From 46089adbc6b17fee5062e224562e0f75fce3cb81 Mon Sep 17 00:00:00 2001 From: iven Date: Sat, 25 Apr 2026 20:30:22 +0800 Subject: [PATCH] =?UTF-8?q?docs(spec):=20=E5=AE=A1=E6=9F=A5=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=E5=8A=9F=E8=83=BD=E5=AE=8C=E5=96=84=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E8=A7=84=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修正审查发现的 CRITICAL/HIGH 问题: - 后端 AI 端点空壳:标注需实现,新增 P0a-P0d 后端阶段 - 用户权限数据源缺失:新增 /auth/me/permissions 端点依赖 - 权限码映射修正:积分页面使用 health.points.* - 组件路径修正:packages/ui-components → apps/web/src/components/ - 小程序路径调整:使用独立 ai-report/ 目录 - 菜单结构修正:扁平结构而非子菜单 - 补充版本回滚机制、安全降级、i18n 前缀约定 --- .../2026-04-25-feature-completion-design.md | 116 ++++++++++-------- 1 file changed, 65 insertions(+), 51 deletions(-) diff --git a/docs/superpowers/specs/2026-04-25-feature-completion-design.md b/docs/superpowers/specs/2026-04-25-feature-completion-design.md index e23d212..a8134f1 100644 --- a/docs/superpowers/specs/2026-04-25-feature-completion-design.md +++ b/docs/superpowers/specs/2026-04-25-feature-completion-design.md @@ -1,7 +1,7 @@ # HMS 功能完善迭代设计规格 > 日期: 2026-04-25 -> 状态: 已确认 +> 状态: 已确认(审查修正版) > 关联: `docs/superpowers/specs/2026-04-25-erp-ai-module-design.md` ## 1. 背景与目标 @@ -10,8 +10,8 @@ HMS 健康管理平台已完成核心业务开发(237 次提交、57k 行 Rust + 174 前端文件),但存在以下功能缺口: -- **按钮级权限控制缺失** — 路由守卫已有,但操作按钮(新增/编辑/删除)未做权限过滤 -- **AI 模块管理端空白** — 后端 6 个 API 端点已实现,但前端无管理页面 +- **按钮级权限控制缺失** — 路由守卫已有,但操作按钮(新增/编辑/删除)未做权限过滤;前端缺少权限数据源(`UserInfo` 接口不含 `permissions` 字段) +- **AI 模块管理端空白** — 后端 6 个 API 端点中 4 个 SSE 流式端点可用,但 Prompt CRUD、分析历史查询、用量统计端点均为空壳或缺失 - **小程序端 AI 不可见** — 患者无法查看 AI 分析报告 ### 1.2 目标 @@ -29,7 +29,9 @@ HMS 健康管理平台已完成核心业务开发(237 次提交、57k 行 Rust ### 2.1 架构 ``` -auth store (permissions: string[]) +后端新增 /api/v1/auth/me/permissions → 返回当前用户权限码列表 + ↓ +auth store (permissions: string[]) ← 登录时从新端点加载 ↓ usePermission(code) → { hasPermission: boolean } ↓ @@ -39,6 +41,8 @@ usePermission(code) → { hasPermission: boolean } 有权限 → 正常渲染子元素 ``` +**前置依赖:** 当前 `UserInfo` 接口不含 `permissions` 字段(仅含 `roles`)。需后端新增 `/api/v1/auth/me/permissions` 端点,返回当前用户所有权限码的扁平列表(从角色 → 权限关联表聚合)。超级管理员(`is_system: true`)默认返回全部权限码。 + ### 2.2 组件设计 **usePermission hook** @@ -51,10 +55,11 @@ function usePermission(code: string): { hasPermission: boolean } - 从 auth store 读取当前用户 permissions 数组 - 返回 code 是否在权限列表中 +- 权限数据加载失败时默认无权限(安全降级) **AuthButton 组件** -位置: `packages/ui-components/src/AuthButton.tsx` +位置: `apps/web/src/components/AuthButton.tsx` Props: - `code: string` — 权限码(如 `health.patient.manage`) @@ -64,7 +69,7 @@ Props: **AuthGuard 组件** -位置: `packages/ui-components/src/AuthGuard.tsx` +位置: `apps/web/src/components/AuthGuard.tsx` Props: - `code: string` — 权限码 @@ -90,9 +95,9 @@ Props: | OfflineEventList | health.articles.manage | | PatientTagManage | health.patient.manage | | StatisticsDashboard | health.health-data.list (只读) | -| PointsProductList | health.articles.manage | -| PointsOrderList | health.articles.list | -| PointsRuleList | health.articles.manage | +| PointsProductList | health.points.manage | +| PointsOrderList | health.points.list | +| PointsRuleList | health.points.manage | 扩展到基础模块页面(Users, Roles, Organizations, Workflow 等)。 @@ -133,14 +138,16 @@ Props: 位置: `apps/web/src/api/ai/prompts.ts` ```typescript -// 对应后端已有的 ai_prompt 实体 CRUD -getPrompts(params: ListParams): Promise> -createPrompt(data: CreatePromptDto): Promise -updatePrompt(id: string, data: UpdatePromptDto): Promise -activatePrompt(id: string): Promise -rollbackPrompt(id: string): Promise +// 后端需新增 Prompt CRUD 端点(当前仅有 service 层的 get_active_prompt + create_prompt) +getPrompts(params: ListParams): Promise> // GET /api/v1/ai/prompts +createPrompt(data: CreatePromptDto): Promise // POST /api/v1/ai/prompts +updatePrompt(id: string, data: UpdatePromptDto): Promise // PUT /api/v1/ai/prompts/{id} +activatePrompt(id: string): Promise // POST /api/v1/ai/prompts/{id}/activate +rollbackPrompt(id: string): Promise // POST /api/v1/ai/prompts/{id}/rollback ``` +**版本回滚机制:** 每次编辑 Prompt 创建新记录(递增 version),回滚 = 将目标旧版本 `is_active` 设为 `true` 并将当前激活版本 `is_active` 设为 `false`。不删除任何版本记录。 + **权限码:** `ai.prompt.list`(查看)、`ai.prompt.manage`(编辑/激活/回滚) ### 3.3 页面 B — 分析历史 @@ -161,8 +168,9 @@ rollbackPrompt(id: string): Promise 位置: `apps/web/src/api/ai/analysis.ts` ```typescript -getAnalysisHistory(params: AnalysisQueryParams): Promise> -getAnalysisDetail(id: string): Promise +// 后端当前 list_analysis/get_analysis 为空壳(返回 ApiResponse::ok(())),需实现真实查询 +getAnalysisHistory(params: AnalysisQueryParams): Promise> // GET /api/v1/ai/analysis/history +getAnalysisDetail(id: string): Promise // GET /api/v1/ai/analysis/{id} ``` **权限码:** `ai.analysis.list`(查看)、`ai.analysis.manage`(重新分析) @@ -185,19 +193,21 @@ getAnalysisDetail(id: string): Promise 位置: `apps/web/src/api/ai/usage.ts` ```typescript -getUsageOverview(): Promise -getUsageTrend(params: TrendParams): Promise -getUsageByType(): Promise -getUsageByUser(params: UserRankingParams): Promise> +// 后端需完全新增:路由、handler、聚合 service +// ai_usage_logs 表需增加 created_by 列(当前缺失 user_id),或复用 ai_analysis_results.created_by 做用户排行 +getUsageOverview(): Promise // GET /api/v1/ai/usage/overview +getUsageTrend(params: TrendParams): Promise // GET /api/v1/ai/usage/trend +getUsageByType(): Promise // GET /api/v1/ai/usage/by-type +getUsageByUser(params: UserRankingParams): Promise> // GET /api/v1/ai/usage/by-user ``` -**后端补充:** 需要在 erp-ai handler 中新增用量统计端点(当前仅有 list/get,需增加 aggregation)。 +**后端补充:** 需在 erp-ai 中新增用量统计聚合端点。优先方案:复用 `ai_analysis_results` 表的 `created_by` 字段做用户维度排行,避免修改 `ai_usage_logs` 表结构。如需精确 token 统计,后续可加迁移增加 `user_id` 列。 **权限码:** `ai.usage.list` ### 3.5 菜单注册 -在 `apps/web/src/layouts/MainLayout.tsx` 健康管理菜单组下新增: +在 `apps/web/src/layouts/MainLayout.tsx` 健康管理菜单组下新增 AI 分析入口。当前菜单为扁平结构(无子菜单折叠),新增项直接追加为同级菜单项: ``` 健康管理 @@ -206,13 +216,11 @@ getUsageByUser(params: UserRankingParams): Promise> ├── 预约管理 ├── 随访管理 ├── 咨询管理 -├── 文章管理 ├── 积分商城 ├── 统计看板 -└── AI 分析 ← 新增 - ├── Prompt 管理 - ├── 分析历史 - └── 用量统计 +├── AI Prompt 管理 ← 新增(扁平) +├── AI 分析历史 ← 新增(扁平) +└── AI 用量统计 ← 新增(扁平) ``` ### 3.6 验证标准 @@ -229,31 +237,32 @@ getUsageByUser(params: UserRankingParams): Promise> ### 4.1 新增页面 -**报告列表页** +**AI 报告列表页** -位置: `apps/miniprogram/src/pages/report/list.tsx` +位置: `apps/miniprogram/src/pages/ai-report/list/index.tsx` -- 调用 `/api/v1/ai/analysis/history?patient_id={currentPatientId}` +- 调用 `GET /api/v1/ai/analysis/history` (后端需实现,根据 JWT user_id → patient_id 自动过滤) - 列表展示分析记录(类型图标 + 时间 + 状态标签) - 点击进入详情 -**报告详情页** +**AI 报告详情页** -位置: `apps/miniprogram/src/pages/report/detail.tsx` +位置: `apps/miniprogram/src/pages/ai-report/detail/index.tsx` -- 调用 `/api/v1/ai/analysis/{id}` -- Markdown 渲染分析结果(使用 Taro rich-text 或 taro-markdown 组件) +- 调用 `GET /api/v1/ai/analysis/{id}` +- 使用 `taro-markdown` 组件渲染 Markdown 格式的分析结果(需先验证兼容性) - 底部展示分析时间和 token 用量信息 ### 4.2 路由集成 在首页(`pages/index/index.tsx`)健康数据区域增加"AI 报告"入口卡片。 -### 4.3 API 复用 +### 4.3 后端依赖 -后端端点已存在(`list_analysis` + `get_analysis`),无需新增。需确保: -- 患者只能查看自己的分析记录(通过 JWT user_id → patient_id 过滤) -- 响应数据中不含 PII +后端 `list_analysis` 和 `get_analysis` 当前为空壳(仅验证权限后返回空值),需实现: +- 根据 JWT 中的 user_id 查找关联 patient_id +- 从 `ai_analysis_results` 表查询该患者的分析记录 +- 返回不含 PII 的脱敏结果 ### 4.4 验证标准 @@ -268,15 +277,19 @@ getUsageByUser(params: UserRankingParams): Promise> | 阶段 | 内容 | 依赖 | 预计工作量 | |------|------|------|-----------| -| P1 | usePermission hook + AuthButton/AuthGuard 组件 | 无 | 2 文件 | -| P2 | 健康模块 15 页面按钮权限改造 | P1 | 15 文件 | -| P3 | AI API 前端封装(3 个 service 文件) | 无 | 3 文件 | -| P4 | AI Prompt 管理页面 | P1, P3 | 1 文件 | -| P5 | AI 分析历史页面 | P1, P3 | 1 文件 | -| P6 | AI 用量统计页面 + 后端聚合 API | P1, P3 | 2 文件 | -| P7 | 菜单注册 + 路由配置 | P4-P6 | 2 文件 | -| P8 | 小程序报告列表 + 详情页 | P3 | 2 文件 | -| P9 | 小程序首页入口集成 | P8 | 1 文件 | +| 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 文件 | --- @@ -294,6 +307,7 @@ getUsageByUser(params: UserRankingParams): Promise> - 前端组件使用 Ant Design 6 现有组件 - 图表使用 Ant Design Charts(项目已有依赖) -- 小程序 Markdown 渲染使用社区 taro-markdown 组件或 rich-text -- 后端新增聚合 API 遵循现有 handler/service 模式 -- 所有新页面使用 i18n key,不硬编码中文 +- 小程序 Markdown 渲染使用 taro-markdown 组件(P8 开始前验证兼容性) +- 后端新增端点遵循现有 handler/service/entity 模式 +- 所有新页面使用 i18n key(前缀约定:`health.ai.*`),不硬编码中文 +- 权限数据加载失败时默认无权限(安全降级,宁可少显示按钮也不暴露越权操作)