Files
zkxw/docs/superpowers/specs/2026-08-20-temporary-qc-external-target-code-design.md
T
zlwuandCursor e527b15221 docs: add temporary QC external target code design
Record the agreed approach for hand-entered external QC object codes on temporary work orders.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-20 10:27:58 +08:00

131 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 临时质检 · 外部质检对象编号(手写)设计
**日期:** 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` 不可再对「外部路径」强制必填;拆成按来源分支校验