Feat:旅居选择日期这里需要加个左右滑动翻页的功能

This commit is contained in:
linxi
2026-02-06 10:52:29 +08:00
parent 39d9c1a76a
commit 910a837638
+149 -60
View File
@@ -28,27 +28,52 @@
</view>
</view>
<view class="days">
<view
v-for="(day, index) in calendarDays"
:key="index"
class="day"
:class="{
'empty': !day,
'selected': isSelected(day),
'in-range': isInRange(day),
'start-date': isStartDate(day),
'end-date': isEndDate(day),
'selecting-start': isSelectingStart(day),
'disabled': isDisabled(day),
'booked': getDateStatus(day) === 1,
'unavailable': getDateStatus(day) === 2,
'available': getDateStatus(day) === 0
}"
@click="selectDate(day)"
>
<text>{{ day || '' }}</text>
<view class="v12-font-20" v-if="day && getDateStatus(day) !== null">{{ getDateStatus(day) }}</view>
<view class="calendar-body">
<view class="days" :class="[isAnimating ? 'absolute ' + transitionMode + '-enter' : '']">
<view
v-for="(day, index) in calendarDays"
:key="index"
class="day"
:class="{
'empty': !day,
'selected': isSelected(day),
'in-range': isInRange(day),
'start-date': isStartDate(day),
'end-date': isEndDate(day),
'selecting-start': isSelectingStart(day),
'disabled': isDisabled(day),
'booked': getDateStatus(day) === '已被预约',
'unavailable': getDateStatus(day) === '不可预约',
'available': getDateStatus(day) === '可预约'
}"
@click="selectDate(day)"
>
<text>{{ day || '' }}</text>
<view class="v12-font-20" v-if="day && getDateStatus(day) !== null">{{ getDateStatus(day) }}</view>
</view>
</view>
<view class="days absolute" v-if="isAnimating" :class="[transitionMode + '-leave']">
<view
v-for="(day, index) in prevMonthDays"
:key="'prev-' + index"
class="day"
:class="{
'empty': !day,
'selected': isSelected(day, prevYear, prevMonth),
'in-range': isInRange(day, prevYear, prevMonth),
'start-date': isStartDate(day, prevYear, prevMonth),
'end-date': isEndDate(day, prevYear, prevMonth),
'selecting-start': isSelectingStart(day, prevYear, prevMonth),
'disabled': isDisabled(day, prevYear, prevMonth),
'booked': getDateStatus(day, prevYear, prevMonth) === '已被预约',
'unavailable': getDateStatus(day, prevYear, prevMonth) === '不可预约',
'available': getDateStatus(day, prevYear, prevMonth) === '可预约'
}"
>
<text>{{ day || '' }}</text>
<view class="v12-font-20" v-if="day && getDateStatus(day, prevYear, prevMonth) !== null">{{ getDateStatus(day, prevYear, prevMonth) }}</view>
</view>
</view>
</view>
</view>
@@ -113,7 +138,13 @@ export default {
dateStatusMap: {}, // 存储日期状态
selectionState: 'initial', // 'initial' | 'selecting' | 'completed'
touchStartX: 0,
touchStartY: 0
touchStartY: 0,
// 动画相关状态
isAnimating: false,
transitionMode: '', // 'next' or 'prev'
prevYear: null,
prevMonth: null,
prevMonthDays: []
}
},
@@ -171,37 +202,38 @@ export default {
methods: {
getDays(){
uni.showLoading({
title: '加载中...',
mask: true,
})
// uni.showLoading({
// title: '加载中...',
// mask: true,
// })
sojoumOrderCalendar({
travelGroupProductId: this.travelGroupProductId,
month: `${this.currentYear}-${String(this.currentMonth + 1).padStart(2, '0')}`
}).then(res => {
if (res.data) {
// 更新日期状态映射
this.dateStatusMap = {}
// 更新日期状态映射,使用合并而不是覆盖,以支持动画时的旧数据显示
const newStatusMap = {}
res.data.forEach(day => {
// inventoryStatus int 状态 (0:可预约, 1:已被预约, 2:不可预约)
this.dateStatusMap[day.date] = day.inventoryStatus === 0 ? '可预约' : day.inventoryStatus === 1 ? '已被预约' : '不可预约'
newStatusMap[day.date] = day.inventoryStatus === 0 ? '可预约' : day.inventoryStatus === 1 ? '已被预约' : '不可预约'
})
this.dateStatusMap = { ...this.dateStatusMap, ...newStatusMap }
}
}).finally(() => {
uni.hideLoading()
})
},
getDateStatus(day) {
getDateStatus(day, year, month) {
if (!day) return null
const date = this.formatDate(this.getDateFromDay(day))
const date = this.formatDate(this.getDateFromDay(day, year, month))
return this.dateStatusMap[date]
},
isDisabled(day) {
isDisabled(day, year, month) {
if (!day) return true
const date = this.getDateFromDay(day)
const date = this.getDateFromDay(day, year, month)
// 禁用过去的日期(今天之前的日期)
const today = new Date()
today.setHours(0, 0, 0, 0)
@@ -212,7 +244,7 @@ export default {
if (this.maxDate && date > new Date(this.maxDate)) return true
// 检查预约状态
const status = this.getDateStatus(day)
const status = this.getDateStatus(day, year, month)
// 只允许选择可预约的日期(状态为"可预约"),其他状态都禁用
return status !== '可预约'
@@ -244,6 +276,15 @@ export default {
},
changeMonth(delta) {
if (this.isAnimating) return
// Setup animation state
this.prevYear = this.currentYear
this.prevMonth = this.currentMonth
this.prevMonthDays = [...this.calendarDays]
this.transitionMode = delta > 0 ? 'next' : 'prev'
this.isAnimating = true
let newMonth = this.currentMonth + delta
if (newMonth < 0) {
this.currentYear--
@@ -253,6 +294,12 @@ export default {
newMonth = 0
}
this.currentMonth = newMonth
// Reset animation state after transition
setTimeout(() => {
this.isAnimating = false
this.prevMonthDays = []
}, 300)
},
onTouchStart(e) {
@@ -285,8 +332,10 @@ export default {
return `${year}-${month}-${day}`
},
getDateFromDay(day) {
return day ? new Date(this.currentYear, this.currentMonth, day) : null
getDateFromDay(day, year, month) {
const y = year !== undefined ? year : this.currentYear
const m = month !== undefined ? month : this.currentMonth
return day ? new Date(y, m, day) : null
},
// isDisabled(day) {
@@ -305,42 +354,42 @@ export default {
// return false
// },
isSelected(day) {
isSelected(day, year, month) {
if (!day) return false
const date = this.getDateFromDay(day)
return this.isStartDate(day) || this.isEndDate(day)
// const date = this.getDateFromDay(day, year, month) // Unused?
return this.isStartDate(day, year, month) || this.isEndDate(day, year, month)
},
isStartDate(day) {
isStartDate(day, year, month) {
if (!day || !this.tempStartDate) return false
const date = this.getDateFromDay(day)
const date = this.getDateFromDay(day, year, month)
return date.getTime() === this.tempStartDate.getTime()
},
isEndDate(day) {
isEndDate(day, year, month) {
if (!day || !this.tempEndDate) return false
const date = this.getDateFromDay(day)
const date = this.getDateFromDay(day, year, month)
return date.getTime() === this.tempEndDate.getTime()
},
isInRange(day) {
isInRange(day, year, month) {
if (!day || !this.tempStartDate || !this.tempEndDate) return false
const date = this.getDateFromDay(day)
const date = this.getDateFromDay(day, year, month)
return date > this.tempStartDate && date < this.tempEndDate
},
isSelectingStart(day) {
isSelectingStart(day, year, month) {
if (!day || !this.tempStartDate || this.tempEndDate) return false
// 只有在选择状态且只有开始日期时才显示特殊样式
if (this.selectionState !== 'selecting') return false
const date = this.getDateFromDay(day)
const date = this.getDateFromDay(day, year, month)
return date.getTime() === this.tempStartDate.getTime()
},
selectDate(day) {
if (!day || this.isDisabled(day)) return
selectDate(day, year, month) {
if (!day || this.isDisabled(day, year, month)) return
const selectedDate = this.getDateFromDay(day)
const selectedDate = this.getDateFromDay(day, year, month)
// 如果设置了最小预订天数,则自动计算结束日期
if (this.minBookingDays > 0) {
@@ -708,17 +757,57 @@ export default {
}
@keyframes pulse {
0% {
opacity: 1;
transform: scale(1);
0% {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 0.7;
transform: scale(1.05);
}
100% {
opacity: 1;
transform: scale(1);
}
}
50% {
opacity: 0.7;
transform: scale(1.05);
// Animation Styles
.calendar-body {
position: relative;
height: 480rpx; // 6 rows * 80rpx
overflow: hidden;
width: 100%;
}
100% {
opacity: 1;
transform: scale(1);
.days.absolute {
position: absolute;
top: 0;
left: 0;
width: 100%;
// height: 100%;
z-index: 1;
}
}
// Keyframes for sliding
@keyframes slide-next-enter {
from { transform: translateX(100%); }
to { transform: translateX(0); }
}
@keyframes slide-next-leave {
from { transform: translateX(0); }
to { transform: translateX(-100%); }
}
@keyframes slide-prev-enter {
from { transform: translateX(-100%); }
to { transform: translateX(0); }
}
@keyframes slide-prev-leave {
from { transform: translateX(0); }
to { transform: translateX(100%); }
}
.next-enter { animation: slide-next-enter 0.3s forwards; }
.next-leave { animation: slide-next-leave 0.3s forwards; }
.prev-enter { animation: slide-prev-enter 0.3s forwards; }
.prev-leave { animation: slide-prev-leave 0.3s forwards; }
</style>