# 临时质检 · 外部质检对象编号(手写)设计 **日期:** 2026-08-20 **状态:** 已评审待实现 **范围:** web-admin 质检工单「临时质检」手动新增/编辑 + 列表/详情展示;backend `biz_qc_work_order` 字段与校验 ## 1. 背景与问题 当前「新增临时质检工单」弹窗中「质检对象」仅能从系统细胞产品主数据(`GET /web/admin/cell-products` → `biz_cell_product`)选择;创建/更新时后端强制校验 `cell_product_id` 必须存在。 客户场景:部分样品来自外部科研机构,**不在系统细胞产品库中**,希望能手写一个编号作为质检对象标识。 ## 2. 需求结论(已确认) | 项 | 结论 | |---|---| | 交互 | 方案 A:来源切换(系统细胞产品 / 外部科研编号) | | 外部信息 | 只要一个编号 | | 唯一性 | 不强制;同一编号可多次建单(复检/多批次) | | 格式 | 无特殊格式;trim 后非空,最长 64 | | 与细胞产品关联 | 不需要;全程不绑细胞产品,纯展示标识 | | 范围 | 手动新增/编辑 + 列表/详情展示;**生产派发临时质检链路不动** | ## 3. 方案选择 采用 **方案 1:工单表增加外部编号字段**。 - 不借用 `sample_code` / `remark`(语义污染) - 不为外部编号自动创建伪细胞产品(污染主数据,且与「不绑定」冲突) - 不新增独立 `qc_target_source` 列:由 `cell_product_id` 与 `external_target_code` 互斥存在推导来源 ## 4. 数据模型 ### 4.1 表字段 表:`biz_qc_work_order` | 字段 | 类型 | 可空 | 说明 | |---|---|---|---| | `external_target_code` | `VARCHAR(64)` | YES | 外部质检对象编号(手写) | 放置位置:业务字段区,建议紧挨 `cell_product_id` 之后。同步更新 SQLAlchemy `BizQcWorkOrder`、`docs/sql/` 增量脚本。 ### 4.2 互斥不变量(仅临时工单手动创建/编辑) 对 `work_order_type = temporary` 的手动写入: 1. **系统产品**:`cell_product_id` 必填且在本租户存在;`external_target_code` 必须为空(写库时清空) 2. **外部编号**:`external_target_code` 必填(trim 后非空且 ≤64);`cell_product_id` 必须为空(写库时清空) 3. 二者不可同时有值;亦不可同时为空 入库/出库工单、生产派发临时质检:**不应用上述外部编号写入路径**(派发仍只写既有 `cell_product_id` 逻辑)。 ### 4.3 API 契约 **创建/更新请求(临时):** - 保留 `cellProductId`(可选) - 新增 `externalTargetCode`(可选) - 服务端按互斥规则校验并归一化(另一侧置空) **列表/详情响应:** - 继续返回 `cellProductId` / `cellProductCode` / `cellProductName` / 类型等(有关联时 enrich) - 新增 `externalTargetCode` - 不强制返回 `qcTargetSource`;前端可用字段有无推导 **列表 keyword:** 临时质检列表现有 keyword 仅匹配工单号;本期在临时工单(及通用列表在 `work_order_type=temporary` 或未限定类型时)keyword 条件中增加 `external_target_code` 模糊匹配。 ## 5. 前端交互(方案 A) 文件焦点:`web-admin/src/views/quality-inspection/qc-work-order/index.vue` 新增/编辑弹窗。 1. **来源类型**:二选一(系统细胞产品 / 外部科研编号) 2. **质检对象**: - 系统:现有远程搜索下拉(`fetchCellProductList`) - 外部:单行输入,placeholder「请输入外部编号」 3. **备注**:不变 行为: - 新增默认「系统细胞产品」 - 编辑:有 `cellProductId` → 系统并回填;有 `externalTargetCode` → 外部并回填 - 切换来源时清空另一侧已填值 - 提交只带当前来源字段;另一侧传空 前端校验与后端错误文案对齐:「请选择质检对象」「请填写外部编号」。 ## 6. 列表 / 详情展示 | 场景 | 系统产品 | 外部编号 | |---|---|---| | 卡片主标题 `resolveTemporaryWorkOrderCardTitle` | `cellProductCode` | `externalTargetCode` | | 卡片 meta(产品名称/类型等) | 照旧 | 增加「质检对象」展示外部编号;产品名称/类型显示 `—` | | 详情 `buildTemporaryViewSections` | 产品编码/名称/类型等 | 「质检对象」= 外部编号 + Tag「外部」;产品字段 `—` | | 任务子列表等同类「质检对象」展示 | 同步兜底外部编号 | 同上 | 列表卡片**不强制**加「外部」Tag(避免多色);详情用 Tag 区分。 ## 7. 改动面清单 | 层 | 内容 | |---|---| | SQL | `docs/sql/` 增加 `external_target_code` | | Backend | `models` / `schemas` / `crud`:`create_temp_qc_work_order`、`update_qc_work_order`、列表 `_row_to_dict` / enrich、keyword | | Frontend API | `QcWorkOrder` 类型增加 `externalTargetCode` | | 弹窗 | `qc-work-order/index.vue` | | 卡片 | `qc-work-order-card-meta.ts`(标题 + temporaryFields) | | 详情 | `inbound-view-sections.ts` 中 `buildTemporaryViewSections`;相关任务子列表展示若有则一并 | ## 8. 明确不做 - 生产派发临时质检链路改造 - 外部编号唯一性、格式正则 - 自动创建细胞产品或事后关联回产品 - 入库/出库工单的质检对象模型变更 ## 9. 验收标准 1. 系统产品路径:行为与现网一致(选产品、建单、列表/详情展示产品信息) 2. 外部编号路径:可建单、可编辑;可切换来源;库中 `cell_product_id` 为空且 `external_target_code` 有值 3. 同一外部编号可创建多张临时工单 4. 列表卡片标题与详情可见外部编号 5. 生产派发临时质检回归无回归问题(链路代码未改或行为不变) ## 10. 风险与注意 - 历史临时工单均无 `external_target_code`,展示逻辑须兼容「仅有 cell_product_id」 - 编辑时从外部切到系统(或反向)须清空对侧字段,避免脏数据写入 - `_validate_cell_product_id` 不可再对「外部路径」强制必填;拆成按来源分支校验