Selaa lähdekoodia

迁移手动发课营期版块

吴树波 4 päivää sitten
vanhempi
commit
7e2f580255
100 muutettua tiedostoa jossa 4362 lisäystä ja 2401 poistoa
  1. 9 3
      fs-admin/src/main/java/com/fs/course/controller/FsUserCoursePeriodController.java
  2. 15 28
      fs-admin/src/main/java/com/fs/his/controller/FsInquiryOrderReportController.java
  3. 15 89
      fs-admin/src/main/java/com/fs/his/task/Task.java
  4. 5 0
      fs-common/src/main/java/com/fs/common/config/FSConfig.java
  5. 3 0
      fs-company-app/src/main/java/com/fs/app/annotation/Login.java
  6. 334 0
      fs-company-app/src/main/java/com/fs/app/controller/CrmController.java
  7. 111 0
      fs-company-app/src/main/java/com/fs/app/controller/CrmEventController.java
  8. 107 0
      fs-company-app/src/main/java/com/fs/app/controller/CrmMsgController.java
  9. 224 0
      fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  10. 65 0
      fs-company-app/src/main/java/com/fs/app/controller/IndexController.java
  11. 96 0
      fs-company-app/src/main/java/com/fs/app/controller/QwCompanyUserController.java
  12. 91 0
      fs-company-app/src/main/java/com/fs/app/controller/QwWorkTaskController.java
  13. 104 0
      fs-company-app/src/main/java/com/fs/app/controller/SmsController.java
  14. 322 0
      fs-company-app/src/main/java/com/fs/app/controller/StatisticsController.java
  15. 140 0
      fs-company-app/src/main/java/com/fs/app/controller/StorePaymentController.java
  16. 85 0
      fs-company-app/src/main/java/com/fs/app/controller/StoreProductPackageController.java
  17. 62 0
      fs-company-app/src/main/java/com/fs/app/controller/TestController.java
  18. 683 0
      fs-company-app/src/main/java/com/fs/app/controller/UserController.java
  19. 192 0
      fs-company-app/src/main/java/com/fs/app/controller/WxCompanyUserController.java
  20. 110 0
      fs-company-app/src/main/java/com/fs/app/controller/WxH5MpController.java
  21. 13 0
      fs-company-app/src/main/java/com/fs/app/param/CrmDoReadMsgParam.java
  22. 12 0
      fs-company-app/src/main/java/com/fs/app/param/FsUserLoginByMpParam.java
  23. 34 0
      fs-company-app/src/main/java/com/fs/app/param/LoginMaWxParam.java
  24. 2 0
      fs-company-app/src/main/java/com/fs/app/param/LoginParam.java
  25. 21 39
      fs-company-app/src/main/java/com/fs/app/vo/UserVO.java
  26. 0 182
      fs-company-app/src/main/java/com/fs/framework/aspectj/DataScopeAspect.java
  27. 0 73
      fs-company-app/src/main/java/com/fs/framework/aspectj/DataSourceAspect.java
  28. 0 245
      fs-company-app/src/main/java/com/fs/framework/aspectj/LogAspect.java
  29. 0 117
      fs-company-app/src/main/java/com/fs/framework/aspectj/RateLimiterAspect.java
  30. 0 31
      fs-company-app/src/main/java/com/fs/framework/config/ApplicationConfig.java
  31. 0 85
      fs-company-app/src/main/java/com/fs/framework/config/CaptchaConfig.java
  32. 0 123
      fs-company-app/src/main/java/com/fs/framework/config/DruidConfig.java
  33. 0 72
      fs-company-app/src/main/java/com/fs/framework/config/FastJson2JsonRedisSerializer.java
  34. 0 59
      fs-company-app/src/main/java/com/fs/framework/config/FilterConfig.java
  35. 0 76
      fs-company-app/src/main/java/com/fs/framework/config/KaptchaTextCreator.java
  36. 0 133
      fs-company-app/src/main/java/com/fs/framework/config/MyBatisConfig.java
  37. 0 121
      fs-company-app/src/main/java/com/fs/framework/config/RedisConfig.java
  38. 0 65
      fs-company-app/src/main/java/com/fs/framework/config/ResourcesConfig.java
  39. 0 51
      fs-company-app/src/main/java/com/fs/framework/config/SecurityConfig.java
  40. 0 33
      fs-company-app/src/main/java/com/fs/framework/config/ServerConfig.java
  41. 0 122
      fs-company-app/src/main/java/com/fs/framework/config/SwaggerConfig.java
  42. 0 63
      fs-company-app/src/main/java/com/fs/framework/config/ThreadPoolConfig.java
  43. 0 20
      fs-company-app/src/main/java/com/fs/framework/config/WebSocketConfig.java
  44. 0 77
      fs-company-app/src/main/java/com/fs/framework/config/properties/DruidProperties.java
  45. 0 27
      fs-company-app/src/main/java/com/fs/framework/datasource/DynamicDataSource.java
  46. 0 45
      fs-company-app/src/main/java/com/fs/framework/datasource/DynamicDataSourceContextHolder.java
  47. 0 56
      fs-company-app/src/main/java/com/fs/framework/interceptor/RepeatSubmitInterceptor.java
  48. 0 126
      fs-company-app/src/main/java/com/fs/framework/interceptor/impl/SameUrlDataInterceptor.java
  49. 0 56
      fs-company-app/src/main/java/com/fs/framework/manager/AsyncManager.java
  50. 0 40
      fs-company-app/src/main/java/com/fs/framework/manager/ShutdownManager.java
  51. 0 103
      fs-company-app/src/main/java/com/fs/framework/manager/factory/AsyncFactory.java
  52. 2 2
      fs-company-app/src/main/resources/application.yml
  53. 256 0
      fs-company/src/main/java/com/fs/company/controller/course/FsUserCoursePeriodController.java
  54. 0 3
      fs-qw-api-msg/src/main/java/com/fs/app/controller/QwMsgController.java
  55. 1 2
      fs-repeat-api/src/main/java/com/fs/app/controller/CommonController.java
  56. 3 7
      fs-service/src/main/java/com/fs/ad/apis/DyApiUtil.java
  57. 1 1
      fs-service/src/main/java/com/fs/ad/service/impl/AdHtmlClickLogServiceImpl.java
  58. 1 1
      fs-service/src/main/java/com/fs/baidu/api/ConvertData.java
  59. 22 0
      fs-service/src/main/java/com/fs/common/param/BaseQueryParam.java
  60. 19 0
      fs-service/src/main/java/com/fs/company/domain/CompanyUser.java
  61. 3 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyPostMapper.java
  62. 1 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyUserMapper.java
  63. 12 0
      fs-service/src/main/java/com/fs/company/param/EditPwdParam.java
  64. 24 0
      fs-service/src/main/java/com/fs/company/param/EditUserInfoParam.java
  65. 16 0
      fs-service/src/main/java/com/fs/company/param/EditUserQrCodeParam.java
  66. 2 0
      fs-service/src/main/java/com/fs/company/service/ICompanyPostService.java
  67. 1 0
      fs-service/src/main/java/com/fs/company/service/ICompanyUserService.java
  68. 7 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyPostServiceImpl.java
  69. 8 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyUserServiceImpl.java
  70. 29 0
      fs-service/src/main/java/com/fs/company/vo/CompanyUserAppVO.java
  71. 84 0
      fs-service/src/main/java/com/fs/core/config/WildcardClasspathConfigDataLoader.java
  72. 35 0
      fs-service/src/main/java/com/fs/core/config/WildcardClasspathConfigDataLocationResolver.java
  73. 55 0
      fs-service/src/main/java/com/fs/course/domain/FsUserCourseCompanyUserTime.java
  74. 6 0
      fs-service/src/main/java/com/fs/course/domain/FsUserCoursePeriodDays.java
  75. 4 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseAnswerLogsMapper.java
  76. 11 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseRedPacketLogMapper.java
  77. 4 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  78. 90 0
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseCompanyUserTimeMapper.java
  79. 4 0
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseMapper.java
  80. 10 1
      fs-service/src/main/java/com/fs/course/mapper/FsUserCoursePeriodMapper.java
  81. 2 0
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java
  82. 25 0
      fs-service/src/main/java/com/fs/course/param/CompanyUserTimeQueryParam.java
  83. 8 1
      fs-service/src/main/java/com/fs/course/param/FsCourseLinkCreateParam.java
  84. 40 0
      fs-service/src/main/java/com/fs/course/param/FsWatchCourseTimeParam.java
  85. 3 0
      fs-service/src/main/java/com/fs/course/param/newfs/UserCourseVideoPageParam.java
  86. 4 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseRedPacketLogService.java
  87. 62 0
      fs-service/src/main/java/com/fs/course/service/IFsUserCourseCompanyUserTimeService.java
  88. 11 0
      fs-service/src/main/java/com/fs/course/service/IFsUserCourseService.java
  89. 4 0
      fs-service/src/main/java/com/fs/course/service/IFsUserCourseVideoService.java
  90. 16 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseRedPacketLogServiceImpl.java
  91. 94 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseCompanyUserTimeServiceImpl.java
  92. 25 3
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodDaysServiceImpl.java
  93. 4 4
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodServiceImpl.java
  94. 311 12
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseServiceImpl.java
  95. 80 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  96. 9 3
      fs-service/src/main/java/com/fs/course/vo/UpdateCourseTimeVo.java
  97. 20 0
      fs-service/src/main/java/com/fs/his/domain/FsUser.java
  98. 12 0
      fs-service/src/main/java/com/fs/his/mapper/FsStoreOrderMapper.java
  99. 57 0
      fs-service/src/main/java/com/fs/his/mapper/FsStorePaymentMapper.java
  100. 9 1
      fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java

+ 9 - 3
fs-admin/src/main/java/com/fs/course/controller/FsUserCoursePeriodController.java

@@ -133,10 +133,16 @@ 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')")

+ 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

+ 15 - 89
fs-admin/src/main/java/com/fs/his/task/Task.java

@@ -1,130 +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.course.service.ITencentCloudCosService;
-import com.fs.crm.param.SmsSendParam;
 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 {

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

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

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

+ 683 - 0
fs-company-app/src/main/java/com/fs/app/controller/UserController.java

@@ -0,0 +1,683 @@
+package com.fs.app.controller;
+
+import cn.hutool.core.lang.Validator;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.fs.app.annotation.Login;
+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.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.StringUtils;
+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.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.Constants.PAGE_SIZE;
+
+@Slf4j
+@Api("个人中心")
+@RestController
+@RequestMapping(value = "/app/user")
+public class UserController extends AppBaseController {
+
+    @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());
+            }
+        }
+
+    }
+
+
+}

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

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

+ 21 - 39
fs-company-app/src/main/java/com/fs/app/vo/UserVO.java

@@ -1,49 +1,31 @@
 package com.fs.app.vo;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@Data
 public class UserVO {
     String nickName;
     String firstLetter;
     String deptName;
+    Long deptId;
     Long userId;
     String avatar;
 
-    public String getAvatar() {
-        return avatar;
-    }
-
-    public void setAvatar(String avatar) {
-        this.avatar = avatar;
-    }
-
-    public String getNickName() {
-        return nickName;
-    }
-
-    public void setNickName(String nickName) {
-        this.nickName = nickName;
-    }
-
-    public String getFirstLetter() {
-        return firstLetter;
-    }
-
-    public void setFirstLetter(String firstLetter) {
-        this.firstLetter = firstLetter;
-    }
-
-    public String getDeptName() {
-        return deptName;
-    }
-
-    public void setDeptName(String deptName) {
-        this.deptName = deptName;
-    }
-
-    public Long getUserId() {
-        return userId;
-    }
-
-    public void setUserId(Long userId) {
-        this.userId = userId;
-    }
+    // 注册时间
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private LocalDate registerTime;
+    // 禁用状态 0正常 1停用
+    private String status;
+    // 电话号码
+    private String phoneNumber;
+    // 审核状态 0未审核 1已审核
+    private Integer isAudit;
+    // 岗位
+    private List<UserPostVO> post;
+    // 角色
+    private List<CompanyRoleVO> roles;
 }

+ 0 - 182
fs-company-app/src/main/java/com/fs/framework/aspectj/DataScopeAspect.java

@@ -1,182 +0,0 @@
-package com.fs.framework.aspectj;
-
-import com.fs.common.annotation.DataScope;
-import com.fs.common.core.domain.BaseEntity;
-import com.fs.common.core.domain.entity.SysRole;
-import com.fs.common.core.domain.entity.SysUser;
-import com.fs.common.core.domain.model.LoginUser;
-import com.fs.common.utils.SecurityUtils;
-import com.fs.common.utils.StringUtils;
-import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.Signature;
-import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Before;
-import org.aspectj.lang.annotation.Pointcut;
-import org.aspectj.lang.reflect.MethodSignature;
-import org.springframework.stereotype.Component;
-
-import java.lang.reflect.Method;
-
-/**
- * 数据过滤处理
- *
-
- */
-@Aspect
-@Component
-public class DataScopeAspect
-{
-    /**
-     * 全部数据权限
-     */
-    public static final String DATA_SCOPE_ALL = "1";
-
-    /**
-     * 自定数据权限
-     */
-    public static final String DATA_SCOPE_CUSTOM = "2";
-
-    /**
-     * 部门数据权限
-     */
-    public static final String DATA_SCOPE_DEPT = "3";
-
-    /**
-     * 部门及以下数据权限
-     */
-    public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";
-
-    /**
-     * 仅本人数据权限
-     */
-    public static final String DATA_SCOPE_SELF = "5";
-
-    /**
-     * 数据权限过滤关键字
-     */
-    public static final String DATA_SCOPE = "dataScope";
-
-    // 配置织入点
-    @Pointcut("@annotation(com.fs.common.annotation.DataScope)")
-    public void dataScopePointCut()
-    {
-    }
-
-    @Before("dataScopePointCut()")
-    public void doBefore(JoinPoint point) throws Throwable
-    {
-        clearDataScope(point);
-        handleDataScope(point);
-    }
-
-    protected void handleDataScope(final JoinPoint joinPoint)
-    {
-        // 获得注解
-        DataScope controllerDataScope = getAnnotationLog(joinPoint);
-        if (controllerDataScope == null)
-        {
-            return;
-        }
-        // 获取当前的用户
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        if (StringUtils.isNotNull(loginUser))
-        {
-            SysUser currentUser = loginUser.getUser();
-            // 如果是超级管理员,则不过滤数据
-            if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin())
-            {
-                dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),
-                        controllerDataScope.userAlias());
-            }
-        }
-    }
-
-    /**
-     * 数据范围过滤
-     *
-     * @param joinPoint 切点
-     * @param user 用户
-     * @param userAlias 别名
-     */
-    public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias)
-    {
-        StringBuilder sqlString = new StringBuilder();
-
-        for (SysRole role : user.getRoles())
-        {
-            String dataScope = role.getDataScope();
-            if (DATA_SCOPE_ALL.equals(dataScope))
-            {
-                sqlString = new StringBuilder();
-                break;
-            }
-            else if (DATA_SCOPE_CUSTOM.equals(dataScope))
-            {
-                sqlString.append(StringUtils.format(
-                        " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias,
-                        role.getRoleId()));
-            }
-            else if (DATA_SCOPE_DEPT.equals(dataScope))
-            {
-                sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
-            }
-            else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
-            {
-                sqlString.append(StringUtils.format(
-                        " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
-                        deptAlias, user.getDeptId(), user.getDeptId()));
-            }
-            else if (DATA_SCOPE_SELF.equals(dataScope))
-            {
-                if (StringUtils.isNotBlank(userAlias))
-                {
-                    sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));
-                }
-                else
-                {
-                    // 数据权限为仅本人且没有userAlias别名不查询任何数据
-                    sqlString.append(" OR 1=0 ");
-                }
-            }
-        }
-
-        if (StringUtils.isNotBlank(sqlString.toString()))
-        {
-            Object params = joinPoint.getArgs()[0];
-            if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
-            {
-                BaseEntity baseEntity = (BaseEntity) params;
-                baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
-            }
-        }
-    }
-
-    /**
-     * 是否存在注解,如果存在就获取
-     */
-    private DataScope getAnnotationLog(JoinPoint joinPoint)
-    {
-        Signature signature = joinPoint.getSignature();
-        MethodSignature methodSignature = (MethodSignature) signature;
-        Method method = methodSignature.getMethod();
-
-        if (method != null)
-        {
-            return method.getAnnotation(DataScope.class);
-        }
-        return null;
-    }
-
-    /**
-     * 拼接权限sql前先清空params.dataScope参数防止注入
-     */
-    private void clearDataScope(final JoinPoint joinPoint)
-    {
-        Object params = joinPoint.getArgs()[0];
-        if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
-        {
-            BaseEntity baseEntity = (BaseEntity) params;
-            baseEntity.getParams().put(DATA_SCOPE, "");
-        }
-    }
-}

+ 0 - 73
fs-company-app/src/main/java/com/fs/framework/aspectj/DataSourceAspect.java

@@ -1,73 +0,0 @@
-package com.fs.framework.aspectj;
-
-import com.fs.common.annotation.DataSource;
-import com.fs.common.utils.StringUtils;
-import com.fs.framework.datasource.DynamicDataSourceContextHolder;
-import org.aspectj.lang.ProceedingJoinPoint;
-import org.aspectj.lang.annotation.Around;
-import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Pointcut;
-import org.aspectj.lang.reflect.MethodSignature;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.core.annotation.AnnotationUtils;
-import org.springframework.core.annotation.Order;
-import org.springframework.stereotype.Component;
-
-import java.util.Objects;
-
-/**
- * 多数据源处理
- * 
-
- */
-@Aspect
-@Order(1)
-@Component
-public class DataSourceAspect
-{
-    protected Logger logger = LoggerFactory.getLogger(getClass());
-
-    @Pointcut("@annotation(com.fs.common.annotation.DataSource)"
-            + "|| @within(com.fs.common.annotation.DataSource)")
-    public void dsPointCut()
-    {
-
-    }
-
-    @Around("dsPointCut()")
-    public Object around(ProceedingJoinPoint point) throws Throwable
-    {
-        DataSource dataSource = getDataSource(point);
-
-        if (StringUtils.isNotNull(dataSource))
-        {
-            DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
-        }
-
-        try
-        {
-            return point.proceed();
-        }
-        finally
-        {
-            // 销毁数据源 在执行方法之后
-            DynamicDataSourceContextHolder.clearDataSourceType();
-        }
-    }
-
-    /**
-     * 获取需要切换的数据源
-     */
-    public DataSource getDataSource(ProceedingJoinPoint point)
-    {
-        MethodSignature signature = (MethodSignature) point.getSignature();
-        DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
-        if (Objects.nonNull(dataSource))
-        {
-            return dataSource;
-        }
-
-        return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);
-    }
-}

+ 0 - 245
fs-company-app/src/main/java/com/fs/framework/aspectj/LogAspect.java

@@ -1,245 +0,0 @@
-package com.fs.framework.aspectj;
-
-import com.alibaba.fastjson.JSON;
-import com.fs.common.annotation.Log;
-import com.fs.common.core.domain.model.LoginUser;
-import com.fs.common.enums.BusinessStatus;
-import com.fs.common.enums.HttpMethod;
-import com.fs.common.utils.SecurityUtils;
-import com.fs.common.utils.ServletUtils;
-import com.fs.common.utils.StringUtils;
-import com.fs.common.utils.ip.IpUtils;
-
-import com.fs.framework.manager.AsyncManager;
-import com.fs.framework.manager.factory.AsyncFactory;
-import com.fs.system.domain.SysOperLog;
-import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.Signature;
-import org.aspectj.lang.annotation.AfterReturning;
-import org.aspectj.lang.annotation.AfterThrowing;
-import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Pointcut;
-import org.aspectj.lang.reflect.MethodSignature;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Component;
-import org.springframework.validation.BindingResult;
-import org.springframework.web.multipart.MultipartFile;
-import org.springframework.web.servlet.HandlerMapping;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.lang.reflect.Method;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Map;
-
-/**
- * 操作日志记录处理
- * 
-
- */
-@Aspect
-@Component
-public class LogAspect
-{
-    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
-
-    // 配置织入点
-    @Pointcut("@annotation(com.fs.common.annotation.Log)")
-    public void logPointCut()
-    {
-    }
-
-    /**
-     * 处理完请求后执行
-     *
-     * @param joinPoint 切点
-     */
-    @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
-    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult)
-    {
-        handleLog(joinPoint, null, jsonResult);
-    }
-
-    /**
-     * 拦截异常操作
-     * 
-     * @param joinPoint 切点
-     * @param e 异常
-     */
-    @AfterThrowing(value = "logPointCut()", throwing = "e")
-    public void doAfterThrowing(JoinPoint joinPoint, Exception e)
-    {
-        handleLog(joinPoint, e, null);
-    }
-
-    protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult)
-    {
-        try
-        {
-            // 获得注解
-            Log controllerLog = getAnnotationLog(joinPoint);
-            if (controllerLog == null)
-            {
-                return;
-            }
-
-            // 获取当前的用户
-            LoginUser loginUser = SecurityUtils.getLoginUser();
-
-            // *========数据库日志=========*//
-            SysOperLog operLog = new SysOperLog();
-            operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
-            // 请求的地址
-            String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
-            operLog.setOperIp(ip);
-            // 返回参数
-            operLog.setJsonResult(JSON.toJSONString(jsonResult));
-
-            operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
-            if (loginUser != null)
-            {
-                operLog.setOperName(loginUser.getUsername());
-            }
-
-            if (e != null)
-            {
-                operLog.setStatus(BusinessStatus.FAIL.ordinal());
-                operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
-            }
-            // 设置方法名称
-            String className = joinPoint.getTarget().getClass().getName();
-            String methodName = joinPoint.getSignature().getName();
-            operLog.setMethod(className + "." + methodName + "()");
-            // 设置请求方式
-            operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
-            // 处理设置注解上的参数
-            getControllerMethodDescription(joinPoint, controllerLog, operLog);
-            // 保存数据库
-            AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
-        }
-        catch (Exception exp)
-        {
-            // 记录本地异常日志
-            log.error("==前置通知异常==");
-            log.error("异常信息:{}", exp.getMessage());
-            exp.printStackTrace();
-        }
-    }
-
-    /**
-     * 获取注解中对方法的描述信息 用于Controller层注解
-     * 
-     * @param log 日志
-     * @param operLog 操作日志
-     * @throws Exception
-     */
-    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog) throws Exception
-    {
-        // 设置action动作
-        operLog.setBusinessType(log.businessType().ordinal());
-        // 设置标题
-        operLog.setTitle(log.title());
-        // 设置操作人类别
-        operLog.setOperatorType(log.operatorType().ordinal());
-        // 是否需要保存request,参数和值
-        if (log.isSaveRequestData())
-        {
-            // 获取参数的信息,传入到数据库中。
-            setRequestValue(joinPoint, operLog);
-        }
-    }
-
-    /**
-     * 获取请求的参数,放到log中
-     * 
-     * @param operLog 操作日志
-     * @throws Exception 异常
-     */
-    private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog) throws Exception
-    {
-        String requestMethod = operLog.getRequestMethod();
-        if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod))
-        {
-            String params = argsArrayToString(joinPoint.getArgs());
-            operLog.setOperParam(StringUtils.substring(params, 0, 2000));
-        }
-        else
-        {
-            Map<?, ?> paramsMap = (Map<?, ?>) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
-            operLog.setOperParam(StringUtils.substring(paramsMap.toString(), 0, 2000));
-        }
-    }
-
-    /**
-     * 是否存在注解,如果存在就获取
-     */
-    private Log getAnnotationLog(JoinPoint joinPoint) throws Exception
-    {
-        Signature signature = joinPoint.getSignature();
-        MethodSignature methodSignature = (MethodSignature) signature;
-        Method method = methodSignature.getMethod();
-
-        if (method != null)
-        {
-            return method.getAnnotation(Log.class);
-        }
-        return null;
-    }
-
-    /**
-     * 参数拼装
-     */
-    private String argsArrayToString(Object[] paramsArray)
-    {
-        String params = "";
-        if (paramsArray != null && paramsArray.length > 0)
-        {
-            for (int i = 0; i < paramsArray.length; i++)
-            {
-                if (StringUtils.isNotNull(paramsArray[i]) && !isFilterObject(paramsArray[i]))
-                {
-                    Object jsonObj = JSON.toJSON(paramsArray[i]);
-                    params += jsonObj.toString() + " ";
-                }
-            }
-        }
-        return params.trim();
-    }
-
-    /**
-     * 判断是否需要过滤的对象。
-     * 
-     * @param o 对象信息。
-     * @return 如果是需要过滤的对象,则返回true;否则返回false。
-     */
-    @SuppressWarnings("rawtypes")
-    public boolean isFilterObject(final Object o)
-    {
-        Class<?> clazz = o.getClass();
-        if (clazz.isArray())
-        {
-            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
-        }
-        else if (Collection.class.isAssignableFrom(clazz))
-        {
-            Collection collection = (Collection) o;
-            for (Iterator iter = collection.iterator(); iter.hasNext();)
-            {
-                return iter.next() instanceof MultipartFile;
-            }
-        }
-        else if (Map.class.isAssignableFrom(clazz))
-        {
-            Map map = (Map) o;
-            for (Iterator iter = map.entrySet().iterator(); iter.hasNext();)
-            {
-                Map.Entry entry = (Map.Entry) iter.next();
-                return entry.getValue() instanceof MultipartFile;
-            }
-        }
-        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
-                || o instanceof BindingResult;
-    }
-}

+ 0 - 117
fs-company-app/src/main/java/com/fs/framework/aspectj/RateLimiterAspect.java

@@ -1,117 +0,0 @@
-package com.fs.framework.aspectj;
-
-import com.fs.common.annotation.RateLimiter;
-import com.fs.common.enums.LimitType;
-import com.fs.common.exception.ServiceException;
-import com.fs.common.utils.ServletUtils;
-import com.fs.common.utils.StringUtils;
-import com.fs.common.utils.ip.IpUtils;
-import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.Signature;
-import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Before;
-import org.aspectj.lang.annotation.Pointcut;
-import org.aspectj.lang.reflect.MethodSignature;
-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.data.redis.core.script.RedisScript;
-import org.springframework.stereotype.Component;
-
-import java.lang.reflect.Method;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * 限流处理
- *
-
- */
-@Aspect
-@Component
-public class RateLimiterAspect
-{
-    private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);
-
-    private RedisTemplate<Object, Object> redisTemplate;
-
-    private RedisScript<Long> limitScript;
-
-    @Autowired
-    public void setRedisTemplate1(RedisTemplate<Object, Object> redisTemplate)
-    {
-        this.redisTemplate = redisTemplate;
-    }
-
-    @Autowired
-    public void setLimitScript(RedisScript<Long> limitScript)
-    {
-        this.limitScript = limitScript;
-    }
-
-    // 配置织入点
-    @Pointcut("@annotation(com.fs.common.annotation.RateLimiter)")
-    public void rateLimiterPointCut()
-    {
-    }
-
-    @Before("rateLimiterPointCut()")
-    public void doBefore(JoinPoint point) throws Throwable
-    {
-        RateLimiter rateLimiter = getAnnotationRateLimiter(point);
-        String key = rateLimiter.key();
-        int time = rateLimiter.time();
-        int count = rateLimiter.count();
-
-        String combineKey = getCombineKey(rateLimiter, point);
-        List<Object> keys = Collections.singletonList(combineKey);
-        try
-        {
-            Long number = redisTemplate.execute(limitScript, keys, count, time);
-            if (StringUtils.isNull(number) || number.intValue() > count)
-            {
-                throw new ServiceException("访问过于频繁,请稍后再试");
-            }
-            log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), key);
-        }
-        catch (ServiceException e)
-        {
-            throw e;
-        }
-        catch (Exception e)
-        {
-            throw new RuntimeException("服务器限流异常,请稍后再试");
-        }
-    }
-
-    /**
-     * 是否存在注解,如果存在就获取
-     */
-    private RateLimiter getAnnotationRateLimiter(JoinPoint joinPoint)
-    {
-        Signature signature = joinPoint.getSignature();
-        MethodSignature methodSignature = (MethodSignature) signature;
-        Method method = methodSignature.getMethod();
-
-        if (method != null)
-        {
-            return method.getAnnotation(RateLimiter.class);
-        }
-        return null;
-    }
-
-    public String getCombineKey(RateLimiter rateLimiter, JoinPoint point)
-    {
-        StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());
-        if (rateLimiter.limitType() == LimitType.IP)
-        {
-            stringBuffer.append(IpUtils.getIpAddr(ServletUtils.getRequest()));
-        }
-        MethodSignature signature = (MethodSignature) point.getSignature();
-        Method method = signature.getMethod();
-        Class<?> targetClass = method.getDeclaringClass();
-        stringBuffer.append("-").append(targetClass.getName()).append("- ").append(method.getName());
-        return stringBuffer.toString();
-    }
-}

+ 0 - 31
fs-company-app/src/main/java/com/fs/framework/config/ApplicationConfig.java

@@ -1,31 +0,0 @@
-package com.fs.framework.config;
-
-import org.mybatis.spring.annotation.MapperScan;
-import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.EnableAspectJAutoProxy;
-
-import java.util.TimeZone;
-
-/**
- * 程序注解配置
- *
-
- */
-@Configuration
-// 表示通过aop框架暴露该代理对象,AopContext能够访问
-@EnableAspectJAutoProxy(exposeProxy = true)
-// 指定要扫描的Mapper类的包的路径
-@MapperScan("com.fs.**.mapper")
-public class ApplicationConfig
-{
-    /**
-     * 时区配置
-     */
-    @Bean
-    public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization()
-    {
-        return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
-    }
-}

+ 0 - 85
fs-company-app/src/main/java/com/fs/framework/config/CaptchaConfig.java

@@ -1,85 +0,0 @@
-package com.fs.framework.config;
-
-import com.google.code.kaptcha.impl.DefaultKaptcha;
-import com.google.code.kaptcha.util.Config;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-import java.util.Properties;
-
-import static com.google.code.kaptcha.Constants.*;
-
-/**
- * 验证码配置
- * 
-
- */
-@Configuration
-public class CaptchaConfig
-{
-    @Bean(name = "captchaProducer")
-    public DefaultKaptcha getKaptchaBean()
-    {
-        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
-        Properties properties = new Properties();
-        // 是否有边框 默认为true 我们可以自己设置yes,no
-        properties.setProperty(KAPTCHA_BORDER, "yes");
-        // 验证码文本字符颜色 默认为Color.BLACK
-        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
-        // 验证码图片宽度 默认为200
-        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
-        // 验证码图片高度 默认为50
-        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
-        // 验证码文本字符大小 默认为40
-        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
-        // KAPTCHA_SESSION_KEY
-        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
-        // 验证码文本字符长度 默认为5
-        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
-        // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
-        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
-        // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
-        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
-        Config config = new Config(properties);
-        defaultKaptcha.setConfig(config);
-        return defaultKaptcha;
-    }
-
-    @Bean(name = "captchaProducerMath")
-    public DefaultKaptcha getKaptchaBeanMath()
-    {
-        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
-        Properties properties = new Properties();
-        // 是否有边框 默认为true 我们可以自己设置yes,no
-        properties.setProperty(KAPTCHA_BORDER, "yes");
-        // 边框颜色 默认为Color.BLACK
-        properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
-        // 验证码文本字符颜色 默认为Color.BLACK
-        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
-        // 验证码图片宽度 默认为200
-        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
-        // 验证码图片高度 默认为50
-        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
-        // 验证码文本字符大小 默认为40
-        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
-        // KAPTCHA_SESSION_KEY
-        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
-        // 验证码文本生成器
-        properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.fs.framework.config.KaptchaTextCreator");
-        // 验证码文本字符间距 默认为2
-        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
-        // 验证码文本字符长度 默认为5
-        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
-        // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
-        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
-        // 验证码噪点颜色 默认为Color.BLACK
-        properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
-        // 干扰实现类
-        properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
-        // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
-        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
-        Config config = new Config(properties);
-        defaultKaptcha.setConfig(config);
-        return defaultKaptcha;
-    }
-}

+ 0 - 123
fs-company-app/src/main/java/com/fs/framework/config/DruidConfig.java

@@ -1,123 +0,0 @@
-package com.fs.framework.config;
-
-import com.alibaba.druid.pool.DruidDataSource;
-import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
-import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
-import com.alibaba.druid.util.Utils;
-import com.fs.common.enums.DataSourceType;
-import com.fs.common.utils.spring.SpringUtils;
-import com.fs.framework.config.properties.DruidProperties;
-import com.fs.framework.datasource.DynamicDataSource;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Primary;
-
-import javax.servlet.*;
-import javax.sql.DataSource;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * druid 配置多数据源
- * 
-
- */
-@Configuration
-public class DruidConfig
-{
-    @Bean
-    @ConfigurationProperties("spring.datasource.mysql.druid.master")
-    public DataSource masterDataSource(DruidProperties druidProperties)
-    {
-        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
-        return druidProperties.dataSource(dataSource);
-    }
-
-    @Bean
-    @ConfigurationProperties("spring.datasource.mysql.druid.slave")
-    @ConditionalOnProperty(prefix = "spring.datasource.mysql.druid.slave", name = "enabled", havingValue = "true")
-    public DataSource slaveDataSource(DruidProperties druidProperties)
-    {
-        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
-        return druidProperties.dataSource(dataSource);
-    }
-
-    @Bean(name = "dynamicDataSource")
-    @Primary
-    public DynamicDataSource dataSource(DataSource masterDataSource)
-    {
-        Map<Object, Object> targetDataSources = new HashMap<>();
-        targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
-        setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");
-        return new DynamicDataSource(masterDataSource, targetDataSources);
-    }
-    
-    /**
-     * 设置数据源
-     * 
-     * @param targetDataSources 备选数据源集合
-     * @param sourceName 数据源名称
-     * @param beanName bean名称
-     */
-    public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName)
-    {
-        try
-        {
-            DataSource dataSource = SpringUtils.getBean(beanName);
-            targetDataSources.put(sourceName, dataSource);
-        }
-        catch (Exception e)
-        {
-        }
-    }
-
-    /**
-     * 去除监控页面底部的广告
-     */
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Bean
-    @ConditionalOnProperty(name = "spring.datasource.mysql.druid.statViewServlet.enabled", havingValue = "true")
-    public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties)
-    {
-        // 获取web监控页面的参数
-        DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
-        // 提取common.js的配置路径
-        String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
-        String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
-        final String filePath = "support/http/resources/js/common.js";
-        // 创建filter进行过滤
-        Filter filter = new Filter()
-        {
-            @Override
-            public void init(javax.servlet.FilterConfig filterConfig) throws ServletException
-            {
-            }
-            @Override
-            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
-                    throws IOException, ServletException
-            {
-                chain.doFilter(request, response);
-                // 重置缓冲区,响应头不会被重置
-                response.resetBuffer();
-                // 获取common.js
-                String text = Utils.readFromResource(filePath);
-                // 正则替换banner, 除去底部的广告信息
-                text = text.replaceAll("<a.*?banner\"></a><br/>", "");
-                text = text.replaceAll("powered.*?shrek.wang</a>", "");
-                response.getWriter().write(text);
-            }
-            @Override
-            public void destroy()
-            {
-            }
-        };
-        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
-        registrationBean.setFilter(filter);
-        registrationBean.addUrlPatterns(commonJsPattern);
-        return registrationBean;
-    }
-}

+ 0 - 72
fs-company-app/src/main/java/com/fs/framework/config/FastJson2JsonRedisSerializer.java

@@ -1,72 +0,0 @@
-package com.fs.framework.config;
-
-import com.alibaba.fastjson.JSON;
-import com.alibaba.fastjson.parser.ParserConfig;
-import com.alibaba.fastjson.serializer.SerializerFeature;
-import com.fasterxml.jackson.databind.JavaType;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.type.TypeFactory;
-import org.springframework.data.redis.serializer.RedisSerializer;
-import org.springframework.data.redis.serializer.SerializationException;
-import org.springframework.util.Assert;
-
-import java.nio.charset.Charset;
-
-/**
- * Redis使用FastJson序列化
- * 
-
- */
-public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
-{
-    @SuppressWarnings("unused")
-    private ObjectMapper objectMapper = new ObjectMapper();
-
-    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
-
-    private Class<T> clazz;
-
-    static
-    {
-        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
-    }
-
-    public FastJson2JsonRedisSerializer(Class<T> clazz)
-    {
-        super();
-        this.clazz = clazz;
-    }
-
-    @Override
-    public byte[] serialize(T t) throws SerializationException
-    {
-        if (t == null)
-        {
-            return new byte[0];
-        }
-        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
-    }
-
-    @Override
-    public T deserialize(byte[] bytes) throws SerializationException
-    {
-        if (bytes == null || bytes.length <= 0)
-        {
-            return null;
-        }
-        String str = new String(bytes, DEFAULT_CHARSET);
-
-        return JSON.parseObject(str, clazz);
-    }
-
-    public void setObjectMapper(ObjectMapper objectMapper)
-    {
-        Assert.notNull(objectMapper, "'objectMapper' must not be null");
-        this.objectMapper = objectMapper;
-    }
-
-    protected JavaType getJavaType(Class<?> clazz)
-    {
-        return TypeFactory.defaultInstance().constructType(clazz);
-    }
-}

+ 0 - 59
fs-company-app/src/main/java/com/fs/framework/config/FilterConfig.java

@@ -1,59 +0,0 @@
-package com.fs.framework.config;
-
-import com.fs.common.filter.RepeatableFilter;
-import com.fs.common.filter.XssFilter;
-import com.fs.common.utils.StringUtils;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-import javax.servlet.DispatcherType;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Filter配置
- *
-
- */
-@Configuration
-@ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
-public class FilterConfig
-{
-    @Value("${xss.excludes}")
-    private String excludes;
-
-    @Value("${xss.urlPatterns}")
-    private String urlPatterns;
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Bean
-    public FilterRegistrationBean xssFilterRegistration()
-    {
-        FilterRegistrationBean registration = new FilterRegistrationBean();
-        registration.setDispatcherTypes(DispatcherType.REQUEST);
-        registration.setFilter(new XssFilter());
-        registration.addUrlPatterns(StringUtils.split(urlPatterns, ","));
-        registration.setName("xssFilter");
-        registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
-        Map<String, String> initParameters = new HashMap<String, String>();
-        initParameters.put("excludes", excludes);
-        registration.setInitParameters(initParameters);
-        return registration;
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Bean
-    public FilterRegistrationBean someFilterRegistration()
-    {
-        FilterRegistrationBean registration = new FilterRegistrationBean();
-        registration.setFilter(new RepeatableFilter());
-        registration.addUrlPatterns("/*");
-        registration.setName("repeatableFilter");
-        registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
-        return registration;
-    }
-
-}

+ 0 - 76
fs-company-app/src/main/java/com/fs/framework/config/KaptchaTextCreator.java

@@ -1,76 +0,0 @@
-package com.fs.framework.config;
-
-import com.google.code.kaptcha.text.impl.DefaultTextCreator;
-
-import java.util.Random;
-
-/**
- * 验证码文本生成器
- * 
-
- */
-public class KaptchaTextCreator extends DefaultTextCreator
-{
-    private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");
-
-    @Override
-    public String getText()
-    {
-        Integer result = 0;
-        Random random = new Random();
-        int x = random.nextInt(10);
-        int y = random.nextInt(10);
-        StringBuilder suChinese = new StringBuilder();
-        int randomoperands = (int) Math.round(Math.random() * 2);
-        if (randomoperands == 0)
-        {
-            result = x * y;
-            suChinese.append(CNUMBERS[x]);
-            suChinese.append("*");
-            suChinese.append(CNUMBERS[y]);
-        }
-        else if (randomoperands == 1)
-        {
-            if (!(x == 0) && y % x == 0)
-            {
-                result = y / x;
-                suChinese.append(CNUMBERS[y]);
-                suChinese.append("/");
-                suChinese.append(CNUMBERS[x]);
-            }
-            else
-            {
-                result = x + y;
-                suChinese.append(CNUMBERS[x]);
-                suChinese.append("+");
-                suChinese.append(CNUMBERS[y]);
-            }
-        }
-        else if (randomoperands == 2)
-        {
-            if (x >= y)
-            {
-                result = x - y;
-                suChinese.append(CNUMBERS[x]);
-                suChinese.append("-");
-                suChinese.append(CNUMBERS[y]);
-            }
-            else
-            {
-                result = y - x;
-                suChinese.append(CNUMBERS[y]);
-                suChinese.append("-");
-                suChinese.append(CNUMBERS[x]);
-            }
-        }
-        else
-        {
-            result = x + y;
-            suChinese.append(CNUMBERS[x]);
-            suChinese.append("+");
-            suChinese.append(CNUMBERS[y]);
-        }
-        suChinese.append("=?@" + result);
-        return suChinese.toString();
-    }
-}

+ 0 - 133
fs-company-app/src/main/java/com/fs/framework/config/MyBatisConfig.java

@@ -1,133 +0,0 @@
-package com.fs.framework.config;
-
-import com.fs.common.utils.StringUtils;
-import org.apache.ibatis.io.VFS;
-import org.apache.ibatis.session.SqlSessionFactory;
-import org.mybatis.spring.SqlSessionFactoryBean;
-import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.env.Environment;
-import org.springframework.core.io.DefaultResourceLoader;
-import org.springframework.core.io.Resource;
-import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
-import org.springframework.core.io.support.ResourcePatternResolver;
-import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
-import org.springframework.core.type.classreading.MetadataReader;
-import org.springframework.core.type.classreading.MetadataReaderFactory;
-import org.springframework.util.ClassUtils;
-
-import javax.sql.DataSource;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-
-/**
- * Mybatis支持*匹配扫描包
- * 
-
- */
-@Configuration
-public class MyBatisConfig
-{
-    @Autowired
-    private Environment env;
-
-    static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
-
-    public static String setTypeAliasesPackage(String typeAliasesPackage)
-    {
-        ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver();
-        MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);
-        List<String> allResult = new ArrayList<String>();
-        try
-        {
-            for (String aliasesPackage : typeAliasesPackage.split(","))
-            {
-                List<String> result = new ArrayList<String>();
-                aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
-                        + ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN;
-                Resource[] resources = resolver.getResources(aliasesPackage);
-                if (resources != null && resources.length > 0)
-                {
-                    MetadataReader metadataReader = null;
-                    for (Resource resource : resources)
-                    {
-                        if (resource.isReadable())
-                        {
-                            metadataReader = metadataReaderFactory.getMetadataReader(resource);
-                            try
-                            {
-                                result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName());
-                            }
-                            catch (ClassNotFoundException e)
-                            {
-                                e.printStackTrace();
-                            }
-                        }
-                    }
-                }
-                if (result.size() > 0)
-                {
-                    HashSet<String> hashResult = new HashSet<String>(result);
-                    allResult.addAll(hashResult);
-                }
-            }
-            if (allResult.size() > 0)
-            {
-                typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0]));
-            }
-            else
-            {
-                throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包");
-            }
-        }
-        catch (IOException e)
-        {
-            e.printStackTrace();
-        }
-        return typeAliasesPackage;
-    }
-
-    public Resource[] resolveMapperLocations(String[] mapperLocations)
-    {
-        ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
-        List<Resource> resources = new ArrayList<Resource>();
-        if (mapperLocations != null)
-        {
-            for (String mapperLocation : mapperLocations)
-            {
-                try
-                {
-                    Resource[] mappers = resourceResolver.getResources(mapperLocation);
-                    resources.addAll(Arrays.asList(mappers));
-                }
-                catch (IOException e)
-                {
-                    // ignore
-                }
-            }
-        }
-        return resources.toArray(new Resource[resources.size()]);
-    }
-
-    @Bean
-    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
-    {
-        String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");
-        String mapperLocations = env.getProperty("mybatis.mapperLocations");
-        String configLocation = env.getProperty("mybatis.configLocation");
-        typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
-        VFS.addImplClass(SpringBootVFS.class);
-
-        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
-        sessionFactory.setDataSource(dataSource);
-        sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
-        sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
-        sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
-        return sessionFactory.getObject();
-    }
-}

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

@@ -1,121 +0,0 @@
-package com.fs.framework.config;
-
-import com.fasterxml.jackson.annotation.JsonAutoDetect;
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
-import com.fasterxml.jackson.annotation.PropertyAccessor;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
-import org.springframework.cache.annotation.CachingConfigurerSupport;
-import org.springframework.cache.annotation.EnableCaching;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.data.redis.connection.RedisConnectionFactory;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.data.redis.core.script.DefaultRedisScript;
-import org.springframework.data.redis.serializer.GenericToStringSerializer;
-import org.springframework.data.redis.serializer.StringRedisSerializer;
-
-/**
- * redis配置
- *
-
- */
-@Configuration
-@EnableCaching
-public class RedisConfig extends CachingConfigurerSupport
-{
-    @Bean
-    @SuppressWarnings(value = { "unchecked", "rawtypes" })
-    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
-    {
-        RedisTemplate<Object, Object> template = new RedisTemplate<>();
-        template.setConnectionFactory(connectionFactory);
-
-        FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
-
-        ObjectMapper mapper = new ObjectMapper();
-        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
-        mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
-        serializer.setObjectMapper(mapper);
-
-        // 使用StringRedisSerializer来序列化和反序列化redis的key值
-        template.setKeySerializer(new StringRedisSerializer());
-        template.setValueSerializer(serializer);
-
-        // Hash的key也采用StringRedisSerializer的序列化方式
-        template.setHashKeySerializer(new StringRedisSerializer());
-        template.setHashValueSerializer(serializer);
-
-        template.afterPropertiesSet();
-        return template;
-    }
-    @Bean
-    public RedisTemplate<String, Boolean> redisTemplateForBoolean(RedisConnectionFactory connectionFactory) {
-        RedisTemplate<String, Boolean> template = new RedisTemplate<>();
-        template.setConnectionFactory(connectionFactory);
-
-        // 使用StringRedisSerializer来序列化和反序列化redis的key值
-        template.setKeySerializer(new StringRedisSerializer());
-        template.setValueSerializer(new GenericToStringSerializer<>(Boolean.class));
-
-        // Hash的key也采用StringRedisSerializer的序列化方式
-        template.setHashKeySerializer(new StringRedisSerializer());
-        template.setHashValueSerializer(new GenericToStringSerializer<>(Boolean.class));
-
-        template.afterPropertiesSet();
-        return template;
-    }
-
-    @Bean
-    @SuppressWarnings(value = { "unchecked", "rawtypes" })
-    public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {
-        RedisTemplate<String, Object> template = new RedisTemplate<>();
-        template.setConnectionFactory(connectionFactory);
-
-        FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
-
-        ObjectMapper mapper = new ObjectMapper();
-        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
-        mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
-        serializer.setObjectMapper(mapper);
-
-        // 使用StringRedisSerializer来序列化和反序列化redis的key值
-        template.setKeySerializer(new StringRedisSerializer());
-        template.setValueSerializer(serializer);
-
-        // Hash的key也采用StringRedisSerializer的序列化方式
-        template.setHashKeySerializer(new StringRedisSerializer());
-        template.setHashValueSerializer(serializer);
-
-        template.afterPropertiesSet();
-        return template;
-    }
-
-    @Bean
-    public DefaultRedisScript<Long> limitScript()
-    {
-        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
-        redisScript.setScriptText(limitScriptText());
-        redisScript.setResultType(Long.class);
-        return redisScript;
-    }
-
-    /**
-     * 限流脚本
-     */
-    private String limitScriptText()
-    {
-        return "local key = KEYS[1]\n" +
-                "local count = tonumber(ARGV[1])\n" +
-                "local time = tonumber(ARGV[2])\n" +
-                "local current = redis.call('get', key);\n" +
-                "if current and tonumber(current) > count then\n" +
-                "    return current;\n" +
-                "end\n" +
-                "current = redis.call('incr', key)\n" +
-                "if tonumber(current) == 1 then\n" +
-                "    redis.call('expire', key, time)\n" +
-                "end\n" +
-                "return current;";
-    }
-}

+ 0 - 65
fs-company-app/src/main/java/com/fs/framework/config/ResourcesConfig.java

@@ -1,65 +0,0 @@
-package com.fs.framework.config;
-
-import com.fs.common.config.FSConfig;
-import com.fs.common.constant.Constants;
-import com.fs.framework.interceptor.RepeatSubmitInterceptor;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.cors.CorsConfiguration;
-import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
-import org.springframework.web.filter.CorsFilter;
-import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
-import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
-/**
- * 通用配置
- * 
-
- */
-@Configuration
-public class ResourcesConfig implements WebMvcConfigurer
-{
-    @Autowired
-    private RepeatSubmitInterceptor repeatSubmitInterceptor;
-
-    @Override
-    public void addResourceHandlers(ResourceHandlerRegistry registry)
-    {
-        /** 本地文件上传路径 */
-        registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + FSConfig.getProfile() + "/");
-
-        /** swagger配置 */
-        registry.addResourceHandler("/swagger-ui/**").addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
-    }
-
-    /**
-     * 自定义拦截规则
-     */
-    @Override
-    public void addInterceptors(InterceptorRegistry registry)
-    {
-        registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
-    }
-
-    /**
-     * 跨域配置
-     */
-    @Bean
-    public CorsFilter corsFilter()
-    {
-        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
-        CorsConfiguration config = new CorsConfiguration();
-        config.setAllowCredentials(true);
-        // 设置访问源地址
-        config.addAllowedOrigin("*");
-        // 设置访问源请求头
-        config.addAllowedHeader("*");
-        // 设置访问源请求方法
-        config.addAllowedMethod("*");
-        // 对接口配置跨域设置
-        source.registerCorsConfiguration("/**", config);
-        return new CorsFilter(source);
-    }
-}

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

@@ -1,51 +0,0 @@
-package com.fs.framework.config;
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.config.BeanIds;
-import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
-
-/**
- * spring security配置
- * 
-
- */
-@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
-public class SecurityConfig extends WebSecurityConfigurerAdapter
-{
-
-    /**
-     * anyRequest          |   匹配所有请求路径
-     * access              |   SpringEl表达式结果为true时可以访问
-     * anonymous           |   匿名可以访问
-     * denyAll             |   用户不能访问
-     * fullyAuthenticated  |   用户完全认证可以访问(非remember-me下自动登录)
-     * hasAnyAuthority     |   如果有参数,参数表示权限,则其中任何一个权限可以访问
-     * hasAnyRole          |   如果有参数,参数表示角色,则其中任何一个角色可以访问
-     * hasAuthority        |   如果有参数,参数表示权限,则其权限可以访问
-     * hasIpAddress        |   如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
-     * hasRole             |   如果有参数,参数表示角色,则其角色可以访问
-     * permitAll           |   用户可以任意访问
-     * rememberMe          |   允许通过remember-me登录的用户访问
-     * authenticated       |   用户登录后可访问
-     */
-    @Override
-    protected void configure(HttpSecurity http) throws Exception
-    {
-        http.authorizeRequests()
-                .antMatchers("/**").permitAll()
-                .antMatchers("/app/crmCustomer/**").anonymous()
-                .anyRequest().authenticated()
-                .and().csrf().disable();
-    }
-
-    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
-    @Override
-    public AuthenticationManager authenticationManagerBean() throws Exception {
-        return super.authenticationManagerBean();
-    }
-
-
-}

+ 0 - 33
fs-company-app/src/main/java/com/fs/framework/config/ServerConfig.java

@@ -1,33 +0,0 @@
-package com.fs.framework.config;
-
-import com.fs.common.utils.ServletUtils;
-import org.springframework.stereotype.Component;
-
-import javax.servlet.http.HttpServletRequest;
-
-/**
- * 服务相关配置
- * 
-
- */
-@Component
-public class ServerConfig
-{
-    /**
-     * 获取完整的请求路径,包括:域名,端口,上下文访问路径
-     * 
-     * @return 服务地址
-     */
-    public String getUrl()
-    {
-        HttpServletRequest request = ServletUtils.getRequest();
-        return getDomain(request);
-    }
-
-    public static String getDomain(HttpServletRequest request)
-    {
-        StringBuffer url = request.getRequestURL();
-        String contextPath = request.getServletContext().getContextPath();
-        return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();
-    }
-}

+ 0 - 122
fs-company-app/src/main/java/com/fs/framework/config/SwaggerConfig.java

@@ -1,122 +0,0 @@
-package com.fs.framework.config;
-
-import com.fs.common.config.FSConfig;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.models.auth.In;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import springfox.documentation.builders.ApiInfoBuilder;
-import springfox.documentation.builders.PathSelectors;
-import springfox.documentation.builders.RequestHandlerSelectors;
-import springfox.documentation.service.*;
-import springfox.documentation.spi.DocumentationType;
-import springfox.documentation.spi.service.contexts.SecurityContext;
-import springfox.documentation.spring.web.plugins.Docket;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Swagger2的接口配置
- * 
-
- */
-@Configuration
-public class SwaggerConfig
-{
-    /** 系统基础配置 */
-    @Autowired
-    private FSConfig fsConfig;
-
-    /** 是否开启swagger */
-    @Value("${swagger.enabled}")
-    private boolean enabled;
-
-    /** 设置请求的统一前缀 */
-    @Value("${swagger.pathMapping}")
-    private String pathMapping;
-
-    /**
-     * 创建API
-     */
-    @Bean
-    public Docket createRestApi()
-    {
-        return new Docket(DocumentationType.SWAGGER_2)
-                // 是否启用Swagger
-                .enable(enabled)
-                // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息)
-                .apiInfo(apiInfo())
-                // 设置哪些接口暴露给Swagger展示
-                .select()
-                // 扫描所有有注解的api,用这种方式更灵活
-                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
-                // 扫描指定包中的swagger注解
-                // .apis(RequestHandlerSelectors.basePackage("com.fs.project.tool.swagger"))
-                // 扫描所有 .apis(RequestHandlerSelectors.any())
-                .paths(PathSelectors.any())
-                .build()
-                /* 设置安全模式,swagger可以设置访问token */
-                .securitySchemes(securitySchemes())
-                .securityContexts(securityContexts())
-                .pathMapping(pathMapping);
-    }
-
-    /**
-     * 安全模式,这里指定token通过Authorization头请求头传递
-     */
-    private List<ApiKey> securitySchemes()
-    {
-        List<ApiKey> apiKeyList = new ArrayList<ApiKey>();
-//        apiKeyList.add(new ApiKey("Authorization", "AppToken", "header"));
-        apiKeyList.add(new ApiKey("Authorization", "Authorization", "header"));
-        return apiKeyList;
-    }
-
-    /**
-     * 安全上下文
-     */
-    private List<SecurityContext> securityContexts()
-    {
-        List<SecurityContext> securityContexts = new ArrayList<>();
-        securityContexts.add(
-                SecurityContext.builder()
-                        .securityReferences(defaultAuth())
-                        .forPaths(PathSelectors.regex("^(?!auth).*$"))
-                        .build());
-        return securityContexts;
-    }
-
-    /**
-     * 默认的安全上引用
-     */
-    private List<SecurityReference> defaultAuth()
-    {
-        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
-        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
-        authorizationScopes[0] = authorizationScope;
-        List<SecurityReference> securityReferences = new ArrayList<>();
-        securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
-        return securityReferences;
-    }
-
-    /**
-     * 添加摘要信息
-     */
-    private ApiInfo apiInfo()
-    {
-        // 用ApiInfoBuilder进行定制
-        return new ApiInfoBuilder()
-                // 设置标题
-                .title("标题:FS管理系统_接口文档")
-                // 描述
-                .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
-                // 作者信息
-                .contact(new Contact(fsConfig.getName(), null, null))
-                // 版本
-                .version("版本号:" + fsConfig.getVersion())
-                .build();
-    }
-}

+ 0 - 63
fs-company-app/src/main/java/com/fs/framework/config/ThreadPoolConfig.java

@@ -1,63 +0,0 @@
-package com.fs.framework.config;
-
-import com.fs.common.utils.Threads;
-import org.apache.commons.lang3.concurrent.BasicThreadFactory;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
-
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.ThreadPoolExecutor;
-
-/**
- * 线程池配置
- *
-
- **/
-@Configuration
-public class ThreadPoolConfig
-{
-    // 核心线程池大小
-    private int corePoolSize = 50;
-
-    // 最大可创建的线程数
-    private int maxPoolSize = 200;
-
-    // 队列最大长度
-    private int queueCapacity = 1000;
-
-    // 线程池维护线程所允许的空闲时间
-    private int keepAliveSeconds = 300;
-
-    @Bean(name = "threadPoolTaskExecutor")
-    public ThreadPoolTaskExecutor threadPoolTaskExecutor()
-    {
-        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
-        executor.setMaxPoolSize(maxPoolSize);
-        executor.setCorePoolSize(corePoolSize);
-        executor.setQueueCapacity(queueCapacity);
-        executor.setKeepAliveSeconds(keepAliveSeconds);
-        // 线程池对拒绝任务(无线程可用)的处理策略
-        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
-        return executor;
-    }
-
-    /**
-     * 执行周期性或定时任务
-     */
-    @Bean(name = "scheduledExecutorService")
-    protected ScheduledExecutorService scheduledExecutorService()
-    {
-        return new ScheduledThreadPoolExecutor(corePoolSize,
-                new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build())
-        {
-            @Override
-            protected void afterExecute(Runnable r, Throwable t)
-            {
-                super.afterExecute(r, t);
-                Threads.printException(r, t);
-            }
-        };
-    }
-}

+ 0 - 20
fs-company-app/src/main/java/com/fs/framework/config/WebSocketConfig.java

@@ -1,20 +0,0 @@
-package com.fs.framework.config;
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.socket.server.standard.ServerEndpointExporter;
-
-@Configuration
-public class WebSocketConfig {
-    /**
-     * ServerEndpointExporter 作用
-     *
-     * 这个Bean会自动注册使用@ServerEndpoint注解声明的websocket endpoint
-     *
-     * @return
-     */
-    @Bean
-    public ServerEndpointExporter serverEndpointExporter() {
-        return new ServerEndpointExporter();
-    }
-}

+ 0 - 77
fs-company-app/src/main/java/com/fs/framework/config/properties/DruidProperties.java

@@ -1,77 +0,0 @@
-package com.fs.framework.config.properties;
-
-import com.alibaba.druid.pool.DruidDataSource;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Configuration;
-
-/**
- * druid 配置属性
- * 
-
- */
-@Configuration
-public class DruidProperties
-{
-    @Value("${spring.datasource.mysql.druid.initialSize}")
-    private int initialSize;
-
-    @Value("${spring.datasource.mysql.druid.minIdle}")
-    private int minIdle;
-
-    @Value("${spring.datasource.mysql.druid.maxActive}")
-    private int maxActive;
-
-    @Value("${spring.datasource.mysql.druid.maxWait}")
-    private int maxWait;
-
-    @Value("${spring.datasource.mysql.druid.timeBetweenEvictionRunsMillis}")
-    private int timeBetweenEvictionRunsMillis;
-
-    @Value("${spring.datasource.mysql.druid.minEvictableIdleTimeMillis}")
-    private int minEvictableIdleTimeMillis;
-
-    @Value("${spring.datasource.mysql.druid.maxEvictableIdleTimeMillis}")
-    private int maxEvictableIdleTimeMillis;
-
-    @Value("${spring.datasource.mysql.druid.validationQuery}")
-    private String validationQuery;
-
-    @Value("${spring.datasource.mysql.druid.testWhileIdle}")
-    private boolean testWhileIdle;
-
-    @Value("${spring.datasource.mysql.druid.testOnBorrow}")
-    private boolean testOnBorrow;
-
-    @Value("${spring.datasource.mysql.druid.testOnReturn}")
-    private boolean testOnReturn;
-
-    public DruidDataSource dataSource(DruidDataSource datasource)
-    {
-        /** 配置初始化大小、最小、最大 */
-        datasource.setInitialSize(initialSize);
-        datasource.setMaxActive(maxActive);
-        datasource.setMinIdle(minIdle);
-
-        /** 配置获取连接等待超时的时间 */
-        datasource.setMaxWait(maxWait);
-
-        /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */
-        datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
-
-        /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */
-        datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
-        datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
-
-        /**
-         * 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
-         */
-        datasource.setValidationQuery(validationQuery);
-        /** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */
-        datasource.setTestWhileIdle(testWhileIdle);
-        /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
-        datasource.setTestOnBorrow(testOnBorrow);
-        /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
-        datasource.setTestOnReturn(testOnReturn);
-        return datasource;
-    }
-}

+ 0 - 27
fs-company-app/src/main/java/com/fs/framework/datasource/DynamicDataSource.java

@@ -1,27 +0,0 @@
-package com.fs.framework.datasource;
-
-import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
-
-import javax.sql.DataSource;
-import java.util.Map;
-
-/**
- * 动态数据源
- * 
-
- */
-public class DynamicDataSource extends AbstractRoutingDataSource
-{
-    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources)
-    {
-        super.setDefaultTargetDataSource(defaultTargetDataSource);
-        super.setTargetDataSources(targetDataSources);
-        super.afterPropertiesSet();
-    }
-
-    @Override
-    protected Object determineCurrentLookupKey()
-    {
-        return DynamicDataSourceContextHolder.getDataSourceType();
-    }
-}

+ 0 - 45
fs-company-app/src/main/java/com/fs/framework/datasource/DynamicDataSourceContextHolder.java

@@ -1,45 +0,0 @@
-package com.fs.framework.datasource;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * 数据源切换处理
- * 
-
- */
-public class DynamicDataSourceContextHolder
-{
-    public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);
-
-    /**
-     * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
-     *  所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
-     */
-    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
-
-    /**
-     * 设置数据源的变量
-     */
-    public static void setDataSourceType(String dsType)
-    {
-//        log.info("切换到{}数据源", dsType);
-        CONTEXT_HOLDER.set(dsType);
-    }
-
-    /**
-     * 获得数据源的变量
-     */
-    public static String getDataSourceType()
-    {
-        return CONTEXT_HOLDER.get();
-    }
-
-    /**
-     * 清空数据源变量
-     */
-    public static void clearDataSourceType()
-    {
-        CONTEXT_HOLDER.remove();
-    }
-}

+ 0 - 56
fs-company-app/src/main/java/com/fs/framework/interceptor/RepeatSubmitInterceptor.java

@@ -1,56 +0,0 @@
-package com.fs.framework.interceptor;
-
-import com.alibaba.fastjson.JSONObject;
-import com.fs.common.annotation.RepeatSubmit;
-import com.fs.common.core.domain.AjaxResult;
-import com.fs.common.utils.ServletUtils;
-import org.springframework.stereotype.Component;
-import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.lang.reflect.Method;
-
-/**
- * 防止重复提交拦截器
- *
-
- */
-@Component
-public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter
-{
-    @Override
-    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
-    {
-        if (handler instanceof HandlerMethod)
-        {
-            HandlerMethod handlerMethod = (HandlerMethod) handler;
-            Method method = handlerMethod.getMethod();
-            RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
-            if (annotation != null)
-            {
-                if (this.isRepeatSubmit(request))
-                {
-                    AjaxResult ajaxResult = AjaxResult.error("不允许重复提交,请稍后再试");
-                    ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult));
-                    return false;
-                }
-            }
-            return true;
-        }
-        else
-        {
-            return super.preHandle(request, response, handler);
-        }
-    }
-
-    /**
-     * 验证是否重复提交由子类实现具体的防重复提交的规则
-     *
-     * @param request
-     * @return
-     * @throws Exception
-     */
-    public abstract boolean isRepeatSubmit(HttpServletRequest request);
-}

+ 0 - 126
fs-company-app/src/main/java/com/fs/framework/interceptor/impl/SameUrlDataInterceptor.java

@@ -1,126 +0,0 @@
-package com.fs.framework.interceptor.impl;
-
-import com.alibaba.fastjson.JSONObject;
-import com.fs.common.constant.Constants;
-import com.fs.common.core.redis.RedisCache;
-import com.fs.common.filter.RepeatedlyRequestWrapper;
-import com.fs.common.utils.StringUtils;
-import com.fs.common.utils.http.HttpHelper;
-import com.fs.framework.interceptor.RepeatSubmitInterceptor;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-
-import javax.servlet.http.HttpServletRequest;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-
-/**
- * 判断请求url和数据是否和上一次相同,
- * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。
- * 
-
- */
-@Component
-public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
-{
-    public final String REPEAT_PARAMS = "repeatParams";
-
-    public final String REPEAT_TIME = "repeatTime";
-
-    // 令牌自定义标识
-    @Value("${token.header}")
-    private String header;
-
-    @Autowired
-    private RedisCache redisCache;
-
-    /**
-     * 间隔时间,单位:秒 默认10秒
-     * 
-     * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据
-     */
-    private int intervalTime = 10;
-
-    public void setIntervalTime(int intervalTime)
-    {
-        this.intervalTime = intervalTime;
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public boolean isRepeatSubmit(HttpServletRequest request)
-    {
-        String nowParams = "";
-        if (request instanceof RepeatedlyRequestWrapper)
-        {
-            RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
-            nowParams = HttpHelper.getBodyString(repeatedlyRequest);
-        }
-
-        // body参数为空,获取Parameter的数据
-        if (StringUtils.isEmpty(nowParams))
-        {
-            nowParams = JSONObject.toJSONString(request.getParameterMap());
-        }
-        Map<String, Object> nowDataMap = new HashMap<String, Object>();
-        nowDataMap.put(REPEAT_PARAMS, nowParams);
-        nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
-
-        // 请求地址(作为存放cache的key值)
-        String url = request.getRequestURI();
-
-        // 唯一值(没有消息头则使用请求地址)
-        String submitKey = request.getHeader(header);
-        if (StringUtils.isEmpty(submitKey))
-        {
-            submitKey = url;
-        }
-
-        // 唯一标识(指定key + 消息头)
-        String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY + submitKey;
-
-        Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);
-        if (sessionObj != null)
-        {
-            Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
-            if (sessionMap.containsKey(url))
-            {
-                Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);
-                if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap))
-                {
-                    return true;
-                }
-            }
-        }
-        Map<String, Object> cacheMap = new HashMap<String, Object>();
-        cacheMap.put(url, nowDataMap);
-        redisCache.setCacheObject(cacheRepeatKey, cacheMap, intervalTime, TimeUnit.SECONDS);
-        return false;
-    }
-
-    /**
-     * 判断参数是否相同
-     */
-    private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
-    {
-        String nowParams = (String) nowMap.get(REPEAT_PARAMS);
-        String preParams = (String) preMap.get(REPEAT_PARAMS);
-        return nowParams.equals(preParams);
-    }
-
-    /**
-     * 判断两次间隔时间
-     */
-    private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap)
-    {
-        long time1 = (Long) nowMap.get(REPEAT_TIME);
-        long time2 = (Long) preMap.get(REPEAT_TIME);
-        if ((time1 - time2) < (this.intervalTime * 1000))
-        {
-            return true;
-        }
-        return false;
-    }
-}

+ 0 - 56
fs-company-app/src/main/java/com/fs/framework/manager/AsyncManager.java

@@ -1,56 +0,0 @@
-package com.fs.framework.manager;
-
-import com.fs.common.utils.Threads;
-import com.fs.common.utils.spring.SpringUtils;
-
-import java.util.TimerTask;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-/**
- * 异步任务管理器
- * 
-
- */
-public class AsyncManager
-{
-    /**
-     * 操作延迟10毫秒
-     */
-    private final int OPERATE_DELAY_TIME = 10;
-
-    /**
-     * 异步操作任务调度线程池
-     */
-    private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
-
-    /**
-     * 单例模式
-     */
-    private AsyncManager(){}
-
-    private static AsyncManager me = new AsyncManager();
-
-    public static AsyncManager me()
-    {
-        return me;
-    }
-
-    /**
-     * 执行任务
-     * 
-     * @param task 任务
-     */
-    public void execute(TimerTask task)
-    {
-        executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
-    }
-
-    /**
-     * 停止任务线程池
-     */
-    public void shutdown()
-    {
-        Threads.shutdownAndAwaitTermination(executor);
-    }
-}

+ 0 - 40
fs-company-app/src/main/java/com/fs/framework/manager/ShutdownManager.java

@@ -1,40 +0,0 @@
-package com.fs.framework.manager;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.PreDestroy;
-
-/**
- * 确保应用退出时能关闭后台线程
- *
-
- */
-@Component
-public class ShutdownManager
-{
-    private static final Logger logger = LoggerFactory.getLogger("sys-user");
-
-    @PreDestroy
-    public void destroy()
-    {
-        shutdownAsyncManager();
-    }
-
-    /**
-     * 停止异步执行任务
-     */
-    private void shutdownAsyncManager()
-    {
-        try
-        {
-            logger.info("====关闭后台任务任务线程池====");
-            AsyncManager.me().shutdown();
-        }
-        catch (Exception e)
-        {
-            logger.error(e.getMessage(), e);
-        }
-    }
-}

+ 0 - 103
fs-company-app/src/main/java/com/fs/framework/manager/factory/AsyncFactory.java

@@ -1,103 +0,0 @@
-package com.fs.framework.manager.factory;
-
-import com.fs.common.constant.Constants;
-import com.fs.common.utils.LogUtils;
-import com.fs.common.utils.ServletUtils;
-import com.fs.common.utils.StringUtils;
-import com.fs.common.utils.ip.AddressUtils;
-import com.fs.common.utils.ip.IpUtils;
-import com.fs.common.utils.spring.SpringUtils;
-import com.fs.system.domain.SysLogininfor;
-import com.fs.system.domain.SysOperLog;
-import com.fs.system.service.ISysLogininforService;
-import com.fs.system.service.ISysOperLogService;
-import eu.bitwalker.useragentutils.UserAgent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.TimerTask;
-
-/**
- * 异步工厂(产生任务用)
- * 
-
- */
-public class AsyncFactory
-{
-    private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");
-
-    /**
-     * 记录登录信息
-     * 
-     * @param username 用户名
-     * @param status 状态
-     * @param message 消息
-     * @param args 列表
-     * @return 任务task
-     */
-    public static TimerTask recordLogininfor(final String username, final String status, final String message,
-            final Object... args)
-    {
-        final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
-        final String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
-        return new TimerTask()
-        {
-            @Override
-            public void run()
-            {
-                String address = AddressUtils.getRealAddressByIP(ip);
-                StringBuilder s = new StringBuilder();
-                s.append(LogUtils.getBlock(ip));
-                s.append(address);
-                s.append(LogUtils.getBlock(username));
-                s.append(LogUtils.getBlock(status));
-                s.append(LogUtils.getBlock(message));
-                // 打印信息到日志
-                sys_user_logger.info(s.toString(), args);
-                // 获取客户端操作系统
-                String os = userAgent.getOperatingSystem().getName();
-                // 获取客户端浏览器
-                String browser = userAgent.getBrowser().getName();
-                // 封装对象
-                SysLogininfor logininfor = new SysLogininfor();
-                logininfor.setUserName(username);
-                logininfor.setIpaddr(ip);
-                logininfor.setLoginLocation(address);
-                logininfor.setBrowser(browser);
-                logininfor.setOs(os);
-                logininfor.setMsg(message);
-                // 日志状态
-                if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER))
-                {
-                    logininfor.setStatus(Constants.SUCCESS);
-                }
-                else if (Constants.LOGIN_FAIL.equals(status))
-                {
-                    logininfor.setStatus(Constants.FAIL);
-                }
-                // 插入数据
-                SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor);
-            }
-        };
-    }
-
-    /**
-     * 操作日志记录
-     * 
-     * @param operLog 操作日志信息
-     * @return 任务task
-     */
-    public static TimerTask recordOper(final SysOperLog operLog)
-    {
-        return new TimerTask()
-        {
-            @Override
-            public void run()
-            {
-                // 远程查询操作地点
-                operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
-                SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog);
-            }
-        };
-    }
-}

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

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

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

@@ -0,0 +1,256 @@
+package com.fs.company.controller.course;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.domain.FsUserCoursePeriod;
+import com.fs.course.domain.FsUserCoursePeriodDays;
+import com.fs.course.domain.FsUserCourseVideoRedPackage;
+import com.fs.course.param.CompanyRedPacketParam;
+import com.fs.course.param.FsBatchPeriodRedPackageParam;
+import com.fs.course.param.PeriodCountParam;
+import com.fs.course.service.IFsUserCoursePeriodDaysService;
+import com.fs.course.service.IFsUserCoursePeriodService;
+import com.fs.course.service.IFsUserCourseVideoRedPackageService;
+import com.fs.course.vo.FsPeriodCountVO;
+import com.fs.course.vo.FsUserCoursePeriodVO;
+import com.fs.course.vo.PeriodRedPacketVO;
+import com.fs.course.vo.UpdateCourseTimeVo;
+import com.fs.framework.security.LoginUser;
+import com.fs.framework.service.TokenService;
+import com.fs.his.vo.OptionsVO;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.LocalDate;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * 会员营期Controller
+ *
+ * @author fs
+ * @date 2025-04-11
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/course/period")
+@Slf4j
+public class FsUserCoursePeriodController extends BaseController {
+    private final IFsUserCoursePeriodService fsUserCoursePeriodService;
+    private final IFsUserCoursePeriodDaysService fsUserCoursePeriodDaysService;
+    private final IFsUserCourseVideoRedPackageService fsUserCourseVideoRedPackageService;
+    private final TokenService tokenService;
+
+    /**
+     * 查询会员营期列表
+     */
+//    @PreAuthorize("@ss.hasPermi('course:period:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsUserCoursePeriod fsUserCoursePeriod)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        fsUserCoursePeriod.setCompanyId(loginUser.getCompany().getCompanyId().toString());
+        List<FsUserCoursePeriod> list = fsUserCoursePeriodService.selectFsUserCoursePeriodList(fsUserCoursePeriod);
+        return getDataTable(list);
+    }
+
+    @PostMapping("/page")
+    @ApiOperation("自定义查询主列表分页")
+    public R pageList(@RequestBody FsUserCoursePeriod fsUserCoursePeriod)
+    {
+//        startPage();
+        PageHelper.startPage(fsUserCoursePeriod.getPageNum(), fsUserCoursePeriod.getPageSize());
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        fsUserCoursePeriod.setCompanyIdList(Collections.singletonList(loginUser.getCompany().getCompanyId()));
+        List<FsUserCoursePeriodVO> list = fsUserCoursePeriodService.selectFsUserCoursePeriodPage(fsUserCoursePeriod);
+        PageInfo<FsUserCoursePeriodVO> pageInfo = new PageInfo<>(list);
+        Map<String, Object> result = new HashMap<>();
+        result.put("rows", pageInfo.getList());
+        result.put("total", pageInfo.getTotal());
+        return R.ok(result);
+//        return getDataTable(list);
+    }
+
+    /**
+     * 导出会员营期列表
+     */
+//    @PreAuthorize("@ss.hasPermi('course:period:export')")
+    @Log(title = "会员营期", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsUserCoursePeriod fsUserCoursePeriod)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        fsUserCoursePeriod.setCompanyId(loginUser.getCompany().getCompanyId().toString());
+        List<FsUserCoursePeriod> list = fsUserCoursePeriodService.selectFsUserCoursePeriodList(fsUserCoursePeriod);
+        ExcelUtil<FsUserCoursePeriod> util = new ExcelUtil<FsUserCoursePeriod>(FsUserCoursePeriod.class);
+        return util.exportExcel(list, "userCoursePeriod");
+    }
+
+    /**
+     * 获取会员营期详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('course:period:query')")
+    @GetMapping(value = "/{periodId}")
+    public AjaxResult getInfo(@PathVariable("periodId") Long periodId)
+    {
+        return AjaxResult.success(fsUserCoursePeriodService.selectFsUserCoursePeriodById(periodId));
+    }
+
+    /**
+     * 新增会员营期
+     */
+    @PreAuthorize("@ss.hasPermi('course:period:add')")
+    @Log(title = "会员营期", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsUserCoursePeriod fsUserCoursePeriod)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        fsUserCoursePeriod.setCompanyId(loginUser.getCompany().getCompanyId().toString());
+        return toAjax(fsUserCoursePeriodService.insertFsUserCoursePeriod(fsUserCoursePeriod));
+    }
+
+    /**
+     * 修改会员营期
+     */
+    @PreAuthorize("@ss.hasPermi('course:period:edit')")
+    @Log(title = "会员营期", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsUserCoursePeriod fsUserCoursePeriod)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        fsUserCoursePeriod.setCompanyId(loginUser.getCompany().getCompanyId().toString());
+        return toAjax(fsUserCoursePeriodService.updateFsUserCoursePeriod(fsUserCoursePeriod));
+    }
+
+    /**
+     * 删除会员营期
+     */
+    @PreAuthorize("@ss.hasPermi('course:period:remove')")
+    @Log(title = "会员营期", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{periodIds}")
+    public AjaxResult remove(@PathVariable Long[] periodIds)
+    {
+        return toAjax(fsUserCoursePeriodService.deleteFsUserCoursePeriodByIds(periodIds));
+    }
+
+    @GetMapping("/getDays")
+    public TableDataInfo getDays(FsUserCoursePeriodDays fsUserCoursePeriodDays){
+        startPage();
+        FsUserCoursePeriod period = fsUserCoursePeriodService.selectFsUserCoursePeriodById(fsUserCoursePeriodDays.getPeriodId());
+        fsUserCoursePeriodDays.setMaxDate(LocalDate.now().plusDays(period.getMaxViewNum()));
+        List<FsUserCoursePeriodDays> list = fsUserCoursePeriodDaysService.selectFsUserCoursePeriodDaysList(fsUserCoursePeriodDays);
+        return getDataTable(list);
+    }
+
+    @PostMapping("/addCourse")
+    public R addCourse(@RequestBody FsUserCoursePeriodDays entity){
+        return fsUserCoursePeriodDaysService.addCourse(entity);
+    }
+    @PostMapping("/updateCourseTime")
+    public R updateCourseTime(@RequestBody UpdateCourseTimeVo vo){
+        return fsUserCoursePeriodDaysService.updateCourseTime(vo);
+    }
+    @PostMapping("/updateCourseDate")
+    public R updateCourseDate(@RequestBody UpdateCourseTimeVo vo){
+        return fsUserCoursePeriodDaysService.updateCourseDate(vo);
+    }
+    @PostMapping("/updateListCourseData")
+    public R updateListCourseData(@RequestBody List<FsUserCoursePeriodDays> entity){
+        return fsUserCoursePeriodDaysService.updateListCourseData(entity);
+    }
+
+    @ApiOperation("根据营期id获取公司红包金额列表(暂废弃)")
+    @GetMapping("/companyList")
+    public R getCompanyByPeriod(Long periodId, Long videoId) {
+        List<CompanyRedPacketParam> companyList = fsUserCoursePeriodDaysService.getCompanyByPeriod(periodId, videoId);
+        return R.ok().put("data", companyList);
+    }
+
+    @ApiOperation("获取设置红包金额列表")
+    @GetMapping("/redPacketList")
+    public R getPeriodRedPacketList(Long periodId, Long companyId) {
+        List<PeriodRedPacketVO> periodRedPacketList = fsUserCoursePeriodDaysService.getPeriodRedPacketList(periodId, companyId);
+        return R.ok().put("data", periodRedPacketList);
+    }
+
+    @ApiOperation("按课程批量保存设置红包金额")
+    @PostMapping("/batchRedPacket")
+    public R batchRedPacketMoney(@RequestBody List<FsUserCourseVideoRedPackage> videoRedPackageList) {
+        try {
+            fsUserCourseVideoRedPackageService.batchSaveCompanyRedPackage(videoRedPackageList);
+        } catch (Exception e) {
+            logger.error("按课程批量保存设置红包金额-失败!,营期id:{}", videoRedPackageList.get(0).getPeriodId());
+            return R.error("保存失败!");
+        }
+        return R.ok();
+    }
+
+    @ApiOperation("按营期批量保存设置红包金额")
+    @PostMapping("/batchRedPacket/byPeriod")
+    public R batchRedPacketByPeriod(@RequestBody List<FsBatchPeriodRedPackageParam> periodRedPackageList) {
+        try {
+            fsUserCourseVideoRedPackageService.batchRedPacketByPeriod(periodRedPackageList);
+        } catch (Exception e) {
+            logger.error("按营期批量保存设置红包金额-失败!,入参:{}", periodRedPackageList);
+            return R.error("保存失败!");
+        }
+        return R.ok();
+    }
+
+    @PostMapping("/periodCount")
+    @ApiOperation("营期统计")
+    public R periodCourseCount(@RequestBody PeriodCountParam param) {
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        FsUserCoursePeriod period = fsUserCoursePeriodService.selectFsUserCoursePeriodById(param.getPeriodId());
+        param.setMaxDate(LocalDate.now().plusDays(period.getMaxViewNum()));
+        List<FsPeriodCountVO> list = fsUserCoursePeriodDaysService.periodCourseCount(param);
+        PageInfo<FsPeriodCountVO> pageInfo = new PageInfo<>(list);
+        Map<String, Object> result = new HashMap<>();
+        result.put("rows", pageInfo.getList());
+        result.put("total", pageInfo.getTotal());
+        return R.ok(result);
+    }
+
+    @GetMapping("/getPeriodListLikeName")
+    public R getPeriodListLikeName(@RequestParam(required = false) String name,
+                                   @RequestParam(required = false) Long campId,
+                                   @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("campId", campId);
+
+        PageHelper.startPage(pageNum, pageSize);
+        List<OptionsVO> periodList = fsUserCoursePeriodDaysService.selectPeriodListByMap(params);
+        return R.ok().put("data", new PageInfo<>(periodList));
+    }
+
+    @ApiOperation("营期课程-上移/下移")
+    @PutMapping("/courseMove")
+    public R periodCourseMove(Long id, Long targetId) {
+        return fsUserCoursePeriodDaysService.periodCourseMove(id, targetId);
+    }
+
+    @ApiOperation("结束营期")
+    @PostMapping("/closePeriod")
+    public R closePeriod(Long id) {
+        fsUserCoursePeriodService.closePeriod(id);
+        return R.ok();
+    }
+
+}

+ 0 - 3
fs-qw-api-msg/src/main/java/com/fs/app/controller/QwMsgController.java

@@ -5,16 +5,13 @@ import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.uuid.IdUtils;
 import com.fs.fastGpt.service.AiHookService;
 import com.fs.qw.domain.QwUser;
-import com.fs.qw.domain.QwUserVideo;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.service.IQwUserVoiceLogService;
-import com.fs.qw.vo.QwMessageListVO;
 import com.fs.wxwork.dto.*;
 import com.fs.wxwork.service.WxWorkService;
 import io.swagger.annotations.Api;
 import lombok.extern.slf4j.Slf4j;
 import org.json.JSONObject;
-import org.omg.CORBA.LongHolder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 

+ 1 - 2
fs-repeat-api/src/main/java/com/fs/app/controller/CommonController.java

@@ -9,7 +9,6 @@ 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;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.rocketmq.spring.core.RocketMQTemplate;
@@ -22,7 +21,7 @@ import org.springframework.web.bind.annotation.RestController;
 @Api("公共接口")
 @RestController
 @AllArgsConstructor
-@Ignore
+//@Ignore
 @RequestMapping(value="/app/common")
 public class CommonController {
     private IAdHtmlClickLogService adHtmlClickLogService;

+ 3 - 7
fs-service/src/main/java/com/fs/ad/apis/DyApiUtil.java

@@ -6,20 +6,16 @@ import cn.hutool.http.HttpUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.fs.ad.dy.vo.DyDataVo;
-import com.fs.ad.iqiyi.vo.IyiqiDataVo;
 import lombok.extern.slf4j.Slf4j;
 
 import java.time.Instant;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.stream.Collectors;
 
 @Slf4j
 public class DyApiUtil {
     private static final String URL = "https://analytics.oceanengine.com/api/v2/conversion";
 
-    public static void dataBack(String clickId, String vid){
-        DyDataVo vo = DyDataVo.builder().event_type("customer_effective").outer_event_id(vid).context(DyDataVo.DyContext.builder().ad(DyDataVo.DyContext.DyAd.builder().callback(clickId).build()).build()).build();
+    public static void dataBack(String clickId, String vid, String dyType){
+        DyDataVo vo = DyDataVo.builder().event_type(dyType).outer_event_id(vid).context(DyDataVo.DyContext.builder().ad(DyDataVo.DyContext.DyAd.builder().callback(clickId).build()).build()).build();
         vo.setTimestamp(Instant.now().toEpochMilli());
         HttpRequest request = HttpUtil.createPost(URL);
         request.body(JSON.toJSONString(vo));
@@ -34,6 +30,6 @@ public class DyApiUtil {
     public static void main(String[] args) {
         String clickId = "B.ezpH241vFUgYLNheuhOp1S12czUywa8aRoZynGsLpFn5fmOU9NdeGkWnPos0VzVGJSxjiCzO64Y3R9il5vt83OWRokMPUSIcxRC9mbcvh48uPR517ae5I5GMNfe5txXsBB";
         String vid = "1833266361549963";
-        dataBack(clickId, vid);
+        dataBack(clickId, vid, "work_wechat_added");
     }
 }

+ 1 - 1
fs-service/src/main/java/com/fs/ad/service/impl/AdHtmlClickLogServiceImpl.java

@@ -221,7 +221,7 @@ public class AdHtmlClickLogServiceImpl extends ServiceImpl<AdHtmlClickLogMapper,
     private void uploadDy(AdHtmlClickLog one, AdUploadType clickType){
         if(clickType != AdUploadType.ADD_WX && StringUtils.isNotEmpty(one.getBackJson())) return;
         JSONObject backJson = JSON.parseObject(one.getBackJson());
-        DyApiUtil.dataBack(backJson.getString("clickId"), one.getVid());
+        DyApiUtil.dataBack(backJson.getString("clickId"), one.getVid(), clickType.getDyType());
     }
 
     @Override

+ 1 - 1
fs-service/src/main/java/com/fs/baidu/api/ConvertData.java

@@ -57,7 +57,7 @@ public class ConvertData {
         CloseableHttpClient client = HttpClients.createDefault();
         HttpPost post = new HttpPost(BAIDU_OCPC_URL);
         post.setHeader("Content-type", "application/json; charset=UTF-8");
-        StringEntity entity = new StringEntity(msg, StandardCharsets.UTF_8);
+        StringEntity entity = new StringEntity(msg, "UTF-8");
         entity.setContentEncoding("UTF-8");
         post.setEntity(entity);
         // 添加失败重试

+ 22 - 0
fs-service/src/main/java/com/fs/common/param/BaseQueryParam.java

@@ -0,0 +1,22 @@
+package com.fs.common.param;
+
+import com.fs.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class BaseQueryParam extends BaseEntity implements Serializable {
+    @ApiModelProperty(value = "页码,默认为1")
+    private Integer pageNum =1;
+    @ApiModelProperty(value = "页码,默认为1")
+    private Integer page =1;
+    @ApiModelProperty(value = "页大小,默认为10")
+    private Integer pageSize = 10;
+    @ApiModelProperty(value = "限制数量")
+    private Integer limit;
+    @ApiModelProperty(value = "搜索字符串")
+    private String keyword;
+
+}

+ 19 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyUser.java

@@ -21,6 +21,9 @@ public class CompanyUser extends BaseEntity
     @Excel(name = "公司ID")
     private Long companyId;
 
+    /** 公司名称 */
+    private String companyName;
+
     public String getCorpId() {
         return corpId;
     }
@@ -54,6 +57,8 @@ public class CompanyUser extends BaseEntity
     /** 手机号码 */
     @Excel(name = "手机号码")
     private String phonenumber;
+    /** 岗位 */
+    private List<CompanyPost> posts;
 
     /** 用户性别(0男 1女 2未知) */
     @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知")
@@ -462,5 +467,19 @@ public class CompanyUser extends BaseEntity
         this.isAudit = isAudit;
     }
 
+    public String getCompanyName() {
+        return companyName;
+    }
+
+    public void setCompanyName(String companyName) {
+        this.companyName = companyName;
+    }
 
+    public List<CompanyPost> getPosts() {
+        return posts;
+    }
+
+    public void setPosts(List<CompanyPost> posts) {
+        this.posts = posts;
+    }
 }

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

@@ -71,4 +71,7 @@ public interface CompanyPostMapper
 
     @Select("select p.post_name from company_user_post up left join company_post p on p.post_id=up.post_id where up.user_id=#{userId}  ")
     List<String> selectPostNameListByUserId(Long userId);
+
+    @Select("select p.post_id, p.post_name from company_user_post up inner join company_post p on p.post_id=up.post_id where up.user_id = #{userId}")
+    List<CompanyPost> selectCompanyPostByUserId(@Param("userId") Long userId);
 }

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

@@ -273,4 +273,5 @@ public interface CompanyUserMapper
 
     int setIsRegisterMember(@Param("status") boolean status, @Param("userIds")List<Long> userIds);
 
+    void auditUsers(@Param("userIds") List<Long> userIds);
 }

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

@@ -0,0 +1,12 @@
+package com.fs.company.param;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class EditPwdParam implements Serializable {
+    private String password;
+    private String oldPassword;
+
+}

+ 24 - 0
fs-service/src/main/java/com/fs/company/param/EditUserInfoParam.java

@@ -0,0 +1,24 @@
+package com.fs.company.param;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+@ApiModel
+public class EditUserInfoParam implements Serializable {
+    @ApiModelProperty(value = "用户性别(0男 1女 2未知)")
+    private String sex;
+    @ApiModelProperty(value = "头像地址")
+    private String headImg;
+    @ApiModelProperty(value = "手机号码")
+    private String mobile;
+    @ApiModelProperty(value = "用户邮箱")
+    private String email;
+    @ApiModelProperty(value = "微信二维码")
+    private String qrCodeWeixin;
+    @ApiModelProperty(value = "用户昵称")
+    private String nickName;
+}

+ 16 - 0
fs-service/src/main/java/com/fs/company/param/EditUserQrCodeParam.java

@@ -0,0 +1,16 @@
+package com.fs.company.param;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class EditUserQrCodeParam implements Serializable {
+
+    private String qrCodeWeixin;
+    private String qrCodeWecom;
+    private String title;
+    private Integer type; //0:个微  1:企微
+    private Long cardId;
+
+}

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

@@ -65,4 +65,6 @@ public interface ICompanyPostService
     List<Integer> selectPostListByUserId(Long userId);
 
     List<String> selectPostNameListByUserId(Long userId);
+
+    List<CompanyPost> selectCompanyPostListByUserId(Long userId);
 }

+ 1 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyUserService.java

@@ -192,4 +192,5 @@ public interface ICompanyUserService {
      */
     Boolean setIsRegisterMember(boolean status,  List<Long> userIds);
 
+    void auditUsers(List<Long> userIds);
 }

+ 7 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyPostServiceImpl.java

@@ -7,6 +7,7 @@ import com.fs.company.service.ICompanyPostService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -109,4 +110,10 @@ public class CompanyPostServiceImpl implements ICompanyPostService
     public List<String> selectPostNameListByUserId(Long userId) {
         return companyPostMapper.selectPostNameListByUserId(userId);
     }
+
+    @Override
+    public List<CompanyPost> selectCompanyPostListByUserId(Long userId) {
+        return companyPostMapper.selectCompanyPostByUserId(userId);
+    }
+
 }

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

@@ -504,4 +504,12 @@ public class CompanyUserServiceImpl implements ICompanyUserService
         }
         return true;
     }
+
+    @Override
+    public void auditUsers(List<Long> userIds) {
+        if (userIds.isEmpty()) {
+            return;
+        }
+        companyUserMapper.auditUsers(userIds);
+    }
 }

+ 29 - 0
fs-service/src/main/java/com/fs/company/vo/CompanyUserAppVO.java

@@ -0,0 +1,29 @@
+package com.fs.company.vo;
+
+import com.fs.company.domain.CompanyUser;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.math.BigDecimal;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class CompanyUserAppVO extends CompanyUser {
+
+    /**
+     * 会员数
+     */
+    private Long vipCount;
+    /**
+     * 新增会员数
+     */
+    private Long newVipCount;
+    /**
+     * 红包数
+     */
+    private Integer redPacketCount;
+    /**
+     * 新用户红包金额
+     */
+    private BigDecimal newVipRedPackAmount;
+}

+ 84 - 0
fs-service/src/main/java/com/fs/core/config/WildcardClasspathConfigDataLoader.java

@@ -0,0 +1,84 @@
+//package com.fs.core.config;
+//
+//import org.springframework.boot.context.config.ConfigData;
+//import org.springframework.boot.context.config.ConfigDataLoader;
+//import org.springframework.boot.context.config.ConfigDataLoaderContext;
+//import org.springframework.boot.context.config.ConfigDataResource;
+//import org.springframework.boot.context.config.ConfigDataResourceNotFoundException;
+//import org.springframework.core.io.Resource;
+//import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+//import org.springframework.core.io.support.ResourcePatternResolver;
+//import org.springframework.util.StringUtils;
+//
+//import java.io.IOException;
+//import java.util.ArrayList;
+//import java.util.Arrays;
+//import java.util.List;
+//
+//public class WildcardClasspathConfigDataLoader implements ConfigDataLoader<WildcardClasspathConfigDataLoader.WildcardResource> {
+//
+//    private static final ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
+//
+//    @Override
+//    public ConfigData load(ConfigDataLoaderContext context, WildcardResource resource) {
+//        try {
+//            List<Resource> resources = resolveResources(resource.getPattern());
+//            if (resources.isEmpty()) {
+//                throw new ConfigDataResourceNotFoundException(resource);
+//            }
+//
+//            ConfigData.Builder builder = new ConfigData.Builde();
+//            for (Resource res : resources) {
+//                builder = builder.with(res, new DefaultConfigDataResource(res));
+//            }
+//            return builder.build();
+//        } catch (IOException e) {
+//            throw new IllegalStateException("Failed to load config resources: " + resource, e);
+//        }
+//    }
+//
+//    private List<Resource> resolveResources(String pattern) throws IOException {
+//        Resource[] resources = resolver.getResources(pattern);
+//        return Arrays.asList(resources);
+//    }
+//
+//    public static class WildcardResource extends ConfigDataResource {
+//        private final String pattern;
+//
+//        public WildcardResource(String pattern) {
+//            this.pattern = pattern;
+//        }
+//
+//        public String getPattern() {
+//            return pattern;
+//        }
+//
+//        @Override
+//        public boolean equals(Object obj) {
+//            return obj instanceof WildcardResource
+//                    && this.pattern.equals(((WildcardResource) obj).pattern);
+//        }
+//
+//        @Override
+//        public int hashCode() {
+//            return pattern.hashCode();
+//        }
+//
+//        @Override
+//        public String toString() {
+//            return "WildcardClasspathResource [pattern='" + pattern + "']";
+//        }
+//    }
+//
+//    public static class DefaultConfigDataResource extends ConfigDataResource {
+//        private final Resource resource;
+//
+//        public DefaultConfigDataResource(Resource resource) {
+//            this.resource = resource;
+//        }
+//
+//        public Resource getResource() {
+//            return resource;
+//        }
+//    }
+//}

+ 35 - 0
fs-service/src/main/java/com/fs/core/config/WildcardClasspathConfigDataLocationResolver.java

@@ -0,0 +1,35 @@
+//package com.fs.core.config;
+//
+//import org.springframework.boot.context.config.ConfigDataLocation;
+//import org.springframework.boot.context.config.ConfigDataLocationResolver;
+//import org.springframework.boot.context.config.ConfigDataLocationResolverContext;
+//import org.springframework.boot.context.config.ConfigDataResource;
+//import org.springframework.boot.context.config.Profiles;
+//import org.springframework.util.StringUtils;
+//
+//import java.util.Collections;
+//import java.util.List;
+//
+//public class WildcardClasspathConfigDataLocationResolver implements ConfigDataLocationResolver<WildcardClasspathConfigDataLoader.WildcardResource> {
+//
+//    private static final String PREFIX = "classpath*:";
+//
+//    @Override
+//    public boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) {
+//        return location.getValue().startsWith(PREFIX);
+//    }
+//
+//    @Override
+//    public List<WildcardClasspathConfigDataLoader.WildcardResource> resolve(
+//            ConfigDataLocationResolverContext context, ConfigDataLocation location, Profiles profiles) {
+//
+//        String pattern = location.getValue().substring(PREFIX.length());
+//        if (!StringUtils.hasText(pattern)) {
+//            return Collections.emptyList();
+//        }
+//
+//        return Collections.singletonList(
+//                new WildcardClasspathConfigDataLoader.WildcardResource(pattern)
+//        );
+//    }
+//}

+ 55 - 0
fs-service/src/main/java/com/fs/course/domain/FsUserCourseCompanyUserTime.java

@@ -0,0 +1,55 @@
+package com.fs.course.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ * 营期课程-销售课程时间对象 fs_user_course_company_user_time
+ *
+ * @author fs
+ * @date 2025-06-09
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsUserCourseCompanyUserTime extends BaseEntity{
+
+    /** id */
+    private Long id;
+
+    /** 营期ID */
+    @Excel(name = "营期ID")
+    private Long periodId;
+
+    /** 课程ID */
+    @Excel(name = "课程ID")
+    private Long courseId;
+
+    /** 视频ID */
+    @Excel(name = "视频ID")
+    private Long videoId;
+
+    /** 销售id */
+    @Excel(name = "销售id")
+    private Long companyUserId;
+
+    /** 公司id */
+    @Excel(name = "公司id")
+    private Long companyId;
+
+    /** 开始时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "开始时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date startDateTime;
+
+    /** 结束时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "结束时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date endDateTime;
+
+
+}

+ 6 - 0
fs-service/src/main/java/com/fs/course/domain/FsUserCoursePeriodDays.java

@@ -27,6 +27,12 @@ import lombok.EqualsAndHashCode;
 @EqualsAndHashCode(callSuper = true)
 public class FsUserCoursePeriodDays extends BaseEntityTow {
 
+    @TableField(exist = false)
+    private Integer pageNum;
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
     /** id */
     @TableId(type = IdType.AUTO)
     private Long id;

+ 4 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseAnswerLogsMapper.java

@@ -119,4 +119,8 @@ public interface FsCourseAnswerLogsMapper
             "</if>" +
             "</script>"})
     int selectErrorCountByCourseVideo(@Param("videoId") Long videoId,@Param("userId") Long userId,@Param("qwUserId") String qwUserId);
+
+    @Select("select count(log_id) from fs_course_red_packet_log where user_id = #{userId} and video_id = #{videoId}")
+    Long selectRedStatus(@Param("userId") Long userId, @Param("videoId") Long videoId);
+
 }

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

@@ -1,5 +1,6 @@
 package com.fs.course.mapper;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 import com.fs.company.vo.RedPacketMoneyVO;
@@ -132,4 +133,14 @@ public interface FsCourseRedPacketLogMapper
 
     @Select("select * from fs_course_red_packet_log where video_id = #{videoId} and user_id = #{userId} limit 1")
     FsCourseRedPacketLog selectFsCourseRedPacketLogByTemporary(@Param("videoId") Long videoId, @Param("userId")Long userId);
+
+    /**
+     * 查询红包数量
+     * @param companyUserId 销售ID
+     * @return count
+     */
+    @Select("select count(fcrpl.log_id) from fs_course_red_packet_log fcrpl where fcrpl.company_user_id = #{companyUserId}")
+    int getCountByCompanyUserIdId(@Param("companyUserId") Long companyUserId);
+
+    BigDecimal getNewVipRedPackAmountByCompanyUserIdId(@Param("companyUserId") Long companyUserId);
 }

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

@@ -15,6 +15,7 @@ import javax.validation.constraints.NotNull;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 短链课程看课记录Mapper接口
@@ -387,4 +388,7 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
             @Param("endDate") Date endDate,
             @Param("maxId") long  maxId,
             @Param("limit") int limit);
+
+    @Select("select count(log_id) AS watchCount, count(case when log_type = 2 then log_id end) AS finishCount, sum(duration) AS watchTime from fs_course_watch_log where user_id = #{userId} and video_id = #{videoId}")
+    Map<String, Object> selectSumByUserIdAndVideoId(@Param("userId") Long userId, @Param("videoId") Long videoId);
 }

+ 90 - 0
fs-service/src/main/java/com/fs/course/mapper/FsUserCourseCompanyUserTimeMapper.java

@@ -0,0 +1,90 @@
+package com.fs.course.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.course.domain.FsUserCourseCompanyUserTime;
+import com.fs.course.param.CompanyUserTimeQueryParam;
+
+import java.util.List;
+
+/**
+ * 营期课程-销售课程时间Mapper接口
+ *
+ * @author fs
+ * @date 2025-06-09
+ */
+public interface FsUserCourseCompanyUserTimeMapper extends BaseMapper<FsUserCourseCompanyUserTime> {
+    /**
+     * 查询营期课程-销售课程时间
+     *
+     * @param id 营期课程-销售课程时间主键
+     * @return 营期课程-销售课程时间
+     */
+    FsUserCourseCompanyUserTime selectFsUserCourseCompanyUserTimeById(Long id);
+
+    /**
+     * 查询营期课程-销售课程时间列表
+     *
+     * @param fsUserCourseCompanyUserTime 营期课程-销售课程时间
+     * @return 营期课程-销售课程时间集合
+     */
+    List<FsUserCourseCompanyUserTime> selectFsUserCourseCompanyUserTimeList(
+            FsUserCourseCompanyUserTime fsUserCourseCompanyUserTime);
+
+    /**
+     * 新增营期课程-销售课程时间
+     *
+     * @param fsUserCourseCompanyUserTime 营期课程-销售课程时间
+     * @return 结果
+     */
+    int insertFsUserCourseCompanyUserTime(FsUserCourseCompanyUserTime fsUserCourseCompanyUserTime);
+
+    /**
+     * 修改营期课程-销售课程时间
+     *
+     * @param fsUserCourseCompanyUserTime 营期课程-销售课程时间
+     * @return 结果
+     */
+    int updateFsUserCourseCompanyUserTime(FsUserCourseCompanyUserTime fsUserCourseCompanyUserTime);
+
+    /**
+     * 删除营期课程-销售课程时间
+     *
+     * @param id 营期课程-销售课程时间主键
+     * @return 结果
+     */
+    int deleteFsUserCourseCompanyUserTimeById(Long id);
+
+    /**
+     * 批量删除营期课程-销售课程时间
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsUserCourseCompanyUserTimeByIds(Long[] ids);
+
+    /**
+     * 批量查询记录
+     *
+     * @param list 查询参数列表
+     * @return 结果列表
+     */
+    List<FsUserCourseCompanyUserTime> batchSelectByParams(List<CompanyUserTimeQueryParam> list);
+
+    /**
+     * 批量插入记录
+     *
+     * @param list 待插入记录列表
+     * @return 影响行数
+     */
+    int batchInsert(List<FsUserCourseCompanyUserTime> list);
+
+    /**
+     * 批量更新记录
+     *
+     * @param list 待更新记录列表
+     * @return 影响行数
+     */
+    int batchUpdate(List<FsUserCourseCompanyUserTime> list);
+
+
+}

+ 4 - 0
fs-service/src/main/java/com/fs/course/mapper/FsUserCourseMapper.java

@@ -1,6 +1,8 @@
 package com.fs.course.mapper;
 
 import java.util.List;
+import java.util.Map;
+
 import com.fs.course.domain.FsUserCourse;
 import com.fs.course.param.FsCourseListBySidebarParam;
 import com.fs.course.param.FsUserCourseAddStudyCourseParam;
@@ -258,4 +260,6 @@ public interface FsUserCourseMapper
             "order by course_id asc" +
             "</script> ")
     List<FsCourseListBySidebarVO> getFsCourseListBySidebar(@Param("data") FsCourseListBySidebarParam param);
+
+    List<FsUserCourseParticipationRecordVO> getParticipationRecordByMap(@Param("params") Map<String, Object> params);
 }

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

@@ -4,6 +4,7 @@ import com.fs.course.domain.FsUserCoursePeriod;
 import com.fs.course.param.CompanyRedPacketParam;
 import com.fs.course.vo.FsUserCoursePeriodVO;
 import com.fs.course.vo.PeriodRedPacketVO;
+import org.apache.ibatis.annotations.MapKey;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.apache.ibatis.annotations.Update;
@@ -118,7 +119,7 @@ public interface FsUserCoursePeriodMapper
      * 开营
      * @param now   当前日期
      */
-    @Update("update fs_user_course_period set period_status = 2, update_time = now() where period_status = 1 and period_starting_time >= #{now}")
+    @Update("update fs_user_course_period set period_status = 2, update_time = now() where period_status = 1 and period_starting_time <= #{now}")
     void startPeriod(@Param("now") LocalDate now);
 
     /**
@@ -127,4 +128,12 @@ public interface FsUserCoursePeriodMapper
      */
     @Update("update fs_user_course_period set period_status = 3, update_time = now() where period_status = 2 and period_end_time < #{now}")
     void endPeriod(@Param("now") LocalDate now);
+
+
+    @Select("select * from fs_user_course_period where find_in_set(${companyId},company_id) and #{previousDay} >= period_starting_time and #{previousDay} <= period_end_time ")
+    List<Long> queryPeriod(@Param("companyId") Long companyId,
+                           @Param("previousDay") LocalDate previousDay);
+
+    List<FsUserCoursePeriod> selectPeriodListByTrainingCampIds(@Param("trainingCampIds") Long[] trainingCampIds);
+
 }

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

@@ -193,4 +193,6 @@ public interface FsUserCourseVideoMapper
             "order by v.video_id asc " +
             "</script>")
     List<FsCourseVideoListBySidebarVO> getFsCourseVideoListBySidebar(@Param("data") FsCourseListBySidebarParam param);
+
+    List<FsUserCourseVideoPageListVO> selectFsUserCourseVideoListByMap(@Param("params") Map<String, Object> params);
 }

+ 25 - 0
fs-service/src/main/java/com/fs/course/param/CompanyUserTimeQueryParam.java

@@ -0,0 +1,25 @@
+package com.fs.course.param;
+
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+@Data
+public class CompanyUserTimeQueryParam {
+
+    /** 营期ID */
+    @Excel(name = "营期ID")
+    private Long periodId;
+
+    /** 课程ID */
+    @Excel(name = "课程ID")
+    private Long courseId;
+
+    /** 视频ID */
+    @Excel(name = "视频ID")
+    private Long videoId;
+
+    /** 销售id */
+    @Excel(name = "销售id")
+    private Long companyUserId;
+
+}

+ 8 - 1
fs-service/src/main/java/com/fs/course/param/FsCourseLinkCreateParam.java

@@ -1,6 +1,6 @@
 package com.fs.course.param;
 
-import com.fs.his.param.BaseParam;
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import java.util.Date;
@@ -30,5 +30,12 @@ public class FsCourseLinkCreateParam {
 
     private Date sendTime;
 
+    @ApiModelProperty(value = "链接有效时长(分钟)")
+    private Integer effectiveDuration;
+
+    private Long periodId;
+
+    @ApiModelProperty(value = "营期课程id")
+    private Long id;
 
 }

+ 40 - 0
fs-service/src/main/java/com/fs/course/param/FsWatchCourseTimeParam.java

@@ -0,0 +1,40 @@
+package com.fs.course.param;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@ApiModel(description = "销售设置课程时间-入参")
+public class FsWatchCourseTimeParam {
+
+    @ApiModelProperty(value = "营期id", required = true)
+    private Long periodId;
+
+    @ApiModelProperty(value = "课程id", required = true)
+    private Long courseId;
+
+    @ApiModelProperty(value = "视频id", required = true)
+    private Long videoId;
+
+    @ApiModelProperty(value = "公司id,可以不传")
+    private Long companyId;
+
+    @ApiModelProperty(value = "销售id,可以不传")
+    private Long companyUserId;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "开始时间")
+    private Date startDateTime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @ApiModelProperty(value = "结束时间")
+    private Date endDateTime;
+//
+//    @ApiModelProperty(value = "营期课程id")
+//    private Long id;
+
+}

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

@@ -29,6 +29,9 @@ public class UserCourseVideoPageParam implements Serializable {
     @ApiModelProperty(value = "公司id")
     private Long companyId;
 
+    @ApiModelProperty(value = "销售id")
+    private Long companyUserId;
+
     private String corpId;
 
     private String qwUserId;

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

@@ -75,4 +75,8 @@ public interface IFsCourseRedPacketLogService
      * @return amount
      */
     BigDecimal getSumByCompanyUserIdId(Long companyUserId);
+
+    int getCountByCompanyUserIdId(Long userId);
+
+    BigDecimal getNewVipRedPackAmountByCompanyUserIdId(Long userId);
 }

+ 62 - 0
fs-service/src/main/java/com/fs/course/service/IFsUserCourseCompanyUserTimeService.java

@@ -0,0 +1,62 @@
+package com.fs.course.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.course.domain.FsUserCourseCompanyUserTime;
+
+import java.util.List;
+
+/**
+ * 营期课程-销售课程时间Service接口
+ * 
+ * @author fs
+ * @date 2025-06-09
+ */
+public interface IFsUserCourseCompanyUserTimeService extends IService<FsUserCourseCompanyUserTime>{
+    /**
+     * 查询营期课程-销售课程时间
+     * 
+     * @param id 营期课程-销售课程时间主键
+     * @return 营期课程-销售课程时间
+     */
+    FsUserCourseCompanyUserTime selectFsUserCourseCompanyUserTimeById(Long id);
+
+    /**
+     * 查询营期课程-销售课程时间列表
+     * 
+     * @param fsUserCourseCompanyUserTime 营期课程-销售课程时间
+     * @return 营期课程-销售课程时间集合
+     */
+    List<FsUserCourseCompanyUserTime> selectFsUserCourseCompanyUserTimeList(FsUserCourseCompanyUserTime fsUserCourseCompanyUserTime);
+
+    /**
+     * 新增营期课程-销售课程时间
+     * 
+     * @param fsUserCourseCompanyUserTime 营期课程-销售课程时间
+     * @return 结果
+     */
+    int insertFsUserCourseCompanyUserTime(FsUserCourseCompanyUserTime fsUserCourseCompanyUserTime);
+
+    /**
+     * 修改营期课程-销售课程时间
+     * 
+     * @param fsUserCourseCompanyUserTime 营期课程-销售课程时间
+     * @return 结果
+     */
+    int updateFsUserCourseCompanyUserTime(FsUserCourseCompanyUserTime fsUserCourseCompanyUserTime);
+
+    /**
+     * 批量删除营期课程-销售课程时间
+     * 
+     * @param ids 需要删除的营期课程-销售课程时间主键集合
+     * @return 结果
+     */
+    int deleteFsUserCourseCompanyUserTimeByIds(Long[] ids);
+
+    /**
+     * 删除营期课程-销售课程时间信息
+     * 
+     * @param id 营期课程-销售课程时间主键
+     * @return 结果
+     */
+    int deleteFsUserCourseCompanyUserTimeById(Long id);
+}

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

@@ -1,6 +1,9 @@
 package com.fs.course.service;
 
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.List;
+import java.util.Map;
 
 import com.fs.common.core.domain.R;
 import com.fs.course.domain.FsUserCourse;
@@ -107,4 +110,12 @@ public interface IFsUserCourseService
     void  processQwSopCourseMaterialTimer();
 
     List<FsCourseListBySidebarVO> getFsCourseListBySidebar(FsCourseListBySidebarParam param);
+
+    List<FsUserCourseParticipationRecordVO> getParticipationRecordByMap(Map<String, Object> params);
+
+    R createCourseSortLink(FsCourseLinkCreateParam fsCourseLinkCreateParam);
+
+    InputStream handleImage(String s, String path) throws IOException;
+
+    String createCourseImageQR(String url, String backgroundImagePath, InputStream file, String outputFormat, String title, String duration) throws Exception;
 }

+ 4 - 0
fs-service/src/main/java/com/fs/course/service/IFsUserCourseVideoService.java

@@ -170,4 +170,8 @@ public interface IFsUserCourseVideoService
      * @return
      */
     R isAllowAnswer(FsUserCourseVideoFinishUParam param);
+
+    List<FsUserCourseVideoPageListVO> selectCourseVideoListByMap(Map<String, Object> params);
+
+    ResponseResult<Boolean> setWatchCourseTime(List<FsWatchCourseTimeParam> collect);
 }

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

@@ -126,4 +126,20 @@ public class FsCourseRedPacketLogServiceImpl implements IFsCourseRedPacketLogSer
     public BigDecimal getSumByCompanyUserIdId(Long companyUserId) {
         return null;
     }
+
+    @Override
+    public int getCountByCompanyUserIdId(Long companyUserId) {
+        return fsCourseRedPacketLogMapper.getCountByCompanyUserIdId(companyUserId);
+    }
+
+    /**
+     * 查询新用户红包金额总和
+     * @param companyUserId 销售ID
+     * @return amount
+     */
+    @Override
+    public BigDecimal getNewVipRedPackAmountByCompanyUserIdId(Long companyUserId) {
+        return fsCourseRedPacketLogMapper.getNewVipRedPackAmountByCompanyUserIdId(companyUserId);
+    }
+
 }

+ 94 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseCompanyUserTimeServiceImpl.java

@@ -0,0 +1,94 @@
+package com.fs.course.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.utils.DateUtils;
+import com.fs.course.domain.FsUserCourseCompanyUserTime;
+import com.fs.course.mapper.FsUserCourseCompanyUserTimeMapper;
+import com.fs.course.service.IFsUserCourseCompanyUserTimeService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 营期课程-销售课程时间Service业务层处理
+ *
+ * @author fs
+ * @date 2025-06-09
+ */
+@Service
+public class FsUserCourseCompanyUserTimeServiceImpl extends ServiceImpl<FsUserCourseCompanyUserTimeMapper, FsUserCourseCompanyUserTime> implements IFsUserCourseCompanyUserTimeService {
+
+    /**
+     * 查询营期课程-销售课程时间
+     *
+     * @param id 营期课程-销售课程时间主键
+     * @return 营期课程-销售课程时间
+     */
+    @Override
+    public FsUserCourseCompanyUserTime selectFsUserCourseCompanyUserTimeById(Long id)
+    {
+        return baseMapper.selectFsUserCourseCompanyUserTimeById(id);
+    }
+
+    /**
+     * 查询营期课程-销售课程时间列表
+     *
+     * @param fsUserCourseCompanyUserTime 营期课程-销售课程时间
+     * @return 营期课程-销售课程时间
+     */
+    @Override
+    public List<FsUserCourseCompanyUserTime> selectFsUserCourseCompanyUserTimeList(FsUserCourseCompanyUserTime fsUserCourseCompanyUserTime)
+    {
+        return baseMapper.selectFsUserCourseCompanyUserTimeList(fsUserCourseCompanyUserTime);
+    }
+
+    /**
+     * 新增营期课程-销售课程时间
+     *
+     * @param fsUserCourseCompanyUserTime 营期课程-销售课程时间
+     * @return 结果
+     */
+    @Override
+    public int insertFsUserCourseCompanyUserTime(FsUserCourseCompanyUserTime fsUserCourseCompanyUserTime)
+    {
+        fsUserCourseCompanyUserTime.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertFsUserCourseCompanyUserTime(fsUserCourseCompanyUserTime);
+    }
+
+    /**
+     * 修改营期课程-销售课程时间
+     *
+     * @param fsUserCourseCompanyUserTime 营期课程-销售课程时间
+     * @return 结果
+     */
+    @Override
+    public int updateFsUserCourseCompanyUserTime(FsUserCourseCompanyUserTime fsUserCourseCompanyUserTime)
+    {
+        fsUserCourseCompanyUserTime.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateFsUserCourseCompanyUserTime(fsUserCourseCompanyUserTime);
+    }
+
+    /**
+     * 批量删除营期课程-销售课程时间
+     *
+     * @param ids 需要删除的营期课程-销售课程时间主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsUserCourseCompanyUserTimeByIds(Long[] ids)
+    {
+        return baseMapper.deleteFsUserCourseCompanyUserTimeByIds(ids);
+    }
+
+    /**
+     * 删除营期课程-销售课程时间信息
+     *
+     * @param id 营期课程-销售课程时间主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsUserCourseCompanyUserTimeById(Long id)
+    {
+        return baseMapper.deleteFsUserCourseCompanyUserTimeById(id);
+    }
+}

+ 25 - 3
fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodDaysServiceImpl.java

@@ -296,9 +296,24 @@ public class FsUserCoursePeriodDaysServiceImpl extends ServiceImpl<FsUserCourseP
     public R updateCourseTime(UpdateCourseTimeVo vo) {
         List<FsUserCoursePeriodDays> list = fsUserCoursePeriodDaysMapper.selectBatchIds(vo.getIds());
         list.forEach(day -> {
-            day.setStartDateTime(LocalDateTime.of(day.getDayDate(), vo.getStartTime()));
-            day.setEndDateTime(LocalDateTime.of(day.getDayDate(), vo.getEndTime1()));
-            day.setLastJoinTime(LocalDateTime.of(day.getDayDate(), vo.getJoinTime()));
+//            day.setStartDateTime(LocalDateTime.of(day.getDayDate(), vo.getStartTime()));
+//            day.setEndDateTime(LocalDateTime.of(day.getDayDate(), vo.getEndTime1()));
+//            day.setLastJoinTime(LocalDateTime.of(day.getDayDate(), vo.getJoinTime()));
+            // 调整时间为直接接收前端传入的年月日,不使用营期的日期(2025年6月11日 10点41分)
+            day.setStartDateTime(vo.getStartTime());
+            day.setEndDateTime(vo.getEndTime1());
+            day.setLastJoinTime(vo.getJoinTime());
+            // 把营期时间改成开始时间
+            day.setDayDate(vo.getStartTime().toLocalDate());
+            // 设置状态
+            LocalDateTime compareDayTime = LocalDateTime.now();
+            if(compareDayTime.isAfter(day.getStartDateTime()) && compareDayTime.isBefore(day.getEndDateTime())){
+                day.setStatus(1);
+            } else if(compareDayTime.isBefore(day.getStartDateTime())){
+                day.setStatus(0);
+            } else {
+                day.setStatus(2);
+            }
             fsUserCoursePeriodDaysMapper.updateById(day);
         });
         return R.ok();
@@ -313,6 +328,13 @@ public class FsUserCoursePeriodDaysServiceImpl extends ServiceImpl<FsUserCourseP
         day.setStartDateTime(LocalDateTime.of(day.getDayDate(), day.getStartDateTime().toLocalTime()));
         day.setEndDateTime(LocalDateTime.of(day.getDayDate(), day.getEndDateTime().toLocalTime()));
         day.setLastJoinTime(LocalDateTime.of(day.getDayDate(), day.getLastJoinTime().toLocalTime()));
+        // 默认开启今天及以后的两天,为进行中
+        LocalDate compareDay = LocalDate.now().plusDays(1);
+        if(day.getDayDate().isBefore(compareDay)){
+            day.setStatus(1);
+        } else {
+            day.setStatus(0);
+        }
         updateById(day);
         return R.ok();
     }

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

@@ -146,10 +146,10 @@ public class FsUserCoursePeriodServiceImpl implements IFsUserCoursePeriodService
 
         // 修改大于当前时间的课程状态
         Wrapper<FsUserCoursePeriodDays> updateWrapper = Wrappers.<FsUserCoursePeriodDays>lambdaUpdate()
-        .set(FsUserCoursePeriodDays::getStatus, 2)
-        .eq(FsUserCoursePeriodDays::getPeriodId, fsUserCoursePeriod.getPeriodId())
-        .eq(FsUserCoursePeriodDays::getStatus, 0)
-        .gt(FsUserCoursePeriodDays::getDayDate, LocalDate.now());
+                .set(FsUserCoursePeriodDays::getStatus, 2)
+                .eq(FsUserCoursePeriodDays::getPeriodId, fsUserCoursePeriod.getPeriodId())
+                .eq(FsUserCoursePeriodDays::getStatus, 0)
+                .gt(FsUserCoursePeriodDays::getDayDate, LocalDate.now());
         fsUserCoursePeriodDaysMapper.update(null, updateWrapper);
     }
 

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

@@ -1,22 +1,26 @@
 package com.fs.course.service.impl;
 
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.net.URL;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Iterator;
+import java.net.URLConnection;
+import java.util.*;
 import java.util.List;
 
 import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.utils.DateUtils;
-import com.fs.course.domain.FsUserCourseStudy;
-import com.fs.course.domain.FsUserCourseStudyLog;
-import com.fs.course.domain.FsUserCourseVideo;
+import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.CompanyTag;
+import com.fs.company.mapper.CompanyTagMapper;
+import com.fs.company.mapper.CompanyUserMapper;
+import com.fs.course.config.CourseConfig;
+import com.fs.course.domain.*;
 import com.fs.course.mapper.*;
 import com.fs.course.param.*;
 import com.fs.course.param.newfs.FsUserCourseListParam;
@@ -35,14 +39,21 @@ import com.fs.qwApi.Result.QwUploadResult;
 import com.fs.qwApi.service.QwApiService;
 import com.fs.system.service.ISysConfigService;
 import com.fs.voice.utils.StringUtil;
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.EncodeHintType;
+import com.google.zxing.client.j2se.MatrixToImageWriter;
+import com.google.zxing.common.BitMatrix;
+import com.google.zxing.qrcode.QRCodeWriter;
 import lombok.extern.slf4j.Slf4j;
 import org.checkerframework.checker.units.qual.A;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import com.fs.course.domain.FsUserCourse;
 import com.fs.course.service.IFsUserCourseService;
 import org.springframework.transaction.annotation.Transactional;
 
+import javax.imageio.ImageIO;
+
 /**
  * 课程Service业务层处理
  *
@@ -53,9 +64,19 @@ import org.springframework.transaction.annotation.Transactional;
 @Slf4j
 public class FsUserCourseServiceImpl implements IFsUserCourseService
 {
+    @Autowired
+    private CompanyTagMapper companyTagMapper;
     @Autowired
     private FsUserCourseMapper fsUserCourseMapper;
     @Autowired
+    private CompanyUserMapper companyUserMapper;
+    @Autowired
+    private FsCourseLinkMapper fsCourseLinkMapper;
+    @Autowired
+    private FsCourseAnswerLogsMapper fsCourseAnswerLogsMapper;
+    @Autowired
+    private FsCourseWatchLogMapper fsCourseWatchLogMapper;
+    @Autowired
     private FsUserCourseCommentMapper fsUserCourseCommentMapper;
     @Autowired
     private FsUserCourseNoteMapper fsUserCourseNoteMapper;
@@ -82,7 +103,9 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
 
     @Autowired
     private RedisCache redisCache;
-
+    private static final String realLink = "/courseH5/pages/course/learning?course=";
+    private static final String shortLink = "/courseH5/pages/course/learning?s=";
+    private static final String userRealLink = "/pages/user/users/becomeVIP?";
     /**
      * 查询课程
      *
@@ -434,6 +457,180 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
         return  fsUserCourseMapper.getFsCourseListBySidebar(param);
     }
 
+    @Override
+    public List<FsUserCourseParticipationRecordVO> getParticipationRecordByMap(Map<String, Object> params) {
+        List<FsUserCourseParticipationRecordVO> list = fsUserCourseMapper.getParticipationRecordByMap(params);
+        list.forEach(recordVO -> {
+            List<CompanyTag> companyTags = companyTagMapper.selectCompanyTagListByUserId(recordVO.getUserId());
+            recordVO.setTags(companyTags);
+
+            Map<String, Object> sumMap = fsCourseWatchLogMapper.selectSumByUserIdAndVideoId(recordVO.getUserId(), recordVO.getVideoId());
+            // 观看次数
+            recordVO.setWatchCount((Long) sumMap.getOrDefault("watchCount", 0L));
+
+            // 完播次数
+            recordVO.setFinishCount((Long) sumMap.getOrDefault("finishCount", 0L));
+
+            // 观看时长
+            recordVO.setWatchTime((BigDecimal) sumMap.getOrDefault("watchTime", BigDecimal.ZERO));
+
+            // 领取状态
+            Long count = fsCourseAnswerLogsMapper.selectRedStatus(recordVO.getUserId(), recordVO.getVideoId());
+            if (Objects.nonNull(count) && count > 0) {
+                recordVO.setRedStatus(1);
+            } else {
+                recordVO.setRedStatus(0);
+            }
+        });
+        return list;
+    }
+
+    @Override
+    public R createCourseSortLink(FsCourseLinkCreateParam param) {
+        String json = configService.selectConfigByKey("h5.course.config");
+        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
+
+        //新增链接表信息
+        FsCourseLink link = new FsCourseLink();
+        BeanUtils.copyProperties(param, link);
+        link.setLinkType(0);
+        link.setIsRoom(0);
+
+        FsCourseRealLink courseMap = new FsCourseRealLink();
+        BeanUtils.copyProperties(link, courseMap);
+        String courseJson = JSON.toJSONString(courseMap);
+
+        link.setRealLink(realLink + courseJson);
+        String random = generateRandomString();
+        link.setLink(random);
+        link.setCreateTime(new Date());
+
+        //获取过期时间
+        Calendar calendar = getExpireDay(param, config, link.getCreateTime());
+        link.setUpdateTime(calendar.getTime());
+        int i = fsCourseLinkMapper.insertFsCourseLink(link);
+        if (i > 0){
+            String domainName = getDomainName(param.getCompanyUserId(), config);
+            String sortLink = domainName + shortLink + link.getLink();
+            return R.ok().put("url", sortLink).put("link", random);
+        }
+        return R.error("生成链接失败!");
+    }
+
+    @Override
+    public InputStream handleImage(String url, String path) throws IOException {
+        InputStream inputstream = null;
+        if(StringUtils.isNotEmpty(url)){
+            URL newUrl = new URL(url);
+            URLConnection connection = newUrl.openConnection();
+            // 设置用户代理,避免被服务器拒绝
+            connection.setRequestProperty("User-Agent", "Mozilla/5.0");
+            inputstream = connection.getInputStream();
+        } else {
+            File file = new File(path);
+            try{
+                inputstream = new FileInputStream(file);
+            } catch (FileNotFoundException e) {
+                e.printStackTrace();
+                log.error("获取本地路径失败:{}", path);
+            }
+        }
+        log.info("头像/logo路径, url:{}, path:{}", url, path);
+        return inputstream;
+    }
+
+    @Override
+    public String createCourseImageQR(String url, String backgroundImagePath, InputStream file,
+                                      String outputFormat, String title, String duration) throws Exception {
+        // 读取并缩放背景图片
+        BufferedImage backgroundImage = createScaledBackgroundImage(backgroundImagePath);
+        int scaledWidth = backgroundImage.getWidth();
+        int scaledHeight = backgroundImage.getHeight();
+
+        // 创建最终的合成图片,确保底部区域有足够空间
+        int bottomHeight = 200; // 增加底部区域高度,确保内容完全显示
+        int totalHeight = scaledHeight + bottomHeight;
+        BufferedImage combined = new BufferedImage(scaledWidth, totalHeight, BufferedImage.TYPE_INT_ARGB);
+        Graphics2D graphics = initializeGraphics(combined);
+
+        // 绘制背景和底部白色区域
+        graphics.drawImage(backgroundImage, 0, 0, null);
+        graphics.setColor(Color.WHITE);
+        graphics.fillRect(0, scaledHeight, scaledWidth, bottomHeight);
+
+        // 绘制推荐区域(图片和文字)
+        drawRecommendationArea(graphics, file, scaledHeight, "云联融智", "为您推荐");
+
+        // 绘制二维码
+        drawQRCode(graphics, url, scaledWidth, totalHeight);
+
+        // 绘制标题和时长
+        drawTitleAndDuration(graphics, title, duration, scaledHeight);
+
+        graphics.dispose();
+
+        // 转换为Base64
+        return convertToBase64(combined, outputFormat);
+    }
+
+    private Graphics2D initializeGraphics(BufferedImage combined) {
+        Graphics2D graphics = combined.createGraphics();
+        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+        graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+        graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
+        return graphics;
+    }
+
+    private BufferedImage createScaledBackgroundImage(String backgroundImagePath) throws IOException {
+        // 设置固定的目标尺寸
+        final int TARGET_WIDTH = 600;
+        final int TARGET_HEIGHT = 300; // 固定背景图片高度为300像素
+
+        URL imagePath = new URL(backgroundImagePath);
+        BufferedImage originalBackground = ImageIO.read(imagePath);
+
+        // 计算缩放比例,以高度为基准
+        double scale = (double) TARGET_HEIGHT / originalBackground.getHeight();
+        int scaledWidth = (int) (originalBackground.getWidth() * scale);
+
+        // 创建固定大小的背景图片
+        BufferedImage backgroundImage = new BufferedImage(TARGET_WIDTH, TARGET_HEIGHT, BufferedImage.TYPE_INT_ARGB);
+        Graphics2D g2d = backgroundImage.createGraphics();
+        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
+
+        // 计算居中位置
+        int x = (TARGET_WIDTH - scaledWidth) / 2;
+
+        // 绘制缩放后的图片
+        g2d.drawImage(originalBackground, x, 0, scaledWidth, TARGET_HEIGHT, null);
+        g2d.dispose();
+
+        return backgroundImage;
+    }
+    private String getDomainName(Long companyUserId, CourseConfig config){
+        String domainName = companyUserMapper.selectDomainByUserId(companyUserId);
+        if (StringUtils.isEmpty(domainName)){
+            domainName = config.getRealLinkDomainName();
+        }
+        return domainName;
+    }
+    public static String generateRandomString() {
+        return FsCourseLinkServiceImpl.generateRandomString();
+    }
+    private static Calendar getExpireDay(FsCourseLinkCreateParam param, CourseConfig config, Date createTime) {
+        Integer expireDuration;
+        if (param.getEffectiveDuration() == null || param.getEffectiveDuration() == 0){
+            expireDuration = config.getVideoLinkExpireDate();
+        }else {
+            expireDuration = param.getEffectiveDuration();
+        }
+        // 设置过期时间
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(createTime);
+        calendar.add(Calendar.MINUTE, expireDuration);
+        return calendar;
+    }
     /**
      * 上传课程图片到企业微信并缓存
      *
@@ -522,4 +719,106 @@ public class FsUserCourseServiceImpl implements IFsUserCourseService
         return (lastIndex != -1 && lastIndex + 1 < fileName.length()) ?
                 fileName.substring(lastIndex + 1) : "";
     }
+
+    /**
+     * 绘制推荐区域
+     */
+    private void drawRecommendationArea(Graphics2D graphics, InputStream file, int scaledHeight, String recommendName, String recommendContent) throws IOException {
+        // 读取并绘制推荐图片
+        BufferedImage referenceImg = ImageIO.read(file);
+        int refHeight = 40;
+        int refWidth = 40;
+        int refY = scaledHeight + 20;
+        int refX = 30;
+        graphics.drawImage(referenceImg, refX, refY, refWidth, refHeight, null);
+
+        // 设置并绘制推荐文字
+        Font recommendFont = new Font("微软雅黑", Font.BOLD, 16);
+        graphics.setFont(recommendFont);
+
+        // 绘制"云联融智"
+        int textX = refX + refWidth + 10;
+        int textY = refY + 25;
+        graphics.setColor(new Color(51, 51, 51));
+        graphics.drawString(recommendName, textX, textY);
+
+        // 绘制"为您推荐"
+        FontMetrics metrics = graphics.getFontMetrics(recommendFont);
+        int brandWidth = metrics.stringWidth(recommendName);
+        int textX1 = textX + brandWidth + 5;
+        graphics.setColor(new Color(102, 102, 102));
+        graphics.drawString(recommendContent, textX1, textY);
+//        FontMetrics metrics = graphics.getFontMetrics(recommendFont);
+        int reWidth = metrics.stringWidth(recommendContent);
+    }
+
+
+    /**
+     * 生成二维码图片
+     */
+    private static BufferedImage generateQrCodeImage(String text, int width, int height) throws Exception {
+        QRCodeWriter qrCodeWriter = new QRCodeWriter();
+        Map<EncodeHintType, Object> hints = new HashMap<>();
+        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
+        hints.put(EncodeHintType.MARGIN, 1);
+        BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height, hints);
+        return MatrixToImageWriter.toBufferedImage(bitMatrix);
+    }
+
+    /**
+     * 绘制二维码
+     */
+    private void drawQRCode(Graphics2D graphics, String url, int scaledWidth, int totalHeight) throws Exception {
+        BufferedImage qrCodeImage = generateQrCodeImage(url, 200, 200);
+        int qrSize = 100;
+        int qrMarginRight = 25;
+        int qrMarginBottom = 30;
+        int qrX = scaledWidth - qrSize - qrMarginRight;
+        int qrY = totalHeight - qrSize - qrMarginBottom;
+        graphics.drawImage(qrCodeImage, qrX, qrY, qrSize, qrSize, null);
+    }
+
+    /**
+     * 绘制标题和时长
+     */
+    private void drawTitleAndDuration(Graphics2D graphics, String title, String duration, int scaledHeight) {
+        Font titleFont = new Font("微软雅黑", Font.BOLD, 18);
+        Font descFont = new Font("微软雅黑", Font.PLAIN, 14);
+
+        int contentX = 30;
+        int titleY = scaledHeight + 85;
+        int descY = titleY + 25;
+
+        graphics.setFont(titleFont);
+        graphics.setColor(new Color(51, 51, 51));
+        graphics.drawString(title, contentX, titleY);
+
+        graphics.setFont(descFont);
+        graphics.setColor(new Color(102, 102, 102));
+        if(StringUtils.isNotBlank(duration)){
+            // 将秒转化为分钟
+            BigDecimal bigDecimal = new BigDecimal(duration);
+            bigDecimal = bigDecimal.divide(new BigDecimal(60), 2, RoundingMode.HALF_UP);
+            String minutes = bigDecimal.toString();
+            graphics.drawString("播放时长:" + minutes + "分钟", contentX, descY);
+        } else {
+            graphics.drawString("播放时长:" + "暂无", contentX, descY);
+        }
+
+    }
+
+    /**
+     * 将图片转换为Base64字符串
+     */
+    private String convertToBase64(BufferedImage image, String outputFormat) throws IOException {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        ImageIO.write(image, outputFormat, outputStream);
+        byte[] imageBytes = outputStream.toByteArray();
+        String s = Base64.getEncoder().encodeToString(imageBytes);
+        StringBuilder result = new StringBuilder();
+        if(StringUtils.isNotEmpty(s)){
+            result.append("data:image/png;base64,").append(s);
+        }
+        return result.toString();
+    }
 }

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

@@ -60,6 +60,7 @@ import com.fs.system.service.ISysConfigService;
 import com.fs.voice.utils.StringUtil;
 import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.rocketmq.spring.core.RocketMQTemplate;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -101,6 +102,8 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     @Autowired
     private IFsUserService fsUserService;
     @Autowired
+    private FsUserCourseCompanyUserTimeMapper companyUserTimeMapper;
+    @Autowired
     private RocketMQTemplate rocketMQTemplate;
     @Autowired
     private FsUserCourseStudyLogMapper courseStudyLogMapper;
@@ -1488,6 +1491,83 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             return R.error("系统异常,请稍后重试");
         }
     }
+
+    @Override
+    public List<FsUserCourseVideoPageListVO> selectCourseVideoListByMap(Map<String, Object> params) {
+        return fsUserCourseVideoMapper.selectFsUserCourseVideoListByMap(params);
+    }
+    /**
+     * 生成唯一键
+     */
+    private String getKey(Long periodId, Long courseId, Long videoId, Long companyUserId) {
+        return String.format("%d_%d_%d_%d", periodId, courseId, videoId, companyUserId);
+    }
+
+    @Override
+    public ResponseResult<Boolean> setWatchCourseTime(List<FsWatchCourseTimeParam> paramList) {
+        if (CollectionUtils.isEmpty(paramList)) {
+            return ResponseResult.fail(400, "参数不能为空");
+        }
+
+        // 1. 查询参数
+        List<CompanyUserTimeQueryParam> queryList = paramList.stream()
+                .map(param -> {
+                    CompanyUserTimeQueryParam query = new CompanyUserTimeQueryParam();
+                    query.setPeriodId(param.getPeriodId());
+                    query.setCourseId(param.getCourseId());
+                    query.setVideoId(param.getVideoId());
+                    query.setCompanyUserId(param.getCompanyUserId());
+                    return query;
+                })
+                .collect(Collectors.toList());
+
+        // 2. 批量查询现有的记录
+        List<FsUserCourseCompanyUserTime> existingRecords = companyUserTimeMapper.batchSelectByParams(queryList);
+        Map<String, FsUserCourseCompanyUserTime> existingMap = existingRecords.stream()
+                .collect(Collectors.toMap(record -> getKey(record.getPeriodId(), record.getCourseId(), record.getVideoId(), record.getCompanyUserId()),
+                        record -> record));
+
+        // 3. 分离需要更新和插入的记录
+        List<FsUserCourseCompanyUserTime> toUpdate = new ArrayList<>();
+        List<FsUserCourseCompanyUserTime> toInsert = new ArrayList<>();
+        Date now = DateUtils.getNowDate();
+
+        for (FsWatchCourseTimeParam param : paramList) {
+            String key = getKey(param.getPeriodId(), param.getCourseId(), param.getVideoId(), param.getCompanyUserId());
+            FsUserCourseCompanyUserTime record = existingMap.get(key);
+
+            if (record != null) {
+                // 需要更新
+                record.setStartDateTime(param.getStartDateTime());
+                record.setEndDateTime(param.getEndDateTime());
+                record.setUpdateTime(now);
+                toUpdate.add(record);
+            } else {
+                // 需要插入
+                FsUserCourseCompanyUserTime newRecord = new FsUserCourseCompanyUserTime();
+                newRecord.setPeriodId(param.getPeriodId());
+                newRecord.setCourseId(param.getCourseId());
+                newRecord.setVideoId(param.getVideoId());
+                newRecord.setCompanyUserId(param.getCompanyUserId());
+                newRecord.setCompanyId(param.getCompanyId());
+                newRecord.setStartDateTime(param.getStartDateTime());
+                newRecord.setEndDateTime(param.getEndDateTime());
+                newRecord.setCreateTime(now);
+                toInsert.add(newRecord);
+            }
+        }
+
+        // 4. 执行批量更新和插入
+        if (!toUpdate.isEmpty()) {
+            companyUserTimeMapper.batchUpdate(toUpdate);
+        }
+        if (!toInsert.isEmpty()) {
+            companyUserTimeMapper.batchInsert(toInsert);
+        }
+
+        return ResponseResult.ok();
+    }
+
     /**
      * 获取视频时长(优先从Redis获取,不存在则查数据库)
      */

+ 9 - 3
fs-service/src/main/java/com/fs/course/vo/UpdateCourseTimeVo.java

@@ -1,8 +1,11 @@
 package com.fs.course.vo;
 
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.Data;
 
 import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.util.List;
 
@@ -11,8 +14,11 @@ public class UpdateCourseTimeVo {
 
     private List<Long> ids;
     private Long id;
-    private LocalTime startTime;
-    private LocalTime endTime1;
-    private LocalTime joinTime;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime startTime;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime endTime1;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime joinTime;
     private LocalDate dayDate;
 }

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

@@ -33,6 +33,7 @@ public class FsUser extends BaseEntity
     private String password;
     private String realName;
     private Long birthday;
+    /** 用户昵称 */
     private String idCard;
 
     /** 用户昵称 */
@@ -152,4 +153,23 @@ public class FsUser extends BaseEntity
 
     private Long qwExtId;
 
+    public void setNickName(String nickname)
+    {
+        if(StringUtils.isNotEmpty(nickname)){
+            this.nickName= EmojiParser.parseToHtmlDecimal(nickname);
+        }
+        else{
+            this.nickName= nickname;
+        }
+    }
+
+    public String getNickName()
+    {
+        if(StringUtils.isNotEmpty(nickName)){
+            return EmojiParser.parseToUnicode(nickName);
+        }
+        else{
+            return nickName;
+        }
+    }
 }

+ 12 - 0
fs-service/src/main/java/com/fs/his/mapper/FsStoreOrderMapper.java

@@ -1069,4 +1069,16 @@ public interface FsStoreOrderMapper
     List<FsStoreOrder> selectFsStoreOrderByOrderIdIn(@Param("ids") List<Long> ids);
 
     List<FsStoreOrder> selectFsStoreOrderStatisticsByUserId(@Param("ids") List<Long> ids);
+
+    @Select({"<script> " +
+            "select ifnull(count(1),0) from fs_store_order o  " +
+            "where o.company_id=#{companyId} and company_user_id=#{userId} " +
+            "<if test = 'type==1   '> " +
+            " AND date_format(o.create_time,'%y%m%d') = date_format(now(),'%y%m%d') " +
+            "</if>" +
+            "<if test = 'type==2   '> " +
+            " AND o.status=0 " +
+            "</if>" +
+            "</script>"})
+    Integer selectFsStoreOrderCountByType(@Param("companyId") Long companyId,@Param("userId") long userId, @Param("type")int type);
 }

+ 57 - 0
fs-service/src/main/java/com/fs/his/mapper/FsStorePaymentMapper.java

@@ -255,4 +255,61 @@ public interface FsStorePaymentMapper
             " ORDER BY payment_id desc  "+
             "</script>"})
     Long selectFsStorePaymentExcelVOCount(@Param("maps") FsStorePaymentParam fsStorePayment);
+
+    @Select({"<script> " +
+            "select p.*,c.company_name,d.dept_name,u.phone as user_phone,cu.nick_name as company_user_nick_name,cu.user_name as company_user_name  from fs_store_payment p left join company_user cu on p.company_user_id=cu.user_id left join fs_user u on u.user_id=p.user_id left join company_dept d on d.dept_id=p.dept_id left join company c on c.company_id=p.company_id  " +
+            "where 1=1 " +
+            "<if test = 'maps.payCode != null and  maps.payCode !=\"\"    '> " +
+            "and p.pay_code like CONCAT('%',#{maps.payCode},'%') " +
+            "</if>" +
+            "<if test = 'maps.mobile != null and  maps.mobile !=\"\"     '> " +
+            "and u.phone like CONCAT('%',#{maps.mobile},'%') " +
+            "</if>" +
+            "<if test = 'maps.bankTransactionId != null and  maps.bankTransactionId !=\"\"     '> " +
+            "and p.bank_transaction_id like CONCAT('%',#{maps.bankTransactionId},'%') " +
+            "</if>" +
+            "<if test = 'maps.bankSerialNo != null and  maps.bankSerialNo !=\"\"     '> " +
+            "and p.bank_serial_no like CONCAT('%',#{maps.bankSerialNo},'%') " +
+            "</if>" +
+            "<if test = 'maps.businessType != null    '> " +
+            "and p.business_type =#{maps.businessType} " +
+            "</if>" +
+            "<if test = 'maps.userId != null    '> " +
+            "and p.user_id =#{maps.userId} " +
+            "</if>" +
+            "<if test = 'maps.status != null    '> " +
+            "and p.status =#{maps.status} " +
+            "</if>" +
+            "<if test = 'maps.companyId != null    '> " +
+            "and p.company_id =#{maps.companyId} " +
+            "</if>" +
+            "<if test = 'maps.companyUserNickName != null and  maps.companyUserNickName !=\"\"     '> " +
+            "and cu.nick_name like CONCAT('%',#{maps.companyUserNickName},'%') " +
+            "</if>" +
+            "<if test = 'maps.createTime != null    '> " +
+            "and DATE_FORMAT(p.create_time,'%Y-%m-%d') = DATE_FORMAT(#{maps.createTime},'%Y-%m-%d')  " +
+            "</if>" +
+
+            "<if test = 'maps.beginTime != null and maps.beginTime != \"\"   '> " +
+            " AND date_format(p.pay_time,'%y%m%d') &gt;= date_format(#{maps.beginTime},'%y%m%d') " +
+            "</if>" +
+            "<if test = 'maps.endTime != null and maps.endTime != \"\"   '> " +
+            " AND date_format(p.pay_time,'%y%m%d') &lt;= date_format(#{maps.endTime},'%y%m%d') " +
+            "</if>" +
+
+            "<if test = 'maps.refundBeginTime != null  and maps.refundBeginTime != \"\"    '> " +
+            "and DATE_FORMAT(p.refund_time,'%y%m%d') &gt;= date_format(#{maps.refundBeginTime},'%y%m%d')  " +
+            "</if>" +
+            "<if test = 'maps.refundEndTime != null and maps.refundEndTime != \"\"   '> " +
+            " AND date_format(p.refund_time,'%y%m%d') &lt;= date_format(#{maps.refundEndTime},'%y%m%d') " +
+            "</if>" +
+
+            "<if test = 'maps.deptId != null    '> " +
+            "  AND (p.dept_id = #{maps.deptId} OR p.dept_id IN ( SELECT t.dept_id FROM company_dept t WHERE find_in_set(#{maps.deptId}, ancestors) )) " +
+            "</if>" +
+            " ${maps.params.dataScope} "+
+            " order by p.payment_id desc "+
+            "</script>"})
+    List<FsStorePaymentVO> selectFsStorePaymentListQueryVO(@Param("maps") FsStorePaymentParam fsStorePayment);
+
 }

+ 9 - 1
fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java

@@ -288,4 +288,12 @@ public interface FsUserMapper
      */
     Integer selectFsUserByUserIds(@Param("userIds") String[] userIds, @Param("companyUserId") Long companyUserId);
 
-}
+    /**
+     * 查询销售会员总数,今日新增会员数
+     * @param companyUserId 销售ID
+     * @return map
+     */
+    Map<String, Long> getUserVipCountByCompanyUserId(@Param("companyUserId") Long companyUserId);
+
+    @Select("select * from fs_user where union_id=#{unionId}")
+    FsUser selectFsUserByUnionId(String unionId);}

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä