2026-08-19-storage-release-dual-gate-design.md 16 KB

入库放行审核 · 生产/质检双闸门

日期:2026-08-19
状态:待审阅
模块:细胞存储 / 生产管理 / 质检管理 → 入库放行审核
关联:

  • docs/superpowers/specs/2026-05-23-storage-release-review-design.md
  • docs/superpowers/specs/2026-07-16-storage-release-review-tabs-design.md
  • docs/superpowers/specs/2026-07-29-storage-release-pending-ready-filter-design.md
    界面模式:P22(审核列表)
    参考页:web-admin/src/views/quality-inspection/storage-release-review/index.vue

1. 背景与目标

现状

入库放行审核挂在 市场 → 细胞存储。一条记录只有一组审核字段;任意有权限的人提交一次「通过」即审核通过,再点「样本入库」才把样本标成已入库。不是会签,也不是多级审批。

需求

客户要求 生产主管与质检主管都审批通过后,才可以入库。

目标

  1. 同一条 biz_storage_release_review 上拆成 生产侧 / 质检侧 两套独立结论。
  2. 三个菜单入口共用同一页面:细胞存储只读总览;生产只审生产侧;质检只审质检侧。
  3. 两侧都「通过」后 自动入库;任一侧改成「不通过」且当前已入库时 直接回退出库(不弹窗)。
  4. 生产、质检页保留「批量入库」,仅补「两侧已通过且尚未入库」。
  5. 历史单人审核结论迁到质检侧;已入库记录保持已入库。

范围外

  • 不上工作流引擎、不加第三人审批节点。
  • 不新建第二张审核表、不复制两套列表数据。
  • 不改细胞产品库位占用;回退出库 不 动库位里的细胞产品。
  • 不改变出库放行审核。
  • 不在本需求中自动给角色授权新菜单(上线后由管理员在角色管理中勾选)。

2. 需求确认记录

维度 决定
数据模型 一条审核记录、两套结论,不拆表
细胞存储菜单 只读总览:看两边结论 + 入库状态;不能审、不能入库
生产 / 质检菜单 各审各侧;两边都能看到对侧结论
入库主路径 两侧都 tg 后自动入库
批量入库 仅生产、质检页保留;仅「双通过且待入库」
单条「样本入库」 去掉(自动入库为主,补点走批量)
改结论 两侧可随时改自己的结论
已入库后改不通过 不弹窗,直接回退出库
回退范围 放行记录改回待入库;采集样本 yrk → jcz;细胞产品库位不动
再次双通过 再自动入库一次
历史未入库「通过」 只记质检侧;生产侧待审
历史已入库 质检记通过、生产待审、入库状态保持已入库
谁先审 无顺序要求
同一人两边都审 系统不禁;靠角色菜单隔离。超管两边都能进

3. 入口与权限

三个入口共用 web-admin/src/views/quality-inspection/storage-release-review/index.vue,用路由 props.reviewRole 区分能力。

入口 路由 path menuCode reviewRole 审核 批量入库
市场 → 细胞存储 /market/cell-storage/storage-release-review biz:storageReleaseReview:list(沿用) overview 否 否
生产 → 生产管理 /production-group/production/storage-release-review production:storageReleaseReview:list production 仅生产侧 是
质检 → 质检管理 /quality-group/quality-manage/storage-release-review quality:storageReleaseReview:list qc 仅质检侧 是

现有质检下隐藏 redirect(QualityInspectionStorageReleaseReviewRedirect → 细胞存储)改为真实菜单项,不再跳转。

sqxp.ts 与 backend/app/api/menu.py 的 STATIC_MENU_TREE 必须同步。

接口鉴权

操作 允许的菜单
列表 / 详情 上述三个 menuCode 任一
提交审核 / 批量审核 仅 production:storageReleaseReview:list 或 quality:storageReleaseReview:list
批量入库 同上(细胞存储不可调)

请求体必须带 reviewSide:production 或 qc。

  • reviewSide=production:用户必须有生产菜单(或超管)。
  • reviewSide=qc:用户必须有质检菜单(或超管)。
  • 细胞存储菜单不能提交审核或入库。
  • 不信任前端用 reviewRole 代替 reviewSide;后端以 reviewSide + 菜单校验为准。

4. 状态机

两侧未齐(汇总为空)
        │
        │  两侧都 tg
        ▼
    自动入库(storage_status=yrk)
        │
        │  任一侧改为 btg(不弹窗)
        ▼
    回退出库(storage_status=drk)
        │
        │  两侧再次都 tg
        ▼
    再自动入库一次

汇总字段 review_conclusion(后端维护,兼容短信、旧查询):

生产结论 质检结论 汇总
tg tg tg
任一侧 btg (另一侧任意) btg
其余(含一侧空) 空(待齐)

5. 数据模型

仍用表 biz_storage_release_review。原 review_* 改为 汇总快照(随两侧提交重算),不再表示「某一个人审过」。

新增列(紧挨原审核字段之后、入库字段之前):

ALTER TABLE `biz_storage_release_review`
  ADD COLUMN `qc_review_conclusion`   VARCHAR(16)   DEFAULT NULL COMMENT '质检侧结论 tg/btg/NULL待审' AFTER `review_time`,
  ADD COLUMN `qc_review_remark`       VARCHAR(512)  DEFAULT NULL COMMENT '质检侧审核备注' AFTER `qc_review_conclusion`,
  ADD COLUMN `qc_review_attachments`  VARCHAR(4000) DEFAULT NULL COMMENT '质检侧审核附件(逗号分隔URL)' AFTER `qc_review_remark`,
  ADD COLUMN `qc_review_by`           VARCHAR(64)   DEFAULT NULL COMMENT '质检侧审核人ID' AFTER `qc_review_attachments`,
  ADD COLUMN `qc_review_by_name`      VARCHAR(64)   DEFAULT NULL COMMENT '质检侧审核人姓名' AFTER `qc_review_by`,
  ADD COLUMN `qc_review_time`         DATETIME      DEFAULT NULL COMMENT '质检侧审核时间' AFTER `qc_review_by_name`,
  ADD COLUMN `prod_review_conclusion` VARCHAR(16)   DEFAULT NULL COMMENT '生产侧结论 tg/btg/NULL待审' AFTER `qc_review_time`,
  ADD COLUMN `prod_review_remark`     VARCHAR(512)  DEFAULT NULL COMMENT '生产侧审核备注' AFTER `prod_review_conclusion`,
  ADD COLUMN `prod_review_attachments` VARCHAR(4000) DEFAULT NULL COMMENT '生产侧审核附件(逗号分隔URL)' AFTER `prod_review_remark`,
  ADD COLUMN `prod_review_by`         VARCHAR(64)   DEFAULT NULL COMMENT '生产侧审核人ID' AFTER `prod_review_attachments`,
  ADD COLUMN `prod_review_by_name`    VARCHAR(64)   DEFAULT NULL COMMENT '生产侧审核人姓名' AFTER `prod_review_by`,
  ADD COLUMN `prod_review_time`       DATETIME      DEFAULT NULL COMMENT '生产侧审核时间' AFTER `prod_review_by_name`;

索引:增加 (tenant_no, qc_review_conclusion, prod_review_conclusion, del_flag),供 Tab / 筛选使用。原 idx_srr_status 保留(汇总结论仍用于短信等)。

DDL 与数据迁移脚本放在 docs/sql/(独立变更 SQL,并同步 docs/sql/zkxw.sql 表结构)。

ORM:BizStorageReleaseReview 增加对应字段。_row_to_dict 为可读字段唯一来源,须输出两侧字段 + 汇总字段。Create/Update schema 与前端 formData 按 docs/dev-field-consistency.md 对齐。

原 review_by / review_by_name / review_time / review_remark / review_attachments:提交后按 后一次导致汇总变化的那一侧 回填汇总人时信息(取该侧审核人/时间/备注/附件)。列表不再展示这组汇总人字段;查看弹窗以两侧字段为准。短信、协议卡等旧读取方仍可读汇总 review_conclusion。

6. 入库与回退

抽公共函数,供自动入库与批量入库共用。整次提交(写结论 + 可能的入库/回退)在同一事务;失败整单回滚。

6.1 自动入库(两侧均为 tg 且 storage_status=drk)

与现网 store_sample 一致:

  • storage_status=yrk,写入 storage_by / storage_by_name / storage_time(当前提交人;若由批量入库触发则为操作人)。
  • reception_source=cell_storage:按 tenant_no + sample_code 更新 biz_protocol_sample.sample_status='yrk'、storage_in_date。
  • 科研捐赠样本:现网入库不改捐赠样本状态,本需求保持不变。
  • 不写库位、不改细胞产品。

6.2 回退出库(任一侧变为 btg 且 storage_status=yrk)

不弹窗,直接执行:

  • storage_status=drk;storage_by / storage_by_name / storage_time 置空。
  • 采集协议样本:仅当 sample_status='yrk' 时改为 jcz(检测中);yzf 等其它状态不改。storage_in_date 清空。
  • 科研捐赠样本状态不改(与入库对称)。
  • 细胞产品、库位占用一律不动。

6.3 批量入库

  • 仅处理:prod_review_conclusion='tg' 且 qc_review_conclusion='tg' 且 storage_status='drk'。
  • 不满足条件的 id 计入 fail,不中断其它 id。
  • 细胞存储入口不展示、不调用该接口。

7. API

前缀保持 /web/admin/storage-release-reviews。

7.1 列表 GET /storage-release-reviews

新增/调整查询参数:

参数 说明
reviewSide overview / production / qc。决定 reviewPhase 语义。缺省按 overview
reviewPhase pending / reviewed
prodReviewConclusion 生产侧 tg / btg
qcReviewConclusion 质检侧 tg / btg
reviewConclusion 仍过滤 汇总 结论(兼容);本页筛选改为两侧下拉后,列表页可不再传此参数
storageStatus / keyword / receptionSource / readyForReviewOnly 保持现网

reviewPhase 按入口:

reviewSide pending reviewed
production 生产侧结论为空 生产侧已有结论
qc 质检侧结论为空 质检侧已有结论
overview 至少一侧结论为空 两侧都已有结论

待审核默认「仅展示双工单侧就绪」(readyForReviewOnly)规则 不变;「展示全部待审核」复选框保留。

列表项增加:prodReviewConclusion、qcReviewConclusion 及对应 Label、两侧审核人/时间(详情/查看用;列表列可不展示人)。保留汇总 reviewConclusion。

7.2 详情 GET /storage-release-reviews/{id}

review 对象带两侧完整字段 + 汇总 + 入库字段。证据域(协议/运输/接收/质检/生产)不变。

7.3 提交 PUT /storage-release-reviews/{id}/review

Body:

{
  "reviewSide": "production",
  "reviewConclusion": "tg",
  "reviewRemark": "",
  "reviewAttachments": ""
}

只更新对应侧字段,然后重算汇总并触发自动入库或回退。

7.4 批量审核 PUT /storage-release-reviews/batch-review

在现有 ids + 结论/备注/附件上增加必填 reviewSide。逐条走与单条相同的提交逻辑。

7.5 单条入库 PUT /.../store

接口可保留供内部/自动入库复用,但 前端不再提供单条「样本入库」按钮。若保留对外接口,门槛改为两侧都 tg 且待入库;无生产/质检菜单则 403。

7.6 批量入库 PUT /.../batch-store

门槛改为两侧都 tg 且待入库。无生产/质检菜单则 403。

8. 前端 UI

页面仍对照现网列表骨架(filter-block → 工具栏 → list-body → 分页)。标题保持「审核列表」(App.vue panelTitleBarTextRules 若已登记则无需改文案)。

8.1 按 reviewRole 的按钮

能力 overview production / qc
批量审核 隐藏 显示;本侧待审或已审均可改
批量入库 隐藏 所选行均为双 tg 且 drk 时可点
行:查看 有 有
行:审核 无 有(提交本侧)
行:样本入库 无 无

8.2 列表列

  • 原「审核结论」拆成两列 Tag:生产结论、质检结论。空 → info「待审核」;tg → success「通过」;btg → danger「不通过」。
  • 去掉列表「审核人」「审核时间」列(改到查看弹窗)。
  • 「入库状态」列保留。

筛选:原「审核结论」改为两个下拉「生产结论」「质检结论」(通过 / 不通过 / 清空=全部)。入库状态、关键词、协议类别不变。

8.3 审核弹窗

证据区(接收 / 质检 / 生产)不变。表单只编辑本侧结论、备注、附件。对侧结论用只读 el-tag 展示(人、时间可一并只读)。

标题区分:「生产入库放行审核」/「质检入库放行审核」;批量时仍为「批量审核(N 条)」。

8.4 查看弹窗

原「放行审核」一节拆为:

  1. 质检放行:结论 Tag、人、时间、备注、附件
  2. 生产放行:同上
  3. 入库:入库状态 Tag、入库人、入库时间

8.5 协议/样本卡复用

sample-storage-release-info 与 get_storage_release_map_for_samples 改为展示两侧结论 + 入库状态,避免协议查看仍像「单人已通过」。

9. 历史数据迁移

一次性 SQL(在 ALTER 之后执行):

  1. 旧 review_conclusion 非空:复制到质检侧(qc_review_* ← review_*)。
  2. 生产侧全部保持空。
  3. 不改 storage_status、入库人、入库时间。
  4. 按第 4 节规则重算汇总 review_conclusion:
    • 两侧都 tg → tg
    • 任一侧 btg → btg
    • 否则 NULL

因此:

  • 旧「通过」未入库 → 质检通过、生产待审、待入库、汇总空。生产审过之后才自动入库。
  • 旧「通过」已入库 → 质检通过、生产待审、仍已入库、汇总空。总览允许「已入库 + 生产待审」。生产之后若改 btg,按新规则直接回退。
  • 旧「不通过」 → 质检不通过、生产待审、汇总 btg。

脚本须可重复执行:仅当 qc_review_conclusion 为空且旧 review_conclusion 非空时拷贝,避免二次覆盖新审核。

10. 其它读取方

读取方 处理
样本入库短信(review_conclusion='btg' 或已入库) 继续用汇总 + storage_status;语义仍成立
储存证等依赖样本 sample_status='yrk' 随自动入库/回退变化;回退后证书资格按现网「已入库」规则自然失效
出库放行审核 不改

11. 测试要点

  1. 质检先过、生产后过 → 自动入库;采集样本变为 yrk。
  2. 生产先过、质检后过 → 同样自动入库。
  3. 已入库后任一侧改 btg → 放行回 drk,采集样本 yrk→jcz,库位产品仍在。
  4. 两侧再都改回 tg → 再次自动入库。
  5. 细胞存储入口无审核/入库按钮,调审核 API 返回 403。
  6. 生产入口不能改质检侧字段(即使 body 乱传)。
  7. 批量入库跳过未双通过或已入库行。
  8. 迁移后:已入库旧数据保持 yrk 且生产待审;未入库旧通过仅质检有结论。
  9. 待审核就绪过滤、作废隐藏规则仍生效。

12. 文件清单(实现时)

区域 文件
SQL docs/sql/ 变更脚本 + docs/sql/zkxw.sql 表结构
模型 / schema / CRUD / API models.py、schemas/storage_release_review.py、crud/storage_release_review.py、api/storage_release_review.py
菜单 backend/app/api/menu.py、web-admin/src/router/modules/sqxp.ts
前端页 storage-release-review/index.vue、StorageReleaseReviewDialog.vue、StorageReleaseViewDialog.vue
API 类型 web-admin/src/api/storage-release-review.ts
协议卡 sample-storage-release-info、CRUD 摘要 map
单测 backend/tests/:汇总重算、自动入库、回退、Tab 过滤、迁移拷贝条件

实现后按 AGENTS.md 增量更新对应 graphify 图谱。