Files
plates-server/src/checkins/checkins.service.ts

121 lines
4.6 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 { Injectable, NotFoundException, Logger, ForbiddenException } from '@nestjs/common';
import { InjectModel } from '@nestjs/sequelize';
import { Checkin, CheckinStatus } from './models/checkin.model';
import { CreateCheckinDto, UpdateCheckinDto, CompleteCheckinDto, RemoveCheckinDto, CheckinResponseDto } from './dto/checkin.dto';
import { ResponseCode } from '../base.dto';
import * as dayjs from 'dayjs';
import { Op } from 'sequelize';
@Injectable()
export class CheckinsService {
private readonly logger = new Logger(CheckinsService.name);
constructor(
@InjectModel(Checkin)
private readonly checkinModel: typeof Checkin,
) { }
async create(dto: CreateCheckinDto): Promise<CheckinResponseDto> {
const record = await this.checkinModel.create({
userId: dto.userId,
workoutId: dto.workoutId || null,
planId: dto.planId || null,
title: dto.title || null,
checkinDate: dto.checkinDate || null,
startedAt: dto.startedAt ? new Date(dto.startedAt) : null,
notes: dto.notes || null,
metrics: dto.metrics || null,
status: CheckinStatus.PENDING,
});
return { code: ResponseCode.SUCCESS, message: 'success', data: record.toJSON() };
}
async update(dto: UpdateCheckinDto, userId: string): Promise<CheckinResponseDto> {
const record = await this.checkinModel.findByPk(dto.id);
if (!record) {
throw new NotFoundException('打卡记录不存在');
}
if (record.userId !== userId) {
throw new ForbiddenException('无权操作该打卡记录');
}
if (dto.workoutId !== undefined) record.workoutId = dto.workoutId;
if (dto.planId !== undefined) record.planId = dto.planId;
if (dto.title !== undefined) record.title = dto.title;
if (dto.checkinDate !== undefined) record.checkinDate = dto.checkinDate as any;
if (dto.startedAt !== undefined) record.startedAt = dto.startedAt ? new Date(dto.startedAt) : null;
if (dto.notes !== undefined) record.notes = dto.notes;
if (dto.metrics !== undefined) record.metrics = dto.metrics as any;
if (dto.status !== undefined) record.status = dto.status;
if (dto.completedAt !== undefined) record.completedAt = dto.completedAt ? new Date(dto.completedAt) : null;
if (dto.durationSeconds !== undefined) record.durationSeconds = dto.durationSeconds;
await record.save();
return { code: ResponseCode.SUCCESS, message: 'success', data: record.toJSON() };
}
async complete(dto: CompleteCheckinDto, userId: string): Promise<CheckinResponseDto> {
const record = await this.checkinModel.findByPk(dto.id);
if (!record) {
throw new NotFoundException('打卡记录不存在');
}
if (record.userId !== userId) {
throw new ForbiddenException('无权操作该打卡记录');
}
record.status = CheckinStatus.COMPLETED;
record.completedAt = dto.completedAt ? new Date(dto.completedAt) : new Date();
if (dto.durationSeconds !== undefined) record.durationSeconds = dto.durationSeconds;
if (dto.notes !== undefined) record.notes = dto.notes;
if (dto.metrics !== undefined) record.metrics = dto.metrics as any;
await record.save();
return { code: ResponseCode.SUCCESS, message: 'success', data: record.toJSON() };
}
async remove(dto: RemoveCheckinDto, userId: string): Promise<CheckinResponseDto> {
const record = await this.checkinModel.findByPk(dto.id);
if (!record) {
throw new NotFoundException('打卡记录不存在');
}
if (record.userId !== userId) {
throw new ForbiddenException('无权操作该打卡记录');
}
await record.destroy();
return { code: ResponseCode.SUCCESS, message: 'success', data: { id: dto.id } };
}
async getDaily(userId: string, date?: string): Promise<CheckinResponseDto> {
const target = date ? dayjs(date) : dayjs();
if (!target.isValid()) {
return { code: ResponseCode.ERROR, message: '无效日期', data: [] };
}
const start = target.startOf('day').toDate();
const end = target.endOf('day').toDate();
// 覆盖两类数据:
// 1) checkinDate == YYYY-MM-DD精确日
// 2) startedAt/ completedAt 落在该日范围内(更鲁棒)
const rows = await this.checkinModel.findAll({
where: {
userId,
[Op.or]: [
{ checkinDate: target.format('YYYY-MM-DD') as any },
{
[Op.or]: [
{ startedAt: { [Op.between]: [start, end] } },
{ completedAt: { [Op.between]: [start, end] } },
],
},
],
},
order: [['createdAt', 'ASC']],
});
return { code: ResponseCode.SUCCESS, message: 'success', data: rows.map(r => r.toJSON()) };
}
}