353 lines
15 KiB
Markdown
353 lines
15 KiB
Markdown
# 质检工单 Tab 拆分与分型展示设计
|
||
|
||
> 日期:2026-06-16
|
||
> 状态:已确认(2026-06-16 组件边界已确认)
|
||
> 范围:`web-admin` 质检工单 + 我的质检任务;后端列表 API 补充分型过滤
|
||
> 关联:`2026-06-12-qc-work-order-fee-summary-design.md`、`outbound-qc-pilot-view-sections.ts`、`2026-06-10-basic-experiment-design.md`
|
||
|
||
---
|
||
|
||
## 1. 背景与目标
|
||
|
||
### 1.1 问题
|
||
|
||
【质检工单】【我的质检任务】原有三 Tab(入库 / 出库 / 临时),同一 Tab 内混用字段模板,导致:
|
||
|
||
- 出库卡片出现入库字段(如「来源类型」`receptionSource`)
|
||
- 基础实验与中试/临床共用卡片 meta,关键业务字段缺失或错位
|
||
- 入库采集与捐赠在组头、查看弹窗混用「协议」语义
|
||
|
||
### 1.2 目标
|
||
|
||
将业务线拆为 **6 个 Tab**,每个 Tab **仅展示、仅查询** 对应子类型的工单与任务;列表卡片、查看弹窗、筛选区与 Tab 一一对应。
|
||
|
||
### 1.3 非目标
|
||
|
||
- 不新增工单创建入口(捐赠入库仍由样本接收自动触发)
|
||
- 不改动质检任务执行、配置检测、物料使用逻辑
|
||
- 不在本期做「全部工单」汇总 Tab
|
||
- 不改动生产工单模块 Tab 结构
|
||
|
||
---
|
||
|
||
## 2. Tab 定义
|
||
|
||
### 2.1 Tab 配置表(权威)
|
||
|
||
| Tab Key | 展示标签 | `workOrderType` | `receptionSource` | `bizType` | 列表布局 |
|
||
|---------|----------|-----------------|-------------------|-----------|----------|
|
||
| `inbound_cell_storage` | 采集入库 | `inbound` | `cell_storage` | — | 样本分组 `inbound-grouped` |
|
||
| `inbound_research_donation` | 捐赠入库 | `inbound` | `research_donation` | — | 样本分组 `inbound-grouped` |
|
||
| `outbound_pilot_service` | 中试 | `outbound` | — | `pilot_service` | 单列 `standalone` |
|
||
| `outbound_basic_experiment` | 基础实验 | `outbound` | — | `basic_experiment` | 单列 `standalone` |
|
||
| `outbound_clinical_application` | 临床应用 | `outbound` | — | `clinical_application` | 单列 `standalone` |
|
||
| `temporary` | 临时 | `temporary` | — | — | 单列 `standalone` |
|
||
|
||
**Tab 栏视觉分组(可选 CSS):** 入库 2 | 出库 3 | 临时 1,标签使用短文案。
|
||
|
||
**默认 Tab:** `inbound_cell_storage`(替换原 `inbound`)。
|
||
|
||
**路由记忆:** `?tab=<tabKey>`,刷新/分享链接保持当前 Tab。
|
||
|
||
### 2.2 数据隔离规则(强约束)
|
||
|
||
每个 Tab 的列表 API 请求 **必须同时携带** 上表中的过滤参数,禁止仅传 `workOrderType` 后在客户端再筛:
|
||
|
||
```
|
||
采集入库 → workOrderType=inbound AND receptionSource=cell_storage
|
||
捐赠入库 → workOrderType=inbound AND receptionSource=research_donation
|
||
中试 → workOrderType=outbound AND bizType=pilot_service
|
||
基础实验 → workOrderType=outbound AND bizType=basic_experiment
|
||
临床应用 → workOrderType=outbound AND bizType=clinical_application
|
||
临时 → workOrderType=temporary
|
||
```
|
||
|
||
**验收:** 在任一 Tab 下,列表中不得出现其它子类型的工单;切换 Tab 后分页重置为第 1 页。
|
||
|
||
---
|
||
|
||
## 3. 筛选区(按 Tab)
|
||
|
||
移除原「业务类型」「来源类型」下拉(已由 Tab 固定)。
|
||
|
||
| Tab | 关键词 placeholder | 时间筛选标签 | 时间字段 | 额外筛选 |
|
||
|-----|-------------------|-------------|----------|----------|
|
||
| 采集入库 | 工单号/样本编码/入库编码 | 创建时间 | `createTime` | 触发来源(样本接收 / 生产过程) |
|
||
| 捐赠入库 | 工单号/样本编码/入库编码 | 创建时间 | `createTime` | 触发来源 |
|
||
| 中试 | 工单号/申请单号/申请单名称/患者 | 输注时间 | `infusionTime` | — |
|
||
| 基础实验 | 工单号/申请单号/课题名称/客户 | 交付时间 | `infusionTime`(schedule 提货时间) | — |
|
||
| 临床应用 | 工单号/申请单号/申请单名称/患者 | 输注时间 | `infusionTime` | — |
|
||
| 临时 | 工单号 | 创建时间 | `createTime` | — |
|
||
|
||
默认时间范围:近 30 天(出库类按输注/交付时间,入库/临时按创建时间)。
|
||
|
||
---
|
||
|
||
## 4. 组件边界(已确认)
|
||
|
||
| 模块 | 策略 | 说明 |
|
||
|------|------|------|
|
||
| `QcWorkOrderTaskSubList` | **共用** | 任务执行、填结果、物料与 Tab 无关 |
|
||
| 配置检测 / 调整检测弹窗 | **共用** | 三种工单类型逻辑相同 |
|
||
| `QcWorkOrderCardList` + `QcWorkOrderSampleGroup` + `QcWorkOrderSingleCard` | **共用** | 各 Tab 通过 props 传入**卡片 meta 字段模板**(组头文案、meta 列、费用条开关) |
|
||
| 查看详情弹窗 | **不共用** | 六 Tab 各一份**独立查看界面**;信息区块差异大,禁止再用 Host + variant 分支 |
|
||
| Tab 页内容(筛选 + 工具栏 + 列表) | **拷贝再改** | 从现有入库/出库/临时 Tab **剪出/拷贝**为 6 个子页面;`index.vue` 仅 Tab 壳 |
|
||
|
||
**我的质检任务:** 与质检工单 **共用同一套 6 个 Tab 子组件**(`tabs/*`),**已确认**。差异仅:
|
||
|
||
- prop `pageMode='mine'`
|
||
- 卡片操作:仅「查看」,无配置检测 / 新增 / 删除等
|
||
- 任务区 `taskListMode='mine'`
|
||
- 数据:`GET /qc-tasks/mine` + 与 Tab 一致的 `receptionSource` / `bizType` 过滤
|
||
|
||
**维护成本:** 6 个 Tab 文件 + 2 个壳页面(`qc-work-order/index.vue`、`my-qc-task/index.vue`),**不是** 12 份拷贝。
|
||
|
||
---
|
||
|
||
## 5. 列表卡片展示矩阵
|
||
|
||
共用 `QcWorkOrderCardList` / `QcWorkOrderSampleGroup` / `QcWorkOrderSingleCard`;各 Tab 子页面传入不同的 **cardMetaConfig**(字段 label、取值、Tag、费用条),禁止在卡片内用 `activeTypeTab === 'outbound'` 大包大揽。
|
||
|
||
### 5.1 入库 · 采集(`inbound_cell_storage`)
|
||
|
||
**样本组头(`QcWorkOrderSampleGroup`)**
|
||
|
||
- 样本编码、样本类型、**采集协议号**、**协议状态**、接收时间、经手人
|
||
|
||
**组内费用条(组级,已有逻辑扩展)**
|
||
|
||
- 组内存在 `cell_storage` 工单且 `paymentSummary` 时展示 `QcWorkOrderProtocolPaymentPanel`
|
||
|
||
**卡片 meta**
|
||
|
||
- 质检对象、触发来源 Tag、关联生产工单(仅 `triggerSource=production`)、实验室入库编码、检测方式、创建时间、备注
|
||
|
||
**卡片费用条**
|
||
|
||
- `paymentSummary`(`QcWorkOrderProtocolPaymentPanel` compact)
|
||
|
||
**工具栏**
|
||
|
||
- 「新增入库质检工单」(仅本 Tab;`receptionSource` 固定 `cell_storage`)
|
||
|
||
### 5.2 入库 · 捐赠(`inbound_research_donation`)
|
||
|
||
**样本组头**
|
||
|
||
- 样本编码、样本类型、**捐赠单号**(`protocolNo` 字段存捐赠编号)、**捐赠状态**、接收时间、经手人
|
||
|
||
**卡片 meta**
|
||
|
||
- 同采集入库卡片结构;**不展示**协议状态、费用相关字段
|
||
|
||
**工具栏**
|
||
|
||
- 无新增按钮
|
||
|
||
### 5.3 出库 · 中试(`outbound_pilot_service`)
|
||
|
||
**卡片 meta**
|
||
|
||
- 申请单号、申请单名称、渠道名称、**患者姓名**、第 N 次 / 共 M 次、输注时间、检测方式、创建时间、备注
|
||
|
||
**禁止展示**
|
||
|
||
- `receptionSource`、业务类型 Tag(Tab 已表达)、基础实验专属字段
|
||
|
||
**费用条**
|
||
|
||
- 不展示
|
||
|
||
### 5.4 出库 · 基础实验(`outbound_basic_experiment`)
|
||
|
||
**卡片 meta**
|
||
|
||
- 申请单号、**课题名称**、**客户名称**、**交付时间**、售卖金额(可选,来自 `feeSummary.saleAmount`)、检测方式、创建时间、备注
|
||
|
||
**费用条**
|
||
|
||
- `QcWorkOrderFeeSummaryBar`(`feeSummary`)
|
||
|
||
### 5.5 出库 · 临床应用(`outbound_clinical_application`)
|
||
|
||
**卡片 meta**
|
||
|
||
- 申请单号、申请单名称、渠道名称、患者姓名、第 N 次 / 共 M 次、输注时间、检测方式、创建时间、备注
|
||
|
||
**费用条**
|
||
|
||
- `QcWorkOrderFeeSummaryBar`(与 `2026-06-13-production-work-order-fee-summary-design.md` D1=B 一致)
|
||
|
||
### 5.6 临时(`temporary`)
|
||
|
||
保持现状:产品编码/名称/类型、检测方式、创建时间;工具栏「新增临时工单」。
|
||
|
||
---
|
||
|
||
## 6. 查看弹窗(六份独立界面)
|
||
|
||
**不共用** `QcWorkOrderViewDialogHost`、`OutboundQcViewDialog` 及其中 `variant` 分支。自现有弹窗**拷贝**后按 Tab 删减字段;检测任务区块(实验室/第三方/参数/附件/物料)可抽 **`useQcWorkOrderTaskViewSections.ts`** 供六弹窗 import,避免任务展示逻辑拷六份。
|
||
|
||
### 6.1 Tab → 弹窗组件(一一对应)
|
||
|
||
| Tab Key | 新建组件 | 拷贝来源 | 主要差异 |
|
||
|---------|----------|----------|----------|
|
||
| `inbound_cell_storage` | `InboundCellStorageViewDialog.vue` | 现 `QcWorkOrderViewDialogHost` + `useQcWorkOrderViewDialog` | 协议状态、协议缴费、运输、样本接收 |
|
||
| `inbound_research_donation` | `InboundResearchDonationViewDialog.vue` | 上者拷贝 | **无**协议缴费;捐赠状态;组头/基本信息用捐赠文案 |
|
||
| `outbound_pilot_service` | `OutboundPilotViewDialog.vue` | 现 `OutboundQcViewDialog` | 仅中试:申请单、患者、输注方案/计划、产品、检测任务;**无**缴费区块 |
|
||
| `outbound_basic_experiment` | `OutboundBasicExperimentViewDialog.vue` | 出库弹窗拷贝 | 课题/客户/交付计划/产品/缴费;**无**患者、输注方案 |
|
||
| `outbound_clinical_application` | `OutboundClinicalViewDialog.vue` | 出库弹窗拷贝 | 同中试结构 + 临床应用缴费信息(如有) |
|
||
| `temporary` | `TemporaryQcViewDialog.vue` | 入库弹窗拷贝 | 仅产品信息 + 检测任务;**无**接收/运输/协议 |
|
||
|
||
### 6.2 挂载方式
|
||
|
||
- 各 **Tab 子页面** 内直接 `import` 对应弹窗,`:visible` + `@view` 打开;**不再**使用统一 `openView(row)` 按类型分流。
|
||
- 旧文件 `QcWorkOrderViewDialogHost.vue`、`OutboundQcViewDialog.vue` 在六弹窗落地并切换引用后**删除**(或首版标记 `@deprecated` 再删)。
|
||
|
||
### 6.3 可共用的底层(非 UI 壳)
|
||
|
||
| 共用项 | 说明 |
|
||
|--------|------|
|
||
| `SystemViewDialog` | 布局壳 |
|
||
| `ProtocolAttachmentReadonly` | 附件只读 |
|
||
| `QcWorkOrderProtocolPaymentPanel` | 仅采集入库弹窗使用 |
|
||
| `fetchQcWorkOrderDetail` / `fetchOutboundQcDetail` | API |
|
||
| `useQcWorkOrderTaskViewSections`(新建) | 检测任务 sections + 附件 slot + 物料 slot |
|
||
|
||
---
|
||
|
||
## 7. Tab 子页面结构(拷贝再改)
|
||
|
||
```
|
||
web-admin/src/views/quality-inspection/qc-work-order/
|
||
index.vue # 6 Tab 壳 + ?tab= 路由
|
||
tabs/
|
||
InboundCellStorageTab.vue # 从原 index 入库区块剪出
|
||
InboundResearchDonationTab.vue # 拷贝 InboundCellStorageTab 再改
|
||
OutboundPilotTab.vue # 从原出库区块剪出
|
||
OutboundBasicExperimentTab.vue # 拷贝 OutboundPilotTab 再改
|
||
OutboundClinicalTab.vue # 拷贝 OutboundPilotTab 再改
|
||
TemporaryTab.vue # 从原临时区块剪出
|
||
view-dialogs/
|
||
InboundCellStorageViewDialog.vue
|
||
InboundResearchDonationViewDialog.vue
|
||
OutboundPilotViewDialog.vue
|
||
OutboundBasicExperimentViewDialog.vue
|
||
OutboundClinicalViewDialog.vue
|
||
TemporaryQcViewDialog.vue
|
||
```
|
||
|
||
`my-qc-task/index.vue` 同样 6 Tab 壳,**import 上述 `tabs/*` 组件**,传 `page-mode="mine"`。
|
||
|
||
---
|
||
|
||
## 8. 我的质检任务
|
||
|
||
与质检工单 **共用** `tabs/*` 子组件与 `cardMetaConfig`;差异:
|
||
|
||
- `pageMode='mine'`:卡片仅「查看」
|
||
- 任务列表 `taskListMode='mine'`
|
||
- 数据流:先按 Tab 参数请求 `GET /qc-tasks/mine`,再聚合为卡片
|
||
|
||
**后端扩展 `list_mine_tasks`:** 增加 `receptionSource`、`bizType` 过滤,与工单列表对齐,避免客户端从全量任务中筛类型。
|
||
|
||
**`qc-mine-task-groups.ts`:**
|
||
|
||
- `QcWorkOrderTypeTab` 替换为 `QcWorkOrderTabKey`
|
||
- `resolveWorkOrderTabKey(task)` 由 `workOrderType` + `receptionSource` / `bizType` 解析
|
||
- `filterMineEntriesByWorkOrderSearch` 按 `tabKey` 固定过滤,移除 `bizType`/`receptionSource` 筛选项
|
||
|
||
---
|
||
|
||
## 9. 后端 API 变更
|
||
|
||
### 7.1 `GET /qc-work-orders`(列表)
|
||
|
||
新增 Query 参数:
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `receptionSource` | string | 入库分型:`cell_storage` / `research_donation` |
|
||
|
||
`list_work_orders()` 在 `work_order_type=inbound` 且 `reception_source` 有值时:
|
||
|
||
```python
|
||
q0 = q0.filter(BizQcWorkOrder.reception_source == rs)
|
||
```
|
||
|
||
出库 Tab 继续传 `bizType`(已有)。
|
||
|
||
### 7.2 `GET /qc-tasks/mine`
|
||
|
||
新增 Query 参数:`receptionSource`、`bizType`,在 join `BizQcWorkOrder` 后过滤。
|
||
|
||
### 7.3 列表 enrich
|
||
|
||
确认基础实验列表项含 `projectTitle`(课题名称)、`customerName`;缺则于 `_enrich_outbound_list_fields` 补充 join。
|
||
|
||
---
|
||
|
||
## 10. 前端模块结构(摘要)
|
||
|
||
```
|
||
web-admin/src/utils/qc-work-order-tabs.ts # Tab 常量 + toListQueryParams
|
||
web-admin/src/utils/qc-work-order-card-meta.ts # 六 Tab 的 cardMetaConfig 导出(供 CardList props)
|
||
web-admin/src/views/.../qc-work-order/tabs/ # 6 Tab 子页面(拷贝再改)
|
||
web-admin/src/views/.../qc-work-order/view-dialogs/ # 6 独立查看弹窗
|
||
web-admin/src/views/.../qc-work-order/composables/useQcWorkOrderTaskViewSections.ts # 检测任务区块共用
|
||
```
|
||
|
||
**共用不改业务:** `QcWorkOrderTaskSubList`、配置检测弹窗(仍在 `index.vue` 或 composable)。
|
||
|
||
**删除/替换:** `QcWorkOrderViewDialogHost.vue`、`OutboundQcViewDialog.vue`、`useQcWorkOrderViewDialog.ts`(逻辑拆入六弹窗 + task composable)。
|
||
|
||
---
|
||
|
||
## 11. 验收清单
|
||
|
||
### 11.1 数据隔离
|
||
|
||
- [ ] 采集入库 Tab 仅 `receptionSource=cell_storage` 的 inbound 工单
|
||
- [ ] 捐赠入库 Tab 仅 `research_donation` 的 inbound 工单
|
||
- [ ] 中试 / 基础实验 / 临床 Tab 各自仅对应 `bizType` 的 outbound 工单
|
||
- [ ] 临时 Tab 仅 `workOrderType=temporary`
|
||
- [ ] 我的质检任务六 Tab 与上相同(任务所属工单类型一致)
|
||
|
||
### 11.2 展示
|
||
|
||
- [ ] 出库卡片无 `receptionSource` 字段
|
||
- [ ] 基础实验卡片无患者/输注疗程字段,有课题/客户/交付时间
|
||
- [ ] 捐赠组头为捐赠单号/捐赠状态,非协议文案
|
||
- [ ] 采集入库查看弹窗有协议缴费;捐赠无
|
||
- [ ] 六 Tab 各打开对应**独立**查看弹窗,无交叉引用 Host/variant
|
||
- [ ] 基础实验查看弹窗无患者/输注方案;中试/临床无课题专属区块
|
||
|
||
### 11.3 操作
|
||
|
||
- [ ] 仅采集入库 Tab 有「新增入库质检工单」
|
||
- [ ] 仅临时 Tab 有「新增临时工单」
|
||
- [ ] 配置检测 / 调整检测 / 编辑备注行为与改版前一致
|
||
|
||
### 11.4 回归
|
||
|
||
- [ ] Tab 切换重置分页与筛选(保留 Tab 专属默认时间范围)
|
||
- [ ] URL `?tab=` 可深链到指定 Tab
|
||
- [ ] 费用摘要条规则与 `2026-06-12-qc-work-order-fee-summary-design.md` 一致
|
||
|
||
---
|
||
|
||
## 12. 决策记录
|
||
|
||
| 项 | 决策 |
|
||
|----|------|
|
||
| Tab 数量 | 6(入库 2 + 出库 3 + 临时 1) |
|
||
| Tab 标签 | 短标签:采集入库 / 捐赠入库 / 中试 / 基础实验 / 临床应用 / 临时 |
|
||
| 实现策略 | **Tab 子页面拷贝再改**;`index.vue` 仅 Tab 壳 |
|
||
| 数据过滤 | **服务端** 强制分型,禁止仅靠前端过滤 |
|
||
| TaskSubList | **共用** |
|
||
| 配置检测弹窗 | **共用** |
|
||
| CardList + SampleGroup | **共用**,props 传 `cardMetaConfig` |
|
||
| 查看弹窗 | **六份独立界面**,不共用 Host / OutboundQcViewDialog |
|
||
| 检测任务展示 | composable 共用,避免六份弹窗重复任务 UI 逻辑 |
|
||
| 我的质检任务 | **已确认** 共用 6 个 `tabs/*`,`pageMode='mine'` |
|