From 323baa876f600cf29b27389cfe0f30138ab7d2c0 Mon Sep 17 00:00:00 2001 From: ziin Date: Wed, 17 Dec 2025 15:51:46 +0800 Subject: [PATCH] =?UTF-8?q?feat(chat):=20=E6=96=B0=E5=A2=9E=E5=85=8D?= =?UTF-8?q?=E8=B4=B9=E9=A2=9D=E5=BA=A6=E4=B8=8EVIP=E6=A0=A1=E9=AA=8C?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在聊天接口中增加用户免费次数及VIP身份校验,未通过时返回新错误码50022; 调用成功后若使用免费额度则自动扣减,保障额度体系闭环。 --- .../com/yolo/keyborad/common/ErrorCode.java | 3 +- .../service/impl/ChatServiceImpl.java | 36 +++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/yolo/keyborad/common/ErrorCode.java b/src/main/java/com/yolo/keyborad/common/ErrorCode.java index 237e8ec..39129c1 100644 --- a/src/main/java/com/yolo/keyborad/common/ErrorCode.java +++ b/src/main/java/com/yolo/keyborad/common/ErrorCode.java @@ -56,7 +56,8 @@ public enum ErrorCode { PRODUCT_QUOTA_NOT_SET(50018, "商品额度未配置"), LACK_ORIGIN_TRANSACTION_ID_ERROR(50019, "缺少原始交易id"), UNKNOWN_PRODUCT_TYPE(50020, "未知商品类型"), - PRODUCT_NOT_FOUND(50021, "商品不存在"); + PRODUCT_NOT_FOUND(50021, "商品不存在"), + NO_QUOTA_AND_NOT_VIP(50022, "免费次数已用完,请开通VIP"); /** * 状态码 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 00a4812..ddcb0ef 100644 --- a/src/main/java/com/yolo/keyborad/service/impl/ChatServiceImpl.java +++ b/src/main/java/com/yolo/keyborad/service/impl/ChatServiceImpl.java @@ -11,10 +11,10 @@ import com.yolo.keyborad.exception.BusinessException; import com.yolo.keyborad.model.dto.chat.ChatReq; import com.yolo.keyborad.model.dto.chat.ChatStreamMessage; import com.yolo.keyborad.model.entity.KeyboardCharacter; +import com.yolo.keyborad.model.entity.KeyboardUser; import com.yolo.keyborad.model.entity.KeyboardUserCallLog; -import com.yolo.keyborad.service.ChatService; -import com.yolo.keyborad.service.KeyboardCharacterService; -import com.yolo.keyborad.service.KeyboardUserCallLogService; +import com.yolo.keyborad.model.entity.KeyboardUserQuotaTotal; +import com.yolo.keyborad.service.*; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.chat.client.ChatClient; @@ -55,6 +55,12 @@ public class ChatServiceImpl implements ChatService { @Resource private KeyboardUserCallLogService callLogService; + @Resource + private KeyboardUserQuotaTotalService quotaTotalService; + + @Resource + private UserService userService; + private final NacosAppConfigCenter.DynamicAppConfig cfgHolder; public ChatServiceImpl(NacosAppConfigCenter.DynamicAppConfig cfgHolder) { @@ -105,6 +111,22 @@ public class ChatServiceImpl implements ChatService { throw new BusinessException(ErrorCode.CHAT_CHARACTER_NOT_FOUND); } + // ============ 3. 校验用户免费次数和VIP ============ + Long userId = StpUtil.getLoginIdAsLong(); + KeyboardUserQuotaTotal quota = quotaTotalService.getById(userId); + boolean hasFreeQuota = quota != null && quota.getUsedQuota() < quota.getTotalQuota(); + AtomicReference usedFreeQuota = new AtomicReference<>(hasFreeQuota); + + if (!hasFreeQuota) { + KeyboardUser user = userService.getById(userId); + boolean isValidVip = user != null && user.getIsVip() != null && user.getIsVip() + && (user.getVipExpiry() == null || user.getVipExpiry().after(new Date())); + if (!isValidVip) { + log.error("用户无免费次数且非VIP,用户ID: {}", userId); + throw new BusinessException(ErrorCode.NO_QUOTA_AND_NOT_VIP); + } + } + // 获取应用配置 // ============ 初始化调用日志相关变量 ============ @@ -260,6 +282,14 @@ public class ChatServiceImpl implements ChatService { callLog.setCreatedAt(new Date()); // 保存日志到数据库 callLogService.save(callLog); + + // 如果使用了免费次数且调用成功,扣减免费次数 + if (usedFreeQuota.get() && callLog.getSuccess()) { + KeyboardUserQuotaTotal updateQuota = new KeyboardUserQuotaTotal(); + updateQuota.setUserId(callLog.getUserId()); + updateQuota.setUsedQuota(quota.getUsedQuota() + 1); + quotaTotalService.updateById(updateQuota); + } } catch (Exception e) { log.error("保存调用日志失败", e); }