如何从Firebase Firestore获取指定日期已预约时段并过滤可选时段
预约系统时段过滤问题
我正在开发一个预约系统,用户提交的信息以日期作为文档ID存储在Firebase Firestore中。需求是获取指定日期已被选择的时段,将这些时段从当前用户的可选时段中过滤掉,避免不同用户在同一日期重复预约。
之前的代码会过滤掉所有日期的已选时段,而我只需要过滤当前选定日期的已预约时段。
Firestore数据结构
reservations集合的文档ID为日期格式(如2024-05-20),每个文档包含一个reservations数组,数组元素是包含time、name等字段的预约对象。
之前的错误代码
async function fetchBookedTimes() { const bookedTimesRef = collection(db, 'reservations') const querySnapshot = await getDocs(bookedTimesRef) const bookedTimesArray = [] querySnapshot.forEach((doc) => { const data = doc.data() bookedTimesArray.push(...data.reservations.map((reservation) => reservation.time)) }) bookedTimes.value = bookedTimesArray } watch(date, async () => { await fetchBookedTimes() }) const availableTimes = computed(() => { const times = [] for (let hour = 8; hour <= 22; hour++) { for (let minute = 0; minute <= 30; minute += 30) { times.push(`${hour}:${minute.toString().padStart(2, '0')}`) } } return times.filter((time) => !bookedTimes.value.includes(time)) })
现有代码
模板部分
<div class="form-group"> <label>Date(Month/Day/Year):</label> <input type="date" v-model="date" :min="currentDate" name="Date" required /> </div> <div class="form-group"> <label>Time:</label> <select v-model="time" name="Time" class="time-sec" required> <option value="" disabled hidden>Select The time</option> <option v-for="time in availableTimes" :key="time" :value="time"> {{ time }} </option> </select> </div>
脚本部分
import { ref } from "vue" const date = ref('') const time = ref('') const bookedTimes = ref([]) const reservations = ref({}) const docId = date.value const currentDate = ref(new Date().toISOString().slice(0, 10)) async function fetchBookedTimes() { const bookedTimesRef = doc(db, 'reservations', docId) const docSnapshot = await getDoc(bookedTimesRef) const bookedTimesArray = [] if (docSnapshot.exists()) { const data = docSnapshot.data() bookedTimesArray.push(...data.reservations.map((reservations) => reservations.time)) } bookedTimes.value = bookedTimesArray console.log(bookedTimesArray) } watch(date, async () => { await fetchBookedTimes() }) const availableTimes = computed(() => { const times = [] for (let hour = 8; hour <= 22; hour++) { for (let minute = 0; minute <= 30; minute += 30) { times.push(`${hour}:${minute.toString().padStart(2, '0')}`) } } return times.filter((time) => !bookedTimes.value.includes(time)) }) async function handleSubmit(event) { bookedTimes.value.push({ date: date.value, time: time.value }) // Check if all times for the selected date are booked if (availableTimes.value.length === 0) { // Move to the next available date date.value = new Date(date.value).addDays(1).toISOString().split('T')[0] // Reset booked times for the new date bookedTimes.value = bookedTimes.value.filter((booking) => booking.date !== date.value) } // Create a new reservation object const reservationData = { time: time.value, name: name.value, email: email.value, phone: phone.value } // Add the reservation to the reservations object if (!reservations.value[date.value]) { reservations.value[date.value] = [] } reservations.value[date.value].push(reservationData) // Log the reservations console.log('Reservations:', reservations.value) const dateId = date.value const reservationRef = doc(collection(db, 'reservations'), dateId) try { getDoc(reservationRef).then((doc) => { if (doc.exists) { // Update the existing document updateDoc(reservationRef, { reservations: [...doc.data().reservations, reservationData] }) } else { // Create a new document setDoc(reservationRef, { reservations: [reservationData] }) } }) } catch (error) { console.error(error) } }
问题修复方案
现有代码核心问题:docId初始化时取了date.value的初始空值,后续日期变化时docId不会自动更新,导致请求无效文档;同时handleSubmit中bookedTimes的更新逻辑格式不统一。
修复后的完整脚本代码
import { ref, watch, computed } from "vue" const date = ref('') const time = ref('') const bookedTimes = ref([]) const name = ref('') const email = ref('') const phone = ref('') const currentDate = ref(new Date().toISOString().slice(0, 10)) // 补充日期递增方法 Date.prototype.addDays = function(days) { const date = new Date(this.valueOf()) date.setDate(date.getDate() + days) return date } async function fetchBookedTimes() { if (!date.value) return const bookedTimesRef = doc(db, 'reservations', date.value) const docSnapshot = await getDoc(bookedTimesRef) const bookedTimesArray = [] if (docSnapshot.exists()) { const data = docSnapshot.data() bookedTimesArray.push(...data.reservations.map(reservation => reservation.time)) } bookedTimes.value = bookedTimesArray } watch(date, async () => { await fetchBookedTimes() }) const availableTimes = computed(() => { const times = [] for (let hour = 8; hour <= 22; hour++) { for (let minute = 0; minute <= 30; minute += 30) { times.push(`${hour}:${minute.toString().padStart(2, '0')}`) } } return times.filter(time => !bookedTimes.value.includes(time)) }) async function handleSubmit(event) { event.preventDefault() if (!date.value || !time.value) return // 统一格式更新本地已选时段 if (!bookedTimes.value.includes(time.value)) { bookedTimes.value.push(time.value) } // 检查日期是否约满并切换 if (availableTimes.value.length === 0) { date.value = new Date(date.value).addDays(1).toISOString().split('T')[0] await fetchBookedTimes() time.value = '' } // 提交到Firestore const reservationData = { time: time.value, name: name.value, email: email.value, phone: phone.value } const reservationRef = doc(db, 'reservations', date.value) try { const docSnapshot = await getDoc(reservationRef) if (docSnapshot.exists()) { await updateDoc(reservationRef, { reservations: [...docSnapshot.data().reservations, reservationData] }) } else { await setDoc(reservationRef, { reservations: [reservationData] }) } // 重置表单 time.value = '' name.value = '' email.value = '' phone.value = '' } catch (error) { console.error('提交失败:', error) } }
内容的提问来源于stack exchange,提问作者coochie
相关产品推荐
相关产品推荐

