前言
阶段七把住院桥接与智能辅助 UI 收成可演示闭环。阶段八转向门诊侧数据可信度与档案治理:开放医疗数据导入后,医生/患者分布失衡、演示账号缺少实习 、 假期 、 停职等真实场景;删除医生档案时患者病历里的接诊医生会消失;列表默认排序把停职案例 but 案例挤到末页看不见;删除接口还因 Pydantic 字段别名报 ValidationError。
本阶段做四件事:演示数据管线与再平衡、在班状态与预约门控、档案列表体验与锁定规则、删除拦截 + 病历医生姓名快照。不新增菜单,核心是工具脚本、服务层校验、ORM/SQL 增量与前端表格/抽屉微调。下文按「问题—根因—改法—联调与踩坑」写,并标注建议配图位置。
目录(仅供提示)
- 背景与阶段八目标
- 开放数据导入与门诊再平衡
- 特殊医师种子:实习 / 假期 / 停职
- 在班状态与患者预约门控
- 档案列表默认排序与停职可见性
- 档案修改权限:谁可以改、谁只读
- 删除医生档案:ValidationError 与临床引用拦截
- 病历接诊医生追溯:姓名快照与多级回退
- 增量 SQL 与脚本清单
- 本地验证与踩坑
- 结语与下阶段排期
1. 背景与阶段八目标
业务上: 带教演示需要实习跟师、假期不可约、停职冻结档案、患者病历永远能查到接诊医生。若停职账号藏在列表最后一页、或删档案后病历医生列空白,演示说服力会大打折扣。
工程上:
| 模块 | 关键路径 |
|---|---|
数据导入 |
|
医生再平衡 |
|
时间线美化 |
|
特殊医师种子 |
|
在班工具 |
|
列表排序 |
|
姓名解析 |
|
删除拦截 |
|
病历快照 |
|
增量 SQL |
|
本阶段交付:
| 项 | 验收方式 |
|---|---|
开放数据导入 |
|
医生患者均衡 | 再平衡脚本后各科室医生均有病例、患者 |
特殊账号 | 6 实习 + 2 假期 + 2 停职,密码 |
在班门控 | 停职/假期/离院不可预约;实习默认可约 |
列表排序 | 医生:在班→状态→科室→专家→姓名;患者:最近就诊→更新时间 |
停职可见 | 末页自动滚动 +「仅看停用」快捷筛选 |
档案锁定 | 停用/离院/暂停执业只读;假期/实习可改 |
删除拦截 | 有病历/处方/预约则拒绝删除,提示改用停用 |
医生追溯 | 病历 |
2. 开放数据导入与门诊再平衡
2.1 现象
a. 导入开放数据集后,病历集中在少数账号(如doctor_wang),其他科室医生列表空荡。
b. 就诊时间扎堆同一天,现病史像模板填空,不像真实门诊节奏。
c. 演示时切换医生账号,候诊/我的患者对不上。
2.2 根因
CPMI / 天池等开放数据未与本地med_clinic_doctor映射;缺少分科室建号与病例再分配脚本;就诊日未打散。
2.3 改法
导入流水线(scripts/clinical_import/):
| 命令 | 说明 |
|---|---|
| 检查数据源与 DB 连通 |
| 知识库 QA 入库 |
| 病历导入(支持 cpmi / tianchi / auto) |
| 清除带 SEED 标签的导入数据 |
再平衡(rebalance_clinic_doctors.py):
按科室批量创建doctor_{dept}{nn}账号
将病历、患者归属从 admin/legacy 账号迁出
支持--dry-run、--max-per-doctor控制每医生病例上限
时间线(realistic_case_timeline.py):
- 就诊日分散到近 4 个月工作日
- 补全现病史问诊叙述(
normalize.enrich_consultation_narrative)
上图仅作部分展示。
3. 特殊医师种子:实习 / 假期 / 停职
3.1 现象
需要演示「实习跟师可接诊」「假期不可约」「停职档案冻结」,但不想改动原有 40 名正常医生。
3.2 改法
scripts/seed_intern_doctors.py独立新增 10 个账号,不改旧数据:
| 类型 | 登录名示例 | status | 说明 |
|---|---|---|---|
实习 |
|
| 6 人,多科室 |
假期 |
|
| 2 人 |
停职 |
|
| 2 人 |
- 人事状态
employment_status保持0(在职),仅用出诊状态区分场景 - 脚本可 补建曾被误删的档案,并恢复误改为停用的旧账号(
RESTORE_NORMAL_USER_IDS) - 统一密码:
admin123
4. 在班状态与患者预约门控
4.1 现象
a. 停职/假期医生仍出现在患者端可预约列表。
b. 患者选到「石停」医生后挂号成功,与业务规则矛盾。
c. 列表「在班」列含义不清。
4.2 根因
仅有med_clinic_doctor.status,未统一「当日是否在班」;预约/挂号入口未校验。
4.3 改法:doctor_duty_util.py
编码约定:
| 字段 | 值 | 含义 |
|---|---|---|
|
| 在班(默认) |
|
| 不在班 |
|
| 正常 / 停用 / 实习 / 假期 |
resolve_doctor_duty规则:
- 停用、离院、暂停执业、假期 →
1不在班 - 实习 → 默认
0在班(跟师;独立出诊以后续排班为准) - 当日排班
stop_flag=1→ 不在班 - 排班未完善时,正常在职默认在班
预约门控assert_doctor_bookable接入:
| 入口 | 文件 |
|---|---|
患者选医生 |
|
患者 DAO 列表过滤 |
|
门诊预约 |
|
现场挂号 |
|
不在班时统一:ServiceException('该医生当前不可预约(假期中/档案已停用/…)')
图中可以看出来不在班和实习的不会被列为可被挂号的医生
5. 档案列表默认排序与停职可见性
5.1 现象
停职演示账号在默认排序下排在最后一页,表格max-height固定,不滚动以为「种子没生效」。
5.2 改法
后端list_sort_util.py:
医生列表:
- 不在班靠后
- 正常 → 实习 → 停用 → 假期(停用排在假期前,便于演示)
- 科室 → 专家号 → sort_num → 姓名
SQL 粗排 +enrich后sort_doctor_rows按onDutyStatus精排当前页。
患者列表:
- 医生「我的患者」:最近就诊日 ↓ → 档案更新时间 ↓ → 姓名 ↑
- 管理员全院:正常档案优先 → 同上
前端clinic/doctor/index.vue:
| 元素 | 行为 |
|---|---|
| 提示停职在末页,需滚动 |
快捷链接 | 「仅看停用/停职」「仅看假期」「仅看实习」 |
| 表单区加高 |
| 末页加载后 |
6. 档案修改权限:谁可以改、谁只读
6.1 现象
停职医生仍能提交档案变更申请;假期医生却被误锁,无法改联系电话。
6.2 改法
is_doctor_profile_locked仅在以下情况锁定:
| 条件 | 锁定 |
|---|---|
| ✅ |
| ✅ |
| ✅ |
| ❌ 可改 |
| ❌ 可改 |
前端:
myProfile.vue:profileLocked时隐藏「提交变更」、展示el-alertdoctor/index.vue管理端编辑:锁定档案表单项disabled,描述「停用/离院/暂停执业:不可修改档案…」
这个不好做展示,就不贴图了。
7. 删除医生档案:ValidationError 与临床引用拦截
7.1 现象
a. 批量删除医生报ValidationError: doctorProfileIds field required。
b. 删除有 hundreds 条病历的医生后,患者档案抽屉「接诊医生」列空白。
c. 用户以为「删档案 = 离职」,实际应「停用」。
7.2 根因
DeleteMedClinicDoctorModel未开populate_by_name,前端 camelCase 无法反序列化- 病历存
doctor_id(用户 ID),展示 joinmed_clinic_doctor取姓名,档案删则 join 失败 - 删除前未统计临床引用
7.3 改法
VO 修复:
class DeleteMedClinicDoctorModel(BaseModel):
model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)
doctor_profile_ids: str # 逗号分隔
删除前校验delete_services:
统计 user_id 关联 → 病历 + 处方 + 预约
若 total > 0 → ServiceException:
「该医生存在临床业务记录(病历 N 条、…),不可删除…请改用停用或离院」
前端确认文案:
若该医生存在病历/处方/预约记录,系统将拒绝删除并提示改用「停用」。
8. 病历接诊医生追溯:姓名快照与多级回退
8.1 设计原则
| 层级 | 策略 |
|---|---|
预防 | 有临床记录禁止物理删档案 |
落库 | 病历写入时冻结 |
展示 | 快照 → 档案 → 用户 → |
8.2 表结构与 ORM
med_case新增:
doctor_name VARCHAR(64) NULL COMMENT '接诊医生姓名快照(落库时冻结,档案删除后仍可追溯)'
ORM:med_case_do.py、med_case_vo.py同步字段。
回填脚本:
mysql ... < sql/patient/upgrade_med_case_doctor_name_snapshot.sql
# 或
python scripts/apply_med_case_doctor_name.py
本地验证:回填 280 条历史病历。
8.3 服务层
| 时机 | 逻辑 |
|---|---|
新建/编辑病历 |
|
列表/分页 |
|
详情 | 无快照时 |
快照与档案不一致 | 附加 |
doctor_display_util.py解析顺序:
med_clinic_doctor.doctor_namesys_user.nick_name/user_name历史医生({uid})
8.4 前端与导出
| 位置 | 变更 |
|---|---|
| 新增列「接诊医生」 |
| Word/PDF 元数据增加「接诊医生」「接诊医生用户ID」 |
9. 增量 SQL 与脚本清单
cd ruoyi-fastapi-backend
# 出诊状态字段注释(0正常 1停用 2实习 3假期)
mysql -u root -p ry-fastapi < sql/patient/upgrade_doctor_clinic_status.sql
# 病历医生姓名快照 + 历史回填
mysql -u root -p ry-fastapi < sql/patient/upgrade_med_case_doctor_name_snapshot.sql
# 特殊医师(不改原医生)
python scripts/seed_intern_doctors.py
# 可选:数据再平衡与时间线
python scripts/rebalance_clinic_doctors.py
python scripts/realistic_case_timeline.py
| 脚本 | 用途 |
|---|---|
| 开放数据导入主入口 |
| 分科建号 + 病例均衡 |
| 就诊日打散 + 叙述补全 |
| 实习/假期/停职种子 |
| 幂等加列 + 回填 |
| 导入后数据审计(可选) |
演示账号速查(密码admin123):
| 账号 | 场景 |
|---|---|
| 实习,可预约 |
| 假期,不可预约 |
| 停职,档案锁定,不可预约 |
10. 本地验证与踩坑
10.1 推荐验证顺序
- 跑
upgrade_doctor_clinic_status.sql+upgrade_med_case_doctor_name_snapshot.sql seed_intern_doctors.py→ 医生列表应 ≥ 50 条- 「仅看停用」→ 见 2 条停职账号
- 患者端预约:选正常医生成功;选停职/假期失败
- 患者档案抽屉 → 就诊记录有「接诊医生」
- 删除有病历医生 → 业务拦截;改 status=停用 → 成功
- 导出病历 → 含接诊医生字段
- 重启后端,使 ORM 新列
doctor_name生效
10.2 踩坑
| 现象 | 原因 | 处理 |
|---|---|---|
删除报 ValidationError | VO 未 | 已修复;强刷前端 |
1054 Unknown column | 未跑快照 SQL | 跑迁移或 |
停职账号「找不到」 | 默认排序在末页 | 点「仅看停用」或滚到底 |
删档案后医生列空白 | 旧数据无快照 | 跑回填;新病历自动写快照 |
PowerShell 内联 Python 引号错 | 转义问题 | 用独立 |
假期账号不能改档案 | 误用旧锁定逻辑 | 确认仅停用/离院/暂停执业锁定 |
列表在班与预约不一致 | SQL 粗排不含当日排班 | 以 |
11. 结语与下阶段规划
阶段八在不加菜单的前提下,把门诊演示数据和档案治理规则补全:导入与再平衡让.wh 让多科室有料可讲;实习/假期/停职种子 + 在班门控让预约规则可演示;列表排序与快捷筛选让特殊账号不再「隐身」;删除拦截 + 病历doctor_name快照让患者历史永远能追到接诊医生。
本篇未做: 处方表doctor_name快照、排班表驱动工作台候诊、全量ry_fastapi.sql合并新列、删除 sys_user 级联策略。
下阶段计划:
1.处方/预约展示层同样落姓名快照
2.排班写入工作台「按日候诊」Tab
3.智能辅助流式输出(阶段七遗留)
4.全量 SQL 与 ORM 扫描脚本纳入 CI