Files
zyt/APPOINTMENT_ROSTER_STATUS_FIX.md
T
2026-03-04 15:32:30 +08:00

347 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 挂号预约排班状态过滤修复
## 问题描述
在挂号预约时,系统显示了所有时间段(9:00-18:00),但没有检查医生的排班状态。即使医生休息或停诊,系统仍然显示可预约时段。
### 问题截图说明
从截图可以看到:
- 周三 03-04 下午显示"休息"
- 但系统仍然可能显示下午的预约时段
## 排班状态定义
根据数据库模型 `Roster`,排班状态定义如下:
| 状态值 | 状态名称 | 说明 |
|--------|---------|------|
| 1 | 出诊 | 医生正常出诊,可以预约 |
| 2 | 停诊 | 医生停诊,不可预约 |
| 3 | 休息 | 医生休息,不可预约 |
| 4 | 请假 | 医生请假,不可预约 |
## 排班时段定义
| 时段值 | 时段名称 | 时间范围 |
|--------|---------|---------|
| 1 | 上午 | 09:00-12:00 |
| 2 | 下午 | 14:00-18:00 |
## 问题根源
### 原来的逻辑
```php
public static function getAvailableSlots(array $params)
{
// 1. 直接生成 9:00-18:00 的所有时间段
for ($hour = 9; $hour < 18; $hour++) {
for ($minute = 0; $minute < 60; $minute += 15) {
$slots[] = [
'time' => sprintf('%02d:%02d', $hour, $minute),
'available' => true,
'quota' => 1
];
}
}
// 2. 只检查已预约的时间段
// ❌ 没有检查医生的排班状态
}
```
### 问题
1. 不检查医生是否有排班
2. 不检查排班状态(出诊/休息/停诊)
3. 不区分上午/下午时段
4. 即使医生休息也显示可预约
## 解决方案
### 修复后的逻辑
```php
public static function getAvailableSlots(array $params)
{
// 1. 先检查医生在该日期是否有出诊排班
$rosters = Roster::where([
'doctor_id' => $doctorId,
'date' => $date,
'status' => 1 // ✅ 只查询出诊状态
])->select()->toArray();
// 如果没有出诊排班,返回空数组
if (empty($rosters)) {
return ['slots' => []];
}
// 2. 根据排班时段生成时间段
foreach ($rosters as $roster) {
if ($roster['period'] == 1) {
// 上午:9:00-12:00
$startHour = 9;
$endHour = 12;
} elseif ($roster['period'] == 2) {
// 下午:14:00-18:00
$startHour = 14;
$endHour = 18;
}
// 生成15分钟间隔的时间段
for ($hour = $startHour; $hour < $endHour; $hour++) {
for ($minute = 0; $minute < 60; $minute += 15) {
$slots[] = [
'time' => sprintf('%02d:%02d', $hour, $minute),
'available' => true,
'quota' => 1,
'period' => $roster['period']
];
}
}
}
// 3. 查询已预约的时间段并标记
// ...
}
```
## 修复效果
### 场景 1:医生上午出诊,下午休息
**排班数据:**
```
date: 2026-03-04
period: 1 (上午)
status: 1 (出诊)
```
**预约时段:**
- ✅ 显示:09:00, 09:15, 09:30, ..., 11:45
- ❌ 不显示:14:00-18:00 的时段
### 场景 2:医生全天休息
**排班数据:**
```
date: 2026-03-04
period: 1 (上午)
status: 3 (休息)
date: 2026-03-04
period: 2 (下午)
status: 3 (休息)
```
**预约时段:**
- ❌ 不显示任何时段
- 💡 提示:该医生暂无可预约时段
### 场景 3:医生全天出诊
**排班数据:**
```
date: 2026-03-04
period: 1 (上午)
status: 1 (出诊)
date: 2026-03-04
period: 2 (下午)
status: 1 (出诊)
```
**预约时段:**
- ✅ 显示:09:00-11:45 (上午)
- ✅ 显示:14:00-17:45 (下午)
### 场景 4:医生上午停诊,下午出诊
**排班数据:**
```
date: 2026-03-04
period: 1 (上午)
status: 2 (停诊)
date: 2026-03-04
period: 2 (下午)
status: 1 (出诊)
```
**预约时段:**
- ❌ 不显示:09:00-12:00 的时段
- ✅ 显示:14:00-17:45 (下午)
## 时间段生成规则
### 上午时段(period = 1
```
开始时间:09:00
结束时间:12:00
间隔:15分钟
生成时段:
09:00, 09:15, 09:30, 09:45,
10:00, 10:15, 10:30, 10:45,
11:00, 11:15, 11:30, 11:45
```
### 下午时段(period = 2
```
开始时间:14:00
结束时间:18:00
间隔:15分钟
生成时段:
14:00, 14:15, 14:30, 14:45,
15:00, 15:15, 15:30, 15:45,
16:00, 16:15, 16:30, 16:45,
17:00, 17:15, 17:30, 17:45
```
## 前端显示逻辑
前端已经正确处理了排班状态的过滤:
```typescript
// 加载医生排班信息
const loadDoctorRoster = async () => {
const res = await rosterLists({
doctor_id: selectedDoctorId.value,
start_date: startDate,
end_date: endDate,
status: 1 // ✅ 只查询出诊状态
})
// 提取有排班的日期
if (res?.lists && res.lists.length > 0) {
doctorRosterDates.value = [...new Set(res.lists.map(item => item.date))].sort()
}
}
```
## 完整流程
### 1. 选择医生
```
用户选择医生 → 加载医生排班 → 只显示有出诊排班的日期
```
### 2. 选择日期
```
用户选择日期 → 加载该日期的可用时段 → 只显示出诊时段的时间
```
### 3. 选择时段
```
用户选择时段 → 检查是否已被预约 → 创建预约
```
## 数据库查询
### 查询医生出诊排班
```sql
SELECT * FROM zyt_doctor_roster
WHERE doctor_id = 1
AND date = '2026-03-04'
AND status = 1 -- 只查询出诊状态
ORDER BY period ASC;
```
### 查询已预约时段
```sql
SELECT appointment_time FROM zyt_doctor_appointment
WHERE doctor_id = 1
AND appointment_date = '2026-03-04'
AND status = 1 -- 只查询有效预约
```
## 测试用例
### 测试 1:医生全天出诊
```sql
-- 插入排班
INSERT INTO zyt_doctor_roster (doctor_id, date, period, status, quota, max_patients)
VALUES
(1, '2026-03-10', 1, 1, 20, 20), -- 上午出诊
(1, '2026-03-10', 2, 1, 20, 20); -- 下午出诊
```
**预期结果:**
- 显示上午时段:09:00-11:45
- 显示下午时段:14:00-17:45
### 测试 2:医生上午出诊,下午休息
```sql
INSERT INTO zyt_doctor_roster (doctor_id, date, period, status, quota, max_patients)
VALUES
(1, '2026-03-11', 1, 1, 20, 20), -- 上午出诊
(1, '2026-03-11', 2, 3, 0, 0); -- 下午休息
```
**预期结果:**
- 显示上午时段:09:00-11:45
- 不显示下午时段
### 测试 3:医生全天休息
```sql
INSERT INTO zyt_doctor_roster (doctor_id, date, period, status, quota, max_patients)
VALUES
(1, '2026-03-12', 1, 3, 0, 0), -- 上午休息
(1, '2026-03-12', 2, 3, 0, 0); -- 下午休息
```
**预期结果:**
- 该日期不出现在可选日期列表中
- 如果强制访问,不显示任何时段
### 测试 4:医生上午停诊,下午出诊
```sql
INSERT INTO zyt_doctor_roster (doctor_id, date, period, status, quota, max_patients)
VALUES
(1, '2026-03-13', 1, 2, 0, 0), -- 上午停诊
(1, '2026-03-13', 2, 1, 20, 20); -- 下午出诊
```
**预期结果:**
- 不显示上午时段
- 显示下午时段:14:00-17:45
## 已修改的文件
-`server/app/adminapi/logic/doctor/AppointmentLogic.php`
## 优势
1. **准确性**:只显示医生实际出诊的时段
2. **用户体验**:避免用户选择无效时段
3. **数据一致性**:预约数据与排班数据保持一致
4. **灵活性**:支持上午/下午独立设置状态
5. **可维护性**:逻辑清晰,易于理解和维护
## 注意事项
1. **排班状态**:只有 `status = 1`(出诊)的排班才会生成时段
2. **时段区分**:上午和下午时段独立判断
3. **时间格式**:统一使用 `HH:MM` 格式(如:09:00
4. **已预约检查**:在生成时段后,还需要检查已预约情况
5. **空数组处理**:如果没有出诊排班,返回空数组而不是错误
---
**修复日期:** 2024-03-04
**状态:** ✅ 完成
**影响范围:** 挂号预约功能