Ai_GirlFriend/xuniYou/pages/mine/invite.vue
2026-01-31 19:15:41 +08:00

263 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view>
<view class="body">
<view class="list">
<view class="poster-container">
<canvas canvas-id="posterCanvas" class="poster-canvas" :style="{ width: canvasWidth + 'px', height: canvasHeight + 'px' }"></canvas>
</view>
</view>
</view>
</view>
</template>
<script>
import {
} from '@/utils/api.js'
import notHave from '@/components/not-have.vue';
import topSafety from '@/components/top-safety.vue';
import tabBar from '@/components/tab-bar.vue';
export default {
components: {
notHave,
topSafety,
tabBar,
},
data() {
return {
canvasWidth: 300,
canvasHeight: 600, // 减小画布高度
posterImageUrl: '',
// 示例数据,实际应从用户信息获取
userInfo: {
name: '154****9090', // 原来的手机号改为用户名
phone: '邀请您加入聊天', // 原来的姓名改为邀请文案
avatar: '/static/images/avatar.png' // 头像路径
},
topImageRatio: 0, // 顶部图片的宽高比
topImageLocalPath: '', // 顶部图片本地路径
qrCodeLocalPath: '' // 二维码图片本地路径
}
},
onLoad() {
this.initCanvas();
},
onReady() {
// 页面准备完成后自动生成海报
setTimeout(() => {
this.downloadImages().then(() => {
this.generatePoster();
}).catch(err => {
console.error('下载图片失败:', err);
uni.hideLoading();
uni.showToast({
title: '图片加载失败',
icon: 'none'
});
});
}, 500);
},
methods: {
initCanvas() {
// 获取设备信息来自适应不同屏幕
const systemInfo = uni.getSystemInfoSync();
// 设置canvas宽度为屏幕宽度的90%,减少左右边距
this.canvasWidth = systemInfo.windowWidth * 0.9;
// 设置canvas高度
this.canvasHeight = this.canvasWidth * 2.0; // 减小长宽比到1.8:1
},
// 下载线上图片到本地临时文件
async downloadImages() {
return new Promise((resolve, reject) => {
uni.showLoading({
title: '图片加载中...'
});
// 同时下载两个图片
Promise.all([
this.downloadImage('https://nvlovers.oss-cn-qingdao.aliyuncs.com/uploads/20251226/cb61a8209c59166e5a56e9c5c470e8f1.png'),
this.downloadImage('https://nvlovers.oss-cn-qingdao.aliyuncs.com/uploads/20251226/54a0da02080e49dbf2d6412791c58281.png')
]).then(([topImagePath, qrCodePath]) => {
this.topImageLocalPath = topImagePath;
this.qrCodeLocalPath = qrCodePath;
// 获取顶部图片信息
uni.getImageInfo({
src: topImagePath,
success: (res) => {
// 计算图片的宽高比
this.topImageRatio = res.width / res.height;
resolve();
},
fail: (err) => {
console.error('获取图片信息失败:', err);
// 如果获取失败,使用默认比例
this.topImageRatio = 3; // 默认宽高比 3:1
resolve();
}
});
}).catch(err => {
console.error('下载图片失败:', err);
reject(err);
});
});
},
// 下载单个图片
downloadImage(url) {
return new Promise((resolve, reject) => {
uni.downloadFile({
url: url,
success: (res) => {
if (res.statusCode === 200) {
resolve(res.tempFilePath);
} else {
reject(new Error(`下载失败: ${res.statusCode}`));
}
},
fail: (err) => {
reject(err);
}
});
});
},
// 绘制圆角矩形的方法
drawRoundedRect(ctx, x, y, width, height, radius) {
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.closePath();
ctx.fill();
},
generatePoster() {
uni.showLoading({
title: '海报生成中...'
});
const ctx = uni.createCanvasContext('posterCanvas', this);
// 清空画布
ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
// 绘制圆角背景
ctx.setFillStyle('#ffffff');
this.drawRoundedRect(ctx, 0, 0, this.canvasWidth, this.canvasHeight, 20);
// 计算居中位置
const centerX = this.canvasWidth / 2;
// 绘制顶部图片宽度与canvas一致高度自适应
const topImageWidth = this.canvasWidth;
// 根据图片原始宽高比计算高度
const topImageHeight = this.topImageRatio > 0 ? topImageWidth / this.topImageRatio : topImageWidth * 0.3;
const topImageX = 0;
const topImageY = 0; // 紧贴顶部
ctx.drawImage(this.topImageLocalPath, topImageX, topImageY, topImageWidth, topImageHeight);
// 绘制二维码,减小尺寸
const qrCodeSize = this.canvasWidth * 0.5; // 减小二维码尺寸
const qrCodeY = topImageHeight + 30; // 减少间距
const qrCodeX = (this.canvasWidth - qrCodeSize) / 2;
ctx.drawImage(this.qrCodeLocalPath, qrCodeX, qrCodeY, qrCodeSize, qrCodeSize);
// 绘制用户信息区域
const userInfoY = qrCodeY + qrCodeSize + 10;
const avatarSize = this.canvasWidth * 0.15;
// 计算头像和文字的整体高度,用于居中对齐
const textHeight = 40; // 文字区域高度估算
const totalHeight = Math.max(avatarSize, textHeight);
const avatarY = userInfoY + (totalHeight - avatarSize) / 2;
const textY = userInfoY + (totalHeight - textHeight) / 2;
// 头像居中对齐
const avatarX = (this.canvasWidth - (avatarSize + this.canvasWidth * 0.4)) / 2;
// 绘制头像
ctx.save();
ctx.beginPath();
ctx.arc(avatarX + avatarSize/2, avatarY + avatarSize/2, avatarSize/2, 0, 2 * Math.PI);
ctx.clip();
ctx.drawImage(this.userInfo.avatar, avatarX, avatarY, avatarSize, avatarSize);
ctx.restore();
// 绘制姓名和手机号(现在是手机号和邀请文案),与头像垂直居中对齐
const textAreaX = avatarX + avatarSize + 20;
ctx.setTextAlign('left');
ctx.setFontSize(18);
ctx.setFillStyle('#333333');
ctx.fillText(this.userInfo.name, textAreaX, textY + 20); // 垂直居中显示手机号
ctx.setFontSize(14);
ctx.setFillStyle('#999999');
ctx.fillText(this.userInfo.phone, textAreaX, textY + 45); // 垂直居中显示邀请文案
// 绘制完成,导出图片
ctx.draw(false, () => {
// 延迟执行以确保绘制完成
setTimeout(() => {
uni.canvasToTempFilePath({
canvasId: 'posterCanvas',
success: (res) => {
this.posterImageUrl = res.tempFilePath;
uni.hideLoading();
uni.showToast({
title: '海报生成成功',
icon: 'success'
});
},
fail: (err) => {
console.error('生成海报失败:', err);
uni.hideLoading();
uni.showToast({
title: '海报生成失败',
icon: 'none'
});
}
}, this);
}, 3000);
});
}
}
}
</script>
<style>
page {
background: #FFFFFF;
}
</style>
<style>
.body {
position: relative;
padding: 0 20rpx; /* 减少左右padding */
}
.list {
position: relative;
margin: 20rpx 0 0 0;
}
.poster-container {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 30rpx;
}
.poster-canvas {
background-color: #f5f5f5;
/* 移除之前的圆角设置因为现在在canvas中绘制 */
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
}
</style>