|
|
@@ -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;
|
|
|
+}
|