For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 在质检任务菜单下新增"入库放行审核"功能,实现样本级别的放行审核和入库操作。
Architecture: 新建独立审核表 biz_storage_release_review,在样本接收完成时自动创建审核记录。后端新建完整的 Model → Schema → CRUD → API 路由链路。前端参照 protocol-audit 模式构建列表页 + 查看弹窗 + 审核弹窗。
Tech Stack: FastAPI + SQLAlchemy + Pydantic v2(后端),Vue 3 + Element Plus + TypeScript(前端)
Design Spec: docs/superpowers/specs/2026-05-23-storage-release-review-design.md
| 操作 | 文件路径 | 职责 |
|---|---|---|
| 新增 | docs/sql/biz_storage_release_review.sql |
DDL + 菜单 SQL |
| 修改 | backend/app/models/models.py |
新增 BizStorageReleaseReview 模型 |
| 新增 | backend/app/schemas/storage_release_review.py |
Pydantic schemas |
| 新增 | backend/app/crud/storage_release_review.py |
CRUD + 聚合查询 |
| 新增 | backend/app/api/storage_release_review.py |
API 路由 |
| 修改 | backend/app/api/__init__.py |
注册新路由 |
| 修改 | backend/app/main.py |
注册新路由 |
| 修改 | backend/app/crud/sample_reception.py |
接收完成时自动创建审核记录 |
| 新增 | web-admin/src/api/storage-release-review.ts |
前端 API 模块 |
| 新增 | web-admin/src/views/quality-inspection/storage-release-review/index.vue |
列表页 |
| 新增 | web-admin/src/views/quality-inspection/storage-release-review/StorageReleaseViewDialog.vue |
查看弹窗 |
| 新增 | web-admin/src/views/quality-inspection/storage-release-review/StorageReleaseReviewDialog.vue |
审核弹窗 |
| 修改 | web-admin/src/router/modules/sqxp.ts |
添加路由 |
| 修改 | web-admin/src/utils/status-tag-registry.ts |
注册状态标签 |
Files:
Create: docs/sql/biz_storage_release_review.sql
[ ] Step 1: 创建 SQL 文件
创建 docs/sql/biz_storage_release_review.sql,包含建表 DDL 和菜单插入语句:
-- 入库放行审核表
CREATE TABLE `biz_storage_release_review` (
`id` VARCHAR(64) NOT NULL COMMENT '主键ID',
`sample_code` VARCHAR(64) NOT NULL COMMENT '样本编码(关联键)',
`reception_source` VARCHAR(32) NOT NULL COMMENT '来源:cell_storage=采集/research_donation=捐赠',
`protocol_id` VARCHAR(64) DEFAULT NULL COMMENT '协议单ID',
`reception_id` VARCHAR(64) DEFAULT NULL COMMENT '样本接收记录ID',
`protocol_no` VARCHAR(64) DEFAULT NULL COMMENT '协议编号',
`sample_name` VARCHAR(128) DEFAULT NULL COMMENT '样本名称',
`review_conclusion` VARCHAR(16) DEFAULT NULL COMMENT '审核结论:tg=通过/btg=不通过/NULL=待审核',
`review_remark` VARCHAR(512) DEFAULT NULL COMMENT '审核备注',
`review_attachments` VARCHAR(4000) DEFAULT NULL COMMENT '审核附件(逗号分隔URL)',
`review_by` VARCHAR(64) DEFAULT NULL COMMENT '审核人ID',
`review_by_name` VARCHAR(64) DEFAULT NULL COMMENT '审核人姓名',
`review_time` DATETIME DEFAULT NULL COMMENT '审核时间',
`storage_status` VARCHAR(16) NOT NULL DEFAULT 'drk' COMMENT '入库状态:drk=待入库/yrk=已入库',
`storage_by` VARCHAR(64) DEFAULT NULL COMMENT '入库操作人ID',
`storage_by_name` VARCHAR(64) DEFAULT NULL COMMENT '入库操作人姓名',
`storage_time` DATETIME DEFAULT NULL COMMENT '入库时间',
`tenant_no` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '租户编号',
`order_num` INT(11) DEFAULT NULL COMMENT '排序号',
`remark` VARCHAR(512) DEFAULT NULL COMMENT '备注',
`create_by` VARCHAR(64) DEFAULT NULL COMMENT '创建人ID',
`create_dept_id` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` VARCHAR(64) DEFAULT NULL COMMENT '更新人ID',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`del_flag` TINYINT(4) NOT NULL DEFAULT 0 COMMENT '删除标记:0-正常 1-已删除',
PRIMARY KEY (`id`),
KEY `idx_srr_sample` (`tenant_no`, `sample_code`, `del_flag`),
KEY `idx_srr_protocol` (`tenant_no`, `protocol_id`, `del_flag`),
KEY `idx_srr_status` (`tenant_no`, `review_conclusion`, `storage_status`, `del_flag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='入库放行审核';
菜单 SQL 需要在 sys_menu 表中插入一条记录,参照现有质检任务子菜单的 ID 规则(如 70000000000000000000000000000008 为质检任务)。新菜单 ID 使用 70000000000000000000000000000011(递增),parent_id 为质量检测节点 70000000000000000000000000000001。
在开发环境的 MySQL 中执行 DDL,确认表创建成功。
Run: 检查表是否创建成功
SHOW CREATE TABLE biz_storage_release_review;
Expected: 表结构正确,索引存在
Files:
backend/app/models/models.py模板参照: 同文件中 BizProtocolAudit 类(line 743-761)
在 BizProtocolAudit 类定义之后(约 line 762)添加:
class BizStorageReleaseReview(Base):
"""入库放行审核 biz_storage_release_review"""
__tablename__ = "biz_storage_release_review"
id = Column(String(64), primary_key=True, comment="主键ID")
sample_code = Column(String(64), nullable=False, comment="样本编码")
reception_source = Column(String(32), nullable=False, comment="来源:cell_storage/research_donation")
protocol_id = Column(String(64), nullable=True, comment="协议单ID")
reception_id = Column(String(64), nullable=True, comment="样本接收记录ID")
protocol_no = Column(String(64), nullable=True, comment="协议编号")
sample_name = Column(String(128), nullable=True, comment="样本名称")
review_conclusion = Column(String(16), nullable=True, comment="审核结论:tg/btg/NULL")
review_remark = Column(String(512), nullable=True, comment="审核备注")
review_attachments = Column(String(4000), nullable=True, comment="审核附件(逗号分隔URL)")
review_by = Column(String(64), nullable=True, comment="审核人ID")
review_by_name = Column(String(64), nullable=True, comment="审核人姓名")
review_time = Column(DateTime, nullable=True, comment="审核时间")
storage_status = Column(String(16), nullable=False, default="drk", comment="入库状态:drk/yrk")
storage_by = Column(String(64), nullable=True, comment="入库操作人ID")
storage_by_name = Column(String(64), nullable=True, comment="入库操作人姓名")
storage_time = Column(DateTime, nullable=True, comment="入库时间")
tenant_no = Column(String(64), nullable=False, default="", comment="租户编号")
order_num = Column(Integer, nullable=True, comment="排序号")
remark = Column(String(512), nullable=True, comment="备注")
create_by = Column(String(64), nullable=True, comment="创建人ID")
create_dept_id = Column(String(64), nullable=False, default="", comment="创建人部门ID")
create_time = Column(DateTime, nullable=False, default=datetime.now, comment="创建时间")
update_by = Column(String(64), nullable=True, comment="更新人ID")
update_time = Column(DateTime, nullable=False, default=datetime.now, onupdate=datetime.now, comment="更新时间")
del_flag = Column(SmallInteger, nullable=False, default=0, comment="删除标记")
Run: cd backend && python -c "from app.models.models import BizStorageReleaseReview; print('OK')"
Expected: OK
Files:
backend/app/schemas/storage_release_review.py模板参照: 同目录下的其他 schema 文件,如 order.py(含 Base/Create/Update/Response 模式)
创建 backend/app/schemas/storage_release_review.py,包含:
"""入库放行审核 Pydantic schemas"""
from datetime import datetime
from typing import Any, Dict, List, Optional
from pydantic import BaseModel, Field
class StorageReleaseReviewBase(BaseModel):
sample_code: str = Field(..., description="样本编码")
reception_source: str = Field(..., description="来源:cell_storage/research_donation")
protocol_id: Optional[str] = Field(None, description="协议单ID")
reception_id: Optional[str] = Field(None, description="样本接收记录ID")
protocol_no: Optional[str] = Field(None, description="协议编号")
sample_name: Optional[str] = Field(None, description="样本名称")
class StorageReleaseReviewListQuery(BaseModel):
"""列表查询参数"""
page: int = Field(1, ge=1)
pageSize: int = Field(20, ge=1, le=200)
reception_source: Optional[str] = Field(None, description="来源筛选")
review_conclusion: Optional[str] = Field(None, description="审核结论筛选")
storage_status: Optional[str] = Field(None, description="入库状态筛选")
keyword: Optional[str] = Field(None, description="关键词搜索")
class ReviewSubmitBody(BaseModel):
"""审核提交请求体"""
review_conclusion: str = Field(..., description="审核结论:tg/btg")
review_remark: Optional[str] = Field(None, description="审核备注")
review_attachments: Optional[str] = Field(None, description="审核附件(逗号分隔URL)")
class BatchReviewBody(BaseModel):
"""批量审核请求体"""
ids: List[str] = Field(..., description="审核记录ID列表")
review_conclusion: str = Field(..., description="审核结论:tg/btg")
review_remark: Optional[str] = Field(None, description="审核备注")
review_attachments: Optional[str] = Field(None, description="审核附件(逗号分隔URL)")
class BatchStoreBody(BaseModel):
"""批量入库请求体"""
ids: List[str] = Field(..., description="入库记录ID列表")
class StorageReleaseReviewListItem(BaseModel):
"""列表项"""
id: str
sample_code: str
reception_source: str
protocol_no: Optional[str] = None
sample_name: Optional[str] = None
review_conclusion: Optional[str] = None
review_remark: Optional[str] = None
review_attachments: Optional[str] = None
review_by_name: Optional[str] = None
review_time: Optional[datetime] = None
storage_status: str = "drk"
storage_by_name: Optional[str] = None
storage_time: Optional[datetime] = None
create_time: Optional[datetime] = None
class StorageReleaseReviewDetail(BaseModel):
"""详情(含聚合信息)"""
review: Dict[str, Any] = {}
protocol_info: Optional[Dict[str, Any]] = None
transport_info: Optional[Dict[str, Any]] = None
reception_info: Optional[Dict[str, Any]] = None
qc_info: Optional[Dict[str, Any]] = None
production_info: Optional[Dict[str, Any]] = None
Run: cd backend && python -c "from app.schemas.storage_release_review import StorageReleaseReviewBase; print('OK')"
Expected: OK
Files:
backend/app/crud/storage_release_review.py模板参照:
backend/app/crud/qc_work_order.py — 跨表聚合查询模式(含 _RECEPTION_SOURCE_LABELS、urls_to_attachment_list)backend/app/crud/sample_reception.py — 租户隔离 + 分页模式(_page_payload)
[ ] Step 1: 创建 CRUD 文件
创建 backend/app/crud/storage_release_review.py,实现以下函数:
"""入库放行审核 CRUD"""
from __future__ import annotations
from datetime import datetime
from typing import Any, Dict, List, Optional
from sqlalchemy import and_, func, or_
from sqlalchemy.orm import Session
from app.core.utils import generate_uuid
from app.models.models import (
BizStorageReleaseReview,
BizSampleReception,
BizCollectionProtocol,
BizProtocolSample,
BizProtocolSampleTransport,
BizProtocolPartyCustomer,
BizQcWorkOrder,
BizQcTask,
BizProductionWorkOrder,
BizProductionTask,
SysUser,
)
from app.models.research_donation import (
BizResearchDonation,
BizResearchDonationSample,
BizResearchDonationSampleTransport,
BizResearchDonationParty,
)
核心函数清单:
create_review_from_reception(db, *, reception, protocol_no, sample_name, tenant_no, user_id, create_dept_id) -> BizStorageReleaseReview
list_reviews(db, *, tenant_no, page, page_size, reception_source=None, review_conclusion=None, storage_status=None, keyword=None) -> dict
biz_storage_release_review{list, total, page, pageSize, totalPages} 格式get_review_detail(db, review_id, tenant_no) -> dict
{review, protocol_info, transport_info, reception_info, qc_info, production_info}submit_review(db, review_id, *, review_conclusion, review_remark, review_attachments, tenant_no, user_id) -> dict
batch_submit_review(db, ids, *, review_conclusion, review_remark, review_attachments, tenant_no, user_id) -> dict
store_sample(db, review_id, *, tenant_no, user_id) -> dict
batch_store_samples(db, ids, *, tenant_no, user_id) -> dict
辅助函数:
_RECEPTION_SOURCE_LABELS = {"cell_storage": "采集协议", "research_donation": "捐赠协议"}
_CONCLUSION_LABELS = {"tg": "通过", "btg": "不通过"}
_STORAGE_STATUS_LABELS = {"drk": "待入库", "yrk": "已入库"}
Run: cd backend && python -c "from app.crud.storage_release_review import list_reviews; print('OK')"
Expected: OK
Files:
backend/app/api/storage_release_review.pybackend/app/api/__init__.pybackend/app/main.py模板参照: backend/app/api/sample_reception.py — 路由定义模式、_get_tenant_no、_get_current_user_id、success_response、error_response、_page_payload
创建 backend/app/api/storage_release_review.py,参照 sample_reception.py 的模式:
"""入库放行审核 API"""
from fastapi import APIRouter, Depends, Query
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.core.auth import require_admin_or_super_admin
from app.schemas.storage_release_review import (
ReviewSubmitBody,
BatchReviewBody,
BatchStoreBody,
)
from app.crud import storage_release_review as svc
# ... 导入辅助函数
router = APIRouter(prefix="/storage-release-reviews", tags=["入库放行审核"])
端点清单:
@router.get("")
async def list_storage_release_reviews(
page: int = Query(1), pageSize: int = Query(20),
reception_source: str = Query(None),
review_conclusion: str = Query(None),
storage_status: str = Query(None),
keyword: str = Query(None),
db: Session = Depends(get_db),
user: dict = Depends(require_admin_or_super_admin),
):
"""分页列表"""
...
@router.get("/{review_id}/detail")
async def get_storage_release_review_detail(
review_id: str,
db: Session = Depends(get_db),
user: dict = Depends(require_admin_or_super_admin),
):
"""详情(聚合全链路)"""
...
@router.post("/{review_id}/review")
async def submit_review(
review_id: str, body: ReviewSubmitBody,
db: Session = Depends(get_db),
user: dict = Depends(require_admin_or_super_admin),
):
"""提交/修改审核"""
...
@router.post("/batch-review")
async def batch_review(
body: BatchReviewBody,
db: Session = Depends(get_db),
user: dict = Depends(require_admin_or_super_admin),
):
"""批量审核"""
...
@router.post("/{review_id}/store")
async def store_sample(
review_id: str,
db: Session = Depends(get_db),
user: dict = Depends(require_admin_or_super_admin),
):
"""样本入库"""
...
@router.post("/batch-store")
async def batch_store(
body: BatchStoreBody,
db: Session = Depends(get_db),
user: dict = Depends(require_admin_or_super_admin),
):
"""批量入库"""
...
修改 backend/app/api/__init__.py:
from app.api.storage_release_review import router as storage_release_review_router
# 添加到 __all__ 列表
修改 backend/app/main.py:
# 导入行添加
from app.api import ..., storage_release_review_router
# 注册行添加
app.include_router(storage_release_review_router, prefix=settings.API_V1_PREFIX)
Run: cd backend && python -c "from app.main import app; routes = [r.path for r in app.routes if hasattr(r, 'path')]; print([r for r in routes if 'storage' in r])"
Expected: 包含 /api/storage-release-reviews 相关路径
启动后端服务,访问 /docs,确认"入库放行审核"分组下有 6 个端点。
Files:
backend/app/crud/sample_reception.py修改位置: create_sample_reception 函数中,conclusion == "js" 分支内(约 line 784-802),在创建 QC 工单和生产工单之后添加审核记录创建逻辑。
在 line 802(prod_wo_svc.create_production_work_order_from_reception(...) 之后)添加:
# 自动创建入库放行审核记录
from app.crud import storage_release_review as srr_svc
# 获取协议编号和样本名称
_protocol_no = ""
_sample_name = ""
if source == "cell_storage":
cp = (
db.query(BizCollectionProtocol)
.filter(BizCollectionProtocol.id == collection_protocol_id)
.first()
)
if cp:
_protocol_no = cp.protocol_no or ""
if sample:
_sample_name = sample.sample_name or sample.sample_code or ""
else:
rd = (
db.query(BizResearchDonation)
.filter(BizResearchDonation.id == _research_donation_id)
.first()
)
if rd:
_protocol_no = rd.protocol_no or ""
if dsample:
_sample_name = dsample.sample_name or dsample.sample_code or ""
srr_svc.create_review_from_reception(
db,
reception=obj,
protocol_no=_protocol_no,
sample_name=_sample_name,
tenant_no=tenant_no,
user_id=user_id,
create_dept_id=create_dept_id or "",
)
Run: cd backend && python -c "from app.crud.sample_reception import create_sample_reception; print('OK')"
Expected: OK
Files:
web-admin/src/api/storage-release-review.ts模板参照: web-admin/src/api/qc-task.ts 或 web-admin/src/api/collection-protocol.ts
创建 web-admin/src/api/storage-release-review.ts:
import request from '@/utils/request'
const BASE = '/api/admin/storage-release-reviews'
/** 分页列表 */
export function fetchStorageReleaseReviewList(params: {
page: number
pageSize: number
receptionSource?: string
reviewConclusion?: string
storageStatus?: string
keyword?: string
}) {
return request({ url: BASE, method: 'get', params })
}
/** 详情(聚合全链路) */
export function fetchStorageReleaseReviewDetail(id: string) {
return request({ url: `${BASE}/${id}/detail`, method: 'get' })
}
/** 提交/修改审核 */
export function submitStorageReleaseReview(
id: string,
data: {
reviewConclusion: string
reviewRemark?: string
reviewAttachments?: string
},
) {
return request({ url: `${BASE}/${id}/review`, method: 'post', data })
}
/** 批量审核 */
export function batchReviewStorageRelease(data: {
ids: string[]
reviewConclusion: string
reviewRemark?: string
reviewAttachments?: string
}) {
return request({ url: `${BASE}/batch-review`, method: 'post', data })
}
/** 样本入库 */
export function storeSample(id: string) {
return request({ url: `${BASE}/${id}/store`, method: 'post' })
}
/** 批量入库 */
export function batchStoreSample(data: { ids: string[] }) {
return request({ url: `${BASE}/batch-store`, method: 'post', data })
}
Files:
Modify: web-admin/src/utils/status-tag-registry.ts
[ ] Step 1: 添加入库放行审核的状态标签
在 status-tag-registry.ts 中新增:
// 入库放行审核结论
storageReleaseConclusion: {
tg: { label: '通过', type: 'success' },
btg: { label: '不通过', type: 'danger' },
} as Record<string, { label: string; type: string }>,
// 入库状态
storageStatus: {
drk: { label: '待入库', type: 'warning' },
yrk: { label: '已入库', type: 'success' },
} as Record<string, { label: string; type: string }>,
同时添加协议类别标签:
// 协议类别
receptionSource: {
cell_storage: { label: '采集协议', type: 'primary' },
research_donation: { label: '捐赠协议', type: 'success' },
} as Record<string, { label: string; type: string }>,
Files:
web-admin/src/views/quality-inspection/storage-release-review/index.vueweb-admin/src/router/modules/sqxp.ts模板参照(严格遵循):
web-admin/src/views/cell-storage/protocol-audit/index.vue — 列表页结构(筛选 + 多选 + 批量审核工具栏)web-admin/src/views/quality-inspection/qc-task/index.vue — 质检任务列表(状态标签、操作按钮条件显示)web-admin/src/views/system/unit/index.vue — 标准列表页模板UI 规范约束(来自 AGENTS.md):
panel-top + h2.title-bar-heading,显示绿色竖线type="primary"),不用 space-betweenfixed="right",min-width >= 260px<el-tag> + 语义颜色排序字段默认不展示
[ ] Step 1: 在 sqxp.ts 中添加路由
在质量检测(QualityInspection)路由组的 children 数组末尾(qc-material-usage 之后)添加:
{
id: '70000000000000000000000000000011',
name: 'QualityInspectionStorageReleaseReview',
path: 'storage-release-review',
component: '/quality-inspection/storage-release-review/index',
meta: {
title: '入库放行审核',
keepAlive: true,
menuCode: 'biz:storageReleaseReview:list',
}
},
创建 web-admin/src/views/quality-inspection/storage-release-review/index.vue。
核心结构:
筛选区域:
工具栏:
表格列(el-table):
组件交互:
StorageReleaseViewDialogStorageReleaseReviewDialogstoreSample API → 刷新列表StorageReleaseReviewDialog(批量模式)批量入库 → 确认弹窗 → 调用 batchStoreSample API → 刷新列表
[ ] Step 3: 验证页面加载
启动前端 dev server,访问 /#/quality-inspection/storage-release-review,确认页面渲染正常,表格显示。
Files:
web-admin/src/views/quality-inspection/storage-release-review/StorageReleaseViewDialog.vue模板参照:
web-admin/src/components/business/qc-task-view-dialog/index.vue — 多分区信息展示弹窗web-admin/src/components/business/sample-qc-info-cards/index.vue — QC 信息卡片组件web-admin/src/components/business/system-view-dialog/index.vue — 通用查看弹窗UI 规范约束:
label-position="top"backdrop-filter: none)使用 .dialog-form-layout 布局
[ ] Step 1: 创建查看弹窗组件
创建 StorageReleaseViewDialog.vue,props:
const props = defineProps<{
visible: boolean
reviewId: string
}>()
const emit = defineEmits(['update:visible'])
加载详情数据:调用 fetchStorageReleaseReviewDetail(reviewId)
内部分区(每个分区用 ▎ 标题栏样式):
SampleQcInfoCards 或自定义卡片展示工单+任务列表所有区域只读展示。
底部按钮:[关闭]
在 index.vue 中引入 StorageReleaseViewDialog,点击[查看]时传入 reviewId 并打开弹窗。
Files:
web-admin/src/views/quality-inspection/storage-release-review/StorageReleaseReviewDialog.vue模板参照:
web-admin/src/views/cell-storage/protocol/ProtocolAuditDialog.vue — 审核弹窗模式(结论 radio + 备注 textarea + 批量支持)web-admin/src/views/research-donation/list/DonationAuditDialog.vue — 捐赠审核弹窗(同模式)UI 规范约束:
label-position="top"附件上传使用卡片化布局
[ ] Step 1: 创建审核弹窗组件
创建 StorageReleaseReviewDialog.vue,props:
const props = defineProps<{
visible: boolean
reviewIds: string[] // 支持单条和批量
}>()
const emit = defineEmits(['update:visible', 'submitted'])
模式切换:
reviewIds.length === 1 → 单条模式:上方展示详情信息(同查看弹窗)+ 下方审核表单reviewIds.length > 1 → 批量模式:仅显示审核表单审核表单:
el-radio-group
el-radio value="tg" 通过el-radio value="btg" 不通过el-input type="textarea" :rows="3"ProtocolFinanceConfirmFields 的模式
#a7f3d0)底部按钮:[取消] [确定]
提交逻辑:
submitStorageReleaseReview(id, data)batchReviewStorageReview({ ids, ...data })成功后 emit submitted,父组件刷新列表
[ ] Step 2: 在列表页中引入并测试
在 index.vue 中引入 StorageReleaseReviewDialog,点击[审核]或[批量审核]时传入 reviewIds 并打开弹窗。
启动后端,通过 Swagger /docs 测试所有 6 个端点:
Run: ./scripts/update-graph.sh all
Expected: 图谱增量更新完成
git add docs/sql/biz_storage_release_review.sql
git add backend/app/models/models.py
git add backend/app/schemas/storage_release_review.py
git add backend/app/crud/storage_release_review.py
git add backend/app/api/storage_release_review.py
git add backend/app/api/__init__.py
git add backend/app/main.py
git add backend/app/crud/sample_reception.py
git add web-admin/src/api/storage-release-review.ts
git add web-admin/src/views/quality-inspection/storage-release-review/
git add web-admin/src/router/modules/sqxp.ts
git add web-admin/src/utils/status-tag-registry.ts
git commit -m "feat: add storage release review module (入库放行审核)"