# 预约时间自由选择 - 改动文档 ## 1. 需求概述 ### 1.1 当前问题 - 用户只能选择固定时段(凌晨0-6、上午6-12、下午12-18、晚上18-24) - 无法灵活选择具体的开始和结束时间 - 跨时段预约显示不直观 ### 1.2 改动目标 1. **时段显示优化**:如果预约时间为15:00-20:00,房间列表页应显示该房间"下午"和"晚上"都被预定 2. **自由时间选择**:创建预约界面允许用户自由选择开始时间和结束时间 --- ## 2. 改动前分析 ### 2.1 当前时段定义 ``` 时段类型 | 时间范围 | 对应值 --------|----------|------- 凌晨 | 00:00-06:00 | 0 上午 | 06:00-12:00 | 1 下午 | 12:00-18:00 | 2 晚上 | 18:00-24:00 | 3 ``` ### 2.2 当前预约创建流程 ```mermaid flowchart TD A[用户选择日期] --> B[选择房间] B --> C[显示可用时段] C --> D{选择固定时段} D -->|凌晨| E1[设置 00:00-06:00] D -->|上午| E2[设置 06:00-12:00] D -->|下午| E3[设置 12:00-18:00] D -->|晚上| E4[设置 18:00-24:00] E1 --> F[提交预约] E2 --> F E3 --> F E4 --> F F --> G[后端创建预约] ``` ### 2.3 当前前端时间计算逻辑 **文件**: `pages/appointment/appointment-page.vue` ```javascript // 当前代码:根据时段类型计算固定时间 const calculateTimeFromSlot = () => { const date = new Date(selectedDate.value); let startHour, endHour; switch (selectedTimeSlot.value) { case 0: // 凌晨 startHour = 0; endHour = 6; break; case 1: // 上午 startHour = 6; endHour = 12; break; case 2: // 下午 startHour = 12; endHour = 18; break; case 3: // 晚上 startHour = 18; endHour = 24; break; } // ... 设置开始和结束时间 }; ``` ### 2.4 当前房间时段状态显示 **文件**: `pages/appointment/book-room-page.vue` ``` ┌─────────────────────────────────────────┐ │ 房间名称 │ ├─────────────────────────────────────────┤ │ [凌晨] [上午] [下午] [晚上] │ │ 🟢 🟢 🟠 🟢 │ │ │ │ 🟢 可预约 🟠 已预约 ⚫ 不可用 🔵 使用中 │ └─────────────────────────────────────────┘ 当前问题:预约15:00-20:00时,仅显示一个时段被占用 ``` ### 2.5 当前后端时段判断逻辑 **文件**: `CoreCms.Net.Services/SQ/SQRoomsServices.cs` ```csharp // 后端已有重叠判断逻辑(可复用) bool isReserved = reservations?.Any(r => r.start_time < slotEnd && r.end_time > slotStart) ?? false; ``` **分析**:后端逻辑已支持跨时段检测,问题在于前端只能选择单一时段。 --- ## 3. 改动后方案 ### 3.1 新的预约创建流程 ```mermaid flowchart TD A[用户选择日期] --> B[选择房间] B --> C[显示房间详情] C --> D[选择开始时间] D --> E[选择结束时间] E --> F{时间校验} F -->|结束时间 > 开始时间| G[计算跨越时段] F -->|无效| H[提示错误] G --> I[检查时段冲突] I -->|无冲突| J[提交预约] I -->|有冲突| K[提示时段已被预约] J --> L[后端创建预约] L --> M[更新房间时段显示] ``` ### 3.2 新的时间选择UI设计 ``` 改动前(固定时段选择): ┌─────────────────────────────────────────┐ │ 选择时段 │ ├─────────────────────────────────────────┤ │ ○ 凌晨 (00:00-06:00) │ │ ○ 上午 (06:00-12:00) │ │ ● 下午 (12:00-18:00) ← 只能单选 │ │ ○ 晚上 (18:00-24:00) │ └─────────────────────────────────────────┘ 改动后(自由时间选择): ┌─────────────────────────────────────────┐ │ 选择时间 │ ├─────────────────────────────────────────┤ │ 开始时间: [15:00 ▼] ← 时间选择器 │ │ 结束时间: [20:00 ▼] ← 时间选择器 │ │ │ │ 预计时长: 5小时 │ │ 跨越时段: 下午、晚上 │ │ │ │ 💡 提示:结束时间必须晚于开始时间 │ └─────────────────────────────────────────┘ ``` ### 3.3 新的房间列表时段显示 ``` 改动前(15:00-20:00预约后): ┌─────────────────────────────────────────┐ │ [凌晨] [上午] [下午] [晚上] │ │ 🟢 🟢 🟠 🟢 ← 只显示下午 │ └─────────────────────────────────────────┘ 改动后(15:00-20:00预约后): ┌─────────────────────────────────────────┐ │ [凌晨] [上午] [下午] [晚上] │ │ 🟢 🟢 🟠 🟠 ← 下午+晚上 │ └─────────────────────────────────────────┘ ``` ### 3.4 时段重叠判断逻辑 ```mermaid flowchart LR subgraph 预约时间 15:00-20:00 P1[15:00] --> P2[20:00] end subgraph 时段判断 S1[凌晨 0-6] --> R1{重叠?} S2[上午 6-12] --> R2{重叠?} S3[下午 12-18] --> R3{重叠?} S4[晚上 18-24] --> R4{重叠?} end R1 -->|否| N1[🟢] R2 -->|否| N2[🟢] R3 -->|是| Y3[🟠] R4 -->|是| Y4[🟠] ``` **重叠判断公式**: ``` 预约与时段重叠 = (预约开始时间 < 时段结束时间) AND (预约结束时间 > 时段开始时间) 示例:预约15:00-20:00 - 凌晨(0-6): 15 < 6 = false → 不重叠 🟢 - 上午(6-12): 15 < 12 = false → 不重叠 🟢 - 下午(12-18): 15 < 18 = true AND 20 > 12 = true → 重叠 🟠 - 晚上(18-24): 15 < 24 = true AND 20 > 18 = true → 重叠 🟠 ``` --- ## 4. 需要改动的文件清单 ### 4.1 前端改动 | 序号 | 文件路径 | 改动内容 | 复杂度 | |------|----------|----------|--------| | 1 | `pages/appointment/appointment-page.vue` | 将固定时段选择改为时间选择器 | ⭐⭐⭐ | | 2 | `pages/appointment/book-room-page.vue` | 时段状态显示逻辑优化(可能无需改动,后端已支持) | ⭐ | | 3 | `components/com/page/reservation-item.vue` | 预约详情显示时间格式调整 | ⭐ | ### 4.2 后端改动 | 序号 | 文件路径 | 改动内容 | 复杂度 | |------|----------|----------|--------| | 1 | `SQController.cs` | 接收自定义开始/结束时间参数 | ⭐⭐ | | 2 | `SQRoomsServices.cs` | 时段状态判断逻辑已支持,可能需微调 | ⭐ | | 3 | `SQReservationsServices.cs` | 预约冲突检测逻辑验证 | ⭐ | --- ## 5. 详细改动说明 ### 5.1 appointment-page.vue 改动 #### 改动前代码 ```vue ``` #### 改动后代码 ```vue ``` ### 5.2 后端 SQController.cs 改动 #### 改动说明 后端接口已支持接收 `start_time` 和 `end_time` 参数,主要验证逻辑需确认: ```csharp // 添加预约时的冲突检测 [HttpPost("AddSQReservation")] public async Task AddSQReservation([FromBody] AddReservationRequest request) { // 验证时间有效性 if (request.end_time <= request.start_time) { return BadRequest("结束时间必须晚于开始时间"); } // 检查时段冲突(已有逻辑) var conflicts = await _reservationService.CheckTimeConflict( request.room_id, request.start_time, request.end_time ); if (conflicts.Any()) { return BadRequest("所选时段已被预约"); } // 创建预约... } ``` ### 5.3 后端时段显示逻辑验证 **文件**: `SQRoomsServices.cs` 当前逻辑已正确支持跨时段检测: ```csharp // 判断预约是否与时段重叠 bool isReserved = reservations?.Any(r => r.start_time < slotEnd && r.end_time > slotStart) ?? false; ``` **验证场景**: - 预约 15:00-20:00 - 下午时段(12:00-18:00): `15:00 < 18:00 && 20:00 > 12:00` = true ✅ - 晚上时段(18:00-24:00): `15:00 < 24:00 && 20:00 > 18:00` = true ✅ **结论**:后端逻辑无需改动,已支持跨时段显示。 --- ## 6. 数据流对比 ### 6.1 改动前数据流 ```mermaid sequenceDiagram participant U as 用户 participant F as 前端 participant B as 后端 participant DB as 数据库 U->>F: 选择日期 U->>F: 选择房间 F->>B: 获取房间时段状态 B->>DB: 查询已有预约 DB-->>B: 返回预约列表 B-->>F: 返回4个时段状态 F-->>U: 显示可选时段 U->>F: 选择"下午"时段 F->>F: calculateTimeFromSlot() Note over F: 固定设置 12:00-18:00 F->>B: 提交预约(12:00-18:00) B->>DB: 保存预约 DB-->>B: 保存成功 B-->>F: 返回成功 F-->>U: 预约成功 ``` ### 6.2 改动后数据流 ```mermaid sequenceDiagram participant U as 用户 participant F as 前端 participant B as 后端 participant DB as 数据库 U->>F: 选择日期 U->>F: 选择房间 F->>B: 获取房间时段状态 B->>DB: 查询已有预约 DB-->>B: 返回预约列表 B-->>F: 返回4个时段状态 F-->>U: 显示时间选择器 U->>F: 选择开始时间 15:00 U->>F: 选择结束时间 20:00 F->>F: validateTimeRange() F->>F: calculateCrossSlots() Note over F: 显示"下午、晚上" F->>B: 提交预约(15:00-20:00) B->>B: 检查时段冲突 B->>DB: 保存预约 DB-->>B: 保存成功 B-->>F: 返回成功 F-->>U: 预约成功 ``` --- ## 7. 测试用例 ### 7.1 时间选择测试 | 测试场景 | 开始时间 | 结束时间 | 预期结果 | |----------|----------|----------|----------| | 正常选择 | 15:00 | 20:00 | 成功,显示跨越"下午、晚上" | | 同时段选择 | 14:00 | 17:00 | 成功,显示跨越"下午" | | 跨三时段 | 10:00 | 20:00 | 成功,显示跨越"上午、下午、晚上" | | 无效时间 | 20:00 | 15:00 | 失败,提示"结束时间必须晚于开始时间" | | 相同时间 | 15:00 | 15:00 | 失败,提示"结束时间必须晚于开始时间" | ### 7.2 时段冲突测试 | 已有预约 | 新预约 | 预期结果 | |----------|--------|----------| | 15:00-20:00 | 10:00-14:00 | 成功(无重叠) | | 15:00-20:00 | 14:00-16:00 | 失败(重叠) | | 15:00-20:00 | 19:00-22:00 | 失败(重叠) | | 15:00-20:00 | 20:00-22:00 | 成功(边界无重叠) | ### 7.3 房间列表显示测试 | 预约时间 | 凌晨 | 上午 | 下午 | 晚上 | |----------|------|------|------|------| | 02:00-05:00 | 🟠 | 🟢 | 🟢 | 🟢 | | 10:00-14:00 | 🟢 | 🟠 | 🟠 | 🟢 | | 15:00-20:00 | 🟢 | 🟢 | 🟠 | 🟠 | | 22:00-04:00 | 🟠 | 🟢 | 🟢 | 🟠 | --- ## 8. 工作量评估 | 模块 | 工作内容 | 复杂度 | |------|----------|--------| | 前端-预约页面 | 时间选择器组件替换、时间计算逻辑 | ⭐⭐⭐ | | 前端-房间列表 | 验证显示逻辑(可能无需改动) | ⭐ | | 前端-预约详情 | 时间格式显示调整 | ⭐ | | 后端-控制器 | 参数验证、冲突检测 | ⭐⭐ | | 后端-服务层 | 逻辑验证(可能无需改动) | ⭐ | | 测试 | 各场景测试 | ⭐⭐ | **总体评估**:中等复杂度改动,主要工作集中在前端预约页面的UI和逻辑重构。 --- ## 9. 风险与注意事项 1. **向后兼容**:已有的固定时段预约数据仍可正常显示 2. **边界条件**:跨天预约(如23:00-02:00)需特殊处理 3. **时间精度**:建议时间选择以30分钟为最小单位 4. **用户体验**:需添加明确的时长提示和时段跨越提示 5. **数据验证**:前后端都需要进行时间有效性验证 --- ## 10. 附录:时段判断工具函数 ```javascript /** * 判断时间范围跨越哪些时段 * @param {number} startHour 开始小时 (0-23) * @param {number} endHour 结束小时 (0-24) * @returns {Array} 跨越的时段数组 */ function getCrossedSlots(startHour, endHour) { const slots = []; const slotRanges = [ { name: '凌晨', start: 0, end: 6 }, { name: '上午', start: 6, end: 12 }, { name: '下午', start: 12, end: 18 }, { name: '晚上', start: 18, end: 24 } ]; for (const slot of slotRanges) { // 重叠判断:预约开始 < 时段结束 AND 预约结束 > 时段开始 if (startHour < slot.end && endHour > slot.start) { slots.push(slot.name); } } return slots; } // 使用示例 getCrossedSlots(15, 20); // ['下午', '晚上'] getCrossedSlots(10, 14); // ['上午', '下午'] getCrossedSlots(2, 5); // ['凌晨'] ```