docs(specs): 7 份设计规格 — 工作台/适老化/硬编码清理/项目分析
新增: 适老化小程序/Action Inbox/统一工作台/医生操作台/ 硬编码清理/健康管理台/全项目深度分析报告
This commit is contained in:
@@ -0,0 +1,213 @@
|
||||
# HMS 小程序患者端 — 老年友好版本设计规格
|
||||
|
||||
> 日期: 2026-04-30 | 状态: 待实施 | 选定方案: A(健康 Tab 导航)
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
患者端小程序面向 60+ 慢病患者群体,当前版本信息密度高、字号小、导航层级深(5 Tab + 40 页),老年用户难以独立使用。基于多专家组(UX 无障碍、老年医学、产品策略)头脑风暴,选定方案 A 进行全面重设计。
|
||||
|
||||
**核心目标:**
|
||||
- 老年患者能独立完成日常操作(记录体征、查看数据、预约挂号、服药提醒)
|
||||
- 每个核心操作路径不超过 3 步
|
||||
- 满足 WCAG 2.1 AA 对比度要求
|
||||
|
||||
## 2. 导航结构
|
||||
|
||||
**4 Tab:首页 / 健康 / 消息 / 我的**
|
||||
|
||||
| Tab | 名称 | 核心内容 | 页面文件 |
|
||||
|-----|------|---------|---------|
|
||||
| 1 | 首页 | 今日打卡 + 体征 2x2 + 快捷操作 | `pages/index/index.tsx` |
|
||||
| 2 | 健康 | 体征录入 + 趋势图 + BLE 设备 | `pages/health/index.tsx`(重写) |
|
||||
| 3 | 消息 | 咨询对话 + 系统通知 | `pages/messages/index.tsx`(新建) |
|
||||
| 4 | 我的 | 个人信息 + 积分 + 菜单 | `pages/profile/index.tsx`(调整) |
|
||||
|
||||
**Tab 迁移映射:**
|
||||
|
||||
| 当前 Tab | 操作 | 去向 |
|
||||
|----------|------|------|
|
||||
| 首页 (index) | 保留,重写 | — |
|
||||
| 上报 (health) | 重命名为"健康",重写 | 合并录入功能 |
|
||||
| 咨询 (consultation) | 从 Tab 移除 | 合并到"消息"Tab 的"咨询"子 Tab |
|
||||
| 商城 (mall) | 从 Tab 移除 | 降级为"我的"页菜单项,`pkg-mall` 子包保留 |
|
||||
| 我的 (profile) | 保留,调整间距 | — |
|
||||
| (新增) 消息 | 新建 Tab + 页面 | `pages/messages/index.tsx` |
|
||||
|
||||
**说明:** `pages/consultation/` 目录及 `pages/consultation/detail/` 保留为路由页面(非 Tab),从消息页的"咨询"子 Tab 导航进入。`pkg-mall` 子包(兑换/订单/详情)全部保留,从"我的"页菜单入口进入。
|
||||
|
||||
## 3. 首页设计
|
||||
|
||||
5 个区域,从上到下:
|
||||
|
||||
1. **问候 + 日期** — "上午好,张大爷" 24px 粗体 + 日期 + 消息红点
|
||||
2. **今日体征完成度** — 圆形进度环(72px)+ 完成百分比 + 4 指标胶囊(血压/心率/血糖/体重)
|
||||
- **计算逻辑(纯前端):** 查询当日体征数据 API,4 个指标(血压/心率/血糖/体重)中当天有记录的计为完成,进度 = 已完成数 / 4
|
||||
- **与积分签到的区别:** 这是"今日体征记录完成度"(纯展示),不是积分商城的"每日签到"(`usePointsStore.checkinStatus`)。两者独立,不耦合。
|
||||
- **无需新后端 API:** 复用现有 `getHealthSummary` 或当日体征查询接口,前端计算百分比。
|
||||
3. **今日体征 2x2** — 白色卡片网格,数值 32px 衬线体,状态标签(正常/偏高/未记录)
|
||||
4. **今日待办(≤3条)** — 预约/随访/异常提醒,带图标和副标题
|
||||
5. **快捷操作** — 两个大按钮:"记录体征"(实色)+ "预约挂号"(描边)
|
||||
|
||||
**首页不放置的内容(从当前首页移除):**
|
||||
- 设备快捷入口(血压计/血糖仪卡片)→ 移至"健康"Tab
|
||||
- 6 项快捷服务网格(预约挂号/健康录入/趋势/告警/资讯/AI)→ 精简为 2 个核心按钮
|
||||
- 健康资讯文章列表 → 入口移至"健康"Tab 底部或"我的"页
|
||||
|
||||
## 4. 健康页设计
|
||||
|
||||
**功能定位:** 体征数据录入 + 趋势查看 + 设备管理
|
||||
|
||||
### 4.1 录入区
|
||||
- 顶部类型 Tab:血压 / 心率 / 血糖 / 体重(56px 高大 Tab,选中项 $pri 实色底白字)
|
||||
- 血压:收缩压 + 舒张压两个大输入框(56px 高,数值 28px 衬线体),上下排列(非左右,防止老年用户填反)
|
||||
- 心率/体重:单个大输入框
|
||||
- 血糖:数值 + 时段选择(空腹/餐后 2h,大按钮组)
|
||||
- 每个输入框下方显示参考范围和实时状态(正常/偏高/偏低)
|
||||
- 保存按钮:全宽 56px 高 $pri 实色
|
||||
- 异常值保存前弹出确认:"血压偏高 (160/95),确认提交?"
|
||||
|
||||
### 4.2 趋势图
|
||||
- 复用现有 `getTrend` API
|
||||
- 7 天柱状图,异常值用 $wrn 色,正常用 $pri 色
|
||||
- 底部显示周一到周日标签
|
||||
|
||||
### 4.3 BLE 设备
|
||||
- 从首页移入此区域
|
||||
- 连接状态卡片:设备图标 + 名称 + 连接状态
|
||||
- 一键同步按钮
|
||||
- 设备管理入口(跳转 `pkg-device-sync`)
|
||||
|
||||
### 4.4 健康资讯入口
|
||||
- 从首页移入,放在页面底部
|
||||
- 单行卡片:"最新健康资讯 ›" 点击跳转文章列表
|
||||
|
||||
## 5. 消息页设计
|
||||
|
||||
**新页面,合并咨询 + 系统通知。**
|
||||
|
||||
- 顶部 Tab 切换:"咨询" | "通知"(56px 大 Tab)
|
||||
- 咨询列表:对话卡片 80px 高,文字 28px,未读红点 24px
|
||||
- 通知列表:随访提醒、预约确认、异常告警、用药提醒
|
||||
|
||||
## 6. 我的页设计
|
||||
|
||||
保留现有结构,调整参数:
|
||||
- 菜单项高度 48px → 64px
|
||||
- 文字 28px
|
||||
- 图标 40px
|
||||
- 积分 + 连续打卡横排展示
|
||||
|
||||
## 7. 设计系统调整
|
||||
|
||||
### 7.1 字号
|
||||
|
||||
> **单位说明:** 代码库统一使用 `px`(Taro 的 `pxtransform` 编译时自动转为 rpx)。以下所有值均为 `px`。
|
||||
|
||||
| 用途 | 当前(px) | 调整为(px) |
|
||||
|------|----------|-----------|
|
||||
| 问候/标题 | 26 | 28 |
|
||||
| 区块标题 | 24 | 26 |
|
||||
| 正文 | 22 | 24 |
|
||||
| 辅助文字 | 20 | 22 |
|
||||
| 体征数值 | 44 | 48-64 |
|
||||
| 按钮文字 | 24 | 28 |
|
||||
| **最小字号** | 20 | **22** |
|
||||
|
||||
### 7.2 间距与触控
|
||||
|
||||
| 参数 | 当前 | 调整为 |
|
||||
|------|------|--------|
|
||||
| 按钮最小高度 | — | 48px(120rpx) |
|
||||
| 主按钮高度 | — | 56px(140rpx) |
|
||||
| 菜单项高度 | 48px | 64px(160rpx) |
|
||||
| 卡片圆角 | 12px | 16px |
|
||||
| 卡片内间距 | 24-28px | 28-32px |
|
||||
| 列表项间距 | 16px | 20px |
|
||||
|
||||
### 7.3 色彩
|
||||
|
||||
> **对比度基于 `$bg` #F5F0EB 计算。** WCAG 2.1 AA 要求:正文(<24px)≥ 4.5:1,大字(≥24px)≥ 3:1。
|
||||
|
||||
| 变量 | 当前 | 调整为 | 对比度 | WCAG |
|
||||
|------|------|--------|--------|------|
|
||||
| `$tx2` | #7A756E | #5A554F | ~5.5:1 | AA 正文 |
|
||||
| `$tx3` | #A8A29E | #78716C | ~4.6:1 | AA 正文 |
|
||||
| `$pri` | #C4623A | **不变** | — | — |
|
||||
| `$bg` | #F5F0EB | **不变** | — | — |
|
||||
|
||||
**使用约束:** `$tx3` 仅用于 24px 及以上的文字或装饰性标签。正文一律使用 `$tx2` 或 `$tx`。
|
||||
|
||||
## 8. 功能优先级
|
||||
|
||||
| 优先级 | 功能 | 状态 |
|
||||
|--------|------|------|
|
||||
| P0 | 体征数据查看(2x2 卡片) | 重写首页 |
|
||||
| P0 | 体征录入(大输入框) | 重写健康页 |
|
||||
| P0 | 今日体征完成度(进度环) | 新增(纯前端,复用现有 API) |
|
||||
| P1 | 今日待办(≤3 条) | 新增 |
|
||||
| P1 | 消息中心(咨询+通知) | 新建页面 |
|
||||
| P1 | BLE 设备同步 | 保留调整 |
|
||||
| P2 | 趋势图简化 | 调整 |
|
||||
| P2 | 用药提醒 | 保留 |
|
||||
| P3 | 积分商城 | 降级为菜单项 |
|
||||
|
||||
## 9. 页面路由变更
|
||||
|
||||
### TabBar 配置(app.config.ts)
|
||||
|
||||
```
|
||||
5 Tab → 4 Tab
|
||||
删除:上报(health)、商城(mall)
|
||||
新增:消息(messages)
|
||||
保留:首页(index)、健康(health → 重写)、我的(profile)
|
||||
```
|
||||
|
||||
### 页面增减
|
||||
|
||||
| 操作 | 页面 |
|
||||
|------|------|
|
||||
| 新建 | `pages/messages/index.tsx` |
|
||||
| 重写 | `pages/index/index.tsx`、`pages/health/index.tsx` |
|
||||
| 调整 | `pages/profile/index.tsx` |
|
||||
| 删除 Tab | `pages/mall/index.tsx`(降级为子页面) |
|
||||
| 保留 | 所有 `pkg-*` 子包页面 |
|
||||
|
||||
## 10. 关键文件
|
||||
|
||||
| 文件 | 改动类型 |
|
||||
|------|---------|
|
||||
| `apps/miniprogram/src/app.config.ts` | TabBar 5→4,路由调整 |
|
||||
| `apps/miniprogram/src/styles/variables.scss` | 字号/色值/间距调整 |
|
||||
| `apps/miniprogram/src/styles/mixins.scss` | 新增老年友好 mixin |
|
||||
| `apps/miniprogram/src/pages/index/index.tsx` | 首页全面重写 |
|
||||
| `apps/miniprogram/src/pages/index/index.scss` | 首页样式全面重写 |
|
||||
| `apps/miniprogram/src/pages/health/index.tsx` | 健康页重写 |
|
||||
| `apps/miniprogram/src/pages/health/index.scss` | 健康页样式重写 |
|
||||
| `apps/miniprogram/src/pages/messages/index.tsx` | **新建**消息页 |
|
||||
| `apps/miniprogram/src/pages/messages/index.scss` | **新建**消息页样式 |
|
||||
| `apps/miniprogram/src/pages/profile/index.tsx` | 调整菜单和间距 |
|
||||
| `apps/miniprogram/src/services/consultation.ts` | 消息页复用咨询列表 API |
|
||||
| `apps/miniprogram/src/services/health.ts` | 复用体征数据查询(打卡进度) |
|
||||
| `apps/miniprogram/src/stores/points.ts` | 签到/积分功能保留,不改动 |
|
||||
| `apps/miniprogram/src/components/` | 新增 ProgressRing 组件 |
|
||||
|
||||
## 11. 验证方式
|
||||
|
||||
1. `pnpm build` — 小程序编译通过
|
||||
2. 微信开发者工具预览 — 布局和字号正确
|
||||
3. 真机测试 — 在 60+ 患者手机上验证可读性和触控体验
|
||||
4. WCAG 2.1 AA — 色值对比度合规(≥4.5:1 正文,≥3:1 大字),使用 axe-core 或微信开发者工具无障碍审计
|
||||
5. 核心路径验证(每条 ≤ 3 步):
|
||||
- 记录血压:首页 → 点击"记录体征" → 输入 → 保存(3 步)
|
||||
- 查看趋势:健康 Tab → 查看趋势图(1 步)
|
||||
- 预约挂号:首页 → 点击"预约挂号" → 选择时间 → 确认(3 步)
|
||||
- 查看消息:消息 Tab → 点击对话(2 步)
|
||||
6. 不同屏幕尺寸测试:特别是老年用户常用的小屏 Android 设备
|
||||
7. 字体回退验证:衬线体在低端 Android 设备上的回退(使用 `Georgia, "PingFang SC", serif`)
|
||||
|
||||
## 12. 迁移与发布策略
|
||||
|
||||
- 一次性全量发布(非 A/B 测试),因为 5 Tab → 4 Tab 是结构性变更,无法共存
|
||||
- 旧路径 `pages/consultation/`、`pages/mall/` 保留为路由页面,但不再从 TabBar 进入
|
||||
- 小程序分享卡片可能指向旧路径——这些页面保留可访问,不受影响
|
||||
- 发布前在测试环境完整走一遍所有核心路径
|
||||
401
docs/superpowers/specs/2026-05-01-action-inbox-design.md
Normal file
401
docs/superpowers/specs/2026-05-01-action-inbox-design.md
Normal file
@@ -0,0 +1,401 @@
|
||||
# 行动收件箱与上下文线程设计规格
|
||||
|
||||
> 日期: 2026-05-01 | 状态: Draft | 关联: `erp-health`, `erp-ai`, Web 前端, 小程序
|
||||
|
||||
## 1. 背景与问题
|
||||
|
||||
### 1.1 问题陈述
|
||||
|
||||
HMS 平台功能完善(328 路由、25 事件类型、97.5% 测试通过率),但用户体验存在**系统性流程断裂**:
|
||||
|
||||
- **告警 → 行动断裂**:医生看到告警后,无直接路径跳到查看患者→安排随访→记录处置
|
||||
- **数据录入 → 反馈断裂**:患者录入体征后无即时趋势对比和行动建议
|
||||
- **AI 建议 → 执行追踪断裂**:审批通过后,后续执行/追踪/结果反馈在 UI 上不可见
|
||||
|
||||
**根因**:前端交互模型是"功能陈列式"的——每个功能是死胡同,没有出口指向下一步。
|
||||
|
||||
### 1.2 设计目标
|
||||
|
||||
建立统一的**行动收件箱 + 上下文线程**机制,让每个"终点"变成"起点":
|
||||
|
||||
1. 用户登录后第一眼看到待处理事项(按优先级排列)
|
||||
2. 每个待办有清晰的时间线展示完整生命周期
|
||||
3. 时间线每一步都可直接跳转到对应功能页
|
||||
4. 操作按钮根据当前状态动态变化
|
||||
5. 架构可扩展——新增行动类型(告警/随访/异常)只需注册聚合器
|
||||
|
||||
### 1.3 范围
|
||||
|
||||
**Phase 1(本次)**:AI 建议闭环 — 后端已完整实现(10 次提交),补齐前端体验
|
||||
**Future**:告警处理闭环、体征反馈闭环、随访到期提醒
|
||||
|
||||
---
|
||||
|
||||
## 2. 设计概览
|
||||
|
||||
```
|
||||
事件源 → 行动收件箱服务 → 前端展示
|
||||
├── Web: 顶栏铃铛 → 列表页 → Drawer
|
||||
└── 小程序: "待办" Tab → 列表 → 半屏弹窗
|
||||
```
|
||||
|
||||
**核心抽象**:`ActionItem` — 统一的待办数据结构,不同类型共用相同接口
|
||||
**核心交互**:`Context Thread` — Drawer/半屏弹窗中的时间线,展示完整处理进度
|
||||
|
||||
---
|
||||
|
||||
## 3. 数据模型
|
||||
|
||||
### 3.1 ActionItem(聚合视图,不建新表)
|
||||
|
||||
```typescript
|
||||
interface ActionItem {
|
||||
id: string; // 格式: "{type}:{source_id}"
|
||||
type: "ai_suggestion" | "alert" | "followup" | "data_anomaly";
|
||||
priority: "urgent" | "high" | "medium" | "low";
|
||||
status: "pending" | "in_progress" | "completed" | "dismissed";
|
||||
title: string;
|
||||
summary: string;
|
||||
patient_id: string;
|
||||
patient_name: string;
|
||||
source_ref: string; // 指向原始实体 ID
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 ThreadEvent(上下文线程事件)
|
||||
|
||||
```typescript
|
||||
interface ThreadEvent {
|
||||
step: string; // "ai_analysis" | "doctor_approval" | "followup_scheduled" | "followup_completed" | "reanalysis"
|
||||
label: string; // 展示文本
|
||||
status: "completed" | "in_progress" | "pending";
|
||||
detail?: string; // 补充说明
|
||||
timestamp?: string; // 完成时间
|
||||
operator?: string; // 操作人
|
||||
link_to?: string; // 跳转路径
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 ActionDefinition(可用操作)
|
||||
|
||||
```typescript
|
||||
interface ActionDefinition {
|
||||
key: string; // "approve" | "reject" | "complete_early" | "acknowledge"
|
||||
label: string; // 按钮文本
|
||||
variant: "primary" | "danger" | "default";
|
||||
confirm_message?: string; // 确认弹窗文案
|
||||
api_endpoint: string; // 调用的 API
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 后端 API 设计
|
||||
|
||||
### 4.1 GET /api/v1/action-inbox
|
||||
|
||||
获取当前用户的行动收件箱列表。
|
||||
|
||||
**Query Params**:
|
||||
- `status`: `pending` | `in_progress` | `completed` | `dismissed`(可选,默认全部)
|
||||
- `type`: `ai_suggestion` | `alert` | `followup` | `data_anomaly`(可选,默认全部)
|
||||
- `page` / `page_size`: 分页(默认 1/20)
|
||||
|
||||
**Response**: `PaginatedResponse<ActionItem>`
|
||||
|
||||
**实现策略**:聚合查询,不建新表。Phase 1 只查 `ai_suggestion` 表:
|
||||
|
||||
```sql
|
||||
-- 注意:patient_id 在 ai_analysis 表上,不在 ai_suggestion 上,需三表 JOIN
|
||||
SELECT s.id, s.suggestion_type, s.risk_level, s.status, s.params,
|
||||
s.created_at, s.updated_at,
|
||||
p.name as patient_name, a.patient_id,
|
||||
a.result_content, a.analysis_type
|
||||
FROM ai_suggestion s
|
||||
JOIN ai_analysis a ON s.analysis_id = a.id
|
||||
JOIN patient p ON a.patient_id = p.id
|
||||
WHERE s.tenant_id = $1
|
||||
AND s.deleted_at IS NULL
|
||||
ORDER BY
|
||||
CASE s.risk_level WHEN 'high' THEN 1 WHEN 'medium' THEN 2 ELSE 3 END,
|
||||
s.created_at DESC
|
||||
```
|
||||
|
||||
### 4.2 GET /api/v1/action-inbox/:source_ref/thread
|
||||
|
||||
获取某个行动项的上下文线程。
|
||||
|
||||
**Response**:
|
||||
|
||||
```typescript
|
||||
interface ThreadResponse {
|
||||
action_item: ActionItem;
|
||||
thread: ThreadEvent[];
|
||||
available_actions: ActionDefinition[];
|
||||
}
|
||||
```
|
||||
|
||||
**线程拼装逻辑**(以 AI 建议为例):
|
||||
|
||||
| 步骤 | 数据来源 | 状态判断 |
|
||||
|------|---------|---------|
|
||||
| AI 分析完成 | `ai_analysis.status = 'completed'` | 始终 completed |
|
||||
| 医生审批 | `ai_suggestion.status` | Approved→completed, Pending→in_progress |
|
||||
| 执行安排 | `ai_suggestion.workflow_instance_id IS NOT NULL` | 有值→completed |
|
||||
| 等待随访 | `follow_up` 关联查询 | 根据随访状态判断 |
|
||||
| 再分析对比 | `ai_suggestion.reanalysis_id IS NOT NULL` | 有值→completed |
|
||||
|
||||
**操作按钮动态生成**:
|
||||
|
||||
| 建议状态 | 可用操作 |
|
||||
|---------|---------|
|
||||
| Pending | 批准(→ `POST /ai/suggestions/:id/approve`)、拒绝 |
|
||||
| Approved/执行中 | 提前完成随访、标记已知悉 |
|
||||
| Executed | 查看前后对比报告 |
|
||||
| Expired/Rejected/ParseFailed | 无操作(只读展示) |
|
||||
| Executed | 查看前后对比报告 |
|
||||
| Expired | 无操作 |
|
||||
|
||||
### 4.3 代码归属与权限码
|
||||
|
||||
**代码位置**:
|
||||
- `ActionInboxService` → `crates/erp-health/src/service/action_inbox_service.rs`(erp-health crate)
|
||||
- `ActionInboxHandler` → `crates/erp-health/src/handler/action_inbox_handler.rs`
|
||||
- 路由注册:在 `erp-health` 模块的 `protected_routes()` 中新增
|
||||
- 跨 crate 查询:通过 raw SQL 直接查 `ai_suggestion` + `ai_analysis` 表(与现有 `ai_suggestion_loader.rs` 模式一致,erp-health 已有跨 crate 读 ai 表的先例)
|
||||
|
||||
**权限码**:新增独立权限码,注册在 `erp-health` 模块的 `permissions()` 中:
|
||||
- `health.action_inbox.list` — 查看行动收件箱
|
||||
- `health.action_inbox.manage` — 执行操作(审批/拒绝/标记已知悉)
|
||||
|
||||
理由:`action-inbox` 是聚合端点,未来包含告警/随访/异常等多种类型,不应绑定到 `ai.suggestion.*` 权限。用 `health.` 前缀与 erp-health crate 归属一致。
|
||||
|
||||
**用户范围**:
|
||||
- Phase 1(AI 建议):返回当前租户下所有有权限查看的待办(`ai_suggestion` 无 `assigned_to` 字段)
|
||||
- Future(告警/随访):告警有 `assigned_to` 关联的负责医生,随访有 `assigned_to` 字段,届时 API 增加 `scope` 参数(`all` | `mine`)
|
||||
|
||||
---
|
||||
|
||||
## 5. Web 前端设计
|
||||
|
||||
### 5.1 入口改造:NotificationPanel 扩展
|
||||
|
||||
**现有**:`apps/web/src/components/NotificationPanel.tsx`(铃铛 + Popover,SSE 推送消息/告警)
|
||||
|
||||
**改造**:
|
||||
- Popover 中增加"待办"区域,显示最近 3 条 ActionItem
|
||||
- 底部增加"查看全部待办"链接,跳转到 `/action-inbox` 页面
|
||||
- 角标数字改为:未读消息数 + 待处理 ActionItem 数
|
||||
|
||||
### 5.2 新增页面:ActionInboxPage
|
||||
|
||||
**路由**:`/action-inbox`
|
||||
|
||||
**组件**:`apps/web/src/pages/ActionInboxPage.tsx`
|
||||
|
||||
**布局**:
|
||||
- 顶部:筛选栏(状态 Tab + 类型下拉)
|
||||
- 主体:Ant Design List 组件,每项显示:
|
||||
- 类型标签(颜色区分)
|
||||
- 标题 + 患者姓名
|
||||
- 优先级标记
|
||||
- 创建时间
|
||||
- 点击 → 打开 Drawer
|
||||
|
||||
### 5.3 新增组件:ActionThreadDrawer
|
||||
|
||||
**组件**:`apps/web/src/components/ActionThreadDrawer.tsx`
|
||||
|
||||
**实现**:Ant Design Drawer + Ant Design Steps/Timeline
|
||||
|
||||
**结构**:
|
||||
```
|
||||
Drawer (width 480px)
|
||||
├── 头部:标题 + 患者摘要卡(年龄/最近体征/关键指标)
|
||||
├── 时间线:Ant Design Timeline 组件
|
||||
│ ├── 每个节点:状态图标 + 文本 + 时间 + 跳转链接
|
||||
│ └── 当前步骤高亮,未来步骤灰色
|
||||
├── 关联信息:可点击跳转的快捷链接
|
||||
└── 操作区:动态按钮组
|
||||
```
|
||||
|
||||
**状态设计**:
|
||||
- **加载中**:Ant Design Skeleton(3 行卡片骨架屏)
|
||||
- **数据获取失败**:Ant Design Result + 重试按钮
|
||||
- **空列表**:插图 + "暂无待办事项"文案
|
||||
- **操作按钮请求中**:按钮 loading 状态 + 禁用
|
||||
|
||||
### 5.4 实时更新策略
|
||||
|
||||
**Phase 1(轮询)**:用户手动刷新或切换页面时重新拉取列表。Drawer 打开时,操作按钮点击后主动调用 `GET /action-inbox/:id/thread` 刷新时间线。
|
||||
|
||||
**Phase 2(SSE 优化)**:复用 `apps/web/src/stores/message.ts` 中的 SSE 连接。后端在建议状态变更时,通过事件总线发布 → 消息服务推送到 SSE 流。前端监听 `suggestion.status_changed` 事件,触发列表/Drawer 刷新。
|
||||
|
||||
Phase 1 选择轮询的理由:现有 SSE 只推送 `message` 和 `alert` 两种类型,新增 `suggestion` 事件需要后端消息服务改造,且 Phase 1 的使用场景(医生不频繁审批)对实时性要求不高。
|
||||
|
||||
---
|
||||
|
||||
## 6. 小程序设计
|
||||
|
||||
### 6.1 TabBar 改造
|
||||
|
||||
**当前**:首页 | 健康 | 消息 | 我的(4 Tab)
|
||||
**新**:首页 | 健康 | 待办 | 消息 | 我的(5 Tab)
|
||||
|
||||
- 在"健康"和"消息"之间插入"待办"Tab
|
||||
- Tab 图标:`todo-list` 或 `check-circle`
|
||||
- 角标显示待处理数量(调用 `GET /action-inbox?status=pending` 获取计数)
|
||||
- 修改文件:`apps/miniprogram/src/app.config.ts`
|
||||
|
||||
### 6.2 新增页面:待办列表
|
||||
|
||||
**路径**:`apps/miniprogram/src/pages/action-inbox/index.tsx`
|
||||
|
||||
**布局**:
|
||||
- 顶部:状态筛选 Tab(全部 | 待处理 | 进行中 | 已完成)
|
||||
- 列表:按优先级排序的待办卡片
|
||||
- 每张卡片:类型标签 + 标题 + 患者名 + 时间 + 箭头
|
||||
- 点击卡片 → 弹出半屏弹窗
|
||||
|
||||
### 6.3 新增组件:ActionHalfScreenDialog
|
||||
|
||||
使用 Taro `half-screen-dialog` 组件或自定义半屏弹窗:
|
||||
|
||||
```
|
||||
半屏弹窗
|
||||
├── 头部:拖拽条 + 类型标签 + 标题
|
||||
├── 摘要:关键信息(患者/风险等级/时间)
|
||||
├── 时间线:简化版(只显示已完成和当前步骤)
|
||||
├── 操作按钮
|
||||
└── 底部:跳转详情链接
|
||||
```
|
||||
|
||||
### 6.4 Service 层
|
||||
|
||||
**文件**:`apps/miniprogram/src/services/action-inbox.ts`
|
||||
|
||||
```typescript
|
||||
// 复用现有 listPendingSuggestions()
|
||||
// 新增:
|
||||
listActionItems(params: { status?: string; type?: string; page: number })
|
||||
→ GET /api/v1/action-inbox
|
||||
|
||||
getActionThread(sourceRef: string)
|
||||
→ GET /api/v1/action-inbox/:source_ref/thread
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 数据映射详细规则
|
||||
|
||||
### 7.1 AI 建议 → ActionItem 映射
|
||||
|
||||
| ActionItem 字段 | 映射来源 | 规则 |
|
||||
|----------------|---------|------|
|
||||
| id | `"ai_suggestion:" + ai_suggestion.id` | 类型前缀 + 原 ID |
|
||||
| type | 固定 `"ai_suggestion"` | — |
|
||||
| priority | `ai_suggestion.risk_level` | High→urgent, Medium→high, Low→medium |
|
||||
| status | `ai_suggestion.status` | Pending→pending, Approved→in_progress, Executed→completed, Expired/Rejected/ParseFailed→dismissed |
|
||||
| title | `suggestion_type` + `risk_level` 拼接模板 | 如 `suggestion_type=Followup` → "建议安排随访";`suggestion_type=Alert` → "建议关注指标异常";从 `params` JSON 提取 `reason` 字段作为补充(若存在) |
|
||||
| summary | `ai_analysis.result_content` | 截取前 100 字符 |
|
||||
| patient_id | `ai_analysis.patient_id`(通过 `analysis_id` JOIN) | 三表 JOIN |
|
||||
| patient_name | `patient.name` | JOIN 查询 |
|
||||
| source_ref | `ai_suggestion.id` | 原始 ID |
|
||||
|
||||
### 7.2 线程步骤映射
|
||||
|
||||
| ThreadEvent.step | 触发条件 | 数据来源 |
|
||||
|-----------------|---------|---------|
|
||||
| `ai_analysis` | 始终存在 | `ai_analysis` 表 |
|
||||
| `doctor_approval` | `suggestion.status ∈ {Approved, Rejected}` | `suggestion.updated_at` 作为近似审批时间(无专用 `approved_at` 字段) |
|
||||
| `followup_scheduled` | `workflow_instance_id IS NOT NULL` | `workflow_instance` 表。注意:`action_dispatched` 步骤已合并到此处——`ai_action_dispatcher` 是事件消费者,不回写时间戳到 `ai_suggestion`,其效果体现为 `workflow_instance_id` 被设置 |
|
||||
| `followup_completed` | `follow_up.status = completed` | `follow_up` 表 |
|
||||
| `reanalysis` | `reanalysis_id IS NOT NULL` | `ai_analysis` (reanalysis) 表 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 实施分阶段
|
||||
|
||||
### Phase 1A:后端 API(2-3 天)
|
||||
|
||||
- [ ] 创建 `ActionInboxService` → `crates/erp-health/src/service/action_inbox_service.rs`
|
||||
- [ ] 创建 `ActionInboxHandler` → `crates/erp-health/src/handler/action_inbox_handler.rs`
|
||||
- [ ] 在 erp-health `protected_routes()` 中注册 2 个新路由
|
||||
- [ ] 实现三表 JOIN 聚合查询(`ai_suggestion` + `ai_analysis` + `patient`)
|
||||
- [ ] 实现线程拼装逻辑(合并 `action_dispatched` 到 `followup_scheduled` 步骤)
|
||||
- [ ] 实现操作按钮动态生成
|
||||
- [ ] 在 erp-health `permissions()` 中注册 `health.action_inbox.list` / `health.action_inbox.manage`
|
||||
|
||||
### Phase 1B:Web 前端(2-3 天)
|
||||
|
||||
- [ ] 扩展 `NotificationPanel`,增加待办区域
|
||||
- [ ] 创建 `ActionInboxPage` 路由页面
|
||||
- [ ] 创建 `ActionThreadDrawer` 组件
|
||||
- [ ] SSE 实时更新集成
|
||||
- [ ] 路由注册 + 菜单入口
|
||||
|
||||
### Phase 1C:小程序(2-3 天)
|
||||
|
||||
- [ ] TabBar 改造(4 Tab → 5 Tab,在"健康"和"消息"间插入"待办")
|
||||
- [ ] 创建待办列表页面
|
||||
- [ ] 创建半屏弹窗组件
|
||||
- [ ] Service 层对接
|
||||
|
||||
### Phase 1D:验证与收尾(1 天)
|
||||
|
||||
- [ ] 三端联调测试
|
||||
- [ ] 更新 wiki 文档
|
||||
- [ ] 提交并推送
|
||||
|
||||
---
|
||||
|
||||
## 9. 验证方案
|
||||
|
||||
### 9.1 后端验证
|
||||
|
||||
```bash
|
||||
# 1. 启动后端
|
||||
cd crates/erp-server && cargo run
|
||||
|
||||
# 2. 创建 AI 分析 → 产生建议
|
||||
# 3. 调用 API 验证
|
||||
curl -H "Authorization: Bearer $TOKEN" \
|
||||
http://localhost:3000/api/v1/action-inbox
|
||||
|
||||
curl -H "Authorization: Bearer $TOKEN" \
|
||||
http://localhost:3000/api/v1/action-inbox/ai_suggestion:{id}/thread
|
||||
```
|
||||
|
||||
### 9.2 Web 验证
|
||||
|
||||
1. 登录 → 顶栏铃铛应显示待办数量
|
||||
2. 点击铃铛 → Popover 显示最近待办
|
||||
3. "查看全部" → 进入 ActionInboxPage
|
||||
4. 点击待办项 → Drawer 打开,时间线正确
|
||||
5. 点击"批准" → 状态变更,时间线更新
|
||||
6. SSE 推送 → Drawer 实时更新
|
||||
|
||||
### 9.3 小程序验证
|
||||
|
||||
1. 底部 TabBar 显示"待办"Tab + 角标
|
||||
2. 进入待办页 → 列表正确
|
||||
3. 点击卡片 → 半屏弹窗弹出
|
||||
4. 操作后 → 状态更新,列表刷新
|
||||
|
||||
---
|
||||
|
||||
## 10. 未来扩展
|
||||
|
||||
新增行动类型只需:
|
||||
|
||||
1. 在 `ActionInboxService` 中注册新的聚合查询器
|
||||
2. 定义 `type → ActionItem` 的映射规则
|
||||
3. 定义线程步骤模板
|
||||
4. 前端自动渲染(共用相同组件)
|
||||
|
||||
**规划中的扩展类型**:
|
||||
- `alert` — 告警处理闭环(告警→评估→处置→追踪)
|
||||
- `followup` — 随访到期提醒(到期→执行→记录→再分析)
|
||||
- `data_anomaly` — 体征异常反馈(异常→趋势对比→建议→操作)
|
||||
499
docs/superpowers/specs/2026-05-01-unified-workbench-design.md
Normal file
499
docs/superpowers/specs/2026-05-01-unified-workbench-design.md
Normal file
@@ -0,0 +1,499 @@
|
||||
# 统一工作台设计规格
|
||||
|
||||
> 日期: 2026-05-01 | 状态: 草案 | 作者: brainstorming session
|
||||
|
||||
## 目录
|
||||
|
||||
1. **背景与目标** — 为什么要做、要解决什么问题
|
||||
2. **设计决策** — 方案选择过程和最终决策
|
||||
3. **页面布局** — 医生视角和主任视角的详细布局
|
||||
4. **待办数据模型** — ActionItem 统一结构和类型定义
|
||||
5. **交互设计** — 弹窗/抽屉混合、筛选、排序、操作按钮
|
||||
6. **角色感知** — 医生 vs 主任的渲染差异
|
||||
7. **后端 API** — ActionInboxService 聚合查询接口
|
||||
8. **与现有模块的关系** — 复用 erp-health / erp-ai 已有能力
|
||||
9. **实施分步** — Phase 划分和依赖关系
|
||||
10. **验证标准** — 完成标准
|
||||
|
||||
---
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
### 1.1 问题
|
||||
|
||||
HMS 平台功能完成度已达 83%,后端 AI 能力成熟(4 个 SSE 分析端点、建议系统、自动趋势分析、本地规则引擎),但审计揭示了一个核心矛盾:**后端能力远超前端覆盖**。
|
||||
|
||||
具体表现:
|
||||
- **AI 分析"有脑无手"** — 后端 4 个 SSE 端点就绪,AI 建议可自动创建,但前端无统一入口展示和处理
|
||||
- **告警"有声无窗"** — 后端告警引擎完整,Web 端无集中展示
|
||||
- **待办分散** — AI 建议、告警、随访、数据异常分布在不同页面,医生需要逐一查看
|
||||
- **主任视角缺失** — 科室主任无法快速掌握团队工作负载和科室风险概况
|
||||
|
||||
### 1.2 目标
|
||||
|
||||
设计一个**统一工作台**,作为医生和科室主任的默认首页,实现:
|
||||
|
||||
1. **一眼看到所有待办** — AI 建议、危急告警、随访、数据异常集中展示
|
||||
2. **一键操作** — 每条待办可直接处理(审批/联系/安排),不强制跳转
|
||||
3. **AI 洞察直达** — 右侧面板实时展示最新 AI 分析洞察
|
||||
4. **主任管理视角** — 团队工作负载、超时升级、科室风险分布一目了然
|
||||
5. **设计一致性** — 医生和主任使用相同的页面结构,通过角色感知差异化
|
||||
|
||||
### 1.3 范围
|
||||
|
||||
- **包含**:Web 端首页工作台重构、后端 ActionInboxService 聚合 API
|
||||
- **不包含**:小程序端改造(独立迭代)、BPMN 工作流编排(AI 行动闭环 Phase 2+)
|
||||
|
||||
---
|
||||
|
||||
## 2. 设计决策
|
||||
|
||||
### 2.1 方案选择过程
|
||||
|
||||
通过高保真 HTML 原型对比了三种工作台形态:
|
||||
|
||||
| 方案 | 描述 | 优势 | 劣势 |
|
||||
|------|------|------|------|
|
||||
| **A · 首页即工作台** | 登录后默认首页,取代现有 Dashboard | 零点击触达待办,信息密度高 | 首页功能增多 |
|
||||
| **B · 独立工作台** | 侧边栏入口,三栏布局(筛选+列表+详情) | 筛选能力强,详情展示充分 | 需要额外导航,脱离首页语境 |
|
||||
| **C · 嵌入式体验** | 顶栏气泡+侧边迷你面板+浮动 AI 助手 | 信息无处不在,上下文关联强 | 实现复杂度高,分散注意力 |
|
||||
|
||||
**最终选择:方案A — 首页即工作台**
|
||||
|
||||
理由:
|
||||
- 医生最核心的需求是"快速知道今天要做什么",方案A 零点击满足
|
||||
- 信息密度适中(左侧待办 + 右侧 AI 洞察),不会过载
|
||||
- 与现有 Home.tsx 的角色感知 Dashboard 结构兼容,改动最小
|
||||
|
||||
### 2.2 科室主任视角
|
||||
|
||||
对比了三种主任工作台方案:
|
||||
|
||||
| 方案 | 描述 | 优势 | 劣势 |
|
||||
|------|------|------|------|
|
||||
| **D · 个人待办 + 团队概览卡** | 和医生同结构,右侧替换为团队概览 | 设计一致性最高 | 团队管理能力相对有限 |
|
||||
| **E · 独立管理仪表盘** | 纯管理视角,6列统计+团队表+告警线 | 管理信息最全面 | 完全不同的页面,开发成本高 |
|
||||
| **F · Tab 双视图** | 同一页面内 Tab 切换 | 兼顾两种需求 | Tab 切换增加认知负担 |
|
||||
|
||||
**最终选择:方案D — 个人待办 + 团队概览卡**
|
||||
|
||||
理由:
|
||||
- 与医生方案保持设计一致性,同一页面结构
|
||||
- 团队概览卡提供足够的主任管理信息(每人工作负载、处理率、超时数)
|
||||
- 实现成本最低,角色感知逻辑复用现有模式
|
||||
|
||||
### 2.3 AI 建议交互
|
||||
|
||||
**决策:弹窗 + 抽屉混合**
|
||||
|
||||
| 操作类型 | 交互方式 | 原因 |
|
||||
|---------|---------|------|
|
||||
| 批准/拒绝/忽略 | Modal 弹窗确认 | 轻操作,一步完成 |
|
||||
| 查看完整 AI 分析 | 右侧 Drawer 抽屉 | 需要展示长文本、基线指标、建议详情 |
|
||||
| 修改后批准 | Drawer 内编辑 | 需要足够空间修改建议内容 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 页面布局
|
||||
|
||||
### 3.1 整体结构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 顶部 Tab 切换栏(仅原型用)│ 实际:MainLayout 侧边栏 + 顶栏 │
|
||||
├──────┬──────────────────────────────────────────────────────┤
|
||||
│ │ 欢迎语 + 日期 + 待办总数 │
|
||||
│ 侧 │ ┌──────┬──────┬──────┬──────┬──────┐ │
|
||||
│ 边 │ │统计卡1│统计卡2│统计卡3│统计卡4│(主任+1)│ │
|
||||
│ 导 │ └──────┴──────┴──────┴──────┴──────┘ │
|
||||
│ 航 │ ┌─────────────────────┬──────────────┐ │
|
||||
│ │ │ │ │ │
|
||||
│ 220px│ │ 待办任务列表 │ AI 洞察 / │ │
|
||||
│ │ │ (按紧急度排序) │ 团队概览 │ │
|
||||
│ │ │ │ (主任) │ │
|
||||
│ │ │ 类型筛选条 │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ └─────────────────────┴──────────────┘ │
|
||||
│ │ 快捷操作区 │
|
||||
├──────┴──────────────────────────────────────────────────────┤
|
||||
```
|
||||
|
||||
### 3.2 医生视角(Doctor)
|
||||
|
||||
**统计卡片(4 列)**:
|
||||
| 序号 | 标签 | 数据源 | 颜色 |
|
||||
|------|------|--------|------|
|
||||
| 1 | 今日待办 | ActionItem count(assigned_to=me, status=pending) | 蓝 #2563EB |
|
||||
| 2 | AI 建议待审 | ActionItem count(type=ai_suggestion, status=pending) | 紫 #7C3AED |
|
||||
| 3 | 危急值告警 | ActionItem count(type=alert, severity=urgent) | 红 #DC2626 |
|
||||
| 4 | 随访到期 | ActionItem count(type=followup, status=pending) | 橙 #D97706 |
|
||||
|
||||
**待办列表**:
|
||||
- 默认按紧急度排序:urgent > high > normal > low
|
||||
- 顶部筛选条:全部 / AI 建议 / 告警 / 随访 / 数据异常
|
||||
- 每条显示:紧急度圆点 + 标题 + 摘要 + 类型标签 + 风险等级 + 时间 + 操作按钮
|
||||
- 点击条目 → Drawer 展开详情
|
||||
|
||||
**右侧 AI 洞察面板(340px)**:
|
||||
- 顶部:AI 图标 + "智能洞察" 标题 + 实时标记
|
||||
- 最近 3 条 AI 分析洞察,每条包含:患者姓名/年龄/诊断、分析摘要、风险等级标签
|
||||
- 第一条洞察下方放快捷操作按钮(联系患者/安排急诊/调整用药)
|
||||
- 底部:快捷操作区(查询患者/新建随访/AI 分析)
|
||||
|
||||
### 3.3 科室主任视角(Director)
|
||||
|
||||
与医生共享同一页面结构,差异化:
|
||||
|
||||
**统计卡片(5 列,多 2 个)**:
|
||||
| 序号 | 标签 | 说明 |
|
||||
|------|------|------|
|
||||
| 1 | 科室待办总计 | 全科室 pending 总数,副文本显示"我负责 N 项" |
|
||||
| 2 | AI 建议待审 | 全科室范围 |
|
||||
| 3 | 危急值告警 | 全科室范围 |
|
||||
| 4 | 随访到期 | 全科室范围 |
|
||||
| 5 | 今日处理率 | 已处理/总数,绿色 |
|
||||
|
||||
**待办列表**:
|
||||
- 仅显示分配给主任的待办:超时升级项、高风险 AI 建议审批、随访审核
|
||||
- 超时升级项带"超时升级"标签和红色高亮
|
||||
|
||||
**右侧团队概览面板(340px)**:
|
||||
- 团队概览卡片:每位医生一行,显示姓名、职称、待办数、处理率进度条、超时数
|
||||
- 超时医生卡片左侧红色边框 + 红色背景高亮
|
||||
- 点击医生卡片 → 展开该医生的待办列表
|
||||
- 底部:科室患者风险分布(高/中/低危统计)
|
||||
|
||||
---
|
||||
|
||||
## 4. 待办数据模型
|
||||
|
||||
### 4.1 ActionItem 统一结构
|
||||
|
||||
```typescript
|
||||
interface ActionItem {
|
||||
id: string; // UUID v7
|
||||
tenant_id: string;
|
||||
type: 'ai_suggestion' | 'alert' | 'followup' | 'data_anomaly';
|
||||
severity: 'urgent' | 'high' | 'normal' | 'low';
|
||||
status: 'pending' | 'in_progress' | 'completed' | 'escalated';
|
||||
title: string; // "张伟 — 血压危急值告警"
|
||||
summary: string; // 一句话摘要
|
||||
patient_id: string;
|
||||
patient_name: string;
|
||||
assigned_to: string; // user_id
|
||||
source_id: string; // 来源记录 ID(ai_suggestion.id / alert.id 等)
|
||||
source_type: string; // "ai_suggestion" / "alert" / "followup" / "data_anomaly"
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
due_at?: string; // 超时时间(用于升级判断)
|
||||
metadata: Record<string, any>; // 类型特定的附加数据
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 类型与来源映射
|
||||
|
||||
| type | 来源模块 | 触发条件 | 默认 severity |
|
||||
|------|---------|---------|--------------|
|
||||
| `ai_suggestion` | erp-ai | AI 分析完成 + structured_output 含 suggestions | 从 AI risk_level 映射 |
|
||||
| `alert` | erp-health | 告警引擎触发危急值 | `urgent` |
|
||||
| `followup` | erp-health | 随访计划到期 | `normal` |
|
||||
| `data_anomaly` | erp-health | 规则引擎检测到异常 | 从规则配置映射 |
|
||||
|
||||
### 4.3 严重度与升级规则
|
||||
|
||||
| severity | 圆点颜色 | 超时 | 升级行为 |
|
||||
|----------|---------|------|---------|
|
||||
| `urgent` | 红 #DC2626 | 4 小时 | 升级至科室主任 |
|
||||
| `high` | 橙 #D97706 | 24 小时 | 升级至科室主任 |
|
||||
| `normal` | 蓝 #2563EB | 72 小时 | 标记逾期 |
|
||||
| `low` | 灰 #94A3B8 | 无 | 不升级 |
|
||||
|
||||
### 4.4 不建新表
|
||||
|
||||
Phase 1 采用三表 JOIN 聚合查询,不创建独立的 `action_items` 表:
|
||||
- `ai_suggestions` + `ai_analysis` + `patient` → AI 建议类待办
|
||||
- `alerts` + `patient` → 告警类待办
|
||||
- `followup_plans` + `patient` → 随访类待办
|
||||
- `device_readings`(异常) + `patient` → 数据异常类待办
|
||||
|
||||
理由:避免数据冗余和同步问题。各模块已有完整数据,工作台只做聚合展示。未来如需独立表,可作为 Phase 2 引入。
|
||||
|
||||
---
|
||||
|
||||
## 5. 交互设计
|
||||
|
||||
### 5.1 待办列表交互
|
||||
|
||||
**筛选**:
|
||||
- 顶部筛选条:全部 / AI 建议 / 告警 / 随访 / 数据异常
|
||||
- 点击切换,无页面刷新,前端过滤已加载的数据
|
||||
- 默认显示"全部"
|
||||
|
||||
**排序**:
|
||||
- 默认按紧急度排序(urgent > high > normal > low)
|
||||
- 同级别按创建时间倒序
|
||||
- 未来可扩展:按患者、按时间排序
|
||||
|
||||
**点击行为**:
|
||||
- 点击待办条目 → 右侧 Drawer 抽屉展开(宽度 480px)
|
||||
- Drawer 内容根据 `type` 不同渲染不同详情组件
|
||||
|
||||
### 5.2 Drawer 详情面板
|
||||
|
||||
**AI 建议 (ai_suggestion)**:
|
||||
- 顶部:类型标签 + 风险等级 + 触发时间
|
||||
- 患者信息:姓名、年龄、性别、诊断、科室
|
||||
- AI 分析摘要(Markdown 渲染)
|
||||
- 建议方案(高亮框)
|
||||
- 基线指标网格(2x2:关键数值 + 趋势箭头)
|
||||
- 操作按钮:批准 / 拒绝 / 修改后批准
|
||||
|
||||
**危急告警 (alert)**:
|
||||
- 告警详情:触发指标、阈值、当前值
|
||||
- 患者基本信息
|
||||
- 快捷操作:联系患者 / 安排急诊 / 调整用药
|
||||
- 操作按钮:已处理 / 转交
|
||||
|
||||
**随访 (followup)**:
|
||||
- 随访计划详情
|
||||
- 上次随访摘要
|
||||
- 操作按钮:开始随访 / 延期 / 标记完成
|
||||
|
||||
**数据异常 (data_anomaly)**:
|
||||
- 异常指标详情
|
||||
- 历史趋势迷你图
|
||||
- 操作按钮:查看详情 / AI 分析 / 忽略
|
||||
|
||||
### 5.3 Modal 弹窗
|
||||
|
||||
**批准确认**:
|
||||
- 显示建议摘要
|
||||
- "确认批准?" + 备注(可选)
|
||||
- 按钮:确认 / 取消
|
||||
|
||||
**拒绝确认**:
|
||||
- 必填拒绝原因
|
||||
- 按钮:确认拒绝 / 取消
|
||||
|
||||
**忽略确认**:
|
||||
- "确认忽略此待办?"
|
||||
- 按钮:确认 / 取消
|
||||
|
||||
### 5.4 右侧面板交互
|
||||
|
||||
**医生 — AI 洞察面板**:
|
||||
- 显示最近 3 条 AI 分析洞察(按时间倒序)
|
||||
- 第一条洞察下方显示快捷操作按钮
|
||||
- 点击洞察标题 → 打开对应患者的 AI 建议 Drawer
|
||||
|
||||
**主任 — 团队概览面板**:
|
||||
- 每位医生一行卡片,hover 高亮
|
||||
- 点击医生卡片 → Drawer 展开该医生的待办列表
|
||||
- 超时医生卡片:左侧红色边框 + 浅红背景 + 超时数红色高亮
|
||||
- 底部风险分布:高/中/低危三色统计块
|
||||
|
||||
---
|
||||
|
||||
## 6. 角色感知
|
||||
|
||||
### 6.1 渲染逻辑
|
||||
|
||||
```
|
||||
if user.role contains 'director' or 'department_head':
|
||||
render DirectorDashboard()
|
||||
else:
|
||||
render DoctorDashboard()
|
||||
```
|
||||
|
||||
共享组件:
|
||||
- `WorkbenchLayout` — 整体布局框架
|
||||
- `StatCardGrid` — 统计卡片网格
|
||||
- `TodoList` — 待办列表
|
||||
- `ActionDrawer` — 详情抽屉
|
||||
- `ActionModal` — 操作弹窗
|
||||
|
||||
差异组件:
|
||||
- `AiInsightPanel` — 医生专属,AI 洞察
|
||||
- `TeamOverviewPanel` — 主任专属,团队概览
|
||||
- `RiskDistribution` — 主任专属,风险分布
|
||||
|
||||
### 6.2 数据范围差异
|
||||
|
||||
| 维度 | 医生 | 主任 |
|
||||
|------|------|------|
|
||||
| 待办范围 | `assigned_to = my_id` | `assigned_to = my_id` + 超时升级项 |
|
||||
| 统计范围 | 仅自己 | 全科室 |
|
||||
| 团队概览 | 不显示 | 显示本科室所有医生 |
|
||||
| 风险分布 | 不显示 | 全科室患者 |
|
||||
| AI 洞察 | 自己负责的患者 | 不显示(用团队概览替代)|
|
||||
|
||||
---
|
||||
|
||||
## 7. 后端 API
|
||||
|
||||
### 7.1 ActionInboxService
|
||||
|
||||
归属 crate:`erp-health`
|
||||
|
||||
**核心方法**:
|
||||
|
||||
| 方法 | 路由 | 说明 | 权限码 |
|
||||
|------|------|------|--------|
|
||||
| `list_action_items` | `GET /api/v1/health/action-inbox` | 聚合查询待办列表 | `health.action_inbox.list` |
|
||||
| `get_action_thread` | `GET /api/v1/health/action-inbox/:id/thread` | 获取待办处理线程 | `health.action_inbox.list` |
|
||||
| `get_team_overview` | `GET /api/v1/health/action-inbox/team` | 主任:团队概览 | `health.action_inbox.team` |
|
||||
| `get_workbench_stats` | `GET /api/v1/health/action-inbox/stats` | 统计卡片数据 | `health.action_inbox.list` |
|
||||
|
||||
### 7.2 list_action_items 查询参数
|
||||
|
||||
```
|
||||
GET /api/v1/health/action-inbox?type=ai_suggestion&severity=urgent&page=1&page_size=20
|
||||
```
|
||||
|
||||
| 参数 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `type` | string | 可选,筛选类型:ai_suggestion / alert / followup / data_anomaly |
|
||||
| `severity` | string | 可选,筛选紧急度 |
|
||||
| `status` | string | 可选,默认 pending |
|
||||
| `patient_id` | uuid | 可选,按患者筛选 |
|
||||
| `page` | number | 页码,默认 1 |
|
||||
| `page_size` | number | 每页条数,默认 20 |
|
||||
|
||||
### 7.3 聚合查询策略
|
||||
|
||||
不建独立表,通过 SQL UNION 聚合四类数据源:
|
||||
|
||||
```sql
|
||||
-- AI 建议类
|
||||
SELECT s.id, 'ai_suggestion' as type, s.risk_level as severity,
|
||||
s.title, s.summary, s.patient_id, p.name as patient_name,
|
||||
s.assigned_to, s.created_at, 'ai_suggestion' as source_type
|
||||
FROM ai_suggestions s JOIN patients p ON s.patient_id = p.id
|
||||
WHERE s.status = 'pending' AND s.tenant_id = $1
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- 告警类
|
||||
SELECT a.id, 'alert' as type, 'urgent' as severity,
|
||||
a.title, a.summary, a.patient_id, p.name as patient_name,
|
||||
a.assigned_to, a.created_at, 'alert' as source_type
|
||||
FROM alerts a JOIN patients p ON a.patient_id = p.id
|
||||
WHERE a.status = 'active' AND a.tenant_id = $1
|
||||
|
||||
-- ... 随访、异常类同理
|
||||
ORDER BY severity_priority, created_at DESC
|
||||
```
|
||||
|
||||
### 7.4 get_team_overview 响应
|
||||
|
||||
```json
|
||||
{
|
||||
"members": [
|
||||
{
|
||||
"user_id": "uuid",
|
||||
"name": "李明远",
|
||||
"title": "副主任医师",
|
||||
"pending_count": 5,
|
||||
"completed_count": 3,
|
||||
"overdue_count": 1,
|
||||
"completion_rate": 0.6
|
||||
}
|
||||
],
|
||||
"risk_distribution": {
|
||||
"high": 3,
|
||||
"medium": 8,
|
||||
"low": 24
|
||||
},
|
||||
"total_pending": 18,
|
||||
"total_completed": 12
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 与现有模块的关系
|
||||
|
||||
### 8.1 复用已有能力
|
||||
|
||||
| 能力 | 来源 | 复用方式 |
|
||||
|------|------|---------|
|
||||
| AI 建议数据 | `erp-ai` AiSuggestionService | 直接查询 ai_suggestions 表 |
|
||||
| 告警数据 | `erp-health` AlertService | 直接查询 alerts 表 |
|
||||
| 随访数据 | `erp-health` FollowupService | 直接查询 followup_plans 表 |
|
||||
| 角色感知 | `Home.tsx` 已有模式 | 参考现有 role-based Dashboard 分发 |
|
||||
| Drawer 组件 | `ActionThreadDrawer` 已存在 | 复用并扩展 |
|
||||
| 建议审批 | `AiSuggestionTab` 已存在 | 复用审批逻辑 |
|
||||
| SSE 客户端 | `analysisSse.ts` 已存在 | 不涉及(工作台不触发分析) |
|
||||
|
||||
### 8.2 新增代码归属
|
||||
|
||||
| 文件 | crate/模块 | 说明 |
|
||||
|------|-----------|------|
|
||||
| `action_inbox_service.rs` | erp-health/service | 聚合查询服务 |
|
||||
| `action_inbox_handler.rs` | erp-health/handler | API 路由处理 |
|
||||
| `WorkbenchHome.tsx` | web/pages | 新首页组件(替代 Home.tsx 中的 Dashboard 部分) |
|
||||
| `TodoList.tsx` | web/components | 待办列表组件 |
|
||||
| `AiInsightPanel.tsx` | web/components | AI 洞察面板 |
|
||||
| `TeamOverviewPanel.tsx` | web/components | 团队概览面板 |
|
||||
| `ActionDetailDrawer.tsx` | web/components | 操作详情抽屉 |
|
||||
| `actionInbox.ts` | web/api/health | API 客户端(已存在,需补充) |
|
||||
|
||||
### 8.3 权限码
|
||||
|
||||
新增权限码(注册在 erp-health):
|
||||
|
||||
| 权限码 | 说明 |
|
||||
|--------|------|
|
||||
| `health.action_inbox.list` | 查看待办列表 |
|
||||
| `health.action_inbox.manage` | 处理待办(批准/拒绝/转交) |
|
||||
| `health.action_inbox.team` | 查看团队概览(主任专属) |
|
||||
|
||||
---
|
||||
|
||||
## 9. 实施分步
|
||||
|
||||
### Phase 1A:后端聚合 API(2-3 天)
|
||||
|
||||
1. 创建 `action_inbox_service.rs` — 实现四类数据源 UNION 聚合查询
|
||||
2. 创建 `action_inbox_handler.rs` — 注册 4 个 API 端点
|
||||
3. 注册权限码 `health.action_inbox.*`
|
||||
4. 编写单元测试
|
||||
|
||||
### Phase 1B:Web 前端组件(2-3 天)
|
||||
|
||||
1. 创建 `TodoList.tsx` — 待办列表组件(筛选、排序、点击)
|
||||
2. 创建 `AiInsightPanel.tsx` — AI 洞察面板
|
||||
3. 创建 `TeamOverviewPanel.tsx` — 团队概览面板
|
||||
4. 创建 `ActionDetailDrawer.tsx` — 详情抽屉(按类型渲染不同内容)
|
||||
5. 补充 `actionInbox.ts` API 客户端
|
||||
6. 改造 `Home.tsx` — 用新组件替换现有 Dashboard
|
||||
|
||||
### Phase 1C:联调验证(1 天)
|
||||
|
||||
1. 前后端联调
|
||||
2. 角色感知测试(医生视角 vs 主任视角)
|
||||
3. 四类待办数据验证
|
||||
4. `pnpm build` 生产构建通过
|
||||
|
||||
---
|
||||
|
||||
## 10. 验证标准
|
||||
|
||||
### 功能验证
|
||||
|
||||
- [ ] 医生登录后,首页显示工作台(4 个统计卡片 + 待办列表 + AI 洞察)
|
||||
- [ ] 主任登录后,首页显示工作台(5 个统计卡片 + 我的待办 + 团队概览)
|
||||
- [ ] 待办列表按紧急度正确排序
|
||||
- [ ] 类型筛选条正确过滤
|
||||
- [ ] 点击 AI 建议待办 → Drawer 展示完整分析 + 操作按钮
|
||||
- [ ] 批准/拒绝操作 → Modal 确认 → 调用后端 API 成功
|
||||
- [ ] 主任团队概览正确显示每位医生的工作负载
|
||||
- [ ] 超时升级项正确出现在主任的待办列表
|
||||
|
||||
### 技术验证
|
||||
|
||||
- [ ] `cargo check` 全 workspace 通过
|
||||
- [ ] `cargo test` 相关测试通过
|
||||
- [ ] `pnpm build` 前端生产构建通过
|
||||
- [ ] API 可通过 Swagger UI 测试
|
||||
- [ ] 权限码正确拦截未授权访问
|
||||
@@ -0,0 +1,539 @@
|
||||
# 医生 & 运营 & 管理员工作台设计规格
|
||||
|
||||
> 日期: 2026-05-02 | 状态: 设计中
|
||||
> 原型参考: `_temp/workbench-doctor-A.html`(医生)、`_temp/workbench-operator-C.html`(运营)、`_temp/workbench-admin.html`(管理员)
|
||||
> 关联文档: `2026-05-02-health-manager-workbench-design.md`(健康管家方案 B)
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
### 1.1 与健康管家工作台的关系
|
||||
|
||||
本规格定义健康管家之外的三个角色工作台。四者共享同一平台、同一全局侧边栏、同一路由入口 `/`(`Home.tsx`),通过 `useDashboardRole()` 按 `doctor` / `health_manager` / `operator` / `admin` 角色分发不同的工作台视图。
|
||||
|
||||
| 角色 | 方案 | 核心交互模式 | 本期优先级 |
|
||||
|------|------|-------------|-----------|
|
||||
| 健康管家 | B 工作流驱动 | 任务队列一件一件处理 | Phase 1(已设计) |
|
||||
| 医生 | A 今日全景 | 仪表盘总览 + AI 建议一键审核 | Phase 1(本文档) |
|
||||
| 运营 | C AI 指挥中心 | AI 洞察驱动运营决策 | Phase 1(本文档) |
|
||||
| 管理员 | 系统管理中心 | 平台运维全局视角 | Phase 1(本文档) |
|
||||
|
||||
### 1.2 医生角色目标
|
||||
|
||||
| 指标 | 当前 | 目标 |
|
||||
|------|------|------|
|
||||
| AI 建议审核响应时间 | 无专门入口,散落在 AI 分析列表 | 工作台直接展示,一键采纳/拒绝 |
|
||||
| 患者咨询回复时间 | 需进入咨询列表才能看到未读 | 工作台右侧实时显示未回复咨询 |
|
||||
| 关注患者认知负担 | 需逐个翻患者详情 | 聚合告警+AI分析的关注列表 |
|
||||
|
||||
### 1.3 运营角色目标
|
||||
|
||||
| 指标 | 当前 | 目标 |
|
||||
|------|------|------|
|
||||
| 内容运营效率 | 各功能模块独立操作 | AI 推荐热点内容,一键关联发布 |
|
||||
| 积分异常发现 | 被动审核订单 | AI 主动发现异常兑换模式 |
|
||||
| 运营决策数据支撑 | 需单独查看统计报表 | 工作台实时展示核心指标 + 趋势 |
|
||||
|
||||
### 1.4 范围
|
||||
|
||||
**本期(Phase 1):**
|
||||
- 医生:4 统计卡片 + AI 建议待审 + 重点关注患者 + 日程 + 咨询摘要
|
||||
- 运营:AI 洞察卡片 + 4 数据指标 + 热门内容排行 + 待办列表 + 积分动态 + 内容矩阵
|
||||
|
||||
**不在本期:**
|
||||
- 医生角色的方案 B/C 工作流模式
|
||||
- 运营角色的方案 A/B 仪表盘模式
|
||||
- 管理员的实时系统指标监控(CPU/内存/磁盘)
|
||||
- 角色间的任务转交/协作流程(Phase 2)
|
||||
- AI 洞察的 SSE 实时推送(Phase 2 使用 30 秒轮询)
|
||||
|
||||
## 2. 角色定义
|
||||
|
||||
### 2.1 医生 — 李明辉
|
||||
|
||||
| 维度 | 描述 |
|
||||
|------|------|
|
||||
| 姓名 | 李明辉 |
|
||||
| 职位 | 主治医师 · 肾内科 |
|
||||
| 年龄 | 42 岁 |
|
||||
| 工作经验 | 15 年临床,8 年肾内科 |
|
||||
| 技术水平 | 基本操作无障碍,不追求花哨功能 |
|
||||
| 日均任务量 | AI 建议审核 3-5 项、咨询回复 2-3 条、查看危急值 1-2 次 |
|
||||
|
||||
#### 典型工作日
|
||||
|
||||
```
|
||||
07:30 晨间查房,查看住院患者
|
||||
08:00 门诊开始,打开工作台扫一眼今日概览
|
||||
08:30 门诊间隙审核 AI 建议(采纳/拒绝)
|
||||
10:00 回复患者咨询消息
|
||||
10:30 多学科会诊
|
||||
14:00 下午门诊
|
||||
16:00 查看告警中心,确认危急值已处理
|
||||
17:00 下班
|
||||
```
|
||||
|
||||
#### 核心痛点
|
||||
|
||||
1. **AI 建议易遗忘**:AI 分析结果在独立列表中,不强制提醒,容易积压
|
||||
2. **咨询回复不及时**:不知道有新咨询,需要主动刷新咨询列表
|
||||
3. **患者上下文分散**:看 AI 建议时需要单独翻患者详情了解病史
|
||||
|
||||
### 2.2 运营 — 王美玲
|
||||
|
||||
| 维度 | 描述 |
|
||||
|------|------|
|
||||
| 姓名 | 王美玲 |
|
||||
| 职位 | 健康运营专员 |
|
||||
| 年龄 | 28 岁 |
|
||||
| 工作经验 | 3 年互联网运营,1 年健康领域 |
|
||||
| 技术水平 | 熟练使用各种运营工具,对数据敏感 |
|
||||
| 日均任务量 | 文章管理 2-3 篇、积分审核 5-10 笔、活动跟进 1-2 个 |
|
||||
|
||||
#### 典型工作日
|
||||
|
||||
```
|
||||
08:30 打开工作台,查看 AI 洞察和昨日数据
|
||||
09:00 审核积分兑换订单(AI 标记异常的优先)
|
||||
10:00 发布新科普文章,关联热门话题
|
||||
11:00 跟进线下活动报名情况
|
||||
14:00 查看内容阅读数据,优化推送策略
|
||||
15:00 整理运营周报
|
||||
16:30 跟进沉默用户,发送关怀消息
|
||||
17:30 下班
|
||||
```
|
||||
|
||||
#### 核心痛点
|
||||
|
||||
1. **数据分散**:积分、内容、活动数据在不同页面,需来回切换
|
||||
2. **缺乏数据驱动**:发什么内容凭经验,不知道什么受欢迎
|
||||
3. **异常发现慢**:积分兑换异常靠人工发现,等到发现时已造成损失
|
||||
|
||||
### 2.3 管理员 — 陈建国
|
||||
|
||||
| 维度 | 描述 |
|
||||
|------|------|
|
||||
| 姓名 | 陈建国 |
|
||||
| 职位 | 系统管理员 / 平台运维 |
|
||||
| 年龄 | 35 岁 |
|
||||
| 工作经验 | 8 年 IT 运维,3 年医疗信息化 |
|
||||
| 技术水平 | 熟悉 Linux/Docker/数据库,能看懂 Rust 错误日志 |
|
||||
| 日均任务量 | 用户管理 5-10 次、权限配置 1-2 次、系统巡检 3-4 次 |
|
||||
|
||||
#### 核心痛点
|
||||
|
||||
1. **系统健康不可见**:不知道各模块是否正常运行,出了问题被动发现
|
||||
2. **操作追溯分散**:用户做了什么操作需要翻审计日志表,没有聚合视图
|
||||
3. **配置入口分散**:用户管理/角色权限/菜单/字典/插件分布在不同页面,来回切换
|
||||
|
||||
## 3. 信息架构
|
||||
|
||||
### 3.1 医生:方案 A「今日全景」布局
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ 全局侧边栏(已有) │ 医生工作台页面内部 │
|
||||
│ │ │
|
||||
│ 🏠 今日全景(高亮) │ ┌──────────────────────────────────────┐ │
|
||||
│ 🩺 患者管理 │ │ 欢迎栏:上午好,李医生 │ │
|
||||
│ 💬 患者咨询 │ ├──────────────────────────────────────┤ │
|
||||
│ 📅 预约排班 │ │ 4 统计卡片(危急值/待审/咨询/预约) │ │
|
||||
│ 🤖 AI 分析 │ ├──────────────────┬───────────────────┤ │
|
||||
│ ⚠️ 告警中心 │ │ 左主内容(flex) │ 右窄栏(340px) │ │
|
||||
│ 📊 统计报表 │ │ │ │ │
|
||||
│ │ │ AI 建议待审列表 │ 今日日程 │ │
|
||||
│ │ │ (采纳/拒绝按钮) │ 未回复咨询 │ │
|
||||
│ │ │ │ 快捷操作 │ │
|
||||
│ │ │ 重点关注患者列表 │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ └──────────────────┴───────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**布局参数**:
|
||||
- 左主内容:`flex: 1`,包含 AI 建议和关注患者两个 Card
|
||||
- 右窄栏:固定 340px,包含日程、咨询、快捷操作
|
||||
|
||||
### 3.2 运营:方案 C「AI 指挥中心」布局
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ 全局侧边栏(已有) │ 运营工作台页面内部 │
|
||||
│ │ │
|
||||
│ 🤖 AI 工作台(高亮) │ ┌──────────────────────────────────────┐ │
|
||||
│ 📝 内容管理 │ │ AI 洞察卡片(暖橙色渐变 Hero) │ │
|
||||
│ 🎁 积分商城 │ │ 3 条洞察 + 操作按钮 │ │
|
||||
│ 🎪 线下活动 │ ├──────────────────────────────────────┤ │
|
||||
│ 👥 患者管理 │ │ 4 数据指标卡片(活跃/阅读/积分/订单) │ │
|
||||
│ 📊 统计报表 │ ├──────────────────┬───────────────────┤ │
|
||||
│ ⚙️ 系统设置 │ │ 热门科普排行 │ 今日待办 │ │
|
||||
│ │ ├──────────────────┼───────────────────┤ │
|
||||
│ │ │ 积分动态 │ 内容矩阵 │ │
|
||||
│ │ └──────────────────┴───────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**布局参数**:
|
||||
- 顶部:AI Hero 卡片(全宽)
|
||||
- 第二行:4 数据指标(grid 4 列)
|
||||
- 第三行起:双栏卡片(grid 2 列等宽)
|
||||
- 最大内容宽度 960px(`max-width`)
|
||||
|
||||
### 3.3 管理员:系统管理中心布局
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ 全局侧边栏(已有) │ 管理员工作台页面内部 │
|
||||
│ │ │
|
||||
│ 🔧 系统管理(高亮) │ ┌──────────────────────────────────────┐ │
|
||||
│ 👤 用户管理 │ │ 系统健康条(6 项状态指示灯) │ │
|
||||
│ 🔑 角色权限 │ ├──────────────────────────────────────┤ │
|
||||
│ 📖 菜单管理 │ │ 4 统计卡片(用户/模块/操作/工单) │ │
|
||||
│ 📋 审计日志 │ ├──────────────────┬───────────────────┤ │
|
||||
│ ⚙️ 系统配置 │ │ 审计日志 │ 模块状态 │ │
|
||||
│ 🧩 插件管理 │ ├──────────────────┼───────────────────┤ │
|
||||
│ 📊 统计报表 │ │ 用户活跃度 │ 系统管理快捷入口 │ │
|
||||
│ │ └──────────────────┴───────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**布局参数**:
|
||||
- 顶部:系统健康条(全宽,flex 横向排列 6 项状态)
|
||||
- 第二行:4 统计卡片(grid 4 列)
|
||||
- 第三行起:双栏卡片(grid 2 列等宽)
|
||||
- 最大内容宽度 1080px
|
||||
|
||||
## 4. 组件清单
|
||||
|
||||
### 4.1 医生组件
|
||||
|
||||
| 组件 | 说明 | 数据源 |
|
||||
|------|------|--------|
|
||||
| **DoctorStatsRow** | 4 统计卡片:危急值/待审/咨询/预约 | `GET /health/action-inbox/stats` + `GET /health/doctor/dashboard` |
|
||||
| **AiSuggestionList** | AI 建议待审列表,内嵌采纳/拒绝按钮 | `GET /health/action-inbox`(过滤 `type=ai_suggestion`) |
|
||||
| **FocusedPatientList** | 重点关注患者(聚合告警+AI 分析) | `GET /health/action-inbox`(按患者聚合) |
|
||||
| **TodaySchedule** | 今日日程(查房/门诊/会诊) | `GET /health/doctor-schedules`(过滤今日) |
|
||||
| **ConsultSummary** | 未回复咨询摘要(侧栏紧凑版) | `GET /health/consultation-sessions`(过滤未回复) |
|
||||
| **QuickActions** | 快捷入口(AI 分析/告警/患者查询) | 前端静态配置 |
|
||||
|
||||
### 4.2 运营组件
|
||||
|
||||
| 组件 | 说明 | 数据源 |
|
||||
|------|------|--------|
|
||||
| **AiInsightHero** | AI 洞察 Hero 卡片(暖橙色渐变) | Phase 1 前端静态展示,Phase 2 接 AI 生成 |
|
||||
| **OperatorStatsRow** | 4 数据指标(活跃/阅读/积分/订单) | `GET /health/admin/statistics/dashboard` + `GET /health/admin/points/statistics` |
|
||||
| **HotContentRank** | 热门科普排行(阅读量排名) | `GET /health/articles`(按 view_count 排序) |
|
||||
| **OperatorTodoList** | 今日待办(积分审核/发布文章/活动跟进等) | 前端状态管理(Phase 2 扩展为任务系统) |
|
||||
| **PointsFeed** | 积分动态流(近期获得/兑换) | `GET /health/admin/points/patients/{id}/transactions`(聚合) |
|
||||
| **ContentMatrix** | 内容矩阵(分类分布条形图) | `GET /health/articles`(按分类聚合统计) |
|
||||
|
||||
### 4.3 共享组件
|
||||
|
||||
以下组件在两个角色中复用,与健康管家工作台共享:
|
||||
|
||||
| 组件 | 复用场景 |
|
||||
|------|---------|
|
||||
| **StatCard** | 统计卡片基础样式(顶部色条 + 数值 + 副文本) |
|
||||
| **Card** | 通用卡片容器(圆角 + 边框 + header + body) |
|
||||
|
||||
### 4.4 管理员组件
|
||||
|
||||
| 组件 | 说明 | 数据源 |
|
||||
|------|------|--------|
|
||||
| **SystemHealthBar** | 6 项系统状态指示灯(API/DB/Redis/邮件/存储/定时任务) | Phase 1 前端静态(Phase 2 接 `/api/v1/system/health`) |
|
||||
| **AdminStatsRow** | 4 统计卡片(注册用户/业务模块/今日操作/待处理工单) | `GET /api/v1/users`(总数)+ 前端计算 |
|
||||
| **AuditLogList** | 最近操作记录(操作人+动作+时间) | `GET /api/v1/audit-logs`(最新 6 条) |
|
||||
| **ModuleStatusList** | 模块状态列表(已启用/未启用) | 前端静态配置(模块列表固定) |
|
||||
| **UserActivityChart** | 用户活跃度分布(今日/本周/本月/总注册 + 角色分布) | `GET /api/v1/users`(聚合统计) |
|
||||
| **AdminQuickActions** | 系统管理快捷入口(8 个管理功能) | 前端静态配置 |
|
||||
|
||||
### 4.5 数据优先级说明
|
||||
|
||||
**医生**:核心数据来自 `action-inbox` 系统(与健康管家共享),额外需要 `doctor/dashboard` API 提供预约和日程数据。
|
||||
|
||||
**运营**:核心数据来自 `statistics/dashboard` + `articles` + `points` API,数据维度完全不同,独立于 action-inbox 系统。
|
||||
|
||||
## 5. 数据流
|
||||
|
||||
### 5.1 医生数据源映射
|
||||
|
||||
| 组件 | API | 参数 | 返回 |
|
||||
|------|-----|------|------|
|
||||
| DoctorStatsRow | `GET /health/action-inbox/stats` | — | `WorkbenchStats`(pending_count 等) |
|
||||
| DoctorStatsRow | `GET /health/doctor/dashboard` | — | 预约数、日程数 |
|
||||
| AiSuggestionList | `GET /health/action-inbox` | `type=ai_suggestion, status=pending` | `ActionItem[]` |
|
||||
| FocusedPatientList | `GET /health/action-inbox` | `status=pending`(前端按 patient_id 聚合) | `ActionItem[]` |
|
||||
| TodaySchedule | `GET /health/doctor-schedules` | `date=today` | `ScheduleItem[]` |
|
||||
| ConsultSummary | `GET /health/consultation-sessions` | `status=active, unread=true` | `Consultation[]` |
|
||||
|
||||
**并行请求策略**:页面加载时使用 `Promise.allSettled` 并行请求 stats + list + schedule + consultations。
|
||||
|
||||
### 5.2 运营数据源映射
|
||||
|
||||
| 组件 | API | 参数 | 返回 |
|
||||
|------|-----|------|------|
|
||||
| OperatorStatsRow | `GET /health/admin/statistics/dashboard` | — | 综合统计数据 |
|
||||
| OperatorStatsRow | `GET /health/admin/points/statistics` | — | 积分统计 |
|
||||
| HotContentRank | `GET /health/articles` | `sort=-view_count, page_size=5` | `Article[]` |
|
||||
| ContentMatrix | `GET /health/articles` | `page_size=1`(仅需 total) | 按分类聚合(前端或后端) |
|
||||
| PointsFeed | `GET /health/admin/points/patients` | 最近交易(需后端扩展) | 积分流水 |
|
||||
|
||||
**AI Hero 洞察**:Phase 1 使用前端静态文案(硬编码洞察示例)。Phase 2 接入 AI 生成接口。
|
||||
|
||||
### 5.3 管理员数据源映射
|
||||
|
||||
| 组件 | API | 参数 | 返回 |
|
||||
|------|-----|------|------|
|
||||
| AdminStatsRow | `GET /api/v1/users` | `page=1, page_size=1` | 用户总数(从 pagination.total) |
|
||||
| AuditLogList | `GET /api/v1/audit-logs` | `page=1, page_size=6` | `AuditLogItem[]` |
|
||||
| UserActivityChart | `GET /api/v1/users` | 聚合查询 | 角色分布统计 |
|
||||
| SystemHealthBar | Phase 1 静态 | — | 前端硬编码状态 |
|
||||
| ModuleStatusList | Phase 1 静态 | — | 前端硬编码模块列表 |
|
||||
| AdminQuickActions | 前端静态 | — | 路由配置 |
|
||||
|
||||
**管理员数据特点**:不依赖 `erp-health` 的任何 API,数据来自 ERP 基础模块(用户、审计、配置)。
|
||||
|
||||
### 5.4 与 action-inbox 的关系
|
||||
|
||||
| 角色 | 使用方式 |
|
||||
|------|---------|
|
||||
| 健康管家 | 完全基于 action-inbox,任务队列 + 详情处理 |
|
||||
| 护士 | 复用健康管家工作台(同一任务队列),不做区分 |
|
||||
| 医生 | 部分使用 action-inbox(仅读取 AI 建议和告警),**不做任务处理流程** |
|
||||
| 运营 | 不使用 action-inbox,数据来源独立 |
|
||||
| 管理员 | 不使用 action-inbox,数据来自 ERP 基础模块(用户/审计/配置) |
|
||||
|
||||
医生角色的 action-inbox 使用是**只读展示**:在 AI 建议列表中直接嵌入「采纳/拒绝」按钮,调用 `/health/ai-analysis/:id/review`,不走 action-inbox 的 complete 流程。
|
||||
|
||||
## 6. 交互流程
|
||||
|
||||
### 6.1 医生:AI 建议审核
|
||||
|
||||
以「张伟 — 血压持续升高建议调整用药」为例:
|
||||
|
||||
```
|
||||
1. 进入工作台
|
||||
└→ 4 统计卡片显示:待审 5 条、未回复 3 条
|
||||
|
||||
2. 浏览 AI 建议列表
|
||||
└→ 列表按风险等级排序(高→中→低)
|
||||
└→ 每条建议显示:风险徽章 + 标题 + 摘要 + 采纳/拒绝按钮
|
||||
|
||||
3. 审核建议
|
||||
└→ 点击「采纳」→ 调用 POST /health/ai-analysis/:id/review?action=approve
|
||||
└→ 或点击「拒绝」→ 弹出拒绝原因输入 → 提交
|
||||
└→ 操作完成后,该建议从列表移除
|
||||
|
||||
4. 查看关注患者
|
||||
└→ 下方列表聚合了有告警/AI 建议的患者
|
||||
└→ 点击患者名称 → 跳转患者详情页
|
||||
|
||||
5. 查看右侧信息
|
||||
└→ 日程卡片:了解今日安排
|
||||
└→ 咨询摘要:点击未回复咨询 → 跳转咨询详情页
|
||||
```
|
||||
|
||||
### 6.2 运营:AI 洞察驱动操作
|
||||
|
||||
以「透析饮食管理文章爆发」洞察为例:
|
||||
|
||||
```
|
||||
1. 进入工作台
|
||||
└→ AI Hero 卡片展示 3 条洞察,每条附带操作按钮
|
||||
|
||||
2. 响应洞察
|
||||
└→ 点击「发布关联文章」→ 跳转文章编辑器(预填关联标签)
|
||||
└→ 或点击「审核积分订单」→ 跳转积分订单列表(标记异常)
|
||||
|
||||
3. 查看热门排行
|
||||
└→ 了解哪些内容受欢迎,指导后续内容策略
|
||||
|
||||
4. 处理今日待办
|
||||
└→ 待办列表展示优先级事项
|
||||
└→ 点击操作按钮 → 跳转对应管理页面
|
||||
|
||||
5. 监控积分动态
|
||||
└→ 实时查看积分发放/兑换流水
|
||||
```
|
||||
|
||||
### 6.3 管理员:系统巡检
|
||||
|
||||
```
|
||||
1. 进入工作台
|
||||
└→ 系统健康条显示 6 项服务状态(绿灯/黄灯/红灯)
|
||||
|
||||
2. 确认系统正常
|
||||
└→ 所有绿灯 → 放心继续
|
||||
└→ 发现黄灯(如邮件队列积压)→ 点击进入邮件服务配置
|
||||
|
||||
3. 查看统计卡片
|
||||
└→ 注册用户/业务模块/今日操作/待处理工单
|
||||
|
||||
4. 翻看审计日志
|
||||
└→ 最近 6 条操作记录(谁做了什么)
|
||||
└→ 发现异常操作 → 点击进入完整审计日志
|
||||
|
||||
5. 检查模块状态
|
||||
└→ 确认各模块运行中
|
||||
└→ 发现未启用模块 → 考虑是否启用
|
||||
|
||||
6. 用户活跃度
|
||||
└→ 查看今日/本周/本月活跃数
|
||||
└→ 角色分布确认人员配置合理
|
||||
|
||||
7. 快捷管理入口
|
||||
└→ 点击用户管理/角色权限/系统配置等 → 跳转对应管理页面
|
||||
```
|
||||
|
||||
### 6.4 空状态处理
|
||||
|
||||
| 角色 | 区域 | 空状态展示 |
|
||||
|------|------|-----------|
|
||||
| 医生 | AI 建议列表 | 「暂无待审 AI 建议」 |
|
||||
| 医生 | 关注患者 | 「暂无重点关注患者」 |
|
||||
| 医生 | 咨询摘要 | 「暂无未回复咨询」 |
|
||||
| 医生 | 日程 | 「今日暂无安排」 |
|
||||
| 运营 | AI Hero | 静态内容,不会为空 |
|
||||
| 运营 | 热门排行 | 「暂无发布内容」 |
|
||||
| 运营 | 待办列表 | 「今日暂无待办」 |
|
||||
| 管理员 | 审计日志 | 「暂无操作记录」 |
|
||||
| 管理员 | 系统健康 | 全绿灯,静态展示 |
|
||||
|
||||
### 6.5 前端状态管理
|
||||
|
||||
三个角色各自独立数据获取,30 秒轮询刷新:
|
||||
|
||||
```typescript
|
||||
// 医生工作台 — 使用现有 workbenchStore + 额外请求
|
||||
const DoctorDashboard: React.FC = () => {
|
||||
const { refreshTasks, refreshStats } = useWorkbenchStore();
|
||||
// 额外请求:日程、咨询
|
||||
const [schedules, setSchedules] = useState([]);
|
||||
const [consults, setConsults] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
refreshTasks();
|
||||
refreshStats();
|
||||
Promise.allSettled([
|
||||
doctorApi.getDashboard(),
|
||||
consultationApi.list({ status: 'active', unread: true }),
|
||||
]).then(...);
|
||||
}, []);
|
||||
};
|
||||
|
||||
// 运营工作台 — 独立数据获取,不使用 workbenchStore
|
||||
const OperatorDashboard: React.FC = () => {
|
||||
const [stats, setStats] = useState(null);
|
||||
const [articles, setArticles] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
Promise.allSettled([
|
||||
statsApi.getDashboard(),
|
||||
articlesApi.list({ sort: '-view_count', page_size: 5 }),
|
||||
pointsApi.getStatistics(),
|
||||
]).then(...);
|
||||
}, []);
|
||||
};
|
||||
|
||||
// 管理员工作台 — 独立数据获取,不使用 workbenchStore
|
||||
const AdminDashboard: React.FC = () => {
|
||||
const [auditLogs, setAuditLogs] = useState([]);
|
||||
const [userCount, setUserCount] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
Promise.allSettled([
|
||||
auditLogApi.list({ page: 1, page_size: 6 }),
|
||||
userApi.list({ page: 1, page_size: 1 }), // 只取 total
|
||||
]).then(...);
|
||||
}, []);
|
||||
};
|
||||
```
|
||||
|
||||
## 7. 与现有系统的关系
|
||||
|
||||
### 7.1 角色路由分发
|
||||
|
||||
在 `Home.tsx` 中通过 `useDashboardRole()` 分发不同工作台组件:
|
||||
|
||||
```typescript
|
||||
const HomePage = () => {
|
||||
const role = useDashboardRole();
|
||||
|
||||
switch (role) {
|
||||
case 'doctor':
|
||||
return <DoctorDashboard />;
|
||||
case 'health_manager':
|
||||
case 'nurse':
|
||||
return <HealthManagerDashboard />; // 方案 B TaskQueue + TaskDetail
|
||||
case 'operator':
|
||||
return <OperatorDashboard />;
|
||||
case 'admin':
|
||||
return <AdminDashboard />; // 系统管理中心
|
||||
default:
|
||||
return <AdminDashboard />;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 7.2 涉及文件
|
||||
|
||||
| 文件 | 改动类型 | 说明 |
|
||||
|------|---------|------|
|
||||
| `apps/web/src/pages/Home.tsx` | **改造** | 角色路由分发 + 导入各角色组件 |
|
||||
| `apps/web/src/pages/health/components/workbench/DoctorDashboard.tsx` | **新增** | 医生方案 A 仪表盘 |
|
||||
| `apps/web/src/pages/health/components/workbench/OperatorDashboard.tsx` | **新增** | 运营方案 C AI 指挥中心 |
|
||||
| `apps/web/src/pages/health/components/workbench/AdminDashboard.tsx` | **新增** | 管理员系统管理中心 |
|
||||
| `apps/web/src/pages/health/components/workbench/TaskQueue.tsx` | **已有** | 健康管家方案 B(Phase 1 已实现) |
|
||||
| `apps/web/src/pages/health/components/workbench/TaskDetail.tsx` | **已有** | 健康管家方案 B(Phase 1 已实现) |
|
||||
|
||||
### 7.3 数据库变更
|
||||
|
||||
Phase 1 **无需新建表**。所有数据来自现有 API:
|
||||
- 医生:action-inbox + doctor/dashboard + consultation-sessions + doctor-schedules
|
||||
- 运营:statistics/dashboard + articles + points/statistics
|
||||
- 管理员:users + audit-logs + 前端静态配置
|
||||
|
||||
### 7.4 权限
|
||||
|
||||
沿用现有权限码,无需新增:
|
||||
|
||||
| 角色 | 所需权限码 |
|
||||
|------|-----------|
|
||||
| 医生 | `health.action-inbox.list` + `health.ai-analysis.review` + `health.consultation.manage` + `health.doctor-schedule.list` |
|
||||
| 运营 | `health.statistics.dashboard` + `health.articles.list` + `health.points.manage` |
|
||||
| 管理员 | `system.users.list` + `system.audit-logs.list` + `system.settings.read` |
|
||||
|
||||
### 7.5 验收标准
|
||||
|
||||
**医生工作台:**
|
||||
- [ ] 工作台显示 4 项统计数据(危急值/待审/咨询/预约)
|
||||
- [ ] AI 建议列表按风险排序,每条有采纳/拒绝按钮
|
||||
- [ ] 采纳/拒绝操作调用对应 API 并刷新列表
|
||||
- [ ] 重点关注患者列表聚合展示(告警+AI 建议)
|
||||
- [ ] 右侧日程卡片显示今日排班
|
||||
- [ ] 右侧咨询摘要显示未回复消息
|
||||
- [ ] 空状态有合理展示
|
||||
|
||||
**运营工作台:**
|
||||
- [ ] AI Hero 卡片展示 3 条洞察 + 操作按钮(Phase 1 静态内容)
|
||||
- [ ] 4 项数据指标展示(活跃用户/阅读量/积分发放/待审订单)
|
||||
- [ ] 热门科普排行按阅读量排序(前 5 名)
|
||||
- [ ] 今日待办列表展示优先事项
|
||||
- [ ] 积分动态流展示近期交易
|
||||
- [ ] 内容矩阵展示分类分布
|
||||
- [ ] 空状态有合理展示
|
||||
|
||||
**管理员工作台:**
|
||||
- [ ] 系统健康条展示 6 项服务状态(Phase 1 静态)
|
||||
- [ ] 4 项统计卡片展示(注册用户/业务模块/今日操作/待处理工单)
|
||||
- [ ] 审计日志展示最近 6 条操作记录
|
||||
- [ ] 模块状态列表展示已启用/未启用模块
|
||||
- [ ] 用户活跃度分布展示
|
||||
- [ ] 8 个系统管理快捷入口可点击跳转
|
||||
- [ ] 空状态有合理展示
|
||||
|
||||
**全局:**
|
||||
- [ ] `useDashboardRole()` 正确分发五个角色的工作台视图
|
||||
- [ ] 30 秒自动刷新数据
|
||||
- [ ] `cargo check` 通过
|
||||
- [ ] `pnpm build` 通过
|
||||
- [ ] 浏览器中实际操作验证通过
|
||||
415
docs/superpowers/specs/2026-05-02-hardcoding-cleanup-design.md
Normal file
415
docs/superpowers/specs/2026-05-02-hardcoding-cleanup-design.md
Normal file
@@ -0,0 +1,415 @@
|
||||
# 系统硬编码清理设计规格
|
||||
|
||||
> 日期: 2026-05-02 | 状态: DRAFT | 范围: 前端硬编码清理 + 后端 API 补建 + 常量统一 + 医疗阈值配置化
|
||||
|
||||
---
|
||||
|
||||
## 1. 背景与动机
|
||||
|
||||
HMS 健康管理平台已进入关键节点 — 后端 328 条路由、45 个 Entity、772 个测试函数已就位。但前端工作台页面存在大量硬编码假数据,直接影响系统可信度:
|
||||
|
||||
- **AdminDashboard** 中 70% 面板数据为假值(系统健康条、用户活跃度、模块状态、角色分布)
|
||||
- **OperatorWorkbench** 中积分动态使用假姓名、内容矩阵数字硬编码、待办事项不可操作
|
||||
- 20+ 处状态映射在多个文件中重复定义(严重度映射 5 处、性别映射 4 处、设备类型 3 处)
|
||||
- 医疗报警阈值(血压/心率/血糖)硬编码在小程序前端,不同患者/年龄段无法差异化
|
||||
|
||||
**目标**:清除所有 CRITICAL 级硬编码,确保用户看到的每个数字都来自真实 API,同时建立常量管理规范防止回退。
|
||||
|
||||
**原则**:
|
||||
- 新建 API 全部遵循现有 `/api/v1/` 前缀 + `ApiResponse<T>` 包装 + 多租户隔离
|
||||
- 常量统一采用混合策略:静态枚举收敛到 `constants/health.ts`,动态选项对接字典 API
|
||||
- 医疗阈值复用现有 `critical_value_threshold` 表及 CRUD API,补充患者端只读接口
|
||||
|
||||
---
|
||||
|
||||
## 2. 影响范围与严重度矩阵
|
||||
|
||||
### 2.1 CRITICAL — 用户看到虚假数据
|
||||
|
||||
| ID | 文件 | 硬编码内容 | 影响面 |
|
||||
|----|------|-----------|--------|
|
||||
| C-1 | `AdminDashboard.tsx` 行 108-115 | 系统健康条 6 项全部假数据 | 所有管理员看到的"API服务正常""队列积压12"等均为虚假 |
|
||||
| C-2 | `AdminDashboard.tsx` 行 230-258 | 用户活跃度 4 项 + 角色分布 5 项全部假数据 | 今日活跃 23 人、医生 12 人等均为虚假 |
|
||||
| C-3 | `AdminDashboard.tsx` 行 41-50 | 模块状态 8 项硬编码 | "44 实体 · 328 路由"等描述不反映真实状态 |
|
||||
| C-4 | `AdminDashboard.tsx` 行 87 | 待处理工单硬编码为 5 | 管理员误以为有 5 个工单待处理 |
|
||||
| C-5 | `OperatorWorkbench.tsx` 行 40-44 | 积分动态 3 人假姓名 | 张伟/王建国/李秀英均为虚构 |
|
||||
| C-6 | `OperatorWorkbench.tsx` 行 142-147 | 内容矩阵"已发布 24 / 草稿箱 3"硬编码 | 不反映真实文章数量 |
|
||||
| C-7 | `OperatorWorkbench.tsx` 行 61 | AI Hero 卡片固定文案"3 个运营洞察" | 不随实际数据变化 |
|
||||
|
||||
### 2.2 HIGH — 限制扩展性
|
||||
|
||||
| ID | 类别 | 数量 | 典型案例 |
|
||||
|----|------|------|---------|
|
||||
| H-1 | 重复状态映射 | 20+ 处 | SEVERITY_COLOR 在 5 个文件各自定义 |
|
||||
| H-2 | 动态选项硬编码 | 6 类 | 科室/职称/设备类型/随访类型/咨询类型/家庭关系 |
|
||||
| H-3 | 默认角色为 admin | 1 处 | `useDashboardRole.ts` 无角色时返回 admin |
|
||||
| H-4 | 医疗阈值硬编码 | 2 处 | 血压 140/90、心率 100/60、血糖 6.1/7.8 |
|
||||
|
||||
### 2.3 MEDIUM — 代码质量
|
||||
|
||||
| ID | 类别 | 说明 |
|
||||
|----|------|------|
|
||||
| M-1 | 小程序菜单用中文做 key | `MENU_PATHS` 用中文字符串做映射 key |
|
||||
| M-2 | 待办模板硬编码 | 5 条固定待办文本,不可操作 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 轨道 1:工作台真实数据化
|
||||
|
||||
### 3.1 现有 API 清单与缺口分析
|
||||
|
||||
**已有且已被前端调用的 API:**
|
||||
|
||||
| API | 路径 | 使用者 |
|
||||
|-----|------|--------|
|
||||
| 工作台统计 | `GET /health/action-inbox/stats` → `WorkbenchStats` | DoctorWorkbench, OperatorWorkbench |
|
||||
| 团队概览 | `GET /health/action-inbox/team` → `TeamOverview` | DoctorWorkbench |
|
||||
| 行动收件箱 | `GET /health/action-inbox` → `ActionItem[]` | DoctorWorkbench |
|
||||
| 6 类统计 | `useStatsData` → patient/consultation/followup/points/healthData/dialysis | 三个工作台 |
|
||||
| 个人统计 | `pointsApi.getPersonalStats` → `PersonalStats` | DoctorWorkbench |
|
||||
| 审计日志 | `listAuditLogs` | AdminDashboard |
|
||||
|
||||
**缺口 — 需要新建的 5 个 API:**
|
||||
|
||||
### 3.2 新增后端 API 设计
|
||||
|
||||
#### API-1: 系统健康检查
|
||||
|
||||
```
|
||||
GET /health/admin/system-health
|
||||
(完整路径: /api/v1/health/admin/system-health,前缀由 erp-server nest 自动添加)
|
||||
权限: health.dashboard.manage(新增,需在 module.rs 权限描述符中注册)
|
||||
响应: ApiResponse<SystemHealth>
|
||||
```
|
||||
|
||||
```typescript
|
||||
interface SystemHealth {
|
||||
services: {
|
||||
name: string; // "API 服务" / "数据库" / "Redis" / ...
|
||||
status: 'healthy' | 'degraded' | 'down';
|
||||
message: string; // "正常" / "队列积压 12" / "连接超时"
|
||||
response_ms?: number;
|
||||
}[];
|
||||
checked_at: string; // ISO timestamp
|
||||
}
|
||||
```
|
||||
|
||||
实现:后端 handler 逐项检查 DB 连接(`SELECT 1`)、Redis PING、SMTP 配置状态、存储路径可用性、定时任务心跳。结果缓存 30 秒避免频繁检查。
|
||||
|
||||
#### API-2: 用户活跃度统计
|
||||
|
||||
```
|
||||
GET /health/admin/user-activity
|
||||
权限: health.dashboard.manage(同 API-1)
|
||||
响应: ApiResponse<UserActivity>
|
||||
```
|
||||
|
||||
```typescript
|
||||
interface UserActivity {
|
||||
daily_active: number;
|
||||
weekly_active: number;
|
||||
monthly_active: number;
|
||||
total_registered: number;
|
||||
by_role: {
|
||||
role: string; // "医生" / "护士" / ...
|
||||
count: number;
|
||||
}[];
|
||||
}
|
||||
```
|
||||
|
||||
实现:基于 `users` 表 `last_login_at` 字段统计,角色分布通过 `user_roles` JOIN `roles` 聚合。
|
||||
|
||||
#### API-3: 模块状态
|
||||
|
||||
```
|
||||
GET /health/admin/modules
|
||||
权限: health.dashboard.manage(同 API-1)
|
||||
响应: ApiResponse<ModuleStatus[]>
|
||||
```
|
||||
|
||||
```typescript
|
||||
interface ModuleStatus {
|
||||
name: string; // "erp-health" / "erp-auth" / ...
|
||||
display_name: string; // "健康管理" / "身份权限" / ...
|
||||
description: string;
|
||||
active: boolean;
|
||||
entity_count?: number;
|
||||
route_count?: number;
|
||||
}
|
||||
```
|
||||
|
||||
实现:从 AppState 中读取已注册的 `ErpModule` 列表 + 查询 `plugins` 表补充插件状态。
|
||||
|
||||
#### API-4: 积分动态流
|
||||
|
||||
```
|
||||
GET /health/points/recent-activity?limit=10
|
||||
权限: health.points.list
|
||||
响应: ApiResponse<PointsActivityItem[]>
|
||||
```
|
||||
|
||||
> **命名约定**:TypeScript 接口字段使用 snake_case 镜像后端字段名,与本项目既有模式一致。
|
||||
|
||||
```typescript
|
||||
interface PointsActivityItem {
|
||||
id: string;
|
||||
user_name: string; // 患者姓名
|
||||
detail: string; // "兑换 · 血压计袖带" / "每日上报 · 血压"
|
||||
amount: string; // "+10" / "-500"
|
||||
type: 'earn' | 'spend';
|
||||
created_at: string;
|
||||
}
|
||||
```
|
||||
|
||||
实现:查询 `points_account_transactions` 最新 N 条,JOIN `patients` 获取姓名。
|
||||
|
||||
#### API-5: 内容统计
|
||||
|
||||
```
|
||||
GET /health/articles/stats
|
||||
权限: health.articles.list(注意复数形式,匹配 module.rs 注册的权限码)
|
||||
响应: ApiResponse<ArticleStats>
|
||||
```
|
||||
|
||||
```typescript
|
||||
interface ArticleStats {
|
||||
published: number;
|
||||
draft: number;
|
||||
pending_review: number;
|
||||
rejected: number;
|
||||
total_views: number;
|
||||
}
|
||||
```
|
||||
|
||||
实现:`SELECT status, COUNT(*) FROM articles WHERE tenant_id = $1 AND deleted_at IS NULL GROUP BY status`。
|
||||
|
||||
### 3.3 工作台页面改造方案
|
||||
|
||||
#### AdminDashboard 改造
|
||||
|
||||
| 面板 | 当前(假数据) | 改造后(真实数据) |
|
||||
|------|---------------|-------------------|
|
||||
| 系统健康条 | 6 项硬编码 | 调用 API-1 `systemHealth` |
|
||||
| 统计卡片 - 注册用户 | useStatsData (已真实) | 保持不变 |
|
||||
| 统计卡片 - 业务模块 | 硬编码 MODULES.length | 调用 API-3 计算活跃数 |
|
||||
| 统计卡片 - 今日操作 | auditLogs.length (已真实) | 保持不变 |
|
||||
| 统计卡片 - 待处理工单 | 硬编码 5 | 改用 actionInboxApi.stats().total_pending |
|
||||
| 用户活跃度 | 4 项百分比 + 角色分布全部假 | 调用 API-2 `userActivity` |
|
||||
| 模块状态 | MODULES 数组硬编码 | 调用 API-3 `modules` |
|
||||
| 快捷管理 | QUICK_ACTIONS 硬编码 | 保留(属 UI 配置) |
|
||||
| 问候语 "X主任" | 硬编码"主任" | 移除称呼后缀,只显示姓 |
|
||||
|
||||
#### OperatorWorkbench 改造
|
||||
|
||||
| 面板 | 当前 | 改造后 |
|
||||
|------|------|--------|
|
||||
| AI Hero 卡片 | 固定文案 "3 个运营洞察" | 动态生成文案基于 stats 数据 |
|
||||
| 统计卡片 | useStatsData + actionInbox (已真实) | 保持不变 |
|
||||
| 今日待办 | 5 条硬编码 todo 模板 | 改用 actionInboxApi.list 筛选 pending 项 |
|
||||
| 积分动态 | 3 人假姓名 | 调用 API-4 `recentActivity` |
|
||||
| 内容矩阵 | "已发布 24 / 草稿箱 3" | 调用 API-5 `articleStats` |
|
||||
| 问候语 "X美玲" | 硬编码"美玲" | 移除,只显示姓 |
|
||||
|
||||
#### DoctorWorkbench
|
||||
|
||||
基本已是真实数据(80%),仅需微调:
|
||||
- 问候语 "X医生" 中"医生"后缀 → 移除,只显示姓
|
||||
- 确认 `personalStats.consultations_this_month` 字段后端已实现(否则用 0 占位)
|
||||
|
||||
---
|
||||
|
||||
## 4. 轨道 2:常量统一
|
||||
|
||||
### 4.1 分类原则
|
||||
|
||||
| 分类 | 存放位置 | 判断标准 | 例子 |
|
||||
|------|---------|---------|------|
|
||||
| 静态映射 | `constants/health.ts` | 枚举固定,后端不可能新增项 | 性别、血型、严重度颜色、状态颜色 |
|
||||
| 动态选项 | 后端字典 API | 业务运营可能新增 | 科室、职称、设备类型、随访类型 |
|
||||
| UI 配置 | 各组件内部 | 纯前端行为,无后端对应 | 快捷操作按钮、Tab 标签文案 |
|
||||
|
||||
### 4.2 静态映射收敛
|
||||
|
||||
统一以下映射组到 `constants/health.ts`,消除所有重复定义:
|
||||
|
||||
| 导出名 | 当前分散位置 | 统一后 |
|
||||
|--------|------------|--------|
|
||||
| `SEVERITY_CONFIG` | AlertDashboard, AlertList, AlertRuleList, ActionInbox, DoctorDashboard (5处) | 1 处 |
|
||||
| `GENDER_OPTIONS` | constants/health.ts, PatientDetail, PatientTagManage, PatientSelect (4处) | 1 处 |
|
||||
| `DEVICE_TYPE_OPTIONS` + `DEVICE_TYPE_COLOR` | DeviceManage, DeviceReadingsTab, AlertRuleList (3处) | 1 处 |
|
||||
| `ALERT_STATUS_CONFIG` | AlertDashboard, AlertList, StatusTag (3处) | 1 处 |
|
||||
| `APPOINTMENT_STATUS_CONFIG` | AppointmentList (1处但含复杂流转) | 1 处 |
|
||||
| `CONSULTATION_STATUS_CONFIG` | ConsultationList (1处) | 1 处 |
|
||||
| `BLOOD_TYPE_OPTIONS` | constants/health.ts (1处) | 保持 |
|
||||
| `STATUS_OPTIONS` (患者状态) | constants/health.ts (1处) | 保持 |
|
||||
|
||||
每个映射组的统一格式:
|
||||
|
||||
```typescript
|
||||
export const SEVERITY_CONFIG: Record<string, { label: string; color: string; bg: string }> = {
|
||||
critical: { label: '危急', color: '#DC2626', bg: '#FEF2F2' },
|
||||
high: { label: '高', color: '#D97706', bg: '#FFFBEB' },
|
||||
medium: { label: '中', color: '#2563EB', bg: '#EFF6FF' },
|
||||
low: { label: '低', color: '#6B7280', bg: '#F9FAFB' },
|
||||
};
|
||||
```
|
||||
|
||||
### 4.3 动态选项字典化
|
||||
|
||||
新增以下字典编码到 `erp-config` 的字典系统(后端已有 `GET /config/dictionaries/items?code=xxx` API,前端 `apps/web/src/api/dictionaries.ts` 已封装 `listItemsByCode`):
|
||||
|
||||
| 字典编码 | 用途 | 种子数据来源 | 影响文件 |
|
||||
|----------|------|-------------|---------|
|
||||
| `health_department` | 科室列表 | DoctorList 现有 DEPARTMENT_OPTIONS | DoctorList, DoctorSchedule |
|
||||
| `health_title` | 医护职称 | DoctorList 现有 TITLE_OPTIONS | DoctorList |
|
||||
| `health_device_type` | 设备类型 | DeviceManage 现有 DEVICE_TYPE_OPTIONS | DeviceManage, DeviceReadingsTab, AlertRuleList |
|
||||
| `health_follow_up_type` | 随访类型 | FollowUpTaskList 现有 FOLLOW_UP_TYPE_OPTIONS | FollowUpTaskList |
|
||||
| `health_consultation_type` | 咨询类型 | ConsultationList 现有 CONSULTATION_TYPE_OPTIONS | ConsultationList |
|
||||
| `health_relationship` | 家庭关系 | FamilyMembersTab 现有 RELATIONSHIP_OPTIONS | FamilyMembersTab, family-add(MP) |
|
||||
|
||||
前端新增 `useDictionary(code)` hook 封装字典获取 + 缓存逻辑:
|
||||
|
||||
```typescript
|
||||
export function useDictionary(code: string) {
|
||||
const [items, setItems] = useState<DictionaryItem[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
listItemsByCode(code)
|
||||
.then(setItems)
|
||||
.catch(() => setItems([]))
|
||||
.finally(() => setLoading(false));
|
||||
}, [code]);
|
||||
|
||||
return { items, loading };
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 小程序联动
|
||||
|
||||
小程序对应的硬编码同步改为字典 API:
|
||||
|
||||
| 文件 | 当前硬编码 | 改造 |
|
||||
|------|-----------|------|
|
||||
| `pages/pkg-health/input/index.tsx` INDICATORS | 6 个体征指标 | 从字典获取 + 缓存 |
|
||||
| `pages/health/index.tsx` VITAL_TABS | 4 个体征 tab | 从字典获取 |
|
||||
| `pages/pkg-profile/family-add/index.tsx` RELATION_OPTIONS | 3 个关系选项 | 从字典获取 |
|
||||
| `pages/pkg-profile/family-add/index.tsx` GENDER_OPTIONS | 3 个性别选项 | 保留为静态映射(不在字典化范围) |
|
||||
| `pages/mall/index.tsx` PRODUCT_TYPE_TABS | 商品类型 tab | 从字典获取 |
|
||||
|
||||
小程序端新增 `useDict(code)` hook + Taro.storage 本地缓存(24h TTL),离线时使用缓存或内置默认值。
|
||||
|
||||
---
|
||||
|
||||
## 5. 轨道 3:医疗阈值配置
|
||||
|
||||
### 5.1 复用现有 `critical_value_threshold` 表
|
||||
|
||||
系统已有完整的危急值阈值基础设施,**无需新建表**:
|
||||
|
||||
- **表**: `critical_value_threshold`(迁移 `m20260426_000060`)
|
||||
- **Entity**: `crates/erp-health/src/entity/critical_value_threshold.rs`
|
||||
- **Handler**: `crates/erp-health/src/handler/critical_value_threshold_handler.rs`
|
||||
- **Service**: `crates/erp-health/src/service/critical_value_threshold_service.rs`
|
||||
- **路由**: `/health/critical-value-thresholds`(CRUD 已注册,见 `module.rs` 行 602-609)
|
||||
- **权限**: `health.critical-value-thresholds.list` + `health.critical-value-thresholds.manage`(已定义)
|
||||
- **种子数据**: 8 条默认记录已存在
|
||||
|
||||
现有表字段:`indicator`、`direction`(高/低)、`threshold_value`、`level`(警告/危急)、`department`、`age_min`、`age_max`、`is_active` + 标准审计字段。
|
||||
|
||||
### 5.2 需补充的工作
|
||||
|
||||
| 工作项 | 说明 |
|
||||
|--------|------|
|
||||
| 补充 warning 级别种子数据 | 现有种子仅有 critical 级别,需新增 warning 级别阈值(血压 140/90、心率 100/60、血糖 6.1/7.8) |
|
||||
| 新增患者端只读 API | `GET /health/critical-value-thresholds/public` — 认证即可,无需管理权限,返回当前租户所有 `is_active` 阈值 |
|
||||
| Web 端阈值管理 UI | 在告警规则管理页面增加"阈值配置"Tab,复用现有 CRUD API |
|
||||
|
||||
### 5.3 前端改造
|
||||
|
||||
**小程序改造流程:**
|
||||
|
||||
1. App 启动时调用 `GET /health/critical-value-thresholds/public` 获取全量阈值
|
||||
2. 存入 `Taro.storage`(key: `health_thresholds`,TTL: 24h)
|
||||
3. 体征页 `health/index.tsx` 从缓存读取阈值替代 `REF_RANGES` 和判断逻辑
|
||||
4. 输入页 `pkg-health/input/index.tsx` 从缓存读取阈值替代 `WARN_THRESHOLDS`
|
||||
5. 缓存未命中时使用内置默认值(与当前硬编码值一致)
|
||||
|
||||
### 5.4 补充种子数据(warning 级别)
|
||||
|
||||
新增迁移脚本插入 warning 级别阈值(现有 critical 级别已由 `m20260426_000060` 种子覆盖):
|
||||
|
||||
| indicator | level | direction | threshold_value | 说明 |
|
||||
|-----------|-------|-----------|-----------------|------|
|
||||
| blood_pressure_systolic | warning | high | 140 | 收缩压参考上限 |
|
||||
| blood_pressure_diastolic | warning | high | 90 | 舒张压参考上限 |
|
||||
| heart_rate | warning | high | 100 | 心率参考上限 |
|
||||
| heart_rate | warning | low | 60 | 心率参考下限 |
|
||||
| blood_sugar_fasting | warning | high | 6.1 | 空腹血糖参考上限 |
|
||||
| blood_sugar_postprandial | warning | high | 7.8 | 餐后血糖参考上限 |
|
||||
|
||||
共 6 条 warning 级别配置,与现有 8 条 critical 级别共同构成完整的阈值体系。
|
||||
|
||||
---
|
||||
|
||||
## 6. 跨切面关注点
|
||||
|
||||
### 6.1 错误处理
|
||||
|
||||
- 所有新建 API 遵循现有 `AppError` → `ApiResponse` 错误链
|
||||
- 前端调用失败时降级显示:统计卡片显示 "—",列表显示"暂无数据"
|
||||
- 系统健康检查 API 本身失败时,前端显示"检查中..."而非假数据
|
||||
|
||||
### 6.2 测试策略
|
||||
|
||||
| 层级 | 测试内容 | 工具 |
|
||||
|------|---------|------|
|
||||
| 后端单元测试 | 每个 handler + service 函数 | `#[tokio::test]` |
|
||||
| 后端集成测试 | 5 个新 API 的完整请求/响应 | Testcontainers |
|
||||
| 前端单元测试 | `useDictionary` hook + 常量导出一致性 | vitest |
|
||||
| 前端组件测试 | 工作台页面 loading/empty/data 三态渲染 | vitest + testing-library |
|
||||
| E2E 测试 | 工作台页面加载无硬编码假数据 | playwright |
|
||||
|
||||
### 6.3 迁移与部署顺序
|
||||
|
||||
三条轨道互不依赖,但建议按以下顺序部署:
|
||||
|
||||
1. **轨道 2(常量统一)** — 纯前端重构,零后端改动,可立即部署
|
||||
2. **轨道 3(医疗阈值)** — 复用现有表,仅需补充种子数据 + 新增患者端只读 API,独立部署
|
||||
3. **轨道 1(工作台 API)** — 需要新建 5 个 API,最后部署
|
||||
|
||||
轨道 1 内部的 API 实现顺序:
|
||||
1. API-5 内容统计(最简单,单表 COUNT)
|
||||
2. API-4 积分动态(单表 JOIN)
|
||||
3. API-3 模块状态(读取 AppState)
|
||||
4. API-2 用户活跃度(多表聚合)
|
||||
5. API-1 系统健康检查(外部连接检测)
|
||||
|
||||
---
|
||||
|
||||
## 7. 验证清单
|
||||
|
||||
### 轨道 1 验证
|
||||
- [ ] AdminDashboard 系统健康条数据来自 API(不出现假数据)
|
||||
- [ ] AdminDashboard 用户活跃度数据来自 API
|
||||
- [ ] AdminDashboard 模块状态来自 API
|
||||
- [ ] OperatorWorkbench 积分动态来自 API
|
||||
- [ ] OperatorWorkbench 内容矩阵来自 API
|
||||
- [ ] OperatorWorkbench 待办来自 actionInbox
|
||||
- [ ] 全部 5 个新 API 在 Swagger UI 可测试
|
||||
- [ ] `cargo test --workspace` 全部通过
|
||||
- [ ] `pnpm build` 前端构建通过
|
||||
|
||||
### 轨道 2 验证
|
||||
- [ ] `SEVERITY_CONFIG` 仅在 `constants/health.ts` 定义一次,其余 4 处改为引用
|
||||
- [ ] `GENDER_OPTIONS` 仅在 `constants/health.ts` 定义一次
|
||||
- [ ] 6 个字典编码在后端种子数据中存在
|
||||
- [ ] `useDictionary` hook 可正常获取字典数据
|
||||
- [ ] 小程序 `useDict` hook + storage 缓存工作正常
|
||||
|
||||
### 轨道 3 验证
|
||||
- [ ] `critical_value_threshold` 表已有 + warning 级别种子数据 6 条正确插入
|
||||
- [ ] 患者端只读 API `GET /health/critical-value-thresholds/public` 可正常访问
|
||||
- [ ] 小程序体征页使用 API 阈值(非硬编码)
|
||||
- [ ] 小程序输入页使用 API 阈值(非硬编码)
|
||||
- [ ] 离线场景下降级到内置默认值
|
||||
@@ -0,0 +1,297 @@
|
||||
# 健康管家工作台 — 方案 B「工作流驱动」设计规格
|
||||
|
||||
> 日期: 2026-05-02 | 状态: 设计中(评审后修订 v2)
|
||||
> 原型参考: `_temp/workbench-health-manager-B.html`
|
||||
> 评审记录: 发现 7 CRITICAL + 5 IMPORTANT,已全部修复
|
||||
|
||||
## 1. 背景与目标
|
||||
|
||||
### 1.1 为什么要重新设计
|
||||
|
||||
现有工作台(方案 A/D/E/F)基于「临床医生管理透析团队」的假设设计。实际用户场景已明确:
|
||||
|
||||
- 机构已有 HIS + 专用血透系统,HMS 不碰临床透析流程
|
||||
- HMS 定位是**患者与机构之间的纽带**:日常健康数据采集、随访干预、积分运营、健康科普
|
||||
- 工作台的第一用户是**健康管家/随访护士**,不是做透析的医生
|
||||
|
||||
### 1.2 目标
|
||||
|
||||
| 指标 | 当前 | 目标 |
|
||||
|------|------|------|
|
||||
| 健康管家每日任务处理效率 | 无专门工作台,散落在各页面 | 统一入口,一件一件处理 |
|
||||
| 任务遗漏率 | 未知(无追踪) | ≤2%(系统强制排序 + 超时提醒) |
|
||||
| AI 建议触达率 | 有 AI 洞察面板但无强制处理流程 | 任务流中自动注入,100% 触达 |
|
||||
| 平均任务响应时间 | 无数据 | 危急 ≤30min,紧急 ≤2h,普通 ≤24h |
|
||||
|
||||
### 1.3 范围
|
||||
|
||||
**分两期实施:**
|
||||
|
||||
| 阶段 | 任务类型 | 数据源状态 |
|
||||
|------|---------|-----------|
|
||||
| **Phase 1(本期)** | 体征告警、AI 建议待审、到期随访 | ✅ 现有 `action_inbox_service.rs` 已聚合 |
|
||||
| **Phase 2(后续)** | 患者咨询、积分审批、体征少报提醒、干预评估 | ⏳ 需扩展数据源或新建调度 |
|
||||
|
||||
- **本期(Phase 1)**:健康管家/随访护士角色,3 种任务类型,三栏工作流布局
|
||||
- **不在本期**:医生角色、运营角色、方案 A/C、Phase 2 任务类型
|
||||
|
||||
## 2. 角色定义 — 健康管家「刘小燕」
|
||||
|
||||
### 2.1 人物画像
|
||||
|
||||
| 维度 | 描述 |
|
||||
|------|------|
|
||||
| 姓名 | 刘小燕 |
|
||||
| 职位 | 主管护师 / 健康管家 |
|
||||
| 年龄 | 32 岁 |
|
||||
| 工作经验 | 8 年护理,3 年健康管理 |
|
||||
| 技术水平 | 熟练使用手机 App,PC 端基本操作无障碍 |
|
||||
| 日均任务量 | 20-30 项(随访 8-12、体征审核 4-6、AI 建议 3-5、其他 3-5) |
|
||||
|
||||
### 2.2 典型工作日
|
||||
|
||||
```
|
||||
08:00 打开工作台,按优先级处理紧急体征告警
|
||||
08:30 逐个处理血压/血糖异常告警(电话随访 + 记录)
|
||||
10:00 处理 AI 建议待审(审核并采纳或转给医生)
|
||||
14:00 处理到期随访任务(电话/微信随访 + 记录)
|
||||
16:00 回复患者咨询、处理积分兑换等(跳转对应模块)
|
||||
17:00 检查今日完成情况,确认无遗漏后下班
|
||||
```
|
||||
|
||||
### 2.3 核心痛点
|
||||
|
||||
1. **任务分散**:随访、体征、AI 建议散落在不同菜单,频繁切换
|
||||
2. **优先级不清**:不知道该先处理哪个,容易遗漏紧急告警
|
||||
3. **上下文缺失**:处理一个告警时需要单独打开患者详情查看历史
|
||||
4. **AI 建议利用率低**:AI 面板在角落,不强制处理,容易被忽略
|
||||
|
||||
## 3. 信息架构 — 三栏布局
|
||||
|
||||
### 3.1 布局结构
|
||||
|
||||
**注意**:侧边栏由全局布局提供(`apps/web/src/layouts/`),工作台页面内部只有两栏(任务队列 + 详情面板)。
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────┐
|
||||
│ 全局侧边栏(已有,不动) │ 工作台页面内部 │
|
||||
│ │ │
|
||||
│ ... │ ┌────────────┬──────────────┐ │
|
||||
│ ⚡ 工作流(高亮) │ │ 任务队列 │ 详情处理面板 │ │
|
||||
│ 📋 随访管理 │ │ 340px │ flex:1 │ │
|
||||
│ 🩺 体征监测 │ │ │ │ │
|
||||
│ 💬 患者咨询 │ │ 头部统计 │ 患者信息栏 │ │
|
||||
│ ... │ │ Tab 切换 │ 异常数据 │ │
|
||||
│ │ │ 任务列表 │ AI 建议 │ │
|
||||
│ │ │ │ 互动记录 │ │
|
||||
│ │ │ │ 操作按钮 │ │
|
||||
│ │ └────────────┴──────────────┘ │
|
||||
└──────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3.2 两栏职责
|
||||
|
||||
| 区域 | 职责 | 交互 |
|
||||
|------|------|------|
|
||||
| **任务队列** | 按优先级排列的待处理任务 + 统计 | 点击选中 → 右侧加载详情 |
|
||||
| **详情面板** | 当前任务的完整上下文 + 操作 | 处理完成后自动跳转下一任务 |
|
||||
|
||||
### 3.3 全局侧边栏菜单调整
|
||||
|
||||
在现有全局侧边栏中,将「工作台」菜单项更名为「工作流」,点击进入方案 B 的三栏工作台。其他菜单项不变。
|
||||
|
||||
## 4. 组件清单
|
||||
|
||||
### 4.1 任务队列组件
|
||||
|
||||
| 组件 | 说明 | 数据源 |
|
||||
|------|------|--------|
|
||||
| **QueueHeader** | 队列统计(待处理/已完成) | `GET /health/action-inbox/stats`(现有) |
|
||||
| **QueueTabs** | Tab 切换:待处理 / 已完成 | 前端状态 |
|
||||
| **TaskItem** | 单个任务卡片:优先级圆点 + 标题 + 元信息 + 标签 + 时间 | 现有 `list_action_inbox` API |
|
||||
| **TaskList** | 可滚动的任务列表容器 | Ant Design `List` + `InfiniteScroll` |
|
||||
|
||||
### 4.2 详情面板组件
|
||||
|
||||
| 组件 | 适用任务类型 | 说明 | 数据源 |
|
||||
|------|-------------|------|--------|
|
||||
| **PatientBar** | 全部 | 患者头像 + 姓名 + 年龄 + 科室 + 病史标签 | `GET /health/patients/:id`(现有) |
|
||||
| **VitalAlertDetail** | 体征异常 | 异常数值 + 近 7 天趋势图 + 参考范围 | `GET /health/action-inbox/:source_ref/thread`(现有)+ `GET /health/vital-signs/trends`(现有) |
|
||||
| **AiSuggestionCard** | AI 建议 | 风险评估 + 建议措施 + 采纳/拒绝操作 | thread API(现有) |
|
||||
| **FollowUpForm** | 到期随访 | 随访表单 + 上次随访摘要 | thread API(现有) |
|
||||
| **InteractionTimeline** | 全部 | 患者近期互动记录 | `GET /health/action-inbox/:source_ref/thread`(现有) |
|
||||
| **ActionBar** | 全部 | 底部操作按钮(因任务类型不同而变化) | — |
|
||||
|
||||
### 4.3 任务类型与优先级(Phase 1 仅 3 种)
|
||||
|
||||
| 优先级 | 类型 | 自动生成规则 | 目标响应时间 | 数据源 |
|
||||
|--------|------|-------------|-------------|--------|
|
||||
| **危急 (P0)** | 体征危急值告警 | 告警系统生成 | ≤30 分钟 | `alerts` 表 |
|
||||
| **紧急 (P1)** | AI 建议待审 | AI 分析引擎生成 | ≤2 小时 | `ai_analysis` 表 |
|
||||
| **普通 (P2)** | 到期随访 | 随访计划到期 | ≤24 小时 | `follow_up_task` 表 |
|
||||
|
||||
### 4.4 任务 ID 格式
|
||||
|
||||
沿用现有 `action_inbox_service.rs` 的复合 ID 格式:`"{action_type}:{uuid}"`
|
||||
|
||||
- 告警任务:`"alert:550e8400-..."`
|
||||
- AI 建议:`"ai_suggestion:660e8400-..."`
|
||||
- 随访任务:`"follow_up:770e8400-..."`
|
||||
|
||||
操作分发逻辑:解析 `action_type` 前缀,路由到对应的底层服务。
|
||||
|
||||
## 5. 数据流与排序
|
||||
|
||||
### 5.1 任务生命周期
|
||||
|
||||
```
|
||||
[自动生成] → [进入队列] → [选中处理] → [执行操作] → [完成/转交]
|
||||
↑ │
|
||||
└── 超时未处理 → 升级优先级 ←──────────────┘
|
||||
```
|
||||
|
||||
### 5.2 现有 API 复用策略
|
||||
|
||||
不新建 API 路径。**改造现有 `action-inbox` 系列接口**:
|
||||
|
||||
| 现有 API | 改造内容 |
|
||||
|---------|---------|
|
||||
| `GET /health/action-inbox` | 增加按优先级排序(改 SQL ORDER BY) |
|
||||
| `GET /health/action-inbox/stats` | 增加「已完成」计数 |
|
||||
| `GET /health/action-inbox/:source_ref/thread` | 增加 patient 上下文字段 |
|
||||
| `POST /health/alerts/:id/acknowledge` | 沿用(完成告警任务) |
|
||||
| `POST /health/ai-analysis/:id/review` | 沿用(采纳/拒绝 AI 建议) |
|
||||
| `POST /health/follow-up/:id/complete` | 沿用(完成随访任务) |
|
||||
|
||||
详情面板的患者信息、趋势图通过**前端并行调用**现有 API 获取:
|
||||
- `GET /health/patients/:id` → PatientBar
|
||||
- `GET /health/vital-signs/trends?patient_id=&days=7` → VitalAlertDetail
|
||||
- `GET /health/action-inbox/:source_ref/thread` → InteractionTimeline + 核心任务数据
|
||||
|
||||
前端用 `Promise.allSettled` 并行请求,加载中显示 Skeleton。
|
||||
|
||||
### 5.3 排序规则修复
|
||||
|
||||
现有 SQL 使用 `created_at DESC`(新的在前),需改为 `created_at ASC`(早的在前,FIFO),与设计规格一致。优先级映射从 3 级扩展为 4 级:
|
||||
|
||||
```sql
|
||||
ORDER BY
|
||||
CASE priority_raw
|
||||
WHEN 'critical' THEN 0 -- P0 新增
|
||||
WHEN 'high' THEN 1
|
||||
WHEN 'urgent' THEN 1
|
||||
WHEN 'medium' THEN 2
|
||||
ELSE 3
|
||||
END,
|
||||
created_at ASC -- 改为 ASC
|
||||
```
|
||||
|
||||
## 6. 交互流程 — 处理一个任务的完整闭环
|
||||
|
||||
以「张伟 — 血压危急值 188/102」为例:
|
||||
|
||||
```
|
||||
1. 进入工作台
|
||||
└→ 任务队列自动加载,张伟的告警排在最前(P0)
|
||||
|
||||
2. 点击任务
|
||||
└→ 右侧详情面板加载(并行请求患者信息 + thread + 趋势):
|
||||
- 患者信息栏:张伟 / 男 / 58岁 / 血透中心 / 高血压3级
|
||||
- 异常数据:收缩压 188 / 舒张压 102 / 心率 92
|
||||
- 近 7 天收缩压趋势图(柱状图)
|
||||
- 近期互动记录
|
||||
|
||||
3. 执行操作
|
||||
└→ 点击「立即电话随访」
|
||||
└→ 弹出电话随访表单(预设患者电话号码)
|
||||
└→ 填写随访记录:确认用药 / 伴随症状 / 处理建议
|
||||
└→ 提交 → 调用 POST /health/alerts/:id/acknowledge
|
||||
|
||||
4. 任务完成
|
||||
└→ 任务从「待处理」移至「已完成」
|
||||
└→ 队列自动选中下一个任务
|
||||
└→ 右侧面板加载新任务的详情
|
||||
|
||||
5. 可选操作
|
||||
└→ 「转给医生」:更改 assigned_to → 对应医生(需 migration 加字段,Phase 2)
|
||||
└→ 「稍后处理」:本地状态,置底并标记延迟时间
|
||||
```
|
||||
|
||||
### 6.1 操作按钮矩阵(Phase 1)
|
||||
|
||||
| 任务类型 | 主操作 | 次要操作 | 底层 API |
|
||||
|---------|--------|---------|---------|
|
||||
| 体征异常告警 | 记录处理结果 + 确认 | 稍后处理 | `POST /health/alerts/:id/acknowledge` |
|
||||
| AI 建议待审 | 采纳 / 拒绝 | 稍后处理 | `POST /health/ai-analysis/:id/review` |
|
||||
| 到期随访 | 开始随访(电话/线上/面访) | 稍后处理 | `POST /health/follow-up/:id/complete` |
|
||||
|
||||
### 6.2 空状态处理
|
||||
|
||||
- 队列为空时:显示「所有任务已处理完毕」+ 今日完成统计
|
||||
- 详情面板未选中任务时:显示空态引导「从左侧选择一个任务开始处理」
|
||||
- 加载中:Skeleton 占位
|
||||
|
||||
### 6.3 前端状态管理
|
||||
|
||||
使用 Zustand store `useWorkbenchStore`:
|
||||
|
||||
```typescript
|
||||
interface WorkbenchState {
|
||||
tasks: ActionItem[]; // 任务列表
|
||||
selectedTaskId: string | null; // 当前选中任务
|
||||
completedCount: number; // 今日完成数
|
||||
tab: 'pending' | 'completed'; // 当前 Tab
|
||||
|
||||
selectTask: (id: string) => void;
|
||||
completeTask: (id: string) => Promise<void>;
|
||||
refreshTasks: () => Promise<void>;
|
||||
}
|
||||
```
|
||||
|
||||
实时刷新策略:Phase 1 使用 30 秒轮询(`setInterval` + `refreshTasks`),Phase 2 考虑升级为 SSE。
|
||||
|
||||
## 7. 与现有系统的关系
|
||||
|
||||
### 7.1 改造策略
|
||||
|
||||
改造现有的 `Home.tsx` 工作台页面,替换当前仪表盘布局为方案 B 的任务队列 + 详情面板两栏布局。
|
||||
|
||||
**不新建页面**,在现有路由 `/health` 上直接改造。侧边栏不变。
|
||||
|
||||
### 7.2 涉及文件
|
||||
|
||||
| 文件 | 改动类型 | 说明 |
|
||||
|------|---------|------|
|
||||
| `apps/web/src/pages/health/Home.tsx` | **重写** | 从仪表盘布局改为任务队列 + 详情面板 |
|
||||
| `apps/web/src/pages/health/components/TaskQueue.tsx` | **新增** | 任务队列组件 |
|
||||
| `apps/web/src/pages/health/components/TaskDetail.tsx` | **新增** | 详情面板组件 |
|
||||
| `apps/web/src/pages/health/components/PatientBar.tsx` | **新增** | 患者信息栏 |
|
||||
| `apps/web/src/stores/workbenchStore.ts` | **新增** | Zustand store |
|
||||
| `crates/erp-health/src/service/action_inbox_service.rs` | **改造** | 修复排序规则 + 扩展优先级 |
|
||||
| `crates/erp-health/src/handler/device_reading_handler.rs` | **改造** | alert acknowledge 增加处理记录 |
|
||||
|
||||
### 7.3 数据库变更
|
||||
|
||||
Phase 1 **无需新建表**。任务从现有 3 张表聚合:
|
||||
- 体征告警 ← `alerts` 表(未确认的告警)
|
||||
- AI 建议 ← `ai_analysis` 表(状态=pending_review)
|
||||
- 到期随访 ← `follow_up_task` 表(状态=pending + 到期日<=今天)
|
||||
|
||||
聚合逻辑沿用现有 `action_inbox_service.rs` 的 UNION ALL 方案。
|
||||
|
||||
### 7.4 权限
|
||||
|
||||
沿用现有权限码:`health.action-inbox.list` + `health.action-inbox.manage`。
|
||||
|
||||
### 7.5 验收标准
|
||||
|
||||
- [ ] 工作台展示 3 种任务类型(告警、AI 建议、随访),按优先级排序
|
||||
- [ ] 点击任务,右侧详情面板展示完整上下文(患者信息 + 原始数据 + 趋势 + 互动记录)
|
||||
- [ ] 告警任务可确认并记录处理结果
|
||||
- [ ] AI 建议可采纳或拒绝
|
||||
- [ ] 随访任务可完成并填写随访记录
|
||||
- [ ] 任务完成后自动选中下一个
|
||||
- [ ] 空状态有合理展示
|
||||
- [ ] 30 秒自动刷新任务列表
|
||||
- [ ] `cargo check` 通过
|
||||
- [ ] 浏览器中实际操作验证通过
|
||||
@@ -1,8 +1,10 @@
|
||||
# HMS 健康管理平台 — 全项目深度分析与多专家组头脑风暴
|
||||
|
||||
> 日期: 2026-05-03 | 类型: 分析报告 | 数据截止: commit 554 | 状态: 草稿
|
||||
> 日期: 2026-05-03 | 类型: 分析报告 | 数据截止: commit 555 | 状态: 定稿
|
||||
>
|
||||
> **如何使用本文档:** §1-2 是全景扫描,所有人应读。§3-7 是专家组深度分析,按需阅读。§8-10 是行动矩阵和风险传导,执行时参考。每个专家组独立成章,可跳读。
|
||||
|
||||
**TL;DR:** HMS 项目整体健康度 B+。架构边界满分,安全基础扎实,文档体系完善。核心风险:前端测试 <5%、55% 事件孤立、审计整改率 8%、73 个未提交文件。建议立即止血(P0)→ 本周补短板(P1)→ 本月治本(P2)。
|
||||
**TL;DR:** HMS 项目整体健康度 B+。架构边界满分,安全基础扎实,文档体系完善。核心风险:前端测试 <5%、55% 事件孤立、审计整改率 8%、73 个未提交文件(截至文档编写时)。建议立即止血(P0)→ 本周补短板(P1)→ 本月治本(P2)。
|
||||
|
||||
---
|
||||
|
||||
@@ -10,7 +12,7 @@
|
||||
|
||||
### 为什么做这次分析
|
||||
|
||||
HMS 项目经过 3 周密集开发(554 次提交,41 份设计规格),已进入功能基本完整的阶段。2026-04-30 完成的全系统审计发现 25 个问题(2 CRITICAL + 3 HIGH + 8 MEDIUM + 12 LOW),但审计后 3 天整改率仅 8%。此时需要一个全面的「体检」来:
|
||||
HMS 项目经过 3 周密集开发(555 次提交,86 份设计规格),已进入功能基本完整的阶段。2026-04-30 完成的全系统审计发现 25 个问题(2 CRITICAL + 3 HIGH + 8 MEDIUM + 12 LOW),但审计后 3 天整改率仅 8%。此时需要一个全面的「体检」来:
|
||||
|
||||
1. 识别系统性风险而非单点问题
|
||||
2. 从多维度(架构/安全/前端/质量/管理)交叉验证
|
||||
@@ -21,10 +23,10 @@ HMS 项目经过 3 周密集开发(554 次提交,41 份设计规格),已
|
||||
| 维度 | 覆盖范围 |
|
||||
|------|---------|
|
||||
| 后端架构 | 17 Rust crates / ~87k 行 / 484 源文件 |
|
||||
| 前端 Web | 199 文件(113 TSX + 86 TS) |
|
||||
| 微信小程序 | 113 文件 / 40 页面 / 5 TabBar |
|
||||
| 数据库 | 103 迁移 / 77+ 表 |
|
||||
| 文档体系 | 12 页 wiki + 41 specs + 38 plans + 18 discussions |
|
||||
| 前端 Web | 151 文件(113 TSX + 38 TS) |
|
||||
| 微信小程序 | 113 文件 / 38 页面 / 5 TabBar |
|
||||
| 数据库 | 104 迁移 / 77+ 表 |
|
||||
| 文档体系 | 12 页 wiki + 86 specs + 41 plans + 12 discussions |
|
||||
|
||||
### 方法论
|
||||
|
||||
@@ -42,14 +44,14 @@ HMS 项目经过 3 周密集开发(554 次提交,41 份设计规格),已
|
||||
| 维度 | 数据 | 评估 |
|
||||
|------|------|------|
|
||||
| Rust 代码 | ~87k 行 / 17 crates / 484 源文件 | 中大型单体,模块边界清晰 |
|
||||
| Web 前端 | 199 文件 (113 TSX + 86 TS) | 中等规模,API 层完整 |
|
||||
| 微信小程序 | 113 文件 / 40 页面 / 5 TabBar | 功能丰富,分包合理 |
|
||||
| 数据库 | 103 迁移 / 77+ 表 | 高频 schema 迭代 |
|
||||
| Web 前端 | 151 文件 (113 TSX + 38 TS) | 中等规模,API 层完整 |
|
||||
| 微信小程序 | 113 文件 / 38 页面 / 5 TabBar | 功能丰富,分包合理 |
|
||||
| 数据库 | 104 迁移 / 77+ 表 | 高频 schema 迭代 |
|
||||
| API 路由 | 328 (8 公开 + 320 受保护) | 全面的业务覆盖 |
|
||||
| 测试 | 772 后端 + 11 前端 | 后端尚可,前端极低 |
|
||||
| 事件系统 | 25 类型 / 44 发布 / 14 消费者 | 设计精良但有孤立事件 |
|
||||
| 设计文档 | 41 specs / 38 plans | 文档驱动,管理有序 |
|
||||
| Git 历史 | 554 次提交 | AI 辅助密集开发 |
|
||||
| 设计文档 | 86 specs / 41 plans | 文档驱动,管理有序 |
|
||||
| Git 历史 | 555 次提交 | AI 辅助密集开发 |
|
||||
|
||||
### 2.2 架构评分矩阵
|
||||
|
||||
@@ -62,7 +64,7 @@ HMS 项目经过 3 周密集开发(554 次提交,41 份设计规格),已
|
||||
| 前端架构 | ⭐⭐⭐⭐☆ | API/Store/Hook 三层分离,但零 i18n、低测试覆盖 |
|
||||
| 代码质量 | ⭐⭐⭐⭐☆ | 4 个 TODO、无 FIXME/HACK,但存在 6 个千行文件 |
|
||||
| 测试覆盖 | ⭐⭐⭐☆☆ | 后端 772 测试尚可,前端 <5%、小程序 0% |
|
||||
| 文档完整性 | ⭐⭐⭐⭐☆ | 12 页 wiki + 41 specs,但 wiki 数据存在不一致 |
|
||||
| 文档完整性 | ⭐⭐⭐⭐☆ | 12 页 wiki + 86 specs,但 wiki 数据存在不一致 |
|
||||
| 运维成熟度 | ⭐⭐⭐☆☆ | Docker + 原生双轨但不同步,单分支开发,大量未提交文件 |
|
||||
|
||||
---
|
||||
@@ -108,6 +110,8 @@ HMS 项目经过 3 周密集开发(554 次提交,41 份设计规格),已
|
||||
|
||||
**优先级:** P1 — 事件是模块间通信的核心,孤立事件 = 功能缺失
|
||||
|
||||
> **交叉引用:** 安全组(§4.1)指出孤立事件会导致合规声明与实际行为不一致;质量组(§6.1)指出 event.rs 本身也是千行文件,重构时需要测试保障。
|
||||
|
||||
## 4. 专家组 2:安全与合规
|
||||
|
||||
**成员画像:** 安全工程师 + 医疗合规专家 + 隐私保护专家
|
||||
@@ -133,6 +137,8 @@ HMS 项目经过 3 周密集开发(554 次提交,41 份设计规格),已
|
||||
3. **P1 — AI 密钥统一:** 与 JWT 密钥一样使用 `__MUST_SET_VIA_ENV__` 占位符模式
|
||||
4. **P2 — 审计日志写入:** fire-and-forget 模式可能导致静默丢失,改为带重试队列
|
||||
|
||||
> **交叉引用:** 质量组(§6.3)指出 `unwrap()` 调用中 PluginHost::db panic 是同一类问题 — 关键路径缺乏容错。
|
||||
|
||||
### 4.2 医疗数据合规性
|
||||
|
||||
**已有能力:**
|
||||
@@ -171,7 +177,9 @@ HMS 项目经过 3 周密集开发(554 次提交,41 份设计规格),已
|
||||
- Web:13 个 Playwright spec(患者旅程、预约、随访、体征、告警等核心流程)
|
||||
- 小程序:4 个 automator spec(商城、健康查看、积分、体征录入)
|
||||
|
||||
**核心判断:** 前端测试覆盖率 <5% 是项目最大的质量风险。后端有 772 个测试保障,但前端 163 个文件几乎裸跑。E2E 测试慢且脆弱,不能替代单元测试 — 任何重构都可能引入不可检测的回归。
|
||||
**核心判断:** 前端测试覆盖率 <5% 是项目最大的质量风险。后端有 772 个测试保障,但前端 151 个文件几乎裸跑。E2E 测试慢且脆弱,不能替代单元测试 — 任何重构都可能引入不可检测的回归。
|
||||
|
||||
> **交叉引用:** 4 个专家组独立得出「前端测试是最大短板」的结论 — 架构组(§3)、质量组(§6)、管理组(§7) 均标记。风险传导链(§10)说明低测试覆盖放大了所有其他重构风险。
|
||||
|
||||
**建议:**
|
||||
1. **P1 — Store 测试:** 6 个 Zustand Store 是状态管理核心,每个至少 10 个测试
|
||||
@@ -235,6 +243,8 @@ HMS 项目经过 3 周密集开发(554 次提交,41 份设计规格),已
|
||||
|
||||
**优先级:** P2 — 在下一次大改动时顺带重构
|
||||
|
||||
> **交叉引用:** 前端组(§5.3)独立发现 Web 侧同样存在 5 个 500+ 行大组件。架构组(§3.1)指出 module.rs 路由注册瓶颈。后端 + 前端共 11 个大文件需要拆分,是跨维度共识。
|
||||
|
||||
### 6.2 前端错误处理统一化
|
||||
|
||||
**重复模式(18+ 文件):**
|
||||
@@ -251,7 +261,9 @@ HMS 项目经过 3 周密集开发(554 次提交,41 份设计规格),已
|
||||
2. 批量替换 18 个文件中的内联模式
|
||||
3. 建立 ESLint 规则禁止该模式
|
||||
|
||||
**优先级:** P2
|
||||
**优先级:** P2 — 依赖 P1 Store 测试完成后再批量重构,避免无安全网的大规模替换
|
||||
|
||||
> **交叉引用:** 前端组(§5.1)指出前端测试 <5%,意味着这个 18 文件重构在没有测试保障下执行 = 高风险。应先完成 #7 Store 测试。
|
||||
|
||||
### 6.3 TypeScript 类型安全
|
||||
|
||||
@@ -296,6 +308,8 @@ HMS 项目经过 3 周密集开发(554 次提交,41 份设计规格),已
|
||||
|
||||
**建议:** 立即执行分类提交 — 按功能 / 文档 / 配置分组,并清理临时文件。
|
||||
|
||||
> **交叉引用:** 架构组(§3.1)指出 wiki 文档未提交,质量组(§6.3)指出过时注释未更新 — 三组数据均指向「闭环工作法未执行」的系统性问题。风险传导链(§10.2)说明未提交文件是人员单点故障的放大器。
|
||||
|
||||
### 7.2 审计整改进度
|
||||
|
||||
**整改率:** 25 个审计发现中仅 1-2 个已处理(~8%,3 天后)
|
||||
@@ -336,53 +350,121 @@ HMS 项目经过 3 周密集开发(554 次提交,41 份设计规格),已
|
||||
|
||||
**建议:** 安排 wiki 刷新会话,逐一校对数据。优先级 P2。
|
||||
|
||||
> **交叉引用:** 本文档自身的数据已用代码库实际值校正(见 §1 头部注释)。但 wiki 中仍有 7 处不一致未修。架构组(§3.2)和本组均发现此问题 — 3 组独立验证,可信度高。
|
||||
|
||||
## 8. 优先级行动矩阵
|
||||
|
||||
### 🔴 P0 — 立即处理(今天)
|
||||
|
||||
| # | 行动 | 工作量 | 影响 |
|
||||
|---|------|--------|------|
|
||||
| 1 | 提交并推送 73 个未提交文件 | 30 min | 防止工作丢失 |
|
||||
| 2 | 修复 C2 告警权限码拼写 | 5 min | 消除最后一个 CRITICAL |
|
||||
| 3 | 确认 C1 晚间血压修复并更新 wiki | 15 min | 关闭审计 CRITICAL |
|
||||
| # | 行动 | 工作量 | 完成标准 | 阻塞 |
|
||||
|---|------|--------|---------|------|
|
||||
| 1 | 提交并推送 73 个未提交文件 | 30 min | `git status` 干净 + `git push` 成功 | 所有后续工作 |
|
||||
| 2 | 修复 C2 告警权限码拼写 | 5 min | AlertList 页面按钮正常显示 + 无 403 | — |
|
||||
| 3 | 确认 C1 晚间血压修复并更新 wiki | 15 min | 小程序录入晚间血压 → 数据库有记录 + wiki 症状导航已更新 | — |
|
||||
|
||||
### 🟠 P1 — 本周内
|
||||
|
||||
| # | 行动 | 工作量 | 影响 |
|
||||
|---|------|--------|------|
|
||||
| 4 | 生产限流 fail-close 配置 | 1h | 生产安全 |
|
||||
| 5 | 补全 erp-health/event.rs 测试 | 4h | 事件系统可靠性 |
|
||||
| 6 | 孤立事件清理(14 个) | 8h | 消除功能断裂风险 |
|
||||
| 7 | 前端 Store 单元测试(6 个 store) | 8h | 前端回归安全网 |
|
||||
| 8 | 小程序透析模块(审计 HIGH H1) | 16h | 医疗完整性 |
|
||||
| 9 | 小程序知情同意模块(审计 HIGH H2) | 8h | 合规底线 |
|
||||
| 10 | health_data_service / action_inbox 补充 tracing | 4h | 可观测性 |
|
||||
| # | 行动 | 工作量 | 完成 standard | 依赖 |
|
||||
|---|------|--------|-------------|------|
|
||||
| 4 | 生产限流 fail-close 配置 | 1h | `config/production.toml` 含 `fail_close = true` + 集成测试验证 | #1 |
|
||||
| 5 | 补全 erp-health/event.rs 测试 | 4h | 每个消费者至少 1 个正向 + 1 个异常测试 | — |
|
||||
| 6 | 孤立事件清理(14 个) | 8h | 每个事件有消费者或已删除,孤立率 <10% | #5 |
|
||||
| 7 | 前端 Store 单元测试(6 个 store) | 8h | 每个 store ≥10 测试,覆盖核心 action 和 selector | #1 |
|
||||
| 8 | 小程序透析模块(审计 HIGH H1) | 16h | 透析记录查看/新增/编辑页面可用 + 4 个 automator spec | #1 |
|
||||
| 9 | 小程序知情同意模块(审计 HIGH H2) | 8h | 知情同意签署页面 + 签署后事件正常发布 | #1 |
|
||||
| 10 | health_data_service / action_inbox 补充 tracing | 4h | 两个文件的关键路径均有 `tracing::info/error` | — |
|
||||
|
||||
### 🟡 P2 — 本月内
|
||||
|
||||
| # | 行动 | 工作量 | 影响 |
|
||||
|---|------|--------|------|
|
||||
| 11 | 前端错误处理统一化(18 个文件) | 4h | 代码一致性 |
|
||||
| 12 | 大文件拆分(后端 6 个千行文件) | 16h | 可维护性 |
|
||||
| 13 | 前端 API 契约测试 | 8h | 集成可靠性 |
|
||||
| 14 | Wiki 数据一致性刷新 | 4h | 文档可信度 |
|
||||
| 15 | 数据库迁移治理策略 | 8h | 运维安全 |
|
||||
| 16 | unwrap() 调用替换(2 处) | 2h | 生产稳定性 |
|
||||
| # | 行动 | 工作量 | 完成 standard | 依赖 |
|
||||
|---|------|--------|-------------|------|
|
||||
| 11 | 前端错误处理统一化(18 个文件) | 4h | 0 处内联错误提取,全部用 `handleApiError` | #7 |
|
||||
| 12 | 大文件拆分(后端 6 个千行文件) | 16h | 无 >1000 行的 service 文件 | — |
|
||||
| 13 | 前端 API 契约测试 | 8h | 每个 API 模块 ≥3 测试(URL/Method/参数) | #7 |
|
||||
| 14 | Wiki 数据一致性刷新 | 4h | wiki 中所有计数与代码库一致 | — |
|
||||
| 15 | 数据库迁移治理策略 | 8h | 新迁移 <500 行 + 有 dry-run 脚本 | — |
|
||||
| 16 | unwrap() 调用替换(2 处) | 2h | `grep -r "unwrap()" service/` 返回 0 结果 | — |
|
||||
|
||||
### 🟢 P3 — 季度规划
|
||||
|
||||
| # | 行动 | 工作量 | 影响 |
|
||||
|---|------|--------|------|
|
||||
| 17 | 编译器警告清理(40 个) | 8h | 代码清洁度 |
|
||||
| 18 | 前端大组件拆分(20 个文件) | 16h | 可维护性 |
|
||||
| 19 | TypeScript any 消除 | 8h | 类型安全 |
|
||||
| 20 | 小程序测试基础设施 | 16h | 小程序质量保障 |
|
||||
| 21 | Docker 配置与文档对齐 | 4h | 部署一致性 |
|
||||
| 22 | 数据保留策略设计 | 16h | 合规准备 |
|
||||
| # | 行动 | 工作量 | 完成 standard | 依赖 |
|
||||
|---|------|--------|-------------|------|
|
||||
| 17 | 编译器警告清理(40 个) | 8h | `cargo check 2>&1 | grep warning` 返回 0 | — |
|
||||
| 18 | 前端大组件拆分(20 个文件) | 16h | 无 >500 行的 TSX 文件 | #12 |
|
||||
| 19 | TypeScript any 消除 | 8h | `grep -r ": any"` Web 返回 0 / 小程序 <5 | — |
|
||||
| 20 | 小程序测试基础设施 | 16h | BLE + secure-storage + 核心页面单元测试 | #8 |
|
||||
| 21 | Docker 配置与文档对齐 | 4h | compose 版本号 = wiki 声明 | #14 |
|
||||
| 22 | 数据保留策略设计 | 16h | 设计规格文档 + 至少 1 个实体的自动化过期 | — |
|
||||
|
||||
---
|
||||
|
||||
## 9. 总结与建议
|
||||
## 9. 交叉验证:多组共识与分歧
|
||||
|
||||
> 5 个专家组独立分析同一代码库。本节记录各组发现的交叉印证和矛盾,增强结论可信度。
|
||||
|
||||
### 9.1 多组共识(≥3 组独立发现同一问题)
|
||||
|
||||
| 共识问题 | 涉及专家组 | 核心引用 |
|
||||
|----------|-----------|---------|
|
||||
| **前端测试空白是最大风险** | 架构(§3) + 前端(§5.1) + 质量(§6) + 管理(§7) | 前端 151 文件仅 11 测试(<5%),4 组独立得出"不可接受"结论 |
|
||||
| **大文件/大组件是可维护性瓶颈** | 架构(§3.1) + 前端(§5.3) + 质量(§6.1) | 后端 6 个千行文件 + 前端 5 个 500+ 行组件,3 组独立标记 |
|
||||
| **Wiki 数据过时** | 架构(§3.2) + 质量(§6.3) + 管理(§7.3) | 迁移数/权限码/entity 计数多处不一致,3 组各自发现不同不一致 |
|
||||
| **审计整改执行纪律缺失** | 管理(§7.2) + 安全(§4.1) + 质量(§6) | C2 五分钟改动 3 天未修,限流 fail-open 未配置,说明流程断裂 |
|
||||
|
||||
### 9.2 组间互补(A 组发现问题,B 组补充影响)
|
||||
|
||||
| 问题 | A 组发现 | B 组补充 |
|
||||
|------|---------|---------|
|
||||
| 孤立事件 | 架构组(§3.3): 55% 孤立率 | 安全组(§4.1): 事件无消费者 = 功能声明与实际不一致,合规审计时被发现 |
|
||||
| 限流 fail-open | 安全组(§4.1): Redis 宕机无限流 | 架构组(§3.1): 单体架构下 Redis 是 SPOF,影响全局 |
|
||||
| 前端错误处理重复 | 质量组(§6.2): 18 文件重复模式 | 前端组(§5.1): 无测试覆盖 = 重构时无法验证不破坏 |
|
||||
| unwrap() 调用 | 质量组(§6.3): 2 处生产风险 | 安全组(§4.1): PluginHost::db panic = 整个插件子系统不可用 |
|
||||
| 小程序页面空白 | 前端组(§5): 功能缺失 | 安全组(§4.2): 知情同意缺失 = 医疗合规底线问题 |
|
||||
|
||||
### 9.3 无重大分歧
|
||||
|
||||
5 组之间无结论性矛盾 — 所有发现方向一致,差异仅在优先级判断上:
|
||||
- i18n:前端组判 P4,安全组未提及。共识:不阻塞
|
||||
- 编译器警告:质量组判 P3,架构组未提及。共识:可延后
|
||||
|
||||
---
|
||||
|
||||
## 10. 风险传导链
|
||||
|
||||
> 风险不是孤立的。以下展示风险如何通过依赖关系互相放大,解释为什么某些 P0 看似小改动却必须立即处理。
|
||||
|
||||
### 10.1 核心传导路径
|
||||
|
||||
```
|
||||
未提交文件积压 (#1)
|
||||
├─→ 本地故障 = 工作丢失 → 阻塞所有后续工作
|
||||
└─→ 审计整改延迟 → C2 五分钟改动被搁置 3 天
|
||||
|
||||
孤立事件 55% (#6)
|
||||
├─→ 功能声明 ≠ 实际行为 → 用户不可见的业务断裂
|
||||
└─→ 无消费者测试 → 重构 event.rs 时无法验证 (#5)
|
||||
|
||||
前端测试 <5% (#7)
|
||||
├─→ 错误处理统一化 (#11) 无法验证 → 技术债固化
|
||||
├─→ 大组件拆分 (#18) 风险极高 → 不敢重构
|
||||
└─→ API 契约测试 (#13) 无回归安全网 → 新功能也可能破坏旧功能
|
||||
|
||||
限流 fail-open (#4)
|
||||
└─→ Redis 宕机 → 无限流 → 恶意请求打垮服务 → 影响所有用户
|
||||
```
|
||||
|
||||
### 10.2 风险放大效应
|
||||
|
||||
| 放大器 | 被放大的风险 | 机制 |
|
||||
|--------|------------|------|
|
||||
| 低测试覆盖 | 重构风险 | 任何代码变更都无法验证不引入回归 |
|
||||
| 孤立事件 | 功能验证盲区 | 发布的事件无消费者 = 变更的影响无法观测 |
|
||||
| 未提交文件 | 人员单点故障 | 唯一开发者本地故障 = 全部工作丢失 |
|
||||
| Wiki 过时 | 决策误导 | 基于过时 wiki 的新决策可能建立在错误前提上 |
|
||||
|
||||
---
|
||||
|
||||
## 11. 总结与建议
|
||||
|
||||
### 整体评分:B+(良好,有明确的提升空间)
|
||||
|
||||
@@ -390,7 +472,7 @@ HMS 项目经过 3 周密集开发(554 次提交,41 份设计规格),已
|
||||
|
||||
1. **架构设计出色** — 分层清晰、模块边界严格、事件驱动解耦、零循环依赖
|
||||
2. **安全基础扎实** — Argon2 + AES-256-GCM + PostgreSQL RLS + 审计哈希链
|
||||
3. **文档驱动开发** — 41 份设计规格、18 份讨论记录、12 页 wiki,决策有据可查
|
||||
3. **文档驱动开发** — 86 份设计规格、12 份讨论记录、12 页 wiki,决策有据可查
|
||||
4. **API 层完整** — 328 路由覆盖所有业务,前端 API 层与后端 1:1 对应
|
||||
5. **前端架构清晰** — API / Store / Hook 三层分离,无 god store、无硬编码数据、无 console.log 残留
|
||||
|
||||
@@ -398,10 +480,26 @@ HMS 项目经过 3 周密集开发(554 次提交,41 份设计规格),已
|
||||
|
||||
1. **前端测试空白** — <5% 覆盖率,任何重构都是冒险
|
||||
2. **审计整改缓慢** — 3 天仅处理 8% 的审计发现,CRITICAL C2(5 分钟改动)仍未修复
|
||||
3. **工作积压** — 55+ 文件未提交,违反闭环工作法
|
||||
3. **工作积压** — 73 个文件未提交,违反闭环工作法
|
||||
4. **孤立事件** — 55% 的事件无消费者,可能是功能断裂的信号
|
||||
5. **可观测性不足** — 多个核心 service 文件仍缺 tracing 日志(patient_service 已补全)
|
||||
|
||||
### 成功度量
|
||||
|
||||
每个优先级阶段的验收标准:
|
||||
|
||||
| 阶段 | 时间窗口 | 核心指标 | 目标 |
|
||||
|------|---------|---------|------|
|
||||
| P0 止血 | 今天 | CRITICAL 项关闭率 | 100%(2/2) |
|
||||
| P0 止血 | 今天 | 未提交文件数 | 0 |
|
||||
| P1 补短板 | 本周 | 审计 HIGH 关闭率 | ≥66%(2/3) |
|
||||
| P1 补短板 | 本周 | 前端 Store 测试数 | ≥60 |
|
||||
| P1 补短板 | 本周 | 事件孤立率 | <10% |
|
||||
| P2 治本 | 本月 | 千行 service 文件 | 0 |
|
||||
| P2 治本 | 本月 | Wiki 数据准确率 | 100% |
|
||||
| P3 持续 | 季度 | 前端测试覆盖率 | >30% |
|
||||
| P3 持续 | 季度 | 编译器警告数 | 0 |
|
||||
|
||||
### 下一步方向
|
||||
|
||||
当前阶段应遵循 **「止血 → 补短板 → 治本」** 路径:
|
||||
|
||||
Reference in New Issue
Block a user