Files
AI-Health/docs/omron_bp_implementation_plan.md
MingNian f01fc9268d 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
- 新增欧姆龙血压计实施方案文档
2026-06-09 17:04:11 +08:00

171 lines
6.8 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.

# 欧姆龙 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 后台断连 | 前台连接同步,完成后断开;不做后台持久连接 |