Files
hms/docs/superpowers/specs/2026-04-28-ui-ux-overhaul-design.md
iven ca32be59be
Some checks failed
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
docs: UI/UX 设计规格二轮修订 — 填充表单分组表、修正 any→unknown
2026-04-28 01:34:16 +08:00

494 lines
22 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 前端 UI/UX 全面重构设计规格
> **日期**: 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 storesauth、theme 等)
- **日期库**: dayjs ^1.11.20,需集中初始化 `relativeTime` 插件 + `zh-cn` locale
## Context
HMS 健康管理平台前端当前存在"大而全"问题:仪表盘堆砌了 7 个信息区块但缺乏行动导向22 个列表页面各自为政3 种容器样式、3 种日期格式、暗色模式覆盖不完整),表单全用 Modal 弹窗无法承载复杂录入,小程序快捷服务用纯文字图标辨识度低。
本次重构目标:对标国内外一流医疗/SaaS 产品MyChart、丁香医生、Linear、Stripe按角色自适应原则重新设计信息架构统一 CRUD 页面模式,建立表单三级容器策略。
---
## 一、Web 仪表盘重构
### 1.1 角色自适应策略
仪表盘根据当前用户角色显示不同视图:
| 角色 | 视图名称 | 核心原则 | 主要内容 |
|------|---------|---------|---------|
| 医生 | 今日工作台 | 行动优先 | 日程时间线 + 紧急提醒 + 化验审核 + 咨询消息 |
| 护士 | 随访监控台 | 监控优先 | 体征异常列表 + 随访队列 + 上报率 + 今日预约 |
| 管理员 | 管理中心 | 数据优先 | 5 KPI + 趋势图 + 医护工作量 + 透析/化验/预约 Tab |
| 运营 | 运营中心 | 转化优先 | 积分发放/消费 + 热门文章 + 活动报名 + 排行 |
角色判定逻辑:从 `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 医生视图布局
```
┌─────────────────────────────────────────────────┐
│ 问候语 + 今日摘要X个预约 · X条待处理 🔍 🔔 │
├─────────────────────────────────────────────────┤
│ [紧急] 张明华 血压 180/110 │ [注意] 2份化验待审 │
├─────────────────────┬───────────────────────────┤
│ │ 化验审核 (2待审) │
│ 今日日程 │ ├ 张明华 — 血常规 3项异常│
│ ├ 09:30 张明华 ←当前│ └ 陈建国 — 肝功能 正常 │
│ ├ 10:00 李秀英 ├───────────────────────────┤
│ ├ 11:00 陈建国 │ 咨询消息 (5未读) │
│ └ 14:00 赵丽芳 │ ├ 王小明 10分钟前 │
│ │ └ 赵丽芳 1小时前 │
├─────────┬──────┬──────────┬────────────────────┤
│ 我的患者│随访率│ 本月咨询 │ 体征上报率 │
│ 186 │ 92% │ 47 │ 78% │
│ ↑12新增 │ ↑5% │ 5待回复 │ ↓3% │
└─────────┴──────┴──────────┴────────────────────┘
```
### 1.3 护士视图布局
```
┌─────────────────────────────────────────────────┐
│ 问候 + 今日待随访12人 · 体征异常5人 │
├─────────────────────────────────────────────────┤
│ 体征异常提醒 (5人异常) 查看全部 → │
│ ├ 张明华 血压 180/110 · 上报08:30 [高危] 通知医生→│
│ └ 刘美华 血糖 12.5 · 上报07:45 [偏高] 通知医生→│
├─────────────────────┬───────────────────────────┤
│ 今日随访队列 (12人) │ 今日体征上报 │
│ [逾期] 王小明 血压 │ 78% │
│ [逾期] 陈小红 用药 │ 142已上报 │ 40未上报 │
│ [今日] 刘美华 用药 │ 催报未上报患者 → │
│ [今日] 赵丽芳 透析 │ │
├─────────┬──────────────┬────────────────────────┤
│ 今日预约│ 随访完成率 │ 逾期随访 │
│ 6 │ 85% │ 8 │
└─────────┴──────────────┴────────────────────────┘
```
### 1.4 管理员视图布局
```
┌─────────────────────────────────────────────────┐
│ 管理中心 · 数据概览 [📅本月▾] [⬇️导出] │
├───────┬───────┬───────┬───────┬─────────────────┤
│患者总数│本月预约│随访完成│体征上报│医护人数 │
│ 1,284 │ 356 │ 86% │ 72% │ 24 │
│ ↑8.2% │ ↓3.1% │ ↑5% │ ↓2% │ 3医21护 │
├─────────────────────────┬───────────────────────┤
│ 患者增长 & 预约趋势图 │ 医护工作量 │
│ [双线图: 新增+预约] │ 王主任 186 ████████ 92%│
│ │ 陈医生 142 ██████ 70%│
│ │ 李护士 28 随访 █████ 85%│
├─────────────────────────┴───────────────────────┤
│ [透析管理] 化验报告 预约分析 体征数据 │
│ 总记录 423 │ 并发症 2.3% │ 均超滤 2100ml │ 均时长245min │
└─────────────────────────────────────────────────┘
```
### 1.5 运营视图布局
```
┌─────────────────────────────────────────────────┐
│ 运营中心 · 积分、内容、活动 [📅本月▾] │
├──────────┬──────────┬──────────┬────────────────┤
│ 积分发放 │ 积分消费 │ 文章发布 │ 活动报名 │
│ 12,450 │ 8,320 │ 18 │ 86 │
│ ↑15% │ 消费率66.8%│ 阅读4520│ 3场进行中 │
├─────────────────────┬───────────────────────────┤
│ 积分消费排行 │ 热门文章 │
│ 1 赵丽芳 3,200分 │ 高血压管理指南 阅读1,230 │
│ 2 王小明 2,800分 │ 透析饮食注意 阅读980 │
│ 3 刘美华 2,150分 │ 春季过敏预防 阅读756 │
├─────────────────────┴───────────────────────────┤
│ 线下活动 │
│ [高血压讲座 5/15 30/50人] [透析培训 5/22 18/30] │
└─────────────────────────────────────────────────┘
```
### 1.6 砍掉的内容
| 当前区块 | 处置 | 原因 |
|---------|------|------|
| 快捷入口8个图标 | 删除 | 与左侧导航完全重复 |
| 积分排行 Top10 | 移至运营视图 | 医护不需要看积分排行 |
| 最近活动 | 删除 | 复用了排行 columns未展示真正活动 |
| 健康数据中心(嵌套 Card>Card | 拆分到管理员视图 | 4 面板数据医护无需关注 |
### 1.7 技术实现
- **组件**: 新建 `StatisticsDashboard/` 目录下 4 个角色组件 + 1 个路由组件
- **API**: 复用现有 `useStatsData` hook 获取全局统计,新增个人维度请求
- **后端**: 新增个人工作量 API
#### 1.7.1 个人工作量 API 契约
```
GET /api/v1/health/dashboard/personal-stats
Authorization: Bearer <jwt>
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其余页面需迁移。
---
## 二、列表页统一规范
### 2.1 统一 PageContainer 组件
提取共享组件 `components/PageContainer.tsx`,解决 3 种容器样式 + 暗色模式缺失:
```typescript
interface PageContainerProps {
title: string;
subtitle?: string;
filters?: React.ReactNode; // 筛选栏
actions?: React.ReactNode; // 右侧操作按钮
batchActions?: React.ReactNode; // 批量操作(选中时显示)
selectedCount?: number; // 选中数量
onSelectAll?: () => void;
onClearSelection?: () => void;
}
```
### 2.2 统一筛选栏规范
每个列表页至少 3 个筛选维度:
| 页面 | 筛选维度 |
|------|---------|
| 患者管理 | 搜索(姓名/手机/身份证) + 状态 + 性别 + 注册日期范围 |
| 医生管理 | 搜索(姓名) + 科室 + 职称 + 在线状态 |
| 预约管理 | 状态 + 日期范围 + 患者搜索 + 预约类型 |
| 随访任务 | 状态 + 计划日期范围 + 随访类型 + 执行人 |
| 咨询管理 | 状态 + 日期范围 |
| 积分规则 | 类型 + 状态 |
| 积分商品 | 搜索(名称) + 类型 + 上架状态 |
| 积分订单 | 状态 + 日期范围 |
| 告警列表 | 状态 + 严重程度 + 规则名搜索 + 日期范围 |
| 文章管理 | 搜索(标题) + 分类 + 状态 |
### 2.3 统一表格列设计原则
- **UUID 永远不暴露给用户**:后端必须返回 name 字段,前端兜底显示"未知患者"
- **日期格式统一**:全部使用 `dayjs(v).format('YYYY-MM-DD HH:mm')`,告警等时间敏感页面用 `fromNow()` + title 悬停绝对时间
- **实体列合并**:姓名列集成副标题(手机号/来源),状态列合并认证状态
- **出生日期 → 年龄**:列表页显示"42岁"比"1984-03-15"更实用
- **增加 Checkbox 列**:支持批量选择和操作(批量导出/删除)
### 2.4 各页面列调整
**患者管理** (9列 → 8列)
- 合并:姓名 + 来源 → 姓名列(副标题显示手机号 + 来源)
- 合并:认证状态 → 状态列
- 变更:出生日期 → 年龄
- 变更:创建时间 → 最近就诊时间
- 新增Checkbox 列
**告警列表** (7列 → 6列)
- 变更Patient ID → 患者姓名(可点击跳转)
- 新增:严重程度筛选 + 日期范围筛选
**随访任务** (7列 → 7列)
- 变更:患者 ID → 患者姓名
- 变更:执行人 ID → 执行人姓名
- 新增:日期范围 + 类型 + 执行人筛选
### 2.5 共享工具
集中初始化 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();
export const calcAge = (birthDate: string) => dayjs().diff(dayjs(birthDate), 'year');
```
提取到 `components/EntityName.tsx`
```typescript
// 统一处理 name 缺失的兜底显示
<EntityName name={record.patient_name} id={record.patient_id} />
// name 存在 → 显示 name
// name 缺失 → 显示 "未知患者" + tooltip 显示 ID
```
---
## 三、表单设计规范
### 3.1 三级容器策略
| 复杂度 | 容器 | 布局 | 适用场景 |
|--------|------|------|---------|
| 简单 (≤6字段) | Modal 弹窗 | 垂直单列 | 状态变更、简单编辑、分配 |
| 中等 (7-12字段) | Drawer 抽屉 | 分组 + 双列网格 | 创建/编辑主实体 |
| 复杂 (>12字段) | 独立页面 | 分步/分组 + 双列 | 完整建档、文章编辑 |
### 3.2 各页面表单容器决策
| 页面 | 当前 → 改进 | 字段数 | 布局 |
|------|------------|--------|------|
| 患者管理 | Modal → **Drawer** | 7→12 | 分组双列(基本/联系/医疗/紧急联系人) |
| 医生管理 | Modal保持 | 6 | 双列网格 |
| 预约管理 | Modal → **Drawer** + 支持编辑 | 6→7 | 双列 + 排班校验反馈 |
| 随访填写 | 3 Modal → Modal + **Drawer** | 5 | 填写记录用 Drawer |
| 积分商品 | Modal → **Drawer** | 7→8 | 双列 + 图片上传 |
| 文章编辑 | 独立页面(保持) | 富文本 | 全屏编辑器 |
### 3.3 DrawerForm 组件接口
```typescript
interface FormSection {
title: string; // 分组标题
fields: React.ReactNode; // 该分组内的表单项
defaultCollapsed?: boolean; // 默认是否折叠
}
interface DrawerFormProps {
title: string; // 抽屉标题
open: boolean;
onClose: () => void;
onSubmit: (values: Record<string, unknown>) => Promise<void>;
initialValues?: Record<string, any>;
loading?: boolean;
width?: number | string; // 默认 640
sections?: FormSection[]; // 分组模式
children?: React.ReactNode; // 非分组模式,直接传入表单项
columns?: 1 | 2; // 布局列数,默认 2
}
```
### 3.4 FilterBar 组件接口
```typescript
// 组合模式FilterBar 提供布局容器,筛选控件由各页面自行组合
interface FilterBarProps {
children: React.ReactNode; // 筛选控件Input/Select/DatePicker 等)
onReset?: () => void; // 重置按钮回调
extra?: React.ReactNode; // 右侧额外操作(如导出按钮)
}
```
使用示例:
```tsx
<FilterBar onReset={handleReset}>
<Input placeholder="搜索姓名/手机号" />
<Select placeholder="状态" options={statusOptions} />
<DatePicker.RangePicker />
</FilterBar>
```
### 3.5 表单分组规范
中等/复杂表单必须分组,每组有标题:
| 表单 | 分组 1 | 分组 2 | 分组 3 | 分组 4 |
|------|--------|--------|--------|--------|
| 患者 | 基本信息(姓名/性别/出生日期/血型) | 联系方式(手机/身份证/地址) | 医疗信息(过敏史/备注) | 紧急联系人(姓名/电话/关系) |
| 预约 | 患者信息(患者/类型/日期) | 医生信息(医生/时段/排班状态) | — | — |
| 随访 | 基本信息(患者/计划日期/类型) | 填写内容(执行人/结果/备注) | — | — |
| 积分商品 | 基本信息(名称/类型/积分/库存) | 展示(图片/描述/上架状态) | — | — |
### 3.6 表单交互规范
- 所有表单字段编辑时必须完整回填(当前患者编辑缺失 allergy_history/notes
- 双列布局中相关字段同行(姓名+性别、出生日期+血型)
- 预约表单选择医生+日期后实时显示排班状态
- 取消预约的取消原因用独立 Drawer 而非嵌套 Modal.confirm
---
## 四、小程序端重构
### 4.1 患者首页
**改动点:**
- 顶部区域从浅色 → 深色渐变卡片,集成今日健康摘要(血压/心率/血糖三格)
- 无数据时显示引导文案:"今天还没录入数据,点击开始" + 录入按钮
- 快捷服务从纯文字图标 → SVG 图标 + 白色卡片日常上报、预约挂号、在线咨询、AI报告。使用微信小程序内置 icon 组件或项目内 SVG 资源,不使用 emoji跨设备渲染不一致
- 待办事项增加日期卡片视觉(左侧显示日期,右侧显示内容)
- 新增"健康资讯"推荐区块1-2 篇文章)
- 提醒角标:顶部右侧显示未读消息/异常提醒数
### 4.2 健康数据 Hub
- 体征卡片增加参考范围文字和微型趋势 sparkline使用纯 CSS/SVG 实现,不加载 ECharts 实例,避免小卡片内运行完整图表库)
- 打卡入口合并到顶部(当前独立卡片)
- 趋势链接优化为横向滚动卡片
### 4.3 日常监测表单
- 8 个区块改为分组折叠:晨间体征(血压/心率)→ 晚间体征 → 其他(体重/血糖/出入量/备注)
- 异常值实时提示:输入超出参考范围时红框高亮 + 文字提醒
- 提交前校验摘要弹窗:"血压偏高 (160/95),确认提交?"
### 4.4 预约流程
- 创建页增加医生排班实时日历视图
- 选择日期后高亮可约时段,不可约时段灰显(增量优化现有 `WeekCalendar` 组件:为 `available_count === 0` 的时段添加灰显样式,不足时显示"当日无空位"提示)
- 预约详情页增加"修改预约"和"取消预约"操作
### 4.5 咨询聊天
- 消息按日期分组显示("今天"、"昨天"、具体日期)
- 增加"对方正在输入"状态提示(需后端支持 WebSocket typing 事件Phase 5 暂不实现,移至后续迭代)
- 图片消息支持点击预览大图
### 4.6 积分商城
- 顶部积分余额大字显示 + 签到按钮
- 商品卡片增加库存提示和兑换按钮
- 分类 Tab 保留但优化视觉
### 4.7 医护工作台
- 顶部增加异常体征提醒横幅(与 Web 医生视图紧急提醒联动)
- 工作概览卡片改为图标 + 数字 + 标签三层结构
- 新增患者搜索入口
- 快捷操作增加"随访记录"、"排班查看"
### 4.8 趋势图表
- ECharts 加载优化:懒加载 + 骨架屏
- 异常值红点标记 + 点击显示详情
- 时间范围选择器7天/30天/90天 按钮组
---
## 五、共享组件抽取
### 5.1 Web 端新增组件
| 组件 | 位置 | 用途 |
|------|------|------|
| `PageContainer` | `components/PageContainer.tsx` | 统一页面容器(标题+筛选+表格+暗色模式) |
| `EntityName` | `components/EntityName.tsx` | 统一实体名称显示(兜底"未知" |
| `RoleDashboard` | `pages/health/StatisticsDashboard/` | 角色自适应仪表盘路由 |
| `FilterBar` | `components/FilterBar.tsx` | 统一筛选栏组件 |
| `DrawerForm` | `components/DrawerForm.tsx` | 抽屉式表单容器(分组+双列) |
### 5.2 小程序端新增组件
| 组件 | 位置 | 用途 |
|------|------|------|
| `HealthSummaryCard` | `components/HealthSummaryCard/` | 健康摘要卡片(带状态色) |
| `DateCard` | `components/DateCard/` | 日期卡片(用于待办/日程) |
| `AlertBanner` | `components/AlertBanner/` | 紧急提醒横幅 |
| `GroupedFormSection` | `components/GroupedFormSection/` | 分组折叠式表单区块 |
### 5.3 共享工具
| 工具 | 位置 | 用途 |
|------|------|------|
| `formatDate/formatDateTime/formatRelative/calcAge` | `utils/format.ts` | 统一日期格式化 |
---
## 六、实施优先级
### Phase 1: 基础组件1-2天
1. 提取 `PageContainer` 组件
2. 提取 `EntityName` 组件
3. 提取 `formatDate/formatDateTime/formatRelative/calcAge` 工具函数
4. 统一暗色模式处理
### Phase 2: 仪表盘重构2-3天
5. 实现 4 角色仪表盘组件
6. 对接现有 API + 新增个人工作量 API
7. 删除快捷入口/积分排行/最近活动区块
### Phase 3: 列表页统一3-4天
8. 各页面迁移到 `PageContainer`
9. 补充筛选器(每页至少 3 个维度)
10. 修复 UUID 暴露(后端 + 前端兜底)
11. 统一日期格式 + 增加 Checkbox 列
12. 调整表格列(合并/变更/新增)
### Phase 4: 表单升级2-3天
13. 实现 `DrawerForm` 组件
14. 患者表单升级Drawer + 分组 + 新增字段
15. 预约表单升级Drawer + 排班校验
16. 随访填写升级Drawer + 完整回填
17. 积分商品升级Drawer + 图片上传
### Phase 5: 小程序重构3-4天
18. 患者首页重设计(深色顶部 + 健康摘要)
19. 健康数据 Hub 优化(参考范围 + sparkline
20. 日常监测表单分组折叠
21. 预约流程优化(排班日历)
22. 咨询聊天优化(消息分组)
23. 积分商城优化(余额+签到)
24. 医护工作台重设计
25. 趋势图表性能优化
### Phase 6: 验收1天
26. 全页面暗色模式测试
27. 响应式布局测试
28. 各角色权限测试
---
## 七、验证方式
1. `pnpm build` — 前端生产构建通过
2. 启动后端 + 前端服务,逐角色登录验证仪表盘
3. 逐页面对比截图,确认每个列表页筛选/列/表单改进生效
4. 小程序编译后真机预览,验证各页面改动
5. 暗色模式全量截图对比