汽车预订系统基于用户输入生成可用时段的后端逻辑咨询
汽车预订系统后端(Node.js+MongoDB)实现方案
一、MongoDB数据模型设计
先定义核心的预订记录集合,用来存储已完成的预订信息,后续生成可用时段时会依赖它排除冲突:
const mongoose = require('mongoose'); const bookingSchema = new mongoose.Schema({ start: { type: Date, required: true }, // 预订开始时间 end: { type: Date, required: true }, // 预订结束时间 duration: { type: Number, required: true } // 用车时长(单位:分钟) }); const Booking = mongoose.model('Booking', bookingSchema);
二、核心逻辑:生成可用时段
1. 基础规则
- 以用户选择日期的0点为起始,按「用车时长+10分钟洗车间隔」循环生成时段,直到当天24点
- 若存在已预订时段,需排除重叠时段,并调整后续时段的起始时间(以上一个已预订时段的结束时间+10分钟为起点)
2. 完整实现函数
使用date-fns处理日期(和前端保持一致,减少跨端差异),函数会自动过滤冲突时段:
const { addMinutes, isSameDay, isWithinInterval, startOfDay, endOfDay } = require('date-fns'); const Booking = require('./models/Booking'); async function generateAvailableSlots(selectedDate, duration) { const timeToWash = 10; const dayStart = startOfDay(new Date(selectedDate)); const dayEnd = endOfDay(new Date(selectedDate)); // 获取当天所有已预订记录,按开始时间排序 const bookings = await Booking.find({ start: { $gte: dayStart, $lt: dayEnd } }).sort({ start: 1 }); // 先生成无冲突的基础时段列表 const baseSlots = []; let currentStart = dayStart; while (addMinutes(currentStart, duration) <= dayEnd) { const currentEnd = addMinutes(currentStart, duration); baseSlots.push({ start: currentStart, end: currentEnd }); currentStart = addMinutes(currentEnd, timeToWash); } // 过滤冲突并调整时段 const availableSlots = []; let lastAvailableEnd = dayStart; for (const slot of baseSlots) { // 检查当前时段是否与已预订记录重叠 const hasConflict = bookings.some(booking => { return isWithinInterval(slot.start, { start: booking.start, end: booking.end }) || isWithinInterval(slot.end, { start: booking.start, end: booking.end }) || isWithinInterval(booking.start, { start: slot.start, end: slot.end }); }); if (!hasConflict) { // 确保当前时段起始时间不早于上一个可用/已预订时段结束+洗车时间 const adjustedStart = addMinutes(lastAvailableEnd, timeToWash) > slot.start ? addMinutes(lastAvailableEnd, timeToWash) : slot.start; const adjustedEnd = addMinutes(adjustedStart, duration); if (adjustedEnd <= dayEnd) { availableSlots.push({ start: adjustedStart.toISOString(), end: adjustedEnd.toISOString() }); lastAvailableEnd = adjustedEnd; } } else { // 找到冲突的预订记录,更新lastAvailableEnd为该预订的结束时间 const conflictBooking = bookings.find(booking => { return isWithinInterval(slot.start, { start: booking.start, end: booking.end }) || isWithinInterval(slot.end, { start: booking.start, end: booking.end }) || isWithinInterval(booking.start, { start: slot.start, end: slot.end }); }); lastAvailableEnd = conflictBooking.end; } } return availableSlots; }
三、Express接口示例
1. 安装依赖
npm install mongoose date-fns express
2. 接口实现
const express = require('express'); const app = express(); const mongoose = require('mongoose'); // 连接MongoDB mongoose.connect('mongodb://localhost:27017/car-booking') .then(() => console.log('MongoDB连接成功')) .catch(err => console.error('MongoDB连接失败:', err)); app.use(express.json()); // 获取可用时段接口 app.post('/api/available-slots', async (req, res) => { try { const { selectedDate, duration } = req.body; if (!selectedDate || duration <= 0) { return res.status(400).json({ error: '参数无效,请检查日期和时长' }); } const slots = await generateAvailableSlots(selectedDate, duration); res.json(slots); } catch (err) { res.status(500).json({ error: err.message }); } }); // 创建预订接口 app.post('/api/bookings', async (req, res) => { try { const { start, end, duration } = req.body; const booking = new Booking({ start, end, duration }); await booking.save(); res.status(201).json(booking); } catch (err) { res.status(400).json({ error: err.message }); } }); app.listen(3000, () => console.log('服务运行在端口3000'));
四、关键注意事项
- 时区处理:始终用ISO字符串或MongoDB的Date类型存储时间,避免前后端时区不一致导致的错误
- 性能优化:给预订集合的
start字段创建索引,提升当天预订记录的查询速度 - 边界处理:函数中通过
adjustedEnd <= dayEnd过滤掉超过当天24点的无效时段 - 冲突判断:覆盖了所有重叠场景(当前时段包含预订时段、预订时段包含当前时段、部分重叠)
内容的提问来源于stack exchange,提问作者Sakin
相关产品推荐
相关产品推荐

