Parcourir la source

Merge remote-tracking branch 'origin/master'

Guos il y a 21 heures
Parent
commit
32c36107b2
21 fichiers modifiés avec 229 ajouts et 68 suppressions
  1. 2 1
      fs-company/src/main/java/com/fs/company/controller/live/OrderController.java
  2. 7 7
      fs-live-app/src/main/java/com/fs/live/task/Task.java
  3. 9 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodServiceImpl.java
  4. 22 21
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  5. 54 0
      fs-service/src/main/java/com/fs/enums/ExceptionCodeEnum.java
  6. 1 0
      fs-service/src/main/java/com/fs/his/enums/FsUserIntegralLogTypeEnum.java
  7. 6 0
      fs-service/src/main/java/com/fs/hisStore/domain/FsStoreAfterSalesScrm.java
  8. 3 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreAfterSalesScrmMapper.java
  9. 9 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsUserScrmMapper.java
  10. 36 1
      fs-service/src/main/java/com/fs/live/service/impl/LiveRedConfServiceImpl.java
  11. 15 8
      fs-service/src/main/java/com/fs/live/service/impl/LiveWatchUserServiceImpl.java
  12. 8 0
      fs-service/src/main/java/com/fs/live/vo/LiveAfterSalesVo.java
  13. 2 2
      fs-service/src/main/resources/application-config-druid-ddgy.yml
  14. 2 2
      fs-service/src/main/resources/application-config-druid-fby.yml
  15. 2 2
      fs-service/src/main/resources/application-config-druid-gzzdy.yml
  16. 2 2
      fs-service/src/main/resources/application-config-druid-hst.yml
  17. 2 2
      fs-service/src/main/resources/application-config-druid-kyt.yml
  18. 6 0
      fs-service/src/main/resources/mapper/live/LiveAfterSalesMapper.xml
  19. 7 1
      fs-websocket/src/main/java/com/fs/websocket/FsWebSocketServiceApplication.java
  20. 4 4
      fs-websocket/src/main/java/com/fs/websocket/config/WebSocketConfig.java
  21. 30 15
      fs-websocket/src/main/java/com/fs/websocket/service/WebSocketServer.java

+ 2 - 1
fs-company/src/main/java/com/fs/company/controller/live/OrderController.java

@@ -66,7 +66,8 @@ public class OrderController extends BaseController
         if(param.getOrderTypeFilter() == null || param.getOrderTypeFilter().equals("2")){
             return getDataTable(new ArrayList<>());
         }
-
+        CompanyUser user = SecurityUtils.getLoginUser().getUser();
+        param.setCompanyId(user.getCompanyId());
         startPage();
         List<MergedOrderVO> list = mergedOrderService.selectMergedOrderList(param);
         for (MergedOrderVO vo : list) {

+ 7 - 7
fs-live-app/src/main/java/com/fs/live/task/Task.java

@@ -947,13 +947,13 @@ public class Task {
                 boolean needUpdate = false;
                 Integer newLogType = log.getLogType();
 
-                // ① 如果在线时长 <= 3分钟,修改 logType 为 4(看课中断)
-                if (onlineSeconds <= 180) { // 3分钟 = 180秒
-                    newLogType = 4;
-                    needUpdate = true;
-                }
-                // ③ 如果直播视频 >= 40分钟,在线时长 >= 30分钟,logType 设置为 2(完课)
-                else if (totalVideoDuration >= 2400 && onlineSeconds >= 1800) { // 40分钟 = 2400秒,30分钟 = 1800秒
+                // ① 如果在线时长 <= 3分钟,修改 logType 为 4(看课中断) lmx-这个逻辑不合理,不能这样判定看课中断
+//                if (onlineSeconds <= 180) { // 3分钟 = 180秒
+//                    newLogType = 4;
+//                    needUpdate = true;
+//                } else
+                    // ③ 如果直播视频 >= 40分钟,在线时长 >= 30分钟,logType 设置为 2(完课)
+                if (totalVideoDuration >= 2400 && onlineSeconds >= 1800) { // 40分钟 = 2400秒,30分钟 = 1800秒
                     newLogType = 2;
                     log.setFinishTime(now);
                     needUpdate = true;

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

@@ -146,6 +146,15 @@ public class FsUserCoursePeriodServiceImpl implements IFsUserCoursePeriodService
             coursePeriodDays.setStartDateTime(startDateTime);
             coursePeriodDays.setEndDateTime(endDateTime);
             coursePeriodDays.setLastJoinTime(lastJsonTime);
+
+            if(LocalDate.now().isBefore(coursePeriodDays.getStartDateTime().toLocalDate())){
+                coursePeriodDays.setStatus(0);
+            } else if(LocalDate.now().isAfter(coursePeriodDays.getStartDateTime().toLocalDate())){
+                coursePeriodDays.setStatus(2);
+            } else{
+                coursePeriodDays.setStatus(1);
+            }
+
             fsUserCoursePeriodDaysMapper.updateFsUserCoursePeriodDays(coursePeriodDays); // 更新数据库中的课程日期
         }
 

+ 22 - 21
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -48,6 +48,7 @@ import com.fs.course.service.IFsUserCompanyUserService;
 import com.fs.course.service.IFsUserCourseVideoService;
 import com.fs.course.vo.*;
 import com.fs.course.vo.newfs.*;
+import com.fs.enums.ExceptionCodeEnum;
 import com.fs.his.config.AppConfig;
 import com.fs.his.domain.FsUser;
 import com.fs.his.domain.FsUserIntegralLogs;
@@ -713,11 +714,11 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
         FsUser fsUser = fsUserMapper.selectFsUserByUserId(param.getUserId());
         //用户不存在唤起重新授权
         if (fsUser == null) {
-            return R.error(401, "未授权");
+            return R.error(ExceptionCodeEnum.USER_NOT_FOUND.getCode(), ExceptionCodeEnum.USER_NOT_FOUND.getDescription());
         }
 
         if (fsUser.getStatus() == 0) {
-            return R.error("会员被停用,无权限,请联系客服!");
+            return R.error(ExceptionCodeEnum.MEMBER_DISABLED.getCode(), ExceptionCodeEnum.MEMBER_DISABLED.getDescription());
         }
 //        if (param.getIsOpenCourse()!=null&&param.getIsOpenCourse()==1){
 //            FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideoByUserId(param.getUserId(), param.getVideoId());
@@ -763,7 +764,7 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
         if (oneCompanyCourse && fsUser.getQwExtId() != null) {
             QwExternalContact qwExternalContact = qwExternalContactMapper.selectById(fsUser.getQwExtId());
             if (qwExternalContact.getCompanyUserId() != null && !qwExternalContact.getCompanyUserId().equals(param.getCompanyUserId())) {
-                return R.error(500, "该用户(" + fsUser.getUserId() + ")已成为其他销售会员");
+                return R.error(ExceptionCodeEnum.USER_ALREADY_OTHER_SALES_MEMBER.getCode(), ExceptionCodeEnum.USER_ALREADY_OTHER_SALES_MEMBER.getFormattedDescription(fsUser.getUserId()));
             }
         }
 
@@ -775,7 +776,7 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
             List<QwExternalContact> qwExternalContacts = qwExternalContactMapper.selectQwExternalContactList(query);
             if (qwExternalContacts != null && !qwExternalContacts.isEmpty() && !Objects.equals(qwExternalContacts.get(0).getCompanyUserId(), param.getCompanyUserId())) {
                 String msgInfo = "该用户(" + fsUser.getUserId() + ")已在公司" + param.getCompanyId() + "成为其他销售会员";
-                return R.error(500, msgInfo);
+                return R.error(ExceptionCodeEnum.USER_COMPANY_OTHER_SALES_MEMBER.getCode(), ExceptionCodeEnum.USER_COMPANY_OTHER_SALES_MEMBER.getFormattedDescription(fsUser.getUserId(),param.getCompanyId()));
             }
         }
 
@@ -794,7 +795,7 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
         } else {
             // 非法参数
             logger.warn("非法参数 isRoom: {}", isRoom);
-            return R.error("参数错误!");
+            return R.error(ExceptionCodeEnum.PARAM_ERROR.getCode(), ExceptionCodeEnum.PARAM_ERROR.getDescription());
         }
 
     }
@@ -804,13 +805,13 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
 //                "\t\t\t\t\t<div style=\"color: #999;font-size: 14px;font-weight: bold;\">添加伴学助手免费领取会员权限</div>";
         QwGroupChat qwGroupChat = qwGroupChatMapper.selectQwGroupChatByChatId(courseLink.getChatId());
         if (qwGroupChat == null) {
-            return R.error("群参数异常");
+            return R.error(ExceptionCodeEnum.GROUP_PARAM_ERROR.getCode(), ExceptionCodeEnum.GROUP_PARAM_ERROR.getDescription());
         }
         SopUserLogsInfo sopUserLogsInfo = new SopUserLogsInfo();
         sopUserLogsInfo.setChatId(courseLink.getChatId());
         List<QwGroupChatUser> qwGroupChatUsers = qwGroupChatUserMapper.selectByChatId(sopUserLogsInfo);
         if (qwGroupChatUsers == null || qwGroupChatUsers.isEmpty()) {
-            return R.error("群参数异常");
+            return R.error(ExceptionCodeEnum.GROUP_PARAM_ERROR.getCode(), ExceptionCodeEnum.GROUP_PARAM_ERROR.getDescription());
         }
         //群聊寻找用户新逻辑
         QwExternalContact qwExternalContact = null;
@@ -2529,10 +2530,10 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
         //查询用户
         FsUser fsUser = fsUserMapper.selectFsUserById(param.getUserId());
         if (fsUser == null) {
-            return ResponseResult.fail(401, "当前用户信息不存在");
+            return ResponseResult.fail(ExceptionCodeEnum.USER_NOT_FOUND.getCode(), ExceptionCodeEnum.USER_NOT_FOUND.getDescription());
         }
         if (fsUser.getStatus() == 0) {
-            return ResponseResult.fail(503, "会员被停用,无权限,请联系客服!");
+            return ResponseResult.fail(ExceptionCodeEnum.MEMBER_DISABLED.getCode(), ExceptionCodeEnum.MEMBER_DISABLED.getDescription());
         }
         //公开课
         if (param.getIsOpenCourse() != null && param.getIsOpenCourse() == 1) {
@@ -2560,14 +2561,14 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
         //判断该销售是否存在
         CompanyUser companyUser = companyUserMapper.selectCompanyUserById(param.getCompanyUserId());
         if (companyUser == null) {
-            return ResponseResult.fail(405, "当前销售不存在");
+            return ResponseResult.fail(ExceptionCodeEnum.SALES_NOT_FOUND.getCode(), ExceptionCodeEnum.SALES_NOT_FOUND.getDescription());
         }
 
         // 获取课程所属项目id
         FsUserCourse fsUserCourse = fsUserCourseMapper.selectFsUserCourseByCourseId(param.getCourseId());
         Long courseProject = fsUserCourse.getProject();
         if (Objects.isNull(courseProject)) {
-            return ResponseResult.fail(504, "课程配置错误,项目归属为空,课程ID: " + param.getCourseId());
+            return ResponseResult.fail(ExceptionCodeEnum.COURSE_CONFIG_ERROR.getCode(),  ExceptionCodeEnum.COURSE_CONFIG_ERROR.getFormattedDescription(param.getCourseId()));
         }
         FsUserCoursePeriod fsUserCoursePeriod = fsUserCoursePeriodMapper.selectFsUserCoursePeriodById(param.getPeriodId());
         FsUserCompanyUser userCompanyUser = userCompanyUserService.selectByUserIdAndProjectId(fsUser.getUserId(), courseProject);
@@ -2580,7 +2581,7 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
                 Company company = companyService.selectCompanyById(param.getCompanyId());
 
                 if ((companyUser.getIsAllowedAllRegister() != null && companyUser.getIsAllowedAllRegister() != 1)) {
-                    return ResponseResult.fail(504, "当前销售禁止绑定会员,请联系销售!");
+                    return ResponseResult.fail(ExceptionCodeEnum.SALES_FORBIDDEN_BIND.getCode(), ExceptionCodeEnum.SALES_FORBIDDEN_BIND.getDescription());
                 }
                 // 使用 Stream API 检查是否包含 companyId
                 // 修正类型转换问题
@@ -2590,7 +2591,7 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
                         && Arrays.stream(fsUserCoursePeriod.getIsNeedRegisterMember().split(","))
                         .map(String::trim)
                         .anyMatch(id -> id.equals(String.valueOf(company.getCompanyId()))))) {
-                    return ResponseResult.fail(504, "请联系销售发送邀请链接成为会员!");
+                    return ResponseResult.fail(ExceptionCodeEnum.CONTACT_SALES_FOR_INVITATION.getCode(), ExceptionCodeEnum.CONTACT_SALES_FOR_INVITATION.getDescription());
                 }
                 int defaultStatus = (company != null ? company.getFsUserIsDefaultBlack() : 0) == 1 ? 0 : 1;
                 userCompanyUser = userCompanyUserService.bindRelationship(param.getUserId(), courseProject, companyUser.getCompanyId(), companyUser.getUserId(), defaultStatus);
@@ -2601,7 +2602,7 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
         if (!param.getCompanyUserId().equals(userCompanyUser.getCompanyUserId())) {
             log.error("进入::isAddCompanyUser 该用户fsUser={},companyUser={},param={}", fsUser, companyUser, param);
 
-            return ResponseResult.fail(500, "该用户(" + fsUser.getUserId() + ")已成为其他销售会员");
+            return ResponseResult.fail(ExceptionCodeEnum.USER_ALREADY_OTHER_SALES_MEMBER.getCode(), ExceptionCodeEnum.USER_ALREADY_OTHER_SALES_MEMBER.getFormattedDescription(fsUser.getUserId()));
         }
 
         // 如果开启了黑名单审核,需要提示
@@ -2612,9 +2613,9 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
 
         if (userCompanyUser.getStatus() == 2) {
             if ("福本源".equals(signProjectName)) {
-                return ResponseResult.fail(504, "服务暂时不可用,请联系管理员");
+                return ResponseResult.fail(ExceptionCodeEnum.SERVICE_UNAVAILABLE.getCode(), ExceptionCodeEnum.SERVICE_UNAVAILABLE.getDescription());
             } else {
-                return ResponseResult.fail(504, "已被拉黑,请联系管理员");
+                return ResponseResult.fail(ExceptionCodeEnum.USER_BLACKLISTED.getCode(), ExceptionCodeEnum.USER_BLACKLISTED.getDescription());
             }
         }
 
@@ -2623,14 +2624,14 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
         FsCourseWatchLog watchCourseVideo = courseWatchLogMapper.getCourseWatchLogByUser(param.getUserId(), param.getVideoId(), param.getPeriodId());
 
         if (!isUserCoursePeriodValid(param)) {
-            return ResponseResult.fail(504, "请观看最新的课程项目");
+            return ResponseResult.fail(ExceptionCodeEnum.WATCH_LATEST_COURSE.getCode(), ExceptionCodeEnum.WATCH_LATEST_COURSE.getDescription());
         }
         // 项目看课数限制
         if (!EXCLUDE_PROJECTS.contains(signProjectName) && !CloudHostUtils.hasCloudHostName("弘德堂")) {
             log.error("进入了看课限制:传入参数:={},watchCourseVideo={}",param, watchCourseVideo);
             Integer logCount = fsUserCourseMapper.selectTodayCourseWatchLogCountByUserIdAndProjectId(param.getUserId(), courseProject);
             if (Objects.isNull(watchCourseVideo) && logCount > 0) {
-                return ResponseResult.fail(504, "超过项目看课数量限制");
+                return ResponseResult.fail(ExceptionCodeEnum.EXCEED_COURSE_LIMIT.getCode(), ExceptionCodeEnum.EXCEED_COURSE_LIMIT.getDescription());
             }
         }else {
             log.error("没有进入看课限制:传入参数:={},watchCourseVideo={}存在问题 ",param, watchCourseVideo);
@@ -2640,7 +2641,7 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
             if (!watchCourseVideo.getCompanyUserId().equals(param.getCompanyUserId())) {
                 //提示
                 log.error("数据库存在销售信息:{},分享得销售信息:{}", watchCourseVideo.getCompanyUserId(), param.getCompanyUserId());
-                return ResponseResult.fail(504, "已看过其他销售分享的此课程,不能重复观看");
+                return ResponseResult.fail(ExceptionCodeEnum.ALREADY_WATCHED_OTHER_SALES_COURSE.getCode(), ExceptionCodeEnum.ALREADY_WATCHED_OTHER_SALES_COURSE.getDescription());
             }
 
             FsCourseWatchLog updateLog = new FsCourseWatchLog();
@@ -3684,11 +3685,11 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
         FsUser fsUser = fsUserMapper.selectFsUserByUserId(param.getUserId());
         //用户不存在唤起重新授权
         if (fsUser == null) {
-            return R.error(504, "未授权");
+            return R.error(ExceptionCodeEnum.USER_NOT_FOUND.getCode(), ExceptionCodeEnum.USER_NOT_FOUND.getDescription());
         }
 
         if (fsUser.getStatus() == 0) {
-            return R.error("会员被停用,无权限,请联系客服!");
+            return R.error(ExceptionCodeEnum.MEMBER_DISABLED.getCode(), ExceptionCodeEnum.MEMBER_DISABLED.getDescription());
         }
         return createWatchIsOpen(param);
     }

+ 54 - 0
fs-service/src/main/java/com/fs/enums/ExceptionCodeEnum.java

@@ -0,0 +1,54 @@
+package com.fs.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum ExceptionCodeEnum {
+
+    // ============ 用户相关错误 (400-419) ============
+    USER_NOT_FOUND(401, "当前用户信息不存在,请重新授权"),
+
+    // ============ 会员相关错误 (420-439) ============
+    USER_BLACKLISTED(421, "已被拉黑,请联系管理员"),
+
+    // ============ 销售相关错误 (440-459) ============
+    SALES_NOT_FOUND(441, "当前销售不存在"),
+    SALES_FORBIDDEN_BIND(442, "当前销售禁止绑定会员,请联系销售!"),
+    CONTACT_SALES_FOR_INVITATION(443, "请联系销售发送邀请链接成为会员!"),
+
+    // ============ 会员关系错误 (460-479) ============
+    MEMBER_DISABLED(461, "会员被停用,无权限,请联系客服!"),
+    USER_ALREADY_OTHER_SALES_MEMBER(462, "该用户(%s)已成为其他销售会员"),
+    USER_COMPANY_OTHER_SALES_MEMBER(463, "该用户(%s)已在公司%s成为其他销售会员"),
+
+    // ============ 课程相关错误 (480-499) ============
+    COURSE_CONFIG_ERROR(481, "课程配置错误,项目归属为空,课程ID: %s"),
+    WATCH_LATEST_COURSE(482, "请观看最新的课程项目"),
+    EXCEED_COURSE_LIMIT(483, "超过项目看课数量限制"),
+    ALREADY_WATCHED_OTHER_SALES_COURSE(484, "已看过其他销售分享的此课程,不能重复观看"),
+
+    // ============ 参数相关错误 (500-519) ============
+    PARAM_ERROR(501, "参数错误!"),
+    GROUP_PARAM_ERROR(502, "群参数异常"),
+    LIVE_PARAM_ERROR(503, "直播参数错误"),
+
+    // ============ 系统相关错误 (520-539) ============
+    SERVICE_UNAVAILABLE(521, "服务暂时不可用,请联系管理员");
+
+    private final Integer code;
+    private final String description;
+
+    ExceptionCodeEnum(Integer code, String description) {
+        this.code = code;
+        this.description = description;
+    }
+
+    /**
+     * 获取格式化后的描述信息
+     * @param args 格式化参数
+     * @return 格式化后的描述
+     */
+    public String getFormattedDescription(Object... args) {
+        return String.format(description, args);
+    }
+}

+ 1 - 0
fs-service/src/main/java/com/fs/his/enums/FsUserIntegralLogTypeEnum.java

@@ -33,6 +33,7 @@ public enum FsUserIntegralLogTypeEnum {
     TYPE_23(23,"管理员添加"),
     TYPE_24(24, "付费课程订阅"),
     TYPE_25(25, "直播完课积分"),
+    TYPE_26(26, "直播红包积分"),
     ;
 
 

+ 6 - 0
fs-service/src/main/java/com/fs/hisStore/domain/FsStoreAfterSalesScrm.java

@@ -150,4 +150,10 @@ public class FsStoreAfterSalesScrm extends BaseEntity
     @TableField(exist = false)
     private String hfOrderCode;
 
+    /**
+     * 用于查询银行交易流水
+     */
+    @TableField(exist = false)
+    private String bankTransactionId;
+
 }

+ 3 - 0
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreAfterSalesScrmMapper.java

@@ -102,6 +102,9 @@ public interface FsStoreAfterSalesScrmMapper
             "<if test =\"maps.hfOrderCode != null and  maps.hfOrderCode!='' \"> " +
               "and fsps.pay_code = #{maps.hfOrderCode} " +
             "</if>" +
+            "<if test =\"maps.bankTransactionId != null and  maps.bankTransactionId!='' \"> " +
+              "and fsps.bank_transaction_id = #{maps.bankTransactionId} " +
+            "</if>" +
             "<if test = 'maps.status != null    '> " +
             "and s.status = #{maps.status} " +
             "</if>" +

+ 9 - 0
fs-service/src/main/java/com/fs/hisStore/mapper/FsUserScrmMapper.java

@@ -124,6 +124,15 @@ public interface FsUserScrmMapper
     @Update("update fs_user set pay_count=pay_count+1" +
             " where user_id=#{userId}")
     int incPayCount(Long userId);
+    
+    /**
+     * 增加用户余额
+     * @param userId 用户ID
+     * @param integral 增加的积分
+     * @return 结果
+     */
+    @Update("update fs_user set integral = IFNULL(integral, 0) + #{integral} where user_id = #{userId}")
+    int incrIntegral(@Param("userId") Long userId, @Param("integral") BigDecimal integral);
     @Select("select * from fs_user where phone=#{phone}")
     FsUserScrm selectFsUserByPhone(String phone);
 

+ 36 - 1
fs-service/src/main/java/com/fs/live/service/impl/LiveRedConfServiceImpl.java

@@ -8,8 +8,13 @@ import com.fs.common.constant.LiveKeysConstant;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.DateUtils;
+import com.fs.his.domain.FsUserIntegralLogs;
+import com.fs.his.enums.FsUserIntegralLogTypeEnum;
+import com.fs.his.mapper.FsUserIntegralLogsMapper;
 import com.fs.his.mapper.FsUserMapper;
 import com.fs.his.service.IFsUserService;
+import com.fs.hisStore.mapper.FsUserIntegralLogsScrmMapper;
+import com.fs.hisStore.mapper.FsUserScrmMapper;
 import com.fs.live.domain.*;
 import com.fs.live.mapper.LiveMapper;
 import com.fs.live.mapper.LiveRedConfMapper;
@@ -57,6 +62,11 @@ public class LiveRedConfServiceImpl implements ILiveRedConfService {
     private LiveRewardRecordMapper liveRewardRecordMapper;
     @Autowired
     private ILiveAutoTaskService liveAutoTaskService;
+    @Autowired
+    private FsUserScrmMapper fsUserScrmMapper;
+    @Autowired
+    private FsUserIntegralLogsMapper fsUserIntegralLogsMapper;
+
 
     private static final String REDPACKET_REMAININGLOTS_KEY = "live:red:remainingLots:";
     private static final String REDPACKET_REMAININGNUM_KEY = "live:red:remainingNum:";
@@ -223,7 +233,7 @@ public class LiveRedConfServiceImpl implements ILiveRedConfService {
     @Transactional
     public R claimRedPacket(RedPO red) {
         // String claimKey = REDPACKET_CLAIM_KEY + red.getRedId();
-        Object o = redisCache.hashGet(String.format(LiveKeysConstant.LIVE_HOME_PAGE_CONFIG_RED, red.getLiveId(), red.getRedId()), String.valueOf(red.getUserId()));
+        Object o = redisCache.hashGet(String.format(LiveKeysConstant. LIVE_HOME_PAGE_CONFIG_RED, red.getLiveId(), red.getRedId()), String.valueOf(red.getUserId()));
         if (ObjectUtil.isNotEmpty(o)) {
             return R.error("您已经领取过红包了!");
         }
@@ -270,6 +280,31 @@ public class LiveRedConfServiceImpl implements ILiveRedConfService {
         record.setUserId(red.getUserId());
         record.setIntegral(integral);
         record.setCreateTime(new Date());
+        // 更新用户余额
+        BigDecimal balanceAmount = BigDecimal.valueOf(integral);
+        int updateResult = fsUserScrmMapper.incrIntegral(red.getUserId(), balanceAmount);
+        if (updateResult <= 0) {
+            log.error("更新用户余额失败,userId: {}, balance: {}", red.getUserId(), balanceAmount);
+            return R.error("更新用户余额失败");
+        }
+
+        // 查询用户当前余额
+        com.fs.hisStore.domain.FsUserScrm user = fsUserScrmMapper.selectFsUserById(red.getUserId());
+        Long currentIntegral = user.getIntegral() != null ? user.getIntegral() : 0L;
+        Long newIntegral = currentIntegral + integral;
+
+        // 添加余额变动记录
+        FsUserIntegralLogs integralLogs = new FsUserIntegralLogs();
+        integralLogs.setUserId(red.getUserId());
+        integralLogs.setIntegral(integral);
+        integralLogs.setBalance(newIntegral);
+        integralLogs.setLogType(FsUserIntegralLogTypeEnum.TYPE_26.getValue()); // 3表示分享获得积分,可根据实际情况调整
+        integralLogs.setBusinessId(String.valueOf(red.getRedId()));
+        integralLogs.setBusinessType(Math.toIntExact(conf.getRedId())); // 1表示直播红包
+        integralLogs.setStatus(0);
+        integralLogs.setCreateTime(new Date());
+        fsUserIntegralLogsMapper.insertFsUserIntegralLogs(integralLogs);
+
         // WebSocket 通知
         //String msg = String.format("用户 %d 抢到了红包 %d,获得 %d 芳华币", userId, redId, integral);
         //WebSocketServer.notifyUsers(msg);

+ 15 - 8
fs-service/src/main/java/com/fs/live/service/impl/LiveWatchUserServiceImpl.java

@@ -13,6 +13,7 @@ import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.course.domain.FsCourseLink;
 import com.fs.course.service.impl.FsUserCourseVideoServiceImpl;
+import com.fs.enums.ExceptionCodeEnum;
 import com.fs.his.domain.FsUser;
 import com.fs.his.mapper.FsUserMapper;
 import com.fs.his.service.IFsUserService;
@@ -669,10 +670,10 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
         FsUser fsUser = fsUserMapper.selectFsUserByUserId(param.getUserId());
         //用户不存在唤起重新授权
         if (fsUser == null) {
-            return R.error(401, "未授权");
+            return R.error(ExceptionCodeEnum.USER_NOT_FOUND.getCode(), ExceptionCodeEnum.USER_NOT_FOUND.getDescription());
         }
         if (fsUser.getStatus() == 0) {
-            return R.error("会员被停用,无权限,请联系客服!");
+            return R.error(ExceptionCodeEnum.MEMBER_DISABLED.getCode(), ExceptionCodeEnum.MEMBER_DISABLED.getDescription());
         }
         //未注册提示
         String noRegisterMsg = "由于您还未完成注册,请联系伴学助手完成注册即可观看!";
@@ -684,7 +685,7 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
         } else if (null != param.getQwExternalId()) {
             return handleLivePerson(param,fsUser, noMemberMsg, noRegisterMsg);
         } else {
-            return R.error("直播参数错误");
+            return R.error(ExceptionCodeEnum.LIVE_PARAM_ERROR.getCode(), ExceptionCodeEnum.LIVE_PARAM_ERROR.getDescription());
         }
 
     }
@@ -874,6 +875,12 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
     @Override
     @Async
     public void qwTagMarkByLiveWatchLog(Long liveId) {
+        //休眠2分钟 等待看课中断的所有看课记录状态被正确处理标记
+        try {
+            Thread.sleep(120000L);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
         log.info("处理直播间打标签: liveId={}", liveId);
         //查询直播间的标签配置
         List<LiveTagItemVO> liveTagConfig = liveTagConfigMapper.getLiveTagListByliveId(liveId);
@@ -1087,7 +1094,7 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
         try {
 
             LiveWatchUser liveWatchUser = baseMapper.selectByUniqueIndex(liveId, userId, liveFlag, replayFlag);
-            
+
             if (liveWatchUser != null) {
                 if (liveWatchUser.getOnlineSeconds() == null || duration > liveWatchUser.getOnlineSeconds()) {
                     liveWatchUser.setOnlineSeconds(duration);
@@ -1116,25 +1123,25 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
     public Long getTotalWatchDuration(Long liveId, Long userId) {
         try {
             long totalDuration = 0L;
-            
+
             // 1. 查询直播观看记录(liveFlag=1, replayFlag=0)
             LiveWatchUser liveRecord = baseMapper.selectByUniqueIndex(liveId, userId, 1, 0);
             if (liveRecord != null && liveRecord.getOnlineSeconds() != null) {
                 totalDuration += liveRecord.getOnlineSeconds();
             }
-            
+
             // 2. 查询回放观看记录(liveFlag=0, replayFlag=1)
             LiveWatchUser replayRecord = baseMapper.selectByUniqueIndex(liveId, userId, 0, 1);
             if (replayRecord != null && replayRecord.getOnlineSeconds() != null) {
                 totalDuration += replayRecord.getOnlineSeconds();
             }
-            
+
             log.debug("查询总观看时长: liveId={}, userId={}, liveDuration={}, replayDuration={}, total={}",
                     liveId, userId,
                     liveRecord != null ? liveRecord.getOnlineSeconds() : 0,
                     replayRecord != null ? replayRecord.getOnlineSeconds() : 0,
                     totalDuration);
-            
+
             return totalDuration;
         } catch (Exception e) {
             log.error("查询总观看时长失败: liveId={}, userId={}", liveId, userId, e);

+ 8 - 0
fs-service/src/main/java/com/fs/live/vo/LiveAfterSalesVo.java

@@ -140,6 +140,14 @@ public class LiveAfterSalesVo {
     @Excel(name = "下单时间",dateFormat = "yyyy-MM-dd HH:mm:ss")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date createTime;
+    /** 创建时间 */
+    @Excel(name = "下单开始时间",dateFormat = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTimeBegin;
+    /** 创建时间 */
+    @Excel(name = "下单结束时间",dateFormat = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTimeEnd;
 
 
 

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

@@ -87,8 +87,8 @@ tencent_cloud_config:
 cloud_host:
   company_name: 叮当国医
   projectCode: DDGY
-  spaceName:
-  volcengineUrl:
+  spaceName: ddgy-2114522511
+  volcengineUrl: https://ddgyvolcengine.ylrztop.com
 #看课授权时显示的头像
 headerImg:
   imgUrl: https://ddgy-1323137866.cos.ap-chongqing.myqcloud.com/fs/20251010/ddgy.jpg

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

@@ -106,8 +106,8 @@ tmp_secret_config:
 cloud_host:
   company_name: 福本源
   projectCode: FBY
-  spaceName:
-  volcengineUrl:
+  spaceName: fby-2114522511
+  volcengineUrl: https://fbyvolcengine.ylrztop.com
 headerImg:
   imgUrl: https://fbylive.obs.cn-southwest-2.myhuaweicloud.com/fs/20250730/1753840024082.png
 ipad:

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

@@ -83,8 +83,8 @@ tencent_cloud_config:
 cloud_host:
   company_name: 广州郑多燕
   projectCode: GZZDY
-  spaceName:
-  volcengineUrl:
+  spaceName: gzzdy-2114522511
+  volcengineUrl: https://gzzdyvolcengine.ylrztop.com
 #看课授权时显示的头像
 headerImg:
   imgUrl:

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

@@ -83,8 +83,8 @@ tencent_cloud_config:
 cloud_host:
   company_name: 鸿森堂
   projectCode: HST
-  spaceName:
-  volcengineUrl:
+  spaceName: hst-2114522
+  volcengineUrl: https://hstvolcengine.ylrztop.com
 #看课授权时显示的头像
 headerImg:
   imgUrl:

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

@@ -83,8 +83,8 @@ tencent_cloud_config:
 cloud_host:
   company_name: 宽益堂
   projectCode: KYT
-  spaceName:
-  volcengineUrl:
+  spaceName: kyt-2114522511
+  volcengineUrl: https://kytvolcengine.ylrztop.com
 #看课授权时显示的头像
 headerImg:
   imgUrl: https://kuanyitang-1317640934.cos.ap-shanghai.myqcloud.com/kuanyitang/20250813/6b3b62e01672407c98f0561b73e35f6a.jpg

+ 6 - 0
fs-service/src/main/resources/mapper/live/LiveAfterSalesMapper.xml

@@ -80,6 +80,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
         <where>
             <if test="hfOrderCode != null and hfOrderCode != ''"> and lop.pay_code = #{hfOrderCode}</if>
+            <if test="bankTransactionId != null and bankTransactionId != ''"> and lop.bank_transaction_id = #{bankTransactionId}</if>
             <if test="liveId != null and liveId != ''"> and las.live_id = #{liveId}</if>
             <if test="companyUserNickName != null and companyUserNickName != ''"> and cu.nick_name like concat(#{companyUserNickName},'%')</if>
             <if test="storeId != null and storeId != ''"> and las.store_id = #{storeId}</if>
@@ -109,6 +110,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="companyUserId != null "> and las.company_user_id = #{companyUserId}</if>
             <if test="deptId != null "> and cu.dept_id = #{deptId}</if>
             <if test="userPhone != null "> and lo.user_phone like concat(#{userPhone},'%')</if>
+            <if test="createTimeBegin != null and createTimeBegin != ''"> and date_format(las.create_time,'%y%m%d') &gt;= date_format(#{createTimeBegin},'%y%m%d')</if>
+            <if test="createTimeEnd != null and createTimeEnd != ''"> and date_format(las.create_time,'%y%m%d') &lt;= date_format(#{createTimeEnd},'%y%m%d')</if>
         </where>
         <if test="productName != null and productName != ''">
         group by las.id
@@ -133,6 +136,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
         where 1=1 and las.is_del = 0 and lo.status = -2 and lop.bank_transaction_id is not null
             <if test="hfOrderCode != null and hfOrderCode != ''"> and lop.pay_code = #{hfOrderCode}</if>
+            <if test="bankTransactionId != null and bankTransactionId != ''"> and lop.bank_transaction_id = #{bankTransactionId}</if>
             <if test="liveId != null and liveId != ''"> and las.live_id = #{liveId}</if>
             <if test="companyUserNickName != null and companyUserNickName != ''"> and cu.nick_name like concat(#{companyUserNickName},'%')</if>
             <if test="storeId != null and storeId != ''"> and las.store_id = #{storeId}</if>
@@ -162,6 +166,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="companyUserId != null "> and las.company_user_id = #{companyUserId}</if>
             <if test="deptId != null "> and cu.dept_id = #{deptId}</if>
             <if test="userPhone != null "> and lo.user_phone like concat(#{userPhone},'%')</if>
+            <if test="createTimeBegin != null and createTimeBegin != ''"> and date_format(las.create_time,'%y%m%d') &gt;= date_format(#{createTimeBegin},'%y%m%d')</if>
+            <if test="createTimeEnd != null and createTimeEnd != ''"> and date_format(las.create_time,'%y%m%d') &lt;= date_format(#{createTimeEnd},'%y%m%d')</if>
 
         <if test="productName != null and productName != ''">
         group by las.id

+ 7 - 1
fs-websocket/src/main/java/com/fs/websocket/FsWebSocketServiceApplication.java

@@ -4,13 +4,19 @@ import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
 import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.FilterType;
 
 /**
  * WebSocket服务启动程序
  *
  * @author fs
  */
-@SpringBootApplication(scanBasePackages = {"com.fs"}, exclude= {DataSourceAutoConfiguration.class})
+@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
+@ComponentScan(basePackages = {"com.fs"}, excludeFilters = {
+        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {com.fs.common.utils.RedisUtil.class,
+                com.fs.common.core.redis.RedisCache.class, com.fs.common.core.redis.RedisCacheT.class})
+        })
 public class FsWebSocketServiceApplication extends SpringBootServletInitializer {
 
     public static void main(String[] args) {

+ 4 - 4
fs-websocket/src/main/java/com/fs/websocket/config/WebSocketConfig.java

@@ -27,13 +27,13 @@ public class WebSocketConfig {
     public ServletServerContainerFactoryBean createWebSocketContainer() {
         ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
         // 设置文本消息缓冲区大小
-        container.setMaxTextMessageBufferSize(10240000);
+        container.setMaxTextMessageBufferSize(1048576);
         // 设置二进制消息缓冲区大小
-        container.setMaxBinaryMessageBufferSize(10240000);
+        container.setMaxBinaryMessageBufferSize(1048576);
         // 设置最大会话空闲超时时间(单位:毫秒)
-        container.setMaxSessionIdleTimeout(20 * 60000L); // 15分钟
+        container.setMaxSessionIdleTimeout(60000L); // 15分钟
         // 设置异步发送超时时间(单位:毫秒)
-        container.setAsyncSendTimeout(300 * 1000L);
+        container.setAsyncSendTimeout(30 * 1000L);
         return container;
     }
 

+ 30 - 15
fs-websocket/src/main/java/com/fs/websocket/service/WebSocketServer.java

@@ -6,15 +6,12 @@ import com.fs.common.utils.StringUtils;
 import com.fs.websocket.bean.SendMsgVO;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
-import org.springframework.util.CollectionUtils;
-
 import javax.websocket.*;
 import javax.websocket.server.PathParam;
 import javax.websocket.server.ServerEndpoint;
 import java.io.IOException;
-import java.util.Collection;
 import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.*;
 import java.util.stream.Collectors;
 
 @ServerEndpoint("/app/webSocket/{userId}")
@@ -24,25 +21,41 @@ public class WebSocketServer {
 
     //concurrent包的线程安全,用来存放每个客户端对应的WebSocketServer的会话对象
     private static final ConcurrentHashMap<Long, Session> sessionPools = new ConcurrentHashMap<>();
-//    private final RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
+
 
     //分发消息
     public void sendMessageToAll(String message) throws IOException {
-        Collection<Session> sessions = sessionPools.values();
-        if(!CollectionUtils.isEmpty(sessions)){
-            for (Session session : sessions) {
-                System.out.println("发送数据:" + message);
-                session.getBasicRemote().sendText(message);
-                log.info("分发消息结束,人数,{},消息内容,{}",  sessionPools.size(), message);
-            }
-        }
+//        Collection<Session> sessions = sessionPools.values();
+//        if(!CollectionUtils.isEmpty(sessions)){
+            sessionPools.forEach((userId, session) -> {
+                if (session.isOpen()) {
+                    try {
+                        // 异步发送,设置超时
+                        Future<Void> future = session.getAsyncRemote().sendText(message);
+                        System.out.println("分发消息,数据内容:" + message);
+                        try {
+                            future.get(10, TimeUnit.SECONDS);
+                        } catch (TimeoutException e) {
+                            // 超时关闭连接
+                            session.close();
+                            log.error("超时关闭连接,并移除用户:{}", userId, e);
+                            sessionPools.remove(userId);
+                        }
+                    } catch (Exception e) {
+                        log.error("分发消息失败,并移除用户: {}", userId, e);
+                        sessionPools.remove(userId);
+                    }
+                }
+            });
+        log.info("分发消息结束,人数,{}",  sessionPools.size());
+//        }
     }
 
     //指定用户发送消息
     public static void sendMessage(Session session, String message) throws IOException {
         if(session != null){
             synchronized (session) {
-                log.info("发送数据:{}", message);
+                log.info("发送心跳数据:{}", message);
                 session.getBasicRemote().sendText(message);
             }
         }
@@ -95,7 +108,9 @@ public class WebSocketServer {
     //错误时调用
     @OnError
     public void onError(Session session, Throwable throwable) {
-        log.error("webSocket连接错误,{}", throwable.getMessage());
+        Map<String, String> params = getParams(session);
+        long userId = Long.parseLong(params.get("userId"));
+        log.error("webSocket连接错误,{},移除用户,{}", throwable.getMessage(), userId);
         throwable.printStackTrace();
     }