# 入库质检工单 · 协议单多样本 Tab 分组 — 设计文档 > 日期:2026-06-25 > 状态:已实现 > 范围:`web-admin` 【质检工单】【我的质检任务】入库类 Tab;后端列表关键词补协议号 > 关联:`2026-06-16-qc-work-order-tab-split-design.md`、`2026-06-25-qc-work-order-all-tab-design.md`、`2026-06-25-qc-inspection-batch-design.md` --- ## 1. 背景与目标 ### 1.1 问题 细胞存储质检、科研捐赠质检的工单均来自**采集协议单 / 科赠协议单**。一份协议单可含**多个样本**,每个样本接收后各生成至少一条质检工单(生产过程可再追加)。 现网列表按 **`sampleCode`(样本编码)** 分组:同一协议下的多个样本各自占一张卡片,协议号等信息在组头副标题重复出现,用户难以「按协议一眼看全样本质检进度」。 ### 1.2 目标 在 **细胞存储质检**、**科研捐赠质检** 两个 Tab 中,将同一协议单下的多个样本**合并为一张协议组卡片**,组内用 **Tab 切换样本**;样本内仍保留现网 **触发来源 Tab**(样本接收 / 生产过程)。 【质检工单】与【我的质检任务】**共用**同一套列表组件与分组逻辑。 ### 1.3 非目标 - 不改变出库、临时 Tab 的列表布局。 - 不在 **「所有」** Tab 做协议分组(沿用平铺 + 类型 Tag,见 `2026-06-25-qc-work-order-all-tab-design.md` §1.3)。 - 不合并细胞存储与科研捐赠(仍分 Tab)。 - 不把同协议多样本压成**单层扁平卡片**(去掉样本层级)。 - 本期不做「按协议分页」后端改造(分页仍按工单条数;见 §5.3 边界说明)。 --- ## 2. 列表信息架构 ### 2.1 三层结构 ``` 协议组(新增外层) └── 样本 Tab(新增中层) └── 触发来源 Tab(现网 QcWorkOrderSampleGroup 内层) └── 工单卡片 + 检测批次 + 任务 ``` ### 2.2 分组键 | 层级 | 分组字段 | 回退 | |------|----------|------| | 协议 | `collectionProtocolId` | `(protocolNo).trim()`,仍空则用首条工单 `id` | | 样本 | `sampleCode` | 工单 `id` | | 工单 | 同样本下按 `triggerSource` Tab 切换 | 现网逻辑 | 说明:科赠工单的 `collectionProtocolId` 存的是 `research_donation_id`(后端建单已如此),与细胞存储共用分组字段名。 ### 2.3 Tab 配置 `listLayout` **保持** `inbound-grouped`(语义扩展为「入库分组列表」,实现改为协议优先分组,不再在 `QcWorkOrderCardList` 顶层直接使用 `QcWorkOrderSampleGroup`)。 受影响 Tab: | Tab Key | 展示标签 | 列表布局(实现) | |---------|----------|------------------| | `inbound_cell_storage` | 细胞存储质检 | 协议分组 + 样本 Tab | | `inbound_research_donation` | 科研捐赠质检 | 协议分组 + 样本 Tab | --- ## 3. UI 设计 ### 3.1 协议组头(`qc-protocol-row__ctx`) 视觉对齐现网 `qc-sample-row__ctx`(绿渐变顶栏 + 序号)。 | 元素 | 细胞存储 | 科研捐赠 | |------|----------|----------| | 主标题 | 协议号 `protocolNo` | 捐赠单号 `protocolNo` | | 副标题 | 协议状态 Tag + `N 个样本` + 可选进度摘要 | 捐赠状态 Tag + `N 个样本` + 可选进度摘要 | | Badge | 组内工单总数(如 `5 条质检`) | 同左 | **进度摘要(可选展示):** 如 `2/3 已配置`,按样本维度统计:该样本下存在 `workOrderStatus !== 'dpz'` 的 gate 工单(优先 `triggerSource=reception`,否则取组内首条)即计为「已配置样本」。无数据时不展示。 **协议费用条:** 仅 **细胞存储** Tab、且组内存在 `paymentSummary` 的工单时,在协议组头下方展示 **一次** `QcWorkOrderProtocolPaymentPanel`(compact),**不要**在每个样本 Tab 内重复。 ### 3.2 样本 Tab 行(`qc-protocol-sample-tabs`) - 样式复用现网 `qc-wo-indep-tabs__btn` / pill Tab(与 `QcWorkOrderSampleGroup` 触发来源 Tab 一致)。 - **仅当组内样本数 ≥ 2** 时展示 Tab 行;**单样本**时隐藏 Tab 行,直接展示该样本工单区。 每个 Tab pill 文案: | 部分 | 内容 | |------|------| | 序号 | `1` `2` `3`(圆点序号,与现网一致) | | 主文案 | 样本编码(monospace) | | 辅助 | 样本类型 `sampleTypeName`(有值时) | | 状态 | 该样本 gate 工单 `workOrderStatus` 的 `el-tag` | Tab 排序:按样本编码字典序;同编码按 gate 工单 `createTime` ASC。 ### 3.3 样本工单区 选中样本后渲染 **`QcWorkOrderSampleGroup`**,传入该样本下的 `workOrders` 子集,并增加 prop: | Prop | 值 | 说明 | |------|-----|------| | `hideContextBar` | `true` | 隐藏原样本组头(协议组头 + 样本 Tab 已表达上下文) | | 其余 | 与现网一致 | 内层触发来源 Tab、卡片、批次、任务 | 单样本且仅 1 条工单时:无样本 Tab、无触发来源 Tab,直接展示 `QcWorkOrderSingleCard`。 ### 3.4 线框(ASCII) ``` ┌─ 1 XY2026001 [协议进行中] 3 个样本 · 2/3 已配置 [5 条质检] ─┐ │ [协议费用 compact — 仅细胞存储] │ ├─ 样本 Tab ───────────────────────────────────────────────────────┤ │ [1 A001·脐带血·待配置] [2 A002·胎盘·已配置] [3 B003·进行中] │ ├─ 触发来源 Tab(样本 A001 有 2 条工单时)───────────────────────────┤ │ [样本接收 ZJ…] [生产过程 ZJ…] │ ├─ 工单 meta + 检测批次 + 任务 ─────────────────────────────────────┤ └───────────────────────────────────────────────────────────────────┘ ``` --- ## 4. 前端实现要点 ### 4.1 新增工具(`web-admin/src/utils/qc-work-order-groups.ts`) ```typescript export type QcWorkOrderProtocolGroupModel = { groupKey: string protocolId: string protocolNo: string receptionSource: 'cell_storage' | 'research_donation' sampleGroups: QcWorkOrderSampleGroupModel[] workOrders: QcWorkOrder[] // 组内全部工单(扁平) } export function groupInboundQcWorkOrdersByProtocol( rows: QcWorkOrder[] ): QcWorkOrderProtocolGroupModel[] ``` 实现步骤: 1. 按 `collectionProtocolId`(及回退键)聚合工单。 2. 每组内调用现有 `groupInboundQcWorkOrders` 得到 `sampleGroups`。 3. 协议组排序:组内最新工单 `createTime DESC`(与列表默认排序一致)。 ### 4.2 新增组件 **`QcWorkOrderProtocolGroup.vue`** - Props / Emits 与 `QcWorkOrderSampleGroup` 对齐(`configure` / `view` / `command` / `tasks-changed`)。 - 内含样本 Tab 状态 `activeSampleKey`(`sampleCode` 或回退 `id`)。 - 渲染选中样本的 `QcWorkOrderSampleGroup`(`hideContextBar=true`)。 ### 4.3 修改组件 | 文件 | 变更 | |------|------| | `QcWorkOrderSampleGroup.vue` | 新增 `hideContextBar?: boolean`,为 true 时不渲染 `qc-sample-row__ctx` | | `QcWorkOrderCardList.vue` | `cardMetaUsesInboundGroups` 时渲染 `QcWorkOrderProtocolGroup` 而非直接 `QcWorkOrderSampleGroup` | | `qc-work-order-card-meta.ts` | 新增 `buildProtocolGroupContextSubtitle(group)`;细胞存储/捐赠分别用协议/捐赠文案 | ### 4.4 「所有」Tab **不变。** `buildAllTabListItems` 中 inbound 仍可按样本合并(或维持现状);本需求不修改 `all` Tab 布局。 ### 4.5 我的质检任务 与 manage 共用 `QcWorkOrderCardList` + 协议分组;`pageMode='mine'` 时卡片仅查看、任务区 `taskListMode='mine'`。 前端 mine 关键词过滤补充 `protocolNo` 字段(`qc-mine-task-groups.ts` → `keywordMatchesWorkOrder`,inbound 组)。 --- ## 5. 后端变更 ### 5.1 列表关键词 — 协议号(必须) `list_work_orders` 在现有关键词 OR 条件中增加: ```python BizQcWorkOrder.protocol_no.like(like) ``` 适用于入库类及「所有」Tab 跨类型搜索。 ### 5.2 筛选 placeholder 入库 Tab 关键词 placeholder 更新为: `工单号/协议号/样本编码/入库编码` (细胞存储写「协议号」,科研捐赠写「捐赠单号」——按 Tab 文案区分。) ### 5.3 分页边界 - 分页单位仍为 **工单条数**(`pageSize` 默认 100)。 - 同一协议多样本可能**跨页**:当前页仅展示本页工单所属的样本 Tab;未出现在本页的样本不出 Tab。**可接受**,二期可选「按协议 ID 拉全量样本工单再分组」(非本期)。 --- ## 6. 与检测批次的关系 检测批次在 **工单卡片内部**(`QcWorkOrderBatchSubList`),与协议/样本分组**正交**: ``` 协议 → 样本 Tab → 触发来源 Tab → 工单 → 批次 → 任务 ``` 本需求不修改批次配置 API 与 UI。 --- ## 7. 验收标准 1. 【质检工单】细胞存储 / 科研捐赠 Tab:同一 `collectionProtocolId` 下多样本合并为 **一张协议组卡片**。 2. 协议组内 **样本 Tab** 可切换;切换后展示对应样本工单与任务。 3. 同样本多工单(接收 + 生产)仍显示 **触发来源 Tab**,行为与改动前一致。 4. 单样本协议组 **不显示** 样本 Tab 行,直接展示工单区。 5. 细胞存储协议组 **协议费用条** 组级展示一次;科研捐赠不展示费用条。 6. 【我的质检任务】同上,且仅查看 + 任务操作。 7. 关键词输入协议号 / 捐赠单号可筛出该协议下全部相关工单。 8. 「所有」Tab、出库 Tab、临时 Tab 列表行为 **回归不变**。 9. 配置检测 / 调整检测 / 查看弹窗 **回归不变**。 --- ## 8. 已确认决策 | 问题 | 决策 | |------|------| | 是否按协议合并多样本? | **是** | | 样本切换交互? | **Tab(pill)**,复用现网触发来源 Tab 样式 | | 单样本是否仍显示 Tab? | **否**,隐藏样本 Tab 行 | | 两页是否一致? | **是** | | 「所有」Tab 是否协议分组? | **否** | | 分页是否改为按协议? | **否**(本期) | | 协议费用条位置? | **协议组头一次**(仅细胞存储) | --- ## 9. 实现阶段建议 | 阶段 | 内容 | 预估 | |------|------|------| | P1 | `groupInboundQcWorkOrdersByProtocol` + `QcWorkOrderProtocolGroup` + SampleGroup `hideContextBar` | 1~1.5 人天 | | P2 | CardList 接入 + card-meta 协议组头 + placeholder | 0.5 人天 | | P3 | 后端 `protocol_no` 关键词 + mine 前端关键词 | 0.5 人天 | | P4 | 两页联调、回归六 Tab + 所有 Tab | 0.5~1 人天 | | **合计** | | **2.5~3.5 人天** | --- ## 10. 下一步 1. 评审本文档 — 无遗漏后进入实现计划(`writing-plans` → `docs/superpowers/plans/`)。 2. 可选:同步 OpenSpec capability `qc-work-order-protocol-group`(与 `ui-conventions` 卡片分组约定对齐)。