diff --git a/miniprogram/src/pages/comprehensive/private/index.vue b/miniprogram/src/pages/comprehensive/private/index.vue index 1da2a76..c883d02 100644 --- a/miniprogram/src/pages/comprehensive/private/index.vue +++ b/miniprogram/src/pages/comprehensive/private/index.vue @@ -2,14 +2,15 @@ {{ item.label }} + :class="{ active: activeTab === tab.value }" + @tap="switchTab(tab.value)" + >{{ tab.label }} + + + + @@ -94,6 +111,8 @@ import { computed, onMounted, ref } from 'vue' import dayjs from 'dayjs' import { privateBookingApi } from '@/modules/comprehensive/api/privateBooking' import { useComprehensiveSessionStore } from '@/modules/comprehensive/stores/session' +import { bookingApi } from '@/modules/comprehensive/api/booking' +import { formatTimeRange } from '@/modules/comprehensive/utils/date' import { toAmountNumber } from '@/modules/comprehensive/utils/money' const HEADER_HEIGHT = 75 @@ -101,9 +120,11 @@ const CELL_HEIGHT = 107 const TIME_COL_WIDTH = 128 const COURT_COL_WIDTH = 149 -const typeOptions = [ - { label: '羽毛球', value: 'badminton' } +const mainTabs = [ + { label: '订场', value: 'booking' }, + { label: '我的预定', value: 'history' } ] +const activeTab = ref('booking') const session = useComprehensiveSessionStore() const courtType = ref('badminton') @@ -115,6 +136,12 @@ const selectedCells = ref({}) const now = ref(dayjs()) let loadRequestId = 0 +const historyList = ref([]) +const historyLoading = ref(false) +const historyPage = ref(1) +const historyPageSize = 20 +const historyHasMore = ref(true) + const bookingConfig = ref({ member_advance_days: 7, non_member_advance_days: 3 }) const weekDays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'] @@ -134,9 +161,6 @@ const dateOptions = computed(() => { }) }) -const openTime = computed(() => normalizeClock(grid.value?.open_time)) -const closeTime = computed(() => normalizeClock(grid.value?.close_time)) - const occupationMap = computed(() => { const map = {} if (!grid.value) return map @@ -257,10 +281,59 @@ async function loadGrid() { } } -function selectType(type) { - if (courtType.value === type) return - courtType.value = type - loadGrid() +function switchTab(tab) { + if (activeTab.value === tab) return + activeTab.value = tab + if (tab === 'history') { + loadHistory(true) + } +} + +async function loadHistory(reset = false) { + if (historyLoading.value) return + if (reset) { + historyPage.value = 1 + historyHasMore.value = true + } + if (!historyHasMore.value) return + historyLoading.value = true + try { + const data = await bookingApi.getPrivateBookings({ + page: historyPage.value, + pageSize: historyPageSize + }) + const tenDaysAgo = dayjs().subtract(10, 'day') + const booked = data.items.filter( + (item) => item.status === 'booked' && item.start_at && dayjs(item.start_at) >= tenDaysAgo + ) + if (reset) { + historyList.value = booked + } else { + historyList.value = [...historyList.value, ...booked] + } + historyHasMore.value = data.page * data.page_size < data.total + if (historyHasMore.value) historyPage.value++ + } catch { + if (reset) historyList.value = [] + } finally { + historyLoading.value = false + } +} + +function historyCourtNames(item) { + return item.courts?.map((c) => c.name).join('、') || '包场预约' +} + +function historyTimeText(item) { + if (!item.start_at || !item.end_at) return '-' + const start = dayjs(item.start_at) + return `${start.month() + 1}/${start.date()} ${formatTimeRange(item.start_at, item.end_at)}` +} + +function goBookingDetail(item) { + uni.navigateTo({ + url: `/pages/comprehensive/bookings/private-detail?id=${item.id}` + }) } function selectDate(date) { @@ -693,4 +766,65 @@ defineExpose({ color: $text-color-light; font-size: 24rpx; } + +.history-empty { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + color: $text-color-light; + font-size: 24rpx; +} + +.history-scroll { + flex: 1; + min-height: 0; +} + +.history-card { + background: $bg-color-main; + border-radius: $border-radius-base; + padding: $spacing-md; + margin: $spacing-sm $spacing-md; + display: flex; + flex-direction: column; + gap: $spacing-xs; +} + +.history-card-top { + display: flex; + justify-content: space-between; + align-items: center; +} + +.history-court { + font-size: 30rpx; + font-weight: 800; + color: $text-color-main; +} + +.history-status { + font-size: 22rpx; + font-weight: 700; + color: #52c41a; +} + +.history-time { + font-size: 26rpx; + font-weight: 600; + color: $text-color-regular; +} + +.history-amount { + font-size: 32rpx; + font-weight: 900; + color: $color-primary; +} + +.history-tip { + text-align: center; + padding: $spacing-md; + color: $text-color-light; + font-size: 24rpx; +}