Files
plates-server/src/water-records/water-records.controller.ts
richarjiang 2c2e964199 feat(water-records): 新增喝水记录功能模块
新增完整的喝水记录管理功能,支持用户记录每日喝水情况、设置目标和查看统计信息。功能包括:

- 创建、查询、更新和删除喝水记录
- 设置和管理每日喝水目标
- 获取今日喝水统计和完成率分析
- 支持分页查询和日期范围筛选
- 完整的数据验证和错误处理机制

该模块已从用户模块中独立出来,提供REST API接口,包含数据库迁移脚本和详细文档。
2025-09-01 11:02:13 +08:00

146 lines
5.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
Controller,
Get,
Post,
Body,
Param,
HttpCode,
HttpStatus,
Put,
Delete,
Query,
Logger,
UseGuards,
NotFoundException,
} from '@nestjs/common';
import { ApiOperation, ApiBody, ApiResponse, ApiTags, ApiQuery } from '@nestjs/swagger';
import { WaterRecordsService } from './water-records.service';
import {
CreateWaterRecordDto,
UpdateWaterRecordDto,
WaterRecordResponseDto,
GetWaterRecordsQueryDto,
WaterRecordsListResponseDto,
UpdateWaterGoalDto,
WaterGoalResponseDto,
TodayWaterStatsResponseDto
} from './dto/water-record.dto';
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
import { CurrentUser } from '../common/decorators/current-user.decorator';
import { AccessTokenPayload } from '../users/services/apple-auth.service';
@ApiTags('water-records')
@Controller('water-records')
export class WaterRecordsController {
private readonly logger = new Logger(WaterRecordsController.name);
constructor(
private readonly waterRecordsService: WaterRecordsService,
) { }
/**
* 创建喝水记录
*/
@UseGuards(JwtAuthGuard)
@Post()
@HttpCode(HttpStatus.CREATED)
@ApiOperation({ summary: '创建喝水记录' })
@ApiBody({ type: CreateWaterRecordDto })
@ApiResponse({ status: 201, description: '成功创建喝水记录', type: WaterRecordResponseDto })
async createWaterRecord(
@Body() createDto: CreateWaterRecordDto,
@CurrentUser() user: AccessTokenPayload,
): Promise<WaterRecordResponseDto> {
this.logger.log(`创建喝水记录 - 用户ID: ${user.sub}, 喝水量: ${createDto.amount}ml`);
return this.waterRecordsService.createWaterRecord(user.sub, createDto);
}
/**
* 获取喝水记录列表
*/
@UseGuards(JwtAuthGuard)
@Get()
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: '获取喝水记录列表' })
@ApiQuery({ name: 'startDate', required: false, description: '开始日期 (YYYY-MM-DD)' })
@ApiQuery({ name: 'endDate', required: false, description: '结束日期 (YYYY-MM-DD)' })
@ApiQuery({ name: 'page', required: false, description: '页码默认1' })
@ApiQuery({ name: 'limit', required: false, description: '每页数量默认20' })
@ApiResponse({ status: 200, description: '成功获取喝水记录列表', type: WaterRecordsListResponseDto })
async getWaterRecords(
@Query() query: GetWaterRecordsQueryDto,
@CurrentUser() user: AccessTokenPayload,
): Promise<WaterRecordsListResponseDto> {
this.logger.log(`获取喝水记录列表 - 用户ID: ${user.sub}`);
return this.waterRecordsService.getWaterRecords(user.sub, query);
}
/**
* 更新喝水记录
*/
@UseGuards(JwtAuthGuard)
@Put(':id')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: '更新喝水记录' })
@ApiBody({ type: UpdateWaterRecordDto })
@ApiResponse({ status: 200, description: '成功更新喝水记录', type: WaterRecordResponseDto })
async updateWaterRecord(
@Param('id') recordId: string,
@Body() updateDto: UpdateWaterRecordDto,
@CurrentUser() user: AccessTokenPayload,
): Promise<WaterRecordResponseDto> {
this.logger.log(`更新喝水记录 - 用户ID: ${user.sub}, 记录ID: ${recordId}`);
return this.waterRecordsService.updateWaterRecord(user.sub, parseInt(recordId), updateDto);
}
/**
* 删除喝水记录
*/
@UseGuards(JwtAuthGuard)
@Delete(':id')
@HttpCode(HttpStatus.NO_CONTENT)
@ApiOperation({ summary: '删除喝水记录' })
@ApiResponse({ status: 204, description: '成功删除喝水记录' })
async deleteWaterRecord(
@Param('id') recordId: string,
@CurrentUser() user: AccessTokenPayload,
): Promise<void> {
this.logger.log(`删除喝水记录 - 用户ID: ${user.sub}, 记录ID: ${recordId}`);
const success = await this.waterRecordsService.deleteWaterRecord(user.sub, parseInt(recordId));
if (!success) {
throw new NotFoundException('喝水记录不存在');
}
}
/**
* 更新喝水目标
*/
@UseGuards(JwtAuthGuard)
@Put('goal/daily')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: '更新每日喝水目标' })
@ApiBody({ type: UpdateWaterGoalDto })
@ApiResponse({ status: 200, description: '成功更新喝水目标', type: WaterGoalResponseDto })
async updateWaterGoal(
@Body() updateDto: UpdateWaterGoalDto,
@CurrentUser() user: AccessTokenPayload,
): Promise<WaterGoalResponseDto> {
this.logger.log(`更新喝水目标 - 用户ID: ${user.sub}, 目标: ${updateDto.dailyWaterGoal}ml`);
return this.waterRecordsService.updateWaterGoal(user.sub, updateDto);
}
/**
* 获取今日喝水统计
*/
@UseGuards(JwtAuthGuard)
@Get('stats/today')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: '获取今日喝水统计' })
@ApiResponse({ status: 200, description: '成功获取今日喝水统计', type: TodayWaterStatsResponseDto })
async getTodayWaterStats(
@CurrentUser() user: AccessTokenPayload,
): Promise<TodayWaterStatsResponseDto> {
this.logger.log(`获取今日喝水统计 - 用户ID: ${user.sub}`);
return this.waterRecordsService.getTodayWaterStats(user.sub);
}
}