docs: add cell storage protocol modules design for 2.2.6–2.2.10

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-05-13 17:48:22 +08:00
1 parent 058811ae77
commit 246ad2228e
153 files changed
+20578 -2040

No files matched your search

+20
View File
@@ -0,0 +1,20 @@
-- 组织管理初始化数据(需求 2.1.3)
-- 市场营销部门下设:采集部、临床部、中试服务部、支持中心、客服部
SET @marketing_id = UUID();
INSERT INTO sys_dept (id, parent_id, dept_name, dept_category_code, status, leader, leader_phone, tenant_no, order_num, create_dept_id, del_flag) VALUES
(UUID(), '0', '中科兴皖', 'gs', '1', NULL, NULL, 'zkxw', 0, '', 0),
(@marketing_id, '0', '市场营销部门', 'bm', '1', NULL, NULL, 'zkxw', 1, '', 0),
(UUID(), '0', '技术研发部', 'bm', '1', NULL, NULL, 'zkxw', 2, '', 0),
(UUID(), '0', '生产部', 'bm', '1', NULL, NULL, 'zkxw', 3, '', 0),
(UUID(), '0', '质量安全部', 'bm', '1', NULL, NULL, 'zkxw', 4, '', 0),
(UUID(), '0', '财务部', 'bm', '1', NULL, NULL, 'zkxw', 5, '', 0),
(UUID(), '0', '综合部', 'bm', '1', NULL, NULL, 'zkxw', 6, '', 0);
INSERT INTO sys_dept (id, parent_id, dept_name, dept_category_code, status, leader, leader_phone, tenant_no, order_num, create_dept_id, del_flag) VALUES
(UUID(), @marketing_id, '采集部', 'bm', '1', NULL, NULL, 'zkxw', 1, '', 0),
(UUID(), @marketing_id, '临床部', 'bm', '1', NULL, NULL, 'zkxw', 2, '', 0),
(UUID(), @marketing_id, '中试服务部', 'bm', '1', NULL, NULL, 'zkxw', 3, '', 0),
(UUID(), @marketing_id, '支持中心', 'bm', '1', NULL, NULL, 'zkxw', 4, '', 0),
(UUID(), @marketing_id, '客服部', 'bm', '1', NULL, NULL, 'zkxw', 5, '', 0);
+24
View File
@@ -0,0 +1,24 @@
-- ============================================================
-- 字典管理初始数据(sys_dict_type / sys_dict_data)
-- 执行前提:zkxw-requirements-v0.3-schema.sql 已建表
-- ============================================================
-- 字典类型
INSERT INTO sys_dict_type (id, dict_name, dict_type, tenant_no, order_num, create_dept_id, del_flag) VALUES
(UUID(), '组织类别编码', 'zzlbbm', 'zkxw', 1, '', 0),
(UUID(), '站点类型', 'zdlx', 'zkxw', 2, '', 0),
(UUID(), '站点业务范围', 'zdywfw', 'zkxw', 3, '', 0),
(UUID(), '部门状态', 'bmzt', 'zkxw', 4, '', 0);
-- 字典数据
INSERT INTO sys_dict_data (id, dict_label, dict_value, dict_type, tenant_no, order_num, create_dept_id, del_flag) VALUES
(UUID(), '公司', 'gs', 'zzlbbm', 'zkxw', 1, '', 0),
(UUID(), '分公司', 'fgs', 'zzlbbm', 'zkxw', 2, '', 0),
(UUID(), '部门', 'bm', 'zzlbbm', 'zkxw', 3, '', 0),
(UUID(), '中心基地', 'zxjd', 'zdlx', 'zkxw', 1, '', 0),
(UUID(), '样本采集', 'ybcj', 'zdywfw', 'zkxw', 1, '', 0),
(UUID(), '样本制备', 'ybzb', 'zdywfw', 'zkxw', 2, '', 0),
(UUID(), '质量检测', 'zljc', 'zdywfw', 'zkxw', 3, '', 0),
(UUID(), '细胞存储', 'xbcc', 'zdywfw', 'zkxw', 4, '', 0),
(UUID(), '停用', '0', 'bmzt', 'zkxw', 1, '', 0),
(UUID(), '正常', '1', 'bmzt', 'zkxw', 2, '', 0);
+24
View File
@@ -0,0 +1,24 @@
-- 2.1.6 菜单管理初始化数据
-- Web端根节点与移动端根节点,parent_id = 0
-- 根节点:Web端菜单、移动端菜单
INSERT INTO sys_menu (id, menu_name, parent_id, menu_type, path, component, visible, status, tenant_no, order_num, create_dept_id, del_flag) VALUES
('1', 'Web端菜单', '0', 'M', '/system', NULL, '1', '1', 'zkxw', 1, '', 0),
('2', '移动端菜单', '0', 'M', '/mini', NULL, '1', '1', 'zkxw', 2, '', 0);
-- Web端菜单 - 系统管理目录
INSERT INTO sys_menu (id, menu_name, parent_id, menu_type, path, component, perms, visible, status, tenant_no, order_num, create_dept_id, del_flag) VALUES
('100', '系统管理', '1', 'M', '/system', '/index/index', NULL, '1', '1', 'zkxw', 1, '', 0);
-- 系统管理子菜单
INSERT INTO sys_menu (id, menu_name, parent_id, menu_type, path, component, perms, visible, status, tenant_no, order_num, create_dept_id, del_flag) VALUES
('101', '租户管理', '100', 'C', 'tenant', '/system/tenant/index', 'system:tenant:list', '1', '1', 'zkxw', 1, '', 0),
('102', '字典管理', '100', 'C', 'dict', '/system/dict/index', 'system:dict:list', '1', '1', 'zkxw', 2, '', 0),
('103', '组织管理', '100', 'C', 'dept', '/system/dept/index', 'system:dept:list', '1', '1', 'zkxw', 3, '', 0),
('104', '用户管理', '100', 'C', 'user', '/system/user/index', 'system:user:list', '1', '1', 'zkxw', 4, '', 0),
('105', '角色管理', '100', 'C', 'role', '/system/role/index', 'system:role:list', '1', '1', 'zkxw', 5, '', 0),
('106', '菜单管理', '100', 'C', 'menu', '/system/menu/index', 'system:menu:list', '1', '1', 'zkxw', 6, '', 0),
('107', '站点管理', '100', 'C', 'site', '/system/site/index', 'system:site:list', '1', '1', 'zkxw', 7, '', 0),
('108', '职位管理', '100', 'C', 'post', '/system/post/index', 'system:post:list', '1', '1', 'zkxw', 8, '', 0),
('109', '物品单位', '100', 'C', 'unit', '/system/unit/index', 'system:unit:list', '1', '1', 'zkxw', 9, '', 0),
('110', '快递公司', '100', 'C', 'express', '/system/express/index', 'system:express:list', '1', '1', 'zkxw', 10, '', 0);
+28
View File
@@ -0,0 +1,28 @@
-- V0.3 角色初始数据
-- sys_role_data_scope_detail 建表语句
CREATE TABLE IF NOT EXISTS `sys_role_data_scope_detail` (
`id` varchar(64) NOT NULL COMMENT '主键ID',
`role_id` varchar(64) NOT NULL COMMENT '角色ID',
`scope_type` varchar(20) NOT NULL COMMENT '范围类型:dept/user',
`scope_value` varchar(100) NOT NULL COMMENT '范围值:部门ID/用户ID',
`tenant_no` varchar(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
`order_num` int 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` smallint NOT NULL DEFAULT '0' COMMENT '删除标记',
PRIMARY KEY (`id`),
KEY `idx_role_id` (`role_id`),
KEY `idx_tenant_no` (`tenant_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色自定义数据权限明细';
-- 角色初始数据
INSERT INTO sys_role (id, role_name, data_scope, status, tenant_no, order_num, create_dept_id, del_flag) VALUES
(UUID(), '超级管理员', '1', '1', 'zkxw', 1, '', 0),
(UUID(), '运营管理员', '1', '1', 'zkxw', 2, '', 0),
(UUID(), '采集专员', '2', '1', 'zkxw', 3, '', 0),
(UUID(), '市场支持专员', '2', '1', 'zkxw', 4, '', 0),
(UUID(), '质检专员', '2', '1', 'zkxw', 5, '', 0);
@@ -0,0 +1,26 @@
-- 站点、职位、物品单位、快递公司 初始化数据
-- 对应模型:SysSite, SysPost, BizItemUnit, BizExpressCompany
-- 站点
INSERT INTO sys_site (id, site_name, site_code, site_type, status, address, contact_name, contact_phone, tenant_no, order_num, create_dept_id, del_flag) VALUES
(UUID(), '中科兴皖中心基地', 'zkxw-zxjd', 'zxjd', '1', '', NULL, NULL, 'zkxw', 1, '', 0);
-- 职位
INSERT INTO sys_post (id, post_name, post_code, status, tenant_no, order_num, create_dept_id, del_flag) VALUES
(UUID(), '采集专员', 'cjzy', '1', 'zkxw', 1, '', 0),
(UUID(), '市场支持专员', 'sczczy', '1', 'zkxw', 2, '', 0),
(UUID(), '质检专员', 'zjzy', '1', 'zkxw', 3, '', 0);
-- 物品单位
INSERT INTO biz_item_unit (id, unit_code, unit_name, tenant_no, order_num, create_dept_id, del_flag) VALUES
(UUID(), 'g', '克', 'zkxw', 1, '', 0),
(UUID(), 'ml', '毫升', 'zkxw', 2, '', 0),
(UUID(), 'ge', '个', 'zkxw', 3, '', 0),
(UUID(), 'fen', '份', 'zkxw', 4, '', 0);
-- 快递公司
INSERT INTO biz_express_company (id, express_code, express_name, tenant_no, order_num, create_dept_id, del_flag) VALUES
(UUID(), 'sf', '顺丰速运', 'zkxw', 1, '', 0),
(UUID(), 'jd', '京东快递', 'zkxw', 2, '', 0),
(UUID(), 'zt', '中通快递', 'zkxw', 3, '', 0),
(UUID(), 'yt', '圆通速递', 'zkxw', 4, '', 0);
+24
View File
@@ -0,0 +1,24 @@
-- zkxw-init-user-data.sql
-- V0.3 用户管理初始化数据(测试用户)
-- 默认 admin 用户已在骨架 SQL 中创建,此处补充测试账号
-- 注意:密码需通过后端 API 创建以获得正确的 bcrypt hash
INSERT INTO sys_user (
id, dept_id, user_no, nick_name, email, phone_no, sex,
password, status, tenant_no, order_num,
create_dept_id, create_by, create_time, update_by, update_time, del_flag
) VALUES
(
REPLACE(UUID(),'-',''),
(SELECT id FROM sys_dept WHERE dept_name='市场营销部' AND del_flag=0 LIMIT 1),
'zhangsan', '张三', 'zhangsan@zkxw.com', '13800000001', '0',
'$2b$12$placeholder_hash_use_api_to_set', '1', 'zkxw', 2,
'', NULL, NOW(), NULL, NOW(), 0
),
(
REPLACE(UUID(),'-',''),
(SELECT id FROM sys_dept WHERE dept_name='市场营销部' AND del_flag=0 LIMIT 1),
'lisi', '李四', 'lisi@zkxw.com', '13800000002', '1',
'$2b$12$placeholder_hash_use_api_to_set', '1', 'zkxw', 3,
'', NULL, NOW(), NULL, NOW(), 0
);
@@ -0,0 +1,159 @@
# 细胞存储管理(2.2.6~2.2.10)— 实现设计(方案 C)
**依据**:`docs/中科兴皖需求V0.3.md` 菜单 2.2.6~2.2.10;数据模型 `docs/sql/zkxw-requirements-v0.3-schema.sql`(`biz_collection_protocol` 及其子表)。
**范围**:Web 管理端 `web-admin` + FastAPI `backend`;租户隔离与既有 `/web/admin` 响应风格保持一致。
---
## 1. 目标与非目标
### 1.1 目标
- 新增一级菜单 **细胞存储管理**,下挂 5 个页面,路由与目录命名已定稿。
- **最小闭环**:协议单列表/概要详情;审核(仅写审核表);财务收款确认与退费确认(限定状态流转);分期缴费预警(固定规则)。
- **审核(2.2.7)**:采用用户确认的 **方案 A**——审核仅写入 `biz_protocol_audit`,**不修改** `biz_collection_protocol.protocol_status`。
- **审核记录策略**:采用 **A1**——同一协议单**允许多条**审核记录,保留历史。
- **收款确认(2.2.8)**:仅处理 `pay_status = jfqrz` → `yjf`。
- **退费确认(2.2.9)**:仅处理 `pay_status = tfqrz` → `ytf`;**不包含**退费发起(不把状态推到 `tfqrz`)。
- **分期预警(2.2.10)**:预警窗口 **未来 15 天**;列表仅包含 `pay_status = dfj` 的分期明细(**不包含 `jfqrz`**);逾期定义为应缴日早于当天。
### 1.2 非目标(本阶段不做)
- 不实现科研捐赠、临床应用等非本菜单范围模块。
- 不把 2.2.6 下所有子表(采集信息、样本、运输、当事人等)一次性做全量录入与维护 UI;**第一版协议单详情以主表 + 缴费相关信息为主**,子表可后续迭代。
- 不引入工作流引擎驱动上述 5 个菜单(除非后续产品明确要求);审核与财务确认以**表字段 + 接口**为准。
- 退费发起、待缴费→提交财务确认等业务动作若未在本阶段定义接口,**不实现**。
---
## 2. 前端:菜单与路由
### 2.1 一级菜单
- **标题**:细胞存储管理
- **路径前缀**:`/cell-storage`
- **组件容器**:与现有模块一致,使用布局父级 ` /index/index`。
### 2.2 子菜单与文件路径
| 需求编号 | 菜单名称 | path | 组件路径 |
|----------|--------------------|--------------------------|----------|
| 2.2.6 | 采集协议单 | `protocol` | `views/cell-storage/protocol/index.vue` |
| 2.2.7 | 采集协议单审核 | `protocol-audit` | `views/cell-storage/protocol-audit/index.vue` |
| 2.2.8 | 收款确认(财务) | `payment-confirm` | `views/cell-storage/payment-confirm/index.vue` |
| 2.2.9 | 退费确认(财务) | `refund-confirm` | `views/cell-storage/refund-confirm/index.vue` |
| 2.2.10 | 分期缴费用户预警 | `installment-warning` | `views/cell-storage/installment-warning/index.vue` |
### 2.3 与后端菜单对齐
- 同步更新 `web-admin/src/router/modules/sqxp.ts` 与 `backend/app/api/menu.py` 中的静态菜单树,保证 **前端路由与后端菜单接口一致**(与仓库现有约定相同)。
### 2.4 UI 约定
- 列表页对齐模板:`web-admin/src/views/system/unit/index.vue`(筛选、工具栏、表格、分页)。
- 弹窗表单:`label-position="top"`,`.dialog-form-layout`,无 backdrop blur;色板遵循 `docs/web-admin-ui-spec-fresh-mint.md`。
---
## 3. 数据与后端建模范围(方案 C)
### 3.1 本阶段必须落地的表(SQLAlchemy Model + CRUD)
| 表名 | 用途 |
|------|------|
| `biz_collection_protocol` | 协议单主表:列表、概要详情 |
| `biz_protocol_audit` | 审核记录:列表、提交审核 |
| `biz_protocol_payment` | 缴费主表:展示缴费模式、合同金额、分期参数(与协议单 1:1) |
| `biz_protocol_payment_detail` | 缴费明细:财务确认列表、状态变更、分期预警 |
可选后续迭代再补:`biz_protocol_collection_info`、`biz_protocol_sample`、`biz_protocol_party_customer` 等。
### 3.2 租户与软删除
- 所有查询默认 `tenant_no = 当前用户租户`、`del_flag = 0`。
- 写入时设置 `tenant_no`、`create_by` / `update_by` 等公共字段(与现有 CRUD 一致)。
### 3.3 列表默认排序
- 无自定义排序时:`order_num ASC, create_time DESC`(与工程规范一致);预警列表可按 `installment_due_date ASC` 等业务需求单独约定。
---
## 4. API 设计(前缀 `/api`,路由挂载与现有 `basic_info`、`admin` 一致)
以下路径均在 **`/web/admin`** 下(与现有基础信息管理相同前缀),具体以路由注册为准。
### 4.1 采集协议单(2.2.6)
- `GET .../collection-protocols`
- Query:`page`, `pageSize`, `keyword`(协议号等), `protocolStatus`(可选)
- `GET .../collection-protocols/{id}`
- 返回:协议单主表字段 + 缴费主表概要(若存在)+ 缴费明细分页或摘要(实现时可先返回主表 + payment 一行)
创建/编辑协议单若产品未在本次冻结字段,可:**第一版仅只读列表 + 详情**,或最小字段新增——以 OpenSpec tasks 为准。
### 4.2 采集协议单审核(2.2.7)
- `GET .../collection-protocol-audits`
- 列表:关联协议单展示协议号、审核状态、审核时间等;支持按 `auditStatus`、`keyword` 筛选
- `POST .../collection-protocols/{id}/audit`
- Body:`auditStatus`(`shtg` | `shth`), `auditRemark`(可选)
- 行为:插入一条 `biz_protocol_audit`(**A1:允许多条**);**不更新** `biz_collection_protocol.protocol_status`
- `auditor_user_id` / `create_by` 使用当前登录用户
### 4.3 收款确认(2.2.8)
- `GET .../protocol-payment-details/receipt-confirm`
- 仅 `pay_status = jfqrz`
- `POST .../protocol-payment-details/{detailId}/receipt-confirm`
- 校验当前行必须为 `jfqrz`
- 更新为 `yjf`,写入 `finance_confirm_attachments`(若前端上传)、备注等
- **幂等**:已为 `yjf` 则返回业务错误提示
### 4.4 退费确认(2.2.9)
- `GET .../protocol-payment-details/refund-confirm`
- 仅 `pay_status = tfqrz`
- `POST .../protocol-payment-details/{detailId}/refund-confirm`
- 校验当前行必须为 `tfqrz`
- 更新为 `ytf`
- **幂等**:已为 `ytf` 则返回业务错误提示
### 4.5 分期缴费预警(2.2.10)
- `GET .../protocol-payment-details/installment-warning`
- 条件:`installment_no IS NOT NULL`、`pay_status = dfj`
- 计算字段(可由后端计算返回):
- `warningType = warn`:`today <= due <= today+15天`
- `warningType = overdue`:`due < today`
- Query:`warningType`(`warn` | `overdue` | `all`)、`page`、`pageSize`
- 排序建议:`installment_due_date ASC`
日期计算使用服务器本地日期(YYYYMMDD 字符串与当天对比)。
---
## 5. 权限(建议)
- 五个菜单默认 **`admin` / `super_admin`** 可见(与 Demo 体系一致);若需细分「财务」角色,在 OpenSpec 任务中增加 `perms` 与角色菜单种子 SQL,不阻塞第一版。
---
## 6. 风险与后续迭代
- **协议单详情不完整**:第一版可能无法满足采集专员全量录入,需在后续变更中按子表拆分页面或 Tab。
- **退费链路不完整**:仅确认 `tfqrz→ytf`,需业务侧在其他模块或后续任务中补齐「发起退费」。
- **附件字段**:`finance_confirm_attachments` 等与 MinIO 上传组件对齐现有项目用法。
---
## 7. OpenSpec 后续步骤
1. 使用 `openspec new change` 创建变更(例如 `cell-storage-protocol-modules`)。
2. 按 `openspec-propose` 生成 `proposal.md`、`design.md`、`tasks.md` 及 capabilities 下各 `spec.md`,与本设计对齐。
3. `openspec-apply-change` 按 tasks 实现后端 Model、CRUD、路由注册、`sqxp.ts` + `menu.py`、五个 Vue 页面及 `web-admin/src/api` 封装。
---
**文档状态**:已定稿上述边界(含 A、A1、财务状态、预警 C+1、菜单与路径)。审阅通过后进入 implementation plan(writing-plans)与 OpenSpec 变更落地。