| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- <template>
- <view class="mine-page">
- <view class="section-card">
- <text class="section-title">我的沙龙</text>
- <text class="card-desc">查看报名、现场签到与会后反馈</text>
- <view v-if="loading" class="empty-tip">加载中…</view>
- <view v-else-if="list.length === 0" class="empty-tip">暂无报名记录</view>
- <view v-else>
- <view class="salon-card" v-for="item in list" :key="item.enrollmentId">
- <view class="salon-head">
- <text class="salon-theme">{{ mapTheme(item.theme) }}</text>
- <view class="head-right">
- <text class="salon-state" :class="stateClass(item.displayStatus)">{{ stateText(item.displayStatus) }}</text>
- <text class="salon-status" v-if="item.checkedIn">已签到</text>
- </view>
- </view>
- <text class="salon-title">{{ item.title }}</text>
- <view class="salon-info">
- <view class="info-item">
- <text class="info-label">时间:</text>
- <text class="info-value">{{ item.time }}</text>
- </view>
- <view class="info-item">
- <text class="info-label">地点:</text>
- <text class="info-value">{{ item.place }}</text>
- </view>
- <view class="info-item">
- <text class="info-label">报名:</text>
- <text class="info-value">{{ statusText(item.status) }}</text>
- </view>
- </view>
- <view class="salon-foot">
- <button
- v-if="canCheckin(item)"
- class="mini-btn primary"
- :loading="checking"
- :disabled="checking"
- @click="handleCheckin(item)"
- >现场签到</button>
- <text v-else-if="item.checkedIn" class="foot-tip">已完成签到</text>
- <button
- v-if="canFeedback(item)"
- class="mini-btn plain"
- :disabled="submitting"
- @click="goFeedback(item)"
- >{{ item.feedbackSubmitted ? '查看反馈' : '去反馈' }}</button>
- <button
- v-if="isUnpaid(item)"
- class="mini-btn plain"
- @click="goPay(item)"
- >去支付</button>
- </view>
- </view>
- </view>
- </view>
- </view>
- </template>
- <script>
- import { getMySalons, salonCheckin } from '@/utils/api.js'
- import { guardPage } from '@/utils/guard.js'
- export default {
- data() {
- return {
- list: [],
- loading: false,
- checking: false,
- submitting: false,
- themeMap: {
- ai_basic: 'AI 认知基础',
- wealth: '家庭财富管理',
- health: '健康管理',
- growth: '孩子成长陪伴'
- }
- }
- },
- onShow() {
- if (!guardPage()) return
- this.loadMine()
- },
- methods: {
- mapTheme: function(theme) {
- return this.themeMap[theme] || theme || '通用主题'
- },
- statusText: function(status) {
- var map = {
- pending: '待支付',
- paid: '已支付',
- confirmed: '已确认',
- rejected: '已拒绝',
- cancelled: '已取消'
- }
- return map[status] || status || ''
- },
- stateText: function(s) {
- var map = { ended: '已结束', ongoing: '进行中', pending_start: '未开始', active: '进行中', draft: '草稿' }
- return map[s] || s || ''
- },
- stateClass: function(s) {
- if (s === 'ended' || s === 'draft') return 'state-end'
- if (s === 'pending_start') return 'state-wait'
- return 'state-go'
- },
- canCheckin: function(item) {
- // 已支付/已确认 + 时间窗内(displayStatus=ongoing)+ 未签到
- var inTime = item.displayStatus === 'ongoing'
- if (!inTime && !item.displayStatus) { inTime = item.salonStatus === 'active' }
- return (item.status === 'paid' || item.status === 'confirmed') && inTime && !item.checkedIn
- },
- canFeedback: function(item) {
- // 已支付/已确认即可反馈(已提交则入口改为查看)
- return item.status === 'paid' || item.status === 'confirmed'
- },
- isUnpaid: function(item) {
- return item.status === 'pending' && item.orderNo
- },
- loadMine: function() {
- var self = this
- self.loading = true
- getMySalons().then(function(resp) {
- self.list = resp.data || []
- }).catch(function() {
- uni.showToast({ title: '加载失败', icon: 'none' })
- }).finally(function() {
- self.loading = false
- })
- },
- handleCheckin: function(item) {
- var self = this
- if (self.checking) return
- self.checking = true
- salonCheckin(item.salonId).then(function(resp) {
- var data = resp && resp.data ? resp.data : {}
- var pts = data.pointsEarned || 0
- var msg = pts > 0 ? '签到成功,获得 ' + pts + ' 积分' : '签到成功'
- uni.showToast({ title: msg, icon: 'success' })
- item.checkedIn = true
- self.loadMine()
- }).catch(function(err) {
- uni.showToast({ title: (err && err.message) || '签到失败', icon: 'none' })
- }).finally(function() {
- self.checking = false
- })
- },
- goFeedback: function(item) {
- uni.navigateTo({
- url: '/pages/salon/feedback?salonId=' + item.salonId +
- '&title=' + encodeURIComponent(item.title)
- })
- },
- goPay: function(item) {
- uni.navigateTo({
- url: '/pages/pay/index?enrollmentId=' + item.enrollmentId
- })
- }
- }
- }
- </script>
- <style scoped>
- .mine-page { min-height: 100vh; background: #F5F5F5; padding: 32rpx; }
- .section-card { background: #FFF; border-radius: 16rpx; padding: 32rpx; }
- .section-title { display: block; font-size: 32rpx; font-weight: 700; color: #1E293B; margin-bottom: 8rpx; border-left: 8rpx solid #F97316; padding-left: 16rpx; }
- .card-desc { display: block; font-size: 26rpx; color: #64748B; margin-bottom: 24rpx; }
- .empty-tip { font-size: 26rpx; color: #94A3B8; padding: 32rpx 0; text-align: center; }
- .salon-card { border: 2rpx solid #E2E8F0; border-radius: 12rpx; padding: 24rpx; margin-bottom: 20rpx; }
- .salon-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8rpx; }
- .head-right { display: flex; align-items: center; gap: 12rpx; }
- .salon-state { font-size: 22rpx; font-weight: 600; padding: 2rpx 12rpx; border-radius: 4rpx; }
- .state-go { background: #DCFCE7; color: #16A34A; }
- .state-wait { background: #FFF7ED; color: #F97316; }
- .state-end { background: #F1F5F9; color: #94A3B8; }
- .salon-theme { display: block; background: #FFF7ED; color: #F97316; font-size: 22rpx; font-weight: 600; padding: 4rpx 12rpx; border-radius: 4rpx; }
- .salon-status { font-size: 22rpx; color: #22C55E; font-weight: 600; }
- .salon-title { display: block; font-size: 30rpx; font-weight: 600; color: #1E293B; margin-bottom: 12rpx; }
- .salon-info { margin-bottom: 16rpx; }
- .info-item { display: flex; align-items: center; margin-bottom: 4rpx; }
- .info-label { font-size: 24rpx; color: #64748B; width: 70rpx; flex-shrink: 0; }
- .info-value { font-size: 26rpx; color: #475569; }
- .salon-foot { display: flex; align-items: center; justify-content: flex-end; gap: 16rpx; }
- .mini-btn { height: 60rpx; line-height: 60rpx; font-size: 26rpx; border-radius: 30rpx; border: none; margin: 0; padding: 0 32rpx; }
- .mini-btn.primary { background: #F97316; color: #FFF; }
- .mini-btn.plain { background: #FFF; color: #F97316; border: 2rpx solid #F97316; }
- .mini-btn:active { opacity: 0.85; }
- .foot-tip { font-size: 24rpx; color: #94A3B8; }
- </style>
|