|
|
<template> <view class="booking-detail"> <view class="section"> <view class="section-title">日期选择</view> <view class="calendar"> <view class="calendar-header"> <text class="month">{{ currentYear }}年{{ currentMonth }}月</text> </view> <view class="calendar-weekdays"> <text v-for="day in weekdays" :key="day" class="weekday">{{ day }}</text> </view> <view class="calendar-days"> <view v-for="(day, index) in calendarDays" :key="index" class="day-item" :class="{ 'other-month': !day.currentMonth, 'selected': day.date === selectedDate, 'disabled': !day.available, 'today': day.isToday }" @click="selectDate(day)" > <text class="day-num">{{ day.day }}</text> <text v-if="day.available && !day.isToday" class="available-tag">开放日</text> <text v-if="day.isToday" class="today-tag">今天</text> </view> </view> </view> </view>
<view class="section"> <view class="section-title">时间选择</view> <view class="time-slots"> <view v-for="slot in timeSlots" :key="slot.id" class="time-slot" :class="{ 'selected': selectedTime === slot.time }" @click="selectTime(slot)" > <text class="time-text">{{ slot.time }}</text> <text v-if="slot.available" class="available-badge">可选</text> <text v-else class="unavailable-badge">已满</text> </view> </view> </view>
<view class="bottom-bar"> <button class="btn-primary" @click="confirmBooking">确认预约</button> </view> </view></template>
<script>export default { data() { return { currentYear: new Date().getFullYear(), currentMonth: new Date().getMonth() + 1, selectedDate: '', selectedTime: '', weekdays: ['日', '一', '二', '三', '四', '五', '六'], calendarDays: [], timeSlots: [ { id: 1, time: '09:15-12:45', available: true }, { id: 2, time: '13:00-16:30', available: false }, { id: 3, time: '16:45-20:15', available: true } ] }; }, onLoad(options) { this.generateCalendar(); }, methods: { generateCalendar() { const year = this.currentYear; const month = this.currentMonth; const firstDay = new Date(year, month - 1, 1); const lastDay = new Date(year, month, 0); const daysInMonth = lastDay.getDate(); const startWeekday = firstDay.getDay(); const today = new Date(); const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
const days = []; const prevMonthLastDay = new Date(year, month - 1, 0).getDate(); for (let i = startWeekday - 1; i >= 0; i--) { days.push({ day: prevMonthLastDay - i, date: '', currentMonth: false, available: false, isToday: false }); }
const todayDate = new Date(); const availableDates = []; for (let i = 0; i < 7; i++) { const date = new Date(todayDate); date.setDate(todayDate.getDate() + i); const dateStr = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`; availableDates.push(dateStr); }
for (let i = 1; i <= daysInMonth; i++) { const dateStr = `${year}-${String(month).padStart(2, '0')}-${String(i).padStart(2, '0')}`; const isAvailable = availableDates.includes(dateStr); const isToday = dateStr === todayStr; days.push({ day: i, date: dateStr, currentMonth: true, available: isAvailable, isToday: isToday }); }
const remainingDays = 42 - days.length; for (let i = 1; i <= remainingDays; i++) { days.push({ day: i, date: '', currentMonth: false, available: false, isToday: false }); }
this.calendarDays = days; if (availableDates.length > 0) { this.selectedDate = availableDates[0]; } }, selectDate(day) { if (!day.available || !day.currentMonth) return; this.selectedDate = day.date; }, selectTime(slot) { if (!slot.available) return; this.selectedTime = slot.time; }, confirmBooking() { if (!this.selectedDate) { uni.showToast({ title: '请选择日期', icon: 'none' }); return; } if (!this.selectedTime) { uni.showToast({ title: '请选择时间段', icon: 'none' }); return; } uni.showLoading({ title: '预约中...' }); setTimeout(() => { uni.hideLoading(); uni.showModal({ title: '预约成功', content: `您已成功预约\n日期:${this.selectedDate}\n时间:${this.selectedTime}`, showCancel: false, confirmText: '确定', success: () => { uni.navigateBack({ delta: 2 }); } }); }, 1500); } }};</script>
<style lang="scss" scoped>.booking-detail { min-height: 100vh; background-color: #f5f5f5; padding-bottom: 70px;}
.section { background-color: #fff; margin: 10px; border-radius: 12px; padding: 16px;}
.section-title { font-size: 16px; font-weight: bold; color: #333; margin-bottom: 16px;}
/* 日历 */.calendar-header { text-align: center; margin-bottom: 12px;}.month { font-size: 16px; color: #333; font-weight: bold;}
.calendar-weekdays { display: flex; justify-content: space-between; margin-bottom: 10px;}.weekday { width: 14.28%; text-align: center; font-size: 13px; color: #999;}
.calendar-days { display: flex; flex-wrap: wrap;}.day-item { width: 14.28%; aspect-ratio: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; margin-bottom: 6px; border-radius: 6px; position: relative;}.day-item.other-month .day-num { color: #ccc;}.day-item.disabled .day-num { color: #ccc;}.day-item.selected { background-color: #01a4fe;}.day-item.selected .day-num { color: #fff; font-size: 15px; font-weight: bold;}.day-item.selected .available-tag,.day-item.selected .today-tag { color: rgba(255, 255, 255, 0.9); font-size: 10px;}.day-item.today:not(.selected) { background-color: #fff3cd;}.day-item.today:not(.selected) .day-num { color: #856404;}
.day-num { font-size: 14px; color: #333;}.available-tag { font-size: 10px; color: #01a4fe; margin-top: 2px;}.today-tag { font-size: 10px; color: #856404; margin-top: 2px;}
/* 时间选择 */.time-slots { display: flex; flex-wrap: wrap; gap: 10px;}.time-slot { width: calc(50% - 5px); display: flex; align-items: center; justify-content: space-between; padding: 12px; background-color: #f8f8f8; border-radius: 8px; border: 1px solid transparent;}.time-slot.selected { background-color: #e8f4fd; border-color: #01a4fe;}.time-text { font-size: 14px; color: #333;}.available-badge { font-size: 12px; color: #01a4fe; background-color: #e8f4fd; padding: 2px 8px; border-radius: 10px;}.unavailable-badge { font-size: 12px; color: #999; background-color: #f0f0f0; padding: 2px 8px; border-radius: 10px;}
/* 底部按钮 */.bottom-bar { position: fixed; bottom: 0; left: 0; right: 0; padding: 10px; background-color: #fff; box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.1);}.btn-primary { width: 100%; height: 44px; line-height: 44px; background-color: #01a4fe; color: #fff; border-radius: 22px; font-size: 15px; border: none;}.btn-primary::after { border: none;}</style>
|