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; }; }