feat(water-records): 新增喝水记录功能模块
新增完整的喝水记录管理功能,支持用户记录每日喝水情况、设置目标和查看统计信息。功能包括: - 创建、查询、更新和删除喝水记录 - 设置和管理每日喝水目标 - 获取今日喝水统计和完成率分析 - 支持分页查询和日期范围筛选 - 完整的数据验证和错误处理机制 该模块已从用户模块中独立出来,提供REST API接口,包含数据库迁移脚本和详细文档。
This commit is contained in:
272
src/water-records/dto/water-record.dto.ts
Normal file
272
src/water-records/dto/water-record.dto.ts
Normal file
@@ -0,0 +1,272 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNumber, IsOptional, IsEnum, Min, Max, IsString, MaxLength, IsDateString } from 'class-validator';
|
||||
import { Transform } from 'class-transformer';
|
||||
import { WaterRecordSource } from '../models/user-water-history.model';
|
||||
|
||||
/**
|
||||
* 创建喝水记录请求DTO
|
||||
*/
|
||||
export class CreateWaterRecordDto {
|
||||
@ApiProperty({
|
||||
description: '喝水量(毫升)',
|
||||
example: 250,
|
||||
minimum: 1,
|
||||
maximum: 5000,
|
||||
})
|
||||
@IsNumber({}, { message: '喝水量必须是数字' })
|
||||
@Min(1, { message: '喝水量不能小于1毫升' })
|
||||
@Max(5000, { message: '喝水量不能大于5000毫升' })
|
||||
amount: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: '记录时间',
|
||||
example: '2023-12-01T10:00:00.000Z',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsDateString({}, { message: '记录时间格式不正确' })
|
||||
recordedAt?: Date;
|
||||
|
||||
@ApiProperty({
|
||||
description: '记录来源',
|
||||
enum: WaterRecordSource,
|
||||
example: WaterRecordSource.Manual,
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsEnum(WaterRecordSource, { message: '记录来源必须是有效值' })
|
||||
source?: WaterRecordSource;
|
||||
|
||||
@ApiProperty({
|
||||
description: '备注',
|
||||
example: '早晨第一杯水',
|
||||
required: false,
|
||||
maxLength: 100,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString({ message: '备注必须是字符串' })
|
||||
@MaxLength(100, { message: '备注长度不能超过100个字符' })
|
||||
note?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新喝水记录请求DTO
|
||||
*/
|
||||
export class UpdateWaterRecordDto {
|
||||
@ApiProperty({
|
||||
description: '喝水量(毫升)',
|
||||
example: 250,
|
||||
minimum: 1,
|
||||
maximum: 5000,
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsNumber({}, { message: '喝水量必须是数字' })
|
||||
@Min(1, { message: '喝水量不能小于1毫升' })
|
||||
@Max(5000, { message: '喝水量不能大于5000毫升' })
|
||||
amount?: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: '记录时间',
|
||||
example: '2023-12-01T10:00:00.000Z',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsDateString({}, { message: '记录时间格式不正确' })
|
||||
recordedAt?: Date;
|
||||
|
||||
@ApiProperty({
|
||||
description: '记录来源',
|
||||
enum: WaterRecordSource,
|
||||
example: WaterRecordSource.Manual,
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsEnum(WaterRecordSource, { message: '记录来源必须是有效值' })
|
||||
source?: WaterRecordSource;
|
||||
|
||||
@ApiProperty({
|
||||
description: '备注',
|
||||
example: '早晨第一杯水',
|
||||
required: false,
|
||||
maxLength: 100,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString({ message: '备注必须是字符串' })
|
||||
@MaxLength(100, { message: '备注长度不能超过100个字符' })
|
||||
note?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取喝水记录查询DTO
|
||||
*/
|
||||
export class GetWaterRecordsQueryDto {
|
||||
@ApiProperty({
|
||||
description: '开始日期 (YYYY-MM-DD)',
|
||||
example: '2023-12-01',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
startDate?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '结束日期 (YYYY-MM-DD)',
|
||||
example: '2023-12-31',
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
endDate?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '页码,默认1',
|
||||
example: 1,
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@Transform(({ value }) => parseInt(value))
|
||||
@IsNumber({}, { message: '页码必须是数字' })
|
||||
@Min(1, { message: '页码不能小于1' })
|
||||
page?: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: '每页数量,默认20',
|
||||
example: 20,
|
||||
required: false,
|
||||
})
|
||||
@IsOptional()
|
||||
@Transform(({ value }) => parseInt(value))
|
||||
@IsNumber({}, { message: '每页数量必须是数字' })
|
||||
@Min(1, { message: '每页数量不能小于1' })
|
||||
@Max(100, { message: '每页数量不能大于100' })
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新喝水目标请求DTO
|
||||
*/
|
||||
export class UpdateWaterGoalDto {
|
||||
@ApiProperty({
|
||||
description: '每日喝水目标(毫升)',
|
||||
example: 2000,
|
||||
minimum: 500,
|
||||
maximum: 10000,
|
||||
})
|
||||
@IsNumber({}, { message: '喝水目标必须是数字' })
|
||||
@Min(500, { message: '喝水目标不能小于500毫升' })
|
||||
@Max(10000, { message: '喝水目标不能大于10000毫升' })
|
||||
dailyWaterGoal: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础响应DTO
|
||||
*/
|
||||
export class BaseResponseDto {
|
||||
@ApiProperty({ description: '是否成功', example: true })
|
||||
success: boolean;
|
||||
|
||||
@ApiProperty({ description: '响应消息', example: '操作成功' })
|
||||
message: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 喝水记录数据DTO
|
||||
*/
|
||||
export class WaterRecordDataDto {
|
||||
@ApiProperty({ description: '记录ID', example: 1 })
|
||||
id: number;
|
||||
|
||||
@ApiProperty({ description: '喝水量(毫升)', example: 250 })
|
||||
amount: number;
|
||||
|
||||
@ApiProperty({ description: '记录时间', example: '2023-12-01T10:00:00.000Z' })
|
||||
recordedAt: Date;
|
||||
|
||||
@ApiProperty({ description: '备注', example: '早晨第一杯水', nullable: true })
|
||||
note: string | null;
|
||||
|
||||
@ApiProperty({ description: '创建时间', example: '2023-12-01T10:00:00.000Z' })
|
||||
createdAt: Date;
|
||||
|
||||
@ApiProperty({ description: '更新时间', example: '2023-12-01T10:00:00.000Z' })
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* 喝水记录响应DTO
|
||||
*/
|
||||
export class WaterRecordResponseDto extends BaseResponseDto {
|
||||
@ApiProperty({ description: '喝水记录数据', type: WaterRecordDataDto })
|
||||
data: WaterRecordDataDto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页信息DTO
|
||||
*/
|
||||
export class PaginationDto {
|
||||
@ApiProperty({ description: '当前页码', example: 1 })
|
||||
page: number;
|
||||
|
||||
@ApiProperty({ description: '每页数量', example: 20 })
|
||||
limit: number;
|
||||
|
||||
@ApiProperty({ description: '总记录数', example: 100 })
|
||||
total: number;
|
||||
|
||||
@ApiProperty({ description: '总页数', example: 5 })
|
||||
totalPages: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 喝水记录列表响应DTO
|
||||
*/
|
||||
export class WaterRecordsListResponseDto extends BaseResponseDto {
|
||||
data: {
|
||||
records: WaterRecordDataDto[];
|
||||
pagination: PaginationDto;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 喝水目标响应DTO
|
||||
*/
|
||||
export class WaterGoalResponseDto extends BaseResponseDto {
|
||||
@ApiProperty({
|
||||
description: '喝水目标数据',
|
||||
example: { dailyWaterGoal: 2000 },
|
||||
})
|
||||
data: {
|
||||
dailyWaterGoal: number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 今日喝水统计响应DTO
|
||||
*/
|
||||
export class TodayWaterStatsResponseDto extends BaseResponseDto {
|
||||
@ApiProperty({
|
||||
description: '今日喝水统计',
|
||||
example: {
|
||||
date: '2023-12-01',
|
||||
totalAmount: 1500,
|
||||
dailyGoal: 2000,
|
||||
completionRate: 75.0,
|
||||
recordCount: 6,
|
||||
records: [],
|
||||
},
|
||||
})
|
||||
data: {
|
||||
date: string;
|
||||
totalAmount: number;
|
||||
dailyGoal: number;
|
||||
completionRate: number;
|
||||
recordCount: number;
|
||||
records: {
|
||||
id: number;
|
||||
amount: number;
|
||||
recordedAt: Date;
|
||||
note: string | null;
|
||||
}[];
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user