761 lines
21 KiB
Vue
761 lines
21 KiB
Vue
<script setup lang="ts">
|
||
import {EventEnum} from "@/constant/enums";
|
||
|
||
const { t } = useI18n();
|
||
import dayjs from "dayjs";
|
||
|
||
// 店铺的营业时间(示例:周一到周五营业,周六周日不营业)
|
||
// 测试用的营业时间字符串
|
||
// MONDAY/TUESDAY/WEDNESDAY 09:00-18:00;THURSDAY/FRIDAY 08:00-09:00; // 周一到周五9点到18点,周四到周五8点到9点
|
||
// MONDAY/TUESDAY/WEDNESDAY 09:00-18:00;THURSDAY/FRIDAY 08:00-12:00;SATURDAY/SUNDAY 10:00-20:00 // 周六周日10点到20点
|
||
// MONDAY/TUESDAY/WEDNESDAY 09:00-16:00
|
||
// MONDAY 09:00-18:00;TUESDAY 09:00-10:00;WEDNESDAY 09:00-18:00;THURSDAY 09:00-18:00;FRIDAY 08:00-09:00
|
||
const storeBusinessHours = ref('');
|
||
// 是否仅选择日期(当前需求:只选哪一天配送,不选具体时间段)
|
||
const onlySelectDay = ref(true);
|
||
|
||
// 业务规则:只能预约周一 / 周四 / 周五
|
||
// JS 中:0-周日 1-周一 ... 4-周四 5-周五
|
||
const allowedWeekdays = [1, 4, 5];
|
||
const isAllowedDay = (date: Date): boolean => {
|
||
const dayIndex = date.getDay();
|
||
return allowedWeekdays.includes(dayIndex);
|
||
};
|
||
|
||
// 解析商家营业时间的接口
|
||
interface BusinessHours {
|
||
days: string[]; // 营业的星期几
|
||
startTime: string; // 开始时间 HH:mm
|
||
endTime: string; // 结束时间 HH:mm
|
||
}
|
||
|
||
/**
|
||
* 解析商家营业时间字符串
|
||
* @param businessHoursStr 营业时间字符串,支持多种格式:
|
||
* - MONDAY/TUESDAY/WEDNESDAY 09:00-18:00;THURSDAY/FRIDAY/SATURDAY/SUNDAY 10:00-20:00
|
||
* - MONDAY/TUESDAY/WEDNESDAY 09:00-18:00
|
||
* - MONDAY 09:00-18:00;TUESDAY 09:00-10:00;WEDNESDAY 09:00-18:00
|
||
* @returns 解析后的营业时间数组
|
||
*/
|
||
const parseBusinessHours = (businessHoursStr: string): BusinessHours[] => {
|
||
if (!businessHoursStr) return [];
|
||
|
||
const businessHours: BusinessHours[] = [];
|
||
// 使用分号分割不同的营业时间段
|
||
const segments = businessHoursStr.split(";");
|
||
|
||
segments.forEach((segment) => {
|
||
const trimmedSegment = segment.trim();
|
||
if (!trimmedSegment) return;
|
||
|
||
// 使用空格分割星期几和时间
|
||
const parts = trimmedSegment.split(" ");
|
||
if (parts.length !== 2) return;
|
||
|
||
const dayStr = parts[0].trim().toUpperCase();
|
||
const timeStr = parts[1];
|
||
|
||
// 解析时间范围
|
||
const timeRange = timeStr.split("-");
|
||
if (timeRange.length !== 2) return;
|
||
|
||
const startTime = timeRange[0].trim();
|
||
const endTime = timeRange[1].trim();
|
||
|
||
// 按斜杠分割星期几,支持 MONDAY/TUESDAY/WEDNESDAY 格式
|
||
const days = dayStr
|
||
.split("/")
|
||
.map((day) => day.trim())
|
||
.filter((day) => day);
|
||
|
||
businessHours.push({
|
||
days, // 支持多个星期几共享同一营业时间
|
||
startTime,
|
||
endTime,
|
||
});
|
||
});
|
||
|
||
return businessHours;
|
||
};
|
||
|
||
/**
|
||
* 获取指定日期的营业时间
|
||
* @param date 日期
|
||
* @returns 营业时间对象,如果不营业返回null
|
||
*/
|
||
const getBusinessHoursForDate = (date: Date): BusinessHours | null => {
|
||
if (!storeBusinessHours.value) return null;
|
||
|
||
const businessHours = parseBusinessHours(storeBusinessHours.value);
|
||
|
||
// 获取星期几的英文名称(确保是大写)(不要国际化导致判断失效)
|
||
const dayNames = [
|
||
"SUNDAY",
|
||
"MONDAY",
|
||
"TUESDAY",
|
||
"WEDNESDAY",
|
||
"THURSDAY",
|
||
"FRIDAY",
|
||
"SATURDAY",
|
||
];
|
||
const dayName = dayNames[date.getDay()];
|
||
|
||
// 查找包含当前星期几的营业时间
|
||
return businessHours.find((hours) => hours.days.includes(dayName)) || null;
|
||
};
|
||
|
||
/**
|
||
* 检查日期是否营业
|
||
* @param date 日期
|
||
* @returns 是否营业
|
||
*/
|
||
const isDateOpen = (date: Date): boolean => {
|
||
if (!storeBusinessHours.value) return true; // 如果没有营业时间限制,默认营业
|
||
return getBusinessHoursForDate(date) !== null;
|
||
};
|
||
|
||
/**
|
||
* 检查日期是否应该显示为可选择状态(营业且有可用时间段)
|
||
* @param date 日期
|
||
* @returns 是否可选择
|
||
*/
|
||
const isDateSelectable = (date: Date): boolean => {
|
||
// 新增:限制只能预约周一 / 周四 / 周五
|
||
if (!isAllowedDay(date)) {
|
||
return false;
|
||
}
|
||
|
||
// 如果只选日期模式,营业即可选择
|
||
if (onlySelectDay.value) {
|
||
if (!storeBusinessHours.value) return true;
|
||
return isDateOpen(date);
|
||
}
|
||
|
||
// 原逻辑:需要营业且有可用时间段
|
||
if (!storeBusinessHours.value) return true; // 如果没有营业时间限制,默认可选择
|
||
if (!isDateOpen(date)) return false;
|
||
return hasAvailableTimeSlots(date);
|
||
};
|
||
|
||
// 生成未来 7 天:设计稿为「本周」5 个圆 +「下周」2 个圆
|
||
const dateOptions = computed(() => {
|
||
const dates: Date[] = [];
|
||
const today = new Date();
|
||
|
||
for (let i = 0; i < 7; i++) {
|
||
const date = new Date(today);
|
||
date.setDate(today.getDate() + i);
|
||
dates.push(date);
|
||
}
|
||
|
||
return dates;
|
||
});
|
||
|
||
const thisWeekDates = computed(() => dateOptions.value.slice(0, 5));
|
||
const nextWeekDates = computed(() => dateOptions.value.slice(5, 7));
|
||
|
||
// 状态管理 - 初始化为第一个营业日期
|
||
const selectedDate = ref<Date>();
|
||
|
||
// 检查指定时间是否在营业时间内
|
||
const isTimeInBusinessHours = (
|
||
hour: number,
|
||
minute: number,
|
||
businessHours: BusinessHours
|
||
): boolean => {
|
||
const timeStr = `${hour.toString().padStart(2, "0")}:${minute
|
||
.toString()
|
||
.padStart(2, "0")}`;
|
||
return timeStr >= businessHours.startTime && timeStr <= businessHours.endTime;
|
||
};
|
||
|
||
// 检查指定日期是否有可用时间段
|
||
const hasAvailableTimeSlots = (date: Date): boolean => {
|
||
const now = new Date();
|
||
const currentHour = now.getHours();
|
||
const currentMinute = now.getMinutes();
|
||
|
||
// 获取指定日期的营业时间
|
||
const businessHours = getBusinessHoursForDate(date);
|
||
|
||
// 如果没有营业时间,返回false
|
||
if (!businessHours) {
|
||
return false;
|
||
}
|
||
|
||
// 解析营业时间的开始和结束时间
|
||
const [startHour, startMinute] = businessHours.startTime
|
||
.split(":")
|
||
.map(Number);
|
||
const [endHour, endMinute] = businessHours.endTime.split(":").map(Number);
|
||
|
||
// 检查是否有可用时间段
|
||
for (let hour = startHour; hour <= endHour; hour++) {
|
||
for (let minute = 0; minute < 60; minute += 30) {
|
||
// 检查时间段开始时间是否在营业时间内
|
||
if (!isTimeInBusinessHours(hour, minute, businessHours)) {
|
||
continue;
|
||
}
|
||
|
||
// 计算时间段结束时间
|
||
let nextHour = hour;
|
||
let nextMinute = minute + 30;
|
||
if (nextMinute >= 60) {
|
||
nextHour++;
|
||
nextMinute = 0;
|
||
}
|
||
|
||
// 检查时间段结束时间是否超出营业时间
|
||
if (!isTimeInBusinessHours(nextHour, nextMinute, businessHours)) {
|
||
if (
|
||
nextHour > endHour ||
|
||
(nextHour === endHour && nextMinute > endMinute)
|
||
) {
|
||
nextHour = endHour;
|
||
nextMinute = endMinute;
|
||
}
|
||
}
|
||
|
||
// 避免生成开始时间和结束时间相同的无效时间段
|
||
if (hour === nextHour && minute === nextMinute) {
|
||
continue;
|
||
}
|
||
|
||
// 如果是今天,过滤掉已经过去的时间
|
||
if (date.toDateString() === now.toDateString()) {
|
||
if (
|
||
hour < currentHour ||
|
||
(hour === currentHour && minute <= currentMinute)
|
||
) {
|
||
continue;
|
||
}
|
||
}
|
||
|
||
// 如果能到这里,说明有可用时间段
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
};
|
||
|
||
// 初始化选中日期为第一个有可用时间段的营业日期
|
||
const initializeSelectedDate = () => {
|
||
if (onlySelectDay.value) {
|
||
// 仅选日期模式:选择第一个“允许预约且营业”的日期(或第一个允许的日期)
|
||
const firstOpen = dateOptions.value.find(
|
||
(d) => isAllowedDay(d) && isDateOpen(d)
|
||
);
|
||
const firstAllowed = firstOpen || dateOptions.value.find((d) => isAllowedDay(d));
|
||
selectedDate.value = firstAllowed || dateOptions.value[0];
|
||
return;
|
||
}
|
||
|
||
// 非仅选日期模式:保留原逻辑
|
||
for (const date of dateOptions.value) {
|
||
if (isDateSelectable(date)) {
|
||
selectedDate.value = date;
|
||
return;
|
||
}
|
||
}
|
||
|
||
const today = new Date();
|
||
const nextBusinessDate = findNextBusinessDate(today);
|
||
if (nextBusinessDate) {
|
||
selectedDate.value = nextBusinessDate;
|
||
nextTick(() => {
|
||
uni.showToast({
|
||
title: t('pages.address.reservationTime.currentTimeExpired'),
|
||
icon: "none",
|
||
duration: 2000,
|
||
});
|
||
});
|
||
} else {
|
||
selectedDate.value = dateOptions.value[0];
|
||
}
|
||
};
|
||
|
||
// 监听dateOptions变化,初始化选中日期
|
||
watch(
|
||
dateOptions,
|
||
() => {
|
||
if (!selectedDate.value) {
|
||
initializeSelectedDate();
|
||
}
|
||
},
|
||
{ immediate: true }
|
||
);
|
||
|
||
// 监听营业时间字符串变化,重新初始化选中日期
|
||
watch(
|
||
storeBusinessHours,
|
||
() => {
|
||
if (storeBusinessHours.value) {
|
||
initializeSelectedDate();
|
||
}
|
||
},
|
||
{ immediate: true }
|
||
);
|
||
const selectedTimeSlot = ref<string>("");
|
||
|
||
/** 圆圈内上行:星期(与全局 dayjs 语言一致) */
|
||
const formatWeekdayCircle = (date: Date) => dayjs(date).format("dddd");
|
||
|
||
/** 圆圈内下行:MM/DD;不可选时显示文案 */
|
||
const formatCircleSubLine = (date: Date) => {
|
||
if (!isDateSelectable(date)) {
|
||
return t("pages.address.reservationTime.notAvailable");
|
||
}
|
||
return dayjs(date).format("MM/DD");
|
||
};
|
||
|
||
/**
|
||
* 检查时间是否在营业时间内
|
||
* @param hour 小时
|
||
* @param minute 分钟
|
||
* @param businessHours 营业时间对象
|
||
* @returns 是否在营业时间内
|
||
*/
|
||
|
||
// 生成时间段选项(根据商家营业时间过滤)
|
||
const timeSlots = computed(() => {
|
||
const slots: string[] = [];
|
||
const now = new Date();
|
||
const currentHour = now.getHours();
|
||
const currentMinute = now.getMinutes();
|
||
|
||
// 如果还没有选中日期,返回空数组
|
||
if (!selectedDate.value) {
|
||
return slots;
|
||
}
|
||
|
||
// 获取选中日期的营业时间
|
||
const businessHours = getBusinessHoursForDate(selectedDate.value);
|
||
|
||
// 如果没有营业时间限制,使用原有逻辑(0-24小时)
|
||
if (!businessHours) {
|
||
for (let hour = 0; hour < 24; hour++) {
|
||
for (let minute = 0; minute < 60; minute += 30) {
|
||
// 如果是今天,过滤掉已经过去的时间
|
||
if (selectedDate.value.toDateString() === now.toDateString()) {
|
||
if (
|
||
hour < currentHour ||
|
||
(hour === currentHour && minute <= currentMinute)
|
||
) {
|
||
continue;
|
||
}
|
||
}
|
||
|
||
const startHour = hour.toString().padStart(2, "0");
|
||
const startMinute = minute.toString().padStart(2, "0");
|
||
const endHour =
|
||
minute === 30
|
||
? (hour + 1).toString().padStart(2, "0")
|
||
: hour.toString().padStart(2, "0");
|
||
const endMinute = minute === 30 ? "00" : "30";
|
||
|
||
const timeSlot = `${startHour}:${startMinute} - ${endHour}:${endMinute}`;
|
||
slots.push(timeSlot);
|
||
}
|
||
}
|
||
return slots;
|
||
}
|
||
|
||
// 解析营业时间的开始和结束时间
|
||
const [startHour, startMinute] = businessHours.startTime
|
||
.split(":")
|
||
.map(Number);
|
||
const [endHour, endMinute] = businessHours.endTime.split(":").map(Number);
|
||
|
||
// 生成营业时间内的时间段
|
||
for (let hour = startHour; hour <= endHour; hour++) {
|
||
for (let minute = 0; minute < 60; minute += 30) {
|
||
// 检查时间段开始时间是否在营业时间内
|
||
if (!isTimeInBusinessHours(hour, minute, businessHours)) {
|
||
continue;
|
||
}
|
||
|
||
// 计算时间段结束时间
|
||
let nextHour = hour;
|
||
let nextMinute = minute + 30;
|
||
if (nextMinute >= 60) {
|
||
nextHour++;
|
||
nextMinute = 0;
|
||
}
|
||
|
||
// 检查时间段结束时间是否超出营业时间
|
||
if (!isTimeInBusinessHours(nextHour, nextMinute, businessHours)) {
|
||
// 如果结束时间超出营业时间,但开始时间在营业时间内,则调整结束时间为营业结束时间
|
||
if (
|
||
nextHour > endHour ||
|
||
(nextHour === endHour && nextMinute > endMinute)
|
||
) {
|
||
nextHour = endHour;
|
||
nextMinute = endMinute;
|
||
}
|
||
}
|
||
|
||
// 避免生成开始时间和结束时间相同的无效时间段(如 18:00 - 18:00)
|
||
if (hour === nextHour && minute === nextMinute) {
|
||
continue;
|
||
}
|
||
|
||
// 如果是今天,过滤掉已经过去的时间
|
||
if (selectedDate.value.toDateString() === now.toDateString()) {
|
||
if (
|
||
hour < currentHour ||
|
||
(hour === currentHour && minute <= currentMinute)
|
||
) {
|
||
continue;
|
||
}
|
||
}
|
||
|
||
const startHourStr = hour.toString().padStart(2, "0");
|
||
const startMinuteStr = minute.toString().padStart(2, "0");
|
||
const endHourStr = nextHour.toString().padStart(2, "0");
|
||
const endMinuteStr = nextMinute.toString().padStart(2, "0");
|
||
|
||
const timeSlot = `${startHourStr}:${startMinuteStr} - ${endHourStr}:${endMinuteStr}`;
|
||
slots.push(timeSlot);
|
||
}
|
||
}
|
||
|
||
return slots;
|
||
});
|
||
|
||
// 监听时间段变化,如果当前选中日期没有可用时间段,自动选择下一个营业日期
|
||
watch(timeSlots, (newSlots) => {
|
||
if (onlySelectDay.value) return; // 仅选日期模式不需要处理时间段
|
||
if (selectedDate.value && newSlots.length === 0) {
|
||
// 当前选中日期没有可用时间段,寻找下一个营业日期
|
||
const nextBusinessDate = findNextBusinessDate(selectedDate.value);
|
||
if (nextBusinessDate) {
|
||
selectedDate.value = nextBusinessDate;
|
||
selectedTimeSlot.value = ""; // 清空已选择的时间段
|
||
uni.showToast({
|
||
title: t('pages.address.reservationTime.noAvailableTime'),
|
||
icon: "none",
|
||
duration: 2000,
|
||
});
|
||
}
|
||
}
|
||
});
|
||
|
||
// 寻找下一个有可用时间段的营业日期
|
||
const findNextBusinessDate = (currentDate: Date): Date | null => {
|
||
const maxDays = 30; // 最多向前查找30天
|
||
for (let i = 1; i <= maxDays; i++) {
|
||
const nextDate = new Date(currentDate);
|
||
nextDate.setDate(currentDate.getDate() + i);
|
||
|
||
// 检查是否在dateOptions范围内
|
||
const isInRange = dateOptions.value.some((date) =>
|
||
dayjs(date).isSame(dayjs(nextDate), "day")
|
||
);
|
||
|
||
if (
|
||
isInRange &&
|
||
isAllowedDay(nextDate) &&
|
||
isDateOpen(nextDate) &&
|
||
hasAvailableTimeSlots(nextDate)
|
||
) {
|
||
return nextDate;
|
||
}
|
||
}
|
||
return null;
|
||
};
|
||
|
||
// 选择日期
|
||
const selectDate = (date: Date) => {
|
||
// 检查日期是否可选择,如果不可选择则不允许选择
|
||
if (!isDateSelectable(date)) {
|
||
uni.showToast({
|
||
title: t('pages.address.reservationTime.dateNotSelectable'),
|
||
icon: "none",
|
||
});
|
||
return;
|
||
}
|
||
|
||
selectedDate.value = date;
|
||
// 选择新日期后,清空已选择的时间段
|
||
selectedTimeSlot.value = "";
|
||
};
|
||
|
||
// 选择时间段
|
||
const selectTimeSlot = (timeSlot: string) => {
|
||
selectedTimeSlot.value = timeSlot;
|
||
};
|
||
|
||
const isDateSelected = (date: Date) =>
|
||
!!selectedDate.value && dayjs(selectedDate.value).isSame(dayjs(date), "day");
|
||
|
||
// 提交预约
|
||
const submitReservation = () => {
|
||
const dateVal = selectedDate.value;
|
||
if (!dateVal) {
|
||
return;
|
||
}
|
||
|
||
// 非仅选日期模式,需要选择时间段
|
||
if (!onlySelectDay.value) {
|
||
if (!selectedTimeSlot.value) {
|
||
uni.showToast({
|
||
title: t('pages.address.reservationTime.selectTimeSlot'),
|
||
icon: "none",
|
||
});
|
||
return;
|
||
}
|
||
}
|
||
|
||
// 计算开始/结束时间
|
||
const selectedDateDayjs = dayjs(dateVal);
|
||
let startTime: dayjs.Dayjs;
|
||
let endTime: dayjs.Dayjs;
|
||
|
||
if (onlySelectDay.value) {
|
||
// 仅选日期:优先使用营业时间范围;若无营业时间限制,则使用当天起止
|
||
const bh = getBusinessHoursForDate(dateVal);
|
||
if (bh) {
|
||
const [startHour, startMinute] = bh.startTime.split(':').map(Number);
|
||
const [endHour, endMinute] = bh.endTime.split(':').map(Number);
|
||
startTime = selectedDateDayjs
|
||
.hour(startHour)
|
||
.minute(startMinute)
|
||
.second(0)
|
||
.millisecond(0);
|
||
endTime = selectedDateDayjs
|
||
.hour(endHour)
|
||
.minute(endMinute)
|
||
.second(0)
|
||
.millisecond(0);
|
||
} else {
|
||
startTime = selectedDateDayjs.startOf('day');
|
||
endTime = selectedDateDayjs.endOf('day');
|
||
}
|
||
} else {
|
||
// 选择了时间段:解析并生成起止时间
|
||
const [startTimeStr, endTimeStr] = selectedTimeSlot.value.split(' - ');
|
||
const [startHour, startMinute] = startTimeStr.split(':').map(Number);
|
||
const [endHour, endMinute] = endTimeStr.split(':').map(Number);
|
||
startTime = selectedDateDayjs
|
||
.hour(startHour)
|
||
.minute(startMinute)
|
||
.second(0)
|
||
.millisecond(0);
|
||
endTime = selectedDateDayjs
|
||
.hour(endHour)
|
||
.minute(endMinute)
|
||
.second(0)
|
||
.millisecond(0);
|
||
}
|
||
|
||
console.log("预约信息:", {
|
||
date: dateVal,
|
||
timeSlot: onlySelectDay.value ? '' : selectedTimeSlot.value,
|
||
startTime: startTime.valueOf(),
|
||
endTime: endTime.valueOf(),
|
||
});
|
||
|
||
uni.$emit(EventEnum.CHOOSE_APPOINTMENT_TIME, {
|
||
date: dateVal,
|
||
timeSlot: onlySelectDay.value ? '' : selectedTimeSlot.value,
|
||
startTime: startTime.valueOf(),
|
||
endTime: endTime.valueOf(),
|
||
});
|
||
|
||
uni.showToast({
|
||
title: t('pages.address.reservationTime.reservationSuccess'),
|
||
icon: "none",
|
||
});
|
||
|
||
uni.navigateBack();
|
||
};
|
||
|
||
const storeId = ref(null);
|
||
|
||
// 页面加载时处理参数
|
||
onLoad((options: any) => {
|
||
if (options.storeId) {
|
||
storeId.value = options.storeId;
|
||
}
|
||
if (options.storeBusinessHours) {
|
||
storeBusinessHours.value = options.storeBusinessHours;
|
||
// 如果传递了该参数,进入仅选日期模式
|
||
onlySelectDay.value = true;
|
||
}
|
||
// 无论是否传参,统一初始化选中日期,避免首屏未选导致不显示时间段
|
||
nextTick(() => {
|
||
initializeSelectedDate();
|
||
});
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<view class="reservation-time-page min-h-screen pb-180rpx">
|
||
<navbar
|
||
:title="t('pages.address.reservationTime.pageTitle')"
|
||
circle-back
|
||
custom-class="reservation-time-navbar"
|
||
/>
|
||
<view class="reservation-time-body px-40rpx pt-40rpx">
|
||
<view class="date-section">
|
||
<text class="section-label">{{ t("pages.address.reservationTime.thisWeek") }}</text>
|
||
<view class="date-row">
|
||
<view
|
||
v-for="(item, index) in thisWeekDates"
|
||
:key="index"
|
||
class="date-circle"
|
||
:class="{
|
||
'date-circle--selected': isDateSelected(item),
|
||
'date-circle--disabled': !isDateSelectable(item),
|
||
}"
|
||
@click="selectDate(item)"
|
||
>
|
||
<text class="date-circle__weekday">{{ formatWeekdayCircle(item) }}</text>
|
||
<text class="date-circle__sub">{{ formatCircleSubLine(item) }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view v-if="nextWeekDates.length" class="date-section date-section--next">
|
||
<text class="section-label">{{ t("pages.address.reservationTime.nextWeek") }}</text>
|
||
<view class="date-row">
|
||
<view
|
||
v-for="(item, index) in nextWeekDates"
|
||
:key="index"
|
||
class="date-circle"
|
||
:class="{
|
||
'date-circle--selected': isDateSelected(item),
|
||
'date-circle--disabled': !isDateSelectable(item),
|
||
}"
|
||
@click="selectDate(item)"
|
||
>
|
||
<text class="date-circle__weekday">{{ formatWeekdayCircle(item) }}</text>
|
||
<text class="date-circle__sub">{{ formatCircleSubLine(item) }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- 时间段选择区域:在仅选日期模式下隐藏 -->
|
||
<view v-if="!onlySelectDay" class="pb-138rpx mx-40rpx bg-white rounded-24rpx overflow-hidden mt-24rpx">
|
||
<view
|
||
v-for="(timeSlot, index) in timeSlots"
|
||
:key="index"
|
||
class="h-108rpx flex-center-sb px-30rpx"
|
||
:class="[
|
||
index === 0 ? '' : 'border-top',
|
||
timeSlots.length - 1 === index ? 'border-bottom' : '',
|
||
]"
|
||
@click="selectTimeSlot(timeSlot)"
|
||
>
|
||
<text class="text-32rpx font-regular">{{ timeSlot }}</text>
|
||
<!-- 单选按钮 -->
|
||
<image
|
||
:src="
|
||
selectedTimeSlot === timeSlot
|
||
? '/static/images/chef/133.png'
|
||
: '/static/images/chef/134.png'
|
||
"
|
||
class="w-48rpx h-48rpx shrink-0"
|
||
mode="aspectFit"
|
||
/>
|
||
</view>
|
||
</view>
|
||
|
||
<fixed-bottom-large-btn
|
||
class="z-100"
|
||
fixed
|
||
:text="`${t('common.submit')}`"
|
||
@click="submitReservation"
|
||
/>
|
||
</view>
|
||
</template>
|
||
|
||
<style scoped lang="scss">
|
||
.reservation-time-body {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.date-section {
|
||
margin-bottom: 48rpx;
|
||
|
||
&--next {
|
||
margin-bottom: 0;
|
||
}
|
||
}
|
||
|
||
.section-label {
|
||
display: block;
|
||
font-size: 32rpx;
|
||
line-height: 44rpx;
|
||
color: #111;
|
||
font-weight: 500;
|
||
margin-bottom: 24rpx;
|
||
}
|
||
|
||
.date-row {
|
||
display: flex;
|
||
flex-direction: row;
|
||
flex-wrap: nowrap;
|
||
gap: 20rpx;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.date-circle {
|
||
width: 118rpx;
|
||
height: 118rpx;
|
||
border-radius: 50%;
|
||
background-color: #fff;
|
||
box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.06);
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.date-circle__weekday {
|
||
font-size: 26rpx;
|
||
line-height: 32rpx;
|
||
color: #111;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.date-circle__sub {
|
||
font-size: 22rpx;
|
||
line-height: 28rpx;
|
||
margin-top: 6rpx;
|
||
color: #111;
|
||
opacity: 0.88;
|
||
}
|
||
|
||
.date-circle--selected {
|
||
background-color: #111;
|
||
box-shadow: none;
|
||
|
||
.date-circle__weekday,
|
||
.date-circle__sub {
|
||
color: #fff;
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
.date-circle--disabled {
|
||
opacity: 0.45;
|
||
}
|
||
|
||
.date-circle--disabled.date-circle--selected {
|
||
opacity: 1;
|
||
}
|
||
</style>
|
||
|
||
<style lang="scss">
|
||
page {
|
||
background-color: #f7f7f9;
|
||
}
|
||
|
||
.reservation-time-page :deep(.reservation-time-navbar.wd-navbar) {
|
||
background-color: #f7f7f9 !important;
|
||
}
|
||
</style>
|