Browse Source

Merge branch 'refs/heads/master' into feature_260128_mergeOrder

yuhongqi 1 day ago
parent
commit
9c66dca7cb
100 changed files with 2750 additions and 527 deletions
  1. 22 0
      fs-admin/src/main/java/com/fs/api/controller/IndexStatisticsController.java
  2. 13 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseTrainingCampController.java
  3. 52 9
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseVideoController.java
  4. 10 0
      fs-admin/src/main/java/com/fs/his/task/Task.java
  5. 9 1
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreAfterSalesScrmController.java
  6. 8 0
      fs-admin/src/main/java/com/fs/qw/controller/QwPushCountController.java
  7. 8 0
      fs-admin/src/main/java/com/fs/qw/controller/QwSopController.java
  8. 3 1
      fs-admin/src/main/java/com/fs/qw/controller/QwUserController.java
  9. 5 0
      fs-admin/src/main/java/com/fs/web/controller/system/SysConfigController.java
  10. 23 0
      fs-company/src/main/java/com/fs/company/controller/common/CommonController.java
  11. 31 1
      fs-company/src/main/java/com/fs/company/controller/company/CompanyProfileController.java
  12. 9 3
      fs-company/src/main/java/com/fs/company/controller/company/CompanyUserController.java
  13. 24 5
      fs-company/src/main/java/com/fs/company/controller/company/IndexStatisticsController.java
  14. 6 2
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseFinishTempParentController.java
  15. 3 1
      fs-company/src/main/java/com/fs/company/controller/course/FsCourseWatchLogController.java
  16. 7 2
      fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactController.java
  17. 3 1
      fs-company/src/main/java/com/fs/company/controller/qw/QwExternalContactTransferLogController.java
  18. 3 1
      fs-company/src/main/java/com/fs/company/controller/qw/QwFriendWelcomeController.java
  19. 3 1
      fs-company/src/main/java/com/fs/company/controller/qw/QwGroupChatController.java
  20. 3 1
      fs-company/src/main/java/com/fs/company/controller/qw/QwSopController.java
  21. 3 1
      fs-company/src/main/java/com/fs/company/controller/qw/QwSopLogsController.java
  22. 14 0
      fs-company/src/main/java/com/fs/company/controller/qw/QwSopTempController.java
  23. 3 1
      fs-company/src/main/java/com/fs/company/controller/qw/QwUserController.java
  24. 3 1
      fs-company/src/main/java/com/fs/company/controller/qw/QwWorkTaskNewController.java
  25. 1 0
      fs-company/src/main/java/com/fs/framework/config/SecurityConfig.java
  26. 209 4
      fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java
  27. 19 0
      fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java
  28. 472 100
      fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java
  29. 15 0
      fs-qwhook-sop/src/main/java/com/fs/app/controller/ApisFsUserCourseVideoController.java
  30. 22 0
      fs-qwhook-sop/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  31. 88 0
      fs-qwhook/src/main/java/com/fs/app/controller/ApisCommonController.java
  32. 50 0
      fs-service/src/main/java/com/fs/aiSoundReplication/mapper/VoiceCloneMapper.java
  33. 83 0
      fs-service/src/main/java/com/fs/aiSoundReplication/param/TtsChargeParam.java
  34. 7 1
      fs-service/src/main/java/com/fs/aiSoundReplication/service/TtsService.java
  35. 66 4
      fs-service/src/main/java/com/fs/aiSoundReplication/service/impl/TtsServiceImpl.java
  36. 1 1
      fs-service/src/main/java/com/fs/aiTongueApi/config/AiTongueConfig.java
  37. 15 4
      fs-service/src/main/java/com/fs/aiTongueApi/service/impl/AiTongueServiceImpl.java
  38. 12 0
      fs-service/src/main/java/com/fs/company/param/VcCompanyUser.java
  39. 2 0
      fs-service/src/main/java/com/fs/company/service/ICompanyDeptService.java
  40. 6 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyDeptServiceImpl.java
  41. 3 0
      fs-service/src/main/java/com/fs/course/config/CourseConfig.java
  42. 29 0
      fs-service/src/main/java/com/fs/course/domain/FsDepVideoShow.java
  43. 5 0
      fs-service/src/main/java/com/fs/course/domain/FsUserCourseVideo.java
  44. 9 2
      fs-service/src/main/java/com/fs/course/mapper/FsCourseRedPacketLogMapper.java
  45. 1 1
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  46. 43 0
      fs-service/src/main/java/com/fs/course/mapper/FsDepVideoShowMapper.java
  47. 1 1
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java
  48. 3 0
      fs-service/src/main/java/com/fs/course/mapper/FsVideoResourceMapper.java
  49. 17 0
      fs-service/src/main/java/com/fs/course/param/FsCourseRedPacketLogParam.java
  50. 5 0
      fs-service/src/main/java/com/fs/course/param/FsUserCourseVideoAddKfUParam.java
  51. 2 0
      fs-service/src/main/java/com/fs/course/service/IFsUserCourseTrainingCampService.java
  52. 3 0
      fs-service/src/main/java/com/fs/course/service/ITencentCloudCosService.java
  53. 5 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseTrainingCampServiceImpl.java
  54. 76 6
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  55. 36 0
      fs-service/src/main/java/com/fs/course/service/impl/TencentCloudCosService.java
  56. 13 0
      fs-service/src/main/java/com/fs/course/vo/FsUserCourseVideoH5DVO.java
  57. 10 0
      fs-service/src/main/java/com/fs/course/vo/newfs/FsUserCourseVideoDetailsVO.java
  58. 1 2
      fs-service/src/main/java/com/fs/fastGpt/service/impl/AiHookServiceImpl.java
  59. 261 4
      fs-service/src/main/java/com/fs/gtPush/service/impl/uniPush2ServiceImpl.java
  60. 1 1
      fs-service/src/main/java/com/fs/gtPush/service/uniPush2Service.java
  61. 8 0
      fs-service/src/main/java/com/fs/his/domain/FsAppVersion.java
  62. 4 0
      fs-service/src/main/java/com/fs/his/domain/FsUser.java
  63. 2 1
      fs-service/src/main/java/com/fs/his/enums/FsUserOperationEnum.java
  64. 3 1
      fs-service/src/main/java/com/fs/his/mapper/FsDoctorMapper.java
  65. 3 4
      fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java
  66. 7 0
      fs-service/src/main/java/com/fs/his/service/IFsHealthTongueService.java
  67. 70 0
      fs-service/src/main/java/com/fs/his/service/impl/FsHealthTongueServiceImpl.java
  68. 232 108
      fs-service/src/main/java/com/fs/his/service/impl/FsInquiryOrderMsgServiceImpl.java
  69. 0 1
      fs-service/src/main/java/com/fs/his/utils/PhoneUtil.java
  70. 9 0
      fs-service/src/main/java/com/fs/his/vo/FsUserVO.java
  71. 6 1
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java
  72. 1 1
      fs-service/src/main/java/com/fs/im/service/impl/OpenIMServiceImpl.java
  73. 1 0
      fs-service/src/main/java/com/fs/im/vo/OpenImMsgCallBackVO.java
  74. 6 0
      fs-service/src/main/java/com/fs/qw/mapper/QwWatchLogMapper.java
  75. 6 0
      fs-service/src/main/java/com/fs/qw/param/QwWatchLogStatisticsListParam.java
  76. 30 26
      fs-service/src/main/java/com/fs/qw/service/AsyncQwAiChatSopService.java
  77. 4 1
      fs-service/src/main/java/com/fs/qw/service/impl/QwContactWayServiceImpl.java
  78. 176 182
      fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java
  79. 4 0
      fs-service/src/main/java/com/fs/qw/vo/QwSopCourseFinishTempSetting.java
  80. 6 0
      fs-service/src/main/java/com/fs/sop/domain/QwSopTemp.java
  81. 3 0
      fs-service/src/main/java/com/fs/sop/domain/QwSopTempRules.java
  82. 3 0
      fs-service/src/main/java/com/fs/sop/mapper/QwSopLogsMapper.java
  83. 4 0
      fs-service/src/main/java/com/fs/sop/service/IQwSopService.java
  84. 49 3
      fs-service/src/main/java/com/fs/sop/service/impl/QwSopServiceImpl.java
  85. 20 3
      fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempServiceImpl.java
  86. 196 5
      fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java
  87. 1 1
      fs-service/src/main/java/com/fs/statis/dto/AnalysisPreviewQueryDTO.java
  88. 7 0
      fs-service/src/main/java/com/fs/statis/service/impl/StatisticsServiceImpl.java
  89. 2 1
      fs-service/src/main/java/com/fs/wxwork/service/WxWorkService.java
  90. 3 1
      fs-service/src/main/java/com/fs/wxwork/service/WxWorkServiceImpl.java
  91. 2 2
      fs-service/src/main/resources/application-config-dev-jnlzjk.yml
  92. 2 2
      fs-service/src/main/resources/application-config-dev-xcsw.yml
  93. 4 4
      fs-service/src/main/resources/application-config-druid-bjzm-test.yml
  94. 4 4
      fs-service/src/main/resources/application-config-druid-bjzm.yml
  95. 2 2
      fs-service/src/main/resources/application-config-druid-cfryt.yml
  96. 2 2
      fs-service/src/main/resources/application-config-druid-ddgy.yml
  97. 2 2
      fs-service/src/main/resources/application-config-druid-fby.yml
  98. 2 2
      fs-service/src/main/resources/application-config-druid-gzzdy.yml
  99. 2 2
      fs-service/src/main/resources/application-config-druid-hdt.yml
  100. 2 2
      fs-service/src/main/resources/application-config-druid-heyantang.yml

+ 22 - 0
fs-admin/src/main/java/com/fs/api/controller/IndexStatisticsController.java

@@ -13,6 +13,7 @@ import com.fs.statis.StatisticsRedisConstant;
 import com.fs.statis.dto.*;
 import com.fs.statis.param.StatisticsDeptCompanyParam;
 import com.fs.statis.service.IStatisticsService;
+import com.fs.statis.service.impl.StatisticsCompanyServiceImpl;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.service.ISysConfigService;
 import com.fs.system.service.ISysDeptService;
@@ -56,6 +57,9 @@ public class IndexStatisticsController {
 
     @Autowired
     private IStatisticsService statisticsService;
+    @Autowired
+    private StatisticsCompanyServiceImpl statisticsCompanyService;
+
     /**
      * 分析概览
      */
@@ -72,6 +76,9 @@ public class IndexStatisticsController {
         if(userType == null) {
             userType = 0;
         }
+        if(param.getType().equals(5)){
+            return R.ok().put("data",statisticsService.analysisPreview(param));
+        }
         if(medicalMallConfig.isStatics()|| (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
             analysisPreviewDTO = redisCache.getCacheObject(String.format("%s:%d:%d",DATA_OVERVIEW_DEALER_ANALYSISPREVIEW,type,userType));
         }else if(param.getCompanyId() != null){
@@ -255,6 +262,9 @@ public class IndexStatisticsController {
             userType = 0;
         }
         List<WatchEndPlayTrendDTO> watchEndPlayTrendDTOS;
+        if (param.getType().equals(5)){
+            return R.ok().put("data", statisticsCompanyService.watchEndPlayTrend(param));
+        }
         // 参考watchCourseTopTen方法的处理逻辑
         if (!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
             String key = String.format("%s:%d:%d", DATA_OVERVIEW_DEALER_CHARTS, type,userType);
@@ -339,6 +349,9 @@ public class IndexStatisticsController {
             userType = 0;
         }
         List<DeaMemberTopTenDTO> deaMemberTopTenDTOS = new ArrayList<>();
+        if (param.getType().equals(5)){
+            return R.ok().put("data", statisticsService.deaMemberTopTen(param));
+        }
         // 参考deaMemberTopTen方法处理逻辑
         if (!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
             String key = String.format("%s:%d:%d:%d", CHARTS_MEMBER_TOP_TEN_WATCH, type, statisticalType,userType);
@@ -396,6 +409,9 @@ public class IndexStatisticsController {
         Integer dataType = param.getDataType();
         Integer userType = param.getUserType();
         List<RewardMoneyTopTenDTO> rewardMoneyTopTenDTOS = new ArrayList<>();
+        if (param.getType().equals(5)){
+            return R.ok().put("data", statisticsService.rewardMoneyTopTen(param));
+        }
         // 参考rewardMoneyTopTen方法处理逻辑
         if(!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
             String key = String.format("%s:%d:%d:%d", CHARTS_REWARD_MONEY_TOP_TEN, type,dataType,userType);
@@ -450,6 +466,9 @@ public class IndexStatisticsController {
         Integer type = param.getType();
         Integer userType = param.getUserType();
         List<RewardMoneyTrendDTO> rewardMoneyTrendDTOS = new ArrayList<>();
+        if (param.getType().equals(5)){
+            return R.ok().put("data", statisticsService.rewardMoneyTrendDTO(param));
+        }
         // 参考rewardMoneyTrend方法处理逻辑
         if(!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
             String key = String.format("%s:%d:%d", CHARTS_REWARD_MONEY_TREND, type,userType);
@@ -503,6 +522,9 @@ public class IndexStatisticsController {
         Integer statisticalType = param.getStatisticalType();
         Integer userType = param.getUserType();
         List<CourseStatsDTO> courseStatsDTOS;
+        if (param.getType().equals(5)){
+            return R.ok().put("data", statisticsCompanyService.watchCourseTopTen(param));
+        }
         if (!medicalMallConfig.isStatics() || (param.getCompanyId() == null && param.getDeptId() == null) || (param.getCompanyId() == null && param.getDeptId() == 1)){
             courseStatsDTOS = redisCache.getCacheObject(String.format("%s:%d:%d:%d:%s", CHARTS_WATCH_TOP_TEN, type,statisticalType,userType,sort));
         }else if(param.getCompanyId() != null){

+ 13 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseTrainingCampController.java

@@ -68,6 +68,19 @@ public class FsUserCourseTrainingCampController {
         return AjaxResult.success(new PageInfo<>(list));
     }
 
+    /**
+     * 查全部训练营
+     * @param
+     * @param
+     * @param
+     * @return
+     */
+    @GetMapping("/listAll")
+    public R listAll() {
+        List<FsUserCourseTrainingCampVO> campList = fsUserCourseTrainingCampService.selectFsUserCourseTrainingCampListAll();
+        return R.ok().put("data", new PageInfo<>(campList));
+    }
+
     /**
      * 新增训练营
      * @param params    参数

+ 52 - 9
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseVideoController.java

@@ -2,6 +2,7 @@ package com.fs.course.controller;
 
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
@@ -12,13 +13,12 @@ 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.FsDepVideoShow;
 import com.fs.course.domain.FsUserCourse;
 import com.fs.course.domain.FsUserCourseVideo;
+import com.fs.course.mapper.FsDepVideoShowMapper;
 import com.fs.course.mapper.FsUserCourseVideoMapper;
-import com.fs.course.param.BatchEditCoverParam;
-import com.fs.course.param.BatchRedUpdate;
-import com.fs.course.param.BatchVideoSvae;
-import com.fs.course.param.CourseVideoUpdates;
+import com.fs.course.param.*;
 import com.fs.course.service.IFsUserCourseService;
 import com.fs.course.service.IFsUserCourseVideoService;
 import com.fs.course.vo.FsUserCourseVideoChooseVO;
@@ -29,6 +29,7 @@ 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.beans.factory.annotation.Value;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
@@ -59,7 +60,10 @@ public class FsUserCourseVideoController extends BaseController
 
     @Autowired
     private ISysConfigService configService;
-
+    @Autowired
+    private FsDepVideoShowMapper fsDepVideoShowMapper;
+    @Value("${cloud_host.company_name}")
+    private String companyName;
     /**
      * 查询课堂视频列表
      */
@@ -138,17 +142,56 @@ public class FsUserCourseVideoController extends BaseController
         // 设置项目ID
         FsUserCourse fsUserCourse = fsUserCourseService.selectFsUserCourseByCourseId(fsUserCourseVideo.getCourseId());
         fsUserCourseVideo.setProjectId(fsUserCourse.getProject());
-        return toAjax(fsUserCourseVideoService.insertFsUserCourseVideo(fsUserCourseVideo));
+        int result = fsUserCourseVideoService.insertFsUserCourseVideo(fsUserCourseVideo);
+        if ("北京卓美".equals(companyName) && result > 0 &&  fsUserCourseVideo.getShowProduct() != null) {
+                // 先检查是否存在相同记录
+                QueryWrapper<FsDepVideoShow> queryWrapper = new QueryWrapper<>();
+                Long videoId = fsUserCourseVideo.getVideoId();
+                queryWrapper.eq("video_id", videoId);
+                FsDepVideoShow fsDepVideoShow = fsDepVideoShowMapper.selectOne(queryWrapper);
+                if (fsDepVideoShow != null) {
+                    // 更新现有记录
+                    fsDepVideoShow.setIsShow(fsUserCourseVideo.getShowProduct().toString());
+                    fsDepVideoShowMapper.updateByVideoId(fsDepVideoShow);
+                } else {
+                    // 插入新记录
+                    fsDepVideoShow = new FsDepVideoShow();
+                    fsDepVideoShow.setVideoId(videoId);
+                    fsDepVideoShow.setIsShow(fsUserCourseVideo.getShowProduct().toString());
+                    fsDepVideoShow.setDepId(loginUser.getDeptId());
+                    fsDepVideoShowMapper.insertFsDepVideoShowByVideoId(fsDepVideoShow);
+                }
+        }
+        return toAjax(result);
     }
-
     /**
      * 修改课堂视频
      */
     @PreAuthorize("@ss.hasPermi('course:userCourseVideo:edit')")
     @Log(title = "课堂视频", businessType = BusinessType.UPDATE)
     @PutMapping
-    public AjaxResult edit(@RequestBody FsUserCourseVideo fsUserCourseVideo)
-    {
+    public AjaxResult edit(@RequestBody FsUserCourseVideo fsUserCourseVideo) {
+        if ("北京卓美".equals(companyName)) {
+            Integer showProduct = fsUserCourseVideo.getShowProduct();
+            if (showProduct != null) {
+                // 先检查是否存在相同记录
+                QueryWrapper<FsDepVideoShow> queryWrapper = new QueryWrapper<>();
+                Long videoId = fsUserCourseVideo.getVideoId();
+                queryWrapper.eq("video_id", videoId);
+                FsDepVideoShow fsDepVideoShow = fsDepVideoShowMapper.selectOne(queryWrapper);
+                if (fsDepVideoShow != null) {
+                    // 更新现有记录
+                    fsDepVideoShow.setIsShow(showProduct.toString());
+                    fsDepVideoShowMapper.updateByVideoId(fsDepVideoShow);
+                } else {
+                    // 插入新记录
+                    fsDepVideoShow = new FsDepVideoShow();
+                    fsDepVideoShow.setIsShow(showProduct.toString());
+                    fsDepVideoShow.setVideoId(videoId);
+                    fsDepVideoShowMapper.insertFsDepVideoShowByVideoId(fsDepVideoShow);
+                }
+            }
+        }
         return toAjax(fsUserCourseVideoService.updateFsUserCourseVideo(fsUserCourseVideo));
     }
 

+ 10 - 0
fs-admin/src/main/java/com/fs/his/task/Task.java

@@ -656,11 +656,21 @@ public class Task {
         tencentCloudCosService.videoTranscode();
     }
 
+    public void videoTranscodeById(String videoId) throws Exception {
+
+        tencentCloudCosService.videoTranscodeById(Long.parseLong(videoId));
+    }
+
     public void updateUrl() throws Exception {
 
         tencentCloudCosService.updateUrl();
     }
 
+    public void updateUrlById(String videoId) throws Exception {
+
+        tencentCloudCosService.updateUrlByVideoId(Long.parseLong(videoId));
+    }
+
     public void addPrescribeImg() throws Exception {
         List<Long> ids = fsPrescribeService.selectFsPrescribeByPrescribeIdByOrderType();
         for (Long id : ids) {

+ 9 - 1
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreAfterSalesScrmController.java

@@ -12,6 +12,7 @@ import com.fs.common.utils.ParseUtils;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.config.cloud.CloudHostProper;
 import com.fs.framework.web.service.TokenService;
 import com.fs.his.domain.FsUser;
 import com.fs.his.service.IFsUserService;
@@ -68,6 +69,9 @@ public class FsStoreAfterSalesScrmController extends BaseController
     @Value("${cloud_host.company_name}")
     private String signProjectName;
 
+    @Autowired
+    private CloudHostProper cloudHostProper;
+
     /**
      * 查询售后记录列表
      */
@@ -78,7 +82,11 @@ public class FsStoreAfterSalesScrmController extends BaseController
         startPage();
         List<FsStoreAfterSalesVO> list = fsStoreAfterSalesService.selectFsStoreAfterSalesListVO(fsStoreAfterSales);
         for (FsStoreAfterSalesVO vo : list){
-            vo.setUserPhone(ParseUtils.parsePhone(vo.getUserPhone()));
+            if (!"广州郑多燕".equals(cloudHostProper.getCompanyName())) {
+                vo.setUserPhone(ParseUtils.parsePhone(vo.getUserPhone()));
+            } else {
+                vo.setUserPhone(vo.getUserPhone());
+            }
         }
         return getDataTable(list);
     }

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

@@ -201,6 +201,14 @@ public class QwPushCountController extends BaseController {
         rspData.setTotal(total);
         return rspData;
     }
+
+    @GetMapping("/tokenExport")
+    public AjaxResult export(FastGptPushTokenTotal pushTokenInfo){
+        List<FastGptPushTokenTotal> list = qwPushCountService.selectFastGptPushTokenTotalList(pushTokenInfo);
+        ExcelUtil<FastGptPushTokenTotal> util = new ExcelUtil<FastGptPushTokenTotal>(FastGptPushTokenTotal.class);
+        return util.exportExcel(list,"token统计");
+    }
+
     @PreAuthorize("@ss.hasPermi('qw:qwPushCount:tokenListDept')")
     @GetMapping("/tokenListDept")
     public TableDataInfo tokenListDept(FastGptPushTokenDeptTotalParam pushTokenInfo) {

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

@@ -123,6 +123,14 @@ public class QwSopController extends BaseController
         List<QwSop> list = qwSopService.selectQwSopMyList(qwSop);
         return getDataTable(list);
     }
+    /**
+     * 查询企微sop列表-全部
+     */
+//    @PreAuthorize("@ss.hasPermi('qw:sop:allList')")
+    @PostMapping("/allList")
+    public R allList(@RequestBody QwSop qwSop) {
+        return R.ok().put("data", qwSopService.selectQwSopMyList(qwSop));
+    }
     /**
      * 导出企微sop列表
      */

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

@@ -204,7 +204,9 @@ public class QwUserController extends BaseController {
             combinedList.add(deptId);
         }
         //本部门的下级部门
-        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //本部门的全部下级部门
+        List<Long> deptList = companyDeptService.getCurrentDeptIdDownTreeIds(deptId);
         if (!deptList.isEmpty()){
             combinedList.addAll(deptList);
         }

+ 5 - 0
fs-admin/src/main/java/com/fs/web/controller/system/SysConfigController.java

@@ -6,6 +6,7 @@ import cn.hutool.core.util.ObjectUtil;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.SecurityUtils;
+import com.fs.sop.service.impl.QwSopServiceImpl;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
@@ -38,6 +39,8 @@ public class SysConfigController extends BaseController {
     private ISysConfigService configService;
     @Autowired
     public RedisCache redisCache;
+    @Autowired
+    private QwSopServiceImpl qwSopServiceImpl;
 
     /**
      * 获取参数配置列表
@@ -140,6 +143,8 @@ public class SysConfigController extends BaseController {
         config.setCreateBy(SecurityUtils.getUsername());
         //修复只能更新的BUG
         if (null != config.getConfigId()) {
+//            今正加了手动关发群
+            qwSopServiceImpl.updateGroupSopStatus(config);
             return toAjax(configService.updateConfig(config));
         } else {
             return toAjax(configService.insertConfig(config));

+ 23 - 0
fs-company/src/main/java/com/fs/company/controller/common/CommonController.java

@@ -1,6 +1,8 @@
 package com.fs.company.controller.common;
 
 import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fs.common.config.FSConfig;
 import com.fs.common.constant.Constants;
 import com.fs.common.core.domain.AjaxResult;
@@ -21,13 +23,19 @@ import com.fs.framework.service.TokenService;
 import com.fs.his.domain.FsExportTask;
 import com.fs.his.dto.InquiryConfigDTO;
 import com.fs.his.service.IFsExportTaskService;
+import com.fs.his.service.IFsInquiryOrderMsgService;
+import com.fs.im.dto.OpenImMsgCallBackResponse;
 import com.fs.im.dto.OpenImResponseDTO;
 import com.fs.im.service.OpenIMService;
+import com.fs.im.vo.OpenImMsgCallBackVO;
 import com.fs.qw.service.IQwWorkTaskService;
 import com.fs.qwApi.service.QwApiService;
 import com.fs.system.oss.CloudStorageService;
 import com.fs.system.oss.OSSFactory;
 import com.fs.system.service.ISysConfigService;
+import com.google.gson.Gson;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -90,6 +98,9 @@ public class CommonController
     @Autowired
     private IQwWorkTaskService qwWorkTaskService;
 
+    @Autowired
+    private IFsInquiryOrderMsgService inquiryOrderMsgService;
+
     @PostMapping("common/test")
     public R test() throws Exception
     {
@@ -363,5 +374,17 @@ public class CommonController
         return AjaxResult.success(inquirySelect);
     }
 
+    @ApiOperation("openIm聊天数据回调")
+    @PostMapping(value = "/app/common/callbackAfterSendSingleMsgCommand")
+    public OpenImMsgCallBackResponse openImMsgCallBack(@RequestBody String body, HttpServletRequest request) throws JsonProcessingException {
+
+        Gson gson = new Gson();
+        OpenImMsgCallBackVO messageInfo = gson.fromJson(body, OpenImMsgCallBackVO.class);
+
+        //openIMService.AiAutoReply(messageInfo);
+
+        log.info("收到的参数{}", JSON.toJSONString(messageInfo));
+        return inquiryOrderMsgService.openImSaveMsg(messageInfo);
+    }
 
 }

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

@@ -7,6 +7,7 @@ import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.enums.ImTypeEnum;
+import com.fs.common.exception.file.OssException;
 import com.fs.common.utils.PatternUtils;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.file.FileUploadUtils;
@@ -18,6 +19,8 @@ import com.fs.framework.security.SecurityUtils;
 import com.fs.framework.service.TokenService;
 import com.fs.im.config.ImTypeConfig;
 import com.fs.im.service.OpenIMService;
+import com.fs.system.oss.CloudStorageService;
+import com.fs.system.oss.OSSFactory;
 import com.fs.system.service.ISysConfigService;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -140,9 +143,16 @@ public class CompanyProfileController extends BaseController
         if (!file.isEmpty())
         {
             LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
-            String avatar = FileUploadUtils.upload(FSConfig.getAvatarPath(), file);
+            if (file.isEmpty())
+            {
+                throw new OssException("上传文件不能为空");
+            }
+            CloudStorageService storage = OSSFactory.build();
+            String avatar = storage.uploadSuffix(file.getBytes(), ".jpg");
             if (userService.updateUserAvatar(loginUser.getUsername(), avatar)>0)
             {
+                CompanyUser companyUser = userService.selectUserByUserName(loginUser.getUsername());
+                openIMService.updateUserInfo(companyUser);
                 AjaxResult ajax = AjaxResult.success();
                 ajax.put("imgUrl", avatar);
                 // 更新缓存用户头像
@@ -153,4 +163,24 @@ public class CompanyProfileController extends BaseController
         }
         return AjaxResult.error("上传图片异常,请联系管理员");
     }
+
+    /**
+     * 头像上传
+     */
+    @Log(title = "用户头像地址保存", businessType = BusinessType.UPDATE)
+    @PostMapping("/avatarNew")
+    public AjaxResult avatarNew(@RequestParam("avatarUrl") String avatarUrl)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        if (userService.updateUserAvatar(loginUser.getUsername(), avatarUrl)>0)
+        {
+            AjaxResult ajax = AjaxResult.success();
+            ajax.put("imgUrl", avatarUrl);
+            // 更新缓存用户头像
+            loginUser.getUser().setAvatar(avatarUrl);
+            tokenService.setLoginUser(loginUser);
+            return ajax;
+        }
+        return AjaxResult.error("保存图片异常,请联系管理员");
+    }
 }

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

@@ -149,7 +149,9 @@ public class CompanyUserController extends BaseController {
             combinedDpetList.add(deptId);
         }
         //本部门的下级部门
-        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //本部门的全部下级部门
+        List<Long> deptList = companyDeptService.getCurrentDeptIdDownTreeIds(deptId);
         if (!deptList.isEmpty()){
             combinedDpetList.addAll(deptList);
         }
@@ -576,7 +578,9 @@ public class CompanyUserController extends BaseController {
             combinedList.add(deptId);
         }
         //本部门的下级部门
-        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //本部门的全部下级部门
+        List<Long> deptList = companyDeptService.getCurrentDeptIdDownTreeIds(deptId);
         if (!deptList.isEmpty()){
             combinedList.addAll(deptList);
         }
@@ -672,7 +676,9 @@ public class CompanyUserController extends BaseController {
             }
 
         //本部门的下级部门
-        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //本部门的全部下级部门
+        List<Long> deptList = companyDeptService.getCurrentDeptIdDownTreeIds(deptId);
         if (!deptList.isEmpty()){
             combinedDeptList.addAll(deptList);
         }

+ 24 - 5
fs-company/src/main/java/com/fs/company/controller/company/IndexStatisticsController.java

@@ -11,6 +11,7 @@ import com.fs.framework.service.TokenService;
 import com.fs.statis.StatisticsRedisConstant;
 import com.fs.statis.dto.*;
 import com.fs.statis.service.IStatisticsService;
+import com.fs.statis.service.impl.StatisticsCompanyServiceImpl;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
@@ -42,6 +43,9 @@ public class IndexStatisticsController {
 
     @Autowired
     CloudHostProper cloudHostProper;
+    @Autowired
+    private StatisticsCompanyServiceImpl statisticsCompanyService;
+
     /**
      * 分析概览
      */
@@ -60,7 +64,11 @@ public class IndexStatisticsController {
         }
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         param.setCompanyId(loginUser.getCompany().getCompanyId());
-        analysisPreviewDTO = redisCache.getCacheObject(String.format("%s:%d:%d:%d",DATA_OVERVIEW_DEALER_ANALYSISPREVIEW,type,userType,param.getCompanyId()));
+        if (param.getType().equals(5)){// 指定日期直接查,不走缓存
+            return R.ok().put("data",statisticsCompanyService.analysisPreview(param));
+        }else {
+            analysisPreviewDTO = redisCache.getCacheObject(String.format("%s:%d:%d:%d",DATA_OVERVIEW_DEALER_ANALYSISPREVIEW,type,userType,param.getCompanyId()));
+        }
 
         return R.ok().put("data",analysisPreviewDTO);
     }
@@ -179,7 +187,9 @@ public class IndexStatisticsController {
         }else{
             Long companyId = loginUser.getCompany().getCompanyId();
             param.setCompanyId(companyId);
-
+            if (param.getType().equals(5)){
+                return R.ok().put("data", statisticsCompanyService.watchEndPlayTrend(param));
+            }
             String key = String.format("%s:%d:%d:%d", DATA_OVERVIEW_DEALER_CHARTS, type,userType,param.getCompanyId());
             List<DeaMemberTopTenDTO> deaMemberTopTenDTOS = redisCache.getCacheObject(key);
             return R.ok().put("data", deaMemberTopTenDTOS);
@@ -204,7 +214,9 @@ public class IndexStatisticsController {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long companyId = loginUser.getCompany().getCompanyId();
         param.setCompanyId(companyId);
-
+        if (param.getType().equals(5)){
+            return R.ok().put("data", statisticsService.deaMemberTopTen(param));
+        }
         List<DeaMemberTopTenDTO> deaMemberTopTenDTOS = redisCache.getCacheObject(String.format("%s:%d:%d:%d:%d", CHARTS_MEMBER_TOP_TEN_WATCH, type, statisticalType,userType,param.getCompanyId()));
         if(deaMemberTopTenDTOS == null){
             deaMemberTopTenDTOS = new ArrayList<>();
@@ -223,7 +235,9 @@ public class IndexStatisticsController {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long companyId = loginUser.getCompany().getCompanyId();
         param.setCompanyId(companyId);
-
+        if (param.getType().equals(5)){
+            R.ok().put("data", statisticsCompanyService.rewardMoneyTopTen(param));
+        }
         List<RewardMoneyTopTenDTO> rewardMoneyTopTenDTOS = redisCache.getCacheObject( String.format("%s:%d:%d:%d:%d", CHARTS_REWARD_MONEY_TOP_TEN, type,dataType,userType,param.getCompanyId()));
         return R.ok().put("data", rewardMoneyTopTenDTOS);
     }
@@ -238,7 +252,9 @@ public class IndexStatisticsController {
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         Long companyId = loginUser.getCompany().getCompanyId();
         param.setCompanyId(companyId);
-
+        if (param.getType().equals(5)){
+            return R.ok().put("data", statisticsCompanyService.rewardMoneyTrendDTO(param));
+        }
         List<RewardMoneyTrendDTO> rewardMoneyTrendDTOS = redisCache.getCacheObject( String.format("%s:%d:%d:%d", CHARTS_REWARD_MONEY_TREND, type,userType,param.getCompanyId()));
         return R.ok().put("data", rewardMoneyTrendDTOS);
     }
@@ -256,6 +272,9 @@ public class IndexStatisticsController {
         Long companyId = loginUser.getCompany().getCompanyId();
         param.setCompanyId(companyId);
 
+        if (param.getType().equals(5)){
+            return R.ok().put("data",statisticsService.watchCourseTopTen(param));
+        }
         List<CourseStatsDTO> courseStatsDTOS = redisCache.getCacheObject(String.format("%s:%d:%d:%d:%s:%d", CHARTS_WATCH_TOP_TEN, type,statisticalType,userType,sort,param.getCompanyId()));
         return R.ok().put("data", courseStatsDTOS);
     }

+ 6 - 2
fs-company/src/main/java/com/fs/company/controller/course/FsCourseFinishTempParentController.java

@@ -92,7 +92,9 @@ public class FsCourseFinishTempParentController extends BaseController
             combinedList.add(deptId);
         }
         //本部门的下级部门
-        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //本部门的全部下级部门
+        List<Long> deptList = companyDeptService.getCurrentDeptIdDownTreeIds(deptId);
         if (!deptList.isEmpty()){
             combinedList.addAll(deptList);
         }
@@ -157,7 +159,9 @@ public class FsCourseFinishTempParentController extends BaseController
             combinedList.add(deptId);
         }
         //本部门的下级部门
-        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //本部门的全部下级部门
+        List<Long> deptList = companyDeptService.getCurrentDeptIdDownTreeIds(deptId);
         if (!deptList.isEmpty()){
             combinedList.addAll(deptList);
         }

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

@@ -118,7 +118,9 @@ public class FsCourseWatchLogController extends BaseController
         }
 
         //本部门的下级部门
-        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //本部门的全部下级部门
+        List<Long> deptList = companyDeptService.getCurrentDeptIdDownTreeIds(deptId);
         if (!deptList.isEmpty()){
             combinedList.addAll(deptList);
         }

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

@@ -210,7 +210,10 @@ public class QwExternalContactController extends BaseController
             combinedList.add(deptId);
         }
         //本部门的下级部门
-        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+
+        //本部门的全部下级部门
+        List<Long> deptList = companyDeptService.getCurrentDeptIdDownTreeIds(deptId);
         if (!deptList.isEmpty()){
             combinedList.addAll(deptList);
         }
@@ -832,7 +835,9 @@ public class QwExternalContactController extends BaseController
                 combinedList.add(deptId);
             }
             //本部门的下级部门
-            List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+            //List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+            //本部门的全部下级部门
+            List<Long> deptList = companyDeptService.getCurrentDeptIdDownTreeIds(deptId);
             if (!deptList.isEmpty()){
                 combinedList.addAll(deptList);
             }

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

@@ -73,7 +73,9 @@ public class QwExternalContactTransferLogController extends BaseController
             combinedList.add(deptId);
         }
         //本部门的下级部门
-        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //本部门的全部下级部门
+        List<Long> deptList = companyDeptService.getCurrentDeptIdDownTreeIds(deptId);
         if (!deptList.isEmpty()){
             combinedList.addAll(deptList);
         }

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

@@ -82,7 +82,9 @@ public class QwFriendWelcomeController extends BaseController
             combinedList.add(deptId);
         }
         //本部门的下级部门
-        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //本部门的全部下级部门
+        List<Long> deptList = companyDeptService.getCurrentDeptIdDownTreeIds(deptId);
         if (!deptList.isEmpty()){
             combinedList.addAll(deptList);
         }

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

@@ -74,7 +74,9 @@ public class QwGroupChatController extends BaseController
             combinedList.add(deptId);
         }
         //本部门的下级部门
-        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //本部门的全部下级部门
+        List<Long> deptList = companyDeptService.getCurrentDeptIdDownTreeIds(deptId);
         if (!deptList.isEmpty()){
             combinedList.addAll(deptList);
         }

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

@@ -114,7 +114,9 @@ public class QwSopController extends BaseController
             combinedList.add(deptId);
         }
         //本部门的下级部门
-        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //本部门的全部下级部门
+        List<Long> deptList = companyDeptService.getCurrentDeptIdDownTreeIds(deptId);
         if (!deptList.isEmpty()){
             combinedList.addAll(deptList);
         }

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

@@ -175,7 +175,9 @@ public class QwSopLogsController extends BaseController
                     combinedList.add(deptId);
                 }
                 // 本部门的下级部门
-                List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+                //List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+                //本部门的全部下级部门
+                List<Long> deptList = companyDeptService.getCurrentDeptIdDownTreeIds(deptId);
                 if (!deptList.isEmpty()) {
                     combinedList.addAll(deptList);
                 }

+ 14 - 0
fs-company/src/main/java/com/fs/company/controller/qw/QwSopTempController.java

@@ -24,6 +24,8 @@ import com.fs.sop.params.BatchOpenOrCloseOfficialParam;
 import com.fs.sop.params.QwSopShareTempParam;
 import com.fs.sop.service.IQwSopTempService;
 import com.fs.sop.vo.UpdateRedVo;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.service.ISysConfigService;
 import com.fs.voice.utils.StringUtil;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -62,6 +64,9 @@ public class QwSopTempController extends BaseController
     @Autowired
     private CompanyUserServiceImpl companyUserService;
 
+    @Autowired
+    private ISysConfigService configService;
+
     /**
      * 查询sop模板列表
      */
@@ -375,4 +380,13 @@ public class QwSopTempController extends BaseController
     public R batchOpenOrCloseOfficial(@RequestBody BatchOpenOrCloseOfficialParam param){
         return qwSopTempService.batchOpenOrCloseOfficial(param);
     }
+
+    /**
+     * 根据后台配置的数据,动态控制前端展示的功能。
+     * */
+    @GetMapping(value = "/getConfigByKey/{configKey}")
+    public AjaxResult getConfigByKey(@PathVariable String configKey) {
+        SysConfig config = configService.selectConfigByConfigKey(configKey);
+        return AjaxResult.success(config);
+    }
 }

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

@@ -199,7 +199,9 @@ public class QwUserController extends BaseController
             combinedList.add(deptId);
         }
         //本部门的下级部门
-        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //本部门的全部下级部门
+        List<Long> deptList = companyDeptService.getCurrentDeptIdDownTreeIds(deptId);
         if (!deptList.isEmpty()){
             combinedList.addAll(deptList);
         }

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

@@ -87,7 +87,9 @@ public class QwWorkTaskNewController extends BaseController
             combinedList.add(deptId);
         }
         //本部门的下级部门
-        List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //List<Long> deptList = companyDeptService.selectCompanyDeptByParentId(deptId);
+        //本部门的全部下级部门
+        List<Long> deptList = companyDeptService.getCurrentDeptIdDownTreeIds(deptId);
         if (!deptList.isEmpty()){
             combinedList.addAll(deptList);
         }

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

@@ -133,6 +133,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                 .antMatchers("/qw/data/**").anonymous()
                 .antMatchers("/qw/user/selectCloudByCompany").anonymous()
                 .antMatchers("/live/LiveMixLiuTestOpen/**").anonymous()
+                .antMatchers("/app/common/callbackAfterSendSingleMsgCommand").anonymous()
                 // 除上面外的所有请求全部需要鉴权认证
                 .anyRequest().authenticated()
                 .and()

+ 209 - 4
fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java

@@ -1,5 +1,6 @@
 package com.fs.app.service;
 
+import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -8,11 +9,12 @@ import com.fs.common.exception.base.BaseException;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.date.DateUtil;
 import com.fs.common.utils.spring.SpringUtils;
+import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyMiniapp;
+import com.fs.company.mapper.CompanyMapper;
 import com.fs.company.service.ICompanyMiniappService;
-import com.fs.course.domain.FsCoursePlaySourceConfig;
-import com.fs.course.domain.FsCourseWatchLog;
-import com.fs.course.domain.FsUserCourseVideo;
+import com.fs.course.config.CourseConfig;
+import com.fs.course.domain.*;
 import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
 import com.fs.course.mapper.FsUserCourseVideoMapper;
 import com.fs.course.service.IFsCoursePlaySourceConfigService;
@@ -26,6 +28,8 @@ import com.fs.live.mapper.LiveWatchLogMapper;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.domain.QwUserVideo;
+import com.fs.qw.mapper.LuckyBagCollectRecordMapper;
+import com.fs.qw.mapper.LuckyBagMapper;
 import com.fs.qw.mapper.QwExternalContactMapper;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.service.IQwUserService;
@@ -35,14 +39,18 @@ import com.fs.qwApi.param.QwExternalContactHParam;
 import com.fs.sop.domain.QwSopLogs;
 import com.fs.sop.service.IQwSopLogsService;
 import com.fs.sop.service.impl.QwSopLogsServiceImpl;
+import com.fs.system.service.ISysConfigService;
 import com.fs.wxwork.dto.*;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import java.time.LocalDateTime;
+import java.time.ZoneId;
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 @Slf4j
@@ -62,6 +70,13 @@ public class IpadSendServer {
     private final IFsCoursePlaySourceConfigService playSourceConfigService;
     private final FsUserMapper fsUserMapper;
     private final FsUserCourseVideoMapper fsUserCourseVideoMapper;
+    private final ISysConfigService configService;
+    private final LuckyBagMapper luckyBagMapper;
+
+    private final CompanyMapper companyMapper;
+
+    @Autowired
+    private LuckyBagCollectRecordMapper luckyBagCollectRecordMapper;
 
 
     private static final List<String> PROJECT_NAMES = Arrays.asList("济南联志健康", "北京存在文化","宽益堂");
@@ -263,7 +278,7 @@ public class IpadSendServer {
         dto.setIsRoom(true);
        ipadSendUtils.sendTxtAtMsgVo(dto, vo.getServerId());
     }
-    
+
     public void sendVoice(BaseVo vo, QwSopCourseFinishTempSetting.Setting content) {
         if (StringUtils.isEmpty(content.getVoiceUrl()) || StringUtils.isEmpty(content.getVoiceDuration())) {
             log.debug("语音未生成无法发送,转文字发送:{}", vo);
@@ -607,6 +622,20 @@ public class IpadSendServer {
                     // 语音
                     sendWxVideo(vo, content);
                     break;
+                case "13":
+                    // 注册过的不在发送了
+                    QwExternalContact qwExternalContact =qwExternalContactMapper.selectQwExternalContactById(qwSopLogs.getExternalId());
+                    if(qwExternalContact!=null && qwExternalContact.getFsUserId()!=null){
+                        qwSopLogsService.updateQwSopLogsByWatchLogType(qwSopLogs.getId(), "已经注册过的客户不发送");
+                    }
+                    sendMiniProgram(vo, content, miniMap, qwUser.getCompanyId());
+                case "14":
+                    // 记录福袋发送记录
+                    Long businessId = addLuckyBagCollectRecord(qwUser, content,qwSopLogs);
+                    if (ObjectUtil.isEmpty(businessId)) {
+                        qwSopLogsService.updateQwSopLogsByWatchLogType(qwSopLogs.getId(), "福袋发放失败,请重新发送!");
+                    }
+                    sendMiniProgram(vo, content, miniMap, qwUser.getCompanyId());
                 case "99":
                     // 群发
                     sendTxtAtMsg(vo);
@@ -625,4 +654,180 @@ public class IpadSendServer {
     public void loginOut(QwUser user) {
         ipadSendUtils.loginOut(user.getUid(), user.getServerId());
     }
+
+    /**
+     * @Description: 生成福袋记录
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2026/2/4 11:39
+     */
+    private Long addLuckyBagCollectRecord(QwUser qwUser, QwSopCourseFinishTempSetting.Setting content, QwSopLogs qwSopLogs) {
+
+        try{
+            String json = configService.selectConfigByKey("course.config");
+            CourseConfig config = JSON.parseObject(json, CourseConfig.class);
+            Date updateTime = createUpdateTime(content, new Date(), config);
+            LuckyBag luckyBag = luckyBagMapper.selectLuckyBagById(content.getLuckyBagId());
+            String companyUserId = String.valueOf(qwUser.getCompanyUserId()).trim();
+            String companyId = String.valueOf(qwUser.getCompanyId()).trim();
+            Long businessId = addLuckyBagCollectRecord(qwUser,luckyBag,content,qwSopLogs,updateTime,companyUserId,companyId,content.getChatId());
+            return businessId;
+        }catch (Exception e){
+            log.error("福袋创建失败:qwUser={},qwSopLogs={}",qwUser,qwSopLogs);
+            return null;
+        }
+    }
+
+    /**
+     * 过期时间
+     *
+     * @param setting
+     * @param sendTime
+     * @param config
+     * @return
+     */
+    private Date createUpdateTime(QwSopCourseFinishTempSetting.Setting setting, Date sendTime, CourseConfig config) {
+
+        Integer expireDays = (setting.getExpiresDays() == null || setting.getExpiresDays() == 0)
+                ? config.getVideoLinkExpireDate()
+                : setting.getExpiresDays();
+
+//         使用 Java 8 时间 API 计算过期时间
+        LocalDateTime sendDateTime = sendTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+        LocalDateTime expireDateTime = sendDateTime.plusDays(expireDays - 1);
+        expireDateTime = expireDateTime.toLocalDate().atTime(23, 59, 59);
+        Date updateTime = Date.from(expireDateTime.atZone(ZoneId.systemDefault()).toInstant());
+
+        return updateTime;
+    }
+
+    /**
+     * 增加福袋发放记录、领取记录
+     *
+     * @param companyId
+     * @param qwUser
+     * @param luckyBag
+     * @param content
+     * @param qwSopLogs
+     * @param sendTime
+     * @param companyUserId
+     * @param chatId
+     */
+    private Long addLuckyBagCollectRecord(QwUser qwUser, LuckyBag luckyBag, QwSopCourseFinishTempSetting.Setting content,
+                                          QwSopLogs qwSopLogs,
+                                          Date sendTime,
+                                          String companyUserId,
+                                          String companyId,
+                                          String chatId) {
+        try {
+            // 参数校验
+            if (content == null || qwSopLogs == null || sendTime == null) {
+                log.error("添加福袋记录失败:必要参数为空 [content:{}, qwSopLogs:{}, sendTime:{}]",
+                        content, qwSopLogs, sendTime);
+                return null;
+            }
+
+            // 验证福袋ID
+            if (content.getLuckyBagId() == null) {
+                log.error("福袋ID为空");
+                return null;
+            }
+
+            // 查询福袋信息
+            if (luckyBag == null) {
+                log.error("未找到对应的福袋信息 [luckyBagId:{}]", content.getLuckyBagId());
+                return null;
+            }
+
+            // 检查福袋状态
+            if (luckyBag.getDataStatus() != null && luckyBag.getDataStatus().equals(0)) {
+                log.error("福袋被禁用 [luckyBagId:{}]", content.getLuckyBagId());
+                return null;
+            }
+
+            // 查询公司信息
+            Company company = (Company)redisCache.getCacheObject("companyId:"+companyId);
+            if (company == null) {
+                company = companyMapper.selectCompanyById(Long.valueOf(companyId));
+                redisCache.setCacheObject("companyId:"+companyId, company, 1 , TimeUnit.DAYS);
+                log.error("未找到对应的公司信息 [companyId:{}]", companyId);
+            }
+
+            // 构建福袋记录
+            LuckyBagCollectRecord luckyBagCollectRecord = buildLuckyBagRecord(qwUser,content, qwSopLogs, sendTime,
+                    companyUserId, companyId, chatId, company, luckyBag);
+            luckyBagCollectRecord.setSendTime(new Date());
+            luckyBagCollectRecord.setCollectType("0");
+            // 插入记录并返回ID
+            int result = luckyBagCollectRecordMapper.insertLuckyBagCollectRecord(luckyBagCollectRecord);
+            if (result <= 0) {
+                log.error("福袋记录插入失败 [luckyBagId:{}]", content.getLuckyBagId());
+                return null;
+            }
+
+            // 返回新增记录的ID
+            Long recordId = luckyBagCollectRecord.getId();
+            if (recordId == null) {
+                log.error("福袋记录插入成功但未返回ID [luckyBagId:{}]", content.getLuckyBagId());
+                return null;
+            }
+
+            log.info("福袋记录添加成功 [recordId:{}, luckyBagId:{}]", recordId, content.getLuckyBagId());
+            return recordId;
+
+        } catch (NumberFormatException e) {
+            log.error("ID转换失败 [companyId:{}, companyUserId:{}]", companyId, companyUserId, e);
+            return null;
+        } catch (Exception e) {
+            log.error("ID:" + (content != null ? content.getLuckyBagId() : "unknown") + "-添加福袋记录失败", e);
+            return null;
+        }
+    }
+
+
+    /**
+     * 构建福袋记录对象
+     */
+    private LuckyBagCollectRecord buildLuckyBagRecord(QwUser qwUser,QwSopCourseFinishTempSetting.Setting content,
+                                                      QwSopLogs qwSopLogs,
+                                                      Date sendTime,
+                                                      String companyUserId,
+                                                      String companyId,
+                                                      String chatId,
+                                                      Company company,
+                                                      LuckyBag luckyBag) {
+        LuckyBagCollectRecord record = new LuckyBagCollectRecord();
+        record.setQwUserId(qwUser.getQwUserId());
+        record.setQwUserName(qwUser.getQwUserName());
+        record.setLuckyBagId(content.getLuckyBagId());
+        record.setExpiryTime(sendTime);
+        record.setCollectType("3");
+        record.setCompanyId(Long.valueOf(companyId));
+        record.setUserId(qwSopLogs.getFsUserId());
+        if (ObjectUtil.isNotEmpty(qwSopLogs.getFsUserId())){
+            FsUser fsUser = fsUserMapper.selectFsUserByUserId(qwSopLogs.getFsUserId());
+            record.setUserName(ObjectUtil.isNotEmpty(fsUser)?fsUser.getNickName():null);
+        }
+        record.setCompanyName(company.getCompanyName());
+        record.setCompanyUserId(Long.valueOf(companyUserId));
+        record.setSendLink(content.getMiniprogramPage());
+
+        // 设置奖励类型和聊天信息
+        if (StringUtils.isNotEmpty(chatId)) {
+            record.setRewardType(1L);
+            record.setChatId(chatId);
+            record.setExternalUserName(qwSopLogs.getExternalUserName());
+        } else {
+            record.setRewardType(2L);
+        }
+
+        // 设置币种金额
+        if (luckyBag.getRewardType() != null && luckyBag.getRewardType().equals("1")) {
+            record.setCoinAmount(luckyBag.getAmount());
+        }
+
+        return record;
+    }
+
 }

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

@@ -11,8 +11,10 @@ import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.StringUtils;
 import com.fs.company.service.ICompanyService;
 import com.fs.company.vo.RedPacketMoneyVO;
+import com.fs.course.config.CourseConfig;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
 import com.fs.course.mapper.FsCourseWatchLogMapper;
+import com.fs.course.param.FsCourseLinkMiniParam;
 import com.fs.course.param.newfs.FsUserCourseAddCompanyUserParam;
 import com.fs.course.service.*;
 import com.fs.course.vo.FsUserCourseVideoQVO;
@@ -34,6 +36,8 @@ import com.fs.sop.mapper.SopUserLogsMapper;
 import com.fs.sop.service.*;
 import com.fs.sop.vo.QwSopLogsDoSendListTVO;
 import com.fs.store.service.IFsUserCourseCountService;
+import com.fs.system.service.ISysConfigService;
+import com.fs.voice.utils.StringUtil;
 import com.fs.wxwork.dto.WxWorkGetQrCodeDTO;
 import com.fs.wxwork.service.WxWorkService;
 import io.swagger.annotations.Api;
@@ -154,6 +158,21 @@ public class CommonController {
     @Autowired
     WxWorkService wxWorkService;
 
+    @Autowired
+    private ISysConfigService configService;
+
+    @GetMapping("/roomLinkAllow")
+    public R roomLinkAllow() {
+
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSON.parseObject(json, CourseConfig.class);
+
+        if (config != null && config.getRoomLinkAllow() != null && config.getRoomLinkAllow()) {
+            return R.error("创建群链接已禁止");
+        }
+        return R.ok();
+    }
+
     /**
      *
      */

File diff suppressed because it is too large
+ 472 - 100
fs-qw-task/src/main/java/com/fs/app/taskService/impl/SopLogsTaskServiceImpl.java


+ 15 - 0
fs-qwhook-sop/src/main/java/com/fs/app/controller/ApisFsUserCourseVideoController.java

@@ -1,6 +1,7 @@
 package com.fs.app.controller;
 
 import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.core.controller.BaseController;
@@ -22,6 +23,7 @@ import com.fs.course.vo.FsCourseVideoListBySidebarVO;
 import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.utils.ConfigUtil;
+import com.fs.hisStore.enums.SysConfigEnum;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.service.IQwExternalContactService;
 import com.fs.system.service.ISysConfigService;
@@ -61,6 +63,8 @@ public class ApisFsUserCourseVideoController extends BaseController {
 
     @Autowired
     private ISysConfigService configService;
+    @Autowired
+    private ConfigUtil configUtil;
 
 
     @ApiOperation("课程视频详情")
@@ -211,6 +215,17 @@ public class ApisFsUserCourseVideoController extends BaseController {
             return R.error("企业id不能为空");
         }
 
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSON.parseObject(json, CourseConfig.class);
+
+        if (config != null && config.getRoomLinkAllow() != null && config.getRoomLinkAllow()) {
+            return R.error("创建群链接已禁止");
+        }
+//        JSONObject jsonObject = configUtil.generateConfigByKey(SysConfigEnum.COURSE_CONFIG.getKey());
+//        if (jsonObject!= null && jsonObject.getString("roomLinkAllow")!= null && Boolean.parseBoolean(jsonObject.getString("roomLinkAllow"))){
+//            return R.error("创建群链接已禁止");
+//        }
+
 
         return fsUserCourseVideoService.createRoomMiniLink(param);
     }

+ 22 - 0
fs-qwhook-sop/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -1,10 +1,12 @@
 package com.fs.app.controller;
 
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.fs.common.annotation.RepeatSubmit;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.utils.CloudHostUtils;
+import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsUserCourse;
 import com.fs.course.param.FsCourseLinkCreateParam;
 import com.fs.course.param.FsCourseLinkMiniParam;
@@ -21,9 +23,12 @@ import com.fs.course.vo.newfs.FsUserCourseListVO;
 import com.fs.course.vo.newfs.FsUserCourseVideoDetailsVO;
 import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
 import com.fs.course.vo.newfs.FsUserVideoListVO;
+import com.fs.his.utils.ConfigUtil;
+import com.fs.hisStore.enums.SysConfigEnum;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.service.IQwExternalContactService;
 import com.fs.qw.service.IQwUserService;
+import com.fs.system.service.ISysConfigService;
 import com.fs.voice.utils.StringUtil;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
@@ -53,6 +58,11 @@ public class FsUserCourseVideoController {
 
     @Autowired
     private IQwExternalContactService qwExternalContactService;
+    @Autowired
+    private ConfigUtil configUtil;
+
+    @Autowired
+    private ISysConfigService configService;
 
 
     @ApiOperation("课程视频详情")
@@ -119,6 +129,18 @@ public class FsUserCourseVideoController {
             return R.error("企业id不能为空");
         }
 
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig config = JSON.parseObject(json, CourseConfig.class);
+
+        if (config != null && config.getRoomLinkAllow() != null && config.getRoomLinkAllow()) {
+            return R.error("创建群链接已禁止");
+        }
+
+//        JSONObject jsonObject = configUtil.generateConfigByKey(SysConfigEnum.COURSE_CONFIG.getKey());
+//        if (jsonObject!= null && jsonObject.getString("roomLinkAllow")!= null && Boolean.parseBoolean(jsonObject.getString("roomLinkAllow"))){
+//            return R.error("创建群链接已禁止");
+//        }
+
         return fsUserCourseVideoService.createRoomMiniLink(param);
     }
 

+ 88 - 0
fs-qwhook/src/main/java/com/fs/app/controller/ApisCommonController.java

@@ -1,17 +1,23 @@
 package com.fs.app.controller;
 
 
+import cn.hutool.core.collection.CollectionUtil;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.common.utils.sign.Md5Utils;
 import com.fs.course.mapper.FsCourseWatchLogMapper;
 import com.fs.course.mapper.FsUserCourseVideoMapper;
 import com.fs.course.service.IFsCourseLinkService;
+import com.fs.fastGpt.domain.FastGptPushTokenTotal;
 import com.fs.fastGpt.mapper.FastgptChatVoiceHomoMapper;
 import com.fs.his.domain.FsAppVersion;
+import com.fs.his.domain.FsUser;
+import com.fs.his.mapper.FsUserMapper;
 import com.fs.his.service.IFsAppVersionService;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwCompanyMapper;
 import com.fs.qw.mapper.QwExternalContactCrmMapper;
+import com.fs.qw.mapper.QwRestrictionPushRecordMapper;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.param.QwConfigSignatureParam;
 import com.fs.qw.service.IQwJsApiService;
@@ -26,10 +32,15 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.error.WxErrorException;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import java.io.IOException;
+import java.util.List;
+
+import static com.fs.his.utils.PhoneUtil.encryptPhone;
+import static com.fs.his.utils.PhoneUtil.encryptPhoneOldKey;
 
 
 @Api("公共接口")
@@ -77,6 +88,83 @@ public class ApisCommonController {
     @Autowired
     private IFsCourseLinkService iFsCourseLinkService;
 
+    @Autowired
+    private QwRestrictionPushRecordMapper qwRestrictionPushRecordMapper;
+
+    @Autowired
+    private FsUserMapper userMapper;
+
+    @GetMapping("/findUsersByPhone")
+    public void findUsersByPhone(String phone) {
+
+        // 先根据加密手机号查询用户
+        String jiami = (encryptPhone(phone));
+
+        FsUser user = null;
+        List<FsUser> usersByPhone = userMapper.selectFsUsersByPhoneLimitOne(jiami);
+        if (CollectionUtil.isEmpty(usersByPhone)) {
+            usersByPhone = userMapper.selectFsUsersByPhoneLimitOne(encryptPhoneOldKey(phone));
+        }
+        // 如果没有找到用户,再根据手机号查询
+        if (CollectionUtil.isEmpty(usersByPhone)) {
+            usersByPhone = userMapper.selectFsUsersByPhoneLimitOne(phone);
+
+        }
+
+        if (CollectionUtil.isEmpty(usersByPhone)){
+            log.error("1111111111111111");
+        }
+        //当前手机号只绑定了单个微信,直接登录
+        if (usersByPhone.size()==1){
+            user = usersByPhone.get(0);
+            // 校验用户是否存在及账号状态
+            if (user == null) {
+                log.error("222222222222");
+            } else if (user.getStatus() == 0) {
+                log.error("33333333333");
+            } else if (StringUtils.isEmpty(user.getPassword())) {
+                log.error("4444444");
+            }
+
+        }
+        System.out.println(usersByPhone);
+    }
+
+    @GetMapping("/sopPushTokenTotal")
+    public void sopPushTokenTotal(String dateTime) {
+
+        // 获取日期字符串(今天或昨天)
+//        String dateTime;
+//            dateTime = DateUtils.getDate();
+        log.info("开始执行sop任务token消耗统计");
+        try {
+            List<FastGptPushTokenTotal> fastGptPushTotalList = qwRestrictionPushRecordMapper.selectFastgptPushTokenTotal(dateTime);
+            if (fastGptPushTotalList != null && !fastGptPushTotalList.isEmpty()) {
+                for (FastGptPushTokenTotal fastGptPushTotal : fastGptPushTotalList) {
+                    // 获取统计数据
+                    Integer type = fastGptPushTotal.getType();
+                    Long count = 0L;
+                    if(type == 7){
+                        count = fastGptPushTotal.getCount() * 450;
+                    }else{
+                        count = fastGptPushTotal.getCount() * 150;
+                    }
+                    fastGptPushTotal.setCount(count);
+                    FastGptPushTokenTotal pushTotal = qwRestrictionPushRecordMapper.selectFastGptPushTokenTotalByInfo(fastGptPushTotal);
+                    if(pushTotal == null){
+                        qwRestrictionPushRecordMapper.insertPushTokenTotal(fastGptPushTotal);
+                    }else{
+                        fastGptPushTotal.setId(pushTotal.getId());
+                        qwRestrictionPushRecordMapper.updatePushTokenTotal(fastGptPushTotal);
+                    }
+                }
+            }
+            log.info("结束执行sop任务token消耗统计");
+        } catch (Exception e) {
+            log.error("执行sop任务token消耗统计异常", e);
+        }
+    }
+
     /**
      * 获取跳转微信小程序的链接地址
      */

+ 50 - 0
fs-service/src/main/java/com/fs/aiSoundReplication/mapper/VoiceCloneMapper.java

@@ -0,0 +1,50 @@
+package com.fs.aiSoundReplication.mapper;
+
+
+import com.fs.aiSoundReplication.param.TtsChargeParam;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+public interface VoiceCloneMapper {
+    // 插入
+    @Insert("INSERT INTO vc_tts_charge_count (company_id,company_user_id,qw_user_id, text, text_length, voice_url, create_time, version_id, duration,fastgpt_role_id) VALUES (#{param.companyId},#{param.companyUserId},#{param.qwUserId} ,#{param.text}, #{param.textLength}, #{param.voiceUrl}, #{param.createTime}, #{param.versionId}, #{param.duration},#{param.fastgptRoleId})")
+    int insert(@Param("param") TtsChargeParam param);
+
+    // 根据ID删除
+    @Delete("DELETE FROM vc_tts_charge_count WHERE id = #{id}")
+    int deleteById(@Param("id") Long id);
+
+    // 更新
+    @Update("UPDATE vc_tts_charge_count SET company_user_id=#{companyUserId}, text=#{text}, text_length=#{textLength}, voice_url=#{voiceUrl}, create_time=#{createTime}, version_id=#{versionId}, unit_price=#{unitPrice}, total_price=#{totalPrice}, duration=#{duration} WHERE id = #{id}")
+    int updateById(@Param("param") TtsChargeParam param);
+
+    // 根据ID查询
+    @Select("SELECT * FROM vc_tts_charge_count WHERE id = #{id}")
+    TtsChargeParam selectById(@Param("id") Long id);
+
+    // 查询所有
+    @Select("SELECT * FROM vc_tts_charge_count")
+    List<TtsChargeParam> selectAll();
+
+    // 条件查询
+    @Select("<script>" +
+            "SELECT * FROM vc_tts_charge_count WHERE 1=1" +
+            "<if test='companyUserId != null'> AND company_user_id = #{companyUserId}</if>" +
+            "<if test='versionId != null'> AND version_id = #{versionId}</if>" +
+            "</script>")
+    List<TtsChargeParam> selectByCondition(@Param("companyUserId") Long companyUserId, @Param("versionId") Integer versionId);
+
+    @Select("SELECT \n" +
+            "company_id as companyId,\n" +
+            "company_user_id as companyUserId," +
+            "qw_user_id as qwUserId," +
+            "fastgpt_role_id as fastgptRoleId," +
+            "create_time as createTime," +
+            "SUM(text_length) AS total_text_length\n" +
+            "FROM vc_tts_charge_count\n" +
+            "WHERE create_time  >= DATE_SUB(CURDATE(), INTERVAL 1 DAY)\n" +
+            "  AND create_time < CURDATE()\n" +
+            "GROUP BY company_id,company_user_id,qw_user_id,fastgpt_role_id ")
+    List<TtsChargeParam> countDailyTtsWords();
+}

+ 83 - 0
fs-service/src/main/java/com/fs/aiSoundReplication/param/TtsChargeParam.java

@@ -0,0 +1,83 @@
+package com.fs.aiSoundReplication.param;
+
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 语音合成计费参数
+ */
+@Data
+@Accessors(chain = true)
+public class TtsChargeParam {
+    /**
+     * 主键
+     */
+    private Long id;
+
+    /**
+     * 公司id
+     */
+    private Long companyId;
+    /**
+     * 销售用户id
+     */
+    private Long companyUserId;
+
+    /**
+     * 企微用户id
+     */
+    private Long qwUserId;
+
+    /**
+     * fastgpt表的roleid
+     */
+    private Long fastgptRoleId;
+    /**
+     * tts的文本
+     */
+    private String text;
+
+    /**
+     * 文本字数
+     */
+    private Integer textLength;
+
+    /**
+     * tts的音频url
+     */
+    private String voiceUrl;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 豆包版本
+     */
+    private Integer versionId;
+
+    /**
+     * 单字价格
+     */
+    private BigDecimal unitPrice;
+
+    /**
+     * 总价
+     */
+    private BigDecimal totalPrice;
+
+    /**
+     * 音频时长
+     */
+    private Integer duration;
+
+    /**
+     * 总字数
+     */
+    private Long totalTextLength;
+}

+ 7 - 1
fs-service/src/main/java/com/fs/aiSoundReplication/service/TtsService.java

@@ -2,7 +2,9 @@ package com.fs.aiSoundReplication.service;
 
 import com.fs.aiSoundReplication.param.TtsRequest;
 import com.fs.aiSoundReplication.param.TtsResponse;
+import com.fs.company.param.VcCompanyUser;
 import com.fs.fastgptApi.vo.AudioVO;
+import com.fs.qw.domain.QwUser;
 import org.springframework.core.io.Resource;
 
 import java.io.File;
@@ -50,8 +52,12 @@ public interface TtsService {
     /**
      * 批量文本转语音
      * @param texts 文本列表
-     * @param voiceType 音色ID
+//     * @param voiceType 音色ID
      * @return 音频文件列表
      */
 //    java.util.List<File> batchTextToSpeech(java.util.List<String> texts, String voiceType);
+
+    void ttsChargeByCount(VcCompanyUser vcCompanyUser, AudioVO audioVO, QwUser user);
+
+    void countDailyTtsWords();
 }

+ 66 - 4
fs-service/src/main/java/com/fs/aiSoundReplication/service/impl/TtsServiceImpl.java

@@ -1,40 +1,52 @@
 package com.fs.aiSoundReplication.service.impl;
 
 
+import cn.hutool.core.bean.BeanUtil;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fs.aiSoundReplication.config.TtsConfig;
 import com.fs.aiSoundReplication.config.VoiceCloneConfig;
 import com.fs.aiSoundReplication.exception.VoiceCloneException;
+import com.fs.aiSoundReplication.mapper.VoiceCloneMapper;
+import com.fs.aiSoundReplication.param.TtsChargeParam;
 import com.fs.aiSoundReplication.param.TtsRequest;
 import com.fs.aiSoundReplication.param.TtsResponse;
 import com.fs.aiSoundReplication.service.TtsService;
-import com.fs.fastgptApi.util.AudioUtils;
+import com.fs.company.param.VcCompanyUser;
+import com.fs.fastGpt.domain.FastgptEventLogTotal;
+import com.fs.fastGpt.mapper.FastGptRoleMapper;
+import com.fs.fastGpt.service.impl.FastgptEventLogTotalServiceImpl;
 import com.fs.fastgptApi.vo.AudioVO;
+import com.fs.qw.domain.QwUser;
+import com.fs.qw.mapper.QwUserMapper;
 import com.fs.system.oss.CloudStorageService;
 import com.fs.system.oss.OSSFactory;
 import lombok.extern.slf4j.Slf4j;
 import okhttp3.*;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.math.BigDecimal;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import java.util.Base64;
 
 import static com.fs.fastgptApi.util.AudioUtils.getDurations;
 import static com.fs.fastgptApi.util.AudioUtils.transferAudioSilk;
 
-@Service
+@Service("ttsService")
 @Slf4j
-public class TtsServiceImpl implements TtsService {
+public class TtsServiceImpl implements TtsService  {
 
     @Autowired
     private TtsConfig ttsConfig;
@@ -52,6 +64,12 @@ public class TtsServiceImpl implements TtsService {
 
     private static final String AUTHORIZATION_HEADER = "Authorization";
     private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
+    @Autowired
+    private VoiceCloneMapper voiceCloneMapper;
+    @Autowired
+    private FastGptRoleMapper fastGptRoleMapper;
+    @Autowired
+    private FastgptEventLogTotalServiceImpl fastgptEventLogTotalServiceImpl;
 
     @Override
     public AudioVO textToSpeech(TtsRequest request) {
@@ -95,6 +113,7 @@ public class TtsServiceImpl implements TtsService {
                 audioVO.setDuration(durations);
                 audioVO.setUrl(silkUrl);
                 audioVO.setWavUrl(wavUrl);
+                audioVO.setVoiceTxt(request.getText());
                 log.info("音频文件上传OSS成功: {}", audioVO.getUrl());
                 return audioVO;
             } finally {
@@ -111,6 +130,49 @@ public class TtsServiceImpl implements TtsService {
         }
     }
 
+    @Override
+    public void ttsChargeByCount(VcCompanyUser vcCompanyUser, AudioVO audioVO, QwUser user) {
+        try {
+            //        BigDecimal ttsCharge = getTtsCharge(texts,unitPrice); // 算钱 暂时没有确认价格,只是统计字数
+            TtsChargeParam ttsChargeParam = new TtsChargeParam();
+            ttsChargeParam.setText(audioVO.getVoiceTxt()).setTextLength(audioVO.getVoiceTxt().length()).setCreateTime(LocalDateTime.now())
+//                .setTotalPrice(ttsCharge).setUnitPrice(unitPrice)
+                    .setCompanyUserId(Long.valueOf(vcCompanyUser.getId())).setVoiceUrl(audioVO.getUrl()).setDuration(audioVO.getDuration())
+                    .setVersionId(vcCompanyUser.getVersionId());
+            if (user.getCompanyId()!=null){
+                ttsChargeParam.setCompanyId(user.getCompanyId()).setQwUserId(user.getId());
+                if (user.getFastGptRoleId()!=null){
+                    ttsChargeParam.setFastgptRoleId(user.getFastGptRoleId());
+                }
+            }
+            voiceCloneMapper.insert(ttsChargeParam);
+        }catch (Exception e){
+            log.error("豆包声音复刻计数异常",e);
+        }
+
+
+    }
+
+    @Override
+    public void countDailyTtsWords() {
+        List<TtsChargeParam> ttsChargeParams = voiceCloneMapper.countDailyTtsWords();
+        if (ttsChargeParams.isEmpty()){
+            log.info("每日统计声音复刻昨日无数据");
+            return;
+        }
+        log.info("每日统计声音复刻:"+ttsChargeParams);
+
+        ArrayList<FastgptEventLogTotal> Totals = new ArrayList<>();
+        ttsChargeParams.forEach(o->{
+            FastgptEventLogTotal bean = BeanUtil.toBean(o, FastgptEventLogTotal.class);
+            bean.setRoleId(o.getFastgptRoleId());
+            bean.setType(14);
+            bean.setCount(o.getTotalTextLength() * 450);
+            bean.setStatTime(o.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+            Totals.add(bean);
+        });
+        fastgptEventLogTotalServiceImpl.getBaseMapper().insertFastgptEventLogTotalBatch(Totals);
+    }
 //    @Override
 //    public String textToSpeech(String text, String voiceType) {
 //        // 创建简化版请求

+ 1 - 1
fs-service/src/main/java/com/fs/aiTongueApi/config/AiTongueConfig.java

@@ -4,7 +4,7 @@ public interface AiTongueConfig {
     String getFaceHistoryByIDUrl="https://api.aikanshe.com/agency/getHistoryByID";
     String quanxiUrl="https://api.aikanshe.com/agency/quanxi";
     String checkTongue="https://api.aikanshe.com/agency/checkTongue";
-    String appKey="i5h5u6g59dw9x0o6yymd3tf5ea6gcdqi";
+//    String appKey="i5h5u6g59dw9x0o6yymd3tf5ea6gcdqi";
 
     String newCheckTongue="http://132.232.234.246:5056/api/detect";
 }

+ 15 - 4
fs-service/src/main/java/com/fs/aiTongueApi/service/impl/AiTongueServiceImpl.java

@@ -1,6 +1,7 @@
 package com.fs.aiTongueApi.service.impl;
 
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.TypeReference;
 import com.fs.aiTongueApi.config.AiTongueConfig;
 import com.fs.aiTongueApi.domain.AITongueResult;
@@ -12,6 +13,8 @@ import com.fs.aiTongueApi.service.AiTongueService;
 import com.fs.common.utils.uuid.UUID;
 import com.fs.his.domain.FsHealthTongue;
 import com.fs.his.service.IFsHealthTongueService;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.mapper.SysConfigMapper;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.hc.core5.net.URIBuilder;
 import org.apache.http.HttpEntity;
@@ -43,10 +46,12 @@ public class AiTongueServiceImpl implements AiTongueService {
 
     @Autowired
     private IFsHealthTongueService tongueService;
+    @Autowired
+    private SysConfigMapper sysConfigMapper;
 
     @Override
     public AITongueResult<TongueData> getHistoryTongue(QueryAiTongue queryAiTongue) {
-        queryAiTongue.setAppkey(AiTongueConfig.appKey);
+        queryAiTongue.setAppkey(getAppKey());
         String result = sendPost(AiTongueConfig.getFaceHistoryByIDUrl, queryAiTongue);
         System.out.println(result);
         AITongueResult<TongueData> aiTongueResult = JSON.parseObject(result, new TypeReference<AITongueResult<TongueData>>(){});
@@ -65,7 +70,7 @@ public class AiTongueServiceImpl implements AiTongueService {
             // 添加文件或表单参数
             builder.addBinaryBody("file", inputStream, ContentType.DEFAULT_BINARY, "图片.jpg");
 
-            builder.addTextBody("appkey", AiTongueConfig.appKey);
+            builder.addTextBody("appkey", getAppKey());
             HttpEntity multipart = builder.build();
             httpPost.setEntity(multipart);
             // 执行请求
@@ -81,6 +86,12 @@ public class AiTongueServiceImpl implements AiTongueService {
         return aiTongueResult;
     }
 
+    private String getAppKey() {
+        SysConfig config = sysConfigMapper.selectConfigByConfigKey("his.config");
+        JSONObject json = JSON.parseObject(config.getConfigValue());
+        return json.getString("tongueAppKey");
+    }
+
     @Override
     public AITongueResult<TongueData> quanXiTongue(QueryQuanXi queryQuanXi) {
         String s="";
@@ -95,7 +106,7 @@ public class AiTongueServiceImpl implements AiTongueService {
 
             builder.addTextBody("age", queryQuanXi.getAge(), ContentType.create("text/plain", Charset.forName("UTF-8")));
             builder.addTextBody("male", queryQuanXi.getMale(), ContentType.create("text/plain", Charset.forName("UTF-8")));
-            builder.addTextBody("appkey", AiTongueConfig.appKey);
+            builder.addTextBody("appkey", getAppKey());
             if (queryQuanXi.getIsYuejin()!=null){
                 builder.addTextBody("isYuejin", queryQuanXi.getIsYuejin(), ContentType.create("text/plain", Charset.forName("UTF-8")));
             }
@@ -112,7 +123,7 @@ public class AiTongueServiceImpl implements AiTongueService {
             // 执行请求
             HttpResponse response = httpClient.execute(httpPost);
             String responseBody = EntityUtils.toString(response.getEntity());
-            System.out.println(responseBody);
+            log.info(responseBody);
             s=responseBody;
         } catch (Exception e) {
             e.printStackTrace();

+ 12 - 0
fs-service/src/main/java/com/fs/company/param/VcCompanyUser.java

@@ -9,6 +9,7 @@ import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 
 import java.io.Serializable;
+import java.math.BigDecimal;
 
 /**
  * 公司用户音色表实体类
@@ -66,6 +67,17 @@ public class VcCompanyUser implements Serializable {
     @TableField("latest_text_to_speech_url")
     private String latestTextToSpeechUrl;
 
+    /**
+     * 豆包版本
+     */
+    @TableField("version_id")
+    private Integer versionId;
+
+    /**
+     * 单价
+     */
+    @TableField("unit_price")
+    private BigDecimal unitPrice;
     // 下面是可选添加的方法和字段
 
     /**

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

@@ -91,4 +91,6 @@ public interface ICompanyDeptService
      * @return 部门
      */
     CompanyDept getDefaultCompanyDeptByCompanyId(Long companyId);
+
+    List<Long> getCurrentDeptIdDownTreeIds(Long deptId);
 }

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

@@ -249,6 +249,12 @@ public class CompanyDeptServiceImpl implements ICompanyDeptService
     public CompanyDept getDefaultCompanyDeptByCompanyId(Long companyId) {
         return companyDeptMapper.getTopCompanyDeptByCompanyId(companyId);
     }
+
+    @Override
+    public List<Long> getCurrentDeptIdDownTreeIds(Long deptId) {
+        return companyDeptMapper.getCurrentDeptIdDownTreeIds(deptId);
+    }
+
     /**
      * 递归列表
      */

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

@@ -97,6 +97,9 @@ public class CourseConfig implements Serializable {
     // 控制休息提示是否打开 默认打开 0-关闭 1-打开
     private Integer isOpenRestReminder;
 
+    // 是否发课不发群  false否,true 是
+    private Boolean roomLinkAllow;
+
 
     @Data
     public static class DisabledTimeVo{

+ 29 - 0
fs-service/src/main/java/com/fs/course/domain/FsDepVideoShow.java

@@ -0,0 +1,29 @@
+package com.fs.course.domain;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 部门视频疗包展示关联对象 fs_dep_video_show
+ *
+ * @author fs
+ * @date 2025-10-11
+ */
+@Data
+@EqualsAndHashCode()
+public class FsDepVideoShow {
+
+    /** 视频id */
+    private Long videoId;
+
+    /** 是否展示疗包 0展示 1不展示 */
+    @Excel(name = "是否展示疗包 0展示 1不展示")
+    private String isShow;
+
+    /** 部门id */
+    @Excel(name = "部门id")
+    private Long depId;
+
+
+}

+ 5 - 0
fs-service/src/main/java/com/fs/course/domain/FsUserCourseVideo.java

@@ -1,5 +1,6 @@
 package com.fs.course.domain;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableLogic;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fs.common.annotation.Excel;
@@ -128,4 +129,8 @@ public class FsUserCourseVideo extends BaseEntity
     private String jobId;
 
     private String vid;
+
+    @TableField(exist = false)
+    private Integer showProduct; //1不展示疗法,0展示疗法
+
 }

+ 9 - 2
fs-service/src/main/java/com/fs/course/mapper/FsCourseRedPacketLogMapper.java

@@ -114,13 +114,15 @@ public interface FsCourseRedPacketLogMapper
     List<FsCourseRedPacketLogListPVO> selectRedPacketLogListVO(@Param("maps") FsCourseRedPacketLogParam param);
 
     @Select({"<script> " +
-            "select l.*,v.title,u.nick_name as fsNickName,u.avatar as fsAvatar,u.phone,cu.nick_name company_user_name,c.company_name,qu.qw_user_name,fuc.course_name,u.phone as phoneNumber,cu.dept_id   from fs_course_red_packet_log l  \n" +
+            "select l.*,v.title,u.nick_name as fsNickName,u.avatar as fsAvatar,u.phone,cu.nick_name company_user_name,c.company_name,qu.qw_user_name,fuc.course_name,u.phone as phoneNumber,cu.dept_id   " +
+            "from fs_course_red_packet_log l  \n" +
             "left join fs_user_course_video v on v.video_id = l.video_id \n" +
             "left join fs_user u on u.user_id = l.user_id \n" +
             "left join fs_user_course fuc on fuc.course_id = l.course_id \n" +
             "left join company_user cu on cu.user_id=l.company_user_id \n" +
             "left join company c on c.company_id=cu.company_id \n" +
             "LEFT JOIN qw_user qu on qu.id= l.qw_user_id  \n" +
+            "left join fs_course_watch_log fcwl on fcwl.log_id = l.watch_log_id \n" +
             "where 1=1   " +
             "<if test = ' maps.userId !=null '> and l.user_id = #{maps.userId} </if>" +
             "<if test = ' maps.logId !=null '> and l.log_id = #{maps.logId} </if>" +
@@ -131,7 +133,6 @@ public interface FsCourseRedPacketLogMapper
             "<if test = ' maps.nickName !=null '> and u.nick_name  like concat('%', #{maps.nickName}, '%') </if>" +
             "<if test = ' maps.courseId !=null '> and l.course_id = #{maps.courseId} </if>" +
             "<if test = ' maps.videoId !=null '> and l.video_id = #{maps.videoId} </if>" +
-            "<if test = ' maps.periodId !=null '> and l.period_id = #{maps.periodId} </if>" +
             "<if test = ' maps.status !=null '> and l.status = #{maps.status} </if>" +
             "<if test = \"maps.phone !=null and maps.phone != '' \"> and u.phone = #{maps.phone} </if>" +
             "<if test = ' maps.qwUserId !=null '> and l.qw_user_id = #{maps.qwUserId} </if>" +
@@ -143,6 +144,12 @@ public interface FsCourseRedPacketLogMapper
             "                    ${item}\n" +
             "                </foreach>\n" +
             "</if>" +
+            "<if test = 'maps.trainingCampId != null and maps.periodId !=null'>\n" +
+            "and fcwl.period_id = #{maps.periodId}\n " +
+            "</if>" +
+            "<if test = 'maps.sopId != null and maps.sopDate != null' >\n" +
+            "and fcwl.sop_id = #{maps.sopId} and fcwl.camp_period_time = #{maps.sopDate}\n"+
+            "</if>"+
             " order by l.log_id desc  "+
             "</script>"})
     List<FsCourseRedPacketLogListPVO> selectFsCourseRedPacketLogListVO(@Param("maps")FsCourseRedPacketLogParam fsCourseRedPacketLog);

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

@@ -256,7 +256,7 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
 //            " LEFT JOIN fs_course_red_packet_log fcr on o.user_id = fcr.user_id and fcr.video_id = o.video_id" + //会有笛卡尔积问题
             "</if>\n" +
             "LEFT JOIN fs_user_course_video v on v.video_id=o.video_id \n" +
-            "LEFT JOIN fs_user_course uc on uc.course_id=v.course_id\n" +
+            "LEFT JOIN fs_user_course uc on uc.course_id=o.course_id\n" +
             "<if test= 'sendType == 1 '> " +
             " LEFT JOIN company_user cu on cu.user_id=o.company_user_id\n" +
             "</if>\n" +

+ 43 - 0
fs-service/src/main/java/com/fs/course/mapper/FsDepVideoShowMapper.java

@@ -0,0 +1,43 @@
+package com.fs.course.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.course.domain.FsDepVideoShow;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+
+/**
+ * 部门视频疗包展示关联Mapper接口
+ * 
+ * @author fs
+ * @date 2025-10-11
+ */
+public interface FsDepVideoShowMapper extends BaseMapper<FsDepVideoShow>{
+    /**
+     * 部门视频疗包展示关联
+     * 
+     * @param videoId, depId  部门视频疗包展示关联主键
+     * @return 部门视频疗包展示关联
+     */
+    @Select("<script>" +
+            "SELECT is_show FROM fs_dep_video_show WHERE video_id = #{videoId}" +
+            "<if test='depId != null'> AND dep_id = #{depId}</if>" +
+            "</script>")
+    String selectFsDepVideoShowByVideoId(@Param("videoId")Long videoId,@Param("depId") Long depId);
+
+    @Select("SELECT is_show FROM fs_dep_video_show WHERE video_id = #{videoId}")
+    String searchAllByVideoIdString(Long videoId);
+    /**
+     * 增加部门视频疗包展示关联
+     *
+     * @param fsDepVideoShow 部门视频疗包展示关联主键
+     * @return 部门视频疗包展示关联
+     */
+    @Insert("INSERT INTO fs_dep_video_show(video_id, is_show, dep_id) VALUES(#{videoId}, #{isShow}, #{depId})")
+    int insertFsDepVideoShowByVideoId(FsDepVideoShow fsDepVideoShow);
+
+    @Update("UPDATE fs_dep_video_show SET is_show = #{isShow} WHERE video_id = #{videoId} AND dep_id = #{depId}")
+    int updateByVideoId(FsDepVideoShow fsDepVideoShow);
+
+}

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

@@ -88,7 +88,7 @@ public interface FsUserCourseVideoMapper extends BaseMapper<FsUserCourseVideo> {
             "select v.*  from fs_user_course_video v  " +
             "where v.is_del = 0 and  v.course_id = #{maps.courseId}   " +
             "<if test = ' maps.title!=null and maps.title != \"\" '> " +
-            "and v.title = #{maps.title} " +
+            "and v.title like concat('%',#{maps.title},'%') " +
             "</if>" +
             "<if test = ' maps.userId!=null and maps.userId != \"\" '> " +
             "and v.user_id = #{maps.userId} " +

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

@@ -22,6 +22,9 @@ public interface FsVideoResourceMapper extends BaseMapper<FsVideoResource> {
     @Select("select * from fs_video_resource where line1 is not null and is_transcode = 0 and is_del = 0")
     List<FsVideoResource> selectVideoNotTranscode();
 
+    @Select("select * from fs_video_resource where video_url = #{videoUrl} and is_transcode = 0 and is_del = 0")
+    FsVideoResource selectVideoByVideoUrl(String videoUrl);
+
 
     @Select("select * from fs_video_resource where file_key = 'course/20251020/1760932918788.mp4'")
     List<FsVideoResource> selectVideoNotTranscodeTest();

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

@@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.time.LocalDate;
 import java.util.Date;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -54,6 +55,22 @@ public class FsCourseRedPacketLogParam implements Serializable {
 
     private List<String> userIds;
 
+    /**
+     * 训练营id
+     */
+    private Long trainingCampId;
+
+    /**
+     * 自动发课营期时间
+     */
+    private LocalDate sopDate;
+    /**
+     * 自动发课营期id
+     */
+    private String sopId;
+
+
+
     public List<String> getUserIds() {
         if (userIds == null || userIds.isEmpty()) {
             return userIds;

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

@@ -70,4 +70,9 @@ public class FsUserCourseVideoAddKfUParam implements Serializable {
 
     private Integer isOpenCourse;
 
+    /**
+     * 1 app 2 小程序
+     */
+    private Integer typeFlag;
+
 }

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

@@ -49,4 +49,6 @@ public interface IFsUserCourseTrainingCampService extends IService<FsUserCourseT
      * @return  list
      */
     List<OptionsVO> selectCampListByMap(Map<String, Object> params);
+
+    List<FsUserCourseTrainingCampVO> selectFsUserCourseTrainingCampListAll();
 }

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

@@ -12,8 +12,11 @@ public interface ITencentCloudCosService {
 
 //    byte[] getQcloudByte();
     R updateUrl();
+    R updateUrlByVideoId(Long videoId);
 
     R videoTranscode();
 
+    R videoTranscodeById(Long videoId);
+
 
 }

+ 5 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseTrainingCampServiceImpl.java

@@ -181,4 +181,9 @@ public class FsUserCourseTrainingCampServiceImpl extends ServiceImpl<FsUserCours
     public List<OptionsVO> selectCampListByMap(Map<String, Object> params) {
         return baseMapper.selectCampListByMap(params);
     }
+
+    @Override
+    public List<FsUserCourseTrainingCampVO> selectFsUserCourseTrainingCampListAll() {
+        return baseMapper.selectFsUserCourseTrainingCampVOListByMap(null);
+    }
 }

+ 76 - 6
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -9,6 +9,9 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.constant.FsConstants;
 import com.fs.common.core.domain.R;
@@ -61,6 +64,7 @@ import com.fs.his.service.IFsUserService;
 import com.fs.his.service.IFsUserWxService;
 import com.fs.his.utils.ConfigUtil;
 import com.fs.his.vo.OptionsVO;
+import com.fs.hisStore.domain.FsStoreProductScrm;
 import com.fs.im.service.OpenIMService;
 import com.fs.qw.domain.*;
 import com.fs.qw.domain.QwCompany;
@@ -252,6 +256,11 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
     @Autowired
     private IFsCourseLinkService linkService;
 
+    @Autowired
+    private FsDepVideoShowMapper fsDepVideoShowMapper;
+
+    @Value("${cloud_host.company_name}")
+    private String companyName;
 
     /**
      * 查询课堂视频
@@ -1008,6 +1017,11 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
                         if (log.getUserId() == null || log.getUserId().equals(0L) || !log.getUserId().equals(param.getUserId())) {
                             log.setUserId(param.getUserId());
                         }
+                        if(CloudHostUtils.hasCloudHostName("木易华康")){
+                            // 看课类型 1.app 2小程序
+                            int watchType = Objects.nonNull(param.getTypeFlag()) && param.getTypeFlag() == 1 ? 1 : 2;
+                            log.setWatchType(watchType);
+                        }
                         log.setUpdateTime(new Date());
                         courseWatchLogMapper.updateFsCourseWatchLog(log);
                     }
@@ -1036,7 +1050,11 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
         log.setQwUserId(Long.valueOf(param.getQwUserId()));
         log.setCreateTime(new Date());
         log.setLogType(3);
-        log.setWatchType(2);
+       if(param.getTypeFlag()==1){
+           log.setWatchType(1);
+       }else {
+           log.setWatchType(2);
+       }
         logger.info("【群聊生成看课记录】:{}", param);
         courseWatchLogMapper.insertFsCourseWatchLog(log);
     }
@@ -1117,6 +1135,11 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
             if (log.getUserId() == null || log.getUserId().equals(0L) || !log.getUserId().equals(param.getUserId())) {
                 log.setUserId(param.getUserId());
             }
+            if(CloudHostUtils.hasCloudHostName("木易华康")){
+                // 看课类型 1.app 2小程序
+                int watchType = Objects.nonNull(param.getTypeFlag()) && param.getTypeFlag() == 1 ? 1 : 2;
+                log.setWatchType(watchType);
+            }
             log.setUpdateTime(new Date());
             courseWatchLogMapper.updateFsCourseWatchLog(log);
 
@@ -1157,7 +1180,11 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
             if (log.getUserId() == null || log.getUserId().equals(0L) || !log.getUserId().equals(param.getUserId())) {
                 log.setUserId(param.getUserId());
             }
-
+            if(CloudHostUtils.hasCloudHostName("木易华康")){
+                // 看课类型 1.app 2小程序
+                int watchType = Objects.nonNull(param.getTypeFlag()) && param.getTypeFlag() == 1 ? 1 : 2;
+                log.setWatchType(watchType);
+            }
             log.setUpdateTime(new Date());
             courseWatchLogMapper.updateFsCourseWatchLog(log);
 
@@ -2829,7 +2856,9 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
         // 1、获取视频详情、问题详情
         ResponseResult<FsUserCourseVideoDetailsVO> videoDetails = this.getVideoDetails(param.getVideoId());
         FsUserCourseVideoDetailsVO courseVideoDetails = videoDetails.getData() != null ? videoDetails.getData() : null;
-
+        if(courseVideoDetails != null && "北京卓美".equals(companyName)){
+            getGoodsAndShow(param.getVideoId(),courseVideoDetails);
+        }
         //课程logo
         if (param.getPeriodId() != null) {
             FsUserCoursePeriod fsUserCoursePeriod = fsUserCoursePeriodMapper.selectFsUserCoursePeriodById(param.getPeriodId());
@@ -3207,7 +3236,6 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
                                      Long fsUserId, QwUser qwUser, Long externalId,Integer watchType) {
 
         try {
-
             FsCourseWatchLog watchLog = new FsCourseWatchLog();
             watchLog.setVideoId(videoId);
             watchLog.setQwExternalContactId(externalId);
@@ -3220,13 +3248,14 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
             watchLog.setCreateTime(new Date());
             watchLog.setUpdateTime(new Date());
             watchLog.setLogType(3);
-            watchLog.setWatchType(watchType);
             if (fsUserId == null) {
                 fsUserId = 0L;
             }
 
             watchLog.setUserId(fsUserId);
-
+            if(!CloudHostUtils.hasCloudHostName("木易华康")){
+                watchLog.setWatchType(watchType);
+            }
             //存看课记录
             courseWatchLogMapper.insertOrUpdateFsCourseWatchLog(watchLog);
 
@@ -3779,6 +3808,11 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
             log.setDuration(0L);
             log.setCreateTime(new Date());
             log.setLogType(3);
+            if(param.getTypeFlag()==1){
+                log.setWatchType(1);
+            }else {
+                log.setWatchType(2);
+            }
             logger.info("【群聊生成看课记录】:{}", param);
             courseWatchLogMapper.insertFsCourseWatchLog(log);
         } catch (BeansException e) {
@@ -4507,5 +4541,41 @@ public class FsUserCourseVideoServiceImpl extends ServiceImpl<FsUserCourseVideoM
     public List<OptionsVO> selectVideoOptionsByCourseId(Long courseId) {
         return fsUserCourseVideoMapper.selectVideoOptionsByCourseId(courseId);
     }
+
+    /**
+     * 小黄车商品和展示
+     */
+    private void getGoodsAndShow(Long videoId, FsUserCourseVideoDetailsVO vo) {
+        String show = fsDepVideoShowMapper.selectFsDepVideoShowByVideoId(videoId, null);
+        vo.setShowProduct(show);
+
+        FsUserCourseVideo courseVideo = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);
+        String packageJson = courseVideo.getPackageJson();
+        if (StringUtils.isNotEmpty(packageJson)) {
+            ObjectMapper objectMapper = new ObjectMapper();
+            JsonNode jsonNode = null;
+            try {
+                jsonNode = objectMapper.readTree(packageJson);
+            } catch (JsonProcessingException e) {
+                throw new RuntimeException(e);
+            }
+            if (jsonNode.isArray()) {
+                List<FsStoreProductScrm> fsPackageListVOS = new ArrayList<>();
+                for (JsonNode node : jsonNode) {
+                    FsStoreProductScrm fsStoreProductScrm = new FsStoreProductScrm();
+                    fsStoreProductScrm.setProductId(node.path("productId").asLong());
+                    fsStoreProductScrm.setImages(node.path("image").asText());
+                    fsStoreProductScrm.setImgUrl(node.path("imgUrl").asText());
+                    fsStoreProductScrm.setBarCode(node.path("barCode").asText());
+                    fsStoreProductScrm.setPrice(new BigDecimal(node.path("price").asText()));
+                    fsStoreProductScrm.setProductName(node.path("productName").asText());
+                    fsPackageListVOS.add(fsStoreProductScrm);
+                }
+                vo.setFsStoreProductScrms(fsPackageListVOS);
+            }
+        } else {
+            vo.setFsStoreProductScrms(new ArrayList<>());
+        }
+    }
 }
 

+ 36 - 0
fs-service/src/main/java/com/fs/course/service/impl/TencentCloudCosService.java

@@ -39,6 +39,7 @@ import java.util.*;
 public class TencentCloudCosService implements ITencentCloudCosService {
     private final COSClient cosClient;
     private final TencentProperties tencentProperties;
+    private final FsUserCourseVideoMapper fsUserCourseVideoMapper;
 
 
     @Override
@@ -202,6 +203,23 @@ public class TencentCloudCosService implements ITencentCloudCosService {
         }
     }
 
+    @Override
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
+    public R updateUrlByVideoId(Long videoId) {
+        try {
+            FsUserCourseVideo courseVideo = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);
+            if (courseVideo != null) {
+                FsVideoResource video = videoResourceMapper.selectVideoByVideoUrl(courseVideo.getVideoUrl());
+                if (video != null) {
+                    updateSingleVideo(video); // 将单个视频更新逻辑提取到方法
+                }
+            }
+            return R.ok();
+        } catch (Exception e) {
+            return R.error(e.getMessage());
+        }
+    }
+
     // 为每个视频更新使用独立事务
     @Transactional(propagation = Propagation.REQUIRES_NEW)
     public void updateSingleVideo(FsVideoResource video) {
@@ -275,6 +293,24 @@ public class TencentCloudCosService implements ITencentCloudCosService {
         return R.ok();
     }
 
+    @Override
+    public R videoTranscodeById(Long videoId) {
+        FsUserCourseVideo courseVideo = fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoId(videoId);
+        if (courseVideo != null) {
+            FsVideoResource video = videoResourceMapper.selectVideoByVideoUrl(courseVideo.getVideoUrl());
+            if (video != null) {
+                String inputPath = "/"+video.getFileKey();
+                String outputPath = "/"+replaceCourse(video.getFileKey());
+                submitTranscodeJob(inputPath,outputPath);
+                FsVideoResource videoMap = new FsVideoResource();
+                videoMap.setId(video.getId());
+                videoMap.setIsTranscode(1);
+                videoResourceMapper.updateById(videoMap);
+            }
+        }
+        return R.ok();
+    }
+
     private MpsClient createMpsClient() {
         Credential cred = new Credential(tencentProperties.secretId, tencentProperties.secretKey);
         HttpProfile httpProfile = new HttpProfile();

+ 13 - 0
fs-service/src/main/java/com/fs/course/vo/FsUserCourseVideoH5DVO.java

@@ -1,8 +1,12 @@
 package com.fs.course.vo;
 
 import com.fs.common.core.domain.BaseEntity;
+import com.fs.course.domain.FsCourseProduct;
+import com.fs.hisStore.domain.FsStoreProductScrm;
 import lombok.Data;
 
+import java.util.List;
+
 /**
  * 课堂视频对象 fs_user_video
  *
@@ -51,4 +55,13 @@ public class FsUserCourseVideoH5DVO extends BaseEntity
 
     private Long listingEndTime;//商品结束售卖时间
 
+    /**
+     * 是否展示商品 0展示 1不展示
+     */
+    private String showProduct;
+
+    /**
+     * 商品列表
+     */
+    private List<FsStoreProductScrm> fsStoreProductScrms;
 }

+ 10 - 0
fs-service/src/main/java/com/fs/course/vo/newfs/FsUserCourseVideoDetailsVO.java

@@ -1,5 +1,6 @@
 package com.fs.course.vo.newfs;
 
+import com.fs.hisStore.domain.FsStoreProductScrm;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -39,4 +40,13 @@ public class FsUserCourseVideoDetailsVO {
     @ApiModelProperty(value = "题库内容")
     private List<FsUserVideoQuestionVO> questionBankList;
 
+
+    /**
+     * 商品列表
+     */
+    private List<FsStoreProductScrm> fsStoreProductScrms;
+    /**
+     * 是否展示商品 0展示 1不展示
+     */
+    private String showProduct;
 }

+ 1 - 2
fs-service/src/main/java/com/fs/fastGpt/service/impl/AiHookServiceImpl.java

@@ -1022,9 +1022,8 @@ public class AiHookServiceImpl implements AiHookService {
         /*判断是否走豆包语音*/
         com.alibaba.fastjson.JSONObject vcConfig = configUtil.generateConfigByKey(SysConfigEnum.VS_CONFIG.getKey());
         if (vcConfig != null && !vcConfig.isEmpty() &&
-//                !vcConfig.equals(new com.alibaba.fastjson.JSONObject()) &&
                 "2".equals(vcConfig.getString("type"))){
-            silkVoice = wxWorkService.getSilkVoiceDoubao(content, user.getCompanyUserId());
+            silkVoice = wxWorkService.getSilkVoiceDoubao(content, user.getCompanyUserId(),user);
         }else {
             silkVoice= wxWorkService.getSilkVoice(content, user.getCompanyUserId());
         }

+ 261 - 4
fs-service/src/main/java/com/fs/gtPush/service/impl/uniPush2ServiceImpl.java

@@ -2,45 +2,67 @@ package com.fs.gtPush.service.impl;
 
 import cn.hutool.http.HttpUtil;
 import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSONObject;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.alibaba.fastjson.JSON;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.gtPush.domain.PushReqBean;
 import com.fs.gtPush.domain.PushResult;
 import com.fs.gtPush.domain.UniPushLog;
 import com.fs.gtPush.service.UniPushLogService;
 import com.fs.gtPush.service.uniPush2Service;
+import com.fs.im.config.IMConfig;
 import com.fs.im.service.OpenIMService;
+import lombok.extern.slf4j.Slf4j;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.service.ISysConfigService;
 import org.springframework.beans.factory.annotation.Autowired;
 import com.fs.gtPush.utils.PushUtils;
 import com.fs.his.domain.FsUser;
 import com.fs.his.service.IFsUserService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
 import java.util.HashMap;
 import java.util.Map;
 
 @Service
+@Slf4j
 public class uniPush2ServiceImpl implements uniPush2Service {
     @Autowired
     private OpenIMService openIMService;
-    private static final String url = "https://fc-mp-de6e03a9-c1a3-439b-9eec-d0dc3c565e4e.next.bspapp.com/push";
+//    private static final String url = "https://fc-mp-de6e03a9-c1a3-439b-9eec-d0dc3c565e4e.next.bspapp.com/push";
+
+//    @Value("${openIM.pushUrl}")
+//    private String openIMpushUrl;
 
     @Autowired
     private IFsUserService userService;
 
     @Autowired
     private UniPushLogService logService;
+    @Autowired
+    private ISysConfigService iSysConfigService;
+
+    @Autowired
+    private CompanyUserMapper companyUserMapper;
 
     @Override
     public PushResult pushMessage(PushReqBean push) {
-        String result = HttpUtil.post(url, push.toString());
-        PushResult pushResult = JSONUtil.toBean(result, PushResult.class);
-        return pushResult;
+        SysConfig config = iSysConfigService.selectConfigByConfigKey("his.config");
+        JSONObject json = JSON.parseObject(config.getConfigValue());
+        String url = json.getString("appPushUrl");
+        if (StringUtils.isBlank(url)) {
+            throw new RuntimeException("his.config 中未配置 appPushUrl");
+        }
+        String result = HttpUtil.post(url, JSON.toJSONString(push));
+        return JSONUtil.toBean(result, PushResult.class);
     }
     @Override
     public void pushSopAppLinkMsgByExternalIM(String cropId, String linkTile, String linkDescribe,String linkImageUrl, String link, Long companyUserId,Long fsUserId) throws JsonProcessingException {
@@ -51,6 +73,241 @@ public class uniPush2ServiceImpl implements uniPush2Service {
 
     }
 
+    @Override
+    public void pushIm(Long userId, Long businessId, String purl, String title, String content, Float type, Integer desType, String imJsonString) {
+        try {
+            // 构造推送参数
+            PushReqBean param = getImParam(userId, purl, title, content, type, desType, imJsonString);
+            if (param == null) {
+                // 用户无 clientId 或参数非法时,走离线推送兜底
+                log.warn("pushIm 参数不合法或用户无 jpushId,取消推送");
+                //pushImOffline(userId, businessId, purl, title, content, type, desType, imJsonString);
+                return;
+            }
+
+            // 强制系统通知,即使 App 在后台或被杀也能显示通知
+            param.setForce_notification(true);
+
+            // payload 附加参数(不会影响通知栏展示)
+            if (param.getPayload() == null) {
+                param.setPayload(new HashMap<>());
+            }
+            param.getPayload().put("url", purl);
+            if (StringUtils.isNotBlank(imJsonString)) {
+                param.getPayload().put("extra", imJsonString);
+            }
+
+            // category 通道标签(区分业务类型,方便厂商识别)
+            Map<String, String> category = new HashMap<>();
+            category.put("harmony", "WORK");
+            category.put("huawei", "WORK");
+            category.put("vivo", "TODO");
+            category.put("oppo", "IM");
+            category.put("xiaomi", "IM");
+            param.setCategory(category);
+
+            // options:各厂商定制推送配置(保证后台能弹出通知)
+            Map<String, Object> options = new HashMap<>();
+            Map<String, Object> android = new HashMap<>();
+
+            // 小米
+            Map<String, Object> xm = new HashMap<>();
+            xm.put("/extra.channel_id", "133892");
+            xm.put("/extra.notify_foreground", true);
+            android.put("XM", xm);
+
+            // OPPO
+            Map<String, Object> op = new HashMap<>();
+            op.put("/channel_id", "push_oplus_category_content");
+            op.put("/category", "IM");
+            op.put("/notify_level", 16);
+            op.put("/off_line", true);
+            android.put("OP", op);
+
+            // VIVO
+            Map<String, Object> vv = new HashMap<>();
+            vv.put("/classification", 1); // 系统通知
+            vv.put("/category", "IM");
+            vv.put("/notify_foreground", true);
+            android.put("VV", vv);
+
+            // 华为
+            Map<String, Object> hw = new HashMap<>();
+            hw.put("/message/android/category", "WORK");
+            hw.put("/message/android/notification/importance", "HIGH");
+            hw.put("/message/android/notification/visibility", "PUBLIC");
+            hw.put("/message/android/notification/channel_id", "133892");
+            android.put("HW", hw);
+
+            // 鸿蒙
+            Map<String, Object> ho = new HashMap<>();
+            ho.put("/android/notification/importance", "NORMAL");
+            ho.put("/android/notification/badge/badgeClass", "io.dcloud.PandoraEntry");
+            android.put("HO", ho);
+
+            // iOS 苹果
+            Map<String, Object> ios = new HashMap<>();
+            Map<String, Object> apns = new HashMap<>();
+            // APNs 配置
+            apns.put("/headers/apns-push-type", "alert");
+            apns.put("/headers/apns-priority", 10);
+            apns.put("/headers/apns-topic", "com.mytek.rtlive");
+
+            // 通知内容配置
+            Map<String, Object> alert = new HashMap<>();
+            alert.put("title", title);
+            alert.put("body", content);
+
+            // 声音配置
+            Map<String, Object> sound = new HashMap<>();
+            sound.put("name", "default");
+            sound.put("critical", 0);
+            sound.put("volume", 1.0);
+
+            // APS 配置
+            Map<String, Object> aps = new HashMap<>();
+            aps.put("alert", alert);
+            aps.put("sound", sound);
+            aps.put("badge", 1);
+            aps.put("mutable-content", 1);
+            aps.put("category", "IM");
+
+            apns.put("/aps", aps);
+
+            // 自定义数据
+            Map<String, Object> payload = new HashMap<>();
+            payload.put("url", purl);
+            if (StringUtils.isNotBlank(imJsonString)) {
+                payload.put("extra", imJsonString);
+            }
+            apns.put("/payload", payload);
+
+            ios.put("APNS", apns);
+
+            options.put("android", android);
+            options.put("harmony", new HashMap<>());
+            options.put("ios", ios);
+            param.setOptions(options);
+
+            // 执行推送param = {PushReqBean@19565} "PushReqBean(push_clientid=68e47070636684b4c6763b4198571821, title=im付成键1, content=图片消息, force_notification=true, category={harmony=WORK, huawei=WORK, xiaomi=IM, oppo=IM, vivo=IM}, payload={data={"sendID":"C9576","callbackCommand":"callbackAfterSendSingleMsgCommand","serverMsgID":"187e71c76ad72e4d180e034b4a3941cb","clientMsgID":"428d7691790232a7892244796f5623ed","operationID":"9ed33f7a-2b88-47ee-8509-5f8eecf42e7f","senderPlatformID":5,"senderNickname":"im付成键1","sessionType":1,"msgFrom":100,"contentType":102,"status":1,"sendTime":null,"createTime":null,"content":"{\"sourcePath\":\"微信图片_20251022163452_134_133.png\",\"sourcePicture\":{\"uuid\":\"1f53a2a8-8e70-4584-a9b0-44d4fd1cce40/微信图片_20251022163452_134_133.png\",\"type\":\"image/png\",\"size\":4756,\"width\":200,\"height\":200,\"url\":\"https://web.im.cdwjyyh.com/api/object/C9576/msg_picture_428d7691790232a7892244796f5623ed.png\"},\"bigPicture\":{\"uuid\":\"\",\"type\":\"\",\"size\":0,\"width\":0,\"height\":0,\"url\":\"\"},\"snapshotPic"… View
+            PushResult pushResult = pushMessage(param);
+            if (pushResult == null) {
+                log.error("pushIm 推送失败,返回为空 userId:{}", userId);
+                return;
+            }
+
+            // 构造日志对象
+            UniPushLog pushLog = new UniPushLog();
+            pushLog.setJpushId(param.getPush_clientid() != null ? param.getPush_clientid().toString() : null);
+            pushLog.setPushMsg(JSON.toJSONString(param));
+            pushLog.setType(type);
+            pushLog.setDesType(desType);
+            pushLog.setUserId(userId);
+            pushLog.setBusinessId(businessId);
+            pushLog.setCreateTime(DateUtils.getNowDate());
+
+            // 保存推送日志
+            logService.insertUniPushLog(PushUtils.returnMsg(pushResult, pushLog));
+
+            if (pushResult.getErrCode() != null && (pushResult.getErrCode() == 0 || pushResult.getErrCode() == 200)) {
+                log.info("pushIm 推送成功 userId:{} msg:{}", userId, pushResult.getErrMsg());
+            } else {
+                log.error("pushIm 推送失败 userId:{} msg:{}", userId, pushResult.getErrMsg());
+            }
+        } catch (Exception e) {
+            log.error("pushIm 异常 userId:{} title:{} content:{}", userId, title, content, e);
+        }
+    }
+
+    /**
+     * 专用于 pushIm 的参数构建方法
+     */
+    private PushReqBean getImParam(Long userId, String purl, String title, String content,
+                                   Float type, Integer desType, String imJsonString) {
+        if (userId == null) return null;
+        String jpushId = "";
+        FsUser fsUser = userService.selectFsUserByUserId(userId);
+        if (fsUser == null){
+            CompanyUser companyUser = companyUserMapper.selectCompanyUserById(userId);
+            if (companyUser == null){
+                return null;
+            }
+            jpushId = companyUser.getJpushId();
+        } else {
+            jpushId = fsUser.getJpushId();
+        }
+
+        if (StringUtils.isBlank(jpushId) || "0".equals(jpushId) || "string".equals(jpushId)) {
+            return null;
+        }
+
+        if (title.length() > 20 || content.length() > 50) {
+            log.warn("pushIm 参数非法:title 或 content 超过长度限制 userId:{}", userId);
+            return null;
+        }
+
+        // payload
+        Map<String, Object> payload = new HashMap<>();
+        if (StringUtils.isNotBlank(purl)) {
+            payload.put("url", purl);
+        }
+        if (StringUtils.isNotEmpty(imJsonString)) {
+            payload.put("data", imJsonString);
+        }
+        payload.put("title", title);
+        payload.put("body", content);
+
+        // category
+        Map<String, String> category = new HashMap<>();
+        category.put("harmony", "WORK");
+        category.put("huawei", "WORK");
+        category.put("vivo", "TODO");
+
+        // options.android
+        Map<String, Object> android = new HashMap<>();
+
+        // 小米
+        Map<String, Object> xm = new HashMap<>();
+        xm.put("/extra.channel_id", "133892");
+        android.put("XM", xm);
+
+        // OPPO
+        Map<String, Object> op = new HashMap<>();
+        op.put("/channel_id", "push_oplus_category_content");
+        op.put("/category", "CONTENT");
+        op.put("/notify_level", 16);
+        android.put("OP", op);
+
+        // VIVO
+        Map<String, Object> vv = new HashMap<>();
+        vv.put("/classification", 1);
+        vv.put("/category", "IM");
+        android.put("VV", vv);
+
+        // 华为
+        Map<String, Object> hw = new HashMap<>();
+        hw.put("/message/android/category", "WORK");
+        hw.put("/message/android/notification/badge/class", "io.dcloud.PandoraEntry");
+        hw.put("/message/android/notification/badge/add_num", 1);
+        android.put("HW", hw);
+
+        // 鸿蒙
+        Map<String, Object> ho = new HashMap<>();
+        ho.put("/android/notification/importance", "NORMAL");
+        ho.put("/android/notification/badge/badgeClass", "io.dcloud.PandoraEntry");
+        android.put("HO", ho);
+
+        Map<String, Object> options = new HashMap<>();
+        options.put("android", android);
+
+        PushReqBean bean = new PushReqBean(jpushId, title, content, payload, options);
+        bean.setForce_notification(false);
+        bean.setCategory(category);
+        bean.setBadge("+1");
+
+        return bean;
+    }
+
     @Override
     public void pushOne(Long userId, Long businessId, String purl, String title, String content, Float type, Integer desType) {
         PushReqBean param = getParam(userId, purl,title,content,type,desType,"");

+ 1 - 1
fs-service/src/main/java/com/fs/gtPush/service/uniPush2Service.java

@@ -12,5 +12,5 @@ public interface uniPush2Service {
 
     PushReqBean getParam(Long userId,String purl,String title,String content,Float type,Integer desType,String imJsonString);
     void pushSopAppLinkMsgByExternalIM(String cropId,String linkTile,String linkDescribe,String linkImageUrl,String link,Long companyUserId,Long fsUserId) throws JsonProcessingException;
-
+    void pushIm(Long userId, Long businessId, String purl, String title, String content, Float type, Integer desType,String imJsonString);
 }

+ 8 - 0
fs-service/src/main/java/com/fs/his/domain/FsAppVersion.java

@@ -36,6 +36,10 @@ public class FsAppVersion extends BaseEntity
     @Excel(name = "下载地址")
     private String url;
 
+    /** 下载地址 */
+    @Excel(name = "wgt下载地址")
+    private String wgtUrl;
+
     /** APP类型 1android 2ios */
     @Excel(name = "APP类型 1android 2ios")
     private Integer type;
@@ -44,6 +48,10 @@ public class FsAppVersion extends BaseEntity
     @Excel(name = "是否强制更新")
     private Integer isForce;
 
+    /** 是否强制更新 */
+    @Excel(name = "热更新强制更新")
+    private Integer isHotForce;
+
     /** APP 类型 1医生端 2药师端 */
     @Excel(name = "APP 类型 1医生端 2药师端")
     private Integer appType;

+ 4 - 0
fs-service/src/main/java/com/fs/his/domain/FsUser.java

@@ -190,6 +190,10 @@ public class FsUser extends BaseEntity
     /** app登录后不为null(表示是否下载app) */
     private String historyApp;
 
+    private String appOpenId;
+
+    private String appleKey; // 苹果key登陆验证
+
     public void setNickName(String nickname)
     {
         if(StringUtils.isNotEmpty(nickname)){

+ 2 - 1
fs-service/src/main/java/com/fs/his/enums/FsUserOperationEnum.java

@@ -9,7 +9,8 @@ public enum FsUserOperationEnum {
     ISADDKF("判断是否成为会员",4),
     STUDY("学习课程",5),
     ANSWER("答题",6),
-    SENDREWARD("发送奖励",7);
+    SENDREWARD("发送奖励",7),
+    USERIP("获取用户IP",7);
 
     private final String label;
     private final Integer value;

+ 3 - 1
fs-service/src/main/java/com/fs/his/mapper/FsDoctorMapper.java

@@ -134,7 +134,8 @@ public interface FsDoctorMapper
             "LEFT JOIN fs_doctor dd ON dd.doctor_id=doc.prescribe_doctor_id \n" +
             "where doc.doctor_id = #{doctorId}\n")
     FsDoctorVO selectFsDoctorVOByDoctorId(Long doctorId);
-    @Select("select doctor_id id,doctor_name name from fs_doctor where doctor_type =1 and doctor_name LIKE CONCAT('%', #{name}, '%')  limit 10")
+
+    @Select("select doctor_id id,doctor_name name,position,certificate_code from fs_doctor where doctor_type =1 and doctor_name LIKE CONCAT('%', #{name}, '%')  limit 10")
     List<UserVo> selectuserDocVoList(String name);
 
 
@@ -196,6 +197,7 @@ public interface FsDoctorMapper
     List<OptionsVO> selectAllfollowDoctorList();
     @Select("select account from fs_doctor where doctor_id=#{id} ")
     String selectFsDoctorNameByDoctorId(Long id);
+
     @Select("select doctor_id id,doctor_name name,position,certificate_code from fs_doctor where doctor_type =1 ")
     List<UserVo> selectAllDocVoList();
 

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

@@ -470,14 +470,13 @@ public interface FsUserMapper
 
     List<FsUser> selectFsUserListByPhone(String phone);
 
-
-    @Select("select * from fs_user where apple_key = #{appleKey}")
-    FsUser findUserByAppleKey(String appleKey);
-
     void updatePasswordByPhone(@Param("password")String password, @Param("encryptPhone")String encryptPhone);
 
     /**
      * 查询用户列表(用于积分管理,支持手机号和昵称模糊查询)
      */
     List<FsUser> selectFsUserListForIntegral(FsUser fsUser);
+
+    @Select("select * from fs_user where apple_key = #{appleKey}")
+    FsUser findUserByAppleKey(String appleKey);
 }

+ 7 - 0
fs-service/src/main/java/com/fs/his/service/IFsHealthTongueService.java

@@ -74,6 +74,13 @@ public interface IFsHealthTongueService
 
     R insertFsHealthTongueByImgUrl(FsHealthTongueUParam param);
 
+    /**
+     * 爱看舌-旧版的舌诊功能
+     * @param param
+     * @return
+     */
+    R insertFsHealthTongueByImgUrlOld(FsHealthTongueUParam param);
+
     FsHealthTongueUVO selectFsHealthTongueByUserId(long userId);
 
     List<FsHealthTongueListVO> selectFsHealthTongueListVO(FsHealthTongueParam param);

+ 70 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsHealthTongueServiceImpl.java

@@ -25,6 +25,8 @@ import com.fs.his.vo.FsHealthTongueUVO;
 import com.qiniu.util.Json;
 import org.redisson.api.RLock;
 import org.redisson.api.RedissonClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.fs.his.mapper.FsHealthTongueMapper;
@@ -40,6 +42,8 @@ import com.fs.his.service.IFsHealthTongueService;
 @Service
 public class FsHealthTongueServiceImpl implements IFsHealthTongueService
 {
+    private static final Logger log = LoggerFactory.getLogger(FsHealthTongueServiceImpl.class);
+
     @Autowired
     private FsHealthTongueMapper fsHealthTongueMapper;
     @Autowired
@@ -186,6 +190,72 @@ public class FsHealthTongueServiceImpl implements IFsHealthTongueService
         }
     }
 
+    @Override
+    public R insertFsHealthTongueByImgUrlOld(FsHealthTongueUParam param) {
+
+        QueryQuanXi queryQuanXi = new QueryQuanXi();
+        if (param.getName()!=null&&!param.getName().equals("")) {
+            queryQuanXi.setName(param.getName());
+        } else {
+            queryQuanXi.setName("匿名");
+        }
+        if (param.getAge()!=null) {
+            queryQuanXi.setAge(param.getAge()+"");
+        } else {
+            queryQuanXi.setAge("55");
+        }
+
+        queryQuanXi.setFile(param.getTongueUrl());
+        if (param.getSex()!=null) {
+            queryQuanXi.setMale(param.getSex()==1?"1":"0");
+        } else {
+            queryQuanXi.setMale("0");
+        }
+
+        AITongueResult<TongueData> tongueDataAITongueResult = aiTongueService.quanXiTongue(queryQuanXi);
+
+        if (tongueDataAITongueResult.getCode().equals("40001")) {
+            FsHealthTongue fsHealthTongue = new FsHealthTongue();
+            fsHealthTongue.setAge(param.getAge());
+            fsHealthTongue.setPatientId(param.getPatientId());
+            fsHealthTongue.setName(param.getName());
+            fsHealthTongue.setSex(param.getSex());
+            fsHealthTongue.setStatus(0);
+            fsHealthTongue.setUserId(param.getUserId());
+            fsHealthTongue.setTongueUrl(param.getTongueUrl());
+            TongueData data = tongueDataAITongueResult.getData();
+            fsHealthTongue.setTongueId(data.getId());
+            fsHealthTongue.setCreateTime(new Date());
+            fsHealthTongue.setTypeName(data.getTypeName()+"质");
+
+            fsHealthTongue.setBotai(data.getBotai());
+            fsHealthTongue.setBotaiDesc(data.getBotaiDesc());
+            fsHealthTongue.setChihen(data.getChihen());
+            fsHealthTongue.setChihenDesc(data.getChihenDesc());
+            fsHealthTongue.setLiewen(data.getLiewen());
+            fsHealthTongue.setLiewenDesc(data.getLiewenDesc());
+            fsHealthTongue.setShemianName(data.getShemianName());
+            fsHealthTongue.setShemianDesc(data.getShemianDesc());
+            fsHealthTongue.setTaiseName(data.getTaiseName());
+            fsHealthTongue.setTaiseDesc(data.getTaiseDesc());
+            String json =fsHealthTongueMapper.selectTypeJSON();
+            String typeName = fsHealthTongue.getTypeName();
+            String itemTypeJSonValue="[]";
+            List<Map<String, Object>> itemTypeJsonList = (List<Map<String, Object>>) JSON.parse(json);
+            for (Map<String, Object> stringStringMap : itemTypeJsonList) {
+                String itemType = (String) stringStringMap.get("itemType");
+                if (itemType.equals(typeName)){
+                    itemTypeJSonValue= Json.encode(stringStringMap.get("item"));
+                }
+            }
+            fsHealthTongue.setTypeJson(itemTypeJSonValue);
+            fsHealthTongueMapper.insertFsHealthTongue(fsHealthTongue);
+            return R.ok().put("data",fsHealthTongue);
+        } else {
+            return R.error(tongueDataAITongueResult.getMeta().getMsg());
+        }
+    }
+
     @Override
     public FsHealthTongueUVO selectFsHealthTongueByUserId(long userId) {
         return fsHealthTongueMapper.selectFsHealthTongueByUserId(userId);

+ 232 - 108
fs-service/src/main/java/com/fs/his/service/impl/FsInquiryOrderMsgServiceImpl.java

@@ -4,10 +4,10 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
+import cn.hutool.http.HttpRequest;
+import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.JsonNode;
@@ -16,13 +16,17 @@ import com.fasterxml.jackson.databind.json.JsonMapper;
 import com.fs.common.service.impl.SmsServiceImpl;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.event.TemplateBean;
 import com.fs.event.TemplateEvent;
 import com.fs.event.TemplateListenEnum;
 import com.fs.event.TemplateListener;
+import com.fs.gtPush.service.uniPush2Service;
 import com.fs.his.domain.*;
 import com.fs.his.dto.FsInquiryOrderPatientDTO;
 import com.fs.his.dto.PayloadDTO;
+import com.fs.his.enums.PushLogDesTypeEnum;
 import com.fs.his.mapper.*;
 import com.fs.his.param.FsFollowReportParam;
 import com.fs.his.param.FsInquiryOrderMsgListDParam;
@@ -33,7 +37,10 @@ import com.fs.his.vo.FsInquiryOrderMsgListDVO;
 import com.fs.im.config.IMConfig;
 import com.fs.im.dto.OpenImMsgCallBackResponse;
 import com.fs.im.service.IImService;
+import com.fs.im.service.OpenIMService;
+import com.fs.im.service.impl.OpenIMServiceImpl;
 import com.fs.im.vo.OpenImMsgCallBackVO;
+import com.fs.im.vo.OpenImResponseDTOTest;
 import com.fs.system.oss.CloudStorageService;
 import com.fs.system.oss.OSSFactory;
 import com.fs.watch.domain.WatchDeviceInfo;
@@ -83,6 +90,14 @@ public class FsInquiryOrderMsgServiceImpl implements IFsInquiryOrderMsgService
     @Autowired
     private DeviceSetUpService deviceSetUpService;
 
+    @Autowired
+    private uniPush2Service uniPush2Service;
+
+    @Autowired
+    private OpenIMService openIMService;
+    @Autowired
+    private CompanyUserMapper companyUserMapper;
+
 //    @Autowired
 //    TemplateListener publisher;
     Logger logger= LoggerFactory.getLogger(getClass());
@@ -335,36 +350,36 @@ public class FsInquiryOrderMsgServiceImpl implements IFsInquiryOrderMsgService
         OpenImMsgCallBackResponse openImMsgCallBackResponse = new OpenImMsgCallBackResponse();
         ObjectMapper objectMapper = new ObjectMapper();
         try {
-            if (openImMsgCallBackVO.getCallbackCommand().equals("callbackBeforeAfterMsgCommand")){
+            if (openImMsgCallBackVO.getCallbackCommand().equals("callbackBeforeAfterMsgCommand")) {
                 fsInquiryOrderMsgMapper.deleteFsInquiryOrderMsgByMsgKey(openImMsgCallBackVO.getClientMsgID());
                 return openImMsgCallBackResponse;
             }
-            String send =openImMsgCallBackVO.getSendID();
-            String to =openImMsgCallBackVO.getRecvID();
-            Long time =openImMsgCallBackVO.getSendTime();
+            String send = openImMsgCallBackVO.getSendID();
+            String to = openImMsgCallBackVO.getRecvID();
+            Long time = openImMsgCallBackVO.getSendTime();
             Date date = new Date(time);
             String content = openImMsgCallBackVO.getContent();
 
 
-            String userId="";
-            String doctorId="";
-            String companyUserId="";
-            String msgType="2";
+            String userId = "";
+            String doctorId = "";
+            String companyUserId = "";
+            String msgType = "2";
             //用户发送消息
-            if (send.contains("U")){
-                msgType="1";
-                userId=send.replace("U","");
-                if (to.contains("D")){
-                    doctorId=to.replace("D","");
-                    fsFollowReportService.addReport(userId,doctorId);
-                }else if (to.contains("C")){
-                    companyUserId=to.replace("C","");
+            if (send.contains("U")) {
+                msgType = "1";
+                userId = send.replace("U", "");
+                if (to.contains("D")) {
+                    doctorId = to.replace("D", "");
+                    fsFollowReportService.addReport(userId, doctorId);
+                } else if (to.contains("C")) {
+                    companyUserId = to.replace("C", "");
                 }
                 //医生发送消息
-            }else if (send.contains("D")){
-                doctorId=send.replace("D","");
-                if (to.contains("U")){
-                    userId=to.replace("U","");
+            } else if (send.contains("D")) {
+                doctorId = send.replace("D", "");
+                if (to.contains("U")) {
+                    userId = to.replace("U", "");
                     TemplateBean templateBean = TemplateBean.builder()
                             .title("您收到咨询回复")
                             .remark("您的咨询已回复")
@@ -372,31 +387,31 @@ public class FsInquiryOrderMsgServiceImpl implements IFsInquiryOrderMsgService
                             .templateType(TemplateListenEnum.TYPE_5.getValue())
                             .build();
                     publisher.publishEvent(new TemplateEvent(this, templateBean));
-                    if (openImMsgCallBackVO.getContentType()==101){
-                        if (content.contains("您的信息我已收到")){
+                    if (openImMsgCallBackVO.getContentType() == 101) {
+                        if (content.contains("您的信息我已收到")) {
                             long doctorIdL = Long.parseLong(doctorId);
                             long userIdL = Long.parseLong(userId);
                             int count = fsFollowReportMapper.selectFollowByUserIdAndDoctorIdAndType(userIdL, doctorIdL);
-                            if (count==0){
+                            if (count == 0) {
                                 FsUser fsUser = fsUserMapper.selectFsUserByUserId(userIdL);
-                                if (fsUser!=null&&fsUser.getPhone()!=null){
+                                if (fsUser != null && fsUser.getPhone() != null) {
                                     FsInquiryOrder order = fsFollowReportMapper.selectFsInquiryOrderByUserAndDoc(userIdL, doctorIdL);
-                                    if (order!=null){
-                                        FsInquiryOrderPatientDTO patientDTO = JSON.parseObject(order.getPatientJson(),FsInquiryOrderPatientDTO.class);
-                                        if (patientDTO!=null&&patientDTO.getPatientName()!=null){
-                                            FsDoctor doctor=doctorMapper.selectFsDoctorByDoctorId(doctorIdL);
-                                            if (doctor.getDeptId()!=null&&doctor.getDeptId().compareTo(39L)==0){
-                                                logger.info("药师回复发送短信:"+fsUser.getPhone()+patientDTO.getPatientName());
+                                    if (order != null) {
+                                        FsInquiryOrderPatientDTO patientDTO = JSON.parseObject(order.getPatientJson(), FsInquiryOrderPatientDTO.class);
+                                        if (patientDTO != null && patientDTO.getPatientName() != null) {
+                                            FsDoctor doctor = doctorMapper.selectFsDoctorByDoctorId(doctorIdL);
+                                            if (doctor.getDeptId() != null && doctor.getDeptId().compareTo(39L) == 0) {
+                                                logger.info("药师回复发送短信:" + fsUser.getPhone() + patientDTO.getPatientName());
                                                 smsService.sendUserSms(fsUser.getPhone(), patientDTO.getPatientName(), "7");
-                                            }else {
-                                                logger.info("医生回复发送短信:"+patientDTO.getMobile()+patientDTO.getPatientName());
+                                            } else {
+                                                logger.info("医生回复发送短信:" + patientDTO.getMobile() + patientDTO.getPatientName());
                                                 smsService.sendUserSms(fsUser.getPhone(), patientDTO.getPatientName(), "4");
                                             }
                                         }
-                                    }else {
+                                    } else {
                                         FsFollow fo = fsFollowReportMapper.selectFsFollowById(userIdL, doctorIdL);
-                                        if (fo!=null&&fo.getPatientName()!=null){
-                                            logger.info("药师回复发送短信:"+fsUser.getPhone()+fo.getPatientName());
+                                        if (fo != null && fo.getPatientName() != null) {
+                                            logger.info("药师回复发送短信:" + fsUser.getPhone() + fo.getPatientName());
                                             smsService.sendUserSms(fsUser.getPhone(), fo.getPatientName(), "7");
                                         }
                                     }
@@ -406,34 +421,78 @@ public class FsInquiryOrderMsgServiceImpl implements IFsInquiryOrderMsgService
                             }
                         }
                     }
-                }else {
-                    companyUserId = to.replace("C","");
+                } else {
+                    companyUserId = to.replace("C", "");
                 }
-                //销售发送消息
-            }else if (send.contains("C")){
-                companyUserId=send.replace("C","");
-                if (to.contains("U")){
-                    userId=to.replace("U","");
-                }else {
-                    doctorId = to.replace("D","");
+                //客服发送消息
+            } else if (send.contains("C")) {
+                companyUserId = send.replace("C", "");
+                if (to.contains("U")) {
+                    userId = to.replace("U", "");
+                } else {
+                    doctorId = to.replace("D", "");
                 }
             }
             Long orderId = fsInquiryOrderMsgMapper.selectFsInquiryOrderMsgOrderId(doctorId, userId);
-            if (orderId==null){
-                orderId = fsInquiryOrderMsgMapper.selectFsInquiryOrderMsgOrderIdByDate(doctorId, userId,date);
+            if (orderId == null) {
+                orderId = fsInquiryOrderMsgMapper.selectFsInquiryOrderMsgOrderIdByDate(doctorId, userId, date);
             }
 
             Integer msgContentType = openImMsgCallBackVO.getContentType();
-            Integer type=0;
-            String cont="";
+            Integer type = 0;
+            String cont = "";
             JsonNode jsonNode = null;
-            if (msgContentType != null ) {
+            String a = "";
+            openImMsgCallBackVO.setType("im");
+            if (send.contains("C") && StringUtils.isEmpty(openImMsgCallBackVO.getSenderNickname())) {
+                CompanyUser companyUser = companyUserMapper.selectCompanyUserById(Long.parseLong(openImMsgCallBackVO.getSendID().replace("C", "")));
+                openImMsgCallBackVO.setSenderNickname(StringUtils.isNotEmpty(companyUser.getImNickName()) ? companyUser.getImNickName() : companyUser.getNickName());
+            }
+            if (send.contains("D")) {
+                FsDoctor fsDoctor = doctorMapper.selectFsDoctorByDoctorId(Long.parseLong(openImMsgCallBackVO.getSendID().replace("D", "")));
+                openImMsgCallBackVO.setSenderNickname(fsDoctor.getDoctorName());
+
+            }
+            String jsonStr = objectMapper.writeValueAsString(openImMsgCallBackVO);
+            if (msgContentType != null) {
+                if (to.startsWith("U")) {
+                    a = to.replace("U", "");
+                } else if (to.startsWith("C")) {
+                    a = to.replace("C", "");
+                }
                 switch (msgContentType) {
+                    case 1601:
+                        log.info("执行音视频通话推送");
+                        cont = "通话消息";
+                        type = 1;
+                        //jsonNode = objectMapper.readTree(content);
+                        String adminToken = openIMService.getAdminToken();
+                        Map<String, Object> paramMap = new HashMap<>();
+                        ArrayList<String> userIDs = new ArrayList<>();
+                        userIDs.add(send);
+                        paramMap.put("userIDs", userIDs);
+
+                        String jsonBody = JSONUtil.toJsonStr(paramMap);
+                        String result1 = HttpRequest.post("https://web.im.cdwjyyh.com/api/user/get_users_info")
+                                .header("operationID", String.valueOf(time))
+                                .header("token", adminToken)
+                                .body(jsonBody)
+                                .execute()
+                                .body();
+                        OpenIMServiceImpl.UpdateUserInfo updateUserInfo = new OpenIMServiceImpl.UpdateUserInfo();
+                        OpenImResponseDTOTest responseDTO1 = JSONUtil.toBean(result1, OpenImResponseDTOTest.class);
+                        List<OpenIMServiceImpl.UserInfo> users = responseDTO1.getData().getUsersInfo();
+
+                        uniPush2Service.pushIm(Long.parseLong(a), 0l, "", users.get(0).getNickname(), "通话消息", 1f, PushLogDesTypeEnum.IM_MSG.getValue(), jsonStr);
+
+                        break;
                     //普通消息
                     case 101:
-                        type=1;
+                        type = 1;
                         jsonNode = objectMapper.readTree(content);
-                        cont=jsonNode.get("content").asText();
+                        cont = jsonNode.get("content").asText();
+                        uniPush2Service.pushIm(Long.parseLong(a), 0l, "", openImMsgCallBackVO.getSenderNickname(), cont, 1f, PushLogDesTypeEnum.IM_MSG.getValue(), jsonStr);
+
                         break;
                     //语音消息
                     case 103:
@@ -442,24 +501,25 @@ public class FsInquiryOrderMsgServiceImpl implements IFsInquiryOrderMsgService
                         try {
                             // 创建URL对象
                             URL url = new URL(soundUrl);
-                            InputStream in =  url.openStream();
+                            InputStream in = url.openStream();
                             CloudStorageService storage = OSSFactory.build();
                             cont = storage.uploadSuffix(in, ".m4a");
                         } catch (IOException e) {
                             e.printStackTrace();
                         }
-                        type=2;
-                        //医生发送的语音消息,这一段是同步语音消息到腕表的
-                        /*if (send.contains("D")){
-                            WatchDeviceInfo u = watchDeviceInfoMapper.selectByUserId(to.replace("U", ""));
-                            if (u!=null&& StringUtils.isNotEmpty(u.getDeviceNumber())){
-                                DeviceSendParam deviceSendParam = new DeviceSendParam();
-                                deviceSendParam.setDeviceId(u.getDeviceNumber());
-                                deviceSendParam.setFileUrl(soundUrl);
-                                deviceSendParam.setSendUserName(openImMsgCallBackVO.getSenderNickname());
-                                deviceSetUpService.sendMp3(deviceSendParam);
-                            }
-                        }*/
+                        type = 2;
+                        //医生发送的语音消息
+//                        if (send.contains("D")) {
+//                            WatchDeviceInfo u = watchDeviceInfoMapper.selectByUserId(to.replace("U", ""));
+//                            if (u != null && StringUtils.isNotEmpty(u.getDeviceNumber())) {
+//                                DeviceSendParam deviceSendParam = new DeviceSendParam();
+//                                deviceSendParam.setDeviceId(u.getDeviceNumber());
+//                                deviceSendParam.setFileUrl(soundUrl);
+//                                deviceSendParam.setSendUserName(openImMsgCallBackVO.getSenderNickname());
+////                                deviceSetUpService.sendMp3(deviceSendParam);
+//                            }
+//                        }
+                        uniPush2Service.pushIm(Long.parseLong(a), 0l, "", openImMsgCallBackVO.getSenderNickname(), "语音消息", 1f, PushLogDesTypeEnum.IM_MSG.getValue(), jsonStr);
                         break;
                     //图片消息
                     case 102:
@@ -467,13 +527,16 @@ public class FsInquiryOrderMsgServiceImpl implements IFsInquiryOrderMsgService
                         String imgUrl = jsonNode.get("sourcePicture").get("url").asText();
                         try {
                             URL url = new URL(imgUrl);
-                            InputStream in =  url.openStream();
+                            InputStream in = url.openStream();
                             CloudStorageService storage = OSSFactory.build();
                             cont = storage.uploadSuffix(in, ".jpg");
                         } catch (IOException e) {
                             e.printStackTrace();
                         }
-                        type=3;
+                        openImMsgCallBackVO.setContent("");
+                        jsonStr = objectMapper.writeValueAsString(openImMsgCallBackVO);
+                        type = 3;
+                        uniPush2Service.pushIm(Long.parseLong(a), 0l, "", openImMsgCallBackVO.getSenderNickname(), "图片消息", 1f, PushLogDesTypeEnum.IM_MSG.getValue(), jsonStr);
                         break;
                     //视频消息
                     case 104:
@@ -481,77 +544,139 @@ public class FsInquiryOrderMsgServiceImpl implements IFsInquiryOrderMsgService
                         String videoUrl = jsonNode.get("videoUrl").asText();
                         try {
                             URL url = new URL(videoUrl);
-                            InputStream in =  url.openStream();
+                            InputStream in = url.openStream();
                             CloudStorageService storage = OSSFactory.build();
-                            cont = storage.uploadSuffix(in, "."+jsonNode.get("videoType").asText());
+                            cont = storage.uploadSuffix(in, "." + jsonNode.get("videoType").asText());
                         } catch (IOException e) {
                             e.printStackTrace();
                         }
-                        type=4;
+                        openImMsgCallBackVO.setContent("");
+                        jsonStr = objectMapper.writeValueAsString(openImMsgCallBackVO);
+                        type = 4;
+                        uniPush2Service.pushIm(Long.parseLong(a), 0l, "", openImMsgCallBackVO.getSenderNickname(), "视频消息", 1f, PushLogDesTypeEnum.IM_MSG.getValue(), jsonStr);
+                        break;
+                    //文件消息
+                    case 105:
+                        jsonNode = objectMapper.readTree(content); // 转为 JsonNode
+                        cont = jsonNode.get("fileName").asText();
+                        type = 4;
+                        openImMsgCallBackVO.setContent("");
+                        jsonStr = objectMapper.writeValueAsString(openImMsgCallBackVO);
+                        uniPush2Service.pushIm(Long.parseLong(a), 0l, "", openImMsgCallBackVO.getSenderNickname(), "文件消息", 1f, PushLogDesTypeEnum.IM_MSG.getValue(), jsonStr);
                         break;
                     //自定义消息
                     case 110:
-                        PayloadDTO payloadDTO = objectMapper.readValue(content, PayloadDTO.class);
-
-                        jsonNode = objectMapper.readTree(payloadDTO.getData());
-                        JsonNode payload = jsonNode.get("payload");
+                        JsonNode rootNode = objectMapper.readTree(content);
+                        String dataStr = rootNode.get("data").asText();
+                        JsonNode innerNode = objectMapper.readTree(dataStr);
+                        JsonNode payload = innerNode.get("payload");
                         String data = payload.get("data").asText();
                         JsonNode extension = payload.get("extension");
-                        if (data.equals("prescribe")){
+                        FsUser user = null;
+                        if (data.equals("prescribe")) {
                             String prescribeId = extension.get("prescribeId").asText();
                             FsPrescribe fsPrescribe = fsPrescribeMapper.selectFsPrescribeByPrescribeId(Long.parseLong(prescribeId));
-                            cont=objectMapper.writeValueAsString(fsPrescribe);
+                            cont = objectMapper.writeValueAsString(fsPrescribe);
                             //orderId = fsPrescribe.getInquiryOrderId();
-                            type=5;
+                            type = 5;
+                            user = fsUserMapper.selectFsUserByUserId(Long.parseLong(a));
+                            if (StringUtils.isNotEmpty(user.getJpushId())) {
+                                uniPush2Service.pushIm(Long.parseLong(a), 0l, "", openImMsgCallBackVO.getSenderNickname(), "电子处方单", 1f, PushLogDesTypeEnum.IM_MSG.getValue(), jsonStr);
+                            }
                             break;
-                        }else if (data.equals("report")){
+                        } else if (data.equals("report")) {
 
                             String description = payload.get("description").asText();
                             FsInquiryOrderReport fsInquiryOrderReport = fsInquiryOrderReportService.selectFsInquiryOrderReportByOrderId(Long.parseLong(description));
-                            if (fsInquiryOrderReport!=null){
+                            if (fsInquiryOrderReport != null) {
                                 cont = fsInquiryOrderReport.getOrderId().toString();
                             }
-                            type=6;
+                            type = 6;
+                            user = fsUserMapper.selectFsUserByUserId(Long.parseLong(a));
+                            if (StringUtils.isNotEmpty(user.getJpushId())) {
+                                uniPush2Service.pushIm(Long.parseLong(a), 0l, "", openImMsgCallBackVO.getSenderNickname(), "问诊报告单", 1f, PushLogDesTypeEnum.IM_MSG.getValue(), jsonStr);
+                            }
                             break;
-                        }else if (data.equals("follow")){
-                            cont=payload.get("extension").get("followId").asText();
-                            type= 7;
+                        } else if (data.equals("follow")) {
+                            cont = payload.get("extension").get("followId").asText();
+                            type = 7;
                             //orderId = payload.get("extension").get("followId").asLong();
+                            user = fsUserMapper.selectFsUserByUserId(Long.parseLong(a));
+                            if (StringUtils.isNotEmpty(user.getJpushId())) {
+                                uniPush2Service.pushIm(Long.parseLong(a), 0l, "", openImMsgCallBackVO.getSenderNickname(), "随访单", 1f, PushLogDesTypeEnum.IM_MSG.getValue(), jsonStr);
+                            }
                             break;
-                        }else if (data.equals("drugReport")){
-                            cont=payload.get("description").asText();
+                        } else if (data.equals("drugReport")) {
+                            cont = payload.get("description").asText();
                             //orderId = payload.get("description").asLong();
-                            type= 8;
+                            type = 8;
+                            user = fsUserMapper.selectFsUserByUserId(Long.parseLong(a));
+                            if (StringUtils.isNotEmpty(user.getJpushId())) {
+                                uniPush2Service.pushIm(Long.parseLong(a), 0l, "", openImMsgCallBackVO.getSenderNickname(), "用药报告单", 1f, PushLogDesTypeEnum.IM_MSG.getValue(), jsonStr);
+                            }
                             break;
-                        } else if (data.equals("package")){
-                            cont=payload.get("extension").get("title").asText();
-                            //orderId = payload.get("description").asLong();
-                            type= 9;
+                        } else if (data.equals("package")) {
+                            cont = payload.get("extension").get("title").asText();
+                            openImMsgCallBackVO.setSendTime(null);
+                            openImMsgCallBackVO.setCreateTime(null);
+                            openImMsgCallBackVO.setFaceURL("");
+                            jsonStr = objectMapper.writeValueAsString(openImMsgCallBackVO);
+                            type = 9;
+                            user = fsUserMapper.selectFsUserByUserId(Long.parseLong(a));
+                            openImMsgCallBackVO.setContent("");
+                            jsonStr = objectMapper.writeValueAsString(openImMsgCallBackVO);
+                            if (StringUtils.isNotEmpty(user.getJpushId())) {
+                                uniPush2Service.pushIm(Long.parseLong(a), 0l, "", openImMsgCallBackVO.getSenderNickname(), "套餐包", 1f, PushLogDesTypeEnum.IM_MSG.getValue(), jsonStr);
+                            }
                             break;
-                        }else if (data.equals("couponPackage")){
-                            cont=payload.get("extension").get("title").asText();
+                        } else if (data.equals("couponPackage")) {
+                            cont = payload.get("extension").get("title").asText();
                             //orderId = payload.get("description").asLong();
-                            type= 10;
+                            type = 10;
+                            user = fsUserMapper.selectFsUserByUserId(Long.parseLong(a));
+                            openImMsgCallBackVO.setContent("");
+                            jsonStr = objectMapper.writeValueAsString(openImMsgCallBackVO);
+                            if (StringUtils.isNotEmpty(user.getJpushId())) {
+                                uniPush2Service.pushIm(Long.parseLong(a), 0l, "", openImMsgCallBackVO.getSenderNickname(), "私域疗法券", 1f, PushLogDesTypeEnum.IM_MSG.getValue(), jsonStr);
+                            }
                             break;
-                        }else if (data.equals("inquirySelect")){
-                            cont=payload.get("extension").get("title").asText();
+                        } else if (data.equals("inquirySelect")) {
+                            cont = payload.get("extension").get("title").asText();
                             //orderId = payload.get("description").asLong();
-                            type= 11;
+                            type = 11;
+                            user = fsUserMapper.selectFsUserByUserId(Long.parseLong(a));
+                            openImMsgCallBackVO.setContent("");
+                            jsonStr = objectMapper.writeValueAsString(openImMsgCallBackVO);
+                            if (StringUtils.isNotEmpty(user.getJpushId())) {
+                                uniPush2Service.pushIm(Long.parseLong(a), 0l, "", openImMsgCallBackVO.getSenderNickname(), "会诊", 1f, PushLogDesTypeEnum.IM_MSG.getValue(), jsonStr);
+                            }
                             break;
-                        }else if (data.equals("startInquiry")||data.equals("finishInquiry")){
-                            cont =payload.get("extension").get("title").asText();
-                            type=1;
+                        } else if (data.equals("startInquiry") || data.equals("finishInquiry")) {
+                            cont = payload.get("extension").get("title").asText();
+                            type = 1;
+                            user = fsUserMapper.selectFsUserByUserId(Long.parseLong(a));
+                            if (StringUtils.isNotEmpty(user.getJpushId())) {
+                                uniPush2Service.pushIm(Long.parseLong(a), 0l, "", openImMsgCallBackVO.getSenderNickname(), "接诊通知", 1f, PushLogDesTypeEnum.IM_MSG.getValue(), jsonStr);
+                            }
+                            break;
+                        } else if (data.equals("course")) {
+                            cont = payload.get("extension").get("title").asText();
+                            type = 1;
+                            user = fsUserMapper.selectFsUserByUserId(Long.parseLong(a));
+                            if (StringUtils.isNotEmpty(user.getJpushId())) {
+                                uniPush2Service.pushIm(Long.parseLong(a), 0l, "", openImMsgCallBackVO.getSenderNickname(), cont, 1f, PushLogDesTypeEnum.IM_MSG.getValue(), jsonStr);
+                            }
                             break;
                         }
 
 
                 }
             }
-            if (StringUtils.isEmpty(cont)){
+            if (StringUtils.isEmpty(cont)) {
                 openImMsgCallBackResponse.setErrMsg("无消息内容,未保存到数据库");
                 return openImMsgCallBackResponse;
             }
-            if (orderId==null&&StringUtils.isNotEmpty(openImMsgCallBackVO.getEx())){
+            if (orderId == null && StringUtils.isNotEmpty(openImMsgCallBackVO.getEx())) {
                 JsonNode exJson = objectMapper.readTree(openImMsgCallBackVO.getEx());
                 orderId = exJson.get("orderId").asLong();
             }
@@ -567,11 +692,11 @@ public class FsInquiryOrderMsgServiceImpl implements IFsInquiryOrderMsgService
             msg.setMsgType(msgType);
             fsInquiryOrderMsgMapper.insertFsInquiryOrderMsg(msg);
             // 极光推送
-            //String pushContent = (type == 1) ? content :"您有一条新消息";
-            //uniPush2Service.pushOne(Long.parseLong(to.replace("U","")), orderId, null, "新消息提醒", pushContent, PushLogTypeEnum.MARKET.getValue(), PushLogDesTypeEnum.MARKET_PUSH.getValue());
-            log.info("返回的参数 {}", JSON.toJSONString(openImMsgCallBackResponse));
+            String pushContent = (type == 1) ? content : "您有一条新消息";
+//            uniPush2Service.pushIm(Long.parseLong(to.replace("U","")), orderId, null, "新消息提醒", pushContent, PushLogTypeEnum.MARKET.getValue(), PushLogDesTypeEnum.IM_MSG.getValue());
+//            log.info("返回的参数 {}", JSON.toJSONString(openImMsgCallBackResponse));
             return openImMsgCallBackResponse;
-        } catch (Exception e){
+        } catch (Exception e) {
             openImMsgCallBackResponse.setActionCode(202);
             openImMsgCallBackResponse.setErrCode(100);
             openImMsgCallBackResponse.setErrDlt("");
@@ -579,7 +704,6 @@ public class FsInquiryOrderMsgServiceImpl implements IFsInquiryOrderMsgService
             log.info("返回的参数 {}", JSON.toJSONString(openImMsgCallBackResponse));
             return openImMsgCallBackResponse;
         }
-
     }
 
 }

+ 0 - 1
fs-service/src/main/java/com/fs/his/utils/PhoneUtil.java

@@ -7,7 +7,6 @@ import javax.crypto.spec.SecretKeySpec;
 import java.util.Base64;
 
 public class PhoneUtil {
-
     public static String encryptPhone(String text) {
         String encryptedText=null;
         try {

+ 9 - 0
fs-service/src/main/java/com/fs/his/vo/FsUserVO.java

@@ -165,4 +165,13 @@ public class FsUserVO extends FsUser implements Serializable
     @ApiModelProperty(value = "绑定时间")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date bindTime;
+
+    @ApiModelProperty(value = "最后一次登录IP")
+    private String lastIp;
+
+    @ApiModelProperty(value = "当前登录设备")
+    private String loginDevice;
+
+    @ApiModelProperty(value = "app来源")
+    private String source;
 }

+ 6 - 1
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java

@@ -635,7 +635,12 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
         List<FsStoreOrderVO> list = fsStoreOrderMapper.selectFsStoreOrderListVO(param);
         for (FsStoreOrderVO vo : list) {
             if (StringUtils.isNotEmpty(vo.getUserPhone())){
-                String nickName = vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2");
+                String nickName;
+                if (!"广州郑多燕".equals(cloudHostProper.getCompanyName())) {
+                    nickName = vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2");
+                } else {
+                    nickName = vo.getUserPhone();
+                }
                 vo.setNickname(nickName);
             }
 

+ 1 - 1
fs-service/src/main/java/com/fs/im/service/impl/OpenIMServiceImpl.java

@@ -457,7 +457,7 @@ public class OpenIMServiceImpl implements OpenIMService {
             updateUserInfo.setUserID(user.getUserID());
             updateUserInfo.setNickname(companyUser.getNickName());
             //updateUserInfo.setFaceURL(Optional.ofNullable(user.getFaceURL()).orElse("http://company.muyi88.com/profile/avatar/2025/09/10/35ed3564-aad9-4580-a746-5da01e24d2ab.jpeg"));
-            updateUserInfo.setFaceURL("http://company.muyi88.com/prod-api/profile/avatar/2025/04/08/aa418999-6738-492d-9856-491916f714d9.jpeg");
+            updateUserInfo.setFaceURL(companyUser.getAvatar());
             updateUserInfo.setEx(Optional.ofNullable(user.getEx()).orElse(""));
 
             Map<String, Object> bodyMap = new HashMap<>();

+ 1 - 0
fs-service/src/main/java/com/fs/im/vo/OpenImMsgCallBackVO.java

@@ -25,4 +25,5 @@ public class OpenImMsgCallBackVO {
     private String faceURL;
     private String ex;
     private String recvID;
+    private String type;
 }

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

@@ -115,6 +115,12 @@ public interface QwWatchLogMapper extends BaseMapper<QwWatchLog>{
             "<if test ='ids !=null and ids!=\"\"'>\n" +
             "   and qec.qw_user_id in (${ids})\n" +
             "</if>" +
+            "<if test = 'addWays != null and addWays.size()>0' >" +
+            "and qec.add_way in  " +
+            "<foreach collection=\"addWays\" item=\"item\" open=\"(\" close=\")\" separator=\",\">\n" +
+            "       ${item}\n" +
+            "                  </foreach>" +
+            "</if>" +
             "GROUP BY\n" +
             "    qec.qw_user_id, DATE(qec.create_time) \n" +
             "ORDER BY\n" +

+ 6 - 0
fs-service/src/main/java/com/fs/qw/param/QwWatchLogStatisticsListParam.java

@@ -45,6 +45,12 @@ public class QwWatchLogStatisticsListParam {
     private Long pageNum;
     private Long pageSize;
     private List<Long> filterDeptIds;
+
+    /**
+     * 添加方式
+     */
+    private List<Integer> addWays;
+
     /**
      * 今正要求把公司筛选条件优化到细分至部门,销售(前端判断,只有今正传)
      */

+ 30 - 26
fs-service/src/main/java/com/fs/qw/service/AsyncQwAiChatSopService.java

@@ -1,6 +1,7 @@
 package com.fs.qw.service;
 
 import com.alibaba.fastjson.JSON;
+import com.fs.common.utils.CloudHostUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.date.DateUtil;
 import com.fs.company.service.ICompanyMiniappService;
@@ -99,7 +100,7 @@ public class AsyncQwAiChatSopService {
 
 
         QwExternalContact contact;
-        if(externalId != null){
+        if (externalId != null) {
             contact = qwExternalContactMapper.selectById(externalId);
         } else {
             contact = null;
@@ -115,23 +116,23 @@ public class AsyncQwAiChatSopService {
 
         if (config == null) {
             log.error("配置为空-新客对话创建失败");
-            return ;
+            return;
         }
 
         QwCompany qwCompany = iQwCompanyService.getQwCompanyByRedis(qwUser.getCorpId());
 
-        if (qwCompany == null ) {
+        if (qwCompany == null) {
             log.error("企业微信主体未配置默认小程序-新客对话创建失败");
-            return ;
+            return;
         }
 
-        if (qwSopAiRuleTimeVOS != null && !qwSopAiRuleTimeVOS.isEmpty()){
+        if (qwSopAiRuleTimeVOS != null && !qwSopAiRuleTimeVOS.isEmpty()) {
 
-            qwSopAiRuleTimeVOS.forEach(item->{
+            qwSopAiRuleTimeVOS.forEach(item -> {
 
                 List<QwSopTempContent> tempContentList = qwSopTempContentMapper.selectQwSopTempContentByTempIdAndRules(item.getTempId());
 
-                tempContentList.forEach(content->{
+                tempContentList.forEach(content -> {
                     QwSopLogs sopLogs = new QwSopLogs();
                     sopLogs.setQwUserKey(qwUser.getId());
                     sopLogs.setQwUserid(userID);
@@ -148,7 +149,7 @@ public class AsyncQwAiChatSopService {
                     sopLogs.setSendType(4);
                     sopLogs.setExternalUserName(externalContactName);
 
-                    List<QwSopTempSetting.Content.Setting> settingList =new ArrayList<>();
+                    List<QwSopTempSetting.Content.Setting> settingList = new ArrayList<>();
                     QwSopTempSetting.Content.Setting setting = JSON.parseObject(content.getContent(), QwSopTempSetting.Content.Setting.class);
 
                     LocalDateTime dateTime = LocalDateTime.of(currentDate, localTime);
@@ -174,30 +175,30 @@ public class AsyncQwAiChatSopService {
 
                             if ("1".equals(setting.getContentType())) {
                                 String defaultName = "同学";
-                                if(contact != null && StringUtils.isNotEmpty(contact.getName()) && !"待同步客户".equals(contact.getName())){
+                                if (contact != null && StringUtils.isNotEmpty(contact.getName()) && !"待同步客户".equals(contact.getName())) {
                                     defaultName = contact.getName();
                                 }
                                 setting.setValue(setting.getValue()
                                         .replaceAll("#销售称呼#", StringUtil.strIsNullOrEmpty(qwUser.getWelcomeText()) ? "" : qwUser.getWelcomeText())
-                                        .replaceAll("#客户称呼#", contact == null || StringUtil.strIsNullOrEmpty(contact.getStageStatus())|| "0".equals(contact.getStageStatus())?defaultName:contact.getStageStatus()));
+                                        .replaceAll("#客户称呼#", contact == null || StringUtil.strIsNullOrEmpty(contact.getStageStatus()) || "0".equals(contact.getStageStatus()) ? defaultName : contact.getStageStatus()));
                             }
 
 
                             break;
                         //小程序单独
                         case "4":
-                            addWatchLogIfNeededByNewChat(item.getId(), content.getVideoId(), content.getCourseId(), fsUserId,qwUser.getId(), qwUser.getCompanyUserId(), qwUser.getCompanyId(),
-                                    externalId, sendTime, expirySendTime,2);
+                            addWatchLogIfNeededByNewChat(item.getId(), content.getVideoId(), content.getCourseId(), fsUserId, qwUser.getId(), qwUser.getCompanyUserId(), qwUser.getCompanyId(),
+                                    externalId, sendTime, expirySendTime, 2);
 
                             String linkByMiniApp = createLinkByMiniAppByNewChat(setting.getExpiresDays(), qwUser.getCorpId(), expirySendTime, content.getCourseId(), content.getVideoId(),
-                                    qwUser.getId(), String.valueOf(qwUser.getCompanyUserId()),String.valueOf(qwUser.getCompanyId()), externalId, config);
+                                    qwUser.getId(), String.valueOf(qwUser.getCompanyUserId()), String.valueOf(qwUser.getCompanyId()), externalId, config);
 
 
                             setting.setMiniprogramAppid(qwCompany.getMiniAppId());
 
                             String miniprogramTitle = setting.getMiniprogramTitle();
                             int maxLength = 17;
-                            setting.setMiniprogramTitle(miniprogramTitle.length() > maxLength ? miniprogramTitle.substring(0, maxLength)+"..." : miniprogramTitle);
+                            setting.setMiniprogramTitle(miniprogramTitle.length() > maxLength ? miniprogramTitle.substring(0, maxLength) + "..." : miniprogramTitle);
                             setting.setMiniprogramPage(linkByMiniApp);
                             break;
                         case "7":
@@ -211,7 +212,7 @@ public class AsyncQwAiChatSopService {
 
                     settingList.add(setting);
 
-                    QwSopTempSetting.Content clonedContent=new QwSopTempSetting.Content();
+                    QwSopTempSetting.Content clonedContent = new QwSopTempSetting.Content();
                     clonedContent.setContentType(setting.getContentType());
                     clonedContent.setCourseId(Long.valueOf(content.getCourseId()));
                     clonedContent.setVideoId(Long.valueOf(content.getVideoId()));
@@ -252,10 +253,11 @@ public class AsyncQwAiChatSopService {
             }
         }
     }
+
     //插入观看记录
     private Long addWatchLogIfNeededByNewChat(String sopId, Integer videoId, Integer courseId,
-                                     Long fsUserId, Long qwUserId, Long companyUserId,
-                                     Long companyId, Long externalId, String startTime, Date createTime,Integer watchType) {
+                                              Long fsUserId, Long qwUserId, Long companyUserId,
+                                              Long companyId, Long externalId, String startTime, Date createTime, Integer watchType) {
 
         try {
             FsCourseWatchLog watchLog = new FsCourseWatchLog();
@@ -272,7 +274,9 @@ public class AsyncQwAiChatSopService {
             watchLog.setUpdateTime(createTime);
             watchLog.setLogType(3);
             watchLog.setUserId(fsUserId);
-            watchLog.setWatchType(watchType);
+            if (!CloudHostUtils.hasCloudHostName("木易华康")) {
+                watchLog.setWatchType(watchType);
+            }
             watchLog.setCampPeriodTime(sopUserLogsInfoService.convertStringToDate(startTime, "yyyy-MM-dd HH:mm:ss"));
 
             //存看课记录
@@ -286,7 +290,7 @@ public class AsyncQwAiChatSopService {
 
     private String createLinkByMiniAppByNewChat(Integer expiresDays, String corpId, Date sendTime,
                                                 Integer courseId, Integer videoId, Long qwUserId,
-                                       String companyUserId, String companyId, Long externalId, CourseConfig config) {
+                                                String companyUserId, String companyId, Long externalId, CourseConfig config) {
 
         try {
             FsCourseLink link = sopUserLogsInfoService.createFsCourseLink(corpId, sendTime, courseId, videoId, qwUserId,
@@ -305,11 +309,11 @@ public class AsyncQwAiChatSopService {
             //存短链-
             fsCourseLinkMapper.insertFsCourseLink(link);
             return link.getRealLink();
-        }catch (Exception e){
+        } catch (Exception e) {
             log.error("创建新客对话短链失败:{}|{}|{}|{}|{}", corpId, sendTime, courseId, videoId, qwUserId);
-            log.error("e",e);
+            log.error("e", e);
         }
-            return null;
+        return null;
     }
 
     public Date createUpdateTimeByNewChat(Integer expiresDays, Date sendTime, CourseConfig config) {
@@ -334,7 +338,7 @@ public class AsyncQwAiChatSopService {
             setting.setVoiceUrl(qwSopTempVoice.getVoiceUrl());
             setting.setVoiceDuration(String.valueOf(qwSopTempVoice.getDuration()));
         } else if (qwSopTempVoice == null) {
-            if(companyUserId != null && setting.getValue() != null){
+            if (companyUserId != null && setting.getValue() != null) {
                 qwSopTempVoice = new QwSopTempVoice();
                 qwSopTempVoice.setCompanyUserId(companyUserId);
                 qwSopTempVoice.setVoiceTxt(setting.getValue());
@@ -348,15 +352,15 @@ public class AsyncQwAiChatSopService {
      * 在职转接 -AI用户信息 一起转
      */
     @Async("threadPoolTaskExecutor")
-    public void executeQwSopJobTransfer(Long externalContactId, Long externalId){
+    public void executeQwSopJobTransfer(Long externalContactId, Long externalId) {
         try {
             QwExternalContactInfo contactInfo = qwExternalContactInfoMapper.selectQwExternalContactInfoByExternalContactId(externalContactId);
             if (contactInfo != null) {
                 contactInfo.setExternalContactId(externalId);
                 qwExternalContactInfoMapper.insertQwExternalContactInfo(contactInfo);
             }
-        }catch (Exception e){
-            log.error("在职转接-转接客户AI信息失败:{},{}",externalContactId,externalId,e);
+        } catch (Exception e) {
+            log.error("在职转接-转接客户AI信息失败:{},{}", externalContactId, externalId, e);
         }
 
     }

+ 4 - 1
fs-service/src/main/java/com/fs/qw/service/impl/QwContactWayServiceImpl.java

@@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSONObject;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.core.domain.R;
 import com.fs.common.exception.CustomException;
+import com.fs.common.utils.CloudHostUtils;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.course.domain.FsCourseWatchLog;
@@ -518,7 +519,9 @@ public class QwContactWayServiceImpl implements IQwContactWayService
         watchLog.setUpdateTime(new Date());
         watchLog.setLogType(3);
         watchLog.setUserId(0L);
-        watchLog.setWatchType(watchType);
+        if(!CloudHostUtils.hasCloudHostName("木易华康")){
+            watchLog.setWatchType(watchType);
+        }
         watchLogMapper.insertOrUpdateFsCourseWatchLog(watchLog);
     }
 

File diff suppressed because it is too large
+ 176 - 182
fs-service/src/main/java/com/fs/qw/service/impl/QwExternalContactServiceImpl.java


+ 4 - 0
fs-service/src/main/java/com/fs/qw/vo/QwSopCourseFinishTempSetting.java

@@ -135,6 +135,10 @@ public class QwSopCourseFinishTempSetting implements Serializable,Cloneable{
          * 业务id
          */
         private String businessId;
+        /**
+         * 群id
+         */
+        private String chatId;
         @Override
         public Setting clone() {
             try {

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

@@ -59,6 +59,12 @@ public class QwSopTemp implements Serializable
     @TableField(exist = false)
     private String openOfficial;
 
+    /**
+     * 是否开启app发课
+     */
+    @TableField(exist = false)
+    private String openAppCourse;
+
     private String corpId;
 
     /**

+ 3 - 0
fs-service/src/main/java/com/fs/sop/domain/QwSopTempRules.java

@@ -39,6 +39,9 @@ public class QwSopTempRules{
     /**是否官方群发 */
     private String isOfficial;
 
+    /**是否App发课 */
+    private String openAppCourse;
+
     /** 消息类别;(1普通,2课程,3订单,4AI触达) */
     @Excel(name = "消息类别;", readConverterExp = "1=普通,2课程,3订单,4AI触达")
     private Integer contentType;

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

@@ -354,4 +354,7 @@ public interface QwSopLogsMapper extends BaseMapper<QwSopLogs> {
             "ORDER BY qw_user_key" +
             "</script>")
     List<QwApiSopLogToken> countQwApiAopLogToken(@Param("data") String dateStr);
+
+    @DataSource(DataSourceType.SOP)
+    void updateGroupSopStatus();
 }

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

@@ -13,6 +13,7 @@ import com.fs.sop.vo.QwSopTask;
 import com.fs.sop.vo.SopVoiceListVo;
 import com.fs.store.vo.h5.ExternalUserStatsVO;
 import com.fs.store.vo.h5.FsUserStatisticsVO;
+import com.fs.system.domain.SysConfig;
 
 import java.io.IOException;
 import java.util.List;
@@ -116,4 +117,7 @@ public interface IQwSopService
 
     //看课足迹--侧边栏
     List<FsCourseWatchLogStatisticsListVO> externalWatchRecordStatsList (QwSidebarStatsParam qwParam);
+
+    //批量修改群发sop为暂停
+    public Integer updateGroupSopStatus(SysConfig config);
 }

+ 49 - 3
fs-service/src/main/java/com/fs/sop/service/impl/QwSopServiceImpl.java

@@ -1,6 +1,8 @@
 package com.fs.sop.service.impl;
 
+import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.fs.common.annotation.DataSource;
 import com.fs.common.core.domain.R;
@@ -11,12 +13,15 @@ import com.fs.common.utils.StringUtils;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.mapper.CompanyUserMapper;
 import com.fs.company.vo.CompanyQwUserByIdsVo;
+import com.fs.course.config.CourseConfig;
 import com.fs.course.mapper.FsCourseWatchLogMapper;
 import com.fs.course.service.IFsCourseLinkService;
 import com.fs.course.service.IFsCourseWatchLogService;
 import com.fs.course.vo.FsCourseWatchLogStatisticsListVO;
 import com.fs.his.mapper.FsUserMapper;
 import com.fs.his.service.IFsUserService;
+import com.fs.his.utils.ConfigUtil;
+import com.fs.hisStore.enums.SysConfigEnum;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwSopUpdateStatus;
 import com.fs.qw.domain.QwUser;
@@ -39,6 +44,7 @@ import com.fs.sop.vo.SopVoiceListVo;
 import com.fs.sop.vo.VoiceVo;
 import com.fs.store.param.h5.UserStatisticsCommonParam;
 import com.fs.store.vo.h5.*;
+import com.fs.system.domain.SysConfig;
 import com.fs.voice.utils.StringUtil;
 import com.fs.wxUser.mapper.CompanyWxUserMapper;
 import com.fs.wxUser.param.CompanyWxUserSopParam;
@@ -69,8 +75,7 @@ import java.util.stream.Collectors;
  * @date 2024-07-31
  */
 @Service
-public class QwSopServiceImpl implements IQwSopService
-{
+public class QwSopServiceImpl implements IQwSopService {
     private static final Logger log = LoggerFactory.getLogger(QwSopServiceImpl.class);
 
     @Autowired
@@ -117,6 +122,8 @@ public class QwSopServiceImpl implements IQwSopService
     private CompanyUserMapper companyUserMapper;
 
     private IQwSopTempVoiceService qwSopTempVoiceService;
+    @Autowired
+    private ConfigUtil configUtil;
 
     @Autowired
     public void setIQwSopTempVoiceService(@Lazy IQwSopTempVoiceService qwSopTempVoiceService) {
@@ -142,6 +149,9 @@ public class QwSopServiceImpl implements IQwSopService
 
     @Autowired
     private FsUserMapper fsUserMapper;
+
+    private static final Long COURSE_CONFIG_ID = 10L;
+
     /**
      * 查询企微sop
      *
@@ -155,7 +165,6 @@ public class QwSopServiceImpl implements IQwSopService
     }
 
 
-
     /**
      * 查询企微sop列表
      *
@@ -1370,6 +1379,43 @@ public class QwSopServiceImpl implements IQwSopService
         return list;
     }
 
+    @Override
+    public Integer updateGroupSopStatus(SysConfig config) {
+        if (Objects.equals(config.getConfigId(), COURSE_CONFIG_ID)) {
+            String configValue = config.getConfigValue();
+            if (configValue != null && configValue.contains("roomLinkAllow")) {
+                try {
+                    CourseConfig newConfig = JSONUtil.toBean(configValue, CourseConfig.class);
+                    if (Boolean.TRUE.equals(newConfig.getRoomLinkAllow())) {
+                        // 获取旧配置
+                        JSONObject oldConfig = configUtil.generateConfigByKey(SysConfigEnum.COURSE_CONFIG.getKey());
+                        Boolean needUpdate = false;
+                        if (oldConfig == null) {
+                            // 旧配置不存在,需要更新
+                            needUpdate = true;
+                        } else {
+                            String oldValueStr = oldConfig.getString("roomLinkAllow");
+                            if (oldValueStr == null) {
+                                // 旧配置没有该字段,需要更新
+                                needUpdate = true;
+                            } else {
+                                Boolean oldValue = Boolean.parseBoolean(oldValueStr);
+                                // 新旧值不同时才需要更新
+                                needUpdate = !newConfig.getRoomLinkAllow().equals(oldValue);
+                            }
+                        }
+                        if (needUpdate) {
+                            qwSopLogsMapper.updateGroupSopStatus();
+                        }
+                    }
+                } catch (Exception e) {
+                    log.error("处理课程配置异常", e);
+                }
+            }
+        }
+        return null;
+    }
+
     /**
      *  获取外部联系人信息
      * */

+ 20 - 3
fs-service/src/main/java/com/fs/sop/service/impl/QwSopTempServiceImpl.java

@@ -469,6 +469,11 @@ public class QwSopTempServiceImpl implements IQwSopTempService {
                 } else {
                     rules.setIsOfficial("0");
                 }
+                if (temp.getOpenAppCourse().equals("1")) {
+                    rules.setOpenAppCourse(sorts.get() == 0 ? "1" : "0");//app看课
+                } else {
+                    rules.setOpenAppCourse("0");
+                }
 
                 if (day.getDayNum() == 1 && sorts.get() == 0 && temp.getOpenOfficial().equals("1")) {
                     rules.setTime("01:05");
@@ -508,7 +513,11 @@ public class QwSopTempServiceImpl implements IQwSopTempService {
 
                 setting.setIsBindUrl(1);
                 setting.setLinkDescribe(e.getTitle());
-                setting.setContentType("4");
+                if (temp.getOpenAppCourse().equals("1")&&temp.getOpenOfficial().equals("0")) { //如果选择了app发课
+                    setting.setContentType("9");//这里的消息类别就是app类型
+                }else {
+                    setting.setContentType("4");
+                }
                 content.setContent(JSON.toJSONString(setting));
                 content.setIsBindUrl(1);
                 List<QwSopTempContent> qwSopTempContents = new ArrayList<>();
@@ -519,7 +528,11 @@ public class QwSopTempServiceImpl implements IQwSopTempService {
                     content2.setContentType(3);
                     QwSopTempSetting2.Content.Setting setting2 = new QwSopTempSetting2.Content.Setting();
                     setting2.setValue(temp.getModeContent());
-                    setting2.setContentType("1");
+                    if (temp.getOpenAppCourse().equals("1")&&temp.getOpenOfficial().equals("0")) { //如果选择了app发课
+                        setting2.setContentType("15");//这里的内容类别就是App文本类型
+                    }else {
+                        setting2.setContentType("1");
+                    }
                     content2.setContent(JSON.toJSONString(setting2));
                     qwSopTempContents.add(content2);
                 }
@@ -530,7 +543,11 @@ public class QwSopTempServiceImpl implements IQwSopTempService {
                     content3.setContentType(3);
                     QwSopTempSetting2.Content.Setting setting3 = new QwSopTempSetting2.Content.Setting();
                     setting3.setValue(temp.getTimeDesc().get(sorts.get() - 1));
-                    setting3.setContentType("1");
+                    if (temp.getOpenAppCourse().equals("1")&&temp.getOpenOfficial().equals("0")) { //如果选择了app发课
+                        setting3.setContentType("15");//这里的内容类别就是App文本类型
+                    }else {
+                        setting3.setContentType("1");
+                    }
                     content3.setContent(JSON.toJSONString(setting3));
                     qwSopTempContents.add(content3);
 

+ 196 - 5
fs-service/src/main/java/com/fs/sop/service/impl/SopUserLogsInfoServiceImpl.java

@@ -520,6 +520,11 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
         }
         List<QwSopLogs> sopLogsList;
         if(param.getFilterMode() != null && param.getFilterMode() == 2 && param.getChatIds() != null && param.getChatIds().length > 0){
+
+            if (config.getRoomLinkAllow() != null && config.getRoomLinkAllow()) {
+                return R.error("创建群链接已禁止");
+            }
+
             List<QwGroupChat> groupList = qwGroupChatMapper.selectQwGroupChatByChatIds(param.getChatIds());
 
             Map<String, QwGroupChat> groupMap = PubFun.listToMapByGroupObject(groupList, QwGroupChat::getChatId);
@@ -614,6 +619,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             replaceContent(st.getContentType(), st.getLinkDescribe(), st::setLinkDescribe, words); // 替换 linkTitle
                         }
 
+                        String miniAppId = null;
                         switch (st.getContentType()) {
                             //文字和短链一起
                             case "1":
@@ -664,7 +670,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                 String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), new Date(), param.getCourseId(), param.getVideoId(),
                                         qwUser.getId(), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(), null, config, qwGroupChat.getChatId());
 
-                                String miniAppId = null;
+
 
                                 int listIndex = 1;
                                 if (!miniMap.isEmpty() && qwUser.getSendMsgType() == 1) {
@@ -718,6 +724,47 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                 st.setMiniprogramAppid(sysConfig.getAppId());
                                 st.setMiniprogramPage(sortLiveLink);
                                 break;
+                            // 注册
+                            case "13":
+                                try{
+
+                                    linkByMiniApp = createGroupRegisteredLinkByMiniApp(st, qwGroupChat.getCorpId(), new Date(), param.getCourseId(), param.getVideoId(),
+                                            qwUser.getId(), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(), config, groupUser.getChatId());
+
+//                                    String luckyjson = configService.selectConfigByKey("luckyBag.config");
+//                                    Map<String, Object> luckyBagConfig = JSON.parseObject(luckyjson, Map.class);
+//                                    miniAppId = String.valueOf(luckyBagConfig.get("appId"));
+
+
+                                   if (!miniMap.isEmpty() && qwUser.getSendMsgType() == 1) {
+                                        Map<Integer, List<CompanyMiniapp>> integerListMap = miniMap.get(Long.valueOf(companyId));
+                                        if (integerListMap != null) {
+                                            int listIndexNum = 1;
+                                            List<CompanyMiniapp> miniapps = integerListMap.get(listIndexNum);
+                                            if (miniapps != null && !miniapps.isEmpty()) {
+                                                CompanyMiniapp companyMiniapp = miniapps.get(0);
+                                                if (companyMiniapp != null && !StringUtil.strIsNullOrEmpty(companyMiniapp.getAppId())) {
+                                                    miniAppId = companyMiniapp.getAppId();
+                                                }
+                                            }
+                                        }
+                                    }
+                                    if (!StringUtil.strIsNullOrEmpty(miniAppId) && !StringUtil.strIsNullOrEmpty(qwCompany.getMiniAppId())) {
+                                        miniAppId = qwCompany.getMiniAppId();
+                                    }
+                                    if (!StringUtil.strIsNullOrEmpty(miniAppId)) {
+                                        st.setMiniprogramAppid(miniAppId);
+                                    } else {
+                                        log.error("公司的小程序id为空:采用了前端传的固定值" + sopLogs.getSopId());
+                                    }
+
+                                    st.setMiniprogramTitle("点击注册");
+                                    st.setMiniprogramPage(linkByMiniApp);
+
+                                }catch (Exception e) {
+                                    log.error("注册链接发送异常:"+e.getMessage());
+                                }
+                                break;
                             case "14":
 
                                 linkByMiniApp = createActivityLinkByMiniApp(st,sopLogs, qwGroupChat.getCorpId(), new Date(), param.getCourseId(), param.getVideoId(),
@@ -814,6 +861,8 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             replaceContent(st.getContentType(), st.getLinkTitle(), st::setLinkTitle, words); // 替换 linkTitle
                             replaceContent(st.getContentType(), st.getLinkDescribe(), st::setLinkDescribe, words); // 替换 linkTitle
                         }
+                        String miniAppId = null;
+                        String companyId = String.valueOf(qwUser.getCompanyId()).trim();
                         switch (st.getContentType()) {
                             //文字和短链一起
                             case "1":
@@ -860,7 +909,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                 String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), new Date(), param.getCourseId(), param.getVideoId(),
                                         qwUser.getId(), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(), null, config, groupChat.getChatId());
 
-                                String miniAppId = null;
+
 
                                 int listIndex = 1;
                                 if (!miniMap.isEmpty() && qwUser.getSendMsgType() == 1) {
@@ -921,8 +970,38 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                                 st.setMiniprogramAppid(sysConfig.getAppId());
                                 st.setMiniprogramPage(sortLiveLink);
                                 break;
+                            case "13":
+
+                                linkByMiniApp = createGroupRegisteredLinkByMiniApp(st, qwUser.getCorpId(), new Date(), param.getCourseId(), param.getVideoId(),
+                                        qwUser.getId(), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(), config, groupChat.getChatId());
+//                                String luckyjson = configService.selectConfigByKey("luckyBag.config");
+//                                Map<String, Object> luckyBagConfig = JSON.parseObject(luckyjson, Map.class);
+//                                miniAppId = String.valueOf(luckyBagConfig.get("appId"));
+                               if (!miniMap.isEmpty() && qwUser.getSendMsgType() == 1) {
+                                    Map<Integer, List<CompanyMiniapp>> integerListMap = miniMap.get(Long.valueOf(companyId));
+                                    if (integerListMap != null) {
+                                        int listIndexNum = 1;
+                                        List<CompanyMiniapp> miniapps = integerListMap.get(listIndexNum);
+                                        if (miniapps != null && !miniapps.isEmpty()) {
+                                            CompanyMiniapp companyMiniapp = miniapps.get(0);
+                                            if (companyMiniapp != null && !StringUtil.strIsNullOrEmpty(companyMiniapp.getAppId())) {
+                                                miniAppId = companyMiniapp.getAppId();
+                                            }
+                                        }
+                                    }
+                                }
+                                if (StringUtil.strIsNullOrEmpty(miniAppId) && !StringUtil.strIsNullOrEmpty(qwCompany.getMiniAppId())) {
+                                    miniAppId = qwCompany.getMiniAppId();
+                                }
+                                if (!StringUtil.strIsNullOrEmpty(miniAppId)) {
+                                    st.setMiniprogramAppid(miniAppId);
+                                } else {
+                                    log.error("公司的小程序id为空:采用了前端传的固定值" + sopLogs.getSopId());
+                                }
+                                st.setMiniprogramTitle("点击注册");
+                                st.setMiniprogramPage(linkByMiniApp);
+                                break;
                             case "14":
-                                String companyId = String.valueOf(qwUser.getCompanyId()).trim();
                                 linkByMiniApp = createActivityLinkByMiniApp(st,sopLogs, qwUser.getCorpId(), new Date(), param.getCourseId(), param.getVideoId(),
                                         String.valueOf(qwUser.getId()), qwUser.getCompanyUserId().toString(), qwUser.getCompanyId().toString(),null, config, groupChat.getChatId());
                                 miniAppId = null;
@@ -1063,6 +1142,7 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                         replaceContent(st.getContentType(), st.getLinkDescribe(), st::setLinkDescribe, words); // 替换 linkTitle
                     }
 
+                    String miniAppId = null;
                     switch (st.getContentType()){
                         //文字和短链一起
                         case "1":
@@ -1111,7 +1191,6 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             String linkByMiniApp = createLinkByMiniApp(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
                                     Long.valueOf(qwUserId), companyUserId, companyId, item.getExternalId(), config, null);
 
-                            String miniAppId = null;
 
                             int effectiveGrade = (item.getGrade() == null) ? 5 : item.getGrade();
                             int listIndex = (effectiveGrade == 1 || effectiveGrade == 2) ? 0 : 1;
@@ -1192,6 +1271,56 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
                             st.setMiniprogramAppid(sysConfig.getAppId());
                             st.setMiniprogramPage(sortLiveLink);
                             break;
+                        case "13":
+
+                            if (sopLogs.getFsUserId() != null && !Objects.equals(0L, sopLogs.getFsUserId())) {
+                                sopLogs.setSendStatus(5L);
+                                sopLogs.setReceivingStatus(0L);
+                                sopLogs.setRemark("已经注册过的客户不发送");
+                            }
+
+                            linkByMiniApp = createRegisteredLinkByMiniApp(st, param.getCorpId(), createTime, param.getCourseId(), param.getVideoId(),
+                                    Long.valueOf(qwUserId), companyUserId, companyId, item.getExternalId(), config);
+//                            String luckyjson1 = configService.selectConfigByKey("luckyBag.config");
+//                            Map<String, Object> luckyBagConfig1 = JSON.parseObject(luckyjson1, Map.class);
+//                            miniAppId = String.valueOf(luckyBagConfig1.get("appId"));
+
+                            if (!miniMap.isEmpty() && qwUser.getSendMsgType() == 1) {
+                                Map<Integer, List<CompanyMiniapp>> integerListMap = miniMap.get(Long.valueOf(companyId));
+                                if (integerListMap != null) {
+                                    int effectiveGradeNum = (item.getGrade() == null) ? 5 : item.getGrade();
+                                    int listIndexNum = (effectiveGradeNum == 1 || effectiveGradeNum == 2) ? 0 : 1;
+
+                                    //评级是6 S级,则走A类小程序
+                                    if (effectiveGradeNum==6){
+                                        listIndexNum=2;
+                                    }
+
+                                    List<CompanyMiniapp> miniapps = integerListMap.get(listIndexNum);
+
+                                    if (miniapps != null && !miniapps.isEmpty()) {
+                                        CompanyMiniapp companyMiniapp = miniapps.get(0);
+                                        if (companyMiniapp != null && !StringUtil.strIsNullOrEmpty(companyMiniapp.getAppId())) {
+                                            miniAppId = companyMiniapp.getAppId();
+                                        }
+                                    }
+                                }
+                            }
+
+                            if (StringUtil.strIsNullOrEmpty(miniAppId) && !StringUtil.strIsNullOrEmpty(qwCompany.getMiniAppId())) {
+                                miniAppId = qwCompany.getMiniAppId();
+                            }
+
+                            if (!StringUtil.strIsNullOrEmpty(miniAppId)) {
+                                st.setMiniprogramAppid(miniAppId);
+                            } else {
+                                log.error("公司的小程序id为空:采用了前端传的固定值" + sopLogs.getSopId());
+                            }
+
+                            st.setMiniprogramTitle("点击注册");
+
+                            st.setMiniprogramPage(linkByMiniApp);
+                            break;
                         case "14":
                             LuckyBag luckyBag = luckyBagMapper.selectLuckyBagById(st.getLuckyBagId());
                             if(ObjectUtil.isNotEmpty(luckyBag)&&luckyBag.getDataStatus().equals("0")){
@@ -2121,7 +2250,9 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
             watchLog.setUpdateTime(createTime);
             watchLog.setLogType(3);
             watchLog.setUserId(fsUserId);
-            watchLog.setWatchType(watchType);
+            if(!CloudHostUtils.hasCloudHostName("木易华康")){
+                watchLog.setWatchType(watchType);
+            }
             watchLog.setCampPeriodTime(convertStringToDate(startTime,"yyyy-MM-dd"));
 
             //存看课记录
@@ -2382,4 +2513,64 @@ public class SopUserLogsInfoServiceImpl implements ISopUserLogsInfoService {
         return record;
     }
 
+    private String createGroupRegisteredLinkByMiniApp(QwSopCourseFinishTempSetting.Setting setting, String corpId, Date sendTime,
+                                                      Integer courseId, Integer videoId, Long qwUserId,
+                                                      String companyUserId, String companyId, CourseConfig config, String chatId) {
+
+        FsCourseLink link = createFsCourseLink(corpId, sendTime, courseId, videoId, qwUserId,
+                companyUserId, companyId, null, 3, chatId);
+
+
+
+        FsCourseRealLink courseMap = new FsCourseRealLink();
+        BeanUtils.copyProperties(link, courseMap);
+
+        String realLinkFull = registeredRealLink + JSON.toJSONString(courseMap);
+        link.setRealLink(realLinkFull);
+
+        Date updateTime = createUpdateTime(setting, sendTime, config);
+
+        link.setUpdateTime(updateTime);
+        //存短链-
+        fsCourseLinkMapper.insertFsCourseLink(link);
+        return link.getRealLink();
+    }
+
+    private String createRegisteredLinkByMiniApp(QwSopCourseFinishTempSetting.Setting setting, String corpId, Date sendTime,
+                                                 Integer courseId, Integer videoId, Long qwUserId,
+                                                 String companyUserId, String companyId, Long externalId, CourseConfig config) {
+
+        FsCourseLink link = new FsCourseLink();
+        link.setCompanyId(Long.parseLong(companyId));
+        link.setQwUserId(qwUserId);
+        link.setCompanyUserId(Long.parseLong(companyUserId));
+        link.setVideoId(videoId.longValue());
+        link.setCorpId(corpId);
+        link.setCourseId(courseId.longValue());
+        link.setQwExternalId(externalId);
+        link.setLinkType(3); //小程序
+        link.setUNo(UUID.randomUUID().toString());
+        String randomString = generateRandomStringWithLock();
+        if (StringUtil.strIsNullOrEmpty(randomString)) {
+            link.setLink(UUID.randomUUID().toString().replace("-", ""));
+        } else {
+            link.setLink(randomString);
+        }
+        link.setCreateTime(sendTime);;
+        Date updateTime = createUpdateTime(setting, sendTime, config);
+        link.setUpdateTime(updateTime);
+
+
+        FsCourseRealLink courseMap = new FsCourseRealLink();
+        BeanUtils.copyProperties(link, courseMap);
+
+        String realLinkFull = registeredRealLink + JSON.toJSONString(courseMap);
+        link.setRealLink(realLinkFull);
+
+        log.error("存入fs_course_link:" + registeredRealLink );
+        //存短链-
+        fsCourseLinkMapper.insertFsCourseLink(link);
+        return link.getRealLink();
+    }
+
 }

+ 1 - 1
fs-service/src/main/java/com/fs/statis/dto/AnalysisPreviewQueryDTO.java

@@ -10,7 +10,7 @@ import java.io.Serializable;
 public class AnalysisPreviewQueryDTO implements Serializable {
 
     /**
-     * 0 今日,1昨日,2本周,3本月,4上月
+     * 0 今日,1昨日,2本周,3本月,4上月,5指定日期(不走缓存,直接查)
      */
     private Integer type;
 

+ 7 - 0
fs-service/src/main/java/com/fs/statis/service/impl/StatisticsServiceImpl.java

@@ -1,5 +1,6 @@
 package com.fs.statis.service.impl;
 
+import cn.hutool.core.map.MapUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.fs.common.constant.FsConstants;
 import com.fs.common.core.domain.R;
@@ -1107,6 +1108,12 @@ public class StatisticsServiceImpl implements IStatisticsService {
     @Override
     public List<WatchCourseStatisticsResultDTO> getWatchCourseStatisticsData(AnalysisPreviewQueryDTO param) {
 
+        if (param.getType().equals(5)){
+            HashMap<String, Object> map = MapUtil.newHashMap();
+            map.put("startTime", param.getStartTime());
+            map.put("endTime", param.getEndTime());
+            return fsCourseWatchLogMapper.watchCourseStatisticsGroupByCompany(map);
+        }
         String redisData = redisCache.getCacheObject(FsConstants.WATCH_COURSE_STATISTICS_GROUP_COMPANY + param.getType());
         List<WatchCourseStatisticsResultDTO> watchCourseStatisticsDTOS = new ArrayList<>();
         if (StringUtils.isNotBlank(redisData)) {

+ 2 - 1
fs-service/src/main/java/com/fs/wxwork/service/WxWorkService.java

@@ -1,5 +1,6 @@
 package com.fs.wxwork.service;
 
+import com.fs.qw.domain.QwUser;
 import com.fs.wxwork.dto.*;
 
 import java.util.List;
@@ -239,5 +240,5 @@ public interface WxWorkService {
      */
     WxWorkResponseDTO<WxCdnUploadImgLinkResp> cdnUploadImgLink(WxCdnUploadImgLinkDTO param, Long serverId);
 
-    WxwSilkVoceDTO getSilkVoiceDoubao(String content, Long companyUserId);
+    WxwSilkVoceDTO getSilkVoiceDoubao(String content, Long companyUserId, QwUser user);
 }

+ 3 - 1
fs-service/src/main/java/com/fs/wxwork/service/WxWorkServiceImpl.java

@@ -12,6 +12,7 @@ import com.fs.company.param.VcCompanyUser;
 import com.fs.config.ai.AiHostProper;
 import com.fs.fastgptApi.vo.AudioVO;
 import com.fs.qw.domain.QwIpadServer;
+import com.fs.qw.domain.QwUser;
 import com.fs.qw.service.IQwIpadServerService;
 import com.fs.wxwork.dto.*;
 import com.fs.wxwork.utils.WxWorkHttpUtil;
@@ -368,7 +369,7 @@ public class WxWorkServiceImpl implements WxWorkService {
     }
 
     @Override
-    public WxwSilkVoceDTO getSilkVoiceDoubao(String content, Long companyUserId) {
+    public WxwSilkVoceDTO getSilkVoiceDoubao(String content, Long companyUserId, QwUser user) {
         VcCompanyUser vcCompanyUser = companyUserMapper.selectVcCompanyUserByCompanyUserId(companyUserId);
         try {
             if (vcCompanyUser == null)throw new RuntimeException("用户不存在");
@@ -386,6 +387,7 @@ public class WxWorkServiceImpl implements WxWorkService {
         data.setDuration(audioVO.getDuration());
         wxwSilkVoceDTO.setData(data);
         wxwSilkVoceDTO.setCode(200);
+        ttsServiceImpl.ttsChargeByCount(vcCompanyUser,audioVO,user);
         log.info("豆包语音生成成功,url: {}", (audioVO.getUrl()));
         return wxwSilkVoceDTO;
     }

+ 2 - 2
fs-service/src/main/resources/application-config-dev-jnlzjk.yml

@@ -70,8 +70,8 @@ nuonuo:
 
 # 存储捅配置
 tencent_cloud_config:
-  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
-  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  secret_id: AKIDLl1tguyrZ6QddTCi2BLJ4e3OXVIuJVVK
+  secret_key: g9R6kLrMp8EDzXszylLispiQxHRN6cw5
   bucket: jnlzjk-1323137866
   app_id: 1323137866
   region: ap-chongqing

+ 2 - 2
fs-service/src/main/resources/application-config-dev-xcsw.yml

@@ -71,8 +71,8 @@ nuonuo:
 
 # 存储捅配置
 tencent_cloud_config:
-  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
-  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  secret_id: AKIDLl1tguyrZ6QddTCi2BLJ4e3OXVIuJVVK
+  secret_key: g9R6kLrMp8EDzXszylLispiQxHRN6cw5
   bucket: shdn-1323137866
   app_id: 1323137866
   region: ap-chongqing

+ 4 - 4
fs-service/src/main/resources/application-config-druid-bjzm-test.yml

@@ -15,8 +15,8 @@ logging:
 wx:
   miniapp:
     configs:
-      - appid: wxd70f99287830cb51   #云联融智
-        secret: 35fca481b59f5924bfb62253b5d0aa18 #北京卓美
+      - appid: wxcfd4cd6e2375e42f   #云联融智
+        secret: 8261ae10c82f009310d92d61c141ea7e #北京卓美
         token: cbnd7lJvkripVOpyTFAna6NAWCxCrvC
         aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
         msgDataFormat: JSON
@@ -74,8 +74,8 @@ nuonuo:
 
 # 存储捅配置
 tencent_cloud_config:
-  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
-  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  secret_id: AKIDLl1tguyrZ6QddTCi2BLJ4e3OXVIuJVVK
+  secret_key: g9R6kLrMp8EDzXszylLispiQxHRN6cw5
   bucket: bjzmky-1323137866
   app_id: 1323137866
   region: ap-chongqing

+ 4 - 4
fs-service/src/main/resources/application-config-druid-bjzm.yml

@@ -10,8 +10,8 @@ logging:
 wx:
   miniapp:
     configs:
-      - appid: wxd70f99287830cb51   #云联融智
-        secret: 35fca481b59f5924bfb62253b5d0aa18 #北京卓美
+      - appid: wxcfd4cd6e2375e42f   #云联融智
+        secret: 8261ae10c82f009310d92d61c141ea7e #北京卓美
         token: cbnd7lJvkripVOpyTFAna6NAWCxCrvC
         aesKey: HlEiBB55eaWUaeBVAQO3cWKWPYv1vOVQSq7nFNICw4E
         msgDataFormat: JSON
@@ -69,8 +69,8 @@ nuonuo:
 
 # 存储捅配置
 tencent_cloud_config:
-  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
-  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  secret_id: AKIDLl1tguyrZ6QddTCi2BLJ4e3OXVIuJVVK
+  secret_key: g9R6kLrMp8EDzXszylLispiQxHRN6cw5
   bucket: bjzmky-1323137866
   app_id: 1323137866
   region: ap-chongqing

+ 2 - 2
fs-service/src/main/resources/application-config-druid-cfryt.yml

@@ -73,8 +73,8 @@ nuonuo:
   secret: A2EB20764D304D16
 # 存储捅配置
 tencent_cloud_config:
-  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
-  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  secret_id: AKIDraAYkjVIvLch4ReiaIr0FTiyGPOGyUr2
+  secret_key: 3tcDi6QccQ971xoU0KRhpkSyIOIzSikZ
   bucket: ryt-1323137866
   app_id: 1323137866
   region: ap-chongqing

+ 2 - 2
fs-service/src/main/resources/application-config-druid-ddgy.yml

@@ -78,8 +78,8 @@ nuonuo:
 
 # 存储捅配置
 tencent_cloud_config:
-  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
-  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  secret_id: AKIDraAYkjVIvLch4ReiaIr0FTiyGPOGyUr2
+  secret_key: 3tcDi6QccQ971xoU0KRhpkSyIOIzSikZ
   bucket: ddgy-1323137866
   app_id: 1323137866
   region: ap-chongqing

+ 2 - 2
fs-service/src/main/resources/application-config-druid-fby.yml

@@ -90,8 +90,8 @@ nuonuo:
 
 # 存储捅配置
 tencent_cloud_config:
-  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
-  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  secret_id: AKIDraAYkjVIvLch4ReiaIr0FTiyGPOGyUr2
+  secret_key: 3tcDi6QccQ971xoU0KRhpkSyIOIzSikZ
   bucket: fby-1323137866
   app_id: 1323137866
   region: ap-chongqing

+ 2 - 2
fs-service/src/main/resources/application-config-druid-gzzdy.yml

@@ -74,8 +74,8 @@ nuonuo:
 
 # 存储捅配置
 tencent_cloud_config:
-  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
-  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  secret_id: AKIDraAYkjVIvLch4ReiaIr0FTiyGPOGyUr2
+  secret_key: 3tcDi6QccQ971xoU0KRhpkSyIOIzSikZ
   bucket: gzzdy1-1323137866
   app_id: 1323137866
   region: ap-chongqing

+ 2 - 2
fs-service/src/main/resources/application-config-druid-hdt.yml

@@ -77,8 +77,8 @@ nuonuo:
   secret: A2EB20764D304D16
 # 存储捅配置
 tencent_cloud_config:
-  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
-  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  secret_id: AKIDLl1tguyrZ6QddTCi2BLJ4e3OXVIuJVVK
+  secret_key: g9R6kLrMp8EDzXszylLispiQxHRN6cw5
   bucket: hdt-1323137866
   app_id: 1323137866
   region: ap-chongqing

+ 2 - 2
fs-service/src/main/resources/application-config-druid-heyantang.yml

@@ -69,8 +69,8 @@ nuonuo:
 
 # 存储捅配置
 tencent_cloud_config:
-  secret_id: AKIDiMq9lDf2EOM9lIfqqfKo7FNgM5meD0sT
-  secret_key: u5SuS80342xzx8FRBukza9lVNHKNMSaB
+  secret_id: AKIDLl1tguyrZ6QddTCi2BLJ4e3OXVIuJVVK
+  secret_key: g9R6kLrMp8EDzXszylLispiQxHRN6cw5
   bucket: cdhyt-1323137866
 #  bucket: cdhyt-1383856587
   app_id: 1323137866

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