2026-07-29-outbound-cell-lineage-qc-design.md 9.4 KB

出库物料准备 — 细胞产品来源链质检查看设计

日期:2026-07-29
状态:已确认(brainstorming)
方案:A(后端聚合接口 + 独立只读弹窗)
入口:出库放行审核 → 出库物料准备 → 出库细胞列表

1. 需求概述

在「出库物料准备」弹窗的「出库细胞」列表中,用户可通过行操作查看所选细胞产品相关的质检信息,用于放行前核对。

必须展示:

  • 质检任务的检测参数、结论、备注、附件(业务所称「检测材料」= 质检任务附件)
  • 整条来源链上的质检:祖先细胞产品 + 上游样本相关质检(不仅当前产品)
  • 全部任务状态(待配置 / 进行中 / 已完成等,含未完成)

数据策略:实时查询,不写入出库台账快照;质检事后变更后再次打开可见最新结果。

交互:主列表保持简洁;行上「查看质检」打开独立弹窗(非行内展开)。

1.1 已确认决策

项 选择
父级范围 B:整条来源链(祖先细胞产品 + 上游样本)
任务状态 B:全部状态
检测材料 质检任务附件(非出库 qcMaterials 库存扣减,非实验室物料使用明细)
交互 B:行按钮 → 独立弹窗
数据 A:实时查询
实现路径 A:后端聚合 API + 只读弹窗

1.2 非目标(本期不做)

  • 出库保存时落质检快照
  • 行内展开 / 添加细胞时自动弹出质检
  • 改造细胞库来源链图谱(/chain 可视化)
  • 展示实验室任务「物料使用」库存明细
  • 同步改造出库审核弹窗 / 查看出库详情(若需要另开需求)
  • 前端拼装多次现有接口作为主方案

2. 背景与现有能力

2.1 传代 / 来源链

biz_cell_product 无 parent_id。父子关系来自生产任务投入/产出:

  • 祖先:get_product_chain → _build_ancestor_chain(backend/app/crud/cell_product.py)
  • 前端已有:fetchCellProductChain → GET /web/admin/cell-products/{id}/chain
  • 设计参考:docs/superpowers/specs/2026-05-24-cell-product-source-chain-design.md

本需求只消费 current + ancestors,不取 descendants。

2.2 质检关联

  • 细胞产品:BizQcWorkOrder.cell_product_id
  • 样本入库质检:list_work_orders_by_sample(sample_code + reception_source,work_order_type=inbound)
  • 任务详情字段:results(参数)、conclusion / remark、attachmentFiles(由附件 URL 解析)
  • 只读 UI 参考:web-admin/.../QcWorkOrderTaskResultPanel.vue

2.3 出库物料弹窗现状

  • 组件:OutboundReleaseMaterialDialog.vue
  • 出库细胞仅存 cellProductId 等台账字段;保存逻辑不因本需求变更

3. 架构与数据流

出库细胞行 [查看质检]
        │
        ▼
GET /web/admin/cell-products/{id}/lineage-qc
        │
        ├─ get_product_chain(复用)→ current + ancestors
        ├─ 展平节点(根→叶,当前最后;按 nodeType+id 去重)
        ├─ cell_product 节点:按 cell_product_id 查工单(不限 work_order_type)
        ├─ sample 节点:按 sampleCode + receptionSource 查入库质检
        └─ 工单批量拉任务详情(参数/结论/备注/附件;不过滤状态)
        │
        ▼
el-dialog「来源链质检」只读展示

4. 后端设计

4.1 接口

  • 方法/路径:GET /web/admin/cell-products/{product_id}/lineage-qc
  • 注册:与 /chain 同域(backend/app/api/production.py)
  • 编排:get_product_lineage_qc(建议在 cell_product.py,内部复用 qc CRUD,禁止复制序列化逻辑)

4.2 响应骨架

{
  "productId": "...",
  "productCode": "...",
  "productName": "...",
  "nodes": [
    {
      "nodeType": "sample | cell_product",
      "id": "...",
      "label": "样本编码或产品编码",
      "productName": "...",
      "passage": "P1",
      "receptionSource": "cell_storage | research_donation | null",
      "isCurrent": false,
      "workOrders": [
        {
          "id": "...",
          "workOrderNo": "...",
          "workOrderType": "...",
          "workOrderStatus": "...",
          "workOrderStatusLabel": "...",
          "tasks": [
            {
              "id": "...",
              "taskNo": "...",
              "itemName": "...",
              "itemCode": "...",
              "taskType": "...",
              "taskStatus": "...",
              "conclusion": "...",
              "conclusionLabel": "...",
              "remark": "...",
              "completedTime": "...",
              "results": [
                { "paramName": "", "paramValue": "", "paramUnit": "" }
              ],
              "attachmentFiles": [
                { "fileName": "", "fileUrl": "", "fileType": "" }
              ]
            }
          ]
        }
      ]
    }
  ]
}

字段命名与现有质检详情 camelCase 对齐,便于前端复用 Tag/附件组件。

4.3 查询规则

  1. 链路:get_product_chain;展平 nested ancestor parent;深度上限沿用 _MAX_CHAIN_DEPTH。
  2. 细胞产品工单:cell_product_id = node.id,del_flag=0,租户过滤;不限 work_order_type。
  3. 样本工单:对齐 list_work_orders_by_sample;reception_source 缺失时该节点 workOrders: [],不 500。
  4. 任务:复用 inspection batch → task → result / attachments 拼装;不过滤任务状态。
  5. 性能(一期):批量查工单与任务,避免 N 次串行 get_work_order_detail;全量一次返回。二期可按节点懒加载。

4.4 错误与边界

情况 行为
产品不存在 / 跨租户 业务 400/404,文案明确
无祖先(如手动录入) nodes 仅含 current
节点无工单 仍返回节点,workOrders: []
单节点加载异常 该节点空列表 + 可选 loadError,不拖垮整响应
附件 URL 坏项 跳过该项

4.5 权限

  • 能进入「出库物料准备」的用户应能调用本只读接口。
  • 实现时使用 require_any_menu_code:任一匹配即可——出库放行相关菜单码,或质检工单列表码,或细胞产品查看码(具体码表在实现计划中对照菜单 SQL 写死)。
  • 租户隔离强制。数据范围:优先按工单 tenant_no 过滤;若套用质检 data scope 会导致「能准备出库物料却看不到质检」则本期对放行入口放宽为租户内只读(实现计划写明最终策略)。

5. 前端设计

5.1 入口

  • 文件:OutboundReleaseMaterialDialog.vue(及若共用的 outbound-material-form-sections,以实现时是否共用为准;至少出库放行物料弹窗落地)
  • 出库细胞操作列增加「查看质检」(View 图标 + 文案);保留「删除」
  • 操作列 min-width 约 ≥ 180px
  • 仅存在 cellProductId 时可点

5.2 弹窗组件

  • 新建 CellProductLineageQcDialog.vue(建议 components/business/ 或 outbound-release-review/)
  • el-dialog + dialog-form-layout,宽约 960–1120px,append-to-body,无 backdrop blur
  • 标题:来源链质检;副信息:当前产品编码 / 名称
  • 打开时请求 lineage-qc;v-loading;失败 ElMessage.error
  • 底栏仅「关闭」(Close 图标)

5.3 信息架构

自上而下:

  1. 当前产品摘要条(编码 · 名称 · 代次)
  2. 按 nodes 分区(可折叠;默认均展开)
    • 样本:编码 + 来源标签
    • 产品:编码、名称、代次;当前节点 Tag「当前」+ 主色强调
  3. 工单卡片:工单号 · 类型 · 状态 Tag
  4. 任务卡片:对齐 QcWorkOrderTaskResultPanel 只读结构
    • 项目名、任务状态、结论 Tag
    • 检测参数
    • 备注(有则显示)
    • 附件(预览/下载,对齐现有附件卡片)
  5. 空态:节点无工单 →「暂无质检工单」;整单无数据 → 友好空状态

节点顺序:上游 → 下游(当前产品在最后)。

5.4 API 封装

  • web-admin/src/api/cell-product.ts 增加 fetchCellProductLineageQc(productId)

5.5 UI 规范

  • Fresh Mint;状态/结论用 el-tag + status-tag-registry
  • 按钮带图标;遮罩无模糊

6. 测试与验收

6.1 后端

  • 仅 current、无祖先
  • P1→P2→当前,顺序与挂载正确
  • 链上样本节点挂入库质检
  • 多状态任务与参数/结论/备注/附件齐全
  • 产品不存在、租户隔离、深度截断

6.2 前端

  • 独立弹窗不打断主弹窗编辑
  • loading / 错误 / 空态
  • 附件可预览下载
  • 操作列不被裁切

6.3 验收(产品语言)

  1. 出库细胞行可打开「来源链质检」,列表保持简洁
  2. 可见该产品 + 全部上游样本/祖先产品的质检任务
  3. 每任务可见检测参数、结论、备注、附件;全部状态可见
  4. 再次打开为实时数据;不写入出库台账

7. 实现顺序建议

  1. 后端:get_product_lineage_qc + 路由 + 单测(展平/样本键/批量)
  2. 前端 API + CellProductLineageQcDialog
  3. 接入 OutboundReleaseMaterialDialog 操作列
  4. 联调验收清单

8. 开放项(实现计划阶段闭合)

  • 精确菜单权限码列表(对照 docs/sql 菜单)
  • 组件最终目录(components/business vs 业务目录)
  • 若 outbound-material-form-sections 与放行弹窗分叉,是否两边都接入口(默认:放行物料弹窗必做;共用组件则一并改)