2025-05-23-storage-entry-sms-notification-design.md 8.9 KB

样本入库信息 — 短信通知功能设计

状态:待评审 日期:2025-05-23 需求来源:客户提出"样本入库也需要给客户发短信"

1. 背景与目标

客户已完成样本接收信息页面(/cell-storage/sample-reception-info),用于管理样本接收后的短信通知(提取短信内容 → 复制到剪贴板 → 用户线下发送)。现需增加样本入库信息页面,在样本完成入库(或拒绝入库)后提供同样的短信通知管理能力。

核心模式:克隆样本接收信息的完整链路(前端页面 + 后端 API + 独立通知表),调整为入库场景。

关键约束:短信不通过系统自动发送,由用户线下手动发送。系统只负责生成短信内容供复制。

2. 决策记录

决策项 选择 理由
数据范围 已入库(yrk) + 拒绝入库(review_conclusion='btg') 展示最终结果的记录
短信模板 系统预设,后续可调 先上线后迭代
页面位置 细胞存储模块下,与样本接收信息同级 用户操作习惯一致
查看弹窗 复用 ProtocolViewDialog 与样本接收信息一致,查看协议完整信息
后端存储 新建独立表 代码独立,不影响现有功能

3. 数据范围

数据源为 biz_storage_release_review 表,筛选条件:

  • storage_status = 'yrk'(已入库),或
  • review_conclusion = 'btg'(审核不通过/拒绝入库)

不展示 storage_status = 'drk'(待入库)且审核未出结论的记录。

重要:仅展示 reception_source = 'cell_storage'(细胞存储)的记录,不包含科研捐赠来源的数据。此过滤条件同时应用于「样本接收信息」和「样本入库信息」两个页面。

4. 后端设计

4.1 数据库

新建表 biz_storage_entry_sms_notification:

CREATE TABLE biz_storage_entry_sms_notification (
  id                    VARCHAR(64)   NOT NULL COMMENT 'UUID主键',
  storage_review_id     VARCHAR(64)   NOT NULL COMMENT '关联 biz_storage_release_review.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 COMMENT '通知操作人ID',
  notified_by_name      VARCHAR(64)   DEFAULT NULL COMMENT '通知操作人姓名',
  notified_time         DATETIME      DEFAULT NULL COMMENT '通知操作时间',
  tenant_no             VARCHAR(64)   DEFAULT NULL COMMENT '租户编号',
  order_num             INT           DEFAULT 0 COMMENT '排序',
  remark                VARCHAR(512)  DEFAULT NULL COMMENT '备注',
  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' COMMENT '0=正常 1=删除',
  PRIMARY KEY (id),
  KEY idx_storage_review_id (storage_review_id),
  KEY idx_tenant_no (tenant_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='样本入库短信通知';

4.2 ORM 模型

在 backend/app/models/models.py 追加 BizStorageEntrySmsNotification,字段与表结构对应。

4.3 CRUD 层

新建 backend/app/crud/storage_entry_sms_notification.py,克隆 sample_sms_notification.py 并调整:

  • 联查:BizStorageReleaseReview LEFT JOIN BizStorageEntrySmsNotification(通过 storage_review_id + tenant_no) LEFT JOIN BizCollectionProtocol LEFT JOIN BizProtocolPartyCustomer LEFT JOIN BizProtocolSample
  • 过滤:del_flag=0,reception_source='cell_storage',(storage_status='yrk' OR review_conclusion='btg'),租户隔离,数据权限(apply_data_scope)
  • 懒创建:列表查询时自动为缺失的 review 记录创建通知记录(sms_notified=0)
  • _row_to_dict():蛇形→驼峰,返回前端所需字段

4.4 短信模板

已入库:尊敬的{母亲}女士,您的样本(编码:{code})已于{date}完成入库处理。如有疑问请联系客服。
拒绝入库:尊敬的{母亲}女士,您的样本(编码:{code})入库审核未通过。如有疑问请联系客服。

变量来源:

  • {母亲}:BizProtocolPartyCustomer.mother_name
  • {code}:BizStorageReleaseReview.sample_code
  • {date}:入库时间 storage_time(拒绝入库用审核时间 review_time)

4.5 API 端点

新建 backend/app/api/storage_entry_sms_notification.py,前缀 /api/web/admin:

方法 路径 功能 权限码
GET /storage-entry-sms-notifications/list 分页列表 cell-storage:storage-entry-info:list
PUT /storage-entry-sms-notifications/{id}/toggle-status 切换通知状态 同上
POST /storage-entry-sms-notifications/{id}/generate-sms 生成短信内容 同上

路由注册:backend/app/api/__init__.py + backend/app/main.py。

5. 前端设计

5.1 路由

在 web-admin/src/router/modules/sqxp.ts 的 CellStorage 子项下添加:

path: 'storage-entry-info'
name: 'CellStorageStorageEntryInfo'
component: '/cell-storage/storage-entry-info/index'
meta: { title: '样本入库信息', keepAlive: true, menuCode: 'cell-storage:storage-entry-info:list' }

5.2 API 模块

新建 web-admin/src/api/storage-entry-sms-notification.ts,3 个函数:

  • fetchStorageEntrySmsList(params) → GET /storage-entry-sms-notifications/list
  • fetchToggleStorageEntrySmsNotified(id, data) → PUT /storage-entry-sms-notifications/{id}/toggle-status
  • fetchGenerateStorageEntrySms(id) → POST /storage-entry-sms-notifications/{id}/generate-sms

5.3 页面组件

新建 web-admin/src/views/cell-storage/storage-entry-info/index.vue,克隆 sample-reception-info/index.vue 并调整:

筛选区: | 字段 | 控件 | 绑定 | |---|---|---| | 关键词 | el-input | keyword(协议号/姓名/样本编码) | | 入库状态 | el-select | storageStatus(已入库 yrk / 拒绝入库 btg) | | 通知状态 | el-select | smsNotified(已通知 1 / 未通知 0) |

表格列(全部 min-width,align="center"): | 列 | prop | 宽度 | 说明 | |---|---|---|---| | 序号 | type=index | 68 | 自动序号 | | 协议号 | protocolNo | 140 | | | 母亲姓名 | motherName | 100 | | | 新生儿姓名 | newbornName | 110 | show-overflow-tooltip | | 样本编码 | sampleCode | 130 | | | 样本类型 | sampleTypeName | 110 | | | 入库时间 | storageTime | 170 | 已入库显示入库时间,拒绝入库显示审核时间 | | 入库状态 | storageStatusLabel | 100 | el-tag:已入库=success,拒绝入库=danger | | 通知状态 | smsNotified | 100 | el-tag:已通知=success,未通知=info | | 操作 | — | 260 | fixed="right" |

操作按钮:

  1. 查看 <el-icon><View /></el-icon> — 打开 ProtocolViewDialog(含 show-audit-history、show-storage-cert)
  2. 提取短信 <el-icon><ChatDotRound /></el-icon> — 调用 fetchGenerateStorageEntrySms,复制到剪贴板
  3. 标记已/未通知 <el-icon><Bell /></el-icon> — 调用 fetchToggleStorageEntrySmsNotified

交互:双击行 → handleView,分页 [10, 20, 50]

5.4 其他修改

  • App.vue:在 panelTitleBarTextRules 注册「样本入库列表」标题文案
  • 菜单配置:后台管理中添加「样本入库信息」菜单项,权限码 cell-storage:storage-entry-info:list

6. 边界情况

场景 处理方式
拒绝入库记录无 storageTime 短信模板用 review_time 替代,表格列也显示审核时间
协议单为空 查看按钮提示"缺少关联协议单",不打开弹窗

7. 文件清单

新建(5 个)

文件 说明
docs/sql/biz_storage_entry_sms_notification.sql 建表 DDL
backend/app/crud/storage_entry_sms_notification.py CRUD 层(联查+懒创建+短信生成)
backend/app/api/storage_entry_sms_notification.py API 路由(3 个端点)
web-admin/src/api/storage-entry-sms-notification.ts 前端 API 封装
web-admin/src/views/cell-storage/storage-entry-info/index.vue 前端页面

修改(4 个)

文件 修改内容
backend/app/models/models.py 追加 BizStorageEntrySmsNotification 模型
backend/app/api/__init__.py 注册新路由
backend/app/main.py 挂载新路由
web-admin/src/router/modules/sqxp.ts 添加路由条目(CellStorage 子项)

8. 不做的事

  • 不实现自动发送短信(线下发送)
  • 不修改现有 sample-reception-info 任何逻辑
  • 不引入新的 npm/pip 依赖
  • 不改动入库放行审核页面逻辑