244 lines
9.6 KiB
Markdown
244 lines
9.6 KiB
Markdown
# HMS 功能审计 — Phase 5: 五种差距模式识别
|
||
|
||
> 日期: 2026-04-30 | 审计范围: 全系统差距模式分析
|
||
|
||
## 总览
|
||
|
||
基于 Phase 0-4 的审计数据,系统性检测五种常见差距模式。
|
||
|
||
---
|
||
|
||
## 1. 模式 1:"写了没接" — 后端路由无前端调用者
|
||
|
||
### 检测方法
|
||
|
||
集合差运算:`backend_routes - web_api_calls - mp_api_calls`
|
||
|
||
### 发现
|
||
|
||
| 路由 | 模块 | 说明 | 严重性 |
|
||
|------|------|------|--------|
|
||
| `POST /health/patients/{id}/trends/generate` | erp-health | 趋势报告生成,无前端调用。可能为后台定时任务触发 | LOW |
|
||
| `POST /ai/analyze/vital-signs` | erp-ai | SSE 端点,Web 和小程序均无 UI 调用 | MEDIUM |
|
||
| `POST /ai/analyze/lab-report` | erp-ai | 同上 | MEDIUM |
|
||
| `POST /ai/analyze/health-trend` | erp-ai | 同上 | MEDIUM |
|
||
| `POST /ai/analyze/health-summary` | erp-ai | 同上 | MEDIUM |
|
||
|
||
**AI 分析 SSE 端点说明**:4 个 AI 分析端点通过 SSE 流式返回结果。前端未调用是因为 AI 分析功能可能仅通过 API 工具(如 Swagger UI)直接测试。这些端点的后端实现完整(含权限检查 `ai.analysis.manage`),但缺少前端管理界面的触发入口。
|
||
|
||
**趋势生成说明**:`POST .../trends/generate` 可能设计为后台任务调用(如定时生成趋势报告),而非前端直接触发。
|
||
|
||
### 统计
|
||
|
||
| 类别 | 数量 |
|
||
|------|------|
|
||
| 孤立后端路由(无任何前端调用) | 5 |
|
||
| 其中 AI SSE 端点 | 4 |
|
||
| 其中后台任务路由 | 1 |
|
||
|
||
---
|
||
|
||
## 2. 模式 2:"接了没传" — 前端调用但参数传递不完整
|
||
|
||
### 检测方法
|
||
|
||
搜索前端 API 调用中空参数传递、缺失 header、字段遗漏。
|
||
|
||
### 发现
|
||
|
||
#### 2.1 小程序 vital_signs 字段遗漏(6 个)
|
||
|
||
已在 Phase 4 §4.3 详细分析。核心问题:`indicator_type` 模型无法传递晚间血压、体温、血氧等字段。
|
||
|
||
#### 2.2 小程序 X-Patient-Id / X-Tenant-Id Header
|
||
|
||
小程序通过 `request.ts` 拦截器统一注入 `X-Patient-Id` 和 `X-Tenant-Id` header。经检查:
|
||
- 所有患者端 API 调用均通过 `request.ts` 封装,header 注入正常
|
||
- 医护端 API 调用使用独立的 `doctorRequest` 实例,header 注入机制一致
|
||
|
||
#### 2.3 后端 DTO 字段前端未传递(低风险)
|
||
|
||
| 端点 | 后端 DTO 字段 | 前端行为 | 风险 |
|
||
|------|-------------|---------|------|
|
||
| `POST /vital-signs` | blood_sugar_type | 小程序不传,后端默认 NULL | LOW |
|
||
| `POST /vital-signs` | source | 小程序不传,后端默认 "manual" | LOW |
|
||
| `POST /device-readings/batch` | raw_data | 前端传递完整 JSON | ✓ |
|
||
|
||
### 统计
|
||
|
||
| 类别 | 数量 |
|
||
|------|------|
|
||
| 前端字段遗漏(HIGH) | 2(晚间血压) |
|
||
| 前端字段遗漏(MEDIUM) | 2(体温、血氧) |
|
||
| 前端字段遗漏(LOW) | 2(血糖类型、来源) |
|
||
| Header 注入问题 | 0 |
|
||
|
||
---
|
||
|
||
## 3. 模式 3:"传了没存" — 数据传递但未完整持久化
|
||
|
||
### 检测方法
|
||
|
||
追踪 4 条关键写入路径:小程序体征录入、Web 创建预约、BLE 设备同步、每日签到。
|
||
|
||
### 路径 1:小程序体征录入
|
||
|
||
```
|
||
inputVitalSign() → POST /health/patients/{id}/vital-signs
|
||
→ health_data_handler::create_vital_signs()
|
||
→ health_data_service::create_vital_signs()
|
||
→ INSERT vital_signs
|
||
```
|
||
|
||
**结果**:✅ 晨间血压/心率/体重/血糖/饮水量/尿量正常写入。❌ 晚间血压/体温/血氧未写入(前端未传)。
|
||
|
||
### 路径 2:Web 创建预约
|
||
|
||
```
|
||
AppointmentList → POST /health/appointments
|
||
→ appointment_handler::create_appointment()
|
||
→ appointment_service::create_appointment()
|
||
→ CAS 原子检查 slot_available → INSERT appointment
|
||
```
|
||
|
||
**结果**:✅ 完整。含 CAS 并发控制、乐观锁、事务保证。
|
||
|
||
### 路径 3:BLE 设备同步
|
||
|
||
```
|
||
BLE scan → uploadReadings() → POST /health/patients/{id}/device-readings/batch
|
||
→ device_reading_handler::batch_create()
|
||
→ device_reading_service::sync_readings()
|
||
→ INSERT device_readings + UPSERT vital_signs_hourly
|
||
```
|
||
|
||
**结果**:✅ 完整。批量插入 + 小时聚合 + 事件发布。
|
||
|
||
### 路径 4:每日签到
|
||
|
||
```
|
||
checkin() → POST /health/points/checkin
|
||
→ points_handler::daily_checkin()
|
||
→ points_service::daily_checkin()
|
||
→ INSERT/UPDATE points_checkin + INSERT points_transaction
|
||
```
|
||
|
||
**结果**:✅ 完整。幂等检查(同日不可重复签到)+ 事务保证 + 事件发布。
|
||
|
||
### 统计
|
||
|
||
| 路径 | 结果 |
|
||
|------|------|
|
||
| 体征录入 | 部分数据丢失(晚间血压等) |
|
||
| 创建预约 | ✅ 完整 |
|
||
| BLE 同步 | ✅ 完整 |
|
||
| 每日签到 | ✅ 完整 |
|
||
|
||
---
|
||
|
||
## 4. 模式 4:"存了没用" — 数据持久化但未被消费
|
||
|
||
### 检测方法
|
||
|
||
检查写入了但从未被读取或展示的数据。
|
||
|
||
### 发现
|
||
|
||
#### 4.1 事件无消费者(14 个)
|
||
|
||
已在 Phase 3 §4.2 详细分析。14 个事件被发布到 EventBus 但没有业务消费者:
|
||
- `patient.updated` — 信息性事件,更新已直接处理
|
||
- `consultation.*`(3 个) — 会话管理已在 service 内直接处理
|
||
- `article.published/rejected` — 状态已更新
|
||
- `points.earned/exchanged/expired`(3 个) — 积分操作已完成
|
||
- 其余 5 个同类型
|
||
|
||
**评估**:这些事件通过 SSE 推送到前端,用于实时通知,不完全是"没用"。但没有专门的后端消费者处理后续业务逻辑。
|
||
|
||
#### 4.2 数据库字段未读取
|
||
|
||
| 字段 | 表 | 写入场景 | 读取场景 | 状态 |
|
||
|------|-----|---------|---------|------|
|
||
| raw_data | device_readings | BLE 同步时写入 | 无专门查询 | MEDIUM |
|
||
| revoke_reason | consent | 撤回知情同意时写入 | 列表查询返回 | ✓ 已用 |
|
||
| model_config | ai_prompt | 创建/更新 Prompt 时写入 | 分析时读取 model/temperature/max_tokens | ✓ 已用 |
|
||
| article_revision | article_revision | 文章编辑时写入 | GET .../revisions 端点返回 | ✓ 已用 |
|
||
|
||
**raw_data 字段说明**:`device_readings.raw_data` 存储 BLE 设备原始 JSONB 数据。当前无专门的读取/分析页面。价值在于数据溯源和异常排查,但在 UI 层面无入口。
|
||
|
||
#### 4.3 entity 字段从未构造
|
||
|
||
Phase 2 发现 `RefRow` struct 从未构造(编译器警告),属于重构残留。
|
||
|
||
### 统计
|
||
|
||
| 类别 | 数量 | 影响 |
|
||
|------|------|------|
|
||
| 无消费者事件 | 14 | LOW(SSE 推送 + 审计追踪仍有价值) |
|
||
| 未读取数据库字段 | 1(raw_data) | MEDIUM(数据溯源需要但无 UI 入口) |
|
||
| 死代码 struct | 1(RefRow) | LOW(编译器警告,重构残留) |
|
||
|
||
---
|
||
|
||
## 5. 模式 5:"双系统不同步" — Web 与小程序实现差异
|
||
|
||
### 检测方法
|
||
|
||
对比共享功能在 Web 和小程序的实现差异,区分"角色分叉(正常)"和"实现缺陷"。
|
||
|
||
### 5.1 角色分叉(正常差异)
|
||
|
||
| 功能 | Web(管理端) | 小程序(患者/医护端) | 差异类型 |
|
||
|------|-------------|-------------------|---------|
|
||
| 积分管理 | 规则 CRUD + 商品管理 + 订单核销 | 签到 + 兑换 + 查看订单 | 角色分叉 ✓ |
|
||
| 文章管理 | CMS 全流程(创建/编辑/审核/发布) | 只读列表(仅 published) | 角色分叉 ✓ |
|
||
| 告警管理 | 规则配置 + 仪表盘 + 处置 | 查看自身告警 + 处理 | 角色分叉 ✓ |
|
||
| 设备管理 | 列表 + 解绑 | BLE 扫描 + 同步 | 平台差异 ✓ |
|
||
| 预约管理 | 全 CRUD + 排班配置 | 创建/查看/取消预约 | 角色分叉 ✓ |
|
||
| 医生管理 | 档案 CRUD + 排班管理 | 查看排班日历 | 角色分叉 ✓ |
|
||
|
||
### 5.2 实现缺陷(需修复)
|
||
|
||
| 功能 | Web | 小程序 | 差异类型 | 优先级 |
|
||
|------|-----|--------|---------|--------|
|
||
| 体征录入 | 结构化表单(所有字段独立输入) | indicator_type 映射(丢失晚间血压/体温/血氧) | **数据模型差异** | P1 |
|
||
| 咨询消息 | 列表 + 详情 + 导出 | 列表 + 详情(无导出) | 功能缺失 | P3 |
|
||
| 透析管理 | 完整 CRUD + 审阅 | **无任何入口** | **功能缺失** | P1 |
|
||
| 知情同意 | 完整 CRUD | **无任何入口** | **功能缺失** | P1 |
|
||
| 健康记录 | 完整 CRUD | **无任何入口** | 功能缺失 | P2 |
|
||
| 诊断记录 | 完整 CRUD | **无任何入口** | 功能缺失 | P2 |
|
||
| 药物管理 | 完整 CRUD | 有页面但 API 调用不明确 | 待验证 | P2 |
|
||
| 权限码拼写 | `health.alerts.manage`(正确) | —(前端用 `health.alert.manage`) | **拼写错误** | P1 |
|
||
|
||
### 5.3 透析管理 — 最大差距
|
||
|
||
透析是唯一一个**后端完整实现但小程序完全空白**的功能域:
|
||
- 后端:12 个路由(记录 CRUD + 处方 CRUD + 审阅 + 统计)
|
||
- Web:完整管理界面(DialysisManageList)
|
||
- 小程序:0 个 API 调用、0 个页面
|
||
|
||
**影响**:透析患者无法在移动端查看自己的透析记录和处方,医护无法在小程序端录入透析数据。
|
||
|
||
### 统计
|
||
|
||
| 差异类型 | 数量 |
|
||
|---------|------|
|
||
| 角色分叉(正常) | 6 |
|
||
| 数据模型差异 | 1 |
|
||
| 功能缺失(P1) | 3(透析/知情同意/体征映射) |
|
||
| 功能缺失(P2) | 3(健康记录/诊断/药物) |
|
||
| 功能缺失(P3) | 1(咨询导出) |
|
||
| 拼写错误 | 1 |
|
||
|
||
---
|
||
|
||
## 6. 差距模式汇总评分
|
||
|
||
| 模式 | 严重程度 | 发现数 | 评分 |
|
||
|------|---------|--------|------|
|
||
| 模式 1: 写了没接 | LOW-MEDIUM | 5 | 95%(仅 AI SSE 和趋势生成孤立) |
|
||
| 模式 2: 接了没传 | HIGH-LOW | 6 | 75%(晚间血压数据丢失是关键缺陷) |
|
||
| 模式 3: 传了没存 | LOW | 1 | 95%(仅体征部分字段未传导致未存) |
|
||
| 模式 4: 存了没用 | LOW | 16 | 85%(大部分事件有 SSE 消费者,raw_data 待利用) |
|
||
| 模式 5: 双系统不同步 | HIGH-LOW | 9 | 65%(透析/知情同意完全缺失,体征映射丢失) |
|