新增普拉提训练系统的数据库结构和数据导入功能

- 创建普拉提分类和动作数据的SQL导入脚本,支持垫上普拉提和器械普拉提的分类管理
- 实现数据库结构迁移脚本,添加新字段以支持普拉提类型和器械名称
- 更新数据库升级总结文档,详细说明数据库结构变更和数据导入步骤
- 创建训练会话相关表,支持每日训练实例功能
- 引入训练会话管理模块,整合训练计划与实际训练会话的关系
This commit is contained in:
richarjiang
2025-08-15 15:34:11 +08:00
parent bea71af5d3
commit 0edcfdcae9
28 changed files with 2528 additions and 164 deletions

View File

@@ -0,0 +1,121 @@
-- 普拉提分类和动作数据导入 SQL
-- 执行前请确保数据库表结构已更新
-- 清空现有数据(可选,根据实际情况决定是否执行)
-- DELETE FROM t_exercises;
-- DELETE FROM t_exercise_categories;
-- 插入普拉提分类数据
INSERT INTO t_exercise_categories (key, name, pilates_type, equipment_name, sort_order, created_at, updated_at) VALUES
-- 垫上普拉提
('mat_pilates', '垫上普拉提', 'mat_pilates', NULL, 1, NOW(), NOW()),
-- 器械普拉提
('reformer', '核心床', 'equipment_pilates', '核心床', 2, NOW(), NOW()),
('cadillac', '凯迪拉克', 'equipment_pilates', '凯迪拉克', 3, NOW(), NOW()),
('chair', '普拉提椅', 'equipment_pilates', '普拉提椅', 4, NOW(), NOW()),
('barrel', '普拉提桶', 'equipment_pilates', '普拉提桶', 5, NOW(), NOW());
-- 插入垫上普拉提动作数据
INSERT INTO t_exercises (
key, name, category_name, description, target_muscle_groups, equipment_name,
beginner_reps, beginner_sets, breathing_cycles, hold_duration, special_instructions,
category_key, sort_order, created_at, updated_at
) VALUES
('mat_hundred', '百次拍打', '垫上普拉提', '经典的普拉提动作,通过有节奏的手臂拍打配合呼吸来激活核心', '核心肌群、呼吸肌群、肩部稳定性', NULL, NULL, NULL, 10, NULL, '10个呼吸循环', 'mat_pilates', 1, NOW(), NOW()),
('mat_roll_up', '卷起', '垫上普拉提', '从仰卧位缓慢卷起至坐姿,锻炼脊柱逐节控制能力', '核心肌群、脊柱灵活性、腘绳肌柔韧性', NULL, 6, NULL, NULL, NULL, NULL, 'mat_pilates', 2, NOW(), NOW()),
('mat_single_leg_circle', '单腿画圈', '垫上普拉提', '单腿做圆周运动,保持骨盆稳定', '核心稳定性、髋关节灵活性、股四头肌、腘绳肌、臀肌', NULL, 5, NULL, NULL, NULL, '每条腿每个方向5次', 'mat_pilates', 3, NOW(), NOW()),
('mat_rolling_like_ball', '滚球', '垫上普拉提', '保持紧凑姿势前后滚动,挑战平衡和控制', '核心肌群、脊柱柔韧性、平衡感', NULL, 8, NULL, NULL, NULL, '6-8次', 'mat_pilates', 4, NOW(), NOW()),
('mat_single_leg_stretch', '单腿伸展', '垫上普拉提', '交替单腿伸展,保持上身抬起', '核心肌群、髋屈肌、股四头肌', NULL, 10, NULL, NULL, NULL, '每侧8-10次', 'mat_pilates', 5, NOW(), NOW()),
('mat_double_leg_stretch', '双腿伸展', '垫上普拉提', '双腿和手臂同时伸展,回到起始位置', '核心肌群、髋屈肌、股四头肌、肩部稳定性', NULL, 10, NULL, NULL, NULL, '6-10次', 'mat_pilates', 6, NOW(), NOW()),
('mat_spine_stretch', '脊柱伸展', '垫上普拉提', '坐姿前屈,逐节伸展脊柱', '脊柱柔韧性、腘绳肌伸展、核心控制', NULL, 6, NULL, NULL, NULL, NULL, 'mat_pilates', 7, NOW(), NOW()),
('mat_saw', '锯式', '垫上普拉提', '坐姿扭转配合前屈,增强脊柱旋转能力', '腹斜肌、背部伸肌、脊柱旋转灵活性', NULL, 6, NULL, NULL, NULL, '每侧6次', 'mat_pilates', 8, NOW(), NOW()),
('mat_swan', '天鹅式', '垫上普拉提', '俯卧位脊柱后伸,强化背部肌群', '背部伸肌、臀肌、腘绳肌', NULL, 6, NULL, NULL, NULL, NULL, 'mat_pilates', 9, NOW(), NOW()),
('mat_shoulder_bridge', '肩桥', '垫上普拉提', '仰卧抬臀,激活后链肌群', '臀肌、腘绳肌、下背部、脊柱灵活性', NULL, 6, NULL, NULL, NULL, NULL, 'mat_pilates', 10, NOW(), NOW());
-- 插入核心床(Reformer)动作数据
INSERT INTO t_exercises (
key, name, category_name, description, target_muscle_groups, equipment_name,
beginner_reps, beginner_sets, breathing_cycles, hold_duration, special_instructions,
category_key, sort_order, created_at, updated_at
) VALUES
('reformer_footwork', '脚部练习系列', '核心床', '在核心床上进行各种脚部位置的推蹬练习', '腿部、足部、核心稳定性', '核心床', 10, NULL, NULL, NULL, NULL, 'reformer', 1, NOW(), NOW()),
('reformer_hundred', '百次拍打', '核心床', '在核心床上进行百次拍打,增加阻力挑战', '核心肌群、呼吸肌群、上身耐力', '核心床', NULL, NULL, 10, NULL, '10个呼吸循环', 'reformer', 2, NOW(), NOW()),
('reformer_bridge', '桥式', '核心床', '在核心床上进行桥式动作,利用弹簧阻力', '臀肌、腘绳肌、脊柱关节', '核心床', 10, NULL, NULL, NULL, '6-10次', 'reformer', 3, NOW(), NOW()),
('reformer_straps', '脚套带练习', '核心床', '使用脚套带进行各种腿部和髋部练习', '髋部灵活性、骨盆稳定性、身体控制、内收肌', '核心床', 10, NULL, NULL, NULL, '8-10次', 'reformer', 4, NOW(), NOW()),
('reformer_elephant', '象式', '核心床', '四点跪撑位置进行推拉练习', '核心肌群、腘绳肌、背部伸肌、肩部稳定性', '核心床', 10, NULL, NULL, NULL, '8-10次', 'reformer', 5, NOW(), NOW()),
('reformer_knee_stretch', '跪姿伸展系列', '核心床', '跪姿位置进行多种伸展动作', '核心肌群、髋部灵活性、肩部控制', '核心床', 10, NULL, NULL, NULL, NULL, 'reformer', 6, NOW(), NOW());
-- 插入凯迪拉克(Cadillac)动作数据
INSERT INTO t_exercises (
key, name, category_name, description, target_muscle_groups, equipment_name,
beginner_reps, beginner_sets, breathing_cycles, hold_duration, special_instructions,
category_key, sort_order, created_at, updated_at
) VALUES
('cadillac_leg_springs', '腿部弹簧系列', '凯迪拉克', '使用腿部弹簧进行各种腿部强化练习', '腘绳肌、股四头肌、臀肌、髋屈肌、内收肌', '凯迪拉克', 20, NULL, NULL, NULL, '10-20次', 'cadillac', 1, NOW(), NOW()),
('cadillac_arm_springs', '手臂弹簧系列', '凯迪拉克', '使用手臂弹簧进行上身力量训练', '胸部、肩部、上背部、手臂', '凯迪拉克', 15, NULL, NULL, NULL, '10-15次', 'cadillac', 2, NOW(), NOW()),
('cadillac_roll_down_bar', '滚背杆卷下', '凯迪拉克', '使用滚背杆进行脊柱逐节控制练习', '腹部肌肉、脊柱灵活性', '凯迪拉克', 12, NULL, NULL, NULL, '8-12次', 'cadillac', 3, NOW(), NOW()),
('cadillac_push_through_bar', '推杆', '凯迪拉克', '推拉横杆进行全身协调练习', '肩部、核心、背部', '凯迪拉克', 12, NULL, NULL, NULL, '8-12次', 'cadillac', 4, NOW(), NOW());
-- 插入普拉提椅(Chair)动作数据
INSERT INTO t_exercises (
key, name, category_name, description, target_muscle_groups, equipment_name,
beginner_reps, beginner_sets, breathing_cycles, hold_duration, special_instructions,
category_key, sort_order, created_at, updated_at
) VALUES
('chair_seated_march', '坐姿行进', '普拉提椅', '坐在椅子上进行交替抬腿练习', '核心肌群、髋屈肌', '普拉提椅', 12, NULL, NULL, NULL, '每侧10-12次', 'chair', 1, NOW(), NOW()),
('chair_seated_leg_lift', '坐姿抬腿', '普拉提椅', '坐姿单腿伸展练习', '股四头肌、核心肌群', '普拉提椅', 12, NULL, NULL, NULL, '每侧10-12次', 'chair', 2, NOW(), NOW()),
('chair_seated_arm_circles', '坐姿手臂画圈', '普拉提椅', '坐姿手臂做圆周运动', '肩部、上背部、手臂', '普拉提椅', 12, NULL, NULL, NULL, '前后各10-12次', 'chair', 3, NOW(), NOW()),
('chair_spine_twist', '脊柱扭转', '普拉提椅', '坐姿脊柱旋转练习', '腹斜肌、脊柱旋转肌', '普拉提椅', 10, NULL, NULL, NULL, '每侧8-10次', 'chair', 4, NOW(), NOW()),
('chair_squat', '椅子深蹲', '普拉提椅', '使用椅子进行深蹲练习', '臀肌、股四头肌、腘绳肌、核心', '普拉提椅', 12, NULL, NULL, NULL, '10-12次', 'chair', 5, NOW(), NOW());
-- 插入普拉提桶(Barrel)动作数据
INSERT INTO t_exercises (
key, name, category_name, description, target_muscle_groups, equipment_name,
beginner_reps, beginner_sets, breathing_cycles, hold_duration, special_instructions,
category_key, sort_order, created_at, updated_at
) VALUES
('barrel_spine_stretch', '脊柱伸展', '普拉提桶', '在桶上进行脊柱后伸练习', '核心肌群、脊柱伸肌、背部肌肉', '普拉提桶', 12, 3, NULL, NULL, '10-12次2-3组', 'barrel', 1, NOW(), NOW()),
('barrel_mermaid', '美人鱼伸展', '普拉提桶', '侧坐在桶上进行侧向伸展', '核心肌群、腹斜肌、侧向柔韧性', '普拉提桶', 10, 3, NULL, NULL, '每侧8-10次2-3组', 'barrel', 2, NOW(), NOW()),
('barrel_side_bend', '侧弯', '普拉提桶', '侧卧在桶上进行侧向弯曲练习', '腹斜肌、腰部塑形、平衡感、核心稳定性', '普拉提桶', 10, 3, NULL, NULL, '每侧8-10次2-3组', 'barrel', 3, NOW(), NOW()),
('barrel_teaser_prep', '预备式Teaser', '普拉提桶', '在桶上进行Teaser动作的预备练习', '核心肌群、平衡感、本体感受', '普拉提桶', 5, 2, NULL, 3, '5次2组保持3秒', 'barrel', 4, NOW(), NOW()),
('barrel_swan_dive_prep', '预备式Swan Dive', '普拉提桶', '在桶上进行Swan Dive的预备练习', '背部伸肌、脊柱伸展、平衡感', '普拉提桶', 5, 2, NULL, 3, '5次2组保持3秒', 'barrel', 5, NOW(), NOW());
-- 提交事务
COMMIT;
-- 验证数据插入
SELECT
ec.name as category_name,
ec.pilates_type,
ec.equipment_name,
COUNT(e.key) as exercise_count
FROM t_exercise_categories ec
LEFT JOIN t_exercises e ON ec.key = e.category_key
GROUP BY ec.key, ec.name, ec.pilates_type, ec.equipment_name
ORDER BY ec.sort_order;

View File

@@ -0,0 +1,64 @@
-- 普拉提数据库结构迁移脚本
-- 此脚本用于将现有的数据库结构升级以支持新的普拉提分类和动作系统
-- 开始事务
BEGIN;
-- 1. 为分类表添加新字段
ALTER TABLE t_exercise_categories
ADD COLUMN pilates_type ENUM('mat_pilates', 'equipment_pilates') NOT NULL DEFAULT 'mat_pilates' COMMENT '普拉提类型:垫上普拉提或器械普拉提';
ALTER TABLE t_exercise_categories
ADD COLUMN equipment_name VARCHAR(255) NULL COMMENT '器械名称(仅器械普拉提需要)';
-- 2. 为动作表添加新字段
ALTER TABLE t_exercises
ADD COLUMN target_muscle_groups TEXT NOT NULL DEFAULT '' COMMENT '主要锻炼肌肉群';
ALTER TABLE t_exercises
ADD COLUMN equipment_name VARCHAR(255) NULL COMMENT '器械名称(器械普拉提专用)';
ALTER TABLE t_exercises
ADD COLUMN beginner_reps INTEGER NULL COMMENT '入门级别建议练习次数';
ALTER TABLE t_exercises
ADD COLUMN beginner_sets INTEGER NULL COMMENT '入门级别建议组数';
ALTER TABLE t_exercises
ADD COLUMN breathing_cycles INTEGER NULL COMMENT '呼吸循环次数(替代普通次数)';
ALTER TABLE t_exercises
ADD COLUMN hold_duration INTEGER NULL COMMENT '保持时间(秒)';
ALTER TABLE t_exercises
ADD COLUMN special_instructions VARCHAR(255) NULL COMMENT '特殊说明(如每侧、前后各等)';
-- 3. 修改现有字段属性
ALTER TABLE t_exercises
MODIFY COLUMN description TEXT NULL COMMENT '动作描述';
-- 提交事务
COMMIT;
-- 验证表结构
SELECT
COLUMN_NAME,
COLUMN_TYPE,
IS_NULLABLE,
COLUMN_DEFAULT,
COLUMN_COMMENT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 't_exercise_categories'
AND TABLE_SCHEMA = DATABASE()
ORDER BY ORDINAL_POSITION;
SELECT
COLUMN_NAME,
COLUMN_TYPE,
IS_NULLABLE,
COLUMN_DEFAULT,
COLUMN_COMMENT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 't_exercises'
AND TABLE_SCHEMA = DATABASE()
ORDER BY ORDINAL_POSITION;

View File

@@ -0,0 +1,135 @@
# 普拉提数据库设计升级总结
## 概述
根据完整的普拉提训练资料,对现有的训练分类和动作数据库设计进行了全面升级,以更好地支持垫上普拉提和器械普拉提的管理。
## 数据库结构变更
### 1. 分类表 (t_exercise_categories) 新增字段
| 字段名 | 类型 | 说明 |
|--------|------|------|
| `pilates_type` | ENUM('mat_pilates', 'equipment_pilates') | 普拉提类型:垫上普拉提或器械普拉提 |
| `equipment_name` | VARCHAR(255) | 器械名称(仅器械普拉提需要) |
### 2. 动作表 (t_exercises) 新增字段
| 字段名 | 类型 | 说明 |
|--------|------|------|
| `target_muscle_groups` | TEXT | 主要锻炼肌肉群 |
| `equipment_name` | VARCHAR(255) | 器械名称(器械普拉提专用) |
| `beginner_reps` | INTEGER | 入门级别建议练习次数 |
| `beginner_sets` | INTEGER | 入门级别建议组数 |
| `breathing_cycles` | INTEGER | 呼吸循环次数(替代普通次数) |
| `hold_duration` | INTEGER | 保持时间(秒) |
| `special_instructions` | VARCHAR(255) | 特殊说明(如每侧、前后各等) |
## 数据分类架构
### 垫上普拉提 (Mat Pilates)
- **分类**: 垫上普拉提
- **动作数量**: 10个经典动作
- **特点**: 无需器械,专注基础动作和呼吸控制
### 器械普拉提 (Equipment Pilates)
#### 1. 核心床 (Reformer)
- **动作数量**: 6个
- **主要功能**: 脚部练习、核心强化、全身协调
#### 2. 凯迪拉克 (Cadillac)
- **动作数量**: 4个
- **主要功能**: 弹簧阻力训练、上下肢力量、脊柱控制
#### 3. 普拉提椅 (Chair)
- **动作数量**: 5个
- **主要功能**: 坐姿训练、平衡挑战、功能性动作
#### 4. 普拉提桶 (Barrel)
- **动作数量**: 5个
- **主要功能**: 脊柱伸展、侧向柔韧性、平衡训练
## 数据导入内容
### 完整动作列表 (共30个动作)
#### 垫上普拉提动作
1. 百次拍打 - 核心肌群、呼吸肌群、肩部稳定性
2. 卷起 - 核心肌群、脊柱灵活性、腘绳肌柔韧性
3. 单腿画圈 - 核心稳定性、髋关节灵活性
4. 滚球 - 核心肌群、脊柱柔韧性、平衡感
5. 单腿伸展 - 核心肌群、髋屈肌、股四头肌
6. 双腿伸展 - 核心肌群、髋屈肌、股四头肌、肩部稳定性
7. 脊柱伸展 - 脊柱柔韧性、腘绳肌伸展、核心控制
8. 锯式 - 腹斜肌、背部伸肌、脊柱旋转灵活性
9. 天鹅式 - 背部伸肌、臀肌、腘绳肌
10. 肩桥 - 臀肌、腘绳肌、下背部、脊柱灵活性
#### 器械普拉提动作 (20个)
涵盖核心床、凯迪拉克、普拉提椅、普拉提桶四种器械的专业动作
## 数据特点
### 精准的训练参数
- **次数建议**: 针对入门级别的具体练习次数
- **组数设置**: 部分动作包含多组训练
- **呼吸循环**: 特殊动作使用呼吸循环替代次数
- **保持时间**: 静态动作的保持时长
- **特殊说明**: 详细的练习要求和注意事项
### 肌肉群定位
每个动作都明确标注主要锻炼的肌肉群,便于:
- 训练计划制定
- 肌肉群平衡分析
- 个性化推荐算法
## 文件清单
1. **pilates-database-migration.sql** - 数据库结构迁移脚本
2. **pilates-data-import.sql** - 完整数据导入脚本
3. **pilates-database-upgrade-summary.md** - 本总结文档
## 使用说明
### 1. 数据库升级步骤
```sql
-- 1. 执行结构迁移
source docs/pilates-database-migration.sql;
-- 2. 导入数据
source docs/pilates-data-import.sql;
```
### 2. 验证导入结果
```sql
-- 查看分类统计
SELECT
ec.name as category_name,
ec.pilates_type,
ec.equipment_name,
COUNT(e.key) as exercise_count
FROM t_exercise_categories ec
LEFT JOIN t_exercises e ON ec.key = e.category_key
GROUP BY ec.key, ec.name, ec.pilates_type, ec.equipment_name
ORDER BY ec.sort_order;
```
## 技术改进
### 1. 模型层更新
- 更新了 `ExerciseCategory``Exercise` 模型
- 添加新字段的 TypeScript 类型定义
- 保持向后兼容性
### 2. 服务层增强
- 更新 `ExercisesService` 以支持新字段
- 添加普拉提类型和器械名称的辅助方法
- 完善数据导入功能
### 3. DTO接口扩展
- 扩展 `ExerciseDto``ExerciseCategoryDto` 接口
- 添加训练参数相关字段
- 支持完整的普拉提训练信息
这次升级使数据库能够完整支持专业的普拉提训练管理,为后续的训练计划制定、进度跟踪和个性化推荐提供了坚实的数据基础。

View File

@@ -0,0 +1,247 @@
-- 普拉提训练系统完整表结构创建脚本
-- 执行前请确保删除旧表(注意删除顺序,避免外键约束错误)
-- 禁用外键检查(创建时)
SET FOREIGN_KEY_CHECKS = 0;
-- 删除现有表(如果存在)
DROP TABLE IF EXISTS `t_schedule_exercises`;
DROP TABLE IF EXISTS `t_training_plans`;
DROP TABLE IF EXISTS `t_exercises`;
DROP TABLE IF EXISTS `t_exercise_categories`;
-- 重新启用外键检查
SET FOREIGN_KEY_CHECKS = 1;
-- 创建分类表
CREATE TABLE `t_exercise_categories` (
`key` varchar(255) NOT NULL COMMENT '分类唯一键(英文/下划线)',
`name` varchar(255) NOT NULL COMMENT '分类中文名称',
`type` enum('mat_pilates','equipment_pilates') NOT NULL DEFAULT 'mat_pilates' COMMENT '普拉提类型:垫上普拉提或器械普拉提',
`equipment_name` varchar(255) DEFAULT NULL COMMENT '器械名称(仅器械普拉提需要)',
`sort_order` int NOT NULL DEFAULT '0' COMMENT '排序(升序)',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`key`),
KEY `idx_sort_order` (`sort_order`),
KEY `idx_type` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='普拉提训练分类表';
-- 创建动作表
CREATE TABLE `t_exercises` (
`key` varchar(255) NOT NULL COMMENT '动作唯一键(英文/下划线)',
`name` varchar(255) NOT NULL COMMENT '动作名称',
`category_name` varchar(255) NOT NULL COMMENT '中文分类名(冗余,便于展示)',
`description` text DEFAULT NULL COMMENT '动作描述',
`target_muscle_groups` text NOT NULL COMMENT '主要锻炼肌肉群',
`equipment_name` varchar(255) DEFAULT NULL COMMENT '器械名称(器械普拉提专用)',
`beginner_reps` int DEFAULT NULL COMMENT '入门级别建议练习次数',
`beginner_sets` int DEFAULT NULL COMMENT '入门级别建议组数',
`breathing_cycles` int DEFAULT NULL COMMENT '呼吸循环次数(替代普通次数)',
`hold_duration` int DEFAULT NULL COMMENT '保持时间(秒)',
`special_instructions` varchar(255) DEFAULT NULL COMMENT '特殊说明(如每侧、前后各等)',
`category_key` varchar(255) NOT NULL COMMENT '分类键',
`sort_order` int NOT NULL DEFAULT '0' COMMENT '排序(分类内)',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`key`),
KEY `idx_category_key` (`category_key`),
KEY `idx_sort_order` (`sort_order`),
KEY `idx_category_sort` (`category_key`, `sort_order`),
KEY `idx_equipment_name` (`equipment_name`),
CONSTRAINT `fk_exercises_category` FOREIGN KEY (`category_key`) REFERENCES `t_exercise_categories` (`key`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='普拉提训练动作表';
-- 创建训练计划表
CREATE TABLE `t_training_plans` (
`id` char(36) NOT NULL COMMENT '训练计划唯一ID',
`is_active` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否激活',
`user_id` varchar(255) NOT NULL COMMENT '用户ID',
`name` varchar(255) DEFAULT NULL COMMENT '计划名称',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`start_date` datetime NOT NULL COMMENT '开始日期',
`mode` enum('daysOfWeek','sessionsPerWeek') NOT NULL COMMENT '计划模式',
`days_of_week` json NOT NULL COMMENT '周几训练0-6',
`sessions_per_week` int NOT NULL COMMENT '每周训练次数',
`goal` enum('postpartum_recovery','fat_loss','posture_correction','core_strength','flexibility','rehab','stress_relief','') NOT NULL COMMENT '训练目标',
`start_weight_kg` float DEFAULT NULL COMMENT '起始体重(公斤)',
`preferred_time_of_day` enum('morning','noon','evening','') NOT NULL DEFAULT '' COMMENT '偏好训练时间',
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否已删除',
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_is_active` (`is_active`),
KEY `idx_deleted` (`deleted`),
KEY `idx_user_active` (`user_id`, `is_active`, `deleted`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='训练计划表';
-- 创建训练计划动作表
CREATE TABLE `t_schedule_exercises` (
`id` char(36) NOT NULL COMMENT '计划动作唯一ID',
`training_plan_id` char(36) NOT NULL COMMENT '训练计划ID',
`user_id` varchar(255) NOT NULL COMMENT '用户ID',
`exercise_key` varchar(255) DEFAULT NULL COMMENT '关联的动作key仅exercise类型',
`name` varchar(255) NOT NULL COMMENT '项目名称',
`sets` int DEFAULT NULL COMMENT '组数',
`reps` int DEFAULT NULL COMMENT '重复次数',
`duration_sec` int DEFAULT NULL COMMENT '持续时长(秒)',
`rest_sec` int DEFAULT NULL COMMENT '休息时长(秒)',
`note` text DEFAULT NULL COMMENT '备注',
`item_type` enum('exercise','rest','note') NOT NULL DEFAULT 'exercise' COMMENT '项目类型',
`completed` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否已完成',
`sort_order` int NOT NULL COMMENT '排序顺序',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否已删除',
PRIMARY KEY (`id`),
KEY `idx_training_plan_id` (`training_plan_id`),
KEY `idx_exercise_key` (`exercise_key`),
KEY `idx_user_id` (`user_id`),
KEY `idx_sort_order` (`sort_order`),
KEY `idx_item_type` (`item_type`),
KEY `idx_plan_sort` (`training_plan_id`, `sort_order`),
CONSTRAINT `fk_schedule_exercises_training_plan` FOREIGN KEY (`training_plan_id`) REFERENCES `t_training_plans` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_schedule_exercises_exercise` FOREIGN KEY (`exercise_key`) REFERENCES `t_exercises` (`key`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='训练计划动作表';
-- 创建索引以优化查询性能
-- 分类表索引已在建表时创建
-- 动作表额外索引
CREATE INDEX `idx_target_muscle_groups` ON `t_exercises` (`target_muscle_groups`(100));
-- 插入初始数据
-- 插入普拉提分类数据
INSERT INTO `t_exercise_categories` (`key`, `name`, `type`, `equipment_name`, `sort_order`, `created_at`, `updated_at`) VALUES
-- 垫上普拉提
('mat_pilates', '垫上普拉提', 'mat_pilates', NULL, 1, NOW(), NOW()),
-- 器械普拉提
('reformer', '核心床', 'equipment_pilates', '核心床', 2, NOW(), NOW()),
('cadillac', '凯迪拉克', 'equipment_pilates', '凯迪拉克', 3, NOW(), NOW()),
('chair', '普拉提椅', 'equipment_pilates', '普拉提椅', 4, NOW(), NOW()),
('barrel', '普拉提桶', 'equipment_pilates', '普拉提桶', 5, NOW(), NOW());
-- 插入垫上普拉提动作数据
INSERT INTO `t_exercises` (
`key`, `name`, `category_name`, `description`, `target_muscle_groups`, `equipment_name`,
`beginner_reps`, `beginner_sets`, `breathing_cycles`, `hold_duration`, `special_instructions`,
`category_key`, `sort_order`, `created_at`, `updated_at`
) VALUES
('mat_hundred', '百次拍打', '垫上普拉提', '经典的普拉提动作,通过有节奏的手臂拍打配合呼吸来激活核心', '核心肌群、呼吸肌群、肩部稳定性', NULL, NULL, NULL, 10, NULL, '10个呼吸循环', 'mat_pilates', 1, NOW(), NOW()),
('mat_roll_up', '卷起', '垫上普拉提', '从仰卧位缓慢卷起至坐姿,锻炼脊柱逐节控制能力', '核心肌群、脊柱灵活性、腘绳肌柔韧性', NULL, 6, NULL, NULL, NULL, NULL, 'mat_pilates', 2, NOW(), NOW()),
('mat_single_leg_circle', '单腿画圈', '垫上普拉提', '单腿做圆周运动,保持骨盆稳定', '核心稳定性、髋关节灵活性、股四头肌、腘绳肌、臀肌', NULL, 5, NULL, NULL, NULL, '每条腿每个方向5次', 'mat_pilates', 3, NOW(), NOW()),
('mat_rolling_like_ball', '滚球', '垫上普拉提', '保持紧凑姿势前后滚动,挑战平衡和控制', '核心肌群、脊柱柔韧性、平衡感', NULL, 8, NULL, NULL, NULL, '6-8次', 'mat_pilates', 4, NOW(), NOW()),
('mat_single_leg_stretch', '单腿伸展', '垫上普拉提', '交替单腿伸展,保持上身抬起', '核心肌群、髋屈肌、股四头肌', NULL, 10, NULL, NULL, NULL, '每侧8-10次', 'mat_pilates', 5, NOW(), NOW()),
('mat_double_leg_stretch', '双腿伸展', '垫上普拉提', '双腿和手臂同时伸展,回到起始位置', '核心肌群、髋屈肌、股四头肌、肩部稳定性', NULL, 10, NULL, NULL, NULL, '6-10次', 'mat_pilates', 6, NOW(), NOW()),
('mat_spine_stretch', '脊柱伸展', '垫上普拉提', '坐姿前屈,逐节伸展脊柱', '脊柱柔韧性、腘绳肌伸展、核心控制', NULL, 6, NULL, NULL, NULL, NULL, 'mat_pilates', 7, NOW(), NOW()),
('mat_saw', '锯式', '垫上普拉提', '坐姿扭转配合前屈,增强脊柱旋转能力', '腹斜肌、背部伸肌、脊柱旋转灵活性', NULL, 6, NULL, NULL, NULL, '每侧6次', 'mat_pilates', 8, NOW(), NOW()),
('mat_swan', '天鹅式', '垫上普拉提', '俯卧位脊柱后伸,强化背部肌群', '背部伸肌、臀肌、腘绳肌', NULL, 6, NULL, NULL, NULL, NULL, 'mat_pilates', 9, NOW(), NOW()),
('mat_shoulder_bridge', '肩桥', '垫上普拉提', '仰卧抬臀,激活后链肌群', '臀肌、腘绳肌、下背部、脊柱灵活性', NULL, 6, NULL, NULL, NULL, NULL, 'mat_pilates', 10, NOW(), NOW());
-- 插入核心床(Reformer)动作数据
INSERT INTO `t_exercises` (
`key`, `name`, `category_name`, `description`, `target_muscle_groups`, `equipment_name`,
`beginner_reps`, `beginner_sets`, `breathing_cycles`, `hold_duration`, `special_instructions`,
`category_key`, `sort_order`, `created_at`, `updated_at`
) VALUES
('reformer_footwork', '脚部练习系列', '核心床', '在核心床上进行各种脚部位置的推蹬练习', '腿部、足部、核心稳定性', '核心床', 10, NULL, NULL, NULL, NULL, 'reformer', 1, NOW(), NOW()),
('reformer_hundred', '百次拍打', '核心床', '在核心床上进行百次拍打,增加阻力挑战', '核心肌群、呼吸肌群、上身耐力', '核心床', NULL, NULL, 10, NULL, '10个呼吸循环', 'reformer', 2, NOW(), NOW()),
('reformer_bridge', '桥式', '核心床', '在核心床上进行桥式动作,利用弹簧阻力', '臀肌、腘绳肌、脊柱关节', '核心床', 10, NULL, NULL, NULL, '6-10次', 'reformer', 3, NOW(), NOW()),
('reformer_straps', '脚套带练习', '核心床', '使用脚套带进行各种腿部和髋部练习', '髋部灵活性、骨盆稳定性、身体控制、内收肌', '核心床', 10, NULL, NULL, NULL, '8-10次', 'reformer', 4, NOW(), NOW()),
('reformer_elephant', '象式', '核心床', '四点跪撑位置进行推拉练习', '核心肌群、腘绳肌、背部伸肌、肩部稳定性', '核心床', 10, NULL, NULL, NULL, '8-10次', 'reformer', 5, NOW(), NOW()),
('reformer_knee_stretch', '跪姿伸展系列', '核心床', '跪姿位置进行多种伸展动作', '核心肌群、髋部灵活性、肩部控制', '核心床', 10, NULL, NULL, NULL, NULL, 'reformer', 6, NOW(), NOW());
-- 插入凯迪拉克(Cadillac)动作数据
INSERT INTO `t_exercises` (
`key`, `name`, `category_name`, `description`, `target_muscle_groups`, `equipment_name`,
`beginner_reps`, `beginner_sets`, `breathing_cycles`, `hold_duration`, `special_instructions`,
`category_key`, `sort_order`, `created_at`, `updated_at`
) VALUES
('cadillac_leg_springs', '腿部弹簧系列', '凯迪拉克', '使用腿部弹簧进行各种腿部强化练习', '腘绳肌、股四头肌、臀肌、髋屈肌、内收肌', '凯迪拉克', 20, NULL, NULL, NULL, '10-20次', 'cadillac', 1, NOW(), NOW()),
('cadillac_arm_springs', '手臂弹簧系列', '凯迪拉克', '使用手臂弹簧进行上身力量训练', '胸部、肩部、上背部、手臂', '凯迪拉克', 15, NULL, NULL, NULL, '10-15次', 'cadillac', 2, NOW(), NOW()),
('cadillac_roll_down_bar', '滚背杆卷下', '凯迪拉克', '使用滚背杆进行脊柱逐节控制练习', '腹部肌肉、脊柱灵活性', '凯迪拉克', 12, NULL, NULL, NULL, '8-12次', 'cadillac', 3, NOW(), NOW()),
('cadillac_push_through_bar', '推杆', '凯迪拉克', '推拉横杆进行全身协调练习', '肩部、核心、背部', '凯迪拉克', 12, NULL, NULL, NULL, '8-12次', 'cadillac', 4, NOW(), NOW());
-- 插入普拉提椅(Chair)动作数据
INSERT INTO `t_exercises` (
`key`, `name`, `category_name`, `description`, `target_muscle_groups`, `equipment_name`,
`beginner_reps`, `beginner_sets`, `breathing_cycles`, `hold_duration`, `special_instructions`,
`category_key`, `sort_order`, `created_at`, `updated_at`
) VALUES
('chair_seated_march', '坐姿行进', '普拉提椅', '坐在椅子上进行交替抬腿练习', '核心肌群、髋屈肌', '普拉提椅', 12, NULL, NULL, NULL, '每侧10-12次', 'chair', 1, NOW(), NOW()),
('chair_seated_leg_lift', '坐姿抬腿', '普拉提椅', '坐姿单腿伸展练习', '股四头肌、核心肌群', '普拉提椅', 12, NULL, NULL, NULL, '每侧10-12次', 'chair', 2, NOW(), NOW()),
('chair_seated_arm_circles', '坐姿手臂画圈', '普拉提椅', '坐姿手臂做圆周运动', '肩部、上背部、手臂', '普拉提椅', 12, NULL, NULL, NULL, '前后各10-12次', 'chair', 3, NOW(), NOW()),
('chair_spine_twist', '脊柱扭转', '普拉提椅', '坐姿脊柱旋转练习', '腹斜肌、脊柱旋转肌', '普拉提椅', 10, NULL, NULL, NULL, '每侧8-10次', 'chair', 4, NOW(), NOW()),
('chair_squat', '椅子深蹲', '普拉提椅', '使用椅子进行深蹲练习', '臀肌、股四头肌、腘绳肌、核心', '普拉提椅', 12, NULL, NULL, NULL, '10-12次', 'chair', 5, NOW(), NOW());
-- 插入普拉提桶(Barrel)动作数据
INSERT INTO `t_exercises` (
`key`, `name`, `category_name`, `description`, `target_muscle_groups`, `equipment_name`,
`beginner_reps`, `beginner_sets`, `breathing_cycles`, `hold_duration`, `special_instructions`,
`category_key`, `sort_order`, `created_at`, `updated_at`
) VALUES
('barrel_spine_stretch', '脊柱伸展', '普拉提桶', '在桶上进行脊柱后伸练习', '核心肌群、脊柱伸肌、背部肌肉', '普拉提桶', 12, 3, NULL, NULL, '10-12次2-3组', 'barrel', 1, NOW(), NOW()),
('barrel_mermaid', '美人鱼伸展', '普拉提桶', '侧坐在桶上进行侧向伸展', '核心肌群、腹斜肌、侧向柔韧性', '普拉提桶', 10, 3, NULL, NULL, '每侧8-10次2-3组', 'barrel', 2, NOW(), NOW()),
('barrel_side_bend', '侧弯', '普拉提桶', '侧卧在桶上进行侧向弯曲练习', '腹斜肌、腰部塑形、平衡感、核心稳定性', '普拉提桶', 10, 3, NULL, NULL, '每侧8-10次2-3组', 'barrel', 3, NOW(), NOW()),
('barrel_teaser_prep', '预备式Teaser', '普拉提桶', '在桶上进行Teaser动作的预备练习', '核心肌群、平衡感、本体感受', '普拉提桶', 5, 2, NULL, 3, '5次2组保持3秒', 'barrel', 4, NOW(), NOW()),
('barrel_swan_dive_prep', '预备式Swan Dive', '普拉提桶', '在桶上进行Swan Dive的预备练习', '背部伸肌、脊柱伸展、平衡感', '普拉提桶', 5, 2, NULL, 3, '5次2组保持3秒', 'barrel', 5, NOW(), NOW());
-- 验证数据插入结果
SELECT
ec.name as category_name,
ec.type,
ec.equipment_name,
COUNT(e.key) as exercise_count
FROM t_exercise_categories ec
LEFT JOIN t_exercises e ON ec.key = e.category_key
GROUP BY ec.key, ec.name, ec.type, ec.equipment_name
ORDER BY ec.sort_order;
-- 验证表结构
SELECT
TABLE_NAME,
TABLE_COMMENT,
TABLE_ROWS
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME IN ('t_exercise_categories', 't_exercises', 't_training_plans', 't_schedule_exercises')
ORDER BY TABLE_NAME;
-- 验证外键约束
SELECT
CONSTRAINT_NAME,
TABLE_NAME,
COLUMN_NAME,
REFERENCED_TABLE_NAME,
REFERENCED_COLUMN_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = DATABASE()
AND REFERENCED_TABLE_NAME IS NOT NULL
AND TABLE_NAME IN ('t_exercises', 't_schedule_exercises')
ORDER BY TABLE_NAME, CONSTRAINT_NAME;

View File

@@ -0,0 +1,138 @@
-- 训练计划相关表单独创建脚本
-- 此脚本仅创建训练计划相关的表,前提是动作表已经存在
-- 禁用外键检查
SET FOREIGN_KEY_CHECKS = 0;
-- 删除训练计划相关表(如果存在)
DROP TABLE IF EXISTS `t_schedule_exercises`;
DROP TABLE IF EXISTS `t_training_plans`;
-- 重新启用外键检查
SET FOREIGN_KEY_CHECKS = 1;
-- 创建训练计划表
CREATE TABLE `t_training_plans` (
`id` char(36) NOT NULL COMMENT '训练计划唯一ID',
`is_active` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否激活',
`user_id` varchar(255) NOT NULL COMMENT '用户ID',
`name` varchar(255) DEFAULT NULL COMMENT '计划名称',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`start_date` datetime NOT NULL COMMENT '开始日期',
`mode` enum('daysOfWeek','sessionsPerWeek') NOT NULL COMMENT '计划模式',
`days_of_week` json NOT NULL COMMENT '周几训练0-6',
`sessions_per_week` int NOT NULL COMMENT '每周训练次数',
`goal` enum('postpartum_recovery','fat_loss','posture_correction','core_strength','flexibility','rehab','stress_relief','') NOT NULL COMMENT '训练目标',
`start_weight_kg` float DEFAULT NULL COMMENT '起始体重(公斤)',
`preferred_time_of_day` enum('morning','noon','evening','') NOT NULL DEFAULT '' COMMENT '偏好训练时间',
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否已删除',
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_is_active` (`is_active`),
KEY `idx_deleted` (`deleted`),
KEY `idx_user_active` (`user_id`, `is_active`, `deleted`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='训练计划表';
-- 创建训练计划动作表
CREATE TABLE `t_schedule_exercises` (
`id` char(36) NOT NULL COMMENT '计划动作唯一ID',
`training_plan_id` char(36) NOT NULL COMMENT '训练计划ID',
`user_id` varchar(255) NOT NULL COMMENT '用户ID',
`exercise_key` varchar(255) DEFAULT NULL COMMENT '关联的动作key仅exercise类型',
`name` varchar(255) NOT NULL COMMENT '项目名称',
`sets` int DEFAULT NULL COMMENT '组数',
`reps` int DEFAULT NULL COMMENT '重复次数',
`duration_sec` int DEFAULT NULL COMMENT '持续时长(秒)',
`rest_sec` int DEFAULT NULL COMMENT '休息时长(秒)',
`note` text DEFAULT NULL COMMENT '备注',
`item_type` enum('exercise','rest','note') NOT NULL DEFAULT 'exercise' COMMENT '项目类型',
`completed` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否已完成',
`sort_order` int NOT NULL COMMENT '排序顺序',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否已删除',
PRIMARY KEY (`id`),
KEY `idx_training_plan_id` (`training_plan_id`),
KEY `idx_exercise_key` (`exercise_key`),
KEY `idx_user_id` (`user_id`),
KEY `idx_sort_order` (`sort_order`),
KEY `idx_item_type` (`item_type`),
KEY `idx_plan_sort` (`training_plan_id`, `sort_order`),
CONSTRAINT `fk_schedule_exercises_training_plan` FOREIGN KEY (`training_plan_id`) REFERENCES `t_training_plans` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `fk_schedule_exercises_exercise` FOREIGN KEY (`exercise_key`) REFERENCES `t_exercises` (`key`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='训练计划动作表';
-- 验证表创建
SELECT
TABLE_NAME,
TABLE_COMMENT,
ENGINE
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME IN ('t_training_plans', 't_schedule_exercises')
ORDER BY TABLE_NAME;
-- 验证外键约束
SELECT
CONSTRAINT_NAME,
TABLE_NAME,
COLUMN_NAME,
REFERENCED_TABLE_NAME,
REFERENCED_COLUMN_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = DATABASE()
AND REFERENCED_TABLE_NAME IS NOT NULL
AND TABLE_NAME = 't_schedule_exercises'
ORDER BY CONSTRAINT_NAME;
-- 测试外键约束(插入测试数据)
-- 注意:这需要先有有效的 exercise_key 数据
/*
示例测试(请根据实际数据调整):
-- 插入测试训练计划
INSERT INTO t_training_plans (
id, user_id, name, start_date, mode, days_of_week, sessions_per_week, goal
) VALUES (
'550e8400-e29b-41d4-a716-446655440000',
'test_user_123',
'测试训练计划',
NOW(),
'daysOfWeek',
'[1,3,5]',
3,
'core_strength'
);
-- 插入测试动作
INSERT INTO t_schedule_exercises (
id, training_plan_id, user_id, exercise_key, name, sets, reps, item_type, sort_order
) VALUES (
'550e8400-e29b-41d4-a716-446655440001',
'550e8400-e29b-41d4-a716-446655440000',
'test_user_123',
'mat_hundred',
'百次拍打',
3,
10,
'exercise',
1
);
-- 验证数据
SELECT
tp.name as plan_name,
se.name as exercise_name,
se.exercise_key,
e.target_muscle_groups
FROM t_training_plans tp
JOIN t_schedule_exercises se ON tp.id = se.training_plan_id
LEFT JOIN t_exercises e ON se.exercise_key = e.key
WHERE tp.user_id = 'test_user_123';
-- 清理测试数据
DELETE FROM t_schedule_exercises WHERE user_id = 'test_user_123';
DELETE FROM t_training_plans WHERE user_id = 'test_user_123';
*/

View File

@@ -0,0 +1,190 @@
# 训练会话 API 使用指南
## 架构说明
新的训练系统采用了分离的架构设计,符合健身应用的最佳实践:
### 1. 训练计划模板 (Training Plans)
- **用途**: 用户创建和管理的训练计划模板
- **表**: `t_training_plans` + `t_schedule_exercises`
- **特点**: 静态配置,不包含完成状态
- **API**: `/training-plans`
### 2. 训练会话实例 (Workout Sessions)
- **用途**: 每日实际训练,从训练计划模板复制而来
- **表**: `t_workout_sessions` + `t_workout_exercises`
- **特点**: 动态数据,包含完成状态、进度追踪
- **API**: `/workouts`
## API 使用流程
### 第一步:创建训练计划模板
```bash
# 1. 创建训练计划
POST /training-plans
{
"name": "全身力量训练",
"startDate": "2024-01-15T00:00:00.000Z",
"mode": "daysOfWeek",
"daysOfWeek": [1, 3, 5],
"goal": "core_strength"
}
# 2. 添加训练动作到计划
POST /training-plans/{planId}/exercises
{
"exerciseKey": "squat",
"name": "深蹲训练",
"sets": 3,
"reps": 15,
"itemType": "exercise"
}
# 3. 激活训练计划
POST /training-plans/{planId}/activate
```
### 第二步:开始每日训练
```bash
# 1. 获取今日训练会话(如不存在则自动创建)
GET /workouts/today
# 系统会自动基于激活的训练计划创建今日训练会话
# 2. 开始训练会话(可选)
POST /workouts/sessions/{sessionId}/start
{
"startedAt": "2024-01-15T09:00:00.000Z"
}
# 3. 开始特定动作
POST /workouts/sessions/{sessionId}/exercises/{exerciseId}/start
# 4. 完成动作
POST /workouts/sessions/{sessionId}/exercises/{exerciseId}/complete
{
"completedSets": 3,
"completedReps": 15,
"actualDurationSec": 180,
"performanceData": {
"sets": [
{ "reps": 15, "difficulty": 7 },
{ "reps": 12, "difficulty": 8 },
{ "reps": 10, "difficulty": 9 }
],
"perceivedExertion": 8
}
}
# 注意:当所有动作完成后,训练会话会自动标记为完成
```
## 主要优势
### 1. 数据分离
- 训练计划是可重用的模板
- 每日训练是独立的实例
- 修改计划不影响历史训练记录
### 2. 自动化管理
- 客户端直接获取今日训练,系统自动创建
- 所有动作完成后自动完成训练会话
- 无需手动管理会话生命周期
### 3. 进度追踪
- 每个训练会话都有完整的状态跟踪
- 支持详细的性能数据记录
- 可以分析训练趋势和进步情况
### 4. 灵活性
- 支持训练中的临时调整
- 支持跳过或修改特定动作
- 自动计算训练统计数据
## API 端点总览
### 训练会话管理
- `GET /workouts/today` - 获取/自动创建今日训练会话 ⭐
- `GET /workouts/sessions` - 获取训练会话列表
- `GET /workouts/sessions/{id}` - 获取训练会话详情
- `POST /workouts/sessions/{id}/start` - 开始训练(可选)
- `DELETE /workouts/sessions/{id}` - 删除训练会话
- 注意:训练会话在所有动作完成后自动完成
### 训练动作管理
- `GET /workouts/sessions/{id}/exercises` - 获取训练动作列表
- `GET /workouts/sessions/{id}/exercises/{exerciseId}` - 获取动作详情
- `POST /workouts/sessions/{id}/exercises/{exerciseId}/start` - 开始动作
- `POST /workouts/sessions/{id}/exercises/{exerciseId}/complete` - 完成动作
- `POST /workouts/sessions/{id}/exercises/{exerciseId}/skip` - 跳过动作
- `PUT /workouts/sessions/{id}/exercises/{exerciseId}` - 更新动作信息
### 统计和快捷功能
- `GET /workouts/sessions/{id}/stats` - 获取训练统计
- `GET /workouts/recent` - 获取最近训练
## 数据模型
### WorkoutSession (训练会话)
```typescript
{
id: string;
userId: string;
trainingPlanId: string; // 关联的训练计划模板
name: string;
scheduledDate: Date;
startedAt?: Date;
completedAt?: Date;
status: 'planned' | 'in_progress' | 'completed' | 'skipped';
totalDurationSec?: number;
summary?: string;
caloriesBurned?: number;
stats?: {
totalExercises: number;
completedExercises: number;
totalSets: number;
completedSets: number;
// ...
};
}
```
### WorkoutExercise (训练动作实例)
```typescript
{
id: string;
workoutSessionId: string;
exerciseKey?: string; // 关联动作库
name: string;
plannedSets?: number; // 计划数值
completedSets?: number; // 实际完成数值
plannedReps?: number;
completedReps?: number;
plannedDurationSec?: number;
actualDurationSec?: number;
status: 'pending' | 'in_progress' | 'completed' | 'skipped';
startedAt?: Date;
completedAt?: Date;
performanceData?: { // 详细性能数据
sets: Array<{
reps?: number;
weight?: number;
difficulty?: number;
notes?: string;
}>;
heartRate?: { avg: number; max: number };
perceivedExertion?: number; // RPE 1-10
};
}
```
## 迁移说明
如果您之前使用了 `training-plans` 的完成状态功能,现在需要:
1. 使用 `/workouts/sessions` 来创建每日训练
2. 使用新的完成状态 API 来跟踪进度
3. 原有的训练计划数据保持不变,作为模板使用
这样的架构分离使得系统更加清晰、可维护,也更符合健身应用的实际使用场景。

View File

@@ -0,0 +1,31 @@
-- 创建训练会话表
CREATE TABLE t_workout_sessions (
id VARCHAR(36) PRIMARY KEY DEFAULT (UUID()),
user_id VARCHAR(255) NOT NULL COMMENT '用户ID',
training_plan_id VARCHAR(36) NOT NULL COMMENT '关联的训练计划模板',
name VARCHAR(255) NOT NULL COMMENT '训练会话名称',
scheduled_date DATETIME NOT NULL COMMENT '计划训练日期',
started_at DATETIME NULL COMMENT '实际开始时间',
completed_at DATETIME NULL COMMENT '实际结束时间',
status ENUM('planned', 'in_progress', 'completed', 'skipped') NOT NULL DEFAULT 'planned' COMMENT '训练状态',
total_duration_sec INT NULL COMMENT '总时长(秒)',
summary TEXT NULL COMMENT '训练总结/备注',
calories_burned INT NULL COMMENT '消耗卡路里(估算)',
stats JSON NULL COMMENT '训练统计数据',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted BOOLEAN DEFAULT FALSE COMMENT '是否已删除',
-- 外键约束
FOREIGN KEY (training_plan_id) REFERENCES t_training_plans(id),
-- 索引
INDEX idx_user_id (user_id),
INDEX idx_training_plan_id (training_plan_id),
INDEX idx_scheduled_date (scheduled_date),
INDEX idx_status (status),
INDEX idx_deleted (deleted)
);
-- 添加表注释
ALTER TABLE t_workout_sessions COMMENT = '训练会话表';

View File

@@ -0,0 +1,85 @@
-- 训练会话相关表创建脚本
-- 用于支持每日训练实例功能
-- 禁用外键检查
SET FOREIGN_KEY_CHECKS = 0;
-- 删除训练会话相关表(如果存在)
DROP TABLE IF EXISTS `t_workout_exercises`;
DROP TABLE IF EXISTS `t_workout_sessions`;
-- 重新启用外键检查
SET FOREIGN_KEY_CHECKS = 1;
-- 创建训练会话表
CREATE TABLE `t_workout_sessions` (
`id` char(36) NOT NULL COMMENT '训练会话唯一ID',
`user_id` varchar(255) NOT NULL COMMENT '用户ID',
`training_plan_id` char(36) NOT NULL COMMENT '关联的训练计划模板',
`name` varchar(255) NOT NULL COMMENT '训练会话名称',
`scheduled_date` datetime NOT NULL COMMENT '计划训练日期',
`started_at` datetime DEFAULT NULL COMMENT '实际开始时间',
`completed_at` datetime DEFAULT NULL COMMENT '实际结束时间',
`status` enum('planned','in_progress','completed','skipped') NOT NULL DEFAULT 'planned' COMMENT '训练状态',
`total_duration_sec` int DEFAULT NULL COMMENT '总时长(秒)',
`summary` text COMMENT '训练总结/备注',
`calories_burned` int DEFAULT NULL COMMENT '消耗卡路里(估算)',
`stats` json DEFAULT NULL COMMENT '训练统计数据',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否已删除',
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_training_plan_id` (`training_plan_id`),
KEY `idx_scheduled_date` (`scheduled_date`),
KEY `idx_status` (`status`),
KEY `idx_deleted` (`deleted`),
KEY `idx_user_date` (`user_id`, `scheduled_date`, `deleted`),
CONSTRAINT `fk_workout_sessions_training_plan` FOREIGN KEY (`training_plan_id`) REFERENCES `t_training_plans` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='训练会话表(每日训练实例)';
-- 创建训练会话动作表
CREATE TABLE `t_workout_exercises` (
`id` char(36) NOT NULL COMMENT '训练动作唯一ID',
`workout_session_id` char(36) NOT NULL COMMENT '所属训练会话ID',
`user_id` varchar(255) NOT NULL COMMENT '用户ID',
`exercise_key` varchar(255) DEFAULT NULL COMMENT '关联的动作key仅exercise类型',
`name` varchar(255) NOT NULL COMMENT '项目名称',
`planned_sets` int DEFAULT NULL COMMENT '计划组数',
`completed_sets` int DEFAULT NULL COMMENT '实际完成组数',
`planned_reps` int DEFAULT NULL COMMENT '计划重复次数',
`completed_reps` int DEFAULT NULL COMMENT '实际完成重复次数',
`planned_duration_sec` int DEFAULT NULL COMMENT '计划持续时长(秒)',
`actual_duration_sec` int DEFAULT NULL COMMENT '实际持续时长(秒)',
`rest_sec` int DEFAULT NULL COMMENT '休息时长(秒)',
`note` text COMMENT '备注',
`item_type` enum('exercise','rest','note') NOT NULL DEFAULT 'exercise' COMMENT '项目类型',
`status` enum('pending','in_progress','completed','skipped') NOT NULL DEFAULT 'pending' COMMENT '动作状态',
`sort_order` int NOT NULL COMMENT '排序顺序',
`started_at` datetime DEFAULT NULL COMMENT '开始时间',
`completed_at` datetime DEFAULT NULL COMMENT '完成时间',
`performance_data` json DEFAULT NULL COMMENT '详细执行数据',
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否已删除',
PRIMARY KEY (`id`),
KEY `idx_workout_session_id` (`workout_session_id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_exercise_key` (`exercise_key`),
KEY `idx_sort_order` (`sort_order`),
KEY `idx_status` (`status`),
KEY `idx_deleted` (`deleted`),
KEY `idx_session_order` (`workout_session_id`, `sort_order`, `deleted`),
CONSTRAINT `fk_workout_exercises_session` FOREIGN KEY (`workout_session_id`) REFERENCES `t_workout_sessions` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_workout_exercises_exercise` FOREIGN KEY (`exercise_key`) REFERENCES `t_exercises` (`key`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='训练会话动作表(每日训练实例动作)';
-- 为 t_schedule_exercises 表添加注释,澄清其用途
ALTER TABLE `t_schedule_exercises` COMMENT = '训练计划动作表(训练计划模板的动作配置)';
-- 创建一些有用的索引
CREATE INDEX `idx_workout_sessions_user_status` ON `t_workout_sessions` (`user_id`, `status`, `deleted`);
CREATE INDEX `idx_workout_exercises_session_type` ON `t_workout_exercises` (`workout_session_id`, `item_type`, `deleted`);
-- 插入一些示例数据来测试
-- 注意实际使用时应该通过API来创建数据