| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- <template>
- <view class="container" v-if="wish">
- <!-- 心愿详情卡片 -->
- <view class="wish-card" :class="wish.status">
- <view class="wish-header">
- <text class="wish-title">{{ wish.title }}</text>
- <text class="wish-status" :class="wish.status">{{ wish.statusText }}</text>
- </view>
-
- <!-- 分类 -->
- <view class="wish-category" v-if="wish.category">
- <text class="category-tag">{{ wish.category }}</text>
- </view>
-
- <!-- 描述 -->
- <view class="wish-desc" v-if="wish.description">
- <text>{{ wish.description }}</text>
- </view>
-
- <!-- 积分信息 -->
- <view class="points-section" v-if="wish.pointsRequired">
- <view class="points-label">所需积分</view>
- <view class="points-value">
- <text class="points-num">{{ wish.pointsRequired }}</text>
- <text class="points-unit">分</text>
- </view>
-
- <!-- 进度条 -->
- <view class="progress-section" v-if="wish.status === 'active'">
- <view class="progress-bar">
- <view class="progress-fill" :style="{ width: wish.progress + '%' }"></view>
- </view>
- <text class="progress-text">
- 当前积分: {{ currentPoints }}分
- </text>
- </view>
- </view>
-
- <!-- 时间信息 -->
- <view class="time-info">
- <text class="time-text">创建于 {{ wish.createdAt }}</text>
- </view>
- </view>
-
- <!-- 操作按钮区 -->
- <view class="action-section">
- <!-- 积攒中:积分足够可申请兑换 -->
- <button
- v-if="wish.status === 'active' && currentPoints >= wish.pointsRequired"
- class="btn-primary"
- @click="requestExchange"
- >
- 申请兑换 ({{ wish.pointsRequired }}积分)
- </button>
-
- <!-- 积攒中:积分不足 -->
- <button
- v-if="wish.status === 'active' && currentPoints < wish.pointsRequired"
- class="btn-disabled"
- disabled
- >
- 还差{{ wish.pointsRequired - currentPoints }}积分可兑换
- </button>
-
- <!-- 待审批 -->
- <view v-if="wish.status === 'pending_exchange'" class="waiting-box">
- <text class="waiting-icon">⏳</text>
- <text class="waiting-text">等待家长审批中...</text>
- </view>
-
- <!-- 已批准,等待兑现 -->
- <view v-if="wish.status === 'approved'" class="waiting-box">
- <text class="waiting-icon">📦</text>
- <text class="waiting-text">家长正在准备中,请耐心等待</text>
- </view>
-
- <!-- 待收货:确认收货按钮 -->
- <button
- v-if="wish.status === 'exchanging'"
- class="btn-primary"
- @click="confirmReceived"
- >
- 确认收货
- </button>
-
- <!-- 已完成 -->
- <view v-if="wish.status === 'fulfilled'" class="fulfilled-box">
- <text class="fulfilled-icon">🎉</text>
- <text class="fulfilled-text">心愿已完成!</text>
- <text class="fulfilled-time">{{ wish.fulfilledAt }}</text>
- </view>
-
- <!-- 待定价 -->
- <view v-if="wish.status === 'draft'" class="waiting-box">
- <text class="waiting-icon">📝</text>
- <text class="waiting-text">等待家长定价中...</text>
- </view>
-
- <!-- 取消按钮(draft或active状态可取消) -->
- <button
- v-if="wish.status === 'draft' || wish.status === 'active'"
- class="btn-cancel"
- @click="cancelWish"
- >
- 取消心愿
- </button>
- </view>
- </view>
-
- <!-- 加载中 -->
- <view class="loading" v-else>
- <text>加载中...</text>
- </view>
- </template>
- <script>
- import {
- getWishById,
- requestWishExchange,
- confirmWishReceived,
- cancelWish as cancelWishApi,
- getPointsBalance
- } from '../../utils/api.js'
- export default {
- data() {
- return {
- wishId: null,
- wish: null,
- currentPoints: 0,
- memberId: ''
- }
- },
- onLoad(options) {
- this.wishId = options.id
- this.loadData()
- },
- methods: {
- async loadData() {
- try {
- // 获取心愿详情
- const res = await getWishById(this.wishId)
- this.wish = res.data
-
- // 获取当前积分
- this.memberId = uni.getStorageSync('currentChildId') || uni.getStorageSync('userId')
- const balanceRes = await getPointsBalance(this.memberId)
- this.currentPoints = (balanceRes.data && balanceRes.data.balance) || 0
- } catch (e) {
- console.error('加载心愿详情失败', e)
- uni.showToast({ title: '加载失败', icon: 'none' })
- }
- },
-
- async requestExchange() {
- uni.showModal({
- title: '申请兑换',
- content: `确定要兑换"${this.wish.title}"吗?\n将消耗${this.wish.pointsRequired}积分`,
- success: async (res) => {
- if (res.confirm) {
- try {
- await requestWishExchange(this.wishId)
- uni.showToast({ title: '已提交申请', icon: 'success' })
- this.loadData()
- } catch (e) {
- uni.showToast({ title: e.message || '申请失败', icon: 'none' })
- }
- }
- }
- })
- },
-
- async confirmReceived() {
- uni.showModal({
- title: '确认收货',
- content: `确定已收到"${this.wish.title}"吗?`,
- success: async (res) => {
- if (res.confirm) {
- try {
- await confirmWishReceived(this.wishId)
- uni.showToast({ title: '心愿已完成!', icon: 'success' })
- this.loadData()
- } catch (e) {
- uni.showToast({ title: '确认失败', icon: 'none' })
- }
- }
- }
- })
- },
-
- async cancelWish() {
- uni.showModal({
- title: '取消心愿',
- content: `确定要取消"${this.wish.title}"吗?`,
- success: async (res) => {
- if (res.confirm) {
- try {
- await cancelWishApi(this.wishId, '不想兑换了')
- uni.showToast({ title: '已取消', icon: 'success' })
- setTimeout(() => {
- uni.navigateBack()
- }, 1500)
- } catch (e) {
- uni.showToast({ title: '取消失败', icon: 'none' })
- }
- }
- }
- })
- }
- }
- }
- </script>
- <style scoped>
- .container {
- padding: 30rpx;
- min-height: 100vh;
- background: #f5f5f5;
- }
- .wish-card {
- background: #fff;
- border-radius: 20rpx;
- padding: 40rpx;
- margin-bottom: 30rpx;
- }
- .wish-card.draft { border-left: 8rpx solid #999; }
- .wish-card.active { border-left: 8rpx solid #10B981; }
- .wish-card.pending_exchange { border-left: 8rpx solid #F59E0B; }
- .wish-card.approved,
- .wish-card.exchanging { border-left: 8rpx solid #3B82F6; }
- .wish-card.fulfilled { border-left: 8rpx solid #8B5CF6; }
- .wish-header {
- display: flex;
- justify-content: space-between;
- align-items: flex-start;
- margin-bottom: 20rpx;
- }
- .wish-title {
- font-size: 36rpx;
- font-weight: bold;
- color: #333;
- flex: 1;
- }
- .wish-status {
- font-size: 24rpx;
- padding: 8rpx 20rpx;
- border-radius: 20rpx;
- background: #f0f0f0;
- color: #666;
- }
- .wish-status.active { background: #D1FAE5; color: #059669; }
- .wish-status.pending_exchange { background: #FEF3C7; color: #D97706; }
- .wish-status.exchanging { background: #DBEAFE; color: #2563EB; }
- .wish-status.fulfilled { background: #EDE9FE; color: #7C3AED; }
- .category-tag {
- font-size: 24rpx;
- color: #666;
- background: #f5f5f5;
- padding: 6rpx 16rpx;
- border-radius: 12rpx;
- display: inline-block;
- margin-bottom: 20rpx;
- }
- .wish-desc {
- font-size: 28rpx;
- color: #666;
- line-height: 1.6;
- margin-bottom: 20rpx;
- padding: 20rpx;
- background: #f9f9f9;
- border-radius: 12rpx;
- }
- .points-section {
- background: linear-gradient(135deg, #F97316, #FB923C);
- border-radius: 15rpx;
- padding: 25rpx;
- color: #fff;
- margin-bottom: 20rpx;
- }
- .points-label {
- font-size: 24rpx;
- opacity: 0.9;
- }
- .points-value {
- margin-top: 10rpx;
- }
- .points-num {
- font-size: 48rpx;
- font-weight: bold;
- }
- .points-unit {
- font-size: 24rpx;
- margin-left: 5rpx;
- }
- .progress-section {
- margin-top: 20rpx;
- }
- .progress-bar {
- height: 12rpx;
- background: rgba(255,255,255,0.3);
- border-radius: 6rpx;
- overflow: hidden;
- }
- .progress-fill {
- height: 100%;
- background: #fff;
- border-radius: 6rpx;
- }
- .progress-text {
- font-size: 22rpx;
- margin-top: 10rpx;
- display: block;
- }
- .time-info {
- margin-top: 20rpx;
- }
- .time-text {
- font-size: 24rpx;
- color: #999;
- }
- /* 操作区域 */
- .action-section {
- padding: 20rpx;
- }
- .btn-primary {
- background: linear-gradient(135deg, #F97316, #FB923C);
- color: #fff;
- font-size: 32rpx;
- padding: 24rpx;
- border-radius: 50rpx;
- margin-bottom: 20rpx;
- }
- .btn-disabled {
- background: #e5e7eb;
- color: #9ca3af;
- font-size: 32rpx;
- padding: 24rpx;
- border-radius: 50rpx;
- margin-bottom: 20rpx;
- }
- .btn-cancel {
- background: #fff;
- color: #999;
- font-size: 28rpx;
- padding: 20rpx;
- border-radius: 40rpx;
- border: 1rpx solid #ddd;
- }
- .waiting-box,
- .fulfilled-box {
- display: flex;
- flex-direction: column;
- align-items: center;
- padding: 40rpx;
- background: #fff;
- border-radius: 20rpx;
- margin-bottom: 20rpx;
- }
- .waiting-icon,
- .fulfilled-icon {
- font-size: 80rpx;
- margin-bottom: 20rpx;
- }
- .waiting-text,
- .fulfilled-text {
- font-size: 30rpx;
- color: #333;
- margin-bottom: 10rpx;
- }
- .fulfilled-time {
- font-size: 24rpx;
- color: #8B5CF6;
- }
- .loading {
- display: flex;
- justify-content: center;
- align-items: center;
- height: 100vh;
- color: #999;
- }
- </style>
|