Browse Source

Merge remote-tracking branch 'origin/master'

ct 4 ngày trước cách đây
mục cha
commit
6f509400ae
25 tập tin đã thay đổi với 617 bổ sung132 xóa
  1. 94 0
      fs-admin/src/main/java/com/fs/qw/FsCourseTask.java
  2. 11 1
      fs-framework/src/main/java/com/fs/framework/web/exception/GlobalExceptionHandler.java
  3. 2 0
      fs-service/src/main/java/com/fs/company/service/ICompanyConfigService.java
  4. 38 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyConfigServiceImpl.java
  5. 15 24
      fs-service/src/main/java/com/fs/core/config/WxMaConfiguration.java
  6. 9 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseRedPacketLog.java
  7. 4 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodServiceImpl.java
  8. 142 83
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  9. 8 4
      fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java
  10. 5 0
      fs-service/src/main/java/com/fs/hisStore/param/FsStoreOrderPayParam.java
  11. 1 0
      fs-service/src/main/java/com/fs/hisStore/param/FsStorePaymentPayParam.java
  12. 22 8
      fs-service/src/main/java/com/fs/system/service/impl/SysConfigServiceImpl.java
  13. 88 0
      fs-service/src/main/resources/application-config-druid-hst.yml
  14. 2 0
      fs-service/src/main/resources/application-config-druid-qdtst.yml
  15. 145 0
      fs-service/src/main/resources/application-druid-hst.yml
  16. 1 1
      fs-service/src/main/resources/application-druid-qdtst.yml
  17. 6 0
      fs-service/src/main/resources/mapper/course/FsCourseRedPacketLogMapper.xml
  18. 3 1
      fs-user-app/src/main/java/com/fs/app/controller/InquiryOrderController.java
  19. 1 1
      fs-user-app/src/main/java/com/fs/app/controller/course/CourseQwController.java
  20. 4 4
      fs-user-app/src/main/java/com/fs/app/controller/store/CourseH5ScrmController.java
  21. 2 2
      fs-user-app/src/main/java/com/fs/app/controller/store/CourseWxH5ScrmController.java
  22. 8 1
      fs-user-app/src/main/java/com/fs/app/controller/store/PaymentScrmController.java
  23. 3 0
      fs-user-app/src/main/java/com/fs/app/controller/store/StoreOrderScrmController.java
  24. 1 1
      fs-user-app/src/main/java/com/fs/app/controller/store/WxUserScrmController.java
  25. 2 1
      fs-user-app/src/main/resources/application.yml

+ 94 - 0
fs-admin/src/main/java/com/fs/qw/FsCourseTask.java

@@ -1,11 +1,27 @@
 package com.fs.qw;
 
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.redis.RedisCache;
 import com.fs.course.service.IFsCourseWatchLogService;
 import com.fs.qw.service.IQwWorkTaskService;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.mapper.SysConfigMapper;
+import io.jsonwebtoken.lang.Assert;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.http.util.Asserts;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
 /**
  * 后台统计相关 定时任务
  */
@@ -16,7 +32,85 @@ public class FsCourseTask {
     private IFsCourseWatchLogService fsCourseWatchLogService;
     @Autowired
     private IQwWorkTaskService qwWorkTaskService;
+    @Autowired
+    private RedisCache redisCache;
+    private static final String REDPACKET_COMPANY_MONEY_CHANGE = "redpacket_money_CHANGE";
+    @Autowired
+    private SysConfigMapper sysConfigMapper;
+    private static final String REDPACKET_POOL_LOCK = "redpacket_pool_lock";
+    private static final String REDPACKET_COMPANY_MONEY = "redpacket_money";
+
+    @Autowired
+    private RedissonClient redissonClient;
+
+    /**
+     * 润天公司账户充值
+     * @param chargeMoney 充值金额
+     */
+    public void rechargeRedpacketMoney(String chargeMoney){
+        Assert.notNull(chargeMoney,"充值金额不能为空!");
+
+        log.info("润天公司账户充值 充值金额: {}",chargeMoney);
+
+        RLock lock = redissonClient.getLock(REDPACKET_POOL_LOCK);
+        try{
+            boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
+
+            if (!locked) {
+                log.error("获取锁失败...");
+                return;
+            }
+
+            BigDecimal redPacketCompanyMoney = redisCache.getCacheObject(REDPACKET_COMPANY_MONEY);
+            if(ObjectUtils.isNull(redPacketCompanyMoney)){
+                redPacketCompanyMoney = BigDecimal.ZERO;
+            }
+            BigDecimal value = redPacketCompanyMoney.add(new BigDecimal(chargeMoney));
+
+            log.info("润天公司账户充值成功 目前余额: {}",value);
 
+            redisCache.setCacheObject(REDPACKET_COMPANY_MONEY,value);
+
+
+            // 保存到数据库
+            SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("company.money");
+
+            sysConfig.setConfigValue(value.setScale(4, RoundingMode.HALF_UP).toPlainString());
+            sysConfig.setConfigKey("company.money");
+            sysConfigMapper.updateConfig(sysConfig);
+
+        }catch (Exception e){
+            log.error("充值失败 原因:{}", ExceptionUtils.getFullStackTrace(e),e);
+            throw new RuntimeException(e);
+        }finally {
+            if (lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
+        }
+    }
+    /**
+     * 公司红包金额变更
+     */
+    public void redpacketCompanyMoneyChange(){
+        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("company.money");
+        Asserts.notNull(sysConfig,"公司账户配置不能为空!");
+
+        String configValue = sysConfig.getConfigValue();
+        Asserts.notNull(configValue,"公司账户余额不能为空");
+
+        BigDecimal oldBigDecimal = new BigDecimal(configValue);
+
+        BigDecimal redPacketCompanyMoney = redisCache.getCacheObject(REDPACKET_COMPANY_MONEY);
+
+        log.info("公司账户红包余额变更 {} -> {}",oldBigDecimal,redPacketCompanyMoney);
+
+        // 如果两者不一致才同步到数据库
+        if(oldBigDecimal.compareTo(redPacketCompanyMoney) != 0){
+            sysConfig.setConfigValue(redPacketCompanyMoney.setScale(4, RoundingMode.HALF_UP).toPlainString());
+            sysConfig.setConfigKey("company.money");
+            sysConfigMapper.updateConfig(sysConfig);
+        }
+    }
     /**
      * 添加企微观看日志
      * @throws Exception

+ 11 - 1
fs-framework/src/main/java/com/fs/framework/web/exception/GlobalExceptionHandler.java

@@ -1,6 +1,8 @@
 package com.fs.framework.web.exception;
 
 import javax.servlet.http.HttpServletRequest;
+
+import com.fs.common.exception.CustomException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.security.access.AccessDeniedException;
@@ -17,7 +19,7 @@ import com.fs.common.utils.StringUtils;
 
 /**
  * 全局异常处理器
- * 
+ *
 
  */
 @RestControllerAdvice
@@ -70,6 +72,14 @@ public class GlobalExceptionHandler
         return AjaxResult.error(e.getMessage());
     }
 
+    @ExceptionHandler(CustomException.class)
+    public AjaxResult handleCustomException(CustomException e, HttpServletRequest request)
+    {
+        String requestURI = request.getRequestURI();
+        log.error("请求地址'{}',发生未知异常.", requestURI, e);
+        return AjaxResult.error(e.getMessage());
+    }
+
     /**
      * 系统异常
      */

+ 2 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyConfigService.java

@@ -67,4 +67,6 @@ public interface ICompanyConfigService
     String selectConfigByKey(String configKey);
 
     CompanyConfig selectCompanyConfigByServerKey(String key);
+
+    String selectRedPacketConfigByKey(Long companyId);
 }

+ 38 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyConfigServiceImpl.java

@@ -8,10 +8,15 @@ import com.fs.company.domain.CompanyConfig;
 import com.fs.company.mapper.CompanyConfigMapper;
 import com.fs.company.service.ICompanyConfigService;
 import com.fs.system.domain.SysConfig;
+import org.apache.http.util.Asserts;
+import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
 
 import static com.fs.common.utils.DictUtils.getCacheKey;
 
@@ -28,6 +33,10 @@ public class CompanyConfigServiceImpl implements ICompanyConfigService
     private RedisCache redisCache;
     @Autowired
     private CompanyConfigMapper companyConfigMapper;
+    @Autowired
+    private RedisTemplate<String, String> redisTemplate; // 注入RedisTemplate
+    private static final String REDIS_KEY_PREFIX = "red_packet_config:";
+    private static final long CACHE_TIMEOUT = 24 * 60 * 60;
 
     /**
      * 查询参数配置
@@ -133,4 +142,33 @@ public class CompanyConfigServiceImpl implements ICompanyConfigService
     public CompanyConfig selectCompanyConfigByServerKey(String key) {
         return companyConfigMapper.selectCompanyConfigByServerKey(key);
     }
+
+    @Override
+    public String selectRedPacketConfigByKey(Long companyId) {
+        Asserts.notNull(companyId,"公司id不能为空!");
+        String redisKey = REDIS_KEY_PREFIX + companyId;
+        String cachedConfig = redisTemplate.opsForValue().get(redisKey);
+        if (cachedConfig != null) {
+            return cachedConfig;
+        }
+        synchronized (getSynchronizationObject(companyId)) {
+            cachedConfig = redisTemplate.opsForValue().get(redisKey);
+
+            if (cachedConfig != null) {
+                return cachedConfig;
+            }
+            String configFromDb = companyConfigMapper.selectRedPacketConfigByKey(companyId);
+            if (configFromDb != null) {
+                redisTemplate.opsForValue().set(redisKey, configFromDb, CACHE_TIMEOUT, TimeUnit.SECONDS);
+            } else {
+                redisTemplate.opsForValue().set(redisKey, "", 5 * 60, TimeUnit.SECONDS);
+            }
+            return configFromDb;
+        }
+    }
+
+    private static final ConcurrentHashMap<Long, Object> LOCKS = new ConcurrentHashMap<>();
+    private static Object getSynchronizationObject(Long companyId) {
+        return LOCKS.computeIfAbsent(companyId, k -> new Object());
+    }
 }

+ 15 - 24
fs-service/src/main/java/com/fs/core/config/WxMaConfiguration.java

@@ -33,8 +33,10 @@ import org.yaml.snakeyaml.events.Event;
 import javax.annotation.PostConstruct;
 import java.io.File;
 import java.util.ArrayList;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
 
 @Slf4j
@@ -97,20 +99,7 @@ public class WxMaConfiguration {
     }
 
     public static WxMaService getMaService(String appid) {
-        // 从缓存获取
-        WxMaService wxService = maServices.get(appid);
-        if (wxService != null) {
-            return wxService;
-        }
-
-        // 缓存未命中,查询数据库
-        synchronized (WxMaConfiguration.class) {
-            // 双重检查
-            wxService = maServices.get(appid);
-            if (wxService != null) {
-                return wxService;
-            }
-
+        return maServices.computeIfAbsent(appid,e->{
             // 查询数据库
             FsCoursePlaySourceConfigMapper configMapper = SpringUtils.getBean(FsCoursePlaySourceConfigMapper.class);
             Wrapper<FsCoursePlaySourceConfig> queryWrapper = Wrappers.<FsCoursePlaySourceConfig>lambdaQuery()
@@ -121,11 +110,8 @@ public class WxMaConfiguration {
                 throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
             }
 
-            WxMaService service = getWxMaService(config.getAppid(), config.getSecret(), config.getToken(), config.getAesKey(), config.getMsgDataFormat());
-            maServices.put(appid, service);
-            log.info("Initialized WxMaService for appid: {}", appid);
-            return service;
-        }
+            return getWxMaService(config.getAppid(), config.getSecret(), config.getToken(), config.getAesKey(), config.getMsgDataFormat());
+        });
     }
 
     /**
@@ -156,11 +142,16 @@ public class WxMaConfiguration {
         }
 
         maServices = configs.stream()
-            .map(a -> {
-                WxMaService service = getWxMaService(a.getAppid(), a.getSecret(), a.getToken(), a.getAesKey(), a.getMsgDataFormat());
-                routers.put(a.getAppid(), this.newRouter(service));
-                return service;
-            }).collect(Collectors.toMap(s -> s.getWxMaConfig().getAppid(), a -> a));
+                .map(a -> {
+                    WxMaService service = getWxMaService(a.getAppid(), a.getSecret(), a.getToken(), a.getAesKey(), a.getMsgDataFormat());
+                    routers.put(a.getAppid(), this.newRouter(service));
+                    return service;
+                }).collect(Collectors.toMap(
+                        s -> s.getWxMaConfig().getAppid(),
+                        a -> a,
+                        (existing, replacement) -> replacement,
+                        ConcurrentHashMap::new
+                ));
     }
 
     private WxMaMessageRouter newRouter(WxMaService service) {

+ 9 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseRedPacketLog.java

@@ -64,4 +64,13 @@ public class FsCourseRedPacketLog extends BaseEntity
 
     private String appId;//小程序appId
 
+    /**
+     * 账户余额扣减前
+     */
+    private BigDecimal accBalanceBefore;
+    /**
+     * 账户余额扣减后
+     */
+    private BigDecimal accBalanceAfter;
+
 }

+ 4 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodServiceImpl.java

@@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.common.exception.CustomException;
 import com.fs.common.exception.ServiceException;
 import com.fs.course.domain.FsUserCoursePeriod;
 import com.fs.course.domain.FsUserCoursePeriodDays;
@@ -114,6 +115,9 @@ public class FsUserCoursePeriodServiceImpl implements IFsUserCoursePeriodService
         }
 
         FsUserCoursePeriod fsUserCoursePeriod1 = fsUserCoursePeriodMapper.selectFsUserCoursePeriodById(fsUserCoursePeriod.getPeriodId());
+        if (!fsUserCoursePeriod1.getTrainingCampId().equals(fsUserCoursePeriod.getTrainingCampId())){
+            throw new CustomException("参数错误,请刷新后重试!");
+        }
         int flag = fsUserCoursePeriodMapper.updateFsUserCoursePeriod(fsUserCoursePeriod);
 
         // 2. 判定是否变更过开始时间(periodStartingTime)

+ 142 - 83
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -4,6 +4,7 @@ import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.core.domain.R;
@@ -22,6 +23,7 @@ import com.fs.company.mapper.CompanyMapper;
 import com.fs.company.mapper.CompanyMoneyLogsMapper;
 import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.company.service.ICompanyService;
+import com.fs.config.cloud.CloudHostProper;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.*;
 import com.fs.course.dto.CoursePackageDTO;
@@ -59,13 +61,20 @@ import com.fs.qwApi.service.QwApiService;
 import com.fs.sop.mapper.QwSopLogsMapper;
 import com.fs.sop.mapper.SopUserLogsInfoMapper;
 import com.fs.sop.service.ISopUserLogsInfoService;
+import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysDictDataMapper;
 import com.fs.system.service.ISysConfigService;
 import com.fs.voice.utils.StringUtil;
 import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
+import com.google.common.collect.Sets;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang.exception.ExceptionUtils;
 import org.apache.rocketmq.spring.core.RocketMQTemplate;
+import org.jetbrains.annotations.NotNull;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.redisson.client.RedisClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
@@ -81,6 +90,7 @@ import java.time.Instant;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
 import java.util.*;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.stream.Collectors;
@@ -103,6 +113,26 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     private Boolean isNewWxMerchant;
     private static final Logger logger = LoggerFactory.getLogger(FsUserCourseVideoServiceImpl.class);
 
+    /**
+     * 红包账户锁
+     */
+    private static final String REDPACKET_POOL_LOCK = "redpacket_pool_lock";
+
+    /**
+     * 公司红包金额
+     */
+    private static final String REDPACKET_COMPANY_MONEY = "redpacket_money";
+
+    /**
+     * 红包改变记录
+     */
+    private static final String REDPACKET_COMPANY_MONEY_CHANGE = "redpacket_money_change";
+
+    /**
+     * 是否开启红包账户扣减
+     */
+    @Value("${enableRedPackAccount:0}")
+    private String ENABLE_RED_PACK_ACCOUNT;
 
     private static final String miniappRealLink = "/pages_course/video.html?course=";
     private static final String REAL_LINK_PREFIX = "/courseH5/pages/course/learning?course=";
@@ -138,6 +168,8 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     private AsyncIsAddKfXfkService xfkService;
 
 
+    @Autowired
+    private RedissonClient redissonClient;
     @Autowired
     private QwExternalContactMapper qwExternalContactMapper;
     @Autowired
@@ -212,6 +244,9 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     @Autowired
     private FsCourseAnswerLogsMapper courseAnswerLogsMapper;
 
+    @Autowired
+    private CloudHostProper cloudHostProper;
+
 
     /**
      * 查询课堂视频
@@ -408,7 +443,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
     @Override
     public R isAddKf(FsUserCourseVideoAddKfUParam param) {
-        logger.info("zyp \n【判断添加客服】:{}",param);
+        logger.info("【判断添加客服】:{}",param);
         //查询用户
         FsUser fsUser = fsUserMapper.selectFsUserByUserId(param.getUserId());
         //用户不存在唤起重新授权
@@ -579,7 +614,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         log.setQwUserId(Long.valueOf(param.getQwUserId()));
         log.setCreateTime(new Date());
         log.setLogType(3);
-        logger.info("zyp \n【群聊生成看课记录】:{}",param);
+        logger.info("【群聊生成看课记录】:{}",param);
         courseWatchLogMapper.insertFsCourseWatchLog(log);
     }
 
@@ -774,7 +809,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     public R getInternetTraffic(FsUserCourseVideoFinishUParam param) {
         try {
             if (param.getBufferRate()==null){
-                logger.error("zyp \n【缓冲值空】参数: {}",param);
+                logger.error("【缓冲值空】参数: {}",param);
                 return R.error("缓冲值空");
             }
             FsCourseTrafficLog trafficLog = new FsCourseTrafficLog();
@@ -801,13 +836,13 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             // 处理 UUID 为空的情况
             if (StringUtils.isNotEmpty(trafficLog.getUuId())) {
                 // 直接插入或更新
-//                logger.error("zyp \n【插入或更新流量】:{}",trafficLog);
+//                logger.error("【插入或更新流量】:{}",trafficLog);
                 fsCourseTrafficLogMapper.insertOrUpdateTrafficLog(trafficLog);
             }
         } catch (Exception e) {
             e.printStackTrace();
             // 打印参数param和异常信息
-            logger.error("zyp \n【插入或更新流量失败】参数: {}, 错误信息:{}", param, e.getMessage(), e);
+            logger.error("【插入或更新流量失败】参数: {}, 错误信息:{}", param, e.getMessage(), e);
             return R.error();
         }
         return R.ok();
@@ -1043,13 +1078,12 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                 try {
                     handleFsUserWx(user,param.getAppId());
                 }catch (Exception e){
-                    logger.error("zyp \n 【更新或插入用户与小程序的绑定关系失败】:{}", user.getUserId());
+                    logger.error("【更新或插入用户与小程序的绑定关系失败】:{}", user.getUserId());
                 }
             }else {
                 packetParam.setOpenId(fsUserWx.getOpenId());
             }
             //查出公司绑定openid并赋值
-
         }
 
         //判断服务号配置是否存在
@@ -1063,104 +1097,126 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         packetParam.setAppId(param.getAppId());
         packetParam.setUser(user);
 
-        System.out.println("红包金额"+amount);
-        System.out.println("红包商户号"+packetParam);
+        logger.info("红包金额 {},红包商户号 {}",amount,packetParam);
         //2025.6.19 红包金额为0的时候
         if (amount.compareTo(BigDecimal.ZERO)>0){
 
-//            Company company = companyMapper.selectCompanyByIdForUpdate(param.getCompanyId());
-           // BigDecimal money = company.getMoney();
-         //   BigDecimal subtract = money.subtract(amount);
-//            if (subtract.compareTo(BigDecimal.ZERO)<0){
-//                FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
-//                redPacketLog.setCourseId(param.getCourseId());
-//                redPacketLog.setCompanyId(param.getCompanyId());
-//                redPacketLog.setUserId(param.getUserId());
-//                redPacketLog.setVideoId(param.getVideoId());
-//                redPacketLog.setStatus(2);
-//                redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
-//                redPacketLog.setCompanyUserId(param.getCompanyUserId());
-//                redPacketLog.setCreateTime(new Date());
-//                redPacketLog.setAmount(amount);
-//                redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
-//                redPacketLog.setPeriodId(param.getPeriodId());
-//                redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
-//                return R.error("余额不足请稍等");
-//            }
-            // 发送红包
-            R sendRedPacket = paymentService.sendRedPacket(packetParam);
-            if (sendRedPacket.get("code").equals(200)) {
-                FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
-                TransferBillsResult transferBillsResult;
-                if (sendRedPacket.get("isNew").equals(1)){
-                    transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
-                    redPacketLog.setResult(JSON.toJSONString(sendRedPacket));
-                    redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
-                }else {
-                    redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
+            //---------------发红包前先判断润天账户余额是否足够---------
+            RLock lock = redissonClient.getLock(REDPACKET_POOL_LOCK);
+            try{
+                boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
+
+                if (!locked) {
+                    logger.error("获取锁失败");
+                    return R.error("[红包领取] 系统繁忙,请重试!");
                 }
-                // 添加红包记录
-                redPacketLog.setCourseId(param.getCourseId());
-//            redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
-                redPacketLog.setCompanyId(param.getCompanyId());
-                redPacketLog.setUserId(param.getUserId());
-                redPacketLog.setVideoId(param.getVideoId());
-                redPacketLog.setStatus(0);
-                redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
-                redPacketLog.setCompanyUserId(param.getCompanyUserId());
-                redPacketLog.setCreateTime(new Date());
-                redPacketLog.setAmount(amount);
-                redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
-                redPacketLog.setPeriodId(param.getPeriodId());
-                redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
 
-                // 更新观看记录的奖励类型
-                log.setRewardType(config.getRewardType());
-                courseWatchLogMapper.updateFsCourseWatchLog(log);
-//
-//                company.setMoney(subtract);
-//                companyMapper.updateCompany(company);
-//
-//                CompanyMoneyLogs logs=new CompanyMoneyLogs();
-//                logs.setCompanyId(company.getCompanyId());
-//                logs.setRemark("扣除红包金额");
-//                logs.setMoney(amount.multiply(new BigDecimal(-1)));
-//                logs.setLogsType(15);
-//                logs.setBalance(company.getMoney());
-//                logs.setCreateTime(new Date());
-//                moneyLogsMapper.insertCompanyMoneyLogs(logs);
+                // 发送红包
+                return sendRedPacketRewardToUser(param, log, config, packetParam, amount);
 
-                return sendRedPacket;
-            } else {
-                return R.error("奖励发送失败,请联系客服");
+            }catch (Exception e){
+                logger.error("领取红包失败原因:{}", ExceptionUtils.getFullStackTrace(e),e);
+                throw new RuntimeException(e);
+            }finally {
+                if (lock.isHeldByCurrentThread()) {
+                    lock.unlock();
+                }
             }
         } else {
             FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
             // 添加红包记录
             redPacketLog.setCourseId(param.getCourseId());
-//            redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
+
             redPacketLog.setCompanyId(param.getCompanyId());
             redPacketLog.setUserId(param.getUserId());
             redPacketLog.setVideoId(param.getVideoId());
             redPacketLog.setStatus(0);
-            redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
+            redPacketLog.setQwUserId(param.getQwUserId());
             redPacketLog.setCompanyUserId(param.getCompanyUserId());
             redPacketLog.setCreateTime(new Date());
             redPacketLog.setAmount(BigDecimal.ZERO);
-            redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
+            redPacketLog.setWatchLogId(log.getLogId());
             redPacketLog.setPeriodId(param.getPeriodId());
             redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
 
             // 更新观看记录的奖励类型
-//            if (param.getLinkType() == null || param.getLinkType() == 0) {
             log.setRewardType(config.getRewardType());
             courseWatchLogMapper.updateFsCourseWatchLog(log);
-//            }
             return R.ok("红包发送成功");
         }
 
     }
 
+    private R sendRedPacketRewardToUser(FsCourseSendRewardUParam param, FsCourseWatchLog log, CourseConfig config, WxSendRedPacketParam packetParam, BigDecimal amount) {
+
+        BigDecimal companyMoney = null;
+        if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
+            companyMoney = redisCache.getCacheObject(REDPACKET_COMPANY_MONEY);
+            if(ObjectUtils.isNull(companyMoney)){
+                SysConfig sysConfig = sysConfigService.selectConfigByConfigKey("company.money");
+                if(ObjectUtils.isNull(sysConfig)){
+                    throw new IllegalArgumentException("润天公司账户余额不能为空!请检查配置!");
+                }
+                String configValue = sysConfig.getConfigValue();
+                companyMoney = new BigDecimal(configValue);
+                logger.info("缓存公司余额为空,从数据库读取 companyMoney: {}",companyMoney);
+            }
+
+            if (companyMoney.compareTo(BigDecimal.ZERO) <= 0) {
+                logger.info("润天账户余额: {} 不足!", companyMoney);
+                return R.error("[红包领取] 账户余额不足,请联系管理员!");
+            }
+        }
+
+        // 发送红包
+        R sendRedPacket = paymentService.sendRedPacket(packetParam);
+        if (sendRedPacket.get("code").equals(200)) {
+            FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
+            TransferBillsResult transferBillsResult;
+            if (sendRedPacket.get("isNew").equals(1)){
+                transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
+                redPacketLog.setResult(JSON.toJSONString(sendRedPacket));
+                redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
+            }else {
+                redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
+            }
+            // 添加红包记录
+            redPacketLog.setCourseId(param.getCourseId());
+            redPacketLog.setCompanyId(param.getCompanyId());
+            redPacketLog.setUserId(param.getUserId());
+            redPacketLog.setVideoId(param.getVideoId());
+            redPacketLog.setStatus(0);
+            redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
+            redPacketLog.setCompanyUserId(param.getCompanyUserId());
+            redPacketLog.setCreateTime(new Date());
+            redPacketLog.setAmount(amount);
+            redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
+            redPacketLog.setPeriodId(param.getPeriodId());
+            if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
+                redPacketLog.setAccBalanceBefore(companyMoney);
+                redPacketLog.setAccBalanceAfter(companyMoney.subtract(amount));
+            }
+
+            CompletableFuture.runAsync(() -> {
+                redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
+                // 更新观看记录的奖励类型
+                log.setRewardType(config.getRewardType());
+                courseWatchLogMapper.updateFsCourseWatchLog(log);
+            });
+
+            if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
+                // 更新账户余额
+                logger.info("[更新账户余额] 当前余额{} 更新后余额{}",companyMoney.toPlainString(),companyMoney.subtract(amount).toPlainString());
+
+                companyMoney = companyMoney.subtract(amount);
+                redisCache.setCacheObject(REDPACKET_COMPANY_MONEY,companyMoney);
+            }
+            return sendRedPacket;
+        } else {
+            return R.error("奖励发送失败,请联系客服");
+        }
+    }
+
 
     private void handleFsUserWx(FsUser user, String appId) {
         FsUserWx fsUserWx = new FsUserWx();
@@ -1173,7 +1229,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         fsUserWx.setUpdateTime(new Date());
         fsUserWxService.saveOrUpdateByUniqueKey(fsUserWx);
 
-        logger.info("zyp \n 【更新或插入用户与小程序{}的绑定关系】:{}", appId, user.getUserId());
+        logger.info("【更新或插入用户与小程序{}的绑定关系】:{}", appId, user.getUserId());
     }
 
     /**
@@ -1228,14 +1284,14 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                 FsUserWx fsUserWx = fsUserWxService.selectByAppIdAndUserId(param.getAppId(),user.getUserId(),1);
                 if (fsUserWx ==null){
                     if (user.getCourseMaOpenId()==null){
-                        logger.error("zyp \n 【转账openId参数错误】:{}", user.getUserId());
+                        logger.error(" 【转账openId参数错误】:{}", user.getUserId());
                         return R.error("openId参数错误,请清理缓存后重新授权!");
                     }
                     packetParam.setOpenId(user.getCourseMaOpenId());
                     try {
                         handleFsUserWx(user,param.getAppId());
                     }catch (Exception e){
-                        logger.error("zyp \n 【更新或插入用户与小程序的绑定关系失败】:{}", user.getUserId(),e);
+                        logger.error(" 【更新或插入用户与小程序的绑定关系失败】:{}", user.getUserId(),e);
                     }
 
                 }else {
@@ -2157,6 +2213,9 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         }else {
             link.setLinkType(3);
         }
+        link.setProjectCode(cloudHostProper.getProjectCode());
+
+        link.setProjectCode(cloudHostProper.getProjectCode());
 
         String randomString = generateRandomStringWithLock();
         if (StringUtil.strIsNullOrEmpty(randomString)){
@@ -2603,7 +2662,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     public R getInternetTrafficIsOpen(FsUserCourseVideoFinishUParam param) {
         try {
             if (param.getBufferRate()==null){
-                logger.error("zyp \n【缓冲值空】参数: {}",param);
+                logger.error("【缓冲值空】参数: {}",param);
                 return R.error("缓冲值空");
             }
             FsCourseTrafficLog trafficLog = new FsCourseTrafficLog();
@@ -2624,13 +2683,13 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             // 处理 UUID 为空的情况
             if (StringUtils.isNotEmpty(trafficLog.getUuId())) {
                 // 直接插入或更新
-//                logger.error("zyp \n【插入或更新流量】:{}",trafficLog);
+//                logger.error("【插入或更新流量】:{}",trafficLog);
                 fsCourseTrafficLogMapper.insertOrUpdateTrafficLog(trafficLog);
             }
         } catch (Exception e) {
             e.printStackTrace();
             // 打印参数param和异常信息
-            logger.error("zyp \n【插入或更新流量失败】参数: {}, 错误信息:{}", param, e.getMessage(), e);
+            logger.error("【插入或更新流量失败】参数: {}, 错误信息:{}", param, e.getMessage(), e);
             return R.error();
         }
         return R.ok();
@@ -2646,7 +2705,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             log.setDuration(0L);
             log.setCreateTime(new Date());
             log.setLogType(3);
-            logger.info("zyp \n【群聊生成看课记录】:{}",param);
+            logger.info("【群聊生成看课记录】:{}",param);
             courseWatchLogMapper.insertFsCourseWatchLog(log);
         } catch (BeansException e) {
             return R.error("群聊生成看课记录失败!");

+ 8 - 4
fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java

@@ -26,6 +26,7 @@ import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.mapper.CompanyConfigMapper;
 import com.fs.company.param.FsStoreStatisticsParam;
+import com.fs.company.service.ICompanyConfigService;
 import com.fs.company.service.ICompanyService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.company.vo.FsStorePaymentStatisticsVO;
@@ -115,6 +116,7 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.servlet.http.HttpServletRequest;
@@ -475,9 +477,11 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
         return fsStorePaymentMapper.selectFsStorePaymentByPaymentCode(payCode);
     }
 
+    @Autowired
+    private ICompanyConfigService companyConfigService;
 
     @Override
-    @Transactional
+    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
     public R sendRedPacket(WxSendRedPacketParam param) {
 
         String json;
@@ -489,7 +493,7 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
                 config = JSONUtil.toBean(json, RedPacketConfig.class);
                 break;
             case 2:
-                json = companyConfigMapper.selectRedPacketConfigByKey(param.getCompanyId());
+                json = companyConfigService.selectRedPacketConfigByKey(param.getCompanyId());
                 config = JSONUtil.toBean(json, RedPacketConfig.class);
                 break;
         }
@@ -499,7 +503,7 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
             String appId = StringUtils.isBlank(param.getAppId()) ? config.getMiniappId() : param.getAppId();
             config.setAppId(appId);
         }
-        System.out.println("最终传参"+config);
+        logger.info("最终传参 {}",config);
         //组合返回参数
         R result = new R();
         // 根据 isNew 判断使用哪种发红包方式
@@ -510,7 +514,7 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
         }
         result.put("mchId",config.getMchId()+"");
         result.put("isNew",config.getIsNew());
-        System.out.println("红包返回:"+result);
+        logger.info("红包返回:{}",result);
         return result;
     }
 

+ 5 - 0
fs-service/src/main/java/com/fs/hisStore/param/FsStoreOrderPayParam.java

@@ -16,4 +16,9 @@ public class FsStoreOrderPayParam implements Serializable
     @ApiModelProperty(value = "payType")
     @NotNull(message = "支付类型不能为空")
     private Integer payType;
+
+    /**
+     * 小程序多商城
+     * **/
+    private String appId;
 }

+ 1 - 0
fs-service/src/main/java/com/fs/hisStore/param/FsStorePaymentPayParam.java

@@ -20,4 +20,5 @@ public class FsStorePaymentPayParam implements Serializable
     private Long companyUserId;
 
     private String code;
+    private String appId;
 }

+ 22 - 8
fs-service/src/main/java/com/fs/system/service/impl/SysConfigServiceImpl.java

@@ -14,8 +14,10 @@ import com.fs.system.service.ISysConfigService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import javax.annotation.PostConstruct;
+import javax.annotation.concurrent.ThreadSafe;
 import java.util.Collection;
 import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * 参数配置 服务层实现
@@ -23,6 +25,7 @@ import java.util.List;
 
  */
 @Service
+@ThreadSafe
 public class SysConfigServiceImpl implements ISysConfigService
 {
     @Autowired
@@ -31,6 +34,7 @@ public class SysConfigServiceImpl implements ISysConfigService
     @Autowired
     private RedisCache redisCache;
 
+    private static final ConcurrentHashMap<String, Object> KEY_LOCKS = new ConcurrentHashMap<>();
     /**
      * 项目启动时,初始化参数到缓存
      */
@@ -69,15 +73,25 @@ public class SysConfigServiceImpl implements ISysConfigService
         {
             return configValue;
         }
-        SysConfig config = new SysConfig();
-        config.setConfigKey(configKey);
-        SysConfig retConfig = configMapper.selectConfig(config);
-        if (StringUtils.isNotNull(retConfig))
-        {
-            redisCache.setCacheObject(getCacheKey(configKey), retConfig.getConfigValue());
-            return retConfig.getConfigValue();
+        Object keyLock = KEY_LOCKS.computeIfAbsent(configKey, k -> new Object());
+
+        synchronized (keyLock){
+            configValue = Convert.toStr(redisCache.getCacheObject(getCacheKey(configKey)));
+            if (StringUtils.isNotEmpty(configValue))
+            {
+                return configValue;
+            }
+
+            SysConfig config = new SysConfig();
+            config.setConfigKey(configKey);
+            SysConfig retConfig = configMapper.selectConfig(config);
+            if (StringUtils.isNotNull(retConfig))
+            {
+                redisCache.setCacheObject(getCacheKey(configKey), retConfig.getConfigValue());
+                return retConfig.getConfigValue();
+            }
+            return StringUtils.EMPTY;
         }
-        return StringUtils.EMPTY;
     }
 
     /**

+ 88 - 0
fs-service/src/main/resources/application-config-druid-hst.yml

@@ -0,0 +1,88 @@
+baidu:
+  token: 1231321232
+  back-domain: https://www.xxxx.com
+#配置
+logging:
+  level:
+    org.springframework.web: INFO
+    com.github.binarywang.demo.wx.cp: DEBUG
+    me.chanjar.weixin: DEBUG
+wx:
+  miniapp:
+    configs:
+      - appid:
+        secret:
+        token:
+        aesKey:
+        msgDataFormat: JSON
+      - appid:
+        secret:
+        token:
+        aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
+        msgDataFormat: JSON
+  cp:
+    corpId: wwb2a10556a7c2
+    appConfigs:
+      - agentId: 100005
+        secret: ec7okROXJqkNafq66aKNasTzQIG0CYrj3vyBbo
+        token: PPKOdAlMO
+        aesKey: PKvaxtpSvNGpfT7VUHIK8Wok2ESyYX24qpXJAdMP
+  pay:
+    appId: wx034403a0b275a492 #微信公众号或者小程序等的appid
+    mchId: 1722734247 #微信支付商户号
+    mchKey: KUANYITANGDAYAOFANGkuanyitangday #微信支付商户密钥
+    subAppId:  #服务商模式下的子商户公众账号ID
+    subMchId:  #服务商模式下的子商户号
+    keyPath: c:\\cert\\apiclient_cert.p12 # p12证书的位置,可以指定绝对路径,也可以指定类路径(以classpath:开头)
+    notifyUrl: https://userapp.schstyl.cn/app/wxpay/wxPayNotify
+  mp:
+    useRedis: false
+    redisConfig:
+      host: 127.0.0.1
+      port: 6379
+      timeout: 2000
+    configs:
+      - appId:  wxd0a67578869950ab # 第一个公众号的appid
+        secret: 645f649be6d748e33e71cefec2469e86  # 公众号的appsecret
+        token: PPKOdAlCoMO # 接口配置里的Token值
+        aesKey: Eswa6VjwtVMCcw03qZy6fWllgrv5aytIA1SZPEU0kU2 # 接口配置里的EncodingAESKey值
+aifabu:  #爱链接
+  appKey: 7b471be905ab17ef358c0dd117601d008
+watch:
+  watchUrl: watch.ylrzcloud.com/prod-api
+#  account: tcloud
+#  password: mdf-m2h_6yw2$hq
+  account1: ccif #866655060138751
+  password1: cp-t5or_6xw7$mt
+  account2: tcloud #rt500台
+  password2: mdf-m2h_6yw2$hq
+  account3: whr
+  password3: v9xsKuqn_$d2y
+
+fs :
+  commonApi: http://172.17.0.10:8010
+  h5CommonApi: http://172.17.0.10:8010
+nuonuo:
+  key: 10924508
+  secret: A2EB20764D304D16
+# 存储捅配置
+tencent_cloud_config:
+  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
+  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  bucket: hst-1323137866
+  app_id: 1323137866
+  region: ap-chongqing
+  proxy: hst
+cloud_host:
+  company_name: 鸿森堂
+  projectCode: HST
+#看课授权时显示的头像
+headerImg:
+  imgUrl:
+ipad:
+  ipadUrl: http://ipad.schstyl.cn
+  aiApi:
+wx_miniapp_temp:
+  pay_order_temp_id:
+  inquiry_temp_id:
+

+ 2 - 0
fs-service/src/main/resources/application-config-druid-qdtst.yml

@@ -93,3 +93,5 @@ ipad:
 wx_miniapp_temp:
   pay_order_temp_id:
   inquiry_temp_id:
+
+enableRedPackAccount: 1

+ 145 - 0
fs-service/src/main/resources/application-druid-hst.yml

@@ -0,0 +1,145 @@
+# 数据源配置
+spring:
+  profiles:
+    include: common,config-druid-hst
+  # redis 配置
+  redis:
+    # 地址
+    host: 172.16.0.53
+    # 端口,默认为6379
+    port: 6379
+    # 密码
+    password: Ylrztek250218!3@.!!hst()
+    # 连接超时时间
+    timeout: 30s
+    lettuce:
+      pool:
+        # 连接池中的最小空闲连接
+        min-idle: 0
+        # 连接池中的最大空闲连接
+        max-idle: 8
+        # 连接池的最大数据库连接数
+        max-active: 100
+        # #连接池最大阻塞等待时间(使用负值表示没有限制)
+        max-wait: -1ms
+    database: 0
+  datasource:
+    mysql:
+      type: com.alibaba.druid.pool.DruidDataSource
+      driverClassName: com.mysql.cj.jdbc.Driver
+      druid:
+        # 主库数据源
+        master:
+          url: jdbc:mysql://172.16.0.56:3306/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+          username: root
+          password: ylrz17452131..!@YY
+        # 从库数据源
+        slave:
+          # 从数据源开关/默认关闭
+          enabled: false
+          url:
+          username:
+          password:
+        # 初始连接数
+        initialSize: 5
+        # 最小连接池数量
+        minIdle: 10
+        # 最大连接池数量
+        maxActive: 200
+        # 配置获取连接等待超时的时间
+        maxWait: 60000
+        # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+        timeBetweenEvictionRunsMillis: 60000
+        # 配置一个连接在池中最小生存的时间,单位是毫秒
+        minEvictableIdleTimeMillis: 300000
+        # 配置一个连接在池中最大生存的时间,单位是毫秒
+        maxEvictableIdleTimeMillis: 900000
+        # 配置检测连接是否有效
+        validationQuery: SELECT 1 FROM DUAL
+        testWhileIdle: true
+        testOnBorrow: false
+        testOnReturn: false
+        webStatFilter:
+          enabled: true
+        statViewServlet:
+          enabled: false
+          # 设置白名单,不填则允许所有访问
+          allow:
+          url-pattern: /druid/*
+          # 控制台管理用户名和密码
+          login-username: fs
+          login-password: 123456
+        filter:
+          stat:
+            enabled: true
+            # 慢SQL记录
+            log-slow-sql: true
+            slow-sql-millis: 1000
+            merge-sql: true
+          wall:
+            config:
+              multi-statement-allow: true
+    sop:
+      type: com.alibaba.druid.pool.DruidDataSource
+      driverClassName: com.mysql.cj.jdbc.Driver
+      druid:
+        # 主库数据源
+        master:
+#          url: jdbc:mysql://172.17.0.3:3306/sop?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+          url: jdbc:mysql://172.16.0.56:3306/sop?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+          username: root
+          password: ylrz17452131..!@YY
+        # 初始连接数
+        initialSize: 5
+        # 最小连接池数量
+        minIdle: 10
+        # 最大连接池数量
+        maxActive: 200
+        # 配置获取连接等待超时的时间
+        maxWait: 60000
+        # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+        timeBetweenEvictionRunsMillis: 60000
+        # 配置一个连接在池中最小生存的时间,单位是毫秒
+        minEvictableIdleTimeMillis: 300000
+        # 配置一个连接在池中最大生存的时间,单位是毫秒
+        maxEvictableIdleTimeMillis: 900000
+        # 配置检测连接是否有效
+        validationQuery: SELECT 1 FROM DUAL
+        testWhileIdle: true
+        testOnBorrow: false
+        testOnReturn: false
+        webStatFilter:
+          enabled: true
+        statViewServlet:
+          enabled: false
+          # 设置白名单,不填则允许所有访问
+          allow:
+          url-pattern: /druid/*
+          # 控制台管理用户名和密码
+          login-username: fs
+          login-password: 123456
+        filter:
+          stat:
+            enabled: true
+            # 慢SQL记录
+            log-slow-sql: true
+            slow-sql-millis: 1000
+            merge-sql: true
+          wall:
+            config:
+              multi-statement-allow: true
+rocketmq:
+  name-server: rmq-1243b25nj.rocketmq.gz.public.tencenttdmq.com:8080 # RocketMQ NameServer 地址
+  producer:
+    group: my-producer-group
+    access-key: ak1243b25nj17d4b2dc1a03 # 替换为实际的 accessKey
+    secret-key: sk08a7ea1f9f4b0237 # 替换为实际的 secretKey
+  consumer:
+    group: test-group
+    access-key: ak1243b25nj17d4b2dc1a03 # 替换为实际的 accessKey
+    secret-key: sk08a7ea1f9f4b0237 # 替换为实际的 secretKey
+openIM:
+  secret: op
+  userID: im
+#是否为新商户,新商户不走mpOpenId
+isNewWxMerchant: true

+ 1 - 1
fs-service/src/main/resources/application-druid-qdtst.yml

@@ -167,4 +167,4 @@ openIM:
     secret:
     userID:
 #是否为新商户,新商户不走mpOpenId
-isNewWxMerchant: true
+isNewWxMerchant: false

+ 6 - 0
fs-service/src/main/resources/mapper/course/FsCourseRedPacketLogMapper.xml

@@ -110,6 +110,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="result != null">result,</if>
             <if test="batchId != null">batch_id,</if>
             <if test="appId != null">app_id,</if>
+            <if test="appId != null">app_id,</if>
+            <if test="appId != null">app_id,</if>
+            <if test="accBalanceBefore != null">acc_balance_before,</if>
+            <if test="accBalanceAfter != null">acc_balance_after,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="courseId != null">#{courseId},</if>
@@ -129,6 +133,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="result != null">#{result},</if>
             <if test="batchId != null">#{batchId},</if>
             <if test="appId != null">#{appId},</if>
+            <if test="accBalanceBefore != null">#{accBalanceBefore},</if>
+            <if test="accBalanceAfter != null">#{accBalanceAfter},</if>
         </trim>
     </insert>
 

+ 3 - 1
fs-user-app/src/main/java/com/fs/app/controller/InquiryOrderController.java

@@ -244,7 +244,9 @@ public class InquiryOrderController extends  AppBaseController {
     @PostMapping("/payment")
     public R payment(HttpServletRequest request, @Validated @RequestBody FsInquiryOrderDoPayParam param)
     {
-        FsUser user = userService.selectFsUserByUserId(param.getUserId());
+        Long userId = Long.parseLong(getUserId());
+
+        FsUser user = userService.selectFsUserByUserId(userId);
         //在线支付
         String json = configService.selectConfigByKey("his.pay");
         PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);

+ 1 - 1
fs-user-app/src/main/java/com/fs/app/controller/course/CourseQwController.java

@@ -222,7 +222,7 @@ public class CourseQwController extends AppBaseController {
     public R sendReward(@RequestBody FsCourseSendRewardUParam param)
     {
         param.setUserId(Long.parseLong(getUserId()));
-        logger.info("zyp \n【发放奖励】:{}",param);
+        logger.info("【发放奖励】:{}",param);
         return courseVideoService.sendReward(param);
     }
 

+ 4 - 4
fs-user-app/src/main/java/com/fs/app/controller/store/CourseH5ScrmController.java

@@ -146,9 +146,9 @@ public class CourseH5ScrmController extends AppBaseController {
     public R courseAnswer(@RequestBody FsCourseQuestionAnswerUParam param)
     {
         param.setUserId(Long.parseLong(getUserId()));
-        logger.info("zyp \n【答题】:{}",param.getQuestions());
+        logger.info("【答题】:{}",param.getQuestions());
         if (param.getDuration()==null){
-            logger.info("zyp \n【未识别到时长】:{}",param.getUserId());
+            logger.info("【未识别到时长】:{}",param.getUserId());
         }
         return questionBankService.courseAnswer(param, false);
     }
@@ -159,13 +159,13 @@ public class CourseH5ScrmController extends AppBaseController {
     public R sendReward(@RequestBody FsCourseSendRewardUParam param)
     {
         param.setUserId(Long.parseLong(getUserId()));
-        logger.info("zyp \n【发放奖励】:{}",param);
+        logger.info("【发放奖励】:{}",param);
         return courseVideoService.sendReward(param);
     }
 
     @PostMapping("/getErrMsg")
     public void getErrMsg(@RequestParam("msg") String msg) {
-        logger.error("zyp \n【h5看课中途报错】:{}",msg);
+        logger.error("【h5看课中途报错】:{}",msg);
     }
 
 }

+ 2 - 2
fs-user-app/src/main/java/com/fs/app/controller/store/CourseWxH5ScrmController.java

@@ -121,14 +121,14 @@ public class CourseWxH5ScrmController extends AppBaseController {
     public R sendReward(@RequestBody FsCourseSendRewardUParam param)
     {
         param.setUserId(Long.parseLong(getUserId()));
-        logger.info("zyp \n【发放奖励】:{}",param);
+        logger.info("【发放奖励】:{}",param);
         return courseVideoService.sendRewardByFsUser(param);
     }
 
 
     @PostMapping("/getErrMsg")
     public void getErrMsg(@RequestParam("msg") String msg) {
-        logger.error("zyp \n【h5看课中途报错】:{}",msg);
+        logger.error("【h5看课中途报错】:{}",msg);
     }
 
 

+ 8 - 1
fs-user-app/src/main/java/com/fs/app/controller/store/PaymentScrmController.java

@@ -44,7 +44,14 @@ public class PaymentScrmController extends AppBaseController {
     @PostMapping("/payment")
     @RepeatSubmit
     public R payment(@Validated @RequestBody FsStorePaymentPayParam payment, HttpServletRequest request){
-        final WxMaService wxService = WxMaConfiguration.getMaService(properties.getConfigs().get(0).getAppid());
+        String appId = null;
+        if (payment.getAppId()!=null && !"".equals(payment.getAppId())){
+            appId= payment.getAppId();
+        }else {
+            appId=properties.getConfigs().get(0).getAppid();
+        }
+
+        final WxMaService wxService = WxMaConfiguration.getMaService(appId);
         try {
             String ip = IpUtil.getRequestIp();
             WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(payment.getCode());

+ 3 - 0
fs-user-app/src/main/java/com/fs/app/controller/store/StoreOrderScrmController.java

@@ -360,6 +360,9 @@ public class StoreOrderScrmController extends AppBaseController {
                     o.setReqSeqId("store-"+storePayment.getPayCode());
                     o.setTransAmt(storePayment.getPayMoney().toString());
                     o.setGoodsDesc("商城订单支付");
+                    if (param != null && StringUtils.isNotBlank(param.getAppId())) {
+                        o.setAppId(param.getAppId());
+                    }
                     HuifuCreateOrderResult result = huiFuService.createOrder(o);
                     if(result.getResp_code()!=null&&(result.getResp_code().equals("00000000")||result.getResp_code().equals("00000100"))){
                         FsStorePaymentScrm mt=new FsStorePaymentScrm();

+ 1 - 1
fs-user-app/src/main/java/com/fs/app/controller/store/WxUserScrmController.java

@@ -307,7 +307,7 @@ public class WxUserScrmController extends AppBaseController {
                     //写入
                     user=new FsUserScrm();
                     user.setPhone(phoneNoInfo.getPhoneNumber());
-                    user.setNickName("微信用户"+phoneNoInfo.getPhoneNumber().substring(phoneNoInfo.getPhoneNumber().length()-4));
+                    user.setNickName(phoneNoInfo.getPhoneNumber() != null ? "微信用户" + phoneNoInfo.getPhoneNumber().substring(phoneNoInfo.getPhoneNumber().length()-4) : "微信用户");
                     user.setAvatar("https://hos-1309931967.cos.ap-chongqing.myqcloud.com/fs/20230725/a848605591384ec29d49773dd58d9345.jpg");
                     user.setStatus(1);
                     user.setMaOpenId(session.getOpenid());

+ 2 - 1
fs-user-app/src/main/resources/application.yml

@@ -11,5 +11,6 @@ spring:
 #    active: druid-yzt
 #    active: druid-hdt
 #    active: druid-sxjz
+    active: druid-qdtst
 #    active: druid-yzt
-    active: druid-jnmy-test
+#    active: druid-jnmy-test