Przeglądaj źródła

暂存生成质保卡图片

NULL1222 12 godzin temu
rodzic
commit
6b53fd6e18
1 zmienionych plików z 166 dodań i 62 usunięć
  1. 166 62
      bgj/warrantyCard/chooseWorkOrder/order.js

+ 166 - 62
bgj/warrantyCard/chooseWorkOrder/order.js

@@ -30,13 +30,19 @@ Page({
   onSearch({
     detail
   }) {
-    this.setData({ condition: detail });
+    this.setData({
+      condition: detail
+    });
     this.data.content.where.condition = detail;
     this.getList(true)
   },
 
-  onChange({ detail }) {
-    this.setData({ condition: detail });
+  onChange({
+    detail
+  }) {
+    this.setData({
+      condition: detail
+    });
   },
 
   getList(init = false) {
@@ -66,13 +72,19 @@ Page({
     workTypes = workTypes.map(item => ({
       ...item,
       itemclassname: item.value,
-      subarea: (item.subvalues || []).map(v => ({ value: item.value + "/" + v, subdep: [] }))
+      subarea: (item.subvalues || []).map(v => ({
+        value: item.value + "/" + v,
+        subdep: []
+      }))
     }));
     let serviceTypes = await _Http.getTypes('servicebookingtype', _Http);
     serviceTypes = serviceTypes.map(item => ({
       ...item,
       itemclassname: item.value,
-      subarea: (item.subvalues || []).map(v => ({ value: item.value + "/" + v, subdep: [] }))
+      subarea: (item.subvalues || []).map(v => ({
+        value: item.value + "/" + v,
+        subdep: []
+      }))
     }));
     this.setData({
       type: options.type || this.data.type,
@@ -84,8 +96,10 @@ Page({
     }
     this.getList()
   },
-  chooseResult(e){
-    let { id } = e.currentTarget.dataset;
+  chooseResult(e) {
+    let {
+      id
+    } = e.currentTarget.dataset;
     this.setData({
       result: id
     });
@@ -110,7 +124,7 @@ Page({
   },
 
   submitAndGenerateImage(id) {
-     // 保存接口返回的质保卡数据(含 cardno)
+    // 保存接口返回的质保卡数据(含 cardno)
     // this.data.cardResult = res.data;
     this.drawWarrantyCardImage();
     // _Http.basic({
@@ -136,39 +150,46 @@ Page({
       this.navigateBackAfterSubmit();
       return;
     }
-
+  
     const dpr = wx.getSystemInfoSync().pixelRatio;
-    const canvasWidth = 600;
-    const canvasHeight = 900;
-
-    // 质保卡号优先使用接口返回的卡号,其次使用原工单上的卡号
-    const cardno = cardResult?.cardno || order.cardno || '';
-
-    wx.showLoading({ title: getApp().globalData.Language.getMapText('生成质保卡图片...') || '生成质保卡图片...', mask: true });
-
+    const canvasWidth = 750;
+    const tempCanvasHeight = 1500;
+  
+    const cardno = cardResult?.cardno || order.cardno || '232223232';
+  
+    wx.showLoading({
+      title: getApp().globalData.Language.getMapText('生成质保卡图片...') || '生成质保卡图片...',
+      mask: true
+    });
+  
     const query = wx.createSelectorQuery();
     query.select('#warrantyCardCanvas')
       .fields({ node: true, size: true })
       .exec(async (res) => {
         if (!res || !res[0]) {
           wx.hideLoading();
-          wx.showToast({ title: '操作成功', icon: 'success', mask: true });
+          wx.showToast({
+            title: '操作成功',
+            icon: 'success',
+            mask: true
+          });
           this.navigateBackAfterSubmit();
           return;
         }
-
+  
         const canvas = res[0].node;
         const ctx = canvas.getContext('2d');
-
+  
+        // 高清适配
         canvas.width = canvasWidth * dpr;
-        canvas.height = canvasHeight * dpr;
+        canvas.height = tempCanvasHeight * dpr;
         ctx.scale(dpr, dpr);
-
-        // 1. 白色背景
+  
+        // 1. 整体白色背景
         ctx.fillStyle = '#FFFFFF';
-        ctx.fillRect(0, 0, canvasWidth, canvasHeight);
-
-        // 2. 头部背景图
+        ctx.fillRect(0, 0, canvasWidth, tempCanvasHeight);
+  
+        // 2. 头部背景图 — 等比例绘制
         const headerBg = canvas.createImage();
         await new Promise((resolve) => {
           headerBg.onload = resolve;
@@ -178,65 +199,128 @@ Page({
           };
           headerBg.src = '/static/image/warrantyBg.png';
         });
-        ctx.drawImage(headerBg, 0, 0, canvasWidth, 180);
-
-        // 3. 标题 质保卡
+  
+        const imgW = headerBg.width;
+        const imgH = headerBg.height;
+        const scale = canvasWidth / imgW;
+        const bgRealHeight = imgH * scale;
+        ctx.drawImage(headerBg, 0, 0, canvasWidth, bgRealHeight);
+  
+        // 3. 标题:质保卡
         ctx.fillStyle = '#FFFFFF';
         ctx.font = 'bold 48px sans-serif';
         ctx.textAlign = 'center';
         ctx.textBaseline = 'middle';
-        ctx.fillText(getApp().globalData.Language.getMapText('质保卡') || '质保卡', canvasWidth / 2, 60);
-
-        // 4. 工单号(右上角)
-        ctx.font = '22px sans-serif';
+        ctx.fillText(
+          getApp().globalData.Language.getMapText('质保卡') || '质保卡',
+          canvasWidth / 2,
+          bgRealHeight / 2
+        );
+  
+        // 4. 右上角质保卡号
+        ctx.font = '24px sans-serif';
+        ctx.fillStyle = '#333333';
         ctx.textAlign = 'right';
         ctx.textBaseline = 'top';
-        ctx.fillText((getApp().globalData.Language.getMapText('工单号') || '工单号') + ':' + (order.billno || ''), canvasWidth - 30, 90);
-
+        ctx.fillText(cardno, canvasWidth - 32, 30);
+  
         // 5. 装饰分隔线
+        const lineTop = bgRealHeight + 30;
         ctx.strokeStyle = '#E8E8E8';
         ctx.lineWidth = 2;
         ctx.beginPath();
-        ctx.moveTo(40, 210);
-        ctx.lineTo(canvasWidth - 40, 210);
+        ctx.moveTo(40, lineTop);
+        ctx.lineTo(canvasWidth - 40, lineTop);
         ctx.stroke();
-
-        // 6. 分隔线下方的小标题
+  
+        // 6. 小标题:质保信息
+        const titleTop = lineTop + 20;
         ctx.fillStyle = '#999999';
         ctx.font = '20px sans-serif';
         ctx.textAlign = 'center';
         ctx.textBaseline = 'top';
-        ctx.fillText(getApp().globalData.Language.getMapText('质保信息') || '质保信息', canvasWidth / 2, 230);
-
-        // 7. 尊敬的xxxxxx用户
+        ctx.fillText(
+          getApp().globalData.Language.getMapText('质保信息') || '质保信息',
+          canvasWidth / 2,
+          titleTop
+        );
+  
+        // 7. 尊敬的XXX用户 + 下划线
         const address = order.address || '';
+        const userTextTop = titleTop + 80;
+        ctx.fillStyle = '#000000';
+        ctx.font = 'bold 36px sans-serif';
+        ctx.textAlign = 'left';
+        ctx.textBaseline = 'top';
+        ctx.fillText('尊敬的', 80, userTextTop);
+  
+        ctx.textAlign = 'center';
+        ctx.fillText(address, canvasWidth / 2, userTextTop);
+  
+        ctx.textAlign = 'right';
+        ctx.fillText('用户:', canvasWidth - 80, userTextTop);
+  
+        // 地址下划线
+        ctx.strokeStyle = '#000000';
+        ctx.lineWidth = 2;
+        ctx.beginPath();
+        const addrWidth = ctx.measureText(address).width;
+        const addrLeft = canvasWidth / 2 - addrWidth / 2;
+        ctx.moveTo(addrLeft - 10, userTextTop + 45);
+        ctx.lineTo(addrLeft + addrWidth + 10, userTextTop + 45);
+        ctx.stroke();
+  
+        // 8. 正文段落(自动换行)
+        const contentTop = userTextTop + 80;
         ctx.fillStyle = '#333333';
-        ctx.font = '36px sans-serif';
+        ctx.font = '28px sans-serif';
+        ctx.textAlign = 'left';
+        ctx.textBaseline = 'top';
+        const content = '您好!感谢您选择班尼戈!您的爱宅水路工程已经结束,并通过了厂家专业检测验收。班尼戈公司为您家水路系统提供10年的产品质量 + 施工质量双重质保!';
+        const lineHeight = 45;
+        const lines = wrapText(ctx, content, canvasWidth - 160, 28);
+        lines.forEach((line, index) => {
+          ctx.fillText(line, 80, contentTop + index * lineHeight);
+        });
+  
+        // 9. 服务热线 蓝色大字
+        const hotlineTop = contentTop + lines.length * lineHeight + 60;
+        ctx.fillStyle = '#0052cc';
+        ctx.font = 'bold 48px sans-serif';
         ctx.textAlign = 'center';
-        ctx.textBaseline = 'middle';
-        ctx.fillText((getApp().globalData.Language.getMapText('尊敬的') || '尊敬的') + address + (getApp().globalData.Language.getMapText('用户') || '用户'), canvasWidth / 2, canvasHeight / 2 - 20);
-
-        // 8. 质保卡号
-        ctx.fillStyle = '#666666';
-        ctx.font = '24px sans-serif';
-        ctx.fillText((getApp().globalData.Language.getMapText('卡号') || '卡号') + ':' + cardno, canvasWidth / 2, canvasHeight / 2 + 50);
-
-        // 9. 底部信息
+        ctx.fillText('服务热线:4001085686', canvasWidth / 2, hotlineTop);
+  
+        // 10. 底部文案
+        const footerTop = hotlineTop + 100;
         ctx.fillStyle = '#BBBBBB';
         ctx.font = '18px sans-serif';
-        ctx.textBaseline = 'bottom';
-        ctx.fillText(getApp().globalData.Language.getMapText('班管家 · 品质服务') || '班管家 · 品质服务', canvasWidth / 2, canvasHeight - 30);
-
-        // 10. 生成日期
+        ctx.textAlign = 'center';
+        ctx.fillText(
+          getApp().globalData.Language.getMapText('班管家 · 品质服务') || '班管家 · 品质服务',
+          canvasWidth / 2,
+          footerTop
+        );
+  
+        // 11. 生成日期
         const now = new Date();
-        const dateStr = now.getFullYear() + '-' + String(now.getMonth() + 1).padStart(2, '0') + '-' + String(now.getDate()).padStart(2, '0');
+        const dateStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
+        const dateTop = footerTop + 30;
         ctx.font = '16px sans-serif';
-        ctx.textBaseline = 'bottom';
-        ctx.fillText(dateStr, canvasWidth / 2, canvasHeight - 55);
-
-        // 生成临时文件
+        ctx.fillStyle = '#BBBBBB';
+        ctx.fillText(dateStr, canvasWidth / 2, dateTop);
+  
+        // 计算真实内容高度
+        const realContentHeight = dateTop + 50;
+  
+        // 导出图片
         wx.canvasToTempFilePath({
           canvas: canvas,
+          x: 0,
+          y: 0,
+          width: canvasWidth,
+          height: realContentHeight,
+          destWidth: canvasWidth * dpr,
+          destHeight: realContentHeight * dpr,
           fileType: 'jpg',
           quality: 1,
           success: (res) => {
@@ -273,4 +357,24 @@ Page({
       phoneNumber: e.currentTarget.dataset.number
     })
   },
-})
+})
+// 文本自动换行辅助方法(放在 Page 外层)
+function wrapText(ctx, text, maxWidth, fontSize) {
+  const arrText = text.split('');
+  const line = [];
+  let lineText = '';
+  // 2d 画布用 font 设置字号
+  ctx.font = `${fontSize}px sans-serif`;
+  arrText.forEach((word) => {
+    const testLine = lineText + word;
+    const metrics = ctx.measureText(testLine);
+    if (metrics.width > maxWidth && lineText) {
+      line.push(lineText);
+      lineText = word;
+    } else {
+      lineText = testLine;
+    }
+  });
+  line.push(lineText);
+  return line;
+}