Files
hms/docs/design/mp-device-sync-redesign/SPEC.md
iven 1e59007bd5 fix(mp): DevTools 卡死 + 主包 2MB→766KB + 代码质量 4 项全通过
根因:主包 2MB 全量组件注入导致 DevTools 渲染引擎内存渐增,
叠加离线时固定 3s 抑制期后的请求洪泛。

修复:
- app.config.ts 添加 lazyCodeLoading: requiredComponents
  主包 2.0MB→766KB,taro.js 526→131KB,vendors.js 230→28KB
- request.ts 离线抑制改为指数退避(3s→6s→12s→30s cap)
  后端不可达时自动延长抑制,防止请求风暴
- SegmentTabs Tab 接口改为 readonly,修复 TS 编译错误
- AbortController polyfill 补齐小程序运行时缺失
- 健康首页/设备同步/健康档案/报告/设置页 UI 重构
- 文章页公开端点适配游客访问
- 健康首页 Swiper 间隔优化 4s→5s,动画 500→300ms
2026-05-24 11:32:40 +08:00

247 lines
11 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.
# 设备同步页面 设计规格
> 来源: mp-device-sync-redesign.html | 平台: 小程序(患者端) | 页面数: 7 | 生成: 2026-05-23
## 页面索引
| 页面 | 截图 | 路由 |
|------|------|------|
| 空闲态 | ![空闲态](./screenshots/screen-1.png) | pages/pkg-health/device-sync/index |
| 扫描中 | ![扫描中](./screenshots/screen-2.png) | pages/pkg-health/device-sync/index |
| 设备列表 | ![设备列表](./screenshots/list.png) | pages/pkg-health/device-sync/index |
| 连接中 | ![连接中](./screenshots/screen-4.png) | pages/pkg-health/device-sync/index |
| 已连接 | ![已连接](./screenshots/screen-5.png) | pages/pkg-health/device-sync/index |
| 同步完成 | ![同步完成](./screenshots/screen-6.png) | pages/pkg-health/device-sync/index |
| 错误状态 | ![错误状态](./screenshots/screen-7.png) | pages/pkg-health/device-sync/index |
## 一、Token 映射
| 原型值 | 项目 Token | 状态 |
|--------|-----------|------|
| T.pri (#C4623A) | --tk-pri | ✅ |
| T.priL (#F0DDD4) | --tk-pri-l | ✅ |
| T.priD (#8B3E1F) | --tk-pri-d | ✅ |
| T.bg (#F5F0EB) | $bg SCSS 变量 | ⚠️ 无 CSS Token直接用 $bg |
| T.card (#FFFFFF) | --tk-card-bg ($card) | ✅ |
| T.surface (#EDE8E2) | --tk-card-bg (≈) | ⚠️ 近似,用 $surface-alt SCSS 变量 |
| T.tx (#2D2A26) | $tx SCSS 变量 | ⚠️ 无 CSS Token直接用 $tx |
| T.tx2 (#5A554F) | $tx2 SCSS 变量 | ⚠️ 无 CSS Token直接用 $tx2 |
| T.tx3 (#78716C) | --tk-text-secondary ($tx3) | ✅ |
| T.bd (#E8E2DC) | $bd SCSS 变量 | ⚠️ 无 CSS Token直接用 $bd |
| T.bdL (#F0EBE5) | $bd-l SCSS 变量 | ⚠️ 无 CSS Token |
| T.acc (#5B7A5E) | $acc SCSS 变量 | ⚠️ 无 CSS Token |
| T.accL (#E8F0E8) | $acc-l SCSS 变量 | ⚠️ 无 CSS Token |
| T.wrn (#C4873A) | $wrn SCSS 变量 | ⚠️ 无 CSS Token |
| T.wrnL (#FFF3E0) | $wrn-l SCSS 变量 | ⚠️ 无 CSS Token |
| T.dan (#B54A4A) | $dan SCSS 变量 | ⚠️ 无 CSS Token |
| T.danL (#FDEAEA) | $dan-l SCSS 变量 | ⚠️ 无 CSS Token |
| T.r (16) | --tk-card-radius ($r) | ✅ |
| T.rSm (12) | $r-sm SCSS 变量 | ⚠️ 无 CSS Token |
| T.rXs (8) | $r-xs SCSS 变量 | ⚠️ 无 CSS Token |
| T.serif (Georgia...) | 字体栈 | ❌ 不映射,直接硬编码 |
| T.sans (-apple-system...) | 字体栈 | ❌ 不映射,直接硬编码 |
> 状态标记: ✅ confirmed 直接使用 | ⚠️ pending 需 SCSS 变量 | ❌ unmatched 需硬编码
## 二、页面结构
### 1. 空闲态idle
![空闲态](./screenshots/screen-1.png)
布局层级(从上到下):
- **NavBar** — 深色主色背景,标题"设备同步"
- **Hero 区域** — 主色渐变背景135deg pri→priD包含
- 蓝牙图标72px 圆形,半透明白底)
- 标题"智能设备同步"serif 22px 700
- 副标题14px 0.75 白色透明度)
- **支持设备** — 三列标签(心率手环/血压计/血糖仪),每个含 SVG 图标
- **上次同步卡片** — ContentCard 样式,左侧绿色勾选图标 + 时间 + 右侧数据量 badge
- **待上传提示** — 黄色背景警告条($wrnL三角感叹号图标
- **扫描按钮** — 全宽主色按钮,蓝牙图标 + "扫描附近设备"
### 2. 扫描中scanning
![扫描中](./screenshots/screen-2.png)
布局层级:
- **NavBar** — 同上
- **居中脉冲区域**
- 三层脉冲圆环CSS animation: pulse-ring外层→中层→内层递进
- 中心 80px 圆形蓝牙图标($priL 底色)
- **标题** — serif 20px "正在搜索设备..."
- **副文本** — 14px $tx3 提示文字
- **进度条** — 180px 宽,渐变填充 $priL→$pri
- **计时文字** — 12px "已用时 6 秒"
### 3. 设备列表found
![设备列表](./screenshots/list.png)
布局层级:
- **NavBar** — 同上
- **结果头部** — 左侧"发现 N 台设备"标题 + 右侧"重新扫描"链接(含刷新图标)
- **设备卡片列表**×3— 每张卡片含:
-44px 圆角方块图标($priL 底色 + 蓝牙 SVG
-设备名16px 600+ 适配器类型12px $tx3
-信号强度条4 级竖条) + 箭头
- **未发现设备提示** — 虚线边框卡片,搜索图标 + 提示文字
### 4. 连接中connecting
![连接中](./screenshots/screen-4.png)
布局层级:
- **NavBar** — 同上
- **居中动画区域**
- 100px 旋转环border-top-color: $priCSS animation: connect-spin
- 60px 中心圆形蓝牙图标
- **标题** — serif 18px "正在连接 {设备名}"
- **副文本** — "正在进行蓝牙配对..."
- **步骤指示器** — 三点一线:发现设备(✓) → 连接中(●脉冲) → 同步数据(○)
### 5. 已连接connected
![已连接](./screenshots/screen-5.png)
布局层级:
- **NavBar** — 同上
- **连接状态卡片** — 绿色渐变背景acc→#4A6B4E),蓝牙图标 + 设备名 + "实时" badge
- **最新读数高亮卡片** — 大卡片r=16 圆角 + shadow
- 52px 心形图标
- 类型+时间小字
- 数值serif 36px 700+ 单位
- **历史读数列表** — 标题 + 表格行(类型/数值/时间),每行 12px 分隔线
- **采集计数** — 居中小字
- **操作按钮行** — 左侧全宽"上传数据"主色按钮 + 右侧 52px 红色断开按钮
### 6. 同步完成done
![同步完成](./screenshots/screen-6.png)
布局层级:
- **NavBar** — 同上
- **居中成功区域**
- 80px 绿色圆形勾选图标
- 标题"同步完成"serif 24px 700
- 副文本"数据已安全上传至健康管理平台"
- **三列统计卡片** — 上传条数(5)/数据类型(3)/成功率(100%)
- **完成按钮** — 全宽主色按钮
### 7. 错误状态error
![错误状态](./screenshots/screen-7.png)
布局层级:
- **NavBar** — 同上
- **居中错误区域**
- 80px 红色圆形叉号图标
- 标题"连接失败"serif 22px 700
- 错误描述文字
- **错误详情卡片** — 含错误码/设备/时间三行键值对
- **重试按钮** — 全宽主色按钮,含刷新图标
- **返回按钮** — 描边按钮
## 三、组件映射
| 原型元素 | 推荐组件 | 来源 | 备注 |
|----------|---------|------|------|
| 页面外壳 | PageShell | @components/ui/PageShell | padding="none"NavBar 自带 |
| 连接状态卡片 | ContentCard | @components/ui/ContentCard | variant="elevated",绿色渐变背景自定义 |
| 成功结果卡片 | ContentCard | @components/ui/ContentCard | variant="elevated",居中布局 |
| 错误详情卡片 | ContentCard | @components/ui/ContentCard | variant="outlined" |
| 扫描按钮/上传按钮 | PrimaryButton | @components/ui/PrimaryButton | size="large"full width |
| 断开连接按钮 | — | 自定义 | 红色小方块图标按钮 |
| 返回按钮 | SecondaryButton | @components/ui/SecondaryButton | — |
| 设备类型标签 | — | 自定义 DeviceTypeTag | 小图标+文字,$bdL 边框 |
| 信号强度 | — | 自定义 SignalBars | 4 级竖条 |
| 上次同步信息 | ListItem | @components/ui/ListItem | leftIcon + title + subtitle + extra |
| 历史读数行 | InfoRow | @components/ui/InfoRow | label + value + last |
| 待上传警告 | AlertCard | @components/ui/AlertCard | variant="bordered",黄色 |
> ⚠️ **需新建**: SignalBars — 4 级竖条信号强度指示器20 行以内小组件)
> ⚠️ **需新建**: DeviceTypeTag — 设备类型标签(图标+文字,已非常简单,可直接内联)
## 四、交互规格
| 元素 | 交互 | 触发 | 反馈 | 备注 |
|------|------|------|------|------|
| 扫描按钮 | 调用 handleScan | onClick | 按钮变灰+loading状态→scanning | 触发 BLE 扫描 |
| 设备卡片 | 调用 handleConnect | onClick | 状态→connecting显示旋转动画 | 传递选中的 BLEDevice |
| 重新扫描链接 | 调用 handleScan | onClick | 同扫描按钮 | 刷新设备列表 |
| 上传数据按钮 | 调用 handleSync | onClick | 状态→syncing → done/error | 上传采集数据到后端 |
| 断开连接按钮 | 调用 handleDisconnect | onClick | 断开 BLE状态→idle | 清空 liveReadings |
| 完成按钮 | handleDisconnect + navigateBack | onClick | 返回上一页 | 如果 returnTo=input 则回填 Storage |
| 重试按钮 | handleScan | onClick | 重新扫描 | 从 error 恢复 |
| 返回按钮 | Taro.navigateBack | onClick | 返回上一页 | 错误状态 |
| 实时数据面板 | 被动更新 | BLE 通知 | 新数据插入列表顶部,数值动画 | useBLEManager hook 驱动 |
## 五、状态变体
- **idle**: 默认状态,展示 Hero + 设备类型 + 上次同步 + 扫描按钮
- **scanning**: 脉冲动画 + 进度条 + 计时,不可操作(无按钮)
- **found**: 设备列表 + 重新扫描链接,点击设备进入 connecting
- **connecting**: 旋转环动画 + 步骤指示器,不可操作
- **connected**: 绿色连接状态卡 + 实时数据面板 + 上传/断开按钮
- **done**: 成功图标 + 统计卡片 + 完成按钮
- **error**: 错误图标 + 错误详情 + 重试/返回按钮
- **syncing**: 复用 scanning 的加载态样式,文字改为"正在上传数据..."
## 六、样式清单
### 关键样式参数
```
/* Hero 渐变 */
background: linear-gradient(135deg, $pri 0%, $pri-d 100%)
padding: 32px 20px 28px
/* 脉冲圆环 */
animation: pulse-ring 2s ease-out infinite
三层: 140px / 110px / 80px (center)
/* 旋转环 */
animation: connect-spin 1s linear infinite
border-top-color: $pri
/* 最新读数数值 */
font-family: $serif; font-size: 36px; font-weight: 700
/* 连接状态卡片渐变 */
background: linear-gradient(135deg, $acc 0%, #4A6B4E 100%)
/* 信号条 */
4 根竖条: height [4, 7, 10, 13]px, width: 3px, gap: 2px
活跃色: $acc, 非活跃: $bd
/* 主按钮 */
background: $pri; border-radius: $r-sm; padding: 16px;
box-shadow: 0 4px 16px rgba(196, 98, 58, 0.3)
```
### 字号映射
| 原型字号 | Token | 用途 |
|---------|-------|------|
| 36px | 超大数值,直接用 serif bold | 最新读数数值 |
| 28px | --tk-font-h1 | 统计卡片数值 |
| 24px | — | 成功/错误标题 |
| 22px | --tk-font-h2 | Hero 标题、连接中标题 |
| 20px | — | 历史读数数值 |
| 18px | --tk-font-body-lg | NavBar 标题、按钮文字 |
| 17px | — | 主按钮文字 |
| 16px | --tk-font-body | 设备名、按钮文字 |
| 15px | — | 完成页副文本 |
| 14px | --tk-font-body-sm | 副文本、描述、列表类型 |
| 13px | --tk-font-cap | 标签文字、小字 |
| 12px | — | 时间、提示 |
---
> 此规格由 design-handoff skill 自动生成。LLM 实施时请:
> 1. 先阅读截图建立视觉印象
> 2. 按 Token 映射表使用项目 Token✅ 标记的直接用,⚠️ 用 SCSS 变量)
> 3. 优先使用"组件映射"中列出的已有组件
> 4. 参考"交互规格"实现对应的交互逻辑
> 5. "需新建"的组件参考截图和布局描述从头实现