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 }}
+
预约
+
+
+
+
+
+
+ {{ historyCourtNames(item) }}
+ {{ item.status_label }}
+
+ {{ historyTimeText(item) }}
+ ¥{{ item.order?.amount || '--' }}
+
+ 加载中...
+ 暂无预定记录
+
+
@@ -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;
+}