소스 검색

Merge remote-tracking branch 'origin/master'

jzp 1 일 전
부모
커밋
3b32bbb74c
100개의 변경된 파일3501개의 추가작업 그리고 281개의 파일을 삭제
  1. 42 3
      fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java
  2. 1 1
      fs-admin/src/main/java/com/fs/his/controller/FsUserController.java
  3. 65 13
      fs-admin/src/main/java/com/fs/his/task/Task.java
  4. 57 0
      fs-admin/src/main/java/com/fs/qw/qwTask/qwTask.java
  5. 199 0
      fs-admin/src/main/java/com/fs/stats/SalesWatchStatisController.java
  6. 11 0
      fs-company-app/src/main/java/com/fs/app/controller/CommonController.java
  7. 11 5
      fs-company-app/src/main/java/com/fs/app/controller/FsUserController.java
  8. 25 18
      fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  9. 3 1
      fs-company/src/main/java/com/fs/company/controller/company/CompanyMenuController.java
  10. 1 1
      fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsController.java
  11. 207 0
      fs-company/src/main/java/com/fs/company/controller/stats/SalesWatchStatisController.java
  12. 40 1
      fs-company/src/main/java/com/fs/company/controller/store/FsStoreOrderController.java
  13. 1 1
      fs-company/src/main/java/com/fs/company/controller/store/FsUserController.java
  14. 1 0
      fs-company/src/main/java/com/fs/framework/config/DataSourceConfig.java
  15. 4 4
      fs-company/src/main/java/com/fs/user/FsUserAdminController.java
  16. 1 0
      fs-framework/src/main/java/com/fs/framework/config/DataSourceConfig.java
  17. 1 0
      fs-qw-api/src/main/java/com/fs/framework/config/DataSourceConfig.java
  18. 39 0
      fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java
  19. 1 1
      fs-qw-task/src/main/java/com/fs/app/task/CourseWatchLogScheduler.java
  20. 1 1
      fs-qw-task/src/main/java/com/fs/app/task/UserCourseWatchCountTask.java
  21. 21 9
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  22. 6 23
      fs-qwhook-sop/src/main/java/com/fs/app/controller/ApisFsUserCourseVideoController.java
  23. 6 23
      fs-qwhook-sop/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  24. 1 0
      fs-qwhook-sop/src/main/java/com/fs/framework/config/DataSourceConfig.java
  25. 6 23
      fs-qwhook/src/main/java/com/fs/app/controller/ApisFsUserCourseVideoController.java
  26. 6 23
      fs-qwhook/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  27. 1 0
      fs-qwhook/src/main/java/com/fs/framework/config/DataSourceConfig.java
  28. 5 0
      fs-service/src/main/java/com/fs/company/cache/ICompanyDeptCacheService.java
  29. 5 0
      fs-service/src/main/java/com/fs/company/cache/ICompanyUserCacheService.java
  30. 27 0
      fs-service/src/main/java/com/fs/company/cache/impl/CompanyDeptCacheServiceImpl.java
  31. 31 0
      fs-service/src/main/java/com/fs/company/cache/impl/CompanyUserCacheServiceImpl.java
  32. 27 6
      fs-service/src/main/java/com/fs/company/mapper/CompanyDeptMapper.java
  33. 10 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyMapper.java
  34. 2 2
      fs-service/src/main/java/com/fs/company/mapper/CompanyRoleMapper.java
  35. 21 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyUserMapper.java
  36. 5 0
      fs-service/src/main/java/com/fs/company/service/ICompanyDeptService.java
  37. 13 0
      fs-service/src/main/java/com/fs/company/service/ICompanyService.java
  38. 16 6
      fs-service/src/main/java/com/fs/company/service/impl/CompanyDeptServiceImpl.java
  39. 2 2
      fs-service/src/main/java/com/fs/company/service/impl/CompanyRoleServiceImpl.java
  40. 454 9
      fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java
  41. 7 1
      fs-service/src/main/java/com/fs/company/service/impl/CompanyTagUserServiceImpl.java
  42. 22 0
      fs-service/src/main/java/com/fs/company/vo/DeptDataVO.java
  43. 3 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseAnswerLogs.java
  44. 1 1
      fs-service/src/main/java/com/fs/course/domain/FsCourseRealLink.java
  45. 2 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseRedPacketLog.java
  46. 1 1
      fs-service/src/main/java/com/fs/course/mapper/FsCourseLinkMapper.java
  47. 13 1
      fs-service/src/main/java/com/fs/course/mapper/FsCourseRedPacketLogMapper.java
  48. 7 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  49. 1 0
      fs-service/src/main/java/com/fs/course/param/FsCourseLinkRoomParam.java
  50. 1 0
      fs-service/src/main/java/com/fs/course/param/FsCourseQuestionAnswerUParam.java
  51. 2 0
      fs-service/src/main/java/com/fs/course/param/FsUserCourseVideoAddKfUParam.java
  52. 4 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseLinkService.java
  53. 116 14
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseLinkServiceImpl.java
  54. 1 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseQuestionBankServiceImpl.java
  55. 6 1
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseRedPacketLogServiceImpl.java
  56. 1 1
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseWatchLogServiceImpl.java
  57. 2 1
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java
  58. 165 50
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  59. 4 0
      fs-service/src/main/java/com/fs/his/mapper/FsStoreOrderMapper.java
  60. 9 9
      fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java
  61. 2 2
      fs-service/src/main/java/com/fs/his/service/impl/FsInquiryOrderServiceImpl.java
  62. 5 0
      fs-service/src/main/java/com/fs/his/service/impl/FsPackageServiceImpl.java
  63. 1 1
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
  64. 57 9
      fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java
  65. 60 0
      fs-service/src/main/java/com/fs/qw/cache/QwSopCacheService.java
  66. 61 0
      fs-service/src/main/java/com/fs/qw/cache/QwUserCacheService.java
  67. 12 0
      fs-service/src/main/java/com/fs/qw/dto/QwUserDTO.java
  68. 14 0
      fs-service/src/main/java/com/fs/qw/mapper/QwUserMapper.java
  69. 4 0
      fs-service/src/main/java/com/fs/sop/domain/QwSop.java
  70. 2 0
      fs-service/src/main/java/com/fs/sop/domain/QwSopLogs.java
  71. 14 0
      fs-service/src/main/java/com/fs/sop/mapper/QwSopLogsMapper.java
  72. 57 0
      fs-service/src/main/java/com/fs/sop/mapper/QwSopMapper.java
  73. 24 0
      fs-service/src/main/java/com/fs/sop/mapper/SopUserLogsMapper.java
  74. 12 0
      fs-service/src/main/java/com/fs/sop/params/GetSOPTaskDataParam.java
  75. 6 0
      fs-service/src/main/java/com/fs/sop/service/IQwSopService.java
  76. 37 4
      fs-service/src/main/java/com/fs/sop/service/impl/QwSopLogsServiceImpl.java
  77. 58 4
      fs-service/src/main/java/com/fs/sop/service/impl/QwSopServiceImpl.java
  78. 28 0
      fs-service/src/main/java/com/fs/sop/vo/QwSopTask.java
  79. 5 0
      fs-service/src/main/java/com/fs/sop/vo/SopUserLogsVo.java
  80. 14 0
      fs-service/src/main/java/com/fs/statis/IFsStatisQwWatchService.java
  81. 6 3
      fs-service/src/main/java/com/fs/statis/domain/FsStatisPeriodWatch.java
  82. 47 0
      fs-service/src/main/java/com/fs/statis/domain/FsStatisQwTempParam.java
  83. 190 0
      fs-service/src/main/java/com/fs/statis/domain/FsStatisQwWatch.java
  84. 52 2
      fs-service/src/main/java/com/fs/statis/domain/FsStatisSalerWatch.java
  85. 157 0
      fs-service/src/main/java/com/fs/statis/domain/FsStatisSopWatch.java
  86. 41 0
      fs-service/src/main/java/com/fs/statis/domain/FsStatisTempFsuser.java
  87. 59 0
      fs-service/src/main/java/com/fs/statis/domain/FsStatisTempParam.java
  88. 24 0
      fs-service/src/main/java/com/fs/statis/domain/FsTempPeriodQuery.java
  89. 23 0
      fs-service/src/main/java/com/fs/statis/dto/FsStatisQwWatchWriteDataDTO.java
  90. 13 0
      fs-service/src/main/java/com/fs/statis/dto/StatsWatchLogPageListDTO.java
  91. 15 0
      fs-service/src/main/java/com/fs/statis/dto/WatchCourseStatisticsDTO.java
  92. 172 0
      fs-service/src/main/java/com/fs/statis/impl/FsStatisQwWatchServiceImpl.java
  93. 8 0
      fs-service/src/main/java/com/fs/statis/mapper/FsStatisPeriodWatchMapper.java
  94. 116 0
      fs-service/src/main/java/com/fs/statis/mapper/FsStatisQwTempParamMapper.java
  95. 97 0
      fs-service/src/main/java/com/fs/statis/mapper/FsStatisQwWatchMapper.java
  96. 31 0
      fs-service/src/main/java/com/fs/statis/mapper/FsStatisSalerWatchMapper.java
  97. 68 0
      fs-service/src/main/java/com/fs/statis/mapper/FsStatisTempFsuserMapper.java
  98. 85 0
      fs-service/src/main/java/com/fs/statis/mapper/FsStatisTempParamMapper.java
  99. 58 0
      fs-service/src/main/java/com/fs/statis/mapper/FsTempPeriodQueryMapper.java
  100. 22 0
      fs-service/src/main/java/com/fs/statis/param/WatchCourseStatisticsParam.java

+ 42 - 3
fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java

@@ -21,6 +21,7 @@ import com.fs.erp.dto.ErpOrderQueryRequert;
 import com.fs.erp.dto.ErpOrderQueryResponse;
 import com.fs.erp.service.IErpOrderService;
 import com.fs.framework.web.service.TokenService;
+import com.fs.his.config.FsSysConfig;
 import com.fs.his.domain.*;
 import com.fs.his.dto.ExpressInfoDTO;
 import com.fs.his.dto.StoreOrderExpressExportDTO;
@@ -31,8 +32,10 @@ import com.fs.his.param.FsStoreOrderSalesParam;
 import com.fs.his.service.IFsExportTaskService;
 import com.fs.his.service.IFsExpressService;
 import com.fs.his.service.IFsStoreService;
+import com.fs.his.utils.ConfigUtil;
 import com.fs.his.vo.*;
 import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
@@ -72,6 +75,15 @@ public class FsStoreOrderController extends BaseController
     private IFsStoreService fsStoreService;
     @Autowired
     private IFsExportTaskService exportTaskService;
+    @Autowired
+    private ConfigUtil configUtil;
+    @Autowired
+    @Qualifier("erpOrderServiceImpl")
+    private IErpOrderService gyOrderService;
+
+    @Autowired
+    @Qualifier("wdtErpOrderServiceImpl")
+    private IErpOrderService wdtOrderService;
     /**
      * 查询订单列表
      */
@@ -194,8 +206,6 @@ public class FsStoreOrderController extends BaseController
     /**
      * 获取订单详细信息
      */
-    @Autowired
-    IErpOrderService erpOrderService;
     @GetMapping(value = "/{orderId}")
     public R getInfo(@PathVariable("orderId") Long orderId) throws ParseException {
         FsStoreOrderVO order = fsStoreOrderService.selectFsStoreOrderByOrderIdVO(orderId);
@@ -317,6 +327,7 @@ public class FsStoreOrderController extends BaseController
     public R updateErpOrder( @RequestBody FsStoreOrder param) {
         FsStoreOrder order = fsStoreOrderService.selectFsStoreOrderByOrderId(param.getOrderId());
         ErpOrderQueryRequert request = new ErpOrderQueryRequert();
+        IErpOrderService erpOrderService = getErpService();
         request.setCode(order.getExtendOrderId());
         ErpOrderQueryResponse response = erpOrderService.getOrder(request);
         if(response.getOrders()!=null&&response.getOrders().size()>0){
@@ -336,6 +347,29 @@ public class FsStoreOrderController extends BaseController
         return R.error("未查询到快递信息");
     }
 
+    private IErpOrderService getErpService() {
+        FsSysConfig sysConfig = configUtil.getSysConfig();
+        Integer erpOpen = sysConfig.getErpOpen();
+        if (erpOpen != null && erpOpen == 1){
+            //判断erp类型
+            Integer erpType = sysConfig.getErpType();
+            if (erpType != null){
+                IErpOrderService erpOrderService = null;
+                if (erpType == 1){
+                    //管易
+                    erpOrderService =  gyOrderService;
+                } else if (erpType == 2){
+                    //旺店通
+                    erpOrderService =  wdtOrderService;
+                }
+                return erpOrderService;
+
+
+            }
+        }
+        return null;
+    }
+
     /**
      * 删除订单
      */
@@ -459,7 +493,12 @@ public class FsStoreOrderController extends BaseController
     public R getEroOrder(@PathVariable("extendOrderId") String extendOrderId) {
         ErpOrderQueryRequert request = new ErpOrderQueryRequert();
         request.setCode(extendOrderId);
-        ErpOrderQueryResponse response = erpOrderService.getOrder(request);
+        IErpOrderService erpOrderService = getErpService();
+        ErpOrderQueryResponse response = new ErpOrderQueryResponse();
+        if (erpOrderService!=null){
+            response = erpOrderService.getOrder(request);
+        }
+
         return R.ok().put("data",response);
     }
 

+ 1 - 1
fs-admin/src/main/java/com/fs/his/controller/FsUserController.java

@@ -197,7 +197,7 @@ public class FsUserController extends BaseController
     @ApiOperation("小黑屋")
     public R darkRoomList(FsUserPageListParam param) {
 //        startPage();
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+//        PageHelper.startPage(param.getPageNum(), param.getPageSize());
         PageInfo<FsUserPageListVO> fsUserPageListVOPageInfo = fsUserService.selectFsUserPageList(param);
         if(ObjectUtils.isNotNull(fsUserPageListVOPageInfo)){
             for (FsUserPageListVO fsUserPageListVO : fsUserPageListVOPageInfo.getList()) {

+ 65 - 13
fs-admin/src/main/java/com/fs/his/task/Task.java

@@ -21,6 +21,7 @@ import com.fs.erp.dto.ErpOrderQueryRequert;
 import com.fs.erp.dto.ErpOrderQueryResponse;
 import com.fs.erp.service.IErpOrderService;
 import com.fs.fastGpt.mapper.FastGptChatSessionMapper;
+import com.fs.his.config.FsSysConfig;
 import com.fs.his.config.StoreConfig;
 import com.fs.his.domain.FsInquiryOrder;
 import com.fs.his.domain.FsStoreAfterSales;
@@ -33,6 +34,7 @@ import com.fs.his.mapper.*;
 import com.fs.his.param.FsInquiryOrderFinishParam;
 import com.fs.his.service.*;
 import com.fs.his.service.impl.FsPackageOrderServiceImpl;
+import com.fs.his.utils.ConfigUtil;
 import com.fs.his.vo.FsSubOrderResultVO;
 import com.fs.im.dto.*;
 import com.fs.im.service.IImService;
@@ -45,6 +47,7 @@ import com.google.gson.Gson;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Component;
 
 import java.util.ArrayList;
@@ -72,8 +75,8 @@ public class Task {
     private IFsFollowService fsFollowService;
     @Autowired
     private IFsStoreAfterSalesService fsStoreAfterSalesService;
-    @Autowired
-    IErpOrderService erpOrderService;
+//    @Autowired
+//    IErpOrderService erpOrderService;
     @Autowired
     FsIntegralOrderMapper integralOrderMapper;
     @Autowired
@@ -139,6 +142,8 @@ public class Task {
 
     @Autowired
     ITencentCloudCosService tencentCloudCosService;
+    @Autowired
+    private ConfigUtil configUtil;
     public void videoTranscode() throws Exception
     {
 
@@ -199,6 +204,14 @@ public class Task {
     }
 
 
+    public void redPacketAddMoney() throws Exception
+    {
+        List<RedPacketMoneyVO> redPacketMoneyVOS = fsCourseRedPacketLogMapper.selectFsCourseAddRedPacketLogByCompany();
+        for (RedPacketMoneyVO redPacketMoneyVO : redPacketMoneyVOS) {
+            companyService.addRedPacketCompanyMoney(redPacketMoneyVO.getMoney(),redPacketMoneyVO.getCompanyId());
+        }
+    }
+
     public void updateCompanyUserStatus()
     {
         CompanyUser user = new CompanyUser();
@@ -232,27 +245,37 @@ public class Task {
 
     public void deliveryOp()
     {
-        List<FsStoreOrder> orders = fsStoreOrderMapper.selectOmsOrderdeliveryOp();
+        IErpOrderService erpOrderService = getErpService();
+        List<FsStoreOrder> orders = null;
+        if (erpOrderService == gyOrderService){
+            orders = fsStoreOrderMapper.selectOmsOrderdeliveryOp();
+        } else if (erpOrderService == wdtOrderService){
+            orders = fsStoreOrderMapper.selectWdtOmsOrderdeliveryOp();
+        }
+
         for(FsStoreOrder order:orders){
 
             ErpOrderQueryRequert request=new ErpOrderQueryRequert();
 
             request.setCode(order.getExtendOrderId());
-            ErpOrderQueryResponse response=erpOrderService.getOrder(request);
-            if(response.getOrders()!=null&&response.getOrders().size()>0){
-                for(ErpOrderQuery orderQuery : response.getOrders()){
-                    if(orderQuery.getDeliverys()!=null&&orderQuery.getDeliverys().size()>0){
-                        for(ErpDeliverys delivery:orderQuery.getDeliverys()){
-                            if(delivery.getDelivery()&& StringUtils.isNotEmpty(delivery.getMail_no())){
-                                //更新商订单状态 删除REDIS
-                                fsStoreOrderService.deliveryOrder(order.getOrderCode(),delivery.getMail_no(),delivery.getExpress_code(),delivery.getExpress_name());
-                                redisCache.deleteObject("delivery"+":"+order.getExtendOrderId());
+            if (erpOrderService != null){
+                ErpOrderQueryResponse response=erpOrderService.getOrder(request);
+                if(response.getOrders()!=null&&response.getOrders().size()>0){
+                    for(ErpOrderQuery orderQuery : response.getOrders()){
+                        if(orderQuery.getDeliverys()!=null&&orderQuery.getDeliverys().size()>0){
+                            for(ErpDeliverys delivery:orderQuery.getDeliverys()){
+                                if(delivery.getDelivery()&& StringUtils.isNotEmpty(delivery.getMail_no())){
+                                    //更新商订单状态 删除REDIS
+                                    fsStoreOrderService.deliveryOrder(order.getOrderCode(),delivery.getMail_no(),delivery.getExpress_code(),delivery.getExpress_name());
+                                    redisCache.deleteObject("delivery"+":"+order.getExtendOrderId());
+                                }
                             }
-                        }
 
+                        }
                     }
                 }
             }
+
         }
 
 
@@ -958,4 +981,33 @@ public class Task {
 //    }
 //
 //}
+    @Autowired
+    @Qualifier("erpOrderServiceImpl")
+    private IErpOrderService gyOrderService;
+
+    @Autowired
+    @Qualifier("wdtErpOrderServiceImpl")
+    private IErpOrderService wdtOrderService;
+    private IErpOrderService getErpService() {
+        FsSysConfig sysConfig = configUtil.getSysConfig();
+        Integer erpOpen = sysConfig.getErpOpen();
+        if (erpOpen != null && erpOpen == 1){
+            //判断erp类型
+            Integer erpType = sysConfig.getErpType();
+            if (erpType != null){
+                IErpOrderService erpOrderService = null;
+                if (erpType == 1){
+                    //管易
+                    erpOrderService =  gyOrderService;
+                } else if (erpType == 2){
+                    //旺店通
+                    erpOrderService =  wdtOrderService;
+                }
+                return erpOrderService;
+
+
+            }
+        }
+        return null;
+    }
 }

+ 57 - 0
fs-admin/src/main/java/com/fs/qw/qwTask/qwTask.java

@@ -7,11 +7,15 @@ import com.fs.qw.service.IQwUserService;
 import com.fs.sop.service.impl.QwSopLogsServiceImpl;
 import com.fs.sop.service.impl.QwSopServiceImpl;
 import com.fs.sop.service.ISopUserLogsService;
+import com.fs.statis.IFsStatisQwWatchService;
+import com.fs.statis.service.FsStatisSalerWatchService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
+import java.time.LocalDate;
+
 @Component("qwTask")
 public class qwTask {
 
@@ -35,6 +39,13 @@ public class qwTask {
     @Autowired
     private IQwUserService qwUserService;
 
+
+    @Autowired
+    private FsStatisSalerWatchService fsStatisSalerWatchService;
+
+    @Autowired
+    private IFsStatisQwWatchService fsStatisQwWatchService;
+
     //正在使用
     public void qwExternalContact()
     {
@@ -131,4 +142,50 @@ public class qwTask {
     public void unlockQwUserLoginCodeUrlTask(){
         qwUserService.unlockQwUserLoginCodeUrlTask();
     }
+
+
+    /**
+     * 看课统计
+     */
+    public void watchCourseStatis(String date){
+        if("1".equals(date)){
+            fsStatisSalerWatchService.writeData(null);
+        } else {
+            fsStatisSalerWatchService.writeData(date);
+        }
+    }
+
+    /**
+     * 看课统计昨天
+     */
+    public void watchCourseStatisPrevious(){
+        LocalDate localDate = LocalDate.now().minusDays(1);
+        fsStatisSalerWatchService.writeData(localDate.toString());
+    }
+    /**
+     * 看课统计-统计当天的-每15分钟统计一次
+     */
+    public void watchCourseStatisToday(){
+        fsStatisSalerWatchService.writeDataToday();
+    }
+
+    /**
+     * 进线转化统计
+     */
+    public void qwWatchCourseStatis(String date){
+        if("1".equals(date)){
+            fsStatisQwWatchService.writeData(null);
+        } else {
+            fsStatisQwWatchService.writeData(date);
+        }
+    }
+
+    /**
+     * 进线转化统计
+     */
+    public void qwWatchCourseStatisToday(){
+        LocalDate today = LocalDate.now();
+        fsStatisQwWatchService.writeData(today.toString());
+    }
+
 }

+ 199 - 0
fs-admin/src/main/java/com/fs/stats/SalesWatchStatisController.java

@@ -0,0 +1,199 @@
+package com.fs.stats;
+
+import com.fs.common.annotation.RateLimiter;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.cache.ICompanyUserCacheService;
+import com.fs.company.service.ICompanyService;
+import com.fs.company.vo.DeptDataVO;
+import com.fs.sop.params.GetSOPTaskDataParam;
+import com.fs.sop.service.IQwSopLogsService;
+import com.fs.sop.service.IQwSopService;
+import com.fs.sop.vo.QwSopTask;
+import com.fs.statis.IFsStatisQwWatchService;
+import com.fs.statis.domain.FsStatisEveryDayWatch;
+import com.fs.statis.domain.FsStatisQwWatch;
+import com.fs.statis.domain.FsStatisSalerWatch;
+import com.fs.statis.domain.FsStatisSopWatch;
+import com.fs.statis.dto.StatsWatchLogPageListDTO;
+import com.fs.statis.service.FsStatisSalerWatchService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.LocalDate;
+import java.util.List;
+
+/**
+ * 看课统计接口
+ */
+@RestController
+@RequestMapping("/stats")
+@AllArgsConstructor
+public class SalesWatchStatisController {
+
+    @Autowired
+    private FsStatisSalerWatchService fsStatisSalerWatchService;
+
+    @Autowired
+    private IQwSopService qwSopService;
+
+    @Autowired
+    private ICompanyService companyService;
+
+    @Autowired
+    private ICompanyUserCacheService companyUserCacheService;
+
+    @Autowired
+    private IFsStatisQwWatchService fsStatisQwWatchService;
+
+    @Autowired
+    private IQwSopLogsService qwSopLogsService;
+
+    @GetMapping("/computedData")
+    public R computedData(@RequestParam("date") String date){
+        fsStatisSalerWatchService.writeData(date);
+        return R.ok();
+    }
+    /**
+     * 销售完播统计查询
+     * @param param param
+     * @return R
+     */
+    @PostMapping("/seller/pageList")
+    public R sellerQueryList(@RequestBody StatsWatchLogPageListDTO param){
+        if(param.getPageNum() == null) {
+            param.setPageNum(1);
+        }
+        if(param.getPageSize() == null) {
+            param.setPageSize(10);
+        }
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+
+        List<FsStatisSalerWatch> list = fsStatisSalerWatchService.queryList(param);
+        return R.ok().put("data",new PageInfo<>(list));
+    }
+
+    /**
+     * 进线转化统计
+     * @param param 参数
+     * @return R
+     */
+    @PostMapping("/inline/pageList")
+    public R inlineTransferStats(@RequestBody StatsWatchLogPageListDTO param){
+        if(param.getPageNum() == null) {
+            param.setPageNum(1);
+        }
+        if(param.getPageSize() == null) {
+            param.setPageSize(10);
+        }
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+
+        List<FsStatisQwWatch> list = fsStatisQwWatchService.queryList(param);
+        return R.ok().put("data",new PageInfo<>(list));
+    }
+    @PostMapping("/inline/export")
+    @RateLimiter(time=5,count = 1)
+    public AjaxResult exportInlineQueryList(@RequestBody StatsWatchLogPageListDTO param){
+        param.setPageNum(null);
+        param.setPageSize(null);
+        List<FsStatisQwWatch> list = fsStatisQwWatchService.exportQueryList(param);
+        ExcelUtil<FsStatisQwWatch> util = new ExcelUtil<>(FsStatisQwWatch.class);
+        return util.exportExcel(list, "销售完播统计");
+    }
+
+
+    @PostMapping("/seller/export")
+    @RateLimiter(time=5,count = 1)
+    public AjaxResult exportSellerQueryList(@RequestBody StatsWatchLogPageListDTO param){
+        param.setPageNum(null);
+        param.setPageSize(null);
+        List<FsStatisSalerWatch> list = fsStatisSalerWatchService.export(param);
+        ExcelUtil<FsStatisSalerWatch> util = new ExcelUtil<>(FsStatisSalerWatch.class);
+        return util.exportExcel(list, "销售完播统计");
+    }
+
+    /**
+     * 训练营完播统计查询
+     * @param param param
+     * @return R
+     */
+    @PostMapping("/period/pageList")
+    public R periodQueryList(@RequestBody StatsWatchLogPageListDTO param){
+        if(param.getPageNum() == null) {
+            param.setPageNum(1);
+        }
+        if(param.getPageSize() == null) {
+            param.setPageSize(10);
+        }
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+
+        List<FsStatisSalerWatch> list = fsStatisSalerWatchService.queryPeriodList(param);
+        return R.ok().put("data", new PageInfo<>(list));
+    }
+
+    @PostMapping("/period/export")
+    @RateLimiter(time=5,count = 1)
+    public AjaxResult exportPeriodQueryList(@RequestBody StatsWatchLogPageListDTO param){
+        param.setPageNum(null);
+        param.setPageSize(null);
+        List<FsStatisSopWatch> list = fsStatisSalerWatchService.exportQueryPeriodList(param);
+        ExcelUtil<FsStatisSopWatch> util = new ExcelUtil<>(FsStatisSopWatch.class);
+        return util.exportExcel(list, "SOP任务完播统计");
+    }
+
+    /**
+     * 每日完播统计查询
+     * @param param param
+     * @return R
+     */
+    @PostMapping("/everyDay/pageList")
+    public R everyDayQueryList(@RequestBody StatsWatchLogPageListDTO param){
+        if(param.getPageNum() == null) {
+            param.setPageNum(1);
+        }
+        if(param.getPageSize() == null) {
+            param.setPageSize(10);
+        }
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<FsStatisSalerWatch> list = fsStatisSalerWatchService.queryTodayList(param);
+        return R.ok().put("data", new PageInfo<>(list));
+    }
+    @PostMapping("/everyDay/export")
+    @RateLimiter(time=5,count = 1)
+    public AjaxResult exportEveryDayQueryList(@RequestBody StatsWatchLogPageListDTO param){
+        param.setPageNum(null);
+        param.setPageSize(null);
+        List<FsStatisEveryDayWatch> list = fsStatisSalerWatchService.exportQueryEveryDayList(param);
+        ExcelUtil<FsStatisEveryDayWatch> util = new ExcelUtil<>(FsStatisEveryDayWatch.class);
+        return util.exportExcel(list, "每日完播统计");
+    }
+    /**
+     * 获取SOP任务数据
+     * @return
+     */
+    @PostMapping("/sopTaskData")
+    public R getSOPTaskData(@RequestBody GetSOPTaskDataParam param){
+        if(StringUtils.isBlank(param.getStartDate()) && StringUtils.isBlank(param.getEndDate())) {
+            param.setStartDate(LocalDate.now().minusDays(7).toString());
+            param.setEndDate(LocalDate.now().toString());
+        }
+        List<QwSopTask> qwSopTaskList = qwSopService.getQwSopTaskList(param);
+        return R.ok().put("data",qwSopTaskList);
+    }
+
+    /**
+     * 获取部门数据
+     * @return
+     */
+    @GetMapping("/getDeptData")
+    public R getDeptData(Long companyId){
+        List<DeptDataVO> data = companyUserCacheService.getDeptData(companyId);
+        return R.ok().put("data",data);
+    }
+
+}

+ 11 - 0
fs-company-app/src/main/java/com/fs/app/controller/CommonController.java

@@ -25,6 +25,7 @@ import com.fs.his.service.IFsAppVersionService;
 import com.fs.his.service.IFsCityService;
 import com.fs.jpush.service.JpushService;
 
+import com.fs.store.service.IFsUserCourseCountService;
 import com.fs.system.oss.CloudStorageService;
 import com.fs.system.oss.OSSFactory;
 import com.fs.system.service.ISysConfigService;
@@ -228,5 +229,15 @@ public class CommonController extends AppBaseController {
 	}
 
 
+	@Autowired
+	private IFsUserCourseCountService userCourseCountService;
+
+	@PostMapping("test")
+	public R test() throws Exception
+	{
+		userCourseCountService.insertFsUserCourseCountTask();
+		return R.ok();
+	}
+
 
 }

+ 11 - 5
fs-company-app/src/main/java/com/fs/app/controller/FsUserController.java

@@ -39,8 +39,9 @@ import org.springframework.web.bind.annotation.*;
 
 import javax.validation.Valid;
 import java.io.InputStream;
-import java.text.SimpleDateFormat;
 import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.*;
 
 @Slf4j
@@ -75,7 +76,7 @@ public class FsUserController extends AppBaseController {
     @ApiOperation("用户会员分页列表")
     public ResponseResult<PageInfo<FsUserPageListVO>> pageList(@RequestBody FsUserPageListParam param) {
         param.setUserId(Long.parseLong(getUserId()));
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+//        PageHelper.startPage(param.getPageNum(), param.getPageSize());
         PageInfo<FsUserPageListVO> fsUserPageListVOPageInfo = fsUserService.selectFsUserPageList(param);
         return ResponseResult.ok(fsUserPageListVOPageInfo);
     }
@@ -152,18 +153,23 @@ public class FsUserController extends AppBaseController {
     public ResponseResult<FsUserStatisticsVO> userStatistics(@ApiParam(value = "开始时间", required = true) @RequestParam String startTime,
                                                              @ApiParam(value = "结束时间", required = true) @RequestParam String endTime) {
         long userId = Long.parseLong(getUserId());
-        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        String nowDate = dateFormat.format(new Date());
         /*---------- 如果传入的日期是今天 ----------*/
         UserStatisticsCommonParam param = new UserStatisticsCommonParam();
         param.setUserId(userId).setStartTime(startTime).setEndTime(endTime);
         FsUserStatisticsVO vo = fsUserService.userStatistics(param);
-        if (nowDate.compareTo(startTime) > 0 && nowDate.compareTo(endTime) < 0) {
+
+        DateTimeFormatter dfm = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        LocalDate today = LocalDate.now();
+        LocalDateTime startDateTime = LocalDateTime.parse(startTime, dfm);
+        LocalDateTime endDateTime = LocalDateTime.parse(endTime, dfm);
+        if (startDateTime.toLocalDate().equals(today) && endDateTime.toLocalDate().equals(today)) {
             String yesterday = LocalDate.now().minusDays(1).toString();
             UserStatisticsCommonParam paramYes = new UserStatisticsCommonParam();
             paramYes.setUserId(userId).setStartTime(yesterday + " 00:00:00").setEndTime(yesterday + " 23:59:59");
             FsUserStatisticsVO fsUserStatisticsVO = fsUserService.userStatistics(paramYes);
             vo.setYesterdayVO(fsUserStatisticsVO);
+        } else {
+            vo.setYesterdayVO(new FsUserStatisticsVO());
         }
         return ResponseResult.ok(vo);
     }

+ 25 - 18
fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -1,14 +1,14 @@
 package com.fs.app.controller;
 
+import cn.hutool.json.JSONUtil;
 import com.fs.app.annotation.Login;
 import com.fs.app.config.ImageStorageConfig;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
-import com.fs.common.enums.BizResponseEnum;
 import com.fs.common.utils.StringUtils;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.service.ICompanyUserService;
-import com.fs.company.service.impl.CompanyServiceImpl;
+import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsUserCoursePeriod;
 import com.fs.course.param.FsCourseLinkCreateParam;
 import com.fs.course.param.FsWatchCourseTimeParam;
@@ -19,11 +19,13 @@ import com.fs.course.service.IFsCourseLinkService;
 import com.fs.course.service.IFsUserCoursePeriodService;
 import com.fs.course.service.IFsUserCourseService;
 import com.fs.course.service.IFsUserCourseVideoService;
+import com.fs.course.service.impl.FsUserCourseServiceImpl;
 import com.fs.course.vo.FsUserCourseParticipationRecordVO;
 import com.fs.course.vo.newfs.FsUserCourseListVO;
 import com.fs.course.vo.newfs.FsUserCourseVideoDetailsVO;
 import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
 import com.fs.course.vo.newfs.FsUserVideoListVO;
+import com.fs.system.service.ISysConfigService;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
@@ -53,6 +55,8 @@ public class FsUserCourseVideoController extends AppBaseController {
 
     @Autowired
     private IFsUserCourseService fsUserCourseService;
+    @Autowired
+    private ISysConfigService configService;
 
     @Autowired
     private IFsCourseLinkService courseLinkService;
@@ -63,7 +67,7 @@ public class FsUserCourseVideoController extends AppBaseController {
     @Autowired
     private IFsUserCoursePeriodService fsUserCoursePeriodService;
     @Autowired
-    private ICompanyUserService companyService;
+    private ICompanyUserService companyUserService;
 
     @Login
     @GetMapping("/pageList")
@@ -114,24 +118,22 @@ public class FsUserCourseVideoController extends AppBaseController {
                                                       @RequestParam(required = false) String keyword,
                                                       @RequestParam(required = false, defaultValue = "1") Integer pageNum,
                                                       @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
-        log.debug("参与记录 keyword: {}, pageNum: {}, pageSize: {}", keyword, pageNum, pageSize);
-        String userId = getUserId();
+        log.debug("参与记录 videoId:{}, type:{}, keyword: {}, pageNum: {}, pageSize: {}", videoId, type, keyword, pageNum, pageSize);
         Map<String, Object> params = new HashMap<>();
-        //判断是否管理员 管理员查所有
-        CompanyUser companyUser = companyService.selectCompanyUserById(Long.valueOf(userId));
-        if (companyUser != null) {
-            if (companyUser.isAdmin()) {
-                params.put("companyId", companyUser.getCompanyId());
-            } else {
-                params.put("companyUserId", userId);
-            }
-        } else {
-            return ResponseResult.fail(BizResponseEnum.PARAM_ERROR);
-        }
         params.put("videoId", videoId);
         params.put("type", type);
         params.put("keyword", keyword);
 
+        // type 0 答题领奖记录----答题正确并且领取红包的
+        // type 1 完播----这堂课看完的人
+        // type 2 未完播---看课中断
+        // 管理员看整个公司 否则看自己的
+        CompanyUser companyUser = companyUserService.selectCompanyUserByUserId(Long.parseLong(getUserId()));
+        if (companyUser.isAdmin()) {
+            params.put("companyId", companyUser.getCompanyId());
+        } else {
+            params.put("companyUserId", companyUser.getUserId());
+        }
 
         PageHelper.startPage(pageNum, pageSize);
         List<FsUserCourseParticipationRecordVO> record = fsUserCourseService.getParticipationRecordByMap(params);
@@ -162,8 +164,13 @@ public class FsUserCourseVideoController extends AppBaseController {
 
         R courseSortLink = fsUserCourseService.createCourseSortLink(fsCourseLinkCreateParam);
         String link = courseSortLink.get("link").toString();
-        R r = courseLinkService.getRealLink(link);
-        String realLink = r.get("realLink").toString();
+//        R r = courseLinkService.getRealLink(link);
+//        String realLink = r.get("realLink").toString();
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        String realLink = config.getRealLinkDomainName() + FsUserCourseServiceImpl.shortLink + link;
+
+        log.info("二维码生成地址:{}", realLink);
         try {
             String path = imageConfig.getServerPath();
             log.info("获取的logo图片路径,fileUrl:{}", path);

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

@@ -77,7 +77,9 @@ public class CompanyMenuController extends BaseController
     public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId)
     {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        List<CompanyMenu> menus = menuService.selectMenuList(new CompanyMenu(),loginUser.getUser().getUserId(),loginUser.getUser().getUserType());
+        CompanyMenu companyMenu = new CompanyMenu();
+        companyMenu.setStatus("0");
+        List<CompanyMenu> menus = menuService.selectMenuList(companyMenu,loginUser.getUser().getUserId(),loginUser.getUser().getUserType());
         AjaxResult ajax = AjaxResult.success();
         ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
         ajax.put("menus", menuService.buildMenuTreeSelect(menus));

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

@@ -112,7 +112,7 @@ public class SopUserLogsController extends BaseController
     /**
      * 删除sopUserLogs
      */
-    @PreAuthorize("@ss.hasPermi('qwSop:sopUserLogs:remove')")
+    @PreAuthorize("@ss.hasPermi('qw:sopUserLogs:remove')")
     @Log(title = "删除sopUserLogs", businessType = BusinessType.DELETE)
     @DeleteMapping("/{ids}")
     public AjaxResult remove(@PathVariable String[] ids)

+ 207 - 0
fs-company/src/main/java/com/fs/company/controller/stats/SalesWatchStatisController.java

@@ -0,0 +1,207 @@
+package com.fs.company.controller.stats;
+
+import com.fs.common.annotation.RateLimiter;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.cache.ICompanyUserCacheService;
+import com.fs.company.service.ICompanyService;
+import com.fs.company.vo.DeptDataVO;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.service.TokenService;
+import com.fs.sop.params.GetSOPTaskDataParam;
+import com.fs.sop.service.IQwSopService;
+import com.fs.sop.vo.QwSopTask;
+import com.fs.statis.IFsStatisQwWatchService;
+import com.fs.statis.domain.FsStatisEveryDayWatch;
+import com.fs.statis.domain.FsStatisQwWatch;
+import com.fs.statis.domain.FsStatisSalerWatch;
+import com.fs.statis.domain.FsStatisSopWatch;
+import com.fs.statis.dto.StatsWatchLogPageListDTO;
+import com.fs.statis.service.FsStatisSalerWatchService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import lombok.AllArgsConstructor;
+import org.apache.http.util.Asserts;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.LocalDate;
+import java.util.List;
+
+/**
+ * 看课统计接口
+ */
+@RestController
+@RequestMapping("/stats")
+@AllArgsConstructor
+public class SalesWatchStatisController {
+
+    @Autowired
+    private FsStatisSalerWatchService fsStatisSalerWatchService;
+
+    @Autowired
+    private IQwSopService qwSopService;
+
+    @Autowired
+    private ICompanyService companyService;
+
+    @Autowired
+    private ICompanyUserCacheService companyUserCacheService;
+
+    @Autowired
+    private IFsStatisQwWatchService fsStatisQwWatchService;
+
+    @Autowired
+    private TokenService tokenService;
+    /**
+     * 销售完播统计查询
+     * @param param param
+     * @return R
+     */
+    @PostMapping("/seller/pageList")
+    public R sellerQueryList(@RequestBody StatsWatchLogPageListDTO param){
+        if(param.getPageNum() == null) {
+            param.setPageNum(1);
+        }
+        if(param.getPageSize() == null) {
+            param.setPageSize(10);
+        }
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+
+        List<FsStatisSalerWatch> list = fsStatisSalerWatchService.queryList(param);
+        return R.ok().put("data",new PageInfo<>(list));
+    }
+
+    /**
+     * 进线转化统计
+     * @param param 参数
+     * @return R
+     */
+    @PostMapping("/inline/pageList")
+    public R inlineTransferStats(@RequestBody StatsWatchLogPageListDTO param){
+        if(param.getPageNum() == null) {
+            param.setPageNum(1);
+        }
+        if(param.getPageSize() == null) {
+            param.setPageSize(10);
+        }
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+
+        List<FsStatisQwWatch> list = fsStatisQwWatchService.queryList(param);
+        return R.ok().put("data",new PageInfo<>(list));
+    }
+    @PostMapping("/inline/export")
+    @RateLimiter(time=5,count = 1)
+    public AjaxResult exportInlineQueryList(@RequestBody StatsWatchLogPageListDTO param){
+        param.setPageNum(null);
+        param.setPageSize(null);
+        List<FsStatisQwWatch> list = fsStatisQwWatchService.exportQueryList(param);
+        ExcelUtil<FsStatisQwWatch> util = new ExcelUtil<>(FsStatisQwWatch.class);
+        return util.exportExcel(list, "销售完播统计");
+    }
+
+
+    @PostMapping("/seller/export")
+    @RateLimiter(time=5,count = 1)
+    public AjaxResult exportSellerQueryList(@RequestBody StatsWatchLogPageListDTO param){
+        param.setPageNum(null);
+        param.setPageSize(null);
+        List<FsStatisSalerWatch> list = fsStatisSalerWatchService.export(param);
+        ExcelUtil<FsStatisSalerWatch> util = new ExcelUtil<>(FsStatisSalerWatch.class);
+        return util.exportExcel(list, "销售完播统计");
+    }
+
+    /**
+     * 训练营完播统计查询
+     * @param param param
+     * @return R
+     */
+    @PostMapping("/period/pageList")
+    public R periodQueryList(@RequestBody StatsWatchLogPageListDTO param){
+        if(param.getPageNum() == null) {
+            param.setPageNum(1);
+        }
+        if(param.getPageSize() == null) {
+            param.setPageSize(10);
+        }
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+
+        List<FsStatisSalerWatch> list = fsStatisSalerWatchService.queryPeriodList(param);
+        return R.ok().put("data", new PageInfo<>(list));
+    }
+
+    @PostMapping("/period/export")
+    @RateLimiter(time=5,count = 1)
+    public AjaxResult exportPeriodQueryList(@RequestBody StatsWatchLogPageListDTO param){
+        param.setPageNum(null);
+        param.setPageSize(null);
+        List<FsStatisSopWatch> list = fsStatisSalerWatchService.exportQueryPeriodList(param);
+        ExcelUtil<FsStatisSopWatch> util = new ExcelUtil<>(FsStatisSopWatch.class);
+        return util.exportExcel(list, "SOP任务完播统计");
+    }
+
+    /**
+     * 每日完播统计查询
+     * @param param param
+     * @return R
+     */
+    @PostMapping("/everyDay/pageList")
+    public R everyDayQueryList(@RequestBody StatsWatchLogPageListDTO param){
+        if(param.getPageNum() == null) {
+            param.setPageNum(1);
+        }
+        if(param.getPageSize() == null) {
+            param.setPageSize(10);
+        }
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<FsStatisSalerWatch> list = fsStatisSalerWatchService.queryTodayList(param);
+        return R.ok().put("data", new PageInfo<>(list));
+    }
+    @PostMapping("/everyDay/export")
+    @RateLimiter(time=5,count = 1)
+    public AjaxResult exportEveryDayQueryList(@RequestBody StatsWatchLogPageListDTO param){
+        param.setPageNum(null);
+        param.setPageSize(null);
+        List<FsStatisEveryDayWatch> list = fsStatisSalerWatchService.exportQueryEveryDayList(param);
+        ExcelUtil<FsStatisEveryDayWatch> util = new ExcelUtil<>(FsStatisEveryDayWatch.class);
+        return util.exportExcel(list, "每日完播统计");
+    }
+    /**
+     * 获取SOP任务数据
+     * @return
+     */
+    @PostMapping("/sopTaskData")
+    public R getSOPTaskData(@RequestBody GetSOPTaskDataParam param){
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long companyId = loginUser.getCompany().getCompanyId();
+
+        if(StringUtils.isBlank(param.getStartDate()) && StringUtils.isBlank(param.getEndDate())) {
+            param.setStartDate(LocalDate.now().minusDays(7).toString());
+            param.setEndDate(LocalDate.now().toString());
+        }
+        param.setCompanyId(companyId);
+        List<QwSopTask> qwSopTaskList = qwSopService.getQwSopTaskList(param);
+        return R.ok().put("data",qwSopTaskList);
+    }
+    /**
+     * 获取部门数据
+     * @return
+     */
+    @GetMapping("/getDeptData")
+    public R getDeptData(Long companyId){
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        companyId = loginUser.getCompany().getCompanyId();
+
+        Long userId = loginUser.getUser().getUserId();
+        Long deptId = loginUser.getUser().getDeptId();
+        Asserts.notNull(companyId,"公司id");
+        Asserts.notNull(userId,"销售id");
+        Asserts.notNull(deptId,"部门id");
+        List<DeptDataVO> data = companyService.getDeptData(companyId,userId,deptId);
+        return R.ok().put("data",data);
+    }
+
+}

+ 40 - 1
fs-company/src/main/java/com/fs/company/controller/store/FsStoreOrderController.java

@@ -17,6 +17,7 @@ import com.fs.erp.dto.ErpOrderQueryResponse;
 import com.fs.erp.service.IErpOrderService;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.security.SecurityUtils;
+import com.fs.his.config.FsSysConfig;
 import com.fs.his.domain.*;
 import com.fs.his.dto.ExpressInfoDTO;
 import com.fs.his.enums.ShipperCodeEnum;
@@ -27,12 +28,14 @@ import com.fs.his.param.FsStoreOrderSalesParam;
 import com.fs.his.service.IFsExportTaskService;
 import com.fs.his.service.IFsExpressService;
 import com.fs.his.service.IFsStoreOrderService;
+import com.fs.his.utils.ConfigUtil;
 import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.FsStoreOrderListVO;
 import com.fs.his.vo.FsStoreOrderVO;
 import com.fs.his.vo.FsStoreProductDeliverExcelVO;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
@@ -460,7 +463,11 @@ public class FsStoreOrderController extends BaseController
     public R getEroOrder(@PathVariable("extendOrderId") String extendOrderId) {
         ErpOrderQueryRequert request = new ErpOrderQueryRequert();
         request.setCode(extendOrderId);
-        ErpOrderQueryResponse response = erpOrderService.getOrder(request);
+        IErpOrderService erpOrderService = getErpService();
+        ErpOrderQueryResponse response = new ErpOrderQueryResponse();
+        if (erpOrderService != null){
+            response = erpOrderService.getOrder(request);
+        }
         return R.ok().put("data",response);
     }
     @Log(title = "同步物流", businessType = BusinessType.UPDATE)
@@ -511,4 +518,36 @@ public class FsStoreOrderController extends BaseController
         return AjaxResult.success(fsStoreOrderService.selectFsFollowVOByFollowId(followId));
     }
 
+    @Autowired
+    private ConfigUtil configUtil;
+    @Autowired
+    @Qualifier("erpOrderServiceImpl")
+    private IErpOrderService gyOrderService;
+
+    @Autowired
+    @Qualifier("wdtErpOrderServiceImpl")
+    private IErpOrderService wdtOrderService;
+    private IErpOrderService getErpService() {
+        FsSysConfig sysConfig = configUtil.getSysConfig();
+        Integer erpOpen = sysConfig.getErpOpen();
+        if (erpOpen != null && erpOpen == 1){
+            //判断erp类型
+            Integer erpType = sysConfig.getErpType();
+            if (erpType != null){
+                IErpOrderService erpOrderService = null;
+                if (erpType == 1){
+                    //管易
+                    erpOrderService =  gyOrderService;
+                } else if (erpType == 2){
+                    //旺店通
+                    erpOrderService =  wdtOrderService;
+                }
+                return erpOrderService;
+
+
+            }
+        }
+        return null;
+    }
+
 }

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

@@ -235,7 +235,7 @@ public class FsUserController extends BaseController
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setUserId(loginUser.getUser().getUserId());
 //        startPage();
-        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+//        PageHelper.startPage(param.getPageNum(), param.getPageSize());
         PageInfo<FsUserPageListVO> fsUserPageListVOPageInfo = fsUserService.selectFsUserPageList(param);
         Map<String, Object> map = new HashMap<String, Object>();
         map.put("rows", fsUserPageListVOPageInfo.getList());

+ 1 - 0
fs-company/src/main/java/com/fs/framework/config/DataSourceConfig.java

@@ -40,6 +40,7 @@ public class DataSourceConfig {
     @Primary
     public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("sopDataSource") DataSource sopDataSource) {
         Map<Object, Object> targetDataSources = new HashMap<>();
+        targetDataSources.put(DataSourceType.MASTER, masterDataSource);
         targetDataSources.put(DataSourceType.SOP.name(), sopDataSource);
         return new DynamicDataSource(masterDataSource, targetDataSources);
     }

+ 4 - 4
fs-company/src/main/java/com/fs/user/FsUserAdminController.java

@@ -53,15 +53,15 @@ public class FsUserAdminController extends BaseController {
         //startPage();
 
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        if (param.isMyFsUser()){
+        if (param.getIsMyFsUser()){
             param.setCompanyId(loginUser.getCompany().getCompanyId());
             param.setCompanyUserId(String.valueOf(loginUser.getUser().getUserId()));
         }else {
             param.setCompanyId(loginUser.getCompany().getCompanyId());
         }
-        if(param.getCompanyUserId() == null) {
-            throw new IllegalArgumentException("当前销售不存在!");
-        }
+//        if(param.getCompanyUserId() == null) {
+//            throw new IllegalArgumentException("当前销售不存在!");
+//        }
         return fsUserService.selectFsUserPageListNew(param);
     }
 

+ 1 - 0
fs-framework/src/main/java/com/fs/framework/config/DataSourceConfig.java

@@ -43,6 +43,7 @@ public class DataSourceConfig {
     @Primary
     public DynamicDataSource dataSource(@Qualifier("clickhouseDataSource") DataSource clickhouseDataSource,@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("sopDataSource") DataSource sopDataSource) {
         Map<Object, Object> targetDataSources = new HashMap<>();
+        targetDataSources.put(DataSourceType.MASTER, masterDataSource);
         targetDataSources.put(DataSourceType.SOP.name(), sopDataSource);
         targetDataSources.put(DataSourceType.CLICKHOUSE.name(), clickhouseDataSource);
         return new DynamicDataSource(masterDataSource, targetDataSources);

+ 1 - 0
fs-qw-api/src/main/java/com/fs/framework/config/DataSourceConfig.java

@@ -40,6 +40,7 @@ public class DataSourceConfig {
     @Primary
     public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("sopDataSource") DataSource sopDataSource) {
         Map<Object, Object> targetDataSources = new HashMap<>();
+        targetDataSources.put(DataSourceType.MASTER, masterDataSource);
         targetDataSources.put(DataSourceType.SOP.name(), sopDataSource);
         return new DynamicDataSource(masterDataSource, targetDataSources);
     }

+ 39 - 0
fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java

@@ -29,6 +29,9 @@ import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.Arrays;
 import java.util.List;
 
@@ -87,6 +90,42 @@ public class CommonController {
     private IFsUserCourseCountService userCourseCountService;
 
 
+    /**
+    * 发官方通连
+    */
+    @GetMapping("/sopguanfanone")
+    public R sopguanfanone(String dateTime) throws Exception {
+
+        LocalDateTime localDateTime = DateUtil.parseLocalDateTime(dateTime);
+
+        int currentHour = localDateTime.getHour();
+        LocalDate localDate = localDateTime.toLocalDate();
+
+        String taskStartTime = localDate.atTime(currentHour, 0, 0)
+                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+        String taskEndTime = localDate.atTime(currentHour, 59, 59)
+                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+
+        qwSopLogsService.createCorpMassSendingByUserLogs( taskStartTime, taskEndTime);
+        return R.ok();
+    }
+
+    /**
+    * 发一对一
+    */
+    @GetMapping("/sopguanfantwo")
+    public R sopguanfantwo(String dateTime) throws Exception {
+
+        LocalDateTime localDateTime = DateUtil.parseLocalDateTime(dateTime);
+
+
+        LocalDate localDate = localDateTime.toLocalDate();
+        String date = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+
+        qwSopLogsService.createCorpMassSending(date);
+        return R.ok();
+    }
+
     @GetMapping("/testSop")
     public R testSop() throws Exception {
 

+ 1 - 1
fs-qw-task/src/main/java/com/fs/app/task/CourseWatchLogScheduler.java

@@ -126,7 +126,7 @@ public class CourseWatchLogScheduler {
 
     }
 
-    @Scheduled(fixedRate = 60000) // 每分钟执行一次
+    @Scheduled(fixedRate = 30000) // 每分钟执行一次
     public void checkFsUserWatchStatus() {
         // 尝试设置标志为 true,表示任务开始执行
         if (!isRunning4.compareAndSet(false, true)) {

+ 1 - 1
fs-qw-task/src/main/java/com/fs/app/task/UserCourseWatchCountTask.java

@@ -16,7 +16,7 @@ public class UserCourseWatchCountTask {
     /**
      * 每15分钟执行一次
      */
-    @Scheduled(cron = "0 */15 * * * ?")  // 每15分钟执行一次
+    @Scheduled(cron = "0 */10 * * * ?")  // 每10分钟执行一次
     public void userCourseCountTask() {
         try {
             log.info("==============会员看课统计任务执行===============开始");

+ 21 - 9
fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java

@@ -774,22 +774,33 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         sopLogs.setQwUserid(logVo.getQwUserId());
         sopLogs.setCorpId(logVo.getCorpId());
         sopLogs.setLogType(ruleTimeVO.getType());
+        sopLogs.setTakeRecords(0);
 
         if (isOfficial == 1) {
 
-            if (fsUserId== null || Long.valueOf(0L).equals(fsUserId)){
-                sopLogs.setSendType(2);
-                sopLogs.setRemark("未绑定小程序用户,单链补发");
-                //时间设置成固定7点
-                LocalDateTime dateTime = LocalDateTime.parse(formattedSendTime, DATE_TIME_FORMATTER);
-                sopLogs.setSendTime(OUTPUT_FORMATTER.format(dateTime));
+            if (logVo.getIsSampSend()== 1) {
+                if (fsUserId == null || Long.valueOf(0L).equals(fsUserId)) {
+                    sopLogs.setSendType(2);
+                    sopLogs.setRemark("未绑定小程序用户,单链补发");
+                    //时间设置成固定8点
+                    LocalDateTime dateTime = LocalDateTime.parse(formattedSendTime, DATE_TIME_FORMATTER);
+                    sopLogs.setSendTime(OUTPUT_FORMATTER.format(dateTime));
+                } else {
+                    sopLogs.setSendType(1);
+                }
+
             }else {
-                sopLogs.setSendType(1);
+                if (fsUserId == null || Long.valueOf(0L).equals(fsUserId)) {
+                    sopLogs.setTakeRecords(1);
+                    sopLogs.setSendType(1);
+                }else {
+                    sopLogs.setSendType(1);
+                }
             }
 
-        }else if (isOfficial==0){
+        } else if (isOfficial == 0) {
             sopLogs.setSendType(ruleTimeVO.getSendType() == 1 ? 2 : ruleTimeVO.getSendType());
-        }else{
+        } else {
             sopLogs.setSendType(ruleTimeVO.getSendType());
         }
 
@@ -1828,6 +1839,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         sopLogs.setExternalUserId(externalContact.getExternalUserId());
         sopLogs.setExternalUserName(externalContact.getName());
         sopLogs.setFsUserId(finishLog.getUserId() != null ? finishLog.getUserId() : null );
+        sopLogs.setUserLogsId("-");
         // 解析模板设置
         List<QwSopCourseFinishTempSetting.Setting> settings = parseSettings(finishTemp.getSetting());
         if (settings == null) {

+ 6 - 23
fs-qwhook-sop/src/main/java/com/fs/app/controller/ApisFsUserCourseVideoController.java

@@ -144,7 +144,11 @@ public class ApisFsUserCourseVideoController extends BaseController {
             return R.error("客户id不能为空");
         }
 
-        return fsUserCourseVideoService.createCartLink(param);
+        if (param.getType()==null || param.getType()==1){
+            return fsUserCourseVideoService.createCartLink(param);
+        }else {
+            return fsUserCourseVideoService.createMiniLink(param);
+        }
     }
 
     @GetMapping("/createRoomLink")
@@ -154,28 +158,7 @@ public class ApisFsUserCourseVideoController extends BaseController {
         if (qwUser==null||qwUser.getCompanyId()==null){
             return R.error("无权限");
         }
-        FsCourseLinkCreateParam createParam = new FsCourseLinkCreateParam();
-        createParam.setCourseId(param.getCourseId());
-        createParam.setVideoId(param.getVideoId());
-        createParam.setCorpId(param.getCorpId());
-        createParam.setCompanyUserId(qwUser.getCompanyUserId());
-        createParam.setCompanyId(qwUser.getCompanyId());
-        createParam.setQwUserId(qwUser.getId());
-        String linkUrl;
-        R createLink = courseLinkService.createRoomLinkUrl(createParam);
-        if (createLink.get("code").equals(500)){
-            return R.error("链接生成失败!");
-        }
-        linkUrl = (String) createLink.get("url");
-
-        FsUserCourse course = fsUserCourseService.selectFsUserCourseByCourseId(param.getCourseId());
-
-        JSONObject news = new JSONObject(true); // true 表示保持字段顺序
-        news.put("link", linkUrl);
-        news.put("title", course.getCourseName());
-        news.put("desc", param.getTitle());
-        news.put("imgUrl", course.getImgUrl());
-        return R.ok().put("news",news);
+        return courseLinkService.createRoomLink(param, qwUser);
     }
 
 }

+ 6 - 23
fs-qwhook-sop/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -101,28 +101,7 @@ public class FsUserCourseVideoController {
         if (qwUser==null||qwUser.getCompanyId()==null){
             return R.error("无权限");
         }
-        FsCourseLinkCreateParam createParam = new FsCourseLinkCreateParam();
-        createParam.setCourseId(param.getCourseId());
-        createParam.setVideoId(param.getVideoId());
-        createParam.setCorpId(param.getCorpId());
-        createParam.setCompanyUserId(qwUser.getCompanyUserId());
-        createParam.setCompanyId(qwUser.getCompanyId());
-        createParam.setQwUserId(qwUser.getId());
-        String linkUrl;
-        R createLink = courseLinkService.createRoomLinkUrl(createParam);
-        if (createLink.get("code").equals(500)){
-            return R.error("链接生成失败!");
-        }
-        linkUrl = (String) createLink.get("url");
-
-        FsUserCourse course = fsUserCourseService.selectFsUserCourseByCourseId(param.getCourseId());
-
-        JSONObject news = new JSONObject(true); // true 表示保持字段顺序
-        news.put("link", linkUrl);
-        news.put("title", course.getCourseName());
-        news.put("desc", param.getTitle());
-        news.put("imgUrl", course.getImgUrl());
-        return R.ok().put("news",news);
+        return courseLinkService.createRoomLink(param, qwUser);
     }
 
     /**
@@ -177,6 +156,10 @@ public class FsUserCourseVideoController {
             return R.error("客户id不能为空");
         }
 
-        return fsUserCourseVideoService.createCartLink(param);
+        if (param.getType()==null || param.getType()==1){
+            return fsUserCourseVideoService.createCartLink(param);
+        }else {
+            return fsUserCourseVideoService.createMiniLink(param);
+        }
     }
 }

+ 1 - 0
fs-qwhook-sop/src/main/java/com/fs/framework/config/DataSourceConfig.java

@@ -40,6 +40,7 @@ public class DataSourceConfig {
     @Primary
     public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("sopDataSource") DataSource sopDataSource) {
         Map<Object, Object> targetDataSources = new HashMap<>();
+        targetDataSources.put(DataSourceType.MASTER, masterDataSource);
         targetDataSources.put(DataSourceType.SOP.name(), sopDataSource);
         return new DynamicDataSource(masterDataSource, targetDataSources);
     }

+ 6 - 23
fs-qwhook/src/main/java/com/fs/app/controller/ApisFsUserCourseVideoController.java

@@ -143,7 +143,11 @@ public class ApisFsUserCourseVideoController extends BaseController {
             return R.error("客户id不能为空");
         }
 
-        return fsUserCourseVideoService.createCartLink(param);
+        if (param.getType()==null || param.getType()==1){
+            return fsUserCourseVideoService.createCartLink(param);
+        }else {
+            return fsUserCourseVideoService.createMiniLink(param);
+        }
 
     }
 
@@ -154,28 +158,7 @@ public class ApisFsUserCourseVideoController extends BaseController {
         if (qwUser==null||qwUser.getCompanyId()==null){
             return R.error("无权限");
         }
-        FsCourseLinkCreateParam createParam = new FsCourseLinkCreateParam();
-        createParam.setCourseId(param.getCourseId());
-        createParam.setVideoId(param.getVideoId());
-        createParam.setCorpId(param.getCorpId());
-        createParam.setCompanyUserId(qwUser.getCompanyUserId());
-        createParam.setCompanyId(qwUser.getCompanyId());
-        createParam.setQwUserId(qwUser.getId());
-        String linkUrl;
-        R createLink = courseLinkService.createRoomLinkUrl(createParam);
-        if (createLink.get("code").equals(500)){
-            return R.error("链接生成失败!");
-        }
-        linkUrl = (String) createLink.get("url");
-
-        FsUserCourse course = fsUserCourseService.selectFsUserCourseByCourseId(param.getCourseId());
-
-        JSONObject news = new JSONObject(true); // true 表示保持字段顺序
-        news.put("link", linkUrl);
-        news.put("title", course.getCourseName());
-        news.put("desc", param.getTitle());
-        news.put("imgUrl", course.getImgUrl());
-        return R.ok().put("news",news);
+        return courseLinkService.createRoomLink(param, qwUser);
     }
 
 }

+ 6 - 23
fs-qwhook/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -150,7 +150,11 @@ public class FsUserCourseVideoController {
             return R.error("客户id不能为空");
         }
 
-        return fsUserCourseVideoService.createCartLink(param);
+        if (param.getType()==null || param.getType()==1){
+            return fsUserCourseVideoService.createCartLink(param);
+        }else {
+            return fsUserCourseVideoService.createMiniLink(param);
+        }
 
     }
 
@@ -161,28 +165,7 @@ public class FsUserCourseVideoController {
         if (qwUser==null||qwUser.getCompanyId()==null){
             return R.error("无权限");
         }
-        FsCourseLinkCreateParam createParam = new FsCourseLinkCreateParam();
-        createParam.setCourseId(param.getCourseId());
-        createParam.setVideoId(param.getVideoId());
-        createParam.setCorpId(param.getCorpId());
-        createParam.setCompanyUserId(qwUser.getCompanyUserId());
-        createParam.setCompanyId(qwUser.getCompanyId());
-        createParam.setQwUserId(qwUser.getId());
-        String linkUrl;
-        R createLink = courseLinkService.createRoomLinkUrl(createParam);
-        if (createLink.get("code").equals(500)){
-            return R.error("链接生成失败!");
-        }
-        linkUrl = (String) createLink.get("url");
-
-        FsUserCourse course = fsUserCourseService.selectFsUserCourseByCourseId(param.getCourseId());
-
-        JSONObject news = new JSONObject(true); // true 表示保持字段顺序
-        news.put("link", linkUrl);
-        news.put("title", course.getCourseName());
-        news.put("desc", param.getTitle());
-        news.put("imgUrl", course.getImgUrl());
-        return R.ok().put("news",news);
+        return courseLinkService.createRoomLink(param, qwUser);
     }
 
 }

+ 1 - 0
fs-qwhook/src/main/java/com/fs/framework/config/DataSourceConfig.java

@@ -40,6 +40,7 @@ public class DataSourceConfig {
     @Primary
     public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("sopDataSource") DataSource sopDataSource) {
         Map<Object, Object> targetDataSources = new HashMap<>();
+        targetDataSources.put(DataSourceType.MASTER, masterDataSource);
         targetDataSources.put(DataSourceType.SOP.name(), sopDataSource);
         return new DynamicDataSource(masterDataSource, targetDataSources);
     }

+ 5 - 0
fs-service/src/main/java/com/fs/company/cache/ICompanyDeptCacheService.java

@@ -0,0 +1,5 @@
+package com.fs.company.cache;
+
+public interface ICompanyDeptCacheService {
+    String getDeptNameById(Long deptId);
+}

+ 5 - 0
fs-service/src/main/java/com/fs/company/cache/ICompanyUserCacheService.java

@@ -1,7 +1,9 @@
 package com.fs.company.cache;
 
 import com.fs.company.domain.CompanyUser;
+import com.fs.company.vo.DeptDataVO;
 
+import java.util.List;
 import java.util.Set;
 
 ;
@@ -29,4 +31,7 @@ public interface ICompanyUserCacheService {
      */
     public Set<Long> selectUserAllCompanyUserId(Long companyUserId);
 
+    List<DeptDataVO> getDeptData(Long companyId);
+    List<DeptDataVO> getDeptData(Long companyId,Long companyUserId);
+
 }

+ 27 - 0
fs-service/src/main/java/com/fs/company/cache/impl/CompanyDeptCacheServiceImpl.java

@@ -0,0 +1,27 @@
+package com.fs.company.cache.impl;
+
+import com.fs.company.cache.ICompanyDeptCacheService;
+import com.fs.company.service.ICompanyDeptService;
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.concurrent.TimeUnit;
+
+@Service
+public class CompanyDeptCacheServiceImpl implements ICompanyDeptCacheService {
+    private static final Cache<Long, String> COMPANY_DEPT_CACHE = Caffeine.newBuilder()
+            .maximumSize(1000)
+            .expireAfterWrite(10, TimeUnit.MINUTES)
+            .build();
+    @Autowired
+    private ICompanyDeptService companyDeptService;
+    @Override
+    public String getDeptNameById(Long deptId) {
+        if(deptId == null) {
+            return "-";
+        }
+        return COMPANY_DEPT_CACHE.get(deptId,e-> companyDeptService.selectDeptNameById(deptId));
+    }
+}

+ 31 - 0
fs-service/src/main/java/com/fs/company/cache/impl/CompanyUserCacheServiceImpl.java

@@ -2,13 +2,17 @@ package com.fs.company.cache.impl;
 
 import com.fs.company.cache.ICompanyUserCacheService;
 import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.ICompanyService;
 import com.fs.company.service.ICompanyUserService;
+import com.fs.company.vo.DeptDataVO;
 import com.github.benmanes.caffeine.cache.Cache;
 import com.github.benmanes.caffeine.cache.Caffeine;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -21,6 +25,9 @@ public class CompanyUserCacheServiceImpl implements ICompanyUserCacheService {
     @Autowired
     private ICompanyUserService companyUserService;
 
+    @Autowired
+    private ICompanyService companyService;
+
     private static final Cache<Long, CompanyUser> USER_CACHE = Caffeine.newBuilder()
             .maximumSize(1000)
             .expireAfterWrite(3, TimeUnit.MINUTES)
@@ -36,6 +43,11 @@ public class CompanyUserCacheServiceImpl implements ICompanyUserCacheService {
             .expireAfterWrite(5, TimeUnit.MINUTES)
             .build();
 
+    private static final Cache<Long,List<DeptDataVO>> COMPANY_USER_TREE_CACHE = Caffeine.newBuilder()
+            .maximumSize(1000)
+            .expireAfterWrite(10, TimeUnit.MINUTES)
+            .build();
+
 
     @Override
     public CompanyUser selectCompanyUserById(Long userId) {
@@ -56,4 +68,23 @@ public class CompanyUserCacheServiceImpl implements ICompanyUserCacheService {
             return set;
         });
     }
+
+    @Override
+    public List<DeptDataVO> getDeptData(Long companyId) {
+        if(companyId == null) {
+            companyId = -1L;
+        }
+        Long finalCompanyId = companyId;
+        return COMPANY_USER_TREE_CACHE.get(companyId, e->{
+            if(ObjectUtils.equals(finalCompanyId,-1L)) {
+                return companyService.getDeptData(null);
+            }
+            return companyService.getDeptData(finalCompanyId);
+        });
+    }
+
+    @Override
+    public List<DeptDataVO> getDeptData(Long companyId, Long companyUserId) {
+        return Collections.emptyList();
+    }
 }

+ 27 - 6
fs-service/src/main/java/com/fs/company/mapper/CompanyDeptMapper.java

@@ -5,6 +5,7 @@ import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * 部门Mapper接口
@@ -30,6 +31,18 @@ public interface CompanyDeptMapper
      */
     public List<CompanyDept> selectCompanyDeptList(CompanyDept companyDept);
 
+    @Select("select * from company_dept where dept_id = #{parentId} or parent_id = #{parentId} and company_id=#{companyId} and status=#{status}")
+    public List<CompanyDept> selectCompanyDeptListByDeptAndParent(CompanyDept companyDept);
+    /**
+     * 获取公司默认部门
+     * @param companyId 公司ID
+     * @return  公司部门
+     * 获取所有部门的数据
+     * @param companyId 公司id
+     * @return 部门数据
+     */
+    @Select("select cd.* from company_dept cd where cd.company_id = #{companyId} and cd.dept_name = '默认' and cd.parent_id = 0 limit 1")
+    CompanyDept getTopCompanyDeptByCompanyId(@Param("companyId") Long companyId);
     /**
      * 新增部门
      *
@@ -83,12 +96,20 @@ public interface CompanyDeptMapper
 
     @Select("select company_id from company_dept where dept_id =#{deptId} ")
     Long selectCompanyDeptByIdCompany(Long deptId);
-
     /**
-     * 获取公司默认部门
-     * @param companyId 公司ID
-     * @return  公司部门
+     * 获取所有部门的数据
+     * @param companyId 公司id
+     * @return 部门数据
      */
-    @Select("select cd.* from company_dept cd where cd.company_id = #{companyId} and cd.dept_name = '默认' and cd.parent_id = 0 limit 1")
-    CompanyDept getTopCompanyDeptByCompanyId(@Param("companyId") Long companyId);
+    @Select("select * from company_dept where company_id = ${companyId}")
+    List<CompanyDept> selectDeptDataByCompanyId(@Param("companyId") Long companyId);
+
+    @Select("select dept_id from company_dept where parent_id=#{parentId}")
+    List<Long> selectCompanyDeptByParentId(@Param("parentId") Long parentId);
+
+    @Select("select * from company_dept where status='0' and del_flag='0'")
+    List<CompanyDept> queryDeptDataAll();
+
+    @Select("select dept_name from company_dept where dept_id=${deptId} limit 1")
+    String selectDeptNameById(@Param("deptId") Long deptId);
 }

+ 10 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyMapper.java

@@ -8,6 +8,7 @@ import com.fs.company.vo.CompanyCrmVO;
 import com.fs.company.vo.CompanyNameVO;
 import com.fs.company.vo.CompanyVO;
 import com.fs.his.vo.OptionsVO;
+import com.fs.huifuPay.sdk.opps.core.utils.StringUtil;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
@@ -170,6 +171,15 @@ public interface CompanyMapper
     @Select("select company_id from company")
     List<Long> selectCompanyIds();
 
+    String selectCompanyNameCompanyByIds(@Param("companyIds") String companyIds);
+
+    String selectDoctorIdsByCompanyId(Long companyId);
+
+    List<Company> selectCompanyAllList();
+
+    List<OptionsVO> selectByIds(@Param("ids") List<Long> ids);
+
+
     /**
      * 通过企业id批量查询
      * **/

+ 2 - 2
fs-service/src/main/java/com/fs/company/mapper/CompanyRoleMapper.java

@@ -65,9 +65,9 @@ public interface CompanyRoleMapper
 
     List<CompanyRole> selectRolesByUserName(String username);
 
-    CompanyRole checkRoleNameUnique(String roleName);
+    CompanyRole checkRoleNameUnique(@Param("roleName") String roleName, @Param("companyId") Long companyId);
 
-    CompanyRole checkRoleKeyUnique(String roleKey);
+    CompanyRole checkRoleKeyUnique(@Param("roleKey") String roleKey,@Param("companyId") Long companyId);
 
     List<Integer> selectRoleListByUserId(Long userId);
 

+ 21 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyUserMapper.java

@@ -17,6 +17,7 @@ import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
 
+import java.time.LocalDate;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -264,4 +265,24 @@ public interface CompanyUserMapper
     List<CompanyUser> getUserInfoByUserIds(@Param("ids") List<Long> ids);
     @DataSource(DataSourceType.MASTER)
     CompanyUser selectCompanyUserByPhone(String phone);
+
+    @Select("select user_id,dept_id,user_name,company_id,nick_name from company_user where ifnull(del_flag,0)=0 and status=0")
+    List<CompanyUser> selectAllCompanyUserList();
+
+    /**
+     * 获取对应的销售观看记录数
+     *
+     * @param companyUserId
+     * @return
+     */
+    Long queryCompanyUserWatchCount(@Param("companyUserId") Long companyUserId,
+                                    @Param("previousDay") LocalDate previousDay);
+
+    Long queryCompanyUserWatchCountCompleted(@Param("companyUserId") Long companyUserId,
+                                             @Param("previousDay") LocalDate previousDay);
+
+    Long queryCompanyUserInterruptCount(@Param("companyUserId") Long companyUserId,
+                                        @Param("previousDay") LocalDate previousDay);
+
+
 }

+ 5 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyDeptService.java

@@ -1,5 +1,6 @@
 package com.fs.company.service;
 
+import com.fs.common.core.domain.entity.SysDept;
 import com.fs.company.domain.CompanyDept;
 import com.fs.company.domain.CompanyDeptTreeSelect;
 
@@ -28,6 +29,7 @@ public interface ICompanyDeptService
      * @return 部门集合
      */
     public List<CompanyDept> selectCompanyDeptList(CompanyDept companyDept);
+    public List<CompanyDept> selectCompanyDeptListByDeptAndParent(CompanyDept companyDept);
 
     /**
      * 新增部门
@@ -78,6 +80,9 @@ public interface ICompanyDeptService
 
     List<String> selectCompanyDeptNamesByIds(String ids);
 
+    List<Long> selectCompanyDeptByParentId(Long parentId);
+
+    String selectDeptNameById(Long deptId);
 
     /**
      * 获取公司默认部门

+ 13 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyService.java

@@ -9,6 +9,7 @@ import com.fs.company.param.CompanyParam;
 import com.fs.company.vo.CompanyCrmVO;
 import com.fs.company.vo.CompanyNameVO;
 import com.fs.company.vo.CompanyVO;
+import com.fs.company.vo.DeptDataVO;
 import com.fs.his.domain.FsInquiryOrder;
 import com.fs.his.domain.FsStoreOrder;
 import com.fs.his.domain.FsStorePayment;
@@ -115,5 +116,17 @@ public interface ICompanyService
 
     List<Long> selectCompanyIds();
 
+    /**
+     * 查询多个公司的名字
+     * @param companyIds
+     * @return
+     */
+    String selectCompanyByIds(String companyIds);
+
+    List<DeptDataVO> getDeptData(Long companyId);
+    List<DeptDataVO> getDeptData(Long companyId,Long currentCompanyUserId,Long currentDeptId);
+
     void configUserCheck(Long companyId, Integer userIsDefaultBlack);
+
+    void addRedPacketCompanyMoney(BigDecimal money, Long companyId);
 }

+ 16 - 6
fs-service/src/main/java/com/fs/company/service/impl/CompanyDeptServiceImpl.java

@@ -15,6 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -57,6 +58,11 @@ public class CompanyDeptServiceImpl implements ICompanyDeptService
         return companyDeptMapper.selectCompanyDeptList(companyDept);
     }
 
+    @Override
+    public List<CompanyDept> selectCompanyDeptListByDeptAndParent(CompanyDept companyDept) {
+        return companyDeptMapper.selectCompanyDeptListByDeptAndParent(companyDept);
+    }
+
     /**
      * 新增部门
      *
@@ -224,16 +230,20 @@ public class CompanyDeptServiceImpl implements ICompanyDeptService
         return companyDeptMapper.selectCompanyDeptNamesByIds(ids);
     }
 
-    /**
-     * 获取公司默认部门
-     * @param companyId 公司ID
-     * @return 部门
-     */
+    @Override
+    public List<Long> selectCompanyDeptByParentId(Long parentId) {
+        return companyDeptMapper.selectCompanyDeptByParentId(parentId);
+    }
+
+    @Override
+    public String selectDeptNameById(Long deptId) {
+        return companyDeptMapper.selectDeptNameById(deptId);
+    }
+
     @Override
     public CompanyDept getDefaultCompanyDeptByCompanyId(Long companyId) {
         return companyDeptMapper.getTopCompanyDeptByCompanyId(companyId);
     }
-
     /**
      * 递归列表
      */

+ 2 - 2
fs-service/src/main/java/com/fs/company/service/impl/CompanyRoleServiceImpl.java

@@ -127,7 +127,7 @@ public class CompanyRoleServiceImpl implements ICompanyRoleService
     @Override
     public String checkRoleNameUnique(CompanyRole role) {
         Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
-        CompanyRole info = companyRoleMapper.checkRoleNameUnique(role.getRoleName());
+        CompanyRole info = companyRoleMapper.checkRoleNameUnique(role.getRoleName(),role.getCompanyId());
         if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue())
         {
             return UserConstants.NOT_UNIQUE;
@@ -139,7 +139,7 @@ public class CompanyRoleServiceImpl implements ICompanyRoleService
     public String checkRoleKeyUnique(CompanyRole role) {
 
         Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
-        CompanyRole info = companyRoleMapper.checkRoleKeyUnique(role.getRoleKey());
+        CompanyRole info = companyRoleMapper.checkRoleKeyUnique(role.getRoleKey(),role.getCompanyId());
         if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue())
         {
             return UserConstants.NOT_UNIQUE;

+ 454 - 9
fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java

@@ -1,10 +1,8 @@
 package com.fs.company.service.impl;
 
 import java.math.BigDecimal;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+import java.util.stream.Collectors;
 
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
@@ -18,22 +16,20 @@ import com.fs.company.service.ICompanyProfitService;
 import com.fs.company.vo.CompanyCrmVO;
 import com.fs.company.vo.CompanyNameVO;
 import com.fs.company.vo.CompanyVO;
+import com.fs.company.vo.DeptDataVO;
 import com.fs.his.config.StoreConfig;
 import com.fs.his.domain.FsInquiryOrder;
-import com.fs.his.domain.FsPayConfig;
 import com.fs.his.domain.FsStoreOrder;
 import com.fs.his.domain.FsStorePayment;
 import com.fs.his.dto.InquiryConfigDTO;
 import com.fs.his.mapper.FsStoreOrderMapper;
-import com.fs.his.service.IFsInquiryOrderService;
-import com.fs.his.service.impl.FsInquiryOrderServiceImpl;
 import com.fs.his.vo.OptionsVO;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
 import com.fs.system.service.ISysConfigService;
 import com.google.gson.Gson;
-import io.swagger.models.auth.In;
-import lombok.Synchronized;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang.ObjectUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -77,6 +73,13 @@ public class CompanyServiceImpl implements ICompanyService
     private ICompanyProfitService companyProfitService;
     @Autowired
     private SysConfigMapper sysConfigMapper;
+
+    @Autowired
+    private CompanyDeptMapper companyDeptMapper;
+
+    @Autowired
+    private CompanyUserMapper companyUserMapper;
+
     @Override
     public List<OptionsVO> selectAllCompanyList() {
         return companyMapper.selectAllCompanyList();
@@ -528,6 +531,427 @@ public class CompanyServiceImpl implements ICompanyService
         return companyMapper.selectCompanyIds() ;
     }
 
+    @Override
+    public String selectCompanyByIds(String companyIds) {
+        return companyMapper.selectCompanyNameCompanyByIds(companyIds);
+
+    }
+
+    @Override
+    public List<DeptDataVO> getDeptData(Long companyId) {
+        List<DeptDataVO> result = new ArrayList<>();
+
+        // 获取用户按部门分组的数据
+        Map<Long, List<CompanyUser>> companyUserGroupByDeptId = getCompanyUserGroupByDeptId();
+        // 获取部门按公司分组的数据
+        Map<Long, List<CompanyDept>> companyDeptGroupByCompanyId = getCompanyDeptGroupByCompanyId();
+        // 获取子部门按父部门分组的数据
+        Map<Long, List<CompanyDept>> deptGroupByParentId = getDeptGroupByParentId();
+
+        if (companyId != null) {
+            Company company = companyMapper.selectCompanyById(companyId);
+            if (company != null) {
+                DeptDataVO companyNode = buildCompanyNode(company, companyUserGroupByDeptId,
+                        companyDeptGroupByCompanyId, deptGroupByParentId);
+                result.add(companyNode);
+            }
+        } else {
+            List<Company> companies = companyMapper.selectCompanyAllList();
+            if (companies != null && !companies.isEmpty()) {
+                for (Company company : companies) {
+                    DeptDataVO companyNode = buildCompanyNode(company, companyUserGroupByDeptId,
+                            companyDeptGroupByCompanyId, deptGroupByParentId);
+                    result.add(companyNode);
+                }
+            }
+        }
+
+        return result.stream()
+                .filter(e -> CollectionUtils.isNotEmpty(e.getChildren()))
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    public List<DeptDataVO> getDeptData(Long companyId, Long currentCompanyUserId, Long currentDeptId) {
+        List<DeptDataVO> result = new ArrayList<>();
+
+        // 1. 获取所有部门数据
+        List<CompanyDept> allCompanyDepts = companyDeptMapper.queryDeptDataAll();
+
+        // 2. 按部门ID分组,方便直接获取部门信息
+        Map<Long, CompanyDept> deptMapById = allCompanyDepts.stream()
+                .filter(e -> e.getDeptId() != null)
+                .collect(Collectors.toMap(CompanyDept::getDeptId, dept -> dept, (a, b) -> a));
+
+        // 3. 按父部门ID分组,用于构建树结构
+        Map<Long, List<CompanyDept>> deptsByParentIdMap = allCompanyDepts.stream()
+                .filter(e -> e.getParentId() != null && e.getDeptId() != null)
+                .collect(Collectors.groupingBy(CompanyDept::getParentId));
+
+        // 4. 获取所有用户数据并按部门分组
+        Map<Long, List<CompanyUser>> allUsersByDeptIdMap = getCompanyUserGroupByDeptId();
+
+        // 5. 获取当前用户可见的部门ID集合(本部门及下级部门)
+        Set<Long> visibleDeptIds = new HashSet<>();
+        if (currentDeptId != null) {
+            visibleDeptIds.add(currentDeptId); // 添加当前部门
+            collectSubDepartments(currentDeptId, visibleDeptIds, deptsByParentIdMap); // 添加所有下级部门
+        }
+
+        // 6. 如果没有可见部门,直接返回空列表
+        if (visibleDeptIds.isEmpty()) {
+            return result;
+        }
+
+        // 7. 获取公司信息
+        Company company = companyMapper.selectCompanyById(companyId);
+        if (company == null) {
+            return result;
+        }
+
+        // 8. 构建公司节点
+        DeptDataVO companyNode = new DeptDataVO();
+        companyNode.setLabel(company.getCompanyName());
+        companyNode.setId(company.getCompanyId());
+
+        // 9. 构建部门树(仅包含可见部门)
+        // 先找到当前部门对象
+        CompanyDept currentDept = deptMapById.get(currentDeptId);
+        if (currentDept == null) {
+            return result;
+        }
+
+        // 获取当前部门的所有上级部门路径
+        List<Long> deptPath = new ArrayList<>();
+        Long tempDeptId = currentDeptId;
+        while (tempDeptId != null && tempDeptId > 0) {
+            CompanyDept dept = deptMapById.get(tempDeptId);
+            if (dept == null) break;
+            deptPath.add(tempDeptId);
+            tempDeptId = dept.getParentId();
+        }
+
+        // 构建以公司为根的树形结构
+        // 找出顶级部门(parentId为null或0的部门)
+        List<CompanyDept> rootDepts = allCompanyDepts.stream()
+                .filter(dept -> dept.getCompanyId() != null &&
+                        dept.getCompanyId().equals(companyId) &&
+                        (dept.getParentId() == null || dept.getParentId().equals(0L)))
+                .collect(Collectors.toList());
+
+        // 递归构建带权限的树
+        List<DeptDataVO> deptTree = buildDeptTreeWithPermission(
+                rootDepts,
+                allUsersByDeptIdMap,
+                deptsByParentIdMap,
+                visibleDeptIds,
+                deptPath,
+                currentDeptId,
+                currentCompanyUserId);
+
+        companyNode.setChildren(deptTree.isEmpty() ? null : deptTree);
+        result.add(companyNode);
+
+        // 过滤掉空公司节点
+        return result.stream()
+                .filter(node -> node.getChildren() != null && !node.getChildren().isEmpty())
+                .collect(Collectors.toList());
+    }
+    /**
+     * 递归收集所有下级部门ID
+     */
+    private void collectSubDepartments(Long parentDeptId, Set<Long> deptIds, Map<Long, List<CompanyDept>> deptsByParentIdMap) {
+        List<CompanyDept> childDepts = deptsByParentIdMap.get(parentDeptId);
+        if (childDepts != null && !childDepts.isEmpty()) {
+            for (CompanyDept childDept : childDepts) {
+                if (childDept.getDeptId() != null && deptIds.add(childDept.getDeptId())) {
+                    collectSubDepartments(childDept.getDeptId(), deptIds, deptsByParentIdMap);
+                }
+            }
+        }
+    }
+    /**
+     * 递归构建带权限控制的部门树
+     */
+    private List<DeptDataVO> buildDeptTreeWithPermission(
+            List<CompanyDept> depts,
+            Map<Long, List<CompanyUser>> allUsersByDeptIdMap,
+            Map<Long, List<CompanyDept>> deptsByParentIdMap,
+            Set<Long> visibleDeptIds,
+            List<Long> deptPath,
+            Long currentDeptId,
+            Long currentCompanyUserId) {
+
+        if (depts == null || depts.isEmpty()) {
+            return new ArrayList<>();
+        }
+        List<DeptDataVO> result = new ArrayList<>();
+        for (CompanyDept dept : depts) {
+            // 如果当前部门不在用户可见范围内,且不在部门路径中,则跳过
+            if (!visibleDeptIds.contains(dept.getDeptId()) && !deptPath.contains(dept.getDeptId())) {
+                continue;
+            }
+
+            // 先递归构建子部门
+            List<CompanyDept> childDepts = deptsByParentIdMap.get(dept.getDeptId());
+            List<DeptDataVO> children = new ArrayList<>();
+
+            if (childDepts != null && !childDepts.isEmpty()) {
+                List<DeptDataVO> childDeptNodes = buildDeptTreeWithPermission(
+                        childDepts,
+                        allUsersByDeptIdMap,
+                        deptsByParentIdMap,
+                        visibleDeptIds,
+                        deptPath,
+                        currentDeptId,
+                        currentCompanyUserId);
+                if (!childDeptNodes.isEmpty()) {
+                    children.addAll(childDeptNodes);
+                }
+            }
+            // 添加部门下的用户(需要权限控制)
+            List<DeptDataVO> userNodes = new ArrayList<>();
+            if (visibleDeptIds.contains(dept.getDeptId())) {
+                List<CompanyUser> deptUsers = allUsersByDeptIdMap.get(dept.getDeptId());
+                if (deptUsers != null && !deptUsers.isEmpty()) {
+                    for (CompanyUser user : deptUsers) {
+                        // 如果是当前部门,只显示当前用户
+                        if (dept.getDeptId().equals(currentDeptId)) {
+                            if (user.getUserId().equals(currentCompanyUserId)) {
+                                DeptDataVO userNode = new DeptDataVO();
+                                userNode.setLabel(user.getNickName() + "_" + user.getUserName());
+                                userNode.setId(user.getUserId());
+                                userNode.setChildren(null);
+                                userNodes.add(userNode);
+                            }
+                        } else {
+                            // 非当前部门,显示所有用户
+                            DeptDataVO userNode = new DeptDataVO();
+                            userNode.setLabel(user.getNickName() + "_" + user.getUserName());
+                            userNode.setId(user.getUserId());
+                            userNode.setChildren(null);
+                            userNodes.add(userNode);
+                        }
+                    }
+                }
+            }
+
+            // 将用户节点添加到子节点列表
+            if (!userNodes.isEmpty()) {
+                children.addAll(userNodes);
+            }
+            // 只有当下面有子部门或者有用户时,才添加此部门
+            if (!children.isEmpty()) {
+                DeptDataVO deptNode = new DeptDataVO();
+                deptNode.setLabel(dept.getDeptName());
+                deptNode.setId(dept.getDeptId());
+                deptNode.setChildren(children);
+                result.add(deptNode);
+            } else if (deptPath.contains(dept.getDeptId())) {
+                // 即使没有子部门和用户,如果是部门路径上的节点,仍然需要添加
+                DeptDataVO deptNode = new DeptDataVO();
+                deptNode.setLabel(dept.getDeptName());
+                deptNode.setId(dept.getDeptId());
+                deptNode.setChildren(null);
+                result.add(deptNode);
+            }
+        }
+        return result;
+    }
+    /**
+     * 获取用户按部门ID分组
+     */
+    public Map<Long, List<CompanyUser>> getCompanyUserGroupByDeptId() {
+        List<CompanyUser> userList = companyUserMapper.selectAllCompanyUserList();
+        return userList.stream()
+                .filter(user -> user.getDeptId() != null)
+                .collect(Collectors.groupingBy(CompanyUser::getDeptId));
+    }
+
+
+    /**
+     * 获取部门按公司ID分组
+     */
+    public Map<Long, List<CompanyDept>> getCompanyDeptGroupByCompanyId() {
+        List<CompanyDept> companyDepts = companyDeptMapper.queryDeptDataAll();
+        return companyDepts.stream()
+                .collect(Collectors.groupingBy(CompanyDept::getCompanyId));
+    }
+
+    /**
+     * 获取部门按父部门ID分组(新增方法)
+     */
+    public Map<Long, List<CompanyDept>> getDeptGroupByParentId() {
+        List<CompanyDept> companyDepts = companyDeptMapper.queryDeptDataAll();
+        return companyDepts.stream()
+                .filter(dept -> dept.getParentId() != null) // 过滤掉顶级部门
+                .collect(Collectors.groupingBy(CompanyDept::getParentId));
+    }
+
+    /**
+     * 构建公司节点,包含其下属多级部门和用户
+     */
+    private DeptDataVO buildCompanyNode(Company company,
+                                        Map<Long, List<CompanyUser>> companyUserGroupByDeptId,
+                                        Map<Long, List<CompanyDept>> companyDeptGroupByCompanyId,
+                                        Map<Long, List<CompanyDept>> deptGroupByParentId) {
+        DeptDataVO companyNode = new DeptDataVO();
+        companyNode.setLabel(company.getCompanyName());
+        companyNode.setId(company.getCompanyId());
+
+        // 获取公司下的顶级部门(parentId为null或为公司ID的部门)
+        List<CompanyDept> topLevelDepts = companyDeptGroupByCompanyId.get(company.getCompanyId());
+        if (topLevelDepts != null) {
+            topLevelDepts = topLevelDepts.stream()
+                    .filter(dept -> dept.getParentId() == null || dept.getParentId().equals(0L))
+                    .collect(Collectors.toList());
+        }
+
+        List<DeptDataVO> deptDataList = buildDeptTree(topLevelDepts, companyUserGroupByDeptId, deptGroupByParentId);
+        companyNode.setChildren(deptDataList.isEmpty() ? null : deptDataList);
+
+        return companyNode;
+    }
+
+    /**
+     * 构建公司节点,包含其下属多级部门和用户
+     */
+    private DeptDataVO buildCompanyNode(Company company,
+                                        Map<Long, List<CompanyUser>> companyUserGroupByDeptId,
+                                        Map<Long, List<CompanyDept>> companyDeptGroupByCompanyId,
+                                        Map<Long, List<CompanyDept>> deptGroupByParentId,
+                                        Long currentDeptId,
+                                        Long currentCompanyUserId
+                                        ) {
+        DeptDataVO companyNode = new DeptDataVO();
+        companyNode.setLabel(company.getCompanyName());
+        companyNode.setId(company.getCompanyId());
+
+        // 获取公司下的顶级部门(parentId为null或为公司ID的部门)
+        List<CompanyDept> topLevelDepts = companyDeptGroupByCompanyId.get(company.getCompanyId());
+        if (topLevelDepts != null) {
+            topLevelDepts = topLevelDepts.stream()
+                    .filter(dept -> dept.getParentId() == null || dept.getParentId().equals(0L))
+                    .collect(Collectors.toList());
+        }
+
+        List<DeptDataVO> deptDataList = buildDeptTree(topLevelDepts, companyUserGroupByDeptId, deptGroupByParentId,currentDeptId,currentCompanyUserId);
+        companyNode.setChildren(deptDataList.isEmpty() ? null : deptDataList);
+
+        return companyNode;
+    }
+
+    /**
+     * 递归构建部门树
+     */
+    private List<DeptDataVO> buildDeptTree(List<CompanyDept> depts,
+                                           Map<Long, List<CompanyUser>> companyUserGroupByDeptId,
+                                           Map<Long, List<CompanyDept>> deptGroupByParentId) {
+        if (depts == null || depts.isEmpty()) {
+            return new ArrayList<>();
+        }
+
+        List<DeptDataVO> result = new ArrayList<>();
+
+        for (CompanyDept dept : depts) {
+            DeptDataVO deptNode = new DeptDataVO();
+            deptNode.setLabel(dept.getDeptName());
+            deptNode.setId(dept.getDeptId());
+
+            List<DeptDataVO> children = new ArrayList<>();
+
+            // 1. 添加子部门(递归)
+            List<CompanyDept> childDepts = deptGroupByParentId.get(dept.getDeptId());
+            if (childDepts != null && !childDepts.isEmpty()) {
+                List<DeptDataVO> childDeptNodes = buildDeptTree(childDepts, companyUserGroupByDeptId, deptGroupByParentId);
+                children.addAll(childDeptNodes);
+            }
+
+            // 2. 添加部门下的用户
+            List<CompanyUser> deptUsers = companyUserGroupByDeptId.get(dept.getDeptId());
+            if (deptUsers != null && !deptUsers.isEmpty()) {
+                for (CompanyUser user : deptUsers) {
+                    DeptDataVO userNode = new DeptDataVO();
+                    userNode.setLabel(user.getNickName()+"_"+user.getUserName());
+                    userNode.setId(user.getUserId());
+                    userNode.setChildren(null);
+                    children.add(userNode);
+                }
+            }
+
+            deptNode.setChildren(children.isEmpty() ? null : children);
+            result.add(deptNode);
+        }
+
+        return result;
+    }
+    /**
+     * 递归构建部门树
+     */
+    /**
+     *
+     * @param depts
+     * @param companyUserGroupByDeptId
+     * @param deptGroupByParentId
+     * @param currentDeptId 当前部门id
+     * @param currentCompanyUserId 当前销售id
+     * @return
+     */
+    private List<DeptDataVO> buildDeptTree(List<CompanyDept> depts,
+                                           Map<Long, List<CompanyUser>> companyUserGroupByDeptId,
+                                           Map<Long, List<CompanyDept>> deptGroupByParentId,
+                                           Long currentDeptId,
+                                           Long currentCompanyUserId) {
+        if (depts == null || depts.isEmpty()) {
+            return new ArrayList<>();
+        }
+
+        List<DeptDataVO> result = new ArrayList<>();
+
+        for (CompanyDept dept : depts) {
+            DeptDataVO deptNode = new DeptDataVO();
+            deptNode.setLabel(dept.getDeptName());
+            deptNode.setId(dept.getDeptId());
+
+            List<DeptDataVO> children = new ArrayList<>();
+
+            // 1. 添加子部门(递归)
+            List<CompanyDept> childDepts = deptGroupByParentId.get(dept.getDeptId());
+            if (childDepts != null && !childDepts.isEmpty()) {
+                List<DeptDataVO> childDeptNodes = buildDeptTree(childDepts, companyUserGroupByDeptId, deptGroupByParentId);
+                children.addAll(childDeptNodes);
+            }
+
+            // 2. 添加部门下的用户
+            List<CompanyUser> deptUsers = companyUserGroupByDeptId.get(dept.getDeptId());
+            if (deptUsers != null && !deptUsers.isEmpty()) {
+                for (CompanyUser user : deptUsers) {
+                    // 如果是销售当前部门,不显示同级其他销售
+                    if(ObjectUtils.equals(dept.getDeptId(),currentDeptId)) {
+                        if(ObjectUtils.equals(user.getUserId(),currentCompanyUserId)) {
+                            DeptDataVO userNode = new DeptDataVO();
+                            userNode.setLabel(user.getNickName()+"_"+user.getUserName());
+                            userNode.setId(user.getUserId());
+                            userNode.setChildren(null);
+                            children.add(userNode);
+                        }
+                    } else {
+                        DeptDataVO userNode = new DeptDataVO();
+                        userNode.setLabel(user.getNickName()+"_"+user.getUserName());
+                        userNode.setId(user.getUserId());
+                        userNode.setChildren(null);
+                        children.add(userNode);
+                    }
+                }
+            }
+
+            deptNode.setChildren(children.isEmpty() ? null : children);
+            result.add(deptNode);
+        }
+
+        return result;
+    }
+
     @Override
     @Transactional
     public void refundCompanyMoney(FsStoreOrder order) {
@@ -588,4 +1012,25 @@ public class CompanyServiceImpl implements ICompanyService
             companyMapper.updateCompany(company);
         }
     }
+
+    @Override
+    @Transactional
+    public void addRedPacketCompanyMoney(BigDecimal money, Long companyId) {
+        if(companyId!=null&&companyId>0){
+            Company company=companyMapper.selectCompanyByIdForUpdate(companyId);
+            if(company!=null){
+                logger.info("退回红包金额:"+money);
+                company.setMoney(company.getMoney().add(money));
+                companyMapper.updateCompany(company);
+                CompanyMoneyLogs log=new CompanyMoneyLogs();
+                log.setCompanyId(company.getCompanyId());
+                log.setRemark("退回红包金额");
+                log.setMoney(money);
+                log.setLogsType(16);
+                log.setBalance(company.getMoney());
+                log.setCreateTime(new Date());
+                moneyLogsMapper.insertCompanyMoneyLogs(log);
+            }
+        }
+    }
 }

+ 7 - 1
fs-service/src/main/java/com/fs/company/service/impl/CompanyTagUserServiceImpl.java

@@ -117,8 +117,14 @@ public class CompanyTagUserServiceImpl implements ICompanyTagUserService
                 keywords = param.getKeyword().split(",");
             }
         }
+        // 判断是否是管理员
+        Long companyId = null;
+        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(param != null ? param.getUserId() : null);
+        if (companyUser != null && companyUser.isAdmin()){
+            companyId = companyUser.getCompanyId();
+        }
         //获取所有销售
-        List<CompanyUser> companyUsers = companyUserMapper.selectAllCompanyUserAndSelf(param != null ? param.getUserId() : null,null);
+        List<CompanyUser> companyUsers = companyUserMapper.selectAllCompanyUserAndSelf(param != null ? param.getUserId() : null, companyId);
         List<Long> userIds = Collections.emptyList();
         if(companyUsers != null && !companyUsers.isEmpty()){
             userIds = companyUsers.stream().map(CompanyUser::getUserId).collect(Collectors.toList());

+ 22 - 0
fs-service/src/main/java/com/fs/company/vo/DeptDataVO.java

@@ -0,0 +1,22 @@
+package com.fs.company.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class DeptDataVO implements Serializable {
+    /**
+     * 节点名称
+     */
+    private String label;
+    /**
+     * 节点id
+     */
+    private Long id;
+    /**
+     * 子节点
+     */
+    private List<DeptDataVO> children;
+}

+ 3 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseAnswerLogs.java

@@ -66,4 +66,7 @@ public class FsCourseAnswerLogs extends BaseEntity {
     private String questionJson;
 
     private Long watchLogId;//绑定观看的记录id
+
+    /** 营期id */
+    private Long periodId;
 }

+ 1 - 1
fs-service/src/main/java/com/fs/course/domain/FsCourseRealLink.java

@@ -42,5 +42,5 @@ public class FsCourseRealLink implements Serializable
     @ApiModelProperty(value = "营期课程id")
     private Long id;
 
-
+    private String chatId;
 }

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

@@ -57,4 +57,6 @@ public class FsCourseRedPacketLog extends BaseEntity
     /** 营期id */
     private Long periodId;
 
+    private String result;
+
 }

+ 1 - 1
fs-service/src/main/java/com/fs/course/mapper/FsCourseLinkMapper.java

@@ -68,7 +68,7 @@ public interface FsCourseLinkMapper
      */
     public int deleteFsCourseLinkByLinkIds(Long[] linkIds);
 
-    @Select("select link, real_link, update_time,company_user_id from fs_course_link where link = #{suffix} order by link_id desc limit 1 ")
+    @Select("select link, real_link,chat_id, update_time,company_user_id from fs_course_link where link = #{suffix} order by link_id desc limit 1 ")
     FsCourseLink selectFsCourseLinkByLink(@Param("suffix") String suffix);
 
     void insertFsCourseLinkBatch(@Param("courseLinks")List<FsCourseLink> courseLinkToInsert);

+ 13 - 1
fs-service/src/main/java/com/fs/course/mapper/FsCourseRedPacketLogMapper.java

@@ -127,7 +127,7 @@ public interface FsCourseRedPacketLogMapper
             "</script>"})
     List<FsCourseRedPacketLogListPVO> selectFsCourseRedPacketLogListVO(@Param("maps")FsCourseRedPacketLogParam fsCourseRedPacketLog);
 
-    @Select("SELECT company_id,sum(amount) as money from fs_course_red_packet_log  WHERE status = 1 and  DATE(create_time) = DATE_SUB(CURDATE(), INTERVAL 1 DAY) GROUP BY company_id")
+    @Select("SELECT company_id, SUM(amount) as money  FROM fs_course_red_packet_log    WHERE status in (0,1) and create_time >= DATE_SUB(CURDATE(), INTERVAL 1 DAY)   AND create_time < CURDATE()  GROUP BY company_id " )
     List<RedPacketMoneyVO> selectFsCourseRedPacketLogByCompany();
 
     List<FsCourseRedPacketLogListPVO> selectFsCourseRedPacketLogListVONew(FsCourseRedPacketLogParam fsCourseRedPacketLog);
@@ -144,4 +144,16 @@ public interface FsCourseRedPacketLogMapper
     int getCountByCompanyUserIdId(@Param("companyUserId") Long companyUserId);
 
     BigDecimal getNewVipRedPackAmountByCompanyUserIdId(@Param("companyUserId") Long companyUserId);
+
+    /**
+     * 查询红包金额数
+     * @param companyUserId 销售ID
+     * @return amount
+     */
+    @Select("select ifnull(sum(fcrpl.amount), 0) from fs_course_red_packet_log fcrpl where fcrpl.company_user_id = #{companyUserId}")
+    BigDecimal getSumByCompanyUserIdId(@Param("companyUserId") Long companyUserId);
+
+    @Select("SELECT company_id, SUM(amount) as money FROM fs_course_red_packet_log    WHERE status = 0 and create_time >= DATE_SUB(CURDATE(), INTERVAL 2 DAY)  AND create_time < DATE_SUB(CURDATE(), INTERVAL 1 DAY) GROUP BY company_id  ")
+    List<RedPacketMoneyVO> selectFsCourseAddRedPacketLogByCompany();
+
 }

+ 7 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java

@@ -396,4 +396,11 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
 
     @Select("select * from fs_course_watch_log where user_id = #{userId} and video_id = #{videoId} and send_type = 1")
     FsCourseWatchLog getCourseWatchLogByUser(@Param("userId") Long userId, @Param("videoId") Long videoId);
+
+    /**
+     * 根据条件查询条数
+     * @param params    参数
+     * @return  count
+     */
+    int countByMap(@Param("params") Map<String, Object> params);
 }

+ 1 - 0
fs-service/src/main/java/com/fs/course/param/FsCourseLinkRoomParam.java

@@ -14,5 +14,6 @@ public class FsCourseLinkRoomParam {
     private Long courseId;
 
     private String title;//视频标题
+    private String chatId;
 
 }

+ 1 - 0
fs-service/src/main/java/com/fs/course/param/FsCourseQuestionAnswerUParam.java

@@ -30,5 +30,6 @@ public class FsCourseQuestionAnswerUParam implements Serializable
     private Long duration;
     private Long qwExternalId;
     private List<FsCourseQuestionBank> questions;
+    private Long periodId;
 
 }

+ 2 - 0
fs-service/src/main/java/com/fs/course/param/FsUserCourseVideoAddKfUParam.java

@@ -61,5 +61,7 @@ public class FsUserCourseVideoAddKfUParam implements Serializable {
     private String link;
 
     private Integer isRoom;
+    private String chatId;
+    private String nickName;
 
 }

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

@@ -3,6 +3,8 @@ package com.fs.course.service;
 import com.fs.common.core.domain.R;
 import com.fs.course.domain.FsCourseLink;
 import com.fs.course.param.FsCourseLinkCreateParam;
+import com.fs.course.param.FsCourseLinkRoomParam;
+import com.fs.qw.domain.QwUser;
 
 import java.util.List;
 
@@ -79,4 +81,6 @@ public interface IFsCourseLinkService
     R createRoomLinkUrl(FsCourseLinkCreateParam param);
 
     R getRealLinkH5(String link);
+
+    R createRoomLink(FsCourseLinkRoomParam param, QwUser qwUser);
 }

+ 116 - 14
fs-service/src/main/java/com/fs/course/service/impl/FsCourseLinkServiceImpl.java

@@ -1,47 +1,51 @@
 package com.fs.course.service.impl;
 
-import cn.hutool.core.util.IdUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.alibaba.fastjson.JSONObject;
 import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.PubFun;
 import com.fs.common.utils.StringUtils;
-import com.fs.company.domain.CompanyUser;
+import com.fs.common.utils.date.DateUtil;
 import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.config.cloud.CloudHostProper;
 import com.fs.course.config.CourseConfig;
-import com.fs.course.domain.FsCourseDomainName;
-import com.fs.course.domain.FsCourseLink;
-import com.fs.course.domain.FsCourseRealLink;
-import com.fs.course.domain.FsUserCourseVideo;
+import com.fs.course.domain.*;
 import com.fs.course.mapper.FsCourseDomainNameMapper;
 import com.fs.course.mapper.FsCourseLinkMapper;
+import com.fs.course.mapper.FsCourseWatchLogMapper;
 import com.fs.course.mapper.FsUserCourseVideoMapper;
 import com.fs.course.param.FsCourseLinkCreateParam;
-import com.fs.course.service.IFsCourseDomainNameService;
+import com.fs.course.param.FsCourseLinkRoomParam;
 import com.fs.course.service.IFsCourseLinkService;
+import com.fs.course.service.IFsUserCourseService;
+import com.fs.qw.domain.QwGroupChat;
+import com.fs.qw.domain.QwGroupChatUser;
 import com.fs.qw.domain.QwUser;
+import com.fs.qw.mapper.QwExternalContactMapper;
 import com.fs.qw.mapper.QwUserMapper;
+import com.fs.qw.service.IQwGroupChatService;
+import com.fs.qw.service.IQwGroupChatUserService;
+import com.fs.qw.vo.GroupUserExternalVo;
 import com.fs.system.service.ISysConfigService;
 import com.fs.voice.utils.StringUtil;
 import lombok.Synchronized;
 import lombok.extern.slf4j.Slf4j;
-import org.checkerframework.checker.units.qual.A;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.io.UnsupportedEncodingException;
-import java.net.URI;
 import java.net.URLDecoder;
-import java.security.SecureRandom;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
 import java.util.*;
 
 import static com.fs.course.utils.LinkUtil.generateRandomStringWithLock;
+import static com.fs.sop.service.impl.SopUserLogsInfoServiceImpl.convertStringToDate;
 
 /**
  * 短链Service业务层处理
@@ -60,6 +64,21 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
 
     @Autowired
     private FsCourseDomainNameMapper fsCourseDomainNameMapper;
+
+    @Autowired
+    private FsCourseWatchLogMapper fsCourseWatchLogMapper;
+
+    @Autowired
+    private QwExternalContactMapper qwExternalContactMapper;
+
+    @Autowired
+    private IFsUserCourseService fsUserCourseService;
+
+    @Autowired
+    private IQwGroupChatService qwGroupChatService;
+
+    @Autowired
+    private IQwGroupChatUserService qwGroupChatUserService;
     @Autowired
     private QwUserMapper qwUserMapper;
     @Autowired
@@ -202,7 +221,7 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
     }
 
     @Override
-    public R createRoomLinkUrl(FsCourseLinkCreateParam param) {
+    public R  createRoomLinkUrl(FsCourseLinkCreateParam param) {
 //        QwUser qwUser;
 //        if(param.getQwUserId() != null){
 //            qwUser = qwUserMapper.selectById(param.getQwUserIdLong());
@@ -216,13 +235,15 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
         BeanUtils.copyProperties(param,link);
         link.setLinkType(0);
         link.setIsRoom(1);
+        String randomString = generateRandomString();
+        link.setLink(randomString);
+        link.setChatId(param.getChatId());
+
         FsCourseRealLink courseMap = new FsCourseRealLink();
         BeanUtils.copyProperties(link,courseMap);
         // 将实体类对象转换为 JSON 字符串
         String course = JSON.toJSONString(courseMap);
         link.setRealLink(realLink+course);
-        String randomString = generateRandomString();
-        link.setLink(randomString);
         link.setCreateTime(new Date());
         Integer expireDays = 0;
         if (param.getDays() == null || param.getDays() == 0){
@@ -238,6 +259,7 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
         if (fsCourseLinkMapper.insertFsCourseLink(link)>0){
             String domainName = getDomainName(param.getCompanyUserId(), config);
             String sortLink = domainName + shortLink + link.getLink();
+
             return R.ok("短链生成").put("url",sortLink);
         }
         return R.error("短链生成失败!");
@@ -559,4 +581,84 @@ public class FsCourseLinkServiceImpl implements IFsCourseLinkService
             return R.error("发生未知错误,请稍后再试").put("realLink", link);
         }
     }
+
+    @Override
+    public R createRoomLink(FsCourseLinkRoomParam param, QwUser qwUser) {
+        FsCourseLinkCreateParam createParam = new FsCourseLinkCreateParam();
+        createParam.setCourseId(param.getCourseId());
+        createParam.setVideoId(param.getVideoId());
+        createParam.setCorpId(param.getCorpId());
+        createParam.setCompanyUserId(qwUser.getCompanyUserId());
+        createParam.setCompanyId(qwUser.getCompanyId());
+        createParam.setQwUserId(qwUser.getId());
+        createParam.setChatId(param.getChatId());
+        String linkUrl;
+        R createLink = createRoomLinkUrl(createParam);
+        if (createLink.get("code").equals(500)){
+            return R.error("链接生成失败!");
+        }
+
+        QwGroupChat groupChat = qwGroupChatService.selectQwGroupChatByChatId(param.getChatId());
+        List<QwGroupChatUser> qwGroupChatUserList = qwGroupChatUserService.selectQwGroupChatUserByChatIds(new String[]{param.getChatId()});
+        List<String> groupChatUserIds = PubFun.listToNewList(qwGroupChatUserList, QwGroupChatUser::getUserId);
+        if(!groupChatUserIds.isEmpty()){
+            List<GroupUserExternalVo> userList = qwExternalContactMapper.selectByGroupUser(groupChatUserIds);
+            Map<String, List<GroupUserExternalVo>> userMap = PubFun.listToMapByGroupList(userList, GroupUserExternalVo::getExternalUserId);
+            qwGroupChatUserList.forEach(e -> {
+                e.setUserList(userMap.getOrDefault(e.getUserId(), Collections.emptyList()));
+            });
+        }
+        try {
+            qwGroupChatUserList.stream().filter(e -> e.getUserList() != null && !e.getUserList().isEmpty()).forEach(e -> {
+                Map<String, GroupUserExternalVo> userMap = PubFun.listToMapByGroupObject(e.getUserList(), GroupUserExternalVo::getUserId);
+                GroupUserExternalVo vo = userMap.get(groupChat.getOwner());
+                if (vo != null && vo.getId() != null) {
+                    addWatchLogIfNeeded(param.getVideoId(), param.getCourseId(), vo.getFsUserId(), qwUser.getId(), qwUser.getCompanyUserId(), qwUser.getCompanyId(), vo.getId(), new Date(), new Date());
+                }
+            });
+        } catch (Exception e) {
+            log.error("群聊创建看课记录失败!", e);
+        }
+
+        linkUrl = (String) createLink.get("url");
+
+        FsUserCourse course = fsUserCourseService.selectFsUserCourseByCourseId(param.getCourseId());
+
+        JSONObject news = new JSONObject(true); // true 表示保持字段顺序
+        news.put("link", linkUrl);
+        news.put("title", course.getCourseName());
+        news.put("desc", param.getTitle()==null?"":param.getTitle());
+        news.put("imgUrl", course.getImgUrl());
+        return R.ok().put("news",news);
+    }
+
+
+    private void addWatchLogIfNeeded(Long videoId, Long courseId,
+                                     Long fsUserId, Long qwUserId, Long companyUserId,
+                                     Long companyId, Long externalId, Date startTime,Date createTime) {
+
+        try {
+            FsCourseWatchLog watchLog = new FsCourseWatchLog();
+            watchLog.setVideoId(videoId);
+            watchLog.setQwExternalContactId(externalId);
+            watchLog.setSendType(2);
+            watchLog.setQwUserId(qwUserId);
+            watchLog.setDuration(0L);
+            watchLog.setCourseId(courseId);
+            watchLog.setCompanyUserId(companyUserId);
+            watchLog.setCompanyId(companyId);
+            watchLog.setCreateTime(createTime);
+            watchLog.setUpdateTime(createTime);
+            watchLog.setLogType(3);
+            watchLog.setUserId(fsUserId);
+            watchLog.setCampPeriodTime(startTime);
+            //存看课记录
+            fsCourseWatchLogMapper.insertOrUpdateFsCourseWatchLog(watchLog);
+        }catch (Exception e){
+            log.error("一键群发失败-插入观看记录失败:"+e.getMessage());
+        }
+
+    }
+
+
 }

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

@@ -230,6 +230,7 @@ public class FsCourseQuestionBankServiceImpl implements IFsCourseQuestionBankSer
         logs.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null );
         logs.setQuestionJson(JSONObject.toJSONString(param.getQuestions()));
         logs.setCreateTime(new Date());
+        logs.setPeriodId(param.getPeriodId());
 
         if (thisRightCount == param.getQuestions().size()) {
             logs.setIsRight(1);

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

@@ -122,9 +122,14 @@ public class FsCourseRedPacketLogServiceImpl implements IFsCourseRedPacketLogSer
         return fsCourseRedPacketLogMapper.selectFsCourseRedPacketLogListVONew(fsCourseRedPacketLog);
     }
 
+    /**
+     * 查询红包金额数
+     * @param companyUserId 销售ID
+     * @return amount
+     */
     @Override
     public BigDecimal getSumByCompanyUserIdId(Long companyUserId) {
-        return null;
+        return fsCourseRedPacketLogMapper.getSumByCompanyUserIdId(companyUserId);
     }
 
     @Override

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

@@ -345,7 +345,7 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
 
     @Override
     public int countByMap(Map<String, Object> params) {
-        return 0;
+        return baseMapper.countByMap(params);
     }
 
     @Override

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

@@ -105,7 +105,8 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
     @Autowired
     private RedisCache redisCache;
     private static final String realLink = "/courseH5/pages/course/learning?course=";
-    private static final String shortLink = "/courseH5/pages/course/learning?s=";
+    public static final String shortLink = "/courseH5/pages/course/learning?s=";
+
     private static final String userRealLink = "/pages/user/users/becomeVIP?";
     /**
      * 查询课程

+ 165 - 50
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -17,8 +17,10 @@ import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.date.DateUtil;
 import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyMoneyLogs;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.mapper.CompanyMapper;
+import com.fs.company.mapper.CompanyMoneyLogsMapper;
 import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.*;
@@ -51,6 +53,7 @@ import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.service.IQwCompanyService;
 import com.fs.qw.service.IQwExternalContactService;
 import com.fs.qwApi.Result.QwAddContactWayResult;
+import com.fs.qwApi.Result.QwGroupChatDetailsResult;
 import com.fs.qwApi.param.QwAddContactWayParam;
 import com.fs.qwApi.service.QwApiService;
 import com.fs.repeat.vo.RepeatUploadVo;
@@ -59,6 +62,7 @@ import com.fs.sop.mapper.SopUserLogsInfoMapper;
 import com.fs.sop.service.ISopUserLogsInfoService;
 import com.fs.system.service.ISysConfigService;
 import com.fs.voice.utils.StringUtil;
+import com.fs.wx.cp.config.WxCpProperties;
 import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
@@ -72,6 +76,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.net.SocketTimeoutException;
 import java.time.Instant;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
@@ -98,7 +103,8 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     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=";
-
+    @Autowired
+    private CompanyMoneyLogsMapper moneyLogsMapper;
     @Autowired
     private FsUserCourseVideoMapper fsUserCourseVideoMapper;
     @Autowired
@@ -391,7 +397,6 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     }
 
     @Override
-    @Transactional
     public R isAddKf(FsUserCourseVideoAddKfUParam param) {
         logger.info("zyp \n【判断添加客服】:{}",param);
         //查询用户
@@ -433,35 +438,103 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     }
 
     private R handleRoom(FsUserCourseVideoAddKfUParam param,FsUser user) {
-        //查询客户列表
-        List<QwExternalContact> contacts = qwExternalContactMapper.selectQwExternalContactListVOByfsUserId(user.getUserId());
-        if (contacts.isEmpty()){
-            return R.error("未注册");
-        }
-        //找出对应销售匹配的客户
-        QwExternalContact matchedContact = contacts.stream()
-                .filter(contact -> contact.getQwUserId().equals(Long.parseLong(param.getQwUserId())))
-                .findFirst()
-                .orElse(null);
-
-        if (matchedContact==null){
-            return R.error("无权限观看,未添加本群主");
-        }
-
-        param.setQwExternalId(matchedContact.getId());
-//        //查询是否有添加客服
-//        QwExternalContact externalContact = qwExternalContactMapper.selectQwExternalContactById(param.getQwExternalId());
-//        if (externalContact==null){
-//            return R.error("客户不存在!");
+//        //查询客户列表
+//        List<QwExternalContact> contacts = qwExternalContactMapper.selectQwExternalContactListVOByfsUserId(user.getUserId());
+//        if (contacts.isEmpty()){
+//            return R.error("未注册");
+//        }
+//        //找出对应销售匹配的客户
+//        QwExternalContact matchedContact = contacts.stream()
+//                .filter(contact -> contact.getQwUserId().equals(Long.parseLong(param.getQwUserId())))
+//                .findFirst()
+//                .orElse(null);
+//
+//        if (matchedContact==null){
+//            return R.error("无权限观看,未添加本群主");
 //        }
-//        if (!externalContact.getQwUserId().equals(param.getUserId())){
-//            return R.error("无权限观看,添加群主非本群主");
+//
+//        param.setQwExternalId(matchedContact.getId());
+////        //查询是否有添加客服
+////        QwExternalContact externalContact = qwExternalContactMapper.selectQwExternalContactById(param.getQwExternalId());
+////        if (externalContact==null){
+////            return R.error("客户不存在!");
+////        }
+////        if (!externalContact.getQwUserId().equals(param.getUserId())){
+////            return R.error("无权限观看,添加群主非本群主");
+////        }
+//        FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideoByExt(param.getQwExternalId(), param.getVideoId(),param.getQwUserId());
+//        if (log==null){
+//            createWatchLog(param);
 //        }
-        FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideoByExt(param.getQwExternalId(), param.getVideoId(),param.getQwUserId());
-        if (log==null){
-            createWatchLog(param);
+//        return R.ok().put("qwExternalId",matchedContact.getId());
+        FsCourseLink courseLink = courseLinkMapper.selectFsCourseLinkByLink(param.getLink());
+        System.out.println("查询的链接参数"+courseLink);
+        String msg = "<div style=\"color: red;margin-bottom: 15px;font-weight: bold;\">本课程为群会员独享<br>请长按二维码</div>\n" +
+                "\t\t\t\t\t<div style=\"color: #999;font-size: 14px;font-weight: bold;\">添加伴学助手免费领取会员权限</div>";
+        System.out.println("企微传参:"+courseLink.getChatId()+"corpId:"+param.getCorpId());
+        QwGroupChatDetailsResult result = qwApiService.groupChatDetails(courseLink.getChatId(), param.getCorpId());
+        if(result.getErrCode() != 0){
+            return R.error("企微接口请求失败,请联系管理员:" +result.getErrMsg());
+        }
+        List<QwGroupChatDetailsResult.Member> collect = result.getGroupChat().getMemberList().stream().filter(e -> e.getType() == 2).collect(Collectors.toList());
+        if(collect.isEmpty()){
+            return addCustomerService(param.getQwUserId(),msg);
+        }
+        Optional<QwGroupChatDetailsResult.Member> optional = collect.stream().filter(e -> e.getName().equals(user.getNickName()) || e.getName().equals(param.getNickName())).findFirst();
+        if(!optional.isPresent()){
+            return addCustomerService(param.getQwUserId(),msg);
+        }
+        QwGroupChatDetailsResult.Member member = optional.get();
+        QwExternalContact qwExternalContact = qwExternalContactMapper.selectOne(new QueryWrapper<QwExternalContact>().eq("user_id", result.getGroupChat().getOwner()).eq("external_user_id", member.getUserId()));
+        if(qwExternalContact==null){
+            return addCustomerService(param.getQwUserId(),msg);
         }
-        return R.ok().put("qwExternalId",matchedContact.getId());
+        Long qwExternalId = qwExternalContact.getId();
+        log.info("外部联系人数据:{}", qwExternalContact);
+//        addCompanyCompanyFsUser(param);
+        FsCourseWatchLog log = courseWatchLogMapper.getWatchCourseVideoByExt(qwExternalId, param.getVideoId(),param.getQwUserId());
+        if (log==null ){
+            return addCustomerService(param.getQwUserId(),msg);
+        }
+        //判断外部联系人有没有绑定userId
+        if (qwExternalContact.getFsUserId()!=null){
+            //有客户有小程序id  但 登录的小程序id和根据外部联系人id查出来的小程序id不一致
+            if (!qwExternalContact.getFsUserId().equals(param.getUserId())) {
+                return addCustomerService(param.getQwUserId(),msg);
+            }
+            List<QwExternalContact> qwExternalContacts = qwExternalContactMapper.selectQwExternalContactByMiniUserId(param.getUserId());
+            //匹配客户公司id
+            if (qwExternalContacts.stream().noneMatch(contact -> contact.getCorpId().equals(param.getCorpId()))){
+                return addCustomerService(param.getQwUserId(),msg);
+            }
+
+            //看课记录中userId为0绑定userId
+            if (log.getUserId()==null||log.getUserId().equals(0L) || !log.getUserId().equals(param.getUserId())){
+                log.setUserId(param.getUserId());
+            }
+
+            log.setUpdateTime(new Date());
+            courseWatchLogMapper.updateFsCourseWatchLog(log);
+
+            iSopUserLogsInfoService.updateSopUserInfoByExternalId(qwExternalId,param.getUserId());
+        }else {
+            //没绑定fsUser直接绑定fsUser
+            QwExternalContact contact = new QwExternalContact();
+            contact.setId(qwExternalId);
+            contact.setFsUserId(param.getUserId());
+            qwExternalContactMapper.updateQwExternalContact(contact);
+            FsUser fsUser = new FsUser();
+            fsUser.setUserId(user.getUserId());
+            fsUser.setIsAddQw(1);
+            fsUserMapper.updateFsUser(fsUser);
+            //绑定上之后 更新观看记录
+            //看课记录中userId为0绑定userId
+            log.setUserId(param.getUserId());
+            log.setUpdateTime(new Date());
+            courseWatchLogMapper.updateFsCourseWatchLog(log);
+        }
+
+        return R.ok().put("qwExternalId", qwExternalContact.getId());
     }
 
     private void createWatchLog(FsUserCourseVideoAddKfUParam param) {
@@ -525,7 +598,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 //        }
 
         //查询是否有添加客服
-        QwExternalContact externalContact = qwExternalContactMapper.selectQwExternalContactById(param.getQwExternalId());
+        QwExternalContact externalContact = qwExternalContactMapper.selectQwExternalContactById(qwExternalId);
 
         //用小程序id查询外部联系人
         List<QwExternalContact> qwExternalContacts = qwExternalContactMapper.selectQwExternalContactByMiniUserId(param.getUserId());
@@ -756,21 +829,28 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         FsCourseWatchLog log = new FsCourseWatchLog();
 
         // 根据链接类型判断是否已发放奖励
-        if (param.getLinkType() != null && param.getLinkType() == 1) {
+        log = courseWatchLogMapper.getWatchCourseVideo(param.getUserId(), param.getVideoId(), param.getQwUserId(), param.getQwExternalId());
+        if (log == null) {
+            return R.error("无记录");
+        }
+        if (log.getRewardType() != null) {
             FsCourseRedPacketLog packetLog = redPacketLogMapper.selectFsCourseRedPacketLogByTemporary(param.getVideoId(), param.getUserId());
-            if (packetLog != null) {
+            if(packetLog != null && packetLog.getStatus() == 1) {
                 return R.error("奖励已发放");
             }
-        } else {
-            log = courseWatchLogMapper.getWatchCourseVideo(param.getUserId(), param.getVideoId(), param.getQwUserId(), param.getQwExternalId());
-            if (log == null) {
-                return R.error("无记录");
+            if(packetLog != null && packetLog.getStatus() == 0) {
+                if(StringUtils.isNotEmpty(packetLog.getResult())){
+                    R r = JSON.parseObject(packetLog.getResult(), R.class);
+                    return r;
+                } else {
+                    return R.error("奖励已发放");
+                }
             }
-            if (log.getRewardType() != null) {
-                return R.error("奖励已发放");
+            if(packetLog != null && packetLog.getStatus() == 2) {
+                return R.error("请联系客服补发");
             }
+            return R.error("奖励已发放");
         }
-
         // 获取视频信息
         FsUserCourseVideo video = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(param.getVideoId());
 
@@ -838,18 +918,22 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
      */
     private R sendRedPacketReward(FsCourseSendRewardUParam param, FsUser user, FsCourseWatchLog log, FsUserCourseVideo video, CourseConfig config) {
         // 判断是否属于领取红包时间(会员看课发放红包)
-        FsUserCoursePeriodDays periodDays = new FsUserCoursePeriodDays();
-        periodDays.setVideoId(param.getVideoId());
-        periodDays.setPeriodId(param.getPeriodId());
-        //正常情况是只能查询到一条,之前可能存在重复的脏数据,暂使用查询list的方式
-        List<FsUserCoursePeriodDays> fsUserCoursePeriodDays = fsUserCoursePeriodDaysMapper.selectFsUserCoursePeriodDaysList(periodDays);
-        if(fsUserCoursePeriodDays != null && !fsUserCoursePeriodDays.isEmpty()){
-            periodDays = fsUserCoursePeriodDays.get(0);
+        if (param.getPeriodId()!=null && param.getPeriodId()>0) {
+            FsUserCoursePeriodDays periodDays = new FsUserCoursePeriodDays();
+            periodDays.setVideoId(param.getVideoId());
+            periodDays.setPeriodId(param.getPeriodId());
+            //正常情况是只能查询到一条,之前可能存在重复的脏数据,暂使用查询list的方式
+            List<FsUserCoursePeriodDays> fsUserCoursePeriodDays = fsUserCoursePeriodDaysMapper.selectFsUserCoursePeriodDaysList(periodDays);
+            if(fsUserCoursePeriodDays != null && !fsUserCoursePeriodDays.isEmpty()){
+                periodDays = fsUserCoursePeriodDays.get(0);
+            }
+            if(periodDays != null && periodDays.getLastJoinTime() !=null && LocalDateTime.now().isAfter(periodDays.getLastJoinTime())) {
+                return R.error(403,"已超过领取红包时间");
+            }
         }
 
-        if(periodDays != null && periodDays.getLastJoinTime() !=null && LocalDateTime.now().isAfter(periodDays.getLastJoinTime())) {
-            return R.error(403,"已超过领取红包时间");
-        }
+
+
 
         // 确定红包金额
         BigDecimal amount = BigDecimal.ZERO;
@@ -879,6 +963,26 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         System.out.println("红包商户号"+packetParam);
         //2025.6.19 红包金额为0的时候
         if (amount.compareTo(BigDecimal.ZERO)>0){
+
+            Company company = companyMapper.selectCompanyByIdForUpdate(param.getCompanyId());
+            BigDecimal money = company.getMoney();
+            BigDecimal subtract = money.subtract(amount);
+            if (subtract.compareTo(BigDecimal.ZERO)<0){
+                FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
+                redPacketLog.setCourseId(param.getCourseId());
+                redPacketLog.setCompanyId(param.getCompanyId());
+                redPacketLog.setUserId(param.getUserId());
+                redPacketLog.setVideoId(param.getVideoId());
+                redPacketLog.setStatus(2);
+                redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
+                redPacketLog.setCompanyUserId(param.getCompanyUserId());
+                redPacketLog.setCreateTime(new Date());
+                redPacketLog.setAmount(amount);
+                redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
+                redPacketLog.setPeriodId(param.getPeriodId());
+                redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
+                return R.error("销售公司余额不足");
+            }
             // 发送红包
             R sendRedPacket = paymentService.sendRedPacket(packetParam);
             if (sendRedPacket.get("code").equals(200)) {
@@ -886,6 +990,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                 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());
@@ -906,10 +1011,20 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                 redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
 
                 // 更新观看记录的奖励类型
-//            if (param.getLinkType() == null || param.getLinkType() == 0) {
                 log.setRewardType(config.getRewardType());
                 courseWatchLogMapper.updateFsCourseWatchLog(log);
-//            }
+                company.setMoney(subtract);
+                companyMapper.updateCompany(company);
+
+                CompanyMoneyLogs logs=new CompanyMoneyLogs();
+                logs.setCompanyId(company.getCompanyId());
+                logs.setRemark("扣除红包金额");
+                logs.setMoney(amount.multiply(new BigDecimal(-1)));
+                logs.setLogsType(15);
+                logs.setBalance(company.getMoney());
+                logs.setCreateTime(new Date());
+                moneyLogsMapper.insertCompanyMoneyLogs(logs);
+
                 return sendRedPacket;
             } else {
                 return R.error("奖励发送失败,请联系客服");

+ 4 - 0
fs-service/src/main/java/com/fs/his/mapper/FsStoreOrderMapper.java

@@ -1081,4 +1081,8 @@ public interface FsStoreOrderMapper
             "</if>" +
             "</script>"})
     Integer selectFsStoreOrderCountByType(@Param("companyId") Long companyId,@Param("userId") long userId, @Param("type")int type);
+
+    @Select("select * from fs_store_order where  `status`=2 ")
+    List<FsStoreOrder> selectWdtOmsOrderdeliveryOp();
+
 }

+ 9 - 9
fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java

@@ -299,7 +299,7 @@ public interface FsUserMapper
     @Select("select * from fs_user where union_id=#{unionId}")
     FsUser selectFsUserByUnionId(String unionId);
 
-    List<UserListCountVO> getUserNumber(@Param("userId") Long userId);
+    List<UserListCountVO> getUserNumber(@Param("userId") Long userId, @Param("companyId") Long companyId);
 
     int getRepeatUserNumber(@Param("userId") Long userId);
 
@@ -309,9 +309,9 @@ public interface FsUserMapper
 
     UserDetailsVO getCountRedPacket(@Param("userId") Long userId, @Param("fsUserId") Long fsUserId, @Param("dateTag") String dateTag);
 
-    FsUserSummaryCountVO countUserSummary(@Param("userId") Long userId);
+    FsUserSummaryCountVO countUserSummary(@Param("userId") Long userId, @Param("companyId") Long companyId);
 
-    List<FsUserSummaryCountTagVO> countTag(@Param("userId") Long userId);
+    List<FsUserSummaryCountTagVO> countTag(@Param("userId") Long userId, @Param("companyId") Long companyId);
 
     Map<String, Long> countUserCourse(UserStatisticsCommonParam param);
 
@@ -319,21 +319,21 @@ public interface FsUserMapper
 
     Map<String, Long> countCourseDetails(UserStatisticsCommonParam param);
 
-    List<FsUserRankingVO> countUserRankingByComplete(@Param("userId") Long userId, @Param("startTime") String startTime, @Param("endTime") String endTime, @Param("periodId") String periodId, @Param("videoId") String videoId, @Param("order") String order);
+    List<FsUserRankingVO> countUserRankingByComplete(@Param("userId") Long userId, @Param("companyId") Long companyId, @Param("startTime") String startTime, @Param("endTime") String endTime, @Param("periodId")String periodId, @Param("videoId")String videoId, @Param("order")String order);
 
-    List<FsUserRankingVO> countUserRankingByRight(@Param("userId") Long userId, @Param("startTime") String startTime, @Param("endTime") String endTime, @Param("periodId") String periodId, @Param("videoId") String videoId, @Param("order") String order);
+    List<FsUserRankingVO> countUserRankingByRight(@Param("userId") Long userId, @Param("companyId") Long companyId, @Param("startTime") String startTime, @Param("endTime") String endTime, @Param("periodId")String periodId, @Param("videoId")String videoId, @Param("order")String order);
 
-    List<FsCourseRankingVO> countCourseRankingByComplete(@Param("userId") Long userId, @Param("startTime") String startTime, @Param("endTime") String endTime, @Param("periodId") String periodId, @Param("videoId") String videoId, @Param("order") String order);
+    List<FsCourseRankingVO> countCourseRankingByComplete(@Param("userId") Long userId, @Param("companyId") Long companyId, @Param("startTime") String startTime, @Param("endTime") String endTime, @Param("periodId")String periodId, @Param("videoId")String videoId, @Param("order")String order);
 
-    List<FsCourseRankingVO> countCourseRankingByRight(@Param("userId") Long userId, @Param("startTime") String startTime, @Param("endTime") String endTime, @Param("periodId") String periodId, @Param("videoId") String videoId, @Param("order") String order);
+    List<FsCourseRankingVO> countCourseRankingByRight(@Param("userId") Long userId, @Param("companyId") Long companyId, @Param("startTime") String startTime, @Param("endTime") String endTime, @Param("periodId")String periodId, @Param("videoId")String videoId, @Param("order")String order);
 
     Map<String, Object> countUserRedPacket(UserStatisticsCommonParam param);
 
     List<FsCourseAnalysisCountVO> courseAnalysisCourseCount(CourseAnalysisParam param);
 
-    CompanyUserSummaryCountVO companyUserCount(@Param("companyUserId") String companyUserId);
+    CompanyUserSummaryCountVO companyUserCount(@Param("companyUserId")String companyUserId, @Param("companyId") Long companyId);
 
-    CompanyUserSummaryCountVO newUserRedPacketCount(@Param("companyUserId") String companyUserId);
+    CompanyUserSummaryCountVO newUserRedPacketCount(@Param("companyUserId")String companyUserId, @Param("companyId") Long companyId);
 
 
     @Select("select * from fs_user where course_ma_open_id=#{openId}")

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

@@ -687,8 +687,8 @@ public class FsInquiryOrderServiceImpl implements IFsInquiryOrderService
                     BigDecimal money=order.getMoney();
                     order.setCompanyId(param.getCompanyId());
                     order.setCompanyUserId(param.getCompanyUserId());
-                    order.setMoney(new BigDecimal(0.1));
-                    order.setPayMoney(new BigDecimal(0.1));
+                    order.setMoney(new BigDecimal(0.0));
+                    order.setPayMoney(new BigDecimal(0.0));
                     order.setCompanyDeductMoney(money);
                     if (companyUser.getDeptId()!=null){
                         order.setDeptId(companyUser.getDeptId());

+ 5 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsPackageServiceImpl.java

@@ -121,6 +121,11 @@ public class FsPackageServiceImpl implements IFsPackageService {
                 fsPackage.setTotalCostPrice(toal.add(in));
             }
 //        }
+        //如果公域改私域 需要去掉disease_type值
+        Integer isShow = fsPackage.getIsShow();
+        if (isShow != null && isShow == 0) {
+            fsPackage.setDiseaseType(-1);
+        }
         return fsPackageMapper.updateFsPackage(fsPackage);
     }
 

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

@@ -1980,7 +1980,6 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
             return R.error("未生成管易云订单");
         }
         ErpOrderQueryRequert request = new ErpOrderQueryRequert();
-        request.setCode(order.getExtendOrderId());
 
         //判断是否开启erp
         FsSysConfig sysConfig = configUtil.getSysConfig();
@@ -1991,6 +1990,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService
             if (erpType != null){
 
                 IErpOrderService erpOrderService = null;
+                request.setCode(order.getExtendOrderId());
                 if (erpType == 1){
                     //管易
                     erpOrderService =  gyOrderService;

+ 57 - 9
fs-service/src/main/java/com/fs/his/service/impl/FsUserServiceImpl.java

@@ -535,6 +535,8 @@ public class FsUserServiceImpl implements IFsUserService
                 }
         }
 
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+
         List<FsUserPageListVO> fsUserPageListVOS = fsUserMapper.selectFsUserPageList(param);
         // 获取当前销售所有重粉会员
         List<FsUserCompanyUser> fsUserCompanyUsers = fsUserCompanyUserMapper.selectRepeatUser(param.getUserId());
@@ -700,7 +702,14 @@ public class FsUserServiceImpl implements IFsUserService
 
     @Override
     public UserListPageVO getUserNumber(Long userId) {
-        List<UserListCountVO> list = fsUserMapper.getUserNumber(userId);
+        // 判断是否是管理员
+        Long companyId = null;
+        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(userId);
+        if (companyUser != null && companyUser.isAdmin()){
+            userId = 0L;
+            companyId = companyUser.getCompanyId();
+        }
+        List<UserListCountVO> list = fsUserMapper.getUserNumber(userId, companyId);
         Map<String, Integer> map = list.stream()
                 .collect(Collectors.toMap(UserListCountVO::getStatus, UserListCountVO::getNum, (v1, v2) -> v1));
         UserListPageVO pageVO = new UserListPageVO();
@@ -744,8 +753,15 @@ public class FsUserServiceImpl implements IFsUserService
 
     @Override
     public FsUserSummaryCountVO userSummaryCount(Long userId) {
-        FsUserSummaryCountVO fsUserSummaryCountVO = fsUserMapper.countUserSummary(userId);
-        List<FsUserSummaryCountTagVO> countTagList = fsUserMapper.countTag(userId);
+        // 判断是否是管理员
+        Long companyId = null;
+        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(userId);
+        if (companyUser != null && companyUser.isAdmin()){
+            userId = 0L;
+            companyId = companyUser.getCompanyId();
+        }
+        FsUserSummaryCountVO fsUserSummaryCountVO = fsUserMapper.countUserSummary(userId, companyId);
+        List<FsUserSummaryCountTagVO> countTagList = fsUserMapper.countTag(userId, companyId);
         fsUserSummaryCountVO.setTagList(countTagList);
         return fsUserSummaryCountVO;
     }
@@ -759,6 +775,11 @@ public class FsUserServiceImpl implements IFsUserService
     public FsUserStatisticsVO userStatisticsDetails(UserStatisticsCommonParam param) {
         FsUserStatisticsVO userStatisticsVO = getUserStatistics(param);
 
+        // 判断是否是管理员
+        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(param.getUserId());
+        if (companyUser != null && companyUser.isAdmin()){
+            param.setUserId(0L);
+        }
         //统计课程数据详情,在查询统计详情的时候需要显示
         Map<String, Long> courseDetailsMap = fsUserMapper.countCourseDetails(param);
         if(courseDetailsMap != null && courseDetailsMap.get("courseNum") != null && courseDetailsMap.get("videoNum") != null && courseDetailsMap.get("courseUserNum") != null){
@@ -772,25 +793,39 @@ public class FsUserServiceImpl implements IFsUserService
     @Override
     public List<FsUserRankingVO> userRanking(Long userId, String startTime, String endTime, String periodId, String videoId, String order, Integer type) {
         List<FsUserRankingVO> listVO = Collections.emptyList();
+        // 判断是否是管理员
+        Long companyId = null;
+        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(userId);
+        if (companyUser != null && companyUser.isAdmin()){
+            userId = 0L;
+            companyId = companyUser.getCompanyId();
+        }
         if(type == 1){
             //按完播率
-            listVO = fsUserMapper.countUserRankingByComplete(userId, startTime, endTime, periodId, videoId, order);
+            listVO = fsUserMapper.countUserRankingByComplete(userId, companyId, startTime, endTime, periodId, videoId, order);
         }
         if(type == 2){
             //按正确率
-            listVO = fsUserMapper.countUserRankingByRight(userId, startTime, endTime, periodId, videoId, order);
+            listVO = fsUserMapper.countUserRankingByRight(userId, companyId, startTime, endTime, periodId, videoId, order);
         }
         return listVO;
     }
 
     @Override
     public List<FsCourseRankingVO> courseRanking(Long userId, String startTime, String endTime, String periodId, String videoId, String order, Integer type) {
+        // 判断是否是管理员
+        Long companyId = null;
+        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(userId);
+        if (companyUser != null && companyUser.isAdmin()){
+            userId = 0L;
+            companyId = companyUser.getCompanyId();
+        }
         List<FsCourseRankingVO> list = Collections.emptyList();
         if(type == 1){
-            list = fsUserMapper.countCourseRankingByComplete(userId, startTime, endTime, periodId, videoId, order);
+            list = fsUserMapper.countCourseRankingByComplete(userId, companyId, startTime, endTime, periodId, videoId, order);
         }
         if(type == 2){
-            list = fsUserMapper.countCourseRankingByRight(userId, startTime, endTime, periodId, videoId, order);
+            list = fsUserMapper.countCourseRankingByRight(userId, companyId, startTime, endTime, periodId, videoId, order);
         }
 
         return list;
@@ -862,8 +897,15 @@ public class FsUserServiceImpl implements IFsUserService
 
     @Override
     public CompanyUserSummaryCountVO companyUserSummaryCount(Long userId, String companyUserId) {
-        CompanyUserSummaryCountVO companyUserCount = fsUserMapper.companyUserCount(companyUserId);
-        CompanyUserSummaryCountVO newUserRedPacketCount = fsUserMapper.newUserRedPacketCount(companyUserId);
+        // 判断是否是管理员
+        Long companyId = null;
+        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(userId);
+        if (companyUser != null && companyUser.isAdmin()){
+            companyUserId = String.valueOf(0);
+            companyId = companyUser.getCompanyId();
+        }
+        CompanyUserSummaryCountVO companyUserCount = fsUserMapper.companyUserCount(companyUserId, companyId);
+        CompanyUserSummaryCountVO newUserRedPacketCount = fsUserMapper.newUserRedPacketCount(companyUserId, companyId);
         CompanyUserSummaryCountVO vo = new CompanyUserSummaryCountVO();
         BeanUtils.copyProperties(companyUserCount, vo);
         vo.setUserRedPacketNum(newUserRedPacketCount.getUserRedPacketNum());
@@ -948,6 +990,12 @@ public class FsUserServiceImpl implements IFsUserService
     private FsUserStatisticsVO getUserStatistics(UserStatisticsCommonParam param) {
         FsUserStatisticsVO fsUserStatisticsVO = new FsUserStatisticsVO();
 
+        // 判断是否是管理员
+        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(param.getUserId());
+        if (companyUser != null && companyUser.isAdmin()){
+            param.setUserId(0L);
+            param.setCompanyId(companyUser.getCompanyId());
+        }
         // 获取课程统计
         Map<String, Long> couserMap = fsUserMapper.countUserCourse(param);
         if (couserMap != null) {

+ 60 - 0
fs-service/src/main/java/com/fs/qw/cache/QwSopCacheService.java

@@ -0,0 +1,60 @@
+package com.fs.qw.cache;
+
+import com.fs.common.utils.StringUtils;
+import com.fs.qw.mapper.QwUserMapper;
+import com.fs.sop.domain.SopUserLogs;
+import com.fs.sop.mapper.QwSopMapper;
+import com.fs.sop.mapper.SopUserLogsMapper;
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.TimeUnit;
+
+@Component
+public class QwSopCacheService {
+    @Autowired
+    private QwSopMapper qwSopMapper;
+
+    @Autowired
+    private QwUserMapper qwUserMapper;
+
+    @Autowired
+    private SopUserLogsMapper sopUserLogsMapper;
+
+    private static final Cache<String, String> QW_SOP_NAME_CACHE = Caffeine.newBuilder()
+            .maximumSize(5000)
+            .expireAfterWrite(10, TimeUnit.MINUTES)
+            .build();
+
+    private static final Cache<String, String> QW_SOP_LOG_NAME_CACHE = Caffeine.newBuilder()
+            .maximumSize(5000)
+            .expireAfterWrite(10, TimeUnit.MINUTES)
+            .build();
+
+
+    public String getQwSopNameBySopId(String sopId) {
+        return QW_SOP_NAME_CACHE.get(sopId,e->{
+            String sopName = qwSopMapper.selectQwSopNameBySopId(sopId);
+            if(StringUtils.isNotBlank(sopName)){
+                return sopName;
+            }
+            return "-";
+        });
+    }
+
+    public String getQwSopLogNameBySopId(String periodId) {
+        return QW_SOP_LOG_NAME_CACHE.get(periodId,e->{
+            SopUserLogs sopUserLogs = sopUserLogsMapper.selectSopUserLogsById(periodId);
+
+            if(sopUserLogs != null) {
+                String qwUserName = qwUserMapper.selectQwUserName(sopUserLogs.getQwUserId(), sopUserLogs.getCorpId());
+                if(qwUserName != null) {
+                    return qwUserName+"_"+sopUserLogs.getStartTime();
+                }
+            }
+            return "-";
+        });
+    }
+}

+ 61 - 0
fs-service/src/main/java/com/fs/qw/cache/QwUserCacheService.java

@@ -0,0 +1,61 @@
+package com.fs.qw.cache;
+
+import com.fs.qw.dto.QwUserDTO;
+import com.fs.qw.mapper.QwUserMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Component
+public class QwUserCacheService {
+
+    @Autowired
+    private QwUserMapper qwUserMapper;
+
+    private Map<String, Map<String, String>> qwUserCache = new ConcurrentHashMap<>();
+
+
+    @PostConstruct
+    public void initCache() {
+        refreshCache();
+    }
+
+    public void refreshCache() {
+        List<QwUserDTO> allUsers = qwUserMapper.selectAllQwUserMapping();
+        Map<String, Map<String, String>> newCache = new ConcurrentHashMap<>();
+
+        for (QwUserDTO user : allUsers) {
+            newCache.computeIfAbsent(user.getCorpId(), k -> new ConcurrentHashMap<>())
+                    .put(user.getQwUserId(), user.getId());
+        }
+
+        this.qwUserCache = newCache;
+    }
+
+    // 根据qwUserId和corpId获取id
+    public String getIdByQwUserIdAndCorpId(String qwUserId, String corpId) {
+        Map<String, String> corpUsers = qwUserCache.get(corpId);
+        return corpUsers != null ? corpUsers.get(qwUserId) : null;
+    }
+
+    public Map<String, String> batchGetIds(List<String> qwUserIds, String corpId) {
+        Map<String, String> result = new HashMap<>();
+        Map<String, String> corpUsers = qwUserCache.get(corpId);
+
+        if (corpUsers != null) {
+            for (String qwUserId : qwUserIds) {
+                String id = corpUsers.get(qwUserId);
+                if (id != null) {
+                    result.put(qwUserId, id);
+                }
+            }
+        }
+
+        return result;
+    }
+}

+ 12 - 0
fs-service/src/main/java/com/fs/qw/dto/QwUserDTO.java

@@ -0,0 +1,12 @@
+package com.fs.qw.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class QwUserDTO implements Serializable {
+    private String qwUserId;
+    private String corpId;
+    private String id;
+}

+ 14 - 0
fs-service/src/main/java/com/fs/qw/mapper/QwUserMapper.java

@@ -5,6 +5,7 @@ import com.fs.course.param.FsCourseListBySidebarParam;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.domain.QwWorkTask;
 import com.fs.qw.dto.QwUserByToolDTO;
+import com.fs.qw.dto.QwUserDTO;
 import com.fs.qw.dto.QwUserKeyDTO;
 import com.fs.qw.param.*;
 import com.fs.qw.vo.*;
@@ -376,4 +377,17 @@ public interface QwUserMapper extends BaseMapper<QwUser>
     List<QwExternalListByHeavyVO> getQwExternalListByHeavy(@Param("data") FsCourseListBySidebarParam param);
 
     List<QwWorkTask> selectQwWorkTaskList(SelectQwWorkTaskListParam param);
+
+    @Select("select id,qw_user_id,company_user_id from qw_user where is_del=0 and company_user_id is not null")
+    List<QwUser> selectQwUserAllList();
+
+    @Select("select qw_user_id, corp_id, id from qw_user where qw_user_id is not null and corp_id is not null")
+    List<QwUserDTO> selectAllQwUserMapping();
+
+    @Select("select qw_user_name from qw_user where qw_user_id=#{qwUserId} and corp_id=#{corpId}")
+    String selectQwUserName(@Param("qwUserId") String qwUserId,@Param("corpId") String corpId);
+
+    @Select("select qw_user_id from qw_user where company_user_id = ${companyUserId}")
+    List<String> findQwUserIdListByCompanyUserId(@Param("companyUserId") Long companyUserId);
+
 }

+ 4 - 0
fs-service/src/main/java/com/fs/sop/domain/QwSop.java

@@ -116,4 +116,8 @@ public class QwSop implements Serializable
     @Excel(name = "开启评论或者弹幕,1-开启评论;2-开启弹幕;3-都关闭")
     private Integer openCommentStatus;
 
+    /**
+     * 是否按照营期 发送官方群发 1是 2否(否的时候按单链发)
+     */
+    private Integer isSampSend;
 }

+ 2 - 0
fs-service/src/main/java/com/fs/sop/domain/QwSopLogs.java

@@ -88,6 +88,8 @@ public class QwSopLogs implements Serializable {
     @TableField(exist = false)
     private Integer takeRecords;
 
+    private String sopTitle;
+
     // 构造函数
 //    public QwSopLogs() {
 //        this.id = UUID.randomUUID().toString();

+ 14 - 0
fs-service/src/main/java/com/fs/sop/mapper/QwSopLogsMapper.java

@@ -9,11 +9,15 @@ import com.fs.sop.params.*;
 import com.fs.sop.vo.QwSopLogsDoSendListTVO;
 import com.fs.sop.vo.QwSopLogsListCVO;
 import com.fs.sop.vo.QwSopLogsListVOByUserInfo;
+import org.apache.ibatis.annotations.MapKey;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.springframework.stereotype.Repository;
 
+import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 企业微信SOP  定时任务Mapper接口
@@ -293,5 +297,15 @@ public interface QwSopLogsMapper extends BaseMapper<QwSopLogs> {
     List<QwSopLogs> selectSopLogsByCreateCorpMassSendResult();
     @DataSource(DataSourceType.SOP)
     List<QwSopLogsListCVO> selectQwSopLogsListByChatSopId(@Param("map") QwSopLogsParam param);
+    @DataSource(DataSourceType.SOP)
+    String queryPeriodNameById(@Param("periodId") String periodId);
+
+    @DataSource(DataSourceType.SOP)
+    @MapKey("id")
+    Map<String,QwSopLogs> queryAllPeriod();
 
+    @DataSource(DataSourceType.SOP)
+    Long selectQwSopLogsCountByQwUserId(@Param("data") List<String> qwUserIdList,
+                                        @Param("periodId") String periodId,
+                                        @Param("previousDay") LocalDate previousDay);
 }

+ 57 - 0
fs-service/src/main/java/com/fs/sop/mapper/QwSopMapper.java

@@ -12,14 +12,18 @@ import com.fs.qw.vo.ChatSopRuleTimeVO;
 import com.fs.qw.vo.QwSopRuleTimeVO;
 import com.fs.qw.vo.WxSopRuleTimeVO;
 import com.fs.sop.domain.QwSop;
+import com.fs.sop.params.GetSOPTaskDataParam;
 import com.fs.sop.params.QwSopAutoByTags;
 import com.fs.sop.params.QwSopAutoTime;
 import com.fs.sop.params.QwSopTagsParam;
+import com.fs.qw.result.QwFilterSopCustomersResult;
+import com.fs.qw.vo.QwSopRuleTimeVO;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.springframework.stereotype.Repository;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * 企微sopMapper接口
@@ -64,6 +68,35 @@ public interface QwSopMapper extends BaseMapper<QwSop> {
     public List<QwSop> selectQwSopList(QwSop qwSop);
 
     @DataSource(DataSourceType.SOP)
+    @Select("<script>" +
+            "select * from qw_sop" +
+            " where 1=1 " +
+            "            <if test=\"name != null  and name != ''\"> and name like concat('%', #{name}, '%')</if>\n" +
+            "            <if test=\"status != null \"> and status = #{status}</if>\n" +
+            "            <if test=\"type != null \"> and type = #{type}</if>\n" +
+            "            <if test=\"id != null and id != '' \"> and id = #{id}</if>\n" +
+            "            <if test=\"companyId != null \"> and company_id = #{companyId}</if>\n" +
+            "            <if test=\"qwUserIds != null  and qwUserIds != ''\"> and FIND_IN_SET(#{qwUserIds}, qw_user_ids) > 0</if>\n" +
+            "            <if test=\"createBy != null  and createBy != ''\"> and create_by = #{createBy}</if>\n" +
+            "            <if test=\"corpId != null  and corpId != ''\"> and corp_id = #{corpId}</if>\n" +
+            "            <if test=\"createTime != null \"> and DATE(create_time) = #{createTime}</if>\n" +
+            "            <if test=\"sendType != null \"> and send_type = #{sendType}</if>\n" +
+            "            <if test=\"expiryTime != null \"> and expiry_time = #{expiryTime}</if>\n" +
+            "            <if test=\"isAutoSop != null \"> and is_auto_sop = #{isAutoSop}</if>\n" +
+            "            <if test=\"autoSopTime != null \"> and auto_sop_time = #{autoSopTime}</if>\n" +
+            "            <if test=\"minSend != null \"> and min_send = #{minSend}</if>\n" +
+            "            <if test=\"maxSend != null \"> and max_send = #{maxSend}</if>\n" +
+            "            <if test=\"stopTime != null \"> and stop_time = #{stopTime}</if>\n" +
+            "            <if test=\"qwUserIdList != null and !qwUserIdList.isEmpty() \">" +
+                            "  and ( \n" +
+                            "    <foreach collection='qwUserIdList' item='item' index='index' separator=' or '> \n" +
+                            "        find_in_set( #{item} , REGEXP_REPLACE(qw_user_ids,  '[\"\\\\[\\\\]]', '' ) ) \n" +
+                            "    </foreach> \n" +
+                            "    )" +
+            "            </if>" +
+            "            <!-- 加入固定条件 -->\n" +
+            "            and status != 6" +
+            "</script>")
     public List<QwSop> selectQwSopMyList(QwSop qwSop);
 
     /**
@@ -362,9 +395,33 @@ public interface QwSopMapper extends BaseMapper<QwSop> {
     @Select("select * FROM qw_sop where is_rating = 1 and send_type in(2,3) and min_conversion_day is not null and max_conversion_day is not null order by create_time desc")
     List<QwSop> selectQwSopByIsRatingNotNull();
 
+    @DataSource(DataSourceType.SOP)
+    List<QwSop> selectQwSopAllList(GetSOPTaskDataParam param);
+
     @DataSource(DataSourceType.SOP)
     public List<ChatSopRuleTimeVO> executeSopChatByIds(@Param("ids") String[] ids);
 
     @DataSource(DataSourceType.SOP)
     public int updateStatusQwSopById2(@Param("ids") List<String> ids);
+
+    List<QwSop> selectQwSopByTempId(@Param("tempId") String tempId);
+
+    @DataSource(DataSourceType.SOP)
+    @Select("select name from qw_sop where id=#{sopId} limit 1")
+    String selectQwSopNameBySopId(@Param("sopId") String sopId);
+
+    /**
+     * 批量更新sop表的chId
+     * @param sopList 更新数据
+     * **/
+    @DataSource(DataSourceType.SOP)
+    void batchUpdateSopChatIdById(@Param("sopList") List<QwSop> sopList);
+
+    /**
+     * 批量查询数据
+     * @param ids id
+     * @return 结果
+     * **/
+    @DataSource(DataSourceType.SOP)
+    List<QwSop> getQwSopInfoById(@Param("ids") Set<String> ids);
 }

+ 24 - 0
fs-service/src/main/java/com/fs/sop/mapper/SopUserLogsMapper.java

@@ -6,6 +6,7 @@ import com.fs.qw.param.SopUserLogsVO;
 import com.fs.qw.vo.UpdateSopUserLogDateVo;
 import com.fs.sop.domain.SopUserLogs;
 import com.fs.sop.domain.SopUserLogsInfo;
+import com.fs.sop.params.GetSOPTaskDataParam;
 import com.fs.sop.params.SopUserLogsList;
 import com.fs.sop.params.SopUserLogsParam;
 import com.fs.sop.params.SopUserLogsParamByDate;
@@ -227,6 +228,29 @@ public interface SopUserLogsMapper {
     @DataSource(DataSourceType.SOP)
     void batchInsertSopUserLogs(@Param("list") List<SopUserLogs> list);
 
+    @DataSource(DataSourceType.SOP)
+    List<String> selectSopUserLogsByQwUserIds(@Param("qwUserIds") List<String> qwUserIdList);
+
+    /**
+     *  未自动创建营期 开启的 (相当于固定营期)
+     *  否则按进线时间每天创建
+     * @return
+     */
+    @DataSource(DataSourceType.SOP)
+    @Select(" SELECT log.id, log.qw_user_id,log.sop_id,log.corp_id, qw_sop.is_auto_sop,log.start_time\n" +
+            "            FROM sop_user_logs log\n" +
+            "            LEFT JOIN qw_sop ON log.sop_id = qw_sop.id\n" +
+            "            WHERE \n" +
+            "              log.status = 1\n" +
+            "             AND qw_sop.status in(2,3)")
+    List<SopUserLogs> queryAllSopUserLogs();
+
     @DataSource(DataSourceType.SOP)
     void updateSopuserLogsDateById(UpdateSopUserLogDateVo vo);
+
+    @DataSource(DataSourceType.SOP)
+    List<SopUserLogs> querySopUserLogsByParam(GetSOPTaskDataParam param);
+
+    @DataSource(DataSourceType.SOP)
+    List<SopUserLogs> getSopUserLogsInfoById(@Param("ids") String[] ids);
 }

+ 12 - 0
fs-service/src/main/java/com/fs/sop/params/GetSOPTaskDataParam.java

@@ -0,0 +1,12 @@
+package com.fs.sop.params;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class GetSOPTaskDataParam implements Serializable {
+    private String startDate;
+    private String endDate;
+    private Long companyId;
+}

+ 6 - 0
fs-service/src/main/java/com/fs/sop/service/IQwSopService.java

@@ -3,8 +3,10 @@ package com.fs.sop.service;
 import com.fs.common.core.domain.R;
 import com.fs.qw.domain.QwSopUpdateStatus;
 import com.fs.sop.domain.QwSop;
+import com.fs.sop.params.GetSOPTaskDataParam;
 import com.fs.sop.params.QwSopAutoTime;
 import com.fs.sop.params.QwSopEditQwUserParam;
+import com.fs.sop.vo.QwSopTask;
 import com.fs.sop.vo.SopVoiceListVo;
 
 import java.io.IOException;
@@ -90,4 +92,8 @@ public interface IQwSopService
     List<SopVoiceListVo> getSopVoiceList(String id);
 
     List<QwSop> selectWxSop();
+
+    List<QwSopTask> getQwSopTaskList(GetSOPTaskDataParam param);
+
+    List<QwSop> selectQwSopByTempId(String tempId);
 }

+ 37 - 4
fs-service/src/main/java/com/fs/sop/service/impl/QwSopLogsServiceImpl.java

@@ -54,6 +54,7 @@ import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.concurrent.*;
 import java.util.function.Function;
+import java.util.stream.Collector;
 import java.util.stream.Collectors;
 
 /**
@@ -744,12 +745,44 @@ public class QwSopLogsServiceImpl implements IQwSopLogsService
             List<QwSopLogsDoSendListTVO> logsByJsApi = qwSopLogsMapper.getQwSopLogsByJsApiAll(param);
 
 
+//            // 优先返回 sendType == 8 的第一条记录
+//            List<QwSopLogsDoSendListTVO> result = logsByJsApi.stream()
+//                    .filter(log -> log.getSendType() == 8)
+//                    .findFirst()
+//                    .map(Collections::singletonList) // 单元素不可变 List
+//                    .orElse(logsByJsApi); // 如果没有匹配项,返回原列表
             // 优先返回 sendType == 8 的第一条记录
             List<QwSopLogsDoSendListTVO> result = logsByJsApi.stream()
-                    .filter(log -> log.getSendType() == 8)
-                    .findFirst()
-                    .map(Collections::singletonList) // 单元素不可变 List
-                    .orElse(logsByJsApi); // 如果没有匹配项,返回原列表
+                    .collect(Collector.of(
+                            () -> new Object() {
+                                QwSopLogsDoSendListTVO type8 = null;
+                                List<QwSopLogsDoSendListTVO> type9List = new ArrayList<>();
+                                List<QwSopLogsDoSendListTVO> otherList = new ArrayList<>();
+                            },
+                            (acc, log) -> {
+                                if (acc.type8 == null && log.getSendType() == 8) {
+                                    acc.type8 = log;
+                                } else if (acc.type8 == null) {
+                                    if (log.getSendType() == 9) {
+                                        acc.type9List.add(log);
+                                    } else {
+                                        acc.otherList.add(log);
+                                    }
+                                }
+                            },
+                            (acc1, acc2) -> { throw new UnsupportedOperationException(); },
+                            acc -> {
+                                if (acc.type8 != null) {
+                                    return Collections.singletonList(acc.type8);
+                                } else if (!acc.type9List.isEmpty()) {
+                                    List<QwSopLogsDoSendListTVO> combined = new ArrayList<>(acc.type9List.size() + acc.otherList.size());
+                                    combined.addAll(acc.type9List);
+                                    combined.addAll(acc.otherList);
+                                    return combined;
+                                }
+                                return logsByJsApi;
+                            }
+                    ));
 
             // 查询员工信息的id
             QwUser qwUser = qwExternalContactService.getQwUserByRedis(param.getCorpId().trim(),param.getQwUserId().trim());

+ 58 - 4
fs-service/src/main/java/com/fs/sop/service/impl/QwSopServiceImpl.java

@@ -27,11 +27,13 @@ import com.fs.sop.domain.*;
 import com.fs.sop.mapper.*;
 import com.fs.sop.params.*;
 import com.fs.sop.service.*;
+import com.fs.sop.vo.QwSopTask;
 import com.fs.sop.vo.SopVoiceListVo;
 import com.fs.sop.vo.VoiceVo;
 import com.fs.voice.utils.StringUtil;
 import com.fs.wxUser.mapper.CompanyWxUserMapper;
 import com.fs.wxUser.param.CompanyWxUserSopParam;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.rocketmq.spring.core.RocketMQTemplate;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -71,6 +73,10 @@ public class QwSopServiceImpl implements IQwSopService
 
     @Autowired
     private SopUserLogsInfoMapper sopUserLogsInfoMapper;
+    @Autowired
+    private AsyncChatSopService asyncChatSopService;
+    @Autowired
+    private QwSopTempMapper qwSopTempMapper;
 
     @Autowired
     private IFsCourseLinkService iFsCourseLinkService;
@@ -83,8 +89,6 @@ public class QwSopServiceImpl implements IQwSopService
 
     @Autowired
     private SopUserLogsMapper sopUserLogsMapper;
-    @Autowired
-    private QwSopTempMapper qwSopTempMapper;
 
     @Autowired
     private AsyncSopService asyncSopService;
@@ -112,8 +116,6 @@ public class QwSopServiceImpl implements IQwSopService
 
     @Autowired
     private RocketMQTemplate rocketMQTemplate;
-    @Autowired
-    private AsyncChatSopService asyncChatSopService;
 
     /**
      * 查询企微sop
@@ -1016,6 +1018,58 @@ public class QwSopServiceImpl implements IQwSopService
         return qwSopMapper.selectWxSop();
     }
 
+    @Override
+    public List<QwSopTask> getQwSopTaskList(GetSOPTaskDataParam param) {
+        List<QwSop> qwSopList = qwSopMapper.selectQwSopAllList(param);
+        Map<String, List<SopUserLogs>> sopUserLogsMap7Days = getSopUserLogsMap(param);
+
+        List<QwSopTask> qwSopTaskList = new ArrayList<>();
+
+        for (QwSop qwSop : qwSopList) {
+            QwSopTask qwSopTask = new QwSopTask();
+            qwSopTask.setId(qwSop.getId());
+            qwSopTask.setLabel(qwSop.getName());
+
+            List<QwSopTask> listData = new ArrayList<>();
+            // 获取对应SOP任务执行记录
+            List<SopUserLogs> sopUserLogs = sopUserLogsMap7Days.get(qwSop.getId());
+            if(CollectionUtils.isEmpty(sopUserLogs)){
+                log.info("当前SOP无记录!已跳过");
+                continue;
+            }
+            for (SopUserLogs sopUserLog : sopUserLogs) {
+                QwSopTask child = new QwSopTask();
+                child.setLabel(sopUserLog.getQwUserId()+"_"+sopUserLog.getStartTime());
+                child.setId(sopUserLog.getId());
+                listData.add(child);
+            }
+            qwSopTask.setChildren(listData);
+
+            qwSopTaskList.add(qwSopTask);
+        }
+        if(CollectionUtils.isEmpty(qwSopTaskList)){
+            return Collections.emptyList();
+        }
+
+        return qwSopTaskList.stream().filter(e-> CollectionUtils.isNotEmpty(e.getChildren())).collect(Collectors.toList());
+    }
+
+
+    @Override
+    @DataSource(DataSourceType.SOP)
+    public List<QwSop> selectQwSopByTempId(String tempId) {
+        return qwSopMapper.selectQwSopByTempId(tempId);
+    }
+
+
+    public Map<String,List<SopUserLogs>> getSopUserLogsMap(GetSOPTaskDataParam param){
+        List<SopUserLogs> sopUserLogs = sopUserLogsMapper.querySopUserLogsByParam(param);
+        if(CollectionUtils.isEmpty(sopUserLogs)) {
+            return new HashMap<>();
+        }
+        return sopUserLogs.stream().collect(Collectors.groupingBy(SopUserLogs::getSopId));
+    }
+
     /**
      *新增员工执行SOP
      */

+ 28 - 0
fs-service/src/main/java/com/fs/sop/vo/QwSopTask.java

@@ -0,0 +1,28 @@
+package com.fs.sop.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 企微sop任务
+ */
+@Data
+public class QwSopTask implements Serializable {
+
+    /**
+     * 任务id
+     */
+    private String id;
+
+    /**
+     * 任务名称
+     */
+    private String label;
+
+    /**
+     * 任务详情
+     */
+    private List<QwSopTask> children;
+}

+ 5 - 0
fs-service/src/main/java/com/fs/sop/vo/SopUserLogsVo.java

@@ -40,4 +40,9 @@ public class SopUserLogsVo  {
     private Integer isRegister;
     private String chatId;
 
+    /**
+     * 是否按照营期 发送官方群发 1 按照【营期+插件补发】的形式发  2 按照【营期+官方单链】的形式发
+     */
+    private Integer isSampSend;
+
 }

+ 14 - 0
fs-service/src/main/java/com/fs/statis/IFsStatisQwWatchService.java

@@ -0,0 +1,14 @@
+package com.fs.statis;
+
+import com.fs.statis.domain.FsStatisQwWatch;
+import com.fs.statis.dto.StatsWatchLogPageListDTO;
+
+import java.util.List;
+
+public interface IFsStatisQwWatchService {
+
+    void writeData(String date);
+
+    List<FsStatisQwWatch> queryList(StatsWatchLogPageListDTO param);
+    List<FsStatisQwWatch> exportQueryList(StatsWatchLogPageListDTO param);
+}

+ 6 - 3
fs-service/src/main/java/com/fs/statis/domain/FsStatisPeriodWatch.java

@@ -1,11 +1,13 @@
 package com.fs.statis.domain;
 
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
-import java.util.Date;
+import java.time.LocalDate;
 
 /**
  * fs_statis_period_watch表 实体类
@@ -22,12 +24,13 @@ public class FsStatisPeriodWatch {
     /**
      * 主键ID (虽然注释中没有,但通常id为主键)
      */
+    @TableId(type = IdType.AUTO)
     private Integer id;
 
     /**
      * 训练营id
      */
-    private Integer periodId;
+    private String periodId;
 
     /**
      * 训练营人数
@@ -97,7 +100,7 @@ public class FsStatisPeriodWatch {
     /**
      * 数据日期
      */
-    private Date dataDate;
+    private LocalDate dataDate;
 
 
     /**

+ 47 - 0
fs-service/src/main/java/com/fs/statis/domain/FsStatisQwTempParam.java

@@ -0,0 +1,47 @@
+package com.fs.statis.domain;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDate;
+
+/**
+ * 企微临时参数统计实体
+ * Corresponds to the fs_statis_qw_temp_param table
+ */
+@Data
+public class FsStatisQwTempParam implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 自增ID
+     */
+    private Integer id;
+
+    /**
+     * 销售id
+     */
+    private Long companyUserId;
+
+    /**
+     * 当天时间
+     */
+    private LocalDate thisDate;
+
+    /**
+     * 企微id
+     */
+    private Long qwUserId;
+
+    /**
+     * 部门ID
+     */
+    private Long deptId;
+
+    /**
+     * 公司
+     */
+    private Long companyId;
+
+}

+ 190 - 0
fs-service/src/main/java/com/fs/statis/domain/FsStatisQwWatch.java

@@ -0,0 +1,190 @@
+package com.fs.statis.domain;
+
+import com.fs.common.annotation.Excel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+
+/**
+ * 企微观看统计
+ * fs_statis_qw_watch
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class FsStatisQwWatch {
+
+    /**
+     * id
+     */
+    private Long id;
+
+    /**
+     * 部门
+     */
+    private Long deptId;
+    @Excel(name = "部门")
+    private String deptName;
+    /**
+     * 销售id
+     */
+    private Long companyUserId;
+
+    /**
+     * 销售
+     */
+    @Excel(name = "销售")
+    private String companyUserName;
+
+    /**
+     * 企微号
+     */
+    private String qwUserId;
+
+    /**
+     * 任务数
+     */
+    @Excel(name = "任务数")
+    private Long sopTaskNum;
+
+    /**
+     * 营期数
+     */
+    @Excel(name = "营期数")
+    private Long periodNum;
+
+    /**
+     * 营期人数
+     */
+    @Excel(name = "营期人数")
+    private Long periodPersonNum;
+
+    /**
+     * 完课数
+     */
+    @Excel(name = "完课数")
+    private Long completedNum;
+
+    /**
+     * 数据日期
+     */
+    private String dataDate;
+
+    /**
+     * 发课数
+     */
+    @Excel(name = "发课数")
+    private Long sendNum;
+
+    /**
+     * 待看课数
+     */
+    @Excel(name = "待看课数")
+    private Long notRegisteredNum;
+
+    /**
+     * 中断数
+     */
+    @Excel(name = "中断数")
+    private Long interruptNum;
+
+    /**
+     * 上线数 (generated column, read-only from insert/update perspective)
+     */
+    @Excel(name = "上线数")
+    private Long registeredNum;
+
+    /**
+     * 企微重粉数
+     */
+    @Excel(name = "企微重粉数")
+    private Long qwRepeatNum;
+
+    /**
+     * 小程序重粉
+     */
+    @Excel(name = "小程序重粉")
+    private Long userRepeatNum;
+
+    /**
+     * 拉黑数
+     */
+    @Excel(name = "拉黑数")
+    private Long blackNum;
+
+    /**
+     * 删除数
+     */
+    @Excel(name = "删除数")
+    private Long deletedNum;
+
+    /**
+     * 订单总数
+     */
+    @Excel(name = "订单总数")
+    private Long orderNum;
+
+    /**
+     * 订单总金额
+     */
+    @Excel(name = "订单总金额")
+    private BigDecimal orderMoneyTotal;
+
+    /**
+     * 红包总金额
+     */
+    @Excel(name = "红包总金额")
+    private BigDecimal redPackageMoneyTotal;
+
+    /**
+     * 总拨打数
+     */
+    @Excel(name = "总拨打数")
+    private Long callNum;
+
+    /**
+     * 接通数
+     */
+    @Excel(name = "接通数")
+    private Long receivePassNum;
+
+    /**
+     * 未接通数
+     */
+    @Excel(name = "未接通数")
+    private Long receiveNotNum;
+
+    /**
+     * 通话时长(单位s)
+     */
+    @Excel(name = "通话时长(单位s)")
+    private Long callTimeTotal;
+
+    /**
+     * 催课未处理数
+     */
+    @Excel(name = "催课未处理数")
+    private Long remindPendingNum;
+
+    /**
+     * 催课已处理数
+     */
+    @Excel(name = "催课已处理数")
+    private Long remindProcessedNum;
+
+    /**
+     * 上线率 (generated column, read-only from insert/update perspective)
+     */
+    @Excel(name = "上线率")
+    private BigDecimal regRate;
+
+    /**
+     * 完课率 (generated column, read-only from insert/update perspective)
+     */
+    @Excel(name = "完课率")
+    private BigDecimal finishedRate;
+}

+ 52 - 2
fs-service/src/main/java/com/fs/statis/domain/FsStatisSalerWatch.java

@@ -1,5 +1,8 @@
 package com.fs.statis.domain;
 
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import lombok.NoArgsConstructor;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
@@ -25,39 +28,78 @@ public class FsStatisSalerWatch {
      * 部门
      */
     private Long deptId;
+    /**
+     * 部门名称
+     */
+    @Excel(name = "所属部门")
+    private String deptName;
 
     /**
      * 销售id
      */
     private Long companyUserId;
+    /**
+     * 销售名称
+     */
+    @Excel(name = "销售名称")
+    private String companyUserName;
 
     /**
      * 训练营人数
      */
+    @Excel(name = "训练营人数")
     private Long trainCampNum;
 
+    /**
+     * 发课数
+     */
+    @Excel(name = "发课数")
+    private Long sendNum;
+
     /**
      * 未报名人数
      */
+    @Excel(name = "未报名人数")
     private Long notRegisteredNum;
 
     /**
      * 已报名人数
      */
+    @Excel(name = "已报名人数")
     private Long registeredNum;
     /**
      * 完课人数
      */
+    @Excel(name = "完课人数")
     private Long completedNum;
+    /**
+     * 看课中断数
+     */
+    @Excel(name = "看课中断数")
+    private Long interruptNum;
+
+    /**
+     * 企微重粉
+     */
+    @Excel(name = "企微重粉")
+    private Long qwRepeatNum;
+
+    /**
+     * 小程序(看课)重粉
+     */
+    @Excel(name = "小程序(看课)重粉")
+    private Long userRepeatNum;
 
     /**
      * 报名率
      */
+    @Excel(name = "上线率")
     private Float regRate;
 
     /**
      * 完课率
      */
+    @Excel(name = "完课率")
     private Float finishedRate;
 
     /**
@@ -101,12 +143,20 @@ public class FsStatisSalerWatch {
     private Long onlineCompletePlayback;
 
     /**
-     * 训练营id
+     * 营id
      */
-    private Long periodId;
+    private String periodId;
+
+    /**
+     * 营期名称
+     */
+    private String periodName;
+
 
     /**
      * 数据日期
      */
     private LocalDate dataDate;
+    private String sopId;
+    private String sopTaskName;
 }

+ 157 - 0
fs-service/src/main/java/com/fs/statis/domain/FsStatisSopWatch.java

@@ -0,0 +1,157 @@
+package com.fs.statis.domain;
+
+import com.fs.common.annotation.Excel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDate;
+
+/**
+ * 销售观看统计实体类
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class FsStatisSopWatch {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 部门
+     */
+    private Long deptId;
+    /**
+     * 部门名称
+     */
+    private String deptName;
+
+    /**
+     * 销售id
+     */
+    private Long companyUserId;
+    /**
+     * 销售名称
+     */
+    private String companyUserName;
+
+    /**
+     * 营期名称
+     */
+    @Excel(name = "sop营期")
+    private String periodName;
+    /**
+     * 训练营人数
+     */
+    @Excel(name = "训练营人数")
+    private Long trainCampNum;
+
+    /**
+     * 发课数
+     */
+    @Excel(name = "发课数")
+    private Long sendNum;
+
+    /**
+     * 未报名人数
+     */
+    @Excel(name = "未报名人数")
+    private Long notRegisteredNum;
+
+    /**
+     * 已报名人数
+     */
+    @Excel(name = "已报名人数")
+    private Long registeredNum;
+    /**
+     * 完课人数
+     */
+    @Excel(name = "完课人数")
+    private Long completedNum;
+    /**
+     * 看课中断数
+     */
+    @Excel(name = "看课中断数")
+    private Long interruptNum;
+
+    /**
+     * 企微重粉
+     */
+    @Excel(name = "企微重粉")
+    private Long qwRepeatNum;
+
+    /**
+     * 小程序(看课)重粉
+     */
+    @Excel(name = "小程序(看课)重粉")
+    private Long userRepeatNum;
+
+    /**
+     * 报名率
+     */
+    @Excel(name = "上线率")
+    private Float regRate;
+
+    /**
+     * 完课率
+     */
+    @Excel(name = "完课率")
+    private Float finishedRate;
+
+    /**
+     * 未上线-总数
+     */
+    private Long offlineTotal;
+
+    /**
+     * 未上线-未参与
+     */
+    private Long offlineNotPart;
+
+    /**
+     * 未上线-未观看 (原SQL注释为'为观看',推测应为'未观看')
+     */
+    private Long offlineNotWatched;
+
+    /**
+     * 已上线-总数
+     */
+    private Long onlineTotal;
+
+    /**
+     * 已上线-上线率
+     */
+    private Float onlineOnlineRate;
+
+    /**
+     * 已上线-完播率
+     */
+    private Float onlinePlaybackCompleRate;
+
+    /**
+     * 已上线-未完播
+     */
+    private Long onlineIncompletePlayback;
+
+    /**
+     * 已上线-已完播
+     */
+    private Long onlineCompletePlayback;
+
+    /**
+     * 营期id
+     */
+    private String periodId;
+
+
+    /**
+     * 数据日期
+     */
+    private LocalDate dataDate;
+    private String sopId;
+}

+ 41 - 0
fs-service/src/main/java/com/fs/statis/domain/FsStatisTempFsuser.java

@@ -0,0 +1,41 @@
+package com.fs.statis.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * fs_statis_temp_fsuser 实体类
+ *
+ * @author YourName
+ * @since YYYY-MM-DD
+ */
+@Data
+public class FsStatisTempFsuser implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 周期ID
+     */
+    @TableField("period_id")
+    private String periodId;
+
+    /**
+     * FS用户ID
+     */
+    @TableField("fs_user_id")
+    private Long fsUserId;
+
+    /**
+     * 企微id
+     */
+    @TableField("qw_user_id")
+    private String qwUserId;
+}

+ 59 - 0
fs-service/src/main/java/com/fs/statis/domain/FsStatisTempParam.java

@@ -0,0 +1,59 @@
+package com.fs.statis.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * DTO for fs_statis_temp_param table
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class FsStatisTempParam {
+
+    /**
+     * id
+     */
+    private Integer id;
+
+    /**
+     * 销售id
+     */
+    private Long companyUserId;
+
+    /**
+     * sop_id
+     */
+    private String sopId;
+
+    /**
+     * 当天时间
+     */
+    private LocalDate thisDate;
+
+    /**
+     * 企微id
+     */
+    private String qwUserId;
+
+    /**
+     * 营期id
+     */
+    private String periodId;
+
+    /**
+     * 营期时间
+     */
+    private String startTime;
+
+    /**
+     * create_time
+     */
+    private LocalDateTime createTime;
+
+    private Long deptId;
+}

+ 24 - 0
fs-service/src/main/java/com/fs/statis/domain/FsTempPeriodQuery.java

@@ -0,0 +1,24 @@
+package com.fs.statis.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 临时期次查询实体类
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class FsTempPeriodQuery {
+
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 期次ID
+     */
+    private String periodId;
+}

+ 23 - 0
fs-service/src/main/java/com/fs/statis/dto/FsStatisQwWatchWriteDataDTO.java

@@ -0,0 +1,23 @@
+package com.fs.statis.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDate;
+
+@Data
+public class FsStatisQwWatchWriteDataDTO implements Serializable {
+    /**
+     * 开始时间
+     */
+    private String startTime;
+    /**
+     * 结束时间
+     */
+    private String endTime;
+    /**
+     * 当前日期
+     */
+    private LocalDate date;
+
+}

+ 13 - 0
fs-service/src/main/java/com/fs/statis/dto/StatsWatchLogPageListDTO.java

@@ -27,4 +27,17 @@ public class StatsWatchLogPageListDTO implements Serializable {
      */
     private List<String> periodList;
 
+    private Integer pageNum;
+    private Integer pageSize;
+
+    /**
+     * 不包含空值
+     */
+    private Boolean excludeNull;
+
+    /**
+     * 包含未发课数
+     */
+    private Boolean includeSend0;
+
 }

+ 15 - 0
fs-service/src/main/java/com/fs/statis/dto/WatchCourseStatisticsDTO.java

@@ -0,0 +1,15 @@
+package com.fs.statis.dto;
+
+import com.fs.course.dto.WatchLogDTO;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 看课统计
+ */
+@Data
+public class WatchCourseStatisticsDTO implements Serializable {
+    private List<WatchLogDTO> data;
+}

+ 172 - 0
fs-service/src/main/java/com/fs/statis/impl/FsStatisQwWatchServiceImpl.java

@@ -0,0 +1,172 @@
+package com.fs.statis.impl;
+
+import com.fs.common.utils.StringUtils;
+import com.fs.company.cache.ICompanyDeptCacheService;
+import com.fs.company.cache.ICompanyUserCacheService;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.mapper.CompanyUserMapper;
+import com.fs.qw.domain.QwUser;
+import com.fs.qw.mapper.QwUserMapper;
+import com.fs.statis.IFsStatisQwWatchService;
+import com.fs.statis.domain.FsStatisQwTempParam;
+import com.fs.statis.domain.FsStatisQwWatch;
+import com.fs.statis.dto.FsStatisQwWatchWriteDataDTO;
+import com.fs.statis.dto.StatsWatchLogPageListDTO;
+import com.fs.statis.mapper.FsStatisQwTempParamMapper;
+import com.fs.statis.mapper.FsStatisQwWatchMapper;
+import com.google.common.collect.Maps;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class FsStatisQwWatchServiceImpl implements IFsStatisQwWatchService {
+    @Autowired
+    private FsStatisQwWatchMapper fsStatisQwWatchMapper;
+
+    @Autowired
+    private CompanyUserMapper companyUserMapper;
+
+    @Autowired
+    private QwUserMapper qwUserMapper;
+
+    @Autowired
+    private ICompanyDeptCacheService companyDeptCacheService;
+
+    @Autowired
+    private ICompanyUserCacheService companyUserCacheService;
+
+    @Autowired
+    private FsStatisQwTempParamMapper fsStatisQwTempParamMapper;
+    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+    @Override
+    public synchronized void writeData(String date) {
+
+        FsStatisQwWatchWriteDataDTO paramByDate = getParamByDate(date);
+
+
+        List<CompanyUser> companyUserList = this.companyUserMapper.selectAllCompanyUserList();
+        Map<Long, List<Long>> qwUserIdMap = queryQwListMap();
+
+
+        List<FsStatisQwTempParam> paramList = new ArrayList<>();
+        for (CompanyUser companyUser : companyUserList) {
+            if(companyUser.getCompanyId() == null) {
+                log.info("销售{} 对应公司id {} 为空!",companyUser.getUserId(),companyUser.getCompanyId());
+                continue;
+            }
+            // 找到销售关联的 企微账号
+            List<Long> qwUserIdList = qwUserIdMap.get(companyUser.getUserId());
+            if(CollectionUtils.isEmpty(qwUserIdList)){
+                log.info("当前销售 {} 没有关联企微账号!",companyUser.getUserId());
+                continue;
+            }
+
+            for (Long qwUserId : qwUserIdList) {
+                FsStatisQwTempParam param = new FsStatisQwTempParam();
+                param.setDeptId(companyUser.getDeptId());
+                param.setCompanyUserId(companyUser.getUserId());
+                param.setQwUserId(qwUserId);
+                param.setThisDate(paramByDate.getDate());
+                param.setCompanyId(companyUser.getCompanyId());
+                paramList.add(param);
+            }
+        }
+        fsStatisQwTempParamMapper.clear();
+
+        fsStatisQwTempParamMapper.insertList(paramList);
+
+        fsStatisQwWatchMapper.generateData(paramByDate);
+
+        fsStatisQwTempParamMapper.clear();
+    }
+
+    @Override
+    public List<FsStatisQwWatch> queryList(StatsWatchLogPageListDTO param) {
+        if(StringUtils.isNull(param.getStartDate()) && StringUtils.isNull(param.getEndDate())) {
+            return Collections.emptyList();
+        }
+
+        List<FsStatisQwWatch> list = fsStatisQwWatchMapper.queryList(param);
+
+        for (FsStatisQwWatch item : list) {
+            if(item.getDeptId() != null) {
+                String deptNameById = companyDeptCacheService.getDeptNameById(item.getDeptId());
+                if(StringUtils.isNotBlank(deptNameById)) {
+                    item.setDeptName(deptNameById);
+                }
+            }
+
+            if(item.getCompanyUserId() != null) {
+                String companyUserName = companyUserCacheService.selectCompanyUserNameUserById(item.getCompanyUserId());
+                if(StringUtils.isNotBlank(companyUserName)) {
+                    item.setCompanyUserName(companyUserName);
+                }
+            }
+        }
+        return list;
+    }
+
+    @Override
+    public List<FsStatisQwWatch> exportQueryList(StatsWatchLogPageListDTO param) {
+        if(StringUtils.isNull(param.getStartDate()) && StringUtils.isNull(param.getEndDate())) {
+            return Collections.emptyList();
+        }
+
+        List<FsStatisQwWatch> list = fsStatisQwWatchMapper.exportList(param);
+
+        return list;
+    }
+
+    private FsStatisQwWatchWriteDataDTO getParamByDate(String dateStr){
+        LocalDate targetDate;
+
+        if (dateStr != null && !dateStr.isEmpty()) {
+            try {
+                targetDate = LocalDate.parse(dateStr, DATE_FORMATTER);
+            } catch (DateTimeParseException e) {
+                log.info("提供的日期字符串格式无效: {} . 期望格式: yyyy-MM-dd" ,dateStr);
+                throw e;
+            }
+        } else {
+            targetDate = LocalDate.now().minusDays(1);
+        }
+
+        LocalDateTime startTime = targetDate.atStartOfDay();
+
+        LocalDateTime endTime = targetDate.plusDays(1).atStartOfDay();
+
+        FsStatisQwWatchWriteDataDTO params = new FsStatisQwWatchWriteDataDTO();
+        params.setDate(targetDate);
+        params.setStartTime(startTime.format(DATE_TIME_FORMATTER));
+        params.setEndTime(endTime.format(DATE_TIME_FORMATTER));
+        return params;
+    }
+
+
+    private Map<Long,List<Long>> queryQwListMap(){
+        List<QwUser> qwUsers = qwUserMapper.selectQwUserAllList();
+        if(CollectionUtils.isEmpty(qwUsers)){
+            return Maps.newHashMap();
+        }
+
+        return qwUsers.stream()
+                .filter(Objects::nonNull)
+                .filter(user -> user.getCompanyUserId() != null && user.getQwUserId() != null)
+                .collect(Collectors.groupingBy(
+                        QwUser::getCompanyUserId,
+                        Collectors.mapping(QwUser::getId, Collectors.toList())
+                ));
+    }
+}

+ 8 - 0
fs-service/src/main/java/com/fs/statis/mapper/FsStatisPeriodWatchMapper.java

@@ -1,9 +1,11 @@
 package com.fs.statis.mapper;
 
+import com.fs.sop.domain.SopUserLogs;
 import com.fs.statis.domain.FsStatisPeriodWatch;
 import com.fs.statis.dto.StatsWatchLogPageListDTO;
 import org.apache.ibatis.annotations.*;
 
+import java.time.LocalDate;
 import java.util.List;
 
 /**
@@ -91,4 +93,10 @@ public interface FsStatisPeriodWatchMapper {
     List<FsStatisPeriodWatch> selectAll();
 
     List<FsStatisPeriodWatch> queryList(StatsWatchLogPageListDTO param);
+
+    /**
+     * 获取每个sop任务对应的营期记录
+     * @return
+     */
+    List<SopUserLogs> selectRecords(@Param("previousDay") LocalDate previousDay);
 }

+ 116 - 0
fs-service/src/main/java/com/fs/statis/mapper/FsStatisQwTempParamMapper.java

@@ -0,0 +1,116 @@
+package com.fs.statis.mapper;
+
+import com.fs.statis.domain.FsStatisQwTempParam;
+import org.apache.ibatis.annotations.Delete;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * Mapper interface for operations on the fs_statis_qw_temp_param table.
+ * The method names should correspond to the 'id' attributes in FsStatisQwTempParamMapper.xml.
+ */
+@Mapper // This annotation is commonly used with Spring Boot to mark it as a MyBatis mapper
+public interface FsStatisQwTempParamMapper {
+
+    /**
+     * Selects a record by its primary key.
+     * Corresponds to the SQL statement with id="selectByPrimaryKey" in the XML.
+     *
+     * @param id The primary key.
+     * @return The FsStatisQwTempParam object, or null if not found.
+     */
+    FsStatisQwTempParam selectByPrimaryKey(Integer id);
+
+    /**
+     * Deletes a record by its primary key.
+     * Corresponds to the SQL statement with id="deleteByPrimaryKey" in the XML.
+     *
+     * @param id The primary key.
+     * @return The number of rows affected.
+     */
+    int deleteByPrimaryKey(Integer id);
+
+    /**
+     * Inserts a new record.
+     * Corresponds to the SQL statement with id="insert" in the XML.
+     * The 'id' property of the 'record' parameter will be populated with the generated ID
+     * if 'useGeneratedKeys="true"' is set in the XML.
+     *
+     * @param record The FsStatisQwTempParam object to insert.
+     * @return The number of rows affected.
+     */
+    int insert(FsStatisQwTempParam record);
+
+    /**
+     * Inserts a new record, only including non-null fields.
+     * Corresponds to the SQL statement with id="insertSelective" in the XML.
+     * The 'id' property of the 'record' parameter will be populated with the generated ID
+     * if 'useGeneratedKeys="true"' is set in the XML.
+     *
+     * @param record The FsStatisQwTempParam object to insert.
+     * @return The number of rows affected.
+     */
+    int insertSelective(FsStatisQwTempParam record);
+
+    /**
+     * Updates an existing record by its primary key, only including non-null fields in the update.
+     * Corresponds to the SQL statement with id="updateByPrimaryKeySelective" in the XML.
+     *
+     * @param record The FsStatisQwTempParam object containing the fields to update and the primary key.
+     * @return The number of rows affected.
+     */
+    int updateByPrimaryKeySelective(FsStatisQwTempParam record);
+
+    /**
+     * Updates an existing record by its primary key, updating all fields.
+     * Corresponds to the SQL statement with id="updateByPrimaryKey" in the XML.
+     *
+     * @param record The FsStatisQwTempParam object containing all fields to update and the primary key.
+     * @return The number of rows affected.
+     */
+    int updateByPrimaryKey(FsStatisQwTempParam record);
+
+    /**
+     * Selects all records from the table.
+     * Corresponds to the SQL statement with id="selectAll" in the XML.
+     *
+     * @return A list of all FsStatisQwTempParam objects.
+     */
+    List<FsStatisQwTempParam> selectAll();
+
+    /**
+     * Selects records based on the provided criteria.
+     * Corresponds to the SQL statement with id="selectByParams" in the XML.
+     * The 'criteria' object's properties are used in the WHERE clause.
+     *
+     * @param criteria An FsStatisQwTempParam object containing the query parameters.
+     * @return A list of FsStatisQwTempParam objects matching the criteria.
+     */
+    List<FsStatisQwTempParam> selectByParams(FsStatisQwTempParam criteria);
+
+    // --- You can add more custom query methods here ---
+    // For example, if you wanted to find records by a specific company_user_id and this_date:
+    /*
+    List<FsStatisQwTempParam> findByCompanyUserAndDate(
+            @Param("companyUserId") Long companyUserId,
+            @Param("thisDate") String thisDate
+    );
+    */
+    // If you add such a method, you'd also need to add a corresponding <select>
+    // statement in your FsStatisQwTempParamMapper.xml, like:
+    /*
+    <select id="findByCompanyUserAndDate" resultMap="BaseResultMap">
+        SELECT <include refid="Base_Column_List" />
+        FROM fs_statis_qw_temp_param
+        WHERE company_user_id = #{companyUserId,jdbcType=BIGINT}
+          AND this_date = #{thisDate,jdbcType=VARCHAR}
+    </select>
+    */
+
+    int insertList(@Param("list") List<FsStatisQwTempParam> recordList);
+
+    @Delete("truncate table fs_statis_qw_temp_param")
+    void clear();
+}

+ 97 - 0
fs-service/src/main/java/com/fs/statis/mapper/FsStatisQwWatchMapper.java

@@ -0,0 +1,97 @@
+package com.fs.statis.mapper;
+
+import com.fs.statis.domain.FsStatisQwWatch;
+import com.fs.statis.dto.FsStatisQwWatchWriteDataDTO;
+import com.fs.statis.dto.StatsWatchLogPageListDTO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+
+@Mapper
+public interface FsStatisQwWatchMapper {
+
+    /**
+     * 根据主键查询
+     *
+     * @param id 主键ID
+     * @return 实体
+     */
+    FsStatisQwWatch selectByPrimaryKey(Long id);
+
+    /**
+     * 根据唯一键查询
+     *
+     * @param deptId 部门ID
+     * @param companyUserId 销售ID
+     * @param qwUserId 企微号
+     * @param dataDate 数据日期
+     * @return 实体
+     */
+    FsStatisQwWatch selectByUniqueKey(@Param("deptId") Long deptId,
+                                      @Param("companyUserId") Long companyUserId,
+                                      @Param("qwUserId") String qwUserId,
+                                      @Param("dataDate") Date dataDate);
+
+    /**
+     * 新增记录 (不包括generated columns)
+     *
+     * @param record 实体
+     * @return 影响行数
+     */
+    int insert(FsStatisQwWatch record);
+
+    /**
+     * 新增记录 - 选择性插入 (不包括generated columns)
+     *
+     * @param record 实体
+     * @return 影响行数
+     */
+    int insertSelective(FsStatisQwWatch record);
+
+    /**
+     * 根据主键更新 (不更新generated columns)
+     *
+     * @param record 实体
+     * @return 影响行数
+     */
+    int updateByPrimaryKey(FsStatisQwWatch record);
+
+    /**
+     * 根据主键选择性更新 (不更新generated columns)
+     *
+     * @param record 实体
+     * @return 影响行数
+     */
+    int updateByPrimaryKeySelective(FsStatisQwWatch record);
+
+    /**
+     * 根据主键删除
+     *
+     * @param id 主键ID
+     * @return 影响行数
+     */
+    int deleteByPrimaryKey(Long id);
+
+    /**
+     * 查询列表 (可添加查询条件参数)
+     *
+     * @param example 查询条件 (可以是一个FsStatisQwWatch对象作为查询模板)
+     * @return 列表
+     */
+    List<FsStatisQwWatch> selectList(FsStatisQwWatch example);
+
+    /**
+     * 批量插入
+     *
+     * @param list 记录列表
+     * @return 影响行数
+     */
+    int batchInsert(@Param("list") List<FsStatisQwWatch> list);
+
+    void generateData(FsStatisQwWatchWriteDataDTO param);
+
+    List<FsStatisQwWatch> queryList(StatsWatchLogPageListDTO param);
+    List<FsStatisQwWatch> exportList(StatsWatchLogPageListDTO param);
+}

+ 31 - 0
fs-service/src/main/java/com/fs/statis/mapper/FsStatisSalerWatchMapper.java

@@ -1,6 +1,11 @@
 package com.fs.statis.mapper;
 
+import com.fs.common.annotation.DataSource;
+import com.fs.common.enums.DataSourceType;
+import com.fs.statis.domain.FsStatisEveryDayWatch;
 import com.fs.statis.domain.FsStatisSalerWatch;
+import com.fs.statis.domain.FsStatisSopWatch;
+import com.fs.statis.domain.FsStatisTempFsuser;
 import com.fs.statis.dto.StatsWatchLogPageListDTO;
 import org.apache.ibatis.annotations.*;
 
@@ -74,7 +79,33 @@ public interface FsStatisSalerWatchMapper {
     @Delete("DELETE FROM fs_statis_saler_watch WHERE id = #{id}")
     int deleteById(@Param("id") Integer id);
 
+    @DataSource(DataSourceType.SLAVE)
     List<FsStatisSalerWatch> queryList(StatsWatchLogPageListDTO param);
 
     void batchSave(@Param("list") List<FsStatisSalerWatch> writeData);
+
+    @DataSource(DataSourceType.SLAVE)
+    List<FsStatisSalerWatch> queryPeriodList(StatsWatchLogPageListDTO param);
+
+    @DataSource(DataSourceType.SLAVE)
+    List<FsStatisSopWatch> queryPeriodListExport(StatsWatchLogPageListDTO param);
+
+    @DataSource(DataSourceType.SLAVE)
+    List<FsStatisSalerWatch> queryTodayList(StatsWatchLogPageListDTO param);
+
+    @DataSource(DataSourceType.SLAVE)
+    List<FsStatisSalerWatch> queryListExport(StatsWatchLogPageListDTO param);
+
+    @DataSource(DataSourceType.SLAVE)
+    List<FsStatisEveryDayWatch> queryEveryDayListExport(StatsWatchLogPageListDTO param);
+
+    void generateData(@Param("date") String date);
+
+    List<FsStatisSalerWatch> generateSopData(@Param("date") String date);
+
+    @DataSource(DataSourceType.SOP)
+    List<FsStatisTempFsuser> querySopRepeatData(@Param("date") String date);
+
+    @Delete("delete from fs_statis_saler_watch where data_date=#{date}")
+    void deleteDateData(@Param("date") String date);
 }

+ 68 - 0
fs-service/src/main/java/com/fs/statis/mapper/FsStatisTempFsuserMapper.java

@@ -0,0 +1,68 @@
+package com.fs.statis.mapper;
+
+import com.fs.statis.domain.FsStatisTempFsuser;
+import org.apache.ibatis.annotations.Delete;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * fs_statis_temp_fsuser Mapper 接口
+ *
+ * @author YourName
+ * @since YYYY-MM-DD
+ */
+@Mapper
+public interface FsStatisTempFsuserMapper {
+
+    /**
+     * 根据ID查询
+     *
+     * @param id 主键ID
+     * @return 实体对象
+     */
+    FsStatisTempFsuser selectById(@Param("id") Long id);
+
+    /**
+     * 查询所有记录
+     *
+     * @return 实体对象列表
+     */
+    List<FsStatisTempFsuser> selectAll();
+
+    /**
+     * 新增数据
+     *
+     * @param fsStatisTempFsuser 实例对象
+     * @return 影响行数
+     */
+    int insert(FsStatisTempFsuser fsStatisTempFsuser);
+
+    /**
+     * 批量新增数据(MyBatis原生foreach方法)
+     *
+     * @param entities List<FsStatisTempFsuser> 实例对象列表
+     * @return 影响行数
+     */
+    int insertBatch(@Param("entities") List<FsStatisTempFsuser> entities);
+
+    /**
+     * 修改数据
+     *
+     * @param fsStatisTempFsuser 实例对象
+     * @return 影响行数
+     */
+    int updateById(FsStatisTempFsuser fsStatisTempFsuser);
+
+    /**
+     * 根据ID删除
+     *
+     * @param id 主键ID
+     * @return 影响行数
+     */
+    int deleteById(@Param("id") Long id);
+
+    @Delete("truncate table fs_statis_temp_fsuser")
+    void clear();
+}

+ 85 - 0
fs-service/src/main/java/com/fs/statis/mapper/FsStatisTempParamMapper.java

@@ -0,0 +1,85 @@
+package com.fs.statis.mapper;
+
+import com.fs.common.annotation.DataSource;
+import com.fs.common.enums.DataSourceType;
+import com.fs.statis.domain.FsStatisTempParam;
+import org.apache.ibatis.annotations.Delete;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface FsStatisTempParamMapper {
+
+    /**
+     * Inserts a new record.
+     *
+     * @param fsStatisTempParam The record to insert.
+     * @return The number of rows affected.
+     */
+    int insert(FsStatisTempParam fsStatisTempParam);
+
+    void batchSave(List<FsStatisTempParam> list);
+
+    @DataSource(DataSourceType.SOP)
+    void batchSaveToSop(List<FsStatisTempParam> list);
+
+    /**
+     * Inserts a new record, only if a field is not null.
+     * (This would typically be implemented in XML with <if> tags)
+     *
+     * @param fsStatisTempParam The record to insert.
+     * @return The number of rows affected.
+     */
+    int insertSelective(FsStatisTempParam fsStatisTempParam);
+
+    /**
+     * Selects a record by its primary key.
+     *
+     * @param id The primary key.
+     * @return The found record, or null if not found.
+     */
+    FsStatisTempParam selectById(Integer id);
+
+    /**
+     * Updates an existing record by its primary key.
+     * All fields will be updated.
+     *
+     * @param fsStatisTempParam The record with updated values.
+     * @return The number of rows affected.
+     */
+    int updateById(FsStatisTempParam fsStatisTempParam);
+
+    /**
+     * Updates an existing record by its primary key.
+     * Only non-null fields in fsStatisTempParam will be updated.
+     * (This would typically be implemented in XML with <if> tags in the SET clause)
+     *
+     * @param fsStatisTempParam The record with updated values.
+     * @return The number of rows affected.
+     */
+    int updateByIdSelective(FsStatisTempParam fsStatisTempParam);
+
+    /**
+     * Deletes a record by its primary key.
+     *
+     * @param id The primary key.
+     * @return The number of rows affected.
+     */
+    int deleteById(Integer id);
+
+    /**
+     * Selects all records from the table.
+     *
+     * @return A list of all records.
+     */
+    List<FsStatisTempParam> selectAll();
+
+    @Delete("truncate table fs_statis_temp_param")
+    void clear();
+
+    @DataSource(DataSourceType.SOP)
+    @Delete("truncate table fs_statis_temp_param")
+    void clearSop();
+
+}

+ 58 - 0
fs-service/src/main/java/com/fs/statis/mapper/FsTempPeriodQueryMapper.java

@@ -0,0 +1,58 @@
+package com.fs.statis.mapper;
+
+import com.fs.statis.domain.FsTempPeriodQuery;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+/**
+ * 临时期次查询Mapper接口
+ */
+@Mapper
+public interface FsTempPeriodQueryMapper {
+
+    /**
+     * 根据ID查询临时期次信息
+     *
+     * @param id 主键ID
+     * @return 临时期次信息
+     */
+    @Select("SELECT id, period_id AS periodId FROM fs_temp_period_query WHERE id = #{id}")
+    FsTempPeriodQuery findById(Long id);
+
+    /**
+     * 新增临时期次信息
+     *
+     * @param fsTempPeriodQuery 临时期次信息
+     * @return 影响行数
+     */
+    @Insert("INSERT INTO fs_temp_period_query(id, period_id) VALUES(#{id}, #{periodId})")
+    int insert(FsTempPeriodQuery fsTempPeriodQuery);
+
+    /**
+     * 更新临时期次信息
+     *
+     * @param fsTempPeriodQuery 临时期次信息
+     * @return 影响行数
+     */
+    @Update("UPDATE fs_temp_period_query SET period_id = #{periodId} WHERE id = #{id}")
+    int update(FsTempPeriodQuery fsTempPeriodQuery);
+
+    /**
+     * 批量插入临时期次信息
+     *
+     * @param list 临时期次信息列表
+     * @return 影响行数
+     */
+    @Insert("<script>" +
+            "INSERT INTO fs_temp_period_query(period_id) VALUES " +
+            "<foreach collection='list' item='item' index='index' separator=','>" +
+            "(#{item})" +
+            "</foreach>" +
+            "</script>")
+    int insertBatch(@Param("list") List<String> list);
+
+    @Delete("truncate table fs_temp_period_query")
+    void clear();
+
+}

+ 22 - 0
fs-service/src/main/java/com/fs/statis/param/WatchCourseStatisticsParam.java

@@ -0,0 +1,22 @@
+ package com.fs.statis.param;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+ /**
+  * 看课统计参数
+  */
+ @Data
+ public class WatchCourseStatisticsParam implements Serializable {
+
+     /**
+      * 0 七天
+      * 1 30天
+      */
+     private Integer type;
+     /**
+      * 企微外部联系人id
+      */
+     private Long qwExternalContactId;
+ }

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.