Files
zkxw/docs/superpowers/specs/2026-06-01-sample-qc-sms-notification-design.md
T
2026-06-02 09:39:50 +08:00

307 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 样本质检信息 Tab — 短信通知功能设计
> 状态:已实现
> 日期:2026-06-01
> 需求来源:样本信息管理页新增「样本质检信息」Tab,质检完成后向客户发送短信(线下复制发送)
## 1. 背景与目标
### 1.1 现状
「样本信息管理」页面(`/#/cell-storage/sample-info`)当前有两个 Tab:
| 顺序 | Tab | 能力 |
|------|-----|------|
| 1 | 样本接收信息 | 接收结论 + 短信提取/标记通知 |
| 2 | 样本入库信息 | 入库结论 + 短信提取/标记通知 |
业务链路:**接收 → 质检 → 入库**。质检环节完成后同样需要通知客户,但当前缺少对应 Tab 与后端能力。
### 1.2 目标
在「样本接收信息」与「样本入库信息」之间插入 **样本质检信息** Tab,交互与「样本入库信息」一致:
- 筛选 + 分页列表
- 查看协议单(`ProtocolViewDialog`)
- **提取短信**(复制到剪贴板)
- **标记已/未通知**
**关键约束**(与现有两个 Tab 一致):系统不自动发短信,仅生成内容供运营线下发送。
### 1.3 参考实现
| 层级 | 样本入库信息(克隆源) |
|------|------------------------|
| 前端 Tab | `StorageEntryInfoTab.vue` |
| 前端 API | `storage-entry-sms-notification.ts` |
| 后端 API | `storage_entry_sms_notification.py` |
| CRUD | `storage_entry_sms_notification.py` |
| 通知表 | `biz_storage_entry_sms_notification` |
| 业务数据源 | `biz_storage_release_review` |
设计文档参考:`docs/superpowers/specs/2025-05-23-storage-entry-sms-notification-design.md`
---
## 2. 数据范围
### 2.1 主数据源
**`biz_qc_work_order`(质检工单)**,筛选条件:
| 字段 | 值 | 说明 |
|------|-----|------|
| `reception_source` | `cell_storage` | 仅细胞存储协议样本,不含科研捐赠 |
| `qc_biz_type` | `inbound` | 入库质检(接收后自动创建的工单类型) |
| `work_order_status` | `ywc` | 工单已完成(所有质检任务均完成) |
| `del_flag` | `0` | 未删除 |
不展示:`dpz`(待配置)、`ypz`(已配置未完成)、`yzf`(已作废)。
### 2.2 质检结论(派生字段)
工单表无单一「综合结论」字段,需从 **`biz_qc_task`** 派生:
```
若任一已完成任务的 conclusion = 'btg' → 综合结论 = 不通过 (btg)
否则(全部任务 conclusion = 'tg')→ 综合结论 = 通过 (tg)
```
任务结论码:`tg` / `btg`(与 `status-tag-registry.ts` 中 `qcConclusion` 一致)。
### 2.3 质检完成时间(展示字段)
取该工单下所有 `task_status = 'ywc'` 任务的 **`completed_time` 最大值**;若无则回退工单 `update_time`(状态变为 `ywc` 时更新)。
### 2.4 关联键
与现有细胞存储跨表约定一致:**`tenant_no` + `sample_code`** 关联协议样本、当事人信息(参见 OpenSpec `api-conventions` § 细胞存储样本跨表关联键)。
联查路径:
```
BizQcWorkOrder
→ BizProtocolSample (sample_code + tenant_no)
→ BizCollectionProtocol
→ BizProtocolPartyCustomer
→ BizQcSmsNotification (懒创建,qc_work_order_id)
```
---
## 3. 方案对比
| 方案 | 描述 | 优点 | 缺点 | 建议 |
|------|------|------|------|------|
| **A. 全量克隆入库短信模块(推荐)** | 新建 `biz_qc_sms_notification` 表 + CRUD + API + Tab | 与现有模式一致;隔离清晰;改动面可控 | 需新建表与 5+ 文件 | ✅ 采用 |
| B. 扩展质检工单列表 API | 在 `qc_work_order` 列表加 SMS 字段 | 少一个 API 模块 | 职责混杂;权限与筛选语义不同;改动质检模块风险高 | ❌ |
| C. 合并到样本接收/入库通知表 | 一张表多类型 | 表少 | 破坏现有独立表设计;联查与模板逻辑耦合 | ❌ |
**推荐方案 A**:与 2025-05-23 入库短信设计同一套路,团队已有成熟模板。
---
## 4. 后端设计
### 4.1 新建表 `biz_qc_sms_notification`
```sql
CREATE TABLE biz_qc_sms_notification (
id VARCHAR(64) NOT NULL COMMENT 'UUID主键',
qc_work_order_id VARCHAR(64) NOT NULL COMMENT '关联 biz_qc_work_order.id',
protocol_id VARCHAR(64) DEFAULT NULL COMMENT '冗余协议单ID',
sms_content VARCHAR(500) DEFAULT NULL COMMENT '生成的短信内容',
sms_notified TINYINT(1) NOT NULL DEFAULT 0 COMMENT '0=未通知 1=已通知',
notified_by VARCHAR(64) DEFAULT NULL,
notified_by_name VARCHAR(64) DEFAULT NULL,
notified_time DATETIME DEFAULT NULL,
tenant_no VARCHAR(64) DEFAULT NULL,
order_num INT DEFAULT 0,
remark VARCHAR(512) DEFAULT NULL,
create_by VARCHAR(64) DEFAULT NULL,
create_dept_id VARCHAR(64) DEFAULT NULL,
create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64) DEFAULT NULL,
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
del_flag CHAR(1) DEFAULT '0',
PRIMARY KEY (id),
KEY idx_qc_work_order_id (qc_work_order_id),
KEY idx_tenant_no (tenant_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='样本质检短信通知';
```
### 4.2 CRUD 要点(`qc_sms_notification.py`)
- **list_notifications**:联查 + 租户隔离 + `apply_data_scope`
- **懒创建**:列表加载时为已完成工单自动插入 `sms_notified=0` 记录
- **toggle_notification_status**:标记已/未通知,记录操作人与时间
- **generate_sms_content**:按综合结论生成模板并持久化到 `sms_content`
列表 `_row_to_dict` 返回字段(驼峰):
| 字段 | 说明 |
|------|------|
| id | 通知记录 ID |
| qcWorkOrderId | 质检工单 ID |
| collectionProtocolId | 协议单 ID |
| protocolNo / protocolStatus | 协议号与状态 |
| motherName / newbornName | 当事人 |
| sampleCode / sampleTypeName | 样本 |
| qcCompleteTime | 质检完成时间 |
| qcConclusion / qcConclusionLabel | tg/btg 及中文标签 |
| smsNotified / smsContent | 通知状态与内容 |
### 4.3 短信模板(初稿,待产品确认)
```
通过:尊敬的{母亲}女士,您的样本(编码:{code})已完成质检,结果合格。如有疑问请联系客服。
不通过:尊敬的{母亲}女士,您的样本(编码:{code})质检未通过。如有疑问请联系客服。
```
变量:`mother_name` ← 当事人表;`code` ← 工单 `sample_code`;日期可选加入完成日期。
### 4.4 API 端点
前缀 `/api/web/admin`:
| 方法 | 路径 | 功能 |
|------|------|------|
| GET | `/qc-sms-notifications/list` | 分页列表 |
| PUT | `/qc-sms-notifications/{id}/toggle-status` | 切换通知状态 |
| POST | `/qc-sms-notifications/{id}/generate-sms` | 生成短信 |
**权限码**(与样本信息管理 Tab 共用,无需新菜单):
```python
require_any_menu_code(
"cell-storage:sample-info:list",
"cell-storage:sample-qc-info:list", # 可选:预留独立权限
)
```
初期建议仅 `cell-storage:sample-info:list`,与入库/接收 API 策略一致。
Query 参数:
| 参数 | 说明 |
|------|------|
| keyword | 协议号/姓名/样本编码 |
| qcConclusion | `tg` / `btg` |
| smsNotified | `0` / `1` |
| qcCompleteTimeStart / qcCompleteTimeEnd | 完成时间范围 |
默认时间范围:**近 30 天**(与另外两个 Tab 一致)。
---
## 5. 前端设计
### 5.1 Tab 入口
修改 `web-admin/src/views/cell-storage/sample-info/index.vue`:
| 顺序 | key | 标题 | 图标建议 |
|------|-----|------|----------|
| 1 | sample-reception | 样本接收信息 | Box |
| 2 | **sample-qc** | **样本质检信息** | **DocumentChecked** |
| 3 | storage-entry | 样本入库信息 | FolderOpened |
`VALID_TABS` 增加 `sample-qc`;样式类由 `--dual` 改为 `--triple`(三 Tab 布局)。
### 5.2 新建组件
`web-admin/src/views/cell-storage/protocol-audit/SampleQcInfoTab.vue`
(与 `SampleReceptionInfoTab` / `StorageEntryInfoTab` 同目录,便于复用)
**筛选区**:
| 字段 | 控件 | 绑定 |
|------|------|------|
| 关键词 | el-input | keyword |
| 质检结论 | el-select | qcConclusion(通过 tg / 不通过 btg) |
| 通知状态 | el-select | smsNotified |
| 质检完成时间 | daterange | qcCompleteTimeRange |
**表格列**(全部 `min-width`,居中,状态用 `el-tag`):
协议号、协议状态、母亲姓名、新生儿姓名、样本编码、样本类型、**质检完成时间**、**质检结论**、通知状态、操作(查看 / 提取短信 / 标记通知)。
**查看**:`ProtocolViewDialog`(`show-audit-history` 等同入库 Tab)。
### 5.3 新建 API 模块
`web-admin/src/api/qc-sms-notification.ts` — 3 个函数,镜像 `storage-entry-sms-notification.ts`。
---
## 6. 业务流程图
```mermaid
flowchart LR
A[样本接收 js] --> B[创建入库质检工单]
B --> C[配置并执行质检任务]
C --> D{全部任务完成?}
D -->|是| E[工单状态 ywc]
E --> F[样本质检信息 Tab 展示]
F --> G[提取短信 / 标记已通知]
G --> H[运营线下发送]
E --> I[后续入库放行...]
```
---
## 7. 边界情况
| 场景 | 处理 |
|------|------|
| 工单 ywc 但部分任务无 conclusion | 不纳入列表,或结论显示「待确认」;实现时需明确(建议:无 conclusion 不展示) |
| 科研捐赠样本 | `reception_source != cell_storage` 过滤排除 |
| 出库/临时质检 | `qc_biz_type != inbound` 过滤排除 |
| 缺少协议单 | 查看按钮提示,不打开弹窗 |
| 旧书签 `?tab=sample-qc` | sample-info 页 onMounted 解析 query |
---
## 8. 文件清单(预估)
### 新建
| 文件 | 说明 |
|------|------|
| `docs/sql/biz_qc_sms_notification.sql` | 建表 DDL |
| `docs/sql/migration-2026-06-01-qc-sms-notification.sql` | 增量迁移 |
| `backend/app/crud/qc_sms_notification.py` | CRUD |
| `backend/app/api/qc_sms_notification.py` | API |
| `web-admin/src/api/qc-sms-notification.ts` | 前端 API |
| `web-admin/src/views/cell-storage/protocol-audit/SampleQcInfoTab.vue` | Tab 组件 |
### 修改
| 文件 | 修改 |
|------|------|
| `backend/app/models/models.py` | `BizQcSmsNotification` 模型 |
| `backend/app/api/__init__.py` / `main.py` | 注册路由 |
| `web-admin/src/views/cell-storage/sample-info/index.vue` | 增加 Tab |
| `docs/sql/zkxw.sql` | 全量基线同步 |
**不做的事**:不自动发短信;不改动质检工单执行逻辑;不修改接收/入库 Tab。
---
## 9. 待确认项(评审门禁)
1. **短信文案**:上述通过/不通过模板是否可用?是否需要包含完成日期?
2. **列表范围**:是否仅「工单已完成 ywc」?是否还需要展示「进行中 ypz」供提前通知?(建议:仅 ywc,与入库 Tab 只展示终态一致)
3. **权限**:是否沿用 `cell-storage:sample-info:list`,无需新菜单权限?
---
## 10. 工作量评估
| 模块 | 预估 |
|------|------|
| 后端(表+CRUD+API) | 0.5~1 天 |
| 前端 Tab + API | 0.5 天 |
| 联调与边界验证 | 0.5 天 |
| **合计** | **约 1.5~2 天** |