feat(private): 订场页改为 订场/我的预定 Tab切换 + 历史列表只显示近10天+未来
- 顶部Tab从羽毛球改为 订场/我的预定 - 我的预定: 卡片列表展示已预约记录,点击跳转详情 - 我的预定只显示最近10天到未来的已预约记录 - 移除未使用的 openTime/closeTime/historyLoaded - 修复 -radius-md 变量不存在的问题
This commit is contained in:
@@ -2,14 +2,15 @@
|
|||||||
<view class="private-page">
|
<view class="private-page">
|
||||||
<view class="tab-bar">
|
<view class="tab-bar">
|
||||||
<view
|
<view
|
||||||
v-for="item in typeOptions"
|
v-for="tab in mainTabs"
|
||||||
:key="item.value"
|
:key="tab.value"
|
||||||
class="tab-item"
|
class="tab-item"
|
||||||
:class="{ active: courtType === item.value }"
|
:class="{ active: activeTab === tab.value }"
|
||||||
@tap="selectType(item.value)"
|
@tap="switchTab(tab.value)"
|
||||||
>{{ item.label }}</view>
|
>{{ tab.label }}</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<template v-if="activeTab === 'booking'">
|
||||||
<scroll-view scroll-x class="date-bar" :show-scrollbar="false">
|
<scroll-view scroll-x class="date-bar" :show-scrollbar="false">
|
||||||
<view class="date-list">
|
<view class="date-list">
|
||||||
<view
|
<view
|
||||||
@@ -86,6 +87,22 @@
|
|||||||
<button class="primary-button submit-btn" :disabled="!canConfirm" @tap="goConfirm">预约</button>
|
<button class="primary-button submit-btn" :disabled="!canConfirm" @tap="goConfirm">预约</button>
|
||||||
</template>
|
</template>
|
||||||
</view>
|
</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>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -94,6 +111,8 @@ import { computed, onMounted, ref } from 'vue'
|
|||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { privateBookingApi } from '@/modules/comprehensive/api/privateBooking'
|
import { privateBookingApi } from '@/modules/comprehensive/api/privateBooking'
|
||||||
import { useComprehensiveSessionStore } from '@/modules/comprehensive/stores/session'
|
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'
|
import { toAmountNumber } from '@/modules/comprehensive/utils/money'
|
||||||
|
|
||||||
const HEADER_HEIGHT = 75
|
const HEADER_HEIGHT = 75
|
||||||
@@ -101,9 +120,11 @@ const CELL_HEIGHT = 107
|
|||||||
const TIME_COL_WIDTH = 128
|
const TIME_COL_WIDTH = 128
|
||||||
const COURT_COL_WIDTH = 149
|
const COURT_COL_WIDTH = 149
|
||||||
|
|
||||||
const typeOptions = [
|
const mainTabs = [
|
||||||
{ label: '羽毛球', value: 'badminton' }
|
{ label: '订场', value: 'booking' },
|
||||||
|
{ label: '我的预定', value: 'history' }
|
||||||
]
|
]
|
||||||
|
const activeTab = ref('booking')
|
||||||
|
|
||||||
const session = useComprehensiveSessionStore()
|
const session = useComprehensiveSessionStore()
|
||||||
const courtType = ref('badminton')
|
const courtType = ref('badminton')
|
||||||
@@ -115,6 +136,12 @@ const selectedCells = ref({})
|
|||||||
const now = ref(dayjs())
|
const now = ref(dayjs())
|
||||||
let loadRequestId = 0
|
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 bookingConfig = ref({ member_advance_days: 7, non_member_advance_days: 3 })
|
||||||
|
|
||||||
const weekDays = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']
|
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 occupationMap = computed(() => {
|
||||||
const map = {}
|
const map = {}
|
||||||
if (!grid.value) return map
|
if (!grid.value) return map
|
||||||
@@ -257,10 +281,59 @@ async function loadGrid() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectType(type) {
|
function switchTab(tab) {
|
||||||
if (courtType.value === type) return
|
if (activeTab.value === tab) return
|
||||||
courtType.value = type
|
activeTab.value = tab
|
||||||
loadGrid()
|
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) {
|
function selectDate(date) {
|
||||||
@@ -693,4 +766,65 @@ defineExpose({
|
|||||||
color: $text-color-light;
|
color: $text-color-light;
|
||||||
font-size: 24rpx;
|
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>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user