diff --git a/miniprogram/.env b/miniprogram/.env
index 7fda9c6..e405b71 100644
--- a/miniprogram/.env
+++ b/miniprogram/.env
@@ -1,2 +1,2 @@
VITE_ICE_API_BASE_URL=https://venue.test.chatgqt.top
-VITE_COMPREHENSIVE_API_BASE_URL=https://venue2.test.chatgqt.top
\ No newline at end of file
+VITE_COMPREHENSIVE_API_BASE_URL=https://8002.frp.chatgqt.top
\ No newline at end of file
diff --git a/miniprogram/src/modules/comprehensive/api/privateBooking.js b/miniprogram/src/modules/comprehensive/api/privateBooking.js
index dd2e852..c789585 100644
--- a/miniprogram/src/modules/comprehensive/api/privateBooking.js
+++ b/miniprogram/src/modules/comprehensive/api/privateBooking.js
@@ -46,10 +46,8 @@ const toPrivateBookingOptions = (backendData = {}) => ({
court_type_label: backendData.court_type_label || '',
open_time: backendData.open_time || '',
close_time: backendData.close_time || '',
- unit_price: backendData.unit_price || '0.00',
- duration_units: toNumber(backendData.duration_units, 2),
+ duration_units: toNumber(backendData.duration_units, 1),
duration_minutes: toNumber(backendData.duration_minutes, 60),
- amount_per_court: backendData.amount_per_court || '0.00',
total_court_count: toNumber(backendData.total_court_count),
time_options: toArray(backendData.time_options).map(toPrivateTimeOption)
})
@@ -67,7 +65,8 @@ const toGridSlot = (backendSlot = {}) => ({
const toGridOccupation = (backendOcc = {}) => ({
court_id: backendOcc.court_id ?? null,
start_at: backendOcc.start_at || '',
- end_at: backendOcc.end_at || ''
+ end_at: backendOcc.end_at || '',
+ source_type: backendOcc.source_type || ''
})
const toPrivateBookingGrid = (backendData = {}) => ({
@@ -76,10 +75,10 @@ const toPrivateBookingGrid = (backendData = {}) => ({
court_type_label: backendData.court_type_label || '',
open_time: backendData.open_time || '',
close_time: backendData.close_time || '',
- unit_price: backendData.unit_price || '0.00',
courts: toArray(backendData.courts).map(toGridCourt),
time_slots: toArray(backendData.time_slots).map(toGridSlot),
- occupations: toArray(backendData.occupations).map(toGridOccupation)
+ occupations: toArray(backendData.occupations).map(toGridOccupation),
+ slot_prices: backendData.slot_prices || {}
})
export const privateBookingApi = {
diff --git a/miniprogram/src/pages/comprehensive/private/confirm.vue b/miniprogram/src/pages/comprehensive/private/confirm.vue
index 5642555..01a27da 100644
--- a/miniprogram/src/pages/comprehensive/private/confirm.vue
+++ b/miniprogram/src/pages/comprehensive/private/confirm.vue
@@ -21,7 +21,7 @@
费用明细
- 半小时段
+ 时段
{{ quote.unit_count }} 段
diff --git a/miniprogram/src/pages/comprehensive/private/index.vue b/miniprogram/src/pages/comprehensive/private/index.vue
index 243b474..e944762 100644
--- a/miniprogram/src/pages/comprehensive/private/index.vue
+++ b/miniprogram/src/pages/comprehensive/private/index.vue
@@ -61,7 +61,9 @@
class="grid-cell"
:class="getCellClass(court.id, si)"
@tap="toggleCell(court.id, si)"
- >
+ >
+ ¥{{ getCellPrice(court.id, si) }}
+
{
for (const court of grid.value.courts) {
status[court.id] = {}
const occs = occupationMap.value[court.id] || []
+ const courtPrices = grid.value?.slot_prices?.[court.id] || []
for (let si = 0; si < grid.value.time_slots.length; si++) {
const slot = grid.value.time_slots[si]
@@ -157,13 +160,23 @@ const cellStatus = computed(() => {
continue
}
- const isOccupied = occs.some((occ) => {
+ const overlappingOcc = occs.find((occ) => {
const occStart = dayjs(occ.start_at)
const occEnd = dayjs(occ.end_at)
return occStart.isBefore(slotEnd) && occEnd.isAfter(slotStart)
})
- status[court.id][si] = isOccupied ? 'occupied' : 'available'
+ if (overlappingOcc) {
+ status[court.id][si] = overlappingOcc.source_type === 'lock' ? 'locked' : 'occupied'
+ continue
+ }
+
+ if (!courtPrices[si]) {
+ status[court.id][si] = 'no_price'
+ continue
+ }
+
+ status[court.id][si] = 'available'
}
}
return status
@@ -180,7 +193,7 @@ const currentTimeTop = computed(() => {
const closeMin = parseTimeToMinutes(grid.value.close_time)
const currentMin = now.value.hour() * 60 + now.value.minute()
if (currentMin < openMin || currentMin > closeMin) return -1
- return HEADER_HEIGHT + ((currentMin - openMin) / 30) * CELL_HEIGHT
+ return HEADER_HEIGHT + ((currentMin - openMin) / 60) * CELL_HEIGHT
})
const selectedCourtCount = computed(() => Object.keys(selectedCells.value).length)
@@ -203,8 +216,15 @@ const selectionTimeText = computed(() => {
})
const selectionAmount = computed(() => {
- const priceVal = parseFloat(grid.value?.unit_price || '0')
- return (priceVal * selectedTotalSlots.value).toFixed(2)
+ let total = 0
+ for (const [courtId, slots] of Object.entries(selectedCells.value)) {
+ const prices = grid.value?.slot_prices?.[courtId] || []
+ for (const slotIndex of slots) {
+ const p = parseFloat(prices[slotIndex] || '0')
+ total += p
+ }
+ }
+ return total.toFixed(2)
})
onMounted(loadGrid)
@@ -249,6 +269,11 @@ function getCellClass(courtId, slotIndex) {
return { [`cell-${status}`]: true }
}
+function getCellPrice(courtId, slotIndex) {
+ const prices = grid.value?.slot_prices?.[courtId] || []
+ return prices[slotIndex] || ''
+}
+
function toggleCell(courtId, slotIndex) {
const status = cellStatus.value[courtId]?.[slotIndex]
if (status !== 'available') return
@@ -530,6 +555,19 @@ defineExpose({
height: 107rpx;
border-right: 1rpx solid $bg-color-hover;
border-bottom: 1rpx solid $bg-color-hover;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.cell-price {
+ font-size: 22rpx;
+ font-weight: 700;
+ color: $text-color-muted;
+}
+
+.cell-selected .cell-price {
+ color: #FFFFFF;
}
.cell-available {
@@ -544,6 +582,26 @@ defineExpose({
background: $bg-color-hover;
}
+.cell-locked {
+ background: $bg-color-hover;
+ position: relative;
+}
+
+.cell-locked::after {
+ content: '锁';
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ font-size: 20rpx;
+ font-weight: 700;
+ color: $text-color-light;
+}
+
+.cell-no_price {
+ background: $bg-color-hover;
+}
+
.cell-selected {
background: $color-primary;
}