8. 健身记录App(technical-architecture)

alt

1. 架构设计

alt

2. 技术描述

  • 前端: React@18 + TypeScript + TailwindCSS@3 + Vite
  • 初始化工具: vite-init
  • 图表库: Recharts@2
  • 表单验证: React Hook Form + Zod
  • 状态管理: React Context + useReducer
  • 后端: Supabase (提供认证、数据库、存储服务)
  • UI组件库: HeadlessUI (可选,用于复杂组件)

3. 路由定义

路由 用途
/ 健身首页,展示训练概览和今日计划
/plans 训练计划页面,管理所有训练计划
/exercises 动作库页面,浏览和搜索训练动作
/record 记录训练页面,进行训练记录
/statistics 数据统计页面,查看训练数据分析
/diet 饮食记录页面,管理饮食信息
/profile 个人资料页面,管理用户信息
/login 登录页面
/register 注册页面

4. 数据模型

4.1 数据模型定义

alt

4.2 数据定义语言

用户表 (users)

-- 创建表
CREATE TABLE users (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  email VARCHAR(255) UNIQUE NOT NULL,
  name VARCHAR(100) NOT NULL,
  avatar_url TEXT,
  fitness_goal VARCHAR(50),
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- 创建索引
CREATE INDEX idx_users_email ON users(email);

训练计划表 (training_plans)

-- 创建表
CREATE TABLE training_plans (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES users(id) ON DELETE CASCADE,
  name VARCHAR(200) NOT NULL,
  description TEXT,
  duration_weeks INTEGER DEFAULT 4,
  difficulty VARCHAR(20) CHECK (difficulty IN ('beginner', 'intermediate', 'advanced')),
  is_active BOOLEAN DEFAULT true,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- 创建索引
CREATE INDEX idx_training_plans_user_id ON training_plans(user_id);
CREATE INDEX idx_training_plans_active ON training_plans(is_active);

动作表 (exercises)

-- 创建表
CREATE TABLE exercises (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name VARCHAR(200) NOT NULL,
  category VARCHAR(50) NOT NULL,
  muscle_group VARCHAR(100),
  equipment VARCHAR(100),
  description TEXT,
  video_url TEXT,
  image_url TEXT,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- 创建索引
CREATE INDEX idx_exercises_category ON exercises(category);
CREATE INDEX idx_exercises_muscle_group ON exercises(muscle_group);

训练记录表 (training_records)

-- 创建表
CREATE TABLE training_records (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES users(id) ON DELETE CASCADE,
  plan_id UUID REFERENCES training_plans(id) ON DELETE SET NULL,
  training_date DATE NOT NULL,
  total_sets INTEGER DEFAULT 0,
  total_reps INTEGER DEFAULT 0,
  total_weight FLOAT DEFAULT 0,
  duration_minutes INTEGER DEFAULT 0,
  notes TEXT,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- 创建索引
CREATE INDEX idx_training_records_user_id ON training_records(user_id);
CREATE INDEX idx_training_records_date ON training_records(training_date);

身体数据表 (body_data)

-- 创建表
CREATE TABLE body_data (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES users(id) ON DELETE CASCADE,
  record_date DATE NOT NULL,
  weight FLOAT,
  height FLOAT,
  body_fat_percentage FLOAT,
  muscle_mass FLOAT,
  notes TEXT,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  UNIQUE(user_id, record_date)
);

-- 创建索引
CREATE INDEX idx_body_data_user_id ON body_data(user_id);
CREATE INDEX idx_body_data_date ON body_data(record_date);

4.3 Supabase权限设置

-- 基本权限设置
GRANT SELECT ON exercises TO anon;
GRANT ALL PRIVILEGES ON exercises TO authenticated;

GRANT SELECT ON training_plans TO anon;
GRANT ALL PRIVILEGES ON training_plans TO authenticated;

GRANT SELECT ON training_records TO anon;
GRANT ALL PRIVILEGES ON training_records TO authenticated;

GRANT SELECT ON body_data TO anon;
GRANT ALL PRIVILEGES ON body_data TO authenticated;

-- RLS (Row Level Security) 策略
ALTER TABLE training_plans ENABLE ROW LEVEL SECURITY;
ALTER TABLE training_records ENABLE ROW LEVEL SECURITY;
ALTER TABLE body_data ENABLE ROW LEVEL SECURITY;

-- 用户只能查看和修改自己的数据
CREATE POLICY "用户只能查看自己的训练计划" ON training_plans
  FOR ALL USING (auth.uid() = user_id);

CREATE POLICY "用户只能查看自己的训练记录" ON training_records
  FOR ALL USING (auth.uid() = user_id);

CREATE POLICY "用户只能查看自己的身体数据" ON body_data
  FOR ALL USING (auth.uid() = user_id);

5. 前端架构设计

5.1 组件结构

src/
├── components/           # 通用组件
│   ├── common/          # 基础组件
│   │   ├── Button.tsx
│   │   ├── Card.tsx
│   │   ├── Input.tsx
│   │   └── Loading.tsx
│   ├── layout/          # 布局组件
│   │   ├── Header.tsx
│   │   ├── BottomNav.tsx
│   │   └── Layout.tsx
│   └── charts/          # 图表组件
│       ├── ProgressChart.tsx
│       ├── WeightChart.tsx
│       └── StatisticsChart.tsx
├── pages/               # 页面组件
│   ├── Home.tsx        # 健身首页
│   ├── Plans.tsx       # 训练计划
│   ├── Exercises.tsx   # 动作库
│   ├── Record.tsx      # 记录训练
│   ├── Statistics.tsx   # 数据统计
│   ├── Diet.tsx        # 饮食记录
│   └── Profile.tsx     # 个人资料
├── hooks/              # 自定义Hook
│   ├── useAuth.ts
│   ├── useTraining.ts
│   └── useStatistics.ts
├── context/            # 上下文管理
│   ├── AuthContext.tsx
│   └── TrainingContext.tsx
├── utils/              # 工具函数
│   ├── validation.ts   # 表单验证
│   ├── date.ts       # 日期处理
│   └── calculation.ts # 数据计算
└── types/              # TypeScript类型定义
    ├── user.ts
    ├── training.ts
    └── exercise.ts

5.2 状态管理

  • 认证状态: 使用React Context管理用户登录状态
  • 训练数据: 使用useReducer管理复杂的训练记录状态
  • UI状态: 使用useState管理组件级别的UI状态

5.3 表单验证

使用React Hook Form + Zod进行表单验证:

// 示例:训练记录表单验证
const trainingRecordSchema = z.object({
  exerciseId: z.string().uuid(),
  sets: z.array(z.object({
    reps: z.number().min(1).max(100),
    weight: z.number().min(0).max(500),
    isCompleted: z.boolean()
  })).min(1),
  notes: z.string().optional()
});

6. 性能优化

6.1 数据获取优化

  • 使用React Query进行数据缓存和同步
  • 实现分页加载,避免一次性加载大量数据
  • 使用Supabase的实时订阅功能,保持数据实时更新

6.2 组件优化

  • 使用React.memo进行组件记忆化
  • 实现虚拟滚动列表,优化长列表性能
  • 使用懒加载策略,按需加载页面和组件

6.3 图片优化

  • 使用WebP格式图片,减少加载时间
  • 实现图片懒加载,提升首屏加载速度
  • 使用CDN加速静态资源访问
20大项目拆解:从PRD到架构 文章被收录于专栏

想独立做出一个完整的项目却不知从何下手?本专栏是你的终极路线图。我们由浅入深,通过20个经典项目案例,手把手带你走过产品构思、需求撰写、功能设计、技术选型、架构搭建的全过程。从“音乐播放器”到“企业后台”,你将逐步建立对软件系统的完整认知,完成从理论到实践、从单一技能到复合能力的飞跃。

全部评论

相关推荐

点赞 评论 收藏
分享
10-22 19:44
门头沟学院 Java
面了100年面试不知...:那我得去剪个头
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务