feat: 添加许愿树功能和Go后端服务
- 新增许愿树页面(Canvas绘制、许愿条展示) - 新增许愿详情页面 - 新增许愿创建弹窗(免费/付费两种模式) - 新增网络请求封装 utils/request.js - 新增Go后端项目结构(Gin + Inertia.js) - 新增用户、订单、许愿数据模型 - 新增数据库迁移脚本 - 更新.gitignore补全忽略规则 - 更新.env.local配置(robot=2, 版本1.0.1) - 添加secrets目录说明文档
This commit is contained in:
@@ -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 : ''}`,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"navigationBarTitleText": "许愿详情",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user