ericwyuan 757afdc941 [阶段9] 界面打磨:hero 圆环、sparkline、骨架屏、动效
参考了 itsdrchen/Garmin-AI-Coach 与主流健康 App(Apple 活动圆环、
Oura/Whoop 的评分环、Garmin Connect 的卡内趋势)的做法。

hero 区(每个视图只有一个 hero 数字):
- 步数目标圆环,超额时转为 status-good 色并保持满环 + 端点标记,
  而不是绕第二圈 —— 绕圈会让 101% 看起来比 100% 还少
- 圆环轨道用填充色同色系的浅阶而非中性灰,两者才读作同一个量器

sparkline(12 点,卡片内嵌):
- 线用去强调色,只有最新一点用强调色,让它成为数字的背景而非对手
- null 处断开而不插值 —— 设备没记录的那天连一条平线过去等于编数据

骨架屏取代转圈:
- 形状与将要出现的内容一致,数据到位时布局不跳
- 用扫光而非闪烁,读起来像进度而不是元素在求关注

动效:
- 卡片/图表依次入场(45ms 递增),引导视线扫过而不是整屏同时砸下来
- 数字滚动到位、圆环扫过、sparkline 描线、悬停抬升、按下微缩
- 全部尊重 prefers-reduced-motion:直接跳过而非缩短时长 ——
  引起不适的是位移本身,不是它持续多久

深色改为冷调(借鉴参考项目):
- 表面从暖近黑 #1a1a19 改为冷近黑 #181b21,更像运动 App
- 换表面意味着原有校验作废,已用校验器对新表面重跑:四个系列色
  全部通过含 3:1 对比度;文字亦逐个复核(正文 14.56:1、
  次要 7.98、弱化 4.38、按钮白字 6.63)

fix(a11y): 大号独立数字不应使用 tabular-nums
- 等宽数字让每个字形都占 0 的宽度,大字号下显得松散;
  等宽只保留给需要纵向对齐的表格列与坐标轴刻度

fix: 数字滚动动画吞掉了小数位
- StatTile 内部按 decimals 格式化,而调用方已经先 round 过一次,
  距离显示成 "9 km"、久坐成 "11 小时"。改为传原值 + decimals

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-08-23 22:48:09 +08:00

佳明健康数据分析平台 (Garmin Health Lab)

一个完整的健康数据分析平台用于获取、分析和可视化你的佳明Garmin设备数据。

📊 主要功能

  • 数据同步: 通过 Garmin API 自动同步你的健康数据
  • 综合分析: 步数、心率、睡眠、运动、压力等多维度分析
  • 数据可视化: 交互式图表和仪表板展示健康数据趋势
  • 智能建议: 基于数据分析的个性化健康建议
  • 数据导出: 支持数据导出为 CSV/JSON 格式

🛠 技术栈

前端

  • React 18 + TypeScript
  • Recharts (数据可视化)
  • Tailwind CSS (样式)
  • Axios (API 请求)

后端

  • Python 3.10+ + Flask
  • Gunicorn生产运行
  • 可插拔数据层SQLite本地开发/ MariaDB生产运行于 NAS经 PyMySQL
  • JWT 鉴权 + scrypt 密码哈希
  • garminconnect可选Garmin API 集成)

注:原 Node/TypeScript 后端保留在 server/(仅 service 逻辑骨架); 当前可运行实现为 backend/ 下的 Python/Flask 单体服务。

📁 项目结构

GarminHealthLab/
├── client/                 # 前端应用 (React 18 + TypeScript)
│   └── src/services/api.ts # API 客户端(含 JWT 拦截器)
├── backend/                # 后端应用 (Python + Flask) —— 当前可运行实现
│   ├── app.py              # 应用工厂 / 路由装配
│   ├── wsgi.py             # Gunicorn 入口
│   ├── config.py           # 配置(读 .env
│   ├── db.py               # 可插拔数据层 (SQLite / MariaDB)
│   ├── auth.py             # scrypt + JWT + require_auth
│   ├── services/           # 业务逻辑 (health / analysis / garmin)
│   ├── routes/             # 蓝图 (auth / garmin / health / analysis)
│   ├── tests/smoke.py      # 冒烟测试
│   ├── requirements.txt
│   └── .env.example
├── server/                 # 原 Node/TS 后端(仅 service 骨架,未接入路由)
├── docs/                   # 文档
├── package.json           # 工作空间根配置
└── README.md

🚀 快速开始

前置要求

  • Node.js 18+
  • npm 或 yarn
  • Garmin Connect 账户

安装依赖

前端React

npm install

后端Python/Flask建议在虚拟环境中安装

cd backend
python -m venv venv && source venv/bin/activate
pip install -r requirements.txt

配置环境变量

复制 backend/.env.examplebackend/.env 并填入真实值(.env 已被 .gitignore 忽略,不会进入版本库):

PORT=5000
DB_TYPE=sqlite                       # 本地开发用 sqlite生产切 mariadb
DATABASE_PATH=./data/health.db
JWT_SECRET=your_jwt_secret_here      # 生产务必更换
CORS_ORIGIN=http://localhost:3000,http://localhost:5173

server/.env 的 Node 配置已弃用,请改用 backend/.env

数据库SQLite / MariaDB 可插拔

数据层通过 DB_TYPE 环境变量切换后端,业务代码无需改动

  • SQLite默认本地开发:零配置,由 DATABASE_PATH 指定文件位置。
  • MariaDB生产运行在 NAS 上):经 mysql2 连接,优先走 socketMARIADB_SOCKET),也可用 MARIADB_HOST + MARIADB_PORT

生产使用 NAS 上的独立库 garmin_health_lab(与 sentinel_home_ai 隔离)。完整配置见 backend/.env.example

DB_TYPE=mariadb
MARIADB_SOCKET=/run/mysqld/mysqld10.sock
MARIADB_USER=root
MARIADB_PASSWORD=your_nas_mariadb_root_password
MARIADB_DATABASE=garmin_health_lab

复制 backend/.env.examplebackend/.env 并填入真实值;.env 已被 .gitignore 忽略,不会进入版本库。

启动开发服务器

后端Flask端口 5000

cd backend
source venv/bin/activate
python app.py
# 或生产方式gunicorn wsgi:app -b 0.0.0.0:5000

前端Vite/React端口 3000 或 5173

npm run dev

冒烟测试

cd backend
python tests/smoke.py

📚 API 文档

认证

  • POST /api/auth/register - 用户注册email, garminEmail, garminPassword
  • POST /api/auth/login - 用户登录email, password
  • POST /api/auth/logout - 用户登出
  • POST /api/auth/refresh - 刷新 Token

Garmin 数据同步

  • POST /api/garmin/sync - 同步 Garmin 数据
  • GET /api/garmin/status - 获取同步状态

健康数据

  • GET /api/health/summary - 获取健康摘要
  • GET /api/health/steps - 获取步数数据
  • GET /api/health/heart-rate - 获取心率数据
  • GET /api/health/sleep - 获取睡眠数据
  • GET /api/health/activities - 获取运动数据

分析与建议

  • GET /api/analysis/trends - 获取数据趋势
  • GET /api/analysis/recommendations - 获取健康建议

🔐 安全说明

  • Garmin 账户密码使用加密存储
  • 所有 API 请求需要 JWT 认证
  • 敏感数据不在前端存储

📝 开发指南

详见 DEVELOPMENT.md

📄 许可证

MIT

Description
No description provided
Readme 9.5 MiB
Languages
JavaScript 61%
Python 22.2%
TypeScript 12.1%
CSS 4.1%
Shell 0.6%