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

7.7 KiB
Raw Blame History

挂号预约排班状态过滤修复

问题描述

在挂号预约时,系统显示了所有时间段(9:00-18:00),但没有检查医生的排班状态。即使医生休息或停诊,系统仍然显示可预约时段。

问题截图说明

从截图可以看到:

  • 周三 03-04 下午显示"休息"
  • 但系统仍然可能显示下午的预约时段

排班状态定义

根据数据库模型 Roster,排班状态定义如下:

状态值 状态名称 说明
1 出诊 医生正常出诊,可以预约
2 停诊 医生停诊,不可预约
3 休息 医生休息,不可预约
4 请假 医生请假,不可预约

排班时段定义

时段值 时段名称 时间范围
1 上午 09:00-12:00
2 下午 14:00-18:00

问题根源

原来的逻辑

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. 即使医生休息也显示可预约

解决方案

修复后的逻辑

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

前端显示逻辑

前端已经正确处理了排班状态的过滤:

// 加载医生排班信息
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. 选择时段

用户选择时段 → 检查是否已被预约 → 创建预约

数据库查询

查询医生出诊排班

SELECT * FROM zyt_doctor_roster
WHERE doctor_id = 1
  AND date = '2026-03-04'
  AND status = 1  -- 只查询出诊状态
ORDER BY period ASC;

查询已预约时段

SELECT appointment_time FROM zyt_doctor_appointment
WHERE doctor_id = 1
  AND appointment_date = '2026-03-04'
  AND status = 1  -- 只查询有效预约

测试用例

测试 1:医生全天出诊

-- 插入排班
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:医生上午出诊,下午休息

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:医生全天休息

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:医生上午停诊,下午出诊

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 状态: 完成 影响范围: 挂号预约功能