瀏覽代碼

Merge branch 'master' into bjcz_his_scrm

# Conflicts:
#	fs-admin/src/main/java/com/fs/his/task/Task.java
#	fs-doctor-app/src/main/java/com/fs/app/controller/InquiryOrderController.java
#	fs-service/src/main/java/com/fs/company/vo/CompanyUserImportVO.java
#	fs-service/src/main/java/com/fs/course/config/CourseConfig.java
#	fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
#	fs-service/src/main/java/com/fs/course/param/FsUserCourseOrderDoPayParam.java
#	fs-service/src/main/java/com/fs/course/service/IFsUserCourseService.java
#	fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java
#	fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
#	fs-service/src/main/java/com/fs/his/mapper/FsDoctorMapper.java
#	fs-service/src/main/java/com/fs/his/service/impl/FsPackageOrderServiceImpl.java
#	fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java
#	fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreCartScrmMapper.java
#	fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreProductScrmMapper.java
#	fs-service/src/main/java/com/fs/hisStore/param/FsStorePaymentPayParam.java
#	fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java
#	fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreProductScrmServiceImpl.java
#	fs-service/src/main/java/com/fs/hisStore/vo/FsStoreProductListVO.java
#	fs-service/src/main/resources/application-config-druid-jnlzjk.yml
#	fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml
#	fs-service/src/main/resources/mapper/hisStore/FsStoreOrderItemScrmMapper.xml
#	fs-user-app/src/main/java/com/fs/app/controller/InquiryOrderController.java
#	fs-user-app/src/main/java/com/fs/app/controller/PatientController.java
#	fs-user-app/src/main/java/com/fs/app/controller/course/CourseFsUserController.java
#	fs-user-app/src/main/java/com/fs/app/controller/store/CompanyUserScrmController.java
#	fs-user-app/src/main/java/com/fs/app/controller/store/WxUserScrmController.java
#	fs-user-app/src/main/resources/application.yml
吴树波 1 周之前
父節點
當前提交
9769f689b2
共有 100 個文件被更改,包括 4647 次插入369 次删除
  1. 1 0
      DirectoryV3.xml
  2. 37 0
      fs-ad-api/src/main/java/com/fs/framework/config/RedisConfig.java
  3. 682 36
      fs-admin/src/main/java/com/fs/api/controller/IndexStatisticsController.java
  4. 41 1
      fs-admin/src/main/java/com/fs/company/controller/CompanyController.java
  5. 81 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyStatisticsController.java
  6. 103 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyTrafficController.java
  7. 49 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyTrafficLogController.java
  8. 41 3
      fs-admin/src/main/java/com/fs/course/controller/FsCoursePlaySourceConfigController.java
  9. 5 5
      fs-admin/src/main/java/com/fs/course/controller/FsCourseRedPacketLogController.java
  10. 14 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseWatchLogController.java
  11. 44 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseCategoryController.java
  12. 22 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseVideoController.java
  13. 19 2
      fs-admin/src/main/java/com/fs/course/controller/FsUserVideoController.java
  14. 14 0
      fs-admin/src/main/java/com/fs/course/controller/qw/QwFsCourseWatchLogController.java
  15. 1 2
      fs-admin/src/main/java/com/fs/fastGpt/FastgptExtUserTagController.java
  16. 25 3
      fs-admin/src/main/java/com/fs/his/controller/FsCompanyController.java
  17. 26 4
      fs-admin/src/main/java/com/fs/his/controller/FsDoctorController.java
  18. 12 12
      fs-admin/src/main/java/com/fs/his/controller/FsHisComplaintController.java
  19. 20 0
      fs-admin/src/main/java/com/fs/his/controller/FsIntegralGoodsController.java
  20. 9 17
      fs-admin/src/main/java/com/fs/his/controller/FsIntegralOrderController.java
  21. 36 8
      fs-admin/src/main/java/com/fs/his/controller/FsPackageController.java
  22. 19 0
      fs-admin/src/main/java/com/fs/his/controller/FsPatientController.java
  23. 71 0
      fs-admin/src/main/java/com/fs/his/controller/FsPromotionalActiveController.java
  24. 41 0
      fs-admin/src/main/java/com/fs/his/controller/FsPromotionalActiveLogController.java
  25. 60 12
      fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java
  26. 0 1
      fs-admin/src/main/java/com/fs/his/controller/FsTestTempItemController.java
  27. 7 1
      fs-admin/src/main/java/com/fs/his/task/Task.java
  28. 24 0
      fs-admin/src/main/java/com/fs/hisStore/FsHisStoreLogController.java
  29. 134 0
      fs-admin/src/main/java/com/fs/hisStore/FsStoreSCRMController.java
  30. 27 2
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreProductScrmController.java
  31. 108 0
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreRecommendScrmController.java
  32. 20 3
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreScrmController.java
  33. 11 1
      fs-admin/src/main/java/com/fs/hisStore/controller/SysOperlogScrmController.java
  34. 94 0
      fs-admin/src/main/java/com/fs/qw/FsCourseTask.java
  35. 33 1
      fs-admin/src/main/java/com/fs/qw/controller/QwCompanyController.java
  36. 50 0
      fs-admin/src/main/java/com/fs/qw/controller/QwExternalContactTransferCompanyAuditController.java
  37. 154 0
      fs-admin/src/main/java/com/fs/qw/controller/QwPushCountController.java
  38. 1 1
      fs-admin/src/main/java/com/fs/qw/controller/QwSopController.java
  39. 34 0
      fs-admin/src/main/java/com/fs/task/FsCompanyTask.java
  40. 39 0
      fs-admin/src/main/java/com/fs/task/FsStoreTask.java
  41. 106 0
      fs-admin/src/main/java/com/fs/user/controller/FsUserComplaintController.java
  42. 109 0
      fs-admin/src/main/java/com/fs/user/controller/FsUserComplaintMsgController.java
  43. 14 0
      fs-admin/src/main/java/com/fs/web/controller/system/SysLoginController.java
  44. 26 3
      fs-admin/src/main/java/com/fs/web/controller/system/SysUserController.java
  45. 2 2
      fs-admin/src/main/resources/application.yml
  46. 18 40
      fs-common-api/src/main/java/com/fs/framework/config/MyBatisConfig.java
  47. 36 0
      fs-common-api/src/main/java/com/fs/framework/config/RedisConfig.java
  48. 2 2
      fs-common-api/src/main/resources/application.yml
  49. 10 1
      fs-common/src/main/java/com/fs/common/core/domain/entity/SysRole.java
  50. 11 0
      fs-common/src/main/java/com/fs/common/core/domain/entity/SysUser.java
  51. 6 2
      fs-common/src/main/java/com/fs/common/core/domain/model/LoginUser.java
  52. 70 5
      fs-common/src/main/java/com/fs/common/core/redis/RedisCache.java
  53. 7 2
      fs-common/src/main/java/com/fs/common/enums/BusinessType.java
  54. 25 0
      fs-common/src/main/java/com/fs/common/utils/DateUtils.java
  55. 140 0
      fs-common/src/main/java/com/fs/common/utils/poi/ExcelUtil.java
  56. 10 0
      fs-company-app/src/main/java/com/fs/app/controller/AppBaseController.java
  57. 1 0
      fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  58. 40 0
      fs-company-app/src/main/java/com/fs/core/config/RedisConfig.java
  59. 7 5
      fs-company/src/main/java/com/fs/company/controller/company/CompanyController.java
  60. 13 3
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseAnswerLogsController.java
  61. 13 2
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseRedPacketLogController.java
  62. 2 0
      fs-company/src/main/java/com/fs/company/controller/course/FsUserCoursePeriodController.java
  63. 1 1
      fs-company/src/main/java/com/fs/company/controller/course/FsUserCourseTrainingCampController.java
  64. 1 1
      fs-company/src/main/java/com/fs/company/controller/course/FsUserOperationLogController.java
  65. 132 3
      fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactController.java
  66. 56 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactTransferCompanyAuditController.java
  67. 97 4
      fs-company/src/main/java/com/fs/company/controller/qw/QwSopController.java
  68. 3 1
      fs-company/src/main/java/com/fs/company/controller/qw/QwSopLogsController.java
  69. 9 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwUserController.java
  70. 80 4
      fs-company/src/main/java/com/fs/company/controller/qw/QwUserVoiceLogController.java
  71. 2 2
      fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsController.java
  72. 2 2
      fs-company/src/main/java/com/fs/company/controller/store/FsStoreOrderController.java
  73. 37 0
      fs-company/src/main/java/com/fs/framework/config/RedisConfig.java
  74. 129 0
      fs-company/src/main/java/com/fs/hisStore/controller/FsIntegralGoodsController.java
  75. 182 0
      fs-company/src/main/java/com/fs/hisStore/controller/FsIntegralOrderController.java
  76. 2 2
      fs-company/src/main/resources/application.yml
  77. 1 10
      fs-doctor-app/src/main/java/com/fs/app/controller/InquiryOrderController.java
  78. 39 0
      fs-doctor-app/src/main/java/com/fs/framework/config/RedisConfig.java
  79. 25 2
      fs-framework/src/main/java/com/fs/framework/aspectj/LogAspect.java
  80. 39 0
      fs-framework/src/main/java/com/fs/framework/config/RedisConfig.java
  81. 7 1
      fs-framework/src/main/java/com/fs/framework/manager/factory/AsyncFactory.java
  82. 38 0
      fs-hospital/src/main/java/com/fs/framework/config/RedisConfig.java
  83. 26 6
      fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java
  84. 69 20
      fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java
  85. 40 0
      fs-ipad-task/src/main/java/com/fs/framework/config/RedisConfig.java
  86. 38 0
      fs-live-app/src/main/java/com/fs/framework/config/RedisConfig.java
  87. 38 37
      fs-qw-api-msg/src/main/java/com/fs/app/controller/QwMsgController.java
  88. 39 0
      fs-qw-api-msg/src/main/java/com/fs/framework/config/RedisConfig.java
  89. 39 0
      fs-qw-api/src/main/java/com/fs/framework/config/RedisConfig.java
  90. 39 0
      fs-qw-mq/src/main/java/com/fs/framework/config/RedisConfig.java
  91. 17 0
      fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java
  92. 271 35
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/AsyncCourseWatchFinishService.java
  93. 52 9
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  94. 40 0
      fs-qw-task/src/main/java/com/fs/framework/config/RedisConfig.java
  95. 42 8
      fs-qw-voice/src/main/java/com/fs/app/controller/CommonController.java
  96. 10 10
      fs-qw-voice/src/main/java/com/fs/app/exception/FSException.java
  97. 101 12
      fs-qw-voice/src/main/java/com/fs/app/mq/RocketMQConsumerService.java
  98. 10 10
      fs-qw-voice/src/main/java/com/fs/app/task/Task.java
  99. 13 3
      fs-qw-voice/src/main/java/com/fs/framework/config/DataSourceConfig.java
  100. 4 4
      fs-qw-voice/src/main/java/com/fs/framework/config/DruidConfig.java

+ 1 - 0
DirectoryV3.xml

@@ -5,4 +5,5 @@
      <tree path="/fs-admin/src/main/java/com/fs/company/controller" title="公司"/>
      <tree path="/fs-admin/src/main/java/com/fs/company/controller" title="公司"/>
      <tree path="/fs-admin/src/main/java/com/fs/live/controller" title="直播"/>
      <tree path="/fs-admin/src/main/java/com/fs/live/controller" title="直播"/>
      <tree path="/fs-admin/src/main/java/com/fs/qw" title="企微"/>
      <tree path="/fs-admin/src/main/java/com/fs/qw" title="企微"/>
+     <tree path="/fs-ad-api" title="广告回传"/>
  </trees>
  </trees>

+ 37 - 0
fs-ad-api/src/main/java/com/fs/framework/config/RedisConfig.java

@@ -15,6 +15,8 @@ import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 
 
+import java.math.BigDecimal;
+
 /**
 /**
  * redis配置
  * redis配置
  *
  *
@@ -65,6 +67,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         template.afterPropertiesSet();
         return template;
         return template;
     }
     }
+    @Bean
+    public RedisTemplate<String, Integer> redisTemplateForInteger(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, Integer> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
 
 
     @Bean
     @Bean
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
@@ -90,7 +110,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         template.afterPropertiesSet();
         return template;
         return template;
     }
     }
+    @Bean
+    public RedisTemplate<String, BigDecimal> redisTemplateForBigDecimal(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, BigDecimal> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
 
 
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
     @Bean
     @Bean
     public DefaultRedisScript<Long> limitScript()
     public DefaultRedisScript<Long> limitScript()
     {
     {

+ 682 - 36
fs-admin/src/main/java/com/fs/api/controller/IndexStatisticsController.java

@@ -1,16 +1,32 @@
 package com.fs.api.controller;
 package com.fs.api.controller;
 
 
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.entity.SysDept;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.company.constant.CompanyTrafficConstants;
+import com.fs.company.domain.Company;
+import com.fs.company.service.ICompanyService;
+import com.fs.company.service.ICompanyTrafficRecordService;
+import com.fs.company.service.impl.CompanyTrafficRecordServiceImpl;
+import com.fs.his.utils.ConfigUtil;
+import com.fs.hisStore.config.MedicalMallConfig;
 import com.fs.statis.StatisticsRedisConstant;
 import com.fs.statis.StatisticsRedisConstant;
 import com.fs.statis.dto.*;
 import com.fs.statis.dto.*;
+import com.fs.statis.param.StatisticsDeptCompanyParam;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.service.ISysConfigService;
 import com.fs.system.service.ISysConfigService;
+import com.fs.system.service.ISysDeptService;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 
 
-import java.util.ArrayList;
-import java.util.List;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.YearMonth;
+import java.util.*;
+import java.util.function.BinaryOperator;
+import java.util.stream.Collectors;
 
 
 import static com.fs.statis.StatisticsRedisConstant.*;
 import static com.fs.statis.StatisticsRedisConstant.*;
 
 
@@ -19,18 +35,31 @@ import static com.fs.statis.StatisticsRedisConstant.*;
  */
  */
 @RestController
 @RestController
 @RequestMapping("/index/statistics")
 @RequestMapping("/index/statistics")
+@Slf4j
 public class IndexStatisticsController {
 public class IndexStatisticsController {
     @Autowired
     @Autowired
     private RedisCache redisCache;
     private RedisCache redisCache;
 
 
     @Autowired
     @Autowired
     private ISysConfigService sysConfigService;
     private ISysConfigService sysConfigService;
+
+    @Autowired
+    private ConfigUtil configUtil;
+
+    @Autowired
+    private ISysDeptService deptService;
+
+    @Autowired
+    private ICompanyService companyService;
+
+    @Autowired
+    private MedicalMallConfig medicalMallConfig;
     /**
     /**
      * 分析概览
      * 分析概览
      */
      */
     @PostMapping("/analysisPreview")
     @PostMapping("/analysisPreview")
     public R analysisPreview(@RequestBody AnalysisPreviewQueryDTO param){
     public R analysisPreview(@RequestBody AnalysisPreviewQueryDTO param){
-        AnalysisPreviewDTO analysisPreviewDTO = null;
+        AnalysisPreviewDTO analysisPreviewDTO = new AnalysisPreviewDTO();
         Integer type = param.getType();
         Integer type = param.getType();
         Integer userType = param.getUserType();
         Integer userType = param.getUserType();
 
 
@@ -41,7 +70,69 @@ public class IndexStatisticsController {
         if(userType == null) {
         if(userType == null) {
             userType = 0;
             userType = 0;
         }
         }
-        analysisPreviewDTO = redisCache.getCacheObject(String.format("%s:%d:%d",DATA_OVERVIEW_DEALER_ANALYSISPREVIEW,type,userType));
+        if(medicalMallConfig.isStatics()|| (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
+            analysisPreviewDTO = redisCache.getCacheObject(String.format("%s:%d:%d",DATA_OVERVIEW_DEALER_ANALYSISPREVIEW,type,userType));
+        }else if(param.getCompanyId() != null){
+            analysisPreviewDTO = redisCache.getCacheObject(String.format("%s:%d:%d:%d",DATA_OVERVIEW_DEALER_ANALYSISPREVIEW,type,userType,param.getCompanyId()));
+        }else{
+            Company company = new Company();
+            company.setDeptId(param.getDeptId());
+            Long[] companyIds = companyService.selectCompanyList(company).stream().map(Company::getCompanyId).toArray(Long[]::new);
+            for(Long companyId : companyIds){
+                AnalysisPreviewDTO clildDTO = redisCache.getCacheObject(String.format("%s:%d:%d:%d",DATA_OVERVIEW_DEALER_ANALYSISPREVIEW,type,userType,companyId));
+                if (clildDTO != null) {
+                    //将除了completedRate、correctRate和watchRate之外的数据相加,并计算completedRate、correctRate和watchRate
+                    analysisPreviewDTO.setWatchUserCount(
+                            analysisPreviewDTO.getWatchUserCount() == 0 ? 0 : analysisPreviewDTO.getWatchUserCount()
+                                +(clildDTO.getWatchUserCount() == 0 ? 0 : clildDTO.getWatchUserCount())
+                    );
+                    analysisPreviewDTO.setCompletedUserCount(
+                            analysisPreviewDTO.getCompletedUserCount() == 0 ? 0 : analysisPreviewDTO.getCompletedUserCount()
+                                +(clildDTO.getCompletedUserCount() == 0 ? 0 : clildDTO.getCompletedUserCount())
+                    );
+                    analysisPreviewDTO.setCompletedCount(
+                            analysisPreviewDTO.getCompletedCount() == 0 ? 0 : analysisPreviewDTO.getCompletedCount()
+                                +(clildDTO.getCompletedCount() == 0 ? 0 : clildDTO.getCompletedCount())
+                    );
+                    analysisPreviewDTO.setWatchCount(
+                            analysisPreviewDTO.getWatchCount() == 0 ? 0 : analysisPreviewDTO.getWatchCount()
+                                +(clildDTO.getWatchCount() == 0 ? 0 : clildDTO.getWatchCount())
+                    );
+                    analysisPreviewDTO.setAnswerMemberCount(
+                            analysisPreviewDTO.getAnswerMemberCount() == 0 ? 0 : analysisPreviewDTO.getAnswerMemberCount()
+                                +(clildDTO.getAnswerMemberCount() == 0 ? 0 : clildDTO.getAnswerMemberCount())
+                    );
+                    analysisPreviewDTO.setCorrectUserCount(
+                            analysisPreviewDTO.getCorrectUserCount() == 0 ? 0 : analysisPreviewDTO.getCorrectUserCount()
+                                +(clildDTO.getCorrectUserCount() == 0 ? 0 : clildDTO.getCorrectUserCount())
+                    );
+                    analysisPreviewDTO.setRewardCount(
+                            analysisPreviewDTO.getRewardCount() == 0 ? 0 : analysisPreviewDTO.getRewardCount()
+                                +(clildDTO.getRewardCount() == 0 ? 0 : clildDTO.getRewardCount())
+                    );
+                    analysisPreviewDTO.setRewardMoney(
+                            analysisPreviewDTO.getRewardMoney() == null ? BigDecimal.ZERO : analysisPreviewDTO.getRewardMoney()
+                                .add(clildDTO.getRewardMoney() == null ? BigDecimal.ZERO : clildDTO.getRewardMoney())
+                    );
+                }
+            }
+            if(analysisPreviewDTO.getAnswerMemberCount() != 0){
+                analysisPreviewDTO.setCorrectRate(
+                        analysisPreviewDTO.getCorrectUserCount() == 0 ? "0" : String.format("%.2f", analysisPreviewDTO.getCorrectUserCount() * 100.0 / analysisPreviewDTO.getAnswerMemberCount())
+                );
+            }
+            if(analysisPreviewDTO.getWatchUserCount() != 0){
+                analysisPreviewDTO.setCompletedRate(
+                        analysisPreviewDTO.getCompletedUserCount() == 0 ? "0" : String.format("%.2f", analysisPreviewDTO.getCompletedUserCount() * 100.0 / analysisPreviewDTO.getWatchUserCount())
+                );
+            }
+            if(analysisPreviewDTO.getWatchCount() != 0){
+                analysisPreviewDTO.setWatchRate(
+                        analysisPreviewDTO.getCompletedCount() == 0 ? "0" : String.format("%.2f", analysisPreviewDTO.getCompletedCount() * 100.0 / analysisPreviewDTO.getWatchCount())
+                );
+            }
+
+        }
 
 
         return R.ok().put("data",analysisPreviewDTO);
         return R.ok().put("data",analysisPreviewDTO);
     }
     }
@@ -51,8 +142,32 @@ public class IndexStatisticsController {
      * 消费余额
      * 消费余额
      */
      */
     @GetMapping("/rechargeComsumption")
     @GetMapping("/rechargeComsumption")
-    public R rechargeComsumption(){
-        ConsumptionBalanceDataDTO consumptionBalanceDataDTO = redisCache.getCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_BALANCE);
+    public R rechargeComsumption(StatisticsDeptCompanyParam param){
+        ConsumptionBalanceDataDTO consumptionBalanceDataDTO = new ConsumptionBalanceDataDTO();
+        if(medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)) {
+            consumptionBalanceDataDTO = redisCache.getCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_BALANCE);
+        }else if(param.getCompanyId() != null){
+            consumptionBalanceDataDTO = redisCache.getCacheObject(String.format("%s:%d",DATA_OVERVIEW_DEALER_BALANCE,param.getCompanyId()));
+        }else{
+            Company company = new Company();
+            company.setDeptId(param.getDeptId());
+            Long[] companyIds = companyService.selectCompanyList(company).stream().map(Company::getCompanyId).toArray(Long[]::new);
+            for(Long companyId : companyIds){
+                ConsumptionBalanceDataDTO clildDTO = redisCache.getCacheObject(String.format("%s:%d",DATA_OVERVIEW_DEALER_BALANCE,companyId));
+                consumptionBalanceDataDTO.setBalance(
+                    (consumptionBalanceDataDTO.getBalance() == null ? BigDecimal.ZERO : consumptionBalanceDataDTO.getBalance())
+                    .add(clildDTO.getBalance() == null ? BigDecimal.ZERO : clildDTO.getBalance())
+                );
+                consumptionBalanceDataDTO.setTodayComsumption(
+                    (consumptionBalanceDataDTO.getTodayComsumption() == null ? BigDecimal.ZERO : consumptionBalanceDataDTO.getTodayComsumption())
+                    .add(clildDTO.getTodayComsumption() == null ? BigDecimal.ZERO : clildDTO.getTodayComsumption())
+                );
+                consumptionBalanceDataDTO.setYesterdayComsumption(
+                    (consumptionBalanceDataDTO.getYesterdayComsumption() == null ? BigDecimal.ZERO : consumptionBalanceDataDTO.getYesterdayComsumption())
+                    .add(clildDTO.getYesterdayComsumption() == null ? BigDecimal.ZERO : clildDTO.getYesterdayComsumption())
+                );
+            }
+        }
 
 
         return R.ok().put("data", consumptionBalanceDataDTO);
         return R.ok().put("data", consumptionBalanceDataDTO);
     }
     }
@@ -62,15 +177,58 @@ public class IndexStatisticsController {
      * @return
      * @return
      */
      */
     @GetMapping("/trafficLog")
     @GetMapping("/trafficLog")
-    public R getTrafficLog(){
-        TrafficLogDTO trafficLogDTO = redisCache.getCacheObject(DATA_OVERVIEW_TRAFFIC_LOG);
-        SysConfig sysConfig = sysConfigService.selectConfigByConfigKey("redPacket.Traffic.config");
-        if(trafficLogDTO == null || sysConfig == null) {
-            return null;
+    public R getTrafficLog(StatisticsDeptCompanyParam  param){
+        TrafficLogDTO result = new TrafficLogDTO();
+        if(!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)) {
+            result = redisCache.getCacheObject(DATA_OVERVIEW_TRAFFIC_LOG);
+            if (!medicalMallConfig.isStatics()) {
+                SysConfig sysConfig = sysConfigService.selectConfigByConfigKey("redPacket.Traffic.config");
+                if(result == null || sysConfig == null) {
+                    return null;
+                }
+                String configValue = sysConfig.getConfigValue();
+                result.setTraffic(configValue);
+            } else {
+                //所有部门流量之和
+                SysDept dept = new SysDept();
+                dept.setParentId(1L);
+                Long[] deptIds = deptService.selectDeptList(dept).stream().map(SysDept::getDeptId).toArray(Long[]::new);
+                long trafficTemp = 0L;
+                for(Long deptId : deptIds){
+                    Object clildTraffic = redisCache.getCacheObject(CompanyTrafficConstants.CACHE_KEY+":"+deptId);
+                    if(clildTraffic != null){
+                        trafficTemp += Long.parseLong(clildTraffic.toString());
+                    }
+                }
+                result.setTraffic(String.format("%.2f",trafficTemp * 1024.0));
+            }
+        }else if(param.getCompanyId() != null){
+            Company company = companyService.selectCompanyById(param.getCompanyId());
+            getTrafficLogResult(result,CompanyTrafficConstants.CACHE_KEY+":"+company.getDeptId()+":"+param.getCompanyId());
+        }else{
+            getTrafficLogResult(result,CompanyTrafficConstants.CACHE_KEY+":"+param.getDeptId());
         }
         }
-        String configValue = sysConfig.getConfigValue();
-        trafficLogDTO.setTraffic(configValue);
-        return R.ok().put("data",trafficLogDTO);
+        return R.ok().put("data",result);
+    }
+
+    private void getTrafficLogResult(TrafficLogDTO result, String key){
+        //昨天
+        LocalDate yesterday = LocalDate.now().minusDays(1);
+        Object yesterdayCount = redisCache.getCacheObject(key+":"+yesterday);
+        Object todayCount = redisCache.getCacheObject(key+":"+LocalDate.now());
+        Object thisMonthCount = redisCache.getCacheObject(key+":"+YearMonth.now());
+        Object traffic = redisCache.getCacheObject(key);
+        result.setYesterday(parseRedisNumberValueToLong(yesterdayCount));
+        //今天
+        result.setToday(parseRedisNumberValueToLong(todayCount));
+        //本月
+        result.setThisMonth(parseRedisNumberValueToLong(thisMonthCount));
+        //剩余
+        result.setTraffic(traffic == null?"0":traffic.toString());
+    }
+
+    private Long parseRedisNumberValueToLong(Object value){
+        return value == null ? 0 : Long.parseLong(value.toString());
     }
     }
 
 
     /**
     /**
@@ -87,9 +245,73 @@ public class IndexStatisticsController {
         if(userType == null){
         if(userType == null){
             userType = 0;
             userType = 0;
         }
         }
-        String key = String.format("%s:%d:%d", DATA_OVERVIEW_DEALER_CHARTS, type,userType);
-        List<DeaMemberTopTenDTO> deaMemberTopTenDTOS = redisCache.getCacheObject(key);
-        return R.ok().put("data", deaMemberTopTenDTOS);
+        List<WatchEndPlayTrendDTO> watchEndPlayTrendDTOS;
+        // 参考watchCourseTopTen方法的处理逻辑
+        if (!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
+            String key = String.format("%s:%d:%d", DATA_OVERVIEW_DEALER_CHARTS, type,userType);
+            watchEndPlayTrendDTOS = redisCache.getCacheObject(key);
+        }else if(param.getCompanyId() != null){
+            String key = String.format("%s:%d:%d:%d", DATA_OVERVIEW_DEALER_CHARTS, type,userType,param.getCompanyId());
+            watchEndPlayTrendDTOS = redisCache.getCacheObject(key);
+        }else{
+            Company company = new Company();
+            company.setDeptId(param.getDeptId());
+            Long[] companyIds = companyService.selectCompanyList(company).stream().map(Company::getCompanyId).toArray(Long[]::new);
+            List<WatchEndPlayTrendDTO> tempDTOS = new ArrayList<>();
+            for(Long companyId : companyIds){
+                String key = String.format("%s:%d:%d:%d", DATA_OVERVIEW_DEALER_CHARTS, type,userType,companyId);
+                List<WatchEndPlayTrendDTO> companyData = redisCache.getCacheObject(key);
+                if (companyData != null) {
+                    tempDTOS.addAll(companyData);
+                }
+            }
+            // 根据startDate 和 x 分组,合并watchUserCount和completedUserCount 限制最多返回10条记录
+            watchEndPlayTrendDTOS = tempDTOS.stream()
+                    .collect(Collectors.groupingBy(
+                            dto -> dto.getStartDate() + ":" + dto.getX(),  // 根据startDate和x分组
+                            Collectors.reducing(new WatchEndPlayTrendDTO(), (dto1, dto2) -> {
+                                // 合并watchUserCount和completedUserCount
+                                WatchEndPlayTrendDTO result = new WatchEndPlayTrendDTO();
+                                // 复制分组标识字段
+                                if (dto2 != null && dto2.getStartDate() != null) {
+                                    result.setStartDate(dto2.getStartDate());
+                                } else if (dto1 != null) {
+                                    result.setStartDate(dto1.getStartDate());
+                                }
+
+                                if (dto2 != null && dto2.getX() != null) {
+                                    result.setX(dto2.getX());
+                                } else if (dto1 != null) {
+                                    result.setX(dto1.getX());
+                                }
+
+                                // 合并数值字段
+                                result.setWatchUserCount(
+                                        (dto1 == null || dto1.getWatchUserCount() == null ? 0 : dto1.getWatchUserCount()) +
+                                                (dto2 == null || dto2.getWatchUserCount() == null ? 0 : dto2.getWatchUserCount())
+                                );
+
+                                result.setCompletedUserCount(
+                                        (dto1 == null || dto1.getCompletedUserCount() == null ? 0 : dto1.getCompletedUserCount()) +
+                                                (dto2 == null || dto2.getCompletedUserCount() == null ? 0 : dto2.getCompletedUserCount())
+                                );
+
+                                return result;
+                            })
+                    ))
+                    .values()
+                    .stream()
+                    .filter(Objects::nonNull)  // 过滤掉null值
+                    .limit(10)
+                    .sorted(Comparator.comparing(WatchEndPlayTrendDTO::getX))
+                    .collect(Collectors.toList());
+        }
+
+        if(watchEndPlayTrendDTOS == null){
+            watchEndPlayTrendDTOS = new ArrayList<>();
+        }
+
+        return R.ok().put("data", watchEndPlayTrendDTOS);
     }
     }
 
 
     /**
     /**
@@ -107,8 +329,49 @@ public class IndexStatisticsController {
         if(userType == null){
         if(userType == null){
             userType = 0;
             userType = 0;
         }
         }
+        List<DeaMemberTopTenDTO> deaMemberTopTenDTOS = new ArrayList<>();
+        // 参考deaMemberTopTen方法处理逻辑
+        if (!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
+            String key = String.format("%s:%d:%d:%d", CHARTS_MEMBER_TOP_TEN_WATCH, type, statisticalType,userType);
+            deaMemberTopTenDTOS =  redisCache.getCacheObject(key);
+        }else if(param.getCompanyId() != null){
+            String key = String.format("%s:%d:%d:%d:%d", CHARTS_MEMBER_TOP_TEN_WATCH, type, statisticalType,userType,param.getCompanyId());
+            deaMemberTopTenDTOS = redisCache.getCacheObject(key);
+        }else{
+            Company company = new Company();
+            company.setDeptId(param.getDeptId());
+            Long[] companyIds = companyService.selectCompanyList(company).stream().map(Company::getCompanyId).toArray(Long[]::new);
+            List<DeaMemberTopTenDTO> tempDTOS = new ArrayList<>();
+            for(Long companyId : companyIds){
+                String key = String.format("%s:%d:%d:%d:%d", CHARTS_MEMBER_TOP_TEN_WATCH, type, statisticalType,userType,companyId);
+                List<DeaMemberTopTenDTO> companyData = redisCache.getCacheObject(key);
+                if (companyData != null) {
+                    tempDTOS.addAll(companyData);
+                }
+            }
+            // companyId 和 companyName 分组,合并watchUserCount 限制最多返回10条记录
+            deaMemberTopTenDTOS = tempDTOS.stream()
+                    .collect(Collectors.groupingBy(
+                            dto -> dto.getCompanyId() + ":" + dto.getCompanyName(),  // 根据companyId和companyName分组
+                            Collectors.reducing(new DeaMemberTopTenDTO(), (dto1, dto2) -> {
+                                DeaMemberTopTenDTO result = new DeaMemberTopTenDTO();
+                                result.setCompanyId(dto1.getCompanyId());
+                                result.setCompanyName(dto1.getCompanyName());
+                                result.setWatchUserCount(
+                                        (dto1.getWatchUserCount() == null ? 0 : dto1.getWatchUserCount()) +
+                                                (dto2 == null || dto2.getWatchUserCount() == null ? 0 : dto2.getWatchUserCount())
+                                );
+                                return result;
+                            })
+                    ))
+                    .values()
+                    .stream()
+                    .filter(Objects::nonNull)  // 过滤掉null值
+                    .limit(10)
+                    .sorted(Comparator.comparing(DeaMemberTopTenDTO::getWatchUserCount, Comparator.nullsLast(Comparator.reverseOrder())))
+                    .collect(Collectors.toList());
+        }
 
 
-        List<DeaMemberTopTenDTO> deaMemberTopTenDTOS = redisCache.getCacheObject(String.format("%s:%d:%d:%d", CHARTS_MEMBER_TOP_TEN_WATCH, type, statisticalType,userType));
         if(deaMemberTopTenDTOS == null){
         if(deaMemberTopTenDTOS == null){
             deaMemberTopTenDTOS = new ArrayList<>();
             deaMemberTopTenDTOS = new ArrayList<>();
         }
         }
@@ -123,8 +386,50 @@ public class IndexStatisticsController {
         Integer type = param.getType();
         Integer type = param.getType();
         Integer dataType = param.getDataType();
         Integer dataType = param.getDataType();
         Integer userType = param.getUserType();
         Integer userType = param.getUserType();
+        List<RewardMoneyTopTenDTO> rewardMoneyTopTenDTOS = new ArrayList<>();
+        // 参考rewardMoneyTopTen方法处理逻辑
+        if(!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
+            String key = String.format("%s:%d:%d:%d", CHARTS_REWARD_MONEY_TOP_TEN, type,dataType,userType);
+            rewardMoneyTopTenDTOS = redisCache.getCacheObject(key);
+        }else if(param.getCompanyId() != null){
+            String key = String.format("%s:%d:%d:%d:%d", CHARTS_REWARD_MONEY_TOP_TEN, type,dataType,userType,param.getCompanyId());
+            rewardMoneyTopTenDTOS = redisCache.getCacheObject(key);
+        }else{
+            Company company = new Company();
+            company.setDeptId(param.getDeptId());
+            Long[] companyIds = companyService.selectCompanyList(company).stream().map(Company::getCompanyId).toArray(Long[]::new);
+            List<RewardMoneyTopTenDTO> tempDTOS = new ArrayList<>();
+            for(Long companyId : companyIds){
+                String key = String.format("%s:%d:%d:%d:%d", CHARTS_REWARD_MONEY_TOP_TEN, type,dataType,userType,companyId);
+                List<RewardMoneyTopTenDTO> companyData = redisCache.getCacheObject(key);
+                if (companyData != null) {
+                    tempDTOS.addAll(companyData);
+                }
+            }
+            rewardMoneyTopTenDTOS = tempDTOS.stream()
+                    .collect(Collectors.groupingBy(
+                            dto -> dto.getCompanyId() + ":" + dto.getCompanyName(),  // 根据companyId和companyName分组
+                            Collectors.reducing(new RewardMoneyTopTenDTO(), (dto1, dto2) -> {
+                                RewardMoneyTopTenDTO result = new RewardMoneyTopTenDTO();
+                                result.setCompanyId(dto1.getCompanyId());
+                                result.setCompanyName(dto1.getCompanyName());
+                                result.setRewardMoney(
+                                        (dto1.getRewardMoney() == null ? BigDecimal.ZERO : dto1.getRewardMoney())
+                                        .add(
+                                                (dto2 == null || dto2.getRewardMoney() == null ? BigDecimal.ZERO : dto2.getRewardMoney())
+                                        )
+                                );
+                                return result;
+                            })
+                    ))
+                    .values()
+                    .stream()
+                    .filter(Objects::nonNull)  // 过滤掉null值
+                    .limit(10)
+                    .sorted(Comparator.comparing(RewardMoneyTopTenDTO::getRewardMoney, Comparator.nullsLast(Comparator.reverseOrder())))
+                    .collect(Collectors.toList());
+        }
 
 
-        List<RewardMoneyTopTenDTO> rewardMoneyTopTenDTOS = redisCache.getCacheObject( String.format("%s:%d:%d:%d", CHARTS_REWARD_MONEY_TOP_TEN, type,dataType,userType));
         return R.ok().put("data", rewardMoneyTopTenDTOS);
         return R.ok().put("data", rewardMoneyTopTenDTOS);
     }
     }
 
 
@@ -135,7 +440,47 @@ public class IndexStatisticsController {
     public R rewardMoneyTrend(@RequestBody AnalysisPreviewQueryDTO param){
     public R rewardMoneyTrend(@RequestBody AnalysisPreviewQueryDTO param){
         Integer type = param.getType();
         Integer type = param.getType();
         Integer userType = param.getUserType();
         Integer userType = param.getUserType();
-        List<RewardMoneyTrendDTO> rewardMoneyTrendDTOS = redisCache.getCacheObject( String.format("%s:%d:%d", CHARTS_REWARD_MONEY_TREND, type,userType));
+        List<RewardMoneyTrendDTO> rewardMoneyTrendDTOS = new ArrayList<>();
+        // 参考rewardMoneyTrend方法处理逻辑
+        if(!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
+            String key = String.format("%s:%d:%d", CHARTS_REWARD_MONEY_TREND, type,userType);
+            rewardMoneyTrendDTOS = redisCache.getCacheObject(key);
+        }else if(param.getCompanyId() != null){
+            String key = String.format("%s:%d:%d:%d", CHARTS_REWARD_MONEY_TREND, type,userType,param.getCompanyId());
+            rewardMoneyTrendDTOS = redisCache.getCacheObject(key);
+        }else{
+            Company company = new Company();
+            company.setDeptId(param.getDeptId());
+            Long[] companyIds = companyService.selectCompanyList(company).stream().map(Company::getCompanyId).toArray(Long[]::new);
+            List<RewardMoneyTrendDTO> tempDTOS = new ArrayList<>();
+            for(Long companyId : companyIds){
+                String key = String.format("%s:%d:%d:%d", CHARTS_REWARD_MONEY_TREND, type,userType,companyId);
+                List<RewardMoneyTrendDTO> companyData = redisCache.getCacheObject(key);
+                if (companyData != null) {
+                    tempDTOS.addAll(companyData);
+                }
+            }
+            //根据startDate和x分组,合并rewardMoney,根据x排序,限制10
+            rewardMoneyTrendDTOS = tempDTOS.stream()
+                    .collect(Collectors.groupingBy(dto -> dto.getStartDate() + ":" + dto.getX(),
+                            Collectors.reducing(new RewardMoneyTrendDTO(), (dto1, dto2) -> {
+                        RewardMoneyTrendDTO result = new RewardMoneyTrendDTO();
+                        result.setStartDate(dto1.getStartDate());
+                        result.setX(dto1.getX());
+                        result.setRewardMoney(
+                                (dto1.getRewardMoney() == null ? BigDecimal.ZERO : dto1.getRewardMoney())
+                                .add(
+                                        (dto2 == null || dto2.getRewardMoney() == null ? BigDecimal.ZERO : dto2.getRewardMoney())
+                                )
+                        );
+                        return result;
+                    })))
+                    .values()
+                    .stream()
+                    .sorted(Comparator.comparing(RewardMoneyTrendDTO::getX))
+                    .limit(10)
+                    .collect(Collectors.toList());
+        }
         return R.ok().put("data", rewardMoneyTrendDTOS);
         return R.ok().put("data", rewardMoneyTrendDTOS);
     }
     }
 
 
@@ -148,29 +493,196 @@ public class IndexStatisticsController {
         String sort = param.getSort();
         String sort = param.getSort();
         Integer statisticalType = param.getStatisticalType();
         Integer statisticalType = param.getStatisticalType();
         Integer userType = param.getUserType();
         Integer userType = param.getUserType();
+        List<CourseStatsDTO> courseStatsDTOS;
+        if (!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
+            courseStatsDTOS = redisCache.getCacheObject(String.format("%s:%d:%d:%d:%s", CHARTS_WATCH_TOP_TEN, type,statisticalType,userType,sort));
+        }else if(param.getCompanyId() != null){
+            courseStatsDTOS = redisCache.getCacheObject(String.format("%s:%d:%d:%d:%s:%d", CHARTS_WATCH_TOP_TEN, type,statisticalType,userType,sort,param.getCompanyId()));
+        }else{
+            Company company = new Company();
+            company.setDeptId(param.getDeptId());
+            Long[] companyIds = companyService.selectCompanyList(company).stream().map(Company::getCompanyId).toArray(Long[]::new);
+            List<CourseStatsDTO> tempDTOS = new ArrayList<>();
+            for(Long companyId : companyIds){
+                List<CourseStatsDTO> companyDTO = redisCache.getCacheObject(String.format("%s:%d:%d:%d:%s:%d", CHARTS_WATCH_TOP_TEN, type,statisticalType,userType,sort,companyId));
+                if (companyDTO != null) {
+                    tempDTOS.addAll(companyDTO);
+                }
+            }
+            // courseId和courseName分组,合并watchUserCount、completedUserCount、answerUserCount、correctUserCount 限制最多返回10条记录
+            courseStatsDTOS = tempDTOS.stream()
+                    .collect(Collectors.groupingBy(dto -> dto.getCourseId() + ":" + dto.getCourseName()))
+                    .values()
+                    .stream()
+                    .map(group -> {
+                        if (group.isEmpty()) {
+                            return null;
+                        }
+
+                        // 取第一个作为基础对象
+                        CourseStatsDTO result = new CourseStatsDTO();
+                        CourseStatsDTO first = group.get(0);
+                        result.setCourseId(first.getCourseId());
+                        result.setCourseName(first.getCourseName());
+
+                        // 合并所有数值字段
+                        int watchUserCount = 0;
+                        int completedUserCount = 0;
+                        int answerUserCount = 0;
+                        int correctUserCount = 0;
+
+                        for (CourseStatsDTO dto : group) {
+                            watchUserCount += (dto.getWatchUserCount() == null ? 0 : dto.getWatchUserCount());
+                            completedUserCount += (dto.getCompletedUserCount() == null ? 0 : dto.getCompletedUserCount());
+                            answerUserCount += (dto.getAnswerUserCount() == null ? 0 : dto.getAnswerUserCount());
+                            correctUserCount += (dto.getCorrectUserCount() == null ? 0 : dto.getCorrectUserCount());
+                        }
+
+                        result.setWatchUserCount(watchUserCount);
+                        result.setCompletedUserCount(completedUserCount);
+                        result.setAnswerUserCount(answerUserCount);
+                        result.setCorrectUserCount(correctUserCount);
+
+                        return result;
+                    })
+                    .filter(Objects::nonNull)
+                    .sorted(Comparator.comparing(CourseStatsDTO::getWatchUserCount, Comparator.nullsLast(Comparator.reverseOrder())))
+                    .limit(10)
+                    .collect(Collectors.toList());
+
+        }
 
 
-        List<CourseStatsDTO> courseStatsDTOS = redisCache.getCacheObject(String.format("%s:%d:%d:%d:%s", CHARTS_WATCH_TOP_TEN, type,statisticalType,userType,sort));
         return R.ok().put("data", courseStatsDTOS);
         return R.ok().put("data", courseStatsDTOS);
     }
     }
 
 
+    private List<CourseStatsDTO> groupAndSumCourseStatsWithStream(List<CourseStatsDTO> courseStatsList) {
+        // 定义合并逻辑
+        BinaryOperator<CourseStatsDTO> mergeFunction = (s1, s2) -> {
+            s1.setWatchUserCount(
+                    (s1.getWatchUserCount() == null ? 0 : s1.getWatchUserCount()) +
+                            (s2.getWatchUserCount() == null ? 0 : s2.getWatchUserCount())
+            );
+
+            s1.setCompletedUserCount(
+                    (s1.getCompletedUserCount() == null ? 0 : s1.getCompletedUserCount()) +
+                            (s2.getCompletedUserCount() == null ? 0 : s2.getCompletedUserCount())
+            );
+
+            s1.setAnswerUserCount(
+                    (s1.getAnswerUserCount() == null ? 0 : s1.getAnswerUserCount()) +
+                            (s2.getAnswerUserCount() == null ? 0 : s2.getAnswerUserCount())
+            );
+
+            s1.setCorrectUserCount(
+                    (s1.getCorrectUserCount() == null ? 0 : s1.getCorrectUserCount()) +
+                            (s2.getCorrectUserCount() == null ? 0 : s2.getCorrectUserCount())
+            );
+
+            return s1;
+        };
+
+        // 分组、合并并排序、限制10条
+        return courseStatsList.stream()
+                .collect(Collectors.toMap(
+                        CourseStatsDTO::getCourseId,
+                        dto -> {
+                            CourseStatsDTO copy = new CourseStatsDTO();
+                            copy.setCourseId(dto.getCourseId());
+                            copy.setCourseName(dto.getCourseName());
+                            copy.setWatchUserCount(dto.getWatchUserCount() == null ? 0 : dto.getWatchUserCount());
+                            copy.setCompletedUserCount(dto.getCompletedUserCount() == null ? 0 : dto.getCompletedUserCount());
+                            copy.setAnswerUserCount(dto.getAnswerUserCount() == null ? 0 : dto.getAnswerUserCount());
+                            copy.setCorrectUserCount(dto.getCorrectUserCount() == null ? 0 : dto.getCorrectUserCount());
+                            return copy;
+                        },
+                        mergeFunction,
+                        LinkedHashMap::new
+                ))
+                .values()
+                .stream()
+                .sorted(Comparator.comparing(CourseStatsDTO::getWatchUserCount, Comparator.nullsLast(Comparator.reverseOrder())))
+                .limit(10)
+                .collect(Collectors.toList());
+    }
+
     /**
     /**
      * 数据概览
      * 数据概览
      */
      */
     @GetMapping("/dealerAggregated")
     @GetMapping("/dealerAggregated")
-    public R dealerAggregated(){
-        DealerAggregatedDTO dealerAggregatedDTO = redisCache.getCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_AGGREGATED);
+    public R dealerAggregated(StatisticsDeptCompanyParam param){
+        DealerAggregatedDTO result = new DealerAggregatedDTO();
+        if (!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)) {
+            result = redisCache.getCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_AGGREGATED);
+        }else if (param.getCompanyId() != null) {
+            result = redisCache.getCacheObject(String.format("%s:%d", DATA_OVERVIEW_DEALER_AGGREGATED, param.getCompanyId()));
+        //没选中销售公司,部门不为总公司
+        }else{
+            //Long padMaxNum = deptLimiteService.selectById(param.getDeptId()).getMaxPadNum();
+            Company company = new Company();
+            company.setDeptId(param.getDeptId());
+            Long[] companyIds = companyService.selectCompanyList(company).stream().map(Company::getCompanyId).toArray(Long[]::new);
+            for(Long companyId : companyIds) {
+                DealerAggregatedDTO dealerAggregatedDTO = redisCache.getCacheObject(String.format("%s:%d", DATA_OVERVIEW_DEALER_AGGREGATED, companyId));
+                // 添加空值检查
+                if (dealerAggregatedDTO != null) {
+                    result.setDealderCount((result.getDealderCount() == null ? 0 : result.getDealderCount())
+                            + (dealerAggregatedDTO.getDealderCount() == null ? 0 : dealerAggregatedDTO.getDealderCount()));
+                    result.setGroupMgrCount((result.getGroupMgrCount() == null ? 0 : result.getGroupMgrCount())
+                            + (dealerAggregatedDTO.getGroupMgrCount() == null ? 0 : dealerAggregatedDTO.getGroupMgrCount()));
+                    result.setMemberCount((result.getMemberCount() == null ? 0 : result.getMemberCount())
+                            + (dealerAggregatedDTO.getMemberCount() == null ? 0 : dealerAggregatedDTO.getMemberCount()));
+                    result.setNormalNum((result.getNormalNum() == null ? 0 : result.getNormalNum())
+                            + (dealerAggregatedDTO.getNormalNum() == null ? 0 : dealerAggregatedDTO.getNormalNum()));
+                    result.setBlackNum((result.getBlackNum() == null ? 0 : result.getBlackNum())
+                            + (dealerAggregatedDTO.getBlackNum() == null ? 0 : dealerAggregatedDTO.getBlackNum()));
+                    result.setQwMemberNum((result.getQwMemberNum() == null ? 0 : result.getQwMemberNum())
+                            + (dealerAggregatedDTO.getQwMemberNum() == null ? 0 : dealerAggregatedDTO.getQwMemberNum()));
+                    result.setTodayIncreaseUserNum((result.getTodayIncreaseUserNum() == null ? 0 : result.getTodayIncreaseUserNum())
+                            + (dealerAggregatedDTO.getTodayIncreaseUserNum() == null ? 0 : dealerAggregatedDTO.getTodayIncreaseUserNum()));
+                    result.setOrderTotalNum((result.getOrderTotalNum() == null ? 0 : result.getOrderTotalNum())
+                            + (dealerAggregatedDTO.getOrderTotalNum() == null ? 0 : dealerAggregatedDTO.getOrderTotalNum()));
+                    result.setTodayOrderNum((result.getTodayOrderNum() == null ? 0 : result.getTodayOrderNum())
+                            + (dealerAggregatedDTO.getTodayOrderNum() == null ? 0 : dealerAggregatedDTO.getTodayOrderNum()));
+                    result.setRecvTodayNum((result.getRecvTodayNum() == null ? 0 : result.getRecvTodayNum())
+                            + (dealerAggregatedDTO.getRecvTodayNum() == null ? 0 : dealerAggregatedDTO.getRecvTodayNum()));
+                    result.setRecvTotalNum((result.getRecvTotalNum() == null ? 0 : result.getRecvTotalNum())
+                            + (dealerAggregatedDTO.getRecvTotalNum() == null ? 0 : dealerAggregatedDTO.getRecvTotalNum()));
+                    result.setGoodsTotalNum((result.getGoodsTotalNum() == null ? 0 : result.getGoodsTotalNum())
+                            + (dealerAggregatedDTO.getGoodsTotalNum() == null ? 0 : dealerAggregatedDTO.getGoodsTotalNum()));
+                    result.setTodayGoodsNum((result.getTodayGoodsNum() == null ? 0 : result.getTodayGoodsNum())
+                            + (dealerAggregatedDTO.getTodayGoodsNum() == null ? 0 : dealerAggregatedDTO.getTodayGoodsNum()));
+                    result.setPadUsedNum((result.getPadUsedNum() == null ? 0 : result.getPadUsedNum())
+                            + (dealerAggregatedDTO.getPadUsedNum() == null ? 0 : dealerAggregatedDTO.getPadUsedNum()));
+                }
+            }
+        }
 
 
-        return R.ok().put("data",dealerAggregatedDTO);
+        return R.ok().put("data",result);
     }
     }
 
 
+
     /**
     /**
      * 短信余额
      * 短信余额
      */
      */
     @GetMapping("/smsBalance")
     @GetMapping("/smsBalance")
-    public R smsBalance(){
-        Long smsBalance = redisCache.getCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_SMS_BALANCE);
-
-        return R.ok().put("data", smsBalance);
+    public R smsBalance(StatisticsDeptCompanyParam param){
+        if (!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
+            return R.ok().put("data", redisCache.getCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_SMS_BALANCE));
+        }else if(param.getCompanyId() != null){
+            return R.ok().put("data", redisCache.getCacheObject(String.format("%s:%d", DATA_OVERVIEW_DEALER_SMS_BALANCE, param.getCompanyId())));
+        }else{
+            Company company = new Company();
+            company.setDeptId(param.getDeptId());
+            long smsBalance = 0L;
+            Long[] companyIds = companyService.selectCompanyList(company).stream().map(Company::getCompanyId).toArray(Long[]::new);
+            for(Long companyId : companyIds) {
+                Long smsBalanceCompany = redisCache.getCacheObject(String.format("%s:%d", DATA_OVERVIEW_DEALER_SMS_BALANCE, companyId));
+                if (smsBalanceCompany != null) {
+                    smsBalance += smsBalanceCompany;
+                }
+            }
+            return R.ok().put("data", smsBalance);
+        }
     }
     }
 
 
 
 
@@ -178,8 +690,33 @@ public class IndexStatisticsController {
      * 授权信息
      * 授权信息
      */
      */
     @GetMapping("/authorizationInfo")
     @GetMapping("/authorizationInfo")
-    public R authorizationInfo(){
-        AuthorizationInfoDTO authorizationInfoDTO = redisCache.getCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_AUTHORIZATION_INFO);
+    public R authorizationInfo(StatisticsDeptCompanyParam  param){
+        AuthorizationInfoDTO authorizationInfoDTO = new AuthorizationInfoDTO();
+        if (!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
+            return R.ok().put("data", redisCache.getCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_AUTHORIZATION_INFO));
+        }else if(param.getCompanyId() != null){
+            return R.ok().put("data", redisCache.getCacheObject(String.format("%s:%d", DATA_OVERVIEW_DEALER_AUTHORIZATION_INFO, param.getCompanyId())));
+        }else{
+            Company company = new Company();
+            company.setDeptId(param.getDeptId());
+            AuthorizationInfoDTO authorizationInfoDTO1 = new AuthorizationInfoDTO();
+            Long[] companyIds = companyService.selectCompanyList(company).stream().map(Company::getCompanyId).toArray(Long[]::new);
+            for(Long companyId : companyIds) {
+                AuthorizationInfoDTO companyDTO = redisCache.getCacheObject(String.format("%s:%d", DATA_OVERVIEW_DEALER_AUTHORIZATION_INFO, companyId));
+                log.info("授权信息:{}", authorizationInfoDTO);
+                if (companyDTO != null) {
+                    authorizationInfoDTO1.setTodayWatchUserCount(
+                            (authorizationInfoDTO1.getTodayWatchUserCount() == null ? 0 : authorizationInfoDTO1.getTodayWatchUserCount()) +
+                                    (companyDTO.getTodayWatchUserCount() == null ? 0 : companyDTO.getTodayWatchUserCount())
+                    );
+
+                    authorizationInfoDTO1.setVersionLimit(
+                            (authorizationInfoDTO1.getVersionLimit() == null ? 0 : authorizationInfoDTO1.getVersionLimit()) +
+                                    (companyDTO.getVersionLimit() == null ? 0 : companyDTO.getVersionLimit())
+                    );
+                }
+            }
+        }
 
 
         return R.ok().put("data", authorizationInfoDTO);
         return R.ok().put("data", authorizationInfoDTO);
     }
     }
@@ -190,9 +727,29 @@ public class IndexStatisticsController {
      * @return
      * @return
      */
      */
     @GetMapping("/thisMonthOrderCount")
     @GetMapping("/thisMonthOrderCount")
-    public R thisMonthOrderCount(){
-        R result = redisCache.getCacheObject(StatisticsRedisConstant.THIS_MONTH_ORDER_COUNT);
-        return result;
+    public R thisMonthOrderCount(StatisticsDeptCompanyParam  param){
+        if (!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
+            return redisCache.getCacheObject(StatisticsRedisConstant.THIS_MONTH_ORDER_COUNT);
+        }else if(param.getCompanyId() != null){
+            return redisCache.getCacheObject(String.format("%s:%d", THIS_MONTH_ORDER_COUNT, param.getCompanyId()));
+        }else{
+            Company company = new Company();
+            company.setDeptId(param.getDeptId());
+            Long[] companyIds = companyService.selectCompanyList(company).stream().map(Company::getCompanyId).toArray(Long[]::new);
+            List<String> datesList = new ArrayList<>();
+            List<Integer> orderCountList = new ArrayList<>();
+            List<Integer> payPriceList = new ArrayList<>();
+            for(Long companyId : companyIds) {
+                R result = redisCache.getCacheObject(String.format("%s:%d", THIS_MONTH_ORDER_COUNT, companyId));
+                Object datas = result.get("datas");
+                Object orderCount = result.get("orderCount");
+                Object payPrice = result.get("payPrice");
+                if(datas != null){
+                    mergeDataListsForInteger(datesList, orderCountList, payPriceList, (List<String>)datas, (List<Integer>)orderCount, (List<Integer>)payPrice);
+                }
+            }
+            return R.ok().put("dates", datesList).put("orderCount", orderCountList).put("payPrice", payPriceList);
+        }
     }
     }
 
 
     /**
     /**
@@ -201,8 +758,97 @@ public class IndexStatisticsController {
      */
      */
 
 
     @GetMapping("/thisMonthRecvCount")
     @GetMapping("/thisMonthRecvCount")
-    public R thisMonthRecvCount(){
-        R result = redisCache.getCacheObject(StatisticsRedisConstant.THIS_MONTH_RECV_COUNT);
-        return result;
+    public R thisMonthRecvCount(StatisticsDeptCompanyParam  param){
+        if (!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
+            return redisCache.getCacheObject(StatisticsRedisConstant.THIS_MONTH_RECV_COUNT);
+        }else if(param.getCompanyId() != null){
+            return redisCache.getCacheObject(String.format("%s:%d", THIS_MONTH_RECV_COUNT, param.getCompanyId()));
+        }else{
+            Company company = new Company();
+            company.setDeptId(param.getDeptId());
+            Long[] companyIds = companyService.selectCompanyList(company).stream().map(Company::getCompanyId).toArray(Long[]::new);
+            List<String> datesList = new ArrayList<>();
+            List<Integer> orderCountList = new ArrayList<>();
+            List<Float> payMoneyList = new ArrayList<>();
+            for(Long companyId : companyIds) {
+               R result = redisCache.getCacheObject(String.format("%s:%d", THIS_MONTH_RECV_COUNT, companyId));
+               Object datas = result.get("datas");
+               Object orderCount = result.get("orderCount");
+               Object payMoney = result.get("payMoney");
+               if(datas != null){
+                   mergeDataLists(datesList, orderCountList, payMoneyList, (List<String>)datas, (List<Integer>)orderCount, (List<Float>)payMoney);
+               }
+            }
+            return R.ok().put("dates", datesList).put("orderCount", orderCountList).put("payMoney", payMoneyList);
+        }
+    }
+
+    private void mergeDataLists(List<String> datasList, List<Integer> orderCountList, List<Float> payMoneyList,
+                               List<String> datas, List<Integer> orderCount, List<Float> payMoney) {
+
+        // 遍历新数据
+        for (int i = 0; i < datas.size(); i++) {
+            String newData = datas.get(i);
+            Integer newOrderCount = orderCount.get(i);
+            Float newPayMoney = payMoney.get(i);
+
+            // 查找在现有列表中的位置
+            int existingIndex = datasList.indexOf(newData);
+
+            if (existingIndex != -1) {
+                // 如果存在,将orderCount和payMoney相加
+                Integer existingOrderCount = orderCountList.get(existingIndex);
+                Float existingPayMoney = payMoneyList.get(existingIndex);
+
+                // 累加orderCount
+                orderCountList.set(existingIndex,
+                        (existingOrderCount == null ? 0 : existingOrderCount) +
+                                (newOrderCount == null ? 0 : newOrderCount));
+
+                // 累加payMoney
+                payMoneyList.set(existingIndex,
+                        (existingPayMoney == null ? 0.0f : existingPayMoney) +
+                                (newPayMoney == null ? 0.0f : newPayMoney));
+            } else {
+                // 如果不存在,直接添加新项
+                datasList.add(newData);
+                orderCountList.add(newOrderCount);
+                payMoneyList.add(newPayMoney);
+            }
+        }
+    }
+
+    private void mergeDataListsForInteger(List<String> datasList, List<Integer> orderCountList, List<Integer> payMoneyList,
+                                          List<String> datas, List<Integer> orderCount, List<Integer> payMoney) {
+        // 遍历新数据
+        for (int i = 0; i < datas.size(); i++) {
+            String newData = datas.get(i);
+            Integer newOrderCount = orderCount.get(i);
+            Integer newPayMoney = payMoney.get(i);
+
+            // 查找在现有列表中的位置
+            int existingIndex = datasList.indexOf(newData);
+
+            if (existingIndex != -1) {
+                // 如果存在,将orderCount和payMoney相加
+                Integer existingOrderCount = orderCountList.get(existingIndex);
+                Integer existingPayMoney = payMoneyList.get(existingIndex);
+
+                // 累加orderCount
+                orderCountList.set(existingIndex,
+                        (existingOrderCount == null ? 0 : existingOrderCount) +
+                                (newOrderCount == null ? 0 : newOrderCount));
+
+                // 累加payMoney
+                payMoneyList.set(existingIndex,
+                        (existingPayMoney == null ? 0 : existingPayMoney) +
+                                (newPayMoney == null ? 0 : newPayMoney));
+            } else {
+                // 如果不存在,直接添加新项
+                datasList.add(newData);
+                orderCountList.add(newOrderCount);
+                payMoneyList.add(newPayMoney);
+            }
+        }
     }
     }
 }
 }

+ 41 - 1
fs-admin/src/main/java/com/fs/company/controller/CompanyController.java

@@ -1,6 +1,7 @@
 package com.fs.company.controller;
 package com.fs.company.controller;
 
 
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.IdUtil;
+import cn.hutool.json.JSONUtil;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.controller.BaseController;
@@ -24,8 +25,10 @@ import com.fs.company.vo.CompanyCrmVO;
 import com.fs.company.vo.CompanyVO;
 import com.fs.company.vo.CompanyVO;
 import com.fs.company.vo.CompanyVoiceCallerListVO;
 import com.fs.company.vo.CompanyVoiceCallerListVO;
 import com.fs.core.utils.OrderCodeUtils;
 import com.fs.core.utils.OrderCodeUtils;
+import com.fs.course.config.CourseConfig;
 import com.fs.framework.web.service.TokenService;
 import com.fs.framework.web.service.TokenService;
 import com.fs.his.vo.OptionsVO;
 import com.fs.his.vo.OptionsVO;
+import com.fs.system.service.ISysConfigService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.annotation.Transactional;
@@ -55,6 +58,8 @@ public class CompanyController extends BaseController
     private ICompanyDeductService deductService;
     private ICompanyDeductService deductService;
     @Autowired
     @Autowired
     private ICompanyVoiceCallerService callerService;
     private ICompanyVoiceCallerService callerService;
+    @Autowired
+    private ISysConfigService configService;
     /**
     /**
      * 查询企业列表
      * 查询企业列表
      */
      */
@@ -63,6 +68,12 @@ public class CompanyController extends BaseController
     public TableDataInfo list(CompanyParam param)
     public TableDataInfo list(CompanyParam param)
     {
     {
         startPage();
         startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
+            param.setDeptId(loginUser.getDeptId());
+        }
         List<CompanyVO> list = companyService.selectCompanyVOList(param);
         List<CompanyVO> list = companyService.selectCompanyVOList(param);
         return getDataTable(list);
         return getDataTable(list);
     }
     }
@@ -75,6 +86,12 @@ public class CompanyController extends BaseController
     @GetMapping("/export")
     @GetMapping("/export")
     public AjaxResult export(CompanyParam company)
     public AjaxResult export(CompanyParam company)
     {
     {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
+            company.setDeptId(loginUser.getDeptId());
+        }
         List<CompanyVO> list = companyService.selectCompanyVOList(company);
         List<CompanyVO> list = companyService.selectCompanyVOList(company);
         ExcelUtil<CompanyVO> util = new ExcelUtil<CompanyVO>(CompanyVO.class);
         ExcelUtil<CompanyVO> util = new ExcelUtil<CompanyVO>(CompanyVO.class);
         return util.exportExcel(list, "company");
         return util.exportExcel(list, "company");
@@ -98,6 +115,10 @@ public class CompanyController extends BaseController
     @PostMapping
     @PostMapping
     public R add(@RequestBody Company company)
     public R add(@RequestBody Company company)
     {
     {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        if(company.getDeptId() != null){
+            company.setDeptId(loginUser.getDeptId());
+        }
         company.setPassword(SecurityUtils.encryptPassword(company.getPassword()));
         company.setPassword(SecurityUtils.encryptPassword(company.getPassword()));
         company.setAppId(Md5Utils.hash(company.getUserName()));
         company.setAppId(Md5Utils.hash(company.getUserName()));
         company.setAppKey(Md5Utils.hash(company.getPassword()));
         company.setAppKey(Md5Utils.hash(company.getPassword()));
@@ -154,6 +175,12 @@ public class CompanyController extends BaseController
     {
     {
         Company map=new Company();
         Company map=new Company();
         map.setIsDel(0);
         map.setIsDel(0);
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
+            map.setDeptId(loginUser.getDeptId());
+        }
         List<Company> list = companyService.selectCompanyList(map);
         List<Company> list = companyService.selectCompanyList(map);
         return R.ok().put("data",list);
         return R.ok().put("data",list);
     }
     }
@@ -164,6 +191,12 @@ public class CompanyController extends BaseController
     public TableDataInfo companyCrmDayCountList(CompanyParam param)
     public TableDataInfo companyCrmDayCountList(CompanyParam param)
     {
     {
         startPage();
         startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
+            param.setDeptId(loginUser.getDeptId());
+        }
         List<CompanyCrmVO> list = companyService.selectCompanyCrmDayCountList(param);
         List<CompanyCrmVO> list = companyService.selectCompanyCrmDayCountList(param);
         return getDataTable(list);
         return getDataTable(list);
     }
     }
@@ -239,7 +272,14 @@ public class CompanyController extends BaseController
     @GetMapping("/allList")
     @GetMapping("/allList")
     public TableDataInfo getHospital()
     public TableDataInfo getHospital()
     {
     {
-        List<OptionsVO> list = companyService.selectAllCompanyList();
+        Long deptId = null;
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
+            deptId = loginUser.getDeptId();
+        }
+        List<OptionsVO> list = companyService.selectAllCompanyList(deptId);
         return getDataTable(list);
         return getDataTable(list);
     }
     }
 }
 }

+ 81 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyStatisticsController.java

@@ -19,6 +19,7 @@ import com.fs.crm.service.ICrmCustomerService;
 import com.fs.crm.service.ICrmCustomerVisitService;
 import com.fs.crm.service.ICrmCustomerVisitService;
 import com.fs.crm.vo.CrmCustomerStatisticsVO;
 import com.fs.crm.vo.CrmCustomerStatisticsVO;
 import com.fs.crm.vo.CrmCustomerVisitStatisticsVO;
 import com.fs.crm.vo.CrmCustomerVisitStatisticsVO;
+import com.fs.his.service.IFsStoreAfterSalesService;
 import com.fs.his.service.IFsStoreOrderService;
 import com.fs.his.service.IFsStoreOrderService;
 import com.fs.his.service.IFsStorePaymentService;
 import com.fs.his.service.IFsStorePaymentService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -31,6 +32,7 @@ import org.springframework.web.bind.annotation.RestController;
 import java.math.BigDecimal;
 import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
 /**
 /**
@@ -49,6 +51,10 @@ public class CompanyStatisticsController extends BaseController
 
 
     @Autowired
     @Autowired
     private IFsStoreOrderService storeOrderService;
     private IFsStoreOrderService storeOrderService;
+
+    @Autowired
+    private IFsStoreAfterSalesService storeAfterSalesService;
+
     @Autowired
     @Autowired
     private IFsStorePaymentService storePaymentService;
     private IFsStorePaymentService storePaymentService;
     @Autowired
     @Autowired
@@ -146,6 +152,55 @@ public class CompanyStatisticsController extends BaseController
         }
         }
     }
     }
 
 
+    @GetMapping("/afterSalesOrder")
+    public R afterSalesOrder(FsStoreStatisticsParam param)
+    {
+        if(StringUtils.isNotEmpty(param.getUserIds())){
+            String[] userIds=param.getUserIds().split(",");
+            Long[] ids=new Long[userIds.length];
+            for(int i=0;i<ids.length; i++){
+                ids[i]=Long.parseLong(userIds[i]);
+            }
+            param.setUsers(ids);
+        }
+        else{
+            //获取部门下的所有用户
+            CompanyUser usermap=new CompanyUser();
+            usermap.setDeptId(param.getDeptId());
+            List<CompanyUser> users = userService.getUserListByDeptId(usermap);
+            List<Long> userIds = users.stream().map(element -> element.getUserId()).collect(Collectors.toList());
+            param.setUsers(userIds.toArray(new Long[userIds.size()]));
+        }
+        if(param.getUsers()!=null&&param.getUsers().length>0){
+            List<FsStoreOrderStatisticsVO> list= storeAfterSalesService.selectFsStoreAfterSalesServiceStatisticsList(param);
+
+            TimeUtils.TimeEntity timeEntity= TimeUtils.parseTime(param.getType().toString(),param.getStartTime(),param.getEndTime());
+            timeEntity.setUserIds(param.getUsers());
+            Integer cycleNum = timeEntity.getCycleNum();
+            Integer beginTime = timeEntity.getBeginTime();
+            List<Integer> timeList = new ArrayList<>();
+            for (int i = 1; i <= cycleNum; i++) {
+                timeList.add(beginTime);
+                beginTime = TimeUtils.formatTime(beginTime);
+            }
+            Map<String, Object> map = timeEntity.toMap();
+            if (StringUtils.isNotBlank(param.getStartTime())){
+                map.put("startTime",param.getStartTime());
+            }
+            if (StringUtils.isNotBlank(param.getEndTime())){
+                map.put("endTime",param.getEndTime());
+            }
+            List<JSONObject> jsonObjectList = storeAfterSalesService.selectFsStoreAfterSales(map);
+            List<String> dates = jsonObjectList.stream().map(jsonObject -> jsonObject.getString("type")).collect(Collectors.toList());
+            List<Integer> orderCount = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("orderCount")).collect(Collectors.toList());
+            List<BigDecimal> payPrice = jsonObjectList.stream().map(jsonObject -> jsonObject.getBigDecimal("payPrice")).collect(Collectors.toList());
+            return R.ok().put("list",list).put("dates",dates).put("orderCount",orderCount).put("payPrice",payPrice);
+        }
+        else {
+            return R.ok("未查找到数据");
+        }
+    }
+
 
 
     @GetMapping("/inquiryOrder")
     @GetMapping("/inquiryOrder")
     public R storeInquiryOrder(FsStoreStatisticsParam param)
     public R storeInquiryOrder(FsStoreStatisticsParam param)
@@ -244,6 +299,32 @@ public class CompanyStatisticsController extends BaseController
         return util.exportExcel(list, "orderLogs");
         return util.exportExcel(list, "orderLogs");
     }
     }
 
 
+    @GetMapping("/exportAfterSalesOrder")
+    public AjaxResult exportAfterSalesOrder(FsStoreStatisticsParam param)
+    {
+        if(StringUtils.isNotEmpty(param.getUserIds())){
+            String[] userIds=param.getUserIds().split(",");
+            Long[] ids=new Long[userIds.length];
+            for(int i=0;i<ids.length; i++){
+                ids[i]=Long.parseLong(userIds[i]);
+            }
+            param.setUsers(ids);
+        }
+        else{
+            //获取所有员工
+            CompanyUser usermap=new CompanyUser();
+            usermap.setDeptId(param.getDeptId());
+            List<CompanyUser> users = userService.getUserListByDeptId(usermap);
+            List<Long> userIds = users.stream().map(element -> element.getUserId()).collect(Collectors.toList());
+            param.setUsers(userIds.toArray(new Long[userIds.size()]));
+        }
+
+        List<FsStoreOrderStatisticsVO> list= storeAfterSalesService.selectFsStoreAfterSalesServiceStatisticsList(param);
+
+        ExcelUtil<FsStoreOrderStatisticsVO> util = new ExcelUtil<FsStoreOrderStatisticsVO>(FsStoreOrderStatisticsVO.class);
+        return util.exportExcel(list, "orderLogs");
+    }
+
 
 
     @GetMapping("/exportInquiryOrder")
     @GetMapping("/exportInquiryOrder")
     public AjaxResult exportInquiryOrder(FsStoreStatisticsParam param)
     public AjaxResult exportInquiryOrder(FsStoreStatisticsParam param)

+ 103 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyTrafficController.java

@@ -0,0 +1,103 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.company.domain.CompanyTrafficRecord;
+import com.fs.company.param.CompanyTrafficRecordChargeParam;
+import com.fs.company.param.CompanyTrafficRecordQueryParam;
+import com.fs.company.service.ICompanyTrafficRecordService;
+import com.fs.framework.web.service.TokenService;
+import com.fs.hisStore.config.MedicalMallConfig;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.PostConstruct;
+import java.util.List;
+
+@RestController
+@RequestMapping("/company/traffic")
+public class CompanyTrafficController extends BaseController {
+
+    @Autowired
+    private ICompanyTrafficRecordService companyTrafficRecordService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    @Autowired
+    private MedicalMallConfig medicalMallConfig;
+
+    /**
+     * 每天扣除流量余额
+     * */
+    @Scheduled(cron = "0 1 0 * * ?")
+    public void refreshTraffic(){
+        if(medicalMallConfig.isStatics())
+            companyTrafficRecordService.refreshTraffic();
+    }
+
+    /**
+     * 重启时重新计算并更新公司缓存
+     * */
+    @PostConstruct
+    public void init() {
+        if(medicalMallConfig.isStatics())
+            companyTrafficRecordService.init();
+    }
+
+    /** 充值流量 */
+    @PreAuthorize("@ss.hasPermi('company:traffic:charge')")
+    @Log(title = "公司流量充值", businessType = BusinessType.INSERT)
+    @PostMapping(value = "/rechargeTraffic")
+    public R rechargeTraffic(@RequestBody CompanyTrafficRecordChargeParam companyTrafficRecord) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        companyTrafficRecord.setUserId(loginUser.getUser().getUserId());
+        companyTrafficRecord.setUserName(loginUser.getUser().getUserName());
+        companyTrafficRecordService.recharge(companyTrafficRecord);
+        return R.ok();
+    }
+
+    /** 流量充值记录查询 */
+    @PreAuthorize("@ss.hasPermi('company:traffic:list')")
+    @GetMapping(value = "/list")
+    public TableDataInfo list(CompanyTrafficRecordQueryParam param) {
+        startPage();
+        List<CompanyTrafficRecord> list = companyTrafficRecordService.selectList(param);
+        return getDataTable(list);
+    }
+
+    /** 流量充值详情 */
+    @PreAuthorize("@ss.hasPermi('company:traffic:detail')")
+    @GetMapping(value = "/detail/{logId}")
+    public R detail(@PathVariable("logId") Long logId) {
+        CompanyTrafficRecord record = companyTrafficRecordService.selectById(logId);
+        return R.ok().put("data", record);
+    }
+
+    /** 流量换算*/
+    @GetMapping(value = "/trafficConversion")
+    public R trafficConversion(@RequestParam("traffic") Long amount) {
+        Long trafficKB = companyTrafficRecordService.trafficConversion(amount);
+        return R.ok().put("data", trafficKB);
+    }
+
+    /** 刷新单价*/
+    @GetMapping(value = "/refreshPrice")
+    public R refreshPrice() {
+        companyTrafficRecordService.refreshPrice();
+        return R.ok();
+    }
+
+    /** 流量统计*/
+    @GetMapping(value = "/trafficStatistics")
+    public R trafficStatistics(CompanyTrafficRecord record) {
+        return R.ok().put("tatol","").put("dept","").put("company","");
+    }
+}

+ 49 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyTrafficLogController.java

@@ -0,0 +1,49 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+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.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyTrafficRecordLog;
+import com.fs.company.param.CompanyTrafficRecordLogQueryParam;
+import com.fs.company.service.ICompanyTrafficRecordLogService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/company/trafficLog")
+public class CompanyTrafficLogController extends BaseController {
+
+    @Autowired
+    private ICompanyTrafficRecordLogService companyTrafficRecordLogService;
+
+
+    /** 流量充值记录查询 */
+    @PreAuthorize("@ss.hasPermi('company:trafficLog:list')")
+    @GetMapping(value = "/list")
+    public TableDataInfo list(CompanyTrafficRecordLogQueryParam param) {
+        startPage();
+        List<CompanyTrafficRecordLog> list = companyTrafficRecordLogService.selectList(param);
+        return getDataTable(list);
+    }
+
+
+    /** 导出 */
+    @PreAuthorize("@ss.hasPermi('company:trafficLog:export')")
+    @Log(title = "流量充值记录导出", businessType = BusinessType.EXPORT)
+    @GetMapping(value = "/export")
+    public AjaxResult export(CompanyTrafficRecordLogQueryParam param) {
+        List<CompanyTrafficRecordLog> list = companyTrafficRecordLogService.selectList(param);
+        ExcelUtil<CompanyTrafficRecordLog> util = new ExcelUtil<>(CompanyTrafficRecordLog.class);
+        return util.exportExcel(list, "流量充值记录");
+    }
+
+
+
+}

+ 41 - 3
fs-admin/src/main/java/com/fs/course/controller/FsCoursePlaySourceConfigController.java

@@ -1,21 +1,29 @@
 package com.fs.course.controller;
 package com.fs.course.controller;
 
 
+import cn.hutool.json.JSONUtil;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.bean.BeanUtils;
 import com.fs.common.utils.bean.BeanUtils;
+import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.param.FsCoursePlaySourceConfigCreateParam;
 import com.fs.course.param.FsCoursePlaySourceConfigCreateParam;
 import com.fs.course.param.FsCoursePlaySourceConfigEditParam;
 import com.fs.course.param.FsCoursePlaySourceConfigEditParam;
 import com.fs.course.service.IFsCoursePlaySourceConfigService;
 import com.fs.course.service.IFsCoursePlaySourceConfigService;
 import com.fs.course.vo.FsCoursePlaySourceConfigVO;
 import com.fs.course.vo.FsCoursePlaySourceConfigVO;
+import com.fs.framework.web.service.TokenService;
+import com.fs.system.service.ISysConfigService;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageHelper;
 import lombok.AllArgsConstructor;
 import lombok.AllArgsConstructor;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -31,16 +39,33 @@ import java.util.*;
 public class FsCoursePlaySourceConfigController extends BaseController {
 public class FsCoursePlaySourceConfigController extends BaseController {
 
 
     private final IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService;
     private final IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService;
+    private final TokenService tokenService;
+    private final ISysConfigService configService;
 
 
     @PreAuthorize("@ss.hasPermi('course:playSourceConfig:list')")
     @PreAuthorize("@ss.hasPermi('course:playSourceConfig:list')")
     @GetMapping("/list")
     @GetMapping("/list")
     public TableDataInfo list(@RequestParam(required = false) String name,
     public TableDataInfo list(@RequestParam(required = false) String name,
                               @RequestParam(required = false) String appid,
                               @RequestParam(required = false) String appid,
+                              @RequestParam(required = false) Integer isMall,
                               @RequestParam(required = false, defaultValue = "1") Integer pageNum,
                               @RequestParam(required = false, defaultValue = "1") Integer pageNum,
                               @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
                               @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
         Map<String, Object> params = new HashMap<>();
         Map<String, Object> params = new HashMap<>();
         params.put("name", name);
         params.put("name", name);
         params.put("appid", appid);
         params.put("appid", appid);
+        params.put("isMall", isMall);
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        Long userId = null;
+        Long deptId = null;
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
+            deptId = loginUser.getDeptId();
+            if(config.getDept() == null || !config.getDept()){
+                userId = loginUser.getUserId();
+            }
+        }
+        params.put("userId", userId);
+        params.put("deptId", deptId);
 
 
         PageHelper.startPage(pageNum, pageSize);
         PageHelper.startPage(pageNum, pageSize);
         List<FsCoursePlaySourceConfigVO> list = fsCoursePlaySourceConfigService.selectCoursePlaySourceConfigVOListByMap(params);
         List<FsCoursePlaySourceConfigVO> list = fsCoursePlaySourceConfigService.selectCoursePlaySourceConfigVOListByMap(params);
@@ -70,8 +95,10 @@ public class FsCoursePlaySourceConfigController extends BaseController {
         if (fsCoursePlaySourceConfigService.count(queryWrapper) > 0) {
         if (fsCoursePlaySourceConfigService.count(queryWrapper) > 0) {
             return AjaxResult.error("appid已存在");
             return AjaxResult.error("appid已存在");
         }
         }
-
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         FsCoursePlaySourceConfig config = new FsCoursePlaySourceConfig();
         FsCoursePlaySourceConfig config = new FsCoursePlaySourceConfig();
+        config.setCreateUserId(loginUser.getUserId());
+        config.setCreateDeptId(loginUser.getDeptId());
         BeanUtils.copyProperties(param, config);
         BeanUtils.copyProperties(param, config);
 
 
         config.setIsDel(0);
         config.setIsDel(0);
@@ -114,8 +141,19 @@ public class FsCoursePlaySourceConfigController extends BaseController {
         fsCoursePlaySourceConfigService.update(updateWrapper);
         fsCoursePlaySourceConfigService.update(updateWrapper);
         return AjaxResult.success();
         return AjaxResult.success();
     }
     }
+
     @GetMapping("/listAll")
     @GetMapping("/listAll")
-    public R listAll() {
-        return R.ok().put("data", fsCoursePlaySourceConfigService.list(new QueryWrapper<FsCoursePlaySourceConfig>().eq("is_del", 0)));
+    public R listAll(Long companyId) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        QueryWrapper<FsCoursePlaySourceConfig> queryWrapper = new QueryWrapper<FsCoursePlaySourceConfig>().eq("is_del", 0);
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
+            queryWrapper.eq("create_user_id", loginUser.getUserId()).eq(config.getDept() == null || !config.getDept(), "create_dept_id", loginUser.getDeptId());
+        }
+        if(companyId != null){
+            queryWrapper.and(e -> e.eq("company_id", companyId).or().isNull("company_id"));
+        }
+        return R.ok().put("data", fsCoursePlaySourceConfigService.list(queryWrapper));
     }
     }
 }
 }

+ 5 - 5
fs-admin/src/main/java/com/fs/course/controller/FsCourseRedPacketLogController.java

@@ -53,11 +53,11 @@ public class FsCourseRedPacketLogController extends BaseController
     @Autowired
     @Autowired
     FsUserCourseMapper fsUserCourseMapper;
     FsUserCourseMapper fsUserCourseMapper;
     @Autowired
     @Autowired
-    FsUserCourseVideoMapper fsUserCourseVideoMapper;
+    TokenService tokenService;
     @Autowired
     @Autowired
-    private TokenService tokenService;
+    ISysConfigService configService;
     @Autowired
     @Autowired
-    private ISysConfigService configService;
+    FsUserCourseVideoMapper fsUserCourseVideoMapper;
     /**
     /**
      * 查询短链课程看课记录列表
      * 查询短链课程看课记录列表
      */
      */
@@ -149,10 +149,10 @@ public class FsCourseRedPacketLogController extends BaseController
         Long userId = loginUser.getUser().getUserId();
         Long userId = loginUser.getUser().getUserId();
         String json = configService.selectConfigByKey("course.config");
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        List<OptionsVO> optionsVOS = new ArrayList<>();
+        List<OptionsVO> optionsVOS;
         if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
         if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
             optionsVOS = fsUserCourseMapper.selectFsUserCourseAllListByUserId(userId);
             optionsVOS = fsUserCourseMapper.selectFsUserCourseAllListByUserId(userId);
-        }else {
+        }else{
             optionsVOS = fsUserCourseMapper.selectFsUserCourseAllList();
             optionsVOS = fsUserCourseMapper.selectFsUserCourseAllList();
         }
         }
         return R.ok().put("list", optionsVOS);
         return R.ok().put("list", optionsVOS);

+ 14 - 0
fs-admin/src/main/java/com/fs/course/controller/FsCourseWatchLogController.java

@@ -5,8 +5,11 @@ import java.util.List;
 
 
 import com.fs.common.constant.HttpStatus;
 import com.fs.common.constant.HttpStatus;
 import com.fs.common.exception.CustomException;
 import com.fs.common.exception.CustomException;
+import com.fs.common.utils.ServletUtils;
+import com.fs.course.param.FsCourseOverParam;
 import com.fs.course.param.FsCourseWatchLogListParam;
 import com.fs.course.param.FsCourseWatchLogListParam;
 import com.fs.course.param.FsCourseWatchLogStatisticsListParam;
 import com.fs.course.param.FsCourseWatchLogStatisticsListParam;
+import com.fs.course.vo.FsCourseOverVO;
 import com.fs.course.vo.FsCourseWatchLogListVO;
 import com.fs.course.vo.FsCourseWatchLogListVO;
 import com.fs.course.vo.FsCourseWatchLogStatisticsListVO;
 import com.fs.course.vo.FsCourseWatchLogStatisticsListVO;
 import com.fs.qw.param.QwWatchLogStatisticsListParam;
 import com.fs.qw.param.QwWatchLogStatisticsListParam;
@@ -164,4 +167,15 @@ public class FsCourseWatchLogController extends BaseController
     {
     {
         return toAjax(fsCourseWatchLogService.deleteFsCourseWatchLogByLogIds(logIds));
         return toAjax(fsCourseWatchLogService.deleteFsCourseWatchLogByLogIds(logIds));
     }
     }
+
+    @GetMapping("/watchLogStatistics")
+    public TableDataInfo watchLogStatistics(FsCourseOverParam param)
+    {
+        startPage();
+        if (param.getSTime()==null||param.getETime()==null){
+            return getDataTable(new ArrayList<>());
+        }
+        List<FsCourseOverVO> list = fsCourseWatchLogService.selectFsCourseWatchLogOverStatisticsListVO(param);
+        return getDataTable(list);
+    }
 }
 }

+ 44 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseCategoryController.java

@@ -3,9 +3,18 @@ package com.fs.course.controller;
 import java.util.List;
 import java.util.List;
 
 
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.utils.ServletUtils;
+import com.fs.framework.web.service.TokenService;
 import com.fs.his.domain.FsStoreProductCategory;
 import com.fs.his.domain.FsStoreProductCategory;
 import com.fs.his.vo.FsStoreProductCategoryVO;
 import com.fs.his.vo.FsStoreProductCategoryVO;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSONUtil;
+import com.fs.course.config.CourseConfig;
+
 import com.fs.his.vo.OptionsVO;
 import com.fs.his.vo.OptionsVO;
+import com.fs.system.service.ISysConfigService;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -38,6 +47,12 @@ public class FsUserCourseCategoryController extends BaseController
     @Autowired
     @Autowired
     private IFsUserCourseCategoryService fsUserCourseCategoryService;
     private IFsUserCourseCategoryService fsUserCourseCategoryService;
 
 
+    @Autowired
+    private TokenService tokenService;
+
+    @Autowired
+    private ISysConfigService configService;
+
     /**
     /**
      * 查询课堂分类列表
      * 查询课堂分类列表
      */
      */
@@ -45,6 +60,13 @@ public class FsUserCourseCategoryController extends BaseController
     @GetMapping("/list")
     @GetMapping("/list")
     public AjaxResult list(FsUserCourseCategory fsUserCourseCategory)
     public AjaxResult list(FsUserCourseCategory fsUserCourseCategory)
     {
     {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+            fsUserCourseCategory.setUserId(userId);
+        }
         List<FsUserCourseCategory> list = fsUserCourseCategoryService.selectFsUserCourseCategoryList(fsUserCourseCategory);
         List<FsUserCourseCategory> list = fsUserCourseCategoryService.selectFsUserCourseCategoryList(fsUserCourseCategory);
         return AjaxResult.success(list);
         return AjaxResult.success(list);
     }
     }
@@ -57,6 +79,13 @@ public class FsUserCourseCategoryController extends BaseController
     @GetMapping("/export")
     @GetMapping("/export")
     public AjaxResult export(FsUserCourseCategory fsUserCourseCategory)
     public AjaxResult export(FsUserCourseCategory fsUserCourseCategory)
     {
     {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+            fsUserCourseCategory.setUserId(userId);
+        }
         List<FsUserCourseCategory> list = fsUserCourseCategoryService.selectFsUserCourseCategoryList(fsUserCourseCategory);
         List<FsUserCourseCategory> list = fsUserCourseCategoryService.selectFsUserCourseCategoryList(fsUserCourseCategory);
         ExcelUtil<FsUserCourseCategory> util = new ExcelUtil<FsUserCourseCategory>(FsUserCourseCategory.class);
         ExcelUtil<FsUserCourseCategory> util = new ExcelUtil<FsUserCourseCategory>(FsUserCourseCategory.class);
         return util.exportExcel(list, "课堂分类数据");
         return util.exportExcel(list, "课堂分类数据");
@@ -80,6 +109,13 @@ public class FsUserCourseCategoryController extends BaseController
     @PostMapping
     @PostMapping
     public AjaxResult add(@RequestBody FsUserCourseCategory fsUserCourseCategory)
     public AjaxResult add(@RequestBody FsUserCourseCategory fsUserCourseCategory)
     {
     {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+            fsUserCourseCategory.setUserId(userId);
+        }
         return toAjax(fsUserCourseCategoryService.insertFsUserCourseCategory(fsUserCourseCategory));
         return toAjax(fsUserCourseCategoryService.insertFsUserCourseCategory(fsUserCourseCategory));
     }
     }
 
 
@@ -119,6 +155,14 @@ public class FsUserCourseCategoryController extends BaseController
     @GetMapping("/getCatePidList")
     @GetMapping("/getCatePidList")
     public R getCatePidList()
     public R getCatePidList()
     {
     {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+            List<OptionsVO> list = fsUserCourseCategoryService.selectFsUserCourseCategoryPidList(userId);
+            return R.ok().put("data", list);
+        }
         List<OptionsVO> list = fsUserCourseCategoryService.selectFsUserCourseCategoryPidList();
         List<OptionsVO> list = fsUserCourseCategoryService.selectFsUserCourseCategoryPidList();
         return R.ok().put("data", list);
         return R.ok().put("data", list);
     }
     }

+ 22 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseVideoController.java

@@ -20,6 +20,7 @@ import com.fs.course.param.BatchVideoSvae;
 import com.fs.course.param.CourseVideoUpdates;
 import com.fs.course.param.CourseVideoUpdates;
 import com.fs.course.service.IFsUserCourseService;
 import com.fs.course.service.IFsUserCourseService;
 import com.fs.course.service.IFsUserCourseVideoService;
 import com.fs.course.service.IFsUserCourseVideoService;
+import com.fs.course.vo.FsUserCourseVideoChooseVO;
 import com.fs.framework.web.service.TokenService;
 import com.fs.framework.web.service.TokenService;
 import com.fs.his.vo.OptionsVO;
 import com.fs.his.vo.OptionsVO;
 import com.fs.system.service.ISysConfigService;
 import com.fs.system.service.ISysConfigService;
@@ -202,6 +203,7 @@ public class FsUserCourseVideoController extends BaseController
         return R.ok();
         return R.ok();
     }
     }
     @PostMapping("/batchUpdateRed")
     @PostMapping("/batchUpdateRed")
+    @Log(title = "按课程批量保存设置红包金额", businessType = BusinessType.UPDATE)
     public R batchUpdateRed(@RequestBody List<BatchRedUpdate> list){
     public R batchUpdateRed(@RequestBody List<BatchRedUpdate> list){
         fsUserCourseVideoService.batchUpdateRed(list);
         fsUserCourseVideoService.batchUpdateRed(list);
         return R.ok();
         return R.ok();
@@ -221,4 +223,24 @@ public class FsUserCourseVideoController extends BaseController
         List<OptionsVO> periodList = fsUserCourseVideoService.selectVideoListByMap(params);
         List<OptionsVO> periodList = fsUserCourseVideoService.selectVideoListByMap(params);
         return R.ok().put("data", new PageInfo<>(periodList));
         return R.ok().put("data", new PageInfo<>(periodList));
     }
     }
+
+    @GetMapping("/getChooseCourseVideoList")
+    public R getChooseCourseVideoList(@RequestParam(required = false) Long courseId,
+                                      @RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                                      @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long userId = loginUser.getUser().getUserId();
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+
+        Map<String,Object> params = new HashMap<>();
+        params.put("courseId", courseId);
+        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+            params.put("userId", userId);
+        }
+
+        PageHelper.startPage(pageNum, pageSize);
+        List<FsUserCourseVideoChooseVO> list = fsUserCourseVideoService.getChooseCourseVideoListByMap(params);
+        return R.ok().put("data", new PageInfo<>(list));
+    }
 }
 }

+ 19 - 2
fs-admin/src/main/java/com/fs/course/controller/FsUserVideoController.java

@@ -180,8 +180,11 @@ public class FsUserVideoController extends BaseController
         return toAjax(fsUserVideoService.updateFsUserVideoIsShow(videoIds,0));
         return toAjax(fsUserVideoService.updateFsUserVideoIsShow(videoIds,0));
     }
     }
 
 
-    private static final String VIDEO_UPLOAD_DIR = "C:\\fs\\uploadPath\\userVideo\\video";  // 上传目录
-    private static final String FRAME_OUTPUT_DIR = "C:\\fs\\uploadPath\\userVideo\\frame";  // 输出帧的目录
+//    private static final String VIDEO_UPLOAD_DIR = "C:\\fs\\uploadPath\\userVideo\\video";  // 上传目录
+//    private static final String FRAME_OUTPUT_DIR = "C:\\fs\\uploadPath\\userVideo\\frame";  // 输出帧的目录
+    // 改为使用系统临时目录或相对路径
+    private static final String VIDEO_UPLOAD_DIR = System.getProperty("java.io.tmpdir") + File.separator + "fs_upload" + File.separator + "userVideo" + File.separator + "video";
+    private static final String FRAME_OUTPUT_DIR = System.getProperty("java.io.tmpdir") + File.separator + "fs_upload" + File.separator + "userVideo" + File.separator + "frame";
 
 
 
 
     /**
     /**
@@ -198,16 +201,19 @@ public class FsUserVideoController extends BaseController
 
 
         // 保存上传的视频文件
         // 保存上传的视频文件
         String videoFileName = System.currentTimeMillis() + "_" + UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
         String videoFileName = System.currentTimeMillis() + "_" + UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
+        createDir(VIDEO_UPLOAD_DIR);
         File videoFile = new File(VIDEO_UPLOAD_DIR, videoFileName);
         File videoFile = new File(VIDEO_UPLOAD_DIR, videoFileName);
         try {
         try {
             file.transferTo(videoFile);
             file.transferTo(videoFile);
         } catch (IOException e) {
         } catch (IOException e) {
+            e.printStackTrace();
             // 记录错误日志
             // 记录错误日志
             return R.error("获取封面失败");
             return R.error("获取封面失败");
         }
         }
 
 
         // 提取视频第一帧
         // 提取视频第一帧
         String frameFileName = FilenameUtils.removeExtension(videoFileName) + "_frame.jpg";
         String frameFileName = FilenameUtils.removeExtension(videoFileName) + "_frame.jpg";
+        createDir(FRAME_OUTPUT_DIR);
         File frameFile = new File(FRAME_OUTPUT_DIR, frameFileName);
         File frameFile = new File(FRAME_OUTPUT_DIR, frameFileName);
         try {
         try {
             extractFirstFrame(videoFile.getAbsolutePath(), frameFile.getAbsolutePath());
             extractFirstFrame(videoFile.getAbsolutePath(), frameFile.getAbsolutePath());
@@ -268,6 +274,17 @@ public class FsUserVideoController extends BaseController
         }
         }
     }
     }
 
 
+    private void createDir(String path){
+        File videoUploadDir = new File(path);
+        if (!videoUploadDir.exists()) {
+            boolean created = videoUploadDir.mkdirs();
+            if (!created) {
+                log.error("创建视频上传目录失败: {}", path);
+            }
+            log.info("创建视频上传目录: {}", path);
+        }
+    }
+
     @PostMapping("/updateUrl")
     @PostMapping("/updateUrl")
     public R updateUrl()
     public R updateUrl()
     {
     {

+ 14 - 0
fs-admin/src/main/java/com/fs/course/controller/qw/QwFsCourseWatchLogController.java

@@ -6,12 +6,15 @@ import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.exception.CustomException;
 import com.fs.common.exception.CustomException;
+import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.course.domain.FsCourseWatchLog;
 import com.fs.course.domain.FsCourseWatchLog;
+import com.fs.course.param.FsCourseOverParam;
 import com.fs.course.param.FsCourseWatchLogListParam;
 import com.fs.course.param.FsCourseWatchLogListParam;
 import com.fs.course.param.FsCourseWatchLogStatisticsListParam;
 import com.fs.course.param.FsCourseWatchLogStatisticsListParam;
 import com.fs.course.param.PeriodStatisticCountParam;
 import com.fs.course.param.PeriodStatisticCountParam;
 import com.fs.course.service.IFsCourseWatchLogService;
 import com.fs.course.service.IFsCourseWatchLogService;
+import com.fs.course.vo.FsCourseOverVO;
 import com.fs.course.vo.FsCourseWatchLogListVO;
 import com.fs.course.vo.FsCourseWatchLogListVO;
 import com.fs.course.vo.FsCourseWatchLogStatisticsListVO;
 import com.fs.course.vo.FsCourseWatchLogStatisticsListVO;
 import com.fs.qw.param.QwWatchLogStatisticsListParam;
 import com.fs.qw.param.QwWatchLogStatisticsListParam;
@@ -150,4 +153,15 @@ public class QwFsCourseWatchLogController extends BaseController
         List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectListBytrainingCampId(param);
         List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectListBytrainingCampId(param);
         return getDataTable(list);
         return getDataTable(list);
     }
     }
+
+    @GetMapping("/watchLogStatistics")
+    public TableDataInfo watchLogStatistics(FsCourseOverParam param)
+    {
+        startPage();
+        if (param.getSTime()==null||param.getETime()==null){
+            return getDataTable(new ArrayList<>());
+        }
+        List<FsCourseOverVO> list = fsCourseWatchLogService.selectFsCourseWatchLogOverStatisticsListVO(param);
+        return getDataTable(list);
+    }
 }
 }

+ 1 - 2
fs-admin/src/main/java/com/fs/fastGpt/FastgptExtUserTagController.java

@@ -4,7 +4,6 @@ import java.util.List;
 
 
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
 import com.fs.fastGpt.vo.FastgptExtUserTagVO;
 import com.fs.fastGpt.vo.FastgptExtUserTagVO;
-import com.fs.framework.web.service.TokenService;
 import com.fs.qw.service.IQwCompanyService;
 import com.fs.qw.service.IQwCompanyService;
 import com.fs.qw.vo.QwOptionsVO;
 import com.fs.qw.vo.QwOptionsVO;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -64,7 +63,7 @@ public class FastgptExtUserTagController extends BaseController
     @GetMapping("/getMyQwUserList")
     @GetMapping("/getMyQwUserList")
     public R getMyQwUserList()
     public R getMyQwUserList()
     {
     {
-        List<QwOptionsVO> list = qwCompanyService.selectQwCompanyListOptionsVO();
+        List<QwOptionsVO> list = qwCompanyService.selectQwCompanyListOptionsVO(null, null);
         return  R.ok().put("data",list);
         return  R.ok().put("data",list);
     }
     }
 
 

+ 25 - 3
fs-admin/src/main/java/com/fs/his/controller/FsCompanyController.java

@@ -2,7 +2,7 @@ package com.fs.his.controller;
 
 
 import java.util.List;
 import java.util.List;
 
 
-import cn.hutool.core.util.IdUtil;
+import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
@@ -22,10 +22,11 @@ import com.fs.company.service.ICompanyService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.company.vo.CompanyVO;
 import com.fs.company.vo.CompanyVO;
 import com.fs.core.utils.OrderCodeUtils;
 import com.fs.core.utils.OrderCodeUtils;
+import com.fs.course.config.CourseConfig;
 import com.fs.framework.web.service.TokenService;
 import com.fs.framework.web.service.TokenService;
-import com.fs.his.domain.FsDoctor;
 import com.fs.his.mapper.FsDoctorMapper;
 import com.fs.his.mapper.FsDoctorMapper;
 import com.fs.his.vo.OptionsVO;
 import com.fs.his.vo.OptionsVO;
+import com.fs.system.service.ISysConfigService;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.annotation.Transactional;
@@ -67,6 +68,8 @@ public class FsCompanyController extends BaseController
     private FsDoctorMapper fsDoctorMapper;
     private FsDoctorMapper fsDoctorMapper;
     @Autowired
     @Autowired
     private ICompanyDeductService deductService;
     private ICompanyDeductService deductService;
+    @Autowired
+    private ISysConfigService configService;
     /**
     /**
      * 查询诊所管理列表
      * 查询诊所管理列表
      */
      */
@@ -75,6 +78,12 @@ public class FsCompanyController extends BaseController
     public TableDataInfo list(Company company)
     public TableDataInfo list(Company company)
     {
     {
         startPage();
         startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
+            company.setDeptId(loginUser.getDeptId());
+        }
         List<CompanyVO> list = companyService.selectCompanyListVO(company);
         List<CompanyVO> list = companyService.selectCompanyListVO(company);
         return getDataTable(list);
         return getDataTable(list);
     }
     }
@@ -83,7 +92,14 @@ public class FsCompanyController extends BaseController
     public R companyList()
     public R companyList()
     {
     {
 
 
-        List<OptionsVO> list = companyService.selectAllCompanyList();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long depId = null;
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
+            depId = loginUser.getDeptId();
+        }
+        List<OptionsVO> list = companyService.selectAllCompanyList(depId);
         return R.ok().put("data",list);
         return R.ok().put("data",list);
     }
     }
     /**
     /**
@@ -133,6 +149,12 @@ public class FsCompanyController extends BaseController
     @PostMapping
     @PostMapping
     public R add(@RequestBody Company company)
     public R add(@RequestBody Company company)
     {
     {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
+            company.setDeptId(loginUser.getDeptId());
+        }
         return companyService.insertCompany(company);
         return companyService.insertCompany(company);
     }
     }
 
 

+ 26 - 4
fs-admin/src/main/java/com/fs/his/controller/FsDoctorController.java

@@ -1,17 +1,19 @@
 package com.fs.his.controller;
 package com.fs.his.controller;
 
 
 import java.util.Base64;
 import java.util.Base64;
+import java.util.HashMap;
 import java.util.List;
 import java.util.List;
+import java.util.Map;
 
 
+import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.SecurityUtils;
 import com.fs.common.utils.SecurityUtils;
 import com.fs.common.utils.sign.Md5Utils;
 import com.fs.common.utils.sign.Md5Utils;
 import com.fs.his.param.*;
 import com.fs.his.param.*;
 import com.fs.his.utils.RedisCacheUtil;
 import com.fs.his.utils.RedisCacheUtil;
-import com.fs.his.vo.FsDoctorListVO;
-import com.fs.his.vo.FsDoctorVO;
-import com.fs.his.vo.OptionsVO;
-import com.fs.his.vo.UserVo;
+import com.fs.his.vo.*;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
@@ -269,4 +271,24 @@ public class FsDoctorController extends BaseController
         return toAjax(fsDoctorService.updateFsDoctor(doc));
         return toAjax(fsDoctorService.updateFsDoctor(doc));
     }
     }
 
 
+    @GetMapping("/getChooseDoctorList")
+    public R getChooseDoctorList(@RequestParam(required = false) String doctorName,
+                                 @RequestParam(required = false) Long hospitalId,
+                                 @RequestParam(required = false) Long deptId,
+                                 @RequestParam(required = false) String position,
+                                 @RequestParam(required = false) String mobile,
+                                 @RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                                 @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
+        Map<String,Object> params = new HashMap<>();
+        params.put("doctorName", doctorName);
+        params.put("hospitalId", hospitalId);
+        params.put("deptId", deptId);
+        params.put("position", position);
+        params.put("mobile", mobile);
+
+        PageHelper.startPage(pageNum, pageSize);
+        List<FsDoctorChooseVO> list = fsDoctorService.getChooseDoctorListByMap(params);
+        return R.ok().put("data", new PageInfo<>(list));
+    }
+
 }
 }

+ 12 - 12
fs-admin/src/main/java/com/fs/his/controller/FsUserComplaintController.java → fs-admin/src/main/java/com/fs/his/controller/FsHisComplaintController.java

@@ -6,8 +6,8 @@ import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.his.domain.FsUserComplaint;
-import com.fs.his.service.IFsUserComplaintService;
+import com.fs.his.domain.FsHisComplaint;
+import com.fs.his.service.IFsHisComplaintService;
 import com.fs.his.vo.FsUserComplaintVo;
 import com.fs.his.vo.FsUserComplaintVo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -23,20 +23,20 @@ import java.util.List;
  */
  */
 @RestController
 @RestController
 @RequestMapping("/his/complaint")
 @RequestMapping("/his/complaint")
-public class FsUserComplaintController extends BaseController
+public class FsHisComplaintController extends BaseController
 {
 {
     @Autowired
     @Autowired
-    private IFsUserComplaintService fsUserComplaintService;
+    private IFsHisComplaintService fsUserComplaintService;
 
 
     /**
     /**
      * 查询用户投诉列表
      * 查询用户投诉列表
      */
      */
     @PreAuthorize("@ss.hasPermi('his:complaint:list')")
     @PreAuthorize("@ss.hasPermi('his:complaint:list')")
     @GetMapping("/list")
     @GetMapping("/list")
-    public TableDataInfo list(FsUserComplaint fsUserComplaint)
+    public TableDataInfo list(FsHisComplaint fsHisComplaint)
     {
     {
         startPage();
         startPage();
-        List<FsUserComplaintVo> list = fsUserComplaintService.selectFsUserComplaintList(fsUserComplaint);
+        List<FsUserComplaintVo> list = fsUserComplaintService.selectFsUserComplaintList(fsHisComplaint);
         return getDataTable(list);
         return getDataTable(list);
     }
     }
 
 
@@ -46,9 +46,9 @@ public class FsUserComplaintController extends BaseController
     @PreAuthorize("@ss.hasPermi('his:complaint:export')")
     @PreAuthorize("@ss.hasPermi('his:complaint:export')")
     @Log(title = "用户投诉", businessType = BusinessType.EXPORT)
     @Log(title = "用户投诉", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
     @GetMapping("/export")
-    public AjaxResult export(FsUserComplaint fsUserComplaint)
+    public AjaxResult export(FsHisComplaint fsHisComplaint)
     {
     {
-        List<FsUserComplaintVo> list = fsUserComplaintService.selectFsUserComplaintList(fsUserComplaint);
+        List<FsUserComplaintVo> list = fsUserComplaintService.selectFsUserComplaintList(fsHisComplaint);
         ExcelUtil<FsUserComplaintVo> util = new ExcelUtil<FsUserComplaintVo>(FsUserComplaintVo.class);
         ExcelUtil<FsUserComplaintVo> util = new ExcelUtil<FsUserComplaintVo>(FsUserComplaintVo.class);
         return util.exportExcel(list, "用户投诉数据");
         return util.exportExcel(list, "用户投诉数据");
     }
     }
@@ -69,9 +69,9 @@ public class FsUserComplaintController extends BaseController
     @PreAuthorize("@ss.hasPermi('his:complaint:add')")
     @PreAuthorize("@ss.hasPermi('his:complaint:add')")
     @Log(title = "用户投诉", businessType = BusinessType.INSERT)
     @Log(title = "用户投诉", businessType = BusinessType.INSERT)
     @PostMapping
     @PostMapping
-    public AjaxResult add(@RequestBody FsUserComplaint fsUserComplaint)
+    public AjaxResult add(@RequestBody FsHisComplaint fsHisComplaint)
     {
     {
-        return toAjax(fsUserComplaintService.insertFsUserComplaint(fsUserComplaint));
+        return toAjax(fsUserComplaintService.insertFsUserComplaint(fsHisComplaint));
     }
     }
 
 
     /**
     /**
@@ -80,9 +80,9 @@ public class FsUserComplaintController extends BaseController
     @PreAuthorize("@ss.hasPermi('his:complaint:edit')")
     @PreAuthorize("@ss.hasPermi('his:complaint:edit')")
     @Log(title = "用户投诉", businessType = BusinessType.UPDATE)
     @Log(title = "用户投诉", businessType = BusinessType.UPDATE)
     @PutMapping
     @PutMapping
-    public AjaxResult edit(@RequestBody FsUserComplaint fsUserComplaint)
+    public AjaxResult edit(@RequestBody FsHisComplaint fsHisComplaint)
     {
     {
-        return toAjax(fsUserComplaintService.updateFsUserComplaint(fsUserComplaint));
+        return toAjax(fsUserComplaintService.updateFsUserComplaint(fsHisComplaint));
     }
     }
 
 
     /**
     /**

+ 20 - 0
fs-admin/src/main/java/com/fs/his/controller/FsIntegralGoodsController.java

@@ -3,20 +3,26 @@ package com.fs.his.controller;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 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.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.his.domain.FsIntegralGoods;
 import com.fs.his.domain.FsIntegralGoods;
 import com.fs.his.service.IFsIntegralGoodsService;
 import com.fs.his.service.IFsIntegralGoodsService;
 import com.fs.his.utils.RedisCacheUtil;
 import com.fs.his.utils.RedisCacheUtil;
+import com.fs.his.vo.FsIntegralGoodsChooseVO;
 import com.fs.his.vo.FsIntegralGoodsListVO;
 import com.fs.his.vo.FsIntegralGoodsListVO;
 import com.fs.his.vo.FsStoreProductExcelVO;
 import com.fs.his.vo.FsStoreProductExcelVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.multipart.MultipartFile;
 
 
+import java.util.HashMap;
 import java.util.List;
 import java.util.List;
+import java.util.Map;
 
 
 /**
 /**
  * 积分商品Controller
  * 积分商品Controller
@@ -127,4 +133,18 @@ public class FsIntegralGoodsController extends BaseController
         redisCacheUtil.delRedisKey("getIntegralGoodsById");
         redisCacheUtil.delRedisKey("getIntegralGoodsById");
         return toAjax(fsIntegralGoodsService.deleteFsIntegralGoodsByGoodsIds(goodsIds));
         return toAjax(fsIntegralGoodsService.deleteFsIntegralGoodsByGoodsIds(goodsIds));
     }
     }
+
+    @GetMapping("/getChooseIntegralGoodsList")
+    public R getChooseIntegralGoodsList(@RequestParam(required = false) String goodsName,
+                                        @RequestParam(required = false) Integer goodsType,
+                                        @RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                                        @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
+        Map<String,Object> params = new HashMap<>();
+        params.put("goodsName", goodsName);
+        params.put("goodsType", goodsType);
+
+        PageHelper.startPage(pageNum, pageSize);
+        List<FsIntegralGoodsChooseVO> list = fsIntegralGoodsService.getChooseIntegralGoodsListByMap(params);
+        return R.ok().put("data", new PageInfo<>(list));
+    }
 }
 }

+ 9 - 17
fs-admin/src/main/java/com/fs/his/controller/FsIntegralOrderController.java

@@ -25,6 +25,7 @@ import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.multipart.MultipartFile;
 
 
 import java.util.List;
 import java.util.List;
+import java.util.Map;
 
 
 import static com.fs.his.utils.PhoneUtil.decryptAutoPhoneMk;
 import static com.fs.his.utils.PhoneUtil.decryptAutoPhoneMk;
 import static com.fs.his.utils.PhoneUtil.decryptPhone;
 import static com.fs.his.utils.PhoneUtil.decryptPhone;
@@ -66,23 +67,7 @@ public class FsIntegralOrderController extends BaseController
     @GetMapping("/export")
     @GetMapping("/export")
     public AjaxResult export(FsIntegralOrder fsIntegralOrder)
     public AjaxResult export(FsIntegralOrder fsIntegralOrder)
     {
     {
-        List<FsIntegralOrder> list = fsIntegralOrderService.selectFsIntegralOrderList(fsIntegralOrder);
-        for (FsIntegralOrder vo : list) {
-            //商品名称以及原价赋值
-            String itemJson = vo.getItemJson();
-            if(StringUtils.isNotBlank(itemJson)){
-                JSONObject jsonObject = JSONObject.parseObject(itemJson);
-                vo.setGoodsName(jsonObject.getString("goodsName"));
-                vo.setOtPrice(jsonObject.getBigDecimal("otPrice"));
-            }
-            if (vo.getUserPhone()!=null&&!vo.getUserPhone().equals("")){
-                if(vo.getUserPhone().chars().allMatch(Character::isDigit)){continue;}
-//                vo.setUserPhone(vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
-                vo.setUserPhone(PhoneUtil.decryptPhone(vo.getUserPhone()));
-            }
-        }
-        ExcelUtil<FsIntegralOrder> util = new ExcelUtil<FsIntegralOrder>(FsIntegralOrder.class);
-        return util.exportExcel(list, "积分商品订单数据");
+        return fsIntegralOrderService.export(fsIntegralOrder);
     }
     }
     /**
     /**
      * 发货
      * 发货
@@ -186,4 +171,11 @@ public class FsIntegralOrderController extends BaseController
     {
     {
         return toAjax(fsIntegralOrderService.deleteFsIntegralOrderByOrderIds(orderIds));
         return toAjax(fsIntegralOrderService.deleteFsIntegralOrderByOrderIds(orderIds));
     }
     }
+    @PreAuthorize("@ss.hasPermi('his:integralOrder:cancel')")
+    @Log(title = "积分商品订单", businessType = BusinessType.UPDATE)
+    @PostMapping("/cancelOrder")
+    public AjaxResult cancelOrder(@RequestBody Map<String, String> requestBody){
+        String orderCode = requestBody.get("orderCode");
+        return toAjax(fsIntegralOrderService.cancelOrder(orderCode));
+    }
 }
 }

+ 36 - 8
fs-admin/src/main/java/com/fs/his/controller/FsPackageController.java

@@ -1,7 +1,9 @@
 package com.fs.his.controller;
 package com.fs.his.controller;
 
 
 import java.util.Collection;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
 import java.util.List;
+import java.util.Map;
 
 
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.core.redis.RedisCache;
@@ -12,20 +14,16 @@ import com.fs.his.param.FsPackageParam;
 import com.fs.his.param.FsStoreProductPackageModifyParam;
 import com.fs.his.param.FsStoreProductPackageModifyParam;
 import com.fs.his.service.IFsFollowTempService;
 import com.fs.his.service.IFsFollowTempService;
 import com.fs.his.utils.RedisCacheUtil;
 import com.fs.his.utils.RedisCacheUtil;
+import com.fs.his.vo.FsPackageChooseVO;
 import com.fs.his.vo.FsPackageExcelVO;
 import com.fs.his.vo.FsPackageExcelVO;
 import com.fs.his.vo.FsPackageListVO;
 import com.fs.his.vo.FsPackageListVO;
 import com.fs.his.vo.OptionsVO;
 import com.fs.his.vo.OptionsVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.AjaxResult;
@@ -147,6 +145,18 @@ public class FsPackageController extends BaseController
         return toAjax(fsPackageService.deleteFsPackageByPackageIds(packageIds));
         return toAjax(fsPackageService.deleteFsPackageByPackageIds(packageIds));
     }
     }
 
 
+
+    /**
+     * 批量复制套餐包
+     */
+    @PreAuthorize("@ss.hasPermi('his:package:bulkCopy')")
+    @Log(title = "套餐包", businessType = BusinessType.DELETE)
+    @GetMapping("/bulkCopy/{packageIds}")
+    public AjaxResult bulkCopy(@PathVariable Long[] packageIds)
+    {
+        return toAjax(fsPackageService.bulkCopyFsPackageByPackage(packageIds));
+    }
+
     /**
     /**
      * 查询套餐包列表
      * 查询套餐包列表
      */
      */
@@ -179,4 +189,22 @@ public class FsPackageController extends BaseController
         return toAjax(fsPackageService.updatePackagesStatus(param.getPackageIds(),param.getStatus()));
         return toAjax(fsPackageService.updatePackagesStatus(param.getPackageIds(),param.getStatus()));
     }
     }
 
 
+    @GetMapping("/getChoosePackageList")
+    public R getChoosePackageList(@RequestParam(required = false) String packageName,
+                                  @RequestParam(required = false) String secondName,
+                                  @RequestParam(required = false) Integer packageType,
+                                  @RequestParam(required = false) Integer packageSubType,
+                                  @RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                                  @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
+        Map<String,Object> params = new HashMap<>();
+        params.put("packageName", packageName);
+        params.put("secondName", secondName);
+        params.put("packageType", packageType);
+        params.put("packageSubType", packageSubType);
+
+        PageHelper.startPage(pageNum, pageSize);
+        List<FsPackageChooseVO> list = fsPackageService.getChoosePackageListByMap(params);
+        return R.ok().put("data", new PageInfo<>(list));
+    }
+
 }
 }

+ 19 - 0
fs-admin/src/main/java/com/fs/his/controller/FsPatientController.java

@@ -67,6 +67,25 @@ public class FsPatientController extends BaseController
         return getDataTable(list);
         return getDataTable(list);
     }
     }
 
 
+    @GetMapping("/userList")
+    public TableDataInfo userList(FsPatientVO fsPatient)
+    {
+        startPage();
+        List<FsPatientVO> list = fsPatientService.selectFsPatientListVO(fsPatient);
+        for (FsPatientVO fsPatientVO : list){
+            if (fsPatientVO.getPhone()!=null){
+                fsPatientVO.setPhone(fsPatientVO.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+            }
+            if (fsPatientVO.getIdCard()!=null){
+                fsPatientVO.setIdCard(fsPatientVO.getIdCard().replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1**********$2"));
+            }
+            if (fsPatientVO.getMobile()!=null){
+                fsPatientVO.setMobile(fsPatientVO.getMobile().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+            }
+        }
+        return getDataTable(list);
+    }
+
     /**
     /**
      * 导出病人列表
      * 导出病人列表
      */
      */

+ 71 - 0
fs-admin/src/main/java/com/fs/his/controller/FsPromotionalActiveController.java

@@ -0,0 +1,71 @@
+package com.fs.his.controller;
+
+import com.fs.common.annotation.Log;
+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.enums.BusinessType;
+import com.fs.his.domain.FsPromotionalActive;
+import com.fs.his.dto.FsPromotionalActiveDTO;
+import com.fs.his.service.IFsPromotionalActiveService;
+import com.fs.his.vo.FsPromotionalActiveVO;
+import lombok.AllArgsConstructor;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 宣传活动控制类
+ */
+@RestController
+@RequestMapping("/his/promotionActive")
+@AllArgsConstructor
+public class FsPromotionalActiveController extends BaseController {
+
+    private final IFsPromotionalActiveService fsPromotionalActiveService;
+
+    @PreAuthorize("@ss.hasPermi('his:promotionActive:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsPromotionalActive active) {
+        startPage();
+        List<FsPromotionalActiveVO> list = fsPromotionalActiveService.selectPromotionalActiveVOList(active);
+        return getDataTable(list);
+    }
+
+    @GetMapping(value = "/{activeId}")
+    public AjaxResult getInfo(@PathVariable Long activeId) {
+        return AjaxResult.success(fsPromotionalActiveService.selectPromotionalActiveVOById(activeId));
+    }
+
+    @PreAuthorize("@ss.hasPermi('his:promotionActive:add')")
+    @Log(title = "宣传活动", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Valid @RequestBody FsPromotionalActiveDTO param) {
+        fsPromotionalActiveService.addPromotionalActive(param);
+        return AjaxResult.success();
+    }
+
+    @PreAuthorize("@ss.hasPermi('his:promotionActive:edit')")
+    @Log(title = "宣传活动", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Valid @RequestBody FsPromotionalActiveDTO param) {
+        fsPromotionalActiveService.editPromotionalActive(param);
+        return AjaxResult.success();
+    }
+
+    @PreAuthorize("@ss.hasPermi('his:promotionActive:remove')")
+    @Log(title = "宣传活动", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{activeIds}")
+    public AjaxResult remove(@PathVariable Long[] activeIds) {
+        fsPromotionalActiveService.logicalRemove(activeIds);
+        return AjaxResult.success();
+    }
+
+    @GetMapping("/getPromotionalActiveOption")
+    public R getPromotionalActiveOption() {
+        return R.ok().put("list", fsPromotionalActiveService.getPromotionalActiveOption());
+    }
+}

+ 41 - 0
fs-admin/src/main/java/com/fs/his/controller/FsPromotionalActiveLogController.java

@@ -0,0 +1,41 @@
+package com.fs.his.controller;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.his.service.IFsPromotionalActiveLogService;
+import com.fs.his.vo.FsPromotionalActiveStatVO;
+import lombok.AllArgsConstructor;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.LocalDate;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RestController
+@RequestMapping("/his/promotionActiveLog")
+@AllArgsConstructor
+public class FsPromotionalActiveLogController extends BaseController {
+
+    private final IFsPromotionalActiveLogService promotionalActiveLogService;
+
+    @PreAuthorize("@ss.hasPermi('his:promotionActiveLog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(@RequestParam(required = false) String name,
+                              @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startTime,
+                              @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endTime) {
+        Map<String, Object> params = new HashMap<>();
+        params.put("name", name);
+        params.put("startTime", startTime);
+        params.put("endTime", endTime);
+
+        startPage();
+        List<FsPromotionalActiveStatVO> list = promotionalActiveLogService.getPromotionalActiveLogStatByMap(params);
+        return getDataTable(list);
+    }
+}

+ 60 - 12
fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java

@@ -2,10 +2,7 @@ package com.fs.his.controller;
 
 
 import java.math.BigDecimal;
 import java.math.BigDecimal;
 import java.text.ParseException;
 import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
@@ -14,10 +11,7 @@ import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.entity.SysRole;
 import com.fs.common.core.domain.entity.SysRole;
 import com.fs.common.core.domain.entity.SysUser;
 import com.fs.common.core.domain.entity.SysUser;
 import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.core.domain.model.LoginUser;
-import com.fs.common.utils.ParseUtils;
-import com.fs.common.utils.SecurityUtils;
-import com.fs.common.utils.ServletUtils;
-import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.*;
 import com.fs.company.param.CompanyStoreOrderMoneyLogsListParam;
 import com.fs.company.param.CompanyStoreOrderMoneyLogsListParam;
 import com.fs.company.service.ICompanyMoneyLogsService;
 import com.fs.company.service.ICompanyMoneyLogsService;
 import com.fs.company.vo.CompanyStoreOrderMoneyLogsVO;
 import com.fs.company.vo.CompanyStoreOrderMoneyLogsVO;
@@ -38,6 +32,7 @@ import com.fs.his.dto.ExpressInfoDTO;
 import com.fs.his.dto.StoreOrderExpressExportDTO;
 import com.fs.his.dto.StoreOrderExpressExportDTO;
 import com.fs.his.dto.TracesDTO;
 import com.fs.his.dto.TracesDTO;
 import com.fs.his.enums.FsStoreOrderLogEnum;
 import com.fs.his.enums.FsStoreOrderLogEnum;
+import com.fs.his.enums.FsStoreOrderStatusEnum;
 import com.fs.his.enums.ShipperCodeEnum;
 import com.fs.his.enums.ShipperCodeEnum;
 import com.fs.his.param.FsFollowMsgParam;
 import com.fs.his.param.FsFollowMsgParam;
 import com.fs.his.param.FsStoreOrderParam;
 import com.fs.his.param.FsStoreOrderParam;
@@ -224,11 +219,19 @@ public class FsStoreOrderController extends BaseController
     @PreAuthorize("@ss.hasPermi('store:storeOrder:export')")
     @PreAuthorize("@ss.hasPermi('store:storeOrder:export')")
     @Log(title = "导出订单", businessType = BusinessType.EXPORT)
     @Log(title = "导出订单", businessType = BusinessType.EXPORT)
     @GetMapping("/orderExport")
     @GetMapping("/orderExport")
-    public AjaxResult orderExport(FsStoreOrderParam param) {
+    public AjaxResult orderExport(FsStoreOrderParam param,String filter) {
         Integer exportType1 = exportTaskService.isExportType1(SecurityUtils.getUserId());
         Integer exportType1 = exportTaskService.isExportType1(SecurityUtils.getUserId());
 //        if (exportType1>0){
 //        if (exportType1>0){
 //            return AjaxResult.error("你已经有正在导出的任务");
 //            return AjaxResult.error("你已经有正在导出的任务");
 //        }
 //        }
+        // 1. 处理filter参数:将逗号分隔的字符串拆分为ArrayList<String>
+        ArrayList<String> filterList = new ArrayList<>();
+        if (StringUtils.isNotBlank(filter)) {
+            // 按逗号拆分,同时去除可能的空格(如filter传"orderId, orderCode"时兼容)
+            String[] filterArr = filter.split("\\s*,\\s*");
+            filterList.addAll(Arrays.asList(filterArr));
+        }
+
         if (fsStoreOrderService.isEntityNull(param)){
         if (fsStoreOrderService.isEntityNull(param)){
             return AjaxResult.error("请筛选数据导出");
             return AjaxResult.error("请筛选数据导出");
         }
         }
@@ -255,7 +258,7 @@ public class FsStoreOrderController extends BaseController
         exportTaskService.insertFsExportTask(task);
         exportTaskService.insertFsExportTask(task);
         param.setTaskId(task.getTaskId());
         param.setTaskId(task.getTaskId());
         boolean checkPhone = isCheckPhone();
         boolean checkPhone = isCheckPhone();
-        exportTaskService.exportStore1Data(param,checkPhone);
+        exportTaskService.exportStore1Data(param,checkPhone, filterList);
 
 
         return new AjaxResult(200,"后台正在导出,请等待...任务ID:"+task.getTaskId(),task.getTaskId());
         return new AjaxResult(200,"后台正在导出,请等待...任务ID:"+task.getTaskId(),task.getTaskId());
 
 
@@ -359,7 +362,11 @@ public class FsStoreOrderController extends BaseController
             moneyLogsMap.setBusinessId(order.getOrderId());
             moneyLogsMap.setBusinessId(order.getOrderId());
             tuiMoneyLogs=moneyLogsService.selectCompanyStoreOrderMoneyLogsList(moneyLogsMap);
             tuiMoneyLogs=moneyLogsService.selectCompanyStoreOrderMoneyLogsList(moneyLogsMap);
         }
         }
-        return R.ok().put("data",order).put("tuiMoneyLogs",tuiMoneyLogs);
+        if ((CloudHostUtils.hasCloudHostName("金牛明医"))){
+            return R.ok().put("data",order).put("tuiMoneyLogs",tuiMoneyLogs).put("isUpdateRefund",1).put("isUpdatePayRemain",1);
+        } else {
+            return R.ok().put("data",order).put("tuiMoneyLogs",tuiMoneyLogs).put("isUpdateRefund",0).put("isUpdatePayRemain",0);
+        }
     }
     }
 
 
     @GetMapping(value = "/queryPhone/{orderId}")
     @GetMapping(value = "/queryPhone/{orderId}")
@@ -415,9 +422,40 @@ public class FsStoreOrderController extends BaseController
     @PutMapping
     @PutMapping
     public AjaxResult edit(@RequestBody FsStoreOrder fsStoreOrder)
     public AjaxResult edit(@RequestBody FsStoreOrder fsStoreOrder)
     {
     {
+        AjaxResult error = moneyCheck(fsStoreOrder);
+        if (error != null) return error;
         return toAjax(fsStoreOrderService.updateFsStoreOrder(fsStoreOrder));
         return toAjax(fsStoreOrderService.updateFsStoreOrder(fsStoreOrder));
     }
     }
 
 
+    private AjaxResult moneyCheck(FsStoreOrder fsStoreOrder) {
+        BigDecimal payRemain = fsStoreOrder.getPayRemain();
+        BigDecimal payPrice = fsStoreOrder.getPayPrice();
+        if (payRemain != null && payPrice == null){
+            return AjaxResult.error("订单应收金额不正确!");
+        }
+        if (payRemain == null && payPrice != null){
+            return AjaxResult.error("订单物流代收金额不正确!");
+        }
+        if (payRemain != null && payPrice != null){
+            FsStoreOrder temp = fsStoreOrderService.selectFsStoreOrderByOrderId(fsStoreOrder.getOrderId());
+            if (!((Objects.equals(temp.getStatus(), FsStoreOrderStatusEnum.STATUS_2.getValue())
+                    || (Objects.equals(temp.getStatus(), FsStoreOrderStatusEnum.STATUS_1.getValue())))
+                    || (StringUtils.isNotBlank(temp.getExtendOrderId())))
+            ){
+
+                BigDecimal payMoney = temp.getPayMoney();
+                if (fsStoreOrder.getPayMoney()!=null){
+                    fsStoreOrder.setPayMoney(payMoney);
+                }
+                BigDecimal tempPayPrice = payMoney.add(payRemain);
+                if(0 != tempPayPrice.compareTo(fsStoreOrder.getPayPrice())){
+                    return AjaxResult.error("订单金额不正确!");
+                }
+            }
+        }
+        return null;
+    }
+
     /**
     /**
      * 修改订单
      * 修改订单
      */
      */
@@ -578,7 +616,15 @@ public class FsStoreOrderController extends BaseController
     {
     {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         fsStoreOrder.setOperator(loginUser.getUser().getNickName());
         fsStoreOrder.setOperator(loginUser.getUser().getNickName());
-        return toAjax(fsStoreOrderService.afterSales(fsStoreOrder));
+        if (fsStoreOrder.getRefundAmount() != null){
+            if (fsStoreOrder.getRefundList()!=null && !fsStoreOrder.getRefundList().isEmpty()){
+                return toAjax(fsStoreOrderService.afterSalesByProduct(fsStoreOrder));
+            } else {
+                return AjaxResult.error("没有选择需要退款的商品!");
+            }
+        } else {
+            return toAjax(fsStoreOrderService.afterSales(fsStoreOrder));
+        }
     }
     }
 
 
     /**
     /**
@@ -658,6 +704,7 @@ public class FsStoreOrderController extends BaseController
                 df.setOrderId(orderId);
                 df.setOrderId(orderId);
                 FsStoreOrderDf temp = fsStoreOrderDfService.selectFsStoreOrderDfByOrderId(df.getOrderId());
                 FsStoreOrderDf temp = fsStoreOrderDfService.selectFsStoreOrderDfByOrderId(df.getOrderId());
                 if (temp == null){
                 if (temp == null){
+                    df.setParcelQuantity(param.getParcelQuantity()); //设置包裹数量
                     fsStoreOrderDfService.insertFsStoreOrderDf(df);
                     fsStoreOrderDfService.insertFsStoreOrderDf(df);
                     fsStoreOrderLogsService.create(orderId, FsStoreOrderLogEnum.SET_PUSH_ACCOUNT.getValue(),
                     fsStoreOrderLogsService.create(orderId, FsStoreOrderLogEnum.SET_PUSH_ACCOUNT.getValue(),
                             nickName + " " +FsStoreOrderLogEnum.SET_PUSH_ACCOUNT.getDesc() + ":" + df.getLoginAccount());
                             nickName + " " +FsStoreOrderLogEnum.SET_PUSH_ACCOUNT.getDesc() + ":" + df.getLoginAccount());
@@ -702,6 +749,7 @@ public class FsStoreOrderController extends BaseController
         orderIds.forEach(orderId->{
         orderIds.forEach(orderId->{
             df.setOrderId(orderId);
             df.setOrderId(orderId);
             FsStoreOrderDf temp = fsStoreOrderDfService.selectFsStoreOrderDfByOrderId(df.getOrderId());
             FsStoreOrderDf temp = fsStoreOrderDfService.selectFsStoreOrderDfByOrderId(df.getOrderId());
+            df.setParcelQuantity(param.getParcelQuantity());
             if (temp != null){
             if (temp != null){
                 df.setUpdateTime(new Date());
                 df.setUpdateTime(new Date());
                 fsStoreOrderDfService.updateFsStoreOrderDf(df);
                 fsStoreOrderDfService.updateFsStoreOrderDf(df);

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

@@ -4,7 +4,6 @@ import java.util.List;
 
 
 import com.fs.his.param.FsTestTempItemParam;
 import com.fs.his.param.FsTestTempItemParam;
 import com.fs.his.vo.FsTestTempItemListVO;
 import com.fs.his.vo.FsTestTempItemListVO;
-import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.PostMapping;

+ 7 - 1
fs-admin/src/main/java/com/fs/his/task/Task.java

@@ -67,6 +67,7 @@ import org.springframework.stereotype.Component;
 
 
 import java.util.*;
 import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
+import java.util.concurrent.CompletableFuture;
 
 
 @Slf4j
 @Slf4j
 @Component("task")
 @Component("task")
@@ -566,9 +567,14 @@ public class Task {
         if (erpOrderService !=null && erpOrderService == dfOrderService){
         if (erpOrderService !=null && erpOrderService == dfOrderService){
             orders = fsStoreOrderMapper.selectShippedOrder();
             orders = fsStoreOrderMapper.selectShippedOrder();
             if(orders!=null&& !orders.isEmpty()){
             if(orders!=null&& !orders.isEmpty()){
+                List<CompletableFuture<Void>> futures = new ArrayList<>();
                 for(FsStoreOrder order:orders){
                 for(FsStoreOrder order:orders){
-                    erpOrderService.getOrderDeliveryStatus(order);
+                    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
+                        erpOrderService.getOrderDeliveryStatus(order);
+                    });
+                    futures.add(future);
                 }
                 }
+                CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
             }
             }
         }
         }
     }
     }

+ 24 - 0
fs-admin/src/main/java/com/fs/hisStore/FsHisStoreLogController.java

@@ -0,0 +1,24 @@
+package com.fs.hisStore;
+
+import com.fs.common.core.domain.R;
+import com.fs.hisStore.domain.SysOperLogScrm;
+import com.fs.hisStore.service.IFsHisStoreAuditLogScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/store/hisStoreLog")
+public class FsHisStoreLogController {
+
+    @Autowired
+    private IFsHisStoreAuditLogScrmService fsHisStoreLogScrmService;
+    @RequestMapping("/{mainId}")
+    public R getInfo(@PathVariable("mainId") Long mainId) {
+        List<SysOperLogScrm> sysOperLogScrms = fsHisStoreLogScrmService.selectOperLogByMainId(mainId);
+        return R.ok().put("data",sysOperLogScrms);
+    }
+}

+ 134 - 0
fs-admin/src/main/java/com/fs/hisStore/FsStoreSCRMController.java

@@ -0,0 +1,134 @@
+package com.fs.hisStore;
+
+import com.fs.common.annotation.Log;
+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.enums.BusinessType;
+import com.fs.common.utils.ParseUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.his.domain.FsStore;
+import com.fs.his.param.FsStoreAuditParam;
+import com.fs.his.service.IFsStoreService;
+import com.fs.hisStore.domain.FsStoreScrm;
+import com.fs.hisStore.service.IFsStoreScrmService;
+import com.fs.hisStore.vo.FsStoreScrmVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 店铺管理Controller
+ *
+ * @author fs
+ * @date 2023-06-15
+ */
+@RestController
+@RequestMapping("/store/store")
+public class FsStoreSCRMController extends BaseController
+{
+    @Autowired
+    private IFsStoreScrmService fsStoreService;
+
+    /**
+     * 查询店铺管理列表
+     */
+    @PreAuthorize("@ss.hasPermi('store:store:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreScrm fsStore)
+    {
+        startPage();
+        List<FsStoreScrm> list = fsStoreService.selectFsStoreList(fsStore);
+        for (FsStoreScrm store : list) {
+            store.setPhone(ParseUtils.parsePhone(store.getPhone()));
+        }
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出店铺管理列表
+     */
+    @PreAuthorize("@ss.hasPermi('store:store:export')")
+    @Log(title = "店铺管理", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreScrm fsStore)
+    {
+        List<FsStoreScrm> list = fsStoreService.selectFsStoreList(fsStore);
+        for (FsStoreScrm store : list) {
+            store.setPhone(ParseUtils.parsePhone(store.getPhone()));
+        }
+        ExcelUtil<FsStoreScrm> util = new ExcelUtil<FsStoreScrm>(FsStoreScrm.class);
+        return util.exportExcel(list, "店铺管理数据");
+    }
+
+    /**
+     * 获取店铺管理详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('store:store:query')")
+    @GetMapping(value = "/{storeId}")
+    public AjaxResult getInfo(@PathVariable("storeId") Long storeId)
+    {
+        FsStoreScrm fsStore = fsStoreService.selectFsStoreByStoreId(storeId);
+        fsStore.setPhone(ParseUtils.parsePhone(fsStore.getPhone()));
+        return AjaxResult.success(fsStore);
+    }
+
+    /**
+     * 新增店铺管理
+     */
+    @PreAuthorize("@ss.hasPermi('store:store:add')")
+    @Log(title = "店铺管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreScrm fsStore)
+    {
+        return AjaxResult.success(fsStoreService.insertFsStore(fsStore));
+    }
+
+    /**
+     * 修改店铺管理
+     */
+    @PreAuthorize("@ss.hasPermi('store:store:edit')")
+    @Log(title = "店铺管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreScrm fsStore)
+    {
+
+        if (fsStore.getPhone()!=null&&fsStore.getPhone().contains("*")){
+            fsStore.setPhone(null);
+        }
+        return toAjax(fsStoreService.updateFsStore(fsStore));
+    }
+
+    /**
+     * 删除店铺管理
+     */
+    @PreAuthorize("@ss.hasPermi('store:store:remove')")
+    @Log(title = "店铺管理", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{storeIds}")
+    public AjaxResult remove(@PathVariable Long[] storeIds)
+    {
+        return toAjax(fsStoreService.deleteFsStoreByStoreIds(storeIds));
+    }
+
+    /**
+     * 店铺审核
+     */
+    @PreAuthorize("@ss.hasPermi('store:store:audit')")
+    @Log(title = "店铺管理", businessType = BusinessType.UPDATE)
+    @PutMapping("/audit")
+    public AjaxResult audit(@RequestBody FsStoreAuditParam fsStore)
+    {
+        return toAjax(fsStoreService.updateFsStoreAudit(fsStore));
+    }
+
+    @GetMapping("/storeList")
+    public R storeList(){
+        List<FsStoreScrmVO> list = fsStoreService.selectAllStore();
+        return R.ok().put("data",list);
+    }
+
+
+}

+ 27 - 2
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreProductScrmController.java

@@ -21,6 +21,7 @@ import com.fs.hisStore.param.FsStoreTuiProductAttrValueParam;
 import com.fs.hisStore.service.IFsStoreProductAttrScrmService;
 import com.fs.hisStore.service.IFsStoreProductAttrScrmService;
 import com.fs.hisStore.service.IFsStoreProductAttrValueScrmService;
 import com.fs.hisStore.service.IFsStoreProductAttrValueScrmService;
 import com.fs.hisStore.service.IFsStoreProductScrmService;
 import com.fs.hisStore.service.IFsStoreProductScrmService;
+import com.fs.statis.dto.ProductAuditDTO;
 import com.mysql.cj.util.StringUtils;
 import com.mysql.cj.util.StringUtils;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
@@ -69,6 +70,17 @@ public class FsStoreProductScrmController extends BaseController
         return R.ok();
         return R.ok();
     }
     }
 
 
+    @PreAuthorize("@ss.hasPermi('store:storeProduct:list')")
+    @PostMapping("/batchAudit")
+    @Log(title = "商品审核", businessType = BusinessType.AUDIT,isStoreLog = true,logParam = {"商品","批量审核商品信息"},
+    logParamExpression = "#p0.getProductIds().size()>1?"
+            +"(#p0.isAudit==1?new String[]{'商品','商品批量审核通过'}: new String[]{'商品','商品批量审核退回'}):" +
+            "(#p0.isAudit==1?new String[]{'商品','商品审核通过'}: new String[]{'商品','商品审核退回'})")
+    public R batchAudit(@RequestBody ProductAuditDTO auditDTO){
+        fsStoreProductService.batchAudit(auditDTO);
+        return R.ok();
+    }
+
     /**
     /**
      * 查询商品列表
      * 查询商品列表
      */
      */
@@ -167,10 +179,23 @@ public class FsStoreProductScrmController extends BaseController
         return toAjax(fsStoreProductService.deleteFsStoreProductByIds(productIds));
         return toAjax(fsStoreProductService.deleteFsStoreProductByIds(productIds));
     }
     }
 
 
+
+    /**
+     * 批量复制商品
+     */
+    @PreAuthorize("@ss.hasPermi('store:storeProduct:bulkCopy')")
+    @Log(title = "商品管理", businessType = BusinessType.UPDATE,isStoreLog = true,
+            logParamExpression ="#p0.length>1?new String[]{'商品','批量复制商品信息'}: new String[]{'商品','复制商品信息'}" )
+    @GetMapping("/bulkCopy/{productIds}")
+    public R bulkCopy(@PathVariable Long[] productIds)
+    {
+        return fsStoreProductService.bulkCopyFsStoreProductByIds(productIds);
+    }
+
     @ApiOperation(value = "生成属性")
     @ApiOperation(value = "生成属性")
     @PostMapping(value = "/genFormatAttr/{productId}")
     @PostMapping(value = "/genFormatAttr/{productId}")
-    public ResponseEntity genFormatAttr(@PathVariable Long productId, @RequestBody String jsonStr){
-        return new ResponseEntity<>(fsStoreProductService.getFormatAttr(productId,jsonStr), HttpStatus.OK);
+    public ResponseEntity genFormatAttr(@PathVariable Long productId, @RequestBody String jsonStr,Long[] stores){
+        return new ResponseEntity<>(fsStoreProductService.getFormatAttr(productId,jsonStr, stores), HttpStatus.OK);
     }
     }
 
 
 
 

+ 108 - 0
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreRecommendScrmController.java

@@ -0,0 +1,108 @@
+package com.fs.hisStore.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.domain.FsStoreRecommendScrm;
+import com.fs.hisStore.service.IFsStoreRecommendScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 店铺推荐Controller
+ *
+ * @author fs
+ * @date 2023-06-15
+ */
+@RestController
+@RequestMapping("/store/recommend")
+public class FsStoreRecommendScrmController extends BaseController
+{
+    @Autowired
+    private IFsStoreRecommendScrmService fsStoreRecommendService;
+
+    /**
+     * 查询店铺推荐列表
+     */
+    @PreAuthorize("@ss.hasPermi('store:recommend:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsStoreRecommendScrm fsStoreRecommendScrm)
+    {
+        startPage();
+        List<FsStoreRecommendScrm> list = fsStoreRecommendService.selectFsStoreRecommendScrmList(fsStoreRecommendScrm);
+        return getDataTable(list);
+    }
+
+    /**
+     * 获取店铺推荐详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('store:recommend:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsStoreRecommendService.selectFsStoreRecommendScrmById(id));
+    }
+
+    /**
+     * 新增店铺推荐
+     */
+    @PreAuthorize("@ss.hasPermi('store:recommend:add')")
+    @Log(title = "店铺推荐", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsStoreRecommendScrm fsStoreRecommendScrm)
+    {
+        return toAjax(fsStoreRecommendService.insertFsStoreRecommendScrm(fsStoreRecommendScrm));
+    }
+
+    /**
+     * 修改店铺推荐
+     */
+    @PreAuthorize("@ss.hasPermi('store:recommend:edit')")
+    @Log(title = "店铺推荐", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsStoreRecommendScrm fsStoreRecommendScrm)
+    {
+        return toAjax(fsStoreRecommendService.updateFsStoreRecommendScrm(fsStoreRecommendScrm));
+    }
+
+    /**
+     * 删除店铺推荐
+     */
+    @PreAuthorize("@ss.hasPermi('store:recommend:delete')")
+    @Log(title = "店铺推荐", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsStoreRecommendService.deleteFsStoreRecommendScrmByIds(ids));
+    }
+
+    /**
+     * 查询有效的推荐店铺列表(用于前端展示)
+     */
+    @GetMapping("/validList")
+    public TableDataInfo validList(FsStoreRecommendScrm fsStoreRecommendScrm)
+    {
+        startPage();
+        List<FsStoreRecommendScrm> list = fsStoreRecommendService.selectValidRecommendList(fsStoreRecommendScrm);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出
+     * */
+    @PreAuthorize("@ss.hasPermi('store:recommend:export')")
+    @Log(title = "店铺推荐", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsStoreRecommendScrm fsStoreRecommendScrm)
+        {
+        List<FsStoreRecommendScrm> list = fsStoreRecommendService.selectFsStoreRecommendScrmList(fsStoreRecommendScrm);
+        ExcelUtil<FsStoreRecommendScrm> util = new ExcelUtil<>(FsStoreRecommendScrm.class);
+        return util.exportExcel(list, "店铺推荐数据");
+    }
+}

+ 20 - 3
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreScrmController.java

@@ -3,6 +3,7 @@ package com.fs.hisStore.controller;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 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.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ParseUtils;
 import com.fs.common.utils.ParseUtils;
@@ -10,6 +11,7 @@ import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.hisStore.domain.FsStoreScrm;
 import com.fs.hisStore.domain.FsStoreScrm;
 import com.fs.his.param.FsStoreAuditParam;
 import com.fs.his.param.FsStoreAuditParam;
 import com.fs.hisStore.service.IFsStoreScrmService;
 import com.fs.hisStore.service.IFsStoreScrmService;
+import com.fs.hisStore.utils.StoreAuditLogUtil;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
@@ -29,6 +31,9 @@ public class FsStoreScrmController extends BaseController
     @Autowired
     @Autowired
     private IFsStoreScrmService fsStoreService;
     private IFsStoreScrmService fsStoreService;
 
 
+    @Autowired
+    private StoreAuditLogUtil storeAuditLogUtil;
+
     /**
     /**
      * 查询店铺管理列表
      * 查询店铺管理列表
      */
      */
@@ -52,6 +57,7 @@ public class FsStoreScrmController extends BaseController
     @GetMapping("/export")
     @GetMapping("/export")
     public AjaxResult export(FsStoreScrm fsStore)
     public AjaxResult export(FsStoreScrm fsStore)
     {
     {
+        storeAuditLogUtil.generateOperId();
         List<FsStoreScrm> list = fsStoreService.selectFsStoreList(fsStore);
         List<FsStoreScrm> list = fsStoreService.selectFsStoreList(fsStore);
         for (FsStoreScrm store : list) {
         for (FsStoreScrm store : list) {
             store.setPhone(ParseUtils.parsePhone(store.getPhone()));
             store.setPhone(ParseUtils.parsePhone(store.getPhone()));
@@ -80,7 +86,8 @@ public class FsStoreScrmController extends BaseController
     @PostMapping
     @PostMapping
     public AjaxResult add(@RequestBody FsStoreScrm fsStore)
     public AjaxResult add(@RequestBody FsStoreScrm fsStore)
     {
     {
-        return toAjax(fsStoreService.insertFsStore(fsStore));
+        storeAuditLogUtil.addOperLog(fsStoreService.insertFsStore(fsStore));
+        return AjaxResult.success();
     }
     }
 
 
     /**
     /**
@@ -113,7 +120,8 @@ public class FsStoreScrmController extends BaseController
      * 店铺审核
      * 店铺审核
      */
      */
     @PreAuthorize("@ss.hasPermi('his:store:audit')")
     @PreAuthorize("@ss.hasPermi('his:store:audit')")
-    @Log(title = "店铺审核", businessType = BusinessType.UPDATE,logParam = {"店铺","店铺审核"},isStoreLog = true)
+    @Log(title = "店铺审核", businessType = BusinessType.AUDIT,logParam = {"店铺","店铺审核"},isStoreLog = true
+    ,logParamExpression = "#p0.getIsAudit()==1?new String[]{'店铺','店铺审核通过'}: new String[]{'店铺','店铺审核退回'}")
     @PutMapping("/audit")
     @PutMapping("/audit")
     public AjaxResult audit(@RequestBody FsStoreAuditParam fsStore)
     public AjaxResult audit(@RequestBody FsStoreAuditParam fsStore)
     {
     {
@@ -126,9 +134,18 @@ public class FsStoreScrmController extends BaseController
     @PreAuthorize("@ss.hasPermi('his:store:refresh')")
     @PreAuthorize("@ss.hasPermi('his:store:refresh')")
     @Log(title = "店铺管理", businessType = BusinessType.UPDATE,logParam = {"店铺","重置店铺密码"},isStoreLog = true)
     @Log(title = "店铺管理", businessType = BusinessType.UPDATE,logParam = {"店铺","重置店铺密码"},isStoreLog = true)
     @PutMapping("/refresh/{storeId}")
     @PutMapping("/refresh/{storeId}")
-    public AjaxResult refresh(Long storeId)
+    public AjaxResult refresh(@PathVariable Long storeId)
     {
     {
         return toAjax(fsStoreService.refreshFsStore(storeId));
         return toAjax(fsStoreService.refreshFsStore(storeId));
     }
     }
 
 
+
+    /**
+     * 店铺审核日志
+     * */
+    @PreAuthorize("@ss.hasPermi('his:store:auditLog')")
+    @GetMapping("/auditLog/{storeId}")
+    public R auditLog(@PathVariable Long storeId){
+        return R.ok().put("auditLog",storeAuditLogUtil.selectOperLogByMainId(storeId));
+    }
 }
 }

+ 11 - 1
fs-admin/src/main/java/com/fs/hisStore/controller/SysOperlogScrmController.java

@@ -3,11 +3,14 @@ package com.fs.hisStore.controller;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 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.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.hisStore.param.StoreOperMainQueryParam;
 import com.fs.hisStore.service.ISysOperLogScrmService;
 import com.fs.hisStore.service.ISysOperLogScrmService;
 import com.fs.hisStore.domain.SysOperLogScrm;
 import com.fs.hisStore.domain.SysOperLogScrm;
+import com.fs.hisStore.vo.StoreOperMainVO;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 
 
@@ -28,7 +31,7 @@ public class SysOperlogScrmController extends BaseController
         this.operLogService = operLogService;
         this.operLogService = operLogService;
     }
     }
 
 
-    @PreAuthorize("@ss.hasPermi('his:storeLog:export')")
+    @PreAuthorize("@ss.hasPermi('his:storeLog:list')")
     @GetMapping("/list")
     @GetMapping("/list")
     public TableDataInfo list(SysOperLogScrm operLog)
     public TableDataInfo list(SysOperLogScrm operLog)
     {
     {
@@ -36,6 +39,13 @@ public class SysOperlogScrmController extends BaseController
         List<SysOperLogScrm> list = operLogService.selectOperLogList(operLog);
         List<SysOperLogScrm> list = operLogService.selectOperLogList(operLog);
         return getDataTable(list);
         return getDataTable(list);
     }
     }
+    @PreAuthorize("@ss.hasPermi('his:storeLog:list')")
+    @GetMapping("/getMains")
+    public R getMains(StoreOperMainQueryParam operLog)
+    {
+        List<StoreOperMainVO> list = operLogService.getMains(operLog);
+        return R.ok().put("data", list);
+    }
 
 
     @Log(title = "操作日志", businessType = BusinessType.EXPORT)
     @Log(title = "操作日志", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('his:storeLog:export')")
     @PreAuthorize("@ss.hasPermi('his:storeLog:export')")

+ 94 - 0
fs-admin/src/main/java/com/fs/qw/FsCourseTask.java

@@ -1,11 +1,27 @@
 package com.fs.qw;
 package com.fs.qw;
 
 
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.redis.RedisCache;
 import com.fs.course.service.IFsCourseWatchLogService;
 import com.fs.course.service.IFsCourseWatchLogService;
 import com.fs.qw.service.IQwWorkTaskService;
 import com.fs.qw.service.IQwWorkTaskService;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.mapper.SysConfigMapper;
+import io.jsonwebtoken.lang.Assert;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.http.util.Asserts;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
 /**
 /**
  * 后台统计相关 定时任务
  * 后台统计相关 定时任务
  */
  */
@@ -16,7 +32,85 @@ public class FsCourseTask {
     private IFsCourseWatchLogService fsCourseWatchLogService;
     private IFsCourseWatchLogService fsCourseWatchLogService;
     @Autowired
     @Autowired
     private IQwWorkTaskService qwWorkTaskService;
     private IQwWorkTaskService qwWorkTaskService;
+    @Autowired
+    private RedisCache redisCache;
+    private static final String REDPACKET_COMPANY_MONEY_CHANGE = "redpacket_money_CHANGE";
+    @Autowired
+    private SysConfigMapper sysConfigMapper;
+    private static final String REDPACKET_POOL_LOCK = "redpacket_pool_lock";
+    private static final String REDPACKET_COMPANY_MONEY = "redpacket_money";
+
+    @Autowired
+    private RedissonClient redissonClient;
+
+    /**
+     * 润天公司账户充值
+     * @param chargeMoney 充值金额
+     */
+    public void rechargeRedpacketMoney(String chargeMoney){
+        Assert.notNull(chargeMoney,"充值金额不能为空!");
+
+        log.info("润天公司账户充值 充值金额: {}",chargeMoney);
+
+        RLock lock = redissonClient.getLock(REDPACKET_POOL_LOCK);
+        try{
+            boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
+
+            if (!locked) {
+                log.error("获取锁失败...");
+                return;
+            }
+
+            BigDecimal redPacketCompanyMoney = redisCache.getCacheObject(REDPACKET_COMPANY_MONEY);
+            if(ObjectUtils.isNull(redPacketCompanyMoney)){
+                redPacketCompanyMoney = BigDecimal.ZERO;
+            }
+            BigDecimal value = redPacketCompanyMoney.add(new BigDecimal(chargeMoney));
+
+            log.info("润天公司账户充值成功 目前余额: {}",value);
 
 
+            redisCache.setCacheObject(REDPACKET_COMPANY_MONEY,value);
+
+
+            // 保存到数据库
+            SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("company.money");
+
+            sysConfig.setConfigValue(value.setScale(4, RoundingMode.HALF_UP).toPlainString());
+            sysConfig.setConfigKey("company.money");
+            sysConfigMapper.updateConfig(sysConfig);
+
+        }catch (Exception e){
+            log.error("充值失败 原因:{}", ExceptionUtils.getFullStackTrace(e),e);
+            throw new RuntimeException(e);
+        }finally {
+            if (lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
+        }
+    }
+    /**
+     * 公司红包金额变更
+     */
+    public void redpacketCompanyMoneyChange(){
+        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("company.money");
+        Asserts.notNull(sysConfig,"公司账户配置不能为空!");
+
+        String configValue = sysConfig.getConfigValue();
+        Asserts.notNull(configValue,"公司账户余额不能为空");
+
+        BigDecimal oldBigDecimal = new BigDecimal(configValue);
+
+        BigDecimal redPacketCompanyMoney = redisCache.getCacheObject(REDPACKET_COMPANY_MONEY);
+
+        log.info("公司账户红包余额变更 {} -> {}",oldBigDecimal,redPacketCompanyMoney);
+
+        // 如果两者不一致才同步到数据库
+        if(oldBigDecimal.compareTo(redPacketCompanyMoney) != 0){
+            sysConfig.setConfigValue(redPacketCompanyMoney.setScale(4, RoundingMode.HALF_UP).toPlainString());
+            sysConfig.setConfigKey("company.money");
+            sysConfigMapper.updateConfig(sysConfig);
+        }
+    }
     /**
     /**
      * 添加企微观看日志
      * 添加企微观看日志
      * @throws Exception
      * @throws Exception

+ 33 - 1
fs-admin/src/main/java/com/fs/qw/controller/QwCompanyController.java

@@ -2,8 +2,14 @@ package com.fs.qw.controller;
 
 
 import java.util.List;
 import java.util.List;
 
 
+import cn.hutool.json.JSONUtil;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.utils.ServletUtils;
+import com.fs.course.config.CourseConfig;
+import com.fs.framework.web.service.TokenService;
 import com.fs.qw.vo.QwOptionsVO;
 import com.fs.qw.vo.QwOptionsVO;
+import com.fs.system.service.ISysConfigService;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -35,6 +41,10 @@ public class QwCompanyController extends BaseController
 {
 {
     @Autowired
     @Autowired
     private IQwCompanyService qwCompanyService;
     private IQwCompanyService qwCompanyService;
+    @Autowired
+    private TokenService tokenService;
+    @Autowired
+    private ISysConfigService configService;
 
 
     /**
     /**
      * 查询企微主体列表
      * 查询企微主体列表
@@ -44,6 +54,13 @@ public class QwCompanyController extends BaseController
     public TableDataInfo list(QwCompany qwCompany)
     public TableDataInfo list(QwCompany qwCompany)
     {
     {
         startPage();
         startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
+            qwCompany.setCreateDeptId(loginUser.getDeptId());
+            qwCompany.setCreateUserId(loginUser.getUserId());
+        }
         List<QwCompany> list = qwCompanyService.selectQwCompanyList(qwCompany);
         List<QwCompany> list = qwCompanyService.selectQwCompanyList(qwCompany);
         return getDataTable(list);
         return getDataTable(list);
     }
     }
@@ -52,7 +69,18 @@ public class QwCompanyController extends BaseController
     @GetMapping("/all")
     @GetMapping("/all")
     public R all()
     public R all()
     {
     {
-        List<QwOptionsVO> list = qwCompanyService.selectQwCompanyListOptionsVO();
+        Long userId = null;
+        Long deptId = null;
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
+            deptId = loginUser.getDeptId();
+            if(config.getDept() == null || !config.getDept()){
+                userId = loginUser.getUserId();
+            }
+        }
+        List<QwOptionsVO> list = qwCompanyService.selectQwCompanyListOptionsVO(userId, deptId);
         return R.ok().put("data", list);
         return R.ok().put("data", list);
     }
     }
     /**
     /**
@@ -86,6 +114,10 @@ public class QwCompanyController extends BaseController
     @PostMapping
     @PostMapping
     public AjaxResult add(@RequestBody QwCompany qwCompany)
     public AjaxResult add(@RequestBody QwCompany qwCompany)
     {
     {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+
+        qwCompany.setCreateUserId(loginUser.getUserId());
+        qwCompany.setCreateDeptId(loginUser.getDeptId());
         return toAjax(qwCompanyService.insertQwCompany(qwCompany));
         return toAjax(qwCompanyService.insertQwCompany(qwCompany));
     }
     }
 
 

+ 50 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwExternalContactTransferCompanyAuditController.java

@@ -0,0 +1,50 @@
+package com.fs.qw.controller;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.utils.SecurityUtils;
+import com.fs.qw.domain.QwExternalContactTransferCompanyAudit;
+import com.fs.qw.dto.CompanyTransferAuditDTO;
+import com.fs.qw.service.IQwExternalContactTransferCompanyAuditService;
+import com.fs.qw.service.IQwExternalContactTransferCompanyAuditUserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.List;
+
+@RestController
+@RequestMapping("/qw/externalContactTransferCompanyAudit")
+public class QwExternalContactTransferCompanyAuditController extends BaseController {
+
+    @Autowired
+    private IQwExternalContactTransferCompanyAuditService auditService;
+    @Autowired
+    private IQwExternalContactTransferCompanyAuditUserService auditUserService;
+
+    @PreAuthorize("@ss.hasPermi('qw:externalContactTransferCompanyAudit:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(QwExternalContactTransferCompanyAudit param) {
+        startPage();
+        List<QwExternalContactTransferCompanyAudit> list = auditService.selectQwExternalContactTransferCompanyAuditList(param);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('qw:externalContactTransferCompanyAudit:detail')")
+    @GetMapping("/detail/{auditId}")
+    public AjaxResult detail(@PathVariable Long auditId) {
+        return AjaxResult.success(auditUserService.getListByAuditId(auditId));
+    }
+
+    @PreAuthorize("@ss.hasPermi('qw:externalContactTransferCompanyAudit:audit')")
+    @PostMapping("/audit")
+    public AjaxResult audit(@Valid @RequestBody CompanyTransferAuditDTO param) {
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        auditService.audit(param, loginUser.getUser().getUserName());
+        return AjaxResult.success();
+    }
+
+}

+ 154 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwPushCountController.java

@@ -0,0 +1,154 @@
+package com.fs.qw.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.qw.domain.QwPushCount;
+import com.fs.qw.service.IQwPushCountService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+
+/**
+ * 定义销售推送不同类型的企业消息的次数Controller
+ *
+ * @author fs
+ * @date 2025-08-22
+ */
+@RestController
+@RequestMapping("/qw/qwPushCount")
+public class QwPushCountController extends BaseController {
+    @Autowired
+    private IQwPushCountService qwPushCountService;
+    @Autowired
+    private ResourceLoader resourceLoader;
+
+    /**
+     * 查询定义销售推送不同类型的企业消息的次数列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwPushCount:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(QwPushCount qwPushCount) {
+        startPage();
+        List<QwPushCount> list = qwPushCountService.selectQwPushCountList(qwPushCount);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出定义销售推送不同类型的企业消息的次数列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwPushCount:export')")
+    @Log(title = "定义销售推送不同类型的企业消息的次数", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(QwPushCount qwPushCount) {
+        List<QwPushCount> list = qwPushCountService.selectQwPushCountList(qwPushCount);
+        ExcelUtil<QwPushCount> util = new ExcelUtil<QwPushCount>(QwPushCount.class);
+        return util.exportExcel(list, "定义销售推送不同类型的企业消息的次数数据");
+    }
+
+    /**
+     * 获取定义销售推送不同类型的企业消息的次数详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwPushCount:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id) {
+        List<Long> companyIdList=new ArrayList<>();
+        QwPushCount qwPushCount = qwPushCountService.selectQwPushCountById(id);
+        companyIdList.add(qwPushCount.getCompanyId());
+        qwPushCount.setCompanyIdList(companyIdList);
+        return AjaxResult.success(qwPushCount);
+    }
+
+
+    /**
+     * 新增定义销售推送不同类型的企业消息的次数
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwPushCount:add')")
+    @Log(title = "定义销售推送不同类型的企业消息的次数", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwPushCount qwPushCount) {
+        List<Long> existingIds = new ArrayList<>();
+        Map<String, Long> existingDataMap = new HashMap<>();
+        List<QwPushCount> existingPushCounts = qwPushCountService.selectQwPushCountLists();
+        if (existingPushCounts != null && !existingPushCounts.isEmpty()) {
+            existingPushCounts.forEach(item -> {
+                String key = buildDataKey(item.getType(), item.getCompanyId());
+                existingDataMap.put(key, item.getId());
+            });
+        }
+        // 处理公司ID列表(可能为null或空)
+        List<Long> companyIdList = qwPushCount.getCompanyIdList();
+        boolean isEmptyList = companyIdList == null || companyIdList.isEmpty();
+
+        if (isEmptyList) {
+            // 处理无公司ID列表的情况
+            String key = buildDataKey(qwPushCount.getType(), null);
+            if (existingDataMap.containsKey(key)) {
+                existingIds.add(qwPushCount.getId());
+            } else {
+                qwPushCountService.insertQwPushCount(qwPushCount);
+            }
+        } else {
+            // 处理有公司ID列表的情况
+            companyIdList.forEach(companyId -> {
+                String key = buildDataKey(qwPushCount.getType(), companyId);
+                if (existingDataMap.containsKey(key)) {
+                    existingIds.add(companyId);
+                } else {
+                    qwPushCount.setCompanyId(companyId);
+                    qwPushCountService.insertQwPushCount(qwPushCount);
+                }
+            });
+        }
+
+        // 统一处理返回结果
+        if (!existingIds.isEmpty()) {
+            return error("新增限定类型已存在:失败条数" + existingIds.size());
+        } else {
+            return toAjax(1);
+        }
+    }
+    private String buildDataKey(Integer type, Long companyId) {
+        return type + "_" + (companyId == null ? "null" : companyId);
+    }
+
+    /**
+     * 修改定义销售推送不同类型的企业消息的次数
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwPushCount:edit')")
+    @Log(title = "定义销售推送不同类型的企业消息的次数", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody QwPushCount qwPushCount) {
+        QwPushCount pushCount;
+        if (qwPushCount.getCompanyId() != null) {
+            pushCount = qwPushCountService.SelectQwPushCountByCompanyId(qwPushCount.getType(), qwPushCount.getCompanyId());
+        } else {
+            pushCount = qwPushCountService.SelectQwPushCountByType(qwPushCount.getType());
+        }
+        if (pushCount != null) {
+            if (!Objects.equals(pushCount.getId(), qwPushCount.getId()) && Objects.equals(pushCount.getCompanyId(), qwPushCount.getCompanyId()) && Objects.equals(pushCount.getType(), qwPushCount.getType())) {
+                return toAjax(0);
+            }
+            if (Objects.equals(pushCount.getPushCount(), qwPushCount.getPushCount())) {
+                return toAjax(0);
+            }
+        }
+        return toAjax(qwPushCountService.updateQwPushCount(qwPushCount));
+    }
+
+    /**
+     * 删除定义销售推送不同类型的企业消息的次数
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwPushCount:remove')")
+    @Log(title = "定义销售推送不同类型的企业消息的次数", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        return toAjax(qwPushCountService.deleteQwPushCountByIds(ids));
+    }
+}

+ 1 - 1
fs-admin/src/main/java/com/fs/qw/controller/QwSopController.java

@@ -52,6 +52,7 @@ public class QwSopController extends BaseController
     private FsUserCourseMapper fsUserCourseMapper;
     private FsUserCourseMapper fsUserCourseMapper;
     @Autowired
     @Autowired
     private FsUserCourseVideoMapper fsUserCourseVideoMapper;
     private FsUserCourseVideoMapper fsUserCourseVideoMapper;
+
     /**
     /**
      * 查询企微sop列表
      * 查询企微sop列表
      */
      */
@@ -133,7 +134,6 @@ public class QwSopController extends BaseController
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         qwSop.setCreateBy(loginUser.getUser().getNickName());
         qwSop.setCreateBy(loginUser.getUser().getNickName());
         qwSop.setCreateTime(sdf.format(new Date()));
         qwSop.setCreateTime(sdf.format(new Date()));
-
         return toAjax(qwSopService.insertQwSop(qwSop));
         return toAjax(qwSopService.insertQwSop(qwSop));
 
 
     }
     }

+ 34 - 0
fs-admin/src/main/java/com/fs/task/FsCompanyTask.java

@@ -0,0 +1,34 @@
+package com.fs.task;
+
+import com.fs.company.service.ICompanyService;
+import com.fs.company.vo.RedPacketMoneyVO;
+import com.fs.course.mapper.FsCourseRedPacketLogMapper;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@AllArgsConstructor
+@Component("companyTask")
+public class FsCompanyTask {
+
+    private FsCourseRedPacketLogMapper fsCourseRedPacketLogMapper;
+    private ICompanyService companyService;
+
+    public void refreshCompanyMoney() {
+        LocalDateTime now = LocalDateTime.now();
+        // 获取上一个小时的开始时间
+        LocalDateTime startTime = now.minusHours(1)
+                .withMinute(0)
+                .withSecond(0);
+        // 获取上一个小时的结束时间
+        LocalDateTime endTime = startTime
+                .withMinute(59)
+                .withSecond(59);
+        List<RedPacketMoneyVO> redPacketMoneyVOS = fsCourseRedPacketLogMapper.selectFsCourseRedPacketLogHourseByCompany(startTime, endTime);
+        for (RedPacketMoneyVO redPacketMoneyVO : redPacketMoneyVOS) {
+            companyService.subtractCompanyMoneyHourse(redPacketMoneyVO.getMoney(), redPacketMoneyVO.getCompanyId(), startTime.toLocalTime(), endTime.toLocalTime());
+        }
+    }
+}

+ 39 - 0
fs-admin/src/main/java/com/fs/task/FsStoreTask.java

@@ -0,0 +1,39 @@
+package com.fs.task;
+
+import com.fs.hisStore.domain.FsStoreScrm;
+import com.fs.hisStore.service.IFsStoreScrmService;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Component;
+import com.fs.common.utils.PubFun;
+
+import java.time.LocalDate;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@AllArgsConstructor
+@Component("storeTaskScrm")
+public class FsStoreTask {
+
+    private final IFsStoreScrmService fsStoreScrmService;
+
+
+    public void store(){
+        LocalDate now = LocalDate.now();
+        List<FsStoreScrm> storeList = fsStoreScrmService.selectOverList();
+        List<FsStoreScrm> collect = storeList.stream().filter(e -> {
+            // 过期判定:任一证件到期日为 null 或 早于今天
+            return e.getBusinessLicenseExpireEnd() == null
+                    || e.getDrugLicenseExpiryEnd() == null
+                    || e.getMedicalLicenseExpiryEnd() == null
+                    || e.getBusinessLicenseExpireEnd().isBefore(now)
+                    || e.getDrugLicenseExpiryEnd().isBefore(now)
+                    || e.getMedicalLicenseExpiryEnd().isBefore(now);
+        }).collect(Collectors.toList());
+
+        if (!collect.isEmpty()) {
+            List<Long> ids = PubFun.listToNewList(collect, FsStoreScrm::getStoreId);
+            fsStoreScrmService.batchUpdateStatusByIds(ids, 0);
+        }
+    }
+
+}

+ 106 - 0
fs-admin/src/main/java/com/fs/user/controller/FsUserComplaintController.java

@@ -0,0 +1,106 @@
+package com.fs.user.controller;
+
+import java.util.List;
+
+import com.fs.user.domain.param.FsUserComplaintParam;
+import com.fs.user.domain.vo.FsUserComplaintVo;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.user.domain.FsUserComplaint;
+import com.fs.user.service.IFsUserComplaintService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 用户投诉Controller
+ *
+ * @author fs
+ * @date 2025-08-27
+ */
+@RestController
+@RequestMapping("/user/complaint")
+public class FsUserComplaintController extends BaseController
+{
+    @Autowired
+    private IFsUserComplaintService fsUserComplaintService;
+
+    /**
+     * 查询用户投诉列表
+     */
+    @PreAuthorize("@ss.hasPermi('user:complaint:list')")
+    @PostMapping("/list")
+    public TableDataInfo list(@RequestBody FsUserComplaintParam param)
+    {
+        startPage();
+        List<FsUserComplaintVo> list = fsUserComplaintService.selectFsUserComplaintVoList(param);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出用户投诉列表
+     */
+    @PreAuthorize("@ss.hasPermi('user:complaint:export')")
+    @Log(title = "用户投诉", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsUserComplaint fsUserComplaint)
+    {
+        List<FsUserComplaint> list = fsUserComplaintService.selectFsUserComplaintList(fsUserComplaint);
+        ExcelUtil<FsUserComplaint> util = new ExcelUtil<FsUserComplaint>(FsUserComplaint.class);
+        return util.exportExcel(list, "用户投诉数据");
+    }
+
+    /**
+     * 获取用户投诉详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('user:complaint:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsUserComplaintService.selectFsUserComplaintVoById(id));
+    }
+
+    /**
+     * 新增用户投诉
+     */
+    @PreAuthorize("@ss.hasPermi('user:complaint:add')")
+    @Log(title = "用户投诉", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsUserComplaint fsUserComplaint)
+    {
+        return toAjax(fsUserComplaintService.insertFsUserComplaint(fsUserComplaint));
+    }
+
+    /**
+     * 修改用户投诉
+     */
+    @PreAuthorize("@ss.hasPermi('user:complaint:edit')")
+    @Log(title = "用户投诉", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsUserComplaint fsUserComplaint)
+    {
+        return toAjax(fsUserComplaintService.updateFsUserComplaint(fsUserComplaint));
+    }
+
+    /**
+     * 删除用户投诉
+     */
+    @PreAuthorize("@ss.hasPermi('user:complaint:remove')")
+    @Log(title = "用户投诉", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsUserComplaintService.deleteFsUserComplaintByIds(ids));
+    }
+}

+ 109 - 0
fs-admin/src/main/java/com/fs/user/controller/FsUserComplaintMsgController.java

@@ -0,0 +1,109 @@
+package com.fs.user.controller;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.user.domain.FsUserComplaintMsg;
+import com.fs.user.service.IFsUserComplaintMsgService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 投诉消息记录Controller
+ *
+ * @author fs
+ * @date 2025-09-08
+ */
+@RestController
+@RequestMapping("/user/msg")
+public class FsUserComplaintMsgController extends BaseController
+{
+    @Autowired
+    private IFsUserComplaintMsgService fsUserComplaintMsgService;
+
+    /**
+     * 查询投诉消息记录列表
+     */
+//    @PreAuthorize("@ss.hasPermi('user:msg:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsUserComplaintMsg fsUserComplaintMsg)
+    {
+        startPage();
+        List<FsUserComplaintMsg> list = fsUserComplaintMsgService.selectFsUserComplaintMsgList(fsUserComplaintMsg);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出投诉消息记录列表
+     */
+//    @PreAuthorize("@ss.hasPermi('user:msg:export')")
+    @Log(title = "投诉消息记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsUserComplaintMsg fsUserComplaintMsg)
+    {
+        List<FsUserComplaintMsg> list = fsUserComplaintMsgService.selectFsUserComplaintMsgList(fsUserComplaintMsg);
+        ExcelUtil<FsUserComplaintMsg> util = new ExcelUtil<FsUserComplaintMsg>(FsUserComplaintMsg.class);
+        return util.exportExcel(list, "投诉消息记录数据");
+    }
+
+    /**
+     * 获取投诉消息记录详细信息
+     */
+//    @PreAuthorize("@ss.hasPermi('user:msg:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsUserComplaintMsgService.selectFsUserComplaintMsgById(id));
+    }
+
+    /**
+     * 新增投诉消息记录
+     */
+    @PreAuthorize("@ss.hasPermi('user:msg:add')")
+    @Log(title = "投诉消息记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsUserComplaintMsg fsUserComplaintMsg)
+    {
+        if (fsUserComplaintMsg.getComplaintId() == null){
+            return AjaxResult.error("未查询到相关投诉!");
+        }
+        Long userId = getUserId();
+        fsUserComplaintMsg.setUserId(userId);
+        fsUserComplaintMsg.setSendType(2); //平台
+        return toAjax(fsUserComplaintMsgService.insertFsUserComplaintMsg(fsUserComplaintMsg));
+    }
+
+    /**
+     * 修改投诉消息记录
+     */
+    @PreAuthorize("@ss.hasPermi('user:msg:edit')")
+    @Log(title = "投诉消息记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsUserComplaintMsg fsUserComplaintMsg)
+    {
+        return toAjax(fsUserComplaintMsgService.updateFsUserComplaintMsg(fsUserComplaintMsg));
+    }
+
+    /**
+     * 删除投诉消息记录
+     */
+    @PreAuthorize("@ss.hasPermi('user:msg:remove')")
+    @Log(title = "投诉消息记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsUserComplaintMsgService.deleteFsUserComplaintMsgByIds(ids));
+    }
+}

+ 14 - 0
fs-admin/src/main/java/com/fs/web/controller/system/SysLoginController.java

@@ -3,9 +3,12 @@ package com.fs.web.controller.system;
 import java.util.List;
 import java.util.List;
 import java.util.Set;
 import java.util.Set;
 
 
+import com.alibaba.fastjson.JSONObject;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.entity.SysRole;
 import com.fs.common.core.domain.entity.SysRole;
 import com.fs.common.utils.PatternUtils;
 import com.fs.common.utils.PatternUtils;
+import com.fs.his.utils.ConfigUtil;
+import com.fs.hisStore.config.MedicalMallConfig;
 import com.fs.system.service.ISysRoleService;
 import com.fs.system.service.ISysRoleService;
 import lombok.Synchronized;
 import lombok.Synchronized;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -45,6 +48,12 @@ public class SysLoginController
     @Autowired
     @Autowired
     private ISysRoleService roleService;
     private ISysRoleService roleService;
 
 
+    @Autowired
+    private ConfigUtil configUtil;
+
+    @Autowired
+    private MedicalMallConfig medicalMallConfig;
+
     /**
     /**
      * 登录方法
      * 登录方法
      *
      *
@@ -78,7 +87,12 @@ public class SysLoginController
         Set<String> roles = permissionService.getRolePermission(user);
         Set<String> roles = permissionService.getRolePermission(user);
         // 权限集合
         // 权限集合
         Set<String> permissions = permissionService.getMenuPermission(user);
         Set<String> permissions = permissionService.getMenuPermission(user);
+        //药品商城参数
         AjaxResult ajax = AjaxResult.success();
         AjaxResult ajax = AjaxResult.success();
+
+        if(medicalMallConfig!=null){
+            ajax.put("medicalMallConfig", medicalMallConfig);
+        }
         ajax.put("user", user);
         ajax.put("user", user);
         Integer isAdmin = 0;
         Integer isAdmin = 0;
         if (permissions.contains("*:*:*")){
         if (permissions.contains("*:*:*")){

+ 26 - 3
fs-admin/src/main/java/com/fs/web/controller/system/SysUserController.java

@@ -1,10 +1,14 @@
 package com.fs.web.controller.system;
 package com.fs.web.controller.system;
 
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
+import com.fs.common.constant.HttpStatus;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.model.LoginUser;
 import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.core.page.PageDomain;
+import com.fs.common.core.page.TableSupport;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.ServletUtils;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.ArrayUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -59,9 +63,28 @@ public class SysUserController extends BaseController
     @GetMapping("/list")
     @GetMapping("/list")
     public TableDataInfo list(SysUser user)
     public TableDataInfo list(SysUser user)
     {
     {
-        startPage();
-        List<SysUser> list = userService.selectUserList(user);
-        return getDataTable(list);
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+        Integer pageNum = pageDomain.getPageNum();
+        Integer pageSize = pageDomain.getPageSize();
+
+
+        long total = userService.selectUserCount(user);
+
+
+        List<Long> userIds = userService.selectUserIdsWithPage(user, pageNum, pageSize);
+
+        List<SysUser> list = new ArrayList<>();
+        if (!userIds.isEmpty()) {
+
+            list = userService.selectUserListByIds(userIds);
+        }
+
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(HttpStatus.SUCCESS);
+        rspData.setMsg("查询成功");
+        rspData.setRows(list);
+        rspData.setTotal(total);
+        return rspData;
     }
     }
 
 
     @Log(title = "用户管理", businessType = BusinessType.EXPORT)
     @Log(title = "用户管理", businessType = BusinessType.EXPORT)

+ 2 - 2
fs-admin/src/main/resources/application.yml

@@ -4,11 +4,11 @@ server:
 # Spring配置
 # Spring配置
 spring:
 spring:
   profiles:
   profiles:
-#    active: druid-myhk-test
+    active: druid-jnmy-test
 #    active: druid-hdt
 #    active: druid-hdt
 #    active: druid-yzt
 #    active: druid-yzt
 #    active: druid-sxjz
 #    active: druid-sxjz
 #    active: druid-sft
 #    active: druid-sft
 #    active: druid-fby
 #    active: druid-fby
-    active: dev
+#    active: dev
 
 

+ 18 - 40
fs-common-api/src/main/java/com/fs/framework/config/MyBatisConfig.java

@@ -32,82 +32,60 @@ import java.util.List;
 
 
  */
  */
 @Configuration
 @Configuration
-public class MyBatisConfig
-{
+public class MyBatisConfig {
     @Autowired
     @Autowired
     private Environment env;
     private Environment env;
 
 
     static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
     static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
 
 
-    public static String setTypeAliasesPackage(String typeAliasesPackage)
-    {
+    public static String setTypeAliasesPackage(String typeAliasesPackage) {
         ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver();
         ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver();
         MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);
         MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);
         List<String> allResult = new ArrayList<String>();
         List<String> allResult = new ArrayList<String>();
-        try
-        {
-            for (String aliasesPackage : typeAliasesPackage.split(","))
-            {
+        try {
+            for (String aliasesPackage : typeAliasesPackage.split(",")) {
                 List<String> result = new ArrayList<String>();
                 List<String> result = new ArrayList<String>();
                 aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
                 aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
                         + ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN;
                         + ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN;
                 Resource[] resources = resolver.getResources(aliasesPackage);
                 Resource[] resources = resolver.getResources(aliasesPackage);
-                if (resources != null && resources.length > 0)
-                {
+                if (resources != null && resources.length > 0) {
                     MetadataReader metadataReader = null;
                     MetadataReader metadataReader = null;
-                    for (Resource resource : resources)
-                    {
-                        if (resource.isReadable())
-                        {
+                    for (Resource resource : resources) {
+                        if (resource.isReadable()) {
                             metadataReader = metadataReaderFactory.getMetadataReader(resource);
                             metadataReader = metadataReaderFactory.getMetadataReader(resource);
-                            try
-                            {
+                            try {
                                 result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName());
                                 result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName());
-                            }
-                            catch (ClassNotFoundException e)
-                            {
+                            } catch (ClassNotFoundException e) {
                                 e.printStackTrace();
                                 e.printStackTrace();
                             }
                             }
                         }
                         }
                     }
                     }
                 }
                 }
-                if (result.size() > 0)
-                {
+                if (result.size() > 0) {
                     HashSet<String> hashResult = new HashSet<String>(result);
                     HashSet<String> hashResult = new HashSet<String>(result);
                     allResult.addAll(hashResult);
                     allResult.addAll(hashResult);
                 }
                 }
             }
             }
-            if (allResult.size() > 0)
-            {
+            if (allResult.size() > 0) {
                 typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0]));
                 typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0]));
-            }
-            else
-            {
+            } else {
                 throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包");
                 throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包");
             }
             }
-        }
-        catch (IOException e)
-        {
+        } catch (IOException e) {
             e.printStackTrace();
             e.printStackTrace();
         }
         }
         return typeAliasesPackage;
         return typeAliasesPackage;
     }
     }
 
 
-    public Resource[] resolveMapperLocations(String[] mapperLocations)
-    {
+    public Resource[] resolveMapperLocations(String[] mapperLocations) {
         ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
         ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
         List<Resource> resources = new ArrayList<Resource>();
         List<Resource> resources = new ArrayList<Resource>();
-        if (mapperLocations != null)
-        {
-            for (String mapperLocation : mapperLocations)
-            {
-                try
-                {
+        if (mapperLocations != null) {
+            for (String mapperLocation : mapperLocations) {
+                try {
                     Resource[] mappers = resourceResolver.getResources(mapperLocation);
                     Resource[] mappers = resourceResolver.getResources(mapperLocation);
                     resources.addAll(Arrays.asList(mappers));
                     resources.addAll(Arrays.asList(mappers));
-                }
-                catch (IOException e)
-                {
+                } catch (IOException e) {
                     // ignore
                     // ignore
                 }
                 }
             }
             }

+ 36 - 0
fs-common-api/src/main/java/com/fs/framework/config/RedisConfig.java

@@ -15,6 +15,8 @@ import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 
 
+import java.math.BigDecimal;
+
 /**
 /**
  * redis配置
  * redis配置
  *
  *
@@ -65,7 +67,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         template.afterPropertiesSet();
         return template;
         return template;
     }
     }
+    @Bean
+    public RedisTemplate<String, Integer> redisTemplateForInteger(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, Integer> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(Integer.class));
 
 
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
     @Bean
     @Bean
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {
@@ -90,7 +109,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         template.afterPropertiesSet();
         return template;
         return template;
     }
     }
+    @Bean
+    public RedisTemplate<String, BigDecimal> redisTemplateForBigDecimal(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, BigDecimal> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
 
 
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
     @Bean
     @Bean
     public DefaultRedisScript<Long> limitScript()
     public DefaultRedisScript<Long> limitScript()
     {
     {

+ 2 - 2
fs-common-api/src/main/resources/application.yml

@@ -4,5 +4,5 @@ server:
 # Spring配置
 # Spring配置
 spring:
 spring:
   profiles:
   profiles:
-#    active: dev
-    active: druid-jnmy
+    active: dev-yjb
+#    active: druid-jnmy

+ 10 - 1
fs-common/src/main/java/com/fs/common/core/domain/entity/SysRole.java

@@ -61,12 +61,21 @@ public class SysRole extends BaseEntity
 
 
     /** 是否可以查看手机全号 0否 1是 */
     /** 是否可以查看手机全号 0否 1是 */
     private Integer isCheckPhone;
     private Integer isCheckPhone;
-
+    /** 是否可以查看地址全号 0否 1是 */
+    private Integer isCheckAddress;
     public SysRole()
     public SysRole()
     {
     {
 
 
     }
     }
 
 
+    public Integer getIsCheckAddress() {
+        return isCheckAddress;
+    }
+
+    public void setIsCheckAddress(Integer isCheckAddress) {
+        this.isCheckAddress = isCheckAddress;
+    }
+
     public SysRole(Long roleId)
     public SysRole(Long roleId)
     {
     {
         this.roleId = roleId;
         this.roleId = roleId;

+ 11 - 0
fs-common/src/main/java/com/fs/common/core/domain/entity/SysUser.java

@@ -95,11 +95,22 @@ public class SysUser extends BaseEntity
     /** 角色ID */
     /** 角色ID */
     private Long roleId;
     private Long roleId;
 
 
+    @Excel(name = "角色名称")
+    private List<String> roleName;
+
     public SysUser()
     public SysUser()
     {
     {
 
 
     }
     }
 
 
+    public List<String> getRoleName() {
+        return roleName;
+    }
+
+    public void setRoleName(List<String> roleName) {
+        this.roleName = roleName;
+    }
+
     public SysUser(Long userId)
     public SysUser(Long userId)
     {
     {
         this.userId = userId;
         this.userId = userId;

+ 6 - 2
fs-common/src/main/java/com/fs/common/core/domain/model/LoginUser.java

@@ -1,7 +1,7 @@
 package com.fs.common.core.domain.model;
 package com.fs.common.core.domain.model;
 
 
-import java.util.Collection;
-import java.util.Set;
+import java.util.*;
+
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.userdetails.UserDetails;
 import org.springframework.security.core.userdetails.UserDetails;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -14,6 +14,7 @@ import com.fs.common.core.domain.entity.SysUser;
  */
  */
 public class LoginUser implements UserDetails
 public class LoginUser implements UserDetails
 {
 {
+    private static final List<String> ADMIN_USER_NAME = Collections.singletonList("admin");
     private static final long serialVersionUID = 1L;
     private static final long serialVersionUID = 1L;
 
 
     /**
     /**
@@ -254,6 +255,9 @@ public class LoginUser implements UserDetails
     {
     {
         return user;
         return user;
     }
     }
+    public boolean isAdmin(){
+        return ADMIN_USER_NAME.contains(user.getUserName());
+    }
 
 
     public void setUser(SysUser user)
     public void setUser(SysUser user)
     {
     {

+ 70 - 5
fs-common/src/main/java/com/fs/common/core/redis/RedisCache.java

@@ -1,10 +1,6 @@
 package com.fs.common.core.redis;
 package com.fs.common.core.redis;
 
 
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeUnit;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.BoundSetOperations;
 import org.springframework.data.redis.core.BoundSetOperations;
@@ -236,4 +232,73 @@ public class RedisCache
     public Boolean setIfAbsent(String key, String value, long timeout, TimeUnit unit) {
     public Boolean setIfAbsent(String key, String value, long timeout, TimeUnit unit) {
         return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit);
         return redisTemplate.opsForValue().setIfAbsent(key, value, timeout, unit);
     }
     }
+
+    public Long decr(final String key,final Long delta) {
+        return redisTemplate.opsForValue().decrement(key, delta);
+    }
+
+    public Long incr(final String key,final Long delta) {
+        return redisTemplate.opsForValue().increment(key, delta);
+    }
+
+    /**
+     * 获得list对象的value
+     *
+     * @param key 缓存的键值
+     * @return 缓存键值对应的数据
+     */
+    public <T> T getVoiceAllList(final String key)
+    {
+        return (T) redisTemplate.opsForList().range(key,0,-1);
+    }
+    /**
+     * 获得缓存的对象id
+     *
+     * @param key 缓存的键值
+     * @return 缓存键值对应的数据
+     */
+    public <T> T popVoiceKey(final String key)
+    {
+        if (Boolean.TRUE.equals(redisTemplate.hasKey(key))) {
+            return (T) redisTemplate.opsForList().leftPop(key);
+        }
+        return null;
+    }
+    /**
+     * 删除缓存Map
+     *
+     * @param key
+     * @param hKey
+     */
+    public <T> void deleteCacheMap(final String key, final String hKey)
+    {
+        if (hKey != null) {
+            redisTemplate.opsForHash().delete(key, hKey);
+        }
+    }
+
+    /**
+     * 添加List消息数据
+     *
+     * @param key 缓存的键值
+     * @param dataList 待缓存的List消息数据
+     * @return 缓存的对象
+     */
+    public <T> long setVoiceList(final String key, final List<T> dataList)
+    {
+        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
+        return count == null ? 0 : count;
+    }
+
+    /**
+     * 添加List消息数据的key
+     *
+     * @param key 缓存的键值
+     * @param value 待缓存的值
+     * @return 缓存的对象
+     */
+    public <T> void setVoice(final String key, final T value)
+    {
+        redisTemplate.opsForList().rightPush(key, value);
+    }
 }
 }

+ 7 - 2
fs-common/src/main/java/com/fs/common/enums/BusinessType.java

@@ -2,7 +2,7 @@ package com.fs.common.enums;
 
 
 /**
 /**
  * 业务操作类型
  * 业务操作类型
- * 
+ *
 
 
  */
  */
 public enum BusinessType
 public enum BusinessType
@@ -51,9 +51,14 @@ public enum BusinessType
      * 生成代码
      * 生成代码
      */
      */
     GENCODE,
     GENCODE,
-    
+
     /**
     /**
      * 清空数据
      * 清空数据
      */
      */
     CLEAN,
     CLEAN,
+
+    /**
+     * 审核
+     * */
+    AUDIT,
 }
 }

+ 25 - 0
fs-common/src/main/java/com/fs/common/utils/DateUtils.java

@@ -270,5 +270,30 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
         cal.add(Calendar.DATE, days);
         cal.add(Calendar.DATE, days);
         return new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime());
         return new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime());
     }
     }
+    /**
+     * 获取到当天时间的开始:当天0时0分0秒0毫秒
+     * @return
+     */
+    public static Long toStartTime( ) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+        return calendar.getTimeInMillis();
+    }
+
+    /**
+     * 获取到当天时间的结束:当天23时59分59秒999毫秒
+     * @return
+     */
+    public static Long toEndTime() {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.HOUR_OF_DAY, 23);
+        calendar.set(Calendar.MINUTE, 59);
+        calendar.set(Calendar.SECOND, 59);
+        calendar.set(Calendar.MILLISECOND, 999);
+        return calendar.getTimeInMillis();
+    }
 
 
 }
 }

+ 140 - 0
fs-common/src/main/java/com/fs/common/utils/poi/ExcelUtil.java

@@ -1274,4 +1274,144 @@ public class ExcelUtil<T>
         }
         }
         return sheetIndexPicMap;
         return sheetIndexPicMap;
     }
     }
+    /**
+     * 对list数据源将其里面的数据导入到excel表单(只导出选中的列)
+     *
+     * @param list 导出数据集合
+     * @param sheetName 工作表的名称
+     * @param selectedFields 选中的字段列表
+     * @return 结果
+     */
+    public AjaxResult exportExcelSelectedColumns(List<T> list, String sheetName, List<String> selectedFields) {
+        this.init(list, sheetName, Type.EXPORT);
+        return exportExcelSelectedColumns(selectedFields);
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单(只导出选中的列)
+     *
+     * @param response 返回数据
+     * @param list 导出数据集合
+     * @param sheetName 工作表的名称
+     * @param selectedFields 选中的字段列表
+     * @return 结果
+     * @throws IOException
+     */
+    public void exportExcelSelectedColumns(HttpServletResponse response, List<T> list, String sheetName, List<String> selectedFields) throws IOException {
+        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+        response.setCharacterEncoding("utf-8");
+        this.init(list, sheetName, Type.EXPORT);
+        exportExcelSelectedColumns(response.getOutputStream(), selectedFields);
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单(只导出选中的列)
+     *
+     * @param selectedFields 选中的字段列表
+     * @return 结果
+     */
+    public void exportExcelSelectedColumns(OutputStream out, List<String> selectedFields) {
+        try {
+            writeSelectedSheet(selectedFields);
+            wb.write(out);
+        } catch (Exception e) {
+            log.error("导出Excel异常{}", e.getMessage());
+        } finally {
+            IOUtils.closeQuietly(wb);
+            IOUtils.closeQuietly(out);
+        }
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单(只导出选中的列)
+     *
+     * @param selectedFields 选中的字段列表
+     * @return 结果
+     */
+    public AjaxResult exportExcelSelectedColumns(List<String> selectedFields) {
+        OutputStream out = null;
+        try {
+            writeSelectedSheet(selectedFields);
+            String filename = encodingFilename(sheetName);
+            out = new FileOutputStream(getAbsoluteFile(filename));
+            wb.write(out);
+            return AjaxResult.success(filename);
+        } catch (Exception e) {
+            log.error("导出Excel异常{}", e.getMessage());
+            throw new UtilException("导出Excel失败,请联系网站管理员!");
+        } finally {
+            IOUtils.closeQuietly(wb);
+            IOUtils.closeQuietly(out);
+        }
+    }
+
+    /**
+     * 创建写入数据到Sheet(只写入选中的列)
+     */
+    public void writeSelectedSheet(List<String> selectedFields) {
+        // 筛选出选中的字段
+        List<Object[]> selectedFieldList = filterSelectedFields(selectedFields);
+
+        // 取出一共有多少个sheet.
+        double sheetNo = Math.ceil(list.size() / sheetSize);
+        for (int index = 0; index <= sheetNo; index++) {
+            createSheet(sheetNo, index);
+
+            // 产生一行
+            Row row = sheet.createRow(0);
+            int column = 0;
+            // 写入各个字段的列头名称(只写入选中的字段)
+            for (Object[] os : selectedFieldList) {
+                Excel excel = (Excel) os[1];
+                this.createCell(excel, row, column++);
+            }
+            if (Type.EXPORT.equals(type)) {
+                fillSelectedExcelData(index, row, selectedFieldList);
+                addStatisticsRow();
+            }
+        }
+    }
+
+    /**
+     * 筛选出选中的字段
+     */
+    private List<Object[]> filterSelectedFields(List<String> selectedFields) {
+        if (selectedFields == null || selectedFields.isEmpty()) {
+            return this.fields; // 如果没有选择字段,返回所有字段
+        }
+
+        List<Object[]> selectedFieldList = new ArrayList<>();
+        for (Object[] fieldInfo : this.fields) {
+            Field field = (Field) fieldInfo[0];
+            if (selectedFields.contains(field.getName())) {
+                selectedFieldList.add(fieldInfo);
+            }
+        }
+        return selectedFieldList;
+    }
+
+    /**
+     * 填充excel数据(只填充选中的列)
+     *
+     * @param index 序号
+     * @param row 单元格行
+     * @param selectedFieldList 选中的字段列表
+     */
+    public void fillSelectedExcelData(int index, Row row, List<Object[]> selectedFieldList) {
+        int startNo = index * sheetSize;
+        int endNo = Math.min(startNo + sheetSize, list.size());
+        for (int i = startNo; i < endNo; i++) {
+            row = sheet.createRow(i + 1 - startNo);
+            // 得到导出对象.
+            T vo = (T) list.get(i);
+            int column = 0;
+            for (Object[] os : selectedFieldList) {
+                Field field = (Field) os[0];
+                Excel excel = (Excel) os[1];
+                // 设置实体类私有属性可访问
+                field.setAccessible(true);
+                this.addCell(excel, row, vo, field, column++);
+            }
+        }
+    }
 }
 }

+ 10 - 0
fs-company-app/src/main/java/com/fs/app/controller/AppBaseController.java

@@ -13,6 +13,8 @@ import com.fs.his.service.IFsUserService;
 import io.jsonwebtoken.Claims;
 import io.jsonwebtoken.Claims;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 
 
+import java.util.concurrent.TimeUnit;
+
 
 
 public class AppBaseController {
 public class AppBaseController {
 	@Autowired
 	@Autowired
@@ -27,8 +29,16 @@ public class AppBaseController {
 	public Long getCompanyId() {
 	public Long getCompanyId() {
 		String headValue =  ServletUtils.getRequest().getHeader("APPToken");
 		String headValue =  ServletUtils.getRequest().getHeader("APPToken");
 		Claims claims=jwtUtils.getClaimByToken(headValue);
 		Claims claims=jwtUtils.getClaimByToken(headValue);
+		if (ObjectUtil.isEmpty(claims)){
+			throw new FSException("未授权,请先登录!");
+		}
 		String userId = claims.getSubject().toString();
 		String userId = claims.getSubject().toString();
 		Long companyId =(Long)redisCache.getCacheObject("companyId:"+userId);
 		Long companyId =(Long)redisCache.getCacheObject("companyId:"+userId);
+		if (companyId==null){
+			CompanyUser companyUser = companyUserService.selectCompanyUserById(Long.parseLong(userId));
+			companyId = companyUser.getCompanyId();
+			redisCache.setCacheObject("companyId:" + companyUser.getUserId(), companyUser.getCompanyId(), 604800, TimeUnit.SECONDS);
+		}
 		return companyId;
 		return companyId;
 	}
 	}
 	public String getUserId()
 	public String getUserId()

+ 1 - 0
fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -123,6 +123,7 @@ public class FsUserCourseVideoController extends AppBaseController {
     @GetMapping("/participationRecord")
     @GetMapping("/participationRecord")
     public ResponseResult<Object> participationRecord(@RequestParam Long videoId,
     public ResponseResult<Object> participationRecord(@RequestParam Long videoId,
                                                       @RequestParam Integer type,
                                                       @RequestParam Integer type,
+                                                      @RequestParam(required = false) Long periodId,
                                                       @RequestParam(required = false) String keyword,
                                                       @RequestParam(required = false) String keyword,
                                                       @RequestParam(required = false) Long periodId,
                                                       @RequestParam(required = false) Long periodId,
                                                       @RequestParam(required = false, defaultValue = "1") Integer pageNum,
                                                       @RequestParam(required = false, defaultValue = "1") Integer pageNum,

+ 40 - 0
fs-company-app/src/main/java/com/fs/core/config/RedisConfig.java

@@ -12,6 +12,8 @@ import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 
 
+import java.math.BigDecimal;
+
 /**
 /**
  * redis配置
  * redis配置
  *
  *
@@ -66,6 +68,44 @@ public class RedisConfig extends CachingConfigurerSupport
         return template;
         return template;
     }
     }
 
 
+    @Bean
+    public RedisTemplate<String, Integer> redisTemplateForInteger(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, Integer> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
+
+    @Bean
+    public RedisTemplate<String, BigDecimal> redisTemplateForBigDecimal(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, BigDecimal> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
+
     @Bean
     @Bean
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {

+ 7 - 5
fs-company/src/main/java/com/fs/company/controller/company/CompanyController.java

@@ -17,10 +17,7 @@ import com.fs.framework.service.TokenService;
 import com.fs.his.vo.OptionsVO;
 import com.fs.his.vo.OptionsVO;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 
 import java.util.List;
 import java.util.List;
 
 
@@ -107,7 +104,7 @@ public class CompanyController extends BaseController
     @GetMapping("/allList")
     @GetMapping("/allList")
     public TableDataInfo getHospital()
     public TableDataInfo getHospital()
     {
     {
-        List<OptionsVO> list = companyService.selectAllCompanyList();
+        List<OptionsVO> list = companyService.selectAllCompanyList(null);
         return getDataTable(list);
         return getDataTable(list);
     }
     }
 
 
@@ -119,4 +116,9 @@ public class CompanyController extends BaseController
         return R.ok();
         return R.ok();
     }
     }
 
 
+    @GetMapping("/getCompanyListByCorId/{corpId}")
+    public R getCompanyListByCorId(@PathVariable String corpId) {
+        List<OptionsVO> list = companyService.getCompanyListByCorpId(corpId);
+        return R.ok().put("data",list);
+    }
 }
 }

+ 13 - 3
fs-company/src/main/java/com/fs/company/controller/course/FsCourseAnswerLogsController.java

@@ -1,5 +1,7 @@
 package com.fs.company.controller.course;
 package com.fs.company.controller.course;
 
 
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSONUtil;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.Log;
 import com.fs.common.constant.HttpStatus;
 import com.fs.common.constant.HttpStatus;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.controller.BaseController;
@@ -8,11 +10,13 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.config.CourseConfig;
 import com.fs.course.param.FsCourseAnswerLogsParam;
 import com.fs.course.param.FsCourseAnswerLogsParam;
 import com.fs.course.service.IFsCourseAnswerLogsService;
 import com.fs.course.service.IFsCourseAnswerLogsService;
 import com.fs.course.vo.FsCourseAnswerLogsListVO;
 import com.fs.course.vo.FsCourseAnswerLogsListVO;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 import com.fs.framework.service.TokenService;
+import com.fs.system.service.ISysConfigService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -38,6 +42,9 @@ public class FsCourseAnswerLogsController extends BaseController
 
 
     @Autowired
     @Autowired
     private TokenService tokenService;
     private TokenService tokenService;
+
+    @Autowired
+    private ISysConfigService configService;
     /**
     /**
      * 查询答题日志列表
      * 查询答题日志列表
      */
      */
@@ -48,10 +55,13 @@ public class FsCourseAnswerLogsController extends BaseController
         if (param.getPhoneMk() != null && param.getPhoneMk() != "") {
         if (param.getPhoneMk() != null && param.getPhoneMk() != "") {
             param.setPhone(param.getPhoneMk());
             param.setPhone(param.getPhoneMk());
         }
         }
-
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        param.setCompanyId( loginUser.getCompany().getCompanyId());
-
+        Long userId = loginUser.getUser().getUserId();
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+            param.setCompanyId( loginUser.getCompany().getCompanyId());
+        }
         List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVONew(param);
         List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVONew(param);
         TableDataInfo rspData = new TableDataInfo();
         TableDataInfo rspData = new TableDataInfo();
         rspData.setCode(HttpStatus.SUCCESS);
         rspData.setCode(HttpStatus.SUCCESS);

+ 13 - 2
fs-company/src/main/java/com/fs/company/controller/course/FsCourseRedPacketLogController.java

@@ -1,5 +1,7 @@
 package com.fs.company.controller.course;
 package com.fs.company.controller.course;
 
 
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSONUtil;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.controller.BaseController;
@@ -9,6 +11,7 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsCourseRedPacketLog;
 import com.fs.course.domain.FsCourseRedPacketLog;
 import com.fs.course.mapper.FsUserCourseMapper;
 import com.fs.course.mapper.FsUserCourseMapper;
 import com.fs.course.mapper.FsUserCourseVideoMapper;
 import com.fs.course.mapper.FsUserCourseVideoMapper;
@@ -19,6 +22,7 @@ import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 import com.fs.framework.service.TokenService;
 import com.fs.his.utils.PhoneUtil;
 import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.OptionsVO;
 import com.fs.his.vo.OptionsVO;
+import com.fs.system.service.ISysConfigService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
@@ -45,7 +49,8 @@ public class FsCourseRedPacketLogController extends BaseController
     FsUserCourseVideoMapper fsUserCourseVideoMapper;
     FsUserCourseVideoMapper fsUserCourseVideoMapper;
     @Autowired
     @Autowired
     private TokenService tokenService;
     private TokenService tokenService;
-
+    @Autowired
+    private ISysConfigService configService;
     /**
     /**
      * 查询短链课程看课记录列表
      * 查询短链课程看课记录列表
      */
      */
@@ -57,8 +62,14 @@ public class FsCourseRedPacketLogController extends BaseController
         if (fsCourseRedPacketLog.getPhoneMk() != null && fsCourseRedPacketLog.getPhoneMk() != "") {
         if (fsCourseRedPacketLog.getPhoneMk() != null && fsCourseRedPacketLog.getPhoneMk() != "") {
             fsCourseRedPacketLog.setPhone(encryptPhone(fsCourseRedPacketLog.getPhoneMk()));
             fsCourseRedPacketLog.setPhone(encryptPhone(fsCourseRedPacketLog.getPhoneMk()));
         }
         }
+
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        fsCourseRedPacketLog.setCompanyId( loginUser.getCompany().getCompanyId());
+        Long userId = loginUser.getUser().getUserId();
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+        if (ObjectUtil.isNotEmpty(config.getIsBound())&&config.getIsBound()){
+            fsCourseRedPacketLog.setCompanyId( loginUser.getCompany().getCompanyId());
+        }
 
 
         List<FsCourseRedPacketLogListPVO> list = fsCourseRedPacketLogService.selectFsCourseRedPacketLogListVO(fsCourseRedPacketLog);
         List<FsCourseRedPacketLogListPVO> list = fsCourseRedPacketLogService.selectFsCourseRedPacketLogListVO(fsCourseRedPacketLog);
         for (FsCourseRedPacketLogListPVO fsCourseRedPacketLogListPVO : list) {
         for (FsCourseRedPacketLogListPVO fsCourseRedPacketLogListPVO : list) {

+ 2 - 0
fs-company/src/main/java/com/fs/company/controller/course/FsUserCoursePeriodController.java

@@ -191,6 +191,7 @@ public class FsUserCoursePeriodController extends BaseController {
 
 
     @ApiOperation("按课程批量保存设置红包金额")
     @ApiOperation("按课程批量保存设置红包金额")
     @PostMapping("/batchRedPacket")
     @PostMapping("/batchRedPacket")
+    @Log(title = "按课程批量保存设置红包金额", businessType = BusinessType.UPDATE)
     public R batchRedPacketMoney(@RequestBody List<FsUserCourseVideoRedPackage> videoRedPackageList) {
     public R batchRedPacketMoney(@RequestBody List<FsUserCourseVideoRedPackage> videoRedPackageList) {
         try {
         try {
             fsUserCourseVideoRedPackageService.batchSaveCompanyRedPackage(videoRedPackageList);
             fsUserCourseVideoRedPackageService.batchSaveCompanyRedPackage(videoRedPackageList);
@@ -203,6 +204,7 @@ public class FsUserCoursePeriodController extends BaseController {
 
 
     @ApiOperation("按营期批量保存设置红包金额")
     @ApiOperation("按营期批量保存设置红包金额")
     @PostMapping("/batchRedPacket/byPeriod")
     @PostMapping("/batchRedPacket/byPeriod")
+    @Log(title = "按营期批量保存设置红包金额", businessType = BusinessType.UPDATE)
     public R batchRedPacketByPeriod(@RequestBody List<FsBatchPeriodRedPackageParam> periodRedPackageList) {
     public R batchRedPacketByPeriod(@RequestBody List<FsBatchPeriodRedPackageParam> periodRedPackageList) {
         try {
         try {
             fsUserCourseVideoRedPackageService.batchRedPacketByPeriod(periodRedPackageList);
             fsUserCourseVideoRedPackageService.batchRedPacketByPeriod(periodRedPackageList);

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

@@ -36,7 +36,7 @@ public class FsUserCourseTrainingCampController {
     /**
     /**
      * 查询训练营列表
      * 查询训练营列表
      */
      */
-    @PreAuthorize("@ss.hasPermi('course:trainingCamp:list')")
+    //@PreAuthorize("@ss.hasPermi('course:trainingCamp:list')")
     @GetMapping("/list")
     @GetMapping("/list")
     public AjaxResult list(@RequestParam(required = false) String trainingCampName,
     public AjaxResult list(@RequestParam(required = false) String trainingCampName,
                            @RequestParam(required = false) String userId,
                            @RequestParam(required = false) String userId,

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

@@ -25,7 +25,7 @@ public class FsUserOperationLogController extends BaseController {
     @Autowired
     @Autowired
     private IFsUserOperationLogService fsUserOperationLogService;
     private IFsUserOperationLogService fsUserOperationLogService;
 
 
-    @PreAuthorize("@ss.hasPermi('his:userOperationLog:list')")
+    //@PreAuthorize("@ss.hasPermi('his:userOperationLog:list')")
     @GetMapping("/list")
     @GetMapping("/list")
     public TableDataInfo list(FsUserOperationLog fsUserOperationLog)
     public TableDataInfo list(FsUserOperationLog fsUserOperationLog)
     {
     {

+ 132 - 3
fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactController.java

@@ -11,6 +11,7 @@ import com.fs.common.utils.PubFun;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyUser;
 import com.fs.company.service.impl.CompanyDeptServiceImpl;
 import com.fs.company.service.impl.CompanyDeptServiceImpl;
 import com.fs.course.param.FsUserCourseListUParam;
 import com.fs.course.param.FsUserCourseListUParam;
 import com.fs.course.service.IFsUserCourseStudyService;
 import com.fs.course.service.IFsUserCourseStudyService;
@@ -21,13 +22,16 @@ import com.fs.crm.vo.CrmMyCustomerListQueryVO;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 import com.fs.framework.service.TokenService;
 import com.fs.his.service.IFsUserService;
 import com.fs.his.service.IFsUserService;
+import com.fs.qw.domain.QwContactWay;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwTag;
 import com.fs.qw.domain.QwTag;
+import com.fs.qw.dto.CompanyTransferDTO;
 import com.fs.qw.param.*;
 import com.fs.qw.param.*;
 import com.fs.qw.service.*;
 import com.fs.qw.service.*;
 import com.fs.qw.vo.QwExternalContactVO;
 import com.fs.qw.vo.QwExternalContactVO;
 import com.fs.qw.vo.QwFsUserVO;
 import com.fs.qw.vo.QwFsUserVO;
 import com.fs.qw.vo.QwUserDelLossLogVO;
 import com.fs.qw.vo.QwUserDelLossLogVO;
+import com.fs.voice.utils.StringUtil;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageHelper;
 import com.google.gson.Gson;
 import com.google.gson.Gson;
 import com.google.gson.reflect.TypeToken;
 import com.google.gson.reflect.TypeToken;
@@ -38,6 +42,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 
 
+import javax.validation.Valid;
 import java.io.IOException;
 import java.io.IOException;
 import java.util.*;
 import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
@@ -78,6 +83,11 @@ public class QwExternalContactController extends BaseController
 
 
     @Autowired
     @Autowired
     private CompanyDeptServiceImpl companyDeptService;
     private CompanyDeptServiceImpl companyDeptService;
+    @Autowired
+    private IQwExternalContactTransferCompanyAuditService auditService;
+
+    @Autowired
+    private IQwContactWayService qwContactWayService;
 
 
     /**
     /**
      * 查询企业微信客户列表
      * 查询企业微信客户列表
@@ -86,8 +96,13 @@ public class QwExternalContactController extends BaseController
     @GetMapping("/list")
     @GetMapping("/list")
     public TableDataInfo list(QwExternalContactParam qwExternalContact)
     public TableDataInfo list(QwExternalContactParam qwExternalContact)
     {
     {
-        startPage();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+
+        QwContactWay qwContactWay=new QwContactWay();
+        qwContactWay.setCompanyId(loginUser.getCompany().getCompanyId());
+        List<QwContactWay> wayList = qwContactWayService.selectQwContactWayList(qwContactWay);
+
+        startPage();
         qwExternalContact.setCompanyId(loginUser.getCompany().getCompanyId());
         qwExternalContact.setCompanyId(loginUser.getCompany().getCompanyId());
         List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(qwExternalContact);
         List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(qwExternalContact);
         list.forEach(item->{
         list.forEach(item->{
@@ -105,11 +120,47 @@ public class QwExternalContactController extends BaseController
 
 
                 item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
                 item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
             }
             }
+
+            if (!StringUtil.strIsNullOrEmpty(item.getState()) && !wayList.isEmpty()) {
+                item.setState(item.getState()+"-"+getContactWayNameStream(item.getState(), wayList));
+            }
+
         });
         });
 
 
         return getDataTable(list);
         return getDataTable(list);
     }
     }
 
 
+
+    public String getContactWayNameStream(String configStr, List<QwContactWay> wayList) {
+        if (configStr == null || wayList == null || wayList.isEmpty()) {
+            return null;
+        }
+
+        return wayList.stream()
+                .filter(way -> way.getId() != null &&
+                        way.getId().toString().equals(extractLastValue(configStr)))
+                .map(QwContactWay::getName)
+                .findFirst()
+                .orElse(null);
+    }
+
+    /**
+     * 提取最后一个冒号后的值
+     */
+    private String extractLastValue(String input) {
+        if (input == null || input.isEmpty()) {
+            return null;
+        }
+
+        int lastColonIndex = input.lastIndexOf(":");
+        if (lastColonIndex == -1) {
+            return input;
+        }
+
+        return input.substring(lastColonIndex + 1);
+    }
+
+
     @GetMapping("/test")
     @GetMapping("/test")
     public AjaxResult test()
     public AjaxResult test()
     {
     {
@@ -154,6 +205,10 @@ public class QwExternalContactController extends BaseController
         qwExternalContact.setUserType(loginUser.getUser().getUserType());
         qwExternalContact.setUserType(loginUser.getUser().getUserType());
         qwExternalContact.setCompanyId(loginUser.getCompany().getCompanyId());
         qwExternalContact.setCompanyId(loginUser.getCompany().getCompanyId());
 
 
+        QwContactWay qwContactWay=new QwContactWay();
+        qwContactWay.setCompanyId(loginUser.getCompany().getCompanyId());
+        List<QwContactWay> wayList = qwContactWayService.selectQwContactWayList(qwContactWay);
+
         startPage();
         startPage();
         List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(qwExternalContact);
         List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(qwExternalContact);
         list.forEach(item->{
         list.forEach(item->{
@@ -171,6 +226,11 @@ public class QwExternalContactController extends BaseController
 
 
                 item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
                 item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
             }
             }
+
+            if (!StringUtil.strIsNullOrEmpty(item.getState()) && !wayList.isEmpty()) {
+                item.setState(item.getState()+"-"+getContactWayNameStream(item.getState(), wayList));
+            }
+
         });
         });
 
 
         return getDataTable(list);
         return getDataTable(list);
@@ -183,8 +243,14 @@ public class QwExternalContactController extends BaseController
         if(qwExternalContact.getQwUserId()==null){
         if(qwExternalContact.getQwUserId()==null){
             return null;
             return null;
         }
         }
-        startPage();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+
+        QwContactWay qwContactWay=new QwContactWay();
+        qwContactWay.setCompanyId(loginUser.getCompany().getCompanyId());
+        List<QwContactWay> wayList = qwContactWayService.selectQwContactWayList(qwContactWay);
+
+
+        startPage();
         qwExternalContact.setCompanyId(loginUser.getCompany().getCompanyId());
         qwExternalContact.setCompanyId(loginUser.getCompany().getCompanyId());
         List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(qwExternalContact);
         List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(qwExternalContact);
         list.forEach(item->{
         list.forEach(item->{
@@ -202,6 +268,10 @@ public class QwExternalContactController extends BaseController
 
 
                 item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
                 item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
             }
             }
+
+            if (!StringUtil.strIsNullOrEmpty(item.getState()) && !wayList.isEmpty()) {
+                item.setState(item.getState()+"-"+getContactWayNameStream(item.getState(), wayList));
+            }
         });
         });
 
 
         return getDataTable(list);
         return getDataTable(list);
@@ -224,7 +294,7 @@ public class QwExternalContactController extends BaseController
     /**
     /**
      * 导出企业微信客户列表
      * 导出企业微信客户列表
      */
      */
-    @PreAuthorize("@ss.hasPermi('qw:externalContact:export')")
+    @PreAuthorize("@ss.hasAnyPermi('qw:externalContact:export,qw:externalContact:companyExport')")
     @Log(title = "企业微信客户", businessType = BusinessType.EXPORT)
     @Log(title = "企业微信客户", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
     @GetMapping("/export")
     public AjaxResult export(QwExternalContactParam qwExternalContact)
     public AjaxResult export(QwExternalContactParam qwExternalContact)
@@ -232,7 +302,13 @@ public class QwExternalContactController extends BaseController
         if (qwExternalContact.getCorpId()==null){
         if (qwExternalContact.getCorpId()==null){
             return AjaxResult.success();
             return AjaxResult.success();
         }
         }
+
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+
+        QwContactWay qwContactWay=new QwContactWay();
+        qwContactWay.setCompanyId(loginUser.getCompany().getCompanyId());
+        List<QwContactWay> wayList = qwContactWayService.selectQwContactWayList(qwContactWay);
+
         qwExternalContact.setCompanyId(loginUser.getCompany().getCompanyId());
         qwExternalContact.setCompanyId(loginUser.getCompany().getCompanyId());
         List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(qwExternalContact);
         List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(qwExternalContact);
         list.forEach(item->{
         list.forEach(item->{
@@ -250,6 +326,10 @@ public class QwExternalContactController extends BaseController
 
 
                 item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
                 item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
             }
             }
+
+            if (!StringUtil.strIsNullOrEmpty(item.getState()) && !wayList.isEmpty()) {
+                item.setState(item.getState()+"-"+getContactWayNameStream(item.getState(), wayList));
+            }
         });
         });
         ExcelUtil<QwExternalContactVO> util = new ExcelUtil<QwExternalContactVO>(QwExternalContactVO.class);
         ExcelUtil<QwExternalContactVO> util = new ExcelUtil<QwExternalContactVO>(QwExternalContactVO.class);
         return util.exportExcel(list, "企业微信客户数据");
         return util.exportExcel(list, "企业微信客户数据");
@@ -266,6 +346,10 @@ public class QwExternalContactController extends BaseController
         }
         }
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         qwExternalContact.setCompanyId(loginUser.getCompany().getCompanyId());
         qwExternalContact.setCompanyId(loginUser.getCompany().getCompanyId());
+        QwContactWay qwContactWay=new QwContactWay();
+        qwContactWay.setCompanyId(loginUser.getCompany().getCompanyId());
+        List<QwContactWay> wayList = qwContactWayService.selectQwContactWayList(qwContactWay);
+
 
 
         List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(qwExternalContact);
         List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(qwExternalContact);
 
 
@@ -284,6 +368,10 @@ public class QwExternalContactController extends BaseController
 
 
                 item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
                 item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
             }
             }
+
+            if (!StringUtil.strIsNullOrEmpty(item.getState()) && !wayList.isEmpty()) {
+                item.setState(item.getState()+"-"+getContactWayNameStream(item.getState(), wayList));
+            }
         });
         });
 
 
         ExcelUtil<QwExternalContactVO> util = new ExcelUtil<QwExternalContactVO>(QwExternalContactVO.class);
         ExcelUtil<QwExternalContactVO> util = new ExcelUtil<QwExternalContactVO>(QwExternalContactVO.class);
@@ -645,4 +733,45 @@ public class QwExternalContactController extends BaseController
         return util.exportExcel(qwUserDelLossLogVOS, "企微用户删除流失统计");
         return util.exportExcel(qwUserDelLossLogVOS, "企微用户删除流失统计");
     }
     }
 
 
+    /**
+     * 公司客户
+     */
+    @PreAuthorize("@ss.hasPermi('qw:externalContact:companyExtList')")
+    @GetMapping("/companyExtList")
+    public TableDataInfo companyExtList(QwExternalContactParam qwExternalContact)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        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:companyTransfer')")
+    @PostMapping("/companyTransfer")
+    public R companyTransfer(@Valid @RequestBody CompanyTransferDTO param) {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        CompanyUser user = loginUser.getUser();
+        auditService.addAudit(param, user.getCompanyId(), user.getUserName());
+        return R.ok();
+    }
+
 }
 }

+ 56 - 0
fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactTransferCompanyAuditController.java

@@ -0,0 +1,56 @@
+package com.fs.company.controller.qw;
+
+import com.fs.common.annotation.Log;
+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.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.service.TokenService;
+import com.fs.qw.domain.QwExternalContactTransferCompanyAudit;
+import com.fs.qw.service.IQwExternalContactTransferCompanyAuditService;
+import com.fs.qw.service.IQwExternalContactTransferCompanyAuditUserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/qw/externalContactTransferCompanyAudit")
+public class QwExternalContactTransferCompanyAuditController extends BaseController {
+
+    @Autowired
+    private IQwExternalContactTransferCompanyAuditService auditService;
+    @Autowired
+    private IQwExternalContactTransferCompanyAuditUserService auditUserService;
+    @Autowired
+    private TokenService tokenService;
+
+    @PreAuthorize("@ss.hasPermi('qw:externalContactTransferCompanyAudit:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(QwExternalContactTransferCompanyAudit param) {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        Long companyId = loginUser.getCompany().getCompanyId();
+        param.setOperCompanyId(companyId);
+        List<QwExternalContactTransferCompanyAudit> list = auditService.selectQwExternalContactTransferCompanyAuditList(param);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('qw:externalContactTransferCompanyAudit:sync')")
+    @Log(title = "公司转接同步", businessType = BusinessType.INSERT)
+    @PostMapping("/sync/{auditId}")
+    public R sync(@PathVariable("auditId") Long auditId) {
+        auditService.syncTransfer(auditId);
+        return R.ok();
+    }
+
+    @PreAuthorize("@ss.hasPermi('qw:externalContactTransferCompanyAudit:detail')")
+    @GetMapping("/detail/{auditId}")
+    public AjaxResult detail(@PathVariable Long auditId) {
+        return AjaxResult.success(auditUserService.getListByAuditId(auditId));
+    }
+}

+ 97 - 4
fs-company/src/main/java/com/fs/company/controller/qw/QwSopController.java

@@ -1,5 +1,6 @@
 package com.fs.company.controller.qw;
 package com.fs.company.controller.qw;
 
 
+import com.alibaba.fastjson.JSONObject;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.controller.BaseController;
@@ -17,21 +18,29 @@ import com.fs.framework.service.TokenService;
 import com.fs.his.vo.OptionsVO;
 import com.fs.his.vo.OptionsVO;
 import com.fs.qw.domain.QwSopUpdateStatus;
 import com.fs.qw.domain.QwSopUpdateStatus;
 import com.fs.qw.service.IQwUserService;
 import com.fs.qw.service.IQwUserService;
+import com.fs.qw.vo.QwUserVO;
 import com.fs.sop.domain.QwSop;
 import com.fs.sop.domain.QwSop;
+import com.fs.sop.domain.QwSopTempContent;
+import com.fs.sop.domain.QwSopTempVoice;
 import com.fs.sop.params.QwSopAutoTime;
 import com.fs.sop.params.QwSopAutoTime;
 import com.fs.sop.params.QwSopEditQwUserParam;
 import com.fs.sop.params.QwSopEditQwUserParam;
 import com.fs.sop.service.ICompanySopRoleService;
 import com.fs.sop.service.ICompanySopRoleService;
 import com.fs.sop.service.IQwSopService;
 import com.fs.sop.service.IQwSopService;
+import com.fs.sop.service.IQwSopTempContentService;
+import com.fs.sop.service.IQwSopTempVoiceService;
 import com.fs.sop.vo.SopVoiceListVo;
 import com.fs.sop.vo.SopVoiceListVo;
+import org.apache.commons.beanutils.ConvertUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 
 
 import java.io.IOException;
 import java.io.IOException;
 import java.text.SimpleDateFormat;
 import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.Date;
 import java.util.List;
 import java.util.List;
+import java.util.stream.Collectors;
 
 
 /**
 /**
  * 企微sopController
  * 企微sopController
@@ -64,6 +73,13 @@ public class QwSopController extends BaseController
     @Autowired
     @Autowired
     private IQwUserService iQwUserService;
     private IQwUserService iQwUserService;
 
 
+
+    @Autowired
+    private IQwSopTempContentService qwSopTempContentService;
+
+    @Autowired
+    private IQwSopTempVoiceService voiceService;
+
     /**
     /**
      * 查询企微sop列表
      * 查询企微sop列表
      */
      */
@@ -228,8 +244,13 @@ public class QwSopController extends BaseController
         qwSop.setCompanyId(companyId);
         qwSop.setCompanyId(companyId);
         qwSop.setCreateBy(loginUser.getUser().getNickName());
         qwSop.setCreateBy(loginUser.getUser().getNickName());
         qwSop.setCreateTime(sdf.format(new Date()));
         qwSop.setCreateTime(sdf.format(new Date()));
-
-        return toAjax(qwSopService.insertQwSop(qwSop));
+        int count = qwSopService.insertQwSop(qwSop);
+        if(count > 0){
+            if(qwSop.getQwUserIds() != null){
+                updateTempVoiceInfo(qwSop);
+            }
+        }
+        return toAjax(count);
 
 
     }
     }
 
 
@@ -241,7 +262,14 @@ public class QwSopController extends BaseController
     @PutMapping
     @PutMapping
     public R edit(@RequestBody QwSop qwSop)
     public R edit(@RequestBody QwSop qwSop)
     {
     {
-        return qwSopService.updateQwSop(qwSop);
+        R sop = qwSopService.updateQwSop(qwSop);
+        String code = sop.get("code").toString();
+        if(code.equals("200")){
+            if(qwSop != null && qwSop.getQwUserIds() != null){
+                updateTempVoiceInfo(qwSop);
+            }
+        }
+        return sop;
     }
     }
 
 
 
 
@@ -267,6 +295,52 @@ public class QwSopController extends BaseController
         return toAjax(qwSopService.updateAutoSopTime(param));
         return toAjax(qwSopService.updateAutoSopTime(param));
     }
     }
 
 
+    /**
+     * 修改qwSop任务,新增或者删除qwUser
+     * @param qwSop
+     */
+    private void updateTempVoiceInfo(QwSop qwSop) {
+        try {
+            String tempId = qwSop.getTempId();
+            String[] split = qwSop.getQwUserIds().split(",");
+            Long[] qwUserIds = (Long[]) ConvertUtils.convert(split, Long.class);
+
+            List<QwSopTempContent> qwSopTempContentList = qwSopTempContentService.selectQwSopTempContentByTempId(tempId);
+            if(qwSopTempContentList != null && !qwSopTempContentList.isEmpty()){
+                for (QwSopTempContent qwSopTemp : qwSopTempContentList) {
+                    if(qwSopTemp != null && qwSopTemp.getContent() != null){
+                        String content = qwSopTemp.getContent();
+                        JSONObject jsonObject = JSONObject.parseObject(content);
+                        String voiceTxt = jsonObject.getString("value");
+                        String contentType = jsonObject.getString("contentType");
+                        if("7".equals(contentType)){
+                            List<QwUserVO> qwUserVoS = qwUserService.selectQwUserVOByIds(qwUserIds);
+                            if(qwUserVoS != null && !qwUserVoS.isEmpty()){
+                                List<Long> companyUserIdList = qwUserVoS.stream().map(QwUserVO::getCompanyUserId).collect(Collectors.toList());
+                                for (Long companyUserId : companyUserIdList) {
+                                    QwSopTempVoice qwSopTempVoice = voiceService.selectQwSopTempVoiceByCompanyUserIdAndVoiceTxt(companyUserId,voiceTxt);
+                                    if(qwSopTempVoice == null){
+                                        if(companyUserId != null && voiceTxt != null){
+                                            QwSopTempVoice tempVoice = new QwSopTempVoice();
+                                            tempVoice.setVoiceTxt(voiceTxt);
+                                            tempVoice.setCompanyUserId(companyUserId);
+                                            tempVoice.setRecordType(0);
+                                            tempVoice.setCreateTime(LocalDateTime.now());
+                                            tempVoice.setTempId(tempId);
+                                            voiceService.insertQwSopTempVoice(tempVoice);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            logger.error("修改企微sop任务,新增或者删除qwUser异常:" + e.getMessage());
+        }
+    }
+
     /**
     /**
      * 删除企微sop
      * 删除企微sop
      */
      */
@@ -278,6 +352,17 @@ public class QwSopController extends BaseController
         return toAjax(qwSopService.deleteQwSopByIds(ids));
         return toAjax(qwSopService.deleteQwSopByIds(ids));
     }
     }
 
 
+    /**
+     * 批量删除SOP 任务下面的执行记录
+     */
+    @PreAuthorize("@ss.hasPermi('qw:sopLogs:removeAll')")
+    @Log(title = "企微sop", businessType = BusinessType.DELETE)
+	@DeleteMapping("/delSopLogs/{ids}")
+    public AjaxResult removeAll(@PathVariable String[] ids)
+    {
+        return toAjax(qwSopService.deleteQwSopLogsBySopIds(ids));
+    }
+
 
 
     /**
     /**
      * 批量执行SOP
      * 批量执行SOP
@@ -296,7 +381,15 @@ public class QwSopController extends BaseController
     @PreAuthorize("@ss.hasPermi('qw:sop:updateSopQwUser')")
     @PreAuthorize("@ss.hasPermi('qw:sop:updateSopQwUser')")
     public R updateSopQwUser(@RequestBody QwSopEditQwUserParam param)
     public R updateSopQwUser(@RequestBody QwSopEditQwUserParam param)
     {
     {
-        return qwSopService.updateSopQwUser(param);
+        R sop = qwSopService.updateSopQwUser(param);
+        String code = sop.get("code").toString();
+        if(code.equals("200")){
+            QwSop qwSop = qwSopService.selectQwSopById(param.getId());
+            if(qwSop != null && qwSop.getQwUserIds() != null){
+                updateTempVoiceInfo(qwSop);
+            }
+        }
+        return sop;
     }
     }
 
 
     /**
     /**

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

@@ -149,7 +149,9 @@ public class QwSopLogsController extends BaseController
      * 我的自动化任务 和部门自动化任务 就只显示自己的或者部门的
      * 我的自动化任务 和部门自动化任务 就只显示自己的或者部门的
      */
      */
     private List<Long> getQwUserKeyList(QwSopLogsParam param, LoginUser loginUser) {
     private List<Long> getQwUserKeyList(QwSopLogsParam param, LoginUser loginUser) {
-
+        if(param.getFilterSopType() == null){
+            return new ArrayList<>(); // 返回空列表而不是null
+        }
         switch (param.getFilterSopType()) {
         switch (param.getFilterSopType()) {
             case 2:
             case 2:
                 CompanyUser companyUser = iCompanyUserService.selectCompanyUserById(loginUser.getUser().getUserId());
                 CompanyUser companyUser = iCompanyUserService.selectCompanyUserById(loginUser.getUser().getUserId());

+ 9 - 0
fs-company/src/main/java/com/fs/company/controller/qw/QwUserController.java

@@ -842,4 +842,13 @@ public class QwUserController extends BaseController
         return R.ok();
         return R.ok();
     }
     }
 
 
+    @GetMapping("/companyQwUserlist")
+    public TableDataInfo companyQwUserlist(@RequestParam Long companyId,
+                                           @RequestParam String corpId,
+                                           @RequestParam(required = false) String nickName)
+    {
+        startPage();
+        List<QwUserVO> list = qwUserService.selectQwUserListByCompanyIdAndCorpIdAndNickName(companyId, corpId, nickName);
+        return getDataTable(list);
+    }
 }
 }

+ 80 - 4
fs-company/src/main/java/com/fs/company/controller/qw/QwUserVoiceLogController.java

@@ -1,12 +1,18 @@
 package com.fs.company.controller.qw;
 package com.fs.company.controller.qw;
 
 
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.Log;
+import com.fs.common.constant.HttpStatus;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.PageDomain;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.core.page.TableSupport;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.ICompanyUserService;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 import com.fs.framework.service.TokenService;
 import com.fs.qw.domain.QwUserVoiceLog;
 import com.fs.qw.domain.QwUserVoiceLog;
@@ -22,8 +28,10 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 import java.util.Objects;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 
 /**
 /**
  * 企微用户通话记录Controller
  * 企微用户通话记录Controller
@@ -44,6 +52,9 @@ public class QwUserVoiceLogController extends BaseController
     @Autowired
     @Autowired
     private IQwTagService iQwTagService;
     private IQwTagService iQwTagService;
 
 
+    @Autowired
+    private ICompanyUserService userService;
+
     /**
     /**
      * 查询企微用户通话记录列表
      * 查询企微用户通话记录列表
      */
      */
@@ -137,23 +148,88 @@ public class QwUserVoiceLogController extends BaseController
     @GetMapping("/totalList")
     @GetMapping("/totalList")
     public TableDataInfo totalList(QwUserVoiceLogTotalVo qwUserVoiceLog)
     public TableDataInfo totalList(QwUserVoiceLogTotalVo qwUserVoiceLog)
     {
     {
-        startPage();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         qwUserVoiceLog.setCompanyId(loginUser.getCompany().getCompanyId());
         qwUserVoiceLog.setCompanyId(loginUser.getCompany().getCompanyId());
         qwUserVoiceLog.setQwUserId(1L);
         qwUserVoiceLog.setQwUserId(1L);
         List<QwUserVoiceLogTotalVo> list = qwUserVoiceLogService.selectQwUserVoiceLogTotalList(qwUserVoiceLog);
         List<QwUserVoiceLogTotalVo> list = qwUserVoiceLogService.selectQwUserVoiceLogTotalList(qwUserVoiceLog);
-        return getDataTable(list);
+        list.forEach(item->{
+            if(item.getQwExternalContact() != null){
+                if (item.getQwExternalContact().getTagIds() != null && !Objects.equals(item.getQwExternalContact().getTagIds(), "[]")) {
+                    QwTagSearchParam param = new QwTagSearchParam();
+                    Gson gson = new Gson();
+                    List<String> tagIds = gson.fromJson(
+                            item.getQwExternalContact().getTagIds(),
+                            new TypeToken<List<String>>() {
+                            }.getType()
+                    );
+                    param.setTagIds(tagIds);
+                    item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
+                }
+            }
+        });
+
+        // 获取分页参数
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+        Integer pageNum = pageDomain.getPageNum();
+        Integer pageSize = pageDomain.getPageSize();
+
+        int total = list.size();
+        // 在内存中进行分页处理
+        if (pageNum != null && pageSize != null) {
+            int fromIndex = (pageNum - 1) * pageSize;
+            int toIndex = Math.min(fromIndex + pageSize, total);
+
+            // 确保索引不越界
+            if (fromIndex < total) {
+                list = list.subList(fromIndex, toIndex);
+            } else {
+                list = new ArrayList<>(); // 返回空列表
+            }
+        }
+
+        // 构造返回结果
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(HttpStatus.SUCCESS);
+        rspData.setMsg("查询成功");
+        rspData.setRows(list);
+        rspData.setTotal(total);
+        return rspData;
     }
     }
 
 
 
 
     @GetMapping("/sellTotalList")
     @GetMapping("/sellTotalList")
     public TableDataInfo sellTotalList(QwUserVoiceLogTotalVo qwUserVoiceLog)
     public TableDataInfo sellTotalList(QwUserVoiceLogTotalVo qwUserVoiceLog)
     {
     {
-        startPage();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         qwUserVoiceLog.setCompanyId(loginUser.getCompany().getCompanyId());
         qwUserVoiceLog.setCompanyId(loginUser.getCompany().getCompanyId());
         List<QwUserVoiceLogTotalVo> list = qwUserVoiceLogService.selectQwUserVoiceLogTotalList(qwUserVoiceLog);
         List<QwUserVoiceLogTotalVo> list = qwUserVoiceLogService.selectQwUserVoiceLogTotalList(qwUserVoiceLog);
-        return getDataTable(list);
+
+        // 获取分页参数
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+        Integer pageNum = pageDomain.getPageNum();
+        Integer pageSize = pageDomain.getPageSize();
+
+        int total = list.size();
+        // 在内存中进行分页处理
+        if (pageNum != null && pageSize != null) {
+            int fromIndex = (pageNum - 1) * pageSize;
+            int toIndex = Math.min(fromIndex + pageSize, total);
+
+            // 确保索引不越界
+            if (fromIndex < total) {
+                list = list.subList(fromIndex, toIndex);
+            } else {
+                list = new ArrayList<>(); // 返回空列表
+            }
+        }
+
+        // 构造返回结果
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(HttpStatus.SUCCESS);
+        rspData.setMsg("查询成功");
+        rspData.setRows(list);
+        rspData.setTotal(total);
+        return rspData;
     }
     }
 
 
     @PreAuthorize("@ss.hasPermi('qw:qwUserVoiceLog:sellTotalExport')")
     @PreAuthorize("@ss.hasPermi('qw:qwUserVoiceLog:sellTotalExport')")

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

@@ -83,10 +83,10 @@ public class SopUserLogsController extends BaseController
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
 
 
         List<String> qwUserIdList=null;
         List<String> qwUserIdList=null;
-        if (sopUserLogs.getType()==2){
+        if (sopUserLogs.getType() != null && sopUserLogs.getType()==2){
             qwUserIdList = iQwUserService.selectQwUserListByCompanyUserId(loginUser.getUser().getUserId(), sopUserLogs.getCorpId());
             qwUserIdList = iQwUserService.selectQwUserListByCompanyUserId(loginUser.getUser().getUserId(), sopUserLogs.getCorpId());
         }
         }
-        if (qwUserIdList!=null&& !qwUserIdList.isEmpty() && sopUserLogs.getType()==2 ){
+        if (qwUserIdList!=null&& !qwUserIdList.isEmpty() && sopUserLogs.getType() != null &&  sopUserLogs.getType()==2 ){
             sopUserLogs.setQwIdsList(qwUserIdList);
             sopUserLogs.setQwIdsList(qwUserIdList);
         }
         }
 
 

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

@@ -130,7 +130,7 @@ public class FsStoreOrderController extends BaseController
         task.setCompanyUserId(userId);
         task.setCompanyUserId(userId);
         exportTaskService.insertFsExportTask(task);
         exportTaskService.insertFsExportTask(task);
         param.setTaskId(task.getTaskId());
         param.setTaskId(task.getTaskId());
-        exportTaskService.exportStore1Data(param,false);
+        exportTaskService.exportStore1Data(param,false, null);
         return new AjaxResult(200,"后台正在导出,请等待...任务ID:"+task.getTaskId(),task.getTaskId());
         return new AjaxResult(200,"后台正在导出,请等待...任务ID:"+task.getTaskId(),task.getTaskId());
 
 
 
 
@@ -172,7 +172,7 @@ public class FsStoreOrderController extends BaseController
         task.setCompanyUserId(userId);
         task.setCompanyUserId(userId);
         exportTaskService.insertFsExportTask(task);
         exportTaskService.insertFsExportTask(task);
         param.setTaskId(task.getTaskId());
         param.setTaskId(task.getTaskId());
-        exportTaskService.exportStore1Data(param,false);
+        exportTaskService.exportStore1Data(param,false, null);
         return new AjaxResult(200,"后台正在导出,请等待...任务ID:"+task.getTaskId(),task.getTaskId());
         return new AjaxResult(200,"后台正在导出,请等待...任务ID:"+task.getTaskId(),task.getTaskId());
     }
     }
     /**
     /**

+ 37 - 0
fs-company/src/main/java/com/fs/framework/config/RedisConfig.java

@@ -19,6 +19,7 @@ import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 
 
+import java.math.BigDecimal;
 import java.util.Arrays;
 import java.util.Arrays;
 
 
 /**
 /**
@@ -55,6 +56,25 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         template.afterPropertiesSet();
         return template;
         return template;
     }
     }
+
+    @Bean
+    public RedisTemplate<String, Integer> redisTemplateForInteger(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, Integer> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
     @Bean
     @Bean
     public RedisTemplate<String, Boolean> redisTemplateForBoolean(RedisConnectionFactory connectionFactory) {
     public RedisTemplate<String, Boolean> redisTemplateForBoolean(RedisConnectionFactory connectionFactory) {
         RedisTemplate<String, Boolean> template = new RedisTemplate<>();
         RedisTemplate<String, Boolean> template = new RedisTemplate<>();
@@ -96,7 +116,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         template.afterPropertiesSet();
         return template;
         return template;
     }
     }
+    @Bean
+    public RedisTemplate<String, BigDecimal> redisTemplateForBigDecimal(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, BigDecimal> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
 
 
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
     @Bean
     @Bean
     public DefaultRedisScript<Long> limitScript()
     public DefaultRedisScript<Long> limitScript()
     {
     {

+ 129 - 0
fs-company/src/main/java/com/fs/hisStore/controller/FsIntegralGoodsController.java

@@ -0,0 +1,129 @@
+package com.fs.hisStore.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.his.domain.FsIntegralGoods;
+import com.fs.his.service.IFsIntegralGoodsService;
+import com.fs.his.utils.RedisCacheUtil;
+import com.fs.his.vo.FsIntegralGoodsListVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+/**
+ * 积分商品Controller
+ *
+ * @author fs
+ * @date 2023-11-02
+ */
+@RestController
+@RequestMapping("/his/integralGoods")
+public class FsIntegralGoodsController extends BaseController
+{
+    @Autowired
+    private IFsIntegralGoodsService fsIntegralGoodsService;
+    @Autowired
+    RedisCacheUtil redisCacheUtil;
+    /**
+     * 查询积分商品列表
+     */
+//    @PreAuthorize("@ss.hasPermi('his:integralGoods:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsIntegralGoods fsIntegralGoods)
+    {
+        startPage();
+        List<FsIntegralGoodsListVO> list = fsIntegralGoodsService.selectFsIntegralGoodsListVO(fsIntegralGoods);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出积分商品列表
+     */
+//    @PreAuthorize("@ss.hasPermi('his:integralGoods:export')")
+    @Log(title = "积分商品", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsIntegralGoods fsIntegralGoods)
+    {
+        List<FsIntegralGoods> list = fsIntegralGoodsService.selectFsIntegralGoodsList(fsIntegralGoods);
+        ExcelUtil<FsIntegralGoods> util = new ExcelUtil<FsIntegralGoods>(FsIntegralGoods.class);
+        return util.exportExcel(list, "积分商品数据");
+    }
+
+    /**
+     * 获取积分商品详细信息
+     */
+//    @PreAuthorize("@ss.hasPermi('his:integralGoods:query')")
+    @GetMapping(value = "/{goodsId}")
+    public AjaxResult getInfo(@PathVariable("goodsId") Long goodsId)
+    {
+        return AjaxResult.success(fsIntegralGoodsService.selectFsIntegralGoodsByGoodsId(goodsId));
+    }
+
+
+    @Log(title = "商品导入", businessType = BusinessType.IMPORT)
+    @PostMapping("/importData")
+    public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
+    {
+        redisCacheUtil.delRedisKey("getIntegralGoodsList");
+        redisCacheUtil.delRedisKey("getIntegralGoodsById");
+        ExcelUtil<FsIntegralGoods> util = new ExcelUtil<>(FsIntegralGoods.class);
+        List<FsIntegralGoods> list = util.importExcel(file.getInputStream());
+        String message = fsIntegralGoodsService.importIntegralGoodsService(list);
+        return AjaxResult.success(message);
+    }
+
+    @GetMapping("/importTemplate")
+    public AjaxResult importTemplate()
+    {
+        ExcelUtil<FsIntegralGoods> util = new ExcelUtil<>(FsIntegralGoods.class);
+        return util.importTemplateExcel("商品数据");
+    }
+
+
+    /**
+     * 新增积分商品
+     */
+//    @PreAuthorize("@ss.hasPermi('his:integralGoods:add')")
+    @Log(title = "积分商品", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsIntegralGoods fsIntegralGoods)
+    {
+        redisCacheUtil.delRedisKey("getIntegralGoodsList");
+        redisCacheUtil.delRedisKey("getIntegralGoodsById");
+        return toAjax(fsIntegralGoodsService.insertFsIntegralGoods(fsIntegralGoods));
+    }
+
+    /**
+     * 修改积分商品
+     */
+//    @PreAuthorize("@ss.hasPermi('his:integralGoods:edit')")
+    @Log(title = "积分商品", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsIntegralGoods fsIntegralGoods)
+    {
+
+        redisCacheUtil.delRedisKey("getIntegralGoodsList");
+        redisCacheUtil.delRedisKey("getIntegralGoodsById");
+        return toAjax(fsIntegralGoodsService.updateFsIntegralGoods(fsIntegralGoods));
+    }
+
+    /**
+     * 删除积分商品
+     */
+//    @PreAuthorize("@ss.hasPermi('his:integralGoods:remove')")
+    @Log(title = "积分商品", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{goodsIds}")
+    public AjaxResult remove(@PathVariable Long[] goodsIds)
+    {
+        redisCacheUtil.delRedisKey("getIntegralGoodsList");
+        redisCacheUtil.delRedisKey("getIntegralGoodsById");
+        return toAjax(fsIntegralGoodsService.deleteFsIntegralGoodsByGoodsIds(goodsIds));
+    }
+}

+ 182 - 0
fs-company/src/main/java/com/fs/hisStore/controller/FsIntegralOrderController.java

@@ -0,0 +1,182 @@
+package com.fs.hisStore.controller;
+
+import cn.hutool.core.lang.TypeReference;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.fs.common.annotation.Log;
+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.enums.BusinessType;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.his.domain.FsIntegralGoods;
+import com.fs.his.domain.FsIntegralOrder;
+import com.fs.his.dto.ExpressInfoDTO;
+import com.fs.his.enums.ShipperCodeEnum;
+import com.fs.his.mapper.FsIntegralGoodsMapper;
+import com.fs.his.param.FsIntegralOrderCreateParam;
+import com.fs.his.param.FsIntegralOrderParam;
+import com.fs.his.service.IFsExpressService;
+import com.fs.his.service.IFsIntegralOrderService;
+import com.fs.his.utils.PhoneUtil;
+import com.fs.his.vo.FsIntegralOrderListVO;
+import com.fs.his.vo.FsIntegralOrderPVO;
+import com.fs.his.vo.FsStoreProductDeliverExcelVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.*;
+
+import static com.fs.his.utils.PhoneUtil.decryptAutoPhoneMk;
+import static com.fs.his.utils.PhoneUtil.decryptPhone;
+
+/**
+ * 积分商品订单Controller
+ *
+ * @author fs
+ * @date 2023-11-02
+ */
+@RestController
+@RequestMapping("/his/integralOrder")
+public class FsIntegralOrderController extends BaseController
+{
+    @Autowired
+    private IFsIntegralOrderService fsIntegralOrderService;
+    @Autowired
+    private IFsExpressService expressService;
+
+    @Autowired
+    private FsIntegralGoodsMapper fsIntegralGoodsMapper;
+    /**
+     * 查询积分商品订单列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:integralOrder:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsIntegralOrderParam fsIntegralOrder)
+    {
+        startPage();
+        List<FsIntegralOrderListVO> list = fsIntegralOrderService.selectFsIntegralOrderListVO(fsIntegralOrder);
+        for (FsIntegralOrderListVO vo : list) {
+            vo.setUserPhone(decryptAutoPhoneMk(vo.getUserPhone()));
+        }
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出积分商品订单列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:integralOrder:export')")
+    @Log(title = "积分商品订单", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsIntegralOrder fsIntegralOrder) {
+        return fsIntegralOrderService.export(fsIntegralOrder);
+    }
+    /**
+     * 发货
+     */
+//    @PreAuthorize("@ss.hasPermi('his:integralOrder:sendGoods')")
+    @PutMapping("/sendGoods")
+    public AjaxResult sendGoods(@RequestBody FsIntegralOrder fsIntegralOrder)
+    {
+        return toAjax(fsIntegralOrderService.sendGoods(fsIntegralOrder));
+    }
+
+    @GetMapping("/importTemplate")
+    public AjaxResult sendExport()
+    {
+        ExcelUtil<FsStoreProductDeliverExcelVO> util = new ExcelUtil<>(FsStoreProductDeliverExcelVO.class);
+        return util.importTemplateExcel("导入运单号");
+    }
+    @Log(title = "导入运单号", businessType = BusinessType.IMPORT)
+    @PostMapping("/importData")
+    public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
+    {
+        ExcelUtil<FsStoreProductDeliverExcelVO> util = new ExcelUtil<>(FsStoreProductDeliverExcelVO.class);
+        List<FsStoreProductDeliverExcelVO> list = util.importExcel(file.getInputStream());
+        String message = fsIntegralOrderService.importProductDeliver(list);
+        return AjaxResult.success(message);
+    }
+//    @PreAuthorize("@ss.hasPermi('his:integralOrder:express')")
+    @GetMapping(value = "/getExpress/{id}")
+    public R getExpress(@PathVariable("id") Long id)
+    {
+        FsIntegralOrder fsIntegralOrder = fsIntegralOrderService.selectFsIntegralOrderByOrderId(id);
+        ExpressInfoDTO expressInfoDTO=null;
+        if(StringUtils.isNotEmpty(fsIntegralOrder.getDeliverySn())){
+            String lastFourNumber = "";
+            if (fsIntegralOrder.getDeliveryCode().equals(ShipperCodeEnum.SF.getValue())) {
+
+                lastFourNumber = fsIntegralOrder.getUserPhone();
+                if (lastFourNumber.length() == 11) {
+                    lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
+                }
+            }
+            expressInfoDTO=expressService.getExpressInfo(fsIntegralOrder.getOrderCode(),fsIntegralOrder.getDeliveryCode(),fsIntegralOrder.getDeliverySn(),lastFourNumber);
+        }
+        return R.ok().put("data",expressInfoDTO);
+    }
+    /**
+     * 获取积分商品订单详细信息
+     */
+//    @PreAuthorize("@ss.hasPermi('his:integralOrder:query')")
+    @GetMapping(value = "/{orderId}")
+    public AjaxResult getInfo(@PathVariable("orderId") Long orderId)
+    {
+        FsIntegralOrderPVO order = fsIntegralOrderService.selectFsIntegralOrderPVO(orderId);
+
+        order.setUserPhone(decryptAutoPhoneMk(order.getUserPhone()));
+        return AjaxResult.success(order);
+    }
+
+    @GetMapping(value = "/queryPhone/{orderId}")
+    @Log(title = "积分订单电话", businessType = BusinessType.GRANT)
+    @PreAuthorize("@ss.hasPermi('his:integralOrder:queryPhone')")
+    public R getPhone(@PathVariable("orderId") Long orderId)
+    {
+        FsIntegralOrderPVO order = fsIntegralOrderService.selectFsIntegralOrderPVO(orderId);
+        String userPhone = order.getUserPhone();
+        if (userPhone.length()>11){
+            userPhone = decryptPhone(userPhone);
+        }
+        return R.ok().put("userPhone",userPhone);
+    }
+
+    /**
+     * 新增积分商品订单
+     */
+//    @PreAuthorize("@ss.hasPermi('his:integralOrder:add')")
+    @Log(title = "积分商品订单", businessType = BusinessType.INSERT)
+    @PostMapping
+    public R add(@RequestBody FsIntegralOrderCreateParam param)
+    {
+        return fsIntegralOrderService.createOrder(param);
+    }
+
+    /**
+     * 修改积分商品订单
+     */
+//    @PreAuthorize("@ss.hasPermi('his:integralOrder:edit')")
+    @Log(title = "积分商品订单", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsIntegralOrder fsIntegralOrder)
+    {
+        return toAjax(fsIntegralOrderService.updateFsIntegralOrder(fsIntegralOrder));
+    }
+
+    /**
+     * 删除积分商品订单
+     */
+//    @PreAuthorize("@ss.hasPermi('his:integralOrder:remove')")
+    @Log(title = "积分商品订单", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{orderIds}")
+    public AjaxResult remove(@PathVariable Long[] orderIds)
+    {
+        return toAjax(fsIntegralOrderService.deleteFsIntegralOrderByOrderIds(orderIds));
+    }
+}

+ 2 - 2
fs-company/src/main/resources/application.yml

@@ -4,11 +4,11 @@ server:
 spring:
 spring:
   profiles:
   profiles:
 #    active: druid-fcky-test
 #    active: druid-fcky-test
-#    active: dev
+    active: druid-jnmy-test
 #    active: druid-jzzx-test
 #    active: druid-jzzx-test
 #    active: druid-hdt
 #    active: druid-hdt
 #    active: druid-sxjz
 #    active: druid-sxjz
 #    active: druid-yzt
 #    active: druid-yzt
 #    active: druid-myhk
 #    active: druid-myhk
 #    active: druid-sft
 #    active: druid-sft
-    active: dev
+#    active: dev-yjb

+ 1 - 10
fs-doctor-app/src/main/java/com/fs/app/controller/InquiryOrderController.java

@@ -1,29 +1,21 @@
 package com.fs.app.controller;
 package com.fs.app.controller;
 
 
 
 
-import cn.hutool.core.util.IdUtil;
-import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSON;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fs.app.annotation.Login;
 import com.fs.app.annotation.Login;
-import com.fs.app.param.InquiryOrderMsgListParam;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.Log;
-import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
-import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.enums.BusinessType;
-import com.fs.common.utils.SecurityUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.StringUtils;
-import com.fs.common.utils.ip.IpUtils;
 import com.fs.company.service.ICompanyService;
 import com.fs.company.service.ICompanyService;
 import com.fs.core.config.WxPayProperties;
 import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
 import com.fs.core.utils.OrderCodeUtils;
 import com.fs.his.domain.*;
 import com.fs.his.domain.*;
 import com.fs.his.dto.FsInquiryOrderPatientDTO;
 import com.fs.his.dto.FsInquiryOrderPatientDTO;
-import com.fs.his.enums.FsInquiryOrderStatusEnum;
 import com.fs.his.param.*;
 import com.fs.his.param.*;
 import com.fs.his.service.*;
 import com.fs.his.service.*;
 import com.fs.his.vo.*;
 import com.fs.his.vo.*;
@@ -45,7 +37,6 @@ import io.swagger.annotations.ApiOperation;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
@@ -128,7 +119,7 @@ public class InquiryOrderController extends  AppBaseController {
     @GetMapping("/getCompanyList")
     @GetMapping("/getCompanyList")
     public R getCompanyList()
     public R getCompanyList()
     {
     {
-        List<OptionsVO> list = companyService.selectAllCompanyList();
+        List<OptionsVO> list = companyService.selectAllCompanyList(null);
         return R.ok().put("list",list);
         return R.ok().put("list",list);
     }
     }
     @Login
     @Login

+ 39 - 0
fs-doctor-app/src/main/java/com/fs/framework/config/RedisConfig.java

@@ -15,6 +15,8 @@ import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 
 
+import java.math.BigDecimal;
+
 /**
 /**
  * redis配置
  * redis配置
  *
  *
@@ -66,6 +68,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         template.afterPropertiesSet();
         return template;
         return template;
     }
     }
+    @Bean
+    public RedisTemplate<String, Integer> redisTemplateForInteger(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, Integer> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
 
 
     @Bean
     @Bean
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
@@ -92,6 +112,25 @@ public class RedisConfig extends CachingConfigurerSupport
         return template;
         return template;
     }
     }
 
 
+    @Bean
+    public RedisTemplate<String, BigDecimal> redisTemplateForBigDecimal(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, BigDecimal> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
+
     @Bean
     @Bean
     public DefaultRedisScript<Long> limitScript()
     public DefaultRedisScript<Long> limitScript()
     {
     {

+ 25 - 2
fs-framework/src/main/java/com/fs/framework/aspectj/LogAspect.java

@@ -1,6 +1,8 @@
 package com.fs.framework.aspectj;
 package com.fs.framework.aspectj;
 
 
 import java.lang.reflect.Method;
 import java.lang.reflect.Method;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.Collection;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Map;
@@ -11,6 +13,8 @@ import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.bean.BeanUtils;
 import com.fs.common.utils.bean.BeanUtils;
 import com.fs.framework.web.domain.server.Sys;
 import com.fs.framework.web.domain.server.Sys;
 import com.fs.hisStore.domain.SysOperLogScrm;
 import com.fs.hisStore.domain.SysOperLogScrm;
+import com.fs.statis.dto.ProductAuditDTO;
+import com.fs.statis.dto.StoreAuditDTO;
 import org.aspectj.lang.JoinPoint;
 import org.aspectj.lang.JoinPoint;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.Signature;
 import org.aspectj.lang.Signature;
@@ -18,6 +22,7 @@ import org.aspectj.lang.annotation.*;
 import org.aspectj.lang.reflect.MethodSignature;
 import org.aspectj.lang.reflect.MethodSignature;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
 import org.springframework.expression.EvaluationContext;
 import org.springframework.expression.EvaluationContext;
 import org.springframework.expression.ExpressionParser;
 import org.springframework.expression.ExpressionParser;
 import org.springframework.expression.spel.standard.SpelExpressionParser;
 import org.springframework.expression.spel.standard.SpelExpressionParser;
@@ -39,6 +44,8 @@ import com.fs.framework.manager.AsyncManager;
 import com.fs.framework.manager.factory.AsyncFactory;
 import com.fs.framework.manager.factory.AsyncFactory;
 import com.fs.system.domain.SysOperLog;
 import com.fs.system.domain.SysOperLog;
 
 
+import static com.fs.common.utils.SecurityUtils.getUserId;
+
 /**
 /**
  * 操作日志记录处理
  * 操作日志记录处理
  *
  *
@@ -123,9 +130,17 @@ public class LogAspect
             getControllerMethodDescription(joinPoint, controllerLog, operLog);
             getControllerMethodDescription(joinPoint, controllerLog, operLog);
             // 保存数据库
             // 保存数据库
             AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
             AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
-            if(controllerLog.isStoreLog()){
+            if(controllerLog.isStoreLog() ){
                 SysOperLogScrm operLogScrm = new SysOperLogScrm();
                 SysOperLogScrm operLogScrm = new SysOperLogScrm();
+                //插入operId
+                String operId = MDC.get("operIds");
                 BeanUtils.copyProperties(operLog, operLogScrm);
                 BeanUtils.copyProperties(operLog, operLogScrm);
+                Long[] operIds = new Long[operId.split(",").length];
+                String[] operIdStrs = operId.split(",");
+                for (int i = 0; i < operIdStrs.length; i++) {
+                    operIds[i] = Long.parseLong(operIdStrs[i]);
+                }
+                operLogScrm.setOperIds(operIds);
                 resolveParam((ProceedingJoinPoint)joinPoint,operLogScrm);
                 resolveParam((ProceedingJoinPoint)joinPoint,operLogScrm);
                 AsyncManager.me().execute(AsyncFactory.recordOperScrm(operLogScrm));
                 AsyncManager.me().execute(AsyncFactory.recordOperScrm(operLogScrm));
             }
             }
@@ -258,7 +273,7 @@ public class LogAspect
 
 
     private final ExpressionParser parser = new SpelExpressionParser();
     private final ExpressionParser parser = new SpelExpressionParser();
 
 
-    public void resolveParam(ProceedingJoinPoint joinPoint, SysOperLogScrm operLog) throws Throwable {
+    public void resolveParam(ProceedingJoinPoint joinPoint, SysOperLogScrm operLog) {
         // 1. 获取注解实例
         // 1. 获取注解实例
         Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
         Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
         Log annotation = method.getAnnotation(Log.class);
         Log annotation = method.getAnnotation(Log.class);
@@ -300,4 +315,12 @@ public class LogAspect
         operLog.setMainType(logParam[0]);
         operLog.setMainType(logParam[0]);
         operLog.setDes(logParam[1]);
         operLog.setDes(logParam[1]);
     }
     }
+
+
+    @After("logPointCut()")
+    public void after(JoinPoint joinPoint) throws Throwable {
+        // 移除 MDC 中的 logId
+        MDC.remove("operIds");
+    }
+
 }
 }

+ 39 - 0
fs-framework/src/main/java/com/fs/framework/config/RedisConfig.java

@@ -15,6 +15,8 @@ import com.fasterxml.jackson.annotation.PropertyAccessor;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
 import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
 
 
+import java.math.BigDecimal;
+
 /**
 /**
  * redis配置
  * redis配置
  *
  *
@@ -66,6 +68,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         template.afterPropertiesSet();
         return template;
         return template;
     }
     }
+    @Bean
+    public RedisTemplate<String, Integer> redisTemplateForInteger(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, Integer> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
 
 
     @Bean
     @Bean
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
@@ -92,6 +112,25 @@ public class RedisConfig extends CachingConfigurerSupport
         return template;
         return template;
     }
     }
 
 
+    @Bean
+    public RedisTemplate<String, BigDecimal> redisTemplateForBigDecimal(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, BigDecimal> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
+
     @Bean
     @Bean
     public DefaultRedisScript<Long> limitScript()
     public DefaultRedisScript<Long> limitScript()
     {
     {

+ 7 - 1
fs-framework/src/main/java/com/fs/framework/manager/factory/AsyncFactory.java

@@ -118,8 +118,14 @@ public class AsyncFactory
             {
             {
                 // 远程查询操作地点
                 // 远程查询操作地点
                 operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
                 operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
-                SpringUtils.getBean(ISysOperLogScrmService.class).insertOperlog(operLog);
+                SpringUtils.getBean(ISysOperLogScrmService.class).updateOperLog(operLog);
             }
             }
         };
         };
     }
     }
+
+    /**
+     * 生成日志记录
+     * */
+
+
 }
 }

+ 38 - 0
fs-hospital/src/main/java/com/fs/framework/config/RedisConfig.java

@@ -16,6 +16,8 @@ import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 
 
+import java.math.BigDecimal;
+
 /**
 /**
  * redis配置
  * redis配置
  *
  *
@@ -67,7 +69,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         template.afterPropertiesSet();
         return template;
         return template;
     }
     }
+    @Bean
+    public RedisTemplate<String, Integer> redisTemplateForInteger(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, Integer> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(Integer.class));
 
 
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
     @Bean
     @Bean
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {
@@ -93,6 +112,25 @@ public class RedisConfig extends CachingConfigurerSupport
         return template;
         return template;
     }
     }
 
 
+    @Bean
+    public RedisTemplate<String, BigDecimal> redisTemplateForBigDecimal(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, BigDecimal> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
+
     @Bean
     @Bean
     public DefaultRedisScript<Long> limitScript()
     public DefaultRedisScript<Long> limitScript()
     {
     {

+ 26 - 6
fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java

@@ -1,9 +1,12 @@
 package com.fs.app.service;
 package com.fs.app.service;
 
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.common.exception.base.BaseException;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.date.DateUtil;
 import com.fs.common.utils.date.DateUtil;
-import com.fs.course.config.CourseMaConfig;
+import com.fs.company.domain.CompanyMiniapp;
+import com.fs.company.service.ICompanyMiniappService;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.domain.FsCourseWatchLog;
 import com.fs.course.domain.FsCourseWatchLog;
 import com.fs.course.service.IFsCourseWatchLogService;
 import com.fs.course.service.IFsCourseWatchLogService;
@@ -15,7 +18,6 @@ import com.fs.qw.mapper.QwExternalContactMapper;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.service.IQwUserService;
 import com.fs.qw.service.IQwUserService;
 import com.fs.qw.service.IQwUserVideoService;
 import com.fs.qw.service.IQwUserVideoService;
-import com.fs.qw.service.impl.QwUserServiceImpl;
 import com.fs.qw.vo.QwSopCourseFinishTempSetting;
 import com.fs.qw.vo.QwSopCourseFinishTempSetting;
 import com.fs.qwApi.param.QwExternalContactHParam;
 import com.fs.qwApi.param.QwExternalContactHParam;
 import com.fs.sop.domain.QwSopLogs;
 import com.fs.sop.domain.QwSopLogs;
@@ -27,6 +29,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
 import java.time.LocalDateTime;
 import java.time.LocalDateTime;
+import java.util.List;
 import java.util.Map;
 import java.util.Map;
 
 
 @Slf4j
 @Slf4j
@@ -42,9 +45,26 @@ public class IpadSendServer {
     private final IFsCourseWatchLogService watchLogService;
     private final IFsCourseWatchLogService watchLogService;
     private final IQwUserVideoService qwUserVideoService;
     private final IQwUserVideoService qwUserVideoService;
     private final RedisCache redisCache;
     private final RedisCache redisCache;
+    private final ICompanyMiniappService companyMiniappService;
 
 
-    private void sendMiniProgram(BaseVo vo, QwSopCourseFinishTempSetting.Setting content, Map<String, FsCoursePlaySourceConfig> miniMap) {
-        FsCoursePlaySourceConfig courseMaConfig = miniMap.get(content.getMiniprogramAppid());
+    private void sendMiniProgram(BaseVo vo, QwSopCourseFinishTempSetting.Setting content, Map<String, FsCoursePlaySourceConfig> miniMap, Long companyId) {
+        String appid = content.getMiniprogramAppid();
+        if(companyId != null && content.getMiniType() != null){
+            List<CompanyMiniapp> list = companyMiniappService.list(new QueryWrapper<CompanyMiniapp>().eq("company_id", companyId).eq("type", content.getMiniType()));
+            if(!list.isEmpty() && list.get(0) != null && StringUtils.isNotEmpty(list.get(0).getAppId())){
+                appid = list.get(0).getAppId();
+            }
+        }
+        FsCoursePlaySourceConfig courseMaConfig = miniMap.get(appid);
+        if(courseMaConfig == null){
+            List<CompanyMiniapp> list = companyMiniappService.list(new QueryWrapper<CompanyMiniapp>().eq("company_id", companyId).eq("type", 1));
+            if(!list.isEmpty() && list.get(0) != null && StringUtils.isNotEmpty(list.get(0).getAppId())){
+                courseMaConfig = miniMap.get(list.get(0).getAppId());
+            }
+        }
+        if(courseMaConfig == null){
+            throw new BaseException("未找到小程序配置:{}", appid);
+        }
         // 小程序
         // 小程序
         MiniProgramVo miniProgramVo = MiniProgramVo.builder()
         MiniProgramVo miniProgramVo = MiniProgramVo.builder()
                 .desc(content.getMiniprogramTitle())
                 .desc(content.getMiniprogramTitle())
@@ -53,7 +73,7 @@ public class IpadSendServer {
                 .imgUrl(content.getMiniprogramPicUrl())
                 .imgUrl(content.getMiniprogramPicUrl())
                 .username(courseMaConfig.getOriginalId() + "@app")
                 .username(courseMaConfig.getOriginalId() + "@app")
                 .pagepath(content.getMiniprogramPage())
                 .pagepath(content.getMiniprogramPage())
-                .appid(content.getMiniprogramAppid())
+                .appid(courseMaConfig.getAppid())
                 .build();
                 .build();
         miniProgramVo.setBase(vo);
         miniProgramVo.setBase(vo);
         WxWorkResponseDTO<WxWorkSendAppMsgRespDTO> resp = ipadSendUtils.sendMiniProgram(miniProgramVo);
         WxWorkResponseDTO<WxWorkSendAppMsgRespDTO> resp = ipadSendUtils.sendMiniProgram(miniProgramVo);
@@ -337,7 +357,7 @@ public class IpadSendServer {
                     break;
                     break;
                 case "4":
                 case "4":
                 case "10":
                 case "10":
-                    sendMiniProgram(vo, content, miniMap);
+                    sendMiniProgram(vo, content, miniMap, qwUser.getCompanyId());
                     break;
                     break;
                 case "5":
                 case "5":
                     // 文件
                     // 文件

+ 69 - 20
fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java

@@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.fs.app.service.IpadSendServer;
 import com.fs.app.service.IpadSendServer;
 import com.fs.common.core.redis.RedisCacheT;
 import com.fs.common.core.redis.RedisCacheT;
+import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.PubFun;
 import com.fs.common.utils.PubFun;
 import com.fs.company.service.ICompanyMiniappService;
 import com.fs.company.service.ICompanyMiniappService;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.config.CourseConfig;
@@ -12,8 +13,12 @@ import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.service.IFsCoursePlaySourceConfigService;
 import com.fs.course.service.IFsCoursePlaySourceConfigService;
 import com.fs.ipad.vo.BaseVo;
 import com.fs.ipad.vo.BaseVo;
 import com.fs.qw.domain.QwIpadServer;
 import com.fs.qw.domain.QwIpadServer;
+import com.fs.qw.domain.QwPushCount;
+import com.fs.qw.domain.QwRestrictionPushRecord;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwIpadServerMapper;
 import com.fs.qw.mapper.QwIpadServerMapper;
+import com.fs.qw.mapper.QwPushCountMapper;
+import com.fs.qw.mapper.QwRestrictionPushRecordMapper;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.service.impl.AsyncSopTestService;
 import com.fs.qw.service.impl.AsyncSopTestService;
 import com.fs.qw.vo.QwSopCourseFinishTempSetting;
 import com.fs.qw.vo.QwSopCourseFinishTempSetting;
@@ -55,6 +60,8 @@ public class SendMsg {
     private final AsyncSopTestService asyncSopTestService;
     private final AsyncSopTestService asyncSopTestService;
     private final ICompanyMiniappService companyMiniappService;
     private final ICompanyMiniappService companyMiniappService;
     private final IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService;
     private final IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService;
+    private final QwPushCountMapper qwPushCountMapper;
+    private final QwRestrictionPushRecordMapper qwRestrictionPushRecordMapper;
 
 
     @Value("${group-no}")
     @Value("${group-no}")
     private String groupNo;
     private String groupNo;
@@ -65,7 +72,7 @@ public class SendMsg {
     @Qualifier("customThreadPool")
     @Qualifier("customThreadPool")
     private ThreadPoolTaskExecutor customThreadPool;
     private ThreadPoolTaskExecutor customThreadPool;
 
 
-    public SendMsg(QwUserMapper qwUserMapper, QwSopLogsMapper qwSopLogsMapper, IpadSendServer sendServer, SysConfigMapper sysConfigMapper, IQwSopLogsService qwSopLogsService, QwIpadServerMapper qwIpadServerMapper, RedisCacheT<Long> redisCache, AsyncSopTestService asyncSopTestService, ICompanyMiniappService companyMiniappService, IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService) {
+    public SendMsg(QwUserMapper qwUserMapper, QwSopLogsMapper qwSopLogsMapper, IpadSendServer sendServer, SysConfigMapper sysConfigMapper, IQwSopLogsService qwSopLogsService, QwIpadServerMapper qwIpadServerMapper, RedisCacheT<Long> redisCache, AsyncSopTestService asyncSopTestService, ICompanyMiniappService companyMiniappService, IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService, QwPushCountMapper qwPushCountMapper, QwRestrictionPushRecordMapper qwRestrictionPushRecordMapper) {
         this.qwUserMapper = qwUserMapper;
         this.qwUserMapper = qwUserMapper;
         this.qwSopLogsMapper = qwSopLogsMapper;
         this.qwSopLogsMapper = qwSopLogsMapper;
         this.sendServer = sendServer;
         this.sendServer = sendServer;
@@ -76,6 +83,8 @@ public class SendMsg {
         this.asyncSopTestService = asyncSopTestService;
         this.asyncSopTestService = asyncSopTestService;
         this.companyMiniappService = companyMiniappService;
         this.companyMiniappService = companyMiniappService;
         this.fsCoursePlaySourceConfigService = fsCoursePlaySourceConfigService;
         this.fsCoursePlaySourceConfigService = fsCoursePlaySourceConfigService;
+        this.qwPushCountMapper = qwPushCountMapper;
+        this.qwRestrictionPushRecordMapper = qwRestrictionPushRecordMapper;
     }
     }
     private List<QwUser> getQwUserList() {
     private List<QwUser> getQwUserList() {
         if (qwUserList.isEmpty()) {
         if (qwUserList.isEmpty()) {
@@ -92,8 +101,8 @@ public class SendMsg {
 
 
     private Map<String, FsCoursePlaySourceConfig> getMiniMap() {
     private Map<String, FsCoursePlaySourceConfig> getMiniMap() {
         List<FsCoursePlaySourceConfig> list = fsCoursePlaySourceConfigService.list(new QueryWrapper<FsCoursePlaySourceConfig>().ne("type", 2).eq("is_del", 0));
         List<FsCoursePlaySourceConfig> list = fsCoursePlaySourceConfigService.list(new QueryWrapper<FsCoursePlaySourceConfig>().ne("type", 2).eq("is_del", 0));
-//        SysConfig maConfig = sysConfigMapper.selectConfigByConfigKey("courseMa.config");
-//        List<CourseMaConfig> courseMaConfigs = JSON.parseArray(maConfig.getConfigValue(), CourseMaConfig.class);
+//        log.info("获取到的小程序配置:{}", JSON.toJSONString(list));
+//        log.info("获取到的小程序配置:{}", JSON.toJSONString(list));
         return PubFun.listToMapByGroupObject(list, FsCoursePlaySourceConfig::getAppid);
         return PubFun.listToMapByGroupObject(list, FsCoursePlaySourceConfig::getAppid);
     }
     }
 
 
@@ -191,27 +200,67 @@ public class SendMsg {
                 continue;
                 continue;
             }
             }
             redisCache.setCacheObject(key, System.currentTimeMillis(), 24, TimeUnit.HOURS);
             redisCache.setCacheObject(key, System.currentTimeMillis(), 24, TimeUnit.HOURS);
+            List<QwPushCount> pushCountList = qwPushCountMapper.selectQwPushCountLists();
+            Map<Integer, List<QwPushCount>> pushMap = pushCountList.stream().collect(Collectors.groupingBy(QwPushCount::getType));
             // 循环发送消息里面的每一条消息
             // 循环发送消息里面的每一条消息
             for (QwSopCourseFinishTempSetting.Setting content : setting.getSetting()) {
             for (QwSopCourseFinishTempSetting.Setting content : setting.getSetting()) {
                 long start4 = System.currentTimeMillis();
                 long start4 = System.currentTimeMillis();
-                // 发送
-                sendServer.send(content, user, qwSopLogs, miniMap, parentVo);
-                long end4 = System.currentTimeMillis();
-                log.info("请求pad发送完成:{}, {}, 时长4:{}", user.getQwUserName(), qwSopLogs.getId(), end4 - start4);
-                if(content.getSendStatus() == 2 && ("请求失败:消息发送过于频繁,请稍后再试".equals(content.getSendRemarks()) || "请求失败:请求频率异常".equals(content.getSendRemarks()))){
-                    QwUser update = new QwUser();
-                    update.setRemark("请求频率异常,暂停发送,三小时后恢复继续发送");
-                    update.setUpdateTime(new Date());
-                    qwUserMapper.update(update, new QueryWrapper<QwUser>().eq("id", user.getId()));
-                    redisCache.setCacheObject("qw:user:id:" + user.getId(), user.getId(), 3, TimeUnit.HOURS);
-                    return;
+                //判断当前销售推送客户消息限制
+                Long qwUserId = qwUser.getId();//销售的Id
+                Integer type = Integer.valueOf(content.getContentType());//发送消息的类型
+                Long customerId = qwSopLogs.getExternalId();//客户ID
+                Long companyId = qwSopLogs.getCompanyId();//公司ID
+                Integer pushCount = -99;
+                if(pushMap.containsKey(type)){
+                    List<QwPushCount> qwPushCounts = pushMap.get(type);
+                    Optional<QwPushCount> optional = qwPushCounts.stream().filter(e -> Objects.equals(e.getCompanyId(), companyId)).findFirst();
+                    if(optional.isPresent()){
+                        pushCount = optional.get().getPushCount();
+                    }else{
+                        Optional<QwPushCount> nullCount = qwPushCounts.stream().filter(e -> e.getCompanyId() == null).findFirst();
+                        if(nullCount.isPresent()){
+                            pushCount = nullCount.get().getPushCount();
+                        }
+                    }
                 }
                 }
-                try {
-                    int delay = ThreadLocalRandom.current().nextInt(300, 1000);
-                    log.debug("pad发送消息等待:{}ms", delay);
-                    Thread.sleep(delay);
-                } catch (InterruptedException e) {
-                    log.error("线程等待错误!");
+                //查询是否有设置限制客服推送消息次数
+//                    Integer pushCount=pushCountMap.containsKey(String.valueOf(companyId)) ? pushCountMap.get(String.valueOf(companyId)): pushCountMap.getOrDefault(String.valueOf(type), -99);
+                int salesPushCustomerMessageCount = qwRestrictionPushRecordMapper.selectQwRestrictionPushRecord(qwUserId, customerId, type, DateUtils.toStartTime(), DateUtils.toEndTime());
+                if (pushCount != -99 && salesPushCustomerMessageCount >= pushCount) {
+                    content.setSendStatus(2);//设置发送失败状态
+                    content.setSendRemarks("发送次数达到上限");
+                } else {
+                    // 发送
+                    sendServer.send(content, user, qwSopLogs, miniMap, parentVo);
+                    //判断销售推送成功:保存记录
+                    if (content.getSendStatus() != 2) {
+                        QwRestrictionPushRecord qrpr = new QwRestrictionPushRecord();
+                        qrpr.setType(type);
+                        qrpr.setQwUserId(qwUserId);
+                        qrpr.setQwExternalId(customerId);
+                        qrpr.setCompanyId(companyId);
+                        qrpr.setStatus(1);
+                        qrpr.setCreateTime(DateUtils.getTime());
+                        qrpr.setTime(System.currentTimeMillis());
+                        qwRestrictionPushRecordMapper.insert(qrpr);
+                    }
+                    long end4 = System.currentTimeMillis();
+                    log.info("请求pad发送完成:{}, {}, 时长4:{}", user.getQwUserName(), qwSopLogs.getId(), end4 - start4);
+                    if(content.getSendStatus() == 2 && ("请求失败:消息发送过于频繁,请稍后再试".equals(content.getSendRemarks()) || "请求失败:请求频率异常".equals(content.getSendRemarks()))){
+                        QwUser update = new QwUser();
+                        update.setRemark("请求频率异常,暂停发送,三小时后恢复继续发送");
+                        update.setUpdateTime(new Date());
+                        qwUserMapper.update(update, new QueryWrapper<QwUser>().eq("id", user.getId()));
+                        redisCache.setCacheObject("qw:user:id:" + user.getId(), user.getId(), 3, TimeUnit.HOURS);
+                        return;
+                    }
+                    try {
+                        int delay = ThreadLocalRandom.current().nextInt(300, 1000);
+                        log.debug("pad发送消息等待:{}ms", delay);
+                        Thread.sleep(delay);
+                    } catch (InterruptedException e) {
+                        log.error("线程等待错误!");
+                    }
                 }
                 }
             }
             }
             // 推送 APP
             // 推送 APP

+ 40 - 0
fs-ipad-task/src/main/java/com/fs/framework/config/RedisConfig.java

@@ -15,6 +15,8 @@ import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 
 
+import java.math.BigDecimal;
+
 /**
 /**
  * redis配置
  * redis配置
  *
  *
@@ -66,6 +68,24 @@ public class RedisConfig extends CachingConfigurerSupport
         return template;
         return template;
     }
     }
 
 
+    @Bean
+    public RedisTemplate<String, Integer> redisTemplateForInteger(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, Integer> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
     @Bean
     @Bean
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {
@@ -91,6 +111,26 @@ public class RedisConfig extends CachingConfigurerSupport
         return template;
         return template;
     }
     }
 
 
+    @Bean
+    public RedisTemplate<String, BigDecimal> redisTemplateForBigDecimal(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, BigDecimal> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
+
+
     @Bean
     @Bean
     public DefaultRedisScript<Long> limitScript()
     public DefaultRedisScript<Long> limitScript()
     {
     {

+ 38 - 0
fs-live-app/src/main/java/com/fs/framework/config/RedisConfig.java

@@ -15,6 +15,8 @@ import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 
 
+import java.math.BigDecimal;
+
 /**
 /**
  * redis配置
  * redis配置
  *
  *
@@ -65,6 +67,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         template.afterPropertiesSet();
         return template;
         return template;
     }
     }
+    @Bean
+    public RedisTemplate<String, Integer> redisTemplateForInteger(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, Integer> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
 
 
     @Bean
     @Bean
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
@@ -91,6 +111,24 @@ public class RedisConfig extends CachingConfigurerSupport
         return template;
         return template;
     }
     }
 
 
+    @Bean
+    public RedisTemplate<String, BigDecimal> redisTemplateForBigDecimal(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, BigDecimal> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
     @Bean
     @Bean
     public DefaultRedisScript<Long> limitScript()
     public DefaultRedisScript<Long> limitScript()
     {
     {

+ 38 - 37
fs-qw-api-msg/src/main/java/com/fs/app/controller/QwMsgController.java

@@ -206,43 +206,43 @@ public class QwMsgController {
         }
         }
         switch (type){
         switch (type){
             case 100001:
             case 100001:
-                System.out.println("扫码返回");
+                log.info("id:{}, 扫码返回", id);
                 break;
                 break;
             case 100002:
             case 100002:
-                System.out.println("取消扫码");
+                log.info("id:{}, 取消扫码", id);
               //  redisCache.setCacheObject("qrCodeUid:"+wxWorkMsgResp.getUuid(),100002,10, TimeUnit.MINUTES);
               //  redisCache.setCacheObject("qrCodeUid:"+wxWorkMsgResp.getUuid(),100002,10, TimeUnit.MINUTES);
                 break;
                 break;
             case 100003:
             case 100003:
-                System.out.println("确认扫码返回");
+                log.info("id:{}, 确认扫码返回", id);
 
 
                 break;
                 break;
             case 104001:
             case 104001:
-                System.out.println("登录成功");
+                log.info("id:{}, 登录成功", id);
 
 
                 JSONObject jsonObject = new JSONObject(wxWorkMsgResp.getJson());
                 JSONObject jsonObject = new JSONObject(wxWorkMsgResp.getJson());
                 QwUser qu = qwUserMapper.selectQwUserById(id);
                 QwUser qu = qwUserMapper.selectQwUserById(id);
                 Long corpId = jsonObject.getLong("Corpid");
                 Long corpId = jsonObject.getLong("Corpid");
-                System.out.println("回调中的"+corpId);
+                log.info("id:{}, 回调中的"+corpId, id);
                 String sCorpId = wxWorkService.getCorpId(wxWorkMsgResp.getUuid(), corpId,serverId);
                 String sCorpId = wxWorkService.getCorpId(wxWorkMsgResp.getUuid(), corpId,serverId);
                 if (sCorpId==null&& sCorpId.isEmpty()){
                 if (sCorpId==null&& sCorpId.isEmpty()){
                     break;
                     break;
                 }
                 }
                 if (!qu.getCorpId().equals(sCorpId)){
                 if (!qu.getCorpId().equals(sCorpId)){
                     redisCache.setCacheObject("qrCodeUid:"+wxWorkMsgResp.getUuid(),22,10, TimeUnit.MINUTES);
                     redisCache.setCacheObject("qrCodeUid:"+wxWorkMsgResp.getUuid(),22,10, TimeUnit.MINUTES);
-                    System.out.println("公司不匹配不给登录");
+                    log.info("id:{}, 公司不匹配不给登录", id);
                     WxWorkGetQrCodeDTO wxWorkGetQrCodeDTO = new WxWorkGetQrCodeDTO();
                     WxWorkGetQrCodeDTO wxWorkGetQrCodeDTO = new WxWorkGetQrCodeDTO();
                     wxWorkGetQrCodeDTO.setUuid(wxWorkMsgResp.getUuid());
                     wxWorkGetQrCodeDTO.setUuid(wxWorkMsgResp.getUuid());
                     wxWorkService.LoginOut(wxWorkGetQrCodeDTO,serverId);
                     wxWorkService.LoginOut(wxWorkGetQrCodeDTO,serverId);
-                    log.info("调用退出登录");
+                    log.info("id:{}, 调用退出登录", id);
                     break;
                     break;
                 }
                 }
                 if (!qu.getQwUserId().equals(jsonObject.get("acctid"))){
                 if (!qu.getQwUserId().equals(jsonObject.get("acctid"))){
                     redisCache.setCacheObject("qrCodeUid:"+wxWorkMsgResp.getUuid(),23,10, TimeUnit.MINUTES);
                     redisCache.setCacheObject("qrCodeUid:"+wxWorkMsgResp.getUuid(),23,10, TimeUnit.MINUTES);
-                    System.out.println("账号不匹配不给登录");
+                    log.info("id:{}, 账号不匹配不给登录", id);
                     WxWorkGetQrCodeDTO wxWorkGetQrCodeDTO = new WxWorkGetQrCodeDTO();
                     WxWorkGetQrCodeDTO wxWorkGetQrCodeDTO = new WxWorkGetQrCodeDTO();
                     wxWorkGetQrCodeDTO.setUuid(wxWorkMsgResp.getUuid());
                     wxWorkGetQrCodeDTO.setUuid(wxWorkMsgResp.getUuid());
                     wxWorkService.LoginOut(wxWorkGetQrCodeDTO,serverId);
                     wxWorkService.LoginOut(wxWorkGetQrCodeDTO,serverId);
-                    log.info("调用退出登录");
+                    log.info("id:{}, 调用退出登录", id);
                     break;
                     break;
                 }
                 }
                 QwUser qwUser = new QwUser();
                 QwUser qwUser = new QwUser();
@@ -250,44 +250,44 @@ public class QwMsgController {
                 qwUser.setVid(jsonObject.get("Vid").toString());
                 qwUser.setVid(jsonObject.get("Vid").toString());
                 qwUser.setIpadStatus(1);
                 qwUser.setIpadStatus(1);
                 qwUserMapper.updateQwUser(qwUser);
                 qwUserMapper.updateQwUser(qwUser);
-                System.out.println("存Vid");
+                log.info("id:{}, 存Vid", id);
                 redisCache.setCacheObject("qrCodeUid:"+wxWorkMsgResp.getUuid(),104001,10, TimeUnit.MINUTES);
                 redisCache.setCacheObject("qrCodeUid:"+wxWorkMsgResp.getUuid(),104001,10, TimeUnit.MINUTES);
                 break;
                 break;
             case 100006:
             case 100006:
 
 
                 break;
                 break;
             case 100004:
             case 100004:
-                System.out.println("需要验证二维码消息");
+                log.info("id:{}, 需要验证二维码消息", id);
                 redisCache.setCacheObject("qrCodeUid:"+wxWorkMsgResp.getUuid(),100004,10, TimeUnit.MINUTES);
                 redisCache.setCacheObject("qrCodeUid:"+wxWorkMsgResp.getUuid(),100004,10, TimeUnit.MINUTES);
                 break;
                 break;
             case 100012:
             case 100012:
-                log.info("需要二次验证:"+wxWorkMsgResp.getJson());
+                log.info("id:{}, 需要二次验证:"+wxWorkMsgResp.getJson(), id);
 
 
                 redisCache.setCacheObject("qrCodeUid:"+wxWorkMsgResp.getUuid(),100012,10, TimeUnit.MINUTES);
                 redisCache.setCacheObject("qrCodeUid:"+wxWorkMsgResp.getUuid(),100012,10, TimeUnit.MINUTES);
 
 
                 break;
                 break;
             case 100005:
             case 100005:
 
 
-                log.info("手机端结束登录:"+wxWorkMsgResp.getJson());
+                log.info("id:{}, 手机端结束登录:"+wxWorkMsgResp.getJson(), id);
                 JSONObject jsonObject1 = new JSONObject(wxWorkMsgResp.getJson());
                 JSONObject jsonObject1 = new JSONObject(wxWorkMsgResp.getJson());
                 qwUserStatus(wxWorkMsgResp.getUuid(),0, jsonObject1.getString("msg"));
                 qwUserStatus(wxWorkMsgResp.getUuid(),0, jsonObject1.getString("msg"));
                 break;
                 break;
             case 100008:
             case 100008:
                 QwUser vidUser = qwUserMapper.selectQwUserById(id);
                 QwUser vidUser = qwUserMapper.selectQwUserById(id);
                 if (vidUser.getUid().equals(wxWorkMsgResp.getUuid())){
                 if (vidUser.getUid().equals(wxWorkMsgResp.getUuid())){
-                    log.info("当前账号在其他设备登录:"+wxWorkMsgResp.getJson());
+                    log.info("id:{}, 当前账号在其他设备登录:"+wxWorkMsgResp.getJson(), id);
                     JSONObject jsonObject2 = new JSONObject(wxWorkMsgResp.getJson());
                     JSONObject jsonObject2 = new JSONObject(wxWorkMsgResp.getJson());
                     qwUserStatus(wxWorkMsgResp.getUuid(),0, jsonObject2.getString("msg"));
                     qwUserStatus(wxWorkMsgResp.getUuid(),0, jsonObject2.getString("msg"));
                 }
                 }
-                log.info("当前账号重新登录:"+wxWorkMsgResp.getJson());
+                log.info("id:{}, 当前账号重新登录:"+wxWorkMsgResp.getJson(), id);
                 break;
                 break;
             case 100007:
             case 100007:
-                log.info("异常断开:"+wxWorkMsgResp.getJson());
+                log.info("id:{}, 异常断开:"+wxWorkMsgResp.getJson(), id);
                 JSONObject jsonObject3 = new JSONObject(wxWorkMsgResp.getJson());
                 JSONObject jsonObject3 = new JSONObject(wxWorkMsgResp.getJson());
                 qwUserStatus(wxWorkMsgResp.getUuid(),0, "异常断开 - " + jsonObject3.getString("msg"));
                 qwUserStatus(wxWorkMsgResp.getUuid(),0, "异常断开 - " + jsonObject3.getString("msg"));
                 break;
                 break;
             case 100009:
             case 100009:
-                log.info("二次验证:"+wxWorkMsgResp.getJson());
+                log.info("id:{}, 二次验证:"+wxWorkMsgResp.getJson(), id);
                 JSONObject jsonObject4 = new JSONObject(wxWorkMsgResp.getJson());
                 JSONObject jsonObject4 = new JSONObject(wxWorkMsgResp.getJson());
                 qwUserStatus(wxWorkMsgResp.getUuid(),0, "二次验证 - " + jsonObject4.getString("msg"));
                 qwUserStatus(wxWorkMsgResp.getUuid(),0, "二次验证 - " + jsonObject4.getString("msg"));
                 break;
                 break;
@@ -307,9 +307,9 @@ public class QwMsgController {
                 if (wxWorkMessageDTO.getMsgtype()==2||wxWorkMessageDTO.getMsgtype()==0||wxWorkMessageDTO.getMsgtype()==16||wxWorkMessageDTO.getMsgtype() == 101||wxWorkMessageDTO.getMsgtype() == 104){
                 if (wxWorkMessageDTO.getMsgtype()==2||wxWorkMessageDTO.getMsgtype()==0||wxWorkMessageDTO.getMsgtype()==16||wxWorkMessageDTO.getMsgtype() == 101||wxWorkMessageDTO.getMsgtype() == 104){
 
 
                     String content = wxWorkMessageDTO.getContent();
                     String content = wxWorkMessageDTO.getContent();
-                    System.out.println("接收人:"+wxWorkMessageDTO.getReceiver());
-                    System.out.println("发送人:"+wxWorkMessageDTO.getSender());
-                    System.out.println("内容:"+content);
+                    log.info("id:{}, 接收人:"+wxWorkMessageDTO.getReceiver(), id);
+                    log.info("id:{}, 发送人:"+wxWorkMessageDTO.getSender(), id);
+                    log.info("id:{}, 内容:"+content, id);
                     Long receiver = wxWorkMessageDTO.getReceiver();
                     Long receiver = wxWorkMessageDTO.getReceiver();
                     Long sender = wxWorkMessageDTO.getSender();
                     Long sender = wxWorkMessageDTO.getSender();
                     if(wxWorkMessageDTO.getMsgtype()==16){
                     if(wxWorkMessageDTO.getMsgtype()==16){
@@ -323,32 +323,32 @@ public class QwMsgController {
                                 TimeUnit.SECONDS.sleep(1); // 阻塞1秒
                                 TimeUnit.SECONDS.sleep(1); // 阻塞1秒
                             } catch (InterruptedException e) {
                             } catch (InterruptedException e) {
                                 Thread.currentThread().interrupt(); // 处理中断异常
                                 Thread.currentThread().interrupt(); // 处理中断异常
-                                System.out.println("第一次语音转换失败");
+                                log.info("id:{}, 第一次语音转换失败", id);
                             }
                             }
                             dto = wxWorkService.SpeechToTextEntity(ste, serverId);
                             dto = wxWorkService.SpeechToTextEntity(ste, serverId);
                         }
                         }
                         WxwSpeechToTextEntityRespDTO data = dto.getData();
                         WxwSpeechToTextEntityRespDTO data = dto.getData();
                         content = data.getText();
                         content = data.getText();
-                        System.out.println("语音消息"+content);
                         if(content == null || content.isEmpty()){
                         if(content == null || content.isEmpty()){
                             content = "==语音转换失败==";
                             content = "==语音转换失败==";
                         }
                         }
+                        log.info("id:{}, 语音消息"+content, id);
                     }
                     }
                     else if (wxWorkMessageDTO.getMsgtype() == 101){
                     else if (wxWorkMessageDTO.getMsgtype() == 101){
                         content = processImageMessage(serverId, wxWorkMessageDTO, wxWorkMsgResp);
                         content = processImageMessage(serverId, wxWorkMessageDTO, wxWorkMsgResp);
-                        System.out.println("用户发送图片"+content);
+                        log.info("id:{}, 用户发送图片"+content, id);
                     }
                     }
                     // gif 表情消息
                     // gif 表情消息
                     else if (wxWorkMessageDTO.getMsgtype() == 104){
                     else if (wxWorkMessageDTO.getMsgtype() == 104){
                         content = wxWorkMessageDTO.getUrl();
                         content = wxWorkMessageDTO.getUrl();
-                        System.out.println("用户发送表情"+content);
+                        log.info("id:{}, 用户发送表情"+content, id);
                     }
                     }
 
 
                     if (2000000000000000L-receiver>0){
                     if (2000000000000000L-receiver>0){
-                        System.out.println("客户发送");
+                        log.info("id:{}, 客户发送", id);
                         aiHookService.qwHookNotifyAiReply(id,sender,content,wxWorkMsgResp.getUuid(),wxWorkMessageDTO.getMsgtype());
                         aiHookService.qwHookNotifyAiReply(id,sender,content,wxWorkMsgResp.getUuid(),wxWorkMessageDTO.getMsgtype());
                     }else {
                     }else {
-                        System.out.println("销售发送");
+                        log.info("id:{}, 销售发送", id);
                         aiHookService.qwHookNotifyAddMsg(id,receiver,content,wxWorkMsgResp.getUuid());
                         aiHookService.qwHookNotifyAddMsg(id,receiver,content,wxWorkMsgResp.getUuid());
                     }
                     }
 
 
@@ -360,12 +360,12 @@ public class QwMsgController {
                     }
                     }
                     Long receiver = wxWorkMessageDTO.getReceiver();
                     Long receiver = wxWorkMessageDTO.getReceiver();
                     Long extId=null;
                     Long extId=null;
-                    Long totalSeconds=null;
+                    long totalSeconds=0L;
                     if (2000000000000000L-receiver>0){
                     if (2000000000000000L-receiver>0){
                          extId = wxWorkMessageDTO.getSender();
                          extId = wxWorkMessageDTO.getSender();
-                        System.out.println("客户发起");
+                        log.info("id:{}, 客户发起", id);
                     }else {
                     }else {
-                        System.out.println("销售发起");
+                        log.info("id:{}, 销售发起", id);
                         extId = wxWorkMessageDTO.getReceiver();
                         extId = wxWorkMessageDTO.getReceiver();
                     }
                     }
                     Integer recordType = wxWorkMessageDTO.getRecordtype();
                     Integer recordType = wxWorkMessageDTO.getRecordtype();
@@ -392,11 +392,11 @@ public class QwMsgController {
                                     seconds = Integer.parseInt(matcher.group(2));
                                     seconds = Integer.parseInt(matcher.group(2));
                                 }
                                 }
                                 totalSeconds = hours * 3600L + minutes * 60L + seconds;
                                 totalSeconds = hours * 3600L + minutes * 60L + seconds;
-                                System.out.println("总通话秒数: " + totalSeconds);
+                                log.info("id:{}, 总通话秒数: " + totalSeconds, id);
                             }
                             }
                         }
                         }
                     } else if (recordType==2){
                     } else if (recordType==2){
-                        System.out.println("通话挂断");
+                        log.info("id:{}, 通话挂断", id);
                     }else {
                     }else {
                         break;
                         break;
                     }
                     }
@@ -425,15 +425,15 @@ public class QwMsgController {
         QwUser user = qwUserMapper.selectQwUserById(qwUserId);
         QwUser user = qwUserMapper.selectQwUserById(qwUserId);
         //查询接收人
         //查询接收人
         if(user==null){
         if(user==null){
-            System.out.println("查询接收人为空");
+            log.info("查询接收人为空");
         }
         }
         if(user.getFastGptRoleId()==null){
         if(user.getFastGptRoleId()==null){
-            System.out.println("未绑定角色");
+            log.info("未绑定角色");
         }
         }
         Long serverId = user.getServerId();
         Long serverId = user.getServerId();
-        System.out.println("服务器id"+serverId);
+        log.info("服务器id"+serverId);
         if (serverId == null) {
         if (serverId == null) {
-            System.out.println("服务id为空");
+            log.info("服务id为空");
         }
         }
 
 
         WxWorkVid2UserIdDTO wxWorkVid2UserIdDTO = new WxWorkVid2UserIdDTO();
         WxWorkVid2UserIdDTO wxWorkVid2UserIdDTO = new WxWorkVid2UserIdDTO();
@@ -444,13 +444,13 @@ public class QwMsgController {
         List<WxWorkVid2UserIdRespDTO> data = WxWorkVid2UserIdRespDTO.getData();
         List<WxWorkVid2UserIdRespDTO> data = WxWorkVid2UserIdRespDTO.getData();
         if (data==null|| data.isEmpty()){
         if (data==null|| data.isEmpty()){
 
 
-            System.out.println("未获取到extId"+wxWorkVid2UserIdDTO);
+            log.info("未获取到extId"+wxWorkVid2UserIdDTO);
         }
         }
         com.fs.wxwork.dto.WxWorkVid2UserIdRespDTO dto = data.get(0);
         com.fs.wxwork.dto.WxWorkVid2UserIdRespDTO dto = data.get(0);
 
 
         QwExternalContact qwExternalContacts = qwExternalContactMapper.selectQwExternalContactByExternalUserIdAndQwUserId(dto.getOpenid(), user.getCorpId(),user.getQwUserId());
         QwExternalContact qwExternalContacts = qwExternalContactMapper.selectQwExternalContactByExternalUserIdAndQwUserId(dto.getOpenid(), user.getCorpId(),user.getQwUserId());
         if (qwExternalContacts==null){
         if (qwExternalContacts==null){
-            System.out.println("没有外部联系人");
+            log.info("没有外部联系人");
         }
         }
 
 
         //处理拉黑的
         //处理拉黑的
@@ -519,6 +519,7 @@ public class QwMsgController {
         Long id = redisCache.getCacheObject("qrCode:uuid:"+uid);
         Long id = redisCache.getCacheObject("qrCode:uuid:"+uid);
         QwUser qwUser = new QwUser();
         QwUser qwUser = new QwUser();
         qwUser.setId(id);
         qwUser.setId(id);
+        qwUser.setRemark(msg);
         qwUser.setIpadStatus(status);
         qwUser.setIpadStatus(status);
         qwUserMapper.updateQwUser(qwUser);
         qwUserMapper.updateQwUser(qwUser);
         QwUser qwUser1 = qwUserMapper.selectQwUserById(id);
         QwUser qwUser1 = qwUserMapper.selectQwUserById(id);

+ 39 - 0
fs-qw-api-msg/src/main/java/com/fs/framework/config/RedisConfig.java

@@ -15,6 +15,8 @@ import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 
 
+import java.math.BigDecimal;
+
 /**
 /**
  * redis配置
  * redis配置
  *
  *
@@ -66,6 +68,43 @@ public class RedisConfig extends CachingConfigurerSupport
         return template;
         return template;
     }
     }
 
 
+    @Bean
+    public RedisTemplate<String, Integer> redisTemplateForInteger(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, Integer> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
+    @Bean
+    public RedisTemplate<String, BigDecimal> redisTemplateForBigDecimal(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, BigDecimal> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
+
     @Bean
     @Bean
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {

+ 39 - 0
fs-qw-api/src/main/java/com/fs/framework/config/RedisConfig.java

@@ -15,6 +15,8 @@ import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 
 
+import java.math.BigDecimal;
+
 /**
 /**
  * redis配置
  * redis配置
  *
  *
@@ -90,6 +92,43 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         template.afterPropertiesSet();
         return template;
         return template;
     }
     }
+    @Bean
+    public RedisTemplate<String, Integer> redisTemplateForInteger(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, Integer> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
+
+    @Bean
+    public RedisTemplate<String, BigDecimal> redisTemplateForBigDecimal(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, BigDecimal> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
 
 
     @Bean
     @Bean
     public DefaultRedisScript<Long> limitScript()
     public DefaultRedisScript<Long> limitScript()

+ 39 - 0
fs-qw-mq/src/main/java/com/fs/framework/config/RedisConfig.java

@@ -15,6 +15,8 @@ import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 
 
+import java.math.BigDecimal;
+
 /**
 /**
  * redis配置
  * redis配置
  *
  *
@@ -66,6 +68,25 @@ public class RedisConfig extends CachingConfigurerSupport
         return template;
         return template;
     }
     }
 
 
+    @Bean
+    public RedisTemplate<String, Integer> redisTemplateForInteger(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, Integer> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
+
     @Bean
     @Bean
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {
@@ -90,6 +111,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         template.afterPropertiesSet();
         return template;
         return template;
     }
     }
+    @Bean
+    public RedisTemplate<String, BigDecimal> redisTemplateForBigDecimal(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, BigDecimal> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
 
 
     @Bean
     @Bean
     public DefaultRedisScript<Long> limitScript()
     public DefaultRedisScript<Long> limitScript()

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

@@ -8,6 +8,9 @@ import com.fs.app.taskService.SopLogsTaskService;
 import com.fs.app.taskService.SopWxLogsService;
 import com.fs.app.taskService.SopWxLogsService;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.core.domain.ResponseResult;
+import com.fs.company.service.ICompanyService;
+import com.fs.company.vo.RedPacketMoneyVO;
+import com.fs.course.mapper.FsCourseRedPacketLogMapper;
 import com.fs.course.mapper.FsCourseWatchLogMapper;
 import com.fs.course.mapper.FsCourseWatchLogMapper;
 import com.fs.course.param.newfs.FsUserCourseAddCompanyUserParam;
 import com.fs.course.param.newfs.FsUserCourseAddCompanyUserParam;
 import com.fs.course.service.*;
 import com.fs.course.service.*;
@@ -76,6 +79,10 @@ public class CommonController {
 
 
     @Autowired
     @Autowired
     private IFsCourseLinkService courseLinkService;
     private IFsCourseLinkService courseLinkService;
+    @Autowired
+    private FsCourseRedPacketLogMapper fsCourseRedPacketLogMapper;
+    @Autowired
+    private ICompanyService companyService;
 
 
     @Autowired
     @Autowired
     private SopUserLogsMapper sopUserLogsMapper;
     private SopUserLogsMapper sopUserLogsMapper;
@@ -298,4 +305,14 @@ public class CommonController {
         }
         }
         return R.ok();
         return R.ok();
     }
     }
+    @GetMapping("/updateRedPack")
+    public R updateRedPack(String start , String end    ){
+        LocalDateTime startTime = DateUtil.parseLocalDateTime(start);
+        LocalDateTime endTime = DateUtil.parseLocalDateTime(end);
+        List<RedPacketMoneyVO> redPacketMoneyVOS = fsCourseRedPacketLogMapper.selectFsCourseRedPacketLogHourseByCompany(startTime, endTime);
+        for (RedPacketMoneyVO redPacketMoneyVO : redPacketMoneyVOS) {
+            companyService.subtractCompanyMoneyHourse(redPacketMoneyVO.getMoney(),redPacketMoneyVO.getCompanyId(), startTime.toLocalTime(), endTime.toLocalTime());
+        }
+        return R.ok();
+    }
 }
 }

+ 271 - 35
fs-qw-task/src/main/java/com/fs/app/taskService/impl/AsyncCourseWatchFinishService.java

@@ -10,14 +10,22 @@ import com.fs.qw.service.IQwCompanyService;
 import com.fs.qw.service.impl.QwExternalContactServiceImpl;
 import com.fs.qw.service.impl.QwExternalContactServiceImpl;
 import lombok.AllArgsConstructor;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
+
+import org.apache.rocketmq.client.exception.MQClientException;
 import org.apache.rocketmq.client.producer.SendCallback;
 import org.apache.rocketmq.client.producer.SendCallback;
 import org.apache.rocketmq.client.producer.SendResult;
 import org.apache.rocketmq.client.producer.SendResult;
+import org.apache.rocketmq.common.message.MessageConst;
 import org.apache.rocketmq.spring.core.RocketMQTemplate;
 import org.apache.rocketmq.spring.core.RocketMQTemplate;
+import org.apache.rocketmq.spring.support.RocketMQHeaders;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.messaging.support.MessageBuilder;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
 import java.util.Optional;
 import java.util.Optional;
+import java.util.concurrent.*;
 
 
 @Slf4j
 @Slf4j
 @Service
 @Service
@@ -36,68 +44,296 @@ public class AsyncCourseWatchFinishService {
     @Autowired
     @Autowired
     RedisCache redisCache;
     RedisCache redisCache;
 
 
+    // 重试队列和调度器
+    private final BlockingQueue<RetryMessage> retryQueue = new LinkedBlockingQueue<>(10000);
+    private final ScheduledExecutorService retryExecutor = Executors.newSingleThreadScheduledExecutor();
+
+    // 主题映射配置
+    private static final String TOPIC = "course-finish-notes";
+
+    @PostConstruct
+    public void init() {
+        // 启动重试任务,每5秒处理一次重试队列
+        retryExecutor.scheduleWithFixedDelay(this::processRetryQueue, 10, 5, TimeUnit.SECONDS);
+        log.info("AsyncCourseWatchFinishService 重试队列处理器已启动");
+    }
+
     /**
     /**
     * 异步处理完课打备注的
     * 异步处理完课打备注的
     */
     */
     @Async("scheduledExecutorService")
     @Async("scheduledExecutorService")
     public void executeCourseWatchFinish(FsCourseWatchLog finishLog) {
     public void executeCourseWatchFinish(FsCourseWatchLog finishLog) {
+//        原代码
+//        FsCourseWatchLog watchLog = new FsCourseWatchLog();
+//        watchLog.setQwExternalContactId(finishLog.getQwExternalContactId());
+//        watchLog.setFinishTime(finishLog.getFinishTime());
+//        watchLog.setQwUserId(finishLog.getQwUserId());
+//
+//
+//        QwUser qwUserByRedis = qwExternalContactService.getQwUserByRedisForId(String.valueOf(finishLog.getQwUserId()));
+//        if (qwUserByRedis == null) {
+//            log.error("无企微员工信息 {} 跳过处理。", finishLog.getQwUserId());
+//            return;
+//        }
+//
+//        QwCompany qwCompany = iQwCompanyService.getQwCompanyByRedis(qwUserByRedis.getCorpId());
+//
+//        if (qwCompany == null) {
+//            log.error("企业微信主体为空 {} 跳过处理。{} ", qwUserByRedis.getCorpId(),watchLog);
+//            return;
+//        }
+//
+//        rocketMQTemplate.asyncSend("course-finish-notes", JSON.toJSONString(finishLog),     new SendCallback() {
+//            @Override public void onSuccess(SendResult sendResult) {
+//                log.info("推送完课打备注成功1:{},{}",JSON.toJSONString(finishLog),sendResult.getMsgId());
+//            }  // 空实现
+//            @Override public void onException(Throwable e) {log.error("推送完课打备注失败1:{},{}",JSON.toJSONString(finishLog),e.getMessage());}          // 空实现
+//        });
+
+
+//        // 定义默认值
+//         final Integer DEFAULT_SERVER_NUM = 99;
+//
+//        // 使用
+//        Integer companyServerNum = Optional.ofNullable(qwCompany.getCompanyServerNum())
+//                .orElse(DEFAULT_SERVER_NUM);
+//        switch (companyServerNum){
+//            case 1:
+//                rocketMQTemplate.asyncSend("course-finish-notes", JSON.toJSONString(finishLog),     new SendCallback() {
+//                    @Override public void onSuccess(SendResult sendResult) {
+//                     log.info("推送完课打备注成功1:{},{}",JSON.toJSONString(finishLog),sendResult.getMsgId());
+//                     }  // 空实现
+//                    @Override public void onException(Throwable e) {log.error("推送完课打备注失败1:{},{}",JSON.toJSONString(finishLog),e.getMessage());}          // 空实现
+//                });
+//                break;
+//            case 2:
+//
+//                rocketMQTemplate.asyncSend("course-finish-notesTwo", JSON.toJSONString(finishLog),     new SendCallback() {
+//                    @Override public void onSuccess(SendResult sendResult) {}  // 空实现
+//                    @Override public void onException(Throwable e) {log.error("推送完课打备注失败2:{},{}",JSON.toJSONString(finishLog),e.getMessage());}          // 空实现
+//                });
+//                break;
+//            case 3:
+//                rocketMQTemplate.asyncSend("course-finish-notesThree", JSON.toJSONString(finishLog),     new SendCallback() {
+//                    @Override public void onSuccess(SendResult sendResult) {}  // 空实现
+//                    @Override public void onException(Throwable e) {log.error("推送完课打备注失败3:{},{}",JSON.toJSONString(finishLog),e.getMessage());}          // 空实现
+//                });
+//                break;
+//            default:
+//                break;
+//        }
+
+
+        // 1. 数据验证和准备
+        ValidationResult validationResult = validateAndPrepareData(finishLog);
+        if (!validationResult.isValid()) {
+            return;
+        }
+
+
+        //  2. 发送消息(使用Tag区分)
+        sendWithFlowControl(finishLog, validationResult, 0);
+
+    }
 
 
+    /**
+     * 数据验证和准备
+     */
+    private ValidationResult validateAndPrepareData(FsCourseWatchLog finishLog) {
+        // 准备日志对象
         FsCourseWatchLog watchLog = new FsCourseWatchLog();
         FsCourseWatchLog watchLog = new FsCourseWatchLog();
         watchLog.setQwExternalContactId(finishLog.getQwExternalContactId());
         watchLog.setQwExternalContactId(finishLog.getQwExternalContactId());
         watchLog.setFinishTime(finishLog.getFinishTime());
         watchLog.setFinishTime(finishLog.getFinishTime());
         watchLog.setQwUserId(finishLog.getQwUserId());
         watchLog.setQwUserId(finishLog.getQwUserId());
 
 
-
+        // 验证企微用户信息
         QwUser qwUserByRedis = qwExternalContactService.getQwUserByRedisForId(String.valueOf(finishLog.getQwUserId()));
         QwUser qwUserByRedis = qwExternalContactService.getQwUserByRedisForId(String.valueOf(finishLog.getQwUserId()));
         if (qwUserByRedis == null) {
         if (qwUserByRedis == null) {
             log.error("无企微员工信息 {} 跳过处理。", finishLog.getQwUserId());
             log.error("无企微员工信息 {} 跳过处理。", finishLog.getQwUserId());
-            return;
+            return ValidationResult.invalid();
         }
         }
 
 
+        // 验证企业主体
         QwCompany qwCompany = iQwCompanyService.getQwCompanyByRedis(qwUserByRedis.getCorpId());
         QwCompany qwCompany = iQwCompanyService.getQwCompanyByRedis(qwUserByRedis.getCorpId());
-
         if (qwCompany == null) {
         if (qwCompany == null) {
-            log.error("企业微信主体为空 {} 跳过处理。", qwUserByRedis.getCorpId());
+            log.error("企业微信主体为空 {} 跳过处理。{} ", qwUserByRedis.getCorpId(), watchLog);
+            return ValidationResult.invalid();
+        }
+
+        return ValidationResult.valid(watchLog, qwUserByRedis, qwCompany);
+    }
+
+
+    /**
+     * 带流控处理的消息发送
+     */
+    private void sendWithFlowControl(FsCourseWatchLog finishLog,
+                                     ValidationResult validationResult, int retryCount) {
+        if (retryCount >= 3) {
+            log.warn("消息重试超过最大次数,转入重试队列: topic={}, qwUserId={}",
+                    TOPIC, finishLog.getQwUserId());
+            offerToRetryQueue(finishLog, validationResult);
             return;
             return;
         }
         }
 
 
-        rocketMQTemplate.asyncSend("course-finish-notes", JSON.toJSONString(finishLog),     new SendCallback() {
-            @Override public void onSuccess(SendResult sendResult) {}  // 空实现
-            @Override public void onException(Throwable e) {log.error("推送完课打备注失败1:{},{}",JSON.toJSONString(finishLog),e.getMessage());}          // 空实现
+        rocketMQTemplate.asyncSend(TOPIC, JSON.toJSONString(finishLog), new SendCallback() {
+            @Override
+            public void onSuccess(SendResult sendResult) {
+                log.info("推送完课打备注成功1:{},{}",JSON.toJSONString(finishLog),sendResult.getMsgId());
+            }
+
+            @Override
+            public void onException(Throwable e) {
+                if (isFlowControlException(e)) {
+                    // 流控异常处理
+                    handleFlowControlRetry(TOPIC, finishLog, validationResult, retryCount, e);
+                    log.error("推送完课打备注失败1流控异常:finishLog={},e={}",JSON.toJSONString(finishLog),e.getMessage());
+                } else {
+                    // 其他异常
+                    log.error("推送完课打备注失败1:{},{}",JSON.toJSONString(finishLog),e.getMessage());
+                }
+            }
         });
         });
+    }
+
+    /**
+     * 放入重试队列
+     */
+    private void offerToRetryQueue(FsCourseWatchLog finishLog,
+                                   ValidationResult validationResult) {
+        RetryMessage retryMessage = new RetryMessage(finishLog, validationResult);
+        boolean offered = retryQueue.offer(retryMessage);
+        if (offered) {
+            log.info("消息已加入重试队列: topic={}, qwUserId={}", TOPIC, finishLog.getQwUserId());
+        } else {
+            log.error("重试队列已满,消息可能丢失: topic={}, qwUserId={}", TOPIC, finishLog.getQwUserId());
+            // 这里可以接入告警系统
+        }
+    }
+
+    /**
+     * 处理重试队列
+     */
+    private void processRetryQueue() {
+        try {
+            int processedCount = 0;
+            RetryMessage retryMessage;
+
+            while (processedCount < 100 && (retryMessage = retryQueue.poll()) != null) {
+                try {
+                    // 重新发送消息
+                    sendWithFlowControl(retryMessage.getFinishLog(),
+                            retryMessage.getValidationResult(), 0);
+                    processedCount++;
+
+                    Thread.sleep(10);
+                } catch (Exception e) {
+                    log.error("重试队列处理失败: {}", e.getMessage());
+                    offerToRetryQueue(retryMessage.getFinishLog(), retryMessage.getValidationResult());
+                }
+            }
+
+            if (processedCount > 0) {
+                log.debug("重试队列处理完成,本次处理数量: {}", processedCount);
+            }
+        } catch (Exception e) {
+            log.error("处理重试队列异常: {}", e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 判断是否为流控异常
+     */
+    private boolean isFlowControlException(Throwable e) {
+        if (e instanceof MQClientException) {
+            return ((MQClientException) e).getResponseCode() == 215;
+        }
+        // 检查异常链
+        Throwable cause = e.getCause();
+        if (cause instanceof MQClientException) {
+            return ((MQClientException) cause).getResponseCode() == 215;
+        }
+        return false;
+    }
+
+    /**
+     * 流控重试处理
+     */
+    private void handleFlowControlRetry(String topic, FsCourseWatchLog finishLog,
+                                        ValidationResult validationResult, int retryCount, Throwable e) {
+        long backoffTime = calculateBackoffTime(retryCount);
+        log.warn("流控触发,{}ms后第{}次重试: topic={}, qwUserId={}",
+                backoffTime, retryCount + 1, topic, finishLog.getQwUserId());
 
 
+        // 使用 ScheduledExecutorService 进行延迟执行
+        retryExecutor.schedule(() -> {
+            try {
+                sendWithFlowControl(finishLog, validationResult, retryCount + 1);
+            } catch (Exception ex) {
+                log.error("延迟重试执行异常: {}", ex.getMessage(), ex);
+            }
+        }, backoffTime, TimeUnit.MILLISECONDS);
+    }
+    /**
+     * 计算退避时间(指数退避)
+     */
+    private long calculateBackoffTime(int retryCount) {
+        return Math.min(1000 * (long) Math.pow(2, retryCount), 10000); // 最大10秒
+    }
+
+    @PreDestroy
+    public void destroy() {
+        retryExecutor.shutdown();
+        try {
+            if (!retryExecutor.awaitTermination(10, TimeUnit.SECONDS)) {
+                retryExecutor.shutdownNow();
+            }
+        } catch (InterruptedException e) {
+            retryExecutor.shutdownNow();
+            Thread.currentThread().interrupt();
+        }
+        log.info("AsyncCourseWatchFinishService 已关闭");
+    }
 
 
-        // 定义默认值
-         final Integer DEFAULT_SERVER_NUM = 99;
-
-        // 使用
-        Integer companyServerNum = Optional.ofNullable(qwCompany.getCompanyServerNum())
-                .orElse(DEFAULT_SERVER_NUM);
-        switch (companyServerNum){
-            case 1:
-                rocketMQTemplate.asyncSend("course-finish-notes", JSON.toJSONString(finishLog),     new SendCallback() {
-                    @Override public void onSuccess(SendResult sendResult) {}  // 空实现
-                    @Override public void onException(Throwable e) {log.error("推送完课打备注失败1:{},{}",JSON.toJSONString(finishLog),e.getMessage());}          // 空实现
-                });
-                break;
-            case 2:
-
-                rocketMQTemplate.asyncSend("course-finish-notesTwo", JSON.toJSONString(finishLog),     new SendCallback() {
-                    @Override public void onSuccess(SendResult sendResult) {}  // 空实现
-                    @Override public void onException(Throwable e) {log.error("推送完课打备注失败2:{},{}",JSON.toJSONString(finishLog),e.getMessage());}          // 空实现
-                });
-                break;
-            case 3:
-                rocketMQTemplate.asyncSend("course-finish-notesThree", JSON.toJSONString(finishLog),     new SendCallback() {
-                    @Override public void onSuccess(SendResult sendResult) {}  // 空实现
-                    @Override public void onException(Throwable e) {log.error("推送完课打备注失败3:{},{}",JSON.toJSONString(finishLog),e.getMessage());}          // 空实现
-                });
-                break;
-            default:
-                break;
+    // 内部辅助类
+    private static class ValidationResult {
+        private final boolean valid;
+        private final FsCourseWatchLog watchLog;
+        private final QwUser qwUser;
+        private final QwCompany qwCompany;
+
+        public ValidationResult(boolean valid, FsCourseWatchLog watchLog, QwUser qwUser, QwCompany qwCompany) {
+            this.valid = valid;
+            this.watchLog = watchLog;
+            this.qwUser = qwUser;
+            this.qwCompany = qwCompany;
         }
         }
 
 
+        public static ValidationResult valid(FsCourseWatchLog watchLog, QwUser qwUser, QwCompany qwCompany) {
+            return new ValidationResult(true, watchLog, qwUser, qwCompany);
+        }
+
+        public static ValidationResult invalid() {
+            return new ValidationResult(false, null, null, null);
+        }
+
+        public boolean isValid() { return valid; }
+        public FsCourseWatchLog getWatchLog() { return watchLog; }
+        public QwUser getQwUser() { return qwUser; }
+        public QwCompany getQwCompany() { return qwCompany; }
+    }
+
+    private static class RetryMessage {
+        private final FsCourseWatchLog finishLog;
+        private final ValidationResult validationResult;
+
+        public RetryMessage(FsCourseWatchLog finishLog, ValidationResult validationResult) {
+            this.finishLog = finishLog;
+            this.validationResult = validationResult;
+        }
 
 
+        public FsCourseWatchLog getFinishLog() { return finishLog; }
+        public ValidationResult getValidationResult() { return validationResult; }
     }
     }
 
 
 }
 }

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

@@ -367,7 +367,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
 
 
 
     private void processSopGroup(String sopId, List<SopUserLogsVo> userLogsVos,LocalDateTime currentTime, Map<String,
     private void processSopGroup(String sopId, List<SopUserLogsVo> userLogsVos,LocalDateTime currentTime, Map<String,
-            QwGroupChat> groupChatMap,CourseConfig config,Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap,
+                                         QwGroupChat> groupChatMap,CourseConfig config,Map<Long, Map<Integer, List<CompanyMiniapp>>> miniMap,
                                  List<Company> companies) throws Exception {
                                  List<Company> companies) throws Exception {
         QwSopRuleTimeVO ruleTimeVO = sopMapper.selectQwSopByClickHouseId(sopId);
         QwSopRuleTimeVO ruleTimeVO = sopMapper.selectQwSopByClickHouseId(sopId);
 
 
@@ -674,11 +674,40 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
         if(content.getSetting() == null){
         if(content.getSetting() == null){
             return;
             return;
         }
         }
+        List<QwSopTempSetting.Content.Setting> setting = content.getSetting().stream().filter(e -> "7".equals(e.getContentType())).collect(Collectors.toList());
+        if (!setting.isEmpty()) {
+            List<String> valuesList = PubFun.listToNewList(setting, QwSopTempSetting.Content.Setting::getValue);
+            if (valuesList != null && !valuesList.isEmpty()) {
+                try {
+                    List<QwSopTempVoice> voiceList = qwSopTempVoiceService.getVoiceByText(Long.parseLong(companyUserId), valuesList);
+                    if (voiceList != null && !voiceList.isEmpty()) {
+                        Map<String, QwSopTempVoice> collect = voiceList.stream().collect(Collectors.toMap(QwSopTempVoice::getVoiceTxt, e -> e));
+                        setting.parallelStream().filter(e -> "7".equals(e.getContentType())).forEach(st -> {
+                            QwSopTempVoice voice = collect.get(st.getValue());
+                            if (voice.getVoiceUrl() == null) {
+                                return;
+                            }
+                            st.setVoiceUrl(voice.getVoiceUrl());
+                            st.setVoiceDuration(voice.getDuration() + "");
+                        });
+                    }
+                } catch (NumberFormatException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
 //        // 发送语音 end
 //        // 发送语音 end
         if (content.getType()==5){
         if (content.getType()==5){
             sopAddTag(logVo,content,sendTime);
             sopAddTag(logVo,content,sendTime);
         }
         }
 
 
+        //当语音模板的qw_sop_temp_voice中无对应语音,就不生成qw_sop_logs记录
+        if (content.getType() == 7 && content.getSetting() != null && !content.getSetting().isEmpty()) {
+            if (content.getSetting().get(0).getVoiceUrl() == null) {
+                return;
+            }
+        }
+
         if (StringUtils.isNotEmpty(logVo.getChatId())) {
         if (StringUtils.isNotEmpty(logVo.getChatId())) {
             QwGroupChat groupChat = groupChatMap.get(logVo.getChatId());
             QwGroupChat groupChat = groupChatMap.get(logVo.getChatId());
             ruleTimeVO.setSendType(6);
             ruleTimeVO.setSendType(6);
@@ -839,11 +868,18 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
             case 5:
             case 5:
 //                handleTagMessage(sopLogs, content);
 //                handleTagMessage(sopLogs, content);
                 break;
                 break;
+            case 7:
+                handleVoiceMessage(sopLogs, content, companyUserId);
+                break;
             default:
             default:
                 log.error("未知的消息类型 {},跳过处理。", type);
                 log.error("未知的消息类型 {},跳过处理。", type);
                 break;
                 break;
         }
         }
     }
     }
+    private void handleVoiceMessage(QwSopLogs sopLogs, QwSopTempSetting.Content content, String companyUserId) {
+        sopLogs.setContentJson(JSON.toJSONString(content));
+        enqueueQwSopLogs(sopLogs);
+    }
 
 
     private void handleNormalMessage(QwSopLogs sopLogs, QwSopTempSetting.Content content,String companyUserId) {
     private void handleNormalMessage(QwSopLogs sopLogs, QwSopTempSetting.Content content,String companyUserId) {
 
 
@@ -861,7 +897,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                                      SopUserLogsVo logVo, Date sendTime, Long courseId, Long videoId, String qwUserId, String companyUserId,
                                      SopUserLogsVo logVo, Date sendTime, Long courseId, Long videoId, String qwUserId, String companyUserId,
                                      String companyId, String externalId, String welcomeText, String qwUserName,
                                      String companyId, String externalId, String welcomeText, String qwUserName,
                                      Long fsUserId, boolean isGroupChat, String miniAppId, QwGroupChat groupChat,CourseConfig config,Map<Long,
                                      Long fsUserId, boolean isGroupChat, String miniAppId, QwGroupChat groupChat,CourseConfig config,Map<Long,
-                                     Map<Integer, List<CompanyMiniapp>>> miniMap,Integer grade, Integer sendMsgType,
+                    Map<Integer, List<CompanyMiniapp>>> miniMap,Integer grade, Integer sendMsgType,
                                      List<Company> companies) {
                                      List<Company> companies) {
         // 深拷贝 Content 对象,避免使用 JSON
         // 深拷贝 Content 对象,避免使用 JSON
         QwSopTempSetting.Content clonedContent = deepCopyContent(content);
         QwSopTempSetting.Content clonedContent = deepCopyContent(content);
@@ -957,6 +993,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                     if(sopLogs.getSendType()==1){
                     if(sopLogs.getSendType()==1){
                         setting.setMiniprogramAppid(miniAppId);
                         setting.setMiniprogramAppid(miniAppId);
                     }else {
                     }else {
+                        int miniType = getLevel(grade);
                         //算主备小程序
                         //算主备小程序
                         String finalAppId = getAppIdFromMiniMap(miniMap, companyId, sendMsgType, grade);
                         String finalAppId = getAppIdFromMiniMap(miniMap, companyId, sendMsgType, grade);
 
 
@@ -964,6 +1001,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                             finalAppId = miniAppId;
                             finalAppId = miniAppId;
                         }
                         }
 
 
+                        setting.setMiniType(miniType);
                         if (!StringUtil.strIsNullOrEmpty(finalAppId)) {
                         if (!StringUtil.strIsNullOrEmpty(finalAppId)) {
                             setting.setMiniprogramAppid(finalAppId);
                             setting.setMiniprogramAppid(finalAppId);
                         } else {
                         } else {
@@ -1036,8 +1074,7 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
             return null;
             return null;
         }
         }
 
 
-        int effectiveGrade = (grade == null) ? 5 : grade;
-        int listIndex = (effectiveGrade == 1 || effectiveGrade == 2) ? 0 : 1;
+        int listIndex = getLevel(grade);
         List<CompanyMiniapp> miniapps = gradeMap.get(listIndex);
         List<CompanyMiniapp> miniapps = gradeMap.get(listIndex);
 
 
         if (miniapps == null || miniapps.isEmpty()) {
         if (miniapps == null || miniapps.isEmpty()) {
@@ -1050,6 +1087,12 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
                 : null;
                 : null;
     }
     }
 
 
+    private static int getLevel(Integer grade) {
+        int effectiveGrade = (grade == null) ? 5 : grade;
+        int listIndex = (effectiveGrade == 1 || effectiveGrade == 2) ? 0 : 1;
+        return listIndex;
+    }
+
     /**
     /**
      * 深拷贝 Content 对象,避免使用 JSON 进行序列化和反序列化
      * 深拷贝 Content 对象,避免使用 JSON 进行序列化和反序列化
      */
      */
@@ -1213,9 +1256,9 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
 
 
 
 
     public FsCourseSopAppLink createFsCourseSopAppLink(String link, Date sendTime, Date updateTime, String companyId,
     public FsCourseSopAppLink createFsCourseSopAppLink(String link, Date sendTime, Date updateTime, String companyId,
-                                         String companyUserId,String qwUserId,String qwUserName,String corpId,
-                                         Long courseId,String linkTile,String linkImageUrl,Long videoId,
-                                         String linkDescribe,String appMsgLink,String externalId){
+                                                       String companyUserId,String qwUserId,String qwUserName,String corpId,
+                                                       Long courseId,String linkTile,String linkImageUrl,Long videoId,
+                                                       String linkDescribe,String appMsgLink,String externalId){
 
 
         FsCourseSopAppLink sopAppLink=new FsCourseSopAppLink();
         FsCourseSopAppLink sopAppLink=new FsCourseSopAppLink();
         sopAppLink.setLink(link);
         sopAppLink.setLink(link);
@@ -1279,8 +1322,8 @@ public class SopLogsTaskServiceImpl implements SopLogsTaskService {
     }
     }
 
 
     private String createLinkByMiniApp(QwSopTempSetting.Content.Setting setting, SopUserLogsVo logVo, Date sendTime,
     private String createLinkByMiniApp(QwSopTempSetting.Content.Setting setting, SopUserLogsVo logVo, Date sendTime,
-                                     Long courseId, Long videoId, String qwUserId,
-                                     String companyUserId, String companyId, String externalId,String isOfficial,Long fsUserId) {
+                                       Long courseId, Long videoId, String qwUserId,
+                                       String companyUserId, String companyId, String externalId,String isOfficial,Long fsUserId) {
         // 获取缓存的配置
         // 获取缓存的配置
         CourseConfig config;
         CourseConfig config;
         synchronized(configLock) {
         synchronized(configLock) {

+ 40 - 0
fs-qw-task/src/main/java/com/fs/framework/config/RedisConfig.java

@@ -15,6 +15,8 @@ import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 
 
+import java.math.BigDecimal;
+
 /**
 /**
  * redis配置
  * redis配置
  *
  *
@@ -66,6 +68,25 @@ public class RedisConfig extends CachingConfigurerSupport
         return template;
         return template;
     }
     }
 
 
+    @Bean
+    public RedisTemplate<String, Integer> redisTemplateForInteger(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, Integer> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(Integer.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
+
     @Bean
     @Bean
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {
@@ -91,6 +112,25 @@ public class RedisConfig extends CachingConfigurerSupport
         return template;
         return template;
     }
     }
 
 
+    @Bean
+    public RedisTemplate<String, BigDecimal> redisTemplateForBigDecimal(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, BigDecimal> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
+
     @Bean
     @Bean
     public DefaultRedisScript<Long> limitScript()
     public DefaultRedisScript<Long> limitScript()
     {
     {

+ 42 - 8
fs-qw-voice/src/main/java/com/fs/app/controller/CommonController.java

@@ -1,20 +1,24 @@
 package com.fs.app.controller;
 package com.fs.app.controller;
 
 
 
 
-import com.fs.ad.enums.AdUploadType;
-import com.fs.ad.service.IAdHtmlClickLogService;
+import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
-import com.fs.company.service.ICompanyWxChatService;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.fastgptApi.util.AudioUtils;
 import com.fs.fastgptApi.util.AudioUtils;
 import com.fs.fastgptApi.vo.AudioVO;
 import com.fs.fastgptApi.vo.AudioVO;
-import com.fs.wxUser.service.ICompanyWxUserService;
+import com.fs.sop.domain.QwSopTempVoice;
+import com.fs.sop.service.IQwSopTempVoiceService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.Api;
 import jdk.nashorn.internal.ir.annotations.Ignore;
 import jdk.nashorn.internal.ir.annotations.Ignore;
 import lombok.AllArgsConstructor;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
 
 
 
 
 @Slf4j
 @Slf4j
@@ -23,7 +27,8 @@ import org.springframework.web.bind.annotation.RestController;
 @AllArgsConstructor
 @AllArgsConstructor
 @Ignore
 @Ignore
 @RequestMapping(value="/app/common")
 @RequestMapping(value="/app/common")
-public class CommonController {
+public class CommonController extends BaseController {
+
 
 
     @GetMapping("/test")
     @GetMapping("/test")
     public R testSend(String voice, Long id){
     public R testSend(String voice, Long id){
@@ -31,4 +36,33 @@ public class CommonController {
         return R.ok().put("data", audioVO);
         return R.ok().put("data", audioVO);
     }
     }
 
 
+    @GetMapping("/voice")
+    public R voice(String voice, Long id){
+        AudioVO audioVO = AudioUtils.transferAudioSilkFromText(voice,id,  false);
+        return R.ok().put("data", audioVO);
+    }
+
+
+    /**
+     * 当只有模板文字text时,生成表中对应条的voice_url和user_voice_url
+     * @param id            qw_sop_temp_voice的id
+     * @return
+     */
+    @GetMapping("/createUserUrlAndUrl")
+    public R createUserUrlAndUrl(@Param("id") Long id,@Param("voiceTxt") String voiceTxt){
+        AudioVO audioVO = AudioUtils.transferCompanyIdAudioSilkFromText(voiceTxt,id,false);
+        return R.ok().put("data", audioVO);
+    }
+
+    /**
+     * 当只有user_voice_url时,生成表中对应条的voice_url
+     * @param userVoiceUrl  wav格式的语音文件
+     * @param id            qw_sop_temp_voice的id
+     * @return
+     */
+    @GetMapping("/createVoiceUrl")
+    public R createVoiceUrl( @RequestParam("id") Long id,@RequestParam("userVoiceUrl") String userVoiceUrl){
+        AudioVO audioVO = AudioUtils.transferAudioSilkFromUrl(userVoiceUrl,  false);
+        return R.ok().put("data", audioVO);
+    }
 }
 }

+ 10 - 10
fs-qw-voice/src/main/java/com/fs/app/exception/FSException.java

@@ -5,26 +5,26 @@ package com.fs.app.exception;
  */
  */
 public class FSException extends RuntimeException {
 public class FSException extends RuntimeException {
 	private static final long serialVersionUID = 1L;
 	private static final long serialVersionUID = 1L;
-	
-    private String msg;
-    private int code = 500;
-    
-    public FSException(String msg) {
+
+	private String msg;
+	private int code = 500;
+
+	public FSException(String msg) {
 		super(msg);
 		super(msg);
 		this.msg = msg;
 		this.msg = msg;
 	}
 	}
-	
+
 	public FSException(String msg, Throwable e) {
 	public FSException(String msg, Throwable e) {
 		super(msg, e);
 		super(msg, e);
 		this.msg = msg;
 		this.msg = msg;
 	}
 	}
-	
+
 	public FSException(String msg, int code) {
 	public FSException(String msg, int code) {
 		super(msg);
 		super(msg);
 		this.msg = msg;
 		this.msg = msg;
 		this.code = code;
 		this.code = code;
 	}
 	}
-	
+
 	public FSException(String msg, int code, Throwable e) {
 	public FSException(String msg, int code, Throwable e) {
 		super(msg, e);
 		super(msg, e);
 		this.msg = msg;
 		this.msg = msg;
@@ -46,6 +46,6 @@ public class FSException extends RuntimeException {
 	public void setCode(int code) {
 	public void setCode(int code) {
 		this.code = code;
 		this.code = code;
 	}
 	}
-	
-	
+
+
 }
 }

+ 101 - 12
fs-qw-voice/src/main/java/com/fs/app/mq/RocketMQConsumerService.java

@@ -1,29 +1,25 @@
 package com.fs.app.mq;
 package com.fs.app.mq;
 
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSON;
-import com.fs.ad.service.IAdHtmlClickLogService;
+import com.alibaba.fastjson.JSONObject;
 import com.fs.common.annotation.DataSource;
 import com.fs.common.annotation.DataSource;
 import com.fs.common.core.redis.RedisCacheT;
 import com.fs.common.core.redis.RedisCacheT;
 import com.fs.common.enums.DataSourceType;
 import com.fs.common.enums.DataSourceType;
-import com.fs.common.utils.PubFun;
-import com.fs.qw.result.QwFilterSopCustomersResult;
-import com.fs.qw.vo.AdUploadVo;
+import com.fs.qw.service.IQwUserService;
+import com.fs.qw.vo.QwUserVO;
 import com.fs.sop.domain.QwSop;
 import com.fs.sop.domain.QwSop;
 import com.fs.sop.domain.QwSopTempContent;
 import com.fs.sop.domain.QwSopTempContent;
-import com.fs.sop.domain.QwSopTempDay;
-import com.fs.sop.mapper.QwSopMapper;
-import com.fs.sop.mapper.QwSopTempContentMapper;
-import com.fs.sop.params.QwSopTagsParam;
+import com.fs.sop.domain.QwSopTempVoice;
+import com.fs.sop.service.IQwSopService;
+import com.fs.sop.service.IQwSopTempContentService;
 import com.fs.sop.service.IQwSopTempDayService;
 import com.fs.sop.service.IQwSopTempDayService;
 import com.fs.sop.service.IQwSopTempVoiceService;
 import com.fs.sop.service.IQwSopTempVoiceService;
 import com.fs.sop.vo.VoiceVo;
 import com.fs.sop.vo.VoiceVo;
-import com.fs.voice.utils.StringUtil;
 import lombok.AllArgsConstructor;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.commons.beanutils.ConvertUtils;
 import org.apache.rocketmq.spring.core.RocketMQListener;
 import org.apache.rocketmq.spring.core.RocketMQListener;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
-import org.springframework.web.bind.annotation.GetMapping;
 
 
 import java.util.Arrays;
 import java.util.Arrays;
 import java.util.List;
 import java.util.List;
@@ -32,10 +28,14 @@ import java.util.stream.Collectors;
 @Slf4j
 @Slf4j
 @Service
 @Service
 @AllArgsConstructor
 @AllArgsConstructor
-@RocketMQMessageListener(topic = "${rocketmq.consumer.topic}", consumerGroup = "${rocketmq.consumer.group}")
+//@RocketMQMessageListener(topic = "${rocketmq.consumer.topic}", consumerGroup = "${rocketmq.consumer.group}")
 public class RocketMQConsumerService implements RocketMQListener<String> {
 public class RocketMQConsumerService implements RocketMQListener<String> {
     private final RedisCacheT<VoiceVo> redisCache;
     private final RedisCacheT<VoiceVo> redisCache;
     public final static String VOICE_CACHE_KEY = "voice:cache:";
     public final static String VOICE_CACHE_KEY = "voice:cache:";
+    private final IQwSopTempVoiceService qwSopTempVoiceService;
+    private final IQwSopTempContentService qwSopTempContentService;
+    private final IQwUserService qwUserService;
+    private final IQwSopService qwSopService;
 
 
     @Override
     @Override
     @DataSource(DataSourceType.SOP)
     @DataSource(DataSourceType.SOP)
@@ -44,6 +44,95 @@ public class RocketMQConsumerService implements RocketMQListener<String> {
         VoiceVo vo = JSON.parseObject(message, VoiceVo.class);
         VoiceVo vo = JSON.parseObject(message, VoiceVo.class);
         vo.setGenerated(0);
         vo.setGenerated(0);
         redisCache.setCacheObject(VOICE_CACHE_KEY + vo.getType() + ":" + vo.getId(), vo);
         redisCache.setCacheObject(VOICE_CACHE_KEY + vo.getType() + ":" + vo.getId(), vo);
+
+        /*VoiceVo vo = JSON.parseObject(message, VoiceVo.class);
+        if(vo.getId() != null){
+            List<QwSopTempContent> contentList = qwSopTempContentService.selectQwSopTempContentByTempId(vo.getId());
+            if(contentList != null && !contentList.isEmpty()){
+                updateTempVoiceInfo(contentList);
+            }
+        }*/
     }
     }
 
 
+    private void updateTempVoiceInfo(List<QwSopTempContent> voiceList) {
+        for (QwSopTempContent qwSopTempContent : voiceList) {
+            String tempId = qwSopTempContent.getTempId();
+            String content = qwSopTempContent.getContent();
+            JSONObject jsonObject = JSONObject.parseObject(content);
+            String text = jsonObject.getString("value");
+            List<QwSop> qwSopList = qwSopService.selectQwSopByTempId(tempId);//通过tempId查询出所有sop
+            if(qwSopList != null && !qwSopList.isEmpty()){
+                for (QwSop qwSop : qwSopList) {
+                    if(qwSop != null && qwSop.getQwUserIds() != null){
+                        //查询出所有的tempContent来筛选文字
+                        List<QwSopTempContent> qwSopTempContentList = qwSopTempContentService.selectQwSopTempContentByTempId(tempId);
+                        if(qwSopTempContentList != null && !qwSopTempContentList.isEmpty()){
+                            for (QwSopTempContent qwSopTemp : qwSopTempContentList) {
+                                if(qwSopTemp != null && qwSopTemp.getContentType() == 7){
+                                    String[] split = qwSop.getQwUserIds().split(",");
+                                    Long[] qwUserIds = (Long[]) ConvertUtils.convert(split, Long.class);
+                                    List<QwUserVO> qwUserVOS = qwUserService.selectQwUserVOByIds(qwUserIds);
+                                    if(qwUserVOS != null){
+                                        for (QwUserVO qwUserVO : qwUserVOS) {
+                                            Long companyUserId = qwUserVO.getCompanyUserId();
+                                            QwSopTempVoice qwSopTempVoice = qwSopTempVoiceService.selectQwSopTempVoiceByCompanyUserIdAndVoiceTxt(companyUserId,text);
+                                            if(qwSopTempVoice == null){
+                                                if(companyUserId != null && text != null){
+                                                    QwSopTempVoice sopTempVoice = new QwSopTempVoice();
+                                                    sopTempVoice.setCompanyUserId(companyUserId);
+                                                    sopTempVoice.setVoiceTxt(text);
+                                                    sopTempVoice.setTempId(tempId);
+                                                    sopTempVoice.setRecordType(0);
+                                                    qwSopTempVoiceService.insertQwSopTempVoice(sopTempVoice);
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        /*if(qwSop != null && qwSop.getQwUserIds() != null){
+            String tempId = qwSop.getTempId();
+            List<QwSopTempContent> voiceList = qwSopTempContentService.selectQwSopTempContentByTempId(tempId);
+            if(voiceList != null && !voiceList.isEmpty()){
+                for (QwSopTempContent qwSopTempContent : voiceList) {
+                    String content = qwSopTempContent.getContent();
+                    JSONObject jsonObject = JSONObject.parseObject(content);
+                    String text = jsonObject.getString("value");
+                    //查询出所有的tempContent来筛选文字
+                    List<QwSopTempContent> qwSopTempContentList = qwSopTempContentService.selectQwSopTempContentByTempId(tempId);
+                    if(qwSopTempContentList != null && !qwSopTempContentList.isEmpty()){
+                        for (QwSopTempContent qwSopTemp : qwSopTempContentList) {
+                            if(qwSopTemp != null && qwSopTemp.getContentType() == 7){
+                                String[] split = qwSop.getQwUserIds().split(",");
+                                Long[] qwUserIds = Arrays.stream(split)
+                                        .filter(s -> !s.isEmpty())
+                                        .map(Long::valueOf)
+                                        .toArray(Long[]::new);
+                                List<QwUserVO> qwUserVOS = qwUserService.selectQwUserVOByIds(qwUserIds);
+                                if(qwUserVOS != null){
+                                    for (QwUserVO qwUserVO : qwUserVOS) {
+                                        Long companyUserId = qwUserVO.getCompanyUserId();
+                                        QwSopTempVoice qwSopTempVoice = qwSopTempVoiceService.selectQwSopTempVoiceByCompanyUserIdAndVoiceTxt(companyUserId,text);
+                                        if(qwSopTempVoice == null){
+                                            QwSopTempVoice sopTempVoice = new QwSopTempVoice();
+                                            sopTempVoice.setCompanyUserId(companyUserId);
+                                            sopTempVoice.setVoiceTxt(text);
+                                            sopTempVoice.setTempId(tempId);
+                                            sopTempVoice.setRecordType(0);
+                                            qwSopTempVoiceService.insertQwSopTempVoice(sopTempVoice);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }*/
+    }
 }
 }

+ 10 - 10
fs-qw-voice/src/main/java/com/fs/app/task/Task.java

@@ -38,14 +38,14 @@ public class Task {
 
 
     @Scheduled(cron = "0 * * * * *")
     @Scheduled(cron = "0 * * * * *")
     @DataSource(DataSourceType.SOP)
     @DataSource(DataSourceType.SOP)
-    public void scheduled(){
+    public void scheduled() {
         List<VoiceVo> list = redisCache.getCacheListByPattern(VOICE_CACHE_KEY + "*");
         List<VoiceVo> list = redisCache.getCacheListByPattern(VOICE_CACHE_KEY + "*");
-        if(list.isEmpty()) return;
+        if (list.isEmpty()) return;
         VoiceVo vo = list.get(0);
         VoiceVo vo = list.get(0);
-        if(vo.getType() == 0){
+        if (vo.getType() == 0) {
             synchronousTemp(Long.parseLong(vo.getId()));
             synchronousTemp(Long.parseLong(vo.getId()));
         }
         }
-        if(vo.getType() == 1){
+        if (vo.getType() == 1) {
             synchronousSop(vo.getId());
             synchronousSop(vo.getId());
         }
         }
         redisCache.deleteObject(VOICE_CACHE_KEY + vo.getType() + ":" + vo.getId());
         redisCache.deleteObject(VOICE_CACHE_KEY + vo.getType() + ":" + vo.getId());
@@ -53,19 +53,19 @@ public class Task {
 
 
 
 
     @DataSource(DataSourceType.SOP)
     @DataSource(DataSourceType.SOP)
-    public void synchronousTemp(Long dayId){
+    public void synchronousTemp(Long dayId) {
         QwSopTempDay day = qwSopTempDayService.getById(dayId);
         QwSopTempDay day = qwSopTempDayService.getById(dayId);
         List<QwSopTempContent> contents = qwSopTempContentMapper.listByTempAndDay(day.getTempId(), dayId);
         List<QwSopTempContent> contents = qwSopTempContentMapper.listByTempAndDay(day.getTempId(), dayId);
         qwSopTempVoiceService.synchronousTemp(contents, day);
         qwSopTempVoiceService.synchronousTemp(contents, day);
     }
     }
 
 
     @DataSource(DataSourceType.SOP)
     @DataSource(DataSourceType.SOP)
-    public void synchronousSop(String sopId){
+    public void synchronousSop(String sopId) {
         QwSop qwSop = qwSopMapper.selectQwSopById(sopId);
         QwSop qwSop = qwSopMapper.selectQwSopById(sopId);
         QwSopTagsParam qwSopTagsParam = new QwSopTagsParam();
         QwSopTagsParam qwSopTagsParam = new QwSopTagsParam();
         //成员筛选
         //成员筛选
-        if (!StringUtil.strIsNullOrEmpty(qwSop.getQwUserIds())){
-            qwSopTagsParam.setUserIdsSelectList(Arrays.asList( qwSop.getQwUserIds().split(",")));
+        if (!StringUtil.strIsNullOrEmpty(qwSop.getQwUserIds())) {
+            qwSopTagsParam.setUserIdsSelectList(Arrays.asList(qwSop.getQwUserIds().split(",")));
         }
         }
 
 
         //标过滤类型
         //标过滤类型
@@ -73,13 +73,13 @@ public class Task {
 
 
 
 
         //标签
         //标签
-        if (!StringUtil.strIsNullOrEmpty(qwSop.getTags())){
+        if (!StringUtil.strIsNullOrEmpty(qwSop.getTags())) {
             qwSopTagsParam.setTagsIdsSelectList(Arrays.asList(qwSop.getTags().split(",")));
             qwSopTagsParam.setTagsIdsSelectList(Arrays.asList(qwSop.getTags().split(",")));
         }
         }
 
 
         //排除标签
         //排除标签
         String excludeTags = qwSop.getExcludeTags();
         String excludeTags = qwSop.getExcludeTags();
-        if (!StringUtil.strIsNullOrEmpty(excludeTags)){
+        if (!StringUtil.strIsNullOrEmpty(excludeTags)) {
             qwSopTagsParam.setOutTagsIdsSelectList(Arrays.asList(excludeTags.split(",")));
             qwSopTagsParam.setOutTagsIdsSelectList(Arrays.asList(excludeTags.split(",")));
         }
         }
         qwSopTagsParam.setCropId(qwSop.getCorpId());
         qwSopTagsParam.setCropId(qwSop.getCorpId());

+ 13 - 3
fs-qw-voice/src/main/java/com/fs/framework/config/DataSourceConfig.java

@@ -21,7 +21,6 @@ import java.util.Map;
 
 
 @Configuration
 @Configuration
 public class DataSourceConfig {
 public class DataSourceConfig {
-
     @Bean
     @Bean
     @ConfigurationProperties(prefix = "spring.datasource.sop.druid.master")
     @ConfigurationProperties(prefix = "spring.datasource.sop.druid.master")
     public DataSource sopDataSource() {
     public DataSource sopDataSource() {
@@ -34,12 +33,23 @@ public class DataSourceConfig {
         return new DruidDataSource();
         return new DruidDataSource();
     }
     }
 
 
+    @Bean
+    @ConfigurationProperties(prefix = "spring.datasource.mysql.druid.slave")
+    public DataSource slaveDataSource() {
+        return new DruidDataSource();
+    }
+
 
 
 
 
     @Bean
     @Bean
     @Primary
     @Primary
-    public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource, @Qualifier("sopDataSource") DataSource sopDataSource) {
+    public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
+                                        @Qualifier("sopDataSource") DataSource sopDataSource,
+                                        @Qualifier("slaveDataSource") DataSource slaveDataSource) {
         Map<Object, Object> targetDataSources = new HashMap<>();
         Map<Object, Object> targetDataSources = new HashMap<>();
+        targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
+
+        targetDataSources.put(DataSourceType.SLAVE.name(), slaveDataSource);
         targetDataSources.put(DataSourceType.SOP.name(), sopDataSource);
         targetDataSources.put(DataSourceType.SOP.name(), sopDataSource);
         return new DynamicDataSource(masterDataSource, targetDataSources);
         return new DynamicDataSource(masterDataSource, targetDataSources);
     }
     }
@@ -49,7 +59,7 @@ public class DataSourceConfig {
      */
      */
     @SuppressWarnings({ "rawtypes", "unchecked" })
     @SuppressWarnings({ "rawtypes", "unchecked" })
     @Bean
     @Bean
-    @ConditionalOnProperty(name = "spring.datasource.mysql.druid.statViewServlet.enabled", havingValue = "true")
+    @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true")
     public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties)
     public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties)
     {
     {
         // 获取web监控页面的参数
         // 获取web监控页面的参数

+ 4 - 4
fs-qw-voice/src/main/java/com/fs/framework/config/DruidConfig.java

@@ -30,7 +30,7 @@ package com.fs.framework.config;//package com.fs.framework.config;
 //public class DruidConfig
 //public class DruidConfig
 //{
 //{
 //    @Bean
 //    @Bean
-//    @ConfigurationProperties("spring.datasource.mysql.druid.master")
+//    @ConfigurationProperties("spring.datasource.druid.master")
 //    public DataSource masterDataSource(DruidProperties druidProperties)
 //    public DataSource masterDataSource(DruidProperties druidProperties)
 //    {
 //    {
 //        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
 //        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
@@ -38,8 +38,8 @@ package com.fs.framework.config;//package com.fs.framework.config;
 //    }
 //    }
 //
 //
 //    @Bean
 //    @Bean
-//    @ConfigurationProperties("spring.datasource.mysql.druid.slave")
-//    @ConditionalOnProperty(prefix = "spring.datasource.mysql.druid.slave", name = "enabled", havingValue = "true")
+//    @ConfigurationProperties("spring.datasource.druid.slave")
+//    @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
 //    public DataSource slaveDataSource(DruidProperties druidProperties)
 //    public DataSource slaveDataSource(DruidProperties druidProperties)
 //    {
 //    {
 //        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
 //        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
@@ -80,7 +80,7 @@ package com.fs.framework.config;//package com.fs.framework.config;
 //     */
 //     */
 //    @SuppressWarnings({ "rawtypes", "unchecked" })
 //    @SuppressWarnings({ "rawtypes", "unchecked" })
 //    @Bean
 //    @Bean
-//    @ConditionalOnProperty(name = "spring.datasource.mysql.druid.statViewServlet.enabled", havingValue = "true")
+//    @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true")
 //    public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties)
 //    public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties)
 //    {
 //    {
 //        // 获取web监控页面的参数
 //        // 获取web监控页面的参数

部分文件因文件數量過多而無法顯示