Files
hms/docs/superpowers/specs/2026-04-23-health-management-module-design.md
iven ca50d32f6e
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled
feat(health): 添加 erp-health 健康管理模块骨架
新建 erp-health 原生 Rust crate,覆盖设计规格中定义的 5 大业务域:

- 16 个 SeaORM Entity(患者/家属/标签/医生/健康档案/体征/化验单/预约/排班/随访/咨询等)
- 16 表数据库迁移(含索引、外键、默认值、可回滚)
- 40+ API 路由骨架(患者管理/健康数据/预约排班/随访/咨询/医生管理)
- 12 个权限声明(health.patient/health-data/appointment/follow-up/consultation/doctor 各 .list/.manage)
- DTO / Service / Handler / Event 四层架构,Service 使用 todo!() 占位
- erp-server 集成:模块注册 + AppState FromRef 桥接 + 路由挂载

同步更新 CLAUDE.md 项目进度、wiki 知识库、设计规格文档。
2026-04-23 19:59:22 +08:00

711 lines
26 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.
# 健康管理系统 — erp-health 模块设计规格
> **文档版本**: 1.0
> **日期**: 2026-04-23
> **状态**: 已确认
> **范围**: V1 — 患者管理 + 健康数据 + 预约排班 + 随访管理 + 咨询管理
---
## 1. 项目背景
### 1.1 产品定位
构建一个面向体检中心/医疗机构的**综合型健康管理平台**,以体检中心为数据源,汇集不同情况的患者,提供全生命周期的健康管理服务。
本系统从 ERP 平台底座分叉独立,作为 **Health Management System (HMS)** 产品演进。ERP 底座提供身份权限、工作流、消息通知、系统配置等基础能力,`erp-health` 作为原生 Rust 模块承载所有医疗业务逻辑。
### 1.2 系统架构
```
📱 患者端(微信小程序) ──┐
├──→ 🔀 API 网关 ──→ 🖥️ ERP 后端HMS
👨‍⚕️ 医护端(小程序/H5 ──┘ │ │
│ ├── erp-auth用户/角色/权限)
│ ├── erp-workflow工作流引擎
│ ├── erp-message消息通知
│ ├── erp-config字典/配置)
│ └── erp-health健康管理★ 新增
└──→ 💾 PostgreSQL + Redis
```
**关键决策:**
- ERP 只负责 **PC 管理后台**功能
- 小程序(患者端/医护端)作为**独立系统**开发
- 数据共享通过 **API 网关**实现
- 健康管理使用**原生 Rust 模块**(非 WASM 插件),获得完整的数据库访问和自定义 API 能力
### 1.3 为什么不用 WASM 插件
| 限制 | 影响 |
|------|------|
| 实体上限 20 个 | 综合健康平台轻松超过 |
| JSONB 存储 | 医疗数据需要强类型、索引、关联 |
| 无自定义 API | 趋势分析、统计报表需要专用端点 |
| 无文件上传 | 化验单、体检报告无法存储 |
| WASM 沙箱限制 | 无法引入加密、AI、外部 API |
原生模块遵循现有模式(如 erp-auth、erp-workflow。**注意:**`ErpModule` trait 没有 `register_routes` 方法。模块通过固有方法 `public_routes()``protected_routes()` 暴露路由,在 `erp-server``main.rs` 中通过 `.nest("/api/v1/health", HealthModule::protected_routes())` 集成。通过 EventBus 通信,未来可平滑拆分为独立微服务。
---
## 2. V1 功能范围
| 模块 | 功能 | 页面数 |
|------|------|--------|
| ① 患者与医护管理 | 患者档案、家庭成员、医护档案、患者标签 | 3 |
| ② 健康数据管理 | 体检记录、日常监测、化验报告、趋势分析 | 3 |
| ③ 预约与排班 | 预约管理、医生排班、日历视图 | 2 |
| ④ 随访管理 | 随访任务、随访记录台账 | 2 |
| ⑤ 咨询管理 | 会话管理、对话记录查看/导出 | 2 |
| ⑥ 医护管理 | 医护人员列表 | 1 |
| **合计** | | **13** |
**V2 预留:** 积分商城、数据统计中心、内容管理增强。
---
## 3. 实体模型
### 3.1 设计原则
- 患者和医护的**账号**走 `erp-auth``users` 表,`erp-health` 只存医疗业务扩展字段
- 通过 `user_id` 外键关联 `users`
- 所有表含 `tenant_id`(多租户隔离)、`id`UUIDv7`created_at``updated_at``created_by``updated_by``deleted_at``version`
- 多对多关系使用中间表
### 3.2 实体定义
#### ① 患者与医护管理
**patient — 患者档案**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | UUIDv7 |
| tenant_id | UUID NOT NULL | 租户 ID |
| user_id | UUID FK → users | 关联 erp-auth 账号 |
| name | VARCHAR(100) | 姓名 |
| gender | VARCHAR(10) | 性别 (male/female/other) |
| birth_date | DATE | 出生日期 |
| blood_type | VARCHAR(10) | 血型 (A/B/AB/O/RH-/RH+) |
| id_number | VARCHAR(20) | 身份证号 |
| allergy_history | TEXT | 过敏史 |
| medical_history_summary | TEXT | 病史摘要 |
| emergency_contact_name | VARCHAR(100) | 紧急联系人姓名 |
| emergency_contact_phone | VARCHAR(20) | 紧急联系人电话 |
| status | VARCHAR(20) | 状态 (active/inactive/deceased) |
| verification_status | VARCHAR(20) | 实名认证 (pending/verified/rejected) |
| source | VARCHAR(100) | 来源(体检中心名称) |
| notes | TEXT | 备注 |
| created_at, updated_at, created_by, updated_by, deleted_at, version | — | 标准字段 |
索引:`(tenant_id, name)`, `(tenant_id, status)`, `(tenant_id, id_number) UNIQUE WHERE deleted_at IS NULL`
**patient_family_member — 家庭成员**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | |
| tenant_id | UUID NOT NULL | |
| patient_id | UUID FK → patient | 患者关联 |
| name | VARCHAR(100) | 姓名 |
| relationship | VARCHAR(50) | 关系(父亲/母亲/配偶/子女等) |
| phone | VARCHAR(20) | 电话 |
| birth_date | DATE | 出生日期 |
| notes | TEXT | 备注 |
| 标准 ERP 字段 | — | |
**doctor_profile — 医护档案**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | |
| tenant_id | UUID NOT NULL | |
| user_id | UUID FK → users | 关联 erp-auth 账号 |
| department | VARCHAR(100) | 科室 |
| title | VARCHAR(50) | 职称(主任医师/副主任医师/主治医师等) |
| specialty | VARCHAR(200) | 专长 |
| license_number | VARCHAR(50) | 执业证号 |
| bio | TEXT | 简介 |
| online_status | VARCHAR(20) | 在线状态 (online/offline/busy) |
| 标准 ERP 字段 | — | |
索引:`(tenant_id, patient_id)`
**patient_tag — 患者标签**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | |
| tenant_id | UUID NOT NULL | |
| name | VARCHAR(50) | 标签名 |
| color | VARCHAR(20) | 颜色值 |
| description | TEXT | 描述 |
| is_system | BOOLEAN | 系统标签(不可删除) |
| 标准 ERP 字段 | — | |
索引:`UNIQUE (tenant_id, name) WHERE deleted_at IS NULL`
**patient_tag_relation — 患者-标签关联**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | |
| tenant_id | UUID NOT NULL | |
| patient_id | UUID FK → patient | |
| tag_id | UUID FK → patient_tag | |
| created_at | TIMESTAMPTZ | |
| updated_at | TIMESTAMPTZ | |
| created_by | UUID | |
| updated_by | UUID | |
| deleted_at | TIMESTAMPTZ | 软删除 |
索引:`(tenant_id, patient_id)`, `(tenant_id, tag_id)`
**patient_doctor_relation — 医患关系**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | |
| tenant_id | UUID NOT NULL | |
| patient_id | UUID FK → patient | |
| doctor_id | UUID FK → doctor_profile | |
| relationship_type | VARCHAR(20) | 类型 (primary/consulting) |
| created_at | TIMESTAMPTZ | |
| updated_at | TIMESTAMPTZ | |
| created_by | UUID | |
| updated_by | UUID | |
| deleted_at | TIMESTAMPTZ | 软删除 |
索引:`(tenant_id, patient_id)`, `(tenant_id, doctor_id)`
#### ② 健康数据管理
**health_record — 体检/就诊记录**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | |
| tenant_id | UUID NOT NULL | |
| patient_id | UUID FK → patient | |
| record_type | VARCHAR(20) | 类型 (checkup/outpatient/inpatient) |
| record_date | DATE | 记录日期 |
| source | VARCHAR(200) | 来源(体检中心/医院名称) |
| overall_assessment | TEXT | 总体评估 |
| report_file_url | VARCHAR(500) | 报告文件 URL |
| notes | TEXT | 备注 |
| 标准 ERP 字段 | — | |
索引:`(tenant_id, patient_id, record_date DESC)`
**vital_signs — 日常监测数据**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | |
| tenant_id | UUID NOT NULL | |
| patient_id | UUID FK → patient | |
| record_date | DATE | 记录日期 |
| systolic_bp_morning | INTEGER | 晨起收缩压 |
| diastolic_bp_morning | INTEGER | 晨起舒张压 |
| systolic_bp_evening | INTEGER | 晚间收缩压 |
| diastolic_bp_evening | INTEGER | 晚间舒张压 |
| heart_rate | INTEGER | 心率 |
| weight | DECIMAL(5,1) | 体重 (kg) |
| blood_sugar | DECIMAL(5,1) | 血糖 (mmol/L) |
| water_intake_ml | INTEGER | 饮水量 (ml) |
| urine_output_ml | INTEGER | 尿量 (ml) |
| notes | TEXT | 备注 |
| 标准 ERP 字段 | — | |
索引:`(tenant_id, patient_id, record_date DESC)`
**lab_report — 化验报告**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | |
| tenant_id | UUID NOT NULL | |
| patient_id | UUID FK → patient | |
| report_date | DATE | 报告日期 |
| report_type | VARCHAR(50) | 报告类型(肾功能/血常规/尿常规等) |
| indicators | JSONB | 指标数据 [{name, value, unit, ref_range, is_abnormal}] |
| image_urls | JSONB | 图片 URLs [url1, url2, ...] |
| doctor_interpretation | TEXT | 医生解读 |
| 标准 ERP 字段 | — | |
索引:`(tenant_id, patient_id, report_date DESC)`, GIN on `indicators`, `(tenant_id, report_type)`
**health_trend — 健康趋势报告**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | |
| tenant_id | UUID NOT NULL | |
| patient_id | UUID FK → patient | |
| period_start | DATE | 周期开始 |
| period_end | DATE | 周期结束 |
| indicator_summary | JSONB | 指标摘要 |
| abnormal_items | JSONB | 异常项 |
| generation_type | VARCHAR(20) | 生成方式 (auto/manual) |
| report_file_url | VARCHAR(500) | 报告文件 URL |
| 标准 ERP 字段 | — | |
索引:`(tenant_id, patient_id, period_start DESC)`
#### ③ 预约排班
**appointment — 预约记录**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | |
| tenant_id | UUID NOT NULL | |
| patient_id | UUID FK → patient | |
| doctor_id | UUID FK → doctor_profile | |
| appointment_type | VARCHAR(20) | 类型 (dialysis/recheck/outpatient) |
| appointment_date | DATE | 预约日期 |
| start_time | TIME | 开始时间 |
| end_time | TIME | 结束时间 |
| status | VARCHAR(20) | 状态 (pending/confirmed/cancelled/completed/no_show) |
| cancel_reason | TEXT | 取消原因 |
| notes | TEXT | 备注 |
| 标准 ERP 字段 | — | |
索引:`(tenant_id, appointment_date, status)`, `(tenant_id, doctor_id, appointment_date)`
**doctor_schedule — 医生排班**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | |
| tenant_id | UUID NOT NULL | |
| doctor_id | UUID FK → doctor_profile | |
| schedule_date | DATE | 排班日期 |
| period_type | VARCHAR(20) | 时段 (am/pm/night/full_day) |
| start_time | TIME | 开始时间 |
| end_time | TIME | 结束时间 |
| max_appointments | INTEGER | 最大预约数 |
| current_appointments | INTEGER | 已预约数(默认 0 |
| status | VARCHAR(20) | 状态 (enabled/disabled) |
| 标准 ERP 字段 | — |
索引:`(tenant_id, doctor_id, schedule_date)`, `UNIQUE (tenant_id, doctor_id, schedule_date, period_type) WHERE deleted_at IS NULL`
**预约并发控制:** 创建预约时使用原子 CAS 操作 `UPDATE doctor_schedule SET current_appointments = current_appointments + 1 WHERE id = $1 AND current_appointments < max_appointments RETURNING *`,防止超额预约。
#### ④ 随访管理
**follow_up_task — 随访任务**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | |
| tenant_id | UUID NOT NULL | |
| patient_id | UUID FK → patient | |
| assigned_to | UUID FK → users | 负责医护 |
| follow_up_type | VARCHAR(20) | 类型 (phone/face_to_face/online) |
| planned_date | DATE | 计划日期 |
| status | VARCHAR(20) | 状态 (pending/in_progress/completed/overdue/cancelled) |
| content_template | TEXT | 随访内容模板 |
| related_appointment_id | UUID FK → appointment | 关联预约 |
| 标准 ERP 字段 | — | |
索引:`(tenant_id, assigned_to, status)`, `(tenant_id, planned_date, status)`
**follow_up_record — 随访记录**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | |
| tenant_id | UUID NOT NULL | |
| task_id | UUID FK → follow_up_task | |
| executed_by | UUID FK → users | 执行医护 |
| executed_date | DATE | 执行日期 |
| result | VARCHAR(20) | 结果 (followed_up/unreachable/refused/other) |
| patient_condition | TEXT | 患者状况 |
| medical_advice | TEXT | 医嘱建议 |
| next_follow_up_date | DATE | 下次随访日期 |
| 标准 ERP 字段 | — | |
索引:`(tenant_id, task_id)`, `(tenant_id, executed_date)`
#### ⑤ 咨询管理
**consultation_session — 咨询会话**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | |
| tenant_id | UUID NOT NULL | |
| patient_id | UUID FK → patient | |
| doctor_id | UUID FK → doctor_profile | |
| type | VARCHAR(20) | 类型 (customer_service/doctor) |
| status | VARCHAR(20) | 状态 (waiting/active/closed) |
| last_message_at | TIMESTAMPTZ | 最后消息时间 |
| unread_count_patient | INTEGER | 患者未读数 |
| unread_count_doctor | INTEGER | 医生未读数 |
| 标准 ERP 字段 | — | |
索引:`(tenant_id, doctor_id, status)`, `(tenant_id, patient_id, status)`
**consultation_message — 咨询消息**
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID PK | |
| tenant_id | UUID NOT NULL | |
| session_id | UUID FK → consultation_session | |
| sender_id | UUID | 发送者 ID |
| sender_role | VARCHAR(20) | 角色 (patient/doctor/system) |
| content_type | VARCHAR(20) | 类型 (text/image/voice/file) |
| content | TEXT | 内容 |
| is_read | BOOLEAN | 已读状态(默认 false |
| created_at | TIMESTAMPTZ | 发送时间 |
| updated_at | TIMESTAMPTZ | |
| created_by | UUID | |
| updated_by | UUID | |
| deleted_at | TIMESTAMPTZ | 软删除(内容审核用) |
| version | INT NOT NULL DEFAULT 1 | 乐观锁 |
索引:`(tenant_id, session_id, created_at)`
**数据增长策略:**`created_at` 按月分区PostgreSQL table partitioning超过 1 年的已关闭会话消息归档到冷存储。
**说明:**
- `patient.user_id` 允许 NULL — 患者可先创建档案(如体检中心导入),后续再绑定 erp-auth 账号
- `consultation_message.sender_id` 引用 `users.id` — 统一使用 erp-auth 用户体系标识发送者
---
## 3.3 状态机定义
### appointment.status 转换
```
pending ──→ confirmed ──→ completed
│ │
│ └──→ no_show预约时间过后系统自动或前台手动触发
└──→ cancelled任意时刻可取消需填 cancel_reason
```
### follow_up_task.status 转换
```
pending ──→ in_progress ──→ completed
│ │
└──→ cancelled └──→ overdue系统定时任务planned_date 已过且仍 pending 自动标记)
```
### consultation_session.status 转换
```
waiting ──→ active第一条消息发送时自动触发──→ closed手动关闭或超时自动关闭
```
### patient.status 转换
```
active ──→ inactive手动停用
active ──→ deceased标记死亡不可逆
inactive ──→ active重新激活
```
### patient.verification_status 转换
```
pending ──→ verified实名认证通过
pending ──→ rejected认证被拒
rejected ──→ pending重新提交认证
```
---
## 4. API 设计
所有端点前缀: `/api/v1/health/`
### 4.1 患者管理
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/patients` | 患者列表(分页、搜索、标签筛选) |
| POST | `/patients` | 创建患者 |
| GET | `/patients/:id` | 患者详情 |
| PUT | `/patients/:id` | 更新患者 |
| DELETE | `/patients/:id` | 软删除 |
| POST | `/patients/:id/tags` | 管理标签(批量设置) |
| GET | `/patients/:id/health-summary` | 健康摘要 |
| GET | `/patients/:id/family-members` | 家庭成员列表 |
| POST | `/patients/:id/family-members` | 新增家庭成员 |
| PUT | `/patients/:id/family-members/:fid` | 更新家庭成员 |
| DELETE | `/patients/:id/family-members/:fid` | 删除家庭成员 |
| POST | `/patients/:id/doctors` | 分配主治医生 |
| DELETE | `/patients/:id/doctors/:did` | 移除医患关系 |
### 4.2 健康数据
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/patients/:id/vital-signs` | 日常监测列表 |
| POST | `/patients/:id/vital-signs` | 新增监测数据 |
| GET | `/patients/:id/lab-reports` | 化验报告列表 |
| POST | `/patients/:id/lab-reports` | 新增化验报告 |
| GET | `/patients/:id/health-records` | 体检/就诊记录 |
| POST | `/patients/:id/health-records` | 新增记录 |
| GET | `/patients/:id/trends` | 趋势报告 |
| POST | `/patients/:id/trends/generate` | 生成趋势报告 |
| GET | `/patients/:id/trends/:indicator` | 单指标时序数据 |
| PUT | `/patients/:id/vital-signs/:vid` | 更新监测数据 |
| DELETE | `/patients/:id/vital-signs/:vid` | 删除监测数据 |
| PUT | `/patients/:id/lab-reports/:rid` | 更新化验报告 |
| DELETE | `/patients/:id/lab-reports/:rid` | 删除化验报告 |
| PUT | `/patients/:id/health-records/:rid` | 更新体检记录 |
| DELETE | `/patients/:id/health-records/:rid` | 删除体检记录 |
### 4.3 预约排班
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/appointments` | 预约列表 |
| POST | `/appointments` | 创建预约 |
| PUT | `/appointments/:id/status` | 更新状态 |
| GET | `/doctor-schedules` | 排班列表 |
| POST | `/doctor-schedules` | 创建排班 |
| PUT | `/doctor-schedules/:id` | 更新排班 |
| GET | `/doctor-schedules/calendar` | 日历视图 |
### 4.4 随访管理
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/follow-up-tasks` | 任务列表 |
| POST | `/follow-up-tasks` | 创建任务 |
| PUT | `/follow-up-tasks/:id` | 更新任务 |
| DELETE | `/follow-up-tasks/:id` | 删除任务 |
| POST | `/follow-up-tasks/:id/records` | 填写随访记录 |
| GET | `/follow-up-records` | 随访台账 |
### 4.5 咨询管理
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/consultation-sessions` | 会话列表 |
| GET | `/consultation-sessions/:id/messages` | 消息记录 |
| PUT | `/consultation-sessions/:id/close` | 关闭会话 |
| POST | `/consultation-messages` | 写入消息API 网关用) |
| GET | `/consultation-sessions/export` | 导出 |
### 4.6 医护管理
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/doctors` | 医护列表 |
| POST | `/doctors` | 创建医护档案 |
| GET | `/doctors/:id` | 医护详情 |
| PUT | `/doctors/:id` | 更新医护档案 |
| DELETE | `/doctors/:id` | 软删除医护档案 |
---
## 5. 前端页面设计
文件位置: `apps/web/src/pages/health/`
### 5.1 页面清单
| # | 页面 | 文件名 | 类型 |
|---|------|--------|------|
| 1 | 患者列表 | PatientList.tsx | 表格+搜索+标签筛选+导出 |
| 2 | 患者详情 | PatientDetail.tsx | Tab布局基本信息/健康趋势/化验报告/就诊记录/随访记录 |
| 3 | 标签管理 | PatientTagManage.tsx | CRUD+颜色+批量打标 |
| 4 | 日常监测 | VitalSignsList.tsx | 按患者+日期+ECharts趋势折线图 |
| 5 | 化验报告 | LabReportList.tsx | 列表+图片预览+指标详情+解读 |
| 6 | 体检记录 | HealthRecordList.tsx | 类型筛选+报告文件查看/上传 |
| 7 | 预约管理 | AppointmentList.tsx | 列表/日历切换+状态流转 |
| 8 | 排班管理 | DoctorSchedule.tsx | 周/月日历+排班模板 |
| 9 | 随访任务 | FollowUpTaskList.tsx | 任务CRUD+分配+关联工作流 |
| 10 | 随访台账 | FollowUpRecordList.tsx | 按患者/医护/日期筛选+导出 |
| 11 | 会话管理 | ConsultationList.tsx | 列表+未回复统计 |
| 12 | 对话记录 | ConsultationDetail.tsx | 聊天气泡+图片/语音查看+导出 |
| 13 | 医护列表 | DoctorList.tsx | 列表+科室筛选+在线状态 |
### 5.2 技术要点
- **ECharts 趋势图** — 血压/体重/血糖曲线图,按日期范围展示
- **文件上传/预览** — 化验单图片、体检报告 PDF需新增基础能力
- **日历组件** — Ant Design Calendar 用于排班和预约视图
- **聊天 UI** — 消息气泡展示(只读,非实时聊天)
- **导出** — 随访台账、咨询记录导出为 Excel
---
## 6. 事件集成
### 6.1 发布事件
| 事件类型 | 触发时机 | 载荷 |
|----------|----------|------|
| `patient.created` | 创建患者 | `{patient_id, name, tenant_id}` |
| `patient.updated` | 更新患者信息 | `{patient_id, changed_fields}` |
| `appointment.created` | 创建预约 | `{appointment_id, patient_id, doctor_id, date}` |
| `appointment.confirmed` | 确认预约 | `{appointment_id}` |
| `appointment.cancelled` | 取消预约 | `{appointment_id, cancel_reason}` |
| `appointment.completed` | 完成就诊 | `{appointment_id}` |
| `follow_up.created` | 创建随访任务 | `{task_id, patient_id, assigned_to, planned_date}` |
| `follow_up.completed` | 完成随访 | `{task_id, record_id, result}` |
| `lab_report.uploaded` | 上传化验报告 | `{report_id, patient_id, report_type, abnormal_count}` |
| `consultation.opened` | 开启咨询 | `{session_id, patient_id, doctor_id}` |
| `consultation.closed` | 关闭咨询 | `{session_id}` |
| `patient.deceased` | 患者死亡标记 | `{patient_id}` |
| `patient.verified` | 实名认证通过 | `{patient_id, id_number}` |
| `follow_up.overdue` | 随访任务逾期 | `{task_id, patient_id, planned_date}` |
| `doctor.online_status_changed` | 医护在线状态变更 | `{doctor_id, old_status, new_status}` |
**随访记录自动创建后续任务:**`follow_up_record.next_follow_up_date` 不为空时,服务层自动创建新的 `follow_up_task`planned_date = next_follow_up_dateassigned_to 沿用当前医护)。
### 6.2 订阅事件
| 事件类型 | 处理逻辑 |
|----------|----------|
| `workflow.task.completed` | 工作流任务完成时更新随访任务状态 |
| `message.sent` | 消息发送时联动咨询会话的 last_message_at |
---
## 7. 模块结构
```
crates/erp-health/
├── Cargo.toml
├── src/
│ ├── lib.rs ← ErpModule trait + public_routes() / protected_routes()
│ ├── error.rs ← HealthError → AppError
│ ├── state.rs ← HealthState (共享状态)
│ ├── entity/ ← SeaORM Entity
│ │ ├── mod.rs
│ │ ├── patient.rs
│ │ ├── patient_family_member.rs
│ │ ├── patient_tag.rs
│ │ ├── patient_tag_relation.rs
│ │ ├── patient_doctor_relation.rs
│ │ ├── doctor_profile.rs
│ │ ├── health_record.rs
│ │ ├── vital_signs.rs
│ │ ├── lab_report.rs
│ │ ├── health_trend.rs
│ │ ├── appointment.rs
│ │ ├── doctor_schedule.rs
│ │ ├── follow_up_task.rs
│ │ ├── follow_up_record.rs
│ │ ├── consultation_session.rs
│ │ └── consultation_message.rs
│ ├── service/ ← 业务逻辑
│ │ ├── mod.rs
│ │ ├── patient_service.rs
│ │ ├── health_data_service.rs
│ │ ├── appointment_service.rs
│ │ ├── follow_up_service.rs
│ │ └── consultation_service.rs
│ ├── handler/ ← Axum 路由
│ │ ├── mod.rs
│ │ ├── patient_handler.rs
│ │ ├── health_data_handler.rs
│ │ ├── appointment_handler.rs
│ │ ├── follow_up_handler.rs
│ │ └── consultation_handler.rs
│ ├── dto/ ← 请求/响应结构体
│ │ ├── mod.rs
│ │ ├── patient_dto.rs
│ │ ├── health_data_dto.rs
│ │ ├── appointment_dto.rs
│ │ ├── follow_up_dto.rs
│ │ └── consultation_dto.rs
│ └── event.rs ← 事件定义和处理器
```
---
## 8. 权限定义
### 8.1 权限码
| 权限码 | 名称 | 说明 |
|--------|------|------|
| `health.patient.list` | 查看患者列表 | 查看和搜索患者列表、详情 |
| `health.patient.manage` | 管理患者 | 创建、编辑、删除患者 |
| `health.health-data.list` | 查看健康数据 | 查看体检记录、监测数据、化验报告 |
| `health.health-data.manage` | 管理健康数据 | 录入、编辑、删除健康数据 |
| `health.appointment.list` | 查看预约 | 查看预约列表和排班 |
| `health.appointment.manage` | 管理预约 | 创建、确认、取消预约 |
| `health.follow-up.list` | 查看随访 | 查看随访任务和记录 |
| `health.follow-up.manage` | 管理随访 | 创建、分配、完成随访任务 |
| `health.consultation.list` | 查看咨询 | 查看咨询会话和消息记录 |
| `health.consultation.manage` | 管理咨询 | 关闭会话、导出记录 |
| `health.doctor.list` | 查看医护 | 查看医护列表和详情 |
| `health.doctor.manage` | 管理医护 | 创建、编辑医护档案、排班 |
### 8.2 数据范围
| 实体 | 支持的数据范围级别 | 说明 |
|------|-------------------|------|
| patient | self, department, department_tree, all | 医生只能看自己负责的患者或本科室患者 |
| follow_up_task | self, department, department_tree, all | 医护只能看分配给自己的随访任务 |
| appointment | self, department, department_tree, all | 按科室隔离预约数据 |
### 8.3 角色模板
| 角色 | 权限 |
|------|------|
| health_admin | 全部 health.* 权限 |
| doctor | health.patient.list, health.health-data.*, health.appointment.list, health.follow-up.*, health.consultation.list, health.doctor.list |
| nurse | health.patient.list, health.health-data.*, health.follow-up.*, health.appointment.list |
| receptionist | health.patient.*, health.appointment.*, health.doctor.list |
---
## 9. 能力扩展
V1 需要新增以下基础能力(在 erp-core 或独立模块中):
1. **文件上传服务** — 文件存储(本地/OSS、URL 生成、图片缩略图
2. **趋势分析** — 时序数据聚合、异常检测逻辑
3. **报告批注** — 医生对化验报告的解读/批注能力
4. **导出增强** — 健康数据导出为 Excel/PDF
---
## 10. 实施步骤
### Phase 1: 项目初始化
- 拷贝 ERP 到 hms
- 验证编译和构建
### Phase 2: erp-health 骨架
- 创建 crate 结构
- 实现 ErpModule trait + `public_routes()` / `protected_routes()` 固有方法
- 注册到 workspace
### Phase 3: 数据库迁移
- 16 张表14 业务实体 + 2 关联表)的迁移文件
- 索引创建、唯一约束
### Phase 4: 业务逻辑(按域迭代)
- ① 患者与医护管理
- ② 健康数据管理
- ③ 预约排班
- ④ 随访管理
- ⑤ 咨询管理
### Phase 5: 前端页面
- 13 个自定义 React 页面
- 路由注册和侧边栏菜单
### Phase 6: 集成测试
- API 端点测试
- 多租户隔离验证
- 端到端功能验证