Files
zyt/app/research/diagnosis_post_flow_audit.md
2026-08-11 09:12:51 +08:00

154 lines
14 KiB
Markdown
Raw Permalink 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.
# 诊单视觉重构最终业务回归审计(三次终验)
- 终验日期:2026-08-10
- 范围:生产视频/IM、医生备注与日常记录 mutation、处方/订单、多挂号精确取消、诊单 Shell owner、列表 QR/日志/订单;并复核上一版已关闭的权限、DTO、隐私与 generation 项。
- 基准:当前最新 Python 源码与测试,以及 `D:/web/zyt/admin``D:/web/zyt/server` 的实际 admin 行为和服务端控制器/Logic。
- 约束:只读业务终验;未安装依赖、未打包、未访问线上接口。除更新本报告外,未修改业务源码或测试。
## 最终结论
第三次终验后的剩余项为:
- **P00,明确无 P0。**
- **P11 项 OPEN。** 诊单列表“创建订单”已调用真实 `order.order/create`,但没有消费返回的 `order_no` 并调用现成的 `generate_order_qrcode`,admin 的付款二维码闭环仍中断。
- **P22 项 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 / 日志 / 创建订单 | **OPENQR/日志/创建主体 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 探针结果:
```text
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 放在系统临时目录;未安装任何依赖:
```text
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,不能作为桌面端单独修复项。