21
This commit is contained in:
parent
05ad1348cf
commit
d085baf581
3
.vs/ProjectSettings.json
Normal file
3
.vs/ProjectSettings.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"CurrentProjectSetting": null
|
||||
}
|
||||
6
.vs/VSWorkspaceState.json
Normal file
6
.vs/VSWorkspaceState.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"ExpandedNodes": [
|
||||
""
|
||||
],
|
||||
"PreviewInSolutionExplorer": false
|
||||
}
|
||||
Binary file not shown.
BIN
.vs/mahjong_group.slnx/v18/.wsuo
Normal file
BIN
.vs/mahjong_group.slnx/v18/.wsuo
Normal file
Binary file not shown.
23
.vs/mahjong_group.slnx/v18/DocumentLayout.json
Normal file
23
.vs/mahjong_group.slnx/v18/DocumentLayout.json
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"Version": 1,
|
||||
"WorkspaceRootPath": "D:\\CodeManage\\Coreshop\\uniapp\\mahjong_group\\",
|
||||
"Documents": [],
|
||||
"DocumentGroupContainers": [
|
||||
{
|
||||
"Orientation": 0,
|
||||
"VerticalTabListWidth": 256,
|
||||
"DocumentGroups": [
|
||||
{
|
||||
"DockedWidth": 200,
|
||||
"SelectedChildIndex": -1,
|
||||
"Children": [
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
"Name": "ST:128:0:{116d2292-e37d-41cd-a077-ebacac4c8cc4}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
.vs/mahjong_group/v18/workspaceFileList.bin
Normal file
BIN
.vs/mahjong_group/v18/workspaceFileList.bin
Normal file
Binary file not shown.
BIN
.vs/slnx.sqlite
Normal file
BIN
.vs/slnx.sqlite
Normal file
Binary file not shown.
|
|
@ -8,8 +8,8 @@ const development = {
|
|||
// API基础URL
|
||||
baseUrl: 'https://sqqp.zpc-xy.com',
|
||||
host: ['https://sqqp.zpc-xy.com'],
|
||||
// baseUrl: 'http://192.168.195.15:2401',
|
||||
// host: ['http://192.168.195.15:2401'],
|
||||
// baseUrl: 'http://192.168.1.21:2016',
|
||||
// host: ['http://192.168.1.21:2016'],
|
||||
// baseUrl: 'http://192.168.1.24:2016',
|
||||
// host: ['http://192.168.1.24:2016'],
|
||||
imageUrl: 'https://guyu-1308826010.cos.ap-shanghai.myqcloud.com',
|
||||
|
|
|
|||
|
|
@ -14,23 +14,40 @@
|
|||
</view>
|
||||
</label-field>
|
||||
<view :style="{ height: lineHeight }"></view>
|
||||
<label-field label="时间段">
|
||||
<view v-if="roomDetailLoading" class="center" style="padding: 30rpx 0;">
|
||||
<text style="color: #999; font-size: 24rpx;">加载时段信息中...</text>
|
||||
</view>
|
||||
<uni-data-select v-else v-model="selectedTimeSlot" placeholder="请选择时间段"
|
||||
:localdata="timeSlotOptions" @change="onTimeSlotChange"></uni-data-select>
|
||||
<view v-if="!roomDetailLoading && timeSlotOptions.length === 0" style="padding: 20rpx 0;">
|
||||
<text style="color: #FF0000; font-size: 24rpx;">当前日期该房间暂无可预约时段</text>
|
||||
</view>
|
||||
<label-field label="开始时间">
|
||||
<picker mode="time" :value="startTime" @change="onStartTimeChange">
|
||||
<view class="picker-value">{{ startTime || '请选择开始时间' }}</view>
|
||||
</picker>
|
||||
</label-field>
|
||||
<view :style="{ height: lineHeight }"></view>
|
||||
<label-field label="最晚到店时间">
|
||||
<view class="input-wrapper" style="padding: 15rpx 20rpx;" @click="openLatestDateTimePicker">
|
||||
<text>{{ getLatestDateTimeDisplayText() }}</text>
|
||||
<label-field label="结束时间">
|
||||
<view class="end-time-row">
|
||||
<picker mode="time" :value="endTime" @change="onEndTimeChange">
|
||||
<view class="picker-value">{{ endTime || '请选择结束时间' }}</view>
|
||||
</picker>
|
||||
<view class="next-day-toggle" v-if="startTime && endTime">
|
||||
<text class="next-day-label" :class="{ active: !isNextDay }" @click="setNextDay(false)">当天</text>
|
||||
<text class="next-day-divider">/</text>
|
||||
<text class="next-day-label" :class="{ active: isNextDay }" @click="setNextDay(true)">次日</text>
|
||||
</view>
|
||||
</view>
|
||||
</label-field>
|
||||
</card-container>
|
||||
<!-- 时长和跨时段信息显示 -->
|
||||
<view class="time-info" v-if="startTime && endTime && !timeError">
|
||||
<view class="time-info-item">
|
||||
<text class="time-info-label">预计时长:</text>
|
||||
<text class="time-info-value">{{ calculateDuration() }}</text>
|
||||
</view>
|
||||
<view class="time-info-item">
|
||||
<text class="time-info-label">跨越时段:</text>
|
||||
<text class="time-info-value">{{ calculateCrossSlots() }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 时间错误提示 -->
|
||||
<view class="time-error" v-if="timeError">
|
||||
<text>{{ timeError }}</text>
|
||||
</view>
|
||||
</card-container>
|
||||
|
||||
<card-container marginTop="30rpx">
|
||||
|
||||
|
|
@ -137,14 +154,9 @@
|
|||
|
||||
</view>
|
||||
</view>
|
||||
<up-datetime-picker :show="datePickerVisible" v-model="datePickerValue" mode="date"
|
||||
:minDate="datePickerMinDate" :maxDate="datePickerMaxDate" title="选择日期" @confirm="onDatePickerConfirm"
|
||||
<up-datetime-picker :show="datePickerVisible" v-model="datePickerValue" mode="date"
|
||||
:minDate="datePickerMinDate" :maxDate="datePickerMaxDate" title="选择日期" @confirm="onDatePickerConfirm"
|
||||
@cancel="() => datePickerVisible = false" @close="() => datePickerVisible = false"></up-datetime-picker>
|
||||
<up-datetime-picker :show="latestDateTimePickerVisible" v-model="latestDateTimePickerValue" mode="time"
|
||||
:minHour="latestDateTimeMinHour" :maxHour="latestDateTimeMaxHour"
|
||||
:minMinute="latestDateTimeMinMinute" :maxMinute="latestDateTimeMaxMinute"
|
||||
title="选择最晚到店时间" @confirm="onLatestDateTimePickerConfirm"
|
||||
@cancel="() => latestDateTimePickerVisible = false" @close="() => latestDateTimePickerVisible = false"></up-datetime-picker>
|
||||
<up-picker title="年龄范围选择" :show="agePickerVisible" :columns="agePickerColumns" :keyName="'text'"
|
||||
:defaultIndex="agePickerDefaultIndex" @confirm="onAgePickerConfirm" @cancel="() => agePickerVisible = false"
|
||||
@close="() => agePickerVisible = false"></up-picker>
|
||||
|
|
@ -224,25 +236,19 @@
|
|||
const lineHeight = ref("15rpx")
|
||||
// 房间页跳转相关
|
||||
const selectedDate = ref(null) // 选中的日期时间戳(秒级)
|
||||
const selectedTimeSlot = ref(null) // 选中的时段类型 0-3,null表示未选择
|
||||
const roomDetail = ref(null) // 房间详情数据
|
||||
const roomDetailLoading = ref(false) // 房间详情加载状态
|
||||
const timeSlotOptions = ref([]) // 时间段选项,从房间详情动态生成
|
||||
// 自由时间选择相关
|
||||
const startTime = ref('') // 开始时间 "HH:mm"
|
||||
const endTime = ref('') // 结束时间 "HH:mm"
|
||||
const timeError = ref('') // 时间错误提示
|
||||
const isNextDay = ref(false) // 结束时间是否为次日(用于通宵预约)
|
||||
// 日期选择器状态
|
||||
const datePickerVisible = ref(false)
|
||||
const datePickerValue = ref(Date.now())
|
||||
const datePickerMinDate = ref(Date.now()) // 最小日期为今天
|
||||
// 最大日期为未来7天(今天+未来6天)
|
||||
const datePickerMaxDate = ref(new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).getTime())
|
||||
// 最晚到店时间选择器状态
|
||||
const latestDateTimePickerVisible = ref(false)
|
||||
const latestDateTimePickerValue = ref('00:00') // 时间选择器值(HH:MM格式字符串)
|
||||
const latestDateTime = ref(null) // 最晚到店时间(秒级时间戳)
|
||||
// 时间选择器范围限制
|
||||
const latestDateTimeMinHour = ref(0)
|
||||
const latestDateTimeMaxHour = ref(23)
|
||||
const latestDateTimeMinMinute = ref(0)
|
||||
const latestDateTimeMaxMinute = ref(59)
|
||||
//提交表单数据
|
||||
const reservationInfo = ref({
|
||||
room_id: 0, //房间id 非空
|
||||
|
|
@ -384,14 +390,15 @@
|
|||
|
||||
// 更新选中的日期
|
||||
selectedDate.value = selectedTimestamp;
|
||||
|
||||
// 重置时段选择
|
||||
selectedTimeSlot.value = null;
|
||||
|
||||
// 重置时间选择
|
||||
startTime.value = '';
|
||||
endTime.value = '';
|
||||
timeError.value = '';
|
||||
isNextDay.value = false; // 重置跨天标记
|
||||
reservationInfo.value.start_time = 0;
|
||||
reservationInfo.value.end_time = 0;
|
||||
// 重置最晚到店时间
|
||||
latestDateTime.value = null;
|
||||
|
||||
|
||||
// 重新加载房间详情
|
||||
if (reservationInfo.value.room_id) {
|
||||
console.log('重新加载房间详情, roomId:', reservationInfo.value.room_id, 'date:', selectedTimestamp);
|
||||
|
|
@ -400,284 +407,204 @@
|
|||
|
||||
datePickerVisible.value = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最晚到店时间显示文本
|
||||
* 开始时间变更处理
|
||||
*/
|
||||
const getLatestDateTimeDisplayText = () => {
|
||||
if (!latestDateTime.value) {
|
||||
return '请选择最晚到店时间';
|
||||
}
|
||||
const date = new Date(latestDateTime.value * 1000);
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
||||
const onStartTimeChange = (e) => {
|
||||
startTime.value = e.detail.value;
|
||||
validateTimeRange();
|
||||
buildTimeFromPicker();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取时间段的时间范围限制
|
||||
* 结束时间变更处理
|
||||
*/
|
||||
const getTimeSlotRange = () => {
|
||||
if (!selectedTimeSlot.value || selectedTimeSlot.value === null || selectedTimeSlot.value === undefined) {
|
||||
return { minHour: 0, maxHour: 23, minMinute: 0, maxMinute: 59 };
|
||||
}
|
||||
|
||||
let minHour = 0, maxHour = 23, minMinute = 0, maxMinute = 59;
|
||||
|
||||
switch (selectedTimeSlot.value) {
|
||||
case 0: // 凌晨 00:00-05:59
|
||||
minHour = 0;
|
||||
maxHour = 5;
|
||||
minMinute = 0;
|
||||
maxMinute = 59;
|
||||
break;
|
||||
case 1: // 上午 06:00-11:59
|
||||
minHour = 6;
|
||||
maxHour = 11;
|
||||
minMinute = 0;
|
||||
maxMinute = 59;
|
||||
break;
|
||||
case 2: // 下午 12:00-17:59
|
||||
minHour = 12;
|
||||
maxHour = 17;
|
||||
minMinute = 0;
|
||||
maxMinute = 59;
|
||||
break;
|
||||
case 3: // 晚上 18:00-23:59
|
||||
minHour = 18;
|
||||
maxHour = 23;
|
||||
minMinute = 0;
|
||||
maxMinute = 59;
|
||||
break;
|
||||
}
|
||||
|
||||
return { minHour, maxHour, minMinute, maxMinute };
|
||||
const onEndTimeChange = (e) => {
|
||||
endTime.value = e.detail.value;
|
||||
// 自动判断是否需要切换到次日
|
||||
autoDetectNextDay();
|
||||
validateTimeRange();
|
||||
buildTimeFromPicker();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 打开最晚到店时间选择器
|
||||
* 自动检测是否需要切换到次日(当结束时间小于开始时间时)
|
||||
*/
|
||||
const openLatestDateTimePicker = () => {
|
||||
if (!selectedDate.value) {
|
||||
uni.showToast({
|
||||
title: '请先选择日期',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
const autoDetectNextDay = () => {
|
||||
if (!startTime.value || !endTime.value) return;
|
||||
|
||||
const [startH, startM] = startTime.value.split(':').map(Number);
|
||||
const [endH, endM] = endTime.value.split(':').map(Number);
|
||||
const startMinutes = startH * 60 + startM;
|
||||
const endMinutes = endH * 60 + endM;
|
||||
|
||||
// 如果结束时间小于开始时间,自动切换到次日
|
||||
if (endMinutes <= startMinutes) {
|
||||
isNextDay.value = true;
|
||||
}
|
||||
|
||||
if (!selectedTimeSlot.value || selectedTimeSlot.value === null || selectedTimeSlot.value === undefined) {
|
||||
uni.showToast({
|
||||
title: '请先选择时间段',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置时间段范围限制
|
||||
const timeRange = getTimeSlotRange();
|
||||
latestDateTimeMinHour.value = timeRange.minHour;
|
||||
latestDateTimeMaxHour.value = timeRange.maxHour;
|
||||
latestDateTimeMinMinute.value = timeRange.minMinute;
|
||||
latestDateTimeMaxMinute.value = timeRange.maxMinute;
|
||||
|
||||
// 如果有选择时间段,使用自动计算的时间
|
||||
updateLatestDateTimeFromSlot();
|
||||
|
||||
// 将时间戳转换为 HH:MM 格式字符串
|
||||
let timeString = null;
|
||||
if (latestDateTime.value) {
|
||||
const date = new Date(latestDateTime.value * 1000);
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
timeString = `${hours}:${minutes}`;
|
||||
} else {
|
||||
// 默认使用时间段开始时间+30分钟
|
||||
const timeRangeForDefault = getTimeSlotRange();
|
||||
let defaultHour = timeRangeForDefault.minHour;
|
||||
let defaultMinute = 30;
|
||||
if (defaultMinute > timeRangeForDefault.maxMinute) {
|
||||
defaultMinute = timeRangeForDefault.maxMinute;
|
||||
}
|
||||
timeString = `${String(defaultHour).padStart(2, '0')}:${String(defaultMinute).padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
// 确保时间字符串格式正确(必须是 "HH:MM" 格式)
|
||||
if (timeString && typeof timeString === 'string' && timeString.match(/^\d{2}:\d{2}$/)) {
|
||||
latestDateTimePickerValue.value = timeString;
|
||||
} else {
|
||||
// 如果格式不正确,使用时间段开始时间作为默认值
|
||||
const timeRangeForFallback = getTimeSlotRange();
|
||||
latestDateTimePickerValue.value = `${String(timeRangeForFallback.minHour).padStart(2, '0')}:00`;
|
||||
}
|
||||
|
||||
// 确保值设置完成后再打开选择器
|
||||
nextTick(() => {
|
||||
latestDateTimePickerVisible.value = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 最晚到店时间选择器确认
|
||||
* 设置结束时间是否为次日
|
||||
*/
|
||||
const onLatestDateTimePickerConfirm = async (e) => {
|
||||
// up-datetime-picker mode="time" 时,v-model 绑定的值应该是 "HH:MM" 格式字符串
|
||||
// 事件参数 e 可能是对象 { value: "HH:MM", mode: 'time' } 或直接是字符串 "HH:MM"
|
||||
let timeString = latestDateTimePickerValue.value;
|
||||
|
||||
// 如果 v-model 的值无效,尝试从事件参数获取
|
||||
if (!timeString || typeof timeString !== 'string') {
|
||||
if (e && typeof e === 'object' && e.value !== undefined) {
|
||||
timeString = e.value;
|
||||
} else if (typeof e === 'string') {
|
||||
timeString = e;
|
||||
}
|
||||
const setNextDay = (value) => {
|
||||
isNextDay.value = value;
|
||||
validateTimeRange();
|
||||
buildTimeFromPicker();
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证时间范围(支持跨天预约)
|
||||
*/
|
||||
const validateTimeRange = () => {
|
||||
timeError.value = '';
|
||||
|
||||
if (!startTime.value || !endTime.value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 验证时间字符串格式
|
||||
if (!timeString || typeof timeString !== 'string' || !timeString.includes(':')) {
|
||||
console.error('时间选择器返回的值格式无效:', e, 'latestDateTimePickerValue:', latestDateTimePickerValue.value);
|
||||
uni.showToast({
|
||||
title: '时间选择失败,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
latestDateTimePickerVisible.value = false;
|
||||
|
||||
const [startH, startM] = startTime.value.split(':').map(Number);
|
||||
const [endH, endM] = endTime.value.split(':').map(Number);
|
||||
const startMinutes = startH * 60 + startM;
|
||||
let endMinutes = endH * 60 + endM;
|
||||
|
||||
// 如果是次日,结束时间加24小时
|
||||
if (isNextDay.value) {
|
||||
endMinutes += 24 * 60;
|
||||
}
|
||||
|
||||
// 计算时长(分钟)
|
||||
const durationMinutes = endMinutes - startMinutes;
|
||||
|
||||
if (durationMinutes <= 0) {
|
||||
timeError.value = '结束时间必须晚于开始时间';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (durationMinutes < 60) {
|
||||
timeError.value = '预约时长不能少于1小时';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (durationMinutes > 720) {
|
||||
timeError.value = '预约时长不能超过12小时';
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建时间戳(从时间选择器值,支持跨天预约)
|
||||
*/
|
||||
const buildTimeFromPicker = () => {
|
||||
if (!selectedDate.value || !startTime.value || !endTime.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 解析时间字符串 "HH:MM"
|
||||
const timeParts = timeString.split(':');
|
||||
if (timeParts.length !== 2) {
|
||||
console.error('时间格式错误:', timeString);
|
||||
uni.showToast({
|
||||
title: '时间格式错误',
|
||||
icon: 'none'
|
||||
});
|
||||
latestDateTimePickerVisible.value = false;
|
||||
|
||||
if (!validateTimeRange()) {
|
||||
// 清空时间戳
|
||||
reservationInfo.value.start_time = 0;
|
||||
reservationInfo.value.end_time = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const hours = parseInt(timeParts[0], 10);
|
||||
const minutes = parseInt(timeParts[1], 10);
|
||||
|
||||
if (isNaN(hours) || isNaN(minutes) || hours < 0 || hours > 23 || minutes < 0 || minutes > 59) {
|
||||
console.error('时间值无效:', hours, minutes);
|
||||
uni.showToast({
|
||||
title: '时间值无效',
|
||||
icon: 'none'
|
||||
});
|
||||
latestDateTimePickerVisible.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证选择的时间是否在时间段范围内
|
||||
if (selectedTimeSlot.value !== null && selectedTimeSlot.value !== undefined) {
|
||||
const timeRange = getTimeSlotRange();
|
||||
if (hours < timeRange.minHour || hours > timeRange.maxHour) {
|
||||
uni.showToast({
|
||||
title: `时间必须在 ${timeRange.minHour}:00-${timeRange.maxHour}:59 范围内`,
|
||||
icon: 'none'
|
||||
});
|
||||
latestDateTimePickerVisible.value = false;
|
||||
return;
|
||||
}
|
||||
if (hours === timeRange.minHour && minutes < timeRange.minMinute) {
|
||||
uni.showToast({
|
||||
title: `时间必须在 ${timeRange.minHour}:${String(timeRange.minMinute).padStart(2, '0')}-${timeRange.maxHour}:59 范围内`,
|
||||
icon: 'none'
|
||||
});
|
||||
latestDateTimePickerVisible.value = false;
|
||||
return;
|
||||
}
|
||||
if (hours === timeRange.maxHour && minutes > timeRange.maxMinute) {
|
||||
uni.showToast({
|
||||
title: `时间必须在 ${timeRange.minHour}:00-${timeRange.maxHour}:${String(timeRange.maxMinute).padStart(2, '0')} 范围内`,
|
||||
icon: 'none'
|
||||
});
|
||||
latestDateTimePickerVisible.value = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有选择日期,使用当前日期
|
||||
if (!selectedDate.value) {
|
||||
uni.showToast({
|
||||
title: '请先选择日期',
|
||||
icon: 'none'
|
||||
});
|
||||
latestDateTimePickerVisible.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 将选择的日期和时间组合
|
||||
|
||||
const date = new Date(selectedDate.value * 1000);
|
||||
const year = date.getFullYear();
|
||||
const month = date.getMonth();
|
||||
const day = date.getDate();
|
||||
const dateTime = new Date(year, month, day, hours, minutes, 0);
|
||||
|
||||
// 转换为秒级时间戳
|
||||
const selectedTimestamp = Math.floor(dateTime.getTime() / 1000);
|
||||
|
||||
// 验证转换后的时间戳是否有效
|
||||
if (isNaN(selectedTimestamp) || selectedTimestamp <= 0) {
|
||||
console.error('时间戳转换失败:', dateTime, selectedTimestamp);
|
||||
uni.showToast({
|
||||
title: '时间处理失败',
|
||||
icon: 'none'
|
||||
});
|
||||
latestDateTimePickerVisible.value = false;
|
||||
return;
|
||||
const [startH, startM] = startTime.value.split(':').map(Number);
|
||||
const [endH, endM] = endTime.value.split(':').map(Number);
|
||||
|
||||
const startDateTime = new Date(date.getFullYear(), date.getMonth(), date.getDate(), startH, startM, 0);
|
||||
|
||||
// 如果是次日,结束时间加1天
|
||||
let endDateTime;
|
||||
if (isNextDay.value) {
|
||||
const nextDay = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1, endH, endM, 0);
|
||||
endDateTime = nextDay;
|
||||
} else {
|
||||
endDateTime = new Date(date.getFullYear(), date.getMonth(), date.getDate(), endH, endM, 0);
|
||||
}
|
||||
|
||||
// 更新最晚到店时间
|
||||
latestDateTime.value = selectedTimestamp;
|
||||
|
||||
latestDateTimePickerVisible.value = false;
|
||||
|
||||
reservationInfo.value.start_time = Math.floor(startDateTime.getTime() / 1000);
|
||||
reservationInfo.value.end_time = Math.floor(endDateTime.getTime() / 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据时间段自动更新最晚到店时间(时间段开始时间+30分钟)
|
||||
* 计算时长显示(支持跨天预约)
|
||||
*/
|
||||
const updateLatestDateTimeFromSlot = () => {
|
||||
if (!selectedDate.value || selectedTimeSlot.value === null || selectedTimeSlot.value === undefined) {
|
||||
return;
|
||||
const calculateDuration = () => {
|
||||
if (!startTime.value || !endTime.value) return '-';
|
||||
|
||||
const [startH, startM] = startTime.value.split(':').map(Number);
|
||||
const [endH, endM] = endTime.value.split(':').map(Number);
|
||||
let endMinutes = endH * 60 + endM;
|
||||
|
||||
// 如果是次日,结束时间加24小时
|
||||
if (isNextDay.value) {
|
||||
endMinutes += 24 * 60;
|
||||
}
|
||||
|
||||
// 将日期时间戳转换为日期对象
|
||||
const date = new Date(selectedDate.value * 1000);
|
||||
const year = date.getFullYear();
|
||||
const month = date.getMonth();
|
||||
const day = date.getDate();
|
||||
|
||||
// 根据时段类型设置开始时间
|
||||
let startHour = 0;
|
||||
let startMinute = 30; // 默认加30分钟
|
||||
|
||||
switch (selectedTimeSlot.value) {
|
||||
case 0: // 凌晨 00:00-05:59
|
||||
startHour = 0;
|
||||
startMinute = 30;
|
||||
break;
|
||||
case 1: // 上午 06:00-11:59
|
||||
startHour = 6;
|
||||
startMinute = 30;
|
||||
break;
|
||||
case 2: // 下午 12:00-17:59
|
||||
startHour = 12;
|
||||
startMinute = 30;
|
||||
break;
|
||||
case 3: // 晚上 18:00-23:59
|
||||
startHour = 18;
|
||||
startMinute = 30;
|
||||
break;
|
||||
|
||||
const diffMinutes = endMinutes - (startH * 60 + startM);
|
||||
|
||||
if (diffMinutes <= 0) return '-';
|
||||
|
||||
const hours = Math.floor(diffMinutes / 60);
|
||||
const mins = diffMinutes % 60;
|
||||
|
||||
if (mins === 0) {
|
||||
return `${hours}小时`;
|
||||
}
|
||||
|
||||
// 创建最晚到店时间(开始时间+30分钟)
|
||||
const latestDateTimeObj = new Date(year, month, day, startHour, startMinute, 0);
|
||||
|
||||
// 转换为秒级时间戳
|
||||
latestDateTime.value = Math.floor(latestDateTimeObj.getTime() / 1000);
|
||||
return `${hours}小时${mins}分钟`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算跨越时段(支持跨天预约)
|
||||
*/
|
||||
const calculateCrossSlots = () => {
|
||||
if (!startTime.value || !endTime.value) return '-';
|
||||
|
||||
const [startH] = startTime.value.split(':').map(Number);
|
||||
const [endH] = endTime.value.split(':').map(Number);
|
||||
|
||||
const slots = [];
|
||||
const ranges = [
|
||||
{ name: '凌晨', start: 0, end: 6 },
|
||||
{ name: '上午', start: 6, end: 12 },
|
||||
{ name: '下午', start: 12, end: 18 },
|
||||
{ name: '晚上', start: 18, end: 24 }
|
||||
];
|
||||
|
||||
if (isNextDay.value) {
|
||||
// 跨天预约:当天的时段 + 次日的时段
|
||||
// 当天:从开始时间到24点
|
||||
for (const r of ranges) {
|
||||
if (startH < r.end && 24 > r.start) {
|
||||
if (!slots.includes(r.name)) {
|
||||
slots.push(r.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 次日:从0点到结束时间
|
||||
for (const r of ranges) {
|
||||
if (0 < r.end && endH > r.start) {
|
||||
if (!slots.includes(r.name)) {
|
||||
slots.push(r.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 同一天:正常判断
|
||||
for (const r of ranges) {
|
||||
// 重叠判断:预约开始 < 时段结束 AND 预约结束 > 时段开始
|
||||
if (startH < r.end && endH > r.start) {
|
||||
slots.push(r.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return slots.join('、') || '-';
|
||||
}
|
||||
|
||||
const tipsShow = () => {
|
||||
submitPopupRef.value.open()
|
||||
}
|
||||
|
|
@ -807,38 +734,27 @@ const onCustomDepositInput = (val) => {
|
|||
return false
|
||||
}
|
||||
|
||||
// 检查是否选择了时段
|
||||
if (selectedTimeSlot.value === null || selectedTimeSlot.value === undefined) {
|
||||
// 检查是否选择了时间
|
||||
if (!startTime.value || !endTime.value) {
|
||||
uni.showToast({
|
||||
title: '请选择时间段',
|
||||
title: '请选择开始和结束时间',
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
// 验证选择的时段是否仍然可预约
|
||||
if (roomDetail.value && roomDetail.value.time_slots) {
|
||||
const selectedSlot = roomDetail.value.time_slots.find(
|
||||
slot => slot.slot_type === selectedTimeSlot.value
|
||||
);
|
||||
|
||||
if (!selectedSlot || selectedSlot.status !== 'available') {
|
||||
uni.showToast({
|
||||
title: '该时段已不可预约,请重新选择',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
// 重新加载房间详情,更新可预约时段
|
||||
if (reservationInfo.value.room_id && selectedDate.value) {
|
||||
await loadRoomDetailForReservation(reservationInfo.value.room_id, selectedDate.value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查时间是否有效
|
||||
if (timeError.value) {
|
||||
uni.showToast({
|
||||
title: timeError.value,
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
if (!info.start_time || info.start_time === 0) {
|
||||
uni.showToast({
|
||||
title: '请选择时间段',
|
||||
title: '请选择开始时间',
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
|
|
@ -846,7 +762,7 @@ const onCustomDepositInput = (val) => {
|
|||
|
||||
if (!info.end_time || info.end_time === 0) {
|
||||
uni.showToast({
|
||||
title: '请选择时间段',
|
||||
title: '请选择结束时间',
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
|
|
@ -947,9 +863,7 @@ const onCustomDepositInput = (val) => {
|
|||
// 确保信誉限制同步
|
||||
credit_limit: currentValue.value,
|
||||
deposit_fee: finalDeposit,
|
||||
important_data: {},
|
||||
// 添加最晚到店时间参数
|
||||
latestDateTime: latestDateTime.value || null
|
||||
important_data: {}
|
||||
}
|
||||
|
||||
// 将玩法类型和具体规则从数字转换为字符串
|
||||
|
|
@ -1079,14 +993,15 @@ const onCustomDepositInput = (val) => {
|
|||
maxPlayerCount.value = savedMaxPlayerCount;
|
||||
peopleRange.value = savedPeopleRange;
|
||||
peopleText.value = savedPeopleText;
|
||||
|
||||
// 重置时段选择
|
||||
selectedTimeSlot.value = null;
|
||||
|
||||
// 重置时间选择
|
||||
startTime.value = '';
|
||||
endTime.value = '';
|
||||
timeError.value = '';
|
||||
isNextDay.value = false; // 重置跨天标记
|
||||
reservationInfo.value.start_time = 0;
|
||||
reservationInfo.value.end_time = 0;
|
||||
// 重置最晚到店时间
|
||||
latestDateTime.value = null;
|
||||
|
||||
|
||||
gameRuleText.value = "请先选择玩法类型"
|
||||
}
|
||||
|
||||
|
|
@ -1145,9 +1060,6 @@ const onCustomDepositInput = (val) => {
|
|||
} else {
|
||||
peopleText.value = "请选择游玩人数";
|
||||
}
|
||||
|
||||
// 从 time_slots 中过滤出可预约的时段,动态生成时间段选项
|
||||
generateTimeSlotOptions(detail.time_slots);
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '获取房间详情失败',
|
||||
|
|
@ -1164,103 +1076,7 @@ const onCustomDepositInput = (val) => {
|
|||
roomDetailLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据房间的 time_slots 动态生成时间段选项
|
||||
* 只显示可预约的时段(status === 'available')
|
||||
*/
|
||||
const generateTimeSlotOptions = (timeSlots) => {
|
||||
if (!timeSlots || !Array.isArray(timeSlots)) {
|
||||
timeSlotOptions.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
// 时段时间范围映射
|
||||
const timeRangeMap = {
|
||||
0: { text: '凌晨', range: '00:00-05:59' },
|
||||
1: { text: '上午', range: '06:00-11:59' },
|
||||
2: { text: '下午', range: '12:00-17:59' },
|
||||
3: { text: '晚上', range: '18:00-23:59' }
|
||||
};
|
||||
|
||||
// 过滤出可预约的时段并生成选项
|
||||
const availableSlots = timeSlots.filter(slot => slot.status === 'available');
|
||||
|
||||
timeSlotOptions.value = availableSlots.map(slot => {
|
||||
const slotInfo = timeRangeMap[slot.slot_type] || { text: slot.slot_name, range: '' };
|
||||
// 生成显示文本
|
||||
let displayText = slotInfo.text;
|
||||
if (slotInfo.range) {
|
||||
displayText += ` (${slotInfo.range})`;
|
||||
}
|
||||
// 如果有价格信息,可以追加显示
|
||||
if (slot.price_desc_standard) {
|
||||
displayText += ` ${slot.price_desc_standard}`;
|
||||
}
|
||||
|
||||
return {
|
||||
value: slot.slot_type,
|
||||
text: displayText
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 时段选择改变事件
|
||||
*/
|
||||
const onTimeSlotChange = (val) => {
|
||||
if (!selectedDate.value) return;
|
||||
selectedTimeSlot.value = val;
|
||||
// 根据日期和时段计算开始时间和结束时间
|
||||
calculateTimeFromSlot();
|
||||
// 自动更新最晚到店时间(时间段开始时间+30分钟)
|
||||
updateLatestDateTimeFromSlot();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据选择的日期和时段计算开始时间和结束时间
|
||||
*/
|
||||
const calculateTimeFromSlot = () => {
|
||||
if (!selectedDate.value || selectedTimeSlot.value === null || selectedTimeSlot.value === undefined) return;
|
||||
|
||||
// 将日期时间戳转换为日期对象
|
||||
const date = new Date(selectedDate.value * 1000);
|
||||
const year = date.getFullYear();
|
||||
const month = date.getMonth();
|
||||
const day = date.getDate();
|
||||
|
||||
// 根据时段类型设置开始时间
|
||||
let startHour = 0;
|
||||
let endHour = 0;
|
||||
|
||||
switch (selectedTimeSlot.value) {
|
||||
case 0: // 凌晨 00:00-05:59
|
||||
startHour = 0;
|
||||
endHour = 6;
|
||||
break;
|
||||
case 1: // 上午 06:00-11:59
|
||||
startHour = 6;
|
||||
endHour = 12;
|
||||
break;
|
||||
case 2: // 下午 12:00-17:59
|
||||
startHour = 12;
|
||||
endHour = 18;
|
||||
break;
|
||||
case 3: // 晚上 18:00-23:59
|
||||
startHour = 18;
|
||||
endHour = 24;
|
||||
break;
|
||||
}
|
||||
|
||||
// 创建开始时间和结束时间
|
||||
const startTime = new Date(year, month, day, startHour, 0, 0);
|
||||
const endTime = new Date(year, month, day, endHour, 0, 0);
|
||||
|
||||
// 转换为秒级时间戳
|
||||
reservationInfo.value.start_time = Math.floor(startTime.getTime() / 1000);
|
||||
reservationInfo.value.end_time = Math.floor(endTime.getTime() / 1000);
|
||||
}
|
||||
|
||||
|
||||
onLoad(async (options) => {
|
||||
const config = await getConfigData();
|
||||
console.log('config', config);
|
||||
|
|
@ -1416,6 +1232,92 @@ const onCustomDepositInput = (val) => {
|
|||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* 时间选择器样式 */
|
||||
.picker-value {
|
||||
padding: 15rpx 20rpx;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 结束时间行布局(时间选择器 + 当天/次日切换) */
|
||||
.end-time-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
/* 当天/次日切换样式 */
|
||||
.next-day-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #f0f0f0;
|
||||
border-radius: 8rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
}
|
||||
|
||||
.next-day-label {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 6rpx;
|
||||
transition: all 0.2s;
|
||||
|
||||
&.active {
|
||||
color: #fff;
|
||||
background-color: #00AC4E;
|
||||
}
|
||||
}
|
||||
|
||||
.next-day-divider {
|
||||
font-size: 24rpx;
|
||||
color: #ccc;
|
||||
margin: 0 4rpx;
|
||||
}
|
||||
|
||||
/* 时间信息显示 */
|
||||
.time-info {
|
||||
margin: 20rpx 0;
|
||||
padding: 20rpx;
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
.time-info-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.time-info-label {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.time-info-value {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 时间错误提示 */
|
||||
.time-error {
|
||||
margin: 16rpx 0;
|
||||
padding: 16rpx;
|
||||
background-color: #fff2f0;
|
||||
border-radius: 8rpx;
|
||||
|
||||
text {
|
||||
font-size: 24rpx;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
}
|
||||
|
||||
/* 可点击的行(年龄范围显示) */
|
||||
.clickable-row {
|
||||
font-size: 28rpx;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user