Просмотр исходного кода

Merge remote-tracking branch 'origin/master'

yuhongqi 1 день назад
Родитель
Сommit
e63d221aa0
18 измененных файлов с 129 добавлено и 44 удалено
  1. 1 1
      fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java
  2. 6 5
      fs-company/src/main/java/com/fs/company/controller/live/LiveDataController.java
  3. 11 2
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  4. 4 2
      fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java
  5. 2 0
      fs-service/src/main/java/com/fs/live/service/ILiveDataService.java
  6. 30 0
      fs-service/src/main/java/com/fs/live/service/impl/LiveDataServiceImpl.java
  7. 19 0
      fs-service/src/main/java/com/fs/live/vo/LiveDataListVo.java
  8. 2 2
      fs-service/src/main/resources/application-config-druid-ddgy.yml
  9. 2 2
      fs-service/src/main/resources/application-config-druid-fby.yml
  10. 2 2
      fs-service/src/main/resources/application-config-druid-gzzdy.yml
  11. 2 2
      fs-service/src/main/resources/application-config-druid-hst.yml
  12. 2 1
      fs-service/src/main/resources/application-config-druid-jnmy.yml
  13. 2 2
      fs-service/src/main/resources/application-config-druid-kyt.yml
  14. 1 1
      fs-service/src/main/resources/application-druid-shdn.yml
  15. 2 2
      fs-user-app/src/main/resources/application.yml
  16. 7 1
      fs-websocket/src/main/java/com/fs/websocket/FsWebSocketServiceApplication.java
  17. 4 4
      fs-websocket/src/main/java/com/fs/websocket/config/WebSocketConfig.java
  18. 30 15
      fs-websocket/src/main/java/com/fs/websocket/service/WebSocketServer.java

+ 1 - 1
fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java

@@ -199,7 +199,7 @@ public class CompanyUserController extends BaseController {
                     }
                     //是否绑定
                     if(QwStatusEnum.BOUND.getCode() == companyUserQwListVO.getQwStatus()){
-                        if(!companyUserQwListVO.getQwUserId().isEmpty()){
+                        if(!StringUtil.strIsNullOrEmpty(companyUserQwListVO.getQwUserId())){
                             Long[] ids = Arrays.stream(companyUserQwListVO.getQwUserId().split(","))
                                     .map(Long::parseLong)
                                     .toArray(Long[]::new);

+ 6 - 5
fs-company/src/main/java/com/fs/company/controller/live/LiveDataController.java

@@ -15,6 +15,7 @@ import com.fs.live.domain.LiveData;
 import com.fs.live.param.LiveDataParam;
 import com.fs.live.service.ILiveDataService;
 import com.fs.live.vo.ColumnsConfigVo;
+import com.fs.live.vo.LiveDataListVo;
 import com.fs.live.vo.LiveUserDetailExportVO;
 import com.github.pagehelper.PageHelper;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -61,7 +62,7 @@ public class LiveDataController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('liveData:liveData:query')")
     @GetMapping("/getLiveUserDetailListBySql")
-    public R getLiveUserDetailListBySql(@RequestParam Long liveId, 
+    public R getLiveUserDetailListBySql(@RequestParam Long liveId,
                                         @RequestParam(defaultValue = "1") Integer pageNum,
                                         @RequestParam(defaultValue = "100") Integer pageSize,
                                         HttpServletRequest request) {
@@ -163,11 +164,11 @@ public class LiveDataController extends BaseController
     @PreAuthorize("@ss.hasPermi('liveData:liveData:export')")
     @Log(title = "直播数据", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
-    public AjaxResult export(LiveData liveData)
+    public AjaxResult export(LiveDataParam param)
     {
-        List<LiveData> list = liveDataService.selectLiveDataList(liveData);
-        ExcelUtil<LiveData> util = new ExcelUtil<LiveData>(LiveData.class);
-        return util.exportExcel(list, "直播数据数据");
+        List<LiveDataListVo> liveDataListVos = liveDataService.exportLiveData(param);
+        ExcelUtil<LiveDataListVo> util = new ExcelUtil<LiveDataListVo>(LiveDataListVo.class);
+        return util.exportExcel(liveDataListVos, "直播数据数据");
     }
 
     /**

+ 11 - 2
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -2205,7 +2205,7 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
                      return R.error("奖励发送失败,请联系客服");
                  }
              }catch (Exception e){
-                 return R.error("发放奖励失败,请联系客服");
+                 return R.error(e.getMessage());
              }
 
             }
@@ -2455,8 +2455,17 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
         FsUserCourseVideoDetailsVO fsUserCourseVideoDetailsVO = new FsUserCourseVideoDetailsVO();
         BeanUtils.copyProperties(fsUserCourseVideo, fsUserCourseVideoDetailsVO);
 
+        //从配置中读取默认线路
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        if (Integer.valueOf(1).equals(config.getDefaultLine())) {
+            fsUserCourseVideoDetailsVO.setVideoUrl(fsUserCourseVideo.getLineTwo());
+        } else {
+            fsUserCourseVideoDetailsVO.setVideoUrl(fsUserCourseVideo.getLineOne());
+        }
         //这里 改成取线路一值,返回给前端。VideoUrl 是原视频(用来算流量的),不要去改,lineOne是转码后的视频
-        fsUserCourseVideoDetailsVO.setVideoUrl(fsUserCourseVideo.getLineOne());
+//        fsUserCourseVideoDetailsVO.setVideoUrl(fsUserCourseVideo.getLineOne());
+
 
         // 获取课程相关的题库
         String questionBankId = fsUserCourseVideo.getQuestionBankId();

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

@@ -659,7 +659,8 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
             return result;
         }catch (Exception e){
             logger.error("领取红包失败原因:{}", ExceptionUtils.getMessage(e),e);
-            if (e instanceof WxPayException && "济南联志健康".equals(signProjectName)) {
+//            if (e instanceof WxPayException && "济南联志健康".equals(signProjectName)) {
+            if (e instanceof WxPayException) {
                 WxPayException wxPayException = (WxPayException) e;
                 String customErrorMsg = wxPayException.getCustomErrorMsg();
                 if (null != customErrorMsg && customErrorMsg.startsWith("商户运营账户资金不足")) {
@@ -923,7 +924,8 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
             return R.ok("发送红包成功").put("orderCode", transferBatchesResult.getOutBatchNo()).put("batchId", transferBatchesResult.getBatchId()).put("mchId", config.getMchId());
         } catch (Exception e) {
             logger.error("商家转账支付失败:参数: {} :原因: {}",JSON.toJSONString(param), e.getMessage(),e);
-            if (e instanceof WxPayException && "济南联志健康".equals(signProjectName)) {
+            if (e instanceof WxPayException) {
+//            if (e instanceof WxPayException && "济南联志健康".equals(signProjectName)) {
                 WxPayException wxPayException = (WxPayException) e;
                 String customErrorMsg = wxPayException.getCustomErrorMsg();
                 if (null != customErrorMsg && customErrorMsg.startsWith("商户运营账户资金不足")) {

+ 2 - 0
fs-service/src/main/java/com/fs/live/service/ILiveDataService.java

@@ -167,4 +167,6 @@ public interface ILiveDataService {
      * @return 导出VO列表
      */
     List<LiveUserDetailExportVO> exportLiveUserDetail(Long liveId, Long companyId, Long companyUserId);
+
+    List<LiveDataListVo> exportLiveData(LiveDataParam param);
 }

+ 30 - 0
fs-service/src/main/java/com/fs/live/service/impl/LiveDataServiceImpl.java

@@ -192,6 +192,36 @@ public class LiveDataServiceImpl implements ILiveDataService {
         return R.ok().put("list", liveDataList).put("data", statistics).put("total", total);
     }
 
+    @Override
+    public List<LiveDataListVo> exportLiveData(LiveDataParam param){
+        List<Live> lives = liveMapper.listLiveData(param);
+        int total = liveMapper.listLiveDataCount(param);
+
+        if (lives == null || lives.isEmpty()) {
+            LiveDataStatisticsVo statistics = new LiveDataStatisticsVo();
+            return Collections.emptyList();
+        }
+
+        // 获取直播间ID列表
+        List<Long> liveIds = lives.stream()
+                .map(Live::getLiveId)
+                .collect(Collectors.toList());
+
+        // 查询统计数据(根据live_watch_user表查询用户的在线时长,计算平均时长
+        // 根据live_video的文件时长,判断用户的完课情况
+        // 根据live_order查询直播间的销量额和订单数)
+        LiveDataStatisticsVo statistics = baseMapper.selectLiveDataStatistics(liveIds);
+        if (statistics == null) {
+            statistics = new LiveDataStatisticsVo();
+        }
+
+        // 查询列表数据(每个直播间的详细统计数据)
+        List<LiveDataListVo> liveDataList = baseMapper.selectLiveDataListByLiveIds(liveIds);
+        if (liveDataList == null) {
+            liveDataList = Collections.emptyList();
+        }
+        return liveDataList;
+    }
     /**
      * 查询直播数据
      *

+ 19 - 0
fs-service/src/main/java/com/fs/live/vo/LiveDataListVo.java

@@ -1,6 +1,7 @@
 package com.fs.live.vo;
 
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
 import lombok.Data;
 
 import java.math.BigDecimal;
@@ -15,59 +16,77 @@ import java.util.Date;
 @Data
 public class LiveDataListVo {
     /** 直播ID */
+    @Excel(name = "直播ID")
     private Long liveId;
 
     /** 直播名称 */
+    @Excel(name = "直播名称")
     private String liveName;
 
     /** 直播类型 1直播,2录播,3直播回放 */
+    @Excel(name = "直播类型 1直播,2录播,3直播回放")
     private Integer liveType;
 
     /** 直播状态 1未开播 2直播中 3已结束 4直播回放中 */
+    @Excel(name = "直播状态 1未开播 2直播中 3已结束 4直播回放中")
     private Integer status;
 
     /** 开始时间 */
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "开始时间", width = 30, dateFormat = "yyyy-MM-dd")
     private Date startTime;
 
     /** 结束时间 */
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "结束时间", width = 30, dateFormat = "yyyy-MM-dd")
     private Date finishTime;
 
     /** 累计观看人数 */
+    @Excel(name = "累计观看人数")
     private Long totalViewers = 0L;
 
     /** 直播观看人数 */
+    @Excel(name = "直播观看人数")
     private Long liveViewers = 0L;
 
     /** 回放观看人数 */
+    @Excel(name = "回放观看人数")
     private Long playbackViewers = 0L;
 
     /** 直播平均时长(秒) */
+    @Excel(name = "直播平均时长")
     private Long liveAvgDuration = 0L;
 
     /** 回放平均时长(秒) */
+    @Excel(name = "回放平均时长")
     private Long playbackAvgDuration = 0L;
 
     /** 累计完课人数 */
+    @Excel(name = "累计完课人数")
     private Long totalCompletedCourses = 0L;
 
     /** 直播完课人数 */
+    @Excel(name = "直播完课人数")
     private Long liveCompletedCourses = 0L;
 
     /** 回放完课人数 */
+    @Excel(name = "回放完课人数")
     private Long playbackCompletedCourses = 0L;
 
     /** GMV(总销售额) */
+    @Excel(name = "总销售额")
     private BigDecimal gmv = BigDecimal.ZERO;
 
     /** 付费人数 */
+    @Excel(name = "付费人数")
     private Long paidUsers = 0L;
 
     /** 付费单数 */
+    @Excel(name = "付费单数")
     private Long paidOrders = 0L;
 
     /** 销量统计 */
+    @Excel(name = "销量统计")
     private Long salesCount = 0L;
 }
 

+ 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 - 1
fs-service/src/main/resources/application-config-druid-jnmy.yml

@@ -88,7 +88,8 @@ tmp_secret_config:
 cloud_host:
   company_name: 金牛明医
   projectCode: JNMY
-  spaceName:
+  spaceName: cdjnmy-2114522511
+  volcengineUrl: https://cdjnmyvolcengine.ylrztop.com
 headerImg:
   imgUrl: https
 ipad:

+ 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

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

@@ -9,7 +9,7 @@ spring:
         # 数据库索引
         database: 0
         # 密码
-        password: !@#123QWe
+        password: QWE123qwe
         # 连接超时时间
         timeout: 30s
         lettuce:

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

@@ -7,8 +7,8 @@ server:
 # Spring配置
 spring:
   profiles:
-    active: druid-myhk-test
-#    active: dev
+#    active: druid-myhk-test
+    active: dev
 #    active: druid-jzzx
 #    active: druid-yzt
 #    active: druid-hdt

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