From 1404cc8f1afe194dd3793eb8e0908257d8705c85 Mon Sep 17 00:00:00 2001 From: iven Date: Tue, 28 Apr 2026 01:31:42 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20UI/UX=20=E8=AE=BE=E8=AE=A1=E8=A7=84?= =?UTF-8?q?=E6=A0=BC=E4=BF=AE=E8=AE=A2=20=E2=80=94=20=E8=A1=A5=E5=85=85=20?= =?UTF-8?q?API=20=E5=A5=91=E7=BA=A6=E3=80=81=E7=BB=84=E4=BB=B6=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E3=80=81=E6=8A=80=E6=9C=AF=E5=89=8D=E7=BD=AE=E6=9D=A1?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增范围与前置条件(antd 6.x、dayjs 初始化、目标目录) - 定义角色 code 映射表和判定逻辑 - 补充个人工作量 API 契约(GET /personal-stats) - 新增 DrawerForm/FilterBar 组件接口定义 - 补充 dayjs 集中初始化方案 - 明确数据层策略(统一 usePaginatedData) - 修正小程序:SVG 图标替代 emoji、sparkline 用 CSS/SVG - 标记输入指示器为后续迭代 - 明确预约日历为现有组件增量优化 --- .../specs/2026-04-28-ui-ux-overhaul-design.md | 124 +++++++++++++++--- 1 file changed, 108 insertions(+), 16 deletions(-) diff --git a/docs/superpowers/specs/2026-04-28-ui-ux-overhaul-design.md b/docs/superpowers/specs/2026-04-28-ui-ux-overhaul-design.md index 98beae4..76a6507 100644 --- a/docs/superpowers/specs/2026-04-28-ui-ux-overhaul-design.md +++ b/docs/superpowers/specs/2026-04-28-ui-ux-overhaul-design.md @@ -2,6 +2,14 @@ > **日期**: 2026-04-28 | **状态**: 待审核 | **范围**: Web 管理后台 + 微信小程序 +## 范围与前置条件 + +- **Web 端改动目标**: `apps/web/`(React 19 SPA),不涉及 `apps/desktop/`(Tauri 桌面壳) +- **小程序改动目标**: `apps/miniprogram/`(Taro 4.2 + React 18) +- **UI 框架**: Ant Design 6.x(已确认 `antd ^6.3.5`),使用 `styles.body` 替代已弃用的 `bodyStyle` +- **状态管理**: Zustand stores(auth、theme 等) +- **日期库**: dayjs ^1.11.20,需集中初始化 `relativeTime` 插件 + `zh-cn` locale + ## Context HMS 健康管理平台前端当前存在"大而全"问题:仪表盘堆砌了 7 个信息区块但缺乏行动导向,22 个列表页面各自为政(3 种容器样式、3 种日期格式、暗色模式覆盖不完整),表单全用 Modal 弹窗无法承载复杂录入,小程序快捷服务用纯文字图标辨识度低。 @@ -23,7 +31,14 @@ HMS 健康管理平台前端当前存在"大而全"问题:仪表盘堆砌了 7 | 管理员 | 管理中心 | 数据优先 | 5 KPI + 趋势图 + 医护工作量 + 透析/化验/预约 Tab | | 运营 | 运营中心 | 转化优先 | 积分发放/消费 + 热门文章 + 活动报名 + 排行 | -角色判定逻辑:从 JWT 中提取用户角色(`user.roles`),按优先级 doctor > nurse > admin > operator 匹配。 +角色判定逻辑:从 `UserInfo.roles: RoleInfo[]` 中提取角色 code(`roles.map(r => r.code)`),按优先级 `doctor > nurse > admin > operator` 匹配第一个命中。多角色用户取最高优先级角色对应的仪表盘。`RoleInfo` 结构:`{ id, name, code, description?, is_system }`。 + +| 仪表盘角色 code | 匹配的 RBAC 角色 code | +|----------------|---------------------| +| `doctor` | `doctor` 或任何以 `doctor` 为前缀的 code | +| `nurse` | `nurse` 或任何以 `nurse` 为前缀的 code | +| `admin` | `admin`、`super_admin` | +| `operator` | `operator`、`content_manager` | ### 1.2 医生视图布局 @@ -120,8 +135,39 @@ HMS 健康管理平台前端当前存在"大而全"问题:仪表盘堆砌了 7 ### 1.7 技术实现 - **组件**: 新建 `StatisticsDashboard/` 目录下 4 个角色组件 + 1 个路由组件 -- **API**: 复用现有 `useStatsData` hook,按角色选择性请求 -- **后端**: 需新增"当前用户工作量"接口(我的患者数、随访完成率等个人维度数据) +- **API**: 复用现有 `useStatsData` hook 获取全局统计,新增个人维度请求 +- **后端**: 新增个人工作量 API + +#### 1.7.1 个人工作量 API 契约 + +``` +GET /api/v1/health/dashboard/personal-stats +Authorization: Bearer + +Response 200: +{ + "success": true, + "data": { + "my_patients": 186, // 我的患者数 + "new_patients_this_month": 12, // 本月新增患者 + "follow_up_rate": 0.92, // 随访完成率 + "consultations_this_month": 47, // 本月咨询数 + "pending_consultations": 5, // 待回复咨询 + "vital_signs_report_rate": 0.78, // 体征上报率(患者维度) + "today_appointments": 6, // 今日预约数 + "overdue_follow_ups": 8, // 逾期随访数 + "today_follow_ups": 12, // 今日待随访数 + "abnormal_vital_signs": 5, // 体征异常患者数 + "vital_signs_reported": 142, // 已上报人数 + "vital_signs_total": 182, // 应上报总人数 + "pending_lab_reviews": 2 // 待审核化验数 + } +} +``` + +#### 1.7.2 数据层策略 + +所有列表页必须统一使用 `usePaginatedData` hook 作为数据层(已有 `apps/web/src/hooks/usePaginatedData.ts`)。`PageContainer` 接收 `usePaginatedData` 返回值作为 props,避免两套分页/筛选系统并存。目前仅 `VitalSignsTab`、`LabReportsTab`、`HealthRecordsTab`、`FollowUpTab` 使用了该 hook,其余页面需迁移。 --- @@ -189,8 +235,19 @@ interface PageContainerProps { ### 2.5 共享工具 -提取到 `utils/format.ts`: +集中初始化 dayjs(`utils/dayjs.ts`): ```typescript +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; +import 'dayjs/locale/zh-cn'; +dayjs.extend(relativeTime); +dayjs.locale('zh-cn'); +export { dayjs }; +``` + +提取到 `utils/format.ts`(依赖 `utils/dayjs.ts`): +```typescript +import { dayjs } from './dayjs'; export const formatDate = (v: string) => dayjs(v).format('YYYY-MM-DD'); export const formatDateTime = (v: string) => dayjs(v).format('YYYY-MM-DD HH:mm'); export const formatRelative = (v: string) => dayjs(v).fromNow(); @@ -228,17 +285,52 @@ export const calcAge = (birthDate: string) => dayjs().diff(dayjs(birthDate), 'ye | 积分商品 | Modal → **Drawer** | 7→8 | 双列 + 图片上传 | | 文章编辑 | 独立页面(保持) | 富文本 | 全屏编辑器 | -### 3.3 表单分组规范 +### 3.3 DrawerForm 组件接口 -中等/复杂表单必须分组,每组有标题: +```typescript +interface FormSection { + title: string; // 分组标题 + fields: React.ReactNode; // 该分组内的表单项 + defaultCollapsed?: boolean; // 默认是否折叠 +} -**患者表单分组:** -- 基本信息:姓名*、性别、出生日期、血型 -- 联系方式:手机号、身份证号、地址 -- 医疗信息:过敏史、备注 -- 紧急联系人:姓名、电话、关系(新增) +interface DrawerFormProps { + title: string; // 抽屉标题 + open: boolean; + onClose: () => void; + onSubmit: (values: Record) => Promise; + initialValues?: Record; + loading?: boolean; + width?: number | string; // 默认 640 + sections?: FormSection[]; // 分组模式 + children?: React.ReactNode; // 非分组模式,直接传入表单项 + columns?: 1 | 2; // 布局列数,默认 2 +} +``` -### 3.4 表单交互规范 +### 3.4 FilterBar 组件接口 + +```typescript +// 组合模式:FilterBar 提供布局容器,筛选控件由各页面自行组合 +interface FilterBarProps { + children: React.ReactNode; // 筛选控件(Input/Select/DatePicker 等) + onReset?: () => void; // 重置按钮回调 + extra?: React.ReactNode; // 右侧额外操作(如导出按钮) +} +``` + +使用示例: +```tsx + + +