@@ -0,0 +1,113 @@
# 诊单编辑对话框:新增「患者业务订单」Tab
## Goal
在「编辑诊单」抽屉对话框(`admin/src/views/tcm/diagnosis/edit.vue` )中新增一个 tab,一站式查看该患者的**处方业务订单**(含订单编号、金额、医生、医助、创建人、时间)。直接复用 `admin/src/views/consumer/prescription/order_list.vue` 所用接口 `/tcm.prescriptionOrder/lists` ,仅以患者维度过滤。tab 受 `tcm.diagnosis/chufang` 权限控制。
## Decision Log
- **D1(数据源)**:处方业务订单 `tcm_prescription_order` (不是支付单 `zyt_order` )。用户明确:「订单信息可以参考这个页面,这个页面接口获取的是所有订单 关联到患者就好了」
- **D2(订单范围 / Q1)**:默认跨诊单聚合 + tab 顶部放切换开关,可一键切到"仅本诊单"
- **D3(接口)**:复用 `prescriptionOrderLists` (`@/api/tcm.ts:346` ),不另起新接口
- **D4(列映射 / Q2)**:5 列:订单编号 / 金额 / 医生(`doctor_name` ) / 创建人·医助(`creator_name` ) / 创建时间。**不**单独显示 `assistant_name` ,与创建人合并 → 后端无需新增字段注入
- **D5(行操作 / Q3)**:纯只读,不点击跳转、不弹详情、不挂任何按钮
## What I already know(已查证的事实)
### 前端
- 「编辑诊单」对话框:`admin/src/views/tcm/diagnosis/edit.vue:55` `<el-tabs>` ,已含 12 个 tab,规范统一为 `:disabled="!formData.id" lazy` + `v-if="hasPermission([...])"` ,子组件用 props 接 `diagnosisId / patientId`
- 处方 tab 现用 `tcm.diagnosis/chufang` 权限:`edit.vue:627`
- 参考页面:`admin/src/views/consumer/prescription/order_list.vue` ( 5890 行)
- 现有 API: `prescriptionOrderLists` → `/tcm.prescriptionOrder/lists` ( `admin/src/api/tcm.ts:346` ),已支持 `patient_keyword / order_no / prescription_id / fulfillment_status / prescription_audit_status / payment_slip_audit_status / start_time / end_time / doctor_id / assistant_id / express_keyword`
- 列表字段(前端列):订单号、处方ID、诊单ID、收货人、费用类别、金额、内部成本、处方审核、支付审核、履约、关联支付单、创建时间、**开方人 `doctor_name` **、**创建人 `creator_name` **
### 后端 `server/app/adminapi/lists/tcm/PrescriptionOrderLists.php`
- `setSearch()` ( line 29-36):当前 `=` 等值过滤仅含 `prescription_id / fulfillment_status / prescription_audit_status / payment_slip_audit_status` , **未含 `diagnosis_id` **
- `applyPatientKeywordFilter()` ( line 768-785):用 `whereExists` 关联 `tcm_diagnosis` ,按 `patient_name LIKE '%kw%' OR phone LIKE '%kw%'` 模糊聚合,**天然跨诊单**,正符合 D2 默认模式
- 响应注入字段(line 436-461):`creator_name` 、`doctor_name` 、`prescription_phone` 已写入;`assistant_id` 已查出(`$assistantByDiag` line 432-434)但**未写入 item**,需要补
- 返回 `assistant_name` 还需要再 `Admin::whereIn('id', assistant_ids)->column('name','id')` 一次
## Assumptions(待确认)
1. * * 「患者」匹配键**:用 `phone` (手机号)作 `patient_keyword` 。如手机号脱敏不可用,回退用 `patient_name` 。需要避免空 phone 误匹配
2. * * 「仅本诊单」开关 = 传 diagnosis_id**:后端补 `setSearch` `'=' => ['diagnosis_id']` 即可
3. **三列字段映射 ** :
- 订单编号 → `order_no`
- 金额 → `amount`
- 医生 → `doctor_name` (开方人,已存在)
- 医助 → `assistant_name` (需后端新增注入)
- 创建人 → `creator_name` (已存在)
- 时间 → `create_time`
4. **只读 ** :tab 内只展示,不嵌业务操作(详情/取消/审核 等都不放)
## Open Questions
(已无阻塞问题,三个 Decision 已落定 D2 / D4 / D5)
## Requirements
- [ ] **后端 ** `server/app/adminapi/lists/tcm/PrescriptionOrderLists.php` :
- `setSearch()` 在 `'='` 数组里追加 `'diagnosis_id'` ,使前端可传 `diagnosis_id` 做精确等值过滤
- 不动其他过滤、不动响应字段
- [ ] **前端 子组件 ** `admin/src/views/tcm/diagnosis/components/PatientOrderList.vue` :
- props: `diagnosisId: number` 、`patientPhone?: string` 、`patientName?: string`
- 顶部 `el-radio-group` /`el-segmented` : `全部历史(默认) | 仅本诊单` 二选一
- 全部历史 → 调 `prescriptionOrderLists({ patient_keyword: phone || patient_name, page_no, page_size })`
- 仅本诊单 → 调 `prescriptionOrderLists({ diagnosis_id, page_no, page_size })`
- 5 列:订单编号(`order_no` ) / 金额(`amount` ) / 医生(`doctor_name` ) / 创建人(`creator_name` ) / 创建时间(`create_time` )
- 分页:默认 size=10,可切 10/20/50
- 空态:`<el-empty>`
- [ ] **前端 入口 ** `admin/src/views/tcm/diagnosis/edit.vue` :
- 在 `<el-tabs>` 内追加 `<el-tab-pane label="业务订单" name="patientOrders" :disabled="!formData.id" lazy v-if="hasPermission(['tcm.diagnosis/chufang'])">`
- 内部嵌 `<PatientOrderList v-if="formData.id" :diagnosisId="Number(formData.id)" :patientPhone="originalPhone || formData.phone" :patientName="formData.patient_name" />` ,否则 `<el-empty>`
## Acceptance Criteria
- [ ] 有 `tcm.diagnosis/chufang` 权限的角色打开任一已保存诊单 → 看到"业务订单"tab
- [ ] 默认聚合该患者所有诊单的处方业务订单(按 phone 优先,回退 patient_name 模糊匹配)
- [ ] 顶部切换到"仅本诊单"后,列表使用新加的 `diagnosis_id` 等值过滤,仅展示当前诊单的订单
- [ ] 5 列正确:`order_no` / `amount` / `doctor_name` / `creator_name` / `create_time`
- [ ] 无该权限的用户看不见此 tab
- [ ] 新建(未保存)诊单 → tab 不可点
- [ ] 既有「处方业务订单」列表页(`consumer/prescription/order_list.vue` )行为完全不变(只新增过滤参数,不改既有过滤)
- [ ] 行无任何点击/操作行为
## Implementation Plan
**PR1(小步合并,约 30 行后端 + 200 行前端) **
1. 后端:`PrescriptionOrderLists.php:32` `setSearch()` 在 `'='` 数组追加 `'diagnosis_id'`
2. 前端:新增 `admin/src/views/tcm/diagnosis/components/PatientOrderList.vue`
3. 前端:`edit.vue` 注册 tab + import + 占位
**手动验证(无单测框架) **
- 角色:医生(有 chufang) / 医助(无 chufang) / 超管 — 看 tab 显隐与数据范围
- 数据:跨诊单同患者、单诊单单订单、无订单 三种场景
- 过滤:聚合开关切换两次响应应不同
- 回归:旧的 `consumer/prescription/order_list.vue` 列表所有过滤项均正常工作
## Definition of Done
- ESLint / vue-tsc 通过;新增字段 TS 类型完整
- 后端无 SQL 注入风险(`diagnosis_id` 走 `setSearch` 自动转 int)
- 不引入 `console.log`
- 既有 `consumer/prescription/order_list.vue` 视觉/交互无回归
## Out of Scope
- 不展示支付单(`zyt_order` ),不在该 tab 内做收款关联
- 不在 tab 内做任何写操作(无审核、改价、取消、退款、发货)
- 不为本 tab 单独建菜单/权限位(沿用 `tcm.diagnosis/chufang` )
## Technical Notes
- 关键文件:
- `admin/src/views/tcm/diagnosis/edit.vue:55-697` ( el-tabs 区)
- `admin/src/views/consumer/prescription/order_list.vue` (参考)
- `admin/src/api/tcm.ts:346` `prescriptionOrderLists`
- `server/app/adminapi/lists/tcm/PrescriptionOrderLists.php:29-36, 430-465, 768-785`
- 风险:
- `patient_keyword` 是 LIKE 模糊匹配,对短手机号 / 同名同号场景可能误聚合 → 建议优先用完整 11 位手机号
- `assistant_name` 注入需要再发一次 `Admin` 查询(很轻量,已有 admin id 集合)
- 测试:手动验证四种角色(医生/医助/超管/无权限)+ 三种诊单(无订单/有 1 条/有 N 条跨诊单)