shish 1 ヶ月 前
コミット
da16d63a4e
1 ファイル変更139 行追加15 行削除
  1. 139 15
      ghsApp/src/pagesClient/member/detail.vue

+ 139 - 15
ghsApp/src/pagesClient/member/detail.vue

@@ -418,6 +418,9 @@
       </view>
       </view>
     </uni-popup>
     </uni-popup>
 
 
+    <!-- 用于生成带支付宝背景和文字的结账二维码 -->
+    <canvas canvas-id="shareCanvas" style="width: 360px; height: 490px; position: fixed; left: -9999px; top: -9999px; z-index: -1;"></canvas>
+
   </view>
   </view>
 </template>
 </template>
 <script>
 <script>
@@ -560,29 +563,150 @@ export default {
       if (isNaN(n)) return 0
       if (isNaN(n)) return 0
       return parseFloat(n.toFixed(2))
       return parseFloat(n.toFixed(2))
     },
     },
+    /**
+     * @description 获取并下载支付宝收款码海报
+     * 职责:从后端 API 获取付款二维码,下载图片后,通过 Canvas 绘制成带支付宝蓝色背景和“支付宝扫一扫”文字的精美海报并保存到相册。
+     * 副作用:会调用系统下载文件和保存相册 API,并显示 Loading 状态。
+     */
     downloadCode(){
     downloadCode(){
       let that = this
       let that = this
+      uni.showLoading({
+        title: '正在生成收款码...',
+        mask: true
+      })
       getGatheringCode({id:this.option.id}).then(res=>{
       getGatheringCode({id:this.option.id}).then(res=>{
         if(res.code == 1){
         if(res.code == 1){
           let url = res.data.imgUrl ? res.data.imgUrl: ''
           let url = res.data.imgUrl ? res.data.imgUrl: ''
-          that.downloadImg(url)
+          if (!url) {
+            uni.hideLoading()
+            uni.showToast({ title: '未获取到二维码链接', icon: 'none' })
+            return
+          }
+          // 下载二维码图片到本地临时路径,以便 Canvas 能够进行绘制
+          uni.downloadFile({
+            url: url,
+            success: (downloadRes) => {
+              if (downloadRes.statusCode === 200) {
+                // 下载成功后,开始绘制支付宝收款码海报
+                that.drawAlipayPoster(downloadRes.tempFilePath)
+              } else {
+                uni.hideLoading()
+                uni.showToast({ title: '下载二维码失败', icon: 'none' })
+              }
+            },
+            fail: (err) => {
+              uni.hideLoading()
+              uni.showToast({ title: '下载二维码失败', icon: 'none' })
+            }
+          })
+        } else {
+          uni.hideLoading()
         }
         }
+      }).catch(err => {
+        uni.hideLoading()
       })
       })
     },
     },
-    downloadImg(url){
-      uni.downloadFile({
-        url: url,
-        success: (res) => {
-          if (res.statusCode === 200) {
-            uni.saveImageToPhotosAlbum({
-              filePath: res.tempFilePath,
-              success: function (data) {
-                uni.showToast({title:'保存成功'})
-              }
-            });
-          }
-        }
-      });
+    /**
+     * @description 使用 Canvas 绘制支付宝收款码海报并保存到相册
+     * @param {String} qrPath 二维码本地临时路径
+     * 职责:通过 Canvas 绘制支付宝蓝色背景(带圆角剪裁)、白色圆角卡片、二维码图片、以及“推荐使用支付宝”、“支付宝扫一扫”等文字,最后导出并保存到用户相册。
+     */
+    drawAlipayPoster(qrPath) {
+      const that = this
+      const ctx = uni.createCanvasContext('shareCanvas', this)
+      
+      const width = 360
+      const height = 490
+      const posterRadius = 24 // 整个海报的圆角大小
+
+      // 1. 绘制整个海报的圆角裁剪区域
+      ctx.save()
+      ctx.beginPath()
+      ctx.moveTo(posterRadius, 0)
+      ctx.lineTo(width - posterRadius, 0)
+      ctx.arcTo(width, 0, width, posterRadius, posterRadius)
+      ctx.lineTo(width, height - posterRadius)
+      ctx.arcTo(width, height, width - posterRadius, height, posterRadius)
+      ctx.lineTo(posterRadius, height)
+      ctx.arcTo(0, height, 0, height - posterRadius, posterRadius)
+      ctx.lineTo(0, posterRadius)
+      ctx.arcTo(0, 0, posterRadius, 0, posterRadius)
+      ctx.closePath()
+      ctx.clip() // 剪裁画布,使后续绘制的所有内容都限制在圆角矩形内
+
+      // 2. 绘制背景 (支付宝经典蓝 #3385FF)
+      ctx.setFillStyle('#3385FF')
+      ctx.fillRect(0, 0, width, height)
+      
+      // 3. 绘制顶部标题 "推荐使用支付宝"
+      ctx.setFontSize(24)
+      ctx.setFillStyle('#ffffff')
+      ctx.setTextAlign('center')
+      ctx.fillText('推荐使用支付宝', 180, 55)
+      
+      // 4. 绘制白色圆角卡片,作为二维码的容器
+      const cardX = 24
+      const cardY = 85
+      const cardW = 312
+      const cardH = 380
+      const radius = 16
+      
+      ctx.beginPath()
+      ctx.moveTo(cardX + radius, cardY)
+      ctx.lineTo(cardX + cardW - radius, cardY)
+      ctx.arcTo(cardX + cardW, cardY, cardX + cardW, cardY + radius, radius)
+      ctx.lineTo(cardX + cardW, cardY + cardH - radius)
+      ctx.arcTo(cardX + cardW, cardY + cardH, cardX + cardW - radius, cardY + cardH, radius)
+      ctx.lineTo(cardX + radius, cardY + cardH)
+      ctx.arcTo(cardX, cardY + cardH, cardX, cardY + cardH - radius, radius)
+      ctx.lineTo(cardX, cardY + radius)
+      ctx.arcTo(cardX, cardY, cardX + radius, cardY, radius)
+      ctx.closePath()
+      ctx.setFillStyle('#ffffff')
+      ctx.fill()
+      
+      // 5. 绘制二维码图片
+      const qrSize = 240
+      const qrX = 180 - qrSize / 2 // 居中计算:180 - 120 = 60
+      const qrY = 120
+      ctx.drawImage(qrPath, qrX, qrY, qrSize, qrSize)
+      
+      // 6. 绘制卡片内底部文字 "扫一扫,向商家付款"
+      ctx.setFontSize(20)
+      ctx.setFillStyle('#3385FF') // 使用支付宝蓝色字体,使其更醒目
+      ctx.setTextAlign('center')
+      ctx.fillText('扫一扫,向商家付款', 180, 415)
+      
+      ctx.restore() // 恢复画布状态
+
+      // 8. 渲染并导出保存
+      ctx.draw(false, () => {
+        // 延迟 300ms 确保 Canvas 渲染引擎已完全绘制,防止部分平台导出空白图片
+        setTimeout(() => {
+          uni.canvasToTempFilePath({
+            canvasId: 'shareCanvas',
+            fileType: 'jpg',
+            quality: 1,
+            success: (res) => {
+              uni.hideLoading()
+              // 保存图片到系统相册
+              uni.saveImageToPhotosAlbum({
+                filePath: res.tempFilePath,
+                success: () => {
+                  uni.showToast({ title: '保存成功', icon: 'success' })
+                },
+                fail: (err) => {
+                  uni.showToast({ title: '保存失败,请检查相册权限', icon: 'none' })
+                }
+              })
+            },
+            fail: (err) => {
+              uni.hideLoading()
+              uni.showToast({ title: '生成图片失败', icon: 'none' })
+            }
+          }, that)
+        }, 300)
+      })
     },
     },
 		inviteToPay(){
 		inviteToPay(){
 			let that = this
 			let that = this