优化训练计划相关服务,移除不必要的completed字段,简化DTO和模型结构。同时,增强训练会话删除逻辑,添加事务处理和错误日志记录,提升数据一致性和操作安全性。
This commit is contained in:
@@ -51,11 +51,6 @@ export class CreateScheduleExerciseDto {
|
|||||||
@IsEnum(['exercise', 'rest', 'note'])
|
@IsEnum(['exercise', 'rest', 'note'])
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
itemType?: ScheduleItemType;
|
itemType?: ScheduleItemType;
|
||||||
|
|
||||||
@ApiProperty({ description: '是否已完成', default: false, required: false })
|
|
||||||
@IsBoolean()
|
|
||||||
@IsOptional()
|
|
||||||
completed?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UpdateScheduleExerciseDto extends PartialType(CreateScheduleExerciseDto) { }
|
export class UpdateScheduleExerciseDto extends PartialType(CreateScheduleExerciseDto) { }
|
||||||
|
|||||||
@@ -60,9 +60,6 @@ export class ScheduleExercise extends Model {
|
|||||||
})
|
})
|
||||||
declare itemType: ScheduleItemType;
|
declare itemType: ScheduleItemType;
|
||||||
|
|
||||||
@Column({ type: DataType.BOOLEAN, defaultValue: false, comment: '是否已完成' })
|
|
||||||
declare completed: boolean;
|
|
||||||
|
|
||||||
@Column({ type: DataType.INTEGER, allowNull: false, comment: '排序顺序' })
|
@Column({ type: DataType.INTEGER, allowNull: false, comment: '排序顺序' })
|
||||||
declare sortOrder: number;
|
declare sortOrder: number;
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { ActivityLogsService } from '../activity-logs/activity-logs.service';
|
|||||||
import { ActivityActionType, ActivityEntityType } from '../activity-logs/models/activity-log.model';
|
import { ActivityActionType, ActivityEntityType } from '../activity-logs/models/activity-log.model';
|
||||||
import { Logger as WinstonLogger } from 'winston';
|
import { Logger as WinstonLogger } from 'winston';
|
||||||
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
|
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
|
||||||
import { Op, Transaction } from 'sequelize';
|
import { Op } from 'sequelize';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ScheduleExerciseService {
|
export class ScheduleExerciseService {
|
||||||
@@ -79,7 +79,6 @@ export class ScheduleExerciseService {
|
|||||||
restSec: dto.restSec,
|
restSec: dto.restSec,
|
||||||
note: dto.note || '',
|
note: dto.note || '',
|
||||||
itemType: dto.itemType || 'exercise',
|
itemType: dto.itemType || 'exercise',
|
||||||
completed: dto.completed || false,
|
|
||||||
sortOrder,
|
sortOrder,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -182,7 +181,6 @@ export class ScheduleExerciseService {
|
|||||||
if (dto.restSec !== undefined) exercise.restSec = dto.restSec;
|
if (dto.restSec !== undefined) exercise.restSec = dto.restSec;
|
||||||
if (dto.note !== undefined) exercise.note = dto.note || '';
|
if (dto.note !== undefined) exercise.note = dto.note || '';
|
||||||
if (dto.itemType !== undefined) exercise.itemType = dto.itemType;
|
if (dto.itemType !== undefined) exercise.itemType = dto.itemType;
|
||||||
if (dto.completed !== undefined) exercise.completed = dto.completed;
|
|
||||||
|
|
||||||
await exercise.save();
|
await exercise.save();
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,11 @@ export class WorkoutsService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!activeTrainingPlan) {
|
if (!activeTrainingPlan) {
|
||||||
throw new NotFoundException('请先激活一个训练计划');
|
this.winstonLogger.info(`今日没有激活的训练计划`, {
|
||||||
|
context: 'WorkoutsService',
|
||||||
|
userId,
|
||||||
|
});
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建今日训练会话
|
// 创建今日训练会话
|
||||||
@@ -352,28 +356,44 @@ export class WorkoutsService {
|
|||||||
* 删除训练会话
|
* 删除训练会话
|
||||||
*/
|
*/
|
||||||
async deleteWorkoutSession(userId: string, sessionId: string) {
|
async deleteWorkoutSession(userId: string, sessionId: string) {
|
||||||
const [count] = await this.workoutSessionModel.update(
|
const transaction = await this.workoutSessionModel.sequelize?.transaction();
|
||||||
{ deleted: true },
|
if (!transaction) throw new Error('Failed to start transaction');
|
||||||
{ where: { id: sessionId, userId, deleted: false } }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (count === 0) {
|
try {
|
||||||
throw new NotFoundException('训练会话不存在');
|
const [count] = await this.workoutSessionModel.update(
|
||||||
|
{ deleted: true },
|
||||||
|
{ where: { id: sessionId, userId, deleted: false }, transaction }
|
||||||
|
);
|
||||||
|
|
||||||
|
if (count === 0) {
|
||||||
|
throw new NotFoundException('训练会话不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同时删除关联的训练动作
|
||||||
|
await this.workoutExerciseModel.update(
|
||||||
|
{ deleted: true },
|
||||||
|
{ where: { workoutSessionId: sessionId, userId, deleted: false }, transaction }
|
||||||
|
);
|
||||||
|
|
||||||
|
await transaction.commit();
|
||||||
|
|
||||||
|
this.winstonLogger.info(`删除训练会话 ${sessionId}`, {
|
||||||
|
context: 'WorkoutsService',
|
||||||
|
userId,
|
||||||
|
sessionId,
|
||||||
|
});
|
||||||
|
|
||||||
|
return { success: true };
|
||||||
|
} catch (error) {
|
||||||
|
await transaction.rollback();
|
||||||
|
this.winstonLogger.error(`删除训练会话失败 ${sessionId}`, {
|
||||||
|
context: 'WorkoutsService',
|
||||||
|
userId,
|
||||||
|
sessionId,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 同时删除关联的训练动作
|
|
||||||
await this.workoutExerciseModel.update(
|
|
||||||
{ deleted: true },
|
|
||||||
{ where: { workoutSessionId: sessionId, userId, deleted: false } }
|
|
||||||
);
|
|
||||||
|
|
||||||
this.winstonLogger.info(`删除训练会话 ${sessionId}`, {
|
|
||||||
context: 'WorkoutsService',
|
|
||||||
userId,
|
|
||||||
sessionId,
|
|
||||||
});
|
|
||||||
|
|
||||||
return { success: true };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 训练动作管理 ====================
|
// ==================== 训练动作管理 ====================
|
||||||
|
|||||||
Reference in New Issue
Block a user