liusz 6 mesi fa
parent
commit
e1e905c338
100 ha cambiato i file con 6874 aggiunte e 0 eliminazioni
  1. 196 0
      pom.xml
  2. 9 0
      poyee-admin/README.md
  3. 134 0
      poyee-admin/pom.xml
  4. 26 0
      poyee-admin/src/main/java/com/poyee/AdminApplication.java
  5. 63 0
      poyee-admin/src/main/java/com/poyee/controller/InfoSyncApiController.java
  6. 41 0
      poyee-admin/src/main/java/com/poyee/controller/PromotionOrderController.java
  7. 37 0
      poyee-admin/src/main/java/com/poyee/controller/PromotionShareInfoController.java
  8. 78 0
      poyee-admin/src/main/java/com/poyee/controller/PromotionTaskController.java
  9. 100 0
      poyee-admin/src/main/resources/application-dev.yml
  10. 63 0
      poyee-admin/src/main/resources/application.yml
  11. 107 0
      poyee-admin/src/main/resources/db/migration/V1.1_promotion_task_create.sql
  12. 84 0
      poyee-admin/src/main/resources/db/migration/V1.2_promotion_order_create.sql
  13. 56 0
      poyee-admin/src/main/resources/db/migration/V1.3_promotion_share_info_create.sql
  14. 53 0
      poyee-admin/src/main/resources/db/migration/V1.4_app_expert_info_create.sql
  15. 21 0
      poyee-admin/src/main/resources/logback-fluentd.xml
  16. 42 0
      poyee-admin/src/main/resources/logback.xml
  17. 14 0
      poyee-admin/src/main/resources/mybatis/mybatis-config.xml
  18. 9 0
      poyee-app/README.md
  19. 133 0
      poyee-app/pom.xml
  20. 26 0
      poyee-app/src/main/java/com/poyee/AppApplication.java
  21. 43 0
      poyee-app/src/main/java/com/poyee/controller/AppExpertApiController.java
  22. 71 0
      poyee-app/src/main/java/com/poyee/controller/MinePromotionApiController.java
  23. 65 0
      poyee-app/src/main/java/com/poyee/controller/PromotionShareInfoController.java
  24. 76 0
      poyee-app/src/main/java/com/poyee/controller/TaskApiController.java
  25. 35 0
      poyee-app/src/main/java/com/poyee/param/TaskApiPageReq.java
  26. 101 0
      poyee-app/src/main/resources/application-dev.yml
  27. 64 0
      poyee-app/src/main/resources/application.yml
  28. 21 0
      poyee-app/src/main/resources/logback-fluentd.xml
  29. 42 0
      poyee-app/src/main/resources/logback.xml
  30. 14 0
      poyee-app/src/main/resources/mybatis/mybatis-config.xml
  31. 41 0
      poyee-base/README.md
  32. 207 0
      poyee-base/pom.xml
  33. 14 0
      poyee-base/src/main/java/com/poyee/annotation/DictTypeFormat.java
  34. 11 0
      poyee-base/src/main/java/com/poyee/annotation/IgnoreSwaggerParameter.java
  35. 18 0
      poyee-base/src/main/java/com/poyee/annotation/JsonFormater.java
  36. 19 0
      poyee-base/src/main/java/com/poyee/annotation/JsonMapper.java
  37. 51 0
      poyee-base/src/main/java/com/poyee/annotation/MpjWapper.java
  38. 13 0
      poyee-base/src/main/java/com/poyee/annotation/ReadConverterExpFormat.java
  39. 25 0
      poyee-base/src/main/java/com/poyee/annotation/UserLoginToken.java
  40. 23 0
      poyee-base/src/main/java/com/poyee/annotation/db/CaseWhen.java
  41. 20 0
      poyee-base/src/main/java/com/poyee/annotation/db/Count.java
  42. 18 0
      poyee-base/src/main/java/com/poyee/annotation/db/Join.java
  43. 21 0
      poyee-base/src/main/java/com/poyee/annotation/db/LeftJoin.java
  44. 15 0
      poyee-base/src/main/java/com/poyee/annotation/db/OrderBy.java
  45. 19 0
      poyee-base/src/main/java/com/poyee/annotation/db/RightJoin.java
  46. 21 0
      poyee-base/src/main/java/com/poyee/annotation/db/Select.java
  47. 17 0
      poyee-base/src/main/java/com/poyee/annotation/db/Sum.java
  48. 30 0
      poyee-base/src/main/java/com/poyee/annotation/db/Where.java
  49. 211 0
      poyee-base/src/main/java/com/poyee/aspectj/UserLoginTokenAspect.java
  50. 64 0
      poyee-base/src/main/java/com/poyee/base/controller/BaseController.java
  51. 162 0
      poyee-base/src/main/java/com/poyee/base/dto/AppBaseUser.java
  52. 19 0
      poyee-base/src/main/java/com/poyee/base/dto/BaseDto.java
  53. 44 0
      poyee-base/src/main/java/com/poyee/base/dto/BaseReq.java
  54. 59 0
      poyee-base/src/main/java/com/poyee/base/dto/Page.java
  55. 13 0
      poyee-base/src/main/java/com/poyee/base/dto/Pays.java
  56. 116 0
      poyee-base/src/main/java/com/poyee/base/dto/Result.java
  57. 74 0
      poyee-base/src/main/java/com/poyee/base/dto/UserInfo.java
  58. 42 0
      poyee-base/src/main/java/com/poyee/base/entity/BaseEntity.java
  59. 11 0
      poyee-base/src/main/java/com/poyee/base/mapper/IBaseMapper.java
  60. 182 0
      poyee-base/src/main/java/com/poyee/base/mapper/provider/BaseProvider.java
  61. 29 0
      poyee-base/src/main/java/com/poyee/base/mapper/provider/ErrMessageContent.java
  62. 129 0
      poyee-base/src/main/java/com/poyee/base/mapper/provider/IBaseProvider.java
  63. 27 0
      poyee-base/src/main/java/com/poyee/base/mapper/provider/domain/LeftJoinInfo.java
  64. 120 0
      poyee-base/src/main/java/com/poyee/base/mapper/provider/domain/MPage.java
  65. 16 0
      poyee-base/src/main/java/com/poyee/base/mapper/provider/domain/OrderByInfo.java
  66. 24 0
      poyee-base/src/main/java/com/poyee/base/mapper/provider/domain/TableInfo.java
  67. 35 0
      poyee-base/src/main/java/com/poyee/base/mapper/provider/domain/WhereInfo.java
  68. 112 0
      poyee-base/src/main/java/com/poyee/base/mapper/provider/util/FormatValueUtil.java
  69. 120 0
      poyee-base/src/main/java/com/poyee/base/mapper/provider/util/InsertUtil.java
  70. 67 0
      poyee-base/src/main/java/com/poyee/base/mapper/provider/util/JoinUtil.java
  71. 285 0
      poyee-base/src/main/java/com/poyee/base/mapper/provider/util/SelectUtil.java
  72. 419 0
      poyee-base/src/main/java/com/poyee/base/mapper/provider/util/SqlUtil.java
  73. 63 0
      poyee-base/src/main/java/com/poyee/base/mapper/provider/util/TableInfoUtil.java
  74. 159 0
      poyee-base/src/main/java/com/poyee/base/mapper/provider/util/UpdateUtil.java
  75. 129 0
      poyee-base/src/main/java/com/poyee/base/mapper/provider/util/WhereUtil.java
  76. 14 0
      poyee-base/src/main/java/com/poyee/base/service/BaseService.java
  77. 279 0
      poyee-base/src/main/java/com/poyee/base/service/impl/BaseServiceImpl.java
  78. 14 0
      poyee-base/src/main/java/com/poyee/common/constant/MqConstants.java
  79. 25 0
      poyee-base/src/main/java/com/poyee/common/constant/SystemConstant.java
  80. 40 0
      poyee-base/src/main/java/com/poyee/common/db/EnhanceOtherTemplateEngine.java
  81. 31 0
      poyee-base/src/main/java/com/poyee/common/db/TableInitCustomerUtil.java
  82. 28 0
      poyee-base/src/main/java/com/poyee/common/domain/MpjWrapper.java
  83. 14 0
      poyee-base/src/main/java/com/poyee/common/dto/DataSourceInfo.java
  84. 25 0
      poyee-base/src/main/java/com/poyee/common/dto/DbConfigModal.java
  85. 45 0
      poyee-base/src/main/java/com/poyee/common/dto/TableColumnConfigModal.java
  86. 58 0
      poyee-base/src/main/java/com/poyee/common/dto/TableConfigModal.java
  87. 37 0
      poyee-base/src/main/java/com/poyee/common/exception/BusinessException.java
  88. 37 0
      poyee-base/src/main/java/com/poyee/common/exception/ServiceException.java
  89. 85 0
      poyee-base/src/main/java/com/poyee/common/json/JsonMapperUtil.java
  90. 48 0
      poyee-base/src/main/java/com/poyee/common/knife4j/Knife4jConfig.java
  91. 255 0
      poyee-base/src/main/java/com/poyee/common/knife4j/SwaggerConfig.java
  92. 34 0
      poyee-base/src/main/java/com/poyee/config/JoinSqlInjector.java
  93. 86 0
      poyee-base/src/main/java/com/poyee/config/RedisConfig.java
  94. 216 0
      poyee-base/src/main/java/com/poyee/dataSource/DataSourceConfig.java
  95. 189 0
      poyee-base/src/main/java/com/poyee/dataSource/DynamicDataSource.java
  96. 69 0
      poyee-base/src/main/java/com/poyee/dataSource/MasterDataSourceConfig.java
  97. 30 0
      poyee-base/src/main/java/com/poyee/dataSource/holder/DataSourceContextHolder.java
  98. 24 0
      poyee-base/src/main/java/com/poyee/enums/CaseWhenValueTypeEnums.java
  99. 27 0
      poyee-base/src/main/java/com/poyee/enums/DataAuth.java
  100. 26 0
      poyee-base/src/main/java/com/poyee/enums/DateEnums.java

+ 196 - 0
pom.xml

@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.3.5.RELEASE</version>
+    </parent>
+
+    <groupId>com.poyee</groupId>
+    <artifactId>product-promotion</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    <name>商品推广</name>
+    <description>商品推广</description>
+
+    <properties>
+        <java.version>1.8</java.version>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <springboot.version>2.3.5.RELEASE</springboot.version>
+        <druid.version>1.2.1</druid.version>
+        <oshi.version>5.2.5</oshi.version>
+        <jna.version>5.5.0</jna.version>
+        <commons.io.version>2.5</commons.io.version>
+        <fastjson.version>1.2.74</fastjson.version>
+    </properties>
+    <dependencyManagement>
+        <dependencies>
+            <!-- SpringBoot的依赖配置-->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-web</artifactId>
+                <version>${springboot.version}</version>
+            </dependency>
+            <!-- SpringBoot 拦截器 -->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-aop</artifactId>
+                <version>${springboot.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-validation</artifactId>
+                <version>${springboot.version}</version>
+            </dependency>
+            <!--        热更新-->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-devtools</artifactId>
+                <version>${springboot.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-test</artifactId>
+                <version>${springboot.version}</version>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.mybatis.spring.boot</groupId>
+                <artifactId>mybatis-spring-boot-starter</artifactId>
+                <version>2.3.0</version>
+            </dependency>
+            <!-- knife4j 接口管理 -->
+            <dependency>
+                <groupId>com.github.xiaoymin</groupId>
+                <artifactId>knife4j-spring-boot-starter</artifactId>
+                <version>2.0.9</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.projectlombok</groupId>
+                <artifactId>lombok</artifactId>
+                <version>1.18.12</version>
+                <optional>true</optional>
+            </dependency>
+            <!--阿里数据库连接池 -->
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>druid-spring-boot-starter</artifactId>
+                <version>${druid.version}</version>
+            </dependency>
+            <!-- 获取系统信息 -->
+            <dependency>
+                <groupId>com.github.oshi</groupId>
+                <artifactId>oshi-core</artifactId>
+                <version>${oshi.version}</version>
+            </dependency>
+            <!-- redis 环境 -->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-data-redis</artifactId>
+                <version>2.1.13.RELEASE</version>
+            </dependency>
+            <dependency>
+                <groupId>redis.clients</groupId>
+                <artifactId>jedis</artifactId>
+                <version>3.1.0</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.commons</groupId>
+                <artifactId>commons-pool2</artifactId>
+                <version>2.11.1</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.session</groupId>
+                <artifactId>spring-session-data-redis</artifactId>
+                <version>2.1.13.RELEASE</version>
+            </dependency>
+            <dependency>
+                <groupId>org.redisson</groupId>
+                <artifactId>redisson</artifactId>
+                <version>3.5.0</version>
+            </dependency>
+
+            <dependency>
+                <groupId>net.java.dev.jna</groupId>
+                <artifactId>jna</artifactId>
+                <version>${jna.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>net.java.dev.jna</groupId>
+                <artifactId>jna-platform</artifactId>
+                <version>${jna.version}</version>
+            </dependency>
+            <!--io常用工具类 -->
+            <dependency>
+                <groupId>commons-io</groupId>
+                <artifactId>commons-io</artifactId>
+                <version>${commons.io.version}</version>
+            </dependency>
+            <!-- 阿里JSON解析器 -->
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>fastjson</artifactId>
+                <version>${fastjson.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.apache.commons</groupId>
+                <artifactId>commons-lang3</artifactId>
+                <version> 3.8.1</version>
+            </dependency>
+            <!-- base模块 -->
+            <dependency>
+                <groupId>com.poyee</groupId>
+                <artifactId>poyee-base</artifactId>
+                <version>1.0-SNAPSHOT</version>
+            </dependency>
+            <!--代码生成-->
+            <dependency>
+                <groupId>com.poyee</groupId>
+                <artifactId>poyee-generator</artifactId>
+                <version>1.0-SNAPSHOT</version>
+            </dependency>
+            <dependency>
+                <groupId>com.poyee</groupId>
+                <artifactId>task</artifactId>
+                <version>1.0-SNAPSHOT</version>
+            </dependency>
+            <dependency>
+                <groupId>com.poyee</groupId>
+                <artifactId>system-base</artifactId>
+                <version>1.0-SNAPSHOT</version>
+            </dependency>
+
+        </dependencies>
+    </dependencyManagement>
+
+    <modules>
+        <module>poyee-base</module>
+        <module>poyee-generator</module>
+        <module>poyee-app</module>
+        <module>poyee-admin</module>
+        <module>task</module>
+        <module>system-base</module>
+    </modules>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.1</version>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 9 - 0
poyee-admin/README.md

@@ -0,0 +1,9 @@
+# admin - 商品推广后台管理
+
+> 后台管理接口服务
+
+# 🌟 核心功能
+
+# 🛠️ 开发环境
+
+# 🛠️ 技术架构

+ 134 - 0
poyee-admin/pom.xml

@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.poyee</groupId>
+        <artifactId>product-promotion</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>poyee-admin</artifactId>
+    <name>后台管理</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+        <!--        热更新-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+        </dependency>
+        <!--阿里数据库连接池 -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+            <version>1.2.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-core</artifactId>
+            <version>3.5.2</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
+            <version>3.4.0</version>
+        </dependency>
+        <!--        -->
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <!--logback-->
+        <dependency>
+            <groupId>org.codehaus.janino</groupId>
+            <artifactId>janino</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sndyuk</groupId>
+            <artifactId>logback-more-appenders</artifactId>
+            <version>1.8.5</version>
+        </dependency>
+        <dependency>
+            <groupId>org.fluentd</groupId>
+            <artifactId>fluent-logger</artifactId>
+            <version>0.3.4</version>
+        </dependency>
+
+        <!-- flyway -->
+        <dependency>
+            <groupId>org.flywaydb</groupId>
+            <artifactId>flyway-core</artifactId>
+        </dependency>
+        <!--模块-->
+        <dependency>
+            <groupId>com.poyee</groupId>
+            <artifactId>poyee-base</artifactId>
+        </dependency>
+        <!--推广任务-->
+        <dependency>
+            <groupId>com.poyee</groupId>
+            <artifactId>task</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.poyee</groupId>
+            <artifactId>system-base</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+<!--                <version>2.1.1.RELEASE</version>-->
+                <version>2.3.5.RELEASE</version>
+                <configuration>
+                    <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
+                    <includeSystemScope>true</includeSystemScope>
+                </configuration>
+
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <version>3.0.0</version>
+                <configuration>
+                    <failOnMissingWebXml>false</failOnMissingWebXml>
+                    <warName>${project.artifactId}</warName>
+                </configuration>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+</project>

+ 26 - 0
poyee-admin/src/main/java/com/poyee/AdminApplication.java

@@ -0,0 +1,26 @@
+package com.poyee;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+/**
+ *
+ */
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, SecurityAutoConfiguration.class }
+        , scanBasePackages = {"com.poyee"})
+@EnableAsync
+@EnableAspectJAutoProxy(proxyTargetClass = true)
+@Slf4j
+public class AdminApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(AdminApplication.class, args);
+        log.info("(♥◠‿◠)ノ゙ 启动成功   ლ(´ڡ`ლ)゙");
+    }
+
+}

+ 63 - 0
poyee-admin/src/main/java/com/poyee/controller/InfoSyncApiController.java

@@ -0,0 +1,63 @@
+package com.poyee.controller;
+
+import com.poyee.base.dto.Result;
+import com.poyee.dto.sync.SyncOrderInfoCreateReq;
+import com.poyee.dto.sync.SyncOrderInfoReq;
+import com.poyee.dto.sync.SyncProductInfoReq;
+import com.poyee.service.InfoSyncService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+
+/**
+ * @description: 商品,订单回调通知
+ * @author: lsz
+ * @date: 2025年4月17日
+ */
+@Api(value = "商品,订单 等信息同步",tags = "商品,订单 等信息同步")
+@Slf4j
+@RestController
+@RequestMapping("/api/sync")
+public class InfoSyncApiController  {
+
+    @Autowired
+    private InfoSyncService infoSyncService;
+
+    /**
+     * 商品信息状态更新
+     */
+    @ApiOperation( value = "商品信息状态更新@(notice-1.0)")
+    @RequestMapping(path = "/productStatus",method = RequestMethod.POST)
+    @ResponseBody
+    public Result productStatus(@RequestBody @Valid SyncProductInfoReq req) {
+        log.info("商品信息状态更新");
+        return infoSyncService.productStatus(req);
+    }
+
+    /**
+     * 订单信息创建
+     */
+    @ApiOperation( value = "订单信息创建-新增@(notice-1.0)")
+    @RequestMapping(path = "/createOrder",method = RequestMethod.POST)
+    @ResponseBody
+    public Result createOrder(@RequestBody @Valid SyncOrderInfoCreateReq req) {
+        log.info("订单信息创建-新增");
+        return infoSyncService.createOrder(req);
+    }
+
+    /**
+     * 订单信息状态更新
+     */
+    @ApiOperation( value = "订单信息状态更新@(notice-1.0)")
+    @RequestMapping(path = "/orderStatus",method = RequestMethod.POST)
+    @ResponseBody
+    public Result orderStatus(@RequestBody @Valid SyncOrderInfoReq req) {
+        log.info("订单信息状态更新");
+        return infoSyncService.orderStatus(req);
+    }
+
+}

+ 41 - 0
poyee-admin/src/main/java/com/poyee/controller/PromotionOrderController.java

@@ -0,0 +1,41 @@
+package com.poyee.controller;
+
+import com.poyee.annotation.UserLoginToken;
+import com.poyee.base.controller.BaseController;
+import com.poyee.base.dto.Page;
+import com.poyee.dto.order.PromotionOrderDto;
+import com.poyee.dto.order.PromotionOrderPageDto;
+import com.poyee.dto.order.PromotionOrderPageReq;
+import com.poyee.dto.order.PromotionOrderReq;
+import com.poyee.enums.Roles;
+import com.poyee.service.IPromotionOrderService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author lsz
+ * @since 2025-04-16
+ */
+@Api(tags = "推广订单")
+@Slf4j
+@RestController
+@RequestMapping("/poyee/promotionOrder")
+public class PromotionOrderController extends BaseController<IPromotionOrderService, PromotionOrderReq, PromotionOrderDto> {
+
+    //列表
+    @ApiOperation(value = "列表@(admin-1.0)")
+    @RequestMapping(path = "/page",method = {RequestMethod.POST})
+    @UserLoginToken(faceVerify = false, roles = {Roles.ADMIN,Roles.SHIPPING})
+    @ResponseBody
+    public Page<PromotionOrderPageDto> page(@RequestBody PromotionOrderPageReq req) {
+        return baseService.page(req);
+    }
+
+
+}

+ 37 - 0
poyee-admin/src/main/java/com/poyee/controller/PromotionShareInfoController.java

@@ -0,0 +1,37 @@
+package com.poyee.controller;
+
+import com.poyee.annotation.UserLoginToken;
+import com.poyee.base.controller.BaseController;
+import com.poyee.base.dto.Page;
+import com.poyee.dto.share.*;
+import com.poyee.enums.Roles;
+import com.poyee.service.IPromotionShareInfoService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author lsz
+ * @since 2025-04-16
+ */
+@Slf4j
+@Api(tags = "推广分享信息")
+@RestController
+@RequestMapping("/poyee/promotionShareInfo")
+public class PromotionShareInfoController extends BaseController<IPromotionShareInfoService, PromotionShareInfoReq, PromotionShareInfoDto> {
+
+    @ApiOperation(value = "列表@(admin-1.0)")
+    @RequestMapping(path = "/page",method = {RequestMethod.POST})
+    @UserLoginToken(faceVerify = false, roles = {Roles.ADMIN})
+    @ResponseBody
+    public Page<PromotionShareInfoPageDto> page(@RequestBody PromotionShareInfoPageReq req) {
+        return baseService.page(req);
+    }
+
+
+}

+ 78 - 0
poyee-admin/src/main/java/com/poyee/controller/PromotionTaskController.java

@@ -0,0 +1,78 @@
+package com.poyee.controller;
+
+import com.poyee.annotation.UserLoginToken;
+import com.poyee.base.controller.BaseController;
+import com.poyee.base.dto.Page;
+import com.poyee.base.dto.Result;
+import com.poyee.dto.task.PromotionTaskDto;
+import com.poyee.dto.task.PromotionTaskPageDto;
+import com.poyee.dto.task.*;
+import com.poyee.enums.Roles;
+import com.poyee.service.IPromotionTaskService;
+import io.swagger.annotations.*;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author lsz
+ * @since 2025-04-08
+ */
+@Api(value = "推广任务", tags = "推广任务" )
+@Slf4j
+@RestController
+@RequestMapping("/poyee/promotionTask")
+public class PromotionTaskController extends BaseController<IPromotionTaskService, PromotionTaskReq, PromotionTaskDto> {
+
+    /**
+     * 列表
+     * @param req
+     * @return
+     */
+    @ApiOperation(value = "列表@(admin-1.0)")
+    @RequestMapping(value = "/page", method = {RequestMethod.POST})
+    @UserLoginToken(faceVerify = false, roles = {Roles.ADMIN,Roles.SHIPPING})
+    @ResponseBody
+    public Page<PromotionTaskPageDto> page(@RequestBody PromotionTaskPageReq req) {
+       return baseService.page(req);
+    }
+
+    /**
+     * 创建任务
+     */
+    @ApiOperation(value = "创建任务@(admin-1.0)")
+    @RequestMapping(value = "/create", method = {RequestMethod.POST})
+    @UserLoginToken(faceVerify = false, roles = {Roles.ADMIN,Roles.SHIPPING})
+    @ResponseBody
+    public Result create(@RequestBody @Valid PromotionTaskCreateReq req) {
+        return baseService.create(req);
+    }
+
+    /**
+     * 任务审核
+     */
+    @ApiOperation(value = "任务审核@(admin-1.0)")
+    @RequestMapping(value = "/audit", method = {RequestMethod.POST})
+    @UserLoginToken(faceVerify = false, roles = {Roles.ADMIN,Roles.SHIPPING})
+    @ResponseBody
+    public Result audit(@RequestBody @Valid PromotionTaskAuditReq req) {
+        return baseService.audit(req);
+    }
+
+    /**
+     * 任务发布
+     */
+    @ApiOperation(value = "任务状态更新@(admin-1.0)")
+    @RequestMapping(value = "/updateStatus", method = {RequestMethod.POST})
+    @UserLoginToken(faceVerify = false, roles = {Roles.ADMIN,Roles.SHIPPING})
+    @ResponseBody
+    public Result updateStatus(@RequestBody @Valid PromotionTaskUpdateReq req) {
+        return baseService.updateStatus(req);
+    }
+
+}

+ 100 - 0
poyee-admin/src/main/resources/application-dev.yml

@@ -0,0 +1,100 @@
+spring:
+  datasource:
+    dynamic:
+      primary: master
+      datasource:
+        master:
+          type: com.alibaba.druid.pool.DruidDataSource
+          driver-class-name: org.postgresql.Driver
+          url: jdbc:postgresql://m2-dev.hobbystocks.cn:5432/tzy_system
+          username: postgres
+          password: 123456
+        slave:
+          type: com.alibaba.druid.pool.DruidDataSource
+          driver-class-name: org.postgresql.Driver
+          url: jdbc:postgresql://localhost:5432/py_test
+          username: postgres
+          password: 123456
+        slave1:
+          type: com.alibaba.druid.pool.DruidDataSource
+          driver-class-name: org.postgresql.Driver
+          url: jdbc:postgresql://pgm-uf69k761dcw5icggdo.pg.rds.aliyuncs.com/hobby_stocks
+          username: hobbystocks
+          password: Pass2010
+        slave2:
+          type: com.alibaba.druid.pool.DruidDataSource
+          driver-class-name: org.postgresql.Driver
+          url: jdbc:postgresql://localhost:5432/tzy_system
+          username: postgres
+          password: 123456
+    druid:
+      # 初始连接数
+      initialSize: 5
+      # 最小连接池数量
+      minIdle: 10
+      # 最大连接池数量
+      maxActive: 20
+      # 配置获取连接等待超时的时间
+      maxWait: 60000
+  redis:
+    database: 1
+    host: 192.168.207.128
+    port: 6379
+    password: #Pass2021    # 密码(默认为空)
+    timeout: 15000  # 连接超时时长(毫秒)
+    pool:
+      max-active: 1000  # 连接池最大连接数(使用负值表示没有限制)
+      max-wait: -1ms    # 连接池最大阻塞等待时间(使用负值表示没有限制)
+      max-idle: 10      # 连接池中的最大空闲连接
+      min-idle: 5       # 连接池中的最小空闲连接
+  #mq
+  rabbitmq:
+    host: 192.168.207.128
+    port: 5672
+    username: guest
+    password: guest
+    #    host: ${SPRING_RABBITMQ_HOST:m2-dev.hobbystocks.cn}
+    #    port: ${SPRING_RABBITMQ_PORT:5672}
+    #    username: ${SPRING_RABBITMQ_USERNAME:admin}
+    #    password: ${SPRING_RABBITMQ_PASSWORD:admin}
+    #确认消息已发送到交换机(Exchange)
+    publisher-confirms: true
+    #确认消息已发送到队列(Queue)
+    publisher-returns: true
+    template:
+      retry:
+        enabled: true
+      mandatory: true
+    listener:
+      simple:
+        acknowledge-mode: manual
+        #并发消费者初始化值
+        #concurrency: 10
+        #并发消费者的最大值
+        #max-concurrency: 20
+        #每个消费者每次监听时可拉取处理的消息数量
+        prefetch: 5
+      direct:
+        retry:
+          enabled: true
+          max-attempts: 1
+
+mybatis-plus:
+  configuration:
+    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+    map-underscore-to-camel-case: true
+  global-config:
+    db-config:
+      column-underline: false
+
+# knife4j 配置
+knife4j:
+  # 是否开启 knife4j
+  enabled: true
+  #生产模式屏蔽
+  production: true
+  basic: #是否需要登录
+    enable: true
+    username: admin
+    password: 123456
+

+ 63 - 0
poyee-admin/src/main/resources/application.yml

@@ -0,0 +1,63 @@
+poyee:
+  name: 推广
+  version: 1.0.0
+  active-db: slave
+  holiday-db: slave2
+  api-version: admin-1.0
+
+spring:
+  application:
+    name:
+  profiles:
+    active: dev
+  #flyway
+  flyway:
+    # 是否启用flyway
+    enabled: true
+    # 指定表
+    table: flyway_schema_history_pp_admin
+    # 禁止清理数据库表
+    clean-disabled: true
+    # 编码格式,默认UTF-8
+    encoding: UTF-8
+    # 迁移sql脚本文件存放路径,默认db/migration
+    locations: classpath:db/migration
+    # 迁移sql脚本文件名称的前缀,默认V
+    sql-migration-prefix: V
+    # 迁移sql脚本文件名称的分隔符,默认2个下划线__
+    sql-migration-separator: _
+    # 迁移sql脚本文件名称的后缀
+    sql-migration-suffixes: .sql
+    # 迁移时是否进行校验,默认true
+    validate-on-migrate: true
+    # 当迁移发现数据库非空且存在没有元数据的表时,自动执行基准迁移,新建schema_version表
+    baseline-on-migrate: true
+    url: ${DB_URL:jdbc:postgresql://localhost:5432/py_test}
+    user: ${DB_USERNAME:postgres}
+    password: ${DB_PASSWORD:123456}
+  jackson:
+    date-format: yyyy-MM-dd HH:mm:ss
+server:
+  port: 8099
+
+# MyBatis
+mybatis:
+  # 搜索指定包别名
+  typeAliasesPackage: com.ibox.**.entity,com.poyee.**.dto,com.ibox.**.req,com.ibox.entity,com.ibox.dto,com.ibox.dto.req
+  # 配置mapper的扫描,找到所有的mapper.xml映射文件
+  mapperLocations: '' #classpath*:mapper/**/*Mapper.xml
+  # 加载全局的配置文件
+  configLocation: classpath:mybatis/mybatis-config.xml
+
+
+#logback
+logging:
+  console.enabled: ${CONSOLE_ENABLED:true}
+  file.enabled: ${FILE_ENABLED:false}
+  level:
+    com.poyee: debug
+    org.springframework: warn
+  fluentd:
+    enabled: ${FLUENTD_ENABLED:false}
+    host: ${FLUENTD_HOST:127.0.0.1}
+    port: ${FLUENTD_PORT:24225}

+ 107 - 0
poyee-admin/src/main/resources/db/migration/V1.1_promotion_task_create.sql

@@ -0,0 +1,107 @@
+-- 商品推广任务表
+create table if not exists promotion_task (
+    id serial primary key, -- 主键,自增
+    user_id int8 not null ,-- 用户ID
+    appid varchar(255) not null , -- 来源平台应用ID
+    source_platform varchar(50) not null default 'HS' , -- 来源平台
+    merchant_id int8 not null, -- 商家ID
+    merchant_name varchar(255) , -- 商家名称
+    type varchar(50) not null , -- 商品类型
+    product_id varchar(50) not null , -- 商品ID
+    name text not null , -- 拼团/商品名称
+    code varchar(255) not null , -- 拼团/商品编码,唯一
+    img text, -- 拼团/商品图片URL
+    link text ,--下单连接
+    specification varchar(255), -- 规格
+    play_method varchar(255), -- 玩法
+    group_progress varchar(255), -- 拼团进度 sold/total ,避免除零错误
+    min_price numeric(10,2) not null default 0, -- 商品单价-min
+    max_price numeric(10,2) not null default 0, -- 商品单价-max
+    product_status varchar(50) not null default 'available' , -- 商品状态
+    status char(1) not null default 'C' , -- 推广任务状态:已创建待自审、待发布、已发布、已结束、已下架
+    expert_level varchar(50) ,-- 指定达人等级 A:高级,B:中级,C:初级
+    promotion_platform varchar(50) not null default 'all' ,--推广指定平台 all:全部,wx:微信,dy:抖音,rb:快手, xhs:小红书
+    activity_type varchar(50) , -- 是否参与活动及活动类型 coupon: 优惠券
+    activity_id int8 ,-- 活动id
+    promotion_type varchar(50) , -- 推广类型
+    publish_time timestamp  , -- 发布时间
+    promotion_start_time timestamp  , -- 推广开始时间
+    promotion_end_time timestamp , -- 推广结束时间
+    total_quantity int8 not null , -- 总量[数量]
+    frozen_quantity int8 default 0, -- 冻结中[数量]
+    settlement_quantity int8 default 0, -- 已结算【数量】
+    promotion_price numeric(10, 2) , -- 推广价格
+    promotion_count bigint default 0, -- 推广总量
+    promotion_sales bigint default 0, -- 已销售数量
+    remark text, -- 推广备注
+    commission_ratio int2 default 0, -- 佣金比例 10% => 10
+    total_commission_min numeric(10, 2) default 0, -- 预估总佣金【金额】单价区间*数量*佣金比例
+    total_commission_max numeric(10, 2) default 0, -- 预估总佣金【金额】单价区间*数量*佣金比例
+    del_flg char(1) default 'N', -- 删除标志,默认N
+    prop1 text,
+    prop2 text,
+    prop3 text,
+    prop4 text,
+    create_time timestamp default current_timestamp, -- 创建时间,默认当前时间
+    create_by varchar(255) ,-- 创建人
+    update_time timestamp default current_timestamp, -- 更新时间,自动更新
+    update_by varchar(255) -- 更新人
+);
+
+-- 添加索引以优化查询性能
+create index if not exists pp_task_user_id on promotion_task (user_id); -- 用户ID索引
+create index if not exists pp_task_product_id on promotion_task (product_id); -- 商品ID索引
+create index if not exists pp_task_merchant_id on promotion_task (merchant_id); -- 商家ID索引
+create index if not exists pp_task_type on promotion_task (type); -- 商品类型索引
+create index if not exists pp_task_product_code on promotion_task (code); -- 商品编码索引
+create index if not exists pp_task_product_status on promotion_task (product_status); -- 商品状态索引
+create index if not exists pp_task_status on promotion_task (status); -- 推广任务状态索引
+create index if not exists pp_task_promotion_time_range on promotion_task (promotion_start_time, promotion_end_time); -- 时间范围复合索引
+create index if not exists pp_task_merchant_promotion_status on promotion_task (merchant_id, status); -- 商家与任务状态复合索引
+create index if not exists pp_task_merchant_name on promotion_task (merchant_name); -- 商家名称索引
+
+-- 添加表级别注释
+comment on table promotion_task is '商品推广任务表,记录商品的推广信息及状态';
+
+comment on column promotion_task.id is '主键,自增';
+comment on column promotion_task.user_id is '用户ID';
+comment on column promotion_task.appid is '来源平台应用ID';
+comment on column promotion_task.source_platform is '来源平台';
+comment on column promotion_task.merchant_id is '商家ID';
+comment on column promotion_task.merchant_name is '商家名称';
+comment on column promotion_task.product_id is '商品ID';
+comment on column promotion_task.name is '商品名称';
+comment on column promotion_task.img is '商品图片URL';
+comment on column promotion_task.type is '商品类型:group(拼团),shop(商城)';
+comment on column promotion_task.code is '商品编码,唯一';
+comment on column promotion_task.link is '下单连接';
+comment on column promotion_task.min_price is '商品单价-min';
+comment on column promotion_task.max_price is '商品单价-max';
+comment on column promotion_task.specification is '规格';
+comment on column promotion_task.play_method is '玩法';
+comment on column promotion_task.group_progress is '拼团进度 sold/total ,避免除零错误';
+comment on column promotion_task.product_status is '商品状态(available: 可用, unavailable: 不可用, sold_out: 售罄)';
+comment on column promotion_task.status is '推广任务状态: C(已创建待自审), P(待发布), R(已发布), E(已结束), D(已下架), B(驳回)';
+comment on column promotion_task.expert_level is '指定达人等级 A:高级,B:中级,C:初级';
+comment on column promotion_task.promotion_platform is '指定平台 all:全部,wx:微信,dy:抖音,rb:快手, xhs:小红书';
+comment on column promotion_task.activity_type is '是否参与活动及活动类型 coupon: 优惠券';
+comment on column promotion_task.activity_id is '活动id';
+comment on column promotion_task.promotion_start_time is '推广开始时间';
+comment on column promotion_task.promotion_end_time is '推广结束时间';
+comment on column promotion_task.promotion_price is '推广价格';
+comment on column promotion_task.promotion_type is '推广类型';
+comment on column promotion_task.promotion_sales is '已销售数量';
+comment on column promotion_task.promotion_count is '推广总量';
+comment on column promotion_task.remark is '推广备注(玩法说明等)';
+comment on column promotion_task.commission_ratio is '佣金比例(扩展字段,用于计算预估总佣金)';
+comment on column promotion_task.total_commission_min is '预估总佣金-min';
+comment on column promotion_task.total_commission_max is '预估总佣金-max';
+comment on column promotion_task.total_quantity is '总量';
+comment on column promotion_task.frozen_quantity is '冻结中';
+comment on column promotion_task.settlement_quantity is '已结算';
+comment on column promotion_task.publish_time is '发布时间';
+comment on column promotion_task.del_flg is '删除标志,默认N';
+comment on column promotion_task.create_time is '创建时间,默认当前时间';
+comment on column promotion_task.update_time is '更新时间,自动更新';
+comment on column promotion_task.create_by is '创建人';
+comment on column promotion_task.update_by is '更新人';

+ 84 - 0
poyee-admin/src/main/resources/db/migration/V1.2_promotion_order_create.sql

@@ -0,0 +1,84 @@
+create table if not exists promotion_order
+(
+    id serial primary key, -- 主键,自增
+    appid varchar(255) not null ,-- 来源平台应用ID
+    source_platform varchar(50) not null default 'HS' , -- 来源平台
+    share_link_id int8 not null ,--分享连接id
+    user_id int8 not null , -- 用户id
+    task_id int8 not null, -- 任务id
+    type varchar(10) not null , -- 商品类型:shop 商品,group 拼团
+    status int4 not null , -- 状态:1 已付款,2 已收货,3 已结算,4 已失效
+    product_order_id varchar(50) not null , -- 平台商品订单id
+    buyer_id varchar(50) not null , -- 买家id
+    product_id varchar(50) not null , -- 平台商品id
+    product_status int4 ,-- 平台商品或拼团状态 201 进行中, 301 团卡完成+待申请打款or待打款  202 团卡超时、999 锁定/下架
+    product_order_status int4 not null , -- 平台订单状态:101 已支付 、103 待发货、104 已发货 301 订单完成、302 订单已结束 204 退款中、205 退款完成、206 退款失败
+    order_amount numeric(10,2) not null ,-- 订单金额
+    pay_amount numeric(10,2) not null ,-- 支付金额
+    pay_time timestamp not null ,-- 支付时间
+    receive_time timestamp not null ,-- 收货时间
+    is_coupon boolean not null ,-- 是否用优惠券
+    coupon_amount numeric(10,2) not null ,-- 优惠金额
+    is_promotion_coupon boolean not null ,-- 是否推广优惠券
+    commission_amount numeric(10,2) not null ,-- 佣金金额
+    is_settlement boolean not null ,-- 是否提现
+    settlement_amount numeric(10,2) not null ,-- 结算金额
+    settlement_time timestamp not null ,-- 结算时间
+    service_charge numeric(10,2) not null ,-- 服务费
+    tax_amount numeric(10,2) not null ,-- 税费
+    del_flg char(1) default 'N', -- 删除标志,默认N
+    remark text, -- 备注
+    prop1 text,
+    prop2 text,
+    prop3 text,
+    prop4 text,
+    create_time timestamp not null default current_timestamp, -- 创建时间,默认当前时间
+    update_time timestamp not null default current_timestamp -- 更新时间,默认当前时间
+);
+-- 添加索引以优化查询性能
+create index if not exists pp_order_user_id on promotion_order(user_id);
+create index if not exists pp_order_task_id on promotion_order(task_id);
+create index if not exists pp_order_share_link_id on promotion_order(share_link_id);
+create index if not exists pp_order_product_order_id on promotion_order(product_order_id);
+create index if not exists pp_order_buyer_id on promotion_order(buyer_id);
+create index if not exists pp_order_status on promotion_order(status);
+create index if not exists pp_order_settlement_time on promotion_order(settlement_time);
+
+--添加表注释
+comment on table promotion_order is '商品推广订单表';
+
+-- 添加字段注释
+comment on column promotion_order.id is '主键,自增';
+comment on column promotion_order.appid is '来源平台应用ID';
+comment on column promotion_order.source_platform is '来源平台,默认为 ''HS''';
+comment on column promotion_order.share_link_id is '分享连接id';
+comment on column promotion_order.user_id is '用户ID';
+comment on column promotion_order.task_id is '任务ID';
+comment on column promotion_order.type is '商品类型:shop 商品,group 拼团';
+comment on column promotion_order.status is '状态:1 已付款,2 已收货,3 已结算,4 已失效';
+comment on column promotion_order.product_order_id is '平台商品订单ID';
+comment on column promotion_order.buyer_id is '买家ID';
+comment on column promotion_order.product_id is '平台商品ID';
+comment on column promotion_order.product_status is '平台商品或拼团状态:201 进行中, 301 团卡完成+待申请打款or待打款, 202 团卡超时、999 锁定/下架';
+comment on column promotion_order.product_order_status is '平台订单状态:101 已支付 、103 待发货、104 已发货 301 订单完成、302 订单已结束 204 退款中、205 退款完成、206 退款失败';
+comment on column promotion_order.order_amount is '订单金额';
+comment on column promotion_order.pay_amount is '支付金额';
+comment on column promotion_order.pay_time is '支付时间';
+comment on column promotion_order.receive_time is '收货时间';
+comment on column promotion_order.is_coupon is '是否使用优惠券';
+comment on column promotion_order.coupon_amount is '优惠金额';
+comment on column promotion_order.is_promotion_coupon is '是否推广优惠券';
+comment on column promotion_order.commission_amount is '佣金金额';
+comment on column promotion_order.is_settlement is '是否提现';
+comment on column promotion_order.settlement_amount is '结算金额';
+comment on column promotion_order.settlement_time is '结算时间';
+comment on column promotion_order.service_charge is '服务费';
+comment on column promotion_order.tax_amount is '税费';
+comment on column promotion_order.del_flg is '删除标志,默认N';
+comment on column promotion_order.remark is '备注';
+comment on column promotion_order.prop1 is '预留字段1(需明确用途)';
+comment on column promotion_order.prop2 is '预留字段2(需明确用途)';
+comment on column promotion_order.prop3 is '预留字段3(需明确用途)';
+comment on column promotion_order.prop4 is '预留字段4(需明确用途)';
+comment on column promotion_order.create_time is '创建时间,默认当前时间';
+comment on column promotion_order.update_time is '更新时间,默认当前时间';

+ 56 - 0
poyee-admin/src/main/resources/db/migration/V1.3_promotion_share_info_create.sql

@@ -0,0 +1,56 @@
+create table if not exists promotion_share_info (
+    id serial primary key, -- 主键,自动递增
+    appid varchar(255) not null,
+    source_platform varchar(32) not null default 'HS',
+    user_id int8 not null,
+    task_id int8 not null,
+    product_type varchar(32) not null,
+    product_id varchar(32) not null,
+    share_url text not null,
+    share_code varchar(32) not null,
+    content text not null,
+    share_times int not null default 0,
+    share_image text not null,
+    activity_type varchar(50) , -- 是否参与活动及活动类型 coupon: 优惠券
+    activity_id int8 ,-- 活动id
+    promotion_platform varchar(32) not null default 'all',
+    click_times int not null default 0, -- 设置默认值
+    order_times int not null default 0, -- 设置默认值
+    share_status varchar(32) not null,
+    del_flg char(1) not null default 'N', -- 默认值为'N'
+    create_time timestamp not null default current_timestamp, -- 带时区的时间戳
+    update_time timestamp not null default current_timestamp -- 带时区的时间戳
+);
+
+-- 为常用查询字段创建索引
+create index if not exists pp_share_user_id on promotion_share_info(user_id);
+create index if not exists pp_share_task_id on promotion_share_info(task_id);
+create index if not exists pp_share_product_id on promotion_share_info(product_id);
+create index if not exists pp_share_del_flg on promotion_share_info(del_flg);
+
+-- 添加表注释
+comment on table promotion_share_info is '推广分享信息表';
+
+-- 添加字段注释
+comment on column promotion_share_info.id is '主键,唯一标识每条记录';
+comment on column promotion_share_info.appid is '应用程序ID';
+comment on column promotion_share_info.source_platform is '来源平台:HS';
+comment on column promotion_share_info.user_id is '用户ID';
+comment on column promotion_share_info.task_id is '任务ID';
+comment on column promotion_share_info.product_type is '商品类型:group:拼团,shop:商品';
+comment on column promotion_share_info.product_id is '商品ID';
+comment on column promotion_share_info.share_url is '分享链接';
+comment on column promotion_share_info.share_code is '分享口令';
+comment on column promotion_share_info.content is '分享内容';
+comment on column promotion_share_info.share_times is '分享次数,默认为0';
+comment on column promotion_share_info.share_image is '分享图片链接,最大长度2048字符';
+comment on column promotion_share_info.activity_type is '是否参与活动及活动类型 coupon: 优惠券';
+comment on column promotion_share_info.activity_id is '活动id';
+comment on column promotion_share_info.activity_id is '活动ID';
+comment on column promotion_share_info.promotion_platform is '指定平台 all:全部,wx:微信,dy:抖音,rb:快手, xhs:小红书';
+comment on column promotion_share_info.click_times is '点击次数,默认为0';
+comment on column promotion_share_info.order_times is '下单次数,默认为0';
+comment on column promotion_share_info.share_status is '分享连接状态';
+comment on column promotion_share_info.del_flg is '删除标记,N表示未删除,Y表示已删除';
+comment on column promotion_share_info.create_time is '创建时间';
+comment on column promotion_share_info.update_time is '更新时间';

+ 53 - 0
poyee-admin/src/main/resources/db/migration/V1.4_app_expert_info_create.sql

@@ -0,0 +1,53 @@
+-- 达人信息包括:用户id,达人等级,达人昵称,达人简介,达人头像,达人积分,成为达人时间,达人状态,
+-- 达人粉丝数,达人关注数,达人成功订单数,达人推广数,达人推广产品标签
+CREATE TABLE IF NOT EXISTS app_expert_info (
+    id serial PRIMARY KEY,
+    user_id int8 NOT NULL,
+    level varchar(16) NOT NULL default 'C' ,
+    nickname VARCHAR(50) ,
+    intro TEXT,
+    avatar VARCHAR(1025),
+    points INT NOT NULL DEFAULT 0,
+    status VARCHAR(10) NOT NULL DEFAULT 'normal',
+    follower_count INT NOT NULL DEFAULT 0,
+    following_count INT NOT NULL DEFAULT 0,
+    successful_orders INT NOT NULL DEFAULT 0,
+    promotions INT NOT NULL DEFAULT 0,
+    product_tags TEXT,
+    prop1 TEXT,
+    prop2 TEXT,
+    prop3 TEXT,
+    prop4 TEXT,
+    create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_by VARCHAR(50),
+    update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+--添加user_id, level ,status 索引
+CREATE INDEX IF NOT EXISTS idx_a_e_i_user_id ON app_expert_info (user_id);
+CREATE INDEX IF NOT EXISTS idx_a_e_i_level ON app_expert_info (level);
+CREATE INDEX IF NOT EXISTS idx_a_e_i_status ON app_expert_info (status);
+
+COMMENT ON TABLE app_expert_info IS '达人信息表,存储达人相关的详细信息';
+
+-- 添加字段注释
+COMMENT ON COLUMN app_expert_info.id IS '唯一标识,主键';
+COMMENT ON COLUMN app_expert_info.user_id IS '用户ID';
+COMMENT ON COLUMN app_expert_info.level IS '达人等级:A:高级,B:中级,C:初级';
+COMMENT ON COLUMN app_expert_info.nickname IS '达人昵称';
+COMMENT ON COLUMN app_expert_info.intro IS '达人简介';
+COMMENT ON COLUMN app_expert_info.avatar IS '达人头像URL';
+COMMENT ON COLUMN app_expert_info.points IS '达人积分,初始值为0';
+COMMENT ON COLUMN app_expert_info.create_time IS '成为达人的时间';
+COMMENT ON COLUMN app_expert_info.status IS '达人当前状态,可选值:正常=normal, 冻结=freeze, 注销=cancel';
+COMMENT ON COLUMN app_expert_info.follower_count IS '达人粉丝数量';
+COMMENT ON COLUMN app_expert_info.following_count IS '达人关注的其他用户数量';
+COMMENT ON COLUMN app_expert_info.successful_orders IS '达人成功完成的订单数量';
+COMMENT ON COLUMN app_expert_info.promotions IS '达人推广的商品数量';
+COMMENT ON COLUMN app_expert_info.product_tags IS '达人推广的商品标签';
+COMMENT ON COLUMN app_expert_info.prop1 IS '预留字段1';
+COMMENT ON COLUMN app_expert_info.prop2 IS '预留字段2';
+COMMENT ON COLUMN app_expert_info.prop3 IS '预留字段3';
+COMMENT ON COLUMN app_expert_info.prop4 IS '预留字段4';
+COMMENT ON COLUMN app_expert_info.update_by IS '更新人';
+COMMENT ON COLUMN app_expert_info.update_time IS '更新时间';
+

+ 21 - 0
poyee-admin/src/main/resources/logback-fluentd.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<included>
+    <appender name="FLUENT_SYNC" class="ch.qos.logback.more.appenders.DataFluentAppender">
+        <tag>logback</tag>
+        <label>${spring.application.name}.${hostname}</label>
+        <remoteHost>${logging.fluentd.host}</remoteHost>
+        <port>${logging.fluentd.port}</port>
+
+        <encoder charset="UTF-8">
+            <pattern>%logger{15}:%L - %msg</pattern>
+        </encoder>
+    </appender>
+
+    <appender name="FLUENT" class="ch.qos.logback.classic.AsyncAppender">
+        <queueSize>500</queueSize>
+        <neverBlock>true</neverBlock>
+        <maxFlushTime>15000</maxFlushTime>
+        <includeCallerData>false</includeCallerData>
+        <appender-ref ref="FLUENT_SYNC"/>
+    </appender>
+</included>

+ 42 - 0
poyee-admin/src/main/resources/logback.xml

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!-- 日志输出格式 -->
+    <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
+    <springProperty scope="context" name="spring.application.name" source="spring.application.name"/>
+    <springProperty scope="context" name="logging.fluentd.enabled" source="logging.fluentd.enabled"/>
+    <springProperty scope="context" name="logging.console.enabled" source="logging.console.enabled"/>
+    <springProperty scope="context" name="logging.fluentd.host" source="logging.fluentd.host"/>
+    <springProperty scope="context" name="logging.fluentd.port" source="logging.fluentd.port"/>
+    <define name="hostname" class="com.poyee.log.CanonicalHostNamePropertyDefiner"/>
+
+    <if condition='p("logging.fluentd.enabled").equals("true")'>
+        <then>
+            <include resource="logback-fluentd.xml"/>
+        </then>
+    </if>
+
+    <!-- 控制台输出 -->
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+    <!-- Spring日志级别控制  -->
+    <logger name="org.springframework" level="warn"/>
+    <!-- Spring日志级别控制  -->
+    <logger name="com.baomidou" level="debug"/>
+    <!--系统操作日志-->
+    <root level="info">
+        <if condition='p("logging.console.enabled").equals("true")'>
+            <then>
+                <appender-ref ref="console"/>
+            </then>
+        </if>
+        <if condition='p("logging.fluentd.enabled").equals("true")'>
+            <then>
+                <appender-ref ref="FLUENT"/>
+            </then>
+        </if>
+    </root>
+</configuration>

+ 14 - 0
poyee-admin/src/main/resources/mybatis/mybatis-config.xml

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

+ 9 - 0
poyee-app/README.md

@@ -0,0 +1,9 @@
+# app - 商品推广移动端
+
+> 移动端接口服务
+
+# 🌟 核心功能
+
+# 🛠️ 开发环境
+
+# 🛠️ 技术架构  

+ 133 - 0
poyee-app/pom.xml

@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.poyee</groupId>
+        <artifactId>product-promotion</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>poyee-app</artifactId>
+    <name>移动端</name>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </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-validation</artifactId>
+        </dependency>
+        <!--        热更新-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+        </dependency>
+        <!--阿里数据库连接池 -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+            <version>1.2.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-core</artifactId>
+            <version>3.5.2</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
+            <version>3.4.0</version>
+        </dependency>
+        <!--        -->
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <!--logback-->
+        <dependency>
+            <groupId>org.codehaus.janino</groupId>
+            <artifactId>janino</artifactId>
+            <version>3.0.12</version>
+        </dependency>
+        <dependency>
+            <groupId>com.sndyuk</groupId>
+            <artifactId>logback-more-appenders</artifactId>
+            <version>1.8.5</version>
+        </dependency>
+        <dependency>
+            <groupId>org.fluentd</groupId>
+            <artifactId>fluent-logger</artifactId>
+            <version>0.3.4</version>
+        </dependency>
+        <!--模块-->
+        <dependency>
+            <groupId>com.poyee</groupId>
+            <artifactId>poyee-base</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.poyee</groupId>
+            <artifactId>task</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <!--                <version>2.1.1.RELEASE</version>-->
+                <version>2.3.5.RELEASE</version>
+                <configuration>
+                    <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
+                    <includeSystemScope>true</includeSystemScope>
+                </configuration>
+
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <version>3.0.0</version>
+                <configuration>
+                    <failOnMissingWebXml>false</failOnMissingWebXml>
+                    <warName>${project.artifactId}</warName>
+                </configuration>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+</project>

+ 26 - 0
poyee-app/src/main/java/com/poyee/AppApplication.java

@@ -0,0 +1,26 @@
+package com.poyee;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+/**
+ *
+ */
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, SecurityAutoConfiguration.class }
+        , scanBasePackages = {"com.poyee"})
+@EnableAsync
+@EnableAspectJAutoProxy(proxyTargetClass = true)
+@Slf4j
+public class AppApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(AppApplication.class, args);
+        log.info("(♥◠‿◠)ノ゙ 启动成功   ლ(´ڡ`ლ)゙");
+    }
+
+}

+ 43 - 0
poyee-app/src/main/java/com/poyee/controller/AppExpertApiController.java

@@ -0,0 +1,43 @@
+package com.poyee.controller;
+
+import com.poyee.annotation.UserLoginToken;
+import com.poyee.base.controller.BaseController;
+import com.poyee.base.dto.Result;
+import com.poyee.dto.AppExpertInfoDto;
+import com.poyee.dto.req.AppExpertInfoReq;
+import com.poyee.enums.Roles;
+import com.poyee.service.IAppExpertInfoService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+
+/**
+ * 我的推广
+ */
+@Slf4j
+@Api(tags = "达人信息")
+@RestController
+@RequestMapping("/api/expert")
+public class AppExpertApiController extends BaseController<IAppExpertInfoService, AppExpertInfoReq, AppExpertInfoDto> {
+
+    /**
+     * 获取达人信息
+     */
+    @ApiOperation(value = "获取达人信息@(app-1.0)")
+    @RequestMapping(path = "/getExpertInfo", method = RequestMethod.GET)
+    @UserLoginToken(faceVerify = false, roles = {Roles.GENERAL_USER})
+    @ResponseBody
+    public Result<AppExpertInfoDto> getExpertInfo() {
+        console("获取达人信息", "");
+        return baseService.getExpertInfo();
+    }
+
+
+
+
+}

+ 71 - 0
poyee-app/src/main/java/com/poyee/controller/MinePromotionApiController.java

@@ -0,0 +1,71 @@
+package com.poyee.controller;
+
+import com.poyee.annotation.UserLoginToken;
+import com.poyee.base.controller.BaseController;
+import com.poyee.base.dto.Page;
+import com.poyee.base.dto.Result;
+import com.poyee.dto.order.MinePromotionOrderDto;
+import com.poyee.dto.order.MinePromotionOrderReq;
+import com.poyee.dto.order.OrderStatisticsReq;
+import com.poyee.enums.Roles;
+import com.poyee.service.MinePromotionApiService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 我的推广
+ */
+@Slf4j
+@Api(tags = "我的推广")
+@RestController
+@RequestMapping("/api/mine/promotion")
+public class MinePromotionApiController extends BaseController {
+
+    @Autowired
+    private MinePromotionApiService minePromotionApiService;
+    /**
+     * 查询可提现金额(元)
+     */
+    @ApiOperation(value = "查询可提现金额@(app-1.0)")
+    @RequestMapping(path = "/queryDrawAmount", method = RequestMethod.GET)
+    @UserLoginToken(faceVerify = false, roles = {Roles.GENERAL_USER})
+    @ResponseBody
+    public Result queryCanWithdrawAmount() {
+        console("查询可提现金额", "");
+        return minePromotionApiService.queryCanWithdrawAmount();
+    }
+
+    /**
+     * 查询推广任务订单
+     */
+    @ApiOperation(value = "查询推广任务订单@(app-1.0)")
+    @RequestMapping(path = "/queryPromotionOrder", method = RequestMethod.POST)
+    @UserLoginToken(faceVerify = false, roles = {Roles.GENERAL_USER})
+    @ResponseBody
+    public Page<MinePromotionOrderDto> queryPromotionOrder(@RequestBody MinePromotionOrderReq req) {
+        console("查询推广任务订单", req);
+        return minePromotionApiService.queryPromotionOrder(req);
+    }
+
+    /**
+     * 全部订单统计
+     * (本日,本周,本月,近三月)
+     * 返回点击次数,付款人数,付款金额,有效付款金额,付款笔数,有效付款笔数,付款预估收入(佣金),有效付款预估收入(佣金),结算预估收入,平均客单价
+     *
+     */
+    @ApiOperation(value = "全部订单统计@(app-1.0)")
+    @RequestMapping(path = "/queryOrderStatistics", method = RequestMethod.POST)
+    @UserLoginToken(faceVerify = false, roles = {Roles.GENERAL_USER})
+    @ResponseBody
+    public Result queryOrderStatistics(@RequestBody OrderStatisticsReq req) {
+        console("全部订单统计", req);
+        return minePromotionApiService.queryOrderStatistics(req);
+    }
+
+
+
+
+}

+ 65 - 0
poyee-app/src/main/java/com/poyee/controller/PromotionShareInfoController.java

@@ -0,0 +1,65 @@
+package com.poyee.controller;
+
+import com.poyee.annotation.UserLoginToken;
+import com.poyee.base.controller.BaseController;
+import com.poyee.base.dto.Page;
+import com.poyee.base.dto.Result;
+import com.poyee.dto.share.*;
+import com.poyee.enums.Roles;
+import com.poyee.service.IPromotionShareInfoService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author lsz
+ * @since 2025-04-16
+ */
+@Slf4j
+@Api(tags = "推广分享信息")
+@RestController
+@RequestMapping("/api/promotionShareInfo")
+public class PromotionShareInfoController extends BaseController<IPromotionShareInfoService, PromotionShareInfoReq, PromotionShareInfoDto> {
+
+    @ApiOperation(value = "列表@(app-1.0)")
+    @RequestMapping(path = "/page",method = {RequestMethod.POST})
+    @UserLoginToken(faceVerify = false, roles = {Roles.ADMIN,Roles.GENERAL_USER})
+    @ResponseBody
+    public Result<PromotionShareInfoPageDto> page(@RequestBody PromotionShareInfoPageReq req) {
+        return Result.success(baseService.page(req));
+    }
+
+    /**
+     * 更新分享内容
+     */
+    @ApiOperation(value = "更新分享内容@(app-1.0)")
+    @RequestMapping(path = "/hold",method = {RequestMethod.POST})
+    @UserLoginToken(faceVerify = false, roles = {Roles.ADMIN,Roles.GENERAL_USER})
+    @ResponseBody
+    public Result hold(@RequestBody @Valid MakeShareInfoReq req) {
+        return baseService.hold(req);
+    }
+
+    /**
+     * 生成分享信息
+     * @param taskId
+     * @return
+     */
+    @ApiOperation(value = "生成分享信息@(app-1.0)")
+    @RequestMapping(path = "/makeShareInfo/{taskId}",method = {RequestMethod.POST})
+    @UserLoginToken(faceVerify = false, roles = {Roles.ADMIN,Roles.GENERAL_USER})
+    @ResponseBody
+    public Result<PromotionShareInfoDto> makeShareInfo(@PathVariable("taskId") Long taskId) {
+        return Result.success(baseService.makeShareInfo(taskId));
+    }
+
+
+
+}

+ 76 - 0
poyee-app/src/main/java/com/poyee/controller/TaskApiController.java

@@ -0,0 +1,76 @@
+package com.poyee.controller;
+
+import com.poyee.annotation.UserLoginToken;
+import com.poyee.base.controller.BaseController;
+import com.poyee.base.dto.Page;
+import com.poyee.base.dto.Result;
+import com.poyee.dto.task.*;
+import com.poyee.enums.Roles;
+import com.poyee.service.IPromotionTaskService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+
+/**
+ *  推广任务
+ */
+@Api(value = "推广任务", tags = "推广任务" )
+@Slf4j
+@RestController
+@RequestMapping("/api/promotionTask")
+public class TaskApiController extends BaseController<IPromotionTaskService, PromotionTaskReq, PromotionTaskDto> {
+    /**
+     * 列表
+     * 商家, 管理员, 运营[客服]等均可见
+     * @param req
+     * @return
+     */
+    @ApiOperation(value = "任务列表@(app-1.0)")
+    @RequestMapping(value = "/page", method = {RequestMethod.POST})
+    @UserLoginToken(faceVerify = false, roles = {Roles.ADMIN,Roles.SHIPPING,Roles.GENERAL_USER,Roles.CUSTOMER})
+    @ResponseBody
+    public Result<PromotionTaskPageDto> page(@RequestBody PromotionTaskPageReq req) {
+        console("任务列表->>", req);
+        //判断是普通用户 或客服【运营】 状态默认为 已发布(R)
+        if(checkHasUserRole(Roles.GENERAL_USER,Roles.CUSTOMER)){
+            req.setStatus("R");
+        }
+        if (StringUtils.isNotBlank(req.getKeyWord())) {
+            req.setMerchantName(req.getKeyWord());
+            req.setProductName(req.getKeyWord());
+        }
+        Page<PromotionTaskPageDto> page = baseService.page(req);
+        return Result.success(page);
+    }
+    /**
+     * 审核
+     */
+    @ApiOperation(value = "审核任务@(app-1.0)")
+    @RequestMapping(value = "/audit", method = {RequestMethod.POST})
+    @UserLoginToken(faceVerify = false, roles = {Roles.ADMIN,Roles.SHIPPING,Roles.CUSTOMER})
+    @ResponseBody
+    public Result audit(@RequestBody @Valid PromotionTaskAuditReq req) {
+        console("审核任务->> ",req);
+        return baseService.audit(req);
+    }
+
+    /**
+     * 更新任务状态: 下架 上架 等
+     */
+    @ApiOperation(value = "更新任务状态@(app-1.0)")
+    @RequestMapping(value = "/updateStatus", method = {RequestMethod.POST})
+    @UserLoginToken(faceVerify = false, roles = {Roles.ADMIN,Roles.SHIPPING,Roles.CUSTOMER})
+    @ResponseBody
+    public Result updateStatus(@RequestBody @Valid PromotionTaskUpdateReq req) {
+        console("更新任务状态->> ",req);
+        return baseService.updateStatus(req);
+    }
+
+
+
+
+}

+ 35 - 0
poyee-app/src/main/java/com/poyee/param/TaskApiPageReq.java

@@ -0,0 +1,35 @@
+package com.poyee.param;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.base.dto.BaseReq;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ *
+ */
+@ApiModel(value = "推广任务分页查询参数" )
+@Data
+@TableName("promotion_task")
+public class TaskApiPageReq extends BaseReq {
+
+    @ApiModelProperty(value = "商品名称")
+    @TableField(value = "product_name")
+    private String productName;
+
+    @ApiModelProperty(value = "商品类型:group(拼团),shop(商城)")
+    @TableField(value = "type")
+    private String type;
+
+    @ApiModelProperty(value = "任务状态: R(已发布)")
+    @TableField(value = "status")
+    private String status;
+
+    @ApiModelProperty(value = "商户id",hidden = true)
+    @TableField(value = "merchant_id")
+    private Integer merchantId;
+
+}
+

+ 101 - 0
poyee-app/src/main/resources/application-dev.yml

@@ -0,0 +1,101 @@
+spring:
+  datasource:
+    dynamic:
+      primary: master
+      datasource:
+        master:
+          type: com.alibaba.druid.pool.DruidDataSource
+          driver-class-name: org.postgresql.Driver
+          url: jdbc:postgresql://m2-dev.hobbystocks.cn:5432/tzy_system
+          username: postgres
+          password: 123456
+        slave:
+          type: com.alibaba.druid.pool.DruidDataSource
+          driver-class-name: org.postgresql.Driver
+          url: jdbc:postgresql://localhost:5432/py_test
+          username: postgres
+          password: 123456
+        slave1:
+          type: com.alibaba.druid.pool.DruidDataSource
+          driver-class-name: org.postgresql.Driver
+          url: jdbc:postgresql://pgm-uf69k761dcw5icggdo.pg.rds.aliyuncs.com/hobby_stocks
+          username: hobbystocks
+          password: Pass2010
+        slave2:
+          type: com.alibaba.druid.pool.DruidDataSource
+          driver-class-name: org.postgresql.Driver
+          url: jdbc:postgresql://localhost:5432/tzy_system
+          username: postgres
+          password: 123456
+    druid:
+      # 初始连接数
+      initialSize: 5
+      # 最小连接池数量
+      minIdle: 10
+      # 最大连接池数量
+      maxActive: 20
+      # 配置获取连接等待超时的时间
+      maxWait: 60000
+  redis:
+    database: 1
+    host: 192.168.207.128
+    port: 6379
+    password: #Pass2021    # 密码(默认为空)
+    timeout: 15000  # 连接超时时长(毫秒)
+    pool:
+      max-active: 1000  # 连接池最大连接数(使用负值表示没有限制)
+      max-wait: -1ms    # 连接池最大阻塞等待时间(使用负值表示没有限制)
+      max-idle: 10      # 连接池中的最大空闲连接
+      min-idle: 5       # 连接池中的最小空闲连接
+  #mq
+  rabbitmq:
+    host: 192.168.207.128
+    port: 5672
+    username: guest
+    password: guest
+    #    host: ${SPRING_RABBITMQ_HOST:m2-dev.hobbystocks.cn}
+    #    port: ${SPRING_RABBITMQ_PORT:5672}
+    #    username: ${SPRING_RABBITMQ_USERNAME:admin}
+    #    password: ${SPRING_RABBITMQ_PASSWORD:admin}
+    #确认消息已发送到交换机(Exchange)
+    publisher-confirms: true
+    #确认消息已发送到队列(Queue)
+    publisher-returns: true
+    template:
+      retry:
+        enabled: true
+      mandatory: true
+    listener:
+      simple:
+        acknowledge-mode: manual
+        #并发消费者初始化值
+        #concurrency: 10
+        #并发消费者的最大值
+        #max-concurrency: 20
+        #每个消费者每次监听时可拉取处理的消息数量
+        prefetch: 5
+      direct:
+        retry:
+          enabled: true
+          max-attempts: 1
+
+mybatis-plus:
+  configuration:
+    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+    map-underscore-to-camel-case: true
+  global-config:
+    db-config:
+      column-underline: false
+#  mapper-locations: classpath*:mapper/*.xml
+
+# knife4j 配置
+knife4j:
+  # 是否开启 knife4j
+  enabled: true
+  #生产模式屏蔽
+  production: true
+  basic: #是否需要登录
+    enable: true
+    username: admin
+    password: 123456
+

+ 64 - 0
poyee-app/src/main/resources/application.yml

@@ -0,0 +1,64 @@
+poyee:
+  name: 推广
+  version: 1.0.0
+  active-db: slave
+  holiday-db: slave2
+  api-version: app-1.0
+
+spring:
+  application:
+    name:
+  profiles:
+    active: dev
+  #flyway
+  flyway:
+    # 是否启用flyway
+    enabled: true
+    # 指定表
+    table: flyway_schema_history_pp_app
+    # 禁止清理数据库表
+    clean-disabled: true
+    # 编码格式,默认UTF-8
+    encoding: UTF-8
+    # 迁移sql脚本文件存放路径,默认db/migration
+    locations: classpath:db/migration
+    # 迁移sql脚本文件名称的前缀,默认V
+    sql-migration-prefix: V
+    # 迁移sql脚本文件名称的分隔符,默认2个下划线__
+    sql-migration-separator: _
+    # 迁移sql脚本文件名称的后缀
+    sql-migration-suffixes: .sql
+    # 迁移时是否进行校验,默认true
+    validate-on-migrate: true
+    # 当迁移发现数据库非空且存在没有元数据的表时,自动执行基准迁移,新建schema_version表
+    baseline-on-migrate: true
+    url: ${DB_URL:jdbc:postgresql://localhost:5432/py_test}
+    user: ${DB_USERNAME:postgres}
+    password: ${DB_PASSWORD:123456}
+  jackson:
+    date-format: yyyy-MM-dd HH:mm:ss
+
+server:
+  port: 8100
+
+# MyBatis
+mybatis:
+  # 搜索指定包别名
+  typeAliasesPackage: com.ibox.**.entity,com.poyee.**.dto,com.ibox.**.req,com.ibox.entity,com.ibox.dto,com.ibox.dto.req
+  # 配置mapper的扫描,找到所有的mapper.xml映射文件
+  mapperLocations: '' #classpath*:mapper/**/*Mapper.xml
+  # 加载全局的配置文件
+  configLocation: classpath:mybatis/mybatis-config.xml
+
+
+#logback
+logging:
+  console.enabled: ${CONSOLE_ENABLED:true}
+  file.enabled: ${FILE_ENABLED:false}
+  level:
+    com.poyee: debug
+    org.springframework: warn
+  fluentd:
+    enabled: ${FLUENTD_ENABLED:false}
+    host: ${FLUENTD_HOST:127.0.0.1}
+    port: ${FLUENTD_PORT:24225}

+ 21 - 0
poyee-app/src/main/resources/logback-fluentd.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<included>
+    <appender name="FLUENT_SYNC" class="ch.qos.logback.more.appenders.DataFluentAppender">
+        <tag>logback</tag>
+        <label>${spring.application.name}.${hostname}</label>
+        <remoteHost>${logging.fluentd.host}</remoteHost>
+        <port>${logging.fluentd.port}</port>
+
+        <encoder charset="UTF-8">
+            <pattern>%logger{15}:%L - %msg</pattern>
+        </encoder>
+    </appender>
+
+    <appender name="FLUENT" class="ch.qos.logback.classic.AsyncAppender">
+        <queueSize>500</queueSize>
+        <neverBlock>true</neverBlock>
+        <maxFlushTime>15000</maxFlushTime>
+        <includeCallerData>false</includeCallerData>
+        <appender-ref ref="FLUENT_SYNC"/>
+    </appender>
+</included>

+ 42 - 0
poyee-app/src/main/resources/logback.xml

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!-- 日志输出格式 -->
+    <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n"/>
+    <springProperty scope="context" name="spring.application.name" source="spring.application.name"/>
+    <springProperty scope="context" name="logging.fluentd.enabled" source="logging.fluentd.enabled"/>
+    <springProperty scope="context" name="logging.console.enabled" source="logging.console.enabled"/>
+    <springProperty scope="context" name="logging.fluentd.host" source="logging.fluentd.host"/>
+    <springProperty scope="context" name="logging.fluentd.port" source="logging.fluentd.port"/>
+    <define name="hostname" class="com.poyee.log.CanonicalHostNamePropertyDefiner"/>
+
+    <if condition='p("logging.fluentd.enabled").equals("true")'>
+        <then>
+            <include resource="logback-fluentd.xml"/>
+        </then>
+    </if>
+
+    <!-- 控制台输出 -->
+    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+    <!-- Spring日志级别控制  -->
+    <logger name="org.springframework" level="warn"/>
+    <!-- Spring日志级别控制  -->
+    <logger name="com.baomidou" level="debug"/>
+    <!--系统操作日志-->
+    <root level="info">
+        <if condition='p("logging.console.enabled").equals("true")'>
+            <then>
+                <appender-ref ref="console"/>
+            </then>
+        </if>
+        <if condition='p("logging.fluentd.enabled").equals("true")'>
+            <then>
+                <appender-ref ref="FLUENT"/>
+            </then>
+        </if>
+    </root>
+</configuration>

+ 14 - 0
poyee-app/src/main/resources/mybatis/mybatis-config.xml

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

+ 41 - 0
poyee-base/README.md

@@ -0,0 +1,41 @@
+# POYEE BASE - 基础插件
+
+> 基础方法
+
+# 🌟 核心功能
+- 自定义注解 [annotation](src%2Fmain%2Fjava%2Fcom%2Fpoyee%2Fannotation)
+- 基础抽象方法 [base](src%2Fmain%2Fjava%2Fcom%2Fpoyee%2Fbase) 
+  >- controller 控制层抽象类
+  >- service 业务层 抽象类
+  >- mapper 数据层抽象类
+  >>- mapper 接口
+  >>- provider 动态sql工具
+  >>>- 根据实体类注解 动态生成查询sql 不需要使用 mapper.xml 文件 \
+       工具内集成基础的查询工具.更复杂的可以自定义手写sql
+  >>>- mapper.java 继承 IBaseProvider \
+       如果自定义手写sql 业务模块需要在mapper包下创建 provider包, 在其下创建*Provider class
+       根据需要 编写自定义sql逻辑的方法 \
+       参考:https://blog.csdn.net/fmwind/article/details/81534357
+  >- entity,dto 实体类
+- common 工具 [common](src%2Fmain%2Fjava%2Fcom%2Fpoyee%2Fcommon)
+  >- 常量
+  >- db生成工具插件
+  >- exception 业务异常工具 
+  >- JsonMapperUtil 工具类
+  >- knife4j swagger2 插件
+- config
+  >- [自定义sql注入器 JoinSqlInjector](src%2Fmain%2Fjava%2Fcom%2Fpoyee%2Fconfig%2FJoinSqlInjector.java)
+  >- [redis配置](src%2Fmain%2Fjava%2Fcom%2Fpoyee%2Fconfig%2FRedisConfig.java)
+- 多数据源配置 [dataSource](src%2Fmain%2Fjava%2Fcom%2Fpoyee%2FdataSource)
+- easyExcel 插件 [easy](src%2Fmain%2Fjava%2Fcom%2Fpoyee%2Feasy)
+- enums 枚举 [enums](src%2Fmain%2Fjava%2Fcom%2Fpoyee%2Fenums)
+- handler 监听器 [handler](src%2Fmain%2Fjava%2Fcom%2Fpoyee%2Fhandler)
+  >- easyExcel监听器 [EasyDataFormatHandler.java](src%2Fmain%2Fjava%2Fcom%2Fpoyee%2Fhandler%2FEasyDataFormatHandler.java)
+  >- easyExcel分页查询监听器 [PageReadListenerHandler.java](src%2Fmain%2Fjava%2Fcom%2Fpoyee%2Fhandler%2FPageReadListenerHandler.java)
+  >- mq [mq](src%2Fmain%2Fjava%2Fcom%2Fpoyee%2Fmq)
+  >- redis工具 [redis](src%2Fmain%2Fjava%2Fcom%2Fpoyee%2Fredis)
+  >- 通用工具类 [util](src%2Fmain%2Fjava%2Fcom%2Fpoyee%2Futil)
+
+# 🛠️ 开发环境
+
+# 🛠️ 技术架构  

+ 207 - 0
poyee-base/pom.xml

@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.poyee</groupId>
+        <artifactId>product-promotion</artifactId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>poyee-base</artifactId>
+    <name>基础</name>
+    <description>poyee-base</description>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-webmvc</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-core</artifactId>
+            <version>3.5.2</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.github.yulichang</groupId>
+            <artifactId>mybatis-plus-join-boot-starter</artifactId>
+            <version>1.4.2.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-generator</artifactId>
+            <version>3.5.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mybatis</groupId>
+            <artifactId>mybatis-spring</artifactId>
+            <version>2.0.7</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-extension</artifactId>
+            <version>3.5.2</version>
+            <scope>compile</scope>
+        </dependency>
+        <!-- knife4j 接口管理 -->
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>knife4j-spring-boot-starter</artifactId>
+        </dependency>
+
+        <!--jdbc-->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-jdbc</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid</artifactId>
+            <version>1.2.1</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-autoconfigure</artifactId>
+            <version>2.3.0</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.aspectj</groupId>
+            <artifactId>aspectjweaver</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+            <version>3.12.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>easyexcel</artifactId>
+            <version>3.3.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.tomcat.embed</groupId>
+            <artifactId>tomcat-embed-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.yaml</groupId>
+            <artifactId>snakeyaml</artifactId>
+        </dependency>
+
+        <!-- redis 环境 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.data</groupId>
+            <artifactId>spring-data-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>redis.clients</groupId>
+            <artifactId>jedis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.session</groupId>
+            <artifactId>spring-session-data-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.redisson</groupId>
+            <artifactId>redisson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-amqp</artifactId>
+        </dependency>
+
+        <!--jwt 鉴权-->
+        <dependency>
+            <groupId>com.auth0</groupId>
+            <artifactId>java-jwt</artifactId>
+            <version>3.3.0</version>
+        </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+            <version>0.9.0</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.8.11</version>
+        </dependency>
+        <!--swagger-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>2.10.5</version>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>2.10.5</version>
+        </dependency>
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-annotations</artifactId>
+            <version>1.5.21</version>
+        </dependency>
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-models</artifactId>
+            <version>1.5.21</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>swagger-bootstrap-ui</artifactId>
+            <version>1.9.5</version>
+        </dependency>
+        <!--    Guava     -->
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>29.0-jre</version>
+        </dependency>
+    </dependencies>
+</project>

+ 14 - 0
poyee-base/src/main/java/com/poyee/annotation/DictTypeFormat.java

@@ -0,0 +1,14 @@
+package com.poyee.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 字典表类型处理s
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DictTypeFormat {
+
+    String value();
+}

+ 11 - 0
poyee-base/src/main/java/com/poyee/annotation/IgnoreSwaggerParameter.java

@@ -0,0 +1,11 @@
+package com.poyee.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface IgnoreSwaggerParameter {
+}

+ 18 - 0
poyee-base/src/main/java/com/poyee/annotation/JsonFormater.java

@@ -0,0 +1,18 @@
+package com.poyee.annotation;
+
+import org.springframework.stereotype.Component;
+
+import java.lang.annotation.*;
+
+/**
+ *
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Component
+public @interface JsonFormater {
+
+    String value() default "";
+
+}

+ 19 - 0
poyee-base/src/main/java/com/poyee/annotation/JsonMapper.java

@@ -0,0 +1,19 @@
+package com.poyee.annotation;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.annotation.*;
+
+/**
+ * json映射
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface JsonMapper {
+
+    @NotNull
+    String name() default "";
+    //类型举例
+    String readConverterExp() default "" ;
+}

+ 51 - 0
poyee-base/src/main/java/com/poyee/annotation/MpjWapper.java

@@ -0,0 +1,51 @@
+package com.poyee.annotation;
+
+
+import java.lang.annotation.*;
+
+/**
+ * 类属性注解
+ * 描述:搜索时使用
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface MpjWapper {
+    //字段
+    String value() ;
+    //字段类型
+    Type columnType() default Type.STRING;
+    //操作符
+    Operator operator() default Operator.EQ;
+    //数据
+    String data() default "";
+
+    enum Type {
+        STRING,
+        NUMBER,
+        DATE,
+        BOOLEAN,
+        ENUM,
+    }
+
+    enum Operator{
+        EQ,
+        NE,
+        GT,
+        GE,
+        LT,
+        LE,
+        LIKE,
+        NOTLIKE,
+        IN,
+        NOTIN,
+        BETWEEN,
+        NOTBETWEEN,
+        ISNULL,
+        ISNOTNULL,
+        ISNOTEMPTY,
+        ISEMPTY,
+        ISNOT
+    }
+
+}

+ 13 - 0
poyee-base/src/main/java/com/poyee/annotation/ReadConverterExpFormat.java

@@ -0,0 +1,13 @@
+package com.poyee.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 列举数据转换注解
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ReadConverterExpFormat {
+    String value();
+}

+ 25 - 0
poyee-base/src/main/java/com/poyee/annotation/UserLoginToken.java

@@ -0,0 +1,25 @@
+package com.poyee.annotation;
+
+import com.poyee.enums.Roles;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+// 需要登录才能进行操作的注解UserLoginToken
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface UserLoginToken {
+    boolean required() default true;
+    boolean faceVerify() default true;
+    /**
+     * @return
+     */
+    Roles[] roles() default {Roles.ADMIN};
+    /**
+     * 通过验证的来源
+     * @return
+     */
+    String pass_aub() default "";
+}

+ 23 - 0
poyee-base/src/main/java/com/poyee/annotation/db/CaseWhen.java

@@ -0,0 +1,23 @@
+package com.poyee.annotation.db;
+
+import com.poyee.enums.CaseWhenValueTypeEnums;
+
+import java.lang.annotation.*;
+
+/**
+ * 聚合等条件取值
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface CaseWhen {
+    //  条件
+    String when() default "";
+    //  值
+    String then() default "";
+    //  是否是else
+    boolean isElse() default false;
+    //  值类型
+    CaseWhenValueTypeEnums valueType() default CaseWhenValueTypeEnums.CONSTANT;
+
+}

+ 20 - 0
poyee-base/src/main/java/com/poyee/annotation/db/Count.java

@@ -0,0 +1,20 @@
+package com.poyee.annotation.db;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+
+import java.lang.annotation.*;
+
+/**
+ * 统计字段  计数
+ * 和 {@link TableField TableField}一起使用
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Count {
+
+    boolean distinct() default false;
+
+    CaseWhen[] caseWhen() default {};
+
+}

+ 18 - 0
poyee-base/src/main/java/com/poyee/annotation/db/Join.java

@@ -0,0 +1,18 @@
+package com.poyee.annotation.db;
+
+import java.lang.annotation.*;
+
+/**
+ * 外连接
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Join {
+    // 关联表
+    String table();
+    // 关联条件
+    String on();
+    // 别名
+    String alias();
+}

+ 21 - 0
poyee-base/src/main/java/com/poyee/annotation/db/LeftJoin.java

@@ -0,0 +1,21 @@
+package com.poyee.annotation.db;
+
+import java.lang.annotation.*;
+
+/**
+ * 左连接
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface LeftJoin {
+    // 关联表
+    Class<?> table();
+    // 关联表(左表。主表)
+    Class<?> leftTable() default void.class;
+    // 关联字段
+    String fieldName() default "";
+    /* 关联字段(左表关联字段)*/
+    String leftFieldName() default "";
+
+}

+ 15 - 0
poyee-base/src/main/java/com/poyee/annotation/db/OrderBy.java

@@ -0,0 +1,15 @@
+package com.poyee.annotation.db;
+
+import com.poyee.enums.OrderBySortEnums;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface OrderBy {
+    // 排序方式
+    OrderBySortEnums sortType() default OrderBySortEnums.ASC;
+    // 顺序
+    int index() default 1;
+}

+ 19 - 0
poyee-base/src/main/java/com/poyee/annotation/db/RightJoin.java

@@ -0,0 +1,19 @@
+package com.poyee.annotation.db;
+
+import java.lang.annotation.*;
+
+/**
+ * 右连接
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RightJoin {
+    // 表名
+    String table();
+    // 关联条件
+    String on();
+    // 别名
+    String alias();
+
+}

+ 21 - 0
poyee-base/src/main/java/com/poyee/annotation/db/Select.java

@@ -0,0 +1,21 @@
+package com.poyee.annotation.db;
+
+import java.lang.annotation.*;
+
+/**
+ * 查询
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Select {
+    // 表名
+    Class<?> table();
+    // 别名
+    String alias() default "";
+    // 字段名
+    String fieldName() default "";
+    // 聚合等条件取值
+    CaseWhen[] caseWhen() default {};
+
+}

+ 17 - 0
poyee-base/src/main/java/com/poyee/annotation/db/Sum.java

@@ -0,0 +1,17 @@
+package com.poyee.annotation.db;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+
+import java.lang.annotation.*;
+
+/**
+ * 统计字段  记和
+ * 和 {@link TableField TableField}一起使用
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Sum {
+
+    CaseWhen[] caseWhen() default {};
+}

+ 30 - 0
poyee-base/src/main/java/com/poyee/annotation/db/Where.java

@@ -0,0 +1,30 @@
+package com.poyee.annotation.db;
+
+import com.poyee.enums.FieldOperator;
+import com.poyee.enums.FieldType;
+
+import java.lang.annotation.*;
+
+/**
+ * 条件
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Where {
+    // 表名、别名 2选一
+    Class<?> table() ;
+    // 别名 、表名 2选一
+    String alias() default "";
+    // 字段名
+    String field();
+    //字段类型
+    FieldType columnType() default FieldType.STRING;
+    //操作符
+    FieldOperator operator() default FieldOperator.EQ;
+
+    boolean isNull() default false;
+
+    boolean isEnd() default false;
+
+}

+ 211 - 0
poyee-base/src/main/java/com/poyee/aspectj/UserLoginTokenAspect.java

@@ -0,0 +1,211 @@
+package com.poyee.aspectj;
+
+import com.alibaba.fastjson.JSONException;
+import com.alibaba.fastjson.JSONObject;
+import com.poyee.annotation.UserLoginToken;
+import com.poyee.base.dto.AppBaseUser;
+import com.poyee.base.dto.UserInfo;
+import com.poyee.common.exception.BusinessException;
+import com.poyee.common.exception.ServiceException;
+import com.poyee.enums.DataAuth;
+import com.poyee.enums.HttpMethod;
+import com.poyee.enums.Roles;
+import com.poyee.util.Base64Util;
+import com.poyee.util.ServletUtils;
+import com.poyee.util.http.HttpClientUtil;
+import com.poyee.util.jwt.JwtUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.Signature;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Aspect
+@Component
+public class UserLoginTokenAspect {
+
+    @Value("${user.info-url:https://coresvc-dev.hobbystocks.cn/user/}")
+    private String userInfoUrl;
+
+    // 配置织入点
+    @Pointcut("@annotation(com.poyee.annotation.UserLoginToken)")
+    public void logPointCut() {
+    }
+
+    /**
+     * @param
+     */
+    @Before("execution(public * com.poyee.*ontroller.*.*(..))")
+    public void doBefore(JoinPoint joinPoint) {
+        HttpServletRequest request = ServletUtils.getRequest();
+        String userInfoStr = request.getHeader("X-USER-BASE64");
+        userInfoStr = StringUtils.isNotEmpty(userInfoStr) ? userInfoStr : request.getHeader("x-user-base64");
+        Signature signature = joinPoint.getSignature();
+        MethodSignature methodSignature = (MethodSignature) signature;
+        Method method = methodSignature.getMethod();
+        log.info(" X-USER-BASE64 >>> {} ",userInfoStr);
+        //头部信息打印
+       /* Enumeration<String> headerNames = request.getHeaderNames();
+        while (headerNames.hasMoreElements()){
+            String name = headerNames.nextElement();
+            log.info(" --头部信息-- {} 值:{} ",name,request.getHeader(name));
+        }*/
+        //检查是否需要 UserLoginToken 认证用户信息
+        //检查用户权限
+        checkUserLoginToken(request, userInfoStr, method);
+    }
+    /**
+     * 检查用户权限
+     * @param request
+     * @param userInfoStr
+     * @param method
+     */
+    private void checkUserLoginToken(HttpServletRequest request, String userInfoStr, Method method) {
+        if (method.isAnnotationPresent(UserLoginToken.class)) {
+            UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
+            if (userLoginToken.required()) {
+                boolean isAuthorization = false;
+                if (StringUtils.isEmpty(userInfoStr)) {
+                    try {
+                        userInfoStr = request.getHeader("authorization");
+                        if (userInfoStr.startsWith("Bearer ")) {
+                            isAuthorization = true;
+                            userInfoStr = userInfoStr.replaceAll("Bearer ", "");
+                        }
+                    }catch (Exception e){
+                        log.error(" 获取token 异常 {} ", userInfoStr);
+                        throw new BusinessException(401, "验证用户信息失败[401]!");
+                    }
+                }
+                String user = "";
+                try {
+                    if(isAuthorization){
+                        user = JSONObject.toJSONString(JwtUtils.getTokenUserInfo(userInfoStr));
+                    }else {
+                        user = new String(Base64Util.decode(userInfoStr), StandardCharsets.UTF_8);
+                        JSONObject.parseObject(user);
+                    }
+                } catch (JSONException jsonExe) {
+                    log.error(" 转换json 异常 {} ", userInfoStr);
+                    //使用jwt进行获取用户信息
+                    user = JSONObject.toJSONString(JwtUtils.getTokenUserInfo(userInfoStr));
+                } catch (IllegalArgumentException ie) {
+                    log.error(" token bease64解析 异常 {} ", userInfoStr);
+                    try {
+                        user = new String(Base64Util.uriDecode(userInfoStr));
+                        log.error(" bease64解析 异常>> 使用uri 解析 》》》{}", user);
+                    } catch (IllegalArgumentException ie1) {
+                        log.error(" uriBease64解析 异常>> 使用uri 解析 》》》 {}", userInfoStr);
+                        throw new BusinessException(402, "验证用户信息失败,请重新登录[402]!");
+                    }
+                }
+                if (StringUtils.isEmpty(user)) {
+                    throw new BusinessException(402, "验证用户信息失败,请重新登录[402]!");
+                }
+                request.getSession().setAttribute("userInfo", user);
+            }
+            if (userLoginToken.faceVerify()) {
+                if (!getAppUserInfo()) {
+                    throw new BusinessException(403, "请先进行实名认证[403]!");
+                }
+            }
+            //权限判断
+            if (!checkRole(userLoginToken)) {
+                throw new BusinessException(403, "无权限操作[403]!");
+            }
+        }
+    }
+
+    /**
+     * @return
+     */
+    private boolean getAppUserInfo() {
+        UserInfo userInfo = ServletUtils.getUserInfo();
+        if (null == userInfo || null == userInfo.getId()) {
+            throw new ServiceException("请重新登录[405]!");
+        }
+        String str = HttpClientUtil.create()
+                                       .uri(userInfoUrl + userInfo.getId(), HttpMethod.GET)
+                                       .build()
+                                       .execute();
+//        String str = HttpClient.get(userInfoUrl + userInfo.getId());
+//        log.info(" 调用接口查询用户详情信息》》》{} ", str);
+        try {
+            AppBaseUser appBaseUser = JSONObject.parseObject(str, AppBaseUser.class);
+            if (1 != appBaseUser.getFaceVerify()) {
+                throw new ServiceException(403, "请先进行实名认证[403]!");
+            }
+            ServletUtils.getSession().setAttribute("appBaseUser",appBaseUser);
+        } catch (Exception e) {
+//            throw new BusinessException(403, "请先进行实名认证[403]!");
+        }
+        return true;
+    }
+    /**
+     * 权限判断
+     * @param userLoginToken
+     * @return
+     */
+    private boolean checkRole(UserLoginToken userLoginToken){
+        UserInfo userInfo = ServletUtils.getUserInfo();
+        if (null == userInfo || null == userInfo.getId()) {
+            throw new BusinessException(405, "请重新登录[405]!");
+        }
+        if (StringUtils.isNotBlank(userLoginToken.pass_aub())) {
+            //如果用户来源与非验证来源一致 不进行角色验证
+            if (Objects.equals(userInfo.getAud(), userLoginToken.pass_aub())) {
+                return true;
+            }
+        }
+        String roleCode = userInfo.getRoleCode();
+        if(StringUtils.isBlank(roleCode) && StringUtils.isBlank(userInfo.getRole())){
+            throw new BusinessException(401,"无权操作[401]");
+        }
+        //判断partnerRoles 是否有值
+        if(CollectionUtils.isNotEmpty(userInfo.getPartnerRoles())){
+            roleCode = String.join(",", userInfo.getPartnerRoles());
+            log.info(" 当前partner用户拥有的角色[{}] ",roleCode);
+        }else{
+            roleCode = StringUtils.isBlank(roleCode)?userInfo.getRole():roleCode;
+        }
+        //用户角色
+        List<Roles> myRoles = Optional.ofNullable(Roles.checkMyRoles(roleCode)).orElseGet(ArrayList::new);
+        //方法角色
+        List<Roles> methodRoles = Arrays.asList(userLoginToken.roles());
+        //符合角色
+        List<Roles> hasRole = methodRoles.stream().filter(myRoles::contains).collect(Collectors.toList());
+        log.info(" 当前用户存在的角色[{}] ",hasRole);
+        if(hasRole.contains(Roles.ADMIN)){
+            userInfo.setDataAuth(DataAuth.ALL);
+            return CollectionUtils.isNotEmpty(hasRole);
+        }
+        if(hasRole.contains(Roles.SHIPPING)){
+            //如果有商家权限 则设置 商家id
+            userInfo.setDataAuth(DataAuth.DEPT);
+            userInfo.setMerchant(true);
+            String merchantName = StringUtils.isBlank(userInfo.getMerchantName()) ? userInfo.getDisplayName() : userInfo.getMerchantName();
+            merchantName = StringUtils.isNotBlank(merchantName) ? merchantName : userInfo.getNickname();
+            userInfo.setMerchantName(merchantName);
+        }else
+        {
+            userInfo.setDataAuth(DataAuth.PERSON);
+        }
+        ServletUtils.getSession().setAttribute("userInfo", JSONObject.toJSONString(userInfo));
+        return CollectionUtils.isNotEmpty(hasRole);
+    }
+
+
+}

+ 64 - 0
poyee-base/src/main/java/com/poyee/base/controller/BaseController.java

@@ -0,0 +1,64 @@
+package com.poyee.base.controller;
+
+import com.poyee.base.dto.BaseDto;
+import com.poyee.base.dto.BaseReq;
+import com.poyee.base.dto.UserInfo;
+import com.poyee.base.service.BaseService;
+import com.poyee.common.exception.ServiceException;
+import com.poyee.enums.Roles;
+import com.poyee.util.DateUtils;
+import com.poyee.util.ServletUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ *
+ */
+@Slf4j
+public abstract class BaseController<S extends BaseService<T, R>, T extends BaseReq, R extends BaseDto> {
+
+    @Autowired
+    public S baseService;
+
+    public void console(String label, Object obj ){
+        //当前操作用户 及 角色 ,操作时间
+        UserInfo userInfo = ServletUtils.getUserInfo();
+        String userName = StringUtils.isNotBlank(userInfo.getDisplayName())?userInfo.getDisplayName():userInfo.getSub();
+        log.info("{} {}\n" +
+                         " 当前用户[{}] 角色【{}】操作时间[{}]",label,obj,
+                 userName, userInfo.getRoleCode(), DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,new Date()));
+    }
+
+    /**
+     * 检查用户角色
+     * @param roles
+     * @return
+     */
+    public boolean checkHasUserRole(Roles... roles){
+        UserInfo userInfo = ServletUtils.getUserInfo();
+        if(Objects.isNull(roles) || CollectionUtils.isEmpty(Arrays.asList(roles))){
+            return true;
+        }
+        if(StringUtils.isNotBlank(userInfo.getRoleCode())){
+            String roleCode = userInfo.getRoleCode();
+            //用户角色
+            List<Roles> myRoles = Optional.ofNullable(Roles.checkMyRoles(roleCode)).orElseGet(ArrayList::new);
+            if(CollectionUtils.isEmpty(myRoles)){
+                throw new ServiceException(401,"当前用户没有权限");
+            }
+            Set<Roles> checkRoles = new HashSet<>(Arrays.asList(roles));
+            //符合角色
+            // 检查用户是否拥有任意一个指定角色
+            List<Roles> hasRole = myRoles.stream().filter(checkRoles::contains).collect(Collectors.toList());
+            log.info(" 当前用户存在的角色[{}] ",hasRole);
+            return CollectionUtils.isNotEmpty(hasRole);
+        }
+        return false;
+    }
+
+}

+ 162 - 0
poyee-base/src/main/java/com/poyee/base/dto/AppBaseUser.java

@@ -0,0 +1,162 @@
+package com.poyee.base.dto;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.poyee.base.entity.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * <p>
+ *
+ * </p>
+ *
+ * @author lsz
+ * @since 2022-12-09
+ */
+@Data
+@ApiModel(value = "AppBaseUser对象", description = "")
+public class AppBaseUser extends BaseEntity implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty("id")
+    private Integer id;
+
+    @ApiModelProperty("所属程序")
+    private String appid;
+
+    @ApiModelProperty("真实姓名")
+    private String realname;
+
+    @ApiModelProperty("昵称")
+    private String nickname;
+
+    @ApiModelProperty("头像")
+    private String avatar;
+
+    @ApiModelProperty("积分")
+    private Long point;
+
+    @ApiModelProperty("会员等级")
+    private Integer level;
+
+    @ApiModelProperty("生日")
+    private Date birthday;
+
+    @ApiModelProperty("性别")
+    private Integer sex;
+
+    @ApiModelProperty("openid")
+    private String openid;
+
+    @ApiModelProperty("unionid")
+    private String unionid;
+
+    @ApiModelProperty("注册渠道")
+    private String registerChannel;
+
+    @ApiModelProperty("状态")
+    private Integer status;
+
+    @ApiModelProperty("删除标记")
+    private Integer delFlg;
+
+    @ApiModelProperty("备注")
+    private String remark;
+
+    @ApiModelProperty("创建人")
+    private String createBy;
+
+    @ApiModelProperty("创建时间")
+    private Date createTime;
+
+    @ApiModelProperty("更新人")
+    private String updateBy;
+
+    @ApiModelProperty("更新时间")
+    private Date updateTime;
+
+    @ApiModelProperty("账号")
+    private String username;
+
+    @ApiModelProperty("会员成长值")
+    private Integer growthNum;
+
+    @ApiModelProperty("会员码")
+    @TableField("code")
+    private String code;
+
+    @ApiModelProperty("是否接受通知消息,1接受,0拒绝")
+    private Integer notifyFlag;
+
+    @ApiModelProperty("app极光注册id")
+    private String smsRegisterId;
+
+    @TableField("user_id")
+    private Integer userId;
+
+    @TableField("notify_type")
+    private String notifyType;
+
+    @ApiModelProperty("通过人脸识别标志:1")
+    private Integer faceVerify;
+
+    @ApiModelProperty("支付开关")
+    private Integer openPsd;
+
+    @ApiModelProperty("支付密码")
+    private String payPsd;
+
+    @ApiModelProperty("登陆密码")
+    private String loginPsd;
+
+    @ApiModelProperty("是否拒绝自提")
+    private Integer refusePickUp;
+
+    @ApiModelProperty("备用")
+    private String prop1;
+
+    @ApiModelProperty("备用")
+    private String prop2;
+
+    @ApiModelProperty("备用")
+    private String prop3;
+
+    @ApiModelProperty("备用")
+    private String prop4;
+
+    @ApiModelProperty("悬浮窗口开关")
+    private Integer windowOpen;
+
+    @ApiModelProperty("身份证姓名")
+    private String certName;
+
+    @ApiModelProperty("支付宝账号")
+    private String alipayAccount;
+
+    @ApiModelProperty("开票权限")
+    private Integer openInvoice;
+
+    @ApiModelProperty("编辑黑名单")
+    private Integer blacklist;
+
+    @ApiModelProperty("身份证号")
+    private String idCard;
+
+    /**
+     * 用户身份证信息
+     **/
+    @ApiModelProperty("用户身份证信息")
+    private String userCertData;
+
+    private String phone;
+
+    private List<Pays> pays;
+
+}

+ 19 - 0
poyee-base/src/main/java/com/poyee/base/dto/BaseDto.java

@@ -0,0 +1,19 @@
+package com.poyee.base.dto;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 出参
+ */
+@Data
+@ApiModel(description = "基础数据输出对象")
+public class BaseDto {
+
+//    @ApiModelProperty(value = "data_source" )
+//    @TableField(value = "data_source",exist = false)
+//    private String dataSource;
+
+}

+ 44 - 0
poyee-base/src/main/java/com/poyee/base/dto/BaseReq.java

@@ -0,0 +1,44 @@
+package com.poyee.base.dto;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.poyee.annotation.IgnoreSwaggerParameter;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ *
+ */
+@Data
+public class BaseReq {
+
+    @ApiModelProperty(value = "数据版本" ,hidden = true)
+    @TableField(exist = false)
+    private String dbVersion;
+
+    @ApiModelProperty(value = "每页数量",example = "10")
+    @TableField(exist = false)
+    private int pageSize = 10;
+
+    @ApiModelProperty(value = "页码",example = "1")
+    @TableField(exist = false)
+    private int pageNo = 1;
+
+    @ApiModelProperty(hidden = true)
+    @TableField(exist = false)
+    private int limit;
+
+    @ApiModelProperty(value = "排序方式")
+    @TableField(exist = false)
+    @IgnoreSwaggerParameter
+    private String sort;
+
+    @ApiModelProperty(value = "排序字段")
+    @TableField(exist = false)
+    private String sidx;
+
+    public void page(Integer pageNo,Integer pageSize){
+        this.pageNo = pageNo;
+        this.pageSize = pageSize;
+    }
+
+}

+ 59 - 0
poyee-base/src/main/java/com/poyee/base/dto/Page.java

@@ -0,0 +1,59 @@
+package com.poyee.base.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ *
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class Page<T> {
+
+    @ApiModelProperty(value = "总记录数")
+    private Long total;
+    @ApiModelProperty(value = "数据列表")
+    private List<T> rows;
+    @ApiModelProperty(value = "当前页码")
+    private Long pageNo;
+    @ApiModelProperty(value = "当前页条数")
+    private Long size;
+
+    public Page(Long total,List<T> rows) {
+        this.rows = rows;
+        if(Objects.nonNull(total)){
+            this.total = total;
+        }else if (Objects.nonNull(rows)) {
+            this.total = (long) rows.size();
+        }
+    }
+
+    public Page(List<T> rows) {
+        this.rows = rows;
+        if (Objects.nonNull(rows)) {
+            this.total = (long) rows.size();
+        }
+    }
+
+    public Page<T> setRows(List<T> rows) {
+        this.rows = rows;
+        return this;
+    }
+
+    public Page<T> setTotal(Long total) {
+        this.total = total;
+        return this;
+    }
+
+    public Page<T> setPage(Long pageNo) {
+        this.pageNo = pageNo;
+        this.size = Objects.nonNull(rows)?(long) rows.size():0;
+        return this;
+    }
+}

+ 13 - 0
poyee-base/src/main/java/com/poyee/base/dto/Pays.java

@@ -0,0 +1,13 @@
+package com.poyee.base.dto;
+
+import lombok.Data;
+
+/**
+ * 高频支付标记
+ */
+@Data
+public class Pays {
+    private String payType;
+
+    private String paySubType;
+}

+ 116 - 0
poyee-base/src/main/java/com/poyee/base/dto/Result.java

@@ -0,0 +1,116 @@
+package com.poyee.base.dto;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import lombok.Data;
+
+import java.util.Objects;
+
+/**
+ * @param <T>
+ */
+@Data
+public class Result<T> {
+
+    private boolean success = false;
+
+    private Integer code = -1;
+
+    private String message = "fail";
+
+    private Long total;
+
+    private T data;
+
+    public static Result ret(boolean b) {
+        if(b){
+            return Result.success();
+        }else{
+            return Result.error();
+        }
+    }
+
+    public static Result success() {
+        Result result = new Result();
+        result.success = true;
+        result.code = 0;
+        result.message = "success";
+        return result;
+    }
+
+    public Result putData(T data){
+       this.data = data;
+       return this;
+    }
+
+    public static Result success(String msg,Object data){
+        Result result = new Result();
+        result.message = msg;
+        result.success = true;
+        result.code = 0;
+        result.data = data;
+        return result;
+    }
+
+    public static Result success(Object data) {
+        Result result = new Result();
+        result.success = true;
+        result.code = 0;
+        result.message = "success";
+        result.data = data;
+        return result;
+    }
+
+    public static Result success(IPage page) {
+        Result result = new Result();
+        result.success = true;
+        result.code = 0;
+        result.message = "success";
+        result.total = page.getTotal();
+        result.data = page.getRecords();
+        return result;
+    }
+
+    public static Result success(Long total,Object records) {
+        Result result = new Result();
+        result.success = true;
+        result.code = 0;
+        result.message = "success";
+        result.total = total;
+        result.data = records;
+        return result;
+    }
+
+    public static Result error() {
+        return new Result();
+    }
+
+    public static Result error(String message) {
+        Result result = error();
+        result.message = message;
+        result.code = 500;
+        return result;
+    }
+
+    public static Result error(Integer code,String message) {
+        Result result = error();
+        result.message = message;
+        result.code = code;
+        return result;
+    }
+
+    public Result put(String key,Object value){
+        T td = this.data;
+        JSONObject jsonObject;
+        if(Objects.isNull(td)){
+            jsonObject = new JSONObject();
+        }else{
+            jsonObject = JSONObject.parseObject(JSONObject.toJSONString(td));
+        }
+        jsonObject.put(key,value);
+        this.data = (T) jsonObject;
+        return this;
+    }
+
+
+}

+ 74 - 0
poyee-base/src/main/java/com/poyee/base/dto/UserInfo.java

@@ -0,0 +1,74 @@
+package com.poyee.base.dto;
+
+import com.poyee.enums.DataAuth;
+import com.poyee.enums.Roles;
+import lombok.Data;
+import lombok.ToString;
+import org.apache.commons.collections4.CollectionUtils;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 用户信息
+ */
+@Data
+@ToString
+public class UserInfo implements Serializable {
+
+    //id
+    private Integer id;
+    //用户id
+    private String userId;
+    //用户头像
+    private String avatar;
+    //角色编码
+    private String roleCode;
+    //角色编码
+    private String role;
+    //请求时间
+    private Long iat;
+    //过期时间
+    private Long exp;
+    //名称
+    private String displayName;
+
+    private String sub;
+
+    private String iss;
+    //来源
+    private String aud;
+
+    private String nbf;
+
+    private String isFaceVerify;
+
+    private List<String> scope;
+    //商家id
+    private Integer merchantId;
+    //商家头像
+    private String merchantAvatar;
+    //商家名称
+    private String merchantName;
+    /**
+     * 数据权限
+     */
+    private DataAuth dataAuth;
+
+    /**
+     * 是否是商家
+     */
+    private boolean merchant;
+    private String nickname;
+
+    private List<String> partnerRoles;
+
+    public boolean hasPartnerRoleAuth(Roles role){
+        if(CollectionUtils.isEmpty(partnerRoles)){
+            return false;
+        }
+        return partnerRoles.contains(role.getRoleCode());
+    }
+
+
+}

+ 42 - 0
poyee-base/src/main/java/com/poyee/base/entity/BaseEntity.java

@@ -0,0 +1,42 @@
+package com.poyee.base.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ *
+ */
+@Data
+public class BaseEntity {
+
+    @ApiModelProperty(value = "数据来源",hidden = true)
+    @TableField(value = "",exist = false)
+    private String dataSourceVersion;
+
+    @ApiModelProperty(value = "每页数量")
+    @TableField(exist = false)
+    private int pageSize = 10;
+
+    @ApiModelProperty(value = "页码")
+    @TableField(exist = false)
+    private int pageNo = 1;
+
+    @ApiModelProperty(hidden = true)
+    @TableField(exist = false)
+    private int limit;
+
+    @ApiModelProperty(value = "排序方式")
+    @TableField(exist = false)
+    private String sort;
+
+    @ApiModelProperty(value = "排序字段")
+    @TableField(exist = false)
+    private String sidx;
+
+    public void page(Integer pageNo,Integer pageSize){
+        this.pageNo = pageNo;
+        this.pageSize = pageSize;
+    }
+
+}

+ 11 - 0
poyee-base/src/main/java/com/poyee/base/mapper/IBaseMapper.java

@@ -0,0 +1,11 @@
+package com.poyee.base.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.github.yulichang.base.MPJBaseMapper;
+import com.poyee.base.dto.BaseDto;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface IBaseMapper<R extends BaseDto> extends BaseMapper<R>, MPJBaseMapper<R> {
+
+}

+ 182 - 0
poyee-base/src/main/java/com/poyee/base/mapper/provider/BaseProvider.java

@@ -0,0 +1,182 @@
+package com.poyee.base.mapper.provider;
+
+import com.poyee.base.dto.BaseDto;
+import com.poyee.base.dto.BaseReq;
+import com.poyee.base.mapper.provider.domain.LeftJoinInfo;
+import com.poyee.base.mapper.provider.domain.MPage;
+import com.poyee.base.mapper.provider.domain.TableInfo;
+import com.poyee.base.mapper.provider.domain.WhereInfo;
+import com.poyee.base.mapper.provider.util.*;
+import com.poyee.common.exception.ServiceException;
+import com.poyee.enums.DbMethodEnums;
+import com.poyee.util.Convert;
+import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * 提供基础的 SQL 构建功能,包括左连接和 WHERE 条件的处理。
+ */
+@Slf4j
+public abstract class BaseProvider {
+
+    // 数据库操作类型
+    public DbMethodEnums dbMethod;
+    // 表计数器
+    public int tableCount = 0;
+    //
+    public boolean isPage = false;
+    // 存储 insert
+    public Object insert;
+    // 记录 UPDATE
+    public Object update;
+    // 记录 SELECT
+    public Object select;
+    // 主表信息
+    public TableInfo superTable;
+    //分页查询
+    public MPage mPage;
+    //标记是否前端传 排序字段
+    public boolean isFrontSort = false;
+    //分页查询
+    public String pageCountSql;
+    // 记录 INSERT key-value(线程安全)
+    public final Map<String, Object> insertMap = new HashMap<>();
+    // 记录 UPDATE key-value(线程安全)
+    public final Map<String, Object> updateMap = new HashMap<>();
+    // 存储表信息的映射(线程安全)
+    public final Map<String, TableInfo> tableInfos = new ConcurrentHashMap<>();
+    // 记录 WHERE 条件(线程安全)
+    public final List<WhereInfo> whereInfos = new CopyOnWriteArrayList<>();
+    // 记录 SELECT 列(线程安全)
+    public final List<String> selectColumns = new CopyOnWriteArrayList<>();
+    // 记录 LEFT JOIN 信息(线程安全)
+    public final List<LeftJoinInfo> leftJoinInfos = new CopyOnWriteArrayList<>();
+    // 记录 ORDER BY 信息(线程安全)
+    public final Map<Integer,String> orderByMap = new HashMap<>();
+
+    /**
+     * @param req
+     * @param clazz
+     * @param <T>
+     * @param <R>
+     * @return
+     */
+    public <T extends BaseReq,R extends BaseDto> MPage<R> mPage(T req, Class<R> clazz){
+        MPage mPage = new MPage();
+        Map<String,Object> map = new HashMap<>();
+        map.put("req",req);
+        map.put("clazz",clazz);
+        String pageSql = pageWrapper(map);
+        mPage.setCountSql(pageCountSql);
+        mPage.setPageSql(pageSql);
+        return mPage;
+    }
+
+    /**
+     * @param object
+     * @return
+     */
+    public String selectOne(Object object) {
+        // 检查传入的对象是否非空
+        if (Objects.nonNull(object)) {
+            dbMethod = DbMethodEnums.SELECT;
+            // 组装 SELECT 语句
+            SelectUtil.init(this).checkSelectBean(object).initSelect(select);
+            // 生成最终的 SQL 字符串
+            return SqlUtil.init(this).buildOne().toSql();
+        }
+        throw new ServiceException("传入对象为空!");
+    }
+
+    /**
+     * 处理查询对象 生成 SQL 字符串。
+     * @param object
+     * @return
+     */
+    public String selectSum(Object object){
+        // 检查传入的对象是否非空
+        if (Objects.nonNull(object)) {
+            dbMethod = DbMethodEnums.SELECT;
+            // 组装 SELECT 语句
+            SelectUtil.init(this).checkSelectBean(object).initSelect(select);
+            // 生成最终的 SQL 字符串
+            return SqlUtil.init(this).buildSum().toSql();
+        }
+        throw new ServiceException("传入对象为空!");
+    }
+
+    /**
+     * 处理新增对象 生成 SQL 字符串。
+     * @param object
+     * @return
+     */
+    public String save(Object object) {
+        // 检查传入的对象是否非空
+        if (Objects.nonNull(object)) {
+            dbMethod = DbMethodEnums.INSERT;
+            InsertUtil.init(this).checkInsertBean(object).initInsert();
+            // 生成最终的 SQL 字符串
+            String sql = SqlUtil.init(this).toSql();
+            log.info("SQL:{}",sql);
+            return sql;
+        }
+        // 如果传入的对象为空,则返回 null
+        throw new ServiceException("传入的对象为空!");
+    }
+
+    public String update(Object object) {
+        // 检查传入的对象是否非空
+        if (Objects.nonNull(object)) {
+            dbMethod = DbMethodEnums.UPDATE;
+            UpdateUtil.init(this).checkUpdateBean(object).initUpdate();
+            // 生成最终的 SQL 字符串
+            return SqlUtil.init(this).toSql();
+        }
+        throw new ServiceException("传入的对象为空!");
+    }
+
+    /**
+     *
+     * @param object
+     * @return
+     */
+    public String pageWrapper(Object object) {
+        // 检查传入的对象是否非空
+        if (Objects.nonNull(object)) {
+            dbMethod = DbMethodEnums.SELECT;
+            isPage = true;
+            // 组装 SELECT 语句
+            SelectUtil.init(this).checkSelectBean(object).initSelect(select);
+            // 生成最终的 SQL 字符串
+            return SqlUtil.init(this).buildPage().toSql();
+        }
+        // 如果传入的对象为空,则返回 null
+        throw new ServiceException("传入的对象为空!");
+    }
+
+    /**
+     * 处理对象的左连接和 WHERE 条件,生成 SQL 字符串。
+     *
+     * @param object 需要处理的对象
+     * @return 生成的 SQL 字符串
+     */
+    public String leftJoinWrapper(Object object) {
+        // 检查传入的对象是否非空
+        if (Objects.nonNull(object)) {
+            dbMethod = DbMethodEnums.SELECT;
+            // 组装 SELECT 语句
+            SelectUtil.init(this).checkSelectBean(object).initSelect(select);
+            // 生成最终的 SQL 字符串
+            return SqlUtil.init(this).toSql();
+        }
+        // 如果传入的对象为空,则返回 null
+        throw new ServiceException("传入的对象为空!");
+    }
+
+
+}

+ 29 - 0
poyee-base/src/main/java/com/poyee/base/mapper/provider/ErrMessageContent.java

@@ -0,0 +1,29 @@
+package com.poyee.base.mapper.provider;
+
+public class ErrMessageContent {
+    //"对象不能为空"
+    public static final String ERROR_MESSAGE_OBJECT_NULL = "{0}对象不能为空";
+    //"构建{0}SQL时发生错误"
+    public static final String ERROR_MESSAGE_TABLE_NAME_MISSING = "{0}对象必须包含@TableName注解";
+    //"构建{0}SQL时发生错误"
+    public static final String ERROR_MESSAGE_BUILD_SQL = "构建{0}SQL时发生错误";
+    //"没有有效的{0}字段"
+    public static final String ERROR_MESSAGE_BEAN_NULL = "{0}对象或映射为空";
+    //"没有有效的{0}字段"
+    public static final String ERROR_MESSAGE_OPERA_NULL = "没有有效的{0}字段";
+    //"访问字段时发生错误"
+    public static final String ERROR_MESSAGE_FIELD_ACCESS = "访问字段时发生错误";
+    //非法参数错误
+    public static final String ERROR_MESSAGE_ILLEGAL_ARGUMENT = "非法参数";
+    //"传入的对象为空!"
+    public static final String ERROR_MESSAGE_OBJECT_IS_NULL = "传入的对象为空!";
+    //"表名注解缺失!"
+    public static final String ERROR_MESSAGE_TABLE_NAME_MISSING_2 = "表名注解缺失!";
+    //"表名不能为空!"
+    public static final String ERROR_MESSAGE_TABLE_NAME_IS_NULL = "表名不能为空!";
+
+    public static String getErrorMessage(String message, Object... args) {
+        return String.format(message, args);
+    }
+
+}

+ 129 - 0
poyee-base/src/main/java/com/poyee/base/mapper/provider/IBaseProvider.java

@@ -0,0 +1,129 @@
+package com.poyee.base.mapper.provider;
+
+import com.poyee.base.dto.BaseDto;
+import com.poyee.base.dto.BaseReq;
+import com.poyee.base.dto.Page;
+import com.poyee.base.mapper.provider.domain.MPage;
+import com.poyee.util.ObjectUtil;
+import org.apache.ibatis.annotations.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @param <T>
+ * @param <R>
+ */
+public interface IBaseProvider<T extends BaseReq, R extends BaseDto> {
+    @SelectProvider(type = FinalProviderSql.class, method = "leftJoinWrapper")
+    List<Map<String, Object>> selectListMap(T req, Class<R> clazz);
+
+    @SelectProvider(type = FinalProviderSql.class, method = "pageCountSql")
+    long pageCount(String sql);
+
+    @SelectProvider(type = FinalProviderSql.class, method = "pageSql")
+    List<Map<String, Object>> page(String sql);
+
+    @SelectProvider(type = FinalProviderSql.class, method = "selectOne")
+    Map<String, Object> selectOneMap(T req, Class<R> clazz);
+
+    @SelectProvider(type = FinalProviderSql.class, method = "selectSum")
+    Map<String, Object> selectSumMap(T req, Class<R> clazz);
+
+    @InsertProvider(type = FinalProviderSql.class, method = "save")
+    @Options(useGeneratedKeys = true, keyProperty = "id")
+//    @SelectKey(statement = "select max(id) from promotion_share_info", keyProperty = "id", before = false, resultType = Long.class)
+    int save(T req);
+
+    @UpdateProvider(type = FinalProviderSql.class, method = "update")
+    int update(T req);
+
+
+    /**
+     * @param clazz
+     * @param req
+     * @return
+     */
+    default R selectOne(T req, Class<R> clazz) {
+        Map<String, Object> resultMaps = selectOneMap(req, clazz);
+        if (resultMaps != null && !resultMaps.isEmpty()) {
+            return ObjectUtil.mapToBeanProvider(resultMaps, clazz);
+        }
+        try {
+            return clazz.newInstance();
+        } catch (InstantiationException | IllegalAccessException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 求和
+     * @param req
+     * @param clazz
+     * @return
+     */
+    default R sum(T req, Class<R> clazz){
+        Map<String, Object> resultMaps = selectSumMap(req, clazz);
+        if (resultMaps != null && !resultMaps.isEmpty()) {
+            return ObjectUtil.mapToBeanProvider(resultMaps, clazz);
+        }
+        try {
+            return clazz.newInstance();
+        } catch (InstantiationException | IllegalAccessException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * @param req
+     * @param clazz
+     * @return
+     */
+    default List<R> selectList(T req, Class<R> clazz) {
+        List<Map<String, Object>> resultMaps = selectListMap(req, clazz);
+        if (resultMaps != null && resultMaps.size() > 0) {
+            return ObjectUtil.mapToListProvider(resultMaps, clazz);
+        }
+        return new ArrayList<>();
+    }
+
+    /**
+     * @param req
+     * @param clazz
+     * @return
+     */
+    default Page<R> selectPage(T req, Class<R> clazz) {
+        MPage<R> mPage = new FinalProviderSql().mPage(req, clazz);
+        long total = pageCount(mPage.getCountSql());
+        List<R> records = null;
+        if (total > 0) {
+            List<Map<String, Object>> pageMaps = page(mPage.getPageSql());
+            records = ObjectUtil.mapToListProvider(pageMaps, clazz);
+        }
+        return new Page<>(total, records).setPage((long) req.getPageNo());
+    }
+
+    /**
+     * 拼接sql
+     */
+    class FinalProviderSql extends BaseProvider {
+        /**
+         * @param sql
+         * @return
+         */
+        public String pageCountSql(String sql) {
+            return sql;
+        }
+
+        /**
+         * @param sql
+         * @return
+         */
+        public String pageSql(String sql) {
+            return sql;
+        }
+    }
+}

+ 27 - 0
poyee-base/src/main/java/com/poyee/base/mapper/provider/domain/LeftJoinInfo.java

@@ -0,0 +1,27 @@
+package com.poyee.base.mapper.provider.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class LeftJoinInfo {
+
+    public LeftJoinInfo(TableInfo tableInfo, TableInfo leftTableInfo) {
+        this.tableInfo = tableInfo;
+        this.leftTableInfo = leftTableInfo;
+    }
+    // 表信息
+    private TableInfo tableInfo;
+    // 关联表信息
+    private TableInfo leftTableInfo;
+    //关联条件
+    private String fieldName;
+    // 关联字段
+    private String leftFieldName;
+    // 别名
+    private String alias;
+
+}

+ 120 - 0
poyee-base/src/main/java/com/poyee/base/mapper/provider/domain/MPage.java

@@ -0,0 +1,120 @@
+package com.poyee.base.mapper.provider.domain;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Data
+public class MPage<T> implements IPage<T> {
+
+    private static final long serialVersionUID = 1L;
+    protected List<T> records;
+    protected long total;
+    protected long size;
+    protected long current;
+    protected List<OrderItem> orders;
+    protected boolean optimizeCountSql;
+    protected boolean searchCount;
+    protected boolean optimizeJoinOfCountSql;
+    protected String countId;
+    protected Long maxLimit;
+
+    protected String countSql;
+
+    protected String pageSql;
+
+    public MPage() {
+        this.records = Collections.emptyList();
+        this.total = 0L;
+        this.size = 10L;
+        this.current = 1L;
+        this.orders = new ArrayList();
+        this.optimizeCountSql = true;
+        this.searchCount = true;
+        this.optimizeJoinOfCountSql = true;
+    }
+    public MPage(long current, long size) {
+        this(current, size, 0L);
+    }
+
+    public MPage(long current, long size, long total) {
+        this(current, size, total, true);
+    }
+
+    public MPage(long current, long size, boolean searchCount) {
+        this(current, size, 0L, searchCount);
+    }
+
+    public MPage(long current, long size, long total, boolean searchCount) {
+        this.records = Collections.emptyList();
+        this.total = 0L;
+        this.size = 10L;
+        this.current = 1L;
+        this.orders = new ArrayList();
+        this.optimizeCountSql = true;
+        this.searchCount = true;
+        this.optimizeJoinOfCountSql = true;
+        if (current > 1L) {
+            this.current = current;
+        }
+
+        this.size = size;
+        this.total = total;
+        this.searchCount = searchCount;
+    }
+
+    @Override
+    public List<OrderItem> orders() {
+        return this.orders;
+    }
+
+    @Override
+    public List<T> getRecords() {
+        return this.records;
+    }
+
+    @Override
+    public IPage<T> setRecords(List<T> records) {
+        this.records = records;
+        return this;
+    }
+
+    @Override
+    public long getTotal() {
+        return this.total;
+    }
+
+    @Override
+    public IPage<T> setTotal(long total) {
+        this.total = total;
+        return this;
+    }
+
+    @Override
+    public long getSize() {
+        return this.size;
+    }
+
+    @Override
+    public IPage<T> setSize(long size) {
+        this.size = size;
+        return this;
+    }
+
+    @Override
+    public long getCurrent() {
+        return this.current;
+    }
+
+    @Override
+    public IPage<T> setCurrent(long current) {
+        this.current = current;
+        return this;
+    }
+
+
+}

+ 16 - 0
poyee-base/src/main/java/com/poyee/base/mapper/provider/domain/OrderByInfo.java

@@ -0,0 +1,16 @@
+package com.poyee.base.mapper.provider.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class OrderByInfo {
+
+    private Integer index;
+    private String column;
+    private String sortType;
+
+}

+ 24 - 0
poyee-base/src/main/java/com/poyee/base/mapper/provider/domain/TableInfo.java

@@ -0,0 +1,24 @@
+package com.poyee.base.mapper.provider.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TableInfo {
+    // 实体类名
+    private String className;
+    // 实体类
+    private Class<?> clazz;
+    // 表名
+    private String tableName;
+    // 别名
+    private String alias;
+    // 索引
+    private Integer idx;
+    // 主键
+    private String primaryKey;
+
+}

+ 35 - 0
poyee-base/src/main/java/com/poyee/base/mapper/provider/domain/WhereInfo.java

@@ -0,0 +1,35 @@
+package com.poyee.base.mapper.provider.domain;
+
+import com.poyee.enums.FieldOperator;
+import com.poyee.enums.FieldType;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class WhereInfo {
+
+    public WhereInfo(TableInfo tableInfo){
+        this.tableInfo = tableInfo;
+    }
+    // 表信息
+    private TableInfo tableInfo;
+    // 字段
+    private String column;
+    // 值
+    private Object value;
+    // 结束值 (between 时使用)
+    private Object endValue;
+    /**
+     * 操作符
+     * @see FieldOperator
+     */
+    private FieldOperator operator;
+    /**
+     * 字段类型
+     * @see FieldType
+     */
+    private FieldType fieldType;
+}

+ 112 - 0
poyee-base/src/main/java/com/poyee/base/mapper/provider/util/FormatValueUtil.java

@@ -0,0 +1,112 @@
+package com.poyee.base.mapper.provider.util;
+
+import com.poyee.base.mapper.provider.domain.WhereInfo;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.List;
+
+/**
+ *  格式化值工具类
+ */
+@Slf4j
+public class FormatValueUtil {
+
+    /**
+     * 构建 IN 或 NOT IN 子句。
+     *
+     * @param whereInfo WHERE 信息
+     * @return 构建的 IN 或 NOT IN 子句
+     */
+    private static String buildInClause(WhereInfo whereInfo) {
+        // 如果值为 null,则返回 "NULL"
+        if (whereInfo.getValue() == null) {
+            return "NULL";
+        }
+        StringBuilder inClause = new StringBuilder("(");
+        // 如果值是字符串类型,则按逗号分割成多个值
+        if (whereInfo.getValue() instanceof String) {
+            String[] values = ((String) whereInfo.getValue()).split(",");
+            for (String value : values) {
+                // 对每个值进行空值和空字符串检查,并构建 IN 子句
+                if (value != null && !value.trim().isEmpty()) {
+                    inClause.append("'").append(escapeValue(value.trim())).append("',");
+                }
+            }
+        } else if (whereInfo.getValue() instanceof List) {
+            // 如果值是 List 类型,则遍历列表中的每个值
+            for (Object value : (List<?>) whereInfo.getValue()) {
+                // 对每个值进行空值检查,并构建 IN 子句
+                if (value != null) {
+                    inClause.append("'").append(escapeValue(value)).append("',");
+                }
+            }
+        } else if (whereInfo.getValue() instanceof Object[]) {
+            // 如果值是数组类型,则遍历数组中的每个值
+            for (Object value : (Object[]) whereInfo.getValue()) {
+                // 对每个值进行空值检查,并构建 IN 子句
+                if (value != null) {
+                    inClause.append("'").append(escapeValue(value)).append("',");
+                }
+            }
+        }
+        // 如果 IN 子句长度大于 1,则移除最后的逗号
+        if (inClause.length() > 1) {
+            inClause.setLength(inClause.length() - 1);
+        }
+        inClause.append(")");
+        return inClause.toString();
+    }
+
+    /**
+     * @param whereInfo
+     * @return
+     */
+    private static String buildBetweenClause(WhereInfo whereInfo) {
+        return "'" + escapeValue(whereInfo.getValue()) + "' AND '" + escapeValue(whereInfo.getEndValue()) + "'";
+    }
+    /**
+     * 根据操作符格式化字符串值。
+     *
+     * @param whereInfo WHERE 信息
+     * @return 格式化后的字符串值
+     */
+    public static String formatStringValue(WhereInfo whereInfo) {
+        // 根据不同的操作符格式化字符串值
+        switch (whereInfo.getOperator()) {
+            case LIKE:
+                // 对于LIKE操作符,前后添加百分号并转义值
+                return "'%" + escapeValue(whereInfo.getValue()) + "%'";
+            case LLIKE:
+                // 对于LLIKE操作符,前面添加百分号并转义值
+                return "'%" + escapeValue(whereInfo.getValue()) + "'";
+            case RLIKE:
+                // 对于RLIKE操作符,后面添加百分号并转义值
+                return "'" + escapeValue(whereInfo.getValue()) + "%'";
+            case IN:
+            case NOTIN:
+                // 对于IN和NOTIN操作符,调用buildInClause方法构建IN子句
+                return buildInClause(whereInfo);
+            case BETWEEN:
+            case NOTBETWEEN:
+                // 对于IN和NOTIN操作符,调用buildInClause方法构建IN子句
+                return buildBetweenClause(whereInfo);
+            default:
+                // 对于其他操作符,直接转义值并添加单引号
+                return "'" + escapeValue(whereInfo.getValue()) + "'";
+        }
+    }
+
+    /**
+     * 转义特殊字符以防止 SQL 注入。
+     *
+     * @param value 值
+     * @return 转义后的值
+     */
+    public static String escapeValue(Object value) {
+        if (value == null) {
+            return "NULL";
+        }
+        return String.valueOf(value).replace("'", "''");
+    }
+
+}

+ 120 - 0
poyee-base/src/main/java/com/poyee/base/mapper/provider/util/InsertUtil.java

@@ -0,0 +1,120 @@
+package com.poyee.base.mapper.provider.util;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.base.mapper.provider.BaseProvider;
+import com.poyee.common.exception.ServiceException;
+import com.poyee.util.DateUtils;
+import lombok.extern.slf4j.Slf4j;
+
+import java.lang.reflect.Field;
+import java.util.Date;
+import java.util.Map;
+import java.util.Objects;
+
+import static com.poyee.base.mapper.provider.ErrMessageContent.*;
+
+@Slf4j
+public class InsertUtil {
+
+    private BaseProvider parent;
+
+    private InsertUtil(BaseProvider parent) {
+        this.parent = parent;
+    }
+
+    public static InsertUtil init(BaseProvider parent) {
+        return new InsertUtil(parent);
+    }
+
+    /**
+     * 检查插入对象是否合法
+     *
+     * @param object 插入对象
+     * @return 自身实例
+     */
+    public InsertUtil checkInsertBean(Object object) {
+        if (object == null) {
+            log.warn("对象不能为空");
+            throw new ServiceException(ERROR_MESSAGE_OBJECT_NULL);
+        }
+        Class<?> aClass = object.getClass();
+        if (!aClass.isAnnotationPresent(TableName.class)) {
+            log.warn("对象必须包含@TableName注解");
+            throw new ServiceException(ERROR_MESSAGE_TABLE_NAME_MISSING);
+        }
+        TableName tableNameAnnotation = aClass.getAnnotation(TableName.class);
+        String tableName = tableNameAnnotation.value();
+        if (tableName == null || tableName.trim().isEmpty()) {
+            log.warn("表名不能为空");
+            throw new ServiceException(ERROR_MESSAGE_TABLE_NAME_IS_NULL);
+        }
+
+        // 初始化表信息
+        TableInfoUtil.init(parent).initTableInfo(aClass);
+        parent.superTable = parent.tableInfos.get(aClass.getName());
+
+        parent.insert = object;
+        return this;
+    }
+
+    /**
+     * 初始化插入操作
+     */
+    public void initInsert() {
+        Object insert = parent.insert;
+        if (insert == null || parent.insertMap == null) {
+            log.warn("插入对象或映射为空,无法生成SQL。对象: {}", insert);
+            throw new ServiceException(getErrorMessage(ERROR_MESSAGE_BEAN_NULL,"插入"));
+        }
+
+        try {
+            Map<String, Object> insertMap = parent.insertMap;
+            insertMap.clear(); // 清空旧数据
+            processFields(insert, insertMap);
+
+            if (insertMap.isEmpty()) {
+                log.warn("没有有效的插入字段,对象: {}", insert);
+                throw new ServiceException(getErrorMessage(ERROR_MESSAGE_OPERA_NULL,"插入"));
+            }
+        } catch (IllegalAccessException e) {
+            log.error("访问字段时发生错误", e);
+            throw new ServiceException(ERROR_MESSAGE_FIELD_ACCESS);
+        } catch (IllegalArgumentException e) {
+            log.error("非法参数错误", e);
+            throw new ServiceException(ERROR_MESSAGE_ILLEGAL_ARGUMENT);
+        } catch (Exception e) {
+            log.error(ERROR_MESSAGE_BUILD_SQL, e);
+            throw new ServiceException(ERROR_MESSAGE_BUILD_SQL);
+        }
+    }
+
+    /**
+     * 处理字段并填充到映射中
+     *
+     * @param object    对象
+     * @param insertMap 插入映射
+     * @throws IllegalAccessException 如果字段访问失败
+     */
+    private void processFields(Object object, Map<String, Object> insertMap) throws IllegalAccessException {
+        Class<?> aClass = object.getClass();
+        Field[] declaredFields = aClass.getDeclaredFields();
+
+        for (Field field : declaredFields) {
+            field.setAccessible(true);
+            if (field.isAnnotationPresent(TableField.class)) {
+                TableField tableField = field.getAnnotation(TableField.class);
+                if (tableField.exist()) {
+                    Object value = field.get(object);
+                    if ( Objects.nonNull(value)) {
+                        if(value instanceof Date){
+                            insertMap.put(tableField.value(), DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, (Date) value));
+                        }else{
+                            insertMap.put(tableField.value(), value);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}

+ 67 - 0
poyee-base/src/main/java/com/poyee/base/mapper/provider/util/JoinUtil.java

@@ -0,0 +1,67 @@
+package com.poyee.base.mapper.provider.util;
+
+import com.poyee.annotation.db.LeftJoin;
+import com.poyee.base.mapper.provider.BaseProvider;
+import com.poyee.base.mapper.provider.domain.LeftJoinInfo;
+import lombok.extern.slf4j.Slf4j;
+
+import java.lang.reflect.Field;
+import java.util.List;
+
+@Slf4j
+public class JoinUtil {
+
+    public static JoinUtil init(BaseProvider baseProvider){
+        return new JoinUtil(baseProvider);
+    }
+
+    private JoinUtil(BaseProvider baseProvider){
+        this.parent = baseProvider;
+    }
+    private BaseProvider parent;
+
+
+    /**
+     * 初始化左连接信息
+     *
+     * @param aClass 实体类类对象,用于获取表信息
+     * @param leftJoinInfos 左连接信息列表,存储处理后的左连接信息
+     * @param declaredField 声明字段,检查是否包含LeftJoin注解
+     */
+    public void initLeftJoin(Class<?> aClass, List<LeftJoinInfo> leftJoinInfos, Field declaredField) {
+        // 检查字段是否包含LeftJoin注解
+        if (declaredField.isAnnotationPresent(LeftJoin.class)) {
+            // 获取字段上的LeftJoin注解
+            LeftJoin leftJoin = declaredField.getAnnotation(LeftJoin.class);
+            // 创建一个新的左连接信息对象
+            LeftJoinInfo leftJoinInfo = new LeftJoinInfo();
+
+            // 获取注解中指定的连接表类
+            Class<?> table = leftJoin.table();
+            // 如果父对象的表信息映射中不包含此表,初始化该表的信息
+            if (!parent.tableInfos.containsKey(table.getName())) {
+                TableInfoUtil.init(parent).initTableInfo(table);
+            }
+            // 设置左连接信息中的表信息和别名
+            leftJoinInfo.setTableInfo(parent.tableInfos.get(table.getName()));
+            leftJoinInfo.setAlias(parent.tableInfos.get(table.getName()).getAlias());
+
+            // 确定左表,如果注解中未指定则使用传入的实体类
+            Class<?> leftTable = leftJoin.leftTable() != void.class ? leftJoin.leftTable() : aClass;
+            // 如果父对象的表信息映射中不包含左表,初始化左表的信息
+            if (!parent.tableInfos.containsKey(leftTable.getName())) {
+                TableInfoUtil.init(parent).initTableInfo(leftTable);
+            }
+            // 设置左连接信息中的左表信息
+            leftJoinInfo.setLeftTableInfo(parent.tableInfos.get(leftTable.getName()));
+
+            // 设置左连接信息中的字段名和左表字段名
+            leftJoinInfo.setFieldName(leftJoin.fieldName());
+            leftJoinInfo.setLeftFieldName(leftJoin.leftFieldName());
+
+            // 将处理后的左连接信息添加到列表中
+            leftJoinInfos.add(leftJoinInfo);
+        }
+    }
+
+}

+ 285 - 0
poyee-base/src/main/java/com/poyee/base/mapper/provider/util/SelectUtil.java

@@ -0,0 +1,285 @@
+package com.poyee.base.mapper.provider.util;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.poyee.annotation.db.*;
+import com.poyee.base.mapper.provider.BaseProvider;
+import com.poyee.base.mapper.provider.domain.MPage;
+import com.poyee.base.mapper.provider.domain.TableInfo;
+import com.poyee.common.exception.ServiceException;
+import com.poyee.util.Convert;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static com.poyee.enums.SqlEnums.sum;
+
+@Slf4j
+public class SelectUtil {
+
+    private BaseProvider parent;
+
+    private SelectUtil(BaseProvider baseProvider) {
+        this.parent = baseProvider;
+    }
+
+    public static SelectUtil init(BaseProvider baseProvider) {
+        return new SelectUtil(baseProvider);
+    }
+    /**
+     * @param object
+     * @return
+     */
+    @NotNull
+    public SelectUtil checkSelectBean(Object object) {
+        Object param;
+        Object select = null; // return class
+        // 判断 object 是否是 Map
+        if (object instanceof Map) {
+            Map<String, Object> map = (Map<String, Object>) object;
+            select = map.get("clazz");
+            param = map.get("req");
+        } else {
+            param = object;
+        }
+        // 如果无法定位返回值,则抛出异常
+        if (Objects.isNull(select)) {
+            throw new ServiceException("无法定位返回值!");
+        }
+        // 获取参数对象的类信息
+        Class<?> aClass = param.getClass();
+        // 初始化表信息
+        TableInfoUtil.init(parent).initTableInfo(aClass);
+        parent.superTable = parent.tableInfos.get(aClass.getName());
+        // 获取超类的所有字段处理分页信息
+        if(parent.isPage) {
+            long page = 0;
+            long size = 10;
+            Class<?> superclass = aClass.getSuperclass();
+            try {
+                Field pageNoFields = superclass.getDeclaredField("pageNo");
+                pageNoFields.setAccessible(true);
+                page = Optional.ofNullable(Convert.toLong(pageNoFields.get(param)))
+                               .orElse(0L);
+                Field pageSizeFields = superclass.getDeclaredField("pageSize");
+                pageSizeFields.setAccessible(true);
+                size = Optional.ofNullable(Convert.toLong(pageSizeFields.get(param)))
+                               .orElse(10L);
+            } catch (NoSuchFieldException | IllegalAccessException e) {
+                throw new RuntimeException(e);
+            }
+            //设置 分页信息
+            parent.mPage = new MPage(page, size);
+            try {
+                //处理排序字段
+                Field sidxField = superclass.getDeclaredField("sidx");
+                sidxField.setAccessible(true);
+                Object sidxObj = sidxField.get(param);
+                if(Objects.nonNull(sidxObj) && StringUtils.isNotBlank(String.valueOf(sidxObj))){
+                    parent.isFrontSort = true;
+                    Field sortField = superclass.getDeclaredField("sort");
+                    sortField.setAccessible(true);
+                    String sort = "asc";
+                    if(Objects.nonNull(sortField.get(param))){
+                        sort = sortField.get(param).toString();
+                    }
+                    parent.orderByMap.put(Objects.equals(sort,"desc") ? -1 : 0 , String.valueOf(sidxObj));
+                }
+            }catch (NoSuchFieldException | IllegalAccessException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        //设置 排序信息
+        Field[] declaredFields = aClass.getDeclaredFields();
+        for (Field declaredField : declaredFields) {
+            declaredField.setAccessible(true);
+            // 构建 WHERE 条件
+            WhereUtil.init(parent).build(param, aClass, parent.whereInfos, declaredField);
+            // 构建 LEFT JOIN 信息
+            JoinUtil.init(parent).initLeftJoin(aClass, parent.leftJoinInfos, declaredField);
+        }
+        parent.select = select;
+        return this;
+    }
+
+    /**
+     * 初始化选择对象的方法
+     * 该方法用于处理传入的选择对象,提取其字段信息,并根据注解确定查询列
+     *
+     * @param select 选择对象,可以是任何类,但通常用于具有@TableField和@Select注解的类
+     */
+    public void initSelect(Object select) {
+        // 检查选择对象是否非空
+        if (Objects.isNull(select)) {
+            log.warn("初始化选择对象失败,传入的对象为 null");
+            throw new ServiceException("初始化选择对象失败,传入的对象为 null");
+        }
+
+        try {
+            // 获取选择对象的实际类信息
+            Class<?> clazz = (Class<?>) select;
+            // 获取类的所有声明的字段
+            Field[] declaredFields = clazz.getDeclaredFields();
+            // 遍历字段
+            for (Field field : declaredFields) {
+                // 设置字段可访问,以处理私有字段
+                field.setAccessible(true);
+                if (!field.isAnnotationPresent(Select.class)
+                        && (field.isAnnotationPresent(TableField.class) || field.isAnnotationPresent(TableId.class))) {
+                    // 检查字段是否包含TableField注解
+                    processTableFieldAnnotation(field);
+                } else if (field.isAnnotationPresent(Select.class)) {
+                    processSelectAnnotation(field);
+                }
+            }
+        } catch (Exception e) {
+            log.error("初始化选择对象时发生异常", e);
+        }
+    }
+
+    /**
+     * 处理 TableField 注解的逻辑
+     *
+     * @param field 字段对象
+     */
+    private void processTableFieldAnnotation(Field field) {
+        try {
+            TableInfo superTable = parent.superTable;
+            TableId tableId = field.getAnnotation(TableId.class);
+            if (Objects.nonNull(tableId)) {
+                String selectSql = superTable.getAlias() + "." + tableId.value() + " AS " + field.getName();
+                checkSelectSql(selectSql, field, superTable, tableId.value());
+            }
+            TableField tableField = field.getAnnotation(TableField.class);
+            if (Objects.nonNull(tableField) && tableField.exist()) {
+                String selectSql;
+                if(field.isAnnotationPresent(Sum.class)){
+                    Sum sum = field.getAnnotation(Sum.class);
+                    CaseWhen[] caseWhens = sum.caseWhen();
+                    String sumFieldSql = "";
+                    if(caseWhens.length > 0){
+                        sumFieldSql = buildCaseWhen( superTable, caseWhens) ;
+                    } else {
+                        sumFieldSql = superTable.getAlias() + "." + tableField.value();
+                    }
+                    selectSql = "COALESCE(SUM(" + sumFieldSql + "),0)" + " AS " + field.getName();
+                } else if(field.isAnnotationPresent(Count.class)) {
+                    Count count = field.getAnnotation(Count.class);
+                    CaseWhen[] caseWhens = count.caseWhen();
+                    String countFieldSql = "";
+                    if(caseWhens.length > 0){
+                        countFieldSql = (count.distinct()?"DISTINCT":"")+" "+buildCaseWhen( superTable, caseWhens);
+                    }else{
+                        countFieldSql = (count.distinct()?"DISTINCT":"")+" "+superTable.getAlias() + "." + tableField.value();
+                    }
+                    selectSql = "COALESCE(COUNT( "+countFieldSql+"),0)" + " AS " + field.getName();
+                } else {
+                    selectSql = superTable.getAlias() + "." + tableField.value() + " AS " + field.getName();
+                }
+                checkSelectSql(selectSql, field, superTable, tableField.value());
+            }
+        } catch (Exception e) {
+            log.error("处理 TableField 注解时发生异常", e);
+        }
+    }
+
+    /**
+     * @param superTable
+     * @param field
+     * @param caseWhens
+     * @return
+     */
+    private String buildCaseWhen(TableInfo superTable, CaseWhen[] caseWhens) {
+        StringBuilder caseSql = new StringBuilder();
+        StringBuilder elseStr = new StringBuilder();
+        AtomicBoolean isFirst = new AtomicBoolean(true);
+        Arrays.asList(caseWhens).forEach(caseWhen -> {
+            if (caseWhen.isElse()) {
+                elseStr.append(" ELSE ").append(caseWhen.then());
+            }else{
+                // 判断是否是第一个条件
+                if(isFirst.get()){
+                    caseSql.append(" CASE WHEN ");
+                    isFirst.set(false);
+                } else {
+                    caseSql.append(" WHEN ");
+                }
+                //  WHEN 条件
+                // 判断条件 - key
+                caseSql.append(superTable.getAlias() + "." + caseWhen.when());
+                //  THEN 值
+                caseSql.append(" THEN ");
+                // 判断值类型
+                switch (caseWhen.valueType()){
+                    case TABLE_COLUMN:
+                        caseSql.append(superTable.getAlias() + "." + caseWhen.then());
+                        break;
+                    case CONSTANT:
+                    case SQL_EXPRESSION:
+                        caseSql.append(caseWhen.then());
+                        break;
+                }
+            }
+        });
+        caseSql.append(elseStr.append(" END "));
+        String selectSql = caseSql.toString();
+        log.info("构建CASE WHEN SQL: {}", caseSql);
+        return selectSql;
+    }
+
+    /**
+     * 检查选择SQL
+     * @param selectSql
+     * @param field
+     * @param tableInfo
+     * @param fieldName
+     */
+    private void checkSelectSql(String selectSql, Field field, TableInfo tableInfo, String fieldName) {
+        parent.selectColumns.add(selectSql);
+        if (!parent.isFrontSort && field.isAnnotationPresent(OrderBy.class)) {
+            OrderBy orderBy = field.getAnnotation(OrderBy.class);
+            parent.orderByMap.put(orderBy.index(), tableInfo.getAlias() + "." + fieldName + " " + orderBy.sortType().getValue());
+        }
+        if (parent.isFrontSort && (parent.orderByMap.containsKey(-1) || parent.orderByMap.containsKey(0))) {
+            int kk = parent.orderByMap.containsKey(-1) ? -1 : 0;
+            if (Objects.equals(field.getName(), parent.orderByMap.get(kk))) {
+                parent.orderByMap.put(kk, tableInfo.getAlias() + "." + fieldName + " " + (kk == -1 ? "desc" : "asc"));
+            }
+        }
+    }
+
+    /**
+     * 处理 Select 注解的逻辑
+     *
+     * @param field 字段对象
+     */
+    private void processSelectAnnotation(Field field) {
+        try {
+            Select selectAnnotation = field.getAnnotation(Select.class);
+            if (Objects.nonNull(selectAnnotation.table())) {
+                String tableName = selectAnnotation.table()
+                                                   .getName();
+                TableInfo tableInfo = parent.tableInfos.get(tableName);
+                if(Objects.isNull(tableInfo)){
+                    TableInfoUtil.init(parent).initTableInfo(selectAnnotation.table());
+                    tableInfo = parent.tableInfos.get(tableName);
+                }
+                if (Objects.nonNull(tableInfo)) {
+                    String selectSql = tableInfo.getAlias() + "." + selectAnnotation.fieldName() + " AS " + field.getName();
+                    checkSelectSql(selectSql, field, tableInfo, selectAnnotation.fieldName());
+                    parent.selectColumns.add(selectSql);
+                } else {
+                    log.warn("未找到表名 {} 对应的 TableInfo 对象", tableName);
+                }
+            }
+        } catch (Exception e) {
+            log.error("处理 Select 注解时发生异常", e);
+        }
+    }
+
+}

+ 419 - 0
poyee-base/src/main/java/com/poyee/base/mapper/provider/util/SqlUtil.java

@@ -0,0 +1,419 @@
+package com.poyee.base.mapper.provider.util;
+
+import com.poyee.base.mapper.provider.BaseProvider;
+import com.poyee.base.mapper.provider.domain.LeftJoinInfo;
+import com.poyee.base.mapper.provider.domain.WhereInfo;
+import com.poyee.common.exception.ServiceException;
+import com.poyee.enums.DbMethodEnums;
+import com.poyee.enums.FieldOperator;
+import com.poyee.enums.FieldType;
+import com.poyee.enums.SqlEnums;
+import com.poyee.util.ObjectUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ *  SQL 生成工具类
+ */
+@Slf4j
+public class SqlUtil {
+    // SQL 类型
+    private SqlEnums type = SqlEnums.all;
+    // 父对象
+    private BaseProvider parent;
+
+    public static SqlUtil init(BaseProvider baseProvider){
+        return new SqlUtil( baseProvider);
+    }
+
+    /**
+     * @return
+     */
+    public SqlUtil buildPage(){
+        this.type = SqlEnums.page;
+        return this;
+    }
+
+    /**
+     * @param baseProvider
+     */
+    private SqlUtil(BaseProvider baseProvider){
+        this.parent = baseProvider;
+    }
+
+    /**
+     * 根据已收集的信息生成最终的 SQL 字符串。
+     *
+     * @return 生成的 SQL 字符串
+     */
+    public String toSql() {
+        String sqlString = "";
+        switch (parent.dbMethod){
+            case SELECT:
+                sqlString = buildSelectSql();
+                break;
+            case INSERT:
+                sqlString = buildInsertSql();
+                break;
+            case UPDATE:
+                sqlString = buildUpdateSql();
+                break;
+            default:
+                log.warn("No select columns or parent is null, returning empty SQL.");
+                throw new ServiceException("No select columns or parent is null.");
+        }
+        return sqlString;
+    }
+
+    /**
+     * 构建插入 SQL 语句
+     *
+     * @return 插入 SQL 语句
+     */
+    private String buildInsertSql() {
+        // 非空检查
+        if (parent == null || parent.insertMap == null || parent.insertMap.isEmpty()) {
+            log.warn("Parent or insert map is null or empty, returning empty SQL.");
+            throw new ServiceException("Parent or insert map is null or empty.");
+        }
+
+        if (parent.superTable == null || parent.superTable.getTableName() == null || parent.superTable.getTableName().isEmpty()) {
+            log.warn("Super table or table name is null or empty, returning empty SQL.");
+            throw new ServiceException("Super table or table name is null or empty.");
+        }
+
+        // 获取键和值列表并进行安全检查
+        List<String> columns = new ArrayList<>(parent.insertMap.keySet());
+        List<Object> values = new ArrayList<>(parent.insertMap.values());
+
+        if (columns.isEmpty() || values.isEmpty()) {
+            log.warn("Insert map contains no valid columns or values, returning empty SQL.");
+            throw new ServiceException("Insert map contains no valid columns or values.");
+        }
+
+        // 校验列名和值是否合法
+        for (String column : columns) {
+            if (column == null || column.isEmpty()) {
+                log.warn("Invalid column name: {}", column);
+                throw new ServiceException("Invalid column name in insert map.");
+            }
+        }
+
+        try {
+            // 构建 SQL 字符串
+            StringBuilder sql = new StringBuilder();
+            sql.append("INSERT INTO ")
+               .append(parent.superTable.getTableName())
+               .append(" (")
+               .append(columns.stream().map(ObjectUtil::escapeIdentifier).collect(Collectors.joining(", "))) // 转义列名
+               .append(") VALUES (")
+               .append(ObjectUtil.join(values)) // 转义值
+               .append(")");
+
+            // 格式化并记录日志
+            String sqlString = sql.toString().trim();
+            log.info("Generated SQL: {}", sqlString); // 记录生成的 SQL
+            return sqlString;
+
+        } catch (Exception e) {
+            log.error("Error building insert SQL. Parent: {}, Columns: {}, Values: {}", parent, columns, values, e);
+            throw new ServiceException("Error building insert SQL.", e);
+        }
+    }
+
+    /**
+     * 构建更新 SQL 语句
+     * @return
+     */
+    @NotNull
+    private String buildUpdateSql(){
+        // 非空检查
+        if (parent == null || parent.updateMap == null || parent.updateMap.isEmpty()) {
+            log.warn("Parent or update map is null or empty, returning empty SQL.");
+            throw new ServiceException("Parent or update map is null or empty.");
+        }
+
+        if (parent.superTable == null || parent.superTable.getTableName() == null || parent.superTable.getTableName().isEmpty()) {
+            log.warn("Super table or table name is null or empty, returning empty SQL.");
+            throw new ServiceException("Super table or table name is null or empty.");
+        }
+        //取出 id
+        Object value = parent.updateMap.get("id");
+        Object idValue = parent.updateMap.remove("id");
+
+        // 获取键和值列表并进行安全检查
+        List<String> columns = new ArrayList<>(parent.updateMap.keySet());
+        List<Object> values = new ArrayList<>(parent.updateMap.values());
+
+        if (columns.isEmpty() || values.isEmpty()) {
+            log.warn("Update map contains no valid columns or values, returning empty SQL.");
+            throw new ServiceException("Update map contains no valid columns or values.");
+        }
+
+        for (String column : columns) {
+            if (column == null || column.isEmpty()) {
+                log.warn("Invalid column name: {}", column);
+                throw new ServiceException("Invalid column name in update map.");
+            }
+        }
+
+        try {
+            // 构建 SQL 字符串
+            StringBuilder sql = new StringBuilder();
+            sql.append("UPDATE ")
+               .append(parent.superTable.getTableName())
+               .append(" SET ");
+            for (int i = 0; i < columns.size(); i++) {
+                sql.append(columns.get(i))
+                   .append(" = ")
+                   .append(ObjectUtil.escapeValue(values.get(i))) // 转义值
+                   .append(i < columns.size() - 1 ? ", " : " ");
+            }
+            //判断where 是否有值
+            if (!parent.whereInfos.isEmpty()) {
+                appendWhereClauses(sql);
+            } else {
+                sql.append("WHERE ")
+                   .append(parent.superTable.getPrimaryKey())
+                   .append(" = ")
+                   .append(ObjectUtil.escapeValue(value));
+            }
+            //判断是否有条件
+            if(!sql.toString().contains(" WHERE ")){
+                log.warn("No where condition found.");
+                throw new ServiceException("No where condition found.");
+            }
+            return sql.toString();
+        } catch (Exception e) {
+            log.error("Error building update SQL. Parent: {}, Columns: {}, Values: {}", parent, columns, values, e);
+            throw new ServiceException("Error building update SQL.", e);
+        }
+    }
+
+    /**
+     * 构建 SELECT 语句。
+     * @return
+     */
+    @NotNull
+    private String buildSelectSql() {
+
+        // 检查是否有选择的列和父对象是否存在,如果不存在,则记录警告并抛出异常
+        if (parent == null || CollectionUtils.isEmpty(parent.selectColumns)) {
+            log.warn("No select columns or parent is null, returning empty SQL.");
+            throw new ServiceException("No select columns or parent is null.");
+        }
+        // 开始构建 SQL 语句的 SELECT 部分
+        StringBuilder sql = new StringBuilder();
+        sql.append("SELECT ")
+           .append(String.join(", ", parent.selectColumns))
+           .append(" ");
+
+        // 依次调用方法以补充 SQL 语句的 FROM、JOIN 和 WHERE 子句
+        appendFromClause(sql);
+        appendJoins(sql);
+        appendWhereClauses(sql);
+
+        // 将构建好的 SQL 字符串进行格式化并记录日志
+        String sqlString = sql.toString().trim();
+        //sql 格式化打印
+        log.info("SQL: {}", sqlString);
+        switch (type) {
+            case page:
+                //生成count sql
+                String[] split = sqlString.split("FROM");
+                parent.pageCountSql = "select count(0) from " + split[1];
+                //拼接排序
+                if (!parent.orderByMap.isEmpty()) {
+                    sql.append(" ORDER BY ");
+                    List<Integer> list = new ArrayList<>(parent.orderByMap.keySet());
+                    Collections.sort(list);
+                    for (Integer integer : list) {
+                        sql.append(parent.orderByMap.get(integer)).append(",");
+                    }
+                    sql.deleteCharAt(sql.length() - 1);
+                }
+                //生成分页sql
+                sqlString = sql.append(" LIMIT ")
+                               .append(parent.mPage.getSize())
+                               .append(" OFFSET ")
+                               .append((parent.mPage.getCurrent() - 1) * parent.mPage.getSize())
+                               .append(" ")
+                               .toString();
+                break;
+            case selectOne:
+                sqlString = sql.append(" LIMIT 1 ").toString();
+                break;
+            default:
+                break;
+        }
+        // 返回构建好的 SQL 字符串
+        return sqlString;
+    }
+
+    /**
+     * 拼接 FROM 子句。
+     *
+     * @param sql SQL 字符串构建器
+     */
+    private void appendFromClause(StringBuilder sql) {
+        if (Objects.nonNull(parent.superTable)) {
+            sql.append("FROM ")
+               .append(parent.superTable.getTableName())
+               .append(" ")
+               .append(parent.superTable.getAlias())
+               .append(" ");
+        }
+    }
+    /**
+     * 将 LEFT JOIN 信息拼接到 SQL 字符串中。
+     *
+     * @param sql SQL 字符串构建器
+     */
+    private void appendJoins(StringBuilder sql) {
+        // 检查是否有左连接信息需要添加
+        if (CollectionUtils.isNotEmpty(parent.leftJoinInfos)) {
+            for (LeftJoinInfo leftJoinInfo : parent.leftJoinInfos) {
+                // 跳过空的 LeftJoinInfo
+                if (leftJoinInfo == null) {
+                    continue;
+                }
+                // 拼接 LEFT JOIN 子句
+                sql.append("LEFT JOIN ")
+                   .append(leftJoinInfo.getTableInfo().getTableName())
+                   .append(" ")
+                   .append(leftJoinInfo.getTableInfo().getAlias())
+                   .append(" ON ")
+                   .append(leftJoinInfo.getLeftTableInfo().getAlias())
+                   .append(".")
+                   .append(leftJoinInfo.getLeftFieldName())
+                   .append(" = ")
+                   .append(leftJoinInfo.getTableInfo().getAlias())
+                   .append(".")
+                   .append(leftJoinInfo.getFieldName())
+                   .append(" ");
+            }
+        }
+    }
+
+    /**
+     * 将 WHERE 条件拼接到 SQL 字符串中。
+     *
+     * @param sql SQL 字符串构建器
+     */
+    private void appendWhereClauses(StringBuilder sql) {
+        // 检查是否有 WHERE 信息需要添加
+        if (CollectionUtils.isNotEmpty(parent.whereInfos)) {
+            StringBuilder whereSql = new StringBuilder("WHERE ");
+            boolean first = true;
+            // 遍历所有 WHERE 信息并构建 WHERE 子句
+            for (WhereInfo whereInfo : parent.whereInfos) {
+                // 除第一个 WHERE 条件外,其他条件前添加 "AND"
+                if (!first) {
+                    whereSql.append("AND ");
+                }
+                // 构建并添加 WHERE 条件
+                String formatSql = buildWhereClause(whereInfo);
+                if(first && StringUtils.isNotBlank(formatSql)){
+                    first = false;
+                }
+                whereSql.append(formatSql+" ");
+            }
+            //如果最后语句为 where 则删除
+            if(whereSql.toString().endsWith("AND ")){
+                whereSql.delete(whereSql.length()-4,whereSql.length());
+            }
+            //如果最后语句为 where 则删除
+            if(whereSql.toString().endsWith("WHERE ")){
+                whereSql.delete(whereSql.length()-6,whereSql.length());
+            }
+            // 将构建好的 WHERE 子句添加到 SQL 字符串中
+            sql.append(whereSql);
+        }
+    }
+
+    /**
+     * 根据WhereInfo对象构建SQL查询的WHERE子句
+     * 此方法用于根据提供的条件信息生成SQL语句中的WHERE部分它检查WhereInfo对象及其属性的有效性,
+     * 然后根据这些属性构建WHERE子句字符串
+     *
+     * @param whereInfo 包含WHERE子句构建所需信息的对象,包括表信息、列名、操作符和值等
+     * @return 返回构建的WHERE子句字符串如果提供的信息不足以构建WHERE子句,则返回空字符串
+     */
+    private String buildWhereClause(WhereInfo whereInfo) {
+        // 检查whereInfo及其关键属性是否存在,如果任一关键属性为空,则返回空字符串
+        if (whereInfo == null || whereInfo.getTableInfo() == null || whereInfo.getColumn() == null) {
+            return "";
+        }
+
+        if(Objects.isNull(whereInfo.getFieldType()) && !FieldOperator.checkEmptyValue(whereInfo.getOperator())
+                && (Objects.isNull(whereInfo.getValue()) || Objects.equals("", whereInfo.getValue())) ){
+            return "";
+        }
+        if(Objects.isNull(whereInfo.getFieldType()) && !FieldOperator.checkEmptyValue(whereInfo.getOperator())){
+            whereInfo.setFieldType(FieldType.STRING);
+        }
+        // 使用StringBuilder来构建WHERE子句
+        StringBuilder clause = new StringBuilder();
+        // 添加表别名和列名到WHERE子句中
+        //如果是更新 则不加别名
+        if(parent.dbMethod == DbMethodEnums.UPDATE){
+            clause.append(whereInfo.getColumn())
+                  .append(" ");
+        } else {
+            clause.append(whereInfo.getTableInfo().getAlias())
+                  .append(".")
+                  .append(whereInfo.getColumn())
+                  .append(" ");
+        }
+        // 添加操作符到WHERE子句中
+        clause.append(whereInfo.getOperator().getOperator())
+              .append(" ");
+        //特殊处理 如果是between 或 not between
+        if (whereInfo.getOperator() == FieldOperator.BETWEEN || whereInfo.getOperator() == FieldOperator.NOTBETWEEN) {
+            // 如果是between 或 not between,则添加起始值和结束值到WHERE子句中
+            clause.append(FormatValueUtil.formatStringValue(whereInfo));
+        }else {
+            // 根据字段类型添加相应的值到WHERE子句中
+            if (whereInfo.getFieldType() == FieldType.STRING) {
+                // 对字符串类型进行特殊格式化处理
+                clause.append(FormatValueUtil.formatStringValue(whereInfo));
+            } else if (whereInfo.getFieldType() == FieldType.NUMBER) {
+                // 直接添加数值类型到WHERE子句中,无需额外格式化
+                clause.append(whereInfo.getValue());
+            } else if (whereInfo.getFieldType() == FieldType.DATE) {
+                // 对日期类型进行转义处理,防止SQL注入
+                clause.append("'").append(FormatValueUtil.escapeValue(whereInfo.getValue())).append("'");
+            } else {
+                // 直接添加到WHERE子句中,无需额外格式化
+                clause.append(whereInfo.getValue());
+            }
+        }
+        // 返回构建完成的WHERE子句
+        return clause.toString();
+    }
+
+    /**
+     * @return
+     */
+    public SqlUtil buildOne() {
+        this.type = SqlEnums.selectOne;
+        return this;
+    }
+
+    /**
+     * @return
+     */
+    public SqlUtil buildSum() {
+        this.type = SqlEnums.sum;
+        return this;
+    }
+}
+

+ 63 - 0
poyee-base/src/main/java/com/poyee/base/mapper/provider/util/TableInfoUtil.java

@@ -0,0 +1,63 @@
+package com.poyee.base.mapper.provider.util;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.base.mapper.provider.BaseProvider;
+import com.poyee.base.mapper.provider.domain.TableInfo;
+import com.poyee.common.exception.ServiceException;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class TableInfoUtil {
+
+    public static TableInfoUtil init(BaseProvider baseProvider) {
+        return new TableInfoUtil(baseProvider);
+    }
+
+    private TableInfoUtil(BaseProvider baseProvider) {
+        this.parent = baseProvider;
+    }
+
+    private final BaseProvider parent;
+
+    /**
+     * 初始化表信息
+     * 该方法用于根据给定的类获取其对应的数据库表名,并生成一个TableInfo对象,最终将该对象存入parent的tableInfos中
+     * 主要功能包括:
+     * 1. 检查给定类是否使用了@TableName注解,如果没有,则抛出异常
+     * 2. 获取@TableName注解的值,作为表名
+     * 3. 根据parent.tableCount的值生成表的别名
+     * 4. 创建TableInfo对象,并将其存入parent.tableInfos中
+     * 5. 增加parent.tableCount的值,为下一个表生成别名做准备
+     *
+     * @param aClass 要初始化表信息的类,该类应使用@TableName注解来指定表名
+     */
+    public TableInfo initTableInfo(Class<?> aClass) {
+        // 检查给定类是否使用了@TableName注解,如果没有,则抛出异常
+        if (!aClass.isAnnotationPresent(TableName.class)) {
+            throw new ServiceException(aClass.getName() + "未设置表名");
+        }
+        // 获取@TableName注解的值,作为表名
+        TableName tableName = aClass.getAnnotation(TableName.class);
+        String firstTableName = tableName.value();
+        //判断是否已经存在表
+        if(parent.tableInfos.containsKey(aClass.getName())){
+            return parent.tableInfos.get(aClass.getName());
+        }
+        // 根据parent.tableCount的值生成表的别名
+        String thisAlisa = "_" + parent.tableCount;
+        if (parent.tableCount == 0) {
+            thisAlisa = "";
+        }
+        String primaryKey = "id";
+        //获取主键
+        if(aClass.isAnnotationPresent(TableId.class)){
+            primaryKey = aClass.getAnnotation(TableId.class).value();
+        }
+        // 创建TableInfo对象,并将其存入parent.tableInfos中
+        parent.tableInfos.put(aClass.getName(), new TableInfo(aClass.getName(), aClass, firstTableName, "t" + thisAlisa, parent.tableCount, primaryKey));
+        // 增加parent.tableCount的值,为下一个表生成别名做准备
+        parent.tableCount++;
+        return parent.tableInfos.get(aClass.getName());
+    }
+}

+ 159 - 0
poyee-base/src/main/java/com/poyee/base/mapper/provider/util/UpdateUtil.java

@@ -0,0 +1,159 @@
+package com.poyee.base.mapper.provider.util;
+
+import com.alibaba.excel.util.StringUtils;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.annotation.db.Where;
+import com.poyee.base.mapper.provider.BaseProvider;
+import com.poyee.base.mapper.provider.domain.TableInfo;
+import com.poyee.base.mapper.provider.domain.WhereInfo;
+import com.poyee.common.exception.ServiceException;
+import com.poyee.enums.FieldOperator;
+import com.poyee.util.DateUtils;
+import lombok.extern.slf4j.Slf4j;
+
+import java.lang.reflect.Field;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import static com.poyee.base.mapper.provider.ErrMessageContent.*;
+
+@Slf4j
+public class UpdateUtil {
+
+    private BaseProvider parent;
+
+    private UpdateUtil(BaseProvider parent) {
+        this.parent = parent;
+    }
+
+    public static UpdateUtil init(BaseProvider parent) {
+        return new UpdateUtil(parent);
+    }
+
+    public UpdateUtil checkUpdateBean(Object object) {
+        if(Objects.isNull(object)){
+            log.warn("传入的对象为空!");
+            throw new ServiceException(ERROR_MESSAGE_OBJECT_IS_NULL);
+        }
+        Class<?> aClass = object.getClass();
+        if(!aClass.isAnnotationPresent(TableName.class)){
+            log.warn("对象必须包含@TableName注解");
+            throw new ServiceException(ERROR_MESSAGE_TABLE_NAME_MISSING_2);
+        }
+        TableName tableNameAnnotation = aClass.getAnnotation(TableName.class);
+        if(Objects.isNull(tableNameAnnotation.value()) || tableNameAnnotation.value().trim().isEmpty()){
+            log.warn("表名不能为空");
+            throw new ServiceException(ERROR_MESSAGE_TABLE_NAME_IS_NULL);
+        }
+
+        // 初始化表信息
+        TableInfo tableInfo = TableInfoUtil.init(parent)
+                                           .initTableInfo(aClass);
+        parent.superTable = tableInfo;
+//        parent.superTable = parent.tableInfos.get(aClass.getName());
+        parent.update = object;
+        return this;
+    }
+
+    /**
+     * 初始化更新条件
+     */
+    public void initUpdate() {
+        Object update = parent.update;
+        if (update == null || parent.updateMap == null) {
+            log.warn("更新对象或映射为空,无法生成SQL。对象: {}", update);
+            throw new ServiceException(getErrorMessage(ERROR_MESSAGE_BEAN_NULL,"更新"));
+        }
+
+        try {
+            Map<String, Object> updateMap = parent.updateMap;
+            updateMap.clear(); // 清空旧数据
+            processFields(update, updateMap);
+
+            if (updateMap.isEmpty()) {
+                log.warn("没有有效的更新字段,对象: {}", update);
+                throw new ServiceException(getErrorMessage(ERROR_MESSAGE_OPERA_NULL,"更新"));
+            }
+        } catch (IllegalAccessException e) {
+            log.error("访问字段时发生错误", e);
+            throw new ServiceException(ERROR_MESSAGE_FIELD_ACCESS);
+        } catch (IllegalArgumentException e) {
+            log.error("非法参数错误", e);
+            throw new ServiceException(ERROR_MESSAGE_ILLEGAL_ARGUMENT);
+        } catch (Exception e) {
+            log.error(getErrorMessage(ERROR_MESSAGE_BUILD_SQL,"更新"), e);
+            throw new ServiceException(getErrorMessage(ERROR_MESSAGE_BUILD_SQL,"更新"));
+        }
+    }
+
+
+    /**
+     * 处理字段并填充到映射中
+     *
+     * @param object    对象
+     * @param updateMap 插入映射
+     * @throws IllegalAccessException 如果字段访问失败
+     */
+    private void processFields(Object object, Map<String, Object> updateMap) throws IllegalAccessException {
+        Class<?> aClass = object.getClass();
+        Field[] declaredFields = aClass.getDeclaredFields();
+
+        for (Field field : declaredFields) {
+            field.setAccessible(true);
+            // 获取字段注解
+            if(!field.isAnnotationPresent(Where.class)) {
+                if (field.isAnnotationPresent(TableField.class)) {
+                    TableField tableField = field.getAnnotation(TableField.class);
+                    if (tableField.exist()) {
+                        Object value = field.get(object);
+                        if (Objects.nonNull(value)) {
+                            if (value instanceof Date) {
+                                updateMap.put(tableField.value(), DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, (Date) value));
+                            } else {
+                                updateMap.put(tableField.value(), value);
+                            }
+                        }
+                    }
+                }else if (field.isAnnotationPresent(TableId.class)) {
+                    TableId tableId = field.getAnnotation(TableId.class);
+                    Object value = field.get(object);
+                    if (Objects.nonNull(value)) {
+                        if (value instanceof Date) {
+                            updateMap.put(tableId.value(), DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, (Date) value));
+                        } else {
+                            updateMap.put(tableId.value(), value);
+                        }
+                    }
+                }
+            }else{
+                //设置where 条件
+                Where where = field.getAnnotation(Where.class);
+                try {
+                    Object value = field.get(object);
+                    // 根据 Where 注解配置和字段值,决定是否创建 WHERE 信息
+                    if ( (value instanceof String && StringUtils.isNotBlank(String.valueOf(value)))
+                            || (!(value instanceof String) && Objects.nonNull(value))
+                            || FieldOperator.checkEmptyValue(where)) {
+                        Class<?> table = where.table();
+                        // 确保表信息已初始化
+                        if (!parent.tableInfos.containsKey(table.getName())) {
+                            TableInfoUtil.init(parent).initTableInfo(table);
+                        }
+                        WhereInfo whereInfo = new WhereInfo(parent.tableInfos.get(table.getName()));
+                        whereInfo.setColumn(where.field());
+                        whereInfo.setValue(value);
+                        whereInfo.setOperator(where.operator());
+                        whereInfo.setFieldType(where.columnType());
+                        parent.whereInfos.add(whereInfo);
+                    }
+                } catch (IllegalAccessException e) {
+                    throw new ServiceException("无法访问字段:" + field.getName(), e);
+                }
+            }
+        }
+    }
+}

+ 129 - 0
poyee-base/src/main/java/com/poyee/base/mapper/provider/util/WhereUtil.java

@@ -0,0 +1,129 @@
+package com.poyee.base.mapper.provider.util;
+
+import com.alibaba.excel.util.StringUtils;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.poyee.annotation.db.Where;
+import com.poyee.base.mapper.provider.BaseProvider;
+import com.poyee.base.mapper.provider.domain.WhereInfo;
+import com.poyee.common.exception.ServiceException;
+import com.poyee.enums.FieldOperator;
+import com.poyee.enums.FieldType;
+import com.poyee.util.DateUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.lang.reflect.Field;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+
+@Slf4j
+public class WhereUtil {
+
+    public static WhereUtil init(BaseProvider baseProvider){
+        return new WhereUtil(baseProvider);
+    }
+
+    private WhereUtil(BaseProvider baseProvider) {
+        this.parent = baseProvider;
+    }
+    private BaseProvider parent;
+
+    /**
+     * 处理 WHERE 条件。
+     *
+     * @param object 对象实例
+     * @param aClass 类对象
+     * @param whereInfos WHERE 信息列表
+     * @param field 字段对象
+     */
+    public void build(Object object, Class<?> aClass, List<WhereInfo> whereInfos, Field field) {
+        // 检查字段是否用 Where 注解标记
+        if (field.isAnnotationPresent(Where.class)) {
+            Where where = field.getAnnotation(Where.class);
+            try {
+                Object value = field.get(object);
+                // 根据 Where 注解配置和字段值,决定是否创建 WHERE 信息
+                if ( (value instanceof String && StringUtils.isNotBlank(String.valueOf(value)))
+                        || (!(value instanceof String) && Objects.nonNull(value))
+                        || FieldOperator.checkEmptyValue(where)) {
+                    Class<?> table = where.table();
+                    // 确保表信息已初始化
+                    if (!parent.tableInfos.containsKey(table.getName())) {
+                        TableInfoUtil.init(parent).initTableInfo(table);
+                    }
+                    WhereInfo whereInfo = new WhereInfo(parent.tableInfos.get(table.getName()));
+                    if((Objects.equals(where.operator(),FieldOperator.BETWEEN)
+                            || Objects.equals(where.operator(),FieldOperator.NOTBETWEEN)) && where.isEnd() ){
+                        whereInfo = whereInfos.stream()
+                                              .filter(whereInfo1 -> Objects.equals(whereInfo1.getColumn(), where.field()))
+                                              .findFirst()
+                                              .orElse(whereInfo);
+                    }
+                    whereInfo.setColumn(where.field());
+                    if((Objects.equals(where.operator(),FieldOperator.BETWEEN)
+                            || Objects.equals(where.operator(),FieldOperator.NOTBETWEEN)) && where.isEnd() ){
+                        whereInfo.setEndValue(valueCase(value,field));
+                    } else {
+                        whereInfo.setValue(valueCase(value,field));
+                    }
+                    whereInfo.setOperator(where.operator());
+                    whereInfo.setFieldType(where.columnType());
+                    whereInfos.add(whereInfo);
+                }
+            } catch (IllegalAccessException e) {
+                throw new ServiceException("无法访问字段:" + field.getName(), e);
+            }
+        }else {
+            // 检查字段是否用 TableField 注解标记
+            if (field.isAnnotationPresent(TableField.class)) {
+                TableField tableField = field.getAnnotation(TableField.class);
+                // 如果字段在数据库中存在,则尝试构建 WHERE 信息
+                if (tableField.exist()) {
+                    try {
+                        Object value = field.get(object);
+                        // 如果字段值非空,则创建 WHERE 信息并添加到列表中
+                        if ((value instanceof String && StringUtils.isNotBlank(String.valueOf(value))) || (!(value instanceof String) && Objects.nonNull(value))) {
+                            WhereInfo whereInfo = new WhereInfo(parent.tableInfos.get(aClass.getName()));
+                            whereInfo.setColumn(tableField.value());
+                            whereInfo.setValue(valueCase(value,field));
+                            whereInfo.setOperator(FieldOperator.EQ);
+                            whereInfo.setFieldType(valueCaseType(value));
+                            whereInfos.add(whereInfo);
+                        }
+                    } catch (IllegalAccessException e) {
+                        throw new ServiceException("无法访问字段:" + field.getName(), e);
+                    }
+                }
+            }
+        }
+    }
+
+    private FieldType valueCaseType(Object value) {
+        if (value instanceof String) {
+            return FieldType.STRING;
+        } else if (value instanceof Integer) {
+            return FieldType.NUMBER;
+        }else if (value instanceof Boolean) {
+            return FieldType.BOOLEAN;
+        }else if (value instanceof java.util.Date) {
+            return FieldType.DATE;
+        }
+        return FieldType.STRING;
+    }
+
+    /**
+     * @param value
+     * @return
+     */
+    private Object valueCase(Object value,Field field) {
+        //如果 是 时间类型  转正格式化的 字符串
+        if (value instanceof java.util.Date && field.isAnnotationPresent(DateTimeFormat.class)) {
+            DateTimeFormat dateFormat = field.getAnnotation(DateTimeFormat.class);
+            return DateUtils.parseDateToStr(dateFormat.pattern(), (Date) value);
+        }
+        return value;
+    }
+
+}

+ 14 - 0
poyee-base/src/main/java/com/poyee/base/service/BaseService.java

@@ -0,0 +1,14 @@
+package com.poyee.base.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.poyee.base.dto.BaseDto;
+import com.poyee.base.dto.BaseReq;
+import com.poyee.base.dto.Result;
+
+public interface BaseService<T extends BaseReq,R extends BaseDto> extends IService<R> {
+
+    public MPJLambdaWrapper<R> mpjWrapper(Object req);
+    public MPJLambdaWrapper<R> mpjWrapper(MPJLambdaWrapper<R> mpjWrapper,Object req);
+
+}

+ 279 - 0
poyee-base/src/main/java/com/poyee/base/service/impl/BaseServiceImpl.java

@@ -0,0 +1,279 @@
+package com.poyee.base.service.impl;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import com.poyee.annotation.MpjWapper;
+import com.poyee.base.dto.BaseDto;
+import com.poyee.base.dto.BaseReq;
+import com.poyee.base.dto.Result;
+import com.poyee.base.dto.UserInfo;
+import com.poyee.base.mapper.IBaseMapper;
+import com.poyee.base.service.BaseService;
+import com.poyee.common.domain.MpjWrapper;
+import com.poyee.common.exception.ServiceException;
+import com.poyee.util.DateUtils;
+import com.poyee.util.GenericlassUtil;
+import com.poyee.util.ObjectUtil;
+import com.poyee.util.ServletUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.lang.reflect.Field;
+import java.util.*;
+
+/**
+ * @param <E>
+ * @param <T>
+ * @param <R>
+ */
+@Slf4j
+@Service
+public abstract class BaseServiceImpl<E extends IBaseMapper<R>, T extends BaseReq, R extends BaseDto> extends ServiceImpl<E, R> implements BaseService<T,R> {
+
+    public UserInfo checkAndGetUserInfo(){
+        return ServletUtils.getUserInfo();
+    }
+
+    public Long getUserId(){
+        UserInfo userInfo = ServletUtils.getUserInfo();
+        return StringUtils.isNotBlank(userInfo.getUserId())?Long.parseLong(userInfo.getUserId()): Long.valueOf(userInfo.getId());
+    }
+
+    public <P extends BaseReq> void checkAndSetUserId(P p){
+        try {
+            UserInfo userInfo = ServletUtils.getUserInfo();
+            //解析 p 中的user_id
+            if (Objects.nonNull(p)) {
+                Field userId = p.getClass().getDeclaredField("userId");
+                if (Objects.nonNull(userId)) {
+                    userId.setAccessible(true);
+                    String typeName = userId.getType().getName();
+                    if(Objects.equals("java.lang.Long",typeName)){
+                        userId.set(p, Long.valueOf(userInfo.getId()));
+                    }else if(Objects.equals("java.lang.Integer",typeName)){
+                        userId.set(p, userInfo.getId());
+                    }
+                }
+            }
+        } catch (NoSuchFieldException ne) {
+            log.error("请求参数中无userId",ne);
+            throw new ServiceException(402, "无权操作【需指定用户】!");
+        } catch (Exception e) {
+            log.error("获取用户信息失败",e);
+            throw new ServiceException("获取用户信息失败!");
+        }
+    }
+
+    public <P extends BaseReq> void checkAndSetMerchantId(P p){
+        try {
+            UserInfo userInfo = ServletUtils.getUserInfo();
+            if(userInfo.isMerchant()) {
+                //解析 p 中的user_id
+                if (Objects.nonNull(p)) {
+                    Field merchantId = p.getClass().getDeclaredField("merchantId");
+                    if (Objects.nonNull(merchantId)) {
+                        merchantId.setAccessible(true);
+                        String typeName = merchantId.getType().getName();
+                        if (Objects.equals("java.lang.Long", typeName)) {
+                            merchantId.set(p, Long.valueOf(userInfo.getMerchantId()));
+                        } else if (Objects.equals("java.lang.Integer", typeName)) {
+                            merchantId.set(p, userInfo.getMerchantId());
+                        }
+                    }
+                }
+            }
+        } catch (NoSuchFieldException ne) {
+            log.error("请求参数中无userId",ne);
+            throw new ServiceException(402, "无权操作【权限不足】!");
+        } catch (Exception e) {
+            log.error("获取用户信息失败",e);
+            throw new ServiceException("获取用户信息失败!");
+        }
+    }
+
+    public Result<R> getPage(T t) {
+        Page<R> page = new Page<>(t.getPageNo(), t.getPageSize());
+        IPage<R> ipage = page(page);
+        return Result.success(ipage)
+                ;
+    }
+
+    public List<R> selectList(MPJLambdaWrapper<R> wrapper){
+        return baseMapper.selectList(wrapper);
+    }
+
+    /**
+     * @param wrapper
+     * @param entity
+     * @return
+     */
+    public Result<R> selectJoinPages(MPJLambdaWrapper<R> wrapper, T entity) {
+        int pageNo = entity.getPageNo() ;
+        int pageSize = entity.getPageSize();
+        Page<R> page = new Page<>(pageNo, pageSize );
+        //拼接排序数据
+        if (StringUtils.isNotBlank(entity.getSidx()) && "desc".equals(entity.getSort())) {
+            wrapper = wrapper.orderByDesc(entity.getSidx());
+        } else if (StringUtils.isNotEmpty(entity.getSidx())) {
+            wrapper = wrapper.orderByAsc(entity.getSidx());
+        }
+//        IPage<Map<String, Object>> mapIPage = baseMapper.selectJoinMapsPage(page, wrapper);
+//        IPage<R> iPage = baseMapper.selectJoinPage(page, getDtoClass(), wrapper);
+        IPage<R> iPage = selectJoinPage(page, getDtoClass(), wrapper);
+        return Result.success(iPage)
+                ;
+    }
+
+    /**
+     * 
+     * @param page
+     * @param clazz
+     * @param wrapper
+     * @return
+     */
+    IPage<R> selectJoinPage( Page<R> page ,Class<R> clazz , MPJLambdaWrapper<R> wrapper){
+        return baseMapper.selectJoinPage(page, clazz, wrapper);
+    }
+
+    /**
+     * @return
+     */
+    protected Class<R> getDtoClass() {
+        return (Class<R>) GenericlassUtil.getActualTypeArgument(this.getClass(), 2);
+    }
+
+
+    /**
+     * @param req
+     * @return
+     */
+    public MPJLambdaWrapper<R> mpjWrapper(Object req) {
+        return mpjWrapper(new MPJLambdaWrapper<>(),req);
+    }
+
+    /**
+     * @param req
+     * @return
+     */
+    public MPJLambdaWrapper<R> mpjWrapper(MPJLambdaWrapper<R> mpjLambdaWrapper,Object req) {
+        try {
+            if (null != req) {
+                Field[] declaredFields = req.getClass().getDeclaredFields();
+                Map<String, MpjWrapper> mpjWapperMap = new HashMap<>();
+                for (Field field : declaredFields) {
+                    field.setAccessible(true);
+                    String name = field.getName();
+                    //判断是否有注解 MpjWapper
+                    MpjWapper mpjWapper = field.getAnnotation(MpjWapper.class);
+                    if (Objects.nonNull(mpjWapper)) {
+                        if (Objects.nonNull(mpjWapper.value()) ) {
+                            MpjWrapper mpjWrapper = Optional.ofNullable(mpjWapperMap.get(mpjWapper.value()))
+                                                            .orElse(new MpjWrapper());
+                            if(Objects.nonNull(field.get(req))) {
+                                mpjWrapper = mpjWrapper.builder(mpjWapper, field.get(req));
+                                mpjWapperMap.put(mpjWapper.value(), mpjWrapper);
+                            }
+                        }
+                    }
+                    //判断非使用属性
+                    TableField tableField = field.getAnnotation(TableField.class);
+                    if (Objects.isNull(tableField) || ( !Objects.isNull(tableField) && !tableField.exist()) ) {
+                        continue;
+                    }
+                    Object value = field.get(req);
+                    if(Objects.isNull(value)){
+                        continue;
+                    }
+                    String column = Objects.isNull(tableField) ? ObjectUtil.toUnderScoreCase(name) : tableField.value();
+                    if (Objects.equals("java.lang.String",field.getType().getName())
+                            && StringUtils.isNotBlank((String) value)) {
+                        mpjLambdaWrapper = mpjLambdaWrapper.like(column, value);
+                    } else if ( Objects.equals("java.lang.Integer",field.getType() .getName())
+                            || Objects.equals("java.lang.Long",field.getType() .getName())
+                    ) {
+                        mpjLambdaWrapper = mpjLambdaWrapper.eq(column, value);
+                    }
+                }
+                if( mpjWapperMap.size() > 0){
+                    //处理 非空条件
+                    MPJLambdaWrapper<R> finalMpjLambdaWrapper = mpjLambdaWrapper;
+                    mpjWapperMap.forEach((key, value) -> checkMpjWrapper(finalMpjLambdaWrapper, value));
+                }
+            }
+        }catch (Exception ex ){
+            ex.printStackTrace();
+        }
+        return mpjLambdaWrapper;
+    }
+
+
+    /**
+     * @param mpjWrapper
+     * @param wrapper
+     */
+    private void checkMpjWrapper(MPJLambdaWrapper<R> mpjWrapper ,MpjWrapper wrapper  ){
+        try {
+            MpjWapper field = wrapper.getField();
+            String value = field.value();
+            String data = wrapper.getData();
+            if(StringUtils.isBlank(data) || data.replaceAll(",","").length() == 0){
+                return ;
+            }
+            switch (field.operator()) {
+                case EQ:
+                    Object eqVal = checkColumnType(wrapper, data);
+                    mpjWrapper = mpjWrapper.eq(value, eqVal);
+                    break;
+                case NE:
+                    Object neVal = checkColumnType(wrapper, data);
+                    mpjWrapper = mpjWrapper.ne(value, neVal);
+                    break;
+                case BETWEEN:
+                    String[] split = data.split(",");
+                    if (split.length != 2) {
+                        throw new ServiceException("参数错误");
+                    }
+                    Object val1 = checkColumnType(wrapper, split[0]);
+                    Object val2 = checkColumnType(wrapper, split[1]);
+                    mpjWrapper = mpjWrapper.between(value, val1, val2);
+                    break;
+            }
+        }catch (Exception ex){
+            throw new ServiceException("参数错误");
+        }
+    }
+
+    /**
+     * @param wrapper
+     * @param data
+     * @return
+     */
+    private Object checkColumnType(MpjWrapper wrapper ,Object data){
+        Object obj = data;
+        boolean isSame = data.getClass().getName().contains(wrapper.getField().columnType().name());
+        if(isSame){
+            return obj;
+        }
+        switch (wrapper.getField().columnType()) {
+            case STRING:
+                obj = data.toString();
+                break;
+            case NUMBER:
+                obj = Double.parseDouble(data.toString());
+                break;
+            case DATE:
+                obj = DateUtils.parseDate(data.toString());
+                break;
+            case BOOLEAN:
+                obj = Boolean.parseBoolean(data.toString());
+                break;
+        }
+        return obj;
+    }
+
+
+}

+ 14 - 0
poyee-base/src/main/java/com/poyee/common/constant/MqConstants.java

@@ -0,0 +1,14 @@
+package com.poyee.common.constant;
+
+/**
+ * mq常量
+ */
+public class MqConstants {
+    //异步退款队列
+    public static final String QUEUE_ASYNC_REFUND = "queue_async_refund";
+
+    //用户实名认证通过之后 整理用户信息
+    public static final String QUEUE_USER_REALNESS_PASS ="queue_user_rename_pass";
+
+
+}

+ 25 - 0
poyee-base/src/main/java/com/poyee/common/constant/SystemConstant.java

@@ -0,0 +1,25 @@
+package com.poyee.common.constant;
+
+public class SystemConstant {
+
+    public static int JWT_ERRCODE_EXPIRE = 401;
+
+    public static int JWT_ERRCODE_FAIL = 400;
+
+    public static String JWT_SECERT = "4570b0";
+
+    public static String AES_KEY = "4570b0";
+    //30分钟过期时间
+    public static long millis = 30*60*1000;
+    //退款手机验证权限码
+    public static String auth_phone_code_refund = "phone_code_refund";
+    //手机验证码-商家禁用 权限码
+    public static String auth_phone_code_merchant_1 = "phone_code_merchant_1";
+    //白名单
+    public static String auth_white = "white";
+    //黑名单
+    public static String auth_black = "black";
+    //超级权限
+    public static String auth_super = "super";
+
+}

+ 40 - 0
poyee-base/src/main/java/com/poyee/common/db/EnhanceOtherTemplateEngine.java

@@ -0,0 +1,40 @@
+package com.poyee.common.db;
+
+
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.generator.config.OutputFile;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
+
+import java.io.File;
+import java.util.Map;
+
+public class EnhanceOtherTemplateEngine extends VelocityTemplateEngine {
+
+    protected void outputCustomFile(Map<String,String> customFile, TableInfo tableInfo, Map<String ,Object> objectMap){
+        String ename = tableInfo.getEntityName();
+        String otherPath = this.getPathInfo(OutputFile.other);
+        customFile.forEach((key,value)->{
+            String fileName = "";
+            switch (key){
+                case "Dto.java":
+                    fileName = String.format(getDtoPath() + File.separator + ename + "%s", key);  ;
+                break;
+                case "index.vue":
+                    fileName = String.format(otherPath+ File.separator + ename + File.separator + "%s", key);
+                break;
+            }
+            if(StringUtils.isNotBlank(fileName)) {
+//            String fileName = String.format(otherPath+ File.separator+ename+"%s", key);
+                this.outputFile(new File(fileName), objectMap, value, true);
+            }
+        });
+    }
+
+    private String getDtoPath (){
+        String entityPath = this.getPathInfo(OutputFile.entity);
+        return entityPath.replace("entity","dto");
+    }
+
+
+}

+ 31 - 0
poyee-base/src/main/java/com/poyee/common/db/TableInitCustomerUtil.java

@@ -0,0 +1,31 @@
+package com.poyee.common.db;
+
+import com.baomidou.mybatisplus.generator.config.po.TableField;
+
+import java.util.*;
+
+public class TableInitCustomerUtil {
+
+    static List<String> selectNoShowColumn = new ArrayList<>(Arrays.asList("id", "create_time", "update_time", "create_by",
+                                                                           "update_by", "remark", "del_flag", "status","del_flg",
+                                                                           "prop1", "prop2", "prop3", "prop4"));
+    static List<String> tableNoShowColumn = new ArrayList<>(Arrays.asList("create_by", "update_by", "remark", "del_flag", "del_flg",
+                                                                          "prop1", "prop2", "prop3", "prop4"));
+
+    public static Map<String, Object> checkCustomMap(TableField field) {
+        //查询数据库 表生成配置
+        Map<String, Object> customMap = new HashMap<>();
+        boolean selected = true;
+        boolean tableShow = true;
+        if(selectNoShowColumn.contains(field.getColumnName())){
+            selected = false;
+        }
+        if(tableNoShowColumn.contains(field.getColumnName())){
+            tableShow = false;
+        }
+        customMap.put("selected", selected);
+        customMap.put("tableShow", tableShow);
+        return customMap;
+    }
+
+}

+ 28 - 0
poyee-base/src/main/java/com/poyee/common/domain/MpjWrapper.java

@@ -0,0 +1,28 @@
+package com.poyee.common.domain;
+
+import com.poyee.annotation.MpjWapper;
+import com.poyee.util.ObjectUtil;
+import lombok.Data;
+
+/**
+ *
+ */
+@Data
+public class MpjWrapper {
+
+    private MpjWapper field;
+
+    private String data;
+
+    public MpjWrapper builder(MpjWapper field,Object data) {
+        if(this.data!=null){
+            //data 使用 逗号拼接
+            this.data = ObjectUtil.trim(this.data+","+data);
+        }else{
+            this.data = ObjectUtil.trim(data.toString());
+        }
+        this.field = field;
+        return this;
+    }
+
+}

+ 14 - 0
poyee-base/src/main/java/com/poyee/common/dto/DataSourceInfo.java

@@ -0,0 +1,14 @@
+package com.poyee.common.dto;
+
+import lombok.Data;
+
+@Data
+public class DataSourceInfo {
+    //数据源名称
+    private String dataSource;
+    private String driverClass;
+    private String url;
+    private String username;
+    private String pwd;
+
+}

+ 25 - 0
poyee-base/src/main/java/com/poyee/common/dto/DbConfigModal.java

@@ -0,0 +1,25 @@
+package com.poyee.common.dto;
+
+import com.poyee.base.entity.BaseEntity;
+import lombok.Data;
+
+@Data
+public class DbConfigModal extends BaseEntity {
+    //数据源
+    private String dataSource;
+    //驱动名称
+    private String driverClassName;
+    //数据库名称
+    private String dataBaseName;
+    //表名称
+    private String tableName;
+    //数据库类型 1:mysql 2:pgsql
+    private String dbType;
+    //数据库连接
+    private String dbUrl;
+    //数据库用户名
+    private String dbUsername;
+    //数据库密码
+    private String dbPwd;
+
+}

+ 45 - 0
poyee-base/src/main/java/com/poyee/common/dto/TableColumnConfigModal.java

@@ -0,0 +1,45 @@
+package com.poyee.common.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ *
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TableColumnConfigModal {
+    //列名 COLUMN_NAME
+    private String columnName;
+    //列序号 ORDINAL_POSITION
+    private Integer ordinalPosition;
+    //列默认值 COLUMN_DEF
+    private String columnDefault;
+    //是否为空 IS_NULLABLE
+    private String isNullable;
+    //列类型 DATA_TYPE
+    private String dataType;
+    //字符长度 CHAR_OCTET_LENGTH
+    private Integer characterOctetLength;
+    //数字长度 NUM_PREC_RADIX
+    private Integer numericPrecision;
+    //小数位数 DECIMAL_DIGITS
+    private Integer numericScale;
+    //日期长度 COLUMN_SIZE
+    private Integer datetimePrecision;
+    //字符集
+    private String characterSetName;
+    //排序规则
+    private String collationName;
+    //列类型 TYPE_NAME
+    private String columnType;
+    //列键
+    private String columnKey;
+    //列权限
+    private String privileges;
+    //列注释 REMARKS
+    private String columnComment;
+
+}

+ 58 - 0
poyee-base/src/main/java/com/poyee/common/dto/TableConfigModal.java

@@ -0,0 +1,58 @@
+package com.poyee.common.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+import java.util.Map;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TableConfigModal {
+
+    public TableConfigModal( String tableName,String tableComment,List<TableColumnConfigModal> columns){
+        this.tableName = tableName;
+        this.tableComment = tableComment;
+        this.columns = columns;
+    }
+    //数据源
+    private String dataSource;
+    //数据库
+    private String tableSchema;
+    //字符集
+    private String tableCollation;
+    //注释
+    private String tableComment;
+    //数据库类型
+    private String dbType;
+    //数据库地址
+    private String dbUrl;
+    //数据库用户名
+    private String dbUsername;
+    //数据库密码
+    private String dbPwd;
+    //作者
+    private String author;
+    //是否开启swagger
+    private boolean openSwagger;
+    //项目地址-java
+    private String javaProjectPath;
+    //父包名
+    private String javaPackage;
+    //模块
+    private String javaModule;
+    //项目地址-vue
+    private String vueProjectPath;
+    //需要生成的模板
+    private List<String> templates;
+    //表名
+    private String tableName;
+    //生成表字段配置
+    private Map<String ,Map<String,Object>> customMap;
+    //表字段
+    private List<TableColumnConfigModal> columns;
+
+
+}

+ 37 - 0
poyee-base/src/main/java/com/poyee/common/exception/BusinessException.java

@@ -0,0 +1,37 @@
+package com.poyee.common.exception;
+
+/**
+ * 业务异常
+ *
+ * @author zheng
+ */
+public class BusinessException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    protected final String message;
+
+    protected Integer code = -1;
+
+    public BusinessException(Integer code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    public BusinessException(String message) {
+        this.message = message;
+    }
+
+    public BusinessException(String message, Throwable e) {
+        super(message, e);
+        this.message = message;
+    }
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+}

+ 37 - 0
poyee-base/src/main/java/com/poyee/common/exception/ServiceException.java

@@ -0,0 +1,37 @@
+package com.poyee.common.exception;
+
+/**
+ * 业务异常
+ *
+ * @author lsz
+ */
+public class ServiceException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    protected final String message;
+    protected int code = 0;
+
+    public ServiceException(String message) {
+        this.message = message;
+    }
+
+    public ServiceException(int code, String message) {
+        this.message = message;
+        this.code = code;
+    }
+
+    public ServiceException(String message, Throwable e) {
+        super(message, e);
+        this.message = message;
+    }
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+
+    public int getCode() {
+        return this.code;
+    }
+
+}

+ 85 - 0
poyee-base/src/main/java/com/poyee/common/json/JsonMapperUtil.java

@@ -0,0 +1,85 @@
+package com.poyee.common.json;
+
+import com.poyee.annotation.JsonMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+@Slf4j
+public class JsonMapperUtil {
+
+    /**
+     * @param srcObj  源
+     * @param destObj 目标
+     */
+    public static void copy(Object srcObj, Object destObj) {
+        Map<String, Object> jsonMap = checkJsonMapper(srcObj);
+        if (!Objects.isNull(destObj)) {
+            Field[] declaredFields = destObj.getClass()
+                                            .getDeclaredFields();
+            for (Field declaredField : declaredFields) {
+                declaredField.setAccessible(true);
+                //过去注解
+                if (declaredField.isAnnotationPresent(JsonMapper.class)) {
+                    //获取注解
+                    JsonMapper jsonMapper = declaredField.getAnnotation(JsonMapper.class);
+                    //获取注解的值
+                    String name = jsonMapper.name();
+                    if(jsonMap.containsKey(name) && !Objects.isNull(jsonMap.get(name))){
+                        try {
+                            String readConverterExp = jsonMapper.readConverterExp();
+                            if(StringUtils.isNotBlank(readConverterExp)){
+                                Arrays.asList(readConverterExp.split(","))
+                                        .forEach(s -> {
+                                            String[] split = s.split("=");
+                                            if (jsonMap.get(name).toString().equals(split[0])) {
+                                                jsonMap.put(name, split[1]);
+                                            }
+                                        });
+                            }
+                            String fTypeName = declaredField.getType().getName();
+                             if (fTypeName.equals("java.lang.Integer")) {
+                                declaredField.set(destObj, Integer.valueOf(jsonMap.get(name).toString()));
+                            } else if (fTypeName.equals("java.lang.Long")) {
+                                declaredField.set(destObj, Long.valueOf(jsonMap.get(name).toString()));
+                            }else{
+                                declaredField.set(destObj, jsonMap.get(name));
+                            }
+                        } catch (IllegalAccessException e) {
+                            log.error("反射赋值失败",e);
+                        }
+                    }
+                }
+            }
+        }
+
+
+    }
+
+    private static Map<String, Object> checkJsonMapper(Object obj) {
+        Map<String, Object> map = new HashMap<>();
+        Field[] declaredFields = obj.getClass().getDeclaredFields();
+        for (Field declaredField : declaredFields) {
+            declaredField.setAccessible(true);
+            //过去注解
+            if (declaredField.isAnnotationPresent(JsonMapper.class)) {
+                //获取注解
+                JsonMapper jsonMapper = declaredField.getAnnotation(JsonMapper.class);
+                //获取注解的值
+                String name = jsonMapper.name();
+                try {
+                    map.put(name, declaredField.get(obj));
+                } catch (IllegalAccessException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+        return map;
+    }
+
+}

+ 48 - 0
poyee-base/src/main/java/com/poyee/common/knife4j/Knife4jConfig.java

@@ -0,0 +1,48 @@
+package com.poyee.common.knife4j;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
+
+@Configuration
+@EnableSwagger2WebMvc
+@RequiredArgsConstructor
+public class Knife4jConfig implements WebMvcConfigurer {
+
+    private static final String API_BASE_PACKAGE = "com.poyee";
+    private static final String API_TITLE = "poyee-admin";
+    private static final String API_DESCRIPTION = "poyee-admin";
+    private static final String API_CONTACT_NAME = "com/poyee";
+    private static final String API_VERSION = "1.0.0";
+    private static final String API_TERMS_OF_SERVICE = "";
+    private static final String API_LICENSE = "Apache 2.0";
+    private static final String API_LICENSE_URL = "";
+
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
+                                                      .select()
+                                                      .apis(RequestHandlerSelectors.basePackage(API_BASE_PACKAGE))
+                                                      .paths(PathSelectors.any())
+                                                      .build();
+    }
+
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder().title(API_TITLE)
+                                   .description(API_DESCRIPTION)
+                                   .contact(new Contact(API_CONTACT_NAME, API_TERMS_OF_SERVICE, API_LICENSE_URL))
+                                   .version(API_VERSION)
+                                   .build();
+    }
+
+
+}

+ 255 - 0
poyee-base/src/main/java/com/poyee/common/knife4j/SwaggerConfig.java

@@ -0,0 +1,255 @@
+package com.poyee.common.knife4j;
+
+import com.poyee.util.SpringUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+import springfox.documentation.RequestHandler;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.*;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spi.service.contexts.SecurityContext;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
+
+import java.util.*;
+
+/**
+ * Swagger2的接口配置
+ */
+
+
+@Slf4j
+@Configuration
+@EnableSwagger2WebMvc
+public class SwaggerConfig {
+
+    @Value("${poyee.api-version:1.0}")
+    private String apiVersion;
+
+    /**
+     * 指定要扫描的路径
+     */
+    private final static String[] BASE_PACKAGES = new String[]{"com.poyee"};
+    /**
+     * 支持协议
+     */
+    private final static String[] protocols = new String[]{"http,https"};
+    /**
+     * 请求头token键
+     */
+    private final static String ACCESS_TOKEN = "Authorization";
+
+    private final static String X_USER_BASE64 = "X-USER-BASE64";
+
+    /**
+     * 是否开启swagger
+     */
+    @Value("${poyee.name:推广}")
+    private String pName;
+    /**
+     * 是否开启swagger
+     */
+    @Value("${poyee.version:1.0.0}")
+    private String pVersion;
+
+    /**
+     * 是否开启swagger
+     */
+    @Value("${swagger.enabled:false}")
+    private boolean enabled;
+
+    /**
+     * 匹配swagger版本 * *
+     *
+     * @param input   ${@link String} 注解解析 *
+     * @param version ${@link String} 版本信息 *
+     * @return String[] ${@link String[]} *
+     * @author zxiaozhou *
+     * @date 2020-07-06 18:49
+     */
+    protected static boolean matchVersion(RequestHandler input, String version) {
+        if (StringUtils.isBlank(version) && !isControllerHidden(input)) {
+            return true;
+        }
+        String[] versions = getVersions(input);
+        for (String v : versions) {
+            if (version.equalsIgnoreCase(v)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 获取版本信息 * *
+     *
+     * @param input ${@link RequestHandler} *
+     * @return String[] ${@link String[]} 获取的接口信息 *
+     * @author zxiaozhou * @date 2020-07-06 18:11
+     */
+
+    protected static String[] getVersions(RequestHandler input) {
+        if (Objects.isNull(input) || isControllerHidden(input)) {
+            return new String[]{};
+        }
+        Optional<ApiOperation> methodAnnotation = input.findAnnotation(ApiOperation.class);
+        if (methodAnnotation.isPresent()) {
+            ApiOperation apiOperation = methodAnnotation.get();
+            return getVersions(apiOperation.value());
+        }
+        return new String[]{};
+    }
+
+    /**
+     * 解析版本信息 * * @param version ${@link String} 匹配版本 * @return String[] ${@link String[]} 匹配后的接口 * @author zxiaozhou * @date 2020-07-06 18:02
+     */
+    private static String[] getVersions(String version) {
+        String reg = "(.)*(@[\\((].*[\\))])(.)*";
+        if (version.matches(reg)) {
+            version = version.replaceAll(reg, "$2");
+            reg = "(@[\\((])(.*)([\\))])";
+            version = version.replaceAll(reg, "$2");
+            return version.split("[,,]");
+        }
+        return new String[]{};
+    }
+
+    /**
+     * 查询controller是否隐藏 * * @param input ${@link RequestHandler} * @author zxiaozhou * @date 2020-07-20 12:48
+     */
+    protected static boolean isControllerHidden(RequestHandler input) {
+        Optional<Api> controllerAnnotation = input.findControllerAnnotation(Api.class);
+        if (controllerAnnotation.isPresent()) {
+            Api api = controllerAnnotation.get();
+            return api.hidden();
+        }
+        return false;
+    }
+
+    /*
+     *
+     * api标题信息 * * @param version ${@link String} 版本 * @return ApiInfo ${@link ApiInfo} api标题信息 * @author zxiaozhou * @date 2020-07-08 18:45
+     */
+    protected ApiInfo apiInfo(String version) {
+        return new ApiInfoBuilder().title("Swagger API配置")
+                                   .description("接口详细说明")
+                                   .contact(new Contact(pName, "", null))
+                                   .version(version)
+                                   .build();
+    }
+
+    /**
+     * 所有api分组信息 * * @return Docket ${@link Docket} * @author zxiaozhou * @date 2020-07-06 18:52
+     */
+    @Bean
+    public Docket allGroup() {
+//        Set<String> setProtocols = new HashSet<>(Arrays.asList(protocols));
+        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo(apiVersion))
+                                                      .groupName(apiVersion)
+                                                      .select()
+                                                      // 扫描所有有注解的api,用这种方式更灵活
+                                                      .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
+//                .apis(basePackage(BASE_PACKAGES))
+                                                      // 扫描所有
+                                                      .apis(RequestHandlerSelectors.any())
+                                                      .apis(input -> matchVersion(input, apiVersion))
+                                                      .paths(PathSelectors.any())
+                                                      .build()
+//                .protocols(setProtocols)
+                                                      .securitySchemes(this.securitySchemes())
+                                                      .securityContexts(this.securityContexts());
+    }
+    /*
+     *
+     * 其他api分组信息 * * @author zxiaozhou * @date 2020-07-06 18:52
+     */
+    @Bean
+    public void otherGroups() {
+        Map<String, String> versions = new HashMap<>(4);
+        Map<RequestMappingInfo, HandlerMethod> handlerMethodMap =
+                SpringUtils.getBean(RequestMappingHandlerMapping.class)
+                           .getHandlerMethods();
+        for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {
+            HandlerMethod handlerMethod = infoEntry.getValue();
+            ApiOperation apiOperation = handlerMethod.getMethodAnnotation(ApiOperation.class);
+            if (Objects.nonNull(apiOperation)) {
+                String value = apiOperation.value();
+                if (StringUtils.isNotBlank(apiOperation.value())) {
+                    String[] versionInfos = getVersions(value);
+                    if (ArrayUtils.getLength(versionInfos) > 0) {
+                        for (String versionInfo : versionInfos) {
+                            versions.put(versionInfo.replace(".", ""), versionInfo);
+                        }
+                    }
+                }
+            }
+        }
+        DefaultListableBeanFactory defaultListableBeanFactory =
+                (DefaultListableBeanFactory) SpringUtils.getAutowireCapableBeanFactory();
+        for (Map.Entry<String, String> version : versions.entrySet()) {
+            Docket docket = createDocket(version.getValue());
+            if (null != docket) {
+                defaultListableBeanFactory.registerSingleton(version.getKey(), docket);
+            }
+        }
+    }
+
+    private List<ApiKey> securitySchemes() {
+        List<ApiKey> list = new ArrayList<>();
+        list.add(new ApiKey(ACCESS_TOKEN, ACCESS_TOKEN, "header"));
+        list.add(new ApiKey(X_USER_BASE64, X_USER_BASE64, "header"));
+        return list;
+    }
+
+    private List<SecurityContext> securityContexts() {
+        List<SecurityContext> list = new ArrayList<>();
+        list.add(SecurityContext.builder()
+                                .securityReferences(this.defaultAuth())
+                                .forPaths(PathSelectors.regex("^(?!auth).*$"))
+                                .build());
+        return list;
+    }
+
+    private List<SecurityReference> defaultAuth() {
+        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
+        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
+        authorizationScopes[0] = authorizationScope;
+        List<SecurityReference> list = new ArrayList<>();
+        list.add(new SecurityReference(ACCESS_TOKEN, authorizationScopes));
+        list.add(new SecurityReference(X_USER_BASE64, authorizationScopes));
+        return list;
+    }
+
+    /**
+     * 构建版本信息 * * @param version ${@link String} 需要构建的版本 * @return Docket ${@link Docket} 版本Docket信息 * @author zxiaozhou * @date 2020-07-08 18:47
+     */
+
+    protected Docket createDocket(String version) {
+        if (apiVersion.equals(version)) {
+            return null;
+        }
+        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo(version))
+                                                      .groupName(version)
+                                                      .select()
+                                                      .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
+//                .apis(basePackage(BASE_PACKAGES))
+                                                      .apis(input -> matchVersion(input, version))
+                                                      .paths(PathSelectors.any())
+                                                      .build()
+                                                      .securitySchemes(this.securitySchemes())
+                                                      .securityContexts(this.securityContexts())
+                ;
+    }
+}

+ 34 - 0
poyee-base/src/main/java/com/poyee/config/JoinSqlInjector.java

@@ -0,0 +1,34 @@
+package com.poyee.config;
+
+import com.baomidou.mybatisplus.core.injector.AbstractMethod;
+import com.baomidou.mybatisplus.core.injector.AbstractSqlInjector;
+import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
+import com.baomidou.mybatisplus.core.metadata.TableInfo;
+import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
+import com.github.yulichang.injector.MPJSqlInjector;
+import com.github.yulichang.interceptor.MPJInterceptor;
+import com.github.yulichang.method.*;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+public class JoinSqlInjector extends AbstractSqlInjector {
+
+    @Override
+    public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
+        List<AbstractMethod> methodList = new ArrayList<>();
+        //添加你的方法
+        methodList.add(new InsertBatchSomeColumn());
+        //多表查询sql注入 从连表插件里移植过来的
+        methodList.add(new SelectJoinOne());
+        methodList.add(new SelectJoinList());
+        methodList.add(new SelectJoinPage());
+        methodList.add(new SelectJoinMap());
+        methodList.add(new SelectJoinMaps());
+        methodList.add(new SelectJoinMapsPage());
+        return methodList;
+    }
+}

+ 86 - 0
poyee-base/src/main/java/com/poyee/config/RedisConfig.java

@@ -0,0 +1,86 @@
+package com.poyee.config;
+
+import org.apache.commons.lang3.StringUtils;
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.Config;
+import org.redisson.config.SentinelServersConfig;
+import org.redisson.config.SingleServerConfig;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.core.*;
+import org.springframework.data.redis.listener.RedisMessageListenerContainer;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import java.io.IOException;
+
+/**
+ * Redis配置
+ *
+ * @author zheng
+ */
+@Configuration
+@EnableCaching
+public class RedisConfig {
+    @Value("${spring.redis.host:127.0.0.1}")
+    private String host;
+    @Value("${spring.redis.port:6379}")
+    private Integer port;
+    @Value("${spring.redis.password}")
+    private String password;
+    @Value("${spring.redis.sentinel.nodes:127.0.0.1:6379}")
+    private String nodes;
+    @Value("${spring.redis.sentinel.master:master}")
+    private String master;
+
+	@Bean
+    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory)
+    {
+        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
+        redisTemplate.setKeySerializer(new StringRedisSerializer());
+        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
+        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
+        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
+        // 开启事务
+        //redisTemplate.setEnableTransactionSupport(true);
+        redisTemplate.setConnectionFactory(factory);
+        return redisTemplate;
+
+    }
+    @Bean
+    public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate)
+    {
+        return redisTemplate.opsForHash();
+    }
+
+    @Bean
+    public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate)
+    {
+        return redisTemplate.opsForValue();
+    }
+
+    @Bean
+    public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate)
+    {
+        return redisTemplate.opsForList();
+    }
+
+    @Bean
+    public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate)
+    {
+        return redisTemplate.opsForSet();
+    }
+
+    @Bean
+    public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate)
+    {
+        return redisTemplate.opsForZSet();
+    }
+
+}

+ 216 - 0
poyee-base/src/main/java/com/poyee/dataSource/DataSourceConfig.java

@@ -0,0 +1,216 @@
+package com.poyee.dataSource;
+
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.core.config.GlobalConfig;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
+import com.github.yulichang.injector.MPJSqlInjector;
+import com.poyee.common.dto.DbConfigModal;
+import com.poyee.common.dto.TableConfigModal;
+import com.poyee.util.TableInitUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.io.VFS;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.mybatis.spring.annotation.MapperScan;
+import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.core.io.DefaultResourceLoader;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.CollectionUtils;
+
+import javax.sql.DataSource;
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.*;
+
+/**
+ *
+ */
+@Slf4j
+@Configuration
+@MapperScan(basePackages = {"com.poyee.mapper","com.poyee.**.mapper"}, sqlSessionFactoryRef = "sqlSessionFactory")
+public class DataSourceConfig {
+
+    // 连接池连接信息
+    @Value("${spring.datasource.druid.initialSize}")
+    private int initialSize;
+    @Value("${spring.datasource.druid.minIdle}")
+    private int minIdle;
+    @Value("${spring.datasource.druid.maxActive}")
+    private int maxActive;
+    @Value("${spring.datasource.druid.maxWait}")
+    private int maxWait;
+    static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
+    @Autowired
+    private Environment env;
+
+    /**
+     * @param typeAliasesPackage
+     * @return
+     */
+    private static String setTypeAliasesPackage(String typeAliasesPackage) {
+        ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver();
+        MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);
+        List<String> allResult = new ArrayList<String>();
+        try {
+            for (String aliasesPackage : typeAliasesPackage.split(",")) {
+                List<String> result = new ArrayList<String>();
+                aliasesPackage =
+                        ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN;
+                Resource[] resources = resolver.getResources(aliasesPackage);
+                if (resources != null && resources.length > 0) {
+                    MetadataReader metadataReader = null;
+                    for (Resource resource : resources) {
+                        if (resource.isReadable()) {
+                            metadataReader = metadataReaderFactory.getMetadataReader(resource);
+                            try {
+                                result.add(Class.forName(metadataReader.getClassMetadata()
+                                                                       .getClassName())
+                                                .getPackage()
+                                                .getName());
+                            } catch (ClassNotFoundException e) {
+                                e.printStackTrace();
+                            }
+                        }
+                    }
+                }
+                if (result.size() > 0) {
+                    HashSet<String> hashResult = new HashSet<String>(result);
+                    allResult.addAll(hashResult);
+                }
+            }
+            if (allResult.size() > 0) {
+                typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0]));
+            } else {
+                throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包");
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return typeAliasesPackage;
+    }
+
+    @Bean("masterDataSource")
+//    @Primary
+    @Qualifier("masterDataSource")
+    @ConfigurationProperties(prefix = "spring.datasource.dynamic.datasource.master")
+    public DataSource dataSource() {
+        DataSource build = DataSourceBuilder.create()
+                                            .build();
+        return build;
+    }
+
+    /**
+     * @return
+     * @throws Exception
+     */
+    @Bean
+    public SqlSessionFactory sqlSessionFactory() throws Exception {
+        String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");
+        String mapperLocations = env.getProperty("mybatis.mapperLocations");
+        String configLocation = env.getProperty("mybatis.configLocation");
+        typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
+        VFS.addImplClass(SpringBootVFS.class);
+        final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
+        sessionFactory.setDataSource(dynamicDataSource());
+        sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
+//        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
+        sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
+        GlobalConfig globalConfig = new GlobalConfig();
+//        globalConfig.setMetaObjectHandler(new MybatisMetaObjectHandler());
+        globalConfig.setSqlInjector(new MPJSqlInjector());
+        sessionFactory.setGlobalConfig(globalConfig);
+        return sessionFactory.getObject();
+    }
+
+    /**
+     * @return
+     * @throws SQLException
+     */
+    @Bean(name = "dynamicDataSource")
+    @Qualifier("dynamicDataSource")
+    public DynamicDataSource dynamicDataSource() throws SQLException {
+        DynamicDataSource dynamicDataSource = new DynamicDataSource();
+        //配置缺省的数据源
+        // 默认数据源配置 DefaultTargetDataSource
+        dynamicDataSource.setDefaultTargetDataSource(dataSource());
+        Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
+        //额外数据源配置 TargetDataSources
+        targetDataSources.put("master", dataSource());
+        try {
+            List<DbConfigModal> dbConfigModals = TableInitUtil.checkTableConfig(new DbConfigModal());
+            if(!CollectionUtils.isEmpty(dbConfigModals)){
+                dbConfigModals.forEach(tableConfigDto -> {
+                    if(StringUtils.isNotBlank(tableConfigDto.getDataSource())){
+                        try {
+                            targetDataSources.put(tableConfigDto.getDataSource(), initDataSource(tableConfigDto));
+                        } catch (SQLException e) {
+                        }
+                    }
+                });
+            }
+        } catch (Exception e) {
+            log.info(" 注册数据源 SLAVE 失败 ");
+            e.printStackTrace();
+        }
+        dynamicDataSource.setTargetDataSources(targetDataSources);
+        return dynamicDataSource;
+    }
+
+
+    private DataSource initDataSource(DbConfigModal config) throws SQLException{
+        DruidDataSource datasource = new DruidDataSource();
+        // 基础连接信息
+        datasource.setUrl(config.getDbUrl());
+        datasource.setUsername(config.getDbUsername());
+        datasource.setPassword(config.getDbPwd());
+        datasource.setDriverClassName(config.getDriverClassName());
+        // 连接池连接信息
+        datasource.setInitialSize(initialSize);
+        datasource.setMinIdle(minIdle);
+        datasource.setMaxActive(maxActive);
+        datasource.setMaxWait(maxWait);
+        datasource.setPoolPreparedStatements(true); //是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
+        datasource.setMaxPoolPreparedStatementPerConnectionSize(20);
+        datasource.setConnectionProperties("druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000");//对于耗时长的查询sql,会受限于ReadTimeout的控制,单位毫秒
+        datasource.setTestOnBorrow(true); //申请连接时执行validationQuery检测连接是否有效,这里建议配置为TRUE,防止取到的连接不可用
+        datasource.setTestWhileIdle(true);//建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
+        String validationQuery = "select 1 ";
+        datasource.setValidationQuery(validationQuery); //用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
+        datasource.setFilters("stat,wall");//属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有:监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall
+        datasource.setTimeBetweenEvictionRunsMillis(60000); //配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+        datasource.setMinEvictableIdleTimeMillis(180000); //配置一个连接在池中最小生存的时间,单位是毫秒,这里配置为3分钟180000
+        datasource.setKeepAlive(true); //打开druid.keepAlive之后,当连接池空闲时,池中的minIdle数量以内的连接,空闲时间超过minEvictableIdleTimeMillis,则会执行keepAlive操作,即执行druid.validationQuery指定的查询SQL,一般为select * from dual,只要minEvictableIdleTimeMillis设置的小于防火墙切断连接时间,就可以保证当连接空闲时自动做保活检测,不会被防火墙切断
+        datasource.setRemoveAbandoned(true); //是否移除泄露的连接/超过时间限制是否回收。
+        datasource.setRemoveAbandonedTimeout(3600); //泄露连接的定义时间(要超过最大事务的处理时间);单位为秒。这里配置为1小时
+        datasource.setLogAbandoned(true); ////移除泄露连接发生是是否记录日志
+        return datasource;
+    }
+
+    @Bean
+    public MybatisPlusInterceptor mybatisPlusInterceptor() {
+        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
+        return interceptor;
+    }
+
+
+
+}

+ 189 - 0
poyee-base/src/main/java/com/poyee/dataSource/DynamicDataSource.java

@@ -0,0 +1,189 @@
+package com.poyee.dataSource;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.alibaba.druid.stat.DruidDataSourceStatManager;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.poyee.common.dto.DataSourceInfo;
+import com.poyee.dataSource.holder.DataSourceContextHolder;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 多数据源
+ */
+@Slf4j
+public class DynamicDataSource extends AbstractRoutingDataSource {
+
+    private Map<Object, Object> targetDataSources;
+
+    private Object defaultTargetDataSource;
+
+    @Value("${poyee.active-db:master}")
+    private String defaultDataSource ;
+
+    /**
+     * @return
+     */
+    @Override
+    protected Object determineCurrentLookupKey() {
+        String dataSource = DataSourceContextHolder.getDataSource();
+        if (StringUtils.isNotBlank(dataSource)) {
+            log.info("当前数据源为:{}", dataSource);
+            if (CollectionUtils.isEmpty(targetDataSources) || !targetDataSources.containsKey(dataSource)) {
+                log.info("不存在的数据源:{}", dataSource);
+                return null;
+            }
+        }else{
+            //如果没有则使用默认数据源
+            dataSource = defaultDataSource;
+            log.info("未传数据源使用默认数据源为:{}", dataSource);
+        }
+        return dataSource;
+    }
+
+    /**
+     * @param targetDataSources
+     */
+    public void setTargetDataSources(Map<Object, Object> targetDataSources) {
+        super.setTargetDataSources(targetDataSources);
+        this.targetDataSources = targetDataSources;
+    }
+
+    /**
+     * @return
+     */
+    public boolean createDataSource(DataSourceInfo config) {
+        try {
+            Class.forName(config.getDriverClass());
+            DriverManager.getConnection(config.getUrl(), config.getUsername(), config.getPwd());
+            @SuppressWarnings("resource") DruidDataSource druidDataSource = new DruidDataSource();
+            druidDataSource.setName(config.getDataSource());
+            druidDataSource.setDriverClassName(config.getDriverClass());
+            druidDataSource.setUrl(config.getUrl());
+            druidDataSource.setUsername(config.getUsername());
+            druidDataSource.setPassword(config.getPwd());
+            druidDataSource.setInitialSize(1); //初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
+            druidDataSource.setMaxActive(20); //最大连接池数量
+            druidDataSource.setMaxWait(60000); //获取连接时最大等待时间,单位毫秒。当链接数已经达到了最大链接数的时候,应用如果还要获取链接就会出现等待的现象,等待链接释放并回到链接池,如果等待的时间过长就应该踢掉这个等待,不然应用很可能出现雪崩现象
+            druidDataSource.setMinIdle(5); //最小连接池数量
+            String validationQuery = "select 1 ";
+            druidDataSource.setTestOnBorrow(true); //申请连接时执行validationQuery检测连接是否有效,这里建议配置为TRUE,防止取到的连接不可用
+            druidDataSource.setTestWhileIdle(true);//建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
+            druidDataSource.setValidationQuery(validationQuery); //用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
+            druidDataSource.setFilters("stat");//属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有:监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall
+            druidDataSource.setTimeBetweenEvictionRunsMillis(60000); //配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+            druidDataSource.setMinEvictableIdleTimeMillis(180000); //配置一个连接在池中最小生存的时间,单位是毫秒,这里配置为3分钟180000
+            druidDataSource.setKeepAlive(true); //打开druid.keepAlive之后,当连接池空闲时,池中的minIdle数量以内的连接,空闲时间超过minEvictableIdleTimeMillis,则会执行keepAlive操作,即执行druid.validationQuery指定的查询SQL,一般为select * from dual,只要minEvictableIdleTimeMillis设置的小于防火墙切断连接时间,就可以保证当连接空闲时自动做保活检测,不会被防火墙切断
+            druidDataSource.setRemoveAbandoned(true); //是否移除泄露的连接/超过时间限制是否回收。
+            druidDataSource.setRemoveAbandonedTimeout(3600); //泄露连接的定义时间(要超过最大事务的处理时间);单位为秒。这里配置为1小时
+            druidDataSource.setLogAbandoned(true); ////移除泄露连接发生是是否记录日志
+            druidDataSource.init();
+            this.targetDataSources.put(config.getDataSource(), druidDataSource);
+            setTargetDataSources(this.targetDataSources);// 将map赋值给父类的TargetDataSources
+            super.afterPropertiesSet();// 将TargetDataSources中的连接信息放入resolvedDataSources管理
+            log.info(config.getDataSource() + "数据源初始化成功");
+            return true;
+        } catch (ClassNotFoundException | SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * @param dataSource
+     * @return
+     */
+    public boolean delDataSources(String dataSource) {
+        Map<Object, Object> dynamicTargetDataSources2 = this.targetDataSources;
+        if (dynamicTargetDataSources2.containsKey(dataSource)) {
+            Set<DruidDataSource> druidDataSourceInstances = DruidDataSourceStatManager.getDruidDataSourceInstances();
+            for (DruidDataSource l : druidDataSourceInstances) {
+                if (dataSource.equals(l.getName())) {
+                    dynamicTargetDataSources2.remove(dataSource);
+                    DruidDataSourceStatManager.removeDataSource(l);
+                    setTargetDataSources(dynamicTargetDataSources2);// 将map赋值给父类的TargetDataSources
+                    super.afterPropertiesSet();// 将TargetDataSources中的连接信息放入resolvedDataSources管理
+                    return true;
+                }
+            }
+            return false;
+        } else {
+            return false;
+        }
+    }
+    // 测试数据源连接是否有效
+    public boolean testDatasource(String driveClass, String url, String username, String password) {
+        try {
+            Class.forName(driveClass);
+            DriverManager.getConnection(url, username, password);
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+    @Override
+    public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
+        super.setDefaultTargetDataSource(defaultTargetDataSource);
+        this.defaultTargetDataSource = defaultTargetDataSource;
+    }
+
+    /**
+     * @param config
+     * @throws Exception
+     */
+    public void createDataSourceWithCheck(DataSourceInfo config) throws Exception {
+        String datasource = config.getDataSource();
+        log.info("正在检查数据源:"+datasource);
+        Map<Object, Object> dynamicTargetDataSources2 = this.targetDataSources;
+        if (dynamicTargetDataSources2.containsKey(datasource)) {
+            log.info("数据源"+datasource+"之前已经创建,准备测试数据源是否正常...");
+            DruidDataSource druidDataSource = (DruidDataSource) dynamicTargetDataSources2.get(datasource);
+            boolean rightFlag = true;
+            Connection connection = null;
+            try {
+                log.info(datasource+"数据源的概况->当前闲置连接数:"+druidDataSource.getPoolingCount());
+                long activeCount = druidDataSource.getActiveCount();
+                log.info(datasource+"数据源的概况->当前活动连接数:"+activeCount);
+                if(activeCount > 0) {
+                    // log.info(datasourceId+"数据源的概况->活跃连接堆栈信息:"+druidDataSource.getActiveConnectionStackTrace());
+                }
+                log.info("准备获取数据库连接...");
+                connection = druidDataSource.getConnection();
+                log.info("数据源"+datasource+"正常");
+            } catch (Exception e) {
+                log.error(e.getMessage(),e); //把异常信息打印到日志文件
+                rightFlag = false;
+                log.info("缓存数据源"+datasource+"已失效,准备删除...");
+                if(delDataSources(datasource)) {
+                    log.info("缓存数据源删除成功");
+                } else {
+                    log.info("缓存数据源删除失败");
+                }
+            } finally {
+                if(null != connection) {
+                    connection.close();
+                }
+            }
+            if(rightFlag) {
+                log.info("不需要重新创建数据源");
+            } else {
+                log.info("准备重新创建数据源...");
+                boolean b = createDataSource(config);
+                log.info("重新创建数据源{}",b?"成功":"失败");
+            }
+        } else {
+            boolean b = createDataSource(config);
+            log.info("创建数据源{}",b?"成功":"失败");
+        }
+
+    }
+
+
+}

+ 69 - 0
poyee-base/src/main/java/com/poyee/dataSource/MasterDataSourceConfig.java

@@ -0,0 +1,69 @@
+/*
+package com.poyee.dataSource;
+
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.mybatis.spring.SqlSessionFactoryBean;
+import org.mybatis.spring.SqlSessionTemplate;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+
+import javax.sql.DataSource;
+
+*/
+/**
+ * 主数据源配置
+ *//*
+
+//@Configuration
+//@MapperScan(basePackages = {"com.poyee"}, sqlSessionFactoryRef = "masterSqlSessionFactory")
+public class MasterDataSourceConfig {
+
+    */
+/**
+     * @return
+     *//*
+
+//    @Bean(name = "masterDataSource")
+//    @Primary
+//    @ConfigurationProperties(prefix = "spring.datasource.master")
+    public DataSource masterDataSource() {
+        return DataSourceBuilder.create()
+                                .build();
+    }
+
+    */
+/**
+     * @param masterDataSource
+     * @return
+     * @throws Exception
+     *//*
+
+//    @Bean(name = "masterSqlSessionFactory")
+//    @Primary
+    public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource masterDataSource) throws Exception {
+        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
+        bean.setDataSource(masterDataSource);
+        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/*.xml"));
+        return bean.getObject();
+    }
+
+    */
+/**
+     * @param sqlSessionFactory
+     * @return
+     *//*
+
+//    @Bean(name = "masterSqlSessionTemplate")
+//    @Primary
+    public SqlSessionTemplate masterSqlSessionTemplate(@Qualifier("masterSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
+        return new SqlSessionTemplate(sqlSessionFactory);
+    }
+
+}
+*/

+ 30 - 0
poyee-base/src/main/java/com/poyee/dataSource/holder/DataSourceContextHolder.java

@@ -0,0 +1,30 @@
+package com.poyee.dataSource.holder;
+
+/**
+ *
+ */
+public class DataSourceContextHolder {
+    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
+
+    /**
+     * @param dataSource
+     */
+    public static void setDataSource(String dataSource)
+    {
+        contextHolder.set(dataSource);
+    }
+    public static String getDataSource()
+    {
+        return contextHolder.get();
+    }
+
+    /**
+     *
+     */
+    public static void clearDataSource()
+    {
+        contextHolder.remove();
+    }
+
+
+}

+ 24 - 0
poyee-base/src/main/java/com/poyee/enums/CaseWhenValueTypeEnums.java

@@ -0,0 +1,24 @@
+package com.poyee.enums;
+
+import lombok.Getter;
+
+/**
+ *
+ */
+@Getter
+public enum CaseWhenValueTypeEnums {
+    // 表字段
+    TABLE_COLUMN("tableColumn"),
+    // 常量
+    CONSTANT("constant"),
+    // sql表达式
+    SQL_EXPRESSION("sqlExpression"),
+    ;
+
+    private String value;
+
+    CaseWhenValueTypeEnums(String value) {
+        this.value = value;
+    }
+
+}

+ 27 - 0
poyee-base/src/main/java/com/poyee/enums/DataAuth.java

@@ -0,0 +1,27 @@
+package com.poyee.enums;
+
+/**
+ * 数据权限
+ */
+public enum DataAuth {
+    /**
+     * 所有
+     */
+    ALL,
+
+    /**
+     * 个人
+     */
+    PERSON,
+
+    /**
+     * 部门
+     */
+    DEPT
+
+    ;
+
+
+
+
+}

+ 26 - 0
poyee-base/src/main/java/com/poyee/enums/DateEnums.java

@@ -0,0 +1,26 @@
+package com.poyee.enums;
+
+import lombok.Getter;
+
+/**
+ *
+ */
+@Getter
+public enum DateEnums {
+    YEAR("年"),
+    MONTH("月"),
+    DAY("日"),
+    HOUR("时"),
+    MINUTE("分"),
+    SECOND("秒"),
+    //毫秒
+    MILLISECOND("毫秒")
+    ;
+
+    private String value;
+
+    DateEnums(String value) {
+        this.value = value;
+    }
+
+}

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