This commit is contained in:
Your Name
2026-08-11 09:12:51 +08:00
parent c3ceb0dd0f
commit cfe4c82c90
111 changed files with 26110 additions and 826 deletions
+153
View File
@@ -0,0 +1,153 @@
# 诊单视觉重构最终业务回归审计(三次终验)
- 终验日期: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,不能作为桌面端单独修复项。