261 lines
21 KiB
Markdown
261 lines
21 KiB
Markdown
# 医生工作站最终发布 parity 审计
|
||
|
||
审计日期:2026-08-10
|
||
|
||
审计对象:`D:\web\zyt\app` 当前源码
|
||
|
||
唯一 Web 基准:`D:\web\zyt\admin\src\views` 及其直接引用的 `src/api`、`src/components`、`src/utils`
|
||
判定范围:医生桌面五页面(接诊台、我的患者、我的问诊、我的处方库、已开处方)及其 `core/services/video` 支撑合同。
|
||
|
||
## 1. 发布结论
|
||
|
||
**RELEASE CANDIDATE。** 原报告的 3 个 P0 与 10 个 P1 已全部关闭:
|
||
|
||
- P0:`CLOSED 3 / OPEN 0`
|
||
- P1:`CLOSED 10 / OPEN 0`
|
||
- 当前未发现医生桌面范围内的发布阻断项。
|
||
- 处方预约上下文、附件上传和预约 ID 语义等高风险路径均有反例测试。
|
||
- 全量测试:**140 项通过**。
|
||
- 静态检查:`ruff check src tests` 通过;`ruff format --check src tests` 显示 **53 files already formatted**。
|
||
|
||
本结论是客户端源码、管理端基准和纯本地测试合同的发布复审结论;服务端生产权限、数据归属和真实第三方视频可用性仍应由部署环境验收。
|
||
|
||
## 2. OPEN / CLOSED 总表
|
||
|
||
| 编号 | 原问题 | 最终状态 | parity 结论 |
|
||
|---|---|---:|---:|
|
||
| P0-1 | 接诊附件未 multipart 上传并可能泄漏本机路径 | **CLOSED** | **EXACT** |
|
||
| P0-2 | appointment 处方查询回退 diagnosis 历史处方,缺 `case_record` | **CLOSED** | **EXACT / fail-closed 加固** |
|
||
| P0-3 | 我的患者预约误用真实患者 ID,排班 DTO 不完整 | **CLOSED** | **EXACT** |
|
||
| P1-1 | DiagnosisDialog 字段缩水、隐私与唯一性检查缺失 | **CLOSED** | **EXACT** |
|
||
| P1-2 | 预约表单缺医生排班、服务端号源和关键字段 | **CLOSED** | **EXACT** |
|
||
| P1-3 | 诊单上下文订单缺失,支付/退款字段缩水 | **CLOSED** | **EXACT** |
|
||
| P1-4 | 建单 paid-order/定金未加载或串诊单竞态 | **CLOSED** | **EXACT / fail-closed 加固** |
|
||
| P1-5 | 患者写操作 latest-wins 吞掉已执行 mutation 回调 | **CLOSED** | **EXACT** |
|
||
| P1-6 | QRunnable worker 读取 QWidget | **CLOSED** | **EXACT** |
|
||
| P1-7 | permission helper 接受点号/斜杠别名,handler 缺二次门槛 | **CLOSED** | **EXACT** |
|
||
| P1-8 | 原生医生直呼复用小程序 `videoQr` 权限 | **CLOSED** | **EXACT(客户端)** |
|
||
| P1-9 | 接诊队列固定前 50 条 | **CLOSED** | **EXACT** |
|
||
| P1-10 | 已开处方无 `readonlyDetail` 权限仍请求诊单 | **CLOSED** | **EXACT** |
|
||
|
||
## 3. P0 逐项复核
|
||
|
||
### P0-1 multipart、两阶段提交与安全路径 — CLOSED
|
||
|
||
Admin 合同:
|
||
|
||
- `D:\web\zyt\admin\src\api\file.ts:9-32`:`POST /upload/image|file`,multipart 字段为 `file`、`cid`,返回 `uri/url`。
|
||
- `D:\web\zyt\admin\src\components\material\picker.vue:260-283`:业务组件只接收上传后的服务端地址。
|
||
- `D:\web\zyt\admin\src\views\patient\reception\components\NoteTimeline.vue:195-225`:最终备注 DTO 为 `diagnosis_id/content/tongue_images/report_files`。
|
||
- `D:\web\zyt\admin\src\api\patient.ts:20-26`:最终提交 `POST /doctor.appointment/addDoctorNote`。
|
||
|
||
App 证据:
|
||
|
||
- `D:\web\zyt\app\src\doctor_workstation\services\api_client.py:134-157,172-196,249-270`:真实 multipart;上传请求不继承 JSON `Content-Type`,boundary 由 `httpx` 生成。
|
||
- `D:\web\zyt\app\src\doctor_workstation\services\repository.py:796-818`:图片走 `upload/image`、文件走 `upload/file`,发送 `file` 与 `cid=0`。
|
||
- `D:\web\zyt\app\src\doctor_workstation\ui\pages\reception.py:1485-1518,1520-1573`:GUI 线程先快照本地选择;worker 按顺序上传全部材料,全部成功后才提交备注。
|
||
- `D:\web\zyt\app\src\doctor_workstation\services\repository.py:825-848,1781-1831`:上传响应和最终 JSON 双层拒绝盘符路径、UNC、`file:` 与反斜杠本机路径;空 `uri/url` 也拒绝。
|
||
- `D:\web\zyt\app\tests\test_api_client.py:77-113`、`D:\web\zyt\app\tests\test_reception_parity_ui.py:462-544`:验证 multipart boundary、服务端 URL-only JSON 和任一上传失败时绝不提交备注。
|
||
|
||
结论:本地文件只作为上传输入,不进入 `addDoctorNote` JSON;原 P0 已关闭。
|
||
|
||
### P0-2 appointment 唯一权威与完整 `case_record` — CLOSED
|
||
|
||
Admin 合同:
|
||
|
||
- `D:\web\zyt\admin\src\views\tcm\diagnosis\index.vue:1685-1694`:问诊行明确传入 `diagnosis_id` 与 `appointment_id`。
|
||
- `D:\web\zyt\admin\src\components\tcm-prescription\index.vue:1850-1863`:首先请求 `GET tcm.prescription/getByAppointment {appointment_id}`。
|
||
- 同文件 `:1865-1895,2251-2267`:无当前挂号处方时从诊单详情生成病例快照,保存 `diagnosis_id/appointment_id/case_record`。
|
||
|
||
App 证据:
|
||
|
||
- `D:\web\zyt\app\src\doctor_workstation\ui\pages\consultations.py:1168-1191`:唯一查询源是 `get_prescription_by_appointment`,不存在 diagnosis 历史回退。
|
||
- 同文件 `:1193-1209,1227-1241,1300-1307`:仅空结果进入新建;查询异常直接 fail-closed;病例快照返回的 diagnosis ID 必须匹配当前行。
|
||
- 同文件 `:1315-1375`:编辑种子和最终创建 DTO 都强制覆盖当前 `diagnosis_id/appointment_id` 并深拷贝完整 `case_record`。
|
||
- `D:\web\zyt\app\src\doctor_workstation\services\repository.py:1030-1039,1118-1132`:端点分别为 `POST tcm.prescription/add` 与 `GET tcm.prescription/getByAppointment`。
|
||
- `D:\web\zyt\app\src\doctor_workstation\core\models.py:581-584,653-657,728-734`:`Prescription` 正式反序列化/序列化 `appointment_id`、`case_record`。
|
||
- `D:\web\zyt\app\src\doctor_workstation\services\mock_repository.py:861-870`:Demo 同样只按 appointment 精确匹配。
|
||
- `D:\web\zyt\app\tests\test_consultations_parity_ui.py:239-348`:覆盖 miss、异常、禁止 diagnosis fallback、ID 与不可变病例快照。
|
||
|
||
说明:Admin 在预约查询异常处吞错后可能继续新建;App 选择更安全的异常 fail-closed,但没有改变 appointment 作为唯一处方权威的业务合同。
|
||
|
||
### P0-3 预约 ID、排班和提交 DTO — CLOSED
|
||
|
||
Admin 合同:
|
||
|
||
- `D:\web\zyt\admin\src\views\first_visit\my_patients\index.vue:513-518`:预约组件的 `patient_id` 被明确覆盖为 `diagnosis_id || id`。
|
||
- `D:\web\zyt\admin\src\views\tcm\diagnosis\appointment.vue:392-402,494-628`:加载医生、未来 7 天有效排班、服务端可用号源。
|
||
- 同文件 `:669-720`:提交 `patient_id,doctor_id,appointment_date,period,appointment_time,appointment_type,remark,channel_source,channel_source_detail`。
|
||
- 端点定义:`D:\web\zyt\admin\src\api\tcm.ts:107-108`、`D:\web\zyt\admin\src\api\doctor.ts:19-20,50-51`、`D:\web\zyt\admin\src\api\first_visit.ts:120-121`。
|
||
|
||
App 证据:
|
||
|
||
- `D:\web\zyt\app\src\doctor_workstation\ui\pages\patients.py:219-251,319-337`:预约上下文和今日重复检查均使用 diagnosis ID;`source_patient_id` 只保留给视频。
|
||
- 同文件 `:410-486,495-585`:请求未来 7 天排班和 `availableSlots`,只接受可用、未过期、有配额的时段。
|
||
- 同文件 `:600-644`:所有必填门槛与 Admin DTO 对齐,`patient_id == diagnosis_id`;特定自媒体渠道要求补充字段。
|
||
- 同文件 `:2208-2223`:确认后通过 `book_patient_appointment` 提交完整快照 DTO。
|
||
- `D:\web\zyt\app\src\doctor_workstation\services\repository.py:722-784,1428-1433,1570-1573`:端点为 `getDoctors`、`doctor.roster/lists`、`availableSlots`、`firstvisit.myPatient/createAppointment`。
|
||
- `D:\web\zyt\app\tests\test_patients_ui.py:276-343`:明确断言 diagnosis ID 与真实 patient ID 不同且 body 使用 diagnosis ID,并核对排班/号源 query 和完整 body。
|
||
|
||
App 额外保留 `diagnosis_id` 作为显式上下文键;服务端仍收到 Admin 所需全部字段,未再混淆 ID。
|
||
|
||
## 4. P1 逐项复核
|
||
|
||
### P1-1 DiagnosisDialog 隐私、字段 DTO 与唯一性 — CLOSED
|
||
|
||
- Admin:`D:\web\zyt\admin\src\views\tcm\diagnosis\edit.vue:823-856,916-970,1013-1132,1263-1275,1331-1367`,明文受 `tcm.diagnosis/phonePlain` 控制,基础字段受服务端锁定,并调用 phone/id-card 唯一性检查。
|
||
- App:`D:\web\zyt\app\src\doctor_workstation\ui\dialogs\diagnosis.py:42-131,213-241,426-450`,接收/继承 permissions,覆盖患者基本信息、生命体征、病史、四诊和诊断字段。
|
||
- App:同文件 `:595-689`,缺权限时 phone/id-card 从 seed 到详情均 fail-closed 脱敏,且不把掩码写回服务端;`patient_basic_locked`/`can_edit_patient_basic=false` 时锁定基础字段。
|
||
- App:同文件 `:829-903`,保存前校验格式并调用 `checkPhone {phone,id}`、`checkIdCard {id_card,id}`,然后 `update_diagnosis`。
|
||
- Repository:`D:\web\zyt\app\src\doctor_workstation\services\repository.py:1474-1509,1575-1583`。
|
||
- 测试:`D:\web\zyt\app\tests\test_prescription_security_ui.py:132-191`。
|
||
|
||
### P1-2 预约医生、排班、号源与字段 — CLOSED
|
||
|
||
P0-3 已给出完整证据。补充:Admin 的可提交条件在 `D:\web\zyt\admin\src\views\tcm\diagnosis\appointment.vue:377-386`;App 对应 fail-closed 条件在 `D:\web\zyt\app\src\doctor_workstation\ui\pages\patients.py:600-644`。医生、排班日、服务端 slot、渠道缺一不可;状态 `1/4` 的今日挂号只阻止再约今天。
|
||
|
||
### P1-3 诊单上下文订单、支付与退款 — CLOSED
|
||
|
||
- Admin:`D:\web\zyt\admin\src\views\tcm\diagnosis\readonly.vue:74-88`,订单区只在 `tcm.diagnosis/patientOrders` 下出现。
|
||
- Admin:`D:\web\zyt\admin\src\views\tcm\diagnosis\components\PatientOrderList.vue:131-178`,exact query 为 `context_diagnosis_id`、可用时的 `patient_id`、`scene='diagnosis_edit'`、`page_size=10`。
|
||
- App:`D:\web\zyt\app\src\doctor_workstation\ui\dialogs\diagnosis.py:506-549,551-563,764-827`,同权限、同 query、同分页,并以 diagnosis generation/target 拒绝过期响应。
|
||
- Repository:`D:\web\zyt\app\src\doctor_workstation\services\repository.py:1134-1145`,透传到 `GET tcm.prescriptionOrder/lists`。
|
||
- 支付/退款:`D:\web\zyt\app\src\doctor_workstation\ui\pages\patients.py:647-747`,支付包含 `order_type/pay_amount/pay_remark/completion_request/pay_create_type`;退款包含原因和可选 `refund_amount`。
|
||
- Admin 对应:`D:\web\zyt\admin\src\views\first_visit\my_patients\components\OrderActionHost.vue:573-621`。
|
||
- 状态门槛:App `D:\web\zyt\app\src\doctor_workstation\ui\pages\patients.py:1687-1757,2415-2420,2520-2578` 与 Admin `D:\web\zyt\admin\src\views\first_visit\my_patients\components\order-actions.ts:89-110` 对齐。
|
||
|
||
### P1-4 paid-order 上下文竞态与定金门槛 — CLOSED
|
||
|
||
- Admin:`D:\web\zyt\admin\src\views\consumer\prescription\index.vue:2307-2337,2435-2480`,诊单变化清空支付单并重新请求,创建 body 绑定 prescription/diagnosis/pay-order。
|
||
- App:`D:\web\zyt\app\src\doctor_workstation\ui\dialogs\prescription.py:1800-1847,1945-1950`,已有处方的 diagnosis ID 锁定,初始保存禁用。
|
||
- App:同文件 `:1965-2060`,变化立即清空旧支付单/定金;响应必须同时匹配 generation、请求 diagnosis、当前 diagnosis。
|
||
- App:同文件 `:2070-2139`,加载中、失败或未就绪均禁止提交;门槛开启时必须选支付单且金额不低于 `deposit_min_amount`。
|
||
- Repository:`D:\web\zyt\app\src\doctor_workstation\services\repository.py:1157-1183`,`paidPayOrders {diagnosis_id}` 与 `prescriptionOrder/create`。
|
||
- 测试:`D:\web\zyt\app\tests\test_prescription_security_ui.py:227-260`。
|
||
|
||
### P1-5 患者 mutation 不丢回调 — CLOSED
|
||
|
||
- `D:\web\zyt\app\src\doctor_workstation\ui\pages\patients.py:2161-2202`:每次写操作有独立 pending token;完成顺序不会使已执行 mutation 的 success/error 回调失效。
|
||
- 同文件 `:2183-2206`:每个服务端成功都 reconcile 患者、订单、面诊进度三工作区。
|
||
- 同文件 `:1687-1757,2415-2420`:handler 提交前重新核对 canonical permission 和行状态。
|
||
- `D:\web\zyt\app\tests\test_patients_ui.py:373-398`:两个 mutation 乱序完成仍触发两次 reconcile。
|
||
|
||
### P1-6 QRunnable 只接收 GUI 快照 — CLOSED
|
||
|
||
- `D:\web\zyt\app\src\doctor_workstation\ui\widgets.py:260-323`:`run_async` 的函数运行在 QRunnable。
|
||
- 接诊:`D:\web\zyt\app\src\doctor_workstation\ui\pages\reception.py:522-607`。
|
||
- 患者列表/订单:`D:\web\zyt\app\src\doctor_workstation\ui\pages\patients.py:1293-1318,1587-1615`。
|
||
- 处方库:`D:\web\zyt\app\src\doctor_workstation\ui\pages\prescription_library.py:221-247`。
|
||
- 模板导入:`D:\web\zyt\app\src\doctor_workstation\ui\dialogs\prescription.py:759-780`。
|
||
- 已开处方:`D:\web\zyt\app\src\doctor_workstation\ui\pages\prescriptions.py:499-540`。
|
||
|
||
上述位置均在 GUI 线程先读取 `.text()`、`.currentData()`、日期/页码等,再向 worker 传纯 query/scalar;worker 不再读取 QWidget。`D:\web\zyt\app\tests\test_reception_parity_ui.py:269-310`、`D:\web\zyt\app\tests\test_patients_ui.py:231-268`、`D:\web\zyt\app\tests\test_prescription_security_ui.py:269-334` 覆盖快照和 pending refresh。
|
||
|
||
视频后端写同样不阻塞 Qt:`D:\web\zyt\app\src\doctor_workstation\video\lifecycle.py:84-153,156-304` 以每通话 FIFO daemon worker 有序执行 `start -> bind -> end`,提供最长 5 秒的有限等待;`D:\web\zyt\app\src\doctor_workstation\video\window.py:515-548` 的窗口关闭只排队结束,不同步阻塞 GUI。
|
||
|
||
### P1-7 canonical permission exact 与 handler 二次门槛 — CLOSED
|
||
|
||
- Admin:`D:\web\zyt\admin\src\utils\perm.ts:3-14`,权限字符串精确匹配。
|
||
- App:`D:\web\zyt\app\src\doctor_workstation\ui\widgets.py:135-183`,只接受 exact、全局 `*`、资源 `prefix/*`;明确不把 `resource.action` 当成 `resource/action`。
|
||
- 处方库按钮和 handlers:`D:\web\zyt\app\src\doctor_workstation\ui\pages\prescription_library.py:100-164,291-392`。
|
||
- 已开处方查看、增改删、患者修正、审核、建单、订单列表 handlers:`D:\web\zyt\app\src\doctor_workstation\ui\pages\prescriptions.py:642-689,707-907`。
|
||
- Canonical action 基准:`D:\web\zyt\admin\src\views\consumer\prescription\list.vue:36,85,93,102` 与 `D:\web\zyt\admin\src\views\consumer\prescription\index.vue:107,112,216,232,242,250,260`。
|
||
- 测试:`D:\web\zyt\app\tests\test_prescription_security_ui.py:123-129`,仅有点号 alias 时 slash action 被拒绝。
|
||
|
||
### P1-8 视频 eligibility 与权限语义 — CLOSED(客户端范围)
|
||
|
||
- Admin:`D:\web\zyt\admin\src\views\tcm\diagnosis\index.vue:390-391` 的 `tcm.diagnosis/videoQr` 只保护小程序二维码;同文件 `:1778-1780` 的问诊视频门槛为 `has_appointment && appointment_status == 1`。
|
||
- App:`D:\web\zyt\app\src\doctor_workstation\ui\pages\consultations.py:166-183,1106-1111,1441-1453`,使用相同 eligibility,且 appointment/patient/diagnosis 三 ID 分离、均需有效。
|
||
- UI 原生直呼不再受 `videoQr` 门槛;测试见 `D:\web\zyt\app\tests\test_consultations_parity_ui.py:86-92,390-403`。
|
||
- Remote endpoint/payload:`D:\web\zyt\app\src\doctor_workstation\services\repository.py:1677-1717`,分别是签名、`startCall`、`bindCallRoom`、`endCall`。
|
||
|
||
服务端仍必须最终验证通话状态和数据归属;这属于服务端安全边界,不是客户端页面缺失。
|
||
|
||
### P1-9 接诊分页 — CLOSED
|
||
|
||
- Admin:`D:\web\zyt\admin\src\views\patient\reception\index.vue:212-214,296-379`,`PAGE_SIZE=15`、按 `total/count` 持续加载和 ID 去重。
|
||
- App:`D:\web\zyt\app\src\doctor_workstation\ui\pages\reception.py:196-208,288-292,513-607,609-696`,同为 15 条;切 tab/搜索重置,加载更多,按 ID 合并,以 generation/query-key 拒绝旧响应。
|
||
- Repository:`D:\web\zyt\app\src\doctor_workstation\services\repository.py:668-695`,透传 `page_no/page_size` 到 `GET doctor.appointment/lists`。
|
||
- 测试:`D:\web\zyt\app\tests\test_reception_parity_ui.py:179-260`,覆盖跨页追加、筛选重置与 total 边界。
|
||
|
||
第 51 位之后的今日患者已可达,旧“固定前 50 条”结论失效。
|
||
|
||
### P1-10 处方进入诊单的权限与只读端点 — CLOSED
|
||
|
||
- `D:\web\zyt\app\src\doctor_workstation\ui\pages\prescriptions.py:642-659`:处方详情先要求 `cf.prescription/read`;诊单按钮另要求 `tcm.diagnosis/readonlyDetail`。
|
||
- 同文件 `:661-698`:handler 再次检查 canonical 权限和 diagnosis ID,明确调用 readonly endpoint;无权时不发请求。
|
||
- `D:\web\zyt\app\src\doctor_workstation\ui\dialogs\prescription.py:1668-1696`:详情按钮按同一权限 boolean 隐藏。
|
||
- `D:\web\zyt\app\src\doctor_workstation\services\repository.py:1474-1488`:`GET tcm.diagnosis/readonlyDetail {id}`。
|
||
- `D:\web\zyt\app\tests\test_prescription_security_ui.py:335-388`:无权限不请求,并拒绝过期 target 响应。
|
||
|
||
## 5. Endpoint / DTO 最终合同
|
||
|
||
| 能力 | Endpoint | 关键 query/body | 状态 |
|
||
|---|---|---|---:|
|
||
| 接诊队列 | `GET doctor.appointment/lists` | `status,start_date,end_date,patient_name,page_no,page_size` | **EXACT** |
|
||
| 材料上传 | `POST upload/image|file` | multipart `file,cid` | **EXACT** |
|
||
| 医生备注 | `POST doctor.appointment/addDoctorNote` | `diagnosis_id,content,tongue_images,report_files`,仅服务器 URI | **EXACT** |
|
||
| 当前挂号处方 | `GET tcm.prescription/getByAppointment` | `appointment_id` | **EXACT** |
|
||
| 新建处方 | `POST tcm.prescription/add` | `diagnosis_id,appointment_id,case_record` + 完整处方字段 | **EXACT** |
|
||
| 预约医生 | `GET tcm.diagnosis/getDoctors` | 无 | **EXACT** |
|
||
| 排班 | `GET doctor.roster/lists` | `doctor_id,start_date,end_date,status,page_no,page_size` | **EXACT** |
|
||
| 可用号源 | `GET doctor.appointment/availableSlots` | `doctor_id,appointment_date,period='all'` | **EXACT** |
|
||
| 我的患者预约 | `POST firstvisit.myPatient/createAppointment` | Admin 九字段;`patient_id == diagnosis_id` | **EXACT** |
|
||
| 诊单详情/编辑 | `GET detail|readonlyDetail`; `POST checkPhone|checkIdCard|edit` | `{id}`、唯一性 DTO、完整医生相关字段 | **EXACT** |
|
||
| 诊单上下文订单 | `GET tcm.prescriptionOrder/lists` | `context_diagnosis_id,patient_id?,scene='diagnosis_edit',page_no,page_size` | **EXACT** |
|
||
| 建单支付单 | `GET tcm.prescriptionOrder/paidPayOrders` | `diagnosis_id` | **EXACT** |
|
||
| 创建业务订单 | `POST tcm.prescriptionOrder/create` | `prescription_id,diagnosis_id,pay_order_ids?` + 收货/服务/金额字段 | **EXACT** |
|
||
| 视频生命周期 | `getCallSignature/startCall/bindCallRoom/endCall` | 三 ID 分离;`call_type=2`;`room_id` | **EXACT(客户端)** |
|
||
|
||
对 `D:\web\zyt\app\src\doctor_workstation\services\repository.py`、Protocol、Remote、Demo 和五页面调用名进行复核,当前新增调用均存在;未发现不存在或错误命名的 repository 方法。关键端点合同由 `D:\web\zyt\app\tests\test_repository_parity.py:127-153,157-267,287-353` 覆盖。
|
||
|
||
## 6. 异步、刷新与目标绑定
|
||
|
||
- 列表请求均以 generation 拒绝旧响应;接诊还绑定 query-key 和 appointment target。
|
||
- 处方库/已开处方在 loading 中收到刷新会记录 pending refresh,而不是静默丢失:`D:\web\zyt\app\src\doctor_workstation\ui\pages\prescription_library.py:221-266`、`D:\web\zyt\app\src\doctor_workstation\ui\pages\prescriptions.py:499-574`。
|
||
- 处方详情、诊单详情、订单详情均绑定 generation + target ID:`D:\web\zyt\app\src\doctor_workstation\ui\pages\prescriptions.py:608-705`、`D:\web\zyt\app\src\doctor_workstation\ui\dialogs\prescription.py:2198-2284`。
|
||
- 问诊切行同时 invalidate prescription generation 并释放 busy:`D:\web\zyt\app\src\doctor_workstation\ui\pages\consultations.py:1085-1111`。
|
||
- Demo 的问诊筛选、字典、appointment-authoritative 处方及 mutation 均有真实离线语义:`D:\web\zyt\app\tests\test_mock_repository.py:140-178,300-396`。
|
||
|
||
上述原 P2 风险也已关闭;不影响本次 P0/P1 发布判断。
|
||
|
||
## 7. 动态菜单与医生桌面范围
|
||
|
||
动态菜单仍以会话 menu 为权威,并要求菜单节点与当前 canonical permission 同时满足:`D:\web\zyt\app\src\doctor_workstation\ui\shell.py:41-80,195-249`。五个本地页面之外的节点不会被错误映射;非 Demo 且服务端 menu 为空时不会自行放宽页面。
|
||
|
||
下列功能明确不属于本次医生桌面同型范围,因此不计为 MISSING:
|
||
|
||
- 患者小程序/H5、消费者端自助下单和二维码页面。
|
||
- 医助 watchCall、医助专属批量分配与其他角色工作台。
|
||
- 企业微信后台运营、素材运营、客户标签、统计/转化后台。
|
||
- 药房、财务、物流、审核员等角色的完整运营路由;医生页只保留其被授权的订单动作。
|
||
- 管理端 `videoQr` 小程序二维码能力;桌面原生直呼使用后端 ticket 与服务端最终授权。
|
||
|
||
## 8. 验证记录
|
||
|
||
执行命令与结果:
|
||
|
||
```text
|
||
.\.venv\Scripts\python.exe -m pytest -o addopts='' --tb=short
|
||
collected 140 items
|
||
140 passed in 1.49s
|
||
|
||
.\.venv\Scripts\python.exe -m pytest --collect-only -q
|
||
140 tests collected across 15 test files
|
||
|
||
.\.venv\Scripts\python.exe -m ruff check src tests
|
||
All checks passed!
|
||
|
||
.\.venv\Scripts\python.exe -m ruff format --check src tests
|
||
53 files already formatted
|
||
```
|
||
|
||
测试数量明细:`12+11+12+2+1+16+2+12+4+7+10+11+12+10+18 = 140`。
|
||
|
||
## 9. 最终门槛
|
||
|
||
- **OPEN P0:0**
|
||
- **OPEN P1:0**
|
||
- **发布阻断:无**
|
||
- **最终结论:可作为医生桌面 release candidate 进入打包和部署环境验收。**
|