feat(private): 订场页改为 订场/我的预定 Tab切换 + 历史列表只显示近10天+未来

- 顶部Tab从羽毛球改为 订场/我的预定
- 我的预定: 卡片列表展示已预约记录,点击跳转详情
- 我的预定只显示最近10天到未来的已预约记录
- 移除未使用的 openTime/closeTime/historyLoaded
- 修复 -radius-md 变量不存在的问题
This commit is contained in:
gqt
2026-08-14 15:56:59 +08:00
parent 30c2b5ffea
commit 7dc0314565
@@ -2,14 +2,15 @@
<view class="private-page">
<view class="tab-bar">
<view
v-for="item in typeOptions"
:key="item.value"
v-for="tab in mainTabs"
:key="tab.value"
class="tab-item"
:class="{ active: courtType === item.value }"
@tap="selectType(item.value)"
>{{ item.label }}</view>
:class="{ active: activeTab === tab.value }"
@tap="switchTab(tab.value)"
>{{ tab.label }}</view>
</view>
<template v-if="activeTab === 'booking'">
<scroll-view scroll-x class="date-bar" :show-scrollbar="false">
<view class="date-list">
<view
@@ -86,6 +87,22 @@
<button class="primary-button submit-btn" :disabled="!canConfirm" @tap="goConfirm">预约</button>
</template>
</view>
</template>
<template v-else-if="activeTab === 'history'">
<scroll-view scroll-y class="history-scroll" @scrolltolower="loadHistory()">
<view v-for="item in historyList" :key="item.id" class="history-card" @tap="goBookingDetail(item)">
<view class="history-card-top">
<text class="history-court">{{ historyCourtNames(item) }}</text>
<text class="history-status">{{ item.status_label }}</text>
</view>
<text class="history-time">{{ historyTimeText(item) }}</text>
<text class="history-amount">¥{{ item.order?.amount || '--' }}</text>
</view>
<view v-if="historyLoading" class="history-tip">加载中...</view>
<view v-else-if="historyList.length === 0" class="history-empty">暂无预定记录</view>
</scroll-view>
</template>
</view>
</template>
@@ -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;
}
</style>