Browse Source

feat: 先提交一版

bianzhenhua123 2 tháng trước cách đây
commit
b78d4cc290
100 tập tin đã thay đổi với 7383 bổ sung0 xóa
  1. 40 0
      .gitignore
  2. 109 0
      pom.xml
  3. 80 0
      poyee-app-mall/pom.xml
  4. 31 0
      poyee-app-mall/src/main/java/com/poyee/MallApplication.java
  5. 46 0
      poyee-app-mall/src/main/java/com/poyee/config/DruidMetricsConfiguration.java
  6. 36 0
      poyee-app-mall/src/main/java/com/poyee/config/MetricsConfig.java
  7. 5 0
      poyee-app-mall/src/main/java/com/poyee/config/NotificationTopic.java
  8. 52 0
      poyee-app-mall/src/main/java/com/poyee/config/R2DBConfig.java
  9. 183 0
      poyee-app-mall/src/main/java/com/poyee/controller/TestController.java
  10. 69 0
      poyee-app-mall/src/main/java/com/poyee/controller/coupon/AppUserCardRecordController.java
  11. 42 0
      poyee-app-mall/src/main/java/com/poyee/controller/coupon/CardBaseInfoController.java
  12. 39 0
      poyee-app-mall/src/main/java/com/poyee/controller/dict/SysDictDataController.java
  13. 301 0
      poyee-app-mall/src/main/java/com/poyee/controller/item/SpuController.java
  14. 97 0
      poyee-app-mall/src/main/java/com/poyee/controller/item/UserCartController.java
  15. 71 0
      poyee-app-mall/src/main/java/com/poyee/controller/live/AppLiveGoodsController.java
  16. 79 0
      poyee-app-mall/src/main/java/com/poyee/controller/live/AppUserLivePrizeController.java
  17. 361 0
      poyee-app-mall/src/main/java/com/poyee/controller/live/CardGroupLivesConfigController.java
  18. 87 0
      poyee-app-mall/src/main/java/com/poyee/controller/live/LiveCartController.java
  19. 38 0
      poyee-app-mall/src/main/java/com/poyee/controller/live/OrderListController.java
  20. 48 0
      poyee-app-mall/src/main/java/com/poyee/controller/live/UserLiveConfigController.java
  21. 137 0
      poyee-app-mall/src/main/java/com/poyee/controller/luckyPoint/LuckyPointController.java
  22. 233 0
      poyee-app-mall/src/main/java/com/poyee/controller/merchant/MerchantController.java
  23. 178 0
      poyee-app-mall/src/main/java/com/poyee/controller/report/ReportInfoController.java
  24. 61 0
      poyee-app-mall/src/main/java/com/poyee/controller/user/AppUserController.java
  25. 90 0
      poyee-app-mall/src/main/java/com/poyee/controller/user/UserFavoriteRecordController.java
  26. 62 0
      poyee-app-mall/src/main/java/com/poyee/controller/volunteer/VolunteerController.java
  27. 18 0
      poyee-app-mall/src/main/java/com/poyee/listen/AppSyncNoticeRecordService.java
  28. 32 0
      poyee-app-mall/src/main/java/com/poyee/listen/InitializingListen.java
  29. 108 0
      poyee-app-mall/src/main/java/com/poyee/listen/NotificationService.java
  30. 41 0
      poyee-app-mall/src/main/java/com/poyee/listen/ProcessService.java
  31. 53 0
      poyee-app-mall/src/main/java/com/poyee/mq/LiveConfigConsumer.java
  32. 79 0
      poyee-app-mall/src/main/java/com/poyee/mq/SkuStockConsumerNew.java
  33. 34 0
      poyee-app-mall/src/main/resources/application-dev.yml
  34. 57 0
      poyee-app-mall/src/main/resources/application-prod.yml
  35. 248 0
      poyee-app-mall/src/main/resources/application.yml
  36. 11 0
      poyee-app-mall/src/main/resources/http/app-req-zyb.http
  37. 21 0
      poyee-app-mall/src/main/resources/logback-fluentd.xml
  38. 128 0
      poyee-app-mall/src/main/resources/logback.xml
  39. 63 0
      poyee-app-mall/src/test/java/com/poyee/test/group/GroupTest.java
  40. 52 0
      poyee-app-mall/src/test/java/com/poyee/test/mall/BaseTest.java
  41. 25 0
      poyee-app-mall/src/test/java/com/poyee/test/mall/ExamTest.java
  42. 69 0
      poyee-app-mall/src/test/java/com/poyee/test/mall/MultiThreadServiceCall.java
  43. 44 0
      poyee-app-mall/src/test/java/com/poyee/test/mall/SkuTest.java
  44. 20 0
      poyee-app-mall/src/test/resources/http/mall-req-hzt.http
  45. 30 0
      poyee-base-api/pom.xml
  46. 134 0
      poyee-base-api/src/main/java/com/poyee/controller/base/BaseController.java
  47. 14 0
      poyee-base-api/src/main/java/com/poyee/controller/base/DeploymentController.java
  48. 52 0
      poyee-base-api/src/main/java/com/poyee/controller/base/ExceptionController.java
  49. 127 0
      poyee-common/pom.xml
  50. 28 0
      poyee-common/src/main/java/com/poyee/anon/ApiLimitRule.java
  51. 39 0
      poyee-common/src/main/java/com/poyee/anon/ApiLog.java
  52. 17 0
      poyee-common/src/main/java/com/poyee/anon/CustomRetry.java
  53. 27 0
      poyee-common/src/main/java/com/poyee/anon/RedisLock.java
  54. 19 0
      poyee-common/src/main/java/com/poyee/anon/RequireRoles.java
  55. 160 0
      poyee-common/src/main/java/com/poyee/aop/ApiLogAspect.java
  56. 80 0
      poyee-common/src/main/java/com/poyee/aop/AppRoleAspect.java
  57. 118 0
      poyee-common/src/main/java/com/poyee/aop/ControllerLogAspect.java
  58. 63 0
      poyee-common/src/main/java/com/poyee/aop/CustomRetryAspect.java
  59. 44 0
      poyee-common/src/main/java/com/poyee/aop/MqConsumerAOP.java
  60. 106 0
      poyee-common/src/main/java/com/poyee/aop/RedisLockAspect.java
  61. 93 0
      poyee-common/src/main/java/com/poyee/config/BaseConfig.java
  62. 32 0
      poyee-common/src/main/java/com/poyee/config/CommonConfig.java
  63. 24 0
      poyee-common/src/main/java/com/poyee/config/InitPoolConnect.java
  64. 70 0
      poyee-common/src/main/java/com/poyee/config/SwaggerConfig.java
  65. 15 0
      poyee-common/src/main/java/com/poyee/config/WebConfig.java
  66. 51 0
      poyee-common/src/main/java/com/poyee/config/interceptor/ActTokenInterceptor.java
  67. 33 0
      poyee-common/src/main/java/com/poyee/config/log/LogInterceptor.java
  68. 29 0
      poyee-common/src/main/java/com/poyee/config/log/MyThreadPoolTaskExecutor.java
  69. 69 0
      poyee-common/src/main/java/com/poyee/config/log/ThreadMdcUtil.java
  70. 22 0
      poyee-common/src/main/java/com/poyee/config/log/WebConfigurerAdapter.java
  71. 210 0
      poyee-common/src/main/java/com/poyee/config/mq/MqConfig.java
  72. 92 0
      poyee-common/src/main/java/com/poyee/config/redis/CacheConfig.java
  73. 71 0
      poyee-common/src/main/java/com/poyee/config/redis/LuaScriptLoader.java
  74. 128 0
      poyee-common/src/main/java/com/poyee/config/redis/RedisConfig.java
  75. 44 0
      poyee-common/src/main/java/com/poyee/config/redis/RedisConfigCacheManager.java
  76. 53 0
      poyee-common/src/main/java/com/poyee/constant/ActConstans.java
  77. 382 0
      poyee-common/src/main/java/com/poyee/constant/Constants.java
  78. 109 0
      poyee-common/src/main/java/com/poyee/constant/MqConstans.java
  79. 53 0
      poyee-common/src/main/java/com/poyee/constant/NoticeMsgModel.java
  80. 68 0
      poyee-common/src/main/java/com/poyee/constant/NoticeType.java
  81. 34 0
      poyee-common/src/main/java/com/poyee/constant/UserType.java
  82. 97 0
      poyee-common/src/main/java/com/poyee/dto/AppUserInfoDto.java
  83. 11 0
      poyee-common/src/main/java/com/poyee/dto/CMemberDiscountDTO.java
  84. 20 0
      poyee-common/src/main/java/com/poyee/dto/ChildDTO.java
  85. 19 0
      poyee-common/src/main/java/com/poyee/dto/CountNumDTO.java
  86. 48 0
      poyee-common/src/main/java/com/poyee/dto/CouponCatDTO.java
  87. 53 0
      poyee-common/src/main/java/com/poyee/dto/CouponInfoDTO.java
  88. 16 0
      poyee-common/src/main/java/com/poyee/dto/CouponProgressDTO.java
  89. 17 0
      poyee-common/src/main/java/com/poyee/dto/CourierDTO.java
  90. 30 0
      poyee-common/src/main/java/com/poyee/dto/GroupSaleCodeDTO.java
  91. 125 0
      poyee-common/src/main/java/com/poyee/dto/InDto.java
  92. 22 0
      poyee-common/src/main/java/com/poyee/dto/LimitAmountConfig.java
  93. 28 0
      poyee-common/src/main/java/com/poyee/dto/LogParam.java
  94. 98 0
      poyee-common/src/main/java/com/poyee/dto/NoticeSyncDTO.java
  95. 23 0
      poyee-common/src/main/java/com/poyee/dto/OrderRefundDTO.java
  96. 194 0
      poyee-common/src/main/java/com/poyee/dto/OutDTO.java
  97. 12 0
      poyee-common/src/main/java/com/poyee/dto/PaniniCheckListBaseInfoDTO.java
  98. 92 0
      poyee-common/src/main/java/com/poyee/dto/ResultDTO.java
  99. 14 0
      poyee-common/src/main/java/com/poyee/dto/ResultMsg.java
  100. 46 0
      poyee-common/src/main/java/com/poyee/dto/StockParam.java

+ 40 - 0
.gitignore

@@ -0,0 +1,40 @@
+# Created by .ignore support plugin (hsz.mobi)
+### Java template
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+*.iml
+
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+/logs/
+/target/
+
+/.idea/
+/*/target/
+
+# Private individual user cursor rules
+.cursor/rules/_*.mdc
+
+# Documentation and templates
+xnotes/
+docs/

+ 109 - 0
pom.xml

@@ -0,0 +1,109 @@
+<?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>
+
+    <groupId>com.poyee</groupId>
+    <artifactId>poyee-parent</artifactId>
+    <packaging>pom</packaging>
+    <version>1.0-SNAPSHOT</version>
+
+    <properties>
+        <java.version>8</java.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <swagger.version>2.9.2</swagger.version>
+        <redisson.version>3.5.0</redisson.version>
+<!--        <fastjson.version>1.2.74</fastjson.version>-->
+        <fastjson.version>2.0.10</fastjson.version>
+        <dozer.version>6.5.2</dozer.version>
+        <skipTests>true</skipTests>
+        <guava.version>27.0.1-jre</guava.version>
+        <postgresql.version>42.7.2</postgresql.version>
+        <!--<org.mapstruct.version>1.5.1.Final</org.mapstruct.version>-->
+    </properties>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.1.17.RELEASE</version>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.junit.vintage</groupId>
+                    <artifactId>junit-vintage-engine</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+
+    <modules>
+        <module>poyee-entity</module>
+        <module>poyee-repository</module>
+        <module>poyee-common</module>
+        <module>poyee-service-common</module>
+        <module>poyee-base-api</module>
+        <module>poyee-service-mall</module>
+        <module>poyee-service-order</module>
+        <module>poyee-app-mall</module>
+    </modules>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.bsc.maven</groupId>
+                <artifactId>maven-processor-plugin</artifactId>
+                <version>3.1.0</version>
+                <configuration>
+                    <defaultOutputDirectory>
+                        ${project.build.directory}/generated-sources/java
+                    </defaultOutputDirectory>
+                    <processors>
+                        <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
+                        <processor>lombok.launch.AnnotationProcessorHider$AnnotationProcessor</processor>
+                        <!--<processor>org.mapstruct.ap.MappingProcessor</processor>-->
+                    </processors>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>process</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>process</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>
+                                ${project.build.directory}/generated-sources/java
+                            </outputDirectory>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>process-test</id>
+                        <phase>generate-test-sources</phase>
+                        <goals>
+                            <goal>process-test</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>
+                                ${project.build.directory}/generated-test-sources/java
+                            </outputDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 80 - 0
poyee-app-mall/pom.xml

@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>poyee-parent</artifactId>
+        <groupId>com.poyee</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>poyee-app-mall</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.poyee</groupId>
+            <artifactId>poyee-service-mall</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+        </dependency>
+
+        <!--flyway-->
+        <dependency>
+            <groupId>org.flywaydb</groupId>
+            <artifactId>flyway-core</artifactId>
+            <version>5.2.4</version>
+        </dependency>
+        <!-- database -->
+        <dependency>
+            <groupId>io.r2dbc</groupId>
+            <artifactId>r2dbc-postgresql</artifactId>
+            <version>0.8.7.RELEASE</version>
+        </dependency>
+            <!--        r2dbc-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-r2dbc</artifactId>
+            <version>2.5.2</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>io.r2dbc</groupId>
+                    <artifactId>r2dbc-pool</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>io.r2dbc</groupId>
+            <artifactId>r2dbc-pool</artifactId>
+            <version>0.8.0.RELEASE</version>
+        </dependency>
+        <!-- database -->
+        <dependency>
+            <groupId>io.r2dbc</groupId>
+            <artifactId>r2dbc-postgresql</artifactId>
+            <version>0.8.0.RELEASE</version>
+        </dependency>
+        <dependency>
+            <groupId>io.micrometer</groupId>
+            <artifactId>micrometer-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.micrometer</groupId>
+            <artifactId>micrometer-registry-prometheus</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 31 - 0
poyee-app-mall/src/main/java/com/poyee/MallApplication.java

@@ -0,0 +1,31 @@
+package com.poyee;
+
+import com.dtflys.forest.springboot.annotation.ForestScan;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.domain.EntityScan;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+/**
+ * @author po'yi
+ */
+@SpringBootApplication(scanBasePackages = "com.poyee")
+@ForestScan(basePackages ="com.poyee.forest")
+@EnableJpaRepositories(basePackages = "com.poyee.repository")
+@EntityScan(basePackages = "com.poyee.entity")
+@EnableAsync
+@EnableCaching
+@Slf4j
+@EnableAspectJAutoProxy(exposeProxy = true)
+public class MallApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(MallApplication.class, args);
+        log.info("(♥◠‿◠)ノ゙ app-mall启动成功   ლ(´ڡ`ლ)゙");
+    }
+
+}

+ 46 - 0
poyee-app-mall/src/main/java/com/poyee/config/DruidMetricsConfiguration.java

@@ -0,0 +1,46 @@
+package com.poyee.config;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import io.micrometer.core.instrument.MeterRegistry;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+
+@Configuration
+public class DruidMetricsConfiguration {
+
+    @Resource
+    private DruidDataSource druidDataSource;
+
+    @Resource
+    private MeterRegistry meterRegistry;
+
+    @Autowired
+    public void configureMetrics(MeterRegistry registry) {
+        registry.config().commonTags(
+                "application", "poyee-mall"
+        );
+    }
+
+    @PostConstruct
+    public void init() {
+        meterRegistry.gauge("druid.activeCount", druidDataSource, DruidDataSource::getActiveCount);
+        meterRegistry.gauge("druid.poolingCount", druidDataSource, DruidDataSource::getPoolingCount);
+        meterRegistry.gauge("druid.connectCount", druidDataSource, DruidDataSource::getConnectCount);
+        meterRegistry.gauge("druid.closeCount", druidDataSource, DruidDataSource::getCloseCount);
+        meterRegistry.gauge("druid.recycleErrorCount", druidDataSource, DruidDataSource::getRecycleErrorCount);
+        meterRegistry.gauge("druid.connectErrorCount", druidDataSource, DruidDataSource::getConnectErrorCount);
+        meterRegistry.gauge("druid.recycleCount", druidDataSource, DruidDataSource::getRecycleCount);
+        meterRegistry.gauge("druid.removeAbandonedCount", druidDataSource, DruidDataSource::getRemoveAbandonedCount);
+        meterRegistry.gauge("druid.notEmptyWaitCount", druidDataSource, DruidDataSource::getNotEmptyWaitCount);
+        meterRegistry.gauge("druid.notEmptySignalCount", druidDataSource, DruidDataSource::getNotEmptySignalCount);
+        meterRegistry.gauge("druid.notEmptyWaitNanos", druidDataSource, DruidDataSource::getNotEmptyWaitNanos);
+        meterRegistry.gauge("druid.activePeak", druidDataSource, DruidDataSource::getActivePeak);
+        meterRegistry.gauge("druid.poolingPeak", druidDataSource, DruidDataSource::getPoolingPeak);
+        meterRegistry.gauge("druid.discardCount", druidDataSource, DruidDataSource::getDiscardCount);
+        meterRegistry.gauge("druid.notEmptyWaitThreadCount", druidDataSource, DruidDataSource::getNotEmptyWaitThreadCount);
+        meterRegistry.gauge("druid.notEmptyWaitThreadPeak", druidDataSource, DruidDataSource::getNotEmptyWaitThreadPeak);
+    }
+}

+ 36 - 0
poyee-app-mall/src/main/java/com/poyee/config/MetricsConfig.java

@@ -0,0 +1,36 @@
+package com.poyee.config;
+
+import io.micrometer.core.instrument.Clock;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.logging.LoggingMeterRegistry;
+import io.micrometer.core.instrument.logging.LoggingRegistryConfig;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
+import org.springframework.context.annotation.Bean;
+
+import java.time.Duration;
+
+//@Configuration
+class MetricsConfig {
+    @Bean
+    public LoggingMeterRegistry loggingMeterRegistry() {
+
+        return new LoggingMeterRegistry(new LoggingRegistryConfig() {
+            @Override
+            public Duration step() {
+                return Duration.ofSeconds(30);//60秒输出一次
+            }
+
+            @Override
+            public String get(String key) {
+                return null;
+            }
+        }, Clock.SYSTEM);
+    }
+
+
+    @Bean
+    public MeterRegistryCustomizer<MeterRegistry> configurer(@Value("${poyee.name}") String applicationName) {
+        return (registry) -> registry.config().commonTags("application", applicationName);
+    }
+}

+ 5 - 0
poyee-app-mall/src/main/java/com/poyee/config/NotificationTopic.java

@@ -0,0 +1,5 @@
+package com.poyee.config;
+
+public enum NotificationTopic {
+    APP_NOTICE_RECORD_SYNC
+}

+ 52 - 0
poyee-app-mall/src/main/java/com/poyee/config/R2DBConfig.java

@@ -0,0 +1,52 @@
+package com.poyee.config;
+
+import io.r2dbc.pool.ConnectionPool;
+import io.r2dbc.pool.ConnectionPoolConfiguration;
+import io.r2dbc.spi.ConnectionFactories;
+import io.r2dbc.spi.ConnectionFactory;
+import io.r2dbc.spi.ConnectionFactoryOptions;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.time.Duration;
+
+/**
+ * @author by po'yi
+ * @Classname CommonConfig
+ * @Description TODO
+ * @Date 2021/12/16 14:05
+ */
+@Configuration
+public class R2DBConfig {
+
+	@Value("${spring.datasource.url}")
+	private String dbUrl;
+	@Value("${spring.datasource.username}")
+	private String username;
+	@Value("${spring.datasource.password}")
+	private String password;
+
+	@Bean
+	public ConnectionPool connectionPool() {
+		String u = dbUrl.split("://")[1];
+		String[] urlArr = u.split(":");
+		String[] dbPort = urlArr[1].split("/");
+
+		ConnectionFactory connectionFactory = ConnectionFactories.get(ConnectionFactoryOptions.builder()
+				.option(ConnectionFactoryOptions.DRIVER, "postgresql")
+				.option(ConnectionFactoryOptions.HOST, urlArr[0])
+				.option(ConnectionFactoryOptions.PORT, Integer.valueOf(dbPort[0]))
+				.option(ConnectionFactoryOptions.DATABASE, dbPort[1])
+				.option(ConnectionFactoryOptions.USER, username)
+				.option(ConnectionFactoryOptions.PASSWORD, password)
+				.build());
+
+		ConnectionPoolConfiguration configuration = ConnectionPoolConfiguration.builder(connectionFactory)
+				.maxIdleTime(Duration.ofMillis(1000))
+				.maxSize(20)
+				.build();
+		// ConnectionPool实现了ConnectionFactory接口,使用ConnectionFactory替换ConnectionFactory
+		return new ConnectionPool(configuration);
+	}
+}

+ 183 - 0
poyee-app-mall/src/main/java/com/poyee/controller/TestController.java

@@ -0,0 +1,183 @@
+package com.poyee.controller;
+
+import com.poyee.anon.ApiLog;
+import com.poyee.config.CommonConfig;
+import com.poyee.constant.Constants;
+import com.poyee.controller.base.BaseController;
+import com.poyee.dto.OutDTO;
+import com.poyee.dto.ResultDTO;
+import com.poyee.entity.CardGroupOrderInfo;
+import com.poyee.entity.SysDictData;
+import com.poyee.entity.TestData;
+import com.poyee.enums.BusinessType;
+import com.poyee.exception.ServiceException;
+import com.poyee.handle.ApiVersion;
+import com.poyee.repository.TestDataRepository;
+import com.poyee.service.AsyncAppService;
+import com.poyee.service.CardGroupGoodsService;
+import com.poyee.service.UserService;
+import com.poyee.service.impl.DictDataCacheService;
+import com.poyee.utils.RandomUtil;
+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.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * swagger 用户测试方法
+ *
+ * @author zheng
+ */
+@Api("用户信息管理")
+@RestController
+@RequestMapping("{version}/test")
+@Slf4j
+public class TestController extends BaseController {
+
+    //@Autowired
+    //private RedisUtils redisUtils;
+    @Resource
+    private TestDataRepository testDataRepository;
+    @Autowired
+    private AsyncAppService asyncAppService;
+    @Autowired
+    private  UserService userService;
+
+    @Autowired
+    protected DictDataCacheService dictDataCacheService;
+    @Resource
+    protected CardGroupGoodsService cardGroupGoodsService;
+
+    public void checkDevEnv() {
+        log.debug("部署环境:{}", CommonConfig.isProdEnv());
+        if (CommonConfig.isProdEnv()) {
+            throw new ServiceException(500,"环境不符合");
+        }
+    }
+
+    @ApiOperation("jpa")
+    @GetMapping("/jpa/insert")
+    @ApiVersion(1.0)
+    @ApiLog(title = "jpaTest", businessType = BusinessType.INSERT)
+    public ResultDTO jpaTest() {
+        checkDevEnv();
+        TestData testData = new TestData(null, "name2022-1",null);
+        //testDataRepository.save(testData);
+        TestData testData1 = testDataRepository.findById(1L).orElse(new TestData());
+        testData1.setName("test-version2-"+testData1.getId());
+        testDataRepository.saveAndFlush(testData1);
+        //log.info("id1:{}",testData.getId());
+        //boolean b = userService.checkUserIsHighFrequency(828L);
+        //List<String> userCats = userService.getUserCats(15055L);
+        //3074
+        //List<CountNumDTO> groupCountByType = cardGroupGoodsService.getGroupCountByType(3074L, 1);
+        //List<CountNumDTO> groupCountByType2 = cardGroupGoodsService.getGroupCountByType(2837L, 2);
+        return successResult(testData.getId());
+    }
+
+    @ApiOperation("bee 查询")
+    @GetMapping("/bee/select")
+    @ApiLog(title = "beeTest", businessType = BusinessType.SEARCH)
+    @ApiVersion(1.0)
+    public OutDTO beeTest(Long id) {
+        //new orderDTO();
+        //List<orderDTO> orderDTOs=suidRich.select(orderDTO);
+        CardGroupOrderInfo orderInfo = new CardGroupOrderInfo();
+        orderInfo.setGroupInfoId(id);
+        //List<CardGroupOrderInfo> select = suidRich.select(orderInfo, 1, 5);
+        //int count = suidRich.count(orderInfo);
+        return OutDTO.ok();
+                //.put("goods", select)
+                //.setCount(5, 1, count);
+    }
+
+    @ApiOperation("version1")
+    @GetMapping("/version")
+    @ApiVersion(1.0)
+    public OutDTO beeTestv(String version) {
+        //int i=1/0;
+        //if(StringUtils.isNotEmpty(version)){
+        //    throw new ServiceException(500,"11");
+        //}
+        log.info("11111");
+        asyncAppService.test();
+        return OutDTO.ok().put("version1.1", version);
+    }
+
+    @ApiOperation("version2")
+    @GetMapping("/version2")
+    //@ApiVersion(2.0)
+    public OutDTO beeTestv2(String version) {
+        //int i=1/0;
+        //if(StringUtils.isNotEmpty(version)){
+        //    throw new ServiceException(500,"11");
+        //}
+        List<SysDictData> dates = dictDataCacheService.getCommonDictData("new_sort_query", null, null,
+                Constants.COUPON_SCOPE_CONFIG_CACHE+"goods", 3600);
+        return OutDTO.ok().put("version2.0", version);
+    }
+
+    @ApiOperation("version1")
+    @GetMapping("/version")
+    @ApiVersion(1.2)
+    public OutDTO beeTestv1() {
+        log.info("samll version1");
+        return OutDTO.ok().put("version", "1");
+    }
+
+    @ApiOperation("version2")
+    @GetMapping("/version")
+    @ApiVersion(1.7)
+    public OutDTO beeTestv2() {
+        log.info("big version2");
+        return OutDTO.ok().put("version", "2");
+    }
+
+    @ApiOperation("version1")
+    @GetMapping("/lock")
+    @ApiVersion(1.0)
+    public OutDTO testLock(int num) {
+        //int i=0;
+        //while(true) {
+        //    if(i>=num){
+        //       break;
+        //    }
+        //    //asyncAppService.test(new TestData(null,"test2022"));
+        //    asyncAppService.test("test",2022L);
+        //    i++;
+        //}
+        return OutDTO.ok();
+    }
+
+
+    @GetMapping("/testCache")
+    @ApiVersion(2.0)
+    public OutDTO testCache() {
+        //List<SysDictData> dates = dictDataCacheService.getCommonDictData(Constants.COUPON_SCOPE_CONFIG, "goods", Constants.STATUS_OK,
+        //        Constants.COUPON_SCOPE_CONFIG_CACHE+"goods", 3600);
+        //AppUserInfoDto user = userService.getUserDetailInfoByCache(272);
+        return OutDTO.ok();
+    }
+
+    @ApiOperation("merchant")
+    @GetMapping("/merchant/user")
+    @ApiVersion(1.0)
+    public OutDTO getMerchantAppInfo(Long merchantId) {
+        checkDevEnv();
+        return OutDTO.ok().put("userInfo",userService.getMerchantAppUserInfo(merchantId));
+    }
+
+    @ApiOperation("merchant")
+    @GetMapping("/no")
+    public ResultDTO buildNo(Long merchantId) {
+        checkDevEnv();
+        return successResult(RandomUtil.getRandomNew("TE"));
+    }
+
+}

+ 69 - 0
poyee-app-mall/src/main/java/com/poyee/controller/coupon/AppUserCardRecordController.java

@@ -0,0 +1,69 @@
+package com.poyee.controller.coupon;
+
+import com.poyee.anon.ApiLimitRule;
+import com.poyee.anon.ApiLog;
+import com.poyee.controller.base.BaseController;
+import com.poyee.dto.AppUserInfoDto;
+import com.poyee.dto.InDto;
+import com.poyee.dto.ResultDTO;
+import com.poyee.entity.CardBaseInfo;
+import com.poyee.enums.BusinessType;
+import com.poyee.param.LimitRule;
+import com.poyee.service.AppUserCardRecordService;
+import com.poyee.service.UserService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+import java.util.Collections;
+
+import static com.poyee.dto.ResultDTO.RESPCODE_FAILURE;
+
+@Slf4j
+@Api("用户优惠券记录api")
+@RestController
+@RequestMapping("/api/userCardRecord")
+public class AppUserCardRecordController extends BaseController {
+
+    @Resource
+    private AppUserCardRecordService appUserCardRecordService;
+    @Resource
+    private UserService userService;
+
+    @PostMapping("/receive")
+    @ApiLog(title = "领取优惠券", businessType = BusinessType.INSERT)
+    @ApiOperation("领取优惠券")
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public ResultDTO goodsCardList(@RequestBody InDto inDto) {
+        Integer userId = getSimpleUserInfo(true).getId();
+        AppUserInfoDto user = userService.getUserDetailInfo(userId);
+        if (user.getAccountStatus() == 2) {
+            return ResultDTO.buildErrorResult(500, "领取失败!");
+        }
+        String liveIdStr = inDto.getString("liveId");
+        Long liveId = null;
+        if (Strings.isNotEmpty(liveIdStr)) {
+            liveId = Long.parseLong(liveIdStr);
+        }
+        String cdkey = inDto.getString("cdkey");
+        // 查询优惠券信息
+        CardBaseInfo cardBaseInfo = appUserCardRecordService.getCardBaseInfoByCdkey(cdkey);
+        String specialActType = cardBaseInfo.getSpecialActType();
+        if(Strings.isNotEmpty(specialActType) && specialActType.startsWith("brand_member")) {
+            boolean hasMember = appUserCardRecordService.checkUserBrandMem(userId, cardBaseInfo);
+            if(!hasMember){
+                // 用户不是该品牌会员 需要跳转至商家会员加入
+                return new ResultDTO(RESPCODE_FAILURE, "需要品牌会员才能领取", Collections.singletonMap("needMerchantId", cardBaseInfo.getMerchantId()));
+            }
+        }
+        appUserCardRecordService.receiveCoupons(cdkey, userId, liveId);
+        return ResultDTO.buildEmptySuccess();
+    }
+}

+ 42 - 0
poyee-app-mall/src/main/java/com/poyee/controller/coupon/CardBaseInfoController.java

@@ -0,0 +1,42 @@
+package com.poyee.controller.coupon;
+
+import com.poyee.anon.ApiLog;
+import com.poyee.controller.base.BaseController;
+import com.poyee.dto.InDto;
+import com.poyee.dto.ResultDTO;
+import com.poyee.enums.BusinessType;
+import com.poyee.service.CardBaseInfoService;
+import com.poyee.service.dto.GoodsCardDTO;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Api("商家商品优惠券api")
+@RestController
+@RequestMapping("/api/cardBaseInfo")
+public class CardBaseInfoController extends BaseController {
+
+    @Resource
+    private CardBaseInfoService cardBaseInfoService;
+
+    @GetMapping("/list")
+    @ApiLog(title = "获取商品优惠券", businessType = BusinessType.SEARCH)
+    @ApiOperation("获取商品优惠券")
+    public ResultDTO goodsCardList(@RequestBody InDto inDto){
+        Map<String, Object> paramMap = inDto.getData();
+        Long userId = Long.valueOf(paramMap.get("userId").toString());
+        Integer goodsId = Integer.valueOf(paramMap.get("goodsId").toString());
+        List<GoodsCardDTO> goodsCardDTOList = cardBaseInfoService.findCardsByGoodsId(userId, goodsId);
+        return ResultDTO.buildSuccessResult(goodsCardDTOList);
+    }
+
+}

+ 39 - 0
poyee-app-mall/src/main/java/com/poyee/controller/dict/SysDictDataController.java

@@ -0,0 +1,39 @@
+package com.poyee.controller.dict;
+
+import com.poyee.anon.ApiLog;
+import com.poyee.controller.base.BaseController;
+import com.poyee.dto.InDto;
+import com.poyee.dto.ResultDTO;
+import com.poyee.entity.Spu;
+import com.poyee.entity.SysDictData;
+import com.poyee.enums.BusinessType;
+import com.poyee.service.CheckListService;
+import com.poyee.service.impl.DictDataCacheService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+@Slf4j
+@Api("字典表api")
+@RestController
+@RequestMapping("/api/dictData")
+public class SysDictDataController extends BaseController {
+
+    @Resource
+    private DictDataCacheService dictDataCacheService;
+
+    @ApiOperation("通用字典表查询接口")
+    @ApiLog(title = "通用字典表查询接口", businessType = BusinessType.SEARCH)
+    @PostMapping("/list")
+    public ResultDTO checklistYear(@RequestBody InDto inDto) {
+        List<SysDictData> sysDictDataList = dictDataCacheService.getCommonDictData(inDto.getString("dictType"), inDto.getString("dictLable"), "1", null, 0);
+        return ResultDTO.buildSuccessResult(sysDictDataList);
+    }
+
+}

+ 301 - 0
poyee-app-mall/src/main/java/com/poyee/controller/item/SpuController.java

@@ -0,0 +1,301 @@
+package com.poyee.controller.item;
+
+import com.poyee.anon.ApiLog;
+import com.poyee.anon.RequireRoles;
+import com.poyee.constant.UserType;
+import com.poyee.controller.base.BaseController;
+import com.poyee.dto.InDto;
+import com.poyee.dto.ResultDTO;
+import com.poyee.dto.ResultMsg;
+import com.poyee.enums.BusinessType;
+import com.poyee.handle.ApiVersion;
+import com.poyee.param.SpuQuery;
+import com.poyee.param.UserInfo;
+import com.poyee.service.dto.*;
+import com.poyee.service.item.SpuService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * @author by po'yi
+ * @Classname SpuController
+ * @Description 商城商品相关api
+ * @Date 2022/8/22 17:40
+ */
+@Slf4j
+@Api("商城商品api")
+@RestController
+@RequestMapping("/api/goods")
+public class SpuController extends BaseController {
+
+	@Autowired
+	private SpuService spuService;
+
+
+	@ApiLog(title = "商品搜索", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("商品搜索")
+	@PostMapping("/{version}/list/search")
+	public ResultDTO searchSku(@RequestBody InDto inDto) {
+		SpuQuery spuQuery = buildQueryParam(inDto, new SpuQuery());
+		UserInfo userInfo = getSimpleUserInfo(false);
+		if(userInfo!=null){
+			spuQuery.setUserId(userInfo.getId());
+		}
+		Page<SpuListDTO> spuList=spuService.searchSpu(spuQuery);
+		return ResultDTO.buildSuccessResult(spuList);
+	}
+
+	@ApiLog(title = "指定优惠券商品列表", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(3.9)
+	@ApiOperation("指定优惠券商品列表")
+	@PostMapping("/{version}/list/coupon")
+	public ResultDTO searchSkuV2(@RequestBody InDto inDto) {
+		SpuQuery spuQuery = buildQueryParam(inDto, new SpuQuery());
+		UserInfo userInfo = getSimpleUserInfo(false);
+		if(userInfo!=null){
+			spuQuery.setUserId(userInfo.getId());
+		}
+		Page<SpuListDTO> spuList=spuService.searchSpuV2(spuQuery);
+		return ResultDTO.buildSuccessResult(spuList);
+	}
+
+	@ApiLog(title = "商品详情", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("商品详情")
+	@PostMapping("/{version}/spuInfo")
+	public ResultDTO spuInfo(@RequestBody InDto inDto) {
+		if(inDto==null||inDto.get("id")==null){
+			return ResultDTO.buildErrorResult("参数为空");
+		}
+		List<Long> status;
+		String skuStatus = inDto.getString("skuStatus");
+		if(StringUtils.isNotEmpty(skuStatus)){
+			status = Arrays.stream(skuStatus.split(",")).map(Long::valueOf).collect(Collectors.toList());
+		}else{
+			status = Stream.of("201").map(Long::valueOf).collect(Collectors.toList());
+		}
+		Long liveId = null;
+		String liveIdStr = inDto.getString("liveId");
+		if(Strings.isNotEmpty(liveIdStr)){
+			liveId = Long.valueOf(liveIdStr);
+		}
+		SpuDTO spuDTO=spuService.getSpuInfo(getSimpleUserInfo(false),
+				Long.valueOf(inDto.getString("id")), status, liveId);
+		return ResultDTO.buildSuccessResult(spuDTO);
+	}
+
+	@ApiLog(title = "直播间商品详情不查销量和库存", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("商品详情")
+	@PostMapping("/{version}/spuInfo/living")
+	public ResultDTO spuInfoForLiving(@RequestBody InDto inDto) {
+		if(inDto==null||inDto.get("id")==null){
+			return ResultDTO.buildErrorResult("参数为空");
+		}
+		List<Long> status;
+		String skuStatus = inDto.getString("skuStatus");
+		if(StringUtils.isNotEmpty(skuStatus)){
+			status = Arrays.stream(skuStatus.split(",")).map(Long::valueOf).collect(Collectors.toList());
+		}else{
+			status = Stream.of("201").map(Long::valueOf).collect(Collectors.toList());
+		}
+		Long liveId = null;
+		String liveIdStr = inDto.getString("liveId");
+		if(Strings.isNotEmpty(liveIdStr)){
+			liveId = Long.valueOf(liveIdStr);
+		}
+		SpuDTO spuDTO=spuService.getSpuInfoForLiving(getSimpleUserInfo(false),
+				Long.valueOf(inDto.getString("id")), status, liveId);
+		return ResultDTO.buildSuccessResult(spuDTO);
+	}
+
+
+	@ApiLog(title = "商品绑定优惠劵", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("商品绑定优惠劵")
+	@PostMapping("/{version}/getBindCoupon")
+	public ResultDTO getSpuBindCoupons(@RequestBody InDto inDto) {
+		if(inDto==null||inDto.get("id")==null){
+			return ResultDTO.buildErrorResult("参数为空");
+		}
+		List<CouponDTO> coupons=spuService.getSpuBindCoupons(getSimpleUserInfo(true),Long.valueOf(inDto.getString("id")));
+		return ResultDTO.buildSuccessResult(coupons);
+	}
+
+	@ApiLog(title = "查询商家所有商品", businessType = BusinessType.SEARCH)
+	@ApiOperation("查询商家所有商品")
+	@PostMapping("/spulist")
+	public ResultDTO findByMerchantId(@RequestBody InDto inDto) {
+		if(inDto==null){
+			return ResultDTO.buildErrorResult("参数为空");
+		}
+		long merchantId = Long.parseLong(inDto.getData().get("merchantId").toString());
+		List<SpuDTO> spuDTOList = spuService.findByMerchantId(merchantId);
+		return ResultDTO.buildSuccessResult(spuDTOList);
+	}
+
+	@ApiLog(title = "热门商品", businessType = BusinessType.SEARCH)
+	@PostMapping(value = "/hot")
+	@ApiOperation("热门商品")
+	public ResultDTO hotProductV3(@RequestBody InDto inDto) {
+		Integer limit = inDto.getIntegerDefault("limit", 3);
+		Page<SpuListDTO> spuList = spuService.getHot(limit);
+		return ResultDTO.buildSuccessResult(spuList);
+	}
+
+	@ApiOperation("审核商品列表")
+	@ApiLog(title = "审核商品列表", businessType = BusinessType.SEARCH)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_SHIPPING})
+	@PostMapping("/review/page")
+	public ResultDTO getReviewSpus(@RequestBody InDto inDto) {
+		Integer status = null;
+		if(Strings.isNotEmpty(inDto.getString("status"))){
+			status = Integer.parseInt(inDto.getString("status"));
+		}
+		PageRequest pageRequest = PageRequest.of(inDto.getPageNo() - 1, inDto.getPageSize(), Sort.Direction.DESC, "id");
+		Page<ReviewSpuDTO> page = spuService.getReviewSpus(status, inDto.getString("searchName"), pageRequest);
+		return ResultDTO.buildSuccessResult(page);
+	}
+
+	@ApiOperation("审核商品详情")
+	@ApiLog(title = "审核商品详情", businessType = BusinessType.SEARCH)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_SHIPPING})
+	@PostMapping("/review/detail")
+	public ResultDTO getReviewDetail(@RequestBody InDto inDto) {
+		Long spuId = null;
+		if(Strings.isNotEmpty(inDto.getString("spuId"))){
+			spuId = Long.parseLong(inDto.getString("spuId"));
+		}
+		SpuDTO spuDTO = spuService.getReviewDetail(spuId);
+		return ResultDTO.buildSuccessResult(spuDTO);
+	}
+
+	@ApiOperation("编辑商品")
+	@ApiLog(title = "编辑商品", businessType = BusinessType.UPDATE)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_SHIPPING})
+	@PostMapping("/edit/spu")
+	public ResultDTO editSpu(@RequestBody InDto inDto) {
+		EditSpuDTO spuDTO = buildQueryParam(inDto, new EditSpuDTO());
+		long result = spuService.editSpu(spuDTO);
+		if(result > 0) {
+			return ResultDTO.buildEmptySuccess().setMsg(ResultMsg.UPDATE_SUCCESS);
+		}
+		return ResultDTO.buildErrorResult().setMsg(ResultMsg.UPDATE_FAIL);
+	}
+
+	@ApiOperation("审核商品")
+	@ApiLog(title = "审核商品", businessType = BusinessType.UPDATE)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN})
+	@PostMapping("/review/spu")
+	public ResultDTO reviewSpu(@RequestBody InDto inDto) {
+		long spuId;
+		if(Strings.isEmpty(inDto.getString("spuId"))){
+			return ResultDTO.buildErrorResult("spuId不能为空");
+		}
+		spuId = Long.parseLong(inDto.getString("spuId"));
+		int reviewStatus;
+		if(Strings.isEmpty(inDto.getString("reviewStatus"))){
+			return ResultDTO.buildErrorResult("reviewStatus不能为空");
+		}
+		reviewStatus = Integer.parseInt(inDto.getString("reviewStatus"));
+		long result = spuService.reviewSpu(spuId, reviewStatus);
+		if(result > 0) {
+			return ResultDTO.buildEmptySuccess().setMsg(ResultMsg.REVIEW_SUCCESS);
+		}
+		return ResultDTO.buildErrorResult().setMsg(ResultMsg.REVIEW_FAIL);
+	}
+
+	@ApiOperation("sku列表")
+	@ApiLog(title = "sku列表", businessType = BusinessType.SEARCH)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_SHIPPING})
+	@PostMapping("/sku/list")
+	public ResultDTO getSkus(@RequestBody InDto inDto) {
+		List<EditSkuDTO> skuList = spuService.getBySpuId(Long.parseLong(inDto.getString("spuId")));
+		return ResultDTO.buildSuccessResult(skuList);
+	}
+
+	@ApiOperation("新增商品sku")
+	@ApiLog(title = "新增商品sku", businessType = BusinessType.INSERT)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_SHIPPING})
+	@PostMapping("/sku/add")
+	public ResultDTO addSku(@RequestBody InDto inDto) {
+		EditSkuDTO skuDTO = buildQueryParam(inDto, new EditSkuDTO());
+		long result = spuService.saveSku(skuDTO);
+		if(result > 0) {
+			return ResultDTO.buildEmptySuccess().setMsg(ResultMsg.OPEARTE_SUCCESS);
+		}
+		return ResultDTO.buildErrorResult().setMsg(ResultMsg.OPEARTE_FAIL);
+	}
+
+	@ApiOperation("编辑sku")
+	@ApiLog(title = "编辑sku", businessType = BusinessType.UPDATE)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_SHIPPING})
+	@PostMapping("/sku/edit")
+	public ResultDTO editSku(@RequestBody InDto inDto) {
+		EditSkuDTO skuDTO = buildQueryParam(inDto, new EditSkuDTO());
+		long result = spuService.editSku(skuDTO);
+		if(result > 0) {
+			return ResultDTO.buildEmptySuccess().setMsg(ResultMsg.UPDATE_SUCCESS);
+		}
+		return ResultDTO.buildErrorResult().setMsg(ResultMsg.UPDATE_FAIL);
+	}
+
+	@ApiOperation("删除sku")
+	@ApiLog(title = "删除sku", businessType = BusinessType.DELETE)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_SHIPPING})
+	@PostMapping("/sku/del")
+	public ResultDTO delSku(@RequestBody InDto inDto) {
+		Long skuId = Long.parseLong(inDto.getString("skuId"));
+		long result = spuService.delSku(skuId);
+		if(result > 0) {
+			return ResultDTO.buildEmptySuccess().setMsg(ResultMsg.DELETE_SUCCESS);
+		}
+		return ResultDTO.buildErrorResult().setMsg(ResultMsg.DELETE_FAIL);
+	}
+
+	@ApiOperation("修改sku库存")
+	@ApiLog(title = "修改sku库存", businessType = BusinessType.UPDATE)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_SHIPPING})
+	@PostMapping("/sku/stock")
+	public ResultDTO updateSkuStock(@RequestBody InDto inDto) {
+		Long skuId = Long.parseLong(inDto.getString("skuId"));
+		Long skuStock = Long.parseLong(inDto.getString("skuStock"));
+		long result = spuService.updateSkuStock(skuId, skuStock);
+		if(result > 0) {
+			return ResultDTO.buildEmptySuccess().setMsg(ResultMsg.UPDATE_SUCCESS);
+		}
+		return ResultDTO.buildErrorResult().setMsg(ResultMsg.UPDATE_FAIL);
+	}
+
+	@ApiLog(title = "拼豆关联商品", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("拼豆关联商品")
+	@PostMapping("/{version}/ref/group")
+	public ResultDTO getGroupActSku(@RequestBody InDto inDto) {
+		SpuQuery spuQuery = buildQueryParam(inDto, new SpuQuery());
+		UserInfo userInfo = getSimpleUserInfo(true);
+		spuQuery.setUserId(userInfo.getId());
+		Page<SpuListDTO> spuList=spuService.getGroupActSku(spuQuery);
+		return ResultDTO.buildSuccessResult(spuList);
+	}
+}

+ 97 - 0
poyee-app-mall/src/main/java/com/poyee/controller/item/UserCartController.java

@@ -0,0 +1,97 @@
+package com.poyee.controller.item;
+
+import com.google.common.collect.ImmutableMap;
+import com.poyee.anon.ApiLog;
+import com.poyee.controller.base.BaseController;
+import com.poyee.dto.InDto;
+import com.poyee.dto.ResultDTO;
+import com.poyee.enums.BusinessType;
+import com.poyee.handle.ApiVersion;
+import com.poyee.param.item.SimpleMerchantDTO;
+import com.poyee.param.item.UserCartDTO;
+import com.poyee.service.OrderService;
+import com.poyee.service.factory.OrderServiceFactory;
+import com.poyee.service.item.SpuService;
+import com.poyee.utils.AppAssert;
+import com.poyee.utils.StringUtils;
+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.annotation.Resource;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author by po'yi
+ * @Classname SpuController
+ * @Description 购物车相关api
+ * @Date 2023/3/22 17:40
+ */
+@Slf4j
+@Api("购物车api")
+@RestController
+@RequestMapping("/api/{version}/cart")
+public class UserCartController extends BaseController {
+
+    @Autowired
+    private OrderServiceFactory orderServiceFactory;
+    @Resource
+    private SpuService spuService;
+
+    @ApiLog(title = "购物车查询", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(1.0)
+    @ApiOperation("购物车查询")
+    @PostMapping("/list")
+    public ResultDTO getUserCart(@RequestBody InDto inDto) {
+        OrderService orderService = orderServiceFactory.getShopOrderService();
+        List<UserCartDTO> carts = orderService.getUserCartList(getSimpleUserInfo(true).getId());
+        List<Long> skuStatus = Arrays.asList(new Long[]{201L});
+        carts.stream().filter(c -> c.getStatus() == 201).forEach(c -> c.setSkuList(spuService.getSoldSkuList(c.getSpuId(), skuStatus)));
+        List<UserCartDTO> offShelfSkus = carts.stream().filter(c -> c.getStatus() != 201).collect(Collectors.toList());
+        Map<SimpleMerchantDTO, List<UserCartDTO>> cartByMerchant = carts.stream().filter(c -> c.getStatus() == 201)
+                .collect(Collectors.groupingBy(UserCartDTO::getMerchantInfo));
+        Map<String, Object> result = ImmutableMap.of("offShelfSkus", offShelfSkus, "cartByMerchant", cartByMerchant);
+        return ResultDTO.buildSuccessResult(result);
+    }
+
+
+    @ApiLog(title = "购物车修改", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(1.0)
+    @ApiOperation("购物车修改")
+    @PostMapping("/edit")
+    public ResultDTO editUserCart(@RequestBody InDto inDto) {
+        Integer skuId = (Integer) inDto.get("skuId");
+        Integer qty = (Integer) inDto.get("qty");
+        AppAssert.notNull(skuId, "参数skuId为空");
+        AppAssert.notNull(qty, "参数qty为空");
+        OrderService orderService = orderServiceFactory.getShopOrderService();
+        orderService.editUserCart(skuId, qty, getSimpleUserInfo(true).getId());
+        return ResultDTO.buildEmptySuccess();
+    }
+
+    @ApiLog(title = "购物车删除", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(1.0)
+    @ApiOperation("购物车删除")
+    @PostMapping("/del")
+    public ResultDTO delUserCart(@RequestBody InDto inDto) {
+        String idStr = inDto.getString("ids");
+        Boolean allFlag = (Boolean) inDto.get("allFlag");
+		boolean isClearAll = allFlag != null && allFlag;
+        if (!isClearAll && StringUtils.isEmpty(idStr)) {
+            return ResultDTO.buildErrorResult("参数为空");
+        }
+        OrderService orderService = orderServiceFactory.getShopOrderService();
+        orderService.delUserCartByIds(idStr, getSimpleUserInfo(true).getId(), isClearAll);
+        return ResultDTO.buildEmptySuccess();
+    }
+
+
+}

+ 71 - 0
poyee-app-mall/src/main/java/com/poyee/controller/live/AppLiveGoodsController.java

@@ -0,0 +1,71 @@
+package com.poyee.controller.live;
+
+import com.poyee.anon.ApiLog;
+import com.poyee.anon.RequireRoles;
+import com.poyee.constant.UserType;
+import com.poyee.controller.base.BaseController;
+import com.poyee.dto.InDto;
+import com.poyee.dto.ResultDTO;
+import com.poyee.entity.AppLiveGoods;
+import com.poyee.entity.QAppLiveGoods;
+import com.poyee.enums.BusinessType;
+import com.poyee.service.AppLiveGoodsService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.domain.Sort;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@Slf4j
+@Api("直播商品api")
+@RestController
+@RequestMapping("/api/liveGoods/")
+public class AppLiveGoodsController extends BaseController {
+
+    @Resource
+    private AppLiveGoodsService appLiveGoodsService;
+
+    @PostMapping("/list")
+    @ApiLog(title = "直播商品列表", businessType = BusinessType.SEARCH)
+    @ApiOperation("直播商品列表")
+    public ResultDTO findList(@RequestBody InDto inDto){
+        Integer liveId = Integer.valueOf(inDto.getData().get("liveId").toString());
+        return appLiveGoodsService.list(liveId);
+    }
+
+    @PostMapping("/list2")
+    @ApiLog(title = "直播商品列表", businessType = BusinessType.SEARCH)
+    @ApiOperation("直播商品列表")
+    public ResultDTO findList2(@RequestBody InDto inDto){
+        Integer liveId = Integer.valueOf(inDto.getData().get("liveId").toString());
+        String type = inDto.getString("type");
+        return appLiveGoodsService.list2(liveId, type);
+    }
+
+    @PostMapping("/start")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    @ApiLog(title = "直播开始", businessType = BusinessType.UPDATE)
+    @ApiOperation("直播开始")
+    public ResultDTO startLive(@RequestBody InDto inDto){
+        Integer liveId = Integer.valueOf(inDto.getString("liveId"));
+        Long goodsId = Long.valueOf(inDto.getString("goodsId"));
+        return appLiveGoodsService.startLive(liveId, goodsId);
+    }
+
+    @PostMapping("/end")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    @ApiLog(title = "直播结束", businessType = BusinessType.UPDATE)
+    @ApiOperation("直播结束")
+    public ResultDTO endLive(@RequestBody InDto inDto){
+        Integer liveId = Integer.valueOf(inDto.getString("liveId"));
+        Long goodsId = Long.valueOf(inDto.getString("goodsId"));
+        String streamId = inDto.getString("streamId");
+        return appLiveGoodsService.endLive(liveId, goodsId, streamId);
+    }
+}

+ 79 - 0
poyee-app-mall/src/main/java/com/poyee/controller/live/AppUserLivePrizeController.java

@@ -0,0 +1,79 @@
+package com.poyee.controller.live;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.poyee.anon.ApiLog;
+import com.poyee.constant.Constants;
+import com.poyee.controller.base.BaseController;
+import com.poyee.dto.InDto;
+import com.poyee.dto.ResultDTO;
+import com.poyee.enums.BusinessType;
+import com.poyee.service.AppUserLivePrizeService;
+import com.poyee.service.dto.LivePrizeDTO;
+import com.poyee.utils.RedisUtils;
+import com.poyee.utils.StringUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Api("直播间奖品信息")
+@Slf4j
+@RestController
+@RequestMapping("/api/livePrize/")
+public class AppUserLivePrizeController extends BaseController {
+
+    @Resource
+    private AppUserLivePrizeService appUserLivePrizeService;
+    @Resource
+    private RedisUtils redisUtils;
+    @Resource
+    private RedisTemplate<String, Object> redisTemplate;
+
+    @ApiOperation("获取直播间奖品列表")
+    @ApiLog(title = "获取直播间奖品列表", businessType = BusinessType.SEARCH)
+    @PostMapping("/list")
+    public ResultDTO list(@RequestBody InDto inDto) {
+        long liveId = Long.parseLong(inDto.getString("liveId"));
+        String key = inDto.getString("key");
+        if(StringUtils.isEmpty(key)){
+            key = "app_live_coupon_record_";
+        }
+        Map<Object, Object> map = redisUtils.hmget(key + liveId);
+        List<LivePrizeDTO> livePrizeDTOList = null;
+        if(map != null){
+            log.debug("从redis中获取直播间奖品列表json:{}", map.values());
+            List<LivePrizeDTO> dtoList = JSONArray.parseArray(map.values().toString(), LivePrizeDTO.class);
+            // 过滤掉停止发放的优惠券
+            livePrizeDTOList = dtoList.stream().filter(livePrizeDTO -> livePrizeDTO.getSendStatus() != null && livePrizeDTO.getSendStatus() == 1).collect(Collectors.toList());
+            String liveJsonArray = null;
+            if(!CollectionUtils.isEmpty(livePrizeDTOList)){
+                liveJsonArray = JSON.toJSONString(livePrizeDTOList);
+                livePrizeDTOList.forEach(livePrizeDTO -> {
+                    // redis中的领取记录
+                    String receiveKey = "app_live_receive_record_" + liveId + "_" +livePrizeDTO.getPrizeId() + "_" + getSimpleUserInfo(true).getId();
+                    if(redisUtils.get(receiveKey) != null) {
+                        livePrizeDTO.setStatus(Constants.ONE);
+                    }
+                });
+            }
+            log.debug("过滤后的直播间奖品列表:{}", liveJsonArray);
+        }
+        return ResultDTO.buildSuccessResult(livePrizeDTOList);
+       /* List<LivePrizeDTO> livePrizeList = appUserLivePrizeService.findLivePrize(liveId, getSimpleUserInfo(true).getId());
+        return ResultDTO.buildSuccessResult(livePrizeList);*/
+    }
+}

+ 361 - 0
poyee-app-mall/src/main/java/com/poyee/controller/live/CardGroupLivesConfigController.java

@@ -0,0 +1,361 @@
+package com.poyee.controller.live;
+
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.poyee.anon.ApiLog;
+import com.poyee.anon.RequireRoles;
+import com.poyee.constant.UserType;
+import com.poyee.controller.base.BaseController;
+import com.poyee.dto.InDto;
+import com.poyee.dto.ResultDTO;
+import com.poyee.entity.CardGroupLivesConfig;
+import com.poyee.entity.QCardGroupLivesConfig;
+import com.poyee.enums.BusinessType;
+import com.poyee.service.CardGroupLivesConfigService;
+import com.poyee.service.dto.AppLiveDTO;
+import com.poyee.service.dto.CloneLiveDTO;
+import com.poyee.utils.Md5Utils;
+import com.poyee.constant.Constants;
+import com.poyee.utils.PushMsgUtil;
+import com.poyee.utils.RedisUtils;
+import com.poyee.utils.WebSocketUtils;
+import com.tencentcloudapi.common.Credential;
+import com.tencentcloudapi.common.exception.TencentCloudSDKException;
+import com.tencentcloudapi.common.profile.ClientProfile;
+import com.tencentcloudapi.common.profile.HttpProfile;
+import com.tencentcloudapi.vod.v20180717.VodClient;
+import com.tencentcloudapi.vod.v20180717.models.LiveRealTimeClipRequest;
+import com.tencentcloudapi.vod.v20180717.models.LiveRealTimeClipResponse;
+import com.tencentcloudapi.vod.v20180717.models.SimpleHlsClipRequest;
+import com.tencentcloudapi.vod.v20180717.models.SimpleHlsClipResponse;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+@Slf4j
+@Api("商家直播api")
+@RestController
+@RequestMapping("/api/live/")
+public class CardGroupLivesConfigController extends BaseController {
+
+    @Resource
+    private CardGroupLivesConfigService cardGroupLivesConfigService;
+
+    @Value("${tencentCloud.living.secretKey:c018bdfe07b758cb11dc10ffea7feca6}")
+    private String livingSecretKey;
+
+    @Value("${living.tencent.secretId:AKIDsZ0A3f29zYrsc5IEsFLBk23oztWsxlIX}")
+    private String secretId;
+
+    @Value("${living.tencent.secretKey:0jBMGtEI5csrZ2E8l9G6fy0lFRN2QXOy}")
+    private String secretKey;
+
+    @Value("${living.im.host:1309648802.vod2.myqcloud.com}")
+    private String host;
+
+    @Resource
+    private WebSocketUtils webSocketUtils;
+
+    @Resource
+    private RedisUtils redisUtils;
+
+    @PostMapping("/volc/steamEnd/callback")
+    @ApiOperation("火山直播断流回调")
+    public ResultDTO volcengineSteamCallback(@RequestBody JSONObject jsonObject){
+        log.info("火山直播断流回调结果:{}", jsonObject.toJSONString());
+        //(直播结束)断流
+        JSONObject data = jsonObject.getJSONObject("data");
+        if(data != null) {
+            String code = data.getString("stream");
+            Object cache = redisUtils.hget(Constants.LIVING_ROOM_LIKE_KEY, code);
+            int likeNum = 0;
+            if(cache != null) {
+                likeNum = Integer.parseInt(cache.toString());
+            }
+            webSocketUtils.sendGroupMsg(code, "火山直播断流通知", JSON.toJSONString(new result().likeNum = likeNum), "STREAMENDNOTIFY");
+        }
+        return ResultDTO.buildEmptySuccess();
+    }
+
+    @PostMapping("/tencent/steamEnd/callback")
+    @ApiOperation("腾讯直播断流回调")
+    public ResultDTO tencentSteamCallback(@RequestBody JSONObject jsonObject){
+        log.info("腾讯直播断流回调结果:{}", jsonObject.toJSONString());
+        if(jsonObject.containsKey("stream_id")) {
+            String code = jsonObject.getString("stream_id");
+            Object cache = redisUtils.hget(Constants.LIVING_ROOM_LIKE_KEY, code);
+            int likeNum = 0;
+            if(cache != null) {
+                likeNum = Integer.parseInt(cache.toString());
+            }
+            webSocketUtils.sendGroupMsg(code, "腾讯直播断流通知", JSON.toJSONString(new result().likeNum = likeNum), "STREAMENDNOTIFY");
+        }
+        return ResultDTO.buildEmptySuccess();
+    }
+
+    @PostMapping("/add")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING,UserType.USER_ROLE_LIVING})
+    @ApiLog(title = "创建直播间", businessType = BusinessType.INSERT)
+    @ApiOperation("创建直播间")
+    public ResultDTO createLives(@RequestBody InDto inDto){
+        AppLiveDTO appLiveDTO = buildQueryParam(inDto, new AppLiveDTO());
+        return cardGroupLivesConfigService.createLives(appLiveDTO, getSimpleUserInfo(true));
+    }
+
+    @PostMapping("/page")
+    @ApiLog(title = "直播列表", businessType = BusinessType.SEARCH)
+    @ApiOperation("直播列表")
+    public ResultDTO findPage(@RequestBody InDto inDto){
+        PageRequest pageRequest = PageRequest.of(Integer.parseInt(inDto.getString("limit")),
+                Integer.parseInt(inDto.getString("offset")), Sort.Direction.DESC, "createTime");
+        Long status = Long.parseLong(inDto.getData().get("status").toString());
+        return cardGroupLivesConfigService.findLivesPage(status, getSimpleUserInfo(true), pageRequest);
+    }
+
+    @PostMapping("/edit")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    @ApiLog(title = "编辑直播间", businessType = BusinessType.UPDATE)
+    @ApiOperation("编辑直播间")
+    public ResultDTO updateLives(@RequestBody InDto inDto){
+        AppLiveDTO appLiveDTO = buildQueryParam(inDto, new AppLiveDTO());
+        return cardGroupLivesConfigService.updateLives(appLiveDTO, getSimpleUserInfo(true));
+    }
+
+    @PostMapping("/start")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING,UserType.USER_ROLE_LIVING})
+    @ApiLog(title = "直播开始", businessType = BusinessType.UPDATE)
+    @ApiOperation("直播开始")
+    public ResultDTO startLive(@RequestBody InDto inDto){
+        return cardGroupLivesConfigService.startLive(Long.valueOf(inDto.getString("id")), getSimpleUserInfo(true).getMerchantId());
+    }
+
+    @PostMapping("/end")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING,UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_LIVING})
+    @ApiLog(title = "直播结束", businessType = BusinessType.UPDATE)
+    @ApiOperation("直播结束")
+    public ResultDTO endLive(@RequestBody InDto inDto){
+        Long id = Long.valueOf(inDto.getString("id"));
+        return cardGroupLivesConfigService.endLive(id, getSimpleUserInfo(true).getMerchantId());
+    }
+
+    @PostMapping("/online/status")
+    @ApiLog(title = "查询帐号在线状态", businessType = BusinessType.SEARCH)
+    @ApiOperation("查询帐号在线状态")
+    public ResultDTO onlineStatus(@RequestBody InDto inDto){
+        return cardGroupLivesConfigService.onlineStatus(getSimpleUserInfo(true).getId().longValue());
+    }
+
+    //@ApiLog(title = "商家直播回调-腾讯直播", businessType = BusinessType.UPDATE)
+    @PostMapping("/tencentCallBack")
+    public void tencentCallBack(@RequestBody JSONObject params) {
+        /*{
+            "app": "mlivecdn.hobbystocks.cn",
+                "appid": 1309648802,
+                "appname": "live",
+                "callback_ext": "{\"video_codec\":\"h264\",\"session_id\":\"1767705490833341553\",\"resolution\":\"1088x1920\"}",
+                "channel_id": "TC4088024121016602",
+                "duration": 45,
+                "end_time": 1733818379,
+                "end_time_usec": 159101,
+                "event_type": 100,
+                "file_format": "hls",
+                "file_id": "1397757899855318636",
+                "file_size": 41151964,
+                "media_start_time": 51331905,
+                "record_bps": 0,
+                "record_file_id": "1397757899855318636",
+                "sign": "f8604f92fa23182847aea96644185726",
+                "start_time": 1733818336,
+                "start_time_usec": 643117,
+                "stream_id": "TC4088024121016602",
+                "stream_param": "txSecret=92eed031935e95dc9e370a102a143bc1&txTime=675b0880",
+                "t": 1733818982,
+                "task_id": "1767705490833341553",
+                "video_id": "1309648802_80c8a08eb60e4df2873efe1c036e46fa",
+                "video_url": "http://1309648802.vod2.myqcloud.com/46b68c6bvodcq1309648802/503721431397757899855318636/playlist.m3u8"
+        }*/
+        //JSONObject retbackMsg = new JSONObject();
+        //retbackMsg.put("code", 0);
+        log.info("tencentCallBack result: " + params);
+        if (null != params) {
+            Integer t = params.getInteger("t");
+            String sign = params.getString("sign");
+            //验签
+            String signStr = Md5Utils.hash(livingSecretKey + t);
+            log.info("商城直播回调signStr: " + signStr);
+            if (StringUtils.isNotEmpty(sign) && StringUtils.isNotEmpty(signStr) && sign.equals(signStr)) {//验签通过
+                QCardGroupLivesConfig qCardGroupLivesConfig = QCardGroupLivesConfig.cardGroupLivesConfig;
+                String streamId = params.getString("stream_id");//直播间code
+                String videoUrl = params.getString("video_url");//回放地址
+                // 查询是否有回放地址
+                CardGroupLivesConfig oldEntity = cardGroupLivesConfigService.getQueryFactory().
+                        selectFrom(qCardGroupLivesConfig)
+                        .where(qCardGroupLivesConfig.code.eq(streamId).and(qCardGroupLivesConfig.category.eq("goods")))
+                        .fetchOne();
+                if(oldEntity == null){
+                    log.error("商城直播不存在");
+                    return;
+                }
+                // 如果之前有回放地址,在后面用逗号追加一个新地址
+                String oldPath = oldEntity.getPlaybackPath();
+                if(Strings.isNotEmpty(oldPath)){
+                    videoUrl = String.join(",", oldPath, videoUrl);
+                }
+                // 腾讯直播结束回调 根据code同步直播间回放地址
+                long result = cardGroupLivesConfigService.buildPlaybackPath(videoUrl, oldEntity.getId());
+                if(result == 0){
+                    log.error("同步回放地址失败:{}", oldEntity.getCode());
+                }
+            }else{
+                log.info("商城直播回调签名失败: {}", signStr);
+            }
+        }
+    }
+
+    @PostMapping("/detail")
+    @ApiLog(title = "商家直播间详情", businessType = BusinessType.SEARCH)
+    @ApiOperation("商家直播间详情")
+    public ResultDTO findDetail(@RequestBody InDto inDto){
+        Long id = Long.valueOf(inDto.getData().get("id").toString());
+        return cardGroupLivesConfigService.findDetail(id, getSimpleUserInfo(true));
+    }
+
+    @PostMapping("/createGroup")
+    @ApiLog(title = "创建聊天室", businessType = BusinessType.INSERT)
+    @ApiOperation("创建聊天室")
+    public ResultDTO createGroup(@RequestBody InDto inDto){
+        String code = inDto.getData().get("code").toString();
+        cardGroupLivesConfigService.createGroup(getSimpleUserInfo(true).toString(), code, code);
+        return successResult(null);
+    }
+
+    @PostMapping("/destroyGroup")
+    @ApiLog(title = "解散聊天室", businessType = BusinessType.UPDATE)
+    @ApiOperation("解散聊天室")
+    public ResultDTO destroyGroup(@RequestBody InDto inDto){
+        String code = inDto.getData().get("code").toString();
+        cardGroupLivesConfigService.destroyGroup(code);
+        return ResultDTO.buildEmptySuccess().setMsg("解散成功");
+    }
+
+    /**
+     * 直播即时剪辑
+     * @param endTime 剪辑结束时间
+     * @param liveStartTime 剪辑开始时间
+     * @param streamId 直播code
+     * @return
+     */
+    @ApiOperation("直播即时剪辑")
+    @PostMapping("/getPlayBackUrl")
+    public String getPlayBackUrl(String endTime, String liveStartTime, String streamId){
+        String respJsonString = null;
+        try {
+            // 调用腾讯云直播剪辑获取商品拆卡直播回放地址
+            Credential cred = new Credential(secretId, secretKey);
+            // 实例化一个http选项,可选的,没有特殊需求可以跳过
+            HttpProfile httpProfile = new HttpProfile();
+            httpProfile.setEndpoint("vod.tencentcloudapi.com");
+            // 实例化一个client选项,可选的,没有特殊需求可以跳过
+            ClientProfile clientProfile = new ClientProfile();
+            clientProfile.setHttpProfile(httpProfile);
+            // 实例化要请求产品的client对象,clientProfile是可选的
+            VodClient client = new VodClient(cred, "", clientProfile);
+            // 实例化一个请求对象,每个接口都会对应一个request对象
+            LiveRealTimeClipRequest req = new LiveRealTimeClipRequest();
+            // 所有时间相关参数统一采用 ISO 8601 表示的 UTC 时间,格式为 YYYY-MM-dd'T'HH:mm:ss'Z'
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+            sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
+            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            Date start = format.parse(liveStartTime);
+            Date end = format.parse(endTime);
+            String startTimestamp = sdf.format(start);
+            String endTimestamp = sdf.format(end);
+            req.setStreamId(streamId);   // 推流直播码
+            req.setStartTime(startTimestamp);  // 直播开始时间
+            req.setEndTime(endTimestamp);    // 直播结束时间
+            req.setHost(host);
+            log.info("直播即时剪辑开始时间:{}, 结束时间:{}", liveStartTime, endTime);
+            // 返回的resp是一个LiveRealTimeClipResponse的实例,与请求对象对应
+            LiveRealTimeClipResponse resp = client.LiveRealTimeClip(req);
+            // 输出json格式的字符串回包
+            respJsonString = LiveRealTimeClipResponse.toJsonString(resp);
+            // 输出json格式的字符串回包
+            log.info("直播剪辑回调:{}" + respJsonString);
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error(e.toString());
+        }
+        return respJsonString;
+    }
+
+    /**
+     * 简单HLS剪辑
+     * @return
+     */
+    @ApiOperation("简单HLS剪辑")
+    @PostMapping( "/simpleHlsClip")
+    public String simpleHlsClip(@RequestBody InDto inDto){
+        String url = inDto.getData().get("url").toString();
+        Float startTimeOffset = Float.valueOf(inDto.getData().get("startTimeOffset").toString());
+        Float endTimeOffset = Float.valueOf(inDto.getData().get("endTimeOffset").toString());
+        String respJsonString = null;
+        try{
+            // 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey,此处还需注意密钥对的保密
+            // 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取
+            Credential cred = new Credential(secretId, secretKey);
+            // 实例化一个http选项,可选的,没有特殊需求可以跳过
+            HttpProfile httpProfile = new HttpProfile();
+            httpProfile.setEndpoint("vod.tencentcloudapi.com");
+            // 实例化一个client选项,可选的,没有特殊需求可以跳过
+            ClientProfile clientProfile = new ClientProfile();
+            clientProfile.setHttpProfile(httpProfile);
+            // 实例化要请求产品的client对象,clientProfile是可选的
+            VodClient client = new VodClient(cred, "", clientProfile);
+            // 实例化一个请求对象,每个接口都会对应一个request对象
+            SimpleHlsClipRequest req = new SimpleHlsClipRequest();
+            req.setUrl(url); // 需要裁剪的腾讯云点播 HLS 视频 URL。
+            req.setStartTimeOffset(startTimeOffset); // 裁剪的开始偏移时间,单位秒。默认 0,即从视频开头开始裁剪。负数表示距离视频结束多少秒开始裁剪。例如 -10 表示从倒数第 10 秒开始裁剪。
+            req.setEndTimeOffset(endTimeOffset); // 裁剪的结束偏移时间,单位秒。默认 0,即裁剪到视频尾部。负数表示距离视频结束多少秒结束裁剪。例如 -10 表示到倒数第 10 秒结束裁剪。
+            log.info("简单HLS剪辑url:{}" + url + "===========剪辑开始偏移时间:{}" + startTimeOffset + "=============剪辑结束偏移时间:{}" + endTimeOffset);
+            // 返回的resp是一个SimpleHlsClipResponse的实例,与请求对象对应
+            SimpleHlsClipResponse resp = client.SimpleHlsClip(req);
+            respJsonString = SimpleHlsClipResponse.toJsonString(resp);
+            // 输出json格式的字符串回包
+            log.info("简单HLS剪辑回调:{}" + respJsonString);
+        } catch (TencentCloudSDKException e) {
+            log.error(e.toString());
+            e.printStackTrace();
+        }
+        return respJsonString;
+    }
+
+    @ApiOperation("克隆直播间")
+    @ApiLog(title = "克隆直播间", businessType = BusinessType.INSERT)
+    @PostMapping( "/cloneLive")
+    public ResultDTO cloneLive(@RequestBody InDto inDto){
+        if(inDto == null)  return ResultDTO.buildErrorResult("参数为空");
+        CloneLiveDTO cloneLiveDTO = new CloneLiveDTO();
+        cloneLiveDTO.setGroupInfoId(Long.parseLong(inDto.get("groupInfoId").toString()));
+        cloneLiveDTO.setMerchantId(Long.parseLong(inDto.get("merchantId").toString()));
+        cloneLiveDTO.setType(Integer.parseInt(inDto.get("type").toString()));
+        cloneLiveDTO.setMerchantName(inDto.get("merchantName").toString());
+        cardGroupLivesConfigService.cloneLive(cloneLiveDTO);
+        return ResultDTO.buildEmptySuccess();
+    }
+
+    private class result {
+        int likeNum;
+    }
+}

+ 87 - 0
poyee-app-mall/src/main/java/com/poyee/controller/live/LiveCartController.java

@@ -0,0 +1,87 @@
+package com.poyee.controller.live;
+
+import com.poyee.anon.ApiLog;
+import com.poyee.controller.base.BaseController;
+import com.poyee.dto.InDto;
+import com.poyee.dto.ResultDTO;
+import com.poyee.entity.CardGroupLiveExplain;
+import com.poyee.enums.BusinessType;
+import com.poyee.service.LiveCartService;
+import com.poyee.service.dto.LiveCatExplainDTO;
+import com.poyee.utils.StringUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+@Slf4j
+@Api("直播间购物车")
+@RequestMapping("/api/liveCart")
+@RestController
+public class LiveCartController extends BaseController {
+
+    @Resource
+    private LiveCartService liveCartService;
+
+    @PostMapping("/lastRecord")
+    @ApiLog(title = "上一次购物车记录", businessType = BusinessType.SEARCH)
+    @ApiOperation("上一次购物车记录")
+    public ResultDTO lastRecord(@RequestBody InDto inDto){
+        String merchantIdStr = inDto.getString("merchantId");
+        if(StringUtils.isEmpty(merchantIdStr)){
+            return ResultDTO.buildErrorResult("参数merchantId不能为空");
+        }
+        Long merchantId = Long.valueOf(merchantIdStr);
+        return liveCartService.findLastCart(merchantId);
+    }
+
+    @PostMapping("/explain")
+    @ApiLog(title = "直播间视频讲解", businessType = BusinessType.UPDATE)
+    @ApiOperation("直播间视频讲解")
+    public ResultDTO explain(@RequestBody InDto inDto){
+        String explainStatusStr = inDto.getString("explainStatus");
+        String orderListIdStr = inDto.getString("orderListId");
+        if(StringUtils.isEmpty(explainStatusStr)){
+            return ResultDTO.buildErrorResult("参数explainStatus不能为空");
+        }
+        if(StringUtils.isEmpty(orderListIdStr)){
+            return ResultDTO.buildErrorResult("参数orderListId不能为空");
+        }
+        Integer explainStatus = Integer.valueOf(explainStatusStr);
+        Long orderListId = Long.valueOf(orderListIdStr);
+        long rs = liveCartService.updateExplainStatus(explainStatus, orderListId);
+        if(rs > 0){
+            return ResultDTO.buildEmptySuccess();
+        }else {
+            return ResultDTO.buildErrorResult();
+        }
+    }
+
+    @PostMapping("/explain2")
+    @ApiLog(title = "直播间视频讲解", businessType = BusinessType.UPDATE)
+    @ApiOperation("直播间视频讲解")
+    public ResultDTO explain2(@RequestBody LiveCatExplainDTO liveCatExplainDTO){
+        if(liveCatExplainDTO == null){
+            return ResultDTO.buildErrorResult("参数为空");
+        }
+        liveCartService.saveExplain(liveCatExplainDTO);
+        return ResultDTO.buildEmptySuccess();
+    }
+
+    @PostMapping("/explain/list")
+    @ApiLog(title = "直播间讲解列表", businessType = BusinessType.UPDATE)
+    @ApiOperation("直播间讲解列表")
+    public ResultDTO explainList(@RequestBody LiveCatExplainDTO liveCatExplainDTO){
+        if(liveCatExplainDTO == null || liveCatExplainDTO.getLiveId() == null){
+            return ResultDTO.buildErrorResult("参数为空");
+        }
+        Page<CardGroupLiveExplain> page =liveCartService.explainList(liveCatExplainDTO);
+        return ResultDTO.buildSuccessResult(page);
+    }
+}

+ 38 - 0
poyee-app-mall/src/main/java/com/poyee/controller/live/OrderListController.java

@@ -0,0 +1,38 @@
+package com.poyee.controller.live;
+
+import com.poyee.anon.ApiLog;
+import com.poyee.anon.RequireRoles;
+import com.poyee.constant.UserType;
+import com.poyee.dto.InDto;
+import com.poyee.dto.ResultDTO;
+import com.poyee.enums.BusinessType;
+import com.poyee.service.OrderListService;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.Map;
+
+@Slf4j
+@RequestMapping("/api/orderList")
+@RestController
+public class OrderListController {
+
+    @Resource private OrderListService orderListService;
+
+    @ApiOperation("商城订单直播操作")
+    @ApiLog(title = "商城订单直播操作", businessType = BusinessType.UPDATE)
+    @PostMapping("/operateOrderLive")
+    public ResultDTO operateOrderLive(@RequestBody InDto inDto) {
+        Map<String, Object> dataMap = inDto.getData();
+        log.info("直播间订单操作:{}", dataMap);
+        Long liveId = null;
+        if(dataMap.get("liveId") != null) liveId = Long.parseLong(dataMap.get("liveId").toString());
+        Integer type = Integer.parseInt(dataMap.get("type").toString());
+        Long orderId = Long.parseLong(dataMap.get("orderId").toString());
+        Long merchantId = Long.parseLong(dataMap.get("merchantId").toString());
+        orderListService.operateOrderLive(type, orderId, liveId, merchantId);
+        return ResultDTO.buildSuccessResult(null);
+    }
+}

+ 48 - 0
poyee-app-mall/src/main/java/com/poyee/controller/live/UserLiveConfigController.java

@@ -0,0 +1,48 @@
+package com.poyee.controller.live;
+
+import com.poyee.anon.ApiLog;
+import com.poyee.controller.base.BaseController;
+import com.poyee.dto.InDto;
+import com.poyee.dto.ResultDTO;
+import com.poyee.entity.CardGroupLivesConfig;
+import com.poyee.enums.BusinessType;
+import com.poyee.service.UserLiveConfigService;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * 用户直播
+ */
+@Slf4j
+@RestController
+@RequestMapping("/api/userLive")
+public class UserLiveConfigController extends BaseController {
+
+    @Resource private UserLiveConfigService userLiveConfigService;
+
+    @ApiOperation("开始直播")
+    @ApiLog(title = "开始直播", businessType = BusinessType.UPDATE)
+    @PostMapping("/start")
+    public ResultDTO startLive(@RequestBody InDto inDto){
+        Long orderId = Long.parseLong(inDto.getString("orderId"));
+        Long goodsId = Long.parseLong(inDto.getString("goodsId"));
+        Long userId = getSimpleUserInfo(true).getId().longValue();
+        CardGroupLivesConfig cardGroupLivesConfig = userLiveConfigService.startLive(userId, orderId, goodsId);
+        return ResultDTO.buildSuccessResult(cardGroupLivesConfig);
+    }
+
+    @ApiOperation("结束直播")
+    @ApiLog(title = "结束直播", businessType = BusinessType.UPDATE)
+    @PostMapping("/end")
+    public ResultDTO endLive(@RequestBody InDto inDto){
+        Long orderListId = Long.parseLong(inDto.getString("id"));
+        userLiveConfigService.endLive(orderListId);
+        return ResultDTO.buildSuccessResult(null);
+    }
+}

+ 137 - 0
poyee-app-mall/src/main/java/com/poyee/controller/luckyPoint/LuckyPointController.java

@@ -0,0 +1,137 @@
+package com.poyee.controller.luckyPoint;
+
+import com.google.common.collect.ImmutableMap;
+import com.poyee.anon.ApiLog;
+import com.poyee.controller.base.BaseController;
+import com.poyee.dto.InDto;
+import com.poyee.dto.ResultDTO;
+import com.poyee.enums.BusinessType;
+import com.poyee.handle.ApiVersion;
+import com.poyee.param.UserInfo;
+import com.poyee.service.LuckyPointService;
+import com.poyee.service.dto.LuckyPointExchangeDetailDTO;
+import com.poyee.service.dto.LuckyPointExchangeRecordByDate;
+import com.poyee.service.dto.LuckyPointExchangeRecordDTO;
+import com.poyee.service.dto.LuckyPointMainDTO;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+
+@Slf4j
+@Api("鸿运活动api")
+@RequestMapping("/api/luckyPoint")
+@RestController
+@CrossOrigin(allowCredentials = "true")
+public class LuckyPointController extends BaseController {
+
+    @Resource
+    private LuckyPointService luckyPointService;
+
+    @ApiOperation("鸿运活动首页")
+    @ApiLog(title = "鸿运活动首页", businessType = BusinessType.SEARCH)
+    @PostMapping("/page")
+    public ResultDTO list(@RequestBody InDto inDto) {
+        Map<String, Object> dataMap = inDto.getData();
+        log.info("鸿运活动首页参数:{}", dataMap);
+        int type = 1;
+        if(inDto.get("type") != null){
+           type = Integer.parseInt(inDto.getString("type"));
+        }
+        String actType = inDto.getString("actType");
+        int progress = 1;
+        if(inDto.get("progress") != null){
+            progress = Integer.parseInt(inDto.getString("progress"));
+        }
+        LuckyPointMainDTO luckyPointMainDTO = luckyPointService.list(getSimpleUserInfo(true).getId().longValue(),
+                type, inDto.getPageNo(), inDto.getPageSize(), actType, progress);
+        return ResultDTO.buildSuccessResult(luckyPointMainDTO);
+    }
+
+    @ApiOperation("抽拉卜卜活动")
+    @ApiLog(title = "抽拉卜卜活动", businessType = BusinessType.SEARCH)
+    @PostMapping("/{version}/page")
+    @ApiVersion(4.1)
+    public ResultDTO listForLabubu(@RequestBody InDto inDto) {
+        Map<String, Object> dataMap = inDto.getData();
+        log.info("鸿运活动首页参数:{}", dataMap);
+        int type = 1;
+        if(inDto.get("type") != null){
+            type = Integer.parseInt(inDto.getString("type"));
+        }
+        String actType = inDto.getString("actType");
+        int progress = 1;
+        if(inDto.get("progress") != null){
+            progress = Integer.parseInt(inDto.getString("progress"));
+        }
+        LuckyPointMainDTO verifyUserAct = luckyPointService.list(getSimpleUserInfo(true).getId().longValue(),
+                type , inDto.getPageNo(), inDto.getPageSize(), "verify_user_act", progress);
+        LuckyPointMainDTO completeOrderAct = luckyPointService.list(getSimpleUserInfo(true).getId().longValue(),
+                type, inDto.getPageNo(), inDto.getPageSize(), "complete_order_act", progress);
+        return ResultDTO.buildSuccessResult(ImmutableMap.of("verify_user_act", verifyUserAct,
+                "complete_order_act", completeOrderAct
+        ));
+    }
+
+    @ApiOperation("兑换详情页")
+    @ApiLog(title = "兑换详情页", businessType = BusinessType.SEARCH)
+    @PostMapping("/detail")
+    public ResultDTO exchangeDetail(@RequestBody InDto inDto) {
+        Map<String, Object> dataMap = inDto.getData();
+        log.info("鸿运活动兑换详情参数:{}", dataMap);
+        Long actId = Long.parseLong(dataMap.get("actId").toString());
+        UserInfo user = getSimpleUserInfo(false);
+        Long userId = user == null ? 72438L : user.getId().longValue();
+        LuckyPointExchangeDetailDTO exchangeDetail = luckyPointService.exchangeDetail(actId, userId);
+        return ResultDTO.buildSuccessResult(exchangeDetail);
+    }
+
+    @ApiOperation("查询我的兑换记录")
+    @ApiLog(title = "查询我的兑换记录", businessType = BusinessType.SEARCH)
+    @PostMapping("/myExchange")
+    public ResultDTO getMyExchangeRecord(@RequestBody InDto inDto) {
+        Map<String, Object> dataMap = inDto.getData();
+        log.info("查询我的兑换记录参数:{}", dataMap);
+        Long actId = Long.parseLong(dataMap.get("actId").toString());
+        List<LuckyPointExchangeRecordDTO> exchangeRecordList = luckyPointService.getMyExchangeRecord(getSimpleUserInfo(true).getId().longValue(), actId);
+        return ResultDTO.buildSuccessResult(exchangeRecordList);
+    }
+
+    @ApiOperation("查询所有用户的记录")
+    @ApiLog(title = "查询所有用户的兑换记录", businessType = BusinessType.SEARCH)
+    @PostMapping("/allExchange")
+    public ResultDTO getAllExchangeRecord(@RequestBody InDto inDto) {
+        Map<String, Object> dataMap = inDto.getData();
+        log.info("查询所有用户的记录参数:{}", dataMap);
+        Long actId = Long.parseLong(dataMap.get("actId").toString());
+        Page<LuckyPointExchangeRecordDTO> exchangeRecordList = luckyPointService.getAllExchangeRecord(actId, inDto.getPageNo(), inDto.getPageSize());
+        return ResultDTO.buildSuccessResult(exchangeRecordList);
+    }
+
+    @ApiOperation("查询我的兑换记录-日期分组")
+    @ApiLog(title = "查询我的兑换记录-日期分组", businessType = BusinessType.SEARCH)
+    @PostMapping("/myExchangeInfo")
+    public ResultDTO getMyExchangeRecordByDate(@RequestBody InDto inDto) {
+        Map<String, Object> dataMap = inDto.getData();
+        log.info("查询我的兑换记录-日期分组参数:{}", dataMap);
+        Long actId = Long.parseLong(dataMap.get("actId").toString());
+        List<LuckyPointExchangeRecordByDate> exchangeRecordList = luckyPointService.getMyExchangeRecordByDate(actId, getSimpleUserInfo(true).getId().longValue());
+        return ResultDTO.buildSuccessResult(exchangeRecordList);
+    }
+
+    @ApiOperation("详情页兑换记录")
+    @ApiLog(title = "详情页兑换记录", businessType = BusinessType.SEARCH)
+    @PostMapping("/detailExchange")
+    public ResultDTO getDetailExchangeRecord(@RequestBody InDto inDto) {
+        Map<String, Object> dataMap = inDto.getData();
+        log.info("详情页兑换记录的记录参数:{}", dataMap);
+        Long actId = Long.parseLong(dataMap.get("actId").toString());
+        Page<LuckyPointExchangeRecordDTO> exchangeRecordList = luckyPointService.getDetailExchangeRecord(actId, inDto.getPageNo(), inDto.getPageSize());
+        return ResultDTO.buildSuccessResult(exchangeRecordList);
+    }
+}

+ 233 - 0
poyee-app-mall/src/main/java/com/poyee/controller/merchant/MerchantController.java

@@ -0,0 +1,233 @@
+package com.poyee.controller.merchant;
+
+import com.poyee.anon.ApiLog;
+import com.poyee.anon.RequireRoles;
+import com.poyee.constant.UserType;
+import com.poyee.controller.base.BaseController;
+import com.poyee.dto.InDto;
+import com.poyee.dto.ResultDTO;
+import com.poyee.enums.BusinessType;
+import com.poyee.handle.ApiVersion;
+import com.poyee.param.SkuGoodsQuery;
+import com.poyee.param.SpuQuery;
+import com.poyee.param.UserInfo;
+import com.poyee.param.dto.GoodsReportDTO;
+import com.poyee.param.dto.OrderPublicParam;
+import com.poyee.param.dto.UserCardGoodsDTO;
+import com.poyee.param.item.SkuDTO;
+import com.poyee.service.MerchantInfoService;
+import com.poyee.service.SkuService;
+import com.poyee.service.UserCardGoodsService;
+import com.poyee.service.dto.MallListDto;
+import com.poyee.service.dto.SpuDTO;
+import com.poyee.service.item.SpuService;
+import com.poyee.utils.UserUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * @author by po'yi
+ * @Classname SpuController
+ * @Description 商城商品相关api
+ * @Date 2022/8/22 17:40
+ */
+@Slf4j
+@Api("商城商家api")
+@RestController
+@RequestMapping("/api/merchant")
+public class MerchantController extends BaseController {
+
+	@Autowired
+	private SpuService spuService;
+	@Autowired
+	private SkuService skuService;
+	@Autowired
+	private UserCardGoodsService userCardGoodsService;
+	@Resource
+	private MerchantInfoService merchantInfoService;
+
+	@ApiLog(title = "商家商品搜索", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("商品搜索")
+	@PostMapping("/{version}/goods/list")
+	@RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+	public ResultDTO searchSku(@RequestBody InDto inDto) {
+		UserInfo userInfo = getSimpleUserInfo(true);
+		if(userInfo.getMerchantId()==null){
+			return ResultDTO.buildErrorResult("商家信息获取失败,请核实权限!");
+		}
+		SpuQuery spuQuery = buildQueryParam(inDto, new SpuQuery());
+		spuQuery.setMerchantId(userInfo.getMerchantId());
+		Page<SkuDTO> skuPage=spuService.searchMerchantSKu(spuQuery);
+		return ResultDTO.buildSuccessResult(skuPage);
+	}
+
+	@ApiLog(title = "商品上下架", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("商品上下架")
+	@PostMapping("/{version}/goods/shelfOnOff")
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_SHIPPING})
+	public ResultDTO shelfOnOff(@RequestBody InDto inDto) {
+		UserInfo userInfo = getSimpleUserInfo(true);
+		skuService.shelfOnOff(userInfo.getMerchantId(),Long.valueOf(inDto.getString("skuId")),Long.valueOf(inDto.getString("status")), userInfo.getRoleCode());
+		return ResultDTO.buildEmptySuccess();
+	}
+
+
+	@ApiLog(title = "查询订单明细的卡密", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("查询订单明细的卡密")
+	@PostMapping("/{version}/getGoodsBySkuId")
+	public ResultDTO getGoodsBySkuId(@RequestBody InDto inDto) {
+		SkuGoodsQuery goodsQuery = buildQueryParam(inDto, new SkuGoodsQuery());
+		Page<UserCardGoodsDTO> goods = userCardGoodsService.getGoodsBySkuId(goodsQuery);
+		return ResultDTO.buildSuccessResult(goods);
+	}
+
+	@ApiLog(title = "查询订单明细的卡密", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(2.6)
+	@ApiOperation("查询订单明细的卡密")
+	@PostMapping("/{version}/getGoodsBySkuId")
+	public ResultDTO getGoodsBySkuIdV2(@RequestBody InDto inDto) {
+		SkuGoodsQuery goodsQuery = buildQueryParam(inDto, new SkuGoodsQuery());
+		Page<UserCardGoodsDTO> goods = userCardGoodsService.getGoodsBySkuId(goodsQuery);
+		GoodsReportDTO reportDTO=userCardGoodsService.getReportUserMsg(goodsQuery.getOrderListId());
+		reportDTO.setPageGoods(goods);
+		return ResultDTO.buildSuccessResult(reportDTO);
+	}
+
+	@ApiLog(title = "订单公示卡片", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("订单公示卡片")
+	@PostMapping("/{version}/order/public")
+	public ResultDTO orderPublic(@RequestBody OrderPublicParam param) {
+		UserCardGoodsDTO goodsDTO = param.getGoods();
+		return ResultDTO.buildSuccessResult(userCardGoodsService.orderPublic(goodsDTO));
+	}
+
+	@ApiLog(title = "订单公示审核", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("订单公示审核")
+	@PostMapping("/{version}/orderGoods/review")
+	//@RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+	public ResultDTO reviewOrderGoods(@RequestBody InDto inDto) {
+		if(inDto==null||inDto.get("orderListId")==null||inDto.get("status")==null){
+			return ResultDTO.buildErrorResult("参数为空");
+		}
+		userCardGoodsService.reviewOrderGoods(Long.valueOf(inDto.getString("orderListId")),Long.valueOf(inDto.getString("status")),
+				getSimpleUserInfo(true).getMerchantId());
+		return ResultDTO.buildEmptySuccess();
+	}
+
+	@ApiLog(title = "删除公示卡密", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("删除公示卡密")
+	@PostMapping("/{version}/orderGoods/del")
+	//@RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+	public ResultDTO delOrderGoods(@RequestBody InDto inDto) {
+		if(inDto==null||inDto.get("id")==null){
+			return ResultDTO.buildErrorResult("参数为空");
+		}
+		userCardGoodsService.delOrderGoods(Long.valueOf(inDto.getString("id")), getSimpleUserInfo(true));
+		return ResultDTO.buildEmptySuccess();
+	}
+
+
+	@ApiLog(title = "获取商城商家用户", businessType = BusinessType.SEARCH)
+	@ApiOperation("获取商城商家用户")
+	@PostMapping("/mallList")
+	public ResultDTO findMallList() {
+		List<MallListDto> mallListDtoList = merchantInfoService.findMallList();
+		return successResult(mallListDtoList);
+	}
+
+	@ApiLog(title = "获取商城商家用户V2", businessType = BusinessType.SEARCH)
+	@ApiOperation("获取商城商家用户V2")
+	@PostMapping("/mallList2")
+	public ResultDTO findMallList(@RequestBody InDto inDto) {
+		Long userId = null;
+		UserInfo userInfo = UserUtils.getSimpleUserInfo(true);
+		if(userInfo != null){
+			userId = userInfo.getId().longValue();
+		}
+		List<MallListDto> mallListDtoList = merchantInfoService.findMallList2(userId, inDto.getIntegerParam("status"));
+		return successResult(mallListDtoList);
+	}
+
+	@ApiLog(title = "获取商家spu", businessType = BusinessType.SEARCH)
+	@ApiOperation("获取商家spu")
+	@PostMapping("/spu/list")
+	@RequireRoles(value = {UserType.USER_ROLE_SHIPPING,UserType.USER_ROLE_PUBLICITY, UserType.USER_ROLE_LIVING, UserType.USER_ROLE_DELIVERY})
+	public ResultDTO searchSpu(@RequestBody InDto inDto) {
+		UserInfo userInfo = getSimpleUserInfo(true);
+		if(userInfo.getMerchantId() == null){
+			return ResultDTO.buildErrorResult("商家信息获取失败,请核实权限!");
+		}
+		PageRequest pageRequest = PageRequest.of(inDto.getPageNo() - 1,
+				inDto.getPageSize(), Sort.Direction.DESC, "id");
+		Page<SpuDTO> page = spuService.searchMerchantSpu(userInfo.getMerchantId(), pageRequest);
+		return ResultDTO.buildSuccessResult(page);
+	}
+
+	@ApiLog(title = "获取商家spu和拍卖商品", businessType = BusinessType.SEARCH)
+	@ApiOperation("获取商家spu")
+	@PostMapping("/spu/list2")
+	@RequireRoles(value = {UserType.USER_ROLE_SHIPPING,UserType.USER_ROLE_PUBLICITY, UserType.USER_ROLE_LIVING, UserType.USER_ROLE_DELIVERY})
+	public ResultDTO searchGoods() {
+		UserInfo userInfo = getSimpleUserInfo(true);
+		if(userInfo.getMerchantId() == null){
+			return ResultDTO.buildErrorResult("商家信息获取失败,请核实权限!");
+		}
+		List<SpuDTO> list = spuService.searchMerchantSpu2(userInfo.getMerchantId());
+		return ResultDTO.buildSuccessResult(list);
+	}
+
+	@ApiLog(title = "管理员:精选公示图片", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("管理员:精选公示图片")
+	@PostMapping("/{version}/goods/img/like")
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN})
+	public ResultDTO likeOrderGoods(@RequestBody InDto inDto) {
+		Integer id = inDto.getIntegerParam("id");
+		if (id == null) {
+			return ResultDTO.buildErrorResult("参数为空");
+		}
+		boolean likeAble = inDto.getBooleanParam("likeAble");
+		userCardGoodsService.likeOrderGoods(id, likeAble);
+		return ResultDTO.buildEmptySuccess();
+	}
+
+	@ApiLog(title = "管理员:精选公示视频", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("管理员:精选公示视频")
+	@PostMapping("/{version}/goods/video/like")
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN})
+	public ResultDTO likeOrderVideoGoods(@RequestBody InDto inDto) {
+		Integer id = inDto.getIntegerParam("id");
+		if (id == null) {
+			return ResultDTO.buildErrorResult("参数为空");
+		}
+		Integer checkStatus = inDto.getIntegerParam("checkStatus");
+		userCardGoodsService.likeOrderGoodsVideo(id, checkStatus);
+		return ResultDTO.buildEmptySuccess();
+	}
+}

+ 178 - 0
poyee-app-mall/src/main/java/com/poyee/controller/report/ReportInfoController.java

@@ -0,0 +1,178 @@
+package com.poyee.controller.report;
+
+
+import com.poyee.anon.ApiLog;
+import com.poyee.controller.base.BaseController;
+import com.poyee.dto.InDto;
+import com.poyee.dto.ResultDTO;
+import com.poyee.entity.ReportInfo;
+import com.poyee.enums.BusinessType;
+import com.poyee.param.UserInfo;
+import com.poyee.service.ReportInfoService;
+import com.poyee.service.dto.ReportInfoRecordDTO;
+import com.poyee.service.impl.DictDataCacheService;
+import com.poyee.utils.VCodeUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.beanutils.BeanUtils;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+@Slf4j
+@Api("拼团&直播间举报")
+@RequestMapping("/api/reportInfo")
+@RestController
+public class ReportInfoController extends BaseController {
+    @Resource
+    private ReportInfoService reportInfoService;
+    @Resource
+    private VCodeUtils vCodeUtils;
+    @Resource
+    private DictDataCacheService dictDataCacheService;
+
+    @ApiOperation("用户撤销举报")
+    @ApiLog(title = "用户撤销举报", businessType = BusinessType.INSERT)
+    @PostMapping("/cancel")
+    public ResultDTO cancel(@RequestBody InDto inDto) {
+        if (null == inDto || inDto.get("id") == null){
+            return ResultDTO.buildErrorResult("参数不能为空");
+        }
+        reportInfoService.cancel(inDto.getIntegerParam("id"));
+        return ResultDTO.buildEmptySuccess();
+    }
+
+    @ApiOperation("新增举报v2")
+    @ApiLog(title = "新增举报v2", businessType = BusinessType.INSERT)
+    @PostMapping("/save")
+    public ResultDTO saveReportInfoV2(@RequestBody InDto inDto) {
+        if (null == inDto){
+            return ResultDTO.buildErrorResult("参数不能为空");
+        }
+        String vcode = inDto.getString("vcode");
+        String phone = inDto.getString("linkPhone");
+        String fullphone =phone;
+        String region = inDto.getString("region");
+        if(region!=null && (region.equals("+852") || region.startsWith("852"))){
+            String regioncode= region.replace("+","");
+            //85284836521
+
+            if(fullphone.length()==8) {
+                fullphone = regioncode+ fullphone;
+            }
+        }
+        if(fullphone.startsWith("+86")||fullphone.startsWith("86")){
+            fullphone = fullphone.replaceFirst("^\\+?86", "");
+        }
+
+        vCodeUtils.checkPhoneCode(fullphone, vcode);
+        Map<String, Object> dataMap = inDto.getData();
+        log.info("新增举报参数:{}", dataMap);
+        ReportInfo reportInfo = new ReportInfo();
+        try {
+            BeanUtils.populate(reportInfo, dataMap);
+        } catch (Exception e) {
+            log.info("转换对象异常", e);
+            return ResultDTO.buildErrorResult();
+        }
+        UserInfo userInfo = getSimpleUserInfo(true);
+        reportInfo.setUserId(userInfo.getId());
+        reportInfo.setReview(0);
+        ResultDTO resultDTO = reportInfoService.checkReport(reportInfo);
+        if (resultDTO != null) {
+            return resultDTO;
+        }
+        ReportInfo result = reportInfoService.saveReportInfoV2(reportInfo);
+        if(result != null && -1 == result.getReview()) {
+            return ResultDTO.buildErrorResult(result.getOperationsRemark());
+        }
+        return ResultDTO.buildSuccessResult(result);
+    }
+
+
+    @ApiOperation("新增举报")
+    @ApiLog(title = "新增举报", businessType = BusinessType.INSERT)
+    //@PostMapping("/save")
+    public ResultDTO saveReportInfo(@RequestBody InDto inDto) {
+        if (null == inDto){
+            return ResultDTO.buildErrorResult("参数不能为空");
+        }
+        String vcode = inDto.getString("vcode");
+        vCodeUtils.checkPhoneCode(inDto.getString("linkPhone"), vcode);
+        Map<String, Object> dataMap = inDto.getData();
+        log.info("新增举报参数:{}", dataMap);
+        ReportInfo reportInfo = new ReportInfo();
+        try {
+            BeanUtils.populate(reportInfo, dataMap);
+        } catch (Exception e) {
+            log.info("转换对象异常", e);
+            return ResultDTO.buildErrorResult();
+        }
+        UserInfo userInfo = getSimpleUserInfo(true);
+        reportInfo.setUserId(userInfo.getId());
+        //reportInfo.setNickname(inDto.getString("nickname"));
+        reportInfo.setReview(0);
+        ResultDTO resultDTO = reportInfoService.checkReport(reportInfo);
+        //Map<String, Boolean> map = Collections.singletonMap("repeat", repeat);
+        if (resultDTO != null) {
+            return resultDTO;
+        }
+        ReportInfo result = reportInfoService.saveReportInfo(reportInfo);
+        if(result != null && -1 == result.getReview()) {
+            return ResultDTO.buildErrorResult(result.getOperationsRemark());
+        }
+        return ResultDTO.buildSuccessResult(result);
+    }
+
+    @ApiOperation("校验举报")
+    @ApiLog(title = "校验举报", businessType = BusinessType.SEARCH)
+    @PostMapping("/valid")
+    public ResultDTO validReportInfo(@RequestBody InDto inDto) {
+        String reportSource = inDto.getString("reportSource");
+        String reportType = inDto.getString("reportType");
+        String groupInfoCode = inDto.getString("groupInfoCode");
+        String orderType = inDto.getString("orderType");
+        boolean result = reportInfoService.validReportInfo(reportSource, reportType, groupInfoCode, getSimpleUserInfo(true).getId(), orderType);
+        if(result){
+            return ResultDTO.buildErrorResult(ResultDTO.RESPCODE_FAILURE, "请勿重复举报");
+        }
+        return ResultDTO.buildEmptySuccess();
+    }
+
+    @ApiOperation("举报记录")
+    @ApiLog(title = "举报记录", businessType = BusinessType.SEARCH)
+    @PostMapping("/record")
+    public ResultDTO record(@RequestBody InDto inDto) {
+        Integer review = inDto.getIntegerParam("review");
+        if(review == null){
+            return ResultDTO.buildErrorResult("状态为空");
+        }
+        Page<ReportInfoRecordDTO> page = reportInfoService.getReportInfoRecord(inDto.getPageNo(), inDto.getPageSize(),
+                getSimpleUserInfo(true).getId(), review);
+        return ResultDTO.buildSuccessResult(page);
+    }
+
+    @ApiOperation("用户反馈")
+    @ApiLog(title = "用户反馈", businessType = BusinessType.SEARCH)
+    @PostMapping("/feedback")
+    public ResultDTO feedback(@RequestBody InDto inDto) {
+        Integer id = inDto.getIntegerParam("id");
+        if(id == null){
+            return ResultDTO.buildErrorResult("举报记录id为空");
+        }
+        Integer userFeedback = inDto.getIntegerParam("userFeedback");
+        if(userFeedback == null){
+            return ResultDTO.buildErrorResult("状态为空");
+        }
+        reportInfoService.feedback(id, userFeedback);
+        return ResultDTO.buildEmptySuccess();
+    }
+}

+ 61 - 0
poyee-app-mall/src/main/java/com/poyee/controller/user/AppUserController.java

@@ -0,0 +1,61 @@
+package com.poyee.controller.user;
+
+import com.google.common.collect.ImmutableMap;
+import com.poyee.anon.ApiLog;
+import com.poyee.controller.base.BaseController;
+import com.poyee.dto.AppUserInfoDto;
+import com.poyee.dto.InDto;
+import com.poyee.dto.ResultDTO;
+import com.poyee.enums.BusinessType;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @author by po'yi
+ * @Classname SpuController
+ * @Description 商城商品相关api
+ * @Date 2023/3/14 17:40
+ */
+@Slf4j
+@Api("app用户api")
+@RestController
+@RequestMapping("/api/user/{version}")
+public class AppUserController extends BaseController {
+
+    private static final String USER_CHILD_INFO = "user_child_info";
+
+    @ApiLog(title = "查询用户信息", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiOperation("用户信息")
+    @PostMapping("/info")
+    public ResultDTO getUserInfo(@RequestBody InDto inDto) {
+        AppUserInfoDto user = getUserDetailInfo();
+        user.setPoint(user.getPoint() != null ? user.getPoint() / 100 : 0);
+        return ResultDTO.buildSuccessResult(ImmutableMap.of("userInfo", user));
+    }
+
+    // @ApiLog(title = "查询用户绑定宝宝信息", businessType = BusinessType.SEARCH)
+    // @ResponseBody
+    // @ApiOperation("查询用户绑定宝宝信息")
+    // @PostMapping("/child")
+    // public ResultDTO getUserChildInfo(@RequestBody InDto inDto) {
+    //     UserInfo user = UserUtils.getSimpleUserInfo(true);
+    //     Object o = RedisTools.getRedisUtils().hget(USER_CHILD_INFO, user.getId().toString());
+    //     return ResultDTO.buildSuccessResult(o);
+    // }
+    //
+    // @ApiLog(title = "设置用户绑定宝宝信息", businessType = BusinessType.SEARCH)
+    // @ResponseBody
+    // @ApiOperation("设置用户绑定宝宝信息")
+    // @PostMapping("/child/edit")
+    // public ResultDTO editUserChildInfo(@RequestBody InDto inDto) {
+    //     UserInfo user = UserUtils.getSimpleUserInfo(true);
+    //     ChildDTO childDTO = inDto.buildParam(new ChildDTO());
+    //     RedisTools.getRedisUtils().hset(USER_CHILD_INFO, user.getId().toString(), JSON.toJSONString(childDTO));
+    //     return ResultDTO.buildSuccessResult(childDTO);
+    // }
+
+
+}

+ 90 - 0
poyee-app-mall/src/main/java/com/poyee/controller/user/UserFavoriteRecordController.java

@@ -0,0 +1,90 @@
+package com.poyee.controller.user;
+
+import com.poyee.anon.ApiLog;
+import com.poyee.controller.base.BaseController;
+import com.poyee.dto.InDto;
+import com.poyee.dto.ResultDTO;
+import com.poyee.entity.UserFavoriteRecord;
+import com.poyee.enums.BusinessType;
+import com.poyee.handle.ApiVersion;
+import com.poyee.param.SpuQuery;
+import com.poyee.service.UserFavoriteRecordService;
+import com.poyee.service.dto.SpuListDTO;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.domain.Page;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.Date;
+
+@Slf4j
+@Api("用户收藏api")
+@RestController
+@RequestMapping("/api/userFavorite")
+public class UserFavoriteRecordController extends BaseController {
+
+    @Resource
+    private UserFavoriteRecordService userFavoriteRecordService;
+
+    /**
+     * 收藏商品
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "收藏商品", businessType = BusinessType.INSERT)
+    @ApiOperation("收藏商品")
+    @PostMapping("/add")
+    public ResultDTO add(@RequestBody InDto inDto){
+        UserFavoriteRecord entity = new UserFavoriteRecord();
+        entity.setUserId(getSimpleUserInfo(true).getId().longValue());
+        entity.setRefId(Long.valueOf(inDto.getString("refId")));
+        entity.setCreateTime(new Date());
+        entity.setType("goods");
+        userFavoriteRecordService.add(entity);
+        return ResultDTO.buildEmptySuccess();
+    }
+
+    /**
+     * 取消收藏
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "取消收藏", businessType = BusinessType.DELETE)
+    @ApiOperation("取消收藏")
+    @PostMapping("/del")
+    public ResultDTO del(@RequestBody InDto inDto){
+        Long userId = getSimpleUserInfo(true).getId().longValue();
+        Long goodsId = Long.valueOf(inDto.getString("refId"));
+        userFavoriteRecordService.delFavorite(userId,goodsId);
+        return successResult(null);
+    }
+
+    /**
+     * 我的收藏
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "我的收藏", businessType = BusinessType.DELETE)
+    @ApiOperation("我的收藏")
+    @ApiVersion(1.0)
+    @PostMapping("/{version}/mine")
+    public ResultDTO mineFavorite(@RequestBody InDto inDto){
+        SpuQuery spuQuery = buildQueryParam(inDto, new SpuQuery());
+        spuQuery.setUserId(getSimpleUserInfo(true).getId());
+        Page<SpuListDTO> spuPage=userFavoriteRecordService.mineFavorite(spuQuery);
+        return ResultDTO.buildSuccessResult(spuPage);
+    }
+
+    /**
+     * 我的收藏商品数
+     * @return Long
+     */
+    @ApiLog(title = "获取我的收藏商品数", businessType = BusinessType.SEARCH)
+    @ApiOperation("获取我的收藏商品数")
+    @PostMapping("/mineFavouriteNum")
+    public ResultDTO mineFavouriteNum(@RequestBody InDto inDto){
+        return successResult(userFavoriteRecordService.getMineFavoriteNum(inDto.getUserId().longValue()));
+    }
+}

+ 62 - 0
poyee-app-mall/src/main/java/com/poyee/controller/volunteer/VolunteerController.java

@@ -0,0 +1,62 @@
+package com.poyee.controller.volunteer;
+
+import com.poyee.anon.ApiLog;
+import com.poyee.controller.base.BaseController;
+import com.poyee.dto.InDto;
+import com.poyee.dto.ResultDTO;
+import com.poyee.entity.Volunteer;
+import com.poyee.enums.BusinessType;
+import com.poyee.service.VolunteerService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.beanutils.BeanUtils;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.Map;
+
+@Slf4j
+@Api("志愿者招募")
+@RequestMapping("/api/volunteer")
+@RestController
+public class VolunteerController extends BaseController {
+    @Resource
+    private VolunteerService volunteerService;
+
+    @ApiOperation("新增志愿者招募")
+    @ApiLog(title = "新增志愿者招募", businessType = BusinessType.INSERT)
+    @PostMapping("/save")
+    public ResultDTO saveReportInfo(@RequestBody InDto inDto) {
+        Map<String, Object> dataMap = inDto.getData();
+        log.info("新增举报参数:{}", dataMap);
+        Volunteer volunteer = new Volunteer();
+        try {
+            BeanUtils.populate(volunteer, dataMap);
+        } catch (Exception e) {
+            log.info("转换对象异常", e);
+            return ResultDTO.buildErrorResult();
+        }
+        volunteer.setUserId(getSimpleUserInfo(true).getId());
+        volunteer.setReviewStatus(0);
+        volunteerService.saveVolunteer(volunteer);
+        return ResultDTO.buildEmptySuccess();
+    }
+
+    @ApiOperation("查询用户招募详情")
+    @ApiLog(title = "查询用户招募详情", businessType = BusinessType.SEARCH)
+    @PostMapping("/find")
+    public ResultDTO findByUser(@RequestBody InDto inDto) {
+
+        Volunteer volunteer = volunteerService.findByProperty("userId", getSimpleUserInfo(true).getId());
+        int reviewStatus = -1; // 没申请过
+        if(volunteer != null){
+            // 有数据说明申请过
+            reviewStatus = volunteer.getReviewStatus();
+        }
+        return ResultDTO.buildSuccessResult(reviewStatus);
+    }
+}

+ 18 - 0
poyee-app-mall/src/main/java/com/poyee/listen/AppSyncNoticeRecordService.java

@@ -0,0 +1,18 @@
+package com.poyee.listen;
+
+import com.poyee.config.NotificationTopic;
+import com.poyee.dto.NoticeSyncDTO;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import reactor.core.publisher.Flux;
+
+@Service
+@RequiredArgsConstructor
+public class AppSyncNoticeRecordService {
+
+    private final NotificationService notificationService;
+
+    public Flux<NoticeSyncDTO> listen2SyncNoticeRecord() {
+        return this.notificationService.listen(NotificationTopic.APP_NOTICE_RECORD_SYNC, NoticeSyncDTO.class);
+    }
+}

+ 32 - 0
poyee-app-mall/src/main/java/com/poyee/listen/InitializingListen.java

@@ -0,0 +1,32 @@
+package com.poyee.listen;
+
+import com.poyee.dto.NoticeSyncDTO;
+import lombok.AllArgsConstructor;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import reactor.core.publisher.Flux;
+
+
+//@Component
+@AllArgsConstructor
+public class InitializingListen implements CommandLineRunner {
+
+    private final AppSyncNoticeRecordService appSyncNoticeRecordService;
+
+    private ThreadPoolTaskExecutor poolTaskExecutor;
+
+    @Override
+    public void run(String... args) throws InterruptedException {
+        poolTaskExecutor.execute(()-> {
+            while (true) {
+                final Flux<NoticeSyncDTO> noticeSyncFlux = this.appSyncNoticeRecordService.listen2SyncNoticeRecord();
+                Flux.merge(noticeSyncFlux).subscribe();
+                try {
+                    Thread.sleep(15000);
+                } catch (Exception e) {
+                }
+            }
+        });
+
+    }
+}

+ 108 - 0
poyee-app-mall/src/main/java/com/poyee/listen/NotificationService.java

@@ -0,0 +1,108 @@
+package com.poyee.listen;
+
+import com.poyee.config.NotificationTopic;
+import io.r2dbc.pool.ConnectionPool;
+import io.r2dbc.postgresql.api.PostgresqlConnection;
+import io.r2dbc.spi.Connection;
+import io.r2dbc.spi.ValidationDepth;
+import io.r2dbc.spi.Wrapped;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+@Component
+@RequiredArgsConstructor
+@Slf4j
+public class NotificationService {
+    AtomicBoolean bool = new AtomicBoolean(false);
+
+    private Lock lock = new ReentrantLock();
+    private final Set<NotificationTopic> watchedTopics = new HashSet<>();
+
+    private final ConnectionPool connectionPool;
+    private PostgresqlConnection postgresqlConnection;
+    private final ProcessService processService;
+
+    public <T> Flux<T> listen(final NotificationTopic topic, final Class<T> clazz) {
+        lock.lock();
+
+        try {
+            checkConnection();
+        } finally {
+            lock.unlock();
+        }
+        if (!watchedTopics.contains(topic)) {
+            synchronized (watchedTopics) {
+                if (!watchedTopics.contains(topic)) {
+                    executeListenStatement(topic);
+                    watchedTopics.add(topic);
+                    return postgresqlConnection.getNotifications()
+                            .filter(notification -> topic.name().equals(notification.getName()) && notification.getParameter() != null)
+                            .handle((notification, sink) -> {
+                                processService.process(notification);
+                            });
+                }
+            }
+        }
+        return Flux.empty();
+    }
+
+    private void checkConnection() {
+        if (Objects.isNull(postgresqlConnection)) {
+            createConnection();
+            watchedTopics.clear();
+            log.debug("{}", "连接为空");
+        }
+
+        postgresqlConnection.validate(ValidationDepth.REMOTE)
+                .flatMap(validationResult -> {
+                    if (validationResult) {
+                        log.debug("{}", "不为空时:成功");
+                        bool.set(true);
+                    } else {
+                        // 获取连接
+                        createConnection();
+                        watchedTopics.clear();
+                    }
+                    return Mono.empty();
+                })
+                .subscribe();
+    }
+
+
+    /**
+     * Execute the SQL statement used to listen to a given topic
+     *
+     * @param topic Name of the topic to listen to
+     */
+    private void executeListenStatement(final NotificationTopic topic) {
+        log.debug("{}", "重新连接");
+        postgresqlConnection.createStatement(String.format("LISTEN \"%s\"", topic)).execute().subscribe();
+    }
+
+    /**
+     * Get or create a PostgreSQL database connection
+     *
+     * @return the connection created synchronously
+     */
+    private void createConnection() {
+        log.debug("{}", "重新连接");
+        postgresqlConnection = Mono.from(connectionPool.create())
+                .map(pooledConnection -> { // class io.r2dbc.pool.PooledConnection
+                    Wrapped<Connection> wrappedConnection = (Wrapped<Connection>) pooledConnection;
+                    return wrappedConnection.unwrap();
+                })
+                .cast(PostgresqlConnection.class)
+                .repeat()
+                .blockFirst();
+    }
+}

+ 41 - 0
poyee-app-mall/src/main/java/com/poyee/listen/ProcessService.java

@@ -0,0 +1,41 @@
+package com.poyee.listen;
+
+import com.alibaba.fastjson2.JSON;
+import com.poyee.dto.NoticeSyncDTO;
+import com.poyee.service.NoticeRecordService;
+import io.r2dbc.postgresql.api.Notification;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+@Slf4j
+@Component
+public class ProcessService {
+
+    @Resource
+    private NoticeRecordService noticeRecordService;
+
+    public void process(Notification notification) {
+        try {
+            executeByNotification(notification);
+        }catch (Exception e){
+            log.error("异步notify执行异常,参数:{}",notification.getParameter(),e);
+        }
+    }
+
+    private void executeByNotification(Notification notification) {
+        String param = notification.getParameter();
+        String name = notification.getName();
+        log.debug("notify参数记录:{}", param);
+        if (StringUtils.isEmpty(param)) {
+            return;
+        }
+        switch (name) {
+            case "APP_NOTICE_RECORD_SYNC":
+                noticeRecordService.sendSmsNotice(JSON.parseObject(param, NoticeSyncDTO.class));
+                break;
+        }
+    }
+}

+ 53 - 0
poyee-app-mall/src/main/java/com/poyee/mq/LiveConfigConsumer.java

@@ -0,0 +1,53 @@
+package com.poyee.mq;
+
+import lombok.extern.slf4j.Slf4j;
+
+
+@Slf4j
+//@Component
+public class LiveConfigConsumer {
+
+   /* @Resource
+    private RedisUtils redisUtils;
+    @Resource
+    private AppUserCardRecordService appUserCardRecordService;
+    @Resource
+    private WebSocketUtils webSocketUtils;
+
+    @RabbitHandler
+    @RabbitListener(queuesToDeclare = @Queue(MqConstans.QUEUE_APP_LIVE_CONFIG))
+    public void liveConfigConsumer(String param, Channel channel, Message message) throws IOException {
+        log.info("直播间推送消费,参数:{}", param);
+        try {
+            liveConsumer(param);
+        } catch (Exception e) {
+            log.info("直播间推送消费异常,参数:{},异常:{}", param, e);
+        }
+        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
+    }
+
+
+    private void liveConsumer(String param) {
+        JSONObject jsonObject = JSONObject.parseObject(param);
+        String type = jsonObject.getString("type");
+        if("coupon_received".equals(type)) {
+            Object lastId = redisUtils.get("app_last_live_coupon_record_id");
+            // mq穿过来的记录ID
+            Long recordId = Long.parseLong(jsonObject.getString("recordId"));
+            if(lastId != null) {
+                long id = Long.parseLong(lastId.toString());
+                if(id > recordId) {
+                    log.debug("直播间优惠券不推送记录ID, {}", recordId);
+                    return;
+                }
+            }
+            Long cardId = Long.parseLong(jsonObject.getString("cardId"));
+            // 当前优惠券最大的记录ID
+            Long maxId = appUserCardRecordService.findMaxId(cardId);
+            String dataJsonString = JSONObject.toJSONString(jsonObject.get("data"));
+            webSocketUtils.sendGroupMsg(jsonObject.getString("code"), "优惠券receive", dataJsonString, "COUPON");
+            redisUtils.set("app_last_live_coupon_record_id", maxId);
+            log.debug("直播间优惠券当前消费记录ID, {}", recordId);
+        }
+    }*/
+}

+ 79 - 0
poyee-app-mall/src/main/java/com/poyee/mq/SkuStockConsumerNew.java

@@ -0,0 +1,79 @@
+package com.poyee.mq;
+
+import com.poyee.constant.MqConstans;
+import com.poyee.dto.StockParam;
+import com.poyee.entity.OrderList;
+import com.poyee.repository.OrderListRepository;
+import com.poyee.service.SkuService;
+import com.poyee.utils.AppAssert;
+import com.poyee.utils.JSONUtils;
+import com.rabbitmq.client.Channel;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.Queue;
+import org.springframework.amqp.rabbit.annotation.RabbitHandler;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.util.List;
+
+
+/**
+ * 新版库存变动
+ */
+@Slf4j
+@Component
+public class SkuStockConsumerNew {
+
+    private static final String TYPE_STR = "type";
+    @Resource
+    private SkuService skuService;
+    @Resource
+    private OrderListRepository orderListRepository;
+
+    @RabbitHandler
+    @RabbitListener(queuesToDeclare = @Queue(MqConstans.QUEUE_SKU_STOCK_UPDATE_NEW))
+    public void skuStockConsumer(String param, Channel channel, Message message) throws IOException {
+        log.info("商品库存或销量修改,参数:{}", param);
+        try {
+            if (param.contains(TYPE_STR)) {
+                editSkuStockOrSoldNum(param);
+            } else {
+                skuService.updateSkuStock(Long.valueOf(param));
+            }
+        } catch (Exception e) {
+            log.error("商品库存修改异常,参数:{},异常:", param, e);
+        }
+        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
+    }
+
+    /**
+     * 参数json转StockParam
+     *
+     * @param param
+     */
+    private void editSkuStockOrSoldNum(String param) {
+        if (StringUtils.isEmpty(param)) {
+            return;
+        }
+        StockParam stockParam = JSONUtils.fromJson(param, StockParam.class);
+        AppAssert.notNull(stockParam, "参数错误");
+        if (StockParam.STOCK_SUB_TYPE_ORDER.equals(stockParam.getSubType())) {
+            List<OrderList> ol = orderListRepository.findByOrderId(stockParam.getId());
+            ol.forEach(o -> {
+                StockParam olParam = new StockParam();
+                olParam.setType(stockParam.getType());
+                olParam.setId(o.getSkuId());
+                olParam.setNum(o.getQty().intValue());
+                skuService.editSkuStockOrSoldNum(olParam);
+            });
+        } else {
+            skuService.editSkuStockOrSoldNum(stockParam);
+        }
+    }
+
+
+}

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

@@ -0,0 +1,34 @@
+# 项目相关配置
+poyee:
+  app-version: test
+
+# Spring配置
+spring:
+  devtools:
+    restart:
+      # 热部署开关
+      enabled: false
+
+  redis:
+    database: 1
+    #host: ${REDIS_HOST:172.29.19.234}
+    #port: ${REDIS_PORT:6379}
+    password: ${REDIS_PASSWORD:Pass2010}
+    sentinel:
+      master: ${SENTINEL_MASTER:poyee-master}
+      nodes: ${SENTINEL_NODES:192.168.50.8:26379}
+    timeout: 15000  # 连接超时时长(毫秒)
+    pool:
+      max-active: 100  # 连接池最大连接数(使用负值表示没有限制)
+      max-wait: -1ms    # 连接池最大阻塞等待时间(使用负值表示没有限制)
+      max-idle: 10      # 连接池中的最大空闲连接
+      min-idle: 5       # 连接池中的最小空闲连接
+
+coreService:
+  user:
+    useServiceUrl: ${OAUTH_BASEURL:http://coresvc}
+#直播间webSocket地址
+liveWebSocketUrl: http://poyee-im/chat/handler
+#手机验证码
+phone:
+  verification_code_uri: https://coresvc-dev.hobbystocks.cn/api/verification/code/

+ 57 - 0
poyee-app-mall/src/main/resources/application-prod.yml

@@ -0,0 +1,57 @@
+# 项目相关配置
+poyee:
+  app-version: prod
+  combMerchantId: 327
+
+# Swagger配置
+swagger:
+  # 是否开启swagger
+  enabled: false
+
+# 日志配置
+logging:
+  console.enabled: ${CONSOLE_ENABLED:true}
+  file.enabled: ${FILE_ENABLED:false}
+  level:
+    com.poyee: info
+    org.springframework: warn
+    io.micrometer.core.instrument.logging.LoggingMeterRegistry: warn
+  fluentd:
+    enabled: ${FLUENTD_ENABLED:false}
+    host: ${FLUENTD_HOST:127.0.0.1}
+    port: ${FLUENTD_PORT:24225}
+
+
+# Spring配置
+spring:
+  devtools:
+    restart:
+      # 热部署开关
+      enabled: false
+
+  redis:
+    database: ${REDIS_DB:1}
+    #host: ${REDIS_HOST:172.29.19.234}
+    #port: ${REDIS_PORT:6379}
+    password: ${REDIS_PASSWORD:Pass2010}
+    sentinel:
+     master: ${SENTINEL_MASTER:poyee-master}
+     nodes: ${SENTINEL_NODES:127.0.0.1:26379}
+    timeout: 15000  # 连接超时时长(毫秒)
+    pool:
+      max-active: 100  # 连接池最大连接数(使用负值表示没有限制)
+      max-wait: -1ms    # 连接池最大阻塞等待时间(使用负值表示没有限制)
+      max-idle: 10      # 连接池中的最大空闲连接
+      min-idle: 5       # 连接池中的最小空闲连接
+  #jpa日志
+  jpa:
+    show-sql: false
+
+coreService:
+  user:
+    useServiceUrl: ${OAUTH_BASEURL:http://coresvc}
+#直播间webSocket地址
+liveWebSocketUrl: http://poyee-im/chat/handler
+#手机验证码
+phone:
+  verification_code_uri: http://coresvc2/api/verification/code/

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

@@ -0,0 +1,248 @@
+# 项目相关配置
+poyee:
+  # 名称
+  name: mall-app
+  # 版本
+  version: 1.0.1
+  # 获取ip地址开关
+  addressEnabled: false
+  #版本
+  app-version: dev
+  #app-version: prod
+  combMerchantId: 172
+
+management:
+  endpoints:
+    web:
+      exposure:
+        include: info, health,metrics,prometheus
+        exclude: shutdown
+      base-path: /actuator
+    enabled-by-default: true
+    jmx:
+      exposure:
+        include: info, health,metrics,prometheus
+  endpoint:
+    health.show-details: never
+    #health.show-details: ALWAYS
+    metrics:
+      enabled: true
+    prometheus:
+      enabled: true
+  metrics:
+    export:
+      prometheus:
+        enabled: true
+        step: 1ms
+        descriptions: true
+    tags:
+      # 为指标设置一个Tag,这里设置为应用名,Tag是Prometheus提供的一种能力,从而实现更加灵活的筛选
+      application: ${poyee.name}
+  health:
+    defaults.enabled: false
+    db.enabled: true
+    diskspace.enabled: true
+
+#Forest
+forest:
+  #bean-id: config0 # 在spring上下文中bean的id(默认为 forestConfiguration)
+  #backend: okhttp3 # 后端HTTP框架(默认为 okhttp3)
+  #max-connections: 1000 # 连接池最大连接数(默认为 500)
+  #max-route-connections: 500 # 每个路由的最大连接数(默认为 500)你这
+  #timeout: 30000 # 请求超时时间,单位为毫秒(默认为 3000)
+  #connect-timeout: 30000 # 连接超时时间,单位为毫秒(默认为 timeout)
+  read-timeout: 10000 # 数据读取超时时间,单位为毫秒(默认为 timeout)
+  #max-retry-count: 0 # 请求失败后重试次数(默认为 0 次不重试)
+  #ssl-protocol: SSLv3 # 单向验证的HTTPS的默认SSL协议(默认为 SSLv3)
+  #logEnabled: true # 打开或关闭日志(默认为 true)
+  #log-request: true # 打开/关闭Forest请求日志(默认为 true)
+  #log-response-status: true # 打开/关闭Forest响应状态日志(默认为 true)
+  #log-response-content: true # 打开/关闭Forest响应内容日志(默认为 false)
+  variables:
+    appleUrl: https://appleid.apple.com/auth
+# 开发环境配置
+server:
+  # 服务器的HTTP端口,默认为80
+  port: 8087
+  tomcat:
+    # tomcat的URI编码
+    uri-encoding: UTF-8
+    # tomcat最大线程数,默认为200
+    max-threads: ${SERVER_TOMCAT_MAX_THREADS:800}
+    # Tomcat启动初始化的线程数,默认值25
+    min-spare-threads: ${SERVER_TOMCAT_MIN_SPARE_THREADS:30}
+    #超时时间
+    connection-timeout: 600000
+    #basedir: c://tmp/logs
+    accesslog:
+      enabled: false
+      buffered: true
+      prefix: access_log
+      file-date-format: .yyyy-MM-dd
+
+
+# 日志配置
+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}
+
+
+# Spring配置
+spring:
+  jackson:
+    time-zone: GMT+8
+    date-format: yyyy-MM-dd HH:mm:ss
+    #default-property-inclusion: non_null
+  # 服务模块
+  devtools:
+    restart:
+      # 热部署开关
+      enabled: true
+  #数据源配置
+  datasource:
+    url: ${SPRING_DATASOURCE_URL:jdbc:postgresql://192.168.50.10:5432/tzy_system}
+    username: ${SPRING_DATASOURCE_USERNAME:postgres}
+    password: ${SPRING_DATASOURCE_PASSWORD:123456}
+    type: com.alibaba.druid.pool.DruidDataSource
+    driver-class-name: org.postgresql.Driver
+    druid:
+      # 初始连接数
+      initialSize: 5
+      # 最小连接池数量
+      minIdle: 10
+      # 最大连接池数量
+      maxActive: 20
+      # 配置获取连接等待超时的时间
+      maxWait: 60000
+      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+      timeBetweenEvictionRunsMillis: 30000
+      #验证连接超时时间(ms)
+      validationQueryTimeout: 300
+      # 配置一个连接在池中最小生存的时间,单位是毫秒
+      minEvictableIdleTimeMillis: 300000
+      # 配置一个连接在池中最大生存的时间,单位是毫秒
+      maxEvictableIdleTimeMillis: 900000
+      webStatFilter:
+        enabled: false
+  jpa:
+    hibernate:
+      ddl-auto: none
+      naming:
+        physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
+    #show-sql: true
+    properties:
+      hibernate:
+        temp:
+          use_jdbc_metadata_defaults: false
+  flyway:
+    # 是否启用flyway
+    enabled: true
+    # 指定表
+    table: flyway_schema_history_mall
+    # 禁止清理数据库表
+    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: ${SPRING_DATASOURCE_URL:jdbc:postgresql://192.168.50.10:5432/tzy_system}
+    user: ${SPRING_DATASOURCE_USERNAME:postgres}
+    password: ${SPRING_DATASOURCE_PASSWORD:123456}
+
+  redis:
+      database: 1
+      host: 192.168.50.8
+      #host: hobbystock.cn
+      port: 6379
+      password: Pass2010    # 密码(默认为空)
+      timeout: 60000  # 连接超时时长(毫秒)
+      pool:
+        max-active: 1000  # 连接池最大连接数(使用负值表示没有限制)
+        max-wait: -1ms    # 连接池最大阻塞等待时间(使用负值表示没有限制)
+        max-idle: 10      # 连接池中的最大空闲连接
+        min-idle: 5       # 连接池中的最小空闲连接
+  #mq
+  rabbitmq:
+    host: ${SPRING_RABBITMQ_HOST:192.168.50.10}
+    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
+
+# Swagger配置
+swagger:
+  # 是否开启swagger
+  enabled: true
+
+#服务前缀路径
+coreService:
+  baseurl: ${CORESERV_BASEURL:https://coresvc-dev.hobbystocks.cn}
+  smsUrl: /api/reminder/live/on
+  appSmsUrl: /api/appmsg/live/on
+  ipUrl: /api/geo/city
+  #用户服务
+  user:
+    # 用户内网地址
+    useServiceUrl: ${CORESERV_BASEURL:https://coresvc-dev.hobbystocks.cn}
+    #用户详情
+    userInfoUrl: /user
+    #商家app用户信息
+    merchantUrl: /user/merchant
+
+tencentCloudAppKey: 31efbaf9da9f08cb24a1de7d9ac257cb
+
+#腾讯云API秘钥
+tencentCloud:
+  secretId: AKIDsZ0A3f29zYrsc5IEsFLBk23oztWsxlIX
+  secretKey: 0jBMGtEI5csrZ2E8l9G6fy0lFRN2QXOy
+  im:
+    SDKAppID: 1400661352
+    # App 管理员帐号
+    identifier: administrator
+    secretKey: 0cfedc6714e281271fa35688f57f5a26070d5ccbd0b821d936f4e513ec4eb27b
+  #腾讯云直播密钥(商家)
+  living:
+    secretKey: c018bdfe07b758cb11dc10ffea7feca6
+
+#消息推送服务地址
+pushBaseUrl: ${CORESERV_BASEURL:https://coresvc-dev.hobbystocks.cn}
+
+#直播间webSocket地址
+liveWebSocketUrl: http://poyee-im/chat/handler

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 11 - 0
poyee-app-mall/src/main/resources/http/app-req-zyb.http


+ 21 - 0
poyee-app-mall/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>poyee-mall.${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>

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

@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+	<!-- 日志存放路径 -->
+	<property name="log.path" value="../logs" />
+	<!-- 日志输出格式 -->
+	<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%X{TRACE_ID}] [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
+	<springProperty scope="context" name="logging.console.enabled" source="logging.console.enabled"/>
+	<springProperty scope="context" name="logging.file.enabled" source="logging.file.enabled"/>
+	<springProperty scope="context" name="logging.fluentd.enabled" source="logging.fluentd.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.utils.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>
+
+	<!-- 系统日志输出 -->
+	<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
+		<file>${log.path}/sys-info.log</file>
+		<!-- 循环政策:基于时间创建日志文件 -->
+		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+			<!-- 日志文件名格式 -->
+			<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
+			<!-- 日志最大的历史 60天 -->
+			<maxHistory>60</maxHistory>
+		</rollingPolicy>
+		<encoder>
+			<pattern>${log.pattern}</pattern>
+			<charset>UTF-8</charset>
+		</encoder>
+		<filter class="ch.qos.logback.classic.filter.LevelFilter">
+			<!-- 过滤的级别 -->
+			<level>INFO</level>
+			<!-- 匹配时的操作:接收(记录) -->
+			<onMatch>ACCEPT</onMatch>
+			<!-- 不匹配时的操作:拒绝(不记录) -->
+			<onMismatch>DENY</onMismatch>
+		</filter>
+	</appender>
+
+	<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+		<file>${log.path}/sys-error.log</file>
+		<!-- 循环政策:基于时间创建日志文件 -->
+		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+			<!-- 日志文件名格式 -->
+			<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
+			<!-- 日志最大的历史 60天 -->
+			<maxHistory>60</maxHistory>
+		</rollingPolicy>
+		<encoder>
+			<pattern>${log.pattern}</pattern>
+			<charset>UTF-8</charset>
+		</encoder>
+		<filter class="ch.qos.logback.classic.filter.LevelFilter">
+			<!-- 过滤的级别 -->
+			<level>ERROR</level>
+			<!-- 匹配时的操作:接收(记录) -->
+			<onMatch>ACCEPT</onMatch>
+			<!-- 不匹配时的操作:拒绝(不记录) -->
+			<onMismatch>DENY</onMismatch>
+		</filter>
+	</appender>
+
+	<!-- 用户访问日志输出  -->
+	<appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
+		<file>${log.path}/sys-user.log</file>
+		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+			<!-- 按天回滚 daily -->
+			<fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
+			<!-- 日志最大的历史 60天 -->
+			<maxHistory>60</maxHistory>
+		</rollingPolicy>
+		<encoder>
+			<pattern>${log.pattern}</pattern>
+			<charset>UTF-8</charset>
+		</encoder>
+	</appender>
+
+	<!--系统操作日志-->
+	<root level="info">
+		<if condition='p("logging.console.enabled").equals("true")'>
+			<then>
+				<appender-ref ref="console" />
+			</then>
+		</if>
+		<if condition='p("logging.file.enabled").equals("true")'>
+			<then>
+				<appender-ref ref="file_info" />
+				<appender-ref ref="file_error" />
+			</then>
+		</if>
+		<if condition='p("logging.fluentd.enabled").equals("true")'>
+			<then>
+				<appender-ref ref="FLUENT"/>
+			</then>
+		</if>
+	</root>
+
+	<!-- 系统模块日志级别控制  -->
+	<logger name="com.ruoyi" level="info" />
+	<!-- Spring日志级别控制  -->
+	<logger name="org.springframework" level="warn" />
+	<!--hibernate-->
+	<!--	<logger name="org.hibernate.SQL" level="DEBUG" />-->
+
+<!--	<logger name="org.hibernate.loader.hql" level="DEBUG" />-->
+<!--	<logger name="org.hibernate.type.descriptor.sql.BasicBinder" level="DEBUG" />-->
+
+	<!--系统用户操作日志-->
+	<logger name="sys-user" level="info">
+		<if condition='p("logging.file.enabled").equals("true")'>
+			<then>
+				<appender-ref ref="sys-user"/>
+			</then>
+		</if>
+	</logger>
+</configuration>

+ 63 - 0
poyee-app-mall/src/test/java/com/poyee/test/group/GroupTest.java

@@ -0,0 +1,63 @@
+package com.poyee.test.group;
+
+import com.alibaba.fastjson.JSON;
+import com.poyee.MallApplication;
+import com.poyee.dto.InDto;
+import com.poyee.service.CardGroupInfoService;
+import com.poyee.test.mall.BaseTest;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.Map;
+
+
+@Slf4j
+@SpringBootTest(classes = MallApplication.class)
+@RunWith(SpringRunner.class)
+@AutoConfigureMockMvc
+public class GroupTest extends BaseTest {
+	@Autowired
+	private MockMvc mockMvc;
+	@Resource
+	private CardGroupInfoService groupInfoService;
+
+	@Test
+	public void testGetGroupGoods() throws Exception {
+		Map<String, Object> data = new HashMap(){{
+			put("groupInfoId",850L);
+			put("paniniListId",1544L);
+		}};
+		InDto inDto = buildMerchantIndto(data);
+
+		MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/api/merchant/v1.7/goods/group")
+				.accept(MediaType.APPLICATION_JSON_UTF8).contentType(MediaType.APPLICATION_JSON_UTF8)
+				.content(JSON.toJSONString(inDto)))
+				.andExpect(MockMvcResultMatchers.status().isOk()).andReturn();
+		int status = mvcResult.getResponse().getStatus();
+		System.out.println(status);
+		String result = mvcResult.getResponse().getContentAsString();
+		System.out.println(result);
+	}
+
+	@Test
+	public void testHaxGroupReq() throws Exception {
+		boolean hasRefundReq = groupInfoService.hasRefundReq(5922);
+		System.out.println(hasRefundReq);
+	}
+
+
+
+
+}

+ 52 - 0
poyee-app-mall/src/test/java/com/poyee/test/mall/BaseTest.java

@@ -0,0 +1,52 @@
+package com.poyee.test.mall;
+
+
+import com.poyee.dto.InDto;
+
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * @author by po'yi
+ * @Classname BaseTest
+ * @Description TODO
+ * @Date 2022/11/14 19:12
+ */
+public class BaseTest {
+
+	/**
+	 * 构建2442用户参数
+	 * @param data
+	 * @return
+	 */
+	protected InDto buildUserIndto(Map<String, Object> data){
+		InDto inDto = new InDto();
+		inDto.setData(data);
+		inDto.setUserType("userType");
+		inDto.setAppid("wx22a7349c29e688d4");
+		inDto.setUnionid("oAbrM6qK1qZO4PbvMLREcAR60JZQ");
+		inDto.setUsername("15618709098");
+		inDto.setVersion("1.7.38");
+		inDto.setDepartId(103);
+		inDto.setTimestamp(new Date().getTime());
+		return inDto;
+	}
+
+	/**
+	 * 构建13号商家参数
+	 * @param data
+	 * @return
+	 */
+	protected InDto buildMerchantIndto(Map<String, Object> data){
+		InDto inDto = new InDto();
+		inDto.setData(data);
+		inDto.setUserType("WX_AUTH");
+		inDto.setAppid("wx22a7349c29e688d4");
+		inDto.setUnionid("oAbrM6qK1qZO4PbvMLREcAR60JZQ");
+		inDto.setUsername("13071005103");
+		inDto.setVersion("1.6.38");
+		inDto.setDepartId(103);
+		inDto.setTimestamp(new Date().getTime());
+		return inDto;
+	}
+}

+ 25 - 0
poyee-app-mall/src/test/java/com/poyee/test/mall/ExamTest.java

@@ -0,0 +1,25 @@
+package com.poyee.test.mall;
+
+import com.poyee.MallApplication;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+
+
+@Slf4j
+@SpringBootTest(classes = MallApplication.class)
+@RunWith(SpringRunner.class)
+public class ExamTest {
+	@Test
+	public void test1(){
+	}
+
+
+
+
+
+
+}

+ 69 - 0
poyee-app-mall/src/test/java/com/poyee/test/mall/MultiThreadServiceCall.java

@@ -0,0 +1,69 @@
+package com.poyee.test.mall;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+class ServiceThread extends Thread {
+    private String serviceUrl;
+    private int threadId;
+
+    public ServiceThread(String serviceUrl, int threadId) {
+        this.serviceUrl = serviceUrl;
+        this.threadId = threadId;
+    }
+
+    @Override
+    public void run() {
+        try {
+            System.out.println("Thread " + threadId + " starting...");
+            URL url = new URL(serviceUrl);
+            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+            connection.setRequestMethod("GET");
+
+            int responseCode = connection.getResponseCode();
+            System.out.println("Thread " + threadId + " received response code: " + responseCode);
+
+            BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
+            String inputLine;
+            StringBuffer content = new StringBuffer();
+            while ((inputLine = in.readLine()) != null) {
+                content.append(inputLine);
+            }
+
+            in.close();
+            connection.disconnect();
+
+            System.out.println("Thread " + threadId + " finished with response: " + "...");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}
+
+public class MultiThreadServiceCall {
+    public static void main(String[] args) {
+        String serviceUrl = "http://localhost:8087/api/userCardRecord/test";
+        //String serviceUrl = "http://localhost:8082/v2/test/num";
+        //String serviceUrl = "http://localhost:8083/test/num";
+        int threadCount = 40;  // 自定义线程数
+
+        Thread[] threads = new Thread[threadCount];
+        for (int i = 0; i < threadCount; i++) {
+            threads[i] = new ServiceThread(serviceUrl, i);
+            threads[i].start();
+        }
+
+        // 等待所有线程完成
+        for (int i = 0; i < threadCount; i++) {
+            try {
+                threads[i].join();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        System.out.println("All threads have finished.");
+    }
+}

+ 44 - 0
poyee-app-mall/src/test/java/com/poyee/test/mall/SkuTest.java

@@ -0,0 +1,44 @@
+package com.poyee.test.mall;
+
+import com.poyee.MallApplication;
+import com.poyee.dto.StockParam;
+import com.poyee.entity.OrderList;
+import com.poyee.repository.OrderListRepository;
+import com.poyee.service.SkuService;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+
+@Slf4j
+@SpringBootTest(classes = MallApplication.class)
+@RunWith(SpringRunner.class)
+public class SkuTest {
+    @Resource
+    private SkuService skuService;
+
+    @Resource
+    private OrderListRepository orderListRepository;
+
+    @Test
+    public void test1() {
+        StockParam stockParam = new StockParam();
+        stockParam.setId(1L);
+        stockParam.setType(StockParam.SKU_NUM_TYPE_SOLD);
+        stockParam.setNum(1);
+        skuService.editSkuStockOrSoldNum(stockParam);
+    }
+
+    @Test
+    public void test2() {
+        List<OrderList> ol = orderListRepository.findByOrderId(252728L);
+        log.debug("ol:{}",ol);
+    }
+
+
+}

+ 20 - 0
poyee-app-mall/src/test/resources/http/mall-req-hzt.http

@@ -0,0 +1,20 @@
+@version=v4
+@mallUrl=localhost:8087
+
+
+###克隆直播
+POST http://{{mallUrl}}/api/live/cloneLive
+Content-Type: application/json
+
+{
+  "userId": 15614,
+  "data": {
+    "type": 1,
+    "merchantId": 182,
+    "groupInfoId": 5098,
+    "merchantName": "yyds"
+  }
+}
+
+
+

+ 30 - 0
poyee-base-api/pom.xml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>poyee-parent</artifactId>
+        <groupId>com.poyee</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>poyee-base-api</artifactId>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>com.poyee</groupId>
+            <artifactId>poyee-service-common</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-test-autoconfigure</artifactId>
+            <version>2.1.17.RELEASE</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+
+</project>

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

@@ -0,0 +1,134 @@
+package com.poyee.controller.base;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.poyee.constant.MqConstans;
+import com.poyee.dto.AppUserInfoDto;
+import com.poyee.dto.InDto;
+import com.poyee.dto.ResultDTO;
+import com.poyee.exception.ServiceException;
+import com.poyee.param.UserInfo;
+import com.poyee.param.dto.OrderSubmitDTO;
+import com.poyee.service.UserService;
+import com.poyee.utils.DozerUtils;
+import com.poyee.utils.MqUtils;
+import com.poyee.utils.UserUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.Objects;
+
+/**
+ * @author by po'yi
+ * @Classname BaseController
+ * @Description TODO
+ * @Date 2022/8/18 11:49
+ */
+@Slf4j
+@Component
+public class BaseController {
+
+	@Autowired
+	private UserService userService;
+	@Autowired
+	private MqUtils mqUtils;
+
+
+	protected ResultDTO successResult(String msg, Object data) {
+		return new ResultDTO(ResultDTO.RESPCODE_SUCCESS, msg, data);
+	}
+
+	protected ResultDTO successResult(Object data) {
+		return new ResultDTO(ResultDTO.RESPCODE_SUCCESS, ResultDTO.MSG_SUCCESS, data);
+	}
+
+	protected ResultDTO failureResult(int code, String msg) {
+		return new ResultDTO(code, msg, null);
+	}
+
+	protected ResultDTO failureResult(String msg, Object data) {
+		return new ResultDTO(ResultDTO.RESPCODE_FAILURE, msg, data);
+	}
+
+	protected ResultDTO failureResult(int code, String msg, Object data) {
+		return new ResultDTO(code, msg, data);
+	}
+
+	protected ResultDTO failureResult(Object data) {
+		return new ResultDTO(ResultDTO.RESPCODE_FAILURE, ResultDTO.MSG_FAIL, data);
+	}
+
+
+	/**
+	 * 查询请求头中用户部分信息
+	 * @param isNeedLogin  是否必须登陆
+	 * @return
+	 */
+	protected UserInfo getSimpleUserInfo(boolean isNeedLogin) {
+		return UserUtils.getSimpleUserInfo(isNeedLogin);
+	}
+
+
+	/**
+	 * 跨服务调用,获取用户详情信息
+	 *
+	 * @return
+	 */
+	protected AppUserInfoDto getUserDetailInfo() {
+		UserInfo simpleUserInfo = getSimpleUserInfo(true);
+		AppUserInfoDto user = userService.getUserDetailInfo(simpleUserInfo.getId());
+		user.setRoleCode(simpleUserInfo.getRoleCode());
+		return user;
+	}
+
+	/**
+	 * 转换indto中data为指定参数
+	 *
+	 * @param inDto
+	 * @param param
+	 * @param <T>
+	 * @return
+	 */
+	protected <T> T buildQueryParam(InDto inDto, T param) {
+		try {
+			//BeanUtils.populate(param, inDto.getData());
+			DozerUtils.copy(inDto.getData(), param);
+			return param;
+		} catch (Exception e) {
+			log.error("参数转换失败:", e);
+		}
+		throw new ServiceException(500, "参数获取失败!");
+	}
+
+	/**
+	 * 订单来源记录
+	 * @param orderParsingRecord
+	 * @param user
+	 * @param orderSubmitDTO
+	 */
+	protected void checkAndSendOrderParsing(com.alibaba.fastjson.JSONObject orderParsingRecord, UserInfo user, OrderSubmitDTO orderSubmitDTO) {
+		if(Objects.nonNull(orderParsingRecord)){
+			try {
+				orderParsingRecord.put("orderId", orderSubmitDTO.getOrderId());
+				orderParsingRecord.put("userId", user.getId());
+				orderParsingRecord.put("submitTime", new Date());
+				orderParsingRecord.put("method", "add");//新增一条记录
+				//如果订单下单成功 生成订单来源记录
+				sendMqMsg(MqConstans.QUEUE_ORDER_PARSING, JSONObject.toJSONString(orderParsingRecord));
+			}catch (Exception e){
+				log.error("订单来源记录生成失败",e);
+			}
+		}
+	}
+
+	/**
+	 * 发送mq
+	 * @param routingKey
+	 * @param data
+	 */
+	protected void sendMqMsg(String routingKey,Object data){
+		MqUtils.sendMq( routingKey, data);
+	}
+
+}

+ 14 - 0
poyee-base-api/src/main/java/com/poyee/controller/base/DeploymentController.java

@@ -0,0 +1,14 @@
+package com.poyee.controller.base;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping
+public class DeploymentController {
+
+    @RequestMapping("/health")
+    public void checkHealth(){
+    }
+
+}

+ 52 - 0
poyee-base-api/src/main/java/com/poyee/controller/base/ExceptionController.java

@@ -0,0 +1,52 @@
+package com.poyee.controller.base;
+
+import com.poyee.dto.ResultDTO;
+import com.poyee.exception.OrderException;
+import com.poyee.exception.ServiceException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import java.sql.SQLException;
+import java.util.Locale;
+
+
+/**
+ * @author po'yi
+ */
+@RestControllerAdvice
+@Slf4j
+public class ExceptionController extends BaseController{
+
+    @ExceptionHandler(ServiceException.class)
+    public ResultDTO handleException(ServiceException e, Locale locale) {
+        log.info("业务异常:{}", e.getMessage());
+        return failureResult(e.getCode(),e.getMessage(),null);
+    }
+
+    @ExceptionHandler(OrderException.class)
+    public ResultDTO handleException(OrderException e, Locale locale) {
+        log.warn("订单异常:{}", e.getMessage());
+        return failureResult(e.getCode(),e.getMessage(),null);
+    }
+
+    @ExceptionHandler(Exception.class)
+    public ResultDTO handleException(Exception e, Locale locale) {
+        log.error("系统异常:{}", e);
+        return failureResult(500,"系统异常");
+    }
+
+    @ExceptionHandler(SQLException.class)
+    public ResultDTO handleException(SQLException e, Locale locale) {
+        log.error("sql异常:{}", e);
+        return failureResult(500,"sql异常,请联系管理员!");
+    }
+
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    public ResultDTO handleMethodArgumentNotValidException(MethodArgumentNotValidException e, Locale locale) {
+        String defaultMessage = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
+        return failureResult(500,"参数错误:"+defaultMessage);
+    }
+
+}

+ 127 - 0
poyee-common/pom.xml

@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>poyee-parent</artifactId>
+        <groupId>com.poyee</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>poyee-common</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.poyee</groupId>
+            <artifactId>poyee-repository</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <!--foest-->
+        <dependency>
+            <groupId>com.dtflys.forest</groupId>
+            <artifactId>forest-spring-boot-starter</artifactId>
+            <version>1.5.24</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>httpclient-cache</artifactId>
+                    <groupId>org.apache.httpcomponents</groupId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>commons-logging</artifactId>
+                    <groupId>commons-logging</groupId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>commons-io</artifactId>
+                    <groupId>commons-io</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <!-- aop 依赖 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+        <!-- Spring Data Redis -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+
+        <!-- redis 环境 -->
+        <dependency>
+            <groupId>org.springframework.session</groupId>
+            <artifactId>spring-session-data-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.redisson</groupId>
+            <artifactId>redisson</artifactId>
+            <version>${redisson.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-amqp</artifactId>
+        </dependency>
+        <!-- JSON工具类 -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+        <!-- 阿里JSON解析器 -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>${fastjson.version}</version>
+        </dependency>
+        <!-- swagger -->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>${swagger.version}</version>
+            <!-- 排除掉swagger中的mapstruct -->
+            <!--<scope>compile</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.mapstruct</groupId>
+                    <artifactId>mapstruct</artifactId>
+                </exclusion>
+            </exclusions>-->
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>${swagger.version}</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/com.github.dozermapper/dozer-core -->
+        <dependency>
+            <groupId>com.github.dozermapper</groupId>
+            <artifactId>dozer-core</artifactId>
+            <version>${dozer.version}</version>
+        </dependency>
+
+        <!-- guava依赖 -->
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>${guava.version}</version>
+        </dependency>
+
+        <!-- 腾讯云直播即时剪辑 -->
+        <dependency>
+            <groupId>com.tencentcloudapi</groupId>
+            <artifactId>tencentcloud-sdk-java-vod</artifactId>
+            <version>3.1.572</version>
+        </dependency>
+        <!-- flyway -->
+        <dependency>
+            <groupId>org.flywaydb</groupId>
+            <artifactId>flyway-core</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 28 - 0
poyee-common/src/main/java/com/poyee/anon/ApiLimitRule.java

@@ -0,0 +1,28 @@
+package com.poyee.anon;
+
+import java.lang.annotation.*;
+
+/**
+ * ip限制
+ *
+ * @author
+ */
+@Target({ ElementType.PARAMETER, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ApiLimitRule {
+     /**几秒内限制*/
+     int seconds();
+     /**可访问次数*/
+     int limitCount();
+     /**超过次数,锁定*/
+     int lockCount() default 0;
+     /**锁定时间*/
+     int lockTime() default 0;
+     /**类型:common:通用ip和url,user:用户 */
+     String type() default "common";
+     /**提醒消息*/
+     String msg() default "";
+     /**活动用户限制秒数*/
+     int actUserLimitSec() default 1;
+}

+ 39 - 0
poyee-common/src/main/java/com/poyee/anon/ApiLog.java

@@ -0,0 +1,39 @@
+package com.poyee.anon;
+
+import com.poyee.enums.BusinessType;
+import com.poyee.enums.OperatorType;
+
+import java.lang.annotation.*;
+
+/**
+ * 自定义接口调用日志注解
+ *
+ * @author lsz
+ */
+@Target({ ElementType.PARAMETER, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ApiLog {
+
+    /**
+     * 模块
+     */
+    public String title() default "";
+
+    /**
+     * 功能
+     */
+    public BusinessType businessType() default BusinessType.OTHER;
+
+    /**
+     * 操作人类别
+     */
+    public OperatorType operatorType() default OperatorType.MOBILE;
+
+    /**
+     * 是否保存请求的参数
+     */
+    public boolean isSaveRequestData() default true;
+
+    String indto() default "";
+}

+ 17 - 0
poyee-common/src/main/java/com/poyee/anon/CustomRetry.java

@@ -0,0 +1,17 @@
+package com.poyee.anon;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CustomRetry {
+    /**最大重试次数*/
+    int maxAttempts() default 2;
+    /**延迟时间*/
+    long delay() default 1000;
+    /**是否使用事务*/
+    boolean isUseTran() default false;
+}

+ 27 - 0
poyee-common/src/main/java/com/poyee/anon/RedisLock.java

@@ -0,0 +1,27 @@
+package com.poyee.anon;
+
+import java.lang.annotation.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * redis 分布式锁注解
+ *
+ * @author
+ */
+@Target({ ElementType.PARAMETER, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RedisLock {
+     /**锁的key,支持SpEL表达式*/
+     String lockKey();
+     /**时间单位*/
+     TimeUnit unit() default TimeUnit.SECONDS;
+     /**锁等待时间*/
+     long waitTime() ;
+     /**锁持续时间,-1:自动续锁*/
+     long leaseTime();
+     /**是否使用事务*/
+     boolean isUseTran() default false;
+     /**失败提示信息*/
+     String failMsg() default "请求失败,请重试!";
+}

+ 19 - 0
poyee-common/src/main/java/com/poyee/anon/RequireRoles.java

@@ -0,0 +1,19 @@
+package com.poyee.anon;
+
+import java.lang.annotation.*;
+
+/**
+ * 角色拦截
+ *
+ * @author
+ */
+@Target({ ElementType.PARAMETER, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RequireRoles {
+
+    /**
+     * 角色
+     */
+    String[] value();
+}

+ 160 - 0
poyee-common/src/main/java/com/poyee/aop/ApiLogAspect.java

@@ -0,0 +1,160 @@
+package com.poyee.aop;
+
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.fastjson2.filter.SimplePropertyPreFilter;
+import com.poyee.anon.ApiLog;
+import com.poyee.dto.InDto;
+import com.poyee.param.CardApiLog;
+import com.poyee.utils.IpUtils;
+import com.poyee.utils.JSONUtils;
+import com.poyee.utils.ServletUtils;
+import com.poyee.utils.StringUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.Signature;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * 操作日志记录处理
+ *
+ * @author zheng
+ */
+@Slf4j
+//@Aspect
+//@Component
+public class ApiLogAspect {
+	/**
+	 * 排除敏感属性字段
+	 */
+	public static final String[] EXCLUDE_PROPERTIES = {"password", "oldPassword", "newPassword", "confirmPassword", "loginPsd", "payPsd"};
+
+	// 配置织入点
+	@Pointcut("@annotation(com.poyee.anon.ApiLog)")
+	public void logPointCut() {
+	}
+
+	@Around("com.poyee.aop.ApiLogAspect.logPointCut()")
+	public Object exeAround(ProceedingJoinPoint pjp) throws Throwable {
+		long s = System.currentTimeMillis();
+		Object proceed = pjp.proceed();
+		log.info("接口请求时间:{},url:{}",System.currentTimeMillis()-s,ServletUtils.getRequest().getRequestURI());
+		return proceed;
+	}
+
+	/**
+	 * 处理完请求后执行
+	 *
+	 * @param joinPoint 切点
+	 */
+	@AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
+	public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {
+		handleLog(joinPoint, null, jsonResult);
+	}
+
+
+	protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) {
+		try {
+			ApiLog controllerLog = getAnnotationLog(joinPoint);
+			if (controllerLog == null) {
+				return;
+			}
+			CardApiLog operLog = new CardApiLog();
+			operLog.setStatus(0);
+			// 请求的地址
+			operLog.setResultData(StringUtils.substring(JSONUtils.toPrettyJson(jsonResult), 0, 2000));
+			operLog.setUrl(ServletUtils.getRequest().getRequestURI());
+			operLog.setIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
+			// 获取参数的信息,传入到数据库中。
+			setRequestValue(joinPoint, operLog);
+
+			if (e != null) {
+				operLog.setStatus(1);
+				operLog.setExceptionMsg(StringUtils.substring(e.getMessage(), 0, 2000));
+			}
+			// 设置方法名称
+			String className = joinPoint.getTarget().getClass().getName();
+			String methodName = joinPoint.getSignature().getName();
+			operLog.setMethod(className + "." + methodName + "()");
+			// 设置请求方式
+			//operLog.setMethodType(ServletUtils.getRequest().getMethod());
+			// 处理设置注解上的参数
+			getControllerMethodDescription(controllerLog, operLog);
+			log.info("接口请求,参数:{}", operLog);
+		} catch (Exception exp) {
+			log.error("前置通知异常,异常信息:", exp);
+		}
+	}
+
+	/**
+	 * 获取注解中对方法的描述信息
+	 *
+	 * @param log     日志
+	 * @param operLog 操作日志
+	 * @throws Exception
+	 */
+	public void getControllerMethodDescription(ApiLog log, CardApiLog operLog) throws Exception {
+		// 设置action动作
+		operLog.setType(log.businessType().ordinal());
+		// 设置标题
+		operLog.setTitle(log.title());
+		// 设置操作人类别
+		operLog.setOperatorType(log.operatorType().ordinal());
+	}
+
+	/**
+	 * 获取请求的参数,放到log中
+	 *
+	 * @param operLog 操作日志
+	 * @throws Exception 异常
+	 */
+	private void setRequestValue(JoinPoint joinPoint, CardApiLog operLog) throws Exception {
+		Map<String, String[]> map = ServletUtils.getRequest().getParameterMap();
+		String indata = "";
+		if (StringUtils.isNotEmpty(map)) {
+			SimplePropertyPreFilter filter = new SimplePropertyPreFilter();
+			filter.getExcludes().addAll(Arrays.asList(EXCLUDE_PROPERTIES));
+			indata = JSON.toJSONString(map, filter);
+		} else {
+			Object[] args = joinPoint.getArgs();
+			if (null != args && args.length > 0) {
+				for (Object org : args) {
+					try {
+						if (!"java.lang.String".equals(org.getClass().getName())) {
+							InDto inDto = (InDto) org;
+							indata = indata + JSONObject.toJSONString(inDto);
+							operLog.setCreateUser(String.valueOf(inDto.getUserId()));
+						} else {
+							indata = indata + org;
+						}
+					} catch (Exception e) {
+						e.printStackTrace();
+					}
+				}
+			}
+		}
+		operLog.setSendData(indata);
+	}
+
+	/**
+	 * 是否存在注解,如果存在就获取
+	 */
+	private ApiLog getAnnotationLog(JoinPoint joinPoint) throws Exception {
+		Signature signature = joinPoint.getSignature();
+		MethodSignature methodSignature = (MethodSignature) signature;
+		Method method = methodSignature.getMethod();
+		if (method != null) {
+			return method.getAnnotation(ApiLog.class);
+		}
+		return null;
+	}
+}

+ 80 - 0
poyee-common/src/main/java/com/poyee/aop/AppRoleAspect.java

@@ -0,0 +1,80 @@
+package com.poyee.aop;
+
+
+import com.poyee.anon.RequireRoles;
+import com.poyee.constant.UserType;
+import com.poyee.dto.ResultDTO;
+import com.poyee.exception.ServiceException;
+import com.poyee.param.UserInfo;
+import com.poyee.utils.AppAssert;
+import com.poyee.utils.CollectionUtil;
+import com.poyee.utils.UserUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.Signature;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author by po'yi
+ * @Classname AppRoleAspect
+ * @Description 角色校验
+ * @Date 2022/1/6 16:43
+ */
+@Slf4j
+@Aspect
+@Component
+public class AppRoleAspect {
+	// 配置织入点
+	@Pointcut("@annotation(com.poyee.anon.RequireRoles)")
+	public void rolePointCut() {
+	}
+
+	//@RequireRoles({"admin"})
+	@Around("com.poyee.aop.AppRoleAspect.rolePointCut()")
+	public Object roleBefore(ProceedingJoinPoint pjp) throws Throwable {
+		UserInfo user;
+		try{
+			 user = UserUtils.getSimpleUserInfo(true);
+		}catch(ServiceException e){
+			return ResultDTO.buildErrorResult(500,"权限不足!");
+		}catch(Exception e){
+			return ResultDTO.buildErrorResult(500,"系统异常!");
+		}
+		AppAssert.notNull(user, "请先登录!");
+		if (UserType.USER_ROLE_ADMIN.equals(user.getRoleCode())) {
+			return pjp.proceed();
+		}
+		Signature signature = pjp.getSignature();
+		MethodSignature methodSignature = (MethodSignature) signature;
+		Method targetMethod = methodSignature.getMethod();
+		RequireRoles annotation = targetMethod.getAnnotation(RequireRoles.class);
+		String[] roles = annotation.value();
+		List<String> requirePermissions = Arrays.asList(roles);
+		List<String> userPermissions = new ArrayList<>();
+		String role = user.getRoleCode() != null ? user.getRoleCode() :CollectionUtil.BLANK;
+		userPermissions.add(role);
+		List<String> permissionsList = user.getPermissionsList();
+		if (!CollectionUtils.isEmpty(permissionsList)) {
+			userPermissions.addAll(permissionsList);
+		}
+		Set<String> commonRole = CollectionUtil.getCommonElements(requirePermissions, userPermissions);
+		if (CollectionUtils.isEmpty(commonRole)) {
+			log.info("权限不足,用户信息:{}",user);
+			return ResultDTO.buildErrorResult(500,"权限不足!");
+		}
+		return pjp.proceed();
+
+	}
+
+}

+ 118 - 0
poyee-common/src/main/java/com/poyee/aop/ControllerLogAspect.java

@@ -0,0 +1,118 @@
+package com.poyee.aop;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.serializer.SimplePropertyPreFilter;
+import com.poyee.dto.InDto;
+import com.poyee.dto.LogParam;
+import com.poyee.utils.IpUtils;
+import com.poyee.utils.JSONUtils;
+import com.poyee.utils.ServletUtils;
+import com.poyee.utils.StringUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * 操作日志记录处理
+ *
+ * @author zheng
+ */
+@Slf4j
+@Aspect
+@Component
+public class ControllerLogAspect {
+    /**
+     * 排除敏感属性字段
+     */
+    public static final String[] EXCLUDE_PROPERTIES = {"password", "oldPassword", "newPassword", "confirmPassword", "loginPsd", "payPsd"};
+
+    // 配置织入点
+    //com.poyee.controller.base.ExceptionController
+    //@Pointcut("execution(* com..*..controller..*.*(..))  && !execution(* com.poyee.controller.base.DeploymentController.*(..))")
+    @Pointcut("execution(* com..*..controller..*.*(..)) " +
+            "&& !execution(* com.poyee.controller.base.DeploymentController.*(..)) " +
+            "&& !execution(* com.poyee.controller.base.ExceptionController.*(..))")
+    public void logPointCut() {
+    }
+
+    @Around("com.poyee.aop.ControllerLogAspect.logPointCut()")
+    public Object exeAround(ProceedingJoinPoint pjp) throws Throwable {
+        long s = System.currentTimeMillis();
+        Object proceed = pjp.proceed();
+        log.info("接口请求时间:{},url:{}", System.currentTimeMillis() - s, ServletUtils.getRequest().getRequestURI());
+        return proceed;
+    }
+
+    /**
+     * 处理完请求后执行
+     *
+     * @param joinPoint 切点
+     */
+    @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
+    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {
+        handleLog(joinPoint, null, jsonResult);
+    }
+
+    protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) {
+        try {
+            LogParam logParam = new LogParam();
+            logParam.setUrl(ServletUtils.getRequest().getRequestURI());
+            logParam.setIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
+            logParam.setResultData(StringUtils.substring(JSONUtils.marshalIgnoreNull(jsonResult), 0, 2000));
+            setRequestValue(joinPoint, logParam);
+            String className = joinPoint.getTarget().getClass().getName();
+            String methodName = joinPoint.getSignature().getName();
+            logParam.setMethod(className + "." + methodName + "()");
+            log.info("接口请求参数:{}", logParam);
+        } catch (Exception exp) {
+            log.error("日志打印异常,信息:", exp);
+        }
+    }
+
+
+    /**
+     * 获取请求的参数,放到log中
+     *
+     * @param logParam 操作日志
+     * @throws Exception 异常
+     */
+    private void setRequestValue(JoinPoint joinPoint, LogParam logParam) throws Exception {
+        Map<String, String[]> map = ServletUtils.getRequest().getParameterMap();
+        StringBuilder indata = new StringBuilder();
+        if (StringUtils.isNotEmpty(map)) {
+            SimplePropertyPreFilter filter = new SimplePropertyPreFilter();
+            filter.getExcludes().addAll(Arrays.asList(EXCLUDE_PROPERTIES));
+            String params = JSONObject.toJSONString(map, filter);
+            indata = new StringBuilder(params);
+        } else {
+            Object[] args = joinPoint.getArgs();
+            if (null != args) {
+                for (Object org : args) {
+                    try {
+                        if (!"java.lang.String".equals(org.getClass().getName())) {
+                            if (org instanceof InDto) {
+                                InDto inDto = (InDto) org;
+                                indata.append(JSONObject.toJSONString(inDto));
+                                logParam.setUser(String.valueOf(inDto.getUserId()));
+                            } else {
+                                indata.append(JSONObject.toJSONString(org));
+                            }
+                        } else {
+                            indata.append(org);
+                        }
+                    } catch (Exception ignored) {
+                    }
+                }
+            }
+        }
+        logParam.setSendData(indata.toString());
+    }
+}

+ 63 - 0
poyee-common/src/main/java/com/poyee/aop/CustomRetryAspect.java

@@ -0,0 +1,63 @@
+package com.poyee.aop;
+
+import com.poyee.anon.CustomRetry;
+import com.poyee.exception.ServiceException;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.support.DefaultTransactionDefinition;
+
+import javax.annotation.Resource;
+
+@Aspect
+@Component
+@Slf4j
+public class CustomRetryAspect {
+    @Resource
+    private PlatformTransactionManager transactionManager;
+
+    @Around("@annotation(customRetry)")
+    public Object around(ProceedingJoinPoint pjp, CustomRetry customRetry) throws Throwable {
+        int maxAttempts = customRetry.maxAttempts();
+        long delay = customRetry.delay();
+        boolean useTran = customRetry.isUseTran();
+
+        int attempts = 0;
+        Throwable lastException = null;
+        while (attempts < maxAttempts) {
+            TransactionStatus status = null;
+            try {
+                Object proceed;
+                if (useTran) {
+                    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
+                    def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
+                    def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
+                    status = transactionManager.getTransaction(def);
+                    proceed = pjp.proceed();
+                    transactionManager.commit(status);
+                } else {
+                    proceed = pjp.proceed();
+                }
+                return proceed;
+            } catch (Throwable t) {
+                if (status != null) {
+                    transactionManager.rollback(status);
+                }
+                lastException = t;
+                attempts++;
+                if (attempts < maxAttempts) {
+                    Thread.sleep(delay);
+                }
+            }
+        }
+        log.error("业务执行失败,重试次数:{},异常:", maxAttempts, lastException);
+        throw new ServiceException(405, "操作失败,请重试!");
+    }
+
+
+}

+ 44 - 0
poyee-common/src/main/java/com/poyee/aop/MqConsumerAOP.java

@@ -0,0 +1,44 @@
+package com.poyee.aop;
+
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.annotation.After;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.slf4j.MDC;
+import org.springframework.stereotype.Component;
+
+import java.util.UUID;
+
+/**
+ * 自定义aop
+ *
+ * @author Administrator
+ *
+ */
+@Component
+@Aspect
+@Slf4j
+public class MqConsumerAOP {
+
+	private static final String TRACE_ID = "TRACE_ID";
+
+	@Pointcut("@annotation(org.springframework.amqp.rabbit.annotation.RabbitListener)")
+	public void mqPointCut() {
+	}
+
+	@Before("mqPointCut()")
+	public void mqConsumerBefore() {
+		String tid = UUID.randomUUID().toString().replace("-", "");
+		if(MDC.get(TRACE_ID)==null){
+			MDC.put(TRACE_ID, tid);
+		}
+	}
+
+	@After("mqPointCut()")
+	public void mqConsumerAfter() {
+		MDC.remove(TRACE_ID);
+	}
+
+
+}

+ 106 - 0
poyee-common/src/main/java/com/poyee/aop/RedisLockAspect.java

@@ -0,0 +1,106 @@
+package com.poyee.aop;
+
+
+import com.poyee.anon.RedisLock;
+import com.poyee.exception.OrderException;
+import com.poyee.exception.ServiceException;
+import com.poyee.utils.RedisUtils;
+import com.poyee.utils.StringUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.Signature;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.support.DefaultTransactionDefinition;
+
+import javax.annotation.Resource;
+import java.lang.reflect.Method;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 分布式
+ *
+ */
+@Slf4j
+@Aspect
+@Component
+public class RedisLockAspect {
+
+	@Resource
+	private RedisUtils redisUtils;
+	@Resource
+	private PlatformTransactionManager transactionManager;
+
+	// 配置织入点
+	@Pointcut("@annotation(com.poyee.anon.RedisLock)")
+	public void lockPointCut() {
+	}
+
+	@Around("com.poyee.aop.RedisLockAspect.lockPointCut()")
+	public Object lockAround(ProceedingJoinPoint pjp) throws Throwable {
+		Signature signature = pjp.getSignature();
+		MethodSignature methodSignature = (MethodSignature) signature;
+		Method targetMethod = methodSignature.getMethod();
+		RedisLock annotation = targetMethod.getAnnotation(RedisLock.class);
+		String lockKey = annotation.lockKey();
+		lockKey = StringUtils.generateKeyBySpEL(lockKey, pjp);
+		log.debug("redis key:{}", lockKey);
+		TimeUnit unit = annotation.unit();
+		long waitTime = annotation.waitTime();
+		long leaseTime = annotation.leaseTime();
+		boolean useTran = annotation.isUseTran();
+		String failMsg = annotation.failMsg();
+
+		TransactionStatus status = null;
+		boolean isLock = false;
+		try {
+			isLock = redisUtils.tryLock(lockKey, unit, waitTime, leaseTime);
+			if (isLock) {
+				Object proceed;
+				if (useTran) {
+					DefaultTransactionDefinition def = new DefaultTransactionDefinition();
+					def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
+					def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
+					status = transactionManager.getTransaction(def);
+					//log.info("redis锁+事务开始,时间:{}",System.currentTimeMillis());
+					proceed = pjp.proceed();
+					transactionManager.commit(status);
+					//log.info("redis锁+事务提交成功,时间:{}",System.currentTimeMillis());
+				} else {
+					proceed = pjp.proceed();
+				}
+				redisUtils.unlock(lockKey);
+				isLock = false;
+				return proceed;
+			}
+		} catch (ServiceException | OrderException e) {
+			log.warn("业务处理失败:", e);
+			if (status != null) {
+				transactionManager.rollback(status);
+			}
+			throw e;
+		} catch (Exception e) {
+			log.error("业务执行异常:", e);
+			if (status != null) {
+				transactionManager.rollback(status);
+			}
+		} finally {
+			try {
+				if (isLock) {
+					redisUtils.unlock(lockKey);
+				}
+			} catch (Exception e) {
+				log.error("分布式锁释放异常:", e);
+			}
+		}
+		throw new ServiceException(405, failMsg);
+	}
+
+
+}

+ 93 - 0
poyee-common/src/main/java/com/poyee/config/BaseConfig.java

@@ -0,0 +1,93 @@
+package com.poyee.config;
+
+import com.poyee.config.log.MyThreadPoolTaskExecutor;
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * 基础config
+ */
+@Configuration
+@Data
+public class BaseConfig {
+	@Value("${poyee.app-version:dev}")
+	private String env;
+	@Value("${coreService.user.useServiceUrl:https://coresvc-dev.hobbystocks.cn}")
+	private String useServiceUrl;
+	@Value("${coreService.user.userInfoUrl:/user}")
+	private String userInfoUrl;
+	@Value("${coreService.user.merchantUrl:/user/merchant}")
+	private String merchantUrl;
+	@Value("${coreService.baseurl:https://coresvc-dev.hobbystocks.cn}")
+	private String baseurl;
+	@Value("${coreService.ipUrl:/api/geo/city}")
+	private String ipUrl;
+	@Value("${poyee.markUserPoint:500000}")
+	private Integer markUserPoint;
+	@Value("${goodsService.baseurl:https://127.0.0.1:8089}")
+	private String goodsBaseurl;
+	@Value("${goodsService.goodsNumByType:/api/goods/num/type}")
+	private String goodsNumByTypeUrl;
+	@Value("${goodsService.goodsPriceByType:/api/goods/price/type}")
+	private String goodsPriceByType;
+	@Value("${goodsService.teamGoodsUrl:/api/goods/group/team/}")
+	private String teamGoodsUrl;
+	@Value("${goodsService.goodsUrl:/api/goods/list}")
+	private String goodsUrl;
+
+	@Autowired
+	protected ApplicationContext applicationContext;
+	// 核心线程池大小
+	private int corePoolSize = 5;
+	// 最大可创建的线程数
+	private int maxPoolSize = 50;
+	// 队列最大长度
+	private int queueCapacity = 600;
+	// 线程池维护线程所允许的空闲时间
+	private int keepAliveSeconds = 120;
+
+	@Bean(name = "threadPoolTaskExecutor")
+	public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
+		ThreadPoolTaskExecutor executor = new MyThreadPoolTaskExecutor();
+		executor.setMaxPoolSize(maxPoolSize);
+		executor.setCorePoolSize(corePoolSize);
+		executor.setQueueCapacity(queueCapacity);
+		executor.setKeepAliveSeconds(keepAliveSeconds);
+		// 线程池对拒绝任务(无线程可用)的处理策略
+		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+		executor.setThreadNamePrefix("order-pool-");
+		return executor;
+	}
+
+	/**
+	 * rest模板
+	 * @return
+	 */
+	@Bean
+	public RestTemplate restTemplate(RestTemplateBuilder builder) {
+		// boot中可使用RestTemplateBuilder.build创建
+		RestTemplate restTemplate = builder.build();
+		// 配置请求工厂
+		HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
+		restTemplate.setRequestFactory(clientHttpRequestFactory);
+		return restTemplate;
+	}
+
+	//@Bean(name = "transactionManager")
+	//public DataSourceTransactionManager getTransactionManager() {
+	//	DataSource dataSource = applicationContext.getBean(DataSource.class);
+	//	DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
+	//	transactionManager.setDataSource(dataSource);
+	//	return transactionManager;
+	//}
+}

+ 32 - 0
poyee-common/src/main/java/com/poyee/config/CommonConfig.java

@@ -0,0 +1,32 @@
+package com.poyee.config;
+
+import org.springframework.context.annotation.Configuration;
+
+import javax.annotation.Resource;
+
+/**
+ * @author by po'yi
+ * @Classname CommonConfig
+ * @Description TODO
+ * @Date 2021/12/16 14:05
+ */
+@Configuration
+public class CommonConfig {
+	public static BaseConfig baseconfig;
+	public static final String ENV_PRO = "prod";
+	public static final String ENV_TEST = "test";
+	public static final String ENV_DEV = "dev";
+
+	@Resource
+	public  void setBaseConfig(BaseConfig baseconfig) {
+		CommonConfig.baseconfig = baseconfig;
+	}
+
+	public static boolean isProdEnv(){
+		return ENV_PRO.equals(baseconfig.getEnv());
+	}
+
+	public static boolean isDevEnv(){
+		return ENV_DEV.equals(baseconfig.getEnv());
+	}
+}

+ 24 - 0
poyee-common/src/main/java/com/poyee/config/InitPoolConnect.java

@@ -0,0 +1,24 @@
+package com.poyee.config;
+
+import com.poyee.repository.DictDataRepository;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+@Component
+@Order
+@Slf4j
+public class InitPoolConnect implements CommandLineRunner {
+
+    @Resource
+    private DictDataRepository dictDataRepository;
+
+    @Override
+    public void run(String... args) throws Exception {
+        dictDataRepository.findById(1L);
+        log.info("data source init");
+    }
+}

+ 70 - 0
poyee-common/src/main/java/com/poyee/config/SwaggerConfig.java

@@ -0,0 +1,70 @@
+package com.poyee.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+/**
+ * Swagger2的接口配置
+ *
+ * @author zheng
+ */
+@Configuration
+@EnableSwagger2
+public class SwaggerConfig
+{
+    /** 是否开启swagger */
+    @Value("${swagger.enabled:false}")
+    private boolean enabled;
+    @Value("${poyee.name}")
+    private String appName;
+
+    /**
+     * 创建API
+     */
+    @Bean
+    public Docket createRestApi()
+    {
+        return new Docket(DocumentationType.SWAGGER_2)
+                // 是否启用Swagger
+                .enable(enabled)
+                // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息)
+                .apiInfo(apiInfo())
+                // 设置哪些接口暴露给Swagger展示
+                .select()
+                // 扫描所有有注解的api,用这种方式更灵活
+                //.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
+                // 扫描指定包中的swagger注解
+                .apis(RequestHandlerSelectors.basePackage("com.poyee.controller"))
+                // 扫描所有
+                .apis(RequestHandlerSelectors.any())
+                .paths(PathSelectors.any())
+                .build();
+    }
+
+    /**
+     * 添加摘要信息
+     */
+    private ApiInfo apiInfo()
+    {
+        // 用ApiInfoBuilder进行定制
+        return new ApiInfoBuilder()
+                // 设置标题
+                .title("标题:珀懿APP_接口文档")
+                // 描述
+                .description("描述:珀懿APP接口")
+                // 作者信息
+                .contact(new Contact(appName, null, null))
+                // 版本
+                .version("版本号:1.0.1")
+                .build();
+    }
+}

+ 15 - 0
poyee-common/src/main/java/com/poyee/config/WebConfig.java

@@ -0,0 +1,15 @@
+package com.poyee.config;
+
+import com.poyee.config.interceptor.ActTokenInterceptor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class WebConfig implements WebMvcConfigurer {
+
+	@Override
+	public void addInterceptors(InterceptorRegistry registry) {
+		registry.addInterceptor(new ActTokenInterceptor()).addPathPatterns("/**/group/submit");
+	}
+}

+ 51 - 0
poyee-common/src/main/java/com/poyee/config/interceptor/ActTokenInterceptor.java

@@ -0,0 +1,51 @@
+package com.poyee.config.interceptor;
+
+import com.poyee.constant.Constants;
+import com.poyee.exception.ServiceException;
+import com.poyee.param.UserInfo;
+import com.poyee.utils.RedisTools;
+import com.poyee.utils.RedisUtils;
+import com.poyee.utils.ServletUtils;
+import com.poyee.utils.UserUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 秒杀token弃用
+ */
+@Slf4j
+@Component
+public class ActTokenInterceptor extends HandlerInterceptorAdapter {
+
+	@Override
+	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+		String actToken = ServletUtils.getRequest().getHeader("ACT_TOKEN");
+		if (StringUtils.isEmpty(actToken)) {
+			return true;
+		}
+		log.debug("------进入actToken前置拦截器--------");
+		try {
+			UserInfo userInfo = UserUtils.getSimpleUserInfo(true);
+			RedisUtils redisUtils = RedisTools.getRedisUtils();
+			String key=Constants.ACT_USER_TOKEN_CACHE + userInfo.getId();
+			Object tokenCache = redisUtils.get(key);
+			if (tokenCache == null) {
+				log.debug("请求无活动token");
+				throw new ServiceException("活动凭证失效,请重试!");
+			}
+			log.debug("活动凭证比较:请求token{},用户缓存token:{}", actToken, tokenCache);
+			if (actToken.equalsIgnoreCase(tokenCache.toString())) {
+				redisUtils.del(key);
+				return true;
+			}
+		} catch (Exception e) {
+			log.error("秒杀token校验异常", e);
+		}
+		throw new ServiceException("活动token失效");
+	}
+}

+ 33 - 0
poyee-common/src/main/java/com/poyee/config/log/LogInterceptor.java

@@ -0,0 +1,33 @@
+package com.poyee.config.log;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.MDC;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.annotation.Nullable;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.UUID;
+
+public class LogInterceptor implements HandlerInterceptor {
+ 
+    private static final String TRACE_ID = "TRACE_ID";
+ 
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
+        String tid = UUID.randomUUID().toString().replace("-", "");
+        //可以考虑让客户端传入链路ID,但需保证一定的复杂度唯一性;如果没使用默认UUID自动生成
+        if (!StringUtils.isEmpty(request.getHeader("TRACE_ID"))){
+            tid=request.getHeader("TRACE_ID");
+        }
+        MDC.put(TRACE_ID, tid);
+        return true;
+    }
+ 
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
+                                @Nullable Exception ex) {
+        MDC.remove(TRACE_ID);
+    }
+ 
+}

+ 29 - 0
poyee-common/src/main/java/com/poyee/config/log/MyThreadPoolTaskExecutor.java

@@ -0,0 +1,29 @@
+package com.poyee.config.log;
+
+import org.slf4j.MDC;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+
+public final class MyThreadPoolTaskExecutor  extends ThreadPoolTaskExecutor {
+    public MyThreadPoolTaskExecutor() {
+        super();
+    }
+    
+    @Override
+    public void execute(Runnable task) {
+        super.execute(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
+    }
+ 
+ 
+    @Override
+    public <T> Future<T> submit(Callable<T> task) {
+        return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
+    }
+ 
+    @Override
+    public Future<?> submit(Runnable task) {
+        return super.submit(ThreadMdcUtil.wrap(task, MDC.getCopyOfContextMap()));
+    }
+}

+ 69 - 0
poyee-common/src/main/java/com/poyee/config/log/ThreadMdcUtil.java

@@ -0,0 +1,69 @@
+package com.poyee.config.log;
+
+import org.slf4j.MDC;
+
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+
+public final class ThreadMdcUtil {
+    private static final String TRACE_ID = "TRACE_ID";
+ 
+    // 获取唯一性标识
+    public static String generateTraceId() {
+        return UUID.randomUUID().toString();
+    }
+ 
+    public static void setTraceIdIfAbsent() {
+        if (MDC.get(TRACE_ID) == null) {
+            MDC.put(TRACE_ID, generateTraceId());
+        }
+    }
+ 
+    /**
+     * 用于父线程向线程池中提交任务时,将自身MDC中的数据复制给子线程
+     *
+     * @param callable
+     * @param context
+     * @param <T>
+     * @return
+     */
+    public static <T> Callable<T> wrap(final Callable<T> callable, final Map<String, String> context) {
+        return () -> {
+            if (context == null) {
+                MDC.clear();
+            } else {
+                MDC.setContextMap(context);
+            }
+            setTraceIdIfAbsent();
+            try {
+                return callable.call();
+            } finally {
+                MDC.clear();
+            }
+        };
+    }
+ 
+    /**
+     * 用于父线程向线程池中提交任务时,将自身MDC中的数据复制给子线程
+     *
+     * @param runnable
+     * @param context
+     * @return
+     */
+    public static Runnable wrap(final Runnable runnable, final Map<String, String> context) {
+        return () -> {
+            if (context == null) {
+                MDC.clear();
+            } else {
+                MDC.setContextMap(context);
+            }
+            setTraceIdIfAbsent();
+            try {
+                runnable.run();
+            } finally {
+                MDC.clear();
+            }
+        };
+    }
+}

+ 22 - 0
poyee-common/src/main/java/com/poyee/config/log/WebConfigurerAdapter.java

@@ -0,0 +1,22 @@
+package com.poyee.config.log;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class WebConfigurerAdapter implements WebMvcConfigurer {
+    @Bean
+    public LogInterceptor logInterceptor() {
+        return new LogInterceptor();
+    }
+ 
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(logInterceptor());
+        //可以具体制定哪些需要拦截,哪些不拦截,其实也可以使用自定义注解更灵活完成
+//                .addPathPatterns("/**")
+//                .excludePathPatterns("/test.html");
+    }
+}

+ 210 - 0
poyee-common/src/main/java/com/poyee/config/mq/MqConfig.java

@@ -0,0 +1,210 @@
+package com.poyee.config.mq;
+
+import com.poyee.constant.MqConstans;
+import org.springframework.amqp.core.*;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Configuration
+public class MqConfig {
+    /**
+     * 队列
+     * durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
+     * exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
+     * autoDelete:是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。
+     * return new Queue("test",true,true,false);
+     * 一般设置一下队列的持久化就好,其余两个就是默认false
+     * @return
+     */
+    @Bean
+    public Queue TestDirectQueue() {
+        return new Queue(MqConstans.TEST_QUEUE,true);
+    }
+
+    @Bean
+    public Queue OrderPayCallBackQueue() {
+        return new Queue(MqConstans.QUEUE_ORDER_PAY_CALLBACK,true);
+    }
+
+    @Bean
+    public Queue PrePayCallBackQueue() {
+        return new Queue(MqConstans.QUEUE_PRE_PAY_CALLBACK,true);
+    }
+
+    @Bean
+    public Queue OrderExpiredQueue() {
+        return new Queue(MqConstans.QUEUE_ORDER_EXPIRED,true);
+    }
+
+    @Bean
+    public Queue orderSuccessQueue() {
+        return new Queue(MqConstans.QUEUE_ORDER_SUCCESS,true);
+    }
+
+    @Bean
+    public Queue userBehavior() {
+        return new Queue(MqConstans.QUEUE_USER_BEHAVIOR,true);
+    }
+
+    @Bean
+    public Queue userPoint() {
+        return new Queue(MqConstans.QUEUE_USER_POINT,true);
+    }
+
+    @Bean
+    public Queue OrderRefundQueue() {
+        return new Queue(MqConstans.QUEUE_ORDER_REFUND,true);
+    }
+
+    @Bean
+    public Queue groupFullQueue() {
+        return new Queue(MqConstans.QUEUE_GROUP_FULL,true);
+    }
+
+    @Bean
+    public Queue groupSortQueue() {
+        return new Queue(MqConstans.QUEUE_GROUP_SORT_UPDATE,true);
+    }
+
+    @Bean
+    public Queue skuStockQueue() {
+        return new Queue(MqConstans.QUEUE_SKU_STOCK_UPDATE,true);
+    }
+    /**
+     * Direct交换机
+     *  return new DirectExchange("test_exchange",true,true);
+     * @return
+     */
+    @Bean
+    public DirectExchange TestDirectExchange() {
+        return new DirectExchange("exchange_test",true,false);
+    }
+
+    @Bean
+    public DirectExchange OrderPayCallBackExchange() {
+        return new DirectExchange(MqConstans.EXCHANGE_ORDER_PAY_CALLBACK,true,false);
+    }
+
+    @Bean
+    public DirectExchange PrePayCallBackExchange() {
+        return new DirectExchange(MqConstans.EXCHANGE_PRE_PAY_CALLBACK,true,false);
+    }
+
+    @Bean
+    public DirectExchange orderSuccessExchange() {
+        return new DirectExchange(MqConstans.EXCHANGE_ORDER_SUCCESS,true,false);
+    }
+
+    @Bean
+    public DirectExchange userBehaviorExchange() {
+        return new DirectExchange(MqConstans.EXCHANGE_USER_BEHAVIOR,true,false);
+    }
+
+    @Bean
+    public DirectExchange userPointExchange() {
+        return new DirectExchange(MqConstans.EXCHANGE_USER_POINT,true,false);
+    }
+
+    @Bean
+    public CustomExchange delayExchange() {
+        Map<String, Object> args = new HashMap<>(1);
+        args.put("x-delayed-type", "direct");
+        return new CustomExchange(MqConstans.EXCHANGE_DELAYED_ORDER_EXPIRED, "x-delayed-message", true, false, args);
+    }
+
+    @Bean
+    public DirectExchange OrderRefundExchange() {
+        return new DirectExchange(MqConstans.EXCHANGE_ORDER_REFUND,true,false);
+    }
+
+    @Bean
+    public DirectExchange groupFullExchange() {
+        return new DirectExchange(MqConstans.EXCHANGE_GROUP_FULL,true,false);
+    }
+
+    @Bean
+    public DirectExchange groupSortExchange() {
+        return new DirectExchange(MqConstans.EXCHANGE_GROUP_SORT_UPDATE,true,false);
+    }
+
+
+    @Bean
+    public DirectExchange skuStockExchange() {
+        return new DirectExchange(MqConstans.EXCHANGE_SKU_STOCK_UPDATE,true,false);
+    }
+
+    @Bean
+    public Binding bindingDelayExchange()
+    {
+        return BindingBuilder.bind(OrderExpiredQueue()).to(delayExchange()).with(MqConstans.ROUTING_KEY_ORDER_EXPIRED).noargs();
+    }
+
+
+    /**
+     * 绑定  将队列和交换机绑定, 并设置用于匹配键:test
+     * @return
+     */
+    @Bean
+    public Binding bindingDirect() {
+        return BindingBuilder.bind(TestDirectQueue()).to(TestDirectExchange()).with("test");
+    }
+
+    @Bean
+    public Binding bindingOrderPayCallBackDirect() {
+        return BindingBuilder.bind(OrderPayCallBackQueue()).to(OrderPayCallBackExchange()).with(MqConstans.ROUTING_KEY_CALLBACK);
+    }
+
+    @Bean
+    public Binding bindingPrePayCallBackDirect() {
+        return BindingBuilder.bind(PrePayCallBackQueue()).to(PrePayCallBackExchange()).with(MqConstans.ROUTING_KEY_PRE_CALLBACK);
+    }
+
+    @Bean
+    public Binding bindingOrderSuccessDirect() {
+        return BindingBuilder.bind(orderSuccessQueue()).to(orderSuccessExchange()).with(MqConstans.ROUTING_KEY_ORDER_SUCCESS);
+    }
+
+    @Bean
+    public Binding bindingUserBehaviorDirect() {
+        return BindingBuilder.bind(userBehavior()).to(userBehaviorExchange()).with(MqConstans.ROUTING_KEY_USER_BEHAVIOR);
+    }
+
+    @Bean
+    public Binding bindingUserPointDirect() {
+        return BindingBuilder.bind(userPoint()).to(userPointExchange()).with(MqConstans.ROUTING_KEY_USER_POINT);
+    }
+
+    @Bean
+    public Binding bindingOrderRefundDirect() {
+        return BindingBuilder.bind(OrderRefundQueue()).to(OrderRefundExchange()).with(MqConstans.ROUTING_KEY_ORDER_REFUND);
+    }
+
+    @Bean
+    public Binding bindingGroupFullDirect() {
+        return BindingBuilder.bind(groupFullQueue()).to(groupFullExchange()).with(MqConstans.ROUTING_KEY_GROUP_FULL);
+    }
+
+    @Bean
+    public Binding bindingGroupSortDirect() {
+        return BindingBuilder.bind(groupSortQueue()).to(groupSortExchange()).with(MqConstans.ROUTING_KEY_GROUP_SORT_UPDATE);
+    }
+
+    @Bean
+    public Binding bindingSkuStockDirect() {
+        return BindingBuilder.bind(skuStockQueue()).to(skuStockExchange()).with(MqConstans.ROUTING_KEY_SKU_STOCK_UPDATE);
+    }
+
+    @Bean
+    public Queue asyncOrderProcessQueue() {
+        return new Queue(MqConstans.QUEUE_ASYNC_ORDER_PROCESS,true);
+    }
+
+    @Bean
+    public Queue queueSkuStockUpdateNew() {
+        return new Queue(MqConstans.QUEUE_SKU_STOCK_UPDATE_NEW,true);
+    }
+
+}

+ 92 - 0
poyee-common/src/main/java/com/poyee/config/redis/CacheConfig.java

@@ -0,0 +1,92 @@
+package com.poyee.config.redis;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.CachingConfigurerSupport;
+import org.springframework.cache.interceptor.*;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.cache.RedisCacheWriter;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializationContext;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import javax.annotation.Resource;
+import java.time.Duration;
+
+@Configuration
+public class CacheConfig extends CachingConfigurerSupport {
+
+    @Resource
+    private RedisConnectionFactory factory;
+
+    /**
+     * 自定义生成redis-key
+     *
+     * @return
+     */
+    @Override
+    @Bean
+    public KeyGenerator keyGenerator() {
+        return (o, method, objects) -> {
+            StringBuilder sb = new StringBuilder();
+            sb.append(o.getClass().getName()).append(".");
+            sb.append(method.getName()).append(".");
+            for (Object obj : objects) {
+                if(obj!=null){
+                    sb.append(obj.toString());
+                }
+            }
+            //System.out.println("keyGenerator=" + sb.toString());
+            return sb.toString();
+        };
+    }
+
+
+    @Bean
+    @Override
+    public CacheResolver cacheResolver() {
+        return new SimpleCacheResolver(cacheManager());
+    }
+
+    @Bean
+    @Override
+    public CacheErrorHandler errorHandler() {
+        // 用于捕获从Cache中进行CRUD时的异常的回调处理器。
+        return new SimpleCacheErrorHandler();
+    }
+
+    //@Bean
+    //@Override
+    //public CacheManager cacheManager() {
+    //    RedisCacheConfiguration cacheConfiguration = defaultCacheConfig()
+    //                    .disableCachingNullValues()
+    //                    .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
+    //    return RedisCacheManager.builder(factory).cacheDefaults(cacheConfiguration).build();
+    //
+    //}
+
+    @Bean
+    @Override
+    public CacheManager cacheManager() {
+        ObjectMapper om = new ObjectMapper();
+        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
+        // 解决查询缓存转换异常的问题
+        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+        jackson2JsonRedisSerializer.setObjectMapper(om);
+        // 配置序列化(解决乱码的问题)
+        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
+                .entryTtl(Duration.ofMillis(-1))
+                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
+                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
+                .disableCachingNullValues();
+        RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(factory);
+        return new RedisConfigCacheManager(cacheWriter, config);
+
+    }
+} 

+ 71 - 0
poyee-common/src/main/java/com/poyee/config/redis/LuaScriptLoader.java

@@ -0,0 +1,71 @@
+package com.poyee.config.redis;
+
+import com.poyee.exception.ServiceException;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.springframework.stereotype.Component;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+@Slf4j
+@Component
+public class LuaScriptLoader {
+
+    private static final String SKU_SUB_STOCK_PATH = "lua/sku_sub_stock.lua";
+    private static final String SKU_ADD_STOCK_PATH = "lua/sku_add_stock.lua";
+    public static  String SKU_SUB_STOCK_LUA=null;
+    public static  String SKU_ADD_STOCK_LUA=null;
+
+    static {
+        try {
+            SKU_SUB_STOCK_LUA = loadScript(SKU_SUB_STOCK_PATH);
+            SKU_ADD_STOCK_LUA = loadScript(SKU_ADD_STOCK_PATH);
+            log.info("加载lua脚本成功,脚本长度,add:{},sub:{}",SKU_ADD_STOCK_LUA.length(),SKU_SUB_STOCK_LUA.length());
+        } catch (Exception e) {
+            log.error("加载lua脚本异常",e);
+        }
+    }
+
+    private static String loadScript(String path) throws IOException {
+        Resource resource = new ClassPathResource(path);
+        try (InputStream inputStream = resource.getInputStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+            byte[] buffer = new byte[1024];
+            int bytesRead;
+            while ((bytesRead = inputStream.read(buffer)) != -1) {
+                outputStream.write(buffer, 0, bytesRead);
+            }
+            return new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
+        }
+    }
+
+
+    public static String getSkuSubStockLua() {
+        if(StringUtils.isEmpty(SKU_SUB_STOCK_LUA)){
+            throw new ServiceException("商品库存执行异常");
+        }
+        return SKU_SUB_STOCK_LUA;
+    }
+
+    public static String getSkuAddStockLua() {
+        if(StringUtils.isEmpty(SKU_ADD_STOCK_LUA)){
+            throw new ServiceException("商品库存执行异常");
+        }
+        return SKU_ADD_STOCK_LUA;
+    }
+
+    // public static String loadLuaScript(String filePath) throws Exception {
+    //     ClassLoader classLoader = LuaScriptLoader.class.getClassLoader();
+    //     byte[] bytes = Files.readAllBytes(Paths.get(classLoader.getResource(filePath).toURI()));
+    //     return new String(bytes, StandardCharsets.UTF_8);
+    // }
+
+    // public static void main(String[] args) throws Exception {
+    //     String luaScript = loadLuaScript("lua/sku_sub_stock.lua");
+    //     System.out.println(luaScript);
+    // }
+}

+ 128 - 0
poyee-common/src/main/java/com/poyee/config/redis/RedisConfig.java

@@ -0,0 +1,128 @@
+package com.poyee.config.redis;
+
+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.core.*;
+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 String 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();
+    }
+
+    @Bean(name = "redissonClient")
+    public RedissonClient redissonClientSingle() throws IOException {
+        Config config = new Config();
+        if(!"127.0.0.1:6379".equals(nodes)&&!"master".equals(master)){
+            SentinelServersConfig sentinelServers = config.useSentinelServers();
+            sentinelServers.addSentinelAddress("redis://"+nodes).setMasterName(master).setDatabase(1);
+            if(!StringUtils.isEmpty(password)){
+                sentinelServers.setPassword(password);
+            }
+        }else {
+            SingleServerConfig singleServer = config.useSingleServer();
+            singleServer.setAddress("redis://"+host+":"+port).setDatabase(1);
+            if(!StringUtils.isEmpty(password)){
+                singleServer.setPassword(password);
+            }
+        }
+        return Redisson.create(config);
+    }
+
+    @Bean(name = "redissonClientOfDb1")
+    public RedissonClient redissonClientSingle2() throws IOException {
+        Config config = new Config();
+        if(!"127.0.0.1:6379".equals(nodes)&&!"master".equals(master)){
+            SentinelServersConfig sentinelServers = config.useSentinelServers();
+            sentinelServers.addSentinelAddress("redis://"+nodes).setMasterName(master).setDatabase(1);
+            if(!StringUtils.isEmpty(password)){
+                sentinelServers.setPassword(password);
+            }
+        }else {
+            SingleServerConfig singleServer = config.useSingleServer();
+            singleServer.setAddress("redis://"+host+":"+port).setDatabase(1);
+            if(!StringUtils.isEmpty(password)){
+                singleServer.setPassword(password);
+            }
+        }
+        return Redisson.create(config);
+    }
+
+    //@Bean
+    //public RedisMessageListenerContainer myRedisMessageListenerContainer(RedisConnectionFactory connectionFactory) {
+    //    RedisMessageListenerContainer container = new RedisMessageListenerContainer();
+    //    container.setConnectionFactory(connectionFactory);
+    //    return container;
+    //}
+
+}

+ 44 - 0
poyee-common/src/main/java/com/poyee/config/redis/RedisConfigCacheManager.java

@@ -0,0 +1,44 @@
+package com.poyee.config.redis;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.data.redis.cache.*;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializationContext;
+
+import java.time.Duration;
+
+/**
+ * redis 配置类
+ */
+@Slf4j
+public class RedisConfigCacheManager extends RedisCacheManager {
+ 
+ 
+    public RedisConfigCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
+        super(cacheWriter, defaultCacheConfiguration);
+    }
+ 
+    private static final RedisSerializationContext.SerializationPair<Object> DEFAULT_PAIR = RedisSerializationContext.SerializationPair
+            .fromSerializer(new GenericJackson2JsonRedisSerializer());
+ 
+    private static final CacheKeyPrefix DEFAULT_CACHE_KEY_PREFIX = cacheName -> cacheName+":";
+ 
+    @Override
+    protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
+        final int lastIndexOf = StringUtils.lastIndexOf(name, '#');
+        Duration duration;
+        if (lastIndexOf > -1) {
+            final String ttl = StringUtils.substring(name, lastIndexOf + 1);
+            duration = Duration.ofSeconds(Long.parseLong(ttl));
+        }else {
+            duration = Duration.ofSeconds(84600L);
+        }
+        cacheConfig = cacheConfig.entryTtl(duration);
+        //修改缓存key和value值的序列化方式
+        cacheConfig = cacheConfig.computePrefixWith(DEFAULT_CACHE_KEY_PREFIX)
+                .serializeValuesWith(DEFAULT_PAIR);
+        final String cacheName = StringUtils.substring(name, 0, lastIndexOf);
+        return super.createRedisCache(cacheName, cacheConfig);
+    }
+}

+ 53 - 0
poyee-common/src/main/java/com/poyee/constant/ActConstans.java

@@ -0,0 +1,53 @@
+package com.poyee.constant;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 广告常量
+ */
+public interface ActConstans {
+    /**拼团-生态购*/
+    String GROUP_SALE_CODE = "group_sale_code";
+    /**拼团-首购金*/
+    String GROUP_FIRST_ORDER = "group_first_order";
+    /**拼团-商家赠礼*/
+    String GROUP_MERCHANT_GIFT = "merchant_act_send_gift";
+    /**拼团-随机卡密优惠劵*/
+    String GROUP_COUPON_RANDOM_GOODS = "group_coupon_random_goods";
+    /**拼团-商家指定卡密优惠劵*/
+    String GROUP_COUPON_SELECT_GOODS = "group_coupon_select_goods";
+    /**拼团活动记录*/
+    String GROUP_ACT_RECORD = "group_act_record";
+
+    /**拼团-免单*/
+    String GROUP_FREE_ORDER = "group_free_order";
+    /** 拼团组齐后发放 */
+    String MERCHANT_ACT_GROUP_FULL="merchant_act_group_full";
+    /** 公示卡密后发放 */
+    String MERCHANT_ACT_PUBLIC_GOODS="merchant_act_public_goods";
+    /** 订单购买后分配 */
+    String MERCHANT_ACT_AFT_ORDER="merchant_act_aft_order";
+    /**平台优惠劵*/
+    String COUPON_COMMON="coupon_common";
+    /**商家优惠劵*/
+    String COUPON_MERCHANT="coupon_merchant";
+    /** 拼团卡密活动查询传null时默认查询类型,组齐或购买后卡密活动 */
+    List<String> NOT_NULL_ACT_TYPE = Arrays.asList(MERCHANT_ACT_PUBLIC_GOODS, MERCHANT_ACT_GROUP_FULL, MERCHANT_ACT_AFT_ORDER);
+    /** 允许克隆的拼团活动类型 */
+    List<String> NEED_CLONE_ACT_TYPE = Arrays.asList(GROUP_COUPON_RANDOM_GOODS, GROUP_COUPON_SELECT_GOODS, GROUP_FIRST_ORDER);
+    /** 优惠劵类型 */
+    List<String> DISCOUNT_COUPON_TYPES = Arrays.asList(COUPON_COMMON, COUPON_MERCHANT);
+    /**满减优惠劵*/
+    String COUPON_FULL_DISCOUNT="full_discount";
+    /**折扣优惠劵*/
+    String COUPON_RATE_DISCOUNT="rete_discount";
+    /**代金劵,直接抵扣*/
+    String COUPON_VOUCHER="voucher";
+    /**盒*/
+    String BOX="BOX";
+    /**箱*/
+    String CARTON="CARTON";
+    /**包*/
+    String PACK="PACK";
+}

+ 382 - 0
poyee-common/src/main/java/com/poyee/constant/Constants.java

@@ -0,0 +1,382 @@
+package com.poyee.constant;
+
+import com.google.common.collect.ImmutableMap;
+
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 通用常量信息
+ * 
+ * @author zheng
+ */
+public class Constants {
+    public static final String UTF8 = "UTF-8";
+    public static final String GBK = "GBK";
+    public static final String STOCK_GROUP_INFO = "STOCK_GROUP_INFO_";
+	public static final String ZERO = "0";
+	public static final String ONE = "1";
+	public static final String TWO = "2";
+    public static final String STATUS_OK = ONE;
+
+    public static final String TRADE_SUCCESS_EN="SUCCESS";
+    public static final String ALIPAY_TRADE_SUCCESS="TRADE_SUCCESS";
+	public static final String REDIRECT_PATH="/pageB/productDetail/productDetail?id=";
+	public static final String MERCHANT_INFO_TYPE_SALE="sale";
+	public static final String MERCHANT_INFO_TYPE_HISTORY="history";
+	//商家拉黑类型:
+    public static final String MER_PULL_BACK = "mer_pull_back";
+	//用户不能下单  标记
+	public static final String CAN_NOT_SUBMIT_ORDER = "can_not_submit_order";
+
+	public static long timesDay=60*60*24*7;
+	/**
+	 * 一天的秒
+	 */
+	public static final Long dayForSecond = 86400L;
+    public static long times=1000*timesDay;
+	public static final String  OPTIONS="OPTIONS";
+	public static final String  ORDER_CANCEL_MARK="ORDER_CANCEL_MARK_";
+	public static final String  ORDER_BUY_ALL_MARK="ORDER_BUY_ALL_MARK";
+	public static final String  CARD_INFO_MARK="CARD_INFO_MARK_";
+	public static final String  CARD_GOODS_ACT_SIGN="CARD_GOODS_ACT_SIGN";
+	public static final String  CARD_INFO_ACT_SIGN="CARD_INFO_ACT_SIGN";
+	public static Map<String, Object> JSON_HEADS = ImmutableMap.of("Content-Type","application/json");
+	public static final String  JPUSH_TYPE_ID="registrationIds";
+	public static final String  ORDER_BUY_ALL_RETURN_TITLE="亲爱的用户您好,感谢您对HOBBY STOCKS的支持,请理性参与购买,祝您玩卡愉快,得到好卡!";
+	public static final String CODE_TYPE_INCR="CODE_TYPE_INCR_";
+	public static final String PRICE_FOR_NEW="price_for_new";
+	public static String PUSH_TYPE_JPUSH="jpush";
+	public static String PUSH_TYPE_SYSTEM="system";
+	public static String PUSH_ACCEPT_TYPE_ALL="all";
+	public static String PUSH_ACCEPT_TYPE_SETS="sets";
+	public static String PUSH_ACCEPT_TYPE_GROUP="group";
+	public static String PUSH_ACCEPT_TYPE_USER="user";
+	public static String APP_VERSION_PROD="prod";
+	public static String INFO_TYPE_BUY_TEAM="买队玩法";
+	public static String INFO_TYPE_SELECT_TEAM="选队随机";
+	public static String INFO_TYPE_SELECT_SETS="自选卡种";
+	public static String INFO_TYPE_TEAM="随机球队";
+	public static String INFO_TYPE_PLAYER="随机球员";
+	public static String INFO_TYPE_SETS="随机卡种(区分编号)";
+	public static String INFO_TYPE_SETS_NO="随机卡种(不区分编号)";
+	/**选队随机 子分类:区域随机*/
+	public static String INFO_SUB_TYPE_AREA_RANDOM="区域随机";
+	public static final String LIMIT_RULE="LIMIT_RULE";
+	public static final String AND_STR="&";
+	public static final String comma=",";
+	public static final String comma2=",,";
+	public static final String comma3=",,,";
+	public static final String bank=" ";
+	public static final String sub="-";
+	public static final String seq_ZN="编";
+	public static final String NO="No.";
+	public static final String All="all";
+	public static final String TRUE_STR="T";
+	public static final String LIVE_TYPE_APPLET="applet";
+	public static final String LIVE_TYPE_WORK_WX="work_wx";
+	public static final String LIVE_TYPE_TENCENT_CLOUD="tencent_cloud";
+	public static String EDIT_TYPE_PAY_PSD="pay_psd";
+	public static String EDIT_TYPE_LOGIN_PSD="login_psd";
+	public static String MSG_PAGE="MSG_PAGE";
+	public static String HOT_TYPE="HOT_TYPE";
+	public static String USER_PSD_COUNT="USER_PSD_COUNT";
+	public static String RONG_CLOUD_PATH_KEY="RONG_CLOUD_PATH_KEY";
+	public static String USER_PAY_REMIND="USER_PAY_REMIND";
+	public static final String UPDATE_GROUP_QUERY="UPDATE_GROUP_QUERY_";
+	/**优惠劵类型:组团*/
+	public static final String COUPON_TYPE_CARD="card";
+	/**优惠劵类型:商品*/
+	public static final String COUPON_TYPE_GOODS="goods";
+	/**订单类型:组团*/
+	public static final String ORDER_TYPE_GROUP="group";
+	/**订单类型:商城*/
+	public static final String ORDER_TYPE_SHOP="shop";
+	/**商品类型:积分*/
+	public static final String SKU_TYPE_POINT="point";
+	/**商城商品*/
+	public static final String SKU_TYPE_GOODS=COUPON_TYPE_GOODS;
+	/**商品类型:纯金额*/
+	public static final String SKU_TYPE_AMOUNT="amount";
+	/**商品类型:混合*/
+	public static final String SKU_TYPE_MIX="mix";
+	/**商品活动类型:优惠劵*/
+	public static final String SKU_ACT_TYPE_COUPON="coupon";
+	/**人脸识别不提醒白名单*/
+	public static String WHITELIST_FAVE_VERIFY_USER="WHITELIST_FAVE_VERIFY_USER";
+	/**spu库存锁key*/
+	public static String SPU_SOLD_STOCK_LOCK="SPU_SOLD_STOCK_LOCK";
+
+	/**商城订单详情新地址*/
+	public static String MALL_ORDER_DETAIL_URL="/pageC/shoppingUser/myOrderDetials?id=";
+	/**组队订单详情*/
+	public static String GROUP_ORDER_DETAIL_URL="/pageC/myPages/myOrderDetail?id=";
+	//组队详情页
+	public static String GROUP_DETAIL_URL = "/pageB/productDetail/productDetail?id=";
+
+	public static final List<Integer> refundOrderStatus = Arrays.asList(103,104,105,106,301);
+	/**限购的订单状态*/
+	public static final List<Long> LIMIT_ORDER_STATUS = Arrays.asList(100L,101L,103L,104L,105L,106L,301L,203L,204L,205L);
+	/**限购的组团订单状态*/
+	public static final List<Long> LIMIT_GROUP_ORDER_STATUS = Arrays.asList(100L,101L);
+	/**已支付的订单状态*/
+	public static final List<Long> PAYED_ORDER_STATUS = Arrays.asList(100L,101L,103L,104L,105L,106L,301L,203L,204L,205L);
+	/** 支付成功的订单状态 **/
+	public static final List<Long> PAYED_SUCCESS_STATUS = Arrays.asList(101L, 102L, 103L, 104L, 105L, 106L, 301L, 302L);
+	/** 组团成功状态 **/
+	public static final List<Long> GROUP_FULL_STATUS = Arrays.asList(203L,204L,205L,2051L,206L,301L);
+	/** 组团公式状态 **/
+	public static final List<Long> GROUP_PUBLIC_STATUS = Arrays.asList(206L,301L);
+	/**商户积分*/
+	public static final String POINT_TYPE_MERCHANT="merchant";
+	/**平台积分*/
+	public static final String POINT_TYPE_COMMON="common";
+	/**商城购物积分*/
+	public static final String POINT_TYPE_GOODS="goods";
+	/**积分消耗*/
+	public static final String POINT_TYPE_COMMON_SUB="common_sub";
+	/**积分活动*/
+	public static final String POINT_TYPE_COMMON_AVT="common_act";
+	public static final String POINT_TYPE_COMMON_AVT_SUB="common_act_sub";
+	/**积分返回*/
+	public static final String POINT_TYPE_COMMON_RETURN="common_return";
+	/**活动积分-SP*/
+	public static final String POINT_TYPE_ACT_SP="SP";
+	/**商城,仅添加记录*/
+	public static final String POINT_TYPE_ADD_RECORD="common_record";
+    public static final String INFO_TEAM_PRICE="info_team_price";
+    public static final String OTHER_STR="OTHER";
+    public static final String TEAM_SIMPLE_NAME="team_simple_name";
+    public static final String INFO_SELECT_TEAM_CACHE="INFO_SELECT_TEAM_CACHE";
+    public static final String INFO_ONLY_TEAM_CACHE="INFO_ONLY_TEAM_CACHE_";
+    public static final String POINT_CHANGE_RMB="point_rmb_rate";
+    /**用户支付类型配置*/
+    public static final String USER_PAY_TYPE_CONFIG="user_pay_type_config";
+	/**订单随机支付类型配置*/
+    public static final String PAY_TYPE_RANDOM_CONFIG="pay_type_random_config";
+    /**每日支付金额统计*/
+    public static final String PAY_AMOUNT_DAY_KEY="pay_amount_day_";
+	/**每日支付次数统计*/
+    public static final String PAY_COUNT_DAY_KEY="pay_count_day_";
+    public static final String PAY_FAIL_COUNT="pay_fail_count";
+    public static final String ENFORCE_FAVE_VERIFY_USER="enforce_fave_verify_user_fail";
+    public static final BigDecimal RMB_ONE_CENT=new BigDecimal("0.01");
+    /**选队转随机*/
+	public static final String INFO_TYPE_TEAM_TO_RANDOM="team_to_random";
+	public static final String INFO_REAL_SOLD_COUNT="info_real_sold_count_";
+	public static final String ALIPAY_MAIN_BF="alipay-main-bf";
+	public static final String WXPAY_MAIN_BF="wxpay-main-bf";
+	public static final String INFO_TEAM_TO_RANDOM_CACHE="info_team_to_random_cache_";
+    public static final String CHINA="china";
+    public static final String IP_CACHE="ip_address_cache";
+    public static final String TEAM_CHANGE_RATE="team_change_rate";
+    public static final String DEFAULT_PAY_TYPE="alipay";
+    public static final String ADD="add";
+    public static final String SUB="sub";
+    public static final String ORDER_PAY_FAIL_COUNT="ORDER_PAY_FAIL_COUNT";
+    public static final String EVALUATION_LEVEL_MIDDLE="middle";
+    public static final String EVALUATION_LEVEL_BAD="bad";
+    public static final String EVALUATION_LEVEL_GOOD="good";
+    public static final String GUESS_GOODS_CACHE="guess_goods_cache_";
+    public static final String URL_LIMIT_COUNT="url_limit_count";
+    //组团详情
+    public static final String BEHAVIOR_TYPE_PV_INFO="pv_info";
+    //商品详情
+    public static final String BEHAVIOR_TYPE_PV_GOODS="pv_goods";
+    //直播
+    public static final String BEHAVIOR_TYPE_LIVING="living";
+    //组团搜索
+    public static final String BEHAVIOR_TYPE_SEARCH_INFO="search_info";
+    //商品搜索
+    public static final String BEHAVIOR_TYPE_SEARCH_GOODS="search_goods";
+	//关注
+	public static final String FANS_TYPE_USER_LIKE="user_like";
+	//用户拉黑
+	public static final String FANS_TYPE_USER_DISLIKE="user_dislike";
+	//商家拉黑
+	public static final String FANS_TYPE_MERCHANT_DISLIKE="merchant_dislike";
+	/**卡种字典表记录id*/
+	public static final String INFO_SETS_RECORD_ID="info_sets_record_id";
+	/**用户下单分布式key,同一时间仅能提交一种订单*/
+	public static final String GROUP_ORDER_LOCK="group_order_lock_";
+	/**AES秘钥*/
+	public static final String AES_TOKEN_PASSWORD="C19CF02FC6A2040FC9A16BA5161F2D17";
+	/**抢购token*/
+	public static final String AES_TOKEN_CACHE="AES_TOKEN_CACHE";
+	public static final String ACT_USER_TOKEN_CACHE="ACT_USER_TOKEN_CACHE";
+	public static final String ASYNC_ORDER_USER_TOKEN_CACHE="ASYNC_ORDER_USER_TOKEN:";
+	public static final String ORDER_EXPIRE_TIME="order_expire_time_";
+	/**卡单用户限制*/
+	public static final String ORDER_LIMIT_USER="order_limit_user";
+	/**订单子类型,赠送订单接收*/
+	public static final String ORDER_SUB_TYPE_RECEIVE="receive";
+	/**订单子类型,赠送订单:赠送*/
+	public static final String ORDER_SUB_TYPE_GIVE_AWAY="give_away";
+	public static final String SKU_COUPON_ID_CACHE="sku_coupon_id_cache";
+	/**秒级别-半小时*/
+	public static final int HALF_AN_HOUR = 30*60;
+	/**秒级别-1小时*/
+	public static final int ONE_HOUR = 60*60;
+	/**优惠劵使用域*/
+	public static final String COUPON_SCOPE_CONFIG = "coupon_scope_config_";
+	public static final String COUPON_SCOPE_CONFIG_CACHE = "coupon_scope_config_cache_";
+	/**支付类型*/
+	public static final String PAYMENT_TYPE = "payment_type";
+
+	public static final String DAY = "day";
+	public static final String HOUR = "hour";
+
+	public static final String DEFAULT_STR = "default";
+	/**发票类型,个人*/
+	public static final String INVOICE_TYPE_PERSON = "person";
+	/**发票类型,企业*/
+	public static final String INVOICE_TYPE_COMPANY = "company";
+
+	public static final BigDecimal HUNDRED = new BigDecimal("100");
+	public static final BigDecimal TEN = new BigDecimal("10");
+	/**sku库存key*/
+	public static final String SKU_STOCK_PRE = "sku_stock_";
+	/**卡密来源-商城*/
+	public static final String GOODS_REF_TYPE_GOODS=COUPON_TYPE_GOODS;
+	/**卡密来源-组团*/
+	public static final String GOODS_REF_TYPE_GROUP=PUSH_ACCEPT_TYPE_GROUP;
+	/**互相拉黑状态*/
+	public static final String[] DISLIKE_TYPE={Constants.FANS_TYPE_MERCHANT_DISLIKE,Constants.FANS_TYPE_USER_DISLIKE};
+
+	/**随买随机分配卡密*/
+	public static final String GROUP_RANDOM_ALL = "random_all";
+	/**选队随机*/
+	public static final String GROUP_RANDOM_SELECT_TEAM = "random_select_team";
+	/**选队,区域随机*/
+	public static final String GROUP_RANDOM_SELECT_CONFERENCE = "random_select_conference";
+	/**选队/区域转随机*/
+	public static final String GROUP_RANDOM_SELECT_TO_RANDOM = "select_to_random";
+	/**买队,无随机 */
+	public static final String GROUP_RANDOM_BUY_TEAM = "random_buy_team";
+	/**组满随机,暂不存在*/
+	public static final String GROUP_RANDOM_FULL_ALL = "random_full_all";
+	/**买队转随机,暂不存在*/
+	public static final String GROUP_RANDOM_BUY_TEAM_ALL = "random_buy_team_all";
+
+	/**鸿运系列积分-lucky_point*/
+	public static final String POINT_TYPE_ACT_LUCKY="lucky_point";
+	public static final String LUCKY_POINT_AMOUNT_LIMIT="lucky_point_amount";
+
+	public static final String addressRegex = "((?<province>[^省]+省|.+自治区)|上海市|北京市|天津市|重庆市)(?<city>[^市]+市|.+自治州|.+区)?(?<country>[^县]+县|.+市|.+区|.+镇|.+局)?(?<town>[^区]+区|.+镇)?(?<village>.*)";
+	// 默认头像
+	public static final String DEFAULT_AVATAR = "https://static.public.hobbystock.cn/applet/share/share_logo2.png";
+
+	/** 用户标签:高频 */
+	public static final String APP_USER_CAT_HIGH_FREQUENCY="high_frequency";
+
+	public static final String REMOTE_SHIPPING_FEE = "remote_shipping_fee";
+
+	/** 秒杀组队 */
+	public static final String GROUP_ACT_TYPE_SECKILL="group_act_seckill";
+	/** 异步秒杀,异步下单 */
+	public static final String GOODS_ASYNC_SEC_KILL="goods_async_sec_kill";
+
+	public static final String APP_CACHE_USER_NOTIFY_CONFIG = "app_cache_user_notify_config_";
+
+	/**消息类型*/
+	public static final String APP_NOTIFY_TYPE_CONFIG = "app_notify_type_config";
+
+	public static final String APP_NOTIFY_TEMPLATE = "app_notify_template";
+
+	public static final String CHAT_TO_PERSONAL = "chat_to_personal";
+
+	public static final String TEXT = "TEXT";
+
+	public static final List<String> NOTIFY_SAME_SUB_TYPE = Arrays.asList("WIN","PAY_RETURN","GROUP_FAIL","GROUP_ORDER_FAIL");
+
+	public static final String GROUP_STOCK_TYPE = "group_stock_type";
+
+	public static final String PART_COUPON = "part_coupon";
+
+	//进度优惠券的subtype
+	public static final String COUPON_PROGRESS_SUBTYPE = "progress";
+	//精美卡片订单
+	public static final String ORDER_TYPE_GIFT_CARD = "gift_card";
+
+	/*
+	 * 订单风险违规类型:拼团内地24-72小时 domestic24
+     * 拼团港澳台/海外15-30天 oversea15
+     * 拼团即将超时24-48小时 pickup24
+     * 拼团内地>72小时 domestic72
+     * 拼团港澳台/海外>30天 oversea30
+     * 拼团物流轨迹时间异常 fake
+     * 拼团未揽收>48小时 pickup48
+	 */
+	public static final List<String> REQ_ORDER_PENDING = Arrays.asList("domestic24", "domestic72", "oversea15", "oversea30");
+
+	public static final List<String> REQ_ORDER_PICKUP = Arrays.asList("pickup24", "pickup48", "fake");
+
+	/*
+	 * 拼团超时直播:
+	 * groupLiveTimeout24 超时直播24-48
+	 * groupLiveTimeout48 超时直播>48
+	 */
+	public static final List<String> REQ_LIVE_TIMEOUT = Arrays.asList("groupLiveTimeout24", "groupLiveTimeout48");
+
+	/**
+	 * 预售超时直播
+	 * timeout24 预售直播超时24-72
+	 * timeout72 预售直播超时>72
+	 */
+	public static final List<String> REQ_PRESALE_TIMEOUT = Arrays.asList("timeout24", "timeout72");
+
+ 	/*
+	 * 超时公示类型:
+	 * reportTimeout24 超时公示24-48
+	 * reportTimeout48 超时公示>48
+	 */
+	public static final List<String> REQ_REPORT_TIMEOUT = Arrays.asList("reportTimeout24", "reportTimeout48");
+
+
+	public static final String MERCHANT_POINT_SHOW = "merchant_point_show";
+	/**商家活动前缀*/
+	public static final String POINT_TYPE_MERCHANT_ACT_PRE="mer_act";
+	/**预售*/
+	public static final String SOLD_PRE_SALE="pre_sale";
+	/**预订*/
+	public static final String SOLD_PRE_BOOK="pre_book";
+	/**支付编号对应订单*/
+	public static final String PAY_TRADE_NO_TO_ORDER = "pay_trade_no_to_order";
+	/**通用拼豆优惠劵类型*/
+	public static final String COUPON_POINT_TYPE_COMMON = "hb_act_common";
+	/**会员折扣权益*/
+	public static final String MEMBER_GOODS_DISCOUNT = "goods_discount";
+	/**订单异步请求记录*/
+	public static final String ORDER_ASYNC_REQ_RECORD_SET="order_async_req_record";
+	public static final String ORDER_ASYNC_RECORD_LOCK_KEY="order_async_record_lock";
+	public static final String ORDER_ASYNC_RECORD_EXIST_KEY="order_async_record_exist";
+	/**订单异步处理key*/
+	public static final String ORDER_ASYNC_PROCESS_LOCK="order_async_process_lock";
+	public static final String ORDER_ASYNC_PROCESS_EXIST="order_async_process_exist";
+
+	public static final String PAY_TYPE_COUPON="优惠劵";
+	/**免运费权益*/
+	public static final String BENEFIT_TYPE_SHIPPING_FREE="shipping_free";
+
+	public static final String PRIORITY_MEMBER = "member";
+	public static final String PRIORITY_GROUP_AMOUNT_ACT = "group_amount_act";
+	/**销售限制商家*/
+	public static final String sales_blocking_merchants = "sales_blocking_merchants";
+	/**拼团组齐标记*/
+	public static final String group_full_flag_pre = "group_full_flag";
+	/**不可使用优惠劵*/
+	public static String NO_COUPON_ACT_TYPE = "no_coupon_act_type";
+	public static String LIMIT_GROUP_POINT_BY_SKU = "limit_group_point_by_sku";
+	/**用户消费限额配置*/
+	public static final String USER_LIMIT_PAY_CONFIG = "user_limit_pay_config";
+	public static final String USER_CAT_UNPAYED_LIMIT = "unpayed_limit";
+	/**生态购商品标记*/
+	public static final String GROUP_SALE_CODE = "group_sale_code";
+	/**直播间点赞key*/
+	public static final String LIVING_ROOM_LIKE_KEY="living_room_like_key:";
+	/**商家发货锁单*/
+	public static final String REDIS_KEY_MERCHANT_DELIVERY_LOCK = "merchant_delivery_lock:";
+}

+ 109 - 0
poyee-common/src/main/java/com/poyee/constant/MqConstans.java

@@ -0,0 +1,109 @@
+package com.poyee.constant;
+
+import lombok.Data;
+
+@Data
+public class MqConstans {
+    public static final String TEST_QUEUE="queue_test";
+    /**订单回调队列*/
+    public static final String QUEUE_ORDER_PAY_CALLBACK="queue_order_pay_callback";
+    /**订单回调交换机*/
+    public static final String EXCHANGE_ORDER_PAY_CALLBACK="exchange_order_pay_callback";
+    /**订单回调key*/
+    public static final String ROUTING_KEY_CALLBACK="callback";
+
+    /**回调前置队列*/
+    public static final String QUEUE_PRE_PAY_CALLBACK="queue_pre_pay_callback";
+    /**回调前置交换机*/
+    public static final String EXCHANGE_PRE_PAY_CALLBACK="exchange_pre_pay_callback";
+    /**回调前置key*/
+    public static final String ROUTING_KEY_PRE_CALLBACK="pre_callback";
+
+    /**订单过期队列*/
+    public static final String QUEUE_ORDER_EXPIRED="queue_order_expired";
+    /**订单延时交换机*/
+    public static final String EXCHANGE_DELAYED_ORDER_EXPIRED="exchange_delayed_order_expired";
+    /**订单延时key*/
+    public static final String ROUTING_KEY_ORDER_EXPIRED="order_expired";
+
+
+    /**订单成功后队列*/
+    public static final String QUEUE_ORDER_SUCCESS="queue_order_success";
+    /**订单成功交换机*/
+    public static final String EXCHANGE_ORDER_SUCCESS="exchange_order_success";
+    /**订单成功key*/
+    public static final String ROUTING_KEY_ORDER_SUCCESS="order_success";
+
+    /**用户行为队列*/
+    public static final String QUEUE_USER_BEHAVIOR="queue_user_behavior";
+    /**用户行为交换机*/
+    public static final String EXCHANGE_USER_BEHAVIOR="exchange_user_behavior";
+    /**用户行为key*/
+    public static final String ROUTING_KEY_USER_BEHAVIOR="user_behavior";
+
+    /**用户积分队列*/
+    public static final String QUEUE_USER_POINT="queue_user_point";
+    /**用户积分交换机*/
+    public static final String EXCHANGE_USER_POINT="exchange_user_point";
+    /**用户积分key*/
+    public static final String ROUTING_KEY_USER_POINT="user_point";
+
+    /**订单退款队列*/
+    public static final String QUEUE_ORDER_REFUND="queue_order_refund";
+    /**订单退款交换机*/
+    public static final String EXCHANGE_ORDER_REFUND="exchange_order_refund";
+    /**订单退款key*/
+    public static final String ROUTING_KEY_ORDER_REFUND="order_refund";
+
+    /**组团成功队列*/
+    public static final String QUEUE_GROUP_FULL="queue_group_full";
+    /**组团成功交换机*/
+    public static final String EXCHANGE_GROUP_FULL="exchange_group_full";
+    /**组团成功key*/
+    public static final String ROUTING_KEY_GROUP_FULL="group_full";
+
+    /**组团排序队列*/
+    public static final String QUEUE_GROUP_SORT_UPDATE="queue_group_sort_update";
+    /**组团排序交换机*/
+    public static final String EXCHANGE_GROUP_SORT_UPDATE="exchange_group_sort_update";
+    /**组团排序key*/
+    public static final String ROUTING_KEY_GROUP_SORT_UPDATE="group_sort_update";
+
+    /**商品sku库存队列*/
+    public static final String QUEUE_SKU_STOCK_UPDATE="queue_sku_stock_update";
+    public static final String QUEUE_SKU_STOCK_UPDATE_NEW="queue_sku_stock_update_new";
+    /**商品sku库存修改交换机*/
+    public static final String EXCHANGE_SKU_STOCK_UPDATE="exchange_sku_stock_update";
+    /**商品sku库存修改key*/
+    public static final String ROUTING_KEY_SKU_STOCK_UPDATE="sku_stock_update";
+
+    /**用户中卡同步队列*/
+    public static final String QUEUE_SYNC_USER_WIN_CARD="queue_sync_user_win_card";
+    /**用户中卡同步交换机*/
+    public static final String EXCHANGE_SYNC_USER_WIN_CARD="exchange_gsync_user_win_card";
+    /**用户中卡同步 key*/
+    public static final String ROUTING_KEY_SYNC_USER_WIN_CARD="sync_user_win_card";
+
+    /**直播间奖品和连麦相关信息*/
+    public static final String QUEUE_APP_LIVE_CONFIG="queue_app_live_config";
+    /**直播间奖品和连麦相关信息交换机*/
+    public static final String EXCHANGE_DELAYED_APP_LIVE_CONFIG="exchange_delayed_app_live_config";
+    /**直播间奖品和连麦相关信息key*/
+    public static final String ROUTING_KEY_APP_LIVE_CONFIG="app_live_config";
+
+    /**用户积分队列-json格式*/
+    public static final String QUEUE_USER_POINT_JSON="queue_user_point_json";
+    /**用户积分key-json格式*/
+    public static final String ROUTING_KEY_USER_POINT_JSON="user_point_json";
+    /**异步处理订单队列*/
+    public static final String QUEUE_ASYNC_ORDER_PROCESS="queue_async_order_process";
+
+    /**订单分析队列*/
+    public static final String QUEUE_ORDER_PARSING="queue_order_parsing";
+    /**订单分析交换机*/
+    public static final String EXCHANGE_DELAYED_ORDER_PARSING="exchange_delayed_order_parsing";
+    /**订单分析key*/
+    public static final String ROUTING_KEY_ORDER_PARSING="order_parsing";
+
+
+}

+ 53 - 0
poyee-common/src/main/java/com/poyee/constant/NoticeMsgModel.java

@@ -0,0 +1,53 @@
+package com.poyee.constant;
+
+/**
+ * @author by po'yi
+ * @Classname NoticeMsgModel
+ * @Description 站内信消息模板
+ * @Date 2022/11/3 15:50
+ */
+public class NoticeMsgModel {
+
+	public static void main(String[] args) {
+		System.out.println( String.format(NoticeMsgModel.GOODS_SEND_OUT, "test111"));
+	}
+
+	/**
+	 * 商家同意退款
+	 * param:商品名称
+	 * */
+	public static String ORDER_REFUND_AGREE="您购买的【%s】退款申请商家已通过,退款金额正在处理中!";
+	/**
+	 * 商家拒绝退款
+	 * param1:购买商品
+	 * param2:拒绝理由
+	 * */
+	public static String ORDER_REFUND_REFUSE="您购买的【%s】退款申请商家已拒绝,拒绝理由:【%s】";
+	/**
+	 * 商家同意地址修改
+	 * param:商品名称
+	 * */
+	public static String EDIT_ADDR_AGREE="您购买的【%s】修改地址申请商家已通过!";
+	/**
+	 * 商家拒绝地址修改
+	 * param:商品名称
+	 * */
+	public static String EDIT_ADDR_REFUSE="您购买的【%s】修改地址申请商家已拒绝!";
+	/**
+	 * 用户申请修改地址
+	 * param1:用户昵称
+	 * param2:商品名称
+	 * */
+	public static String EDIT_ADDR_APPLY="【%s】购买的【%s】申请修改地址,请尽快处理!";
+	/**
+	 * 商家发货通知
+	 * param:商品名称
+	 * */
+	public static String GOODS_SEND_OUT="您购买的【%s】已发货!";
+	/**
+	 * 商家发货通知
+	 * param:商品名称
+	 * */
+	public static String GOODS_WAITING_SHIPPING="您购买的【%s】拆卡报告已更新,等待商家发货!";
+	public static String USER_PAY_LIMIT_NOTICE="【您本月已消费%s元,达到了消费限额。如有问题请联系平台客服】";
+}

+ 68 - 0
poyee-common/src/main/java/com/poyee/constant/NoticeType.java

@@ -0,0 +1,68 @@
+package com.poyee.constant;
+
+/**
+ * 通知类型
+ */
+public class NoticeType {
+    /**
+     * 支付成功 PAY_SUCCESS
+     */
+    public static String PAY_SUCCESS = "PAY_SUCCESS";
+    /**
+     * 退款 PAY_RETURN
+     */
+    public static String PAY_RETURN = "PAY_RETURN";
+    /**
+     * 众筹组满 GROUP_FULL
+     */
+    public static String GROUP_FULL = "GROUP_FULL";
+    /**
+     * 众筹失败 GROUP_FAIL
+     */
+    public static String GROUP_FAIL = "GROUP_FAIL";
+    /**
+     * 众筹失败(订单) GROUP_ORDER_FAIL
+     */
+    public static String GROUP_ORDER_FAIL = "GROUP_ORDER_FAIL";
+    /**
+     * 直播开始 LIVE_BEGIN
+     */
+    public static String LIVE_BEGIN = "LIVE_BEGIN";
+    /**
+     * 公示 PUBLICITY
+     */
+    public static String PUBLICITY = "PUBLICITY";
+    /**
+     * 中卡 WIN
+     */
+    public static String WIN = "WIN";
+    /**
+     * 发货 SEND_EXPRESS
+     */
+    public static String SEND_EXPRESS = "SEND_EXPRESS";
+    /**
+     * 系统通知 SYSTEM
+     */
+    public static String SYSTEM = "SYSTEM";
+    /**
+     * 订单相关 ORDER
+     */
+    public static String ORDER = "ORDER";
+
+    //组队详情页
+    public static String group_detail_url = "/pageB/productDetail/productDetail?id=";
+    //订单详情页
+    public static String order_detail_url = "/pageC/myPages/myOrderDetail?id=";
+    //商家管理地址申请
+    public static final String MERCHANT_ADDR_PAGE = "/pageC/shopingShop/merchantDismantleRetreat?numType=5&type=merchant&typeName=收货地址修改审核";
+
+    public static final String MERCHANT_ADDR_GROUP_PAGE = "/pageC/shopingShop/merchantDismantleRetreat?numType=7&type=merchant&typeName=地址修改审核";
+
+    public static final String COUPON_URL = "/pageC/myPages/myCoupon";
+
+    public static final String COUPON_URL_NEW = "/pageC/myCoupon/couponList";
+
+    public static final String ORDER_SHOP_URL = "/pageG/myOrder/myOrderDetail?orderId=";
+
+    public static final String ORDER_SHOP_URL_NEW = "/pageC/shoppingUser/myOrderDetials?id=";
+}

+ 34 - 0
poyee-common/src/main/java/com/poyee/constant/UserType.java

@@ -0,0 +1,34 @@
+package com.poyee.constant;
+
+import com.poyee.dto.InDto;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class UserType {
+    //微信公众号
+    public static String WX_WEB = "WX_WEB";
+    //微信小程序
+    public static String WX_APPLET = "WX_APPLET";
+    //第三方
+    public static String THIRD = "THIRD";
+    //第三方-安卓
+    public static String THIRD_APK = "THIRD_APK";
+    //第三方-ios
+    public static String THIRD_APP = "THIRD_APP";
+    //苹果授权登陆
+    public static String APPLE_AUTH = "APPLE_AUTH";
+    //微信授权登陆
+    public static String WX_AUTH = "WX_AUTH";
+    //角色
+    public static final String USER_ROLE_SHIPPING = "shipping";
+    public static final String USER_ROLE_GENERAL_USER = "general_user";
+    public static final String USER_ROLE_ADMIN = "admin";
+    public static final String USER_ROLE_LIVING = "living";
+
+    // 拼团 publicity
+    public static final String USER_ROLE_PUBLICITY = "merchant_sub_publicity";
+    // 物流 delivery
+    public static final String USER_ROLE_DELIVERY = "merchant_sub_delivery";
+
+
+}

+ 97 - 0
poyee-common/src/main/java/com/poyee/dto/AppUserInfoDto.java

@@ -0,0 +1,97 @@
+package com.poyee.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class AppUserInfoDto implements Serializable {
+    private static final long serializableUID = 1L;
+    //id
+    private Long id;
+    //openid
+    private String openid;
+    //unionid
+    private String unionid;
+    //账号
+    private String account;
+    //真实姓名
+    private String realname;
+    //昵称
+    private String nickname;
+    private String username;
+    //头像
+    private String avatar;
+    //会员等级
+    private Integer level;
+    //积分
+    private Long point;
+    //手机号
+    private String phone;
+    //邮箱
+    private String email;
+    //角色id
+    private Integer roleId;
+    //角色编码
+    private String roleCode;
+    //注册时间
+    private Date registerTime;
+    //注册渠道(用户类型) WX_WEB = 公众号, WX_APPLET = 小程序 , THIRD = 第三方
+    private String registerChannel;
+    //会员成长值
+    private Long growthNum;
+    //会员码
+    private String code;
+    /**是否接受通知*/
+    private Integer notifyFlag;
+    /**极光推送*/
+    private String smsRegisterId;
+    private String notifyType;
+    private Integer faceVerify;
+    /**支付开关,1开启,0关闭*/
+
+    private Integer openPsd;
+    /**支付密码*/
+    @JsonIgnore
+    private String loginPsd;
+    /**登陆密码*/
+    @JsonIgnore
+    private String payPsd;
+    private Boolean payPsdExist;
+    private Boolean loginPsdExist;
+    private Integer refusePickUp;
+    private Integer num;
+    /**限额额度,默认1万,prop1字段*/
+    private String payAmountOfDay;
+    /**开启限额,prop2字段*/
+    private String openPayAmount;
+    /**悬浮窗口开关*/
+    private Integer windowOpen;
+    /**身份证*/
+    private String certName;
+    /**阿里账户*/
+    private String alipayAccount;
+    /**1删除*/
+    private Integer delFlg;
+    /**1开票权限*/
+    private Integer openInvoice;
+    /**用户状态,正常:0,锁定:1,限购:2*/
+    private Integer accountStatus;
+    /**会员等级*/
+    private Integer memberLevel;
+    /**会员名称*/
+    private String memberName;
+    /**当月已获取成长值*/
+    private Integer currentMonthGrowth;
+    /**月初初始化标志,默认0:未开始,1:已初始化*/
+    private Integer memberInitFlag;
+    /**当前会员保级所需成长值*/
+    private Integer memberKeepGrowth;
+    private Boolean payInfoFlag;
+    //月消费限额
+    private int monthlyLimit;
+}

+ 11 - 0
poyee-common/src/main/java/com/poyee/dto/CMemberDiscountDTO.java

@@ -0,0 +1,11 @@
+package com.poyee.dto;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+public class CMemberDiscountDTO {
+    private BigDecimal discount;
+    private Integer merchantGroupId;
+}

+ 20 - 0
poyee-common/src/main/java/com/poyee/dto/ChildDTO.java

@@ -0,0 +1,20 @@
+package com.poyee.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @Classname ChildDTO
+ * @Description TODO
+ * @Date 2024/1/18 11:07
+ * @Created by Administrator
+ */
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ChildDTO implements Serializable {
+    private String name;
+    private String idCard;
+    private String birStr;
+}

+ 19 - 0
poyee-common/src/main/java/com/poyee/dto/CountNumDTO.java

@@ -0,0 +1,19 @@
+package com.poyee.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+@AllArgsConstructor
+@NoArgsConstructor
+public class CountNumDTO implements Serializable {
+	/**聚合类型*/
+	private String type;
+	/**数量*/
+	private long num;
+}

+ 48 - 0
poyee-common/src/main/java/com/poyee/dto/CouponCatDTO.java

@@ -0,0 +1,48 @@
+package com.poyee.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class CouponCatDTO implements Serializable {
+	public static final String COUPON_TYPE_GROUP="group";
+	public static final String COUPON_TYPE_GOODS="goods";
+	public static final String COUPON_TYPE_SETS="sets";
+	public static final String COUPON_TYPE_INFO_TYPE="infoType";
+	public static final String COUPON_TYPE_MERCHANTS="merchants";
+	public static final String COUPON_TYPE_SETS_NEW="sets_new";
+	public static final String COUPON_TYPE_PANINI_SETS="panini_sets";
+	public static final String COUPON_TYPE_HB_ACT_COMMON="hb_act_common";
+	//生态购货源保障
+	public static final String COUPON_SUB_TYPE_SALE_CODE="group_sale_code";
+	// 品牌券
+	public static final String BRAND_MEMBER_MERCHANTS = "brand_member_merchants";
+	// 指定panini_checklist优惠券
+	public static final String COUPON_SUB_TYPE_PANINI_CHECKLIST = "panini_checklist";
+	/**类型:group:指定组团,有id,sets:系列,infoType:玩法*/
+	private String type;
+	//货源保障:group_sale_code
+	private String subType;
+	//版本
+	private String setVersion;
+	// 厂商
+	private String manufacturer;
+	// 运动类型
+	private String sport;
+	/**组团id*/
+	private Integer id;
+	/**系列或者玩法名*/
+	private String name;
+
+	private List<CouponCatDTO> catList;
+
+	// 商城券指定paninilistId 和 版本
+	private Long paniniListId;
+	private String paniniListName;
+	private String paniniListSport;
+	private String paniniListVersion;
+}

+ 53 - 0
poyee-common/src/main/java/com/poyee/dto/CouponInfoDTO.java

@@ -0,0 +1,53 @@
+package com.poyee.dto;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+public class CouponInfoDTO {
+    //记录id
+    private Long id;
+    //用户id
+    private Long userId;
+    //卡券id
+    private Long cardId;
+    //卡券名称
+    private String cardName;
+    //使用订单id
+    private Long orderId;
+    //状态 0= 未使用 1= 已使用 2= 已过期
+    private String status;
+    //折扣金额 满减券/代金券的优惠金额
+    private BigDecimal discount;
+    //卡券类型:满减券,折扣券,代金券
+    private String category;
+    //折扣率 折扣券的折扣率
+    private String discountRate;
+    //满减金额 :满减券 需达到这个金额 才能进行优惠
+    private BigDecimal fullMinusDiscount;
+    //使用限制:商品限制
+    private String useCategory;
+    //有效时间-开始时间
+    private Date useStartTime;
+    //有效时间-结束时间
+    private Date useEndTime;
+    //使用范围:订单,组团...card,goods
+    private String useScope;
+    //过期时间
+    private Date expiryTime;
+    private Integer merchantId;
+    private String fromCategory;
+    private String merchantName;
+    private String merchantAvatar;
+    private String actType;
+    private String sport;
+    // '结算类型:1 平台,2 商家';
+    private Integer settlementCategory;
+    /**兑换积分类型*/
+    private String pointType;
+    private String specialActType;
+    private Long sourceId;
+    private String sourceType;
+}

+ 16 - 0
poyee-common/src/main/java/com/poyee/dto/CouponProgressDTO.java

@@ -0,0 +1,16 @@
+package com.poyee.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class CouponProgressDTO implements Serializable {
+	private String type;
+	private String subType;
+	private Integer progressStart;
+	private Integer progressEnd;
+}

+ 17 - 0
poyee-common/src/main/java/com/poyee/dto/CourierDTO.java

@@ -0,0 +1,17 @@
+package com.poyee.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class CourierDTO implements Serializable {
+	/** 物流公司 */
+	private String courierCompany;
+	/** 物流编码 */
+	private String courierNum;
+}

+ 30 - 0
poyee-common/src/main/java/com/poyee/dto/GroupSaleCodeDTO.java

@@ -0,0 +1,30 @@
+package com.poyee.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+@AllArgsConstructor
+@NoArgsConstructor
+public class GroupSaleCodeDTO implements Serializable {
+    // 箱:CARTON;盒:BOX,包:PACK
+    private String boxType;
+    // 数量
+    private int boxNum;
+    private boolean hasBoxConfig;
+
+    public GroupSaleCodeDTO(boolean hasBoxConfig) {
+        this.hasBoxConfig = hasBoxConfig;
+    }
+
+    public GroupSaleCodeDTO(String boxType, int boxNum) {
+        this.boxType = boxType;
+        this.boxNum = boxNum;
+        hasBoxConfig=true;
+    }
+}

+ 125 - 0
poyee-common/src/main/java/com/poyee/dto/InDto.java

@@ -0,0 +1,125 @@
+package com.poyee.dto;
+
+import com.poyee.exception.ServiceException;
+import com.poyee.utils.DozerUtils;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.util.CollectionUtils;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 接口入参
+ */
+@Data
+@Slf4j
+public class InDto implements Serializable {
+    private static final long serialVersionUID = 1L;
+    //appid
+    private String appid;
+    //openid
+    private String openid;
+    //unionid
+    private String unionid;
+    //用户类型: WX_WEB (微信公众号) WX_APPLET (微信小程序) THIRD (第三方) WX_AUTH(微信授权登陆)
+    private String userType;
+    //userid
+    private Integer userId;
+    //账号
+    private String username;
+    //每页数据条数
+    private Integer pageSize = 10;
+    //页码数
+    private Integer pageNo = 1;
+    //其他数据
+    private Map<String,Object> data;
+    //部门id
+    private Integer departId;
+
+    private Integer offset;
+
+    private long timestamp;
+
+    private String version;
+    // 极光id
+    private String smsRegisterId;
+    //签名
+    private String sign;
+
+    public Object get(String key){
+        if (!CollectionUtils.isEmpty(data)) {
+            return this.data.get(key);
+        }
+        return null;
+    }
+
+    public String getString(String key) {
+        if (!CollectionUtils.isEmpty(data)) {
+            Object v = this.data.get(key);
+            return v != null ? String.valueOf(v) : null;
+        }
+        return null;
+    }
+    public InDto put(String key ,Object value){
+        if(null == this.data) {
+            this.data = new HashMap<>();
+        }
+        this.data.put(key, value);
+        return this;
+    }
+
+    public Integer getPageSize() {
+        return this.pageSize!=null&& this.pageSize>0? this.pageSize:10;
+    }
+
+    public Integer getPageNo() {
+        return this.pageNo!=null&& this.pageNo>0? this.pageNo:1;
+    }
+
+    public Integer getOffset(){
+        return((pageNo) - 1 ) * pageSize;
+    }
+    public Integer getIntegerDefault(String key, Integer value) {
+        if (!CollectionUtils.isEmpty(data)) {
+            Integer ret = (Integer) this.data.get(key);
+            return ret == null ? value : ret;
+        }
+        return value;
+    }
+
+    public Integer getIntegerParam(String key) {
+        if (CollectionUtils.isEmpty(data)) {
+            return null;
+        }
+        return (Integer) this.data.get(key);
+    }
+
+    public boolean getBooleanParam(String key) {
+        if (CollectionUtils.isEmpty(data)) {
+            return false;
+        }
+        Boolean b = (Boolean) this.data.get(key);
+        return b != null && b;
+    }
+
+    /**
+     * 转换indto中data为指定参数
+     *
+     * @param param
+     * @param <T>
+     * @return
+     */
+    public <T> T buildParam( T param) {
+        try {
+            DozerUtils.copy(this.data, param);
+            return param;
+        } catch (Exception e) {
+            log.error("参数转换失败:{}", e);
+        }
+        throw new ServiceException(500, "参数获取失败!");
+    }
+
+
+}

+ 22 - 0
poyee-common/src/main/java/com/poyee/dto/LimitAmountConfig.java

@@ -0,0 +1,22 @@
+package com.poyee.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class LimitAmountConfig implements Serializable {
+    // 新用户限制额度,负数
+    private int newUserAmount;
+    private List<MemberAmount> memberAmount;
+
+    @JsonIgnoreProperties(ignoreUnknown = true)
+    @Data
+    public static class MemberAmount implements Serializable {
+        private int member;
+        private int amount;
+    }
+}

+ 28 - 0
poyee-common/src/main/java/com/poyee/dto/LogParam.java

@@ -0,0 +1,28 @@
+package com.poyee.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class LogParam implements Serializable {
+
+    private String user;
+    /**
+     * 请求方法
+     */
+    private String method;
+    /**
+     * ip
+     */
+    private String ip;
+    /**
+     * url
+     */
+    private String url;
+    /** 发送数据 */
+    private String sendData;
+    /** 返回数据 */
+    private String resultData;
+
+}

+ 98 - 0
poyee-common/src/main/java/com/poyee/dto/NoticeSyncDTO.java

@@ -0,0 +1,98 @@
+package com.poyee.dto;
+
+import com.alibaba.fastjson2.annotation.JSONField;
+import com.poyee.constant.Constants;
+import com.poyee.constant.NoticeType;
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.Serializable;
+
+/**
+ * @author by po'yi
+ * @Classname NoticeSyncDTO
+ * @Description
+ * @Date 2023/8/11 11:23
+ */
+@Data
+public class NoticeSyncDTO implements Serializable {
+	@JSONField(name = "f1")
+	private Long id;
+	@JSONField(name = "f2")
+	private Long toUserId;
+	@JSONField(name = "f3")
+	private String type;
+	@JSONField(name = "f4")
+	private String msg;
+	@JSONField(name = "f5")
+	private String contentUrl;
+	@JSONField(name = "f6")
+	private Long contentId;
+	@JSONField(name = "f7")
+	private Integer templateId;
+	@JSONField(name = "f8")
+	private String subType;
+	@JSONField(name = "f9")
+	private String title;
+
+	public String getSubType() {
+		if (StringUtils.isEmpty(subType) && Constants.NOTIFY_SAME_SUB_TYPE.contains(type.toUpperCase())) {
+			return type;
+		}
+		return subType;
+	}
+
+	public Integer getTemplateId() {
+		if (templateId == null) {
+			String subType2 = getSubType();
+			if (StringUtils.isEmpty(subType2)) {
+				return null;
+			}
+			switch (subType2.toUpperCase()) {
+				case "GROUP_ORDER_FAIL":
+					templateId = 5;
+					break;
+				case "GROUP_FULL_MERCHANT":
+					templateId = 6;
+					break;
+				case "WIN":
+					templateId = 7;
+					break;
+				case "GROUP_FAIL":
+					templateId = 8;
+					break;
+				case "ACT_POINT":
+					templateId = 9;
+					break;
+				case "PAY_RETURN":
+					templateId = 10;
+					break;
+				//case "SALE":
+				//	templateId = 11;
+				//	break;
+				//case "LIVE":
+				//	templateId = 12;
+				//	break;
+				case "ACT_GROUP_MERCHANT":
+					templateId = 13;
+					break;
+			}
+		}
+
+		return templateId;
+	}
+
+	public String getContentUrl() {
+		if(StringUtils.isNotEmpty(contentUrl)){
+			contentUrl=contentUrl.replace(NoticeType.ORDER_SHOP_URL, NoticeType.ORDER_SHOP_URL_NEW)
+					.replace(NoticeType.COUPON_URL,NoticeType.COUPON_URL_NEW);
+		}
+		return contentUrl;
+	}
+	//
+	//public static void main(String[] args) {
+	//	String s =  NoticeType.ORDER_SHOP_URL+"1212313";
+	//	s = s.replace(NoticeType.ORDER_SHOP_URL,"/pageC/shoppingUser/myOrderDetials?id=");
+	//	System.out.println(s);
+	//}
+}

+ 23 - 0
poyee-common/src/main/java/com/poyee/dto/OrderRefundDTO.java

@@ -0,0 +1,23 @@
+package com.poyee.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class OrderRefundDTO implements Serializable {
+	private static final long serialVersionUID = 1L;
+	//订单id
+	private Long orderId ;
+	//订单no
+	private String orderNo ;
+	//退款金额
+	private BigDecimal amount ;
+
+	private String msg ;
+}

+ 194 - 0
poyee-common/src/main/java/com/poyee/dto/OutDTO.java

@@ -0,0 +1,194 @@
+package com.poyee.dto;
+
+import lombok.Data;
+import lombok.ToString;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 输出参数
+ */
+@Data
+@ToString
+public class OutDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+    private boolean success = true;
+
+    private Integer code = 0;
+
+    private String msg = "成功";
+
+    private Map<String ,Object> data;
+    //时间戳
+    private long timestamp = System.currentTimeMillis();
+    //数据总量
+    private Integer total;
+    //每页条数
+    private Integer pageSize = 10;
+    //页码
+    private Integer pageNo = 1;
+    //总页数
+    private Integer pages;
+    //
+    private String roleCode;
+
+    public OutDTO(){}
+
+    public OutDTO(boolean success, Integer code, String msg){
+        this.success =success;
+        this.code = code;
+        this.msg = msg;
+    }
+
+    /**
+     *
+     * @param pageSize 每页条数
+     * @param pageNo 页码
+     * @param total 总量
+     * @return
+     */
+    public OutDTO setCount(Integer pageSize ,Integer pageNo ,Integer total){
+        this.total = total;
+        this.pageSize = pageSize;
+        this.pageNo = pageNo;
+        if(total % pageSize > 0){
+            this.pages = total / pageSize + 1;
+        }else{
+            this.pages = total / pageSize;
+        }
+        return this;
+    }
+
+    /**
+     * @param inDto
+     * @param total
+     * 设置分页
+     * @return
+     */
+    public OutDTO setCount(InDto inDto,Integer total){
+        this.total = total;
+        this.pageSize = inDto.getPageSize();
+        this.pageNo = inDto.getPageNo();
+        if(total % this.pageSize > 0){
+            this.pages = total / this.pageSize + 1;
+        }else{
+            this.pages = total / this.pageSize;
+        }
+        return this;
+    }
+
+    public OutDTO page(InDto inDto,Integer total , String key, List datas){
+        OutDTO outDTO = this.setCount(inDto, total);
+        if(null != datas && datas.size() > 0 ){
+            if(datas.size() >= inDto.getPageSize() * inDto.getPageNo()){
+                datas = datas.subList(inDto.getPageSize() *(inDto.getPageNo()-1),inDto.getPageSize() *inDto.getPageNo() );
+            }else{
+                datas = datas.subList(inDto.getPageSize() *(inDto.getPageNo()-1),datas.size());
+            }
+        }
+        outDTO.put(key,datas);
+        return outDTO;
+    }
+
+    public OutDTO buildPage(InDto inDto,Integer total , String key, List datas){
+        OutDTO outDTO = this.setCount(inDto, total);
+        outDTO.put(key,datas);
+        return outDTO;
+    }
+
+    /**
+     *
+     * @param key
+     * @param value
+     * @return
+     */
+    public OutDTO put(String key,Object value){
+        if(null == this.data) this.data = new HashMap<>();
+        this.data.put(key,value);
+        return this;
+    }
+
+    /**
+     *
+     * @param key
+     * @param value
+     * @return
+     */
+    public OutDTO putString(String key,String value){
+        if(null == this.data) this.data = new HashMap<>();
+        this.data.put(key,value);
+        return this;
+    }
+
+    /**
+     *
+     * @param key
+     * @return
+     */
+    public Object get(String key){
+        if(null != this.data) return this.data.get(key);
+        return null;
+    }
+
+    /**
+     * get String
+     * @param key
+     * @return
+     */
+    public String getString(String key){
+        if(null != this.data)  return (String) this.data.get(key);
+        return null;
+    }
+
+    public static OutDTO ok(){
+        OutDTO outDTO = new OutDTO();
+        outDTO.put("ok","");
+        return outDTO;
+    }
+
+    public static OutDTO ok(String msg) {
+        return new OutDTO(true,200,msg);
+    }
+
+    public static OutDTO ok(Integer code ,String msg){
+        return new OutDTO(true,code,msg);
+    }
+
+    public static OutDTO ok(Map data) {
+        OutDTO r = new OutDTO();
+        r.setData(data);
+        return r;
+    }
+
+    /**
+     * 失败
+     * @param code
+     * @param msg
+     * @return
+     */
+    public static OutDTO error(Integer code,String msg){
+        return new OutDTO(false,code,msg);
+    }
+
+    /**
+     *
+     * @param message
+     * @return
+     */
+    public static OutDTO error500(String message) {
+        return new OutDTO(false,500,message);
+    }
+
+    /**
+     * 无权限访问返回结果
+     */
+    public static OutDTO noauth(String msg) {
+        return error(510, msg);
+    }
+
+
+
+}

+ 12 - 0
poyee-common/src/main/java/com/poyee/dto/PaniniCheckListBaseInfoDTO.java

@@ -0,0 +1,12 @@
+package com.poyee.dto;
+
+import lombok.Data;
+
+@Data
+public class PaniniCheckListBaseInfoDTO {
+    private Long paniniCheckListId;
+    private String year;
+    private String manufacturer;
+    private String sport;
+    private String sets;
+}

+ 92 - 0
poyee-common/src/main/java/com/poyee/dto/ResultDTO.java

@@ -0,0 +1,92 @@
+/**
+ *
+ */
+package com.poyee.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 控制层统一返回数据格式
+ *
+ * @author poyee
+ *
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Accessors(chain = true)
+public class ResultDTO implements Serializable {
+	/** 状态码 成功: 0 */
+	public static final int RESPCODE_SUCCESS = 0;
+	/** 状态码 失败: 1 */
+	public static final int RESPCODE_FAILURE = 1;
+	/** 权限不足 */
+	public static final int RESPCODE_NO_AUTH = -1;
+	/**返回成功信息*/
+	public static final String MSG_SUCCESS = "OK";
+	/** 失败信息FAIL */
+	public static final String MSG_FAIL = "FAIL";
+	/**权限不足返回信息*/
+	public static final String MSG_NO_AUTH = "权限不足";
+
+	/** 返回码 */
+	private int code;
+	/** 返回信息 */
+	private String msg;
+	/** 返回数据 */
+	private Object data;
+	/** 时间戳 */
+	private Long timestamp=System.currentTimeMillis();
+
+	public ResultDTO(int code, String msg, Object data) {
+		this.code = code;
+		this.msg = msg;
+		this.data = data;
+	}
+
+	/**
+	 * 构造错误result
+	 *
+	 * @return
+	 */
+	public static ResultDTO buildErrorResult() {
+		return new ResultDTO(RESPCODE_FAILURE, MSG_FAIL, null);
+	}
+
+	/**
+	 * 构造空result
+	 *
+	 * @return 200 ok
+	 */
+	public static ResultDTO buildEmptySuccess() {
+		return new ResultDTO(RESPCODE_SUCCESS, MSG_SUCCESS, null);
+	}
+
+	/**
+	 * 构造错误result
+	 *
+	 * @return
+	 */
+	public static ResultDTO buildErrorResult(String msg) {
+		return new ResultDTO(RESPCODE_FAILURE, msg, null);
+	}
+
+
+	public static ResultDTO buildErrorResult(int code,String msg) {
+		return new ResultDTO(code, msg, null);
+	}
+
+	public static ResultDTO build500Error(String msg) {
+		return new ResultDTO(500, msg, null);
+	}
+
+	public static ResultDTO buildSuccessResult(Object o) {
+		return new ResultDTO(RESPCODE_SUCCESS, MSG_SUCCESS, o);
+	}
+
+}

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

@@ -0,0 +1,14 @@
+package com.poyee.dto;
+
+public class ResultMsg {
+
+    public static final String OPEARTE_SUCCESS = "操作成功";
+    public static final String UPDATE_SUCCESS = "修改成功";
+    public static final String DELETE_SUCCESS = "删除成功";
+    public static final String REVIEW_SUCCESS = "审核成功";
+
+    public static final String OPEARTE_FAIL = "操作失败";
+    public static final String UPDATE_FAIL = "修改失败";
+    public static final String DELETE_FAIL = "删除失败";
+    public static final String REVIEW_FAIL = "审核失败";
+}

+ 46 - 0
poyee-common/src/main/java/com/poyee/dto/StockParam.java

@@ -0,0 +1,46 @@
+package com.poyee.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @Classname StockParam
+ * @Description 库存,售卖数量变动
+ * @Date 2024/7/18 15:07
+ * @Created by Administrator
+ */
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+@NoArgsConstructor
+public class StockParam implements Serializable {
+    public final static String STOCK_SUB_TYPE_ORDER = "order";
+    public final static String SKU_NUM_TYPE_SOLD = "sold_num";
+    public final static String SKU_NUM_TYPE_STOCK = "stock_num";
+    /**type类型: 已售数量:sold_num, 库存:stock_num */
+    private String type;
+    /**subType子类型: 订单:order*/
+    private String subType;
+    /**skuId*/
+    private Long id;
+    /**变动数量*/
+    private int num;
+
+    public StockParam(String type, String subType, Long id) {
+        this.type = type;
+        this.subType = subType;
+        this.id = id;
+    }
+
+    public StockParam(String type, Long id, int num) {
+        this.type = type;
+        this.id = id;
+        this.num = num;
+    }
+
+    public static StockParam buildOrderParam(Long orderId, String type) {
+        return new StockParam(type, STOCK_SUB_TYPE_ORDER, orderId);
+    }
+}

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác