Files
2026-06-29 10:54:33 +08:00

234 lines
5.9 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="container">
<view class="card filters">
<view class="row sc">
<view v-for="s in tabs" :key="s.value" class="chip" :class="{ on: s.value === active }" hover-class="none" @tap="setActive(s.value)">
{{ s.label }}
</view>
</view>
</view>
<view class="list">
<view v-for="c in viewList" :key="c.id" class="card item" @tap="open(c.id)">
<view class="row between">
<view class="n">{{ c.projectName }}</view>
<view class="tag">剩余 {{ c.remainingTimes }}</view>
</view>
<view class="muted meta">核销码{{ c.verifyCode }}</view>
<view class="muted meta" v-if="c.validText">有效期{{ c.validText }}</view>
<view class="row between meta2">
<view class="muted">状态{{ c.uiStatus }}</view>
<view class="amt">¥{{ c.amount }}</view>
</view>
<view class="row between ops" v-if="c.uiStatus === '未使用'">
<view class="btn btn-ghost ob" @tap.stop="book(c)">去使用预约</view>
<view class="btn btn-primary ob" @tap.stop="openCode(c)">核销码</view>
</view>
</view>
</view>
<AiFloat />
</view>
</template>
<script>
import AiFloat from '@/components/AiFloat.vue'
import { demoOrders } from '@/common/demoOrders'
function buildCoupons() {
const now = Date.now()
const extra = [
{
id: 'cp_demo_unused_001',
createdAt: now - 2 * 24 * 60 * 60 * 1000,
status: '待核销',
amount: 299,
projectId: 'p9',
projectName: '新客体验套餐 · 3 次',
durationMin: 60,
orderType: 'coupon',
couponTitle: '新客体验套餐 · 3 次',
couponPlanKey: 'package',
couponPlanLabel: '套餐',
validText: '有效期 90 天',
remainingTimes: 3,
verifyCode: 'VCCP20260621001'
},
{
id: 'cp_demo_pending_001',
createdAt: now - 6 * 24 * 60 * 60 * 1000,
status: '待付款',
amount: 168,
projectId: 'p2',
projectName: '深层清洁黑头管理',
durationMin: 75,
orderType: 'coupon',
couponTitle: '深层清洁黑头管理',
couponPlanKey: 'single',
couponPlanLabel: '单次券',
validText: '有效期 30 天',
remainingTimes: 1,
verifyCode: 'VCCP20260621002'
},
{
id: 'cp_demo_used_001',
createdAt: now - 18 * 24 * 60 * 60 * 1000,
status: '已完成',
amount: 899,
projectId: 'p5',
projectName: '皮肤管理次卡 5 次',
durationMin: 60,
orderType: 'coupon',
couponTitle: '皮肤管理次卡 5 次',
couponPlanKey: 'times5',
couponPlanLabel: '次卡 5 次',
validText: '有效期 180 天',
remainingTimes: 0,
verifyCode: 'VCCP20260621003'
},
{
id: 'cp_demo_expired_001',
createdAt: now - 65 * 24 * 60 * 60 * 1000,
status: '已过期',
amount: 99,
projectId: 'p1',
projectName: '水氧净透体验',
durationMin: 60,
orderType: 'coupon',
couponTitle: '水氧净透体验',
couponPlanKey: 'single',
couponPlanLabel: '单次券',
validText: '已过期(原型演示)',
remainingTimes: 1,
verifyCode: 'VCCP20260621004'
}
]
const all = [...demoOrders.filter((x) => x.orderType === 'coupon'), ...extra]
return all.map((x) => {
const uiStatus = x.status === '待核销' ? '未使用' : x.status === '已完成' ? '已核销' : x.status === '待付款' ? '待付款' : '已过期'
const group = uiStatus === '已核销' ? 'used' : uiStatus === '待付款' ? 'pending' : uiStatus === '已过期' ? 'expired' : 'unused'
return { ...x, uiStatus, group }
})
}
export default {
components: { AiFloat },
data() {
const coupons = buildCoupons()
const init = coupons.filter((x) => x.group === 'unused')
return {
tabs: [
{ value: 'unused', label: '未使用' },
{ value: 'used', label: '已核销' },
{ value: 'pending', label: '待付款' },
{ value: 'expired', label: '已过期' }
],
active: 'unused',
coupons,
viewList: init && init.length ? init : coupons.slice(0, 3)
}
},
onLoad() {
this.apply()
},
onShow() {
this.coupons = buildCoupons()
this.apply()
},
methods: {
apply() {
const v = this.coupons.filter((x) => x.group === this.active)
this.viewList = v && v.length ? v : this.coupons.slice(0, 3)
},
setActive(v) {
if (!v || v === this.active) return
this.active = v
this.apply()
},
open(id) {
const c = this.coupons.find((x) => x.id === id) || this.coupons[0]
const payload = encodeURIComponent(JSON.stringify(c))
uni.navigateTo({ url: `/pages/orders/detail?payload=${payload}` })
},
book(c) {
uni.navigateTo({ url: `/pages/booking/create?projectId=${c.projectId}` })
},
openCode(c) {
const payload = encodeURIComponent(JSON.stringify(c))
uni.navigateTo({ url: `/pages/verify/code?payload=${payload}` })
},
goProjects() {
uni.switchTab({ url: '/pages/projects/list' })
}
}
}
</script>
<style lang="scss" scoped>
.filters {
padding: 16rpx;
}
.sc {
white-space: nowrap;
}
.chip {
padding: 14rpx 18rpx;
margin-right: 12rpx;
border-radius: 999rpx;
font-size: 26rpx;
background: rgba(17, 24, 39, 0.06);
color: #111827;
flex: 0 0 auto;
}
.on {
background: rgba(59, 130, 246, 0.14);
color: #1d4ed8;
}
.empty {
margin-top: 18rpx;
padding: 26rpx;
}
.e1 {
font-size: 36rpx;
font-weight: 950;
}
.e2 {
margin-top: 10rpx;
font-size: 26rpx;
}
.ebtn {
margin-top: 18rpx;
}
.list {
margin-top: 18rpx;
}
.item {
padding: 22rpx;
margin-bottom: 18rpx;
}
.n {
font-size: 32rpx;
font-weight: 950;
max-width: 520rpx;
}
.meta {
margin-top: 12rpx;
font-size: 26rpx;
}
.meta2 {
margin-top: 10rpx;
}
.ops {
margin-top: 16rpx;
gap: 14rpx;
}
.ob {
flex: 1;
height: 80rpx;
}
.amt {
font-weight: 950;
}
</style>