- 创建普拉提分类和动作数据的SQL导入脚本,支持垫上普拉提和器械普拉提的分类管理 - 实现数据库结构迁移脚本,添加新字段以支持普拉提类型和器械名称 - 更新数据库升级总结文档,详细说明数据库结构变更和数据导入步骤 - 创建训练会话相关表,支持每日训练实例功能 - 引入训练会话管理模块,整合训练计划与实际训练会话的关系
171 lines
4.8 KiB
TypeScript
171 lines
4.8 KiB
TypeScript
import { ApiProperty, PartialType } from '@nestjs/swagger';
|
||
import { IsArray, IsBoolean, IsDateString, IsEnum, IsInt, IsNotEmpty, IsOptional, IsString, IsUUID, Min, Max } from 'class-validator';
|
||
import { WorkoutItemType, WorkoutExerciseStatus } from '../models/workout-exercise.model';
|
||
|
||
export class CreateWorkoutExerciseDto {
|
||
@ApiProperty({ description: '关联的动作key(仅exercise类型需要)', required: false })
|
||
@IsString()
|
||
@IsOptional()
|
||
exerciseKey?: string;
|
||
|
||
@ApiProperty({ description: '项目名称' })
|
||
@IsString()
|
||
@IsNotEmpty()
|
||
name: string;
|
||
|
||
@ApiProperty({ description: '计划组数', required: false })
|
||
@IsInt()
|
||
@Min(0)
|
||
@IsOptional()
|
||
plannedSets?: number;
|
||
|
||
@ApiProperty({ description: '计划重复次数', required: false })
|
||
@IsInt()
|
||
@Min(0)
|
||
@IsOptional()
|
||
plannedReps?: number;
|
||
|
||
@ApiProperty({ description: '计划持续时长(秒)', required: false })
|
||
@IsInt()
|
||
@Min(0)
|
||
@IsOptional()
|
||
plannedDurationSec?: number;
|
||
|
||
@ApiProperty({ description: '休息时长(秒)', required: false })
|
||
@IsInt()
|
||
@Min(0)
|
||
@IsOptional()
|
||
restSec?: number;
|
||
|
||
@ApiProperty({ description: '备注', required: false })
|
||
@IsString()
|
||
@IsOptional()
|
||
note?: string;
|
||
|
||
@ApiProperty({
|
||
enum: ['exercise', 'rest', 'note'],
|
||
description: '项目类型',
|
||
default: 'exercise',
|
||
required: false
|
||
})
|
||
@IsEnum(['exercise', 'rest', 'note'])
|
||
@IsOptional()
|
||
itemType?: WorkoutItemType;
|
||
}
|
||
|
||
export class UpdateWorkoutExerciseDto extends PartialType(CreateWorkoutExerciseDto) {
|
||
@ApiProperty({ description: '实际完成组数', required: false })
|
||
@IsInt()
|
||
@Min(0)
|
||
@IsOptional()
|
||
completedSets?: number;
|
||
|
||
@ApiProperty({ description: '实际完成重复次数', required: false })
|
||
@IsInt()
|
||
@Min(0)
|
||
@IsOptional()
|
||
completedReps?: number;
|
||
|
||
@ApiProperty({ description: '实际持续时长(秒)', required: false })
|
||
@IsInt()
|
||
@Min(0)
|
||
@IsOptional()
|
||
actualDurationSec?: number;
|
||
|
||
@ApiProperty({ enum: ['pending', 'in_progress', 'completed', 'skipped'], required: false })
|
||
@IsEnum(['pending', 'in_progress', 'completed', 'skipped'])
|
||
@IsOptional()
|
||
status?: WorkoutExerciseStatus;
|
||
}
|
||
|
||
export class StartWorkoutExerciseDto {
|
||
@ApiProperty({ description: '开始时间', required: false })
|
||
@IsDateString()
|
||
@IsOptional()
|
||
startedAt?: string;
|
||
}
|
||
|
||
export class CompleteWorkoutExerciseDto {
|
||
@ApiProperty({ description: '实际完成组数', required: false })
|
||
@IsInt()
|
||
@Min(0)
|
||
@IsOptional()
|
||
completedSets?: number;
|
||
|
||
@ApiProperty({ description: '实际完成重复次数', required: false })
|
||
@IsInt()
|
||
@Min(0)
|
||
@IsOptional()
|
||
completedReps?: number;
|
||
|
||
@ApiProperty({ description: '实际持续时长(秒)', required: false })
|
||
@IsInt()
|
||
@Min(0)
|
||
@IsOptional()
|
||
actualDurationSec?: number;
|
||
|
||
@ApiProperty({ description: '完成时间', required: false })
|
||
@IsDateString()
|
||
@IsOptional()
|
||
completedAt?: string;
|
||
|
||
@ApiProperty({ description: '详细执行数据', required: false })
|
||
@IsOptional()
|
||
performanceData?: {
|
||
sets?: Array<{
|
||
reps?: number;
|
||
weight?: number;
|
||
duration?: number;
|
||
restTime?: number;
|
||
difficulty?: number;
|
||
notes?: string;
|
||
}>;
|
||
heartRate?: {
|
||
avg?: number;
|
||
max?: number;
|
||
};
|
||
perceivedExertion?: number;
|
||
};
|
||
}
|
||
|
||
export class UpdateWorkoutExerciseOrderDto {
|
||
@ApiProperty({ description: '动作ID列表,按新的顺序排列' })
|
||
@IsArray()
|
||
@IsString({ each: true })
|
||
exerciseIds: string[];
|
||
}
|
||
|
||
export class WorkoutExerciseResponseDto {
|
||
@ApiProperty() id: string;
|
||
@ApiProperty() workoutSessionId: string;
|
||
@ApiProperty() userId: string;
|
||
@ApiProperty({ required: false }) exerciseKey?: string;
|
||
@ApiProperty() name: string;
|
||
@ApiProperty({ required: false }) plannedSets?: number;
|
||
@ApiProperty({ required: false }) completedSets?: number;
|
||
@ApiProperty({ required: false }) plannedReps?: number;
|
||
@ApiProperty({ required: false }) completedReps?: number;
|
||
@ApiProperty({ required: false }) plannedDurationSec?: number;
|
||
@ApiProperty({ required: false }) actualDurationSec?: number;
|
||
@ApiProperty({ required: false }) restSec?: number;
|
||
@ApiProperty({ required: false }) note?: string;
|
||
@ApiProperty({ enum: ['exercise', 'rest', 'note'] }) itemType: WorkoutItemType;
|
||
@ApiProperty({ enum: ['pending', 'in_progress', 'completed', 'skipped'] }) status: WorkoutExerciseStatus;
|
||
@ApiProperty() sortOrder: number;
|
||
@ApiProperty({ required: false }) startedAt?: Date;
|
||
@ApiProperty({ required: false }) completedAt?: Date;
|
||
@ApiProperty({ required: false }) performanceData?: any;
|
||
@ApiProperty() createdAt: Date;
|
||
@ApiProperty() updatedAt: Date;
|
||
|
||
// 关联的动作信息(仅exercise类型时存在)
|
||
@ApiProperty({ required: false })
|
||
exercise?: {
|
||
key: string;
|
||
name: string;
|
||
description: string;
|
||
categoryKey: string;
|
||
categoryName: string;
|
||
};
|
||
}
|