248 lines
9.4 KiB
JavaScript
248 lines
9.4 KiB
JavaScript
const api = require('../../utils/api')
|
||
const app = getApp()
|
||
|
||
Page({
|
||
data: {
|
||
statusBarHeight: 44,
|
||
navBarHeight: 44,
|
||
totalNavHeight: 88,
|
||
posters: [],
|
||
currentPosterIndex: 0,
|
||
qrCodeUrl: '',
|
||
referralCode: '',
|
||
canvasWidth: 1080,
|
||
canvasHeight: 1920,
|
||
isLoading: true,
|
||
userInfo: null
|
||
},
|
||
|
||
onLoad(options) {
|
||
const systemInfo = wx.getSystemInfoSync()
|
||
const statusBarHeight = systemInfo.statusBarHeight || 44
|
||
const menuButton = wx.getMenuButtonBoundingClientRect()
|
||
const navBarHeight = menuButton.height + (menuButton.top - statusBarHeight) * 2
|
||
const totalNavHeight = statusBarHeight + navBarHeight
|
||
|
||
this.setData({
|
||
statusBarHeight,
|
||
navBarHeight,
|
||
totalNavHeight,
|
||
userInfo: app.globalData.userInfo || wx.getStorageSync('user_info')
|
||
})
|
||
|
||
this.loadData();
|
||
},
|
||
|
||
async loadData() {
|
||
try {
|
||
// 1. 获取推荐码
|
||
const statsRes = await api.commission.getStats();
|
||
let referralCode = 'default';
|
||
if (statsRes.success && statsRes.data) {
|
||
referralCode = statsRes.data.referralCode;
|
||
this.setData({ referralCode });
|
||
}
|
||
|
||
// 2. 设置小程序二维码地址
|
||
// scene 格式必须为 r=XXX 才能被 app.js 正确解析
|
||
const baseUrl = app.globalData.baseUrl || 'https://ai-c.maimanji.com';
|
||
const qrCodeUrl = `${baseUrl}/api/user/qrcode?scene=r=${referralCode}&page=pages/index/index`;
|
||
this.setData({ qrCodeUrl });
|
||
|
||
// 3. 获取动态海报背景列表
|
||
const assetRes = await api.pageAssets.getAssets('posters');
|
||
if (assetRes && assetRes.success && assetRes.data && assetRes.data.length > 0) {
|
||
const posters = assetRes.data.map(item => {
|
||
let url = (item.asset_url || '').trim();
|
||
// 如果是相对路径,补充完整域名
|
||
if (url && !url.startsWith('http')) {
|
||
url = baseUrl + (url.startsWith('/') ? '' : '/') + url;
|
||
}
|
||
return {
|
||
id: item.asset_key,
|
||
url: url,
|
||
qrBottom: 4.5, // 对应 1920 高度下的位置
|
||
qrRight: 8 // 对应 1080 宽度下的位置
|
||
};
|
||
});
|
||
this.setData({ posters, isLoading: false });
|
||
} else {
|
||
// 兜底默认海报
|
||
this.setData({
|
||
posters: [
|
||
{ id: 'default', url: 'https://ai-c.maimanji.com/uploads/assets/poster-1.png', qrBottom: 4.5, qrRight: 8 }
|
||
],
|
||
isLoading: false
|
||
});
|
||
}
|
||
} catch (err) {
|
||
console.error('[promote-poster] loadData failed:', err);
|
||
this.setData({ isLoading: false });
|
||
}
|
||
},
|
||
|
||
onPosterChange(e) {
|
||
this.setData({ currentPosterIndex: e.detail.current })
|
||
},
|
||
|
||
onImageError(e) {
|
||
console.error('[promote-poster] 海报图加载失败:', e.detail.errMsg);
|
||
wx.showToast({ title: '海报背景加载失败', icon: 'none' });
|
||
},
|
||
|
||
onQrError(e) {
|
||
console.error('[promote-poster] 二维码加载失败:', e.detail.errMsg);
|
||
wx.showToast({ title: '二维码加载失败', icon: 'none' });
|
||
},
|
||
|
||
/**
|
||
* 下载文件辅助函数
|
||
*/
|
||
downloadFile(url) {
|
||
return new Promise((resolve, reject) => {
|
||
wx.downloadFile({
|
||
url,
|
||
success: res => {
|
||
if (res.statusCode === 200) resolve(res.tempFilePath);
|
||
else reject(new Error('Download failed: ' + url));
|
||
},
|
||
fail: err => {
|
||
console.error('Download failed:', url, err);
|
||
reject(err);
|
||
}
|
||
});
|
||
});
|
||
},
|
||
|
||
async savePoster() {
|
||
if (this.data.posters.length === 0) return;
|
||
|
||
wx.showLoading({ title: '生成中...', mask: true });
|
||
|
||
try {
|
||
const template = this.data.posters[this.data.currentPosterIndex];
|
||
|
||
// 1. 下载资源
|
||
const [bgPath, qrPath] = await Promise.all([
|
||
this.downloadFile(template.url),
|
||
this.downloadFile(this.data.qrCodeUrl)
|
||
]);
|
||
|
||
// 2. 初始化 Canvas
|
||
const query = wx.createSelectorQuery()
|
||
query.select('#posterCanvas')
|
||
.fields({ node: true, size: true })
|
||
.exec(async (res) => {
|
||
if (!res[0] || !res[0].node) {
|
||
wx.hideLoading();
|
||
wx.showToast({ title: 'Canvas初始化失败', icon: 'none' });
|
||
return;
|
||
}
|
||
|
||
const canvas = res[0].node
|
||
const ctx = canvas.getContext('2d')
|
||
const dpr = wx.getSystemInfoSync().pixelRatio
|
||
|
||
const canvasW = 1080;
|
||
const canvasH = 1920;
|
||
|
||
canvas.width = canvasW * dpr
|
||
canvas.height = canvasH * dpr
|
||
ctx.scale(dpr, dpr)
|
||
|
||
// 3. 绘制背景
|
||
const bgImg = canvas.createImage();
|
||
bgImg.src = bgPath;
|
||
await new Promise((resolve, reject) => {
|
||
bgImg.onload = resolve;
|
||
bgImg.onerror = reject;
|
||
});
|
||
ctx.drawImage(bgImg, 0, 0, canvasW, canvasH);
|
||
|
||
// 4. 绘制二维码
|
||
const qrImg = canvas.createImage();
|
||
qrImg.src = qrPath;
|
||
await new Promise((resolve, reject) => {
|
||
qrImg.onload = resolve;
|
||
qrImg.onerror = reject;
|
||
});
|
||
|
||
// 识别白框位置:根据 1080x1920 设计稿,白框在右下角
|
||
// 二维码尺寸 260x260
|
||
const qrW = 260;
|
||
const qrX = 720; // 1080 - 100 - 260
|
||
const qrY = 1580; // 1920 - 80 - 260
|
||
|
||
// 绘制二维码背景(白框内可能需要微调,这里先绘制一个纯白背景确保清晰)
|
||
ctx.fillStyle = '#FFFFFF';
|
||
ctx.beginPath();
|
||
this.roundRect(ctx, qrX - 5, qrY - 5, qrW + 10, qrW + 10, 10);
|
||
ctx.fill();
|
||
|
||
ctx.drawImage(qrImg, qrX, qrY, qrW, qrW);
|
||
|
||
// 6. 导出
|
||
setTimeout(() => {
|
||
wx.canvasToTempFilePath({
|
||
canvas: canvas,
|
||
success: (fileRes) => {
|
||
wx.saveImageToPhotosAlbum({
|
||
filePath: fileRes.tempFilePath,
|
||
success: () => {
|
||
wx.hideLoading();
|
||
wx.showToast({ title: '已保存到相册', icon: 'success' })
|
||
},
|
||
fail: (err) => {
|
||
wx.hideLoading();
|
||
if (err.errMsg.indexOf('auth deny') !== -1) {
|
||
wx.showModal({
|
||
title: '提示',
|
||
content: '请授权保存图片到相册',
|
||
success: (sm) => {
|
||
if (sm.confirm) wx.openSetting();
|
||
}
|
||
});
|
||
} else {
|
||
wx.showToast({ title: '保存失败', icon: 'none' })
|
||
}
|
||
}
|
||
})
|
||
},
|
||
fail: (err) => {
|
||
console.error('canvasToTempFilePath fail:', err);
|
||
wx.hideLoading();
|
||
wx.showToast({ title: '生成图片失败', icon: 'none' });
|
||
}
|
||
})
|
||
}, 300);
|
||
})
|
||
} catch (err) {
|
||
console.error('[promote-poster] savePoster error:', err);
|
||
wx.hideLoading();
|
||
wx.showToast({ title: '海报资源加载失败', icon: 'none' });
|
||
}
|
||
},
|
||
|
||
roundRect(ctx, x, y, w, h, r) {
|
||
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);
|
||
},
|
||
|
||
onShareAppMessage() {
|
||
const title = "发现一个超赞的AI情感陪伴官,快来看看吧!";
|
||
const imageUrl = this.data.posters[this.data.currentPosterIndex]?.url || '';
|
||
return {
|
||
title: title,
|
||
path: `/pages/index/index?referralCode=${this.data.referralCode}`,
|
||
imageUrl: imageUrl
|
||
}
|
||
},
|
||
|
||
goBack() {
|
||
wx.navigateBack();
|
||
}
|
||
});
|