Преглед на файлове

Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_his_scrm_java

yzx преди 3 дни
родител
ревизия
9664731300
променени са 100 файла, в които са добавени 6420 реда и са изтрити 562 реда
  1. 3 0
      fs-ad-api/src/main/java/com/fs/FsAdApiApplication.java
  2. 16 2
      fs-ad-api/src/main/java/com/fs/app/controller/AdCallbackController.java
  3. 0 2
      fs-ad-api/src/main/java/com/fs/app/controller/CommonController.java
  4. 0 31
      fs-ad-api/src/main/java/com/fs/app/mq/RocketMQAiMsgService.java
  5. 1 1
      fs-ad-api/src/main/java/com/fs/app/mq/RocketMQConsumerService.java
  6. 0 26
      fs-ad-api/src/main/java/com/fs/app/mq/RocketMQConsumerServiceByQw.java
  7. 0 4
      fs-ad-api/src/main/java/com/fs/app/task/Task.java
  8. 3 2
      fs-ad-api/src/main/resources/application.yml
  9. 3 11
      fs-admin/src/main/java/com/fs/ad/controller/AdAccountController.java
  10. 9 16
      fs-admin/src/main/java/com/fs/ad/controller/AdDomainController.java
  11. 103 0
      fs-admin/src/main/java/com/fs/ad/controller/AdDyAccountController.java
  12. 114 0
      fs-admin/src/main/java/com/fs/ad/controller/AdDyApiController.java
  13. 8 14
      fs-admin/src/main/java/com/fs/ad/controller/AdHtmlClickLogController.java
  14. 9 16
      fs-admin/src/main/java/com/fs/ad/controller/AdHtmlTemplateController.java
  15. 9 16
      fs-admin/src/main/java/com/fs/ad/controller/AdIqiyiAccountController.java
  16. 19 16
      fs-admin/src/main/java/com/fs/ad/controller/AdSiteController.java
  17. 97 0
      fs-admin/src/main/java/com/fs/ad/controller/AdUploadLogController.java
  18. 9 16
      fs-admin/src/main/java/com/fs/ad/controller/AdYoukuAccountController.java
  19. 8 18
      fs-admin/src/main/java/com/fs/ad/controller/BdAccountController.java
  20. 1 1
      fs-admin/src/main/java/com/fs/ad/controller/MockAppController.java
  21. 9 3
      fs-admin/src/main/java/com/fs/ad/controller/StatisticsController.java
  22. 197 0
      fs-admin/src/main/java/com/fs/api/controller/IndexStatisticsController.java
  23. 20 1
      fs-admin/src/main/java/com/fs/company/controller/CompanyUserController.java
  24. 100 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseFinishTempController.java
  25. 97 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseFinishTempParentController.java
  26. 2 2
      fs-admin/src/main/java/com/fs/course/controller/FsCourseQuestionBankController.java
  27. 3 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseTrafficLogController.java
  28. 128 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseWatchCommentController.java
  29. 61 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseWatchLogController.java
  30. 110 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseComplaintRecordController.java
  31. 101 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseComplaintTypeController.java
  32. 107 1
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseController.java
  33. 18 5
      fs-admin/src/main/java/com/fs/course/controller/FsUserCoursePeriodController.java
  34. 1 1
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseTrainingCampController.java
  35. 48 18
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseVideoController.java
  36. 115 18
      fs-admin/src/main/java/com/fs/course/controller/FsUserVideoController.java
  37. 1 1
      fs-admin/src/main/java/com/fs/course/controller/FsVideoResourceController.java
  38. 142 0
      fs-admin/src/main/java/com/fs/course/controller/qw/QwFsCourseWatchLogController.java
  39. 16 0
      fs-admin/src/main/java/com/fs/course/task/VideoTask.java
  40. 1 1
      fs-admin/src/main/java/com/fs/his/controller/FsCompanyController.java
  41. 15 28
      fs-admin/src/main/java/com/fs/his/controller/FsInquiryOrderReportController.java
  42. 12 1
      fs-admin/src/main/java/com/fs/his/controller/FsIntegralGoodsController.java
  43. 6 0
      fs-admin/src/main/java/com/fs/his/controller/FsPackageCateController.java
  44. 31 0
      fs-admin/src/main/java/com/fs/his/controller/FsUserController.java
  45. 47 0
      fs-admin/src/main/java/com/fs/his/task/FsCourseTask.java
  46. 24 91
      fs-admin/src/main/java/com/fs/his/task/Task.java
  47. 64 0
      fs-admin/src/main/java/com/fs/qw/FsCourseTask.java
  48. 138 0
      fs-admin/src/main/java/com/fs/qw/controller/QwExternalContactController.java
  49. 1 1
      fs-admin/src/main/java/com/fs/qw/controller/QwSopTempController.java
  50. 41 0
      fs-admin/src/main/java/com/fs/qw/controller/QwTagGroupController.java
  51. 10 0
      fs-admin/src/main/java/com/fs/qw/controller/QwUserController.java
  52. 28 2
      fs-admin/src/main/java/com/fs/qw/controller/SopUserLogsController.java
  53. 97 0
      fs-admin/src/main/java/com/fs/transfer/CustomerTransferApprovalController.java
  54. 12 1
      fs-admin/src/main/java/com/fs/web/controller/system/SysDictDataController.java
  55. 151 0
      fs-admin/src/main/java/com/fs/web/controller/system/SysKeywordController.java
  56. 5 0
      fs-admin/src/main/java/com/fs/web/controller/system/SysLoginController.java
  57. 7 0
      fs-admin/src/main/java/com/fs/web/controller/system/SysProfileController.java
  58. 103 0
      fs-admin/src/main/java/com/fs/web/controller/system/SysUserSetController.java
  59. 5 1
      fs-admin/src/main/resources/application.yml
  60. 6 6
      fs-admin/src/main/resources/logback.xml
  61. 0 1
      fs-ai-chat/src/main/resources/application.yml
  62. 2 2
      fs-common-api/src/main/resources/application.yml
  63. 5 0
      fs-common/src/main/java/com/fs/common/config/FSConfig.java
  64. 3 2
      fs-common/src/main/java/com/fs/common/constant/FsConstants.java
  65. 1 1
      fs-common/src/main/java/com/fs/common/core/domain/entity/SysUser.java
  66. 115 19
      fs-common/src/main/java/com/fs/common/utils/DateUtils.java
  67. 17 0
      fs-common/src/main/java/com/fs/common/utils/PatternUtils.java
  68. 3 0
      fs-company-app/src/main/java/com/fs/app/annotation/Login.java
  69. 18 0
      fs-company-app/src/main/java/com/fs/app/config/ImageStorageConfig.java
  70. 26 1
      fs-company-app/src/main/java/com/fs/app/controller/AppBaseController.java
  71. 89 0
      fs-company-app/src/main/java/com/fs/app/controller/CompanyTagController.java
  72. 311 0
      fs-company-app/src/main/java/com/fs/app/controller/CompanyUserController.java
  73. 334 0
      fs-company-app/src/main/java/com/fs/app/controller/CrmController.java
  74. 111 0
      fs-company-app/src/main/java/com/fs/app/controller/CrmEventController.java
  75. 107 0
      fs-company-app/src/main/java/com/fs/app/controller/CrmMsgController.java
  76. 339 0
      fs-company-app/src/main/java/com/fs/app/controller/FsUserController.java
  77. 224 0
      fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  78. 65 0
      fs-company-app/src/main/java/com/fs/app/controller/IndexController.java
  79. 96 0
      fs-company-app/src/main/java/com/fs/app/controller/QwCompanyUserController.java
  80. 91 0
      fs-company-app/src/main/java/com/fs/app/controller/QwWorkTaskController.java
  81. 104 0
      fs-company-app/src/main/java/com/fs/app/controller/SmsController.java
  82. 322 0
      fs-company-app/src/main/java/com/fs/app/controller/StatisticsController.java
  83. 140 0
      fs-company-app/src/main/java/com/fs/app/controller/StorePaymentController.java
  84. 85 0
      fs-company-app/src/main/java/com/fs/app/controller/StoreProductPackageController.java
  85. 62 0
      fs-company-app/src/main/java/com/fs/app/controller/TestController.java
  86. 650 162
      fs-company-app/src/main/java/com/fs/app/controller/UserController.java
  87. 192 0
      fs-company-app/src/main/java/com/fs/app/controller/WxCompanyUserController.java
  88. 110 0
      fs-company-app/src/main/java/com/fs/app/controller/WxH5MpController.java
  89. 44 0
      fs-company-app/src/main/java/com/fs/app/controller/WxMpController.java
  90. 26 0
      fs-company-app/src/main/java/com/fs/app/param/ChangeUserDeptAndPostParam.java
  91. 29 0
      fs-company-app/src/main/java/com/fs/app/param/CompanyUserChangeApplyParam.java
  92. 32 0
      fs-company-app/src/main/java/com/fs/app/param/CompanyUserParam.java
  93. 27 0
      fs-company-app/src/main/java/com/fs/app/param/CompanyUserUpdateParam.java
  94. 13 0
      fs-company-app/src/main/java/com/fs/app/param/CrmDoReadMsgParam.java
  95. 12 0
      fs-company-app/src/main/java/com/fs/app/param/FsUserLoginByMpParam.java
  96. 22 0
      fs-company-app/src/main/java/com/fs/app/param/FsUserTagUpdateParam.java
  97. 26 0
      fs-company-app/src/main/java/com/fs/app/param/FsUserUpdateParam.java
  98. 34 0
      fs-company-app/src/main/java/com/fs/app/param/LoginMaWxParam.java
  99. 2 0
      fs-company-app/src/main/java/com/fs/app/param/LoginParam.java
  100. 39 0
      fs-company-app/src/main/java/com/fs/app/service/IAppService.java

+ 3 - 0
fs-ad-api/src/main/java/com/fs/FsAdApiApplication.java

@@ -1,8 +1,10 @@
 package com.fs;
 
+import org.apache.rocketmq.spring.autoconfigure.RocketMQAutoConfiguration;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.context.annotation.Import;
 import org.springframework.scheduling.annotation.EnableAsync;
 import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.transaction.annotation.EnableTransactionManagement;
@@ -11,6 +13,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
  * 启动程序
  */
 @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
+@Import({ RocketMQAutoConfiguration.class })
 @EnableTransactionManagement
 @EnableAsync
 @EnableScheduling

+ 16 - 2
fs-ad-api/src/main/java/com/fs/app/controller/AdCallbackController.java

@@ -11,12 +11,13 @@ import com.fs.ad.service.IAdSiteService;
 import com.fs.baidu.api.BaiduApis;
 import com.fs.baidu.service.IBdAccountService;
 import com.fs.baidu.vo.ad.AdBaiduClickCallbackVo;
-import com.fs.baidu.vo.AdClickCallbackVo;
+import com.fs.baidu.vo.ad.AdDyClickCallbackVo;
 import com.fs.baidu.vo.ad.AdIqiyiClickCallbackVo;
 import com.fs.baidu.vo.ad.AdYouKuClickCallbackVo;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.R;
-import com.fs.common.utils.StringUtils;
+import com.fs.qw.domain.QwWorkLink;
+import com.fs.qw.service.IQwWorkLinkService;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -41,6 +42,7 @@ public class AdCallbackController extends BaseController {
     private final IBdAccountService bdAccountService;
     private final IAdSiteService adSiteService;
     private final IAdAccountService adAccountService;
+    private final IQwWorkLinkService qwWorkLinkService;
 
     //百度-页面点击接口
 //    @GetMapping("/callback")
@@ -69,6 +71,12 @@ public class AdCallbackController extends BaseController {
     @GetMapping("/getTemplateById")
     public R getTemplateById(Long id){
         AdSite site = adSiteService.getById(id);
+        if(site.getWorkId() != null){
+            QwWorkLink byId = qwWorkLinkService.getById(site.getWorkId());
+            if(byId != null){
+                site.setWorkUrl(byId.getUrl());
+            }
+        }
         AdHtmlTemplate htmlUrl = adHtmlTemplateMapper.selectById(site.getTemplateId());
         if(htmlUrl == null){
             return R.error("错误编号");
@@ -106,6 +114,12 @@ public class AdCallbackController extends BaseController {
         adHtmlClickLogService.setLogIqiyi(vo);
         return R.ok();
     }
+    @GetMapping("/dyClickCallback")
+    public R dyClickCallback(AdDyClickCallbackVo vo){
+        log.info("抖音监听地址返回数据:{}", JSON.toJSONString(vo));
+        adHtmlClickLogService.setLogDy(vo);
+        return R.ok();
+    }
 
 
 }

+ 0 - 2
fs-ad-api/src/main/java/com/fs/app/controller/CommonController.java

@@ -5,9 +5,7 @@ import com.alibaba.fastjson.JSON;
 import com.fs.ad.enums.AdUploadType;
 import com.fs.ad.service.IAdHtmlClickLogService;
 import com.fs.common.core.domain.R;
-import com.fs.company.service.ICompanyWxChatService;
 import com.fs.qw.vo.AdUploadVo;
-import com.fs.wxUser.service.ICompanyWxUserService;
 import io.swagger.annotations.Api;
 import jdk.nashorn.internal.ir.annotations.Ignore;
 import lombok.AllArgsConstructor;

+ 0 - 31
fs-ad-api/src/main/java/com/fs/app/mq/RocketMQAiMsgService.java

@@ -1,31 +0,0 @@
-//package com.fs.app.mq;
-//
-//import cn.hutool.json.JSONUtil;
-//import com.alibaba.fastjson.JSON;
-//import com.fs.ad.service.IAdHtmlClickLogService;
-//import com.fs.fastGpt.mapper.FastGptChatReplaceWordsMapper;
-//import com.fs.fastGpt.service.IFastGptChatSessionService;
-//import com.fs.qw.vo.AdUploadVo;
-//import com.fs.qwHookApi.vo.QwHookMsgVO;
-//import lombok.AllArgsConstructor;
-//import lombok.extern.slf4j.Slf4j;
-//import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
-//import org.apache.rocketmq.spring.core.RocketMQListener;
-//import org.springframework.beans.factory.annotation.Autowired;
-//import org.springframework.stereotype.Service;
-//
-//@Slf4j
-//@Service
-//@AllArgsConstructor
-//@RocketMQMessageListener(topic = "msg", consumerGroup = "msg-group")
-//public class RocketMQAiMsgService implements RocketMQListener<String> {
-//
-//    @Autowired
-//    private IFastGptChatSessionService fastGptChatSessionService;
-//    @Override
-//    public void onMessage(String message) {
-//        log.info("消息队列接收到消息:{}",  message);
-//        QwHookMsgVO msgVo= JSONUtil.toBean(message,QwHookMsgVO.class);
-//        fastGptChatSessionService.qwHookNotifyAddMsg(msgVo);
-//    }
-//}

+ 1 - 1
fs-ad-api/src/main/java/com/fs/app/mq/RocketMQConsumerService.java

@@ -14,7 +14,7 @@ import org.springframework.stereotype.Service;
 @Slf4j
 @Service
 @AllArgsConstructor
-@RocketMQMessageListener(topic = "${rocketmq.consumer.topic}", consumerGroup = "${rocketmq.consumer.group}")
+@RocketMQMessageListener(topic = "ad-upload", consumerGroup = "${rocketmq.consumer.group}")
 public class RocketMQConsumerService implements RocketMQListener<String> {
 
     private final IAdHtmlClickLogService  adHtmlClickLogService;

+ 0 - 26
fs-ad-api/src/main/java/com/fs/app/mq/RocketMQConsumerServiceByQw.java

@@ -1,26 +0,0 @@
-//package com.fs.app.mq;
-//
-//import com.alibaba.fastjson.JSON;
-//import com.fs.ad.service.IAdHtmlClickLogService;
-//import com.fs.qw.vo.AdUploadVo;
-//import lombok.AllArgsConstructor;
-//import lombok.extern.slf4j.Slf4j;
-//import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
-//import org.apache.rocketmq.spring.core.RocketMQListener;
-//import org.springframework.stereotype.Service;
-//
-//@Slf4j
-//@Service
-//@AllArgsConstructor
-////@RocketMQMessageListener(topic = "ad-qw-external-contact", consumerGroup = "ad-group")
-//@RocketMQMessageListener(topic = "ad-qw-external-contact", consumerGroup = "test-group")
-//public class RocketMQConsumerServiceByQw implements RocketMQListener<String> {
-//
-//
-//    @Override
-//    public void onMessage(String message) {
-//
-//        log.info("消息队列接收到消息qw:{}",  message);
-//
-//    }
-//}

+ 0 - 4
fs-ad-api/src/main/java/com/fs/app/task/Task.java

@@ -4,15 +4,11 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.fs.ad.domain.AdHtmlClickLog;
 import com.fs.ad.service.IAdHtmlClickLogService;
 import com.fs.ad.service.impl.AdHtmlClickLogServiceImpl;
-import com.fs.common.core.redis.RedisCache;
 import com.fs.common.core.redis.RedisCacheT;
-import com.fs.live.domain.Live;
-import com.fs.live.service.ILiveService;
 import lombok.AllArgsConstructor;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
-import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.temporal.ChronoUnit;
 import java.util.List;

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

@@ -4,5 +4,6 @@ server:
 # Spring配置
 spring:
   profiles:
-    active: dev
-    include: common,config-dev
+#    active: dev
+#    active: druid-hdt
+    active: druid-myhk

+ 3 - 11
fs-admin/src/main/java/com/fs/ad/controller/AdAccountController.java

@@ -1,20 +1,12 @@
 package com.fs.ad.controller;
 
-import com.fs.ad.domain.AdSite;
 import com.fs.ad.service.IAdAccountService;
-import com.fs.ad.service.IAdSiteService;
-import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
-import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
-import com.fs.common.core.page.TableDataInfo;
-import com.fs.common.enums.BusinessType;
-import com.fs.common.utils.poi.ExcelUtil;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
 /**
  * 站点管理Controller

+ 9 - 16
fs-admin/src/main/java/com/fs/ad/controller/AdDomainController.java

@@ -1,26 +1,19 @@
 package com.fs.ad.controller;
 
-import java.util.List;
-
-import com.fs.common.core.domain.R;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import com.fs.ad.domain.AdDomain;
+import com.fs.ad.service.IAdDomainService;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
-import com.fs.ad.domain.AdDomain;
-import com.fs.ad.service.IAdDomainService;
 import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 广告域名Controller

+ 103 - 0
fs-admin/src/main/java/com/fs/ad/controller/AdDyAccountController.java

@@ -0,0 +1,103 @@
+package com.fs.ad.controller;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.ad.domain.AdDyAccount;
+import com.fs.ad.service.IAdDyAccountService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 抖音账户Controller
+ * 
+ * @author 吴树波
+ * @date 2025-05-27
+ */
+@RestController
+@RequestMapping("/ad/AdDyAccount")
+public class AdDyAccountController extends BaseController
+{
+    @Autowired
+    private IAdDyAccountService adDyAccountService;
+
+    /**
+     * 查询抖音账户列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdDyAccount:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AdDyAccount adDyAccount)
+    {
+        startPage();
+        List<AdDyAccount> list = adDyAccountService.selectAdDyAccountList(adDyAccount);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出抖音账户列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdDyAccount:export')")
+    @Log(title = "抖音账户", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(AdDyAccount adDyAccount)
+    {
+        List<AdDyAccount> list = adDyAccountService.selectAdDyAccountList(adDyAccount);
+        ExcelUtil<AdDyAccount> util = new ExcelUtil<AdDyAccount>(AdDyAccount.class);
+        return util.exportExcel(list, "抖音账户数据");
+    }
+
+    /**
+     * 获取抖音账户详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdDyAccount:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(adDyAccountService.selectAdDyAccountById(id));
+    }
+
+    /**
+     * 新增抖音账户
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdDyAccount:add')")
+    @Log(title = "抖音账户", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AdDyAccount adDyAccount)
+    {
+        return toAjax(adDyAccountService.insertAdDyAccount(adDyAccount));
+    }
+
+    /**
+     * 修改抖音账户
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdDyAccount:edit')")
+    @Log(title = "抖音账户", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AdDyAccount adDyAccount)
+    {
+        return toAjax(adDyAccountService.updateAdDyAccount(adDyAccount));
+    }
+
+    /**
+     * 删除抖音账户
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdDyAccount:remove')")
+    @Log(title = "抖音账户", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(adDyAccountService.deleteAdDyAccountByIds(ids));
+    }
+}

+ 114 - 0
fs-admin/src/main/java/com/fs/ad/controller/AdDyApiController.java

@@ -0,0 +1,114 @@
+package com.fs.ad.controller;
+
+import java.util.List;
+
+import com.fs.ad.vo.DyAuthorizedVo;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.ad.domain.AdDyApi;
+import com.fs.ad.service.IAdDyApiService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 抖音投流API信息Controller
+ * 
+ * @author 吴树波
+ * @date 2025-05-27
+ */
+@RestController
+@RequestMapping("/ad/adDyApi")
+public class AdDyApiController extends BaseController
+{
+    @Autowired
+    private IAdDyApiService adDyApiService;
+
+    /**
+     * 查询抖音投流API信息列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDyApi:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AdDyApi adDyApi)
+    {
+        startPage();
+        List<AdDyApi> list = adDyApiService.selectAdDyApiList(adDyApi);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出抖音投流API信息列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDyApi:export')")
+    @Log(title = "抖音投流API信息", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(AdDyApi adDyApi)
+    {
+        List<AdDyApi> list = adDyApiService.selectAdDyApiList(adDyApi);
+        ExcelUtil<AdDyApi> util = new ExcelUtil<AdDyApi>(AdDyApi.class);
+        return util.exportExcel(list, "抖音投流API信息数据");
+    }
+
+    /**
+     * 获取抖音投流API信息详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDyApi:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(adDyApiService.selectAdDyApiById(id));
+    }
+
+    /**
+     * 新增抖音投流API信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDyApi:add')")
+    @Log(title = "抖音投流API信息", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AdDyApi adDyApi)
+    {
+        return toAjax(adDyApiService.insertAdDyApi(adDyApi));
+    }
+
+    /**
+     * 修改抖音投流API信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDyApi:edit')")
+    @Log(title = "抖音投流API信息", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AdDyApi adDyApi)
+    {
+        return toAjax(adDyApiService.updateAdDyApi(adDyApi));
+    }
+
+    /**
+     * 删除抖音投流API信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDyApi:remove')")
+    @Log(title = "抖音投流API信息", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(adDyApiService.deleteAdDyApiByIds(ids));
+    }
+    /**
+     * 删除抖音投流API信息
+     */
+    @Log(title = "抖音API授权", businessType = BusinessType.UPDATE)
+	@GetMapping("/authorized")
+    public String authorized(DyAuthorizedVo vo){
+        System.out.println(vo);
+        return "授权成功";
+    }
+}

+ 8 - 14
fs-admin/src/main/java/com/fs/ad/controller/AdHtmlClickLogController.java

@@ -1,24 +1,18 @@
 package com.fs.ad.controller;
 
-import java.util.List;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import com.fs.ad.domain.AdHtmlClickLog;
+import com.fs.ad.service.IAdHtmlClickLogService;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
-import com.fs.ad.domain.AdHtmlClickLog;
-import com.fs.ad.service.IAdHtmlClickLogService;
 import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 广告点击Controller

+ 9 - 16
fs-admin/src/main/java/com/fs/ad/controller/AdHtmlTemplateController.java

@@ -1,26 +1,19 @@
 package com.fs.ad.controller;
 
-import java.util.List;
-
-import com.fs.common.core.domain.R;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import com.fs.ad.domain.AdHtmlTemplate;
+import com.fs.ad.service.IAdHtmlTemplateService;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
-import com.fs.ad.domain.AdHtmlTemplate;
-import com.fs.ad.service.IAdHtmlTemplateService;
 import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 广告信息流链接Controller

+ 9 - 16
fs-admin/src/main/java/com/fs/ad/controller/AdIqiyiAccountController.java

@@ -1,26 +1,19 @@
 package com.fs.ad.controller;
 
-import java.util.List;
-
-import com.fs.common.core.domain.R;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import com.fs.ad.domain.AdIqiyiAccount;
+import com.fs.ad.service.IAdIqiyiAccountService;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
-import com.fs.ad.domain.AdIqiyiAccount;
-import com.fs.ad.service.IAdIqiyiAccountService;
 import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 爱奇艺广告账号Controller

+ 19 - 16
fs-admin/src/main/java/com/fs/ad/controller/AdSiteController.java

@@ -1,26 +1,19 @@
 package com.fs.ad.controller;
 
-import java.util.List;
-
-import com.fs.common.core.domain.R;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import com.fs.ad.domain.AdSite;
+import com.fs.ad.service.IAdSiteService;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
-import com.fs.ad.domain.AdSite;
-import com.fs.ad.service.IAdSiteService;
 import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 站点管理Controller
@@ -47,6 +40,16 @@ public class AdSiteController extends BaseController
         return getDataTable(list);
     }
 
+    /**
+     * 查询站点管理列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adSite:list')")
+    @GetMapping("/listAll")
+    public R listAll(AdSite adSite){
+        List<AdSite> list = adSiteService.selectAdSiteList(adSite);
+        return R.ok().put("data", list);
+    }
+
     /**
      * 导出站点管理列表
      */

+ 97 - 0
fs-admin/src/main/java/com/fs/ad/controller/AdUploadLogController.java

@@ -0,0 +1,97 @@
+package com.fs.ad.controller;
+
+import com.fs.ad.domain.AdUploadLog;
+import com.fs.ad.service.IAdUploadLogService;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 百度回传日志Controller
+ * 
+ * @author fs
+ * @date 2025-03-14
+ */
+@RestController
+@RequestMapping("/ad/AdUploadLog")
+public class AdUploadLogController extends BaseController
+{
+    @Autowired
+    private IAdUploadLogService adUploadLogService;
+
+    /**
+     * 查询百度回传日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdUploadLog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AdUploadLog adUploadLog)
+    {
+        startPage();
+        List<AdUploadLog> list = adUploadLogService.selectAdUploadLogList(adUploadLog);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出百度回传日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdUploadLog:export')")
+    @Log(title = "百度回传日志", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(AdUploadLog adUploadLog)
+    {
+        List<AdUploadLog> list = adUploadLogService.selectAdUploadLogList(adUploadLog);
+        ExcelUtil<AdUploadLog> util = new ExcelUtil<AdUploadLog>(AdUploadLog.class);
+        return util.exportExcel(list, "百度回传日志数据");
+    }
+
+    /**
+     * 获取百度回传日志详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdUploadLog:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(adUploadLogService.selectAdUploadLogById(id));
+    }
+
+    /**
+     * 新增百度回传日志
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdUploadLog:add')")
+    @Log(title = "百度回传日志", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AdUploadLog adUploadLog)
+    {
+        return toAjax(adUploadLogService.insertAdUploadLog(adUploadLog));
+    }
+
+    /**
+     * 修改百度回传日志
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdUploadLog:edit')")
+    @Log(title = "百度回传日志", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AdUploadLog adUploadLog)
+    {
+        return toAjax(adUploadLogService.updateAdUploadLog(adUploadLog));
+    }
+
+    /**
+     * 删除百度回传日志
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdUploadLog:remove')")
+    @Log(title = "百度回传日志", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(adUploadLogService.deleteAdUploadLogByIds(ids));
+    }
+}

+ 9 - 16
fs-admin/src/main/java/com/fs/ad/controller/AdYoukuAccountController.java

@@ -1,26 +1,19 @@
 package com.fs.ad.controller;
 
-import java.util.List;
-
-import com.fs.common.core.domain.R;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import com.fs.ad.domain.AdYoukuAccount;
+import com.fs.ad.service.IAdYoukuAccountService;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
-import com.fs.ad.domain.AdYoukuAccount;
-import com.fs.ad.service.IAdYoukuAccountService;
 import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
 
 /**
  * 优酷广告账号Controller

+ 8 - 18
fs-admin/src/main/java/com/fs/ad/controller/BdAccountController.java

@@ -1,31 +1,21 @@
 package com.fs.ad.controller;
 
-import java.time.LocalDate;
-import java.util.List;
-import java.util.Optional;
-
 import com.fs.baidu.api.BaiduApis;
 import com.fs.baidu.domain.*;
-import com.fs.baidu.enums.BdTimeUnit;
-import com.fs.baidu.param.QueryReportDataParam;
 import com.fs.baidu.service.*;
-import com.fs.common.core.domain.R;
-import lombok.AllArgsConstructor;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
+import lombok.AllArgsConstructor;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Optional;
 
 /**
  * 百度账号Controller

+ 1 - 1
fs-admin/src/main/java/com/fs/ad/controller/MockAppController.java

@@ -1,8 +1,8 @@
 package com.fs.ad.controller;
 
-import com.fs.baidu.utils.SignService;
 import com.fs.baidu.domain.BdApi;
 import com.fs.baidu.service.IBdApiService;
+import com.fs.baidu.utils.SignService;
 import com.fs.huifuPay.sdk.opps.core.exception.BasePayException;
 import com.fs.huifuPay.sdk.opps.core.utils.HttpClientUtils;
 import lombok.extern.slf4j.Slf4j;

+ 9 - 3
fs-admin/src/main/java/com/fs/ad/controller/StatisticsController.java

@@ -1,7 +1,10 @@
 package com.fs.ad.controller;
 
 import com.fs.baidu.api.BaiduApis;
+import com.fs.baidu.domain.BdAccount;
+import com.fs.baidu.domain.BdApi;
 import com.fs.baidu.enums.BdTimeUnit;
+import com.fs.baidu.mapper.BdApiMapper;
 import com.fs.baidu.param.QueryReportDataParam;
 import com.fs.baidu.service.IBdAccountService;
 import com.fs.bdAdv.param.FsAdvSemStatisticsByDayParam;
@@ -14,7 +17,6 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.qw.param.ConversionStatisticsParam;
 import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
@@ -30,6 +32,7 @@ public class StatisticsController extends BaseController {
     private final IFsAdvSemService fsAdvSemService;
     private final IBdAccountService bdAccountService;
     private final BaiduApis baiduApis;
+    private final BdApiMapper bdApiMapper;
 
     @GetMapping("/conversionStatistics")
     public R conversionStatistics(ConversionStatisticsParam param){
@@ -65,8 +68,11 @@ public class StatisticsController extends BaseController {
         param.setEndDate(endDate);
         param.setPage(page);
         param.setRowCount(rowCount);
-        param.setTimeUnit(BdTimeUnit.DAY);
-        return baiduApis.getReportData(bdAccountService.getById(id), param);
+        param.setTimeUnit(BdTimeUnit.SUMMARY);
+        BdAccount account = bdAccountService.getById(id);
+        BdApi byId = bdApiMapper.selectById(account.getApiId());
+        return baiduApis.getReportData(byId.getAccessToken(), account.getAccountName(), param);
+//        return R.ok();
     }
 
     @GetMapping("/bdDataStatic")

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

@@ -0,0 +1,197 @@
+package com.fs.api.controller;
+
+import com.fs.common.core.domain.R;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.statis.StatisticsRedisConstant;
+import com.fs.statis.dto.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.fs.statis.StatisticsRedisConstant.*;
+
+/**
+ * 首页-统计
+ */
+@RestController
+@RequestMapping("/index/statistics")
+public class IndexStatisticsController {
+    @Autowired
+    private RedisCache redisCache;
+    /**
+     * 分析概览
+     */
+    @PostMapping("/analysisPreview")
+    public R analysisPreview(@RequestBody AnalysisPreviewQueryDTO param){
+        AnalysisPreviewDTO analysisPreviewDTO = null;
+        Integer type = param.getType();
+        Integer userType = param.getUserType();
+
+        if(type == null) {
+            type = 0;
+        }
+
+        if(userType == null) {
+            userType = 0;
+        }
+        analysisPreviewDTO = redisCache.getCacheObject(String.format("%s:%d:%d",DATA_OVERVIEW_DEALER_ANALYSISPREVIEW,type,userType));
+
+        return R.ok().put("data",analysisPreviewDTO);
+    }
+
+
+    /**
+     * 消费余额
+     */
+    @GetMapping("/rechargeComsumption")
+    public R rechargeComsumption(){
+        ConsumptionBalanceDataDTO consumptionBalanceDataDTO = redisCache.getCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_BALANCE);
+
+        return R.ok().put("data", consumptionBalanceDataDTO);
+    }
+
+    /**
+     * 获取统计流量
+     * @return
+     */
+    @GetMapping("/trafficLog")
+    public R getTrafficLog(){
+        TrafficLogDTO trafficLogDTO = redisCache.getCacheObject(DATA_OVERVIEW_TRAFFIC_LOG);
+        return R.ok().put("data",trafficLogDTO);
+    }
+
+    /**
+     * 观看趋势
+     */
+    @PostMapping("/watchEndPlayTrend")
+    public R watchEndPlayTrend(@RequestBody AnalysisPreviewQueryDTO param){
+        Integer type = param.getType();
+        Integer userType = param.getUserType();
+
+        if(type == null) {
+            type = 0;
+        }
+        if(userType == null){
+            userType = 0;
+        }
+        String key = String.format("%s:%d:%d", DATA_OVERVIEW_DEALER_CHARTS, type,userType);
+        List<DeaMemberTopTenDTO> deaMemberTopTenDTOS = redisCache.getCacheObject(key);
+        return R.ok().put("data", deaMemberTopTenDTOS);
+    }
+
+    /**
+     * 经销商会员观看
+     */
+    @PostMapping("/deaMemberTopTen")
+    public R deaMemberTopTen(@RequestBody AnalysisPreviewQueryDTO param){
+        Integer type = param.getType();
+        Integer statisticalType = param.getStatisticalType();
+        Integer userType = param.getUserType();
+
+        if(type == null) {
+            type = 0;
+        }
+        if(userType == null){
+            userType = 0;
+        }
+
+        List<DeaMemberTopTenDTO> deaMemberTopTenDTOS = redisCache.getCacheObject(String.format("%s:%d:%d:%d", CHARTS_MEMBER_TOP_TEN_WATCH, type, statisticalType,userType));
+        if(deaMemberTopTenDTOS == null){
+            deaMemberTopTenDTOS = new ArrayList<>();
+        }
+        return R.ok().put("data", deaMemberTopTenDTOS);
+    }
+
+    /**
+     * 奖励金额top10
+     */
+    @PostMapping("/rewardMoneyTopTen")
+    public R rewardMoneyTopTen(@RequestBody AnalysisPreviewQueryDTO param){
+        Integer type = param.getType();
+        Integer dataType = param.getDataType();
+        Integer userType = param.getUserType();
+
+        List<RewardMoneyTopTenDTO> rewardMoneyTopTenDTOS = redisCache.getCacheObject( String.format("%s:%d:%d:%d", CHARTS_REWARD_MONEY_TOP_TEN, type,dataType,userType));
+        return R.ok().put("data", rewardMoneyTopTenDTOS);
+    }
+
+    /**
+     * 答题红包金额趋势图
+     */
+    @PostMapping("/rewardMoneyTrend")
+    public R rewardMoneyTrend(@RequestBody AnalysisPreviewQueryDTO param){
+        Integer type = param.getType();
+        Integer userType = param.getUserType();
+        List<RewardMoneyTrendDTO> rewardMoneyTrendDTOS = redisCache.getCacheObject( String.format("%s:%d:%d", CHARTS_REWARD_MONEY_TREND, type,userType));
+        return R.ok().put("data", rewardMoneyTrendDTOS);
+    }
+
+    /**
+     * 课程观看top10
+     */
+    @PostMapping("/watchCourseTopTen")
+    public R watchCourseTopTen(@RequestBody AnalysisPreviewQueryDTO param){
+        Integer type = param.getType();
+        String sort = param.getSort();
+        Integer statisticalType = param.getStatisticalType();
+        Integer userType = param.getUserType();
+
+        List<CourseStatsDTO> courseStatsDTOS = redisCache.getCacheObject(String.format("%s:%d:%d:%d:%s", CHARTS_WATCH_TOP_TEN, type,statisticalType,userType,sort));
+        return R.ok().put("data", courseStatsDTOS);
+    }
+
+    /**
+     * 数据概览
+     */
+    @GetMapping("/dealerAggregated")
+    public R dealerAggregated(){
+        DealerAggregatedDTO dealerAggregatedDTO = redisCache.getCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_AGGREGATED);
+
+        return R.ok().put("data",dealerAggregatedDTO);
+    }
+
+    /**
+     * 短信余额
+     */
+    @GetMapping("/smsBalance")
+    public R smsBalance(){
+        Long smsBalance = redisCache.getCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_SMS_BALANCE);
+
+        return R.ok().put("data", smsBalance);
+    }
+
+
+    /**
+     * 授权信息
+     */
+    @GetMapping("/authorizationInfo")
+    public R authorizationInfo(){
+        AuthorizationInfoDTO authorizationInfoDTO = redisCache.getCacheObject(StatisticsRedisConstant.DATA_OVERVIEW_DEALER_AUTHORIZATION_INFO);
+
+        return R.ok().put("data", authorizationInfoDTO);
+    }
+
+
+    /**
+     * 当月订单数统计
+     * @return
+     */
+    @GetMapping("/thisMonthOrderCount")
+    public R thisMonthOrderCount(){
+        R result = redisCache.getCacheObject(StatisticsRedisConstant.THIS_MONTH_ORDER_COUNT);
+        return result;
+    }
+
+    /**
+     * 当月收益统计
+     * @return
+     */
+
+    @GetMapping("/thisMonthRecvCount")
+    public R thisMonthRecvCount(){
+        R result = redisCache.getCacheObject(StatisticsRedisConstant.THIS_MONTH_RECV_COUNT);
+        return result;
+    }
+}

+ 20 - 1
fs-admin/src/main/java/com/fs/company/controller/CompanyUserController.java

@@ -109,7 +109,12 @@ public class CompanyUserController extends BaseController
         List<CompanyUser> list = companyUserService.selectCompanyUserList(map);
         return R.ok().put("data",list);
     }
-
+    @GetMapping("/getAllUserListLimit")
+    public R getAllUserListLimit(@RequestParam(required = false) Long companyId,
+                                 @RequestParam(required = false) String keywords){
+        List<CompanyUser> list = companyUserService.getAllUserListLimit(companyId,keywords);
+        return R.ok().put("data", list);
+    }
     @GetMapping("/getUserListByDeptId")
     public R getUserListByDeptId(CompanyUser user)
     {
@@ -117,4 +122,18 @@ public class CompanyUserController extends BaseController
         List<CompanyUser> list = companyUserService.getUserListByDeptId(user);
         return R.ok().put("data",list);
     }
+
+    /**
+     * 获取所有的销售列表
+     * @param companyId
+     * @return
+     */
+    @GetMapping("/getUserList")
+    public R getUserList(@RequestParam("companyId") Long companyId)
+    {
+        CompanyUser map=new CompanyUser();
+        map.setCompanyId(companyId);
+        List<CompanyUser> list = companyUserService.selectCompanyUserList(map);
+        return  R.ok().put("data",list);
+    }
 }

+ 100 - 0
fs-admin/src/main/java/com/fs/course/controller/FsCourseFinishTempController.java

@@ -0,0 +1,100 @@
+package com.fs.course.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.domain.FsCourseFinishTemp;
+import com.fs.course.service.IFsCourseFinishTempService;
+import com.fs.course.vo.FsCourseFinishTempListVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 完课模板Controller
+ *
+ * @author fs
+ * @date 2024-12-19
+ */
+@RestController
+@RequestMapping("/course/courseFinishTemp")
+public class FsCourseFinishTempController extends BaseController
+{
+    @Autowired
+    private IFsCourseFinishTempService fsCourseFinishTempService;
+
+    /**
+     * 查询完课模板列表
+     */
+    @PreAuthorize("@ss.hasPermi('courseFinishTemp:course:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsCourseFinishTemp fsCourseFinishTemp)
+    {
+        startPage();
+        List<FsCourseFinishTempListVO> list = fsCourseFinishTempService.selectFsCourseFinishTempListVO(fsCourseFinishTemp);
+        return getDataTable(list);
+    }
+
+
+    /**
+     * 导出完课模板列表
+     */
+    @PreAuthorize("@ss.hasPermi('courseFinishTemp:course:export')")
+    @Log(title = "完课模板", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsCourseFinishTemp fsCourseFinishTemp)
+    {
+        List<FsCourseFinishTemp> list = fsCourseFinishTempService.selectFsCourseFinishTempList(fsCourseFinishTemp);
+        ExcelUtil<FsCourseFinishTemp> util = new ExcelUtil<FsCourseFinishTemp>(FsCourseFinishTemp.class);
+        return util.exportExcel(list, "完课模板数据");
+    }
+
+    /**
+     * 获取完课模板详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('courseFinishTemp:course:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+//        return AjaxResult.success(fsCourseFinishTempService.selectFsCourseFinishTempById(id));
+        return AjaxResult.success(fsCourseFinishTempService.selectFsCourseFinishTempByIdVO(id));
+    }
+
+    /**
+     * 新增完课模板
+     */
+    @PreAuthorize("@ss.hasPermi('courseFinishTemp:course:add')")
+    @Log(title = "完课模板", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsCourseFinishTemp fsCourseFinishTemp)
+    {
+        return toAjax(fsCourseFinishTempService.insertFsCourseFinishTemp(fsCourseFinishTemp));
+    }
+
+    /**
+     * 修改完课模板
+     */
+    @PreAuthorize("@ss.hasPermi('courseFinishTemp:course:edit')")
+    @Log(title = "完课模板", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsCourseFinishTemp fsCourseFinishTemp)
+    {
+        return toAjax(fsCourseFinishTempService.updateFsCourseFinishTemp(fsCourseFinishTemp));
+    }
+
+    /**
+     * 删除完课模板
+     */
+    @PreAuthorize("@ss.hasPermi('courseFinishTemp:course:remove')")
+    @Log(title = "完课模板", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsCourseFinishTempService.deleteFsCourseFinishTempByIds(ids));
+    }
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/course/controller/FsCourseFinishTempParentController.java

@@ -0,0 +1,97 @@
+package com.fs.course.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.domain.FsCourseFinishTempParent;
+import com.fs.course.service.IFsCourseFinishTempParentService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 完课模板Controller
+ * 
+ * @author 吴树波
+ * @date 2025-05-22
+ */
+@RestController
+@RequestMapping("/course/courseFinishTempParent")
+public class FsCourseFinishTempParentController extends BaseController
+{
+    @Autowired
+    private IFsCourseFinishTempParentService fsCourseFinishTempParentService;
+
+    /**
+     * 查询完课模板列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseFinishTempParent:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsCourseFinishTempParent fsCourseFinishTempParent)
+    {
+        startPage();
+        List<FsCourseFinishTempParent> list = fsCourseFinishTempParentService.selectFsCourseFinishTempParentList(fsCourseFinishTempParent);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出完课模板列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseFinishTempParent:export')")
+    @Log(title = "完课模板", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsCourseFinishTempParent fsCourseFinishTempParent)
+    {
+        List<FsCourseFinishTempParent> list = fsCourseFinishTempParentService.selectFsCourseFinishTempParentList(fsCourseFinishTempParent);
+        ExcelUtil<FsCourseFinishTempParent> util = new ExcelUtil<FsCourseFinishTempParent>(FsCourseFinishTempParent.class);
+        return util.exportExcel(list, "完课模板数据");
+    }
+
+    /**
+     * 获取完课模板详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseFinishTempParent:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsCourseFinishTempParentService.selectFsCourseFinishTempParentById(id));
+    }
+
+    /**
+     * 新增完课模板
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseFinishTempParent:add')")
+    @Log(title = "完课模板", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsCourseFinishTempParent fsCourseFinishTempParent){
+
+        return toAjax(fsCourseFinishTempParentService.insertFsCourseFinishTempParent(fsCourseFinishTempParent));
+    }
+
+    /**
+     * 修改完课模板
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseFinishTempParent:edit')")
+    @Log(title = "完课模板", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsCourseFinishTempParent fsCourseFinishTempParent)
+    {
+        return toAjax(fsCourseFinishTempParentService.updateFsCourseFinishTempParent(fsCourseFinishTempParent));
+    }
+
+    /**
+     * 删除完课模板
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseFinishTempParent:remove')")
+    @Log(title = "完课模板", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsCourseFinishTempParentService.deleteFsCourseFinishTempParentByIds(ids));
+    }
+}

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

@@ -55,8 +55,8 @@ public class FsCourseQuestionBankController extends BaseController
     @GetMapping("/export")
     public AjaxResult export(FsCourseQuestionBank fsCourseQuestionBank)
     {
-        List<FsCourseQuestionBank> list = fsCourseQuestionBankService.selectFsCourseQuestionBankList(fsCourseQuestionBank);
-        ExcelUtil<FsCourseQuestionBank> util = new ExcelUtil<FsCourseQuestionBank>(FsCourseQuestionBank.class);
+        List<FsCourseQuestionBankImportDTO> list = fsCourseQuestionBankService.exportData(fsCourseQuestionBank);
+        ExcelUtil<FsCourseQuestionBankImportDTO> util = new ExcelUtil<>(FsCourseQuestionBankImportDTO.class);
         return util.exportExcel(list, "题库数据");
     }
 

+ 3 - 0
fs-admin/src/main/java/com/fs/course/controller/FsCourseTrafficLogController.java

@@ -1,10 +1,13 @@
 package com.fs.course.controller;
 
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.List;
 
+import com.fs.common.exception.CustomException;
 import com.fs.course.param.FsCourseTrafficLogParam;
 import com.fs.course.vo.FsCourseTrafficLogListVO;
+import com.fs.qw.param.QwWatchLogStatisticsListParam;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;

+ 128 - 0
fs-admin/src/main/java/com/fs/course/controller/FsCourseWatchCommentController.java

@@ -0,0 +1,128 @@
+package com.fs.course.controller;
+
+import java.util.List;
+
+import com.fs.common.core.domain.R;
+import com.fs.course.param.FsCourseWatchCommentPageParam;
+import com.fs.course.vo.FsCourseWatchCommentListVO;
+import com.fs.qw.service.IQwExternalContactService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.course.domain.FsCourseWatchComment;
+import com.fs.course.service.IFsCourseWatchCommentService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 看课评论Controller
+ *
+ * @author fs
+ * @date 2025-05-26
+ */
+@RestController
+@RequestMapping("/course/courseWatchComment")
+public class FsCourseWatchCommentController extends BaseController
+{
+    @Autowired
+    private IFsCourseWatchCommentService fsCourseWatchCommentService;
+
+    @Autowired
+    private IQwExternalContactService qwExternalContactService;
+
+    /**
+     * 查询看课评论列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchComment:list')")
+    @GetMapping("/list")
+    public R list(FsCourseWatchCommentPageParam fsCourseWatchCommentPageParam)
+    {
+//        startPage();
+        PageHelper.startPage(fsCourseWatchCommentPageParam.getPageNum(), fsCourseWatchCommentPageParam.getPageSize());
+        List<FsCourseWatchCommentListVO> list = fsCourseWatchCommentService.selectFsCourseWatchCommentList(fsCourseWatchCommentPageParam);
+        PageInfo<FsCourseWatchCommentListVO> pageInfo = new PageInfo<>(list);
+        return R.ok().put("rows", pageInfo);
+    }
+
+    /**
+     * 导出看课评论列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchComment:export')")
+    @Log(title = "看课评论", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsCourseWatchCommentPageParam fsCourseWatchCommentPageParam)
+    {
+        List<FsCourseWatchCommentListVO> list = fsCourseWatchCommentService.selectFsCourseWatchCommentList(fsCourseWatchCommentPageParam);
+        ExcelUtil<FsCourseWatchCommentListVO> util = new ExcelUtil<FsCourseWatchCommentListVO>(FsCourseWatchCommentListVO.class);
+        return util.exportExcel(list, "看课评论数据");
+    }
+
+    /**
+     * 获取看课评论详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchComment:query')")
+    @GetMapping(value = "/{commentId}")
+    public AjaxResult getInfo(@PathVariable("commentId") Long commentId)
+    {
+        return AjaxResult.success(fsCourseWatchCommentService.selectFsCourseWatchCommentByCommentId(commentId));
+    }
+
+    /**
+     * 新增看课评论
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchComment:add')")
+    @Log(title = "看课评论", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsCourseWatchComment fsCourseWatchComment)
+    {
+        return toAjax(fsCourseWatchCommentService.insertFsCourseWatchComment(fsCourseWatchComment));
+    }
+
+    /**
+     * 修改看课评论
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchComment:edit')")
+    @Log(title = "看课评论", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsCourseWatchComment fsCourseWatchComment)
+    {
+        return toAjax(fsCourseWatchCommentService.updateFsCourseWatchComment(fsCourseWatchComment));
+    }
+
+    /**
+     * 删除看课评论
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchComment:remove')")
+    @Log(title = "看课评论", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{commentIds}")
+    public AjaxResult remove(@PathVariable Long[] commentIds)
+    {
+        return toAjax(fsCourseWatchCommentService.deleteFsCourseWatchCommentByCommentIds(commentIds));
+    }
+
+    @Log(title = "手动拉黑外部联系人用户", businessType = BusinessType.UPDATE)
+    @PutMapping("/addBlack")
+    public R addBlack(Integer commentStatus, Long fsUserId)
+    {
+        int i = qwExternalContactService.updateQwExternalContactByFsUserId(commentStatus, fsUserId);
+        if (i > 0){
+            return R.ok();
+        } else {
+            return R.error();
+        }
+    }
+
+}

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

@@ -1,9 +1,16 @@
 package com.fs.course.controller;
 
+import java.util.ArrayList;
 import java.util.List;
 
+import com.fs.common.constant.HttpStatus;
+import com.fs.common.exception.CustomException;
 import com.fs.course.param.FsCourseWatchLogListParam;
+import com.fs.course.param.FsCourseWatchLogStatisticsListParam;
 import com.fs.course.vo.FsCourseWatchLogListVO;
+import com.fs.course.vo.FsCourseWatchLogStatisticsListVO;
+import com.fs.qw.param.QwWatchLogStatisticsListParam;
+import com.fs.qw.service.IQwWatchLogService;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -36,6 +43,8 @@ public class FsCourseWatchLogController extends BaseController
     @Autowired
     private IFsCourseWatchLogService fsCourseWatchLogService;
 
+    @Autowired
+    private IQwWatchLogService qwWatchLogService;
     /**
      * 查询短链课程看课记录列表
      */
@@ -48,6 +57,58 @@ public class FsCourseWatchLogController extends BaseController
         return getDataTable(list);
     }
 
+    @GetMapping("/qwWatchLogAllStatisticsList")
+    public TableDataInfo qwWatchLogAllStatisticsList(QwWatchLogStatisticsListParam param)
+    {
+        logger.info("会员课程数据汇总 参数: {}",param);
+
+        if(param.getCompanyId() == null){
+            throw new CustomException("必须选择公司!");
+        }
+        if (param.getSTime()==null||param.getETime()==null){
+            return getDataTable(new ArrayList<>());
+        }
+        return qwWatchLogService.selectQwWatchLogAllStatisticsListVONew(param);
+    }
+    @GetMapping("/qwWatchLogStatisticsList")
+    public TableDataInfo qwWatchLogStatisticsList(QwWatchLogStatisticsListParam param)
+    {
+        if(param.getPageNum() == null){
+            param.setPageNum(1L);
+        }
+        if(param.getPageSize() == null){
+            param.setPageSize(10L);
+        }
+        if (param.getSTime()==null||param.getETime()==null){
+            return getDataTable(new ArrayList<>());
+        }
+        if(param.getCompanyId() == null){
+            throw new CustomException("必须选择公司!");
+        }
+        return qwWatchLogService.selectQwWatchLogStatisticsListVONew(param);
+    }
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:statisticsList')")
+    @GetMapping("/statisticsList")
+    public TableDataInfo statisticsList(FsCourseWatchLogStatisticsListParam param)
+    {
+        // 如果看指定用户就不用设置公司
+        if(param.getCompanyId() == null){
+            if(param.getUserId() == null) {
+                throw new CustomException("查看公司或者用户必填!");
+            }
+        }
+        if (param.getSTime()==null||param.getETime()==null){
+            throw new CustomException("必须选择开始时间和结束时间!");
+        }
+        List<FsCourseWatchLogStatisticsListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogStatisticsListVONew(param);
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(HttpStatus.SUCCESS);
+        rspData.setMsg("查询成功");
+        rspData.setRows(list);
+        rspData.setTotal(fsCourseWatchLogService.selectFsCourseWatchLogStatisticsListVONewCount(param));
+        return rspData;
+    }
+
     /**
      * 导出短链课程看课记录列表
      */

+ 110 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseComplaintRecordController.java

@@ -0,0 +1,110 @@
+package com.fs.course.controller;
+
+import java.util.List;
+
+import com.fs.common.core.domain.R;
+import com.fs.course.vo.FsUserCourseComplaintRecordPageListVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.course.domain.FsUserCourseComplaintRecord;
+import com.fs.course.service.IFsUserCourseComplaintRecordService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 看课投诉记录Controller
+ *
+ * @author fs
+ * @date 2025-06-04
+ */
+@RestController
+@RequestMapping("/course/userCourseComplaintRecord")
+public class FsUserCourseComplaintRecordController extends BaseController
+{
+    @Autowired
+    private IFsUserCourseComplaintRecordService fsUserCourseComplaintRecordService;
+
+    /**
+     * 查询看课投诉记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourseComplaintRecord:list')")
+    @GetMapping("/list")
+    public R list(FsUserCourseComplaintRecord fsUserCourseComplaintRecord)
+    {
+//        startPage();
+        PageHelper.startPage(fsUserCourseComplaintRecord.getPageNum(), fsUserCourseComplaintRecord.getPageSize());
+        List<FsUserCourseComplaintRecordPageListVO> list = fsUserCourseComplaintRecordService.selectFsUserCourseComplaintRecordList(fsUserCourseComplaintRecord);
+        PageInfo<FsUserCourseComplaintRecordPageListVO> pageInfo = new PageInfo<>(list);
+        return R.ok().put("rows", pageInfo);
+    }
+
+    /**
+     * 导出看课投诉记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourseComplaintRecord:export')")
+    @Log(title = "看课投诉记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsUserCourseComplaintRecord fsUserCourseComplaintRecord)
+    {
+        List<FsUserCourseComplaintRecordPageListVO> list = fsUserCourseComplaintRecordService.selectFsUserCourseComplaintRecordList(fsUserCourseComplaintRecord);
+        ExcelUtil<FsUserCourseComplaintRecordPageListVO> util = new ExcelUtil<>(FsUserCourseComplaintRecordPageListVO.class);
+        return util.exportExcel(list, "看课投诉记录");
+    }
+
+    /**
+     * 获取看课投诉记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourseComplaintRecord:query')")
+    @GetMapping(value = "/{recordId}")
+    public AjaxResult getInfo(@PathVariable("recordId") Long recordId)
+    {
+        return AjaxResult.success(fsUserCourseComplaintRecordService.selectFsUserCourseComplaintRecordByRecordId(recordId));
+    }
+
+    /**
+     * 新增看课投诉记录
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourseComplaintRecord:add')")
+    @Log(title = "看课投诉记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsUserCourseComplaintRecord fsUserCourseComplaintRecord)
+    {
+        return toAjax(fsUserCourseComplaintRecordService.insertFsUserCourseComplaintRecord(fsUserCourseComplaintRecord));
+    }
+
+    /**
+     * 修改看课投诉记录
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourseComplaintRecord:edit')")
+    @Log(title = "看课投诉记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsUserCourseComplaintRecord fsUserCourseComplaintRecord)
+    {
+        return toAjax(fsUserCourseComplaintRecordService.updateFsUserCourseComplaintRecord(fsUserCourseComplaintRecord));
+    }
+
+    /**
+     * 删除看课投诉记录
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourseComplaintRecord:remove')")
+    @Log(title = "看课投诉记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{recordIds}")
+    public AjaxResult remove(@PathVariable Long[] recordIds)
+    {
+        return toAjax(fsUserCourseComplaintRecordService.deleteFsUserCourseComplaintRecordByRecordIds(recordIds));
+    }
+}

+ 101 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseComplaintTypeController.java

@@ -0,0 +1,101 @@
+package com.fs.course.controller;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.course.domain.FsUserCourseComplaintType;
+import com.fs.course.service.IFsUserCourseComplaintTypeService;
+import com.fs.common.utils.poi.ExcelUtil;
+
+/**
+ * 看课投诉类型Controller
+ * 
+ * @author fs
+ * @date 2025-06-04
+ */
+@RestController
+@RequestMapping("/course/userCourseComplaintType")
+public class FsUserCourseComplaintTypeController extends BaseController
+{
+    @Autowired
+    private IFsUserCourseComplaintTypeService fsUserCourseComplaintTypeService;
+
+    /**
+     * 查询看课投诉类型列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourseComplaintType:list')")
+    @GetMapping("/list")
+    public AjaxResult list(FsUserCourseComplaintType fsUserCourseComplaintType)
+    {
+        List<FsUserCourseComplaintType> list = fsUserCourseComplaintTypeService.selectFsUserCourseComplaintTypeList(fsUserCourseComplaintType);
+        return AjaxResult.success(list);
+    }
+
+    /**
+     * 导出看课投诉类型列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourseComplaintType:export')")
+    @Log(title = "看课投诉类型", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsUserCourseComplaintType fsUserCourseComplaintType)
+    {
+        List<FsUserCourseComplaintType> list = fsUserCourseComplaintTypeService.selectFsUserCourseComplaintTypeList(fsUserCourseComplaintType);
+        ExcelUtil<FsUserCourseComplaintType> util = new ExcelUtil<FsUserCourseComplaintType>(FsUserCourseComplaintType.class);
+        return util.exportExcel(list, "看课投诉类型数据");
+    }
+
+    /**
+     * 获取看课投诉类型详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourseComplaintType:query')")
+    @GetMapping(value = "/{complaintTypeId}")
+    public AjaxResult getInfo(@PathVariable("complaintTypeId") Long complaintTypeId)
+    {
+        return AjaxResult.success(fsUserCourseComplaintTypeService.selectFsUserCourseComplaintTypeByComplaintTypeId(complaintTypeId));
+    }
+
+    /**
+     * 新增看课投诉类型
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourseComplaintType:add')")
+    @Log(title = "看课投诉类型", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsUserCourseComplaintType fsUserCourseComplaintType)
+    {
+        return toAjax(fsUserCourseComplaintTypeService.insertFsUserCourseComplaintType(fsUserCourseComplaintType));
+    }
+
+    /**
+     * 修改看课投诉类型
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourseComplaintType:edit')")
+    @Log(title = "看课投诉类型", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsUserCourseComplaintType fsUserCourseComplaintType)
+    {
+        return toAjax(fsUserCourseComplaintTypeService.updateFsUserCourseComplaintType(fsUserCourseComplaintType));
+    }
+
+    /**
+     * 删除看课投诉类型
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourseComplaintType:remove')")
+    @Log(title = "看课投诉类型", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{complaintTypeIds}")
+    public AjaxResult remove(@PathVariable Long[] complaintTypeIds)
+    {
+        return toAjax(fsUserCourseComplaintTypeService.deleteFsUserCourseComplaintTypeByComplaintTypeIds(complaintTypeIds));
+    }
+}

+ 107 - 1
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseController.java

@@ -43,7 +43,7 @@ public class FsUserCourseController extends BaseController
     /**
      * 查询课程列表
      */
-//    @PreAuthorize("@ss.hasPermi('course:userCourse:list')")
+    @PreAuthorize("@ss.hasPermi('course:userCourse:list')")
     @GetMapping("/list")
     public TableDataInfo list(FsUserCourse fsUserCourse)
     {
@@ -52,6 +52,18 @@ public class FsUserCourseController extends BaseController
         return getDataTable(list);
     }
 
+    /**
+     * 查询公域课程列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourse:publicList')")
+    @GetMapping("/publicList")
+    public TableDataInfo publicList(FsUserCourse fsUserCourse)
+    {
+        startPage();
+        List<FsUserCourseListPVO> list = fsUserCourseService.selectFsUserCourseListPVO(fsUserCourse);
+        return getDataTable(list);
+    }
+
     /**
      * 导出课程列表
      */
@@ -65,6 +77,19 @@ public class FsUserCourseController extends BaseController
         return util.exportExcel(list, "课程数据");
     }
 
+    /**
+     * 导出公域课程列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourse:publicExport')")
+    @Log(title = "课程", businessType = BusinessType.EXPORT)
+    @GetMapping("/publicExport")
+    public AjaxResult publicExport(FsUserCourse fsUserCourse)
+    {
+        List<FsUserCourse> list = fsUserCourseService.selectFsUserCourseList(fsUserCourse);
+        ExcelUtil<FsUserCourse> util = new ExcelUtil<FsUserCourse>(FsUserCourse.class);
+        return util.exportExcel(list, "课程数据");
+    }
+
     /**
      * 获取课程详细信息
      */
@@ -75,6 +100,16 @@ public class FsUserCourseController extends BaseController
         return AjaxResult.success(fsUserCourseService.selectFsUserCourseByCourseId(courseId));
     }
 
+    /**
+     * 获取公域课程详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourse:publicQuery')")
+    @GetMapping(value = "/public/{courseId}")
+    public AjaxResult publicGetInfo(@PathVariable("courseId") Long courseId)
+    {
+        return AjaxResult.success(fsUserCourseService.selectFsUserCourseByCourseId(courseId));
+    }
+
     /**
      * 新增课程
      */
@@ -89,6 +124,20 @@ public class FsUserCourseController extends BaseController
         return toAjax(1);
     }
 
+    /**
+     * 新增课程
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourse:publicAdd')")
+    @Log(title = "课程", businessType = BusinessType.INSERT)
+    @PostMapping("/public")
+    public AjaxResult publicAdd(@RequestBody FsUserCourse fsUserCourse)
+    {
+        fsUserCourseService.insertFsUserCourse(fsUserCourse);
+        redisCacheUtil.delRedisKey("getCourseList");
+
+        return toAjax(1);
+    }
+
     /**
      * 修改课程
      */
@@ -102,6 +151,19 @@ public class FsUserCourseController extends BaseController
         return toAjax(1);
     }
 
+    /**
+     * 修改课程
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourse:publicEdit')")
+    @Log(title = "课程", businessType = BusinessType.UPDATE)
+    @PutMapping("/public")
+    public AjaxResult publicEdit(@RequestBody FsUserCourse fsUserCourse)
+    {
+        fsUserCourseService.updateFsUserCourse(fsUserCourse);
+        redisCacheUtil.delRedisKey("getCourseList");
+        return toAjax(1);
+    }
+
     /**
      * 删除课程
      */
@@ -115,6 +177,19 @@ public class FsUserCourseController extends BaseController
         return toAjax(1);
     }
 
+    /**
+     * 删除课程
+     */
+    @PreAuthorize("@ss.hasPermi('course:userCourse:publicRemove')")
+    @Log(title = "课程", businessType = BusinessType.DELETE)
+    @DeleteMapping("/public/{courseIds}")
+    public AjaxResult publicRemove(@PathVariable Long[] courseIds)
+    {
+        fsUserCourseService.deleteFsUserCourseByCourseIds(courseIds);
+        redisCacheUtil.delRedisKey("getCourseList");
+        return toAjax(1);
+    }
+
 
     @GetMapping("/getAllList")
     public R getAllList()
@@ -123,6 +198,7 @@ public class FsUserCourseController extends BaseController
         return R.ok().put("data", list);
     }
 
+    @PreAuthorize("@ss.hasPermi('course:userCourse:updateIsShow')")
     @Log(title = "课程上架", businessType = BusinessType.UPDATE)
     @PostMapping("/updateIsShow")
     public AjaxResult updateIsShow(@RequestBody FsUserCourse fsUserCourse)
@@ -132,6 +208,16 @@ public class FsUserCourseController extends BaseController
        return toAjax(1);
     }
 
+    @PreAuthorize("@ss.hasPermi('course:userCourse:publicUpdateIsShow')")
+    @Log(title = "课程上架", businessType = BusinessType.UPDATE)
+    @PostMapping("/publicUpdateIsShow")
+    public AjaxResult publicUpdateIsShow(@RequestBody FsUserCourse fsUserCourse)
+    {
+        fsUserCourseService.updateFsUserCourse(fsUserCourse);
+        redisCacheUtil.delRedisKey("getCourseList");
+        return toAjax(1);
+    }
+
     @PreAuthorize("@ss.hasPermi('course:userCourse:putOn')")
     @Log(title = "课程批量上架", businessType = BusinessType.UPDATE)
     @PostMapping("/putOn/{courseIds}")
@@ -142,6 +228,16 @@ public class FsUserCourseController extends BaseController
         return toAjax(1);
     }
 
+    @PreAuthorize("@ss.hasPermi('course:userCourse:publicPutOn')")
+    @Log(title = "课程批量上架", businessType = BusinessType.UPDATE)
+    @PostMapping("/publicPutOn/{courseIds}")
+    public AjaxResult publicPutOn(@PathVariable Long[] courseIds)
+    {
+        fsUserCourseService.updateFsUserCourseIsShow(courseIds,1);
+        redisCacheUtil.delRedisKey("getCourseList");
+        return toAjax(1);
+    }
+
     @PreAuthorize("@ss.hasPermi('course:userCourse:putOn')")
     @Log(title = "课程批量下架", businessType = BusinessType.UPDATE)
     @PostMapping("/pullOff/{courseIds}")
@@ -151,4 +247,14 @@ public class FsUserCourseController extends BaseController
         redisCacheUtil.delRedisKey("getCourseList");
         return toAjax(1);
     }
+
+    @PreAuthorize("@ss.hasPermi('course:userCourse:publicPutOff')")
+    @Log(title = "课程批量下架", businessType = BusinessType.UPDATE)
+    @PostMapping("/publicPutOff/{courseIds}")
+    public AjaxResult publicPutOff(@PathVariable Long[] courseIds)
+    {
+        fsUserCourseService.updateFsUserCourseIsShow(courseIds,0);
+        redisCacheUtil.delRedisKey("getCourseList");
+        return toAjax(1);
+    }
 }

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

@@ -61,6 +61,7 @@ public class FsUserCoursePeriodController extends BaseController {
         return getDataTable(list);
     }
 
+    @PreAuthorize("@ss.hasPermi('course:period:list')")
     @PostMapping("/page")
     @ApiOperation("自定义查询主列表分页")
     public R pageList(@RequestBody FsUserCoursePeriod fsUserCoursePeriod)
@@ -94,8 +95,7 @@ public class FsUserCoursePeriodController extends BaseController {
      */
     @PreAuthorize("@ss.hasPermi('course:period:query')")
     @GetMapping(value = "/{periodId}")
-    public AjaxResult getInfo(@PathVariable("periodId") Long periodId)
-    {
+    public AjaxResult getInfo(@PathVariable("periodId") Long periodId) {
         return AjaxResult.success(fsUserCoursePeriodService.selectFsUserCoursePeriodById(periodId));
     }
 
@@ -133,16 +133,25 @@ public class FsUserCoursePeriodController extends BaseController {
     }
 
     @GetMapping("/getDays")
-    public TableDataInfo getDays(FsUserCoursePeriodDays fsUserCoursePeriodDays){
-        startPage();
+    public R getDays(FsUserCoursePeriodDays fsUserCoursePeriodDays){
+//        startPage();
+        PageHelper.startPage(fsUserCoursePeriodDays.getPageNum(), fsUserCoursePeriodDays.getPageSize());
         List<FsUserCoursePeriodDays> list = fsUserCoursePeriodDaysService.selectFsUserCoursePeriodDaysList(fsUserCoursePeriodDays);
-        return getDataTable(list);
+
+        PageInfo<FsUserCoursePeriodDays> pageInfo = new PageInfo<>(list);
+        Map<String, Object> result = new HashMap<>();
+        result.put("rows", pageInfo.getList());
+        result.put("total", pageInfo.getTotal());
+        return R.ok(result);
     }
 
+    @PreAuthorize("@ss.hasPermi('course:period:addCourse')")
     @PostMapping("/addCourse")
     public R addCourse(@RequestBody FsUserCoursePeriodDays entity){
         return fsUserCoursePeriodDaysService.addCourse(entity);
     }
+
+    @PreAuthorize("@ss.hasPermi('course:period:updateCourseTime')")
     @PostMapping("/updateCourseTime")
     public R updateCourseTime(@RequestBody UpdateCourseTimeVo vo){
         return fsUserCoursePeriodDaysService.updateCourseTime(vo);
@@ -170,6 +179,7 @@ public class FsUserCoursePeriodController extends BaseController {
         return R.ok().put("data", periodRedPacketList);
     }
 
+    @PreAuthorize("@ss.hasPermi('course:period:setCourseRedPacket')")
     @ApiOperation("按课程批量保存设置红包金额")
     @PostMapping("/batchRedPacket")
     public R batchRedPacketMoney(@RequestBody List<FsUserCourseVideoRedPackage> videoRedPackageList) {
@@ -182,6 +192,7 @@ public class FsUserCoursePeriodController extends BaseController {
         return R.ok();
     }
 
+    @PreAuthorize("@ss.hasPermi('course:period:setRedPacket')")
     @ApiOperation("按营期批量保存设置红包金额")
     @PostMapping("/batchRedPacket/byPeriod")
     public R batchRedPacketByPeriod(@RequestBody List<FsBatchPeriodRedPackageParam> periodRedPackageList) {
@@ -220,12 +231,14 @@ public class FsUserCoursePeriodController extends BaseController {
         return R.ok().put("data", new PageInfo<>(periodList));
     }
 
+    @PreAuthorize("@ss.hasPermi('course:period:courseMove')")
     @ApiOperation("营期课程-上移/下移")
     @PutMapping("/courseMove")
     public R periodCourseMove(Long id, Long targetId) {
         return fsUserCoursePeriodDaysService.periodCourseMove(id, targetId);
     }
 
+    @PreAuthorize("@ss.hasPermi('course:period:close')")
     @ApiOperation("结束营期")
     @PostMapping("/closePeriod")
     public R closePeriod(Long id) {

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

@@ -99,7 +99,7 @@ public class FsUserCourseTrainingCampController {
      * @param id    参数
      * @return  AjaxResult
      */
-    @PreAuthorize("@ss.hasPermi('course:trainingCamp:add')")
+    @PreAuthorize("@ss.hasPermi('course:trainingCamp:copy')")
     @Log(title = "训练营", businessType = BusinessType.INSERT)
     @PostMapping("/copy/{id}")
     public AjaxResult copy(@PathVariable Long id) {

+ 48 - 18
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseVideoController.java

@@ -1,29 +1,28 @@
 package com.fs.course.controller;
 
-import java.util.List;
-
-import com.fs.common.core.domain.R;
-import com.fs.course.domain.FsUserVideo;
-import com.fs.course.mapper.FsUserCourseVideoMapper;
-import com.fs.course.service.IFsUserCourseService;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.course.domain.FsUserCourseVideo;
+import com.fs.course.mapper.FsUserCourseVideoMapper;
+import com.fs.course.param.BatchRedUpdate;
+import com.fs.course.param.BatchVideoSvae;
+import com.fs.course.param.CourseVideoUpdates;
 import com.fs.course.service.IFsUserCourseVideoService;
-import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
+import com.fs.his.vo.OptionsVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
  * 课堂视频Controller
@@ -127,4 +126,35 @@ public class FsUserCourseVideoController extends BaseController
     {
         return R.ok().put("data",fsUserCourseVideoService.selectCourseVideoSort(courseId));
     }
+
+    @PostMapping("/updates")
+    public R updates(@RequestBody CourseVideoUpdates vo){
+        fsUserCourseVideoService.updates(vo);
+        return R.ok();
+    }
+    @PostMapping("/batchSaveVideo")
+    public R batchSaveVideo(@RequestBody BatchVideoSvae vo){
+        fsUserCourseVideoService.batchSaveVideo(vo);
+        return R.ok();
+    }
+    @PostMapping("/batchUpdateRed")
+    public R batchUpdateRed(@RequestBody List<BatchRedUpdate> list){
+        fsUserCourseVideoService.batchUpdateRed(list);
+        return R.ok();
+    }
+
+
+    @GetMapping("/getVideoListLikeName")
+    public R getVideoListLikeName(@RequestParam(required = false) String name,
+                                   @RequestParam(required = false) String periodId,
+                                   @RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                                   @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
+        Map<String,Object> params = new HashMap<>();
+        params.put("name", name);
+        params.put("periodId", periodId);
+
+        PageHelper.startPage(pageNum, pageSize);
+        List<OptionsVO> periodList = fsUserCourseVideoService.selectVideoListByMap(params);
+        return R.ok().put("data", new PageInfo<>(periodList));
+    }
 }

+ 115 - 18
fs-admin/src/main/java/com/fs/course/controller/FsUserVideoController.java

@@ -1,34 +1,38 @@
 package com.fs.course.controller;
 
-import java.io.*;
-import java.util.Date;
-import java.util.List;
-
+import com.alibaba.fastjson.JSON;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
-import com.fs.course.param.FsUserVideoAddParam;
-import com.fs.course.param.FsUserVideoAuditParam;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.domain.FsUserVideo;
+import com.fs.course.domain.FsVideoResource;
+import com.fs.course.param.*;
+import com.fs.course.service.IFsUserVideoService;
+import com.fs.course.service.IFsVideoResourceService;
+import com.fs.course.service.impl.TencentCloudCosService;
 import com.fs.course.vo.FsUserVideoListPVO;
 import com.fs.course.vo.FsUserVideoPVO;
-import com.fs.course.param.FsUserVideoParam;
 import com.fs.his.service.IFsPackageService;
 import com.fs.his.vo.FsPackageVO;
 import com.fs.system.oss.CloudStorageService;
 import com.fs.system.oss.OSSFactory;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.io.FilenameUtils;
-import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
-import com.fs.common.annotation.Log;
-import com.fs.common.core.controller.BaseController;
-import com.fs.common.core.domain.AjaxResult;
-import com.fs.common.enums.BusinessType;
-import com.fs.course.domain.FsUserVideo;
-import com.fs.course.service.IFsUserVideoService;
-import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.io.*;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
 /**
  * 课堂视频Controller
  *
@@ -42,9 +46,15 @@ public class FsUserVideoController extends BaseController
 {
     @Autowired
     private IFsUserVideoService fsUserVideoService;
+
+    @Autowired
+    private TencentCloudCosService tencentCloudCosService;
     @Autowired
     private IFsPackageService fsPackageService;
 
+    @Autowired
+    private IFsVideoResourceService iFsVideoResourceService;
+
     /**
      * 查询课堂视频列表
      */
@@ -182,7 +192,7 @@ public class FsUserVideoController extends BaseController
         }
 
         // 保存上传的视频文件
-        String videoFileName = System.currentTimeMillis() + "_" + file.getOriginalFilename();
+        String videoFileName = System.currentTimeMillis() + "_" + UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
         File videoFile = new File(VIDEO_UPLOAD_DIR, videoFileName);
         try {
             file.transferTo(videoFile);
@@ -227,7 +237,9 @@ public class FsUserVideoController extends BaseController
                 "ffmpeg",
                 "-i", videoPath,
 //                "-ss", "00:00:01.000", // 截取1秒处的帧
-                "-vframes", "1",
+                "-frames:v", "1",
+                "-f", "image2",
+                "-update", "1",
                 "-q:v", "10", // 质量,1为最好,31为最差
                 outputImagePath
         };
@@ -262,4 +274,89 @@ public class FsUserVideoController extends BaseController
         }
         return R.ok();
     }
+
+    /**
+     * 点播编排转码
+     * @return
+     */
+    @PostMapping("/videoTranscode")
+    public R videoTranscode(@RequestBody String rawBody) {
+        try {
+            // 解析输入JSON
+            VideoTranscodeParam videoTranscodeParam = JSON.parseObject(rawBody, VideoTranscodeParam.class);
+            if (videoTranscodeParam == null || videoTranscodeParam.getScheduleTaskEvent() == null) {
+                log.error("请求体格式无效或缺少scheduleTaskEvent信息");
+                return R.error("请求格式无效");
+            }
+
+            // 检查错误码
+            VideoScheduleTaskEventParam event = videoTranscodeParam.getScheduleTaskEvent();
+            if (!Integer.valueOf(0).equals(event.getErrCode())) {
+                log.warn("收到转码事件非零错误码: {}", event.getErrCode());
+                return R.ok(); // 仍然返回ok确认已处理通知
+            }
+
+            // 验证输入路径
+            if (event.getInputInfo() == null || event.getInputInfo().getCosInputInfo() == null) {
+                log.error("转码事件中缺少输入信息");
+                return R.error("缺少输入信息");
+            }
+
+            String inputPaths = event.getInputInfo().getCosInputInfo().getObject();
+            if (StringUtils.isBlank(inputPaths)) {
+                log.error("转码事件中的输入路径为空");
+                return R.error("输入路径为空");
+            }
+
+            // 移除可能的前导斜杠
+            String inputPath = inputPaths.startsWith("/") ? inputPaths.substring(1) : inputPaths;
+
+            // 查找视频资源
+            FsVideoResource video = iFsVideoResourceService.selectByFileKey(inputPath);
+            if (video == null) {
+                log.warn("未找到文件键对应的视频资源: {}", inputPath);
+                return R.ok();
+            }
+
+            // 验证输出路径
+            if (event.getActivityResultSet() == null || event.getActivityResultSet().isEmpty()) {
+                log.error("转码事件中缺少活动结果集");
+                return R.error("缺少活动结果");
+            }
+
+            VideoActivityResItemParam activityResItem = event.getActivityResultSet().get(0).getActivityResItem();
+            if (activityResItem == null || activityResItem.getTranscodeTask() == null ||
+                    activityResItem.getTranscodeTask().getOutput() == null) {
+                log.error("转码任务信息不完整");
+                return R.error("转码任务不完整");
+            }
+
+            String outputPath = activityResItem.getTranscodeTask().getOutput().getPath();
+            if (StringUtils.isBlank(outputPath)) {
+                log.error("转码事件中的输出路径为空");
+                return R.error("输出路径为空");
+            }
+
+            // 移除可能的前导斜杠
+            String transcodeFileKey = outputPath.startsWith("/") ? outputPath.substring(1) : outputPath;
+
+            // 提交转码作业
+            log.info("开始提交转码作业,输入路径: {}, 输出路径: {}", inputPaths, outputPath);
+            tencentCloudCosService.submitTranscodeJob(inputPaths, outputPath);
+
+            // 更新视频资源
+            FsVideoResource videoMap = new FsVideoResource();
+            videoMap.setId(video.getId());
+            videoMap.setIsTranscode(1);
+            videoMap.setLine1(video.getLine1().replace(inputPath,transcodeFileKey));
+            videoMap.setTranscodeFileKey(transcodeFileKey);
+            iFsVideoResourceService.updateById(videoMap);
+            log.info("成功更新视频转码状态,视频ID: {}", video.getId());
+
+            return R.ok();
+        } catch (Exception e) {
+            log.error("处理视频转码请求时发生异常", e);
+            return R.error("服务器内部错误");
+        }
+    }
 }

+ 1 - 1
fs-admin/src/main/java/com/fs/course/controller/FsVideoResourceController.java

@@ -102,7 +102,7 @@ public class FsVideoResourceController extends BaseController {
         return AjaxResult.success();
     }
 
-    @PreAuthorize("@ss.hasPermi('course:videoResource:add')")
+    @PreAuthorize("@ss.hasPermi('course:videoResource:batchAdd')")
     @Log(title = "视频素材库", businessType = BusinessType.INSERT)
     @PostMapping("/batchAddVideoResource")
     public AjaxResult batchAddVideoResource(@RequestBody List<FsVideoResource> list) {

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

@@ -0,0 +1,142 @@
+package com.fs.course.controller.qw;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.exception.CustomException;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.domain.FsCourseWatchLog;
+import com.fs.course.param.FsCourseWatchLogListParam;
+import com.fs.course.param.FsCourseWatchLogStatisticsListParam;
+import com.fs.course.service.IFsCourseWatchLogService;
+import com.fs.course.vo.FsCourseWatchLogListVO;
+import com.fs.course.vo.FsCourseWatchLogStatisticsListVO;
+import com.fs.qw.param.QwWatchLogStatisticsListParam;
+import com.fs.qw.service.IQwWatchLogService;
+import com.fs.qw.vo.QwWatchLogAllStatisticsListVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 短链课程看课记录Controller
+ *
+ * @author fs
+ * @date 2024-10-24
+ */
+@RestController
+@RequestMapping("/qw/course/courseWatchLog")
+public class QwFsCourseWatchLogController extends BaseController
+{
+    @Autowired
+    private IFsCourseWatchLogService fsCourseWatchLogService;
+
+    @Autowired
+    private IQwWatchLogService qwWatchLogService;
+    /**
+     * 查询短链课程看课记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsCourseWatchLogListParam param)
+    {
+        startPage();
+        List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVO(param);
+        return getDataTable(list);
+    }
+
+    @GetMapping("/qwWatchLogAllStatisticsList")
+    public TableDataInfo qwWatchLogAllStatisticsList(QwWatchLogStatisticsListParam param)
+    {
+        logger.info("企微课程数据汇总 参数:{}",param);
+        startPage();
+        if (param.getSTime()==null||param.getETime()==null){
+            return getDataTable(new ArrayList<>());
+        }
+        List<QwWatchLogAllStatisticsListVO> list = qwWatchLogService.selectQwWatchLogAllStatisticsListVO(param);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:statisticsList')")
+    @GetMapping("/statisticsList")
+    public TableDataInfo statisticsList(FsCourseWatchLogStatisticsListParam param)
+    {
+        startPage();
+        if (param.getSTime()==null||param.getETime()==null){
+            return getDataTable(new ArrayList<>());
+        }
+        List<FsCourseWatchLogStatisticsListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogStatisticsListVO(param);
+        return getDataTable(list);
+    }
+    @GetMapping("/qwWatchLogStatisticsList")
+    public TableDataInfo qwWatchLogStatisticsList(QwWatchLogStatisticsListParam param)
+    {
+        if (param.getSTime()==null||param.getETime()==null){
+            return getDataTable(new ArrayList<>());
+        }
+        if(param.getCompanyId() == null){
+            throw new CustomException("必须选择公司!");
+        }
+        return qwWatchLogService.selectQwWatchLogStatisticsListVO(param);
+    }
+    /**
+     * 导出短链课程看课记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:export')")
+    @Log(title = "短链课程看课记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsCourseWatchLogListParam param)
+    {
+        List<FsCourseWatchLogListVO> list = fsCourseWatchLogService.selectFsCourseWatchLogListVO(param);
+        ExcelUtil<FsCourseWatchLogListVO> util = new ExcelUtil<FsCourseWatchLogListVO>(FsCourseWatchLogListVO.class);
+        return util.exportExcel(list, "短链课程看课记录数据");
+    }
+
+    /**
+     * 获取短链课程看课记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:query')")
+    @GetMapping(value = "/{logId}")
+    public AjaxResult getInfo(@PathVariable("logId") Long logId)
+    {
+        return AjaxResult.success(fsCourseWatchLogService.selectFsCourseWatchLogByLogId(logId));
+    }
+
+    /**
+     * 新增短链课程看课记录
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:add')")
+    @Log(title = "短链课程看课记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsCourseWatchLog fsCourseWatchLog)
+    {
+        return toAjax(fsCourseWatchLogService.insertFsCourseWatchLog(fsCourseWatchLog));
+    }
+
+    /**
+     * 修改短链课程看课记录
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:edit')")
+    @Log(title = "短链课程看课记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsCourseWatchLog fsCourseWatchLog)
+    {
+        return toAjax(fsCourseWatchLogService.updateFsCourseWatchLog(fsCourseWatchLog));
+    }
+
+    /**
+     * 删除短链课程看课记录
+     */
+    @PreAuthorize("@ss.hasPermi('course:courseWatchLog:remove')")
+    @Log(title = "短链课程看课记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{logIds}")
+    public AjaxResult remove(@PathVariable Long[] logIds)
+    {
+        return toAjax(fsCourseWatchLogService.deleteFsCourseWatchLogByLogIds(logIds));
+    }
+}

+ 16 - 0
fs-admin/src/main/java/com/fs/course/task/VideoTask.java

@@ -5,6 +5,7 @@ import com.fs.common.core.redis.RedisCache;
 import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.*;
 import com.fs.course.mapper.*;
+import com.fs.course.service.IFsCourseTrafficLogService;
 import com.fs.course.service.IFsUserVideoCommentService;
 import com.fs.his.domain.FsUser;
 import com.fs.his.mapper.FsUserMapper;
@@ -18,6 +19,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
 import java.time.LocalDate;
@@ -55,6 +57,9 @@ public class VideoTask {
     @Autowired
     private FsCourseRedPacketLogMapper redPacketLogMapper;
 
+    @Autowired
+    private IFsCourseTrafficLogService iFsCourseTrafficLogService;
+
     public void autoNotShowVideo() {
         List<Long> list = videoMapper.selectNotAuditVideo();
         for (Long videoId : list){
@@ -238,4 +243,15 @@ public class VideoTask {
 
         }
     }
+
+    /**
+     * 存储课程流量日志
+     * @throws Exception
+     */
+//    @Scheduled(fixedRate = 1000)
+    public void saveCourseTrafficLog() throws Exception
+    {
+        iFsCourseTrafficLogService.saveCourseTrafficLog();
+    }
+
 }

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

@@ -165,7 +165,7 @@ public class FsCompanyController extends BaseController
     public AjaxResult resetPwd(@PathVariable Long companyId)
     {
         Company company=companyService.selectCompanyById(companyId);
-        return toAjax(userService.resetUserPwdByUserId(company.getUserId(), SecurityUtils.encryptPassword("123456")));
+        return toAjax(userService.resetUserPwdByUserId(company.getUserId(), SecurityUtils.encryptPassword("cq654321!!")));
     }
 
     @PreAuthorize("@ss.hasPermi('his:company:recharge')")

+ 15 - 28
fs-admin/src/main/java/com/fs/his/controller/FsInquiryOrderReportController.java

@@ -1,46 +1,33 @@
 package com.fs.his.controller;
 
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
 import com.alibaba.fastjson.JSON;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.ParseUtils;
 import com.fs.common.utils.SecurityUtils;
 import com.fs.his.domain.FsExportTask;
-import com.fs.his.domain.FsInquiryDisease;
+import com.fs.his.domain.FsInquiryOrderReport;
 import com.fs.his.param.FsInquiryOrderReportParam;
 import com.fs.his.service.IFsExportTaskService;
-import com.fs.his.service.IFsInquiryDiseaseService;
-import com.fs.his.vo.FsInquiryDiseaseVO;
+import com.fs.his.service.IFsInquiryOrderReportService;
 import com.fs.his.vo.FsInquiryOrderReportListVO;
 import com.fs.his.vo.FsInquiryOrderReportVO;
-import com.qiniu.util.Json;
-import com.sun.media.jfxmedia.logging.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.fs.common.annotation.Log;
-import com.fs.common.core.controller.BaseController;
-import com.fs.common.core.domain.AjaxResult;
-import com.fs.common.enums.BusinessType;
-import com.fs.his.domain.FsInquiryOrderReport;
-import com.fs.his.service.IFsInquiryOrderReportService;
-import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.common.core.page.TableDataInfo;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
 
-import static com.fs.his.utils.PhoneUtil.*;
+import static com.fs.his.utils.PhoneUtil.decryptPhone;
+import static com.fs.his.utils.PhoneUtil.decryptPhoneMk;
 
 /**
  * 问诊报告Controller

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

@@ -8,6 +8,7 @@ import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.his.domain.FsIntegralGoods;
 import com.fs.his.service.IFsIntegralGoodsService;
+import com.fs.his.utils.RedisCacheUtil;
 import com.fs.his.vo.FsIntegralGoodsListVO;
 import com.fs.his.vo.FsStoreProductExcelVO;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -29,7 +30,8 @@ public class FsIntegralGoodsController extends BaseController
 {
     @Autowired
     private IFsIntegralGoodsService fsIntegralGoodsService;
-
+    @Autowired
+    RedisCacheUtil redisCacheUtil;
     /**
      * 查询积分商品列表
      */
@@ -70,6 +72,8 @@ public class FsIntegralGoodsController extends BaseController
     @PostMapping("/importData")
     public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
     {
+        redisCacheUtil.delRedisKey("getIntegralGoodsList");
+        redisCacheUtil.delRedisKey("getIntegralGoodsById");
         ExcelUtil<FsIntegralGoods> util = new ExcelUtil<>(FsIntegralGoods.class);
         List<FsIntegralGoods> list = util.importExcel(file.getInputStream());
         String message = fsIntegralGoodsService.importIntegralGoodsService(list);
@@ -92,6 +96,8 @@ public class FsIntegralGoodsController extends BaseController
     @PostMapping
     public AjaxResult add(@RequestBody FsIntegralGoods fsIntegralGoods)
     {
+        redisCacheUtil.delRedisKey("getIntegralGoodsList");
+        redisCacheUtil.delRedisKey("getIntegralGoodsById");
         return toAjax(fsIntegralGoodsService.insertFsIntegralGoods(fsIntegralGoods));
     }
 
@@ -103,6 +109,9 @@ public class FsIntegralGoodsController extends BaseController
     @PutMapping
     public AjaxResult edit(@RequestBody FsIntegralGoods fsIntegralGoods)
     {
+
+        redisCacheUtil.delRedisKey("getIntegralGoodsList");
+        redisCacheUtil.delRedisKey("getIntegralGoodsById");
         return toAjax(fsIntegralGoodsService.updateFsIntegralGoods(fsIntegralGoods));
     }
 
@@ -114,6 +123,8 @@ public class FsIntegralGoodsController extends BaseController
 	@DeleteMapping("/{goodsIds}")
     public AjaxResult remove(@PathVariable Long[] goodsIds)
     {
+        redisCacheUtil.delRedisKey("getIntegralGoodsList");
+        redisCacheUtil.delRedisKey("getIntegralGoodsById");
         return toAjax(fsIntegralGoodsService.deleteFsIntegralGoodsByGoodsIds(goodsIds));
     }
 }

+ 6 - 0
fs-admin/src/main/java/com/fs/his/controller/FsPackageCateController.java

@@ -125,4 +125,10 @@ public class FsPackageCateController extends BaseController
         Map map = fsPackageCateService.selectFsArticleCateAllList();
         return AjaxResult.success(map);
     }
+    @GetMapping("/cateList")
+    public TableDataInfo cateList()
+    {
+        List<OptionsVO> list = fsPackageCateService.selectCateList();
+        return getDataTable(list);
+    }
 }

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

@@ -1,8 +1,11 @@
 package com.fs.his.controller;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.utils.ParseUtils;
 import com.fs.common.utils.SecurityUtils;
 import com.fs.his.domain.FsUserAddress;
@@ -11,6 +14,11 @@ import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.FsUserExportListVO;
 import com.fs.his.vo.FsUserVO;
 import com.fs.his.vo.UserVo;
+import com.fs.store.param.h5.FsUserPageListParam;
+import com.fs.store.vo.h5.FsUserPageListVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.ApiOperation;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -183,5 +191,28 @@ public class FsUserController extends BaseController
         return R.ok().put("data",list);
     }
 
+    @PreAuthorize("@ss.hasPermi('his:user:darkRoomList')")
+    @GetMapping("/darkRoomList")
+    @ApiOperation("小黑屋")
+    public R darkRoomList(FsUserPageListParam param) {
+//        startPage();
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        PageInfo<FsUserPageListVO> fsUserPageListVOPageInfo = fsUserService.selectFsUserPageList(param);
+        for (FsUserPageListVO fsUserPageListVO : fsUserPageListVOPageInfo.getList()) {
+            fsUserPageListVO.setPhone(ParseUtils.parsePhone(fsUserPageListVO.getPhone()));
+        }
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("rows", fsUserPageListVOPageInfo.getList());
+        map.put("total", fsUserPageListVOPageInfo.getList().size());
+        return R.ok(map);
+    }
+
+    @PreAuthorize("@ss.hasPermi('his:user:enabledUsers')")
+    @PostMapping("/enabledUsers")
+    @ApiOperation("批量启用会员")
+    public ResponseResult<Boolean> enabledUsers(@RequestBody String[] ids) {
+        Boolean r = fsUserService.disabledUser(ids, true);
+        return ResponseResult.ok(r);
+    }
 
 }

+ 47 - 0
fs-admin/src/main/java/com/fs/his/task/FsCourseTask.java

@@ -0,0 +1,47 @@
+package com.fs.his.task;
+
+import com.fs.course.service.IFsCourseWatchLogService;
+import com.fs.qw.service.IHyWorkTaskService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 后台统计相关 定时任务
+ */
+@Slf4j
+@Service("fsCourseTask")
+public class FsCourseTask {
+    @Autowired
+    private IFsCourseWatchLogService fsCourseWatchLogService;
+    @Autowired
+    private IHyWorkTaskService hyWorkTaskService;
+    /**
+     * 添加会员观看日志
+     * @throws Exception
+     */
+    public void addHyWatchLog() throws Exception
+    {
+        fsCourseWatchLogService.addCourseWatchLogDayNew();
+    }
+
+    /**
+     * 删除过期数据
+     * @throws Exception
+     */
+    public void hyWorkTask4() throws Exception
+    {
+        // 更新已完课的催课看板
+        hyWorkTaskService.delHyWorkTaskByOver();
+    }
+
+    /**
+     * 会员查看催课面板 获取看课中断和待看的先导课
+     * @throws Exception
+     */
+    public void hyWorkTask(){
+
+        hyWorkTaskService.hyWorkTask();
+    }
+
+}

+ 24 - 91
fs-admin/src/main/java/com/fs/his/task/Task.java

@@ -1,129 +1,56 @@
 package com.fs.his.task;
 
-import cn.binarywang.wx.miniapp.api.WxMaService;
-import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
-import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
 import cn.hutool.core.date.DateTime;
-import cn.hutool.core.net.URLDecoder;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.http.HttpUtil;
-import cn.hutool.json.JSONArray;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.JSONObject;
-import com.alibaba.fastjson.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fs.common.annotation.Log;
-import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
-import com.fs.common.exception.CustomException;
 import com.fs.common.service.impl.SmsServiceImpl;
-import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.SecurityUtils;
-import com.fs.common.utils.poi.ExcelUtil;
-import com.fs.company.domain.*;
+import com.fs.company.domain.CompanyMoneyLogs;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.domain.CompanyVoiceCaller;
 import com.fs.company.mapper.*;
 import com.fs.company.service.ICompanyService;
-import com.fs.company.service.impl.CompanyMoneyLogsServiceImpl;
 import com.fs.company.vo.RedPacketMoneyVO;
-import com.fs.core.config.WxMaConfiguration;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
 import com.fs.course.service.IFsCourseWatchLogService;
-import com.fs.crm.param.SmsSendParam;
+import com.fs.course.service.ITencentCloudCosService;
 import com.fs.erp.domain.ErpDeliverys;
 import com.fs.erp.domain.ErpOrderQuery;
-import com.fs.erp.dto.*;
+import com.fs.erp.dto.ErpOrderQueryRequert;
+import com.fs.erp.dto.ErpOrderQueryResponse;
 import com.fs.erp.service.IErpOrderService;
-import com.fs.event.TemplateBean;
-import com.fs.event.TemplateEvent;
-import com.fs.event.TemplateListenEnum;
-import com.fs.fastGpt.config.ModeConfig;
-import com.fs.fastGpt.domain.FastGptRole;
 import com.fs.fastGpt.mapper.FastGptChatSessionMapper;
-import com.fs.fastgptApi.param.ChatParam;
-import com.fs.fastgptApi.param.VoiceParam;
-import com.fs.fastgptApi.result.ChatDetailTStreamFResult;
-import com.fs.fastgptApi.service.Impl.AudioServiceImpl;
-import com.fs.fastgptApi.util.AudioUtils;
 import com.fs.his.config.StoreConfig;
-import com.fs.his.domain.*;
-import com.fs.his.dto.*;
+import com.fs.his.domain.FsInquiryOrder;
+import com.fs.his.domain.FsStoreAfterSales;
+import com.fs.his.domain.FsStoreOrder;
+import com.fs.his.domain.FsUser;
+import com.fs.his.dto.FsInquiryOrderPatientDTO;
 import com.fs.his.enums.FsStoreOrderLogEnum;
 import com.fs.his.enums.FsStoreOrderStatusEnum;
-import com.fs.his.enums.ShipperCodeEnum;
 import com.fs.his.mapper.*;
-import com.fs.his.param.FsFollowMsgParam;
 import com.fs.his.param.FsInquiryOrderFinishParam;
-import com.fs.his.param.FsPackageOrderDoPayParam;
 import com.fs.his.service.*;
-import com.fs.his.service.impl.*;
-import com.fs.his.vo.FsStoreProductExcelVO;
-import com.fs.his.vo.FsStoreProductVO;
+import com.fs.his.service.impl.FsPackageOrderServiceImpl;
 import com.fs.his.vo.FsSubOrderResultVO;
 import com.fs.im.dto.*;
 import com.fs.im.service.IImService;
-import com.fs.qw.mapper.QwAppContactWayMapper;
-import com.fs.qw.mapper.QwExternalContactTransferLogMapper;
 import com.fs.qw.service.IQwAppContactWayService;
 import com.fs.qw.service.IQwExternalContactTransferLogService;
-import com.fs.qw.service.impl.QwAppContactWayServiceImpl;
-import com.fs.qwApi.Result.QwSendMsgResult;
-import com.fs.qwApi.param.QwSendMsgParam;
 import com.fs.qwApi.service.QwApiService;
-import com.fs.qwApi.service.impl.QwApiServiceImpl;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
-import com.fs.system.oss.CloudStorageService;
-import com.fs.system.oss.OSSFactory;
-import com.fs.tzBankPay.TzBankService.TzBankService;
-import com.fs.tzBankPay.doman.*;
 import com.google.gson.Gson;
-import com.qiniu.util.Json;
-import com.tencentcloudapi.mongodb.v20180408.models.SpecItem;
-import io.lettuce.core.ScriptOutputType;
-import javafx.scene.effect.Bloom;
-import jdk.nashorn.internal.scripts.JS;
-import org.apache.catalina.Store;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.http.HttpEntity;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.utils.URLEncodedUtils;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.message.BasicNameValuePair;
-import org.apache.http.util.EntityUtils;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.ApplicationEventPublisher;
-import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
 
-import javax.imageio.ImageIO;
-import javax.sound.sampled.Line;
-import java.awt.image.BufferedImage;
-import java.io.*;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.net.URL;
-import java.net.URLConnection;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.text.ParseException;
-import java.time.Duration;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.*;
-import java.util.logging.Logger;
-import java.util.regex.Pattern;
-
-import static com.fs.his.utils.PhoneUtil.decryptPhone;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
 
 @Component("task")
 public class Task {
@@ -210,13 +137,19 @@ public class Task {
     @Autowired
     private IFsCourseWatchLogService fsCourseWatchLogService;
 
-    public void tt() throws Exception
+    @Autowired
+    ITencentCloudCosService tencentCloudCosService;
+    public void videoTranscode() throws Exception
     {
 
-
+        tencentCloudCosService.videoTranscode();
     }
 
+    public void updateUrl() throws Exception
+    {
 
+        tencentCloudCosService.updateUrl();
+    }
     public void addPrescribeImg() throws Exception
     {
        List<Long> ids= fsPrescribeService.selectFsPrescribeByPrescribeIdByOrderType();

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

@@ -0,0 +1,64 @@
+package com.fs.qw;
+
+import com.fs.course.service.IFsCourseWatchLogService;
+import com.fs.qw.service.IQwWorkTaskService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 后台统计相关 定时任务
+ */
+@Slf4j
+@Service("qwFsCourseTask")
+public class FsCourseTask {
+    @Autowired
+    private IFsCourseWatchLogService fsCourseWatchLogService;
+    @Autowired
+    private IQwWorkTaskService qwWorkTaskService;
+
+    /**
+     * 添加企微观看日志
+     * @throws Exception
+     */
+    public void addQwWatchLog() throws Exception
+    {
+        fsCourseWatchLogService.addCourseWatchLogDay();
+    }
+
+    /**
+     * 企微任务定时更新
+     * @throws Exception
+     */
+    public void qwWorkTask1() throws Exception
+    {
+        qwWorkTaskService.addQwWorkByCourse4();
+        qwWorkTaskService.addQwWorkByCourseLastTime();
+    }
+    /**
+     * 企微待看课和先导课
+     * @throws Exception
+     */
+    public void qwWorkTask2() throws Exception
+    {
+        qwWorkTaskService.addQwWorkByCourse();
+        qwWorkTaskService.addQwWorkByFirstCourse();
+    }
+    /**
+     * 用户大小转
+     * @throws Exception
+     */
+    public void qwWorkTask3() throws Exception
+    {
+        qwWorkTaskService.addQwWorkByConversionDay();
+    }
+    /**
+     * 删除过期数据
+     * @throws Exception
+     */
+    public void qwWorkTask4() throws Exception
+    {
+        qwWorkTaskService.delQwWorkTaskByOver();
+    }
+
+}

+ 138 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwExternalContactController.java

@@ -0,0 +1,138 @@
+package com.fs.qw.controller;
+
+import java.util.List;
+import java.util.Objects;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.fs.common.exception.ServiceException;
+import com.fs.qw.param.QwExternalContactParam;
+import com.fs.qw.param.QwTagSearchParam;
+import com.fs.qw.service.IQwTagService;
+import com.fs.qw.vo.QwExternalContactVO;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.qw.domain.QwExternalContact;
+import com.fs.qw.service.IQwExternalContactService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 企业微信客户Controller
+ * 
+ * @author fs
+ * @date 2025-06-13
+ */
+@RestController
+@RequestMapping("/qw/externalContact")
+public class QwExternalContactController extends BaseController
+{
+    private IQwExternalContactService qwExternalContactService;
+    private IQwTagService iQwTagService;
+
+    QwExternalContactController(IQwExternalContactService qwExternalContactService,IQwTagService iQwTagService){
+        this.qwExternalContactService=qwExternalContactService;
+        this.iQwTagService=iQwTagService;
+    }
+
+
+    /**
+     * 查询企业微信客户列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:externalContact:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(QwExternalContactParam qwExternalContact)
+    {
+        if(ObjectUtil.isEmpty(qwExternalContact.getCompanyId())){
+            throw new ServiceException("操作失败,请选择企业!");
+        }
+        startPage();
+        List<QwExternalContactVO> list = qwExternalContactService.selectQwExternalContactListVO(qwExternalContact);
+        list.forEach(item->{
+
+            if (!Objects.equals(item.getTagIds(), "[]") && item.getTagIds()!=null) {
+                QwTagSearchParam param = new QwTagSearchParam();
+                Gson gson = new Gson();
+                List<String> tagIds = gson.fromJson(
+                        item.getTagIds(),
+                        new TypeToken<List<String>>() {
+                        }.getType()
+                );
+
+                param.setTagIds(tagIds);
+
+                item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
+            }
+        });
+
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出企业微信客户列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:externalContact:export')")
+    @Log(title = "企业微信客户", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(QwExternalContact qwExternalContact)
+    {
+        List<QwExternalContact> list = qwExternalContactService.selectQwExternalContactList(qwExternalContact);
+        ExcelUtil<QwExternalContact> util = new ExcelUtil<QwExternalContact>(QwExternalContact.class);
+        return util.exportExcel(list, "企业微信客户数据");
+    }
+
+    /**
+     * 获取企业微信客户详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:externalContact:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(qwExternalContactService.selectQwExternalContactById(id));
+    }
+
+    /**
+     * 新增企业微信客户
+     */
+    @PreAuthorize("@ss.hasPermi('qw:externalContact:add')")
+    @Log(title = "企业微信客户", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwExternalContact qwExternalContact)
+    {
+        return toAjax(qwExternalContactService.insertQwExternalContact(qwExternalContact));
+    }
+
+    /**
+     * 修改企业微信客户
+     */
+    @PreAuthorize("@ss.hasPermi('qw:externalContact:edit')")
+    @Log(title = "企业微信客户", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody QwExternalContact qwExternalContact)
+    {
+        return toAjax(qwExternalContactService.updateQwExternalContact(qwExternalContact));
+    }
+
+    /**
+     * 删除企业微信客户
+     */
+    @PreAuthorize("@ss.hasPermi('qw:externalContact:remove')")
+    @Log(title = "企业微信客户", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(qwExternalContactService.deleteQwExternalContactByIds(ids));
+    }
+}

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

@@ -128,7 +128,7 @@ public class QwSopTempController extends BaseController
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         qwSopTemp.setCreateBy(loginUser.getUser().getUserId().toString());
         int i = qwSopTempService.addNew(qwSopTemp);
-        if(qwSopTemp.getSendType() == 5){
+        if(qwSopTemp.getSendType() == 11){
             new Thread(() -> qwSopTempService.createSopTempRules(qwSopTemp)).start();
         }
         return toAjax(i);

+ 41 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwTagGroupController.java

@@ -0,0 +1,41 @@
+package com.fs.qw.controller;
+
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.qw.domain.QwTagGroup;
+import com.fs.qw.service.IQwTagGroupService;
+import com.fs.qw.vo.QwTagGroupListVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 企微客户标签组Controller
+ *
+ * @author fs
+ * @date 2024-06-20
+ */
+@RestController
+@RequestMapping("/qw/tagGroup")
+public class QwTagGroupController extends BaseController
+{
+    @Autowired
+    private IQwTagGroupService qwTagGroupService;
+
+    @Autowired
+    private RedisTemplate redisTemplate;
+
+    /**
+    * 所有标签列表
+    */
+    @GetMapping("/allList")
+    public TableDataInfo allList(QwTagGroup qwTagGroup)
+    {
+        startPage();
+
+        List<QwTagGroupListVO> list = qwTagGroupService.selectQwTagGroupListVO(qwTagGroup);
+        return getDataTable(list);
+    }
+}

+ 10 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwUserController.java

@@ -1,7 +1,9 @@
 package com.fs.qw.controller;
 
+import com.baomidou.mybatisplus.extension.api.R;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.qw.param.QwFsUserParam;
 import com.fs.qw.service.IQwUserService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -24,4 +26,12 @@ public class QwUserController extends BaseController {
     public AjaxResult getQwUserAll(){
         return AjaxResult.success(qwUserService.getQwUserAll());
     }
+
+    /**
+     * 获取企微信息
+     * **/
+    @GetMapping("/getQwUserInfo")
+    public R getQwUserInfo(QwFsUserParam param){
+        return R.ok(qwUserService.getQwUserInfo(param));
+    }
 }

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

@@ -4,7 +4,10 @@ package com.fs.qw.controller;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.page.TableDataInfo;
+import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.param.SopUserLogsVO;
+import com.fs.sop.domain.QwSop;
+import com.fs.sop.mapper.QwSopMapper;
 import com.fs.sop.params.SopUserLogsParam;
 import com.fs.sop.service.ISopUserLogsService;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -29,14 +32,37 @@ public class SopUserLogsController extends BaseController
     @Autowired
     private ISopUserLogsService sopUserLogsService;
 
+    @Autowired
+    private QwSopMapper sopMapper;
+
+    @Autowired
+    private QwUserMapper qwUserMapper;
+
+
     /**
      * 查询sopUserLogs列表
      */
     @GetMapping("/list")
     public TableDataInfo list(SopUserLogsParam sopUserLogs)
     {
-        startPage();
-        List<SopUserLogsVO> list = sopUserLogsService.selectSopUserLogsList(sopUserLogs);
+
+        QwSop qwSop = sopMapper.selectQwSopById(sopUserLogs.getSopId());
+        Integer filterMode = qwSop.getFilterMode();
+
+        List<SopUserLogsVO> list=null;
+        if(filterMode == null || filterMode == 1){
+            startPage();
+            list = sopUserLogsService.selectSopUserLogsList(sopUserLogs);
+        }else {
+            startPage();
+            list = sopUserLogsService.selectSopUserLogsGroupListByParam(sopUserLogs);
+        }
+
+
+        list.forEach(item->{
+            item.setQwUserName(qwUserMapper.selectQwUserByQwUserIdAndCorpId(item.getQwUserId(), item.getCorpId()));
+        });
+
         return getDataTable(list);
     }
 

+ 97 - 0
fs-admin/src/main/java/com/fs/transfer/CustomerTransferApprovalController.java

@@ -0,0 +1,97 @@
+package com.fs.transfer;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.qw.domain.CustomerTransferApproval;
+import com.fs.qw.service.ICustomerTransferApprovalService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 客户转移审批Controller
+ *
+ * @author fs
+ * @date 2025-04-01
+ */
+@RestController
+@RequestMapping("/system/approval")
+public class CustomerTransferApprovalController extends BaseController
+{
+    @Autowired
+    private ICustomerTransferApprovalService customerTransferApprovalService;
+
+    /**
+     * 查询客户转移审批列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:approval:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CustomerTransferApproval customerTransferApproval)
+    {
+        startPage();
+        List<CustomerTransferApproval> list = customerTransferApprovalService.selectCustomerTransferApprovalList(customerTransferApproval);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出客户转移审批列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:approval:export')")
+    @Log(title = "客户转移审批", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CustomerTransferApproval customerTransferApproval)
+    {
+        List<CustomerTransferApproval> list = customerTransferApprovalService.selectCustomerTransferApprovalList(customerTransferApproval);
+        ExcelUtil<CustomerTransferApproval> util = new ExcelUtil<CustomerTransferApproval>(CustomerTransferApproval.class);
+        return util.exportExcel(list, "approval");
+    }
+
+    /**
+     * 获取客户转移审批详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:approval:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(customerTransferApprovalService.selectCustomerTransferApprovalById(id));
+    }
+
+    /**
+     * 新增客户转移审批
+     */
+    @PreAuthorize("@ss.hasPermi('system:approval:add')")
+    @Log(title = "客户转移审批", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CustomerTransferApproval customerTransferApproval)
+    {
+        return toAjax(customerTransferApprovalService.insertCustomerTransferApproval(customerTransferApproval));
+    }
+
+    /**
+     * 修改客户转移审批
+     */
+    @PreAuthorize("@ss.hasPermi('system:approval:edit')")
+    @Log(title = "客户转移审批", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CustomerTransferApproval customerTransferApproval)
+    {
+        return toAjax(customerTransferApprovalService.updateCustomerTransferApproval(customerTransferApproval));
+    }
+
+    /**
+     * 删除客户转移审批
+     */
+    @PreAuthorize("@ss.hasPermi('system:approval:remove')")
+    @Log(title = "客户转移审批", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(customerTransferApprovalService.deleteCustomerTransferApprovalByIds(ids));
+    }
+}

+ 12 - 1
fs-admin/src/main/java/com/fs/web/controller/system/SysDictDataController.java

@@ -26,7 +26,7 @@ import com.fs.system.service.ISysDictTypeService;
 
 /**
  * 数据字典信息
- * 
+ *
 
  */
 @RestController
@@ -117,4 +117,15 @@ public class SysDictDataController extends BaseController
         dictDataService.deleteDictDataByIds(dictCodes);
         return success();
     }
+
+
+    /**
+     * 不分页获取列表
+     */
+    @GetMapping("/allList")
+    public AjaxResult allList(SysDictData dictData) {
+        List<SysDictData> list = dictDataService.selectDictDataList(dictData);
+        return AjaxResult.success(list);
+    }
+
 }

+ 151 - 0
fs-admin/src/main/java/com/fs/web/controller/system/SysKeywordController.java

@@ -0,0 +1,151 @@
+package com.fs.web.controller.system;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.system.domain.SysKeyword;
+import com.fs.system.service.ISysKeywordService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.PostConstruct;
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 系统关键字Controller
+ *
+ * @author fs
+ * @date 2025-05-14
+ */
+@RestController
+@RequestMapping("/system/keyword")
+public class SysKeywordController extends BaseController
+{
+    @Autowired
+    private ISysKeywordService sysKeywordService;
+
+    @Autowired
+    RedisCache redisCache;
+
+    @Autowired
+    public RedisTemplate<String,String> redisTemplate;
+
+    private static final String REDIS_KEY = "sys:keywords";
+
+    /**
+     * 查询系统关键字列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:keyword:list')")
+    @GetMapping("/list")
+    public R list(SysKeyword sysKeyword)
+    {
+//        startPage();
+        PageHelper.startPage(sysKeyword.getPageNum(), sysKeyword.getPageSize());
+        List<SysKeyword> list = sysKeywordService.selectSysKeywordList(sysKeyword);
+
+        PageInfo<SysKeyword> pageInfo = new PageInfo<>(list);
+        Map<String, Object> result = new HashMap<>();
+        result.put("rows", pageInfo.getList());
+        result.put("total", pageInfo.getTotal());
+        return R.ok(result);
+    }
+
+    /**
+     * 导出系统关键字列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:keyword:export')")
+    @Log(title = "系统关键字", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(SysKeyword sysKeyword)
+    {
+        List<SysKeyword> list = sysKeywordService.selectSysKeywordList(sysKeyword);
+        ExcelUtil<SysKeyword> util = new ExcelUtil<SysKeyword>(SysKeyword.class);
+        return util.exportExcel(list, "系统关键字数据");
+    }
+
+    /**
+     * 获取系统关键字详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:keyword:query')")
+    @GetMapping(value = "/{keywordId}")
+    public AjaxResult getInfo(@PathVariable("keywordId") Long keywordId)
+    {
+        return AjaxResult.success(sysKeywordService.selectSysKeywordById(keywordId));
+    }
+
+    /**
+     * 新增系统关键字
+     */
+    @PreAuthorize("@ss.hasPermi('system:keyword:add')")
+    @Log(title = "系统关键字", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody SysKeyword sysKeyword)
+    {
+        int i = sysKeywordService.insertSysKeyword(sysKeyword);
+        // 缓存
+        redisTemplate.opsForSet().add(REDIS_KEY, sysKeyword.getKeyword());
+        return toAjax(i);
+    }
+
+    /**
+     * 修改系统关键字
+     */
+    @PreAuthorize("@ss.hasPermi('system:keyword:edit')")
+    @Log(title = "系统关键字", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysKeyword sysKeyword)
+    {
+        //获取之前的数据
+        SysKeyword sysKeywordOld = sysKeywordService.selectSysKeywordById(sysKeyword.getKeywordId());
+        String keywordOld = sysKeywordOld.getKeyword();
+        int i = sysKeywordService.updateSysKeyword(sysKeyword);
+        // 更新缓存
+        redisTemplate.opsForSet().remove(REDIS_KEY, keywordOld);
+        redisTemplate.opsForSet().add(REDIS_KEY, sysKeyword.getKeyword());
+        return toAjax(i);
+    }
+
+    /**
+     * 删除系统关键字
+     */
+    @PreAuthorize("@ss.hasPermi('system:keyword:remove')")
+    @Log(title = "系统关键字", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{keywordIds}")
+    public AjaxResult remove(@PathVariable Long[] keywordIds)
+    {
+        List<SysKeyword> sysKeywords = sysKeywordService.selectSysKeywordByIds(keywordIds);
+        int i = sysKeywordService.deleteSysKeywordByIds(keywordIds);
+        if (!CollectionUtils.isEmpty(sysKeywords)) {
+            redisTemplate.opsForSet().remove(REDIS_KEY, sysKeywords.stream().map(SysKeyword::getKeyword).toArray(String[]::new));
+        }
+        return toAjax(i);
+    }
+
+    /**
+     * 启动加载全部关键字到缓存
+     */
+    @PostConstruct
+    public void initKeywords() {
+        SysKeyword sysKeywordParam = new SysKeyword();
+        List<SysKeyword> sysKeywords = sysKeywordService.selectSysKeywordList(sysKeywordParam);
+        List<String> keywords = sysKeywords.stream()
+                .map(SysKeyword::getKeyword)
+                .collect(Collectors.toList());
+
+        if (!keywords.isEmpty()) {
+            redisTemplate.opsForSet().add(REDIS_KEY, keywords.toArray(new String[0]));
+        }
+        System.out.println("加载全部关键字到缓存");
+    }
+}

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

@@ -3,6 +3,8 @@ package com.fs.web.controller.system;
 import java.util.List;
 import java.util.Set;
 
+import com.fs.common.core.domain.R;
+import com.fs.common.utils.PatternUtils;
 import lombok.Synchronized;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Async;
@@ -47,6 +49,9 @@ public class SysLoginController
     @PostMapping("/login")
     public AjaxResult login(@RequestBody LoginBody loginBody)
     {
+        if (!PatternUtils.checkPassword(loginBody.getPassword())) {
+            return AjaxResult.error("密码格式不正确,需包含字母、数字和特殊字符,长度为 8-20 位");
+        }
         AjaxResult ajax = AjaxResult.success();
         // 生成令牌
         String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),

+ 7 - 0
fs-admin/src/main/java/com/fs/web/controller/system/SysProfileController.java

@@ -1,6 +1,8 @@
 package com.fs.web.controller.system;
 
 import java.io.IOException;
+
+import com.fs.common.utils.PatternUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -101,6 +103,11 @@ public class SysProfileController extends BaseController
         {
             return AjaxResult.error("修改密码失败,旧密码错误");
         }
+
+        if (!PatternUtils.checkPassword(newPassword)) {
+            return AjaxResult.error("新密码格式不正确,需包含字母、数字和特殊字符,长度为 8-20 位");
+        }
+
         if (SecurityUtils.matchesPassword(newPassword, password))
         {
             return AjaxResult.error("新密码不能与旧密码相同");

+ 103 - 0
fs-admin/src/main/java/com/fs/web/controller/system/SysUserSetController.java

@@ -0,0 +1,103 @@
+package com.fs.web.controller.system;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.system.domain.SysUserSet;
+import com.fs.system.service.ISysUserSetService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 用户设置Controller
+ *
+ * @author fs
+ * @date 2025-06-04
+ */
+@RestController
+@RequestMapping("/system/set")
+public class SysUserSetController extends BaseController
+{
+    @Autowired
+    private ISysUserSetService sysUserSetService;
+
+    /**
+     * 查询用户设置列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:set:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysUserSet sysUserSet)
+    {
+        startPage();
+        List<SysUserSet> list = sysUserSetService.selectSysUserSetList(sysUserSet);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出用户设置列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:set:export')")
+    @Log(title = "用户设置", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(SysUserSet sysUserSet)
+    {
+        List<SysUserSet> list = sysUserSetService.selectSysUserSetList(sysUserSet);
+        ExcelUtil<SysUserSet> util = new ExcelUtil<SysUserSet>(SysUserSet.class);
+        return util.exportExcel(list, "用户设置数据");
+    }
+
+    /**
+     * 获取用户设置详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:set:query')")
+    @GetMapping(value = "/{userId}")
+    public AjaxResult getInfo(@PathVariable("userId") Long userId)
+    {
+        return AjaxResult.success(sysUserSetService.selectSysUserSetByUserId(userId));
+    }
+
+    /**
+     * 新增用户设置
+     */
+    @PreAuthorize("@ss.hasPermi('system:set:add')")
+    @Log(title = "用户设置", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody SysUserSet sysUserSet)
+    {
+        return toAjax(sysUserSetService.insertSysUserSet(sysUserSet));
+    }
+
+    /**
+     * 修改用户设置
+     */
+    @PreAuthorize("@ss.hasPermi('system:set:edit')")
+    @Log(title = "用户设置", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysUserSet sysUserSet)
+    {
+        return toAjax(sysUserSetService.updateSysUserSet(sysUserSet));
+    }
+
+    /**
+     * 删除用户设置
+     */
+    @PreAuthorize("@ss.hasPermi('system:set:remove')")
+    @Log(title = "用户设置", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{userIds}")
+    public AjaxResult remove(@PathVariable Long[] userIds)
+    {
+        return toAjax(sysUserSetService.deleteSysUserSetByUserIds(userIds));
+    }
+}

+ 5 - 1
fs-admin/src/main/resources/application.yml

@@ -5,4 +5,8 @@ server:
 spring:
   profiles:
     active: dev
-    include: common,config-dev
+#    active: druid-hdt
+#    active: druid-yzt
+#    active: druid-sxjz
+#    active: druid-sft
+

+ 6 - 6
fs-admin/src/main/resources/logback.xml

@@ -19,8 +19,8 @@
 		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
             <!-- 日志文件名格式 -->
 			<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
-			<!-- 日志最大的历史 60天 -->
-			<maxHistory>60</maxHistory>
+			<!-- 日志最大的历史 30 -->
+			<maxHistory>30</maxHistory>
 		</rollingPolicy>
 		<encoder>
 			<pattern>${log.pattern}</pattern>
@@ -41,8 +41,8 @@
         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
             <!-- 日志文件名格式 -->
             <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
-			<!-- 日志最大的历史 60天 -->
-			<maxHistory>60</maxHistory>
+			<!-- 日志最大的历史 30 -->
+			<maxHistory>30</maxHistory>
         </rollingPolicy>
         <encoder>
             <pattern>${log.pattern}</pattern>
@@ -63,8 +63,8 @@
         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
             <!-- 按天回滚 daily -->
             <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
-            <!-- 日志最大的历史 60天 -->
-            <maxHistory>60</maxHistory>
+            <!-- 日志最大的历史 30 -->
+            <maxHistory>30</maxHistory>
         </rollingPolicy>
         <encoder>
             <pattern>${log.pattern}</pattern>

+ 0 - 1
fs-ai-chat/src/main/resources/application.yml

@@ -5,4 +5,3 @@ server:
 spring:
   profiles:
     active: dev
-    include: common,config-dev

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

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

+ 5 - 0
fs-common/src/main/java/com/fs/common/config/FSConfig.java

@@ -148,4 +148,9 @@ public class FSConfig
     {
         return getProfile() + "/upload";
     }
+
+    public static String getQrPath()
+    {
+        return getProfile() + "/qr";
+    }
 }

+ 3 - 2
fs-common/src/main/java/com/fs/common/constant/FsConstants.java

@@ -1,12 +1,13 @@
 package com.fs.common.constant;
 
 
-public interface FsConstants
-{
+public interface FsConstants {
     String REDIS_INQUIRY_ORDER_OUTTIME_UNPAY = "inquiry:order:unpay:";
     String REDIS_INQUIRY_ORDER_OUTTIME_UNRECEIVE = "inquiry:order:unreceive:";
     String REDIS_PACKAGE_ORDER_UNPAY = "package:order:unpay:";
     String REDIS_CHAT_SESSION = "chat:session:";
     String REDIS_CHAT_NEXTCURSOR = "chat:nextcursor:";
     String REDIS_QW_appKey_Active = "qwActive:";
+
+    String FRIEND_WELCOME_VIDEO_KEY = "friend:welcome:";
 }

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

@@ -122,7 +122,7 @@ public class SysUser extends BaseEntity
 
     public static boolean isAdmin(Long userId)
     {
-        return userId != null && (1L == userId || 145L == userId);
+        return userId != null && (1L == userId);
     }
 
     public Long getDeptId()

+ 115 - 19
fs-common/src/main/java/com/fs/common/utils/DateUtils.java

@@ -3,13 +3,16 @@ package com.fs.common.utils;
 import java.lang.management.ManagementFactory;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
-import java.util.*;
-
+import java.time.*;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.Calendar;
+import java.util.Date;
 import org.apache.commons.lang3.time.DateFormatUtils;
 
 /**
  * 时间工具类
- * 
+ *
 
  */
 public class DateUtils extends org.apache.commons.lang3.time.DateUtils
@@ -23,15 +26,16 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
     public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
 
     public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
-    
+
     private static String[] parsePatterns = {
-            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", 
+            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
             "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
             "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
+    private static final DateTimeFormatter OUTPUT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
 
     /**
      * 获取当前Date型日期
-     * 
+     *
      * @return Date() 当前日期
      */
     public static Date getNowDate()
@@ -41,7 +45,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
 
     /**
      * 获取当前日期, 默认格式为yyyy-MM-dd
-     * 
+     *
      * @return String
      */
     public static String getDate()
@@ -122,7 +126,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
             return null;
         }
     }
-    
+
     /**
      * 获取服务器启动时间
      */
@@ -153,20 +157,112 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
         // long sec = diff % nd % nh % nm / ns;
         return day + "天" + hour + "小时" + min + "分钟";
     }
+    public static int getAge(Date birthDay) {
+        Calendar cal = Calendar.getInstance();
+        //出生日期晚于当前时间,无法计算
+        if (cal.before(birthDay)) {
+            throw new IllegalArgumentException(
+                    "The birthDay is before Now.It's unbelievable!");
+        }
+        //当前年份
+        int yearNow = cal.get(Calendar.YEAR);
+        //当前月份
+        int monthNow = cal.get(Calendar.MONTH);
+        //当前日期
+        int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH);
+        cal.setTime(birthDay);
+        int yearBirth = cal.get(Calendar.YEAR);
+        int monthBirth = cal.get(Calendar.MONTH);
+        int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
+        //计算整岁数
+        int age = yearNow - yearBirth;
+        if (monthNow <= monthBirth) {
+            if (monthNow == monthBirth) {
+                if (dayOfMonthNow < dayOfMonthBirth) {
+                    //当前日期在生日之前,年龄减一
+                    age--;
+                }
+            } else {
+                //当前月份在生日之前,年龄减一
+                age--;
 
+            }
+        }
+        return age;
+    }
+    /**
+     * 计算给定日期与当前日期相差的天数 (基于日历日期)。
+     * 例如:昨天 23:59 和 今天 00:01 相差 1 天。
+     *
+     * @param createTime 起始时间 (java.util.Date)
+     * @return 相差的天数 (long)。如果 createTime 为 null,返回 0。
+     *         如果 createTime 在当前时间之后,结果为负数。
+     */
+    public static long getDaysDifferenceFromNow(Date createTime) {
+        if (createTime == null) {
+            return 0; // 或者根据业务抛出异常或返回特定值
+        }
+        // 1. 将 java.util.Date 转换为 Instant (时间线上的一个点)
+        Instant createInstant = createTime.toInstant();
+        // 2. 获取当前时间的 Instant
+        Instant nowInstant = Instant.now();
+        // 3. 指定时区 (非常重要!否则会使用系统默认时区,可能导致不一致)
+        //    建议使用一个明确的时区,例如服务器所在时区或业务标准时区
+        ZoneId zoneId = ZoneId.systemDefault(); // 或者 ZoneId.of("Asia/Shanghai");
+        // 4. 将 Instant 转换为 LocalDate (只包含年月日,忽略时分秒)
+        LocalDate createDate = createInstant.atZone(zoneId).toLocalDate();
+        LocalDate nowDate = nowInstant.atZone(zoneId).toLocalDate(); // 使用相同的时区
+        // 5. 使用 ChronoUnit.DAYS.between 计算两个 LocalDate 之间的天数差
+        long daysBetween = ChronoUnit.DAYS.between(createDate, nowDate);
+        return daysBetween;
+    }
 
-    public static List<String> getDayListOfMonth(Date date) {
-        List<String> list = new ArrayList();
-        Calendar aCalendar = Calendar.getInstance(Locale.CHINA);
-        aCalendar.setTime(date);
-        int year = aCalendar.get(Calendar.YEAR);//年份
-        int month = aCalendar.get(Calendar.MONTH) + 1;//月份
-        int day = aCalendar.getActualMaximum(Calendar.DATE);
-        for (int i = 1; i <= day; i++) {
-            String aDate = String.valueOf(year) + "-" + month + "-" + i;
-            list.add(aDate);
+    /**
+     * 获取指定日期当天的开始时间字符串 (格式: yyyy-MM-dd 00:00:00)
+     *
+     * @param date 输入的 Date 对象
+     * @return 当天开始时间的字符串表示,如果输入为 null 则返回 null
+     */
+    public static String getStartOfDayString(Date date) {
+        // 使用 Objects.requireNonNull(date, "输入日期不能为 null"); 如果希望在输入为 null 时抛出异常
+        if (date == null) {
+            return null;
         }
-        return  list;
+        // 1. 将 Date 转换为更现代的 LocalDateTime (考虑时区)
+        //    使用系统默认时区。如果需要特定时区,请替换 ZoneId.systemDefault()
+        //    例如:ZoneId.of("Asia/Shanghai")
+        LocalDateTime localDateTime = date.toInstant()
+                .atZone(ZoneId.systemDefault())
+                .toLocalDateTime();
+        // 2. 获取该日期的开始时间 (00:00:00)
+        LocalDateTime startOfDay = localDateTime.toLocalDate().atStartOfDay();
+        // 3. 格式化为目标字符串
+        return startOfDay.format(OUTPUT_FORMATTER);
     }
+    /**
+     * 获取指定日期当天的结束时间字符串 (格式: yyyy-MM-dd 23:59:59)
+     *
+     * @param date 输入的 Date 对象
+     * @return 当天结束时间的字符串表示,如果输入为 null 则返回 null
+     */
+    public static String getEndOfDayString(Date date) {
+        if (date == null) {
+            return null;
+        }
+        // 1. 将 Date 转换为 LocalDateTime (考虑时区)
+        LocalDateTime localDateTime = date.toInstant()
+                .atZone(ZoneId.systemDefault())
+                .toLocalDateTime();
+        // 2. 获取该日期的 LocalDate 部分
+        LocalDate localDate = localDateTime.toLocalDate();
+        // 3. 创建当天的结束时间 (23:59:59)
+        LocalDateTime endOfDay = LocalDateTime.of(localDate, LocalTime.of(23, 59, 59));
+        // 注意: 如果需要的是一天的最后一纳秒 (23:59:59.999999999),可以使用:
+        // LocalDateTime endOfDay = LocalDateTime.of(localDate, LocalTime.MAX);
+        // 但根据 "23:59:59" 的要求,明确指定秒更符合。
+        // 4. 格式化为目标字符串
+        return endOfDay.format(OUTPUT_FORMATTER);
+    }
+
 
 }

+ 17 - 0
fs-common/src/main/java/com/fs/common/utils/PatternUtils.java

@@ -0,0 +1,17 @@
+package com.fs.common.utils;
+
+import java.util.regex.Pattern;
+
+public class PatternUtils {
+
+    private final static Pattern PWD = Pattern.compile("^(?=.*[A-Za-z])(?=.*\\d)(?=.*[^A-Za-z0-9]).{8,20}$");
+
+    /**
+     * 校验密码是否符合条件
+     * @param value 密码
+     * @return boolean
+     */
+    public static boolean checkPassword(String value) {
+        return PWD.matcher(value).matches();
+    }
+}

+ 3 - 0
fs-company-app/src/main/java/com/fs/app/annotation/Login.java

@@ -9,4 +9,7 @@ import java.lang.annotation.*;
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 public @interface Login {
+    // 添加一个判断 是否是小程序登录
+    boolean isMiniLogin() default false;
+
 }

+ 18 - 0
fs-company-app/src/main/java/com/fs/app/config/ImageStorageConfig.java

@@ -0,0 +1,18 @@
+package com.fs.app.config;
+
+import lombok.Getter;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+@Getter
+@Configuration
+public class ImageStorageConfig {
+
+    // 直接返回配置的路径
+    @Value("${image.storage.local-path}")
+    private String localPath;
+
+    @Value("${image.storage.server-path}")
+    private String serverPath;
+
+}

+ 26 - 1
fs-company-app/src/main/java/com/fs/app/controller/AppBaseController.java

@@ -1,9 +1,14 @@
 package com.fs.app.controller;
 
 
+import com.fs.app.exception.FSException;
 import com.fs.app.utils.JwtUtils;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.ServletUtils;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.ICompanyUserService;
+import com.fs.his.domain.FsUser;
+import com.fs.his.service.IFsUserService;
 import io.jsonwebtoken.Claims;
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -14,6 +19,17 @@ public class AppBaseController {
 	@Autowired
 	RedisCache redisCache;
 
+	@Autowired
+	private ICompanyUserService companyUserService;
+	@Autowired
+	private IFsUserService userService;
+	public Long getCompanyId() {
+		String headValue =  ServletUtils.getRequest().getHeader("APPToken");
+		Claims claims=jwtUtils.getClaimByToken(headValue);
+		String userId = claims.getSubject().toString();
+		Long companyId =(Long)redisCache.getCacheObject("companyId:"+userId);
+		return companyId;
+	}
 	public String getUserId()
 	{
 		String headValue =  ServletUtils.getRequest().getHeader("APPToken");
@@ -21,6 +37,15 @@ public class AppBaseController {
 		String userId = claims.getSubject().toString();
 		return userId;
 	}
-
+	//获取商城手机号
+	public Long getUserId(Long companyUserId)
+	{
+		CompanyUser companyUser=companyUserService.selectCompanyUserById(companyUserId);
+		FsUser user=userService.selectFsUserByPhone(companyUser.getPhonenumber());
+		if(user==null){
+			throw new FSException("未授权,请用员工手机号登录商城");
+		}
+		return user.getUserId();
+	}
 
 }

+ 89 - 0
fs-company-app/src/main/java/com/fs/app/controller/CompanyTagController.java

@@ -0,0 +1,89 @@
+package com.fs.app.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.fs.app.annotation.Login;
+import com.fs.common.core.domain.R;
+import com.fs.common.exception.CustomException;
+import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.CompanyTag;
+import com.fs.company.service.ICompanyTagService;
+import com.fs.company.service.ICompanyTagUserService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Api(tags = "企业标签接口")
+@RestController
+@RequestMapping("/app/companyTag")
+@AllArgsConstructor
+public class CompanyTagController extends AppBaseController {
+
+    private final ICompanyTagService companyTagService;
+    private final ICompanyTagUserService companyTagUserService;
+
+    /**
+     * 查询公司标签列表
+     */
+    @Login
+    @GetMapping("/list")
+    @ApiOperation("查询公司标签列表")
+    public R list(@RequestParam(required = false) String keyword,
+                  @RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                  @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
+        log.debug("查询公司标签列表 keyword: {}, pageNum: {}, pageSize: {}", keyword, pageNum, pageSize);
+
+        Map<String, Object> params = new HashMap<>();
+        params.put("companyId", getCompanyId());
+        if (StringUtils.isNotBlank(keyword)) {
+            params.put("keyword", keyword.split(","));
+        }
+
+        PageHelper.startPage(pageNum, pageSize);
+        List<CompanyTag> list = companyTagService.selectCompanyTagListByMap(params);
+        return R.ok().put("data", new PageInfo<>(list));
+    }
+
+    /**
+     * 新增公司标签
+     */
+    @Login
+    @PostMapping("/add")
+    @ApiOperation("新增公司标签")
+    public R add(@RequestBody CompanyTag companyTag) throws CustomException {
+        log.debug("新增公司标签 companyTag: {}", JSON.toJSONString(companyTag));
+        companyTag.setCompanyId(getCompanyId());
+        companyTagService.insertCompanyTag(companyTag);
+        return R.ok();
+    }
+
+    /**
+     * 删除公司标签
+     */
+    @Login
+    @PostMapping("/delete")
+    @ApiOperation("删除公司标签")
+    public R remove(@RequestParam List<Long> tagIds) {
+        log.debug("删除公司标签 tagIds: {}", tagIds);
+        companyTagService.deleteCompanyTagByTagIds(tagIds);
+        return R.ok();
+    }
+
+    @Login
+    @GetMapping("/tagSubUsers")
+    @ApiOperation("标签下会员列表")
+    public R tagSubUsers(@RequestParam List<Long> tagId) {
+        Map<String, Object> params = new HashMap<>();
+        params.put("tagIds", tagId);
+        params.put("companyId", getCompanyId());
+        return R.ok().put("data", companyTagUserService.selectUserListByMap(params));
+    }
+}

+ 311 - 0
fs-company-app/src/main/java/com/fs/app/controller/CompanyUserController.java

@@ -0,0 +1,311 @@
+package com.fs.app.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.fs.app.annotation.Login;
+import com.fs.app.param.ChangeUserDeptAndPostParam;
+import com.fs.app.param.CompanyUserChangeApplyParam;
+import com.fs.app.param.CompanyUserParam;
+import com.fs.app.param.CompanyUserUpdateParam;
+import com.fs.app.service.IAppService;
+import com.fs.app.vo.CompanySubUserVO;
+import com.fs.common.annotation.RepeatSubmit;
+import com.fs.common.constant.UserConstants;
+import com.fs.common.core.domain.R;
+import com.fs.common.exception.ServiceException;
+import com.fs.common.utils.PatternUtils;
+import com.fs.common.utils.bean.BeanUtils;
+import com.fs.company.domain.*;
+import com.fs.company.mapper.CompanyRoleMapper;
+import com.fs.company.service.ICompanyDeptService;
+import com.fs.company.service.ICompanyService;
+import com.fs.company.service.ICompanyUserChangeApplyService;
+import com.fs.company.service.ICompanyUserService;
+import com.fs.company.vo.CompanyUserChangeApplyVO;
+import com.fs.core.security.SecurityUtils;
+import com.fs.course.service.IFsCourseRedPacketLogService;
+import com.fs.course.service.IFsCourseWatchLogService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDate;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Api(tags = "企业用户接口")
+@RestController
+@RequestMapping("/app/companyUser")
+@AllArgsConstructor
+public class CompanyUserController extends AppBaseController {
+
+    private final ICompanyUserService companyUserService;
+    private final ICompanyService companyService;
+    private final ICompanyDeptService companyDeptService;
+    private final IFsCourseWatchLogService courseWatchLogService;
+    private final IFsCourseRedPacketLogService courseRedPacketLogService;
+    private final ICompanyUserChangeApplyService companyUserChangeApplyService;
+    private final CompanyRoleMapper companyRoleMapper;
+    private final IAppService appService;
+
+    @Login
+    @ApiOperation("查询用户列表")
+    @GetMapping("/getCompanyUserList")
+    public R getCompanyUserList(@RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                                @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
+        log.debug("查询用户列表 pageNum: {}, pageSize: {}", pageNum, pageSize);
+
+        Long userId = Long.parseLong(getUserId());
+        CompanyUser companyUser = companyUserService.selectCompanyUserById(userId);
+        List<CompanyRole> companyRoles = companyRoleMapper.selectRolePermissionByUserId(userId);
+        List<CompanyUser> companyUsers;
+
+        // 判断是否管理员 或者包含 1:全部数据权限
+        if (companyUser.isAdmin() || companyRoles.stream().anyMatch(r -> "1".equals(r.getDataScope()))) {
+            PageHelper.startPage(pageNum, pageSize);
+            companyUsers = companyUserService.getCompanyUserListByDeptId(null);
+        }
+        // 判断是否包含 3:本部门数据权限 4:本部门及以下数据权限
+        else if (companyRoles.stream().anyMatch(r -> "3".equals(r.getDataScope()) || "4".equals(r.getDataScope()))) {
+            PageHelper.startPage(pageNum, pageSize);
+            companyUsers = companyUserService.getCompanyUserListByDeptId(companyUser.getDeptId());
+        }
+        // 默认空 -- 判断是否包含 5:仅可查看本人
+        else {
+            companyUsers = new ArrayList<>();
+        }
+        PageInfo<CompanyUser> page = new PageInfo<>(companyUsers);
+
+        // 转换对象
+        List<CompanySubUserVO> users = page.getList().stream().map(u -> {
+            CompanySubUserVO vo = new CompanySubUserVO();
+            BeanUtils.copyProperties(u, vo);
+
+            Map<String, Object> params = new HashMap<>();
+            params.put("date", LocalDate.now());
+            params.put("companyUserId", u.getUserId());
+            params.put("logTypes", Arrays.asList(1,2,4));
+
+            // 今日观看人数
+            int count = courseWatchLogService.countByMap(params);
+            vo.setTodayWatchCount(count);
+
+            // 今日完播人数
+            params.put("logTypes", Collections.singletonList(2));
+            int finishCount = courseWatchLogService.countByMap(params);
+            vo.setTodayFinishCount(finishCount);
+
+            // 今日完播率
+            BigDecimal rate = count > 0 ? BigDecimal.valueOf(finishCount)
+                    .divide(BigDecimal.valueOf(count), 2, RoundingMode.HALF_UP)
+                    .multiply(BigDecimal.valueOf(100)) : BigDecimal.ZERO;
+            vo.setTodayFinishRate(rate);
+
+            // 今日红包金额
+            BigDecimal amount = courseRedPacketLogService.getSumByCompanyUserIdId(u.getUserId());
+            vo.setTodayRedPacketAmount(amount);
+
+            // 是否存在会员转移申请
+            Wrapper<CompanyUserChangeApply> applyWrapper = Wrappers.<CompanyUserChangeApply>lambdaQuery()
+                    .eq(CompanyUserChangeApply::getFrom, u.getUserId())
+                    .orderByDesc(CompanyUserChangeApply::getApplyTime)
+                    .last("limit 1");
+            CompanyUserChangeApply apply = companyUserChangeApplyService.getOne(applyWrapper);
+            int applyStatus = 3; // 不存在
+            if (Objects.nonNull(apply)) {
+                applyStatus = apply.getStatus();
+            }
+            vo.setApplyStatus(applyStatus);
+
+            return vo;
+        }).collect(Collectors.toList());
+
+        PageInfo<CompanySubUserVO> pageInfo = new PageInfo<>();
+        BeanUtils.copyProperties(page, pageInfo);
+        pageInfo.setList(users);
+
+        return R.ok().put("data", pageInfo);
+    }
+
+    @Login
+    @ApiOperation("获取销售信息")
+    @GetMapping("/getCompanyUserInfo")
+    public R getCompanyUserInfo(@ApiParam(name = "companyUserId", value = "销售用户ID", required = true)
+                                @RequestParam Long companyUserId) {
+        return R.ok().put("data", companyUserService.selectCompanyUserById(companyUserId));
+    }
+
+    @Login
+    @ApiOperation("修改用户信息")
+    @PostMapping("/updateUserInfo")
+    public R updateUserInfo(@Valid @RequestBody CompanyUserUpdateParam param) {
+        CompanyUser companyUser = companyUserService.selectCompanyUserById(param.getUserId());
+        if (Objects.isNull(companyUser)) {
+            throw new ServiceException("用户不存在");
+        }
+
+        companyUser.setUserId(param.getUserId());
+        companyUser.setNickName(param.getNickName());
+        companyUser.setPhonenumber(param.getPhoneNumber());
+        companyUser.setRemark(param.getRemark());
+        companyUserService.updateCompanyUser(companyUser);
+        return R.ok();
+    }
+
+    @ApiOperation("注册")
+    @PostMapping("/resisterCompanyUser")
+    public R resisterCompanyUser(@Valid @RequestBody CompanyUserParam param) {
+        Company company = companyService.selectCompanyById(param.getCompanyId());
+        if (Objects.isNull(company)) {
+            return R.error("公司不存在");
+        }
+
+        // 判断用户数量是否已达到上线
+        Integer count = companyUserService.selectCompanyUserCountByCompanyId(param.getCompanyId());
+        if(count > company.getLimitUserCount()) {
+            return R.error("用户数量已达到上限");
+        }
+
+        if (UserConstants.NOT_UNIQUE.equals(String.valueOf(companyUserService.checkUserName(param.getPhoneNumber())))) {
+            return R.error("注册用户'" + param.getPhoneNumber() + "'失败,登录账号已存在");
+        }
+
+        // 密码校验
+        if (!PatternUtils.checkPassword(param.getPassword())) {
+            return R.error("密码格式不正确,需包含字母、数字和特殊字符,长度为 8-20位");
+        }
+
+        // 组装参数
+        CompanyUser companyUser = new CompanyUser();
+        BeanUtils.copyProperties(param, companyUser);
+
+        companyUser.setUserName(param.getPhoneNumber());
+        companyUser.setPhonenumber(param.getPhoneNumber());
+        companyUser.setPassword(SecurityUtils.encryptPassword(companyUser.getPassword()));
+        companyUser.setCreateTime(new Date());
+        companyUser.setIsAudit(0);
+
+        // 部门
+        CompanyDept dept = companyDeptService.getDefaultCompanyDeptByCompanyId(param.getCompanyId());
+        if (Objects.nonNull(dept)) {
+            companyUser.setDeptId(dept.getDeptId());
+        }
+
+        companyUserService.insertUser(companyUser);
+        return R.ok();
+    }
+
+    @Login
+    @ApiOperation("接收群管列表")
+    @GetMapping("/companyUserListByCompanyId")
+    public R CompanyUserListByCompanyId(){
+        // 查询公司下销售
+        CompanyUser companyUser = new CompanyUser();
+        companyUser.setCompanyId(getCompanyId());
+        List<CompanyUser> companyUsers = companyUserService.selectCompanyUserList(companyUser);
+        return R.ok().put("data",companyUsers);
+    }
+
+    @Login
+    @RepeatSubmit
+    @ApiOperation("更换会员归属申请")
+    @PostMapping("/changeUserParentApply")
+    public R changeVipUser(@Valid @RequestBody CompanyUserChangeApplyParam param) {
+        // 参数校验
+        CompanyUser fromUser = companyUserService.selectCompanyUserById(param.getFrom());
+        if (Objects.isNull(fromUser)) {
+            return R.error("原归属销售不存在");
+        }
+
+        CompanyUser toUser = companyUserService.selectCompanyUserById(param.getTo());
+        if (Objects.isNull(toUser)) {
+            throw new ServiceException("申请更换归属销售不存在");
+        }
+
+        if (param.getType() != 0 && param.getType() != 1) {
+            throw new ServiceException("类型不正确");
+        }
+
+        if (param.getType() == 1 && (Objects.isNull(param.getIds()) || param.getIds().isEmpty())) {
+            throw new ServiceException("请先选择会员");
+        }
+
+        // 存在待审核的申请不能再次申请
+        Wrapper<CompanyUserChangeApply> applyWrapper = Wrappers.<CompanyUserChangeApply>lambdaQuery()
+                .eq(CompanyUserChangeApply::getFrom, fromUser.getUserId())
+                .eq(CompanyUserChangeApply::getStatus, 0);
+        if (companyUserChangeApplyService.count(applyWrapper) > 0) {
+            throw new ServiceException("存在待审核申请");
+        }
+
+        CompanyUser companyUser = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
+
+        // 添加申请
+        companyUserChangeApplyService.apply(param.getFrom(), param.getTo(), param.getType(), param.getIds(), companyUser.getCompanyId(), companyUser.getUserName());
+        return R.ok();
+    }
+
+    @Login
+    @ApiOperation("申请列表")
+    @GetMapping("/applyList")
+    public R applyList(@RequestParam(required = false) Integer status,
+                       @RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                       @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
+        log.debug("申请列表 status: {}, pageNum: {}, pageSize: {}", status, pageNum, pageSize);
+
+        Map<String, Object> map = new HashMap<>();
+        map.put("status", status);
+        map.put("companyId", getCompanyId());
+
+        PageHelper.startPage(pageNum, pageSize);
+        List<CompanyUserChangeApplyVO> list = companyUserChangeApplyService.selectApplyListByMap(map);
+        PageInfo<CompanyUserChangeApplyVO> page = new PageInfo<>(list);
+        return R.ok().put("data", page);
+    }
+
+    @Login
+    @ApiOperation("部门树列表")
+    @GetMapping("/deptList")
+    public R deptList() {
+        return R.ok().put("data", appService.getDeptTreeSelect(getCompanyId()));
+    }
+
+    @Login
+    @ApiOperation("岗位列表")
+    @GetMapping("/postList")
+    public R postList() {
+        return R.ok().put("data", appService.postList(getCompanyId()));
+    }
+
+    @Login
+    @ApiOperation("角色列表")
+    @GetMapping("/roleList")
+    public R roleList() {
+        return R.ok().put("data", appService.roleList(getCompanyId()));
+    }
+
+    @Login
+    @ApiOperation("修改用户部门和岗位")
+    @PostMapping("/changeUserDeptAndPost")
+    public R changeUserDeptAndPost(@Valid @RequestBody ChangeUserDeptAndPostParam param) {
+        log.debug("changeUserDeptAndPost param: {}", JSON.toJSONString(param));
+
+        CompanyUser companyUser = companyUserService.selectCompanyUserByUserId(Long.parseLong(getUserId()));
+        if (!companyUser.isAdmin()) {
+            return R.error("没有权限");
+        }
+
+        appService.changeUserDeptAndPost(param);
+        return R.ok();
+    }
+}

+ 334 - 0
fs-company-app/src/main/java/com/fs/app/controller/CrmController.java

@@ -0,0 +1,334 @@
+package com.fs.app.controller;
+
+
+import com.fs.app.annotation.Login;
+import com.fs.app.utils.JwtUtils;
+import com.fs.common.OrderUtils;
+import com.fs.common.annotation.DataScope;
+import com.fs.common.core.domain.R;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.param.CompanySmsLogsListQueryParam;
+import com.fs.company.param.CompanyVoiceLogsListQueryParam;
+import com.fs.company.service.ICompanySmsLogsService;
+import com.fs.company.service.ICompanyUserService;
+import com.fs.company.service.ICompanyVoiceLogsService;
+import com.fs.company.vo.CompanySmsLogsListQueryVO;
+import com.fs.company.vo.CompanyVoiceLogsListVO;
+import com.fs.crm.domain.CrmCustomer;
+import com.fs.crm.domain.CrmCustomerContacts;
+import com.fs.crm.domain.CrmCustomerExt;
+import com.fs.crm.param.*;
+import com.fs.crm.service.*;
+import com.fs.crm.vo.*;
+import com.fs.his.service.IFsStoreOrderService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+
+import static com.fs.common.constant.Constants.PAGE_SIZE;
+
+
+@Api("客户接口")
+@RestController
+@RequestMapping(value="/app/crm")
+public class CrmController extends  AppBaseController {
+	@Autowired
+	private ICrmCustomerContactsService crmCustomerContactsService;
+	@Autowired
+	private ICrmCustomerExtService crmCustomerExtService;
+	@Autowired
+    JwtUtils jwtUtils;
+	@Autowired
+	ICrmCustomerService crmCustomerService;
+	@Autowired
+	ICrmCustomerUserService crmCustomerUserService;
+	@Autowired
+	ICompanyUserService companyUserService;
+	@Autowired
+	private ICrmCustomerLogsService crmCustomerLogsService;
+	@Autowired
+	private ICrmCustomerVisitService crmCustomerVisitService;
+	@Autowired
+	ICompanyVoiceLogsService companyVoiceLogsService;
+	@Autowired
+	ICompanySmsLogsService companySmsLogsService;
+	@Autowired
+	IFsStoreOrderService storeOrderService;
+
+	@Login
+	@ApiOperation("获取公海客户列表")
+	@GetMapping("/getFullCustomerList")
+	@DataScope(deptAlias = "c",userAlias = "c")
+	public R getFullCustomerList(CrmFullCustomerListQueryParam param){
+		PageHelper.startPage(param.getPage(), param.getPageSize());
+		param.setCompanyId(getCompanyId());
+		if(getCompanyId()==116){   // 河北湘银信息咨询服务有限公司(JZ-1)客户假删除不显示
+			param.setCompanyId(0L);
+		}
+		List<CrmFullCustomerListQueryVO> list = crmCustomerService.selectCrmFullCustomerListQuery(param);
+		PageInfo<CrmFullCustomerListQueryVO> listPageInfo=new PageInfo<>(list);
+		return R.ok().put("data",listPageInfo);
+	}
+
+	@Login
+	@ApiOperation("获取我的客户列表")
+	@GetMapping("/getMyCustomerList")
+	public R getMyCustomerList(CrmMyCustomerListQueryParam param){
+		PageHelper.startPage(param.getPage(), param.getPageSize());
+		param.setCompanyId(getCompanyId());
+		if(getCompanyId()==116){   // 河北湘银信息咨询服务有限公司(JZ-1)客户假删除不显示
+			param.setCompanyId(0L);
+		}
+		param.setCompanyUserId(Long.parseLong(getUserId()));
+		List<CrmMyCustomerListQueryVO> list = crmCustomerService.selectCrmMyCustomerListQuery(param);
+		PageInfo<CrmMyCustomerListQueryVO> listPageInfo=new PageInfo<>(list);
+		return R.ok().put("data",listPageInfo);
+	}
+
+	@Login
+	@ApiOperation("获取客户详情")
+	@GetMapping("/getCustomerDetails")
+	public R getMyCustomerDetails(
+			HttpServletRequest request,
+			@ApiParam(required = true, name = "customerId", value = "customerId")
+			@RequestParam(value = "customerId", required = false) Long customerId){
+		CrmCustomer customer=crmCustomerService.selectCrmCustomerById(customerId);
+		Boolean isReceive=false;
+		if(customer.getIsReceive()!=null&&customer.getIsReceive()==1&&customer.getReceiveUserId()!=null&&getUserId().equals(customer.getReceiveUserId().toString())){
+			isReceive=true;
+		}
+		return R.ok().put("data",customer).put("isReceive",isReceive);
+	}
+	/**
+	 * 修改客户
+	 */
+	@Login
+	@ApiOperation("编辑客户")
+	@PostMapping("/edit")
+	public R edit(@RequestBody CrmCustomer crmCustomer)
+	{
+		if(crmCustomerService.updateCrmCustomer(crmCustomer)>0){
+			return R.ok();
+		}
+		else{
+			return R.error();
+		}
+	}
+	@Login
+	@ApiOperation("添加客户")
+	@PostMapping("/add")
+	public R add(@RequestBody CrmCustomer crmCustomer)
+	{
+		CompanyUser companyUser=companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
+		crmCustomer.setDeptId(companyUser.getDeptId());
+		crmCustomer.setCustomerCode(OrderUtils.getOrderNo());
+		crmCustomer.setIsLine(0);
+		crmCustomer.setIsDel(0);
+		crmCustomer.setIsReceive(0);
+		crmCustomer.setStatus(1);
+		crmCustomer.setDeptId(companyUser.getDeptId());
+		crmCustomer.setCompanyId(getCompanyId());
+		crmCustomer.setCreateUserId(Long.parseLong(getUserId()));
+		if(crmCustomerService.insertCrmCustomer(crmCustomer)>0){
+			CrmCustomeReceiveParam param=new CrmCustomeReceiveParam();
+			String operName = companyUser.getNickName();
+			param.setCompanyId(companyUser.getCompanyId());
+			param.setCompanyUserId(companyUser.getUserId());
+			param.setCustomerId(crmCustomer.getCustomerId());
+			crmCustomerService.receive(param,operName);
+			return R.ok();
+		}
+		else{
+			return R.error();
+		}
+	}
+
+	//认领
+	@Login
+	@ApiOperation("认领")
+	@PostMapping("/receive")
+	public R receive(@RequestBody CrmCustomeReceiveParam param)
+	{
+		CompanyUser companyUser=companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
+		String operName = companyUser.getNickName();
+		param.setCompanyId(companyUser.getCompanyId());
+		param.setCompanyUserId(companyUser.getUserId());
+		return crmCustomerService.receive(param,operName);
+
+	}
+	//回收
+	@Login
+	@PostMapping("/recover")
+	@ApiOperation("回收公海")
+	public R recover(@RequestBody CrmCustomeRecoverParam param)
+	{
+		CompanyUser companyUser=companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
+		String operName = companyUser.getNickName();
+		param.setCompanyId(companyUser.getCompanyId());
+		param.setCompanyUserId(companyUser.getUserId());
+		return crmCustomerService.recover(param,operName);
+
+	}
+
+	@Login
+	@PostMapping("/assignUser")
+	@ApiOperation("转移用户")
+	public R assignUser(@RequestBody CrmCustomeAssignUserParam param)
+	{
+		CompanyUser companyUser=companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
+		String operName = companyUser.getNickName();
+		return crmCustomerService.assignUser(param,operName);
+
+	}
+
+	@GetMapping("/getCustomerLogsList")
+	@ApiOperation("获取客户日志")
+	public R getCustomerLogsList(CrmCustomerLogsListQueryParam param)
+	{
+		PageHelper.startPage(param.getPage(), PAGE_SIZE);
+		List<CrmCustomerLogsListQueryVO> list = crmCustomerLogsService.selectCrmCustomerLogsListQuery(param);
+		PageInfo<CrmCustomerLogsListQueryVO> listPageInfo=new PageInfo<>(list);
+		return R.ok().put("data",listPageInfo);
+	}
+
+	@GetMapping("/getCustomerVisitList")
+	@ApiOperation("获取客户跟进记录")
+	public R getCustomerVisitList(CrmCustomerVisitListQueryParam param)
+	{
+		PageHelper.startPage(param.getPage(), PAGE_SIZE);
+		param.setCompanyId(getCompanyId());
+		List<CrmCustomerVisitListVO> list = crmCustomerVisitService.selectCrmCustomerVisitListQuery(param);
+		PageInfo<CrmCustomerVisitListVO> listPageInfo=new PageInfo<>(list);
+		return R.ok().put("data",listPageInfo);
+	}
+	@Login
+	@ApiOperation("提交跟进")
+	@PostMapping("/addVisit")
+	public R addVisit(@RequestBody CrmCustomerVisitAddParam param) {
+		param.setCompanyUserId(Long.parseLong(getUserId()));
+		return crmCustomerVisitService.addVisit(param);
+	}
+
+
+	@Login
+	@GetMapping("/getCustomerVoiceLogsList")
+	@ApiOperation("获取客户通话记录")
+	public R getCustomerVoiceLogsList(CompanyVoiceLogsListQueryParam param) {
+		PageHelper.startPage(param.getPage(), PAGE_SIZE);
+		param.setCompanyId(getCompanyId());
+		List<CompanyVoiceLogsListVO> list = companyVoiceLogsService.selectCompanyVoiceLogsListQuery(param);
+		PageInfo<CompanyVoiceLogsListVO> listPageInfo=new PageInfo<>(list);
+		return R.ok().put("data",listPageInfo);
+	}
+
+	@Login
+	@GetMapping("/getCustomerSmsLogsList")
+	@ApiOperation("获取客户短信记录")
+	public R getCustomerSmsLogsList(CompanySmsLogsListQueryParam param) {
+		PageHelper.startPage(param.getPage(), PAGE_SIZE);
+		param.setCompanyId(getCompanyId());
+		List<CompanySmsLogsListQueryVO> list = companySmsLogsService.selectCompanySmsLogsListQuery(param);
+		PageInfo<CompanySmsLogsListQueryVO> listPageInfo=new PageInfo<>(list);
+		return R.ok().put("data",listPageInfo);
+	}
+
+	@Login
+	@PostMapping("/editTags")
+	@ApiOperation("修改标签")
+	public R editTags(@RequestBody CrmCustomerEditTagsParam param) {
+		return crmCustomerService.editTags(param);
+	}
+
+
+	@Login
+	@ApiOperation("获取自定义字段列表")
+	@GetMapping("/getCustomerExt")
+	public R getCustomerExt(CrmCustomerExt crmCustomerExt) {
+		CrmCustomerExt map=new CrmCustomerExt();
+		map.setStatus(1);
+		map.setCompanyId(getCompanyId());
+		List<CrmCustomerExt> list = crmCustomerExtService.selectCrmCustomerExtList(map);
+		return R.ok().put("data",list);
+	}
+
+
+
+ 	@Login
+	@ApiOperation("获取客户联系人")
+	@GetMapping("/getCustomerContacts")
+	public R getCustomerContacts(CrmCustomerContactsListQueryParam param) {
+		PageHelper.startPage(param.getPage(), PAGE_SIZE);
+		param.setCompanyId(getCompanyId());
+		List<CrmCustomerContactsListQueryVO> list = crmCustomerContactsService.selectCrmCustomerContactsListQuery(param);
+		PageInfo<CrmCustomerContactsListQueryVO> listPageInfo=new PageInfo<>(list);
+		return R.ok().put("data",listPageInfo);
+	}
+
+
+	@Login
+	@ApiOperation("获取客户联系人详情")
+	@GetMapping(value = "/getCustomerContactsDetails")
+	public R getCustomerContactsDetails(@ApiParam(required = true, name = "contactsId", value = "contactsId") @RequestParam(value = "contactsId", required = false) Long contactsId)
+	{
+		CrmCustomerContacts contacts=crmCustomerContactsService.selectCrmCustomerContactsById(contactsId);
+		return R.ok().put("data",contacts);
+	}
+
+
+	@Login
+	@ApiOperation("新增联系人")
+	@PostMapping("/addContacts")
+	public R addContacts(@RequestBody CrmCustomerContacts crmCustomerContacts)
+	{
+		crmCustomerContacts.setCompanyId(getCompanyId());
+		if(crmCustomerContactsService.insertCrmCustomerContacts(crmCustomerContacts)>0){
+			return R.ok();
+		}
+		else{
+			return R.error();
+		}
+	}
+
+	@Login
+	@ApiOperation("修改联系人")
+	@PostMapping("/editContacts")
+	public R editContacts(@RequestBody CrmCustomerContacts crmCustomerContacts)
+	{
+		if(crmCustomerContactsService.updateCrmCustomerContacts(crmCustomerContacts)>0){
+			return R.ok();
+		}
+		else{
+			return R.error();
+		}
+	}
+	@Login
+	@ApiOperation("删除联系人")
+	@PostMapping("/delContacts")
+	public R delContacts(@RequestBody CrmCustomerContacts crmCustomerContacts)
+	{
+		if(crmCustomerContactsService.deleteCrmCustomerContactsById(crmCustomerContacts.getContactsId())>0){
+			return R.ok();
+		}
+		else{
+			return R.error();
+		}
+	}
+
+	@Login
+	@ApiOperation("查询客户")
+	@GetMapping("/getCustomerListBySearch")
+	public R getCustomerListBySearch(CrmCustomerSearchParam param){
+		param.setCompanyId(getCompanyId());
+		List<CrmCustomer> list = crmCustomerService.selectCrmCustomerListBySearch(param);
+		return R.ok().put("data",list);
+	}
+
+
+}

+ 111 - 0
fs-company-app/src/main/java/com/fs/app/controller/CrmEventController.java

@@ -0,0 +1,111 @@
+package com.fs.app.controller;
+
+
+import com.fs.app.annotation.Login;
+import com.fs.app.utils.JwtUtils;
+import com.fs.common.core.domain.R;
+import com.fs.crm.domain.CrmEvent;
+import com.fs.crm.param.CrmAddEventParam;
+import com.fs.crm.param.CrmDelEventParam;
+import com.fs.crm.param.CrmDoEventParam;
+import com.fs.crm.param.CrmEventListQueryParam;
+import com.fs.crm.service.ICrmEventService;
+import com.fs.crm.vo.CrmEventListQueryVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static com.fs.common.constant.Constants.PAGE_SIZE;
+
+
+@Api("代办事项接口")
+@RestController
+@RequestMapping(value="/app/crmEvent")
+public class CrmEventController extends  AppBaseController {
+	@Autowired
+    JwtUtils jwtUtils;
+	@Autowired
+	ICrmEventService eventService;
+
+	@Login
+	@GetMapping("/getMyCrmDoEventList")
+	@ApiOperation("获取我代办事件列表")
+	public R getMyCrmDoEventList()
+	{
+		CrmEventListQueryParam param=new CrmEventListQueryParam();
+		param.setCompanyId(getCompanyId());
+		param.setCompanyUserId(Long.parseLong(getUserId()));
+		param.setStatus(0);
+		List<CrmEventListQueryVO> list = eventService.selectCrmEventListQuery(param);
+		PageInfo<CrmEventListQueryVO> listPageInfo=new PageInfo<>(list);
+		return R.ok().put("data",listPageInfo);
+	}
+	@Login
+	@GetMapping("/getMyCrmEventList")
+	@ApiOperation("获取我的事件列表")
+	public R getMyCrmEventList(CrmEventListQueryParam param)
+	{
+		PageHelper.startPage(param.getPage(), PAGE_SIZE);
+		param.setCompanyId(getCompanyId());
+		param.setCompanyUserId(Long.parseLong(getUserId()));
+		List<CrmEventListQueryVO> list = eventService.selectCrmEventListQuery(param);
+		PageInfo<CrmEventListQueryVO> listPageInfo=new PageInfo<>(list);
+		return R.ok().put("data",listPageInfo);
+	}
+
+	@Login
+	@PostMapping("/addCrmEvent")
+	@ApiOperation("添加事件")
+	public R addCrmEvent(@RequestBody CrmAddEventParam param)
+	{
+		CrmEvent event=new CrmEvent();
+		BeanUtils.copyProperties(param,event);
+		event.setCompanyId(getCompanyId());
+		event.setCompanyUserId(Long.parseLong(getUserId()));
+		if(eventService.insertCrmEvent(event)>0){
+			return R.ok("操作成功");
+		}
+		else{
+			return R.error("操作失败");
+		}
+	}
+
+	@Login
+	@PostMapping("/doEvent")
+	@ApiOperation("完成事件")
+	public R doEvent(@RequestBody CrmDoEventParam param)
+	{
+		CrmEvent event=eventService.selectCrmEventById(param.getEventId());
+		if(event.getStatus()!=0){
+			return R.error("此事件已完成");
+		}
+		event.setStatus(1);
+		if(eventService.updateCrmEvent(event)>0){
+			return R.ok("操作成功");
+		}
+		else{
+			return R.error("操作失败");
+		}
+	}
+
+	@Login
+	@PostMapping("/delCrmEvent")
+	@ApiOperation("删除事件")
+	public R addCrmEvent(@RequestBody CrmDelEventParam param)
+	{
+		if(eventService.deleteCrmEventById(param.getEventId())>0){
+			return R.ok("操作成功");
+		}
+		else{
+			return R.error("操作失败");
+		}
+	}
+
+
+}

+ 107 - 0
fs-company-app/src/main/java/com/fs/app/controller/CrmMsgController.java

@@ -0,0 +1,107 @@
+package com.fs.app.controller;
+
+
+import com.fs.app.annotation.Login;
+import com.fs.app.param.CrmDoReadMsgParam;
+import com.fs.app.utils.JwtUtils;
+import com.fs.common.core.domain.R;
+import com.fs.crm.param.CrmMsgListQueryParam;
+import com.fs.crm.service.ICrmMsgService;
+import com.fs.crm.vo.CrmMsgListQueryVO;
+import com.fs.crm.vo.CrmMsgTypeVO;
+import com.fs.system.service.ISysDictDataService;
+import com.fs.system.vo.DictVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.fs.common.constant.Constants.PAGE_SIZE;
+
+
+@Api("消息接口")
+@RestController
+@RequestMapping(value="/app/crmMsg")
+public class CrmMsgController extends  AppBaseController {
+	@Autowired
+    JwtUtils jwtUtils;
+	@Autowired
+	ICrmMsgService msgService;
+	@Autowired
+	private ISysDictDataService dictDataService;
+	@Login
+	@ApiOperation("获取消息数量")
+	@GetMapping("/getMsgCount")
+	public R getMsgCount(HttpServletRequest request){
+		Long count= msgService.selectCrmMsgCountByUserId(Long.parseLong(getUserId()));
+		return R.ok().put("counts",count);
+
+	}
+	@Login
+	@ApiOperation("获取消息")
+	@GetMapping("/getMsg")
+	public R getMsg(HttpServletRequest request){
+		//获取用户未读总数
+		//获取所有类型
+		List<DictVO> types=dictDataService.selectDictDataListByType("crm_msg_type");
+		List<CrmMsgTypeVO> counts=new ArrayList<>();
+		for(DictVO v:types){
+			Long count= msgService.selectCrmMsgCountByUserId(Long.parseLong(getUserId()),Integer.parseInt(v.getDictValue()));
+			String title=msgService.selectCrmNewMsgByUserId(Long.parseLong(getUserId()),Integer.parseInt(v.getDictValue()));
+			CrmMsgTypeVO typeVO=new CrmMsgTypeVO();
+			typeVO.setMsgType(Integer.parseInt(v.getDictValue()));
+			typeVO.setTotal(count);
+			if(title!=null){
+				typeVO.setTitle(title);
+			}
+			typeVO.setMsgTypeName(v.getDictLabel());
+			counts.add(typeVO);
+		}
+		return R.ok().put("counts",counts);
+	}
+
+
+	@Login
+	@GetMapping("/getMsgList")
+	@ApiOperation("获取我的消息列表")
+	public R getMsgList(CrmMsgListQueryParam param)
+	{
+		PageHelper.startPage(param.getPage(), PAGE_SIZE);
+		param.setCompanyId(getCompanyId());
+		param.setCompanyUserId(Long.parseLong(getUserId()));
+		List<CrmMsgListQueryVO> list = msgService.selectCrmMsgListQuery(param);
+		PageInfo<CrmMsgListQueryVO> listPageInfo=new PageInfo<>(list);
+		return R.ok().put("data",listPageInfo);
+	}
+
+
+
+	@Login
+	@PostMapping("/doRead")
+	@ApiOperation("已读")
+	public R doRead(@RequestBody CrmDoReadMsgParam param)
+	{
+		msgService.setReadByType(Long.parseLong(getUserId()),param.getMsgType());
+		return R.ok("操作成功");
+	}
+
+
+	@Login
+	@ApiOperation("全部已读")
+	@PostMapping("/setAllRead")
+	public R setAllRead()
+	{
+		msgService.setAllRead(Long.parseLong(getUserId()));
+		return R.ok();
+	}
+
+
+
+
+}

+ 339 - 0
fs-company-app/src/main/java/com/fs/app/controller/FsUserController.java

@@ -0,0 +1,339 @@
+package com.fs.app.controller;
+
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.fs.app.annotation.Login;
+import com.fs.app.config.ImageStorageConfig;
+
+import com.fs.app.param.FsUserTagUpdateParam;
+import com.fs.app.param.FsUserUpdateParam;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.ResponseResult;
+import com.fs.common.exception.ServiceException;
+import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.ICompanyTagUserService;
+import com.fs.company.service.ICompanyUserService;
+import com.fs.course.param.CourseAnalysisParam;
+import com.fs.course.param.newfs.FsUserCourseBeMemberImageParam;
+import com.fs.course.param.newfs.FsUserCourseBeMemberParam;
+import com.fs.course.service.IFsUserCourseService;
+import com.fs.course.vo.newfs.FsCourseAnalysisVO;
+import com.fs.his.domain.FsUser;
+import com.fs.his.service.IFsUserService;
+import com.fs.store.param.h5.FsUserPageListParam;
+import com.fs.store.param.h5.TagListParam;
+import com.fs.store.param.h5.UserStatisticsCommonParam;
+import com.fs.store.service.IFsUserCourseCountService;
+import com.fs.store.vo.h5.*;
+import com.fs.system.service.ISysConfigService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.util.*;
+
+@Slf4j
+@Api(tags = "用户会员相关接口")
+@RestController
+@RequestMapping("/app/fs/user")
+public class FsUserController extends AppBaseController {
+
+    @Autowired
+    private IFsUserService fsUserService;
+
+    @Autowired
+    private ICompanyUserService companyUserService;
+
+    @Autowired
+    private ICompanyTagUserService companyTagUserService;
+
+    @Autowired
+    private ImageStorageConfig imageConfig;
+
+    @Autowired
+    private IFsUserCourseService fsUserCourseService;
+
+    @Autowired
+    private IFsUserCourseCountService userCourseCountService;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @Login
+    @PostMapping("/pageList")
+    @ApiOperation("用户会员分页列表")
+    public ResponseResult<PageInfo<FsUserPageListVO>> pageList(@RequestBody FsUserPageListParam param) {
+        param.setUserId(Long.parseLong(getUserId()));
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        PageInfo<FsUserPageListVO> fsUserPageListVOPageInfo = fsUserService.selectFsUserPageList(param);
+//        PageInfo<FsUserPageListVO> pageInfo = new PageInfo<>(list);
+        return ResponseResult.ok(fsUserPageListVOPageInfo);
+    }
+
+    @Login
+    @GetMapping("/allCompanyUser")
+    @ApiOperation("获取所有公司销售")
+    public ResponseResult<List<CompanyUser>> getAllCompanyUser() {
+        List<CompanyUser> companyUsers = companyUserService.selectAllCompanyUserAndSelf(Long.parseLong(getUserId()));
+        return ResponseResult.ok(companyUsers);
+    }
+
+    @Login
+    @GetMapping("/totalNumber")
+    @ApiOperation("用户会员数量统计")
+    public ResponseResult<UserListPageVO> getTotalNumber() {
+        UserListPageVO userNumber = fsUserService.getUserNumber(Long.parseLong(getUserId()));
+        return ResponseResult.ok(userNumber);
+    }
+
+    @Login
+    @GetMapping("/details")
+    @ApiOperation("用户会员详情")
+    public ResponseResult<UserDetailsVO> getUserDetails(@ApiParam(value = "用户id", required = true) @RequestParam Long userId,
+                                                        @ApiParam(value = "时间tab,不传表示查询全部,分别是:今天、昨天、前天、近七天", required = true) @RequestParam(required = false) String dateTag) {
+        UserDetailsVO userDetails = fsUserService.getUserDetails(Long.parseLong(getUserId()), userId, dateTag);
+        return ResponseResult.ok(userDetails);
+    }
+
+    @Login
+    @GetMapping("/tagList")
+    @ApiOperation("用户会员标签列表")
+    public ResponseResult<PageInfo<CompanyUserTagListVO>> getTagList(TagListParam param) {
+        param.setUserId(Long.parseLong(getUserId()));
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<CompanyUserTagListVO> tagList = companyTagUserService.getTagList(param);
+        PageInfo<CompanyUserTagListVO> pageInfo = new PageInfo<>(tagList);
+        return ResponseResult.ok(pageInfo);
+    }
+
+    @Login
+    @PostMapping("/disabled")
+    @ApiOperation("批量禁用会员")
+    public ResponseResult<Boolean> disabledUser(@ApiParam(value = "联系人id集合", required = true) @RequestBody String[] ids) {
+        Boolean r = fsUserService.disabledUser(ids, false);
+        return ResponseResult.ok(r);
+    }
+
+    @Login
+    @PostMapping("/enabled")
+    @ApiOperation("批量启用会员")
+    public ResponseResult<Boolean> enabledUser(@ApiParam(value = "联系人id集合", required = true) @RequestBody String[] ids) {
+        // 如果存在重粉的数据,则禁止启用,需要提示
+        long companyUserId = Long.parseLong(getUserId());
+        Integer count = fsUserService.selectFsUserByUserIds(ids, companyUserId);
+        if(count > 0){
+            return ResponseResult.fail(400, "重粉会员不能移除小黑屋");
+        }
+        Boolean r = fsUserService.disabledUser(ids, true);
+        return ResponseResult.ok(r);
+    }
+
+    @Login
+    @GetMapping("/firstPage/summaryCount")
+    @ApiOperation("首页数据-顶部汇总统计")
+    public ResponseResult<FsUserSummaryCountVO> userSummaryCount() {
+        long userId = Long.parseLong(getUserId());
+        return ResponseResult.ok(fsUserService.userSummaryCount(userId));
+    }
+
+    @Login
+    @GetMapping("/firstPage/statistics")
+    @ApiOperation("首页数据-课程/答题/红包统计")
+    public ResponseResult<FsUserStatisticsVO> userStatistics(@ApiParam(value = "开始时间", required = true) @RequestParam String startTime,
+                                                             @ApiParam(value = "结束时间", required = true) @RequestParam String endTime) {
+        long userId = Long.parseLong(getUserId());
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        String nowDate = dateFormat.format(new Date());
+        /*---------- 如果传入的日期是今天 ----------*/
+        UserStatisticsCommonParam param = new UserStatisticsCommonParam();
+        param.setUserId(userId).setStartTime(startTime).setEndTime(endTime);
+        FsUserStatisticsVO vo = fsUserService.userStatistics(param);
+        if (nowDate.compareTo(startTime) > 0 && nowDate.compareTo(endTime) < 0) {
+            String yesterday = LocalDate.now().minusDays(1).toString();
+            UserStatisticsCommonParam paramYes = new UserStatisticsCommonParam();
+            paramYes.setUserId(userId).setStartTime(yesterday + " 00:00:00").setEndTime(yesterday + " 23:59:59");
+            FsUserStatisticsVO fsUserStatisticsVO = fsUserService.userStatistics(paramYes);
+            vo.setYesterdayVO(fsUserStatisticsVO);
+        }
+        return ResponseResult.ok(vo);
+    }
+
+    @Login
+    @GetMapping("/statistics/details")
+    @ApiOperation("数据统计详情-课程/答题/红包统计")
+    public ResponseResult<FsUserStatisticsVO> userStatisticsDetails(@ApiParam(value = "营期id") @RequestParam(required = false) String periodId,
+                                                                    @ApiParam(value = "视频id") @RequestParam(required = false) String videoId) {
+        long userId = Long.parseLong(getUserId());
+        long companyId = getCompanyId();
+        UserStatisticsCommonParam param = new UserStatisticsCommonParam();
+        param.setUserId(userId).setPeriodId(periodId).setVideoId(videoId).setCompanyId(companyId);
+        FsUserStatisticsVO fsUserStatisticsVO = fsUserService.userStatisticsDetails(param);
+        return ResponseResult.ok(fsUserStatisticsVO);
+    }
+
+    @Login
+    @GetMapping("/firstPage/userRanking")
+    @ApiOperation("首页数据/详情-销售排行榜统计")
+    public ResponseResult<List<FsUserRankingVO>> userRanking(
+            @ApiParam(value = "开始时间") @RequestParam(required = false) String startTime,
+            @ApiParam(value = "结束时间") @RequestParam(required = false) String endTime,
+            @ApiParam(value = "营期id") @RequestParam(required = false) String periodId,
+            @ApiParam(value = "视频id") @RequestParam(required = false) String videoId,
+            @ApiParam(value = "asc-正序,desc-倒序", required = true) @RequestParam String order,
+            @ApiParam(value = "类型,1-按完播率,2-按正确率", required = true) @RequestParam Integer type
+    ) {
+        long userId = Long.parseLong(getUserId());
+        return ResponseResult.ok(fsUserService.userRanking(userId, startTime, endTime, periodId, videoId, order, type));
+    }
+
+    @Login
+    @GetMapping("/firstPage/courseRanking")
+    @ApiOperation("首页数据/详情-课程排行榜统计")
+    public ResponseResult<List<FsCourseRankingVO>> courseRanking(
+            @ApiParam(value = "开始时间") @RequestParam(required = false) String startTime,
+            @ApiParam(value = "结束时间") @RequestParam(required = false) String endTime,
+            @ApiParam(value = "课程id") @RequestParam(required = false) String courseId,
+            @ApiParam(value = "视频id") @RequestParam(required = false) String videoId,
+            @ApiParam(value = "asc-正序,desc-倒序", required = true) @RequestParam String order,
+            @ApiParam(value = "类型,1-按完播率,2-按正确率", required = true) @RequestParam Integer type
+    ) {
+        long userId = Long.parseLong(getUserId());
+        return ResponseResult.ok(fsUserService.courseRanking(userId, startTime, endTime, courseId, videoId, order, type));
+    }
+
+    @Login
+    @GetMapping("/firstPage/graphic")
+    @ApiOperation("首页数据-转化漏斗图")
+    public ResponseResult<List<FsUserGraphicStatisticsVO>> graphicStatistics(@ApiParam(value = "开始时间", required = true) @RequestParam String startTime,
+                                                                             @ApiParam(value = "结束时间", required = true) @RequestParam String endTime) {
+        long userId = Long.parseLong(getUserId());
+        UserStatisticsCommonParam param = new UserStatisticsCommonParam();
+        param.setUserId(userId).setStartTime(startTime).setEndTime(endTime);
+        List<FsUserGraphicStatisticsVO> list = fsUserService.graphicStatistics(param);
+        return ResponseResult.ok(list);
+    }
+
+    @Login
+    @GetMapping("/graphic/details")
+    @ApiOperation("详情-转化漏斗图")
+    public ResponseResult<List<FsUserGraphicStatisticsVO>> graphicStatisticsDetails(@ApiParam(value = "营期id") @RequestParam(required = false) String periodId,
+                                                                                    @ApiParam(value = "视频id") @RequestParam(required = false) String videoId) {
+        long userId = Long.parseLong(getUserId());
+        UserStatisticsCommonParam param = new UserStatisticsCommonParam();
+        param.setUserId(userId).setPeriodId(periodId).setVideoId(videoId);
+        List<FsUserGraphicStatisticsVO> list = fsUserService.graphicStatistics(param);
+        return ResponseResult.ok(list);
+    }
+
+    @Login
+    @ApiOperation("修改用户备注、姓名")
+    @PostMapping("/changeUserInfo")
+    public ResponseResult<Object> changeUserInfo(@Valid @RequestBody FsUserUpdateParam param) {
+        log.debug("修改用户备注、姓名 param:{}", JSON.toJSONString(param));
+        FsUser fsUser = fsUserService.selectFsUserById(param.getFsUserId());
+        if (Objects.isNull(fsUser)) {
+            throw new ServiceException("用户不存在");
+        }
+
+        fsUser.setNickName(param.getNickName());
+        fsUser.setRemark(param.getRemark());
+        fsUserService.updateFsUser(fsUser);
+        return ResponseResult.ok();
+    }
+
+    @Login
+    @ApiOperation("修改用户标签")
+    @PostMapping("/changeUserTags")
+    public ResponseResult<Object> changeUserTags(@Valid @RequestBody FsUserTagUpdateParam param) {
+        companyTagUserService.changeUserTags(param.getFsUserIds(), param.getTagIds());
+        return ResponseResult.ok();
+    }
+
+    @Login
+    @GetMapping("/courseAnalysis")
+    @ApiOperation("管理-课程分析-分页列表查询")
+    public ResponseResult<PageInfo<FsCourseAnalysisVO>> courseAnalysisList(CourseAnalysisParam param) {
+        param.setCompanyId(getCompanyId());
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<FsCourseAnalysisVO> list = fsUserService.courseAnalysis(param);
+        PageInfo<FsCourseAnalysisVO> pageInfo = new PageInfo<>(list);
+        return ResponseResult.ok(pageInfo);
+    }
+
+    @Login
+    @GetMapping("/companyUser/details")
+    @ApiOperation("管理-群管数据-根据销售id,群管数据统计")
+    public ResponseResult<FsUserStatisticsVO> companyUserStatistics(@ApiParam(value = "营期id") @RequestParam(required = false) String periodId,
+                                                                    @ApiParam(value = "视频id") @RequestParam(required = false) String videoId,
+                                                                    @ApiParam(value = "销售用户id", required = true) @RequestParam String companyUserId) {
+        UserStatisticsCommonParam param = new UserStatisticsCommonParam();
+        param.setUserId(Long.parseLong(getUserId()))
+                .setPeriodId(periodId).setVideoId(videoId)
+                .setCompanyId(getCompanyId())
+                .setCompanyUserId(companyUserId);
+        FsUserStatisticsVO fsUserStatisticsVO = fsUserService.userStatisticsDetails(param);
+        return ResponseResult.ok(fsUserStatisticsVO);
+    }
+
+    @Login
+    @GetMapping("/companyUser/summaryCount")
+    @ApiOperation("管理-群管数据-顶部会员统计")
+    public ResponseResult<CompanyUserSummaryCountVO> companyUserSummaryCount(@ApiParam(value = "销售用户id", required = true) @RequestParam String companyUserId) {
+        long userId = Long.parseLong(getUserId());
+        return ResponseResult.ok(fsUserService.companyUserSummaryCount(userId, companyUserId));
+    }
+
+    @Login
+    @ApiOperation("会员关联绑定销售")
+    @PostMapping("/beMember")
+    public ResponseResult<Boolean> becomeMember(@Valid @RequestBody FsUserCourseBeMemberParam param) {
+        return fsUserService.becomeMember(param);
+    }
+
+    @Login
+    @PostMapping("/userImage")
+    @ApiOperation("生成分享会员海报")
+    public R createCourseImage(@RequestBody FsUserCourseBeMemberImageParam param) {
+        try {
+            //获取用户头像
+//            FsUser fsUser = fsUserService.selectFsUserById(param.getUserId());
+//            String url = "";
+//            if(fsUser != null) {
+//                url = fsUser.getAvatar();
+//            }
+            String path = imageConfig.getServerPath();
+            InputStream inputStream = fsUserCourseService.handleImage("", path);
+
+            // 背景图片使用的后台商城配置的会员海报,如果没有配置则使用默认的logo图片
+            String config = configService.selectConfigByKey("store.config");
+            JSONObject jsonObject = JSONObject.parseObject(config);
+            String userPosterImage = jsonObject.getString("userPosterImage");
+            String backgroundImagePath;
+            if(StringUtils.isEmpty(userPosterImage)){
+                backgroundImagePath = "https://fbylive.obs.cn-southwest-2.myhuaweicloud.com/fs/20250430/1745980979886.png";
+            } else {
+                backgroundImagePath = userPosterImage;
+            }
+            String base64Image = fsUserCourseService.createUserImageQR(param.getRealLink(), backgroundImagePath, inputStream, "png", param.getCompanyUserId());
+            // 返回Base64编码的图片字符串
+            Map<String, Object> map = new HashMap<>();
+            map.put("url", base64Image);
+            return R.ok().put("posterImage", map);
+        } catch (Exception e) {
+            log.error("生成海报失败,param:{}", param);
+            return R.error("生成海报失败!");
+        }
+    }
+
+}

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

@@ -0,0 +1,224 @@
+package com.fs.app.controller;
+
+import com.fs.app.annotation.Login;
+import com.fs.app.config.ImageStorageConfig;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.ResponseResult;
+import com.fs.common.utils.StringUtils;
+import com.fs.course.domain.FsUserCoursePeriod;
+import com.fs.course.param.FsCourseLinkCreateParam;
+import com.fs.course.param.FsWatchCourseTimeParam;
+import com.fs.course.param.newfs.FsCourseSortLinkParam;
+import com.fs.course.param.newfs.FsUserCourseListParam;
+import com.fs.course.param.newfs.UserCourseVideoPageParam;
+import com.fs.course.service.IFsCourseLinkService;
+import com.fs.course.service.IFsUserCoursePeriodService;
+import com.fs.course.service.IFsUserCourseService;
+import com.fs.course.service.IFsUserCourseVideoService;
+import com.fs.course.vo.FsUserCourseParticipationRecordVO;
+import com.fs.course.vo.newfs.FsUserCourseListVO;
+import com.fs.course.vo.newfs.FsUserCourseVideoDetailsVO;
+import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
+import com.fs.course.vo.newfs.FsUserVideoListVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.InputStream;
+import java.time.LocalDate;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+
+@Api("课程库相关接口")
+@RestController
+@RequestMapping("/app/fs/course")
+@Slf4j
+public class FsUserCourseVideoController extends AppBaseController {
+
+    @Autowired
+    private IFsUserCourseVideoService fsUserCourseVideoService;
+
+    @Autowired
+    private IFsUserCourseService fsUserCourseService;
+
+    @Autowired
+    private IFsCourseLinkService courseLinkService;
+
+    @Autowired
+    private ImageStorageConfig imageConfig;
+
+    @Autowired
+    private IFsUserCoursePeriodService fsUserCoursePeriodService;
+
+    @Login
+    @GetMapping("/pageList")
+    @ApiOperation("课程分页列表")
+    public ResponseResult<PageInfo<FsUserCourseVideoPageListVO>> list(UserCourseVideoPageParam param) {
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        param.setCompanyId(getCompanyId());
+        param.setCompanyUserId(Long.parseLong(getUserId()));
+        List<FsUserCourseVideoPageListVO> list = fsUserCourseVideoService.pageListCourseVideo(param);
+        PageInfo<FsUserCourseVideoPageListVO> pageInfo = new PageInfo<>(list);
+        return ResponseResult.ok(pageInfo);
+    }
+
+    @Login
+    @ApiOperation("课程视频详情")
+    @GetMapping(value = "/videoDetails")
+    public ResponseResult<FsUserCourseVideoDetailsVO> getVideoDetails(Long videoId) {
+        return fsUserCourseVideoService.getVideoDetails(videoId);
+    }
+
+    @Login
+    @GetMapping("/courseList")
+    @ApiOperation("获取课程下拉列表")
+    public ResponseResult<PageInfo<FsUserCourseListVO>> getAllCourseList(FsUserCourseListParam param) {
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        param.setCompanyId(getCompanyId());
+        List<FsUserCourseListVO> fsUserCourseList = fsUserCourseService.getFsUserCourseList(param);
+        PageInfo<FsUserCourseListVO> pageInfo = new PageInfo<>(fsUserCourseList);
+        return ResponseResult.ok(pageInfo);
+    }
+
+    @Login
+    @GetMapping("/videoList")
+    @ApiOperation("获取视频下拉列表")
+    public ResponseResult<PageInfo<FsUserVideoListVO>> getAllVideoList(UserCourseVideoPageParam param) {
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        param.setCompanyId(getCompanyId());
+        List<FsUserVideoListVO> listCourseVideo = fsUserCourseVideoService.getListCourseVideo(param);
+        PageInfo<FsUserVideoListVO> result = new PageInfo<>(listCourseVideo);
+        return ResponseResult.ok(result);
+    }
+
+    @Login
+    @ApiOperation("参与记录")
+    @GetMapping("/participationRecord")
+    public ResponseResult<Object> participationRecord(@RequestParam Long videoId,
+                                                      @RequestParam Integer type,
+                                                      @RequestParam(required = false) String keyword,
+                                                      @RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                                                      @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
+        log.debug("参与记录 keyword: {}, pageNum: {}, pageSize: {}", keyword, pageNum, pageSize);
+        Map<String, Object> params = new HashMap<>();
+        params.put("videoId", videoId);
+        params.put("type", type);
+        params.put("keyword", keyword);
+
+        PageHelper.startPage(pageNum, pageSize);
+        List<FsUserCourseParticipationRecordVO> record = fsUserCourseService.getParticipationRecordByMap(params);
+        return ResponseResult.ok(new PageInfo<>(record));
+    }
+
+    @Login
+    @PostMapping("/courseSortLink")
+    @ApiOperation("生成课程分享短链")
+    public R createCourseSortLink(@RequestBody FsCourseSortLinkParam param) {
+        FsCourseLinkCreateParam fsCourseLinkCreateParam = new FsCourseLinkCreateParam();
+        BeanUtils.copyProperties(param, fsCourseLinkCreateParam);
+
+        R courseSortLink = fsUserCourseService.createCourseSortLink(fsCourseLinkCreateParam);
+        String url = courseSortLink.get("url").toString();
+        Map<String, Object> map = new HashMap<>();
+        map.put("url", url);
+        return R.ok(map);
+    }
+
+    @Login
+    @PostMapping("/courseImage")
+    @ApiOperation("生成课程海报")
+    public R createCourseImage(@RequestBody FsCourseSortLinkParam param) {
+        // 获取生成链接
+        FsCourseLinkCreateParam fsCourseLinkCreateParam = new FsCourseLinkCreateParam();
+        BeanUtils.copyProperties(param, fsCourseLinkCreateParam);
+
+        R courseSortLink = fsUserCourseService.createCourseSortLink(fsCourseLinkCreateParam);
+        String link = courseSortLink.get("link").toString();
+        R r = courseLinkService.getRealLink(link);
+        String realLink = r.get("realLink").toString();
+        try {
+            String path = imageConfig.getServerPath();
+            log.info("获取的logo图片路径,fileUrl:{}", path);
+            InputStream inputStream = fsUserCourseService.handleImage("", path);
+
+            // 获取营期的课程风格url
+            String imgUrl;
+            FsUserCoursePeriod fsUserCoursePeriod = fsUserCoursePeriodService.selectFsUserCoursePeriodById(param.getPeriodId());
+            if (fsUserCoursePeriod != null) {
+                imgUrl = fsUserCoursePeriod.getCourseStyle();
+            } else {
+                imgUrl = param.getImgUrl();
+            }
+            if(StringUtils.isEmpty(imgUrl)){
+                return R.error(400, "营期风格图片或课程封面不能为空!");
+            }
+
+            String base64Image = fsUserCourseService.createCourseImageQR(realLink, imgUrl, inputStream, "png", param.getTitle(), param.getDuration());
+            // 返回Base64编码的图片字符串
+            Map<String, Object> map = new HashMap<>();
+            map.put("url", base64Image);
+            return R.ok().put("posterImage", map);
+        } catch (Exception e) {
+            log.error("生成海报失败,param:{}", param);
+            return R.error("生成海报失败!");
+        }
+    }
+
+
+//    @Login
+//    @PostMapping("/sortLink/courseMember")
+//    @ApiOperation("生成分享成为会员短链")
+//    public R createCourseMemberSortLink(@RequestBody FsUserCourseBeMemberParam param) {
+//        FsCourseLinkCreateParam fsCourseLinkCreateParam = new FsCourseLinkCreateParam();
+//        BeanUtils.copyProperties(param, fsCourseLinkCreateParam);
+//
+//        R courseSortLink = fsUserCourseService.createCourseMemberSortLink(fsCourseLinkCreateParam);
+//        String url = courseSortLink.get("url").toString();
+//        Map<String, Object> map = new HashMap<>();
+//        map.put("url", url);
+//        return R.ok(map);
+//    }
+
+    @Login
+    @GetMapping("/todayCourseList")
+    @ApiOperation("今日课程")
+    public ResponseResult<PageInfo<FsUserCourseVideoPageListVO>> todayCourseList(@RequestParam(defaultValue = "1") Integer pageNum,
+                                                                                 @RequestParam(defaultValue = "10") Integer pageSize) {
+        Long companyId = getCompanyId();
+        if (Objects.isNull(companyId)) {
+            ResponseResult.fail(400, "未获取到公司ID,请重新登录后再试");
+        }
+
+        Map<String, Object> params = new HashMap<>();
+        params.put("companyId", companyId);
+        params.put("dayDate", LocalDate.now());
+        params.put("companyUserId", Long.parseLong(getUserId()));
+
+        PageHelper.startPage(pageNum, pageSize);
+        List<FsUserCourseVideoPageListVO> list = fsUserCourseVideoService.selectCourseVideoListByMap(params);
+        PageInfo<FsUserCourseVideoPageListVO> pageInfo = new PageInfo<>(list);
+        return ResponseResult.ok(pageInfo);
+    }
+
+    @Login
+    @PostMapping("/setWatchTime")
+    @ApiOperation("销售设置课程时间")
+    public ResponseResult<Boolean> setWatchCourseTime(@RequestBody List<FsWatchCourseTimeParam> paramList) {
+        List<FsWatchCourseTimeParam> collect = paramList.stream().peek(v -> {
+            v.setCompanyUserId(Long.parseLong(getUserId()));
+            v.setCompanyId(getCompanyId());
+        }).collect(Collectors.toList());
+        return fsUserCourseVideoService.setWatchCourseTime(collect);
+    }
+
+
+}

+ 65 - 0
fs-company-app/src/main/java/com/fs/app/controller/IndexController.java

@@ -0,0 +1,65 @@
+package com.fs.app.controller;
+
+
+import com.fs.app.annotation.Login;
+import com.fs.app.utils.JwtUtils;
+import com.fs.common.core.domain.R;
+import com.fs.company.domain.Company;
+import com.fs.company.service.ICompanyService;
+import com.fs.company.service.ICompanyUserService;
+import com.fs.crm.param.CrmFullCustomerListQueryParam;
+import com.fs.crm.service.ICrmCustomerService;
+import com.fs.crm.service.ICrmCustomerUserService;
+import com.fs.his.service.IFsStoreOrderService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+@Api("首页接口")
+@RestController
+@RequestMapping(value="/app/index")
+public class IndexController extends  AppBaseController {
+	@Autowired
+    JwtUtils jwtUtils;
+	@Autowired
+	ICrmCustomerService crmCustomerService;
+	@Autowired
+	IFsStoreOrderService storeOrderService;
+	@Autowired
+	ICompanyUserService companyUserService;
+	@Autowired
+	ICrmCustomerUserService crmCustomerUserService;
+	@Autowired
+	private ICompanyService companyService;
+	@Login
+	@ApiOperation("获取首页数据")
+	@GetMapping("/getIndexData")
+	public R getIndexData(CrmFullCustomerListQueryParam param){
+		Company company=companyService.selectCompanyById(getCompanyId());
+		//获取统计数据
+		Integer newCustomerCounts=crmCustomerService.selectCrmCustomerCountByType(company.getCompanyId(),1);
+		Integer fullCustomerCounts=crmCustomerService.selectCrmCustomerCountByType(company.getCompanyId(),2);
+		Integer myCustomerCounts=crmCustomerUserService.selectCrmMyCustomerUserCount(company.getCompanyId(),Long.parseLong(getUserId()));
+
+		Integer dayOrderCounts=storeOrderService.selectFsStoreOrderCountByType(company.getCompanyId(),Long.parseLong(getUserId()),1);
+		Integer doBuyOrderCounts=storeOrderService.selectFsStoreOrderCountByType(company.getCompanyId(),Long.parseLong(getUserId()),2);
+		Map<String,Object> data=new HashMap<>();
+		data.put("company",company);
+		data.put("newCustomerCounts",newCustomerCounts);
+		data.put("fullCustomerCounts",fullCustomerCounts);
+		data.put("myCustomerCounts",myCustomerCounts);
+		data.put("dayOrderCounts",dayOrderCounts);
+		data.put("doBuyOrderCounts",doBuyOrderCounts);
+
+		return R.ok().put("data",data);
+	}
+
+
+}

+ 96 - 0
fs-company-app/src/main/java/com/fs/app/controller/QwCompanyUserController.java

@@ -0,0 +1,96 @@
+package com.fs.app.controller;
+
+
+import com.fs.app.annotation.Login;
+import com.fs.common.core.domain.ResponseResult;
+import com.fs.qw.param.ExternalContactDetailsParam;
+import com.fs.qw.param.newparam.ContactTagListParam;
+import com.fs.qw.param.newparam.ExternalContactPageListParam;
+import com.fs.qw.service.IQwExternalContactService;
+import com.fs.qw.service.IQwTagService;
+import com.fs.qw.vo.ExternalContactDetailsVO;
+import com.fs.qw.vo.QwTagVO;
+import com.fs.qw.vo.newvo.ExternalContactListVO;
+import com.fs.qw.vo.newvo.ExternalContactPageVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+
+@Api(tags = "企微用户相关接口")
+@RestController
+@RequestMapping("/app/company/user")
+public class QwCompanyUserController extends AppBaseController {
+
+    @Autowired
+    private IQwExternalContactService qwExternalContactService;
+
+    @Autowired
+    private IQwTagService tagService;
+
+    @Login
+    @GetMapping("/pageList")
+    @ApiOperation("会员分页列表")
+    public ResponseResult<PageInfo<ExternalContactListVO>> pageList(ExternalContactPageListParam param) {
+        param.setUserId(Long.parseLong(getUserId()));
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<ExternalContactListVO> list = qwExternalContactService.externalContactPageList(param);
+        PageInfo<ExternalContactListVO> pageInfo = new PageInfo<>(list);
+        return ResponseResult.ok(pageInfo);
+    }
+
+    @Login
+    @GetMapping("/totalNumber")
+    @ApiOperation("会员数量统计")
+    public ResponseResult<ExternalContactPageVO> getTotalNumber() {
+        ExternalContactPageVO contactNumber = qwExternalContactService.getContactNumber(Long.parseLong(getUserId()));
+        return ResponseResult.ok(contactNumber);
+    }
+
+    @Login
+    @GetMapping("/details")
+    @ApiOperation("会员详情")
+    public ResponseResult<ExternalContactDetailsVO> getUserDetails(@ApiParam(value = "外部联系人id", required = true) @RequestParam Long contactId,
+                                                                   @ApiParam(value = "时间tab,不传表示查询全部,分别是:今天、昨天、前天、近七天", required = true) @RequestParam String dateTag) {
+        ExternalContactDetailsParam externalContactDetailsParam = new ExternalContactDetailsParam();
+        externalContactDetailsParam.setUserId(Long.parseLong(getUserId()));
+        externalContactDetailsParam.setContactId(contactId);
+        externalContactDetailsParam.setDateTag(dateTag);
+        return ResponseResult.ok(qwExternalContactService.getUserDetails(externalContactDetailsParam));
+    }
+
+    @Login
+    @GetMapping("/tagList")
+    @ApiOperation("会员标签列表")
+    public ResponseResult<PageInfo<QwTagVO>> getTagList(ContactTagListParam param) {
+        param.setUserId(Long.parseLong(getUserId()));
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<QwTagVO> tagList = tagService.getTagListByUserId(param);
+        PageInfo<QwTagVO> pageInfo = new PageInfo<>(tagList);
+        return ResponseResult.ok(pageInfo);
+    }
+
+    @Login
+    @PostMapping("/disabled")
+    @ApiOperation("批量禁用会员")
+    public ResponseResult<Boolean> disabledUser(@ApiParam(value = "联系人id集合", required = true) @RequestBody String[] ids) {
+        Boolean r = qwExternalContactService.disabledUser(ids, false);
+        return ResponseResult.ok(r);
+    }
+
+    @Login
+    @PostMapping("/enabled")
+    @ApiOperation("批量启用会员")
+    public ResponseResult<Boolean> enabledUser(@ApiParam(value = "联系人id集合", required = true) @RequestBody String[] ids) {
+        Boolean r = qwExternalContactService.disabledUser(ids, true);
+        return ResponseResult.ok(r);
+    }
+
+
+}

+ 91 - 0
fs-company-app/src/main/java/com/fs/app/controller/QwWorkTaskController.java

@@ -0,0 +1,91 @@
+package com.fs.app.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.fs.app.annotation.Login;
+import com.fs.common.core.domain.R;
+import com.fs.qw.domain.QwWorkTask;
+import com.fs.qw.param.QwWorkTaskQueryParam;
+import com.fs.qw.service.IQwUserService;
+import com.fs.qw.service.IQwWorkTaskService;
+import com.fs.qw.vo.QwOptionsVO;
+import com.fs.qw.vo.UserVOs;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Api(tags = "企微任务看板接口")
+@RestController
+@RequestMapping("/app/qwWorkTask")
+@AllArgsConstructor
+public class QwWorkTaskController extends AppBaseController {
+
+    private final IQwWorkTaskService qwWorkTaskService;
+    private final IQwUserService qwUserService;
+
+    @Login
+    @ApiOperation("企微任务看板列表")
+    @GetMapping("/list")
+    public R list(@Valid QwWorkTaskQueryParam param) {
+        log.debug("企微任务看板列表:{}", JSON.toJSONString(param));
+
+        Map<String, Object> params = new HashMap<>();
+        params.put("qwUserId", param.getQwUserId());
+        params.put("companyId", getCompanyId());
+        params.put("companyUserId", getUserId());
+        params.put("date", param.getDate());
+
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<QwWorkTask> list = qwWorkTaskService.selectQwWorkTaskListByMap(params);
+
+        PageInfo<QwWorkTask> pageInfo = new PageInfo<>(list);
+        return R.ok().put("data", pageInfo);
+    }
+
+    @Login
+    @ApiOperation("销售下的企微用户")
+    @GetMapping("/getMyQwUserList")
+    public R userList(@RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                      @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
+        Long userId = Long.parseLong(getUserId());
+        PageHelper.startPage(pageNum, pageSize);
+        List<QwOptionsVO> list = qwUserService.selectQwUserListOptionsVOByCompanyUserId(userId);
+        return R.ok().put("data", new PageInfo<>(list));
+    }
+
+    @Login
+    @ApiOperation("催课看板会员列表")
+    @GetMapping("/getUserList")
+    public R getUserList(@RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                         @RequestParam(required = false, defaultValue = "10") Integer pageSize) {
+        Long userId = Long.parseLong(getUserId());
+        PageHelper.startPage(pageNum, pageSize);
+        List<UserVOs> list = qwUserService.getUserList(userId);
+        return R.ok().put("data", new PageInfo<>(list));
+    }
+
+    @Login
+    @ApiOperation("催课看板企微会员列表")
+    @GetMapping("/getQwUserList")
+    public R getQwUserList(@RequestParam(required = false, defaultValue = "1") Integer pageNum,
+                           @RequestParam(required = false, defaultValue = "10") Integer pageSize,
+                           @RequestParam(required = false, defaultValue = "10") String qwUserId) {
+        Long userId = Long.parseLong(getUserId());
+        PageHelper.startPage(pageNum, pageSize);
+        List<UserVOs> list = qwUserService.getQwUserList(userId, qwUserId);
+        return R.ok().put("data", new PageInfo<>(list));
+    }
+
+}

+ 104 - 0
fs-company-app/src/main/java/com/fs/app/controller/SmsController.java

@@ -0,0 +1,104 @@
+package com.fs.app.controller;
+
+import com.fs.app.annotation.Login;
+import com.fs.app.utils.JwtUtils;
+import com.fs.common.annotation.RepeatSubmit;
+import com.fs.common.core.domain.R;
+import com.fs.common.service.ISmsService;
+import com.fs.company.domain.CompanySms;
+import com.fs.company.param.CompanySmsTempListQueryParam;
+import com.fs.company.service.ICompanySmsLogsService;
+import com.fs.company.service.ICompanySmsService;
+import com.fs.company.service.ICompanySmsTempService;
+import com.fs.company.vo.CompanySmsTempListQueryVO;
+import com.fs.crm.param.SmsSendBatchParam;
+import com.fs.crm.param.SmsSendParam;
+import com.fs.crm.service.ICrmCustomerService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+
+@Api("短信接口")
+@RestController
+@RequestMapping(value="/app/sms")
+public class SmsController extends  AppBaseController {
+	Logger logger = LoggerFactory.getLogger(getClass());
+	@Autowired
+    JwtUtils jwtUtils;
+
+	@Autowired
+	private ICompanySmsTempService smsTempService;
+
+	@Autowired
+	private ICompanySmsService companySmsService;
+
+	@Autowired
+	private ICompanySmsLogsService smsLogsService;
+
+	@Autowired
+	private ICrmCustomerService crmCustomerService;
+
+	@Autowired
+	private ISmsService smsService;
+
+	@Login
+	@ApiOperation("获取短信模版列表")
+	@GetMapping("/getSmsTempList")
+	public R getSmsTempList(){
+		CompanySmsTempListQueryParam map=new CompanySmsTempListQueryParam();
+		map.setStatus(1);
+		map.setIsAudit(1);
+		map.setCompanyId(getCompanyId());
+		List<CompanySmsTempListQueryVO> smsTemp=smsTempService.selectCompanySmsTempListQuery(map);
+		return R.ok().put("data",smsTemp);
+
+	}
+
+	@Login
+	@ApiOperation("发送短信")
+	@PostMapping("/sendCustomerMsg")
+	@RepeatSubmit
+	@Transactional
+	public  R sendCustomerMsg(@Validated @RequestBody SmsSendParam param){
+		param.setCompanyId(getCompanyId());
+		param.setCompanyUserId(Long.parseLong(getUserId()));
+		return smsService.sendSms(param);
+	}
+
+	@Login
+	@ApiOperation("发送短信")
+	@PostMapping("/sendCustomerBatchMsg")
+	@RepeatSubmit
+	@Transactional
+	public  R sendCustomerBatchMsg(@Validated @RequestBody SmsSendBatchParam param){
+		param.setCompanyId(getCompanyId());
+		param.setCompanyUserId(Long.parseLong(getUserId()));
+		return smsService.sendBatchSms(param);
+	}
+
+
+	@PostMapping("/notify")
+	public  String notify(@RequestBody String json){
+		logger.info("smsNotify");
+		logger.info(json);
+		return smsService.smsNotify(json);
+	}
+
+
+	@Login
+	@ApiOperation("获取短信数量")
+	@GetMapping("/getCompanySmsCount")
+	public R getCompanySmsCount( ) {
+		CompanySms companySms=companySmsService.selectCompanySmsByCompanyId(getCompanyId());
+		return R.ok().put("data",companySms);
+	}
+
+}

+ 322 - 0
fs-company-app/src/main/java/com/fs/app/controller/StatisticsController.java

@@ -0,0 +1,322 @@
+package com.fs.app.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fs.app.annotation.Login;
+import com.fs.common.core.domain.R;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.TimeUtils;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.param.CompanyStatisticsParam;
+import com.fs.company.param.FsStoreStatisticsParam;
+import com.fs.company.service.ICompanySmsLogsService;
+import com.fs.company.service.ICompanyUserService;
+import com.fs.company.service.ICompanyVoiceLogsService;
+import com.fs.company.vo.CompanySmsLogsStatisticsVO;
+import com.fs.company.vo.CompanyVoiceLogsStatisticsVO;
+import com.fs.company.vo.FsStoreOrderStatisticsVO;
+import com.fs.company.vo.FsStorePaymentStatisticsVO;
+import com.fs.crm.param.CrmCustomerStatisticsParam;
+import com.fs.crm.service.ICrmCustomerService;
+import com.fs.crm.service.ICrmCustomerVisitService;
+import com.fs.crm.vo.CrmCustomerStatisticsVO;
+import com.fs.crm.vo.CrmCustomerVisitStatisticsVO;
+import com.fs.his.service.IFsStoreOrderService;
+import com.fs.his.service.IFsStorePaymentService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+
+@Api("统计")
+@RestController
+@RequestMapping("/app/statistics")
+public class StatisticsController extends AppBaseController
+{
+
+    @Autowired
+    private ICompanyUserService userService;
+
+    @Autowired
+    private ICrmCustomerService crmCustomerService;
+    @Autowired
+    private ICrmCustomerVisitService crmCustomerVisitService;
+    @Autowired
+    private IFsStoreOrderService storeOrderService;
+    @Autowired
+    private IFsStorePaymentService storePaymentService;
+    @Autowired
+    private ICompanyVoiceLogsService voiceLogsService;
+    @Autowired
+    private ICompanySmsLogsService smsLogsService;
+
+    @Login
+    @ApiOperation("客户统计")
+    @GetMapping("/getCustomerStatistics")
+    public R getCustomerStatistics(CrmCustomerStatisticsParam param)
+    {
+        if(StringUtils.isNotEmpty(param.getUserIds())){
+            String[] userIds=param.getUserIds().split(",");
+            Long[] ids=new Long[userIds.length];
+            for(int i=0;i<ids.length; i++){
+                ids[i]=Long.parseLong(userIds[i]);
+            }
+            param.setUsers(ids);
+        }
+        else{
+            //获取部门下的所有用户
+            CompanyUser usermap=new CompanyUser();
+            usermap.setDeptId(param.getDeptId());
+            List<CompanyUser> users = userService.getUserListByDeptId(usermap);
+            List<Long> userIds = users.stream().map(element -> element.getUserId()).collect(Collectors.toList());
+            param.setUsers(userIds.toArray(new Long[userIds.size()]));
+        }
+        if(param.getUsers()!=null&&param.getUsers().length>0){
+            List<CrmCustomerStatisticsVO> list= crmCustomerService.selectCrmCustomerStatisticsList(param);
+            TimeUtils.TimeEntity timeEntity=TimeUtils.parseTime(param.getType().toString(),param.getStartTime(),param.getEndTime());
+            timeEntity.setUserIds(param.getUsers());
+            Integer cycleNum = timeEntity.getCycleNum();
+            Integer beginTime = timeEntity.getBeginTime();
+            List<Integer> timeList = new ArrayList<>();
+            for (int i = 1; i <= cycleNum; i++) {
+                timeList.add(beginTime);
+                beginTime = TimeUtils.formatTime(beginTime);
+            }
+            List<JSONObject> jsonObjectList = crmCustomerService.selectCrmCustomerCounts(timeEntity.toMap());
+            List<String> dates = jsonObjectList.stream().map(jsonObject -> jsonObject.getString("type")).collect(Collectors.toList());
+            List<Integer> receiveCount = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("receiveCount")).collect(Collectors.toList());
+            List<Integer> poolCount = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("poolCount")).collect(Collectors.toList());
+            return R.ok().put("list",list).put("dates",dates).put("receiveCount",receiveCount).put("poolCount",poolCount);
+        }
+        else {
+            return R.ok("未查找到数据");
+        }
+    }
+    @ApiOperation("客户跟进统计")
+    @GetMapping("/getCustomerVisitStatistics")
+    public R getCustomerVisitStatistics(CrmCustomerStatisticsParam param)
+    {
+        if(StringUtils.isNotEmpty(param.getUserIds())){
+            String[] userIds=param.getUserIds().split(",");
+            Long[] ids=new Long[userIds.length];
+            for(int i=0;i<ids.length; i++){
+                ids[i]=Long.parseLong(userIds[i]);
+            }
+            param.setUsers(ids);
+        }
+        else{
+            //获取部门下的所有用户
+            CompanyUser usermap=new CompanyUser();
+            usermap.setDeptId(param.getDeptId());
+            List<CompanyUser> users = userService.getUserListByDeptId(usermap);
+            List<Long> userIds = users.stream().map(element -> element.getUserId()).collect(Collectors.toList());
+            param.setUsers(userIds.toArray(new Long[userIds.size()]));
+        }
+        if(param.getUsers()!=null&&param.getUsers().length>0){
+            List<CrmCustomerVisitStatisticsVO> list= crmCustomerVisitService.selectCrmCustomerVisitStatisticsList(param);
+
+            TimeUtils.TimeEntity timeEntity=TimeUtils.parseTime(param.getType().toString(),param.getStartTime(),param.getEndTime());
+            timeEntity.setUserIds(param.getUsers());
+            Integer cycleNum = timeEntity.getCycleNum();
+            Integer beginTime = timeEntity.getBeginTime();
+            List<Integer> timeList = new ArrayList<>();
+            for (int i = 1; i <= cycleNum; i++) {
+                timeList.add(beginTime);
+                beginTime = TimeUtils.formatTime(beginTime);
+            }
+            List<JSONObject> jsonObjectList = crmCustomerVisitService.selectCrmCustomerVisitCounts(timeEntity.toMap());
+            List<String> dates = jsonObjectList.stream().map(jsonObject -> jsonObject.getString("type")).collect(Collectors.toList());
+            List<Integer> customerCount = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("customerCount")).collect(Collectors.toList());
+            List<Integer> visitCount = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("visitCount")).collect(Collectors.toList());
+            return R.ok().put("list",list).put("dates",dates).put("customerCount",customerCount).put("visitCount",visitCount);
+        }
+        else {
+            return R.ok("未查找到数据");
+        }
+    }
+
+    @ApiOperation("订单统计")
+    @GetMapping("/getStoreOrderStatistics")
+    public R getStoreOrderStatistics(FsStoreStatisticsParam param)
+    {
+        if(StringUtils.isNotEmpty(param.getUserIds())){
+            String[] userIds=param.getUserIds().split(",");
+            Long[] ids=new Long[userIds.length];
+            for(int i=0;i<ids.length; i++){
+                ids[i]=Long.parseLong(userIds[i]);
+            }
+            param.setUsers(ids);
+        }
+        else{
+            //获取部门下的所有用户
+            CompanyUser usermap=new CompanyUser();
+            usermap.setDeptId(param.getDeptId());
+            List<CompanyUser> users = userService.getUserListByDeptId(usermap);
+            List<Long> userIds = users.stream().map(element -> element.getUserId()).collect(Collectors.toList());
+            param.setUsers(userIds.toArray(new Long[userIds.size()]));
+        }
+        if(param.getUsers()!=null&&param.getUsers().length>0){
+            List<FsStoreOrderStatisticsVO> list= storeOrderService.selectFsStoreOrderStatisticsList(param);
+
+            TimeUtils.TimeEntity timeEntity=TimeUtils.parseTime(param.getType().toString(),param.getStartTime(),param.getEndTime());
+            timeEntity.setUserIds(param.getUsers());
+            Integer cycleNum = timeEntity.getCycleNum();
+            Integer beginTime = timeEntity.getBeginTime();
+            List<Integer> timeList = new ArrayList<>();
+            for (int i = 1; i <= cycleNum; i++) {
+                timeList.add(beginTime);
+                beginTime = TimeUtils.formatTime(beginTime);
+            }
+            List<JSONObject> jsonObjectList = storeOrderService.selectFsStoreOrderCounts(timeEntity.toMap());
+            List<String> dates = jsonObjectList.stream().map(jsonObject -> jsonObject.getString("type")).collect(Collectors.toList());
+            List<Integer> orderCount = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("orderCount")).collect(Collectors.toList());
+            List<Integer> payPrice = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("payPrice")).collect(Collectors.toList());
+            return R.ok().put("list",list).put("dates",dates).put("orderCount",orderCount).put("payPrice",payPrice);
+        }
+        else {
+            return R.ok("未查找到数据");
+        }
+    }
+    @ApiOperation("收款订单统计")
+    @GetMapping("/getStorePaymentStatistics")
+    public R getStorePaymentStatistics(FsStoreStatisticsParam param)
+    {
+        if(StringUtils.isNotEmpty(param.getUserIds())){
+            String[] userIds=param.getUserIds().split(",");
+            Long[] ids=new Long[userIds.length];
+            for(int i=0;i<ids.length; i++){
+                ids[i]=Long.parseLong(userIds[i]);
+            }
+            param.setUsers(ids);
+        }
+        else{
+            //获取部门下的所有用户
+            CompanyUser usermap=new CompanyUser();
+            usermap.setDeptId(param.getDeptId());
+            List<CompanyUser> users = userService.getUserListByDeptId(usermap);
+            List<Long> userIds = users.stream().map(element -> element.getUserId()).collect(Collectors.toList());
+            param.setUsers(userIds.toArray(new Long[userIds.size()]));
+        }
+        if(param.getUsers()!=null&&param.getUsers().length>0){
+            List<FsStorePaymentStatisticsVO> list= storePaymentService.selectFsStorePaymentStatisticsList(param);
+            TimeUtils.TimeEntity timeEntity=TimeUtils.parseTime(param.getType().toString(),param.getStartTime(),param.getEndTime());
+            timeEntity.setUserIds(param.getUsers());
+            Integer cycleNum = timeEntity.getCycleNum();
+            Integer beginTime = timeEntity.getBeginTime();
+            List<Integer> timeList = new ArrayList<>();
+            for (int i = 1; i <= cycleNum; i++) {
+                timeList.add(beginTime);
+                beginTime = TimeUtils.formatTime(beginTime);
+            }
+            List<JSONObject> jsonObjectList = storePaymentService.selectFsStorePaymentCounts(timeEntity.toMap());
+            List<String> dates = jsonObjectList.stream().map(jsonObject -> jsonObject.getString("type")).collect(Collectors.toList());
+            List<Integer> orderCount = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("orderCount")).collect(Collectors.toList());
+            List<Integer> payMoney = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("payMoney")).collect(Collectors.toList());
+            return R.ok().put("list",list).put("dates",dates).put("orderCount",orderCount).put("payMoney",payMoney);
+        }
+        else {
+            return R.ok("未查找到数据");
+        }
+    }
+
+    @ApiOperation("通话统计")
+    @GetMapping("/getVoiceLogsStatistics")
+    public R getVoiceLogsStatistics(CompanyStatisticsParam param)
+    {
+        if(StringUtils.isNotEmpty(param.getUserIds())){
+            String[] userIds=param.getUserIds().split(",");
+            Long[] ids=new Long[userIds.length];
+            for(int i=0;i<ids.length; i++){
+                ids[i]=Long.parseLong(userIds[i]);
+            }
+            param.setUsers(ids);
+        }
+        else{
+            //获取部门下的所有用户
+            CompanyUser usermap=new CompanyUser();
+            usermap.setDeptId(param.getDeptId());
+            List<CompanyUser> users = userService.getUserListByDeptId(usermap);
+            List<Long> userIds = users.stream().map(element -> element.getUserId()).collect(Collectors.toList());
+            param.setUsers(userIds.toArray(new Long[userIds.size()]));
+        }
+        if(param.getUsers()!=null&&param.getUsers().length>0){
+            List<CompanyVoiceLogsStatisticsVO> list= voiceLogsService.selectVoiceLogsStatisticsList(param);
+            if(list!=null){
+                for(CompanyVoiceLogsStatisticsVO vo:list){
+                    double f1 = new BigDecimal((float)vo.getCallSuccessCount()/vo.getCallCount()).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue()*100;
+                    vo.setCallRate(f1);
+                }
+            }
+            TimeUtils.TimeEntity timeEntity=TimeUtils.parseTime(param.getType().toString(),param.getStartTime(),param.getEndTime());
+            timeEntity.setUserIds(param.getUsers());
+            Integer cycleNum = timeEntity.getCycleNum();
+            Integer beginTime = timeEntity.getBeginTime();
+            List<Integer> timeList = new ArrayList<>();
+            for (int i = 1; i <= cycleNum; i++) {
+                timeList.add(beginTime);
+                beginTime = TimeUtils.formatTime(beginTime);
+            }
+            List<JSONObject> jsonObjectList = voiceLogsService.selectVoiceLogsTotalCount(timeEntity.toMap());
+            List<String> dates = jsonObjectList.stream().map(jsonObject -> jsonObject.getString("type")).collect(Collectors.toList());
+            List<Integer> callCount = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("callCount")).collect(Collectors.toList());
+            List<Integer> callSuccessCount = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("callSuccessCount")).collect(Collectors.toList());
+            List<Integer> times = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("times")).collect(Collectors.toList());
+            List<Integer> billingTime = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("billingTime")).collect(Collectors.toList());
+            return R.ok().put("list",list).put("dates",dates).put("callCount",callCount).put("callSuccessCount",callSuccessCount).put("times",times).put("billingTime",billingTime);
+        }
+        else {
+            return R.ok("未查找到数据");
+        }
+    }
+
+    @ApiOperation("短信统计")
+    @GetMapping("/getSmsLogsStatistics")
+    public R smsLogs(CompanyStatisticsParam param)
+    {
+        if(StringUtils.isNotEmpty(param.getUserIds())){
+            String[] userIds=param.getUserIds().split(",");
+            Long[] ids=new Long[userIds.length];
+            for(int i=0;i<ids.length; i++){
+                ids[i]=Long.parseLong(userIds[i]);
+            }
+            param.setUsers(ids);
+        }
+        else{
+            //获取部门下的所有用户
+            CompanyUser usermap=new CompanyUser();
+            usermap.setDeptId(param.getDeptId());
+            List<CompanyUser> users = userService.getUserListByDeptId(usermap);
+            List<Long> userIds = users.stream().map(element -> element.getUserId()).collect(Collectors.toList());
+            param.setUsers(userIds.toArray(new Long[userIds.size()]));
+        }
+        if(param.getUsers()!=null&&param.getUsers().length>0){
+            List<CompanySmsLogsStatisticsVO> list= smsLogsService.selectSmsLogsStatisticsList(param);
+
+            TimeUtils.TimeEntity timeEntity=TimeUtils.parseTime(param.getType().toString(),param.getStartTime(),param.getEndTime());
+            timeEntity.setUserIds(param.getUsers());
+            Integer cycleNum = timeEntity.getCycleNum();
+            Integer beginTime = timeEntity.getBeginTime();
+            List<Integer> timeList = new ArrayList<>();
+            for (int i = 1; i <= cycleNum; i++) {
+                timeList.add(beginTime);
+                beginTime = TimeUtils.formatTime(beginTime);
+            }
+            List<JSONObject> jsonObjectList = smsLogsService.selectSmsLogsCounts(timeEntity.toMap());
+            List<String> dates = jsonObjectList.stream().map(jsonObject -> jsonObject.getString("type")).collect(Collectors.toList());
+            List<Integer> smsCount = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("smsCount")).collect(Collectors.toList());
+            List<Integer> successCount = jsonObjectList.stream().map(jsonObject -> jsonObject.getInteger("successCount")).collect(Collectors.toList());
+            return R.ok().put("list",list).put("dates",dates).put("smsCount",smsCount).put("successCount",successCount);
+        }
+        else {
+            return R.ok("未查找到数据");
+        }
+    }
+
+}

+ 140 - 0
fs-company-app/src/main/java/com/fs/app/controller/StorePaymentController.java

@@ -0,0 +1,140 @@
+package com.fs.app.controller;
+
+import cn.hutool.core.img.ImgUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.extra.qrcode.QrCodeUtil;
+import com.fs.app.annotation.Login;
+import com.fs.common.annotation.DataScope;
+import com.fs.common.config.FSConfig;
+import com.fs.common.core.domain.R;
+import com.fs.common.exception.CustomException;
+import com.fs.common.utils.ServletUtils;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.ICompanyUserService;
+import com.fs.his.param.FsStorePaymentParam;
+import com.fs.his.service.IFsStorePaymentService;
+import com.fs.his.vo.FsStorePaymentVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.ApiOperation;
+import org.apache.commons.io.FileUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+
+@RestController
+@RequestMapping("/app/storePayment")
+public class StorePaymentController extends AppBaseController
+{
+    @Autowired
+    private FSConfig fsConfig;
+    @Autowired
+    private IFsStorePaymentService fsStorePaymentService;
+    @Autowired
+    private ICompanyUserService companyUserService;
+    @Login
+    @GetMapping("/getPaymenyList")
+    @DataScope(deptAlias = "p",userAlias = "cu")
+    public R list(FsStorePaymentParam param)
+    {
+        PageHelper.startPage(ServletUtils.getParameterToInt("page"), ServletUtils.getParameterToInt("pageSize"));
+        param.setBusinessType(1);
+        param.setStatus(1);
+        param.setCompanyId(getCompanyId());
+        List<FsStorePaymentVO> list = fsStorePaymentService.selectFsStorePaymentListQueryVO(param);
+        PageInfo<FsStorePaymentVO> listPageInfo=new PageInfo<>(list);
+        return R.ok().put("data",listPageInfo);
+    }
+
+
+    @Login
+    @ApiOperation("获取支付宝收款码")
+    @GetMapping("/getAlipayQrImg")
+    public R getAlipayQrImg(  HttpServletRequest request){
+        Long userId=Long.parseLong(getUserId());
+        try {
+            CompanyUser companyUser=companyUserService.selectCompanyUserById(userId);
+            File newFile = new File("qr.jpg");
+            File newFileT = new File("simsunb.ttf");
+            try {
+                InputStream stream =  getClass().getClassLoader().getResourceAsStream("qr.jpg");
+                FileUtils.copyInputStreamToFile(stream, newFile);
+                // if(!newFile.exists()){
+                //     InputStream stream =  getClass().getClassLoader().getResourceAsStream("fx.jpg");
+                //     FileUtils.copyInputStreamToFile(stream, newFile);
+                // }
+                if(!newFileT.exists()){
+                    InputStream streamT =  getClass().getClassLoader()
+                            .getResourceAsStream("simsunb.ttf");
+                    FileUtils.copyInputStreamToFile(streamT, newFileT);
+                }
+            } catch (IOException e) {
+
+                throw new CustomException(e.getMessage());
+            }
+
+            try {
+                String url=fsConfig.getQrPath()+"/qr-"+userId+".jpg";
+                File outputFile = new File(url);
+                if(!outputFile.exists())
+                {
+                    try {
+                        outputFile.createNewFile();
+
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                }
+//                Font font =  Font.createFont(Font.TRUETYPE_FONT, newFileT);
+//                Font f= font.deriveFont(Font.PLAIN,20);
+//                ImgUtil.pressText(//
+//                        newFile,
+//                        outputFile,
+//                        companyUser.getNickName()+" 为您服务",
+//                        Color.BLACK,
+//                        f, //字体
+//                        65, //x坐标修正值。 默认在中间,偏移量相对于中间偏移
+//                        100, //y坐标修正值。 默认在中间,偏移量相对于中间偏移
+//                        0.8f//透明度:alpha 必须是范围 [0.0, 1.0] 之内(包含边界值)的一个浮点数字
+//                );
+                File qr = new File(fsConfig.getQrPath()+"/qr-"+userId+".png");
+                if(!qr.exists())
+                {
+                    try {
+                        qr.createNewFile();
+
+                    } catch (IOException e) {
+                        e.printStackTrace();
+                    }
+                }
+                QrCodeUtil.generate( "http://alipay.yjf.runtzh.com/#/?companyId="+companyUser.getCompanyId()+"&companyUserId="+companyUser.getUserId(), 200, 200,
+                        FileUtil.file(fsConfig.getQrPath()+"/qr-"+userId+".png"));
+                ImgUtil.pressImage(
+                        newFile,
+                        outputFile,
+                        ImgUtil.read(qr), //QR图片
+                        0, //x坐标修正值。 默认在中间,偏移量相对于中间偏移
+                        20, //y坐标修正值。 默认在中间,偏移量相对于中间偏移
+                        1f
+                );
+                return R.ok().put("url","profile/qr/qr-"+userId+".jpg");
+
+            } catch (Exception e) {
+                e.printStackTrace();
+                return R.error("操作异常");
+            }
+        } catch (Exception e){
+
+            return R.error("操作异常");
+        }
+    }
+
+}

+ 85 - 0
fs-company-app/src/main/java/com/fs/app/controller/StoreProductPackageController.java

@@ -0,0 +1,85 @@
+package com.fs.app.controller;
+
+
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONUtil;
+import com.fs.app.annotation.Login;
+import com.fs.common.core.domain.R;
+import com.fs.his.domain.FsStoreProduct;
+import com.fs.his.domain.FsStoreProductAttrValue;
+import com.fs.his.domain.FsStoreProductPackage;
+import com.fs.his.dto.StoreOrderProductDTO;
+import com.fs.his.dto.StorePackageProductDTO;
+import com.fs.his.param.FsStoreProductPackageQueryParam;
+import com.fs.his.service.IFsStoreProductAttrValueService;
+import com.fs.his.service.IFsStoreProductPackageService;
+import com.fs.his.service.IFsStoreProductService;
+import com.fs.his.vo.FsStoreProductPacketVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.List;
+
+
+@Api("套餐")
+@RestController
+@RequestMapping(value="/app/storeProductPackage")
+public class StoreProductPackageController extends  AppBaseController {
+
+    @Autowired
+    private IFsStoreProductPackageService productPackageService;
+    @Autowired
+    private IFsStoreProductAttrValueService attrValueService;
+    @Autowired
+    private IFsStoreProductService storeProductService;
+    @Login
+    @ApiOperation("获取套餐列表")
+    @GetMapping("/getStoreProductPackage")
+    public R getStoreProductPackage(FsStoreProductPackageQueryParam param, HttpServletRequest request){
+        PageHelper.startPage(param.getPage(), param.getPageSize());
+        List<FsStoreProductPacketVO> list=productPackageService.selectFsStoreProductPackageListQueryVO(param);
+        PageInfo<FsStoreProductPacketVO> listPageInfo=new PageInfo<>(list);
+        return R.ok().put("data",listPageInfo);
+    }
+    @Login
+    @ApiOperation("获取套餐详情")
+    @GetMapping("/getStoreProductPackageDetails")
+    public R getStoreProductPackageDetails(@RequestParam("packageId") Long packageId, HttpServletRequest request){
+        FsStoreProductPackage storeProductPackage=productPackageService.selectFsStoreProductPackageById(packageId);
+        List<StoreOrderProductDTO> productList=new ArrayList<>();
+        JSONArray jsonArray= JSONUtil.parseArray(storeProductPackage.getProducts());
+        List<StorePackageProductDTO> goodsList=JSONUtil.toList(jsonArray, StorePackageProductDTO.class);
+        for(StorePackageProductDTO dto:goodsList){
+            StoreOrderProductDTO productDTO=new StoreOrderProductDTO();
+            FsStoreProductAttrValue attrValue=attrValueService.selectFsStoreProductAttrValueById(dto.getId());
+            if(attrValue!=null){
+                FsStoreProduct product=storeProductService.selectFsStoreProductById(attrValue.getProductId());
+                if(product!=null){
+                    productDTO.setProductId(attrValue.getProductId());
+                    productDTO.setId(dto.getId());
+                    productDTO.setBarCode(attrValue.getBarCode());
+                    productDTO.setPrice(attrValue.getPrice());
+                    productDTO.setCount(dto.getCount());
+                    productDTO.setSku(attrValue.getSku());
+                    productDTO.setImage(attrValue.getImage());
+                    productDTO.setProductName(product.getProductName());
+                    productList.add(productDTO);
+                }
+
+            }
+
+        }
+        storeProductPackage.setProductList(productList);
+        return R.ok().put("data",storeProductPackage);
+    }
+
+}

+ 62 - 0
fs-company-app/src/main/java/com/fs/app/controller/TestController.java

@@ -0,0 +1,62 @@
+package com.fs.app.controller;
+
+
+import com.fs.wx.cp.config.WxCpConfiguration;
+import io.swagger.annotations.ApiOperation;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.cp.api.WxCpExternalContactService;
+import me.chanjar.weixin.cp.api.WxCpMessageService;
+import me.chanjar.weixin.cp.api.WxCpService;
+import me.chanjar.weixin.cp.bean.message.WxCpMessage;
+import me.chanjar.weixin.cp.bean.message.WxCpMessageSendResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+
+@RestController
+@RequestMapping(value="/")
+public class TestController extends AppBaseController {
+
+
+	@Autowired
+	private WxCpConfiguration wxCpConfiguration;
+
+	@ApiOperation("获取数据字典")
+	@GetMapping("/WW_verify_vFu5z0l4wIXrSMbr.txt")
+	public String getDicts(
+	){
+
+		return "vFu5z0l4wIXrSMbr";
+
+	}
+
+	@ApiOperation("test")
+	@GetMapping("/sendTest")
+	public WxCpMessageSendResult sendTest(
+	) throws WxErrorException {
+		WxCpService cpService = wxCpConfiguration.getCpService(1000002);
+		WxCpExternalContactService externalContactService=cpService.getExternalContactService();
+		List<String> list=externalContactService.listExternalContacts("YuZhongXin");
+		WxCpMessage message=new WxCpMessage();
+		message.setAgentId(1000002);
+		message.setToUser("YuZhongXin");
+		message.setContent("test");
+		message.setMsgType("text");
+		WxCpMessageService messageService=cpService.getMessageService();
+		cpService.getExternalContactService();
+		WxCpMessageSendResult data=messageService.send(message);
+		return data;
+
+	}
+
+
+
+
+
+
+
+}

+ 650 - 162
fs-company-app/src/main/java/com/fs/app/controller/UserController.java

@@ -1,195 +1,683 @@
 package com.fs.app.controller;
 
-
-import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.lang.Validator;
 import cn.hutool.json.JSONUtil;
-import com.fs.ai.service.IBaiduAIService;
-import com.fs.ai.vo.BaiduAIMsgResultVO;
+import com.alibaba.fastjson.JSONObject;
 import com.fs.app.annotation.Login;
-import com.fs.app.param.AICallChatParam;
-import com.fs.app.param.EditChatMsgParam;
 import com.fs.app.param.LoginParam;
+import com.fs.app.utils.JwtUtils;
+import com.fs.app.vo.CompanyRoleVO;
 import com.fs.app.vo.UserListVO;
+import com.fs.app.vo.UserPostVO;
 import com.fs.app.vo.UserVO;
-import com.fs.chat.config.WxConfig;
-import com.fs.chat.domain.ChatMsg;
-import com.fs.chat.domain.ChatMsgLogs;
-import com.fs.chat.domain.ChatRole;
-import com.fs.chat.domain.ChatSession;
-import com.fs.chat.param.ChatMsgListAParam;
-import com.fs.chat.service.IChatMsgLogsService;
-import com.fs.chat.service.IChatMsgService;
-import com.fs.chat.service.IChatRoleService;
-import com.fs.chat.service.IChatSessionService;
-import com.fs.chat.vo.ChatMsgListAVO;
-import com.fs.common.annotation.Log;
-import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.annotation.RepeatSubmit;
+import com.fs.common.config.FSConfig;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.common.exception.ServiceException;
+import com.fs.common.exception.base.BaseException;
+import com.fs.common.utils.PatternUtils;
 import com.fs.common.utils.PinYinUtil;
-import com.fs.common.utils.SecurityUtils;
-import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
-import com.fs.common.utils.sign.Md5Utils;
-import com.fs.common.utils.spring.SpringUtils;
+import com.fs.common.utils.bean.BeanUtils;
+import com.fs.common.utils.http.HttpUtils;
+import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyUser;
-import com.fs.company.service.ICompanyPostService;
-import com.fs.company.service.ICompanyUserService;
+import com.fs.company.domain.CompanyUserCard;
+import com.fs.company.param.CompanyUserCardQueryParam;
+import com.fs.company.param.EditPwdParam;
+import com.fs.company.param.EditUserInfoParam;
+import com.fs.company.param.EditUserQrCodeParam;
+import com.fs.company.service.*;
+import com.fs.company.vo.CompanyUserAppVO;
 import com.fs.company.vo.CompanyUserVO;
+import com.fs.core.security.SecurityUtils;
+import com.fs.course.service.IFsCourseRedPacketLogService;
 import com.fs.his.service.IFsUserService;
+import com.fs.wx.miniapp.config.WxMaProperties;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
+import java.time.ZoneId;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
-import static com.fs.common.constant.FsConstants.REDIS_CHAT_SESSION;
-
+import static com.fs.common.constant.Constants.PAGE_SIZE;
 
+@Slf4j
+@Api("个人中心")
 @RestController
-@RequestMapping(value="/app/user")
+@RequestMapping(value = "/app/user")
 public class UserController extends AppBaseController {
-	@Autowired
-	ICompanyPostService postService;
-	@Autowired
-	IChatRoleService chatRoleService;
-	@Autowired
-	ICompanyUserService companyUserService;
-
-	@Autowired
-	RedisCache redisCache;
-	@PostMapping("/login")
-	public R login(@RequestBody LoginParam param)
-	{
-		CompanyUser user=companyUserService.selectUserByUserName(param.getAccount());
-		if(user==null){
-			return R.error("帐号不存在");
-		}
-		if(!user.getStatus().equals("0")){
-			return R.error("帐号已被禁用");
-		}
-		if(!SecurityUtils.matchesPassword(param.getPassword(),user.getPassword())){
-			return R.error("密码不正确");
-		}
-		String token = jwtUtils.generateToken(user.getUserId());
-//		redisCache.setCacheObject("doctorToken:"+user.getUserId(),token,604800, TimeUnit.SECONDS);
-		redisCache.setCacheObject("AiChatToken:"+user.getUserId(),token,604800, TimeUnit.SECONDS);
-
-		Map<String,Object> map=new HashMap<>();
-		map.put("token",token);
-		map.put("user",user);
-
-		return R.ok().put("data",map);
-	}
-
-
- 	@Login
-	@GetMapping("getCompanyUser")
-	public R getCompanyUser()
-	{
-		CompanyUser user = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
-		return R.ok().put("data",user);
-	}
-
-	@ApiOperation("检测是否登录")
-	@GetMapping("/checkLogin")
-	public R checkLogin(HttpServletRequest request){
-		if(StringUtils.isEmpty(getUserId())){
-			//未登录
-			return R.error("未登录");
-		}
-		else{
-			//登录
-			String token = jwtUtils.generateToken(Long.parseLong(getUserId()));
-			Map<String,Object> map=new HashMap<>();
-			map.put("token",token);
-			return R.ok("认证成功").put("userId",getUserId()).put("token",token);
-		}
-	}
-
-	@Login
-	@ApiOperation("获取通讯录")
-	@GetMapping("/getAllUsers")
-	public R getAllUsers(HttpServletRequest request, @ApiParam(required = false, name = "searchKey", value = "searchKey") @RequestParam(value = "searchKey", required = false) String searchKey){
-		CompanyUser user=new CompanyUser();
-		user.setNickName(searchKey);
-		CompanyUser companyUser = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
-		user.setCompanyId(companyUser.getCompanyId());
-		user.setIsDel(0);
-		List<CompanyUserVO> list = companyUserService.selectMyUserList(user);
-		List<UserVO> users=new ArrayList<>();
-		for(CompanyUserVO u:list){
-			UserVO vo=new UserVO();
-			vo.setDeptName(u.getDeptName());
-			vo.setFirstLetter(PinYinUtil.cn2py(u.getNickName().substring(0,1)));
-			vo.setNickName(u.getNickName());
-			vo.setUserId(u.getUserId());
-			vo.setAvatar(u.getAvatar());
-			users.add(vo);
-		}
-		Map<Object, List<UserVO>> res = users.parallelStream().collect(
-				Collectors.groupingBy(
-						item->{return Character.toUpperCase(item.getFirstLetter().charAt(0));},//根据首字母分组
-						TreeMap::new,//有序map实现排序
-						Collectors.toList()
-				)
-		);
-		List<UserListVO> vos=res.entrySet().stream().map(e -> new UserListVO(e.getKey().toString(),e.getValue())).collect(Collectors.toList());
-		return R.ok( ).put("users",vos);
-	}
-
-	/**
-	 * 获取用户信息
-	 * @param request
-	 * @return
-	 */
-	@Login
-	@ApiOperation("获取用户信息")
-	@GetMapping("/getUserInfo")
-	public R getUserInfo(HttpServletRequest request){
-		try {
-			CompanyUser companyUser=companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
-			List<String> postList=postService.selectPostNameListByUserId(Long.parseLong(getUserId()));
-			if(companyUser==null){
-				return R.error(40001,"用户不存在");
-			}
-			if(companyUser.getStatus().equals("1")){
-				return R.error(40002,"用户已停用");
-			}
-			return R.ok().put("user",companyUser).put("post",postList);
-		} catch (Exception e){
-
-			return R.error("操作异常");
-		}
-	}
-	@Login
-	@ApiOperation("获取用户信息ByUserId")
-	@GetMapping("/getUserInfoByUserId")
-	public R getUserInfoByUserId(
-			@ApiParam(required = true, name = "userId", value = "用户ID") @RequestParam(value = "userId", required = false) Long userId,
-			HttpServletRequest request){
-		try {
-			CompanyUser user=companyUserService.selectCompanyUserById(userId);
-			List<String> postList=postService.selectPostNameListByUserId(userId);
-			if(user==null){
-				return R.error(40001,"用户不存在");
-			}
-			if(user.getStatus().equals("1")){
-				return R.error(40002,"用户已停用");
-			}
-			return R.ok().put("user",user).put("post",postList);
-		} catch (Exception e){
-
-			return R.error("操作异常");
-		}
-	}
 
+    @Autowired
+    private FSConfig fsConfig;
+    @Autowired
+    JwtUtils jwtUtils;
+    @Autowired
+    ICompanyUserService userService;
+    @Autowired
+    ICompanyPostService postService;
+    @Autowired
+    ICompanyMenuService menuService;
+    @Autowired
+    private ICompanyService companyService;
+    @Autowired
+    RedisCache redisCache;
+    @Autowired
+    ICompanyUserService companyUserService;
+
+    @Autowired
+    ICompanyUserCardService companyUserCardService;
+    @Autowired
+    private IFsUserService fsUserService;
+    @Autowired
+    private IFsCourseRedPacketLogService courseRedPacketLogService;
+
+    @Autowired
+    private WxMaProperties properties;
+    private String aifabuAppId = "7b471be905ab17e00f3b858c6710dd117601d008";
+
+//	@PostMapping("/loginByPwd")
+//	@ApiOperation("密码登录")
+//	public R loginByPwd(@Validated @RequestBody LoginParam param){
+//		try {
+//
+//			CompanyUser companyUser=userService.selectUserByUserName(param.getUserName());
+//			if(companyUser==null){
+//				return R.error("工号不存在");
+//			}
+//			if(companyUser.getStatus().equals("1")){
+//				return R.error("用户已禁用");
+//			}
+//			if (!SecurityUtils.matchesPassword(param.getPassword(), companyUser.getPassword())) {
+//				return R.error("密码错误");
+//			}
+//			Company company=companyService.selectCompanyById(companyUser.getCompanyId()) ;
+//			if(company==null||company.getStatus()==0||company.getIsDel()==1){
+//				throw new BaseException("此用户所属公司不存在或已停用");
+//			}
+//			if(StringUtils.isNotEmpty(param.getJpushId())){
+//				companyUser.setJpushId(param.getJpushId());
+//				userService.updateUserProfile(companyUser);
+//			}
+//			//生成token
+//			String token = jwtUtils.generateToken(companyUser.getUserId());
+//			//调用REDIS生成用户的TOKEN
+//
+//			//redisCache.setCacheObject("token:"+companyUser.getUserId(),token,2592000, TimeUnit.SECONDS);
+//			//redisCache.setCacheObject("companyId:"+companyUser.getUserId(),companyUser.getCompanyId(),2592000, TimeUnit.SECONDS);
+//
+//			redisCache.setCacheObject("token:"+companyUser.getUserId(),token,604800, TimeUnit.SECONDS);
+//			redisCache.setCacheObject("companyId:"+companyUser.getUserId(),companyUser.getCompanyId(),604800, TimeUnit.SECONDS);
+//
+//			//获取权限
+//			Set<String> perms = new HashSet<String>();
+//			// 管理员拥有所有权限
+//			if (companyUser.isAdmin())
+//			{
+//				perms.add("*:*:*");
+//			}
+//			else
+//			{
+//				perms.addAll(menuService.selectMenuPermsByUserId(companyUser.getUserId()));
+//			}
+//
+//			//redisCache.setCacheObject("perms:"+companyUser.getUserId(), JSONUtil.toJsonStr(perms),2592000, TimeUnit.SECONDS);
+//			redisCache.setCacheObject("perms:"+companyUser.getUserId(), JSONUtil.toJsonStr(perms),604800, TimeUnit.SECONDS);
+//
+//			Map<String ,Object> result=new HashMap<>();
+//			result.put("token",token);
+//			result.put("user",companyUser);
+//			result.put("perms",perms);
+//			return R.ok("登录成功").put("data",result);
+//		} catch (Exception e) {
+//			return R.error("登录异常");
+//		}
+//	}
+
+    @PostMapping("/login")
+    @ApiOperation("密码登录")
+    public R login(@Validated @RequestBody LoginParam param) {
+
+        // 密码校验
+        if (!PatternUtils.checkPassword(param.getPassword())) {
+            return R.error("密码格式不正确,需包含字母、数字和特殊字符,长度为 8-20位");
+        }
+
+        try {
+            //判断用户基本规则
+            CompanyUser companyUser = userService.selectUserByUserName(param.getAccount());
+            if (companyUser == null) {
+                return R.error("工号不存在");
+            }
+            if (companyUser.getStatus().equals("1")) {
+                return R.error("用户已禁用");
+            }
+            if (!SecurityUtils.matchesPassword(param.getPassword(), companyUser.getPassword())) {
+                return R.error("密码错误");
+            }
+            if (companyUser.getIsAudit() == 0) {
+                return R.error("用户未审核");
+            }
+
+            Company company = companyService.selectCompanyById(companyUser.getCompanyId());
+            if (company == null || company.getStatus() == 0 || company.getIsDel() == 1) {
+                throw new BaseException("此用户所属公司不存在或已停用");
+            }
+
+            // 公司名称
+            companyUser.setCompanyName(company.getCompanyName());
+            // 岗位
+            companyUser.setPosts(postService.selectCompanyPostListByUserId(companyUser.getUserId()));
+
+            if (StringUtils.isNotEmpty(param.getJpushId())) {
+                companyUser.setJpushId(param.getJpushId());
+                userService.updateUserProfile(companyUser);
+            }
+            //生成token
+            String token = jwtUtils.generateToken(companyUser.getUserId());
+            //调用REDIS生成用户的TOKEN
+
+            redisCache.setCacheObject("token:" + companyUser.getUserId(), token, 604800, TimeUnit.SECONDS);
+            redisCache.setCacheObject("companyId:" + companyUser.getUserId(), companyUser.getCompanyId(), 604800, TimeUnit.SECONDS);
+
+            //获取权限
+            Set<String> perms = new HashSet<String>();
+            // 管理员拥有所有权限
+            if (companyUser.isAdmin()) {
+                perms.add("*:*:*");
+            } else {
+                perms.addAll(menuService.selectMenuPermsByUserId(companyUser.getUserId()));
+            }
+
+            //redisCache.setCacheObject("perms:"+companyUser.getUserId(), JSONUtil.toJsonStr(perms),2592000, TimeUnit.SECONDS);
+            redisCache.setCacheObject("perms:" + companyUser.getUserId(), JSONUtil.toJsonStr(perms), 604800, TimeUnit.SECONDS);
+
+            Map<String, Object> result = new HashMap<>();
+            result.put("token", token);
+            result.put("user", companyUser);
+            result.put("perms", perms);
+            return R.ok("登录成功").put("data", result);
+        } catch (Exception e) {
+            return R.error("登录异常");
+        }
+    }
+
+//    /**
+//     * 获取用户信息
+//     *
+//     * @param request
+//     * @return
+//     */
+//    @Login
+//    @ApiOperation("获取用户信息")
+//    @GetMapping("/getUserInfo")
+//    public R getUserInfo(HttpServletRequest request) {
+//        try {
+//            CompanyUser companyUser = userService.selectCompanyUserById(Long.parseLong(getUserId()));
+//            List<String> postList = postService.selectPostNameListByUserId(Long.parseLong(getUserId()));
+//            if (companyUser == null) {
+//                return R.error(40001, "用户不存在");
+//            }
+//            if (companyUser.getStatus().equals("1")) {
+//                return R.error(40002, "用户已停用");
+//            }
+//            return R.ok().put("user", companyUser).put("post", postList);
+//        } catch (Exception e) {
+//
+//            return R.error("操作异常");
+//        }
+//    }
+
+    @Login
+    @ApiOperation("获取用户信息")
+    @GetMapping("/getCompanyUser")
+    public R getCompanyUser() {
+        try {
+            CompanyUser companyUser = userService.selectCompanyUserById(Long.parseLong(getUserId()));
+            if (companyUser == null) {
+                return R.error(40001, "用户不存在");
+            }
+            if (companyUser.getStatus().equals("1")) {
+                return R.error(40002, "用户已停用");
+            }
+            // 公司名称
+            Company company = companyService.selectCompanyById(companyUser.getCompanyId());
+            companyUser.setCompanyName(company.getCompanyName());
+            // 岗位
+            companyUser.setPosts(postService.selectCompanyPostListByUserId(companyUser.getUserId()));
+            return R.ok().put("user", companyUser);
+        } catch (Exception e) {
+
+            return R.error("操作异常");
+        }
+    }
+
+    @Login
+    @ApiOperation("检测是否登录")
+    @GetMapping("/checkLogin")
+    public R checkLogin(HttpServletRequest request) {
+        return R.ok("认证成功");
+    }
+
+
+    @Login
+    @ApiOperation("获取通讯录")
+    @GetMapping("/getAllUsers")
+    public R getAllUsers(HttpServletRequest request, @ApiParam(required = false, name = "searchKey", value = "searchKey") @RequestParam(value = "searchKey", required = false) String searchKey,
+                         @RequestParam Integer isAudit) {
+        log.debug("获取通讯录 searchKey:{}, isAudit: {}", searchKey, isAudit);
+        CompanyUser user = new CompanyUser();
+        user.setNickName(searchKey);
+        user.setCompanyId(getCompanyId());
+        user.setIsAudit(isAudit);
+        user.setIsDel(0);
+        List<CompanyUserVO> list = userService.selectMyUserList(user);
+        List<UserVO> users = new ArrayList<>();
+        for (CompanyUserVO u : list) {
+            UserVO vo = new UserVO();
+            if (Objects.nonNull(u.getDept())) {
+                vo.setDeptId(u.getDept().getDeptId());
+                vo.setDeptName(u.getDept().getDeptName());
+            }
+            vo.setFirstLetter(PinYinUtil.cn2py(u.getNickName().substring(0, 1)));
+            vo.setNickName(u.getNickName());
+            vo.setUserId(u.getUserId());
+            vo.setAvatar(u.getAvatar());
+            if (Objects.nonNull(u.getCreateTime())) {
+                vo.setRegisterTime(u.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
+            }
+            vo.setStatus(u.getStatus());
+            vo.setPhoneNumber(u.getPhonenumber());
+            vo.setIsAudit(u.getIsAudit());
+
+            // 岗位信息
+            if (Objects.nonNull(u.getPosts())) {
+                vo.setPost(u.getPosts().stream().map(p -> {
+                    UserPostVO post = new UserPostVO();
+                    post.setPostId(p.getPostId());
+                    post.setPostName(p.getPostName());
+                    return post;
+                }).collect(Collectors.toList()));
+            }
+
+            // 角色信息
+            if (Objects.nonNull(u.getRoles())) {
+                vo.setRoles(u.getRoles().stream().map(r -> {
+                    CompanyRoleVO role = new CompanyRoleVO();
+                    role.setRoleId(r.getRoleId());
+                    role.setRoleName(r.getRoleName());
+                    return role;
+                }).collect(Collectors.toList()));
+            }
+
+            users.add(vo);
+        }
+        Map<Object, List<UserVO>> res = users.parallelStream().collect(
+                Collectors.groupingBy(
+                        item -> {
+                            return Character.toUpperCase(item.getFirstLetter().charAt(0));
+                        },//根据首字母分组
+                        TreeMap::new,//有序map实现排序
+                        Collectors.toList()
+                )
+        );
+        List<UserListVO> vos = res.entrySet().stream().map(e -> new UserListVO(e.getKey().toString(), e.getValue())).collect(Collectors.toList());
+        return R.ok().put("users", vos);
+    }
+
+//    @Login
+    @ApiOperation("获取用户信息ByUserId")
+    @GetMapping("/getUserInfoByUserId")
+    public R getUserInfoByUserId(
+            @ApiParam(required = true, name = "userId", value = "用户ID") @RequestParam(value = "userId", required = false) Long userId,
+            HttpServletRequest request) {
+        try {
+            log.debug("获取用户信息ByUserId userId:{}", userId);
+            CompanyUser user = userService.selectCompanyUserById(userId);
+            List<String> postList = postService.selectPostNameListByUserId(userId);
+            if (user == null) {
+                return R.error(40001, "用户不存在");
+            }
+            if (user.getStatus().equals("1")) {
+                return R.error(40002, "用户已停用");
+            }
+
+
+            // 查询用户会员数、今日新增用户数
+            Map<String, Long> result = fsUserService.getUserVipCountByCompanyUserId(userId);
+            // 红包数
+            int redPackCount = courseRedPacketLogService.getCountByCompanyUserIdId(userId);
+            // 新用户红包金额
+            BigDecimal newVipRedPackAmount = courseRedPacketLogService.getNewVipRedPackAmountByCompanyUserIdId(userId);
+
+            CompanyUserAppVO userVO = new CompanyUserAppVO();
+            BeanUtils.copyProperties(user, userVO);
+
+            userVO.setVipCount(result.getOrDefault("vipCount", 0L));
+            userVO.setNewVipCount(result.getOrDefault("newVipCount", 0L));
+            userVO.setRedPacketCount(redPackCount);
+            userVO.setNewVipRedPackAmount(newVipRedPackAmount);
+
+            return R.ok().put("user", userVO).put("post", postList);
+        } catch (Exception e) {
+
+            return R.error("操作异常");
+        }
+    }
+
+    @Login
+    @ApiOperation("修改密码")
+    @PostMapping("/setPwd")
+    public R setPwd(HttpServletRequest request, @RequestBody EditPwdParam param) {
+        try {
+
+            CompanyUser user = userService.selectCompanyUserById(Long.parseLong(getUserId()));
+            if (!SecurityUtils.matchesPassword(param.getOldPassword(), user.getPassword())) {
+                return R.error("旧密码错误");
+            }
+            if (SecurityUtils.matchesPassword(param.getOldPassword(), param.getPassword())) {
+                return R.error("新密码不能与旧密码相同");
+            }
+            if (userService.resetUserPwd(user.getUserName(), SecurityUtils.encryptPassword(param.getPassword())) > 0) {
+                return R.ok("密码修改成功");
+            } else {
+                return R.error("密码修改失败");
+            }
+        } catch (Exception e) {
+
+            return R.error("操作异常" + e.getMessage());
+        }
+    }
+
+    /**
+     * 修改头像
+     *
+     * @param request
+     * @param headImg
+     * @return
+     */
+    @Login
+    @ApiOperation("修改头像")
+    @PostMapping("/setHeadImg")
+    public R setHeadImg(HttpServletRequest request,
+                        @ApiParam(required = true, name = "headImg", value = "用户头像") @RequestParam(value = "headImg", required = false) String headImg) {
+        try {
+            CompanyUser user = userService.selectCompanyUserById(Long.parseLong(getUserId()));
+            if (user == null) {
+                return R.error("用户不存在");
+            }
+            if (user.getStatus().equals("1")) {
+                return R.error("用户已停用");
+            }
+            CompanyUser map = new CompanyUser();
+            map.setUserId(user.getUserId());
+            if (userService.updateUserAvatar(user.getUserName(), headImg) > 0) {
+                return R.ok("修改成功");
+            } else {
+                return R.error("修改失败");
+            }
+        } catch (Exception e) {
+
+            return R.error("操作异常");
+        }
+    }
+
+
+    @Login
+    @ApiOperation("修改用户信息")
+    @PostMapping("/setUserInfo")
+    public R setUserInfo(HttpServletRequest request, @RequestBody EditUserInfoParam param) {
+        try {
+
+            CompanyUser user = userService.selectCompanyUserById(Long.parseLong(getUserId()));
+            if (user == null) {
+                return R.error("用户不存在");
+            }
+            if (user.getStatus().equals("1")) {
+                return R.error("用户已停用");
+            }
+            if (param == null) {
+                return R.error("修改参数对象不能为空");
+            }
+            if (!Validator.isMobile(param.getMobile())) {
+                return R.error("手机号不正确");
+            }
+            if (!Validator.isEmail(param.getEmail())) {
+                return R.error("邮箱格式不正确");
+            }
+            user.setAvatar(param.getHeadImg());
+            user.setPhonenumber(param.getMobile());
+            user.setEmail(param.getEmail());
+            user.setSex(param.getSex());
+            user.setNickName(param.getNickName());
+            user.setQrCodeWeixin(param.getQrCodeWeixin());
+            if (userService.updateUserProfile(user) > 0) {
+                return R.ok("修改成功");
+            } else {
+                return R.error("修改失败");
+            }
+        } catch (Exception e) {
+            return R.error("操作异常" + e.getMessage());
+        }
+    }
+
+    @Login
+    @ApiOperation("修改二维码")
+    @PostMapping("/editQrCode")
+    @RepeatSubmit
+    public R editQrCode(HttpServletRequest request, @RequestBody EditUserQrCodeParam param) {
+        try {
+            CompanyUser user = userService.selectCompanyUserById(Long.parseLong(getUserId()));
+            if (user == null) {
+                return R.error("用户不存在");
+            }
+            if (user.getStatus().equals("1")) {
+                return R.error("用户已禁用");
+            }
+            //个人微信
+            CompanyUserCard companyUserCard = null;
+            if (param.getCardId() == null) {   //添加名片
+                companyUserCard = new CompanyUserCard();
+                companyUserCard.setUserId(Long.parseLong(getUserId()));
+                companyUserCard.setCompanyId(getCompanyId());
+                companyUserCard.setTitle(param.getTitle());
+                companyUserCard.setCreateTime(new Date());
+                companyUserCard.setType((long) param.getType());
+                companyUserCard.setImageUrl(param.getQrCodeWeixin());
+                int rows = companyUserCardService.insertCompanyUserCard(companyUserCard);
+                if (rows > 0) {
+                    String shorUrl = this.getShortUrlAction(companyUserCard.getId(), param.getTitle());
+                    companyUserCard.setShortUrl(shorUrl);
+                    if (companyUserCardService.updateUserCardShortUrlById(companyUserCard.getId(), shorUrl) > 0) {
+                        return R.ok("修改成功");
+                    }
+                }
+                return R.error("修改失败");
+            } else {
+                companyUserCard = companyUserCardService.selectCompanyUserCardById(param.getCardId());
+                companyUserCard.setImageUrl(param.getQrCodeWeixin());
+                companyUserCard.setUpdateTime(new Date());
+                if (companyUserCardService.updateCompanyUserCard(companyUserCard) > 0) {
+                    return R.ok("修改成功");
+                } else {
+                    return R.error("修改失败");
+                }
+            }
+
+        } catch (Exception e) {
+            return R.error("操作异常" + e.getMessage());
+        }
+    }
+
+    @Login
+    @ApiOperation("获取我的名片列表")
+    @GetMapping("/getMyCardList")
+    public R getMyCardList(CompanyUserCardQueryParam param) {
+        PageHelper.startPage(param.getPage(), PAGE_SIZE);
+        param.setCompanyId(getCompanyId());
+        param.setCompanyUserId(Long.parseLong(getUserId()));
+        List<CompanyUserCard> list = companyUserCardService.selectMyCardListQuery(param);
+        PageInfo<CompanyUserCard> listPageInfo = new PageInfo<>(list);
+        return R.ok().put("data", listPageInfo);
+    }
+
+
+    @Login
+    @ApiOperation("删除名片")
+    @PostMapping("/delMyCard")
+    public R delMyCard(@RequestParam("cardId") Long cardId) {
+        try {
+            CompanyUserCard companyUserCard = companyUserCardService.selectCompanyUserCardById(cardId);
+            String shortUrl = companyUserCard.getShortUrl();
+            String[] chainArr = shortUrl.split(".cn/");
+            String chain = "";
+            if (chainArr.length == 2) {
+                chain = chainArr[1];
+            }
+            if (StringUtils.isNotEmpty(chain)) {
+                JSONObject jsonObject = new JSONObject();
+                jsonObject.put("apikey", aifabuAppId);
+                String[] chains = new String[1];
+                chains[0] = chain;
+                jsonObject.put("chains", "[" + chain + "]");
+                String paramStr = jsonObject.toJSONString();
+                String postUrl = "https://openapi.aifabu.com/v1/chain/delChain?apikey=" + aifabuAppId + "&chains=" + "[" + chain + "]";
+                String postStr = HttpUtils.sendPost(postUrl, paramStr);
+                JSONObject obj = JSONObject.parseObject(postStr);
+//				Integer code= obj.getInteger("code");
+//				if(code==1){
+//
+//				}
+            }
+            if (companyUserCardService.deleteCompanyUserCardById(cardId) > 0) {
+                return R.ok("操作成功");
+            } else {
+                return R.error("操作失败");
+            }
+        } catch (Exception e) {
+            return R.error("操作异常" + e.getMessage());
+        }
+    }
+
+
+    @ApiOperation("查询微信urlScheme")
+    @GetMapping("/getAppletScheme")
+    public R getAppletScheme(@RequestParam(value = "cardId") Long cardId) {
+        try {
+            String appId = properties.getConfigs().get(0).getAppid();
+            String secret = properties.getConfigs().get(0).getSecret();
+            String rspStr = HttpUtils.sendGet("https://api.weixin.qq.com/cgi-bin/token", "grant_type=client_credential&" + "appid=" + appId + "&secret=" + secret);
+            JSONObject obj = JSONObject.parseObject(rspStr);
+            String access_token = obj.getString("access_token");
+            JSONObject jsonObject = new JSONObject();
+            JSONObject jump_wxaObj = new JSONObject();
+            jump_wxaObj.put("path", "/pages_company/card");
+            jump_wxaObj.put("query", "id=" + cardId);
+            jsonObject.put("jump_wxa", jump_wxaObj);
+            jsonObject.put("is_expire", false);
+            String paramStr = jsonObject.toJSONString();
+            String postStr = HttpUtils.sendPost("https://api.weixin.qq.com/wxa/generatescheme?access_token=" + access_token, paramStr);
+            obj = JSONObject.parseObject(postStr);
+            //response.addHeader("Access-Control-Allow-Origin", "*");
+            return R.ok().put("result", obj);
+        } catch (Exception e) {
+            return R.error("操作失败");
+        }
+    }
+
+
+    private String getShortUrlAction(Long cardId, String title) {
+        try {
+
+            JSONObject jsonObject = new JSONObject();
+            jsonObject.put("apikey", aifabuAppId);
+            String url = "http://company.yjf.runtzh.com/wx.html?id=" + cardId;
+            jsonObject.put("target_url", url);
+            jsonObject.put("group_id", 308195);
+            if (StringUtils.isNotEmpty(title)) {
+                jsonObject.put("chain_title", title);
+            }
+            String paramStr = jsonObject.toJSONString();
+            String postStr = HttpUtils.sendPost("https://openapi.aifabu.com/v1/chain/createChain", paramStr);
+            JSONObject obj = JSONObject.parseObject(postStr);
+            Integer code = obj.getInteger("code");
+            String shortUrl = "";
+            if (code == 1) {
+                JSONObject result = obj.getJSONObject("result");
+                shortUrl = result.getString("render_url");
+            }
+            return shortUrl;
+        } catch (Exception e) {
+            return "";
+        }
+    }
+
+    @Login
+    @ApiOperation("获取短链接")
+    @GetMapping("/getShortUrl")
+    public R getShortUrl(@RequestParam(value = "url") String url, @RequestParam(value = "title") String title) {
+
+        try {
+            JSONObject jsonObject = new JSONObject();
+            jsonObject.put("apikey", aifabuAppId);
+            jsonObject.put("target_url", url);
+            jsonObject.put("group_id", 308195);
+            if (StringUtils.isNotEmpty(title)) {
+                jsonObject.put("chain_title", title);
+            }
+            String paramStr = jsonObject.toJSONString();
+            String postStr = HttpUtils.sendPost("https://openapi.aifabu.com/v1/chain/createChain", paramStr);
+            JSONObject obj = JSONObject.parseObject(postStr);
+            return R.ok().put("data", obj);
+        } catch (Exception e) {
+            return R.error("操作失败");
+        }
+    }
+
+    @GetMapping("/getUserList")
+    public R getUserList() {
+        CompanyUser companyUser = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
+        CompanyUser map = new CompanyUser();
+        map.setCompanyId(companyUser.getCompanyId());
+        List<CompanyUser> list = companyUserService.selectCompanyUserList(map);
+        return R.ok().put("data", list);
+    }
+
+    @Login
+    @ApiOperation("修改用户状态")
+    @PostMapping("/changeUserState")
+    public R changeUserState(@RequestParam Long userId) {
+        log.debug("修改用户状态 userId :{}", userId);
+        CompanyUser companyUser = companyUserService.selectCompanyUserById(userId);
+        if (Objects.isNull(companyUser)) {
+            throw new ServiceException("用户不存在");
+        }
+
+        String state = "0".equals(companyUser.getStatus()) ? "1" : "0";
+        companyUser.setStatus(state);
+        companyUserService.updateCompanyUser(companyUser);
+        return R.ok();
+    }
+
+    @Login
+    @ApiOperation("批量审核用户")
+    @PostMapping("/audit")
+    public R auditUser(@RequestParam List<Long> userIds) {
+        log.debug("批量审核用户 userIds :{}", userIds);
+        companyUserService.auditUsers(userIds);
+        return R.ok();
+    }
 
 }

+ 192 - 0
fs-company-app/src/main/java/com/fs/app/controller/WxCompanyUserController.java

@@ -0,0 +1,192 @@
+package com.fs.app.controller;
+
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
+import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
+import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
+import cn.hutool.core.date.DateTime;
+import com.fs.app.annotation.Login;
+import com.fs.app.param.LoginMaWxParam;
+import com.fs.app.utils.JwtUtils;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.common.utils.ServletUtils;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.ICompanyDeptService;
+import com.fs.company.service.ICompanyUserService;
+import com.fs.core.config.WxMaConfiguration;
+import com.fs.his.domain.FsUser;
+import com.fs.his.service.IFsUserService;
+import com.fs.wx.miniapp.config.WxMaProperties;
+import io.jsonwebtoken.Claims;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Date;
+
+@Api("微信小程序相关接口(暂废弃,后面再删除)")
+@RestController
+@RequestMapping(value = "/app/wx/miniapp")
+@Slf4j
+public class WxCompanyUserController extends AppBaseController {
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    @Autowired
+    private WxMaProperties maProperties;
+
+    @Autowired
+    JwtUtils jwtUtils;
+
+    @Autowired
+    RedisCache redisCache;
+
+    @Autowired
+    private ICompanyUserService companyUserService;
+
+    @Autowired
+    private ICompanyDeptService companyDeptService;
+
+    @Autowired
+    private IFsUserService userService;
+
+    @ApiOperation("小程序-授权登录")
+    @PostMapping("/loginByMa")
+    public R login(@RequestBody LoginMaWxParam param) {
+        if (StringUtils.isBlank(param.getCode())) {
+            return R.error("code不存在");
+        }
+        //获取第二个小程序配置,序号从0开始
+        final WxMaService wxService = WxMaConfiguration.getMaService(maProperties.getConfigs().get(1).getAppid());
+        try {
+            WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(param.getCode());
+            this.logger.info(session.getSessionKey());
+            this.logger.info(session.getOpenid());
+            // 解密
+            WxMaPhoneNumberInfo phoneNoInfo = wxService.getUserService().getPhoneNoInfo(session.getSessionKey(), param.getEncryptedData(), param.getIv());
+            WxMaUserInfo userInfo = wxService.getUserService().getUserInfo(session.getSessionKey(), param.getEncryptedData(), param.getIv());
+
+            //以下暂时注释,不需要往销售表添加数据
+//            CompanyUser companyUser = companyUserService.getCompanyUserByOpenId(session.getOpenid());
+//            String ip = IpUtil.getRequestIp();
+//
+////            // 如果公司id为空(表示可能是该公司的第一位销售管理员),则需要根据电话号码判断是否存在销售,如果不存在则提示
+////            if (param.getCompanyId() == null) {
+////                if (checkPhone == null) {
+////                    throw new CustomException("由于不是管理员,不能直接登录", 401);
+////                }
+////            }
+//            if (companyUser == null) {
+//                CompanyUser checkPhone = companyUserService.getCompanyUserByPhone(phoneNoInfo.getPhoneNumber());
+//                if (checkPhone != null) {
+//                    if (checkPhone.getMaOpenId() == null) {
+//                        companyUser = checkPhone;
+//                        companyUser.setMaOpenId(session.getOpenid());
+//                        companyUser.setUserId(companyUser.getUserId());
+//                        companyUser.setUpdateTime(new DateTime());
+//                        companyUser.setLoginIp(ip);
+//                        companyUserService.updateUserProfile(companyUser);
+//                    } else {
+//                        throw new CustomException("此手机号用户已存在");
+//                    }
+//                } else {
+//                    //新增
+//                    companyUser = new CompanyUser();
+//                    companyUser.setUserName(phoneNoInfo.getPhoneNumber());
+//                    companyUser.setNickName(userInfo.getNickName() == null ? "微信用户" : userInfo.getNickName());
+//                    companyUser.setPhonenumber(phoneNoInfo.getPhoneNumber());
+//                    companyUser.setSex(userInfo.getGender());
+//                    //密码初始化为123456
+//                    String pw = "123456";
+//                    companyUser.setPassword(SecurityUtils.encryptPassword(param.getPassword() == null ? pw : param.getPassword()));
+//                    companyUser.setCreateTime(new Date());
+//                    companyUser.setCompanyId(param.getCompanyId());
+//                    companyUser.setParentId(param.getParentCompanyUseId());
+//                    companyUser.setMaOpenId(session.getOpenid());
+//
+//                    //部门信息
+//                    CompanyDept dept = companyDeptService.getDefaultCompanyDeptByCompanyId(param.getCompanyId());
+//                    if (Objects.nonNull(dept)) {
+//                        companyUser.setDeptId(dept.getDeptId());
+//                    }
+//                    companyUserService.insertUser(companyUser);
+//                }
+//            } else {
+//                CompanyUser companyUserMp = new CompanyUser();
+//                companyUserMp.setPhonenumber(phoneNoInfo.getPhoneNumber());
+//                companyUserMp.setUserId(companyUser.getUserId());
+//                companyUserMp.setUpdateTime(new DateTime());
+//                companyUserMp.setLoginIp(ip);
+//                companyUserService.updateUserProfile(companyUser);
+//            }
+
+            // 添加会员表数据
+            FsUser user = userService.selectFsUserByMpOpenId(session.getOpenid());
+            if (user != null) {
+                //修改
+                FsUser userMap = new FsUser();
+                userMap.setUserId(user.getUserId());
+                userMap.setMpOpenId(session.getOpenid());
+                userMap.setUnionId(session.getUnionid());
+                userMap.setUpdateTime(new DateTime());
+                userMap.setNickName(userInfo.getNickName() != null ? userInfo.getNickName() : "微信用户");
+                userMap.setAvatar(userInfo.getAvatarUrl() != null ? userInfo.getAvatarUrl() : null);
+                userMap.setPhone(phoneNoInfo.getPhoneNumber());
+                userService.updateFsUser(userMap);
+            } else {
+                //新增
+                user = new FsUser();
+                user.setNickName(userInfo.getNickName() != null ? userInfo.getNickName() : "微信用户");
+                user.setAvatar(userInfo.getAvatarUrl() != null ? userInfo.getAvatarUrl() : null);
+                user.setStatus(1);
+                user.setMpOpenId(session.getOpenid());
+                user.setUnionId(session.getUnionid());
+                user.setCreateTime(new Date());
+                user.setPhone(phoneNoInfo.getPhoneNumber());
+                userService.insertFsUser(user);
+            }
+            log.info("保存成功的用户信息user: {}, 用户id: {}", user, user.getUserId());
+            String token = jwtUtils.generateToken(user.getUserId());
+            // 返回一个写死的数据到前端
+            return R.ok("登录成功").put("token", token).put("phoneNumber", phoneNoInfo.getPhoneNumber()).put("nickName", "微信用户").put("user", user);
+        } catch (WxErrorException e) {
+            this.logger.error(e.getMessage(), e);
+            return R.error("授权失败," + e.getMessage());
+        }
+    }
+
+    @Login(isMiniLogin = true)
+    @ApiOperation("获取销售通过小程序登录后的用户信息")
+    @GetMapping("/getMaUser")
+    public R getUserInfo() {
+        try {
+            CompanyUser companyUser = companyUserService.selectCompanyUserById(Long.parseLong(getUserId()));
+            if (companyUser == null) {
+                return R.error(401, "用户信息不存在");
+            }
+            return R.ok().put("user", companyUser);
+        } catch (Exception e) {
+            return R.error("操作异常");
+        }
+    }
+
+    /**
+     * 特殊要求:销售小程序临时登录,登录后页面中还有一个之前常用的登录,所以为了区分,token名称不能跟之前的一样
+     *
+     * @return 用户id
+     */
+    public String getUserId() {
+        String headValue = ServletUtils.getRequest().getHeader("UserToken");
+        Claims claims = jwtUtils.getClaimByToken(headValue);
+        String userId = claims.getSubject().toString();
+        return userId;
+    }
+
+
+}

+ 110 - 0
fs-company-app/src/main/java/com/fs/app/controller/WxH5MpController.java

@@ -0,0 +1,110 @@
+package com.fs.app.controller;
+
+import cn.hutool.core.date.DateTime;
+import com.fs.app.param.FsUserLoginByMpParam;
+import com.fs.app.utils.JwtUtils;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.course.mapper.FsCourseWatchLogMapper;
+import com.fs.his.domain.FsUser;
+import com.fs.his.service.IFsUserService;
+import com.fs.qw.mapper.QwExternalContactMapper;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
+import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.mp.api.WxMpService;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+@Api("会员-h5-微信相关接口")
+@RestController
+@RequestMapping("/app/wx/h5/mp")
+@Slf4j
+public class WxH5MpController {
+    Logger logger = LoggerFactory.getLogger(getClass());
+    @Autowired
+    private WxMpService wxMpService;
+
+    @Autowired
+    private IFsUserService userService;
+
+    @Autowired
+    JwtUtils jwtUtils;
+    @Autowired
+    RedisCache redisCache;
+
+    @Autowired
+    FsCourseWatchLogMapper fsCourseWatchLogMapper;
+    @Autowired
+    QwExternalContactMapper qwExternalContactMapper;
+
+
+    @ApiOperation("微信授权登录成为会员")
+    @PostMapping("/loginByMp")
+    public R loginByMp(@Valid @RequestBody FsUserLoginByMpParam param) {
+        try {
+            //获取微信用户信息
+            WxOAuth2AccessToken wxMpOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(param.getCode());
+            WxOAuth2UserInfo wxMpUser = wxMpService.getOAuth2Service().getUserInfo(wxMpOAuth2AccessToken, null);
+//            FsUser user = userService.selectFsUserByUnionid(wxMpUser.getUnionId());
+            FsUser user;
+            if(StringUtils.isNotEmpty(wxMpUser.getUnionId())) {
+                user = userService.selectFsUserByUnionId(wxMpUser.getUnionId());
+            } else {
+                user = userService.selectFsUserByMpOpenId(wxMpUser.getOpenid());
+            }
+            if (user != null) {
+                //修改
+                FsUser userMap = new FsUser();
+                userMap.setUserId(user.getUserId());
+                userMap.setMpOpenId(wxMpUser.getOpenid());
+                userMap.setUnionId(wxMpUser.getUnionId());
+                userMap.setUpdateTime(new DateTime());
+                userMap.setNickName(wxMpUser.getNickname());
+                userMap.setAvatar(wxMpUser.getHeadImgUrl());
+                userService.updateFsUser(userMap);
+            } else {
+                //新增
+                user = new FsUser();
+                user.setNickName(wxMpUser.getNickname());
+                user.setAvatar(wxMpUser.getHeadImgUrl());
+                user.setStatus(1);
+                user.setMpOpenId(wxMpUser.getOpenid());
+                user.setUnionId(wxMpUser.getUnionId());
+                user.setCreateTime(new Date());
+                userService.insertFsUser(user);
+            }
+            log.info("用户信息user: {}, 用户id: {}", user, user.getUserId());
+            String token = jwtUtils.generateToken(user.getUserId());
+            redisCache.setCacheObject("token:" + user.getUserId(), token, 604800, TimeUnit.SECONDS);
+            Map<String, Object> map = new HashMap<>();
+            map.put("token", token);
+            map.put("user", user);
+            return R.ok(map);
+        } catch (WxErrorException e) {
+            if (e.getError().getErrorCode() == 40163) {
+                return R.error(40163, e.getError().getErrorMsg());
+            } else {
+                return R.error("授权失败," + e.getMessage());
+            }
+        }
+
+    }
+
+
+}

+ 44 - 0
fs-company-app/src/main/java/com/fs/app/controller/WxMpController.java

@@ -0,0 +1,44 @@
+package com.fs.app.controller;
+
+import com.fs.common.core.domain.R;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.Synchronized;
+import me.chanjar.weixin.common.bean.WxJsapiSignature;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.mp.api.WxMpService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+
+
+@RestController
+@Api("微信配置")
+@RequestMapping("/app/wx/mp")
+public class WxMpController {
+
+    @Autowired
+    private WxMpService wxMpService;
+
+
+    @GetMapping("/getWeiXinConfig")
+    @ApiOperation("微信url验证")
+    @Synchronized
+    public R getWxConfig(@RequestParam String url) throws WxErrorException {
+        try {
+            String sLink = URLDecoder.decode(url, "UTF-8");
+            final WxJsapiSignature jsapiSignature = wxMpService.createJsapiSignature(sLink);
+            return R.ok().put("data", jsapiSignature);
+        } catch (UnsupportedEncodingException e) {
+            // URL解码异常
+            return R.error(e.getMessage());
+        }
+    }
+
+
+}

+ 26 - 0
fs-company-app/src/main/java/com/fs/app/param/ChangeUserDeptAndPostParam.java

@@ -0,0 +1,26 @@
+package com.fs.app.param;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+@Data
+public class ChangeUserDeptAndPostParam {
+    /**
+     * 销售ID
+     */
+    @NotBlank(message = "销售ID不能为空")
+    private String companyUserIds;
+    /**
+     * 部门ID
+     */
+    private Long deptId;
+    /**
+     * 岗位ID
+     */
+    private String postIds;
+    /**
+     * 角色ID
+     */
+    private String roleIds;
+}

+ 29 - 0
fs-company-app/src/main/java/com/fs/app/param/CompanyUserChangeApplyParam.java

@@ -0,0 +1,29 @@
+package com.fs.app.param;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+@Data
+public class CompanyUserChangeApplyParam {
+    /**
+     * 原归属销售
+     */
+    @NotNull(message = "原归属销售ID不能为空")
+    private Long from;
+    /**
+     * 申请归属销售
+     */
+    @NotNull(message = "申请更换归属销售ID不能为空")
+    private Long to;
+    /**
+     * 类型  0全部 1部分
+     */
+    @NotNull(message = "类型不能为空")
+    private Integer type;
+    /**
+     * 需更换归属会员id集合
+     */
+    private List<Long> ids;
+}

+ 32 - 0
fs-company-app/src/main/java/com/fs/app/param/CompanyUserParam.java

@@ -0,0 +1,32 @@
+package com.fs.app.param;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Data
+public class CompanyUserParam {
+
+    /**
+     * 公司ID
+     */
+    @NotNull(message = "公司ID不能为空")
+    private Long companyId;
+    /**
+     * 手机号码
+     */
+    @NotBlank(message = "手机号码不能为空")
+    private String phoneNumber;
+    /**
+     * 昵称
+     */
+    @NotBlank(message = "昵称不能为空")
+    private String nickName;
+    /**
+     * 密码
+     */
+    @NotBlank(message = "用户密码不能为空")
+    private String password;
+
+}

+ 27 - 0
fs-company-app/src/main/java/com/fs/app/param/CompanyUserUpdateParam.java

@@ -0,0 +1,27 @@
+package com.fs.app.param;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class CompanyUserUpdateParam {
+
+    /**
+     * 用户ID
+     */
+    @NotNull(message = "用户ID不能为空")
+    private Long userId;
+    /**
+     * 昵称
+     */
+    private String nickName;
+    /**
+     * 电话号码
+     */
+    private String phoneNumber;
+    /**
+     * 备注
+     */
+    private String remark;
+}

+ 13 - 0
fs-company-app/src/main/java/com/fs/app/param/CrmDoReadMsgParam.java

@@ -0,0 +1,13 @@
+package com.fs.app.param;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class CrmDoReadMsgParam implements Serializable {
+
+
+    private Integer msgType;
+
+}

+ 12 - 0
fs-company-app/src/main/java/com/fs/app/param/FsUserLoginByMpParam.java

@@ -0,0 +1,12 @@
+package com.fs.app.param;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+
+@Data
+public class FsUserLoginByMpParam implements Serializable {
+    @NotBlank(message = "code参数缺失")
+    private String code;
+}

+ 22 - 0
fs-company-app/src/main/java/com/fs/app/param/FsUserTagUpdateParam.java

@@ -0,0 +1,22 @@
+package com.fs.app.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import java.util.List;
+
+@Data
+public class FsUserTagUpdateParam {
+    /**
+     * 用户ID
+     */
+    @ApiModelProperty("用户ID集合")
+    @NotEmpty(message = "用户ID不能为空")
+    private List<Long> fsUserIds;
+    /**
+     * 标签ID
+     */
+    @ApiModelProperty("标签ID集合")
+    private List<Long> tagIds;
+}

+ 26 - 0
fs-company-app/src/main/java/com/fs/app/param/FsUserUpdateParam.java

@@ -0,0 +1,26 @@
+package com.fs.app.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class FsUserUpdateParam {
+    /**
+     * 用户ID
+     */
+    @ApiModelProperty("用户ID")
+    @NotNull(message = "用户ID不能为空")
+    private Long fsUserId;
+    /**
+     * 用户昵称
+     */
+    @ApiModelProperty("用户昵称")
+    private String nickName;
+    /**
+     * 用户备注
+     */
+    @ApiModelProperty("用户备注")
+    private String remark;
+}

+ 34 - 0
fs-company-app/src/main/java/com/fs/app/param/LoginMaWxParam.java

@@ -0,0 +1,34 @@
+package com.fs.app.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import java.io.Serializable;
+
+@Data
+public class LoginMaWxParam implements Serializable {
+
+    @NotBlank(message = "code参数缺失")
+    @ApiModelProperty(value = "小程序登陆code")
+    private String code;
+
+    @ApiModelProperty(value = "小程序完整用户信息的加密数据")
+    private String encryptedData;
+
+    @ApiModelProperty(value = "小程序加密算法的初始向量")
+    private String iv;
+
+//    @ApiModelProperty(value = "公司id,如果不是第一位销售,都需要传")
+//    private Long companyId;
+
+//    @ApiModelProperty(value = "电话号码")
+//    private String phoneNumber;
+
+//    @ApiModelProperty(value = "上级销售id,如果没有则不传")
+//    private Long parentCompanyUseId;
+//
+//    @ApiModelProperty(value = "用户密码")
+//    private String password;
+
+}

+ 2 - 0
fs-company-app/src/main/java/com/fs/app/param/LoginParam.java

@@ -12,4 +12,6 @@ public class LoginParam {
     private String account;
     @NotBlank(message = "请填写密码")
     private String password;
+
+    private String jpushId;
 }

+ 39 - 0
fs-company-app/src/main/java/com/fs/app/service/IAppService.java

@@ -0,0 +1,39 @@
+package com.fs.app.service;
+
+import com.fs.app.param.ChangeUserDeptAndPostParam;
+import com.fs.app.vo.CompanyRoleVO;
+import com.fs.app.vo.UserPostVO;
+import com.fs.company.domain.CompanyDeptTreeSelect;
+
+import java.util.List;
+
+
+public interface IAppService {
+
+    /**
+     * 修改用户部门和岗位
+     * @param param 参数
+     */
+    void changeUserDeptAndPost(ChangeUserDeptAndPostParam param);
+
+    /**
+     * 获取公司部门树
+     * @param companyId 公司ID
+     * @return  list
+     */
+    List<CompanyDeptTreeSelect> getDeptTreeSelect(Long companyId);
+
+    /**
+     * 获取公司岗位列表
+     * @param companyId 公司ID
+     * @return list
+     */
+    List<UserPostVO> postList(Long companyId);
+
+    /**
+     * 获取公司角色列表
+     * @param companyId 公司ID
+     * @return  list
+     */
+    List<CompanyRoleVO> roleList(Long companyId);
+}

Някои файлове не бяха показани, защото твърде много файлове са промени