|
|
@@ -9,6 +9,7 @@ Page({
|
|
|
*/
|
|
|
data: {
|
|
|
appAssetsUrl: app.appAssetsUrl,
|
|
|
+ appAssetsUrl3: app.appAssetsUrl3,
|
|
|
bottomLeft: app.bottomLeft,
|
|
|
user: {},
|
|
|
name: '',
|
|
|
@@ -31,16 +32,17 @@ Page({
|
|
|
})
|
|
|
this.getCode();
|
|
|
wx.setNavigationBarTitle({
|
|
|
- title: options.inviteCode ? '他/她的邀请码' : '我的邀请码'
|
|
|
+ title: options.inviteCode ? '他/她的会员码' : '我的会员码'
|
|
|
});
|
|
|
},
|
|
|
downloadQR() {
|
|
|
+ console.log('下载海报');
|
|
|
const that = this;
|
|
|
wx.getSetting({ //获取权限
|
|
|
success(res) {
|
|
|
console.log(res);
|
|
|
if (res.authSetting["scope.writePhotosAlbum"]) {
|
|
|
- that.sendCode();
|
|
|
+ that.createPoster();
|
|
|
} else if (res.authSetting["scope.writePhotosAlbum"] == false) {
|
|
|
wx.showToast({
|
|
|
title: '请先授权相册',
|
|
|
@@ -49,14 +51,14 @@ Page({
|
|
|
wx.openSetting({
|
|
|
scope: "scope.writePhotosAlbum",
|
|
|
success() {
|
|
|
- that.sendCode();
|
|
|
+ that.createPoster();
|
|
|
}
|
|
|
});
|
|
|
} else {
|
|
|
wx.authorize({
|
|
|
scope: "scope.writePhotosAlbum",
|
|
|
success() {
|
|
|
- that.sendCode();
|
|
|
+ that.createPoster();
|
|
|
},
|
|
|
fail(e) {
|
|
|
console.log('未授权相册', e);
|
|
|
@@ -70,6 +72,267 @@ Page({
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
+
|
|
|
+ // 生成海报
|
|
|
+ createPoster() {
|
|
|
+ wx.showLoading({
|
|
|
+ title: '生成海报中...',
|
|
|
+ });
|
|
|
+ const that = this;
|
|
|
+ // 获取背景图片的实际尺寸
|
|
|
+ const bgUrl = that.data.appAssetsUrl3 + 'invitation_code_bg.png';
|
|
|
+ // 使用背景图片的实际尺寸作为画布尺寸
|
|
|
+ const canvasWidth = 750;
|
|
|
+ const canvasHeight = 1334;
|
|
|
+
|
|
|
+ // 计算缩放比例
|
|
|
+ const scale = Math.min(canvasWidth, canvasHeight) / Math.min(canvasWidth, canvasHeight);
|
|
|
+
|
|
|
+ // 创建canvas绘图上下文
|
|
|
+ const ctx = wx.createCanvasContext('myCanvas', that);
|
|
|
+
|
|
|
+ // 绘制背景图片,沾满整个画布
|
|
|
+ that.drawImageWithRetry(ctx, bgUrl, 0, 0, canvasWidth, canvasHeight, false, () => {
|
|
|
+ // 背景图片绘制完成后继续绘制其他元素
|
|
|
+ // 绘制完成,导出图片
|
|
|
+ ctx.draw(false, () => {
|
|
|
+ // 绘制用户头像
|
|
|
+ const avatarUrl = that.data.memberphoto ? that.data.memberphoto : (that.data.appAssetsUrl + '/images/bz1_nor.png');
|
|
|
+ // 按比例调整头像尺寸和位置
|
|
|
+ const avatarSize = 99 * scale; // 99rpx
|
|
|
+ const avatarX = 40 * scale;
|
|
|
+ const avatarY = 40 * scale;
|
|
|
+ that.drawImageWithRetry(ctx, avatarUrl, avatarX, avatarY, avatarSize, avatarSize, true, () => {
|
|
|
+ // 绘制用户名 (与头像对齐并排展示)
|
|
|
+ ctx.setTextAlign('left');
|
|
|
+ ctx.setFillStyle('#ffffff');
|
|
|
+ ctx.setFontSize(30 * scale); // 字体大小
|
|
|
+ // 文字垂直居中对齐头像
|
|
|
+ const textY = avatarY + avatarSize / 2 - 10 * scale;
|
|
|
+ ctx.fillText(that.data.name || '--', avatarX + avatarSize + 20 * scale, textY);
|
|
|
+
|
|
|
+ // 绘制邀请码 (与头像对齐并排展示)
|
|
|
+ ctx.setFontSize(28 * scale); // 字体大小
|
|
|
+ ctx.fillText('邀请码: ' + (that.data.inviteCode || ''), avatarX + avatarSize + 20 * scale, textY + 35 * scale);
|
|
|
+
|
|
|
+ // 头像和文字绘制完成后绘制二维码
|
|
|
+ if (that.data.invitationCodeImg) {
|
|
|
+ // 按比例调整二维码尺寸和位置,保持居中
|
|
|
+ const qrSize = 148 * scale; // 148rpx
|
|
|
+ const qrX = (canvasWidth - qrSize) / 2; // 居中显示
|
|
|
+ const qrY = canvasHeight - 200 * scale - 20 * scale; // 向上移动20px
|
|
|
+ that.drawImageWithRetry(ctx, that.data.invitationCodeImg, qrX, qrY, qrSize, qrSize, false, () => {
|
|
|
+ // 二维码绘制完成后绘制底部文字,保持居中
|
|
|
+ ctx.setTextAlign('center');
|
|
|
+ ctx.setFillStyle('#ffffff');
|
|
|
+ ctx.setFontSize(30 * scale);
|
|
|
+ ctx.fillText('青雲慧青年服务平台', canvasWidth / 2, canvasHeight - 30 * scale);
|
|
|
+
|
|
|
+ // 全部绘制完成,导出图片
|
|
|
+ ctx.draw(true, () => {
|
|
|
+ that.exportCanvasToImage();
|
|
|
+ });
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ // 没有二维码时绘制底部文字,保持居中
|
|
|
+ ctx.setTextAlign('center');
|
|
|
+ ctx.setFillStyle('#ffffff');
|
|
|
+ ctx.setFontSize(30 * scale);
|
|
|
+ ctx.fillText('青雲慧青年服务平台', canvasWidth / 2, canvasHeight - 30 * scale);
|
|
|
+
|
|
|
+ // 全部绘制完成,导出图片
|
|
|
+ ctx.draw(true, () => {
|
|
|
+ that.exportCanvasToImage();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 带重试机制的图片绘制方法
|
|
|
+ drawImageWithRetry(ctx, imageUrl, x, y, width, height, isAvatar, callback) {
|
|
|
+ const that = this;
|
|
|
+
|
|
|
+ // 检查是否为base64格式的图片数据
|
|
|
+ if (imageUrl && (imageUrl.startsWith('data:image') || imageUrl.startsWith('/9j/'))) {
|
|
|
+ // 处理base64格式的图片
|
|
|
+ that.drawBase64Image(ctx, imageUrl, x, y, width, height, isAvatar, callback);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果imageUrl为空或无效,直接回调
|
|
|
+ if (!imageUrl) {
|
|
|
+ callback && callback();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ wx.getImageInfo({
|
|
|
+ src: imageUrl,
|
|
|
+ success: function(res) {
|
|
|
+ try {
|
|
|
+ // 检查是否为二维码图片,如果是则添加圆角
|
|
|
+ if (!isAvatar && that.data.invitationCodeImg && imageUrl === that.data.invitationCodeImg) {
|
|
|
+ // 为二维码添加5px圆角
|
|
|
+ ctx.save();
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.moveTo(x + 5, y);
|
|
|
+ ctx.lineTo(x + width - 5, y);
|
|
|
+ ctx.quadraticCurveTo(x + width, y, x + width, y + 5);
|
|
|
+ ctx.lineTo(x + width, y + height - 5);
|
|
|
+ ctx.quadraticCurveTo(x + width, y + height, x + width - 5, y + height);
|
|
|
+ ctx.lineTo(x + 5, y + height);
|
|
|
+ ctx.quadraticCurveTo(x, y + height, x, y + height - 5);
|
|
|
+ ctx.lineTo(x, y + 5);
|
|
|
+ ctx.quadraticCurveTo(x, y, x + 5, y);
|
|
|
+ ctx.closePath();
|
|
|
+ ctx.clip();
|
|
|
+ ctx.drawImage(res.path, x, y, width, height);
|
|
|
+ ctx.restore();
|
|
|
+ } else if (isAvatar) {
|
|
|
+ // 如果是头像,需要圆形裁剪
|
|
|
+ ctx.save();
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.arc(x + width/2, y + height/2, width/2, 0, 2 * Math.PI);
|
|
|
+ ctx.clip();
|
|
|
+ ctx.drawImage(res.path, x, y, width, height);
|
|
|
+ ctx.restore();
|
|
|
+ } else {
|
|
|
+ // 普通图片直接绘制
|
|
|
+ ctx.drawImage(res.path, x, y, width, height);
|
|
|
+ }
|
|
|
+ callback && callback();
|
|
|
+ } catch (e) {
|
|
|
+ console.log('绘制图片失败', e);
|
|
|
+ callback && callback();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fail: function(err) {
|
|
|
+ console.log('获取图片失败', err, imageUrl);
|
|
|
+ // 如果是头像且获取失败,使用默认头像
|
|
|
+ if (isAvatar) {
|
|
|
+ const defaultAvatar = that.data.appAssetsUrl + '/images/bz1_nor.png';
|
|
|
+ if (defaultAvatar !== imageUrl) {
|
|
|
+ // 重试默认头像
|
|
|
+ that.drawImageWithRetry(ctx, defaultAvatar, x, y, width, height, true, callback);
|
|
|
+ } else {
|
|
|
+ // 默认头像也失败了,直接回调
|
|
|
+ callback && callback();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 非头像图片失败,直接回调
|
|
|
+ callback && callback();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 绘制base64格式的图片
|
|
|
+ drawBase64Image(ctx, base64Data, x, y, width, height, isAvatar, callback) {
|
|
|
+ try {
|
|
|
+ const that = this;
|
|
|
+ // 创建文件管理器
|
|
|
+ const fsm = wx.getFileSystemManager();
|
|
|
+ // 生成临时文件路径
|
|
|
+ const filePath = `${wx.env.USER_DATA_PATH}/temp_image_${Date.now()}_${Math.floor(Math.random() * 1000)}.png`;
|
|
|
+
|
|
|
+ // 清理base64数据
|
|
|
+ let imageData = base64Data;
|
|
|
+ if (imageData.includes('data:image')) {
|
|
|
+ imageData = imageData.split(',')[1];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 将base64数据写入临时文件
|
|
|
+ fsm.writeFile({
|
|
|
+ filePath: filePath,
|
|
|
+ data: imageData,
|
|
|
+ encoding: 'base64',
|
|
|
+ success: function () {
|
|
|
+ try {
|
|
|
+ // 绘制图片
|
|
|
+ if (isAvatar) {
|
|
|
+ // 如果是头像,需要圆形裁剪
|
|
|
+ ctx.save();
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.arc(x + width / 2, y + height / 2, width / 2, 0, 2 * Math.PI);
|
|
|
+ ctx.clip();
|
|
|
+ ctx.drawImage(filePath, x, y, width, height);
|
|
|
+ ctx.restore();
|
|
|
+ } else {
|
|
|
+ // 普通图片直接绘制
|
|
|
+ ctx.drawImage(filePath, x, y, width, height);
|
|
|
+ }
|
|
|
+ // 延迟删除临时文件,确保绘制完成
|
|
|
+ setTimeout(() => {
|
|
|
+ try {
|
|
|
+ fsm.unlinkSync(filePath);
|
|
|
+ } catch (e) {
|
|
|
+ console.log('删除临时文件失败', e);
|
|
|
+ }
|
|
|
+ }, 1000);
|
|
|
+ callback && callback();
|
|
|
+ } catch (e) {
|
|
|
+ console.log('绘制base64图片失败', e);
|
|
|
+ // 清理临时文件
|
|
|
+ try {
|
|
|
+ fsm.unlinkSync(filePath);
|
|
|
+ } catch (e) {
|
|
|
+ console.log('删除临时文件失败', e);
|
|
|
+ }
|
|
|
+ callback && callback();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fail: function (err) {
|
|
|
+ console.log('写入base64图片失败', err);
|
|
|
+ callback && callback();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } catch (e) {
|
|
|
+ console.log('处理base64图片异常', e);
|
|
|
+ callback && callback();
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 导出canvas到图片
|
|
|
+ exportCanvasToImage() {
|
|
|
+ const that = this;
|
|
|
+ wx.canvasToTempFilePath({
|
|
|
+ canvasId: 'myCanvas',
|
|
|
+ success: function(res) {
|
|
|
+ wx.hideLoading();
|
|
|
+ // 保存图片到相册
|
|
|
+ that.saveImageToPhotosAlbum(res.tempFilePath);
|
|
|
+ },
|
|
|
+ fail: function(err) {
|
|
|
+ wx.hideLoading();
|
|
|
+ console.log('生成海报失败', err);
|
|
|
+ wx.showToast({
|
|
|
+ title: '生成海报失败',
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }, that);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 保存图片到相册
|
|
|
+ saveImageToPhotosAlbum(filePath) {
|
|
|
+ wx.saveImageToPhotosAlbum({
|
|
|
+ filePath: filePath,
|
|
|
+ success: function() {
|
|
|
+ wx.showToast({
|
|
|
+ title: '已保存到相册',
|
|
|
+ icon: 'success'
|
|
|
+ });
|
|
|
+ },
|
|
|
+ fail: function(err) {
|
|
|
+ console.log('保存失败', err);
|
|
|
+ wx.showToast({
|
|
|
+ title: '保存失败',
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
//将base64图片转网络图片
|
|
|
sendCode() {
|
|
|
let code = this.data.invitationCodeImg;
|
|
|
@@ -203,4 +466,4 @@ Page({
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
-})
|
|
|
+})
|