feat: 完善课程订阅
This commit is contained in:
@@ -56,8 +56,9 @@
|
||||
v-for="booking in upcomingBookings"
|
||||
:key="booking.id"
|
||||
class="booking-card"
|
||||
@tap="goDetail(booking)"
|
||||
>
|
||||
<view class="booking-stripe stripe--confirmed" />
|
||||
<view class="booking-stripe" :class="stripeClass(booking.status)" />
|
||||
<view class="booking-content">
|
||||
<view class="booking-header">
|
||||
<view class="booking-datetime">
|
||||
@@ -66,19 +67,26 @@
|
||||
{{ booking.timeSlot.startTime.slice(0, 5) }} - {{ booking.timeSlot.endTime.slice(0, 5) }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="status-badge badge--confirmed">
|
||||
<text class="status-text">已预约</text>
|
||||
<view class="status-badge" :class="statusBadgeClass(booking.status)">
|
||||
<text class="status-text">{{ statusLabel(booking.status) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="booking-footer">
|
||||
<view v-if="booking.status !== 'PENDING_CONFIRMATION'" class="booking-footer">
|
||||
<view class="booking-meta">
|
||||
<text class="meta-label">使用卡种</text>
|
||||
<text class="meta-value">{{ booking.membership.cardType.name }}</text>
|
||||
</view>
|
||||
<view class="cancel-btn" @tap="handleCancel(booking)">
|
||||
<view class="cancel-btn" @tap.stop="handleCancel(booking)">
|
||||
<text class="cancel-text">取消预约</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="booking-footer">
|
||||
<view class="booking-meta">
|
||||
<text class="meta-label">使用卡种</text>
|
||||
<text class="meta-value">{{ booking.membership.cardType.name }}</text>
|
||||
</view>
|
||||
<text class="pending-hint">等待老师确认</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -121,6 +129,7 @@
|
||||
v-for="booking in historyBookings"
|
||||
:key="booking.id"
|
||||
class="booking-card"
|
||||
@tap="goDetail(booking)"
|
||||
>
|
||||
<view class="booking-stripe" :class="stripeClass(booking.status)" />
|
||||
<view class="booking-content">
|
||||
@@ -190,7 +199,9 @@ const today = computed(() => formatDate(new Date()))
|
||||
const upcomingBookings = computed<BookingWithDetails[]>(() => {
|
||||
return safeBookings()
|
||||
.filter(
|
||||
(b) => b.status === BookingStatus.CONFIRMED && toDateStr(b.timeSlot.date) >= today.value,
|
||||
(b) =>
|
||||
(b.status === BookingStatus.PENDING_CONFIRMATION || b.status === BookingStatus.CONFIRMED) &&
|
||||
toDateStr(b.timeSlot.date) >= today.value,
|
||||
)
|
||||
.sort((a, b) => {
|
||||
const dateA = toDateStr(a.timeSlot.date)
|
||||
@@ -222,36 +233,39 @@ const historyBookings = computed<BookingWithDetails[]>(() => {
|
||||
const upcomingCount = computed(() => upcomingBookings.value.length)
|
||||
|
||||
// ─── Helpers ──────────────────────────────────────────────
|
||||
const STATUS_LABELS: Record<BookingStatus, string> = {
|
||||
const STATUS_LABELS: Record<string, string> = {
|
||||
[BookingStatus.PENDING_CONFIRMATION]: '待确认',
|
||||
[BookingStatus.CONFIRMED]: '已预约',
|
||||
[BookingStatus.CANCELLED]: '已取消',
|
||||
[BookingStatus.COMPLETED]: '已完成',
|
||||
[BookingStatus.NO_SHOW]: '未出席',
|
||||
}
|
||||
|
||||
const STATUS_BADGE_CLASSES: Record<BookingStatus, string> = {
|
||||
const STATUS_BADGE_CLASSES: Record<string, string> = {
|
||||
[BookingStatus.PENDING_CONFIRMATION]: 'badge--pending',
|
||||
[BookingStatus.CONFIRMED]: 'badge--confirmed',
|
||||
[BookingStatus.CANCELLED]: 'badge--cancelled',
|
||||
[BookingStatus.COMPLETED]: 'badge--completed',
|
||||
[BookingStatus.NO_SHOW]: 'badge--noshow',
|
||||
}
|
||||
|
||||
const STATUS_STRIPE_CLASSES: Record<BookingStatus, string> = {
|
||||
const STATUS_STRIPE_CLASSES: Record<string, string> = {
|
||||
[BookingStatus.PENDING_CONFIRMATION]: 'stripe--pending',
|
||||
[BookingStatus.CONFIRMED]: 'stripe--confirmed',
|
||||
[BookingStatus.CANCELLED]: 'stripe--cancelled',
|
||||
[BookingStatus.COMPLETED]: 'stripe--completed',
|
||||
[BookingStatus.NO_SHOW]: 'stripe--noshow',
|
||||
}
|
||||
|
||||
function statusLabel(status: BookingStatus): string {
|
||||
function statusLabel(status: string): string {
|
||||
return STATUS_LABELS[status] ?? status
|
||||
}
|
||||
|
||||
function statusBadgeClass(status: BookingStatus): string {
|
||||
function statusBadgeClass(status: string): string {
|
||||
return STATUS_BADGE_CLASSES[status] ?? ''
|
||||
}
|
||||
|
||||
function stripeClass(status: BookingStatus): string {
|
||||
function stripeClass(status: string): string {
|
||||
return STATUS_STRIPE_CLASSES[status] ?? ''
|
||||
}
|
||||
|
||||
@@ -297,6 +311,10 @@ function goBooking() {
|
||||
uni.switchTab({ url: '/pages/booking/index' })
|
||||
}
|
||||
|
||||
function goDetail(booking: BookingWithDetails) {
|
||||
uni.navigateTo({ url: `/pages/booking/detail?id=${booking.id}` })
|
||||
}
|
||||
|
||||
async function handleCancel(booking: BookingWithDetails) {
|
||||
const dateLabel = formatDateDisplay(booking.timeSlot.date)
|
||||
const timeLabel = booking.timeSlot.startTime.slice(0, 5)
|
||||
@@ -535,6 +553,7 @@ onMounted(() => {
|
||||
width: 8rpx;
|
||||
flex-shrink: 0;
|
||||
|
||||
&.stripe--pending { background: #f59e0b; }
|
||||
&.stripe--confirmed { background: $primary-dark; }
|
||||
&.stripe--completed { background: #66bb6a; }
|
||||
&.stripe--cancelled { background: #e0e0e0; }
|
||||
@@ -580,6 +599,7 @@ onMounted(() => {
|
||||
border-radius: 20rpx;
|
||||
flex-shrink: 0;
|
||||
|
||||
&.badge--pending { background: rgba(245, 158, 11, 0.12); }
|
||||
&.badge--confirmed { background: rgba(201, 168, 124, 0.12); }
|
||||
&.badge--completed { background: rgba(102, 187, 106, 0.12); }
|
||||
&.badge--cancelled { background: rgba(0, 0, 0, 0.04); }
|
||||
@@ -590,6 +610,7 @@ onMounted(() => {
|
||||
font-size: 22rpx;
|
||||
font-weight: 600;
|
||||
|
||||
.badge--pending & { color: #f59e0b; }
|
||||
.badge--confirmed & { color: $primary-dark; }
|
||||
.badge--completed & { color: #66bb6a; }
|
||||
.badge--cancelled & { color: #bbb; }
|
||||
@@ -650,6 +671,12 @@ onMounted(() => {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.pending-hint {
|
||||
font-size: 24rpx;
|
||||
color: #f59e0b;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* ── Spacer ──────────────────────────────────────────── */
|
||||
.scroll-bottom-spacer {
|
||||
height: 48rpx;
|
||||
|
||||
Reference in New Issue
Block a user