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