# 预约时间自由选择 - 改动文档
## 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
{{ slot.label }}
```
#### 改动后代码
```vue
开始时间
{{ startTime || '请选择' }}
结束时间
{{ endTime || '请选择' }}
预计时长: {{ calculateDuration() }}
跨越时段: {{ calculateCrossSlots() }}
```
### 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); // ['凌晨']
```