瀏覽代碼

first add

zero 1 月之前
當前提交
320cf0c4de
共有 99 個文件被更改,包括 8804 次插入0 次删除
  1. 341 0
      pom.xml
  2. 24 0
      src/main/java/com/cslg/ppa/PpaApplication.java
  3. 131 0
      src/main/java/com/cslg/ppa/common/core/auth/Response.java
  4. 66 0
      src/main/java/com/cslg/ppa/common/core/auth/ResponseEnum.java
  5. 30 0
      src/main/java/com/cslg/ppa/common/core/auth/WxResultStatus.java
  6. 149 0
      src/main/java/com/cslg/ppa/common/core/base/Constants.java
  7. 23 0
      src/main/java/com/cslg/ppa/common/core/log/BusinessLogTypeEnum.java
  8. 213 0
      src/main/java/com/cslg/ppa/common/core/log/LogHelper.java
  9. 48 0
      src/main/java/com/cslg/ppa/common/core/redis/CacheTTLEnum.java
  10. 493 0
      src/main/java/com/cslg/ppa/common/core/redis/RedisService.java
  11. 47 0
      src/main/java/com/cslg/ppa/common/exception/BusinessException.java
  12. 100 0
      src/main/java/com/cslg/ppa/common/exception/ExceptionEnum.java
  13. 43 0
      src/main/java/com/cslg/ppa/common/exception/GlobalException.java
  14. 17 0
      src/main/java/com/cslg/ppa/common/exception/ThrowException.java
  15. 30 0
      src/main/java/com/cslg/ppa/common/exception/WxApiException.java
  16. 45 0
      src/main/java/com/cslg/ppa/common/exception/XiaoShiException.java
  17. 153 0
      src/main/java/com/cslg/ppa/common/okhttp/MyCookieStore.java
  18. 50 0
      src/main/java/com/cslg/ppa/common/okhttp/MyOkHttpClient.java
  19. 9 0
      src/main/java/com/cslg/ppa/common/utils/BackupUtils.java
  20. 83 0
      src/main/java/com/cslg/ppa/common/utils/BeanUtil.java
  21. 249 0
      src/main/java/com/cslg/ppa/common/utils/DataUtils.java
  22. 387 0
      src/main/java/com/cslg/ppa/common/utils/DateUtil.java
  23. 763 0
      src/main/java/com/cslg/ppa/common/utils/DateUtils.java
  24. 180 0
      src/main/java/com/cslg/ppa/common/utils/ExcelUtils.java
  25. 306 0
      src/main/java/com/cslg/ppa/common/utils/FileUtils.java
  26. 166 0
      src/main/java/com/cslg/ppa/common/utils/HttpUtils.java
  27. 381 0
      src/main/java/com/cslg/ppa/common/utils/JsonUtils.java
  28. 58 0
      src/main/java/com/cslg/ppa/common/utils/RandomUtil.java
  29. 323 0
      src/main/java/com/cslg/ppa/common/utils/ReadExcelUtils.java
  30. 80 0
      src/main/java/com/cslg/ppa/common/utils/RegexUtil.java
  31. 20 0
      src/main/java/com/cslg/ppa/config/MybatisPlusConfig.java
  32. 11 0
      src/main/java/com/cslg/ppa/config/WebSocketConfig.java
  33. 45 0
      src/main/java/com/cslg/ppa/controller/ArticleInfoController.java
  34. 43 0
      src/main/java/com/cslg/ppa/controller/CategoryController.java
  35. 85 0
      src/main/java/com/cslg/ppa/controller/ReportController.java
  36. 14 0
      src/main/java/com/cslg/ppa/dto/ArticleInfoIdDTO.java
  37. 9 0
      src/main/java/com/cslg/ppa/dto/AssoReportArticleIdDTO.java
  38. 11 0
      src/main/java/com/cslg/ppa/dto/CategoryDTO.java
  39. 13 0
      src/main/java/com/cslg/ppa/dto/CategoryIdDTO.java
  40. 24 0
      src/main/java/com/cslg/ppa/dto/FMSDeleteFileDTO.java
  41. 30 0
      src/main/java/com/cslg/ppa/dto/GetArticleInfoDTO.java
  42. 25 0
      src/main/java/com/cslg/ppa/dto/OAMessageDTO.java
  43. 26 0
      src/main/java/com/cslg/ppa/dto/ReportDTO.java
  44. 13 0
      src/main/java/com/cslg/ppa/dto/ReportIdDTO.java
  45. 32 0
      src/main/java/com/cslg/ppa/dto/SelectArticleInfoDTO.java
  46. 9 0
      src/main/java/com/cslg/ppa/dto/SelectAssoReportArticleDTO.java
  47. 11 0
      src/main/java/com/cslg/ppa/dto/SelectCategoryListDTO.java
  48. 13 0
      src/main/java/com/cslg/ppa/dto/SelectReportListDTO.java
  49. 13 0
      src/main/java/com/cslg/ppa/dto/UpdateArticleInfoDTO.java
  50. 44 0
      src/main/java/com/cslg/ppa/entity/ArticleInfo.java
  51. 42 0
      src/main/java/com/cslg/ppa/entity/AssoReportArticle.java
  52. 28 0
      src/main/java/com/cslg/ppa/entity/BaseEntity.java
  53. 23 0
      src/main/java/com/cslg/ppa/entity/Category.java
  54. 39 0
      src/main/java/com/cslg/ppa/entity/Report.java
  55. 32 0
      src/main/java/com/cslg/ppa/entity/ReportTemple.java
  56. 31 0
      src/main/java/com/cslg/ppa/entity/SourceInfo.java
  57. 57 0
      src/main/java/com/cslg/ppa/entity/commom/Article.java
  58. 37 0
      src/main/java/com/cslg/ppa/entity/commom/BaseResp.java
  59. 30 0
      src/main/java/com/cslg/ppa/entity/commom/BaseVO.java
  60. 50 0
      src/main/java/com/cslg/ppa/entity/commom/BizData.java
  61. 35 0
      src/main/java/com/cslg/ppa/entity/commom/Calculate.java
  62. 15 0
      src/main/java/com/cslg/ppa/entity/commom/DifyFile.java
  63. 25 0
      src/main/java/com/cslg/ppa/entity/commom/PatentData.java
  64. 11 0
      src/main/java/com/cslg/ppa/entity/commom/Records.java
  65. 33 0
      src/main/java/com/cslg/ppa/entity/commom/SystemFile.java
  66. 112 0
      src/main/java/com/cslg/ppa/entity/commom/WxResultBody.java
  67. 18 0
      src/main/java/com/cslg/ppa/mapper/ArticleInfoMapper.java
  68. 10 0
      src/main/java/com/cslg/ppa/mapper/AssoReportArticleMapper.java
  69. 9 0
      src/main/java/com/cslg/ppa/mapper/CategoryMapper.java
  70. 16 0
      src/main/java/com/cslg/ppa/mapper/ReportMapper.java
  71. 14 0
      src/main/java/com/cslg/ppa/mapper/ReportTempleMapper.java
  72. 9 0
      src/main/java/com/cslg/ppa/mapper/SourceInfoMapper.java
  73. 104 0
      src/main/java/com/cslg/ppa/service/ArticleInfoService.java
  74. 15 0
      src/main/java/com/cslg/ppa/service/AssoReportArticleService.java
  75. 74 0
      src/main/java/com/cslg/ppa/service/CategoryService.java
  76. 241 0
      src/main/java/com/cslg/ppa/service/GetWebArticle/GetCNIPAArticleService.java
  77. 57 0
      src/main/java/com/cslg/ppa/service/GetWebArticle/GetLocalInformationService.java
  78. 259 0
      src/main/java/com/cslg/ppa/service/GetWebArticle/GetProvinceNewsService.java
  79. 278 0
      src/main/java/com/cslg/ppa/service/GetWebArticle/GetWeChatArticleService.java
  80. 292 0
      src/main/java/com/cslg/ppa/service/ReportService.java
  81. 13 0
      src/main/java/com/cslg/ppa/service/ReportTempleService.java
  82. 16 0
      src/main/java/com/cslg/ppa/service/SourceInfoService.java
  83. 56 0
      src/main/java/com/cslg/ppa/service/commom/DifyService.java
  84. 250 0
      src/main/java/com/cslg/ppa/service/commom/FileManagerService.java
  85. 239 0
      src/main/java/com/cslg/ppa/service/commom/WeiXinApi.java
  86. 41 0
      src/main/java/com/cslg/ppa/service/commom/XmlParseService.java
  87. 13 0
      src/main/java/com/cslg/ppa/vo/ExportReportDetailVO.java
  88. 13 0
      src/main/java/com/cslg/ppa/vo/ExportReportVO.java
  89. 39 0
      src/main/java/com/cslg/ppa/vo/SelectArticleInfoVO.java
  90. 37 0
      src/main/java/com/cslg/ppa/vo/SelectAssoReportArticleVO.java
  91. 29 0
      src/main/java/com/cslg/ppa/vo/SelectReportListVO.java
  92. 72 0
      src/main/resources/application-dev.yml
  93. 43 0
      src/main/resources/application.yml
  94. 2 0
      src/main/resources/config/cron.setting
  95. 110 0
      src/main/resources/config/logback-spring.xml
  96. 二進制
      src/main/resources/file/article-export.docx
  97. 69 0
      src/main/resources/mapper/ArticleInfoMapper.xml
  98. 25 0
      src/main/resources/mapper/ReportMapper.xml
  99. 262 0
      src/test/java/com/cslg/ppa/PpaApplicationTests.java

+ 341 - 0
pom.xml

@@ -0,0 +1,341 @@
+<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>3.1.3</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.cslg</groupId>
+    <artifactId>PPA</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>PPA</name>
+    <description>PPA project for Spring Boot</description>
+
+    <properties>
+        <java.version>8</java.version>
+        <jwt.version>0.9.0</jwt.version>
+        <commons.io.version>2.5</commons.io.version>
+        <mybatisplus.version>3.5.3.1</mybatisplus.version>
+        <google.code.gson.version>2.7</google.code.gson.version>
+        <hutool.version>5.6.5</hutool.version>
+        <okhttps.version>4.10.0</okhttps.version>
+        <poi.version>4.1.2</poi.version>
+        <poi-tl.version>1.10.3</poi-tl.version>
+        <druid.version>1.1.20</druid.version>
+        <fastjson.version>2.0.12</fastjson.version>
+        <sa-token.version>1.29.0</sa-token.version>
+        <springdoc.version>1.6.6</springdoc.version>
+        <elasticsearch.version>8.6.1</elasticsearch.version>
+    </properties>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springdoc</groupId>
+            <artifactId>springdoc-openapi-ui</artifactId>
+            <version>${springdoc.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.deepoove</groupId>
+            <artifactId>poi-tl</artifactId>
+            <version>${poi-tl.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.dev33</groupId>
+            <artifactId>sa-token-spring-boot-starter</artifactId>
+            <version>${sa-token.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.dev33</groupId>
+            <artifactId>sa-token-dao-redis-jackson</artifactId>
+            <version>${sa-token.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+            <version>${druid.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>${fastjson.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-compress</artifactId>
+            <version>1.21</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.6</version>
+        </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+            <version>${jwt.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.ejlchina</groupId>
+            <artifactId>okhttps</artifactId>
+            <version>3.1.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+            <version>3.14.9</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-thymeleaf</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>${hutool.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mybatis</groupId>
+            <artifactId>mybatis-typehandlers-jsr310</artifactId>
+            <version>1.0.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>${mybatisplus.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <version>3.1.3</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.mysql</groupId>
+            <artifactId>mysql-connector-j</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi</artifactId>
+            <version>${poi.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+            <version>${poi.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-scratchpad</artifactId>
+            <version>${poi.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-fileupload</groupId>
+            <artifactId>commons-fileupload</artifactId>
+            <version>1.3.3</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
+            <version>1.4.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-quartz</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.mchange</groupId>
+            <artifactId>c3p0</artifactId>
+            <version>0.9.5.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-text</artifactId>
+            <version>1.11.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jsoup</groupId>
+            <artifactId>jsoup</artifactId>
+            <version>1.14.3</version>
+        </dependency>
+        <!-- Selenium WebDriver -->
+        <dependency>
+            <groupId>org.seleniumhq.selenium</groupId>
+            <artifactId>selenium-java</artifactId>
+            <version>4.25.0</version>
+        </dependency>
+        <dependency>
+            <groupId>joda-time</groupId>
+            <artifactId>joda-time</artifactId>
+            <version>2.9.9</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.antlr</groupId>
+            <artifactId>antlr4-runtime</artifactId>
+            <version>4.12.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.pdfbox</groupId>
+            <artifactId>pdfbox</artifactId>
+            <version>2.0.16</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>dom4j</groupId>
+            <artifactId>dom4j</artifactId>
+            <version>1.6.1</version>
+        </dependency>
+        <dependency>
+            <groupId>jaxen</groupId>
+            <artifactId>jaxen</artifactId>
+            <version>1.2.0</version> <!-- 使用你需要的版本 -->
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-test</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-amqp</artifactId>
+        </dependency>
+
+        <!--  poi-->
+        <dependency>
+            <groupId>io.github.draco1023</groupId>
+            <artifactId>poi-tl-ext</artifactId>
+            <version>0.4.2</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+            <version>1.9.3</version>
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>alimt20181012</artifactId>
+            <version>1.3.1</version>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <finalName>PPA_PROD_TEST</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <includeSystemScope>true</includeSystemScope>
+                    <!-- 指定该Main Class为全局的唯一入口 -->
+                    <mainClass>cn.cslg.ppa.PpaApplication</mainClass>
+                    <layout>ZIP</layout>
+                    <excludes>
+                        <exclude>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                        </exclude>
+                    </excludes>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal><!--可以把依赖的包都打包到生成的Jar包中-->
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>16</source>
+                    <target>16</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>8</source>
+                    <target>8</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <!--阿里云镜像源(因需要提交到GithubActions,会引起依赖下载过慢的问题)-->
+    <repositories>
+        <repository>
+            <id>nexus-aliyun</id>
+            <name>nexus-aliyun</name>
+            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+        <repository>
+            <id>com.e-iceblue</id>
+            <name>e-iceblue</name>
+            <url>http://repo.e-iceblue.com/nexus/content/groups/public/</url>
+        </repository>
+    </repositories>
+
+</project>

+ 24 - 0
src/main/java/com/cslg/ppa/PpaApplication.java

@@ -0,0 +1,24 @@
+package com.cslg.ppa;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+@EnableCaching
+@EnableAsync
+@EnableScheduling
+@SpringBootApplication
+public class PpaApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(PpaApplication.class, args);
+        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "-----The Project started");
+    }
+
+}

+ 131 - 0
src/main/java/com/cslg/ppa/common/core/auth/Response.java

@@ -0,0 +1,131 @@
+package com.cslg.ppa.common.core.auth;
+
+
+import com.cslg.ppa.common.utils.JsonUtils;
+import com.cslg.ppa.entity.commom.BaseVO;
+
+public class Response {
+
+    private Integer code;
+    private Object data;
+    private String message;
+    private Object pageColumn;
+
+    public static String success() {
+        Response response = new Response();
+        response.setResultEnum(ResponseEnum.SUCCESS);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String success(Object data) {
+        Response response = new Response();
+        response.setResultEnum(ResponseEnum.SUCCESS);
+        response.setData(data);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String success(Object data, BaseVO baseVO) {
+        Response response = new Response();
+        response.setResultEnum(ResponseEnum.SUCCESS);
+        response.setData(data);
+        response.setPageColumn(baseVO);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String websocket(Object data, ResponseEnum responseEnum) {
+        Response response = new Response();
+        response.setResultEnum(responseEnum);
+        response.setData(data);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String error() {
+        Response response = new Response();
+        response.setData(Boolean.FALSE);
+        response.setResultEnum(ResponseEnum.ERROR);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static Response fail(Object data) {
+        Response response = new Response();
+        response.setCode(ResponseEnum.ERROR.getCode());
+        response.setMessage(data + "");
+        response.setData(data);
+        return response;
+    }
+
+    public static String error(String message) {
+        Response response = new Response();
+        response.setCode(ResponseEnum.ERROR.getCode());
+        response.setData(Boolean.FALSE);
+        response.setMessage(message);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String error(Object data,String message) {
+        Response response = new Response();
+        response.setCode(ResponseEnum.ERROR.getCode());
+        response.setData(data);
+        response.setMessage(message);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String error(ResponseEnum responseEnum) {
+        Response response = new Response();
+        response.setResultEnum(responseEnum);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public static String error(Integer code, String message) {
+        Response response = new Response();
+        response.setCode(code);
+        response.setData(Boolean.FALSE);
+        response.setMessage(message);
+        return JsonUtils.objectToJson(response);
+    }
+
+    public Response(Integer code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    public Response() {
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    public void setData(Object data) {
+        this.data = data;
+    }
+
+    public Object getPageColumn() {
+        return pageColumn;
+    }
+
+    public void setPageColumn(Object pageColumn) {
+        this.pageColumn = pageColumn;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    private void setResultEnum(ResponseEnum responseEnum) {
+        this.code = responseEnum.getCode();
+        this.message = responseEnum.getMessage();
+    }
+}

+ 66 - 0
src/main/java/com/cslg/ppa/common/core/auth/ResponseEnum.java

@@ -0,0 +1,66 @@
+package com.cslg.ppa.common.core.auth;
+
+public enum ResponseEnum {
+
+    SUCCESS(200, "请求成功"),
+    WEB_SOCKET_SUCCESS(2, "WebSocket请求成功"),
+    BATCH_UPLOAD_INSTRUCTION_TASK_SUCCESS(900, "WebSocket请求成功"),
+    PROJECT_IMPORT_TASK_SUCCESS(901, "WebSocket请求成功"),
+    PROJECT_EXPORT_TASK_SUCCESS(902, "WebSocket请求成功"),
+    PATENT_IMPORT_TASK_SUCCESS(903, "WebSocket请求成功"),
+    PATENT_EXPORT_TASK_SUCCESS(904, "WebSocket请求成功"),
+    UNAUTHORIZED(401, "未登录"),
+    NOT_PERMISSION(402, "无操作权限"),
+    FORBIDDEN(403, "拒绝访问"),
+    USERNAME_ERROR(0, "用户名不存在"),
+    PASSWORD_ERROR(0, "密码错误"),
+    VERIFY_CODE_ERROR(0, "验证码错误"),
+    QUERY_CACHE_ERROR(0, "专利检索缓存失效,请重试"),
+    BATCH_UPLOAD_INSTRUCTION_TASK_ERROR(800, "导入说明书失败"),
+    PROJECT_EXPORT_TASK_ERROR(802, "专题库数据导出失败"),
+    PATENT_IMPORT_TASK_ERROR(803, "专利导入专利失败"),
+    PATENT_EXPORT_TASK_ERROR(804, "专利导出专利失败"),
+    SYSTEM_ERROR(500, "系统异常"),
+    ERROR(0, "请求失败"),
+    TENANT_STATUS_ERROR(805, "该用户的租户未启用"),
+    PERSONNEL_STATUS_ERROR(806, "该用户未启用"),
+    TENANT_DEADLINE_ERROR(0, "该用户的租户已过期"),
+    THE_TOKEN_IS_INVALID(500, "token失效"),
+    THE_REQUEST_TIME_OVERTIME(500, "请求时间超时"),
+    THE_SIGN_IS_NOT_SAME(500, "请求SIGN不一致,重新检查"),
+    THE_MACHINE_CODE_IS_NULL(500, "机器码不可为空"),
+    DO_NOT_LOG_IN_TO_MORE_THAN_TWO_NEW_MACHINES_WITH_THE_SAME_ACCOUNT(500, "同一账号新机登录不可超过两个"),
+    THE_PHONE_FORMAT_ERROR(500,"手机号格式错误"),
+    THE_PHONE_IS_NOT_EMPTY(500,"手机号不可为空"),
+    THE_PHONE_CODE_IS_INVALID(500,"手机验证码失效"),
+    THE_PHONE_CODE_IS_NOT_NULL(500,"手机验证码不可为空"),
+    THE_PHONE_CODE_IS_INCONFORMITY(500,"验证码不一致"),
+    THE_PERSONNEL_IS_NOT_EXIST(500,"用户不存在"),
+    THE_PERSONNEL_IS_FORBIDDEN(500,"该用户已停用"),
+    THE_VERSION_IS_NULL(500, "版本号不可为空");
+
+
+    private Integer code;
+    private String message;
+
+    ResponseEnum(Integer code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+}

+ 30 - 0
src/main/java/com/cslg/ppa/common/core/auth/WxResultStatus.java

@@ -0,0 +1,30 @@
+package com.cslg.ppa.common.core.auth;
+
+/**
+ * @author zsq
+ * @version 1.0
+ * @date 2021/3/31 14:19
+ */
+public enum WxResultStatus {
+
+    /**请求成功**/
+    SUCCESS(200, "成功"),
+    /**请求失败**/
+    FAIL(500, "请求失败"),
+    /**返回结果对象解析失败**/
+    FAIL_NULL_RES(510, "返回结果对象解析失败"),
+    /**返回结果为失败状态**/
+    FAIL_STATUS(520, "返回结果为失败状态"),
+    /**读取io流失败**/
+    FAIL_IO_ERR(530, "读取io流失败")
+    ;
+
+    private int status;
+    private String name;
+
+    WxResultStatus(int status, String name){
+        this.status = status;
+        this.name = name;
+    }
+
+}

+ 149 - 0
src/main/java/com/cslg/ppa/common/core/base/Constants.java

@@ -0,0 +1,149 @@
+package com.cslg.ppa.common.core.base;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Constants {
+
+    public static final String ADMIN_USERNAME = "admin";
+
+    public static final String PROJECT_INFO_FILE_NAME = "project.json";
+    public static final String PROJECT_REPORT_DIRECTORY_NAME = "project-report";
+    public static final String PROJECT_REPORT_FILE_NAME = "project-report.json";
+    public static final String PROJECT_FILE_DIRECTORY_NAME = "project-file";
+    public static final String PROJECT_FILE_FILE_NAME = "project-file.json";
+    public static final String PROJECT_PATENT_LINK_FILE_NAME = "project-patent-link.json";
+    public static final String PATENT_IMAGE_DIRECTORY_NAME = "patent-image";
+    public static final String PATENT_IMAGE_FILE_NAME = "patent-image.json";
+    public static final String PATENT_INSTRUCTION_DIRECTORY_NAME = "patent-instruction";
+    public static final String PATENT_INSTRUCTION_FILE_NAME = "patent-instruction.json";
+    public static final String PATENT_APPLICANT_MERGE_LINK_FILE_NAME = "patent-applicant-merge-link.json";
+    public static final String PATENT_APPLICANT_FILE_NAME = "patent-applicant.json";
+    public static final String PATENT_APPLICANT_LINK_FILE_NAME = "patent-applicant-link.json";
+    public static final String PATENT_FILE_NAME = "patent.json";
+    public static final String PATENT_ID_PATENT_NO_FILE_NAME = "patent-id-patentno.json";
+    public static final String PATENT_AFFAIR_FILE_NAME = "patent-affair.json";
+    public static final String PATENT_AGENCY_FILE_NAME = "patent-agency.json";
+    public static final String PATENT_AGENT_LINK_FILE_NAME = "patent-agent-link.json";
+    public static final String PATENT_AGENT_FILE_NAME = "patent-agent.json";
+    public static final String PATENT_INSTRUCTION_TEXT_FILE_NAME = "patent-instruction-text.json";
+    public static final String PATENT_INVENTOR_LINK_FILE_NAME = "patent-inventor-link.json";
+    public static final String PATENT_INVENTOR_MERGE_FILE_NAME = "patent-inventor-merge.json";
+    public static final String PATENT_INVENTOR_FILE_NAME = "patent-inventor.json";
+    public static final String PATENT_LICENSOR_FILE_NAME = "patent-licensor.json";
+    public static final String PATENT_PLEDGE_FILE_NAME = "patent-pledge.json";
+    public static final String PATENT_RIGHT_FILE_NAME = "patent-right.json";
+    public static final String PATENT_FAMILY_LINK_FILE_NAME = "patent-family-link.json";
+    public static final String PATENT_FAMILY_FILE_NAME = "patent-family.json";
+    public static final String PATENT_CLASS_NUMBER_FILE_NAME = "patent-class-number.json";
+    public static final String PATENT_LABEL_FILE_NAME = "patent-label.json";
+    public static final String PROJECT_FIELD_FILE_NAME = "project-field.json";
+    public static final String PROJECT_FIELD_OPTION_FILE_NAME = "project-field-option.json";
+    public static final String PROJECT_FIELD_TREE_FILE_NAME = "project-field-tree.json";
+    public static final String PROJECT_FIELD_TEXT_FILE_NAME = "project-field-text.json";
+    public static final String PROJECT_FIELD_PATENT_LINK_FILE_NAME = "project-field-patent-link.json";
+
+    public static final String API_XiaoSHI = "/api/xiaoshi";
+    public static final String API_PPA = "/api/xiaoshi/ppa";
+
+    public static final Integer PATENT_CLASS_NUMBER_IPC = 1;
+    public static final Integer PATENT_CLASS_NUMBER_CPC = 2;
+    public static final Integer PATENT_CLASS_NUMBER_UPC = 3;
+    public static final Integer PATENT_CLASS_NUMBER_LOC = 4;
+    public static final Integer MAX_IMPORT_TASK_COUNT=5;
+    public static final  Integer IMPORT_PATENT_TO=1;
+    public static final String   IMPORT_TASK_CONFIG="importTaskConfig";
+    /**
+     * 分隔符-竖线
+     */
+    public static final String SEPARATOR_VERTICAL_BAR = " | ";
+
+    /**
+     * 系统字段类型-查询检索
+     */
+    public static final String SYSTEM_FIELD_QUERY = "query";
+
+    /**
+     * 系统字段类型-专利导出
+     */
+    public static final String SYSTEM_FIELD_EXPORT = "export";
+
+    /**
+     * 系统字段类型-专利列表
+     */
+    public static final String SYSTEM_FIELD_PATENT_LIST = "list";
+
+    /**
+     * 系统字段类型-专题库字段
+     */
+    public static final String SYSTEM_FIELD_PROJECT = "project";
+
+    /**
+     * 专题库导入专利任务名称
+     */
+    public static final Integer TASK_IMPORT_PATENT = 1;
+
+    /**
+     * 专利说明书导入任务名称
+     */
+    public static final Integer TASK_IMPORT_PATENT_INSTRUCTION = 3;
+
+    /**
+     * 专利导出任务名称
+     */
+    public static final Integer TASK_EXPORT_PATENT = 2;
+
+    /**
+     * 日期位移值
+     */
+    public static final Map<String, Integer> DATE_OFFSET = new HashMap<String, Integer>() {{
+        put("月", -1);
+        put("季", -3);
+        put("半年", -6);
+        put("年", -12);
+        put("2年", -24);
+        put("3年", -36);
+        put("5年", -60);
+    }};
+
+    /**
+     * 专利类型
+     */
+    public static final String PATENT_TYPE = "PATENT_TYPE";
+
+    /**
+     * 机构类型
+     */
+    public static final String ORGAN_TYPE = "ORGAN_TYPE";
+
+    /**
+     * 许可人/被许可人
+     */
+    public static final String LICENSOR_TYPE = "LICENSOR_TYPE";
+
+    /**
+     * 简单法律状态
+     */
+    public static final String PATENT_SIMPLE_STATUS = "PATENT_SIMPLE_STATUS";
+
+    /**
+     * 国家
+     */
+    public static final String COUNTRIES = "COUNTRIES";
+
+    /**
+     * 法律状态
+     */
+    public static final String PATENT_STATUS = "PATENT_STATUS";
+
+    /**
+     * 企业应用场景
+     */
+    public static final String ENTERPRISE_APPLICATION_SCENARIO = "ENTERPRISE_APPLICATION_SCENARIO";
+
+    /**
+     * 调查类型
+     */
+    public static final String INVESTIGATION_TYPE = "INVESTIGATION_TYPE";
+
+}

+ 23 - 0
src/main/java/com/cslg/ppa/common/core/log/BusinessLogTypeEnum.java

@@ -0,0 +1,23 @@
+package com.cslg.ppa.common.core.log;
+
+public enum BusinessLogTypeEnum {
+	ECOMMERCE("ecommerce","小世电商模块");
+	private String desc;
+	private String type;
+	private BusinessLogTypeEnum(String type, String desc) {
+		this.setType(type);
+		this.setDesc(desc);
+	}
+	public String getType() {
+		return type;
+	}
+	public void setType(String type) {
+		this.type = type;
+	}
+	public String getDesc() {
+		return desc;
+	}
+	public void setDesc(String desc) {
+		this.desc = desc;
+	}
+}

+ 213 - 0
src/main/java/com/cslg/ppa/common/core/log/LogHelper.java

@@ -0,0 +1,213 @@
+package com.cslg.ppa.common.core.log;
+
+
+import com.cslg.ppa.common.exception.BusinessException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * 日志工具类
+ * @author Peach
+ *
+ */
+public class LogHelper {
+	
+	private static Logger logger = null;
+
+	//------------------------------------------系统日志记录-------------------------
+	/**
+	 * @param info
+	 */
+	public static void log(Object...info) {
+		logger = LoggerFactory.getLogger("");
+		logger.info("info={}",info);
+	}
+	
+	public static void log(Throwable e,Object...info) {
+		logger = LoggerFactory.getLogger("");
+		logger.info("exception={} info={}",throwable2String(e),info);
+	}
+	
+	/**
+	 * @param clazz
+	 * @param info
+	 */
+	public static void log(Class clazz, String info) {
+		logger = LoggerFactory.getLogger(clazz);
+		logger.info(info);
+	}
+	
+	/**
+	 * @param clazz
+	 * @param e
+	 */
+	public static void log(Class clazz, Throwable e) {
+		log(clazz,throwable2String(e));
+	}
+	
+	/**
+	 * @param name
+	 * @param info
+	 */
+	@Deprecated
+	public static void log(String name, String info) {
+		logger = LoggerFactory.getLogger(name);
+		logger.info(name+"-"+info);
+	}
+	
+	/**
+	 * @param name
+	 * @param e
+	 */
+	@Deprecated
+	public static void log(String name, Throwable e) {
+		log(name,throwable2String(e));
+	}
+	
+	
+	/**
+	 * @param name
+	 * @param info
+	 * @param e
+	 */
+	@Deprecated
+	public static void log(String name, String info,Throwable e) {
+		log(name,info+"-"+throwable2String(e));
+	}
+	
+	
+	/**
+	 * @param clazz
+	 * @param info
+	 * @param e
+	 */
+	public static void log(Class clazz, String info,Throwable e) {
+		log(clazz,info+"-"+throwable2String(e));
+	}
+	
+	/**
+	 * 将异常信息转为string
+	 * @param e
+	 * @return
+	 */
+	private static String throwable2String(Throwable e){
+		if(checkBaseBusinessException(e)) {
+			BusinessException bbe = (BusinessException)e;
+			return "----->"+bbe.getErrorMessage();
+		}
+		PrintWriter pw = null;
+		StringWriter sw = null;
+		try{
+			sw = new StringWriter();
+			pw = new PrintWriter(sw);
+			e.printStackTrace(pw);
+			pw.flush();
+			sw.flush();
+		}catch (Exception e1) {
+			logger.info(e.getMessage());
+		}finally{
+			if(sw!=null){
+				try{
+					sw.close();
+				}catch (Exception e2) {
+					e2.printStackTrace();
+					return "";
+				}
+			}else{
+				return "";
+			}
+			if(pw!=null){
+				pw.close();
+			}
+			return sw.toString();
+		}
+		
+	}
+	
+	
+	/**
+	* @Title: checkBaseBusinessException
+	* @Description: 判断异常是否为系统异常
+	* @param @param e
+	* @param @return    参数
+	* @return boolean    返回类型
+	* @throws
+	* @author Orange
+	* @date 2019年1月23日
+	*/
+	private static boolean checkBaseBusinessException(Throwable e) {
+		return BusinessException.class.isInstance(e);
+	}
+	
+	
+	//------------------------------------------多业务日志记录-------------------------
+	
+	/**
+	* @Title: log
+	* @Description: 多业务动态日志
+	* @param @param businessLogTypeEnum
+	* @param @param info    参数
+	* @return void    返回类型
+	* @throws
+	* @author Orange
+	* @date 2019年1月21日
+	*/
+	public static void log(BusinessLogTypeEnum businessLogTypeEnum, Object...info) {
+		MDC.put("businessName", businessLogTypeEnum.getType());
+		Logger logger = LoggerFactory.getLogger("business_log");
+		logger.info("businessName={}, info={}", businessLogTypeEnum.getType(), info);
+		MDC.remove(businessLogTypeEnum.getType());
+	}
+	
+	
+	
+	/**
+	* @Title: log
+	* @Description: 多业务动态日志
+	* @param @param businessLogTypeEnum
+	* @param @param e
+	* @param @param info    参数
+	* @return void    返回类型
+	* @throws
+	* @author Orange
+	* @date 2019年1月21日
+	*/
+	public static void log(BusinessLogTypeEnum businessLogTypeEnum, Throwable e, Object...info) {
+		MDC.put("businessName", businessLogTypeEnum.getType());
+		Logger logger = LoggerFactory.getLogger("business_log");
+		logger.info("businessName={}, exception={} ,info={}", businessLogTypeEnum.getType(), throwable2String(e),info);
+		MDC.remove(businessLogTypeEnum.getType());
+	}
+	
+	
+	
+	/**
+	* @Title: warnLog
+	* @Description: 警告日志
+	* @param @param e
+	* @param @param info    参数
+	* @return void    返回类型
+	* @throws
+	* @author Orange
+	* @date 2019年1月26日
+	*/
+	public static void warnLog(Throwable e,Object...info) {
+		//系统级别日志不打印
+		if(checkBaseBusinessException(e)) {
+			log(e,info);
+		}else {
+			Logger logger = LoggerFactory.getLogger("error_log");
+			logger.warn("[System Exception] exception={} ,info={}", throwable2String(e),info);
+		}
+	}
+
+	public static void warnLog(String warnInfo){
+		Logger logger = LoggerFactory.getLogger("error_log");
+		logger.warn(warnInfo);
+	}
+
+}

+ 48 - 0
src/main/java/com/cslg/ppa/common/core/redis/CacheTTLEnum.java

@@ -0,0 +1,48 @@
+package com.cslg.ppa.common.core.redis;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @ClassName
+ * @Description TODO
+ * @Author 陈凯裕
+ * @Date 2022/7/15 18:08
+ * @Version TODO
+ **/
+public class CacheTTLEnum {
+
+    public static final CacheTTLEnum ONE_MINUTE = new CacheTTLEnum(1L,TimeUnit.MINUTES);
+
+    public static final CacheTTLEnum TEN_MINUTE = new CacheTTLEnum(10L,TimeUnit.MINUTES);
+
+    public static final CacheTTLEnum FIVE_MINUTE = new CacheTTLEnum(5L,TimeUnit.MINUTES);
+
+    public static final CacheTTLEnum FIFTEEN_MINUTE = new CacheTTLEnum(15L,TimeUnit.MINUTES);
+
+    public static final CacheTTLEnum THIRTY_MINUTE = new CacheTTLEnum(30L,TimeUnit.MINUTES);
+
+    public static final CacheTTLEnum ONE_HOUR = new CacheTTLEnum(1L,TimeUnit.HOURS);
+
+    public static final CacheTTLEnum TWELVE_HOUR = new CacheTTLEnum(12L,TimeUnit.HOURS);
+
+    public static final CacheTTLEnum ONE_DAY = new CacheTTLEnum(1L,TimeUnit.DAYS);
+    public static final CacheTTLEnum TWO_HOUR = new CacheTTLEnum(2L,TimeUnit.HOURS);
+
+
+    private Long time;
+
+    private TimeUnit unit;
+
+    protected CacheTTLEnum(Long time, TimeUnit unit) {
+        this.time = time;
+        this.unit = unit;
+    }
+
+    public Long getTime() {
+        return time;
+    }
+
+    public TimeUnit getUnit() {
+        return unit;
+    }
+}

+ 493 - 0
src/main/java/com/cslg/ppa/common/core/redis/RedisService.java

@@ -0,0 +1,493 @@
+
+package com.cslg.ppa.common.core.redis;
+
+
+import com.cslg.ppa.common.utils.DateUtil;
+import jakarta.annotation.Resource;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.support.atomic.RedisAtomicLong;
+import org.springframework.stereotype.Component;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+
+@Component
+public class RedisService {
+
+    @Resource
+    RedisTemplate redisTemplate;
+
+
+/** -------------------key相关操作--------------------- */
+
+
+    /**
+     * 删除key
+     */
+    public void delete(String key) {
+        redisTemplate.delete(key);
+    }
+
+    /**
+     * 批量删除key
+     */
+    public void delete(Collection<String> keys) {
+        redisTemplate.delete(keys);
+    }
+
+
+    /**
+     * 是否存在key
+     */
+    public Boolean hasKey(String key) {
+        return redisTemplate.hasKey(key);
+    }
+
+
+    /**
+     * 设置过期时间
+     */
+    public Boolean expire(String key, CacheTTLEnum ttlEnum) {
+        return redisTemplate.expire(key, ttlEnum.getTime(), ttlEnum.getUnit());
+    }
+
+
+    /**
+     * 移除 key 的过期时间,key 将持久保持
+     */
+    public Boolean persist(String key) {
+        return redisTemplate.persist(key);
+    }
+
+
+    /**
+     * 返回 key 的剩余的过期时间
+     */
+    public Long getExpire(String key, TimeUnit unit) {
+        return redisTemplate.getExpire(key, unit);
+    }
+
+
+    /**
+     * 修改 key 的名称
+     */
+    public void rename(String oldKey, String newKey) {
+        redisTemplate.rename(oldKey, newKey);
+    }
+
+
+/** -------------------string相关操作--------------------- */
+
+
+    /**
+     * 设置指定 key 的值
+     */
+
+    public void set(String key, Object value) {
+        redisTemplate.opsForValue().set(key, value);
+    }
+
+
+    /**
+     * 获取指定 key 的值
+     */
+    public Object get(String key) {
+        return redisTemplate.opsForValue().get(key);
+    }
+
+    public <T> T get(String key, Class<T> clazz) {
+        return (T) get(key);
+    }
+
+
+    /**
+     * 将给定 key 的值设为 value ,并返回 key 的旧值(old value)
+     */
+    public Object getAndSet(String key, Object value) {
+        return redisTemplate.opsForValue().getAndSet(key, value);
+    }
+
+    public <T> T getAndSet(String key, Object value, Class<T> clazz) {
+        return (T) getAndSet(key, value);
+    }
+
+
+    /**
+     * 批量获取
+     */
+    public List<Object> multiGet(Collection<String> keys) {
+        return redisTemplate.opsForValue().multiGet(keys);
+    }
+
+
+    /**
+     * 只有在 key 不存在时设置 key 的值
+     */
+    public boolean setIfAbsent(String key, Object value) {
+        return redisTemplate.opsForValue().setIfAbsent(key, value);
+    }
+
+
+    /**
+     * 设置一个key,值为自增的LONG类型,每调用一次+1并且返回值自增后的值
+     */
+    public Long incrBy(String key) {
+        RedisAtomicLong redisAtomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
+        return redisAtomicLong.incrementAndGet();
+    }
+
+
+/** -------------------hash相关操作------------------------- */
+
+
+    /**
+     * 获取存储在hash表中指定字段的值
+     */
+    public Object hGet(String key, String field) {
+        return redisTemplate.opsForHash().get(key, field);
+    }
+
+
+    /*
+     * 存储指定键值对至hash表中
+     **/
+    public void hPut(String key, String hashKey, Object value) {
+        redisTemplate.opsForHash().put(key, hashKey, value);
+    }
+
+    /**
+     * 获取hash表中所有的键值对
+     */
+    public Map<String, Object> hGetAll(String key) {
+        return redisTemplate.opsForHash().entries(key);
+    }
+
+
+    /**
+     * 获取hash表中所有给定字段的值
+     */
+    public List<Object> hMultiGet(String key, Collection<String> fields) {
+        return redisTemplate.opsForHash().multiGet(key, fields);
+    }
+
+
+    /*
+     * 批量插入到hash表中
+     * */
+    public void hPutAll(String key, Map<String, Object> maps) {
+        redisTemplate.opsForHash().putAll(key, maps);
+    }
+
+
+    /**
+     * 删除一个或多个hash表字段
+     */
+    public Long hDelete(String key, String... fields) {
+        return redisTemplate.opsForHash().delete(key, fields);
+    }
+
+
+    /**
+     * 查看hash表 key 中,指定的字段是否存在
+     */
+    public boolean hExists(String key, String field) {
+        return redisTemplate.opsForHash().hasKey(key, field);
+    }
+
+
+    /**
+     * 获取所有hash表中的字段
+     */
+    public Set<String> hKeys(String key) {
+        return redisTemplate.opsForHash().keys(key);
+    }
+
+
+    /**
+     * 获取hash表中字段的数量
+     */
+    public Long hSize(String key) {
+        return redisTemplate.opsForHash().size(key);
+    }
+
+
+/** ------------------------list相关操作---------------------------- */
+
+
+    /**
+     * 通过索引获取列表中的元素
+     */
+    public Object lIndex(String key, long index) {
+        return redisTemplate.opsForList().index(key, index);
+    }
+
+
+    /**
+     * 通过索引设置列表元素的值
+     */
+    public void lSet(String key, long index, String value) {
+        redisTemplate.opsForList().set(key, index, value);
+    }
+
+    /**
+     * 列表队列左push
+     */
+    public Long lLeftPush(String key, Object value) {
+        return redisTemplate.opsForList().leftPush(key, value);
+    }
+
+
+    /**
+     * 列表队列批量左push
+     */
+    public Long lLeftPushAll(String key, Object... value) {
+        if (value.length == 0)
+            return 0L;
+        return redisTemplate.opsForList().leftPushAll(key, value);
+    }
+
+
+    /**
+     * 列表队列右push
+     */
+    public Long lRightPush(String key, Object value) {
+        return redisTemplate.opsForList().rightPush(key, value);
+    }
+
+
+    /**
+     * 列表队列批量右push
+     */
+    public Long lRightPushAll(String key, Object... value) {
+        if (value.length == 0)
+            return 0L;
+        return redisTemplate.opsForList().rightPushAll(key, value);
+    }
+
+
+    /**
+     * 弹出列表左侧的第一个元素
+     */
+    public Object lLeftPop(String key) {
+        return redisTemplate.opsForList().leftPop(key);
+    }
+
+    /**
+     * 弹出列表右侧的第一个元素
+     *
+     * @param key
+     * @return 删除的元素
+     */
+    public Object lRightPop(String key) {
+        return redisTemplate.opsForList().rightPop(key);
+    }
+
+
+    /**
+     * 获取列表长度
+     */
+    public Long lLen(String key) {
+        return redisTemplate.opsForList().size(key);
+    }
+
+
+/** --------------------set相关操作-------------------------- */
+
+
+    /**
+     * set添加元素
+     */
+    public Long sAdd(String key, Object... values) {
+        return redisTemplate.opsForSet().add(key, values);
+    }
+
+    /**
+     * set移除元素
+     */
+    public Long sRemove(String key, Object... values) {
+        return redisTemplate.opsForSet().remove(key, values);
+    }
+
+
+    /**
+     * 获取集合的大小
+     *
+     * @param key
+     * @return
+     */
+    public Long sSize(String key) {
+        return redisTemplate.opsForSet().size(key);
+    }
+
+
+    /**
+     * 获取集合所有元素
+     */
+    public Set<String> sGetMembers(String key) {
+        return redisTemplate.opsForSet().members(key);
+    }
+
+
+    /**
+     * 判断集合是否包含元素
+     */
+    public boolean sContains(String key, Object value) {
+        return redisTemplate.opsForSet().isMember(key, value);
+    }
+
+
+/**------------------zSet相关操作--------------------------------*/
+
+
+    /**
+     * 添加元素,有序集合是按照元素的score值由小到大排列
+     */
+    public Boolean zAdd(String key, Object value, double score) {
+        return redisTemplate.opsForZSet().add(key, value, score);
+    }
+
+
+    /**
+     * 移除指定value的值
+     */
+    public Long zRemove(String key, Object... values) {
+        return redisTemplate.opsForZSet().remove(key, values);
+    }
+
+    /**
+     * 增加元素的score值,并返回增加后的值
+     */
+    public Double zIncrementScore(String key, Object value, double delta) {
+        return redisTemplate.opsForZSet().incrementScore(key, value, delta);
+    }
+
+    /**
+     * 返回元素在集合的排名,按Score升序排名
+     */
+    public Long zRank(String key, Object value) {
+        return redisTemplate.opsForZSet().rank(key, value);
+    }
+
+    /**
+     * 返回元素在集合的排名,按Score倒序排名
+     */
+    public Long zReverseRank(String key, Object value) {
+        return redisTemplate.opsForZSet().reverseRank(key, value);
+    }
+
+    /**
+     * 获取集合的元素, 升序
+     */
+    public Set<String> zRange(String key, long start, long end) {
+        return redisTemplate.opsForZSet().range(key, start, end);
+    }
+
+    /**
+     * 获取集合的元素, 倒序
+     */
+    public Set<String> zReverseRange(String key, long start, long end) {
+        return redisTemplate.opsForZSet().reverseRange(key, start, end);
+    }
+
+    /**
+     * 根据Score值查询集合元素,升序
+     */
+    public Set<String> zRangeByScore(String key, double min, double max) {
+        return redisTemplate.opsForZSet().rangeByScore(key, min, max);
+    }
+
+
+    /**
+     * 根据Score值查询集合元素, 倒序
+     */
+    public Set<Object> zReverseRangeByScore(String key, double min,
+                                            double max) {
+        return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max);
+    }
+
+
+    /**
+     * 根据score值获取集合元素数量
+     */
+    public Long zCount(String key, double min, double max) {
+        return redisTemplate.opsForZSet().count(key, min, max);
+    }
+
+
+    /**
+     * 获取集合大小
+     *
+     * @param key
+     * @return
+     */
+    public Long zSize(String key) {
+        return redisTemplate.opsForZSet().size(key);
+    }
+
+
+    /**
+     * 获取集合中value元素的score值
+     */
+    public Double zScore(String key, Object value) {
+        return redisTemplate.opsForZSet().score(key, value);
+    }
+
+
+    /**
+     * 移除指定索引位置的成员
+     */
+    public Long zRemoveRange(String key, long start, long end) {
+        return redisTemplate.opsForZSet().removeRange(key, start, end);
+    }
+
+
+    /**
+     * 根据指定的score值的范围来移除成员
+     */
+    public Long zRemoveRangeByScore(String key, double min, double max) {
+        return redisTemplate.opsForZSet().removeRangeByScore(key, min, max);
+    }
+
+
+    /**
+     * 设置key值在下一天零点过期
+     *
+     * @param key
+     */
+    public void removeKeyBySecond(String key) {
+        Long second = DateUtil.getRemainingSecond();
+        if (second <= 0) {
+            this.delete(key);
+        }
+    }
+
+    /**
+     * 将值 value 关联到 key ,并将 key 的过期时间设为 timeout
+     *
+     * @param key
+     * @param value
+     * @param timeout 过期时间
+     * @param unit    时间单位, 天:TimeUnit.DAYS 小时:TimeUnit.HOURS 分钟:TimeUnit.MINUTES
+     *                秒:TimeUnit.SECONDS 毫秒:TimeUnit.MILLISECONDS
+     */
+    public void setEx(String key, Object value, long timeout, TimeUnit unit) {
+        redisTemplate.opsForValue().set(key, value, timeout, unit);
+    }
+
+    /**
+     * 设置键值并且过期时间是午夜
+     * @param key
+     * @param value
+     */
+    public  void setKeyLastToMidNight(String key ,String value){
+       Long second= DateUtil.getRemainingSecond();
+        redisTemplate.opsForValue().set(key, value, second, TimeUnit.SECONDS);
+    }
+}
+
+
+

+ 47 - 0
src/main/java/com/cslg/ppa/common/exception/BusinessException.java

@@ -0,0 +1,47 @@
+package com.cslg.ppa.common.exception;
+
+
+import lombok.Getter;
+
+/**
+ * @ClassName
+ * @Description 业务异常
+ * @Version TODO
+ **/
+@Getter
+public class BusinessException extends RuntimeException {
+
+	private String errorCode;// 异常代码
+	private String errorMessage;// 异常信息
+
+	public BusinessException(String errorCode, String errorMessage) {
+		super(errorMessage);
+		this.errorCode = errorCode;
+		this.errorMessage = errorMessage;
+	}
+
+	public BusinessException(ExceptionEnum e) {
+		super(e.getMessage());
+		this.errorMessage = e.getMessage();
+		this.errorCode = e.getCode();
+	}
+
+
+	public String getErrorCode() {
+		return errorCode;
+	}
+
+	public void setErrorCode(String errorCode) {
+		this.errorCode = errorCode;
+	}
+
+	public String getErrorMessage() {
+		return errorMessage;
+	}
+
+	public void setErrorMessage(String errorMessage) {
+		this.errorMessage = errorMessage;
+	}
+
+
+}

+ 100 - 0
src/main/java/com/cslg/ppa/common/exception/ExceptionEnum.java

@@ -0,0 +1,100 @@
+package com.cslg.ppa.common.exception;
+
+import lombok.Getter;
+
+@Getter
+public enum ExceptionEnum {
+    //400~500  登录相关异常提示
+    LOGIN_NO_LOGIN("401","未登录"),
+    LOGIN_ACCOUNT_MISTAKE("402","账号错误"),
+    LOGIN_PASSWORD_MISTAKE("403","密码错误"),
+    LOGIN_ERROR("405","登录错误"),
+    LOGIN_INVITE_ERROR("406","邀请码错误"),
+    THE_TOKEN_IS_INVALID("407", "token失效"),
+    THE_REQUEST_TIME_OVERTIME("408", "请求时间超时"),
+    THE_SIGN_IS_NOT_SAME("408", "请求SIGN不一致,重新检查"),
+    THE_MACHINE_CODE_IS_NULL("409", "机器码不可为空"),
+    DO_NOT_LOG_IN_TO_MORE_THAN_TWO_NEW_MACHINES_WITH_THE_SAME_ACCOUNT("410", "同一账号新机登录不可超过两个"),
+    THE_PHONE_FORMAT_ERROR("411","手机号格式错误"),
+    THE_PHONE_IS_NOT_EMPTY("412","手机号不可为空"),
+    THE_PHONE_CODE_IS_INVALID("413","手机验证码失效"),
+    THE_PHONE_CODE_IS_NOT_NULL("414","手机验证码不可为空"),
+    THE_PHONE_CODE_IS_INCONFORMITY("415","验证码不一致"),
+    THE_PERSONNEL_IS_NOT_EXIST("416","用户不存在"),
+    THE_PERSONNEL_IS_FORBIDDEN("417","该用户不可用"),
+    THE_VERSION_IS_NULL("418", "版本号不可为空"),
+    THE_PERSONNEL_IS_EXIST("419","用户已存在"),
+    //500~600   业务异常相关
+    THE_SYSTEM_ERROR("500", "系统异常"),
+
+    //600~700  权限相关异常提示
+    PERMISSION_ERROR("601","无权限"),
+    PERMISSION_NO_VIP("606","未开会员"),
+    PERMISSION_BEYOND_USETIME("607","超过使用次数"),
+
+    //700~800  参数相关异常提示
+    BUSINESS_ERROR("708","业务错误"),
+    BUSINESS_CHECK("709","参数校验错误"),
+
+
+    NO_NEED_PAY("901","支付成功"),
+
+
+
+
+
+    /*APP端 100000-300000*/
+    SUCCESS("000000", "调用成功"),
+    PARAMETER_VERIFICATION_ERROR("000001", "数据参数校验异常"),
+    PHONE_FORMAT_ERROR("000002","手机号格式错误"),
+
+    VERIFY_CODE("10001", "校验码失效"),
+    CODE_WRONG("10002","验证码错误"),
+    INIT_GENERICITY_BEAN_ERROR("10003","泛型实例化异常"),
+    THE_PHONE_CANNOT_BE_EXIST("10004","手机号已存在"),
+    THE_LOG_OUT("10004","未登录"),
+    THE_CODE_IS_NOT_NULL("10006","验证码不能为空"),
+
+    //异常20000
+    THE_PARAMETER_EXCEPTION("20001", "参数异常,请传入数据"),
+    THE_GET_INFORMATION_TOKEN_INVALID("20002", "获取用户信息token失效"),
+    THE_FAIL_TO_DELETE("20003", "删除失败"),
+
+    //业务异常
+    THE_PRODUCT_CATEGORY_NAME_IS_EXIST("607", "产品类别名称已存在"),
+    THE_LOG_INVALID_NEED_LOGIN_AGAIN("606","登录失效,请重新登录"),
+
+
+
+
+
+
+
+
+
+    SYSTEM_ERROR("999999", "系统异常");
+
+    private String code;// 异常代码
+    private String message;// 异常信息
+
+    ExceptionEnum(String code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+}

+ 43 - 0
src/main/java/com/cslg/ppa/common/exception/GlobalException.java

@@ -0,0 +1,43 @@
+package com.cslg.ppa.common.exception;
+
+import cn.dev33.satoken.exception.NotLoginException;
+import com.cslg.ppa.common.core.auth.Response;
+import com.cslg.ppa.common.core.auth.ResponseEnum;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+
+/**
+ * 全局异常处理
+ */
+@Slf4j
+@RestControllerAdvice // 可指定包前缀,比如:(basePackages = "com.pj.admin")
+public class GlobalException {
+
+    // 全局异常拦截(拦截项目中的所有异常)
+    @ExceptionHandler
+    public String handlerException(Exception e, HttpServletRequest request, HttpServletResponse response) throws Exception {
+        // 打印堆栈,以供调试
+        e.printStackTrace();
+        if (e instanceof NotLoginException) {
+            return Response.error(ResponseEnum.UNAUTHORIZED);
+        } else {
+            return Response.error(e.getMessage());
+        }
+    }
+
+    //小世异常
+    @ExceptionHandler
+    public String handlerXiaoShiException(XiaoShiException e) {
+        log.info("全局异常处理机制捕获到XiaoShiException,异常信息提示为:{}", e.getErrorCode() + "--" + e.getMessage());
+        if (StringUtils.isNotEmpty(e.getErrorCode())) {
+            return Response.error(Integer.parseInt(e.getErrorCode()), e.getErrorMessage());
+        } else {
+            return Response.error(e.getMessage());
+        }
+    }
+}

+ 17 - 0
src/main/java/com/cslg/ppa/common/exception/ThrowException.java

@@ -0,0 +1,17 @@
+package com.cslg.ppa.common.exception;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @Author chenyu
+ * @Date 2023/4/2
+ */
+@Slf4j
+public class ThrowException {
+
+    public static void throwXiaoShiException(String message) {
+        log.info("{}", message);
+        throw new XiaoShiException(message);
+    }
+
+}

+ 30 - 0
src/main/java/com/cslg/ppa/common/exception/WxApiException.java

@@ -0,0 +1,30 @@
+package com.cslg.ppa.common.exception;
+
+
+import com.cslg.ppa.common.core.auth.WxResultStatus;
+
+/**
+ * @author zsq
+ * @version 1.0
+ * @date 2021/3/31 14:37
+ */
+public class WxApiException extends RuntimeException {
+
+    /**错误枚举**/
+    private WxResultStatus wxResultStatus;
+
+    public WxApiException(WxResultStatus wxResultStatus) {
+        super(wxResultStatus.name());
+        this.wxResultStatus = wxResultStatus;
+    }
+
+    public WxApiException(WxResultStatus wxResultStatus, Exception e) {
+        super(wxResultStatus.name(), e);
+        this.wxResultStatus = wxResultStatus;
+    }
+
+    public WxResultStatus getWxResultStatus() {
+        return wxResultStatus;
+    }
+
+}

+ 45 - 0
src/main/java/com/cslg/ppa/common/exception/XiaoShiException.java

@@ -0,0 +1,45 @@
+package com.cslg.ppa.common.exception;
+
+/**
+ * 整个项目通用异常类
+ *
+ * @Author chenyu
+ * @Data 2023/2/15
+ */
+public class XiaoShiException extends RuntimeException {
+
+    private String errorCode;// 异常代码
+    private String errorMessage;// 异常信息
+    public XiaoShiException(String message) {
+        super(message);
+    }
+
+    public XiaoShiException(ExceptionEnum e, String errorMessage) {
+        super(errorMessage);
+        this.errorCode = e.getCode();
+        this.errorMessage = errorMessage;
+    }
+
+    public XiaoShiException(ExceptionEnum e) {
+        super(e.getMessage());
+        this.errorMessage = e.getMessage();
+        this.errorCode = e.getCode();
+    }
+
+
+    public String getErrorCode() {
+        return errorCode;
+    }
+
+    public void setErrorCode(String errorCode) {
+        this.errorCode = errorCode;
+    }
+
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    public void setErrorMessage(String errorMessage) {
+        this.errorMessage = errorMessage;
+    }
+}

+ 153 - 0
src/main/java/com/cslg/ppa/common/okhttp/MyCookieStore.java

@@ -0,0 +1,153 @@
+package com.cslg.ppa.common.okhttp;
+
+import com.cslg.ppa.common.utils.JsonUtils;
+import com.fasterxml.jackson.core.type.TypeReference;
+import okhttp3.Cookie;
+import okhttp3.CookieJar;
+import okhttp3.HttpUrl;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+/**
+ * cookie管理
+ * @author zsq
+ * @version 1.0
+ * @date 2021/3/31 16:17
+ */
+public class MyCookieStore implements CookieJar {
+
+    /**打印日志用**/
+    private static volatile boolean debug = false;
+
+    /**登录后拿到的token**/
+    private static String TOKEN = "";
+
+    /**管理cookie**/
+    private static ConcurrentHashMap<String, ConcurrentHashMap<String, Cookie>> cookieStore = new ConcurrentHashMap<>();
+
+    /**token资源文件位置**/
+    public static final String TOKEN_FILE_PATH = "/store/token.txt";
+
+    /**cookie资源文件位置**/
+    public static final String COOKIE_FILE_PATH = "/store/cookie.txt";
+
+
+    @Override
+    public void saveFromResponse(HttpUrl httpUrl, List<Cookie> list) {
+        log("-----保存cookie");
+
+        //保存cookie
+        log("httpUrl host: " + httpUrl.host());
+        ConcurrentHashMap<String, Cookie> cookieMap = cookieStore.get(httpUrl.host());
+        if (cookieMap == null) {
+            cookieMap = new ConcurrentHashMap<>();
+            cookieStore.put(httpUrl.host(), cookieMap);
+        }
+        for (Cookie cookie : list) {
+            cookieMap.put(cookie.name(), cookie);
+        }
+
+        if (list != null && list.size() > 0) {
+            //存到本地,需要自己写持久化的实现,可用redis,或本地
+        }
+
+        log("-----保存到cookie:" + cookieStore.toString());
+        log("------------------------:");
+    }
+
+    @Override
+    public List<Cookie> loadForRequest(HttpUrl httpUrl) {
+        log("---加载 cookie");
+        List<Cookie> cookies = new ArrayList<>();
+        Map<String, Cookie> cookieMap = cookieStore.get(httpUrl.host());
+        if (cookieMap != null) {
+            cookieMap.forEach((name, cookie)->{
+                log("--cookie:" + name + "=" + cookie.value());
+                cookies.add(cookie);
+            });
+        }
+        log("---load cookie");
+        return cookies;
+    }
+
+    public static void setToken(String token) {
+        TOKEN = token;
+    }
+
+    public static String getToken() {
+        return TOKEN;
+    }
+
+    /**
+     * 保存cookie
+     * @param resPath 资源文件目录
+     */
+    public static void saveCookie (String resPath, ConcurrentHashMap<String, ConcurrentHashMap<String, Cookie>> cookieMap) {
+
+    }
+
+    /**
+     * 保存到文件
+     * @param resPath 资源文件目录
+     */
+    public static void saveToFile (String resPath, String str) {
+        URL resource = MyCookieStore.class.getResource(resPath);
+        try {
+            IOUtils.write(str.getBytes(), new FileOutputStream(resource.getFile()));
+        } catch (IOException e) {
+            System.out.println("---保存数据到本地失败");
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 加载cookie到内存
+     */
+    public static void loadCookie() {
+        InputStream resourceAsStream = MyCookieStore.class.getResourceAsStream(COOKIE_FILE_PATH);
+        String cookieTxt = null;
+        try {
+            cookieTxt = IOUtils.toString(resourceAsStream);
+            if (StringUtils.isNotBlank(cookieTxt)) {
+                //转成对象
+                ConcurrentHashMap<String, ConcurrentHashMap<String, Cookie>> nativeCookie = JsonUtils.jsonToObj(cookieTxt,
+                        new TypeReference<ConcurrentHashMap<String, ConcurrentHashMap<String, Cookie>>>() {});
+                cookieStore = nativeCookie;
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 加载token到内存
+     */
+    public static void loadToken() {
+        InputStream resourceAsStream = MyCookieStore.class.getResourceAsStream(TOKEN_FILE_PATH);
+        String s = null;
+        try {
+            s = IOUtils.toString(resourceAsStream);
+            TOKEN = s;
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static void log(String log) {
+        if (!debug) {
+            return;
+        }
+        System.out.println(log);
+    }
+
+}

+ 50 - 0
src/main/java/com/cslg/ppa/common/okhttp/MyOkHttpClient.java

@@ -0,0 +1,50 @@
+package com.cslg.ppa.common.okhttp;
+
+import okhttp3.*;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 静态化一个okhttp实例
+ * @author zsq
+ * @version 1.0
+ * @date 2021/3/31 10:58
+ */
+public class MyOkHttpClient {
+
+    /**okhttp实例**/
+    public static OkHttpClient client;
+
+    private static String referer = "https://mp.weixin.qq.com/";
+    private static String userAgent = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.190 Safari/537.36";
+    private static String xRequestedWith = "XMLHttpRequest";
+
+    static {
+        //初始化一个okhttp实例
+        client = new OkHttpClient.Builder()
+                .connectTimeout(15, TimeUnit.SECONDS)
+                .connectionPool(new ConnectionPool(5, 20, TimeUnit.SECONDS))
+                .readTimeout(15, TimeUnit.SECONDS)
+
+
+                //管理cookie
+                .cookieJar(new MyCookieStore())
+                //添加请求头
+                .addInterceptor(new Interceptor() {
+                    @Override
+                    public Response intercept(Chain chain) throws IOException {
+                        //添加请求头
+                        Request request = chain.request().newBuilder()
+                                .addHeader("referer", referer)
+                                .addHeader("userAgent", userAgent)
+                                .addHeader("xRequestedWith", xRequestedWith)
+                                .build();
+
+                        return chain.proceed(request);
+                    }
+                })
+                .build();
+    }
+
+}

+ 9 - 0
src/main/java/com/cslg/ppa/common/utils/BackupUtils.java

@@ -0,0 +1,9 @@
+package com.cslg.ppa.common.utils;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class BackupUtils {
+
+
+}

+ 83 - 0
src/main/java/com/cslg/ppa/common/utils/BeanUtil.java

@@ -0,0 +1,83 @@
+package com.cslg.ppa.common.utils;
+
+
+import com.cslg.ppa.common.core.log.LogHelper;
+import com.cslg.ppa.common.exception.BusinessException;
+import com.cslg.ppa.common.exception.ExceptionEnum;
+
+public  class BeanUtil {
+
+
+	/**
+	* @Title: copy
+	* @Description: 类属性复制
+	* @param @param source
+	* @param @param target    参数
+	* @return void    返回类型
+	* @throws
+	*/
+	public static void copy(Object source,Object target){
+		org.springframework.beans.BeanUtils.copyProperties(source, target);
+	}
+
+	/**
+	 * @name: 克隆source为新对象
+	 * @author Peach
+	 * @date:2018/9/4
+	 */
+	public static <T> T cloneNewObject(Object source,Class<T> clazz){
+		T t = null;
+		try {
+			t = clazz.newInstance();
+		} catch (Exception e) {
+			LogHelper.log(BeanUtil.class, "泛型实例化异常:" + clazz.getName(), e);
+			throw new BusinessException(ExceptionEnum.INIT_GENERICITY_BEAN_ERROR);
+		}
+		BeanUtil.copy(source,t);
+		return t;
+	}
+
+
+	/**
+	 * @Title: newTclass
+	 * @Description: 实例化泛型类
+	 * @param @param
+	 *            clazz
+	 * @param @return
+	 * @param @throws
+	 *            InstantiationException
+	 * @param @throws
+	 *            IllegalAccessException 参数
+	 * @return T 返回类型
+	 * @throws @author
+	 *             Orange
+	 * @date 2018年1月16日
+	 */
+	public static <T> T newTclass(Class<T> clazz) {
+		T a = null;
+		try {
+			a = clazz.newInstance();
+		} catch (Exception e) {
+			LogHelper.log(BeanUtil.class, "泛型实例化异常:" + clazz.getName(), e);
+			throw new BusinessException(ExceptionEnum.INIT_GENERICITY_BEAN_ERROR);
+		}
+		return a;
+	}
+
+	public static Object[] getEntities(Object target, Class<?>[] objs) {
+		Object[] entities = new Object[objs.length];
+		int count = 0;
+		for (Class<?> o : objs) {
+			Object entity = null;
+			try {
+				entity = o.newInstance();
+			} catch (Exception e) {
+				continue;
+			}
+			if (target != null)
+				copy(target, entity);
+			entities[count ++] = entity;
+		}
+		return entities;
+	}
+}

+ 249 - 0
src/main/java/com/cslg/ppa/common/utils/DataUtils.java

@@ -0,0 +1,249 @@
+package com.cslg.ppa.common.utils;
+
+
+import cn.dev33.satoken.secure.SaSecureUtil;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Base64Utils;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.MessageDigest;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+@Component
+public class DataUtils {
+
+    //秘钥
+    public static final String PASSWORD_KEY = "835a9bdc-4f9f-4614-a0cc-493a12454156";
+
+
+
+    /**
+     * 对称加密
+     */
+    public static String aesEncrypt(String password) {
+        return SaSecureUtil.aesEncrypt(PASSWORD_KEY, password);
+    }
+
+    /**
+     * 对称解密
+     */
+    public static String aesDecrypt(String password) {
+        return SaSecureUtil.aesDecrypt(PASSWORD_KEY, password);
+    }
+
+    /**
+     * @return 1.对比数据库内减少了那些数据 2.对比数据库内改变了那些数据(新增 修改) 3.两份数组中不变的数据
+     * @author 沈永艺
+     * @description 计算数据库内已有数据List 和 前台传入新的数据List 之间的比较
+     */
+    public static Map<String, List<Integer>> compareTwoList(List<Integer> dbList, List<Integer> frontList) {
+        //创建一个存放比对结果的Map 数组
+        Map<String, List<Integer>> comparisonResults = new HashMap<>();
+        //减少
+        List<Integer> reduce = dbList.stream().filter(item -> !frontList.contains(item)).collect(Collectors.toList());
+        //改变
+        List<Integer> change = frontList.stream().filter(item -> !dbList.contains(item)).collect(Collectors.toList());
+        //不变
+        List<Integer> unChange = dbList.stream().filter(frontList::contains).collect(Collectors.toList());
+        //填充数据
+        comparisonResults.put("reduce", reduce);
+        comparisonResults.put("change", change);
+        comparisonResults.put("unChange", unChange);
+        return comparisonResults;
+    }
+
+    /**
+     * @return 去重后的数据
+     * @author 沈永艺
+     * @description 在对象数组中按照某一类属性进行去重
+     */
+    //用例:待去重List.stream().filter(DataUtils.distinctByKey(对象::get属性字段)).collect(Collectors.toList());
+    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
+        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
+    }
+
+    /**
+     * @return 计算完成度
+     * @author 沈永艺
+     * @description 输入完成数量和全部数量计算完成百分比
+     */
+    public String calculateCompletion(Integer finishNum, Integer allNum) {
+        return finishNum / allNum + "%";
+    }
+
+    /**
+     * @return 拆分出的特征
+     * @author 沈永艺
+     * @description 处理权利要求
+     */
+    // TODO: 2022/11/2 未完成
+    public List<String> processRightToFeatures(List<String> rightList, String patentNo) {
+        List<String> features = new ArrayList<>();
+        if (patentNo != null) {
+            String country = patentNo.substring(0, 2);
+            if (country.equals("CN") || country.equals("JP")) {
+
+            } else {
+
+            }
+        }
+
+        return features;
+    }
+
+
+    /**
+     * 比较两个字符串的相识度
+     * 核心算法:用一个二维数组记录每个字符串是否相同,如果相同记为0,不相同记为1,每行每列相同个数累加
+     * 则数组最后一个数为不相同的总数,从而判断这两个字符的相识度
+     *
+     * @param str
+     * @param target
+     * @return
+     */
+    private static int compare(String str, String target) {
+        int d[][];              // 矩阵
+        int n = str.length();
+        int m = target.length();
+        int i;                  // 遍历str的
+        int j;                  // 遍历target的
+        char ch1;               // str的
+        char ch2;               // target的
+        int temp;               // 记录相同字符,在某个矩阵位置值的增量,不是0就是1
+        if (n == 0) {
+            return m;
+        }
+        if (m == 0) {
+            return n;
+        }
+        d = new int[n + 1][m + 1];
+        // 初始化第一列
+        for (i = 0; i <= n; i++) {
+            d[i][0] = i;
+        }
+        // 初始化第一行
+        for (j = 0; j <= m; j++) {
+            d[0][j] = j;
+        }
+        for (i = 1; i <= n; i++) {
+            // 遍历str
+            ch1 = str.charAt(i - 1);
+            // 去匹配target
+            for (j = 1; j <= m; j++) {
+                ch2 = target.charAt(j - 1);
+                if (ch1 == ch2 || ch1 == ch2 + 32 || ch1 + 32 == ch2) {
+                    temp = 0;
+                } else {
+                    temp = 1;
+                }
+                // 左边+1,上边+1, 左上角+temp取最小
+                d[i][j] = min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + temp);
+            }
+        }
+        return d[n][m];
+    }
+
+
+    /**
+     * 获取最小的值
+     */
+    private static int min(int one, int two, int three) {
+        return (one = one < two ? one : two) < three ? one : three;
+    }
+
+    /**
+     * 获取两字符串的相似度
+     */
+    public static float getSimilarityRatio(String str, String target) {
+        int max = Math.max(str.length(), target.length());
+        return 1 - (float) compare(str, target) / max;
+
+    }
+
+
+    public static String[] chars = new String[] { "a", "b", "c", "d", "e", "f",
+            "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
+            "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
+            "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
+            "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
+            "W", "X", "Y", "Z" };
+
+    public static String generateShortUuid() {
+        StringBuffer shortBuffer = new StringBuffer();
+        String uuid = UUID.randomUUID().toString().replace("-", "");
+        for (int i = 0; i < 8; i++) {
+            String str = uuid.substring(i * 4, i * 4 + 4);
+            int x = Integer.parseInt(str, 16);
+            shortBuffer.append(chars[x % 0x3E]);
+        }
+        return shortBuffer.toString();
+    }
+
+    public static <T> List<T> objToList(Object obj, Class<T> cla){
+        List<T> list = new ArrayList<T>();
+        if (obj instanceof ArrayList<?>) {
+            for (Object o : (List<?>) obj) {
+                list.add(cla.cast(o));
+            }
+            return list;
+        }
+        return null;
+    }
+
+    public static String MD5Base64(String s) {
+        if (s == null)
+            return null;
+        String encodeStr = "";
+        byte[] utfBytes = s.getBytes();
+        MessageDigest mdTemp;
+        try {
+            mdTemp = MessageDigest.getInstance("MD5");
+            mdTemp.update(utfBytes);
+            byte[] md5Bytes = mdTemp.digest();
+            byte[] by =  Base64.getEncoder().encode(md5Bytes);
+
+            encodeStr = Base64Utils.encodeToString(by);
+        } catch (Exception e) {
+            throw new Error("Failed to generate MD5 : " + e.getMessage());
+        }
+        return encodeStr;
+    }
+    /*
+     * 计算 HMAC-SHA1
+     */
+    public static String HMACSha1(String data, String key) {
+        String result;
+        try {
+            SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), "HmacSHA1");
+            Mac mac = Mac.getInstance("HmacSHA1");
+            mac.init(signingKey);
+            byte[] rawHmac = mac.doFinal(data.getBytes());
+            byte[] by =Base64.getEncoder().encode(rawHmac);
+            result = Base64Utils.encodeToString(by);
+        } catch (Exception e) {
+            throw new Error("Failed to generate HMAC : " + e.getMessage());
+        }
+        return result;
+    }
+
+    //将Unicode代码转为字符
+    public static String unicodeDecode(String string) {
+        Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
+        Matcher matcher = pattern.matcher(string);
+        char ch;
+        while (matcher.find()) {
+            ch = (char) Integer.parseInt(matcher.group(2), 16);
+            string = string.replace(matcher.group(1), ch + "");
+        }
+        return string;
+    }
+
+}

+ 387 - 0
src/main/java/com/cslg/ppa/common/utils/DateUtil.java

@@ -0,0 +1,387 @@
+/**
+ * Copyright (c) 2015-2016, Chill Zhuang 庄骞 (smallchill@163.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cslg.ppa.common.utils;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.time.DateFormatUtils;
+
+import java.sql.Timestamp;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.*;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+public class DateUtil {
+
+
+
+	/**
+	 * 获取YYYY格式
+	 *
+	 * @return
+	 */
+
+	public static String getYear() {
+		return formatDate(new Date(), "yyyy");
+	}
+
+
+	/**
+	 * 获取YYYY格式
+	 *
+	 * @return
+	 */
+
+	public static String getYear(Date date) {
+		return formatDate(date, "yyyy");
+	}
+
+	public static String getCurrentServerDate(String format) {
+		return formatDate(new Date(), format);
+	}
+	
+
+	/**
+	 * 获取YYYY-MM-DD格式
+	 *
+	 * @return
+	 */
+
+	public static String getDay() {
+		return formatDate(new Date(), "yyyy-MM-dd");
+	}
+
+
+	/**
+	 * 获取YYYY-MM-DD格式
+	 *
+	 * @return
+	 */
+
+	public static String getDay(Date date) {
+		return formatDate(date, "yyyy-MM-dd");
+	}
+
+
+	/**
+	 * 获取YYYYMMDD格式
+	 *
+	 * @return
+	 */
+
+	public static String getDays() {
+		return formatDate(new Date(), "yyyyMMdd");
+	}
+
+
+	/**
+	 * 获取YYYYMMDD格式
+	 *
+	 * @return
+	 */
+
+	public static String getDays(Date date) {
+		return formatDate(date, "yyyyMMdd");
+	}
+
+	/**
+	 * 获取YYYY-MM-DD HH:mm:ss格式
+	 *
+	 * @return
+	 */
+
+	public static String getTime() {
+		return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss");
+	}
+
+
+ 	/**
+	 * 获取YYYY-MM-DD HH:mm:ss.SSS格式
+	 *
+	 * @return
+	 */
+
+	public static String getMsTime() {
+		return formatDate(new Date(), "yyyy-MM-dd HH:mm:ss.SSS");
+	}
+
+
+	/**
+	 * 获取YYYYMMDDHHmmss格式
+	 *
+	 * @return
+	 */
+
+	public static String getAllTime() {
+		return formatDate(new Date(), "yyyyMMddHHmmss");
+	}
+
+	/**
+	 * 获取YYYY-MM-DD HH:mm:ss格式
+	 *
+	 * @return
+	 */
+
+	public static String getTime(Date date) {
+		return formatDate(date, "yyyy-MM-dd HH:mm:ss");
+	}
+
+	public static String formatDate(Date date, String pattern) {
+		String formatDate = null;
+		if (StringUtils.isNotBlank(pattern)) {
+			formatDate = DateFormatUtils.format(date, pattern);
+		} else {
+			formatDate = DateFormatUtils.format(date, "yyyy-MM-dd");
+		}
+		return formatDate;
+	}
+
+
+	/**
+	 * 格式化日期
+	 *
+	 * @return
+	 */
+
+	public static String format(Date date, String pattern) {
+		return DateFormatUtils.format(date, pattern);
+	}
+
+
+	/**
+	 * 把日期转换为Timestamp
+	 *
+	 * @param date
+	 * @return
+	 */
+
+	public static Timestamp format(Date date) {
+		return new Timestamp(date.getTime());
+	}
+
+
+	public static int getDiffYear(String startTime, String endTime) {
+		DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd");
+		try {
+			int years = (int) (((fmt.parse(endTime).getTime() - fmt.parse(
+					startTime).getTime()) / (1000 * 60 * 60 * 24)) / 365);
+			return years;
+		} catch (Exception e) {
+			// 如果throw java.text.ParseException或者NullPointerException,就说明格式不对
+			return 0;
+		}
+	}
+
+
+	/**
+	 * <li>功能描述:时间相减得到天数
+	 *
+	 * @param beginDateStr
+	 * @param endDateStr
+	 * @return long
+	 * @author Administrator
+	 */
+
+	public static long getDaySub(String beginDateStr, String endDateStr) {
+		long day = 0;
+		SimpleDateFormat format = new SimpleDateFormat(
+				"yyyy-MM-dd");
+		Date beginDate = null;
+		Date endDate = null;
+
+		try {
+			beginDate = format.parse(beginDateStr);
+			endDate = format.parse(endDateStr);
+		} catch (ParseException e) {
+			e.printStackTrace();
+		}
+		day = (endDate.getTime() - beginDate.getTime()) / (24 * 60 * 60 * 1000);
+		// System.out.println("相隔的天数="+day);
+
+		return day;
+	}
+
+
+	/**
+	 * 得到n天之后的日期
+	 *
+	 * @param days
+	 * @return
+	 */
+
+	public static String getAfterDayDate(String days) {
+		int daysInt = Integer.parseInt(days);
+
+		Calendar canlendar = Calendar.getInstance(); // java.util包
+		canlendar.add(Calendar.DATE, daysInt); // 日期减 如果不够减会将月变动
+		Date date = canlendar.getTime();
+
+		SimpleDateFormat sdfd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+		String dateStr = sdfd.format(date);
+
+		return dateStr;
+	}
+
+
+	/**
+	 * 得到n天之后是周几
+	 *
+	 * @param days
+	 * @return
+	 */
+
+	public static String getAfterDayWeek(String days) {
+		int daysInt = Integer.parseInt(days);
+
+		Calendar canlendar = Calendar.getInstance(); // java.util包
+		canlendar.add(Calendar.DATE, daysInt); // 日期减 如果不够减会将月变动
+		Date date = canlendar.getTime();
+
+		SimpleDateFormat sdf = new SimpleDateFormat("E");
+		String dateStr = sdf.format(date);
+
+		return dateStr;
+	}
+
+
+	/**
+	 * 格式化Oracle Date
+	 * @param value
+	 * @return
+	 */
+
+//	public static String buildDateValue(Object value){
+//		if(Func.isOracle()){
+//			return "to_date('"+ value +"','yyyy-mm-dd HH24:MI:SS')";
+//		}else{
+//			return Func.toStr(value);
+//		}
+//	}
+
+	/**
+	 * @Description: 获取当前时间的周一及周日
+	 * @Param: Date
+	 * @Author: LHX
+	 * @Date: 9:59 2018/11/19
+	 * @return: java.util.Map<java.lang.String,java.lang.String>
+	 */
+
+	public static Map<String,String> getWeekDate(Date date) {
+		Map<String,String> map = new HashMap();
+		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(date);
+		// 设置一个星期的第一天,按中国的习惯一个星期的第一天是星期一
+		cal.setFirstDayOfWeek(Calendar.MONDAY);
+		// 获得当前日期是一个星期的第几天
+		int dayWeek = cal.get(Calendar.DAY_OF_WEEK);
+		if(dayWeek==1){
+			dayWeek = 8;
+		}
+		// 根据日历的规则,给当前日期减去星期几与一个星期第一天的差值
+		cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - dayWeek);
+		Date mondayDate = cal.getTime();
+		String weekBegin = sdf.format(mondayDate);
+		//获取星期日
+		cal.add(Calendar.DATE, 4 +cal.getFirstDayOfWeek());
+		Date sundayDate = cal.getTime();
+		String weekEnd = sdf.format(sundayDate);
+		map.put("mondayDate", weekBegin);
+		map.put("sundayDate", weekEnd);
+		return map;
+	}
+
+	public static void main(String[] args) {
+		System.out.println(getTime(new Date()));
+		System.out.println(getAfterDayWeek("3"));
+	}
+
+	public static Long getRemainingSecond() {
+		// 获取当前时间
+		LocalDateTime now = LocalDateTime.now();
+
+		// 计算当天零点的时间
+		LocalDateTime midnight = now.plusDays(1).truncatedTo(ChronoUnit.DAYS);
+
+		// 转换为ZonedDateTime以获取时区信息
+		ZonedDateTime zonedDateTime = midnight.atZone(ZoneId.systemDefault());
+
+		// 转换为Unix时间戳(秒)
+		long midnightTimestamp = TimeUnit.MILLISECONDS.toSeconds(zonedDateTime.toInstant().toEpochMilli());
+
+		// 获取当前时间的Unix时间戳(秒)
+		long currentTimestamp = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis());
+
+		// 计算剩余秒数直到当天零点
+
+//		// 如果已经过了零点,则设置过期时间为0或者重新计算逻辑
+//		if (ttlSeconds <= 0) {
+//			ttlSeconds = 0; // 或者你可以设置为其他逻辑,比如下一个天的零点
+//		}
+		return midnightTimestamp - currentTimestamp;
+	}
+
+	/**
+	 * 获取当前日期减1天的 Date 对象
+	 */
+	public static Date getYesterdayDate() {
+		// 使用 Java 8 的 LocalDate 计算日期
+		LocalDate yesterdayLocalDate = LocalDate.now().minusDays(1);
+
+		// 将 LocalDate 转换为 Date 对象(基于系统默认时区)
+		return Date.from(yesterdayLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
+	}
+
+	/**
+	 * 获取当前日期减1天的 String 对象
+	 */
+	public static String getYesterdayDateStr() {
+		return LocalDate.now().minusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+	}
+
+	/**
+	 * 判断两个 Date 对象的日期部分是否相等(忽略时间)
+	 */
+	public static boolean isDateEqualIgnoreTime(Date date1, Date date2) {
+		if (date1 == null || date2 == null) {
+			return false;
+		}
+		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+		String str1 = sdf.format(date1);
+		String str2 = sdf.format(date2);
+		return str1.equals(str2);
+	}
+
+	public static String convertTimestamp(long timestamp) {
+		// 将秒级时间戳转换为Instant对象
+		Instant instant = Instant.ofEpochSecond(timestamp);
+		// 创建日期格式化器,并指定UTC时区
+		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
+				.withZone(ZoneId.of("GMT+8"));
+		// 格式化Instant为字符串
+		return formatter.format(instant);
+	}
+}
+

+ 763 - 0
src/main/java/com/cslg/ppa/common/utils/DateUtils.java

@@ -0,0 +1,763 @@
+package com.cslg.ppa.common.utils;
+
+
+import com.cslg.ppa.entity.commom.Calculate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.management.ManagementFactory;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.regex.Pattern;
+
+public class DateUtils {
+    public static final String START_TIME = " 00:00:00";
+    public static final String END_TIME = " 23:59:59";
+    public final static String FORMAT_STRING = "yyyy-MM-dd HH:mm:ss";
+    public final static String[] REPLACE_STRING = new String[]{"GMT+0800", "GMT+08:00"};
+    public final static String SPLIT_STRING = "(中国标准时间)";
+    public static Logger log = LoggerFactory.getLogger(DateUtils.class);
+    public static String YYYY = "yyyy";
+    public static String YYYY_MM = "yyyy-MM";
+    public static String YYYY_MM_DD = "yyyy-MM-dd";
+    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
+    public static String YYYYMMDD = "yyyyMMdd";
+    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
+    private static String[] parsePatterns = {
+            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
+            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
+            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
+
+//    public static String getDateSourceName(Date startTime, Date endTime, Integer offset, Integer index) {
+//        String ret = null;
+//        switch (offset) {
+//            //月份
+//            case -1:
+//                ret = DateUtil.format(startTime, "yyyy-MM");
+//                break;
+//            //季度
+//            case -3:
+//                ret = String.format("%s-Q%s", DateUtil.format(startTime, "yyyy"), (index % 4) + 1);
+//                break;
+//            //半年
+//            case -6:
+//                ret = String.format("%s-%s", DateUtil.format(startTime, "yyyy"), index % 2 == 0 ? "H1" : "H2");
+//                break;
+//            //1年
+//            case -12:
+//                ret = DateUtil.format(startTime, "yyyy");
+//                break;
+//            //2年,3年,5年
+//            case -24:
+//            case -36:
+//            case -60:
+//                ret = String.format("%s-%s", DateUtil.format(DateUtil.offsetMonth(endTime, offset / 12 * -1), "yyyy"), DateUtil.format(startTime, "yyyy"));
+//                break;
+//        }
+//        return ret;
+//    }
+//
+//    private DateUtils() {
+//    }
+
+
+
+    public static boolean belongCalendar(Date nowTime, Date beginTime, Date endTime) {
+        Calendar date = Calendar.getInstance();
+        date.setTime(nowTime);
+        Calendar begin = Calendar.getInstance();
+        begin.setTime(beginTime);
+        Calendar end = Calendar.getInstance();
+        end.setTime(endTime);
+        return date.after(begin) && date.before(end);
+    }
+
+    /**
+     * 获取现在的时间 yyyy-MM-dd HH:mm:ss
+     */
+    public static String getNowTime() {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Date date = new Date(System.currentTimeMillis());
+        return format.format(date);
+    }
+
+    /**
+     * 获取当前Date型日期
+     *
+     * @return Date() 当前日期
+     */
+    public static Date getNowDate() {
+        return new Date();
+    }
+
+    public static Integer getDateTime() {
+        return (int) (new Date().getTime() / 1000);
+    }
+
+//    public static Integer getDateTime(String date) {
+//        int dateTime = 0;
+//        if (date.contains("/")) {
+//            dateTime = Math.toIntExact(strToDateTime(date, parsePatterns[4]).getTime() / 1000);
+//        } else if (date.contains("-")) {
+//            dateTime = Math.toIntExact(strToDateTime(date, YYYY_MM_DD).getTime() / 1000);
+//        }
+//        return dateTime;
+//    }
+
+        public static Date getDateTime(String date) {
+        Date dateTime = null;
+        if (date.contains("/")) {
+            dateTime = strToDateTime(date, parsePatterns[4]);
+        } else if (date.contains("-")) {
+            dateTime = strToDateTime(date, YYYY_MM_DD);
+        }
+        return dateTime;
+    }
+
+    /**
+     * @author 陌溪
+     * @date 2018年6月14日
+     */
+    public static String getNowTimeFormat(String format) {
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
+        Date date = new Date(System.currentTimeMillis());
+        return simpleDateFormat.format(date);
+    }
+
+
+    public static Date str2Date(String dateString) {
+        try {
+            dateString = dateString.split(Pattern.quote(SPLIT_STRING))[0].replace(REPLACE_STRING[0], REPLACE_STRING[1]);
+            SimpleDateFormat sf1 = new SimpleDateFormat("E MMM dd yyyy HH:mm:ss z", Locale.US);
+            return sf1.parse(dateString);
+        } catch (Exception e) {
+            throw new RuntimeException("时间转化格式错误" + "[dateString=" + dateString + "]" + "[FORMAT_STRING=" + FORMAT_STRING + "]");
+        }
+    }
+
+    public static Date strToDate(String dateString) {
+        try {
+            SimpleDateFormat sf1;
+            if (dateString.contains("-")) {
+                sf1 = new SimpleDateFormat("yyyy-MM-dd");
+            } else if (dateString.contains("/")) {
+                sf1 = new SimpleDateFormat("yyyy/MM/dd");
+            } else if (dateString.contains(":")) {
+                sf1 = new SimpleDateFormat("yyyy:MM:dd");
+            } else if (dateString.contains(".")) {
+                sf1 = new SimpleDateFormat("yyyy.MM.dd");
+            } else {
+                sf1 = new SimpleDateFormat("yyyyMMdd");
+            }
+
+            return sf1.parse(dateString);
+        } catch (Exception e) {
+            System.out.println ("时间转化格式错误" + "[dateString=" + dateString + "]" + "[FORMAT_STRING=" + FORMAT_STRING + "]");
+
+            return null;
+        }
+    }
+
+    /**
+     * 获取今天开始的时间
+     */
+    public static String getToDayStartTime() {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        Date date = new Date(System.currentTimeMillis());
+        return format.format(date);
+    }
+
+    /**
+     * 获取今天结束的时间
+     */
+    public static String getToDayEndTime() {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
+        Date date = new Date(System.currentTimeMillis());
+        return format.format(date);
+    }
+
+    /**
+     * 获取昨天开始的时间
+     */
+    public static String getYesterdayStartTime() {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        Date date = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000L);
+        return format.format(date);
+    }
+
+    /**
+     * 获取昨天结束的时间
+     */
+    public static String getYesterdayEndTime() {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
+        Date date = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000L);
+        return format.format(date);
+    }
+
+    /**
+     * 获取某天开始的时间
+     */
+    public static String getOneDayStartTime(String oneDay) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        Date date = new Date(oneDay);
+        return format.format(oneDay);
+    }
+
+    /**
+     * 获取某天开始的日期
+     */
+    public static String getOneDayStartTime(Date oneDay) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        return format.format(oneDay);
+    }
+
+    /**
+     * 获取某天结束的时间
+     */
+    public static String getOneDayEndTime(String oneDay) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        Date date = new Date(oneDay);
+        return format.format(date);
+    }
+
+    /**
+     * 获取某天结束的日期
+     */
+    public static String getOneDayEndTime(Date oneDay) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        return format.format(oneDay);
+    }
+
+    /**
+     * 获取本周开始的时间
+     */
+    public static Date getWeekStartTime() {
+        //获得本周一0点时间
+        Calendar cal = Calendar.getInstance();
+        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
+        return cal.getTime();
+    }
+
+    /**
+     * 将 String 转换成 Date
+     */
+    public static Date strToDateTime(String dateTime) {
+        Date date = null;
+        try {
+            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            date = format.parse(dateTime);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return date;
+    }
+
+    /**
+     * 将 String 转换成 Date (转换格式可传入)
+     */
+    public static Date strToDateTime(String dateTime, String fmt) {
+        Date date = null;
+        try {
+            SimpleDateFormat format = new SimpleDateFormat(fmt);
+            date = format.parse(dateTime);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return date;
+    }
+
+    /**
+     * 将 Date 转换成时间戳
+     */
+    public static Long dateToStamp(String s) throws ParseException {
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Date date = simpleDateFormat.parse(s);
+        return date.getTime();
+    }
+
+    /**
+     * 将 Date 转换成 String
+     */
+    public static String dateTimeToStr(Date dateTime) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        return format.format(dateTime);
+    }
+
+    public static String dateTimeToStr(Date dateTime, String fmt) {
+
+        SimpleDateFormat format = new SimpleDateFormat(fmt);
+        return format.format(dateTime);
+    }
+
+    /**
+     * 获取本周开始的时间的字符串
+     */
+    public static String getWeekStartTimeStr() {
+        //获得本周一0点时间
+        Calendar cal = Calendar.getInstance();
+        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        return format.format(cal.getTime());
+    }
+
+    /**
+     * 获取本周结束的时间
+     */
+    public static Date getWeekEndTime() {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(getWeekStartTime());
+        cal.add(Calendar.DAY_OF_WEEK, 7);
+        return cal.getTime();
+    }
+
+    /**
+     * 获取本周结束的时间的字符串
+     */
+    public static String getWeekEndTimeStr() {
+        Calendar cal = Calendar.getInstance();
+        cal.setTime(getWeekStartTime());
+        cal.add(Calendar.DAY_OF_WEEK, 7);
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
+        return format.format(cal.getTime());
+    }
+
+    /**
+     * 获取上周开始的时间的字符串
+     */
+    public static String getLastWeekStartTimeStr() {
+        int weeks = -1;
+        int mondayPlus = getMondayPlus();
+        GregorianCalendar currentDate = new GregorianCalendar();
+        currentDate.add(GregorianCalendar.DATE, mondayPlus + 7 * weeks);
+        Date monday = currentDate.getTime();
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
+        return format.format(monday);
+    }
+
+    /**
+     * 获取本月开始的时间
+     */
+    public static Date getMonthStartTime() {
+        Calendar cal = Calendar.getInstance();
+        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH));
+        return cal.getTime();
+    }
+
+    /**
+     * 获取本月开始的时间的字符串
+     */
+    public static String getMonthStartTimeStr() {
+        Calendar cal = Calendar.getInstance();
+        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH));
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
+        return format.format(cal.getTime());
+    }
+
+    /**
+     * 获取本月结束的时间
+     */
+    public static Date getMonthEndTime() {
+        Calendar cal = Calendar.getInstance();
+        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
+        cal.set(Calendar.HOUR_OF_DAY, 24);
+        return cal.getTime();
+    }
+
+    /**
+     * 获取本月结束的时间的字符串
+     */
+    public static String getMonthEndTimeStr() {
+        Calendar cal = Calendar.getInstance();
+        cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
+        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
+        cal.set(Calendar.HOUR_OF_DAY, 24);
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
+        return format.format(cal.getTime());
+    }
+
+    /**
+     * 获取当月的 天数
+     */
+    public static int getCurrentMonthDay() {
+        Calendar a = Calendar.getInstance();
+        a.set(Calendar.DATE, 1);
+        a.roll(Calendar.DATE, -1);
+        return a.get(Calendar.DATE);
+    }
+
+    /**
+     * 得到二个日期间的间隔天数
+     */
+    public static int getDayByTwoDay(String date1, String date2) {
+        SimpleDateFormat myFormatter = new SimpleDateFormat("yyyy-MM-dd");
+        long day;
+        try {
+            Date date = myFormatter.parse(date1);
+            Date myDate = myFormatter.parse(date2);
+            day = (date.getTime() - myDate.getTime()) / (24 * 60 * 60 * 1000);
+        } catch (Exception e) {
+            return 0;
+        }
+        return (int) day;
+    }
+
+    /**
+     * 得到两个日期相差的秒数
+     */
+    public static int getSecondByTwoDay(Date lastDate, Date date) {
+        long second;
+        try {
+            second = (lastDate.getTime() - date.getTime()) / 1000;
+        } catch (Exception e) {
+            return 0;
+        }
+        return (int) second;
+    }
+
+    /**
+     * 判断某个日期属于本周的第几天 (星期一代表第一天)
+     */
+    public static int getDaysByWeek(String dateTime) throws ParseException {
+        Calendar cal = Calendar.getInstance();
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        Date date = dateFormat.parse(dateTime);
+        cal.setTime(date);
+        int day = cal.get(Calendar.DAY_OF_WEEK);
+        day = day - 1;
+        if (day == 0) {
+            day = 7;
+        }
+        return day;
+    }
+
+    /**
+     * 判断某个日期属于本月的第几天
+     */
+    public static int getDaysByMonth(String dateTime) throws ParseException {
+        Calendar cal = Calendar.getInstance();
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        Date date = dateFormat.parse(dateTime);
+        cal.setTime(date);
+        return cal.get(Calendar.DAY_OF_MONTH);
+    }
+
+    /**
+     * 根据年 月 获取对应的月份 天数
+     */
+    public static int getDaysByYearMonth(int year, int month) {
+        Calendar a = Calendar.getInstance();
+        a.set(Calendar.YEAR, year);
+        a.set(Calendar.MONTH, month - 1);
+        a.set(Calendar.DATE, 1);
+        a.roll(Calendar.DATE, -1);
+        return a.get(Calendar.DATE);
+    }
+
+
+    /**
+     * 获取当前的年
+     */
+    public static Integer getYears() {
+        Calendar calendar = new GregorianCalendar(TimeZone
+                .getDefault());
+        return calendar.get(Calendar.YEAR);
+    }
+
+    /**
+     * 获取当前的月
+     */
+    public static Integer getMonth() {
+        Calendar calendar = new GregorianCalendar(TimeZone
+                .getDefault());
+        return calendar.get(Calendar.MONTH) + 1;
+    }
+
+    /**
+     * 获取当前天
+     */
+    public static Integer getDay() {
+        Calendar calendar = new GregorianCalendar(TimeZone
+                .getDefault());
+        return calendar.get(Calendar.DAY_OF_MONTH);
+    }
+
+    /**
+     * wx支付的过期时间
+     */
+    public static String getTime(double hour) {
+        long time = (long) (System.currentTimeMillis() + hour * 60 * 60 * 1000L);
+        Date date = new Date(time);
+        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
+        return format.format(date);
+    }
+
+    /**
+     * 获得当前日期与本周日相差的天数
+     */
+    private static int getMondayPlus() {
+        Calendar cd = Calendar.getInstance();
+        // 获得今天是一周的第几天,星期日是第一天,星期二是第二天......
+        // 因为按中国礼拜一作为第一天所以这里减1
+        int dayOfWeek = cd.get(Calendar.DAY_OF_WEEK) - 1;
+        if (dayOfWeek == 1) {
+            return 0;
+        } else {
+            return 1 - dayOfWeek;
+        }
+    }
+
+    /**
+     * 获取几天之后的日期
+     *
+     * @param date yyyy-MM-dd HH:mm:ss
+     * @param day  加减的天数
+     */
+    public static Date getDate(String date, int day) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Calendar cal = Calendar.getInstance();
+        Date beforeDate;
+        try {
+            beforeDate = format.parse(date);
+            cal.setTime(beforeDate);
+            cal.add(Calendar.DAY_OF_MONTH, day);
+            return cal.getTime();
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 获取几天之后的日期
+     *
+     * @param date yyyy-MM-dd HH:mm:ss
+     * @param day  加减的天数
+     */
+    public static Date getDate(Date date, int day) {
+        Calendar cal = Calendar.getInstance();
+            cal.setTime(date);
+            cal.add(Calendar.DAY_OF_MONTH, day);
+            return cal.getTime();
+    }
+
+    /**
+     * 获取某个日期 在加上 秒数的时间
+     *
+     * @param beforeDate yyyy-MM-dd HH:mm:ss
+     * @param timeSecond 加减的秒数
+     */
+    public static String getDateStr(Date beforeDate, Long timeSecond) {
+        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        try {
+            // 返回毫秒数 + 添加的毫秒数
+            Long time = beforeDate.getTime() + timeSecond * 1000;
+            return format.format(time);
+        } catch (Exception e) {
+            log.error(e.getMessage());
+        }
+        return "";
+    }
+
+    /**
+     * 把date转换成字符串
+     */
+    public static String formatDate(Date date, String code) {
+        SimpleDateFormat format = new SimpleDateFormat(code);
+        return format.format(date);
+    }
+
+    public static String formatDate(Integer timestamp, String code) {
+        if (timestamp == null || timestamp == 0) {
+            return "";
+        }
+        return formatDate(new Date(timestamp * 1000L), code);
+    }
+
+    /**
+     * 获取过去N天内的日期数组
+     *
+     * @param intervals intervals天内
+     * @param formatStr 格式化字符串   yyyy-MM-dd
+     * @return 日期数组
+     */
+    public static ArrayList<String> getDaysByN(int intervals, String formatStr) {
+        ArrayList<String> pastDaysList = new ArrayList<>();
+        for (int i = intervals - 1; i >= 0; i--) {
+            pastDaysList.add(getPastDate(i, formatStr));
+        }
+        return pastDaysList;
+    }
+
+    /**
+     * 获取过去第几天的日期
+     */
+    public static String getPastDate(int past, String formatStr) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) - past);
+        Date today = calendar.getTime();
+        SimpleDateFormat format = new SimpleDateFormat(formatStr);
+        return format.format(today);
+    }
+
+    /**
+     * 获取某个时间段内所有日期
+     */
+    public static List<String> getDayBetweenDates(String begin, String end) {
+        Date dBegin = strToDateTime(begin);
+        Date dEnd = strToDateTime(end);
+        List<String> lDate = new ArrayList<>();
+        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
+        lDate.add(sd.format(dBegin));
+        Calendar calBegin = Calendar.getInstance();
+        // 使用给定的 Date 设置此 Calendar 的时间
+        calBegin.setTime(dBegin);
+        Calendar calEnd = Calendar.getInstance();
+        // 使用给定的 Date 设置此 Calendar 的时间
+        calEnd.setTime(dEnd);
+        // 测试此日期是否在指定日期之后
+        while (dEnd.after(calBegin.getTime())) {
+            // 根据日历的规则,为给定的日历字段添加或减去指定的时间量
+            calBegin.add(Calendar.DAY_OF_MONTH, 1);
+            lDate.add(sd.format(calBegin.getTime()));
+        }
+        return lDate;
+    }
+
+    /**
+     * 获取服务器启动时间
+     */
+    public static Date getServerStartDate() {
+        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
+        return new Date(time);
+    }
+
+    /**
+     * 计算两个时间差
+     */
+    public static String getDatePoor(Date endDate, Date nowDate) {
+        long nd = 1000 * 24 * 60 * 60;
+        long nh = 1000 * 60 * 60;
+        long nm = 1000 * 60;
+        // 获得两个时间的毫秒时间差异
+        long diff = endDate.getTime() - nowDate.getTime();
+        // 计算差多少天
+        long day = diff / nd;
+        // 计算差多少小时
+        long hour = diff % nd / nh;
+        // 计算差多少分钟
+        long min = diff % nd % nh / nm;
+        return day + "天" + hour + "小时" + min + "分钟";
+    }
+
+    public static long getTimeDiff(Date date) {
+        long NTime = date.getTime();
+        long OTime = getNowDate().getTime();
+        return (NTime - OTime) / 1000 / 60;
+    }
+
+    public static Date setDateHourAndMinute(Date date, int hour, int minute) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        calendar.set(Calendar.HOUR_OF_DAY, hour);
+        calendar.set(Calendar.MINUTE, minute);
+        calendar.set(Calendar.SECOND, 0);
+        return calendar.getTime();
+    }
+
+
+    /**
+     * 根据起止条数计算开始页数、开始页数的开始位置、结束页数、结束页数的结束位置
+     *
+     * @param startNumber 起始条数
+     * @param endNumber   终止条数
+     * @return 返回计算结果对象(开始页数、开始页数的开始位置、结束页数、结束页数的结束位置)
+     */
+    public static Calculate calculateFromStartAndEndNumber(Integer startNumber, Integer endNumber, Integer pageSize) {
+        int startPage;  //检索开始页数
+        int startNum;  //检索开始页数的开始专利位置
+        int endPage;  //检索结束页数
+        int endNum;  //检索结束页数的结束专利位置
+        if (startNumber % pageSize != 0) {
+            startPage = startNumber / pageSize;
+            startNum = startNumber % pageSize;
+        } else {
+            startPage = startNumber / pageSize;
+            startNum = pageSize;
+        }
+        if (endNumber % pageSize != 0) {
+            endPage = endNumber / pageSize + 1;
+            endNum = endNumber % pageSize;
+        } else {
+            endPage = endNumber / pageSize;
+            endNum = pageSize;
+        }
+
+        Calculate calculate = new Calculate()
+                .setStartPage(startPage)
+                .setStartNum(startNum)
+                .setEndPage(endPage)
+                .setEndNum(endNum);
+
+        return calculate;
+    }
+    /**
+     * 专利之星返回日期格式为字符串 yyyyMMdd,如 "20230713",本方法将其转成10位数字时间戳
+     *
+     * @param dateStr yyyyMMdd格式字符串日期
+     * @return 返回10位数字时间戳
+     */
+    public static int  stringDateToTimeStamp(String dateStr) {
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
+        Date date;
+        try {
+            date = dateFormat.parse(dateStr);
+        } catch (ParseException e) {
+            //日期格式转换异常
+            e.printStackTrace();
+            return Integer.parseInt(dateStr);
+        }
+        long timeStamp = date.getTime() / 1000;
+        return (int) timeStamp;
+    }
+
+    public static String strToStr(String dateString,String dateForm) {
+        try {
+            SimpleDateFormat sf1;
+            if (dateString.contains("-")) {
+                sf1 = new SimpleDateFormat("yyyy-MM-dd");
+            } else if (dateString.contains("/")) {
+                sf1 = new SimpleDateFormat("yyyy/MM/dd");
+            } else if (dateString.contains(":")) {
+                sf1 = new SimpleDateFormat("yyyy:MM:dd");
+            } else if (dateString.contains(".")) {
+                sf1 = new SimpleDateFormat("yyyy.MM.dd");
+            } else {
+                sf1 = new SimpleDateFormat("yyyyMMdd");
+            }
+
+
+            SimpleDateFormat format = new SimpleDateFormat(dateForm);
+            Date a= sf1.parse(dateString);
+           String reDate= format.format(a);
+            return reDate;
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+
+    /*
+     * 获取时间
+     */
+    public static String toGMTString(Date date) {
+        SimpleDateFormat df = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z", Locale.UK);
+        df.setTimeZone(new SimpleTimeZone(0, "GMT"));
+        return df.format(date);
+    }
+}

+ 180 - 0
src/main/java/com/cslg/ppa/common/utils/ExcelUtils.java

@@ -0,0 +1,180 @@
+package com.cslg.ppa.common.utils;
+
+import org.apache.poi.hssf.usermodel.*;
+import org.apache.poi.ooxml.POIXMLDocumentPart;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.*;
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
+
+import java.awt.*;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ExcelUtils {
+
+    public static Map<String, PictureData> getDataFromExcel(String filePath) throws IOException {
+        //判断是否为excel类型文件
+        if (!filePath.endsWith(".xls") && !filePath.endsWith(".xlsx") && !filePath.endsWith(".XLS") && !filePath.endsWith(".XLSX")) {
+            System.out.println("文件不是excel类型");
+        }
+
+        FileInputStream fis = null;
+        Workbook wookbook = null;
+        Sheet sheet = null;
+        try {
+            //获取一个绝对地址的流
+            fis = new FileInputStream(filePath);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        try {
+            //2003版本的excel,用.xls结尾
+            wookbook = new HSSFWorkbook(fis);//得到工作簿
+        } catch (Exception ex) {
+            //ex.printStackTrace();
+            try {
+                //2007版本的excel,用.xlsx结尾
+                fis = new FileInputStream(filePath);
+                wookbook = new XSSFWorkbook(fis);//得到工作簿
+            } catch (IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+        Map<String, PictureData> maplist = null;
+        //拿到excel表格的第一个sheet工作簿
+        sheet = wookbook.getSheetAt(0);
+        // 判断用07还是03的方法获取图片
+        if (filePath.endsWith(".xls") || filePath.endsWith(".XLS")) {
+            maplist = getPictures1((HSSFSheet) sheet);
+        } else if (filePath.endsWith(".xlsx") || filePath.endsWith(".XLSX")) {
+            maplist = getPictures2((XSSFSheet) sheet);
+        }
+        wookbook.close();
+        return maplist;
+    }
+
+    /**
+     * 获取图片和位置 (xls)
+     *
+     * @param sheet
+     * @return
+     * @throws IOException
+     */
+    public static Map<String, PictureData> getPictures1(HSSFSheet sheet) throws IOException {
+        Map<String, PictureData> map = new HashMap();
+        if (sheet.getDrawingPatriarch() != null) {
+            List<HSSFShape> list = sheet.getDrawingPatriarch().getChildren();
+            for (HSSFShape shape : list) {
+                if (shape instanceof HSSFPicture) {
+                    HSSFPicture picture = (HSSFPicture) shape;
+                    HSSFClientAnchor cAnchor = (HSSFClientAnchor) picture.getAnchor();
+                    PictureData pdata = picture.getPictureData();
+                    String key = String.valueOf(cAnchor.getRow1());
+                    map.put(key, pdata);
+                }
+            }
+        }
+        return map;
+    }
+
+    /**
+     * 获取图片和位置 (xlsx)
+     *
+     * @param sheet
+     * @return
+     * @throws IOException
+     */
+    public static Map<String, PictureData> getPictures2(XSSFSheet sheet) throws IOException {
+        Map<String, PictureData> map = new HashMap();
+        List<POIXMLDocumentPart> list = sheet.getRelations();
+        for (POIXMLDocumentPart part : list) {
+            if (part instanceof XSSFDrawing) {
+                XSSFDrawing drawing = (XSSFDrawing) part;
+                List<XSSFShape> shapes = drawing.getShapes();
+                for (XSSFShape shape : shapes) {
+                    XSSFPicture picture = (XSSFPicture) shape;
+                    Dimension d = picture.getImageDimension();
+                    //解决图片空指针报错问题 lig  2021-06-03
+                    XSSFClientAnchor anchor = (XSSFClientAnchor) shape.getAnchor();
+                    //XSSFClientAnchor anchor = picture.getPreferredSize();
+                    CTMarker marker = anchor.getFrom();
+                    String key = String.valueOf(marker.getRow());
+                    map.put(key, picture.getPictureData());
+                }
+            }
+        }
+        return map;
+    }
+
+//    /**
+//     * @param pictureData 图片
+//     * @return 返回图片的文件路径和文件名称
+//     */
+//    public static Map<String, String> savePicture(PictureData pictureData) throws IOException {
+//        FileUtils fileUtils = SpringUtils.getBean(FileUtils.class);
+//        Map<String, String> result = new HashMap<>();
+//        String ext = pictureData.suggestFileExtension();
+//        byte[] data = pictureData.getData();
+//        String picName = IdUtil.simpleUUID() + "." + ext;
+//        String date = DateUtils.getNowTimeFormat("yyyyMMdd");
+//        String folderPath = fileUtils.getSavePath(date);
+//        String filePath = FileUtils.FILE_SEPARATOR + date + FileUtils.FILE_SEPARATOR + picName;
+//        File directory = new File(folderPath);
+//        if (!directory.exists()) {
+//            directory.mkdir();
+//        }
+//        FileOutputStream out = new FileOutputStream(folderPath + picName);
+//        out.write(data);
+//        out.close();
+//        result.put("path", filePath);
+//        result.put("name", picName);
+//        return result;
+//    }
+
+    /**
+     * @param
+     * @param x           单元格x轴坐标
+     * @param y           单元格y轴坐标
+     * @param pictureData 图片二进制数据
+     * @param picType     图片格式
+     */
+    public static void writePicture(Sheet sheet, int x, int y, byte[] pictureData, int picType) {
+        Drawing drawingPatriarch = sheet.createDrawingPatriarch();
+        //设置图片单元格位置
+        ClientAnchor anchor = drawingPatriarch.createAnchor(0, 0, 0, 0, x, y, x + 1, y + 1);
+        //随单元格改变位置和大小
+        anchor.setAnchorType(ClientAnchor.AnchorType.MOVE_AND_RESIZE);
+        //添加图片
+        int pictureIndex = sheet.getWorkbook().addPicture(pictureData, picType);
+        drawingPatriarch.createPicture(anchor, pictureIndex);
+    }
+
+    public static void setExcelCellStyle(HSSFCellStyle cellStyle) {
+        cellStyle.setBorderBottom(BorderStyle.THIN);
+        cellStyle.setBorderLeft(BorderStyle.THIN);
+        cellStyle.setBorderRight(BorderStyle.THIN);
+        cellStyle.setBorderTop(BorderStyle.THIN);
+    }
+
+    public static String getValue(Cell cell) {
+        if (cell != null) {
+            if (cell.getCellType() == CellType.NUMERIC && HSSFDateUtil.isCellDateFormatted(cell)) {
+                Date date = cell.getDateCellValue();
+                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+                String dateString = dateFormat.format(date);
+                return dateString;
+            } else {
+                return cell.toString();
+            }
+        }
+        return "";
+    }
+
+
+}

+ 306 - 0
src/main/java/com/cslg/ppa/common/utils/FileUtils.java

@@ -0,0 +1,306 @@
+package com.cslg.ppa.common.utils;
+
+
+import cn.hutool.core.util.IdUtil;
+import com.alibaba.fastjson.JSON;
+import com.cslg.ppa.PpaApplication;
+import org.springframework.boot.system.ApplicationHome;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+
+@Service
+public class FileUtils {
+
+    public static final String FILE_SEPARATOR = System.getProperty("file.separator");
+    public static final String COMMON_FILE = "file";
+    public static final String BACKUP_FILE = "backup";
+
+    public static String getStaticPath(String fileName) {
+        //ApplicationHome类 返回target目录层级
+        ApplicationHome ah = new ApplicationHome(PpaApplication.class);
+        //获取 applicationHome 内的路径 ...\target\classes 到这一层级下
+        File file = ah.getSource();
+        //获取 file的parentFile 即最后一级之前的所有层级路径(包括盘符) 这里能获得到的最终层级为  ...\target 后续用FILE_SEPARATOR(系统路径分割通配符 即 "\") 以及fileName拼接生成存放文件的目录层级 即为根目录 root
+        String rootPath = null;
+
+        if (fileName != null && !fileName.equals("")) {
+            rootPath = file.getParentFile().toString() + FILE_SEPARATOR + fileName;
+        } else {
+            rootPath = file.getParentFile().toString();
+        }
+        //根据上方生成的根目录路径 生成对应文件夹 没有就新建
+        File root = new File(rootPath);
+        if (!root.exists()) {
+            root.mkdir();
+        }
+        //返回的最终形式为 盘符:\项目层级\target\file
+        return rootPath;
+    }
+
+    public String analysisJsonFile() {
+        ApplicationHome ah = new ApplicationHome(BackupUtils.class);
+        File file = ah.getSource();
+//        String settingFilePath = file.getParentFile().toString() + FileUtils.FILE_SEPARATOR + "\\jsons\\" + "uploadSetting.json";
+        String settingFilePath = file.getParentFile().toString() + FileUtils.FILE_SEPARATOR + "uploadSetting.json";
+        BufferedReader reader = null;
+        StringBuilder last = new StringBuilder();
+        InputStreamReader inputStreamReader;
+        try (FileInputStream fileInputStream = new FileInputStream(settingFilePath)) {
+            inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
+
+            reader = new BufferedReader(inputStreamReader);
+            String tempString;
+            while ((tempString = reader.readLine()) != null) {
+                last.append(tempString);
+            }
+            reader.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return last.toString();
+    }
+
+    public static File getFileByBytes(byte[] bytes, String prefix, String suffix) {
+        BufferedOutputStream bos = null;
+        FileOutputStream fos = null;
+        File file = null;
+        try {
+
+            file = File.createTempFile(prefix, suffix);
+
+            //输出流
+            fos = new FileOutputStream(file);
+
+            //缓冲流
+            bos = new BufferedOutputStream(fos);
+
+            //将字节数组写出
+            bos.write(bytes);
+            return file;
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (bos != null) {
+                try {
+                    bos.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (fos != null) {
+                try {
+                    fos.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            return file;
+        }
+    }
+
+
+    public static File getFileByUrl(String dataUrl) throws IOException {
+
+        URL url = new URL(dataUrl);  //想要读取的url地址
+        InputStream in = url.openStream();
+        File file = File.createTempFile("new_url", ".pdf");  //创建文件
+        OutputStream os = new FileOutputStream(file);  //创建文件输出流
+        int bytesRead;
+        byte[] buffer = new byte[8192];
+        int len = 8192;
+        while ((bytesRead = in.read(buffer, 0, len)) != -1) {
+            os.write(buffer, 0, bytesRead);
+        }
+        //关闭释放流
+        os.close();
+        in.close();
+        return file;
+    }
+
+    public static File getPictureFileByUrl(String dataUrl) throws IOException {
+
+        URL url = new URL(dataUrl);  //想要读取的url地址
+        InputStream in = url.openStream();
+        File file = File.createTempFile("new_url", ".jpg");  //创建文件
+        OutputStream os = new FileOutputStream(file);  //创建文件输出流
+        int bytesRead;
+        byte[] buffer = new byte[8192];
+        int len = 8192;
+        while ((bytesRead = in.read(buffer, 0, len)) != -1) {
+            os.write(buffer, 0, bytesRead);
+        }
+        //关闭释放流
+        os.close();
+        in.close();
+        return file;
+    }
+
+    public String getPath(String url) {
+        return getStaticPath(COMMON_FILE) + url;
+    }
+
+    public String getDirectoryName() {
+        return DateUtils.getNowTimeFormat("yyyyMMdd");
+    }
+
+    public String getSavePath(String directoryName) {
+        return getStaticPath(COMMON_FILE) + FILE_SEPARATOR + directoryName + FILE_SEPARATOR;
+    }
+
+    public String createDirectory() {
+        String directoryName = this.getDirectoryName();
+        String savePath = this.getSavePath(directoryName);
+        File directory = new File(savePath);
+        if (!directory.exists()) {
+            directory.mkdir();
+        }
+        return directoryName;
+    }
+
+    public String createRandomDirectory() {
+        String directoryName = IdUtil.simpleUUID();
+        String savePath = this.getSavePath(directoryName);
+        File directory = new File(savePath);
+        if (!directory.exists()) {
+            directory.mkdir();
+        }
+        return directoryName;
+    }
+
+    public static FileInputStream byteToFile(byte[] bytes) {
+        String fileName = IdUtil.simpleUUID() + ".png";
+        File file = new File(fileName);
+        FileInputStream fileInputStream = null;
+        try {
+            OutputStream output = new FileOutputStream(file);
+            BufferedOutputStream bufferedOutput = new BufferedOutputStream(output);
+            bufferedOutput.write(bytes);
+            fileInputStream = new FileInputStream(file);
+            file.deleteOnExit();
+            return fileInputStream;
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return fileInputStream;
+    }
+
+    public String getTempPath(String fileName) {
+        String tempPath = getStaticPath(COMMON_FILE) + FILE_SEPARATOR + "temp";
+        File file = new File(tempPath);
+        if (!file.exists()) {
+            file.mkdir();
+        }
+        return tempPath + FILE_SEPARATOR + fileName;
+    }
+
+    public String getDirectory(String fileName) {
+        return FILE_SEPARATOR + this.createDirectory() + FILE_SEPARATOR + fileName;
+    }
+
+    public String getSystemPath(String url) {
+        return getStaticPath(COMMON_FILE) + FILE_SEPARATOR + url;
+    }
+
+    public static String getSystemPath2(String url) {
+        return getStaticPath(COMMON_FILE) + FILE_SEPARATOR + url;
+    }
+
+    public static void writeFile(String json, String FilePath) {
+
+        try {
+            File file = new File(FilePath);
+
+            // if file doesnt exists, then create it
+            if (!file.exists()) {
+                file.createNewFile();
+            } else {
+                file.delete();
+                file.createNewFile();
+            }
+
+            // true = append file
+            FileWriter fileWritter = new FileWriter(file, false);
+            BufferedWriter bufferWritter = new BufferedWriter(fileWritter);
+            bufferWritter.write(json);
+            bufferWritter.close();
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static File getFileByName(File file, String name) {
+        for (File file1 : file.listFiles()) {
+            if (file1.getName().equals(name)) {
+                return file1;
+            }
+        }
+        return null;
+    }
+
+
+    public static void writeFile(Object object, File file) {
+        String json = JSON.toJSONString(object);
+        try {
+            // if file doesnt exists, then create it
+            if (!file.exists()) {
+                file.createNewFile();
+            } else {
+                file.delete();
+                file.createNewFile();
+            }
+            // true = append file
+            FileWriter fileWritter = new FileWriter(file, false);
+            BufferedWriter bufferWritter = new BufferedWriter(fileWritter);
+            bufferWritter.write(json);
+            bufferWritter.close();
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static File multipartFileToFile(MultipartFile file) throws Exception {
+        File toFile = null;
+        if (file == null || file.equals("") || file.getSize() <= 0) {
+            file = null;
+        } else {
+            InputStream ins = null;
+            ins = file.getInputStream();
+            toFile = new File(file.getOriginalFilename());
+            inputStreamToFile(ins, toFile);
+            ins.close();
+        }
+        return toFile;
+    }
+
+    //获取流文件
+    private static void inputStreamToFile(InputStream ins, File file) {
+        try {
+            OutputStream os = new FileOutputStream(file);
+            int bytesRead = 0;
+            byte[] buffer = new byte[8192];
+            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
+                os.write(buffer, 0, bytesRead);
+            }
+            os.close();
+            ins.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

File diff suppressed because it is too large
+ 166 - 0
src/main/java/com/cslg/ppa/common/utils/HttpUtils.java


+ 381 - 0
src/main/java/com/cslg/ppa/common/utils/JsonUtils.java

@@ -0,0 +1,381 @@
+package com.cslg.ppa.common.utils;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonSyntaxException;
+import com.google.gson.reflect.TypeToken;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * json解析的工具类
+ */
+public class JsonUtils {
+
+    // 定义jackson对象
+    public static Logger log = LoggerFactory.getLogger(JsonUtils.class);
+    private static ObjectMapper MAPPER;
+
+    static {
+        MAPPER = new ObjectMapper();
+        MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
+    }
+
+    /**
+     * 把对象转换为json数据
+     *
+     * @param obj
+     * @return 2018年5月7日  下午5:27:16
+     */
+    public static String objectToJson(Object obj) {
+        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
+        try {
+            String json = gson.toJson(obj);
+            return json;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 将Object转换成Map
+     *
+     * @param obj
+     * @return
+     */
+    public static Map<String, Object> objectToMap(Object obj) {
+
+        try {
+            Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
+            String json = gson.toJson(obj);
+            return jsonToMap(json);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 将Object类型的map转换成String类型
+     *
+     * @param map
+     * @return
+     */
+    public static Map<String, String> mapToMap(Map<String, Object> map) {
+        Map<String, String> returnMap = new HashMap<>();
+        for (String key : map.keySet()) {
+            returnMap.put(key, String.valueOf(map.get(key)));
+        }
+        return returnMap;
+    }
+
+    /**
+     * 任意类型转换成Map
+     * @return
+     */
+    public static Map<String, String> object2Map(Object obj) {
+        Map<String, String> hashMap = new HashMap();
+        try {
+            Class c = obj.getClass();
+            Method m[] = c.getDeclaredMethods();
+            for (int i = 0; i < m.length; i++) {
+                if (m[i].getName().indexOf("get")==0) {
+                    // 得到Map的key
+                    String suffixKey = m[i].getName().substring(4);
+                    String prefixKey = m[i].getName().substring(3,4).toLowerCase();
+                    hashMap.put(prefixKey + suffixKey, String.valueOf(m[i].invoke(obj, new Object[0])));
+                }
+            }
+        } catch (Throwable e) {
+            log.error(e.getMessage());
+        }
+        return hashMap;
+    }
+
+
+    /**
+     * 把json字符串转化为对象
+     *
+     * @param jsonString
+     * @param clazz
+     * @return
+     */
+    public static Object jsonToObject(String jsonString, Class<?> clazz) {
+
+        Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
+        Object obj = null;
+        try {
+            obj = gson.fromJson(jsonString, clazz);
+        } catch (JsonSyntaxException e) {
+            e.printStackTrace();
+        }
+        return obj;
+    }
+
+    /**
+     * josn转arrayList
+     *
+     * @param jsonArray
+     * @return
+     */
+    public static ArrayList<?> jsonArrayToArrayList(String jsonArray) {
+
+        Gson gson = new GsonBuilder()
+                .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
+                .setDateFormat("yyyy-MM-dd HH:mm:ss")
+                .serializeNulls()
+                .create();
+        ArrayList<?> list = null;
+        try {
+            Type listType = new TypeToken<ArrayList<?>>() {
+            }.getType();
+
+            list = gson.fromJson(jsonArray, listType);
+        } catch (JsonSyntaxException e) {
+            e.printStackTrace();
+        }
+        return list;
+    }
+
+    /**
+     * JSON 转 ArrayList
+     */
+    public static ArrayList<?> jsonArrayToArrayList(String jsonArray, Class<?> clazz) {
+
+        Gson gson = new GsonBuilder()
+                .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
+                .setDateFormat("yyyy-MM-dd HH:mm:ss")
+                .serializeNulls()
+                .create();
+        ArrayList<?> list = null;
+        try {
+
+            list = (ArrayList<?>) gson.fromJson(jsonArray, clazz);
+        } catch (JsonSyntaxException e) {
+            e.printStackTrace();
+        }
+        return list;
+    }
+
+    /**
+     * 把json转换为map类型的数据
+     *
+     * @param json
+     * @return
+     */
+    public static Map<String, Object> jsonToMap(String json) {
+
+        Gson gson = new GsonBuilder()
+                .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
+                .setDateFormat("yyyy-MM-dd HH:mm:ss")
+                .serializeNulls()
+                .create();
+        Map<String, Object> map = null;
+        try {
+            Type type = new TypeToken<Map<String, Object>>() {
+            }.getType();
+
+            map = gson.fromJson(json, type);
+        } catch (JsonSyntaxException e) {
+            e.printStackTrace();
+        }
+        return map;
+    }
+
+    /**
+     * 将Json转换成Map<String, ?>
+     *
+     * @param json
+     * @param clazz
+     * @return
+     */
+    public static Map<String, ?> jsonToMap(String json, Class<?> clazz) {
+
+        Gson gson = new GsonBuilder()
+                .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
+                .setDateFormat("yyyy-MM-dd HH:mm:ss")
+                .serializeNulls()
+                .create();
+        Map<String, ?> map = null;
+        try {
+            Type type = new TypeToken<Map<String, ?>>() {
+            }.getType();
+
+            map = gson.fromJson(json, type);
+        } catch (JsonSyntaxException e) {
+            e.printStackTrace();
+        }
+        return map;
+    }
+
+    /**
+     * 将map转换成pojo
+     *
+     * @param map
+     * @param beanType
+     * @param <T>
+     * @return
+     */
+    public static <T> T mapToPojo(Map<String, Object> map, Class<T> beanType) {
+
+        Gson gson = new GsonBuilder()
+                .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
+                .setDateFormat("yyyy-MM-dd HH:mm:ss")
+                .serializeNulls()
+                .create();
+
+        JsonElement jsonElement = gson.toJsonTree(map);
+        T pojo = gson.fromJson(jsonElement, beanType);
+
+        return pojo;
+    }
+
+    /**
+     * 将json结果集转化为对象
+     *
+     * @param jsonData
+     * @param beanType
+     * @param <T>
+     * @return
+     */
+    public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
+        try {
+            T t = MAPPER.readValue(jsonData, beanType);
+            return t;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 将json数据转换成pojo对象list
+     *
+     * @param jsonData
+     * @param beanType
+     * @return
+     */
+    public static <T> List<T> jsonToList(String jsonData, Class<T> beanType) {
+        JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
+        try {
+            List<T> list = MAPPER.readValue(jsonData, javaType);
+            return list;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    /**
+     * 将任意pojo转化成map
+     *
+     * @param t pojo对象
+     * @return
+     */
+    public static <T> Map<String, Object> pojoToMap(T t) {
+        Map<String, Object> result = new HashMap<String, Object>();
+        Method[] methods = t.getClass().getMethods();
+        try {
+            for (Method method : methods) {
+                Class<?>[] paramClass = method.getParameterTypes();
+                // 如果方法带参数,则跳过
+                if (paramClass.length > 0) {
+                    continue;
+                }
+                String methodName = method.getName();
+                if (methodName.startsWith("get")) {
+                    Object value = method.invoke(t);
+                    result.put(methodName, value);
+                }
+            }
+        } catch (IllegalArgumentException e) {
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+        } catch (SecurityException e) {
+            e.printStackTrace();
+        }
+        return result;
+    }
+
+
+    /**
+     * 将二叉树json对象转为sql where后的条件语句
+     *liRJ
+     * @param jsonObject jsaonObject
+     * @return
+     */
+    public static String reSql(JSONObject jsonObject){
+        String str1 = "";
+        String str2 = "";
+        JSONObject jsonLeft =jsonObject.getJSONObject("left");
+        JSONObject jsonRight =jsonObject.getJSONObject("right");
+        if(jsonLeft.containsKey("left")){
+            str1 = reSql(jsonLeft);
+        }
+        else{
+            str1 = jsonLeft.get("field").toString()+jsonLeft.get("opr").toString()+jsonLeft.get("value").toString();
+        }
+        if(jsonRight.containsKey("right")){
+            str2= reSql( jsonRight);
+        }
+        else{
+            str2 =jsonRight.get("field").toString()+jsonRight.get("opr").toString()+jsonRight.get("value").toString();
+        }
+        String sql ="("+ str1+") "+ jsonObject.get("logicOpr")+" ("+str2+")";
+
+        return sql;
+    }
+
+    /**
+     * json转对象
+     * @param jsonStr
+     * @param clazz
+     * @param <T>
+     * @return
+     */
+    public static <T> T jsonToObj(String jsonStr, Class<T> clazz) {
+        try {
+            return MAPPER.readValue(jsonStr, clazz);
+        } catch (IOException e) {
+            throw new RuntimeException("json转换出错", e);
+        }
+    }
+
+    /**
+     * json转对象
+     * @param jsonStr
+     * @param typeReference
+     * @param <T>
+     * @return
+     */
+    public static <T> T jsonToObj(String jsonStr, TypeReference<T> typeReference) {
+        try {
+            return MAPPER.readValue(jsonStr, typeReference);
+        } catch (IOException e) {
+            throw new RuntimeException("json转换出错", e);
+        }
+    }
+
+}

+ 58 - 0
src/main/java/com/cslg/ppa/common/utils/RandomUtil.java

@@ -0,0 +1,58 @@
+package com.cslg.ppa.common.utils;
+
+import java.security.SecureRandom;
+import java.util.Random;
+
+public class RandomUtil {
+
+    // 定义可用来生成邀请码的字符集
+    private static final String CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+    // 定义邀请码的长度
+    private static final int CODE_LENGTH = 8;
+
+    private static String[] STR_ARR = new String[] { "a", "b", "c", "d", "e",
+            "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r",
+            "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E",
+            "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
+            "S", "T", "U", "V", "W", "X", "Y", "Z", "1", "2", "3", "4", "5",
+            "6", "7", "8", "9", "0"};
+
+    /**
+     * 随机验证码
+     * @return
+     */
+    public static String getSixRandom(){
+        return String.valueOf((int) ((Math.random() * 9 + 1) * Math.pow(10, 5)));
+    }
+
+    /**
+     * 随机生成code码的方法
+     * @param length
+     * @return
+     */
+    public static String generateRandomString(int length) {
+        StringBuilder sb = new StringBuilder();
+        Random rand = new Random();
+        for (int i = 0; i < length; i++) {
+            sb.append(STR_ARR[rand.nextInt(STR_ARR.length)]);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * 生成随机邀请码的方法
+     *
+     * @return 生成的邀请码
+     */
+    public static String generateInvitationCode() {
+        SecureRandom random = new SecureRandom();
+        StringBuilder codeBuilder = new StringBuilder(CODE_LENGTH);
+
+        for (int i = 0; i < CODE_LENGTH; i++) {
+            int index = random.nextInt(CHARACTERS.length());
+            codeBuilder.append(CHARACTERS.charAt(index));
+        }
+
+        return codeBuilder.toString();
+    }
+}

+ 323 - 0
src/main/java/com/cslg/ppa/common/utils/ReadExcelUtils.java

@@ -0,0 +1,323 @@
+package com.cslg.ppa.common.utils;
+
+import com.cslg.ppa.common.exception.ThrowException;
+import com.cslg.ppa.entity.commom.PatentData;
+import org.apache.poi.hssf.usermodel.*;
+import org.apache.poi.ooxml.POIXMLDocumentPart;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.xssf.usermodel.*;
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * @Author xiexiang
+ * @Date 2023/5/30
+ */
+@Service
+public class ReadExcelUtils {
+    /**
+     * 检测Excel文件合法性
+     *
+     * @param tempFile 临时文件
+     * @return 返回文件总行数
+     */
+    public static Integer textExcel(File tempFile, String sourceId) throws IOException {
+        //判断文件是否存在
+        if (!tempFile.exists() || tempFile.getPath().trim().equals("")) {
+            ThrowException.throwXiaoShiException("文件上传失败,服务器忙请稍后再试!");
+        }
+
+        // 检测是否为excel文件
+        String suffix = tempFile.getPath().substring(tempFile.getPath().lastIndexOf("."));
+        if (!suffix.equals(".xls") && !suffix.equals(".xlsx") && !suffix.equals(".XLS") && !suffix.equals(".XLSX")) {
+            //删除临时文件tempFile
+            new File(tempFile.getPath()).delete();
+            ThrowException.throwXiaoShiException("文件格式错误,请上传Excel文件!");
+        }
+
+        InputStream fis = new FileInputStream(tempFile);
+        //使用poi框架解析处理Excel文件
+        Workbook workbook = null;
+        //区分不同版本Excel,使用各自对应的工具类
+        if (suffix.equals(".xls") || suffix.equals(".XLS")) {
+            workbook = new HSSFWorkbook(fis);
+        } else if (suffix.equals(".xlsx") || suffix.equals(".XLSX")) {
+            workbook = new XSSFWorkbook(fis);
+        }
+        //读取第几个sheet
+        Sheet sheet = workbook.getSheetAt(0);
+        //读取总行数
+        int rows = sheet.getPhysicalNumberOfRows();
+        if (rows <= 1) {
+            //删除临时文件tempFile
+            fis.close();
+            new File(tempFile.getPath()).delete();
+            ThrowException.throwXiaoShiException("文件内容格式不正确,请检查总行数是否有专利内容");
+        }
+
+        //获取第一行抬头
+        Row firstRow = sheet.getRow(0);
+        boolean flag1 = false;  //是否有 "公开(公告)号"
+        boolean flag2 = false;  //是否有 "申请号"
+        //遍历第一行单元格抬头,检查合法性
+        String title = "", source = "";
+        if (sourceId.equals("1")) {
+            source = "智慧芽";
+            title = "公开(公告)号";
+        } else if (sourceId.equals("2")) {
+            source = "合享";
+            title = "公开(公告)号";
+        } else {
+            source = "Patentics";
+            title = "公开号";
+        }
+        for (Cell cell : firstRow) {
+            if (cell.getStringCellValue().equals(title)) {
+                flag1 = true;
+            }
+            if (cell.getStringCellValue().equals("申请号")) {
+                flag2 = true;
+            }
+        }
+        if (!flag1 || !flag2) {
+            //删除临时文件tempFile
+            fis.close();
+            new File(tempFile.getPath()).delete();
+            ThrowException.throwXiaoShiException("文件内容格式不正确,您选择【" + source + "】来源,Excel第一行抬头必须有【" + title + "】和【申请号】");
+        }
+        //关闭流
+        fis.close();
+        //返回文件总行数-1(即专利总数量)
+        return rows - 1;
+    }
+
+    /**
+     * 获取一行专利的全部数据(专利内容数据 + 摘要附图)
+     *
+     * @param tempFile Excel临时文件
+     * @param row      行数
+     * @return 返回装载专利数据(专利内容数据 + 摘要附图)的对象
+     */
+    public static PatentData readExcelOneRow(File tempFile, Sheet sheet, int row) throws IOException {
+        //创建返回最终结果的对象 patentData
+        PatentData patentData = new PatentData();
+        //装载专利数据(除了摘要附图)的map:(key:表头如 "公开(公告)号"  value:表头对应内容如 "CN1307082B")
+        Map<Object, Object> map = new HashMap<>();
+        //装载摘要附图的对象
+        PictureData pictureData = null;
+
+        //开始装载专利数据
+        Row firstRow = sheet.getRow(0);
+        Row needRow = sheet.getRow(row);
+        //获得总列数
+        int columns = firstRow.getLastCellNum();
+        for (int i = 0; i < columns; i++) {
+            map.put(firstRow.getCell(i) + "", ExcelUtils.getValue(needRow.getCell(i)) + "");
+        }
+
+        //开始装载专利摘要附图(判断用07还是03的方法获取图片)
+        String suffix = tempFile.getName().substring(tempFile.getName().lastIndexOf("."));
+        if (suffix.equals(".xls") || suffix.equals(".XLS")) {
+            pictureData = getPictures1((HSSFSheet) sheet, row);
+        } else if (suffix.equals(".xlsx") || suffix.equals(".XLSX")) {
+            pictureData = getPictures2((XSSFSheet) sheet, row);
+        }
+
+        //返回结果对象装载结果
+        patentData.setMap(map);
+        patentData.setPictureData(pictureData);
+
+        return patentData;
+    }
+
+    /**
+     * 获取一行专利的全部数据(专利内容数据 + 摘要附图)
+     *
+     * @param tempFile Excel临时文件
+     * @param row      行数
+     * @return 返回装载专利数据(专利内容数据 + 摘要附图)的对象
+     */
+    public static PatentData readExcelTwoRow(File tempFile, Sheet sheet, int row) throws IOException {
+        //创建返回最终结果的对象 patentData
+        PatentData patentData = new PatentData();
+        //装载专利数据(除了摘要附图)的map:(key:表头如 "公开(公告)号"  value:表头对应内容如 "CN1307082B")
+        Map<Object, Object> map = new HashMap<>();
+        //装载摘要附图的对象
+        PictureData pictureData = null;
+
+        //开始装载专利数据
+        Row firstRow = sheet.getRow(1);
+        Row needRow = sheet.getRow(row);
+        //获得总列数
+        int columns = firstRow.getLastCellNum();
+        for (int i = 0; i < columns; i++) {
+            map.put(firstRow.getCell(i) + "", ExcelUtils.getValue(needRow.getCell(i)) + "");
+        }
+
+        //开始装载专利摘要附图(判断用07还是03的方法获取图片)
+        String suffix = tempFile.getName().substring(tempFile.getName().lastIndexOf("."));
+        if (suffix.equals(".xls") || suffix.equals(".XLS")) {
+            pictureData = getPictures1((HSSFSheet) sheet, row);
+        } else if (suffix.equals(".xlsx") || suffix.equals(".XLSX")) {
+            pictureData = getPictures2((XSSFSheet) sheet, row);
+        }
+
+        //返回结果对象装载结果
+        patentData.setMap(map);
+        patentData.setPictureData(pictureData);
+
+        return patentData;
+    }
+
+    public static Sheet readExcel(File tempFile) {
+        Sheet sheet = null;
+
+        try {
+            InputStream inputStream = new FileInputStream(tempFile);
+            //POI可以处理Excel文件
+            Workbook workbook = null;
+            //当文件以.xls结尾时
+            String suffix = tempFile.getName().substring(tempFile.getName().lastIndexOf("."));
+            if (suffix.equals(".xls") || suffix.equals(".XLS")) {
+                workbook = new HSSFWorkbook(inputStream);
+            } else if (suffix.equals(".xlsx") || suffix.equals(".XLSX")) {
+                workbook = new XSSFWorkbook(inputStream);
+            }
+
+            //读取第几个sheet
+            sheet = workbook.getSheetAt(0);
+
+            //关闭流
+            inputStream.close();
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        return sheet;
+    }
+
+    /**
+     * 03版本Excel取附图
+     *
+     * @param sheet Excel工作簿
+     * @return 返回附图map
+     */
+    public static PictureData getPictures1(HSSFSheet sheet, Integer row) throws IOException {
+        if (sheet.getDrawingPatriarch() != null) {
+            List<HSSFShape> list = sheet.getDrawingPatriarch().getChildren();
+            for (HSSFShape shape : list) {
+                if (shape instanceof HSSFPicture) {
+                    HSSFPicture picture = (HSSFPicture) shape;
+                    HSSFClientAnchor cAnchor = (HSSFClientAnchor) picture.getAnchor();
+                    int row1 = cAnchor.getRow1();
+                    if (row1 == row) {
+                        return picture.getPictureData();
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 07版本Excel取附图
+     *
+     * @param sheet Excel工作簿
+     * @return 返回附图map
+     */
+    public static PictureData getPictures2(XSSFSheet sheet, Integer row) throws IOException {
+        List<POIXMLDocumentPart> list = sheet.getRelations();
+        for (POIXMLDocumentPart part : list) {
+            if (part instanceof XSSFDrawing) {
+                XSSFDrawing drawing = (XSSFDrawing) part;
+                List<XSSFShape> shapes = drawing.getShapes();
+                for (XSSFShape shape : shapes) {
+                    //解决图片空指针报错问题 lig  2021-06-03
+                    XSSFClientAnchor anchor = (XSSFClientAnchor) shape.getAnchor();
+                    //XSSFClientAnchor anchor = picture.getPreferredSize();
+                    CTMarker marker = anchor.getFrom();
+                    int excelRow = marker.getRow();
+                    if (excelRow == row) {
+                        XSSFPicture picture = (XSSFPicture) shape;
+                        return picture.getPictureData();
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public static String getValue(Cell cell) {
+        if (cell != null) {
+            if (cell.getCellType() == CellType.NUMERIC && HSSFDateUtil.isCellDateFormatted(cell)) {
+                Date date = cell.getDateCellValue();
+                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+                String dateString = dateFormat.format(date);
+                return dateString;
+            } else {
+                return cell.toString();
+            }
+        }
+        return "";
+    }
+
+
+    /**
+     * @param sheet
+     * @return
+     * @throws IOException
+     */
+    public static List<String> getPatentNoFromExcel(Sheet sheet) throws IOException {
+        List<String> patentNos = new ArrayList<>();
+        int rows = sheet.getPhysicalNumberOfRows();
+        Integer cellId = null;
+        //开始装载专利数据
+        Row firstRow = sheet.getRow(0);
+
+        //查找列
+        int columns = firstRow.getLastCellNum();
+        for (int t = 0; t < columns; t++) {
+            if (firstRow.getCell(t).toString().equals("专利号")) {
+                cellId = t;
+            }
+        }
+        for (int i = 1; i < rows; i++) {
+            Row row = sheet.getRow(i);
+            String patentNo = row.getCell(cellId).toString();
+            patentNos.add(patentNo);
+        }
+        return patentNos;
+    }
+
+
+    public static Integer testNoImport(Sheet sheet) throws IOException {
+        int rows = sheet.getPhysicalNumberOfRows();
+        Integer cellId = null;
+        //开始装载专利数据
+        Row firstRow = sheet.getRow(0);
+
+        //查找列
+        int columns = firstRow.getLastCellNum();
+        for (int t = 0; t < columns; t++) {
+            if (firstRow.getCell(t).toString().equals("专利号")) {
+                cellId = t;
+            }
+        }
+
+        if(cellId!=null&&rows==1){
+            cellId=-1;
+        }
+        return cellId;
+    }
+
+
+}

+ 80 - 0
src/main/java/com/cslg/ppa/common/utils/RegexUtil.java

@@ -0,0 +1,80 @@
+package com.cslg.ppa.common.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+/**
+  * 正则工具类
+ */
+public class RegexUtil {
+
+    /**
+     * 大陆号码或香港号码均可
+     */
+    public static boolean isPhoneLegal(String str) throws PatternSyntaxException {
+        return isChinaPhoneLegal(str) || isHKPhoneLegal(str);
+    }
+
+    /**
+     * 手机号验证,1开头,后面10位随机0-9数字
+     */
+    public static boolean isChinaPhoneLegal(String str) throws PatternSyntaxException {
+        if (str == null) {
+            return false;
+        }
+        String regExp = "^[1][0-9]{10}$";
+        Pattern p = Pattern.compile(regExp);
+        Matcher m = p.matcher(str);
+        return m.matches();
+    }
+
+    /**
+     * 香港手机号码8位数,5|6|8|9开头+7位任意数
+     */
+    public static boolean isHKPhoneLegal(String str) throws PatternSyntaxException {
+        if (str == null) {
+            return false;
+        }
+        String regExp = "^(5|6|8|9)\\d{7}$";
+        Pattern p = Pattern.compile(regExp);
+        Matcher m = p.matcher(str);
+        return m.matches();
+    }
+
+    public static boolean isRegExpReplace(String str) throws PatternSyntaxException {
+        if (str == null) {
+            return false;
+        }
+        String regExp = "[,。、;,./;]";
+        Pattern p = Pattern.compile(regExp);
+        Matcher m = p.matcher(str);
+        return m.matches();
+    }
+
+    //split By分隔符忽略引号
+    public static List<String> splitByDelimiters(String input) {
+        List<String> result = new ArrayList<>();
+        // 正则表达式匹配分隔符,但忽略引号内的内容
+        // 注意:这里使用了Unicode转义序列来表示中文引号
+        Pattern pattern = Pattern.compile("\"([^\"]*)\"|’([^’]*)’|‘([^’]*)’|“([^\"]*)”|([^,。、;,./;\\s+]+)");
+        Matcher matcher = pattern.matcher(input);
+
+        while (matcher.find()) {
+            if (matcher.group(1) != null) { // 英文双引号
+                result.add(matcher.group(1));
+            } else if (matcher.group(2) != null) { // 中文单引号
+                result.add(matcher.group(2));
+            } else if (matcher.group(3) != null) { // 中文单引号(另一种可能的形式)
+                result.add(matcher.group(3));
+            } else if (matcher.group(4) != null) { // 中文双引号
+                result.add(matcher.group(4));
+            } else { // 其他内容(即分隔符外的部分)
+                result.add(matcher.group(5));
+            }
+        }
+        return result;
+    }
+}

+ 20 - 0
src/main/java/com/cslg/ppa/config/MybatisPlusConfig.java

@@ -0,0 +1,20 @@
+package com.cslg.ppa.config;
+
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@MapperScan("com.cslg.ppa.mapper")
+public class MybatisPlusConfig {
+    @Bean
+    public MybatisPlusInterceptor mybatisPlusInterceptor() {
+        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
+        return interceptor;
+    }
+}

+ 11 - 0
src/main/java/com/cslg/ppa/config/WebSocketConfig.java

@@ -0,0 +1,11 @@
+package com.cslg.ppa.config;
+
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class WebSocketConfig {
+//    @Bean
+//    public ServerEndpointExporter serverEndpointExporter() {
+//        return new ServerEndpointExporter();
+//    }
+}

+ 45 - 0
src/main/java/com/cslg/ppa/controller/ArticleInfoController.java

@@ -0,0 +1,45 @@
+package com.cslg.ppa.controller;
+
+import com.cslg.ppa.common.core.auth.Response;
+import com.cslg.ppa.common.core.base.Constants;
+import com.cslg.ppa.dto.ArticleInfoIdDTO;
+import com.cslg.ppa.dto.SelectArticleInfoDTO;
+import com.cslg.ppa.dto.UpdateArticleInfoDTO;
+import com.cslg.ppa.service.ArticleInfoService;
+import io.swagger.v3.oas.annotations.Operation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RequestMapping(Constants.API_PPA + "/articleInfo")
+@RestController
+@RequiredArgsConstructor(onConstructor_ = {@Lazy})
+public class ArticleInfoController {
+
+    @Autowired
+    private ArticleInfoService articleInfoService;
+
+    @Operation(summary = "查询资讯列表")
+    @PostMapping("/selectArticleInfoList")
+    public String selectArticleInfoList(@RequestBody SelectArticleInfoDTO vo) {
+        return articleInfoService.selectArticleInfoList(vo);
+    }
+
+    @Operation(summary = "编辑资讯信息")
+    @PostMapping("/updateArticleInfo")
+    public String updateArticleInfo(@RequestBody UpdateArticleInfoDTO infoDTO) {
+        final Integer id = articleInfoService.updateArticleInfo(infoDTO);
+        return Response.success(id);
+    }
+
+    @Operation(summary = "删除资讯信息")
+    @PostMapping("/deleteArticleInfo")
+    public String deleteArticleInfo(@RequestBody ArticleInfoIdDTO vo) {
+        articleInfoService.deleteArticleInfo(vo);
+        return Response.success("删除成功");
+    }
+}

+ 43 - 0
src/main/java/com/cslg/ppa/controller/CategoryController.java

@@ -0,0 +1,43 @@
+package com.cslg.ppa.controller;
+
+import com.cslg.ppa.common.core.auth.Response;
+import com.cslg.ppa.common.core.base.Constants;
+import com.cslg.ppa.dto.*;
+import com.cslg.ppa.service.CategoryService;
+import io.swagger.v3.oas.annotations.Operation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RequestMapping(Constants.API_PPA + "/category")
+@RestController
+@RequiredArgsConstructor(onConstructor_ = {@Lazy})
+public class CategoryController {
+
+    @Autowired
+    private CategoryService categoryService;
+
+    @Operation(summary = "查询类别列表")
+    @PostMapping("/selectCategoryList")
+    public String selectCategoryList(@RequestBody SelectCategoryListDTO vo) {
+        return categoryService.selectCategoryList(vo);
+    }
+
+    @Operation(summary = "新增或编辑类别信息")
+    @PostMapping("/addOrEditCategory")
+    public String addOrEditCategory(@RequestBody CategoryDTO vo) {
+        final Integer id = categoryService.addOrEditCategory(vo);
+        return Response.success(id);
+    }
+
+    @Operation(summary = "删除类别信息")
+    @PostMapping("/deleteCategory")
+    public String deleteCategory(@RequestBody CategoryIdDTO vo) {
+        categoryService.deleteCategory(vo);
+        return Response.success("删除成功");
+    }
+}

+ 85 - 0
src/main/java/com/cslg/ppa/controller/ReportController.java

@@ -0,0 +1,85 @@
+package com.cslg.ppa.controller;
+
+import com.cslg.ppa.common.core.auth.Response;
+import com.cslg.ppa.common.core.base.Constants;
+import com.cslg.ppa.dto.*;
+import com.cslg.ppa.service.ReportService;
+import com.cslg.ppa.vo.SelectAssoReportArticleVO;
+import io.swagger.v3.oas.annotations.Operation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RequestMapping(Constants.API_PPA + "/report")
+@RestController
+@RequiredArgsConstructor(onConstructor_ = {@Lazy})
+public class ReportController {
+
+    @Autowired
+    private ReportService reportService;
+
+    @Operation(summary = "查询报告列表")
+    @PostMapping("/selectReportList")
+    public String selectReportList(@RequestBody SelectReportListDTO vo) {
+        return reportService.selectReportList(vo);
+    }
+
+    @Operation(summary = "查询报告详情")
+    @PostMapping("/selectReportDetail")
+    public String selectReportDetail(@RequestBody ReportIdDTO vo) {
+        return reportService.selectReportDetail(vo);
+    }
+
+    @Operation(summary = "新增报告信息")
+    @PostMapping("/addReport")
+    public String addReport(@RequestBody ReportDTO vo) {
+        Integer id = reportService.addReport(vo);
+        return Response.success(id);
+    }
+
+    @Operation(summary = "编辑报告信息")
+    @PostMapping("/editReport")
+    public String editReport(@RequestBody ReportDTO vo) {
+        Integer id = reportService.editReport(vo);
+        return Response.success(id);
+    }
+
+    @Operation(summary = "删除报告")
+    @PostMapping("/deleteReport")
+    public String deleteReport(@RequestBody ReportIdDTO vo) {
+        reportService.deleteReport(vo);
+        return Response.success("删除成功");
+    }
+
+    @Operation(summary = "查询报告及关联资讯列表")
+    @PostMapping("/selectAssoReportArticleList")
+    public String selectAssoReportArticleList(@RequestBody SelectAssoReportArticleDTO vo) {
+        List<SelectAssoReportArticleVO> articleVOS = reportService.selectAssoReportArticleList(vo);
+        return Response.success(articleVOS);
+    }
+
+    @Operation(summary = "添加资讯到报告中")
+    @PostMapping("/addArticleToReport")
+    public String addArticleToReport(@RequestBody ReportDTO vo) {
+        Integer id = reportService.addArticleToReport(vo);
+        return Response.success(id);
+    }
+
+    @Operation(summary = "移除报告的关联资讯")
+    @PostMapping("/removeAssoArticleReport")
+    public String removeAssoArticleReport(@RequestBody AssoReportArticleIdDTO vo) {
+        Integer id = reportService.removeAssoArticleReport(vo);
+        return Response.success(id);
+    }
+
+    @Operation(summary = "导出报告信息")
+    @GetMapping("/exportReport")
+    public String exportReport(Integer reportId) {
+        String guid = reportService.exportReport(reportId);
+        return Response.success(guid);
+    }
+
+}

+ 14 - 0
src/main/java/com/cslg/ppa/dto/ArticleInfoIdDTO.java

@@ -0,0 +1,14 @@
+package com.cslg.ppa.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class ArticleInfoIdDTO {
+
+    private Integer articleId;
+
+    private List<Integer> articleIds;
+
+}

+ 9 - 0
src/main/java/com/cslg/ppa/dto/AssoReportArticleIdDTO.java

@@ -0,0 +1,9 @@
+package com.cslg.ppa.dto;
+
+import lombok.Data;
+
+@Data
+public class AssoReportArticleIdDTO {
+
+    private Integer assoId;
+}

+ 11 - 0
src/main/java/com/cslg/ppa/dto/CategoryDTO.java

@@ -0,0 +1,11 @@
+package com.cslg.ppa.dto;
+
+import lombok.Data;
+
+@Data
+public class CategoryDTO {
+
+    private Integer categoryId;
+
+    private String name;
+}

+ 13 - 0
src/main/java/com/cslg/ppa/dto/CategoryIdDTO.java

@@ -0,0 +1,13 @@
+package com.cslg.ppa.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class CategoryIdDTO {
+
+    private Integer categoryId;
+
+    private List<Integer> categoryIds;
+}

+ 24 - 0
src/main/java/com/cslg/ppa/dto/FMSDeleteFileDTO.java

@@ -0,0 +1,24 @@
+package com.cslg.ppa.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 调用FMS系统删除文件接口
+ *
+ * @Author xiexiang
+ * @Date 2023/8/14
+ */
+@Data
+public class FMSDeleteFileDTO {
+    /**
+     * 文件ids
+     */
+    private List<String> guids;
+
+    /**
+     * 删除类型(2物理删除 1逻辑删除)
+     */
+    private Integer type;
+}

+ 30 - 0
src/main/java/com/cslg/ppa/dto/GetArticleInfoDTO.java

@@ -0,0 +1,30 @@
+package com.cslg.ppa.dto;
+
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class GetArticleInfoDTO {
+    //资讯标题
+    private String title;
+
+    //摘要
+    private String digest;
+
+    //类别 1 国家知识产权局 2 地方相关法律法规 3 判例   4国外相关资讯 5 行业资讯
+    private Integer categoryId;
+
+    //来源id
+    private Integer sourceId;
+
+    //资讯发布时间
+    private Date publicTime;
+
+    //资讯链接
+    private String articleUrl;
+
+    //公众号资讯链接
+    private String wxArticleIcon;
+
+}

+ 25 - 0
src/main/java/com/cslg/ppa/dto/OAMessageDTO.java

@@ -0,0 +1,25 @@
+package com.cslg.ppa.dto;
+
+import com.cslg.ppa.entity.commom.DifyFile;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+
+import java.util.List;
+import java.util.Map;
+
+@Data
+public class OAMessageDTO {
+    @SerializedName("response_mode")
+    private String responseMode;
+    @JsonProperty("user")
+    private String user;
+
+    private Map<String,Object> inputs;
+    private List<DifyFile> files;
+
+    @SerializedName("conversation_id")
+    private String conversationId;
+
+    private String  query;
+}

+ 26 - 0
src/main/java/com/cslg/ppa/dto/ReportDTO.java

@@ -0,0 +1,26 @@
+package com.cslg.ppa.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+import java.util.List;
+
+@Data
+public class ReportDTO {
+
+    private Integer reportId;
+
+    private String reportName;
+
+    private List<Integer> articleIds;
+
+    private String approve;
+
+//    @DateTimeFormat(pattern = "yyyy-MM-dd")
+//    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
+//    private Date approveTime;
+
+    private Integer approveStatus;
+}

+ 13 - 0
src/main/java/com/cslg/ppa/dto/ReportIdDTO.java

@@ -0,0 +1,13 @@
+package com.cslg.ppa.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class ReportIdDTO {
+
+    private Integer reportId;
+
+    private List<Integer> reportIds;
+}

+ 32 - 0
src/main/java/com/cslg/ppa/dto/SelectArticleInfoDTO.java

@@ -0,0 +1,32 @@
+package com.cslg.ppa.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+@Data
+public class SelectArticleInfoDTO {
+
+    private String key;
+
+    private Integer categoryId;
+
+    private String categoryName;
+
+    private String sourceName;
+
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
+    private Date beginTime;
+
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
+    private Date endTime;
+
+    private Long pageNum;
+
+    private Long pageSize;
+
+}

+ 9 - 0
src/main/java/com/cslg/ppa/dto/SelectAssoReportArticleDTO.java

@@ -0,0 +1,9 @@
+package com.cslg.ppa.dto;
+
+import lombok.Data;
+
+@Data
+public class SelectAssoReportArticleDTO {
+
+    private Integer reportId;
+}

+ 11 - 0
src/main/java/com/cslg/ppa/dto/SelectCategoryListDTO.java

@@ -0,0 +1,11 @@
+package com.cslg.ppa.dto;
+
+import lombok.Data;
+
+@Data
+public class SelectCategoryListDTO {
+
+    private Long pageNum;
+
+    private Long pageSize;
+}

+ 13 - 0
src/main/java/com/cslg/ppa/dto/SelectReportListDTO.java

@@ -0,0 +1,13 @@
+package com.cslg.ppa.dto;
+
+import lombok.Data;
+
+@Data
+public class SelectReportListDTO {
+
+    private String reportName;
+
+    private Long pageNum;
+
+    private Long pageSize;
+}

+ 13 - 0
src/main/java/com/cslg/ppa/dto/UpdateArticleInfoDTO.java

@@ -0,0 +1,13 @@
+package com.cslg.ppa.dto;
+
+import lombok.Data;
+
+@Data
+public class UpdateArticleInfoDTO {
+
+    private Integer articleId;
+
+    private Integer categoryId;
+
+    private String digest;
+}

+ 44 - 0
src/main/java/com/cslg/ppa/entity/ArticleInfo.java

@@ -0,0 +1,44 @@
+package com.cslg.ppa.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@TableName("article_info")
+public class ArticleInfo extends BaseEntity<ArticleInfo> {
+
+    //资讯标题
+    @TableField(value = "title")
+    private String title;
+
+    //摘要
+    @TableField(value = "digest")
+    private String digest;
+
+    //类别 1 国家知识产权局 2 地方相关法律法规 3 判例   4国外相关资讯 5 行业资讯
+    @TableField(value = "category_id")
+    private Integer categoryId;
+
+    //来源id
+    @TableField(value = "source_id")
+    private Integer sourceId;
+
+    //资讯发布时间
+    @TableField(value = "public_time")
+    private Date publicTime;
+
+    //创建时间
+    @TableField(value = "create_time")
+    private Date createTime;
+
+    //资讯链接
+    @TableField(value = "article_url")
+    private String articleUrl;
+
+    //公众号资讯图标
+    @TableField(value = "wx_article_icon")
+    private String wxArticleIcon;
+}

+ 42 - 0
src/main/java/com/cslg/ppa/entity/AssoReportArticle.java

@@ -0,0 +1,42 @@
+package com.cslg.ppa.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@TableName("asso_report_article")
+public class AssoReportArticle extends BaseEntity<AssoReportArticle>{
+
+    //报告id
+    @TableField(value = "report_id")
+    private Integer reportId;
+
+    //资讯id
+    @TableField(value = "article_id")
+    private Integer articleId;
+
+    //资讯是否使用到
+    //0 未使用
+    //1 使用中
+    @TableField(value = "if_use")
+    private Integer ifUse;
+
+    //创建人
+    @TableField(value = "creator")
+    private String creator;
+
+    //创建时间
+    @TableField(value = "create_time")
+    private Date createTime;
+
+    //修改人
+    @TableField(value = "update_id")
+    private String updateId;
+
+    //修改时间
+    @TableField(value = "update_time")
+    private Date updateTime;
+}

+ 28 - 0
src/main/java/com/cslg/ppa/entity/BaseEntity.java

@@ -0,0 +1,28 @@
+package com.cslg.ppa.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import lombok.Data;
+
+
+/**
+ * Entity基类
+ *
+ */
+@Data
+@SuppressWarnings("rawtypes")
+public class BaseEntity<T extends Model> extends Model {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = -4851055162892178225L;
+
+    /**
+     * 唯一ID
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+}

+ 23 - 0
src/main/java/com/cslg/ppa/entity/Category.java

@@ -0,0 +1,23 @@
+package com.cslg.ppa.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@TableName("category")
+public class Category extends BaseEntity<Category> {
+    //类别名称
+    @TableField(value = "name")
+    private String name;
+
+    //创建人
+    @TableField(value = "creator")
+    private String creator;
+
+    //创建时间
+    @TableField(value = "create_time")
+    private Date createTime;
+}

+ 39 - 0
src/main/java/com/cslg/ppa/entity/Report.java

@@ -0,0 +1,39 @@
+package com.cslg.ppa.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@TableName("report")
+public class Report extends BaseEntity<Report> {
+    //报告名称
+    @TableField(value = "report_name")
+    private String reportName;
+
+    //创建人
+    @TableField(value = "creator")
+    private String creator;
+
+    //创建时间
+    @TableField(value = "create_time")
+    private Date createTime;
+
+    //审核人
+    @TableField(value = "approve")
+    private String approve;
+
+    //审核时间
+    @TableField(value = "approve_time")
+    private Date approveTime;
+
+    //审核状态
+    //0 未审核
+    //1 审核中
+    //2 已审核
+    @TableField(value = "approve_status")
+    private Integer approveStatus;
+
+}

+ 32 - 0
src/main/java/com/cslg/ppa/entity/ReportTemple.java

@@ -0,0 +1,32 @@
+package com.cslg.ppa.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@TableName("report_temple")
+public class ReportTemple extends BaseEntity<ReportTemple> {
+    /**
+     * 模板名称
+     */
+    @TableField(value = "template_name")
+    private String templateName;
+    /**
+     * 模板路径
+     */
+    @TableField(value = "template_path")
+    private String templatePath;
+    /**
+     * 模板创建人id
+     */
+    @TableField(value = "create_id")
+    private Integer createId;
+    /**
+     * 模板创建时间
+     */
+    @TableField(value = "create_time")
+    private Date createTime;
+}

+ 31 - 0
src/main/java/com/cslg/ppa/entity/SourceInfo.java

@@ -0,0 +1,31 @@
+package com.cslg.ppa.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+@Data
+@TableName("source_info")
+public class SourceInfo extends BaseEntity<SourceInfo> {
+    //来源名称
+    @TableField(value = "source_name")
+    private String sourceName;
+
+    //来源链接
+    @TableField(value = "source_url")
+    private String sourceUrl;
+
+    //来源类型
+    //1 网址
+    //2 公众号
+    @TableField(value = "source_type")
+    private Integer sourceType;
+
+    //公众号唯一id
+    @TableField(value = "fake_id")
+    private String fakeId;
+
+    //图标
+    @TableField(value = "icon")
+    private String icon;
+}

+ 57 - 0
src/main/java/com/cslg/ppa/entity/commom/Article.java

@@ -0,0 +1,57 @@
+package com.cslg.ppa.entity.commom;
+
+/**
+ * 文章数据
+ * @author xx
+ * @date 2024/8/31 - 21:54
+ */
+public class Article {
+
+    private String title;
+
+    private String link;
+
+    private String create_time;
+
+    private String cover;
+
+    public String getCreate_time() {
+        return create_time;
+    }
+
+    public void setCreate_time(String create_time) {
+        this.create_time = create_time;
+    }
+
+    public String getLink() {
+        return link;
+    }
+
+    public void setLink(String link) {
+        this.link = link;
+    }
+    //...还有很多参数
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getCover() {
+        return cover;
+    }
+
+    public void setCover(String cover) {
+        this.cover = cover;
+    }
+
+    @Override
+    public String toString() {
+        return "Article{" +
+                "title='" + title + '\'' +
+                '}';
+    }
+}

+ 37 - 0
src/main/java/com/cslg/ppa/entity/commom/BaseResp.java

@@ -0,0 +1,37 @@
+package com.cslg.ppa.entity.commom;
+
+/**
+ * @author zsq
+ * @version 1.0
+ * @date 2021/3/31 11:18
+ */
+public class BaseResp {
+
+    private String err_msg;
+
+    private Integer ret;
+
+    public String getErr_msg() {
+        return err_msg;
+    }
+
+    public void setErr_msg(String err_msg) {
+        this.err_msg = err_msg;
+    }
+
+    public Integer getRet() {
+        return ret;
+    }
+
+    public void setRet(Integer ret) {
+        this.ret = ret;
+    }
+
+    @Override
+    public String toString() {
+        return "BaseResp{" +
+                "err_msg='" + err_msg + '\'' +
+                ", ret=" + ret +
+                '}';
+    }
+}

+ 30 - 0
src/main/java/com/cslg/ppa/entity/commom/BaseVO.java

@@ -0,0 +1,30 @@
+package com.cslg.ppa.entity.commom;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @author 沈永艺
+ * @date 2022-8-3
+ * @description VO基类
+ */
+
+@Data
+@Accessors(chain = true)
+public class BaseVO {
+    /**
+     * 每页条数
+     */
+    private Integer size;
+
+    /**
+     * 当前页数
+     */
+    private Integer current;
+
+    /**
+     * 数据总数
+     */
+    private Integer total;
+
+}

+ 50 - 0
src/main/java/com/cslg/ppa/entity/commom/BizData.java

@@ -0,0 +1,50 @@
+package com.cslg.ppa.entity.commom;
+
+/**
+ * 公众号数据
+ * @author zsq
+ * @date 2021/3/31 - 21:38
+ */
+public class BizData {
+
+    private String fakeid;
+
+    private String nickname;
+
+    private String round_head_img;
+//    ...还有很多参数
+
+
+    public String getFakeid() {
+        return fakeid;
+    }
+
+    public void setFakeid(String fakeid) {
+        this.fakeid = fakeid;
+    }
+
+    public String getNickname() {
+        return nickname;
+    }
+
+    public void setNickname(String nickname) {
+        this.nickname = nickname;
+    }
+
+    public String getRound_head_img() {
+        return round_head_img;
+    }
+
+    public void setRound_head_img(String round_head_img) {
+        this.round_head_img = round_head_img;
+    }
+
+    @Override
+    public String toString() {
+        return "BizData{" +
+                "fakeid='" + fakeid + '\'' +
+                ", nickname='" + nickname + '\'' +
+                ", round_head_img='" + round_head_img + '\'' +
+                '}';
+    }
+}

+ 35 - 0
src/main/java/com/cslg/ppa/entity/commom/Calculate.java

@@ -0,0 +1,35 @@
+package com.cslg.ppa.entity.commom;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 根据起止条数计算开始页数、开始页数的开始位置、结束页数、结束页数的结束位置
+ *
+ * @Author chenyu
+ * @Date 2023/7/14
+ */
+@Accessors(chain = true)
+@Data
+public class Calculate implements Serializable {
+    /**
+     * 检索开始页数
+     */
+    private Integer startPage;
+    /**
+     * 检索开始页数的开始专利位置
+     */
+    private Integer startNum;
+    /**
+     * 检索结束页数
+     */
+    private Integer endPage;
+    /**
+     * 检索结束页数的结束专利位置
+     */
+    private Integer endNum;
+
+
+}

+ 15 - 0
src/main/java/com/cslg/ppa/entity/commom/DifyFile.java

@@ -0,0 +1,15 @@
+package com.cslg.ppa.entity.commom;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+
+@Data
+public class DifyFile {
+    private String type;
+    @SerializedName("transfer_method")
+    private String transferMethod;
+    private String url;
+    @JsonProperty("upload_file_id")
+    private String uploadFileId;
+}

+ 25 - 0
src/main/java/com/cslg/ppa/entity/commom/PatentData.java

@@ -0,0 +1,25 @@
+package com.cslg.ppa.entity.commom;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+import org.apache.poi.ss.usermodel.PictureData;
+
+import java.util.Map;
+
+/**
+ * @Author chenyu
+ * @Date 2023/5/31
+ */
+@Accessors(chain = true)
+@Data
+public class PatentData {
+    /**
+     * 专利内容数据(除了摘要附图, key:表头如 "公开(公告)号"  value:表头对应内容如 "CN1307082B")
+     */
+    private Map<Object, Object> map;
+    /**
+     * 专利摘要附图
+     */
+    private PictureData pictureData;
+
+}

+ 11 - 0
src/main/java/com/cslg/ppa/entity/commom/Records.java

@@ -0,0 +1,11 @@
+package com.cslg.ppa.entity.commom;
+
+import lombok.Data;
+
+@Data
+public class Records {
+    private Long current;
+    private Long size;
+    private Long total;
+    private Object data;
+}

+ 33 - 0
src/main/java/com/cslg/ppa/entity/commom/SystemFile.java

@@ -0,0 +1,33 @@
+package com.cslg.ppa.entity.commom;
+
+import lombok.Data;
+
+/**
+ * 系统文件实体类
+ *
+ * @Author xiexiang
+ * @Date 2023/6/1
+ */
+@Data
+
+public class SystemFile {
+    /**
+     * 文件guid
+     */
+    private String guid;
+
+    /**
+     * 文件名称
+     */
+    private String fileName;
+
+    /**
+     * 原始名称
+     */
+    private String originalName;
+
+    /**
+     * 文件类型
+     */
+    private String type;
+}

+ 112 - 0
src/main/java/com/cslg/ppa/entity/commom/WxResultBody.java

@@ -0,0 +1,112 @@
+package com.cslg.ppa.entity.commom;
+
+/**
+ * @Author xiexiang
+ * @Date 2024/7/10
+ */
+public class WxResultBody<L> {
+    private Integer acct_size;
+
+    private String err_msg;
+
+    private String redirect_url;
+
+    private Integer ret;
+
+    private Integer status;
+
+    private Integer user_category;
+
+    private BaseResp base_resp;
+
+    private L list;
+
+    private L app_msg_list;
+
+    public BaseResp getBase_resp() {
+        return base_resp;
+    }
+
+    public void setBase_resp(BaseResp base_resp) {
+        this.base_resp = base_resp;
+    }
+
+    public Integer getAcct_size() {
+        return acct_size;
+    }
+
+    public void setAcct_size(Integer acct_size) {
+        this.acct_size = acct_size;
+    }
+
+    public String getErr_msg() {
+        return err_msg;
+    }
+
+    public void setErr_msg(String err_msg) {
+        this.err_msg = err_msg;
+    }
+
+    public Integer getRet() {
+        return ret;
+    }
+
+    public void setRet(Integer ret) {
+        this.ret = ret;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public Integer getUser_category() {
+        return user_category;
+    }
+
+    public void setUser_category(Integer user_category) {
+        this.user_category = user_category;
+    }
+
+    public String getRedirect_url() {
+        return redirect_url;
+    }
+
+    public void setRedirect_url(String redirect_url) {
+        this.redirect_url = redirect_url;
+    }
+
+    public L getList() {
+        return list;
+    }
+
+    public void setList(L list) {
+        this.list = list;
+    }
+
+    public L getApp_msg_list() {
+        return app_msg_list;
+    }
+
+    public void setApp_msg_list(L app_msg_list) {
+        this.app_msg_list = app_msg_list;
+    }
+
+    @Override
+    public String toString() {
+        return "WxResultBody{" +
+                "acct_size=" + acct_size +
+                ", err_msg='" + err_msg + '\'' +
+                ", redirect_url='" + redirect_url + '\'' +
+                ", ret=" + ret +
+                ", status=" + status +
+                ", user_category=" + user_category +
+                ", base_resp=" + base_resp +
+                ", list=" + list +
+                ", app_msg_list=" + app_msg_list +
+                '}';
+    }
+}

+ 18 - 0
src/main/java/com/cslg/ppa/mapper/ArticleInfoMapper.java

@@ -0,0 +1,18 @@
+package com.cslg.ppa.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cslg.ppa.dto.SelectArticleInfoDTO;
+import com.cslg.ppa.entity.ArticleInfo;
+import com.cslg.ppa.vo.SelectArticleInfoVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface ArticleInfoMapper extends BaseMapper<ArticleInfo> {
+
+    List<SelectArticleInfoVO> selectArticleInfoList(@Param("vo") SelectArticleInfoDTO vo);
+
+    Long selectArticleInfoCount(@Param("vo") SelectArticleInfoDTO vo);
+}

+ 10 - 0
src/main/java/com/cslg/ppa/mapper/AssoReportArticleMapper.java

@@ -0,0 +1,10 @@
+package com.cslg.ppa.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cslg.ppa.entity.AssoReportArticle;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface AssoReportArticleMapper extends BaseMapper<AssoReportArticle> {
+
+}

+ 9 - 0
src/main/java/com/cslg/ppa/mapper/CategoryMapper.java

@@ -0,0 +1,9 @@
+package com.cslg.ppa.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cslg.ppa.entity.Category;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface CategoryMapper extends BaseMapper<Category> {
+}

+ 16 - 0
src/main/java/com/cslg/ppa/mapper/ReportMapper.java

@@ -0,0 +1,16 @@
+package com.cslg.ppa.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cslg.ppa.entity.Report;
+import com.cslg.ppa.vo.SelectAssoReportArticleVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface ReportMapper extends BaseMapper<Report> {
+
+    public List<SelectAssoReportArticleVO> selectAssoReportArticleList(@Param("reportId") Integer reportId);
+
+}

+ 14 - 0
src/main/java/com/cslg/ppa/mapper/ReportTempleMapper.java

@@ -0,0 +1,14 @@
+package com.cslg.ppa.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cslg.ppa.entity.ReportTemple;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 报告产品表
+ * @Author zero
+ * @Date 2023/12/09
+ */
+@Mapper
+public interface ReportTempleMapper extends BaseMapper<ReportTemple> {
+}

+ 9 - 0
src/main/java/com/cslg/ppa/mapper/SourceInfoMapper.java

@@ -0,0 +1,9 @@
+package com.cslg.ppa.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cslg.ppa.entity.SourceInfo;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface SourceInfoMapper extends BaseMapper<SourceInfo> {
+}

+ 104 - 0
src/main/java/com/cslg/ppa/service/ArticleInfoService.java

@@ -0,0 +1,104 @@
+package com.cslg.ppa.service;
+
+import com.alibaba.druid.sql.visitor.functions.If;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cslg.ppa.common.core.auth.Response;
+import com.cslg.ppa.dto.ArticleInfoIdDTO;
+import com.cslg.ppa.dto.GetArticleInfoDTO;
+import com.cslg.ppa.dto.SelectArticleInfoDTO;
+import com.cslg.ppa.dto.UpdateArticleInfoDTO;
+import com.cslg.ppa.entity.ArticleInfo;
+import com.cslg.ppa.entity.BaseEntity;
+import com.cslg.ppa.entity.commom.Records;
+import com.cslg.ppa.mapper.ArticleInfoMapper;
+import com.cslg.ppa.service.commom.DifyService;
+import com.cslg.ppa.vo.SelectArticleInfoVO;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import java.util.Arrays;
+import java.util.List;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor(onConstructor_ = {@Lazy})
+public class ArticleInfoService extends ServiceImpl<ArticleInfoMapper, ArticleInfo> {
+
+    @Autowired
+    private ArticleInfoMapper articleInfoMapper;
+
+    public void batchAddArticleInfo(List<GetArticleInfoDTO> articleInfoDTOS) {
+        if (!CollectionUtils.isEmpty(articleInfoDTOS)) {
+            for (GetArticleInfoDTO articleInfoDTO : articleInfoDTOS) {
+                this.addArticleInfo(articleInfoDTO);
+            }
+        }
+    }
+
+    //添加资讯
+    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Throwable.class)
+    public void addArticleInfo(GetArticleInfoDTO infoDTO) {
+        ArticleInfo articleInfo = new ArticleInfo();
+        articleInfo.setTitle(infoDTO.getTitle());
+        articleInfo.setDigest(infoDTO.getDigest());
+        articleInfo.setCategoryId(infoDTO.getCategoryId());
+        articleInfo.setPublicTime(infoDTO.getPublicTime());
+        articleInfo.setArticleUrl(infoDTO.getArticleUrl());
+        articleInfo.setSourceId(infoDTO.getSourceId());
+        articleInfo.setWxArticleIcon(infoDTO.getWxArticleIcon());
+        articleInfo.insert();
+    }
+
+    /**
+     * 查询资讯列表
+     *
+     * @param vo
+     * @return
+     */
+    public String selectArticleInfoList(SelectArticleInfoDTO vo) {
+        List<SelectArticleInfoVO> articleInfoVOS = articleInfoMapper.selectArticleInfoList(vo);
+        Long count = articleInfoMapper.selectArticleInfoCount(vo);
+        Records records = new Records();
+        records.setTotal(count);
+        records.setCurrent(vo.getPageNum());
+        records.setSize(vo.getPageSize());
+        records.setData(articleInfoVOS);
+        return Response.success(records);
+    }
+
+    /**
+     * 编辑资讯信息
+     * @param infoDTO
+     * @return
+     */
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
+    public Integer updateArticleInfo(UpdateArticleInfoDTO infoDTO) {
+        Integer articleId = infoDTO.getArticleId();
+        ArticleInfo articleInfo = articleInfoMapper.selectById(articleId);
+        articleInfo.setDigest(infoDTO.getDigest());
+        articleInfo.setCategoryId(infoDTO.getCategoryId());
+        articleInfo.updateById();
+        return articleInfo.getId();
+    }
+
+    /**
+     * 删除资讯
+     * @param vo
+     */
+    public void deleteArticleInfo(ArticleInfoIdDTO vo) {
+        List<Integer> articleIds = vo.getArticleIds();
+        if (!CollectionUtils.isEmpty(articleIds)) {
+            articleInfoMapper.deleteBatchIds(articleIds);
+        }
+    }
+}

+ 15 - 0
src/main/java/com/cslg/ppa/service/AssoReportArticleService.java

@@ -0,0 +1,15 @@
+package com.cslg.ppa.service;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cslg.ppa.entity.AssoReportArticle;
+import com.cslg.ppa.mapper.AssoReportArticleMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor(onConstructor_ = {@Lazy})
+public class AssoReportArticleService extends ServiceImpl<AssoReportArticleMapper, AssoReportArticle> {
+}

+ 74 - 0
src/main/java/com/cslg/ppa/service/CategoryService.java

@@ -0,0 +1,74 @@
+package com.cslg.ppa.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cslg.ppa.common.core.auth.Response;
+import com.cslg.ppa.dto.CategoryDTO;
+import com.cslg.ppa.dto.CategoryIdDTO;
+import com.cslg.ppa.dto.SelectCategoryListDTO;
+import com.cslg.ppa.entity.BaseEntity;
+import com.cslg.ppa.entity.Category;
+import com.cslg.ppa.entity.commom.Records;
+import com.cslg.ppa.mapper.CategoryMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor(onConstructor_ = {@Lazy})
+public class CategoryService extends ServiceImpl<CategoryMapper, Category> {
+
+    @Autowired
+    private CategoryMapper categoryMapper;
+
+    public String selectCategoryList(SelectCategoryListDTO vo) {
+        Records records = new Records();
+        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
+        List<Category> categoryList = new ArrayList<>();
+        if (vo.getPageNum()!= null && vo.getPageSize() != null) {
+            Page<Category> page = new Page<>(vo.getPageNum(), vo.getPageSize());
+            Page<Category> categoryPage = categoryMapper.selectPage(page, wrapper);
+            categoryList = categoryPage.getRecords();
+            long total = categoryPage.getTotal();
+            records.setCurrent(vo.getPageNum());
+            records.setTotal(total);
+            records.setSize(vo.getPageSize());
+        } else {
+            categoryList = categoryMapper.selectList(wrapper);
+        }
+        records.setData(categoryList);
+        return Response.success(records);
+    }
+
+
+    public Integer addOrEditCategory(CategoryDTO vo) {
+        Integer categoryId = vo.getCategoryId();
+        if (ObjectUtils.isNotEmpty(categoryId)) {
+            Category category = categoryMapper.selectById(categoryId);
+            category.setName(vo.getName());
+            category.updateById();
+        } else {
+            Category category = new Category();
+            category.setName(vo.getName());
+            category.insert();
+            categoryId = category.getId();
+        }
+        return categoryId;
+    }
+
+    public void deleteCategory(CategoryIdDTO vo) {
+        List<Integer> categoryIds = vo.getCategoryIds();
+        if (!CollectionUtils.isEmpty(categoryIds)) {
+            categoryMapper.deleteBatchIds(categoryIds);
+        }
+    }
+}

+ 241 - 0
src/main/java/com/cslg/ppa/service/GetWebArticle/GetCNIPAArticleService.java

@@ -0,0 +1,241 @@
+package com.cslg.ppa.service.GetWebArticle;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.cslg.ppa.common.utils.DateUtil;
+import com.cslg.ppa.dto.GetArticleInfoDTO;
+import com.cslg.ppa.entity.ArticleInfo;
+import com.cslg.ppa.service.ArticleInfoService;
+import com.cslg.ppa.service.commom.DifyService;
+import com.cslg.ppa.service.commom.XmlParseService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+import org.openqa.selenium.WebDriver;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class GetCNIPAArticleService {
+    private final ArticleInfoService articleInfoService;
+    private final XmlParseService xmlParseService;
+    @Autowired
+    private DifyService difyService;
+
+    @Scheduled(cron = "0 0 2 * * ?")
+    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Throwable.class)
+    public void getCNIPA(){
+        System.out.println(new Date() + "CNIPA-Begin");
+        Map<String , String> urlMap = new HashMap<>();
+        // 首页 - 专题 - 专利审查高速路(PPH)专栏 - 通知  669
+//        urlMap.put("https://www.cnipa.gov.cn/col/col340/index.html", "669");
+        // 政务 - 政策文件 - 公告   485
+        urlMap.put("https://www.cnipa.gov.cn/col/col74/index.html", "17035");
+        // 政务 - 政策文件 - 通知   485
+        urlMap.put("https://www.cnipa.gov.cn/col/col75/index.html", "17035");
+        // 新闻 - 地方动态 - 动态信息
+//        urlMap.put("https://www.cnipa.gov.cn/col/col57/index.html", "485");
+
+        for (Map.Entry<String, String> entry : urlMap.entrySet()) {
+            String url = entry.getKey();
+            CloseableHttpClient httpClient = HttpClients.createDefault();
+            try {
+                HttpGet request = new HttpGet(url);
+                HttpResponse response = httpClient.execute(request);
+                String responseBody = EntityUtils.toString(response.getEntity());
+                httpClient.close();
+                if (responseBody != null) {
+                    String key = entry.getValue();
+                    this.readJson(key, responseBody,1);
+                }
+            } catch (Exception e) {
+                System.out.println("Get Web Article Error:" + e);
+            }
+        }
+        System.out.println(new Date() + "CNIPA-End");
+    }
+
+    public void readJson(String key, String responseBody,Integer type) {
+        try {
+            List<GetArticleInfoDTO> articleInfoDTOS = new ArrayList<>();
+            //使用JSoup解析HTML
+            Document doc = Jsoup.parse(responseBody);
+            Element div = doc.getElementById(key);
+            Element scriptElement = div.select("script").first();
+            String contentText = scriptElement.html();
+            List<String> reStrs = xmlParseService.xmlParse(contentText, "record");
+            for (String reStr : reStrs) {
+                Document document = Jsoup.parse(reStr);
+                Element linkElement = document.getElementsByTag("a").first();
+                //获取时间
+                String dateStr = document.getElementsByTag("span").text().trim();
+                String yesterdayDateStr = DateUtil.getYesterdayDateStr();
+                if (!StringUtils.equals(dateStr, yesterdayDateStr)) {
+                    continue;
+                }
+                Date date = new Date();
+                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+                try {
+                    date = dateFormat.parse(dateStr);
+                } catch (Exception e) {
+                    continue;
+                }
+
+                String link = linkElement.attr("href");
+                String title = linkElement.text();
+
+                // 检查文章是否已存在
+                ArticleInfo articleInfo = articleInfoService.getOne(new QueryWrapper<ArticleInfo>().lambda().eq(ArticleInfo::getTitle, title));
+                if (ObjectUtils.isNotEmpty(articleInfo)) {
+                    continue; // 文章已存在,跳过
+                }
+
+                String digest = null;
+                try {
+                    digest = this.getDigest(link);
+                } catch (Exception e) {
+                    digest = "";
+                }
+                if (StringUtils.isEmpty(digest)) {
+                    continue;
+                }
+                String condensedAbstract = null;
+                try {
+                    condensedAbstract = difyService.getCondensedAbstract(digest);
+                } catch (Exception e) {
+
+                }
+                if (StringUtils.isEmpty(condensedAbstract)) {
+                    continue;
+                }
+                GetArticleInfoDTO articleInfoDTO = new GetArticleInfoDTO();
+                articleInfoDTO.setCategoryId(type);
+                articleInfoDTO.setSourceId(1);
+                articleInfoDTO.setArticleUrl(link);
+                articleInfoDTO.setTitle(title);
+                articleInfoDTO.setPublicTime(date);
+                articleInfoDTO.setDigest(condensedAbstract);
+                articleInfoDTOS.add(articleInfoDTO);
+            }
+            articleInfoService.batchAddArticleInfo(articleInfoDTOS);
+        } catch (Exception e) {
+            System.out.println("Read Json Error" + e);
+        }
+    }
+
+    //精简摘要
+    public String getDigest(String url) throws IOException {
+        String digest = "";
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        HttpGet request = new HttpGet(url);
+        HttpResponse response = httpClient.execute(request);
+        String responseBody = EntityUtils.toString(response.getEntity());
+        httpClient.close();
+        if (responseBody != null) {
+            digest = this.readJson(responseBody);
+        }
+        return digest;
+    }
+
+    public String readJson(String responseBody) {
+        StringBuilder builder = new StringBuilder();
+        try {
+            //使用JSoup解析HTML
+            Document doc = Jsoup.parse(responseBody);
+//            String title = doc.title();
+//            Elements paragraphs = doc.select("p");
+//            for (Element paragraph : paragraphs) {
+//                String text = paragraph.text();
+//            }
+            // 获取description元数据
+            Element metaElement = doc.selectFirst("meta[name=description]");
+            if (metaElement != null) {
+                String content = metaElement.attr("content");
+                builder = new StringBuilder(content);
+            } else {
+                builder = new StringBuilder();
+            }
+        } catch (Exception e) {
+            builder = new StringBuilder();
+        }
+        return builder.toString();
+    }
+
+    //精简摘要
+    public void getDigest1(String url) throws IOException {
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        HttpGet request = new HttpGet(url);
+        HttpResponse response = httpClient.execute(request);
+        String responseBody = EntityUtils.toString(response.getEntity());
+        httpClient.close();
+        if (responseBody != null) {
+            this.readJson1(responseBody,url);
+        }
+    }
+
+    public void readJson1(String responseBody, String articleUrl) {
+        StringBuilder builder = new StringBuilder();
+        try {
+            //使用JSoup解析HTML
+            Document doc = Jsoup.parse(responseBody);
+            String title = doc.title();
+            // 通过 CSS 选择器定位元素
+            Element dateSpan = doc.selectFirst("div.article-info.clearfix > span:containsOwn(发布时间:)");
+
+            Date date = new Date();
+            if (dateSpan != null) {
+                String fullText = dateSpan.text();
+                String publishDate = fullText.replace("发布时间:", "").trim();
+                System.out.println("发布时间:" + publishDate);
+                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+                try {
+                    date = dateFormat.parse(publishDate);
+                } catch (Exception e) {
+                }// 输出:2025-08-21
+            } else {
+                System.out.println("未找到发布时间");
+            }
+            // 获取description元数据
+            Element metaElement = doc.selectFirst("meta[name=description]");
+            if (metaElement != null) {
+                String content = metaElement.attr("content");
+                builder = new StringBuilder(content);
+            } else {
+                builder = new StringBuilder();
+            }
+            System.out.println(builder.toString());
+            String condensedAbstract = difyService.getCondensedAbstract(builder.toString());
+            ArticleInfo articleInfo = new ArticleInfo();
+            articleInfo.setTitle(title);
+            articleInfo.setDigest(condensedAbstract);
+            articleInfo.setCategoryId(1);
+            articleInfo.setSourceId(1);
+            articleInfo.setPublicTime(date);
+            articleInfo.setArticleUrl(articleUrl);
+            articleInfo.insert();
+        } catch (Exception e) {
+        }
+    }
+}
+

+ 57 - 0
src/main/java/com/cslg/ppa/service/GetWebArticle/GetLocalInformationService.java

@@ -0,0 +1,57 @@
+package com.cslg.ppa.service.GetWebArticle;
+
+import com.cslg.ppa.service.ArticleInfoService;
+import com.cslg.ppa.service.commom.XmlParseService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class GetLocalInformationService {
+    private final GetCNIPAArticleService getCNIPAArticleService;
+
+    @Scheduled(cron = "0 0 3 * * ?")
+    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Throwable.class)
+    public void getLocalInformation(){
+        System.out.println(new Date() + "Local-Begin");
+        Map<String , String> urlMap = new HashMap<>();
+        // 首页 - 专题 - 专利审查高速路(PPH)专栏 - 通知  669
+//        urlMap.put("https://www.cnipa.gov.cn/col/col340/index.html", "669");
+        // 政务 - 政策文件 - 公告   485
+//        urlMap.put("https://www.cnipa.gov.cn/col/col74/index.html", "485");
+        // 政务 - 政策文件 - 通知   485
+//        urlMap.put("https://www.cnipa.gov.cn/col/col75/index.html", "485");
+        // 新闻 - 地方动态 - 动态信息
+        urlMap.put("https://www.cnipa.gov.cn/col/col57/index.html", "485");
+
+        for (Map.Entry<String, String> entry : urlMap.entrySet()) {
+            String url = entry.getKey();
+            CloseableHttpClient httpClient = HttpClients.createDefault();
+            try {
+                HttpGet request = new HttpGet(url);
+                HttpResponse response = httpClient.execute(request);
+                String responseBody = EntityUtils.toString(response.getEntity());
+                httpClient.close();
+                if (responseBody != null) {
+                    String key = entry.getValue();
+                    getCNIPAArticleService.readJson(key, responseBody, 2);
+                }
+            } catch (Exception e) {
+                System.out.println("Get Web Article Error:" + e);
+            }
+        }
+        System.out.println(new Date() + "Local-End");
+    }
+}

+ 259 - 0
src/main/java/com/cslg/ppa/service/GetWebArticle/GetProvinceNewsService.java

@@ -0,0 +1,259 @@
+package com.cslg.ppa.service.GetWebArticle;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.cslg.ppa.common.utils.DateUtil;
+import com.cslg.ppa.dto.GetArticleInfoDTO;
+import com.cslg.ppa.entity.ArticleInfo;
+import com.cslg.ppa.service.commom.DifyService;
+import com.cslg.ppa.service.commom.XmlParseService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.nodes.Node;
+import org.jsoup.select.Elements;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class GetProvinceNewsService {
+    private final XmlParseService xmlParseService;
+    @Autowired
+    private DifyService difyService;
+
+    private static List<String> TitleList = Arrays.asList("要闻动态", "通知公告");
+    private static final Pattern DATE_PATTERN = Pattern.compile("(?<!\\d)(\\d{4}-\\d{2}-\\d{2})(?!\\d)");
+    // 新闻动态项的CSS选择器 (通用配置,适用于大部分政府网站)
+    private static final String NEWS_CONTAINER_SELECTOR = "div.con-right-list,div.main-content-right,div.tab-content,div.subpageCon-con,div.gl-main,div.nymain," +
+            "div.contain";
+    private static final String TITLE_SELECTOR = "a";
+    private static final String LINK_SELECTOR = "a[href]";
+
+    public void crawlArticles(String baseUrl) throws IOException {
+        // 使用Jsoup连接并解析网页
+        Document doc = Jsoup.connect(baseUrl)
+                .timeout(15000) // 增加超时时间
+                .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36")
+                .followRedirects(true) // 跟随重定向
+                .get();
+
+        // 改进的新闻列表抓取逻辑
+        Elements newsItems  = doc.select(LINK_SELECTOR);
+        List<String> list = new ArrayList<>();
+        for (Element item : newsItems) {
+            try {
+                Element titleElement = item.selectFirst(TITLE_SELECTOR);
+                Element linkElement = item.selectFirst(LINK_SELECTOR);
+
+                if (titleElement != null && linkElement != null) {
+                    String title = titleElement.text().trim();
+                    if (TitleList.contains(title)) {
+                        String link = linkElement.absUrl("href"); // 获取绝对URL
+                        list.add(link);
+                    }
+                }
+            } catch (Exception e) {
+                log.warn("解析单个新闻项时出错: ", e);
+            }
+        }
+        if (!CollectionUtils.isEmpty(list)) {
+            List<String> collect = list.stream().distinct().collect(Collectors.toList());
+            for (String url : collect) {
+                this.crawlArticlesDetail(url);
+            }
+        }
+    }
+
+    public List<GetArticleInfoDTO> crawlArticlesDetail(String baseUrl) throws IOException {
+        List<GetArticleInfoDTO> articleInfoDTOS = new ArrayList<>();
+        // 使用Jsoup连接并解析网页
+        Document doc = Jsoup.connect(baseUrl)
+                .timeout(15000) // 增加超时时间
+                .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36")
+                .followRedirects(true) // 跟随重定向
+                .get();
+
+        // 改进的新闻列表抓取逻辑
+        Element container = doc.selectFirst(NEWS_CONTAINER_SELECTOR);
+        //todo 如果找不到该怎么做
+//        if (container == null) {
+//            String contentText = doc.html();
+//            List<String> reStrs = xmlParseService.xmlParse(contentText, "record");
+//            System.out.println(reStrs);
+//        }
+        Element scriptElement = container.select("script").first();
+        List<String> reStrs = new ArrayList<>();
+        if (scriptElement == null) {
+            Elements elements = container.select("li");
+//            List<String> collect = elements.stream().map(Node::outerHtml).collect(Collectors.toList());
+            for (Element element : elements) {
+                String liTag = element.outerHtml().trim();
+                reStrs.add(liTag);
+            }
+        } else {
+            String contentText = scriptElement.html();
+            if (contentText.contains("record")) {
+                try {
+                    reStrs = xmlParseService.xmlParse(contentText, "record");
+                } catch (Exception ignored) {
+
+                }
+            }
+        }
+        if (CollectionUtils.isEmpty(reStrs)) {
+            Elements elements = container.select("li");
+//            List<String> collect = elements.stream().map(Node::outerHtml).collect(Collectors.toList());
+            for (Element element : elements) {
+                String liTag = element.outerHtml().trim();
+                reStrs.add(liTag);
+            }
+        }
+        int count = 1;
+        for (String reStr : reStrs) {
+            // 限制处理的新闻项数量,避免处理过多数据
+            if (count >= 10) {
+                log.info("已达到处理上限(30条),停止处理更多新闻项");
+                break;
+            }
+            Document document = Jsoup.parse(reStr);
+            Element linkElement = document.getElementsByTag("a").first();
+            //获取时间
+            String dateStr = document.getElementsByTag("span").text().trim();
+            if (baseUrl.contains("zjippc.org.cn")) {
+                dateStr = extractDate(dateStr);
+            }
+            String yesterdayDateStr = DateUtil.getYesterdayDateStr();
+//            if (!StringUtils.equals(dateStr, yesterdayDateStr)) {
+//                continue;
+//            }
+            Date date = new Date();
+            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+            try {
+                date = dateFormat.parse(dateStr);
+            } catch (Exception e) {
+                continue;
+            }
+
+            String title = linkElement.text();
+            if (baseUrl.contains("zjippc.org.cn")) {
+                title = title.replace(dateStr, "");
+            }
+            // 检查文章是否已存在
+//            ArticleInfo articleInfo = articleInfoService.getOne(new QueryWrapper<ArticleInfo>().lambda().eq(ArticleInfo::getTitle, title));
+//            if (ObjectUtils.isNotEmpty(articleInfo)) {
+//                continue; // 文章已存在,跳过
+//            }
+
+            String link = linkElement.absUrl("href");
+            // 如果absUrl没有返回有效链接,尝试其他方式
+            if (StringUtils.isEmpty(link)) {
+                link = linkElement.attr("href");
+            }
+            if (link.startsWith("/")) {
+                // 提取基础URL的协议和域名
+                int endIndex = baseUrl.indexOf("/", 8); // 跳过http://或https://
+                String baseDomain = endIndex > 0 ? baseUrl.substring(0, endIndex) : baseUrl;
+                link = baseDomain + link;
+            } else if (!link.startsWith("http")) {
+                // 处理相对路径
+                int lastSlash = baseUrl.lastIndexOf("/");
+                String basePath = lastSlash > 0 ? baseUrl.substring(0, lastSlash + 1) : baseUrl + "/";
+                link = basePath + link;
+            }
+
+            String digest = null;
+            try {
+                digest = this.getDigest(link);
+            } catch (Exception e) {
+                System.out.println(e);
+                System.out.println(link);
+                System.out.println(title);
+                continue;
+            }
+//            if (StringUtils.isEmpty(digest)) {
+//                continue;
+//            }
+            String condensedAbstract = null;
+//            try {
+//                condensedAbstract = difyService.getCondensedAbstract(digest);
+//            } catch (Exception e) {
+//
+//            }
+//            if (StringUtils.isEmpty(condensedAbstract)) {
+//                continue;
+//            }
+            GetArticleInfoDTO articleInfoDTO = new GetArticleInfoDTO();
+//            articleInfoDTO.setCategoryId(type);
+            articleInfoDTO.setSourceId(1);
+            articleInfoDTO.setArticleUrl(link);
+            articleInfoDTO.setTitle(title);
+            articleInfoDTO.setPublicTime(date);
+            articleInfoDTO.setDigest(digest);
+//            articleInfoDTOS.add(articleInfoDTO);
+            count++;
+        }
+//        articleInfoService.batchAddArticleInfo(articleInfoDTOS);
+        return articleInfoDTOS;
+    }
+
+    public String getDigest(String baseUrl) throws IOException {
+        // 使用Jsoup连接并解析网页
+        Document doc = Jsoup.connect(baseUrl)
+                .timeout(15000) // 增加超时时间
+                .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36")
+                .followRedirects(true) // 跟随重定向
+                .get();
+
+        // 改进的新闻列表抓取逻辑
+        String content = "";
+        List<String> list = new ArrayList<>();
+        Elements elements = doc.select("p");
+        for (Element element : elements) {
+            String text = element.text();
+            if (StringUtils.isNotEmpty(text)) {
+                list.add(text);
+            }
+        }
+        if (CollectionUtils.isEmpty(list)) {
+            String articleContent = doc.text();
+            list.add(articleContent);
+            content = StringUtils.join(list, "\n");
+        } else {
+            content = StringUtils.join(list, "\n");
+        }
+        return content;
+    }
+
+    public static String extractDate(String input) {
+        if (input == null || input.trim().isEmpty()) {
+            return null;
+        }
+
+        Matcher matcher = DATE_PATTERN.matcher(input);
+        String lastMatch = null;
+
+        // 查找所有匹配项并记录最后一个
+        while (matcher.find()) {
+            lastMatch = matcher.group(1);
+        }
+
+        return lastMatch;
+    }
+}

+ 278 - 0
src/main/java/com/cslg/ppa/service/GetWebArticle/GetWeChatArticleService.java

@@ -0,0 +1,278 @@
+package com.cslg.ppa.service.GetWebArticle;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.cslg.ppa.common.utils.DateUtil;
+import com.cslg.ppa.dto.GetArticleInfoDTO;
+import com.cslg.ppa.entity.ArticleInfo;
+import com.cslg.ppa.entity.SourceInfo;
+import com.cslg.ppa.entity.commom.Article;
+import com.cslg.ppa.entity.commom.WxResultBody;
+import com.cslg.ppa.mapper.SourceInfoMapper;
+import com.cslg.ppa.service.ArticleInfoService;
+import com.cslg.ppa.service.commom.DifyService;
+import com.cslg.ppa.service.commom.WeiXinApi;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class GetWeChatArticleService {
+    @Value("${WeChat.token}")
+    private String token;
+    @Value("${WeChat.cookie}")
+    private String cookie;
+
+    @Autowired
+    private SourceInfoMapper sourceInfoMapper;
+    @Autowired
+    private ArticleInfoService articleInfoService;
+    @Autowired
+    private DifyService difyService;
+
+    @Scheduled(cron = "0 0 4 * * ?")
+    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Throwable.class)
+    public void getWeChatArticle() throws Exception {
+        System.out.println(new Date() + "Wechat-Begin");
+        List<SourceInfo> sourceInfos = sourceInfoMapper.selectList(new LambdaQueryWrapper<SourceInfo>()
+                .eq(SourceInfo::getSourceType, 2));
+        for (SourceInfo sourceInfo : sourceInfos) {
+            final String fakeId = sourceInfo.getFakeId();
+            WxResultBody<List<Article>> findExList = WeiXinApi.findExList(fakeId, token,cookie);
+            List<Article> exList = findExList.getApp_msg_list();
+
+            List<GetArticleInfoDTO> articleInfoDTOS = new ArrayList<>();
+            for (Article article : exList) {
+                String createTimeSecondStr = article.getCreate_time();
+                long secondCreateTime = Long.parseLong(createTimeSecondStr);
+                String createTimeStr = DateUtil.convertTimestamp(secondCreateTime);
+                String yesterdayDateStr = DateUtil.getYesterdayDateStr();
+                if (!StringUtils.equals(createTimeStr, yesterdayDateStr)) {
+                    continue;
+                }
+                Date createTime = new Date();
+                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+                try {
+                    createTime = dateFormat.parse(createTimeStr);
+                } catch (Exception e) {
+                    continue;
+                }
+                String title = article.getTitle();
+                String link = article.getLink();
+                String cover = article.getCover();
+
+                // 检查文章是否已存在
+                ArticleInfo articleInfo = articleInfoService.getOne(new QueryWrapper<ArticleInfo>().lambda().eq(ArticleInfo::getTitle, title));
+                if (ObjectUtils.isNotEmpty(articleInfo)) {
+                    continue; // 文章已存在,跳过
+                }
+
+                //获取公众号内容
+                String weChatArticleContent = null;
+                try {
+                    weChatArticleContent = this.getWeChatArticleContent(link);
+                } catch (Exception e) {
+                    weChatArticleContent = "";
+                }
+                if (StringUtils.isEmpty(weChatArticleContent)) {
+                    continue;
+                }
+                String condensedAbstract = null;
+                try {
+                    condensedAbstract = difyService.getCondensedAbstract(weChatArticleContent);
+                } catch (Exception e) {
+                    continue;
+                }
+                if (StringUtils.isEmpty(condensedAbstract)) {
+                    continue;
+                }
+
+                GetArticleInfoDTO articleInfoDTO = new GetArticleInfoDTO();
+                if (sourceInfo.getSourceName().equals("国专知识产权")) {
+                    articleInfoDTO.setCategoryId(4);
+                } else if (sourceInfo.getSourceName().equals("IPRdaily")) {
+                    articleInfoDTO.setCategoryId(3);
+                } else if (sourceInfo.getSourceName().equals("知识产权界")) {
+                    articleInfoDTO.setCategoryId(5);
+                } else {
+                    articleInfoDTO.setCategoryId(6);
+                }
+                articleInfoDTO.setSourceId(sourceInfo.getId());
+                articleInfoDTO.setArticleUrl(link);
+                articleInfoDTO.setTitle(title);
+                articleInfoDTO.setPublicTime(createTime);
+                articleInfoDTO.setWxArticleIcon(cover);
+                articleInfoDTO.setDigest(condensedAbstract);
+                articleInfoDTOS.add(articleInfoDTO);
+            }
+            articleInfoService.batchAddArticleInfo(articleInfoDTOS);
+        }
+        System.out.println(new Date() + "Wechat-End");
+    }
+
+    public String getWeChatArticleContent(String articleUrl) {
+        String content = "";
+        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+            HttpGet request = new HttpGet(articleUrl);
+            // 设置完整的请求头(关键步骤!)
+            request.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36");
+            request.setHeader("Referer", "https://mp.weixin.qq.com/");
+            request.setHeader("Cookie", cookie);
+
+            //执行请求并处理响应
+            try (CloseableHttpResponse response = httpClient.execute(request)) {
+                final int code = response.getStatusLine().getStatusCode();
+                // 检查响应状态码
+                if (code != 200) {
+                    System.err.println("请求失败,状态码: " + code);
+                    return content;
+                }
+
+                // 4. 解析HTML内容
+                String htmlContent = EntityUtils.toString(response.getEntity(), "UTF-8");
+                Document doc = Jsoup.parse(htmlContent);
+                // 5. 提取文章正文(微信使用特定class)
+                Element contentElement = doc.selectFirst("#js_content");
+                if (contentElement != null) {
+                    List<String> list = new ArrayList<>();
+                    Elements elements = contentElement.select("p");
+                    for (Element element : elements) {
+                        String text = element.text();
+                        if (StringUtils.isNotEmpty(text)) {
+                            list.add(text);
+                        }
+                    }
+                    if (CollectionUtils.isEmpty(list)) {
+                        String articleContent = contentElement.text();
+                        list.add(articleContent);
+                        content = StringUtils.join(list, "\n");
+                    } else {
+                        content = StringUtils.join(list, "\n");
+                    }
+                }
+            }
+        } catch (Exception e) {
+        }
+        return content;
+    }
+
+    public void getWeChatArticleContent1(String articleUrl,Integer categoryId,Integer sourceId) {
+        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+            HttpGet request = new HttpGet(articleUrl);
+            // 设置完整的请求头(关键步骤!)
+            request.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36");
+            request.setHeader("Referer", "https://mp.weixin.qq.com/");
+            request.setHeader("Cookie", cookie);
+
+            //执行请求并处理响应
+            try (CloseableHttpResponse response = httpClient.execute(request)) {
+                final int code = response.getStatusLine().getStatusCode();
+                // 检查响应状态码
+                if (code != 200) {
+                    System.err.println("请求失败,状态码: " + code);
+                }
+
+                // 4. 解析HTML内容
+                String htmlContent = EntityUtils.toString(response.getEntity(), "UTF-8");
+                Document doc = Jsoup.parse(htmlContent);
+                Elements h1 = doc.select("h1");
+                String title = h1.text();
+
+                Elements scripts = doc.select("script");
+                String createTimeStr = "";
+                for (Element script : scripts) {
+                    String scriptContent = script.html();
+                    // 提取 var ct 的值(字符串或数字)
+                    createTimeStr = extractVariable(scriptContent, "ct");
+                    if (StringUtils.isNotEmpty(createTimeStr)) {
+                        break;
+                    }
+                }
+                Date createTime = new Date();
+                if (StringUtils.isNotEmpty(createTimeStr)) {
+                    long secondCreateTime = Long.parseLong(createTimeStr);
+                    String createTimeStr1 = DateUtil.convertTimestamp(secondCreateTime);
+                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+                    try {
+                        createTime = dateFormat.parse(createTimeStr1);
+                    } catch (Exception e) {
+                    }
+                }
+
+
+                // 5. 提取文章正文(微信使用特定class)
+                String content = "";
+                Element contentElement = doc.selectFirst("#js_content");
+                if (contentElement != null) {
+                    List<String> list = new ArrayList<>();
+                    Elements elements = contentElement.select("p");
+                    for (Element element : elements) {
+                        String text = element.text();
+                        if (StringUtils.isNotEmpty(text)) {
+                            list.add(text);
+                        }
+                    }
+                    if (CollectionUtils.isEmpty(list)) {
+                        String articleContent = contentElement.text();
+                        list.add(articleContent);
+                        content = StringUtils.join(list, "\n");
+                    } else {
+                        content = StringUtils.join(list, "\n");
+                    }
+                }
+                String condensedAbstract = difyService.getCondensedAbstract(content);
+                ArticleInfo articleInfo = new ArticleInfo();
+                articleInfo.setTitle(title);
+                articleInfo.setDigest(condensedAbstract);
+                articleInfo.setCategoryId(categoryId);
+                articleInfo.setSourceId(sourceId);
+                articleInfo.setPublicTime(createTime);
+                articleInfo.setArticleUrl(articleUrl);
+                articleInfo.insert();
+            }
+        } catch (Exception e) {
+        }
+
+
+    }
+
+    private static String extractVariable(String scriptContent, String varName) {
+        // 正则表达式匹配变量赋值(支持字符串或数字)
+        Pattern pattern = Pattern.compile(
+                "var\\s+" + varName + "\\s*=\\s*(['\"])?(.*?)\\1\\s*;", // 匹配 var varName = 'value' 或 var varName = 123;
+                Pattern.DOTALL
+        );
+        Matcher matcher = pattern.matcher(scriptContent);
+        if (matcher.find()) {
+            return matcher.group(2).trim(); // 返回捕获的值(第二组)
+        }
+        return null;
+    }
+}

+ 292 - 0
src/main/java/com/cslg/ppa/service/ReportService.java

@@ -0,0 +1,292 @@
+package com.cslg.ppa.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cslg.ppa.common.core.auth.Response;
+import com.cslg.ppa.common.exception.ExceptionEnum;
+import com.cslg.ppa.common.exception.XiaoShiException;
+import com.cslg.ppa.common.utils.FileUtils;
+import com.cslg.ppa.dto.*;
+import com.cslg.ppa.entity.*;
+import com.cslg.ppa.entity.commom.Records;
+import com.cslg.ppa.mapper.AssoReportArticleMapper;
+import com.cslg.ppa.mapper.ReportMapper;
+import com.cslg.ppa.service.commom.FileManagerService;
+import com.cslg.ppa.vo.ExportReportDetailVO;
+import com.cslg.ppa.vo.ExportReportVO;
+import com.cslg.ppa.vo.SelectAssoReportArticleVO;
+import com.cslg.ppa.vo.SelectReportListVO;
+import com.deepoove.poi.XWPFTemplate;
+import com.deepoove.poi.config.Configure;
+import com.deepoove.poi.config.ConfigureBuilder;
+import com.deepoove.poi.plugin.toc.TOCRenderPolicy;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.poi.xwpf.usermodel.*;
+import org.apache.xmlbeans.XmlCursor;
+import org.ddr.poi.html.HtmlRenderPolicy;
+import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor(onConstructor_ = {@Lazy})
+public class ReportService extends ServiceImpl<ReportMapper, Report> {
+
+    @Autowired
+    private ReportTempleService reportTempleService;
+    @Autowired
+    private FileUtils fileUtils;
+    @Autowired
+    private FileManagerService fileManagerService;
+    @Autowired
+    private ReportMapper reportMapper;
+    @Autowired
+    private AssoReportArticleMapper assoReportArticleMapper;
+
+    public String selectReportList(SelectReportListDTO vo) {
+        LambdaQueryWrapper<Report> wrapper = new LambdaQueryWrapper<>();
+        if (StringUtils.isNotEmpty(vo.getReportName())) {
+            wrapper.eq(Report::getReportName, vo.getReportName());
+        }
+        wrapper.orderByDesc(Report::getCreateTime);
+        Page<Report> page = new Page<>(vo.getPageNum(), vo.getPageSize());
+        Page<Report> reportPage = reportMapper.selectPage(page, wrapper);
+        List<Report> reports = reportPage.getRecords();
+        List<SelectReportListVO> reportList = new ArrayList<>();
+        if (!CollectionUtils.isEmpty(reports)) {
+            for (Report report : reports) {
+                SelectReportListVO reportVO = new SelectReportListVO();
+                reportVO.setReportId(report.getId());
+                reportVO.setReportName(report.getReportName());
+                reportVO.setApprove(report.getApprove());
+                reportVO.setCreator(report.getCreator());
+                reportVO.setApproveStatus(report.getApproveStatus());
+                reportVO.setCreateTime(report.getCreateTime());
+                reportVO.setApproveTime(report.getApproveTime());
+                reportList.add(reportVO);
+            }
+        }
+        Records records = new Records();
+        long total = reportPage.getTotal();
+        records.setCurrent(vo.getPageNum());
+        records.setTotal(total);
+        records.setSize(vo.getPageSize());
+        records.setData(reportList);
+        return Response.success(records);
+    }
+
+    public String selectReportDetail(ReportIdDTO vo) {
+        Report report = reportMapper.selectById(vo.getReportId());
+        return Response.success(report);
+    }
+
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
+    public Integer addReport(ReportDTO vo) {
+        String reportName = vo.getReportName();
+        if (StringUtils.isEmpty(reportName)) {
+            throw new XiaoShiException(ExceptionEnum.BUSINESS_ERROR, "报告名称不可为空");
+        }
+        //todo 创建者字段后续再加
+        Report report = new Report();
+        report.setReportName(vo.getReportName());
+        report.insert();
+        List<Integer> articleIds = vo.getArticleIds();
+        if (!CollectionUtils.isEmpty(articleIds)) {
+            for (Integer articleId : articleIds) {
+                Long count = assoReportArticleMapper.selectCount(new LambdaQueryWrapper<AssoReportArticle>()
+                        .eq(AssoReportArticle::getArticleId, articleId)
+                        .eq(AssoReportArticle::getIfUse, 1));
+                if (count > 1) {
+                    continue;
+                }
+                AssoReportArticle assoReportArticle = new AssoReportArticle();
+                assoReportArticle.setReportId(report.getId());
+                assoReportArticle.setArticleId(articleId);
+                assoReportArticle.insert();
+            }
+        }
+        return report.getId();
+    }
+
+    public Integer editReport(ReportDTO vo) {
+        Report report = reportMapper.selectById(vo.getReportId());
+        report.setReportName(vo.getReportName());
+        report.updateById();
+        return report.getId();
+    }
+
+    public void deleteReport(ReportIdDTO vo) {
+        List<Integer> reportIds = vo.getReportIds();
+        if (!CollectionUtils.isEmpty(reportIds)) {
+            for (Integer reportId : reportIds) {
+                //删除关联
+                List<AssoReportArticle> assoReportArticles = assoReportArticleMapper.selectList(new LambdaQueryWrapper<AssoReportArticle>()
+                        .eq(AssoReportArticle::getReportId, reportId));
+                if (!CollectionUtils.isEmpty(assoReportArticles)) {
+                    List<Integer> collect = assoReportArticles.stream().map(BaseEntity::getId).collect(Collectors.toList());
+                    assoReportArticleMapper.deleteBatchIds(collect);
+                }
+                //删除报告
+                reportMapper.deleteById(reportId);
+            }
+        }
+    }
+
+    public List<SelectAssoReportArticleVO> selectAssoReportArticleList(SelectAssoReportArticleDTO vo) {
+        Integer reportId = vo.getReportId();
+        List<SelectAssoReportArticleVO> articleVOS = reportMapper.selectAssoReportArticleList(reportId);
+        if (CollectionUtils.isEmpty(articleVOS)) {
+            articleVOS = new ArrayList<>();
+        }
+        return articleVOS;
+    }
+
+    public Integer addArticleToReport(ReportDTO vo) {
+        //todo 创建者字段后续再加
+        Integer reportId = vo.getReportId();
+        List<Integer> articleIds = vo.getArticleIds();
+        if (!CollectionUtils.isEmpty(articleIds)) {
+            for (Integer articleId : articleIds) {
+                Long count = assoReportArticleMapper.selectCount(new LambdaQueryWrapper<AssoReportArticle>()
+                        .eq(AssoReportArticle::getArticleId, articleId)
+                        .eq(AssoReportArticle::getIfUse, 1));
+                if (count > 1) {
+                    continue;
+                }
+                AssoReportArticle assoReportArticle = new AssoReportArticle();
+                assoReportArticle.setReportId(reportId);
+                assoReportArticle.setArticleId(articleId);
+                assoReportArticle.insert();
+            }
+        }
+        return reportId;
+    }
+
+    public Integer removeAssoArticleReport(AssoReportArticleIdDTO vo) {
+        Integer assoId = vo.getAssoId();
+        AssoReportArticle assoReportArticle = assoReportArticleMapper.selectById(assoId);
+        assoReportArticle.setIfUse(0);
+        assoReportArticle.updateById();
+        return assoId;
+    }
+
+    public String exportReport(Integer reportId) {
+        List<SelectAssoReportArticleVO> articleVOS = reportMapper.selectAssoReportArticleList(reportId);
+        List<ExportReportVO> reportVOS = new ArrayList<>();
+        if (!CollectionUtils.isEmpty(articleVOS)) {
+            Map<String, List<SelectAssoReportArticleVO>> map = articleVOS.stream().collect(Collectors.groupingBy(SelectAssoReportArticleVO::getCategoryName));
+            if (!CollectionUtils.isEmpty(map)) {
+                for (String key : map.keySet()) {
+                    ExportReportVO reportVO = new ExportReportVO();
+                    reportVO.setCategoryName(key);
+                    List<SelectAssoReportArticleVO> reportArticleVOS = map.get(key);
+                    List<ExportReportDetailVO> detailVOS = new ArrayList<>();
+                    if (!CollectionUtils.isEmpty(reportArticleVOS)) {
+                        int i = 1;
+                        for (SelectAssoReportArticleVO reportArticleVO : reportArticleVOS) {
+                            ExportReportDetailVO detailVO = new ExportReportDetailVO();
+                            detailVO.setTitle(i + "、" + reportArticleVO.getTitle());
+                            detailVO.setDigest(reportArticleVO.getDigest());
+                            String htmlLink = "<a href='" + reportArticleVO.getArticleUrl() + "'>" + reportArticleVO.getArticleUrl() + "</a>";
+                            detailVO.setArticle_url(htmlLink);
+                            detailVOS.add(detailVO);
+                            i++;
+                        }
+                    }
+                    reportVO.setDetailVOS(detailVOS);
+                    reportVOS.add(reportVO);
+                }
+            }
+        }
+
+        List<ExportReportDetailVO> list = new ArrayList<>();
+        List<ExportReportDetailVO> list1 = new ArrayList<>();
+        List<ExportReportDetailVO> list2 = new ArrayList<>();
+        List<ExportReportDetailVO> list3 = new ArrayList<>();
+        List<ExportReportDetailVO> list4 = new ArrayList<>();
+        if (!CollectionUtils.isEmpty(reportVOS)) {
+            for (ExportReportVO reportVO : reportVOS) {
+                String categoryName = reportVO.getCategoryName();
+                if (StringUtils.equals(categoryName, "国家知识产权局")) {
+                    list.addAll(reportVO.getDetailVOS());
+                } else if (StringUtils.equals(categoryName, "地方相关法律法规")) {
+                    list1.addAll(reportVO.getDetailVOS());
+                } else if (StringUtils.equals(categoryName, "判例")) {
+                    list2.addAll(reportVO.getDetailVOS());
+                } else if (StringUtils.equals(categoryName, "国外相关资讯")) {
+                    list3.addAll(reportVO.getDetailVOS());
+                } else if (StringUtils.equals(categoryName, "行业资讯")) {
+                    list4.addAll(reportVO.getDetailVOS());
+                }
+            }
+        }
+
+        Map<String, Object> map = new HashMap<>();
+        map.put("country_list", list);
+        map.put("local_list", list1);
+        map.put("case_list", list2);
+        map.put("foreign_list", list3);
+        map.put("business_list", list4);
+        ReportTemple reportTemplate = reportTempleService.getById(1);
+        String templateFilePath = fileUtils.getPath(reportTemplate.getTemplatePath());
+        Report report = this.getById(reportId);
+        String reportName = report.getReportName();
+        //生成文档
+        String fileGuid = null;
+        try {
+            fileGuid = this.generateReportFile(map, templateFilePath, reportName);
+            //todo 后续添加导出记录
+        } catch (Exception e) {
+            throw new XiaoShiException(ExceptionEnum.BUSINESS_ERROR, "导出资讯报告失败");
+        }
+        return fileGuid;
+    }
+
+    public String generateReportFile(Map<String, Object> map, String templateFilePath, String name) throws Exception {
+        XWPFTemplate xwpfTemplate = this.getHtmlTemplate(map, templateFilePath);
+        String fileName = name + ".docx";
+        String directoryName = fileUtils.createDirectory();
+        String outPath = fileUtils.getSavePath(directoryName) + fileName;
+        File file = new File(outPath);
+        // 生成word保存在指定目录
+        xwpfTemplate.writeToFile(outPath);
+        xwpfTemplate.close();
+        List<String> ids = fileManagerService.uploadFileGetGuid2(Collections.singletonList(file));
+        if (CollectionUtils.isEmpty(ids)) {
+            throw new XiaoShiException("保存记录失败");
+        }
+        return ids.get(0);
+    }
+
+    private XWPFTemplate getHtmlTemplate(Map<String, Object> map, String filePath) {
+        XWPFTemplate template = null;
+        try {
+            HtmlRenderPolicy htmlRenderPolicy = new HtmlRenderPolicy();
+            ConfigureBuilder configureBuilder = Configure.builder().useSpringEL(false);
+            configureBuilder.bind("article_url", htmlRenderPolicy);
+            Configure configure = configureBuilder.build();
+            template = XWPFTemplate.compile(filePath, configure).render(map);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new XiaoShiException(ExceptionEnum.BUSINESS_ERROR, "未匹配到模版文件");
+        }
+        return template;
+    }
+
+}

+ 13 - 0
src/main/java/com/cslg/ppa/service/ReportTempleService.java

@@ -0,0 +1,13 @@
+package com.cslg.ppa.service;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cslg.ppa.entity.ReportTemple;
+import com.cslg.ppa.mapper.ReportTempleMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+@Service
+@Slf4j
+public class ReportTempleService extends ServiceImpl<ReportTempleMapper, ReportTemple> {
+
+}

+ 16 - 0
src/main/java/com/cslg/ppa/service/SourceInfoService.java

@@ -0,0 +1,16 @@
+package com.cslg.ppa.service;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cslg.ppa.entity.SourceInfo;
+import com.cslg.ppa.mapper.SourceInfoMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor(onConstructor_ = {@Lazy})
+public class SourceInfoService extends ServiceImpl<SourceInfoMapper, SourceInfo> {
+
+}

+ 56 - 0
src/main/java/com/cslg/ppa/service/commom/DifyService.java

@@ -0,0 +1,56 @@
+package com.cslg.ppa.service.commom;
+
+import com.alibaba.fastjson.JSONObject;
+import com.cslg.ppa.common.utils.DataUtils;
+import com.cslg.ppa.dto.OAMessageDTO;
+import com.google.gson.Gson;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+@RequiredArgsConstructor
+@Slf4j
+@Service
+public class DifyService {
+    @Value("${DIFY.url}")
+    private String url;
+    @Value("${DIFY.getAbstractKey}")
+    private String getAbstractKey;
+
+    public String getCondensedAbstract(String text) throws Exception {
+        Map<String, Object> map = new HashMap<>();
+        map.put("content", text);
+        OAMessageDTO oaMessageDTO = new OAMessageDTO();
+        oaMessageDTO.setInputs(map);
+        oaMessageDTO.setResponseMode("blocking");
+        oaMessageDTO.setUser("1");
+
+        String param = new Gson().toJson(oaMessageDTO);
+        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), param);
+        OkHttpClient client = new OkHttpClient.Builder()
+                .connectTimeout(600, TimeUnit.SECONDS)
+                .writeTimeout(600, TimeUnit.SECONDS)
+                .readTimeout(600, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(url + "workflows/run")
+                .addHeader("Authorization", "Bearer " + getAbstractKey)
+                .post(requestBody)
+                .build();
+        String res = Objects.requireNonNull(client.newCall(request).execute().body()).string();
+        JSONObject jsonObject = JSONObject.parseObject(res);
+        String dataStr = jsonObject.get("data").toString();
+        JSONObject dataObject = JSONObject.parseObject(dataStr);
+        String outPuts = dataObject.get("outputs").toString();
+        JSONObject jsonObject1 = JSONObject.parseObject(outPuts);
+        String content = jsonObject1.get("text").toString();
+        return DataUtils.unicodeDecode(content);
+    }
+}

+ 250 - 0
src/main/java/com/cslg/ppa/service/commom/FileManagerService.java

@@ -0,0 +1,250 @@
+package com.cslg.ppa.service.commom;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.cslg.ppa.dto.FMSDeleteFileDTO;
+import com.cslg.ppa.entity.commom.SystemFile;
+import com.google.gson.Gson;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
+import org.apache.commons.compress.utils.IOUtils;
+import org.apache.commons.io.FileUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.util.FileCopyUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import static cn.hutool.core.io.FileUtil.getMimeType;
+
+/**
+ * Okhttp调用FMS上传文件接口
+ *
+ * @Author xiexiang
+ * @Date 2023/8/10
+ */
+@RequiredArgsConstructor
+@Slf4j
+@Service
+public class FileManagerService {
+    @Value("${FMSUrl}")
+    private String FMSUrl;
+    @Value("${FileSource}")
+    private String FileSource;
+    /**
+     * 调用文件系统上传文件接口
+     *
+     * @param multipartFiles 文件
+     */
+    public String uploadFile(List<MultipartFile> multipartFiles) throws IOException {
+        List<File> files = new ArrayList<>();
+        for (MultipartFile multipartFile : multipartFiles) {
+            File file = new File(multipartFile.getOriginalFilename());
+            FileCopyUtils.copy(multipartFile.getBytes(), file);
+            files.add(file);
+        }
+        MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder()
+                .setType(MultipartBody.FORM);
+        for (File file : files) {
+            //根据文件名获取文件的MIME类型
+            String mimeType = getMimeType(file.getPath());
+            multipartBodyBuilder.addFormDataPart("files", file.getName(), RequestBody.create(MediaType.parse(mimeType), file));
+        }
+        RequestBody requestBody = multipartBodyBuilder
+                .addFormDataPart("sourceId", String.valueOf(FileSource))
+                .build();
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(FMSUrl + "/fileManager/uploadNormalFile")
+                .post(requestBody)
+                .build();
+        Response response = null;
+        response = okHttpClient.newCall(request).execute();
+        // 最后记得删除临时文件
+        for (File file : files) {
+            FileUtils.deleteQuietly(file);
+        }
+        return Objects.requireNonNull(response.body()).string();
+    }
+
+    public List<String> uploadFileGetGuid(List<MultipartFile> multipartFiles) throws IOException {
+        String res = this.uploadFile(multipartFiles);
+        JSONObject jsonObject = JSONObject.parseObject(res);
+        List<String> guids = JSONArray.parseArray(jsonObject.get("data").toString(), String.class);
+        return guids;
+    }
+
+    /**
+     * 调用文件系统取出文件接口(获得文件流)
+     * @param fieldId 文件id
+     */
+    public byte[] downloadSystemFileFromFMS(String fieldId) throws IOException {
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60000, TimeUnit.SECONDS)
+                .writeTimeout(60000, TimeUnit.SECONDS)
+                .readTimeout(60000, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(FMSUrl + "/fileManager/downloadFile?fileId=" + fieldId)
+                .get()
+                .build();
+        return Objects.requireNonNull(okHttpClient.newCall(request).execute().body()).bytes();
+    }
+
+    /**
+     * 调用文件系统获取文件信息接口
+     *
+     * @param fileIds 文件ids
+     */
+    public String getSystemFileFromFMS(List<String> fileIds) throws IOException {
+        String param = new Gson().toJson(fileIds);
+        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), param);
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(FMSUrl + "/fileManager/getFileData")
+                .post(requestBody)
+                .build();
+        return Objects.requireNonNull(okHttpClient.newCall(request).execute().body()).string();
+    }
+
+    /**
+     * 调用文件系统删除文件接口
+     *
+     * @param ids 需要删除的文件ids
+     */
+    public String deleteFileFromFMS(List<String> ids) throws IOException {
+        FMSDeleteFileDTO fmsDeleteFileDTO = new FMSDeleteFileDTO();
+        fmsDeleteFileDTO.setGuids(ids);
+        fmsDeleteFileDTO.setType(2);
+        String param = new Gson().toJson(fmsDeleteFileDTO);
+        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), param);
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(FMSUrl + "/fileManager/deleteSystemFile")
+                .post(requestBody)
+                .build();
+        return Objects.requireNonNull(okHttpClient.newCall(request).execute().body()).string();
+    }
+
+    public String uploadFileWithGuid(File file, String guid) throws IOException {
+        MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder()
+                .setType(MultipartBody.FORM);
+        //根据文件名获取文件的MIME类型
+        String mimeType = getMimeType(file.getPath());
+        multipartBodyBuilder.addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse(mimeType), file));
+        RequestBody requestBody = multipartBodyBuilder
+                .addFormDataPart("sourceId", String.valueOf(FileSource))
+                .addFormDataPart("fileGuid", guid)
+                .build();
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(FMSUrl + "/fileManager/replaceFile")
+                .post(requestBody)
+                .build();
+        Response response = null;
+        response = okHttpClient.newCall(request).execute();
+        // 最后记得删除临时文件
+//        FileUtils.deleteQuietly(file);
+
+        return Objects.requireNonNull(response.body()).string();
+    }
+
+    /**
+     * 调用文件系统上传文件接口
+     */
+    public String uploadFile2(List<File> files) throws IOException {
+
+        MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder()
+                .setType(MultipartBody.FORM);
+        for (File file : files) {
+            //根据文件名获取文件的MIME类型
+            String mimeType = getMimeType(file.getPath());
+            multipartBodyBuilder.addFormDataPart("files", file.getName(), RequestBody.create(MediaType.parse(mimeType), file));
+        }
+        RequestBody requestBody = multipartBodyBuilder
+                .addFormDataPart("sourceId", String.valueOf(FileSource))
+                .build();
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(FMSUrl + "/fileManager/uploadNormalFile")
+                .post(requestBody)
+                .build();
+        Response response = null;
+        response = okHttpClient.newCall(request).execute();
+        // 最后记得删除临时文件
+        for (File file : files) {
+//            FileUtils.deleteQuietly(file);
+        }
+        return Objects.requireNonNull(response.body()).string();
+    }
+
+    public List<String> uploadFileGetGuid2(List<File> files) throws IOException {
+        String res = this.uploadFile2(files);
+        JSONObject jsonObject = JSONObject.parseObject(res);
+        List<String> guids = JSONArray.parseArray(jsonObject.get("data").toString(), String.class);
+        return guids;
+    }
+
+    /**
+     * 调用文件系统获得专利图片的guid
+     *
+     * @param appNo 申请号
+     */
+    public String getPatentPictureGuids(String appNo) throws IOException {
+        OkHttpClient okHttpClient = new OkHttpClient.Builder()
+                .connectTimeout(60, TimeUnit.SECONDS)
+                .writeTimeout(60, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+        Request request = new Request.Builder()
+                .url(FMSUrl + "/fileManager/getPatentPictureGuids?appNo=" + appNo)
+                .get()
+                .build();
+        return Objects.requireNonNull(okHttpClient.newCall(request).execute().body()).string();
+    }
+
+    public  File getTempFileByGuid(String guid)throws IOException{
+        String res = this.getSystemFileFromFMS(Arrays.asList(guid));
+        List<SystemFile> systemFiles = JSONArray.parseArray(res, SystemFile.class);
+        SystemFile systemFile = systemFiles.get(0);
+        String suffix = systemFile.getFileName().substring(systemFile.getFileName().lastIndexOf("."));
+        //调用文件系统取出文件接口,获得文件流
+        byte[] bytes = this.downloadSystemFileFromFMS(guid);
+        //创建临时文件tempFile,并将文件读取到tempFile
+        File tempFile = File.createTempFile(systemFile.getFileName() + "temp", suffix);
+        try (
+                InputStream inputStream = new ByteArrayInputStream(bytes);
+                FileOutputStream outputStream = new FileOutputStream(tempFile);
+        ) {
+            IOUtils.copy(inputStream, outputStream); // 将输入流复制到临时文件
+        }
+        return  tempFile;
+    }
+}

+ 239 - 0
src/main/java/com/cslg/ppa/service/commom/WeiXinApi.java

@@ -0,0 +1,239 @@
+package com.cslg.ppa.service.commom;
+
+
+import com.cslg.ppa.common.core.auth.WxResultStatus;
+import com.cslg.ppa.common.exception.WxApiException;
+import com.cslg.ppa.common.okhttp.MyCookieStore;
+import com.cslg.ppa.common.utils.HttpUtils;
+import com.cslg.ppa.common.utils.JsonUtils;
+import com.cslg.ppa.entity.commom.Article;
+import com.cslg.ppa.entity.commom.BizData;
+import com.cslg.ppa.entity.commom.WxResultBody;
+import com.fasterxml.jackson.core.type.TypeReference;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @Author xiexiang
+ * @Date 2024/7/10
+ */
+public class WeiXinApi {
+
+    /**接口地址**/
+    public static final Map<String, String> URL_MAP = new HashMap<>();
+
+    static {
+        //初始化登录cookie
+        URL_MAP.put("startLogin", "https://mp.weixin.qq.com/cgi-bin/bizlogin?action=startlogin");
+
+        //二维码图片接口
+        URL_MAP.put("getqrcode", "https://mp.weixin.qq.com/cgi-bin/scanloginqrcode");
+
+        //二维码扫描状态接口
+        URL_MAP.put("qrcodeAsk", "https://mp.weixin.qq.com/cgi-bin/scanloginqrcode");
+
+        //扫码确认后,登录接口
+        URL_MAP.put("bizlogin", "https://mp.weixin.qq.com/cgi-bin/bizlogin?action=login");
+
+        //扫码确认后,登录接口
+        URL_MAP.put("searchbiz", "https://mp.weixin.qq.com/cgi-bin/searchbiz");
+
+        //扫码确认后,登录接口
+        URL_MAP.put("findListEx", "https://mp.weixin.qq.com/cgi-bin/appmsg");
+    }
+
+    /**
+     * POST请求开始登录接口,初始化cookie
+     * @param sessionid 时间戳,加两位随机数
+     * @return
+     */
+    public static WxResultBody startLogin(String sessionid) {
+        if (StringUtils.isBlank(sessionid)) {
+            sessionid = "" + System.currentTimeMillis() + (int)(Math.random()*100);
+        }
+
+        Map<String, String> params = new HashMap<>(8);
+        params.put("sessionid", sessionid);
+        params.put("userlang", "zh_CN");
+        params.put("redirect_url", "");
+        params.put("login_type", "3");
+        params.put("token", "");
+        params.put("lang", "zh_CN");
+        params.put("f", "json");
+        params.put("ajax", "1");
+
+        WxResultBody wxResultBody = parseWxResultBody(HttpUtils.doPost(URL_MAP.get("startLogin"), params));
+
+        return wxResultBody;
+    }
+
+    /**
+     * 获取二维码图片 字节输出流
+     * @return
+     */
+    public static InputStream getQRCode() {
+        Map<String, String> params = new HashMap<>(2);
+        params.put("action", "getqrcode");
+        params.put("random", System.currentTimeMillis() + "");
+        InputStream inputStream = HttpUtils.doGetStream(URL_MAP.get("getqrcode"), params);
+
+        return inputStream;
+    }
+
+
+    /**
+     * GET 轮询二维码状态接口
+     * @return
+     */
+    public static WxResultBody askQRCode() {
+        Map<String, String> params = new HashMap<>(5);
+        params.put("action", "ask");
+        params.put("token", "");
+        params.put("lang", "zh_CN");
+        params.put("f", "json");
+        params.put("ajax", "1");
+
+        WxResultBody wxResultBody = parseWxResultBody(HttpUtils.doGet(URL_MAP.get("qrcodeAsk"), params));
+
+        return wxResultBody;
+    }
+
+    /**
+     * 扫码确认后,登录接口
+     * @return
+     */
+    public static WxResultBody bizlogin() {
+        Map<String, String> params = new HashMap<>(10);
+        params.put("userlang", "zh_CN");
+        params.put("redirect_url", "");
+        params.put("cookie_forbidden", "0");
+        params.put("cookie_cleaned", "0");
+        params.put("plugin_used", "0");
+        params.put("login_type", "3");
+        params.put("token", "");
+        params.put("lang", "zh_CN");
+        params.put("f", "json");
+        params.put("ajax", "1");
+
+        WxResultBody wxResultBody = parseWxResultBody(HttpUtils.doPost(URL_MAP.get("bizlogin"), params));
+
+        return wxResultBody;
+    }
+
+
+    /**
+     * 搜索公众号
+     * @return
+     */
+    public static WxResultBody<List<BizData>> searchBiz(String keyword){
+        Map<String, String> params = new HashMap<>(10);
+        params.put("action", "search_biz");
+        params.put("begin", "0");
+        params.put("count", "10");
+        params.put("query", keyword);
+        params.put("token", MyCookieStore.getToken());
+        params.put("lang", "zh_CN");
+        params.put("f", "json");
+        params.put("ajax", "1");
+
+        WxResultBody<List<BizData>> wxResultBody = parseWxResultBody(HttpUtils.doGet(URL_MAP.get("searchbiz"), params),
+                new TypeReference<WxResultBody<List<BizData>>>() {}
+        );
+
+        return wxResultBody;
+    }
+
+    /**
+     * 搜索公众号的文章
+     * @return
+     */
+    public static WxResultBody<List<Article>> findExList(String fakeid){
+        Map<String, String> params = new HashMap<>(10);
+        params.put("action", "list_ex");
+        params.put("begin", "0");
+        params.put("count", "5");
+        params.put("fakeid", fakeid);
+        params.put("token", MyCookieStore.getToken());
+//        params.put("token", "538670236");
+        params.put("type", "9");
+        params.put("query", "");
+        params.put("lang", "zh_CN");
+        params.put("f", "json");
+        params.put("ajax", "1");
+//        System.out.println(HttpUtils.doGet(URL_MAP.get("findListEx"), params));
+        WxResultBody<List<Article>> wxResultBody = parseWxResultBody(HttpUtils.doGet(URL_MAP.get("findListEx"), params),
+                new TypeReference<WxResultBody<List<Article>>>() {}
+        );
+        return wxResultBody;
+    }
+
+    /**
+     * 搜索公众号的文章
+     *
+     * @return
+     */
+    public static WxResultBody<List<Article>> findExList(String fakeid, String token, String cookie) {
+        Map<String, String> params = new HashMap<>(10);
+        params.put("action", "list_ex");
+        params.put("begin", "0");
+        params.put("count", "5");
+        params.put("fakeid", fakeid);
+        params.put("token", token);
+        params.put("type", "9");
+//        long startTime = 1753977600L;
+//        long currentTime = 1754755200L;
+//        String query = String.format("createtime_start:%d&createtime_end:%d", startTime, currentTime);
+//        params.put("query", query);
+        params.put("query", "");
+        params.put("lang", "zh_CN");
+        params.put("f", "json");
+        params.put("ajax", "1");
+//        System.out.println(HttpUtils.doGet(URL_MAP.get("findListEx"), params));
+        WxResultBody<List<Article>> wxResultBody = parseWxResultBody(HttpUtils.doGet(URL_MAP.get("findListEx"), params,cookie),
+                new TypeReference<WxResultBody<List<Article>>>() {
+                }
+        );
+        return wxResultBody;
+    }
+
+
+    /**
+     * 转成java bean
+     * @param jsonRes json结果字符串
+     * @return
+     */
+    public static WxResultBody parseWxResultBody(String jsonRes) {
+        WxResultBody wxResultBody = JsonUtils.jsonToObj(jsonRes, WxResultBody.class);
+
+        checkIsSuccess(wxResultBody);
+
+        return wxResultBody;
+    }
+
+    /**
+     * 转成java bean
+     * @param jsonRes json结果字符串
+     * @return
+     */
+    public static <T> T parseWxResultBody(String jsonRes, TypeReference<T> typeReference) {
+        T wxResultBody = JsonUtils.jsonToObj(jsonRes, typeReference);
+        checkIsSuccess((WxResultBody) wxResultBody);
+        return wxResultBody;
+    }
+
+    public static void checkIsSuccess(WxResultBody wxResultBody) {
+        // 判断是否请求成功
+        if (wxResultBody == null) {
+            throw new WxApiException(WxResultStatus.FAIL_NULL_RES);
+        }
+
+        if (wxResultBody.getBase_resp().getRet() == null
+                || wxResultBody.getBase_resp().getRet() != 0) {
+            throw new WxApiException(WxResultStatus.FAIL_STATUS);
+        }
+    }
+}

+ 41 - 0
src/main/java/com/cslg/ppa/service/commom/XmlParseService.java

@@ -0,0 +1,41 @@
+package com.cslg.ppa.service.commom;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+
+
+@Slf4j
+@Service
+public class XmlParseService {
+    public List<String> xmlParse(String xmlData, String str) {
+        List<String> reStrs = new ArrayList<>();
+        try {
+            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            DocumentBuilder builder = factory.newDocumentBuilder();
+            InputSource src = new InputSource(new StringReader(xmlData));
+            Document doc = builder.parse(src);
+            NodeList recordList = doc.getElementsByTagName(str);
+            for (int i = 0; i < recordList.getLength(); i++) {
+                Node recordNode = recordList.item(i);
+                if (recordNode.getNodeType() == Node.ELEMENT_NODE) {
+                    Element element = (Element) recordNode;
+                    reStrs.add(element.getTextContent());
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return reStrs;
+    }
+}

+ 13 - 0
src/main/java/com/cslg/ppa/vo/ExportReportDetailVO.java

@@ -0,0 +1,13 @@
+package com.cslg.ppa.vo;
+
+import lombok.Data;
+
+@Data
+public class ExportReportDetailVO {
+
+    private String title;
+
+    private String digest;
+
+    private String article_url;
+}

+ 13 - 0
src/main/java/com/cslg/ppa/vo/ExportReportVO.java

@@ -0,0 +1,13 @@
+package com.cslg.ppa.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class ExportReportVO {
+
+    private String categoryName;
+
+    private List<ExportReportDetailVO> detailVOS;
+}

+ 39 - 0
src/main/java/com/cslg/ppa/vo/SelectArticleInfoVO.java

@@ -0,0 +1,39 @@
+package com.cslg.ppa.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+@Data
+public class SelectArticleInfoVO {
+    private Integer articleId;
+
+    private String title;
+
+    private String digest;
+
+    private Integer categoryId;
+
+    private String categoryName;
+
+    private Integer sourceId;
+
+    private String sourceName;
+    
+    private Integer sourceType;
+
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
+    private Date publicTime;
+
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
+    private Date createTime;
+
+    private String articleUrl;
+
+    private String wxArticleIcon;
+
+}

+ 37 - 0
src/main/java/com/cslg/ppa/vo/SelectAssoReportArticleVO.java

@@ -0,0 +1,37 @@
+package com.cslg.ppa.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+@Data
+public class SelectAssoReportArticleVO {
+
+    private Integer assoId;
+
+    private Integer reportId;
+
+    private Integer articleId;
+
+    private String title;
+
+    private String digest;
+
+    private Integer categoryId;
+
+    private String categoryName;
+
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
+    private Date publicTime;
+
+    private String articleUrl;
+
+    private Integer sourceId;
+
+    private Integer sourceType;
+
+    private String sourceName;
+}

+ 29 - 0
src/main/java/com/cslg/ppa/vo/SelectReportListVO.java

@@ -0,0 +1,29 @@
+package com.cslg.ppa.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+@Data
+public class SelectReportListVO {
+
+    private Integer reportId;
+
+    private String reportName;
+
+    private String creator;
+
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
+    private Date createTime;
+
+    private String approve;
+
+    @DateTimeFormat(pattern = "yyyy-MM-dd")
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
+    private Date approveTime;
+
+    private Integer approveStatus;
+}

File diff suppressed because it is too large
+ 72 - 0
src/main/resources/application-dev.yml


+ 43 - 0
src/main/resources/application.yml

@@ -0,0 +1,43 @@
+server:
+  servlet:
+    context-path: /
+  port: 8099
+spring:
+  thymeleaf:
+    cache: false
+    mode: HTML5
+  aop:
+    auto: true
+    proxy-target-class: true
+  application:
+    name: PPA
+  servlet:
+    multipart:
+      max-file-size: 1000MB
+      max-request-size: 1000MB
+  profiles:
+    active: dev
+  jackson:
+    default-property-inclusion: non_null
+    serialization:
+      INDENT_OUTPUT: true
+    date-format: yyyy-MM-dd HH:mm:ss
+    time-zone: Asia/Shanghai
+logging:
+  config: classpath:config/logback-spring.xml
+  level:
+    cn.cslg.ppa.mapper: debug
+mybatis-plus:
+  typeAliasesPackage: cn.cslg.ppa.entity
+  global-config:
+    db-config:
+      id-type: AUTO
+      logic-delete-value: 0
+      logic-not-delete-value: 1
+      update-strategy: ignored
+  configuration:
+    map-underscore-to-camel-case: true
+    cache-enabled: false
+  mapper-locations: classpath:mapper/*.xml
+queueName: emailProd.queue
+

+ 2 - 0
src/main/resources/config/cron.setting

@@ -0,0 +1,2 @@
+[cn.cslg.pas.common.utils]
+BackupUtils.run = 00 03 * * *

+ 110 - 0
src/main/resources/config/logback-spring.xml

@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <contextName>${APP_NAME}</contextName>
+
+    <springProperty name="APP_NAME" scope="context" source="spring.application.name"/>
+    <springProperty name="LOG_FILE" scope="context" source="logging.file" defaultValue="./logs/${APP_NAME}"/>
+    <springProperty name="LOG_POINT_FILE" scope="context" source="logging.file" defaultValue="./logs/point"/>
+    <springProperty name="LOG_MAXFILESIZE" scope="context" source="logback.filesize" defaultValue="50MB"/>
+    <springProperty name="LOG_FILEMAXDAY" scope="context" source="logback.filemaxday" defaultValue="7"/>
+    <springProperty name="ServerIP" scope="context" source="server.address" defaultValue="0.0.0.0"/>
+    <springProperty name="ServerPort" scope="context" source="server.port" defaultValue="0000"/>
+
+    <!-- 彩色日志 -->
+    <!-- 彩色日志依赖的渲染类 -->
+    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
+    <conversionRule conversionWord="wex"
+                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
+    <conversionRule conversionWord="wEx"
+                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
+
+    <!-- 彩色日志格式 -->
+    <property name="CONSOLE_LOG_PATTERN"
+              value="[${APP_NAME}:${ServerIP}:${ServerPort}] [%clr(%X{traceid}){yellow},%clr(%X{X-B3-TraceId}){yellow}] %clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%level){blue} %clr(${PID}){magenta} %clr([%thread]){orange} %clr(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
+    <property name="CONSOLE_LOG_PATTERN_NO_COLOR"
+              value="[${APP_NAME}:${ServerIP}:${ServerPort}] [%X{traceid},%X{X-B3-TraceId}] %d{yyyy-MM-dd HH:mm:ss.SSS} %level ${PID} [%thread] %logger %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
+
+
+    <!-- 控制台日志 -->
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <withJansi>true</withJansi>
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+
+    <!-- 按照每天生成常规日志文件 -->
+    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_FILE}/${APP_NAME}-error.log</file>
+        <!-- 基于时间的分包策略 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_FILE}/${APP_NAME}-error.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <maxFileSize>100MB</maxFileSize>
+            <!--保留时间,单位:天-->
+            <maxHistory>7</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN_NO_COLOR}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+            <MaxFileSize>100MB</MaxFileSize>
+        </triggeringPolicy>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter"><!-- 只打印错误日志 -->
+            <level>ERROR</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 按照每天生成常规日志文件 -->
+    <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_FILE}/${APP_NAME}-info.log</file>
+        <!-- 基于时间的分包策略 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_FILE}/${APP_NAME}-info.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <maxFileSize>100MB</maxFileSize>
+            <!--保留时间,单位:天-->
+            <maxHistory>7</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN_NO_COLOR}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>INFO</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 按照每天生成常规日志文件 -->
+    <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${LOG_FILE}/${APP_NAME}-debug.log</file>
+        <!-- 基于时间的分包策略 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_FILE}/${APP_NAME}-debug.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <maxFileSize>100MB</maxFileSize>
+            <!--保留时间,单位:天-->
+            <maxHistory>7</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN_NO_COLOR}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>DEBUG</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <root level="INFO">
+        <appender-ref ref="STDOUT"/>
+        <appender-ref ref="ERROR"/>
+        <appender-ref ref="INFO"/>
+        <appender-ref ref="DEBUG"/>
+    </root>
+
+</configuration>

二進制
src/main/resources/file/article-export.docx


+ 69 - 0
src/main/resources/mapper/ArticleInfoMapper.xml

@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.cslg.ppa.mapper.ArticleInfoMapper">
+
+    <select id="selectArticleInfoList" resultType="com.cslg.ppa.vo.SelectArticleInfoVO">
+        select ai.id as articleId,
+               ai.title,
+               ai.digest,
+               ai.category_id,
+               ai.source_id,
+               ai.public_time,
+               ai.create_time,
+               ai.article_url,
+               ai.wx_article_icon,
+               ca.name as categoryName,
+               si.source_name,
+               si.source_type
+        from article_info ai
+        left join category ca on ca.id = ai.category_id
+        left join source_info si on si.id = ai.source_id
+        <where>
+            <if test="vo.key != null and vo.key != ''">
+                ai.title like concat('%',#{vo.key},'%')
+            </if>
+            <if test="vo.categoryId != null">
+                and ai.category_id = #{vo.categoryId}
+            </if>
+            <if test="vo.sourceName != null and vo.sourceName != ''">
+                and si.source_name = #{vo.sourceName}
+            </if>
+            <if test="vo.beginTime != null">
+                and ai.public_time &gt;= #{vo.beginTime}
+            </if>
+            <if test="vo.endTime != null">
+                and ai.public_time &lt;= #{vo.endTime}
+            </if>
+        </where>
+        order by ai.public_time desc,ai.id desc
+        <if test="vo.pageNum != null and vo.pageSize != null">
+            limit
+            ${(vo.pageNum -1) * vo.pageSize},${vo.pageSize}
+        </if>
+    </select>
+
+    <select id="selectArticleInfoCount" resultType="java.lang.Long">
+        select count(*)
+        from article_info ai
+        left join category ca on ca.id = ai.category_id
+        left join source_info si on si.id = ai.source_id
+        <where>
+            <if test="vo.key != null and vo.key != ''">
+                ai.title like concat('%',#{vo.key},'%')
+            </if>
+            <if test="vo.categoryId != null">
+                and ai.category_id = #{vo.categoryId}
+            </if>
+            <if test="vo.sourceName != null and vo.sourceName != ''">
+                and si.source_name = #{vo.sourceName}
+            </if>
+            <if test="vo.beginTime != null">
+                and ai.public_time &gt;= #{vo.beginTime}
+            </if>
+            <if test="vo.endTime != null">
+                and ai.public_time &lt;= #{vo.endTime}
+            </if>
+        </where>
+    </select>
+
+</mapper>

+ 25 - 0
src/main/resources/mapper/ReportMapper.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+<mapper namespace="com.cslg.ppa.mapper.ReportMapper">
+
+    <select id="selectAssoReportArticleList" resultType="com.cslg.ppa.vo.SelectAssoReportArticleVO">
+        select ara.id as assoId,
+               ara.report_id,
+               ara.article_id,
+               ai.title,
+               ai.digest,
+               ai.category_id,
+               ca.name as categoryName,
+               ai.public_time,
+               ai.article_url,
+               ai.source_id,
+               si.source_name,
+               si.source_type
+        from asso_report_article ara
+        left join article_info ai on ai.id = ara.article_id
+        left join category ca on ca.id = ai.category_id
+        left join source_info si on si.id = ai.source_id
+        where ara.report_id = #{reportId} and ara.if_use = 1
+        order by ai.public_time desc
+    </select>
+</mapper>

File diff suppressed because it is too large
+ 262 - 0
src/test/java/com/cslg/ppa/PpaApplicationTests.java