Feat:旅居选择日期这里需要加个左右滑动翻页的功能
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user