28 KiB
“我的处方库 / 已开处方”桌面端对齐审计
审计日期:2026-08-10
1. 范围、基准与结论口径
本审计只读检查以下两套实现,没有修改业务源码:
- 管理端唯一功能基准:D:/web/zyt/admin/src/views
- Python 桌面端:D:/web/zyt/app/src/doctor_workstation
管理端 API 包装文件、通用组件和分页 hook 仅用于解析“页面已经发起的调用”的 URL、参数与直接子组件行为,不把相邻页面或未被页面调用的 API 当成处方页功能。
结论标签:
- EXACT:用户可见行为、状态语义和请求合同均与基准一致;不要求布局像素一致。
- PARTIAL:仅覆盖基准的子集,或字段/状态/校验语义有差异。
- MISSING:基准存在,而 Python 没有入口或没有可达实现。
- EXACT(负向):基准明确没有该能力,Python 也没有;不能把它列为待补功能。
2. 真实页面定位
| 业务名 | 管理端真实 view 组件 | Python 页面 | 结论 |
|---|---|---|---|
| 我的处方库 | D:/web/zyt/admin/src/views/consumer/prescription/list.vue:1-414;script name 为 prescriptionLibrary(234) | D:/web/zyt/app/src/doctor_workstation/ui/pages/prescription_library.py:251-545;固定导航见 D:/web/zyt/app/src/doctor_workstation/ui/shell.py:48-54 | EXACT(组件映射) |
| 已开处方 / 处方管理 | D:/web/zyt/admin/src/views/consumer/prescription/index.vue:1-4892;script name 为 prescriptionList(1697) | D:/web/zyt/app/src/doctor_workstation/ui/pages/prescriptions.py:72-436;固定导航见 D:/web/zyt/app/src/doctor_workstation/ui/shell.py:55-61 | EXACT(组件映射),功能不是 EXACT |
管理端采用动态菜单,单凭 src/views 只能确定组件键应分别落到 consumer/prescription/list 与 consumer/prescription/index,不能确定生产环境最终 URL、菜单标题或 route.meta.perms。Python 则固定注册为 prescription_library / prescriptions。审计不伪造管理端生产 URL。
3. 直接子组件与边界
3.1 MedicineNameSelect
处方库在 D:/web/zyt/admin/src/views/consumer/prescription/list.vue:158-165 使用;已开处方的主方、辅方行分别在 D:/web/zyt/admin/src/views/consumer/prescription/index.vue:695-726、736-767 使用。
真实合同:
- 远程、可过滤选择器,提示支持药材名或拼音首字母:D:/web/zyt/admin/src/components/medicine-name-select/index.vue:3-24。
- 展开或搜索时 GET /doctor.medicine/lists,参数 name、page_no=1、page_size=100、status=1:同文件 69-92;URL 包装见 D:/web/zyt/admin/src/api/medicine.ts:6-8。
- 选择后同时回写 name 和 medicine_id;不能把任意自由文本当成一次有效选择:组件 95-110。
Python 处方库的 HerbRow 是两个自由文本 QLineEdit,medicine_id 只会保留已有行上的值,新增行没有药材主数据选择:D:/web/zyt/app/src/doctor_workstation/ui/pages/prescription_library.py:76-110。结论:PARTIAL。
3.2 DaterangePicker
已开处方在 D:/web/zyt/admin/src/views/consumer/prescription/index.vue:19-23 使用。直接子组件默认 datetimerange,值格式 YYYY-MM-DD HH:mm:ss,并分别回写 start_time/end_time:D:/web/zyt/admin/src/components/daterange-picker/index.vue:1-48。
Python 没有日期范围控件:MISSING。
3.3 TcmDiagnosisEditView
已开处方异步加载 D:/web/zyt/admin/src/views/tcm/diagnosis/edit.vue,并在 diagnosis_id>0 时提供“查看患者诊单详情”:D:/web/zyt/admin/src/views/consumer/prescription/index.vue:566-574、1692-1693、1728、2910-2921。
直接调用 openViewOnly(id);子页面以同一套界面只读打开、加载 GET /tcm.diagnosis/detail {id},默认病历 tab:D:/web/zyt/admin/src/views/tcm/diagnosis/edit.vue:1263-1264、1310-1322;URL 见 D:/web/zyt/admin/src/api/tcm.ts:59-62。
该只读子页仍保留全套 tab 边界:
- 病历字段整体 disabled:diagnosis/edit.vue:55-67。
- 医生备注 readonly、日常记录 read-only:633-670。
- 处方 tab 受 tcm.diagnosis/chufang 控制且 read-only:673-686。
- 业务订单受 tcm.diagnosis/patientOrders 控制:688-702。
- 视频回放、聊天、指派、挂号分别受 tcm.diagnosis/huifang、tcm.diagnosis/chat、tcm.diagnosis/assign 或 detail、doctor.appointment/lists 控制:704-758。
Python 已开处方没有 diagnosis_id 跳转或只读诊单子页:MISSING。
3.4 分页
两个管理端页面均通过 usePaging 自动发送 page_no/page_size,默认 page=1、size=15,并消费 count/lists/extend:D:/web/zyt/admin/src/hooks/usePaging.ts:13-49。Python 两页均默认 page_size=20,使用 PageResult/Pager:
- 处方库:D:/web/zyt/app/src/doctor_workstation/ui/pages/prescription_library.py:263-266、413-442。
- 已开处方:D:/web/zyt/app/src/doctor_workstation/ui/pages/prescriptions.py:84-89、284-316。
参数和总数分页机制 EXACT,默认每页条数 PARTIAL(15 vs 20)。
4. 我的处方库:管理端真实合同
4.1 筛选、字段与状态
- 筛选:prescription_name、formula_type=主方|辅方、is_public=0|1,查询回第一页,重置为初始值:D:/web/zyt/admin/src/views/consumer/prescription/list.vue:5-31、247-252、281-284。
- 列表字段:id、prescription_name、formula_type、herbs.length、全部 herbs 的 name/dosage(g)、is_public、disable_edit、creator_name、create_time:list.vue:44-107。
- 公开范围:0=仅自己可见,1=所有人可见:list.vue:21-26、67-72、195-205。
- disable_edit:0=可修改,1=已禁用;真实语义是“导入到已开处方后锁定整张处方药材”,不是“禁止维护这条模板自身”:list.vue:74-79、208-220。
- 普通用户只管理本人 creator_id;root=1 或 role_ids 含 0、3 可管理任意模板:list.vue:276-301。
4.2 查看、创建、编辑、删除、复制
- 新增:独立按钮,表单字段为 prescription_name(maxlength=100)、formula_type、herbs、is_public、disable_edit:list.vue:35-41、116-230、259-267。
- 查看:有单独 read 权限按钮,复用列表行数据打开完全禁用的表单;不调用 detail:list.vue:83-87、123-129、333-343。
- 编辑:仅 owner 或管理角色可见;仍可修改 disable_edit=1 模板本身的药材:list.vue:88-106、345-355。
- 删除:确认后 POST {id}:list.vue:403-409。
- 复制:页面没有复制/克隆按钮、函数或端点。导入模板属于“已开处方”的复用流程,不是复制模板 CRUD。
- 导出/打印:本页面没有。
4.3 药材行和校验
- 药材 DTO:{medicine_id?: number, name: string, dosage: number}:list.vue:259-266。
- name 必须由 MedicineNameSelect 选取并同步 ID;dosage 是 min=0、precision=1、step=0.5 的数字控件:list.vue:156-190。
- 提交要求:名称必填、至少一味药、每行 name 非空、dosage>0:list.vue:269-274、357-379。
4.4 API DTO
页面调用来源见 list.vue:234-245;URL 包装见 D:/web/zyt/admin/src/api/tcm.ts:591-615。
| 方法与端点 | 页面请求参数 / body | 页面使用情况 |
|---|---|---|
| GET /tcm.prescriptionLibrary/lists | page_no、page_size、prescription_name、formula_type、is_public | 列表与分页 |
| POST /tcm.prescriptionLibrary/add | prescription_name、formula_type、herbs、is_public、disable_edit;页面对象还带重置后的 id=0 | 新增 |
| POST /tcm.prescriptionLibrary/edit | id、prescription_name、formula_type、herbs、is_public、disable_edit | 编辑 |
| POST /tcm.prescriptionLibrary/delete | {id} | 删除 |
| GET /tcm.prescriptionLibrary/detail | {id} | API 已封装,但该 view 没有调用 |
权限码为 wcf.prescription/add、read、edit、delete:list.vue:36、85、93、102。
5. 我的处方库:Python 逐项对比
| 项目 | Python 证据 | 结论 |
|---|---|---|
| 页面入口 | shell.py:48-54 以 tcm.prescriptionLibrary/lists 注册;页面标题见 prescription_library.py:251-282 | EXACT |
| 筛选 | Python 有关键词、主/辅方、公开范围;repository 把 keyword 改成 prescription_name,把 main/aux 改为主方/辅方:prescription_library.py:284-315、413-429;repository.py:279-298、586-588 | PARTIAL:请求合同基本一致,但“名称或药材”的占位文案(291)是假的,实际只查 prescription_name |
| 分页 | page/page_size 经 invoke 转 page_no/page_size;Pager 消费总数:prescription_library.py:409-442,widgets.py:221-223 | PARTIAL:默认 20,基准 15 |
| 列表字段 | Python 只显示名称、类型、最多 4 味摘要、公开范围、创建人、时间:prescription_library.py:357-384 | PARTIAL:缺 id、药材数量、完整药材、disable_edit;把 create_time 列标题写成“更新时间” |
| 单独查看 | 没有 read 按钮;双击只会走 _edit_selected,且需 edit 按钮可见及 owner/管理员:prescription_library.py:330-350、385-386、479-485 | MISSING |
| 新增 | _new_template -> save -> repository add:prescription_library.py:474-501;repository.py:309-323 | PARTIAL:端点可用,但药材和 disable_edit 语义不完整 |
| 编辑 | 使用列表行直接打开,与基准一样不请求 detail;保存到 edit:prescription_library.py:479-501;repository.py:325-347 | PARTIAL |
| 删除 | owner/管理员检查、确认、POST {id}:prescription_library.py:454-472、507-537;repository.py:349-352 | EXACT |
| 公开范围 | 复选框产生 bool,repository 规范为 0/1:prescription_library.py:157-159、218-228;repository.py:572-575 | EXACT |
| disable_edit | Python 把它解释成“当前模板药材不可编辑”,隐藏增删并禁用输入;而管理端只在导入已开处方后锁药材。Python 也没有切换开关,只能原样回传:prescription_library.py:117-140、167-170、218-224 | PARTIAL(语义错误) |
| 药材选择 | 自由文本 name/dosage;新行无 medicine_id,已有行才保留:prescription_library.py:76-110 | PARTIAL |
| 药材校验 | 只检查至少一行、有名称时 dosage 非空:prescription_library.py:230-248 | PARTIAL:不校验数字和 >0,且允许“10g”字符串,与基准 number DTO 不同 |
| 所有权 | user id 相同、root、role 0/3:prescription_library.py:460-472 | EXACT |
| API CRUD | list/detail/add/edit/delete 均存在且 URL、id 合同正确:repository.py:279-352 | EXACT(仓储层) |
| 模型 | PrescriptionTemplate 保留 id/name/formula/herbs/public/disable/creator/time/raw,to_api_dict 正规化中文方型和 0/1:core/models.py:426-477 | EXACT(字段合同) |
| 权限 | add/edit/delete 接受基准 wcf.,同时接受 tcm.prescriptionLibrary/ 别名:prescription_library.py:274-279、332-347 | PARTIAL:动作基本受控,但缺 wcf.prescription/read 的可达只读查看;额外别名不是 view 基准 |
| 复制 | 两边都没有 | EXACT(负向) |
| 导出/打印 | 两边都没有 | EXACT(负向) |
6. 已开处方:管理端真实合同
6.1 筛选与分页 DTO
页面筛选控件见 D:/web/zyt/admin/src/views/consumer/prescription/index.vue:4-99;状态对象见 1874-1887:
- sn:处方编号模糊查询。
- patient_name。
- creator_ids:医生 ID 多选;有值才发数组。
- audit_filter:all、pending、passed、not_passed、rejected;all 被正规化为空字符串。
- source_filter:all、manual、system;all 被正规化为空字符串。
- start_time/end_time:创建时间,格式 YYYY-MM-DD HH:mm:ss。
- 快捷日期:全部、今日、昨日、前天,切换后立即回第一页查询:index.vue:3013-3048。
最终 GET /tcm.prescription/lists 参数是 page_no、page_size 与上述字段;creator_ids 空数组会被省略:index.vue:2990-3007。默认 page_size=15。
6.2 列表字段、状态与可达动作
列表与按钮位于 index.vue:102-270:
- 列:sn、id、订单一致性警告、prescription_type、is_system_auto(1=空白处方,其他=手工)、patient_name/gender/age、综合审核状态和驳回意见、void_status、doctor_name/prescription_date、assistant_name、create_time。
- audit_status:0 待审核、1 已通过、2 已驳回:index.vue:3113-3123。
- business_prescription_audit_rejected=1 时,列表主状态覆盖为“已驳回”,并分别展示业务订单与消费者处方的驳回意见:index.vue:3125-3151。
- void_status=1 单独显示“作废”。
- 已有关联业务订单时,药材为空或重名会在编号下给出警告:index.vue:3192-3216。
动作门槛:
- 查看:cf.prescription/read。
- 修正姓名/性别/手机:未作废且 tcm.prescription/patchPatient。
- 创建订单:has_prescription_order=0、未作废且 tcm.prescriptionOrder/create。
- 编辑、删除:只有“非 audit_status=1 且未作废”才出现,分别需 cf.prescription/edit、cf.prescription/del。
- 审核:audit_status=0、未作废且 cf.prescription/audit。
- 业务订单列表:tcm.prescriptionOrder/lists。
精确条件和权限见 index.vue:214-264;“已通过且未作废”判定见 3154-3157。
6.3 查看详情、打印与 PDF
查看先用列表行渲染,再 GET /tcm.prescription/detail {id} 覆盖:index.vue:3796-3817。
A4 处方笺显示:
- 来源、作废、消费者审核、业务订单审核及意见:index.vue:284-343。
- 日期/编号;患者姓名、性别、年龄、电话、收件信息、临床诊断:345-390。
- 主方/辅方药材,单剂 dosage 与 dose_count 计算后的总量:392-433。
- 主辅方用法、医嘱、忌口、备注、药房备注、出丸:435-448。
- 医师手写签名、医生、类型、天数/剂数、单剂量:450-481。
- 审核人、审核时间、审核意见:484-496。
打印调用 window.print:index.vue:2741-2751。PDF 用 html2canvas(scale=2) 渲染 A4,再由 jsPDF 分页并下载:index.vue:2753-2813。页面没有“列表导出 Excel”;tcm.ts:384-387 的业务订单导出 API 没有被此 view 导入或调用。
6.4 新增/编辑字段与药材规则
表单位于 index.vue:499-1153,reactive DTO 在 2815-2862:
- 关联/系统:id、diagnosis_id、creator_id、is_system_auto。
- 患者:patient_name、gender、age、visit_no、prescription_date。
- 四诊/诊断:tongue、tongue_image、pulse、pulse_condition、clinical_diagnosis。
- 药材:herbs[{medicine_id?, name, dosage, formula_type=主方|辅方, locked?}]。
- 剂型:prescription_type(浓缩水丸、饮片、颗粒、丸剂、散剂、膏方、汤剂)、dosage_amount、dosage_unit、dosage_bag_count、need_decoction、bags_per_dose、dose_count、dose_unit。
- 主方用法:usage_days、times_per_day、usage_instruction、usage_time、usage_way、dietary_taboo[]、usage_notes。
- 辅方用法 aux_usage:dosage_amount、dosage_bag_count、need_decoction、bags_per_dose、times_per_day、usage_days、prescription_name。
- 医师:doctor_name、doctor_signature(手写 canvas 生成 PNG data URL,必填)。
- 隐藏状态:is_shared、visible_role_ids、audit_status/time/by/remark、业务订单审核字段。
主辅方各自使用 MedicineNameSelect 和数字 dosage;导入 disable_edit=1 模板时给行加 locked 并锁定整张处方药材:index.vue:667-813、3489-3515、3712-3732。
新增/编辑校验:
- patient_name、gender、prescription_date、clinical_diagnosis、dose_count、doctor_name、doctor_signature 必填:index.vue:2955-2988。
- 至少一味药,每行 name 非空、dosage>0:3920-3947。
- 新增提交前强制 audit_status=0;add/edit 都把完整 editForm 展开为 body:3951-3961。
- 编辑提示保存后重新进入待审核;已作废/已驳回可经编辑恢复,业务订单侧审核会重置:index.vue:514-565。
公开/共享范围的特殊事实:is_shared、visible_role_ids 虽存在于 editForm、详情回填和展开 payload(2846-2847、3889-3890、3952),但模板区没有任何 v-model 控件;formatVisibleRoleNames 也未被模板调用(3348-3364)。因此该真实 view 不允许用户设置共享范围。桌面端不应凭字段存在擅自新增 UI。
6.5 处方库导入、粘贴导入与“复制”
- 从处方库导入对话框支持处方名称、主/辅方筛选、replace/append、10/15/20/50 分页,展示公开范围和创建人:index.vue:1539-1633。
- 请求 GET /tcm.prescriptionLibrary/lists,参数 page_no、page_size、prescription_name、formula_type、prescribing_creator_id:index.vue:3444-3468。
- prescribing_creator_id 取当前开方医生;语义是“该医生自己的模板 + 公共模板”。
- 粘贴导入解析 name/dosage,只接受 GET /doctor.medicine/lists 中 name 完全相同且唯一的药材;请求 name、page_no=1、page_size=200、status=1:index.vue:3538-3709。
- replace 只替换同方型药材,append 追加;重复名仅警告。
该页面没有“复制某张已开处方”动作或端点。处方库导入与文本导入是新增/编辑中的填充方式,不等于复制已开处方。Python 也没有复制:EXACT(负向)。
6.6 审核联动
- POST /tcm.prescription/audit body={id, action:'approve'|'reject', remark}:D:/web/zyt/admin/src/api/tcm.ts:365-372;调用见 index.vue:3367-3395。
- reject 必填 remark,成功语义为“驳回并作废处方”:index.vue:1669-1689、3373-3385。
- 返回 wecom_notify_ok=false 且有 wecom_notify_hint 时额外警告:3384-3388。
- 页面定义 root/role_ids 0、3 的审核角色辅助函数,但该函数没有被模板使用;真实按钮门槛仍是 v-perms cf.prescription/audit 加行状态:index.vue:1854-1855、247-253、3104-3110。
6.7 患者修正与订单联动
患者修正:
- 对话框只改 patient_name、gender、phone,明确不改审核状态,并记录到业务订单日志:index.vue:1155-1195。
- POST /tcm.prescription/patchPatient body={id,patient_name,phone,gender}:index.vue:1948-1973;API 类型见 tcm.ts:330-338。
订单读取与一致性:
- 编辑处方时 GET /tcm.prescriptionOrder/lists,参数 page_no=1、page_size=5、prescription_id,显示最近订单的 order_no、medication_days、remark_assistant:index.vue:769-811、2879-2907。
- 业务订单审核驳回可以覆盖处方列表状态和处方笺状态,但保留消费者处方本身的 audit_status:index.vue:165-190、295-343、3125-3151。
从处方创建业务订单:
- 三步表单:诊单患者与收件信息;服务/发货/支付单;费用与备注:index.vue:1197-1537。
- 诊单患者远程搜索意图为 GET /tcm.diagnosis/searchPatient,参数 keyword、page_no=1、page_size=10:index.vue:2384-2401;API 定义在 D:/web/zyt/admin/src/api/order.ts:88-91。
- GET /tcm.prescriptionOrder/paidPayOrders {diagnosis_id} 返回可关联支付单和 deposit_min_amount:index.vue:2307-2329;API 见 tcm.ts:389-398。
- POST /tcm.prescriptionOrder/create 的 body: prescription_id、diagnosis_id、recipient_name、recipient_phone、shipping_address、is_follow_up、prev_staff、service_channel、service_package(逗号拼接)、express_company、tracking_number、ship_mode、fee_type、amount、remark_extra、remark_assistant;可选 shipping_province/city/district、medication_days、internal_cost、pay_order_ids。证据:index.vue:2435-2485;URL 见 tcm.ts:374-382。
- ship_mode 选择需 tcm.prescriptionOrder/setShipMode;internal_cost 需 finance.account_log/lists;remark_extra 需 tcm.prescriptionOrder/editRemarkExtra:index.vue:1307-1314、1466-1488、2041-2043。
- 服务套餐来自 GET /config/dict {type:'server_order'}:index.vue:2180-2187;URL 见 D:/web/zyt/admin/src/api/app.ts:13-16。
7. 已开处方:Python 逐项对比
D:/web/zyt/app/src/doctor_workstation/ui/pages/prescriptions.py:1 已明确把本页定义为 “Read-only list and detail view for issued prescriptions”。这不是完整管理端主链。
| 项目 | Python 证据 | 结论 |
|---|---|---|
| 页面入口 | shell.py:55-61,以 tcm.prescription/lists 控制 | EXACT |
| 筛选 | 只有一个“编号/患者”关键词和 audit 0/1/2:prescriptions.py:101-125、284-303 | PARTIAL |
| 请求映射 | repository 根据 RX/CF/纯数字猜 sn,否则 patient_name;status 转 pending/passed/rejected:repository.py:354-387 | PARTIAL:已有控件映射正确;缺 creator_ids、日期、source、not_passed;同一关键词不能同时查编号与患者 |
| 分页 | PageResult/Pager 完整 | PARTIAL:默认 20,基准 15 |
| 列表字段 | sn、patient、audit、source、doctor、prescription_date:prescriptions.py:139-180 | PARTIAL:缺 id、prescription_type、gender/age、业务/消费者驳回意见、void 独立列、assistant、create_time、订单警告 |
| 来源 | is_system_auto -> “系统代开/医生开具”:prescriptions.py:67-70 | PARTIAL:基准语义/文案是“空白处方/手工” |
| 状态 | 先作废,再业务订单驳回/消费者驳回,再通过/待审;raw fallback 可读模型未声明字段:prescriptions.py:46-60,widgets.py:48-66 | PARTIAL:主标签逻辑接近,但不能分别显示两类驳回意见、审核人/时间和独立作废信息 |
| 详情请求 | 选中后 GET /tcm.prescription/detail {id}:prescriptions.py:326-357;repository.py:389-396 | EXACT(端点) |
| 详情字段 | 患者/性别/年龄、医生、日期、类型、剂数、药材/剂量/方型、频次/天数/方式/时间/忌口/说明和一条审核备注:prescriptions.py:360-420 | PARTIAL |
| A4 处方笺 | 无 A4 版式;缺电话/收件、临床诊断、签名、单味总量、药房备注/出丸、审核轨迹等 | MISSING |
| 新增 | 页面无按钮、无表单;RemoteRepository 无 prescription add 方法 | MISSING |
| 编辑 | 页面无按钮、无表单;缺主/辅方药材、剂型用法、签名、重新待审完整流程 | MISSING |
| 删除 | 无按钮;RemoteRepository 无 delete | MISSING |
| 患者修正 | 无 patchPatient UI/仓储方法 | MISSING |
| 审核 | 无 approve/reject UI/仓储方法;无驳回必填、作废联动、企微提示 | MISSING |
| 订单联动 | 无订单列表入口、创建订单、支付单关联、处方一致性警告、最近订单提示 | MISSING |
| 处方库导入 | 无新增/编辑,自然也没有 replace/append、锁药材、prescribing_creator_id | MISSING |
| 文本导入 | 无解析及药材完全同名验证 | MISSING |
| 药材编辑行 | 详情表只读;无 medicine_id 选择与 dosage 校验 | MISSING |
| 打印 | 无 window/Qt 打印等价能力 | MISSING |
| 无处方笺 PDF 导出 | MISSING | |
| 列表 Excel | 基准页也没有 | EXACT(负向) |
| 复制已开处方 | 基准页也没有 | EXACT(负向) |
| 共享范围 UI | Python 不展示 is_shared/visible_role_ids;基准 view 也没有可见控件 | EXACT(只读 UI 的负向行为) |
| 共享字段模型 | Prescription 存 is_shared、visible_role_ids,但没有 mutation:core/models.py:519-521、574-576 | PARTIAL(数据保留) |
| 诊单详情联动 | 没有 diagnosis_id “查看诊单详情”和全 tab 只读子页 | MISSING |
| 动作权限 | 构造器保存 permissions 但页面没有任何 has_permission 动作判断:prescriptions.py:72-99 | MISSING(动作本身也缺) |
7.1 Python Prescription DTO 覆盖度
Prescription 模型保留绝大多数列表/详情核心字段:id、diagnosis、sn、患者、四诊、药材、剂型/主方用法、aux_usage、签名、creator/assistant、source/share/audit/void/order/create_time,并保留 raw:D:/web/zyt/app/src/doctor_workstation/core/models.py:480-587。
结论:PARTIAL。
原因:
- 模型层比 UI 完整,但 UI 只消费很小子集。
- business_prescription_audit_rejected、business_prescription_audit_remark、收件/药房/出丸等不设显式 dataclass 字段,只能从 raw 兜底;get_value 确实支持 raw fallback:widgets.py:48-66。
- RemoteRepository 只实现 GET lists/detail:repository.py:354-396;没有 add/edit/delete/patch/audit/order 的请求合同。
8. 权限码总表
8.1 我的处方库
| 能力 | 管理端真实码 | Python |
|---|---|---|
| 页面/列表 | 动态菜单实际值不能由 view 单独确定;接口是 tcm.prescriptionLibrary/lists | shell 固定 tcm.prescriptionLibrary/lists |
| 新增 | wcf.prescription/add | 接受 wcf.prescription/add 或 tcm.prescriptionLibrary/add |
| 查看 | wcf.prescription/read | MISSING |
| 编辑 | wcf.prescription/edit + owner/root/role 0,3 | 同时接受 wcf 或 tcm 别名 + 同一所有权规则 |
| 删除 | wcf.prescription/delete + owner/root/role 0,3 | 同时接受 wcf 或 tcm 别名 + 同一所有权规则 |
8.2 已开处方
管理端真实页面使用:
- cf.prescription/add、read、edit、audit、del。
- tcm.prescription/patchPatient。
- tcm.prescriptionLibrary/lists。
- tcm.prescriptionOrder/create、lists、setShipMode、editRemarkExtra。
- finance.account_log/lists。
- 诊单子页另用 tcm.diagnosis/chufang、patientOrders、huifang、chat、assign/detail 和 doctor.appointment/lists。
证据集中在 index.vue:102-117、214-264、667-680、1307-1314、1466-1488、1692-1728。
Python 只有页面入口 tcm.prescription/lists(shell.py:55-61);PrescriptionsPage 没有上述动作,也没有动作权限判断。结论:MISSING。
9. 基准 view 自身的边界/风险(不计作 Python 差异)
- 订单患者搜索在 index.vue:2391 调用 searchPatientsAPI,但 index.vue:1698-1714 的显式 import 没有该符号;真正 export 位于 api/order.ts:88-91。若工程没有为这个本地 API 符号做自动导入,远程患者搜索会失败。仅以 views 不能证明是否存在额外自动导入,故结论是“高风险未确认”,不是把不存在的合同补到 Python。
- is_shared、visible_role_ids、roleAll、formatVisibleRoleNames 存在,但没有表单绑定;不要把死状态误判成可见“公开范围”功能。
- userCanAudit() 定义了 root/role 0,3,但没有被模板调用;真实前端门槛是 cf.prescription/audit 和行状态,后端仍是最终边界。
- prescriptionVoid API 虽在 tcm.ts:360-363 存在,但此 route 没有导入/直接调用;该页的可达作废路径是 audit reject 的服务端联动。
- prescriptionOrderExport API 存在,但“已开处方” route 不调用;不能据此声称本页有 Excel 导出。
- 两个基准页面均无“复制”能力。
10. P0 / P1 缺口
P0
- 已开处方主链整体缺失:新增、编辑、删除及其 RemoteRepository POST 合同均不存在。当前 Python 实现是明确的只读页,无法替代管理端真实路由。
- 医疗安全关键编辑合同缺失:药材必须来自 MedicineNameSelect、主辅方和 locked 模板规则、dosage>0、剂型/用法、临床诊断、手写医生签名、编辑后重入待审,Python 全部不可达。
- 审核/作废闭环缺失:approve/reject、驳回意见必填、reject 同时作废、两类审核意见、企微通知提示均不存在。
- 订单联动缺失:患者修正、订单创建、支付单关联/定金门槛、发货模式权限、订单审核驳回覆盖状态、处方/订单药材一致性提示全部不存在。
- 权限闭环缺失:已开处方除了列表入口没有任何 cf.prescription/、patchPatient、prescriptionOrder/ 动作校验;在补动作前必须按基准精确落码,不能以 lists 权限兜底。
P1
- 已开处方列表筛选不完整:缺医生多选、创建时间/快捷日期、来源、not_passed;关键词还通过内容猜测 sn 或 patient_name。
- 已开处方列表/详情展示不完整:缺业务订单警告、两类驳回意见、独立作废/审核轨迹、收件/电话、临床诊断、医生签名、药房备注/出丸及 A4 处方笺。
- 已开处方缺打印和 A4 PDF 下载。
- 已开处方缺 diagnosis_id 只读诊单子页及其权限化 tabs。
- 处方库缺真正的 wcf.prescription/read 查看路径;只有有编辑权且可管理该行的用户能通过编辑对话框看完整内容。
- 处方库药材行应改为药材远程选择与数字 dosage;当前自由文本允许合同无效值。
- 处方库 disable_edit 语义错误且无切换开关:它应控制“导入后的已开处方药材锁定”,不应锁死模板自身编辑。
- 处方库表格缺 id、药材数、完整明细、disable_edit,且时间列标题与数据不一致。
- 两页默认 page_size 与基准不同(20 vs 15);属于低风险但可见的分页差异。
“复制”不是缺口:两个管理端基准页面均没有复制动作,Python 也没有。