11 KiB
入库质检工单 · 协议单多样本 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)
export type QcWorkOrderProtocolGroupModel = {
groupKey: string
protocolId: string
protocolNo: string
receptionSource: 'cell_storage' | 'research_donation'
sampleGroups: QcWorkOrderSampleGroupModel[]
workOrders: QcWorkOrder[] // 组内全部工单(扁平)
}
export function groupInboundQcWorkOrdersByProtocol(
rows: QcWorkOrder[]
): QcWorkOrderProtocolGroupModel[]
实现步骤:
- 按
collectionProtocolId(及回退键)聚合工单。 - 每组内调用现有
groupInboundQcWorkOrders得到sampleGroups。 - 协议组排序:组内最新工单
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 条件中增加:
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. 验收标准
- 【质检工单】细胞存储 / 科研捐赠 Tab:同一
collectionProtocolId下多样本合并为 一张协议组卡片。 - 协议组内 样本 Tab 可切换;切换后展示对应样本工单与任务。
- 同样本多工单(接收 + 生产)仍显示 触发来源 Tab,行为与改动前一致。
- 单样本协议组 不显示 样本 Tab 行,直接展示工单区。
- 细胞存储协议组 协议费用条 组级展示一次;科研捐赠不展示费用条。
- 【我的质检任务】同上,且仅查看 + 任务操作。
- 关键词输入协议号 / 捐赠单号可筛出该协议下全部相关工单。
- 「所有」Tab、出库 Tab、临时 Tab 列表行为 回归不变。
- 配置检测 / 调整检测 / 查看弹窗 回归不变。
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. 下一步
- 评审本文档 — 无遗漏后进入实现计划(
writing-plans→docs/superpowers/plans/)。 - 可选:同步 OpenSpec capability
qc-work-order-protocol-group(与ui-conventions卡片分组约定对齐)。