Browse Source

Merge remote-tracking branch 'origin/master'

yfh 4 days ago
parent
commit
fd530c7247
26 changed files with 627 additions and 144 deletions
  1. 94 0
      fs-admin/src/main/java/com/fs/qw/FsCourseTask.java
  2. 2 0
      fs-service/src/main/java/com/fs/company/service/ICompanyConfigService.java
  3. 38 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyConfigServiceImpl.java
  4. 15 24
      fs-service/src/main/java/com/fs/core/config/WxMaConfiguration.java
  5. 9 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseRedPacketLog.java
  6. 137 83
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  7. 23 7
      fs-service/src/main/java/com/fs/erp/service/impl/K9OrderScrmServiceImpl.java
  8. 1 1
      fs-service/src/main/java/com/fs/his/service/impl/FsPackageOrderServiceImpl.java
  9. 8 4
      fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java
  10. 2 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderItemScrmMapper.java
  11. 2 0
      fs-service/src/main/java/com/fs/hisStore/service/IFsStoreOrderItemScrmService.java
  12. 5 0
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderItemScrmServiceImpl.java
  13. 2 0
      fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemVO.java
  14. 22 8
      fs-service/src/main/java/com/fs/system/service/impl/SysConfigServiceImpl.java
  15. 88 0
      fs-service/src/main/resources/application-config-druid-hst.yml
  16. 2 0
      fs-service/src/main/resources/application-config-druid-qdtst.yml
  17. 145 0
      fs-service/src/main/resources/application-druid-hst.yml
  18. 1 1
      fs-service/src/main/resources/application-druid-qdtst.yml
  19. 6 0
      fs-service/src/main/resources/mapper/course/FsCourseRedPacketLogMapper.xml
  20. 12 6
      fs-service/src/main/resources/mapper/hisStore/FsStoreOrderItemScrmMapper.xml
  21. 3 1
      fs-user-app/src/main/java/com/fs/app/controller/InquiryOrderController.java
  22. 1 1
      fs-user-app/src/main/java/com/fs/app/controller/course/CourseQwController.java
  23. 4 4
      fs-user-app/src/main/java/com/fs/app/controller/store/CourseH5ScrmController.java
  24. 2 2
      fs-user-app/src/main/java/com/fs/app/controller/store/CourseWxH5ScrmController.java
  25. 1 1
      fs-user-app/src/main/java/com/fs/app/controller/store/WxUserScrmController.java
  26. 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

+ 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;
+
 }

+ 137 - 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;
@@ -60,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;
@@ -82,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;
@@ -104,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=";
@@ -139,6 +168,8 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     private AsyncIsAddKfXfkService xfkService;
 
 
+    @Autowired
+    private RedissonClient redissonClient;
     @Autowired
     private QwExternalContactMapper qwExternalContactMapper;
     @Autowired
@@ -412,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());
         //用户不存在唤起重新授权
@@ -583,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);
     }
 
@@ -778,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();
@@ -805,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();
@@ -1047,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并赋值
-
         }
 
         //判断服务号配置是否存在
@@ -1067,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();
@@ -1177,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());
     }
 
     /**
@@ -1232,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 {
@@ -2163,6 +2215,8 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         }
         link.setProjectCode(cloudHostProper.getProjectCode());
 
+        link.setProjectCode(cloudHostProper.getProjectCode());
+
         String randomString = generateRandomStringWithLock();
         if (StringUtil.strIsNullOrEmpty(randomString)){
             link.setLink(UUID.randomUUID().toString().replace("-", ""));
@@ -2608,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();
@@ -2629,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();
@@ -2651,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("群聊生成看课记录失败!");

+ 23 - 7
fs-service/src/main/java/com/fs/erp/service/impl/K9OrderScrmServiceImpl.java

@@ -5,6 +5,7 @@ import cn.hutool.http.HttpUtil;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
 import com.fs.common.exception.ServiceException;
+import com.fs.common.utils.CloudHostUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.erp.domain.*;
 import com.fs.erp.dto.*;
@@ -20,6 +21,7 @@ import com.fs.hisStore.dto.FsStoreCartDTO;
 import com.fs.hisStore.mapper.FsStoreOrderScrmMapper;
 import com.fs.hisStore.mapper.FsStoreProductScrmMapper;
 import com.fs.hisStore.service.IFsStoreOrderItemScrmService;
+import com.fs.hisStore.vo.FsStoreOrderItemVO;
 import lombok.extern.slf4j.Slf4j;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -336,13 +338,27 @@ public class K9OrderScrmServiceImpl implements IErpOrderService {
 
     private List<KingbosOrderD1Data> buildOrderDetailData(FsStoreOrderScrm order, String orderId) {
         logger.debug("【金博网络订单】开始构建订单明细,订单号: {}", order.getOrderCode());
-        FsStoreOrderItemScrm query = new FsStoreOrderItemScrm();
-        query.setOrderId(order.getId());
-        List<FsStoreOrderItemScrm> orderItems = storeOrderItemService.selectFsStoreOrderItemList(query);
+//        FsStoreOrderItemScrm query = new FsStoreOrderItemScrm();
+//        query.setOrderId(order.getId());
+//        List<FsStoreOrderItemScrm> orderItems = storeOrderItemService.selectFsStoreOrderItemList(query);
+
+//        List<KingbosOrderD1Data> d1Datas = orderItems.stream()
+//                .map(item -> buildOrderDetailItem(item, orderId))
+//                .collect(Collectors.toList());
+
+
+        List<FsStoreOrderItemVO> orderItems = storeOrderItemService.selectFsStoreOrderItemListAndProductByOrderId(order.getId());
+        //2025.09.19 中康需求只推非药品
+        List<KingbosOrderD1Data> d1Datas = orderItems.stream().filter(item->{
+                    if (CloudHostUtils.hasCloudHostName("中康")){
+                        return item.getIsDrug() == null || item.getIsDrug() == 1;
+                    } else {
+                        return true;
+                    }
+                })
+                .map(item -> buildOrderDetailItem(item, orderId))
+                .collect(Collectors.toList());
 
-        List<KingbosOrderD1Data> d1Datas = orderItems.stream()
-            .map(item -> buildOrderDetailItem(item, orderId))
-            .collect(Collectors.toList());
 
         logger.debug("【金博网络订单】订单明细构建完成,订单号: {}, 明细数量: {}", order.getOrderCode(), d1Datas.size());
         return d1Datas;
@@ -355,7 +371,7 @@ public class K9OrderScrmServiceImpl implements IErpOrderService {
         return item;
     }
 
-    private KingbosOrderD1Data buildOrderDetailItem(FsStoreOrderItemScrm orderItem, String orderId) {
+    private KingbosOrderD1Data buildOrderDetailItem(FsStoreOrderItemVO orderItem, String orderId) {
         FsStoreCartDTO cartDTO = JSONUtil.toBean(orderItem.getJsonInfo(), FsStoreCartDTO.class);
         BigDecimal quantity = new BigDecimal(orderItem.getNum());
 

+ 1 - 1
fs-service/src/main/java/com/fs/his/service/impl/FsPackageOrderServiceImpl.java

@@ -1402,7 +1402,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
             CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                 FsStorePayment fsStorePayment = fsStorePaymentMapper.selectLastByBusinessCode(vo.getOrderSn());
                 if (fsStorePayment != null) {
-                    vo.setBusinessCode("package-" + fsStorePayment.getBusinessCode());
+                    vo.setBusinessCode("package-" + fsStorePayment.getPayCode());
                 }
             });
             futures.add(future);

+ 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;
     }
 

+ 2 - 0
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderItemScrmMapper.java

@@ -72,6 +72,8 @@ public interface FsStoreOrderItemScrmMapper
     @Select("select * from fs_store_order_item_scrm where order_id=#{orderId}")
     List<FsStoreOrderItemVO> selectMyFsStoreOrderItemListByOrderId(Long id);
 
+    List<FsStoreOrderItemVO> selectFsStoreOrderItemListAndProductByOrderId(Long id);
+
     @Select({"<script> " +
             "select i.*,o.user_id,o.status, o.real_name,o.user_phone,o.user_address,o.create_time,o.pay_time,o.delivery_sn,o.delivery_name,o.delivery_id, c.company_name ,cu.nick_name as company_user_nick_name ,cu.phonenumber as company_usere_phonenumber,o.upload_time ,CASE WHEN o.certificates IS NULL OR o.certificates = '' THEN 0 ELSE 1 END AS is_upload   " +
             " ,p.title as package_name,cts.name as scheduleName from fs_store_order_item_scrm i left join fs_store_order_scrm o on o.id=i.order_id left join fs_user u on o.user_id=u.user_id  " +

+ 2 - 0
fs-service/src/main/java/com/fs/hisStore/service/IFsStoreOrderItemScrmService.java

@@ -66,6 +66,8 @@ public interface IFsStoreOrderItemScrmService
 
     List<FsStoreOrderItemVO> selectFsStoreOrderItemListByOrderId(Long ordreId);
 
+    List<FsStoreOrderItemVO> selectFsStoreOrderItemListAndProductByOrderId(Long orderId);
+
     List<FsStoreOrderItemExportVO> selectFsStoreOrderItemListExportVO(FsStoreOrderParam fsStoreOrder);
 
     Long countFsStoreOrderItemListExportVO(FsStoreOrderParam fsStoreOrder);

+ 5 - 0
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderItemScrmServiceImpl.java

@@ -102,6 +102,11 @@ public class FsStoreOrderItemScrmServiceImpl implements IFsStoreOrderItemScrmSer
         return fsStoreOrderItemMapper.selectFsStoreOrderItemListByOrderId(ordreId);
     }
 
+    @Override
+    public List<FsStoreOrderItemVO> selectFsStoreOrderItemListAndProductByOrderId(Long orderId) {
+        return fsStoreOrderItemMapper.selectFsStoreOrderItemListAndProductByOrderId(orderId);
+    }
+
     @Override
     public List<FsStoreOrderItemExportVO> selectFsStoreOrderItemListExportVO(FsStoreOrderParam fsStoreOrder) {
         return fsStoreOrderItemMapper.selectFsStoreOrderItemListExportVO(fsStoreOrder);

+ 2 - 0
fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemVO.java

@@ -46,4 +46,6 @@ public class FsStoreOrderItemVO  implements Serializable
     @Excel(name = "是否为处方")
     private Integer isPrescribe;
 
+    private Integer isDrug; //是否为药品
+
 }

+ 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>
 

+ 12 - 6
fs-service/src/main/resources/mapper/hisStore/FsStoreOrderItemScrmMapper.xml

@@ -3,7 +3,7 @@
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.fs.hisStore.mapper.FsStoreOrderItemScrmMapper">
-    
+
     <resultMap type="FsStoreOrderItemScrm" id="FsStoreOrderItemResult">
         <result property="itemId"    column="item_id"    />
         <result property="orderId"    column="order_id"    />
@@ -22,7 +22,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
     <select id="selectFsStoreOrderItemList" parameterType="FsStoreOrderItemScrm" resultMap="FsStoreOrderItemResult">
         <include refid="selectFsStoreOrderItemVo"/>
-        <where>  
+        <where>
             <if test="orderId != null "> and order_id = #{orderId}</if>
             <if test="orderCode != null  and orderCode != ''"> and order_code = #{orderCode}</if>
             <if test="cartId != null "> and cart_id = #{cartId}</if>
@@ -33,12 +33,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="isPrescribe != null "> and is_prescribe = #{isPrescribe}</if>
         </where>
     </select>
-    
+
     <select id="selectFsStoreOrderItemById" parameterType="Long" resultMap="FsStoreOrderItemResult">
         <include refid="selectFsStoreOrderItemVo"/>
         where item_id = #{itemId}
     </select>
-        
+    <select id="selectFsStoreOrderItemListAndProductByOrderId"
+            resultType="com.fs.hisStore.vo.FsStoreOrderItemVO">
+        select i.*,p.is_drug from fs_store_order_item_scrm i
+                 left join fs_store_product_scrm p on i.product_id = p.product_id
+                 where i.order_id=#{orderId}
+    </select>
+
     <insert id="insertFsStoreOrderItem" parameterType="FsStoreOrderItemScrm" useGeneratedKeys="true" keyProperty="itemId">
         insert into fs_store_order_item_scrm
         <trim prefix="(" suffix=")" suffixOverrides=",">
@@ -88,5 +94,5 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{itemId}
         </foreach>
     </delete>
-    
-</mapper>
+
+</mapper>

+ 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);
     }
 
 

+ 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