diff --git a/components-diy/diy-recommend-code.vue b/components-diy/diy-recommend-code.vue index 372490a..1c0eeda 100644 --- a/components-diy/diy-recommend-code.vue +++ b/components-diy/diy-recommend-code.vue @@ -769,130 +769,110 @@ export default { * 返回 Promise */ generateSharePoster() { - const v = this.nc; - const code = this.code || v.placeholderCode || 'ABCD1234'; - const title = v.title || '我的推荐码'; - const W = 375; - const H = 480; - return new Promise((resolve, reject) => { - try { - const ctx = uni.createCanvasContext('sharePosterCanvas', this); - if (!ctx) 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; - if (qr) { - // 先下载到本地临时路径 - this._downloadImage(qr).then((localPath) => { - // 二维码绘制在中部下方,正方形 180x180 - 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(localPath, qrX, qrY, qrSize, qrSize); - // 7. 底部提示 - ctx.setFontSize(11); - ctx.setFillStyle('#999999'); - ctx.setTextAlign('center'); - ctx.fillText(v.posterQrTip || '扫码进入并填写入驻信息', W / 2, qrY + qrSize + 24); - this._exportCanvas(W, H).then(resolve).catch(reject); - }).catch(() => { - // 二维码加载失败,直接导出无二维码版 - this._exportCanvas(W, H).then(resolve).catch(reject); - }); - } else { - this._exportCanvas(W, H).then(resolve).catch(reject); + 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); } - } catch (e) { - reject(e); - } - }); - }, + }); + }, /** * canvas 转图片(uni.canvasToTempFilePath Promise 化) */ _exportCanvas(W, H) { return new Promise((resolve, reject) => { - // 微信小程序: type=2d canvas,需要传入 canvas 实例 - // 旧版非 type=2d: 用 canvasId 字符串 - // 这里两种方式都尝试 - const query = uni.createSelectorQuery().in(this); - query.select('#sharePosterCanvas') - .fields({ node: true, size: true }) - .exec((res) => { - if (res && res[0] && res[0].node) { - // 新版 type=2d canvas - uni.canvasToTempFilePath({ - canvas: res[0].node, - width: W, - height: H, - destWidth: W * 2, - destHeight: H * 2, - fileType: 'png', - quality: 1, - success: (r) => resolve(r.tempFilePath), - fail: (err) => { - // 退化到旧 API - uni.canvasToTempFilePath({ - canvasId: 'sharePosterCanvas', - width: W, - height: H, - destWidth: W * 2, - destHeight: H * 2, - fileType: 'png', - quality: 1, - success: (r2) => resolve(r2.tempFilePath), - fail: (err2) => reject(err2 || err) - }, this); - } - }, this); - } else { - // 旧版 canvas:ctx.draw(false, ...) 后导出 - const ctx = uni.createCanvasContext('sharePosterCanvas', this); - if (ctx && ctx.draw) { - ctx.draw(false, () => { - uni.canvasToTempFilePath({ - canvasId: 'sharePosterCanvas', - width: W, - height: H, - destWidth: W * 2, - destHeight: H * 2, - fileType: 'png', - quality: 1, - success: (r) => resolve(r.tempFilePath), - fail: (err) => reject(err) - }, this); - }); - } else { - reject(new Error('canvas 初始化失败')); - } - } - }); + 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); }); }, /** @@ -1238,6 +1218,11 @@ export default { console.warn('[推荐码分享] 跳过预生成:推荐码为空'); return; } + // 安全:isH5Platform 为 true 时不进入(H5 下 canvas 不渲染,createCanvasContext 会失败) + if (this.isH5Platform) { + console.log('[推荐码分享] H5 环境跳过海报预生成'); + return; + } try { console.log('[推荐码分享] 开始调 generateSharePoster...'); this.generateSharePoster().then(function(posterPath) {