Files
2026-06-27 01:26:11 +08:00

281 lines
8.0 KiB
JavaScript

// pages/haibao/haibao.js
import request from '../../utils/request.js';
const app = getApp();
Page({
data: {
qrcodeUrl: '',
isLoading: false,
showPosterCanvas: false,
posterImageTemp: '',
avatarUrl: '',
uid: '',
nickName: '',
},
onLoad() {
this.loadQRCodeFromCache();
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()
};
}
},
loadQRCodeFromCache() {
try {
const relativeUrl = wx.getStorageSync('haibao_url');
if (relativeUrl) {
const fullUrl = this.getFullImageUrl(relativeUrl);
this.setData({ qrcodeUrl: fullUrl });
} else {
this.setData({ qrcodeUrl: '' });
}
} catch (error) {
console.error('读取缓存失败', error);
}
},
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 });
},
getFullImageUrl(url) {
if (!url) return '';
const ossUrl = app.globalData.ossImageUrl || '';
return url.startsWith('http') ? url : ossUrl + url;
},
refreshQRCode() {
if (this.data.isLoading) return;
this.setData({ isLoading: true });
request({
url: '/peizhi/guanshiewm',
method: 'POST',
}).then(res => {
if (res.data && res.data.code === 0) {
const relativeUrl = res.data.data.url;
if (relativeUrl) {
wx.setStorageSync('haibao_url', relativeUrl);
const fullUrl = this.getFullImageUrl(relativeUrl);
this.setData({ qrcodeUrl: fullUrl });
wx.showToast({ title: '获取成功', icon: 'success' });
} else {
wx.showToast({ title: '返回数据异常', icon: 'none' });
}
} 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' });
}
});
},
generateMyPoster() {
if (!this.data.qrcodeUrl) {
wx.showToast({ title: '请先生成二维码', icon: 'none' });
return;
}
wx.showLoading({ title: '生成海报中...', mask: true });
const ossUrl = app.globalData.ossImageUrl || '';
const bgUrl = ossUrl + 'beijing/haibaobeijing.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 }, () => {
setTimeout(() => {
this.drawPoster(images[0], images[1], images[2]);
}, 200);
});
})
.catch((err) => {
wx.hideLoading();
wx.showToast({ title: '图片加载失败', icon: 'none' });
console.error('图片加载失败', err);
});
},
loadImage(url) {
return new Promise((resolve, reject) => {
wx.getImageInfo({
src: url,
success: (res) => resolve(res.path),
fail: reject
});
});
},
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);
const qrSize = 100;
const margin = 5;
const qrX = canvasWidth - qrSize - margin;
const qrY = canvasHeight - qrSize - margin;
ctx.drawImage(qrPath, qrX, qrY, qrSize, qrSize);
const avatarSize = 60;
const avatarX = margin + 20;
const avatarY = canvasHeight - avatarSize - margin;
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' });
}
});
},
});