Bläddra i källkod

Merge remote-tracking branch 'origin/master'

ct 3 veckor sedan
förälder
incheckning
341a5c289a

+ 2 - 1
fs-service/src/main/java/com/fs/course/service/IFsUserCompanyUserService.java

@@ -9,7 +9,7 @@ import java.util.Map;
 
 /**
  * 微信用户和销售关系Service接口
- * 
+ *
  * @author fs
  * @date 2025-05-09
  */
@@ -75,6 +75,7 @@ public interface IFsUserCompanyUserService extends IService<FsUserCompanyUser>{
      * @param projectId   项目ID
      * @return FsUserCompanyUser
      */
+    FsUserCompanyUser selectByUserIdAndProjectId(Long userId, Long projectId,Long companyUserId);
     FsUserCompanyUser selectByUserIdAndProjectId(Long userId, Long projectId);
 
     /**

+ 1 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsCourseRedPacketLogServiceImpl.java

@@ -215,6 +215,7 @@ public class FsCourseRedPacketLogServiceImpl implements IFsCourseRedPacketLogSer
                 packetParam.setSource(2);
                 packetParam.setRedPacketMode(1);
                 packetParam.setCompanyId(param.getCompanyId());
+                packetParam.setUser(user);
                 R sendRedPacket = paymentService.sendRedPacket(packetParam);
                 if (sendRedPacket.get("code").equals(200)) {
                     FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();

+ 10 - 1
fs-service/src/main/java/com/fs/course/service/impl/FsUserCompanyUserServiceImpl.java

@@ -17,7 +17,7 @@ import java.util.Objects;
 
 /**
  * 微信用户和销售关系Service业务层处理
- * 
+ *
  * @author fs
  * @date 2025-05-09
  */
@@ -111,6 +111,15 @@ public class FsUserCompanyUserServiceImpl extends ServiceImpl<FsUserCompanyUserM
      * @param projectId   项目ID
      * @return FsUserCompanyUser
      */
+    @Override
+    public FsUserCompanyUser selectByUserIdAndProjectId(Long userId, Long projectId,Long companyUserId) {
+        LambdaQueryWrapper<FsUserCompanyUser> queryWrapper = Wrappers.<FsUserCompanyUser>lambdaQuery()
+                .eq(FsUserCompanyUser::getUserId, userId)
+                .eq(FsUserCompanyUser::getProjectId, projectId)
+                .eq(FsUserCompanyUser::getCompanyUserId, companyUserId);
+        return getOne(queryWrapper);
+    }
+
     @Override
     public FsUserCompanyUser selectByUserIdAndProjectId(Long userId, Long projectId) {
         LambdaQueryWrapper<FsUserCompanyUser> queryWrapper = Wrappers.<FsUserCompanyUser>lambdaQuery()

+ 68 - 233
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -116,32 +116,6 @@ 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_USER_LIMIT = "redpacket_user_limit:%s:%d";
-
-    /**
-     * 红包改变记录
-     */
-    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=";
     private static final String SHORT_LINK_PREFIX = "/courseH5/pages/course/learning?s=";
@@ -258,17 +232,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     @Autowired
     ConfigUtil configUtil;
 
-    @Autowired
-    private RedisTemplate<String,BigDecimal> redisTemplate;
 
-    @Autowired
-    private RedisTemplate<String,Integer> redisTemplateInteger;
-
-    /**
-     * 红包领取数量限制 默认一个用户当天最多只能领取10个
-     */
-    @Value("${RED_PACKET_LIMIT_COUNT:10}")
-    private Integer RED_PACKET_LIMIT_COUNT;
 
     /**
      * 查询课堂视频
@@ -1176,23 +1140,46 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
         // 准备发送红包参数
         WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
-        packetParam.setOpenId(user.getMpOpenId());
-        // 来源是小程序切换openId
-        if (param.getSource() == 2) {
-            //处理多小程序问题
+
+        if (user.getMpOpenId()!=null&&!isNewWxMerchant){
+            packetParam.setOpenId(user.getMpOpenId());
+        }else {
+            //修复数据
             FsUserWx fsUserWx = fsUserWxService.selectByAppIdAndUserId(param.getAppId(),user.getUserId(),1);
             if (fsUserWx ==null){
+                if (user.getCourseMaOpenId()==null){
+                    logger.error(" 【转账openId参数错误】:{}", user.getUserId());
+                    return R.error("openId参数错误,请清理缓存后重新授权!");
+                }
+                packetParam.setOpenId(user.getCourseMaOpenId());
                 try {
                     handleFsUserWx(user,param.getAppId());
                 }catch (Exception e){
-                    logger.error("【更新或插入用户与小程序的绑定关系失败】:{}", user.getUserId());
+                    logger.error(" 【更新或插入用户与小程序的绑定关系失败】:{}", user.getUserId(),e);
                 }
+
             }else {
                 packetParam.setOpenId(fsUserWx.getOpenId());
             }
-            //查出公司绑定openid并赋值
         }
 
+//        packetParam.setOpenId(user.getMpOpenId());
+//        // 来源是小程序切换openId
+//        if (param.getSource() == 2) {
+//            //处理多小程序问题
+//            FsUserWx fsUserWx = fsUserWxService.selectByAppIdAndUserId(param.getAppId(),user.getUserId(),1);
+//            if (fsUserWx ==null){
+//                try {
+//                    handleFsUserWx(user,param.getAppId());
+//                }catch (Exception e){
+//                    logger.error("【更新或插入用户与小程序的绑定关系失败】:{}", user.getUserId());
+//                }
+//            }else {
+//                packetParam.setOpenId(fsUserWx.getOpenId());
+//            }
+//            //查出公司绑定openid并赋值
+//        }
+
         //判断服务号配置是否存在
         if (StringUtils.isNotEmpty(config.getMpAppId())){
             packetParam.setMpAppId(config.getMpAppId());
@@ -1207,28 +1194,8 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         logger.info("红包金额 {},红包商户号 {}",amount,packetParam);
         //2025.6.19 红包金额为0的时候
         if (amount.compareTo(BigDecimal.ZERO)>0){
-
-            //---------------发红包前先判断润天账户余额是否足够---------
-            RLock lock = redissonClient.getLock(REDPACKET_POOL_LOCK);
-            try{
-                boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
-
-                if (!locked) {
-                    logger.error("获取锁失败");
-                    return R.error("[红包领取] 系统繁忙,请重试!");
-                }
-
-                // 发送红包
-                return sendRedPacketRewardToUser(param, log, config, packetParam, amount);
-
-            }catch (Exception e){
-                logger.error("领取红包失败原因:{}", ExceptionUtils.getFullStackTrace(e),e);
-                throw new RuntimeException(e);
-            }finally {
-                if (lock.isHeldByCurrentThread()) {
-                    lock.unlock();
-                }
-            }
+            // 发送红包
+            return sendRedPacketRewardToUser(param, log, config, packetParam, amount);
         } else {
             FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
             // 添加红包记录
@@ -1256,44 +1223,6 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
     private R sendRedPacketRewardToUser(FsCourseSendRewardUParam param, FsCourseWatchLog log, CourseConfig config, WxSendRedPacketParam packetParam, BigDecimal amount) {
 
-        // 判断当前用户是否限流
-        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
-        String today = sdf.format(new Date());
-        String userLimitKey = String.format(REDPACKET_USER_LIMIT, today, param.getUserId());
-        Integer userCount =  redisTemplateInteger.opsForValue().get(userLimitKey);
-
-        // 首次领取
-        if(userCount == null) {
-            userCount = 0;
-            long expireSeconds = getExpireSeconds();
-            redisTemplateInteger.opsForValue().set(userLimitKey, userCount, expireSeconds, TimeUnit.SECONDS);
-        }
-
-        if(userCount >= RED_PACKET_LIMIT_COUNT){
-            logger.info("[红包领取] 用户{} 领取红包已经达到最大限制!",param.getUserId());
-            return R.error("[红包领取] 当前用户当前已经领取红包已经达到限制!");
-        }
-
-
-        BigDecimal companyMoney = null;
-        if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
-            companyMoney = redisTemplate.opsForValue().get(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);
@@ -1319,44 +1248,19 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             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));
-            }
 
             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);
-                redisTemplate.opsForValue().set(REDPACKET_COMPANY_MONEY,companyMoney);
-            }
-
-            // 用户领取红包次数+1
-            redisTemplateInteger.opsForValue().increment(userLimitKey, 1);
-
             return sendRedPacket;
         } else {
             return R.error("奖励发送失败,请联系客服");
         }
     }
 
-    private static long getExpireSeconds() {
-        Calendar calendar = Calendar.getInstance();
-        calendar.add(Calendar.DAY_OF_YEAR, 1);
-        calendar.set(Calendar.HOUR_OF_DAY, 0);
-        calendar.set(Calendar.MINUTE, 0);
-        calendar.set(Calendar.SECOND, 0);
-        calendar.set(Calendar.MILLISECOND, 0);
-        // 计算从现在到明天凌晨的秒数
-        long expireSeconds = (calendar.getTimeInMillis() - System.currentTimeMillis()) / 1000;
-        return expireSeconds;
-    }
+
 
 
     private void handleFsUserWx(FsUser user, String appId) {
@@ -1463,112 +1367,43 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                 return R.error("服务商余额不足,请联系群主服务器充值!");
             }
 
-            //---------------发红包前先判断润天账户余额是否足够---------
-            RLock lock = redissonClient.getLock(REDPACKET_POOL_LOCK);
-            try{
-                boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
-
-                if (!locked) {
-                    logger.error("获取锁失败");
-                    return R.error("[红包领取] 系统繁忙,请重试!");
-                }
-
-                // 判断当前用户是否限流
-                SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
-                String today = sdf.format(new Date());
-                String userLimitKey = String.format(REDPACKET_USER_LIMIT, today, param.getUserId());
-                Integer userCount =  redisTemplateInteger.opsForValue().get(userLimitKey);
-
-                // 首次领取
-                if(userCount == null) {
-                    userCount = 0;
-                    long expireSeconds = getExpireSeconds();
-                    redisTemplateInteger.opsForValue().set(userLimitKey, userCount, expireSeconds, TimeUnit.SECONDS);
-                }
-
-                if(userCount >= RED_PACKET_LIMIT_COUNT){
-                    logger.info("[红包领取] 用户{} 领取红包已经达到最大限制!",param.getUserId());
-                    return R.error("[红包领取] 当前用户当前已经领取红包已经达到限制!");
-                }
-
-                BigDecimal companyMoney = null;
-                if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
-                    companyMoney = redisTemplate.opsForValue().get(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.setBatchId(sendRedPacket.get("batchId").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());
-                    redPacketLog.setAppId(param.getAppId());
-                    if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
-                        redPacketLog.setAccBalanceBefore(companyMoney);
-                        redPacketLog.setAccBalanceAfter(companyMoney.subtract(amount));
-                    }
-                    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);
-                        redisTemplate.opsForValue().set(REDPACKET_COMPANY_MONEY,companyMoney);
-                    }
-
-                    // 用户领取红包次数+1
-                    redisTemplateInteger.opsForValue().increment(userLimitKey, 1);
-                    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();
+            // 发送红包
+            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.setBatchId(sendRedPacket.get("batchId").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());
+                redPacketLog.setAppId(param.getAppId());
+
+                redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
+
+                // 更新观看记录的奖励类型
+                log.setRewardType(config.getRewardType());
+                courseWatchLogMapper.updateFsCourseWatchLog(log);
+
+                return sendRedPacket;
+            } else {
+                return R.error("奖励发送失败,请联系客服");
             }
-
         } else {
             FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
             // 添加红包记录
@@ -1868,7 +1703,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         }
 
         // 查询【用户-项目】关系
-        FsUserCompanyUser userCompanyUser = userCompanyUserService.selectByUserIdAndProjectId(fsUser.getUserId(), courseProject);
+        FsUserCompanyUser userCompanyUser = userCompanyUserService.selectByUserIdAndProjectId(fsUser.getUserId(), courseProject,companyUser.getUserId());
 
         // 添加逻辑:如果存在fs_user表数据,但是又不存在fs_user_company_user表,则表示是以前企微看课的,需要手动绑定
         if(Objects.isNull(userCompanyUser)) {

+ 100 - 0
fs-service/src/main/java/com/fs/his/domain/RedPacketLog.java

@@ -0,0 +1,100 @@
+package com.fs.his.domain;
+
+import lombok.Data;
+import lombok.Builder;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.Date;
+
+/**
+ * 红包发放日志表
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class RedPacketLog {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 用户ID
+     */
+    private Long userId;
+
+    /**
+     * 红包金额
+     */
+    private BigDecimal amount;
+
+    /**
+     * 公司ID
+     */
+    private Long companyId;
+
+    /**
+     * 来源 1:h5 2:看课小程序
+     */
+    private Integer source;
+
+    /**
+     * 红包模式
+     */
+    private Integer redPacketMode;
+
+    /**
+     * 应用ID
+     */
+    private String appId;
+
+    /**
+     * 扣减前余额
+     */
+    private BigDecimal accBalanceBefore;
+
+    /**
+     * 扣减后余额
+     */
+    private BigDecimal accBalanceAfter;
+
+    /**
+     * 状态:0-处理中 1-成功 2-失败
+     */
+    private Integer status;
+
+    /**
+     * 错误信息
+     */
+    private String errorMsg;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 创建人
+     */
+    private String createBy;
+
+    /**
+     * 更新人
+     */
+    private String updateBy;
+
+    /**
+     * 备注
+     */
+    private String remark;
+}

+ 88 - 0
fs-service/src/main/java/com/fs/his/mapper/RedPacketLogMapper.java

@@ -0,0 +1,88 @@
+package com.fs.his.mapper;
+
+import com.fs.his.domain.RedPacketLog;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+/**
+ * 红包发放日志表 Mapper接口
+ */
+@Mapper
+public interface RedPacketLogMapper {
+
+    /**
+     * 根据ID查询红包发放日志
+     *
+     * @param id 主键ID
+     * @return 红包发放日志
+     */
+    @Select("SELECT * FROM red_packet_log WHERE id = #{id}")
+    RedPacketLog selectById(Long id);
+
+    /**
+     * 查询用户红包发放日志列表
+     *
+     * @param userId 用户ID
+     * @return 红包发放日志列表
+     */
+    @Select("SELECT * FROM red_packet_log WHERE user_id = #{userId} ORDER BY create_time DESC")
+    List<RedPacketLog> selectByUserId(Long userId);
+
+    /**
+     * 查询公司红包发放日志列表
+     *
+     * @param companyId 公司ID
+     * @return 红包发放日志列表
+     */
+    @Select("SELECT * FROM red_packet_log WHERE company_id = #{companyId} ORDER BY create_time DESC")
+    List<RedPacketLog> selectByCompanyId(Long companyId);
+
+    /**
+     * 查询指定状态的红包发放日志列表
+     *
+     * @param status 状态
+     * @return 红包发放日志列表
+     */
+    @Select("SELECT * FROM red_packet_log WHERE status = #{status} ORDER BY create_time DESC")
+    List<RedPacketLog> selectByStatus(Integer status);
+
+    /**
+     * 插入红包发放日志
+     *
+     * @param redPacketLog 红包发放日志
+     * @return 影响行数
+     */
+    @Insert("INSERT INTO red_packet_log (user_id, amount, company_id, source, red_packet_mode, app_id, " +
+            "acc_balance_before, acc_balance_after, status, error_msg, create_by, update_by, remark) " +
+            "VALUES (#{userId}, #{amount}, #{companyId}, #{source}, #{redPacketMode}, #{appId}, " +
+            "#{accBalanceBefore}, #{accBalanceAfter}, #{status}, #{errorMsg}, #{createBy}, #{updateBy}, #{remark})")
+    @Options(useGeneratedKeys = true, keyProperty = "id")
+    int insert(RedPacketLog redPacketLog);
+
+    /**
+     * 更新红包发放日志
+     *
+     * @param redPacketLog 红包发放日志
+     * @return 影响行数
+     */
+    @Update("<script>" +
+            "UPDATE red_packet_log SET " +
+            "<if test='status != null'>status = #{status}, </if>" +
+            "<if test='errorMsg != null'>error_msg = #{errorMsg}, </if>" +
+            "<if test='updateBy != null'>update_by = #{updateBy}, </if>" +
+            "<if test='remark != null'>remark = #{remark}, </if>" +
+            "update_time = NOW() " +
+            "WHERE id = #{id}" +
+            "</script>")
+    int update(RedPacketLog redPacketLog);
+
+    /**
+     * 根据ID删除红包发放日志
+     *
+     * @param id 主键ID
+     * @return 影响行数
+     */
+    @Delete("DELETE FROM red_packet_log WHERE id = #{id}")
+    int deleteById(Long id);
+}

+ 194 - 35
fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java

@@ -3,7 +3,10 @@ package com.fs.his.service.impl;
 import java.lang.reflect.Field;
 import java.math.BigDecimal;
 import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
 import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
 
 import cn.binarywang.wx.miniapp.api.WxMaService;
 import cn.hutool.core.util.IdUtil;
@@ -11,6 +14,7 @@ import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.TypeReference;
 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.annotation.DataScope;
 import com.fs.common.annotation.Log;
@@ -45,10 +49,7 @@ import com.fs.erp.dto.ErpRefundUpdateRequest;
 import com.fs.his.domain.*;
 import com.fs.his.dto.PayConfigDTO;
 import com.fs.his.enums.PaymentMethodEnum;
-import com.fs.his.mapper.FsExportTaskMapper;
-import com.fs.his.mapper.FsStorePaymentMapper;
-import com.fs.his.mapper.FsUserMapper;
-import com.fs.his.mapper.FsUserWxMapper;
+import com.fs.his.mapper.*;
 import com.fs.his.param.FsStoreOrderParam;
 import com.fs.his.param.FsStorePaymentParam;
 import com.fs.his.param.PayOrderParam;
@@ -110,10 +111,16 @@ import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferRequ
 import me.chanjar.weixin.common.bean.WxJsapiSignature;
 import me.chanjar.weixin.common.error.WxErrorException;
 import me.chanjar.weixin.mp.api.WxMpService;
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.hc.core5.concurrent.CompletedFuture;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
@@ -174,6 +181,40 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
     @Autowired
     private CloudHostProper cloudHostProper;
 
+    @Autowired
+    private RedisTemplate<String,BigDecimal> redisTemplate;
+
+    @Autowired
+    private RedisTemplate<String,Integer> redisTemplateInteger;
+    /**
+     * 红包领取数量限制 默认一个用户当天最多只能领取10个
+     */
+    @Value("${RED_PACKET_LIMIT_COUNT:10}")
+    private Integer RED_PACKET_LIMIT_COUNT;
+    @Autowired
+    private ISysConfigService sysConfigService;
+
+    /**
+     * 是否开启红包账户扣减
+     */
+    @Value("${enableRedPackAccount:0}")
+    private String ENABLE_RED_PACK_ACCOUNT;
+
+    /**
+     * 红包账户锁
+     */
+    private static final String REDPACKET_POOL_LOCK = "redpacket_pool_lock";
+
+    /**
+     * 公司红包金额
+     */
+    private static final String REDPACKET_COMPANY_MONEY = "redpacket_money";
+
+    /**
+     * 用户领取红包限制
+     */
+    private static final String REDPACKET_USER_LIMIT = "redpacket_user_limit:%s:%d";
+
     /**
      * 查询支付明细
      *
@@ -480,44 +521,162 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
     @Autowired
     private ICompanyConfigService companyConfigService;
 
+    @Autowired
+    private RedissonClient redissonClient;
+
+    @Autowired
+    private RedPacketLogMapper redPacketLogMapper;
     @Override
     @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
     public R sendRedPacket(WxSendRedPacketParam param) {
 
-        String json;
-        RedPacketConfig config = new RedPacketConfig();
-        // 根据红包模式获取配置
-        switch (param.getRedPacketMode()){
-            case 1:
-                json = configService.selectConfigByKey("redPacket.config");
-                config = JSONUtil.toBean(json, RedPacketConfig.class);
-                break;
-            case 2:
-                json = companyConfigService.selectRedPacketConfigByKey(param.getCompanyId());
-                config = JSONUtil.toBean(json, RedPacketConfig.class);
-                break;
-        }
-        //H5的用公众号的appid发,小程序的用小程序的appid来发
-        if (param.getSource()==2){
-            // 传参appId为空时,仍然使用配置里面的
-            String appId = StringUtils.isBlank(param.getAppId()) ? config.getMiniappId() : param.getAppId();
-            config.setAppId(appId);
-        }
-        logger.info("最终传参 {}",config);
-        //组合返回参数
-        R result = new R();
-        // 根据 isNew 判断使用哪种发红包方式
-        if (config.getIsNew() != null && config.getIsNew() == 1) {
-            result = sendRedPacketV3Internal(param, config);
-        } else {
-            result= sendRedPacketLegacyInternal(param, config);
+        //---------------发红包前先判断润天账户余额是否足够---------
+        RLock lock = redissonClient.getLock(REDPACKET_POOL_LOCK);
+        RedPacketLog redPacketLog = null;
+
+        try{
+            boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
+
+            if (!locked) {
+                logger.error("获取锁失败");
+                return R.error("[红包领取] 系统繁忙,请重试!");
+            }
+
+            FsUser user = param.getUser();
+            BigDecimal amount = param.getAmount();
+
+            if(user == null) {
+                throw new IllegalArgumentException("[发送红包] 用户id为必传参数!");
+            }
+            Long userId = user.getUserId();
+
+            // 判断当前用户是否限流
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+            String today = sdf.format(new Date());
+            String userLimitKey = String.format(REDPACKET_USER_LIMIT, today, userId);
+            Integer userCount =  redisTemplateInteger.opsForValue().get(userLimitKey);
+
+
+            // 首次领取
+            if(userCount == null) {
+                userCount = 0;
+                long expireSeconds = getExpireSeconds();
+                redisTemplateInteger.opsForValue().set(userLimitKey, userCount, expireSeconds, TimeUnit.SECONDS);
+            }
+
+            if(userCount >= RED_PACKET_LIMIT_COUNT){
+                logger.info("[红包领取] 用户{} 领取红包已经达到最大限制!",userId);
+                return R.error("[红包领取] 当前用户当前已经领取红包已经达到限制!");
+            }
+
+
+            BigDecimal companyMoney = null;
+
+            if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
+                companyMoney = redisTemplate.opsForValue().get(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("[红包领取] 账户余额不足,请联系管理员!");
+                }
+
+                redPacketLog = new RedPacketLog();
+                redPacketLog.setRedPacketMode(param.getRedPacketMode());
+                redPacketLog.setAmount(param.getAmount());
+                redPacketLog.setAppId(param.getAppId());
+                redPacketLog.setCompanyId(param.getCompanyId());
+                redPacketLog.setCreateTime(LocalDateTime.now());
+                redPacketLog.setUserId(userId);
+                redPacketLog.setAccBalanceBefore(companyMoney);
+                redPacketLog.setSource(param.getSource());
+            }
+
+            String json;
+            RedPacketConfig config = new RedPacketConfig();
+            // 根据红包模式获取配置
+            switch (param.getRedPacketMode()){
+                case 1:
+                    json = configService.selectConfigByKey("redPacket.config");
+                    config = JSONUtil.toBean(json, RedPacketConfig.class);
+                    break;
+                case 2:
+                    json = companyConfigService.selectRedPacketConfigByKey(param.getCompanyId());
+                    config = JSONUtil.toBean(json, RedPacketConfig.class);
+                    break;
+            }
+            //H5的用公众号的appid发,小程序的用小程序的appid来发
+            if (param.getSource()==2){
+                // 传参appId为空时,仍然使用配置里面的
+                String appId = StringUtils.isBlank(param.getAppId()) ? config.getMiniappId() : param.getAppId();
+                config.setAppId(appId);
+            }
+            logger.info("最终传参 {}",config);
+            //组合返回参数
+            R result = new R();
+            // 根据 isNew 判断使用哪种发红包方式
+            if (config.getIsNew() != null && config.getIsNew() == 1) {
+                result = sendRedPacketV3Internal(param, config);
+            } else {
+                result= sendRedPacketLegacyInternal(param, config);
+            }
+            result.put("mchId",config.getMchId()+"");
+            result.put("isNew",config.getIsNew());
+            logger.info("红包返回:{}",result);
+
+
+            if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
+                // 更新账户余额
+                logger.info("[更新账户余额] 当前余额{} 更新后余额{}",companyMoney.toPlainString(),companyMoney.subtract(amount).toPlainString());
+
+                companyMoney = companyMoney.subtract(amount);
+                redisTemplate.opsForValue().set(REDPACKET_COMPANY_MONEY,companyMoney);
+
+
+                redPacketLog.setAccBalanceAfter(companyMoney);
+                redPacketLog.setUpdateTime(LocalDateTime.now());
+                redPacketLog.setStatus(1);
+            }
+
+            // 用户领取红包次数+1
+            redisTemplateInteger.opsForValue().increment(userLimitKey, 1);
+            return result;
+        }catch (Exception e){
+            logger.error("领取红包失败原因:{}", ExceptionUtils.getFullStackTrace(e),e);
+            if(redPacketLog != null) {
+                redPacketLog.setStatus(2);
+                redPacketLog.setErrorMsg(ExceptionUtils.getFullStackTrace(e));
+            }
+            throw new RuntimeException(e);
+        }finally {
+            if (lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
+            if(redPacketLog != null) {
+                redPacketLogMapper.insert(redPacketLog);
+            }
         }
-        result.put("mchId",config.getMchId()+"");
-        result.put("isNew",config.getIsNew());
-        logger.info("红包返回:{}",result);
-        return result;
     }
 
+    private static long getExpireSeconds() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.add(Calendar.DAY_OF_YEAR, 1);
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        // 计算从现在到明天凌晨的秒数
+        return (calendar.getTimeInMillis() - System.currentTimeMillis()) / 1000;
+    }
     // 内部方法:处理新版本的发红包逻辑
     private R sendRedPacketV3Internal(WxSendRedPacketParam param, RedPacketConfig config) {
 

+ 64 - 18
fs-service/src/main/java/com/fs/qw/mapper/QwFriendWelcomeMapper.java

@@ -55,25 +55,71 @@ public interface QwFriendWelcomeMapper
      * @param qwFriendWelcomeParam 好友欢迎语
      * @return 好友欢迎语集合
      */
+//    @Select("<script> " +
+//            "select  qfw.*  from qw_friend_welcome qfw " +
+//            "left join qw_user qu  ON FIND_IN_SET(qu.id,REPLACE(REPLACE(REPLACE(qfw.qw_user_ids, '[', ''), ']', ''), ' ', '')) > 0 " +
+//            "LEFT JOIN company_user cu on  cu.user_id =qu.company_user_id " +
+//            "        <where>  \n" +
+//            "            <if test=\"qwUserIds != null  and qwUserIds != ''\"> and  FIND_IN_SET(#{qwUserIds},REPLACE(REPLACE(REPLACE(qw_user_ids, '[', ''), ']', ''), ' ', '')) > 0 </if>\n" +
+//            "            <if test=\"isSendMsg != null \"> and qfw.is_send_msg = #{isSendMsg}</if>\n" +
+//            "            <if test=\"welcomeText != null  and welcomeText != ''\"> and qfw.welcome_text = #{welcomeText}</if>\n" +
+//            "            <if test=\"isDayparting != null \"> and qfw.is_dayparting = #{isDayparting}</if>\n" +
+//            "            <if test=\"companyId != null \"> and qfw.company_id = #{companyId}</if>\n" +
+//            "            <if test=\"createTime != null \"> and qfw.create_time = #{createTime}</if>\n" +
+//            "            <if test=\"updateTime != null \"> and qfw.update_time = #{updateTime}</if>\n" +
+//            "            <if test=\"companyUserId != null \"> and qu.company_user_id = #{companyUserId}</if>\n" +
+//            "            <if test=\"cuDeptIdList != null and !cuDeptIdList.isEmpty() and  userType != '00' \">" +
+//            "               AND cu.dept_id IN " +
+//            "                   <foreach collection='cuDeptIdList' item='item' open='(' separator=',' close=')'> " +
+//            "                       #{item} " +
+//            "                   </foreach> " +
+//            "            </if>" +
+//            "        </where>" +
+//            "</script>")
+//    public List<QwFriendWelcome> selectQwFriendWelcomeListMyVO(QwFriendWelcomeParam qwFriendWelcomeParam);
     @Select("<script> " +
-            "select  qfw.*  from qw_friend_welcome qfw " +
-            "left join qw_user qu  ON FIND_IN_SET(qu.id,REPLACE(REPLACE(REPLACE(qfw.qw_user_ids, '[', ''), ']', ''), ' ', '')) > 0 " +
-            "        <where>  \n" +
-            "            <if test=\"qwUserIds != null  and qwUserIds != ''\"> and  FIND_IN_SET(#{qwUserIds},REPLACE(REPLACE(REPLACE(qw_user_ids, '[', ''), ']', ''), ' ', '')) > 0 </if>\n" +
-            "            <if test=\"isSendMsg != null \"> and qfw.is_send_msg = #{isSendMsg}</if>\n" +
-            "            <if test=\"welcomeText != null  and welcomeText != ''\"> and qfw.welcome_text = #{welcomeText}</if>\n" +
-            "            <if test=\"isDayparting != null \"> and qfw.is_dayparting = #{isDayparting}</if>\n" +
-            "            <if test=\"companyId != null \"> and qfw.company_id = #{companyId}</if>\n" +
-            "            <if test=\"createTime != null \"> and qfw.create_time = #{createTime}</if>\n" +
-            "            <if test=\"updateTime != null \"> and qfw.update_time = #{updateTime}</if>\n" +
-            "            <if test=\"companyUserId != null \"> and qu.company_user_id = #{companyUserId}</if>\n" +
-            "            <if test=\"cuDeptIdList != null and !cuDeptIdList.isEmpty() and  userType != '00' \">" +
-            "               AND cu.dept_id IN " +
-            "                   <foreach collection='cuDeptIdList' item='item' open='(' separator=',' close=')'> " +
-            "                       #{item} " +
-            "                   </foreach> " +
-            "            </if>" +
-            "        </where>" +
+            "SELECT qfw.* FROM qw_friend_welcome qfw " +
+            "WHERE " +
+            "   <if test=\"qwUserIds != null and qwUserIds != ''\"> " +
+            "       EXISTS ( " +
+            "           SELECT 1 FROM qw_user qu " +
+            "           JOIN company_user cu ON cu.user_id = qu.company_user_id " +
+            "           WHERE FIND_IN_SET(qu.id, REPLACE(REPLACE(REPLACE(qfw.qw_user_ids, '[', ''), ']', ''), ' ', '')) > 0 " +
+            "           AND qu.id = #{qwUserIds} " +
+            "       ) AND " +
+            "   </if>" +
+            "   <if test=\"isSendMsg != null\"> qfw.is_send_msg = #{isSendMsg} AND </if>" +
+            "   <if test=\"welcomeText != null and welcomeText != ''\"> qfw.welcome_text = #{welcomeText} AND </if>" +
+            "   <if test=\"isDayparting != null\"> qfw.is_dayparting = #{isDayparting} AND </if>" +
+            "   <if test=\"companyId != null\"> qfw.company_id = #{companyId} AND </if>" +
+            "   <if test=\"corpId != null\"> " +
+            "       EXISTS ( " +
+            "           SELECT 1 FROM qw_user qu " +
+            "           JOIN company_user cu ON cu.user_id = qu.company_user_id " +
+            "           WHERE FIND_IN_SET(qu.id, REPLACE(REPLACE(REPLACE(qfw.qw_user_ids, '[', ''), ']', ''), ' ', '')) > 0 " +
+            "           AND qu.corp_id = #{corpId} " +
+            "       ) AND " +
+            "   </if>" +
+            "   <if test=\"companyUserId != null\"> " +
+            "       EXISTS ( " +
+            "           SELECT 1 FROM qw_user qu " +
+            "           JOIN company_user cu ON cu.user_id = qu.company_user_id " +
+            "           WHERE FIND_IN_SET(qu.id, REPLACE(REPLACE(REPLACE(qfw.qw_user_ids, '[', ''), ']', ''), ' ', '')) > 0 " +
+            "           AND qu.company_user_id = #{companyUserId} " +
+            "       ) AND " +
+            "   </if>" +
+            "   <if test=\"cuDeptIdList != null and !cuDeptIdList.isEmpty() and userType != '00'\"> " +
+            "       EXISTS ( " +
+            "           SELECT 1 FROM qw_user qu " +
+            "           JOIN company_user cu ON cu.user_id = qu.company_user_id " +
+            "           WHERE FIND_IN_SET(qu.id, REPLACE(REPLACE(REPLACE(qfw.qw_user_ids, '[', ''), ']', ''), ' ', '')) > 0 " +
+            "           AND cu.dept_id IN " +
+            "               <foreach collection='cuDeptIdList' item='item' open='(' separator=',' close=')'> " +
+            "                   #{item} " +
+            "               </foreach> " +
+            "       ) AND " +
+            "   </if>" +
+            "   1=1 "+
             "</script>")
     public List<QwFriendWelcome> selectQwFriendWelcomeListMyVO(QwFriendWelcomeParam qwFriendWelcomeParam);
 

+ 4 - 0
fs-service/src/main/resources/application-config-druid-jzzx.yml

@@ -46,6 +46,10 @@ wx:
         secret: 1afa05f0c71beff0d52fb849c62e479a # 公众号的appsecret
         token: PPKOdAlCoMO # 接口配置里的Token值
         aesKey: Eswa6VjwtVMCcw03qZy6fWllgrv5aytIA1SZPEU0kU2 # 接口配置里的EncodingAESKey值
+  # 开放平台app微信授权配置
+  open:
+    app-id: wxe4d352ea8ddbcf3c
+    secret: be6c179d79fcf97cbfb0b36c08877220
 aifabu:  #爱链接
   appKey: 7b471be905ab17e00f3b858c6710dd117601d008
 watch:

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

@@ -141,5 +141,8 @@ rocketmq:
 openIM:
   secret: op
   userID: im
+
 #是否为新商户,新商户不走mpOpenId
-isNewWxMerchant: true
+isNewWxMerchant: false
+
+enableRedPackAccount: 1

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

@@ -171,4 +171,6 @@ openIM:
     secret: openIM123
     userID: imAdmin
 #是否为新商户,新商户不走mpOpenId
-isNewWxMerchant: true
+isNewWxMerchant: false
+
+enableRedPackAccount: 1

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

@@ -146,6 +146,6 @@ openIM:
   secret: op
   userID: im
 #是否为新商户,新商户不走mpOpenId
-isNewWxMerchant: true
+isNewWxMerchant: false
 
 enableRedPackAccount: 1

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

@@ -168,3 +168,5 @@ openIM:
     userID:
 #是否为新商户,新商户不走mpOpenId
 isNewWxMerchant: false
+
+enableRedPackAccount: 1

+ 1 - 1
fs-service/src/main/resources/mapper/company/CompanyMapper.xml

@@ -232,7 +232,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
     <select id="selectCompanyByIds2" parameterType="Long" resultType="Company">
         <include refid="selectCompanyVo"/>
-        where company_id in
+        where is_del = 0 and company_id in
         <foreach item="companyId" collection="companyIds" open="(" separator="," close=")">
             #{companyId}
         </foreach>

+ 15 - 4
fs-user-app/src/main/java/com/fs/app/controller/course/CourseFsUserController.java

@@ -2,12 +2,15 @@ package com.fs.app.controller.course;
 
 
 
+import cn.hutool.core.util.ObjectUtil;
 import com.fs.app.annotation.UserOperationLog;
 import com.fs.app.controller.AppBaseController;
 import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
 import com.fs.app.annotation.Login;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.utils.SecurityUtils;
 import com.fs.course.param.FsCourseQuestionAnswerUParam;
 import com.fs.course.param.FsCourseSendRewardUParam;
 import com.fs.course.param.FsUserCourseVideoFinishUParam;
@@ -53,8 +56,10 @@ public class CourseFsUserController extends AppBaseController {
     @ApiOperation("判断是否添加客服(是否关联销售)")
     @PostMapping("/isAddKf")
     public ResponseResult<FsUser> isAddCompanyUser(@Valid @RequestBody FsUserCourseAddCompanyUserParam param) {
-        Long userId = Long.parseLong(getUserId());
-        param.setUserId(userId);
+        if (ObjectUtil.isEmpty(param.getUserId())){
+            Long userId = Long.parseLong(getUserId());
+            param.setUserId(userId);
+        }
         return courseVideoService.isAddCompanyUser(param);
     }
 
@@ -103,7 +108,10 @@ public class CourseFsUserController extends AppBaseController {
     @PostMapping("/courseAnswer")
     @UserOperationLog(operationType = FsUserOperationEnum.ANSWER)
     public R courseAnswer(@RequestBody FsCourseQuestionAnswerUParam param){
-        param.setUserId(Long.parseLong(getUserId()));
+        if (ObjectUtil.isEmpty(param.getUserId())){
+            Long userId = Long.parseLong(getUserId());
+            param.setUserId(userId);
+        }
         logger.info("zyp \n【答题】:{}",param.getQuestions());
         if (param.getDuration()==null){
             logger.info("zyp \n【未识别到时长】:{}",param.getUserId());
@@ -117,7 +125,10 @@ public class CourseFsUserController extends AppBaseController {
     @RepeatSubmit
     public R sendReward(@RequestBody FsCourseSendRewardUParam param)
     {
-        param.setUserId(Long.parseLong(getUserId()));
+        if (ObjectUtil.isEmpty(param.getUserId())){
+            Long userId = Long.parseLong(getUserId());
+            param.setUserId(userId);
+        }
         logger.info("zyp \n【发放奖励】:{}",param);
         return courseVideoService.sendRewardByFsUser(param);
     }