吴树波 3 viikkoa sitten
commit
9d0a6d8d59
100 muutettua tiedostoa jossa 9709 lisäystä ja 0 poistoa
  1. 57 0
      .gitignore
  2. 8 0
      DirectoryV3.xml
  3. 36 0
      README.en.md
  4. 37 0
      README.md
  5. BIN
      doc.jpg
  6. 141 0
      fs-ad-api/pom.xml
  7. 14 0
      fs-ad-api/src/main/java/com/fs/FSServletInitializer.java
  8. 25 0
      fs-ad-api/src/main/java/com/fs/FsAdApiApplication.java
  9. 12 0
      fs-ad-api/src/main/java/com/fs/app/annotation/Login.java
  10. 15 0
      fs-ad-api/src/main/java/com/fs/app/annotation/LoginUser.java
  11. 111 0
      fs-ad-api/src/main/java/com/fs/app/controller/AdCallbackController.java
  12. 39 0
      fs-ad-api/src/main/java/com/fs/app/controller/CommonController.java
  13. 215 0
      fs-ad-api/src/main/java/com/fs/app/controller/MockAppController.java
  14. 51 0
      fs-ad-api/src/main/java/com/fs/app/exception/FSException.java
  15. 81 0
      fs-ad-api/src/main/java/com/fs/app/exception/FSExceptionHandler.java
  16. 31 0
      fs-ad-api/src/main/java/com/fs/app/mq/RocketMQAiMsgService.java
  17. 30 0
      fs-ad-api/src/main/java/com/fs/app/mq/RocketMQConsumerService.java
  18. 26 0
      fs-ad-api/src/main/java/com/fs/app/mq/RocketMQConsumerServiceByQw.java
  19. 38 0
      fs-ad-api/src/main/java/com/fs/app/task/Task.java
  20. 182 0
      fs-ad-api/src/main/java/com/fs/framework/aspectj/DataScopeAspect.java
  21. 73 0
      fs-ad-api/src/main/java/com/fs/framework/aspectj/DataSourceAspect.java
  22. 245 0
      fs-ad-api/src/main/java/com/fs/framework/aspectj/LogAspect.java
  23. 117 0
      fs-ad-api/src/main/java/com/fs/framework/aspectj/RateLimiterAspect.java
  24. 31 0
      fs-ad-api/src/main/java/com/fs/framework/config/ApplicationConfig.java
  25. 85 0
      fs-ad-api/src/main/java/com/fs/framework/config/CaptchaConfig.java
  26. 100 0
      fs-ad-api/src/main/java/com/fs/framework/config/DataSourceConfig.java
  27. 123 0
      fs-ad-api/src/main/java/com/fs/framework/config/DruidConfig.java
  28. 72 0
      fs-ad-api/src/main/java/com/fs/framework/config/FastJson2JsonRedisSerializer.java
  29. 59 0
      fs-ad-api/src/main/java/com/fs/framework/config/FilterConfig.java
  30. 76 0
      fs-ad-api/src/main/java/com/fs/framework/config/KaptchaTextCreator.java
  31. 150 0
      fs-ad-api/src/main/java/com/fs/framework/config/MyBatisConfig.java
  32. 121 0
      fs-ad-api/src/main/java/com/fs/framework/config/RedisConfig.java
  33. 65 0
      fs-ad-api/src/main/java/com/fs/framework/config/ResourcesConfig.java
  34. 50 0
      fs-ad-api/src/main/java/com/fs/framework/config/SecurityConfig.java
  35. 33 0
      fs-ad-api/src/main/java/com/fs/framework/config/ServerConfig.java
  36. 121 0
      fs-ad-api/src/main/java/com/fs/framework/config/SwaggerConfig.java
  37. 63 0
      fs-ad-api/src/main/java/com/fs/framework/config/ThreadPoolConfig.java
  38. 77 0
      fs-ad-api/src/main/java/com/fs/framework/config/properties/DruidProperties.java
  39. 27 0
      fs-ad-api/src/main/java/com/fs/framework/datasource/DynamicDataSource.java
  40. 45 0
      fs-ad-api/src/main/java/com/fs/framework/datasource/DynamicDataSourceContextHolder.java
  41. 56 0
      fs-ad-api/src/main/java/com/fs/framework/interceptor/RepeatSubmitInterceptor.java
  42. 126 0
      fs-ad-api/src/main/java/com/fs/framework/interceptor/impl/SameUrlDataInterceptor.java
  43. 56 0
      fs-ad-api/src/main/java/com/fs/framework/manager/AsyncManager.java
  44. 40 0
      fs-ad-api/src/main/java/com/fs/framework/manager/ShutdownManager.java
  45. 103 0
      fs-ad-api/src/main/java/com/fs/framework/manager/factory/AsyncFactory.java
  46. 1 0
      fs-ad-api/src/main/resources/META-INF/spring-devtools.properties
  47. 94 0
      fs-ad-api/src/main/resources/application-dev.yml
  48. 147 0
      fs-ad-api/src/main/resources/application-druid-myhk.yml
  49. 139 0
      fs-ad-api/src/main/resources/application-druid.yml
  50. 132 0
      fs-ad-api/src/main/resources/application.yml
  51. 2 0
      fs-ad-api/src/main/resources/banner.txt
  52. 37 0
      fs-ad-api/src/main/resources/i18n/messages.properties
  53. 93 0
      fs-ad-api/src/main/resources/logback.xml
  54. 15 0
      fs-ad-api/src/main/resources/mybatis/mybatis-config.xml
  55. 119 0
      fs-admin/pom.xml
  56. 26 0
      fs-admin/src/main/java/com/fs/FSApplication.java
  57. 14 0
      fs-admin/src/main/java/com/fs/FSServletInitializer.java
  58. 37 0
      fs-admin/src/main/java/com/fs/ad/controller/AdAccountController.java
  59. 78 0
      fs-admin/src/main/java/com/fs/ad/controller/AdCallbackController.java
  60. 113 0
      fs-admin/src/main/java/com/fs/ad/controller/AdDomainController.java
  61. 103 0
      fs-admin/src/main/java/com/fs/ad/controller/AdHtmlClickLogController.java
  62. 110 0
      fs-admin/src/main/java/com/fs/ad/controller/AdHtmlTemplateController.java
  63. 113 0
      fs-admin/src/main/java/com/fs/ad/controller/AdIqiyiAccountController.java
  64. 106 0
      fs-admin/src/main/java/com/fs/ad/controller/AdSiteController.java
  65. 113 0
      fs-admin/src/main/java/com/fs/ad/controller/AdYoukuAccountController.java
  66. 151 0
      fs-admin/src/main/java/com/fs/ad/controller/BdAccountController.java
  67. 215 0
      fs-admin/src/main/java/com/fs/ad/controller/MockAppController.java
  68. 78 0
      fs-admin/src/main/java/com/fs/ad/controller/StatisticsController.java
  69. 25 0
      fs-admin/src/main/java/com/fs/ad/controller/task/BaiduTask.java
  70. 124 0
      fs-admin/src/main/java/com/fs/chat/controller/ChatDatasetController.java
  71. 166 0
      fs-admin/src/main/java/com/fs/chat/controller/ChatDatasetFileController.java
  72. 86 0
      fs-admin/src/main/java/com/fs/chat/controller/ChatKeywordController.java
  73. 130 0
      fs-admin/src/main/java/com/fs/chat/controller/ChatMsgController.java
  74. 114 0
      fs-admin/src/main/java/com/fs/chat/controller/ChatMsgLogsController.java
  75. 200 0
      fs-admin/src/main/java/com/fs/chat/controller/ChatRoleController.java
  76. 111 0
      fs-admin/src/main/java/com/fs/chat/controller/ChatSessionController.java
  77. 89 0
      fs-admin/src/main/java/com/fs/chat/controller/ChatUploadController.java
  78. 97 0
      fs-admin/src/main/java/com/fs/chat/controller/ChatUserController.java
  79. 112 0
      fs-admin/src/main/java/com/fs/chat/controller/FastGptRoleController.java
  80. 9 0
      fs-admin/src/main/java/com/fs/chat/param/ChatUploadFileCParam.java
  81. 244 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyController.java
  82. 103 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyDeptController.java
  83. 97 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyLogininforController.java
  84. 97 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyMenuController.java
  85. 179 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyMoneyLogsController.java
  86. 97 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyOperLogController.java
  87. 97 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyPostController.java
  88. 276 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyProfitController.java
  89. 97 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyRoleController.java
  90. 97 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyRoleDeptController.java
  91. 97 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyRoleMenuController.java
  92. 98 0
      fs-admin/src/main/java/com/fs/company/controller/CompanySmsController.java
  93. 122 0
      fs-admin/src/main/java/com/fs/company/controller/CompanySmsLogsController.java
  94. 99 0
      fs-admin/src/main/java/com/fs/company/controller/CompanySmsOrderController.java
  95. 97 0
      fs-admin/src/main/java/com/fs/company/controller/CompanySmsPackageController.java
  96. 115 0
      fs-admin/src/main/java/com/fs/company/controller/CompanySmsTempController.java
  97. 634 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyStatisticsController.java
  98. 261 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyTcmReportController.java
  99. 120 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyTcmScheduleController.java
  100. 120 0
      fs-admin/src/main/java/com/fs/company/controller/CompanyUserController.java

+ 57 - 0
.gitignore

@@ -0,0 +1,57 @@
+# Compiled class file
+
+target/
+#resources/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+#logback.xml
+application-druid-rt.yml
+application-druid-yjf.yml
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+*.DS_Store
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+
+#1.配置语法: 以斜杠“/”开头表示目录: 以星号“*”通配多个字符: 以问号“?”通配单个字符 以方括号“[]”包含单个字符的匹配列表: 以叹号“!”表示不忽略(跟踪)匹配到的文件或目录:
+#此外,git 对于 .ignore 配置文件是按行从上到下进行规则匹配的,意味着如果前面的规则匹配的范围更大,则后面的规则将不会生效

+ 8 - 0
DirectoryV3.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?> 
+ <trees>
+     <tree path="/fs-admin/src/main/resources" title="资源目录" extension="" presentableText="" tooltipTitle=""/>
+     <tree path="/fs-admin/src/main/java/com/fs/ad/controller" title="广告"/>
+     <tree path="/fs-admin/src/main/java/com/fs/company/controller" title="公司"/>
+     <tree path="/fs-admin/src/main/java/com/fs/live/controller" title="直播"/>
+     <tree path="/fs-admin/src/main/java/com/fs/qw" title="企微"/>
+ </trees>

+ 36 - 0
README.en.md

@@ -0,0 +1,36 @@
+# his_java
+
+#### Description
+问诊平台
+
+#### Software Architecture
+Software architecture description
+
+#### Installation
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### Instructions
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### Contribution
+
+1.  Fork the repository
+2.  Create Feat_xxx branch
+3.  Commit your code
+4.  Create Pull Request
+
+
+#### Gitee Feature
+
+1.  You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
+2.  Gitee blog [blog.gitee.com](https://blog.gitee.com)
+3.  Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
+4.  The most valuable open source project [GVP](https://gitee.com/gvp)
+5.  The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
+6.  The most popular members  [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

+ 37 - 0
README.md

@@ -0,0 +1,37 @@
+# his_java
+
+#### 介绍
+问诊平台
+
+#### 软件架构
+软件架构说明
+
+
+#### 安装教程
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### 使用说明
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### 参与贡献
+
+1.  Fork 本仓库
+2.  新建 Feat_xxx 分支
+3.  提交代码
+4.  新建 Pull Request
+
+
+#### 特技
+
+1.  使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
+2.  Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
+3.  你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
+4.  [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
+5.  Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
+6.  Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

BIN
doc.jpg


+ 141 - 0
fs-ad-api/pom.xml

@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>fs</artifactId>
+        <groupId>com.fs</groupId>
+        <version>1.1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>fs-ad-api</artifactId>
+    <description>
+       投流接口
+    </description>
+    <dependencies>
+
+        <!-- spring-boot-devtools -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <optional>true</optional> <!-- 表示依赖不会传递 -->
+        </dependency>
+        <!-- swagger2-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+        </dependency>
+
+        <!-- swagger2-UI-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>swagger-bootstrap-ui</artifactId>
+            <version>1.9.3</version>
+        </dependency>
+
+
+        <!-- Mysql驱动包 -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
+        <!-- SpringBoot Web容器 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <!-- SpringBoot 拦截器 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+
+        <!-- 阿里数据库连接池 -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+        </dependency>
+
+        <!-- 验证码 -->
+        <dependency>
+            <groupId>com.github.penggle</groupId>
+            <artifactId>kaptcha</artifactId>
+            <exclusions>
+                <exclusion>
+                    <artifactId>javax.servlet-api</artifactId>
+                    <groupId>javax.servlet</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- 获取系统信息 -->
+        <dependency>
+            <groupId>com.github.oshi</groupId>
+            <artifactId>oshi-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fs</groupId>
+            <artifactId>fs-service</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.tencentyun</groupId>
+            <artifactId>tls-sig-api-v2</artifactId>
+            <version>2.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-websocket</artifactId>
+            <version>5.1.10.RELEASE</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.rocketmq</groupId>
+            <artifactId>rocketmq-spring-boot-starter</artifactId>
+            <version>2.2.3</version>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.1.1.RELEASE</version>
+                <configuration>
+                    <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <version>3.1.0</version>
+                <configuration>
+                    <failOnMissingWebXml>false</failOnMissingWebXml>
+                    <warName>${project.artifactId}</warName>
+                </configuration>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+
+</project>

+ 14 - 0
fs-ad-api/src/main/java/com/fs/FSServletInitializer.java

@@ -0,0 +1,14 @@
+package com.fs;
+
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+
+public class FSServletInitializer extends SpringBootServletInitializer
+{
+    @Override
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
+    {
+        return application.sources(FsAdApiApplication.class);
+    }
+}

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

@@ -0,0 +1,25 @@
+package com.fs;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+/**
+ * 启动程序
+ */
+@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
+@EnableTransactionManagement
+@EnableAsync
+@EnableScheduling
+public class FsAdApiApplication
+{
+    public static void main(String[] args)
+    {
+        // System.setProperty("spring.devtools.restart.enabled", "false");
+        SpringApplication.run(FsAdApiApplication.class, args);
+        System.out.println("ad-api启动成功");
+    }
+}

+ 12 - 0
fs-ad-api/src/main/java/com/fs/app/annotation/Login.java

@@ -0,0 +1,12 @@
+package com.fs.app.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * app登录效验
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Login {
+}

+ 15 - 0
fs-ad-api/src/main/java/com/fs/app/annotation/LoginUser.java

@@ -0,0 +1,15 @@
+package com.fs.app.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 登录用户信息
+ */
+@Target(ElementType.PARAMETER)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface LoginUser {
+
+}

+ 111 - 0
fs-ad-api/src/main/java/com/fs/app/controller/AdCallbackController.java

@@ -0,0 +1,111 @@
+package com.fs.app.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.fs.ad.domain.AdHtmlTemplate;
+import com.fs.ad.domain.AdSite;
+import com.fs.ad.mapper.AdHtmlTemplateMapper;
+import com.fs.ad.service.IAdAccountService;
+import com.fs.ad.service.IAdHtmlClickLogService;
+import com.fs.ad.service.IAdSiteService;
+import com.fs.baidu.api.BaiduApis;
+import com.fs.baidu.service.IBdAccountService;
+import com.fs.baidu.vo.ad.AdBaiduClickCallbackVo;
+import com.fs.baidu.vo.AdClickCallbackVo;
+import com.fs.baidu.vo.ad.AdIqiyiClickCallbackVo;
+import com.fs.baidu.vo.ad.AdYouKuClickCallbackVo;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.common.utils.StringUtils;
+import 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.RestController;
+
+/**
+ * 知识库Controller
+ *
+ * @author fs
+ * @date 2024-04-21
+ */
+@Slf4j
+@AllArgsConstructor
+@RestController
+@RequestMapping("/baidu")
+public class AdCallbackController extends BaseController {
+
+    private final AdHtmlTemplateMapper adHtmlTemplateMapper;
+    private final IAdHtmlClickLogService adHtmlClickLogService;
+    private final BaiduApis baiduApis;
+    private final IBdAccountService bdAccountService;
+    private final IAdSiteService adSiteService;
+    private final IAdAccountService adAccountService;
+
+    //百度-页面点击接口
+//    @GetMapping("/callback")
+//    public R callback(String url, String bdVid, String t, Long id) {
+//        if(id == null || StringUtils.isEmpty(bdVid)) {
+//            return R.ok();
+//        }
+//        adHtmlClickLogService.addLog(url, id, bdVid, t);
+//        return R.ok();
+//    }
+    // 百度点击监听返回接口
+//    @GetMapping("/clickCallback")
+//    public R clickCallback(AdClickCallbackVo vo){
+//        log.info("百度监听地址返回数据:{}", JSON.toJSONString(vo));
+//        adHtmlClickLogService.setLogBaiDu(vo, "67", 0);
+//        return R.ok();
+//    }
+    @GetMapping("/getTemplateByNo")
+    public R getTemplateByNo(String no){
+        AdHtmlTemplate htmlUrl = adHtmlTemplateMapper.selectOne(new QueryWrapper<AdHtmlTemplate>().eq("no", no));
+        if(htmlUrl == null){
+            return R.error("错误编号");
+        }
+        return R.ok().put("data",  htmlUrl);
+    }
+    @GetMapping("/getTemplateById")
+    public R getTemplateById(Long id){
+        AdSite site = adSiteService.getById(id);
+        AdHtmlTemplate htmlUrl = adHtmlTemplateMapper.selectById(site.getTemplateId());
+        if(htmlUrl == null){
+            return R.error("错误编号");
+        }
+        return R.ok().put("site", site).put("data",  htmlUrl);
+    }
+//    @GetMapping("/syncPlan")
+//    public R syncPlan(){
+//        baiduApis.listAccount(1L);
+//        return R.ok();
+//    }
+
+
+    @GetMapping("/baiduClickCallbackApi")
+    public R baiduClickCallbackApi(AdBaiduClickCallbackVo vo){
+        log.info("百度点击监听地址返回数据:{}", JSON.toJSONString(vo));
+        adHtmlClickLogService.setLogBaiDuApi(vo);
+        return R.ok();
+    }
+    @GetMapping("/baiduClickCallback")
+    public R baiduClickCallback(AdBaiduClickCallbackVo vo){
+        log.info("百度监听地址返回数据:{}", JSON.toJSONString(vo));
+        adHtmlClickLogService.setLogBaiDu(vo);
+        return R.ok();
+    }
+    @GetMapping("/youkuClickCallback")
+    public R youkuClickCallback(AdYouKuClickCallbackVo vo){
+        log.info("优酷监听地址返回数据:{}", JSON.toJSONString(vo));
+        adHtmlClickLogService.setLogYouKu(vo);
+        return R.ok();
+    }
+    @GetMapping("/iqiyiClickCallback")
+    public R iqiyiClickCallback(AdIqiyiClickCallbackVo vo){
+        log.info("爱奇艺监听地址返回数据:{}", JSON.toJSONString(vo));
+        adHtmlClickLogService.setLogIqiyi(vo);
+        return R.ok();
+    }
+
+
+}

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

@@ -0,0 +1,39 @@
+package com.fs.app.controller;
+
+
+import com.alibaba.fastjson.JSON;
+import com.fs.ad.enums.AdUploadType;
+import com.fs.ad.service.IAdHtmlClickLogService;
+import com.fs.common.core.domain.R;
+import com.fs.company.service.ICompanyWxChatService;
+import com.fs.qw.vo.AdUploadVo;
+import com.fs.wxUser.service.ICompanyWxUserService;
+import io.swagger.annotations.Api;
+import jdk.nashorn.internal.ir.annotations.Ignore;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.spring.core.RocketMQTemplate;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@Slf4j
+@Api("公共接口")
+@RestController
+@AllArgsConstructor
+@Ignore
+@RequestMapping(value="/app/common")
+public class CommonController {
+    private IAdHtmlClickLogService adHtmlClickLogService;
+    private RocketMQTemplate rocketMQTemplate;
+
+    @GetMapping("/testSend")
+    public R testSend(String id){
+        AdUploadVo build = AdUploadVo.builder().state(id).type(AdUploadType.ADD_WX).build();
+        rocketMQTemplate.syncSend("ad-upload", JSON.toJSONString(build));
+//        adHtmlClickLogService.upload(id, AdUploadType.ADD_WX, e -> {});
+        return R.ok();
+    }
+
+}

+ 215 - 0
fs-ad-api/src/main/java/com/fs/app/controller/MockAppController.java

@@ -0,0 +1,215 @@
+package com.fs.app.controller;
+
+import com.fs.baidu.domain.BdApi;
+import com.fs.baidu.service.IBdApiService;
+import com.fs.baidu.utils.SignService;
+import com.fs.huifuPay.sdk.opps.core.exception.BasePayException;
+import com.fs.huifuPay.sdk.opps.core.utils.HttpClientUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.json.JSONObject;
+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.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+@Slf4j
+@RestController
+@RequestMapping("/baiduBack")
+public class MockAppController {
+    private static final String APPID = "appId";
+    private static final String AUTH_CODE = "authCode";
+    private static final String USERID = "userId";
+    private static final String TIMESTAMP = "timestamp";
+    private static final String SIGNATURE = "signature";
+    private static final String STATE = "state";
+    private static final String ACCESSTOKEN_URL = "https://u.baidu.com/oauth/accessToken";
+
+    @Autowired
+    private IBdApiService bdApiService; // 开发者自定义
+    @Autowired
+    private SignService signService; // 开发者可自定义
+
+    @GetMapping("/callback")
+    public String mockApp(HttpServletRequest request) throws BasePayException {
+
+        // 获取请求参数
+        Map<String, String> params = new HashMap<>();
+        this.fillParams(params, request);
+        log.info("callback: params = {}", JSONObject.valueToString(params));
+        int userIdInt = 0;
+        try {
+            userIdInt = Integer.parseInt(params.get(USERID));
+        } catch (Exception e) {
+            return this.getResponseJson(600011, "参数错误", new Object());
+        }
+        // 对签名内容进行判空
+        if (StringUtils.isBlank(params.get(SIGNATURE))) {
+            return this.getResponseJson(600011, "参数错误", new Object());
+        }
+
+        // 获取应用对应的密钥
+        BdApi app = bdApiService.getAppByAppId(params.get(APPID));
+        String sk = app.getAppSecretKey();
+        // 开发者进行验签
+        // 检查状态码
+//        if (!this.checkState(params.get(APPID), app.getAppUserId(), params.get(STATE))) {
+//            log.info("callback: state check fail");
+//            return this.getResponseJson(600011, "状态码错误", new Object());
+//        }
+
+        // 签名验证
+        if (!this.checkSignature(params, sk)) {
+            log.info("callback: signature check fail");
+            return this.getResponseJson(600011, "签名错误", new Object());
+        }
+
+        // 调用接口换取授权令牌
+        String response = this.getAccessToken(params, sk, userIdInt);
+        log.info("callback:getAccesstoken, response={}", response);
+        String accessToken = null;
+        String refreshToken = null;
+        int uid;
+
+        if (response.length() > 0) {
+            JSONObject res = new JSONObject(response);
+            int code = (int) res.get("code");
+            if (code == 0) {
+                JSONObject data = res.getJSONObject("data");
+                accessToken = (String) data.get("accessToken");
+                // 注释部分为 accessToken 其他信息,各应用开发者酌情使用即可
+                 refreshToken = (String) data.get("refreshToken");
+                String openId = data.getString("openId");
+                int expiresIn = data.getInt("expiresIn");
+                int refreshExpiresIn = data.getInt("refreshExpiresIn");
+                app.setAccessToken(accessToken);
+                app.setRefreshToken(refreshToken);
+                app.setExpiresIn(expiresIn);
+                app.setOpenId(openId);
+                app.setRefreshExpiresIn(refreshExpiresIn);
+                app.setAuthCode(params.get(AUTH_CODE));
+                bdApiService.updateById(app);
+
+                // TODO 相关信息落库处理
+            } else {
+                return this.getResponseJson(600011, "未获取到 access_token", new Object());
+            }
+        }
+        Map<String, String> data = new HashMap<>();
+        data.put("accessToken", accessToken);
+        return this.getResponseJson(0, "success", data);
+    }
+
+    /**
+     * 填充请求参数,开发者可用实体代替map
+     *
+     * @param params
+     * @param request
+     */
+    private void fillParams(Map<String, String> params, HttpServletRequest request) {
+        params.put(APPID, request.getParameter(APPID));
+        params.put(AUTH_CODE, request.getParameter(AUTH_CODE));
+        params.put(USERID, request.getParameter(USERID));
+        params.put(TIMESTAMP, request.getParameter(TIMESTAMP));
+        params.put(SIGNATURE, request.getParameter(SIGNATURE));
+        params.put(STATE, request.getParameter(STATE));
+    }
+
+    /**
+     * 校验状态码是否符合预期
+     *
+     * @param appId  应用ID
+     * @param userId 创建应用的ID
+     * @param state  请求参数中的状态码
+     * @return
+     */
+    private boolean checkState(String appId, Long userId, String state) {
+        // md5util 开发者自行开发即可
+        String newState = md5(appId.concat("_").concat(String.valueOf(userId)));
+        return newState.equals(state);
+    }
+    public static String md5(String input) {
+        try {
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] messageDigest = md.digest(input.getBytes());
+            StringBuilder hexString = new StringBuilder();
+            for (byte b : messageDigest) {
+                String hex = Integer.toHexString(0xff & b);
+                if (hex.length() == 1) {
+                    hexString.append('0');
+                }
+                hexString.append(hex);
+            }
+            return hexString.toString();
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException(e);
+        }
+    }
+    /**
+     * 签名验证方法
+     *
+     * @param params
+     * @param sk
+     * @return
+     */
+    private boolean checkSignature(Map<String, String> params, String sk) {
+        // 获取验签字符串:按key自然排序,拼接成 json 字符串,
+        // 示例:str1 = {"appId": xxxxx, "authCode": xxx, "state": xxx,"timestamp": xxx}
+        TreeMap<String, Object> map = new TreeMap<>();
+        map.put(APPID, params.get(APPID));
+        map.put(AUTH_CODE, params.get(AUTH_CODE));
+        map.put(USERID, params.get(USERID));
+        map.put(STATE, params.get(STATE));
+        map.put(TIMESTAMP, params.get(TIMESTAMP));
+        // 根据上述签名算法对接收到的参数签名
+        String sign = signService.paramsSign(sk, map);
+        log.info("callback: signature = {}", sign);
+        // 判断签名和URL传参签名是否一致
+        return params.get(SIGNATURE).equals(sign);
+    }
+
+    /**
+     * 换取授权令牌
+     *
+     * @param params
+     * @param sk
+     * @param userIdInt 授权账户ID
+     * @return
+     */
+    private String getAccessToken(Map<String, String> params, String sk, int userIdInt) throws BasePayException {
+        Map<String, Object> requestMap = new HashMap<>();
+        requestMap.put(APPID, params.get(APPID));
+        requestMap.put("secretKey", sk);
+        requestMap.put(AUTH_CODE, params.get(AUTH_CODE));
+        requestMap.put("grantType", "access_token");
+        requestMap.put("userId", userIdInt);
+
+        String paramsJson = JSONObject.valueToString(requestMap);
+        // 开发者自行增加异常判断
+        return HttpClientUtils.httpPostJson(ACCESSTOKEN_URL, new HashMap<>(), paramsJson);
+    }
+
+    /**
+     * 封装返回json串
+     *
+     * @param code
+     * @param message
+     * @param data
+     * @return
+     */
+    private String getResponseJson(int code, String message, Object data) {
+        // 封装返回字段的map
+        Map<String, Object> responseMap = new HashMap<>();
+        responseMap.put("code", code);
+        responseMap.put("message", message);
+        responseMap.put("data", data);
+        return JSONObject.valueToString(responseMap);
+    }
+}

+ 51 - 0
fs-ad-api/src/main/java/com/fs/app/exception/FSException.java

@@ -0,0 +1,51 @@
+package com.fs.app.exception;
+
+/**
+ * 自定义异常
+ */
+public class FSException extends RuntimeException {
+	private static final long serialVersionUID = 1L;
+	
+    private String msg;
+    private int code = 500;
+    
+    public FSException(String msg) {
+		super(msg);
+		this.msg = msg;
+	}
+	
+	public FSException(String msg, Throwable e) {
+		super(msg, e);
+		this.msg = msg;
+	}
+	
+	public FSException(String msg, int code) {
+		super(msg);
+		this.msg = msg;
+		this.code = code;
+	}
+	
+	public FSException(String msg, int code, Throwable e) {
+		super(msg, e);
+		this.msg = msg;
+		this.code = code;
+	}
+
+	public String getMsg() {
+		return msg;
+	}
+
+	public void setMsg(String msg) {
+		this.msg = msg;
+	}
+
+	public int getCode() {
+		return code;
+	}
+
+	public void setCode(int code) {
+		this.code = code;
+	}
+	
+	
+}

+ 81 - 0
fs-ad-api/src/main/java/com/fs/app/exception/FSExceptionHandler.java

@@ -0,0 +1,81 @@
+package com.fs.app.exception;
+
+
+
+
+import com.fs.common.core.domain.R;
+import com.fs.common.exception.CustomException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.validation.BindException;
+import org.springframework.validation.FieldError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.NoHandlerFoundException;
+
+
+/**
+ * 异常处理器
+ */
+@RestControllerAdvice
+public class FSExceptionHandler {
+	private Logger logger = LoggerFactory.getLogger(getClass());
+
+	/**
+	 * 处理自定义异常
+	 */
+	@ExceptionHandler(FSException.class)
+	public R handleRRException(FSException e){
+		R r = new R();
+		r.put("code", e.getCode());
+		r.put("msg", e.getMessage());
+
+		return r;
+	}
+
+	@ExceptionHandler(NoHandlerFoundException.class)
+	public R handlerNoFoundException(Exception e) {
+		logger.error(e.getMessage(), e);
+		return R.error(404, "路径不存在,请检查路径是否正确");
+	}
+
+	@ExceptionHandler(DuplicateKeyException.class)
+	public R handleDuplicateKeyException(DuplicateKeyException e){
+		logger.error(e.getMessage(), e);
+		return R.error("数据库中已存在该记录");
+	}
+
+
+	@ExceptionHandler(Exception.class)
+	public R handleException(Exception e){
+		logger.error(e.getMessage(), e);
+		return R.error();
+	}
+	@ExceptionHandler(AccessDeniedException.class)
+	public R handleAccessDeniedException(AccessDeniedException e){
+		logger.error(e.getMessage(), e);
+		return R.error("没有权限");
+	}
+
+	@ExceptionHandler(BindException.class)
+	public R bindExceptionHandler(BindException e) {
+		FieldError error = e.getFieldError();
+		String message = String.format("%s",  error.getDefaultMessage());
+		return R.error(message);
+	}
+
+	@ExceptionHandler(MethodArgumentNotValidException.class)
+	public R exceptionHandler(MethodArgumentNotValidException e) {
+		FieldError error = e.getBindingResult().getFieldError();
+		String message = String.format("%s",  error.getDefaultMessage());
+		return R.error(message);
+	}
+	@ExceptionHandler(CustomException.class)
+	public R handleException(CustomException e){
+
+		return R.error(e.getMessage());
+	}
+}

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

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

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

@@ -0,0 +1,30 @@
+package com.fs.app.mq;
+
+import com.alibaba.fastjson.JSON;
+import com.fs.ad.service.IAdHtmlClickLogService;
+import com.fs.common.utils.StringUtils;
+import com.fs.qw.domain.QwExternalContact;
+import com.fs.qw.vo.AdUploadVo;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+@AllArgsConstructor
+@RocketMQMessageListener(topic = "${rocketmq.consumer.topic}", consumerGroup = "${rocketmq.consumer.group}")
+public class RocketMQConsumerService implements RocketMQListener<String> {
+
+    private final IAdHtmlClickLogService  adHtmlClickLogService;
+
+    @Override
+    public void onMessage(String message) {
+        AdUploadVo adUploadVo = JSON.parseObject(message, AdUploadVo.class);
+        if(adUploadVo == null  || StringUtils.isEmpty(adUploadVo.getState()) || "null".equals(adUploadVo.getState())){
+            return;
+        }
+        adHtmlClickLogService.upload(adUploadVo.getState(), adUploadVo.getType());
+    }
+}

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

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

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

@@ -0,0 +1,38 @@
+package com.fs.app.task;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.fs.ad.domain.AdHtmlClickLog;
+import com.fs.ad.service.IAdHtmlClickLogService;
+import com.fs.ad.service.impl.AdHtmlClickLogServiceImpl;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.common.core.redis.RedisCacheT;
+import com.fs.live.domain.Live;
+import com.fs.live.service.ILiveService;
+import lombok.AllArgsConstructor;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@Component
+@AllArgsConstructor
+public class Task {
+    private RedisCacheT<AdHtmlClickLog> redisCache;
+    private IAdHtmlClickLogService adHtmlClickLogService;
+
+//    @Scheduled(cron = "0/30 * * * * ?")
+    @Scheduled(cron = "0 0/30 * * * ?")
+    public void saveLog() {
+        List<AdHtmlClickLog> list = redisCache.getCacheListByPattern(AdHtmlClickLogServiceImpl.AD_LOG_KEY + "*");
+        list.stream().filter(e -> e.getId() == null).forEach(e -> {
+            String key = AdHtmlClickLogServiceImpl.genKey(e.getVid(), e.getType(), e.getClickType());
+            adHtmlClickLogService.save(e);
+            redisCache.setCacheObject(key, e, LocalDateTime.now().until(e.getLastTime(), ChronoUnit.MINUTES), TimeUnit.MINUTES);
+        });
+        list.stream().filter(e -> e.getId() != null).forEach(e -> adHtmlClickLogService.update(e, new QueryWrapper<AdHtmlClickLog>().eq("vid", e.getVid()).eq("click_type", e.getClickType())));
+    }
+}

+ 182 - 0
fs-ad-api/src/main/java/com/fs/framework/aspectj/DataScopeAspect.java

@@ -0,0 +1,182 @@
+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, "");
+        }
+    }
+}

+ 73 - 0
fs-ad-api/src/main/java/com/fs/framework/aspectj/DataSourceAspect.java

@@ -0,0 +1,73 @@
+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);
+    }
+}

+ 245 - 0
fs-ad-api/src/main/java/com/fs/framework/aspectj/LogAspect.java

@@ -0,0 +1,245 @@
+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;
+    }
+}

+ 117 - 0
fs-ad-api/src/main/java/com/fs/framework/aspectj/RateLimiterAspect.java

@@ -0,0 +1,117 @@
+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();
+    }
+}

+ 31 - 0
fs-ad-api/src/main/java/com/fs/framework/config/ApplicationConfig.java

@@ -0,0 +1,31 @@
+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());
+    }
+}

+ 85 - 0
fs-ad-api/src/main/java/com/fs/framework/config/CaptchaConfig.java

@@ -0,0 +1,85 @@
+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;
+    }
+}

+ 100 - 0
fs-ad-api/src/main/java/com/fs/framework/config/DataSourceConfig.java

@@ -0,0 +1,100 @@
+package com.fs.framework.config;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
+import com.alibaba.druid.util.Utils;
+import com.fs.common.enums.DataSourceType;
+import com.fs.framework.datasource.DynamicDataSource;
+import org.springframework.beans.factory.annotation.Qualifier;
+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;
+
+@Configuration
+public class DataSourceConfig {
+
+    @Bean
+    @ConfigurationProperties(prefix = "spring.datasource.clickhouse")
+    public DataSource clickhouseDataSource() {
+        return new DruidDataSource();
+    }
+
+    @Bean
+    @ConfigurationProperties(prefix = "spring.datasource.mysql.druid.master")
+    public DataSource masterDataSource() {
+        return new DruidDataSource();
+    }
+
+    @Bean
+    @ConfigurationProperties(prefix = "spring.datasource.mysql.druid.slave")
+    public DataSource slaveDataSource() {
+        return new DruidDataSource();
+    }
+
+    @Bean
+    @Primary
+    public DynamicDataSource dataSource(@Qualifier("clickhouseDataSource") DataSource clickhouseDataSource,
+                                        @Qualifier("masterDataSource") DataSource masterDataSource,
+                                        @Qualifier("slaveDataSource") DataSource slaveDataSource) {
+        Map<Object, Object> targetDataSources = new HashMap<>();
+        targetDataSources.put(DataSourceType.MASTER, masterDataSource);
+        targetDataSources.put(DataSourceType.SLAVE, slaveDataSource);
+        targetDataSources.put(DataSourceType.CLICKHOUSE.name(), clickhouseDataSource); // Ensure matching key
+        return new DynamicDataSource(masterDataSource, targetDataSources);
+    }
+
+    /**
+     * 去除监控页面底部的广告
+     */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Bean
+    @ConditionalOnProperty(name = "spring.datasource.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;
+    }
+}

+ 123 - 0
fs-ad-api/src/main/java/com/fs/framework/config/DruidConfig.java

@@ -0,0 +1,123 @@
+//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.druid.master")
+//    public DataSource masterDataSource(DruidProperties druidProperties)
+//    {
+//        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
+//        return druidProperties.dataSource(dataSource);
+//    }
+//
+//    @Bean
+//    @ConfigurationProperties("spring.datasource.druid.slave")
+//    @ConditionalOnProperty(prefix = "spring.datasource.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.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;
+//    }
+//}

+ 72 - 0
fs-ad-api/src/main/java/com/fs/framework/config/FastJson2JsonRedisSerializer.java

@@ -0,0 +1,72 @@
+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);
+    }
+}

+ 59 - 0
fs-ad-api/src/main/java/com/fs/framework/config/FilterConfig.java

@@ -0,0 +1,59 @@
+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;
+    }
+
+}

+ 76 - 0
fs-ad-api/src/main/java/com/fs/framework/config/KaptchaTextCreator.java

@@ -0,0 +1,76 @@
+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();
+    }
+}

+ 150 - 0
fs-ad-api/src/main/java/com/fs/framework/config/MyBatisConfig.java

@@ -0,0 +1,150 @@
+package com.fs.framework.config;
+
+import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
+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();
+//    }
+    @Bean
+    public SqlSessionFactory sqlSessionFactorys(DataSource dataSource) throws Exception
+    {
+        String typeAliasesPackage = env.getProperty("mybatis-plus.typeAliasesPackage");
+        String mapperLocations = env.getProperty("mybatis-plus.mapperLocations");
+        String configLocation = env.getProperty("mybatis-plus.configLocation");
+        typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
+        VFS.addImplClass(SpringBootVFS.class);
+
+        final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
+        sessionFactory.setDataSource(dataSource);
+        sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
+        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
+        sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
+        return sessionFactory.getObject();
+    }
+}

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

@@ -0,0 +1,121 @@
+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;";
+    }
+}

+ 65 - 0
fs-ad-api/src/main/java/com/fs/framework/config/ResourcesConfig.java

@@ -0,0 +1,65 @@
+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);
+    }
+}

+ 50 - 0
fs-ad-api/src/main/java/com/fs/framework/config/SecurityConfig.java

@@ -0,0 +1,50 @@
+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()
+                .anyRequest().authenticated()
+                .and().csrf().disable();
+    }
+
+    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
+    @Override
+    public AuthenticationManager authenticationManagerBean() throws Exception {
+        return super.authenticationManagerBean();
+    }
+
+
+}

+ 33 - 0
fs-ad-api/src/main/java/com/fs/framework/config/ServerConfig.java

@@ -0,0 +1,33 @@
+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();
+    }
+}

+ 121 - 0
fs-ad-api/src/main/java/com/fs/framework/config/SwaggerConfig.java

@@ -0,0 +1,121 @@
+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", "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();
+    }
+}

+ 63 - 0
fs-ad-api/src/main/java/com/fs/framework/config/ThreadPoolConfig.java

@@ -0,0 +1,63 @@
+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);
+            }
+        };
+    }
+}

+ 77 - 0
fs-ad-api/src/main/java/com/fs/framework/config/properties/DruidProperties.java

@@ -0,0 +1,77 @@
+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;
+    }
+}

+ 27 - 0
fs-ad-api/src/main/java/com/fs/framework/datasource/DynamicDataSource.java

@@ -0,0 +1,27 @@
+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();
+    }
+}

+ 45 - 0
fs-ad-api/src/main/java/com/fs/framework/datasource/DynamicDataSourceContextHolder.java

@@ -0,0 +1,45 @@
+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();
+    }
+}

+ 56 - 0
fs-ad-api/src/main/java/com/fs/framework/interceptor/RepeatSubmitInterceptor.java

@@ -0,0 +1,56 @@
+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);
+}

+ 126 - 0
fs-ad-api/src/main/java/com/fs/framework/interceptor/impl/SameUrlDataInterceptor.java

@@ -0,0 +1,126 @@
+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;
+    }
+}

+ 56 - 0
fs-ad-api/src/main/java/com/fs/framework/manager/AsyncManager.java

@@ -0,0 +1,56 @@
+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);
+    }
+}

+ 40 - 0
fs-ad-api/src/main/java/com/fs/framework/manager/ShutdownManager.java

@@ -0,0 +1,40 @@
+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);
+        }
+    }
+}

+ 103 - 0
fs-ad-api/src/main/java/com/fs/framework/manager/factory/AsyncFactory.java

@@ -0,0 +1,103 @@
+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);
+            }
+        };
+    }
+}

+ 1 - 0
fs-ad-api/src/main/resources/META-INF/spring-devtools.properties

@@ -0,0 +1 @@
+restart.include.json=/com.alibaba.fastjson.*.jar

+ 94 - 0
fs-ad-api/src/main/resources/application-dev.yml

@@ -0,0 +1,94 @@
+# 数据源配置
+spring:
+    # redis 配置
+    redis:
+        # 地址
+        host: localhost
+        # 端口,默认为6379
+        port: 6379
+        # 数据库索引
+        database: 0
+        # 密码
+        password:
+        # 连接超时时间
+        timeout: 20s
+        lettuce:
+            pool:
+                # 连接池中的最小空闲连接
+                min-idle: 0
+                # 连接池中的最大空闲连接
+                max-idle: 8
+                # 连接池的最大数据库连接数
+                max-active: 8
+                # #连接池最大阻塞等待时间(使用负值表示没有限制)
+                max-wait: -1ms
+    datasource:
+        mysql:
+            type: com.alibaba.druid.pool.DruidDataSource
+            driverClassName: com.mysql.cj.jdbc.Driver
+            druid:
+                # 主库数据源
+                master:
+                    url: jdbc:mysql://42.194.245.189:3306/rt_fs_his_test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: root
+                    password: YJF_2024
+                # 从库数据源
+                slave:
+                    # 从数据源开关/默认关闭
+                    enabled: false
+                    url:
+                    username:
+                    password:
+                # 初始连接数
+                initialSize: 5
+                # 最小连接池数量
+                minIdle: 10
+                # 最大连接池数量
+                maxActive: 20
+                # 配置获取连接等待超时的时间
+                maxWait: 60000
+                # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+                timeBetweenEvictionRunsMillis: 60000
+                # 配置一个连接在池中最小生存的时间,单位是毫秒
+                minEvictableIdleTimeMillis: 300000
+                # 配置一个连接在池中最大生存的时间,单位是毫秒
+                maxEvictableIdleTimeMillis: 900000
+                # 配置检测连接是否有效
+                validationQuery: SELECT 1 FROM DUAL
+                testWhileIdle: true
+                testOnBorrow: false
+                testOnReturn: false
+                webStatFilter:
+                    enabled: true
+                statViewServlet:
+                    enabled: true
+                    # 设置白名单,不填则允许所有访问
+                    allow:
+                    url-pattern: /druid/*
+                    # 控制台管理用户名和密码
+                    login-username: fs
+                    login-password: 123456
+                filter:
+                    stat:
+                        enabled: true
+                        # 慢SQL记录
+                        log-slow-sql: true
+                        slow-sql-millis: 1000
+                        merge-sql: true
+                    wall:
+                        config:
+                            multi-statement-allow: true
+
+
+rocketmq:
+    name-server: rmq-1243b25nj.rocketmq.gz.public.tencenttdmq.com:8080 # RocketMQ NameServer 地址
+    producer:
+        group: my-producer-group
+        access-key: ak1243b25nj17d4b2dc1a03 # 替换为实际的 accessKey
+        secret-key: sk08a7ea1f9f4b0237 # 替换为实际的 secretKey
+    consumer:
+        topic: test-ad-upload
+        group: test-group
+        access-key: ak1243b25nj17d4b2dc1a03 # 替换为实际的 accessKey
+        secret-key: sk08a7ea1f9f4b0237 # 替换为实际的 secretKey
+

+ 147 - 0
fs-ad-api/src/main/resources/application-druid-myhk.yml

@@ -0,0 +1,147 @@
+# 数据源配置
+spring:
+    # redis 配置
+    redis:
+        host: 172.27.0.6
+        port: 6379
+        # 数据库索引
+        database: 0
+        # 密码
+        password: myhk888777666.
+        # 连接超时时间
+        timeout: 10s
+        lettuce:
+            pool:
+                # 连接池中的最小空闲连接
+                min-idle: 0
+                # 连接池中的最大空闲连接
+                max-idle: 8
+                # 连接池的最大数据库连接数
+                max-active: 8
+                # #连接池最大阻塞等待时间(使用负值表示没有限制)
+                max-wait: -1ms
+    datasource:
+        clickhouse:
+            type: com.alibaba.druid.pool.DruidDataSource
+            driverClassName: com.clickhouse.jdbc.ClickHouseDriver
+            url: jdbc:clickhouse://1.14.104.71:8123/sop_test?compress=0&use_server_time_zone=true&use_client_time_zone=false&timezone=Asia/Shanghai
+            username: rt_2024
+            password: Yzx_19860213
+            initialSize: 10
+            maxActive: 100
+            minIdle: 10
+            maxWait: 6000
+        mysql:
+            type: com.alibaba.druid.pool.DruidDataSource
+            driverClassName: com.mysql.cj.jdbc.Driver
+            druid:
+                # 主库数据源
+                master:
+                    url: jdbc:mysql://172.27.0.17:3306/fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: root
+                    password: myhk888777666.
+                # 从库数据源
+                slave:
+                    # 从数据源开关/默认关闭
+                    enabled: false
+                    url:
+                    username:
+                    password:
+                # 初始连接数
+                initialSize: 5
+                # 最小连接池数量
+                minIdle: 10
+                # 最大连接池数量
+                maxActive: 20
+                # 配置获取连接等待超时的时间
+                maxWait: 60000
+                # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+                timeBetweenEvictionRunsMillis: 60000
+                # 配置一个连接在池中最小生存的时间,单位是毫秒
+                minEvictableIdleTimeMillis: 300000
+                # 配置一个连接在池中最大生存的时间,单位是毫秒
+                maxEvictableIdleTimeMillis: 900000
+                # 配置检测连接是否有效
+                validationQuery: SELECT 1 FROM DUAL
+                testWhileIdle: true
+                testOnBorrow: false
+                testOnReturn: false
+                webStatFilter:
+                    enabled: true
+                statViewServlet:
+                    enabled: true
+                    # 设置白名单,不填则允许所有访问
+                    allow:
+                    url-pattern: /druid/*
+                    # 控制台管理用户名和密码
+                    login-username: fs
+                    login-password: 123456
+                filter:
+                    stat:
+                        enabled: true
+                        # 慢SQL记录
+                        log-slow-sql: true
+                        slow-sql-millis: 1000
+                        merge-sql: true
+                    wall:
+                        config:
+                            multi-statement-allow: true
+        sop:
+            type: com.alibaba.druid.pool.DruidDataSource
+            driverClassName: com.mysql.cj.jdbc.Driver
+            druid:
+                # 主库数据源
+                master:
+                    url: jdbc:mysql://172.27.0.17:3306/fs_his_sop?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: root
+                    password: myhk888777666.
+                # 初始连接数
+                initialSize: 5
+                # 最小连接池数量
+                minIdle: 10
+                # 最大连接池数量
+                maxActive: 20
+                # 配置获取连接等待超时的时间
+                maxWait: 60000
+                # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+                timeBetweenEvictionRunsMillis: 60000
+                # 配置一个连接在池中最小生存的时间,单位是毫秒
+                minEvictableIdleTimeMillis: 300000
+                # 配置一个连接在池中最大生存的时间,单位是毫秒
+                maxEvictableIdleTimeMillis: 900000
+                # 配置检测连接是否有效
+                validationQuery: SELECT 1 FROM DUAL
+                testWhileIdle: true
+                testOnBorrow: false
+                testOnReturn: false
+                webStatFilter:
+                    enabled: true
+                statViewServlet:
+                    enabled: true
+                    # 设置白名单,不填则允许所有访问
+                    allow:
+                    url-pattern: /druid/*
+                    # 控制台管理用户名和密码
+                    login-username: fs
+                    login-password: 123456
+                filter:
+                    stat:
+                        enabled: true
+                        # 慢SQL记录
+                        log-slow-sql: true
+                        slow-sql-millis: 1000
+                        merge-sql: true
+                    wall:
+                        config:
+                            multi-statement-allow: true
+rocketmq:
+    name-server: rmq-1243b25nj.rocketmq.gz.public.tencenttdmq.com:8080 # RocketMQ NameServer 地址
+    producer:
+        group: my-producer-group
+        access-key: ak1243b25nj17d4b2dc1a03 # 替换为实际的 accessKey
+        secret-key: sk08a7ea1f9f4b0237 # 替换为实际的 secretKey
+    consumer:
+        group: voice-group
+        access-key: ak1243b25nj17d4b2dc1a03 # 替换为实际的 accessKey
+        secret-key: sk08a7ea1f9f4b0237 # 替换为实际的 secretKey
+

+ 139 - 0
fs-ad-api/src/main/resources/application-druid.yml

@@ -0,0 +1,139 @@
+# 数据源配置
+spring:
+    # redis 配置
+    redis:
+        # 地址  localhost
+        host: 127.0.0.1
+        # 端口,默认为6379
+        port: 6379
+        # 数据库索引
+        database: 0
+        # 密码
+        password:
+        #        password:
+        # 连接超时时间
+        timeout: 10s
+        lettuce:
+            pool:
+                # 连接池中的最小空闲连接
+                min-idle: 0
+                # 连接池中的最大空闲连接
+                max-idle: 8
+                # 连接池的最大数据库连接数
+                max-active: 8
+                # #连接池最大阻塞等待时间(使用负值表示没有限制)
+                max-wait: -1ms
+    datasource:
+        clickhouse:
+            type: com.alibaba.druid.pool.DruidDataSource
+            driverClassName: com.clickhouse.jdbc.ClickHouseDriver
+            url: jdbc:clickhouse://cc-2vc8zzo26w0l7m2l6.public.clickhouse.ads.aliyuncs.com/sop?compress=0&use_server_time_zone=true&use_client_time_zone=false&timezone=Asia/Shanghai
+            username: rt_2024
+            password: Yzx_19860213
+            initialSize: 10
+            maxActive: 100
+            minIdle: 10
+            maxWait: 6000
+        mysql:
+            type: com.alibaba.druid.pool.DruidDataSource
+            driverClassName: com.mysql.cj.jdbc.Driver
+            druid:
+                # 主库数据源
+                master:
+                    url: jdbc:mysql://42.194.245.189:3306/rt_fs_his?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: root
+                    password: YJF_2024
+                # 从库数据源
+                slave:
+                    # 从数据源开关/默认关闭
+                    enabled: false
+                    url:
+                    username:
+                    password:
+                # 初始连接数
+                initialSize: 5
+                # 最小连接池数量
+                minIdle: 10
+                # 最大连接池数量
+                maxActive: 20
+                # 配置获取连接等待超时的时间
+                maxWait: 60000
+                # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+                timeBetweenEvictionRunsMillis: 60000
+                # 配置一个连接在池中最小生存的时间,单位是毫秒
+                minEvictableIdleTimeMillis: 300000
+                # 配置一个连接在池中最大生存的时间,单位是毫秒
+                maxEvictableIdleTimeMillis: 900000
+                # 配置检测连接是否有效
+                validationQuery: SELECT 1 FROM DUAL
+                testWhileIdle: true
+                testOnBorrow: false
+                testOnReturn: false
+                webStatFilter:
+                    enabled: true
+                statViewServlet:
+                    enabled: true
+                    # 设置白名单,不填则允许所有访问
+                    allow:
+                    url-pattern: /druid/*
+                    # 控制台管理用户名和密码
+                    login-username: fs
+                    login-password: 123456
+                filter:
+                    stat:
+                        enabled: true
+                        # 慢SQL记录
+                        log-slow-sql: true
+                        slow-sql-millis: 1000
+                        merge-sql: true
+                    wall:
+                        config:
+                            multi-statement-allow: true
+        sop:
+            type: com.alibaba.druid.pool.DruidDataSource
+            driverClassName: com.mysql.cj.jdbc.Driver
+            druid:
+                # 主库数据源
+                master:
+                    url: jdbc:mysql://42.194.245.189:3306/test_his_sop?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                    username: root
+                    password: YJF_2024
+                # 初始连接数
+                initialSize: 5
+                # 最小连接池数量
+                minIdle: 10
+                # 最大连接池数量
+                maxActive: 20
+                # 配置获取连接等待超时的时间
+                maxWait: 60000
+                # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+                timeBetweenEvictionRunsMillis: 60000
+                # 配置一个连接在池中最小生存的时间,单位是毫秒
+                minEvictableIdleTimeMillis: 300000
+                # 配置一个连接在池中最大生存的时间,单位是毫秒
+                maxEvictableIdleTimeMillis: 900000
+                # 配置检测连接是否有效
+                validationQuery: SELECT 1 FROM DUAL
+                testWhileIdle: true
+                testOnBorrow: false
+                testOnReturn: false
+                webStatFilter:
+                    enabled: true
+                statViewServlet:
+                    enabled: true
+                    # 设置白名单,不填则允许所有访问
+                    allow:
+                    url-pattern: /druid/*
+                    # 控制台管理用户名和密码
+                    login-username: fs
+                    login-password: 123456
+                filter:
+                    stat:
+                        enabled: true
+                        # 慢SQL记录
+                        log-slow-sql: true
+                        slow-sql-millis: 1000
+                        merge-sql: true
+                    wall:
+                        config:
+                            multi-statement-allow: true

+ 132 - 0
fs-ad-api/src/main/resources/application.yml

@@ -0,0 +1,132 @@
+# 项目相关配置
+fs:
+  # 名称
+  name: fs
+  # 版本
+  version: 1.1.0
+  # 版权年份
+  copyrightYear: 2021
+  # 实例演示开关
+  demoEnabled: true
+  # 文件路径 示例( Windows配置D:/fs/uploadPath,Linux配置 /home/fs/uploadPath)
+  profile: c:/fs/uploadPath
+  # 获取ip地址开关
+  addressEnabled: false
+  # 验证码类型 math 数组计算 char 字符验证
+  captchaType: math
+
+# 开发环境配置
+server:
+  # 服务器的HTTP端口,默认为8080
+  port: 8008
+  servlet:
+    # 应用的访问路径
+    context-path: /
+  tomcat:
+    # tomcat的URI编码
+    uri-encoding: UTF-8
+    # tomcat最大线程数,默认为200
+    max-threads: 800
+    # Tomcat启动初始化的线程数,默认值25
+    min-spare-threads: 30
+
+# 日志配置
+logging:
+  level:
+    com.fs: debug
+    org.springframework: warn
+
+# Spring配置
+spring:
+  # 资源信息
+  messages:
+    # 国际化资源文件路径
+    basename: i18n/messages
+  profiles:
+#    active: dev
+    active: druid-yjf
+    include: config
+  mvc:
+    async:
+      request-timeout: 30000
+
+  # 文件上传
+  servlet:
+     multipart:
+       # 单个文件大小
+       max-file-size:  3GB
+       # 设置总上传的文件大小
+       max-request-size:  3GB
+  # 服务模块
+  devtools:
+    restart:
+      # 热部署开关
+      enabled: true
+
+
+# token配置
+token:
+    # 令牌自定义标识
+    header: Authorization
+    # 令牌密钥
+    secret: abcdefghijklmnopqrstuvwxyz
+    # 令牌有效期(默认30分钟)
+    expireTime: 180
+mybatis-plus:
+  # 搜索指定包别名
+  typeAliasesPackage: com.fs.**.domain,com.fs.**.bo
+  # 配置mapper的扫描,找到所有的mapper.xml映射文件
+  mapperLocations: classpath*:/mapper/**/*.xml
+  configLocation: classpath:mybatis/mybatis-config.xml
+  # 全局配置
+  global-config:
+    db-config:
+      # 主键类型  0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
+      idType: AUTO
+      # 字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
+      fieldStrategy: NOT_EMPTY
+    banner: false
+    # 配置
+  configuration:
+    # 驼峰式命名
+    mapUnderscoreToCamelCase: true
+    # 全局映射器启用缓存
+    cacheEnabled: true
+    # 配置默认的执行器
+    defaultExecutorType: REUSE
+    # 允许 JDBC 支持自动生成主键
+    useGeneratedKeys: true
+
+# MyBatis配置
+mybatis:
+    # 搜索指定包别名
+    typeAliasesPackage: com.fs.**.domain
+    # 配置mapper的扫描,找到所有的mapper.xml映射文件
+    mapperLocations: classpath*:mapper/**/*Mapper.xml
+    # 加载全局的配置文件
+    configLocation: classpath:mybatis/mybatis-config.xml
+
+# PageHelper分页插件
+pagehelper:
+  helperDialect: mysql
+  supportMethodsArguments: true
+  params: count=countSql
+
+# Swagger配置
+swagger:
+  # 是否开启swagger
+  enabled: false
+  # 请求前缀
+  pathMapping: /dev-api
+
+# 防止XSS攻击
+xss:
+  # 过滤开关
+  enabled: true
+  # 排除链接(多个用逗号分隔)
+  excludes: /system/notice,/system/config/*
+  # 匹配链接
+  urlPatterns: /system/*,/monitor/*,/tool/*
+zhyf:
+  url: https://zhyf-testController.jingpai.com
+

+ 2 - 0
fs-ad-api/src/main/resources/banner.txt

@@ -0,0 +1,2 @@
+Application Version: ${fs.version}
+Spring Boot Version: ${spring-boot.version}

+ 37 - 0
fs-ad-api/src/main/resources/i18n/messages.properties

@@ -0,0 +1,37 @@
+#错误消息
+not.null=* 必须填写
+user.jcaptcha.error=验证码错误
+user.jcaptcha.expire=验证码已失效
+user.not.exists=用户不存在/密码错误
+user.password.not.match=用户不存在/密码错误
+user.password.retry.limit.count=密码输入错误{0}次
+user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定10分钟
+user.password.delete=对不起,您的账号已被删除
+user.blocked=用户已封禁,请联系管理员
+role.blocked=角色已封禁,请联系管理员
+user.logout.success=退出成功
+
+length.not.valid=长度必须在{min}到{max}个字符之间
+
+user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
+user.password.not.valid=* 5-50个字符
+ 
+user.email.not.valid=邮箱格式错误
+user.mobile.phone.number.not.valid=手机号格式错误
+user.login.success=登录成功
+user.register.success=注册成功
+user.notfound=请重新登录
+user.forcelogout=管理员强制退出,请重新登录
+user.unknown.error=未知错误,请重新登录
+
+##文件上传消息
+upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB!
+upload.filename.exceed.length=上传的文件名最长{0}个字符
+
+##权限
+no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]
+no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]
+no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]
+no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]
+no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]
+no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]

+ 93 - 0
fs-ad-api/src/main/resources/logback.xml

@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!-- 日志存放路径 -->
+	<property name="log.path" value="/home/fs-ai-websocket/logs" />
+    <!-- 日志输出格式 -->
+	<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
+
+	<!-- 控制台输出 -->
+	<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+		<encoder>
+			<pattern>${log.pattern}</pattern>
+		</encoder>
+	</appender>
+
+	<!-- 系统日志输出 -->
+	<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
+	    <file>${log.path}/sys-info.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+			<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
+			<!-- 日志最大的历史 60天 -->
+			<maxHistory>60</maxHistory>
+		</rollingPolicy>
+		<encoder>
+			<pattern>${log.pattern}</pattern>
+		</encoder>
+		<filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 过滤的级别 -->
+            <level>INFO</level>
+            <!-- 匹配时的操作:接收(记录) -->
+            <onMatch>ACCEPT</onMatch>
+            <!-- 不匹配时的操作:拒绝(不记录) -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+	</appender>
+
+	<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+	    <file>${log.path}/sys-error.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+            <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
+			<!-- 日志最大的历史 60天 -->
+			<maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 过滤的级别 -->
+            <level>ERROR</level>
+			<!-- 匹配时的操作:接收(记录) -->
+            <onMatch>ACCEPT</onMatch>
+			<!-- 不匹配时的操作:拒绝(不记录) -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+	<!-- 用户访问日志输出  -->
+    <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
+		<file>${log.path}/sys-user.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 按天回滚 daily -->
+            <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 日志最大的历史 60天 -->
+            <maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+    </appender>
+
+	<!-- 系统模块日志级别控制  -->
+	<logger name="com.fs" level="info" />
+	<!-- Spring日志级别控制  -->
+	<logger name="org.springframework" level="warn" />
+
+	<root level="info">
+		<appender-ref ref="console" />
+	</root>
+
+	<!--系统操作日志-->
+    <root level="info">
+        <appender-ref ref="file_info" />
+        <appender-ref ref="file_error" />
+    </root>
+
+	<!--系统用户操作日志-->
+    <logger name="sys-user" level="info">
+        <appender-ref ref="sys-user"/>
+    </logger>
+</configuration>

+ 15 - 0
fs-ad-api/src/main/resources/mybatis/mybatis-config.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE configuration
+PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-config.dtd">
+<configuration>
+	
+	<settings>
+		<setting name="cacheEnabled"             value="true" />  <!-- 全局映射器启用缓存 -->
+		<setting name="useGeneratedKeys"         value="true" />  <!-- 允许 JDBC 支持自动生成主键 -->
+		<setting name="defaultExecutorType"      value="REUSE" /> <!-- 配置默认的执行器 -->
+		<setting name="logImpl"                  value="SLF4J" /> <!-- 指定 MyBatis 所用日志的具体实现 -->
+		 <setting name="mapUnderscoreToCamelCase" value="true"/>
+	</settings>
+	
+</configuration>

+ 119 - 0
fs-admin/pom.xml

@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>fs</artifactId>
+        <groupId>com.fs</groupId>
+        <version>1.1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging>
+    <artifactId>fs-admin</artifactId>
+
+    <description>
+        web服务入口
+    </description>
+
+    <dependencies>
+
+        <!-- spring-boot-devtools -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <optional>true</optional> <!-- 表示依赖不会传递 -->
+        </dependency>
+         <!-- Mysql驱动包 -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.fs</groupId>
+            <artifactId>fs-framework</artifactId>
+        </dependency>
+
+        <!-- 定时任务-->
+        <dependency>
+            <groupId>com.fs</groupId>
+            <artifactId>fs-quartz</artifactId>
+        </dependency>
+
+        <!-- 代码生成-->
+        <dependency>
+            <groupId>com.fs</groupId>
+            <artifactId>fs-generator</artifactId>
+        </dependency>
+        <!-- swagger2-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.clickhouse</groupId>
+            <artifactId>clickhouse-jdbc</artifactId>
+            <version>0.4.6</version>
+        </dependency>
+        <!-- swagger2-UI-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>swagger-bootstrap-ui</artifactId>
+            <version>1.9.3</version>
+        </dependency>
+        <dependency>
+            <groupId>com.tencentcloudapi</groupId>
+            <artifactId>tencentcloud-sdk-java</artifactId>
+            <version>3.1.322</version>
+            <scope>compile</scope>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/com.qcloud/qcloud-java-sdk -->
+        <dependency>
+            <groupId>com.qcloud</groupId>
+            <artifactId>qcloud-java-sdk</artifactId>
+            <version>2.0.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.clickhouse</groupId>
+            <artifactId>clickhouse-jdbc</artifactId>
+            <version>0.4.6</version>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.1.1.RELEASE</version>
+                <configuration>
+                    <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <version>3.1.0</version>
+                <configuration>
+                    <failOnMissingWebXml>false</failOnMissingWebXml>
+                    <warName>${project.artifactId}</warName>
+                </configuration>
+           </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+
+</project>

+ 26 - 0
fs-admin/src/main/java/com/fs/FSApplication.java

@@ -0,0 +1,26 @@
+package com.fs;
+
+import com.qiniu.common.Zone;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * 启动程序
+ */
+@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
+@Transactional
+@EnableAsync
+@EnableScheduling
+public class FSApplication
+{
+    public static void main(String[] args)
+    {
+        // System.setProperty("spring.devtools.restart.enabled", "false");
+        SpringApplication.run(FSApplication.class, args);
+        System.out.println("admin启动成功");
+    }
+}

+ 14 - 0
fs-admin/src/main/java/com/fs/FSServletInitializer.java

@@ -0,0 +1,14 @@
+package com.fs;
+
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+
+public class FSServletInitializer extends SpringBootServletInitializer
+{
+    @Override
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
+    {
+        return application.sources(FSApplication.class);
+    }
+}

+ 37 - 0
fs-admin/src/main/java/com/fs/ad/controller/AdAccountController.java

@@ -0,0 +1,37 @@
+package com.fs.ad.controller;
+
+import com.fs.ad.domain.AdSite;
+import com.fs.ad.service.IAdAccountService;
+import com.fs.ad.service.IAdSiteService;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 站点管理Controller
+ * 
+ * @author fs
+ * @date 2025-03-04
+ */
+@RestController
+@RequestMapping("/ad/adAccount")
+public class AdAccountController extends BaseController
+{
+    @Autowired
+    private IAdAccountService adAccountService;
+
+    @GetMapping("/listAll")
+    public R listAll(){
+        return R.ok().put("data", adAccountService.listAll());
+    }
+
+}

+ 78 - 0
fs-admin/src/main/java/com/fs/ad/controller/AdCallbackController.java

@@ -0,0 +1,78 @@
+package com.fs.ad.controller;//package com.fs.ad.controller;
+//
+//import com.alibaba.fastjson.JSON;
+//import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+//import com.fs.ad.domain.AdHtmlUrl;
+//import com.fs.ad.mapper.AdHtmlUrlMapper;
+//import com.fs.ad.service.IAdHtmlClickLogService;
+//import com.fs.ad.yk.utils.ApiUtils;
+//import com.fs.ad.yk.vo.DataBackVo;
+//import com.fs.baidu.api.BaiduApis;
+//import com.fs.baidu.api.ConvertData;
+//import com.fs.baidu.vo.AdClickCallbackVo;
+//import com.fs.common.core.controller.BaseController;
+//import com.fs.common.core.domain.R;
+//import com.fs.common.utils.StringUtils;
+//import lombok.AllArgsConstructor;
+//import lombok.extern.slf4j.Slf4j;
+//import org.springframework.web.bind.annotation.*;
+//
+///**
+// * 知识库Controller
+// *
+// * @author fs
+// * @date 2024-04-21
+// */
+//@Slf4j
+//@AllArgsConstructor
+//@RestController
+//@RequestMapping("/baidu")
+//public class AdCallbackController extends BaseController {
+//
+//    private final AdHtmlUrlMapper adHtmlUrlMapper;
+//    private final IAdHtmlClickLogService adHtmlClickLogService;
+//    private final BaiduApis baiduApis;
+//
+//    //百度-页面点击接口
+//    @GetMapping("/callback")
+//    public R callback(String url, String no, String bdVid, String t) {
+//        if(StringUtils.isEmpty(no) || StringUtils.isEmpty(bdVid)) {
+//            return R.ok();
+//        }
+//        adHtmlClickLogService.addLog(url, no, bdVid, t, 0);
+//        Runnable runnable = () -> ConvertData.uploadConvertData(url, Integer.parseInt(t));
+//        runnable.run();
+//        return R.ok();
+//    }
+//    // 百度点击监听返回接口
+//    @GetMapping("/clickCallback")
+//    public R clickCallback(AdClickCallbackVo vo){
+//        log.info("百度监听地址返回数据:{}", JSON.toJSONString(vo));
+//        adHtmlClickLogService.setLog(vo, "67", 0);
+//        return R.ok();
+//    }
+//    @GetMapping("/getTemplate")
+//    public R getTemplate(String no){
+//        AdHtmlUrl htmlUrl = adHtmlUrlMapper.selectOne(new QueryWrapper<AdHtmlUrl>().eq("no", no));
+//        if(htmlUrl == null){
+//            return R.error("错误编号");
+//        }
+//        return R.ok().put("images", htmlUrl.getImages().split(",")).put("json", StringUtils.isNotEmpty(htmlUrl.getDataJson()) ? JSON.parseObject(htmlUrl.getDataJson()) : null);
+//    }
+//    @GetMapping("/syncPlan")
+//    public R syncPlan(){
+//        baiduApis.listAccount(1L);
+//        return R.ok();
+//    }
+//
+//
+//    @GetMapping("/youkuClickCallback")
+//    public R youkuClickCallback(AdClickCallbackVo vo){
+//        log.info("优酷监听地址返回数据:{}", JSON.toJSONString(vo));
+//        adHtmlClickLogService.setLog(vo, "wechat", 1);
+////        ApiUtils.dataBack(DataBackVo.builder().trackId(vo.getBd_vid()).creativeId(vo.getAid()).build());
+//        return R.ok();
+//    }
+//
+//
+//}

+ 113 - 0
fs-admin/src/main/java/com/fs/ad/controller/AdDomainController.java

@@ -0,0 +1,113 @@
+package com.fs.ad.controller;
+
+import java.util.List;
+
+import com.fs.common.core.domain.R;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.ad.domain.AdDomain;
+import com.fs.ad.service.IAdDomainService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 广告域名Controller
+ * 
+ * @author fs
+ * @date 2025-03-04
+ */
+@RestController
+@RequestMapping("/ad/adDomain")
+public class AdDomainController extends BaseController
+{
+    @Autowired
+    private IAdDomainService adDomainService;
+
+    /**
+     * 查询广告域名列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDomain:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AdDomain adDomain)
+    {
+        startPage();
+        List<AdDomain> list = adDomainService.selectAdDomainList(adDomain);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出广告域名列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDomain:export')")
+    @Log(title = "广告域名", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(AdDomain adDomain)
+    {
+        List<AdDomain> list = adDomainService.selectAdDomainList(adDomain);
+        ExcelUtil<AdDomain> util = new ExcelUtil<AdDomain>(AdDomain.class);
+        return util.exportExcel(list, "广告域名数据");
+    }
+
+    /**
+     * 获取广告域名详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDomain:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(adDomainService.selectAdDomainById(id));
+    }
+
+    /**
+     * 新增广告域名
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDomain:add')")
+    @Log(title = "广告域名", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AdDomain adDomain)
+    {
+        return toAjax(adDomainService.insertAdDomain(adDomain));
+    }
+
+    /**
+     * 修改广告域名
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDomain:edit')")
+    @Log(title = "广告域名", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AdDomain adDomain)
+    {
+        return toAjax(adDomainService.updateAdDomain(adDomain));
+    }
+
+    /**
+     * 删除广告域名
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adDomain:remove')")
+    @Log(title = "广告域名", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(adDomainService.deleteAdDomainByIds(ids));
+    }
+
+
+
+
+    @GetMapping(value = "/listAll")
+    public R listAll(){
+        return R.ok().put("data", adDomainService.list());
+    }
+}

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

@@ -0,0 +1,103 @@
+package com.fs.ad.controller;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.ad.domain.AdHtmlClickLog;
+import com.fs.ad.service.IAdHtmlClickLogService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 广告点击Controller
+ * 
+ * @author fs
+ * @date 2025-01-09
+ */
+@RestController
+@RequestMapping("/ad/clickLog")
+public class AdHtmlClickLogController extends BaseController
+{
+    @Autowired
+    private IAdHtmlClickLogService adHtmlClickLogService;
+
+    /**
+     * 查询广告点击列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:clickLog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AdHtmlClickLog adHtmlClickLog)
+    {
+        startPage();
+        List<AdHtmlClickLog> list = adHtmlClickLogService.selectAdHtmlClickLogList(adHtmlClickLog);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出广告点击列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:clickLog:export')")
+    @Log(title = "广告点击", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(AdHtmlClickLog adHtmlClickLog)
+    {
+        List<AdHtmlClickLog> list = adHtmlClickLogService.selectAdHtmlClickLogList(adHtmlClickLog);
+        ExcelUtil<AdHtmlClickLog> util = new ExcelUtil<AdHtmlClickLog>(AdHtmlClickLog.class);
+        return util.exportExcel(list, "广告点击数据");
+    }
+
+    /**
+     * 获取广告点击详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:clickLog:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(adHtmlClickLogService.selectAdHtmlClickLogById(id));
+    }
+
+    /**
+     * 新增广告点击
+     */
+    @PreAuthorize("@ss.hasPermi('ad:clickLog:add')")
+    @Log(title = "广告点击", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AdHtmlClickLog adHtmlClickLog)
+    {
+        return toAjax(adHtmlClickLogService.insertAdHtmlClickLog(adHtmlClickLog));
+    }
+
+    /**
+     * 修改广告点击
+     */
+    @PreAuthorize("@ss.hasPermi('ad:clickLog:edit')")
+    @Log(title = "广告点击", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AdHtmlClickLog adHtmlClickLog)
+    {
+        return toAjax(adHtmlClickLogService.updateAdHtmlClickLog(adHtmlClickLog));
+    }
+
+    /**
+     * 删除广告点击
+     */
+    @PreAuthorize("@ss.hasPermi('ad:clickLog:remove')")
+    @Log(title = "广告点击", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(adHtmlClickLogService.deleteAdHtmlClickLogByIds(ids));
+    }
+}

+ 110 - 0
fs-admin/src/main/java/com/fs/ad/controller/AdHtmlTemplateController.java

@@ -0,0 +1,110 @@
+package com.fs.ad.controller;
+
+import java.util.List;
+
+import com.fs.common.core.domain.R;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.ad.domain.AdHtmlTemplate;
+import com.fs.ad.service.IAdHtmlTemplateService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 广告信息流链接Controller
+ * 
+ * @author fs
+ * @date 2024-12-31
+ */
+@RestController
+@RequestMapping("/ad/html/template")
+public class AdHtmlTemplateController extends BaseController
+{
+    @Autowired
+    private IAdHtmlTemplateService adHtmlUrlService;
+
+    /**
+     * 查询广告信息流链接列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:html:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AdHtmlTemplate adHtmlTemplate)
+    {
+        startPage();
+        List<AdHtmlTemplate> list = adHtmlUrlService.selectAdHtmlUrlList(adHtmlTemplate);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出广告信息流链接列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:html:export')")
+    @Log(title = "广告信息流链接", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(AdHtmlTemplate adHtmlTemplate)
+    {
+        List<AdHtmlTemplate> list = adHtmlUrlService.selectAdHtmlUrlList(adHtmlTemplate);
+        ExcelUtil<AdHtmlTemplate> util = new ExcelUtil<AdHtmlTemplate>(AdHtmlTemplate.class);
+        return util.exportExcel(list, "广告信息流链接数据");
+    }
+
+    /**
+     * 获取广告信息流链接详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:html:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(adHtmlUrlService.selectAdHtmlUrlById(id));
+    }
+
+    /**
+     * 新增广告信息流链接
+     */
+    @PreAuthorize("@ss.hasPermi('ad:html:add')")
+    @Log(title = "广告信息流链接", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AdHtmlTemplate adHtmlTemplate)
+    {
+        return toAjax(adHtmlUrlService.insertAdHtmlUrl(adHtmlTemplate));
+    }
+
+    /**
+     * 修改广告信息流链接
+     */
+    @PreAuthorize("@ss.hasPermi('ad:html:edit')")
+    @Log(title = "广告信息流链接", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AdHtmlTemplate adHtmlTemplate)
+    {
+        return toAjax(adHtmlUrlService.updateAdHtmlUrl(adHtmlTemplate));
+    }
+
+    /**
+     * 删除广告信息流链接
+     */
+    @PreAuthorize("@ss.hasPermi('ad:html:remove')")
+    @Log(title = "广告信息流链接", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(adHtmlUrlService.deleteAdHtmlUrlByIds(ids));
+    }
+
+    @GetMapping(value = "/listAll")
+    public R listAll(){
+        return R.ok().put("data", adHtmlUrlService.list());
+    }
+}

+ 113 - 0
fs-admin/src/main/java/com/fs/ad/controller/AdIqiyiAccountController.java

@@ -0,0 +1,113 @@
+package com.fs.ad.controller;
+
+import java.util.List;
+
+import com.fs.common.core.domain.R;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.ad.domain.AdIqiyiAccount;
+import com.fs.ad.service.IAdIqiyiAccountService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 爱奇艺广告账号Controller
+ * 
+ * @author fs
+ * @date 2025-03-03
+ */
+@RestController
+@RequestMapping("/ad/AdIqiyiAccount")
+public class AdIqiyiAccountController extends BaseController
+{
+    @Autowired
+    private IAdIqiyiAccountService adIqiyiAccountService;
+
+    /**
+     * 查询爱奇艺广告账号列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdIqiyiAccount:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AdIqiyiAccount adIqiyiAccount)
+    {
+        startPage();
+        List<AdIqiyiAccount> list = adIqiyiAccountService.selectAdIqiyiAccountList(adIqiyiAccount);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出爱奇艺广告账号列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdIqiyiAccount:export')")
+    @Log(title = "爱奇艺广告账号", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(AdIqiyiAccount adIqiyiAccount)
+    {
+        List<AdIqiyiAccount> list = adIqiyiAccountService.selectAdIqiyiAccountList(adIqiyiAccount);
+        ExcelUtil<AdIqiyiAccount> util = new ExcelUtil<AdIqiyiAccount>(AdIqiyiAccount.class);
+        return util.exportExcel(list, "爱奇艺广告账号数据");
+    }
+
+    /**
+     * 获取爱奇艺广告账号详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdIqiyiAccount:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(adIqiyiAccountService.selectAdIqiyiAccountById(id));
+    }
+
+    /**
+     * 新增爱奇艺广告账号
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdIqiyiAccount:add')")
+    @Log(title = "爱奇艺广告账号", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AdIqiyiAccount adIqiyiAccount)
+    {
+        return toAjax(adIqiyiAccountService.insertAdIqiyiAccount(adIqiyiAccount));
+    }
+
+    /**
+     * 修改爱奇艺广告账号
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdIqiyiAccount:edit')")
+    @Log(title = "爱奇艺广告账号", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AdIqiyiAccount adIqiyiAccount)
+    {
+        return toAjax(adIqiyiAccountService.updateAdIqiyiAccount(adIqiyiAccount));
+    }
+
+    /**
+     * 删除爱奇艺广告账号
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdIqiyiAccount:remove')")
+    @Log(title = "爱奇艺广告账号", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(adIqiyiAccountService.deleteAdIqiyiAccountByIds(ids));
+    }
+    /**
+     * 删除优酷广告账号
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdYouKuaccount:list')")
+    @GetMapping("/listAll")
+    public R listAll(){
+        return R.ok().put("data", adIqiyiAccountService.listAll());
+    }
+}

+ 106 - 0
fs-admin/src/main/java/com/fs/ad/controller/AdSiteController.java

@@ -0,0 +1,106 @@
+package com.fs.ad.controller;
+
+import java.util.List;
+
+import com.fs.common.core.domain.R;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.ad.domain.AdSite;
+import com.fs.ad.service.IAdSiteService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 站点管理Controller
+ * 
+ * @author fs
+ * @date 2025-03-04
+ */
+@RestController
+@RequestMapping("/ad/adSite")
+public class AdSiteController extends BaseController
+{
+    @Autowired
+    private IAdSiteService adSiteService;
+
+    /**
+     * 查询站点管理列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adSite:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AdSite adSite)
+    {
+        startPage();
+        List<AdSite> list = adSiteService.selectAdSiteList(adSite);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出站点管理列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adSite:export')")
+    @Log(title = "站点管理", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(AdSite adSite)
+    {
+        List<AdSite> list = adSiteService.selectAdSiteList(adSite);
+        ExcelUtil<AdSite> util = new ExcelUtil<AdSite>(AdSite.class);
+        return util.exportExcel(list, "站点管理数据");
+    }
+
+    /**
+     * 获取站点管理详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adSite:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(adSiteService.selectAdSiteById(id));
+    }
+
+    /**
+     * 新增站点管理
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adSite:add')")
+    @Log(title = "站点管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AdSite adSite)
+    {
+        return toAjax(adSiteService.insertAdSite(adSite));
+    }
+
+    /**
+     * 修改站点管理
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adSite:edit')")
+    @Log(title = "站点管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AdSite adSite)
+    {
+        return toAjax(adSiteService.updateAdSite(adSite));
+    }
+
+    /**
+     * 删除站点管理
+     */
+    @PreAuthorize("@ss.hasPermi('ad:adSite:remove')")
+    @Log(title = "站点管理", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(adSiteService.deleteAdSiteByIds(ids));
+    }
+
+}

+ 113 - 0
fs-admin/src/main/java/com/fs/ad/controller/AdYoukuAccountController.java

@@ -0,0 +1,113 @@
+package com.fs.ad.controller;
+
+import java.util.List;
+
+import com.fs.common.core.domain.R;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.ad.domain.AdYoukuAccount;
+import com.fs.ad.service.IAdYoukuAccountService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 优酷广告账号Controller
+ * 
+ * @author fs
+ * @date 2025-02-19
+ */
+@RestController
+@RequestMapping("/ad/AdYouKuAccount")
+public class AdYoukuAccountController extends BaseController
+{
+    @Autowired
+    private IAdYoukuAccountService adYoukuAccountService;
+
+    /**
+     * 查询优酷广告账号列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdYouKuaccount:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(AdYoukuAccount adYoukuAccount)
+    {
+        startPage();
+        List<AdYoukuAccount> list = adYoukuAccountService.selectAdYoukuAccountList(adYoukuAccount);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出优酷广告账号列表
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdYouKuaccount:export')")
+    @Log(title = "优酷广告账号", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(AdYoukuAccount adYoukuAccount)
+    {
+        List<AdYoukuAccount> list = adYoukuAccountService.selectAdYoukuAccountList(adYoukuAccount);
+        ExcelUtil<AdYoukuAccount> util = new ExcelUtil<AdYoukuAccount>(AdYoukuAccount.class);
+        return util.exportExcel(list, "优酷广告账号数据");
+    }
+
+    /**
+     * 获取优酷广告账号详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdYouKuaccount:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(adYoukuAccountService.selectAdYoukuAccountById(id));
+    }
+
+    /**
+     * 新增优酷广告账号
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdYouKuaccount:add')")
+    @Log(title = "优酷广告账号", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody AdYoukuAccount adYoukuAccount)
+    {
+        return toAjax(adYoukuAccountService.insertAdYoukuAccount(adYoukuAccount));
+    }
+
+    /**
+     * 修改优酷广告账号
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdYouKuaccount:edit')")
+    @Log(title = "优酷广告账号", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody AdYoukuAccount adYoukuAccount)
+    {
+        return toAjax(adYoukuAccountService.updateAdYoukuAccount(adYoukuAccount));
+    }
+
+    /**
+     * 删除优酷广告账号
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdYouKuaccount:remove')")
+    @Log(title = "优酷广告账号", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(adYoukuAccountService.deleteAdYoukuAccountByIds(ids));
+    }
+    /**
+     * 删除优酷广告账号
+     */
+    @PreAuthorize("@ss.hasPermi('ad:AdYouKuaccount:list')")
+	@GetMapping("/listAll")
+    public R listAll(){
+        return R.ok().put("data", adYoukuAccountService.listAll());
+    }
+}

+ 151 - 0
fs-admin/src/main/java/com/fs/ad/controller/BdAccountController.java

@@ -0,0 +1,151 @@
+package com.fs.ad.controller;
+
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Optional;
+
+import com.fs.baidu.api.BaiduApis;
+import com.fs.baidu.domain.*;
+import com.fs.baidu.enums.BdTimeUnit;
+import com.fs.baidu.param.QueryReportDataParam;
+import com.fs.baidu.service.*;
+import com.fs.common.core.domain.R;
+import lombok.AllArgsConstructor;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 百度账号Controller
+ * 
+ * @author fs
+ * @date 2025-01-20
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/bd/BdAccount")
+public class BdAccountController extends BaseController {
+    private final IBdAccountService bdAccountService;
+    private final IBdPlanService bdPlanService;
+    private final IBdUnitService bdUnitService;
+    private final IBdCreativeService bdCreativeService;
+    private final IBdApiService bdApiService;
+    private final BaiduApis baiduApis;
+
+    /**
+     * 查询百度账号列表
+     */
+    @PreAuthorize("@ss.hasPermi('baidu:BdAccount:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(BdAccount bdAccount){
+        startPage();
+        List<BdAccount> list = bdAccountService.selectBdAccountList(bdAccount);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出百度账号列表
+     */
+    @PreAuthorize("@ss.hasPermi('baidu:BdAccount:export')")
+    @Log(title = "百度账号", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(BdAccount bdAccount)
+    {
+        List<BdAccount> list = bdAccountService.selectBdAccountList(bdAccount);
+        ExcelUtil<BdAccount> util = new ExcelUtil<BdAccount>(BdAccount.class);
+        return util.exportExcel(list, "百度账号数据");
+    }
+
+    /**
+     * 获取百度账号详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('baidu:BdAccount:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(bdAccountService.selectBdAccountById(id));
+    }
+
+    /**
+     * 新增百度账号
+     */
+    @PreAuthorize("@ss.hasPermi('baidu:BdAccount:add')")
+    @Log(title = "百度账号", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody BdAccount bdAccount)
+    {
+        return toAjax(bdAccountService.insertBdAccount(bdAccount));
+    }
+
+    /**
+     * 修改百度账号
+     */
+    @PreAuthorize("@ss.hasPermi('baidu:BdAccount:edit')")
+    @Log(title = "百度账号", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody BdAccount bdAccount)
+    {
+        return toAjax(bdAccountService.updateBdAccount(bdAccount));
+    }
+
+    /**
+     * 删除百度账号
+     */
+    @PreAuthorize("@ss.hasPermi('baidu:BdAccount:remove')")
+    @Log(title = "百度账号", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(bdAccountService.deleteBdAccountByIds(ids));
+    }
+
+
+    /**
+     * 查询百度账号列表
+     */
+    @GetMapping("/listAll")
+    public R listAll(BdAccount bdAccount){
+        return R.ok().put("data", bdAccountService.selectBdAccountList(bdAccount));
+    }
+    @GetMapping("/listAllPlan")
+    public R listAllPlan(BdPlan plan){
+        return R.ok().put("data", bdPlanService.selectBdPlanList(plan));
+    }
+    @GetMapping("/listAllUnit")
+    public R listAllUnit(BdUnit unit){
+        return R.ok().put("data", bdUnitService.selectBdUnitList(unit));
+    }
+    @GetMapping("/listAllCreative")
+    public R listAllCreative(BdCreative creative){
+        return R.ok().put("data", bdCreativeService.selectBdCreativeList(creative));
+    }
+    @GetMapping("/authorizationUrl")
+    public R authorizationUrl(Long id){
+        Optional<BdApi> first = bdApiService.list().stream().findFirst();
+        if(!first.isPresent()){
+            return R.error("未找到API信息");
+        }
+        return R.ok().put("url", bdApiService.authorizationUrl(first.get().getId()));
+    }
+    @GetMapping("/syncAccount")
+    public R syncAccount(Long id){
+        Optional<BdApi> first = bdApiService.list().stream().findFirst();
+        if(!first.isPresent()){
+            return R.error("未找到API信息");
+        }
+        baiduApis.listAccount(1L, id);
+        return R.ok();
+    }
+}

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

@@ -0,0 +1,215 @@
+package com.fs.ad.controller;
+
+import com.fs.baidu.utils.SignService;
+import com.fs.baidu.domain.BdApi;
+import com.fs.baidu.service.IBdApiService;
+import com.fs.huifuPay.sdk.opps.core.exception.BasePayException;
+import com.fs.huifuPay.sdk.opps.core.utils.HttpClientUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.json.JSONObject;
+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.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+@Slf4j
+@RestController
+@RequestMapping("/baiduBack")
+public class MockAppController {
+    private static final String APPID = "appId";
+    private static final String AUTH_CODE = "authCode";
+    private static final String USERID = "userId";
+    private static final String TIMESTAMP = "timestamp";
+    private static final String SIGNATURE = "signature";
+    private static final String STATE = "state";
+    private static final String ACCESSTOKEN_URL = "https://u.baidu.com/oauth/accessToken";
+
+    @Autowired
+    private IBdApiService bdApiService; // 开发者自定义
+    @Autowired
+    private SignService signService; // 开发者可自定义
+
+    @GetMapping("/callback")
+    public String mockApp(HttpServletRequest request) throws BasePayException {
+
+        // 获取请求参数
+        Map<String, String> params = new HashMap<>();
+        this.fillParams(params, request);
+        log.info("callback: params = {}", JSONObject.valueToString(params));
+        int userIdInt = 0;
+        try {
+            userIdInt = Integer.parseInt(params.get(USERID));
+        } catch (Exception e) {
+            return this.getResponseJson(600011, "参数错误", new Object());
+        }
+        // 对签名内容进行判空
+        if (StringUtils.isBlank(params.get(SIGNATURE))) {
+            return this.getResponseJson(600011, "参数错误", new Object());
+        }
+
+        // 获取应用对应的密钥
+        BdApi app = bdApiService.getAppByAppId(params.get(APPID));
+        String sk = app.getAppSecretKey();
+        // 开发者进行验签
+        // 检查状态码
+//        if (!this.checkState(params.get(APPID), app.getAppUserId(), params.get(STATE))) {
+//            log.info("callback: state check fail");
+//            return this.getResponseJson(600011, "状态码错误", new Object());
+//        }
+
+        // 签名验证
+        if (!this.checkSignature(params, sk)) {
+            log.info("callback: signature check fail");
+            return this.getResponseJson(600011, "签名错误", new Object());
+        }
+
+        // 调用接口换取授权令牌
+        String response = this.getAccessToken(params, sk, userIdInt);
+        log.info("callback:getAccesstoken, response={}", response);
+        String accessToken = null;
+        String refreshToken = null;
+        int uid;
+
+        if (response.length() > 0) {
+            JSONObject res = new JSONObject(response);
+            int code = (int) res.get("code");
+            if (code == 0) {
+                JSONObject data = res.getJSONObject("data");
+                accessToken = (String) data.get("accessToken");
+                // 注释部分为 accessToken 其他信息,各应用开发者酌情使用即可
+                 refreshToken = (String) data.get("refreshToken");
+                String openId = data.getString("openId");
+                int expiresIn = data.getInt("expiresIn");
+                int refreshExpiresIn = data.getInt("refreshExpiresIn");
+                app.setAccessToken(accessToken);
+                app.setRefreshToken(refreshToken);
+                app.setExpiresIn(expiresIn);
+                app.setOpenId(openId);
+                app.setRefreshExpiresIn(refreshExpiresIn);
+                app.setAuthCode(params.get(AUTH_CODE));
+                bdApiService.updateById(app);
+
+                // TODO 相关信息落库处理
+            } else {
+                return this.getResponseJson(600011, "未获取到 access_token", new Object());
+            }
+        }
+        Map<String, String> data = new HashMap<>();
+        data.put("accessToken", accessToken);
+        return this.getResponseJson(0, "success", data);
+    }
+
+    /**
+     * 填充请求参数,开发者可用实体代替map
+     *
+     * @param params
+     * @param request
+     */
+    private void fillParams(Map<String, String> params, HttpServletRequest request) {
+        params.put(APPID, request.getParameter(APPID));
+        params.put(AUTH_CODE, request.getParameter(AUTH_CODE));
+        params.put(USERID, request.getParameter(USERID));
+        params.put(TIMESTAMP, request.getParameter(TIMESTAMP));
+        params.put(SIGNATURE, request.getParameter(SIGNATURE));
+        params.put(STATE, request.getParameter(STATE));
+    }
+
+    /**
+     * 校验状态码是否符合预期
+     *
+     * @param appId  应用ID
+     * @param userId 创建应用的ID
+     * @param state  请求参数中的状态码
+     * @return
+     */
+    private boolean checkState(String appId, Long userId, String state) {
+        // md5util 开发者自行开发即可
+        String newState = md5(appId.concat("_").concat(String.valueOf(userId)));
+        return newState.equals(state);
+    }
+    public static String md5(String input) {
+        try {
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] messageDigest = md.digest(input.getBytes());
+            StringBuilder hexString = new StringBuilder();
+            for (byte b : messageDigest) {
+                String hex = Integer.toHexString(0xff & b);
+                if (hex.length() == 1) {
+                    hexString.append('0');
+                }
+                hexString.append(hex);
+            }
+            return hexString.toString();
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException(e);
+        }
+    }
+    /**
+     * 签名验证方法
+     *
+     * @param params
+     * @param sk
+     * @return
+     */
+    private boolean checkSignature(Map<String, String> params, String sk) {
+        // 获取验签字符串:按key自然排序,拼接成 json 字符串,
+        // 示例:str1 = {"appId": xxxxx, "authCode": xxx, "state": xxx,"timestamp": xxx}
+        TreeMap<String, Object> map = new TreeMap<>();
+        map.put(APPID, params.get(APPID));
+        map.put(AUTH_CODE, params.get(AUTH_CODE));
+        map.put(USERID, params.get(USERID));
+        map.put(STATE, params.get(STATE));
+        map.put(TIMESTAMP, params.get(TIMESTAMP));
+        // 根据上述签名算法对接收到的参数签名
+        String sign = signService.paramsSign(sk, map);
+        log.info("callback: signature = {}", sign);
+        // 判断签名和URL传参签名是否一致
+        return params.get(SIGNATURE).equals(sign);
+    }
+
+    /**
+     * 换取授权令牌
+     *
+     * @param params
+     * @param sk
+     * @param userIdInt 授权账户ID
+     * @return
+     */
+    private String getAccessToken(Map<String, String> params, String sk, int userIdInt) throws BasePayException {
+        Map<String, Object> requestMap = new HashMap<>();
+        requestMap.put(APPID, params.get(APPID));
+        requestMap.put("secretKey", sk);
+        requestMap.put(AUTH_CODE, params.get(AUTH_CODE));
+        requestMap.put("grantType", "access_token");
+        requestMap.put("userId", userIdInt);
+
+        String paramsJson = JSONObject.valueToString(requestMap);
+        // 开发者自行增加异常判断
+        return HttpClientUtils.httpPostJson(ACCESSTOKEN_URL, new HashMap<>(), paramsJson);
+    }
+
+    /**
+     * 封装返回json串
+     *
+     * @param code
+     * @param message
+     * @param data
+     * @return
+     */
+    private String getResponseJson(int code, String message, Object data) {
+        // 封装返回字段的map
+        Map<String, Object> responseMap = new HashMap<>();
+        responseMap.put("code", code);
+        responseMap.put("message", message);
+        responseMap.put("data", data);
+        return JSONObject.valueToString(responseMap);
+    }
+}

+ 78 - 0
fs-admin/src/main/java/com/fs/ad/controller/StatisticsController.java

@@ -0,0 +1,78 @@
+package com.fs.ad.controller;
+
+import com.fs.baidu.api.BaiduApis;
+import com.fs.baidu.enums.BdTimeUnit;
+import com.fs.baidu.param.QueryReportDataParam;
+import com.fs.baidu.service.IBdAccountService;
+import com.fs.bdAdv.param.FsAdvSemStatisticsByDayParam;
+import com.fs.bdAdv.service.IFsAdvSemService;
+import com.fs.bdAdv.vo.FsAdvSemStatisticsByDayVo;
+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.utils.poi.ExcelUtil;
+import com.fs.qw.param.ConversionStatisticsParam;
+import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@RestController
+@AllArgsConstructor
+@RequestMapping("/baiduStatistics")
+public class StatisticsController extends BaseController {
+
+    private final IFsAdvSemService fsAdvSemService;
+    private final IBdAccountService bdAccountService;
+    private final BaiduApis baiduApis;
+
+    @GetMapping("/conversionStatistics")
+    public R conversionStatistics(ConversionStatisticsParam param){
+        return bdAccountService.conversionStatistics(param);
+    }
+
+
+    @GetMapping("/selectFsAdvSemStatisticsByDayVo")
+    public TableDataInfo selectFsAdvSemStatisticsByDayVo(FsAdvSemStatisticsByDayParam param){
+        startPage();
+        return getDataTable(fsAdvSemService.selectFsAdvSemStatisticsByDayVo(param));
+    }
+
+    /**
+     * 导出
+     * @param param
+     * @return
+     */
+    @GetMapping("/fsAdvSemStatisticsExport")
+    public AjaxResult fsAdvSemStatisticsExport(FsAdvSemStatisticsByDayParam param){
+        List<FsAdvSemStatisticsByDayVo> list = fsAdvSemService.selectFsAdvSemStatisticsByDayVo(param);
+        ExcelUtil<FsAdvSemStatisticsByDayVo> util = new ExcelUtil<FsAdvSemStatisticsByDayVo>(FsAdvSemStatisticsByDayVo.class);
+        return util.exportExcel(list, "企微主体数据");
+    }
+
+
+
+    @GetMapping("/getReportData")
+    public R getReportData(Long id, Integer reportType, LocalDate startDate, LocalDate endDate, Integer page, Integer rowCount){
+        QueryReportDataParam param = new QueryReportDataParam();
+        param.setReportType(reportType);
+        param.setStartDate(startDate);
+        param.setEndDate(endDate);
+        param.setPage(page);
+        param.setRowCount(rowCount);
+        param.setTimeUnit(BdTimeUnit.DAY);
+        return baiduApis.getReportData(bdAccountService.getById(id), param);
+    }
+
+    @GetMapping("/bdDataStatic")
+    public R bdDataStatic(){
+        return baiduApis.bdDataStatic();
+    }
+
+
+}

+ 25 - 0
fs-admin/src/main/java/com/fs/ad/controller/task/BaiduTask.java

@@ -0,0 +1,25 @@
+package com.fs.ad.controller.task;
+
+import com.fs.qw.service.IQwWorkUserService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component("baiduTask")
+public class BaiduTask {
+
+    @Autowired
+    private IQwWorkUserService qwWorkUserService;
+
+    /**
+     * 同步完企微客户,然后对加微的数据信息筛选并上传给百度进行投流优化
+     */
+    public void bdUpload(){
+        qwWorkUserService.uploadBd();
+//        qwWorkUserService.uploadYk();
+    }
+
+
+}

+ 124 - 0
fs-admin/src/main/java/com/fs/chat/controller/ChatDatasetController.java

@@ -0,0 +1,124 @@
+package com.fs.chat.controller;
+
+import com.fs.ai.service.IBaiduAIService;
+import com.fs.chat.domain.ChatDataset;
+import com.fs.chat.param.ChatDatasetCParam;
+import com.fs.chat.service.IChatDatasetService;
+import com.fs.chat.service.IChatRoleService;
+import com.fs.chat.vo.ChatDatasetListCVO;
+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 org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 知识库Controller
+ *
+ * @author fs
+ * @date 2024-04-21
+ */
+@RestController
+@RequestMapping("/chat/chatDataset")
+public class ChatDatasetController extends BaseController
+{
+    @Autowired
+    private IChatDatasetService chatDatasetService;
+    @Autowired
+    private IChatRoleService chatRoleService;
+    @Autowired
+    private IBaiduAIService baiduAIService;
+
+
+    /**
+     * 查询知识库列表
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatDataset:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(ChatDatasetCParam chatDataset)
+    {
+        startPage();
+        List<ChatDatasetListCVO> list = chatDatasetService.selectChatDatasetListCVO(chatDataset);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出知识库列表
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatDataset:export')")
+    @Log(title = "知识库", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(ChatDataset chatDataset)
+    {
+        List<ChatDataset> list = chatDatasetService.selectChatDatasetList(chatDataset);
+        ExcelUtil<ChatDataset> util = new ExcelUtil<ChatDataset>(ChatDataset.class);
+        return util.exportExcel(list, "知识库数据");
+    }
+
+    /**
+     * 获取知识库详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatDataset:query')")
+    @GetMapping(value = "/{datasetId}")
+    public AjaxResult getInfo(@PathVariable("datasetId") Long datasetId)
+    {
+        return AjaxResult.success(chatDatasetService.selectChatDatasetByDatasetId(datasetId));
+    }
+
+    /**
+     * 新增知识库
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatDataset:add')")
+    @Log(title = "知识库", businessType = BusinessType.INSERT)
+    @PostMapping
+    public R add(@RequestBody ChatDataset chatDataset)
+    {
+        //判断角色是否已创建知识库
+       if(chatDatasetService.check(chatDataset.getRoleId())>0){
+           return R.error("此客服角色已创建知识库");
+       }
+        String id=baiduAIService.createDataset(chatDataset.getDatasetName());
+        chatDataset.setExtId(id);
+        chatDataset.setCompanyId(0L);
+        return chatDatasetService.insertChatDataset(chatDataset)>0?R.ok():R.error();
+    }
+
+    /**
+     * 修改知识库
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatDataset:edit')")
+    @Log(title = "知识库", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody ChatDataset chatDataset)
+    {
+        ChatDataset chatDataset1=chatDatasetService.selectChatDatasetByDatasetId(chatDataset.getDatasetId());
+        if(!chatDataset1.getRoleId().equals(chatDataset.getRoleId())){
+            if(chatDatasetService.check(chatDataset.getRoleId())>0){
+                return AjaxResult.error("此客服角色已创建知识库");
+            }
+        }
+
+
+        return toAjax(chatDatasetService.updateChatDataset(chatDataset));
+    }
+
+    /**
+     * 删除知识库
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatDataset:remove')")
+    @Log(title = "知识库", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{datasetIds}")
+    public AjaxResult remove(@PathVariable Long[] datasetIds)
+    {
+
+        return toAjax(chatDatasetService.deleteChatDatasetByDatasetIds(datasetIds));
+    }
+}

+ 166 - 0
fs-admin/src/main/java/com/fs/chat/controller/ChatDatasetFileController.java

@@ -0,0 +1,166 @@
+package com.fs.chat.controller;
+
+import com.fs.ai.service.IBaiduAIService;
+import com.fs.chat.domain.ChatDataset;
+import com.fs.chat.domain.ChatDatasetFile;
+import com.fs.chat.dto.ChatDatasetFileExportDTO;
+import com.fs.chat.service.IChatDatasetFileService;
+import com.fs.chat.service.IChatDatasetService;
+import com.fs.common.annotation.Log;
+import com.fs.common.config.FSConfig;
+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.exception.file.OssException;
+import com.fs.common.utils.file.FileUploadUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+
+/**
+ * 文件Controller
+ *
+ * @author fs
+ * @date 2024-04-21
+ */
+@RestController
+@RequestMapping("/chat/chatDatasetFile")
+public class ChatDatasetFileController extends BaseController
+{
+    @Autowired
+    private IChatDatasetFileService chatDatasetFileService;
+    @Autowired
+    private IChatDatasetService chatDatasetService;
+    @Autowired
+    private IBaiduAIService baiduAIService;
+    /**
+     * 查询文件列表
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatDatasetFile:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(ChatDatasetFile chatDatasetFile)
+    {
+        startPage();
+        List<ChatDatasetFile> list = chatDatasetFileService.selectChatDatasetFileList(chatDatasetFile);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出文件列表
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatDatasetFile:export')")
+    @Log(title = "文件", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(ChatDatasetFile chatDatasetFile)
+    {
+        List<ChatDatasetFile> list = chatDatasetFileService.selectChatDatasetFileList(chatDatasetFile);
+        ExcelUtil<ChatDatasetFile> util = new ExcelUtil<ChatDatasetFile>(ChatDatasetFile.class);
+        return util.exportExcel(list, "文件数据");
+    }
+
+    /**
+     * 获取文件详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatDatasetFile:query')")
+    @GetMapping(value = "/{fileId}")
+    public AjaxResult getInfo(@PathVariable("fileId") Long fileId)
+    {
+        return AjaxResult.success(chatDatasetFileService.selectChatDatasetFileByFileId(fileId));
+    }
+
+    /**
+     * 新增文件
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatDatasetFile:add')")
+    @Log(title = "文件", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    public R add(@RequestParam("file") MultipartFile file,@RequestParam Long datasetId) throws Exception {
+        ChatDataset dataset=chatDatasetService.selectChatDatasetByDatasetId(datasetId);
+        if (file.isEmpty())
+        {
+            throw new OssException("上传文件不能为空");
+        }
+        String originalFilename = file.getOriginalFilename();
+        String fileExtension = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
+        if (fileExtension.equalsIgnoreCase("xls") || fileExtension.equalsIgnoreCase("xlsx")) {
+            // 文件属于Excel格式
+            String fileName = getFileNameWithoutExtension(originalFilename);
+            ExcelUtil<ChatDatasetFileExportDTO> util = new ExcelUtil<>(ChatDatasetFileExportDTO.class);
+            List<ChatDatasetFileExportDTO> list = util.importExcel(file.getInputStream());
+            file = chatDatasetFileService.convertChatDatasetFileByExcel(list,fileName);
+        }
+        // 上传文件路径
+        String filePath = FSConfig.getUploadPath();
+        // 上传并返回新文件名称
+        String fileName = FileUploadUtils.upload(filePath, file);
+        String url =filePath + fileName.replaceAll("/profile/upload","");
+        // 上传文件
+        String[] documentIds =baiduAIService.addDocument(dataset.getExtId(),url);
+        if(documentIds.length>0){
+            ChatDatasetFile chatDatasetFile=new ChatDatasetFile();
+            chatDatasetFile.setDatasetId(datasetId);
+            chatDatasetFile.setFileName(file.getOriginalFilename());
+            chatDatasetFile.setExtId(documentIds[0]);
+            if(chatDatasetFileService.insertChatDatasetFile(chatDatasetFile)>0){
+                return R.ok("操作成功");
+            }
+            else{
+                return R.error("操作失败");
+            }
+        }
+        else {
+            return R.error("文件上传失败");
+        }
+
+    }
+
+    /**
+     * 修改文件
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatDatasetFile:edit')")
+    @Log(title = "文件", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody ChatDatasetFile chatDatasetFile)
+    {
+        return toAjax(chatDatasetFileService.updateChatDatasetFile(chatDatasetFile));
+    }
+
+    /**
+     * 删除文件
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatDatasetFile:remove')")
+    @Log(title = "文件", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{fileIds}")
+    public R remove(@PathVariable Long[] fileIds)
+    {
+        for(Long id:fileIds){
+            ChatDatasetFile file=chatDatasetFileService.selectChatDatasetFileByFileId(id);
+            ChatDataset dataset=chatDatasetService.selectChatDatasetByDatasetId(file.getDatasetId());
+            baiduAIService.delDocument(dataset.getExtId(),file.getExtId());
+
+        }
+        chatDatasetFileService.deleteChatDatasetFileByFileIds(fileIds);
+        return R.ok();
+    }
+
+    private String getFileNameWithoutExtension(String fileName) {
+        Path filePath = Paths.get(fileName);
+        String nameWithExtension = filePath.getFileName().toString();
+        int dotIndex = nameWithExtension.lastIndexOf(".");
+
+        // 检查文件名是否有扩展名
+        if (dotIndex > 0 && dotIndex < nameWithExtension.length() - 1) {
+            return nameWithExtension.substring(0, dotIndex);
+        }
+
+        return nameWithExtension;
+    }
+}

+ 86 - 0
fs-admin/src/main/java/com/fs/chat/controller/ChatKeywordController.java

@@ -0,0 +1,86 @@
+package com.fs.chat.controller;
+
+import com.fs.chat.domain.ChatKeyword;
+import com.fs.chat.service.IChatKeywordService;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 关键字Controller
+ *
+ * @author fs
+ * @date 2024-04-19
+ */
+@RestController
+@RequestMapping("/chat/chatKeyword")
+public class ChatKeywordController extends BaseController
+{
+    @Autowired
+    private IChatKeywordService chatKeywordService;
+    /**
+     * 查询关键字列表
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatKeyword:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(ChatKeyword chatKeyword)
+    {
+        startPage();
+        List<ChatKeyword> list = chatKeywordService.selectChatKeywordList(chatKeyword);
+        return getDataTable(list);
+    }
+
+
+
+    /**
+     * 获取关键字详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatKeyword:query')")
+    @GetMapping(value = "/{keywordId}")
+    public AjaxResult getInfo(@PathVariable("keywordId") Long keywordId)
+    {
+        return AjaxResult.success(chatKeywordService.selectChatKeywordByKeywordId(keywordId));
+    }
+
+    /**
+     * 新增关键字
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatKeyword:add')")
+    @Log(title = "关键字", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody ChatKeyword chatKeyword)
+    {
+        chatKeyword.setCompanyId(0L);
+        return toAjax(chatKeywordService.insertChatKeyword(chatKeyword));
+    }
+
+    /**
+     * 修改关键字
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatKeyword:edit')")
+    @Log(title = "关键字", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody ChatKeyword chatKeyword)
+    {
+        return toAjax(chatKeywordService.updateChatKeyword(chatKeyword));
+    }
+
+    /**
+     * 删除关键字
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatKeyword:remove')")
+    @Log(title = "关键字", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{keywordIds}")
+    public AjaxResult remove(@PathVariable Long[] keywordIds)
+    {
+        return toAjax(chatKeywordService.deleteChatKeywordByKeywordIds(keywordIds));
+    }
+}

+ 130 - 0
fs-admin/src/main/java/com/fs/chat/controller/ChatMsgController.java

@@ -0,0 +1,130 @@
+package com.fs.chat.controller;
+
+import com.fs.chat.domain.ChatMsg;
+import com.fs.chat.domain.ChatMsgLogs;
+import com.fs.chat.param.ChatMsgListCParam;
+import com.fs.chat.service.IChatMsgLogsService;
+import com.fs.chat.service.IChatMsgService;
+import com.fs.chat.vo.ChatMsgListCVO;
+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.model.LoginUser;
+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.framework.web.service.TokenService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 聊天消息记录Controller
+ *
+ * @author fs
+ * @date 2024-04-19
+ */
+@RestController
+@RequestMapping("/chat/chatMsg")
+public class ChatMsgController extends BaseController
+{
+    @Autowired
+    private IChatMsgService chatMsgService;
+
+
+    @Autowired
+    private IChatMsgLogsService chatMsgLogsService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 查询聊天消息记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatMsg:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(ChatMsgListCParam param)
+    {
+        startPage();
+        List<ChatMsgListCVO> list = chatMsgService.selectChatMsgListCVO(param);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出聊天消息记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatMsg:export')")
+    @Log(title = "聊天消息记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(ChatMsgListCParam param)
+    {
+        List<ChatMsgListCVO> list = chatMsgService.selectChatMsgListCVO(param);
+        ExcelUtil<ChatMsgListCVO> util = new ExcelUtil<ChatMsgListCVO>(ChatMsgListCVO.class);
+        return util.exportExcel(list, "聊天消息记录数据");
+    }
+
+    /**
+     * 获取聊天消息记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatMsg:query')")
+    @GetMapping(value = "/{msgId}")
+    public AjaxResult getInfo(@PathVariable("msgId") Long msgId)
+    {
+        return AjaxResult.success(chatMsgService.selectChatMsgVOByMsgId(msgId));
+    }
+
+    /**
+     * 新增聊天消息记录
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatMsg:add')")
+    @Log(title = "聊天消息记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody ChatMsg chatMsg)
+    {
+        chatMsg.setCompanyId(0L);
+        return toAjax(chatMsgService.insertChatMsg(chatMsg));
+    }
+
+    /**
+     * 修改聊天消息记录
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatMsg:edit')")
+    @Log(title = "聊天消息记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody ChatMsg chatMsg)
+    {
+        if (chatMsg.getStatus()!=null){
+            return toAjax(chatMsgService.updateChatMsg(chatMsg));
+        }
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        ChatMsg map = chatMsgService.selectChatMsgByMsgId(chatMsg.getMsgId());
+        ChatMsgLogs logs = new ChatMsgLogs();
+        logs.setMsgId(chatMsg.getMsgId());
+        logs.setLogsType(2);
+        if (chatMsg.getContent()!=null&&!chatMsg.getContent().equals("")){
+            logs.setContent(chatMsg.getContent());
+        }
+        String userContent = chatMsgService.selectUserContent(map.getMsgId(), map.getUserId(),map.getRoleId());
+        logs.setSContent(map.getContent());
+        logs.setUserContent(userContent);
+        logs.setCreateBy(loginUser.getUser().getNickName());
+        logs.setCompanyId(0L);
+        chatMsgLogsService.insertChatMsgLogs(logs);
+
+        return toAjax(chatMsgService.updateChatMsg(chatMsg));
+    }
+
+    /**
+     * 删除聊天消息记录
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatMsg:remove')")
+    @Log(title = "聊天消息记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{msgIds}")
+    public AjaxResult remove(@PathVariable Long[] msgIds)
+    {
+        return toAjax(chatMsgService.deleteChatMsgByMsgIds(msgIds));
+    }
+}

+ 114 - 0
fs-admin/src/main/java/com/fs/chat/controller/ChatMsgLogsController.java

@@ -0,0 +1,114 @@
+package com.fs.chat.controller;
+
+import com.fs.chat.domain.ChatMsgLogs;
+import com.fs.chat.param.ChatMsgLogsListCParam;
+import com.fs.chat.service.IChatMsgLogsService;
+import com.fs.chat.vo.ChatMsgLogsListCVO;
+import com.fs.chat.vo.ChatMsgLogsVO;
+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.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 消息操作日志Controller
+ *
+ * @author fs
+ * @date 2024-05-10
+ */
+@RestController
+@RequestMapping("/chat/chatMsgLogs")
+public class ChatMsgLogsController extends BaseController
+{
+    @Autowired
+    private IChatMsgLogsService chatMsgLogsService;
+
+
+    /**
+     * 查询消息操作日志列表
+     */
+
+    @GetMapping("/list")
+    public TableDataInfo list(ChatMsgLogs chatMsgLogs)
+    {
+        startPage();
+        List<ChatMsgLogsVO> list = chatMsgLogsService.selectChatMsgLogsListCVO(chatMsgLogs);
+        return getDataTable(list);
+    }
+
+    @GetMapping("/logsList")
+    public R list(ChatMsgLogsListCParam param)
+    {
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<ChatMsgLogsListCVO> list= chatMsgLogsService.selectChatMsgLogsListVO(param);
+        PageInfo<ChatMsgLogsListCVO> listPageInfo=new PageInfo<>(list);
+        return R.ok().put("data",listPageInfo);
+    }
+
+    /**
+     * 导出消息操作日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatMsgLogs:export')")
+    @Log(title = "消息操作日志", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(ChatMsgLogsListCParam chatMsgLogs)
+    {
+        List<ChatMsgLogsListCVO> list = chatMsgLogsService.selectChatMsgLogsListVO(chatMsgLogs);
+        ExcelUtil<ChatMsgLogsListCVO> util = new ExcelUtil<ChatMsgLogsListCVO>(ChatMsgLogsListCVO.class);
+        return util.exportExcel(list, "消息操作日志数据");
+    }
+
+    /**
+     * 获取消息操作日志详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatMsgLogs:query')")
+    @GetMapping(value = "/{logsId}")
+    public AjaxResult getInfo(@PathVariable("logsId") Long logsId)
+    {
+        return AjaxResult.success(chatMsgLogsService.selectChatMsgLogsByLogsId(logsId));
+    }
+
+    /**
+     * 新增消息操作日志
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatMsgLogs:add')")
+    @Log(title = "消息操作日志", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody ChatMsgLogs chatMsgLogs)
+    {
+        return toAjax(chatMsgLogsService.insertChatMsgLogs(chatMsgLogs));
+    }
+
+    /**
+     * 修改消息操作日志
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatMsgLogs:edit')")
+    @Log(title = "消息操作日志", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody ChatMsgLogs chatMsgLogs)
+    {
+        return toAjax(chatMsgLogsService.updateChatMsgLogs(chatMsgLogs));
+    }
+
+    /**
+     * 删除消息操作日志
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatMsgLogs:remove')")
+    @Log(title = "消息操作日志", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{logsIds}")
+    public AjaxResult remove(@PathVariable Long[] logsIds)
+    {
+        return toAjax(chatMsgLogsService.deleteChatMsgLogsByLogsIds(logsIds));
+    }
+}

+ 200 - 0
fs-admin/src/main/java/com/fs/chat/controller/ChatRoleController.java

@@ -0,0 +1,200 @@
+package com.fs.chat.controller;
+
+import cn.hutool.json.JSONUtil;
+import com.fs.chat.config.QwConfig;
+import com.fs.chat.domain.ChatRole;
+import com.fs.chat.param.ChatRoleAddEditCParam;
+import com.fs.chat.service.IChatRoleService;
+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.company.domain.CompanyConfig;
+import com.fs.company.service.ICompanyConfigService;
+
+import com.fs.fastGpt.domain.FastGptRole;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.service.ISysConfigService;
+import com.fs.wx.kf.dto.WeixinKfAddEditAccountDTO;
+import com.fs.wx.kf.dto.WeixinKfDelAccountDTO;
+import com.fs.wx.kf.dto.WeixinKfGetFileDTO;
+import com.fs.wx.kf.dto.WeixinKuGetAccountUrlDTO;
+import com.fs.wx.kf.service.IWeixinKfService;
+import com.fs.wx.kf.vo.WeixinKfAddEditAccountVO;
+import com.fs.wx.kf.vo.WeixinKfDelAccountVO;
+import com.fs.wx.kf.vo.WeixinKfGetAccountUrlVO;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 聊天角色Controller
+ *
+ * @author fs
+ * @date 2024-04-19
+ */
+@RestController
+@RequestMapping("/chat/chatRole")
+public class ChatRoleController extends BaseController
+{
+    @Autowired
+    private ICompanyConfigService companyConfigService;
+    @Autowired
+    private IChatRoleService chatRoleService;
+    @Autowired
+    private IWeixinKfService weixinKfService;
+    @Autowired
+    private ISysConfigService sysConfigService;
+    /**
+     * 查询聊天角色列表
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatRole:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(ChatRole chatRole)
+    {
+        startPage();
+        List<ChatRole> list = chatRoleService.selectChatRoleList(chatRole);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出聊天角色列表
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatRole:export')")
+    @Log(title = "聊天角色", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(ChatRole chatRole)
+    {
+        List<ChatRole> list = chatRoleService.selectChatRoleList(chatRole);
+        ExcelUtil<ChatRole> util = new ExcelUtil<ChatRole>(ChatRole.class);
+        return util.exportExcel(list, "聊天角色数据");
+    }
+
+    /**
+     * 获取聊天角色详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatRole:query')")
+    @GetMapping(value = "/{roleId}")
+    public R getInfo(@PathVariable("roleId") Long roleId)
+    {
+//        SysConfig config = sysConfigService.selectConfigByConfigKey("qw:config");
+////        CompanyConfig config=companyConfigService.selectCompanyConfigByKey(0L,"qw:config");
+//        QwConfig qwConfig= JSONUtil.toBean(config.getConfigValue(), QwConfig.class);
+
+        ChatRole chatRole=chatRoleService.selectChatRoleByRoleId(roleId);
+        return R.ok().put("data",chatRole);
+    }
+
+    /**
+     * 新增聊天角色
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatRole:add')")
+    @Log(title = "聊天角色", businessType = BusinessType.INSERT)
+    @PostMapping
+    public R add(@RequestBody ChatRoleAddEditCParam param)
+    {
+        WeixinKfAddEditAccountDTO dto=new WeixinKfAddEditAccountDTO();
+        dto.setName(param.getRoleName());
+        dto.setMedia_id(param.getKfMediaId());
+        SysConfig config = sysConfigService.selectConfigByConfigKey("qw:config");
+        QwConfig qwConfig= JSONUtil.toBean(config.getConfigValue(), QwConfig.class);
+
+
+
+        WeixinKfAddEditAccountVO vo=weixinKfService.addAccount(qwConfig.getCorpId(),qwConfig.getSecret(),dto);
+        if(vo.getErrcode().equals(0)){
+            WeixinKuGetAccountUrlDTO urlDTO=new WeixinKuGetAccountUrlDTO();
+            urlDTO.setOpen_kfid(vo.getOpen_kfid());
+            WeixinKfGetAccountUrlVO urlVO=weixinKfService.getAccountUrl(qwConfig.getCorpId(),qwConfig.getSecret(),urlDTO);
+
+            ChatRole chatRole=new ChatRole();
+            BeanUtils.copyProperties(param,chatRole);
+            chatRole.setCompanyId(0L);
+            chatRole.setKfId(vo.getOpen_kfid());
+            chatRole.setKfUrl(urlVO.getUrl());
+            if(chatRoleService.insertChatRole(chatRole)>0){
+
+                return R.ok();
+            }
+            else{
+                return R.error();
+            }
+        }
+        else{
+            return R.error(vo.getErrmsg());
+        }
+
+    }
+
+    /**
+     * 修改聊天角色
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatRole:edit')")
+    @Log(title = "聊天角色", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public R edit(@RequestBody ChatRoleAddEditCParam param)
+    {
+        SysConfig config = sysConfigService.selectConfigByConfigKey("qw:config");
+        QwConfig qwConfig= JSONUtil.toBean(config.getConfigValue(), QwConfig.class);
+
+
+        ChatRole chatRole=chatRoleService.selectChatRoleByRoleId(param.getRoleId());
+        WeixinKfAddEditAccountDTO dto=new WeixinKfAddEditAccountDTO();
+        dto.setOpen_kfid(chatRole.getKfId());
+        dto.setName(param.getRoleName());
+        dto.setMedia_id(param.getKfMediaId());
+        WeixinKfAddEditAccountVO vo=weixinKfService.editAccount(qwConfig.getCorpId(),qwConfig.getSecret(),dto);
+        if(vo.getErrcode().equals(0)){
+            BeanUtils.copyProperties(param,chatRole);
+            if(chatRoleService.updateChatRole(chatRole)>0){
+                return R.ok();
+            }
+            else{
+                return R.error();
+            }
+        }
+        else{
+            return R.error(vo.getErrmsg());
+        }
+    }
+
+    /**
+     * 删除聊天角色
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatRole:remove')")
+    @Log(title = "聊天角色", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{roleIds}")
+    public R remove(@PathVariable Long[] roleIds)
+    {
+        SysConfig config = sysConfigService.selectConfigByConfigKey("qw:config");
+        QwConfig qwConfig= JSONUtil.toBean(config.getConfigValue(), QwConfig.class);
+
+        for(Long id:roleIds){
+            ChatRole chatRole=chatRoleService.selectChatRoleByRoleId(id);
+            WeixinKfDelAccountDTO dto=new WeixinKfDelAccountDTO();
+            dto.setOpen_kfid(chatRole.getKfId());
+            WeixinKfDelAccountVO vo=weixinKfService.delAccount(qwConfig.getCorpId(),qwConfig.getSecret(),dto);
+            if(vo.getErrcode().equals(0)){
+
+            }
+            chatRoleService.deleteChatRoleByRoleId(id);
+        }
+        return R.ok();
+    }
+
+    @GetMapping("/getAllRoleList")
+    public R getAllRoleList()
+    {
+        ChatRole chatRole=new ChatRole();
+        List<ChatRole> list = chatRoleService.selectChatRoleList(chatRole);
+        return R.ok().put("data",list);
+    }
+
+}

+ 111 - 0
fs-admin/src/main/java/com/fs/chat/controller/ChatSessionController.java

@@ -0,0 +1,111 @@
+package com.fs.chat.controller;
+
+import com.fs.chat.domain.ChatSession;
+import com.fs.chat.param.ChatSessionListCParam;
+import com.fs.chat.service.IChatMsgService;
+import com.fs.chat.service.IChatSessionService;
+import com.fs.chat.vo.ChatMsgVO;
+import com.fs.chat.vo.ChatSessionCVO;
+import com.fs.chat.vo.ChatSessionListCVO;
+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 org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 会话Controller
+ *
+ * @author fs
+ * @date 2024-05-11
+ */
+@RestController
+@RequestMapping("/chat/chatSession")
+public class ChatSessionController extends BaseController
+{
+    @Autowired
+    private IChatSessionService chatSessionService;
+
+
+    @Autowired
+    private IChatMsgService chatMsgService;
+
+    /**
+     * 查询会话列表
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatSession:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(ChatSessionListCParam param)
+    {
+        startPage();
+        List<ChatSessionListCVO> list = chatSessionService.selectChatSessionListCVO(param);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出会话列表
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatSession:export')")
+    @Log(title = "会话", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(ChatSessionListCParam param)
+    {
+        List<ChatSessionListCVO> list = chatSessionService.selectChatSessionListCVO(param);
+        ExcelUtil<ChatSessionListCVO> util = new ExcelUtil<ChatSessionListCVO>(ChatSessionListCVO.class);
+        return util.exportExcel(list, "会话数据");
+    }
+
+    /**
+     * 获取会话详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatSession:query')")
+    @GetMapping(value = "/{sessionId}")
+    public R getInfo(@PathVariable("sessionId") Long sessionId)
+    {
+        ChatSessionCVO sessionCVO = chatSessionService.selectChatSessionCVOBySessionId(sessionId);
+        List<ChatMsgVO> list = chatMsgService.selectChatMsgBySessionId(sessionId);
+        return R.ok().put("data",sessionCVO).put("list",list);
+    }
+
+    /**
+     * 新增会话
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatSession:add')")
+    @Log(title = "会话", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody ChatSession chatSession)
+    {
+        chatSession.setCompanyId(0L);
+        return toAjax(chatSessionService.insertChatSession(chatSession));
+    }
+
+    /**
+     * 修改会话
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatSession:edit')")
+    @Log(title = "会话", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody ChatSession chatSession)
+    {
+        return toAjax(chatSessionService.updateChatSession(chatSession));
+    }
+
+    /**
+     * 删除会话
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatSession:remove')")
+    @Log(title = "会话", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{sessionIds}")
+    public AjaxResult remove(@PathVariable Long[] sessionIds)
+    {
+        return toAjax(chatSessionService.deleteChatSessionBySessionIds(sessionIds));
+    }
+}

+ 89 - 0
fs-admin/src/main/java/com/fs/chat/controller/ChatUploadController.java

@@ -0,0 +1,89 @@
+package com.fs.chat.controller;
+
+import cn.hutool.json.JSONUtil;
+import com.fs.ai.service.IBaiduAIService;
+import com.fs.chat.config.QwConfig;
+import com.fs.chat.param.ChatUploadFileCParam;
+import com.fs.common.config.FSConfig;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.R;
+import com.fs.common.exception.file.OssException;
+import com.fs.common.utils.file.FileUploadUtils;
+import com.fs.company.domain.CompanyConfig;
+import com.fs.company.service.ICompanyConfigService;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.service.ISysConfigService;
+import com.fs.wx.kf.dto.WeixinKfGetFileDTO;
+import com.fs.wx.kf.dto.WeixinKfUploadDTO;
+import com.fs.wx.kf.service.IWeixinKfService;
+import com.fs.wx.kf.vo.WeixinKfUploadVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+
+@RestController
+@RequestMapping("/chat/upload")
+public class ChatUploadController extends BaseController
+{
+    @Autowired
+    private ICompanyConfigService companyConfigService;
+    @Autowired
+    private IWeixinKfService weixinKfService;
+    @Autowired
+    private IBaiduAIService baiduAIService;
+    @Autowired
+    private ISysConfigService sysConfigService;
+
+
+    @PostMapping("/uploadBaiduDoc")
+    public R uploadBaiduDoc(@RequestParam("file") MultipartFile file,@RequestParam("datasetId") String datasetId) throws Exception
+    {
+        if (file.isEmpty())
+        {
+            throw new OssException("上传文件不能为空");
+        }
+        // 上传文件路径
+        String filePath = FSConfig.getUploadPath();
+        // 上传并返回新文件名称
+        String fileName = FileUploadUtils.upload(filePath, file);
+        String url =filePath + fileName.replaceAll("/profile/upload","");
+        // 上传文件
+        String[] documentIds =baiduAIService.addDocument(datasetId,url);
+        return R.ok().put("data",documentIds);
+    }
+
+
+    @PostMapping("/uploadFile")
+    public R uploadFile(@RequestParam("media") MultipartFile file) throws Exception
+    {
+
+        SysConfig config = sysConfigService.selectConfigByConfigKey("qw:config");
+        QwConfig qwConfig= JSONUtil.toBean(config.getConfigValue(), QwConfig.class);
+
+        if (file.isEmpty())
+        {
+            throw new OssException("上传文件不能为空");
+        }
+        WeixinKfUploadDTO dto=new WeixinKfUploadDTO();
+        dto.setFile(file);
+        dto.setType("image");
+        WeixinKfUploadVO vo= weixinKfService.uploadFile(qwConfig.getCorpId(),qwConfig.getSecret(),dto);
+        WeixinKfGetFileDTO fileDTO=new WeixinKfGetFileDTO();
+        fileDTO.setMedia_id(vo.getMedia_id());
+        String url=weixinKfService.getFile(qwConfig.getCorpId(),qwConfig.getSecret(),fileDTO);
+        vo.setUrl(url);
+        return R.ok().put("data",vo);
+    }
+    @PostMapping("/getUrl")
+    public R getUrl( @RequestBody ChatUploadFileCParam param)
+    {
+        SysConfig config = sysConfigService.selectConfigByConfigKey("qw:config");
+        QwConfig qwConfig= JSONUtil.toBean(config.getConfigValue(), QwConfig.class);
+
+        WeixinKfGetFileDTO dto=new WeixinKfGetFileDTO();
+        dto.setMedia_id(param.getMediaId());
+        String url=weixinKfService.getFile(qwConfig.getCorpId(),qwConfig.getSecret(),dto);
+        return R.ok().put("data",url);
+    }
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/chat/controller/ChatUserController.java

@@ -0,0 +1,97 @@
+package com.fs.chat.controller;
+
+import com.fs.chat.domain.ChatUser;
+import com.fs.chat.service.IChatUserService;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 客户Controller
+ *
+ * @author fs
+ * @date 2024-05-11
+ */
+@RestController
+@RequestMapping("/chat/chatUser")
+public class ChatUserController extends BaseController
+{
+    @Autowired
+    private IChatUserService chatUserService;
+
+    /**
+     * 查询客户列表
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatUser:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(ChatUser chatUser)
+    {
+        startPage();
+        List<ChatUser> list = chatUserService.selectChatUserList(chatUser);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出客户列表
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatUser:export')")
+    @Log(title = "客户", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(ChatUser chatUser)
+    {
+        List<ChatUser> list = chatUserService.selectChatUserList(chatUser);
+        ExcelUtil<ChatUser> util = new ExcelUtil<ChatUser>(ChatUser.class);
+        return util.exportExcel(list, "客户数据");
+    }
+
+    /**
+     * 获取客户详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatUser:query')")
+    @GetMapping(value = "/{userId}")
+    public AjaxResult getInfo(@PathVariable("userId") Long userId)
+    {
+        return AjaxResult.success(chatUserService.selectChatUserByUserId(userId));
+    }
+
+    /**
+     * 新增客户
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatUser:add')")
+    @Log(title = "客户", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody ChatUser chatUser)
+    {
+        return toAjax(chatUserService.insertChatUser(chatUser));
+    }
+
+    /**
+     * 修改客户
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatUser:edit')")
+    @Log(title = "客户", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody ChatUser chatUser)
+    {
+        return toAjax(chatUserService.updateChatUser(chatUser));
+    }
+
+    /**
+     * 删除客户
+     */
+    @PreAuthorize("@ss.hasPermi('chat:chatUser:remove')")
+    @Log(title = "客户", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{userIds}")
+    public AjaxResult remove(@PathVariable Long[] userIds)
+    {
+        return toAjax(chatUserService.deleteChatUserByUserIds(userIds));
+    }
+}

+ 112 - 0
fs-admin/src/main/java/com/fs/chat/controller/FastGptRoleController.java

@@ -0,0 +1,112 @@
+package com.fs.chat.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.fastGpt.domain.FastGptRole;
+import com.fs.fastGpt.service.IFastGptRoleService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 应用Controller
+ *
+ * @author fs
+ * @date 2024-09-30
+ */
+@RestController
+@RequestMapping("/fastGpt/fastGptRole")
+public class FastGptRoleController extends BaseController
+{
+    @Autowired
+    private IFastGptRoleService fastGptRoleService;
+
+
+
+    @GetMapping("/getAllRoleList")
+    public R getAllRoleList()
+    {
+        FastGptRole role=new FastGptRole();
+        role.setRoleType(3);
+        List<FastGptRole> list = fastGptRoleService.selectFastGptRoleList(role);
+        return R.ok().put("data",list);
+    }
+
+    /**
+     * 查询应用列表
+     */
+    @PreAuthorize("@ss.hasPermi('shop:role:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FastGptRole fastgptRole)
+    {
+        startPage();
+        List<FastGptRole> list = fastGptRoleService.selectAiDoctorList(fastgptRole);
+        return getDataTable(list);
+    }
+
+
+    /**
+     * 导出应用列表
+     */
+    @PreAuthorize("@ss.hasPermi('shop:role:export')")
+    @Log(title = "应用", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FastGptRole fastgptRole)
+    {
+        List<FastGptRole> list = fastGptRoleService.selectFastGptRoleList(fastgptRole);
+        ExcelUtil<FastGptRole> util = new ExcelUtil<FastGptRole>(FastGptRole.class);
+        return util.exportExcel(list, "应用数据");
+    }
+
+    /**
+     * 获取应用详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('shop:role:query')")
+    @GetMapping(value = "/{roleId}")
+    public AjaxResult getInfo(@PathVariable("roleId") Long roleId)
+    {
+        return AjaxResult.success(fastGptRoleService.selectFastGptRoleByRoleId(roleId));
+    }
+
+    /**
+     * 新增应用
+     */
+    @PreAuthorize("@ss.hasPermi('shop:role:add')")
+    @Log(title = "应用", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FastGptRole fastgptRole)
+    {
+        fastgptRole.setRoleType(3);
+        return toAjax(fastGptRoleService.insertFastGptRole(fastgptRole));
+    }
+
+    /**
+     * 修改应用
+     */
+    @PreAuthorize("@ss.hasPermi('shop:role:edit')")
+    @Log(title = "应用", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FastGptRole fastgptRole)
+    {
+        return toAjax(fastGptRoleService.updateFastGptRole(fastgptRole));
+    }
+
+    /**
+     * 删除应用
+     */
+    @PreAuthorize("@ss.hasPermi('shop:role:remove')")
+    @Log(title = "应用", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{roleIds}")
+    public AjaxResult remove(@PathVariable Long[] roleIds)
+    {
+        return toAjax(fastGptRoleService.deleteFastGptRoleByRoleIds(roleIds));
+    }
+
+}

+ 9 - 0
fs-admin/src/main/java/com/fs/chat/param/ChatUploadFileCParam.java

@@ -0,0 +1,9 @@
+package com.fs.chat.param;
+
+import lombok.Data;
+
+@Data
+public class ChatUploadFileCParam {
+    String mediaId;
+    Long companyId;
+}

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

@@ -0,0 +1,244 @@
+package com.fs.company.controller;
+
+import cn.hutool.core.util.IdUtil;
+import com.fs.common.annotation.Log;
+import com.fs.common.annotation.RepeatSubmit;
+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.domain.model.LoginUser;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.SecurityUtils;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.utils.sign.Md5Utils;
+import com.fs.company.domain.*;
+import com.fs.company.param.CompanyDeductParam;
+import com.fs.company.param.CompanyParam;
+import com.fs.company.param.CompanyRechargeParam;
+import com.fs.company.param.CompanyVoiceCallerParam;
+import com.fs.company.service.*;
+import com.fs.company.vo.CompanyCrmVO;
+import com.fs.company.vo.CompanyVO;
+import com.fs.company.vo.CompanyVoiceCallerListVO;
+import com.fs.core.utils.OrderCodeUtils;
+import com.fs.framework.web.service.TokenService;
+import com.fs.his.vo.OptionsVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 企业Controller
+ *
+ * @author fs
+ * @date 2021-10-04
+ */
+@RestController
+@RequestMapping("/company/company")
+public class CompanyController extends BaseController
+{
+    @Autowired
+    private TokenService tokenService;
+    @Autowired
+    private ICompanyService companyService;
+    @Autowired
+    private ICompanyUserService userService;
+    @Autowired
+    private ICompanyRechargeService rechargeService;
+    @Autowired
+    private ICompanyDeductService deductService;
+    @Autowired
+    private ICompanyVoiceCallerService callerService;
+    /**
+     * 查询企业列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:company:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyParam param)
+    {
+        startPage();
+        List<CompanyVO> list = companyService.selectCompanyVOList(param);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出企业列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:company:export')")
+    @Log(title = "企业", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyParam company)
+    {
+        List<CompanyVO> list = companyService.selectCompanyVOList(company);
+        ExcelUtil<CompanyVO> util = new ExcelUtil<CompanyVO>(CompanyVO.class);
+        return util.exportExcel(list, "company");
+    }
+
+    /**
+     * 获取企业详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:company:query')")
+    @GetMapping(value = "/{companyId}")
+    public AjaxResult getInfo(@PathVariable("companyId") Long companyId)
+    {
+        return AjaxResult.success(companyService.selectCompanyById(companyId));
+    }
+
+    /**
+     * 新增企业
+     */
+    @PreAuthorize("@ss.hasPermi('company:company:add')")
+    @Log(title = "企业", businessType = BusinessType.INSERT)
+    @PostMapping
+    public R add(@RequestBody Company company)
+    {
+        company.setPassword(SecurityUtils.encryptPassword(company.getPassword()));
+        company.setAppId(Md5Utils.hash(company.getUserName()));
+        company.setAppKey(Md5Utils.hash(company.getPassword()));
+        company.setOmsCode("SF.1");
+        return companyService.insertCompany(company);
+    }
+
+    /**
+     * 修改企业
+     */
+    @PreAuthorize("@ss.hasPermi('company:company:edit')")
+    @Log(title = "企业", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody Company company)
+    {
+        CompanyUser companyUser = new CompanyUser();
+        if (company.getStatus()==0){
+            companyUser.setStatus("1");
+            companyUser.setCompanyId(company.getCompanyId());
+            companyUser.setUserType("00");
+            userService.updateAllCompanyUser(companyUser);
+            CompanyVoiceCallerParam param = new CompanyVoiceCallerParam();
+            param.setCompanyId(company.getCompanyId());
+            List<CompanyVoiceCallerListVO> list = callerService.selectCompanyVoiceCallerListVO(param);
+            for (CompanyVoiceCallerListVO vo : list){
+                CompanyVoiceCaller caller=callerService.selectCompanyVoiceCallerById(vo.getCallerId());
+                caller.setCompanyId(0L);
+                caller.setCompanyUserId(0L);
+                caller.setMobile("");
+                caller.setStatus(1);
+                caller.setBindTime(null);
+                callerService.updateCompanyVoiceCaller(caller);
+            }
+        }
+        return toAjax(companyService.updateCompany(company));
+    }
+
+
+
+    /**
+     * 删除企业
+     */
+    @PreAuthorize("@ss.hasPermi('company:company:remove')")
+    @Log(title = "企业", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{companyIds}")
+    public AjaxResult remove(@PathVariable Long[] companyIds)
+    {
+        return toAjax(companyService.deleteCompanyByIds(companyIds));
+    }
+
+    @GetMapping("/getCompanyList")
+    public R getCompanyList()
+    {
+        Company map=new Company();
+        map.setIsDel(0);
+        List<Company> list = companyService.selectCompanyList(map);
+        return R.ok().put("data",list);
+    }
+
+
+//  @PreAuthorize("@ss.hasPermi('company:company:crmDayCountlist')")
+    @GetMapping("/crmDayCountlist")
+    public TableDataInfo companyCrmDayCountList(CompanyParam param)
+    {
+        startPage();
+        List<CompanyCrmVO> list = companyService.selectCompanyCrmDayCountList(param);
+        return getDataTable(list);
+    }
+
+
+
+    @PreAuthorize("@ss.hasPermi('company:company:resetPwd')")
+    @PostMapping("/resetPwd/{companyId}")
+    public AjaxResult resetPwd(@PathVariable Long companyId)
+    {
+        Company company=companyService.selectCompanyById(companyId);
+        return toAjax(userService.resetUserPwdByUserId(company.getUserId(),SecurityUtils.encryptPassword("123456")));
+    }
+
+//    @PreAuthorize("@ss.hasPermi('company:company:resetMoney')")
+//    @PostMapping("/resetMoney/{companyId}")
+//    public R resetMoney(@PathVariable Long companyId)
+//    {
+//        //companyService.resetMoney(companyId);
+//        return R.ok("功能已停用");
+//    }
+
+
+    @PreAuthorize("@ss.hasPermi('company:company:recharge')")
+    @Log(title = "企业转账", businessType = BusinessType.INSERT)
+    @PostMapping(value = "/recharge")
+    @Transactional
+    @RepeatSubmit
+    public R recharge(@RequestBody CompanyRechargeParam param)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        CompanyRecharge recharge=new CompanyRecharge();
+        String orderSn =  OrderCodeUtils.getOrderSn();
+        if(StringUtils.isEmpty(orderSn)){
+            return R.error("订单生成失败,请重试");
+        }
+        recharge.setRechargeNo(orderSn);
+        recharge.setCompanyId(param.getCompanyId());
+        recharge.setMoney(param.getMoney());
+        recharge.setCreateUserId(loginUser.getUser().getUserId());
+        recharge.setIsAudit(0);
+        recharge.setStatus(0);
+        recharge.setRemark(param.getRemark());
+        recharge.setPayType(3);
+        rechargeService.insertCompanyRecharge(recharge);
+        return R.ok("提交成功,等待审核");
+
+    }
+
+    @PreAuthorize("@ss.hasPermi('company:company:deduct')")
+    @Log(title = "企业扣款", businessType = BusinessType.INSERT)
+    @PostMapping(value = "/deduct")
+    @Transactional
+    @RepeatSubmit
+    public R deduct(@RequestBody CompanyDeductParam param)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        CompanyDeduct deduct=new CompanyDeduct();
+        String orderSn =  OrderCodeUtils.getOrderSn();
+        if(StringUtils.isEmpty(orderSn)){
+            return R.error("订单生成失败,请重试");
+        }
+        deduct.setDeductNo(orderSn);
+        deduct.setCompanyId(param.getCompanyId());
+        deduct.setMoney(param.getMoney());
+        deduct.setCreateUserId(loginUser.getUser().getUserId());
+        deduct.setIsAudit(0);
+        deduct.setRemark(param.getRemark());
+        deductService.insertCompanyDeduct(deduct);
+        return R.ok("提交成功,等待审核");
+    }
+
+    @GetMapping("/allList")
+    public TableDataInfo getHospital()
+    {
+        List<OptionsVO> list = companyService.selectAllCompanyList();
+        return getDataTable(list);
+    }
+}

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

@@ -0,0 +1,103 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyDept;
+import com.fs.company.service.ICompanyDeptService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+
+@RestController
+@RequestMapping("/company/companyDept")
+public class CompanyDeptController extends BaseController
+{
+    @Autowired
+    private ICompanyDeptService companyDeptService;
+
+    /**
+     * 查询部门列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDept:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyDept companyDept)
+    {
+        startPage();
+        List<CompanyDept> list = companyDeptService.selectCompanyDeptList(companyDept);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出部门列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDept:export')")
+    @Log(title = "部门", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyDept companyDept)
+    {
+        List<CompanyDept> list = companyDeptService.selectCompanyDeptList(companyDept);
+        ExcelUtil<CompanyDept> util = new ExcelUtil<CompanyDept>(CompanyDept.class);
+        return util.exportExcel(list, "companyDept");
+    }
+
+    /**
+     * 获取部门详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDept:query')")
+    @GetMapping(value = "/{deptId}")
+    public AjaxResult getInfo(@PathVariable("deptId") Long deptId)
+    {
+        return AjaxResult.success(companyDeptService.selectCompanyDeptById(deptId));
+    }
+
+    /**
+     * 新增部门
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDept:add')")
+    @Log(title = "部门", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyDept companyDept)
+    {
+        return toAjax(companyDeptService.insertCompanyDept(companyDept));
+    }
+
+    /**
+     * 修改部门
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDept:edit')")
+    @Log(title = "部门", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyDept companyDept)
+    {
+        return toAjax(companyDeptService.updateCompanyDept(companyDept));
+    }
+
+    /**
+     * 删除部门
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyDept:remove')")
+    @Log(title = "部门", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{deptIds}")
+    public AjaxResult remove(@PathVariable Long[] deptIds)
+    {
+        return toAjax(companyDeptService.deleteCompanyDeptByIds(deptIds));
+    }
+
+    /**
+     * 获取部门下拉树列表
+     */
+    @GetMapping("/treeselect")
+    public AjaxResult treeselect(CompanyDept dept)
+    {
+        dept.setStatus("0");
+        List<CompanyDept> depts = companyDeptService.selectCompanyDeptList(dept);
+        return AjaxResult.success(companyDeptService.buildDeptTreeSelect(depts));
+    }
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyLogininforController.java

@@ -0,0 +1,97 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyLogininfor;
+import com.fs.company.service.ICompanyLogininforService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 系统访问记录Controller
+ *
+ * @author fs
+ * @date 2021-10-04
+ */
+@RestController
+@RequestMapping("/company/companyLogininfor")
+public class CompanyLogininforController extends BaseController
+{
+    @Autowired
+    private ICompanyLogininforService companyLogininforService;
+
+    /**
+     * 查询系统访问记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyLogininfor:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyLogininfor companyLogininfor)
+    {
+        startPage();
+        List<CompanyLogininfor> list = companyLogininforService.selectCompanyLogininforList(companyLogininfor);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出系统访问记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyLogininfor:export')")
+    @Log(title = "系统访问记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyLogininfor companyLogininfor)
+    {
+        List<CompanyLogininfor> list = companyLogininforService.selectCompanyLogininforList(companyLogininfor);
+        ExcelUtil<CompanyLogininfor> util = new ExcelUtil<CompanyLogininfor>(CompanyLogininfor.class);
+        return util.exportExcel(list, "companyLogininfor");
+    }
+
+    /**
+     * 获取系统访问记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyLogininfor:query')")
+    @GetMapping(value = "/{infoId}")
+    public AjaxResult getInfo(@PathVariable("infoId") Long infoId)
+    {
+        return AjaxResult.success(companyLogininforService.selectCompanyLogininforById(infoId));
+    }
+
+    /**
+     * 新增系统访问记录
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyLogininfor:add')")
+    @Log(title = "系统访问记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyLogininfor companyLogininfor)
+    {
+        return toAjax(companyLogininforService.insertCompanyLogininfor(companyLogininfor));
+    }
+
+    /**
+     * 修改系统访问记录
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyLogininfor:edit')")
+    @Log(title = "系统访问记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyLogininfor companyLogininfor)
+    {
+        return toAjax(companyLogininforService.updateCompanyLogininfor(companyLogininfor));
+    }
+
+    /**
+     * 删除系统访问记录
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyLogininfor:remove')")
+    @Log(title = "系统访问记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{infoIds}")
+    public AjaxResult remove(@PathVariable Long[] infoIds)
+    {
+        return toAjax(companyLogininforService.deleteCompanyLogininforByIds(infoIds));
+    }
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyMenuController.java

@@ -0,0 +1,97 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyMenu;
+import com.fs.company.service.ICompanyMenuService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 菜单权限Controller
+ *
+ * @author fs
+ * @date 2021-10-04
+ */
+@RestController
+@RequestMapping("/company/companyMenu")
+public class CompanyMenuController extends BaseController
+{
+    @Autowired
+    private ICompanyMenuService companyMenuService;
+
+    /**
+     * 查询菜单权限列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyMenu:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyMenu companyMenu)
+    {
+        startPage();
+        List<CompanyMenu> list = companyMenuService.selectCompanyMenuList(companyMenu);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出菜单权限列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyMenu:export')")
+    @Log(title = "菜单权限", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyMenu companyMenu)
+    {
+        List<CompanyMenu> list = companyMenuService.selectCompanyMenuList(companyMenu);
+        ExcelUtil<CompanyMenu> util = new ExcelUtil<CompanyMenu>(CompanyMenu.class);
+        return util.exportExcel(list, "companyMenu");
+    }
+
+    /**
+     * 获取菜单权限详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyMenu:query')")
+    @GetMapping(value = "/{menuId}")
+    public AjaxResult getInfo(@PathVariable("menuId") Long menuId)
+    {
+        return AjaxResult.success(companyMenuService.selectCompanyMenuById(menuId));
+    }
+
+    /**
+     * 新增菜单权限
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyMenu:add')")
+    @Log(title = "菜单权限", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyMenu companyMenu)
+    {
+        return toAjax(companyMenuService.insertCompanyMenu(companyMenu));
+    }
+
+    /**
+     * 修改菜单权限
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyMenu:edit')")
+    @Log(title = "菜单权限", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyMenu companyMenu)
+    {
+        return toAjax(companyMenuService.updateCompanyMenu(companyMenu));
+    }
+
+    /**
+     * 删除菜单权限
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyMenu:remove')")
+    @Log(title = "菜单权限", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{menuIds}")
+    public AjaxResult remove(@PathVariable Long[] menuIds)
+    {
+        return toAjax(companyMenuService.deleteCompanyMenuByIds(menuIds));
+    }
+}

+ 179 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyMoneyLogsController.java

@@ -0,0 +1,179 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ParseUtils;
+import com.fs.common.utils.SecurityUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyDept;
+import com.fs.company.domain.CompanyMoneyLogs;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.param.CompanyMoneyLogsParam;
+import com.fs.company.service.ICompanyDeptService;
+import com.fs.company.service.ICompanyMoneyLogsService;
+import com.fs.company.service.ICompanyService;
+import com.fs.company.service.ICompanyUserService;
+import com.fs.company.vo.CompanyMoneyLogsExport1VO;
+import com.fs.company.vo.CompanyMoneyLogsExport2VO;
+import com.fs.company.vo.CompanyMoneyLogsExportVO;
+import com.fs.company.vo.CompanyMoneyLogsVO;
+import com.fs.his.domain.FsExportTask;
+import com.fs.his.domain.FsInquiryOrder;
+import com.fs.his.domain.FsStoreOrder;
+import com.fs.his.domain.FsStorePayment;
+import com.fs.his.param.FsCompanyMoneyLogsExportParam;
+import com.fs.his.service.IFsExportTaskService;
+import com.fs.his.service.IFsInquiryOrderService;
+import com.fs.his.service.IFsStoreOrderService;
+import com.fs.his.service.IFsStorePaymentService;
+import com.fs.his.vo.FsStoreOrderExportVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 企业账户记录Controller
+ *
+ * @author fs
+ * @date 2021-10-04
+ */
+@RestController
+@RequestMapping("/company/companyMoneyLogs")
+public class CompanyMoneyLogsController extends BaseController
+{
+    @Autowired
+    private ICompanyMoneyLogsService companyMoneyLogsService;
+
+    @Autowired
+    private IFsExportTaskService exportTaskService;
+
+    /**
+     * 查询企业账户记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyMoneyLogs:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyMoneyLogsParam companyMoneyLogs)
+    {
+        startPage();
+        if(!StringUtils.isEmpty(companyMoneyLogs.getCreateTimeRange())){
+            companyMoneyLogs.setCreateTimeList(companyMoneyLogs.getCreateTimeRange().split("--"));
+        }
+        if(companyMoneyLogs.getLogsType()!=null){
+            if(companyMoneyLogs.getLogsType()==3 || companyMoneyLogs.getLogsType()==4 || companyMoneyLogs.getLogsType()==5 || companyMoneyLogs.getLogsType()==6 || companyMoneyLogs.getLogsType()==13|| companyMoneyLogs.getLogsType()==14){
+                List<CompanyMoneyLogsVO> list = companyMoneyLogsService.selectCompanyMoneyLogsMallVOList(companyMoneyLogs);
+                return getDataTable(list);
+            }
+        }
+        List<CompanyMoneyLogsVO> list = companyMoneyLogsService.selectCompanyMoneyLogsVOList(companyMoneyLogs);
+        return getDataTable(list);
+    }
+
+
+    //转账记录
+    @PreAuthorize("@ss.hasPermi('company:companyMoneyLogs:list1')")
+    @GetMapping("/list1")
+
+    public TableDataInfo list1(CompanyMoneyLogsParam companyMoneyLogs)
+    {
+        startPage();
+        companyMoneyLogs.setLogsType(1);
+        List<CompanyMoneyLogsVO> list = companyMoneyLogsService.selectCompanyMoneyLogsVOList(companyMoneyLogs);
+        return getDataTable(list);
+    }
+    //转账记录
+    @PreAuthorize("@ss.hasPermi('company:companyMoneyLogs:list2')")
+    @GetMapping("/list2")
+
+    public TableDataInfo list2(CompanyMoneyLogsParam companyMoneyLogs) {
+        startPage();
+        companyMoneyLogs.setLogsType(2);
+        List<CompanyMoneyLogsVO> list = companyMoneyLogsService.selectCompanyMoneyLogsVOList(companyMoneyLogs);
+        return getDataTable(list);
+    }
+    //扣款
+    @PreAuthorize("@ss.hasPermi('company:companyMoneyLogs:list3')")
+    @GetMapping("/list3")
+    public TableDataInfo list3(CompanyMoneyLogsParam companyMoneyLogs) {
+        startPage();
+        companyMoneyLogs.setLogsType(3);
+        List<CompanyMoneyLogsVO> list = companyMoneyLogsService.selectCompanyMoneyLogsVOList(companyMoneyLogs);
+        return getDataTable(list);
+    }
+    /**
+     * 导出企业账户记录列表
+     */
+    @PreAuthorize("@ss.hasAnyPermi('company:companyMoneyLogs:export,company:companyMoneyLogs:export1,company:companyMoneyLogs:export2')")
+    @Log(title = "企业账户记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsCompanyMoneyLogsExportParam param)   {
+        if(!StringUtils.isEmpty(param.getCreateTimeRange())){
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        Integer exportType1 = exportTaskService.isExportType1(SecurityUtils.getUserId());
+        if (exportType1>0){
+            return AjaxResult.error("你已经有正在导出的任务");
+        }
+        //导出全部
+        if(param.getType().equals(0)){
+            //判断是否达到数据上线
+            Integer count=companyMoneyLogsService.selectCompanyMoneyLogsExportCounts(param);
+            if(count>30000){
+                return AjaxResult.error("导出数据已超出上限,最多可导出30000条数据");
+            }
+            FsExportTask task=new FsExportTask();
+            task.setTaskType(1);
+            task.setStatus(0);
+            task.setStartTime(new Date());
+            task.setRemark("账户流水导出");
+            task.setSysType(1);
+            task.setUserId(SecurityUtils.getUserId());
+            exportTaskService.insertFsExportTask(task);
+            param.setTaskId(task.getTaskId());
+            companyMoneyLogsService.exportData(param);
+            return new AjaxResult(200,"后台正在导出,请等待...任务ID:"+task.getTaskId(),task.getTaskId());
+        }
+        else if(param.getType().equals(1))
+        {
+            Integer count=companyMoneyLogsService.selectCompanyMoneyLogsExport1Counts(param);
+            if(count>30000){
+                return AjaxResult.error("导出数据已超出上限,最多可导出30000条数据");
+            }
+            FsExportTask task=new FsExportTask();
+            task.setTaskType(1);
+            task.setStatus(0);
+            task.setStartTime(new Date());
+            task.setSysType(1);
+            task.setRemark("导出商城订单明细");
+            task.setUserId(SecurityUtils.getUserId());
+            exportTaskService.insertFsExportTask(task);
+            param.setTaskId(task.getTaskId());
+            companyMoneyLogsService.exportData(param);
+            return new AjaxResult(200,"后台正在导出,任务ID:"+task.getTaskId(),task.getTaskId());
+        }
+        return new AjaxResult(500,"导出失败");
+
+    }
+
+    /**
+     * 获取企业账户记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyMoneyLogs:query')")
+    @GetMapping(value = "/{logsId}")
+    public AjaxResult getInfo(@PathVariable("logsId") Long logsId) {
+        return AjaxResult.success(companyMoneyLogsService.selectCompanyMoneyLogsById(logsId));
+    }
+
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyOperLogController.java

@@ -0,0 +1,97 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyOperLog;
+import com.fs.company.service.ICompanyOperLogService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 操作日志记录Controller
+ *
+ * @author fs
+ * @date 2021-10-04
+ */
+@RestController
+@RequestMapping("/company/companyOperLog")
+public class CompanyOperLogController extends BaseController
+{
+    @Autowired
+    private ICompanyOperLogService companyOperLogService;
+
+    /**
+     * 查询操作日志记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyOperLog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyOperLog companyOperLog)
+    {
+        startPage();
+        List<CompanyOperLog> list = companyOperLogService.selectCompanyOperLogList(companyOperLog);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出操作日志记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyOperLog:export')")
+    @Log(title = "操作日志记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyOperLog companyOperLog)
+    {
+        List<CompanyOperLog> list = companyOperLogService.selectCompanyOperLogList(companyOperLog);
+        ExcelUtil<CompanyOperLog> util = new ExcelUtil<CompanyOperLog>(CompanyOperLog.class);
+        return util.exportExcel(list, "companyOperLog");
+    }
+
+    /**
+     * 获取操作日志记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyOperLog:query')")
+    @GetMapping(value = "/{operId}")
+    public AjaxResult getInfo(@PathVariable("operId") Long operId)
+    {
+        return AjaxResult.success(companyOperLogService.selectCompanyOperLogById(operId));
+    }
+
+    /**
+     * 新增操作日志记录
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyOperLog:add')")
+    @Log(title = "操作日志记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyOperLog companyOperLog)
+    {
+        return toAjax(companyOperLogService.insertCompanyOperLog(companyOperLog));
+    }
+
+    /**
+     * 修改操作日志记录
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyOperLog:edit')")
+    @Log(title = "操作日志记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyOperLog companyOperLog)
+    {
+        return toAjax(companyOperLogService.updateCompanyOperLog(companyOperLog));
+    }
+
+    /**
+     * 删除操作日志记录
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyOperLog:remove')")
+    @Log(title = "操作日志记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{operIds}")
+    public AjaxResult remove(@PathVariable Long[] operIds)
+    {
+        return toAjax(companyOperLogService.deleteCompanyOperLogByIds(operIds));
+    }
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyPostController.java

@@ -0,0 +1,97 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyPost;
+import com.fs.company.service.ICompanyPostService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 岗位信息Controller
+ *
+ * @author fs
+ * @date 2021-10-04
+ */
+@RestController
+@RequestMapping("/company/companyPost")
+public class CompanyPostController extends BaseController
+{
+    @Autowired
+    private ICompanyPostService companyPostService;
+
+    /**
+     * 查询岗位信息列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyPost:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyPost companyPost)
+    {
+        startPage();
+        List<CompanyPost> list = companyPostService.selectCompanyPostList(companyPost);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出岗位信息列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyPost:export')")
+    @Log(title = "岗位信息", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyPost companyPost)
+    {
+        List<CompanyPost> list = companyPostService.selectCompanyPostList(companyPost);
+        ExcelUtil<CompanyPost> util = new ExcelUtil<CompanyPost>(CompanyPost.class);
+        return util.exportExcel(list, "companyPost");
+    }
+
+    /**
+     * 获取岗位信息详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyPost:query')")
+    @GetMapping(value = "/{postId}")
+    public AjaxResult getInfo(@PathVariable("postId") Long postId)
+    {
+        return AjaxResult.success(companyPostService.selectCompanyPostById(postId));
+    }
+
+    /**
+     * 新增岗位信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyPost:add')")
+    @Log(title = "岗位信息", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyPost companyPost)
+    {
+        return toAjax(companyPostService.insertCompanyPost(companyPost));
+    }
+
+    /**
+     * 修改岗位信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyPost:edit')")
+    @Log(title = "岗位信息", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyPost companyPost)
+    {
+        return toAjax(companyPostService.updateCompanyPost(companyPost));
+    }
+
+    /**
+     * 删除岗位信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyPost:remove')")
+    @Log(title = "岗位信息", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{postIds}")
+    public AjaxResult remove(@PathVariable Long[] postIds)
+    {
+        return toAjax(companyPostService.deleteCompanyPostByIds(postIds));
+    }
+}

+ 276 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyProfitController.java

@@ -0,0 +1,276 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyMoneyLogs;
+import com.fs.company.domain.CompanyProfit;
+import com.fs.company.domain.CompanyProfitLogs;
+import com.fs.company.param.CompanyProfitAuditParam;
+import com.fs.company.service.ICompanyMoneyLogsService;
+import com.fs.company.service.ICompanyProfitLogsService;
+import com.fs.company.service.ICompanyProfitService;
+import com.fs.company.service.ICompanyService;
+import com.fs.company.vo.CompanyProfitVO;
+import com.fs.framework.web.service.TokenService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 提现Controller
+ *
+ * @author fs
+ * @date 2022-07-04
+ */
+@RestController
+@RequestMapping("/company/companyProfit")
+public class CompanyProfitController extends BaseController
+{
+    @Autowired
+    private ICompanyProfitService companyProfitService;
+    @Autowired
+    private ICompanyService companyService;
+    @Autowired
+    private ICompanyMoneyLogsService moneyLogsService;
+    @Autowired
+    private ICompanyProfitLogsService logsService;
+    @Autowired
+    private TokenService tokenService;
+    /**
+     * 查询提现列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyProfit:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyProfit companyProfit)
+    {
+        startPage();
+        List<CompanyProfitVO> list = companyProfitService.selectCompanyProfitListVO(companyProfit);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出提现列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyProfit:export')")
+    @Log(title = "提现", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyProfit companyProfit)
+    {
+        List<CompanyProfitVO> list = companyProfitService.selectCompanyProfitListVO(companyProfit);
+        ExcelUtil<CompanyProfitVO> util = new ExcelUtil<CompanyProfitVO>(CompanyProfitVO.class);
+        return util.exportExcel(list, "公司提现记录");
+    }
+
+    /**
+     * 获取提现详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyProfit:query')")
+    @GetMapping(value = "/{profitId}")
+    public R getInfo(@PathVariable("profitId") Long profitId)
+    {
+        CompanyProfit profit=companyProfitService.selectCompanyProfitById(profitId);
+        CompanyProfitLogs map=new CompanyProfitLogs();
+        map.setProfitId(profitId);
+        List<CompanyProfitLogs> logs= logsService.selectCompanyProfitLogsList(map);
+        return R.ok().put("profit",profit).put("logs",logs);
+    }
+
+    /**
+     * 新增提现
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyProfit:add')")
+    @Log(title = "提现", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyProfit companyProfit)
+    {
+        return toAjax(companyProfitService.insertCompanyProfit(companyProfit));
+    }
+
+    /**
+     * 修改提现
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyProfit:edit')")
+    @Log(title = "提现", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyProfit companyProfit)
+    {
+        return toAjax(companyProfitService.updateCompanyProfit(companyProfit));
+    }
+
+    /**
+     * 删除提现
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyProfit:remove')")
+    @Log(title = "提现", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{profitIds}")
+    public AjaxResult remove(@PathVariable Long[] profitIds)
+    {
+        return toAjax(companyProfitService.deleteCompanyProfitByIds(profitIds));
+    }
+
+    @PreAuthorize("@ss.hasPermi('company:companyProfit:audit1')")
+    @PostMapping("/audit1")
+    @Transactional
+    public R audit1(@RequestBody CompanyProfitAuditParam param)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        CompanyProfit profit=companyProfitService.selectCompanyProfitById(param.getProfitId());
+        if(profit.getProfitStatus()!=1){
+            return R.error("非法操作");
+        }
+        Company company=companyService.selectCompanyByIdForUpdate(profit.getCompanyId());
+        if(param.getStatus()==1){
+            profit.setRemark(param.getRemark());
+            profit.setProfitStatus(2);
+            profit.setUpdateTime(new Date());
+            companyProfitService.updateCompanyProfit(profit);
+            CompanyProfitLogs logs=new CompanyProfitLogs();
+            logs.setProfitId(profit.getProfitId());
+            logs.setReason(param.getRemark());
+            logs.setCreateTime(new Date());
+            logs.setTitle(loginUser.getUser().getNickName()+"审核通过");
+            logsService.insertCompanyProfitLogs(logs);
+        }
+        else if(param.getStatus()==0){
+            //驳回退款
+            profit.setRemark(param.getRemark());
+            profit.setProfitStatus(0);
+            profit.setUpdateTime(new Date());
+            companyProfitService.updateCompanyProfit(profit);
+            company.setMoney(company.getMoney().add(profit.getMoney()));
+            companyService.updateCompany(company);
+            CompanyMoneyLogs logs=new CompanyMoneyLogs();
+            logs.setCompanyId(company.getCompanyId());
+            logs.setMoney(profit.getMoney());
+            logs.setLogsType(8);
+            logs.setBalance(company.getMoney());
+            logs.setRemark("驳回退款:"+profit.getMoney());
+            logs.setCreateTime(new Date());
+            moneyLogsService.insertCompanyMoneyLogs(logs);
+
+            CompanyProfitLogs profitLogs=new CompanyProfitLogs();
+            profitLogs.setProfitId(profit.getProfitId());
+            profitLogs.setReason(param.getRemark());
+            profitLogs.setCreateTime(new Date());
+            profitLogs.setTitle(loginUser.getUser().getNickName()+"驳回退款");
+            logsService.insertCompanyProfitLogs(profitLogs);
+        }
+        return R.ok("操作成功");
+    }
+
+    @PreAuthorize("@ss.hasPermi('company:companyProfit:audit2')")
+    @PostMapping("/audit2")
+    @Transactional
+    public R audit2(@RequestBody CompanyProfitAuditParam param)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        CompanyProfit profit=companyProfitService.selectCompanyProfitById(param.getProfitId());
+        if(profit.getProfitStatus()!=2){
+            return R.error("非法操作");
+        }
+
+        if(param.getStatus()==1){
+            profit.setRemark(param.getRemark());
+            profit.setProfitStatus(4);
+            profit.setUpdateTime(new Date());
+            companyProfitService.updateCompanyProfit(profit);
+            CompanyProfitLogs logs=new CompanyProfitLogs();
+            logs.setProfitId(profit.getProfitId());
+            logs.setReason(param.getRemark());
+            logs.setCreateTime(new Date());
+            logs.setTitle(loginUser.getUser().getNickName()+"审核通过");
+            logsService.insertCompanyProfitLogs(logs);
+        }
+        else if(param.getStatus()==0){
+            //驳回退款
+            profit.setRemark(param.getRemark());
+            profit.setProfitStatus(0);
+            profit.setUpdateTime(new Date());
+            companyProfitService.updateCompanyProfit(profit);
+            Company company=companyService.selectCompanyByIdForUpdate(profit.getCompanyId());
+            company.setMoney(company.getMoney().add(profit.getMoney()));
+            companyService.updateCompany(company);
+            CompanyMoneyLogs logs=new CompanyMoneyLogs();
+            logs.setCompanyId(company.getCompanyId());
+            logs.setMoney(profit.getMoney());
+            logs.setLogsType(8);
+            logs.setBalance(company.getMoney());
+            logs.setRemark("驳回退款:"+profit.getMoney());
+            logs.setCreateTime(new Date());
+            moneyLogsService.insertCompanyMoneyLogs(logs);
+
+            CompanyProfitLogs profitLogs=new CompanyProfitLogs();
+            profitLogs.setProfitId(profit.getProfitId());
+            profitLogs.setReason(param.getRemark());
+            profitLogs.setCreateTime(new Date());
+            profitLogs.setTitle(loginUser.getUser().getNickName()+"驳回退款");
+            logsService.insertCompanyProfitLogs(profitLogs);
+        }
+        return R.ok("操作成功");
+    }
+
+    @PreAuthorize("@ss.hasPermi('company:companyProfit:audit3')")
+    @PostMapping("/audit3")
+    @Transactional
+    public R audit3(@RequestBody CompanyProfitAuditParam param)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        CompanyProfit profit=companyProfitService.selectCompanyProfitById(param.getProfitId());
+        if(profit.getProfitStatus()!=3){
+            return R.error("非法操作");
+        }
+        Company company=companyService.selectCompanyByIdForUpdate(profit.getCompanyId());
+        if(param.getStatus()==1){
+            profit.setRemark(param.getRemark());
+            profit.setProfitStatus(4);
+            profit.setUpdateTime(new Date());
+            profit.setImgUrl(param.getImgUrl());
+            companyProfitService.updateCompanyProfit(profit);
+            CompanyProfitLogs logs=new CompanyProfitLogs();
+            logs.setProfitId(profit.getProfitId());
+            logs.setReason(param.getRemark());
+            logs.setCreateTime(new Date());
+            logs.setTitle(loginUser.getUser().getNickName()+"审核通过");
+            logsService.insertCompanyProfitLogs(logs);
+        }
+        else if(param.getStatus()==0){
+            //驳回退款
+            profit.setRemark(param.getRemark());
+            profit.setProfitStatus(0);
+            profit.setUpdateTime(new Date());
+            companyProfitService.updateCompanyProfit(profit);
+            company.setMoney(company.getMoney().add(profit.getMoney()));
+            companyService.updateCompany(company);
+            CompanyMoneyLogs logs=new CompanyMoneyLogs();
+            logs.setCompanyId(company.getCompanyId());
+            logs.setMoney(profit.getMoney());
+            logs.setLogsType(8);
+            logs.setBalance(company.getMoney());
+            logs.setRemark("驳回退款:"+profit.getMoney());
+            logs.setCreateTime(new Date());
+            moneyLogsService.insertCompanyMoneyLogs(logs);
+
+            CompanyProfitLogs profitLogs=new CompanyProfitLogs();
+            profitLogs.setProfitId(profit.getProfitId());
+            profitLogs.setReason(param.getRemark());
+            profitLogs.setCreateTime(new Date());
+            profitLogs.setTitle(loginUser.getUser().getNickName()+"驳回退款");
+            logsService.insertCompanyProfitLogs(profitLogs);
+        }
+        return R.ok("操作成功");
+    }
+
+
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyRoleController.java

@@ -0,0 +1,97 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyRole;
+import com.fs.company.service.ICompanyRoleService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 角色信息Controller
+ *
+ * @author fs
+ * @date 2021-10-04
+ */
+@RestController
+@RequestMapping("/company/companyRole")
+public class CompanyRoleController extends BaseController
+{
+    @Autowired
+    private ICompanyRoleService companyRoleService;
+
+    /**
+     * 查询角色信息列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRole:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyRole companyRole)
+    {
+        startPage();
+        List<CompanyRole> list = companyRoleService.selectCompanyRoleList(companyRole);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出角色信息列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRole:export')")
+    @Log(title = "角色信息", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyRole companyRole)
+    {
+        List<CompanyRole> list = companyRoleService.selectCompanyRoleList(companyRole);
+        ExcelUtil<CompanyRole> util = new ExcelUtil<CompanyRole>(CompanyRole.class);
+        return util.exportExcel(list, "companyRole");
+    }
+
+    /**
+     * 获取角色信息详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRole:query')")
+    @GetMapping(value = "/{roleId}")
+    public AjaxResult getInfo(@PathVariable("roleId") Long roleId)
+    {
+        return AjaxResult.success(companyRoleService.selectCompanyRoleById(roleId));
+    }
+
+    /**
+     * 新增角色信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRole:add')")
+    @Log(title = "角色信息", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyRole companyRole)
+    {
+        return toAjax(companyRoleService.insertCompanyRole(companyRole));
+    }
+
+    /**
+     * 修改角色信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRole:edit')")
+    @Log(title = "角色信息", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyRole companyRole)
+    {
+        return toAjax(companyRoleService.updateCompanyRole(companyRole));
+    }
+
+    /**
+     * 删除角色信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRole:remove')")
+    @Log(title = "角色信息", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{roleIds}")
+    public AjaxResult remove(@PathVariable Long[] roleIds)
+    {
+        return toAjax(companyRoleService.deleteCompanyRoleByIds(roleIds));
+    }
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyRoleDeptController.java

@@ -0,0 +1,97 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyRoleDept;
+import com.fs.company.service.ICompanyRoleDeptService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 角色和部门关联Controller
+ *
+ * @author fs
+ * @date 2021-10-04
+ */
+@RestController
+@RequestMapping("/company/companyRoleDept")
+public class CompanyRoleDeptController extends BaseController
+{
+    @Autowired
+    private ICompanyRoleDeptService companyRoleDeptService;
+
+    /**
+     * 查询角色和部门关联列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRoleDept:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyRoleDept companyRoleDept)
+    {
+        startPage();
+        List<CompanyRoleDept> list = companyRoleDeptService.selectCompanyRoleDeptList(companyRoleDept);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出角色和部门关联列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRoleDept:export')")
+    @Log(title = "角色和部门关联", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyRoleDept companyRoleDept)
+    {
+        List<CompanyRoleDept> list = companyRoleDeptService.selectCompanyRoleDeptList(companyRoleDept);
+        ExcelUtil<CompanyRoleDept> util = new ExcelUtil<CompanyRoleDept>(CompanyRoleDept.class);
+        return util.exportExcel(list, "companyRoleDept");
+    }
+
+    /**
+     * 获取角色和部门关联详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRoleDept:query')")
+    @GetMapping(value = "/{roleId}")
+    public AjaxResult getInfo(@PathVariable("roleId") Long roleId)
+    {
+        return AjaxResult.success(companyRoleDeptService.selectCompanyRoleDeptById(roleId));
+    }
+
+    /**
+     * 新增角色和部门关联
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRoleDept:add')")
+    @Log(title = "角色和部门关联", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyRoleDept companyRoleDept)
+    {
+        return toAjax(companyRoleDeptService.insertCompanyRoleDept(companyRoleDept));
+    }
+
+    /**
+     * 修改角色和部门关联
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRoleDept:edit')")
+    @Log(title = "角色和部门关联", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyRoleDept companyRoleDept)
+    {
+        return toAjax(companyRoleDeptService.updateCompanyRoleDept(companyRoleDept));
+    }
+
+    /**
+     * 删除角色和部门关联
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRoleDept:remove')")
+    @Log(title = "角色和部门关联", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{roleIds}")
+    public AjaxResult remove(@PathVariable Long[] roleIds)
+    {
+        return toAjax(companyRoleDeptService.deleteCompanyRoleDeptByIds(roleIds));
+    }
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyRoleMenuController.java

@@ -0,0 +1,97 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyRoleMenu;
+import com.fs.company.service.ICompanyRoleMenuService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 角色和菜单关联Controller
+ *
+ * @author fs
+ * @date 2021-10-04
+ */
+@RestController
+@RequestMapping("/company/companyRoleMenu")
+public class CompanyRoleMenuController extends BaseController
+{
+    @Autowired
+    private ICompanyRoleMenuService companyRoleMenuService;
+
+    /**
+     * 查询角色和菜单关联列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRoleMenu:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyRoleMenu companyRoleMenu)
+    {
+        startPage();
+        List<CompanyRoleMenu> list = companyRoleMenuService.selectCompanyRoleMenuList(companyRoleMenu);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出角色和菜单关联列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRoleMenu:export')")
+    @Log(title = "角色和菜单关联", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyRoleMenu companyRoleMenu)
+    {
+        List<CompanyRoleMenu> list = companyRoleMenuService.selectCompanyRoleMenuList(companyRoleMenu);
+        ExcelUtil<CompanyRoleMenu> util = new ExcelUtil<CompanyRoleMenu>(CompanyRoleMenu.class);
+        return util.exportExcel(list, "companyRoleMenu");
+    }
+
+    /**
+     * 获取角色和菜单关联详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRoleMenu:query')")
+    @GetMapping(value = "/{roleId}")
+    public AjaxResult getInfo(@PathVariable("roleId") Long roleId)
+    {
+        return AjaxResult.success(companyRoleMenuService.selectCompanyRoleMenuById(roleId));
+    }
+
+    /**
+     * 新增角色和菜单关联
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRoleMenu:add')")
+    @Log(title = "角色和菜单关联", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyRoleMenu companyRoleMenu)
+    {
+        return toAjax(companyRoleMenuService.insertCompanyRoleMenu(companyRoleMenu));
+    }
+
+    /**
+     * 修改角色和菜单关联
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRoleMenu:edit')")
+    @Log(title = "角色和菜单关联", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyRoleMenu companyRoleMenu)
+    {
+        return toAjax(companyRoleMenuService.updateCompanyRoleMenu(companyRoleMenu));
+    }
+
+    /**
+     * 删除角色和菜单关联
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRoleMenu:remove')")
+    @Log(title = "角色和菜单关联", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{roleIds}")
+    public AjaxResult remove(@PathVariable Long[] roleIds)
+    {
+        return toAjax(companyRoleMenuService.deleteCompanyRoleMenuByIds(roleIds));
+    }
+}

+ 98 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanySmsController.java

@@ -0,0 +1,98 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanySms;
+import com.fs.company.service.ICompanySmsService;
+import com.fs.company.vo.CompanySmsListVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 公司短信Controller
+ *
+ * @author fs
+ * @date 2023-01-09
+ */
+@RestController
+@RequestMapping("/company/companySms")
+public class CompanySmsController extends BaseController
+{
+    @Autowired
+    private ICompanySmsService companySmsService;
+
+    /**
+     * 查询公司短信列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySms:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanySms companySms)
+    {
+        startPage();
+        List<CompanySmsListVO> list = companySmsService.selectCompanySmsList(companySms);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出公司短信列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySms:export')")
+    @Log(title = "公司短信", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanySms companySms)
+    {
+        List<CompanySmsListVO> list = companySmsService.selectCompanySmsList(companySms);
+        ExcelUtil<CompanySmsListVO> util = new ExcelUtil<CompanySmsListVO>(CompanySmsListVO.class);
+        return util.exportExcel(list, "companySms");
+    }
+
+    /**
+     * 获取公司短信详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySms:query')")
+    @GetMapping(value = "/{smsId}")
+    public AjaxResult getInfo(@PathVariable("smsId") Long smsId)
+    {
+        return AjaxResult.success(companySmsService.selectCompanySmsById(smsId));
+    }
+
+    /**
+     * 新增公司短信
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySms:add')")
+    @Log(title = "公司短信", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanySms companySms)
+    {
+        return toAjax(companySmsService.insertCompanySms(companySms));
+    }
+
+    /**
+     * 修改公司短信
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySms:edit')")
+    @Log(title = "公司短信", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanySms companySms)
+    {
+        return toAjax(companySmsService.updateCompanySms(companySms));
+    }
+
+    /**
+     * 删除公司短信
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySms:remove')")
+    @Log(title = "公司短信", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{smsIds}")
+    public AjaxResult remove(@PathVariable Long[] smsIds)
+    {
+        return toAjax(companySmsService.deleteCompanySmsByIds(smsIds));
+    }
+}

+ 122 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanySmsLogsController.java

@@ -0,0 +1,122 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanySmsLogs;
+import com.fs.company.param.CompanySmsLogsListParam;
+import com.fs.company.service.ICompanySmsLogsService;
+import com.fs.company.vo.CompanySmsLogsListVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 短信发送记录Controller
+ *
+ * @author fs
+ * @date 2023-01-09
+ */
+@RestController
+@RequestMapping("/company/companySmsLogs")
+public class CompanySmsLogsController extends BaseController
+{
+    @Autowired
+    private ICompanySmsLogsService companySmsLogsService;
+
+    /**
+     * 查询短信发送记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsLogs:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanySmsLogsListParam companySmsLogs)
+    {
+        startPage();
+        if(!StringUtils.isEmpty(companySmsLogs.getCreateTimeRange())){
+            companySmsLogs.setCreateTimeList(companySmsLogs.getCreateTimeRange().split("--"));
+        }
+        List<CompanySmsLogsListVO> list = companySmsLogsService.selectCompanySmsLogsList(companySmsLogs);
+        if (list != null) {
+            for (CompanySmsLogsListVO vo : list) {
+                if(vo.getPhone()!=null){
+                    vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+
+            }
+        }
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出短信发送记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsLogs:export')")
+    @Log(title = "短信发送记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanySmsLogsListParam companySmsLogs)
+    {
+        if(!StringUtils.isEmpty(companySmsLogs.getCreateTimeRange())){
+            companySmsLogs.setCreateTimeList(companySmsLogs.getCreateTimeRange().split("--"));
+        }
+        List<CompanySmsLogsListVO> list = companySmsLogsService.selectCompanySmsLogsList(companySmsLogs);
+        if (list != null) {
+            for (CompanySmsLogsListVO vo : list) {
+                if(vo.getPhone()!=null){
+                    vo.setPhone(vo.getPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                }
+
+            }
+        }
+        ExcelUtil<CompanySmsLogsListVO> util = new ExcelUtil<CompanySmsLogsListVO>(CompanySmsLogsListVO.class);
+        return util.exportExcel(list, "companySmsLogs");
+    }
+
+    /**
+     * 获取短信发送记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsLogs:query')")
+    @GetMapping(value = "/{logsId}")
+    public AjaxResult getInfo(@PathVariable("logsId") Long logsId)
+    {
+        return AjaxResult.success(companySmsLogsService.selectCompanySmsLogsById(logsId));
+    }
+
+    /**
+     * 新增短信发送记录
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsLogs:add')")
+    @Log(title = "短信发送记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanySmsLogs companySmsLogs)
+    {
+        return toAjax(companySmsLogsService.insertCompanySmsLogs(companySmsLogs));
+    }
+
+    /**
+     * 修改短信发送记录
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsLogs:edit')")
+    @Log(title = "短信发送记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanySmsLogs companySmsLogs)
+    {
+        return toAjax(companySmsLogsService.updateCompanySmsLogs(companySmsLogs));
+    }
+
+    /**
+     * 删除短信发送记录
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsLogs:remove')")
+    @Log(title = "短信发送记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{logsIds}")
+    public AjaxResult remove(@PathVariable Long[] logsIds)
+    {
+        return toAjax(companySmsLogsService.deleteCompanySmsLogsByIds(logsIds));
+    }
+}

+ 99 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanySmsOrderController.java

@@ -0,0 +1,99 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanySmsOrder;
+import com.fs.company.param.CompanySmsOrderListParam;
+import com.fs.company.service.ICompanySmsOrderService;
+import com.fs.company.vo.CompanySmsOrderListVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 短信购买订单Controller
+ *
+ * @author fs
+ * @date 2023-01-09
+ */
+@RestController
+@RequestMapping("/company/companySmsOrder")
+public class CompanySmsOrderController extends BaseController
+{
+    @Autowired
+    private ICompanySmsOrderService companySmsOrderService;
+
+    /**
+     * 查询短信购买订单列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsOrder:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanySmsOrderListParam param)
+    {
+        startPage();
+        List<CompanySmsOrderListVO> list = companySmsOrderService.selectCompanySmsOrderList(param);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出短信购买订单列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsOrder:export')")
+    @Log(title = "短信购买订单", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanySmsOrderListParam param)
+    {
+        List<CompanySmsOrderListVO> list = companySmsOrderService.selectCompanySmsOrderList(param);
+        ExcelUtil<CompanySmsOrderListVO> util = new ExcelUtil<CompanySmsOrderListVO>(CompanySmsOrderListVO.class);
+        return util.exportExcel(list, "companySmsOrder");
+    }
+
+    /**
+     * 获取短信购买订单详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsOrder:query')")
+    @GetMapping(value = "/{orderId}")
+    public AjaxResult getInfo(@PathVariable("orderId") Long orderId)
+    {
+        return AjaxResult.success(companySmsOrderService.selectCompanySmsOrderById(orderId));
+    }
+
+    /**
+     * 新增短信购买订单
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsOrder:add')")
+    @Log(title = "短信购买订单", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanySmsOrder companySmsOrder)
+    {
+        return toAjax(companySmsOrderService.insertCompanySmsOrder(companySmsOrder));
+    }
+
+    /**
+     * 修改短信购买订单
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsOrder:edit')")
+    @Log(title = "短信购买订单", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanySmsOrder companySmsOrder)
+    {
+        return toAjax(companySmsOrderService.updateCompanySmsOrder(companySmsOrder));
+    }
+
+    /**
+     * 删除短信购买订单
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsOrder:remove')")
+    @Log(title = "短信购买订单", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{orderIds}")
+    public AjaxResult remove(@PathVariable Long[] orderIds)
+    {
+        return toAjax(companySmsOrderService.deleteCompanySmsOrderByIds(orderIds));
+    }
+}

+ 97 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanySmsPackageController.java

@@ -0,0 +1,97 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanySmsPackage;
+import com.fs.company.service.ICompanySmsPackageService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 短信套餐包Controller
+ *
+ * @author fs
+ * @date 2023-01-09
+ */
+@RestController
+@RequestMapping("/company/companySmsPackage")
+public class CompanySmsPackageController extends BaseController
+{
+    @Autowired
+    private ICompanySmsPackageService companySmsPackageService;
+
+    /**
+     * 查询短信套餐包列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsPackage:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanySmsPackage companySmsPackage)
+    {
+        startPage();
+        List<CompanySmsPackage> list = companySmsPackageService.selectCompanySmsPackageList(companySmsPackage);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出短信套餐包列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsPackage:export')")
+    @Log(title = "短信套餐包", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanySmsPackage companySmsPackage)
+    {
+        List<CompanySmsPackage> list = companySmsPackageService.selectCompanySmsPackageList(companySmsPackage);
+        ExcelUtil<CompanySmsPackage> util = new ExcelUtil<CompanySmsPackage>(CompanySmsPackage.class);
+        return util.exportExcel(list, "companySmsPackage");
+    }
+
+    /**
+     * 获取短信套餐包详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsPackage:query')")
+    @GetMapping(value = "/{packageId}")
+    public AjaxResult getInfo(@PathVariable("packageId") Long packageId)
+    {
+        return AjaxResult.success(companySmsPackageService.selectCompanySmsPackageById(packageId));
+    }
+
+    /**
+     * 新增短信套餐包
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsPackage:add')")
+    @Log(title = "短信套餐包", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanySmsPackage companySmsPackage)
+    {
+        return toAjax(companySmsPackageService.insertCompanySmsPackage(companySmsPackage));
+    }
+
+    /**
+     * 修改短信套餐包
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsPackage:edit')")
+    @Log(title = "短信套餐包", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanySmsPackage companySmsPackage)
+    {
+        return toAjax(companySmsPackageService.updateCompanySmsPackage(companySmsPackage));
+    }
+
+    /**
+     * 删除短信套餐包
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsPackage:remove')")
+    @Log(title = "短信套餐包", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{packageIds}")
+    public AjaxResult remove(@PathVariable Long[] packageIds)
+    {
+        return toAjax(companySmsPackageService.deleteCompanySmsPackageByIds(packageIds));
+    }
+}

+ 115 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanySmsTempController.java

@@ -0,0 +1,115 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanySmsTemp;
+import com.fs.company.service.ICompanySmsTempService;
+import com.fs.company.vo.CompanySmsTempListVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 短信模板Controller
+ *
+ * @author fs
+ * @date 2023-01-09
+ */
+@RestController
+@RequestMapping("/company/companySmsTemp")
+public class CompanySmsTempController extends BaseController
+{
+    @Autowired
+    private ICompanySmsTempService companySmsTempService;
+
+    /**
+     * 查询短信模板列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsTemp:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanySmsTemp companySmsTemp)
+    {
+        startPage();
+        List<CompanySmsTempListVO> list = companySmsTempService.selectCompanySmsTempListVO(companySmsTemp);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出短信模板列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsTemp:export')")
+    @Log(title = "短信模板", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanySmsTemp companySmsTemp)
+    {
+        List<CompanySmsTemp> list = companySmsTempService.selectCompanySmsTempList(companySmsTemp);
+        ExcelUtil<CompanySmsTemp> util = new ExcelUtil<CompanySmsTemp>(CompanySmsTemp.class);
+        return util.exportExcel(list, "companySmsTemp");
+    }
+
+    /**
+     * 获取短信模板详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsTemp:query')")
+    @GetMapping(value = "/{tempId}")
+    public AjaxResult getInfo(@PathVariable("tempId") Long tempId)
+    {
+        return AjaxResult.success(companySmsTempService.selectCompanySmsTempById(tempId));
+    }
+
+    /**
+     * 新增短信模板
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsTemp:add')")
+    @Log(title = "短信模板", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanySmsTemp companySmsTemp)
+    {
+        return toAjax(companySmsTempService.insertCompanySmsTemp(companySmsTemp));
+    }
+
+    /**
+     * 修改短信模板
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsTemp:edit')")
+    @Log(title = "短信模板", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanySmsTemp companySmsTemp)
+    {
+        return toAjax(companySmsTempService.updateCompanySmsTemp(companySmsTemp));
+    }
+
+    /**
+     * 删除短信模板
+     */
+    @PreAuthorize("@ss.hasPermi('company:companySmsTemp:remove')")
+    @Log(title = "短信模板", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{tempIds}")
+    public AjaxResult remove(@PathVariable Long[] tempIds)
+    {
+        return toAjax(companySmsTempService.deleteCompanySmsTempByIds(tempIds));
+    }
+
+
+    @PreAuthorize("@ss.hasPermi('company:companySmsTemp:audit')")
+    @PostMapping("/audit")
+    public R audit(@RequestBody CompanySmsTemp companySmsTemp)
+    {
+        CompanySmsTemp map=new CompanySmsTemp();
+        map.setIsAudit(1);
+        map.setTempId(companySmsTemp.getTempId());
+        if(companySmsTempService.updateCompanySmsTemp(map)>0){
+            return R.ok("操作成功");
+        }
+        else{
+            return R.error("操作失败");
+        }
+    }
+}

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

@@ -0,0 +1,634 @@
+package com.fs.company.controller;
+
+import com.alibaba.fastjson.JSONObject;
+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.utils.StringUtils;
+import com.fs.common.utils.TimeUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+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 org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 统计
+ *
+ * @author fs
+ * @date 2021-03-22
+ */
+@RestController
+@RequestMapping("/company/statistics")
+public class CompanyStatisticsController extends BaseController
+{
+
+    @Autowired
+    private ICompanyUserService userService;
+
+    @Autowired
+    private IFsStoreOrderService storeOrderService;
+    @Autowired
+    private IFsStorePaymentService storePaymentService;
+    @Autowired
+    private ICompanyVoiceLogsService voiceLogsService;
+    @Autowired
+    private ICompanySmsLogsService smsLogsService;
+
+
+    @Autowired
+    private ICrmCustomerService crmCustomerService;
+    @Autowired
+    private ICrmCustomerVisitService crmCustomerVisitService;
+    @GetMapping("/storeOrder")
+    public R storeOrder(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("未查找到数据");
+        }
+    }
+
+
+    @GetMapping("/packageOrder")
+    public R storePackageOrder(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.selectFsPackageOrderStatisticsList(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.selectFsPackageOrderCounts(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("未查找到数据");
+        }
+    }
+
+
+    @GetMapping("/inquiryOrder")
+    public R storeInquiryOrder(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.selectFsInquiryOrderStatisticsList(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.selectFsInquiryOrderCounts(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("未查找到数据");
+        }
+    }
+
+
+
+
+    @GetMapping("/exportStoreOrder")
+    public AjaxResult exportStoreOrder(FsStoreStatisticsParam param)
+    {
+        if(StringUtils.isNotEmpty(param.getUserIds())){
+            String[] userIds=param.getUserIds().split(",");
+            Long[] ids=new Long[userIds.length];
+            for(int i=0;i<ids.length; i++){
+                ids[i]=Long.parseLong(userIds[i]);
+            }
+            param.setUsers(ids);
+        }
+        else{
+            //获取所有员工
+            CompanyUser usermap=new CompanyUser();
+            usermap.setDeptId(param.getDeptId());
+            List<CompanyUser> users = userService.getUserListByDeptId(usermap);
+            List<Long> userIds = users.stream().map(element -> element.getUserId()).collect(Collectors.toList());
+            param.setUsers(userIds.toArray(new Long[userIds.size()]));
+        }
+
+        List<FsStoreOrderStatisticsVO> list= storeOrderService.selectFsStoreOrderStatisticsList(param);
+
+        ExcelUtil<FsStoreOrderStatisticsVO> util = new ExcelUtil<FsStoreOrderStatisticsVO>(FsStoreOrderStatisticsVO.class);
+        return util.exportExcel(list, "orderLogs");
+    }
+
+    @GetMapping("/exportPackageOrder")
+    public AjaxResult exportPackageOrder(FsStoreStatisticsParam param)
+    {
+        if(StringUtils.isNotEmpty(param.getUserIds())){
+            String[] userIds=param.getUserIds().split(",");
+            Long[] ids=new Long[userIds.length];
+            for(int i=0;i<ids.length; i++){
+                ids[i]=Long.parseLong(userIds[i]);
+            }
+            param.setUsers(ids);
+        }
+        else{
+            //获取所有员工
+            CompanyUser usermap=new CompanyUser();
+            usermap.setDeptId(param.getDeptId());
+            List<CompanyUser> users = userService.getUserListByDeptId(usermap);
+            List<Long> userIds = users.stream().map(element -> element.getUserId()).collect(Collectors.toList());
+            param.setUsers(userIds.toArray(new Long[userIds.size()]));
+        }
+
+        List<FsStoreOrderStatisticsVO> list= storeOrderService.selectFsPackageOrderStatisticsList(param);
+
+        ExcelUtil<FsStoreOrderStatisticsVO> util = new ExcelUtil<FsStoreOrderStatisticsVO>(FsStoreOrderStatisticsVO.class);
+        return util.exportExcel(list, "orderLogs");
+    }
+
+
+    @GetMapping("/exportInquiryOrder")
+    public AjaxResult exportInquiryOrder(FsStoreStatisticsParam param)
+    {
+        if(StringUtils.isNotEmpty(param.getUserIds())){
+            String[] userIds=param.getUserIds().split(",");
+            Long[] ids=new Long[userIds.length];
+            for(int i=0;i<ids.length; i++){
+                ids[i]=Long.parseLong(userIds[i]);
+            }
+            param.setUsers(ids);
+        }
+        else{
+            //获取所有员工
+            CompanyUser usermap=new CompanyUser();
+            usermap.setDeptId(param.getDeptId());
+            List<CompanyUser> users = userService.getUserListByDeptId(usermap);
+            List<Long> userIds = users.stream().map(element -> element.getUserId()).collect(Collectors.toList());
+            param.setUsers(userIds.toArray(new Long[userIds.size()]));
+        }
+
+        List<FsStoreOrderStatisticsVO> list= storeOrderService.selectFsInquiryOrderStatisticsList(param);
+
+        ExcelUtil<FsStoreOrderStatisticsVO> util = new ExcelUtil<FsStoreOrderStatisticsVO>(FsStoreOrderStatisticsVO.class);
+        return util.exportExcel(list, "orderLogs");
+    }
+
+    @GetMapping("/storePayment")
+    public R storePayment(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("未查找到数据");
+        }
+    }
+
+    @GetMapping("/exportStorePayment")
+    public AjaxResult exportStorePayment(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.selectCompanyUserList(usermap);
+            List<Long> userIds = users.stream().map(element -> element.getUserId()).collect(Collectors.toList());
+            param.setUsers(userIds.toArray(new Long[userIds.size()]));
+        }
+
+        List<FsStorePaymentStatisticsVO> list= storePaymentService.selectFsStorePaymentStatisticsList(param);
+
+        ExcelUtil<FsStorePaymentStatisticsVO> util = new ExcelUtil<FsStorePaymentStatisticsVO>(FsStorePaymentStatisticsVO.class);
+        return util.exportExcel(list, "paymentLogs");
+    }
+
+//分割
+
+    @GetMapping("/voiceLogs")
+    public R voiceLogs(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("未查找到数据");
+        }
+    }
+
+    @GetMapping("/exportVoiceLogs")
+    public AjaxResult exportVoiceLogs(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()]));
+        }
+
+        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);
+            }
+        }
+        ExcelUtil<CompanyVoiceLogsStatisticsVO> util = new ExcelUtil<CompanyVoiceLogsStatisticsVO>(CompanyVoiceLogsStatisticsVO.class);
+        return util.exportExcel(list, "voiceLogs");
+    }
+
+
+
+
+
+
+
+
+    @GetMapping("/smsLogs")
+    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("未查找到数据");
+        }
+    }
+
+    @GetMapping("/exportSmsLogs")
+    public AjaxResult exportSmsLogs(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()]));
+        }
+
+        List<CompanySmsLogsStatisticsVO> list= smsLogsService.selectSmsLogsStatisticsList(param);
+
+        ExcelUtil<CompanySmsLogsStatisticsVO> util = new ExcelUtil<CompanySmsLogsStatisticsVO>(CompanySmsLogsStatisticsVO.class);
+        return util.exportExcel(list, "voiceLogs");
+    }
+
+
+    @GetMapping("/customer")
+    public R customer(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("未查找到数据");
+        }
+    }
+
+    @GetMapping("/exportCustomer")
+    public AjaxResult exportCustomer(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()]));
+        }
+
+        List<CrmCustomerStatisticsVO> list= crmCustomerService.selectCrmCustomerStatisticsList(param);
+        ExcelUtil<CrmCustomerStatisticsVO> util = new ExcelUtil<CrmCustomerStatisticsVO>(CrmCustomerStatisticsVO.class);
+        return util.exportExcel(list, "customer");
+    }
+
+
+    @GetMapping("/customerVisit")
+    public R customerVisit(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("未查找到数据");
+        }
+    }
+
+    @GetMapping("/exportCustomerVisit")
+    public AjaxResult exportCustomerVisit(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()]));
+        }
+        List<CrmCustomerVisitStatisticsVO> list= crmCustomerVisitService.selectCrmCustomerVisitStatisticsList(param);
+        ExcelUtil<CrmCustomerVisitStatisticsVO> util = new ExcelUtil<CrmCustomerVisitStatisticsVO>(CrmCustomerVisitStatisticsVO.class);
+        return util.exportExcel(list, "visit");
+    }
+}

+ 261 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyTcmReportController.java

@@ -0,0 +1,261 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyTcmSchedule;
+import com.fs.company.param.CompanyTcmReportListQueryParam;
+import com.fs.company.service.ICompanyTcmReportService;
+import com.fs.company.service.ICompanyTcmScheduleService;
+import com.fs.company.vo.CompanyTcmReportExportVO;
+import com.fs.company.vo.CompanyTcmReportListVO;
+import com.fs.company.vo.CompanyTcmStatisticsExportVO;
+import com.fs.framework.web.service.TokenService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.List;
+
+/**
+ * 中医档期业绩报表Controller
+ *
+ * @author fs
+ * @date 2023-09-05
+ */
+@RestController
+@RequestMapping("/company/scheduleReport")
+public class CompanyTcmReportController extends BaseController
+{
+    @Autowired
+    private ICompanyTcmReportService companyTcmReportService;
+
+    @Autowired
+    private ICompanyTcmScheduleService companyTcmScheduleService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    @PreAuthorize("@ss.hasPermi('company:scheduleReport:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyTcmReportListQueryParam param)
+    {
+        startPage();
+        if(!StringUtils.isEmpty(param.getCreateTimeRange())){
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDateRange())){
+            param.setStartTimeList(param.getDateRange().split("--"));
+        }
+        List<CompanyTcmReportListVO> list = companyTcmReportService.selectCompanyTcmReportListVOList(param);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('company:scheduleReport:statistics')")
+    @GetMapping("/statistics")
+    public TableDataInfo statisticsList(CompanyTcmReportListQueryParam param)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        if(!StringUtils.isEmpty(param.getCreateTimeRange())){
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDateRange())){
+            param.setStartTimeList(param.getDateRange().split("--"));
+        }
+        List<CompanyTcmReportListVO> list = companyTcmReportService.selectCompanyTcmReportStatisticsVOList(param);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('company:scheduleReport:statistics')")
+    @GetMapping("/getStatisticsByScheduleId")
+    public TableDataInfo getReportStatisticsListByScheduleId(CompanyTcmReportListQueryParam param)
+    {
+        startPage();
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        if(!StringUtils.isEmpty(param.getCreateTimeRange())){
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDateRange())){
+            param.setStartTimeList(param.getDateRange().split("--"));
+        }
+        List<CompanyTcmReportListVO> list = companyTcmReportService.selectReportStatisticsByScheduleId(param);
+        return getDataTable(list);
+    }
+
+    @PreAuthorize("@ss.hasPermi('company:scheduleReport:export')")
+    @Log(title = "中医档期业绩报表", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyTcmReportListQueryParam param)
+    {
+        if(!StringUtils.isEmpty(param.getCreateTimeRange())){
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDateRange())){
+            param.setStartTimeList(param.getDateRange().split("--"));
+        }
+        List<CompanyTcmReportExportVO> list = companyTcmReportService.selectCompanyTcmReportExportVOList(param);
+        ExcelUtil<CompanyTcmReportExportVO> util = new ExcelUtil<CompanyTcmReportExportVO>(CompanyTcmReportExportVO.class);
+        return util.exportExcel(list, "companyTcmScheduleReport");
+    }
+
+    /**
+     * 导出中医档期业绩报表列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:scheduleReport:export')")
+    @Log(title = "中医档期业绩统计报表", businessType = BusinessType.EXPORT)
+    @GetMapping("/exportStatistics")
+    public AjaxResult exportStatistics(CompanyTcmReportListQueryParam param)
+    {
+        if(!StringUtils.isEmpty(param.getCreateTimeRange())){
+            param.setCreateTimeList(param.getCreateTimeRange().split("--"));
+        }
+        if(!StringUtils.isEmpty(param.getDateRange())){
+            param.setStartTimeList(param.getDateRange().split("--"));
+        }
+        List<CompanyTcmStatisticsExportVO> list = companyTcmReportService.selectCompanyTcmStatisticsExportVOList(param);
+        for(CompanyTcmStatisticsExportVO item:list){
+            if(item.getTotalNum()!=null && item.getTotalNum().doubleValue()>0){
+                item.setRegisterRate(String.format("%.3f",getLongRate(item.getRegisterNum().doubleValue(),item.getTotalNum())*100.0).toString()+"%");
+                item.setOnlineRate(String.format("%.3f",getLongRate(item.getOnlineNum().doubleValue(),item.getTotalNum())*100.0).toString()+"%");
+                item.setFinishRate(String.format("%.3f", getLongRate(item.getFinishNum().doubleValue(),item.getTotalNum())*100.0).toString()+"%");
+                item.setRLine(new BigDecimal(getLongRate(item.getTotalMoney().doubleValue(),item.getTotalNum())*1.0).setScale(3, RoundingMode.HALF_UP));
+
+            }else{
+                item.setRegisterRate("0%");
+                item.setOnlineRate("0%");
+                item.setFinishRate("0%");
+                item.setRLine(new BigDecimal(0.0));
+            }
+
+            if(item.getCuCount()!=null && item.getCuCount().doubleValue()>0){
+                item.setPersonMoney(String.format("%.3f",getLongRate(item.getTotalMoney().doubleValue(),Long.valueOf(item.getCuCount()))*1.0).toString());
+            }else{
+                item.setCuCount(0);
+            }
+
+            if(item.getTargetMoney()!=null && item.getTargetMoney().doubleValue()>0){
+                item.setTargetRate(String.format("%.3f", item.getTotalMoney().doubleValue()/item.getTargetMoney().doubleValue()*100.0).toString()+"%");
+            }else{
+                item.setTargetRate("0%");
+            }
+            if(item.getMoney()!=null && item.getMoney().doubleValue()>0){
+                item.setZroi(new BigDecimal(item.getTotalMoney().doubleValue()/item.getMoney().doubleValue()*1.0).setScale(3, RoundingMode.HALF_UP));
+            }else{
+                item.setZroi(new BigDecimal(0.0));
+            }
+            if(item.getRound1Order()!=null){
+                item.setRound1Rate(getRoundRate(item.getRound1Order(),item.getTotalNum()));
+                item.setRound1Unit(new BigDecimal(getRoundUnit(item.getRound1Money(),item.getRound1Order())).setScale(3, RoundingMode.HALF_UP));
+            }
+            if(item.getRound2Order()!=null){
+                item.setRound2Rate(getRoundRate(item.getRound2Order(),item.getTotalNum()));
+                item.setRound2Unit(new BigDecimal(getRoundUnit(item.getRound2Money(),item.getRound2Order())).setScale(3, RoundingMode.HALF_UP));
+            }
+            if(item.getRound3Order()!=null){
+                item.setRound3Rate(getRoundRate(item.getRound3Order(),item.getTotalNum()));
+                item.setRound3Unit(new BigDecimal(getRoundUnit(item.getRound3Money(),item.getRound3Order())).setScale(3, RoundingMode.HALF_UP));
+            }
+            if(item.getRound4Order()!=null){
+                item.setRound4Rate(getRoundRate(item.getRound4Order(),item.getTotalNum()));
+                item.setRound4Unit(new BigDecimal(getRoundUnit(item.getRound4Money(),item.getRound4Order())).setScale(3, RoundingMode.HALF_UP));
+            }
+            if(item.getRound5Order()!=null){
+                item.setRound5Rate(getRoundRate(item.getRound5Order(),item.getTotalNum()));
+                item.setRound5Unit(new BigDecimal(getRoundUnit(item.getRound5Money(),item.getRound5Order())).setScale(3, RoundingMode.HALF_UP));
+            }
+            if(item.getRound6Order()!=null){
+                item.setRound6Rate(getRoundRate(item.getRound6Order(),item.getTotalNum()));
+                item.setRound6Unit(new BigDecimal(getRoundUnit(item.getRound6Money(),item.getRound6Order())).setScale(3, RoundingMode.HALF_UP));
+            }
+            if(item.getRound7Order()!=null) {
+                item.setRound7Rate(getRoundRate(item.getRound7Order(), item.getTotalNum()));
+                item.setRound7Unit(new BigDecimal(getRoundUnit(item.getRound7Money(), item.getRound7Order())).setScale(3, RoundingMode.HALF_UP));
+            }
+            if (item.getRound8Order() != null) {
+                item.setRound8Rate(getRoundRate(item.getRound8Order(), item.getTotalNum()));
+                item.setRound8Unit(new BigDecimal(getRoundUnit(item.getRound8Money(), item.getRound8Order())).setScale(3, RoundingMode.HALF_UP));
+            }
+            if (item.getRound9Order() != null) {
+                item.setRound9Rate(getRoundRate(item.getRound9Order(), item.getTotalNum()));
+                item.setRound9Unit(new BigDecimal(getRoundUnit(item.getRound9Money(), item.getRound9Order())).setScale(3, RoundingMode.HALF_UP));
+            }
+
+        }
+
+        ExcelUtil<CompanyTcmStatisticsExportVO> util = new ExcelUtil<CompanyTcmStatisticsExportVO>(CompanyTcmStatisticsExportVO.class);
+        return util.exportExcel(list, "statisticsScheduleReport");
+    }
+
+
+
+    /**
+     * 查询可用中医档期列表
+     */
+    @GetMapping("/getScheduleList")
+    public TableDataInfo getScheduleList()
+    {
+        startPage();
+        List<CompanyTcmSchedule> list = companyTcmScheduleService.selectUseableScheduleList();
+        return getDataTable(list);
+    }
+
+    /**
+     * 查询中医档期列表
+     */
+    @GetMapping("/getAllScheduleList")
+    public TableDataInfo getAllScheduleList()
+    {
+        startPage();
+        List<CompanyTcmSchedule> list = companyTcmScheduleService.selectCompanyTcmScheduleList(new CompanyTcmSchedule());
+        return getDataTable(list);
+    }
+
+    /**
+     * 获取中医档期业绩报表详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:scheduleReport:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(companyTcmReportService.selectCompanyTcmReportById(id));
+    }
+
+    public String getRoundRate(Long roundOrder,Long totalNum){
+        String sorStr="0%";
+        if(totalNum.longValue()>0){
+            sorStr=String.format("%.3f", roundOrder.doubleValue()/totalNum*100.0).toString()+"%";
+        }
+        return sorStr;
+    }
+
+    public double getRoundUnit(BigDecimal roundMoney,Long roundOrder){
+        double sorNum=0;
+        if(roundOrder.longValue()>0){
+            sorNum=roundMoney.doubleValue()/roundOrder*1.0;
+        }
+        return sorNum;
+    }
+
+
+    public double getLongRate(double num1,Long num2){
+        double sorNum=0;
+        if(num2.longValue()>0){
+            sorNum=num1/num2*1.0;
+        }
+        return sorNum;
+    }
+
+
+}

+ 120 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyTcmScheduleController.java

@@ -0,0 +1,120 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.domain.model.LoginUser;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyTcmSchedule;
+import com.fs.company.service.ICompanyTcmScheduleService;
+import com.fs.framework.web.service.TokenService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 中医档期管理Controller
+ *
+ * @author fs
+ * @date 2023-09-05
+ */
+@RestController
+@RequestMapping("/company/schedule")
+public class CompanyTcmScheduleController extends BaseController
+{
+    @Autowired
+    private ICompanyTcmScheduleService companyTcmScheduleService;
+
+    @Autowired
+    private TokenService tokenService;
+    /**
+     * 查询中医档期管理列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:schedule:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyTcmSchedule companyTcmSchedule)
+    {
+        startPage();
+        List<CompanyTcmSchedule> list = companyTcmScheduleService.selectCompanyTcmScheduleList(companyTcmSchedule);
+        return getDataTable(list);
+    }
+
+    @GetMapping("/getTcmScheduleList")
+    public R getCompanyTcmScheduleList()
+    {
+        CompanyTcmSchedule map = new CompanyTcmSchedule();
+        map.setStatus(1L);
+        List<CompanyTcmSchedule> list = companyTcmScheduleService.selectCompanyTcmScheduleList(map);
+        return R.ok().put("data",list);
+    }
+
+    /**
+     * 导出中医档期管理列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:schedule:export')")
+    @Log(title = "中医档期管理", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyTcmSchedule companyTcmSchedule)
+    {
+        List<CompanyTcmSchedule> list = companyTcmScheduleService.selectCompanyTcmScheduleList(companyTcmSchedule);
+        ExcelUtil<CompanyTcmSchedule> util = new ExcelUtil<CompanyTcmSchedule>(CompanyTcmSchedule.class);
+        return util.exportExcel(list, "schedule");
+    }
+
+    /**
+     * 获取中医档期管理详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:schedule:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(companyTcmScheduleService.selectCompanyTcmScheduleById(id));
+    }
+
+    /**
+     * 新增中医档期管理
+     */
+    @PreAuthorize("@ss.hasPermi('company:schedule:add')")
+    @Log(title = "中医档期管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyTcmSchedule companyTcmSchedule)
+    {
+
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        List<CompanyTcmSchedule> scheduleList=companyTcmScheduleService.selectCompanyTcmScheduleList(companyTcmSchedule);
+        if(scheduleList.size()>0){
+            return AjaxResult.error("档期名称已经存在");
+        }
+        companyTcmSchedule.setCreateUserId(loginUser.getUser().getUserId());
+        //companyTcmSchedule.setUpdateUserId(loginUser.getUser().getUserId());
+        return toAjax(companyTcmScheduleService.insertCompanyTcmSchedule(companyTcmSchedule));
+    }
+
+    /**
+     * 修改中医档期管理
+     */
+    @PreAuthorize("@ss.hasPermi('company:schedule:edit')")
+    @Log(title = "中医档期管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyTcmSchedule companyTcmSchedule)
+    {
+        return toAjax(companyTcmScheduleService.updateCompanyTcmSchedule(companyTcmSchedule));
+    }
+
+    /**
+     * 删除中医档期管理
+     */
+    @PreAuthorize("@ss.hasPermi('company:schedule:remove')")
+    @Log(title = "中医档期管理", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(companyTcmScheduleService.deleteCompanyTcmScheduleByIds(ids));
+    }
+}

+ 120 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyUserController.java

@@ -0,0 +1,120 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.constant.UserConstants;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.ICompanyUserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 企业员工信息Controller
+ *
+ * @author fs
+ * @date 2021-10-04
+ */
+@RestController
+@RequestMapping("/company/companyUser")
+public class CompanyUserController extends BaseController
+{
+    @Autowired
+    private ICompanyUserService companyUserService;
+
+    /**
+     * 查询企业员工信息列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyUser:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyUser companyUser)
+    {
+        startPage();
+        List<CompanyUser> list = companyUserService.selectCompanyUserList(companyUser);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出企业员工信息列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyUser:export')")
+    @Log(title = "企业员工信息", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyUser companyUser)
+    {
+        List<CompanyUser> list = companyUserService.selectCompanyUserList(companyUser);
+        ExcelUtil<CompanyUser> util = new ExcelUtil<CompanyUser>(CompanyUser.class);
+        return util.exportExcel(list, "companyUser");
+    }
+
+    /**
+     * 获取企业员工信息详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyUser:query')")
+    @GetMapping(value = "/{userId}")
+    public AjaxResult getInfo(@PathVariable("userId") Long userId)
+    {
+        return AjaxResult.success(companyUserService.selectCompanyUserById(userId));
+    }
+
+    /**
+     * 新增企业员工信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyUser:add')")
+    @Log(title = "企业员工信息", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyUser companyUser)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(companyUserService.checkUserNameUnique(companyUser.getUserName())))
+        {
+            return AjaxResult.error("新增用户'" + companyUser.getUserName() + "'失败,登录账号已存在");
+        }
+        return toAjax(companyUserService.insertCompanyUser(companyUser));
+    }
+
+    /**
+     * 修改企业员工信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyUser:edit')")
+    @Log(title = "企业员工信息", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyUser companyUser)
+    {
+        return toAjax(companyUserService.updateCompanyUser(companyUser));
+    }
+
+    /**
+     * 删除企业员工信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyUser:remove')")
+    @Log(title = "企业员工信息", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{userIds}")
+    public AjaxResult remove(@PathVariable Long[] userIds)
+    {
+        return toAjax(companyUserService.deleteCompanyUserByIds(userIds));
+    }
+
+    @GetMapping("/getAllUserlist")
+    public R getAllUserlist(@RequestParam Long companyId)
+    {
+        CompanyUser map=new CompanyUser();
+        map.setCompanyId(companyId);
+        List<CompanyUser> list = companyUserService.selectCompanyUserList(map);
+        return R.ok().put("data",list);
+    }
+
+    @GetMapping("/getUserListByDeptId")
+    public R getUserListByDeptId(CompanyUser user)
+    {
+
+        List<CompanyUser> list = companyUserService.getUserListByDeptId(user);
+        return R.ok().put("data",list);
+    }
+}

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