Files
xuetang/app/research/diagnosis_post_flow_audit.md
2026-09-08 11:40:15 +08:00

14 KiB
Raw Permalink Blame History

诊单视觉重构最终业务回归审计(三次终验)

  • 终验日期:2026-08-10
  • 范围:生产视频/IM、医生备注与日常记录 mutation、处方/订单、多挂号精确取消、诊单 Shell owner、列表 QR/日志/订单;并复核上一版已关闭的权限、DTO、隐私与 generation 项。
  • 基准:当前最新 Python 源码与测试,以及 D:/web/zyt/admin、D:/web/zyt/server 的实际 admin 行为和服务端控制器/Logic。
  • 约束:只读业务终验;未安装依赖、未打包、未访问线上接口。除更新本报告外,未修改业务源码或测试。

最终结论

第三次终验后的剩余项为:

  • P0:0,明确无 P0。
  • P1:1 项 OPEN。 诊单列表“创建订单”已调用真实 order.order/create,但没有消费返回的 order_no 并调用现成的 generate_order_qrcode,admin 的付款二维码闭环仍中断。
  • P2:2 项 OPEN。 一是日常矩阵不能编辑已有血糖/饮食/运动记录;二是视频回放只显示每条记录的第一个 URL,且没有 admin 的“向具体通话记录追加回放”入口。
  • 服务端不可实现限制:不计入 P0/P1/P2。 医生备注与跟踪备注的服务端契约只支持按当天追加;服务端没有任意旧正文覆盖或整条删除 endpoint,桌面端无法在不扩展后端的前提下实现这些动作。
  • 其余本轮复核项均 CLOSED:生产视频/IM 取数与同步、备注追加/附件、日常新增与待办、处方动作、订单详情/偏移、精确挂号取消、列表视频/确认 QR 与日志、真实 Shell 60%/move-resize/close generation。
  • 定向离线回归:128/128 passed。
复核项 三次终验状态 最终等级 摘要
生产视频/IM only_archived、sync、上传、回放 OPEN(主体 CLOSED) P2 生产接口、同步、工具栏上传和首个回放可用;多 URL 与指定 call-record 追加入口缺失
医生备注 mutation CLOSED — 追加正文、上传舌象/报告、删除单附件均走真实合同;正文覆盖/整条删除属后端无 endpoint 限制
日常记录 mutation OPEN(新增 CLOSED) P2 新增血糖/饮食/运动/跟踪备注及待办新增/取消可用;已有三类记录不能编辑
处方/详情订单动作 CLOSED — 开方、处方查看、业务订单列表/详情与诊次偏移均真实落库/取数
多挂号精确取消 CLOSED — 每个挂号卡携带精确 ID,最终调用 doctor.appointment/cancel
诊单 owner、60%、move-resize、generation CLOSED — 每次打开重绑真实 Shell,宽度为 Shell 60%,移动/缩放/关闭同步且所有异步代次失效
列表 QR / 日志 / 创建订单 OPEN(QR/日志/创建主体 CLOSED) P1 视频/确认 QR、日志、创建订单均真实调用;创建成功后的支付 QR 未接入 UI

上一版已关闭的 phonePlain、canonical diagnosis_type、viewOnly endpoint 分流、detail 失败禁存、身份证 15/18 位校验、权限 Tab 裁剪与隐私脱敏,本轮定向回归均未发现反弹。

逐项证据

1. 生产视频/IM:[OPEN / P2,主体 CLOSED]

已关闭部分:

  • RemoteDoctorRepository 已实现生产 getCallRecords、手工 call record、附件关联及“上传 → 创建记录 → 关联”顺序:src/doctor_workstation/services/repository.py:1875-1943。这与 admin CallRecordPanel 的真实流程一致:D:/web/zyt/admin/src/views/tcm/diagnosis/components/CallRecordPanel.vue:109-180。
  • IM 首次读取明确发 only_archived=1,同步走 triggerImChatSync:src/doctor_workstation/services/repository.py:1945-1965;dialog 的 lazy 查询也固定 only_archived=True:src/doctor_workstation/ui/dialogs/diagnosis.py:2016-2038。admin 对照为 D:/web/zyt/admin/src/views/tcm/diagnosis/components/ImChatRecordPanel.vue:148-185。
  • edit 态视频工具栏调用真实上传,成功后按 media generation 重新加载;聊天同步成功后延时重新读取归档:src/doctor_workstation/ui/dialogs/diagnosis.py:2541-2611。聊天图片/文件只能通过 HTTP(S) 安全打开::2652-2658。
  • production/server 合同存在:D:/web/zyt/server/app/adminapi/controller/tcm/DiagnosisController.php:397-438、:505-538;归档快路径在 D:/web/zyt/server/app/adminapi/logic/tcm/DiagnosisLogic.php:1015-1045。

仍 OPEN 的 P2:

  • 服务端返回 recording_urls_list 数组:D:/web/zyt/server/app/adminapi/logic/tcm/DiagnosisLogic.php:1810-1833;admin 把完整数组交给播放器,并在每个具体 call row 提供上传入口:D:/web/zyt/admin/src/views/tcm/diagnosis/components/CallRecordPanel.vue:30-72。
  • Python _fill_video 只取 raw_urls[0],其余回放不可见,且视频表没有指定 call_record_id 的上传操作列:src/doctor_workstation/ui/dialogs/diagnosis.py:1126-1135、:2844-2881。虽然 repository 已支持 call_record_id(src/doctor_workstation/services/repository.py:1894-1913),UI 没有把它接出来。

该问题不造成错误写入,且工具栏上传与一个回放可用,故按 P2 而非 P1 计。

2. 医生备注:[CLOSED;后端限制已明确]

  • NotesTimeline 已暴露新增、上传、删除单附件与打开附件信号:src/doctor_workstation/ui/diagnosis_drawer.py:1804-1810、:1820-1851、:1887-1961;dialog 绑定真实方法:src/doctor_workstation/ui/dialogs/diagnosis.py:989-997、:2376-2487。
  • production DTO 分别走 doctor.appointment/addDoctorNote、doctor.appointment/doctorNotes、doctor.appointment/deleteDoctorNoteImage:src/doctor_workstation/services/repository.py:935-985。权限分别按新增与删除附件 endpoint 裁剪:src/doctor_workstation/ui/dialogs/diagnosis.py:478-483、:1233-1241。
  • admin 自身也只有追加、上传、删除单附件动作:D:/web/zyt/admin/src/views/patient/reception/components/NoteTimeline.vue:195-268;API 定义仅三条:D:/web/zyt/admin/src/api/patient.ts:19-40。

服务端不可实现边界:

  • controller 仅暴露 addDoctorNote、doctorNotes、deleteDoctorNoteImage,随后类即结束:D:/web/zyt/server/app/adminapi/controller/doctor/AppointmentController.php:168-198。
  • DoctorNoteLogic::addOrAppend 对当天正文使用换行追加,不支持任意旧正文覆盖:D:/web/zyt/server/app/adminapi/logic/doctor/DoctorNoteLogic.php:12-76;唯一删除逻辑只删除附件数组中的单项::111-136。

因此“任意旧笔记正文覆盖/整条删除”不是桌面端漏接已有合同,而是服务端没有 endpoint;本报告将其列为后端限制,不计客户端 P0/P1/P2。

3. 日常记录:[OPEN / P2,新增 CLOSED]

已关闭部分:

  • edit 态已提供血糖、饮食、运动、跟踪备注新增按钮和待办新增/取消;只读态/无权限态隐藏:src/doctor_workstation/ui/diagnosis_drawer.py:1363-1371、:1431-1450、:1481-1511、:1760-1791。
  • dialog 将 signal 接到真实 add/todo repository,并为每次 mutation 使用 diagnosis-id + generation 校验后强制刷新:src/doctor_workstation/ui/dialogs/diagnosis.py:1089-1101、:2175-2358。
  • production 合同为 tcm.bloodRecord/add、tcm.dietRecord/add、tcm.exerciseRecord/add、tcm.diagnosis/addTrackingNote、todo add/cancel:src/doctor_workstation/services/repository.py:1745-1765、:1778-1805、:1847-1873。

仍 OPEN 的 P2:

  • admin 点击已有单元格时会把记录(含 id)放入表单,保存时分别调用 blood/diet/exercise edit:D:/web/zyt/admin/src/views/tcm/diagnosis/components/DailyMatrix.vue:921-1013。
  • Python matrix 明确 NoEditTriggers、NoSelection,只有 daily_add_requested,没有已有记录 edit signal:src/doctor_workstation/ui/diagnosis_drawer.py:1366-1371、:1455-1463。dialog 也只选择 add_*:src/doctor_workstation/ui/dialogs/diagnosis.py:2260-2284。
  • 这不是后端限制:production repository 已实现三类 edit:src/doctor_workstation/services/repository.py:1767-1776、:1787-1796、:1807-1818。

跟踪备注例外:server 设计就是“仅给今天追加”。controller 仅有 add/list:D:/web/zyt/server/app/adminapi/controller/tcm/DiagnosisController.php:180-214;TrackingNoteLogic 只有 addOrAppend/getByDiagnosis,类在第 95 行结束:D:/web/zyt/server/app/adminapi/logic/tcm/TrackingNoteLogic.php:8-95。其任意旧正文覆盖/整条删除同样属于后端无 endpoint 限制,不计客户端问题。

4. 处方与详情订单动作:[CLOSED]

  • “开具处方”打开真实 PrescriptionEditorDialog,accepted 后调用 create_prescription,并携带 diagnosis/appointment/case snapshot:src/doctor_workstation/ui/dialogs/diagnosis.py:2489-2539。
  • 历史处方的“查看”打开真实 PrescriptionDetailDialog::2791-2842。
  • 业务订单 lazy 列表、详情权限/真实 repository 门禁、异步 order generation 及详情 dialog 均已接通::1998-2000、:2069-2074、:2883-2991。
  • 全局诊次偏移调用真实 setRevisitSlotStartOffset,并有独立 generation::2613-2650。

未发现处方或详情订单的假动作/越权入口,本项 CLOSED。

5. 多挂号精确取消:[CLOSED]

  • 每个可取消挂号卡按精确 primary key 生成按钮,signal 携带原 record 与该 appointment-id:src/doctor_workstation/ui/diagnosis_index_widgets.py:150-163、:1121-1148。歧义的行级“取消挂号”仍只在唯一挂号时出现::1403-1410。
  • handler 选择当前诊单后再次按 ID 和状态校验,确认前后都防 stale,最终仅调用 exact capability:src/doctor_workstation/ui/pages/consultations.py:1868-1921。
  • production 方法明确走 doctor.appointment/cancel,不再误用患者工作区 endpoint:src/doctor_workstation/services/repository.py:1545-1555。
  • 新测试覆盖两个挂号、超 32 位 appointment-id、错误诊单、状态刷新、权限/能力缺失与 canonical endpoint:tests/test_diagnosis_index_visual.py:340-379、tests/test_consultations_parity_ui.py:610-774、tests/test_diagnosis_detail_contract.py:90-105。

本项 CLOSED。

6. 真实 Shell owner / 60% / move-resize / generation:[CLOSED]

  • _owner 不再在 page 构造期缓存;每次 open_for/showEvent 都从当前 parent.window() 重绑真实 Shell:src/doctor_workstation/ui/dialogs/diagnosis.py:526-527、:1314-1349、:1398-1408。
  • overlay 与 owner 同位置/尺寸,宽屏 drawer 固定为 owner 宽度 60%;监听 owner 的 Resize/Move/Show/Close::1283-1299、:1351-1371。
  • reject/done 及 owner Close 会使 detail/save/orders/order-detail/daily/notes/media/offset/所有 lazy-tab generation 全部失效::1373-1383、:1681-1700。

真实 ShellWindow -> QStackedWidget -> ConsultationsPage -> cached DiagnosisDialog offscreen 探针结果:

OPEN  owner_shell=True shell=(1200,760) dialog=(1200,760) panel=720 expected=720 pos=(80,60)
MOVED shell=(1024,650) dialog=(1024,650) panel=614 expected=614 pos=(190,140)
CLOSE visible=False generation=True media=True

本项 CLOSED。现有 tests/test_diagnosis_drawer_visual.py:837-861 仍只用直接顶层 owner;本次额外真实 Shell 探针补足了业务终验,但建议后续把该探针固化成回归测试。

7. 列表 QR / 日志 / 订单:[OPEN / P1,主体 CLOSED]

已关闭部分:

  • 页面只在 canonical 权限与真实 repository 方法同时存在时展示视频 QR、确认 QR、日志、订单入口:src/doctor_workstation/ui/pages/consultations.py:704-715、:1005-1030。
  • QR DTO 校验 patient/doctor/share-user/diagnosis,日志使用 diagnosis-id,所有菜单请求均受 selection generation 保护::1972-2091。
  • production repository 真实调用 generateMiniProgramQrcode、guahaoLogList、order.order/create:src/doctor_workstation/services/repository.py:1967-2060。测试验证 exact DTO、权限裁剪与 stale callback:tests/test_diagnosis_detail_contract.py:85-127、tests/test_consultations_parity_ui.py:777-958。

仍 OPEN 的 P1:

  • admin 创建订单成功后读取 order_no,立即调用 generateOrderQrcode 并展示付款 QR:D:/web/zyt/admin/src/views/tcm/diagnosis/index.vue:1474-1509。
  • Python _create_diagnosis_order 把真实 create 放进通用 _run_mutation;该 helper 丢弃 _result,只 toast + refresh,因此永远不会生成付款 QR:src/doctor_workstation/ui/pages/consultations.py:2093-2128、:2460-2479。
  • repository 明明已有 generate_order_qrcode:src/doctor_workstation/services/repository.py:2062-2076,但 UI 源码没有任何调用。现有测试也只分别测试“UI 创建订单”和“repository 可生成 QR”,未覆盖两者串联:tests/test_consultations_parity_ui.py:777-872、tests/test_diagnosis_detail_contract.py:88-89。

订单已实际创建却不展示付款入口,用户容易停在半完成状态或重复建单;这是主流程闭环缺失,按 P1 OPEN 计。

离线验证记录

使用项目现有 .venv,设置 QT_QPA_PLATFORM=offscreen、PYTHONDONTWRITEBYTECODE=1,禁用 pytest cache,并把 basetemp 放在系统临时目录;未安装任何依赖:

pytest -q -p no:cacheprovider \
  tests/test_diagnosis_detail_contract.py \
  tests/test_diagnosis_index_visual.py \
  tests/test_diagnosis_drawer_visual.py \
  tests/test_appointment_drawer_visual.py \
  tests/test_consultations_parity_ui.py \
  tests/test_prescription_security_ui.py \
  tests/test_patients_ui.py \
  tests/test_repository_parity.py \
  tests/test_permissions.py

128 passed

测试退出码为 0;--collect-only -q 分文件计数合计 128。另执行了上述真实 Shell owner 探针,退出码为 0。

发布判断

当前不存在错误 endpoint、歧义挂号取消、权限泄漏、隐私明文回流或关闭后旧异步回调落地等 P0 风险。生产视频/IM、备注追加、日常新增、处方、订单详情及列表主要动作均已从“假动作/未接入”进展为真实 repository 行为。

但若发布标准是“完整保留 admin 的订单支付闭环与所有已存在的数据编辑/回放能力”,当前仍不满足:剩余 P0 0 / P1 1 / P2 2。其中任意旧医生/跟踪笔记正文覆盖或整条删除必须先扩展 server endpoint,不能作为桌面端单独修复项。