From f28e6b7c39a2382342d2cac3365a7761dd189fde Mon Sep 17 00:00:00 2001 From: ziin Date: Tue, 27 Jan 2026 21:11:45 +0800 Subject: [PATCH] =?UTF-8?q?fix(service):=20=E5=BB=B6=E5=90=8EVIP=E4=BD=93?= =?UTF-8?q?=E9=AA=8C=E6=AC=A1=E6=95=B0=E6=89=A3=E5=87=8F=E8=87=B3AI?= =?UTF-8?q?=E5=93=8D=E5=BA=94=E6=88=90=E5=8A=9F=E5=90=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/ChatServiceImpl.java | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/yolo/keyborad/service/impl/ChatServiceImpl.java b/src/main/java/com/yolo/keyborad/service/impl/ChatServiceImpl.java index ca240fa..c167fd7 100644 --- a/src/main/java/com/yolo/keyborad/service/impl/ChatServiceImpl.java +++ b/src/main/java/com/yolo/keyborad/service/impl/ChatServiceImpl.java @@ -376,41 +376,29 @@ public class ChatServiceImpl implements ChatService { public ChatMessageVO message(String content, String userId, Long companionId) { log.info("同步对话请求, userId: {}, companionId: {}, content: {}", userId, companionId, content); - // ============ VIP等级检查 ============ + // ============ VIP等级检查(先检查,不增加次数) ============ AppConfig appConfig = cfgHolder.getRef().get(); KeyboardUser user = userService.getById(Long.parseLong(userId)); // 获取VIP等级(null视为0) int vipLevel = user != null && user.getVipLevel() != null ? user.getVipLevel() : 0; - // 如果VIP等级 <= 1,需要限制每日体验次数 - if (vipLevel <= 1) { - Integer dailyLimit = appConfig.getUserRegisterProperties().getVipFreeTrialTalk(); - String redisKey = CHAT_DAILY_LIMIT_PREFIX + userId; + // 记录是否需要扣减体验次数(VIP等级 <= 1 的用户需要扣减) + boolean needDeductQuota = vipLevel <= 1; + String redisKey = CHAT_DAILY_LIMIT_PREFIX + userId; + Integer dailyLimit = appConfig.getUserRegisterProperties().getVipFreeTrialTalk(); + // 如果VIP等级 <= 1,先检查每日体验次数是否用完 + if (needDeductQuota) { // 获取当前使用次数 String countStr = stringRedisTemplate.opsForValue().get(redisKey); int currentCount = countStr != null ? Integer.parseInt(countStr) : 0; - // 检查是否超出限制 + // 检查是否超出限制,超出直接返回 if (currentCount >= dailyLimit) { log.warn("用户 {} VIP等级 {} 已达到每日体验次数限制 {}", userId, vipLevel, dailyLimit); throw new BusinessException(ErrorCode.VIP_TRIAL_LIMIT_REACHED); } - - // 增加使用次数 - Long newCount = stringRedisTemplate.opsForValue().increment(redisKey); - - // 设置到午夜过期(只有第一次设置时需要设置过期时间) - if (newCount != null && newCount == 1) { - // 计算到今天午夜的剩余秒数 - LocalDateTime now = LocalDateTime.now(ZoneId.of("America/New_York")); - LocalDateTime midnight = LocalDateTime.of(LocalDate.now(ZoneId.of("America/New_York")).plusDays(1), LocalTime.MIDNIGHT); - long secondsUntilMidnight = ChronoUnit.SECONDS.between(now, midnight); - stringRedisTemplate.expire(redisKey, secondsUntilMidnight, TimeUnit.SECONDS); - } - - log.info("用户 {} VIP等级 {} 今日已使用 {}/{} 次", userId, vipLevel, newCount, dailyLimit); } long startTime = System.currentTimeMillis(); @@ -431,6 +419,22 @@ public class ChatServiceImpl implements ChatService { // 保存用户消息和AI响应到聊天记录 saveChatMessages(Long.parseLong(userId), companionId, content, response); + // ============ 成功后扣减体验次数 ============ + if (needDeductQuota) { + Long newCount = stringRedisTemplate.opsForValue().increment(redisKey); + + // 设置到午夜过期(只有第一次设置时需要设置过期时间) + if (newCount != null && newCount == 1) { + // 计算到今天午夜的剩余秒数 + LocalDateTime now = LocalDateTime.now(ZoneId.of("America/New_York")); + LocalDateTime midnight = LocalDateTime.of(LocalDate.now(ZoneId.of("America/New_York")).plusDays(1), LocalTime.MIDNIGHT); + long secondsUntilMidnight = ChronoUnit.SECONDS.between(now, midnight); + stringRedisTemplate.expire(redisKey, secondsUntilMidnight, TimeUnit.SECONDS); + } + + log.info("用户 {} VIP等级 {} 今日已使用 {}/{} 次", userId, vipLevel, newCount, dailyLimit); + } + // 生成音频任务 ID String audioId = UUID.randomUUID().toString().replace("-", "");