116-基于Flask的健身房会员锻炼数据可视化分析系统

健身房会员锻炼数据可视化分析系统 -- 技术文档

目录

  • [1. 项目概述](#1. 项目概述)
  • [2. 技术栈与依赖](#2. 技术栈与依赖)
  • [3. 系统架构](#3. 系统架构)
  • [4. 配置系统](#4. 配置系统)
  • [5. 数据库设计](#5. 数据库设计)
  • [6. 功能模块详解](#6. 功能模块详解)
  • [7. 表单设计](#7. 表单设计)
  • [8. 前端技术](#8. 前端技术)
  • [9. 权限系统](#9. 权限系统)
  • [10. API接口](#10. API接口)
  • [11. 数据导入与导出](#11. 数据导入与导出)
  • [12. 错误处理](#12. 错误处理)
  • [13. 部署说明](#13. 部署说明)
  • [附录A: 数据库ER关系图(文字描述)](#附录A: 数据库ER关系图(文字描述))
  • [附录B: 模板文件清单](#附录B: 模板文件清单)

1. 项目概述

1.1 项目简介

本系统是一套基于 Flask 框架开发的健身房会员锻炼数据可视化分析系统。系统面向健身房管理者和教练团队,提供会员信息管理、锻炼记录跟踪、课程排期管理、数据分析与可视化等核心功能。系统采用经典的 MVC 架构模式,通过 Bootstrap 5 + ECharts 构建现代化的数据分析前端界面,后端使用 SQLAlchemy ORM 管理 MySQL 数据库。

1.2 核心业务场景

  1. 会员信息管理 -- 录入、编辑、查询、删除会员基本信息(姓名、性别、年龄、身高、体重、BMI、体脂率等)
  2. 锻炼记录管理 -- 记录会员每次锻炼的类型、时长、消耗卡路里、心率等数据
  3. 课程管理 -- 管理健身课程(瑜伽、力量训练、有氧等),安排课程时间表,处理会员报名
  4. 锻炼计划 -- 为会员制定个性化锻炼计划,包含多个锻炼项目
  5. 身体测量记录 -- 跟踪会员体围数据(胸围、腰围、臀围、上臂围、大腿围)变化
  6. 数据可视化分析 -- 提供仪表盘、趋势分析、分布分析、相关性分析等深度数据洞察
  7. 数据导入导出 -- 支持 CSV 格式的批量数据导入和导出
  8. 用户与权限管理 -- 基于角色的访问控制(RBAC),支持管理员和普通用户两种角色

1.3 项目目录结构

复制代码
code/
├── app/                          # 应用主包
│   ├── __init__.py               # 应用工厂函数 create_app()
│   ├── extensions.py             # Flask 扩展初始化
│   ├── decorators.py             # 权限装饰器
│   ├── models/                   # 数据模型层
│   │   ├── __init__.py           # 模型汇总导出
│   │   ├── user.py               # 用户、角色、权限模型
│   │   ├── member.py             # 会员、锻炼会话模型
│   │   ├── gym_member.py         # 健身房会员、身体测量模型
│   │   ├── activity.py           # 活动记录模型
│   │   ├── course.py             # 课程、课程安排、报名模型
│   │   └── workout.py            # 锻炼计划、锻炼记录、锻炼详情模型
│   ├── main/                     # 主业务蓝图
│   │   ├── __init__.py
│   │   ├── routes.py             # 主业务路由(约2050行)
│   │   └── forms.py              # 主业务表单
│   ├── auth/                     # 认证蓝图
│   │   ├── __init__.py
│   │   ├── routes.py             # 认证路由
│   │   ├── forms.py              # 认证表单
│   │   └── email.py              # 邮件发送功能
│   ├── api/                      # API蓝图
│   │   ├── __init__.py
│   │   ├── auth.py               # API认证(JWT)
│   │   ├── members.py            # 会员API
│   │   ├── analytics.py          # 分析API
│   │   └── errors.py             # API错误处理
│   ├── errors/                   # 错误处理蓝图
│   │   ├── __init__.py
│   │   └── handlers.py           # 全局错误处理器
│   └── templates/                # Jinja2 模板
│       ├── base.html             # 基础布局模板
│       ├── main/                 # 主业务模板(30+页面)
│       ├── auth/                 # 认证模板
│       ├── email/                # 邮件模板
│       └── errors/               # 错误页面
├── config.py                     # 多环境配置
├── run.py                        # 应用启动入口 + CLI命令
├── import_data.py                # 数据导入脚本
├── requirements.txt              # Python依赖清单
├── migrations/                   # Alembic数据库迁移
├── data/                         # 原始数据文件
├── uploads/                      # 用户上传文件
├── logs/                         # 应用日志
└── tests/                        # 单元测试



































2. 技术栈与依赖

2.1 核心框架

包名 版本 用途
Flask 3.0.0 Web应用框架
Flask-SQLAlchemy 3.1.1 SQLAlchemy ORM 集成
Flask-Migrate 4.0.5 Alembic 数据库迁移管理
Flask-Login 0.6.3 用户会话管理、登录状态维护
Flask-WTF 1.2.1 WTForms 表单集成、CSRF保护
Flask-Mail 0.9.1 邮件发送(密码重置、邮箱确认)
Flask-RESTful 0.3.10 RESTful API 构建
Flask-JWT-Extended 4.5.3 JWT 令牌认证
Flask-CORS 4.0.0 跨域资源共享
Flask-Moment 1.0.5 时间日期本地化显示
Flask-Bootstrap5 -- Bootstrap5 集成(通过 Bootstrap5 类)
Flask-Caching 2.1.0 缓存支持(simple/redis)

2.2 数据库

包名 版本 用途
SQLAlchemy 2.0.21 Python SQL工具包和ORM
PyMySQL 1.1.0 MySQL 纯Python驱动
mysqlclient 2.2.1 MySQL C语言驱动(备选)

2.3 表单与验证

包名 版本 用途
WTForms 3.0.1 表单渲染与验证
email-validator 2.1.0.post1 邮箱格式验证

2.4 安全与加密

包名 版本 用途
Werkzeug 3.0.1 密码哈希(generate_password_hash/check_password_hash)
PyJWT 2.8.0 JWT 令牌生成与验证
bcrypt 4.0.1 备用密码加密
cryptography 41.0.4 加密工具集

2.5 数据分析

包名 版本 用途
pandas 2.1.4 数据处理、CSV导入导出
numpy 1.26.3 数值计算、相关系数矩阵
scikit-learn 1.3.2 机器学习(预留)
scipy 1.11.3 科学计算

2.6 数据可视化

包名 版本 用途
matplotlib 3.7.2 静态图表生成
seaborn 0.12.2 统计可视化
plotly 5.16.1 交互式图表

2.7 文件处理

包名 版本 用途
openpyxl 3.1.2 Excel .xlsx 读写
xlrd 2.0.1 Excel .xls 读取
chardet 5.2.0 CSV编码自动检测
Pillow 10.2.0 头像图片处理(缩放、格式转换)
python-magic 0.4.27 文件MIME类型检测

2.8 运维与开发

包名 版本 用途
gunicorn 21.2.0 生产环境 WSGI 服务器
python-dotenv 1.0.0 .env 环境变量加载
requests 2.31.0 HTTP 请求
python-dateutil 2.8.2 日期时间增强
Faker 19.6.2 虚拟测试数据生成
pytest 7.4.4 测试框架
pytest-cov 4.1.0 测试覆盖率
pytest-flask 1.2.0 Flask测试工具
flake8 7.0.0 代码规范检查
black 23.12.1 代码格式化

3. 系统架构

3.1 应用工厂模式

系统采用 Flask 推荐的应用工厂模式(Application Factory Pattern),核心函数位于 app/__init__.py

python 复制代码
def create_app(config_name='default'):
    app = Flask(__name__)
    app.config.from_object(config[config_name])
    config[config_name].init_app(app)
    # 初始化9个扩展
    # 注册4个蓝图
    # 注册模板过滤器、全局变量
    # 健康检查端点
    # 数据库表创建
    return app

工厂函数执行流程:

  1. 创建 Flask 应用实例
  2. 根据 config_name 加载对应配置类(development/testing/production)
  3. 调用配置类的 init_app() 方法进行环境特定初始化
  4. 依次初始化 9 个 Flask 扩展:db, migrate, login_manager, mail, moment, cors, cache, jwt, bootstrap
  5. 注册 4 个蓝图(Blueprint):main, auth, api, errors
  6. 注册 Shell 上下文处理器(在 flask shell 中自动导入常用模型)
  7. 注册模板全局变量(app_name, app_version, Permission)
  8. 注册 4 个自定义模板过滤器(datetime, number, percentage, exercise_type_cn)
  9. 创建上传目录
  10. 创建健康检查路由 /health
  11. 在应用上下文中执行 db.create_all() 创建数据库表

3.2 蓝图划分

蓝图名称 URL前缀 模块文件 职责
main /(无前缀) app/main/ 核心业务:首页、仪表盘、会员管理、锻炼记录、课程管理、数据导入导出、备份、分析
auth /auth app/auth/ 用户认证:登录、注册、个人资料、密码管理、用户管理
api /api app/api/ RESTful API:JSON数据接口、JWT认证
errors 无(错误处理器) app/errors/ 全局HTTP错误处理:400/403/404/500

3.3 扩展初始化

扩展在 app/extensions.py 中统一声明,在工厂函数中统一初始化:

扩展 变量名 配置说明
SQLAlchemy db ORM引擎,支持连接池(pool_size=10)
Migrate migrate Alembic数据库迁移
LoginManager login_manager 登录视图指向 auth.login,未登录提示"请先登录以访问此页面"
Mail mail SMTP邮件服务
Moment moment 前端时间格式化
CORS cors 跨域支持
Cache cache 开发环境simple缓存,生产环境redis
JWTManager jwt JWT令牌管理
Bootstrap5 bootstrap Bootstrap5模板渲染

3.4 请求处理流水线

复制代码
HTTP请求 → Flask路由匹配 → before_app_request (更新last_seen)
  → 蓝图路由函数 → 权限装饰器检查 → 表单验证 → 业务逻辑
  → SQLAlchemy ORM操作 → 模板渲染/JSON响应 → 返回HTTP响应

before_app_request 钩子位于 app/auth/routes.py 末尾,每次请求前自动调用 current_user.ping() 更新用户的 last_seen 时间戳。


4. 配置系统

4.1 配置类层次

配置文件 config.py 定义了 4 个配置类,形成继承层次:

复制代码
Config (基类)
  ├── DevelopmentConfig  (开发环境)
  ├── TestingConfig      (测试环境)
  └── ProductionConfig   (生产环境)

4.2 基础配置(Config 类)

配置项 说明
SECRET_KEY 环境变量或 'dev-key-please-change-in-production' Flask会话密钥
SQLALCHEMY_DATABASE_URI 环境变量或 mysql://root:123456@localhost:3306/design_116_exercise 数据库连接URI
SQLALCHEMY_TRACK_MODIFICATIONS False 关闭修改跟踪以提升性能
SQLALCHEMY_RECORD_QUERIES True 记录SQL查询用于性能分析
SQLALCHEMY_ENGINE_OPTIONS pool_size=10, pool_recycle=3600, pool_pre_ping=True 连接池配置
POSTS_PER_PAGE 10 帖子/记录分页每页条数
USERS_PER_PAGE 15 用户列表分页
ITEMS_PER_PAGE 10 通用分页
MAIL_SERVER 环境变量或 smtp.gmail.com SMTP服务器
MAIL_PORT 环境变量或 587 SMTP端口
MAIL_USE_TLS true 启用TLS
MAX_CONTENT_LENGTH 16 * 1024 * 1024 (16MB) 上传文件大小限制
ALLOWED_EXTENSIONS txt, pdf, png, jpg, jpeg, gif, csv, xlsx 允许的文件类型
CACHE_TYPE simple 缓存类型
CACHE_DEFAULT_TIMEOUT 300 (5分钟) 默认缓存超时
JWT_SECRET_KEY 环境变量或 'jwt-secret-key' JWT签名密钥
JWT_ACCESS_TOKEN_EXPIRES timedelta(hours=1) JWT访问令牌1小时过期
JWT_REFRESH_TOKEN_EXPIRES timedelta(days=30) JWT刷新令牌30天过期
LANGUAGES ['zh', 'en'] 支持语言
TIMEZONE 'Asia/Shanghai' 时区
WTF_CSRF_ENABLED True 启用CSRF保护
WTF_CSRF_TIME_LIMIT 3600 (1小时) CSRF令牌有效期
DATA_ANALYSIS_CACHE_TIMEOUT 1800 (30分钟) 数据分析缓存
CHART_CACHE_TIMEOUT 600 (10分钟) 图表缓存

4.3 开发环境配置

  • DEBUG = True
  • SQLALCHEMY_ECHO = True(打印SQL语句)
  • 配置 RotatingFileHandler 写入 logs/gym_analysis.log(10MB轮转,保留10个备份)
  • 支持 LOG_TO_STDOUT 环境变量切换到标准输出

4.4 测试环境配置

  • TESTING = True
  • 使用 SQLite 内存数据库 sqlite:///:memory:
  • WTF_CSRF_ENABLED = False(禁用CSRF方便测试)
  • CACHE_TYPE = 'null'
  • MAIL_SUPPRESS_SEND = True(抑制邮件发送)

4.5 生产环境配置

  • DEBUG = False
  • 使用 mysql+pymysql 驱动 + charset=utf8mb4
  • CACHE_TYPE = 'redis',连接 redis://localhost:6379/0
  • 配置 SMTPHandler 发送错误邮件给管理员
  • RotatingFileHandler 记录日志

4.6 配置选择机制

python 复制代码
config_name = os.getenv('FLASK_CONFIG') or 'default'
app = create_app(config_name)

通过环境变量 FLASK_CONFIG 指定,未设置时默认使用 development 配置。


5. 数据库设计

5.1 数据库选择

默认使用 MySQL 8.x,数据库名 design_116_exercise,字符集 UTF-8。测试环境使用 SQLite 内存数据库。

5.2 模型总览

系统共定义 12 个数据库模型,分布在 6 个模型文件中:

模型类 数据库表名 所属文件 说明
Role roles user.py 角色表
Permission -- user.py 权限常量类(非数据库表)
User users user.py 系统用户表
Member members member.py 会员基础信息表
ExerciseSession exercise_sessions member.py 锻炼会话记录表
GymMember gym_members gym_member.py 健身房会员扩展表
BodyMeasurement body_measurements gym_member.py 身体测量记录表
Activity activities activity.py 活动日志表
Course courses course.py 健身课程表
CourseSchedule course_schedules course.py 课程安排表
CourseEnrollment course_enrollments course.py 课程报名表
WorkoutPlan workout_plans workout.py 锻炼计划表
WorkoutPlanExercise workout_plan_exercises workout.py 计划内运动项目表
WorkoutRecord workout_records workout.py 健身记录表
WorkoutDetail workout_details workout.py 锻炼详情表

5.3 各模型详细字段说明


5.3.1 Role(角色模型)

表名: roles

字段名 类型 约束 说明
id Integer PRIMARY KEY 角色ID,自增
name String(64) UNIQUE, NOT NULL, INDEX 角色名称(如"普通用户"、"管理员")
description Text NULLABLE 角色描述
permissions Integer DEFAULT 0 权限位掩码(位运算存储多个权限)
created_at DateTime DEFAULT utcnow 创建时间
updated_at DateTime DEFAULT utcnow, ON UPDATE 更新时间

关联关系:

  • users -> User(一对多,backref='role',lazy='dynamic')

预置角色:

  • 普通用户:权限 = VIEW(1)
  • 管理员:权限 = VIEW(1) + WRITE(2) + MODERATE(4) + ADMIN(8) + IMPORT(16) + EXPORT(32) + BACKUP(64) = 127

关键方法:

  • has_permission(permission) -- 位运算检查是否有指定权限
  • add_permission(permission) -- 添加权限位
  • remove_permission(permission) -- 移除权限位
  • reset_permissions() -- 重置为0
  • insert_roles() -- 静态方法,插入默认角色

5.3.2 Permission(权限常量)

注意: Permission 不是数据库模型,而是纯Python类,定义权限常量。

常量 二进制 说明
VIEW 1 0b0000001 查看权限
WRITE 2 0b0000010 写入权限
MODERATE 4 0b0000100 管理权限
ADMIN 8 0b0001000 管理员权限
IMPORT 16 0b0010000 导入权限
EXPORT 32 0b0100000 导出权限
BACKUP 64 0b1000000 备份权限

5.3.3 User(用户模型)

表名: users

字段名 类型 约束 说明
id Integer PRIMARY KEY 用户ID,自增
username String(64) UNIQUE, INDEX 用户名
email String(120) UNIQUE, INDEX 邮箱地址
password_hash String(128) -- 密码哈希值(Werkzeug生成)
is_active Boolean DEFAULT True 账户是否激活
is_administrator Boolean DEFAULT False 是否为管理员(快捷标记)
created_at DateTime DEFAULT utcnow 注册时间
last_login DateTime NULLABLE 最后登录时间(登录时自动更新)
real_name String(64) NULLABLE 真实姓名
phone String(20) NULLABLE 手机号码
avatar String(128) NULLABLE 头像文件名
bio Text NULLABLE 个人简介
confirmed Boolean DEFAULT False 邮箱是否已确认
last_seen DateTime DEFAULT utcnow 最后活跃时间
role_id Integer FOREIGN KEY -> roles.id 角色外键

继承: UserMixin(Flask-Login),db.Model

关联关系:

  • role -> Role(多对一,backref)
  • courses -> Course(一对多,教练关联,backref='courses')

关键方法:

方法 说明
set_password(password) 使用 Werkzeug 的 generate_password_hash 设置密码
check_password(password) 使用 check_password_hash 验证密码
is_admin() 返回 is_administrator 字段
can(permission) 检查用户角色是否有指定权限
ping() 更新 last_seen 为当前时间
get_reset_password_token(expires_in=600) 生成JWT密码重置令牌(默认10分钟有效)
verify_reset_password_token(token) 验证密码重置令牌
get_confirmation_token(expires_in=3600) 生成JWT邮箱确认令牌(默认1小时有效)
confirm(token) 验证邮箱确认令牌并设置 confirmed=True
to_dict(include_email=False) 序列化为字典(API用)
from_dict(data, new_user=False) 从字典反序列化更新
generate_fake(count=100) 生成虚拟用户数据(使用Faker)
get_avatar(size) 获取头像URL(自定义或Gravatar)
upload_avatar(file) 上传头像(检测MIME类型,Pillow处理缩放至200x200)

头像处理流程:

  1. 使用 python-magic 检测文件MIME类型,确保是图片
  2. 生成唯一文件名 avatar_{user_id}_{timestamp}.{ext}
  3. 使用 Pillow 打开图片
  4. RGBA/LA模式转RGB(白色背景)
  5. 缩放至 200x200(LANCZOS算法)
  6. 保存为 JPEG(quality=95, optimize=True)
  7. 删除旧头像文件
  8. 更新数据库 avatar 字段

5.3.4 Member(会员基础信息模型)

表名: members

字段名 类型 约束 说明
id Integer PRIMARY KEY 会员ID,自增
name String(100) NOT NULL 会员姓名
gender String(10) NOT NULL 性别('Male'/'Female')
birth_date Date NOT NULL 出生日期
phone String(20) NOT NULL 手机号码
email String(120) NULLABLE 邮箱地址
address String(200) NULLABLE 地址
height Float NULLABLE 身高(米)
weight Float NULLABLE 体重(公斤)
bmi Float NULLABLE BMI指数(weight/height^2)
fat_percentage Float NULLABLE 体脂率(%)
water_intake Float NULLABLE 每日饮水量(升)
workout_frequency Integer NULLABLE 每周锻炼次数
experience_level Integer NULLABLE 经验等级(1=初学者, 2=中级, 3=专家)
created_at DateTime DEFAULT utcnow 创建时间
updated_at DateTime DEFAULT utcnow, ON UPDATE 更新时间

关联关系:

  • sessions -> ExerciseSession(一对多,backref='member',lazy='dynamic')
  • gym_membership -> GymMember(一对一,backref='member',uselist=False)
  • activities -> Activity(一对多,backref='member',lazy='dynamic')
  • course_enrollments -> CourseEnrollment(一对多,backref='member',lazy='dynamic')

计算属性:

  • age -- 根据 birth_date 计算当前年龄(考虑月/日)

序列化方法: to_dict() 返回完整字段字典


5.3.5 ExerciseSession(锻炼会话记录模型)

表名: exercise_sessions

字段名 类型 约束 说明
id Integer PRIMARY KEY 记录ID,自增
member_id Integer FOREIGN KEY -> members.id 所属会员ID
date DateTime DEFAULT utcnow 锻炼日期时间
duration Integer NULLABLE 锻炼时长(分钟)
exercise_type String(50) NULLABLE 锻炼类型(Cardio/Strength/Yoga/HIIT/Swimming/Pilates/Other)
calories_burned Float NULLABLE 消耗卡路里(千卡)
heart_rate_avg Integer NULLABLE 平均心率(次/分钟)
max_heart_rate Integer NULLABLE 最大心率(次/分钟)
resting_heart_rate Integer NULLABLE 静息心率(次/分钟)
notes Text NULLABLE 备注
created_at DateTime DEFAULT utcnow 记录创建时间

关联关系:

  • member -> Member(多对一,backref)

锻炼类型枚举值:

英文值 中文名
Strength 力量训练
Cardio 有氧运动
Yoga 瑜伽
HIIT HIIT高强度间歇
Swimming 游泳
Pilates 普拉提
Other 其他

5.3.6 GymMember(健身房会员扩展模型)

表名: gym_members

字段名 类型 约束 说明
id Integer PRIMARY KEY 记录ID,自增
member_id Integer FOREIGN KEY -> members.id, NOT NULL 关联基础会员ID
membership_type String(50) NOT NULL 会员类型(普通会员/VIP会员等)
start_date DateTime NOT NULL 会员开始日期
end_date DateTime NOT NULL 会员到期日期
status String(20) NOT NULL 状态(active/expired/suspended)
created_at DateTime DEFAULT utcnow 创建时间
updated_at DateTime DEFAULT utcnow, ON UPDATE 更新时间

关联关系:

  • member -> Member(多对一,backref='gym_membership',uselist=False 一对一)
  • measurements -> BodyMeasurement(一对多,backref='member',lazy='dynamic')
  • workout_records -> WorkoutRecord(一对多,backref='member',lazy='dynamic')

计算属性:

  • bmi -- 根据 height 和 weight 计算BMI(注意:此处height单位为cm)
  • is_active -- 检查 end_date 是否 >= 当前日期
  • days_remaining -- 计算距离到期的剩余天数

5.3.7 BodyMeasurement(身体测量记录模型)

表名: body_measurements

字段名 类型 约束 说明
id Integer PRIMARY KEY 记录ID,自增
member_id Integer FOREIGN KEY -> gym_members.id, NOT NULL 所属会员ID
measurement_date Date NOT NULL 测量日期
weight Float NULLABLE 体重(kg)
body_fat Float NULLABLE 体脂率(%)
muscle_mass Float NULLABLE 肌肉量(kg)
chest Float NULLABLE 胸围(cm)
waist Float NULLABLE 腰围(cm)
hip Float NULLABLE 臀围(cm)
biceps Float NULLABLE 上臂围(cm)
thigh Float NULLABLE 大腿围(cm)
notes Text NULLABLE 备注
created_at DateTime DEFAULT utcnow 创建时间

关联关系:

  • member -> GymMember(多对一,backref='measurements',lazy='dynamic')

5.3.8 Activity(活动记录模型)

表名: activities

字段名 类型 约束 说明
id Integer PRIMARY KEY 活动ID,自增
member_id Integer FOREIGN KEY -> members.id, NULLABLE 关联会员ID(系统级操作如备份可为NULL)
activity_type String(50) NOT NULL 活动类型(workout/plan_created/backup/restore/delete_backup等)
description String(200) NULLABLE 活动描述
timestamp DateTime DEFAULT utcnow 活动发生时间
created_at DateTime DEFAULT utcnow 记录创建时间

关联关系:

  • member -> Member(多对一,backref='activities',lazy='dynamic')

关键方法:

方法 说明
log_activity(member_id, activity_type, description) 静态方法,记录活动日志并添加到会话
to_dict() 转换为字典格式

5.3.9 Course(健身课程模型)

表名: courses

字段名 类型 约束 说明
id Integer PRIMARY KEY 课程ID,自增
name String(100) NOT NULL 课程名称
description Text NULLABLE 课程描述
course_type String(50) NOT NULL 课程类型(团课/私教/体验课/其他)
duration Integer NOT NULL 课程时长(分钟)
max_capacity Integer NOT NULL 最大容纳人数
price Float NOT NULL 课程价格(元)
instructor_id Integer FOREIGN KEY -> users.id, NOT NULL 教练(用户)ID
created_at DateTime DEFAULT utcnow 创建时间
updated_at DateTime DEFAULT utcnow, ON UPDATE 更新时间

关联关系:

  • instructor -> User(多对一,backref='courses',lazy='joined',foreign_keys=[instructor_id])
  • schedules -> CourseSchedule(一对多,backref='course',lazy='dynamic')
  • enrollments -> CourseEnrollment(一对多,backref='course',lazy='dynamic')

计算属性:

  • current_enrollment_count -- 当前活跃报名人数
  • is_full -- 是否已满员

5.3.10 CourseSchedule(课程安排模型)

表名: course_schedules

字段名 类型 约束 说明
id Integer PRIMARY KEY 安排ID,自增
course_id Integer FOREIGN KEY -> courses.id, NOT NULL 所属课程ID
start_time DateTime NOT NULL 开始时间
end_time DateTime NOT NULL 结束时间
location String(100) NOT NULL 上课地点
status String(20) DEFAULT 'scheduled' 状态(scheduled/ongoing/completed/cancelled)
created_at DateTime DEFAULT utcnow 创建时间

关联关系:

  • course -> Course(多对一,backref)
  • enrollments -> CourseEnrollment(一对多,backref='schedule',lazy='dynamic')

5.3.11 CourseEnrollment(课程报名模型)

表名: course_enrollments

字段名 类型 约束 说明
id Integer PRIMARY KEY 报名ID,自增
course_id Integer FOREIGN KEY -> courses.id, NOT NULL 课程ID
member_id Integer FOREIGN KEY -> members.id, NOT NULL 会员ID
schedule_id Integer FOREIGN KEY -> course_schedules.id, NOT NULL 课程安排ID
status String(20) DEFAULT 'active' 状态(active/cancelled/completed)
enrollment_date DateTime DEFAULT utcnow 报名日期
created_at DateTime DEFAULT utcnow 创建时间

关联关系:

  • course -> Course(多对一,backref)
  • member -> Member(多对一,backref='course_enrollments',lazy='dynamic')
  • schedule -> CourseSchedule(多对一,backref='enrollments',lazy='dynamic')

5.3.12 WorkoutPlan(锻炼计划模型)

表名: workout_plans

字段名 类型 约束 说明
id Integer PRIMARY KEY 计划ID,自增
name String(100) NOT NULL 计划名称
description Text NULLABLE 计划描述
difficulty String(20) NULLABLE 难度级别(初级/中级/高级)
duration Integer NULLABLE 计划时长(天)
created_at DateTime DEFAULT utcnow 创建时间
updated_at DateTime DEFAULT utcnow, ON UPDATE 更新时间

关联关系:

  • exercises -> WorkoutPlanExercise(一对多,backref='plan',lazy='dynamic')

序列化方法: to_dict() 返回完整字段字典


5.3.13 WorkoutPlanExercise(锻炼计划运动项目模型)

表名: workout_plan_exercises

字段名 类型 约束 说明
id Integer PRIMARY KEY 项目ID,自增
plan_id Integer FOREIGN KEY -> workout_plans.id, NOT NULL 所属计划ID
exercise_name String(100) NOT NULL 运动名称
sets Integer NULLABLE 组数
reps Integer NULLABLE 每组次数
weight Float NULLABLE 重量(kg)
duration Integer NULLABLE 时长(秒)
rest_time Integer NULLABLE 休息时间(秒)
notes Text NULLABLE 备注
order Integer NULLABLE 顺序号
created_at DateTime DEFAULT utcnow 创建时间

关联关系:

  • plan -> WorkoutPlan(多对一,backref)

5.3.14 WorkoutRecord(健身记录模型)

表名: workout_records

字段名 类型 约束 说明
id Integer PRIMARY KEY 记录ID,自增
member_id Integer FOREIGN KEY -> gym_members.id, NOT NULL 所属会员ID
workout_date Date NOT NULL 锻炼日期
workout_type String(50) NOT NULL 锻炼类型
duration Integer NOT NULL 锻炼时长(分钟)
calories_burned Integer NULLABLE 消耗卡路里
heart_rate_avg Integer NULLABLE 平均心率
heart_rate_max Integer NULLABLE 最大心率
notes Text NULLABLE 备注
created_at DateTime DEFAULT utcnow 创建时间

关联关系:

  • member -> GymMember(多对一,backref='workout_records',lazy='dynamic')
  • details -> WorkoutDetail(一对多,backref='record',lazy='dynamic')

5.3.15 WorkoutDetail(锻炼详情模型)

表名: workout_details

字段名 类型 约束 说明
id Integer PRIMARY KEY 详情ID,自增
record_id Integer FOREIGN KEY -> workout_records.id, NOT NULL 所属健身记录ID
exercise_name String(50) NOT NULL 运动名称
sets Integer NULLABLE 组数
reps Integer NULLABLE 每组次数
weight Float NULLABLE 重量(kg)
duration Integer NULLABLE 时长(秒)
distance Float NULLABLE 距离(米)
created_at DateTime DEFAULT utcnow 创建时间

关联关系:

  • record -> WorkoutRecord(多对一,backref='details',lazy='dynamic')

5.4 模型关系图(文字描述)

复制代码
Role (1) ──────< User (N)
                   │
                   ├──< Course (N) [as instructor]
                   │       ├──< CourseSchedule (N)
                   │       │       └──< CourseEnrollment (N)
                   │       └──< CourseEnrollment (N)
                   │
Member (1) ──────< ExerciseSession (N)
   │    \
   │     ├──< Activity (N)
   │     ├──< CourseEnrollment (N)
   │     └── GymMember (1) [一对一]
   │              ├──< BodyMeasurement (N)
   │              └──< WorkoutRecord (N)
   │                       └──< WorkoutDetail (N)
   │
WorkoutPlan (1) ──< WorkoutPlanExercise (N)

6. 功能模块详解

6.1 主业务模块(main 蓝图)

主业务模块是系统的核心,包含约 2050 行路由代码,涵盖以下功能组:

6.1.1 首页与仪表盘
路由 方法 函数名 说明
//index GET index() 系统首页,显示基础统计(会员总数、锻炼总数、近7天数据、热门锻炼类型)
/dashboard GET dashboard() 数据仪表盘,支持 week/month/year 时间段切换,显示:会员增长趋势、年龄分布、锻炼趋势、运动类型分布、时段分布、活跃度热力图、最新动态

仪表盘数据统计指标:

  • 会员总数及变化率
  • 总锻炼人次及变化率
  • 平均锻炼时长及变化率
  • 会员活跃率及变化率

仪表盘图表类型:

  1. 会员增长趋势折线图(新增 + 累计)
  2. 会员年龄分布饼图(18-25/26-35/36-45/46-55/56+)
  3. 锻炼趋势折线图(人次 + 卡路里)
  4. 运动类型分布饼图
  5. 时段分布柱状图(6-9/9-12/12-15/15-18/18-21/21-24点)
  6. 活跃度热力图(周几 x 时段矩阵)
  7. 最新动态列表(锻炼记录 + 新会员注册)
6.1.2 会员管理
路由 方法 函数名 说明
/members GET members() 会员列表,支持搜索(姓名/电话/邮箱)、性别筛选、分页
/member/<id> GET member_detail(id) 会员详情,显示基本信息 + 最近5条锻炼记录
/member/<id>/edit GET/POST edit_member(id) 编辑会员信息,年龄转出生日期,自动计算BMI
/member/<id>/delete POST delete_member(id) 删除会员(级联删除锻炼记录)
/member/new GET/POST new_member() 添加新会员
6.1.3 锻炼记录管理
路由 方法 函数名 说明
/sessions GET sessions() 锻炼记录列表,支持按运动类型、会员、日期范围筛选
/session/<id> GET session_detail(id) 锻炼记录详情
/session/<id>/edit GET/POST edit_session(id) 编辑锻炼记录
/session/<id>/delete POST delete_session(id) 删除锻炼记录
/session/new GET/POST new_session() 添加新锻炼记录
/add_session GET/POST add_session() 添加锻炼记录(需要WRITE权限)
/member/<member_id>/workout/add GET/POST add_workout_record(member_id) 为指定会员添加锻炼记录
6.1.4 身体测量记录
路由 方法 函数名 说明
/member/<member_id>/measurement/add GET/POST add_body_measurement(member_id) 添加身体测量记录
/measurement/<id> GET body_measurement_detail(id) 测量记录详情
6.1.5 锻炼计划管理
路由 方法 函数名 说明
/member/<id>/plans GET workout_plans(id) 会员锻炼计划列表
/member/<id>/plan/add GET/POST add_workout_plan(id) 添加锻炼计划
/plan/<id> GET workout_plan_detail(id) 锻炼计划详情
/plan/<id>/edit GET/POST edit_workout_plan(id) 编辑锻炼计划
/plan/<id>/delete POST delete_workout_plan(id) 删除锻炼计划
/plan/<id>/exercise/add GET/POST add_workout_plan_exercise(id) 添加计划运动项目
/plan/exercise/<id>/edit GET/POST edit_workout_plan_exercise(id) 编辑计划运动项目
/plan/exercise/<id>/delete POST delete_workout_plan_exercise(id) 删除计划运动项目
6.1.6 课程管理
路由 方法 函数名 说明
/courses GET courses() 课程列表,支持按类型和教练筛选
/courses/add GET/POST add_course() 添加课程(需WRITE权限)
/courses/<id> GET course_detail(id) 课程详情
/courses/<id>/edit GET/POST edit_course(id) 编辑课程(需WRITE权限)
/courses/<id>/schedules GET course_schedules(id) 课程安排列表
/courses/<id>/schedules/add GET/POST add_course_schedule(id) 添加课程安排(需WRITE权限)
/courses/schedules/<id>/edit POST edit_course_schedule(id) 编辑课程安排
/courses/schedules/<id>/delete POST delete_course_schedule(id) 删除课程安排(检查是否有活跃报名)
/courses/<course_id>/enroll GET/POST enroll_course(course_id) 课程报名(检查容量和重复报名)
/courses/enrollments GET course_enrollments() 报名记录列表,支持按课程/会员/状态筛选
/courses/enrollments/<id>/cancel POST cancel_course_enrollment(id) 取消报名
/courses/enrollments/<id>/edit POST edit_course_enrollment(id) 编辑报名状态
/courses/enrollments/<id>/delete POST delete_course_enrollment(id) 删除报名记录
6.1.7 数据分析
路由 方法 函数名 说明
/analytics GET analytics() 深度数据分析页面,14种分析维度
/member/<id>/analytics GET member_analytics(id) 单会员数据分析
/workout/stats GET workout_stats() 锻炼统计页面
/api/chart_data GET chart_data() 图表数据API(gender/workout_types/monthly_trend)

深度分析(analytics)包含的14种分析:

  1. 性别分布(饼图)
  2. 运动类型分布(饼图)
  3. 运动类型按性别分组(分组柱状图)
  4. 各运动类型平均卡路里(柱状图)
  5. BMI分布(直方图,7个分桶:<15/15-18.5/18.5-25/25-30/30-35/35-40/40+)
  6. 体重分布(直方图,9个分桶:30-40/40-50/.../110+)
  7. 卡路里消耗分布(直方图,8个分桶)
  8. 散点图:体脂率 vs 卡路里(按运动类型着色)
  9. 散点图:锻炼时长 vs 卡路里(按运动类型着色)
  10. 散点图:体重 vs 卡路里(按经验等级着色)
  11. 散点图:BMI vs 卡路里
  12. 经验等级分布(饼图)
  13. 每周锻炼频率分布(饼图)
  14. 相关性热力图(11个数值变量的相关系数矩阵,使用numpy.corrcoef)

相关性热力图的11个变量: Age, Height, Weight, BMI, Fat%, Water, Duration, Calories, AvgHR, MaxHR, RestHR

6.1.8 数据导入导出
路由 方法 函数名 权限要求 说明
/data/import GET/POST import_data() IMPORT + 管理员 CSV数据导入
/data/export GET/POST export_data() EXPORT + 管理员 CSV数据导出
6.1.9 数据备份与恢复
路由 方法 函数名 权限要求 说明
/data/backup GET/POST backup_data() BACKUP 创建数据库备份(支持MySQL和SQLite)
/data/backup/list GET backup_list() BACKUP 备份文件列表
/data/backup/download/<filename> GET download_backup(filename) ADMIN 下载备份文件
/data/backup/restore/<filename> POST restore_backup(filename) ADMIN 从备份恢复数据
/data/backup/delete/<filename> POST delete_backup(filename) ADMIN 删除备份文件

备份实现说明:

  • 使用 sqlalchemy.make_url() 解析数据库连接字符串,替代字符串分割
  • MySQL 备份通过 subprocess.run 调用 mysqldump,以二进制模式捕获输出,返回码非零时抛出异常
  • SQLite 备份通过 shutil.copy2 复制数据库文件
  • 备份操作记录到 Activity 日志(member_id 为 NULL,属系统级操作)
6.1.10 数据搜索
路由 方法 函数名 说明
/data/search GET search_data() 统一搜索入口,支持 members 和 sessions 两种类型
6.1.11 辅助函数

main/routes.py 底部定义了大量辅助数据计算函数:

函数名 说明
calculate_change_rate(current, previous) 计算环比变化率(%)
calculate_active_rate(start_date, end_date) 计算活跃会员率
get_member_growth_data(start, end, fmt) 获取会员增长趋势数据
get_age_distribution() 获取年龄分布数据
get_workout_trend_data(start, end, fmt) 获取锻炼趋势数据
get_exercise_type_distribution(start, end) 获取运动类型分布(含中英文映射)
get_time_distribution(start, end) 获取时段分布数据
get_activity_heatmap(start, end) 获取活跃度热力图数据
get_member_activity_data(start, end) 获取会员活跃度数据
get_top_members(start, end, limit=10) 获取锻炼排行榜(按次数排序)
get_member_workout_trend(member, start, end) 获取单会员锻炼趋势
get_member_exercise_type_distribution(member, start, end) 获取单会员运动类型分布
get_member_calories_trend(member, start, end) 获取单会员卡路里趋势
get_member_heart_rate_trend(member, start, end) 获取单会员心率趋势

6.2 认证模块(auth 蓝图)

认证模块处理用户身份验证和个人信息管理。

路由 方法 函数名 说明
/auth/login GET/POST login() 用户登录(用户名+密码,支持"记住我",登录成功自动更新 last_login 时间戳)
/auth/logout GET logout() 用户登出
/auth/register GET/POST register() 用户注册
/auth/confirm/<token> GET confirm(token) 邮箱确认
/auth/confirm GET resend_confirmation() 重新发送确认邮件
/auth/profile GET profile() 查看个人资料
/auth/edit_profile GET/POST edit_profile() 编辑个人资料(含头像上传)
/auth/change_password GET/POST change_password() 修改密码
/auth/reset_password_request GET/POST reset_password_request() 请求重置密码(发送邮件)
/auth/reset_password/<token> GET/POST reset_password(token) 重置密码
/auth/users GET users() 用户列表(管理员功能,支持搜索)
/auth/user/<id> GET user(id) 查看用户详情(管理员或本人)
/auth/edit_user/<id> GET/POST edit_user(id) 编辑用户(管理员功能)
/auth/toggle_user_status/<id> GET toggle_user_status(id) 切换用户激活/禁用状态(管理员功能,不允许禁用自己)

6.3 API模块(api 蓝图)

API模块提供JSON格式的RESTful接口,通过JWT进行认证。

6.3.1 认证接口(api/auth.py)
路由 方法 说明
/api/auth/login POST API登录,返回JWT令牌和用户信息
/api/auth/profile GET 获取当前用户信息(需登录)
/api/auth/refresh POST 刷新JWT令牌

JWT令牌生成逻辑:

python 复制代码
payload = {
    'user_id': user.id,
    'username': user.username,
    'exp': datetime.utcnow() + JWT_ACCESS_TOKEN_EXPIRES  # 默认1小时
}
token = jwt.encode(payload, JWT_SECRET_KEY, algorithm='HS256')
6.3.2 会员接口(api/members.py)
路由 方法 说明 权限
/api/members GET 获取会员列表(分页、筛选) 登录
/api/members/<id> GET 获取单个会员详情 登录
/api/members POST 创建新会员 WRITE
/api/members/<id> PUT 更新会员信息 WRITE
/api/members/<id> DELETE 删除会员 MODERATE
/api/members/<id>/sessions GET 获取会员锻炼记录 登录
/api/sessions GET 获取锻炼记录列表 登录
/api/sessions POST 创建锻炼记录 WRITE
6.3.3 分析接口(api/analytics.py)
路由 方法 说明
/api/analytics/overview GET 总览数据(总会员、活跃会员、总锻炼、总卡路里、总时长)
/api/analytics/gender_distribution GET 性别分布
/api/analytics/age_distribution GET 年龄分布(18-24/25-34/35-44/45-54/55+)
/api/analytics/bmi_distribution GET BMI分布(偏瘦/正常/超重/肥胖)
/api/analytics/workout_types GET 锻炼类型统计
/api/analytics/monthly_trend GET 月度趋势
/api/analytics/member_stats/<member_id> GET 指定会员统计
6.3.4 课程API(内嵌于main/routes.py)
路由 方法 说明
/api/courses/<id>/schedules GET 获取课程未来安排(含可用名额)
/api/courses/stats GET 课程统计(类型分布、报名统计、教练课程数)
/api/chart_data?type=xxx GET 图表数据(gender/workout_types/monthly_trend)
6.3.5 API错误处理(api/errors.py)

提供标准化的JSON错误响应格式:

python 复制代码
{
    "error": "Bad Request",
    "message": "缺少必需字段: name"
}

支持的HTTP状态码:400(bad_request)、401(unauthorized)、403(forbidden)、404(not_found)、500(internal_server_error)


7. 表单设计

7.1 认证表单(app/auth/forms.py)

LoginForm -- 登录表单
字段 类型 验证规则 说明
username StringField DataRequired, Length(1,64) 用户名
password PasswordField DataRequired 密码
remember_me BooleanField -- 记住我
submit SubmitField -- 登录按钮
RegistrationForm -- 注册表单
字段 类型 验证规则 说明
username StringField DataRequired, Length(1,64), Regexp(字母开头,允许字母数字点下划线) 用户名
email StringField DataRequired, Length(1,64), Email 邮箱
real_name StringField Length(0,64) 真实姓名
password PasswordField DataRequired, Length(min=6) 密码
password2 PasswordField DataRequired, EqualTo('password') 确认密码
submit SubmitField -- 注册按钮

自定义验证: 验证用户名和邮箱唯一性

ChangePasswordForm -- 修改密码表单
字段 类型 验证规则
old_password PasswordField DataRequired
password PasswordField DataRequired, Length(8,128)
password2 PasswordField DataRequired, EqualTo('password')
PasswordResetRequestForm -- 密码重置请求表单
字段 类型 验证规则
email StringField DataRequired, Email
PasswordResetForm -- 密码重置表单
字段 类型 验证规则
password PasswordField DataRequired, Length(8,128)
password2 PasswordField DataRequired, EqualTo('password')
EditProfileForm -- 编辑个人资料表单
字段 类型 验证规则 说明
avatar FileField FileAllowed(['jpg','jpeg','png','gif']) 头像上传
real_name StringField Length(0,64) 真实姓名
phone StringField Length(0,20) 手机号码
bio TextAreaField Length(0,140) 个人简介
EditProfileAdminForm -- 管理员编辑用户表单
字段 类型 验证规则
username StringField DataRequired, Length(1,64)
email StringField DataRequired, Email
confirmed BooleanField --
real_name StringField Length(0,64)
phone StringField Length(0,20)
bio TextAreaField Length(0,140)

构造函数接收 user 参数用于唯一性验证(排除自身)


7.2 主业务表单(app/main/forms.py)

GymMemberForm -- 健身房会员表单
字段 类型 验证规则 说明
name StringField DataRequired, Length(1,64) 姓名
email StringField DataRequired, Email 邮箱
phone StringField Length(0,20) 手机号码
age IntegerField DataRequired, NumberRange(16,100) 年龄
gender SelectField DataRequired 性别(Male/Female)
weight FloatField DataRequired, NumberRange(30,300) 体重(kg)
height FloatField DataRequired, NumberRange(1.0,2.5) 身高(m)
fat_percentage FloatField Optional, NumberRange(5,50) 体脂率(%)
water_intake FloatField Optional, NumberRange(0.5,10) 日饮水量(升)
workout_frequency IntegerField DataRequired, NumberRange(1,7) 每周锻炼频率(天)
experience_level SelectField DataRequired, coerce=int 经验等级(1/2/3)
membership_type SelectField -- 会员类型
join_date DateField DataRequired, default=today 入会日期
is_active BooleanField default=True 是否活跃

构造参数: original_email -- 编辑时传入原邮箱,validate_email 仅在邮箱变更时检查唯一性,避免编辑保存时报"邮箱已被使用"。

WorkoutRecordForm -- 健身记录表单
字段 类型 验证规则 说明
member_id SelectField DataRequired, coerce=int 会员(下拉选择)
workout_date DateField DataRequired 锻炼日期
workout_type SelectField DataRequired 锻炼类型(7种)
duration IntegerField DataRequired, NumberRange(1,300) 锻炼时长(分钟)
calories_burned IntegerField Optional, NumberRange(0,2000) 消耗卡路里
heart_rate_avg IntegerField Optional, NumberRange(40,200) 平均心率
heart_rate_max IntegerField Optional, NumberRange(40,220) 最大心率
notes TextAreaField Optional 备注
WorkoutDetailForm -- 锻炼详情表单
字段 类型 验证规则
exercise_name StringField DataRequired, Length(max=50)
sets IntegerField Optional, NumberRange(1,20)
reps IntegerField Optional, NumberRange(1,100)
weight FloatField Optional, NumberRange(0,500)
duration IntegerField Optional, NumberRange(1,3600)
distance FloatField Optional, NumberRange(0,100000)
BodyMeasurementForm -- 身体测量记录表单
字段 类型 验证规则 说明
measurement_date DateField DataRequired 测量日期
weight FloatField Optional, NumberRange(30,200) 体重(kg)
body_fat FloatField Optional, NumberRange(3,50) 体脂率(%)
muscle_mass FloatField Optional, NumberRange(10,100) 肌肉量(kg)
chest FloatField Optional, NumberRange(50,150) 胸围(cm)
waist FloatField Optional, NumberRange(40,150) 腰围(cm)
hip FloatField Optional, NumberRange(50,150) 臀围(cm)
biceps FloatField Optional, NumberRange(20,50) 上臂围(cm)
thigh FloatField Optional, NumberRange(30,80) 大腿围(cm)
notes TextAreaField Optional 备注
WorkoutPlanForm -- 锻炼计划表单
字段 类型 验证规则
title StringField DataRequired, Length(max=100)
description TextAreaField --
start_date DateField DataRequired
end_date DateField DataRequired
status SelectField active/completed/cancelled
WorkoutPlanExerciseForm -- 锻炼计划项目表单
字段 类型 验证规则
exercise_type SelectField 9种运动类型
target_duration IntegerField DataRequired, NumberRange(min=1)
target_calories FloatField Optional, NumberRange(min=0)
target_heart_rate IntegerField Optional, NumberRange(40,220)
notes TextAreaField --
scheduled_date DateField DataRequired
status SelectField pending/completed/skipped
CourseForm -- 课程表单
字段 类型 验证规则
name StringField DataRequired, Length(max=100)
description TextAreaField Optional, Length(max=500)
course_type SelectField DataRequired(团课/私教/体验课/其他)
duration IntegerField DataRequired, NumberRange(10,300)
max_capacity IntegerField DataRequired, NumberRange(1,100)
price FloatField DataRequired, NumberRange(min=0)
instructor_id IntegerField DataRequired
CourseScheduleForm -- 课程安排表单
字段 类型 验证规则
course_id IntegerField DataRequired
start_time DateTimeField DataRequired, format='%Y-%m-%d %H:%M'
end_time DateTimeField DataRequired, format='%Y-%m-%d %H:%M'
location StringField DataRequired, Length(max=100)
status SelectField scheduled/ongoing/completed/cancelled
CourseEnrollmentForm -- 课程报名表单
字段 类型 验证规则
course_id IntegerField DataRequired
member_id IntegerField DataRequired
schedule_id IntegerField DataRequired
status SelectField active/cancelled
其他表单
  • SearchForm -- 搜索表单(query + data_type)
  • FilterForm -- 筛选表单(membership_type + status + date_from + date_to)
  • DataImportForm -- 数据导入表单(file + data_type)
  • DataExportForm -- 数据导出表单(data_type)
  • MemberForm -- 通用会员表单(含membership_type和start_date/end_date)
  • ExerciseSessionForm -- 锻炼会话表单

8. 前端技术

8.1 模板引擎

使用 Jinja2 模板引擎(Flask内置),采用模板继承机制:

  • base.html -- 基础布局模板,定义整体页面结构
  • 各子模板通过 {% extends "base.html" %} 继承,使用 {% block content %}{% block scripts %} 填充内容

8.2 CSS框架

Bootstrap 5.3.0 -- 通过CDN引入,提供响应式栅格系统和基础组件样式。

系统在 base.html 中定义了大量自定义CSS变量和组件样式,采用现代设计语言

CSS变量体系:

css 复制代码
:root {
    --primary: #0d9488;       /* 主色调(青绿色) */
    --primary-dark: #0f766e;
    --primary-light: #14b8a6;
    --secondary: #f97316;     /* 辅助色(橙色) */
    --accent: #0ea5e9;        /* 强调色(蓝色) */
    --success: #10b981;       /* 成功(绿色) */
    --warning: #f59e0b;       /* 警告(黄色) */
    --danger: #ef4444;        /* 危险(红色) */
    --radius: 12px;           /* 圆角 */
    --shadow-md: ...;         /* 阴影 */
    --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); /* 过渡动画 */
    --sidebar-width: 260px;   /* 侧边栏宽度 */
}

自定义组件类:

  • .sidebar -- 固定左侧导航栏,深绿色渐变背景
  • .card-modern -- 现代卡片组件,hover时上浮效果
  • .stat-card-modern -- 统计数据卡片,5种颜色主题
  • .table-modern -- 现代表格样式
  • .badge-modern -- 胶囊形标签
  • .form-control-modern -- 现代输入框
  • .alert-custom -- 自定义警告框,带左侧彩条

响应式设计:

  • @media (max-width: 992px) -- 侧边栏隐藏,显示汉堡菜单按钮
  • @media (max-width: 576px) -- 缩小内容区域内边距

8.3 JavaScript图表库

ECharts 5.4.0 -- 百度开源可视化库,通过CDN引入,用于绘制所有交互式图表。

仪表盘和分析页面使用ECharts渲染的图表类型:

  • 折线图(会员增长趋势、锻炼趋势、卡路里趋势、心率趋势)
  • 饼图(年龄分布、运动类型分布、性别分布、经验等级分布)
  • 柱状图(时段分布、BMI分布、体重分布、卡路里分布)
  • 散点图(体脂率vs卡路里、时长vs卡路里、体重vs卡路里、BMIvs卡路里)
  • 热力图(活跃度热力图、相关性矩阵)
  • 面积图(趋势数据)

8.4 图标库

Font Awesome 6.4.0 -- 通过CDN引入,提供丰富的矢量图标。

系统使用的主要图标:

  • fa-dumbbell -- 品牌图标
  • fa-home -- 首页
  • fa-chart-pie -- 仪表盘
  • fa-chart-bar -- 数据分析
  • fa-users -- 会员管理
  • fa-running -- 锻炼记录
  • fa-calendar-check -- 课程管理
  • fa-file-import/export -- 数据导入导出
  • fa-user-shield -- 用户管理
  • fa-database -- 数据备份

8.5 字体

Google Fonts -- Noto Sans SC -- 思源黑体,支持300-700多种字重,用于中文显示。

8.6 页面布局

采用左侧固定导航栏 + 右侧主内容区的经典后台布局:

  1. 侧边栏(Sidebar):

    • 品牌区域(图标 + 系统名称)
    • 导航菜单分组:主菜单 / 业务管理 / 数据工具 / 系统管理
    • 用户信息区(头像、用户名、角色标签、下拉菜单)
    • 移动端可折叠
    • 菜单可见性: "业务管理"(会员管理、锻炼记录、课程管理)和"数据工具"仅管理员可见;"系统管理"仅超级管理员可见
  2. 主内容区:

    • 顶部粘性Header栏(面包屑 + 用户标签 + 头像)
    • Flash消息区域(自动4秒消失)
    • 页面内容(各模板block)

8.7 模板文件清单

模板路径 说明
base.html 基础布局(侧边栏 + Header + 内容区)
main/index.html 系统首页
main/dashboard.html 数据仪表盘
main/analytics.html 深度数据分析
main/members.html 会员列表
main/member_detail.html 会员详情
main/edit_member.html 编辑/添加会员
main/new_member.html 新增会员
main/member_analytics.html 会员个人分析
main/sessions.html 锻炼记录列表
main/session_detail.html 锻炼记录详情
main/edit_session.html 编辑锻炼记录
main/new_session.html 新增锻炼记录
main/add_workout_record.html 添加健身记录
main/workout_stats.html 锻炼统计
main/workout_plans.html 锻炼计划列表
main/workout_plan_detail.html 锻炼计划详情
main/workout_plan_form.html 锻炼计划表单
main/workout_plan_exercise_form.html 计划项目表单
main/courses.html 课程列表
main/course_detail.html 课程详情
main/add_course.html 添加课程
main/edit_course.html 编辑课程
main/course_schedules.html 课程安排列表
main/add_course_schedule.html 添加课程安排
main/enroll_course.html 课程报名
main/course_enrollments.html 报名记录列表
main/import_data.html 数据导入
main/export_data.html 数据导出
main/backup_data.html 数据备份
main/backup_list.html 备份列表
auth/login.html 登录页面
auth/register.html 注册页面
auth/profile.html 个人资料
auth/edit_profile.html 编辑资料
auth/change_password.html 修改密码
auth/reset_password_request.html 请求重置密码
auth/reset_password.html 重置密码
auth/users.html 用户管理列表
auth/user.html 用户详情
auth/edit_user.html 编辑用户
email/confirm.html 邮箱确认邮件(HTML)
email/confirm.txt 邮箱确认邮件(纯文本)
errors/404.html 404错误页面

9. 权限系统

9.1 RBAC模型

系统采用基于角色的访问控制(Role-Based Access Control, RBAC)模型:

复制代码
用户(User) --[多对一]--> 角色(Role) --[包含]--> 权限(Permission)

9.2 权限位掩码机制

使用整数位运算存储和检查权限,每个权限占一个二进制位:

复制代码
权限值    二进制      含义
1        0000001    VIEW - 查看
2        0000010    WRITE - 写入
4        0000100    MODERATE - 管理
8        0001000    ADMIN - 管理员
16       0010000    IMPORT - 导入
32       0100000    EXPORT - 导出
64       1000000    BACKUP - 备份

检查权限:(permissions & permission) == permission

添加权限:permissions += permission

9.3 角色权限矩阵

角色 VIEW WRITE MODERATE ADMIN IMPORT EXPORT BACKUP 总值
普通用户 Y - - - - - - 1
管理员 Y Y Y Y Y Y Y 127

9.4 权限装饰器

定义在 app/decorators.py 中:

装饰器 检查权限 说明
@permission_required(permission) 自定义权限 通用权限检查
@admin_required Permission.ADMIN 管理员权限
@import_required Permission.IMPORT 导入权限
@export_required Permission.EXPORT 导出权限
@backup_required Permission.BACKUP 备份权限

装饰器工作流程:

  1. 检查 current_user.can(permission)
  2. 如果无权限,flash错误消息并重定向到首页
  3. 如果有权限,执行被装饰的函数

9.5 页面级权限控制

在模板中通过 Jinja2 条件判断控制导航菜单和操作按钮显示:

jinja2 复制代码
{% if current_user.is_admin() %}
    <!-- 业务管理菜单(会员管理、锻炼记录、课程管理) -->
    <!-- 数据工具菜单(数据导入、数据导出) -->
    <!-- 首页"添加会员""添加记录"按钮、快速操作面板 -->
{% endif %}

{% if current_user.is_administrator %}
    <!-- 系统管理菜单(用户管理、数据备份、角色管理) -->
{% endif %}

9.6 双重权限标识

系统同时使用两种管理员标识:

  1. User.is_administrator -- Boolean字段,快捷标记
  2. User.role.name == '管理员' -- 基于角色的权限系统

在不同场景下混合使用,如 current_user.is_admin() 检查布尔字段,current_user.can(Permission.WRITE) 检查角色权限位。


10. API接口

10.1 认证机制

API采用JWT(JSON Web Token)认证:

  1. 客户端通过 /api/auth/login 发送用户名和密码
  2. 服务端验证后返回JWT令牌
  3. 客户端在后续请求的Header中携带令牌:Authorization: Bearer <token>
  4. 令牌默认1小时过期
  5. 可通过 /api/auth/refresh 刷新令牌

10.2 通用响应格式

成功响应:

json 复制代码
{
    "id": 1,
    "username": "admin",
    "email": "admin@gym.com"
}

分页响应:

json 复制代码
{
    "members": [...],
    "total": 100,
    "pages": 5,
    "current_page": 1,
    "per_page": 20
}

错误响应:

json 复制代码
{
    "error": "Bad Request",
    "message": "缺少必需字段: name"
}

10.3 健康检查端点

复制代码
GET /health

返回:

json 复制代码
{
    "status": "healthy",
    "service": "健身房数据分析系统",
    "version": "1.0.0"
}

11. 数据导入与导出

11.1 CSV数据导入

支持两种数据类型的CSV导入:

会员数据(members):

  • 必填字段:name, gender, phone
  • 可选字段:email, height, weight, bmi
  • 最大10000行
  • 数值字段自动验证格式

锻炼记录(sessions):

  • 必填字段:member_id, date, exercise_type, duration, calories_burned
  • 可选字段:avg_heart_rate, max_heart_rate, notes
  • 验证member_id存在性
  • 导入时自动记录Activity日志

11.2 CSV数据导出

支持导出为CSV文件(UTF-8 with BOM编码,兼容Excel中文显示):

  • 会员数据导出: name, gender, age, phone, email, height, weight, bmi, fat_percentage, workout_frequency, experience_level, created_at
  • 锻炼记录导出: member_id, member_name, date, exercise_type, duration, calories_burned, avg_heart_rate, max_heart_rate, notes, created_at

11.3 批量数据导入脚本

import_data.py 脚本用于从 data/gym_members_data.csv 批量导入数据:

  1. 自动检测并添加新字段到已有表(ALTER TABLE)
  2. 确保数据库表存在(db.create_all())
  3. 读取CSV文件
  4. 为每条记录生成随机中文姓名和手机号
  5. 每个会员生成3-8条锻炼记录(日期分布在90天内)
  6. 每100条提交一次

12. 错误处理

12.1 全局HTTP错误处理

定义在 app/errors/handlers.py 中:

HTTP状态码 处理函数 模板 说明
400 bad_request_error() errors/400.html 请求错误
403 forbidden_error() errors/403.html 访问被拒绝
404 not_found_error() errors/404.html 页面未找到
500 internal_error() errors/500.html 服务器内部错误(自动回滚数据库事务)

12.2 API错误处理

app/api/errors.py 提供JSON格式的错误响应:

  • bad_request(message) -- 400
  • unauthorized(message) -- 401
  • forbidden(message) -- 403
  • not_found(message) -- 404
  • internal_server_error(message) -- 500

12.3 日志系统

  • 开发环境:RotatingFileHandler 写入 logs/gym_analysis.log(10MB轮转,10个备份)
  • 生产环境:额外配置 SMTPHandler 发送错误邮件给管理员
  • 日志格式:%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]

13. 部署说明

13.1 环境要求

  • Python 3.8+
  • MySQL 8.0+(或 SQLite 用于开发/测试)
  • Redis(生产环境缓存,可选)

13.2 安装步骤

bash 复制代码
# 1. 克隆项目
cd F:\code\116-基于Flask的健身房会员锻炼数据可视化分析系统\code

# 2. 创建虚拟环境
python -m venv venv
source venv/bin/activate  # Linux/Mac
# 或 venv\Scripts\activate  # Windows

# 3. 安装依赖
pip install -r requirements.txt

# 4. 配置环境变量(可选)
export FLASK_CONFIG=development
export SECRET_KEY=your-secret-key
export DATABASE_URL=mysql://user:password@localhost:3306/design_116_exercise

# 5. 初始化数据库
flask init-db

# 6. 导入测试数据(可选)
flask import-data
# 或使用独立脚本
python import_data.py

# 7. 启动开发服务器
python run.py
# 或
flask run --host=0.0.0.0 --port=5000

13.3 数据库初始化

flask init-db 命令执行以下操作:

  1. 创建所有数据库表
  2. 创建默认角色(管理员、普通用户)
  3. 创建默认管理员账户:admin / admin123
  4. 创建默认普通用户账户:user / user123

13.4 生产环境部署

bash 复制代码
# 使用 Gunicorn
gunicorn -w 4 -b 0.0.0.0:5000 "app:create_app('production')"

# 设置环境变量
export FLASK_CONFIG=production
export SECRET_KEY=<强随机密钥>
export DATABASE_URL=mysql+pymysql://user:password@localhost:3306/design_116_exercise?charset=utf8mb4
export REDIS_URL=redis://localhost:6379/0
export MAIL_SERVER=smtp.example.com
export MAIL_USERNAME=your-email
export MAIL_PASSWORD=your-password

13.5 CLI命令

命令 说明
flask init-db 初始化数据库、角色和默认用户
flask import-data 从CSV导入健身房数据
flask create-fake-data 创建50个虚拟会员和随机锻炼记录
flask test [--coverage] 运行单元测试(可选覆盖率报告)

13.6 数据库迁移

使用 Flask-Migrate(Alembic)管理数据库架构变更:

bash 复制代码
# 生成迁移脚本
flask db migrate -m "描述信息"

# 应用迁移
flask db upgrade

# 回滚迁移
flask db downgrade

迁移历史位于 migrations/versions/ 目录。

13.7 默认账户

用户名 密码 角色 说明
admin admin123 管理员 系统管理员,拥有所有权限
user user123 普通用户 普通用户,仅有查看权限

生产环境部署时务必修改默认密码和SECRET_KEY。


附录A: 数据库ER关系图

复制代码
┌──────────────┐     ┌──────────────┐     ┌──────────────────────┐
│    roles      │     │    users      │     │     courses           │
├──────────────┤     ├──────────────┤     ├──────────────────────┤
│ id (PK)      │◄────│ role_id (FK) │     │ id (PK)              │
│ name         │     │ id (PK)      │◄────│ instructor_id (FK)   │
│ description  │     │ username     │     │ name                 │
│ permissions  │     │ email        │     │ description          │
│ created_at   │     │ password_hash│     │ course_type          │
│ updated_at   │     │ is_active    │     │ duration             │
└──────────────┘     │ is_admin     │     │ max_capacity         │
                     │ real_name    │     │ price                │
                     │ phone        │     │ created_at           │
                     │ avatar       │     │ updated_at           │
                     │ bio          │     └──────────┬───────────┘
                     │ confirmed    │                │
                     │ last_seen    │     ┌──────────┴───────────┐
                     │ created_at   │     │  course_schedules     │
                     │ last_login   │     ├──────────────────────┤
                     └──────────────┘     │ id (PK)              │
                                          │ course_id (FK)       │
┌──────────────┐     ┌──────────────┐     │ start_time           │
│   members     │     │ gym_members   │     │ end_time             │
├──────────────┤     ├──────────────┤     │ location             │
│ id (PK)      │◄────│ member_id(FK)│     │ status               │
│ name         │     │ id (PK)      │     └──────────┬───────────┘
│ gender       │     │ membership   │                │
│ birth_date   │     │ start_date   │     ┌──────────┴───────────┐
│ phone        │     │ end_date     │     │ course_enrollments    │
│ email        │     │ status       │     ├──────────────────────┤
│ height       │     └──────┬───────┘     │ id (PK)              │
│ weight       │            │             │ course_id (FK)       │
│ bmi          │     ┌──────┴───────┐     │ member_id (FK)───────┤──┐
│ fat_percentage│    │body_measure- │     │ schedule_id (FK)     │  │
│ water_intake │     │   ments      │     │ status               │  │
│ workout_freq │     ├──────────────┤     │ enrollment_date      │  │
│ experience   │     │ id (PK)      │     └──────────────────────┘  │
│ created_at   │     │ member_id(FK)│                               │
│ updated_at   │     │ date         │     ┌──────────────────────┐  │
└──────┬───────┘     │ weight       │     │  workout_plans        │  │
       │             │ body_fat     │     ├──────────────────────┤  │
       │             │ muscle_mass  │     │ id (PK)              │  │
       │             │ chest/waist  │     │ name                 │  │
       │             │ hip/biceps   │     │ description          │  │
       │             │ thigh        │     │ difficulty           │  │
       │             └──────────────┘     │ duration             │  │
       │                                  └──────────┬───────────┘  │
┌──────┴───────┐     ┌──────────────┐                │              │
│  activities   │     │exercise_     │     ┌──────────┴───────────┐  │
├──────────────┤     │  sessions    │     │workout_plan_exercises │  │
│ id (PK)      │     ├──────────────┤     ├──────────────────────┤  │
│ member_id(FK)│     │ id (PK)      │     │ id (PK)              │  │
│ activity_type│     │ member_id(FK)│     │ plan_id (FK)         │  │
│ description  │     │ date         │     │ exercise_name        │  │
│ timestamp    │     │ duration     │     │ sets/reps/weight     │  │
│ created_at   │     │ exercise_type│     │ duration/rest_time   │  │
└──────────────┘     │ calories     │     │ notes/order          │  │
                     │ heart_rate_* │     └──────────────────────┘  │
                     │ notes        │                               │
                     └──────────────┘     ┌──────────────────────┐  │
                                          │  workout_records      │  │
                     ┌──────────────┐     ├──────────────────────┤  │
                     │workout_      │     │ id (PK)              │  │
                     │  details     │     │ member_id (FK)───────┤──┘
                     ├──────────────┤     │ workout_date         │
                     │ id (PK)      │     │ workout_type         │
                     │ record_id(FK)│◄────│ duration             │
                     │ exercise_name│     │ calories_burned      │
                     │ sets/reps    │     │ heart_rate_avg/max   │
                     │ weight/dur   │     │ notes                │
                     │ distance     │     └──────────────────────┘
                     └──────────────┘

附录B: 模板文件清单

共 44 个模板文件:

复制代码
templates/
├── base.html                              # 基础布局(侧边栏+Header)
├── auth/
│   ├── login.html                         # 登录页
│   ├── register.html                      # 注册页
│   ├── profile.html                       # 个人资料
│   ├── edit_profile.html                  # 编辑资料
│   ├── change_password.html               # 修改密码
│   ├── reset_password_request.html        # 请求重置密码
│   ├── reset_password.html                # 重置密码
│   ├── users.html                         # 用户管理列表
│   ├── user.html                          # 用户详情
│   └── edit_user.html                     # 编辑用户
├── main/
│   ├── index.html                         # 系统首页
│   ├── dashboard.html                     # 数据仪表盘
│   ├── analytics.html                     # 深度数据分析
│   ├── members.html                       # 会员列表
│   ├── member_detail.html                 # 会员详情
│   ├── member_analytics.html              # 会员个人分析
│   ├── edit_member.html                   # 编辑/添加会员
│   ├── new_member.html                    # 新增会员
│   ├── sessions.html                      # 锻炼记录列表
│   ├── session_detail.html                # 锻炼记录详情
│   ├── edit_session.html                  # 编辑锻炼记录
│   ├── new_session.html                   # 新增锻炼记录
│   ├── add_workout_record.html            # 添加健身记录
│   ├── workout_stats.html                 # 锻炼统计
│   ├── workout_plans.html                 # 锻炼计划列表
│   ├── workout_plan_detail.html           # 锻炼计划详情
│   ├── workout_plan_form.html             # 锻炼计划表单
│   ├── workout_plan_exercise_form.html    # 计划项目表单
│   ├── courses.html                       # 课程列表
│   ├── course_detail.html                 # 课程详情
│   ├── add_course.html                    # 添加课程
│   ├── edit_course.html                   # 编辑课程
│   ├── course_schedules.html              # 课程安排列表
│   ├── add_course_schedule.html           # 添加课程安排
│   ├── enroll_course.html                 # 课程报名
│   ├── course_enrollments.html            # 报名记录列表
│   ├── import_data.html                   # 数据导入
│   ├── export_data.html                   # 数据导出
│   ├── backup_data.html                   # 数据备份
│   └── backup_list.html                   # 备份列表
├── email/
│   ├── confirm.html                       # 邮箱确认(HTML)
│   └── confirm.txt                        # 邮箱确认(纯文本)
└── errors/
    └── 404.html                           # 404错误页面

文档版本:1.0.0
生成日期:2026年5月3日
系统名称:健身房会员锻炼数据可视化分析系统

相关推荐
wcy_10112 小时前
QCoder智能生成Excel数据清洗与可视化代码
python·excel
biyezuopinvip2 小时前
分布式风电场低电压穿越故障建模与仿真
分布式·matlab·毕业设计·毕业论文·分布式风电场·低电压穿越故障·建模与仿真
财经资讯数据_灵砚智能2 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(夜间-次晨)2026年5月2日
人工智能·python·信息可视化·自然语言处理·ai编程
skiy2 小时前
SpringBoot项目中读取resource目录下的文件(六种方法)
spring boot·python·pycharm
2601_956139422 小时前
集团品牌全案公司哪家专业
大数据·人工智能·python
ouliten2 小时前
[Triton笔记1]核心概念
笔记·python·深度学习·triton
清水白石0082 小时前
生成器不是性能银弹:什么时候该用 `yield` 省内存,什么时候它会拖慢 Python 数据处理吞吐?
开发语言·python·原型模式
李松桃2 小时前
Python爬虫-实战
爬虫·python
观无3 小时前
Python读取excel并形成api接口案例
python·pandas·fastapi