新增功能
This commit is contained in:
@@ -0,0 +1,346 @@
|
||||
# 挂号预约排班状态过滤修复
|
||||
|
||||
## 问题描述
|
||||
|
||||
在挂号预约时,系统显示了所有时间段(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
|
||||
**状态:** ✅ 完成
|
||||
**影响范围:** 挂号预约功能
|
||||
Reference in New Issue
Block a user