Files
DDUp/README.md
lzh 4c22a137cf refactor: 管理员账号存储在数据库,生产环境使用宿主机目录存储数据
- 管理员账号在数据库初始化时创建,不再从环境变量读取
  - 默认账号: admin / admin123
  - 首次启动时自动创建,请在登录后修改密码
- 移除 ADMIN_USERNAME 和 ADMIN_PASSWORD 环境变量
- 生产环境 MySQL 数据直接存储在宿主机 /opt/vitals/mysql_data
  - 便于备份和恢复
  - 更直观的数据管理
- 更新部署指南,添加 MySQL 数据目录创建和备份说明
- 更新 .env.example 和 README.md 反映新的配置方式

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 21:16:32 +08:00

546 lines
18 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.

# Vitals
本地优先的综合健康管理应用,整合运动、饮食、睡眠、体重和阅读数据。
## 功能特性
### 健康数据追踪
- **运动记录** - 跑步、游泳、骑行、力量训练等,支持时长、距离、心率记录
- **饮食记录** - 三餐及加餐支持卡路里、蛋白质、碳水、脂肪追踪AI 智能识别食物
- **睡眠记录** - 入睡/起床时间、睡眠时长、睡眠质量评分
- **体重记录** - 体重、体脂率、肌肉量追踪
### 阅读习惯追踪
- **阅读记录** - 时长、书名、作者、封面(自动获取)、读后感
- **心情记录** - 5 种表情选择(😄😊😐😔😢)
- **我的书库** - 书籍封面网格展示,按书名归类
- **统计图表** - 阅读时长趋势、心情分布饼图
### 多用户与认证
- **用户档案** - 姓名、性别、身高、体重、年龄
- **BMI 计算** - 自动计算并显示健康状态(偏瘦/正常/偏胖/肥胖)
- **用户切换** - 支持多用户数据隔离
- **数据管理** - 按日期范围或数据类型清除数据
- **JWT 认证** - HTTPOnly Cookie + Authorization Header 混合认证
- **记住我** - 可选 1 天或 30 天登录有效期
- **邀请码注册** - 通过邀请码控制用户注册
- **管理员面板** - 用户管理、邀请码管理
### 数据管理
- **数据导出** - 支持 JSON/CSV 格式导出
- **数据导入** - 从 JSON 文件导入数据
- **自动备份** - 数据写入后自动备份
- **备份恢复** - 支持从备份文件恢复数据
### 提醒功能
- **定时提醒** - 体重、睡眠、运动、饮食提醒
- **系统通知** - 支持 macOS/Linux/Windows 系统通知
### 数据可视化
- **今日概览** - 运动、饮食、睡眠、体重、阅读汇总
- **本周报告** - 趋势分析和统计图表
- **详细报告** - 各项数据的深度分析
## 快速开始
### Docker 部署(推荐)
```bash
# 1. 复制环境变量模板
cp .env.example .env
# 2. 编辑 .env 文件,设置 JWT 密钥
vim .env
# 3. 启动服务
docker-compose up -d
# 4. 访问 http://localhost:8888
# 默认管理员账号: admin / admin123
```
### 本地开发
```bash
# 安装依赖
pip install -e .
# 设置 MySQL 环境变量
export MYSQL_HOST=localhost
export MYSQL_PORT=3306
export MYSQL_USER=vitals
export MYSQL_PASSWORD=your_password
export MYSQL_DATABASE=vitals
# 设置 JWT 密钥
export JWT_SECRET=$(openssl rand -hex 32)
# 启动服务
uvicorn vitals.web.app:app --host 0.0.0.0 --port 8080
```
访问 `http://localhost:8080` 即可使用 Web 界面。
> **注意**: 默认管理员账号为 `admin` / `admin123`,请在首次登录后及时修改密码。
### 页面导航
- `/` - 首页(今日概览)
- `/login` - 登录页面
- `/register` - 注册页面(需邀请码)
- `/admin` - 管理员面板
- `/exercise` - 运动记录
- `/meal` - 饮食记录
- `/sleep` - 睡眠记录
- `/weight` - 体重记录
- `/reading` - 阅读记录
- `/report` - 健康报告
- `/settings` - 设置页面
## API 接口
### 认证
| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/auth/login` | POST | 用户登录,返回 JWT Token + 设置 Cookie |
| `/api/auth/register` | POST | 用户注册(需邀请码) |
| `/api/auth/logout` | POST | 用户登出,清除 Cookie |
| `/api/auth/me` | GET | 获取当前用户信息 |
### 管理员
| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/admin/users` | GET | 获取所有用户列表 |
| `/api/admin/users/{id}/disable` | POST | 禁用用户 |
| `/api/admin/users/{id}/enable` | POST | 启用用户 |
| `/api/admin/users/{id}` | DELETE | 删除用户 |
| `/api/admin/invites` | GET | 获取邀请码列表 |
| `/api/admin/invites` | POST | 创建邀请码 |
| `/api/admin/invites/{id}` | DELETE | 删除邀请码 |
### 用户管理
| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/users` | GET | 获取所有用户 |
| `/api/users` | POST | 创建新用户 |
| `/api/users/active` | GET | 获取当前活跃用户 |
| `/api/users/{id}` | GET | 获取指定用户 |
| `/api/users/{id}` | PUT | 更新用户信息 |
| `/api/users/{id}` | DELETE | 删除用户 |
| `/api/users/{id}/activate` | POST | 设置活跃用户 |
### 数据管理
| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/data/preview-delete` | POST | 预览删除数量 |
| `/api/data/clear` | POST | 执行数据删除 |
### 运动
| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/exercises` | GET | 获取运动记录 |
| `/api/exercise` | POST | 添加运动记录 |
| `/api/exercise/{id}` | DELETE | 删除单条运动记录 |
| `/api/exercises/stats` | GET | 运动统计 |
### 饮食
| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/meals` | GET | 获取饮食记录 |
| `/api/meal` | POST | 添加饮食记录 |
| `/api/meal/{id}` | DELETE | 删除单条饮食记录 |
| `/api/meals/nutrition` | GET | 营养统计 |
| `/api/food/recognize` | POST | AI 识别食物 |
### 睡眠
| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/sleep` | GET | 获取睡眠记录 |
| `/api/sleep` | POST | 添加睡眠记录 |
| `/api/sleep/{id}` | DELETE | 删除单条睡眠记录 |
### 体重
| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/weight` | GET | 获取体重记录 |
| `/api/weight` | POST | 添加体重记录 |
| `/api/weight/{id}` | DELETE | 删除单条体重记录 |
### 阅读
| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/reading` | GET | 获取阅读记录(支持 ?days=N |
| `/api/reading` | POST | 添加阅读记录 |
| `/api/reading/{id}` | DELETE | 删除阅读记录 |
| `/api/reading/today` | GET | 今日阅读摘要 |
| `/api/reading/stats` | GET | 阅读统计 |
| `/api/books/search` | GET | 搜索书籍封面OpenLibrary |
### 汇总
| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/today` | GET | 今日概览 |
| `/api/week` | GET | 本周汇总 |
## 命令行使用
### 数据记录
```bash
# 记录体重
vitals log weight 72.5 --fat 18.5
# 记录饮食
vitals log meal 午餐 "燕麦+鸡蛋+牛奶"
# 记录睡眠
vitals log sleep 23:30 07:00 --quality 4
# 记录运动
vitals log exercise 跑步 30min --distance 5km
```
### 数据查看
```bash
# 查看今日概览
vitals show today
# 查看本周汇总
vitals show week
# 设置个人信息
vitals config set --age 28 --gender male --height 175 --weight 72
```
### 数据导出与导入
```bash
# 导出所有数据为 JSON
vitals export json ~/backup.json
# 导出运动数据为 CSV
vitals export csv --type exercise ~/exercise.csv
# 从 JSON 导入数据
vitals export import-json ~/backup.json
```
### 数据库备份
```bash
# 创建备份
vitals backup create
# 列出所有备份
vitals backup list
# 恢复备份
vitals backup restore ~/.vitals/backups/vitals_20260122_120000.db
# 清理旧备份(保留最近 7 天)
vitals backup cleanup --days 7
```
### 定时提醒
```bash
# 设置体重提醒(每天 07:00
vitals remind set weight --time 07:00
# 列出所有提醒
vitals remind list
# 禁用/启用提醒
vitals remind disable weight
vitals remind enable weight
# 测试系统通知
vitals remind test
# 设置定时任务macOS
vitals remind setup
```
## 安装
```bash
pip install -e .
```
## 环境变量
| 变量 | 必填 | 说明 |
|------|------|------|
| `MYSQL_HOST` | 是 | MySQL 服务器地址(默认 `localhost` |
| `MYSQL_PORT` | 否 | MySQL 端口(默认 `3306` |
| `MYSQL_USER` | 是 | MySQL 用户名 |
| `MYSQL_PASSWORD` | 是 | MySQL 密码 |
| `MYSQL_DATABASE` | 是 | MySQL 数据库名(默认 `vitals` |
| `MYSQL_ROOT_PASSWORD` | 是 | MySQL root 密码Docker 部署时需要) |
| `JWT_SECRET` | 是 | JWT 签名密钥(建议用 `openssl rand -hex 32` 生成) |
| `DASHSCOPE_API_KEY` | 否 | 阿里云通义千问 API Key用于 AI 食物识别 |
| `DEEPSEEK_API_KEY` | 否 | DeepSeek API Key用于 AI 食物识别 |
**默认管理员账号**: `admin` / `admin123`(请在首次登录后修改)
## 技术栈
- **后端**: Python, FastAPI, MySQL 8.0
- **前端**: HTML, CSS, JavaScript, Chart.js
- **认证**: JWT (PyJWT), bcrypt
- **部署**: Docker, Docker Compose
- **AI**: 阿里云通义千问 / DeepSeek (食物识别)
- **外部 API**: OpenLibrary (书籍封面搜索)
## 设计系统
| 元素 | 值 |
|------|------|
| Primary | `#3B82F6` |
| Secondary | `#60A5FA` |
| CTA | `#F97316` |
| Background | `#F8FAFC` |
| Text | `#1E293B` |
| Headings | Lora |
| Body | Raleway |
| Style | Vibrant & Block-based |
## 项目结构
```
vitals/
├── src/vitals/
│ ├── core/
│ │ ├── models.py # 数据模型User, Invite, Exercise, Meal...
│ │ ├── database.py # MySQL 数据库操作(连接池管理)
│ │ ├── auth.py # JWT 认证、密码哈希
│ │ ├── backup.py # 数据库备份
│ │ ├── export.py # 数据导出导入
│ │ ├── report.py # 健康报告生成
│ │ └── calories.py # 卡路里计算
│ ├── vision/
│ │ ├── analyzer.py # 食物识别分析器
│ │ └── providers/ # AI 提供商通义千问、DeepSeek
│ ├── importers/ # 数据导入器Garmin、Codoon、CSV
│ ├── web/
│ │ └── app.py # FastAPI 应用
│ └── cli.py # 命令行工具
├── scripts/
│ └── migrate_sqlite_to_mysql.py # SQLite 到 MySQL 迁移脚本
├── tests/ # 测试文件
├── docs/
│ ├── context/ # 开发上下文
│ └── plans/ # 设计文档
├── Dockerfile # Docker 镜像配置
├── docker-compose.yml # Docker Compose + MySQL 配置
├── .env.example # 环境变量模板
├── pyproject.toml # Python 项目配置
└── README.md
```
## 文档
### 部署文档
- [云服务器部署指南](docs/deployment-guide.md) - 详细的公网部署步骤
### 设计文档
- [Vitals 设计文档](docs/plans/2025-01-17-vitals-design.md)
- [设置页面实现计划](docs/plans/2026-01-19-settings-page-implementation.md)
- [阅读模块设计文档](docs/plans/2026-01-20-reading-module-design.md)
- [公网部署设计文档](docs/plans/2026-01-20-public-deployment-design.md)
- [开发任务清单](docs/plans/task.md)
## 开发进度
### 已完成功能 ✅
#### 核心数据追踪
- [x] **运动记录** - 类型、时长、距离、卡路里、心率追踪,支持 Garmin/Codoon/CSV 导入
- [x] **饮食记录** - 三餐+加餐,营养数据(卡路里/蛋白质/碳水/脂肪),照片上传
- [x] **睡眠记录** - 入睡/起床时间、时长、质量评分(1-5)、深睡时长
- [x] **体重记录** - 体重(kg)、体脂率(%)、肌肉量,趋势分析
- [x] **阅读记录** - 书名、作者、封面(自动获取)、时长、心情(5种表情)、读后感
#### 用户认证与管理
- [x] **JWT 认证** - 服务端认证 + Cookie支持 1 天/30 天过期
- [x] **密码安全** - bcrypt 哈希加密
- [x] **多用户支持** - 用户档案、数据隔离、用户切换
- [x] **邀请码注册** - 控制用户注册,支持有效期设置
- [x] **管理员面板** - 用户管理(启用/禁用/删除)、邀请码管理
#### Web 应用
- [x] **完整页面** - 登录、注册、管理员、首页、运动、饮食、睡眠、体重、阅读、报告、设置
- [x] **认证中间件** - 保护所有页面(登录/注册除外)
- [x] **REST API** - 40+ 个接口,完整的 CRUD 操作
- [x] **照片管理** - 饮食照片上传和静态文件服务
#### 数据管理
- [x] **数据导出** - JSON 和 CSV 格式
- [x] **数据导入** - JSON 文件导入(带验证)
- [x] **自动备份** - 数据写入后自动备份7 天保留策略
- [x] **备份恢复** - 从备份文件恢复数据
- [x] **数据清理** - 按日期范围或数据类型删除,支持预览
#### AI 集成
- [x] **食物识别** - 阿里通义千问(Qwen VL)、DeepSeek Vision、Claude Vision
- [x] **卡路里估算** - 基于食物描述的营养值计算
#### 数据导入器
- [x] **Garmin 导入** - 从 Garmin 设备导入运动数据
- [x] **Codoon 导入** - 支持咔豆运动数据导入
- [x] **CSV 导入** - 通用 CSV 导入(运动/饮食/睡眠/体重)
#### 报告与分析
- [x] **今日概览** - 所有健康指标汇总
- [x] **本周汇总** - 7 天趋势分析
- [x] **阅读统计** - 时长趋势、心情分布、书库展示
- [x] **图表展示** - 运动趋势、营养统计、睡眠热力图
#### CLI 工具
- [x] **数据记录** - `vitals log` 记录各类数据
- [x] **数据查看** - `vitals show` 显示汇总
- [x] **数据导出** - `vitals export` 导出 JSON/CSV
- [x] **数据备份** - `vitals backup` 管理备份
#### 部署
- [x] **Docker 支持** - Dockerfile + docker-compose.yml
- [x] **环境变量配置** - 灵活的配置管理
- [x] **健康检查** - Docker 容器健康检查
- [x] **MySQL 数据库** - MySQL 8.0 连接池,支持数据迁移
#### 移动端 H5 适配
- [x] **响应式布局** - 所有页面适配移动端屏幕768px/400px 断点)
- [x] **底部 Tab 导航** - 移动端专属底部导航栏,支持"更多"菜单
- [x] **触控优化** - 按钮和交互元素符合 44px/48px 触控标准
- [x] **iOS 安全区域** - 支持 iPhone 刘海屏和底部横条
- [x] **全页面适配** - 登录/注册、首页、运动、饮食、睡眠、体重、阅读、报告、设置、管理页面
### 待完善功能 🚧
#### 高优先级
- [ ] **提醒系统完善** - 定时提醒功能已有框架,但系统集成需要完善
- [ ] **数据编辑功能** - 目前仅支持删除,需要添加编辑已有记录的功能
- [ ] **错误处理优化** - 前端错误提示和异常处理需要更友好
#### 中优先级
- [ ] **月度报告** - PDF 报告生成功能(已有框架,需完善)
- [ ] **目标设定** - 运动目标、饮食目标、体重目标的设定和追踪
- [ ] **数据统计增强** - 更丰富的图表和趋势分析
- [x] **移动端优化** - 响应式设计改进,全部页面已适配移动端
- [ ] **离线支持** - PWA 支持,离线数据缓存
#### 低优先级
- [ ] **国际化(i18n)** - 多语言支持
- [ ] **云同步** - 跨设备数据同步
- [ ] **社交功能** - 数据分享、好友挑战
- [ ] **智能建议** - 基于数据的个性化健康建议
- [ ] **Apple Health 集成** - 与 Apple Health 数据同步
- [ ] **深色模式** - UI 深色主题支持
### 已知问题 🐛
- [ ] 大量数据时列表加载性能需优化
- [ ] 书籍封面搜索有时无法找到匹配结果
## 数据迁移
### 从 SQLite 迁移到 MySQL
如果你有旧版本的 SQLite 数据需要迁移,可以使用迁移脚本:
```bash
# 1. 确保 MySQL 服务已启动并配置好环境变量
export MYSQL_HOST=localhost
export MYSQL_PORT=3306
export MYSQL_USER=vitals
export MYSQL_PASSWORD=your_password
export MYSQL_DATABASE=vitals
# 2. 运行迁移脚本(默认从 ~/.vitals/vitals.db 读取)
python scripts/migrate_sqlite_to_mysql.py
# 或指定 SQLite 数据库路径
VITALS_DB_PATH=/path/to/old/vitals.db python scripts/migrate_sqlite_to_mysql.py
```
迁移脚本会自动处理:
- 用户数据users
- 运动记录exercise
- 饮食记录meal
- 睡眠记录sleep
- 体重记录weight
- 阅读记录reading
- 邀请码invites
- 配置数据config
## 更新日志
### 2026-01-23
#### 🗄️ MySQL 数据库迁移
- **数据库切换** - 从 SQLite 迁移到 MySQL 8.0
- **连接池支持** - 使用 MySQL 连接池管理,提升性能
- **Docker 集成** - docker-compose 自动配置 MySQL 服务
- **数据迁移脚本** - 提供 SQLite 到 MySQL 的数据迁移工具
- **类型兼容性修复** - 添加 `_parse_datetime``_parse_date``_parse_time` 辅助函数,处理 MySQL 返回原生类型
#### 🔒 用户权限增强
- **API 权限控制** - `/api/users` 非管理员仅返回自己,`/api/users/{id}` 非管理员只能查询自己(否则 403
- **导航栏隐藏** - 非管理员用户隐藏「管理」入口
#### 📱 移动端 H5 全页面适配
- **登录/注册页面** - 移动端布局优化,触摸目标符合标准
- **首页 Dashboard** - 卡片布局适配,底部导航栏
- **运动/饮食页面** - 表格转卡片列表,表单输入增大
- **睡眠/体重/阅读页面** - 响应式布局48px 输入框
- **报告页面** - 按钮触摸目标优化(48px),底部导航
- **设置页面** - 响应式布局,支持手机浏览
- **管理页面** - 表格改为卡片列表(data-label)
- **底部 Tab 导航** - 固定底部导航栏 + "更多"菜单
- **iOS 安全区域** - 支持刘海屏和底部横条
#### 🌐 网络访问
- **绑定地址优化** - 默认绑定 `0.0.0.0`,支持局域网访问和移动端真机测试
### 2026-01-22
#### 🔐 混合认证方案优化
- 修改 login/register API 使用 JSONResponse 正确设置 Cookie
- 添加 `path="/"` 确保 Cookie 在所有路径可用
- 前端同时使用 localStorage token 进行 API 认证
- 修复登录后闪屏返回登录页的问题
#### ✨ 登录功能全面升级
- **服务端认证中间件** - 未登录用户自动重定向到登录页
- **HTTPOnly Cookie** - 使用 HTTPOnly Cookie 存储 token比 localStorage 更安全)
- **"记住我"功能** - 勾选30 天有效期不勾选1 天有效期
- **登出 API** - 新增 `/api/auth/logout` 接口
- **登录后重定向** - 支持登录后返回原访问页面
#### 🎨 登录/注册页面 UI 升级
- 采用 **Neumorphism新拟态** 设计风格
- 健康主题配色(青色 + 绿色渐变)
- Lora + Raleway 字体组合
- 柔和阴影效果,提升视觉体验
### 历史版本
- **2026-01-20** - 阅读模块上线(书库、心情追踪、统计图表)
- **2026-01-19** - 设置页面重构(用户档案、数据管理)
- **2026-01-17** - 公网部署支持JWT 认证、邀请码、管理员面板)
- **2026-01-15** - 第一版发布(核心健康追踪功能)
## License
MIT