Files
zyt/.trellis/tasks/archive/2026-05/05-05-tcm-diagnosis-patient-orders-tab/prd.md
T

7.7 KiB
Raw Blame History

诊单编辑对话框:新增「患者业务订单」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.vue5890 行)
  • 现有 APIprescriptionOrderLists/tcm.prescriptionOrder/listsadmin/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_namedoctor_nameprescription_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
    • propsdiagnosisId: numberpatientPhone?: stringpatientName?: 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_idsetSearch 自动转 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-697el-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 条跨诊单)