Kaynağa Gözat

Merge branch 'master' into 宣传活动

Long 1 hafta önce
ebeveyn
işleme
12cd74578b
100 değiştirilmiş dosya ile 2655 ekleme ve 502 silme
  1. 18 0
      fs-ad-api/src/main/java/com/fs/framework/config/RedisConfig.java
  2. 5 5
      fs-admin/src/main/java/com/fs/company/controller/CompanyController.java
  3. 81 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyStatisticsController.java
  4. 2 2
      fs-admin/src/main/java/com/fs/course/controller/FsCoursePlaySourceConfigController.java
  5. 14 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseWatchLogController.java
  6. 44 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseCategoryController.java
  7. 14 0
      fs-admin/src/main/java/com/fs/course/controller/qw/QwFsCourseWatchLogController.java
  8. 3 3
      fs-admin/src/main/java/com/fs/his/controller/FsCompanyController.java
  9. 1 17
      fs-admin/src/main/java/com/fs/his/controller/FsIntegralOrderController.java
  10. 47 6
      fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java
  11. 0 1
      fs-admin/src/main/java/com/fs/his/controller/FsTestTempItemController.java
  12. 7 1
      fs-admin/src/main/java/com/fs/his/task/Task.java
  13. 2 2
      fs-admin/src/main/java/com/fs/qw/controller/QwCompanyController.java
  14. 34 0
      fs-admin/src/main/java/com/fs/task/FsCompanyTask.java
  15. 26 3
      fs-admin/src/main/java/com/fs/web/controller/system/SysUserController.java
  16. 17 0
      fs-common-api/src/main/java/com/fs/framework/config/RedisConfig.java
  17. 10 1
      fs-common/src/main/java/com/fs/common/core/domain/entity/SysRole.java
  18. 11 0
      fs-common/src/main/java/com/fs/common/core/domain/entity/SysUser.java
  19. 10 0
      fs-company-app/src/main/java/com/fs/app/controller/AppBaseController.java
  20. 2 0
      fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  21. 19 0
      fs-company-app/src/main/java/com/fs/core/config/RedisConfig.java
  22. 14 5
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseAnswerLogsController.java
  23. 14 4
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseRedPacketLogController.java
  24. 85 2
      fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactController.java
  25. 19 0
      fs-company/src/main/java/com/fs/framework/config/RedisConfig.java
  26. 129 0
      fs-company/src/main/java/com/fs/hisStore/controller/FsIntegralGoodsController.java
  27. 182 0
      fs-company/src/main/java/com/fs/hisStore/controller/FsIntegralOrderController.java
  28. 1 1
      fs-company/src/main/resources/application.yml
  29. 18 0
      fs-doctor-app/src/main/java/com/fs/framework/config/RedisConfig.java
  30. 18 0
      fs-framework/src/main/java/com/fs/framework/config/RedisConfig.java
  31. 17 0
      fs-hospital/src/main/java/com/fs/framework/config/RedisConfig.java
  32. 2 2
      fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java
  33. 18 0
      fs-ipad-task/src/main/java/com/fs/framework/config/RedisConfig.java
  34. 18 0
      fs-live-app/src/main/java/com/fs/framework/config/RedisConfig.java
  35. 18 0
      fs-qw-api-msg/src/main/java/com/fs/framework/config/RedisConfig.java
  36. 18 0
      fs-qw-api/src/main/java/com/fs/framework/config/RedisConfig.java
  37. 19 0
      fs-qw-mq/src/main/java/com/fs/framework/config/RedisConfig.java
  38. 17 0
      fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java
  39. 271 35
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/AsyncCourseWatchFinishService.java
  40. 19 0
      fs-qw-task/src/main/java/com/fs/framework/config/RedisConfig.java
  41. 18 0
      fs-qw-voice/src/main/java/com/fs/framework/config/RedisConfig.java
  42. 1 1
      fs-qw-voice/src/main/resources/application.yml
  43. 18 0
      fs-qwhook-msg/src/main/java/com/fs/framework/config/RedisConfig.java
  44. 5 0
      fs-qwhook-sop/src/main/java/com/fs/app/controller/ApisQwSopController.java
  45. 11 2
      fs-qwhook-sop/src/main/java/com/fs/app/controller/QwUserController.java
  46. 18 0
      fs-qwhook-sop/src/main/java/com/fs/framework/config/RedisConfig.java
  47. 165 0
      fs-qwhook/src/main/java/com/fs/app/controller/ApisQwSopController.java
  48. 5 1
      fs-qwhook/src/main/java/com/fs/app/controller/QwSopController.java
  49. 11 2
      fs-qwhook/src/main/java/com/fs/app/controller/QwUserController.java
  50. 19 0
      fs-qwhook/src/main/java/com/fs/framework/config/RedisConfig.java
  51. 18 0
      fs-redis/src/main/java/com/fs/framework/config/RedisConfig.java
  52. 17 0
      fs-repeat-api/src/main/java/com/fs/framework/config/RedisConfig.java
  53. 1 35
      fs-service/src/main/java/com/fs/company/mapper/CompanyUserMapper.java
  54. 21 8
      fs-service/src/main/java/com/fs/company/mapper/CompanyUserRoleMapper.java
  55. 3 0
      fs-service/src/main/java/com/fs/company/service/ICompanyService.java
  56. 33 94
      fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java
  57. 0 2
      fs-service/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java
  58. 2 0
      fs-service/src/main/java/com/fs/company/vo/CompanyUserQwListVO.java
  59. 2 1
      fs-service/src/main/java/com/fs/company/vo/FsStoreOrderStatisticsVO.java
  60. 6 0
      fs-service/src/main/java/com/fs/config/ai/AiHostProper.java
  61. 6 1
      fs-service/src/main/java/com/fs/core/config/RedissonConfig.java
  62. 10 10
      fs-service/src/main/java/com/fs/core/utils/OrderCodeUtils.java
  63. 5 0
      fs-service/src/main/java/com/fs/course/config/CourseConfig.java
  64. 83 0
      fs-service/src/main/java/com/fs/course/domain/FsBlackTalent.java
  65. 2 0
      fs-service/src/main/java/com/fs/course/domain/FsUserCourseCategory.java
  66. 25 0
      fs-service/src/main/java/com/fs/course/domain/FsUserTalent.java
  67. 76 0
      fs-service/src/main/java/com/fs/course/mapper/FsBlackTalentMapper.java
  68. 1 2
      fs-service/src/main/java/com/fs/course/mapper/FsCourseAnswerLogsMapper.java
  69. 3 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseRedPacketLogMapper.java
  70. 0 2
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  71. 3 0
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseCategoryMapper.java
  72. 11 0
      fs-service/src/main/java/com/fs/course/mapper/FsUserTalentFollowMapper.java
  73. 5 0
      fs-service/src/main/java/com/fs/course/mapper/FsUserTalentMapper.java
  74. 25 0
      fs-service/src/main/java/com/fs/course/mapper/FsUserVideoMapper.java
  75. 3 0
      fs-service/src/main/java/com/fs/course/mapper/FsUserVideoTagsMapper.java
  76. 14 0
      fs-service/src/main/java/com/fs/course/param/FsBlackTalentAuditParam.java
  77. 1 0
      fs-service/src/main/java/com/fs/course/param/FsCoursePlaySourceConfigCreateParam.java
  78. 1 0
      fs-service/src/main/java/com/fs/course/param/FsCoursePlaySourceConfigEditParam.java
  79. 9 1
      fs-service/src/main/java/com/fs/course/param/FsCourseSendRewardUParam.java
  80. 1 0
      fs-service/src/main/java/com/fs/course/param/FsCourseWatchLogListParam.java
  81. 3 0
      fs-service/src/main/java/com/fs/course/param/FsUserCourseVideoAddKfUParam.java
  82. 10 0
      fs-service/src/main/java/com/fs/course/param/FsUserTalentFansParam.java
  83. 77 0
      fs-service/src/main/java/com/fs/course/service/IFsBlackTalentService.java
  84. 1 7
      fs-service/src/main/java/com/fs/course/service/IFsUserCompanyUserService.java
  85. 1 0
      fs-service/src/main/java/com/fs/course/service/IFsUserCourseCategoryService.java
  86. 11 0
      fs-service/src/main/java/com/fs/course/service/IFsUserTalentFollowService.java
  87. 10 0
      fs-service/src/main/java/com/fs/course/service/IFsUserTalentService.java
  88. 12 0
      fs-service/src/main/java/com/fs/course/service/IFsUserVideoService.java
  89. 2 0
      fs-service/src/main/java/com/fs/course/service/IFsUserVideoTagsService.java
  90. 126 0
      fs-service/src/main/java/com/fs/course/service/impl/FsBlackTalentServiceImpl.java
  91. 135 57
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseFinishTempServiceImpl.java
  92. 1 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseRedPacketLogServiceImpl.java
  93. 7 1
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseWatchLogServiceImpl.java
  94. 2 7
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCompanyUserServiceImpl.java
  95. 4 1
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseCategoryServiceImpl.java
  96. 1 1
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java
  97. 96 176
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  98. 24 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserTalentFollowServiceImpl.java
  99. 117 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserTalentServiceImpl.java
  100. 93 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserVideoServiceImpl.java

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

@@ -67,6 +67,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         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
     @SuppressWarnings(value = { "unchecked", "rawtypes" })

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

@@ -71,7 +71,7 @@ public class CompanyController extends BaseController
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if(!loginUser.isAdmin() && config.getIsBound() != null && config.getIsBound()){
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
             param.setDeptId(loginUser.getDeptId());
         }
         List<CompanyVO> list = companyService.selectCompanyVOList(param);
@@ -89,7 +89,7 @@ public class CompanyController extends BaseController
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if(!loginUser.isAdmin() && config.getIsBound() != null && config.getIsBound()){
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
             company.setDeptId(loginUser.getDeptId());
         }
         List<CompanyVO> list = companyService.selectCompanyVOList(company);
@@ -178,7 +178,7 @@ public class CompanyController extends BaseController
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if(!loginUser.isAdmin() && config.getIsBound() != null && config.getIsBound()){
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
             map.setDeptId(loginUser.getDeptId());
         }
         List<Company> list = companyService.selectCompanyList(map);
@@ -194,7 +194,7 @@ public class CompanyController extends BaseController
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if(!loginUser.isAdmin() && config.getIsBound() != null && config.getIsBound()){
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
             param.setDeptId(loginUser.getDeptId());
         }
         List<CompanyCrmVO> list = companyService.selectCompanyCrmDayCountList(param);
@@ -276,7 +276,7 @@ public class CompanyController extends BaseController
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if(!loginUser.isAdmin() && config.getIsBound() != null && config.getIsBound()){
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
             deptId = loginUser.getDeptId();
         }
         List<OptionsVO> list = companyService.selectAllCompanyList(deptId);

+ 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.vo.CrmCustomerStatisticsVO;
 import com.fs.crm.vo.CrmCustomerVisitStatisticsVO;
+import com.fs.his.service.IFsStoreAfterSalesService;
 import com.fs.his.service.IFsStoreOrderService;
 import com.fs.his.service.IFsStorePaymentService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -31,6 +32,7 @@ import org.springframework.web.bind.annotation.RestController;
 import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 /**
@@ -49,6 +51,10 @@ public class CompanyStatisticsController extends BaseController
 
     @Autowired
     private IFsStoreOrderService storeOrderService;
+
+    @Autowired
+    private IFsStoreAfterSalesService storeAfterSalesService;
+
     @Autowired
     private IFsStorePaymentService storePaymentService;
     @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")
     public R storeInquiryOrder(FsStoreStatisticsParam param)
@@ -244,6 +299,32 @@ public class CompanyStatisticsController extends BaseController
         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")
     public AjaxResult exportInquiryOrder(FsStoreStatisticsParam param)

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

@@ -58,7 +58,7 @@ public class FsCoursePlaySourceConfigController extends BaseController {
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
         Long userId = null;
         Long deptId = null;
-        if(!loginUser.isAdmin() && config.getIsBound() != null && config.getIsBound()){
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
             deptId = loginUser.getDeptId();
             if(config.getDept() == null || !config.getDept()){
                 userId = loginUser.getUserId();
@@ -148,7 +148,7 @@ public class FsCoursePlaySourceConfigController extends BaseController {
         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.getIsBound() != null && config.getIsBound()){
+        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){

+ 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.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.FsCourseWatchLogStatisticsListParam;
+import com.fs.course.vo.FsCourseOverVO;
 import com.fs.course.vo.FsCourseWatchLogListVO;
 import com.fs.course.vo.FsCourseWatchLogStatisticsListVO;
 import com.fs.qw.param.QwWatchLogStatisticsListParam;
@@ -164,4 +167,15 @@ public class FsCourseWatchLogController extends BaseController
     {
         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 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.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.system.service.ISysConfigService;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -38,6 +47,12 @@ public class FsUserCourseCategoryController extends BaseController
     @Autowired
     private IFsUserCourseCategoryService fsUserCourseCategoryService;
 
+    @Autowired
+    private TokenService tokenService;
+
+    @Autowired
+    private ISysConfigService configService;
+
     /**
      * 查询课堂分类列表
      */
@@ -45,6 +60,13 @@ public class FsUserCourseCategoryController extends BaseController
     @GetMapping("/list")
     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);
         return AjaxResult.success(list);
     }
@@ -57,6 +79,13 @@ public class FsUserCourseCategoryController extends BaseController
     @GetMapping("/export")
     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);
         ExcelUtil<FsUserCourseCategory> util = new ExcelUtil<FsUserCourseCategory>(FsUserCourseCategory.class);
         return util.exportExcel(list, "课堂分类数据");
@@ -80,6 +109,13 @@ public class FsUserCourseCategoryController extends BaseController
     @PostMapping
     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));
     }
 
@@ -119,6 +155,14 @@ public class FsUserCourseCategoryController extends BaseController
     @GetMapping("/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();
         return R.ok().put("data", list);
     }

+ 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.enums.BusinessType;
 import com.fs.common.exception.CustomException;
+import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.course.domain.FsCourseWatchLog;
+import com.fs.course.param.FsCourseOverParam;
 import com.fs.course.param.FsCourseWatchLogListParam;
 import com.fs.course.param.FsCourseWatchLogStatisticsListParam;
 import com.fs.course.param.PeriodStatisticCountParam;
 import com.fs.course.service.IFsCourseWatchLogService;
+import com.fs.course.vo.FsCourseOverVO;
 import com.fs.course.vo.FsCourseWatchLogListVO;
 import com.fs.course.vo.FsCourseWatchLogStatisticsListVO;
 import com.fs.qw.param.QwWatchLogStatisticsListParam;
@@ -150,4 +153,15 @@ public class QwFsCourseWatchLogController extends BaseController
         List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectListBytrainingCampId(param);
         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);
+    }
 }

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

@@ -81,7 +81,7 @@ public class FsCompanyController extends BaseController
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if(!loginUser.isAdmin() && config.getIsBound() != null && config.getIsBound()){
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
             company.setDeptId(loginUser.getDeptId());
         }
         List<CompanyVO> list = companyService.selectCompanyListVO(company);
@@ -96,7 +96,7 @@ public class FsCompanyController extends BaseController
         Long depId = null;
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if(!loginUser.isAdmin() && config.getIsBound() != null && config.getIsBound()){
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
             depId = loginUser.getDeptId();
         }
         List<OptionsVO> list = companyService.selectAllCompanyList(depId);
@@ -152,7 +152,7 @@ public class FsCompanyController extends BaseController
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if(!loginUser.isAdmin() && config.getIsBound() != null && config.getIsBound()){
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
             company.setDeptId(loginUser.getDeptId());
         }
         return companyService.insertCompany(company);

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

@@ -66,23 +66,7 @@ public class FsIntegralOrderController extends BaseController
     @GetMapping("/export")
     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);
     }
     /**
      * 发货

+ 47 - 6
fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java

@@ -11,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.SysUser;
 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.service.ICompanyMoneyLogsService;
 import com.fs.company.vo.CompanyStoreOrderMoneyLogsVO;
@@ -35,6 +32,7 @@ import com.fs.his.dto.ExpressInfoDTO;
 import com.fs.his.dto.StoreOrderExpressExportDTO;
 import com.fs.his.dto.TracesDTO;
 import com.fs.his.enums.FsStoreOrderLogEnum;
+import com.fs.his.enums.FsStoreOrderStatusEnum;
 import com.fs.his.enums.ShipperCodeEnum;
 import com.fs.his.param.FsFollowMsgParam;
 import com.fs.his.param.FsStoreOrderParam;
@@ -364,7 +362,11 @@ public class FsStoreOrderController extends BaseController
             moneyLogsMap.setBusinessId(order.getOrderId());
             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}")
@@ -420,9 +422,40 @@ public class FsStoreOrderController extends BaseController
     @PutMapping
     public AjaxResult edit(@RequestBody FsStoreOrder fsStoreOrder)
     {
+        AjaxResult error = moneyCheck(fsStoreOrder);
+        if (error != null) return error;
         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;
+    }
+
     /**
      * 修改订单
      */
@@ -583,7 +616,15 @@ public class FsStoreOrderController extends BaseController
     {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         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));
+        }
     }
 
     /**

+ 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.vo.FsTestTempItemListVO;
-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;

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

@@ -62,6 +62,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Component;
 
 import java.util.*;
+import java.util.concurrent.CompletableFuture;
 
 @Slf4j
 @Component("task")
@@ -555,9 +556,14 @@ public class Task {
         if (erpOrderService !=null && erpOrderService == dfOrderService){
             orders = fsStoreOrderMapper.selectShippedOrder();
             if(orders!=null&& !orders.isEmpty()){
+                List<CompletableFuture<Void>> futures = new ArrayList<>();
                 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();
             }
         }
     }

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

@@ -57,7 +57,7 @@ public class QwCompanyController extends BaseController
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if(!loginUser.isAdmin() && config.getIsBound() != null && config.getIsBound()){
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
             qwCompany.setCreateDeptId(loginUser.getDeptId());
             qwCompany.setCreateUserId(loginUser.getUserId());
         }
@@ -74,7 +74,7 @@ public class QwCompanyController extends BaseController
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        if(!loginUser.isAdmin() && config.getIsBound() != null && config.getIsBound()){
+        if(!loginUser.isAdmin() && config.getDept() != null && config.getDept()){
             deptId = loginUser.getDeptId();
             if(config.getDept() == null || !config.getDept()){
                 userId = loginUser.getUserId();

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

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

@@ -1,10 +1,14 @@
 package com.fs.web.controller.system;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 
+import com.fs.common.constant.HttpStatus;
 import com.fs.common.core.domain.R;
 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 org.apache.commons.lang3.ArrayUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -59,9 +63,28 @@ public class SysUserController extends BaseController
     @GetMapping("/list")
     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)

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

@@ -67,7 +67,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         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
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {

+ 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是 */
     private Integer isCheckPhone;
-
+    /** 是否可以查看地址全号 0否 1是 */
+    private Integer isCheckAddress;
     public SysRole()
     {
 
     }
 
+    public Integer getIsCheckAddress() {
+        return isCheckAddress;
+    }
+
+    public void setIsCheckAddress(Integer isCheckAddress) {
+        this.isCheckAddress = isCheckAddress;
+    }
+
     public SysRole(Long 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 */
     private Long roleId;
 
+    @Excel(name = "角色名称")
+    private List<String> roleName;
+
     public SysUser()
     {
 
     }
 
+    public List<String> getRoleName() {
+        return roleName;
+    }
+
+    public void setRoleName(List<String> roleName) {
+        this.roleName = roleName;
+    }
+
     public SysUser(Long userId)
     {
         this.userId = userId;

+ 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 org.springframework.beans.factory.annotation.Autowired;
 
+import java.util.concurrent.TimeUnit;
+
 
 public class AppBaseController {
 	@Autowired
@@ -27,8 +29,16 @@ public class AppBaseController {
 	public Long getCompanyId() {
 		String headValue =  ServletUtils.getRequest().getHeader("APPToken");
 		Claims claims=jwtUtils.getClaimByToken(headValue);
+		if (ObjectUtil.isEmpty(claims)){
+			throw new FSException("未授权,请先登录!");
+		}
 		String userId = claims.getSubject().toString();
 		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;
 	}
 	public String getUserId()

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

@@ -108,12 +108,14 @@ public class FsUserCourseVideoController extends AppBaseController {
     @GetMapping("/participationRecord")
     public ResponseResult<Object> participationRecord(@RequestParam Long videoId,
                                                       @RequestParam Integer type,
+                                                      @RequestParam(required = false) Long periodId,
                                                       @RequestParam(required = false) String keyword,
                                                       @RequestParam(required = false, defaultValue = "1") Integer pageNum,
                                                       @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
         log.debug("参与记录 videoId:{}, type:{}, keyword: {}, pageNum: {}, pageSize: {}", videoId, type, keyword, pageNum, pageSize);
         Map<String, Object> params = new HashMap<>();
         params.put("videoId", videoId);
+        params.put("periodId", periodId);
         params.put("type", type);
         params.put("keyword", keyword);
 

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

@@ -64,6 +64,25 @@ public class RedisConfig extends CachingConfigurerSupport
         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<>();

+ 14 - 5
fs-company/src/main/java/com/fs/company/controller/course/FsCourseAnswerLogsController.java

@@ -1,5 +1,7 @@
 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.constant.HttpStatus;
 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.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.config.CourseConfig;
 import com.fs.course.param.FsCourseAnswerLogsParam;
 import com.fs.course.service.IFsCourseAnswerLogsService;
 import com.fs.course.vo.FsCourseAnswerLogsListVO;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
+import com.fs.system.service.ISysConfigService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -38,6 +42,9 @@ public class FsCourseAnswerLogsController extends BaseController
 
     @Autowired
     private TokenService tokenService;
+
+    @Autowired
+    private ISysConfigService configService;
     /**
      * 查询答题日志列表
      */
@@ -48,11 +55,13 @@ public class FsCourseAnswerLogsController extends BaseController
         if (param.getPhoneMk() != null && param.getPhoneMk() != "") {
             param.setPhone(param.getPhoneMk());
         }
-
-//        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        // 如果他可以看两个销售公司就会查不出来
-//        param.setCompanyId( loginUser.getCompany().getCompanyId());
-
+        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()){
+            param.setCompanyId( loginUser.getCompany().getCompanyId());
+        }
         List<FsCourseAnswerLogsListVO> list = fsCourseAnswerLogsService.selectFsCourseAnswerLogsListVONew(param);
         TableDataInfo rspData = new TableDataInfo();
         rspData.setCode(HttpStatus.SUCCESS);

+ 14 - 4
fs-company/src/main/java/com/fs/company/controller/course/FsCourseRedPacketLogController.java

@@ -1,5 +1,7 @@
 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.RepeatSubmit;
 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.utils.ServletUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsCourseRedPacketLog;
 import com.fs.course.mapper.FsUserCourseMapper;
 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.his.utils.PhoneUtil;
 import com.fs.his.vo.OptionsVO;
+import com.fs.system.service.ISysConfigService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
@@ -45,7 +49,8 @@ public class FsCourseRedPacketLogController extends BaseController
     FsUserCourseVideoMapper fsUserCourseVideoMapper;
     @Autowired
     private TokenService tokenService;
-
+    @Autowired
+    private ISysConfigService configService;
     /**
      * 查询短链课程看课记录列表
      */
@@ -57,9 +62,14 @@ public class FsCourseRedPacketLogController extends BaseController
         if (fsCourseRedPacketLog.getPhoneMk() != null && fsCourseRedPacketLog.getPhoneMk() != "") {
             fsCourseRedPacketLog.setPhone(encryptPhone(fsCourseRedPacketLog.getPhoneMk()));
         }
-//        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-        // 如果他可以看两个销售公司就会查不出来
-//        fsCourseRedPacketLog.setCompanyId( loginUser.getCompany().getCompanyId());
+
+        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()){
+            fsCourseRedPacketLog.setCompanyId( loginUser.getCompany().getCompanyId());
+        }
 
         List<FsCourseRedPacketLogListPVO> list = fsCourseRedPacketLogService.selectFsCourseRedPacketLogListVO(fsCourseRedPacketLog);
         for (FsCourseRedPacketLogListPVO fsCourseRedPacketLogListPVO : list) {

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

@@ -21,6 +21,7 @@ import com.fs.crm.vo.CrmMyCustomerListQueryVO;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 import com.fs.his.service.IFsUserService;
+import com.fs.qw.domain.QwContactWay;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwTag;
 import com.fs.qw.param.*;
@@ -28,6 +29,7 @@ import com.fs.qw.service.*;
 import com.fs.qw.vo.QwExternalContactVO;
 import com.fs.qw.vo.QwFsUserVO;
 import com.fs.qw.vo.QwUserDelLossLogVO;
+import com.fs.voice.utils.StringUtil;
 import com.github.pagehelper.PageHelper;
 import com.google.gson.Gson;
 import com.google.gson.reflect.TypeToken;
@@ -79,6 +81,9 @@ public class QwExternalContactController extends BaseController
     @Autowired
     private CompanyDeptServiceImpl companyDeptService;
 
+    @Autowired
+    private IQwContactWayService qwContactWayService;
+
     /**
      * 查询企业微信客户列表
      */
@@ -86,8 +91,13 @@ public class QwExternalContactController extends BaseController
     @GetMapping("/list")
     public TableDataInfo list(QwExternalContactParam qwExternalContact)
     {
-        startPage();
         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());
         List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(qwExternalContact);
         list.forEach(item->{
@@ -105,11 +115,47 @@ public class QwExternalContactController extends BaseController
 
                 item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
             }
+
+            if (!StringUtil.strIsNullOrEmpty(item.getState()) && !wayList.isEmpty()) {
+                item.setState(item.getState()+"-"+getContactWayNameStream(item.getState(), wayList));
+            }
+
         });
 
         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")
     public AjaxResult test()
     {
@@ -154,6 +200,10 @@ public class QwExternalContactController extends BaseController
         qwExternalContact.setUserType(loginUser.getUser().getUserType());
         qwExternalContact.setCompanyId(loginUser.getCompany().getCompanyId());
 
+        QwContactWay qwContactWay=new QwContactWay();
+        qwContactWay.setCompanyId(loginUser.getCompany().getCompanyId());
+        List<QwContactWay> wayList = qwContactWayService.selectQwContactWayList(qwContactWay);
+
         startPage();
         List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(qwExternalContact);
         list.forEach(item->{
@@ -171,6 +221,11 @@ public class QwExternalContactController extends BaseController
 
                 item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
             }
+
+            if (!StringUtil.strIsNullOrEmpty(item.getState()) && !wayList.isEmpty()) {
+                item.setState(item.getState()+"-"+getContactWayNameStream(item.getState(), wayList));
+            }
+
         });
 
         return getDataTable(list);
@@ -183,8 +238,14 @@ public class QwExternalContactController extends BaseController
         if(qwExternalContact.getQwUserId()==null){
             return null;
         }
-        startPage();
         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());
         List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(qwExternalContact);
         list.forEach(item->{
@@ -202,6 +263,10 @@ public class QwExternalContactController extends BaseController
 
                 item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
             }
+
+            if (!StringUtil.strIsNullOrEmpty(item.getState()) && !wayList.isEmpty()) {
+                item.setState(item.getState()+"-"+getContactWayNameStream(item.getState(), wayList));
+            }
         });
 
         return getDataTable(list);
@@ -232,7 +297,13 @@ public class QwExternalContactController extends BaseController
         if (qwExternalContact.getCorpId()==null){
             return AjaxResult.success();
         }
+
         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());
         List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(qwExternalContact);
         list.forEach(item->{
@@ -250,6 +321,10 @@ public class QwExternalContactController extends BaseController
 
                 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);
         return util.exportExcel(list, "企业微信客户数据");
@@ -266,6 +341,10 @@ public class QwExternalContactController extends BaseController
         }
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         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);
 
@@ -284,6 +363,10 @@ public class QwExternalContactController extends BaseController
 
                 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);

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

@@ -56,6 +56,25 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         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, Boolean> redisTemplateForBoolean(RedisConnectionFactory connectionFactory) {
         RedisTemplate<String, Boolean> template = new RedisTemplate<>();

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

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

@@ -4,7 +4,7 @@ server:
 spring:
   profiles:
 #    active: druid-fcky-test
-    active: dev
+    active: druid-jnmy-test
 #    active: druid-jzzx-test
 #    active: druid-hdt
 #    active: druid-sxjz

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

@@ -68,6 +68,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         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
     @SuppressWarnings(value = { "unchecked", "rawtypes" })

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

@@ -68,6 +68,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         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
     @SuppressWarnings(value = { "unchecked", "rawtypes" })

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

@@ -69,7 +69,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         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
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {

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

@@ -92,8 +92,8 @@ public class SendMsg {
 
     private Map<String, FsCoursePlaySourceConfig> getMiniMap() {
         List<FsCoursePlaySourceConfig> list = fsCoursePlaySourceConfigService.list(new QueryWrapper<FsCoursePlaySourceConfig>().ne("type", 2).eq("is_del", 0));
-        log.info("获取到的小程序配置:{}", JSON.toJSONString(list));
-        log.info("获取到的小程序配置:{}", JSON.toJSONString(list));
+//        log.info("获取到的小程序配置:{}", JSON.toJSONString(list));
+//        log.info("获取到的小程序配置:{}", JSON.toJSONString(list));
         return PubFun.listToMapByGroupObject(list, FsCoursePlaySourceConfig::getAppid);
     }
 

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

@@ -68,6 +68,24 @@ public class RedisConfig extends CachingConfigurerSupport
         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
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {

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

@@ -67,6 +67,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         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
     @SuppressWarnings(value = { "unchecked", "rawtypes" })

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

@@ -68,6 +68,24 @@ public class RedisConfig extends CachingConfigurerSupport
         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<>();

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

@@ -92,6 +92,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         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) {

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

@@ -68,6 +68,25 @@ public class RedisConfig extends CachingConfigurerSupport
         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
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {

+ 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.common.core.domain.R;
 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.param.newfs.FsUserCourseAddCompanyUserParam;
 import com.fs.course.service.*;
@@ -76,6 +79,10 @@ public class CommonController {
 
     @Autowired
     private IFsCourseLinkService courseLinkService;
+    @Autowired
+    private FsCourseRedPacketLogMapper fsCourseRedPacketLogMapper;
+    @Autowired
+    private ICompanyService companyService;
 
     @Autowired
     private SopUserLogsMapper sopUserLogsMapper;
@@ -298,4 +305,14 @@ public class CommonController {
         }
         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 lombok.AllArgsConstructor;
 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.SendResult;
+import org.apache.rocketmq.common.message.MessageConst;
 import org.apache.rocketmq.spring.core.RocketMQTemplate;
+import org.apache.rocketmq.spring.support.RocketMQHeaders;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.messaging.support.MessageBuilder;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
 import java.util.Optional;
+import java.util.concurrent.*;
 
 @Slf4j
 @Service
@@ -36,68 +44,296 @@ public class AsyncCourseWatchFinishService {
     @Autowired
     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")
     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();
         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;
+            return ValidationResult.invalid();
         }
 
+        // 验证企业主体
         QwCompany qwCompany = iQwCompanyService.getQwCompanyByRedis(qwUserByRedis.getCorpId());
-
         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;
         }
 
-        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; }
     }
 
 }

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

@@ -68,6 +68,25 @@ public class RedisConfig extends CachingConfigurerSupport
         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
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {

+ 18 - 0
fs-qw-voice/src/main/java/com/fs/framework/config/RedisConfig.java

@@ -67,6 +67,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         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
     @SuppressWarnings(value = { "unchecked", "rawtypes" })

+ 1 - 1
fs-qw-voice/src/main/resources/application.yml

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

+ 18 - 0
fs-qwhook-msg/src/main/java/com/fs/framework/config/RedisConfig.java

@@ -68,6 +68,24 @@ public class RedisConfig extends CachingConfigurerSupport
         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
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {

+ 5 - 0
fs-qwhook-sop/src/main/java/com/fs/app/controller/ApisQwSopController.java

@@ -4,6 +4,7 @@ import com.fs.app.params.SopLogsEditParam;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.fastGpt.param.FastGptChatSessionParam;
 import com.fs.fastGpt.service.IFastGptChatSessionService;
 import com.fs.qw.domain.QwTagGroup;
 import com.fs.qw.param.SopMsgParam;
@@ -95,6 +96,10 @@ public class ApisQwSopController {
         return qwSopLogsService.deleteQwSopLogsByJsApi(param);
 
     }
+    @PostMapping("/artificialInfo")
+    public R artificialInfo(@RequestBody FastGptChatSessionParam sessionParam) {
+        return R.ok().put("type",fastGptChatSessionService.selectFastGptChatSessionArtificialType(sessionParam));
+    }
 
     @GetMapping("/getQwSopLogs")
     public R getQwSopLogs(SopMsgParam param) throws Exception {

+ 11 - 2
fs-qwhook-sop/src/main/java/com/fs/app/controller/QwUserController.java

@@ -97,9 +97,18 @@ public class QwUserController extends BaseController {
         if(qwExternalContactId == null) {
             throw new CustomException("企微外部联系人id不能为空!");
         }
+//        QwExternalContact qwExternalContact = qwExternalContactService.selectQwExternalContactById(qwExternalContactId);
+        QwExternalContactInfo contactInfo = qwExternalContactInfoService.selectQwExternalContactInfoByExternalContactId(qwExternalContactId);
+        if (contactInfo==null){
 
-        QwExternalContactInfo qwExternalContactInfo = qwExternalContactInfoService.selectQwExternalContactInfoByExternalContactId(qwExternalContactId);
-        return R.ok().put("data",qwExternalContactService.selectQwExternalContactById(qwExternalContactId)).put("moreInfo",qwExternalContactInfo);
+            contactInfo = new QwExternalContactInfo();
+            contactInfo.setExternalContactId(qwExternalContactId);
+            qwExternalContactInfoService.insertQwExternalContactInfo(contactInfo);
+
+        }
+
+//        return R.ok().put("data",qwExternalContact).put("moreInfo",contactInfo);
+        return R.ok().put("moreInfo",contactInfo);
     }
 
     @PostMapping("/updateQwUserInfo")

+ 18 - 0
fs-qwhook-sop/src/main/java/com/fs/framework/config/RedisConfig.java

@@ -67,6 +67,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         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
     @SuppressWarnings(value = { "unchecked", "rawtypes" })

+ 165 - 0
fs-qwhook/src/main/java/com/fs/app/controller/ApisQwSopController.java

@@ -0,0 +1,165 @@
+package com.fs.app.controller;
+
+import com.fs.app.params.SopLogsEditParam;
+import com.fs.common.BeanCopyUtils;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.fastGpt.param.FastGptChatSessionParam;
+import com.fs.fastGpt.service.IFastGptChatSessionService;
+import com.fs.qw.domain.QwTagGroup;
+import com.fs.qw.param.SopMsgParam;
+import com.fs.qw.param.sidebar.ExternalContactInfoParam;
+import com.fs.qw.param.sidebar.TagGroupListParam;
+import com.fs.qw.param.sidebar.TagGroupUpdateParam;
+import com.fs.qw.result.QwExternalContactByQwResult;
+import com.fs.qw.service.IQwExternalContactService;
+import com.fs.qw.service.IQwTagGroupService;
+import com.fs.qw.vo.QwTagGroupListVO;
+import com.fs.qw.vo.sidebar.ExternalContactInfoVO;
+import com.fs.qw.vo.sidebar.ExternalContactTagVO;
+import com.fs.sop.domain.QwSopLogs;
+import com.fs.sop.params.GetQwSopLogsByJsApiParam;
+import com.fs.sop.params.SendSopParamDetailsC;
+import com.fs.sop.service.IQwSopLogsService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+
+@RestController
+@RequestMapping("/apis/app/qwSop")
+public class ApisQwSopController {
+
+    @Autowired
+    RedisCache redisCache;
+    @Autowired
+    IFastGptChatSessionService fastGptChatSessionService;
+    @Autowired
+    private IQwSopLogsService qwSopLogsService;
+
+    @Autowired
+    private IQwExternalContactService qwExternalContactService;
+
+    @Autowired
+    private IQwTagGroupService qwTagGroupService;
+
+    /**
+     * 更新AI发送状态
+     */
+    @PostMapping("/updateQwSopLogs")
+    public R updateCourseSopLogs(@RequestBody SopLogsEditParam param){
+
+        try {
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            QwSopLogs qwSopLogs=new QwSopLogs();
+            qwSopLogs.setId(param.getId());
+            qwSopLogs.setReceivingStatus(param.getReceivingStatus());
+            qwSopLogs.setSendStatus(param.getSendStatus());
+            qwSopLogs.setRealSendTime(sdf.format(new Date()));
+            qwSopLogs.setRemark(param.getRemark());
+            qwSopLogsService.updateQwSopLogsSendType(qwSopLogs);
+                return  R.ok();
+        }catch (Exception e){
+                return R.error("更新失败");
+            }
+
+    }
+
+    //主动获取发送信息
+    @PostMapping("/getQwSopLogsByJsApi")
+    public R getQwSopLogsByJsApi(@RequestBody GetQwSopLogsByJsApiParam param) {
+
+        SendSopParamDetailsC qwSopLogsByJsApi = qwSopLogsService.getQwSopLogsByJsApi(param);
+
+        return R.ok().put("data",qwSopLogsByJsApi);
+    }
+
+    //获取销售的某个联系人
+    @GetMapping("/getExternalContactByAppKey/{appKey}")
+    public R getExternalContactByAppKey(@PathVariable("appKey") String appKey) {
+
+        QwExternalContactByQwResult result=qwSopLogsService.getExternalContactByAppKey(appKey);
+
+        return R.ok().put("data",result);
+    }
+
+    //清除不是当前员工的 外部联系以及营期
+    @PostMapping("/deleteQwSopLogsByJsApi")
+    public R deleteQwSopLogsByJsApi(@RequestBody GetQwSopLogsByJsApiParam param) {
+
+        return qwSopLogsService.deleteQwSopLogsByJsApi(param);
+
+    }
+    @PostMapping("/artificialInfo")
+    public R artificialInfo(@RequestBody FastGptChatSessionParam sessionParam) {
+        return R.ok().put("type",fastGptChatSessionService.selectFastGptChatSessionArtificialType(sessionParam));
+    }
+
+    @GetMapping("/getQwSopLogs")
+    public R getQwSopLogs(SopMsgParam param) throws Exception {
+        //获取记录
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<QwSopLogs> list = qwSopLogsService.selectQwSopLogsListVO(param);
+        PageInfo<QwSopLogs> listPageInfo=new PageInfo<>(list);
+        return R.ok().put("data",listPageInfo);
+    }
+
+    @GetMapping("/externalContact")
+    @ApiOperation("获取侧边栏外部联系人信息")
+    public R getExternalContactInfo(@RequestParam(value = "qwExternalContactId") Long qwExternalContactId) {
+        ExternalContactInfoVO externalContactInfo = qwExternalContactService.getExternalContactInfo(qwExternalContactId);
+        return R.ok().put("data", externalContactInfo);
+    }
+
+
+    @GetMapping("/externalContact/tag")
+    @ApiOperation("获取侧边栏外部联系人标签")
+    public R getExternalContactTag(@RequestParam(value = "qwExternalContactId") Long qwExternalContactId) {
+        List<ExternalContactTagVO> tagList = qwExternalContactService.getExternalContactTag(qwExternalContactId);
+        return R.ok().put("data", tagList);
+    }
+
+    @PutMapping("/externalContact")
+    @ApiOperation("编辑外部联系人信息")
+    public R updateExternalContactInfo(@RequestBody ExternalContactInfoParam param) {
+        return qwExternalContactService.updateExternalContactInfo(param);
+    }
+
+    @GetMapping("/tagGroupList")
+    @ApiOperation("获取所有标签组和其下标签")
+    public R getTagGroupList(TagGroupListParam param) {
+        QwTagGroup qwTagGroup = new QwTagGroup();
+        BeanCopyUtils.copy(param, qwTagGroup);
+        qwTagGroup.setName(param.getTagName());
+
+        PageHelper.startPage(qwTagGroup.getPageNum(), qwTagGroup.getPageSize());
+        List<QwTagGroupListVO> list = qwTagGroupService.selectQwGroupTagList(qwTagGroup);
+
+        PageInfo<QwTagGroupListVO> result = new PageInfo<>(list);
+        return R.ok().put("data", result);
+    }
+
+//    @GetMapping("/searchTags")
+//    @ApiOperation("搜索标签-跟管理端保持一致")
+//    public R searchTagList(QwTagParam param) {
+//        List<QwTagGroupListVO> list = qwTagService.searchTags(param);
+//        return R.ok().put("data", list);
+//    }
+
+    @PutMapping("/externalContact/tag")
+    @ApiOperation("编辑标签")
+    public R updateExternalContactTag(@RequestBody TagGroupUpdateParam param) {
+        int i = qwExternalContactService.updateExternalContactTag(param);
+        if (i > 0) {
+            return R.ok();
+        }
+        return R.error();
+    }
+
+}

+ 5 - 1
fs-qwhook/src/main/java/com/fs/app/controller/QwSopController.java

@@ -1,6 +1,7 @@
 package com.fs.app.controller;
 
 import com.alibaba.fastjson.JSON;
+import com.fs.fastGpt.param.FastGptChatSessionParam;
 import com.fs.fastGpt.param.SendHookAIParam;
 import com.fs.fastGpt.service.IFastGptChatSessionService;
 import com.fs.qw.param.QwLoginParam;
@@ -69,7 +70,10 @@ public class QwSopController {
         return R.ok("已关闭");
     }
 
-
+    @PostMapping("/artificialInfo")
+    public R artificialInfo(@RequestBody FastGptChatSessionParam sessionParam) {
+        return R.ok().put("type",fastGptChatSessionService.selectFastGptChatSessionArtificialType(sessionParam));
+    }
     /**
      * 更新AI发送状态
      */

+ 11 - 2
fs-qwhook/src/main/java/com/fs/app/controller/QwUserController.java

@@ -99,9 +99,18 @@ public class QwUserController extends BaseController {
         if(qwExternalContactId == null) {
             throw new CustomException("企微外部联系人id不能为空!");
         }
+//        QwExternalContact qwExternalContact = qwExternalContactService.selectQwExternalContactById(qwExternalContactId);
+        QwExternalContactInfo contactInfo = qwExternalContactInfoService.selectQwExternalContactInfoByExternalContactId(qwExternalContactId);
+        if (contactInfo==null){
 
-        QwExternalContactInfo qwExternalContactInfo = qwExternalContactInfoService.selectQwExternalContactInfoByExternalContactId(qwExternalContactId);
-        return R.ok().put("data",qwExternalContactService.selectQwExternalContactById(qwExternalContactId)).put("moreInfo",qwExternalContactInfo);
+            contactInfo = new QwExternalContactInfo();
+            contactInfo.setExternalContactId(qwExternalContactId);
+            qwExternalContactInfoService.insertQwExternalContactInfo(contactInfo);
+
+        }
+
+//        return R.ok().put("data",qwExternalContact).put("moreInfo",contactInfo);
+        return R.ok().put("moreInfo",contactInfo);
     }
 
     @PostMapping("/updateQwUserInfo")

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

@@ -68,6 +68,25 @@ public class RedisConfig extends CachingConfigurerSupport
         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
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {

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

@@ -68,6 +68,24 @@ public class RedisConfig extends CachingConfigurerSupport
         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
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {

+ 17 - 0
fs-repeat-api/src/main/java/com/fs/framework/config/RedisConfig.java

@@ -92,7 +92,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         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<>();

+ 1 - 35
fs-service/src/main/java/com/fs/company/mapper/CompanyUserMapper.java

@@ -151,41 +151,7 @@ public interface CompanyUserMapper
     @Select("select * from  qw_user  where corp_id=#{corpId} and company_id=#{companyId}")
     List<QwUserVO> selectCompanyQwUserList(@Param("corpId") String corpId,@Param("companyId")Long companyId);
 
-    @Select({"<script> " +
-            "select u.*, d.dept_name, d.leader from company_user u\n" +
-            "        left join company_dept d on u.dept_id = d.dept_id\n" +
-            "        where u.del_flag = '0'\n" +
-            "        <if test=\"userName != null and userName != ''\">\n" +
-            "            AND u.user_name like concat('%', #{userName}, '%')\n" +
-            "        </if>\n" +
-            "\n" +
-            "        <if test=\"nickName != null and nickName != ''\">\n" +
-            "            AND u.nick_name like concat( #{nickName}, '%')\n" +
-            "        </if>\n" +
-            "        <if test=\"companyId != null and companyId != ''\">\n" +
-            "            AND u.company_id = #{companyId}\n" +
-            "        </if>\n" +
-            "        <if test=\"status != null and status != ''\">\n" +
-            "            AND u.status = #{status}\n" +
-            "        </if>\n" +
-            "        <if test=\"qwStatus != null \">\n" +
-            "            AND u.qw_status = #{qwStatus} \n" +
-            "        </if>\n" +
-            "        <if test=\"phonenumber != null and phonenumber != ''\">\n" +
-            "            AND u.phonenumber like concat('%', #{phonenumber}, '%')\n" +
-            "        </if>\n" +
-            "        <if test=\"beginTime != null and beginTime != ''\"><!-- 开始时间检索 -->\n" +
-            "            AND date_format(u.create_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d')\n" +
-            "        </if>\n" +
-            "        <if test=\"endTime != null and endTime != ''\"><!-- 结束时间检索 -->\n" +
-            "            AND date_format(u.create_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d')\n" +
-            "        </if>\n" +
-            "        <if test=\"deptId != null and deptId != 0\">\n" +
-            "            AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM company_dept t WHERE find_in_set(#{deptId}, ancestors) ))\n" +
-            "        </if>\n" +
-            "        <!-- 数据范围过滤 -->\n" +
-            "        ${params.dataScope}"+
-            "</script>"})
+
     List<CompanyUserQwListVO> selectCompanyUserQwListVO(CompanyUserQwParam user);
 
 

+ 21 - 8
fs-service/src/main/java/com/fs/company/mapper/CompanyUserRoleMapper.java

@@ -1,20 +1,33 @@
 package com.fs.company.mapper;
 
 import com.fs.company.domain.CompanyUserRole;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
 
 import java.util.List;
 
 /**
  * 用户和角色关联Mapper接口
- * 
+ *
  * @author fs
  * @date 2021-05-25
  */
-public interface CompanyUserRoleMapper 
+public interface CompanyUserRoleMapper
 {
+    @Select("\n" +
+            "SELECT \n" +
+            "   cur.user_id\n" +
+            "FROM \n" +
+            "    company_user_role cur\n" +
+            "JOIN \n" +
+            "    company_role cr ON cur.role_id = cr.role_id and cr.role_key = 'admin'\n" +
+            "WHERE \n" +
+            "    cur.user_id = #{userId} " +
+            "LIMIT 1")
+    public Long companyUserIsAdmin(@Param("userId") Long userId);
     /**
      * 查询用户和角色关联
-     * 
+     *
      * @param userId 用户和角色关联ID
      * @return 用户和角色关联
      */
@@ -22,7 +35,7 @@ public interface CompanyUserRoleMapper
 
     /**
      * 查询用户和角色关联列表
-     * 
+     *
      * @param companyUserRole 用户和角色关联
      * @return 用户和角色关联集合
      */
@@ -30,7 +43,7 @@ public interface CompanyUserRoleMapper
 
     /**
      * 新增用户和角色关联
-     * 
+     *
      * @param companyUserRole 用户和角色关联
      * @return 结果
      */
@@ -38,7 +51,7 @@ public interface CompanyUserRoleMapper
 
     /**
      * 修改用户和角色关联
-     * 
+     *
      * @param companyUserRole 用户和角色关联
      * @return 结果
      */
@@ -46,7 +59,7 @@ public interface CompanyUserRoleMapper
 
     /**
      * 删除用户和角色关联
-     * 
+     *
      * @param userId 用户和角色关联ID
      * @return 结果
      */
@@ -54,7 +67,7 @@ public interface CompanyUserRoleMapper
 
     /**
      * 批量删除用户和角色关联
-     * 
+     *
      * @param userIds 需要删除的数据ID
      * @return 结果
      */

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

@@ -1,6 +1,7 @@
 package com.fs.company.service;
 
 import java.math.BigDecimal;
+import java.time.LocalTime;
 import java.util.List;
 
 import com.fs.common.core.domain.R;
@@ -159,4 +160,6 @@ public interface ICompanyService
      * @return
      */
     List<CompanyUser> selectCompanyListByIds(String result);
+
+    void subtractCompanyMoneyHourse(BigDecimal money, Long companyId, LocalTime start, LocalTime end);
 }

+ 33 - 94
fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java

@@ -1,9 +1,11 @@
 package com.fs.company.service.impl;
 
 import java.math.BigDecimal;
+import java.time.LocalTime;
 import java.util.*;
 import java.util.stream.Collectors;
 
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.core.domain.R;
@@ -820,10 +822,17 @@ public class CompanyServiceImpl implements ICompanyService
                 .collect(Collectors.toList());
     }
 
+    @Autowired
+    private CompanyUserRoleMapper companyUserRoleMapper;
     @Override
     public List<DeptDataVO> getDeptData(Long companyId, Long currentCompanyUserId, Long currentDeptId) {
         List<DeptDataVO> result = new ArrayList<>();
 
+        Long isAdmin = companyUserRoleMapper.companyUserIsAdmin(currentCompanyUserId);
+        logger.info("当前用户 {} 是公司admin 返回公司所有部门树",currentDeptId);
+        if(isAdmin!=null){
+            return getDeptData(companyId);
+        }
         // 1. 获取所有部门数据
         List<CompanyDept> allCompanyDepts = companyDeptMapper.queryDeptDataAll();
 
@@ -1062,34 +1071,6 @@ public class CompanyServiceImpl implements ICompanyService
         return companyNode;
     }
 
-    /**
-     * 构建公司节点,包含其下属多级部门和用户
-     */
-    private DeptDataVO buildCompanyNode(Company company,
-                                        Map<Long, List<CompanyUser>> companyUserGroupByDeptId,
-                                        Map<Long, List<CompanyDept>> companyDeptGroupByCompanyId,
-                                        Map<Long, List<CompanyDept>> deptGroupByParentId,
-                                        Long currentDeptId,
-                                        Long currentCompanyUserId
-                                        ) {
-        DeptDataVO companyNode = new DeptDataVO();
-        companyNode.setLabel(company.getCompanyName());
-        companyNode.setId("company_"+company.getCompanyId());
-
-        // 获取公司下的顶级部门(parentId为null或为公司ID的部门)
-        List<CompanyDept> topLevelDepts = companyDeptGroupByCompanyId.get(company.getCompanyId());
-        if (topLevelDepts != null) {
-            topLevelDepts = topLevelDepts.stream()
-                    .filter(dept -> dept.getParentId() == null || dept.getParentId().equals(0L))
-                    .collect(Collectors.toList());
-        }
-
-        List<DeptDataVO> deptDataList = buildDeptTree(topLevelDepts, companyUserGroupByDeptId, deptGroupByParentId,currentDeptId,currentCompanyUserId);
-        companyNode.setChildren(deptDataList.isEmpty() ? null : deptDataList);
-
-        return companyNode;
-    }
-
     /**
      * 递归构建部门树
      */
@@ -1134,72 +1115,6 @@ public class CompanyServiceImpl implements ICompanyService
 
         return result;
     }
-    /**
-     * 递归构建部门树
-     */
-    /**
-     *
-     * @param depts
-     * @param companyUserGroupByDeptId
-     * @param deptGroupByParentId
-     * @param currentDeptId 当前部门id
-     * @param currentCompanyUserId 当前销售id
-     * @return
-     */
-    private List<DeptDataVO> buildDeptTree(List<CompanyDept> depts,
-                                           Map<Long, List<CompanyUser>> companyUserGroupByDeptId,
-                                           Map<Long, List<CompanyDept>> deptGroupByParentId,
-                                           Long currentDeptId,
-                                           Long currentCompanyUserId) {
-        if (depts == null || depts.isEmpty()) {
-            return new ArrayList<>();
-        }
-
-        List<DeptDataVO> result = new ArrayList<>();
-
-        for (CompanyDept dept : depts) {
-            DeptDataVO deptNode = new DeptDataVO();
-            deptNode.setLabel(dept.getDeptName());
-            deptNode.setId("dept_"+dept.getDeptId());
-
-            List<DeptDataVO> children = new ArrayList<>();
-
-            // 1. 添加子部门(递归)
-            List<CompanyDept> childDepts = deptGroupByParentId.get(dept.getDeptId());
-            if (childDepts != null && !childDepts.isEmpty()) {
-                List<DeptDataVO> childDeptNodes = buildDeptTree(childDepts, companyUserGroupByDeptId, deptGroupByParentId);
-                children.addAll(childDeptNodes);
-            }
-
-            // 2. 添加部门下的用户
-            List<CompanyUser> deptUsers = companyUserGroupByDeptId.get(dept.getDeptId());
-            if (deptUsers != null && !deptUsers.isEmpty()) {
-                for (CompanyUser user : deptUsers) {
-                    // 如果是销售当前部门,不显示同级其他销售
-                    if(ObjectUtils.equals(dept.getDeptId(),currentDeptId)) {
-                        if(ObjectUtils.equals(user.getUserId(),currentCompanyUserId)) {
-                            DeptDataVO userNode = new DeptDataVO();
-                            userNode.setLabel(user.getNickName()+"_"+user.getUserName());
-                            userNode.setId("user_"+user.getUserId());
-                            userNode.setChildren(null);
-                            children.add(userNode);
-                        }
-                    } else {
-                        DeptDataVO userNode = new DeptDataVO();
-                        userNode.setLabel(user.getNickName()+"_"+user.getUserName());
-                        userNode.setId("user_"+user.getUserId());
-                        userNode.setChildren(null);
-                        children.add(userNode);
-                    }
-                }
-            }
-
-            deptNode.setChildren(children.isEmpty() ? null : children);
-            result.add(deptNode);
-        }
-
-        return result;
-    }
 
     @Override
     @Transactional
@@ -1333,4 +1248,28 @@ public class CompanyServiceImpl implements ICompanyService
     public List<CompanyUser> selectCompanyListByIds(String result) {
         return companyMapper.selectCompanyListByIds(result);
     }
+    @Override
+    @Transactional
+    public void subtractCompanyMoneyHourse(BigDecimal money, Long companyId, LocalTime start, LocalTime end) {
+        if(companyId!=null&&companyId>0){
+            Company company=companyMapper.selectCompanyByIdForUpdate(companyId);
+            if(company!=null){
+                logger.info("每个小时扣除红包金额:{}", money);
+                company.setMoney(company.getMoney().subtract(money));
+                companyMapper.updateCompany(company);
+                CompanyMoneyLogs log=new CompanyMoneyLogs();
+                log.setCompanyId(company.getCompanyId());
+                if(end != null && start.getHour() != end.getHour()){
+                    log.setRemark("扣除"+start.getHour() + "到" + end.getHour() +"点红包金额");
+                }else{
+                    log.setRemark("扣除"+start.getHour()+"点红包金额");
+                }
+                log.setMoney(money.multiply(new BigDecimal(-1)));
+                log.setLogsType(15);
+                log.setBalance(company.getMoney());
+                log.setCreateTime(new Date());
+                moneyLogsMapper.insertCompanyMoneyLogs(log);
+            }
+        }
+    }
 }

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

@@ -108,8 +108,6 @@ public class CompanyUserServiceImpl implements ICompanyUserService
     @Autowired
     private ICompanyService companyService;
 
-    @Autowired
-    private IQwExternalContactService qwExternalContactService;
 
     @Autowired
     private IQwUserService qwUserService;

+ 2 - 0
fs-service/src/main/java/com/fs/company/vo/CompanyUserQwListVO.java

@@ -93,6 +93,8 @@ public class CompanyUserQwListVO extends BaseEntity {
     /** 角色对象 */
     private List<CompanyRole> roles;
 
+    /** 角色名称 */
+    private List<String> roleNames;
     /** 角色组 */
     private Long[] roleIds;
 

+ 2 - 1
fs-service/src/main/java/com/fs/company/vo/FsStoreOrderStatisticsVO.java

@@ -4,6 +4,7 @@ import com.fs.common.annotation.Excel;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.math.BigDecimal;
 
 @Data
 public class FsStoreOrderStatisticsVO implements Serializable
@@ -13,7 +14,7 @@ public class FsStoreOrderStatisticsVO implements Serializable
     @Excel(name = "订单数")
     Integer orderCount;
     @Excel(name = "订单金额")
-    Integer payPrice;
+    BigDecimal payPrice;
 
 
 

+ 6 - 0
fs-service/src/main/java/com/fs/config/ai/AiHostProper.java

@@ -16,4 +16,10 @@ public class AiHostProper {
     @Value("${ipad.voiceApi}")
     private String voiceApi;
 
+
+    @Value("${ipad.commonApi}")
+    private String commonApi;
+
+
+
 }

+ 6 - 1
fs-service/src/main/java/com/fs/core/config/RedissonConfig.java

@@ -19,6 +19,9 @@ public class RedissonConfig {
     @Value("${spring.redis.host}")
     private String host;
 
+    @Value("${spring.redis.database}")
+    private int database;
+
     @Bean(destroyMethod = "shutdown")
     public RedissonClient redissonClient() {
         String address = "redis://" + host + ":" + port;
@@ -26,7 +29,9 @@ public class RedissonConfig {
         config.useSingleServer()
                 .setAddress(address) // 设置连接地址
                 .setConnectionMinimumIdleSize(10) // 最小空闲连接数
-                .setConnectionPoolSize(64); // 最大连接数
+                .setConnectionPoolSize(64) // 最大连接数
+                .setDatabase(database); //数据库
+
         if (null!=password&&!"".equals(password)) {
             config.useSingleServer().setPassword(password);
         }

+ 10 - 10
fs-service/src/main/java/com/fs/core/utils/OrderCodeUtils.java

@@ -44,16 +44,16 @@ public class OrderCodeUtils {
 
     }
     public static String getOrderSn(){
-//        String url= FSConfig.getCommonApi()+ "/app/common/genOrderCode";
-////        String url= "42.194.245.189:8010/app/common/genOrderCode";
-//        String json = HttpRequest.get(url)
-//                .execute().body();
-//        OrderCodeVO vo= JSONUtil.toBean(json, OrderCodeVO.class);
-//        if(vo.getCode()==200){
-//            return vo.getOrderCode();
-//        }
-//        else return null;
-        return OrderCodeUtils.genOrderSn();
+        String url= FSConfig.getCommonApi()+ "/app/common/genOrderCode";
+//        String url= "42.194.245.189:8010/app/common/genOrderCode";
+        String json = HttpRequest.get(url)
+                .execute().body();
+        OrderCodeVO vo= JSONUtil.toBean(json, OrderCodeVO.class);
+        if(vo.getCode()==200){
+            return vo.getOrderCode();
+        }
+        else return null;
+        //return OrderCodeUtils.genOrderSn();
 
     }
 

+ 5 - 0
fs-service/src/main/java/com/fs/course/config/CourseConfig.java

@@ -62,6 +62,11 @@ public class CourseConfig implements Serializable {
      * 是否绑定
      */
     private Boolean isBound;
+
+    /**
+     * 是否显示企微二维码
+     */
+    private Boolean showQwCode;
     private Boolean dept;
     /**
      * 是否单销售观看(只能在第一次绑定的销售头上看课)

+ 83 - 0
fs-service/src/main/java/com/fs/course/domain/FsBlackTalent.java

@@ -0,0 +1,83 @@
+package com.fs.course.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ * 达人或视频举报拉黑功能对象 fs_black_talent
+ *
+ * @author fs
+ * @date 2025-08-17
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsBlackTalent extends BaseEntity{
+
+    /** $column.columnComment */
+    private Long id;
+
+    /** 用户id */
+    @Excel(name = "用户id")
+    private Long userId;
+
+    /** 达人id */
+    @Excel(name = "达人id")
+    private Long talentId;
+
+    /** 类型1:拉黑,2:举报 */
+    @Excel(name = "类型1:拉黑,2:举报")
+    private String type;
+
+    /** 举报说明(拉黑为空) */
+    @Excel(name = "举报说明", readConverterExp = "拉=黑为空")
+    private String reportDesc;
+
+    /** 是否审核-1:驳回,0:待审核,1:通过(拉黑不需要审核) */
+    @Excel(name = "是否审核-1:驳回,0:待审核,1:通过", readConverterExp = "拉=黑不需要审核")
+    private String isAudit;
+
+    /** 审核时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "审核时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date auditTime;
+
+    /** 审核人 */
+    @Excel(name = "审核人")
+    private Long auditUser;
+
+    /** 审核说明 */
+    @Excel(name = "审核说明")
+    private String auditDesc;
+
+    /** 创建时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date creatTime;
+
+    /** 短视频id */
+    @Excel(name = "短视频id")
+    private Long videoId;
+
+    /** 1:达人,2:短视频 */
+    @Excel(name = "1:达人,2:短视频")
+    private String style;
+
+    @Excel(name = "联系方式")
+    private String phone;
+
+    /** 图片地址 */
+    @Excel(name = "图片地址")
+    private String urls;
+
+    @Excel(name = "投诉模板id")
+    private Long templateId;
+    //交易截图
+    private String tradeImage;
+
+
+}

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

@@ -40,4 +40,6 @@ public class FsUserCourseCategory extends BaseEntity
 
     private String pic;
 
+
+    private Long userId;
 }

+ 25 - 0
fs-service/src/main/java/com/fs/course/domain/FsUserTalent.java

@@ -111,4 +111,29 @@ public class FsUserTalent extends BaseEntity
     @Excel(name = "已提现佣金")
     private BigDecimal extractMoney;
 
+    /** 达人类别1:普通达人2:带货达人 */
+    @Excel(name = "达人类别1:普通达人2:带货达人")
+    private String talentType;
+
+    @Excel(name = "状态1正常状态,2禁用状态")
+    private Long status;
+
+    @Excel(name = "生日")
+    private String birthDay;
+
+    @Excel(name = "背景")
+    private String backGround;
+
+    /** 收货人所在省 */
+    @Excel(name = "收货人所在省")
+    private String province;
+
+    /** 收货人所在市 */
+    @Excel(name = "收货人所在市")
+    private String city;
+
+    /** 收货人所在区 */
+    @Excel(name = "收货人所在区")
+    private String district;
+
 }

+ 76 - 0
fs-service/src/main/java/com/fs/course/mapper/FsBlackTalentMapper.java

@@ -0,0 +1,76 @@
+package com.fs.course.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.course.domain.FsBlackTalent;
+import com.fs.course.param.FsBlackTalentAuditParam;
+import com.fs.course.vo.FsBlackTalentPVO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 达人或视频举报拉黑功能Mapper接口
+ * 
+ * @author fs
+ * @date 2025-08-17
+ */
+public interface FsBlackTalentMapper extends BaseMapper<FsBlackTalent>{
+    /**
+     * 查询达人或视频举报拉黑功能
+     * 
+     * @param id 达人或视频举报拉黑功能主键
+     * @return 达人或视频举报拉黑功能
+     */
+    FsBlackTalent selectFsBlackTalentById(Long id);
+
+    /**
+     * 查询达人或视频举报拉黑功能列表
+     * 
+     * @param fsBlackTalent 达人或视频举报拉黑功能
+     * @return 达人或视频举报拉黑功能集合
+     */
+    List<FsBlackTalent> selectFsBlackTalentList(FsBlackTalent fsBlackTalent);
+
+    List<FsBlackTalentPVO> selectFsBlackTalentPVOList(FsBlackTalent fsBlackTalent);
+    /**
+     * 新增达人或视频举报拉黑功能
+     * 
+     * @param fsBlackTalent 达人或视频举报拉黑功能
+     * @return 结果
+     */
+    int insertFsBlackTalent(FsBlackTalent fsBlackTalent);
+
+    /**
+     * 修改达人或视频举报拉黑功能
+     * 
+     * @param fsBlackTalent 达人或视频举报拉黑功能
+     * @return 结果
+     */
+    int updateFsBlackTalent(FsBlackTalent fsBlackTalent);
+
+    /**
+     * 删除达人或视频举报拉黑功能
+     * 
+     * @param id 达人或视频举报拉黑功能主键
+     * @return 结果
+     */
+    int deleteFsBlackTalentById(Long id);
+
+    /**
+     * 批量删除达人或视频举报拉黑功能
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsBlackTalentByIds(Long[] ids);
+
+    int deleteFsBlackVideo(@Param("userId")String userId, @Param("videoId") String videoId);
+
+    int deleteFsBlackTalent(@Param("userId")String userId,@Param("talentId") String talentId);
+
+    int audit(@Param("map") FsBlackTalentAuditParam fsBlackTalentAuditParam);
+
+    List<FsBlackTalent> selectBlackAndReportVideoIdsByUserId(@Param("userId") Long userId);
+
+    int selectBlackTalent(@Param("talentId") Long talentId,@Param("loginUserId") Long loginUserId);
+}

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

@@ -120,8 +120,7 @@ public interface FsCourseAnswerLogsMapper
             "</script>"})
     int selectErrorCountByCourseVideo(@Param("videoId") Long videoId,@Param("userId") Long userId,@Param("qwUserId") String qwUserId);
 
-    @Select("select count(log_id) from fs_course_red_packet_log where user_id = #{userId} and video_id = #{videoId}")
-    Long selectRedStatus(@Param("userId") Long userId, @Param("videoId") Long videoId);
+    Long selectRedStatus(@Param("userId") Long userId, @Param("videoId") Long videoId, @Param("periodId") Long periodId);
 
     List<FsCourseAnswerLogsListVO> selectFsCourseAnswerLogsListVONew(FsCourseAnswerLogsParam param);
 

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

@@ -1,6 +1,7 @@
 package com.fs.course.mapper;
 
 import java.math.BigDecimal;
+import java.time.LocalDateTime;
 import java.util.List;
 
 import com.fs.company.vo.RedPacketMoneyVO;
@@ -168,4 +169,6 @@ public interface FsCourseRedPacketLogMapper
 
     @Select("SELECT * FROM fs_course_red_packet_log WHERE status = 0 and create_time > DATE_SUB(NOW(), INTERVAL 2 day) and company_user_id =#{userId}")
     List<FsCourseRedPacketLog> selectFail(@Param("userId") Long userId);
+
+    List<RedPacketMoneyVO> selectFsCourseRedPacketLogHourseByCompany(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);
 }

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

@@ -2,7 +2,6 @@ package com.fs.course.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.fs.course.domain.FsCourseWatchLog;
-import com.fs.course.domain.FsUserCourseVideo;
 import com.fs.course.dto.WatchLogDTO;
 import com.fs.course.param.*;
 import com.fs.course.vo.*;
@@ -12,7 +11,6 @@ import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
 
-import javax.validation.constraints.NotNull;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;

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

@@ -71,6 +71,9 @@ public interface FsUserCourseCategoryMapper
     @Select("select cate_id dict_value, cate_name dict_label  from fs_user_course_category WHERE pid = 0 and is_del=0 ")
     List<OptionsVO> selectFsUserCourseCategoryPidList();
 
+    @Select("select cate_id dict_value, cate_name dict_label  from fs_user_course_category WHERE pid = 0 and is_del=0 and user_id = #{userId}")
+    List<OptionsVO> selectFsUserCourseCategoryPidListByUserId(Long userId);
+
     @Select("select cate_id dict_value, cate_name dict_label  from fs_user_course_category WHERE pid =#{pid} and is_del=0 ")
     List<OptionsVO> selectCateListByPid(Long pid);
 

+ 11 - 0
fs-service/src/main/java/com/fs/course/mapper/FsUserTalentFollowMapper.java

@@ -2,6 +2,9 @@ package com.fs.course.mapper;
 
 import java.util.List;
 import com.fs.course.domain.FsUserTalentFollow;
+import com.fs.course.param.FsUserTalentFansParam;
+import com.fs.course.vo.FsUserTalentFansVo;
+import com.fs.course.vo.FsUserTalentFollowVo;
 import org.apache.ibatis.annotations.Delete;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
@@ -68,4 +71,12 @@ public interface FsUserTalentFollowMapper
 
     @Delete("delete from fs_user_talent_follow  where talent_id =#{talentId} and user_id=#{userId} ")
     int deleteFollow(@Param("talentId") Long talentId,@Param("userId")long userId);
+
+    Integer queryFansCount(Long talentId);
+
+    Integer queryIdolCount(Long userId);
+
+    List<FsUserTalentFansVo> selectFsUserTalentFansVoList(@Param("maps") FsUserTalentFansParam param);
+
+    List<FsUserTalentFollowVo> selectFsUserFollowVoList(@Param("maps")FsUserTalentFansParam param);
 }

+ 5 - 0
fs-service/src/main/java/com/fs/course/mapper/FsUserTalentMapper.java

@@ -66,4 +66,9 @@ public interface FsUserTalentMapper
 
     @Update("update fs_user_talent set fans=fans-1 where talent_id=#{talentId}")
     int minusFans(Long talentId);
+
+    //根据userID查询达人数据
+    FsUserTalent queryTalentByUserId(Long userId);
+
+    int updateFsUserTalentByUser(FsUserTalent fsUserTalent);
 }

+ 25 - 0
fs-service/src/main/java/com/fs/course/mapper/FsUserVideoMapper.java

@@ -138,6 +138,7 @@ public interface FsUserVideoMapper
             "left join fs_user_talent t on t.talent_id = v.talent_id " +
             " left join fs_package p on p.package_id = v.product_id " +
             "where v.is_del = 0 and v.status = 1  " +
+            " and v.is_audit = 1 " +
             "<if test = ' maps.keyword!=null and maps.keyword != \"\" '> " +
             "and v.title like CONCAT('%',#{maps.keyword},'%') " +
             "</if>" +
@@ -242,5 +243,29 @@ public interface FsUserVideoMapper
 
     @Select("select * from fs_user_video where url like CONCAT('%','https://obs.jy.cc','%') ")
     List<FsUserVideo> selectVideo();
+
+    List<FsUserVideo> selectVideoByTalentId(Long talentId);
+
+    @Select("SELECT count(1) from fs_user_video_favorite f LEFT JOIN " +
+            "fs_user_video v ON v.video_id = f.video_id  " +
+            "where v.is_del = 0 and  v.status = 1 and f.user_id = #{userId}")
+    int countFavoriteVideos(@Param("userId") Long userId);
+
+    @Select({"<script> " +
+            "select v.video_id as id,v.title,v.description as msg,t.nick_name as username,t.avatar as headImg, " +
+            "v.thumbnail as cover,v.url as src,v.likes as likeNum,v.comments as smsNum,v.favorite_num," +
+            "v.create_time,v.views as playNumber,v.product_id,p.img_url,p.package_name,v.upload_type,v.shares,v.add_num,v.is_audit,v.fail_reason,v.status from fs_user_video v " +
+            "left join fs_user_talent t on t.talent_id = v.talent_id " +
+            " left join fs_package p on p.package_id = v.product_id " +
+            "where v.is_del = 0 and (" +
+            "(#{oneSelf} = true and (v.is_audit = -1 or v.is_audit = 0 or v.is_audit = 1)) or " +
+            "(#{oneSelf} = false and v.is_audit = 1 and v.status = 1)" +
+            ") " +
+            "<if test = ' talentId!=null and talentId != \"\" '> " +
+            "and v.talent_id = #{talentId}" +
+            " order by v.create_time" +
+            "</if>" +
+            "</script>"})
+    List<FsUserVideoListUVO> selectFsUserVideoListUVOByUser(@Param("talentId") Long talentId, @Param("oneSelf") boolean oneSelf);
 }
 

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

@@ -64,4 +64,7 @@ public interface FsUserVideoTagsMapper
 
     @Select("select * from fs_user_video_tags where pid !=0 and is_del = 0 ")
     List<FsUserVideoTagsPVO> selectFsUserVideoTagsSubList();
+
+    @Select("select * from fs_user_video_tags where is_del = 0")
+    List<FsUserVideoTags> selectTagList();
 }

+ 14 - 0
fs-service/src/main/java/com/fs/course/param/FsBlackTalentAuditParam.java

@@ -0,0 +1,14 @@
+package com.fs.course.param;
+
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class FsBlackTalentAuditParam {
+    private Long auditUser;
+    private String isAudit;
+    private Long id;
+    private Date auditTime;
+    private String auditDesc;
+}

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

@@ -48,4 +48,5 @@ public class FsCoursePlaySourceConfigCreateParam {
 
     @ApiModelProperty("是否是互医/商城小程序")
     private Integer isMall;
+    private Long createDeptId;
 }

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

@@ -45,4 +45,5 @@ public class FsCoursePlaySourceConfigEditParam {
 
     @ApiModelProperty("是否是互医/商城小程序")
     private Integer isMall;
+    private Long createDeptId;
 }

+ 9 - 1
fs-service/src/main/java/com/fs/course/param/FsCourseSendRewardUParam.java

@@ -2,6 +2,8 @@ package com.fs.course.param;
 
 import lombok.Data;
 
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
 import java.io.Serializable;
 
 /**
@@ -14,19 +16,25 @@ import java.io.Serializable;
 public class FsCourseSendRewardUParam implements Serializable
 {
     private Long userId;
+    @NotNull(message = "课程参数不能为空")
     private Long videoId;//小节Id
+    @NotBlank(message = "客服参数不能为空")
     private String qwUserId;
+    @NotNull(message = "客服参数不能为空")
     private Long companyUserId;
+    @NotNull(message = "经销商参数不能为空")
     private Long companyId;
+    @NotNull(message = "课程参数不能为空")
     private Long courseId;
     private String corpId;
     private Integer linkType;
+    @NotNull(message = "课程参数不能为空")
     private Long qwExternalId;
     private Integer source=1;//来源 1:h5  2:小程序
     private Integer isRoom;
     private Integer sendType;
     private Long periodId;
-
+    @NotBlank(message = "小程序参数不能为空")
     private String appId; //前端传来的小程序的appid
 
     private String code;

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

@@ -61,6 +61,7 @@ public class FsCourseWatchLogListParam implements Serializable {
 
 
     private Long taskId;//任务ID
+    private Long project;//任务ID
 
     private String customPageStr;
 

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

@@ -35,10 +35,12 @@ public class FsUserCourseVideoAddKfUParam implements Serializable {
     /**
     *   companyUserId
     */
+    @NotNull(message = "客服参数不能为空")
     private Long companyUserId;
     /**
     * 公司id
     */
+    @NotNull(message = "经销商参数参数不能为空")
     private Long companyId;
 
     /**
@@ -50,6 +52,7 @@ public class FsUserCourseVideoAddKfUParam implements Serializable {
     /**
     * 外部联系的id
     */
+//    @NotNull(message = "客户参数不能为空")
     private Long qwExternalId;
 
     private Integer sendType; //归属发送方式:1 个微  2 企微

+ 10 - 0
fs-service/src/main/java/com/fs/course/param/FsUserTalentFansParam.java

@@ -0,0 +1,10 @@
+package com.fs.course.param;
+
+import com.fs.watch.param.BaseQueryParam;
+import lombok.Data;
+
+@Data
+public class FsUserTalentFansParam extends BaseQueryParam {
+    private Long talentId;
+    private Long userId;
+}

+ 77 - 0
fs-service/src/main/java/com/fs/course/service/IFsBlackTalentService.java

@@ -0,0 +1,77 @@
+package com.fs.course.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.course.domain.FsBlackTalent;
+import com.fs.course.param.FsBlackTalentAuditParam;
+import com.fs.course.vo.FsBlackTalentPVO;
+
+import java.util.List;
+
+/**
+ * 达人或视频举报拉黑功能Service接口
+ * 
+ * @author fs
+ * @date 2025-08-17
+ */
+public interface IFsBlackTalentService extends IService<FsBlackTalent>{
+    /**
+     * 查询达人或视频举报拉黑功能
+     * 
+     * @param id 达人或视频举报拉黑功能主键
+     * @return 达人或视频举报拉黑功能
+     */
+    FsBlackTalent selectFsBlackTalentById(Long id);
+
+    /**
+     * 查询达人或视频举报拉黑功能列表
+     * 
+     * @param fsBlackTalent 达人或视频举报拉黑功能
+     * @return 达人或视频举报拉黑功能集合
+     */
+    List<FsBlackTalentPVO> selectFsBlackTalentList(FsBlackTalent fsBlackTalent);
+
+    /**
+     * 新增达人或视频举报拉黑功能
+     * 
+     * @param fsBlackTalent 达人或视频举报拉黑功能
+     * @return 结果
+     */
+    int insertFsBlackTalent(FsBlackTalent fsBlackTalent);
+
+    /**
+     * 修改达人或视频举报拉黑功能
+     * 
+     * @param fsBlackTalent 达人或视频举报拉黑功能
+     * @return 结果
+     */
+    int updateFsBlackTalent(FsBlackTalent fsBlackTalent);
+
+    /**
+     * 批量删除达人或视频举报拉黑功能
+     * 
+     * @param ids 需要删除的达人或视频举报拉黑功能主键集合
+     * @return 结果
+     */
+    int deleteFsBlackTalentByIds(Long[] ids);
+
+    /**
+     * 删除达人或视频举报拉黑功能信息
+     * 
+     * @param id 达人或视频举报拉黑功能主键
+     * @return 结果
+     */
+    int deleteFsBlackTalentById(Long id);
+
+    int addBlack(FsBlackTalent blackTalent);
+
+    int deleteFsBlackVideo(String userId,String videoId);
+
+    int deleteFsBlackTalent(String userId,String talentId);
+
+    int audit(FsBlackTalentAuditParam fsBlackTalentAuditParam);
+
+    List<FsBlackTalent> selectBlackAndReportVideoIdsByUserId(Long userId);
+
+    int selectBlackTalent(Long talentId,Long loginUserId);
+
+}

+ 1 - 7
fs-service/src/main/java/com/fs/course/service/IFsUserCompanyUserService.java

@@ -9,7 +9,7 @@ import java.util.Map;
 
 /**
  * 微信用户和销售关系Service接口
- * 
+ *
  * @author fs
  * @date 2025-05-09
  */
@@ -69,12 +69,6 @@ public interface IFsUserCompanyUserService extends IService<FsUserCompanyUser>{
      */
     int deleteFsUserCompanyUserById(Long id);
 
-    /**
-     * 根据用户ID和项目ID查询微信用户与销售的关系
-     * @param userId            用户ID
-     * @param projectId   项目ID
-     * @return FsUserCompanyUser
-     */
     FsUserCompanyUser selectByUserIdAndProjectId(Long userId, Long projectId);
 
     /**

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

@@ -64,6 +64,7 @@ public interface IFsUserCourseCategoryService
     List<OptionsVO> selectFsUserCoursePidList();
 
     List<OptionsVO> selectFsUserCourseCategoryPidList();
+    List<OptionsVO> selectFsUserCourseCategoryPidList(Long userId);
 
     List<OptionsVO> selectCateListByPid(Long pid);
 }

+ 11 - 0
fs-service/src/main/java/com/fs/course/service/IFsUserTalentFollowService.java

@@ -4,6 +4,9 @@ import java.util.List;
 
 import com.fs.common.core.domain.R;
 import com.fs.course.domain.FsUserTalentFollow;
+import com.fs.course.param.FsUserTalentFansParam;
+import com.fs.course.vo.FsUserTalentFansVo;
+import com.fs.course.vo.FsUserTalentFollowVo;
 
 /**
  * 达人关注Service接口
@@ -64,4 +67,12 @@ public interface IFsUserTalentFollowService
     R checkFollow(Long talentId, long userId);
 
     int deleteFollow(Long talentId, long userId);
+
+    Integer queryFansCount(Long talentId);
+
+    Integer queryIdolCount(Long userId);
+
+    List<FsUserTalentFansVo> selectFsUserTalentFansVoList(FsUserTalentFansParam param);
+
+    List<FsUserTalentFollowVo> selectFsUserFollowVoList(FsUserTalentFansParam param);
 }

+ 10 - 0
fs-service/src/main/java/com/fs/course/service/IFsUserTalentService.java

@@ -1,6 +1,8 @@
 package com.fs.course.service;
 
 import java.util.List;
+
+import com.fs.common.core.domain.R;
 import com.fs.course.domain.FsUserTalent;
 
 /**
@@ -61,4 +63,12 @@ public interface IFsUserTalentService
 
 
     int updateFans(Long talentId, Integer type);
+
+    FsUserTalent queryTalentByUserId(Long userId);
+
+    R getTalentDetail(Long userId, Long loginUser);
+
+    int addFsUserTalent(Long userId);
+
+    int updateFsUserTalentByUser(FsUserTalent fsUserTalent);
 }

+ 12 - 0
fs-service/src/main/java/com/fs/course/service/IFsUserVideoService.java

@@ -92,4 +92,16 @@ public interface IFsUserVideoService {
     void updateVideoUrl();
 
     List<FsUserVideoListUVO> addNum(List<FsUserVideoListUVO> oldList);
+
+    List<FsUserVideo> selectVideoByTalentId(Long talentId);
+
+    int countFavoriteVideos(Long userId);
+
+    R addUserVideoByTalent(FsUserVideoAddParam param);
+
+    List<FsUserVideoListUVO> selectFsUserVideoListUVOByUser(Long talentId, boolean oneSelf, Long userId);
+
+    R deleteFsUserVideoByVideoIdWithVerify(Long videoId, Long userId);
+
+    R updateVideoStatusWithVerify(FsUserVideo fsUserVideo, Long userId);
 }

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

@@ -61,4 +61,6 @@ public interface IFsUserVideoTagsService
     public int deleteFsUserVideoTagsByTagId(Long tagId);
 
     List<FsUserVideoTagsPVO> selectFsUserVideoTagsSubList();
+
+    List<FsUserVideoTags> selectTagList();
 }

+ 126 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsBlackTalentServiceImpl.java

@@ -0,0 +1,126 @@
+package com.fs.course.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.course.domain.FsBlackTalent;
+import com.fs.course.mapper.FsBlackTalentMapper;
+import com.fs.course.param.FsBlackTalentAuditParam;
+import com.fs.course.service.IFsBlackTalentService;
+import com.fs.course.vo.FsBlackTalentPVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 达人或视频举报拉黑功能Service业务层处理
+ * 
+ * @author fs
+ * @date 2025-08-17
+ */
+@Service
+public class FsBlackTalentServiceImpl extends ServiceImpl<FsBlackTalentMapper, FsBlackTalent> implements IFsBlackTalentService {
+    @Autowired
+    private FsBlackTalentMapper blackTalentMapper;
+    /**
+     * 查询达人或视频举报拉黑功能
+     * 
+     * @param id 达人或视频举报拉黑功能主键
+     * @return 达人或视频举报拉黑功能
+     */
+    @Override
+    public FsBlackTalent selectFsBlackTalentById(Long id)
+    {
+        return baseMapper.selectFsBlackTalentById(id);
+    }
+
+    /**
+     * 查询达人或视频举报拉黑功能列表
+     * 
+     * @param fsBlackTalent 达人或视频举报拉黑功能
+     * @return 达人或视频举报拉黑功能
+     */
+    @Override
+    public List<FsBlackTalentPVO> selectFsBlackTalentList(FsBlackTalent fsBlackTalent)
+    {
+        return blackTalentMapper.selectFsBlackTalentPVOList(fsBlackTalent);
+    }
+
+    /**
+     * 新增达人或视频举报拉黑功能
+     * 
+     * @param fsBlackTalent 达人或视频举报拉黑功能
+     * @return 结果
+     */
+    @Override
+    public int insertFsBlackTalent(FsBlackTalent fsBlackTalent)
+    {
+        return baseMapper.insertFsBlackTalent(fsBlackTalent);
+    }
+
+    /**
+     * 修改达人或视频举报拉黑功能
+     * 
+     * @param fsBlackTalent 达人或视频举报拉黑功能
+     * @return 结果
+     */
+    @Override
+    public int updateFsBlackTalent(FsBlackTalent fsBlackTalent)
+    {
+        return baseMapper.updateFsBlackTalent(fsBlackTalent);
+    }
+
+    /**
+     * 批量删除达人或视频举报拉黑功能
+     * 
+     * @param ids 需要删除的达人或视频举报拉黑功能主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsBlackTalentByIds(Long[] ids)
+    {
+        return baseMapper.deleteFsBlackTalentByIds(ids);
+    }
+
+    /**
+     * 删除达人或视频举报拉黑功能信息
+     * 
+     * @param id 达人或视频举报拉黑功能主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsBlackTalentById(Long id)
+    {
+        return baseMapper.deleteFsBlackTalentById(id);
+    }
+
+    @Override
+    public int addBlack(FsBlackTalent blackTalent) {
+        return blackTalentMapper.insertFsBlackTalent(blackTalent);
+    }
+
+    @Override
+    public int deleteFsBlackVideo(String userId,String videoId) {
+        return blackTalentMapper.deleteFsBlackVideo(userId,videoId);
+    }
+
+    @Override
+    public int deleteFsBlackTalent(String userId,String talentId) {
+        return blackTalentMapper.deleteFsBlackTalent(userId,talentId);
+    }
+
+    @Override
+    public int audit(FsBlackTalentAuditParam fsBlackTalentAuditParam) {
+        return blackTalentMapper.audit(fsBlackTalentAuditParam);
+    }
+
+    @Override
+    public List<FsBlackTalent> selectBlackAndReportVideoIdsByUserId(Long userId) {
+        return blackTalentMapper.selectBlackAndReportVideoIdsByUserId(userId);
+    }
+
+    @Override
+    public int selectBlackTalent(Long talentId, Long loginUserId) {
+
+        return blackTalentMapper.selectBlackTalent(talentId,loginUserId);
+    }
+}

+ 135 - 57
fs-service/src/main/java/com/fs/course/service/impl/FsCourseFinishTempServiceImpl.java

@@ -28,6 +28,7 @@ import com.fs.qwApi.service.QwApiService;
 import com.fs.voice.utils.StringUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
 import java.time.LocalDate;
@@ -209,9 +210,10 @@ public class FsCourseFinishTempServiceImpl implements IFsCourseFinishTempService
     /**
      * 完课用户 打备注
      */
+    @Async
     @Override
     public void finishCourseExtContactIdByRemark(FsCourseWatchLog watchLog) {
-
+        addRandomDelay();
         Long qwExternalContactId = watchLog.getQwExternalContactId();
 
         Date finishTime = watchLog.getFinishTime();
@@ -259,50 +261,15 @@ public class FsCourseFinishTempServiceImpl implements IFsCourseFinishTempService
 
             // 3. 检查是否需要更新
             boolean shouldUpdate = true;
-            int currentYear = Calendar.getInstance().get(Calendar.YEAR);
-
-            // Convert input dates to full YYYYMMDD format
-            String fullMonthDay = String.valueOf(currentYear) + monthDay; // becomes YYYYMMDD
-            String fullDayOfMonth = String.valueOf(currentYear) +
-                    String.format("%02d", Calendar.getInstance().get(Calendar.MONTH) + 1) +
-                    String.format("%02d", Integer.parseInt(dayOfMonth));
 
             for (String mark : allOldMarks) {
-                Matcher numMatcher = Pattern.compile("\\*(\\d{1,4})完").matcher(mark);
-                if (numMatcher.find()) {
-                    String numStr = numMatcher.group(1);
-                    String fullOldDate;
-
-                    if (numStr.length() <= 2) { // 处理 "*D完" 格式
-
-                        int day = Integer.parseInt(numStr);
-                        Calendar cal = Calendar.getInstance();
-                        int currentMonth = cal.get(Calendar.MONTH) + 1;
-                        int currentDay = cal.get(Calendar.DAY_OF_MONTH);
-                        int year = cal.get(Calendar.YEAR);
-
-                        // 获取上个月的最大天数
-                        int prevMonth = (currentMonth == 1) ? 12 : currentMonth - 1;
-                        int prevYear = (currentMonth == 1) ? year - 1 : year;
-                        cal.set(prevYear, prevMonth - 1, 1); // Calendar 月份是 0-based
-                        int maxDaysInPrevMonth = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
-
-                        // 如果 day > 上个月的天数,说明是上个月的日期
-                        if (day > maxDaysInPrevMonth || day > currentDay + 7) {
-                            currentMonth = prevMonth;
-                            year = prevYear;
-                        }
-
-                        fullOldDate = String.format("%04d%02d%02d", year, currentMonth, day);
-
-                        // 比较日期
-                        if (Integer.parseInt(fullOldDate) >= Integer.parseInt(fullMonthDay) ||
-                                Integer.parseInt(fullOldDate) >= Integer.parseInt(fullDayOfMonth)) {
-                            shouldUpdate = false;
-                            break;
-                        }
-                    }
 
+                String normalizedOldMark = normalizeMarkFormat(mark);
+                // 直接比较字符串是否相等
+                if (normalizedOldMark.equals(newNotes) ||
+                        normalizedOldMark.equals(newNotesDay)) {
+                    shouldUpdate = false;
+                    break;
                 }
             }
 
@@ -335,7 +302,8 @@ public class FsCourseFinishTempServiceImpl implements IFsCourseFinishTempService
             remarkParam.setUserid(externalContact.getUserId());
             remarkParam.setExternal_userid(externalContact.getExternalUserId());
 
-            for (int attempt = 1; attempt <= 2; attempt++) {
+//            for (int attempt = 1; attempt <= 2; attempt++) {
+            for (int attempt = 1; attempt <= 3; attempt++) { // 增加到3次重试
                 try {
                     QwExternalContactRemarkResult qwResult = qwApiService.externalcontactRemark(remarkParam, externalContact.getCorpId());
                     if (qwResult.getErrcode() == 0) {
@@ -349,23 +317,46 @@ public class FsCourseFinishTempServiceImpl implements IFsCourseFinishTempService
 
                         break;
                     } else {
-                        if (attempt==2 && (qwResult.getErrcode() == 45033 || qwResult.getErrcode()== -1 || qwResult.getErrcode()== 60020)) {
-                            QwCourseFinishRemarkRty remarkRty=new QwCourseFinishRemarkRty();
-                            remarkRty.setQwUserId(externalContact.getUserId());
-                            remarkRty.setCorpId(externalContact.getCorpId());
-                            remarkRty.setExternalUserId(externalContact.getExternalUserId());
-                            remarkRty.setExternalId(externalContact.getId());
-                            remarkRty.setRemark(newRemark);
-                            remarkRty.setCreateTime(new Date());
-                            finishRemarkRtyService.insertOrUpdateQwCourseFinishRemarkRty(remarkRty);
-
+//                        if (attempt==2 && (qwResult.getErrcode() == 45033 || qwResult.getErrcode()== -1 || qwResult.getErrcode()== 60020 )) {
+//                            QwCourseFinishRemarkRty remarkRty=new QwCourseFinishRemarkRty();
+//                            remarkRty.setQwUserId(externalContact.getUserId());
+//                            remarkRty.setCorpId(externalContact.getCorpId());
+//                            remarkRty.setExternalUserId(externalContact.getExternalUserId());
+//                            remarkRty.setExternalId(externalContact.getId());
+//                            remarkRty.setRemark(newRemark);
+//                            remarkRty.setCreateTime(new Date());
+//                            finishRemarkRtyService.insertOrUpdateQwCourseFinishRemarkRty(remarkRty);
+//
+//                        }
+//
+//                        log.error("完课加备注失败:" + externalContact.getName() + "|" + externalContact.getExternalUserId() + "|" + externalContact.getCorpId() + "|" + externalContact.getUserId() + "|" + newRemark + "|原因" + qwResult.getErrmsg());
+
+                        // 根据错误码智能处理
+                        if (isRateLimitError(qwResult.getErrcode())) {
+                            // 保存到重试表
+                            saveToRetryTable(externalContact, newRemark);
+
+                            // 智能延迟
+                            if (attempt < 3) {
+                                smartDelayByErrorCode(qwResult.getErrcode(), attempt);
+                                continue; // 继续重试
+                            }
                         }
-
-                        log.error("完课加备注失败:" + externalContact.getName() + "|" + externalContact.getExternalUserId() + "|" + externalContact.getCorpId() + "|" + externalContact.getUserId() + "|" + newRemark + "|原因" + qwResult.getErrmsg());
-
+                        log.error("完课加备注失败:{}|{}|{}|{}|{}|原因{}",
+                                externalContact.getName(), externalContact.getExternalUserId(),
+                                externalContact.getCorpId(), externalContact.getUserId(),
+                                newRemark, qwResult.getErrmsg());
                     }
                 } catch (Exception e) {
-                    log.error("添加备注异常 [尝试第 " + attempt + " 次]:" + externalContact.getName() + "|" + externalContact.getExternalUserId() + "|" + externalContact.getCorpId() + "|" + externalContact.getUserId() + "|" + newRemark + "|" + e.getMessage());
+//                    log.error("添加备注异常 [尝试第 " + attempt + " 次]:" + externalContact.getName() + "|" + externalContact.getExternalUserId() + "|" + externalContact.getCorpId() + "|" + externalContact.getUserId() + "|" + newRemark + "|" + e.getMessage());
+                    log.error("添加备注异常 [尝试第 {} 次]:{}|{}|{}|{}|{}|{}",
+                            attempt, externalContact.getName(), externalContact.getExternalUserId(),
+                            externalContact.getCorpId(), externalContact.getUserId(),
+                            newRemark, e.getMessage());
+
+                    if (attempt < 3) {
+                        smartDelayByErrorCode(-1, attempt);
+                    }
                 }
 
                 // 若不是最后一次尝试,则等待3秒再试
@@ -385,6 +376,33 @@ public class FsCourseFinishTempServiceImpl implements IFsCourseFinishTempService
 
     }
 
+    /**
+     * 标准化标记格式,将不同格式统一为标准格式
+     * 例如: "*5完" -> "*05完", "*305完" -> "*0305完" (如果是3位数字)
+     */
+    private String normalizeMarkFormat(String mark) {
+        Matcher matcher = Pattern.compile("\\*(\\d{1,4})完").matcher(mark);
+        if (matcher.find()) {
+            String digits = matcher.group(1);
+
+            // 根据数字长度进行标准化
+            switch (digits.length()) {
+                case 1: // "*D完" -> "*0D完"
+                    return "*0" + digits + "完";
+                case 2: // "*DD完" -> 保持不变
+                    return mark;
+                case 3: // "*DDD完" -> 可能是 "*MDD完" 或 "*DDM完",统一为4位
+                    // 假设是月日格式,补零到4位 "*0MDD完"
+                    return "*0" + digits + "完";
+                case 4: // "*MMDD完" -> 保持不变
+                    return mark;
+                default:
+                    return mark;
+            }
+        }
+        return mark;
+    }
+
 //    @Override
 //    public void updateFsCourseFinishTempByCompanyUserId() {
 //        List<FsCourseFinishTemp> fsCourseFinishTemps = fsCourseFinishTempMapper.selectFsCourseFinishTempByCompanyList();
@@ -419,4 +437,64 @@ public class FsCourseFinishTempServiceImpl implements IFsCourseFinishTempService
     public List<FsCourseFinishTempListVO> selectFsCourseFinishTempListVO(FsCourseFinishTemp fsCourseFinishTemp) {
         return fsCourseFinishTempMapper.selectFsCourseFinishTempListVO(fsCourseFinishTemp);
     }
+
+    /**
+     * 添加随机延迟,分散请求峰值
+     */
+    private void addRandomDelay() {
+        try {
+            // 随机延迟100-500ms,避免同时大量请求
+            Thread.sleep(100 + (long)(Math.random() * 400));
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            log.warn("延迟被中断", e);
+        }
+    }
+
+    /**
+     * 根据错误码智能延迟
+     */
+    private void smartDelayByErrorCode(Integer errcode, int attempt) {
+        try {
+            long delayMs;
+            if (errcode == 45033) { // 并发限制
+                delayMs = 5000 + attempt * 2000L; // 递增延迟
+            } else if (errcode == 60020) { // 频率限制
+                delayMs = 3000 + attempt * 1000L;
+            } else if (errcode == -1) { // 系统繁忙
+                delayMs = 2000;
+            } else {
+                delayMs = 1000; // 默认延迟
+            }
+            log.info("因错误码 {} 延迟 {}ms", errcode, delayMs);
+            Thread.sleep(delayMs);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+        }
+    }
+
+    /**
+     * 判断是否为频率限制类错误
+     */
+    private boolean isRateLimitError(Integer errcode) {
+        return errcode == 45033 || errcode == 60020 || errcode == -1;
+    }
+
+    /**
+     * 保存到重试表
+     */
+    private void saveToRetryTable(QwExternalContact externalContact, String remark) {
+        try {
+            QwCourseFinishRemarkRty remarkRty=new QwCourseFinishRemarkRty();
+            remarkRty.setQwUserId(externalContact.getUserId());
+            remarkRty.setCorpId(externalContact.getCorpId());
+            remarkRty.setExternalUserId(externalContact.getExternalUserId());
+            remarkRty.setExternalId(externalContact.getId());
+            remarkRty.setRemark(remark);
+            remarkRty.setCreateTime(new Date());
+            finishRemarkRtyService.insertOrUpdateQwCourseFinishRemarkRty(remarkRty);
+        } catch (Exception e) {
+            log.error("保存重试记录失败", e);
+        }
+    }
 }

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

@@ -215,6 +215,7 @@ public class FsCourseRedPacketLogServiceImpl implements IFsCourseRedPacketLogSer
                 packetParam.setSource(2);
                 packetParam.setRedPacketMode(1);
                 packetParam.setCompanyId(param.getCompanyId());
+                packetParam.setUser(user);
                 R sendRedPacket = paymentService.sendRedPacket(packetParam);
                 if (sendRedPacket.get("code").equals(200)) {
                     FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();

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

@@ -383,7 +383,13 @@ public class FsCourseWatchLogServiceImpl extends ServiceImpl<FsCourseWatchLogMap
             watchLog.setDuration(duration);
 
             //取对应视频的时长
-            Long videoDuration = getFsUserVideoDuration(videoId);
+            Long videoDuration = 0L;
+            try {
+                videoDuration = getFsUserVideoDuration(videoId);
+            }catch (Exception e){
+                log.error("视频时长识别错误:{}", key);
+                continue;
+            }
             if (videoDuration != null && videoDuration != 0) {
                 //判断是否完课
                 long percentage = (duration * 100 / videoDuration);

+ 2 - 7
fs-service/src/main/java/com/fs/course/service/impl/FsUserCompanyUserServiceImpl.java

@@ -17,7 +17,7 @@ import java.util.Objects;
 
 /**
  * 微信用户和销售关系Service业务层处理
- * 
+ *
  * @author fs
  * @date 2025-05-09
  */
@@ -105,12 +105,7 @@ public class FsUserCompanyUserServiceImpl extends ServiceImpl<FsUserCompanyUserM
         return baseMapper.deleteFsUserCompanyUserById(id);
     }
 
-    /**
-     * 根据用户ID和项目ID查询微信用户与销售的关系
-     * @param userId            用户ID
-     * @param projectId   项目ID
-     * @return FsUserCompanyUser
-     */
+
     @Override
     public FsUserCompanyUser selectByUserIdAndProjectId(Long userId, Long projectId) {
         LambdaQueryWrapper<FsUserCompanyUser> queryWrapper = Wrappers.<FsUserCompanyUser>lambdaQuery()

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

@@ -105,7 +105,10 @@ public class FsUserCourseCategoryServiceImpl implements IFsUserCourseCategorySer
         return fsUserCourseCategoryMapper.selectFsUserCourseCategoryPidList();
     }
 
-
+    @Override
+    public List<OptionsVO> selectFsUserCourseCategoryPidList(Long userId) {
+        return fsUserCourseCategoryMapper.selectFsUserCourseCategoryPidListByUserId(userId);
+    }
     @Override
     public List<OptionsVO> selectCateListByPid(Long pid) {
         return fsUserCourseCategoryMapper.selectCateListByPid(pid);

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

@@ -540,7 +540,7 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
             recordVO.setWatchLxCount(lxDay);
 
             // 领取状态
-            Long count = fsCourseAnswerLogsMapper.selectRedStatus(recordVO.getUserId(), recordVO.getVideoId());
+            Long count = fsCourseAnswerLogsMapper.selectRedStatus(recordVO.getUserId(), recordVO.getVideoId(), (Long) params.get("periodId"));
             if (Objects.nonNull(count) && count > 0) {
                 recordVO.setRedStatus(1);
             } else {

+ 96 - 176
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -86,6 +86,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.text.SimpleDateFormat;
 import java.time.*;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
@@ -112,27 +113,6 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     private Boolean isNewWxMerchant;
     private static final Logger logger = LoggerFactory.getLogger(FsUserCourseVideoServiceImpl.class);
 
-    /**
-     * 红包账户锁
-     */
-    private static final String REDPACKET_POOL_LOCK = "redpacket_pool_lock";
-
-    /**
-     * 公司红包金额
-     */
-    private static final String REDPACKET_COMPANY_MONEY = "redpacket_money";
-
-    /**
-     * 红包改变记录
-     */
-    private static final String REDPACKET_COMPANY_MONEY_CHANGE = "redpacket_money_change";
-
-    /**
-     * 是否开启红包账户扣减
-     */
-    @Value("${enableRedPackAccount:0}")
-    private String ENABLE_RED_PACK_ACCOUNT;
-
     private static final String miniappRealLink = "/pages_course/video.html?course=";
     private static final String REAL_LINK_PREFIX = "/courseH5/pages/course/learning?course=";
     private static final String SHORT_LINK_PREFIX = "/courseH5/pages/course/learning?s=";
@@ -249,8 +229,6 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     @Autowired
     ConfigUtil configUtil;
 
-    @Autowired
-    private RedisTemplate<String,BigDecimal> redisTemplate;
 
 
     /**
@@ -777,7 +755,12 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     }
 
     private R addCustomerService(String qwUserById,String msg){
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
         String contactWay = "";
+        if (ObjectUtils.isNotEmpty(config.getShowQwCode())&&!config.getShowQwCode()){
+            return R.error(400,msg).put("qrcode",contactWay);
+        }
         QwUser qwUser = qwUserMapper.selectQwUserById(Long.parseLong(qwUserById));
         if (qwUser==null){
             return R.error("客服不存在");
@@ -1011,23 +994,31 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 //        if (StringUtils.isEmpty(user.getMpOpenId())){
 //            return R.error("未识别到领取信息");
 //        }
+        log.info("查询会员信息:{}", user);
         if (user.getStatus()==0){
             return R.error("会员被停用,无权限,请联系客服!");
         }
-        FsCourseWatchLog log = new FsCourseWatchLog();
+        FsCourseWatchLog watchLog = new FsCourseWatchLog();
 
         // 根据链接类型判断是否已发放奖励
-        log = courseWatchLogMapper.getWatchCourseVideo(param.getUserId(), param.getVideoId(), param.getQwUserId(), param.getQwExternalId());
-        if (log == null) {
+        watchLog = courseWatchLogMapper.getWatchCourseVideo(param.getUserId(), param.getVideoId(), param.getQwUserId(), param.getQwExternalId());
+        log.info("看课记录:{}", watchLog);
+        if (watchLog == null) {
             return R.error("无记录");
         }
-        if (log.getRewardType() != null) {
+        if (watchLog.getLogType() != 2) {
+            return R.error("未完课");
+        }
+        if (watchLog.getRewardType() != null) {
             FsCourseRedPacketLog packetLog = redPacketLogMapper.selectFsCourseRedPacketLogByTemporary(param.getVideoId(), param.getUserId());
+            log.info("课程红包:{}", packetLog);
             if(packetLog != null && packetLog.getStatus() == 1) {
                 return R.error("已领取该课程奖励,不可重复领取!");
             }
             if(packetLog != null && packetLog.getStatus() == 0) {
+                log.info("判断领取记录");
                 if(StringUtils.isNotEmpty(packetLog.getResult())){
+                    log.info("是否有结果");
                     R r = JSON.parseObject(packetLog.getResult(), R.class);
                     return r;
                 } else {
@@ -1045,22 +1036,22 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         // 获取配置信息
         String json = configService.selectConfigByKey("course.config");
         CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-
+        log.info("奖励类型:{}", config.getRewardType());
         // 根据奖励类型发放不同奖励
         switch (config.getRewardType()) {
             // 红包奖励
             case 1:
-                return sendRedPacketReward(param, user, log, video, config);
+                return sendRedPacketReward(param, user, watchLog, video, config);
             // 积分奖励
             case 2:
-                return sendIntegralReward(param,user, log, config);
+                return sendIntegralReward(param,user, watchLog, config);
             // 红包+积分
             case 3:
-                R sendRed = sendRedPacketReward(param, user, log, video, config);
+                R sendRed = sendRedPacketReward(param, user, watchLog, video, config);
                 if (!Objects.equals(sendRed.get("code"), 200)) {
                     return sendRed;
                 }
-                return sendIntegralReward(param,user, log, config);
+                return sendIntegralReward(param,user, watchLog, config);
             default:
                 return R.error("参数错误!");
         }
@@ -1068,6 +1059,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
     @Override
     public R sendRewardByFsUser(FsCourseSendRewardUParam param) {
+        log.info("进入用户判断");
         FsUser user = fsUserMapper.selectFsUserByUserId(param.getUserId());
         if (user == null){
             return R.error("未识别到用户信息");
@@ -1143,7 +1135,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
      * @return 处理结果
      */
     private R sendRedPacketReward(FsCourseSendRewardUParam param, FsUser user, FsCourseWatchLog log, FsUserCourseVideo video, CourseConfig config) {
-
+        logger.info("进入发放红包");
         // 确定红包金额
         BigDecimal amount = BigDecimal.ZERO;
         FsUserCourseVideoRedPackage redPackage = fsUserCourseVideoRedPackageMapper.selectRedPacketByCompanyId(param.getVideoId(), param.getCompanyId(), param.getPeriodId());
@@ -1156,23 +1148,46 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
         // 准备发送红包参数
         WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
-        packetParam.setOpenId(user.getMpOpenId());
-        // 来源是小程序切换openId
-        if (param.getSource() == 2) {
-            //处理多小程序问题
+
+        if (user.getMpOpenId()!=null&&!isNewWxMerchant){
+            packetParam.setOpenId(user.getMpOpenId());
+        }else {
+            //修复数据
             FsUserWx fsUserWx = fsUserWxService.selectByAppIdAndUserId(param.getAppId(),user.getUserId(),1);
             if (fsUserWx ==null){
+                if (user.getCourseMaOpenId()==null){
+                    logger.error(" 【转账openId参数错误】:{}", user.getUserId());
+                    return R.error("openId参数错误,请清理缓存后重新授权!");
+                }
+                packetParam.setOpenId(user.getCourseMaOpenId());
                 try {
                     handleFsUserWx(user,param.getAppId());
                 }catch (Exception e){
-                    logger.error("【更新或插入用户与小程序的绑定关系失败】:{}", user.getUserId());
+                    logger.error(" 【更新或插入用户与小程序的绑定关系失败】:{}", user.getUserId(),e);
                 }
+
             }else {
                 packetParam.setOpenId(fsUserWx.getOpenId());
             }
-            //查出公司绑定openid并赋值
         }
 
+//        packetParam.setOpenId(user.getMpOpenId());
+//        // 来源是小程序切换openId
+//        if (param.getSource() == 2) {
+//            //处理多小程序问题
+//            FsUserWx fsUserWx = fsUserWxService.selectByAppIdAndUserId(param.getAppId(),user.getUserId(),1);
+//            if (fsUserWx ==null){
+//                try {
+//                    handleFsUserWx(user,param.getAppId());
+//                }catch (Exception e){
+//                    logger.error("【更新或插入用户与小程序的绑定关系失败】:{}", user.getUserId());
+//                }
+//            }else {
+//                packetParam.setOpenId(fsUserWx.getOpenId());
+//            }
+//            //查出公司绑定openid并赋值
+//        }
+
         //判断服务号配置是否存在
         if (StringUtils.isNotEmpty(config.getMpAppId())){
             packetParam.setMpAppId(config.getMpAppId());
@@ -1187,28 +1202,8 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         logger.info("红包金额 {},红包商户号 {}",amount,packetParam);
         //2025.6.19 红包金额为0的时候
         if (amount.compareTo(BigDecimal.ZERO)>0){
-
-            //---------------发红包前先判断润天账户余额是否足够---------
-            RLock lock = redissonClient.getLock(REDPACKET_POOL_LOCK);
-            try{
-                boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
-
-                if (!locked) {
-                    logger.error("获取锁失败");
-                    return R.error("[红包领取] 系统繁忙,请重试!");
-                }
-
-                // 发送红包
-                return sendRedPacketRewardToUser(param, log, config, packetParam, amount);
-
-            }catch (Exception e){
-                logger.error("领取红包失败原因:{}", ExceptionUtils.getFullStackTrace(e),e);
-                throw new RuntimeException(e);
-            }finally {
-                if (lock.isHeldByCurrentThread()) {
-                    lock.unlock();
-                }
-            }
+            // 发送红包
+            return sendRedPacketRewardToUser(param, log, config, packetParam, amount);
         } else {
             FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
             // 添加红包记录
@@ -1236,25 +1231,6 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
     private R sendRedPacketRewardToUser(FsCourseSendRewardUParam param, FsCourseWatchLog log, CourseConfig config, WxSendRedPacketParam packetParam, BigDecimal amount) {
 
-        BigDecimal companyMoney = null;
-        if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
-            companyMoney = redisTemplate.opsForValue().get(REDPACKET_COMPANY_MONEY);
-
-            if(ObjectUtils.isNull(companyMoney)){
-                SysConfig sysConfig = sysConfigService.selectConfigByConfigKey("company.money");
-                if(ObjectUtils.isNull(sysConfig)){
-                    throw new IllegalArgumentException("润天公司账户余额不能为空!请检查配置!");
-                }
-                String configValue = sysConfig.getConfigValue();
-                companyMoney = new BigDecimal(configValue);
-                logger.info("缓存公司余额为空,从数据库读取 companyMoney: {}",companyMoney);
-            }
-
-            if (companyMoney.compareTo(BigDecimal.ZERO) <= 0) {
-                logger.info("润天账户余额: {} 不足!", companyMoney);
-                return R.error("[红包领取] 账户余额不足,请联系管理员!");
-            }
-        }
 
         // 发送红包
         R sendRedPacket = paymentService.sendRedPacket(packetParam);
@@ -1280,23 +1256,12 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             redPacketLog.setAmount(amount);
             redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
             redPacketLog.setPeriodId(param.getPeriodId());
-            if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
-                redPacketLog.setAccBalanceBefore(companyMoney);
-                redPacketLog.setAccBalanceAfter(companyMoney.subtract(amount));
-            }
 
             redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
             // 更新观看记录的奖励类型
             log.setRewardType(config.getRewardType());
             courseWatchLogMapper.updateFsCourseWatchLog(log);
 
-            if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
-                // 更新账户余额
-                logger.info("[更新账户余额] 当前余额{} 更新后余额{}",companyMoney.toPlainString(),companyMoney.subtract(amount).toPlainString());
-
-                companyMoney = companyMoney.subtract(amount);
-                redisTemplate.opsForValue().set(REDPACKET_COMPANY_MONEY,companyMoney);
-            }
             return sendRedPacket;
         } else {
             return R.error("奖励发送失败,请联系客服");
@@ -1304,6 +1269,8 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     }
 
 
+
+
     private void handleFsUserWx(FsUser user, String appId) {
         FsUserWx fsUserWx = new FsUserWx();
         fsUserWx.setType(1);
@@ -1408,92 +1375,43 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                 return R.error("服务商余额不足,请联系群主服务器充值!");
             }
 
-            //---------------发红包前先判断润天账户余额是否足够---------
-            RLock lock = redissonClient.getLock(REDPACKET_POOL_LOCK);
-            try{
-                boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
-
-                if (!locked) {
-                    logger.error("获取锁失败");
-                    return R.error("[红包领取] 系统繁忙,请重试!");
-                }
-
-                BigDecimal companyMoney = null;
-                if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
-                    companyMoney = redisTemplate.opsForValue().get(REDPACKET_COMPANY_MONEY);
-                    if(ObjectUtils.isNull(companyMoney)){
-                        SysConfig sysConfig = sysConfigService.selectConfigByConfigKey("company.money");
-                        if(ObjectUtils.isNull(sysConfig)){
-                            throw new IllegalArgumentException("润天公司账户余额不能为空!请检查配置!");
-                        }
-                        String configValue = sysConfig.getConfigValue();
-                        companyMoney = new BigDecimal(configValue);
-                        logger.info("缓存公司余额为空,从数据库读取 companyMoney: {}",companyMoney);
-                    }
-
-                    if (companyMoney.compareTo(BigDecimal.ZERO) <= 0) {
-                        logger.info("润天账户余额: {} 不足!", companyMoney);
-                        return R.error("[红包领取] 账户余额不足,请联系管理员!");
-                    }
-                }
-                // 发送红包
-                R sendRedPacket = paymentService.sendRedPacket(packetParam);
-                if (sendRedPacket.get("code").equals(200)) {
-                    FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
-                    TransferBillsResult transferBillsResult;
-                    if (sendRedPacket.get("isNew").equals(1)){
-                        transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
-                        redPacketLog.setResult(JSON.toJSONString(sendRedPacket));
-                        redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
-                    }else {
-                        redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
-                        redPacketLog.setBatchId(sendRedPacket.get("batchId").toString());
-                    }
-                    // 添加红包记录
-                    redPacketLog.setCourseId(param.getCourseId());
-                    redPacketLog.setCompanyId(param.getCompanyId());
-                    redPacketLog.setUserId(param.getUserId());
-                    redPacketLog.setVideoId(param.getVideoId());
-                    redPacketLog.setStatus(0);
-                    redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
-                    redPacketLog.setCompanyUserId(param.getCompanyUserId());
-                    redPacketLog.setCreateTime(new Date());
-                    redPacketLog.setAmount(amount);
-                    redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
-                    redPacketLog.setPeriodId(param.getPeriodId());
-                    redPacketLog.setAppId(param.getAppId());
-                    if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
-                        redPacketLog.setAccBalanceBefore(companyMoney);
-                        redPacketLog.setAccBalanceAfter(companyMoney.subtract(amount));
-                    }
-                    redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
-
-                    // 更新观看记录的奖励类型
-                    log.setRewardType(config.getRewardType());
-                    courseWatchLogMapper.updateFsCourseWatchLog(log);
-
-
-                    if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
-                        // 更新账户余额
-                        logger.info("[更新账户余额] 当前余额{} 更新后余额{}",companyMoney.toPlainString(),companyMoney.subtract(amount).toPlainString());
-
-                        companyMoney = companyMoney.subtract(amount);
-                        redisTemplate.opsForValue().set(REDPACKET_COMPANY_MONEY,companyMoney);
-                    }
-
-                    return sendRedPacket;
-                } else {
-                    return R.error("奖励发送失败,请联系客服");
-                }
-            }catch (Exception e){
-                logger.error("领取红包失败原因:{}", ExceptionUtils.getFullStackTrace(e),e);
-                throw new RuntimeException(e);
-            }finally {
-                if (lock.isHeldByCurrentThread()) {
-                    lock.unlock();
+            // 发送红包
+            R sendRedPacket = paymentService.sendRedPacket(packetParam);
+            if (sendRedPacket.get("code").equals(200)) {
+                FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
+                TransferBillsResult transferBillsResult;
+                if (sendRedPacket.get("isNew").equals(1)){
+                    transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
+                    redPacketLog.setResult(JSON.toJSONString(sendRedPacket));
+                    redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
+                }else {
+                    redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
+                    redPacketLog.setBatchId(sendRedPacket.get("batchId").toString());
                 }
+                // 添加红包记录
+                redPacketLog.setCourseId(param.getCourseId());
+                redPacketLog.setCompanyId(param.getCompanyId());
+                redPacketLog.setUserId(param.getUserId());
+                redPacketLog.setVideoId(param.getVideoId());
+                redPacketLog.setStatus(0);
+                redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
+                redPacketLog.setCompanyUserId(param.getCompanyUserId());
+                redPacketLog.setCreateTime(new Date());
+                redPacketLog.setAmount(amount);
+                redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
+                redPacketLog.setPeriodId(param.getPeriodId());
+                redPacketLog.setAppId(param.getAppId());
+
+                redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
+
+                // 更新观看记录的奖励类型
+                log.setRewardType(config.getRewardType());
+                courseWatchLogMapper.updateFsCourseWatchLog(log);
+
+                return sendRedPacket;
+            } else {
+                return R.error("奖励发送失败,请联系客服");
             }
-
         } else {
             FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
             // 添加红包记录
@@ -1651,6 +1569,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         redPacketLog.setAmount(BigDecimal.valueOf(config.getAnswerIntegral()).divide(BigDecimal.valueOf(1000)));
         redPacketLog.setRemark("点播答题领取积分转");
         redPacketLog.setWatchLogId(log.getLogId() !=null ? log.getLogId() : null);
+        redPacketLog.setPeriodId(param.getPeriodId());
         redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
         return R.ok("奖励发放成功").put("rewardType",config.getRewardType());
     }
@@ -1792,7 +1711,6 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             return ResponseResult.fail(504, "课程配置错误,项目归属为空,课程ID: " + param.getCourseId());
         }
 
-        // 查询【用户-项目】关系
         FsUserCompanyUser userCompanyUser = userCompanyUserService.selectByUserIdAndProjectId(fsUser.getUserId(), courseProject);
 
         // 添加逻辑:如果存在fs_user表数据,但是又不存在fs_user_company_user表,则表示是以前企微看课的,需要手动绑定
@@ -1915,6 +1833,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         LocalDateTime effectiveEndTime = companyUserEndDateTime != null ?
                 companyUserEndDateTime : periodDays.getEndDateTime();
         // 检查时间范围和状态
+        log.error("传入参数:开始时间:{},结束时间:{},periodDays={}",effectiveStartTime,effectiveEndTime,periodDays);
         return DateUtil.isWithinRangeSafe(LocalDateTime.now(), effectiveStartTime, effectiveEndTime)&& periodDays.getStatus() == 1;
     }
 
@@ -2861,3 +2780,4 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     }
 
 }
+

+ 24 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsUserTalentFollowServiceImpl.java

@@ -1,9 +1,13 @@
 package com.fs.course.service.impl;
 
+import java.util.Collections;
 import java.util.List;
 
 import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
+import com.fs.course.param.FsUserTalentFansParam;
+import com.fs.course.vo.FsUserTalentFansVo;
+import com.fs.course.vo.FsUserTalentFollowVo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.fs.course.mapper.FsUserTalentFollowMapper;
@@ -107,4 +111,24 @@ public class FsUserTalentFollowServiceImpl implements IFsUserTalentFollowService
         return fsUserTalentFollowMapper.deleteFollow(talentId,userId);
     }
 
+    @Override
+    public Integer queryFansCount(Long talentId) {
+        return fsUserTalentFollowMapper.queryFansCount(talentId);
+    }
+
+    @Override
+    public Integer queryIdolCount(Long userId) {
+        return fsUserTalentFollowMapper.queryIdolCount(userId);
+    }
+
+    @Override
+    public List<FsUserTalentFansVo> selectFsUserTalentFansVoList(FsUserTalentFansParam param) {
+        return fsUserTalentFollowMapper.selectFsUserTalentFansVoList(param);
+    }
+
+    @Override
+    public List<FsUserTalentFollowVo> selectFsUserFollowVoList(FsUserTalentFansParam param) {
+        return fsUserTalentFollowMapper.selectFsUserFollowVoList(param);
+    }
+
 }

+ 117 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsUserTalentServiceImpl.java

@@ -1,12 +1,26 @@
 package com.fs.course.service.impl;
 
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+
+import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
+import com.fs.course.domain.FsUserVideo;
+import com.fs.course.service.IFsBlackTalentService;
+import com.fs.course.service.IFsUserTalentFollowService;
+import com.fs.course.service.IFsUserVideoService;
+import com.fs.his.domain.FsUser;
+import com.fs.his.service.IFsUserService;
+import com.fs.his.utils.PhoneUtil;
+import com.fs.huifuPay.sdk.opps.core.utils.StringUtil;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.fs.course.mapper.FsUserTalentMapper;
 import com.fs.course.domain.FsUserTalent;
 import com.fs.course.service.IFsUserTalentService;
+import org.springframework.transaction.annotation.Transactional;
 
 /**
  * 达人Service业务层处理
@@ -19,6 +33,14 @@ public class FsUserTalentServiceImpl implements IFsUserTalentService
 {
     @Autowired
     private FsUserTalentMapper fsUserTalentMapper;
+    @Autowired
+    private IFsUserTalentFollowService userTalentFollowService;
+    @Autowired
+    private IFsBlackTalentService blackTalentService;
+    @Autowired
+    private IFsUserVideoService fsUserVideoService;
+    @Autowired
+    private IFsUserService fsUserService;
 
     /**
      * 查询达人
@@ -101,4 +123,99 @@ public class FsUserTalentServiceImpl implements IFsUserTalentService
             return fsUserTalentMapper.minusFans(talentId);
         }
     }
+
+    @Override
+    public FsUserTalent queryTalentByUserId(Long userId){
+        return fsUserTalentMapper.queryTalentByUserId(userId);
+    }
+
+    @Override
+    @Transactional
+    public int addFsUserTalent(Long userId) {
+        //根据userID查询达人表中是否存在数据
+        FsUserTalent fsUserTalent = queryTalentByUserId(userId);
+        if (null!=fsUserTalent){
+            return 0;
+        }
+        FsUser fsUser1 = fsUserService.selectFsUserByUserId(userId);
+        fsUserTalent = new FsUserTalent();
+        if (!StringUtil.isEmpty(fsUser1.getAvatar())){
+            fsUserTalent.setAvatar(fsUser1.getAvatar());
+        }
+        fsUserTalent.setUserId(fsUser1.getUserId());
+        if (!StringUtil.isEmpty(fsUser1.getPhone())){
+            fsUserTalent.setNickName(fsUser1.getNickName());
+        }
+        if (!StringUtil.isEmpty(fsUser1.getPhone())){
+            String phone = PhoneUtil.decryptPhone(fsUser1.getPhone());
+            fsUserTalent.setPhone(phone);
+
+        }
+        fsUserTalent.setCreateTime(new Date());
+        if (!StringUtil.isEmpty(fsUser1.getSex())){
+            fsUserTalent.setSex(fsUser1.getSex().longValue());
+        }
+        fsUserTalent.setLevel(1l);
+        fsUserTalent.setTalentType("1");
+        fsUserTalent.setIsAudit(1l);
+        fsUserTalent.setAuditTime(new Date());
+        fsUserTalent.setStatus(1l);
+        fsUserTalent.setIsDel(1l);
+        fsUserTalentMapper.insertFsUserTalent(fsUserTalent);
+        return 1;
+    }
+
+    @Override
+    public int updateFsUserTalentByUser(FsUserTalent fsUserTalent)
+    {
+        return fsUserTalentMapper.updateFsUserTalentByUser(fsUserTalent);
+    }
+
+    @Override
+    public R getTalentDetail(Long userId, Long loginUser) {
+
+        HashMap<String, Object> map = new HashMap<>();
+        FsUserTalent fsUserTalent = queryTalentByUserId(userId);
+        if (null==fsUserTalent){
+            return R.error("该用户暂未注册达人身份");
+        }
+
+        //查询达人粉丝数
+        Integer fansCount = userTalentFollowService.queryFansCount(fsUserTalent.getTalentId());
+        //查询关注的达人数量
+        Integer idolCount = userTalentFollowService.queryIdolCount(userId);
+        //查询视频列表
+        List<FsUserVideo> fsUserVideos = fsUserVideoService.selectVideoByTalentId(fsUserTalent.getTalentId());
+        //所有视频的收藏量
+//        Long favoriteNum=0l;
+        Long likeNum = 0l;
+        //拿到用户的所有视频id
+        ArrayList<Long> videoIds = new ArrayList<>();
+        for (FsUserVideo fsUserVideo : fsUserVideos) {
+//            favoriteNum+=fsUserVideo.getFavoriteNum();
+            likeNum+=fsUserVideo.getLikes();
+            //videoIds.add(fsUserVideo.getVideoId());
+        }
+        //查询我的——> 我的视频  视频收藏数量
+        int favoriteNum = fsUserVideoService.countFavoriteVideos(userId);
+        //查询视频收藏数量
+        /*if (fsUserVideos.size()>0){
+            fsUserVideoFavoriteService.queryFavoriteCount(fsUserTalent.getTalentId());
+        }*/
+        //查询当前达人是否被查询的用户拉黑或举报
+        if (loginUser>0){
+            if (blackTalentService.selectBlackTalent(fsUserTalent.getTalentId(),loginUser)>0){
+                map.put("isBlack",1);
+            }
+        }
+        map.put("fsUserTalent",fsUserTalent);
+        map.put("fansCount",fansCount);
+        map.put("idolCount",idolCount);
+        //map.put("fsUserVideos",fsUserVideos);
+        map.put("favoriteNum",favoriteNum);
+        map.put("likeNum",likeNum);
+
+        return R.ok().put("data",map);
+    }
+
 }

+ 93 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsUserVideoServiceImpl.java

@@ -338,6 +338,99 @@ public class FsUserVideoServiceImpl implements IFsUserVideoService {
         return oldList;
     }
 
+    @Override
+    public List<FsUserVideo> selectVideoByTalentId(Long talentId) {
+        return fsUserVideoMapper.selectVideoByTalentId(talentId);
+    }
+
+    @Override
+    public int countFavoriteVideos(Long userId) {
+        return fsUserVideoMapper.countFavoriteVideos(userId);
+    }
+
+    @Override
+    public R addUserVideoByTalent(FsUserVideoAddParam param) {
+        FsUserVideo fsUserVideo = new FsUserVideo();
+        BeanUtils.copyProperties(param, fsUserVideo);
+        fsUserVideo.setCreateTime(DateUtils.getNowDate());
+        fsUserVideo.setIsAudit(0);
+        fsUserVideo.setSource(2);
+        fsUserVideo.setStatus(1);
+        //fsUserVideo.setCateId(param.getCateId());
+//        fsUserVideo.setComments(0L);
+        fsUserVideoMapper.insertFsUserVideo(fsUserVideo);
+        return R.ok();
+    }
+
+    @Override
+    public List<FsUserVideoListUVO> selectFsUserVideoListUVOByUser(Long talentId, boolean oneSelf, Long userId) {
+        List<FsUserVideoListUVO> list = fsUserVideoMapper.selectFsUserVideoListUVOByUser(talentId, oneSelf);
+        /*if (param != null && param.getUserId() != null) {
+            Long userId = param.getUserId();
+            list = selectLikesAndFavorites(userId, list);
+        }*/
+        // 当前视频是否被自己喜欢或收藏
+        if (list.size() > 0) {
+            selectLikesAndFavoritesByMyself(list,userId);
+        }
+
+
+        return list;
+    }
+
+    /**
+     * 删除达人视频信息
+     *
+     * @param videoId 课堂视频id
+     * @param userId 用户id
+     * @return 结果
+     */
+    @Override
+    public R deleteFsUserVideoByVideoIdWithVerify(Long videoId, Long userId) {
+        if (videoId == null) {
+            return R.error("请选择要删除的视频");
+        }
+        FsUserVideoPVO entity = fsUserVideoMapper.selectFsUserVideoPVO(videoId);
+        if (entity == null) {
+            return R.error("视频不存在");
+        } else if (!Objects.equals(entity.getUserId(), userId)) {
+            return R.error("您没有权限删除此视频");
+        }
+        this.deleteFsUserVideoByVideoId(videoId.toString().trim());
+        return R.ok();
+    }
+
+    @Override
+    public R updateVideoStatusWithVerify(FsUserVideo fsUserVideo, Long userId) {
+        if (fsUserVideo.getVideoId() == null) {
+            return R.error("请选择要操作的视频");
+        }
+        FsUserVideoPVO entity = fsUserVideoMapper.selectFsUserVideoPVO(fsUserVideo.getVideoId());
+        if (entity == null) {
+            return R.error("视频不存在");
+        } else if (!Objects.equals(entity.getUserId(), userId)) {
+            return R.error("您没有权限操作此视频");
+        }
+        this.updateFsUserVideoIsShow(new Long[]{fsUserVideo.getVideoId()}, fsUserVideo.getStatus());
+        return R.ok();
+    }
+
+    private void selectLikesAndFavoritesByMyself(List<FsUserVideoListUVO> list, long userId) {
+        List<Long> videoIds = list.stream().map(vo -> Long.parseLong(vo.getId())).collect(Collectors.toList());
+        Map<Long, VideoLikeStatusDTO> likeMaps = fsUserVideoLikeMapper.checkLikes(videoIds, userId);
+        Map<Long, VideoFavoriteStatusDTO> FavoriteMaps = fsUserVideoFavoriteMapper.checkFavorites(videoIds, userId);
+        long videoId;
+        for (FsUserVideoListUVO entity : list) {
+            videoId = Long.parseLong(entity.getId());
+            if (likeMaps.containsKey(videoId)) {
+                entity.setLike(1);
+            }
+            if (FavoriteMaps.containsKey(videoId)) {
+                entity.setFavorite(1);
+            }
+        }
+    }
+
     public static String updateUrlPrefix(String url) {
         final String oldPrefix = "https://obs.ylrztop.com";
         final String newPrefix = "https://rtobs.ylrztop.com";

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor