From 910a837638ef76aabc6ac0aaad22857a856ca5f8 Mon Sep 17 00:00:00 2001 From: linxi <957440651@qq.com> Date: Fri, 6 Feb 2026 10:52:29 +0800 Subject: [PATCH] =?UTF-8?q?Feat=EF=BC=9A=E6=97=85=E5=B1=85=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E6=97=A5=E6=9C=9F=E8=BF=99=E9=87=8C=E9=9C=80=E8=A6=81?= =?UTF-8?q?=E5=8A=A0=E4=B8=AA=E5=B7=A6=E5=8F=B3=E6=BB=91=E5=8A=A8=E7=BF=BB?= =?UTF-8?q?=E9=A1=B5=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DateRangePicker/DateRangePicker.vue | 209 +++++++++++++----- 1 file changed, 149 insertions(+), 60 deletions(-) diff --git a/components/DateRangePicker/DateRangePicker.vue b/components/DateRangePicker/DateRangePicker.vue index 95a24cf..a080334 100644 --- a/components/DateRangePicker/DateRangePicker.vue +++ b/components/DateRangePicker/DateRangePicker.vue @@ -28,27 +28,52 @@ - - - {{ day || '' }} - {{ getDateStatus(day) }} + + + + {{ day || '' }} + {{ getDateStatus(day) }} + + + + + + {{ day || '' }} + {{ getDateStatus(day, prevYear, prevMonth) }} + @@ -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; }