feat(training-plans): 添加训练计划名称字段并实现软删除功能
- 在 DTO 和模型中新增 name 字段,支持可选的计划名称 - 实现分页查询功能,优化列表接口返回结构 - 将删除操作改为软删除,新增 deleted 字段控制 - 更新服务逻辑以支持新字段和分页参数
This commit is contained in:
@@ -7,6 +7,11 @@ export class CreateTrainingPlanDto {
|
|||||||
@IsDateString()
|
@IsDateString()
|
||||||
startDate: string;
|
startDate: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '计划名称' })
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
name: string;
|
||||||
|
|
||||||
@ApiProperty({ enum: ['daysOfWeek', 'sessionsPerWeek'] })
|
@ApiProperty({ enum: ['daysOfWeek', 'sessionsPerWeek'] })
|
||||||
@IsEnum(['daysOfWeek', 'sessionsPerWeek'])
|
@IsEnum(['daysOfWeek', 'sessionsPerWeek'])
|
||||||
mode: PlanMode;
|
mode: PlanMode;
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ export class TrainingPlan extends Model {
|
|||||||
@Column({ type: DataType.STRING, allowNull: false })
|
@Column({ type: DataType.STRING, allowNull: false })
|
||||||
declare userId: string;
|
declare userId: string;
|
||||||
|
|
||||||
|
// 计划名称
|
||||||
|
@Column({ type: DataType.STRING, allowNull: true })
|
||||||
|
declare name: string;
|
||||||
|
|
||||||
@Column({ type: DataType.DATE, allowNull: false })
|
@Column({ type: DataType.DATE, allowNull: false })
|
||||||
declare createdAt: Date;
|
declare createdAt: Date;
|
||||||
|
|
||||||
@@ -44,6 +48,9 @@ export class TrainingPlan extends Model {
|
|||||||
|
|
||||||
@Column({ type: DataType.DATE, defaultValue: DataType.NOW })
|
@Column({ type: DataType.DATE, defaultValue: DataType.NOW })
|
||||||
declare updatedAt: Date;
|
declare updatedAt: Date;
|
||||||
|
|
||||||
|
@Column({ type: DataType.BOOLEAN, defaultValue: false })
|
||||||
|
declare deleted: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Body, Controller, Delete, Get, Param, Post, UseGuards } from '@nestjs/common';
|
import { Body, Controller, Delete, Get, Param, Post, Query, UseGuards } from '@nestjs/common';
|
||||||
import { ApiBody, ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger';
|
import { ApiBody, ApiOperation, ApiParam, ApiTags } from '@nestjs/swagger';
|
||||||
import { TrainingPlansService } from './training-plans.service';
|
import { TrainingPlansService } from './training-plans.service';
|
||||||
import { CreateTrainingPlanDto } from './dto/training-plan.dto';
|
import { CreateTrainingPlanDto } from './dto/training-plan.dto';
|
||||||
@@ -28,8 +28,12 @@ export class TrainingPlansController {
|
|||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
@ApiOperation({ summary: '训练计划列表' })
|
@ApiOperation({ summary: '训练计划列表' })
|
||||||
async list(@CurrentUser() user: AccessTokenPayload) {
|
async list(
|
||||||
return this.service.list(user.sub);
|
@CurrentUser() user: AccessTokenPayload,
|
||||||
|
@Query('page') page: number = 1,
|
||||||
|
@Query('limit') limit: number = 10,
|
||||||
|
) {
|
||||||
|
return this.service.list(user.sub, page, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(':id')
|
@Get(':id')
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export class TrainingPlansService {
|
|||||||
const plan = await this.trainingPlanModel.create({
|
const plan = await this.trainingPlanModel.create({
|
||||||
id,
|
id,
|
||||||
userId,
|
userId,
|
||||||
|
name: dto.name ?? '',
|
||||||
createdAt,
|
createdAt,
|
||||||
startDate: new Date(dto.startDate),
|
startDate: new Date(dto.startDate),
|
||||||
mode: dto.mode,
|
mode: dto.mode,
|
||||||
@@ -39,7 +40,10 @@ export class TrainingPlansService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async remove(userId: string, id: string) {
|
async remove(userId: string, id: string) {
|
||||||
const count = await this.trainingPlanModel.destroy({ where: { id, userId } });
|
const [count] = await this.trainingPlanModel.update(
|
||||||
|
{ deleted: true },
|
||||||
|
{ where: { id, userId, deleted: false } }
|
||||||
|
);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
await this.activityLogsService.record({
|
await this.activityLogsService.record({
|
||||||
userId,
|
userId,
|
||||||
@@ -52,14 +56,26 @@ export class TrainingPlansService {
|
|||||||
return { success: count > 0 };
|
return { success: count > 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
async list(userId: string) {
|
async list(userId: string, page: number = 1, limit: number = 10) {
|
||||||
const rows = await this.trainingPlanModel.findAll({ where: { userId }, order: [['created_at', 'DESC']] });
|
const offset = (page - 1) * limit;
|
||||||
return rows.map(r => ({
|
const { rows, count } = await this.trainingPlanModel.findAndCountAll({
|
||||||
|
where: { userId, deleted: false },
|
||||||
|
order: [['created_at', 'DESC']],
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: rows.map(r => ({
|
||||||
id: r.id,
|
id: r.id,
|
||||||
createdAt: r.createdAt,
|
createdAt: r.createdAt,
|
||||||
startDate: r.startDate,
|
startDate: r.startDate,
|
||||||
goal: r.goal,
|
goal: r.goal,
|
||||||
}));
|
})),
|
||||||
|
total: count,
|
||||||
|
page,
|
||||||
|
limit,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async detail(userId: string, id: string) {
|
async detail(userId: string, id: string) {
|
||||||
|
|||||||
Reference in New Issue
Block a user