From 04903426d12ba70ed393782d5ccbb19f4839459d Mon Sep 17 00:00:00 2001 From: richarjiang Date: Wed, 27 Aug 2025 19:01:21 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E6=AC=A1=E6=95=B0=E6=89=A3=E9=99=A4=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E8=B0=83=E6=95=B4=E6=B4=BB=E5=8A=A8=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E5=8F=8A=E8=AE=B0=E5=BD=95=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ai-coach/ai-coach.controller.ts | 1 - src/ai-coach/ai-coach.service.ts | 3 ++ src/goals/services/goal-task.service.ts | 44 +++++++++++++++++-------- src/users/models/user-activity.model.ts | 6 ++-- src/users/users.module.ts | 2 +- 5 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/ai-coach/ai-coach.controller.ts b/src/ai-coach/ai-coach.controller.ts index 7f82faa..b24843b 100644 --- a/src/ai-coach/ai-coach.controller.ts +++ b/src/ai-coach/ai-coach.controller.ts @@ -65,7 +65,6 @@ export class AiCoachController { confirmationData: body.confirmationData, }); - await this.usersService.deductUserUsageCount(userId); // 普通流式/非流式响应 const readable = result as any; diff --git a/src/ai-coach/ai-coach.service.ts b/src/ai-coach/ai-coach.service.ts index 2a02030..5f51f3f 100644 --- a/src/ai-coach/ai-coach.service.ts +++ b/src/ai-coach/ai-coach.service.ts @@ -517,6 +517,9 @@ export class AiCoachService { messages.unshift({ role: 'system', content: NUTRITION_ANALYST_PROMPT }); } + // 普通聊天才需要扣减次数 + await this.usersService.deductUserUsageCount(params.userId); + return this.generateAIResponse(params.conversationId, params.userId, messages); } diff --git a/src/goals/services/goal-task.service.ts b/src/goals/services/goal-task.service.ts index 44e8d42..fc021d8 100644 --- a/src/goals/services/goal-task.service.ts +++ b/src/goals/services/goal-task.service.ts @@ -3,12 +3,14 @@ import { InjectModel } from '@nestjs/sequelize'; import { Op, WhereOptions } from 'sequelize'; import { Goal, GoalRepeatType, GoalStatus } from '../models/goal.model'; import { GoalTask, TaskStatus } from '../models/goal-task.model'; -import { CreateGoalTaskDto, UpdateGoalTaskDto, GoalTaskQueryDto, CompleteGoalTaskDto } from '../dto/goal-task.dto'; +import { UpdateGoalTaskDto, GoalTaskQueryDto, CompleteGoalTaskDto } from '../dto/goal-task.dto'; import * as dayjs from 'dayjs'; import * as weekOfYear from 'dayjs/plugin/weekOfYear'; import * as isoWeek from 'dayjs/plugin/isoWeek'; import * as isSameOrBefore from 'dayjs/plugin/isSameOrBefore'; import * as isSameOrAfter from 'dayjs/plugin/isSameOrAfter'; +import { ActivityLevel, ActivityType } from 'src/users/models/user-activity.model'; +import { UserActivityService } from 'src/users/services/user-activity.service'; dayjs.extend(weekOfYear); dayjs.extend(isoWeek); @@ -24,6 +26,7 @@ export class GoalTaskService { private readonly goalModel: typeof Goal, @InjectModel(GoalTask) private readonly goalTaskModel: typeof GoalTask, + private readonly userActivityService: UserActivityService, ) { } /** @@ -42,7 +45,7 @@ export class GoalTaskService { } const goals = await this.goalModel.findAll({ where }); - + this.logger.log(`为用户 ${userId} 找到 ${goals.length} 个活跃目标`); for (const goal of goals) { @@ -155,14 +158,14 @@ export class GoalTaskService { // 检查是否有自定义重复规则指定星期几 const weekdays = goal.customRepeatRule?.weekdays; - + if (weekdays && weekdays.length > 0) { // 如果有指定星期几,按指定星期几生成任务 this.logger.log(`为目标 ${goal.title} 生成每周任务,指定星期几: ${weekdays}`); - + // 从今天开始生成,如果开始日期晚于今天则从开始日期开始 let current = startDate.isBefore(today) ? today : startDate; - + let generatedCount = 0; while (current.isSameOrBefore(actualEndDate)) { @@ -199,9 +202,9 @@ export class GoalTaskService { current = current.add(1, 'day'); } - + this.logger.log(`为目标 ${goal.title} 生成了 ${generatedCount} 个每周任务`); - } + } } /** @@ -233,11 +236,11 @@ export class GoalTaskService { while (current.isSameOrBefore(actualEndDate)) { // 计算该月的目标日期 const targetDate = current.date(targetDayOfMonth); - + // 如果目标日期超出了该月的天数,则使用该月的最后一天 const daysInMonth = current.daysInMonth(); const actualTargetDate = targetDayOfMonth > daysInMonth ? current.date(daysInMonth) : targetDate; - + // 检查是否已经过了该月的目标日期 if (actualTargetDate.isBefore(today)) { this.logger.log(`跳过 ${current.format('YYYY年MM月')},目标日期 ${actualTargetDate.format('MM-DD')} 已过期`); @@ -272,7 +275,7 @@ export class GoalTaskService { current = current.add(1, 'month'); } - + this.logger.log(`为目标 ${goal.title} 生成了 ${generatedCount} 个每月任务`); } @@ -291,7 +294,7 @@ export class GoalTaskService { } const { weekdays } = goal.customRepeatRule; - + this.logger.log(`为目标 ${goal.title} 生成自定义任务,重复规则: ${JSON.stringify(goal.customRepeatRule)}`); if (weekdays && weekdays.length > 0) { @@ -302,7 +305,7 @@ export class GoalTaskService { // 从今天开始生成,如果开始日期晚于今天则从开始日期开始 let current = startDate.isBefore(today) ? today : startDate; - + let generatedCount = 0; this.logger.log(`开始生成自定义任务,日期范围: ${current.format('YYYY-MM-DD')} 到 ${actualEndDate.format('YYYY-MM-DD')}`); @@ -340,7 +343,7 @@ export class GoalTaskService { current = current.add(1, 'day'); } - + this.logger.log(`为目标 ${goal.title} 生成了 ${generatedCount} 个自定义任务`); } else { this.logger.warn(`目标 ${goal.title} 的自定义重复规则中没有指定星期几`); @@ -452,6 +455,21 @@ export class GoalTaskService { await task.save(); + try { + const today = dayjs().format('YYYY-MM-DD'); + + await this.userActivityService.recordActivity(userId, { + activityType: ActivityType.GOAL, + activityDate: today, + level: ActivityLevel.MEDIUM, + remark: `完成目标任务: ${task.title}`, + }); + this.logger.log(`记录用户活跃 - 用户: ${userId} 完成目标任务: ${task.title}`); + } catch (activityError) { + // 记录活跃失败不影响主要业务流程 + this.logger.error(`记录用户活跃失败: ${activityError.message}`); + } + this.logger.log(`用户 ${userId} 完成任务: ${task.title}, 当前进度: ${task.currentCount}/${task.targetCount}`); return this.formatTaskResponse(task); diff --git a/src/users/models/user-activity.model.ts b/src/users/models/user-activity.model.ts index 7986b11..61f5018 100644 --- a/src/users/models/user-activity.model.ts +++ b/src/users/models/user-activity.model.ts @@ -4,7 +4,7 @@ import { User } from './user.model'; export enum ActivityType { LOGIN = 1, // 登录 - WORKOUT = 2, // 训练 + GOAL = 2, // 目标任务完成 DIET_RECORD = 3, // 饮食记录 WEIGHT_RECORD = 4, // 体重记录 PROFILE_UPDATE = 5, // 资料更新 @@ -14,7 +14,7 @@ export enum ActivityType { // 活跃类型显示名称映射 export const ActivityTypeNames: Record = { [ActivityType.LOGIN]: '登录', - [ActivityType.WORKOUT]: '训练', + [ActivityType.GOAL]: '目标任务完成', [ActivityType.DIET_RECORD]: '饮食记录', [ActivityType.WEIGHT_RECORD]: '体重记录', [ActivityType.PROFILE_UPDATE]: '资料更新', @@ -77,7 +77,7 @@ export class UserActivity extends SequelizeModel