Files
lunar-mini/mini/pages/wish-tree/wish-tree.js
T
gouki 11bfc15141 feat: 添加许愿树功能和Go后端服务
- 新增许愿树页面(Canvas绘制、许愿条展示)
- 新增许愿详情页面
- 新增许愿创建弹窗(免费/付费两种模式)
- 新增网络请求封装 utils/request.js
- 新增Go后端项目结构(Gin + Inertia.js)
- 新增用户、订单、许愿数据模型
- 新增数据库迁移脚本
- 更新.gitignore补全忽略规则
- 更新.env.local配置(robot=2, 版本1.0.1)
- 添加secrets目录说明文档
2026-08-06 12:26:29 +00:00

275 lines
7.2 KiB
JavaScript

const { request } = require('../../utils/request.js');
Page({
data: {
tree: null,
wishes: [],
loading: true,
canvasWidth: 375,
canvasHeight: 600,
showCreateModal: false,
wishContent: '',
wishType: 'free', // free: 免费, paid: 付费
maxFreeLength: 20,
maxPaidLength: 100,
products: [],
selectedProduct: null,
},
onLoad() {
this.loadWishTree();
this.loadProducts();
},
onPullDownRefresh() {
this.loadWishTree().then(() => {
wx.stopPullDownRefresh();
});
},
// 加载许愿树数据
async loadWishTree() {
try {
const res = await request({
url: '/api/wish/tree',
method: 'GET',
});
if (res.code === 0) {
this.setData({
tree: res.data.tree,
wishes: res.data.wishes || [],
loading: false,
});
this.drawTree();
}
} catch (err) {
console.error('加载许愿树失败:', err);
this.setData({ loading: false });
// 使用本地模拟数据
this.setData({
tree: { id: 1, name: '祈福许愿树', maxWishes: 100 },
wishes: this.getMockWishes(),
loading: false,
});
this.drawTree();
}
},
// 加载许愿商品
async loadProducts() {
try {
const res = await request({
url: '/api/wish/products',
method: 'GET',
});
if (res.code === 0) {
this.setData({ products: res.data.list || [] });
}
} catch (err) {
console.error('加载商品失败:', err);
// 使用默认商品
this.setData({
products: [
{ id: 1, name: '普通许愿条', price: 100, duration: 7, position: 0 },
{ id: 2, name: '精品许愿条', price: 500, duration: 30, position: 10 },
{ id: 3, name: '至尊许愿条', price: 2000, duration: 90, position: 100 },
],
});
}
},
// 模拟许愿数据
getMockWishes() {
return [
{ id: 1, content: '愿家人平安健康', type: 'paid', position: 10, isRobot: false },
{ id: 2, content: '事业顺利', type: 'free', position: 5, isRobot: false },
{ id: 3, content: '心想事成', type: 'paid', position: 20, isRobot: true },
{ id: 4, content: '考试通过', type: 'free', position: 3, isRobot: false },
{ id: 5, content: '财源广进', type: 'paid', position: 15, isRobot: false },
];
},
// 绘制许愿树
drawTree() {
const ctx = wx.createCanvasContext('wishTree', this);
const { canvasWidth, canvasHeight, wishes } = this.data;
// 清空画布
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
// 绘制树干
ctx.setFillStyle('#8B4513');
ctx.fillRect(canvasWidth / 2 - 20, canvasHeight - 150, 40, 150);
// 绘制树冠(圆形)
ctx.setFillStyle('#228B22');
ctx.beginPath();
ctx.arc(canvasWidth / 2, canvasHeight - 200, 120, 0, 2 * Math.PI);
ctx.fill();
// 绘制许愿条
wishes.forEach((wish, index) => {
const angle = (index / wishes.length) * 2 * Math.PI;
const radius = 80 + Math.random() * 40;
const x = canvasWidth / 2 + radius * Math.cos(angle);
const y = canvasHeight - 200 + radius * Math.sin(angle);
// 根据类型设置颜色
if (wish.type === 'paid') {
ctx.setFillStyle('#FFD700'); // 金色 - 付费
} else {
ctx.setFillStyle('#FF6B6B'); // 红色 - 免费
}
// 绘制许愿条(小矩形)
ctx.fillRect(x - 15, y - 5, 30, 10);
// 绘制文字
ctx.setFillStyle('#FFFFFF');
ctx.setFontSize(8);
ctx.setTextAlign('center');
ctx.fillText(wish.content.substring(0, 4), x, y + 3);
});
ctx.draw();
},
// 打开许愿弹窗
openCreateModal() {
this.setData({ showCreateModal: true });
},
// 关闭许愿弹窗
closeCreateModal() {
this.setData({
showCreateModal: false,
wishContent: '',
wishType: 'free',
selectedProduct: null,
});
},
// 输入许愿内容
onInputContent(e) {
this.setData({ wishContent: e.detail.value });
},
// 选择许愿类型
selectType(e) {
const type = e.currentTarget.dataset.type;
this.setData({ wishType: type });
},
// 选择商品
selectProduct(e) {
const id = e.currentTarget.dataset.id;
const product = this.data.products.find(p => p.id === id);
this.setData({ selectedProduct: product });
},
// 提交许愿
async submitWish() {
const { wishContent, wishType, selectedProduct } = this.data;
if (!wishContent.trim()) {
wx.showToast({ title: '请输入许愿内容', icon: 'none' });
return;
}
// 检查字数限制
const maxLength = wishType === 'free' ? this.data.maxFreeLength : this.data.maxPaidLength;
if (wishContent.length > maxLength) {
wx.showToast({ title: `最多输入${maxLength}个字`, icon: 'none' });
return;
}
// 付费许愿需要选择商品
if (wishType === 'paid' && !selectedProduct) {
wx.showToast({ title: '请选择许愿商品', icon: 'none' });
return;
}
try {
// 如果是付费许愿,先创建订单
if (wishType === 'paid') {
const orderRes = await request({
url: '/api/pay/create',
method: 'POST',
data: {
type: 'wish',
productId: selectedProduct.id,
content: wishContent,
},
});
if (orderRes.code === 0) {
// 调起微信支付
await this.wxPay(orderRes.data);
}
} else {
// 免费许愿直接创建
const res = await request({
url: '/api/wish/create',
method: 'POST',
data: {
content: wishContent,
type: 'free',
treeId: this.data.tree.id,
},
});
if (res.code === 0) {
wx.showToast({ title: '许愿成功', icon: 'success' });
this.closeCreateModal();
this.loadWishTree();
}
}
} catch (err) {
console.error('许愿失败:', err);
wx.showToast({ title: '许愿失败,请重试', icon: 'none' });
}
},
// 微信支付
async wxPay(orderData) {
return new Promise((resolve, reject) => {
wx.requestPayment({
timeStamp: orderData.timeStamp,
nonceStr: orderData.nonceStr,
package: orderData.package,
signType: orderData.signType,
paySign: orderData.paySign,
success: () => {
wx.showToast({ title: '支付成功', icon: 'success' });
this.closeCreateModal();
this.loadWishTree();
resolve();
},
fail: (err) => {
console.error('支付失败:', err);
wx.showToast({ title: '支付失败', icon: 'none' });
reject(err);
},
});
});
},
// 查看许愿详情
viewWishDetail(e) {
const id = e.currentTarget.dataset.id;
wx.navigateTo({
url: `/pages/wish-detail/wish-detail?id=${id}`,
});
},
// 分享
onShareAppMessage() {
return {
title: '快来许愿树许下你的愿望吧!',
path: '/pages/wish-tree/wish-tree',
};
},
});