fix(diy-recommend-code): generateSharePoster 等方法移到 methods 块
问题: 用户日志显示 "TypeError: this.generateSharePoster is not a function"。 原因: generateSharePoster / _exportCanvas / _roundRect / _downloadImage 等方法之前被定义在 methods 块外的 export default 对象上(与 onShareAppMessage 这种生命周期钩子同级),Vue 不会自动绑定它们到 组件实例,导致 this.xxx 找不到。 修复: - 删除 methods 块外的那 5 个方法的旧定义 - 重新加到 methods 块内(放在 goLogin 后,methods 块关闭 } 之前) - onShareAppMessage / onShareTimeline 是小程序生命周期钩子, 必须留在 export default 对象上,不能进 methods(保留不动) 验证: - H5 测试 isH5Platform=true,提前 return 不进入 generateSharePoster,正常 - 小程序下 this.generateSharePoster 现在能找到方法 - loadCode 成功后 _prepareSharePoster 调用正常
This commit is contained in:
@@ -764,148 +764,8 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 生成推荐码组件的分享海报
|
* 小程序分享到朋友圈(uniapp 生命周期钩子,必须在 export default 对象上,不能进 methods)
|
||||||
* 画布内容:白底 + 标题 + 推荐码大字 + 二维码(如果有) + 简短提示
|
|
||||||
* 返回 Promise<tempFilePath>
|
|
||||||
*/
|
*/
|
||||||
generateSharePoster() {
|
|
||||||
const v = this.nc;
|
|
||||||
const code = this.code || v.placeholderCode || 'ABCD1234';
|
|
||||||
const title = v.title || '我的推荐码';
|
|
||||||
const W = 375;
|
|
||||||
const H = 480;
|
|
||||||
console.log('[推荐码分享] generateSharePoster 进入');
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
try {
|
|
||||||
console.log('[推荐码分享] 准备 createCanvasContext');
|
|
||||||
const ctx = uni.createCanvasContext('sharePosterCanvas', this);
|
|
||||||
console.log('[推荐码分享] createCanvasContext 返回:', !!ctx);
|
|
||||||
if (!ctx) {
|
|
||||||
console.error('[推荐码分享] createCanvasContext 失败');
|
|
||||||
return reject(new Error('createCanvasContext 失败'));
|
|
||||||
}
|
|
||||||
// 1. 白底
|
|
||||||
ctx.setFillStyle('#FFFFFF');
|
|
||||||
ctx.fillRect(0, 0, W, H);
|
|
||||||
// 2. 顶部标题
|
|
||||||
ctx.setFontSize(18);
|
|
||||||
ctx.setFillStyle('#1A1A1A');
|
|
||||||
ctx.setTextAlign('left');
|
|
||||||
ctx.fillText(title, 24, 44);
|
|
||||||
// 3. 提示文字
|
|
||||||
ctx.setFontSize(12);
|
|
||||||
ctx.setFillStyle('#999999');
|
|
||||||
ctx.fillText('分享给好友,邀请入驻获得奖励', 24, 70);
|
|
||||||
// 4. 米黄背景区
|
|
||||||
ctx.setFillStyle('#FFF8F0');
|
|
||||||
const blockY = 90, blockH = 120, blockX = 24, blockW = W - 48;
|
|
||||||
this._roundRect(ctx, blockX, blockY, blockW, blockH, 12);
|
|
||||||
ctx.fill();
|
|
||||||
// 5. 推荐码(居中)
|
|
||||||
ctx.setFontSize(36);
|
|
||||||
ctx.setFillStyle(v.codeColor || '#DC143C');
|
|
||||||
ctx.setTextAlign('center');
|
|
||||||
ctx.setFontWeight('bold');
|
|
||||||
ctx.fillText(code, W / 2, blockY + blockH / 2 + 12);
|
|
||||||
// 6. 二维码(如果有 url)
|
|
||||||
const qr = this.qrcodeRenderUrl;
|
|
||||||
console.log('[推荐码分享] qrcodeRenderUrl=', qr);
|
|
||||||
const drawQrcodeAndExport = (qrLocalPath) => {
|
|
||||||
console.log('[推荐码分享] drawQrcodeAndExport 进入, qrLocalPath=', qrLocalPath);
|
|
||||||
if (qrLocalPath) {
|
|
||||||
const qrSize = 180;
|
|
||||||
const qrX = (W - qrSize) / 2;
|
|
||||||
const qrY = blockY + blockH + 24;
|
|
||||||
ctx.setFillStyle('#FFFFFF');
|
|
||||||
this._roundRect(ctx, qrX - 6, qrY - 6, qrSize + 12, qrSize + 12, 12);
|
|
||||||
ctx.fill();
|
|
||||||
ctx.drawImage(qrLocalPath, qrX, qrY, qrSize, qrSize);
|
|
||||||
ctx.setFontSize(11);
|
|
||||||
ctx.setFillStyle('#999999');
|
|
||||||
ctx.setTextAlign('center');
|
|
||||||
ctx.fillText(v.posterQrTip || '扫码进入并填写入驻信息', W / 2, qrY + qrSize + 24);
|
|
||||||
}
|
|
||||||
console.log('[推荐码分享] 准备 ctx.draw(false, cb)');
|
|
||||||
// 关键: ctx.draw(false, cb) 是异步绘制,必须在 cb 里导出
|
|
||||||
ctx.draw(false, () => {
|
|
||||||
console.log('[推荐码分享] ctx.draw callback 触发,准备 _exportCanvas');
|
|
||||||
this._exportCanvas(W, H).then(resolve).catch(reject);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
if (qr) {
|
|
||||||
this._downloadImage(qr).then(drawQrcodeAndExport).catch(() => drawQrcodeAndExport(null));
|
|
||||||
} else {
|
|
||||||
drawQrcodeAndExport(null);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('[推荐码分享] generateSharePoster try 块异常:', e);
|
|
||||||
reject(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* canvas 转图片(uni.canvasToTempFilePath Promise 化)
|
|
||||||
*/
|
|
||||||
_exportCanvas(W, H) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
console.log('[推荐码分享] _exportCanvas 开始执行');
|
|
||||||
// 直接用 canvasId 导出(不需要 selectorQuery,更可靠)
|
|
||||||
// 微信小程序会自动找到对应 canvas
|
|
||||||
uni.canvasToTempFilePath({
|
|
||||||
canvasId: 'sharePosterCanvas',
|
|
||||||
width: W,
|
|
||||||
height: H,
|
|
||||||
destWidth: W * 2,
|
|
||||||
destHeight: H * 2,
|
|
||||||
fileType: 'png',
|
|
||||||
quality: 1,
|
|
||||||
success: (r) => {
|
|
||||||
console.log('[推荐码分享] canvasToTempFilePath 成功:', r.tempFilePath);
|
|
||||||
resolve(r.tempFilePath);
|
|
||||||
},
|
|
||||||
fail: (err) => {
|
|
||||||
console.error('[推荐码分享] canvasToTempFilePath 失败:', err);
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
}, this);
|
|
||||||
// 兜底超时:5s 后还没返回就 reject,避免永远卡住
|
|
||||||
setTimeout(() => {
|
|
||||||
console.warn('[推荐码分享] canvasToTempFilePath 超时');
|
|
||||||
reject(new Error('canvasToTempFilePath 超时'));
|
|
||||||
}, 5000);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 圆角矩形路径(canvas API)
|
|
||||||
*/
|
|
||||||
_roundRect(ctx, x, y, w, h, r) {
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.moveTo(x + r, y);
|
|
||||||
ctx.arcTo(x + w, y, x + w, y + h, r);
|
|
||||||
ctx.arcTo(x + w, y + h, x, y + h, r);
|
|
||||||
ctx.arcTo(x, y + h, x, y, r);
|
|
||||||
ctx.arcTo(x, y, x + w, y, r);
|
|
||||||
ctx.closePath();
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 下载图片到临时路径(Promise 化)
|
|
||||||
* 支持本地路径直接返回
|
|
||||||
*/
|
|
||||||
_downloadImage(url) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
if (!url) return reject(new Error('url 为空'));
|
|
||||||
// 已是临时/本地路径
|
|
||||||
if (!/^https?:\/\//i.test(url)) return resolve(url);
|
|
||||||
uni.downloadFile({
|
|
||||||
url,
|
|
||||||
success: (res) => {
|
|
||||||
if (res.statusCode === 200 && res.tempFilePath) resolve(res.tempFilePath);
|
|
||||||
else reject(new Error('下载失败:' + res.statusCode));
|
|
||||||
},
|
|
||||||
fail: reject
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onShareTimeline() {
|
onShareTimeline() {
|
||||||
const v = this.nc;
|
const v = this.nc;
|
||||||
// 从H5分享链接中提取完整查询参数,与分享给好友保持一致
|
// 从H5分享链接中提取完整查询参数,与分享给好友保持一致
|
||||||
@@ -1418,6 +1278,147 @@ onShareClick() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成推荐码组件的分享海报(canvas 绘制 → 临时文件路径)
|
||||||
|
* 画布内容:白底 + 标题 + 推荐码大字 + 二维码(如有) + 简短提示
|
||||||
|
* 返回 Promise<tempFilePath>
|
||||||
|
*/
|
||||||
|
generateSharePoster() {
|
||||||
|
const v = this.nc;
|
||||||
|
const code = this.code || v.placeholderCode || 'ABCD1234';
|
||||||
|
const title = v.title || '我的推荐码';
|
||||||
|
const W = 375;
|
||||||
|
const H = 480;
|
||||||
|
console.log('[推荐码分享] generateSharePoster 进入');
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
console.log('[推荐码分享] 准备 createCanvasContext');
|
||||||
|
const ctx = uni.createCanvasContext('sharePosterCanvas', this);
|
||||||
|
console.log('[推荐码分享] createCanvasContext 返回:', !!ctx);
|
||||||
|
if (!ctx) {
|
||||||
|
console.error('[推荐码分享] createCanvasContext 失败');
|
||||||
|
return reject(new Error('createCanvasContext 失败'));
|
||||||
|
}
|
||||||
|
// 1. 白底
|
||||||
|
ctx.setFillStyle('#FFFFFF');
|
||||||
|
ctx.fillRect(0, 0, W, H);
|
||||||
|
// 2. 顶部标题
|
||||||
|
ctx.setFontSize(18);
|
||||||
|
ctx.setFillStyle('#1A1A1A');
|
||||||
|
ctx.setTextAlign('left');
|
||||||
|
ctx.fillText(title, 24, 44);
|
||||||
|
// 3. 提示文字
|
||||||
|
ctx.setFontSize(12);
|
||||||
|
ctx.setFillStyle('#999999');
|
||||||
|
ctx.fillText('分享给好友,邀请入驻获得奖励', 24, 70);
|
||||||
|
// 4. 米黄背景区
|
||||||
|
ctx.setFillStyle('#FFF8F0');
|
||||||
|
const blockY = 90, blockH = 120, blockX = 24, blockW = W - 48;
|
||||||
|
this._roundRect(ctx, blockX, blockY, blockW, blockH, 12);
|
||||||
|
ctx.fill();
|
||||||
|
// 5. 推荐码(居中)
|
||||||
|
ctx.setFontSize(36);
|
||||||
|
ctx.setFillStyle(v.codeColor || '#DC143C');
|
||||||
|
ctx.setTextAlign('center');
|
||||||
|
ctx.setFontWeight('bold');
|
||||||
|
ctx.fillText(code, W / 2, blockY + blockH / 2 + 12);
|
||||||
|
// 6. 二维码(如果有 url)
|
||||||
|
const qr = this.qrcodeRenderUrl;
|
||||||
|
console.log('[推荐码分享] qrcodeRenderUrl=', qr);
|
||||||
|
const drawQrcodeAndExport = (qrLocalPath) => {
|
||||||
|
console.log('[推荐码分享] drawQrcodeAndExport 进入, qrLocalPath=', qrLocalPath);
|
||||||
|
if (qrLocalPath) {
|
||||||
|
const qrSize = 180;
|
||||||
|
const qrX = (W - qrSize) / 2;
|
||||||
|
const qrY = blockY + blockH + 24;
|
||||||
|
ctx.setFillStyle('#FFFFFF');
|
||||||
|
this._roundRect(ctx, qrX - 6, qrY - 6, qrSize + 12, qrSize + 12, 12);
|
||||||
|
ctx.fill();
|
||||||
|
ctx.drawImage(qrLocalPath, qrX, qrY, qrSize, qrSize);
|
||||||
|
ctx.setFontSize(11);
|
||||||
|
ctx.setFillStyle('#999999');
|
||||||
|
ctx.setTextAlign('center');
|
||||||
|
ctx.fillText(v.posterQrTip || '扫码进入并填写入驻信息', W / 2, qrY + qrSize + 24);
|
||||||
|
}
|
||||||
|
console.log('[推荐码分享] 准备 ctx.draw(false, cb)');
|
||||||
|
// 关键: ctx.draw(false, cb) 是异步绘制,必须在 cb 里导出
|
||||||
|
ctx.draw(false, () => {
|
||||||
|
console.log('[推荐码分享] ctx.draw callback 触发,准备 _exportCanvas');
|
||||||
|
this._exportCanvas(W, H).then(resolve).catch(reject);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (qr) {
|
||||||
|
this._downloadImage(qr).then(drawQrcodeAndExport).catch(() => drawQrcodeAndExport(null));
|
||||||
|
} else {
|
||||||
|
drawQrcodeAndExport(null);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[推荐码分享] generateSharePoster try 块异常:', e);
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* canvas 转图片(uni.canvasToTempFilePath Promise 化)
|
||||||
|
*/
|
||||||
|
_exportCanvas(W, H) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
console.log('[推荐码分享] _exportCanvas 开始执行');
|
||||||
|
uni.canvasToTempFilePath({
|
||||||
|
canvasId: 'sharePosterCanvas',
|
||||||
|
width: W,
|
||||||
|
height: H,
|
||||||
|
destWidth: W * 2,
|
||||||
|
destHeight: H * 2,
|
||||||
|
fileType: 'png',
|
||||||
|
quality: 1,
|
||||||
|
success: (r) => {
|
||||||
|
console.log('[推荐码分享] canvasToTempFilePath 成功:', r.tempFilePath);
|
||||||
|
resolve(r.tempFilePath);
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
console.error('[推荐码分享] canvasToTempFilePath 失败:', err);
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
// 兜底超时:5s 后还没返回就 reject,避免永远卡住
|
||||||
|
setTimeout(() => {
|
||||||
|
console.warn('[推荐码分享] canvasToTempFilePath 超时');
|
||||||
|
reject(new Error('canvasToTempFilePath 超时'));
|
||||||
|
}, 5000);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 圆角矩形路径(canvas API)
|
||||||
|
*/
|
||||||
|
_roundRect(ctx, x, y, w, h, r) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(x + r, y);
|
||||||
|
ctx.arcTo(x + w, y, x + w, y + h, r);
|
||||||
|
ctx.arcTo(x + w, y + h, x, y + h, r);
|
||||||
|
ctx.arcTo(x, y + h, x, y, r);
|
||||||
|
ctx.arcTo(x, y, x + w, y, r);
|
||||||
|
ctx.closePath();
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 下载图片到临时路径(Promise 化)
|
||||||
|
* 支持本地路径直接返回
|
||||||
|
*/
|
||||||
|
_downloadImage(url) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!url) return reject(new Error('url 为空'));
|
||||||
|
if (!/^https?:\/\//i.test(url)) return resolve(url);
|
||||||
|
uni.downloadFile({
|
||||||
|
url,
|
||||||
|
success: (res) => {
|
||||||
|
if (res.statusCode === 200 && res.tempFilePath) resolve(res.tempFilePath);
|
||||||
|
else reject(new Error('下载失败:' + res.statusCode));
|
||||||
|
},
|
||||||
|
fail: reject
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user