Feat:订单预约日期

This commit is contained in:
LinCyJang
2025-10-21 01:24:12 +08:00
parent ac3d11ff2a
commit e3c74241b4
3 changed files with 311 additions and 8 deletions
+188
View File
@@ -0,0 +1,188 @@
<template>
<view class="calendar-wrapper">
<u-calendar
ref="ucalendar"
:show="show"
:mode="'range'"
:maxRange="999"
:defaultDate="defaultDate"
:minDate="minDate"
:disabledDate="disabledDates"
color="#C52733"
@confirm="handleDateChange"
@close="hideCalendar"
:monthNum="1"
>
<view slot="tooltip" class="calendar-tooltip">
{{ tooltipText }}
</view>
</u-calendar>
</view>
</template>
<script>
export default {
name: 'Calendar',
props: {
minDay: {
type: Number,
default: 1
}
},
data() {
return {
show: false,
defaultDate: null,
minDate: new Date().getTime(),
disabledDates: [], // 存储禁用日期
tooltipText: '请选择入住日期(最多连续5天)',
selectedRange: {
startDate: null,
endDate: null
},
dateList: []
}
},
onReady() {
// 如果需要兼容微信小程序的话,需要用此写法
this.$refs.ucalendar.setFormatter(this.formatter)
},
methods: {
formatter(day) {
// 将day.date转换为yyyy-MM-dd格式,用于与dateList中的日期比较
const currentDate = new Date(day.date)
const dateStr = `${currentDate.getFullYear()}-${String(currentDate.getMonth() + 1).padStart(2, '0')}-${String(currentDate.getDate()).padStart(2, '0')}`
// 在dateList中查找匹配的日期
const matchedDate = this.dateList.find(item => item.date === dateStr)
if (matchedDate) {
// 根据inventoryStatus设置bottomInfo和disabled状态
switch (matchedDate.inventoryStatus) {
case -1:
day.bottomInfo = '不可预约'
day.disabled = true
break
case 0:
day.bottomInfo = '可预约'
day.disabled = false
break
case 1:
day.bottomInfo = '已被预约'
day.disabled = true
break
case 2:
day.bottomInfo = '不可预约'
day.disabled = true
break
}
}
return day
},
showCalendar(days) {
this.show = true
this.dateList = days
},
hideCalendar() {
this.show = false
},
// 处理日期选择变化
handleDateChange(e) {
// e是选中的日期数组 ["2025-10-21", "2025-10-22", "2025-10-23", "2025-10-24", "2025-10-25"]
// 检查是否有不可选的日期
const hasInvalidDate = e.some(date => {
const matchedDate = this.dateList.find(item => item.date === date)
return matchedDate && (matchedDate.inventoryStatus === 1 || matchedDate.inventoryStatus === 2 || matchedDate.inventoryStatus === -1)
})
if (hasInvalidDate) {
uni.showToast({
title: '所选日期包含不可预约日期',
icon: 'none'
})
this.resetSelection()
return
}
// 更新选择状态
this.selectedRange = {
startDate: e[0],
endDate: e[e.length - 1]
}
// 如果选择的天数小于minDay,提示用户选择至少minDay天
if (e.length < this.minDay) {
uni.showToast({
title: `请选择至少${this.minDay}`,
icon: 'none'
})
this.resetSelection()
return
}
// 触发父组件事件
this.$emit('dateSelected', this.selectedRange)
this.hideCalendar()
},
// 检查日期范围内是否有不可预约的日期
checkInvalidDatesInRange(start, end) {
// 遍历日期范围内的每一天
for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
const dateStr = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
const matchedDate = this.dateList.find(item => item.date === dateStr)
// 如果找到匹配的日期,且状态为已被预约(1)或不可预约(2)
if (matchedDate && (matchedDate.inventoryStatus === 1 || matchedDate.inventoryStatus === 2)) {
return true
}
}
return false
},
// 检查选择范围内是否有禁用日期
checkDisabledDatesInRange(start, end) {
return this.disabledDates.some(date => {
const disabledDate = new Date(date)
return disabledDate >= start && disabledDate <= end
})
},
// 重置选择
resetSelection() {
this.selectedRange = {
startDate: null,
endDate: null
}
this.defaultDate = null
},
// 处理月份切换
handleMonthSwitch(e) {
// 可以在这里处理月份切换逻辑,例如加载该月的禁用日期
this.$emit('monthChange', e)
},
// 设置禁用日期
setDisabledDates(dates) {
this.disabledDates = dates
}
}
}
</script>
<style lang="scss" scoped>
.calendar-wrapper {
width: 100%;
background-color: #fff;
border-radius: 12rpx;
overflow: hidden;
.calendar-tooltip {
padding: 20rpx;
font-size: 28rpx;
color: #666;
text-align: center;
}
}
</style>
+122 -7
View File
@@ -47,12 +47,12 @@
<view></view>
<view></view>
</view>
<view v-for="(d) in currentWeek" :key="d.date" class="date-item">
<view v-for="(d) in currentWeek" :key="d.date" class="date-item">
<view>{{ d.week }}</view>
<view class="v12-my-1 v12-primary-text">{{ d.monthDay }}</view>
<view>不可预约</view>
<view>{{ d.status }}</view>
</view>
<view class="v12-primary-text v12-font-24 date-item v12-white v12-px-1">
<view @click="handleDate" class="v12-primary-text v12-font-24 date-item v12-white v12-px-1">
<view></view>
<view></view>
<view></view>
@@ -133,14 +133,22 @@
<view class="buy-btn" @click="bookNow">立即购买</view>
</view>
</view>
<Calendar ref="calendar"
:minDay="detail.minBookingDays"
@dateSelected="handleDateSelected"
></Calendar>
</view>
</template>
<script>
import { getJiaLouProductDetail, getJiaLouCalendar,getJiaLouBookingRules } from '@/api/qianxian'
import {getGiftCardSendBackground} from "@/api/gift"
import Calendar from '../components/Calendar.vue'
export default {
name: 'GroupBuyDetails',
components: {
Calendar
},
data() {
return {
webUrl: this.$VUE_APP_RESOURCES_URL,
@@ -193,7 +201,8 @@ export default {
},
calendar: [],
currentWeek: [],
rules: ""
rules: "",
rangeDate: {}
}
},
onShow() {
@@ -214,6 +223,14 @@ export default {
})
},
methods: {
handleDateSelected(dateRange) {
console.log(dateRange, 'dateRange');
this.rangeDate = dateRange
},
handleDate() {
this.$refs.calendar.showCalendar(this.calendar)
},
/**
* 获取产品可预约日期
*/
@@ -245,6 +262,7 @@ export default {
result.push({
date: dateStr,
week: this.getWeekLabel(dateStr),
status: this.findDateStatus(dateStr),
monthDay: i === 0 ? '今日' : this.getMonthDay(dateStr)
})
}
@@ -285,8 +303,100 @@ export default {
uni.showToast({ title: '已为您接入管家', icon: 'none' })
},
bookNow() {
uni.navigateTo({ url: '/pkg_product/views/submitOrder?id=' + this.id + '&orderStartDate=' + this.currentWeek[0].date + '&orderEndDate=' + this.currentWeek[4].date })
}
uni.navigateTo({ url: '/pkg_product/views/submitOrder?id=' + this.id + '&orderStartDate=' + this.rangeDate.startDate + '&orderEndDate=' + this.rangeDate.endDate })
},
/**
* 查找指定日期的预约状态
* @param {string} dateStr YYYY-MM-DD格式的日期字符串
* @returns {string} 预约状态文本:可约、已约、不可约
*/
findDateStatus(dateStr) {
// 在calendar数组中查找匹配的日期
const matchedDate = this.calendar.find(item => item.date === dateStr)
console.log('未找到匹配日期:', matchedDate)
// 如果找到匹配的日期,根据inventoryStatus返回对应文本
if (matchedDate) {
switch (matchedDate.inventoryStatus) {
case 0:
return '可订'
case 1:
return '不可订'
case 2:
return '不可订'
default:
return '不可订'
}
}
// 如果没有找到匹配的日期,返回不可约
return '不可订'
},
/**
* 处理日期点击事件
* @param {Object} date 日期对象
*/
handleDateClick(date) {
// 如果是不可订的日期,直接返回
if (date.status === '不可订') {
uni.showToast({
title: '该日期不可预订',
icon: 'none'
})
return
}
// 检查是否已选中
const index = this.rangeDate.indexOf(date.date)
if (index > -1) {
// 如果已选中,则取消选中
this.rangeDate.splice(index, 1)
} else {
// 如果未选中,则添加到选中列表
this.rangeDate.push(date.date)
// 对日期进行排序
this.rangeDate.sort()
// 检查日期连续性
if (this.rangeDate.length > 1) {
const isConsecutive = this.checkConsecutiveDates(this.rangeDate)
if (!isConsecutive) {
uni.showToast({
title: '请选择连续的日期',
icon: 'none'
})
// 移除最后添加的日期
this.rangeDate.pop()
}
}
}
},
/**
* 检查日期是否被选中
* @param {string} date 日期字符串
* @returns {boolean} 是否被选中
*/
isDateSelected(date) {
return this.rangeDate.includes(date)
},
/**
* 检查日期是否连续
* @param {Array} dates 日期数组
* @returns {boolean} 是否连续
*/
checkConsecutiveDates(dates) {
for (let i = 1; i < dates.length; i++) {
const curr = new Date(dates[i])
const prev = new Date(dates[i-1])
const diffDays = (curr - prev) / (1000 * 60 * 60 * 24)
if (diffDays !== 1) {
return false
}
}
return true
},
}
}
</script>
@@ -383,8 +493,13 @@ export default {
color: #333;
height: 160rpx;
padding: 0 4rpx;
.selected-date {
background-color: #E9BABA;
font-weight: bold;
border-radius: 100rpx;
}
}
.simple-table {
margin-top: 12rpx;
border: 1rpx solid #FADE9F;
+1 -1
View File
@@ -108,7 +108,6 @@
</view>
<!-- 日期选择器简单占位 -->
<u-calendar v-model="showCalendar" mode="range" :min-date="minDate" @confirm="onDateConfirm" />
<passkeyborad
v-if="isShowPayPwdPop"
ref='payPwdPop'
@@ -118,6 +117,7 @@
@close="pwdPopClose"
@finish="pwdPopFinish"
></passkeyborad>
<Calendar ref="calendar"></Calendar>
</view>
</template>