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

314 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`
```typescript
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`
```typescript
// 后端需新增 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`
```typescript
// 后端当前 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`
```typescript
// 后端需完全新增路由、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_analysis``get_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.*`),不硬编码中文
- 权限数据加载失败时默认无权限(安全降级,宁可少显示按钮也不暴露越权操作)