356 lines
10 KiB
JavaScript
356 lines
10 KiB
JavaScript
// pages/zuzhanghaibao/zuzhanghaibao.js
|
||
import request from '../../utils/request.js';
|
||
|
||
const app = getApp();
|
||
|
||
Page({
|
||
data: {
|
||
qrcodeUrl: '', // 二维码完整URL
|
||
yaoqingma: '', // 组长邀请码字符串
|
||
isLoading: false,
|
||
showPosterCanvas: false,
|
||
posterImageTemp: '', // 生成的海报临时路径
|
||
avatarUrl: '', // 用户头像完整URL
|
||
uid: '',
|
||
nickName: '',
|
||
},
|
||
|
||
onLoad() {
|
||
this.loadFromCache();
|
||
this.loadUserInfo();
|
||
},
|
||
|
||
onShow() {
|
||
this.registerNotificationComponent();
|
||
},
|
||
|
||
registerNotificationComponent() {
|
||
const notificationComp = this.selectComponent('#global-notification');
|
||
if (notificationComp && notificationComp.showNotification) {
|
||
app.globalData.globalNotification = {
|
||
show: (data) => notificationComp.showNotification(data),
|
||
hide: () => notificationComp.hideNotification()
|
||
};
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 从缓存加载二维码URL和邀请码
|
||
* 缓存键名使用独特拼音,避免与管事页面冲突
|
||
*/
|
||
loadFromCache() {
|
||
try {
|
||
const relativeUrl = wx.getStorageSync('zuzhang_haibao_url');
|
||
if (relativeUrl) {
|
||
const fullUrl = this.getFullImageUrl(relativeUrl);
|
||
this.setData({ qrcodeUrl: fullUrl });
|
||
}
|
||
const yaoqingma = wx.getStorageSync('zuzhang_yaoqingma');
|
||
if (yaoqingma) {
|
||
this.setData({ yaoqingma });
|
||
}
|
||
} catch (error) {
|
||
console.error('读取缓存失败', error);
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 加载用户头像、昵称、UID
|
||
*/
|
||
loadUserInfo() {
|
||
const touxiang = wx.getStorageSync('touxiang');
|
||
const ossUrl = app.globalData.ossImageUrl || '';
|
||
const defaultAvatar = ossUrl + (app.globalData.morentouxiang || 'avatar/default.jpg');
|
||
let avatarUrl = defaultAvatar;
|
||
if (touxiang && typeof touxiang === 'string' && touxiang.trim() !== '') {
|
||
avatarUrl = this.getFullImageUrl(touxiang);
|
||
}
|
||
const uid = wx.getStorageSync('uid') || '';
|
||
// 组长昵称可能从全局变量或缓存获取
|
||
let nickName = app.globalData.nicheng || wx.getStorageSync('nicheng') || '组长';
|
||
this.setData({ avatarUrl, uid, nickName });
|
||
},
|
||
|
||
/**
|
||
* 拼接完整图片URL
|
||
*/
|
||
getFullImageUrl(url) {
|
||
if (!url) return '';
|
||
const ossUrl = app.globalData.ossImageUrl || '';
|
||
return url.startsWith('http') ? url : ossUrl + url;
|
||
},
|
||
|
||
/**
|
||
* 刷新/获取二维码和邀请码
|
||
* 调用 /peizhi/zuzhanghb 接口
|
||
*/
|
||
refreshQRCode() {
|
||
if (this.data.isLoading) return;
|
||
this.setData({ isLoading: true });
|
||
|
||
request({
|
||
url: '/peizhi/zuzhanghb',
|
||
method: 'POST',
|
||
})
|
||
.then(res => {
|
||
if (res.data && res.data.code === 0) {
|
||
const { url: relativeUrl, yaoqingma } = res.data.data; // 假设返回字段为 url 和 yaoqingma
|
||
if (relativeUrl) {
|
||
wx.setStorageSync('zuzhang_haibao_url', relativeUrl);
|
||
const fullUrl = this.getFullImageUrl(relativeUrl);
|
||
this.setData({ qrcodeUrl: fullUrl });
|
||
}
|
||
if (yaoqingma) {
|
||
wx.setStorageSync('zuzhang_yaoqingma', yaoqingma);
|
||
this.setData({ yaoqingma });
|
||
}
|
||
wx.showToast({ title: '获取成功', icon: 'success' });
|
||
} else {
|
||
wx.showToast({ title: res.data.msg || '获取失败', icon: 'none' });
|
||
}
|
||
})
|
||
.catch(err => {
|
||
console.error('获取组长海报失败', err);
|
||
wx.showToast({ title: '网络错误', icon: 'none' });
|
||
})
|
||
.finally(() => {
|
||
this.setData({ isLoading: false });
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 保存二维码到相册(先下载网络图片)
|
||
*/
|
||
saveToAlbum() {
|
||
if (!this.data.qrcodeUrl) {
|
||
wx.showToast({ title: '暂无二维码', icon: 'none' });
|
||
return;
|
||
}
|
||
|
||
wx.showLoading({ title: '保存中...', mask: true });
|
||
wx.downloadFile({
|
||
url: this.data.qrcodeUrl,
|
||
success: (res) => {
|
||
wx.hideLoading();
|
||
if (res.statusCode === 200) {
|
||
this.downloadAndSave(res.tempFilePath);
|
||
} else {
|
||
wx.showToast({ title: '下载失败', icon: 'none' });
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
wx.hideLoading();
|
||
console.error('下载二维码失败', err);
|
||
wx.showToast({ title: '下载失败', icon: 'none' });
|
||
}
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 复制邀请码到剪贴板
|
||
*/
|
||
copyInviteCode() {
|
||
if (!this.data.yaoqingma) {
|
||
wx.showToast({ title: '暂无邀请码', icon: 'none' });
|
||
return;
|
||
}
|
||
wx.setClipboardData({
|
||
data: this.data.yaoqingma,
|
||
success: () => {
|
||
wx.showToast({ title: '复制成功', icon: 'success' });
|
||
},
|
||
fail: () => {
|
||
wx.showToast({ title: '复制失败', icon: 'none' });
|
||
}
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 生成专属海报(包含头像、二维码、昵称、标语)
|
||
*/
|
||
generateMyPoster() {
|
||
if (!this.data.qrcodeUrl) {
|
||
wx.showToast({ title: '请先生成二维码', icon: 'none' });
|
||
return;
|
||
}
|
||
|
||
wx.showLoading({ title: '生成海报中...', mask: true });
|
||
|
||
const ossUrl = app.globalData.ossImageUrl || '';
|
||
// 🔥 组长海报背景图路径:beijing/zuzhangbeijing.jpg
|
||
const bgUrl = ossUrl + 'beijing/zuzhangbeijing.jpg';
|
||
const urls = [bgUrl, this.data.qrcodeUrl, this.data.avatarUrl];
|
||
|
||
// 并行加载所有图片
|
||
const promises = urls.map(url => this.loadImage(url));
|
||
Promise.all(promises)
|
||
.then((images) => {
|
||
wx.hideLoading();
|
||
this.setData({ showPosterCanvas: true }, () => {
|
||
// 确保 canvas 已渲染
|
||
setTimeout(() => {
|
||
this.drawPoster(images[0], images[1], images[2]);
|
||
}, 200);
|
||
});
|
||
})
|
||
.catch((err) => {
|
||
wx.hideLoading();
|
||
wx.showToast({ title: '图片加载失败', icon: 'none' });
|
||
console.error('图片加载失败', err);
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 加载图片为本地路径(用于 canvas 绘制)
|
||
*/
|
||
loadImage(url) {
|
||
return new Promise((resolve, reject) => {
|
||
wx.getImageInfo({
|
||
src: url,
|
||
success: (res) => resolve(res.path),
|
||
fail: reject
|
||
});
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 绘制海报
|
||
* @param {string} bgPath 背景图本地路径
|
||
* @param {string} qrPath 二维码本地路径
|
||
* @param {string} avatarPath 头像本地路径
|
||
*/
|
||
drawPoster(bgPath, qrPath, avatarPath) {
|
||
const ctx = wx.createCanvasContext('posterCanvas', this);
|
||
const query = wx.createSelectorQuery().in(this);
|
||
query.select('.poster-canvas').boundingClientRect(rect => {
|
||
if (!rect) {
|
||
wx.showToast({ title: '画布获取失败', icon: 'none' });
|
||
return;
|
||
}
|
||
const canvasWidth = rect.width;
|
||
const canvasHeight = rect.height;
|
||
|
||
// 1. 绘制背景
|
||
ctx.drawImage(bgPath, 0, 0, canvasWidth, canvasHeight);
|
||
|
||
// 🔥【位置调整】二维码向右上角移动一丢丢 (增加 margin 从 5 到 15)
|
||
const qrSize = 100;
|
||
const margin = 15; // 原来 5,现在 15,向右下各移一点,但看起来更协调
|
||
const qrX = canvasWidth - qrSize - margin;
|
||
const qrY = canvasHeight - qrSize - margin;
|
||
ctx.drawImage(qrPath, qrX, qrY, qrSize, qrSize);
|
||
|
||
// 🔥【位置调整】头像也向右上移动一丢丢 (原来 margin 5,现在 margin 15)
|
||
const avatarSize = 60;
|
||
const avatarMargin = 15;
|
||
const avatarX = avatarMargin + 10; // 原来 margin 5+20,现在 15+20,相当于右移10
|
||
const avatarY = canvasHeight - avatarSize - avatarMargin;
|
||
|
||
// 圆形头像裁剪
|
||
ctx.save();
|
||
ctx.beginPath();
|
||
ctx.arc(avatarX + avatarSize/2, avatarY + avatarSize/2, avatarSize/2, 0, 2 * Math.PI);
|
||
ctx.clip();
|
||
ctx.drawImage(avatarPath, avatarX, avatarY, avatarSize, avatarSize);
|
||
ctx.restore();
|
||
|
||
// 绘制昵称(右侧)
|
||
ctx.setFontSize(16);
|
||
ctx.setFillStyle('#333333'); // 根据背景图颜色可调整
|
||
ctx.setTextAlign('left');
|
||
|
||
let nick = this.data.nickName || '组长';
|
||
if (nick.length > 3) {
|
||
nick = nick.substring(0, 3) + '...';
|
||
}
|
||
const nameText = nick;
|
||
const textX = avatarX + avatarSize + 8;
|
||
const textY = avatarY + avatarSize/2 + 6;
|
||
ctx.fillText(nameText, textX, textY);
|
||
|
||
// 绘制邀请语
|
||
ctx.setFontSize(18);
|
||
ctx.setFillStyle('#ffaa00'); // 金黄色,呼应组长主题
|
||
ctx.setTextAlign('left');
|
||
const slogan = '加入我的团队 ✦';
|
||
const sloganX = avatarX;
|
||
const sloganY = avatarY - 12;
|
||
ctx.fillText(slogan, sloganX, sloganY);
|
||
|
||
// 异步绘制
|
||
ctx.draw(false, () => {
|
||
wx.canvasToTempFilePath({
|
||
canvasId: 'posterCanvas',
|
||
success: (res) => {
|
||
this.setData({ posterImageTemp: res.tempFilePath });
|
||
},
|
||
fail: (err) => {
|
||
console.error('生成海报临时文件失败', err);
|
||
}
|
||
}, this);
|
||
});
|
||
}).exec();
|
||
},
|
||
|
||
/**
|
||
* 保存生成的海报
|
||
*/
|
||
savePoster() {
|
||
if (!this.data.posterImageTemp) {
|
||
wx.showToast({ title: '海报尚未生成', icon: 'none' });
|
||
return;
|
||
}
|
||
this.downloadAndSave(this.data.posterImageTemp);
|
||
},
|
||
|
||
/**
|
||
* 隐藏海报画布,返回主界面
|
||
*/
|
||
hidePoster() {
|
||
this.setData({ showPosterCanvas: false, posterImageTemp: '' });
|
||
},
|
||
|
||
/**
|
||
* 通用保存图片到相册(带权限检查)
|
||
*/
|
||
downloadAndSave(filePath) {
|
||
wx.getSetting({
|
||
success: (res) => {
|
||
if (!res.authSetting['scope.writePhotosAlbum']) {
|
||
wx.authorize({
|
||
scope: 'scope.writePhotosAlbum',
|
||
success: () => {
|
||
this._saveImage(filePath);
|
||
},
|
||
fail: () => {
|
||
wx.showModal({
|
||
title: '提示',
|
||
content: '需要您授权保存到相册',
|
||
success: (modalRes) => {
|
||
if (modalRes.confirm) {
|
||
wx.openSetting();
|
||
}
|
||
}
|
||
});
|
||
}
|
||
});
|
||
} else {
|
||
this._saveImage(filePath);
|
||
}
|
||
}
|
||
});
|
||
},
|
||
|
||
_saveImage(filePath) {
|
||
wx.saveImageToPhotosAlbum({
|
||
filePath: filePath,
|
||
success: () => {
|
||
wx.showToast({ title: '保存成功', icon: 'success' });
|
||
},
|
||
fail: (err) => {
|
||
console.error('保存失败', err);
|
||
wx.showToast({ title: '保存失败', icon: 'none' });
|
||
}
|
||
});
|
||
},
|
||
}); |