日期: 2026-05-27
状态: 待审阅
父模块: 中试服务管理 → 出库放行审核
关联:openspec/changes/outbound-release-review、方案 A(独立弹窗 + 子表)
库存策略(已确认): 台账模式 — 出库物料准备界面仅记录,不联动库存
biz_outbound_release_review。针对每条输注计划,提供「出库物料准备」界面,用于登记拟出库内容(台账),保存时不改变细胞产品状态、不扣质检物料库存:
| 区块 | 数据来源 | 保存行为 |
|---|---|---|
| 出库细胞 | 细胞产品库勾选 | 写入关联 ID + 字段快照,不改 biz_cell_product |
| 使用的物料 | 质检物料库勾选 + 用量 | 写入关联 ID + 用量 + 快照,不扣 stock_qty |
| 其他纸质材料 | 附件上传 | 仅存 URL |
biz_qc_material_usage)。biz_pilot_delivery_material)合并或自动同步。| 项 | 决策 |
|---|---|
| UI 定位 | 「出库物料准备」— 台账登记,非库存事务 |
| UI | 列表操作列「出库物料」→ OutboundReleaseMaterialDialog.vue |
| 数据 | 1 主表 + 2 子表;纸质附件放主表 |
| 保存语义 | 全量替换:软删旧子表行 → 写入新行 + 主数据快照 |
| 库存 | 零联动;前端可展示当前库存/状态作参考,保存时不校验库存是否足够 |
| 复杂度 | 无 revert/apply、无 qc_material_usage 扩展、无库位占用变更 |
SQL 文件:docs/sql/outbound_release_material.sql
biz_outbound_release_material(主表,1:1 输注计划)CREATE TABLE `biz_outbound_release_material` (
`id` varchar(64) NOT NULL COMMENT '主键ID',
`infusion_schedule_id` varchar(64) NOT NULL COMMENT '输注计划ID',
`paper_attachments` varchar(4000) DEFAULT NULL COMMENT '其他纸质材料附件(逗号分隔URL)',
`tenant_no` varchar(64) NOT NULL DEFAULT 'zkxw',
`order_num` int(11) DEFAULT NULL,
`remark` varchar(512) DEFAULT NULL,
`create_by` varchar(64) DEFAULT NULL,
`create_dept_id` varchar(64) NOT NULL DEFAULT '',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_by` varchar(64) DEFAULT NULL,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`del_flag` tinyint(4) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_orm_schedule` (`infusion_schedule_id`, `del_flag`),
KEY `idx_orm_tenant` (`tenant_no`, `del_flag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='出库放行-出库物料准备主表';
biz_outbound_release_cell(出库细胞行)CREATE TABLE `biz_outbound_release_cell` (
`id` varchar(64) NOT NULL,
`material_id` varchar(64) NOT NULL COMMENT '关联 biz_outbound_release_material.id',
`infusion_schedule_id` varchar(64) NOT NULL COMMENT '冗余,便于查询',
`cell_product_id` varchar(64) NOT NULL COMMENT '细胞产品ID',
`product_code` varchar(128) DEFAULT NULL COMMENT '保存时快照',
`product_name` varchar(200) DEFAULT NULL,
`product_type_name` varchar(100) DEFAULT NULL,
`spec_name` varchar(100) DEFAULT NULL,
`passage` varchar(32) DEFAULT NULL,
`batch_no` varchar(64) DEFAULT NULL,
`storage_slot_name` varchar(200) DEFAULT NULL,
`product_status` varchar(32) DEFAULT NULL COMMENT '保存时状态快照(只读展示)',
`tenant_no` varchar(64) NOT NULL DEFAULT 'zkxw',
`order_num` int(11) DEFAULT NULL,
`remark` varchar(512) DEFAULT NULL,
`create_by` varchar(64) DEFAULT NULL,
`create_dept_id` varchar(64) NOT NULL DEFAULT '',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_by` varchar(64) DEFAULT NULL,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`del_flag` tinyint(4) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_orc_schedule_product` (`infusion_schedule_id`, `cell_product_id`, `del_flag`),
KEY `idx_orc_product` (`cell_product_id`, `del_flag`),
KEY `idx_orc_material` (`material_id`, `del_flag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='出库放行-出库细胞(台账)';
不需要
product_status_before/storage_slot_id回滚字段。
biz_outbound_release_qc_material(质检物料行)CREATE TABLE `biz_outbound_release_qc_material` (
`id` varchar(64) NOT NULL,
`material_id` varchar(64) NOT NULL COMMENT '关联 biz_outbound_release_material.id',
`infusion_schedule_id` varchar(64) NOT NULL,
`qc_material_id` varchar(64) NOT NULL,
`qty` decimal(18,4) NOT NULL COMMENT '计划用量(台账)',
`material_code` varchar(64) DEFAULT NULL,
`material_name` varchar(200) DEFAULT NULL,
`spec_model` varchar(200) DEFAULT NULL,
`unit` varchar(32) DEFAULT NULL,
`tenant_no` varchar(64) NOT NULL DEFAULT 'zkxw',
`order_num` int(11) DEFAULT NULL,
`remark` varchar(512) DEFAULT NULL,
`create_by` varchar(64) DEFAULT NULL,
`create_dept_id` varchar(64) NOT NULL DEFAULT '',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_by` varchar(64) DEFAULT NULL,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`del_flag` tinyint(4) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_orqm_schedule_material` (`infusion_schedule_id`, `qc_material_id`, `del_flag`),
KEY `idx_orqm_material` (`material_id`, `del_flag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='出库放行-质检物料(台账)';
不关联
biz_qc_material_usage;不扩展source_type。
save_outbound_release_material(schedule_id, payload):
1. 校验输注计划存在 + 租户 + 数据权限
2. 校验 payload:
- cells 内 cell_product_id 不重复
- qcMaterials 内 material_id 不重复
- qty > 0
- 关联主数据存在且未软删(产品/物料)
3. upsert 主表(paper_attachments、remark)
4. 软删本 schedule 下旧 cell / qc_material 子行
5. 对每个 cell_product_id:读主数据 → 写快照 → insert 子行
6. 对每个 qc_material + qty:读主数据 → 写快照 → insert 子行
7. db.commit()
明确不做:
cell_product.update / 不改 product_statusoccupancy_svc.remove_by_itemqc_material_usage.deduct_*| 规则 | 说明 |
|---|---|
| 同计划细胞不重复 | 同一 infusion_schedule_id 下 cell_product_id 唯一 |
| 同计划物料不重复 | 同一 schedule 下 qc_material_id 唯一 |
| 跨计划可重复引用 | 不同输注计划可登记同一细胞/物料(台账互不排斥) |
| 主数据存在性 | 保存时产品/物料须存在;已软删的主数据不允许新增引用 |
| 细胞状态 | 不限制可选状态;选择器展示状态供人判断,保存时不拦截 |
TaskInputEnhancedTable 选择弹窗模式)。前缀:/web/admin/pilot-release-reviews
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /{scheduleId}/outbound-materials |
获取出库物料准备(主表 + 细胞行 + 质检行) |
| PUT | /{scheduleId}/outbound-materials |
全量保存(仅写台账) |
PUT Body:
{
"paperAttachments": "url1,url2",
"remark": "",
"cells": [{ "cellProductId": "..." }],
"qcMaterials": [{ "materialId": "...", "qty": 1.5, "remark": "" }]
}
cells / qcMaterials 可为空数组。GET .../detail 响应增加 outboundMaterial 域(查看弹窗只读)。TaskInputEnhancedTable.vueqc-task/index.vue 物料使用区(去掉库存不足拦截)OutboundReleaseReviewDialog.vue 卡片上传| 文件 | 改动 |
|---|---|
outbound-release-review/index.vue |
操作列「出库物料」 |
OutboundReleaseMaterialDialog.vue |
新建 |
OutboundReleaseViewDialog.vue |
Section「出库物料准备」只读 |
api/outbound-release-review.ts |
fetch/save API |
| 文件 | 职责 |
|---|---|
app/crud/outbound_release_material.py |
查询、全量 save、主数据快照 |
app/schemas/outbound_release_material.py |
Pydantic |
app/api/outbound_release_review.py |
两个端点 |
app/models/models.py |
三个 ORM 模型 |
不修改: qc_material_usage.py、cell_product.py 库存/状态逻辑。
| 场景 | HTTP | 说明 |
|---|---|---|
| 细胞/物料不存在 | 400 | ID 无效或已删除 |
| 同计划重复勾选 | 400 | 同一产品/物料不可重复 |
| qty ≤ 0 | 400 | 用量须大于 0 |
| 输注计划不存在 | 404 | — |
biz_cell_product 状态/库位不变;biz_qc_material.stock_qty 不变。outbound-release-material-api: GET/PUT outbound-materials(台账 CRUD)outbound-release-material-ui: 出库物料准备弹窗 + 查看 Section| 项 | 人天 |
|---|---|
| SQL + Model + CRUD | 1.0 |
| API + 详情聚合 | 0.5 |
| 前端弹窗 + 查看 | 1.5 |
| 联调 | 0.5 |
| 合计 | ~3.5 |
| 版本 | 策略 | 说明 |
|---|---|---|
| v0(讨论稿) | B 真实出库 | 保存时改状态 + 扣库存 + 回滚 |
| v1(当前) | 台账模式 | 出库物料准备界面仅记录;与交付清单类似,不联动库存 |
若后续需要在「审核通过」或独立「确认出库」节点做真实出库,应新建 spec,与本台账表通过 infusion_schedule_id 衔接,避免在本界面混入库存事务。