Files
hms/docs/superpowers/specs/2026-04-25-feature-completion-design.md
iven 46089adbc6
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled
docs(spec): 审查修正功能完善设计规格
修正审查发现的 CRITICAL/HIGH 问题:
- 后端 AI 端点空壳:标注需实现,新增 P0a-P0d 后端阶段
- 用户权限数据源缺失:新增 /auth/me/permissions 端点依赖
- 权限码映射修正:积分页面使用 health.points.*
- 组件路径修正:packages/ui-components → apps/web/src/components/
- 小程序路径调整:使用独立 ai-report/ 目录
- 菜单结构修正:扁平结构而非子菜单
- 补充版本回滚机制、安全降级、i18n 前缀约定
2026-04-25 20:30:22 +08:00

12 KiB
Raw Blame History

HMS 功能完善迭代设计规格

日期: 2026-04-25 状态: 已确认(审查修正版) 关联: docs/superpowers/specs/2026-04-25-erp-ai-module-design.md

1. 背景与目标

1.1 项目现状

HMS 健康管理平台已完成核心业务开发237 次提交、57k 行 Rust + 174 前端文件),但存在以下功能缺口:

  • 按钮级权限控制缺失 — 路由守卫已有,但操作按钮(新增/编辑/删除)未做权限过滤;前端缺少权限数据源(UserInfo 接口不含 permissions 字段)
  • AI 模块管理端空白 — 后端 6 个 API 端点中 4 个 SSE 流式端点可用,但 Prompt CRUD、分析历史查询、用量统计端点均为空壳或缺失
  • 小程序端 AI 不可见 — 患者无法查看 AI 分析报告

1.2 目标

通过纵向切片方式逐步交付三个功能域,每个切片从前到后完整打通:

  1. 切片 1按钮级权限 — 基础设施,后续页面的前置依赖
  2. 切片 2AI 管理端 — 3 个 PC 管理页面
  3. 切片 3小程序报告 — 患者端只读查看

2. 切片 1按钮级权限控制

2.1 架构

后端新增 /api/v1/auth/me/permissions → 返回当前用户权限码列表
    ↓
auth store (permissions: string[]) ← 登录时从新端点加载
    ↓
usePermission(code) → { hasPermission: boolean }
    ↓
<AuthButton code="health.patient.manage"> ... </AuthButton>
    ↓
无权限 → 不渲染hidden 模式)
有权限 → 正常渲染子元素

前置依赖: 当前 UserInfo 接口不含 permissions 字段(仅含 roles)。需后端新增 /api/v1/auth/me/permissions 端点,返回当前用户所有权限码的扁平列表(从角色 → 权限关联表聚合)。超级管理员(is_system: true)默认返回全部权限码。

2.2 组件设计

usePermission hook

位置: apps/web/src/hooks/usePermission.ts

function usePermission(code: string): { hasPermission: boolean }
  • 从 auth store 读取当前用户 permissions 数组
  • 返回 code 是否在权限列表中
  • 权限数据加载失败时默认无权限(安全降级)

AuthButton 组件

位置: apps/web/src/components/AuthButton.tsx

Props:

  • code: string — 权限码(如 health.patient.manage
  • children: ReactNode — 受保护的按钮内容

行为: 无权限时不渲染 childrenhidden 模式)。

AuthGuard 组件

位置: apps/web/src/components/AuthGuard.tsx

Props:

  • code: string — 权限码
  • children: ReactNode — 受保护的内容块

行为: 同 AuthButton用于包裹非按钮内容如整个 Tab、区块

2.3 改造范围

优先改造健康模块 15 个页面中的操作按钮:

页面 按钮权限码
PatientList health.patient.manage
PatientDetail health.patient.manage
AppointmentList health.appointment.manage
DoctorList health.doctor.manage
DoctorSchedule health.doctor.manage
FollowUpTaskList health.follow-up.manage
FollowUpRecordList health.follow-up.manage
ConsultationList health.consultation.manage
ConsultationDetail health.consultation.manage
OfflineEventList health.articles.manage
PatientTagManage health.patient.manage
StatisticsDashboard health.health-data.list (只读)
PointsProductList health.points.manage
PointsOrderList health.points.list
PointsRuleList health.points.manage

扩展到基础模块页面Users, Roles, Organizations, Workflow 等)。

2.4 验证标准

  • 无权限用户看不到操作按钮
  • 有权限用户操作正常
  • 权限变更后界面实时更新(无需刷新)

3. 切片 2AI 管理端 3 页面

3.1 路由设计

/health/ai/prompts     → Prompt 管理
/health/ai/analysis    → 分析历史
/health/ai/usage       → 用量统计

3.2 页面 A — Prompt 管理

位置: apps/web/src/pages/health/AiPromptList.tsx

功能清单:

功能 说明
列表展示 表格:名称/类型(化验单解读、趋势分析、体检方案、报告摘要)/版本号/状态active/draft/更新时间
新建 Prompt Modal 表单:名称、类型(下拉)、系统提示词、用户提示词模板(支持 {{variable}} 占位符)
编辑 Prompt 同新建,自动递增版本号
激活/停用 切换按钮,激活时停用同类型旧模板
版本历史 展开行显示所有历史版本,支持一键回滚

API 封装:

位置: apps/web/src/api/ai/prompts.ts

// 后端需新增 Prompt CRUD 端点(当前仅有 service 层的 get_active_prompt + create_prompt
getPrompts(params: ListParams): Promise<PaginatedResponse<Prompt>>        // GET /api/v1/ai/prompts
createPrompt(data: CreatePromptDto): Promise<Prompt>                      // POST /api/v1/ai/prompts
updatePrompt(id: string, data: UpdatePromptDto): Promise<Prompt>          // PUT /api/v1/ai/prompts/{id}
activatePrompt(id: string): Promise<Prompt>                               // POST /api/v1/ai/prompts/{id}/activate
rollbackPrompt(id: string): Promise<Prompt>                               // POST /api/v1/ai/prompts/{id}/rollback

版本回滚机制: 每次编辑 Prompt 创建新记录(递增 version回滚 = 将目标旧版本 is_active 设为 true 并将当前激活版本 is_active 设为 false。不删除任何版本记录。

权限码: ai.prompt.list(查看)、ai.prompt.manage(编辑/激活/回滚)

3.3 页面 B — 分析历史

位置: apps/web/src/pages/health/AiAnalysisList.tsx

功能清单:

功能 说明
列表展示 表格:分析类型/患者姓名/状态streaming/completed/failed/创建时间/token 用量
详情查看 点击行展开/Modal 展示完整分析结果Markdown 渲染)
筛选 按类型4 种、时间范围DateRangePicker、患者PatientSelect 组件复用)
重新分析 对 failed 记录支持重新发起分析

API 封装:

位置: apps/web/src/api/ai/analysis.ts

// 后端当前 list_analysis/get_analysis 为空壳(返回 ApiResponse::ok(())),需实现真实查询
getAnalysisHistory(params: AnalysisQueryParams): Promise<PaginatedResponse<Analysis>>  // GET /api/v1/ai/analysis/history
getAnalysisDetail(id: string): Promise<Analysis>                                       // GET /api/v1/ai/analysis/{id}

权限码: ai.analysis.list(查看)、ai.analysis.manage(重新分析)

3.4 页面 C — 用量统计

位置: apps/web/src/pages/health/AiUsageDashboard.tsx

功能清单:

功能 说明
概览卡片 4 张 StatCard总用量/本月/今日/平均 token
趋势图 Ant Design Charts 折线图,按日/周/月切换
类型分布 饼图展示 4 种分析类型的占比
用户排行 表格展示用户维度用量排名

API 封装:

位置: apps/web/src/api/ai/usage.ts

// 后端需完全新增路由、handler、聚合 service
// ai_usage_logs 表需增加 created_by 列(当前缺失 user_id或复用 ai_analysis_results.created_by 做用户排行
getUsageOverview(): Promise<UsageOverview>                                    // GET /api/v1/ai/usage/overview
getUsageTrend(params: TrendParams): Promise<TrendData[]>                     // GET /api/v1/ai/usage/trend
getUsageByType(): Promise<TypeDistribution[]>                                // GET /api/v1/ai/usage/by-type
getUsageByUser(params: UserRankingParams): Promise<PaginatedResponse<UserUsage>>  // GET /api/v1/ai/usage/by-user

后端补充: 需在 erp-ai 中新增用量统计聚合端点。优先方案:复用 ai_analysis_results 表的 created_by 字段做用户维度排行,避免修改 ai_usage_logs 表结构。如需精确 token 统计,后续可加迁移增加 user_id 列。

权限码: ai.usage.list

3.5 菜单注册

apps/web/src/layouts/MainLayout.tsx 健康管理菜单组下新增 AI 分析入口。当前菜单为扁平结构(无子菜单折叠),新增项直接追加为同级菜单项:

健康管理
├── 患者管理
├── 医护管理
├── 预约管理
├── 随访管理
├── 咨询管理
├── 积分商城
├── 统计看板
├── AI Prompt 管理   ← 新增(扁平)
├── AI 分析历史      ← 新增(扁平)
└── AI 用量统计      ← 新增(扁平)

3.6 验证标准

  • Prompt CRUD 全流程可用(创建/编辑/激活/回滚)
  • 分析历史可筛选、可查看详情Markdown 正确渲染)
  • 用量统计图表数据正确
  • 所有操作按钮受 AuthButton 权限控制
  • 页面响应式布局正常

4. 切片 3小程序 AI 报告查看

4.1 新增页面

AI 报告列表页

位置: apps/miniprogram/src/pages/ai-report/list/index.tsx

  • 调用 GET /api/v1/ai/analysis/history (后端需实现,根据 JWT user_id → patient_id 自动过滤)
  • 列表展示分析记录(类型图标 + 时间 + 状态标签)
  • 点击进入详情

AI 报告详情页

位置: apps/miniprogram/src/pages/ai-report/detail/index.tsx

  • 调用 GET /api/v1/ai/analysis/{id}
  • 使用 taro-markdown 组件渲染 Markdown 格式的分析结果(需先验证兼容性)
  • 底部展示分析时间和 token 用量信息

4.2 路由集成

在首页(pages/index/index.tsx)健康数据区域增加"AI 报告"入口卡片。

4.3 后端依赖

后端 list_analysisget_analysis 当前为空壳(仅验证权限后返回空值),需实现:

  • 根据 JWT 中的 user_id 查找关联 patient_id
  • ai_analysis_results 表查询该患者的分析记录
  • 返回不含 PII 的脱敏结果

4.4 验证标准

  • 患者可查看自己的 AI 分析历史
  • 详情页 Markdown 正确渲染
  • 无法查看其他患者的报告
  • 无报告时显示空状态提示

5. 实施顺序

阶段 内容 依赖 预计工作量
P0a 后端:新增 /api/v1/auth/me/permissions 端点 erp-auth handler + service
P0b 后端:实现 Prompt CRUD 端点list/create/update/activate/rollback erp-ai handler + service
P0c 后端实现分析历史查询list_analysis/get_analysis 从空壳到真实查询) erp-ai handler + service
P0d 后端新增用量统计聚合端点overview/trend/by-type/by-user erp-ai handler + service + 可能迁移
P1 前端usePermission hook + AuthButton/AuthGuard 组件 + auth store 加载 permissions P0a 3 文件
P2 前端:健康模块页面按钮权限改造 P1 15 文件
P3 前端AI API 封装3 个 service 文件) P0b-d 3 文件
P4 前端AI Prompt 管理页面 P1, P3 1 文件
P5 前端AI 分析历史页面 P1, P3 1 文件
P6 前端AI 用量统计页面 P1, P3 1 文件
P7 前端:菜单注册 + 路由配置 P4-P6 2 文件
P8 小程序:验证 taro-markdown 兼容性 + AI 报告列表/详情页 P0c 3 文件
P9 小程序:首页入口集成 P8 1 文件

6. 非目标(明确排除)

  • 不涉及 CI/CD 流水线建设(属于安全与稳定性方向)
  • 不涉及 erp-plugin unwrap 修复(属于代码质量方向)
  • 不涉及 TypeScript strict 模式开启(属于质量方向,单独处理)
  • 不涉及新的 AI 提供商接入(仅使用现有 Claude 提供商)
  • 不涉及用量配额/计费功能(后续迭代)

7. 技术约束

  • 前端组件使用 Ant Design 6 现有组件
  • 图表使用 Ant Design Charts项目已有依赖
  • 小程序 Markdown 渲染使用 taro-markdown 组件P8 开始前验证兼容性)
  • 后端新增端点遵循现有 handler/service/entity 模式
  • 所有新页面使用 i18n key前缀约定health.ai.*),不硬编码中文
  • 权限数据加载失败时默认无权限(安全降级,宁可少显示按钮也不暴露越权操作)