Files
chazhi/src/components/BookingTime.vue
wangxiaowei 90e9448b68 调试接口
2025-12-22 19:06:04 +08:00

230 lines
10 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<wd-popup v-model="showPopup" lock-scroll custom-style="border-radius: 32rpx 32rpx 0rpx 0rpx;" position="bottom">
<view class="relative pb-78rpx">
<view class="absolute top-18rpx right-30rpx" @click="showPopup = false">
<wd-img width="60rpx" height='60rpx' :src="`${OSS}icon/icon_close.png`"></wd-img>
</view>
<view class="text-36rpx text-[#121212] leading-50rpx text-center pt-50rpx pb-40rpx">选择时间</view>
<view class="">
<view class="booking-time">
<wd-tabs v-model="selectedDay" color="#4C9F44" @click="BookingTime.handleChangeTimeTab">
<scroll-view scroll-y class="!h-500rpx pb-100rpx">
<block v-for="(item, index) in day.time" :key="index">
<wd-tab :title="`${item.display}`" :name="item.display">
<view class="">
<view class=" mt-30rpx">
<view class="grid grid-cols-4 gap-x-20rpx gap-y-20rpx mx-30rpx">
<view v-for="item2 in item.time_slots" :key="item2.start_time"
class="h-72rpx rounded-16rpx flex items-center justify-center text-28rpx leading-40rpx"
:class="[
item2.disabled == 1
? 'bg-[#F7F7F7] text-[#C9C9C9]' // 禁用高亮
: selectedTime.some(t => t.date === item.date && t.time === item2.start_time)
? 'bg-[#F1F8F0] text-[#4C9F44]' // 选中高亮
: 'bg-[#F7F7F7] text-[#303133]', // 可选高亮
]" @click="item2.disabled == 0 && BookingTime.handleSelectTime(item2.start_time, item2.timestamp, item.time_slots, item.date, item.display)">
{{ item2.start_time }}
</view>
</view>
</view>
</view>
</wd-tab>
</block>
</scroll-view>
</wd-tabs>
<view class="">
<view>
<wd-gap height="2rpx" bg-color="#E5E5E5"></wd-gap>
</view>
<view class="">
<view class="w-full fixed bottom-0 left-0 right-0 bg-white h-152rpx text-32rpx leading-44rpx flex items-center justify-center leading-90rpx text-center">
<view class="w-330rpx h-90rpx bg-[#F6F7F8] rounded-8rpx text-[#303133] mr-30rpx" @click="BookingTime.handleResetSelectedTime">重置</view>
<view class="w-330rpx h-90rpx bg-[#4C9F44] rounded-8rpx text-[#fff]" @click="BookingTime.handleConfirmSelectedTime">
<text>确定</text>
<text v-if="countSelectedTime">{{countSelectedTime}}小时</text>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</wd-popup>
</template>
<script lang="ts" setup name="BookingTime">
import {toast} from '@/utils/toast'
const OSS = inject('OSS')
/**
* BookingTime 预约时间
* @description 茶室预约时间选择组件
*/
const props = defineProps({
modelValue: {
type: Boolean,
default: false
},
day: {
type: Object,
default: {}
},
})
// 初始化时间
onMounted(() => {
console.log("🚀 ~ day:", props.day)
})
/** 日期相关 **/
const days = ref<string[]>([])
const selectedDay = ref<number>(0)
// 支持跨天选择,结构为 { date, time, timestamp }
const selectedTime = ref<Array<{ date: string, time: string, timestamp: number }>>([])
const countSelectedTime = ref<number>(0)
const selectTimeIndex = ref<number>(0) // 选择的时间tab索引
const BookingTime = {
/**
* 选择时间段逻辑,支持跨天
* @param time 选择的时间字符串 "HH:MM"
* @param timestamp 选择的时间戳
* @param timeSlots 当前日期的所有时间段
* @param date 当前选择的日期 "2025-12-20"
* @param display 当前选择的日期展示 "12/20周六"
*/
handleSelectTime: (time: string, timestamp: number, timeSlots: any[], date: string, display: string) => {
// 获取当前tab的日期
const currentDate = props.day.time[selectTimeIndex.value].date
const idx = selectedTime.value.findIndex(t => t.date === currentDate && t.time === time)
if (selectedTime.value.length === 0 || selectedTime.value.length > 1) {
// 第一次点击或已选2个及以上重置为只选当前
selectedTime.value = [{ date: currentDate, time, timestamp }]
} else if (selectedTime.value.length === 1) {
// 第二次点击,做范围选择
const first = selectedTime.value[0]
const second = { date: currentDate, time, timestamp }
// 获取所有可选时间段(含跨天)
let allSlots = []
props.day.time.forEach(dayItem => {
dayItem.time_slots.forEach(slot => {
if (slot.disabled == 0) {
allSlots.push({ date: dayItem.date, time: slot.start_time, timestamp: slot.timestamp })
}
})
})
// 按 timestamp 排序
allSlots = allSlots.sort((a, b) => a.timestamp - b.timestamp)
// 找到 first 和 second 的索引
const idx1 = allSlots.findIndex(t => t.date === first.date && t.time === first.time)
const idx2 = allSlots.findIndex(t => t.date === second.date && t.time === second.time)
if (idx1 > -1 && idx2 > -1) {
const [start, end] = idx1 < idx2 ? [idx1, idx2] : [idx2, idx1]
selectedTime.value = allSlots.slice(start, end + 1)
} else {
// 找不到则只选当前
selectedTime.value = [second]
}
}
countSelectedTime.value = BookingTime.handleCalcContinuousHours(selectedTime.value.map(t => t.timestamp))
},
// 确认选择的时间
handleConfirmSelectedTime: () => {
if (selectedTime.value.length === 0) {
toast.info('请选择时间')
return
}
if (countSelectedTime.value < props.day.minimum_time) {
toast.info(props.day.minimum_time + '小时起订')
return
}
// 返回所有已选的时间段含日期、时间、timestamp及所有timestamp数组
const sortedSelected = selectedTime.value.slice().sort((a, b) => a.timestamp - b.timestamp)
const timestamps = sortedSelected.map(t => t.timestamp)
// 格式化时间戳为 2025-12-18 和 周三03/18
function formatDate(ts: number) {
const d = new Date(ts * 1000)
const y = d.getFullYear()
const m = (d.getMonth() + 1).toString().padStart(2, '0')
const day = d.getDate().toString().padStart(2, '0')
return `${y}-${m}-${day}`
}
function formatWeek(ts: number) {
const d = new Date(ts * 1000)
const weekArr = ['周日','周一','周二','周三','周四','周五','周六']
const week = weekArr[d.getDay()]
const m = (d.getMonth() + 1).toString().padStart(2, '0')
const day = d.getDate().toString().padStart(2, '0')
return `${week}${m}/${day}`
}
const dayTime = formatDate(timestamps[0])
const dayTitle = formatWeek(timestamps[0])
const data = {
selectedDay: dayTime,
selectedTime: sortedSelected,
selectedTimestamps: timestamps,
dayTitle,
dayTime,
countSelectedTime: countSelectedTime.value
}
emit('selectedTime', data)
showPopup.value = false
},
// 切换时间tab的时候不重置已选实现跨天选择
handleChangeTimeTab: (e: any) => {
selectTimeIndex.value = e.index
// 不重置 selectedTime
},
// 计算所有连续区间的小时数总和timestamps 为时间戳数组
handleCalcContinuousHours(timestamps: number[]): number {
if (timestamps.length < 1) return 0
const sorted = timestamps.slice().sort((a, b) => a - b)
let count = 0
let segment = 1
for (let i = 1; i < sorted.length; i++) {
if (sorted[i] - sorted[i - 1] === 1800) {
segment++
} else {
count += (segment - 1) * 0.5
segment = 1
}
}
count += (segment - 1) * 0.5
return count
},
// 重置选择的时间
handleResetSelectedTime: () => {
selectedTime.value = []
countSelectedTime.value = 0
},
}
const showPopup = computed({
get: () => props.modelValue,
set: (val: boolean) => emit('update:modelValue', val)
})
const emit = defineEmits(['update:modelValue', 'selectedTime'])
</script>
<script lang="ts">
export default {}
</script>
<style lang="scss">
</style>