feat(diet-records): 新增营养成分分析免费使用次数限制
在营养成分分析功能中添加免费使用次数检查和扣减机制,非VIP用户免费次数用尽时将无法使用该功能。分析成功后自动扣减用户免费次数,确保资源合理使用。
This commit is contained in:
@@ -23,6 +23,7 @@ import { NutritionAnalysisRecordsResponseDto, GetNutritionAnalysisRecordsQueryDt
|
|||||||
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
|
import { JwtAuthGuard } from '../common/guards/jwt-auth.guard';
|
||||||
import { CurrentUser } from '../common/decorators/current-user.decorator';
|
import { CurrentUser } from '../common/decorators/current-user.decorator';
|
||||||
import { AccessTokenPayload } from '../users/services/apple-auth.service';
|
import { AccessTokenPayload } from '../users/services/apple-auth.service';
|
||||||
|
import { UsersService } from '../users/users.service';
|
||||||
|
|
||||||
@ApiTags('diet-records')
|
@ApiTags('diet-records')
|
||||||
@Controller('diet-records')
|
@Controller('diet-records')
|
||||||
@@ -32,6 +33,7 @@ export class DietRecordsController {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly dietRecordsService: DietRecordsService,
|
private readonly dietRecordsService: DietRecordsService,
|
||||||
private readonly nutritionAnalysisService: NutritionAnalysisService,
|
private readonly nutritionAnalysisService: NutritionAnalysisService,
|
||||||
|
private readonly usersService: UsersService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -190,13 +192,30 @@ export class DietRecordsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// 检查用户免费使用次数
|
||||||
|
const userUsageCount = await this.usersService.getUserUsageCount(user.sub);
|
||||||
|
|
||||||
|
// 如果用户不是VIP且免费次数不足,返回错误
|
||||||
|
if (userUsageCount <= 0) {
|
||||||
|
this.logger.warn(`营养成分表分析失败 - 用户ID: ${user.sub}, 免费次数不足`);
|
||||||
|
return NutritionAnalysisResponseDto.createError('免费使用次数已用完,请开通会员获取更多使用次数');
|
||||||
|
}
|
||||||
|
|
||||||
// 传递用户ID以便保存分析记录
|
// 传递用户ID以便保存分析记录
|
||||||
const result = await this.nutritionAnalysisService.analyzeNutritionImage(requestDto.imageUrl, user.sub);
|
const result = await this.nutritionAnalysisService.analyzeNutritionImage(requestDto.imageUrl, user.sub);
|
||||||
|
|
||||||
this.logger.log(`营养成分表分析完成 - 用户ID: ${user.sub}, 成功: ${result.success}, 营养素数量: ${result.data.length}`);
|
this.logger.log(`营养成分表分析完成 - 用户ID: ${user.sub}, 成功: ${result.success}, 营养素数量: ${result.data.length}`);
|
||||||
|
|
||||||
// 转换旧的响应格式到新的通用格式
|
// 如果分析成功,扣减用户免费使用次数
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
|
try {
|
||||||
|
await this.usersService.deductUserUsageCount(user.sub, 1);
|
||||||
|
this.logger.log(`营养成分表分析成功,已扣减用户免费次数 - 用户ID: ${user.sub}, 剩余次数: ${userUsageCount - 1}`);
|
||||||
|
} catch (deductError) {
|
||||||
|
this.logger.error(`扣减用户免费次数失败 - 用户ID: ${user.sub}, 错误: ${deductError instanceof Error ? deductError.message : String(deductError)}`);
|
||||||
|
// 不影响主流程,继续返回成功结果
|
||||||
|
}
|
||||||
|
|
||||||
return NutritionAnalysisResponseDto.createSuccess(result.data, result.message || '分析成功');
|
return NutritionAnalysisResponseDto.createSuccess(result.data, result.message || '分析成功');
|
||||||
} else {
|
} else {
|
||||||
return NutritionAnalysisResponseDto.createError(result.message || '分析失败');
|
return NutritionAnalysisResponseDto.createError(result.message || '分析失败');
|
||||||
|
|||||||
Reference in New Issue
Block a user