feat: UI清爽紫蓝风全面改造 + 对话卡片重构 + 配色体系升级
- 新增 AppColors 统一配色方案(清爽紫蓝,参考蚂蚁阿福风格) - 新增 common_widgets(GradientBorderButton / CardActionButton / IconBox) - AgentWelcomeCard 美化:渐变 header + AI标签 + 核心功能区 + 快捷操作区 - DataConfirmCard 统一:三合一(健康/药品/运动),可编辑字段列表 - 删除死代码:medicationConfirm/dietAnalysis/reportAnalysis/quickOptions 卡片 - 删除死路由:doctors/profileEdit/editProfile - AI 对话去除 Markdown 符号(_stripMd),统一行间距 1.5 - 逐字淡入动画修复:key 改用 stableId 避免重复触发 - 健康概览时间修复:前端发送 UTC 避免时区歧义 - PG 数据目录迁入项目 backend/pgdata/,加入 .gitignore - 新增欧姆龙血压计实施方案文档
This commit is contained in:
170
docs/omron_bp_implementation_plan.md
Normal file
170
docs/omron_bp_implementation_plan.md
Normal file
@@ -0,0 +1,170 @@
|
||||
# 欧姆龙 J735 蓝牙血压计 — 实施计划
|
||||
|
||||
---
|
||||
|
||||
## 一、当前状态
|
||||
|
||||
- 设备已购:欧姆龙 J735
|
||||
- 前端占位:`DeviceManagementPage` 目前是空壳(显示"暂无绑定设备"),路由 `devices` 已注册,入口在 ProfilePage → 设备管理
|
||||
- 项目风格:淡紫清新风(`AppTheme`),Material 3 + shadcn_ui + Riverpod
|
||||
- 本地存储:SQLite(`LocalDatabase`,kv_store 表)
|
||||
- 后端:已有 `POST /api/health-records` 支持 BloodPressure 类型,Source 枚举需加 `Device`
|
||||
|
||||
---
|
||||
|
||||
## 二、实施范围
|
||||
|
||||
### 2.1 新增依赖
|
||||
|
||||
```yaml
|
||||
# pubspec.yaml
|
||||
flutter_blue_plus: ^1.34.0 # BLE 核心
|
||||
permission_handler: ^11.3.0 # 蓝牙权限
|
||||
```
|
||||
|
||||
### 2.2 新增文件(6 个)
|
||||
|
||||
```
|
||||
health_app/lib/
|
||||
├── services/
|
||||
│ └── omron_ble_service.dart # BLE 连接 + SFLOAT 协议解析
|
||||
├── models/
|
||||
│ └── bp_reading.dart # 血压数据模型
|
||||
├── providers/
|
||||
│ └── omron_device_provider.dart # 设备绑定状态 + 实时读数
|
||||
├── pages/
|
||||
│ └── device/
|
||||
│ ├── device_scan_page.dart # 扫描设备页
|
||||
│ └── device_bind_page.dart # 已绑定设备管理页(替换空壳)
|
||||
```
|
||||
|
||||
### 2.3 修改文件(3 个)
|
||||
|
||||
| 文件 | 改动内容 |
|
||||
|------|---------|
|
||||
| `pages/remaining_pages.dart` | 替换 `DeviceManagementPage` 空壳为 `DeviceBindPage` |
|
||||
| `core/app_router.dart` | `devices` 路由指向新页面 |
|
||||
| `providers/data_providers.dart` | 新增 `omronBleServiceProvider`、`bpReadingsProvider` |
|
||||
| 后端 `health_enums.cs` | `HealthRecordSource` 加 `Device` |
|
||||
|
||||
---
|
||||
|
||||
## 三、分步实施(3 天)
|
||||
|
||||
### Day 1 — BLE 服务层
|
||||
|
||||
**目标**:手机能搜到 J735、连接上、收到蓝牙数据并正确解析
|
||||
|
||||
1. 添加 `flutter_blue_plus` + `permission_handler` 依赖
|
||||
2. 配置 Android 蓝牙权限(`AndroidManifest.xml`)+ iOS 权限(`Info.plist`)
|
||||
3. 实现 `BpReading` 数据模型(systolic/diastolic/pulse/timestamp/status)
|
||||
4. 实现 `OmronBleService`:
|
||||
- `scan()` — 过滤蓝牙名含 `OMRON`/`HEM`/`BLEsmart` 且有 `0x1810` 服务的设备
|
||||
- `connect()` — 连接 → discoverServices → 订阅 `0x2A35` Indicate
|
||||
- `_parseReading()` — SFLOAT 解码 + Flags 解析(kPa 转换、体动、心律等)
|
||||
- `_syncTime()` — 写入 `0x2A08` 同步时间
|
||||
- `disconnect()` / `dispose()`
|
||||
5. 用 nRF Connect 抓包验证原始 HEX → SFLOAT 解码结果与屏幕一致
|
||||
|
||||
**产出**:`OmronBleService` 可独立运行,单元测试验证 SFLOAT 解码
|
||||
|
||||
### Day 2 — UI 页面
|
||||
|
||||
**目标**:实现扫描绑定页 + 已绑定管理页,风格对齐项目淡紫主题
|
||||
|
||||
#### 扫描绑定页 (`DeviceScanPage`)
|
||||
- AppBar 标题"添加血压计",返回按钮
|
||||
- 顶部:扫描状态指示(转圈 + "正在扫描..." / "扫描完成,发现 N 台设备")
|
||||
- 空状态:未发现设备时显示使用说明卡片(装电池 → 长按蓝牙键 → 手机靠近 → 检查权限)
|
||||
- 设备列表:每行显示 BLE 设备名 + 信号强度 + MAC + "连接"按钮
|
||||
- 连接中:按钮变 loading
|
||||
- 连接成功:SnackBar "已连接 OMRON xxx",返回上一页并传递设备信息
|
||||
- 底部:重新扫描按钮
|
||||
|
||||
#### 已绑定管理页 (`DeviceBindPage`,替换空壳)
|
||||
- **未绑定状态**:大蓝牙图标 + "未绑定设备" + 说明文字 + "添加设备"按钮,点击跳扫描页
|
||||
- **已绑定状态**:白底圆角卡片
|
||||
- 设备图标(紫色渐变圆)+ 设备名
|
||||
- MAC 地址(灰色小字)
|
||||
- 上次同步时间
|
||||
- "解绑设备"按钮(红色文字)
|
||||
|
||||
**风格要点**(保证不出现"全黑"):
|
||||
- 背景色:`AppTheme.bg`(淡紫白 `#FAF9FF`)
|
||||
- 卡片:白色 `Colors.white`,圆角 `AppTheme.rLg`(20),`AppTheme.shadowCard` 阴影
|
||||
- 按钮:紫色实心(`AppTheme.primary`)+ 圆角 `AppTheme.rPill`
|
||||
- 空状态图标:`Colors.grey[300]`,文字 `AppTheme.textHint`
|
||||
- 使用 shadcn_ui 图标(`LucideIcons`)
|
||||
- 与 SettingsPage、ProfilePage 保持一致的 AppBar 风格
|
||||
|
||||
**产出**:两个 UI 页面,风格与项目统一,从 ProfilePage → 设备管理可进入
|
||||
|
||||
### Day 3 — 数据同步 + 联调
|
||||
|
||||
1. **Provider 层**:`omronDeviceProvider` 管理绑定状态(MAC/name/lastSync 存入 SQLite)
|
||||
2. **自动同步**:收到 BLE 读数后自动 `POST /api/health-records`
|
||||
```dart
|
||||
{
|
||||
'type': 'BloodPressure',
|
||||
'systolic': reading.systolic,
|
||||
'diastolic': reading.diastolic,
|
||||
'source': 'Device',
|
||||
'unit': 'mmHg',
|
||||
'recordedAt': reading.timestamp.toUtc().toIso8601String(),
|
||||
}
|
||||
```
|
||||
3. **去重逻辑**:同一时间戳(精确到秒)+ 同一值 → 跳过
|
||||
4. **健康概览刷新**:同步后 `ref.invalidate(latestHealthProvider)`
|
||||
5. **真机 + J735 联调**:
|
||||
- 扫描 → 连接 → 测量 → 数据上传 → 健康概览显示新数据
|
||||
- 断连 → 重新打开 App → 再次连接
|
||||
- iOS 和 Android 双平台测试
|
||||
|
||||
---
|
||||
|
||||
## 四、交互流程
|
||||
|
||||
```
|
||||
用户操作 App 行为
|
||||
──────── ────────
|
||||
设置 → 蓝牙血压计 打开 DeviceBindPage(已绑定/未绑定)
|
||||
│
|
||||
├─ 未绑定
|
||||
│ └─ 点"添加设备" 打开 DeviceScanPage
|
||||
│ └─ 扫到 J735 点击"连接"
|
||||
│ └─ 连接成功 返回 DeviceBindPage(已绑定状态)
|
||||
│
|
||||
└─ 已绑定
|
||||
└─ 血压计测量 血压计按开始键 → 测量完成
|
||||
│ BLE Indicate 推送数据
|
||||
│ App 收到 120/80
|
||||
│ SnackBar: "已同步: 120/80 mmHg"
|
||||
│ 自动写入 HealthRecords
|
||||
│ 健康概览刷新
|
||||
└─ 查看 点"健康概览"可看到新数据
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、预期效果
|
||||
|
||||
- 从 ProfilePage → 设备管理,不再是全黑空壳,而是漂亮的设备管理页面
|
||||
- 点击"添加设备"打开扫描页,15 秒内搜索到 J735
|
||||
- 点击"连接" 2 秒内完成绑定
|
||||
- J735 测量完毕后,App 自动收到数据(无需手动操作)
|
||||
- 数据自动写入健康记录,健康概览实时刷新
|
||||
- 同一数据不重复录入
|
||||
- 重新打开 App 后已绑定设备状态保留
|
||||
- iOS + Android 双平台均可使用
|
||||
|
||||
---
|
||||
|
||||
## 六、风险点
|
||||
|
||||
| 风险 | 应对 |
|
||||
|------|------|
|
||||
| J735 蓝牙名称与预期不符 | 不硬编码名称,用 `0x1810` 服务 UUID 过滤;首次连接后打印实际名称 |
|
||||
| Android 12+ 蓝牙权限弹窗被拒 | `permission_handler` 检测权限状态,引导用户去设置开启 |
|
||||
| 设备已被系统蓝牙占用 | 扫描页提示"如搜不到请先取消系统蓝牙配对" |
|
||||
| SFLOAT 解码与屏幕值有偏差 | 用 nRF Connect 抓 HEX 对比,误差 > 1 则调整解码 |
|
||||
| iOS BLE 后台断连 | 前台连接同步,完成后断开;不做后台持久连接 |
|
||||
Reference in New Issue
Block a user