const { request } = require('../../utils/request.js'); // 预设的树冠挂载点(百分比坐标) const CANOPY_SLOTS = [ { x: 16, y: 34 }, { x: 27, y: 21 }, { x: 39, y: 14 }, { x: 52, y: 12 }, { x: 63, y: 18 }, { x: 74, y: 26 }, { x: 84, y: 38 }, { x: 12, y: 50 }, { x: 23, y: 46 }, { x: 34, y: 40 }, { x: 66, y: 40 }, { x: 78, y: 50 }, { x: 88, y: 30 }, { x: 45, y: 30 }, ]; // 标签颜色配置 const TAG_COLORS = { amber: { color: '#ffd700', bgColor: 'rgba(255, 215, 0, 0.9)', borderColor: 'rgba(255, 215, 0, 0.6)', shadowColor: 'rgba(255, 215, 0, 0.4)', }, red: { color: '#ff6b6b', bgColor: 'rgba(255, 107, 107, 0.9)', borderColor: 'rgba(255, 107, 107, 0.6)', shadowColor: 'rgba(255, 107, 107, 0.4)', }, jade: { color: '#51cf66', bgColor: 'rgba(81, 207, 102, 0.9)', borderColor: 'rgba(81, 207, 102, 0.6)', shadowColor: 'rgba(81, 207, 102, 0.4)', }, }; // 生成伪随机数(用于萤火虫和花瓣位置) function seeded(i, salt) { const v = Math.sin((i + 1) * 12.9898 + salt * 78.233) * 43758.5453; return v - Math.floor(v); } Page({ data: { wishes: [], recentWishes: [], loading: true, showCreateModal: false, wishContent: '', wishType: 'free', maxFreeLength: 20, maxPaidLength: 100, products: [], selectedProduct: null, fireflies: [], petals: [], }, onLoad() { this.initAmbiance(); this.loadWishes(); this.loadProducts(); }, onPullDownRefresh() { this.loadWishes().then(() => { wx.stopPullDownRefresh(); }); }, // 初始化氛围效果 initAmbiance() { // 萤火虫 const fireflies = []; for (let i = 0; i < 22; i++) { fireflies.push({ left: seeded(i, 1) * 100, top: seeded(i, 2) * 100, size: 2 + seeded(i, 3) * 4, duration: 2.5 + seeded(i, 4) * 3.5, delay: seeded(i, 5) * 4, }); } // 花瓣 const petals = []; for (let i = 0; i < 10; i++) { petals.push({ left: seeded(i, 6) * 100, size: 5 + seeded(i, 7) * 6, duration: 10 + seeded(i, 8) * 8, delay: seeded(i, 9) * 12, }); } this.setData({ fireflies, petals }); }, // 加载许愿 async loadWishes() { try { const res = await request({ url: '/api/wish/tree/1/wishes', method: 'GET', }); if (res.code === 0) { const wishes = this.formatWishes(res.data.list || []); this.setData({ wishes, recentWishes: wishes.slice(0, 8), loading: false, }); } } catch (err) { console.error('加载许愿失败:', err); const wishes = this.formatWishes(this.getMockWishes()); this.setData({ wishes, recentWishes: wishes.slice(0, 8), loading: false, }); } }, // 格式化许愿数据 formatWishes(list) { const colorKeys = Object.keys(TAG_COLORS); return list.map((wish, index) => { const slot = this.pickSlot(index); const colorKey = colorKeys[index % colorKeys.length]; const colors = TAG_COLORS[colorKey]; return { id: wish.id, content: wish.content, author: wish.author || '匿名', type: wish.type, x: slot.x, y: slot.y, color: colors.color, bgColor: colors.bgColor, borderColor: colors.borderColor, shadowColor: colors.shadowColor, swayDuration: 3.4 + (index % 5) * 0.6, swayDelay: (index % 7) * 0.35, isNew: false, }; }); }, // 选择挂载点 pickSlot(index) { const base = CANOPY_SLOTS[index % CANOPY_SLOTS.length]; const wrap = Math.floor(index / CANOPY_SLOTS.length); if (wrap === 0) return base; const jitterX = ((wrap * 37) % 9) - 4; const jitterY = ((wrap * 53) % 9) - 4; return { x: Math.min(92, Math.max(8, base.x + jitterX)), y: Math.min(58, Math.max(10, base.y + jitterY)), }; }, // 模拟许愿数据 getMockWishes() { return [ { id: 1, content: '愿家人平安喜乐,身体健康', author: '小满', type: 'paid' }, { id: 2, content: '希望今年考研上岸,一战成硕', author: '阿远', type: 'free' }, { id: 3, content: '愿世界温柔以待每一个努力的人', author: '林深', type: 'paid' }, { id: 4, content: '早日遇见那个对的人', author: '拾光', type: 'free' }, { id: 5, content: '祝爸妈身体硬朗,笑口常开', author: '念念', type: 'paid' }, { id: 6, content: '愿所求皆如愿,所行皆坦途', author: '白露', type: 'free' }, { id: 7, content: '希望新工作顺顺利利', author: '子夜', type: 'paid' }, { id: 8, content: '愿此生尽兴,赤诚善良', author: '青禾', type: 'free' }, { id: 9, content: '愿代码零bug,一次通过', author: '小测', type: 'paid' }, ]; }, // 加载许愿商品 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 }, { id: 2, name: '精品许愿条', price: 500, duration: 30 }, { id: 3, name: '至尊许愿条', price: 2000, duration: 90 }, ], }); } }, // 打开许愿弹窗 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, treeId: 1, }, }); 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: 1, }, }); if (res.code === 0) { wx.showToast({ title: '许愿成功', icon: 'success' }); this.closeCreateModal(); this.loadWishes(); } } } 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.loadWishes(); 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', }; }, });