Browse Source

Merge remote-tracking branch 'origin/master'

chenguo 13 hours ago
parent
commit
1c29f6b005
100 changed files with 3594 additions and 404 deletions
  1. 42 3
      fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java
  2. 57 13
      fs-admin/src/main/java/com/fs/his/task/Task.java
  3. 57 0
      fs-admin/src/main/java/com/fs/qw/qwTask/qwTask.java
  4. 199 0
      fs-admin/src/main/java/com/fs/stats/SalesWatchStatisController.java
  5. 13 2
      fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  6. 2 1
      fs-company/src/main/java/com/fs/company/controller/company/CompanyMenuController.java
  7. 12 0
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseRedPacketLogController.java
  8. 52 22
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseWatchLogController.java
  9. 53 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactController.java
  10. 35 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactTransferLogController.java
  11. 37 4
      fs-company/src/main/java/com/fs/company/controller/qw/QwFriendWelcomeController.java
  12. 59 1
      fs-company/src/main/java/com/fs/company/controller/qw/QwGroupChatController.java
  13. 71 14
      fs-company/src/main/java/com/fs/company/controller/qw/QwSopController.java
  14. 35 4
      fs-company/src/main/java/com/fs/company/controller/qw/QwUserController.java
  15. 1 1
      fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsController.java
  16. 207 0
      fs-company/src/main/java/com/fs/company/controller/stats/SalesWatchStatisController.java
  17. 40 1
      fs-company/src/main/java/com/fs/company/controller/store/FsStoreOrderController.java
  18. 4 4
      fs-company/src/main/java/com/fs/user/FsUserAdminController.java
  19. 5 0
      fs-service/src/main/java/com/fs/company/cache/ICompanyDeptCacheService.java
  20. 5 0
      fs-service/src/main/java/com/fs/company/cache/ICompanyUserCacheService.java
  21. 27 0
      fs-service/src/main/java/com/fs/company/cache/impl/CompanyDeptCacheServiceImpl.java
  22. 31 0
      fs-service/src/main/java/com/fs/company/cache/impl/CompanyUserCacheServiceImpl.java
  23. 28 6
      fs-service/src/main/java/com/fs/company/mapper/CompanyDeptMapper.java
  24. 10 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyMapper.java
  25. 2 2
      fs-service/src/main/java/com/fs/company/mapper/CompanyRoleMapper.java
  26. 21 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyUserMapper.java
  27. 5 0
      fs-service/src/main/java/com/fs/company/service/ICompanyDeptService.java
  28. 11 0
      fs-service/src/main/java/com/fs/company/service/ICompanyService.java
  29. 16 6
      fs-service/src/main/java/com/fs/company/service/impl/CompanyDeptServiceImpl.java
  30. 8 4
      fs-service/src/main/java/com/fs/company/service/impl/CompanyMenuServiceImpl.java
  31. 2 2
      fs-service/src/main/java/com/fs/company/service/impl/CompanyRoleServiceImpl.java
  32. 433 9
      fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java
  33. 22 0
      fs-service/src/main/java/com/fs/company/vo/DeptDataVO.java
  34. 2 0
      fs-service/src/main/java/com/fs/course/domain/FsVideoResource.java
  35. 1 1
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java
  36. 17 0
      fs-service/src/main/java/com/fs/course/param/FsCourseWatchLogListParam.java
  37. 3 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseRedPacketLogService.java
  38. 78 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseRedPacketLogServiceImpl.java
  39. 6 3
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java
  40. 3 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  41. 2 0
      fs-service/src/main/java/com/fs/course/vo/FsVideoResourceVO.java
  42. 4 0
      fs-service/src/main/java/com/fs/his/mapper/FsStoreOrderMapper.java
  43. 2 2
      fs-service/src/main/java/com/fs/his/service/impl/FsInquiryOrderServiceImpl.java
  44. 5 0
      fs-service/src/main/java/com/fs/his/service/impl/FsPackageServiceImpl.java
  45. 1 1
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
  46. 60 0
      fs-service/src/main/java/com/fs/qw/cache/QwSopCacheService.java
  47. 61 0
      fs-service/src/main/java/com/fs/qw/cache/QwUserCacheService.java
  48. 12 0
      fs-service/src/main/java/com/fs/qw/dto/QwUserDTO.java
  49. 6 1
      fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactMapper.java
  50. 6 0
      fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactTransferLogMapper.java
  51. 6 0
      fs-service/src/main/java/com/fs/qw/mapper/QwFriendWelcomeMapper.java
  52. 6 0
      fs-service/src/main/java/com/fs/qw/mapper/QwGroupChatMapper.java
  53. 39 0
      fs-service/src/main/java/com/fs/qw/mapper/QwUserMapper.java
  54. 11 0
      fs-service/src/main/java/com/fs/qw/param/QwExternalContactParam.java
  55. 12 0
      fs-service/src/main/java/com/fs/qw/param/QwExternalContactTransferLogParam.java
  56. 11 0
      fs-service/src/main/java/com/fs/qw/param/QwFriendWelcomeParam.java
  57. 10 0
      fs-service/src/main/java/com/fs/qw/param/QwGroupChatParam.java
  58. 15 0
      fs-service/src/main/java/com/fs/qw/param/QwUserListParam.java
  59. 1 2
      fs-service/src/main/java/com/fs/qw/service/IQwGroupChatService.java
  60. 5 0
      fs-service/src/main/java/com/fs/qw/service/IQwUserService.java
  61. 22 21
      fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java
  62. 8 4
      fs-service/src/main/java/com/fs/qw/service/impl/QwGroupChatServiceImpl.java
  63. 12 0
      fs-service/src/main/java/com/fs/qw/service/impl/QwUserServiceImpl.java
  64. 1 0
      fs-service/src/main/java/com/fs/qw/vo/QwUserVO.java
  65. 24 0
      fs-service/src/main/java/com/fs/sop/domain/QwSop.java
  66. 2 0
      fs-service/src/main/java/com/fs/sop/domain/QwSopLogs.java
  67. 14 0
      fs-service/src/main/java/com/fs/sop/mapper/QwSopLogsMapper.java
  68. 57 0
      fs-service/src/main/java/com/fs/sop/mapper/QwSopMapper.java
  69. 24 0
      fs-service/src/main/java/com/fs/sop/mapper/SopUserLogsMapper.java
  70. 12 0
      fs-service/src/main/java/com/fs/sop/params/GetSOPTaskDataParam.java
  71. 6 0
      fs-service/src/main/java/com/fs/sop/service/IQwSopService.java
  72. 58 4
      fs-service/src/main/java/com/fs/sop/service/impl/QwSopServiceImpl.java
  73. 28 0
      fs-service/src/main/java/com/fs/sop/vo/QwSopTask.java
  74. 14 0
      fs-service/src/main/java/com/fs/statis/IFsStatisQwWatchService.java
  75. 6 3
      fs-service/src/main/java/com/fs/statis/domain/FsStatisPeriodWatch.java
  76. 47 0
      fs-service/src/main/java/com/fs/statis/domain/FsStatisQwTempParam.java
  77. 190 0
      fs-service/src/main/java/com/fs/statis/domain/FsStatisQwWatch.java
  78. 52 2
      fs-service/src/main/java/com/fs/statis/domain/FsStatisSalerWatch.java
  79. 157 0
      fs-service/src/main/java/com/fs/statis/domain/FsStatisSopWatch.java
  80. 41 0
      fs-service/src/main/java/com/fs/statis/domain/FsStatisTempFsuser.java
  81. 59 0
      fs-service/src/main/java/com/fs/statis/domain/FsStatisTempParam.java
  82. 24 0
      fs-service/src/main/java/com/fs/statis/domain/FsTempPeriodQuery.java
  83. 23 0
      fs-service/src/main/java/com/fs/statis/dto/FsStatisQwWatchWriteDataDTO.java
  84. 37 0
      fs-service/src/main/java/com/fs/statis/dto/StatsWatchLogPageListDTO.java
  85. 15 0
      fs-service/src/main/java/com/fs/statis/dto/WatchCourseStatisticsDTO.java
  86. 172 0
      fs-service/src/main/java/com/fs/statis/impl/FsStatisQwWatchServiceImpl.java
  87. 8 0
      fs-service/src/main/java/com/fs/statis/mapper/FsStatisPeriodWatchMapper.java
  88. 116 0
      fs-service/src/main/java/com/fs/statis/mapper/FsStatisQwTempParamMapper.java
  89. 97 0
      fs-service/src/main/java/com/fs/statis/mapper/FsStatisQwWatchMapper.java
  90. 31 0
      fs-service/src/main/java/com/fs/statis/mapper/FsStatisSalerWatchMapper.java
  91. 68 0
      fs-service/src/main/java/com/fs/statis/mapper/FsStatisTempFsuserMapper.java
  92. 85 0
      fs-service/src/main/java/com/fs/statis/mapper/FsStatisTempParamMapper.java
  93. 58 0
      fs-service/src/main/java/com/fs/statis/mapper/FsTempPeriodQueryMapper.java
  94. 22 0
      fs-service/src/main/java/com/fs/statis/param/WatchCourseStatisticsParam.java
  95. 0 47
      fs-service/src/main/java/com/fs/statis/service/FsStatisEveryDayWatchService.java
  96. 0 56
      fs-service/src/main/java/com/fs/statis/service/FsStatisPeriodWatchService.java
  97. 15 1
      fs-service/src/main/java/com/fs/statis/service/FsStatisSalerWatchService.java
  98. 2 6
      fs-service/src/main/java/com/fs/statis/service/IStatisticsService.java
  99. 0 70
      fs-service/src/main/java/com/fs/statis/service/impl/FsStatisEveryDayWatchServiceImpl.java
  100. 0 81
      fs-service/src/main/java/com/fs/statis/service/impl/FsStatisPeriodWatchServiceImpl.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);
     }
 

+ 57 - 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
     {
 
@@ -240,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());
+                                }
                             }
-                        }
 
+                        }
                     }
                 }
             }
+
         }
 
 
@@ -966,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);
+    }
+
+}

+ 13 - 2
fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -1,5 +1,6 @@
 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;
@@ -7,6 +8,7 @@ import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.utils.StringUtils;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.service.ICompanyUserService;
+import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsUserCoursePeriod;
 import com.fs.course.param.FsCourseLinkCreateParam;
 import com.fs.course.param.FsWatchCourseTimeParam;
@@ -17,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;
@@ -51,6 +55,8 @@ public class FsUserCourseVideoController extends AppBaseController {
 
     @Autowired
     private IFsUserCourseService fsUserCourseService;
+    @Autowired
+    private ISysConfigService configService;
 
     @Autowired
     private IFsCourseLinkService courseLinkService;
@@ -158,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);

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

@@ -77,7 +77,8 @@ 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();
+        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));

+ 12 - 0
fs-company/src/main/java/com/fs/company/controller/course/FsCourseRedPacketLogController.java

@@ -194,6 +194,18 @@ public class FsCourseRedPacketLogController extends BaseController
         return toAjax(fsCourseRedPacketLogService.deleteFsCourseRedPacketLogByLogIds(logIds));
     }
 
+
+    /**
+     * 删除短链课程看课记录
+     */
+
+    @Log(title = "短链课程看课记录", businessType = BusinessType.DELETE)
+    @PutMapping("/retryCourseRedPacketLog/{logIds}")
+    public AjaxResult retryCourseRedPacketLog(@PathVariable Long[] logIds)
+    {
+        return toAjax(fsCourseRedPacketLogService.retryCourseRedPacketLog(logIds));
+    }
+
     @GetMapping("/courseList")
     public R courseList()
     {

+ 52 - 22
fs-company/src/main/java/com/fs/company/controller/course/FsCourseWatchLogController.java

@@ -7,6 +7,7 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.service.impl.CompanyDeptServiceImpl;
 import com.fs.course.domain.FsCourseWatchLog;
 import com.fs.course.param.FsCourseOverParam;
 import com.fs.course.param.FsCourseUserStatisticsListParam;
@@ -49,6 +50,10 @@ public class FsCourseWatchLogController extends BaseController
     private SopUserLogsMapper sopUserLogsMapper;
     @Autowired
     private IQwWatchLogService qwWatchLogService;
+
+    @Autowired
+    private CompanyDeptServiceImpl companyDeptService;
+
     /**
      * 查询短链课程看课记录列表
      */
@@ -56,14 +61,6 @@ public class FsCourseWatchLogController extends BaseController
     @GetMapping("/list")
     public TableDataInfo list(FsCourseWatchLogListParam param)
     {
-
-//        if (param.getScheduleStartTime() != null && param.getScheduleEndTime() != null){
-//            List<String> sopUserLogsVOS = sopUserLogsMapper.selectSopUserLogsByDate(param.getScheduleStartTime(), param.getScheduleEndTime());
-//            param.setSopIds(sopUserLogsVOS);
-//            if (sopUserLogsVOS==null||sopUserLogsVOS.size()==0){
-//                return getDataTable(new ArrayList<>());
-//            }
-//        }
         startPage();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setCompanyId( loginUser.getCompany().getCompanyId());
@@ -71,6 +68,53 @@ public class FsCourseWatchLogController extends BaseController
         return getDataTable(list);
     }
 
+
+    /**
+     * 查询短链课程 我的部门 看课记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:deptList')")
+    @GetMapping("/deptList")
+    public TableDataInfo deptList(FsCourseWatchLogListParam param) {
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+
+
+        List<Long> combinedList = new ArrayList<>();
+        //本部门
+        Long deptId = loginUser.getUser().getDeptId();
+        if (deptId!=null){
+            combinedList.add(deptId);
+        }
+        //本部门的下级部门
+        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        if (!deptList.isEmpty()){
+            combinedList.addAll(deptList);
+        }
+
+        param.setCuDeptIdList(combinedList);
+        param.setUserType(loginUser.getUser().getUserType());
+        param.setCompanyId(loginUser.getCompany().getCompanyId());
+
+        startPage();
+        List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVO(param);
+
+        return getDataTable(list);
+    }
+    /**
+     * 查询短链课程看课记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:myList')")
+    @GetMapping("/myList")
+    public TableDataInfo myList(FsCourseWatchLogListParam param)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        param.setCompanyUserId( loginUser.getUser().getUserId());
+        List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVO(param);
+        return getDataTable(list);
+    }
+
+
     @PreAuthorize("@ss.hasPermi('course:courseWatchLog:statisticsList')")
     @GetMapping("/statisticsList")
     public TableDataInfo statisticsList(FsCourseWatchLogStatisticsListParam param)
@@ -171,20 +215,6 @@ public class FsCourseWatchLogController extends BaseController
 
 
 
-    /**
-     * 查询短链课程看课记录列表
-     */
-    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:myList')")
-    @GetMapping("/myList")
-    public TableDataInfo myList(FsCourseWatchLogListParam param)
-    {
-        startPage();
-        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        param.setCompanyUserId( loginUser.getUser().getUserId());
-        List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVO(param);
-        return getDataTable(list);
-    }
-
     /**
      * 导出短链课程看课记录列表
      */

+ 53 - 0
fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactController.java

@@ -10,6 +10,7 @@ import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.service.impl.CompanyDeptServiceImpl;
 import com.fs.course.param.FsUserCourseListUParam;
 import com.fs.course.service.IFsUserCourseStudyService;
 import com.fs.course.vo.FsUserCourseStudyListUVO;
@@ -38,6 +39,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
@@ -72,6 +74,10 @@ public class QwExternalContactController extends BaseController
 
     @Autowired
     private IQwExternalContactInfoService qwExternalContactInfoService;
+
+    @Autowired
+    private CompanyDeptServiceImpl companyDeptService;
+
     /**
      * 查询企业微信客户列表
      */
@@ -122,6 +128,53 @@ public class QwExternalContactController extends BaseController
         return qwExternalContactService.syncQwExternalContact(qwExternalContact.getCorpId());
     }
 
+    /**
+     * 我的部门客户
+     */
+    @PreAuthorize("@ss.hasPermi('qw:externalContact:myDeptExtList')")
+    @GetMapping("/myDeptExtList")
+    public TableDataInfo myDeptExtList(QwExternalContactParam qwExternalContact)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+
+        List<Long> combinedList = new ArrayList<>();
+        //本部门
+        Long deptId = loginUser.getUser().getDeptId();
+        if (deptId!=null){
+            combinedList.add(deptId);
+        }
+        //本部门的下级部门
+        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        if (!deptList.isEmpty()){
+            combinedList.addAll(deptList);
+        }
+
+        qwExternalContact.setCuDeptIdList(combinedList);
+        qwExternalContact.setUserType(loginUser.getUser().getUserType());
+        qwExternalContact.setCompanyId(loginUser.getCompany().getCompanyId());
+
+        startPage();
+        List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(qwExternalContact);
+        list.forEach(item->{
+
+            if (!Objects.equals(item.getTagIds(), "[]") && item.getTagIds()!=null) {
+                QwTagSearchParam param = new QwTagSearchParam();
+                Gson gson = new Gson();
+                List<String> tagIds = gson.fromJson(
+                        item.getTagIds(),
+                        new TypeToken<List<String>>() {
+                        }.getType()
+                );
+
+                param.setTagIds(tagIds);
+
+                item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
+            }
+        });
+
+        return getDataTable(list);
+    }
+
     @PreAuthorize("@ss.hasPermi('qw:externalContact:myList')")
     @GetMapping("/myList")
     public TableDataInfo myList(QwExternalContactParam qwExternalContact)

+ 35 - 0
fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactTransferLogController.java

@@ -8,6 +8,7 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.service.impl.CompanyDeptServiceImpl;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 import com.fs.qw.domain.QwExternalContactTransferLog;
@@ -18,6 +19,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -32,8 +34,13 @@ public class QwExternalContactTransferLogController extends BaseController
 {
     @Autowired
     private IQwExternalContactTransferLogService qwExternalContactTransferLogService;
+
     @Autowired
     private TokenService tokenService;
+
+    @Autowired
+    private CompanyDeptServiceImpl companyDeptService;
+
     /**
      * 查询转接记录列表
      */
@@ -50,6 +57,34 @@ public class QwExternalContactTransferLogController extends BaseController
         return getDataTable(list);
     }
 
+    /**
+     * 查询部门转接记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:externalContactTransferLog:deptList')")
+    @GetMapping("/deptList")
+    public TableDataInfo deptList(QwExternalContactTransferLogParam qwExternalContactTransferLog)
+    {
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        List<Long> combinedList = new ArrayList<>();
+        //本部门
+        Long deptId = loginUser.getUser().getDeptId();
+        if (deptId!=null){
+            combinedList.add(deptId);
+        }
+        //本部门的下级部门
+        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        if (!deptList.isEmpty()){
+            combinedList.addAll(deptList);
+        }
+        qwExternalContactTransferLog.setCuDeptIdList(combinedList);
+        qwExternalContactTransferLog.setUserType(loginUser.getUser().getUserType());
+
+        startPage();
+        List<QwExternalContactTransferLogListVO> list = qwExternalContactTransferLogService.selectQwExternalContactTransferLogListVO(qwExternalContactTransferLog);
+        return getDataTable(list);
+    }
+
     @PreAuthorize("@ss.hasPermi('qw:externalContactTransferLog:myList')")
     @GetMapping("/myList")
     public TableDataInfo myList(QwExternalContactTransferLogParam qwExternalContactTransferLog)

+ 37 - 4
fs-company/src/main/java/com/fs/company/controller/qw/QwFriendWelcomeController.java

@@ -10,6 +10,7 @@ import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.impl.CompanyDeptServiceImpl;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 import com.fs.qw.domain.QwFriendWelcome;
@@ -22,10 +23,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -46,6 +44,10 @@ public class QwFriendWelcomeController extends BaseController
 
     @Autowired
     private IQwUserService qwUserService;
+
+    @Autowired
+    private CompanyDeptServiceImpl companyDeptService;
+
     /**
      * 查询好友欢迎语列表
      */
@@ -61,6 +63,37 @@ public class QwFriendWelcomeController extends BaseController
         return getDataTable(list);
     }
 
+
+    /**
+     * 查询部门好友欢迎语列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:friendWelcome:deptList')")
+    @GetMapping("/deptList")
+    public TableDataInfo deptList(QwFriendWelcomeParam qwFriendWelcomeParam)
+    {
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        qwFriendWelcomeParam.setCompanyId(loginUser.getCompany().getCompanyId());
+        List<Long> combinedList = new ArrayList<>();
+        //本部门
+        Long deptId = loginUser.getUser().getDeptId();
+        if (deptId!=null){
+            combinedList.add(deptId);
+        }
+        //本部门的下级部门
+        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        if (!deptList.isEmpty()){
+            combinedList.addAll(deptList);
+        }
+        qwFriendWelcomeParam.setCuDeptIdList(combinedList);
+        qwFriendWelcomeParam.setUserType(loginUser.getUser().getUserType());
+
+        startPage();
+        List<QwFriendWelcome> list = qwFriendWelcomeService.selectQwFriendWelcomeListMyVO(qwFriendWelcomeParam);
+        return getDataTable(list);
+    }
+
+
     /**
      * 查询好友欢迎语列表
      */

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

@@ -4,9 +4,13 @@ import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.utils.ServletUtils;
+import com.fs.company.service.impl.CompanyDeptServiceImpl;
+import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 import com.fs.qw.param.QwGroupChatParam;
 import com.fs.qw.service.IQwGroupChatService;
+import com.fs.qw.service.IQwUserService;
 import com.fs.qw.vo.QwGroupChatOptionsVO;
 import com.fs.qw.vo.QwGroupChatVO;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -16,6 +20,7 @@ import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -33,6 +38,14 @@ public class QwGroupChatController extends BaseController
 
     @Autowired
     private TokenService tokenService;
+
+    @Autowired
+    private CompanyDeptServiceImpl companyDeptService;
+
+
+    @Autowired
+    private IQwUserService iQwUserService;
+
     /**
      * 查询客户群详情列表
      */
@@ -45,6 +58,35 @@ public class QwGroupChatController extends BaseController
         return getDataTable(list);
     }
 
+    /**
+     * 查询我的部门客户群详情列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:groupChat:deptList')")
+    @GetMapping("/deptList")
+    public TableDataInfo deptList(QwGroupChatParam qwGroupChat)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+
+        List<Long> combinedList = new ArrayList<>();
+        //本部门
+        Long deptId = loginUser.getUser().getDeptId();
+        if (deptId!=null){
+            combinedList.add(deptId);
+        }
+        //本部门的下级部门
+        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        if (!deptList.isEmpty()){
+            combinedList.addAll(deptList);
+        }
+        qwGroupChat.setCuDeptIdList(combinedList);
+        qwGroupChat.setUserType(loginUser.getUser().getUserType());
+
+
+        startPage();
+        List<QwGroupChatVO> list = qwGroupChatService.selectQwGroupChatList(qwGroupChat);
+        return getDataTable(list);
+    }
+
 
     /**
      * 我的-查询客户群详情列表
@@ -53,6 +95,9 @@ public class QwGroupChatController extends BaseController
     @GetMapping("/myList")
     public TableDataInfo myList(QwGroupChatParam qwGroupChat)
     {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        qwGroupChat.setCompanyId(loginUser.getCompany().getCompanyId());
+        qwGroupChat.setCompanyUserId(loginUser.getUser().getUserId());
         startPage();
         List<QwGroupChatVO> list = qwGroupChatService.selectQwGroupChatList(qwGroupChat);
         return getDataTable(list);
@@ -77,8 +122,21 @@ public class QwGroupChatController extends BaseController
 
 //        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
 //        Long companyId = loginUser.getCompany().getCompanyId();
+        List<String> qwUserIdList=new ArrayList<>();
+        return qwGroupChatService.cogradientGroupChat(corpId,qwUserIdList);
+    }
+
+    /**
+     *  同步 我的客户群信息
+     */
+    @GetMapping("/cogradientMyGroupChat/{corpId}")
+    public R cogradientMyGroupChat(@PathVariable("corpId") String corpId) throws Exception {
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+
+        List<String> qwUserIdList = iQwUserService.selectQwUserListByCompanyUserId(loginUser.getUser().getUserId(), corpId);
 
-        return qwGroupChatService.cogradientGroupChat(corpId);
+        return qwGroupChatService.cogradientGroupChat(corpId,qwUserIdList);
     }
 
     @GetMapping("/allList/{corpId}")

+ 71 - 14
fs-company/src/main/java/com/fs/company/controller/qw/QwSopController.java

@@ -9,6 +9,7 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.service.impl.CompanyDeptServiceImpl;
 import com.fs.course.mapper.FsUserCourseMapper;
 import com.fs.course.mapper.FsUserCourseVideoMapper;
 import com.fs.framework.security.LoginUser;
@@ -28,6 +29,7 @@ import org.springframework.web.bind.annotation.*;
 
 import java.io.IOException;
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
@@ -55,6 +57,13 @@ public class QwSopController extends BaseController
     private FsUserCourseVideoMapper fsUserCourseVideoMapper;
     @Autowired
     private ICompanySopRoleService companySopRoleService;
+
+    @Autowired
+    private CompanyDeptServiceImpl companyDeptService;
+
+    @Autowired
+    private IQwUserService iQwUserService;
+
     /**
      * 查询企微sop列表
      */
@@ -70,6 +79,67 @@ public class QwSopController extends BaseController
         return getDataTable(list);
     }
 
+    /**
+     * 查询部门企微sop列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:sop:deptList')")
+    @GetMapping("/deptList")
+    public TableDataInfo deptList(QwSop qwSop)
+    {
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        qwSop.setCompanyId(loginUser.getCompany().getCompanyId());
+
+        List<Long> combinedList = new ArrayList<>();
+        //本部门
+        Long deptId = loginUser.getUser().getDeptId();
+        if (deptId!=null){
+            combinedList.add(deptId);
+        }
+        //本部门的下级部门
+        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        if (!deptList.isEmpty()){
+            combinedList.addAll(deptList);
+        }
+        qwSop.setCuDeptIdList(combinedList);
+        qwSop.setUserType(loginUser.getUser().getUserType());
+
+        List<Long> userIds = iQwUserService.selectQwUserListByCuDeptIdList(qwSop);
+
+        qwSop.setQwUserIdList(userIds);
+
+        startPage();
+        List<QwSop> list = qwSopService.selectQwSopMyList(qwSop);
+        return getDataTable(list);
+    }
+
+
+
+    /**
+     * 查询企微sop列表-我的
+     */
+    @PreAuthorize("@ss.hasPermi('qw:sop:myList')")
+    @GetMapping("/myList")
+    public TableDataInfo myList(QwSop qwSop)
+    {
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        qwSop.setCompanyId( loginUser.getCompany().getCompanyId());
+        qwSop.setUserId(loginUser.getUser().getUserId());
+        List<Long> userIds = iQwUserService.selectQwUserListByCuDeptIdList(qwSop);
+        qwSop.setQwUserIdList(userIds);
+
+        List<QwSop> list=new ArrayList<>();
+
+        if (userIds.isEmpty()){
+            return  getDataTable(list);
+        }
+
+        startPage();
+        list = qwSopService.selectQwSopMyList(qwSop);
+        return getDataTable(list);
+    }
+
     /**
      * 查询aiChatsop列表
      */
@@ -97,20 +167,7 @@ public class QwSopController extends BaseController
         List<OptionsVO> optionsVOS = fsUserCourseVideoMapper.selectFsUserCourseVodeAllList(id);
         return R.ok().put("list", optionsVOS);
     }
-    /**
-     * 查询企微sop列表-我的
-     */
-    @PreAuthorize("@ss.hasPermi('qw:sop:myList')")
-    @GetMapping("/myList")
-    public TableDataInfo myList(QwSop qwSop)
-    {
-        startPage();
-        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        qwSop.setCompanyId( loginUser.getCompany().getCompanyId());
-        qwSop.setQwUserIds(String.valueOf(loginUser.getUser().getQwUserId()));
-        List<QwSop> list = qwSopService.selectQwSopMyList(qwSop);
-        return getDataTable(list);
-    }
+
     /**
      * 导出企微sop列表
      */

+ 35 - 4
fs-company/src/main/java/com/fs/company/controller/qw/QwUserController.java

@@ -18,6 +18,7 @@ import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.company.service.ICompanyUserService;
+import com.fs.company.service.impl.CompanyDeptServiceImpl;
 import com.fs.fastGpt.domain.FastGptRole;
 import com.fs.fastGpt.mapper.FastGptRoleMapper;
 import com.fs.framework.manager.AsyncManager;
@@ -51,10 +52,7 @@ import org.springframework.security.core.Authentication;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -96,6 +94,9 @@ public class QwUserController extends BaseController
     @Resource
     private AuthenticationManager authenticationManager;
 
+    @Autowired
+    private CompanyDeptServiceImpl companyDeptService;
+
     /**
      * 查询企微员工列表
      */
@@ -111,6 +112,36 @@ public class QwUserController extends BaseController
         return getDataTable(list);
     }
 
+    /**
+     * 查询我的部门 企业微信员工列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:user:myDepartList')")
+    @GetMapping("/myDepartList")
+    public TableDataInfo myDepartList(QwUserListParam qwUser)
+    {
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        qwUser.setCompanyId(loginUser.getCompany().getCompanyId());
+        qwUser.setUserType(loginUser.getUser().getUserType());
+        List<Long> combinedList = new ArrayList<>();
+        //本部门
+        Long deptId = loginUser.getUser().getDeptId();
+        if (deptId!=null){
+            combinedList.add(deptId);
+        }
+        //本部门的下级部门
+        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        if (!deptList.isEmpty()){
+            combinedList.addAll(deptList);
+        }
+        qwUser.setCuDeptIdList(combinedList);
+        qwUser.setUserType(loginUser.getUser().getUserType());
+
+        startPage();
+        List<QwUserVO> list = qwUserService.selectQwUserListStaffVO(qwUser);
+        return getDataTable(list);
+    }
+
     @PreAuthorize("@ss.hasPermi('qw:user:login')")
     @PostMapping("/loginQwIpad")
     public R loginQwIpad(@RequestBody QwLoginHookParam loginParam){

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

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

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

+ 28 - 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);
     /**
      * 新增部门
      *
@@ -54,6 +67,7 @@ public interface CompanyDeptMapper
      */
     public int deleteCompanyDeptById(Long deptId);
 
+
     /**
      * 批量删除部门
      *
@@ -83,12 +97,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);
 
     /**
      * 获取公司默认部门

+ 11 - 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,6 +116,16 @@ 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);
     }
-
     /**
      * 递归列表
      */

+ 8 - 4
fs-service/src/main/java/com/fs/company/service/impl/CompanyMenuServiceImpl.java

@@ -140,8 +140,11 @@ public class CompanyMenuServiceImpl implements ICompanyMenuService
             // 如果是顶级节点, 遍历该父节点的所有子节点
             if (!tempList.contains(menu.getParentId()))
             {
-                recursionFn(menus, menu);
-                returnList.add(menu);
+                // 如果正常
+                if("0".equals(menu.getStatus())){
+                    recursionFn(menus, menu);
+                    returnList.add(menu);
+                }
             }
         }
         if (returnList.isEmpty())
@@ -233,7 +236,6 @@ public class CompanyMenuServiceImpl implements ICompanyMenuService
         else
         {
             menu.getParams().put("userId", userId);
-//            menu.setStatus("0");
             menuList = companyMenuMapper.selectCompanyMenuList(menu);
         }
         return menuList;
@@ -300,7 +302,9 @@ public class CompanyMenuServiceImpl implements ICompanyMenuService
             CompanyMenu n = (CompanyMenu) it.next();
             if (n.getParentId().longValue() == t.getMenuId().longValue())
             {
-                tlist.add(n);
+                if("0".equals(n.getStatus())){
+                    tlist.add(n);
+                }
             }
         }
         return tlist;

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

+ 433 - 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_"+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_"+user.getUserId());
+                                userNode.setChildren(null);
+                                userNodes.add(userNode);
+                            }
+                        } else {
+                            // 非当前部门,显示所有用户
+                            DeptDataVO userNode = new DeptDataVO();
+                            userNode.setLabel(user.getNickName() + "_" + user.getUserName());
+                            userNode.setId("user_"+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_"+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_"+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_"+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_"+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_"+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_"+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_"+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_"+user.getUserId());
+                            userNode.setChildren(null);
+                            children.add(userNode);
+                        }
+                    } else {
+                        DeptDataVO userNode = new DeptDataVO();
+                        userNode.setLabel(user.getNickName()+"_"+user.getUserName());
+                        userNode.setId("user_"+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) {

+ 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 String id;
+    /**
+     * 子节点
+     */
+    private List<DeptDataVO> children;
+}

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

@@ -95,4 +95,6 @@ public class FsVideoResource {
     private Integer isTranscode;//是否转码
 
     private String transcodeFileKey;//转码的文件key
+
+    private Integer sort;
 }

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

@@ -152,7 +152,7 @@ public interface FsUserCourseVideoMapper
     List<FsUserCourseVideo> selectVideoIsPrivate();
     @Select("select * from fs_user_course_video WHERE video_id=#{videoId}")
     FsUserCourseVideo selectFsUserCourseVideoByVideoStringId(String videoId);
-    @Select("select * from fs_user_course_video WHERE course_id=#{courseId}")
+    @Select("select * from fs_user_course_video WHERE course_id=#{courseId} and is_del = 0 order by course_sort,video_id")
     List<FsUserCourseVideo> selectVideoByCourseId(Long courseId);
     @Select("select v.* from fs_user_course_video v " +
             "left join fs_user_course c on c.course_id = v.course_id " +

+ 17 - 0
fs-service/src/main/java/com/fs/course/param/FsCourseWatchLogListParam.java

@@ -54,4 +54,21 @@ public class FsCourseWatchLogListParam implements Serializable {
     private String scheduleEndTime;
 
     private List<String> sopIds;
+
+
+    private Long taskId;//任务ID
+
+    private String customPageStr;
+
+    private Long lastId;
+
+    /**
+     * 销售部门
+     */
+    private List<Long> cuDeptIdList;
+
+    /**
+     * 部门类型 00 管理员 01 员工
+     */
+    private String userType;
 }

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

@@ -79,4 +79,7 @@ public interface IFsCourseRedPacketLogService
     int getCountByCompanyUserIdId(Long userId);
 
     BigDecimal getNewVipRedPackAmountByCompanyUserIdId(Long userId);
+
+    int retryCourseRedPacketLog(Long[] logIds);
+
 }

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

@@ -5,15 +5,26 @@ import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 
+import com.alibaba.fastjson.JSON;
 import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyMoneyLogs;
+import com.fs.company.mapper.CompanyMapper;
+import com.fs.company.mapper.CompanyMoneyLogsMapper;
 import com.fs.course.param.FsCourseRedPacketLogParam;
 import com.fs.course.vo.FsCourseRedPacketLogListPVO;
+import com.fs.his.domain.FsUser;
+import com.fs.his.mapper.FsUserMapper;
+import com.fs.his.param.WxSendRedPacketParam;
+import com.fs.his.service.IFsStorePaymentService;
+import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
 import com.fs.course.domain.FsCourseRedPacketLog;
 import com.fs.course.service.IFsCourseRedPacketLogService;
+import org.springframework.transaction.annotation.Transactional;
 
 /**
  * 短链课程看课记录Service业务层处理
@@ -146,5 +157,72 @@ public class FsCourseRedPacketLogServiceImpl implements IFsCourseRedPacketLogSer
     public BigDecimal getNewVipRedPackAmountByCompanyUserIdId(Long companyUserId) {
         return fsCourseRedPacketLogMapper.getNewVipRedPackAmountByCompanyUserIdId(companyUserId);
     }
+    @Autowired
+    private IFsStorePaymentService paymentService;
+    @Autowired
+    private FsUserMapper fsUserMapper;
+    @Autowired
+    private CompanyMapper companyMapper;
+    @Autowired
+    private CompanyMoneyLogsMapper moneyLogsMapper;
+    @Override
+    @Transactional
+    public int retryCourseRedPacketLog(Long[] logIds) {
+        for (int i = 0; i < logIds.length; i++) {
+            Long id = logIds[i];
+            FsCourseRedPacketLog param = fsCourseRedPacketLogMapper.selectFsCourseRedPacketLogByLogId(id);
+
+
+            if (param!=null&&param.getStatus()==2){
+                Company company = companyMapper.selectCompanyByIdForUpdate(param.getCompanyId());
+                BigDecimal amount = param.getAmount();
+                BigDecimal money = company.getMoney();
+                BigDecimal subtract = money.subtract(amount);
+                if (subtract.compareTo(BigDecimal.ZERO)<0){
+                    return 0;
+                }
+
+
+                WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
+                FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
+                packetParam.setOpenId(user.getMaOpenId());
+                packetParam.setOpenId(user.getCourseMaOpenId());
+                packetParam.setAmount(param.getAmount());
+                packetParam.setSource(2);
+                packetParam.setRedPacketMode(1);
+                packetParam.setCompanyId(param.getCompanyId());
+                R sendRedPacket = paymentService.sendRedPacket(packetParam);
+                if (sendRedPacket.get("code").equals(200)) {
+                    FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
+                    TransferBillsResult transferBillsResult;
+                    if (sendRedPacket.get("isNew").equals(1)){
+                        transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
+                        redPacketLog.setResult(JSON.toJSONString(sendRedPacket));
+                        redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
+                    }else {
+                        redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
+                    }
+                    // 添加红包记录
+                    redPacketLog.setStatus(0);
+                    fsCourseRedPacketLogMapper.updateFsCourseRedPacketLog(redPacketLog);
+                    // 更新观看记录的奖励类型
+
+                    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 0;
+    }
 
 }

+ 6 - 3
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?";
     /**
      * 查询课程
@@ -490,19 +491,21 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
     public R createCourseSortLink(FsCourseLinkCreateParam param) {
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        //短链参数
+        String random = generateRandomString();
 
         //新增链接表信息
         FsCourseLink link = new FsCourseLink();
         BeanUtils.copyProperties(param, link);
         link.setLinkType(0);
         link.setIsRoom(0);
+        link.setLink(random);
 
         FsCourseRealLink courseMap = new FsCourseRealLink();
         BeanUtils.copyProperties(link, courseMap);
         String courseJson = JSON.toJSONString(courseMap);
-
         link.setRealLink(realLink + courseJson);
-        String random = generateRandomString();
+
         link.setLink(random);
         link.setCreateTime(new Date());
 

+ 3 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -1487,6 +1487,9 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     @Override
     public void batchSaveVideo(BatchVideoSvae vo) {
         List<FsVideoResource> videoResourceList = fsVideoResourceMapper.selectBatchIds(vo.getIds());
+        videoResourceList = videoResourceList.stream()
+                .sorted(Comparator.comparing(FsVideoResource::getSort).thenComparing(FsVideoResource::getId))
+                .collect(Collectors.toList());
         FsUserCourseVideo param = new FsUserCourseVideo();
         param.setCourseId(vo.getCourseId());
         List<FsUserCourseVideo> videoList = selectFsUserCourseVideoList(param);

+ 2 - 0
fs-service/src/main/java/com/fs/course/vo/FsVideoResourceVO.java

@@ -85,4 +85,6 @@ public class FsVideoResourceVO {
      * 课程ID
      */
     private String projectIds;
+
+    private Integer sort;
 }

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

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

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

+ 6 - 1
fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactMapper.java

@@ -256,7 +256,12 @@ public interface QwExternalContactMapper extends BaseMapper<QwExternalContact> {
             "            <if test=\"sTime != null \">  and DATE(ec.create_time) &gt;= DATE(#{sTime})</if>\n" +
             "            <if test=\"eTime != null \">  and DATE(ec.create_time) &lt;= DATE(#{eTime})</if>\n" +
             "            <if test=\"companyUserName != null  and companyUserName != ''\"> and cu.user_name = #{companyUserName}</if>\n" +
-
+            "            <if test=\"cuDeptIdList != null and !cuDeptIdList.isEmpty() and  userType != '00' \">" +
+            "               AND cur.dept_id IN " +
+            "                   <foreach collection='cuDeptIdList' item='item' open='(' separator=',' close=')'> " +
+            "                       #{item} " +
+            "                   </foreach> " +
+            "            </if>" +
             "<if test ='companyUser!=null'> " +
                 "and (cu.nick_name like concat('%', #{companyUser}, '%') or cu.phonenumber= #{companyUser})"+
             "</if> " +

+ 6 - 0
fs-service/src/main/java/com/fs/qw/mapper/QwExternalContactTransferLogMapper.java

@@ -100,6 +100,12 @@ public interface QwExternalContactTransferLogMapper
             "            <if test=\"customerId != null \"> and l.customer_id = #{customerId}</if>\n" +
             "            <if test=\"externalContactId != null \"> and l.external_contact_id = #{externalContactId}</if>\n" +
             "            <if test=\"status != null  and status != ''\"> and l.status = #{status}</if>\n" +
+            "            <if test=\"cuDeptIdList != null and !cuDeptIdList.isEmpty() and  userType != '00' \">" +
+            "               AND cu.dept_id IN " +
+            "                   <foreach collection='cuDeptIdList' item='item' open='(' separator=',' close=')'> " +
+            "                       #{item} " +
+            "                   </foreach> " +
+            "            </if>" +
             "        </where> " +
             "order by l.create_time desc "+
             "</script>"})

+ 6 - 0
fs-service/src/main/java/com/fs/qw/mapper/QwFriendWelcomeMapper.java

@@ -67,6 +67,12 @@ public interface QwFriendWelcomeMapper
             "            <if test=\"createTime != null \"> and qfw.create_time = #{createTime}</if>\n" +
             "            <if test=\"updateTime != null \"> and qfw.update_time = #{updateTime}</if>\n" +
             "            <if test=\"companyUserId != null \"> and qu.company_user_id = #{companyUserId}</if>\n" +
+            "            <if test=\"cuDeptIdList != null and !cuDeptIdList.isEmpty() and  userType != '00' \">" +
+            "               AND cu.dept_id IN " +
+            "                   <foreach collection='cuDeptIdList' item='item' open='(' separator=',' close=')'> " +
+            "                       #{item} " +
+            "                   </foreach> " +
+            "            </if>" +
             "        </where>" +
             "</script>")
     public List<QwFriendWelcome> selectQwFriendWelcomeListMyVO(QwFriendWelcomeParam qwFriendWelcomeParam);

+ 6 - 0
fs-service/src/main/java/com/fs/qw/mapper/QwGroupChatMapper.java

@@ -66,6 +66,12 @@ public interface QwGroupChatMapper
             "           and gc.owner in " +
             "                   <foreach  item='item' index='index' collection='qwUserIds' open='(' separator=',' close=')'> #{item}   </foreach> " +
             "           </if>" +
+            "            <if test=\"map.cuDeptIdList != null and !map.cuDeptIdList.isEmpty() and  map.userType != '00' \">" +
+            "               AND cu.dept_id IN " +
+            "                   <foreach collection='map.cuDeptIdList' item='item' open='(' separator=',' close=')'> " +
+            "                       #{item} " +
+            "                   </foreach> " +
+            "            </if>" +
             "        </where>" +
             "GROUP BY " +
             "    gc.chat_id, cu.nick_name,qu.qw_user_name   " +

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

@@ -5,9 +5,11 @@ 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.*;
+import com.fs.sop.domain.QwSop;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.ibatis.annotations.MapKey;
 import org.apache.ibatis.annotations.Param;
@@ -150,6 +152,12 @@ public interface QwUserMapper extends BaseMapper<QwUser>
             "            <if test=\"qwUserName != null  and qwUserName != ''\"> and qu.qw_user_name like concat( #{qwUserName}, '%') </if> " +
             "            <if test=\"corpId != null \"> and qu.corp_id = #{corpId}</if>\n" +
             "            <if test=\"companyId != null \"> and qu.company_id = #{companyId}</if>\n " +
+            "            <if test=\"cuDeptIdList != null and !cuDeptIdList.isEmpty() and  userType != '00' \">" +
+            "               AND cu.dept_id IN " +
+            "                   <foreach collection='cuDeptIdList' item='item' open='(' separator=',' close=')'> " +
+            "                       #{item} " +
+            "                   </foreach> " +
+            "            </if>" +
             "ORDER BY  qu.login_status asc,qu.tool_status desc " +
             "</script>"})
     List<QwUserVO> selectQwUserListStaffVO(QwUserListParam qwUser);
@@ -376,4 +384,35 @@ 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);
+
+    @Select("select qw_user_id from qw_user where company_user_id = #{userId} and corp_id = #{corpId}")
+    List<String> selectQwUserListByCompanyUserId(@Param("userId") Long userId,@Param("corpId") String corpId);
+
+    @Select("<script>" +
+            "select qu.id from qw_user qu " +
+            "left join company_user cu on cu.user_id=qu.company_user_id " +
+            "where 1=1 " +
+            "            <if test=\"map.corpId != null \"> and qu.corp_id = #{map.corpId}</if>\n" +
+            "            <if test=\"map.userId != null \"> and qu.company_user_id = #{map.userId}</if>\n " +
+            "            <if test=\"map.cuDeptIdList != null and !map.cuDeptIdList.isEmpty() and  map.userType != '00' \">" +
+            "               AND cu.dept_id IN " +
+            "                   <foreach collection='map.cuDeptIdList' item='item' open='(' separator=',' close=')'> " +
+            "                       #{item} " +
+            "                   </foreach> " +
+            "            </if>" +
+            "</script>")
+    List<Long> selectQwUserListByCuDeptIdList(@Param("map") QwSop qwSop);
+
 }

+ 11 - 0
fs-service/src/main/java/com/fs/qw/param/QwExternalContactParam.java

@@ -111,4 +111,15 @@ public class QwExternalContactParam {
 
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date sTime;
+
+    /**
+     * 销售部门
+     */
+    private List<Long> cuDeptIdList;
+
+    /**
+     * 部门类型 00 管理员 01 员工
+     */
+    private String userType;
+
 }

+ 12 - 0
fs-service/src/main/java/com/fs/qw/param/QwExternalContactTransferLogParam.java

@@ -5,6 +5,7 @@ import com.fs.common.annotation.Excel;
 import lombok.Data;
 
 import java.util.Date;
+import java.util.List;
 
 @Data
 public class QwExternalContactTransferLogParam {
@@ -44,4 +45,15 @@ public class QwExternalContactTransferLogParam {
     private Integer status;
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date createTime;
+
+
+    /**
+     * 销售部门
+     */
+    private List<Long> cuDeptIdList;
+
+    /**
+     * 部门类型 00 管理员 01 员工
+     */
+    private String userType;
 }

+ 11 - 0
fs-service/src/main/java/com/fs/qw/param/QwFriendWelcomeParam.java

@@ -6,6 +6,7 @@ import com.fs.common.core.domain.BaseEntity;
 import lombok.Data;
 
 import java.util.Date;
+import java.util.List;
 
 @Data
 public class QwFriendWelcomeParam extends BaseEntity {
@@ -61,4 +62,14 @@ public class QwFriendWelcomeParam extends BaseEntity {
     /** 部门ID */
     private Long deptId;
 
+    /**
+     * 销售部门
+     */
+    private List<Long> cuDeptIdList;
+
+    /**
+     * 部门类型 00 管理员 01 员工
+     */
+    private String userType;
+
 }

+ 10 - 0
fs-service/src/main/java/com/fs/qw/param/QwGroupChatParam.java

@@ -50,4 +50,14 @@ public class QwGroupChatParam {
     /** 状态集合 */
     private List<String> statusList;
 
+    /**
+     * 销售部门
+     */
+    private List<Long> cuDeptIdList;
+
+    /**
+     * 部门类型 00 管理员 01 员工
+     */
+    private String userType;
+
 }

+ 15 - 0
fs-service/src/main/java/com/fs/qw/param/QwUserListParam.java

@@ -47,4 +47,19 @@ public class QwUserListParam {
 
     private Integer sendType;
 
+    /**
+     * 企业微信李的部门
+     */
+    private Long deptId;
+
+    /**
+     * 销售部门
+     */
+    private List<Long> cuDeptIdList;
+
+    /**
+     * 部门类型 00 管理员 01 员工
+     */
+    private String userType;
+
 }

+ 1 - 2
fs-service/src/main/java/com/fs/qw/service/IQwGroupChatService.java

@@ -10,7 +10,6 @@ import com.fs.qw.vo.QwGroupChatOptionsVO;
 import com.fs.qw.vo.QwGroupChatTransferVO;
 import com.fs.qw.vo.QwGroupChatVO;
 
-import javax.validation.Valid;
 import java.util.List;
 
 /**
@@ -40,7 +39,7 @@ public interface IQwGroupChatService
     /**
      *  同步客户群列表
      */
-    public R cogradientGroupChat(String corpId) throws Exception;
+    public R cogradientGroupChat(String corpId,List<String> qwUserIdList ) throws Exception;
     /**
      * 新增客户群
      *

+ 5 - 0
fs-service/src/main/java/com/fs/qw/service/IQwUserService.java

@@ -9,6 +9,7 @@ import com.fs.qw.vo.QwHookAuthVO;
 import com.fs.qw.vo.QwOptionsVO;
 import com.fs.qw.vo.QwUserVO;
 import com.fs.qw.vo.UserVOs;
+import com.fs.sop.domain.QwSop;
 import org.apache.commons.lang3.tuple.Pair;
 
 import java.util.ArrayList;
@@ -166,6 +167,10 @@ public interface IQwUserService
 
     List<QwWorkTask> selectQwWorkTaskList(SelectQwWorkTaskListParam param);
 
+    List<String> selectQwUserListByCompanyUserId(Long userId,String corpId );
+    List<Long> selectQwUserListByCuDeptIdList(QwSop qwSop);
+
+
     /**
      * 重启云主机
      * @param IP 服务器ip

+ 22 - 21
fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java

@@ -1144,6 +1144,7 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
                     qwTransferCustomerParam.setTakeover_userid(qwUser.getQwUserId());
                     qwTransferCustomerParam.setExternal_userid(Arrays.asList(qwExternalContact.getExternalUserId()));
                     QwTransferCustomerResult qwTransferCustomerResult = qwApiService.transferCustomer(qwTransferCustomerParam, param.getCorpId());
+//                    logger.info("返回:{}",qwTransferCustomerResult);
 
                     if (qwTransferCustomerResult.getErrcode() == 0) {
                         List<QwCustomer> customer = qwTransferCustomerResult.getCustomer();
@@ -1700,27 +1701,27 @@ public class QwExternalContactServiceImpl extends ServiceImpl<QwExternalContactM
         qwExternalContact.setExternalUserId(externalUserID); // 设置外部联系人ID
         qwExternalContact.setCorpId(corpId);
         qwExternalContact.setCreateTime(new Date());
-        if(StringUtils.isNotEmpty(state)){
-            try {
-                AdUploadVo vo = AdUploadVo.builder().state(state).type(AdUploadType.ADD_WX).build();
-                logger.info("上传mq:{}", vo);
-                rocketMQTemplate.syncSend("ad-upload", JSON.toJSONString(vo));
-            }catch (Exception e){
-                logger.error("广告回调上传",e);
-            }
-        }
-        try {
-            new Thread(() -> {
-                try {
-                    Thread.sleep(3000);
-                    rocketMQTemplate.syncSend("repeat-upload", JSON.toJSONString(RepeatUploadVo.builder().type(0).externalUserId(externalUserID).build()));
-                } catch (InterruptedException e) {
-                    logger.error("添加等待时长错误", e);
-                }
-            }).start();
-        }catch (Exception e){
-            logger.error("重粉提交mq失败", e);
-        }
+//        if(StringUtils.isNotEmpty(state)){
+//            try {
+//                AdUploadVo vo = AdUploadVo.builder().state(state).type(AdUploadType.ADD_WX).build();
+//                logger.info("上传mq:{}", vo);
+//                rocketMQTemplate.syncSend("ad-upload", JSON.toJSONString(vo));
+//            }catch (Exception e){
+//                logger.error("广告回调上传",e);
+//            }
+//        }
+//        try {
+//            new Thread(() -> {
+//                try {
+//                    Thread.sleep(3000);
+//                    rocketMQTemplate.syncSend("repeat-upload", JSON.toJSONString(RepeatUploadVo.builder().type(0).externalUserId(externalUserID).build()));
+//                } catch (InterruptedException e) {
+//                    logger.error("添加等待时长错误", e);
+//                }
+//            }).start();
+//        }catch (Exception e){
+//            logger.error("重粉提交mq失败", e);
+//        }
 //        iAdHtmlClickLogService.upload(state, AdUploadType.ADD_WX, e -> finalQwExternalContact.setUploadAddWxStatus(1));
 
         //先入一次库

+ 8 - 4
fs-service/src/main/java/com/fs/qw/service/impl/QwGroupChatServiceImpl.java

@@ -249,21 +249,25 @@ public class QwGroupChatServiceImpl implements IQwGroupChatService
      *  同步客户群列表
      */
     @Override
-    public R cogradientGroupChat(String corpId) throws Exception {
+    public R cogradientGroupChat(String corpId,List<String> qwUserIdList) throws Exception {
 
 //        过滤群主的id集合
-        ArrayList<String> ownerFilterList=new ArrayList<>();
-
+        ArrayList<String> ownerFilterList = new ArrayList<>(qwUserIdList);
         try {
             QwGroupChatListResult qwGroupChatListResult = qwApiService.groupChatList(ownerFilterList, null, corpId);
 
+            if (qwGroupChatListResult.getErrcode()!=0){
+                return R.error(qwGroupChatListResult.getErrmsg());
+            }
             insertGroupChatList(qwGroupChatListResult,corpId,ownerFilterList);
 
         }catch (Exception e){
+            e.printStackTrace();
+            System.out.println("同步客户群列表失败");
             return R.error(e.getMessage());
         }
 
-
+        System.out.println("同步客户群列表成功");
         return R.ok();
 
     }

+ 12 - 0
fs-service/src/main/java/com/fs/qw/service/impl/QwUserServiceImpl.java

@@ -37,6 +37,7 @@ import com.fs.qwApi.domain.QwUserIdResult;
 import com.fs.qwApi.domain.inner.DeptUser;
 import com.fs.qwApi.param.QwOpenidByUserParams;
 import com.fs.qwApi.service.QwApiService;
+import com.fs.sop.domain.QwSop;
 import com.fs.voice.utils.StringUtil;
 import com.fs.wxwork.dto.*;
 import com.fs.wxwork.service.WxWorkService;
@@ -238,6 +239,17 @@ public class QwUserServiceImpl implements IQwUserService
         return qwWorkTasks;
     }
 
+    @Override
+    public List<String> selectQwUserListByCompanyUserId(Long userId, String corpId) {
+        return qwUserMapper.selectQwUserListByCompanyUserId(userId,corpId);
+
+    }
+
+    @Override
+    public List<Long> selectQwUserListByCuDeptIdList(QwSop qwSop) {
+        return qwUserMapper.selectQwUserListByCuDeptIdList(qwSop);
+    }
+
 
     /**
      * 查询企微用户

+ 1 - 0
fs-service/src/main/java/com/fs/qw/vo/QwUserVO.java

@@ -40,6 +40,7 @@ public class QwUserVO {
     private String nickName;
     private String userName;
     private String welcomeText;
+    private Integer isSendMsg;
     /**
     * 活码id
     */

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

@@ -1,12 +1,14 @@
 package com.fs.sop.domain;
 
 import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fs.common.annotation.Excel;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.util.List;
 
 /**
  * 企微sop对象 qw_sop
@@ -113,6 +115,28 @@ public class QwSop implements Serializable
     // 群聊ID
     private String chatId;
 
+
+    /**
+     * 销售id
+     */
+    @TableField(exist = false)
+    private Long userId;
+
+    /**
+     * 销售部门
+     */
+    @TableField(exist = false)
+    private List<Long> cuDeptIdList;
+
+    /**
+     * 部门类型 00 管理员 01 员工
+     */
+    @TableField(exist = false)
+    private String userType;
+
+    @TableField(exist = false)
+    private List<Long> qwUserIdList;
+
     @Excel(name = "开启评论或者弹幕,1-开启评论;2-开启弹幕;3-都关闭")
     private Integer openCommentStatus;
 

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

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

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

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

@@ -4,6 +4,7 @@ import lombok.Data;
 
 import java.io.Serializable;
 import java.util.List;
+import java.util.stream.Collectors;
 
 @Data
 public class StatsWatchLogPageListDTO implements Serializable {
@@ -13,6 +14,29 @@ public class StatsWatchLogPageListDTO implements Serializable {
      */
     private List<String> userIds;
 
+    public List<String> getUserIds() {
+        if (userIds == null || userIds.isEmpty()) {
+            return userIds;
+        }
+
+        return userIds.stream()
+                .map(id -> {
+                    if (id == null) {
+                        return null;
+                    }
+                    // 去除前缀
+                    if (id.startsWith("dept_")) {
+                        return id.substring(5);
+                    } else if (id.startsWith("company_")) {
+                        return id.substring(8);
+                    } else if (id.startsWith("user_")) {
+                        return id.substring(5);
+                    }
+                    return id;
+                })
+                .collect(Collectors.toList());
+    }
+
     /**
      * 开始时间
      */
@@ -27,4 +51,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;
+ }

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

@@ -1,47 +0,0 @@
-package com.fs.statis.service;
-
-import com.fs.statis.domain.FsStatisEveryDayWatch;
-import com.fs.statis.domain.FsStatisSalerWatch;
-import com.fs.statis.dto.StatsWatchLogPageListDTO;
-
-import java.util.List;
-
-/**
- * 每日统计数据服务接口
- */
-public interface FsStatisEveryDayWatchService {
-
-    /**
-     * 根据主键ID查询每日统计数据
-     *
-     * @param id 主键ID
-     * @return 每日统计数据对象,如果不存在则返回null
-     */
-    FsStatisEveryDayWatch findById(Integer id);
-
-    /**
-     * 新增每日统计数据
-     *
-     * @param fsStatisEveryDayWatch 待插入的每日统计数据对象
-     * @return 影响的行数,通常是1表示成功
-     */
-    int create(FsStatisEveryDayWatch fsStatisEveryDayWatch);
-
-    /**
-     * 更新每日统计数据
-     *
-     * @param fsStatisEveryDayWatch 待更新的每日统计数据对象 (必须包含ID)
-     * @return 影响的行数,通常是1表示成功,0表示未找到对应记录
-     */
-    int update(FsStatisEveryDayWatch fsStatisEveryDayWatch);
-
-    /**
-     * 查询所有每日统计数据
-     *
-     * @return 每日统计数据列表
-     */
-    List<FsStatisEveryDayWatch> findAll();
-
-    List<FsStatisSalerWatch> queryList(StatsWatchLogPageListDTO param);
-
-}

+ 0 - 56
fs-service/src/main/java/com/fs/statis/service/FsStatisPeriodWatchService.java

@@ -1,56 +0,0 @@
-package com.fs.statis.service; // 假设Service接口放在此包下
-
-import com.fs.statis.domain.FsStatisPeriodWatch;
-import com.fs.statis.dto.StatsWatchLogPageListDTO;
-
-import java.util.List;
-
-/**
- * 训练营周期统计数据服务接口
- * 对应表 fs_statis_period_watch
- */
-public interface FsStatisPeriodWatchService {
-
-    /**
-     * 根据主键ID查询训练营周期统计数据
-     *
-     * @param id 主键ID
-     * @return 训练营周期统计数据对象,如果不存在则返回null
-     */
-    FsStatisPeriodWatch findById(Integer id);
-
-    /**
-     * 新增训练营周期统计数据
-     *
-     * @param fsStatisPeriodWatch 待插入的训练营周期统计数据对象
-     * @return 影响的行数,通常是1表示成功
-     */
-    int create(FsStatisPeriodWatch fsStatisPeriodWatch);
-
-    /**
-     * 根据主键更新训练营周期统计数据
-     * (只会更新实体中非null的字段)
-     *
-     * @param fsStatisPeriodWatch 待更新的训练营周期统计数据对象 (必须包含ID)
-     * @return 影响的行数,通常是1表示成功,0表示未找到对应记录或未更新任何字段
-     */
-    int updateById(FsStatisPeriodWatch fsStatisPeriodWatch);
-
-    /**
-     * 根据主键ID删除训练营周期统计数据
-     *
-     * @param id 主键ID
-     * @return 影响的行数
-     */
-    int deleteById(Integer id);
-
-    /**
-     * 查询所有训练营周期统计数据
-     *
-     * @return 训练营周期统计数据列表
-     */
-    List<FsStatisPeriodWatch> findAll();
-
-    List<FsStatisPeriodWatch> queryList(StatsWatchLogPageListDTO param);
-
-}

+ 15 - 1
fs-service/src/main/java/com/fs/statis/service/FsStatisSalerWatchService.java

@@ -1,6 +1,8 @@
 package com.fs.statis.service;
 
+import com.fs.statis.domain.FsStatisEveryDayWatch;
 import com.fs.statis.domain.FsStatisSalerWatch;
+import com.fs.statis.domain.FsStatisSopWatch;
 import com.fs.statis.dto.StatsWatchLogPageListDTO;
 
 import java.util.List;
@@ -50,10 +52,22 @@ public interface FsStatisSalerWatchService {
     boolean deleteById(Integer id);
 
     List<FsStatisSalerWatch> queryList(StatsWatchLogPageListDTO param);
+    List<FsStatisSalerWatch> queryPeriodList(StatsWatchLogPageListDTO param);
+    List<FsStatisSalerWatch> queryTodayList(StatsWatchLogPageListDTO param);
+    List<FsStatisSalerWatch> export(StatsWatchLogPageListDTO param);
+    List<FsStatisSopWatch> exportQueryPeriodList(StatsWatchLogPageListDTO param);
+    List<FsStatisEveryDayWatch> exportQueryEveryDayList(StatsWatchLogPageListDTO param);
+
 
 
     /**
      * 写入数据 写入前一天的数据
      */
-    void writeData();
+    void writeData(String date);
+
+    /**
+     * 计算每天的数据
+     */
+    void writeDataToday();
+
 }

+ 2 - 6
fs-service/src/main/java/com/fs/statis/service/IStatisticsService.java

@@ -1,9 +1,8 @@
 package com.fs.statis.service;
 
 import com.fs.statis.dto.*;
-import com.fs.statistics.dto.WatchCourseStatisticsDTO;
 import com.fs.statistics.param.WatchCourseStatisticsParam;
-
+import com.fs.statistics.dto.WatchCourseStatisticsDTO;
 import java.util.List;
 
 /**
@@ -114,9 +113,6 @@ public interface IStatisticsService {
 
     /**
      * 查询看课统计
-     *
-     * @param param
-     * @return
      */
-    public WatchCourseStatisticsDTO queryWatchCourse(WatchCourseStatisticsParam param);
+    WatchCourseStatisticsDTO queryWatchCourse(WatchCourseStatisticsParam param);
 }

+ 0 - 70
fs-service/src/main/java/com/fs/statis/service/impl/FsStatisEveryDayWatchServiceImpl.java

@@ -1,70 +0,0 @@
-package com.fs.statis.service.impl;
-
-import com.fs.statis.domain.FsStatisEveryDayWatch;
-import com.fs.statis.domain.FsStatisSalerWatch;
-import com.fs.statis.dto.StatsWatchLogPageListDTO;
-import com.fs.statis.mapper.FsStatisEveryDayWatchMapper;
-import com.fs.statis.service.FsStatisEveryDayWatchService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.List;
-
-/**
- * 每日统计数据服务实现类
- */
-@Service
-public class FsStatisEveryDayWatchServiceImpl implements FsStatisEveryDayWatchService {
-
-    private final FsStatisEveryDayWatchMapper fsStatisEveryDayWatchMapper;
-
-    /**
-     * 通过构造函数注入Mapper
-     * @param fsStatisEveryDayWatchMapper 每日统计数据Mapper
-     */
-    @Autowired
-    public FsStatisEveryDayWatchServiceImpl(FsStatisEveryDayWatchMapper fsStatisEveryDayWatchMapper) {
-        this.fsStatisEveryDayWatchMapper = fsStatisEveryDayWatchMapper;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public FsStatisEveryDayWatch findById(Integer id) {
-        return fsStatisEveryDayWatchMapper.findById(id);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    @Transactional
-    public int create(FsStatisEveryDayWatch fsStatisEveryDayWatch) {
-        return fsStatisEveryDayWatchMapper.insert(fsStatisEveryDayWatch);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    @Transactional
-    public int update(FsStatisEveryDayWatch fsStatisEveryDayWatch) {
-        return fsStatisEveryDayWatchMapper.update(fsStatisEveryDayWatch);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public List<FsStatisEveryDayWatch> findAll() {
-        return fsStatisEveryDayWatchMapper.findAll();
-    }
-
-    @Override
-    public List<FsStatisSalerWatch> queryList(StatsWatchLogPageListDTO param) {
-        return fsStatisEveryDayWatchMapper.queryList(param);
-    }
-
-}

+ 0 - 81
fs-service/src/main/java/com/fs/statis/service/impl/FsStatisPeriodWatchServiceImpl.java

@@ -1,81 +0,0 @@
-package com.fs.statis.service.impl; // 假设Service实现类放在此包下
-
-import com.fs.statis.domain.FsStatisPeriodWatch;
-import com.fs.statis.dto.StatsWatchLogPageListDTO;
-import com.fs.statis.mapper.FsStatisPeriodWatchMapper;
-import com.fs.statis.service.FsStatisPeriodWatchService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.List;
-
-/**
- * 训练营周期统计数据服务实现类
- */
-@Service
-public class FsStatisPeriodWatchServiceImpl implements FsStatisPeriodWatchService {
-
-    private final FsStatisPeriodWatchMapper fsStatisPeriodWatchMapper;
-
-    /**
-     * 通过构造函数注入Mapper
-     * @param fsStatisPeriodWatchMapper 训练营周期统计数据Mapper
-     */
-    @Autowired
-    public FsStatisPeriodWatchServiceImpl(FsStatisPeriodWatchMapper fsStatisPeriodWatchMapper) {
-        this.fsStatisPeriodWatchMapper = fsStatisPeriodWatchMapper;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public FsStatisPeriodWatch findById(Integer id) {
-        return fsStatisPeriodWatchMapper.selectById(id);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    @Transactional // 标记此方法需要事务管理
-    public int create(FsStatisPeriodWatch fsStatisPeriodWatch) {
-        // 在这里可以添加业务逻辑,例如参数校验等
-        return fsStatisPeriodWatchMapper.insert(fsStatisPeriodWatch);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    @Transactional // 标记此方法需要事务管理
-    public int updateById(FsStatisPeriodWatch fsStatisPeriodWatch) {
-        // 在这里可以添加业务逻辑,例如检查记录是否存在,或在更新前进行特定校验
-        // 注意:Mapper中的updateById是动态SQL,只更新非null字段
-        return fsStatisPeriodWatchMapper.updateById(fsStatisPeriodWatch);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    @Transactional // 标记此方法需要事务管理
-    public int deleteById(Integer id) {
-        // 在这里可以添加业务逻辑,例如检查关联数据等
-        return fsStatisPeriodWatchMapper.deleteById(id);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public List<FsStatisPeriodWatch> findAll() {
-        return fsStatisPeriodWatchMapper.selectAll();
-    }
-
-    @Override
-    public List<FsStatisPeriodWatch> queryList(StatsWatchLogPageListDTO param) {
-        return fsStatisPeriodWatchMapper.queryList(param);
-    }
-}

Some files were not shown because too many files changed in this diff