Przeglądaj źródła

fix(消费服务): 消费服务运行bug修改

1.人脸消费时参数验证不通过问题
2.修正接口查询错误
3.修正缓存处理逻辑,缓存中没有则从数据库获取
4.修正了余额初始化逻辑,一次加载后程序处理结果
autumnal_wind 11 miesięcy temu
rodzic
commit
23911003e3

+ 1 - 2
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java

@@ -185,8 +185,7 @@ public interface CacheNames {
      */
     String PT_USER_ACCOUNT_ID = "pt_user_account_id";
     String PT_USER_ACCOUNT_NO = "pt_user_account_no";
-    String PT_USER_ACCOUNT_List = "pt_user_account_list";
-
+    String PT_USER_ACCOUNT_LIST = "pt_user_account_list";
     /**
      * 营业时段/餐类
      */

+ 42 - 22
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/business/CardBusiness.java

@@ -4,6 +4,9 @@ import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.dromara.backstage.api.RemoteCardService;
+import org.dromara.backstage.api.RemoteUserAccountService;
 import org.dromara.backstage.api.domain.vo.RemoteCardVo;
 import org.dromara.backstage.api.domain.vo.RemoteUserAccountVo;
 import org.dromara.common.core.api.ReturnResult;
@@ -21,6 +24,7 @@ import org.dromara.server.consume.domain.vo.PtBagVo;
 import org.dromara.server.consume.domain.vo.yc.BagInfo;
 import org.dromara.server.consume.domain.vo.yc.CardBagInfo;
 import org.dromara.server.consume.service.IPtBagService;
+import org.dromara.system.api.RemoteDeptService;
 import org.springframework.http.HttpStatus;
 import org.springframework.stereotype.Service;
 
@@ -43,25 +47,51 @@ public class CardBusiness {
     private final IPtBagService ptBagService;
 
     public ReturnResult getCardBagsByCardNo(Long cardNo) {
-        // RemoteCardVo remoteCardVo = remoteCardService.queryCardByCardNo(cardNo);
         String strCardNo = String.valueOf(cardNo);
-        ErrorResult errorResult = createErrorResult(cardNo);
-        if (RedisUtils.getCacheMapValue(CacheNames.PT_USER_CARD_NO, strCardNo) != null) {
-            RemoteCardVo remoteCardVo = JsonUtils.parseObject(RedisUtils.getCacheMapValue(CacheNames.PT_USER_CARD_NO, strCardNo).toString(), RemoteCardVo.class);
-            if (remoteCardVo == null) {
-                return ReturnResult.failure(ResultCodeEnum.DATA_NOT_FOUND, errorResult);
-            }
-            return ReturnResult.success(this.setCardBagInfo(remoteCardVo));
+        Object objCard = RedisUtils.getCacheMapValue(CacheNames.PT_USER_CARD_NO, strCardNo);
+        if (objCard == null) {
+            ErrorResult result = new ErrorResult();
+            result.setStatusCode(HttpStatus.NOT_FOUND.value());
+            result.setMessage("获取卡片信息失败");
+            result.getErrors()
+                .add(new ErrorInfo(1, "获取卡片信息失败", ApiErrorTypeConstants.NOT_FOUND, "流水号为[" + cardNo + "]的卡片不存在!"));
+
+            return ReturnResult.failure(ResultCodeEnum.DATA_NOT_FOUND, result);
+        }
+        RemoteCardVo remoteCardVo = JsonUtils.parseObject(objCard.toString(), RemoteCardVo.class);
+        if (remoteCardVo == null) {
+            ErrorResult result = new ErrorResult();
+            result.setStatusCode(HttpStatus.NOT_FOUND.value());
+            result.setMessage("获取卡片信息失败");
+            result.getErrors()
+                .add(new ErrorInfo(1, "获取卡片信息失败", ApiErrorTypeConstants.NOT_FOUND, "流水号为[" + cardNo + "]的卡片不存在!"));
+
+            return ReturnResult.failure(ResultCodeEnum.DATA_NOT_FOUND, result);
+        }
+        Object obj = setCardBagInfo(remoteCardVo);
+        if (obj == null) {
+            ErrorResult result = new ErrorResult();
+            result.setStatusCode(HttpStatus.NOT_FOUND.value());
+            result.setMessage("获取卡片信息失败");
+            result.getErrors()
+                .add(new ErrorInfo(1, "获取卡片信息失败", ApiErrorTypeConstants.NOT_FOUND, "流水号为[" + cardNo + "]的卡片无对应人员信息!"));
+
+            return ReturnResult.failure(ResultCodeEnum.DATA_NOT_FOUND, result);
         } else {
-            return ReturnResult.failure(ResultCodeEnum.DATA_NOT_FOUND, errorResult);
+            return ReturnResult.success(obj);
         }
+
     }
 
     private Object setCardBagInfo(RemoteCardVo remoteCardVo) {
         CardBagInfo cardBagInfo = new CardBagInfo();
-        // RemoteUserAccountVo userAccountVo = remoteUserAccountService.getUserAccountVoById(remoteCardVo.getUserId());
-        String strUserId = String.valueOf(remoteCardVo.getUserId());
-        RemoteUserAccountVo userAccountVo = RedisUtils.getCacheMapValue(CacheNames.PT_USER_ACCOUNT_ID, strUserId);
+        Long userId = remoteCardVo.getUserId();
+        List<RemoteUserAccountVo> listUserAccount = RedisUtils.getCacheList(CacheNames.PT_USER_ACCOUNT_LIST);
+        RemoteUserAccountVo userAccountVo = listUserAccount.parallelStream().filter(p -> userId.equals(p.getUserId()))
+            .findFirst().orElse(null);
+        if (userAccountVo == null) {
+            return null;
+        }
         PtBagBo bagBo = new PtBagBo();
         bagBo.setUserId(remoteCardVo.getUserId());
         List<PtBagVo> bagVos = ptBagService.queryList(bagBo);
@@ -118,14 +148,4 @@ public class CardBusiness {
 
         return cardBagInfo;
     }
-
-    private ErrorResult createErrorResult(Long cardNo) {
-        ErrorResult result = new ErrorResult();
-        result.setStatusCode(HttpStatus.NOT_FOUND.value());
-        result.setMessage("获取卡片信息失败");
-        result.getErrors()
-            .add(new ErrorInfo(1, "获取卡片信息失败", ApiErrorTypeConstants.NOT_FOUND, "流水号为[" + cardNo + "]的卡片不存在!"));
-
-        return result;
-    }
 }

+ 5 - 5
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/business/EmployeeBusiness.java

@@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.dubbo.config.annotation.DubboReference;
+import org.dromara.backstage.api.RemoteCardService;
 import org.dromara.backstage.api.RemoteUserAccountService;
 import org.dromara.backstage.api.domain.vo.RemoteCardVo;
 import org.dromara.backstage.api.domain.vo.RemoteUserAccountVo;
@@ -20,6 +21,7 @@ import org.dromara.system.api.RemoteDeptService;
 import org.dromara.system.api.domain.vo.RemoteDeptVo;
 import org.springframework.http.HttpStatus;
 import org.springframework.stereotype.Service;
+
 /**
  * @ClassName EmployeeBusiness
  * @Description TODO
@@ -37,7 +39,6 @@ public class EmployeeBusiness {
     @DubboReference
     private final RemoteDeptService remoteDeptService;
 
-
     public ReturnResult getEmployeeVoByNumb(String userNumb) {
         RemoteUserAccountVo userAccountVo = remoteUserAccountService.getUserAccountVoByUserNumb(userNumb);
         // RemoteUserAccountVo userAccountVo = RedisUtils.getCacheMapValue(CacheNames);
@@ -50,7 +51,6 @@ public class EmployeeBusiness {
 
             return ReturnResult.failure(ResultCodeEnum.DATA_NOT_FOUND, result);
         }
-        // RemoteUserAccountVo userAccountVo = new RemoteUserAccountVo();
         return ReturnResult.success(this.setReturnEmployeeVo(userAccountVo));
     }
 
@@ -70,13 +70,13 @@ public class EmployeeBusiness {
         RemoteCardVo remoteCardVo = JsonUtils.parseObject(objCard.toString(), RemoteCardVo.class);
         UserCardVo userCardVo = new UserCardVo();
         Long cardNo = 0L;
-        if (ObjectUtil.isNotEmpty(remoteCardVo)) {
+        if (remoteCardVo != null) {
             CardStatusVo cardStatusVo = new CardStatusVo();
             int cardStatusId = Integer.parseInt(remoteCardVo.getStatus());
             cardStatusVo.setCardStatusID(cardStatusId);
             cardStatusVo.setCardStatus(cardStatusId == 1 ? "正常"
-                                           : cardStatusId == 2 ? "挂失" : cardStatusId == 3 ? "注销"
-                                           : cardStatusId == 4 ? "退卡" : cardStatusId == 7 ?"冻结" :"未知");
+                : cardStatusId == 2 ? "挂失" : cardStatusId == 3 ? "注销"
+                : cardStatusId == 4 ? "退卡" : cardStatusId == 7 ? "冻结" : "未知");
             userCardVo.setCardStatus(cardStatusVo);
 
             CardTypeVo cardTypeVo = new CardTypeVo();

+ 39 - 42
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/business/InitBusiness.java

@@ -11,8 +11,12 @@ import org.dromara.backstage.api.domain.vo.*;
 import org.dromara.common.core.constant.CacheNames;
 import org.dromara.common.json.utils.JsonUtils;
 import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.server.consume.domain.PtBag;
 import org.dromara.server.consume.domain.bo.XfCardLimitedBo;
+import org.dromara.server.consume.domain.bo.XfUserTotalBo;
+import org.dromara.server.consume.domain.vo.PtBagVo;
 import org.dromara.server.consume.domain.vo.XfCardLimitedVo;
+import org.dromara.server.consume.domain.vo.XfConsumeDetailVo;
 import org.dromara.server.consume.domain.vo.XfTermVo;
 import org.dromara.server.consume.service.IPtBagService;
 import org.dromara.server.consume.service.IXfCardLimitedService;
@@ -21,7 +25,9 @@ import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
 import java.time.Duration;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 消费相关基础数据初始化类
@@ -121,7 +127,7 @@ public class InitBusiness {
         if (CollUtil.isNotEmpty(discountCards)) {
             RedisUtils.deleteKeys(CacheNames.T_XF_DISCOUNT);
             discountCards.forEach(p -> {
-                String key = String.valueOf(p.getCardType());
+                String key = String.format("%s-%s",p.getCardType(),p.getMealType());
                 RedisUtils.setCacheMapValue(CacheNames.T_XF_DISCOUNT, key, p);
             });
         }
@@ -153,17 +159,18 @@ public class InitBusiness {
      * 余额会因充值、退款、错扣补款、消费等原因发生变化,所以需要定时初始化
      */
     public void initUserBalance() {
-        List<Long> idList = remoteUserAccountService.getUserAccountIdList();
-        if (CollUtil.isNotEmpty(idList)) {
-            RedisUtils.deleteKeys(CacheNames.USER_TOTAL_BALANCE);
-            idList.forEach(id -> {
-                String userId = String.valueOf(id);
-                BigDecimal balance = bagService.getUserBalance(id);
-                RedisUtils.setCacheMapValue(CacheNames.USER_TOTAL_BALANCE, userId, balance);
-            });
-            RedisUtils.expire(CacheNames.USER_TOTAL_BALANCE, Duration.ofHours(5));
+        List<PtBagVo> list = bagService.selectBalanceBag();
+        Map<String, BigDecimal> sumMap = new HashMap<>();
+        for (PtBagVo vo : list) {
+            String userId = String.valueOf(vo.getUserId());
+             BigDecimal amount = vo.getBalance();
+            sumMap.merge(userId, amount, BigDecimal::add);
+        }
+        for (Map.Entry<String, BigDecimal> entry : sumMap.entrySet()) {
+            RedisUtils.setCacheMapValue(CacheNames.USER_TOTAL_BALANCE, entry.getKey(), entry.getValue());
         }
-        log.info("人员余额参数完成");
+        RedisUtils.expire(CacheNames.USER_TOTAL_BALANCE, Duration.ofHours(5));
+        log.info("初始化人员余额参数完成");
     }
 
     /**
@@ -190,8 +197,6 @@ public class InitBusiness {
             list.forEach(v -> {
                 String cardNo = String.valueOf(v.getCardNo());
                 String userId = String.valueOf(v.getUserId());
-                // RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_NO, cardNo, v);
-                // RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_USER_ID, userId, v);
                 String strCard = JsonUtils.toJsonString(v);
                 RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_NO, cardNo, strCard);
                 RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_USER_ID, userId, strCard);
@@ -220,6 +225,8 @@ public class InitBusiness {
             String strCard = JsonUtils.toJsonString(cardVo);
             RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_NO, cardNo, strCard);
             RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_USER_ID, userId, strCard);
+            // RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_NO, cardNo, cardVo);
+            // RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_USER_ID, userId, cardVo);
         }
         log.info("初始指定人员卡片参数完成,人员Id:{}", id);
     }
@@ -235,20 +242,9 @@ public class InitBusiness {
                 && p.getLifespan().getTime() > System.currentTimeMillis()).toList();
 
         if (CollectionUtil.isNotEmpty(filterList)) {
-            RedisUtils.deleteKeys(CacheNames.USER_TOTAL_BALANCE);
-            RedisUtils.deleteKeys(CacheNames.PT_USER_ACCOUNT_List);
-
-            RedisUtils.setCacheList(CacheNames.PT_USER_ACCOUNT_List, filterList);
-            list.forEach(v -> {
-                Long userId = v.getUserId();
-                String strUserId = String.valueOf(userId);
-
-                BigDecimal balance = bagService.getUserBalance(userId);
-                RedisUtils.setCacheMapValue(CacheNames.USER_TOTAL_BALANCE, strUserId, balance);
-
-            });
-            RedisUtils.expire(CacheNames.PT_USER_ACCOUNT_ID, Duration.ofHours(5));
-            RedisUtils.expire(CacheNames.PT_USER_ACCOUNT_List, Duration.ofHours(5));
+            RedisUtils.deleteKeys(CacheNames.PT_USER_ACCOUNT_LIST);
+            RedisUtils.setCacheList(CacheNames.PT_USER_ACCOUNT_LIST, filterList);
+            RedisUtils.expire(CacheNames.PT_USER_ACCOUNT_LIST, Duration.ofHours(5));
         }
         log.info("初始化人员账户参数完成");
     }
@@ -260,21 +256,22 @@ public class InitBusiness {
      * @param id 人员Id
      */
     public void initUserAccountById(Long id) {
-        RemoteUserAccountVo accountVo = remoteUserAccountService.getUserAccountVoById(id);
-        if (ObjectUtil.isNotEmpty(accountVo)) {
-            String strUserId = String.valueOf(id);
-            String strUserNo = String.valueOf(accountVo.getUserNo());
-
-            RedisUtils.delCacheMapValue(CacheNames.PT_USER_ACCOUNT_ID, strUserId);
-            RedisUtils.delCacheMapValue(CacheNames.PT_USER_ACCOUNT_NO, strUserNo);
-
-            RedisUtils.setCacheMapValue(CacheNames.PT_USER_ACCOUNT_ID, strUserId, accountVo);
-            RedisUtils.setCacheMapValue(CacheNames.PT_USER_ACCOUNT_NO, strUserNo, accountVo);
-
-            BigDecimal balance = bagService.getUserBalance(id);
-            RedisUtils.delCacheMapValue(CacheNames.PT_USER_CARD_NO, strUserId);
-            RedisUtils.setCacheMapValue(CacheNames.USER_TOTAL_BALANCE, strUserId, balance);
-        }
+        // RemoteUserAccountVo accountVo = remoteUserAccountService.getUserAccountVoById(id);
+        // if (ObjectUtil.isNotEmpty(accountVo)) {
+        //     List<RemoteUserAccountVo> list = RedisUtils.getCacheList(CacheNames.PT_USER_ACCOUNT_LIST);
+            // String strUserId = String.valueOf(id);
+            // String strUserNo = String.valueOf(accountVo.getUserNo());
+            //
+            // RedisUtils.delCacheMapValue(CacheNames.PT_USER_ACCOUNT_ID, strUserId);
+            // RedisUtils.delCacheMapValue(CacheNames.PT_USER_ACCOUNT_NO, strUserNo);
+            //
+            // RedisUtils.setCacheMapValue(CacheNames.PT_USER_ACCOUNT_ID, strUserId, accountVo);
+            // RedisUtils.setCacheMapValue(CacheNames.PT_USER_ACCOUNT_NO, strUserNo, accountVo);
+            //
+            // BigDecimal balance = bagService.getUserBalance(id);
+            // RedisUtils.delCacheMapValue(CacheNames.PT_USER_CARD_NO, strUserId);
+            // RedisUtils.setCacheMapValue(CacheNames.USER_TOTAL_BALANCE, strUserId, balance);
+        // }
         log.info("初始化指定人员账户参数完成,人员Id:{}", id);
     }
 

+ 74 - 173
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/check/CardConsumeValidation.java

@@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollectionUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.backstage.api.domain.vo.*;
-import org.dromara.common.core.constant.ApiErrorTypeConstants;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.domain.model.ErrorInfo;
 import org.dromara.common.core.enums.TradeStatusEnum;
@@ -23,10 +22,8 @@ import java.math.RoundingMode;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Supplier;
 
@@ -54,14 +51,12 @@ public class CardConsumeValidation {
                                        RemoteMealTypeVo mealTypeVo,
                                        XfCardLimitedVo cardLimitedVo, Map<String, Boolean> mapCardLimited) {
 
-        // public R<ErrorInfo> cardValidation(CardConsumeValidationContext validationContext) {
+    // public R<ErrorInfo> cardValidation(CardConsumeValidationContext validationContext) {
         // 1.初始化验证上下文
         CardConsumeValidationContext validationContext = CardConsumeValidationContext.create(bo, termVo, userCardVo, mealTypeVo.getTypeId());
-        CardConsumeValidationContext discountCtx = CardConsumeValidationContext.create(bo, termVo, userCardVo, mealTypeVo.getTypeId());
-        CardConsumeValidationContext limitedCtx = CardConsumeValidationContext.create(bo, termVo, userCardVo, mealTypeVo.getTypeId());
 
         // 2. 执行异步验证链
-        R<ErrorInfo> result = executeCardValidationChain(validationContext, discountCtx, limitedCtx);
+        R<ErrorInfo> result = executeCardValidationChain(validationContext);
         // if (R.isSuccess(result)) {
         //     dealCardQuota(validationContext);
         // }
@@ -75,40 +70,33 @@ public class CardConsumeValidation {
         return result;
     }
 
-    private R<ErrorInfo> executeCardValidationChain(CardConsumeValidationContext ctx, CardConsumeValidationContext discountCtx,
-                                                    CardConsumeValidationContext limitedCtx) {
+    private R<ErrorInfo> executeCardValidationChain(CardConsumeValidationContext ctx) {
         // 创建验证任务列表
         List<Supplier<R<ErrorInfo>>> validationTasks = new ArrayList<>();
-
-        validationTasks.add(() -> dealCardDiscount(discountCtx));
-        validationTasks.add(() -> dealCardLimited(limitedCtx));
+        validationTasks.add(() -> dealCardDiscount(ctx));
+        validationTasks.add(() -> dealCardLimited(ctx));
 
         // 用于存储第一个错误结果
         AtomicReference<R<ErrorInfo>> firstError = new AtomicReference<>(null);
+
         // 使用CountDownLatch跟踪任务完成
         CountDownLatch latch = new CountDownLatch(validationTasks.size());
-        AtomicBoolean cancelled = new AtomicBoolean(false);
 
         // 提交所有验证任务
-        for (int i = 0, j = validationTasks.size(); i < j; i++) {
-            final int taskIndex = i;
-            final Supplier<R<ErrorInfo>> task = validationTasks.get(taskIndex);
+        for (Supplier<R<ErrorInfo>> task : validationTasks) {
             taskExecutor.execute(() -> {
-                if (cancelled.get()) {
-                    latch.countDown();
-                    return;
-                }
                 try {
                     R<ErrorInfo> result = task.get();
                     // 如果发现错误且尚未设置错误结果
-                    if (result != null && R.isError(result) && firstError.compareAndSet(null, result)) {
-                        log.warn("{} 验证失败: {}", getTaskName(taskIndex), result);
-                        triggerCancellation(cancelled, taskIndex);
+                    if (result != null && R.isError(result) &&
+                            firstError.compareAndSet(null, result)) {
+                        // 取消其他任务(通过中断)
+                        taskExecutor.getThreadPoolExecutor().getQueue().clear();
                     }
                 } catch (Exception e) {
-                    log.error("任务 {} 执行异常", getTaskName(taskIndex), e);
+                    log.error("系统错误1", e);
                     if (firstError.compareAndSet(null, commonCheck.createError(TradeStatusEnum.SysError))) {
-                        triggerCancellation(cancelled, taskIndex);
+                        taskExecutor.getThreadPoolExecutor().getQueue().clear();
                     }
                 } finally {
                     latch.countDown();
@@ -119,22 +107,15 @@ public class CardConsumeValidation {
         try {
             // 等待所有任务完成或超时
             if (!latch.await(VALIDATION_TIMEOUT, TimeUnit.MILLISECONDS)) {
-                log.warn("任务超时 ({} ms)", VALIDATION_TIMEOUT);
-                triggerCancellation(cancelled, -1);
+                return commonCheck.createError(TradeStatusEnum.VALIDATION_TIMEOUT);
             }
 
             // 返回第一个发现的错误,如果没有错误则返回成功
-            if (firstError.get() != null) {
+            // return firstError.get() != null ? firstError.get() : R.ok();
+            if(firstError.get() != null){
                 return firstError.get();
             } else {
-                // 将限次与折扣验证数据合并到主上下文
-                mergeValidationResults(ctx, discountCtx, limitedCtx);
-                // 限额验证
-                R<ErrorInfo> result = dealCardQuota(ctx);
-                if (R.isError(result)) {
-                    return result;
-                }
-                return R.ok();
+                return dealCardQuota(ctx);
             }
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
@@ -143,111 +124,43 @@ public class CardConsumeValidation {
         }
     }
 
-    private String getTaskName(int taskIndex) {
-        return switch (taskIndex) {
-            case 0 -> "卡类折扣验证";
-            case 1 -> "卡类限次验证";
-            case 2 -> "卡类限额验证";
-            default -> "未知任务";
-        };
-    }
-
-    private void triggerCancellation(AtomicBoolean cancelled, int triggerTask) {
-        // 确保只触发一次取消操作
-        if (cancelled.compareAndSet(false, true)) {
-            // 记录触发取消的任务信息
-            String taskName = getTaskName(triggerTask);
-            if (triggerTask >= 0) {
-                log.warn("任务 [{}] 触发取消操作: {}", triggerTask, taskName);
-            } else {
-                log.warn("超时触发取消操作");
-            }
-
-            // 清空任务队列(取消未开始的任务)
-            int cancelledCount = taskExecutor.getThreadPoolExecutor().getQueue().size();
-            taskExecutor.getThreadPoolExecutor().getQueue().clear();
-            log.info("已取消 {} 个待执行任务", cancelledCount);
-
-            // 中断正在运行的任务
-            // 获取所有活动线程
-            Set<Thread> activeThreads = Thread.getAllStackTraces().keySet();
-            String threadPoolPrefix = taskExecutor.getThreadNamePrefix();
-
-            int interruptedCount = 0;
-
-            for (Thread thread : activeThreads) {
-                // 只中断本线程池创建的线程
-                if (thread.getName().startsWith(threadPoolPrefix)) {
-                    if (!thread.isInterrupted()) {
-                        thread.interrupt();
-                        interruptedCount++;
-                        log.debug("已发送中断信号给线程: {}", thread.getName());
-                    }
-                }
-            }
-
-            log.info("已向 {} 个运行中的任务发送中断信号", interruptedCount);
-        }
-
-    }
-
-    private void mergeValidationResults(CardConsumeValidationContext mainCtx,
-                                        CardConsumeValidationContext discountCtx,
-                                        CardConsumeValidationContext limitedCtx) {
-        // 合并折扣计算结果
-        mainCtx.setHasDiscount(discountCtx.getHasDiscount());
-        mainCtx.setDiscountMoney(discountCtx.getDiscountMoney());
-        // 合并限次计算结果
-        mainCtx.setHasLimited(limitedCtx.getHasLimited());
-    }
-
     // region 卡片折扣处理
     private R<ErrorInfo> dealCardDiscount(CardConsumeValidationContext ctx) {
-        if (Thread.currentThread().isInterrupted()) {
-            log.debug("折扣计算任务被取消,提前退出");
-            return commonCheck.createErrorResponse(1, ApiErrorTypeConstants.PARAM_ERROR,
-                "折扣计算任务被取消,提前退出", "折扣计算任务被取消,提前退出");
-        }
         if (!validationParam.getRATE_CONSUME()) {
-            log.debug("全局折扣功能未启用,跳过折扣验证");
+            log.warn("全局折扣功能未启用,跳过折扣验证");
             return R.ok();
         }
 
         List<String> termIds = validationParam.getDisCountTermIdList();
         String currentTermId = String.valueOf(ctx.getTermId());
         if (CollectionUtil.isEmpty(termIds) || !termIds.contains(currentTermId)) {
-            log.debug("终端[{}]未配置折扣功能,跳过折扣验证", ctx.getTermNo());
+            log.warn("终端[{}]未配置折扣功能,跳过折扣验证", ctx.getTermNo());
             return R.ok();
         }
 
         List<RemoteDiscountVo> discountVos = validationParam.getDiscountVos();
         if (CollectionUtil.isEmpty(discountVos)) {
-            log.debug("未配置卡类折扣功能,跳过折扣验证");
+            log.warn("未配置卡类折扣功能,跳过折扣验证");
             return R.ok();
         }
         String cardType = String.valueOf(ctx.getCardType());
         Long mealType = Long.valueOf(ctx.getLastMeal());
         RemoteDiscountVo discountVo = discountVos.stream()
-            .filter(p -> cardType.equals(p.getCardType())
-                && mealType.equals(p.getMealType())
-                && validationParam.getIsUse().equals(p.getStatus())).findFirst().orElse(null);
-        try {
-            XfCardLimitedVo cardLimitedVo = ctx.getCardLimitedVo();
-            if (discountVo != null) {
-                ctx.setHasDiscount(Boolean.TRUE);
-                ctx.discountMoney = getDisCountMoney(cardLimitedVo, ctx.getConsumeMoney(), discountVo);
-                return R.ok();
-            } else {
-                log.debug("卡片[{}]未配置折扣,跳过折扣验证", ctx.getCardNo());
-            }
-
+                                          .filter(p -> cardType.equals(p.getCardType())
+                                                           && mealType.equals(p.getMealType())
+                                                           && validationParam.getIsUse().equals(p.getStatus())).findFirst().orElse(null);
+        ;
+
+        XfCardLimitedVo cardLimitedVo = ctx.getCardLimitedVo();
+        if (discountVo != null) {
+            ctx.setHasDiscount(Boolean.TRUE);
+            ctx.discountMoney = getDisCountMoney(cardLimitedVo, ctx.getConsumeMoney(), discountVo);
             return R.ok();
-        } catch (Exception e) {
-            Thread.currentThread().interrupt();
-            log.debug("折扣计算任务异常", e);
-            return commonCheck.createErrorResponse(1, ApiErrorTypeConstants.PARAM_ERROR,
-                "折扣计算任务异常", e.getMessage());
+        } else {
+            log.warn("卡片[{}]未配置折扣,跳过折扣验证", ctx.getCardNo());
         }
+
+        return R.ok();
     }
 
     /**
@@ -279,18 +192,13 @@ public class CardConsumeValidation {
         // 4. 计算折扣金额(统一处理精度)
         BigDecimal discountFactor = selectedRate.divide(PERCENT_DIVISOR, 2, RoundingMode.HALF_UP);
         return consumeValue
-            .multiply(discountFactor)
-            .setScale(2, RoundingMode.HALF_UP);
+                   .multiply(discountFactor)
+                   .setScale(2, RoundingMode.HALF_UP);
     }
     // endregion
 
     //region 卡片限次处理
     private R<ErrorInfo> dealCardLimited(CardConsumeValidationContext ctx) {
-        if (Thread.currentThread().isInterrupted()) {
-            log.debug("卡片限次验证任务被取消,提前退出");
-            return commonCheck.createErrorResponse(1, ApiErrorTypeConstants.PARAM_ERROR,
-                "卡片限次验证任务被取消,提前退出", "卡片限次验证任务被取消,提前退出");
-        }
         if (!validationParam.getXC_CONSUME()) {
             log.debug("全局限次功能未启用,跳过限次验证");
             return R.ok();
@@ -309,40 +217,33 @@ public class CardConsumeValidation {
         }
         Long cardType = ctx.getCardType();
         RemoteLimitedVo limitedVo = limitedCards.stream()
-            .filter(p -> cardType.equals(p.getCardType())
-                && validationParam.getIsUse().equals(p.getStatus())).findFirst().orElse(null);
+                                        .filter(p -> cardType.equals(p.getCardType())
+                                                         && validationParam.getIsUse().equals(p.getStatus())).findFirst().orElse(null);
         if (limitedVo == null) {
             return R.ok();
         }
 
         ctx.setHasLimited(Boolean.TRUE);
-        try {
-            // 日限次校验
-            R<ErrorInfo> dailyCheck = checkDailyLimit(limitedVo, ctx.getCardLimitedVo().getDayCount());
-            if (dailyCheck != null) {
-                return dailyCheck;
-            }
-
-            // 餐类限次检查
-            return checkMealLimit(limitedVo, ctx.getLastMeal(), ctx.getCardLimitedVo().getMealCount());
-        } catch (Exception e) {
-            Thread.currentThread().interrupt();
-            log.debug("卡片限次验证任务异常", e);
-            return commonCheck.createErrorResponse(1, ApiErrorTypeConstants.PARAM_ERROR,
-                "卡片限次验证任务异常", e.getMessage());
+        // 日限次校验
+        R<ErrorInfo> dailyCheck = checkDailyLimit(limitedVo, ctx.getCardLimitedVo().getDayCount());
+        if (dailyCheck != null) {
+            return dailyCheck;
         }
+
+        // 餐类限次检查
+        return checkMealLimit(limitedVo, ctx.getLastMeal(), ctx.getCardLimitedVo().getMealCount());
     }
 
     /**
      * 检查每日消费次数限制。
      *
-     * @param limitedVo       卡片的限制信息对象,包含有关每日消费限额的数据(如每日最大消费次数或金额)。
-     *                        通过此对象可以获取卡片的每日消费限制规则。
+     * @param limitedVo     卡片的限制信息对象,包含有关每日消费限额的数据(如每日最大消费次数或金额)。
+     *                      通过此对象可以获取卡片的每日消费限制规则。
      * @param currentDayCount 当前日期内的消费次数或金额,表示在当天已经发生的消费总量。
      *                        这个参数用于与限制规则进行比较,以判断是否超出限制。
      * @return 返回一个泛型为 ErrorInfo 的结果对象 R<ErrorInfo>。
-     * 如果未超出限制,返回成功结果;
-     * 如果超出限制,返回包含错误信息的结果(例如超限的具体原因)。
+     *         如果未超出限制,返回成功结果;
+     *         如果超出限制,返回包含错误信息的结果(例如超限的具体原因)。
      */
     private R<ErrorInfo> checkDailyLimit(RemoteLimitedVo limitedVo, Long currentDayCount) {
         Long dayLimit = limitedVo.getDailyCount();
@@ -355,15 +256,15 @@ public class CardConsumeValidation {
     /**
      * 检查每餐消费次数限制。
      *
-     * @param limitedVo        卡片的限制信息对象,包含有关餐次消费限额的数据(如每餐最大消费次数或金额)。
-     *                         通过此对象可以获取卡片的餐次消费限制规则。
-     * @param mealType         餐类标识符,用于区分不同的餐次类型(例如早餐、午餐、晚餐等)。
-     *                         这个参数决定了要针对哪一类餐次进行消费限制的检查。
+     * @param limitedVo       卡片的限制信息对象,包含有关餐次消费限额的数据(如每餐最大消费次数或金额)。
+     *                        通过此对象可以获取卡片的餐次消费限制规则。
+     * @param mealType        餐类标识符,用于区分不同的餐次类型(例如早餐、午餐、晚餐等)。
+     *                        这个参数决定了要针对哪一类餐次进行消费限制的检查。
      * @param currentMealCount 当前餐次内的消费次数或金额,表示在当前餐次已经发生的消费总量。
      *                         这个参数用于与限制规则进行比较,以判断是否超出限制。
      * @return 返回一个泛型为 ErrorInfo 的结果对象 R<ErrorInfo>。
-     * 如果未超出限制,返回成功结果;
-     * 如果超出限制,返回包含错误信息的结果(例如超限的具体原因)。
+     *         如果未超出限制,返回成功结果;
+     *         如果超出限制,返回包含错误信息的结果(例如超限的具体原因)。
      */
     private R<ErrorInfo> checkMealLimit(RemoteLimitedVo limitedVo, String mealType, Long currentMealCount) {
         Map<String, Long> mealLimits = Map.of(
@@ -380,7 +281,7 @@ public class CardConsumeValidation {
 
         if (currentMealCount >= mealLimit) {
             String mealName = MEAL_TYPE_NAMES.getOrDefault(mealType, "未知餐次");
-            return commonCheck.createError(TradeStatusEnum.MealLimitTimes, String.format("卡类%s次数限制", mealName));
+            return commonCheck.createError(TradeStatusEnum.MealLimitTimes,String.format("卡类%s次数限制", mealName));
         }
         return R.ok();
     }
@@ -406,8 +307,8 @@ public class CardConsumeValidation {
         }
         Long cardType = ctx.getCardType();
         RemoteQuotaVo quotaVo = quotaCards.stream()
-            .filter(p -> cardType.equals(p.getCardType())
-                && validationParam.getIsUse().equals(p.getStatus())).findFirst().orElse(null);
+                                        .filter(p -> cardType.equals(p.getCardType())
+                                                         && validationParam.getIsUse().equals(p.getStatus())).findFirst().orElse(null);
         if (quotaVo == null) {
             return R.ok();
         }
@@ -426,17 +327,17 @@ public class CardConsumeValidation {
     /**
      * 检查每日消费额度限制。
      * 如果设置的日限额>0 并且当天已消费金额+当餐消费的金额比设置的大,则超额不能消费
+     * @param quotaVo     卡片的限制信息对象,包含有关每日消费限额的数据(如每日最大消费额度或金额)。
+     *                      通过此对象可以获取卡片的每日消费限制规则。
+     * @param dayMoney    当前日期内的消费额度或金额,表示在当天已经发生的消费总量。
+     *                    这个参数用于与限制规则进行比较,以判断是否超出限制。
+     * @param consumeMoney  消费金额
      *
-     * @param quotaVo      卡片的限制信息对象,包含有关每日消费限额的数据(如每日最大消费额度或金额)。
-     *                     通过此对象可以获取卡片的每日消费限制规则。
-     * @param dayMoney     当前日期内的消费额度或金额,表示在当天已经发生的消费总量。
-     *                     这个参数用于与限制规则进行比较,以判断是否超出限制。
-     * @param consumeMoney 消费金额
      * @return 返回一个泛型为 ErrorInfo 的结果对象 R<ErrorInfo>。
-     * 如果未超出限制,返回成功结果;
-     * 如果超出限制,返回包含错误信息的结果(例如超限的具体原因)。
+     *         如果未超出限制,返回成功结果;
+     *         如果超出限制,返回包含错误信息的结果(例如超限的具体原因)。
      */
-    private R<ErrorInfo> checkDailyQuota(RemoteQuotaVo quotaVo, BigDecimal dayMoney, BigDecimal consumeMoney) {
+    private R<ErrorInfo> checkDailyQuota(RemoteQuotaVo quotaVo, BigDecimal dayMoney,BigDecimal consumeMoney) {
         BigDecimal dayQuotaMoney = quotaVo.getDailyMoney();
         if (dayQuotaMoney.compareTo(BigDecimal.ZERO) > 0 && dayQuotaMoney.compareTo(dayMoney.add(consumeMoney)) < 0) {
             return commonCheck.createError(TradeStatusEnum.DayLimitMoney, "卡类日限制额度");
@@ -447,17 +348,17 @@ public class CardConsumeValidation {
     /**
      * 检查每餐消费额度限制。
      *
-     * @param quotaVo      卡片的限制信息对象,包含有关餐次消费限额的数据(如每餐最大消费额度或金额)。
-     *                     通过此对象可以获取卡片的餐次消费限制规则。
-     * @param mealType     餐类标识符,用于区分不同的餐次类型(例如早餐、午餐、晚餐等)。
-     *                     这个参数决定了要针对哪一类餐次进行消费限制的检查。
-     * @param mealMoney    当   当前餐次内的消费额度或金额,表示在当前餐次已经发生的消费总量。
+     * @param quotaVo       卡片的限制信息对象,包含有关餐次消费限额的数据(如每餐最大消费额度或金额)。
+     *                        通过此对象可以获取卡片的餐次消费限制规则。
+     * @param mealType        餐类标识符,用于区分不同的餐次类型(例如早餐、午餐、晚餐等)。
+     *                        这个参数决定了要针对哪一类餐次进行消费限制的检查。
+     * @param mealMoney 当   当前餐次内的消费额度或金额,表示在当前餐次已经发生的消费总量。
      * @param consumeMoney 当 当前餐次的消费金额。表示在当前餐次中再次消费的金额
      * @return 返回一个泛型为 ErrorInfo 的结果对象 R<ErrorInfo>。
-     * 如果未超出限制,返回成功结果;
-     * 如果超出限制,返回包含错误信息的结果(例如超限的具体原因)。
+     *         如果未超出限制,返回成功结果;
+     *         如果超出限制,返回包含错误信息的结果(例如超限的具体原因)。
      */
-    private R<ErrorInfo> checkMealQuota(RemoteQuotaVo quotaVo, String mealType, BigDecimal mealMoney, BigDecimal consumeMoney) {
+    private R<ErrorInfo> checkMealQuota(RemoteQuotaVo quotaVo, String mealType, BigDecimal mealMoney,BigDecimal consumeMoney) {
         Map<String, BigDecimal> mealQuotas = Map.of(
             "1", quotaVo.getOneMoney(),
             "2", quotaVo.getTwoMoney(),
@@ -470,7 +371,7 @@ public class CardConsumeValidation {
             return null;
         }
 
-        if (mealQuota.compareTo(BigDecimal.ZERO) > 0) {
+        if (mealQuota.compareTo(BigDecimal.ZERO)>0) {
             if (mealQuota.compareTo(mealMoney.add(consumeMoney)) < 0) {
                 String mealName = MEAL_TYPE_NAMES.getOrDefault(mealType, "未知餐次");
                 return commonCheck.createError(TradeStatusEnum.MealLimitMoney, String.format("卡类%s额度限制", mealName));

+ 93 - 207
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/check/CommonCheck.java

@@ -22,6 +22,7 @@ import org.dromara.common.json.utils.JsonUtils;
 import org.dromara.common.redis.utils.RedisUtils;
 import org.dromara.server.common.domain.consume.bo.ConsumptionBo;
 import org.dromara.server.consume.business.BaseBusiness;
+import org.dromara.server.consume.business.InitBusiness;
 import org.dromara.server.consume.domain.vo.XfCardLimitedVo;
 import org.dromara.server.consume.domain.vo.XfTermVo;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@@ -33,7 +34,6 @@ import java.time.Duration;
 import java.util.*;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Supplier;
 
@@ -50,7 +50,7 @@ import java.util.function.Supplier;
 @Service
 @RequiredArgsConstructor
 public class CommonCheck {
-    // 用户校验模式 0-userId 1- userNo
+    // 用户校验模式 0-userId 1- userNo 2-userNumb
     private static final Integer userIdMode = 0;
     private static final Integer userNoMode = 1;
     private static final Integer userNumbMode = 2;
@@ -61,9 +61,11 @@ public class CommonCheck {
     private static final long VALIDATION_TIMEOUT = 300;
 
     private final BaseBusiness baseBusiness;
+    private final InitBusiness initBusiness;
     private final ThreadPoolTaskExecutor taskExecutor;
 
     //region 账户、卡片与设备验证
+
     /**
      * 账户、设备有效性验证
      *
@@ -71,7 +73,7 @@ public class CommonCheck {
      * @return 校验结果,包含错误信息或成功标识
      */
     public R<ErrorInfo> consumeValidation(AllowConsumeValidationContext ctx) {
-        // 2. 执行异步验证链
+        // 1. 执行异步验证链
         R<ErrorInfo> result = executeTermValidationChain(ctx);
         if (R.isError(result)) {
             return result;
@@ -89,41 +91,30 @@ public class CommonCheck {
         // 创建验证任务列表
         List<Supplier<R<ErrorInfo>>> validationTasks = new ArrayList<>();
 
-        AllowConsumeValidationContext termCtx = AllowConsumeValidationContext.create(ctx.getBo());
-        AllowConsumeValidationContext userAccountCtx = AllowConsumeValidationContext.create(ctx.getBo());
-
-        // checkUserAccount(userAccountCtx);
-
         validationTasks.add(() -> checkParam(ctx));
-        validationTasks.add(() -> checkTerm(termCtx));
-        validationTasks.add(() -> checkUserAccount(userAccountCtx));
+        validationTasks.add(() -> checkTerm(ctx));
+        validationTasks.add(() -> checkUserAccount(ctx));
 
         // 用于存储第一个错误结果
         AtomicReference<R<ErrorInfo>> firstError = new AtomicReference<>(null);
+
         // 使用CountDownLatch跟踪任务完成
         CountDownLatch latch = new CountDownLatch(validationTasks.size());
-        AtomicBoolean cancelled = new AtomicBoolean(false);
 
         // 提交所有验证任务
-        for (int i = 0, j = validationTasks.size(); i < j; i++) {
-            final int taskIndex = i;
-            final Supplier<R<ErrorInfo>> task = validationTasks.get(taskIndex);
+        for (Supplier<R<ErrorInfo>> task : validationTasks) {
             taskExecutor.execute(() -> {
-                if (cancelled.get()) {
-                    latch.countDown();
-                    return;
-                }
                 try {
                     R<ErrorInfo> result = task.get();
                     // 如果发现错误且尚未设置错误结果
-                    if (result != null && R.isError(result) && firstError.compareAndSet(null, result)) {
-                        log.warn("任务 {} 验证失败: {}", getTaskName(taskIndex), result);
-                        triggerCancellation(cancelled, taskIndex);
+                    if (result != null && R.isError(result) &&
+                        firstError.compareAndSet(null, result)) {
+                        // 取消其他任务(通过中断)
+                        taskExecutor.getThreadPoolExecutor().getQueue().clear();
                     }
                 } catch (Exception e) {
-                    log.error("任务 {} 执行异常", getTaskName(taskIndex), e);
                     if (firstError.compareAndSet(null, createError(TradeStatusEnum.SysError))) {
-                        triggerCancellation(cancelled, taskIndex);
+                        taskExecutor.getThreadPoolExecutor().getQueue().clear();
                     }
                 } finally {
                     latch.countDown();
@@ -134,98 +125,17 @@ public class CommonCheck {
         try {
             // 等待所有任务完成或超时
             if (!latch.await(VALIDATION_TIMEOUT, TimeUnit.MILLISECONDS)) {
-                log.warn("验证任务超时 ({} ms)", VALIDATION_TIMEOUT);
-                triggerCancellation(cancelled, -1);
+                return createError(TradeStatusEnum.VALIDATION_TIMEOUT);
             }
+
+            // 返回第一个发现的错误,如果没有错误则返回成功
+            return firstError.get() != null ? firstError.get() : R.ok();
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
-            log.error("等待任务完成时被中断", e);
-            // 检查是否有部分成功的结果
-            if (firstError.get() != null) {
-                return firstError.get();
-            }
+            log.error("error:{}", e.getMessage(), e);
             return createError(TradeStatusEnum.SysError);
         }
-
-        // 返回第一个发现的错误,如果没有错误则返回成功
-        if (firstError.get() != null) {
-            return firstError.get();
-        }
-
-        mergeValidationResults(ctx, termCtx, userAccountCtx);
-        return R.ok();
-    }
-
-    private void triggerCancellation(AtomicBoolean cancelled, int triggerTask) {
-        // 确保只触发一次取消操作
-        if (cancelled.compareAndSet(false, true)) {
-            // 记录触发取消的任务信息
-            String taskName = getTaskName(triggerTask);
-            if (triggerTask >= 0) {
-                log.warn("任务 [{}] 触发取消操作: {}", triggerTask, taskName);
-            } else {
-                log.warn("超时触发取消操作");
-            }
-
-            // 清空任务队列(取消未开始的任务)
-            int cancelledCount = taskExecutor.getThreadPoolExecutor().getQueue().size();
-            taskExecutor.getThreadPoolExecutor().getQueue().clear();
-            log.info("已取消 {} 个待执行任务", cancelledCount);
-
-            // 中断正在运行的任务
-            // 获取所有活动线程
-            Set<Thread> activeThreads = Thread.getAllStackTraces().keySet();
-            String threadPoolPrefix = taskExecutor.getThreadNamePrefix();
-
-            int interruptedCount = 0;
-
-            for (Thread thread : activeThreads) {
-                // 只中断本线程池创建的线程
-                if (thread.getName().startsWith(threadPoolPrefix)) {
-                    if (!thread.isInterrupted()) {
-                        thread.interrupt();
-                        interruptedCount++;
-                        log.debug("已发送中断信号给线程: {}", thread.getName());
-                    }
-                }
-            }
-
-            log.info("已向 {} 个运行中的任务发送中断信号", interruptedCount);
-        }
-
-    }
-
-    private void mergeValidationResults(AllowConsumeValidationContext mainCtx,
-                                        AllowConsumeValidationContext termCtx,
-                                        AllowConsumeValidationContext accountCtx) {
-        // 合并终端验证结果
-        if (termCtx.getUseTermVo() != null) {
-            mainCtx.setUseTermVo(termCtx.getUseTermVo());
-        }
-
-        // 合并账户验证结果
-        if (accountCtx.getUserCardVo() != null) {
-            mainCtx.setUserCardVo(accountCtx.getUserCardVo());
-        }
-        if (accountCtx.getUserAccountVo() != null) {
-            mainCtx.setUserAccountVo(accountCtx.getUserAccountVo());
-        }
-        if (accountCtx.getBo() != null) {
-            mainCtx.setBo(accountCtx.getBo());
-        }
-        // 参数验证不需要合并
-        log.debug("验证结果已合并到主上下文");
-    }
-
-    private String getTaskName(int taskIndex) {
-        return switch (taskIndex) {
-            case 0 -> "参数验证";
-            case 1 -> "终端验证";
-            case 2 -> "账户验证";
-            default -> "未知任务";
-        };
     }
-    //endregion
 
     // region 消费参数校验
 
@@ -238,33 +148,21 @@ public class CommonCheck {
      * @return 校验结果,包含错误信息或成功标识
      */
     public R<ErrorInfo> checkParam(AllowConsumeValidationContext ctx) {
-        if (Thread.currentThread().isInterrupted()) {
-            log.debug("参数验证任务被取消,提前退出");
+        // 1. 校验设备标识参数
+        if (isTerminalInvalid(ctx)) {
             return createErrorResponse(1, ApiErrorTypeConstants.PARAM_ERROR,
-                "参数验证任务被取消,提前退出", "参数验证任务被取消,提前退出");
+                "设备机号不正确", "设备机号必须大于零或MAC地址不能为空!");
         }
-        try {
-            // 1. 校验设备标识参数
-            if (isTerminalInvalid(ctx)) {
-                return createErrorResponse(1, ApiErrorTypeConstants.PARAM_ERROR,
-                    "设备机号不正确", "设备机号必须大于零或MAC地址不能为空!");
-            }
-
-            // 2. 校验用户标识参数
-            if (isUserIdentifierInvalid(ctx)) {
-                return createErrorResponse(1, ApiErrorTypeConstants.PARAM_ERROR,
-                    "交易人员标识不满足",
-                    "必须提供 [CardNo | FactoryId | userNo | userNumb]  中至少1项来标识交易用户");
-            }
 
-            // 3. 所有参数校验通过
-            return R.ok();
-        } catch (Exception e) {
-            Thread.currentThread().interrupt();
-            log.debug("参数验证任务异常", e);
+        // 2. 校验用户标识参数
+        if (isUserIdentifierInvalid(ctx)) {
             return createErrorResponse(1, ApiErrorTypeConstants.PARAM_ERROR,
-                "参数验证任务异常", e.getMessage());
+                "交易人员标识不满足",
+                "必须提供 [CardNo | FactoryId | userNo | userNumb]  中至少1项来标识交易用户");
         }
+
+        // 3. 所有参数校验通过
+        return R.ok();
     }
 
     /**
@@ -303,48 +201,43 @@ public class CommonCheck {
      * @return 检查结果
      */
     public R<ErrorInfo> checkTerm(AllowConsumeValidationContext ctx) {
-        if (Thread.currentThread().isInterrupted()) {
-            log.debug("设备验证任务被取消,提前退出");
-            return createErrorResponse(1, ApiErrorTypeConstants.PARAM_ERROR,
-                "设备验证任务被取消,提前退出", "设备证任务被取消,提前退出");
-        }
-        try {
-            String msgInfo = ObjectUtil.isEmpty(ctx.getTermMac()) ? ctx.getTermNo().toString() : ctx.getTermMac();
-            // 先从缓存获取数据
-            List<XfTermVo> list = RedisUtils.getCacheList(CacheNames.PT_TERM_LIST);
+        String msgInfo = ObjectUtil.isEmpty(ctx.getTermMac()) ? ctx.getTermNo().toString() : ctx.getTermMac();
+        // 先从缓存获取数据
+        List<XfTermVo> list = RedisUtils.getCacheList(CacheNames.PT_TERM_LIST);
+        if (CollectionUtil.isEmpty(list)) {
+            // 如果第一次没有从缓存中取到,则使用数据库初始化下
+            initBusiness.initTermInfo();
+            list = RedisUtils.getCacheList(CacheNames.PT_TERM_LIST);
             if (CollectionUtil.isEmpty(list)) {
+                // 如果执行了初始化还没有数据,则返回错误
                 return createErrorResponse(1, ApiErrorTypeConstants.OBJECT_NOT_EXISTS,
                     "未获取到设备数据",
                     "获取消费设备失败");
             }
-            XfTermVo termVo;
-            String mac = ctx.getTermMac();
-            Long termNo = ctx.getTermNo();
-            if (ObjectUtil.isNotEmpty(mac)) {
-                termVo = list.stream().filter(x -> ObjectUtil.equals(x.getTermMac(), mac)).findFirst().orElse(null);
-            } else {
-                termVo = list.stream().filter(x -> ObjectUtil.equals(x.getTermNo(), termNo)).findFirst().orElse(null);
-            }
-            if (ObjectUtil.isEmpty(termVo)) {
-                return createErrorResponse(400, ApiErrorTypeConstants.OBJECT_NOT_EXISTS,
-                    "设备不存在",
-                    MessageFormat.format("机号或MAC为[{0}]的设备不存在,不允许交易", msgInfo));
-            }
-            // 因为后续处理都是用的机号,如果消费机上传的是mac地址,则将termNo更新到消费业务对象
-            if (termVo != null) {
-                ctx.getBo().setTermNo(termVo.getTermNo());
-                ctx.getBo().setTermName(termVo.getTermName());
-            }
-            // 将消费机数据复制提供后续业务使用
-            ctx.setUseTermVo(termVo);
+        }
 
-            return R.ok();
-        } catch (Exception e) {
-            Thread.currentThread().interrupt();
-            log.debug("终端验证任务异常", e);
-            return createErrorResponse(1, ApiErrorTypeConstants.PARAM_ERROR,
-                "终端验证任务异常", e.getMessage());
+        XfTermVo termVo;
+        String mac = ctx.getTermMac();
+        Long termNo = ctx.getTermNo();
+        if (ObjectUtil.isNotEmpty(mac)) {
+            termVo = list.stream().filter(x -> ObjectUtil.equals(x.getTermMac(), mac)).findFirst().orElse(null);
+        } else {
+            termVo = list.stream().filter(x -> ObjectUtil.equals(x.getTermNo(), termNo)).findFirst().orElse(null);
+        }
+        if (ObjectUtil.isEmpty(termVo)) {
+            return createErrorResponse(400, ApiErrorTypeConstants.OBJECT_NOT_EXISTS,
+                "设备不存在",
+                MessageFormat.format("机号或MAC为[{0}]的设备不存在,不允许交易", msgInfo));
+        }
+        // 因为后续处理都是用的机号,如果消费机上传的是mac地址,则将termNo更新到消费业务对象
+        if (termVo != null) {
+            ctx.getBo().setTermNo(termVo.getTermNo());
+            ctx.getBo().setTermName(termVo.getTermName());
         }
+        // 将消费机数据复制提供后续业务使用
+        ctx.setUseTermVo(termVo);
+
+        return R.ok();
     }
     // endregion
 
@@ -357,33 +250,21 @@ public class CommonCheck {
      * @return 如果校验失败,则返回包含错误信息的 R 对象;如果校验成功,则返回表示成功的 R 对象
      */
     public R<ErrorInfo> checkUserAccount(AllowConsumeValidationContext ctx) {
-        if (Thread.currentThread().isInterrupted()) {
-            log.debug("账户与卡片验证任务被取消,提前退出");
-            return createErrorResponse(1, ApiErrorTypeConstants.PARAM_ERROR,
-                "账户与卡片验证任务被取消,提前退出", "账户与卡片证任务被取消,提前退出");
-        }
-        try {
-            long cardNo = ObjectUtil.isEmpty(ctx.getCardNo()) ? 0 : ctx.getCardNo();
-            long userNo = ObjectUtil.isEmpty(ctx.getUserNo()) ? 0 : ctx.getUserNo();
-            String userNumb = ObjectUtil.isEmpty(ctx.getUserNumb()) ? null : ctx.getUserNumb();
+        long cardNo = ObjectUtil.isEmpty(ctx.getCardNo()) ? 0 : ctx.getCardNo();
+        long userNo = ObjectUtil.isEmpty(ctx.getUserNo()) ? 0 : ctx.getUserNo();
+        String userNumb = ObjectUtil.isEmpty(ctx.getUserNumb()) ? null : ctx.getUserNumb();
 
-            // 如果卡流水号>0验证卡信息
-            if (cardNo > 0) {
-                return checkCardNo(ctx);
-            }
-            if (userNo > 0) {
-                return checkUserNo(ctx);
-            }
-            if (ObjectUtil.isNotEmpty(userNumb)) {
-                return checkUserNumb(ctx);
-            }
-            return R.ok();
-        } catch (Exception e) {
-            Thread.currentThread().interrupt();
-            log.debug("账户与卡片验证任务异常", e);
-            return createErrorResponse(1, ApiErrorTypeConstants.PARAM_ERROR,
-                "账户与卡片验证任务异常", e.getMessage());
+        // 如果卡流水号>0验证卡信息
+        if (cardNo > 0) {
+            return checkCardNo(ctx);
         }
+        if (userNo > 0) {
+            return checkUserNo(ctx);
+        }
+        if (ObjectUtil.isNotEmpty(userNumb)) {
+            return checkUserNumb(ctx);
+        }
+        return R.ok();
     }
 
     /**
@@ -410,8 +291,8 @@ public class CommonCheck {
 
         }
         // 获取消费账户信息
-        String userId = String.valueOf(ctx.getUserCardVo().getUserId());
-        result = checkUser(userId, userIdMode, ctx);
+        String strUserId = String.valueOf(ctx.getUserCardVo().getUserId());
+        result = checkUser(strUserId, userIdMode, ctx);
         if (R.isError(result)) {
             return result;
         }
@@ -435,19 +316,11 @@ public class CommonCheck {
             return result;
         }
         // 校验卡片信息
-        Long userId = ctx.getUserAccountVo().getUserId();
-        result = checkCard(userId, cardIdMode, ctx);
-        if (R.isError(result)) {
-            return result;
-        }
-        // 更新bo中部分值息
-        setCheckAfterAccountData(ctx);
-
-        return R.ok();
+        return checkCardAfterUser(ctx);
     }
 
     /**
-     * 根据用户编号校验账户是否可以消费。
+     * 根据用户编号号校验账户是否可以消费。
      *
      * @param ctx 消费有效性校验上下文,包含消费相关的基础信息(如用户流水号、消费金额等)
      * @return 如果校验失败,则返回包含错误信息的 R 对象;如果校验成功,则返回表示成功的 R 对象
@@ -460,6 +333,12 @@ public class CommonCheck {
             return result;
         }
         // 校验卡片信息
+        return checkCardAfterUser(ctx);
+
+    }
+
+    private R<ErrorInfo> checkCardAfterUser(AllowConsumeValidationContext ctx) {
+        R<ErrorInfo> result;
         Long userId = ctx.getUserAccountVo().getUserId();
         result = checkCard(userId, cardIdMode, ctx);
         if (R.isError(result)) {
@@ -470,6 +349,7 @@ public class CommonCheck {
 
         return R.ok();
     }
+
     /**
      * 校验用户账户信息是否符合交易条件。
      * 该方法会检查账户是否存在、是否被冻结、状态是否正常、是否已开户以及是否过期。
@@ -484,7 +364,7 @@ public class CommonCheck {
         // 1. 从缓存获取账户信息
         RemoteUserAccountVo accountVo = getAccountFromCache(checkParam, checkMode);
         // 账户不存在,不允许交易
-        if (ObjectUtil.isEmpty(accountVo)) {
+        if (accountVo == null) {
             return createErrorResponse(400, ApiErrorTypeConstants.NOT_FOUND,
                 "账户不存在",
                 MessageFormat.format("流水号或Id为[{0}]的账户不存在,不允许交易", checkParam));
@@ -532,7 +412,7 @@ public class CommonCheck {
     private R<ErrorInfo> checkCard(Long checkParam, Integer checkMode, AllowConsumeValidationContext ctx) {
         RemoteCardVo cardVo = getCardFromCache(checkParam, checkMode);
         // 卡片不存在,不允许消费
-        if (ObjectUtil.isEmpty(cardVo)) {
+        if (cardVo == null) {
             return createErrorResponse(400, ApiErrorTypeConstants.CARD_NOT_EXISTS,
                 "卡片不存在",
                 MessageFormat.format("流水号或用户Id或物理卡号为[{0}]的卡片不存在,不允许交易", checkParam));
@@ -558,9 +438,15 @@ public class CommonCheck {
      * @return 账户信息对象
      */
     private RemoteUserAccountVo getAccountFromCache(String checkParam, Integer checkMode) {
-        List<RemoteUserAccountVo> list = RedisUtils.getCacheList(CacheNames.PT_USER_ACCOUNT_List);
+        List<RemoteUserAccountVo> list = RedisUtils.getCacheList(CacheNames.PT_USER_ACCOUNT_LIST);
         if (CollectionUtil.isEmpty(list)) {
-            return null;
+            // 如果缓存没有,初始化
+            initBusiness.initUserAccount();
+            list = RedisUtils.getCacheList(CacheNames.PT_USER_ACCOUNT_LIST);
+            // 初始化后还没有,返回空
+            if (CollectionUtil.isEmpty(list)) {
+                return null;
+            }
         }
         Long tempValue = Long.valueOf(checkParam);
         if (checkMode.equals(userIdMode)) {

+ 15 - 15
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/check/ConsumeRequestCheck.java

@@ -2,6 +2,7 @@ package org.dromara.server.consume.check;
 
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSONUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.dromara.backstage.api.domain.vo.RemoteCardVo;
@@ -74,8 +75,8 @@ public class ConsumeRequestCheck {
         RemoteMealTypeVo remoteMealTypeVo = commonCheck.getMealType(consumeDate);
         if (ObjectUtil.isEmpty(remoteMealTypeVo)) {
             return commonCheck.createErrorResponse(400, ApiErrorTypeConstants.NOT_FOUND, "不在交易时段",
-                MessageFormat.format("非营业时段,不允许交易。消费时间[{0}]",
-                    DateUtil.format(consumeDate, "HH:mm:ss")));
+                                                   MessageFormat.format("非营业时段,不允许交易。消费时间[{0}]",
+                                                                        DateUtil.format(consumeDate, "HH:mm:ss")));
         }
         // 设置消费记录的当前餐类
         bo.setMealType(Long.valueOf(remoteMealTypeVo.getTypeId()));
@@ -83,7 +84,7 @@ public class ConsumeRequestCheck {
         XfCardLimitedVo xfCardLimitedVo = new XfCardLimitedVo();
         int statusFlag = bo.getStatusFlag();
         if (statusFlag == Integer.parseInt(ConsumeRecordTypeEnum.XFJXF_1.code())
-            || statusFlag == Integer.parseInt(ConsumeRecordTypeEnum.XFJXF_4.code())) {
+                || statusFlag == Integer.parseInt(ConsumeRecordTypeEnum.XFJXF_4.code())) {
 
             // 设备是否可以消费验证
             result = checkTermLimitedAndOther(bo, useTermVo, userCardVo, remoteMealTypeVo);
@@ -106,7 +107,7 @@ public class ConsumeRequestCheck {
         return R.ok();
     }
 
-    private R<ErrorInfo> obtainResult(R<ErrorInfo> result) {
+    private  R<ErrorInfo> obtainResult(R<ErrorInfo> result){
         ErrorInfo data = result.getData();
         String details = Optional.ofNullable(data).map(ErrorInfo::getDetils).orElse("超过消费限制");
         String msg = Optional.ofNullable(data).map(ErrorInfo::getMessage).orElse("消费限制判断存在问题");
@@ -151,7 +152,7 @@ public class ConsumeRequestCheck {
         }
         if (consumeMoney.compareTo(totalBalance) > 0) {
             return commonCheck.createErrorResponse(400, ApiErrorTypeConstants.CONSUME_CHECK_FAIL, "账户余额不足",
-                MessageFormat.format("总余额[{0}],消费金额[{1}]", totalBalance, consumeMoney));
+                                                   MessageFormat.format("总余额[{0}],消费金额[{1}]", totalBalance, consumeMoney));
         }
         // 计算扣费后的余额
         BigDecimal balance = totalBalance.subtract(consumeMoney);
@@ -179,11 +180,11 @@ public class ConsumeRequestCheck {
         String originalId = bo.getOriginalId();
         if (ObjectUtil.isEmpty(originalId)) {
             originalId = RecordIdUtils.getRecordId(bo.getConsumeDate(), bo.getTermNo().shortValue(),
-                bo.getTermRecordId().shortValue(), bo.getUserNo().shortValue(), 0);
+                                                   bo.getTermRecordId().shortValue(), bo.getUserNo().shortValue(), 0);
         }
         if (originalIdSet.contains(originalId)) {
             return commonCheck.createErrorResponse(400, ApiErrorTypeConstants.CONSUME_CHECK_FAIL, "原始消费记录存在",
-                MessageFormat.format("原始消费记录已存在:{0}", originalId));
+                                                   MessageFormat.format("原始消费记录已存在:{0}", originalId));
         }
         bo.setOriginalId(originalId);
 
@@ -226,9 +227,9 @@ public class ConsumeRequestCheck {
      */
     private void initializeCardData(RemoteCardVo cardVo, RemoteMealTypeVo mealVo) {
         LocalDateTime now = LocalDateTime.now();
+        // 如果卡片没有最后支付日期,默认设置为前一天
         LocalDateTime beforeTime = LocalDateTime.now().plusDays(-1);
         LocalDateTime lastPay = cardVo.getLastPay() == null ? beforeTime : CardDateUtils.toLocalDateTime(cardVo.getLastPay());
-
         // 餐类数据初始化
         boolean sameMeal = mealVo.getTypeId().equals(cardVo.getLastMeal().toString());
         boolean sameDay = now.toLocalDate().equals(lastPay.toLocalDate());
@@ -237,7 +238,6 @@ public class ConsumeRequestCheck {
             cardVo.setMealCount(0L);
             cardVo.setMealTotal(BigDecimal.ZERO);
         }
-
         // 日消费数据初始化
         if (!sameDay) {
             cardVo.setDayCount(0L);
@@ -286,7 +286,7 @@ public class ConsumeRequestCheck {
                     R<ErrorInfo> result = task.get();
                     // 如果发现错误且尚未设置错误结果
                     if (result != null && R.isError(result) &&
-                        firstError.compareAndSet(null, result)) {
+                            firstError.compareAndSet(null, result)) {
                         // 取消其他任务(通过中断)
                         taskExecutor.getThreadPoolExecutor().getQueue().clear();
                     }
@@ -322,30 +322,30 @@ public class ConsumeRequestCheck {
         long intervalMin = (currentSec - lastPaySec) / 60;
 
         return intervalMin < ctx.getTermSwipeInterval() ?
-            commonCheck.createError(TradeStatusEnum.TimeInterval) : null;
+                   commonCheck.createError(TradeStatusEnum.TimeInterval) : null;
     }
 
     private R<ErrorInfo> validateSingleLimit(TermConsumeValidationContext ctx) {
         if (ctx.getTermSingleMoney().compareTo(BigDecimal.ZERO) <= 0) return null;
         return ctx.getConsumeValue().compareTo(ctx.getTermSingleMoney()) > 0 ?
-            commonCheck.createError(TradeStatusEnum.OnceBigMoney) : null;
+                   commonCheck.createError(TradeStatusEnum.OnceBigMoney) : null;
     }
 
     private R<ErrorInfo> validateCardValidity(TermConsumeValidationContext ctx) {
         if (ctx.getFactoryId() == 0 || !ctx.isTermUseValidity()) return null;
         return ctx.getCurrentTime().isAfter(ctx.getExpiryTime()) ?
-            commonCheck.createError(TradeStatusEnum.CardValidDate) : null;
+                   commonCheck.createError(TradeStatusEnum.CardValidDate) : null;
     }
 
     private R<ErrorInfo> validateCardType(TermConsumeValidationContext ctx) {
         int mask = 1 << (ctx.getCardType() - 1);
         return (mask & ctx.getTermCardType()) == 0 ?
-            commonCheck.createError(TradeStatusEnum.CardTypeLimit) : null;
+                   commonCheck.createError(TradeStatusEnum.CardTypeLimit) : null;
     }
 
     private R<ErrorInfo> validateMealLimit(TermConsumeValidationContext ctx) {
         return ctx.getTermMealCount() > 0 && ctx.getMealCount() >= ctx.getTermMealCount() ?
-            commonCheck.createError(TradeStatusEnum.MealLimitTimes) : null;
+                   commonCheck.createError(TradeStatusEnum.MealLimitTimes) : null;
     }
 
     private R<ErrorInfo> validateDailyLimit(TermConsumeValidationContext ctx) {

+ 2 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/IPtBagService.java

@@ -110,5 +110,7 @@ public interface IPtBagService {
     BigDecimal getUserBalance(Long userId);
 
     void updateConsumeBalance(List<PtBagVo> bagVos);
+
+    List<PtBagVo> selectBalanceBag();
     // boolean updateBalanceByByConsume(PtBagBo bo);
 }

+ 9 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/service/impl/PtBagServiceImpl.java

@@ -330,6 +330,15 @@ public class PtBagServiceImpl implements IPtBagService {
         }
     }
 
+    @Override
+    public List<PtBagVo> selectBalanceBag() {
+        LambdaQueryWrapper<PtBag> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.in(PtBag::getBagCode, Arrays.asList("1", "3"));
+        queryWrapper.select(PtBag::getBalance,PtBag::getUserId);
+
+        return baseMapper.selectVoList(queryWrapper);
+    }
+
     /**
      * 组装充值钱包数据
      * 1.设置充值后余额=账户原余额+充值金额

+ 8 - 7
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/task/InitTasks.java

@@ -32,13 +32,14 @@ public class InitTasks implements ApplicationRunner {
     public void run(ApplicationArguments args) throws Exception {
         log.info("初始化消费验证基础数据");
         long startTime = System.currentTimeMillis();
-        // initBusiness.initGlobalData();
-        // initBusiness.initTermInfo();
-        // initBusiness.initMealTypeInfo();
-        // initBusiness.initDiscountAndOther();
-        // initBusiness.initUserCard();
-        // initBusiness.initUserAccount();
-        // initBusiness.initXfCardLimited();
+        initBusiness.initGlobalData();
+        initBusiness.initTermInfo();
+        initBusiness.initMealTypeInfo();
+        initBusiness.initDiscountAndOther();
+        initBusiness.initUserCard();
+        initBusiness.initUserAccount();
+        initBusiness.initXfCardLimited();
+        initBusiness.initUserBalance();
         validationParam.refresh();
 
         log.info("初始化消费验证基础数据完成。耗时:{} ms", System.currentTimeMillis() - startTime);

+ 5 - 9
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/task/ScheduledTasks.java

@@ -70,21 +70,17 @@ public class ScheduledTasks {
 
     @Scheduled(cron = "0 0 4 * * ?")
     public void initDiscountAndOther() {
-        ThreadUtil.execAsync(baseBusiness::initGlobalData);
-        ThreadUtil.execAsync(baseBusiness::initDiscountAndOther);
-        ThreadUtil.execAsync(baseBusiness::initTermInfo);
-        ThreadUtil.execAsync(baseBusiness::initMealTypeInfo);
-    }
-
-    @Scheduled(cron = "0 30 4 * * ?")
-    public void initValidationParam() {
+        baseBusiness.initGlobalData();
+        baseBusiness.initDiscountAndOther();
+        baseBusiness.initTermInfo();
+        baseBusiness.initMealTypeInfo();
         validationParam.refresh();
     }
-
     @Scheduled(cron = "0 0 5,9,13,16,20 * * ?")
     public void initConsumeInfo() {
         ThreadUtil.execAsync(baseBusiness::initXfCardLimited);
         ThreadUtil.execAsync(baseBusiness::initUserCard);
         ThreadUtil.execAsync(baseBusiness::initUserAccount);
+        ThreadUtil.execAsync(baseBusiness::initUserBalance);
     }
 }