feat: 添加许愿树功能和Go后端服务

- 新增许愿树页面(Canvas绘制、许愿条展示)
- 新增许愿详情页面
- 新增许愿创建弹窗(免费/付费两种模式)
- 新增网络请求封装 utils/request.js
- 新增Go后端项目结构(Gin + Inertia.js)
- 新增用户、订单、许愿数据模型
- 新增数据库迁移脚本
- 更新.gitignore补全忽略规则
- 更新.env.local配置(robot=2, 版本1.0.1)
- 添加secrets目录说明文档
This commit is contained in:
gouki
2026-08-06 12:26:29 +00:00
parent 9c178e6d49
commit 11bfc15141
31 changed files with 2025 additions and 1 deletions
+56
View File
@@ -0,0 +1,56 @@
const { request } = require('../../utils/request.js');
Page({
data: {
wish: null,
loading: true,
},
onLoad(options) {
const { id } = options;
if (id) {
this.loadWishDetail(id);
}
},
async loadWishDetail(id) {
try {
const res = await request({
url: `/api/wish/detail/${id}`,
method: 'GET',
});
if (res.code === 0) {
this.setData({
wish: res.data,
loading: false,
});
}
} catch (err) {
console.error('加载许愿详情失败:', err);
// 使用模拟数据
this.setData({
wish: {
id: id,
content: '愿家人平安健康,事业顺利,心想事成!',
type: 'paid',
createdAt: '2024-01-15 12:00:00',
user: {
nickname: '祈福用户',
avatar: '',
},
},
loading: false,
});
}
},
// 分享
onShareAppMessage() {
const { wish } = this.data;
return {
title: wish ? `我的愿望:${wish.content.substring(0, 20)}...` : '快来许愿吧!',
path: `/pages/wish-detail/wish-detail?id=${wish ? wish.id : ''}`,
};
},
});
+4
View File
@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "许愿详情",
"enablePullDownRefresh": false
}
+46
View File
@@ -0,0 +1,46 @@
<view class="container">
<view class="loading" wx:if="{{loading}}">
<text>加载中...</text>
</view>
<view class="wish-detail" wx:else>
<view class="wish-card {{wish.type}}">
<view class="wish-header">
<image class="avatar" src="{{wish.user.avatar || '/images/default-avatar.png'}}" mode="aspectFill"></image>
<view class="user-info">
<text class="nickname">{{wish.user.nickname}}</text>
<text class="time">{{wish.createdAt}}</text>
</view>
<view class="wish-badge" wx:if="{{wish.type === 'paid'}}">
<text>VIP</text>
</view>
</view>
<view class="wish-content">
<text>{{wish.content}}</text>
</view>
<view class="wish-footer">
<view class="wish-type">
<text class="type-tag {{wish.type}}">{{wish.type === 'paid' ? '付费许愿' : '免费许愿'}}</text>
</view>
<view class="wish-actions">
<button class="btn-action" bindtap="onShare">
<text class="icon">📤</text>
<text>分享</text>
</button>
</view>
</view>
</view>
<!-- 相关推荐 -->
<view class="recommend-section">
<view class="section-title">更多愿望</view>
<view class="recommend-list">
<view class="recommend-item" wx:for="{{[1,2,3]}}" wx:key="*this">
<text class="recommend-text">愿所有美好如期而至</text>
</view>
</view>
</view>
</view>
</view>
+145
View File
@@ -0,0 +1,145 @@
.container {
min-height: 100vh;
background: #FFFBF5;
padding: 30rpx;
}
.loading {
display: flex;
align-items: center;
justify-content: center;
height: 400rpx;
color: #999;
}
.wish-card {
background: #fff;
border-radius: 24rpx;
padding: 40rpx;
box-shadow: 0 4rpx 20rpx rgba(0,0,0,0.08);
}
.wish-card.paid {
border: 2rpx solid #FFD700;
}
.wish-header {
display: flex;
align-items: center;
gap: 20rpx;
margin-bottom: 30rpx;
}
.avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: #f0f0f0;
}
.user-info {
flex: 1;
}
.nickname {
display: block;
font-size: 28rpx;
font-weight: bold;
color: #333;
}
.time {
display: block;
font-size: 22rpx;
color: #999;
margin-top: 8rpx;
}
.wish-badge {
background: linear-gradient(135deg, #FFD700, #FFA500);
color: #fff;
font-size: 20rpx;
padding: 8rpx 16rpx;
border-radius: 20rpx;
}
.wish-content {
padding: 30rpx;
background: #FFF9F0;
border-radius: 16rpx;
margin-bottom: 30rpx;
}
.wish-content text {
font-size: 32rpx;
color: #333;
line-height: 1.8;
}
.wish-footer {
display: flex;
align-items: center;
justify-content: space-between;
}
.type-tag {
font-size: 22rpx;
padding: 8rpx 16rpx;
border-radius: 20rpx;
}
.type-tag.free {
background: #FFE4E1;
color: #FF6B6B;
}
.type-tag.paid {
background: #FFF8DC;
color: #DAA520;
}
.btn-action {
display: flex;
align-items: center;
gap: 8rpx;
background: #C41E3A;
color: #fff;
font-size: 24rpx;
padding: 12rpx 24rpx;
border-radius: 30rpx;
border: none;
}
.btn-action .icon {
font-size: 28rpx;
}
/* 推荐区域 */
.recommend-section {
margin-top: 40rpx;
}
.section-title {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
}
.recommend-list {
display: flex;
flex-direction: column;
gap: 16rpx;
}
.recommend-item {
padding: 24rpx;
background: #fff;
border-radius: 16rpx;
box-shadow: 0 2rpx 10rpx rgba(0,0,0,0.05);
}
.recommend-text {
font-size: 26rpx;
color: #666;
}