15 KiB
行动收件箱与上下文线程设计规格
日期: 2026-05-01 | 状态: Draft | 关联:
erp-health,erp-ai, Web 前端, 小程序
1. 背景与问题
1.1 问题陈述
HMS 平台功能完善(328 路由、25 事件类型、97.5% 测试通过率),但用户体验存在系统性流程断裂:
- 告警 → 行动断裂:医生看到告警后,无直接路径跳到查看患者→安排随访→记录处置
- 数据录入 → 反馈断裂:患者录入体征后无即时趋势对比和行动建议
- AI 建议 → 执行追踪断裂:审批通过后,后续执行/追踪/结果反馈在 UI 上不可见
根因:前端交互模型是"功能陈列式"的——每个功能是死胡同,没有出口指向下一步。
1.2 设计目标
建立统一的行动收件箱 + 上下文线程机制,让每个"终点"变成"起点":
- 用户登录后第一眼看到待处理事项(按优先级排列)
- 每个待办有清晰的时间线展示完整生命周期
- 时间线每一步都可直接跳转到对应功能页
- 操作按钮根据当前状态动态变化
- 架构可扩展——新增行动类型(告警/随访/异常)只需注册聚合器
1.3 范围
Phase 1(本次):AI 建议闭环 — 后端已完整实现(10 次提交),补齐前端体验 Future:告警处理闭环、体征反馈闭环、随访到期提醒
2. 设计概览
事件源 → 行动收件箱服务 → 前端展示
├── Web: 顶栏铃铛 → 列表页 → Drawer
└── 小程序: "待办" Tab → 列表 → 半屏弹窗
核心抽象:ActionItem — 统一的待办数据结构,不同类型共用相同接口
核心交互:Context Thread — Drawer/半屏弹窗中的时间线,展示完整处理进度
3. 数据模型
3.1 ActionItem(聚合视图,不建新表)
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(上下文线程事件)
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(可用操作)
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 表:
-- 注意: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:
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
// 复用现有 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 后端验证
# 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 验证
- 登录 → 顶栏铃铛应显示待办数量
- 点击铃铛 → Popover 显示最近待办
- "查看全部" → 进入 ActionInboxPage
- 点击待办项 → Drawer 打开,时间线正确
- 点击"批准" → 状态变更,时间线更新
- SSE 推送 → Drawer 实时更新
9.3 小程序验证
- 底部 TabBar 显示"待办"Tab + 角标
- 进入待办页 → 列表正确
- 点击卡片 → 半屏弹窗弹出
- 操作后 → 状态更新,列表刷新
10. 未来扩展
新增行动类型只需:
- 在
ActionInboxService中注册新的聚合查询器 - 定义
type → ActionItem的映射规则 - 定义线程步骤模板
- 前端自动渲染(共用相同组件)
规划中的扩展类型:
alert— 告警处理闭环(告警→评估→处置→追踪)followup— 随访到期提醒(到期→执行→记录→再分析)data_anomaly— 体征异常反馈(异常→趋势对比→建议→操作)