docs: record dual-gate storage release review design.
Capture production and QC dual approval, three menu entry points, auto store and rollback, and historical data rules before implementation. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
cd8ab170ba
commit
e9942af37f
1 file changed
+323
@@ -0,0 +1,323 @@
|
||||
# 入库放行审核 · 生产/质检双闸门
|
||||
|
||||
> 日期: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_*` 改为 **汇总快照**(随两侧提交重算),不再表示「某一个人审过」。
|
||||
|
||||
新增列(紧挨原审核字段之后、入库字段之前):
|
||||
|
||||
```sql
|
||||
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:
|
||||
|
||||
```json
|
||||
{
|
||||
"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 图谱。
|
||||
Reference in new issue
Block a user