Kaynağa Gözat

feat: 复制master

bianzhenhua123 4 ay önce
işleme
82bbcfffc0
100 değiştirilmiş dosya ile 15623 ekleme ve 0 silme
  1. 51 0
      .gitignore
  2. 1 0
      README.md
  3. 214 0
      pom.xml
  4. 90 0
      poyi-app-common/pom.xml
  5. 20 0
      poyi-app-common/src/main/java/com/tzy/common/config/BaseConfig.java
  6. 33 0
      poyi-app-common/src/main/java/com/tzy/common/config/CommonConfig.java
  7. 22 0
      poyi-app-common/src/main/java/com/tzy/common/config/QuerySql.java
  8. 14 0
      poyi-app-common/src/main/java/com/tzy/common/config/handle/ApiVersion.java
  9. 72 0
      poyi-app-common/src/main/java/com/tzy/common/config/handle/ApiVesrsionCondition.java
  10. 29 0
      poyi-app-common/src/main/java/com/tzy/common/config/handle/CustomRequestMappingHandlerMapping.java
  11. 16 0
      poyi-app-common/src/main/java/com/tzy/common/config/handle/VersionConfiguration.java
  12. 10 0
      poyi-app-common/src/main/java/com/tzy/dto/EndLiveParam.java
  13. 17 0
      poyi-app-common/src/main/java/com/tzy/dto/ImParam.java
  14. 21 0
      poyi-app-common/src/main/java/com/tzy/dto/ImUserDTO.java
  15. 14 0
      poyi-app-common/src/main/java/com/tzy/dto/ImUserResp.java
  16. 19 0
      poyi-app-common/src/main/java/com/tzy/dto/LivingUserParam.java
  17. 53 0
      poyi-app-common/src/main/java/com/tzy/dto/Message.java
  18. 34 0
      poyi-app-common/src/main/java/com/tzy/dto/QuizActivityDto.java
  19. 29 0
      poyi-app-common/src/main/java/com/tzy/dto/QuizLibDto.java
  20. 35 0
      poyi-app-common/src/main/java/com/tzy/dto/RefundNoticeDTO.java
  21. 20 0
      poyi-app-common/src/main/java/com/tzy/dto/UserLikeParam.java
  22. 26 0
      poyi-app-common/src/main/java/com/tzy/mapper/QuestionnaireMapper.java
  23. 8 0
      poyi-app-common/src/main/java/com/tzy/mapper/QuizActivityMapper.java
  24. 15 0
      poyi-app-common/src/main/java/com/tzy/mapper/QuizAnswerMapper.java
  25. 10 0
      poyi-app-common/src/main/java/com/tzy/mapper/QuizLibMapper.java
  26. 46 0
      poyi-app-common/src/main/java/com/tzy/mapper/StatsDataMapper.java
  27. 46 0
      poyi-app-common/src/main/java/com/tzy/mapper/StatsRecordMapper.java
  28. 61 0
      poyi-app-common/src/main/java/com/tzy/util/BarcodeUtil.java
  29. 10 0
      poyi-app-common/src/main/java/com/tzy/valid/Detail.java
  30. 10 0
      poyi-app-common/src/main/java/com/tzy/valid/Insert.java
  31. 10 0
      poyi-app-common/src/main/java/com/tzy/valid/Select.java
  32. 10 0
      poyi-app-common/src/main/java/com/tzy/valid/Update.java
  33. 89 0
      poyi-app-common/src/main/resources/mapper/QuestionnaireMapper.xml
  34. 11 0
      poyi-app-common/src/main/resources/mapper/QuizActivityMapper.xml
  35. 16 0
      poyi-app-common/src/main/resources/mapper/QuizAnswerMapper.xml
  36. 10 0
      poyi-app-common/src/main/resources/mapper/QuizLibMapper.xml
  37. 87 0
      poyi-app-common/src/main/resources/mapper/TStatsDataMapper.xml
  38. 84 0
      poyi-app-common/src/main/resources/mapper/TStatsRecordMapper.xml
  39. 29 0
      poyi-app/README.md
  40. 93 0
      poyi-app/pom.xml
  41. 36 0
      poyi-app/src/main/java/com/tzy/PoyiApplication.java
  42. 69 0
      poyi-app/src/main/java/com/tzy/SwaggerConfig.java
  43. 44 0
      poyi-app/src/main/java/com/tzy/aop/MqConsumerAOP.java
  44. 26 0
      poyi-app/src/main/java/com/tzy/aop/SensitiveDataAspect.java
  45. 93 0
      poyi-app/src/main/java/com/tzy/config/AppCommonConfig.java
  46. 161 0
      poyi-app/src/main/java/com/tzy/config/ConnectionPoolWarmer.java
  47. 38 0
      poyi-app/src/main/java/com/tzy/config/DruidMetricsConfiguration.java
  48. 36 0
      poyi-app/src/main/java/com/tzy/config/MetricsConfig.java
  49. 453 0
      poyi-app/src/main/java/com/tzy/config/MqConfig.java
  50. 36 0
      poyi-app/src/main/java/com/tzy/config/WebConfigurerAdapter.java
  51. 674 0
      poyi-app/src/main/java/com/tzy/controller/CommonController.java
  52. 648 0
      poyi-app/src/main/java/com/tzy/controller/TestController.java
  53. 112 0
      poyi-app/src/main/java/com/tzy/controller/appuser/AppNotifyController.java
  54. 61 0
      poyi-app/src/main/java/com/tzy/controller/appuser/AppUserBarrageRecordController.java
  55. 2542 0
      poyi-app/src/main/java/com/tzy/controller/appuser/AppUserControllerNew.java
  56. 55 0
      poyi-app/src/main/java/com/tzy/controller/appuser/AppUserShareController.java
  57. 60 0
      poyi-app/src/main/java/com/tzy/controller/appuser/QuestionnaireController.java
  58. 145 0
      poyi-app/src/main/java/com/tzy/controller/appuser/QuizActivityController.java
  59. 62 0
      poyi-app/src/main/java/com/tzy/controller/appuser/RecommendController.java
  60. 112 0
      poyi-app/src/main/java/com/tzy/controller/business/AppUserBusinessSettledController.java
  61. 424 0
      poyi-app/src/main/java/com/tzy/controller/grade/GradeOrderController.java
  62. 128 0
      poyi-app/src/main/java/com/tzy/controller/group/GroupActController.java
  63. 1482 0
      poyi-app/src/main/java/com/tzy/controller/group/GroupControllerNew.java
  64. 382 0
      poyi-app/src/main/java/com/tzy/controller/group/GroupGoodsController.java
  65. 514 0
      poyi-app/src/main/java/com/tzy/controller/group/GroupLocalController.java
  66. 135 0
      poyi-app/src/main/java/com/tzy/controller/group/ListCalendarController.java
  67. 77 0
      poyi-app/src/main/java/com/tzy/controller/ierp/PyErpRandomCodeController.java
  68. 117 0
      poyi-app/src/main/java/com/tzy/controller/living/GroupLivingController.java
  69. 366 0
      poyi-app/src/main/java/com/tzy/controller/living/LivingApiController.java
  70. 115 0
      poyi-app/src/main/java/com/tzy/controller/mall/EvaluationController.java
  71. 427 0
      poyi-app/src/main/java/com/tzy/controller/mall/MallOrderController.java
  72. 1078 0
      poyi-app/src/main/java/com/tzy/controller/merchant/MerchantControllerNew.java
  73. 88 0
      poyi-app/src/main/java/com/tzy/controller/pay/PaymentController.java
  74. 47 0
      poyi-app/src/main/java/com/tzy/controller/permissions/AppMerPermissionsController.java
  75. 2314 0
      poyi-app/src/main/java/com/tzy/controller/prize/AppActController.java
  76. 50 0
      poyi-app/src/main/java/com/tzy/dto/AppActDTO.java
  77. 20 0
      poyi-app/src/main/java/com/tzy/dto/AuctionJPushDTO.java
  78. 21 0
      poyi-app/src/main/java/com/tzy/dto/EvaluationDTO.java
  79. 55 0
      poyi-app/src/main/java/com/tzy/dto/LivingRoomDTO.java
  80. 22 0
      poyi-app/src/main/java/com/tzy/dto/LivingRoomLikeDTO.java
  81. 10 0
      poyi-app/src/main/java/com/tzy/dto/LivingScreenDTO.java
  82. 21 0
      poyi-app/src/main/java/com/tzy/dto/MineCountDTO.java
  83. 42 0
      poyi-app/src/main/java/com/tzy/dto/OrderCountDTO.java
  84. 10 0
      poyi-app/src/main/java/com/tzy/dto/OrderReq.java
  85. 22 0
      poyi-app/src/main/java/com/tzy/dto/OrderStatusCountDTO.java
  86. 21 0
      poyi-app/src/main/java/com/tzy/dto/SimplePrizeRecord.java
  87. 25 0
      poyi-app/src/main/java/com/tzy/dto/SkuDTO.java
  88. 48 0
      poyi-app/src/main/java/com/tzy/dto/SpuDTO.java
  89. 16 0
      poyi-app/src/main/java/com/tzy/dto/local/AddressDTO.java
  90. 16 0
      poyi-app/src/main/java/com/tzy/dto/local/AllocateResult.java
  91. 122 0
      poyi-app/src/main/java/com/tzy/dto/local/CardGroupGoodsDTO.java
  92. 110 0
      poyi-app/src/main/java/com/tzy/dto/local/CardGroupInfoDTO.java
  93. 20 0
      poyi-app/src/main/java/com/tzy/dto/local/LivingExplainDTO.java
  94. 46 0
      poyi-app/src/main/java/com/tzy/dto/local/OrderDTO.java
  95. 84 0
      poyi-app/src/main/java/com/tzy/dto/local/ResultDTO.java
  96. 18 0
      poyi-app/src/main/java/com/tzy/dto/local/UserPointDTO.java
  97. 31 0
      poyi-app/src/main/java/com/tzy/dto/local/card/CardQuery.java
  98. 66 0
      poyi-app/src/main/java/com/tzy/listener/mq/AppUserBrowseRecordConsumer.java
  99. 39 0
      poyi-app/src/main/java/com/tzy/listener/mq/CommunityNotifyConsumer.java
  100. 46 0
      poyi-app/src/main/java/com/tzy/listener/mq/GiftCardConsumer.java

+ 51 - 0
.gitignore

@@ -0,0 +1,51 @@
+
+.idea
+*.iml
+# Compiled class file
+*.class
+*.zip
+
+/tzy-admin/target/
+/tzy-api/target/
+/tzy-base/target/
+/tzy-common/target/
+/tzy-cust/target/
+/tzy-framework/target/
+/tzy-generator/target/
+/tzy-order/target/
+/tzy-quartz/target/
+/tzy-sportcard/target/
+/tzy-system/target/
+/weixin-api/target
+/target/*
+
+### Java template
+
+
+# Log file
+*.log
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+*.springBeans
+*.project
+*.classpath
+/tzy-base/.settings/
+/tzy-base/.mvn/
+/tzy-admin/.settings/
+/tzy-api/.settings/
+/tzy-api/.mvn/
+/tzy-common/.settings/
+/tzy-cust/.settings/
+/tzy-cust/.mvn/
+/tzy-framework/.settings/
+/tzy-generator/.settings/
+/tzy-order/.settings/
+/tzy-quartz/.settings/
+/tzy-system/.settings/
+/checkstyleidea.tmp/
+/bin/
+/poyi-app-common/target
+/poyi-app/target
+/poyi-pojo/target
+/poyi-service/target

+ 1 - 0
README.md

@@ -0,0 +1 @@
+拍卖项目APP

+ 214 - 0
pom.xml

@@ -0,0 +1,214 @@
+<?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.tzy</groupId>
+    <artifactId>tzy</artifactId>
+    <version>4.5.0</version>
+
+    <name>poyee-app</name>
+    <description>app</description>
+    
+    <properties>
+        <tzy.version>4.5.0</tzy.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <java.version>1.8</java.version>
+        <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
+        <druid.version>1.2.19</druid.version>
+        <bitwalker.version>1.19</bitwalker.version>
+        <kaptcha.version>2.3.2</kaptcha.version>
+        <swagger.version>2.9.2</swagger.version>
+        <pagehelper.boot.version>1.3.0</pagehelper.boot.version>
+        <fastjson.version>2.0.10</fastjson.version>
+        <oshi.version>5.2.5</oshi.version>
+        <jna.version>5.5.0</jna.version>
+        <commons.io.version>2.5</commons.io.version>
+        <commons.fileupload.version>1.3.3</commons.fileupload.version>
+        <poi.version>3.17</poi.version>
+        <velocity.version>1.7</velocity.version>
+        <skipTests>true</skipTests>
+    </properties>
+
+    <!-- 依赖声明 -->
+    <dependencyManagement>
+        <dependencies>
+            <!-- SpringBoot的依赖配置-->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>2.2.5.RELEASE</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-test</artifactId>
+                <version>2.1.17.RELEASE</version>
+                <scope>test</scope>
+            </dependency>
+            <!--阿里数据库连接池 -->
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>druid-spring-boot-starter</artifactId>
+                <version>${druid.version}</version>
+            </dependency>
+            <!--验证码 -->
+            <dependency>
+                <groupId>com.github.penggle</groupId>
+                <artifactId>kaptcha</artifactId>
+                <version>${kaptcha.version}</version>
+            </dependency>
+            <!-- 解析客户端操作系统、浏览器等 -->
+            <dependency>
+                <groupId>eu.bitwalker</groupId>
+                <artifactId>UserAgentUtils</artifactId>
+                <version>${bitwalker.version}</version>
+            </dependency>
+            <!-- pagehelper 分页插件 -->
+            <dependency>
+                <groupId>com.github.pagehelper</groupId>
+                <artifactId>pagehelper-spring-boot-starter</artifactId>
+                <version>${pagehelper.boot.version}</version>
+            </dependency>
+            <!-- 获取系统信息 -->
+            <dependency>
+                <groupId>com.github.oshi</groupId>
+                <artifactId>oshi-core</artifactId>
+                <version>${oshi.version}</version>
+            </dependency>
+            <!-- swagger2-->
+            <dependency>
+                <groupId>io.springfox</groupId>
+                <artifactId>springfox-swagger2</artifactId>
+                <version>${swagger.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>io.swagger</groupId>
+                        <artifactId>swagger-annotations</artifactId>
+                    </exclusion>
+                    <exclusion>
+                        <groupId>io.swagger</groupId>
+                        <artifactId>swagger-models</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <!-- swagger2-UI-->
+            <dependency>
+                <groupId>io.springfox</groupId>
+                <artifactId>springfox-swagger-ui</artifactId>
+                <version>${swagger.version}</version>
+            </dependency>
+            <!--io常用工具类 -->
+            <dependency>
+                <groupId>commons-io</groupId>
+                <artifactId>commons-io</artifactId>
+                <version>${commons.io.version}</version>
+            </dependency>
+            <!--文件上传工具类 -->
+            <dependency>
+                <groupId>commons-fileupload</groupId>
+                <artifactId>commons-fileupload</artifactId>
+                <version>${commons.fileupload.version}</version>
+            </dependency>
+            <!-- excel工具 -->
+            <dependency>
+                <groupId>org.apache.poi</groupId>
+                <artifactId>poi-ooxml</artifactId>
+                <version>${poi.version}</version>
+            </dependency>
+            <!-- 阿里JSON解析器 -->
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>fastjson</artifactId>
+                <version>${fastjson.version}</version>
+            </dependency>
+            <!-- 核心模块-->
+            <dependency>
+                <groupId>com.tzy</groupId>
+                <artifactId>tzy-framework</artifactId>
+                <version>${tzy.version}</version>
+            </dependency>
+            <!-- 系统模块-->
+            <dependency>
+                <groupId>com.tzy</groupId>
+                <artifactId>tzy-system</artifactId>
+                <version>${tzy.version}</version>
+            </dependency>
+            <!-- 通用工具-->
+            <dependency>
+                <groupId>com.tzy</groupId>
+                <artifactId>tzy-common</artifactId>
+                <version>${tzy.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.tzy</groupId>
+                <artifactId>weixin-api</artifactId>
+                <version>${tzy.version}</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <modules>
+        <module>poyi-pojo</module>
+        <module>tzy-common</module>
+        <module>poyi-app-common</module>
+        <module>tzy-system</module>
+        <module>tzy-framework</module>
+        <module>weixin-api</module>
+        <module>poyi-service</module>
+        <module>poyi-app</module>
+    </modules>
+    <packaging>pom</packaging>
+
+
+    <dependencies>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.1</version>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <repositories>
+        <repository>
+            <id>public</id>
+            <name>aliyun nexus</name>
+            <url>https://maven.aliyun.com/repository/public</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+        </repository>
+        <repository>
+            <id>zto-maven</id>
+            <url>https://dl.bintray.com/chocotan/maven</url>
+        </repository>
+    </repositories>
+
+    <pluginRepositories>
+        <pluginRepository>
+            <id>public</id>
+            <name>aliyun nexus</name>
+            <url>https://maven.aliyun.com/repository/public</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </pluginRepository>
+    </pluginRepositories>
+
+</project>

+ 90 - 0
poyi-app-common/pom.xml

@@ -0,0 +1,90 @@
+<?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>tzy</artifactId>
+        <groupId>com.tzy</groupId>
+        <version>4.5.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>poyi-app-common</artifactId>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <mahout.version>0.9</mahout.version>
+    </properties>
+
+    <dependencies>
+        <!-- 通用工具-->
+        <dependency>
+            <groupId>com.tzy</groupId>
+            <artifactId>tzy-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+<!--            <exclusions>-->
+<!--                <exclusion>-->
+<!--                    <groupId>org.springframework.boot</groupId>-->
+<!--                    <artifactId>spring-boot-starter-tomcat</artifactId>-->
+<!--                </exclusion>-->
+<!--            </exclusions>-->
+        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>org.springframework.boot</groupId>-->
+<!--            <artifactId>spring-boot-starter-tomcat</artifactId>-->
+<!--            <scope>provided</scope>-->
+<!--        </dependency>-->
+        <!-- swagger2-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+        </dependency>
+        <!--防止进入swagger页面报类型转换错误,排除2.9.2中的引用,手动增加1.5.21版本-->
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-annotations</artifactId>
+            <version>1.5.21</version>
+        </dependency>
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-models</artifactId>
+            <version>1.5.21</version>
+        </dependency>
+        <!-- swagger2-UI-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-openfeign</artifactId>
+            <version>2.2.5.RELEASE</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.google.guava</groupId>
+                    <artifactId>guava</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>io.github.openfeign</groupId>
+            <artifactId>feign-httpclient</artifactId>
+            <version>11.10</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.zxing</groupId>
+            <artifactId>core</artifactId>
+            <version>3.4.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.zxing</groupId>
+            <artifactId>javase</artifactId>
+            <version>3.4.1</version>
+        </dependency>
+    </dependencies>
+
+</project>

+ 20 - 0
poyi-app-common/src/main/java/com/tzy/common/config/BaseConfig.java

@@ -0,0 +1,20 @@
+package com.tzy.common.config;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@Data
+public class BaseConfig {
+	@Value("${tzy.app-version:dev}")
+	private String env;
+	@Value("${imServer.baseUrl}")
+	private String imBaseUrl;
+	@Value("${imServer.userUrl}")
+	private String imUserUrl;
+	@Value("${forumServer.baseurl:http://community}")
+	private String forumServiceURL;
+	@Value("${mallServer.baseurl:http://poyee-mall}")
+	private String mallServiceURL;
+}

+ 33 - 0
poyi-app-common/src/main/java/com/tzy/common/config/CommonConfig.java

@@ -0,0 +1,33 @@
+package com.tzy.common.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());
+	}
+}

+ 22 - 0
poyi-app-common/src/main/java/com/tzy/common/config/QuerySql.java

@@ -0,0 +1,22 @@
+package com.tzy.common.config;
+
+import org.teasoft.bee.osql.exception.SqlNullException;
+import org.teasoft.honey.osql.util.PropertiesReader;
+
+public class QuerySql {
+    private static PropertiesReader querySqlSqlProp = new PropertiesReader("config/sql.properties");
+
+    public QuerySql() {
+    }
+
+    public static String getQuerySql(String sqlId) {
+        String sql = querySqlSqlProp.getValue(sqlId);
+        if (sql == null) {
+            throw new SqlNullException("The sql statement string get by sqlId:" + sqlId + ", is Null !");
+        } else if ("".equals(sql.trim())) {
+            throw new SqlNullException("The sql statement string get by sqlId:" + sqlId + ", is empty !");
+        } else {
+            return sql;
+        }
+    }
+}

+ 14 - 0
poyi-app-common/src/main/java/com/tzy/common/config/handle/ApiVersion.java

@@ -0,0 +1,14 @@
+package com.tzy.common.config.handle;
+
+import org.springframework.web.bind.annotation.Mapping;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Mapping
+public @interface ApiVersion {
+    double value();
+
+}

+ 72 - 0
poyi-app-common/src/main/java/com/tzy/common/config/handle/ApiVesrsionCondition.java

@@ -0,0 +1,72 @@
+package com.tzy.common.config.handle;
+
+import com.tzy.common.config.CommonConfig;
+import org.slf4j.Logger;
+import org.springframework.web.servlet.mvc.condition.RequestCondition;
+import org.teasoft.honey.util.StringUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ApiVesrsionCondition implements RequestCondition<ApiVesrsionCondition> {
+
+	private static final Logger LOG= org.slf4j.LoggerFactory.getLogger(ApiVesrsionCondition.class);
+	private final static Pattern VERSION_PREFIX_PATTERN = Pattern.compile("v\\d*\\.\\d*|v\\d+");
+
+
+	private double apiVersion;
+
+
+	public ApiVesrsionCondition(double apiVersion) {
+		this.apiVersion = apiVersion;
+
+	}
+
+	@Override
+	public ApiVesrsionCondition combine(ApiVesrsionCondition other) {
+		return new ApiVesrsionCondition(other.getApiVersion());
+	}
+
+	@Override
+	public ApiVesrsionCondition getMatchingCondition(HttpServletRequest request) {
+		if(CommonConfig.isDevEnv()){
+			return this;
+		}
+		Matcher m = VERSION_PREFIX_PATTERN.matcher(request.getRequestURI());
+		Boolean flag = m.find();
+		if (flag) {
+			String group = m.group();
+			String v = group.substring(1, group.length());
+			if(StringUtils.isEmpty(v)){
+				return null;
+			}
+			Double version = Double.parseDouble(v);
+			if (version == 0) {
+				if(version <= this.apiVersion){
+					return this;
+				}
+			}
+			if (version >= this.apiVersion) {
+				return this;
+			}
+
+		}
+		return null;
+	}
+
+	@Override
+	public int compareTo(ApiVesrsionCondition other, HttpServletRequest request) {
+		LOG.debug("other:{}",other.getApiVersion());
+		LOG.debug("api version:{}",this.apiVersion);
+		if(other.getApiVersion() <= this.apiVersion  ){
+			return -1;
+		}
+		return 0;
+	}
+
+	public double getApiVersion() {
+		return apiVersion;
+	}
+
+}

+ 29 - 0
poyi-app-common/src/main/java/com/tzy/common/config/handle/CustomRequestMappingHandlerMapping.java

@@ -0,0 +1,29 @@
+package com.tzy.common.config.handle;
+
+
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.core.annotation.Order;
+import org.springframework.web.servlet.mvc.condition.RequestCondition;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+
+import java.lang.reflect.Method;
+
+@Order(0)
+public class CustomRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
+
+    @Override
+    protected RequestCondition<ApiVesrsionCondition> getCustomTypeCondition(Class<?> handlerType) {
+        ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType, ApiVersion.class);
+        return createCondition(apiVersion);
+    }
+
+    @Override
+    protected RequestCondition<ApiVesrsionCondition> getCustomMethodCondition(Method method) {
+        ApiVersion apiVersion = AnnotationUtils.findAnnotation(method, ApiVersion.class);
+        return createCondition(apiVersion);
+    }
+
+    private RequestCondition<ApiVesrsionCondition> createCondition(ApiVersion apiVersion) {
+        return apiVersion == null ? null : new ApiVesrsionCondition(apiVersion.value());
+    }
+}

+ 16 - 0
poyi-app-common/src/main/java/com/tzy/common/config/handle/VersionConfiguration.java

@@ -0,0 +1,16 @@
+package com.tzy.common.config.handle;
+
+import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+
+@Configuration
+public class VersionConfiguration implements WebMvcRegistrations {
+
+    @Override
+    public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
+        return new CustomRequestMappingHandlerMapping();
+    }
+
+}
+

+ 10 - 0
poyi-app-common/src/main/java/com/tzy/dto/EndLiveParam.java

@@ -0,0 +1,10 @@
+package com.tzy.dto;
+
+import com.tzy.common.base.BaseQuery;
+import lombok.Data;
+
+@Data
+public class EndLiveParam extends BaseQuery {
+    private Long refId;
+    private Integer userId;
+}

+ 17 - 0
poyi-app-common/src/main/java/com/tzy/dto/ImParam.java

@@ -0,0 +1,17 @@
+package com.tzy.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ImParam implements Serializable {
+    //直播间code
+    private String code;
+    //用户id集合
+    private List<Integer> userIds;
+}

+ 21 - 0
poyi-app-common/src/main/java/com/tzy/dto/ImUserDTO.java

@@ -0,0 +1,21 @@
+package com.tzy.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ImUserDTO implements Serializable {
+    private Integer id;
+    private Integer memberLevel;
+    private String nickname;
+    private String avatar;
+    //是否购买过
+    private boolean buyFlag;
+    //直播间是否匿名观看
+    @JsonIgnore
+    private Integer liveAnonymous;
+}

+ 14 - 0
poyi-app-common/src/main/java/com/tzy/dto/ImUserResp.java

@@ -0,0 +1,14 @@
+package com.tzy.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ImUserResp implements Serializable {
+    private int code;
+    private List<Integer> data;
+}

+ 19 - 0
poyi-app-common/src/main/java/com/tzy/dto/LivingUserParam.java

@@ -0,0 +1,19 @@
+package com.tzy.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.tzy.common.base.BaseQuery;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotEmpty;
+
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class LivingUserParam extends BaseQuery {
+    //直播间code
+    @NotEmpty(message = "直播间code不能为空")
+    private String code;
+
+}

+ 53 - 0
poyi-app-common/src/main/java/com/tzy/dto/Message.java

@@ -0,0 +1,53 @@
+package com.tzy.dto;
+
+import lombok.Builder;
+import lombok.Data;
+
+
+/**
+ *  Message message = Message.builder().code("1").code("chat")
+ *                 .messageType("chat_to_room")
+ *                 .messageParam(
+ *                         MessageParam.builder()
+ *                                 .receiver("TC-8050597605559")
+ *                                 .payload(
+ *                                         MessageParam.Payload.builder()
+ *                                                 .contentType("CHANGES_NUM_PEOPLE")
+ *                                                 .sender("2477")
+ *                                                 .content("你好!")
+ *                                                 .extra("{}")
+ *                                                 .build()
+ *                                 ).build()).build();
+ */
+@Data
+@Builder
+public class Message {
+    //推送code
+    private String code;
+    //推送消息类型
+    private String messageType;
+    //推送消息参数
+    private MessageParam messageParam;
+
+    @Data
+    @Builder
+    public static class MessageParam {
+        //接受者(直播间code等)
+        private String receiver;
+        //消息体
+        private Payload payload;
+
+        @Data
+        @Builder
+        public static class Payload {
+            //类型
+            private String contentType;
+            //发送人,无随意
+            private String sender;
+            //标题
+            private String content;
+            //json参数
+            private String extra;
+        }
+    }
+}

+ 34 - 0
poyi-app-common/src/main/java/com/tzy/dto/QuizActivityDto.java

@@ -0,0 +1,34 @@
+package com.tzy.dto;
+
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+
+@Data
+@ApiModel("答题活动详情")
+public class QuizActivityDto {
+    @ApiModelProperty("答题活动id")
+    private Long id;
+    @ApiModelProperty("活动名称")
+    private String activityName;
+    @ApiModelProperty("开始时间")
+    private Date startTime;
+    @ApiModelProperty("结束时间")
+    private Date endTime;
+    @ApiModelProperty("答题资格刷新周期")
+    private Integer refreshCycle;
+    @ApiModelProperty("题目数量")
+    private Integer questionNum;
+    @ApiModelProperty("状态:0、未启用,1、已启用")
+    private Integer status;
+    @ApiModelProperty("大转盘1 id")
+    private Long actId1;
+    @ApiModelProperty("大转盘2 id")
+    private Long actId2;
+
+    private List<QuizLibDto> quizLibDtoList;
+}

+ 29 - 0
poyi-app-common/src/main/java/com/tzy/dto/QuizLibDto.java

@@ -0,0 +1,29 @@
+package com.tzy.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@ApiModel("答题活动题目信息")
+public class QuizLibDto {
+
+    @ApiModelProperty("题目id")
+    private Long id;
+    @ApiModelProperty("答题活动id")
+    private Long activityId;
+    @ApiModelProperty("题目类型:choice_single,选择题多选:choice_multi,文字:text")
+    private String type;
+    @ApiModelProperty("题目内容")
+    private String questionText;
+    @ApiModelProperty("题目选项,json格式")
+    private String questionChoiceText;
+    @ApiModelProperty("创建时间")
+    private Date createTime;
+    @ApiModelProperty("是否必答题")
+    private Integer required;
+    @ApiModelProperty("状态:0、未启用,1、已启用")
+    private Integer status;
+}

+ 35 - 0
poyi-app-common/src/main/java/com/tzy/dto/RefundNoticeDTO.java

@@ -0,0 +1,35 @@
+package com.tzy.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.tzy.common.constant.Constants;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+@AllArgsConstructor
+@NoArgsConstructor
+public class RefundNoticeDTO implements Serializable {
+    /**退款类型:amount_async*/
+    private String type;
+    /**退款类型:amount和point*/
+    private String subType;
+    private Long orderId;
+    private BigDecimal refundFee;
+    /**订单唯一标识*/
+    private String refundId;
+    //交易编号
+    private String tradeNo;
+
+    public RefundNoticeDTO(String subType,Long orderId, BigDecimal refundFee, String refundId) {
+        this.subType = subType;
+        this.orderId = orderId;
+        this.refundFee = refundFee;
+        this.refundId = refundId;
+        this.type = Constants.ASYNC_REFUND_TYPE;
+    }
+}

+ 20 - 0
poyi-app-common/src/main/java/com/tzy/dto/UserLikeParam.java

@@ -0,0 +1,20 @@
+package com.tzy.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.tzy.common.base.BaseQuery;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotEmpty;
+
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class UserLikeParam extends BaseQuery {
+    //直播间code
+    @NotEmpty(message = "直播间code不能为空")
+    private String code;
+    //点赞数量
+    private int num;
+}

+ 26 - 0
poyi-app-common/src/main/java/com/tzy/mapper/QuestionnaireMapper.java

@@ -0,0 +1,26 @@
+package com.tzy.mapper;
+
+import com.tzy.pojo.question.Question;
+import com.tzy.pojo.question.QuestionAnswer;
+import com.tzy.pojo.question.Questionnaire;
+import com.tzy.pojo.question.UserLimitRecord;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface QuestionnaireMapper {
+
+    Long hasUserQuestionnaireByType(@Param("userId") Integer userId, @Param("type") String type);
+
+    Questionnaire getLastQuestionnaire(@Param("type") String type, @Param("id") Long id, @Param("memberLevel") Integer memberLevel);
+
+    List<Question> getQuestionsByQuestionnaireId(@Param("questionnaireId") Long questionnaireId);
+
+    int insertUserLimitRecord(UserLimitRecord record);
+
+    int batchInsertQuestionAnswers(List<QuestionAnswer> questionAnswers);
+
+    Long hasUserQuestionnaire(@Param("userId") Integer userId,  @Param("memberLevel") Integer memberLevel);
+
+    int getLastNewMonthlyLimit(Long userId);
+}

+ 8 - 0
poyi-app-common/src/main/java/com/tzy/mapper/QuizActivityMapper.java

@@ -0,0 +1,8 @@
+package com.tzy.mapper;
+
+import com.tzy.dto.QuizActivityDto;
+
+public interface QuizActivityMapper {
+
+    QuizActivityDto queryQuizActivity(Long id);
+}

+ 15 - 0
poyi-app-common/src/main/java/com/tzy/mapper/QuizAnswerMapper.java

@@ -0,0 +1,15 @@
+package com.tzy.mapper;
+
+
+import com.tzy.pojo.quiz.QuizAnswer;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface QuizAnswerMapper {
+
+    boolean batchSaveQuizAnswer(@Param("quizAnswerList") List<QuizAnswer> quizAnswerList);
+
+    int countRoundByUserId(@Param("userId") Integer userId,@Param("round") Long round,@Param("activityId") Long activityId);
+
+}

+ 10 - 0
poyi-app-common/src/main/java/com/tzy/mapper/QuizLibMapper.java

@@ -0,0 +1,10 @@
+package com.tzy.mapper;
+
+import com.tzy.dto.QuizLibDto;
+
+import java.util.List;
+
+public interface QuizLibMapper {
+
+    List<QuizLibDto> queryQuizLibByActivityId(Long id);
+}

+ 46 - 0
poyi-app-common/src/main/java/com/tzy/mapper/StatsDataMapper.java

@@ -0,0 +1,46 @@
+package com.tzy.mapper;
+
+import com.tzy.pojo.app.StatsData;
+
+import java.util.List;
+
+/**
+ * 统计Mapper接口
+ *
+ * @author tencheer
+ * @date 2025-01-07
+ */
+public interface StatsDataMapper {
+    /**
+     * 查询统计
+     *
+     * @param id 统计ID
+     * @return 统计
+     */
+    public StatsData selectStatsDataById(Long id);
+
+    /**
+     * 查询统计列表
+     *
+     * @param statsData 统计
+     * @return 统计集合
+     */
+    public List<StatsData> selectStatsDataList(StatsData statsData);
+
+    /**
+     * 新增统计
+     *
+     * @param statsData 统计
+     * @return 结果
+     */
+    public int insertStatsData(StatsData statsData);
+
+    /**
+     * 修改统计
+     *
+     * @param statsData 统计
+     * @return 结果
+     */
+    public int updateStatsData(StatsData statsData);
+
+}

+ 46 - 0
poyi-app-common/src/main/java/com/tzy/mapper/StatsRecordMapper.java

@@ -0,0 +1,46 @@
+package com.tzy.mapper;
+
+import com.tzy.pojo.app.StatsRecord;
+
+import java.util.List;
+
+/**
+ * 统计明细Mapper接口
+ *
+ * @author tencheer
+ * @date 2025-01-07
+ */
+public interface StatsRecordMapper {
+    /**
+     * 查询统计明细
+     *
+     * @param id 统计明细ID
+     * @return 统计明细
+     */
+    public StatsRecord selectStatsRecordById(Long id);
+
+    /**
+     * 查询统计明细列表
+     *
+     * @param StatsRecord 统计明细
+     * @return 统计明细集合
+     */
+    public List<StatsRecord> selectStatsRecordList(StatsRecord StatsRecord);
+
+    /**
+     * 新增统计明细
+     *
+     * @param StatsRecord 统计明细
+     * @return 结果
+     */
+    public int insertStatsRecord(StatsRecord StatsRecord);
+
+    /**
+     * 修改统计明细
+     *
+     * @param StatsRecord 统计明细
+     * @return 结果
+     */
+    public int updateStatsRecord(StatsRecord StatsRecord);
+
+}

+ 61 - 0
poyi-app-common/src/main/java/com/tzy/util/BarcodeUtil.java

@@ -0,0 +1,61 @@
+package com.tzy.util;
+
+import com.google.zxing.*;
+import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
+import com.google.zxing.common.HybridBinarizer;
+import com.google.zxing.qrcode.QRCodeReader;
+import com.tzy.common.exception.ServiceException;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+public class BarcodeUtil {
+
+    /**
+     * 条形码识别
+     * @param file
+     * @return
+     */
+    public static String decodeBarcodeByFile(File file) {
+        try {
+            // 读取图片
+            BufferedImage bufferedImage = ImageIO.read(file);
+            LuminanceSource source = new BufferedImageLuminanceSource(bufferedImage);
+            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
+            // 解码条形码
+            Result result = new MultiFormatReader().decode(bitmap);
+            return result.getText();
+        } catch (Exception e) {
+            throw new ServiceException("识别失败,请重试");
+        }
+    }
+
+    public static String decodeBarcode(BufferedImage bufferedImage) {
+        try {
+            LuminanceSource source = new BufferedImageLuminanceSource(bufferedImage);
+            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
+            Result result = new MultiFormatReader().decode(bitmap);
+            return result.getText();
+        } catch (Exception e) {
+            throw new ServiceException("识别失败,请重试");
+        }
+    }
+
+    // 使用ZXing解析二维码
+    public static String decodeQRCode(BufferedImage bufferedImage) {
+        QRCodeReader qrCodeReader = new QRCodeReader();
+        try {
+            LuminanceSource source = new BufferedImageLuminanceSource(bufferedImage);
+            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
+            Map<DecodeHintType, Object> hintMap = new HashMap<>();
+            hintMap.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);  // 尝试更努力的解码
+            Result result = qrCodeReader.decode(bitmap, hintMap);
+            return result.getText();
+        } catch (Exception e) {
+            return null;
+        }
+    }
+}

+ 10 - 0
poyi-app-common/src/main/java/com/tzy/valid/Detail.java

@@ -0,0 +1,10 @@
+package com.tzy.valid;
+
+/**
+ * @author by po'yi
+ * @Classname Query
+ * @Description TODO
+ * @Date 2023/12/21 15:02
+ */
+public interface Detail {
+}

+ 10 - 0
poyi-app-common/src/main/java/com/tzy/valid/Insert.java

@@ -0,0 +1,10 @@
+package com.tzy.valid;
+
+/**
+ * @author by po'yi
+ * @Classname Query
+ * @Description TODO
+ * @Date 2023/12/21 15:02
+ */
+public interface Insert {
+}

+ 10 - 0
poyi-app-common/src/main/java/com/tzy/valid/Select.java

@@ -0,0 +1,10 @@
+package com.tzy.valid;
+
+/**
+ * @author by po'yi
+ * @Classname Query
+ * @Description TODO
+ * @Date 2023/12/21 15:02
+ */
+public interface Select {
+}

+ 10 - 0
poyi-app-common/src/main/java/com/tzy/valid/Update.java

@@ -0,0 +1,10 @@
+package com.tzy.valid;
+
+/**
+ * @author by po'yi
+ * @Classname Query
+ * @Description TODO
+ * @Date 2023/12/21 15:02
+ */
+public interface Update {
+}

+ 89 - 0
poyi-app-common/src/main/resources/mapper/QuestionnaireMapper.xml

@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.tzy.mapper.QuestionnaireMapper">
+
+    <select id="hasUserQuestionnaireByType" resultType="java.lang.Long" parameterType="object">
+        SELECT id FROM "user_limit_record" WHERE user_id = #{userId} and type = #{type} and status = 1
+    </select>
+
+    <select id="getLastQuestionnaire" resultType="com.tzy.pojo.question.Questionnaire" parameterType="object">
+        SELECT id,title,description,incr_amount incrAmount,type,daily_limit dailyLimit,weekly_limit weeklyLimit
+        FROM "questionnaire"
+        WHERE  status = 1
+        <if test="id != null"> and id = #{id} </if>
+        <if test="type != null and type !='' "> and type = #{type} </if>
+        <if test="memberLevel != null"> and member_level = #{memberLevel} </if>
+        limit 1
+    </select>
+
+    <select id="getQuestionsByQuestionnaireId" resultType="com.tzy.pojo.question.Question" parameterType="Long">
+        SELECT id,type,questionnaire_id questionnaireId,question_text questionText,question_choice_text questionChoiceText
+        FROM "question" WHERE questionnaire_id=#{questionnaireId} and status=1
+    </select>
+
+    <insert id="insertUserLimitRecord" parameterType="com.tzy.pojo.question.UserLimitRecord" keyProperty="id" keyColumn="id" useGeneratedKeys="true">
+        insert into user_limit_record
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="type != null and type != ''">type,</if>
+            <if test="userId != null">user_id,</if>
+            <if test="previousMonthlyLimit != null">previous_monthly_limit,</if>
+            <if test="newMonthlyLimit != null">new_monthly_limit,</if>
+            <if test="previousDailyLimit != null">previous_daily_limit,</if>
+            <if test="newDailyLimit != null">new_daily_limit,</if>
+            <if test="previousWeeklyLimit != null">previous_weekly_limit,</if>
+            <if test="newWeeklyLimit != null">new_weekly_limit,</if>
+            <if test="status != null">status,</if>
+            create_time,
+            <if test="createdBy != null and createdBy != ''">created_by,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="type != null and type != ''">#{type},</if>
+            <if test="userId != null">#{userId},</if>
+            <if test="previousMonthlyLimit != null">#{previousMonthlyLimit},</if>
+            <if test="newMonthlyLimit != null">#{newMonthlyLimit},</if>
+            <if test="previousDailyLimit != null">#{previousDailyLimit},</if>
+            <if test="newDailyLimit != null">#{newDailyLimit},</if>
+            <if test="previousWeeklyLimit != null">#{previousWeeklyLimit},</if>
+            <if test="newWeeklyLimit != null">#{newWeeklyLimit},</if>
+            <if test="status != null">#{status},</if>
+            now(),
+            <if test="createdBy != null and createdBy != ''">#{createdBy},</if>
+        </trim>
+    </insert>
+
+
+    <insert id="batchInsertQuestionAnswers" parameterType="java.util.List">
+        insert into question_answer (
+        questionnaire_id,
+        question_id,
+        user_id,
+        answer_text,
+        record_id,
+        create_time
+        )
+        values
+        <foreach collection="list" item="item" index="index" separator=",">
+            (
+            #{item.questionnaireId},
+            #{item.questionId},
+            #{item.userId},
+            #{item.answerText},
+            #{item.recordId},
+            now()
+            )
+        </foreach>
+    </insert>
+
+    <select id="hasUserQuestionnaire" resultType="java.lang.Long" parameterType="object">
+        SELECT id FROM "user_limit_record" WHERE user_id= #{userId} and status=1 and type = (
+            SELECT 'questionnaire_' || id FROM questionnaire
+            WHERE type='user_incr_amount'  and member_level = #{memberLevel} and status=1 order by id desc limit 1
+        ) LIMIT 1
+    </select>
+
+    <select id="getLastNewMonthlyLimit" resultType="int">
+        select new_monthly_limit from user_limit_record where user_id = #{userId} and type = 'customer' order by id desc limit 1
+    </select>
+</mapper>

+ 11 - 0
poyi-app-common/src/main/resources/mapper/QuizActivityMapper.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.tzy.mapper.QuizActivityMapper">
+    <select id="queryQuizActivity" resultType="com.tzy.dto.QuizActivityDto">
+        select id,activity_name activityName,start_time startTime,end_time endTime,
+        refresh_cycle refreshCycle,question_num questionNum,status,act_id_1 actId1,act_id_2 actId2 from quiz_activity
+        where id=#{id}
+    </select>
+</mapper>

+ 16 - 0
poyi-app-common/src/main/resources/mapper/QuizAnswerMapper.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.tzy.mapper.QuizAnswerMapper">
+    <insert id="batchSaveQuizAnswer" parameterType="com.tzy.pojo.quiz.QuizAnswer">
+        insert into quiz_answer (activity_id,quiz_id,user_id,round,answer,create_time) values
+        <foreach collection="quizAnswerList" item="quizAnswer" separator=",">
+        (#{quizAnswer.activityId},#{quizAnswer.quizId},#{quizAnswer.userId},#{quizAnswer.round},#{quizAnswer.answer},now())
+        </foreach>
+    </insert>
+    <select id="countRoundByUserId" resultType="int">
+        select count(*) from quiz_answer where user_id=#{userId} and round = #{round} and activity_id=${activityId}
+    </select>
+
+</mapper>

+ 10 - 0
poyi-app-common/src/main/resources/mapper/QuizLibMapper.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.tzy.mapper.QuizLibMapper">
+    <select id="queryQuizLibByActivityId" resultType="com.tzy.dto.QuizLibDto">
+    select id,activity_id activityId,type,question_text questionText,question_choice_text questionChoiceText,create_time createTime, required,status
+         from quiz_lib where activity_id =#{activityId} and status =1
+    </select>
+</mapper>

+ 87 - 0
poyi-app-common/src/main/resources/mapper/TStatsDataMapper.xml

@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.tzy.mapper.StatsDataMapper">
+    
+    <resultMap type="com.tzy.pojo.app.StatsData" id="StatsDataResult">
+        <result property="id"    column="id"    />
+        <result property="type"    column="type"    />
+        <result property="collectionUserId"    column="collection_user_id"    />
+        <result property="collectionTypeId"    column="collection_type_id"    />
+        <result property="collectionNum"    column="collection_num"    />
+        <result property="name"    column="name"    />
+        <result property="remark"    column="remark"    />
+        <result property="status"    column="status"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="prop1"    column="prop1"    />
+        <result property="prop2"    column="prop2"    />
+        <result property="version"    column="version"    />
+    </resultMap>
+
+    <sql id="selectStatsDataVo">
+        select id, type, collection_user_id, collection_type_id, collection_num, name, remark, status, prop1, prop2, version from t_stats_data
+    </sql>
+
+    <select id="selectStatsDataList" parameterType="com.tzy.pojo.app.StatsData" resultMap="StatsDataResult">
+        <include refid="selectStatsDataVo"/>
+        <where>  
+            <if test="status != null "> and status = #{status} </if>
+            <if test="type != null "> and type = #{type} </if>
+            <if test="collectionUserId != null "> and collection_user_id = #{collectionUserId} </if>
+            <if test="collectionTypeId != null "> and collection_type_id = #{collectionTypeId} </if>
+        </where>
+    </select>
+    
+    <select id="selectTStatsDataById" parameterType="Long" resultMap="StatsDataResult">
+        <include refid="selectStatsDataVo"/>
+        where id = #{id}
+    </select>
+        
+    <insert id="insertStatsData" parameterType="com.tzy.pojo.app.StatsData">
+        insert into t_stats_data
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="type != null">type,</if>
+            <if test="collectionUserId != null">collection_user_id,</if>
+            <if test="collectionTypeId != null">collection_type_id,</if>
+            <if test="collectionNum != null">collection_num,</if>
+            <if test="name != null">name,</if>
+            <if test="remark != null">remark,</if>
+            <if test="status != null">status,</if>
+            <if test="prop1 != null">prop1,</if>
+            <if test="prop2 != null">prop2,</if>
+            <if test="version != null">version,</if>
+            create_time,
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="type != null">#{type},</if>
+            <if test="collectionUserId != null">#{collectionUserId},</if>
+            <if test="collectionTypeId != null">#{collectionTypeId},</if>
+            <if test="collectionNum != null">#{collectionNum},</if>
+            <if test="name != null">#{name},</if>
+            <if test="remark != null">#{remark},</if>
+            <if test="status != null">#{status},</if>
+            <if test="prop1 != null">#{prop1},</if>
+            <if test="prop2 != null">#{prop2},</if>
+            <if test="version != null">#{version},</if>
+            now(),
+         </trim>
+    </insert>
+
+    <update id="updateStatsData" parameterType="com.tzy.pojo.app.StatsData">
+        update t_stats_data
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="collectionNum != null">collection_num = #{collectionNum},</if>
+            <if test="name != null">name = #{name},</if>
+            <if test="remark != null">remark = #{remark},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="prop1 != null">prop1 = #{prop1},</if>
+            <if test="prop2 != null">prop2 = #{prop2},</if>
+            <if test="version != null">version = #{version},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+</mapper>

+ 84 - 0
poyi-app-common/src/main/resources/mapper/TStatsRecordMapper.xml

@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.tzy.mapper.StatsRecordMapper">
+    
+    <resultMap type="com.tzy.pojo.app.StatsRecord" id="TStatsRecordResult">
+        <result property="id"    column="id"    />
+        <result property="type"    column="type"    />
+        <result property="collectionUserId"    column="collection_user_id"    />
+        <result property="collectionTypeId"    column="collection_type_id"    />
+        <result property="refUserId"    column="ref_user_id"    />
+        <result property="status"    column="status"    />
+        <result property="num"    column="num"    />
+        <result property="extraProp"    column="extra_prop"    />
+        <result property="remark"    column="remark"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="prop1"    column="prop1"    />
+        <result property="version"    column="version"    />
+    </resultMap>
+
+    <sql id="selectTStatsRecordVo">
+        select id, type, collection_user_id, collection_type_id, ref_user_id, status, num, extra_prop, remark, prop1, version from t_stats_record
+    </sql>
+
+    <select id="selectStatsRecordList" parameterType="com.tzy.pojo.app.StatsRecord" resultMap="TStatsRecordResult">
+        <include refid="selectTStatsRecordVo"/>
+        <where>  
+        </where>
+    </select>
+    
+    <select id="selectStatsRecordById" parameterType="Long" resultMap="TStatsRecordResult">
+        <include refid="selectTStatsRecordVo"/>
+        where id = #{id}
+    </select>
+        
+    <insert id="insertStatsRecord" parameterType="com.tzy.pojo.app.StatsRecord">
+        insert into t_stats_record
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="type != null">type,</if>
+            <if test="collectionUserId != null">collection_user_id,</if>
+            <if test="collectionTypeId != null">collection_type_id,</if>
+            <if test="refUserId != null">ref_user_id,</if>
+            <if test="status != null">status,</if>
+            <if test="num != null">num,</if>
+            <if test="extraProp != null">extra_prop,</if>
+            <if test="remark != null">remark,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="prop1 != null">prop1,</if>
+            <if test="version != null">version,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="type != null">#{type},</if>
+            <if test="collectionUserId != null">#{collectionUserId},</if>
+            <if test="collectionTypeId != null">#{collectionTypeId},</if>
+            <if test="refUserId != null">#{refUserId},</if>
+            <if test="status != null">#{status},</if>
+            <if test="num != null">#{num},</if>
+            <if test="extraProp != null">#{extraProp},</if>
+            <if test="remark != null">#{remark},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="prop1 != null">#{prop1},</if>
+            <if test="version != null">#{version},</if>
+         </trim>
+    </insert>
+
+    <update id="updateStatsRecord" parameterType="com.tzy.pojo.app.StatsRecord">
+        update t_stats_record
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="type != null">type = #{type},</if>
+            <if test="collectionUserId != null">collection_user_id = #{collectionUserId},</if>
+            <if test="collectionTypeId != null">collection_type_id = #{collectionTypeId},</if>
+            <if test="refUserId != null">ref_user_id = #{refUserId},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="num != null">num = #{num},</if>
+            <if test="extraProp != null">extra_prop = #{extraProp},</if>
+            <if test="remark != null">remark = #{remark},</if>
+            <if test="prop1 != null">prop1 = #{prop1},</if>
+            <if test="version != null">version = #{version},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+</mapper>

+ 29 - 0
poyi-app/README.md

@@ -0,0 +1,29 @@
+# py-app - 移动端
+
+> 项目说明
+
+# 🌟 核心功能
+
+#### 1. 接口
+>- api/{version}/group/changeInfoType 
+>  + **old**
+>  + 切换剩余随机 【选队随机】
+>- api/{version}/group/v3/team
+>  + 队伍信息
+>- api/{version}/group/v2/changeInfoType
+>  + **new**
+>  + 切换剩余随机 【选队随机|买队】
+>- api/{version}/group/v4/team
+>  + **new**
+>  + 队伍信息【支持买队】
+>- api/merchant/sendExpressNew
+>  + 发货
+  
+#### 2. 消息队列
+>- 支付回调 mq 
+>  + EXCHANGE_PRE_PAY_CALLBACK
+>  + QUEUE_PRE_PAY_CALLBACK   queue
+
+# 🛠️ 开发环境
+
+# 🛠️ 技术架构  

+ 93 - 0
poyi-app/pom.xml

@@ -0,0 +1,93 @@
+<?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>tzy</artifactId>
+        <groupId>com.tzy</groupId>
+        <version>4.5.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>poyi-app</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.tzy</groupId>
+            <artifactId>poyi-service</artifactId>
+            <version>${tzy.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.janino</groupId>
+            <artifactId>janino</artifactId>
+            <version>3.0.12</version>
+        </dependency>
+        <dependency>
+            <groupId>com.sndyuk</groupId>
+            <artifactId>logback-more-appenders</artifactId>
+            <version>1.8.5</version>
+        </dependency>
+        <dependency>
+            <groupId>org.fluentd</groupId>
+            <artifactId>fluent-logger</artifactId>
+            <version>0.3.4</version>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter</artifactId>
+            <version>RELEASE</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-test-autoconfigure</artifactId>
+            <version>2.1.17.RELEASE</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</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>
+                <version>2.1.1.RELEASE</version>
+                <configuration>
+                    <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
+                    <includeSystemScope>true</includeSystemScope>
+                </configuration>
+
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <version>3.0.0</version>
+                <configuration>
+                    <failOnMissingWebXml>false</failOnMissingWebXml>
+                    <warName>${project.artifactId}</warName>
+                </configuration>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+</project>

+ 36 - 0
poyi-app/src/main/java/com/tzy/PoyiApplication.java

@@ -0,0 +1,36 @@
+package com.tzy;
+
+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.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.FilterType;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+
+/**
+ * 启动程序
+ * 
+ * @author tzy
+ */
+@SpringBootApplication(scanBasePackages = "com.tzy")
+@ComponentScan(excludeFilters = {
+        @ComponentScan.Filter(type = FilterType.REGEX,pattern = "com.tzy.framework.shiro.*"),
+        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {DataSourceAutoConfiguration.class,SecurityAutoConfiguration.class})
+})
+@EnableAsync
+@EnableCaching
+@ForestScan(basePackages = "com.tzy.common.utils.http.forest")
+@Slf4j
+@EnableFeignClients(basePackages = "com.tzy.openfeign")
+public class PoyiApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(PoyiApplication.class, args);
+        log.info("(♥◠‿◠)ノ゙ app启动成功   ლ(´ڡ`ლ)゙");
+    }
+}

+ 69 - 0
poyi-app/src/main/java/com/tzy/SwaggerConfig.java

@@ -0,0 +1,69 @@
+package com.tzy;
+
+import com.tzy.common.config.Global;
+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;
+
+    /**
+     * 创建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.tzy"))
+                // 扫描所有
+                .apis(RequestHandlerSelectors.any())
+                .paths(PathSelectors.any())
+                .build();
+    }
+
+    /**
+     * 添加摘要信息
+     */
+    private ApiInfo apiInfo()
+    {
+        // 用ApiInfoBuilder进行定制
+        return new ApiInfoBuilder()
+                // 设置标题
+                .title("标题:珀懿APP_接口文档")
+                // 描述
+                .description("描述:珀懿APP接口")
+                // 作者信息
+                .contact(new Contact(Global.getName(), null, null))
+                // 版本
+                .version("版本号:" + Global.getVersion())
+                .build();
+    }
+}

+ 44 - 0
poyi-app/src/main/java/com/tzy/aop/MqConsumerAOP.java

@@ -0,0 +1,44 @@
+package com.tzy.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);
+	}
+
+
+}

+ 26 - 0
poyi-app/src/main/java/com/tzy/aop/SensitiveDataAspect.java

@@ -0,0 +1,26 @@
+package com.tzy.aop;
+
+import com.tzy.common.utils.bean.SensitiveDataUtils;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.stereotype.Component;
+
+/**
+ * 敏感数据处理切面
+ */
+@Aspect
+@Component
+public class SensitiveDataAspect {
+
+    @Pointcut("@annotation(com.tzy.common.annotation.SensitiveData)")
+    public void sensitiveDataPointcut() {
+    }
+
+    @AfterReturning(pointcut = "sensitiveDataPointcut()", returning = "result")
+    public void handleSensitiveData(Object result) {
+        if (result != null) {
+            SensitiveDataUtils.handleSensitiveData(result);
+        }
+    }
+}

+ 93 - 0
poyi-app/src/main/java/com/tzy/config/AppCommonConfig.java

@@ -0,0 +1,93 @@
+package com.tzy.config;
+
+import com.impossibl.postgres.jdbc.PGConnectionPoolDataSource;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+
+import javax.sql.PooledConnection;
+import java.sql.SQLException;
+
+/**
+ * @author by po'yi
+ * @Classname CommonConfig
+ * @Description TODO
+ * @Date 2021/12/16 14:05
+ */
+//@Configuration
+public class AppCommonConfig {
+
+	@Value("${spring.datasource.druid.master.url}")
+	private String dbUrl;
+	@Value("${spring.datasource.druid.master.username}")
+	private String username;
+	@Value("${spring.datasource.druid.master.password}")
+	private String password;
+
+	//@Bean
+	//public PGDataSource pgDataSource() {
+	//	PGDataSource ds = new PGDataSource();
+	//	//ds.setDatabaseUrl(dbUrl);
+	//	ds.setHost("m2-dev.hobbystocks.cn");
+	//	ds.setPort(5432);
+	//	ds.setDatabaseName("tzy_system");
+	//	ds.setUser(username);
+	//	ds.setPassword(password);
+	//	return ds;
+	//}
+	//
+	@Bean
+	public PooledConnection pooledConnection() throws SQLException {
+		PGConnectionPoolDataSource source = new PGConnectionPoolDataSource();
+		source.setServerName("m2-dev.hobbystocks.cn");
+		source.setPortNumber(5432);
+		source.setDatabaseName("tzy_system");
+		source.setUser(username);
+		source.setPassword(password);
+		return source.getPooledConnection();
+	}
+
+
+	//@Bean
+	//public void pgListen() throws SQLException {
+	//    System.out.println("初始化监听器");
+	//    //获取数据库连接
+	//    Connection connection =pooledConnection().getConnection();
+	//    //将数据库连接还原为原始的PGConnection
+	//    PGConnection pgConnection = connection.unwrap(PGConnection.class);
+	//    //为连接添加监听器
+	//    pgConnection.addNotificationListener(new PGNotificationListener() {
+	//        @Override
+	//        public void notification(int processId, String channelName, String payload) {
+	//            System.out.println("Received Notification: " + processId + ", " + channelName + ", " + payload);
+	//        }
+	//        @Override
+	//        public void closed() {
+	//            PGNotificationListener.super.closed();
+	//        }
+	//    });
+	//
+	//	//设置监听通道 对应pgnotify的channel
+	//	Statement stmt = pgConnection.createStatement();
+	//	stmt.executeUpdate("LISTEN CARD_GROUP_ORDER_INFO_MODIFIED_TEST");
+	//	stmt.close();
+	//}
+
+	//@Bean
+	//public ConnectionFactory connectionFactory(){
+	//	ConnectionFactory connectionFactory= ConnectionFactories.get(ConnectionFactoryOptions.builder()
+	//			.option(DRIVER,"postgresql")
+	//			.option(HOST,host)
+	//			.option(PORT,port)
+	//			.option(USER,username)
+	//			.option(PASSWORD,password)
+	//			.option(DATABASE,database)
+	//			.build());
+	//
+	//	ConnectionPoolConfiguration configuration = ConnectionPoolConfiguration.builder(connectionFactory)
+	//			.maxIdleTime(Duration.ofMillis(1000))
+	//			.maxSize(20)
+	//			.build();
+	//	// ConnectionPool实现了ConnectionFactory接口,使用ConnectionFactory替换ConnectionFactory
+	//	return new ConnectionPool(configuration);
+	//}
+}

+ 161 - 0
poyi-app/src/main/java/com/tzy/config/ConnectionPoolWarmer.java

@@ -0,0 +1,161 @@
+package com.tzy.config;
+
+import com.tzy.elasticsearch.dto.CardGroupInfoGoodsDTO;
+import com.tzy.elasticsearch.service.CardGroupInfoGoodsService;
+import com.tzy.framework.util.RedisTools;
+import com.tzy.sportcard.api.dto.group.SimpleGroupDTO;
+import com.tzy.sportcard.api.service.GroupApiService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.stereotype.Component;
+import org.teasoft.bee.osql.SuidRich;
+
+import javax.annotation.Resource;
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Arrays;
+import java.util.List;
+
+@Component
+@Slf4j
+public class ConnectionPoolWarmer implements ApplicationRunner {
+
+    @Resource
+    private DataSource dataSource;
+    @Resource
+    private CardGroupInfoGoodsService cardGroupInfoGoodsService;
+    @Autowired
+    @Qualifier("threadPoolTaskExecutor")
+    private ThreadPoolTaskExecutor pools;
+    @Resource
+    private SuidRich suidRich;
+    @Resource
+    private GroupApiService groupApiService;
+
+
+    List<String> tables = Arrays.asList(
+            "card_group_order_info", "card_group_goods", "card_group_info", "order_list", "card_check_list", "tzy_sys_notice_record",
+            "app_base_user", "tzy_app_info", "card_group_lives_config", "app_user_card_record", "tzy_card_base_info"
+    );
+
+    @Override
+    public void run(ApplicationArguments args) {
+        RedisTools.getRedisUtils().set("test_init", 1, 3);
+        log.debug("redis init");
+        initPool();
+        log.debug("pool init");
+        poolPrepare();
+        log.debug("db pool init");
+        indexPrepare();
+        log.debug("db index init");
+        initSuidRich();
+        log.debug("suid init");
+        initEs();
+        log.debug("es init");
+        initRecommend();
+        log.debug("recommend init");
+    }
+
+    private void initRecommend() {
+        try {
+            groupApiService.getRecommendInfo(272, 1, 20);
+        } catch (Exception ignored) {
+        }
+    }
+
+    private void initSuidRich() {
+        try {
+            SimpleGroupDTO groupInfo = new SimpleGroupDTO();
+            groupInfo.setStatus(201);
+            suidRich.select(groupInfo);
+        } catch (Exception ignored) {
+        }
+    }
+
+    private void initPool() {
+        pools.execute(() -> log.debug("db pool init"));
+    }
+
+    private void initEs() {
+        try {
+            CardGroupInfoGoodsDTO query = new CardGroupInfoGoodsDTO();
+            query.setStatus("201");
+            query.setRows(100);
+            cardGroupInfoGoodsService.page(query);
+        } catch (Exception ignored) {
+        }
+    }
+
+    private void poolPrepare() {
+        for (int i = 0; i < 30; i++) {
+            try (Connection connection = dataSource.getConnection();
+                 Statement statement = connection.createStatement()) {
+                // 执行简单的查询,确保连接可用
+                // 连接会在try块结束时自动关闭
+                statement.execute("SELECT 1");
+
+            } catch (SQLException ignored) {
+            }
+        }
+    }
+
+    private void indexPrepare() {
+        try (Connection connection = dataSource.getConnection();
+             Statement statement = connection.createStatement()) {
+            for (String table : tables) {
+                // 执行简单的查询,确保连接可用
+                // 连接会在try块结束时自动关闭
+                statement.execute("SELECT id FROM " + table + " ORDER BY id DESC LIMIT 1000");
+                statement.execute("SELECT * FROM " + table + " LIMIT 1000");
+            }
+
+            statement.execute("SELECT id,username FROM  app_base_user  ORDER BY username LIMIT 1000");
+
+            statement.execute("SELECT to_userid FROM  tzy_sys_notice_record  ORDER BY to_userid DESC LIMIT 1000");
+
+            statement.execute("SELECT user_id FROM  app_user_card_record  where status='0' and user_id>0 ORDER BY user_id DESC LIMIT 1000");
+            statement.execute("SELECT order_id FROM  app_user_card_record  where  order_id >0 ORDER BY order_id DESC LIMIT 1000");
+            statement.execute("SELECT card_id FROM  app_user_card_record  where  card_id >0 ORDER BY card_id DESC LIMIT 1000");
+
+            statement.execute("SELECT merchant_id FROM  tzy_card_base_info where  merchant_id >0  ORDER BY merchant_id DESC LIMIT 1000");
+
+            statement.execute("SELECT user_id FROM  card_group_order_info  ORDER BY user_id DESC LIMIT 1000");
+            statement.execute("SELECT group_info_id FROM  card_group_order_info  ORDER BY group_info_id DESC LIMIT 1000");
+            statement.execute("SELECT merchant_id FROM  card_group_order_info  ORDER BY merchant_id DESC LIMIT 1000");
+
+            statement.execute("SELECT min(user_id),max(user_id) FROM  card_group_order_info");
+            statement.execute("SELECT min(group_info_id),max(group_info_id) FROM  card_group_order_info");
+            statement.execute("SELECT min(merchant_id),max(merchant_id) FROM  card_group_order_info");
+
+            statement.execute("SELECT order_id FROM  order_list  ORDER BY order_id DESC LIMIT 1000");
+            statement.execute("SELECT sku_id FROM  order_list  where sku_id >0 ORDER BY sku_id DESC LIMIT 1000");
+            statement.execute("SELECT spu_id FROM  order_list where spu_id> 0 ORDER BY spu_id DESC LIMIT 1000");
+
+            statement.execute("SELECT min(order_id),max(order_id) FROM  order_list");
+            statement.execute("SELECT min(sku_id),max(sku_id) FROM  order_list");
+            statement.execute("SELECT min(spu_id),max(spu_id) FROM  order_list");
+
+            statement.execute("SELECT user_id FROM  card_group_goods  ORDER BY user_id DESC LIMIT 1000");
+            statement.execute("SELECT user_order_id FROM  card_group_goods  ORDER BY user_order_id DESC LIMIT 1000");
+            statement.execute("SELECT group_info_id FROM  card_group_goods  ORDER BY group_info_id DESC LIMIT 1000");
+
+            statement.execute("SELECT min(group_info_id),max(group_info_id) FROM  card_group_goods");
+            statement.execute("SELECT min(user_order_id),max(user_order_id) FROM  card_group_goods");
+            statement.execute("SELECT min(user_id),max(user_id) FROM  card_group_goods");
+
+            statement.execute("SELECT group_info_id FROM  card_group_lives_config  ORDER BY group_info_id DESC LIMIT 1000");
+
+            statement.execute("SELECT merchant_id FROM  card_group_info  ORDER BY merchant_id DESC LIMIT 1000");
+            statement.execute("SELECT id,status,merchant_id FROM  card_group_info where  status = 201 LIMIT 1000");
+
+        } catch (Exception e) {
+            log.error("db index init error", e);
+        }
+    }
+}

+ 38 - 0
poyi-app/src/main/java/com/tzy/config/DruidMetricsConfiguration.java

@@ -0,0 +1,38 @@
+package com.tzy.config;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import io.micrometer.core.instrument.MeterRegistry;
+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;
+
+    @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
poyi-app/src/main/java/com/tzy/config/MetricsConfig.java

@@ -0,0 +1,36 @@
+package com.tzy.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);//300秒输出一次
+            }
+
+            @Override
+            public String get(String key) {
+                return null;
+            }
+        }, Clock.SYSTEM);
+    }
+
+
+    @Bean
+    public MeterRegistryCustomizer<MeterRegistry> configurer(@Value("${tzy.name}") String applicationName) {
+        return (registry) -> registry.config().commonTags("application", applicationName);
+    }
+}

+ 453 - 0
poyi-app/src/main/java/com/tzy/config/MqConfig.java

@@ -0,0 +1,453 @@
+package com.tzy.config;
+
+import com.tzy.common.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 Binding bindingDirect() {
+        return BindingBuilder.bind(TestDirectQueue()).to(TestDirectExchange()).with("test");
+    }
+
+    //@Bean
+    //public Queue TestDirectQueue2() {
+    //    return new Queue(MqConstans.TEST_QUEUE+2,true);
+    //}
+
+    /**
+     * 绑定  将队列和交换机绑定, 并设置用于匹配键:test
+     * 星号(*) :只能匹配一个单词
+     * 井号(#):可以匹配0个或多个单词
+     * @return
+     */
+    //@Bean
+    //public Binding bindingDirect() {
+    //    return BindingBuilder.bind(TestDirectQueue()).to(TestTopicExchange()).with("test");
+    //}
+    //@Bean
+    //public Binding bindingDirect2() {
+    //    return BindingBuilder.bind(TestDirectQueue2()).to(TestTopicExchange()).with("test.#");
+    //}
+
+    /**
+     * Topic交换机
+     *  return new DirectExchange("test_exchange",true,true);
+     * @return
+     */
+    //@Bean
+    //public TopicExchange TestTopicExchange() {
+    //    return new TopicExchange("exchange_test2");
+    //}
+
+    /**
+     * Direct交换机
+     *  return new DirectExchange("test_exchange",true,true);
+     * @return
+     */
+    @Bean
+    public DirectExchange TestDirectExchange() {
+        return new DirectExchange("exchange_test",true,false);
+    }
+
+    @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 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 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 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 Queue OrderExpiredQueue() {
+        return new Queue(MqConstans.QUEUE_ORDER_EXPIRED,true);
+    }
+
+    @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 Binding bindingDelayExchange()
+    {
+        return BindingBuilder.bind(OrderExpiredQueue()).to(delayExchange()).with(MqConstans.ROUTING_KEY_ORDER_EXPIRED).noargs();
+    }
+
+    @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 Queue groupAllocateGoodsQueue() {
+        return new Queue(MqConstans.QUEUE_GROUP_ALLOCATE_GOODS,true);
+    }
+
+    @Bean
+    public DirectExchange groupAllocateGoodsExchange() {
+        return new DirectExchange(MqConstans.EXCHANGE_GROUP_ALLOCATE_GOODS,true,false);
+    }
+
+    @Bean
+    public Binding bindingGroupAllocateGoodsDirect() {
+        return BindingBuilder.bind(groupAllocateGoodsQueue()).to(groupAllocateGoodsExchange()).with(MqConstans.ROUTING_KEY_GROUP_ALLOCATE_GOODS);
+    }
+
+    @Bean
+    public Queue groupGoodsEsQueue() {
+        return new Queue(MqConstans.QUEUE_GROUP_GOODS_SYNC_ES,true);
+    }
+
+    @Bean
+    public DirectExchange groupGoodsEsExchange() {
+        return new DirectExchange(MqConstans.EXCHANGE_GROUP_GOODS_SYNC_ES,true,false);
+    }
+
+    @Bean
+    public Binding bindingGroupGoodsEsDirect() {
+        return BindingBuilder.bind(groupGoodsEsQueue()).to(groupGoodsEsExchange()).with(MqConstans.ROUTING_KEY_GROUP_GOODS_SYNC_ES);
+    }
+
+    @Bean
+    public Queue syncUserWinCardQueue() {
+        return new Queue(MqConstans.QUEUE_SYNC_USER_WIN_CARD,true);
+    }
+
+    @Bean
+    public DirectExchange syncUserWinExchange() {
+        return new DirectExchange(MqConstans.EXCHANGE_SYNC_USER_WIN_CARD,true,false);
+    }
+
+    @Bean
+    public Binding bindingSyncUserWinDirect() {
+        return BindingBuilder.bind(syncUserWinCardQueue()).to(syncUserWinExchange()).with(MqConstans.ROUTING_KEY_SYNC_USER_WIN_CARD);
+    }
+
+    @Bean
+    public Queue orderAftAllocateQueue() {
+        return new Queue(MqConstans.QUEUE_ORDER_AFT_ALLOCATE, true);
+    }
+
+    @Bean
+    public DirectExchange orderAftAllocateExchange() {
+        return new DirectExchange(MqConstans.EXCHANGE_ORDER_AFT_ALLOCATE, true, false);
+    }
+
+    @Bean
+    public Binding bindingOrderAftAllocateDirect() {
+        return BindingBuilder.bind(orderAftAllocateQueue()).to(orderAftAllocateExchange()).with(MqConstans.ROUTING_KEY_ORDER_AFT_ALLOCATE);
+    }
+
+
+    @Bean
+    public Queue initUserMemberQueue() {
+        return new Queue(MqConstans.QUEUE_INIT_USER_USER_MEMBER, true);
+    }
+
+    @Bean
+    public DirectExchange initUserMemberExchange() {
+        return new DirectExchange(MqConstans.EXCHANGE_INIT_USER_MEMBER, true, false);
+    }
+
+    @Bean
+    public Binding bindingInitUserMemberDirect() {
+        return BindingBuilder.bind(initUserMemberQueue()).to(initUserMemberExchange()).with(MqConstans.ROUTING_KEY_INIT_USER_MEMBER);
+    }
+
+    @Bean
+    public Queue userPointJson() {
+        return new Queue(MqConstans.QUEUE_USER_POINT_JSON,true);
+    }
+
+    @Bean
+    public Binding bindingUserPointJsonDirect() {
+        return BindingBuilder.bind(userPointJson()).to(userPointExchange()).with(MqConstans.ROUTING_KEY_USER_POINT_JSON);
+    }
+
+
+    @Bean
+    public Queue appLiveConfigQueue() {
+        return new Queue(MqConstans.QUEUE_APP_LIVE_CONFIG,true);
+    }
+
+    @Bean
+    public CustomExchange appLiveConfigDelayExchange() {
+        Map<String, Object> args = new HashMap<>(1);
+        args.put("x-delayed-type", "direct");
+        return new CustomExchange(MqConstans.EXCHANGE_DELAYED_APP_LIVE_CONFIG, "x-delayed-message", true, false, args);
+    }
+
+    @Bean
+    public Binding bindingAppLiveConfigDelayExchange()
+    {
+        return BindingBuilder.bind(appLiveConfigQueue()).to(appLiveConfigDelayExchange()).with(MqConstans.ROUTING_KEY_APP_LIVE_CONFIG).noargs();
+    }
+
+
+    @Bean
+    public Queue autoAddActQueue() {
+        return new Queue(MqConstans.QUEUE_LUCKY_ACT_AUTO_ADD, true);
+    }
+
+    @Bean
+    public DirectExchange autoAddActExchange() {
+        return new DirectExchange(MqConstans.EXCHANGE_LUCKY_ACT_AUTO_ADD, true, false);
+    }
+
+    @Bean
+    public Binding bindingAutoAddActDirect() {
+        return BindingBuilder.bind(autoAddActQueue()).to(autoAddActExchange()).with(MqConstans.ROUTING_KEY_LUCKY_ACT_AUTO_ADD);
+    }
+
+
+    @Bean
+    public Queue userListActQueue() {
+        return new Queue(MqConstans.QUEUE_USER_LIST_ACT, true);
+    }
+
+    @Bean
+    public DirectExchange userListActExchange() {
+        return new DirectExchange(MqConstans.EXCHANGE_USER_LIST_ACT, true, false);
+    }
+
+    @Bean
+    public Binding bindingUserListActQueueDirect() {
+        return BindingBuilder.bind(userListActQueue()).to(userListActExchange()).with(MqConstans.ROUTING_KEY_USER_LIST_ACT);
+    }
+
+    @Bean
+    public Queue merchantNotifyQueue() {
+        return new Queue(MqConstans.QUEUE_MERCHANT_NOTIFY, true);
+    }
+
+    @Bean
+    public Queue communityNotifyQueue() {
+        return new Queue(MqConstans.QUEUE_COMMUNITY_NOTIFY, true);
+    }
+
+    @Bean
+    public Queue actQueue() {
+        return new Queue(MqConstans.QUEUE_GROUP_ORDER_ACT, true);
+    }
+
+    @Bean
+    public Queue giftCardQueue() {
+        return new Queue(MqConstans.QUEUE_GROUP_GIFT_CARD, true);
+    }
+
+    @Bean
+    public Queue initUserGiftCardQueue() {
+        return new Queue(MqConstans.QUEUE_INIT_USER_GIFT_CARD, true);
+    }
+
+
+    // @Bean
+    // public Queue TestDirectQueueV2() {
+    //     return new Queue("TestDirectQueueV2");
+    // }
+    // @Bean
+    // public Queue TestDirectQueueV3() {
+    //     return new Queue("TestDirectQueueV3");
+    // }
+    // @Bean
+    // public Queue actDrawOrderQueue() {
+    //     return new Queue(MqConstans.QUEUE_ORDER_DRAW_CARD, true);
+    // }
+    // @Bean
+    // public Queue drawOrderCallbackQueue() {
+    //     return new Queue(MqConstans.QUEUE_DRAW_ORDER_CALLBACK, true);
+    // }
+    // @Bean
+    // public Binding bindingTestDirectV2() {
+    //     return BindingBuilder.bind(TestDirectQueueV2()).to(testTopicExchangeV3()).with("test");
+    // }
+    // @Bean
+    // public Binding bindingTestDirectV3() {
+    //     return BindingBuilder.bind(TestDirectQueueV3()).to(testTopicExchangeV3()).with("test.#");
+    // }
+    // @Bean
+    // public TopicExchange testTopicExchangeV3() {
+    //     return new TopicExchange("TestTopicExchangeV3");
+    // }
+
+    @Bean
+    public Queue orderOverQueue() {
+        return new Queue(MqConstans.QUEUE_ORDER_OVER, true);
+    }
+
+    @Bean
+    public Queue asyncRefundQueue() {
+        return new Queue(MqConstans.QUEUE_ASYNC_REFUND, true);
+    }
+
+
+    @Bean
+    public Queue luckyBagQueue() {
+        return new Queue(MqConstans.QUEUE_LUCKY_BAG_EXPIRED,true);
+    }
+
+    @Bean
+    public CustomExchange luckyBagDelayExchange() {
+        Map<String, Object> args = new HashMap<>(1);
+        args.put("x-delayed-type", "direct");
+        return new CustomExchange(MqConstans.EXCHANGE_DELAYED_LUCKY_BAG_EXPIRED, "x-delayed-message", true, false, args);
+    }
+
+    @Bean
+    public Binding bindingLuckyBagDelayExchange()
+    {
+        return BindingBuilder.bind(luckyBagQueue()).to(luckyBagDelayExchange()).with(MqConstans.ROUTING_KEY_LUCKY_BAG_EXPIRED).noargs();
+    }
+
+    @Bean
+    public Queue userBrowseRecordQueue() {
+        return new Queue(MqConstans.QUEUE_USER_BROWSE_RECORD,true);
+    }
+
+    @Bean
+    public CustomExchange userBrowseRecordDelayExchange() {
+        Map<String, Object> args = new HashMap<>(1);
+        args.put("x-delayed-type", "direct");
+        return new CustomExchange(MqConstans.EXCHANGE_USER_BROWSE_RECORD, "x-delayed-message", true, false, args);
+    }
+
+    @Bean
+    public Binding bindingUserBrowseRecordDelayExchange() {
+        return BindingBuilder.bind(userBrowseRecordQueue()).to(userBrowseRecordDelayExchange()).with(MqConstans.ROUTING_KEY_USER_BROWSE_RECORD).noargs();
+    }
+}

+ 36 - 0
poyi-app/src/main/java/com/tzy/config/WebConfigurerAdapter.java

@@ -0,0 +1,36 @@
+package com.tzy.config;
+
+import com.tzy.sportcard.api.log.LogInterceptor;
+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();
+    }
+
+//    @Bean
+//    public JsonParamArgumentResolver jsonParamArgumentResolver() {
+//        return new JsonParamArgumentResolver();
+//    }
+ 
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(logInterceptor());
+        //可以具体制定哪些需要拦截,哪些不拦截,其实也可以使用自定义注解更灵活完成
+//                .addPathPatterns("/**")
+//                .excludePathPatterns("/test.html");
+    }
+
+//    @Override
+//    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
+//        argumentResolvers.add(jsonParamArgumentResolver());
+//    }
+
+
+
+}

+ 674 - 0
poyi-app/src/main/java/com/tzy/controller/CommonController.java

@@ -0,0 +1,674 @@
+package com.tzy.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.tzy.annotation.ApiLog;
+import com.tzy.annotation.RequireRoles;
+import com.tzy.common.config.QuerySql;
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.common.constant.Constants;
+import com.tzy.common.core.controller.BaseController;
+import com.tzy.common.core.domain.entity.SysDictData;
+import com.tzy.common.dto.InDto;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.dto.pay.PaymentChannel;
+import com.tzy.common.enums.BusinessType;
+import com.tzy.common.enums.NotifyNameEnum;
+import com.tzy.common.utils.DateUtils;
+import com.tzy.common.utils.ServletUtils;
+import com.tzy.common.utils.StringUtils;
+import com.tzy.common.utils.UserType;
+import com.tzy.common.utils.bean.DozerUtils;
+import com.tzy.common.utils.http.forest.CommonForestClient;
+import com.tzy.common.utils.security.Md5Utils;
+import com.tzy.coupon.card.domain.AppUserCardRecord;
+import com.tzy.coupon.card.domain.TzyCardBaseInfo;
+import com.tzy.coupon.card.domain.TzyCardTaskRemind;
+import com.tzy.coupon.card.service.ITzyCardBaseInfoService;
+import com.tzy.coupon.card.service.ITzyCardTaskRemindService;
+import com.tzy.dto.AppActDTO;
+import com.tzy.dto.local.ResultDTO;
+import com.tzy.express.service.ExpressService;
+import com.tzy.framework.util.RedisUtils;
+import com.tzy.pojo.app.AppActConfig;
+import com.tzy.sportcard.api.domain.AppNotifyConfig;
+import com.tzy.sportcard.api.domain.AppUserInfoDto;
+import com.tzy.sportcard.api.domain.CouponInfo;
+import com.tzy.sportcard.api.dto.merchant.MerchantScoreDTO;
+import com.tzy.sportcard.api.dto.merchant.MerchantSimpleDTO;
+import com.tzy.sportcard.api.mapper.MerchantApiMapper;
+import com.tzy.sportcard.api.service.*;
+import com.tzy.sportcard.base.service.CommonCacheService;
+import com.tzy.sportcard.base.service.CommonConsumeRankService;
+import com.tzy.sportcard.base.service.ITzyPlayerInfoService;
+import com.tzy.sportcard.dto.CommonConsumeRankParamDTO;
+import com.tzy.sportcard.dto.TzyPlayerInfoDTO;
+import com.tzy.sportcard.group.dto.ExpressCourierNumDTO;
+import com.tzy.sportcard.group.service.ICardGroupOrderInfoService;
+import com.tzy.util.BarcodeUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.elasticsearch.common.Strings;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.DigestUtils;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import org.teasoft.bee.osql.PreparedSql;
+import org.teasoft.bee.osql.SuidRich;
+
+import javax.annotation.Resource;
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
+import java.net.URLEncoder;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * @author by po'yi
+ * @Classname RongCloudController
+ * @Description 融云api
+ * @Date 2022/2/28 11:56
+ */
+@Slf4j
+@Api("通用api")
+@RestController
+@RequestMapping("/api/common")
+public class CommonController extends BaseController {
+
+	@Value("${suolink.appKey:634586a92dfbd60cb30a7be89e@c758d0a2fa07d96b8471757554333ed4}")
+	private String suolinkKey;
+	@Value("${suolink.domainUrl:i6q.cn}")
+	private String domainUrl;
+	@Autowired
+	private PreparedSql preparedSql;
+	@Autowired
+	private SuidRich suidRich;
+	@Autowired
+	private MineApiService mineApiService;
+	@Resource
+	private CommonForestClient commonForestClient;
+	@Autowired
+	private RedisUtils redisUtils;
+	@Autowired
+	private MerchantApiService merchantApiService;
+	@Resource
+	private AsyncAppService asyncAppService;
+	@Resource
+	private IAppNotifyConfigService notifyConfigService;
+	@Autowired
+	private ITzyCardBaseInfoService cardBaseInfoService;
+
+	private final String linkReqUrl = "http://api.suolink.cn/api.htm";
+
+	@Resource private CommonConsumeRankService commonConsumeRankService;
+
+	@Resource private CommonCacheService commonCacheService;
+
+	@Resource private ITzyPlayerInfoService playerInfoService;
+
+	@Resource private ICardGroupOrderInfoService cardGroupOrderInfoService;
+	@Autowired
+	private ITzyCardTaskRemindService cardTaskRemindService;
+	@Resource
+	private TzyMerchantAssessService tzyMerchantAssessService;
+	@Autowired
+	private ExpressService expressService;
+
+	@ApiLog(title = "生成短链", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@RequestMapping(value = "/{version}/suolink", method = RequestMethod.POST)
+	@ApiVersion(1.0)
+	@ApiOperation("生成短链")
+	public OutDTO getSuolink(@RequestBody InDto inDto) throws UnsupportedEncodingException {
+		String url = inDto.getString("url");
+		if (StringUtils.isEmpty(url)) {
+			return OutDTO.error500("url为空");
+		}
+		String key1="app_suo_link_cache";
+		String key2= Md5Utils.hash(url);
+		Object linkUrlCache = redisUtils.hget(key1, key2);
+		if(linkUrlCache!=null){
+			return OutDTO.ok().put("linkUrl", linkUrlCache);
+		}
+		StringBuffer reqUrl = new StringBuffer().append(linkReqUrl).append("?url=")
+				.append(URLEncoder.encode(inDto.getString("url"), Constants.UTF8)).append("&key=")
+				.append(suolinkKey).append("&expireDate=2030-12-31").append("&domain=").append(domainUrl);
+		String linkUrl = commonForestClient.sendGet(reqUrl.toString());
+		redisUtils.hset(key1, key2,linkUrl);
+		return OutDTO.ok().put("linkUrl", linkUrl);
+
+	}
+
+
+	@ApiLog(title = "获取优惠劵信息", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@RequestMapping(value = "/{version}/getCouponByIds", method = RequestMethod.POST)
+	@ApiVersion(1.0)
+	@ApiOperation("获取优惠劵信息")
+	public OutDTO getCouponByIds(@RequestBody InDto inDto) {
+		if (StringUtils.isEmpty(inDto.getString("ids"))) {
+			return OutDTO.error500("id为空");
+		}
+		List<TzyCardBaseInfo> coupons = Arrays.asList(inDto.getString("ids").split(","))
+				.stream().map(id -> getCoupon(Long.valueOf(id))).collect(Collectors.toList());
+		return OutDTO.ok().put("coupons", coupons);
+	}
+
+
+	@ApiLog(title = "获取开屏广告等活动", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@RequestMapping(value = "/{version}/act", method = RequestMethod.POST)
+	@ApiVersion(1.0)
+	@ApiOperation("获取开屏广告等活动")
+	public OutDTO getAct(@RequestBody InDto inDto) {
+		//优惠券发放活动,查询发放活动提醒表,
+		log.info("开屏广告查询 userId {}",inDto.getUserId());
+		List<AppActDTO> appActDTOList=new ArrayList<>();
+		List<TzyCardTaskRemind> cardTaskRemindList = cardTaskRemindService.getRemindByUserId(inDto.getUserId());
+		if (!CollectionUtils.isEmpty(cardTaskRemindList)){
+			for (TzyCardTaskRemind tzyCardTaskRemind : cardTaskRemindList) {
+				AppActDTO appActDTO=new AppActDTO();
+				appActDTO.setActImg(tzyCardTaskRemind.getImgUrl());
+				appActDTO.setImgType("0");
+				appActDTO.setActUrl("/pageC/myCoupon/couponList");
+				appActDTO.setClickType(0);
+				appActDTO.setCouponIds("10");
+				appActDTO.setLastTime(5);
+
+				appActDTOList.add(appActDTO);
+				//更新提醒状态
+				cardTaskRemindService.updateCardTaskRemind(tzyCardTaskRemind.getId(),1);
+			}
+			log.info("优惠券提醒list:{}",appActDTOList);
+		}
+		List<AppActConfig> actList = getAppActConfigs(inDto.getUserId());
+		if (actList.isEmpty()) {
+			return OutDTO.ok().put("page_act",appActDTOList);
+		}
+		Map<String, List<AppActConfig>> groupActs = actList.stream().collect(Collectors.groupingBy(AppActConfig::getSubType));
+		//开屏广告
+		List<AppActConfig> open_ad = groupActs.get("open_ad");
+		//首页活动
+		List<AppActConfig> firstPageActs = groupActs.get("first_page");
+		List<AppActDTO> pageActs;
+		if (firstPageActs != null) {
+			pageActs = firstPageActs.stream().filter(act -> checkAct(act, inDto.getUserId()))
+					.map(act -> DozerUtils.map(act, AppActDTO.class)).collect(Collectors.toList());
+		}else {
+			pageActs=new ArrayList<>();
+		}
+		pageActs.addAll(appActDTOList);
+		AppActDTO ad = null;
+		if (open_ad != null && !open_ad.isEmpty()) {
+			ad = DozerUtils.map(open_ad.get(0), AppActDTO.class);
+		}
+
+		return OutDTO.ok().put("open_ad", ad).put("page_act", pageActs);
+	}
+
+	private List<AppActConfig> getAppActConfigs(Integer userId) {
+		Object actCache = redisUtils.get(Constants.APP_ACT_CACHE);
+		List<AppActConfig> actList;
+		if (actCache == null) {
+			String sql = QuerySql.getQuerySql("com.tzy.pojo.app.AppActConfig.getAct");
+			actList = preparedSql.selectSomeField(sql, new AppActConfig(), new Object[]{});
+			redisUtils.set(Constants.APP_ACT_CACHE, actList);
+		} else {
+			actList = (List<AppActConfig>) actCache;
+		}
+		if (!actList.isEmpty()) {
+			int currentHour = DateUtils.getCurrentHour();
+			Date now = new Date();
+			actList = actList.stream().filter(act -> {
+				if (now.before(act.getStartTime()) || now.after(act.getEndTime())) {
+					return false;
+				}
+				if (currentHour < act.getStartHour() || currentHour >= act.getEndHour()) {
+					return false;
+				}
+				if (act.getCatId() != null && act.getCatId() > 0) {
+					List<Long> userIds = mineApiService.getUserIdByCatId(act.getCatId());
+					return userId != null && userIds.contains(userId.longValue());
+				}
+				return true;
+			}).collect(Collectors.toList());
+		}
+		return actList;
+	}
+
+	private TzyCardBaseInfo getCoupon(Long id) {
+		if (id == null) {
+			return null;
+		}
+		TzyCardBaseInfo condition = new TzyCardBaseInfo();
+		condition.setId(id);
+		return suidRich.selectOne(condition);
+	}
+
+	private boolean checkAct(AppActConfig act, Integer userId) {
+		if(userId==null||userId<1){
+			return true;
+		}
+		boolean isRemind=act.getRemindTime() > 0;
+		String key = "act_remind_cache_" + act.getId() + "_userid_" + userId;
+		if (isRemind && redisUtils.hasKey(key)) {
+			//限制时间内不再提示
+			return false;
+		}
+		boolean needLogin = act.getHistoryLimitDay() > 0 || act.getUserGrowth() > 0;
+		//判断条件
+		if (!needLogin) {
+			if (isRemind) {
+				redisUtils.set(key, 1, act.getRemindTime() * 3600);
+			}
+			return true;
+		}
+
+		if (needLogin && userId == null) {
+			return false;
+		}
+
+		boolean buyFlag = true;
+		if (act.getHistoryLimitDay() > 0) {
+			String limitDay = " and (now() - create_time::timestamp < interval '" + act.getHistoryLimitDay() + " day')";
+			String sql = QuerySql.getQuerySql("com.tzy.pojo.app.AppActConfig.getUserOrderCount");
+			sql += limitDay;
+			String orderCount = preparedSql.selectFun(sql, new Object[]{userId});
+			if (Integer.parseInt(orderCount) == 0) {
+				buyFlag = false;
+			}
+		}
+
+		boolean growthFlag = true;
+		if (act.getUserGrowth() > 0) {
+			AppUserInfoDto user = mineApiService.searchUserInfoById(userId);
+			if (user.getGrowthNum() < act.getUserGrowth() * 100) {
+				growthFlag = false;
+			}
+		}
+		boolean reminderFlag = act.getOp() == 0 ? buyFlag || growthFlag : buyFlag && growthFlag;
+		if (reminderFlag && StringUtils.isNotEmpty(act.getCouponIds())) {
+			String sql = "SELECT count(0) FROM app_user_card_record WHERE user_id=" + userId + " and card_id in (" + act.getCouponIds() + ")";
+			String couponCount = preparedSql.selectFun(sql, new Object[]{});
+			if (Integer.parseInt(couponCount) > 0) {
+				return false;
+			}
+		}
+
+		if (reminderFlag && isRemind) {
+			redisUtils.set(key, 1, act.getRemindTime() * 3600);
+		}
+
+		return reminderFlag;
+	}
+
+	@ApiLog(title = "查询活动优惠券",businessType = BusinessType.UPDATE,indto = "{{inDto}}")
+	@ResponseBody
+	@RequestMapping(value = "/act/coupon", method = RequestMethod.POST)
+	public OutDTO findActCoupon(@RequestBody InDto inDto){
+		if (null == inDto) {
+			return OutDTO.error500( "参数不能为空");
+		}
+		String actType=inDto.getString("actType");
+		if(StringUtils.isEmpty(actType)){
+			actType="双11";
+		}
+		Object merchantId = inDto.get("merchantId");
+		AppUserCardRecord appUserCardRecord = new AppUserCardRecord();
+		appUserCardRecord.setSport(inDto.getString("sport"));
+		appUserCardRecord.setActType(actType);
+		appUserCardRecord.setPage(inDto.getPageNo());
+		appUserCardRecord.setRows(inDto.getPageSize());
+		appUserCardRecord.setMerchantName(inDto.getString("merchantName"));
+		if(merchantId!=null){
+			appUserCardRecord.setMerchantId((Integer)merchantId);
+		}
+		if(StringUtils.isNotEmpty(inDto.getString("keyword"))){
+			appUserCardRecord.setFromCategory(inDto.getString("keyword"));
+		}
+		if(inDto.getUserId()!=null){
+			appUserCardRecord.setUserId(inDto.getUserId().longValue());
+		}
+		// 排序
+		Integer orderType = Integer.valueOf(inDto.getData().get("orderType").toString());
+		String sidx = "cbi.create_time DESC";
+		// 排序类型:1新到券、2快过期、3面额从大到小、4折扣从大到小
+		switch (orderType){
+			case 1: // 新到券
+				//sidx = " cbi.create_time DESC";
+				break;
+			case 2: // 前端冲突,弃用
+				//sidx = " AND (aucr.expiry_time - now()::timestamp < interval '24 hour')  ORDER BY aucr.expiry_time DESC";
+				break;
+			case 3:  // 面额从大到小
+				sidx = " cbi.discount DESC ";
+				break;
+			case 4:  // 折扣率从大到小
+				sidx = " discountRate ASC ";
+				break;
+			case 5: // 快领完
+				sidx = " num ASC ";
+				break;
+			default:
+				//sidx = " case when (cbi.max_claim - cbi.received )>0 and aucr.user_id is null THEN 1 ELSE 0 end desc ,cbi.discount DESC";
+				break;
+		}
+		appUserCardRecord.setSidx(sidx);
+		List<CouponInfo> couponInfos = mineApiService.findActCoupon(appUserCardRecord);
+
+		return OutDTO.ok().put("couponInfos",couponInfos);
+	}
+
+	@ApiLog(title = "查询参加优惠劵活动的商家",businessType = BusinessType.UPDATE,indto = "{{inDto}}")
+	@ResponseBody
+	@RequestMapping(value = "/act/coupon/merchant", method = RequestMethod.POST)
+	public OutDTO findActMerchant(@RequestBody InDto inDto){
+		if (null == inDto) {
+			return OutDTO.error500( "参数不能为空");
+		}
+		String actType=inDto.getString("actType");
+		if(StringUtils.isEmpty(actType)){
+			actType="双11";
+		}
+		List<MerchantSimpleDTO> merchantInfos=merchantApiService.findActMerchant(actType,inDto.getString("name"));
+		return OutDTO.ok().put("merchantInfos",merchantInfos);
+	}
+
+	@ApiLog(title = "查询活动消费排行榜",businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@PostMapping("/consumeRank")
+	public OutDTO consumeRank(@RequestBody InDto inDto){
+		if (null == inDto) {
+			return OutDTO.error500( "参数不能为空");
+		}
+
+		List<SysDictData> sysDictDataList = commonCacheService.getCommonDictData("consume_rank", null, Constants.STATUS_OK, null, 600);
+		//{"merchantId":85,"startTime":"2022-11-24","endTime":"2022-12-06","hotType":"2022双11主,2022双11分"}
+		if (CollectionUtils.isEmpty(sysDictDataList)) {
+			return OutDTO.error500( "活动不存在");
+		}
+		String paramStr = sysDictDataList.get(0).getDictValue();
+		com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(paramStr);
+		CommonConsumeRankParamDTO dto = JSONObject.toJavaObject(jsonObject, CommonConsumeRankParamDTO.class);
+		Object hotType = jsonObject.get("hotType");
+		if(null != hotType) {
+			dto.setHotTypes(hotType.toString().split(","));
+		}
+		return OutDTO.ok().put("data", commonConsumeRankService.consumeRank(dto, inDto.getUserId()));
+	}
+
+	@ApiLog(title = "根据球员姓名查询球员",businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@PostMapping("/getPlayerByNames")
+	public OutDTO getPlayerByNames(@RequestBody InDto inDto){
+		if (null == inDto) {
+			return OutDTO.error500( "参数不能为空");
+		}
+		List<TzyPlayerInfoDTO> playerInfoList = playerInfoService
+				.getPlayerInfoByNames(inDto.getString("name"), inDto.getString("sport"));
+		return OutDTO.ok().put("playerInfoList", playerInfoList);
+	}
+
+	/**
+	 * 查询订单物流轨迹
+	 */
+	@ApiLog(title = "根据物流单号公司查询物流轨迹v3", businessType = BusinessType.SEARCH)
+	@PostMapping( "/order/express3")
+	@ResponseBody
+	public OutDTO getOrderExpressInfoV3(@RequestBody InDto inDto) {
+		mineApiService.checkUserNew(inDto);
+		String courierNum = inDto.getString("courierNum"); // 快递单号
+		if (StringUtils.isEmpty(courierNum)) {
+			return OutDTO.error500("参数[courierNum]不能为空");
+		}
+		String curierCompany = inDto.getString("curierCompany"); // 快递公司
+		if (StringUtils.isEmpty(curierCompany)) {
+			return OutDTO.error500("参数[curierCompany]不能为空");
+		}
+		String phone = inDto.getString("phone"); // 手机号
+		ExpressCourierNumDTO courierDTO = new ExpressCourierNumDTO(0, courierNum, curierCompany, phone);
+
+		if (curierCompany.contains("顺丰")) {
+			if (StringUtils.isEmpty(phone)) {
+				return OutDTO.error500("参数[phone]不能为空");
+			}
+			if(courierNum.startsWith("SF")) {
+				return OutDTO.ok().put("expressData", cardGroupOrderInfoService.getSFExpressInfo(courierDTO));
+			}else {
+				return OutDTO.ok().put("expressData", null);
+			}
+		} else {
+			return OutDTO.ok().put("expressData", cardGroupOrderInfoService.getOtherExpressInfo(courierDTO));
+		}
+	}
+
+
+	/**
+	 * 查询订单物流轨迹
+	 */
+	@ApiLog(title = "根据物流单号公司查询物流轨迹v4", businessType = BusinessType.SEARCH)
+	@PostMapping( "/order/v4/express")
+	@ResponseBody
+	public OutDTO getOrderExpressInfoV4(@RequestBody InDto inDto) {
+		mineApiService.checkUserNew(inDto);
+		String courierNum = inDto.getString("courierNum"); // 快递单号
+		if (StringUtils.isEmpty(courierNum)) {
+			return OutDTO.error500("参数[courierNum]不能为空");
+		}
+		String curierCompany = inDto.getString("curierCompany"); // 快递公司
+		if (StringUtils.isEmpty(curierCompany)) {
+			return OutDTO.error500("参数[curierCompany]不能为空");
+		}
+		String phone = inDto.getString("phone"); // 手机号
+		ExpressCourierNumDTO courierDTO = new ExpressCourierNumDTO(0, courierNum, curierCompany, phone);
+
+		//2025年8月25日 修改 ,顺丰时 查询快递记录表是否是一键发货订单 如果是一键发货订单,如果是sfgf 调用顺丰获取路由接口
+		if(curierCompany.contains("顺丰")) {
+			if (StringUtils.isEmpty(phone)) {
+				return OutDTO.error500("参数[phone]不能为空");
+			}
+			if(courierNum.startsWith("SF")) {
+				return OutDTO.ok().put("expressData", expressService.getCourierRoute(phone,courierNum));
+			}else {
+				return OutDTO.ok().put("expressData", null);
+			}
+		}else{
+			return OutDTO.ok().put("expressData", cardGroupOrderInfoService.getOtherExpressInfo(courierDTO));
+		}
+	}
+
+	@ApiLog(title = "消息推送",businessType = BusinessType.INSERT)
+	@ResponseBody
+	@PostMapping("/push")
+	public OutDTO push(@RequestBody InDto inDto){
+		if(inDto.existKeyString("userId")){
+			Integer userId = Integer.parseInt(inDto.getString("userId"));
+			// 验证用户是否开启聊天通知
+			List<AppNotifyConfig> configs = notifyConfigService.selectNotifyConfigByUserId(userId);
+			if(!CollectionUtils.isEmpty(configs)){
+				Optional<AppNotifyConfig> optional = configs.stream()
+						.filter(config -> NotifyNameEnum.CHAT.getType().equals(config.getMsgType()) && config.getStatus() == 1)
+						.findFirst();
+				if(optional.isPresent()) {
+					AppUserInfoDto appUserInfoDto = mineApiService.searchUserInfoById(userId);
+					//AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+					String userName = inDto.getString("userName");
+					String message = inDto.getString("message");
+					List<String> params = Lists.newArrayList();
+					params.add(userName);
+					params.add(message);
+					Map<String, String> extrasMap = Maps.newHashMap();
+					extrasMap.put("url", inDto.getString("url"));
+					asyncAppService.jpush(14, Constants.JPUSH_TYPE_ID, Collections.singletonList(appUserInfoDto.getSmsRegisterId()), params, extrasMap);
+				}
+			}
+			return OutDTO.ok();
+		}
+		else if(inDto.existKeyString("merchantId")){
+			//查询商家账号对应的开启聊天通知的SmsRegisterId列表
+			List<AppUserInfoDto> SmsRegisterIdList = merchantApiService.getSmsRegisterIdsByMerchantId(Integer.parseInt(inDto.getString("merchantId")));
+			List<Integer> userIDs = SmsRegisterIdList.stream().map(AppUserInfoDto::getId).collect(Collectors.toList());
+
+			//由于通知设置的存储结构限制,还需逐个判断是否能发到具体用户上
+			List<AppNotifyConfig> chatConfigs = notifyConfigService.selectChatNotifyConfigByUserIds(userIDs);
+
+			if(!CollectionUtils.isEmpty(SmsRegisterIdList)){
+				SmsRegisterIdList.forEach(userInfo->{
+					Optional<AppNotifyConfig> optional = chatConfigs.stream()
+							.filter(config -> NotifyNameEnum.CHAT.getType().equals(config.getMsgType()) && config.getUserId()==userInfo.getId().longValue() && config.getStatus() == 1)
+							.findFirst();
+					if(optional.isPresent()) {
+						String userName = inDto.getString("userName");
+						String message = inDto.getString("message");
+						List<String> params = Lists.newArrayList();
+						params.add(userName);
+						params.add(message);
+						Map<String, String> extrasMap = Maps.newHashMap();
+						extrasMap.put("url", inDto.getString("url"));
+						asyncAppService.jpush(14, Constants.JPUSH_TYPE_ID, Collections.singletonList(userInfo.getSmsRegisterId()), params, extrasMap);
+					}
+				});
+			}
+			return OutDTO.ok();
+		}
+		else if(inDto.existKeyString("hscs")){
+			List<SysDictData> sysDictDataList = commonCacheService.getCommonDictData("IMAdmin", null, Constants.STATUS_OK, "IMAdmin", 600);
+			List<String> accountName = sysDictDataList.stream().map(dict -> dict.getDictValue()).collect(Collectors.toList());
+			List<Long> userids = sysDictDataList.stream().map(dict -> Long.parseLong(dict.getDictLabel())).collect(Collectors.toList());
+			//查询客服的userid
+			List<String> SmsRegisterIdList = Stream.concat(mineApiService.getAllIMAdminSmsRegisterIdListByUsername(accountName).stream(), mineApiService.getAllIMAdminSmsRegisterIdList(userids).stream())
+					.distinct()
+					.collect(Collectors.toCollection(ArrayList::new));
+			// 客服不校验聊天通知
+			if(!CollectionUtils.isEmpty(SmsRegisterIdList)){
+					String userName = inDto.getString("userName");
+					String message = inDto.getString("message");
+					List<String> params = Lists.newArrayList();
+					params.add(userName);
+					params.add(message);
+					Map<String, String> extrasMap = Maps.newHashMap();
+					extrasMap.put("url", inDto.getString("url"));
+					asyncAppService.jpush(14, Constants.JPUSH_TYPE_ID, SmsRegisterIdList, params, extrasMap);
+			}
+			return OutDTO.ok();
+		}else if(inDto.existKeyString("operation")){
+			List<SysDictData> sysDictDataList = commonCacheService.getCommonDictData("operationUserId", null, Constants.STATUS_OK, "operationUserId", 600);
+			List<String> useridStr = JSON.parseObject( sysDictDataList.get(0).getDictValue(),List.class);
+			List<Long> userids = useridStr.stream().map(Long::parseLong).collect(Collectors.toList());
+			//查询运营的userid
+			List<String> SmsRegisterIdList =  mineApiService.getAllIMAdminSmsRegisterIdList(userids).stream()
+					.distinct()
+					.collect(Collectors.toCollection(ArrayList::new));
+			// 运营不校验聊天通知
+			if(!CollectionUtils.isEmpty(SmsRegisterIdList)){
+				String userName = inDto.getString("userName");
+				String message = inDto.getString("message");
+				List<String> params = Lists.newArrayList();
+				params.add(userName);
+				params.add(message);
+				Map<String, String> extrasMap = Maps.newHashMap();
+				extrasMap.put("url", inDto.getString("url"));
+				asyncAppService.jpush(14, Constants.JPUSH_TYPE_ID, SmsRegisterIdList, params, extrasMap);
+			}
+			return OutDTO.ok();
+		}
+		else{return OutDTO.error(400,"InDto missing param");}
+	}
+
+	@ApiLog(title = "修改优惠劵msg",businessType = BusinessType.INSERT)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN})
+	@ResponseBody
+	@PostMapping("/check/coupon")
+	public OutDTO checkCoupon(@RequestBody InDto inDto) {
+		Integer id = inDto.getIntegerParam("id");
+		String msg = inDto.getString("msg");
+		if (id == null || StringUtils.isEmpty(msg)) {
+			return OutDTO.error500("参数缺失!");
+		}
+		TzyCardBaseInfo updateMsg = new TzyCardBaseInfo();
+		updateMsg.setId(id.longValue());
+		updateMsg.setMsg(msg);
+		cardBaseInfoService.updateTzyCardBaseInfo(updateMsg);
+		return OutDTO.ok();
+	}
+
+	@PostMapping("/barcode/decode")
+	@ResponseBody
+	public OutDTO decodeBarcode(@RequestParam("file") MultipartFile file,
+								@RequestParam(required = false, defaultValue = "barcode") String type) throws IOException {
+		// 直接从流读取 BufferedImage
+		BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
+		if (bufferedImage == null) {
+			return OutDTO.error500("无法读取图片");
+		}
+		String barcodeText = null;
+		if ("barcode".equalsIgnoreCase(type)) {
+			barcodeText = BarcodeUtil.decodeBarcode(bufferedImage);
+		} else if ("qrcode".equalsIgnoreCase(type)) {
+			barcodeText = BarcodeUtil.decodeQRCode(bufferedImage);
+		} else {
+			return OutDTO.error500("未知的类型,请选择barcode或qrcode");
+		}
+		return OutDTO.ok().put("barCode", barcodeText);
+	}
+
+
+	@GetMapping("/merchant/score/{merchantId}")
+	@ApiOperation("商家店铺评分")
+	public ResultDTO merchantScore(@PathVariable Long merchantId){
+		String timestamp =  ServletUtils.getRequest().getHeader("timestamp"); // 时间戳
+		String token = ServletUtils.getRequest().getHeader("token"); // 校验请求身份
+		String key = "hobby_" + timestamp + "_merchant_score";
+		String md5PassWord = DigestUtils.md5DigestAsHex(key.getBytes()).toUpperCase();
+		if(Strings.isEmpty(token) || !token.equals(md5PassWord)){
+			return ResultDTO.build500Error("token认证失败");
+		}
+		MerchantScoreDTO merchantScoreDTO = tzyMerchantAssessService.getMerchantMemberInfoV3(merchantId);
+		return ResultDTO.buildSuccessResult(merchantScoreDTO);
+	}
+
+	@GetMapping("/merchant/scores/{ids}")
+	@ApiOperation("多商家店铺评分")
+	public ResultDTO merchantScore(@PathVariable String ids){
+		String timestamp =  ServletUtils.getRequest().getHeader("timestamp"); // 时间戳
+		String token = ServletUtils.getRequest().getHeader("token"); // 校验请求身份
+		String key = "hobby_multiple_" + timestamp + "_merchant_scores";
+		String md5PassWord = DigestUtils.md5DigestAsHex(key.getBytes()).toUpperCase();
+		if(Strings.isEmpty(token) || !token.equals(md5PassWord)){
+			return ResultDTO.build500Error("token认证失败");
+		}
+		String[] idArray = ids.split(",");
+		List<MerchantScoreDTO> resultList = new ArrayList<>();
+
+		for (String idStr : idArray) {
+			Long merchantId = Long.parseLong(idStr.trim());
+			MerchantScoreDTO merchantScoreDTO = tzyMerchantAssessService.getMerchantMemberInfoV3(merchantId);
+			merchantScoreDTO.setId(merchantId);
+			resultList.add(merchantScoreDTO);
+		}
+		return ResultDTO.buildSuccessResult(resultList);
+	}
+
+	@GetMapping("/merchant/scores/avg")
+	@ApiOperation("活跃商家店铺平均分")
+	public ResultDTO activeMerchantAvg(){
+		String timestamp =  ServletUtils.getRequest().getHeader("timestamp"); // 时间戳
+		String token = ServletUtils.getRequest().getHeader("token"); // 校验请求身份
+		String key = "hobby_" + timestamp + "_merchant_avg_score";
+		String md5PassWord = DigestUtils.md5DigestAsHex(key.getBytes()).toUpperCase();
+		if(Strings.isEmpty(token) || !token.equals(md5PassWord)){
+			return ResultDTO.build500Error("token认证失败");
+		}
+		BigDecimal avgScore = tzyMerchantAssessService.getActiveMerchantAvg();
+		return ResultDTO.buildSuccessResult(avgScore);
+	}
+}

+ 648 - 0
poyi-app/src/main/java/com/tzy/controller/TestController.java

@@ -0,0 +1,648 @@
+package com.tzy.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.tzy.annotation.ApiLog;
+import com.tzy.app.domain.order.OrderRefundDTO;
+import com.tzy.app.domain.order.PayRecord;
+import com.tzy.app.mapper.PayRecordMapper;
+import com.tzy.app.service.RetryService;
+import com.tzy.common.annotation.JsonParam;
+import com.tzy.common.annotation.SensitiveData;
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.common.constant.Constants;
+import com.tzy.common.constant.MqConstans;
+import com.tzy.common.core.controller.BaseController;
+import com.tzy.common.core.domain.entity.SysDictData;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.dto.group.PublicGoodsDTO;
+import com.tzy.common.dto.group.SyncUserWinCardDTO;
+import com.tzy.common.enums.BusinessType;
+import com.tzy.common.exception.ServiceException;
+import com.tzy.common.utils.DateUtils;
+import com.tzy.common.utils.LogSyncUtil;
+import com.tzy.common.utils.bean.DozerUtils;
+import com.tzy.common.utils.http.forest.AppleUtil;
+import com.tzy.coupon.card.service.ITzyCardBaseInfoService;
+import com.tzy.framework.pay.dto.PaymentInfoResponseDto;
+import com.tzy.framework.pay.service.PaymentService;
+import com.tzy.framework.util.RandomUtil;
+import com.tzy.framework.util.RedisUtils;
+import com.tzy.pojo.card.CardGroupOrderInfo;
+import com.tzy.sportcard.api.bean.act.GoodsActRecord;
+import com.tzy.sportcard.api.bean.act.UserActTimes;
+import com.tzy.sportcard.api.bean.act.UserListActParam;
+import com.tzy.sportcard.api.domain.AppUserInfoDto;
+import com.tzy.sportcard.api.dto.ResourceData;
+import com.tzy.sportcard.api.mapper.AppActPrizeRecordMapper;
+import com.tzy.sportcard.api.mapper.GroupApiMapper;
+import com.tzy.sportcard.api.mapper.UserActTimesMapper;
+import com.tzy.sportcard.api.service.*;
+import com.tzy.sportcard.group.domain.CardGroupGoods;
+import com.tzy.sportcard.group.domain.CardGroupInfo;
+import com.tzy.sportcard.group.mapper.CardGroupGoodsMapper;
+import com.tzy.sportcard.group.mapper.CardGroupInfoMapper;
+import com.tzy.sportcard.group.mapper.CardGroupOrderInfoMapper;
+import com.tzy.sportcard.group.service.AppActService;
+import com.tzy.sportcard.group.service.ICardGroupGoodsService;
+import com.tzy.sportcard.group.service.ICardGroupOrderInfoService;
+import com.tzy.sportcard.point.domain.AppUserPointRecord;
+import com.tzy.system.service.ISysDictDataService;
+import com.tzy.system.service.ITzySysNoticeRecordService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.*;
+import org.teasoft.bee.osql.SuidRich;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.sql.SQLException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * swagger 用户测试方法
+ *
+ * @author zheng
+ */
+@Api("用户信息管理")
+@RestController
+@RequestMapping("{version}/test")
+@Slf4j
+public class TestController extends BaseController {
+
+	@Autowired
+	private RedisUtils redisUtils;
+	@Autowired
+	private GroupApiService groupApiService;
+	@Autowired
+	private MerchantApiService merchantApiService;
+	@Autowired
+	private ITzySysNoticeRecordService noticeRecordService;
+	@Resource
+	private CardGroupGoodsMapper cardGroupGoodsMapper;
+	@Resource
+	private CardGroupOrderInfoMapper cardGroupOrderInfoMapper;
+	@Autowired
+	private ISysDictDataService dictDataService;
+	@Autowired
+	private SuidRich suidRich;
+	@Autowired
+	private AsyncAppService asyncAppService;
+	@Value("${tzy.app-version:dev}")
+	private String appVersion;
+	@Resource
+	private PayRecordMapper payRecordMapper;
+	@Autowired
+	private RabbitTemplate rabbitTemplate;
+	//@Autowired
+	//private DataModel dataModel;
+	@Resource
+	private CardGroupInfoMapper cardGroupInfoMapper;
+	@Autowired
+	private ICardGroupGoodsService cardGroupGoodsService;
+	@Resource
+	private IMemberManageService memberManageService;
+	@Autowired
+	private PaymentService paymentService;
+	@Resource
+	private AppActService appActService;
+	@Autowired
+	private CardGroupOrderInfoMapper orderInfoMapper;
+	//@Resource
+	//private Connection connection;
+	//@Resource
+	//private PooledConnection pooledConnection;
+	@Autowired
+	private MineApiService mineApiService;
+	@Resource
+	private AppActPrizeRecordMapper actPrizeRecordMapper;
+	@Resource
+	private GroupApiMapper groupApiMapper;
+	@Resource
+	private ICardGroupOrderInfoService cardGroupOrderInfoService;
+	@Resource
+	private RetryService retryService;
+	@Resource
+	private ITzyCardBaseInfoService cardBaseInfoService;
+	@Resource
+	private UserActTimesMapper userActTimesMapper;
+
+	@GetMapping("/groupFull/{id}")
+	public void testGroupFullConsumer(@PathVariable("id") Long id){
+		rabbitTemplate.convertAndSend(MqConstans.EXCHANGE_GROUP_FULL, MqConstans.ROUTING_KEY_GROUP_FULL, id);
+	}
+	public void checkDevEnv() {
+		log.debug("部署环境:{}", appVersion);
+		if (Constants.APP_VERSION_PROD.equals(appVersion)) {
+			throw new ServiceException(500, "环境不符合");
+		}
+	}
+
+	@ApiOperation("data")
+	@GetMapping("/check/act")
+	@ApiVersion(1.0)
+	public OutDTO checkAct() throws Exception {
+		checkDevEnv();
+		Date day = DateUtils.addCalendar(new Date(), "day", -100);
+		UserActTimes userActTimes = new UserActTimes().setActType("joint_num").setUserId(15400L).setRefType("joint_num1").setCreateTime(day);
+		int count = userActTimesMapper.selectUserActTimesCount(userActTimes);
+		return OutDTO.ok().put("count",count);
+	}
+
+	@ApiOperation("data")
+	@GetMapping("/notice/act")
+	@ApiVersion(1.0)
+	public OutDTO noticeAct(Integer id) throws Exception {
+		checkDevEnv();
+		//int actCount = actPrizeRecordMapper.getActCount(38, false, 0, 10);
+		//asyncAppService.noticePublicCode(id);
+		//groupApiMapper.selectUserIdsV2(null,105,null);
+		return OutDTO.ok();
+	}
+
+	@ApiOperation("data")
+	@GetMapping("/syncGoods")
+	@ApiVersion(1.0)
+	public OutDTO syncGoods(Long id) throws Exception {
+		checkDevEnv();
+		//cardGroupGoodsService.syncGoods(id);
+		//List<TypeCountDTO> countList = cardGroupGoodsService.getUserGoodsNum(3409L);
+		return OutDTO.ok();
+	}
+
+	@ApiOperation("data")
+	@GetMapping("/infoQuery")
+	@ApiVersion(1.0)
+	public OutDTO testInfoQuery(Long id) throws Exception {
+		checkDevEnv();
+		CardGroupInfo cardGroupInfo = cardGroupInfoMapper.selectCardGroupInfoById(id);
+		asyncAppService.updateInfoSortQueryV3(cardGroupInfo);
+		return OutDTO.ok();
+	}
+
+	@ApiOperation("recommend")
+	@GetMapping("/recommend/{userId}")
+	@ApiVersion(1.0)
+	public OutDTO recommendByUser(@PathVariable("userId") Integer userId) throws Exception {
+		checkDevEnv();
+		return OutDTO.ok()
+				//.put("list",list)
+				;
+	}
+
+	@ApiLog(title = "test", businessType = BusinessType.SEARCH)
+	@ApiOperation("data")
+	@GetMapping("/dataTest")
+	@ApiVersion(1.0)
+	@SensitiveData
+	public OutDTO dataTest(Integer i) throws Exception {
+		checkDevEnv();
+		//DataModel model=dataModel;
+		//data1(model);
+		log.info("---1111111----");
+		//{{version}}/test/bee/select
+		//data2(model);
+		//log.info("---2222222----");
+		//data3(model);
+		//log.info("---3333333----");
+		//asyncAppService.test();
+		//List<MemberManage> memberManages = memberManageService.selectOnlineMemberList();
+		//MemberManage userMemberLevel = memberManageService.getUserMemberLevel(i);
+		//memberManageService.initMember();
+		//List<GoodsActRecord> allActGoods = cardGroupGoodsService.getActGoods(i.longValue(),Constants.MERCHANT_ACT_AFT_ORDER);
+		//rabbitTemplate.convertAndSend(MqConstans.EXCHANGE_GROUP_FULL, MqConstans.ROUTING_KEY_GROUP_FULL, 1823);
+		//testPointJson();
+		//List<SensitiveDTO> list = Arrays.asList(new SensitiveDTO(1, "test2121"), new SensitiveDTO(2, "17000000041"));
+		//redisUtils.del("app_dict_cache");
+		// String message = "Hello, world!";
+		// rabbitTemplate.convertAndSend("TestTopicExchangeV3", "test", message);
+		// // 发送消息到交换机,使用路由键 "test.abc"
+		// String message2 = "Hello, world again!";
+		// rabbitTemplate.convertAndSend("TestTopicExchangeV3", "test.abc", message2);
+		return OutDTO.ok()
+				//.put("test", list)
+				;
+	}
+
+	private void testPointJson() {
+		AppUserPointRecord pointRecord = new AppUserPointRecord();
+		pointRecord.setChangePoint(2990L);
+		pointRecord.setType(Constants.POINT_TYPE_GOODS);
+		pointRecord.setUserId(2487L);
+		pointRecord.setOrderId(23644L);
+		pointRecord.setOrderNo("SO620220928167151695");
+		pointRecord.setCreateTime(new Date());
+		pointRecord.setMerchantId(13L);
+		rabbitTemplate.convertAndSend(MqConstans.EXCHANGE_USER_POINT, MqConstans.ROUTING_KEY_USER_POINT, pointRecord);
+		//rabbitTemplate.convertAndSend(MqConstans.EXCHANGE_USER_POINT, MqConstans.ROUTING_KEY_USER_POINT_JSON, JSON.toJSONString(pointRecord));
+	}
+
+	@ApiOperation("bee")
+	@GetMapping("/bee/select")
+	@ApiVersion(1.0)
+	public OutDTO beeTest(Long id) {
+        // try {
+        //     Thread.sleep(61000);
+        // } catch (InterruptedException e) {
+        //     throw new RuntimeException(e);
+        // }
+        CardGroupOrderInfo orderInfo = new CardGroupOrderInfo();
+		orderInfo.setGroupInfoId(id);
+		List<CardGroupOrderInfo> select = suidRich.select(orderInfo, 0, 5);
+		int count = suidRich.count(orderInfo);
+		return OutDTO.ok().put("goods", select)
+				.setCount(5, 1, count);
+	}
+
+	@ApiOperation("bee")
+	@GetMapping("/bee/update")
+	@ApiVersion(1.0)
+	public OutDTO beeUpdate(Long id) {
+		checkDevEnv();
+		CardGroupOrderInfo orderInfo = new CardGroupOrderInfo();
+		orderInfo.setId(id);
+		orderInfo.setProp1("111");
+		suidRich.update(orderInfo, "prop1");
+		return OutDTO.ok();
+	}
+
+	@ApiOperation("act")
+	@GetMapping("/list/act")
+	public OutDTO listAct() {
+		checkDevEnv();
+		List<GoodsActRecord> userListAct = groupApiService.getUserListAct(1716L);
+		UserListActParam listActParam = new UserListActParam(3222L, 0, 1716L, Constants.LIST_ACT_SELECT_PLAYER);
+		//groupApiService.buildUserListActRecord(listActParam);
+		//appActService.delUserListActCache(1716,2459);
+		//List<PaniniCheckList> paniniCheckLists = groupApiService.selectPaniniActListByType(1716L, Constants.LIST_ACT_SELECT_PLAYER, 13352L);
+		return OutDTO.ok();
+	}
+
+	@ApiOperation("version1")
+	@GetMapping("/version")
+	@ApiVersion(1.0)
+	public OutDTO beeTestv() {
+		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("payAct")
+	@GetMapping("/payAct")
+	public OutDTO payAct(String no) {
+		checkDevEnv();
+		//com.tzy.sportcard.group.domain.CardGroupOrderInfo orderInfo = cardGroupOrderInfoMapper.getByOrderNo(no);
+		//asyncAppService.complyPayAct(orderInfo);
+		return OutDTO.ok().put("no", no);
+	}
+
+	@ApiOperation("paySuccess")
+	@GetMapping("/paySuccess")
+	public OutDTO paySuccess(String no) {
+		checkDevEnv();
+		com.tzy.sportcard.group.domain.CardGroupOrderInfo orderInfo = cardGroupOrderInfoMapper.getByOrderNo(no);
+		CardGroupInfo cardGroupInfo = cardGroupInfoMapper.selectCardGroupInfoById(orderInfo.getGroupInfoId());
+		asyncAppService.orderPaySuccess(orderInfo, cardGroupInfo);
+		return OutDTO.ok();
+	}
+
+	@ApiOperation("callback")
+	@GetMapping("/callback")
+	public OutDTO callback(String no) {
+		checkDevEnv();
+		//Long[] idxes={1L,2L};
+		//log.info("订单no:{},保存队伍选择卡密id集合:{}",no, Arrays.toString(idxes));
+		//RedisTools.getRedisUtils().set("test","1111",3);
+		ResourceData resourceData = new ResourceData();
+		ResourceData.PayAmount payAmount = new ResourceData.PayAmount();
+		if (no.startsWith(RandomUtil.GROUP_USER_ORDER) || no.startsWith(RandomUtil.MALL_USER_ORDER)) {
+			com.tzy.sportcard.group.domain.CardGroupOrderInfo orderInfo = cardGroupOrderInfoMapper.getByOrderNo(no);
+			resourceData.setTrade_type(orderInfo.getPaymentType());
+			resourceData.setSubPaymentType(orderInfo.getPaymentSubType());
+			payAmount.setTotal(orderInfo.getActualPayment().multiply(new BigDecimal(100)).intValue());
+			resourceData.setOut_trade_no(StringUtils.isEmpty(orderInfo.getTradeNo()) ? no : orderInfo.getTradeNo());
+		} else {
+			PayRecord payRecord = payRecordMapper.selectPayRecordByNo(no);
+			resourceData.setTrade_type(payRecord.getPaymentType());
+			resourceData.setSubPaymentType(payRecord.getPaymentSubType());
+			payAmount.setTotal(payRecord.getPayAmount().multiply(new BigDecimal(100)).intValue());
+			resourceData.setOut_trade_no(no);
+		}
+		resourceData.setTransaction_id(String.valueOf(System.currentTimeMillis()));//支付流水号,微信支付订单号
+		resourceData.setSuccess_time(DateUtils.dateTime(new Date()));//支付成功时间
+		resourceData.setTrade_state("TRADE_SUCCESS");//支付状态
+		resourceData.setTrade_state_desc("TRADE_SUCCESS");//支付状态说明
+		resourceData.setBank_type("支付宝");//付款银行
+		payAmount.setPayer_total(payAmount.getTotal());
+		resourceData.setAmount(payAmount);
+		groupApiService.prePayByMQ(resourceData);
+		return OutDTO.ok().put("no", no);
+	}
+
+	@ApiOperation("stock")
+	@GetMapping("/updateStock")
+	public OutDTO updateStock(Long orderId) {
+		//com.tzy.sportcard.group.domain.CardGroupOrderInfo cardGroupOrderInfo = cardGroupOrderInfoMapper.selectCardGroupOrderInfoById(orderId);
+		//asyncAppService.updateSoldAndRealStock(cardGroupOrderInfo);
+		return OutDTO.ok();
+	}
+
+	@ApiOperation("mq")
+	@GetMapping("/testMq")
+	public OutDTO testMq() {
+		checkDevEnv();
+		String messageId = String.valueOf(UUID.randomUUID());
+		String messageData = "message: testFanoutMessage ";
+		String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+		//rabbitTemplate.convertAndSend("exchange_test2", "test", new TestParam(messageId, messageData, createTime));
+		//rabbitTemplate.convertAndSend("exchange_test2", "test.test", new TestParam(messageId, messageData, createTime));
+		//sendMsg();
+		//orderRefund();
+		//rabbitTemplate.convertAndSend(MqConstans.EXCHANGE_GROUP_FULL, MqConstans.ROUTING_KEY_GROUP_FULL, 738L);
+		//sendLiveMsg();
+		//rabbitTemplate.convertAndSend(MqConstans.QUEUE_MERCHANT_NOTIFY,"12222");
+		//JSONObject param2 = new JSONObject();
+		//param2.put("type","sale");
+		//param2.put("merchantId",13);
+		//param2.put("merchantName","YYDS");
+		//param2.put("groupInfoId","2919");
+		//param2.put("groupInfoName","1111");
+		//rabbitTemplate.convertAndSend(MqConstans.QUEUE_MERCHANT_NOTIFY, JSON.toJSONString(param2));
+		//rabbitTemplate.convertAndSend(MqConstans.EXCHANGE_GROUP_FULL, MqConstans.ROUTING_KEY_GROUP_FULL, 3067);
+		//GroupActRecord actRecord = new GroupActRecord().setType(Constants.GROUP_GIFT_CARD).setRefId(3380).setActType(Constants.GROUP_GIFT_CARD);
+		//rabbitTemplate.convertAndSend(MqConstans.QUEUE_GROUP_GIFT_CARD, com.alibaba.fastjson2.JSON.toJSONString(actRecord));
+		//List<UserGiftCardDTO> userWaitCards = mineApiService.getUserInitWaitGiftCards(2492);
+		return OutDTO.ok();
+
+	}
+
+	private void orderRefund() {
+		rabbitTemplate.convertAndSend(MqConstans.EXCHANGE_ORDER_REFUND, MqConstans.ROUTING_KEY_ORDER_REFUND, new OrderRefundDTO(1L, BigDecimal.ONE));
+	}
+
+	public void sendMsg() {
+		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+		System.out.println("消息发送时间:" + sdf.format(new Date()));
+		rabbitTemplate.convertAndSend(MqConstans.EXCHANGE_DELAYED_ORDER_EXPIRED, MqConstans.ROUTING_KEY_ORDER_EXPIRED, 1L, message -> {
+			//消息延迟5秒
+			message.getMessageProperties().setHeader("x-delay", 1000 * 3);
+			return message;
+		});
+	}
+
+	public void sendLiveMsg() {
+		Map data = new HashMap() {{
+			put("type", "1");
+			put("data", "11111");
+			put("time", new Date().toString());
+		}};
+		rabbitTemplate.convertAndSend(MqConstans.EXCHANGE_DELAYED_APP_LIVE_CONFIG, MqConstans.ROUTING_KEY_APP_LIVE_CONFIG, JSON.toJSONString(data), message -> {
+			//消息延迟5秒
+			message.getMessageProperties().setHeader("x-delay", 3000);
+			return message;
+		});
+	}
+
+
+	@ApiOperation("stock")
+	@GetMapping("/testLock")
+	public OutDTO testLock() {
+		String name = Thread.currentThread().getName();
+		log.info("请求进来了:{}", name);
+		String lockKey = "test_key";
+		long l = System.currentTimeMillis();
+		boolean isGetLock = false;
+		try {
+			boolean isLock = redisUtils.tryLock(lockKey, TimeUnit.SECONDS, 5L, -1);
+			if (isLock) {
+				isGetLock = true;
+				log.info("3333------->{}", name);
+				//Thread.sleep(40000L);
+				log.info("1111------->{}", name);
+				redisUtils.unlock(lockKey);
+				log.info("222------->{}", name);
+				//isGetLock = false;
+				return OutDTO.ok("2222");
+			}
+		} catch (Exception e) {
+			log.error("异常:{}", e);
+		} finally {
+			try {
+				//if (isGetLock) {
+				log.info("finally unlock-------");
+				redisUtils.unlock(lockKey);
+				//}
+			} catch (Exception e) {
+				log.error("锁释放异常:{}", e);
+				return OutDTO.ok();
+			}
+
+		}
+		log.info("等待时间:name:{}------->时间:{}", name, System.currentTimeMillis() - l);
+		return OutDTO.error500("500");
+	}
+
+
+	@ApiOperation("codeVerify")
+	@GetMapping("/codeVerify")
+	public OutDTO codeVerify(String jwt) throws Exception {
+		AppleUtil.verify(jwt);
+		return OutDTO.ok();
+	}
+
+	@ApiOperation("syncWinCardTest")
+	@GetMapping("/sync/win/card")
+	public OutDTO syncWinCardTest(String type, Integer id) {
+		checkDevEnv();
+		ArrayList<Integer> ids = new ArrayList<>();
+		ids.add(id);
+		SyncUserWinCardDTO param = new SyncUserWinCardDTO(type, ids);
+		rabbitTemplate.convertAndSend(MqConstans.EXCHANGE_SYNC_USER_WIN_CARD, MqConstans.ROUTING_KEY_SYNC_USER_WIN_CARD, JSONObject.toJSONString(param));
+		return OutDTO.ok();
+	}
+
+
+	@ApiOperation("dozer")
+	@GetMapping("/dozer/test")
+	public OutDTO codeVerify() throws Exception {
+		CardGroupGoods cardGroupGoods = new CardGroupGoods();
+		cardGroupGoods.setId(1L);
+		cardGroupGoods.setImg("1L");
+		cardGroupGoods.setUserAvatar("1L");
+		cardGroupGoods.setUserNickname("2L");
+
+		PublicGoodsDTO goods = DozerUtils.map(cardGroupGoods, PublicGoodsDTO.class);
+		log.debug("数据:{}", goods);
+		return OutDTO.ok();
+	}
+
+	@ApiOperation("log")
+	@GetMapping("/log/sync")
+	public OutDTO logTest() throws Exception {
+		LogSyncUtil.logSync("打印日志,参数1:{},参数2,{}", 1, 2);
+		return OutDTO.ok();
+	}
+
+	@ApiOperation("query")
+	@GetMapping("/query/pay")
+	public OutDTO queryPay(String no) {
+		checkDevEnv();
+		com.tzy.sportcard.group.domain.CardGroupOrderInfo orderInfo = cardGroupOrderInfoMapper.getByOrderNo(no);
+		PaymentInfoResponseDto result = paymentService.queryPaymentOrder(orderInfo.getPaymentSubType(), orderInfo.getTradeNo());
+		return OutDTO.ok().put("result", result);
+	}
+
+	@ApiOperation("query")
+	@GetMapping("/v1/page/check")
+	public OutDTO checkPageBug() {
+		//PageHelper.startPage(1,10);
+		//int i=1/0;
+		return OutDTO.ok();
+	}
+
+	@ApiOperation("query")
+	@GetMapping("/v2/page/check")
+	public OutDTO checkPageBug2() {
+		//List<AppCarouselPicture> banners=appCarouselPictureService.getBanner(null);
+		return OutDTO.ok();
+	}
+
+
+	@ApiOperation("query")
+	@GetMapping("/pg/notify")
+	public OutDTO testNotify() throws SQLException {
+		//将数据库连接还原为原始的PGConnection
+		//PGConnection pgConnection = pooledConnection.getConnection().unwrap(PGConnection.class);
+		//Statement stmt = pgConnection.createStatement();
+		//stmt.execute("NOTIFY CARD_GROUP_ORDER_INFO_MODIFIED_TEST,'123'");
+		//stmt.close();
+		//ExpressInDto expressInDto = new ExpressInDto();
+		//expressInDto.setShipTime(new Date());
+		//expressInDto.setStatus(103L);//已发货状态
+		//expressInDto.setPickUpType("2");
+		//expressInDto.setCourierNum("1213123131");//保存快递单号信息;
+		//expressInDto.setUnSendFlag(true);
+		//int i = orderInfoMapper.sendExpress(expressInDto,Arrays.asList(207915L,207914L));
+		//id=null, userId=2442, currPoint=null, lastPoint=null, changePoint=-10000, orderId=253589, merchantId=null,
+		// type=common_record, orderNo=SO4240125148608069, createTime=null, userDeduct=1, pointRate=null
+//		AppUserPointRecord pointRecord = new AppUserPointRecord();
+//		//pointRecord.setType(Constants.POINT_TYPE_GIFT_CARD_PRE + 1);
+//		pointRecord.setType("common_record");
+//		pointRecord.setChangePoint(10000);
+//		//pointRecord.setCurrPoint(1L);
+//		pointRecord.setUserId(2442L);
+//		pointRecord.setOrderId(253589L);
+//		pointRecord.setOrderNo("SO4240125148608069");
+//		pointRecord.setUserDeduct(1);
+//		pointRecord.setCreateTime(new Date());
+//		//增加积分明细记录
+//		mineApiService.addUserPoint(pointRecord);
+		return OutDTO.ok();
+	}
+
+	@ApiOperation("cache")
+	@GetMapping("/cache")
+	public OutDTO testCache(String v) {
+		checkDevEnv();
+		//String s=appActService.testCache(v);
+		List<SysDictData> newSortQuery = dictDataService.selectDictDataByCache("new_sort_query", null, null, true);
+		return OutDTO.ok();
+	}
+
+	@ApiOperation("cache")
+	@GetMapping("/cache/del")
+	public OutDTO testDelCache(String v) {
+		checkDevEnv();
+		redisUtils.del(v);
+		return OutDTO.ok();
+	}
+
+	@ApiOperation("cache")
+	@GetMapping("/remote/channel")
+	public OutDTO testRemoteChannel() {
+		checkDevEnv();
+		AppUserInfoDto appUserInfoDto = new AppUserInfoDto();
+		appUserInfoDto.setGrowthNum(4000L);
+		//String rs = cardGroupOrderInfoService.getPayTypeByUser("uac", appUserInfoDto, 86L, false, "group");
+		return OutDTO.ok()
+				//.put("data", rs)
+				;
+	}
+
+	@ApiOperation("point")
+	@GetMapping("/point")
+	public OutDTO testPoint() throws SQLException {
+		checkDevEnv();
+		//id=null, userId=2442, currPoint=null, lastPoint=null, changePoint=-10000, orderId=253589, merchantId=null,
+		// type=common_record, orderNo=SO4240125148608069, createTime=null, userDeduct=1, pointRate=null
+//		AppUserPointRecord pointRecord = new AppUserPointRecord();
+//		pointRecord.setType("common_record");
+//		pointRecord.setChangePoint(-10000);
+//		pointRecord.setUserId(2442L);
+//		pointRecord.setOrderId(253589L);
+//		pointRecord.setOrderNo("SO4240125148608069");
+//		pointRecord.setUserDeduct(1);
+//		pointRecord.setPointRate(100d);
+//		pointRecord.setCreateTime(new Date());
+//		//增加积分明细记录
+//		mineApiService.addUserPoint(pointRecord);
+// 		InvoiceOrderQuery query = new InvoiceOrderQuery().setMerchantId(182).setUserId(15399);
+// 		List<SimpleOrderDTO> invoiceOrder = cardGroupOrderInfoMapper.getInvoiceOrder(query);
+		return OutDTO.ok();
+	}
+
+	@ApiLog(title = "test", businessType = BusinessType.SEARCH)
+	@ApiOperation("point")
+	@PostMapping("/param/anon")
+	public OutDTO testParamConvert(@JsonParam AppUserPointRecord pointRecord){
+		return OutDTO.ok().put("param", pointRecord);
+	}
+
+	@ApiLog(title = "test", businessType = BusinessType.SEARCH)
+	@ApiOperation("point")
+	@PostMapping("/param/anon/list")
+	public OutDTO testParamConvert(@JsonParam(objectType = AppUserPointRecord.class) List<AppUserPointRecord> pointRecords){
+		return OutDTO.ok().put("param", pointRecords);
+	}
+
+	@ApiLog(title = "retry", businessType = BusinessType.SEARCH)
+	@ApiOperation("retry")
+	@PostMapping("/retry")
+	public OutDTO testRetry(){
+		checkDevEnv();
+		// retryService.retryMethod1();
+		// retryService.retryMethod2();
+		// String day = DateUtils.dateTime();
+		// String key = Constants.MERCHANT_USER_ORDER_NUM + day + 11;
+		// redisUtils.hset(key, "1", 1);
+		// redisUtils.expire(key, Constants.dayForSecond);
+		//asyncAppService.recordUserCurrentDayOrderNum(181L,15594L);
+		return OutDTO.ok();
+	}
+
+	// @GetMapping("/num")
+	// @ApiLog(title = "领取优惠券", businessType = BusinessType.INSERT)
+	// @ApiOperation("领取优惠券")
+	// //@ApiLimitRule(seconds = 1, limitCount = 30, type = LimitRule.ACT, msg = "操作频繁,请稍后再试!")
+	// public OutDTO test(){
+	// 	cardBaseInfoService.test(2302);
+	//     return OutDTO.ok();
+	// }
+
+}

+ 112 - 0
poyi-app/src/main/java/com/tzy/controller/appuser/AppNotifyController.java

@@ -0,0 +1,112 @@
+package com.tzy.controller.appuser;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.tzy.annotation.ApiLog;
+import com.tzy.app.dto.SimpleMerchantInfo;
+import com.tzy.common.dto.InDto;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.enums.BusinessType;
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.sportcard.api.domain.AppNotifyConfig;
+import com.tzy.sportcard.api.domain.AppUserInfoDto;
+import com.tzy.sportcard.api.service.IAppNotifyConfigService;
+import com.tzy.sportcard.api.service.MerchantApiService;
+import com.tzy.sportcard.api.service.MineApiService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+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;
+
+/**
+ * @author by po'yi
+ * @Classname AppNotifyController
+ * @Description
+ * @Date 2023/8/8 13:26
+ */
+@Api(value = "app消息通知")
+@RestController
+@RequestMapping("/api/{version}/notify")
+@Slf4j
+public class AppNotifyController {
+
+	@Resource
+	private MineApiService mineApiService;
+	@Resource
+	private IAppNotifyConfigService notifyConfigService;
+	@Autowired
+	private MerchantApiService merchantApiService;
+
+
+	@ApiLog(title = "获取个人消息通知配置", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@PostMapping(value = "/user/config")
+	@ApiVersion(1.0)
+	@ApiOperation("获取个人消息通知配置")
+	public OutDTO getUserNotifyConfig(@RequestBody InDto inDto) {
+		AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+		List<AppNotifyConfig> configs = notifyConfigService.selectNotifyConfigByUserId(user.getId());
+		return OutDTO.ok().put("notifyConfigs",configs);
+	}
+
+	@ApiLog(title = "修改通知配置", businessType = BusinessType.UPDATE)
+	@ResponseBody
+	@PostMapping(value = "/edit/config")
+	@ApiVersion(1.0)
+	@ApiOperation("修改通知配置")
+	public OutDTO editUserConfig(@RequestBody InDto inDto) {
+		AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+		AppNotifyConfig notifyConfig = inDto.buildParam(new AppNotifyConfig());
+		notifyConfig.setUserId(user.getId().longValue());
+		notifyConfigService.updateAppNotifyConfig(notifyConfig);
+		notifyConfigService.editUserNotifyType(user.getId());
+		return OutDTO.ok();
+	}
+
+
+	@ApiLog(title = "获取关注商家通知配置", businessType = BusinessType.UPDATE)
+	@ResponseBody
+	@PostMapping(value = "/user/merchant")
+	@ApiVersion(1.0)
+	@ApiOperation("获取关注商家通知配置")
+	public OutDTO getMerchantNotifyConfig(@RequestBody InDto inDto) {
+		Integer id = (Integer) inDto.get("id");
+		if (id == null) {
+			return OutDTO.error500("参数为空!");
+		}
+		AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+		AppNotifyConfig config = notifyConfigService.selectNotifyConfigById(id);
+		if (config == null || config.getUserId() != user.getId().longValue()) {
+			return OutDTO.error500("数据异常,请重试!");
+		}
+		List<SimpleMerchantInfo> followMerchants = merchantApiService.selectFollowMerchants(user.getId());
+		if (!followMerchants.isEmpty() && "private_merchant".equals(config.getNotifyType())
+				&& StringUtils.isNotEmpty(config.getNotifyConfig())) {
+			JSONObject configJson = JSON.parseObject(config.getNotifyConfig());
+			String merchantIds = configJson.getString("merchantIds");
+			if (StringUtils.isNotEmpty(merchantIds)) {
+				List<String> merchantIdList = Arrays.asList(merchantIds.split(","));
+				followMerchants.forEach(m -> m.setNotifyFlag(merchantIdList.contains(m.getId().toString())));
+			}
+		}
+		return OutDTO.ok().put("followMerchants", followMerchants);
+	}
+
+
+	@ApiLog(title = "消息列表", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@PostMapping(value = "/msg/list")
+	@ApiVersion(1.0)
+	@ApiOperation("消息列表")
+	public OutDTO getUserNotifyMsgList(@RequestBody InDto inDto) {
+		AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+		List<AppNotifyConfig> configs = notifyConfigService.getUserNotifyMsgList(user.getId());
+		return OutDTO.ok().put("notifyConfigs",configs);
+	}
+}

+ 61 - 0
poyi-app/src/main/java/com/tzy/controller/appuser/AppUserBarrageRecordController.java

@@ -0,0 +1,61 @@
+package com.tzy.controller.appuser;
+
+import com.tzy.annotation.ApiLog;
+import com.tzy.app.domain.AppUserBarrageRecord;
+import com.tzy.app.dto.AppUserBarrageRecordDTO;
+import com.tzy.app.service.AppUserBarrageRecordService;
+import com.tzy.common.core.controller.BaseController;
+import com.tzy.common.dto.InDto;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.enums.BusinessType;
+import com.tzy.sportcard.api.domain.AppUserInfoDto;
+import com.tzy.sportcard.api.service.MineApiService;
+import com.tzy.util.BeanUtil;
+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;
+
+/**
+ * 用户弹幕
+ */
+@RestController
+@RequestMapping("/api/barrage")
+public class AppUserBarrageRecordController extends BaseController {
+
+    @Resource
+    private AppUserBarrageRecordService appUserBarrageRecordService;
+    @Resource
+    private MineApiService mineApiService;
+
+    @PostMapping("/save")
+    @ApiLog(title = "新增弹幕", businessType = BusinessType.INSERT)
+    public OutDTO save(@RequestBody InDto inDto){
+        if(inDto.getData() == null){
+            return OutDTO.error500("参数不能为空");
+        }
+        AppUserBarrageRecord appUserBarrageRecord = new AppUserBarrageRecord();
+        BeanUtil.populate(appUserBarrageRecord, inDto.getData());
+        mineApiService.checkUserNew(inDto);
+        int result = appUserBarrageRecordService.insertBarrageRecord(appUserBarrageRecord);
+        if(result == 0){
+            return OutDTO.error500("发送失败");
+        }
+        return OutDTO.ok();
+    }
+
+    @PostMapping("/list")
+    @ApiLog(title = "弹幕列表", businessType = BusinessType.INSERT)
+    public OutDTO list(@RequestBody InDto inDto){
+        if(inDto.getData() == null || inDto.get("groupInfoId") == null){
+            return OutDTO.error500("参数不能为空");
+        }
+        AppUserBarrageRecord appUserBarrageRecord = new AppUserBarrageRecord();
+        BeanUtil.populate(appUserBarrageRecord, inDto.getData());
+        List<AppUserBarrageRecordDTO> list = appUserBarrageRecordService.selectBarrageRecords(appUserBarrageRecord);
+        return OutDTO.ok().put("list", list);
+    }
+}

+ 2542 - 0
poyi-app/src/main/java/com/tzy/controller/appuser/AppUserControllerNew.java

@@ -0,0 +1,2542 @@
+package com.tzy.controller.appuser;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.github.pagehelper.PageInfo;
+import com.google.common.collect.ImmutableMap;
+import com.tzy.annotation.ApiLimitRule;
+import com.tzy.annotation.ApiLog;
+import com.tzy.annotation.RequireRoles;
+import com.tzy.app.domain.AppUserDetailInfo;
+import com.tzy.app.domain.AppUserPoint;
+import com.tzy.app.dto.CardCountDTO;
+import com.tzy.app.dto.SimpleMerchantInfo;
+import com.tzy.app.dto.SimpleUserMerchant;
+import com.tzy.app.dto.UserGroupOrderDTO;
+import com.tzy.app.dto.group.GiftCardManage;
+import com.tzy.app.dto.group.UserGoodsDTO;
+import com.tzy.app.dto.user.AppUserParam;
+import com.tzy.app.dto.user.UserConfigDTO;
+import com.tzy.app.service.AppUserDetailInfoService;
+import com.tzy.app.service.IAppAccountService;
+import com.tzy.app.service.IAppBaseUserService;
+import com.tzy.common.config.QuerySql;
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.common.constant.Constants;
+import com.tzy.common.constant.MqConstans;
+import com.tzy.common.constant.MsgConstants;
+import com.tzy.common.core.domain.AjaxResult;
+import com.tzy.common.core.domain.entity.SysDictData;
+import com.tzy.common.dto.UserInfo;
+import com.tzy.common.dto.*;
+import com.tzy.common.dto.group.OrderQuery;
+import com.tzy.common.dto.group.RefundReqDTO;
+import com.tzy.common.dto.invoice.InvoiceMerchantDTO;
+import com.tzy.common.dto.invoice.InvoiceMerchantQuery;
+import com.tzy.common.dto.invoice.InvoiceOrderQuery;
+import com.tzy.common.dto.invoice.SimpleOrderDTO;
+import com.tzy.common.dto.order.CostOrderDTO;
+import com.tzy.common.dto.order.MerchantCostConfig;
+import com.tzy.common.dto.order.ShippingPayParam;
+import com.tzy.common.dto.order.ShippingPayResult;
+import com.tzy.common.enums.BusinessType;
+import com.tzy.common.exception.AppAssert;
+import com.tzy.common.exception.ServiceException;
+import com.tzy.common.utils.*;
+import com.tzy.common.utils.bean.BeanUtils;
+import com.tzy.common.utils.bean.JSONTools;
+import com.tzy.common.utils.poi.ExcelUtil;
+import com.tzy.common.utils.qiniu.QiniuUtil;
+import com.tzy.coupon.card.domain.TzyCardBaseInfo;
+import com.tzy.coupon.card.service.ITzyCardBaseInfoService;
+import com.tzy.framework.util.RedisTools;
+import com.tzy.framework.util.RedisUtils;
+import com.tzy.framework.web.domain.LimitRule;
+import com.tzy.member.benefits.dto.SimpleBenefitsDTO;
+import com.tzy.member.benefits.service.IMemberBenefitsService;
+import com.tzy.pojo.app.*;
+import com.tzy.pojo.card.CardGroupInfo;
+import com.tzy.pojo.card.CardGroupOrderInfo;
+import com.tzy.pojo.item.EvaluationRecord;
+import com.tzy.sportcard.api.bean.invoice.AppUserInvoice;
+import com.tzy.sportcard.api.bean.invoice.AppUserInvoiceRecord;
+import com.tzy.sportcard.api.bean.param.ShippingQuery;
+import com.tzy.sportcard.api.domain.*;
+import com.tzy.sportcard.api.dto.Carmichae;
+import com.tzy.sportcard.api.dto.ReceiveGoodsDTO;
+import com.tzy.sportcard.api.service.*;
+import com.tzy.sportcard.base.service.CommonCacheService;
+import com.tzy.sportcard.dto.MineCardDTO;
+import com.tzy.sportcard.dto.RefundCheckDTO;
+import com.tzy.sportcard.group.domain.*;
+import com.tzy.sportcard.group.service.*;
+import com.tzy.sportcard.group.service.impl.GroupActService;
+import com.tzy.sportcard.point.service.IAppUserPointRecordService;
+import com.tzy.system.domain.TzyShippingAddress;
+import com.tzy.system.domain.TzySysNoticeRecord;
+import com.tzy.system.service.ISysDictDataService;
+import com.tzy.system.service.ITzyShippingAddressService;
+import com.tzy.system.service.ITzySysNoticeRecordService;
+import com.tzy.util.RandomUtil;
+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.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.DigestUtils;
+import org.springframework.web.bind.annotation.*;
+import org.teasoft.bee.osql.*;
+import org.teasoft.honey.osql.core.ConditionImpl;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.math.BigDecimal;
+import java.text.ParseException;
+import java.time.LocalDate;
+import java.util.*;
+import java.util.concurrent.Future;
+import java.util.stream.Collectors;
+
+/**
+ * @author by po'yi
+ * @Classname AppUserControllerNew
+ * @Description
+ * @Date 2022/3/3 13:24
+ */
+@Api(value = "app用户相关-新")
+@RestController
+@RequestMapping("/api/{version}/mine")
+@Slf4j
+public class AppUserControllerNew {
+    @Autowired
+    private MineApiService mineApiService;
+    @Autowired
+    private SuidRich suidRich;
+    @Autowired
+    private PreparedSql preparedSql;
+    @Autowired
+    private GroupApiService groupApiService;
+    @Autowired
+    private RedisUtils redisUtils;
+    @Autowired
+    private ISysDictDataService dictDataService;
+    @Autowired
+    private ICardGroupOrderInfoService orderInfoService;
+    @Autowired
+    private ITzyCardBaseInfoService cardBaseInfoService;
+    @Value("${tzy.app-version:dev}")
+    private String appVersion;
+    @Autowired
+    private IAppAccountService appAccountService;
+    @Autowired
+    private MerchantApiService merchantApiService;
+    @Autowired
+    @Qualifier("threadPoolTaskExecutor")
+    private ThreadPoolTaskExecutor pools;
+    @Resource
+    private AsyncAppService asyncAppService;
+    @Resource
+    private ChecklistCalendarService checklistCalendarService;
+    @Resource
+    private IAppUserWinCardService appUserWinCardService;
+    @Resource
+    private ICardGroupOrderInfoService cardGroupOrderInfoService;
+    @Resource
+    private ITzySysNoticeRecordService noticeRecordService;
+    @Resource
+    private CommonCacheService commonCacheService;
+    @Resource
+    private AppUserInvoiceRecordService appUserInvoiceRecordService;
+    @Resource
+    private IMemberBenefitsService memberBenefitsService;
+    @Resource
+    private IAppBaseUserService appBaseUserService;
+    @Resource
+    private RabbitTemplate rabbitTemplate;
+    @Resource
+    private IAppUserPointRecordService appUserPointRecordService;
+    @Resource
+    private ICardGroupOrderReviewService groupReviewService;
+    @Resource
+    private GroupActService groupActService;
+    @Resource
+    private ITzyShippingAddressService addressService;
+    @Resource
+    private AppUserDetailInfoService appUserDetailInfoService;
+    @Value("${tzy.idCardMaxNum:2}")
+    private Integer idCardMaxNum;
+    @Resource
+    private ITzyMerchantInfoService tzyMerchantInfoService;
+    @Autowired
+    private NoticeService noticeService;
+    @Autowired
+    private IOrderChangeRecordService orderChangeRecordService;
+
+    @ApiLog(title = "获取用戶累积发货卡片数量", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/card/waitShippingCount", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("累积待处理数量")
+    public OutDTO waitShippingCount(@RequestBody InDto inDto) {
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        String sql = QuerySql.getQuerySql("com.tzy.app.dto.CardGoodsDTO.getWaitShippingMerchants");
+        List<MerchantInfo> merchantInfos = preparedSql.selectSomeField(sql, new MerchantInfo(),new Object[]{user.getId()});
+        return OutDTO.ok().put("merchantInfos", merchantInfos.stream().map(m -> m.getName()).collect(Collectors.toList()));
+    }
+
+    @ApiLog(title = "用戶拒绝Or同意商家名下所有订单累积发货", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/order/refuseByMerchant", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("用戶拒绝Or同意商家名下所有订单累积发货,传参{id,refuseStatus}")
+    public OutDTO refuseByMerchant(@RequestBody InDto inDto) {
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        CardGroupOrderInfo condition = new CardGroupOrderInfo();
+        if (inDto.get("refuseStatus") == null || inDto.get("id") == null) {
+            return OutDTO.error(500, "参数为空");
+        }
+        condition.setMerchantId(Long.valueOf((inDto.get("id").toString())));
+        condition.setUserId(user.getId().longValue());
+        condition.setPickUpType("3");
+        //condition.setRefuseStatus(0);
+
+        CardGroupOrderInfo updateInfo = new CardGroupOrderInfo();
+        int refuseStatus = (Integer) inDto.get("refuseStatus");
+        if(2 == refuseStatus) {
+            condition.setRefuseStatus(0); // 更新累计状态为0的时间
+            updateInfo.setRefuseTime(DateUtils.getNowDate()); // 用户确认累计时间
+        }
+        updateInfo.setRefuseStatus(refuseStatus);
+        updateInfo.setUpdateTime(DateUtils.getTimestampNow());
+        suidRich.update(condition, updateInfo);
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "用户同意累积发货", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    //@RequestMapping(value = "/order/allowPickUp", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("用户同意累积发货,传参{orderId}")
+    public OutDTO allowPickUp(@RequestBody InDto inDto) {
+        mineApiService.checkUserNew(inDto);
+        CardGroupOrderInfo updateInfo = new CardGroupOrderInfo();
+        updateInfo.setId(Long.valueOf((inDto.get("orderId").toString())));
+        updateInfo.setRefuseStatus(2);
+        updateInfo.setUpdateTime(DateUtils.getTimestampNow());
+        suidRich.update(updateInfo);
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "用戶自提", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    //@RequestMapping(value = "/order/pickUp", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("用戶自提,传参:{orderId}")
+    public OutDTO pickUpOrder(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        CardGroupOrderInfo condition = new CardGroupOrderInfo();
+        condition.setUserId(userInfo.getId().longValue());
+        condition.setId(Long.valueOf((inDto.get("orderId").toString())));
+        condition.setStatus(103L);
+        //condition.setRefuseStatus(0);
+        CardGroupOrderInfo orderInfo = suidRich.selectOne(condition);
+        if (orderInfo == null) {
+            return OutDTO.error(10010, "订单不符合自提要求!");
+        }
+        CardGroupOrderInfo updateInfo = new CardGroupOrderInfo();
+        updateInfo.setStatus(301L);
+        updateInfo.setPickUpType("1");
+        updateInfo.setShipTime(DateUtils.getTimestampNow());
+        updateInfo.setFinishedTime(DateUtils.getTimestampNow());
+        if(Constants.ORDER_TYPE_GROUP.equals(orderInfo.getOrderType())){
+            //组团下所有中卡订单全部改为自提
+            //自提确认收货 即代表订单完成
+            Condition beeCondition = new ConditionImpl();
+            beeCondition.op("status", Op.eq, 103)
+                    .op("groupInfoId", Op.eq, orderInfo.getGroupInfoId())
+                    .op("refuseStatus", Op.lt, 3)
+                    .op("userId", Op.eq, userInfo.getId());
+            suidRich.update(updateInfo, "status,pickUpType,shipTime,finishedTime",beeCondition);
+        }else if(Constants.ORDER_TYPE_SHOP.equals(orderInfo.getOrderType())){
+            //商城订单
+            updateInfo.setId(orderInfo.getId());
+            if(!Constants.payment_type.contains(orderInfo.getPaymentType()) ){
+                updateInfo.setClosePaymentStatus(100);//商城订单的打款状态: 0=未结束,100=可申请,200=申请中,300=已打款
+                try {
+                    Date afterNumWorkDay = DateUtils.getNumWorkDayByNow(new Date(), 5);
+                    updateInfo.setClosePaymentTime(afterNumWorkDay);
+                } catch (ParseException e) {
+                    e.printStackTrace();
+                }
+            }
+            suidRich.update(updateInfo);
+            asyncAppService.addPointByMallOrder(orderInfoService.selectCardGroupOrderInfoById(orderInfo.getId()));
+        }
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "限额提醒", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    //@RequestMapping(value = "/payMsgFlag", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("限额提醒")
+    public OutDTO payMsgFlag(@RequestBody InDto inDto) {
+        AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+        String key = LocalDate.now() + "_" + inDto.getUserId();
+        boolean msgOfDay = RedisTools.getRedisUtils().hHasKey(Constants.USER_PAY_REMIND, key);
+        if (msgOfDay) {
+            return OutDTO.ok().put("payMsgFlag", false);
+        }
+        String sql = QuerySql.getQuerySql("com.tzy.sportcard.api.domain.AppUserInfoDto.getUserOrderAmountOfDay");
+        String s = preparedSql.selectFun(sql, new Object[]{inDto.getUserId()});
+        boolean flag = false;
+        if (Constants.ONE.equals(appUserInfoDto.getOpenPayAmount())
+                && new BigDecimal(appUserInfoDto.getPayAmountOfDay()).compareTo(new BigDecimal(s)) == -1) {
+            flag = true;
+            RedisTools.getRedisUtils().hset(Constants.USER_PAY_REMIND, key, 1, 24 * 60 * 60);
+        }
+        return OutDTO.ok().put("payMsgFlag", flag);
+    }
+
+    @ApiLog(title = "限额提醒V2", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/payMsgFlag", method = RequestMethod.POST)
+    @ApiVersion(2.2)
+    @ApiOperation("限额提醒2")
+    public OutDTO payMsgFlagV2(@RequestBody InDto inDto) {
+        AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+        String key = Constants.USER_PAY_REMIND + LocalDate.now() + "_" + appUserInfoDto.getId();
+        String sql = QuerySql.getQuerySql("com.tzy.sportcard.api.domain.AppUserInfoDto.getUserOrderAmountOfDay");
+        String s = preparedSql.selectFun(sql, new Object[]{inDto.getUserId()});
+        BigDecimal userDayAmount = new BigDecimal(s);
+        if (!redisUtils.hasKey(key) && Constants.ONE.equals(appUserInfoDto.getOpenPayAmount()) && new BigDecimal(appUserInfoDto.getPayAmountOfDay()).compareTo(userDayAmount) == -1) {
+            redisUtils.set(key, 1, 12 * 60 * 60);
+            return OutDTO.ok().put("payMsgFlag", true).put("type", "user").put("amount", appUserInfoDto.getPayAmountOfDay());
+        }
+
+        if (!redisUtils.hasKey(key + "_day")) {
+            List<SysDictData> remindDay = commonCacheService.getCommonDictData(Constants.USER_PAY_REMIND_DAY, null, null, Constants.USER_PAY_REMIND_DAY, -1);
+            int remindDayAmount = CollectionUtils.isEmpty(remindDay) ? 5000 : Integer.parseInt(remindDay.get(0).getDictValue());
+            if (userDayAmount.doubleValue() > remindDayAmount) {
+                redisUtils.set(key + "_day", 1, 12 * 60 * 60);
+                return OutDTO.ok().put("payMsgFlag", true).put("type", "day").put("amount", remindDayAmount);
+            }
+        }
+        if (!redisUtils.hasKey(key + "_month")) {
+            String sql2 = QuerySql.getQuerySql("com.tzy.sportcard.api.domain.AppUserInfoDto.getUserOrderAmountOfMonth");
+            String monthAmount = preparedSql.selectFun(sql2, new Object[]{inDto.getUserId()});
+            List<SysDictData> remindMonth = commonCacheService.getCommonDictData(Constants.USER_PAY_REMIND_MONTH, null, null, Constants.USER_PAY_REMIND_MONTH, -1);
+            int remindMonthAmount = CollectionUtils.isEmpty(remindMonth) ? 30000 : Integer.parseInt(remindMonth.get(0).getDictValue());
+            if (new BigDecimal(monthAmount).doubleValue() > remindMonthAmount) {
+                redisUtils.set(key + "_month", 1, 12 * 60 * 60);
+                return OutDTO.ok().put("payMsgFlag", true).put("type", "month").put("amount", remindMonthAmount);
+            }
+        }
+        return OutDTO.ok().put("payMsgFlag", false);
+    }
+
+    private List<UserGroupOrderDTO> buildOrderGroupMerchant(Map<String, List<GroupUserOrderDto>> orders) {
+        List<UserGroupOrderDTO> data = new ArrayList<>();
+        Set<Map.Entry<String, List<GroupUserOrderDto>>> entries = orders.entrySet();
+        for (Map.Entry<String, List<GroupUserOrderDto>> entry : entries) {
+            List<GroupUserOrderDto> value = entry.getValue();
+            List<GroupUserOrderDto> infoOrder = value.stream().filter(o -> o.getId() != null).collect(Collectors.toList());
+            List<GroupUserOrderDto> mallOrder = value.stream().filter(o -> o.getId() == null).collect(Collectors.toList());
+            String[] merArray = entry.getKey().split("#");
+            data.add(new UserGroupOrderDTO(new SimpleMerchantInfo(Integer.valueOf(merArray[0]), merArray[1], merArray[2]), infoOrder,mallOrder));
+        }
+        return data;
+    }
+
+    @ApiLog(title = "获取用户名下累积发货订单(包含商城累计)", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/getWaitShippingOrder", method = RequestMethod.POST)
+    @ApiVersion(2.6)
+    @ApiOperation("获取用户名下累积发货订单(包含商城累计)")
+    public OutDTO getWaitShippingOrderV2(@RequestBody InDto inDto) {
+        UserInfo userInfo = UserUtils.getSimpleUserInfo();
+        if(userInfo==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        Integer refuseStatus = inDto.getIntegerParam("refuseStatus");
+        refuseStatus=refuseStatus==null?0:refuseStatus;
+        int size = inDto.getPageSize();
+        int offSet = (inDto.getPageNo() - 1) * size;
+
+        OutDTO result = OutDTO.ok();
+        ShippingQuery query = new ShippingQuery().setUserId(userInfo.getId()).setRefuseStatus(refuseStatus)
+                .setPageSize(size).setOffset(offSet).setKeyword(inDto.getString("keyword"));
+        List<GroupUserOrderDto> userOrders =orderInfoService.getUserWaitShippingOrder(query);
+        if (userOrders.isEmpty()) {
+            return result;
+        }
+        Map<String, List<GroupUserOrderDto>> data = new HashMap<>();
+        Map<String, String> address = new HashMap<>();
+        GroupUserOrderDto firstOrder = userOrders.get(0);
+        address.put("shippingAddressId", firstOrder.getShippingAddressId().toString());
+        address.put("shippingAddress", firstOrder.getShippingAddress());
+        address.put("shippingAddressLinkname", firstOrder.getShippingAddressLinkname());
+        address.put("shippingAddressPhone", firstOrder.getShippingAddressPhone());
+        List<Integer> userOrderIds = userOrders.stream().filter(o -> o.getId()!=null).map(GroupUserOrderDto::getUserOrderId).collect(Collectors.toList());
+        List<Carmichae> allCardGoods=new ArrayList<>();
+        if(!CollectionUtils.isEmpty(userOrderIds)){
+            allCardGoods = groupApiService.selectGoodsByOrderIds(userOrderIds, 1);
+        }
+        for (GroupUserOrderDto order : userOrders) {
+            if (order.getId()!=null) {
+                List<Carmichae> carmichael = allCardGoods.stream().filter(c -> c.getUserOrderId() == order.getUserOrderId().intValue()).collect(Collectors.toList());
+                order.setCarmichaels(carmichael);
+                if (!CollectionUtils.isEmpty(carmichael)) {
+                    List<String> collect = carmichael.stream().map(Carmichae::getCarmichael).filter(StringUtils::isNotEmpty).collect(Collectors.toList());
+                    order.setCarmichael(collect);
+                    List<String> collect2 = carmichael.stream().map(Carmichae::getPicture).filter(StringUtils::isNotEmpty).collect(Collectors.toList());
+                    order.setPictureList(collect2);
+                }
+            }
+            String key = order.getMerchantId() + "#" + order.getMerName() + "#" + order.getMerAvatar();
+            if (data.containsKey(key)) {
+                List<GroupUserOrderDto> value = data.get(key);
+                value.add(order);
+            } else {
+                List<GroupUserOrderDto> value = new ArrayList<>();
+                value.add(order);
+                data.put(key, value);
+            }
+        }
+        return result.put("groupOrders", buildOrderGroupMerchant(data))
+                .put("address", address);
+    }
+
+
+    @ApiLog(title = "用户消费总金额和支付限制", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/totalAmount", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("用户消费总金额和支付限制")
+    public OutDTO userTotalAmount(@RequestBody InDto inDto) {
+        if(inDto.getUserId()==null){
+            return OutDTO.ok();
+        }
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        Set<String> whitelist = getMarkUserIds();
+        if (!whitelist.isEmpty() && whitelist.contains(inDto.getUserId().toString())) {
+            return OutDTO.ok().put("totalAmount", BigDecimal.ZERO);
+        }
+        String sql = QuerySql.getQuerySql("com.tzy.sportcard.api.domain.AppUserInfoDto.getUserTotalAmount");
+        String s = preparedSql.selectFun(sql, new Object[]{userInfo.getId()});
+        List<SysDictData> payLimit = dictDataService.getByTypeAndStatus("user_pay_limit", Constants.STATUS_OK);
+        long count=3;
+        int time=1;
+        if(!payLimit.isEmpty()){
+            count=payLimit.get(0).getDictSort();
+            time=Integer.valueOf(payLimit.get(0).getDictValue());
+        }
+        String countSql = QuerySql.getQuerySql("com.tzy.sportcard.api.domain.AppUserInfoDto.getUserOrderCountByTime");
+        countSql +=" and (now() - create_time::timestamp < interval '"+time+" minute')";
+        String orderCount = preparedSql.selectFun(countSql, new Object[]{userInfo.getId()});
+        return OutDTO.ok().put("totalAmount", new BigDecimal(s)).put("payLimit",Integer.valueOf(orderCount)>=count);
+    }
+
+    private Set<String> getMarkUserIds() {
+        Object o = redisUtils.get(Constants.WHITELIST_FAVE_VERIFY_USER);
+        if (o == null) {
+            SysDictData dictData = new SysDictData();
+            dictData.setDictType(Constants.WHITELIST_FAVE_VERIFY_USER);
+            dictData.setStatus(Constants.STATUS_OK);
+            List<SysDictData> list = dictDataService.selectDictDataList(dictData);
+            Set<String> collect = new HashSet<>();
+            if (!list.isEmpty()) {
+                collect = list.stream().map(d -> d.getDictValue()).collect(Collectors.toSet());
+                redisUtils.set(Constants.WHITELIST_FAVE_VERIFY_USER, collect, 60);
+            }
+            return collect;
+        }
+        return (Set<String>) o;
+    }
+
+    /**
+     * 查询我的关注,收藏信息
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "查询我的关注,收藏信息", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+    @ResponseBody
+    @ApiOperation("用户我的数量显示")
+    @RequestMapping(value = "/getMinesCount", method = RequestMethod.POST)
+    public OutDTO getMinesCount(@RequestBody InDto inDto) {
+        return OutDTO.ok();
+    }
+
+    /**
+     * 查询我的关注,收藏信息
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "查询我的关注,收藏信息", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+    @ResponseBody
+    @ApiOperation("查询我的所有数据")
+    @RequestMapping(value = "/getMineTotalCount", method = RequestMethod.POST)
+    public OutDTO getMineTotalCount(@RequestBody InDto inDto) throws Exception {
+        return OutDTO.ok();
+    }
+
+    /**
+     * 评论通用接口
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "评论通用接口", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+    @ResponseBody
+    @ApiOperation("评论通用接口")
+    @RequestMapping(value = "/common/evaluation", method = RequestMethod.POST)
+    public OutDTO evaluation(@RequestBody InDto inDto) {
+        if(StringUtils.isEmpty(inDto.getString("type"))||StringUtils.isEmpty(inDto.getString("refId"))){
+            return OutDTO.error500("参数为空!");
+        }
+
+        AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+        EvaluationRecord evaluationRecord = new EvaluationRecord();
+        evaluationRecord.setType(inDto.getString("type"));
+        evaluationRecord.setRefId(Long.valueOf(inDto.getString("refId")));
+        evaluationRecord.setCreateUserId(appUserInfoDto.getId());
+        List<EvaluationRecord> list = suidRich.select(evaluationRecord);
+        if (!list.isEmpty()) {
+            return OutDTO.error(500, "重复!");
+        }
+
+        evaluationRecord.setAvatar(appUserInfoDto.getAvatar());
+        evaluationRecord.setNickName(appUserInfoDto.getNickname());
+        evaluationRecord.setAnonymous((Integer) inDto.get("anonymous"));
+        evaluationRecord.setContent(inDto.getString("content"));
+        evaluationRecord.setImgUrl(inDto.getString("imgUrl"));
+        evaluationRecord.setValue((Integer) inDto.get("value"));
+
+        evaluationRecord.setCreateTime(DateUtils.getTimestampNow());
+        suidRich.insert(evaluationRecord);
+        if (inDto.get("orderId") != null) {
+            CardGroupOrderInfo update = new CardGroupOrderInfo();
+            update.setId(Long.valueOf((inDto.getString("orderId"))));
+            update.setEvaluation(JSONTools.obj2json(evaluationRecord));
+            suidRich.update(update);
+        }
+
+        if(Constants.EVALUATION_TYPE_LIST_CALENDAR.equals(evaluationRecord.getType())){
+            //日历点赞人数
+            checklistCalendarService.updateCalendarLikeNums(evaluationRecord.getRefId());
+        }
+        return OutDTO.ok();
+    }
+
+    /**
+     * 取消评论
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "取消评论", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+    @ResponseBody
+    @ApiOperation("取消评论")
+    @RequestMapping(value = "/common/evaluation/cancel", method = RequestMethod.POST)
+    public OutDTO delEvaluation(@RequestBody InDto inDto) {
+        if(StringUtils.isEmpty(inDto.getString("type"))||StringUtils.isEmpty(inDto.getString("refId"))){
+            return OutDTO.error500("参数为空!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        EvaluationRecord evaluationRecord = new EvaluationRecord();
+        evaluationRecord.setType(inDto.getString("type"));
+        evaluationRecord.setRefId(Long.valueOf(inDto.getString("refId")));
+        evaluationRecord.setCreateUserId(user.getId());
+        suidRich.delete(evaluationRecord);
+        if(Constants.EVALUATION_TYPE_LIST_CALENDAR.equals(evaluationRecord.getType())){
+            //日历点赞人数
+            checklistCalendarService.updateCalendarLikeNums(evaluationRecord.getRefId());
+        }
+        return OutDTO.ok();
+
+    }
+    /**
+     * 根据卡片数量计算物流费用
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "根据卡片数量计算物流费用", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+    @ResponseBody
+    @ApiOperation("根据卡片数量计算物流费用")
+    @PostMapping(value = "/shippingCost")
+    public OutDTO shippingCost(@RequestBody InDto inDto) {
+        Integer totalCount = inDto.getIntegerParam("totalCount");
+        Integer cardId = inDto.getIntegerParam("cardId");
+        Integer merchantId = inDto.getIntegerParam("merchantId");
+        BigDecimal cost;
+        if (merchantId == null) {
+            cost = getShippingCost(totalCount, cardId);
+        } else {
+            cost = getShippingCost(totalCount, cardId, merchantId);
+        }
+        return OutDTO.ok().put("cost", cost);
+    }
+
+
+    private BigDecimal getShippingCost(Integer totalCount, Integer cardId) {
+        if (totalCount < 1) {
+            throw new ServiceException(500, "订单数量异常");
+        }
+        String type = "shipping_cost";
+        String cost = "99";
+        String sql = QuerySql.getQuerySql("com.tzy.sportcard.api.domain.GroupUserOrderDto.getShippingCost");
+        try {
+            String cardType = cardId != null ? type + cardId : type;
+            cost = preparedSql.selectFun(sql, new Object[]{cardType, totalCount, totalCount});
+        } catch (Exception e) {
+            log.error("运费查询异常", e);
+        }
+        if (StringUtils.isEmpty(cost) || "-1".equals(cost)) {
+            cost = preparedSql.selectFun(sql, new Object[]{type, totalCount, totalCount});
+        }
+        return new BigDecimal(cost);
+    }
+
+    private BigDecimal getShippingCost(Integer totalCount, Integer cardId, Integer merchantId) {
+        if (totalCount < 1 || cardId == null) {
+            throw new ServiceException(500, "订单数量异常");
+        }
+        MerchantInfo merchant = merchantApiService.getMerchantInfo(merchantId);
+        if (StringUtils.isNotEmpty(merchant.getShippingCostConfig())) {
+            MerchantCostConfig costConfig = JSONTools.jsonStr2obj(merchant.getShippingCostConfig(), MerchantCostConfig.class);
+            return MerchantCostConfig.buildMerchantShippingCost(costConfig, totalCount);
+        }
+        List<SysDictData> merchantShippingCost = dictDataService.selectDictDataByCache("merchant_shipping_cost_config", merchantId.toString(), Constants.ONE, true);
+        String type = "shipping_cost";
+        String cardType = type + cardId;
+        if (!CollectionUtils.isEmpty(merchantShippingCost) && StringUtils.isNotEmpty(merchantShippingCost.get(0).getDictValue())) {
+            List<String> cardCost = Arrays.asList(merchantShippingCost.get(0).getDictValue().split(","));
+            if (cardCost.contains(cardId.toString())) {
+                cardType = "merchant_shipping_cost:" + merchantId;
+            }
+        }
+        String sql = QuerySql.getQuerySql("com.tzy.sportcard.api.domain.GroupUserOrderDto.getShippingCost");
+        String cost = "99";
+        try {
+            cost = preparedSql.selectFun(sql, new Object[]{cardType, totalCount, totalCount});
+        } catch (Exception e) {
+            log.error("运费查询异常", e);
+        }
+        if (StringUtils.isEmpty(cost) || "-1".equals(cost)) {
+            cost = preparedSql.selectFun(sql, new Object[]{type, totalCount, totalCount});
+        }
+        BigDecimal bigDecimal = new BigDecimal(cost);
+        if (bigDecimal.doubleValue() < 0) {
+            throw new ServiceException(500, "运费设置异常");
+        }
+        return new BigDecimal(cost);
+    }
+
+    /**
+     * 兑换商家积分
+     * 2023-3-29 弃用
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "兑换商家积分", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+    @ResponseBody
+    @ApiOperation("兑换商家积分")
+    //@RequestMapping(value = "/exchangePoint", method = RequestMethod.POST)
+    public OutDTO exchangePoint(@RequestBody InDto inDto) {
+        mineApiService.checkUserNew(inDto);
+        //多个用逗号隔开
+        String userOrderIds = inDto.getString("userOrderIds");
+        if (StringUtils.isEmpty(userOrderIds)) {
+            return OutDTO.error500("订单为空!");
+        }
+        String[] ids = userOrderIds.split(",");
+        for(String id :ids){
+            orderInfoService.exchangePoint(Long.valueOf(id));
+        }
+        return OutDTO.ok();
+    }
+
+    /**
+     * 查询用户商家积分
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "查询用户商家积分", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+    @ResponseBody
+    @ApiOperation("查询用户商家积分")
+    @RequestMapping(value = "/getMerchantPoint", method = RequestMethod.POST)
+    public OutDTO getMerchantPoint(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        String sql = QuerySql.getQuerySql("com.tzy.common.dto.MerchantPointDTO.getMerchantPoint");
+        List<MerchantPointDTO> points = preparedSql.selectSomeField(sql, new MerchantPointDTO(), new Object[]{userInfo.getId()});
+        //points.forEach(r -> r.setPointTypeMsg(dictDataService.getMerchantPointMsg(r.getType())));
+        return OutDTO.ok().put("points", points);
+    }
+
+
+    /**
+     * 查询用户商家积分
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "兑换优惠劵", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+    @ResponseBody
+    @ApiOperation("兑换优惠劵")
+    @RequestMapping(value = "/exchangeCoupon", method = RequestMethod.POST)
+    public OutDTO exchangeCoupon(@RequestBody InDto inDto) {
+//        AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+//        String cdkey = inDto.getString("cdkey");
+//        if(StringUtils.isEmpty(cdkey)){
+//            return OutDTO.error500("兑换码为空!");
+//        }
+//        return orderInfoService.exchangeCoupon(cdkey.trim(),appUserInfoDto.getId());
+        return OutDTO.error500("请下载最新版本app!");
+    }
+
+    /**
+     * 查询用户商家积分
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "兑换优惠劵", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+    @ResponseBody
+    @ApiOperation("兑换优惠劵")
+    @ApiLimitRule(seconds = 2,limitCount=10,type= LimitRule.ACT_TOKEN,msg="抱歉,抢购人数太多,请稍后再试!")
+    //@RequestMapping(value = "/exchange/coupon/id", method = RequestMethod.POST)
+    public OutDTO exchangeCouponById(@RequestBody InDto inDto) {
+        AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+        Object couponId = inDto.get("id");
+        if(couponId==null){
+            return OutDTO.error500("兑换参数为空!");
+        }
+        return orderInfoService.exchangeCouponById(Long.valueOf(couponId.toString()),appUserInfoDto.getId());
+    }
+
+
+    /**
+     * 查询用户商家积分
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "根据key查询优惠劵详情", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+    @ResponseBody
+    @ApiOperation("根据key查询优惠劵详情")
+    @RequestMapping(value = "/getCouponByKey", method = RequestMethod.POST)
+    public OutDTO getCouponByKey(@RequestBody InDto inDto) {
+        String cdkey = inDto.getString("cdkey");
+        if(StringUtils.isEmpty(cdkey)){
+            return OutDTO.error500("key为空!");
+        }
+        TzyCardBaseInfo condition = new TzyCardBaseInfo();
+        condition.setCdkey(cdkey.trim());
+        List<TzyCardBaseInfo> tzyCardBaseInfos = cardBaseInfoService.selectTzyCardBaseInfoList(condition);
+        if (tzyCardBaseInfos.isEmpty()) {
+            return OutDTO.error500("优惠劵不存在!");
+        }
+        TzyCardBaseInfo cardBaseInfo = tzyCardBaseInfos.get(0);
+        if(StringUtils.isNotEmpty(cardBaseInfo.getPointType())){
+            cardBaseInfo.setPointTypeMsg(dictDataService.getMerchantPointMsg(cardBaseInfo.getPointType()));
+        }
+        return OutDTO.ok().put("coupon",cardBaseInfo);
+    }
+
+    /**
+     * 查询用户商家积分
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "积分明细", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+    @ResponseBody
+    @ApiVersion(1.0)
+    @ApiOperation("积分明细")
+    @RequestMapping(value = "/pointRecord", method = RequestMethod.POST)
+    public OutDTO getPointRecordByType(@RequestBody InDto inDto) {
+        AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+        AppUserPointRecord recordCondition = new AppUserPointRecord();
+        Long userId = appUserInfoDto.getId().longValue();
+        recordCondition.setUserId(userId);
+        Condition condition = new ConditionImpl();
+        BigDecimal sumGrowth = new BigDecimal(0);
+        //类型,merchant
+        String type = inDto.getString("type");
+        if (Constants.POINT_TYPE_MERCHANT.equals(type)) {
+            condition.op("type", Op.eq, Constants.POINT_TYPE_MERCHANT);
+            condition.op("merchantId", Op.eq, Long.valueOf(inDto.getString("merchantId")));
+        } else if (Constants.POINT_TYPE_GOODS.equals(type)) {
+            condition.op("type", Op.eq, Constants.POINT_TYPE_GOODS);
+        } else if (StringUtils.isNotEmpty(type) && type.startsWith(Constants.POINT_TYPE_MERCHANT_ACT_PRE)) {
+            condition.op("type", Op.eq, type);
+            condition.op("merchantId", Op.eq, Long.valueOf(inDto.getString("merchantId")));
+        } else if (StringUtils.isNotEmpty(type) && type.startsWith(Constants.POINT_TYPE_HB_ACT_PRE)) {
+            condition.op("type", Op.eq, type);
+        } else if (Constants.POINT_TYPE_USER_GROWTH.equals(type)) {
+            // 会员成长值
+            condition.op("type", Op.eq, Constants.POINT_TYPE_USER_GROWTH);
+            String currentMonth = inDto.getString("currentMonth"); // 是否当月 0否 1是
+            String monthStr = DateUtils.dateTimeNow(DateUtils.YYYY_MM);
+            if ("0".equals(currentMonth)) {
+                monthStr = DateUtils.getLastMonthStr();
+                condition.op("createTime", Op.greatEqual, DateUtils.getLastMonthDay(1))
+                        .op("createTime", Op.lt, DateUtils.getFirstDayOfMonth());
+            } else {
+                condition.op("createTime", Op.greatEqual, DateUtils.getFirstDayOfMonth());
+            }
+            sumGrowth = appUserPointRecordService.sumGrowthByMonth(userId, monthStr);
+        } else if (StringUtils.isNotEmpty(type) && type.startsWith(Constants.BRAND_POINT_TYPE_PRE)) {
+            // 品牌会员积分
+            condition.op("type", Op.eq, type)
+                    .op("createTime", Op.greatEqual, DateUtils.getDateByDay(-90)); // 近90天
+        } else if (StringUtils.isNotEmpty(type) && type.startsWith(Constants.BRAND_GROWTH_TYPE_PRE)) {
+            // 品牌会员成长值
+            condition.op("type", Op.eq, type);
+            String currentMonth = inDto.getString("currentMonth"); // 是否当月 0否 1是
+            if ("0".equals(currentMonth)) {
+                condition.op("createTime", Op.greatEqual, DateUtils.getLastMonthDay(1))
+                        .op("createTime", Op.lt, DateUtils.getFirstDayOfMonth());
+            } else {
+                condition.op("createTime", Op.greatEqual, DateUtils.getFirstDayOfMonth());
+            }
+        }else if (StringUtils.isNotEmpty(type) && type.startsWith(Constants.POINT_TYPE_ACT_LUCKY)) {
+            condition.op("type", Op.eq, type);
+        } else {
+            condition.op("type", Op.likeRight, Constants.POINT_TYPE_COMMON)
+                    .op("createTime", Op.greatEqual, DateUtils.getDateByDay(-90)); // 近90天
+        }
+        String subType = inDto.getString("subType");
+        if(Constants.ADD.equals(subType)){
+            condition.op("changePoint", Op.gt,0);
+        }else if(Constants.SUB.equals(subType)){
+            condition.op("changePoint", Op.lt,0);
+        }
+        condition.orderBy("id", OrderType.DESC);
+        int page=inDto.getPageNo()!=null&&inDto.getPageNo()>1?inDto.getPageNo():1;
+        int size=inDto.getPageSize()!=null&&inDto.getPageSize()>1?inDto.getPageSize():10;
+        int offSet=(page-1)*size;
+        condition.start(offSet).size(size);
+        List<AppUserPointRecord> records = suidRich.select(recordCondition, condition);
+        String rStr="refund_"+userId+"_";
+        records.stream().filter(r -> r.getMerchantId() != null).forEach(r -> {
+            r.setPointTypeMsg(dictDataService.getMerchantPointMsg(r.getType()));
+            if (StringUtils.isNotEmpty(r.getRefId()) && r.getRefId().startsWith(rStr)) {
+                Long refundId = Long.valueOf(r.getRefId().replace(rStr, StringUtils.EMPTY));
+                PointRefundRecord refundRecord = mineApiService.getPointRecord(refundId);
+                if (refundRecord != null) {
+                    r.setRefundStatus(getPointRefundMsf(refundRecord.getStatus(),refundRecord.getMerchantRemark()));
+                }
+            }
+//            MerchantInfo merchant = merchantApiService.getMerchantByCache(r.getMerchantId().intValue());
+//            r.setRefundLimitDay(merchant.getRefundLimitDay());
+        });
+        return OutDTO.ok()
+                .put("records",records)
+                .put("sumGrowth", sumGrowth);
+    }
+
+    private String getPointRefundMsf(Integer status, String merchantRemark) {
+        String msg;
+        if (status == 6) {
+            msg = "已退款";
+        } else if (status == 2) {
+            msg = "退款失败【" + merchantRemark + "】";
+        } else if (status == 1) {
+            msg = "待审核";
+        }  else if (status == 5) {
+            msg = "退款失败【" + merchantRemark + "】";
+        } else {
+            msg = "退款中";
+        }
+        return msg;
+    }
+
+    /**
+     * 导出用户卡密
+     *
+     * @param
+     * @return
+     */
+    @ResponseBody
+    @ApiVersion(1.0)
+    @ApiOperation("导出用户卡密")
+    @GetMapping("/exportGoods")
+    @CrossOrigin(allowCredentials = "true")
+    public void exportGoods(Long groupInfoId, String code, String token, HttpServletResponse response) throws Exception {
+        if(groupInfoId==null||StringUtils.isEmpty(code)||StringUtils.isEmpty(token)){
+            throw new ServiceException(500,"参数为空!");
+        }
+        AppBaseUser user = new AppBaseUser();
+        user.setCode(code);
+        AppBaseUser existUser = suidRich.selectOne(user);
+        if(existUser == null){
+            throw new ServiceException(500,"用户不存在!");
+        }
+
+        if (Constants.APP_VERSION_PROD.equals(appVersion)) {
+            Object o = redisUtils.get("export_token" + existUser.getId());
+            if(Objects.isNull(o)){
+                throw new ServiceException(500,"token失效!");
+            }
+            if(StringUtils.isEmpty(token)||!token.equals(o.toString())){
+                throw new ServiceException(500,"token失效!");
+            }
+        }
+
+        CardGroupInfo cardGroupInfo = new CardGroupInfo();
+        cardGroupInfo.setId(groupInfoId);
+        CardGroupInfo info = suidRich.selectOne(cardGroupInfo);
+        if(info==null){
+            throw new ServiceException(500,"组团不存在");
+        }
+        UserGoodsDTO con = new UserGoodsDTO();
+        con.setGroupInfoId(info.getId());
+        con.setUserId(existUser.getId());
+        List<UserGoodsDTO> goods = suidRich.selectOrderBy(con, "cast(substring(no from '([0-9]+)$') as integer)");
+        if (goods.isEmpty()) {
+            throw new ServiceException(500, "卡密为空");
+        }
+        ExcelUtil<UserGoodsDTO> util = new ExcelUtil(UserGoodsDTO.class);
+        String fileName=info.getCode();
+        util.exportExcelHttp(goods, response,fileName);
+    }
+
+    /**
+     * 获取下载token
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "获取下载token", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(1.0)
+    @ApiOperation("获取下载token")
+    @PostMapping("/getExportToken")
+    public OutDTO getExportToken(@RequestBody InDto inDto) {
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        UUID uuid = UUID.randomUUID();
+        redisUtils.set("export_token"+user.getId(), uuid,30);
+        return OutDTO.ok().put("token",uuid);
+    }
+
+    /**
+     * 查询用户,仅用于code
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "查询用户", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(1.0)
+    @ApiOperation("查询用户")
+    @PostMapping("/getUser")
+    public OutDTO getUser(@RequestBody InDto inDto) {
+        if(StringUtils.isEmpty(inDto.getString("code"))){
+            return OutDTO.error500("code为空!");
+        }
+        AppBaseUser user = new AppBaseUser();
+        user.setCode(inDto.getString("code"));
+        AppBaseUser existUser = suidRich.selectOne(user);
+        return OutDTO.ok().put("user",existUser);
+    }
+
+    /**
+     * 赠送优惠劵
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "赠送优惠劵", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(1.0)
+    @ApiOperation("赠送优惠劵")
+    @PostMapping("/giveawayCoupon")
+    public OutDTO giveawayCoupon(@RequestBody InDto inDto) {
+        AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+        Object couponId = inDto.get("couponId");
+        Object userId = inDto.get("userId");
+        if(couponId==null||userId==null){
+            return OutDTO.error500("参数为空!");
+        }
+
+        com.tzy.coupon.card.domain.AppUserCardRecord appUserCardRecord = new com.tzy.coupon.card.domain.AppUserCardRecord();
+        appUserCardRecord.setUserId(appUserInfoDto.getId().longValue());
+        appUserCardRecord.setColumnsearch(" and cbi.give_status=1 and aucr.id = " + couponId);
+        CouponInfo giveCoupon = mineApiService.getOneMineCard(appUserCardRecord);
+        if(giveCoupon==null){
+            return OutDTO.error500("优惠劵不存在!");
+        }
+
+        AppUserCardRecord coupon = new AppUserCardRecord();
+        coupon.setId(Long.parseLong(couponId.toString()));
+        coupon.setUserId(Long.valueOf(userId.toString()));
+        suidRich.update(coupon);
+        return OutDTO.ok();
+    }
+
+    /**
+     * 获取用户名下所有积分
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "获取用户名下所有积分", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(1.0)
+    @ApiOperation("获取用户名下所有积分")
+    @PostMapping("/point")
+    public OutDTO getPoint(@RequestBody InDto inDto) {
+        AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+        AppUserPoint userPoint = new AppUserPoint();
+        userPoint.setUserId(appUserInfoDto.getId());
+        if(StringUtils.isNotEmpty(inDto.getString("type"))){
+            userPoint.setType(inDto.getString("type"));
+        }
+        List<AppUserPoint> points = suidRich.select(userPoint);
+        Map<String, List<AppUserPoint>> pointType=null;
+        if(!points.isEmpty()){
+            pointType = points.stream().collect(Collectors.groupingBy(AppUserPoint::getName));
+        }
+        return OutDTO.ok().put("userPoint",pointType);
+    }
+
+    /**
+     * 拉黑商家
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "拉黑商家", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(1.0)
+    @ApiOperation("拉黑商家")
+    @PostMapping("/pullBack")
+    public OutDTO pullBack(@RequestBody InDto inDto) {
+        if(inDto.get("merchantId")==null&&inDto.get("merchantAppUserId")==null){
+            return OutDTO.error500("参数为空");
+        }
+        Long merchantId;
+        if(inDto.get("merchantId")!=null){
+            merchantId= Long.parseLong(inDto.getString("merchantId"));
+        }else{
+            MerchantInfo merchantInfo=merchantApiService.getMerchantByAppUserId((Integer)inDto.get("merchantAppUserId"));
+            merchantId=merchantInfo.getId().longValue();
+        }
+
+        AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+        AppMerchantFans appMerchantFans = new AppMerchantFans();
+        appMerchantFans.setUserId(appUserInfoDto.getId().longValue());
+        appMerchantFans.setMerchantId(merchantId);
+        appMerchantFans.setType(Constants.FANS_TYPE_USER_DISLIKE);
+        if(inDto.get("status")==null||Constants.STATUS_OK.equals(inDto.getString("status"))){
+            List<AppMerchantFans> existFans = suidRich.select(appMerchantFans);
+            if(existFans.isEmpty()){
+                appMerchantFans.setCreateTime(new Date());
+                suidRich.insert(appMerchantFans);
+            }
+        }else{
+            suidRich.delete(appMerchantFans);
+        }
+        redisUtils.del("user_dislike_merchant:"+inDto.getUserId());
+        return OutDTO.ok();
+    }
+
+    /**
+     * 获取抢购token
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "获取抢购token", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(1.0)
+    @ApiOperation("获取抢购token")
+    @ApiLimitRule(seconds = 1,limitCount=1,type= LimitRule.USER,msg="火爆抢购中,请稍后再试!")
+    @PostMapping("/getActToken")
+    public OutDTO getActToken(@RequestBody InDto inDto) throws Exception {
+        mineApiService.checkUserNew(inDto);
+        String key=Constants.AES_TOKEN_CACHE+"_EXPIRE_TIME";
+        Object token = redisUtils.rightPop(Constants.AES_TOKEN_CACHE);
+        if(token!=null){
+            redisUtils.set(Constants.ACT_USER_TOKEN_CACHE+inDto.getUserId(),token.toString(),30);
+            return OutDTO.ok().put("token",AESUtil.encryptData(token.toString(),Constants.AES_TOKEN_PASSWORD));
+        }
+
+        if(redisUtils.hasKey(key)){
+            return OutDTO.error500("火爆抢购中,请稍后再试!");
+        }else{
+            redisUtils.set(key,1,2);
+            List<String> tokens = new ArrayList<>(20);
+            for(int i = 0; i <20;i++){
+                tokens.add(UUID.randomUUID().toString());
+            }
+            redisUtils.lCommit(Constants.AES_TOKEN_CACHE,tokens);
+            token=redisUtils.rightPop(Constants.AES_TOKEN_CACHE).toString();
+            redisUtils.set(Constants.ACT_USER_TOKEN_CACHE+inDto.getUserId(),token.toString(),30);
+            return OutDTO.ok().put("token",AESUtil.encryptData(token.toString(),Constants.AES_TOKEN_PASSWORD));
+        }
+    }
+
+    /**
+     * 批量解锁卡片
+     */
+    @ApiLog(title = "批量解锁卡片",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @RequestMapping(value = "/batch/unlockGoods", method = RequestMethod.POST)
+    public OutDTO unlockGoods(@RequestBody InDto inDto) {
+        mineApiService.checkUserNew(inDto);
+        String ids = inDto.getString("ids");
+        if (StringUtils.isEmpty(ids)){
+            return OutDTO.error500("参数[ids]不能为空");
+        }
+        List<Integer> idList = Arrays.asList(ids.split(",")).stream().map(id -> Integer.valueOf(id)).collect(Collectors.toList());
+        groupApiService.unlockGoodsByIds(idList);
+        return OutDTO.ok();
+    }
+
+
+    /**
+     * 注销
+     */
+    @ApiLog(title = "注销", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/logoff")
+    public OutDTO logoff(@RequestBody InDto inDto) {
+        AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+        mineApiService.checkUserOff(appUserInfoDto.getId());
+        com.tzy.app.domain.AppAccount appAccount = new com.tzy.app.domain.AppAccount();
+        appAccount.setAccount(appUserInfoDto.getAccount());
+        appAccount.setDelFlg(1);
+        appAccount.setLogOffTime(new Date());
+        appAccountService.updateByAccount(appAccount);
+        return OutDTO.ok();
+    }
+
+    /**
+     * 赠送卡密
+     */
+    @ApiLog(title = "赠送卡密",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @RequestMapping(value = "/giveawayGoods", method = RequestMethod.POST)
+    public OutDTO giveawayGoods(@RequestBody InDto inDto) throws Exception {
+        String ids = inDto.getString("ids");
+        if (StringUtils.isEmpty(ids)){
+            return OutDTO.error500("参数[ids]不能为空");
+        }
+        Object receiveUserId = inDto.get("receiveUserId");
+        if(receiveUserId==null){
+            return OutDTO.error500("被赠与方不能为空");
+        }
+        Integer groupInfoId = (Integer) inDto.get("groupInfoId");
+        AppUserInfoDto appUserInfo = mineApiService.checkUserNew(inDto);
+        String key="app_order_receive"+appUserInfo.getId();
+        if(redisUtils.hasKey(key)){
+            return OutDTO.error500("操作频繁,请稍后再试!");
+        }
+        redisUtils.set(key,1,10);
+        Set<Long> idSet = Arrays.stream(ids.split(",")).map(Long::valueOf).collect(Collectors.toSet());
+        orderInfoService.giveawayGoods(appUserInfo,(Integer)receiveUserId,new ArrayList<>(idSet),groupInfoId);
+        redisUtils.del(key);
+        return OutDTO.ok();
+    }
+
+    private List<GiveReceiveGoods> getGiveReceiveGoods(ReceiveGoodsDTO ro,String type) {
+        boolean isGive=Constants.ORDER_SUB_TYPE_GIVE_AWAY.equals(type);
+        Long orderId=isGive?ro.getRefOrderId():ro.getOrderId();
+        GiveReceiveGoods cond = new GiveReceiveGoods();
+        cond.setOrderId(orderId);
+        cond.setType(Constants.ORDER_SUB_TYPE_RECEIVE);
+        return suidRich.select(cond);
+    }
+
+    /**
+     * 赠送,接收卡密记录
+     * V2:兼容新库卡密
+     */
+    @ApiLog(title = "赠送,接收卡密记录",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @RequestMapping(value = "/giveOrReceiveGoodsRecord", method = RequestMethod.POST)
+    @ApiVersion(2.0)
+    public OutDTO giveOrReceiveGoodsRecordV2(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        String type = inDto.getString("type");
+        if(!(Constants.ORDER_SUB_TYPE_GIVE_AWAY.equals(type)|| Constants.ORDER_SUB_TYPE_RECEIVE.equals(type))){
+            return OutDTO.error500("类型不存在");
+        }
+
+        String keyword = inDto.getString("keyword");
+        PageInfo<ReceiveGoodsDTO> orderPage=orderInfoService.getGiveReceiveOrder(userInfo.getId(),type,keyword,inDto.getPageNo(),inDto.getPageSize());
+        orderPage.getList().forEach(g -> g.setGoods(getGiveReceiveGoods(g,type)));
+
+        String countSql=QuerySql.getQuerySql("com.tzy.sportcard.api.dto.ReceiveGoodsDTO.getGiveReceiveGoodsCount");
+        String giveCount = preparedSql.selectFun(countSql, new Object[]{userInfo.getId(),Constants.ORDER_SUB_TYPE_GIVE_AWAY});
+        String receiveCount = preparedSql.selectFun(countSql, new Object[]{userInfo.getId(),Constants.ORDER_SUB_TYPE_RECEIVE});
+
+        return OutDTO.ok().put("receiveOrders",orderPage.getList()).put("total",orderPage.getTotal())
+                .put("receiveCount",receiveCount).put("giveCount",giveCount);
+    }
+
+
+    /**
+     * 查看接受的卡密订单
+     */
+    @ApiLog(title = "查看接受的卡密订单",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @RequestMapping(value = "/readReceiveOrder", method = RequestMethod.POST)
+    public OutDTO readReceiveOrder(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        CardGroupOrderInfo condition = new CardGroupOrderInfo();
+        condition.setOrderSubType(Constants.ORDER_SUB_TYPE_RECEIVE);
+        condition.setUserId(userInfo.getId().longValue());
+        condition.setReadFlag(0);
+
+        CardGroupOrderInfo updateOrder = new CardGroupOrderInfo();
+        updateOrder.setReadFlag(1);
+        updateOrder.setUpdateTime(DateUtils.getTimestampNow());
+        suidRich.update(condition,updateOrder);
+        return OutDTO.ok();
+    }
+
+
+    /**
+     * 查询赠送卡密历史用户
+     */
+    @ApiLog(title = "查询赠送卡密历史用户",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @RequestMapping(value = "/getGiveHistoryUser", method = RequestMethod.POST)
+    public OutDTO getGiveHistoryUser(@RequestBody InDto inDto) {
+        mineApiService.checkUserNew(inDto);
+        String sql=QuerySql.getQuerySql("com.tzy.common.dto.GiveUserDTO.getGiveHistoryUser");
+        String keyword = inDto.getString("keyword");
+        StringBuffer querySql=new StringBuffer("");
+        if(StringUtils.isNotEmpty(keyword)){
+            querySql.append(" and  u.nickname ILIKE '%").append(keyword).append("%'");
+        }
+        String aftSql=" GROUP BY u.code,u.id,u.nickname,u.avatar order by  num desc";
+        sql=sql+querySql.toString()+aftSql;
+        int offSet=(inDto.getPageNo()-1)*inDto.getPageSize();
+        List<GiveUserDTO> giveUsers = preparedSql.selectSomeField(sql, new GiveUserDTO(), new Object[]{inDto.getUserId()},offSet,inDto.getPageSize());
+        return OutDTO.ok().put("giveUsers",giveUsers);
+    }
+
+
+    /**
+     * 添加发票抬头信息
+     */
+    @ApiLog(title = "添加发票抬头信息",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("添加发票抬头信息,参数:AppUserInvoice")
+    @ResponseBody
+    @RequestMapping(value = "/invoice/add", method = RequestMethod.POST)
+    public OutDTO addInvoice(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        AppUserInvoice userInvoice = new AppUserInvoice();
+        BeanUtil.populate(userInvoice,inDto.getData());
+
+        if(StringUtils.isEmpty(userInvoice.getInvoiceName())){
+            return OutDTO.error500("发票抬头信息为空!");
+        }
+
+        AppUserInvoice condition = new AppUserInvoice();
+        condition.setUserId(userInfo.getId().longValue());
+        condition.setTaxId(userInvoice.getTaxId()); // 税号
+        condition.setInvoiceName(userInvoice.getInvoiceName()); // 抬头名称
+        condition.setEmail(userInvoice.getEmail()); // 邮箱
+        /*if(Constants.INVOICE_TYPE_COMPANY.equals(userInvoice.getType())){
+            if(StringUtils.isEmpty(userInvoice.getTaxId())){
+                return OutDTO.error500("发票信息为空!");
+            }
+            condition.setTaxId(userInvoice.getTaxId());
+        }else{
+            condition.setInvoiceName(userInvoice.getInvoiceName());
+        }*/
+        List<AppUserInvoice> existInvoice = suidRich.select(condition);
+        if(!CollectionUtils.isEmpty(existInvoice)){
+            return OutDTO.error(10500, "发票信息重复!");
+        }
+        userInvoice.setCreateTime(DateUtils.getTimestampNow());
+        userInvoice.setUserId(userInfo.getId().longValue());
+        userInvoice.setStatus(1);
+        if(userInvoice.getDefaultFlag()){
+            // 如果设置了默认抬头、把该用户所有的抬头改成false
+            cardGroupOrderInfoService.updateInvoice(userInvoice.getUserId());
+        }
+        suidRich.insert(userInvoice);
+        return OutDTO.ok();
+    }
+
+    /**
+     * 修改发票抬头信息
+     */
+    @ApiLog(title = "修改发票抬头信息",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("修改发票抬头信息,参数:AppUserInvoice")
+    @ResponseBody
+    @RequestMapping(value = "/invoice/update", method = RequestMethod.POST)
+    public OutDTO updateInvoice(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        AppUserInvoice userInvoice = new AppUserInvoice();
+        BeanUtil.populate(userInvoice,inDto.getData());
+
+        if(StringUtils.isEmpty(userInvoice.getInvoiceName())||userInvoice.getId()<1){
+            return OutDTO.error500("发票抬头信息为空!");
+        }
+        userInvoice.setCreateTime(null);
+        userInvoice.setUpdateTime(DateUtils.getTimestampNow());
+        if(userInvoice.getDefaultFlag()){
+            // 如果设置了默认抬头、把该用户所有的抬头改成false
+            cardGroupOrderInfoService.updateInvoice(userInvoice.getUserId());
+        }
+        suidRich.update(userInvoice);
+        return OutDTO.ok();
+    }
+
+    /**
+     * 删除发票抬头信息
+     */
+    @ApiLog(title = "删除发票抬头信息",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("删除发票抬头信息,参数:id")
+    @ResponseBody
+    @RequestMapping(value = "/invoice/del", method = RequestMethod.POST)
+    public OutDTO delInvoice(@RequestBody InDto inDto) {
+        Integer id = (Integer) inDto.get("id");
+        if(id==null){
+            return OutDTO.error500("id为空");
+        }
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        AppUserInvoice userInvoice = new AppUserInvoice();
+        userInvoice.setId(id.longValue());
+        suidRich.delete(userInvoice);
+        return OutDTO.ok();
+    }
+    /**
+     * 获取发票抬头信息
+     */
+    @ApiLog(title = "获取发票抬头信息",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("获取发票抬头信息,无参数")
+    @ResponseBody
+    @RequestMapping(value = "/invoice/list", method = RequestMethod.POST)
+    public OutDTO getInvoice(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        AppUserInvoice userInvoice = new AppUserInvoice();
+        userInvoice.setUserId(userInfo.getId().longValue());
+        List<AppUserInvoice> invoiceList = suidRich.selectOrderBy(userInvoice,"id",new OrderType[] {OrderType.DESC});
+        return OutDTO.ok().put("invoiceList",invoiceList);
+    }
+
+    /**
+     * 获取申请开票金额v3
+     */
+    @ApiLog(title = "获取申请开票金额v3",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("获取申请开票金额,参数:merchantId")
+    @ApiVersion(3.3)
+    @ResponseBody
+    @RequestMapping(value = "/invoice/amount", method = RequestMethod.POST)
+    public OutDTO openInvoiceAmountV3(@RequestBody InDto inDto) {
+        Integer merchantId = inDto.getIntegerParam("merchantId");
+        if (merchantId == null) {
+            return OutDTO.error500("merchantId为空");
+        }
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        if (user == null) {
+            return OutDTO.error500("请先登录!");
+        }
+        String orderType = inDto.getString("orderType");
+        if(Strings.isEmpty(orderType)){ // 默认拼团订单
+            orderType = "group";
+        }
+        InvoiceOrderQuery query = new InvoiceOrderQuery()
+                .setMerchantId(merchantId)
+                .setUserId(user.getId())
+                .setLimitTime(!checkUserInvoiceOpen(user.getId()))
+                .setOrderType(orderType);
+        query.setPageNo(inDto.getPageNo());
+        query.setPageSize(inDto.getPageSize());
+        PageInfo<SimpleOrderDTO> orderPage = orderInfoService.getMerchantInvoiceOrderV3(query);
+        if (inDto.getPageNo() == 1 && CollectionUtils.isEmpty(orderPage.getList())) {
+            return OutDTO.error500("不存在需要开票的订单!");
+        }
+        List<InvoiceMerchantDTO> merchants = orderInfoService.getInvoiceMerchantV3(user.getId(), merchantId, !checkUserInvoiceOpen(user.getId()), orderType);
+        BigDecimal invoiceAmount = CollectionUtils.isEmpty(merchants) ? BigDecimal.ZERO : merchants.get(0).getInvoiceAmount();
+        return OutDTO.ok().put("invoiceAmount", invoiceAmount).put("orderPage", orderPage);
+    }
+
+    /**
+     * 获取申请开票金额v2
+     */
+    @ApiLog(title = "获取申请开票金额v2",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("获取申请开票金额,参数:merchantId")
+    @ApiVersion(1.0)
+    @ResponseBody
+    @RequestMapping(value = "/invoice/amount", method = RequestMethod.POST)
+    public OutDTO openInvoiceAmountV2(@RequestBody InDto inDto) {
+        Integer merchantId = inDto.getIntegerParam("merchantId");
+        if (merchantId == null) {
+            return OutDTO.error500("merchantId为空");
+        }
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        if (user == null) {
+            return OutDTO.error500("请先登录!");
+        }
+        InvoiceOrderQuery query = new InvoiceOrderQuery().setMerchantId(merchantId).setUserId(user.getId()).setLimitTime(!checkUserInvoiceOpen(user.getId()));
+        query.setPageNo(inDto.getPageNo());
+        query.setPageSize(inDto.getPageSize());
+        PageInfo<SimpleOrderDTO> orderPage = orderInfoService.getMerchantInvoiceOrder(query);
+        if (inDto.getPageNo() == 1 && CollectionUtils.isEmpty(orderPage.getList())) {
+            return OutDTO.error500("不存在需要开票的订单!");
+        }
+        List<InvoiceMerchantDTO> merchants = orderInfoService.getInvoiceMerchant(user.getId(), merchantId, !checkUserInvoiceOpen(user.getId()));
+        BigDecimal invoiceAmount = CollectionUtils.isEmpty(merchants) ? BigDecimal.ZERO : merchants.get(0).getInvoiceAmount();
+        return OutDTO.ok().put("invoiceAmount", invoiceAmount).put("orderPage", orderPage);
+    }
+
+    /**
+     * 申请开票
+     */
+    @ApiLog(title = "申请开票v3",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("申请开票v3,参数:merchantId,invoiceId")
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    @ResponseBody
+    @RequestMapping(value = "/invoice/open", method = RequestMethod.POST)
+    @ApiVersion(3.3)
+    public OutDTO openInvoiceV3(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        Integer merchantId = inDto.getIntegerParam("merchantId");
+        if (merchantId == null) {
+            return OutDTO.error500("merchantId为空");
+        }
+        Integer invoiceId = inDto.getIntegerParam("invoiceId");
+        if (invoiceId == null) {
+            return OutDTO.error500("invoiceId为空");
+        }
+        String orderType = inDto.getString("orderType");
+        if(Strings.isEmpty(orderType)){ // 默认拼团订单
+            orderType = "group";
+        }
+        String orderIds =  inDto.getString("orderIds");
+        String key="invoice_"+user.getId();
+        if(redisUtils.hasKey(key)){
+            return OutDTO.error500("申请频繁,请稍后再试!");
+        }
+        AppUserInvoiceRecord invoiceRecord=orderInfoService.openInvoiceV3(user,merchantId,invoiceId,orderIds, orderType);
+        redisUtils.del(key);
+        return OutDTO.ok().put("invoiceRecord",invoiceRecord);
+    }
+
+    /**
+     * 申请开票
+     */
+    @ApiLog(title = "申请开票v2",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("申请开票v2,参数:merchantId,invoiceId")
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    @ResponseBody
+    @RequestMapping(value = "/invoice/open", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    public OutDTO openInvoiceV2(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        Integer merchantId = inDto.getIntegerParam("merchantId");
+        if (merchantId == null) {
+            return OutDTO.error500("merchantId为空");
+        }
+        Integer invoiceId = inDto.getIntegerParam("invoiceId");
+        if (invoiceId == null) {
+            return OutDTO.error500("invoiceId为空");
+        }
+        String orderIds =  inDto.getString("orderIds");
+        String key="invoice_"+user.getId();
+        if(redisUtils.hasKey(key)){
+            return OutDTO.error500("申请频繁,请稍后再试!");
+        }
+        AppUserInvoiceRecord invoiceRecord=orderInfoService.openInvoiceV2(user,merchantId,invoiceId,orderIds);
+        redisUtils.del(key);
+        return OutDTO.ok().put("invoiceRecord",invoiceRecord);
+    }
+
+    /**
+     * 获取开票记录
+     */
+    @ApiLog(title = "获取开票记录",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("获取开票记录,参数:status")
+    @ResponseBody
+    @RequestMapping(value = "/invoice/mine", method = RequestMethod.POST)
+    public OutDTO mineInvoice(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        AppAssert.notNull(user,MsgConstants.NEED_LOGIN);
+        Integer merchantId = null;
+        Integer userId = null;
+        if(StringUtils.isNotEmpty(inDto.getString("merchant"))){
+            AppAssert.notNull(user.getMerchantId(),MsgConstants.NEED_LOGIN);
+            merchantId = user.getMerchantId();
+        }else{
+            userId = user.getId();
+        }
+        PageInfo<AppUserInvoiceRecord> recordList = appUserInvoiceRecordService.page(inDto.getPageNo(), inDto.getPageSize(), merchantId, userId, (Integer) inDto.get("status"), inDto.getString("keyword"));
+        return OutDTO.ok().put("invoiceRecord",recordList.getList());
+
+    }
+
+    /**
+     * 获取开票记录
+     */
+    @ApiLog(title = "获取开票记录",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("获取开票记录,参数:status")
+    @ApiVersion(3.3)
+    @ResponseBody
+    @RequestMapping(value = "/invoice/mine", method = RequestMethod.POST)
+    public OutDTO mineInvoiceV3(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        AppAssert.notNull(user,MsgConstants.NEED_LOGIN);
+        Integer merchantId = null;
+        Integer userId = null;
+        if(StringUtils.isNotEmpty(inDto.getString("merchant"))){
+            AppAssert.notNull(user.getMerchantId(),MsgConstants.NEED_LOGIN);
+            merchantId = user.getMerchantId();
+        }else{
+            userId = user.getId();
+        }
+        String orderType = inDto.getString("orderType");
+        PageInfo<AppUserInvoiceRecord> recordList = appUserInvoiceRecordService.pageV3(inDto.getPageNo(), inDto.getPageSize(),
+                merchantId, userId,
+                (Integer) inDto.get("status"),
+                inDto.getString("keyword"), orderType);
+        return OutDTO.ok().put("invoiceRecord",recordList.getList());
+
+    }
+
+    /**
+     * 获取开票关联订单
+     */
+    @ApiLog(title = "获取开票关联订单",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("查询发票关联订单,参数:invoiceId")
+    @ApiVersion(1.0)
+    @ResponseBody
+    @RequestMapping(value = "/invoice/order", method = RequestMethod.POST)
+    public OutDTO mineInvoiceOrder(@RequestBody InDto inDto) {
+        mineApiService.checkUserNew(inDto);
+        Integer invoiceId = (Integer) inDto.get("invoiceId");
+        if (invoiceId == null) {
+            return OutDTO.error500("invoiceId为空");
+        }
+
+        SimpleOrderDTO condition = new SimpleOrderDTO();
+        condition.setInvoiceId(invoiceId);
+        Condition beeCondition = new ConditionImpl();
+        beeCondition.orderBy("id", OrderType.DESC);
+        beeCondition.start((inDto.getPageNo() - 1) * inDto.getPageSize()).size(inDto.getPageSize());
+        List<SimpleOrderDTO> orders = suidRich.select(condition, beeCondition);
+        return OutDTO.ok().put("invoiceOrders",orders);
+    }
+
+    /**
+     * 获取开票商家
+     */
+    @ApiLog(title = "获取开票商家v2",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("获取开票商家,参数:无")
+    @ApiVersion(1.0)
+    @ResponseBody
+    @RequestMapping(value = "/invoice/merchant", method = RequestMethod.POST)
+    public OutDTO getInvoiceMerchantV2(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        List<InvoiceMerchantDTO> list = orderInfoService.getInvoiceMerchant(user.getId(),null,!checkUserInvoiceOpen(user.getId()));
+        return OutDTO.ok().put("merchants",list);
+    }
+
+    /**
+     * 获取开票商家
+     */
+    @ApiLog(title = "获取开票商家v3",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("获取开票商家,参数:无")
+    @ApiVersion(3.3)
+    @ResponseBody
+    @RequestMapping(value = "/invoice/merchant", method = RequestMethod.POST)
+    public OutDTO getInvoiceMerchantV3(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        String orderType = inDto.getString("orderType");
+        if(Strings.isEmpty(orderType)){ // 默认拼团订单
+            orderType = "group";
+        }
+        List<InvoiceMerchantDTO> list = orderInfoService.getInvoiceMerchantV3(user.getId(),null,!checkUserInvoiceOpen(user.getId()), orderType);
+        return OutDTO.ok().put("merchants",list);
+    }
+    @ApiLog(title = "获取开票商家v4",businessType = BusinessType.SEARCH,indto = "{{invoiceMerchantQuery}}")
+    @ApiOperation("获取开票商家,参数:用户id")
+    @ApiVersion(4.5)
+    @ResponseBody
+    @RequestMapping(value = "/invoice/merchant", method = RequestMethod.POST)
+    public OutDTO getInvoiceMerchantV4(@RequestBody InDto inDto){
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        String orderType = inDto.getString("orderType");
+        if(Strings.isEmpty(orderType)){ // 默认拼团订单
+            orderType="group";
+        }
+        InvoiceMerchantQuery invoiceMerchantQuery = new InvoiceMerchantQuery();
+        invoiceMerchantQuery.setOrderType(orderType);
+        invoiceMerchantQuery.setLimitTime(!checkUserInvoiceOpen(user.getId()));
+        invoiceMerchantQuery.setMerchantName(inDto.getString("merchantName"));
+        invoiceMerchantQuery.setPageNo(inDto.getPageNo());
+        invoiceMerchantQuery.setPageSize(inDto.getPageSize());
+        invoiceMerchantQuery.setUserId(user.getId());
+        PageInfo<InvoiceMerchantDTO> invoiceMerchantV4 = orderInfoService.getInvoiceMerchantV4(invoiceMerchantQuery);
+        return OutDTO.ok().buildPage(inDto,Math.toIntExact(invoiceMerchantV4.getTotal()),"merchants",invoiceMerchantV4.getList());
+    }
+    private boolean checkUserInvoiceOpen(Integer userId) {
+        return orderInfoService.checkUserInvoiceOpen(userId);
+    }
+
+    /**
+     * 获取商家用户拉黑情况
+     */
+    @ApiLog(title = "获取商家用户拉黑情况",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("获取商家用户拉黑情况")
+    @ResponseBody
+    @RequestMapping(value = "/getUserBackStatus", method = RequestMethod.POST)
+    public OutDTO getUserBackStatus(@RequestBody InDto inDto) {
+        Integer merchantAppUserId = inDto.getIntegerParam("merchantAppUserId");
+        if (inDto.get("userId") == null || merchantAppUserId == null) {
+            return OutDTO.error500("参数为空");
+        }
+        MerchantInfo merchantInfo = merchantApiService.getMerchantByAppUserId(merchantAppUserId);
+        if (merchantInfo == null) {
+            return OutDTO.error500("商家不存在");
+        }
+        AppMerchantFans condition = new AppMerchantFans();
+        condition.setUserId(Long.valueOf(inDto.getString("userId")));
+        condition.setMerchantId(merchantInfo.getId().longValue());
+        List<AppMerchantFans> fansList = suidRich.select(condition, "type");
+        String status = "non";
+        if (!fansList.isEmpty()) {
+            List<String> types = fansList.stream().map(f -> f.getType()).collect(Collectors.toList());
+            if (types.contains(Constants.FANS_TYPE_USER_DISLIKE)) {
+                status = Constants.FANS_TYPE_USER_DISLIKE;
+            } else if (types.contains(Constants.FANS_TYPE_MERCHANT_DISLIKE)) {
+                status = Constants.FANS_TYPE_MERCHANT_DISLIKE;
+            }
+        }
+        return OutDTO.ok().put("status", status);
+    }
+
+    @ApiLog(title = "新版个人中卡查询",businessType = BusinessType.UPDATE,indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/card/new")
+    public OutDTO selectWinCardNew(@RequestBody InDto inDto){
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        GoodsQuery condition = new GoodsQuery().setUserId(user.getId()).setKeyword(inDto.getString("keyword"))
+                .setRefType(inDto.getString("refType")).setPageNo(inDto.getPageNo()).setPageSize(inDto.getPageSize());
+        Object del = inDto.get("delFlag");
+        int delFlag=del==null?0:(Integer)del;
+        condition.setDelFlag(delFlag);
+        String sport = inDto.getString("sport");
+        if(StringUtils.isNotEmpty(sport)){
+            condition.setSportList(groupApiService.getSportList(sport));
+        }
+
+        PageInfo<AppUserWinCard> cards = appUserWinCardService.selectWinCard(condition);
+        List<CardCountDTO> count = appUserWinCardService.selectWinCardCount(condition.getUserId(),delFlag);
+        return OutDTO.ok().put("cards", cards)
+                .put("countMap", count.stream().collect(Collectors.toMap(CardCountDTO::getSport, CardCountDTO::getCount)))
+                .put("totalCount", count.stream().mapToLong(CardCountDTO::getCount).sum());
+    }
+
+    @ApiLog(title = "修改中卡仓库状态",businessType = BusinessType.UPDATE,indto = "{{inDto}}")
+    @ResponseBody
+    @RequestMapping(value = "/card/edit/status", method = RequestMethod.POST)
+    public OutDTO updateWinCardStatus(@RequestBody InDto inDto){
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        Integer status = (Integer) inDto.get("status");
+        AppUserWinCard card = new AppUserWinCard();
+        card.setUserId(user.getId());
+        card.setId(Long.valueOf(inDto.getString("id")));
+        card.setDelFlag(status);
+        if(1==status){
+            card.setDelTime(new Date());
+        }
+        suidRich.update(card);
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "我的优惠券", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @PostMapping("/coupon")
+    public OutDTO findMineCoupon(@RequestBody InDto inDto){
+        if (null == inDto) return OutDTO.error(10000, "参数不能为空");
+        OutDTO checkUser = mineApiService.checkUser(inDto);
+        if (!checkUser.isSuccess()) return checkUser;
+        MineCardDTO mineCardDTO = mineApiService.findMineCard(inDto);
+        List<CouponInfo> couponInfoList = mineCardDTO.getCouponInfos();
+        PageInfo<CouponInfo> pageInfo = new PageInfo<>(couponInfoList);
+        return OutDTO.ok().put("couponInfos", pageInfo)
+                .put("merchantTotal", mineCardDTO.getMerchantTotal())
+                .put("platformTotal", mineCardDTO.getPlatformTotal());
+    }
+
+    @ApiVersion(3.6)
+    @ApiLog(title = "我的优惠券", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @PostMapping("/coupon")
+    public OutDTO findMineCouponV2(@RequestBody InDto inDto){
+        if (null == inDto) return OutDTO.error(10000, "参数不能为空");
+
+        AppUserInfoDto appUserInfoDto;
+        try {
+            appUserInfoDto = mineApiService.checkUserNew(inDto);
+        } catch (Exception e) {
+            return OutDTO.error500(e.getMessage());
+        }
+
+        MineCardDTO mineCardDTO = mineApiService.findMineCardV2(inDto, appUserInfoDto);
+        List<CouponInfo> couponInfoList = mineCardDTO.getCouponInfos();
+        PageInfo<CouponInfo> pageInfo = new PageInfo<>(couponInfoList);
+        return OutDTO.ok().put("couponInfos", pageInfo)
+                .put("merchantTotal", mineCardDTO.getMerchantTotal())
+                .put("platformTotal", mineCardDTO.getPlatformTotal());
+    }
+
+    @ApiLog(title = "预售订单主动退款", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @PostMapping("/order/refund")
+    public OutDTO refundPreSaleOrder(@RequestBody InDto inDto) {
+        if (null == inDto) {
+            return OutDTO.error500("参数不能为空!");
+        }
+        Integer orderId = (Integer) inDto.get("orderId");
+        if (orderId == null) {
+            return OutDTO.error500("orderId不能为空!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        cardGroupOrderInfoService.refundPreSaleOrder(user.getId(), orderId.longValue());
+        return OutDTO.ok();
+    }
+
+
+    @ApiLog(title = "首页消息提醒(5合1版)", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @PostMapping("/msg/recommend")
+    public OutDTO getUserMsgRecommend(@RequestBody InDto inDto) throws Exception {
+        Integer userId = inDto.getUserId();
+        Future<List<LockCardOrderCunt>> unlockGoodsFuture= pools.submit(() ->  mineApiService.selectLockCardOrderCount(userId));
+        Future<List<RefundReqDTO>> refundFuture= pools.submit(() ->  cardGroupOrderInfoService.getUserRefundReq(userId));
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        OutDTO outDTO = OutDTO.ok()
+                //.put("refuseCount", refuseWaitShipping(user))
+                .put("refuseCount", 0)
+                //.put("merchantInfo", waitShippingCount(user))
+                .put("merchantInfo",new ArrayList<>())
+                .put("receiveCount", getUserReceiveCount(user.getId()))
+                .put("unReadeCount", getUserMsgUnReadeCount(user.getId()))
+                //.put("waitApplyOrderFlag", hasWaitApplyCardOrder(user.getId()));
+                .put("waitApplyOrderFlag", false);
+        return outDTO.put("unlockGoods", unlockGoodsFuture.get()).put("refundReqs", refundFuture.get());
+    }
+
+    @ApiLog(title = "订单页消息提醒", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @PostMapping("/order/recommend")
+    public OutDTO getOrderMsgRecommend(@RequestBody InDto inDto) throws Exception {
+        if (inDto.getUserId() == null) {
+            return OutDTO.error500(MsgConstants.NEED_LOGIN);
+        }
+        return OutDTO.ok().put("giftMsg", groupActService.getGiftMsg(inDto.getUserId()));
+    }
+
+    public int getUserMsgUnReadeCount(Integer userId) {
+        //未读消息
+        TzySysNoticeRecord noticeRecord = new TzySysNoticeRecord();
+        noticeRecord.setToUserid(userId.longValue());
+        return noticeRecordService.selectUnreaderTotal(noticeRecord);
+    }
+
+    private int getUserReceiveCount(Integer userId) {
+        //有无赠送卡密
+        String sql = QuerySql.getQuerySql("com.tzy.sportcard.api.domain.MineCount.getReceiveOrderCount");
+        String roCount = preparedSql.selectFun(sql, new Object[]{userId});
+        return Integer.parseInt(roCount);
+    }
+
+    @ApiLog(title = "用户配置", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @PostMapping("/config")
+    public OutDTO getUserConfig(@RequestBody InDto inDto) {
+        if(inDto.getUserId()==null){
+            return OutDTO.error500("参数缺失!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        UserConfigDTO config= mineApiService.getUserConfig(inDto.getUserId());
+        if (StringUtils.isNotEmpty(config.getEffectsType()) && config.getEffectsType().contains(Constants.LIVE_EFFECTS)
+                && !memberBenefitsService.checkUseHasBenefitsByType(user.getMemberLevel(), Constants.LIVE_EFFECTS)) {
+            config.setEffectsType(config.getEffectsType().replace(Constants.LIVE_EFFECTS, ""));
+        }
+        SimpleBenefitsDTO result = memberBenefitsService.querySimpleBenefits(inDto.getUserId());
+        return OutDTO.ok().put("userConfig",config).put("result", result);
+    }
+
+
+    /**
+     * @return
+     */
+    @ApiLog(title = "修改个人信息V2", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/edit/user")
+    public OutDTO editUserV2(@RequestBody InDto inDto) throws Exception {
+        AppUserInfoDto existUser = mineApiService.checkUserNew(inDto);
+        AppUserParam param = inDto.buildParam(new AppUserParam());
+        // 去空格
+        if (StringUtils.isNotEmpty(param.getNickname())){
+            param.setNickname(param.getNickname().replaceAll("\\s+", ""));
+            if(!QiniuUtil.checkText(param.getNickname())) {
+                return OutDTO.error500("存在不合规的文字!");
+            }
+        }
+        com.tzy.app.domain.AppBaseUser user = new com.tzy.app.domain.AppBaseUser();
+        BeanUtils.copyBeanNonProp(param,user);
+        user.setId(inDto.getUserId().longValue());
+        if (user.getEffectsType() != null) {
+            String effectsTypeStr = user.getEffectsType();
+            if (effectsTypeStr.contains(Constants.LIVE_EFFECTS)) {
+                if (!memberBenefitsService.checkUseHasBenefitsByType(existUser.getMemberLevel(), Constants.LIVE_EFFECTS)) {
+                    return OutDTO.error500("该会员等级不支持直播间特效");
+                }
+            }
+        }
+        if (existUser.getBlacklist() != 1) {
+            if (!StringUtils.isEmpty(user.getNickname())) {
+                List<SysDictData> data = commonCacheService.getCommonDictData(Constants.APP_NAME_BACK_LIST_CACHE, null, "1", Constants.APP_NAME_BACK_LIST_CACHE, 600);
+                if (!CollectionUtils.isEmpty(data)) {
+                    Set<String> backNames = data.stream().map(SysDictData::getDictValue).collect(Collectors.toSet());
+                    if (backNames.contains(user.getNickname())) {
+                        return OutDTO.error500("昵称不可用!");
+                    }
+                }
+                // 用户昵称不能与商家名称相同
+                boolean available = tzyMerchantInfoService.checkNickname(user.getNickname());
+                if(!available){
+                    return OutDTO.error500("昵称不能与商家同名!");
+                }
+            }
+        }
+        String key = LocalDate.now() + "_" + inDto.getUserId();
+        if (StringUtils.isNotEmpty(user.getPayAmountOfDay())) {
+            redisUtils.hdel(Constants.USER_PAY_REMIND, key);
+        }
+        if (StringUtils.isNotEmpty(user.getOpenPayAmount())) {
+            redisUtils.hdel(Constants.USER_PAY_REMIND, key);
+        }
+        appBaseUserService.updateAppBaseUser(user);
+        redisUtils.del("app_cache_user_cfg:"+inDto.getUserId());
+        return OutDTO.ok().put("userConfig",mineApiService.getUserConfig(inDto.getUserId()));
+    }
+
+    /**
+     * 用户实名认证
+     * @return
+     */
+    @ApiLog(title = "修改个人信息V2", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/user/verify")
+    @ApiLimitRule(seconds = 2, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public OutDTO userFaceVerifyV2(@RequestBody InDto inDto) throws Exception {
+        AppUserInfoDto existUser = mineApiService.checkUserNew(inDto);
+        Integer userId =  inDto.getIntegerParam("userId");
+        Integer faceVerify =  inDto.getIntegerParam("faceVerify");
+        if (userId != null && userId != existUser.getId().intValue()) {
+            return OutDTO.error500("参数错误!");
+        }
+        if (faceVerify == null) {
+            return OutDTO.error500("参数缺失!");
+        }
+        if (StringUtils.isEmpty(existUser.getUserCertData())) {
+            return OutDTO.error500("实名异常,请重试!");
+        }
+        com.tzy.app.domain.AppBaseUser user = new com.tzy.app.domain.AppBaseUser();
+        user.setId(inDto.getUserId().longValue());
+        String userCertData = AESUtil.decryptData(existUser.getUserCertData(), Constants.AES_USER_PASSWORD);
+        JSONObject jsonObject = JSON.parseObject(userCertData);
+        String certNo = jsonObject.getString("certNo");
+        String certName = jsonObject.getString("certName");
+        String signStr = certName.trim() + certNo.trim();
+        if (userId != null) {
+            signStr += userId.toString().trim();
+        }
+        String sign = AESUtil.encryptData(signStr, Constants.AES_TOKEN_PASSWORD);
+        if (!sign.equalsIgnoreCase(inDto.getSign())) {
+            return OutDTO.error500("参数错误!");
+        }
+        //限制次数
+        String signNo = DigestUtils.md5DigestAsHex(certNo.getBytes());
+        int existNoNum = mineApiService.getExistUserNum(signNo);
+        if (existNoNum > idCardMaxNum) {
+            return OutDTO.error500("您绑定的账号已超过上限!");
+        }
+
+        jsonObject.put("status", "1");
+        user.setUserCertData(AESUtil.encryptData(JSON.toJSONString(jsonObject), Constants.AES_USER_PASSWORD));
+        user.setFaceVerify(1);
+        int i = appBaseUserService.updateAppBaseUser(user);
+        if(i>0){
+            JSONObject appBaseUser = new JSONObject();
+            appBaseUser.put("id", user.getId());
+            // MD5身份证号加密
+            appBaseUser.put("idCard", user.getIdCard());
+            appBaseUser.put("userCertData", user.getUserCertData());
+            //如果更新成功则进行发送mq 同步数据
+            log.info("用户实名认证成功 ,发送mq->QUEUE_USER_REALNESS_PASS,用户ID:{}",inDto.getUserId());
+            rabbitTemplate.convertAndSend(MqConstans.QUEUE_USER_REALNESS_PASS, com.alibaba.fastjson2.JSON.toJSONString(appBaseUser));
+        }
+        redisUtils.del("app_cache_user_cfg:"+inDto.getUserId());
+        return OutDTO.ok().put("userConfig", mineApiService.getUserConfig(inDto.getUserId()));
+    }
+
+    /**
+     * 可进行实名认证类型
+     * @return
+     */
+    @ApiLog(title = "可进行实名认证类型", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/canVerifyType")
+    public OutDTO canVerifyType(@RequestBody InDto inDto) {
+        //根据token获取用户信息
+        AppUserInfoDto existUser = mineApiService.checkUserNew(inDto);
+        return mineApiService.checkUserVerifyType(existUser);
+    }
+
+    /**
+     * 已经实名认证类型
+     * @return
+     */
+    @ApiLog(title = "已经实名认证类型", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/hasVerifyType")
+    public OutDTO hasVerifyType(@RequestBody InDto inDto) {
+        //根据token获取用户信息
+        AppUserInfoDto existUser = mineApiService.checkUserNew(inDto);
+        return mineApiService.userHasVerifyType(existUser);
+    }
+
+    @ApiLog(title = "获取用户关注情况",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("获取用户关注情况")
+    @ResponseBody
+    @PostMapping(value = "/follow/type")
+    public OutDTO getUserFollowByType(@RequestBody InDto inDto) {
+        Integer userId = inDto.getIntegerParam("userId");
+        Integer followId = inDto.getIntegerParam("followId");
+        String followType = inDto.getString("followType");
+        if (userId == null || followId == null || StringUtils.isEmpty(followType)) {
+            return OutDTO.error500("参数为空");
+        }
+        AppMerchantFans condition = new AppMerchantFans();
+        condition.setUserId(userId.longValue());
+        condition.setCollectionTypeId(followId.longValue());
+        condition.setType(followType);
+        List<AppMerchantFans> fansList = suidRich.select(condition,"type");
+        int followCount=mineApiService.getFollowCountByType(followType,followId);
+        return OutDTO.ok().put("hasFollow",!fansList.isEmpty()).put("followCount",followCount);
+    }
+
+    @ApiLog(title = "编辑用户关注情况",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("编辑用户关注情况")
+    @ResponseBody
+    @PostMapping(value = "/edit/follow/type")
+    public OutDTO editUserFollowByType(@RequestBody InDto inDto) {
+        Integer userId = inDto.getIntegerParam("userId");
+        Integer followId = inDto.getIntegerParam("followId");
+        String followType = inDto.getString("followType");
+        if (userId == null || followId == null || StringUtils.isEmpty(followType)) {
+            return OutDTO.error500("参数为空");
+        }
+        Integer dirType = inDto.getIntegerParam("dirType");
+        AppMerchantFans condition = new AppMerchantFans();
+        condition.setUserId(userId.longValue());
+        condition.setCollectionTypeId(followId.longValue());
+        condition.setType(followType);
+        if(dirType==null||dirType==1){
+            List<AppMerchantFans> fansList = suidRich.select(condition, "id");
+            if(!CollectionUtils.isEmpty(fansList)){
+                return OutDTO.error500("您已关注,请勿重复点击");
+            }
+            condition.setCreateTime(DateUtils.getTimestampNow());
+            suidRich.insert(condition);
+        }else {
+            suidRich.delete(condition);
+        }
+        int followCount=mineApiService.getFollowCountByType(followType,followId);
+        editRefNum(followType, followId, followCount);
+        return OutDTO.ok().put("followCount",followCount);
+    }
+
+    private void editRefNum(String followType, Integer followId, int followCount) {
+        if (Constants.FOLLOW_TOP_CARD_LIKE.equals(followType)) {
+            MerchantActGoods merchantActGoods = new MerchantActGoods();
+            merchantActGoods.setId(followId.longValue());
+            merchantActGoods.setLikeNum(followCount);
+            suidRich.update(merchantActGoods);
+        }
+    }
+
+
+    /**
+     * 查询订单精美卡片数量
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "查询订单精美卡片数量v3", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @ApiVersion(value = 2.0)
+    @ApiOperation("查询订单精美卡片数量v3")
+    @PostMapping(value = "/gift/card")
+    public OutDTO getUserGiftCard(@RequestBody InDto inDto) {
+        List<SimpleUserMerchant> merchants = orderInfoService.getUserGiftCard(inDto.getUserId(),inDto.getPageSize(),inDto.getOffset());
+        return OutDTO.ok().put("merchants",merchants);
+    }
+
+
+    /**
+     * 生成精美卡片运费订单v2
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "生成精美卡片运费订单v3", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @ApiVersion(value = 2.3)
+    @ApiOperation("生成精美卡片运费订单v3,参数:merchantId,addressId")
+    @PostMapping(value = "/gift/card/prepay")
+    @ApiLimitRule(seconds = 1,limitCount=1,type= LimitRule.USER,msg="操作频繁,请稍后再试!")
+    public OutDTO shippingPrePayV3(@RequestBody InDto inDto) {
+        Integer merchantId = inDto.getIntegerParam("merchantId");
+        Integer addressId = inDto.getIntegerParam("addressId");
+        Integer cardId = inDto.getIntegerParam("cardId");
+        Integer shippingNum = inDto.getIntegerParam("shippingNum");
+        if (merchantId == null || addressId == null || cardId == null || shippingNum == null || shippingNum < 1) {
+            return OutDTO.error500("参数为空!");
+        }
+        List<GiftCardManage> giftCards = merchantApiService.selectGiftCard(merchantId, cardId);
+        if (CollectionUtils.isEmpty(giftCards)) {
+            return OutDTO.error500("精美卡片类型不存在!");
+        }
+        GiftCardManage giftCard=giftCards.get(0);
+        if (shippingNum > giftCard.getMaxCardNum()) {
+            return OutDTO.error500("数据提交异常!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        BigDecimal totalCost = BigDecimal.ZERO;
+        if (shippingNum < giftCard.getMinCardNum()) {
+            totalCost = getShippingCost(shippingNum, cardId,merchantId);
+        }
+        AppUserPoint shipRecord = new AppUserPoint().setUserId(user.getId()).setType(Constants.POINT_TYPE_GIFT_CARD_PRE + cardId)
+                .setMerchantId(merchantId).setRefId(cardId);
+        return orderInfoService.shippingPayV3(shipRecord, totalCost, shippingNum, inDto.getString("payType"), addressId);
+    }
+
+
+    /**
+     * 精美卡片初始化
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "精美卡片初始化", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @ApiVersion(value = 2.0)
+    @ApiOperation("精美卡片初始化")
+    @PostMapping(value = "/gift/card/init")
+    public OutDTO initUserGiftCard(@RequestBody InDto inDto) {
+        List<SysDictData> dictData = dictDataService.selectDictDataByCache(Constants.GROUP_GIFT_CARD, null, "1", true);
+        if (CollectionUtils.isEmpty(dictData)) {
+            return OutDTO.ok();
+        }
+        AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+        // 初始化会员等级
+        memberBenefitsService.initMemberBeneifts(appUserInfoDto.getMemberLevel(), appUserInfoDto.getId().longValue());
+        String key = "init_card_key" + inDto.getUserId();
+        boolean hasKey = redisUtils.hasKey(key);
+        if (!hasKey && !redisUtils.hHasKey("init_user_gift_card", inDto.getUserId().toString())) {
+            Map<String, String> param = ImmutableMap.of("userId", inDto.getUserId().toString());
+            rabbitTemplate.convertAndSend(MqConstans.QUEUE_INIT_USER_GIFT_CARD, JSON.toJSONString(param));
+        }
+        if (!hasKey) {
+            redisUtils.set(key, 1, 600);
+        }
+        return OutDTO.ok();
+    }
+
+    /**
+     * 用户个人中心数量显示
+     */
+    @Deprecated
+    @ApiLog(title = "用户个人中心数量显示",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/center/num")
+    @ApiVersion(2.0)
+    public OutDTO getUserCenterNum() {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if (user == null) {
+            return OutDTO.error500("请先登录!");
+        }
+        MineCount mineCount = mineApiService.selectUserCenterCount(user.getId(), null);
+        return OutDTO.ok().put("mineCount", mineCount);
+    }
+
+    /**
+     * 用户个人中心数量显示
+     */
+    @ApiLog(title = "用户个人中心数量显示",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/center/num")
+    @ApiVersion(3.8)
+    public OutDTO getUserCenterNumV2() {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if (user == null) {
+            return OutDTO.error500("请先登录!");
+        }
+        InDto inDto = new InDto();
+        inDto.setUserId(user.getId());
+        AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+        MineCount mineCount = mineApiService.selectUserCenterCount(user.getId(), appUserInfoDto);
+        int followMerchantsCount=merchantApiService.getFollowMerchants(user.getId());
+        int mineGoodsFavoriteCount=mineApiService.getGoodsFavoriteCount(user.getId());
+        return OutDTO.ok().put("mineCount", mineCount).put("followMerchantsCount",followMerchantsCount).put("mineFavoriteGoodsCount",mineGoodsFavoriteCount);
+    }
+
+    /**
+     * 商家个人中心数量显示
+     */
+    @ApiLog(title = "商家个人中心数量显示",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @ApiVersion(2.0)
+    @PostMapping(value = "/merchant/center/num")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_DELIVERY, UserType.USER_ROLE_PUBLICITY, UserType.USER_ROLE_LIVING})
+    public OutDTO getMerchantCenterNum() {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        if (user == null || user.getMerchantId() == null) {
+            return OutDTO.error500("权限不足!");
+        }
+        MerchantGoods merchantCount=mineApiService.selectMerchantCenterCountV2(user.getMerchantId());
+        MerchantInfo merchantInfo = merchantApiService.getMerchantInfo(user.getMerchantId());
+        SimpleUser merchantAppUser = mineApiService.selectAppUserByMerchantId(user.getMerchantId());
+        return OutDTO.ok().put("merchantCount",merchantCount).put("merchantInfo",merchantInfo).put("merchantAppUser",merchantAppUser);
+    }
+
+    /**
+     * 用户申请自提
+     */
+    @ApiLog(title = "用户申请自提",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/apply/pickup/code")
+    @ApiVersion(2.0)
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public OutDTO applyPickUpCode(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if (user == null) {
+            return OutDTO.error500("请先登录!");
+        }
+        Integer merchantId = inDto.getIntegerParam("merchantId");
+        if (merchantId == null) {
+            return OutDTO.error500("参数缺失!");
+        }
+        String code =RandomUtil.random(8);
+        int count=merchantApiService.applySelfPickUpCode(user.getId(),merchantId,code);
+        return OutDTO.ok().put("count", count).put("code", code);
+    }
+
+    /**
+     * 商家核销用户码
+     */
+    @ApiLog(title = "商家核销用户码",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/verify/pickup/code")
+    @ApiVersion(2.0)
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_DELIVERY})
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public OutDTO verifyPickUpCode(@RequestBody InDto inDto) throws ParseException {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if (user == null||user.getMerchantId()==null) {
+            return OutDTO.error500("权限不足!");
+        }
+        String code = inDto.getString("code");
+        if(StringUtils.isEmpty(code)){
+            return OutDTO.error500("自提码为空!");
+        }
+        Integer merchantId = user.getMerchantId();
+        CardGroupOrderInfo condition = new CardGroupOrderInfo();
+        condition.setMerchantId(merchantId.longValue());
+        condition.setStatus(103L);
+        condition.setSelfPickupCode(code);
+        List<CardGroupOrderInfo> orders = suidRich.select(condition);
+        if (CollectionUtils.isEmpty(orders)) {
+            return OutDTO.error500("自提码无效!");
+        }
+        if (new Date().getTime() - orders.get(0).getSelfPickupTime().getTime() > DateUtils.day2second * 1000) {
+            return OutDTO.error500("自提码已过期!");
+        }
+        int count = merchantApiService.verifyPickUpCode(merchantId, code);
+        if (count == 0) {
+            return OutDTO.error500("自提码无效!");
+        }
+        Set<Long> mallOrderIds = orders.stream().filter(o -> Constants.ORDER_TYPE_SHOP.equals(o.getOrderType())).map(CardGroupOrderInfo::getId).collect(Collectors.toSet());
+        if(!CollectionUtils.isEmpty(mallOrderIds)){
+            Date afterNumWorkDay = DateUtils.getNumWorkDayByNow(new Date(), 5);
+            com.tzy.sportcard.group.domain.CardGroupOrderInfo updateOrder = new com.tzy.sportcard.group.domain.CardGroupOrderInfo();
+            updateOrder.setClosePaymentStatus(100);
+            updateOrder.setClosePaymentTime(afterNumWorkDay);
+            orderInfoService.updateOrderByIds(updateOrder, mallOrderIds);
+        }
+        orders.stream().filter(o -> Constants.ORDER_TYPE_SHOP.equals(o.getOrderType()) && o.getGiveOrderId() == null)
+                .forEach(order -> asyncAppService.addPointByMallOrder(orderInfoService.selectCardGroupOrderInfoById(order.getId())));
+        // 商城订单完结
+        /*orders.stream().filter(o -> Constants.ORDER_TYPE_SHOP.equals(o.getOrderType()) && o.getGiveOrderId() == null)
+                .forEach(order -> {
+                    Map<String, Object> param = ImmutableMap.of("type", Constants.TYPE_SHOP_POINT, "orderId", order.getId());
+                    MqUtils.sendMq(MqConstans.QUEUE_ORDER_OVER, JSONTools.obj2json(param));
+                });*/
+        return OutDTO.ok().put("count", count);
+    }
+
+    /**
+     * 用户申请积分退款
+     */
+    @ApiLog(title = "用户申请积分退款",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/point/refund")
+    @ApiVersion(2.0)
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public OutDTO pointRefund(@RequestBody InDto inDto){
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if (user == null) {
+            return OutDTO.error500("请先登录!");
+        }
+        PointRefundRecord param = inDto.buildParam(new PointRefundRecord());
+        if (param.getMerchantId() == null || StringUtils.isEmpty(param.getPointType())) {
+            return OutDTO.error500("参数为空!");
+        }
+        param.setUserId(user.getId());
+        mineApiService.pointRefund(param);
+        return OutDTO.ok();
+    }
+
+    /**
+     * 用户申请积分退款前置校验
+     */
+    @ApiLog(title = "用户申请积分退款前置校验",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/point/refund/check")
+    @ApiVersion(2.0)
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public OutDTO checkPointRefund(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if (user == null) {
+            return OutDTO.error500("请先登录!");
+        }
+        Integer merchantId = inDto.getIntegerParam("merchantId");
+        if(merchantId==null){
+            return OutDTO.error500("商家id为空!");
+        }
+        RefundCheckDTO checkDTO=mineApiService.checkPointRefund(user.getId(),merchantId);
+        return OutDTO.ok().put("checkResult",checkDTO);
+    }
+
+    /**
+     * 用户审批商家退款申请
+     */
+    @ApiLog(title = "用户审批商家退款申请",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/check/refund/req")
+    @ApiVersion(2.0)
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public OutDTO checkRefundReq(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        if (user == null) {
+            return OutDTO.error500("请先登录!");
+        }
+        Integer groupInfoId = inDto.getIntegerParam("groupInfoId");
+        if (groupInfoId == null) {
+            return OutDTO.error500("groupInfoId为空!");
+        }
+        boolean checkFlag = inDto.getBooleanParam("checkFlag");
+        int serverStatus = checkFlag ? 20 : 10;
+        int count = orderInfoService.checkRefundReq(user.getId(), groupInfoId, serverStatus);
+        if (count==0){
+            //防止用户从多个入口发起多次请求
+            return OutDTO.ok("您已处理过退款审批了");
+        }
+        groupReviewService.editRefRefundReqReview(groupInfoId, serverStatus, user.getId());
+        //发送im修改小卡片状态
+
+        noticeService.sendRefundChange(Long.valueOf(user.getId()), Long.valueOf(groupInfoId),checkFlag?1:2);
+        return OutDTO.ok();
+    }
+    @PostMapping("/queryRefundStatus")
+    @ResponseBody
+    @ApiVersion(1.0)
+    @ApiOperation(value = "用户审批退款状态查询",notes = "")
+    public AjaxResult queryRefundStatus(@RequestBody List<Long> idList){
+        log.info("用户退款审批状态查询参数:{}",idList);
+        List<OrderChangeRecord> orderChangeRecord = orderChangeRecordService.getOrderChangeRecord(idList);
+        List<HashMap<String,Object>> result=new ArrayList<>();
+        for (OrderChangeRecord changeRecord : orderChangeRecord) {
+            HashMap<String, Object> item = new HashMap<>();
+            item.put("id",changeRecord.getId());
+            String refundStatus="";
+            int status=changeRecord.getStatus();
+            if (status==0){
+                refundStatus="pending";
+            }else if (status==1){
+                refundStatus="agree";
+            }else if (status==2){
+                refundStatus="refuse";
+            }else if (status==3){
+                refundStatus="pass";
+            }
+            item.put("refundStatus",refundStatus);
+            result.add(item);
+        }
+        return AjaxResult.success(result);
+    }
+    @ApiLog(title = "用户拼豆订单",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/cost/card/merchant")
+    @ApiVersion(1.0)
+    @ApiLimitRule(seconds = 1, limitCount = 2, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public OutDTO userCostCardMerchant(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(user, MsgConstants.NEED_LOGIN);
+        boolean payed = inDto.getBooleanParam("payed");
+        List<SimpleMerchantInfo> merchants = orderInfoService.getUserCostCardMerchant(user.getId(), payed);
+        return OutDTO.ok().put("merchants", merchants);
+    }
+
+    @ApiLog(title = "用户拼豆订单",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/cost/card/order")
+    @ApiVersion(1.0)
+    @ApiLimitRule(seconds = 1, limitCount = 2, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public OutDTO userCostCardOrders(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(user, MsgConstants.NEED_LOGIN);
+        OrderQuery orderQuery = inDto.buildParam(new OrderQuery());
+        orderQuery.setUserId(user.getId()).setPageNo(inDto.getPageNo()).setPageSize(inDto.getPageSize());
+        PageInfo<CostOrderDTO> pageOrder = orderInfoService.userCostCardOrders(orderQuery);
+        return OutDTO.ok().put("pageOrder", pageOrder);
+    }
+
+    @ApiLog(title = "拼豆订单运费下单",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/apply/card/cost")
+    @ApiVersion(1.0)
+    @ApiLimitRule(seconds = 5, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public OutDTO userCardShippingCost(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(user, MsgConstants.NEED_LOGIN);
+        String ids = inDto.getString("ids");
+        if (StringUtils.isEmpty(ids)) {
+            return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+        }
+        Integer merchantId = inDto.getIntegerParam("merchantId");
+        if (merchantId == null) {
+            return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+        }
+        String payType = inDto.getString("payType");
+        if (StringUtils.isEmpty(payType)) {
+            return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+        }
+        List<Long> idList = Arrays.stream(ids.split(",")).map(Long::valueOf).collect(Collectors.toList());
+        if (idList.size() > 100) {
+            return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+        }
+        orderInfoService.checkOrderInfoStatus(idList);
+        int totalNum = orderInfoService.getCardNum(user.getId(), idList);
+        MerchantInfo merchant = merchantApiService.getMerchantInfo(merchantId);
+        BigDecimal shippingCost;
+        if (StringUtils.isNotEmpty(merchant.getShippingCostConfig())) {
+            MerchantCostConfig costConfig = JSONTools.jsonStr2obj(merchant.getShippingCostConfig(), MerchantCostConfig.class);
+            if (totalNum > costConfig.getMaxNum() || totalNum < costConfig.getMinNum()) {
+                return OutDTO.error500(MsgConstants.MERCHANT_COND_MET);
+            }
+            shippingCost = MerchantCostConfig.buildMerchantShippingCost(costConfig, totalNum);
+        } else {
+            shippingCost = getShippingCost(totalNum, 1, merchantId);
+        }
+        Integer addressId = inDto.getIntegerParam("addressId");
+        if (addressId != null) {
+            TzyShippingAddress address = addressService.selectUserAddress(user.getId(), addressId);
+            if (address == null) {
+                return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+            }
+            com.tzy.sportcard.group.domain.CardGroupOrderInfo editOrder = new com.tzy.sportcard.group.domain.CardGroupOrderInfo();
+            editOrder.setShippingAddressId(address.getId());
+            editOrder.setShippingAddressLinkname(address.getLinkname());
+            editOrder.setShippingAddress(address.getAddress() + address.getAddressMore());
+            editOrder.setShippingAddressPhone(address.getPhone());
+            orderInfoService.updateOrderByIds(editOrder, new HashSet<>(idList));
+        }
+        ShippingPayParam payParam = new ShippingPayParam().setCardType(ShippingPayParam.CARD_TYPE_POINT).setUserId(user.getId()).setOrderIds(idList)
+                .setTotalCost(shippingCost).setShippingNum(totalNum).setPayType(payType);
+        ShippingPayResult payResult = orderInfoService.cardShippingPayNew(payParam);
+        return OutDTO.ok().put("payResult", payResult);
+    }
+
+    @ApiLog(title = "拼豆订单运费下单",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/v2/apply/card/cost")
+    @ApiVersion(1.0)
+    @ApiLimitRule(seconds = 5, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public OutDTO userCardShippingCostV2(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(user, MsgConstants.NEED_LOGIN);
+        String ids = inDto.getString("ids");
+        if (StringUtils.isEmpty(ids)) {
+            return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+        }
+        Integer merchantId = inDto.getIntegerParam("merchantId");
+        if (merchantId == null) {
+            return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+        }
+        String payType = inDto.getString("payType");
+        if (StringUtils.isEmpty(payType)) {
+            return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+        }
+        List<Long> idList = Arrays.stream(ids.split(",")).map(Long::valueOf).collect(Collectors.toList());
+        if (idList.size() > 100) {
+            return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+        }
+        orderInfoService.checkOrderInfoStatus(idList);
+        int totalNum = orderInfoService.getCardNum(user.getId(), idList);
+        MerchantInfo merchant = merchantApiService.getMerchantInfo(merchantId);
+        BigDecimal shippingCost;
+        if (StringUtils.isNotEmpty(merchant.getShippingCostConfig())) {
+            MerchantCostConfig costConfig = JSONTools.jsonStr2obj(merchant.getShippingCostConfig(), MerchantCostConfig.class);
+            if (totalNum > costConfig.getMaxNum() || totalNum < costConfig.getMinNum()) {
+                return OutDTO.error500(MsgConstants.MERCHANT_COND_MET);
+            }
+            shippingCost = MerchantCostConfig.buildMerchantShippingCost(costConfig, totalNum);
+        } else {
+            shippingCost = getShippingCost(totalNum, 1, merchantId);
+        }
+        Integer addressId = inDto.getIntegerParam("addressId");
+        if (addressId != null) {
+            TzyShippingAddress address = addressService.selectUserAddress(user.getId(), addressId);
+            if (address == null) {
+                return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+            }
+            com.tzy.sportcard.group.domain.CardGroupOrderInfo editOrder = new com.tzy.sportcard.group.domain.CardGroupOrderInfo();
+            editOrder.setShippingAddressId(address.getId());
+            editOrder.setShippingAddressLinkname(address.getLinkname());
+            editOrder.setShippingAddress(address.getAddress() + address.getAddressMore());
+            editOrder.setShippingAddressPhone(address.getPhone());
+            orderInfoService.updateOrderByIds(editOrder, new HashSet<>(idList));
+        }
+        ShippingPayParam payParam = new ShippingPayParam().setCardType(ShippingPayParam.CARD_TYPE_POINT).setUserId(user.getId()).setOrderIds(idList)
+                                                          .setTotalCost(shippingCost).setShippingNum(totalNum).setPayType(payType);
+
+        ShippingPayResult payResult = orderInfoService.cardShippingPayV2(payParam);
+        return OutDTO.ok().put("payResult", payResult);
+    }
+    @ApiLog(title = "提醒-用户点击我的页面",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/recommend")
+    @ApiVersion(1.0)
+    @ApiLimitRule(seconds = 1, limitCount = 2, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public OutDTO getUserCenterRecommend(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(user, MsgConstants.NEED_LOGIN);
+        OutDTO dto = OutDTO.ok();
+        if (user.getMerchantId() != null) {
+            dto.put("sendCard", orderInfoService.selectMerchantNoticePointOrder(user.getMerchantId()));
+        }
+        String curDayKey = Constants.REFUSE_CARD_NOTICE + DateUtils.getDate() + user.getId();
+        boolean isApplyShipment = false;
+        if (!redisUtils.hasKey(curDayKey)) {
+            redisUtils.set(curDayKey, "1", Constants.dayForSecond);
+            boolean isRefuseNotice = redisUtils.hasKey(Constants.REFUSE_CARD_NOTICE + user.getId());
+            isApplyShipment = !isRefuseNotice && orderInfoService.selectUserNoticePointOrder(user.getId());
+
+        }
+        dto.put("applyShipment", isApplyShipment);
+        return dto;
+    }
+
+    @ApiLog(title = "提醒-用户点击我的页面",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/refuse/notice")
+    @ApiVersion(1.0)
+    @ApiLimitRule(seconds = 1, limitCount = 2, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public OutDTO refuseCardNotice(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(user, MsgConstants.NEED_LOGIN);
+        String type = inDto.getString("type");
+        if (StringUtils.isEmpty(type)) {
+            redisUtils.set(Constants.REFUSE_CARD_NOTICE + user.getId(), "1", Constants.dayForSecond * 30);
+        }
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "更新个人资料",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/edit/detail")
+    public OutDTO editUserDetail(@RequestBody AppUserDetailInfo appUserDetailInfo) {
+        if(appUserDetailInfo == null){
+            return OutDTO.error500("参数为空");
+        }
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(user, MsgConstants.NEED_LOGIN);
+        appUserDetailInfo.setUserId(user.getId().longValue());
+        int rs = appUserDetailInfoService.update(appUserDetailInfo);
+        if(rs == 0){
+            return OutDTO.error500("更新失败");
+        }
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "更新个人资料",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/user/detail")
+    public OutDTO getUserDetail() {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(user, MsgConstants.NEED_LOGIN);
+        AppUserDetailInfo appUserDetailInfo = appUserDetailInfoService.getByUserId(user.getId());
+        return OutDTO.ok().put("user", appUserDetailInfo);
+    }
+
+    @ApiLog(title = "用户填写邀请码",businessType = BusinessType.UPDATE,indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/user/invited")
+    @ApiLimitRule(seconds = 1, limitCount = 2, type = LimitRule.COMMON, msg = "操作频繁,请稍后再试!")
+    public OutDTO fillUserInviteCode(@RequestBody AppUserDetailInfo appUserDetailInfo) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(user, MsgConstants.NEED_LOGIN);
+        // 检查appUserDetailInfo.getInviteCode() 不能为空 且长度为6位
+        if(StringUtils.isEmpty(appUserDetailInfo.getInviteCode())){
+            return OutDTO.error500("邀请码不能为空");
+        }
+
+        if(appUserDetailInfo.getInviteCode().length() != 6){
+            return OutDTO.error500("邀请码长度必须为6位");
+        }
+        String inviteCode = appUserDetailInfo.getInviteCode();
+        AppUserDetailInfo parentUser = appUserDetailInfoService.getByUserInviteCode(appUserDetailInfo.getInviteCode());
+        if(parentUser == null){
+            return OutDTO.error500("无效的邀请码");
+        }
+        appUserDetailInfo = appUserDetailInfoService.updateInviteCode(user,appUserDetailInfo);
+        List<CouponInfo> coupons = appUserDetailInfoService.sendInviteCodeComplete(appUserDetailInfo,inviteCode,parentUser);
+
+        return OutDTO.ok().put("user", appUserDetailInfo).put("parentUser",parentUser).put("coupons", coupons);
+    }
+}

+ 55 - 0
poyi-app/src/main/java/com/tzy/controller/appuser/AppUserShareController.java

@@ -0,0 +1,55 @@
+package com.tzy.controller.appuser;
+
+import com.alibaba.fastjson2.JSON;
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.common.dto.InDto;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.sportcard.api.service.IAppShareConfigService;
+import com.tzy.sportcard.group.domain.AppShareConfig;
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import static cn.com.sand.hmpay.util.JacksonUtil.jsonToBean;
+
+@Api(value = "app用户分享相关")
+@RestController
+@RequestMapping("/api/{version}/share")
+@Slf4j
+public class AppUserShareController {
+    @Autowired
+    private IAppShareConfigService appShareConfigService;
+
+    @ResponseBody
+    @RequestMapping(value = "/info", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    public OutDTO waitShippingCount(@RequestBody InDto inDto) {
+        Long refId = inDto.getIntegerParam("refId").longValue();
+        String typeStr = inDto.getString("type");
+        AppShareConfig config = appShareConfigService.selectAppShareConfigById(refId,typeStr);
+        return OutDTO.ok().put("AppShareConfig", config);
+    }
+
+    @ResponseBody
+    @RequestMapping(value = "/update", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    public OutDTO refuseByMerchant(@RequestBody InDto inDto) {
+        String appShareConfigStr = inDto.getString("AppShareConfig");
+        AppShareConfig config = new  AppShareConfig();
+        config.setId(inDto.getIntegerParam("id")==null?0:inDto.getIntegerParam("id").longValue());
+        config.setRefId(inDto.getIntegerParam("refId").longValue());
+        config.setType(inDto.getString("type"));
+        config.setConfig(inDto.getString("config"));
+        AppShareConfig configval = appShareConfigService.selectAppShareConfigById(config.getRefId(),config.getType());
+        if(configval==null){
+            config.setId(null);
+            appShareConfigService.insertAppUserWinCard(config);
+        }
+        else{
+            appShareConfigService.updateAppUserWinCard(config);
+        }
+        return OutDTO.ok();
+    }
+
+}

+ 60 - 0
poyi-app/src/main/java/com/tzy/controller/appuser/QuestionnaireController.java

@@ -0,0 +1,60 @@
+package com.tzy.controller.appuser;
+
+import com.tzy.annotation.ApiLimitRule;
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.common.constant.MsgConstants;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.dto.UserInfo;
+import com.tzy.common.exception.AppAssert;
+import com.tzy.common.utils.UserUtils;
+import com.tzy.dto.QuestionParam;
+import com.tzy.framework.web.domain.LimitRule;
+import com.tzy.pojo.question.Questionnaire;
+import com.tzy.service.question.QuestionnaireService;
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+
+@Api(value = "问卷")
+@RestController
+@RequestMapping("/api/{version}/questionnaire")
+@Slf4j
+public class QuestionnaireController {
+
+    @Resource
+    private QuestionnaireService questionnaireService;
+
+    private static final String QUESTIONNAIRE_SUCCESS_MSG =  "【感谢您的参与!您的消费额度已提升】";
+    private static final String QUESTIONNAIRE_FAIL_MSG =   "【您的消费额度提升失败!如有问题请联系平台客服】";
+
+    /**
+     * 查询问卷
+     */
+    @ApiVersion(1.0)
+    @PostMapping(value = "/{id}")
+    @ResponseBody
+    public OutDTO getQuestionnaireDetail(@PathVariable("id") Long id){
+        Questionnaire questionnaire = questionnaireService.getQuestionnaireDetail(id);
+        return OutDTO.ok().put("questionnaire", questionnaire);
+    }
+
+    /**
+     * 查询问卷
+     */
+    @ApiVersion(1.0)
+    @ApiLimitRule(seconds = 2,limitCount=1,type= LimitRule.USER,msg="操作频繁,请稍后再试!")
+    @PostMapping(value = "/submit")
+    @ResponseBody
+    public OutDTO submitQuestionnaire(@RequestBody QuestionParam questionParam) {
+        AppAssert.notNull(questionParam, MsgConstants.PARAM_EMPTY);
+        AppAssert.notNull(questionParam.getQuestionnaireId(), MsgConstants.PARAM_EMPTY);
+        AppAssert.notEmpty(questionParam.getQuestionAnswers(), MsgConstants.PARAM_EMPTY);
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(user, MsgConstants.NEED_LOGIN);
+        questionParam.setUserId(user.getId());
+        boolean result = questionnaireService.submitQuestionnaire(questionParam);
+        return OutDTO.ok(result ? QUESTIONNAIRE_SUCCESS_MSG : QUESTIONNAIRE_FAIL_MSG).put("result", result);
+    }
+}

+ 145 - 0
poyi-app/src/main/java/com/tzy/controller/appuser/QuizActivityController.java

@@ -0,0 +1,145 @@
+package com.tzy.controller.appuser;
+
+import com.tzy.annotation.ApiLimitRule;
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.common.core.domain.AjaxResult;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.dto.UserInfo;
+import com.tzy.common.utils.UserUtils;
+import com.tzy.dto.QuizActivityDto;
+import com.tzy.dto.QuizActivityParam;
+import com.tzy.dto.QuizLibDto;
+import com.tzy.framework.web.domain.LimitRule;
+import com.tzy.pojo.quiz.QuizAnswer;
+import com.tzy.service.QuizActivityService;
+import com.tzy.service.QuizAnswerService;
+import com.tzy.service.QuizLibService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 答题活动
+ */
+
+@Api(tags = "答题活动")
+@RestController
+@RequestMapping("/api/{version}/quiz")
+public class QuizActivityController {
+
+    @Autowired
+    QuizLibService quizLibService;
+    @Autowired
+    QuizActivityService quizActivityService;
+    @Autowired
+    QuizAnswerService quizAnswerService;
+    /**
+     * 根据活动id查询题目,且当前时间在活动时间范围内,
+     * 判断用户是否已在该轮次答题,已答题,直接返回,未答题,随机生成题目
+     */
+    @PostMapping("/quizLib/{id}")
+    @ApiVersion(1.0)
+    @ApiOperation("查询答题活动详情及题目列表")
+    public AjaxResult getQuizLibList(@PathVariable("id") Long activityId){
+        QuizActivityDto quizActivityDto = quizActivityService.getById(activityId);
+        //判断当前活动状态及时间范围
+        if (quizActivityDto.getStatus()==0){
+            return AjaxResult.error("当前活动未开启");
+        }
+        Date now = new Date();
+        Date startTime = quizActivityDto.getStartTime();
+        if (now.before(startTime)||now.after(quizActivityDto.getEndTime())){
+            return AjaxResult.error("当前时间不在活动时间范围内");
+        }
+        //计算当前答题轮次
+        long round = quizActivityService.calculateRound(quizActivityDto);
+        //查询用户答题轮次是否大于等于当前轮次
+        UserInfo simpleUserInfo = UserUtils.getSimpleUserInfo();
+        if (simpleUserInfo==null){
+            return AjaxResult.error("请先登录");
+        }
+        Integer id = simpleUserInfo.getId();
+        int count = quizAnswerService.countRoundByUser(id, round,activityId);
+        if (count>0){
+            return AjaxResult.error("您已参与本轮答题活动");
+        }
+        //查询活动题库
+        List<QuizLibDto> quizLibDtoList = quizLibService.queryQuizLibByActivityId(activityId);
+        //非必答题集合
+        List<QuizLibDto> optionQuizLib = quizLibDtoList.stream().filter(quizLibDto -> quizLibDto.getRequired() == 0).collect(Collectors.toList());
+        //必答题集合
+        List<QuizLibDto> mustAnswerQuizLib = quizLibDtoList.stream().filter(quizLibDto -> quizLibDto.getRequired() == 1).collect(Collectors.toList());
+        //假如有必答题
+
+        int randomNum = quizActivityDto.getQuestionNum() - mustAnswerQuizLib.size();
+        if (randomNum > 0) {
+            //需要随机生成剩余题目,题目不能重复
+            Random random = new Random();
+            random.ints(0, optionQuizLib.size()).distinct().limit(randomNum).forEach((i) -> {
+                QuizLibDto quizLibDto = optionQuizLib.get(i);
+                //加入题目集合
+                mustAnswerQuizLib.add(quizLibDto);
+            });
+        }
+
+
+        quizActivityDto.setQuizLibDtoList(mustAnswerQuizLib);
+        return AjaxResult.success(quizActivityDto);
+    }
+
+    /**
+     * 用户答题接口
+     * @return
+     */
+    @PostMapping("/answer")
+    @ApiVersion(1.0)
+    @ApiLimitRule(seconds = 2,limitCount=1,type= LimitRule.USER,msg="操作频繁,请稍后再试!")
+    @ApiOperation("用户提交答题接口")
+    public OutDTO answer(@RequestBody QuizActivityParam quizActivityParam){
+        //计算当前答题轮次,并判断用户当前答题轮次是否大于等于当前轮次
+        QuizActivityDto quizActivityDto = quizActivityService.getById(quizActivityParam.getActivityId());
+        //判断当前活动状态及时间范围
+        if (quizActivityDto.getStatus()==0){
+            return OutDTO.error500("当前活动未开启");
+        }
+        Date now = new Date();
+        Date startTime = quizActivityDto.getStartTime();
+        if (now.before(startTime)||now.after(quizActivityDto.getEndTime())){
+            return OutDTO.error500("当前时间不在活动时间范围内");
+        }
+        //计算当前答题轮次
+        long round = quizActivityService.calculateRound(quizActivityDto);
+        UserInfo simpleUserInfo = UserUtils.getSimpleUserInfo();
+        if (simpleUserInfo==null){
+            return OutDTO.error500("请先登录");
+        }
+        Integer userInfoId = simpleUserInfo.getId();
+        int count = quizAnswerService.countRoundByUser(userInfoId, round,quizActivityParam.getActivityId());
+        if (count>0){
+            return OutDTO.error500("您已参与本轮答题活动");
+        }
+        //插入用户答题表
+        List<QuizAnswer> quizAnswers = quizActivityParam.getQuizAnswers();
+        quizAnswers.forEach(quizAnswer -> {
+            quizAnswer.setRound(round);
+            quizAnswer.setActivityId(quizActivityParam.getActivityId());
+            quizAnswer.setUserId(userInfoId);
+        });
+        boolean batchSaveAnswer = quizAnswerService.batchSaveAnswer(quizAnswers);
+        if (!batchSaveAnswer){
+            return OutDTO.error500("答题失败,请联系系统管理员");
+        }
+        long errorAnswerCount = quizAnswers.stream().filter(quizAnswer -> quizAnswer.getType()==0).count();
+        HashMap<String, Object> resultMap = new HashMap<>();
+        resultMap.put("allRight",errorAnswerCount==0);
+        return OutDTO.ok(resultMap);
+    }
+
+
+
+}

+ 62 - 0
poyi-app/src/main/java/com/tzy/controller/appuser/RecommendController.java

@@ -0,0 +1,62 @@
+package com.tzy.controller.appuser;
+
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.common.constant.MsgConstants;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.dto.UserInfo;
+import com.tzy.common.exception.AppAssert;
+import com.tzy.common.utils.UserUtils;
+import com.tzy.dto.UserPayNoticeDTO;
+import com.tzy.sportcard.group.service.ICardGroupOrderInfoService;
+import com.tzy.sportcard.message.service.IAppMsgRecordService;
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+@Api(value = "用户提示")
+@RestController
+@RequestMapping("/api/{version}/recommend")
+@Slf4j
+public class RecommendController {
+
+    @Resource
+    private ICardGroupOrderInfoService orderService;
+    @Resource
+    private IAppMsgRecordService msgRecordService;
+
+    /**
+     * 下单前消费金额提示
+     */
+    @ApiVersion(1.0)
+    @PostMapping(value = "/order")
+    @ResponseBody
+    public OutDTO preOrderRecommend() {
+        UserInfo userInfo = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(userInfo, MsgConstants.NEED_LOGIN);
+        UserPayNoticeDTO notice = orderService.preOrderRecommendAmount(userInfo.getId());
+        if(notice.isNoticeFlag()){
+            msgRecordService.addRecord(userInfo.getId(),notice);
+        }
+        return OutDTO.ok().put("notice", notice);
+    }
+
+    /**
+     * 下单前消费金额提示
+     */
+    @ApiVersion(2.0)
+    @PostMapping(value = "/order")
+    public OutDTO preOrderRecommend2() {
+        UserInfo userInfo = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(userInfo, MsgConstants.NEED_LOGIN);
+        UserPayNoticeDTO notice = orderService.preOrderRecommendAmount2(userInfo.getId());
+        if(notice.isNoticeFlag()){
+            msgRecordService.addRecord(userInfo.getId(),notice);
+        }
+        return OutDTO.ok().put("notice", notice);
+    }
+}

+ 112 - 0
poyi-app/src/main/java/com/tzy/controller/business/AppUserBusinessSettledController.java

@@ -0,0 +1,112 @@
+package com.tzy.controller.business;
+
+import java.lang.reflect.InvocationTargetException;
+import java.math.BigDecimal;
+import java.util.List;
+
+import com.tzy.annotation.ApiLog;
+import com.tzy.business.domain.AppUserBusinessSettled;
+import com.tzy.business.service.IAppUserBusinessSettledService;
+import com.tzy.common.dto.InDto;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.utils.DateUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.beanutils.BeanUtils;
+import org.apache.commons.beanutils.ConvertUtils;
+import org.apache.commons.beanutils.converters.BigDecimalConverter;
+import org.apache.commons.beanutils.converters.DateConverter;
+import org.springframework.cglib.beans.BeanMap;
+import org.springframework.web.bind.annotation.*;
+import com.tzy.common.enums.BusinessType;
+import com.tzy.common.core.controller.BaseController;
+import com.tzy.common.core.page.TableDataInfo;
+
+import javax.annotation.Resource;
+
+/**
+ * 商家入驻Controller
+ * 
+ * @author poyee
+ * @date 2023-03-09
+ */
+@Api("商家入驻")
+@Slf4j
+@RestController
+@RequestMapping("/api/settled")
+public class AppUserBusinessSettledController extends BaseController {
+
+    @Resource
+    private IAppUserBusinessSettledService appUserBusinessSettledService;
+
+
+    @ApiOperation("查询商家入驻列表")
+    @ApiLog(title = "查询商家入驻列表", businessType = BusinessType.SEARCH)
+    @PostMapping("/list")
+    public TableDataInfo list(AppUserBusinessSettled appUserBusinessSettled) {
+        startPage();
+        List<AppUserBusinessSettled> list = appUserBusinessSettledService.selectAppUserBusinessSettledList(appUserBusinessSettled);
+        return getDataTable(list);
+    }
+
+    @ApiOperation("新增商家入驻")
+    @ApiLog(title = "新增商家入驻", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    public OutDTO addSave(@RequestBody InDto inDto) {
+        AppUserBusinessSettled appUserBusinessSettled = new AppUserBusinessSettled();
+        try {
+            DateConverter dateConverter = new DateConverter(null);
+            String[] datepattern = {DateUtils.YYYY_MM_DD, DateUtils.YYYY_MM_DD_HH_MM_SS };
+            dateConverter.setPatterns(datepattern);
+            ConvertUtils.register(dateConverter, java.util.Date.class);
+            ConvertUtils.register(new BigDecimalConverter(0.0), BigDecimal.class);
+            BeanUtils.populate(appUserBusinessSettled, inDto.getData());
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+        }
+        appUserBusinessSettledService.insertAppUserBusinessSettled(appUserBusinessSettled);
+        return OutDTO.ok();
+    }
+
+    @ApiOperation("查询商家入驻详情")
+    @ApiLog(title = "查询商家入驻详情", businessType = BusinessType.SEARCH)
+    @PostMapping("/findById")
+    public OutDTO findById(@RequestBody InDto inDto) {
+        List<AppUserBusinessSettled> list = appUserBusinessSettledService.selectAppUserBusinessSettledById(inDto.getUserId());
+        return OutDTO.ok().put("info", list);
+    }
+
+    @ApiOperation("修改商家入驻")
+    @ApiLog(title = "修改商家入驻", businessType = BusinessType.UPDATE)
+    @PostMapping("/edit")
+    public OutDTO editSave(@RequestBody InDto inDto) {
+        AppUserBusinessSettled appUserBusinessSettled = new AppUserBusinessSettled();
+        try {
+            DateConverter dateConverter = new DateConverter(null);
+            String[] datepattern = {DateUtils.YYYY_MM_DD, DateUtils.YYYY_MM_DD_HH_MM_SS };
+            dateConverter.setPatterns(datepattern);
+            ConvertUtils.register(dateConverter, java.util.Date.class);
+            ConvertUtils.register(new BigDecimalConverter(0.0), BigDecimal.class);
+            BeanUtils.populate(appUserBusinessSettled, inDto.getData());
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+        }
+        appUserBusinessSettledService.updateAppUserBusinessSettled(appUserBusinessSettled);
+        return OutDTO.ok();
+    }
+
+    @ApiOperation("删除商家入驻")
+    @ApiLog(title = "删除商家入驻", businessType = BusinessType.DELETE)
+    @PostMapping("/remove")
+    public OutDTO delete(@RequestBody InDto inDto) {
+        String idStr = inDto.getData().get("id").toString();
+        appUserBusinessSettledService.deleteAppUserBusinessSettledById(Long.valueOf(idStr));
+        return OutDTO.ok();
+    }
+
+}

+ 424 - 0
poyi-app/src/main/java/com/tzy/controller/grade/GradeOrderController.java

@@ -0,0 +1,424 @@
+package com.tzy.controller.grade;
+
+import com.tzy.annotation.ApiLimitRule;
+import com.tzy.annotation.ApiLog;
+import com.tzy.annotation.RequireRoles;
+import com.tzy.app.dto.grade.GradeOrderDTO;
+import com.tzy.app.dto.grade.GradeOrderParam;
+import com.tzy.app.dto.user.UserConfigDTO;
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.common.dto.InDto;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.dto.UserInfo;
+import com.tzy.common.enums.BusinessType;
+import com.tzy.common.utils.UserType;
+import com.tzy.common.utils.UserUtils;
+import com.tzy.express.ExpressUtils;
+import com.tzy.framework.web.domain.LimitRule;
+import com.tzy.sportcard.api.bean.grade.GradeTypeManage;
+import com.tzy.sportcard.api.domain.AppUserInfoDto;
+import com.tzy.sportcard.api.service.MineApiService;
+import com.tzy.sportcard.grade.dto.GradeAuthTypeDTO;
+import com.tzy.sportcard.grade.dto.GradeChangeRecordDTO;
+import com.tzy.sportcard.grade.dto.GradeQuery;
+import com.tzy.sportcard.grade.dto.GradeSuppleDTO;
+import com.tzy.sportcard.grade.service.IGradeOrderService;
+import io.swagger.annotations.ApiOperation;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Controller;
+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.ResponseBody;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 【评级相关】Controller
+ *
+ * @date 2023-11-30
+ */
+@Controller
+@RequestMapping("/api/{version}/grade")
+public class GradeOrderController {
+
+	@Resource
+	private IGradeOrderService gradeOrderService;
+	@Resource
+	private MineApiService mineApiService;
+
+	@ApiLog(title = "评级认证类型", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+	@ResponseBody
+	@PostMapping(value = "/auth/type")
+	@ApiVersion(2.0)
+	public OutDTO getGradeAuthType(@RequestBody InDto inDto) {
+		String type = inDto.getString("type");
+		List<GradeTypeManage> types = gradeOrderService.getGradeAuthType(type);
+		return OutDTO.ok().put("types", types);
+	}
+
+	@ApiLog(title = "查询评级订单", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+	@ResponseBody
+	@PostMapping(value = "/list")
+	@ApiVersion(2.0)
+	public OutDTO getGradeOrderList(@RequestBody InDto inDto) {
+		GradeQuery gradeQuery = inDto.buildParam(new GradeQuery());
+		UserInfo userInfo = UserUtils.getSimpleUserInfo();
+		Integer userId = userInfo != null && UserType.USER_ROLE_ADMIN.equals(userInfo.getRoleCode()) ? null : inDto.getUserId();
+		gradeQuery.setUserId(userId).setPageNo(inDto.getPageNo()).setRows(inDto.getPageSize());
+		if (StringUtils.isNumeric(gradeQuery.getKeyword())) {
+			gradeQuery.setOrderNo(gradeQuery.getKeyword()).setKeyword(null);
+		}
+		List<GradeOrderDTO> orders = gradeOrderService.getGradeOrderList(gradeQuery);
+		return OutDTO.ok().put("orders", orders);
+	}
+
+	@ApiLog(title = "提交", businessType = BusinessType.INSERT, indto = "{{inDto}}")
+	@ResponseBody
+	@PostMapping(value = "/submit")
+	@ApiVersion(2.0)
+	@ApiLimitRule(seconds = 2, limitCount = 10, msg = "操作频繁,请稍后再试!")
+	public OutDTO submitGradeOrder(@RequestBody InDto inDto) {
+		mineApiService.checkUserNew(inDto);
+		GradeOrderParam gradeParam = inDto.buildParam(new GradeOrderParam());
+		gradeParam.setUserId(inDto.getUserId().longValue());
+		List<Long> orderIds = gradeOrderService.submitGradeOrder(gradeParam);
+		return OutDTO.ok().put("orderIds", orderIds);
+	}
+
+	@ApiLog(title = "明细", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+	@ApiOperation("评级订单明细,参数:id")
+	@ResponseBody
+	@PostMapping(value = "/detail")
+	@ApiVersion(2.0)
+	public OutDTO getGradeOrderDetail(@RequestBody InDto inDto) {
+		mineApiService.checkUserNew(inDto);
+		Integer id = inDto.getIntegerParam("id");
+		Integer payStatus = inDto.getIntegerParam("payStatus");
+		UserInfo userInfo = UserUtils.getSimpleUserInfo();
+		Integer userId = userInfo != null && UserType.USER_ROLE_ADMIN.equals(userInfo.getRoleCode()) ? null : inDto.getUserId();
+		GradeOrderDTO gradeOrder = gradeOrderService.getGradeOrderDetail(id, userId);
+		GradeAuthTypeDTO authType = gradeOrderService.selectAuthTypeById(gradeOrder.getAuthTypeId());
+		gradeOrder.setAuthName(authType.getName()).setAuthParentName(authType.getParentName());
+		UserConfigDTO user=mineApiService.getUserConfig(gradeOrder.getUserId().intValue());
+		if(user != null){
+			gradeOrder.setNickname(user.getNickname()).setAvatar(user.getAvatar());
+		}else {
+			gradeOrder.setNickname("已注销");
+		}
+		List<GradeChangeRecordDTO> recordList = gradeOrderService.getGradeChangeRecord(id, payStatus);
+		gradeOrder.setRecords(recordList);
+		return OutDTO.ok().put("gradeOrder", gradeOrder);
+	}
+
+	@ApiLog(title = "预支付", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+	@ApiOperation("预支付,参数:id,payType")
+	@ResponseBody
+	@PostMapping(value = "/prepay")
+	@ApiVersion(2.0)
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+	public OutDTO gradeOrderPrepay(@RequestBody InDto inDto) {
+		AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+		Integer id = inDto.getIntegerParam("id");
+		String payType = inDto.getString("payType");
+		if (StringUtils.isEmpty(payType)) {
+			return OutDTO.error500("请选择支付方式!");
+		}
+		return gradeOrderService.gradeOrderPrepay(id, payType, user);
+	}
+
+	@ApiLog(title = "查询已支付的明细和总金额", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+	@ApiOperation("查询已支付的明细和总金额,参数id")
+	@ResponseBody
+	@PostMapping(value = "/payed/record")
+	@ApiVersion(2.0)
+	public OutDTO getGradePayedRecord(@RequestBody InDto inDto) {
+		Integer id = inDto.getIntegerParam("id");
+		UserInfo userInfo = UserUtils.getSimpleUserInfo();
+		Integer userId = userInfo != null && UserType.USER_ROLE_ADMIN.equals(userInfo.getRoleCode()) ? null : inDto.getUserId();
+		GradeOrderDTO order = gradeOrderService.getGradeOrderDetail(id, userId);
+		if (order == null) {
+			return OutDTO.error500("权限不足!");
+		}
+		List<GradeChangeRecordDTO> recordList = gradeOrderService.getGradeChangeRecord(id, 101);
+		BigDecimal totalPayAmount = BigDecimal.ZERO;
+		if (!CollectionUtils.isEmpty(recordList)) {
+			totalPayAmount = recordList.stream().map(GradeChangeRecordDTO::getActualPayment).reduce(BigDecimal::add).get();
+		}
+		return OutDTO.ok().put("totalPayAmount", totalPayAmount).put("payedRecords", recordList);
+	}
+
+	@ApiLog(title = "用户添加寄送物流信息", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+	@ApiOperation("用户添加寄送物流信息")
+	@ResponseBody
+	@PostMapping(value = "/user/add/shipping")
+	@ApiVersion(2.0)
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+	public OutDTO addGradeShipping(@RequestBody InDto inDto) {
+		mineApiService.checkUserNew(inDto);
+		Integer id = inDto.getIntegerParam("id");
+		String courierNum = inDto.getString("courierNum");
+		String courierCompany = inDto.getString("courierCompany");
+		String courierImg = inDto.getString("courierImg");
+		String receiveAddress = inDto.getString("receiveAddress");
+		if (StringUtils.isEmpty(courierNum) || StringUtils.isEmpty(courierCompany) || StringUtils.isEmpty(courierImg) || StringUtils.isEmpty(receiveAddress)) {
+			return OutDTO.error500("物流信息缺失!");
+		}
+		if (!ExpressUtils.checkExpressCode(courierNum)) {
+			return OutDTO.error(10059, "快递单号不符合规范[" + courierNum + "]");
+		}
+		gradeOrderService.addGradeShipping(inDto.getUserId(), id, courierNum, courierCompany, courierImg, receiveAddress);
+		return OutDTO.ok();
+	}
+
+
+	@ApiLog(title = "评级服务方签收", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+	@ApiOperation("收到用户寄送")
+	@ResponseBody
+	@PostMapping(value = "/card/receive")
+	@ApiVersion(2.0)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN})
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+	public OutDTO receiveUserCard(@RequestBody InDto inDto) {
+		mineApiService.checkUserNew(inDto);
+		String courierNum = inDto.getString("courierNum");
+		String courierImg = inDto.getString("courierImg");
+		if (StringUtils.isEmpty(courierNum) || StringUtils.isEmpty(courierImg)) {
+			return OutDTO.error500("物流信息缺失!");
+		}
+		gradeOrderService.receiveUserCard(inDto.getUserId(), courierNum, courierImg);
+		return OutDTO.ok();
+	}
+
+
+	@ApiLog(title = "补充信息,仅admin权限", businessType = BusinessType.INSERT, indto = "{{inDto}}")
+	@ApiOperation("补充信息,仅admin权限")
+	@ResponseBody
+	@PostMapping(value = "/supple/info")
+	@ApiVersion(2.0)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN})
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+	public OutDTO suppleGradeInfo(@RequestBody InDto inDto) {
+		GradeSuppleDTO suppleInfo = inDto.buildParam(new GradeSuppleDTO());
+		gradeOrderService.suppleGradeInfo(inDto.getUserId(), suppleInfo);
+		return OutDTO.ok();
+	}
+
+
+	@ApiLog(title = "预评估", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+	@ApiOperation("预评估,补差价,id,preGradeReport,payAmount")
+	@ResponseBody
+	@PostMapping(value = "/pre/evaluation")
+	@ApiVersion(2.0)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN})
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+	public OutDTO preEvaluation(@RequestBody InDto inDto) {
+		mineApiService.checkUserNew(inDto);
+		Integer id = inDto.getIntegerParam("id");
+		String preGradeReport = inDto.getString("preGradeReport");
+		if (StringUtils.isEmpty(preGradeReport) || id == null) {
+			return OutDTO.error500("预评参数缺失!");
+		}
+		gradeOrderService.preEvaluation(inDto.getUserId(), id, preGradeReport);
+		return OutDTO.ok();
+	}
+
+
+	@ApiLog(title = "修改评级金额", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+	@ApiOperation("修改评级金额,id,payAmount,describe")
+	@ResponseBody
+	@PostMapping(value = "/edit/grade/price")
+	@ApiVersion(2.0)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN})
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+	public OutDTO editGradeAmount(@RequestBody InDto inDto) {
+		Integer id = inDto.getIntegerParam("id");
+		String payAmount = inDto.getString("payAmount");
+		String describe = inDto.getString("describe");
+		if (id == null || StringUtils.isEmpty(describe) || StringUtils.isEmpty(payAmount)) {
+			return OutDTO.error500("预评参数缺失!");
+		}
+		gradeOrderService.editGradeAmount(id, describe, new BigDecimal(payAmount));
+		return OutDTO.ok();
+	}
+
+
+	@ApiLog(title = "补差价", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+	@ApiOperation("补差价,id,payAmount,describe")
+	@ResponseBody
+	//@PostMapping(value = "/balance/price")
+	@ApiVersion(2.0)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN})
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+	public OutDTO editBalancePrice(@RequestBody InDto inDto) {
+		Integer id = inDto.getIntegerParam("id");
+		String payAmount = inDto.getString("payAmount");
+		String describe = inDto.getString("describe");
+		if (id == null || StringUtils.isEmpty(describe) || StringUtils.isEmpty(payAmount)) {
+			return OutDTO.error500("预评参数缺失!");
+		}
+		gradeOrderService.editBalancePrice(id, describe, payAmount);
+		return OutDTO.ok();
+	}
+
+
+	@ApiLog(title = "补差价", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+	@ApiOperation("补差价,id,payAmount,describe")
+	@ResponseBody
+	@PostMapping(value = "/cancel/unpayed")
+	@ApiVersion(2.0)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN})
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+	public OutDTO cancelUnPayedRecord(@RequestBody InDto inDto) {
+		Integer id = inDto.getIntegerParam("id");
+		gradeOrderService.cancelUnPayedRecord(id);
+		return OutDTO.ok();
+	}
+
+	@ApiLog(title = "确认送评", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+	@ApiOperation("确认送评")
+	@ResponseBody
+	@PostMapping(value = "/confirm/grade")
+	@ApiVersion(2.0)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN})
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+	public OutDTO confirmUserGrade(@RequestBody InDto inDto) {
+		Integer id = inDto.getIntegerParam("id");
+		gradeOrderService.confirmUserGrade(id, inDto.getUserId());
+		return OutDTO.ok();
+	}
+
+	@ApiLog(title = "上传评级报告", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+	@ApiOperation("上传评级报告")
+	@ResponseBody
+	@PostMapping(value = "/report/add")
+	@ApiVersion(2.0)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN})
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+	public OutDTO addGradeReport(@RequestBody InDto inDto) {
+		Integer id = inDto.getIntegerParam("id");
+		String gradeReport = inDto.getString("gradeReport");
+		String gradeProp = inDto.getString("gradeProp");
+		if (id == null || StringUtils.isEmpty(gradeReport)) {
+			return OutDTO.error500("预评参数缺失!");
+		}
+		gradeOrderService.addGradeReport(id, gradeReport, gradeProp);
+		return OutDTO.ok();
+	}
+
+
+	@ApiLog(title = "确认收到评级公司回寄", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+	@ApiOperation("确认收到评级公司回寄")
+	@ResponseBody
+	@PostMapping(value = "/confirm/back")
+	@ApiVersion(2.0)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN})
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+	public OutDTO confirmBack(@RequestBody InDto inDto) {
+		Integer id = inDto.getIntegerParam("id");
+		String courierNum = inDto.getString("courierNum");
+		String courierCompany = inDto.getString("courierCompany");
+		String courierImg = inDto.getString("courierImg");
+		if (id == null || StringUtils.isEmpty(courierNum) || StringUtils.isEmpty(courierCompany) || StringUtils.isEmpty(courierImg)) {
+			return OutDTO.error500("物流信息缺失!");
+		}
+		gradeOrderService.confirmBack(id, courierCompany, courierNum, courierImg);
+		return OutDTO.ok();
+	}
+
+
+	@ApiLog(title = "填写回寄用户物流", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+	@ApiOperation("填写回寄用户物流")
+	@ResponseBody
+	@PostMapping(value = "/send/back/user")
+	@ApiVersion(2.0)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN})
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+	public OutDTO sendUserBack(@RequestBody InDto inDto) {
+		Integer id = inDto.getIntegerParam("id");
+		String courierNum = inDto.getString("courierNum");
+		String courierCompany = inDto.getString("courierCompany");
+		String courierImg = inDto.getString("courierImg");
+		if (id == null || StringUtils.isEmpty(courierNum) || StringUtils.isEmpty(courierCompany) || StringUtils.isEmpty(courierImg)) {
+			return OutDTO.error500("物流信息缺失!");
+		}
+		gradeOrderService.sendUserBack(id, courierCompany, courierNum, courierImg);
+		return OutDTO.ok();
+	}
+
+	@ApiLog(title = "用户签收", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+	@ApiOperation("用户签收")
+	@ResponseBody
+	@PostMapping(value = "/user/sign/for")
+	@ApiVersion(2.0)
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+	public OutDTO userSignFor(@RequestBody InDto inDto) {
+		Integer id = inDto.getIntegerParam("id");
+		gradeOrderService.userSignFor(id, inDto.getUserId());
+		return OutDTO.ok();
+	}
+
+
+	@ApiLog(title = "取消", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+	@ApiOperation("取消")
+	@ResponseBody
+	@PostMapping(value = "/cancel")
+	@ApiVersion(2.0)
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+	public OutDTO cancelOrder(@RequestBody InDto inDto) {
+		Integer id = inDto.getIntegerParam("id");
+		UserInfo userInfo = UserUtils.getSimpleUserInfo();
+		Integer userId = userInfo != null && UserType.USER_ROLE_ADMIN.equals(userInfo.getRoleCode()) ? null : inDto.getUserId();
+		gradeOrderService.cancelOrder(userId, id);
+		return OutDTO.ok();
+	}
+
+	@ApiLog(title = "用户编辑收货地址", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+	@ApiOperation("用户编辑收货地址")
+	@ResponseBody
+	@PostMapping(value = "/edit/address")
+	@ApiVersion(2.0)
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+	public OutDTO editAddress(@RequestBody InDto inDto) {
+		Integer id = inDto.getIntegerParam("id");
+		Integer addressId = inDto.getIntegerParam("addressId");
+		gradeOrderService.editAddress(inDto.getUserId(), id, addressId);
+		return OutDTO.ok();
+	}
+
+	@ApiLog(title = "用户申请退款", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+	@ApiOperation("用户申请退款")
+	@ResponseBody
+	@PostMapping(value = "/apply/refund")
+	@ApiVersion(2.0)
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+	public OutDTO applyRefund(@RequestBody InDto inDto) {
+		Integer id = inDto.getIntegerParam("id");
+		gradeOrderService.applyRefund(inDto.getUserId(), id);
+		return OutDTO.ok();
+	}
+
+	@ApiLog(title = "填写回寄用户物流", businessType = BusinessType.UPDATE, indto = "{{inDto}}")
+	@ApiOperation("填写回寄用户物流")
+	@ResponseBody
+	@PostMapping(value = "/send/grade/shipping")
+	@ApiVersion(2.0)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN})
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+	public OutDTO addSendGradeShipping(@RequestBody InDto inDto) {
+		Integer id = inDto.getIntegerParam("id");
+		String courierNum = inDto.getString("courierNum");
+		String courierCompany = inDto.getString("courierCompany");
+		String courierImg = inDto.getString("courierImg");
+		if (id == null || StringUtils.isEmpty(courierNum) || StringUtils.isEmpty(courierCompany)) {
+			return OutDTO.error500("物流信息缺失!");
+		}
+		gradeOrderService.addSendGradeShipping(id, courierCompany, courierNum, courierImg);
+		return OutDTO.ok();
+	}
+
+
+}

+ 128 - 0
poyi-app/src/main/java/com/tzy/controller/group/GroupActController.java

@@ -0,0 +1,128 @@
+package com.tzy.controller.group;
+
+import com.tzy.annotation.ApiLimitRule;
+import com.tzy.annotation.ApiLog;
+import com.tzy.annotation.RequireRoles;
+import com.tzy.app.dto.user.PrizeQuery;
+import com.tzy.app.dto.user.SendPrizeParam;
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.common.constant.MsgConstants;
+import com.tzy.common.dto.InDto;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.dto.UserInfo;
+import com.tzy.common.enums.BusinessType;
+import com.tzy.common.utils.UserType;
+import com.tzy.common.utils.UserUtils;
+import com.tzy.framework.web.domain.LimitRule;
+import com.tzy.sportcard.api.domain.GroupInfo;
+import com.tzy.sportcard.api.service.GroupApiService;
+import com.tzy.sportcard.group.service.impl.GroupActService;
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+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.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author by po'yi
+ * @Classname GroupActController
+ * @Description
+ * @Date 2024/6/28 13:24
+ */
+@Api(value = "拼团活动接口")
+@RestController
+@RequestMapping("/api/{version}/group/act")
+@Slf4j
+public class GroupActController {
+	@Resource
+	private GroupActService groupActService;
+	@Resource
+	private GroupApiService groupService;
+
+	@ApiLog(title = "拼团商家赠礼活动", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+	@PostMapping(value = "/gifts")
+	@ApiVersion(2.0)
+	@ApiLimitRule(seconds = 1, limitCount = 2, type = LimitRule.USER)
+	//@RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_SHIPPING})
+	public OutDTO groupMerchantGifts(@RequestBody InDto inDto) {
+		Integer infoId = inDto.getIntegerParam("groupInfoId");
+		if (infoId == null) {
+			return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+		}
+		return OutDTO.ok().put("giftActData", groupActService.getMerchantActGift(infoId.longValue()));
+	}
+
+	@ApiLog(title = "拼团赠礼用户", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+	@PostMapping(value = "/gift/user")
+	@ApiVersion(2.0)
+	@ApiLimitRule(seconds = 1, limitCount = 2, type = LimitRule.USER)
+	@RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+	public OutDTO groupMerchantGiftUsers(@RequestBody InDto inDto) {
+		PrizeQuery query = inDto.buildParam(new PrizeQuery());
+		if (query.getRecordId() == null || query.getGroupInfoId() == null) {
+			return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+		}
+		return OutDTO.ok().put("sendGiftCount",groupActService.getGroupSendGiftCount(query))
+				.put("groupUsers",groupActService.getGroupMerchantGiftUsers(query));
+	}
+
+	@ApiLog(title = "商家赠礼", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+	@PostMapping(value = "/gift/send")
+	@ApiVersion(2.0)
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER)
+	@RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+	public OutDTO sendGroupMerchantGift(@RequestBody InDto inDto) {
+		UserInfo user = UserUtils.getSimpleUserInfo(true);
+		SendPrizeParam param = inDto.buildParam(new SendPrizeParam());
+		if (param.getRecordId() == null || param.getGroupInfoId() == null || StringUtils.isEmpty(param.getUserIds())) {
+			return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+		}
+		GroupInfo group = groupService.getGroupInfoById(param.getGroupInfoId());
+		if (group == null || group.getMerchantId() != user.getMerchantId().intValue()) {
+			return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+		}
+		groupActService.sendGroupMerchantGift(param);
+		return OutDTO.ok();
+	}
+
+	@ApiLog(title = "用户确认收货", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+	@PostMapping(value = "/gift/received")
+	@ApiVersion(2.0)
+	@ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER)
+	public OutDTO confirmReceived(@RequestBody InDto inDto) {
+		String ids = inDto.getString("ids");
+		Integer userId = inDto.getUserId();
+		if (StringUtils.isEmpty(ids) || userId == null) {
+			return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+		}
+		boolean received = inDto.getBooleanParam("received");
+		List<Long> idList = Arrays.stream(ids.split(",")).map(Long::parseLong).collect(Collectors.toList());
+		groupActService.confirmReceived(userId, idList,received);
+		return OutDTO.ok();
+	}
+
+	@ApiLog(title = "编辑商家赠礼活动信息", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+	@PostMapping(value = "/edit/name")
+	@ApiVersion(2.0)
+	@ApiLimitRule(seconds = 1, limitCount = 2, type = LimitRule.USER)
+	@RequireRoles(value = {UserType.USER_ROLE_ADMIN})
+	public OutDTO editActDesc(@RequestBody InDto inDto) {
+		Integer id = inDto.getIntegerParam("id");
+		String actName = inDto.getString("actName");
+		if (id == null || StringUtils.isEmpty(actName)) {
+			return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+		}
+		groupActService.editActDesc(id, actName);
+		return OutDTO.ok();
+	}
+
+
+
+}

+ 1482 - 0
poyi-app/src/main/java/com/tzy/controller/group/GroupControllerNew.java

@@ -0,0 +1,1482 @@
+package com.tzy.controller.group;
+
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.collect.ImmutableMap;
+import com.tzy.annotation.ApiLimitRule;
+import com.tzy.annotation.ApiLog;
+import com.tzy.annotation.RequireRoles;
+import com.tzy.app.domain.act.ActSaleCode;
+import com.tzy.app.domain.act.SaleCodeRecord;
+import com.tzy.app.dto.ExtraInfoDTO;
+import com.tzy.app.dto.InfoActConfig;
+import com.tzy.app.dto.MerchantSortDTO;
+import com.tzy.app.dto.group.BaseMerchantDTO;
+import com.tzy.app.dto.group.MerchantGroupDTO;
+import com.tzy.app.mapper.OrderListMapper;
+import com.tzy.common.config.QuerySql;
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.common.constant.ActConstans;
+import com.tzy.common.constant.Constants;
+import com.tzy.common.constant.MqConstans;
+import com.tzy.common.constant.MsgConstants;
+import com.tzy.common.core.domain.entity.SysDictData;
+import com.tzy.common.dto.*;
+import com.tzy.common.dto.act.CheckSaleCodeDTO;
+import com.tzy.common.dto.act.GroupSaleCodeDTO;
+import com.tzy.common.dto.group.GroupOrderUserDTO;
+import com.tzy.common.dto.group.GroupQuery;
+import com.tzy.common.dto.group.SimpleGroupGoodsDTO;
+import com.tzy.common.enums.BusinessType;
+import com.tzy.common.exception.AppAssert;
+import com.tzy.common.exception.ServiceException;
+import com.tzy.common.utils.DateUtils;
+import com.tzy.common.utils.StringUtils;
+import com.tzy.common.utils.UserType;
+import com.tzy.common.utils.UserUtils;
+import com.tzy.common.utils.bean.JSONTools;
+import com.tzy.framework.util.RedisTools;
+import com.tzy.framework.util.RedisUtils;
+import com.tzy.framework.web.domain.LimitRule;
+import com.tzy.ierp.domain.PyErpRandomCode;
+import com.tzy.ierp.dto.ChecklistConfigDto;
+import com.tzy.ierp.dto.PyErpRandomCodeReq;
+import com.tzy.ierp.dto.RandomCodeMerInReq;
+import com.tzy.ierp.enums.PyRandomCodeEnums;
+import com.tzy.ierp.service.PyErpRandomCodeService;
+import com.tzy.pojo.card.CardGroupGoods;
+import com.tzy.sportcard.api.domain.AppUserInfoDto;
+import com.tzy.sportcard.api.domain.GoodsInfo;
+import com.tzy.sportcard.api.domain.GroupInfo;
+import com.tzy.sportcard.api.domain.MerchantInfo;
+import com.tzy.sportcard.api.dto.group.RecommendInfoDTO;
+import com.tzy.sportcard.api.dto.group.SearchAdDTO;
+import com.tzy.sportcard.api.dto.merchant.ActGoods;
+import com.tzy.sportcard.api.service.*;
+import com.tzy.sportcard.base.service.CommonCacheService;
+import com.tzy.sportcard.enums.GroupOrderStatusEnums;
+import com.tzy.sportcard.group.domain.CardGroupInfo;
+import com.tzy.sportcard.group.domain.CardGroupOrderInfo;
+import com.tzy.sportcard.group.service.ICardGroupInfoService;
+import com.tzy.sportcard.group.service.ICardGroupOrderInfoService;
+import com.tzy.sportcard.group.service.ITzyMerchantInfoService;
+import com.tzy.sportcard.group.service.impl.GroupActService;
+import com.tzy.system.service.ISysDictDataService;
+import com.tzy.util.mq.MqUtils;
+import com.tzy.valid.Insert;
+import com.tzy.valid.Select;
+import com.tzy.valid.Update;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.elasticsearch.common.Strings;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.transaction.annotation.Isolation;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.teasoft.bee.osql.*;
+import org.teasoft.honey.osql.core.ConditionImpl;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * @author by po'yi
+ * @Classname GroupControllerNew
+ * @Description
+ * @Date 2022/4/26 13:24
+ */
+@Api(value = "组团新接口")
+@RestController
+@RequestMapping("/api/{version}/group")
+@Slf4j
+public class GroupControllerNew {
+
+    @Autowired
+    private MineApiService mineApiService;
+    @Autowired
+    private SuidRich suidRich;
+    @Autowired
+    private PreparedSql preparedSql;
+    @Autowired
+    private GroupApiService groupApiService;
+    @Autowired
+    private ISysDictDataService dictDataService;
+    @Resource
+    private OrderListMapper orderListMapper;
+    @Autowired
+    private ICardGroupInfoService cardGroupInfoService;
+    @Autowired
+    private RedisUtils redisUtils;
+    @Autowired
+    private ICardGroupOrderInfoService orderInfoService;
+    @Resource
+    private ITzyMerchantInfoService merchantInfoService;
+    @Resource
+    private IAppAdConfigService adConfigService;
+    @Autowired
+    @Qualifier("threadPoolTaskExecutor")
+    private ThreadPoolTaskExecutor pools;
+    @Resource
+    private CommonCacheService commonCacheService;
+    @Resource
+    private GroupActService groupActService;
+    @Resource
+    private PyErpRandomCodeService pyErpRandomCodeService;
+    @Autowired
+    private MerchantApiService merchantApiService;
+    @Autowired
+    private AsyncAppService asyncAppService;
+
+
+    /**
+     * @return
+     * @throws Exception
+     */
+    @ApiLog(title = "拼团排名", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/info/rank")
+    @ApiVersion(3.2)
+    public OutDTO getGroupInfoRankV5(@RequestBody GroupInfo groupInfo) {
+        if (groupInfo == null || groupInfo.getId() == null) {
+            return OutDTO.error500("拼团id为空");
+        }
+        CardGroupInfo cardGroupInfo = cardGroupInfoService.selectCardGroupInfoById(groupInfo.getId());
+        if (cardGroupInfo == null) {
+            return OutDTO.error500("拼团不存在");
+        }
+        if (cardGroupInfo.getPaniniListId() == null) {
+            return OutDTO.ok().put("rankInfo", null);
+        }
+        GoodsInfo goodsInfo = new GoodsInfo();
+        goodsInfo.setId(cardGroupInfo.getId().intValue());
+        goodsInfo.setMerchantId(cardGroupInfo.getMerchantId().longValue());
+        goodsInfo.setSport(cardGroupInfo.getSport());
+        goodsInfo.setPaniniBaseId(cardGroupInfo.getPaniniListId().intValue());
+        goodsInfo.setStatus(cardGroupInfo.getStatus().intValue());
+        List<GoodsInfo> infos = Collections.singletonList(goodsInfo);
+        groupApiService.getGroupRankV5(infos);
+        return OutDTO.ok().put("rankInfo", infos.get(0).getRankInfo());
+    }
+
+    /**
+     * @return
+     * @throws Exception
+     */
+    @ApiLog(title = "拼团排名", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/info/rank")
+    @ApiVersion(3.1)
+    public OutDTO getGroupInfoRank(@RequestBody GroupInfo groupInfo) {
+        if (groupInfo == null || groupInfo.getId() == null) {
+            return OutDTO.error500("拼团id为空");
+        }
+        CardGroupInfo cardGroupInfo = cardGroupInfoService.selectCardGroupInfoById(groupInfo.getId());
+        if (cardGroupInfo == null) {
+            return OutDTO.error500("拼团不存在");
+        }
+        if (cardGroupInfo.getPaniniListId() == null) {
+            return OutDTO.ok().put("rankInfo", null);
+        }
+        GoodsInfo goodsInfo = new GoodsInfo();
+        goodsInfo.setId(cardGroupInfo.getId().intValue());
+        goodsInfo.setMerchantId(cardGroupInfo.getMerchantId().longValue());
+        goodsInfo.setSport(cardGroupInfo.getSport());
+        goodsInfo.setPaniniBaseId(cardGroupInfo.getPaniniListId().intValue());
+        goodsInfo.setStatus(cardGroupInfo.getStatus().intValue());
+        List<GoodsInfo> infos = Collections.singletonList(goodsInfo);
+        groupApiService.getGroupRank(infos);
+        return OutDTO.ok().put("rankInfo", infos.get(0).getRankInfo());
+    }
+
+    /**
+     * 组团es
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "组团列表搜索-es版", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/list/search")
+    @ApiVersion(1.1)
+    @ApiLimitRule(seconds = 1, limitCount = 90)
+    public OutDTO searchGroupByEsV3(@RequestBody InDto inDto) throws Exception {
+        GroupQuery query = inDto.buildParam(new GroupQuery());
+        query.setPageNo(inDto.getPageNo()).setRows(inDto.getPageSize()).setUserId(inDto.getUserId()).setExtraAddInfo(false);
+        OutDTO result = OutDTO.ok();
+        if (query.isRecommendFlag()) {
+            RecommendInfoDTO recommendInfo = groupApiService.getRecommendInfo(inDto.getUserId(), inDto.getPageSize(), inDto.getPageNo());
+            if (!CollectionUtils.isEmpty(recommendInfo.getIds())) {
+                query.setSortIds(recommendInfo.getIds());
+                result.put("recId", recommendInfo.getRecId());
+                query.setPageNo(1);
+            }
+        }
+        Future<ExtraInfoDTO> future = getExtraInfoFuture(query);
+        List<GoodsInfo> infos = groupApiService.searchGroupByEs(query);
+        ExtraInfoDTO extraInfo = future.get();
+        List<SearchAdDTO> adList = extraInfo.getExtraInfos();
+        infos = buildInfoByAd(infos, adList, inDto, query.isRecommendFlag());
+        if (query.isTeamActQuery()) {
+            // 球队活动页,数据按商家聚合重组
+            buildInfoByMerchant(infos, result);
+            infos = null;
+        }
+        result.put("merchants", extraInfo.getMerchants());
+        return result.put("cardGroupInfos", infos).put("ref", "es");
+    }
+
+    /**
+     * 组团es
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "组团列表搜索-es版", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/list/search")
+    @ApiVersion(3.1)
+    @ApiLimitRule(seconds = 1, limitCount = 90)
+    public OutDTO searchGroupByEsV4(@RequestBody InDto inDto) throws Exception {
+        GroupQuery query = inDto.buildParam(new GroupQuery());
+        query.setPageNo(inDto.getPageNo()).setRows(inDto.getPageSize()).setUserId(inDto.getUserId()).setExtraAddInfo(false);
+        OutDTO result = OutDTO.ok();
+        if (query.isRecommendFlag()) {
+            RecommendInfoDTO recommendInfo = groupApiService.getRecommendInfo(inDto.getUserId(), inDto.getPageSize(), inDto.getPageNo());
+            if (!CollectionUtils.isEmpty(recommendInfo.getIds())) {
+                query.setSortIds(recommendInfo.getIds());
+                result.put("recId", recommendInfo.getRecId());
+                query.setPageNo(1);
+            }
+        }
+        Future<ExtraInfoDTO> future = getExtraInfoFuture(query);
+        List<GoodsInfo> infos = groupApiService.searchGroupByEs(query);
+        ExtraInfoDTO extraInfo = future.get();
+        List<SearchAdDTO> adList = extraInfo.getExtraInfos();
+        infos = buildInfoByAd(infos, adList, inDto, query.isRecommendFlag());
+        if (query.isTeamActQuery()) {
+            // 球队活动页,数据按商家聚合重组
+            buildInfoByMerchant(infos, result);
+            infos = null;
+        }
+        result.put("merchants", extraInfo.getMerchants());
+        groupApiService.getGroupRank(infos);
+        return result.put("cardGroupInfos", infos).put("ref", "es");
+    }
+
+    /**
+     * 组团es
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "组团列表搜索-es版", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/list/search")
+    @ApiVersion(3.2)
+    @ApiLimitRule(seconds = 1, limitCount = 90)
+    public OutDTO searchGroupByEsV5(@RequestBody InDto inDto) throws Exception {
+        GroupQuery query = inDto.buildParam(new GroupQuery());
+        query.setPageNo(inDto.getPageNo()).setRows(inDto.getPageSize()).setUserId(inDto.getUserId()).setExtraAddInfo(false);
+        OutDTO result = OutDTO.ok();
+        if (query.isRecommendFlag()) {
+            RecommendInfoDTO recommendInfo = groupApiService.getRecommendInfo(inDto.getUserId(), inDto.getPageSize(), inDto.getPageNo());
+            if (!CollectionUtils.isEmpty(recommendInfo.getIds())) {
+                query.setSortIds(recommendInfo.getIds());
+                result.put("recId", recommendInfo.getRecId());
+                query.setPageNo(1);
+            }
+        }
+        Future<ExtraInfoDTO> future = getExtraInfoFuture(query);
+        List<GoodsInfo> infos = groupApiService.searchGroupByEs(query);
+        ExtraInfoDTO extraInfo = future.get();
+        List<SearchAdDTO> adList = extraInfo.getExtraInfos();
+        infos = buildInfoByAd(infos, adList, inDto, query.isRecommendFlag());
+        if (query.isTeamActQuery()) {
+            // 球队活动页,数据按商家聚合重组
+            buildInfoByMerchant(infos, result);
+            infos = null;
+        }
+        result.put("merchants", extraInfo.getMerchants());
+        groupApiService.getGroupRankV5(infos);
+        return result.put("cardGroupInfos", infos).put("ref", "es");
+    }
+
+
+    /**
+     * 组团es
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "组团列表搜索-分页key版", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/list/search")
+    @ApiVersion(4.3)
+    @ApiLimitRule(seconds = 1, limitCount = 400)
+    public OutDTO searchGroupByEsV6(@RequestBody InDto inDto) throws Exception {
+        String markId = inDto.getString("markId");
+        String excludedIdsStr = inDto.getString("excludedids");
+        List<Long> markIdList = new ArrayList<>();
+
+        GroupQuery query = inDto.buildParam(new GroupQuery());
+        if (!Strings.isEmpty(markId)) {
+            markIdList = (List<Long>)redisUtils.get(Constants.APP_SEARCH_CACHE_KEY+markId);
+            query.setExcludeInfoIds(markIdList);
+        }else if((!Strings.isEmpty(markId))){
+            List<String> excludedIds = Arrays.asList(excludedIdsStr.split(","));
+            // 批量构建 Redis Key
+            List<String> redisKeys = excludedIds.stream()
+                    .map(id -> Constants.APP_SEARCH_CACHE_KEY + id)
+                    .collect(Collectors.toList());
+            // 批量查询(假设 redisUtils 支持批量操作)
+            List<Object> results = redisUtils.multiGet(redisKeys);  // 需要自定义 redisUtils 方法实现
+            // 合并结果(处理类型安全)
+            markIdList = results.stream()
+                    .filter(Objects::nonNull)          // 过滤 null 值
+                    .filter(obj -> obj instanceof List)// 确保是 List 类型
+                    .flatMap(obj -> ((List<?>) obj).stream())
+                    .filter(Long.class::isInstance)    // 确保元素为 Long 类型
+                    .map(Long.class::cast)
+                    .distinct()                        // 去重(底层基于 equals/hashCode)
+                    .collect(Collectors.toList());     // 转 List
+            query.setInfoIds(markIdList);
+        }
+        query.setPageNo(inDto.getPageNo()).setRows(inDto.getPageSize()).setUserId(inDto.getUserId()).setExtraAddInfo(false);
+        OutDTO result = OutDTO.ok();
+        if (query.isRecommendFlag()) {
+            RecommendInfoDTO recommendInfo = groupApiService.getRecommendInfo(inDto.getUserId(), inDto.getPageSize(), inDto.getPageNo());
+            if (!CollectionUtils.isEmpty(recommendInfo.getIds())) {
+                query.setSortIds(recommendInfo.getIds());
+                result.put("recId", recommendInfo.getRecId());
+                query.setPageNo(1);
+            }
+        }
+
+        Future<ExtraInfoDTO> future = getExtraInfoFuture(query);
+        List<GoodsInfo> infos = groupApiService.searchGroupByEs(query);
+        ExtraInfoDTO extraInfo = future.get();
+        List<SearchAdDTO> adList = extraInfo.getExtraInfos();
+        infos = buildInfoByAd(infos, adList, inDto, query.isRecommendFlag());
+        if (query.isTeamActQuery()) {
+            // 球队活动页,数据按商家聚合重组
+            buildInfoByMerchant(infos, result);
+            infos = null;
+        }
+        result.put("merchants", extraInfo.getMerchants());
+        groupApiService.getGroupRankV5(infos);
+        UUID uuid = UUID.randomUUID();
+        List<Long> idList = infos.stream()
+                .map(GoodsInfo::getId).mapToLong(id -> id).boxed()
+                .collect(Collectors.toList());
+        if(markIdList!=null){idList.addAll(markIdList);}
+        redisUtils.set(Constants.APP_SEARCH_CACHE_KEY+uuid, idList, 10*60);
+        return result.put("cardGroupInfos", infos).put("ref", "es").put("markId", uuid).put("markLength", idList.size());
+    }
+
+    /**
+     * 组团es
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "指定优惠券拼团列表", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/list/coupon")
+    @ApiVersion(3.9)
+    @ApiLimitRule(seconds = 1, limitCount = 90)
+    public OutDTO searchCouponGroupByEs(@RequestBody InDto inDto) throws Exception {
+        GroupQuery query = inDto.buildParam(new GroupQuery());
+        query.setPageNo(inDto.getPageNo()).setRows(inDto.getPageSize()).setUserId(inDto.getUserId()).setExtraAddInfo(false);
+        OutDTO result = OutDTO.ok();
+        if (query.isRecommendFlag()) {
+            RecommendInfoDTO recommendInfo = groupApiService.getRecommendInfo(inDto.getUserId(), inDto.getPageSize(), inDto.getPageNo());
+            if (!CollectionUtils.isEmpty(recommendInfo.getIds())) {
+                query.setSortIds(recommendInfo.getIds());
+                result.put("recId", recommendInfo.getRecId());
+                query.setPageNo(1);
+            }
+        }
+        Future<ExtraInfoDTO> future = getExtraInfoFuture(query);
+        List<GoodsInfo> infos = groupApiService.searchGroupByEsV6(query);
+        ExtraInfoDTO extraInfo = future.get();
+        List<SearchAdDTO> adList = extraInfo.getExtraInfos();
+        infos = buildInfoByAd(infos, adList, inDto, query.isRecommendFlag());
+        if (query.isTeamActQuery()) {
+            // 球队活动页,数据按商家聚合重组
+            buildInfoByMerchant(infos, result);
+            infos = null;
+        }
+        result.put("merchants", extraInfo.getMerchants());
+        groupApiService.getGroupRankV5(infos);
+        return result.put("cardGroupInfos", infos).put("ref", "es");
+    }
+
+    @PostMapping(value = "/recommend")
+    @ApiOperation("推荐有效拼团")
+    public OutDTO getRecommend(@RequestBody InDto inDto) {
+        if(Strings.isEmpty(inDto.getString("groupInfoId"))){
+            return OutDTO.ok().put("cardGroupInfos", null);
+        }
+        Long groupInfoId = Long.parseLong(inDto.getString("groupInfoId"));
+        List<GoodsInfo> infos = groupApiService.getRecommend2(groupInfoId, inDto.getUserId(), inDto.getPageNo(), inDto.getPageSize());
+        return OutDTO.ok().put("cardGroupInfos", infos).put("ref", "es");
+    }
+
+    @ApiVersion(4.4)
+    @PostMapping(value = "/recommend")
+    @ApiOperation("推荐有效拼团")
+    public OutDTO getRecommend3(@RequestBody InDto inDto) {
+        if(Strings.isEmpty(inDto.getString("groupInfoId"))){
+            return OutDTO.ok().put("cardGroupInfos", null);
+        }
+        Long groupInfoId = Long.parseLong(inDto.getString("groupInfoId"));
+        CompletableFuture<List<GoodsInfo>> recommendFuture = groupApiService.getRecommend3(groupInfoId, inDto.getUserId());
+        List<GoodsInfo> infos = recommendFuture.join();
+        return OutDTO.ok().put("cardGroupInfos", infos).put("ref", "es");
+    }
+
+    private void buildInfoByMerchant(List<GoodsInfo> infos, OutDTO result) {
+        if (CollectionUtils.isEmpty(infos)) {
+            return;
+        }
+        Set<Long> merchantIds = infos.stream().map(GoodsInfo::getMerchantId).collect(Collectors.toSet());
+        List<MerchantSortDTO> sortValues = merchantInfoService.getTeamSortVale(new ArrayList<>(merchantIds));
+        // 按商家排序
+        sortValues.sort(Comparator.comparing(MerchantSortDTO::isLivingFlag).reversed()
+                .thenComparing((MerchantSortDTO dto) -> (double) dto.getSaleNum() / dto.getTotalNum(), Comparator.reverseOrder())
+                .thenComparing(MerchantSortDTO::getId));
+
+        // 按商家ID分组
+        Map<Long, List<GoodsInfo>> groupedByMerchant = infos.stream().collect(Collectors.groupingBy(GoodsInfo::getMerchantId));
+
+        List<MerchantGroupDTO> infoByMerchant = new ArrayList<>();
+        List<BaseMerchantDTO> livingMerchant = new ArrayList<>();
+        for (MerchantSortDTO sortValue : sortValues) {
+            Integer merchantId = sortValue.getId();
+            List<GoodsInfo> merchantGoods = groupedByMerchant.get(merchantId.longValue());
+            if (merchantGoods != null) {
+                merchantGoods.sort(Comparator.comparingDouble(goods -> -((double) goods.getRealSoldNum() / goods.getCopies())));
+                GoodsInfo goodsInfo = merchantGoods.get(0);
+                BaseMerchantDTO merchantInfo = new BaseMerchantDTO(sortValue.getId(), goodsInfo.getMerchantName(), goodsInfo.getAvatar());
+                infoByMerchant.add(new MerchantGroupDTO(merchantInfo, merchantGoods));
+                if (sortValue.isLivingFlag()) {
+                    livingMerchant.add(merchantInfo);
+                }
+            }
+        }
+        result.put("infoByMerchant", infoByMerchant);
+        result.put("livingMerchant", livingMerchant);
+    }
+
+
+    private Future<ExtraInfoDTO> getExtraInfoFuture(GroupQuery query) {
+        String keyword = query.getKeyword();
+        return pools.submit(() -> {
+            ExtraInfoDTO extraInfo = new ExtraInfoDTO();
+            if (StringUtils.isNotEmpty(keyword)) {
+                extraInfo.setMerchants(merchantInfoService.selectMerchant(keyword));
+            }
+            // 球队活动页不查询广告
+            if (!query.isTeamActQuery()) {
+                extraInfo.setExtraInfos(adConfigService.selectAdBySearch(query));
+            }
+            return extraInfo;
+        });
+    }
+
+    private List<GoodsInfo> buildInfoByAd(List<GoodsInfo> groups, List<SearchAdDTO> adList, InDto inDto, boolean recommendFlag) {
+        log.debug("广告信息:{}", adList);
+        if (CollectionUtils.isEmpty(adList)) {
+            return groups;
+        }
+        List<GoodsInfo> infos = CollectionUtils.isEmpty(groups) ? new ArrayList<>() : groups;
+        List<Long> adInfoIds = adList.stream().filter(ad -> Constants.ORDER_TYPE_GROUP.equals(ad.getType()))
+                .map(SearchAdDTO::getRefId).collect(Collectors.toList());
+        List<GoodsInfo> adInfos = new ArrayList<>();
+        if (!CollectionUtils.isEmpty(adInfoIds)) {
+            adInfos = groupApiService.searchGroupByEs(new GroupQuery().setInfoIds(adInfoIds).setUserId(inDto.getUserId()));
+        }
+        int startNum = (inDto.getPageNo() - 1) * inDto.getPageSize() + 1;
+        // 插入广告信息到 infos 中
+        for (SearchAdDTO ad : adList) {
+            GoodsInfo adInfo = convertToInfo(ad, adInfos);
+            if (adInfo == null) {
+                continue;
+            }
+            int index = ad.getAdNum() - startNum;
+            boolean isUpdated = false;
+            if (Constants.ORDER_TYPE_GROUP.equals(ad.getType())) {
+                for (int i = 0; i < infos.size(); i++) {
+                    GoodsInfo info = infos.get(i);
+                    if (info.getId() == ad.getRefId().intValue()) {
+                        info.setAdFlag(true);
+                        info.setAdType(ad.getType());
+                        if (i != index && index >= 0 && index < infos.size()) {
+                            infos.remove(i);
+                            infos.add(index, info);
+                        }
+                        isUpdated = true;
+                        break;
+                    }
+                }
+            }
+            if (!isUpdated) {
+                if (index >= 0 && index < infos.size()) {
+                    infos.add(index, adInfo);
+                } else {
+                    infos.add(adInfo);
+                }
+            }
+        }
+        if (infos.size() > inDto.getPageSize()) {
+            infos = infos.subList(0, inDto.getPageSize());
+        }
+        return infos;
+    }
+
+    private GoodsInfo convertToInfo(SearchAdDTO ad, List<GoodsInfo> adInfos) {
+        if (Constants.ORDER_TYPE_GROUP.equals(ad.getType())) {
+            return adInfos.stream().filter(info -> info.getId() == ad.getRefId().intValue())
+                    .findFirst().map(info -> {
+                        info.setAdFlag(true);
+                        info.setAdType(ad.getType());
+                        info.setRefAdId(ad.getId());
+                        return info;
+                    }).orElse(null);
+        }
+        return buildMerchantAdInfo(ad);
+    }
+
+    private static GoodsInfo buildMerchantAdInfo(SearchAdDTO ad) {
+        GoodsInfo info = new GoodsInfo();
+        info.setAdFlag(true);
+        info.setAdType(ad.getType());
+        info.setName(ad.getName());
+        info.setCoverPicture(ad.getImgUrl());
+        info.setLinkUrl(ad.getLinkUrl());
+        info.setId(ad.getRefId().intValue());
+        info.setMerchantId(ad.getRefId());
+        info.setRefAdId(ad.getId());
+        return info;
+    }
+
+    /**
+     * 查询组团卡密
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "查询组团卡密", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/goods")
+    public OutDTO getGroupGoods(@RequestBody InDto inDto) {
+        return groupApiService.searchGroupGoodsNew(inDto);
+    }
+
+    @ApiLog(title = "获取组队密队伍信息", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/guess")
+    @ApiVersion(1.0)
+    @ApiOperation("获取组队卡密队伍信息")
+    public OutDTO getGroupGuessTeam(@RequestBody InDto inDto) {
+        Object id = inDto.get("id");
+        String type = inDto.getString("type");
+        if (id == null || StringUtils.isEmpty(type)) {
+            return OutDTO.error500("参数为空!");
+        }
+        String key = Constants.INFO_ONLY_TEAM_CACHE + type + id;
+        Object cache = redisUtils.hget(Constants.INFO_ONLY_TEAM_CACHE, key);
+        if (cache != null) {
+            return OutDTO.ok().put("guessInfo", cache);
+        }
+
+        String sql;
+        boolean isTeam = false;
+        if (InfoActConfig.ACT_GUESS_TYPE_TEAM.equals(type)) {
+            isTeam = true;
+            sql = QuerySql.getQuerySql("com.tzy.common.dto.GroupTeamDTO.getGroupTeam");
+        } else if (InfoActConfig.ACT_GUESS_TYPE_SET.equals(type)) {
+            sql = QuerySql.getQuerySql("com.tzy.common.dto.GroupTeamDTO.getGroupBySet");
+        } else if (InfoActConfig.ACT_GUESS_TYPE_PLAYER.equals(type)) {
+            sql = QuerySql.getQuerySql("com.tzy.common.dto.GroupTeamDTO.getGroupByPlayer");
+        } else {
+            return OutDTO.error500("类型不存在!");
+        }
+
+        List<GroupTeamDTO> list = preparedSql.selectSomeField(sql, new GroupTeamDTO(), new Object[]{id});
+        if (isTeam) {
+            list.stream().filter(t -> StringUtils.isEmpty(t.getSimpleTeamName())).forEach(team -> {
+                String simpleName = groupApiService.getTeamSimpleName(team.getTeam().trim());
+                team.setSimpleTeamName(simpleName);
+            });
+        }
+        redisUtils.hset(Constants.INFO_ONLY_TEAM_CACHE, key, list, 7200);
+        return OutDTO.ok().put("guessInfo", list);
+    }
+
+    @ApiLog(title = "获取组队密队伍信息,新接口,替换之前接口", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/v3/team", method = RequestMethod.POST)
+    @ApiVersion(2.0)
+    @ApiOperation("获取组队卡密队伍信息")
+    public OutDTO getGroupTeamV3(@RequestBody InDto inDto) {
+        Integer id = (Integer) inDto.get("id");
+        Boolean onlyTeam = (Boolean) inDto.get("onlyTeam");
+        Boolean cacheFlag = (Boolean) inDto.get("cacheFlag");
+        boolean isUserCache = cacheFlag == null || cacheFlag;
+        Map<String, List<GroupTeamDTO>> list = buildSelectTeamsNew(id, onlyTeam, isUserCache);
+        return OutDTO.ok().put("groupTeam", list);
+    }
+    @ApiLog(title = "获取组队密队伍信息,【支持买队剩余随机】", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/v4/buyTeam", method = RequestMethod.POST)
+    @ApiVersion(2.0)
+    @ApiOperation("获取组队卡密队伍信息【支持买队剩余随机】")
+    public OutDTO getGroupTeamV4(@RequestBody InDto inDto) {
+        Integer id = (Integer) inDto.get("id");
+        Boolean onlyTeam = (Boolean) inDto.get("onlyTeam");
+        Boolean cacheFlag = (Boolean) inDto.get("cacheFlag");
+        boolean isUserCache = cacheFlag == null || cacheFlag;
+        Map<String, List<GroupTeamDTO>> list = buildSelectTeamsNewV2(id, onlyTeam, isUserCache);
+        return OutDTO.ok().put("groupTeam", list);
+    }
+
+    /**
+     * 支持查询
+     * @param infoId
+     * @param isOnlyTeam
+     * @param isUserCache
+     * @return
+     */
+    private Map<String, List<GroupTeamDTO>> buildSelectTeamsNewV2(Integer infoId, boolean isOnlyTeam, boolean isUserCache) {
+        GroupInfo groupInfo = groupApiService.getGroupInfoById(infoId);
+        Map<String, List<GroupTeamDTO>> list;
+        if (Constants.INFO_TYPE_TEAM_TO_RANDOM.equals(groupInfo.getChangeType())) {
+//            return groupApiService.getGroupTeamToRandom(infoId);
+            return groupApiService.getGroupTeamToRandomV2(infoId,groupInfo.getType());
+        }
+        //如果买队 查询剩余的 卡密列表和库存
+        if (Constants.INFO_TYPE_BUY_TEAM.equals(groupInfo.getType())) {
+            List<SimpleGroupGoodsDTO> goods = groupApiService.selectedGoodsByInfoIdV2(infoId.longValue(), groupInfo.getStatus() >= 201);
+            log.debug("查询剩余的卡密列表和库存:{}", goods);
+            Map<String, List<SimpleGroupGoodsDTO>> collect = goods.stream()
+                                                                  .collect(Collectors.groupingBy(SimpleGroupGoodsDTO::getTeam));
+            list = collect.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue()
+                                                                                                         .stream()
+                                                                                                         .map(goodsDto -> {
+                                                                                                             GroupTeamDTO team =new GroupTeamDTO();
+                                                                                                             team.setPlayerName(goodsDto.getPlayerName());
+                                                                                                             team.setTeam(goodsDto.getTeam());
+                                                                                                             team.setSimpleTeamName(goodsDto.getSimpleTeamName());
+                                                                                                             team.setPrice(goodsDto.getPrice());
+                                                                                                             team.setTeamId(goodsDto.getTeamId());
+                                                                                                             team.setCopies(1);//买队默认 为1份
+                                                                                                             team.setConference(goodsDto.getConference());
+                                                                                                             return team;
+                                                                                                         }).collect(Collectors.toList())));
+
+            return list;
+        }
+        String key = isOnlyTeam ? Constants.INFO_ONLY_TEAM_CACHE + infoId : Constants.INFO_SELECT_TEAM_CACHE + infoId;
+        Object cache = RedisTools.getRedisUtils().hget(key, infoId.toString());
+        if (cache == null || !isUserCache) {
+            List<SimpleGroupGoodsDTO> goods = groupApiService.selectedGoodsByInfoId(infoId.longValue(), groupInfo.getStatus() >= 201);
+            list = buildGroupTeams(groupInfo, isOnlyTeam, goods);
+            RedisTools.getRedisUtils().hset(key, infoId.toString(), list, 7200);
+            if (!isOnlyTeam) {
+                RedisTools.getRedisUtils().expire(key, 1800);
+            }
+        } else {
+            list = (Map<String, List<GroupTeamDTO>>) cache;
+        }
+        return list;
+    }
+
+    private Map<String, List<GroupTeamDTO>> buildSelectTeamsNew(Integer infoId, boolean isOnlyTeam, boolean isUserCache) {
+        GroupInfo groupInfo = groupApiService.getGroupInfoById(infoId);
+        if (Constants.INFO_TYPE_TEAM_TO_RANDOM.equals(groupInfo.getChangeType())) {
+            return groupApiService.getGroupTeamToRandom(infoId);
+        }
+        String key = isOnlyTeam ? Constants.INFO_ONLY_TEAM_CACHE + infoId : Constants.INFO_SELECT_TEAM_CACHE + infoId;
+        Object cache = RedisTools.getRedisUtils().hget(key, infoId.toString());
+        Map<String, List<GroupTeamDTO>> list;
+        if (cache == null || !isUserCache) {
+            List<SimpleGroupGoodsDTO> goods = groupApiService.selectedGoodsByInfoId(infoId.longValue(), groupInfo.getStatus() >= 201);
+            list = buildGroupTeams(groupInfo, isOnlyTeam, goods);
+            RedisTools.getRedisUtils().hset(key, infoId.toString(), list, 7200);
+            if (!isOnlyTeam) {
+                RedisTools.getRedisUtils().expire(key, 1800);
+            }
+        } else {
+            list = (Map<String, List<GroupTeamDTO>>) cache;
+        }
+        return list;
+    }
+
+    private Map<String, List<GroupTeamDTO>> buildGroupTeams(GroupInfo groupInfo, boolean isOnlyTeam, List<SimpleGroupGoodsDTO> goods) {
+        boolean isArea = Constants.INFO_SUB_TYPE_AREA_RANDOM.equals(groupInfo.getSubType());
+        Map<String, Integer> numByTeamOrConference = new HashMap<>();
+        if (!isOnlyTeam) {
+            numByTeamOrConference = getSoldNumByType(groupInfo.getId().intValue(), isArea);
+        }
+
+        Map<String, List<SimpleGroupGoodsDTO>> goodsByTeamOrConference;
+        if (isArea) {
+            goodsByTeamOrConference = goods.stream().collect(Collectors.groupingBy(SimpleGroupGoodsDTO::getConference));
+        } else {
+            goodsByTeamOrConference = goods.stream().collect(Collectors.groupingBy(SimpleGroupGoodsDTO::getTeam));
+        }
+
+        Map<String, List<GroupTeamDTO>> list;
+        List<GroupTeamDTO> groupTeams = new ArrayList<>();
+        Set<String> teams = goodsByTeamOrConference.keySet();
+        for (String team : teams) {
+            List<SimpleGroupGoodsDTO> goodsByTeam = goodsByTeamOrConference.get(team);
+            SimpleGroupGoodsDTO simpleGroupGoods = goodsByTeam.get(0);
+            GroupTeamDTO groupTeam = new GroupTeamDTO();
+            groupTeam.setConference(simpleGroupGoods.getConference());
+            groupTeam.setPrice(simpleGroupGoods.getPrice());
+            groupTeam.setCopies(goodsByTeam.size());
+
+            if (!isArea) {
+                groupTeam.setZnTeam(simpleGroupGoods.getZnTeam());
+                groupTeam.setTeamId(simpleGroupGoods.getTeamId());
+                groupTeam.setTeam(team);
+                GroupTeamDTO simpleDto = groupApiService.getSimpleTeamDTO(team.trim());
+                groupTeam.setSimpleTeamName(simpleDto.getSimpleTeamName());
+                groupTeam.setRemark(simpleDto.getRemark());
+            }
+
+            if (!isOnlyTeam) {
+                Integer num = numByTeamOrConference.get(isArea ? groupTeam.getConference() : groupTeam.getTeamId().toString());
+                groupTeam.setSoldCopies(num != null ? num : 0);
+            }
+            groupTeams.add(groupTeam);
+        }
+        list = groupTeams.stream().collect(Collectors.groupingBy(GroupTeamDTO::getConference));
+        return list;
+    }
+
+    private Map<String, Integer> getSoldNumByType(Integer infoId, Boolean isArea) {
+        Map<String, Integer> numByTeamOrConference;
+        if (isArea) {
+            numByTeamOrConference = groupApiService.getGroupLockNumByConference(infoId);
+        } else {
+            numByTeamOrConference = groupApiService.getGroupLockNumByTeamId(infoId);
+        }
+        return numByTeamOrConference;
+    }
+
+
+    private Map<String, List<GroupTeamDTO>> getSelectTeams(Object id, Object onlyTeam) {
+        String key;
+        boolean isOnlyTeam = onlyTeam != null && (Boolean) onlyTeam;
+        if (isOnlyTeam) {
+            key = Constants.INFO_ONLY_TEAM_CACHE + id;
+        } else {
+            key = Constants.INFO_SELECT_TEAM_CACHE + id;
+        }
+        Object cache = RedisTools.getRedisUtils().hget(key, id.toString());
+        Map<String, List<GroupTeamDTO>> list;
+        if (cache == null) {
+            String sql = QuerySql.getQuerySql("com.tzy.common.dto.GroupTeamDTO.getGroupTeam");
+            List<GroupTeamDTO> groupTeamDTOS = preparedSql.selectSomeField(sql, new GroupTeamDTO(), new Object[]{id});
+            groupTeamDTOS.forEach(team -> setCountAndSimpleName(team, id, onlyTeam));
+            list = groupTeamDTOS.stream().collect(Collectors.groupingBy(GroupTeamDTO::getConference));
+            RedisTools.getRedisUtils().hset(key, id.toString(), list, 7200);
+            if (!isOnlyTeam) {
+                RedisTools.getRedisUtils().expire(key, 60);
+            }
+        } else {
+            list = (Map<String, List<GroupTeamDTO>>) cache;
+        }
+        return list;
+    }
+
+    private void setCountAndSimpleName(GroupTeamDTO team, Object id, Object onlyTeam) {
+        if (onlyTeam == null || !(Boolean) onlyTeam) {
+            String sql = QuerySql.getQuerySql("com.tzy.common.dto.GroupTeamDTO.getGroupTeamCount");
+            List<TeamCountDTO> countDTOS = preparedSql.selectSomeField(sql, new TeamCountDTO(), new Object[]{id, team.getTeamId()});
+            TeamCountDTO teamCountDTO = countDTOS.get(0);
+            Integer unPayOrderCount = orderListMapper.selectUnPayTeamCount((Integer) id, team.getTeamId());
+            team.setCopies(teamCountDTO.getCopies());
+            team.setSoldCopies(teamCountDTO.getSoldCopies() + unPayOrderCount);
+        }
+
+        if (StringUtils.isEmpty(team.getSimpleTeamName())) {
+            String simpleName = groupApiService.getTeamSimpleName(team.getTeam().trim());
+            team.setSimpleTeamName(simpleName);
+        }
+
+    }
+
+    /**
+     * 选队随机玩法从选队改为随机
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "选队随机玩法从选队改为随机", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @RequestMapping(value = "/changeInfoType", method = RequestMethod.POST)
+    @RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_SHIPPING})
+    public OutDTO changeInfoType(@RequestBody InDto inDto) {
+        AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+        Integer groupInfoId = (Integer) inDto.get("groupInfoId");
+        CardGroupInfo cardGroupInfo = cardGroupInfoService.selectSoldCardGroupInfoById(groupInfoId.longValue());
+        if (cardGroupInfo == null || !Constants.INFO_TYPE_SELECT_TEAM.equals(cardGroupInfo.getType())) {
+            return OutDTO.error500("组团信息不符合要求!");
+        }
+        List<SysDictData> changeType = dictDataService.getByTypeAndStatus(Constants.TEAM_CHANGE_RATE, Constants.ONE);
+        int rate = 50;
+        if (!changeType.isEmpty()) {
+            if (changeType.size() == 1) {
+                rate = Integer.parseInt(changeType.get(0).getDictValue());
+            } else {
+                List<SysDictData> rateValue = changeType.stream().filter(t -> appUserInfoDto.getRolecode().equals(t.getDictLabel())).collect(Collectors.toList());
+                rate = Integer.parseInt(rateValue.get(0).getDictValue());
+            }
+        }
+        if (cardGroupInfo.getRealSoldNum() * 100 / cardGroupInfo.getCopies() < rate) {
+            return OutDTO.error500("售出比例不足,无法修改!");
+        }
+
+        String lockKey = "BUY_LOCK_" + groupInfoId;
+        boolean isLock;
+        try {
+            isLock = redisUtils.tryLock(lockKey, TimeUnit.SECONDS, 15L);
+            if (isLock) {
+                // 查询未付款的用户数(订单)
+                if (orderInfoService.checkIsUnPayOrder(groupInfoId)) {
+                    redisUtils.unlock(lockKey);
+                    return OutDTO.error(500, "存在未支付订单,玩法不可修改,请稍后再试!");
+                }
+                CardGroupInfo update = new CardGroupInfo();
+                update.setId(cardGroupInfo.getId());
+                update.setChangeType(Constants.INFO_TYPE_TEAM_TO_RANDOM);
+                BigDecimal price = cardGroupInfoService.calculateUnitPrice(groupInfoId);
+                if (StringUtils.isNotEmpty(cardGroupInfo.getPointType()) && cardGroupInfo.getPointType().startsWith(Constants.POINT_TYPE_MERCHANT_ACT_PRE)) {
+                    price = new BigDecimal(price.intValue() + "");
+                }
+                update.setUnitPrice(price);
+                cardGroupInfoService.updateCardGroupInfo(update);
+                log.info("选队转随机,拼团code:{},价格:{}", cardGroupInfo.getCode(), price);
+                cardGroupInfoService.markGoodsStatus(cardGroupInfo.getId());
+                Map<String, List<GroupTeamDTO>> selectTeams = getSelectTeams(groupInfoId, false);
+                redisUtils.hset(Constants.INFO_TEAM_TO_RANDOM_CACHE, groupInfoId.toString(), selectTeams);
+                redisUtils.del("order_group_cache:" + groupInfoId);
+                redisUtils.unlock(lockKey);
+                return OutDTO.ok();
+            }
+        } catch (ServiceException e) {
+            log.error("修改组队玩法异常,id:{}", groupInfoId, e);
+            return OutDTO.error(e.getCode(), e.getMessage());
+        } catch (Exception e) {
+            log.error("修改组队玩法异常,id:{}", groupInfoId, e);
+        } finally {
+            try {
+                redisUtils.unlock(lockKey);
+            } catch (Exception e) {
+                log.error("锁释放异常:", e);
+            }
+        }
+        return OutDTO.error500("修改组队玩法失败");
+    }
+
+
+    /**
+     * 选队随机/买队玩法 改为剩余随机
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "选队随机/买队玩法 改为剩余随机", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @RequestMapping(value = "/v2/changeInfoType", method = RequestMethod.POST)
+    @RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_SHIPPING})
+    public OutDTO changeInfoTypeV2(@RequestBody InDto inDto) {
+        AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+        Integer groupInfoId = (Integer) inDto.get("groupInfoId");
+        CardGroupInfo cardGroupInfo = cardGroupInfoService.selectSoldCardGroupInfoById(groupInfoId.longValue());
+        if (cardGroupInfo == null || !Constants.CAN_CHANGE_RATE.contains(cardGroupInfo.getType())) {
+            return OutDTO.error500("组团信息不符合要求!");
+        }
+        List<SysDictData> changeType = dictDataService.getByTypeAndStatus(Constants.BUY_TEAM_CHANGE_RATE, Constants.ONE);
+        int rate = 50;
+        if (!changeType.isEmpty()) {
+            if (changeType.size() == 1) {
+                rate = Integer.parseInt(changeType.get(0).getDictValue());
+            } else {
+                List<SysDictData> rateValue = changeType.stream().filter(t -> appUserInfoDto.getRolecode().equals(t.getDictLabel())).collect(Collectors.toList());
+                rate = Integer.parseInt(rateValue.get(0).getDictValue());
+            }
+        }
+        if (cardGroupInfo.getRealSoldNum() * 100 / cardGroupInfo.getCopies() < rate) {
+            return OutDTO.error500("售出比例不足,无法修改!");
+        }
+
+        String lockKey = "BUY_LOCK_" + groupInfoId;
+        boolean isLock;
+        try {
+            isLock = redisUtils.tryLock(lockKey, TimeUnit.SECONDS, 15L);
+            if (isLock) {
+                // 查询未付款的用户数(订单)
+                if (orderInfoService.checkIsUnPayOrder(groupInfoId)) {
+                    redisUtils.unlock(lockKey);
+                    return OutDTO.error(500, "存在未支付订单,玩法不可修改,请稍后再试!");
+                }
+                CardGroupInfo update = new CardGroupInfo();
+                update.setId(cardGroupInfo.getId());
+                update.setChangeType(Constants.INFO_TYPE_TEAM_TO_RANDOM);
+                BigDecimal price = cardGroupInfoService.calculateUnitPrice(groupInfoId);
+                if (StringUtils.isNotEmpty(cardGroupInfo.getPointType()) && cardGroupInfo.getPointType().startsWith(Constants.POINT_TYPE_MERCHANT_ACT_PRE)) {
+                    price = new BigDecimal(price.intValue() + "");
+                }
+                update.setUnitPrice(price);
+                cardGroupInfoService.updateCardGroupInfo(update);
+                log.info("选队随机/买队玩法 改为剩余随机,拼团code:{},玩法:{},价格:{}", cardGroupInfo.getCode(),cardGroupInfo.getType(), price);
+                cardGroupInfoService.markGoodsStatus(cardGroupInfo.getId());
+                boolean onlyTeam = cardGroupInfo.getType().equals(Constants.INFO_TYPE_BUY_TEAM);
+                Map<String, List<GroupTeamDTO>> selectTeams;
+                //如果是买队转随机 查询已转随机的卡密
+                if (onlyTeam) {
+                    selectTeams = getBuyTeamToChange(groupInfoId);
+                } else {
+                    selectTeams = getSelectTeams(groupInfoId, onlyTeam);
+                }
+                redisUtils.hset(Constants.INFO_TEAM_TO_RANDOM_CACHE, groupInfoId.toString(), selectTeams);
+                redisUtils.del("order_group_cache:" + groupInfoId);
+                redisUtils.unlock(lockKey);
+                return OutDTO.ok();
+            }
+        } catch (ServiceException e) {
+            log.error("修改组队玩法异常,id:{}", groupInfoId, e);
+            return OutDTO.error(e.getCode(), e.getMessage());
+        } catch (Exception e) {
+            log.error("修改组队玩法异常,id:{}", groupInfoId, e);
+        } finally {
+            try {
+                redisUtils.unlock(lockKey);
+            } catch (Exception e) {
+                log.error("锁释放异常:", e);
+            }
+        }
+        return OutDTO.error500("修改组队玩法失败");
+    }
+
+    /**
+     * 买队转随机 查询已转随机的卡密
+     * @param groupInfoId
+     * @return
+     */
+    private Map<String, List<GroupTeamDTO>> getBuyTeamToChange(Integer groupInfoId) {
+        Map<String, List<GroupTeamDTO>> selectTeams;
+        String sql = QuerySql.getQuerySql("com.tzy.common.dto.GroupTeamDTO.getGroupChangeTeam");
+        List<GroupTeamDTO> groupTeamDTOS = preparedSql.selectSomeField(sql, new GroupTeamDTO(), new Object[]{groupInfoId});
+        groupTeamDTOS.forEach(team -> {
+            String simpleName = groupApiService.getTeamSimpleName(team.getTeam().trim());
+            team.setSimpleTeamName(simpleName);
+        });
+        selectTeams = groupTeamDTOS.stream().collect(Collectors.groupingBy(GroupTeamDTO::getConference));
+        return selectTeams;
+    }
+
+    /**
+     * 获取组团订单金额信息
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "获取组团订单金额信息", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @RequestMapping(value = "/getGroupAmount", method = RequestMethod.POST)
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_LIVING, UserType.USER_ROLE_DELIVERY, UserType.USER_ROLE_PUBLICITY})
+    public OutDTO getGroupAmount(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        AppAssert.notNull(user, MsgConstants.NEED_LOGIN);
+        Integer groupInfoId = inDto.getIntegerParam("groupInfoId");
+        CardGroupInfo cardGroupInfo = cardGroupInfoService.selectCardGroupInfoById(groupInfoId.longValue());
+        if (cardGroupInfo == null || user.getMerchantId() != cardGroupInfo.getMerchantId().intValue()) {
+            return OutDTO.error500("组团信息不符合要求!");
+        }
+        return cardGroupInfoService.getGroupAmount(cardGroupInfo);
+    }
+
+
+    /**
+     * 卡密详情
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "卡密详情", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @RequestMapping(value = "/getGoodsDetail", method = RequestMethod.POST)
+    public OutDTO getGoodsDetail(@RequestBody InDto inDto) {
+        Object id = inDto.get("id");
+        if (id == null) {
+            return OutDTO.error500("id为空!");
+        }
+        CardGroupGoods goods = new CardGroupGoods();
+        goods.setId(Long.valueOf(id.toString()));
+        CardGroupGoods groupGoods = suidRich.selectOne(goods);
+        return OutDTO.ok().put("groupGoods", groupGoods);
+    }
+
+    /**
+     * 获取活动卡密
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "获取活动卡密", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @RequestMapping(value = "/act/goods", method = RequestMethod.POST)
+    public OutDTO getActGoods(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        if (inDto.get("id") == null) {
+            return OutDTO.error500("参数为空");
+        }
+        List<ActGoods> goodsList = getActGoods(Long.valueOf(inDto.getString("id")), userInfo.getId().longValue());
+        return OutDTO.ok().put("goods", goodsList);
+    }
+
+    private List<ActGoods> getActGoods(Long infoId, Long userId) {
+        ActGoods goods = new ActGoods();
+        goods.setGroupInfoId(infoId);
+        goods.setUserId(userId);
+        goods.setActStatus(0);
+        Condition condition = new ConditionImpl();
+        condition.op("actId", Op.gt, 0);
+        List<ActGoods> goodsList = suidRich.select(goods, condition);
+        return goodsList;
+    }
+
+    /**
+     * 获取活动卡密
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "获取活动卡密", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @RequestMapping(value = "/act/goods/exchange", method = RequestMethod.POST)
+    public OutDTO exchangeActGoods(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        if (inDto.get("id") == null) {
+            return OutDTO.error500("参数为空");
+        }
+        Long infoId = Long.valueOf(inDto.getString("id"));
+        CardGroupInfo cardGroupInfo = cardGroupInfoService.selectCardGroupInfoById(infoId);
+        if (!Constants.GROUP_FULL_STATUS.contains(cardGroupInfo.getStatus().intValue())) {
+            return OutDTO.error500("组团尚未完成,请组齐后再兑换");
+        }
+        if (StringUtils.isNotEmpty(cardGroupInfo.getHotTypeConfig())) {
+            JSONObject jsonObject = JSONObject.parseObject(cardGroupInfo.getHotTypeConfig());
+            String endTime = jsonObject.getString("endTime");
+            Date date = DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, endTime);
+            if (date.before(new Date())) {
+                return OutDTO.error500("已过奖品兑换时间!");
+            }
+        }
+        List<ActGoods> goodsList = getActGoods(infoId, userInfo.getId().longValue());
+        orderInfoService.exchangeActGoods(goodsList, userInfo);
+        return OutDTO.ok();
+    }
+
+
+    /**
+     * 查询组团订单用户信息
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "查询组团订单用户信息", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @RequestMapping(value = "/order/user", method = RequestMethod.POST)
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_LIVING, UserType.USER_ROLE_DELIVERY, UserType.USER_ROLE_PUBLICITY})
+    public OutDTO getGroupOrderUser(@RequestBody InDto inDto) {
+        GroupOrderUserDTO orderUserDTO = new GroupOrderUserDTO();
+        orderUserDTO.setGroupInfoId(Integer.valueOf(inDto.getString("ids")));
+        String statusStr = inDto.getString("status");
+        List<Integer> statusList;
+        boolean isHide = false;
+        if (StringUtils.isNotEmpty(statusStr)) {
+            statusList = Arrays.stream(statusStr.split(",")).map(s -> Integer.valueOf(s)).collect(Collectors.toList());
+            if (statusList.contains(201)) {
+                isHide = true;
+            }
+        } else {
+            statusList = Arrays.asList(new Integer[]{101});
+        }
+
+
+        // orderUserDTO.setStatus(101);
+        Condition condition = new ConditionImpl();
+        condition.op("status", Op.in, statusList);
+        condition.op("orderSubType", Op.eq, null);
+        condition.orderBy("id", OrderType.DESC);
+        condition.start((inDto.getPageNo() - 1) * inDto.getPageSize()).size(inDto.getPageSize());
+        List<GroupOrderUserDTO> groupUserOrderDtos = suidRich.select(orderUserDTO, condition);
+        if (isHide) {
+            groupUserOrderDtos.forEach(g -> {
+                g.setShippingAddressLinkname(null);
+                g.setShippingAddress(null);
+                g.setShippingAddressPhone(null);
+            });
+        }
+        return OutDTO.ok().put("groupUserOrderDtos", groupUserOrderDtos);
+    }
+
+    /**
+     * 查询组团订单用户信息
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiVersion(3.9)
+    @ApiLog(title = "查询组团订单用户信息", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @RequestMapping(value = "/order/user", method = RequestMethod.POST)
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_LIVING, UserType.USER_ROLE_DELIVERY, UserType.USER_ROLE_PUBLICITY})
+    public OutDTO getGroupOrderUserV2(@RequestBody InDto inDto) {
+        String statusStr = inDto.getString("status");
+        //isMerchantOpen 空-全部 0-否商家代搓 1-是商家代搓
+        Integer isMerchantOpen =-1;
+        if(inDto.existKeyString("isMerchantOpen") && inDto.getIntegerParam("isMerchantOpen")!=null){
+            isMerchantOpen = inDto.getIntegerParam("isMerchantOpen");
+        }
+        List<Integer> statusList;
+        boolean isHide = false;
+        if (StringUtils.isNotEmpty(statusStr)) {
+            statusList = Arrays.stream(statusStr.split(",")).map(s -> Integer.valueOf(s)).collect(Collectors.toList());
+            if (statusList.contains(201)) {
+                isHide = true;
+            }
+        } else {
+            statusList = Arrays.asList(new Integer[]{101});
+        }
+        List<GroupOrderUserDTO> groupUserOrderDtos;
+        if (isMerchantOpen >= 0) {
+            // 使用带商户开放状态筛选的查询
+            groupUserOrderDtos = groupApiService.getGroupOrderUserWithMerchantOpen(Long.valueOf(inDto.getString("ids")), statusList,isMerchantOpen);
+        } else {
+            // 使用普通查询
+            groupUserOrderDtos = groupApiService.getGroupOrderUserV2(Long.valueOf(inDto.getString("ids")), statusList);
+        }
+
+        groupUserOrderDtos.forEach(g -> {
+            //已支付的查询是否已开卡密
+            if(g.getStatus() != 206 && g.getStatus() != 301){
+                //查询未解锁的数据
+                int unLockCount = groupApiService.getCountByLockstatus(g.getUserId().intValue(), g.getId().intValue(), 0);
+                g.setUnLockStatus(unLockCount == 0 ? 1 : 0);
+            }else{
+                g.setUnLockStatus(1);
+            }
+        });
+        if (isHide) {
+            groupUserOrderDtos.forEach(g -> {
+                g.setShippingAddressLinkname(null);
+                g.setShippingAddress(null);
+                g.setShippingAddressPhone(null);
+            });
+        }
+        return OutDTO.ok().put("groupUserOrderDtos", groupUserOrderDtos);
+    }
+
+
+    @ApiLog(title = "上传生态购code", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁!")
+    @RequestMapping(value = "/info/code/save", method = RequestMethod.POST)
+    @RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_OPERATE_USER})
+    @ApiVersion(2.0)
+    public OutDTO saveSaleCode(@RequestBody InDto inDto) {
+        ActSaleCode saleCode = inDto.buildParam(new ActSaleCode());
+        if (StringUtils.isEmpty(saleCode.getCode()) || saleCode.getMerchantId() == null || saleCode.getPaniniBaseId() == null) {
+            return OutDTO.error500("参数缺失!");
+        }
+        if (!CollectionUtils.isEmpty(suidRich.select(new ActSaleCode(saleCode.getCode()).setStatus(0)))) {
+            return OutDTO.error500("该code已存在!");
+        }
+        saleCode.setCreateTime(new Date());
+        suidRich.insert(saleCode);
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "核销code", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.0)
+    @PostMapping(value = "/verify/info/code")
+    @ApiOperation("核销code")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    public OutDTO verifyInfoCode(@RequestBody InDto inDto) {
+        SaleCodeRecord codeRecord = inDto.buildParam(new SaleCodeRecord());
+        SaleCodeRecord existRecord = checkCodeRecord(codeRecord);
+        SaleCodeRecord editRecord = new SaleCodeRecord().setId(existRecord.getId()).setStatus(1)
+                .setImg(codeRecord.getImg()).setVerifyTime(new Date()).setRemark(codeRecord.getRemark());
+        suidRich.update(editRecord);
+        return OutDTO.ok();
+    }
+
+    private SaleCodeRecord checkCodeRecord(SaleCodeRecord codeRecord) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        if (user == null || user.getMerchantId() == null) {
+            throw new ServiceException("权限不足!");
+        }
+        if (StringUtils.isEmpty(codeRecord.getCode()) || StringUtils.isEmpty(codeRecord.getImg()) || codeRecord.getRefId() == null) {
+            throw new ServiceException("参数缺失!");
+        }
+        GroupInfo groupInfo = groupApiService.getGroupInfoById(codeRecord.getRefId());
+        if (groupInfo == null || groupInfo.getMerchantId() != user.getMerchantId().longValue() || groupInfo.getStatus() != 203) {
+            throw new ServiceException("被核销拼团信息异常!");
+        }
+        SaleCodeRecord cond = new SaleCodeRecord().setCode(codeRecord.getCode()).setStatus(0).setRefId(codeRecord.getRefId()).setType(Constants.ORDER_TYPE_GROUP);
+        SaleCodeRecord existRecord = suidRich.selectOne(cond);
+        if (existRecord == null) {
+            throw new ServiceException("核销码记录不存在!");
+        }
+        return existRecord;
+    }
+
+    @ResponseBody
+    @RequestMapping(value = "/info/code/select", method = RequestMethod.POST)
+    @RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_OPERATE_USER})
+    public OutDTO selectSaleCode(@Validated(Select.class) @RequestBody ActSaleCode saleCode) {
+        return OutDTO.ok().put("codes", suidRich.select(saleCode));
+    }
+
+
+    /**
+     * 上传生态购code
+     * @param saleCode
+     * @return
+     */
+    @ResponseBody
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁!")
+    @RequestMapping(value = "/v2/info/code/save", method = RequestMethod.POST)
+    @RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_OPERATE_USER,UserType.USER_ROLE_MERCHANT_OPERATE_CODE, UserType.USER_ROLE_ECOLOGICAL_SHOPPING})
+    @ApiVersion(3.2)
+    public OutDTO saveSaleCodeV2(@Validated(Insert.class) @RequestBody ActSaleCode saleCode) {
+        if (ActConstans.CARTON.equals(saleCode.getBoxType()) && saleCode.getBoxNum() > 1) {
+            return OutDTO.error500("箱数量不能超过1!");
+        }
+        if (!CollectionUtils.isEmpty(suidRich.select(new ActSaleCode(saleCode.getCode()).setStatus(0)))) {
+            return OutDTO.error500("该code已存在!");
+        }
+        //start 2024年11月28日 校验生态购验证码是否存在,且是否有效
+        PyErpRandomCode pyErpRandomCode = pyErpRandomCodeService.checkPyErpRandomCode(saleCode);
+        //end
+        CardGroupOrderInfo orderInfo = checkBindOrder(saleCode,pyErpRandomCode);
+//        CardGroupOrderInfo orderInfo = checkBindOrder(saleCode);
+        int totalCount = getTotalCount(saleCode.getOrderId(), saleCode.getBoxType());
+        int totalNum = totalCount + saleCode.getBoxNum();
+        AppAssert.isTrue(totalNum <= orderInfo.getPurchaseCount(), "超出订单最大数量!");
+        boolean isOver = totalNum == orderInfo.getPurchaseCount();
+        saleCode.setCreateTime(new Date());
+        //设置panini listId ,拼团listId ,setsVersion , 商家id
+        saleCode.setPaniniBaseId(Math.toIntExact(pyErpRandomCode.getPaniniId()));
+        saleCode.setListId(pyErpRandomCode.getListId());
+        saleCode.setSetsVersion(pyErpRandomCode.getSetsVersion());
+        saleCode.setMerchantId(saleCode.getMerchantId());
+        saleCode.setCode(pyErpRandomCode.getRandomCodePri());
+        saleCode.setCodePub(pyErpRandomCode.getRandomCodePub());
+        int insert = suidRich.insert(saleCode);
+        //如果新增成功, 则更新为 已出库 2024年11月28日
+        if(insert > 0){
+            //如果新增成功, 则更新为 已出库
+            pyErpRandomCode.setOrderId(saleCode.getOrderId());
+            pyErpRandomCode.setMerchantId(Long.valueOf(saleCode.getMerchantId()));
+            pyErpRandomCode.setProp2(saleCode.getRemark());
+            pyErpRandomCodeService.updatePyErpRandomCode(pyErpRandomCode);
+        }
+        //end
+        if (isOver) {
+            completeSaleCodeOrder(saleCode);
+        }
+        return OutDTO.ok().put("completed", isOver).put("totalNum", totalNum);
+    }
+
+
+
+    @ResponseBody
+    @RequestMapping(value = "/count/order/code", method = RequestMethod.POST)
+    @RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_OPERATE_USER,UserType.USER_ROLE_MERCHANT_OPERATE_CODE})
+    @ApiVersion(3.2)
+    public OutDTO countOrderSaleCode(@RequestBody ActSaleCode saleCode) {
+        int totalCount = getTotalCount(saleCode.getOrderId(), saleCode.getBoxType());
+        return OutDTO.ok().put("totalNum", totalCount);
+    }
+
+    /**
+     * 添加判断订单是否是同一产品
+     * @param saleCode
+     * @param pyErpRandomCode
+     * @return
+     */
+    private CardGroupOrderInfo checkBindOrder(ActSaleCode saleCode,PyErpRandomCode pyErpRandomCode) {
+        //修改为对象返回 基础库id, 系列版本,2024年11月28日
+        ChecklistConfigDto checklistConfigDto = orderInfoService.getOneOrderSkuUnit(saleCode.getOrderId());
+        //判断是否是同一产品 根据基础库id 和版本
+        AppAssert.isTrue(Objects.equals(pyErpRandomCode.getPaniniId(),checklistConfigDto.getPaniniListId())
+                                 && Objects.equals(pyErpRandomCode.getSetsVersion(),checklistConfigDto.getSetsVersion()), "上传产品和商品产品不一致!");
+        //end
+        CardGroupOrderInfo orderInfo = orderInfoService.selectCardGroupOrderInfoById(saleCode.getOrderId());
+        AppAssert.isTrue(orderInfo.getServeStatus() == 200, "订单未处于待核销状态!");
+        AppAssert.isTrue(saleCode.getBoxNum() <= orderInfo.getPurchaseCount(), "超出订单最大数量!");
+        AppAssert.isTrue(saleCode.getBoxType().equals(GroupActService.getSpecConfigType(checklistConfigDto.getUnit())), "上传规格和商品规格不一致!");
+        return orderInfo;
+    }
+
+    private void completeSaleCodeOrder(ActSaleCode saleCode) {
+        CardGroupOrderInfo order = new CardGroupOrderInfo();
+        order.setId(saleCode.getOrderId());
+        order.setServeStatus(210);
+        orderInfoService.updateCardGroupOrderInfo(order);
+    }
+
+    private int getTotalCount(Long orderId, String boxType) {
+        ActSaleCode cond = new ActSaleCode().setStatus(0).setOrderId(orderId).setBoxType(boxType);
+        String s = suidRich.selectWithFun(cond, FunctionType.SUM, "boxNum");
+        return StringUtils.isEmpty(s) ? 0 : Integer.parseInt(s);
+    }
+
+    @ResponseBody
+    @ApiVersion(3.2)
+    @PostMapping(value = "/v2/verify/info/code")
+    @ApiOperation("新版核销code")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    public OutDTO verifyInfoCodeV2(@Validated @RequestBody CheckSaleCodeDTO checkSaleCode) {
+        UserInfo userInfo = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(userInfo, "权限不足!");
+        checkSaleCode.setMerchantId(userInfo.getMerchantId());
+        //添加验证商家是否已经收货
+        PyErpRandomCodeReq pyErpRandomCode = new PyErpRandomCodeReq();
+        pyErpRandomCode.setCode(checkSaleCode.getCode());
+        PyErpRandomCode erpRandomCode = pyErpRandomCodeService.getPyErpRandomCode(pyErpRandomCode);
+        if(!Objects.equals(erpRandomCode.getStatus(),PyRandomCodeEnums.MER_IN_STOCK.getCode())){
+            return OutDTO.error500("该核销码处于【"+PyRandomCodeEnums.getMsg(erpRandomCode.getStatus())+"】!");
+        }
+        ActSaleCode saleCode = groupActService.checkSaleCode(checkSaleCode.getCode(), checkSaleCode.getMerchantId());
+        GroupSaleCodeDTO saleCodeConfig = groupApiService.checkGroup(checkSaleCode.getGroupInfoId(), saleCode.getSetsVersion());
+        checkSaleCode.setSaleCodeConfig(saleCodeConfig);
+        groupActService.checkUsedGroupSaleCode(checkSaleCode, saleCode);
+        boolean livingOpenAble = groupActService.checkGroupSaleCodeCount(checkSaleCode.getGroupInfoId(), checkSaleCode.getMerchantId(), saleCodeConfig);
+        return OutDTO.ok().put("livingOpenAble", livingOpenAble);
+    }
+
+    /**
+     * 商家签收生态购订单
+     *
+     */
+    @ResponseBody
+    @ApiVersion(1.0)
+    @PostMapping(value = "/merchant/sign/order")
+    @ApiOperation("商家签收生态购订单")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
+    public OutDTO merchantSignOrder(@Validated(Update.class) @RequestBody RandomCodeMerInReq req) {
+        UserInfo userInfo = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(userInfo, "权限不足!");
+        //查询订单信息
+        CardGroupOrderInfo orderInfo = orderInfoService.selectCardGroupOrderInfoById(req.getOrderId());
+        AppAssert.notNull(orderInfo, "订单不存在!");
+        //查询订单所属商家
+        //根据userId 查询商家
+        MerchantInfo merchantInfo = merchantApiService.getMerchantByAppUserId(Math.toIntExact(orderInfo.getUserId()));
+        AppAssert.notNull(merchantInfo, "权限不足!");
+        //判断购买订单商家id 与当前登录商家id 是否一致
+        if(!Objects.equals(userInfo.getMerchantId(),merchantInfo.getId())){
+            throw new ServiceException("权限不足!");
+        }
+        if (!Objects.equals(orderInfo.getStatus() , 106L) && !Objects.equals(orderInfo.getStatus(),104L)) {
+            throw new ServiceException("签收失败,订单当前处于【"+GroupOrderStatusEnums.getMsg(Math.toIntExact(orderInfo.getStatus()))+"】状态!");
+        }
+        //判断生态购code 是否存在
+        PyErpRandomCode pyErpRandomCode = pyErpRandomCodeService.checkPyErpRandomCodeAndMerchant(new ActSaleCode(req.getCode()).setMerchantId(userInfo.getMerchantId()), PyRandomCodeEnums.OUT_STOCK);
+        if (!Objects.equals(pyErpRandomCode.getOrderId() , req.getOrderId())) {
+            throw new ServiceException("订单号与code不匹配!");
+        }
+        //处理签收信息 先更新code 的入库状态
+        int noInNum = pyErpRandomCodeService.merInAndSearchNoInNum(pyErpRandomCode);
+        //查询订单下的code数量
+        if(noInNum == 0){
+            //更新订单状态为 301 订单完成
+            int update = orderInfoService.updateCardGroupOrderInfo(new CardGroupOrderInfo().setStatus(301L).setId(req.getOrderId()));
+            if(update <= 0){
+                throw new ServiceException("订单签收异常!");
+            }
+            //订单完全签收之后赠送生态购积分
+            if (Constants.ORDER_TYPE_SHOP.equals(orderInfo.getOrderType()) && orderInfo.getGiveOrderId() == null) {
+                asyncAppService.addPointByMallOrder(orderInfo);
+                // 商城订单完结
+                Map<String, Object> param = ImmutableMap.of("type", Constants.TYPE_SHOP_POINT, "orderId", orderInfo.getId());
+                MqUtils.sendMq(MqConstans.QUEUE_ORDER_OVER, JSONTools.obj2json(param));
+            }
+        }
+        return OutDTO.ok()
+                     .put("noInNum",noInNum)
+                ;
+
+    }
+
+
+    /**
+     * 商家签收生态购订单
+     *
+     */
+    @ResponseBody
+    @ApiVersion(1.2)
+    @PostMapping(value = "/v1/merchant/sign/order")
+    @ApiOperation("商家签收生态购订单")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    @Transactional(rollbackFor = {ServiceException.class,Exception.class}, isolation = Isolation.READ_COMMITTED)
+    public OutDTO merchantSignOrderV1(@Validated(Insert.class) @RequestBody RandomCodeMerInReq req) {
+        UserInfo userInfo = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(userInfo, "权限不足!");
+        //根据userId 查询商家
+        MerchantInfo merchantInfo = merchantApiService.getMerchantByAppUserId(Math.toIntExact(userInfo.getId()));
+        AppAssert.notNull(merchantInfo, "权限不足!");
+        //判断生态购code 是否存在
+        PyErpRandomCode pyErpRandomCode = pyErpRandomCodeService.checkPyErpRandomCodeAndMerchant(new ActSaleCode(req.getCode()).setMerchantId(userInfo.getMerchantId()), PyRandomCodeEnums.OUT_STOCK);
+        //查询订单信息
+        CardGroupOrderInfo orderInfo = orderInfoService.selectCardGroupOrderInfoById(pyErpRandomCode.getOrderId());
+        AppAssert.notNull(orderInfo, "订单不存在!");
+        if (!Objects.equals(orderInfo.getStatus() , 106L) && !Objects.equals(orderInfo.getStatus(),104L)) {
+            throw new ServiceException("签收失败,订单当前处于【"+GroupOrderStatusEnums.getMsg(Math.toIntExact(orderInfo.getStatus()))+"】状态!");
+        }
+        //处理签收信息 先更新code 的入库状态
+        int noInNum = pyErpRandomCodeService.merInAndSearchNoInNum(pyErpRandomCode);
+        //查询订单下的code数量
+        if(noInNum == 0){
+            //更新订单状态为 301 订单完成
+            int update = orderInfoService.updateCardGroupOrderInfo(new CardGroupOrderInfo().setStatus(301L).setId(pyErpRandomCode.getOrderId()));
+            if(update <= 0){
+                throw new ServiceException("订单签收异常!");
+            }
+            //订单完全签收之后赠送生态购积分
+            if (Constants.ORDER_TYPE_SHOP.equals(orderInfo.getOrderType()) && orderInfo.getGiveOrderId() == null) {
+                asyncAppService.addPointByMallOrder(orderInfo);
+                // 商城订单完结
+                Map<String, Object> param = ImmutableMap.of("type", Constants.TYPE_SHOP_POINT, "orderId", orderInfo.getId());
+                MqUtils.sendMq(MqConstans.QUEUE_ORDER_OVER, JSONTools.obj2json(param));
+            }
+        }
+        return OutDTO.ok()
+                     .put("noInNum",noInNum)
+                ;
+
+    }
+
+}

+ 382 - 0
poyi-app/src/main/java/com/tzy/controller/group/GroupGoodsController.java

@@ -0,0 +1,382 @@
+package com.tzy.controller.group;
+
+import com.github.pagehelper.PageInfo;
+import com.tzy.annotation.ApiLimitRule;
+import com.tzy.annotation.ApiLog;
+import com.tzy.annotation.RequireRoles;
+import com.tzy.app.dto.OpenCardParam;
+import com.tzy.common.annotation.SensitiveData;
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.common.constant.MsgConstants;
+import com.tzy.common.dto.GoodsQuery;
+import com.tzy.common.dto.InDto;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.dto.UserInfo;
+import com.tzy.common.enums.BusinessType;
+import com.tzy.common.exception.AppAssert;
+import com.tzy.common.utils.StringUtils;
+import com.tzy.common.utils.UserType;
+import com.tzy.common.utils.UserUtils;
+import com.tzy.framework.web.domain.LimitRule;
+import com.tzy.pojo.card.CardGroupGoods;
+import com.tzy.pojo.card.CardGroupInfo;
+import com.tzy.sportcard.api.bean.goods.PaniniCheckList;
+import com.tzy.sportcard.api.bean.param.GoodsCheckParam;
+import com.tzy.sportcard.api.bean.param.GroupPublicParam;
+import com.tzy.sportcard.api.bean.param.PublicReportDTO;
+import com.tzy.sportcard.api.domain.AppUserInfoDto;
+import com.tzy.sportcard.api.domain.GoodsSerialDto;
+import com.tzy.sportcard.api.service.*;
+import com.tzy.sportcard.group.domain.AppUserWinCard;
+import com.tzy.sportcard.group.domain.MerchantActGoods;
+import com.tzy.sportcard.group.dto.MerchantCardInfoDTO;
+import com.tzy.sportcard.group.dto.MerchantCardQuery;
+import com.tzy.sportcard.group.dto.OpenCardDTO;
+import com.tzy.sportcard.group.mapper.AppUserWinCardMapper;
+import com.tzy.sportcard.group.service.ICardGroupGoodsService;
+import com.tzy.sportcard.group.service.ICardGroupOrderReviewService;
+import com.tzy.sportcard.group.service.impl.MerchantActGoodsService;
+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.context.annotation.Lazy;
+import org.springframework.web.bind.annotation.*;
+import org.teasoft.bee.osql.Condition;
+import org.teasoft.bee.osql.Op;
+import org.teasoft.bee.osql.SuidRich;
+import org.teasoft.honey.osql.core.ConditionImpl;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author by po'yi
+ * @Classname GroupControllerNew
+ * @Description
+ * @Date 2022/12/15 13:24
+ */
+@Api(value = "卡密相关新接口")
+@RestController
+@RequestMapping("/api/goods")
+@Slf4j
+public class GroupGoodsController {
+    @Autowired
+    @Lazy
+    private GroupApiService groupApiService;
+    @Autowired
+    private ICardGroupOrderReviewService cardGroupOrderReviewService;
+    @Autowired
+    private SuidRich suidRich;
+    @Autowired
+    private ICardGroupGoodsService cardGroupGoodsService;
+    @Resource
+    @Lazy
+    private IAllocateGoodsService allocateGoodsService;
+    @Autowired
+    private MineApiService mineApiService;
+    @Resource
+    private MerchantActGoodsService merchantActGoodsService;
+    @Resource
+    private  IAppUserWinCardService appUserWinCardService;
+    @Resource
+    private  ICardReportService cardReportService;
+    @Resource
+    private AppUserWinCardMapper appUserWinCardMapper;
+
+    /**
+     * 查询组团卡密
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "查询组团卡密", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @ApiVersion(1.0)
+    @PostMapping(value = "/{version}/public/list")
+    public OutDTO getPublicGroupGoods(@RequestBody InDto inDto) {
+        return groupApiService.searchPublicGoods(inDto);
+    }
+
+    /**
+     * 新版公示,兼容新旧版本
+     */
+    @ApiLog(title = "填写公示结果", businessType = BusinessType.INSERT, indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/{version}/merchant/publicity")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_ADMIN})
+    public OutDTO publicityResult(@RequestBody PublicReportDTO param) {
+        if (param==null){
+            return OutDTO.error500("参数不能为空");
+        }
+        GroupPublicParam publicParam = param.getPublicParam();
+        groupApiService.publicityResult(publicParam);
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "卡片审核", businessType = BusinessType.SEARCH)
+    @PostMapping(value = "/{version}/merchant/check/card")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_ADMIN})
+    public OutDTO checkCardOrPass(@RequestBody InDto inDto) {
+        GoodsCheckParam checkParam = inDto.buildParam(new GoodsCheckParam());
+        if (checkParam.getGroupInfoId() == null || checkParam.getReviewStatus() == null) {
+            return OutDTO.error(10090, "参数错误!");
+        }
+        if (StringUtils.isEmpty( checkParam.getIds()) &&  checkParam.getReviewStatus() == 3) {
+            return OutDTO.error(10090, "请选中条目驳回!");
+        }
+        Long infoStatus=cardGroupOrderReviewService.checkGoods(checkParam);
+        return OutDTO.ok().put("infoStatus", infoStatus);
+    }
+
+    @ApiLog(title = "清除新版卡密公示信息", businessType = BusinessType.SEARCH)
+    @PostMapping(value = "/{version}/merchant/publicity/del")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_ADMIN})
+    @ApiOperation("清除新版卡密公示信息,参数id(卡密id),goodsType")
+    public OutDTO delGoodsPublicity(@RequestBody InDto inDto) {
+        groupApiService.delGoodsPublicity(Long.valueOf(inDto.getString("id")),Integer.valueOf(inDto.getString("goodsType")));
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "删除卡密子条目", businessType = BusinessType.SEARCH)
+    @PostMapping(value = "/{version}/merchant/publicity/del/sub")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_ADMIN})
+    @ApiOperation("删除卡密子条目,参数id(卡密id),goodsType,paniniListId")
+    public OutDTO delSubGoodsPublicity(@RequestBody InDto inDto) {
+        groupApiService.delSubGoodsPublicity(Long.valueOf(inDto.getString("id")),Integer.valueOf(inDto.getString("goodsType")),
+                Long.valueOf(inDto.getString("paniniListId")));
+        return OutDTO.ok();
+    }
+
+    /**
+     * 球队,球队帅选条件
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "球队,球队帅选条件", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/selected/param/type")
+    public OutDTO searchParamByType(@RequestBody InDto inDto) {
+        Integer paniniListId = (Integer) inDto.get("paniniListId");
+        if(paniniListId==null){
+            return OutDTO.error500("参数为空!");
+        }
+        String title = inDto.getString("title");
+        if(StringUtils.isEmpty(title)){
+            return OutDTO.error500("参数为空!");
+        }
+        String team = inDto.getString("team");
+        String playerName = inDto.getString("playerName");
+        if(StringUtils.isEmpty(team)&&StringUtils.isEmpty(playerName)){
+            return OutDTO.error500("参数为空!");
+        }
+        return groupApiService.searchParamByType(title,paniniListId,team,playerName);
+    }
+
+    @ApiLog(title = "修改拆卡报告图片", businessType = BusinessType.UPDATE)
+    @PostMapping(value = "/{version}/change/publicity/image")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_ADMIN})
+    @ApiOperation("修改拆卡报告图片,参数:groupInfoId,reportFlag(1:新,0:,旧)")
+    @ApiVersion(1.0)
+    public OutDTO changePublicityImage(@RequestBody InDto inDto) {
+        Long groupInfoId = Long.valueOf(inDto.getString("groupInfoId"));
+        Long cardGoodsId = Long.valueOf(inDto.getString("cardGoodsId"));
+        String img = inDto.getString("imageStr");
+
+        CardGroupGoods goods = new CardGroupGoods();
+        goods.setGroupInfoId(groupInfoId);
+        goods.setId(cardGoodsId);
+        goods.setImg(img);
+        suidRich.update(goods);
+        AppUserWinCard appUserWinCard = new AppUserWinCard();
+        List<Integer> ids = new ArrayList<>();
+        ids.add(cardGoodsId.intValue());
+        List<Long> cardids = appUserWinCardMapper.selectUserWindCardByGoodsId(ids);
+        if(cardids!=null&&cardids.size()>0){
+            appUserWinCard.setId(cardids.get(0));
+        }
+        appUserWinCard.setRefInfoId(groupInfoId);
+        appUserWinCard.setGroupGoodsId(cardGoodsId);
+        appUserWinCard.setImgUrl(img);
+        appUserWinCardService.updateAppUserWinCard(appUserWinCard);
+        List<Long> idList=new ArrayList<>();
+        idList.add(cardGoodsId);
+        cardReportService.syncCardWithGoodsId(idList);
+        return OutDTO.ok();
+    }
+
+
+    @ApiLog(title = "切换拆卡报告版本", businessType = BusinessType.SEARCH)
+    @PostMapping(value = "/{version}/change/publicity/type")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_ADMIN})
+    @ApiOperation("切换拆卡报告版本,参数:groupInfoId,reportFlag(1:新,0:,旧)")
+    @ApiVersion(1.0)
+    public OutDTO changePublicityType(@RequestBody InDto inDto) {
+        Integer reportFlag=Integer.valueOf(inDto.getString("reportFlag"));
+        Long groupInfoId=Long.valueOf(inDto.getString("groupInfoId"));
+        CardGroupInfo groupInfo = new CardGroupInfo();
+        groupInfo.setId(groupInfoId);
+        CardGroupInfo cardGroupInfo = suidRich.selectOne(groupInfo);
+        if(cardGroupInfo==null||cardGroupInfo.getStatus()!=205){
+            return  OutDTO.error500("待公示的组队不存在");
+        }
+
+        if(cardGroupInfo.getPaniniListId()==null&&reportFlag==1){
+            return  OutDTO.error500("此组队不支持新版公示报告");
+        }
+        Integer[] statusArr=new Integer[]{100,3,2,1};
+        CardGroupGoods goods = new CardGroupGoods();
+        goods.setGroupInfoId(groupInfoId);
+        Condition beeCondition = new ConditionImpl();
+        beeCondition.op("status", Op.in,statusArr);
+        beeCondition.start(0).size(1);
+        List<CardGroupGoods> existGoods = suidRich.select(goods, beeCondition);
+        if(!existGoods.isEmpty()){
+            return  OutDTO.error500("此组队已存在公示信息,暂不支持切换!");
+        }
+        groupInfo.setReportFlag(reportFlag);
+        suidRich.update(groupInfo);
+        return OutDTO.ok().put("reportFlag",reportFlag);
+    }
+
+    @ApiLog(title = "根据条件查询卡密信息", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @ApiVersion(1.0)
+    @RequestMapping(value = "/{version}/team/id", method = RequestMethod.POST)
+    public OutDTO getGroupGoods(@RequestBody InDto inDto) {
+        String team = inDto.getString("team");
+        Integer groupInfoId = (Integer) inDto.get("groupInfoId");
+        String idxStr = inDto.getString("idx");
+        if (StringUtils.isEmpty(team) && StringUtils.isEmpty(idxStr) && groupInfoId == null) {
+            return OutDTO.error500("参数为空");
+        }
+        CardGroupInfo cardGroupInfo = getCardGroupInfo(groupInfoId);
+        if(cardGroupInfo==null){
+            return OutDTO.error500("组队不存在");
+        }
+        boolean isNewGoods = cardGroupInfo.getGoodsType() == 1;
+        GoodsQuery query = new GoodsQuery().setGroupInfoId(cardGroupInfo.getId()).setTeam(team).setIdStr(idxStr);
+        List<GoodsSerialDto> goods = cardGroupGoodsService.selectGoods(isNewGoods, query);
+        return OutDTO.ok().put("goods", goods);
+    }
+
+    private CardGroupInfo getCardGroupInfo(Integer groupInfoId) {
+        CardGroupInfo info = new CardGroupInfo();
+        info.setId(groupInfoId.longValue());
+        CardGroupInfo cardGroupInfo = suidRich.selectOne(info);
+        return cardGroupInfo;
+    }
+
+    @ApiLog(title = "预售订单获取卡密", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ApiOperation("预售订单获取卡密,参数:OpenCardParam")
+    @ResponseBody
+    @ApiVersion(1.0)
+    @ApiLimitRule(seconds = 2,limitCount=20,type= LimitRule.ACT,msg="抱歉,开卡人数太多,请稍后再试!")
+    @PostMapping("/{version}/order/open")
+    public OutDTO openGoodsByOrder(@RequestBody InDto inDto) {
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        OpenCardParam param = inDto.buildParam(new OpenCardParam());
+        if(param.getNum()==null||param.getNum()<1||param.getOrderId()==null){
+            return OutDTO.error500("参数不符合要求");
+        }
+        param.setUser(user);
+        OpenCardDTO openCardDTO = allocateGoodsService.allocateUserGoodsByOrder(param);
+        return OutDTO.ok().put("openCardDTO",openCardDTO);
+    }
+
+    @ApiLog(title = "查询panini卡密", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ApiOperation("查询panini卡密,参数:GoodsQuery")
+    @ResponseBody
+    @ApiVersion(2.0)
+    @PostMapping("/{version}/panini/list")
+    public OutDTO getMineGoodsByCond(@RequestBody InDto inDto) {
+        GoodsQuery query = inDto.buildParam(new GoodsQuery());
+        query.setPageNo(inDto.getPageNo()).setPageSize(inDto.getPageSize());
+        List<PaniniCheckList> goods = groupApiService.selectPaniniList(query);
+        return OutDTO.ok().put("goods",goods);
+    }
+
+    @ApiLog(title = "商家好卡查询", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ApiOperation("商家好卡查询")
+    @ResponseBody
+    @ApiVersion(2.0)
+    @SensitiveData
+    @PostMapping("/{version}/top")
+    public OutDTO getMerchantTopCard(@RequestBody InDto inDto) {
+        MerchantCardQuery cardQuery = inDto.buildParam(new MerchantCardQuery());
+        if (cardQuery.getMerchantId() == null && cardQuery.getPaniniListId() == null) {
+            return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+        }
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if (user == null && cardQuery.getPaniniListId() == null) {
+            return OutDTO.error500(MsgConstants.NEED_LOGIN);
+        }
+        boolean isMerchantOwner=false;
+        if (user != null) {
+            cardQuery.setUserId(user.getId());
+            isMerchantOwner = Objects.equals(user.getMerchantId(), cardQuery.getMerchantId());
+            if (!isMerchantOwner && cardQuery.getStatus() == null) {
+                cardQuery.setStatus(1);
+            }
+        }
+        if (cardQuery.getPaniniListId() != null) {
+            cardQuery.setStatus(1);
+        }
+        cardQuery.setPageNo(inDto.getPageNo());
+        cardQuery.setPageSize(inDto.getPageSize());
+        PageInfo<MerchantCardInfoDTO> cards = merchantActGoodsService.getMerchantTopCards(cardQuery);
+        if (!isMerchantOwner && cardQuery.getMerchantId() != null && Objects.equals(cardQuery.getStatus(), 1)) {
+            cards.setTotal(Math.min(cards.getTotal(), 100));
+        }
+        return OutDTO.ok().put("cards", cards);
+    }
+
+    @ApiLog(title = "商家编辑好卡展示和排序", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ApiOperation("商家编辑好卡展示和排序")
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作太频繁,请稍后再试!")
+    @ResponseBody
+    @ApiVersion(2.0)
+    @SensitiveData
+    @PostMapping("/{version}/top/edit")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    public OutDTO editCardShow(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(user, MsgConstants.NEED_LOGIN);
+        Integer id = inDto.getIntegerParam("id");
+        Integer sortValue = inDto.getIntegerParam("sortValue");
+        Integer status = inDto.getIntegerParam("status");
+        if (id == null || (status == null && sortValue == null)) {
+            return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+        }
+        MerchantActGoods editGoods = new MerchantActGoods().setId(id.longValue()).setMerchantId(user.getMerchantId()).setSortValue(sortValue).setStatus(status);
+        merchantActGoodsService.updateMerchantActGoods(editGoods);
+        return OutDTO.ok();
+    }
+
+
+    @ApiLog(title = "商家选择或者取消好卡", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ApiOperation("商家选择或者取消好卡")
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作太频繁,请稍后再试!")
+    @ResponseBody
+    @ApiVersion(2.0)
+    @SensitiveData
+    @PostMapping("/{version}/top/show")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    public OutDTO editGoodsTopShow(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(user, MsgConstants.NEED_LOGIN);
+        Integer id = inDto.getIntegerParam("id");
+        Integer topSort = inDto.getIntegerParam("topSort");
+        if (id == null || topSort == null) {
+            return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+        }
+        Long infoId = cardGroupGoodsService.editGoodsTopShow(id, topSort, user.getMerchantId());
+        if (infoId != null) {
+            merchantActGoodsService.syncTopGoodsRecord(infoId);
+        }
+        return OutDTO.ok();
+    }
+}

+ 514 - 0
poyi-app/src/main/java/com/tzy/controller/group/GroupLocalController.java

@@ -0,0 +1,514 @@
+package com.tzy.controller.group;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.github.pagehelper.PageInfo;
+import com.google.common.collect.Lists;
+import com.tzy.annotation.ApiLog;
+import com.tzy.app.domain.AppBaseUser;
+import com.tzy.app.domain.AppUserDetailInfo;
+import com.tzy.app.domain.order.OrderListDTO;
+import com.tzy.app.dto.mq.GoodsListDTO;
+import com.tzy.app.service.AppUserDetailInfoService;
+import com.tzy.app.service.IAppBaseUserService;
+import com.tzy.common.constant.Constants;
+import com.tzy.common.constant.MsgConstants;
+import com.tzy.common.constant.NoticeMsgModel;
+import com.tzy.common.core.domain.AjaxResult;
+import com.tzy.common.dto.InDto;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.dto.UserInfo;
+import com.tzy.common.dto.order.OrderStatusDTO;
+import com.tzy.common.enums.BusinessType;
+import com.tzy.common.exception.AppAssert;
+import com.tzy.common.exception.ServiceException;
+import com.tzy.common.utils.DateUtils;
+import com.tzy.common.utils.ServletUtils;
+import com.tzy.common.utils.UserUtils;
+import com.tzy.dto.AuctionJPushDTO;
+import com.tzy.dto.local.*;
+import com.tzy.framework.util.RedisUtils;
+import com.tzy.member.benefits.dto.OrderSubmitDTO;
+import com.tzy.pojo.card.CardGroupOrderInfo;
+import com.tzy.pojo.item.Sku;
+import com.tzy.service.SkuService;
+import com.tzy.sportcard.api.bean.act.AppActPrize;
+import com.tzy.sportcard.api.domain.AppUserInfoDto;
+import com.tzy.sportcard.api.domain.GroupInfo;
+import com.tzy.sportcard.api.domain.MerchantInfo;
+import com.tzy.sportcard.api.dto.AuctionOrderDTO;
+import com.tzy.sportcard.api.dto.LiveDTO;
+import com.tzy.sportcard.api.dto.ResourceData;
+import com.tzy.sportcard.api.dto.group.GroupStatusInfoDto;
+import com.tzy.sportcard.api.dto.group.ProductPromGroupInfoDto;
+import com.tzy.sportcard.api.dto.merchant.MerchantScoreDTO;
+import com.tzy.sportcard.api.dto.prize.PublicCodeParam;
+import com.tzy.sportcard.api.dto.prize.PublicCodeResultDTO;
+import com.tzy.sportcard.api.service.*;
+import com.tzy.sportcard.group.domain.CardGroupLivesConfig;
+import com.tzy.sportcard.group.dto.MerchantAvatarsDTO;
+import com.tzy.sportcard.group.dto.OrderCallBackDTO;
+import com.tzy.sportcard.group.mapper.CardGroupLivesConfigMapper;
+import com.tzy.sportcard.group.service.AppActService;
+import com.tzy.sportcard.group.service.ICardGroupInfoService;
+import com.tzy.sportcard.group.service.ICardGroupOrderInfoService;
+import com.tzy.sportcard.group.service.ITzyMerchantInfoService;
+import com.tzy.system.domain.TzyShippingAddress;
+import com.tzy.system.domain.TzySysNoticeRecord;
+import com.tzy.system.mapper.TzyShippingAddressMapper;
+import com.tzy.system.service.ITzySysNoticeRecordService;
+import com.tzy.util.NoticeType;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.elasticsearch.common.Strings;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.DigestUtils;
+import org.springframework.web.bind.annotation.*;
+import org.teasoft.bee.osql.SuidRich;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author by po'yi
+ * @Classname GroupControllerNew
+ * @Description
+ * @Date 2022/11/24 13:24
+ */
+@Api(value = "内网访问组团新接口")
+@RestController
+@RequestMapping("/api/local")
+@Slf4j
+public class GroupLocalController {
+
+    @Autowired
+    private SuidRich suidRich;
+    @Resource
+    private IAllocateGoodsService allocateGoodsService;
+    @Autowired
+    private AppActService appActService;
+    @Autowired
+    private AsyncAppService asyncAppService;
+    @Autowired
+    private RedisUtils redisUtils;
+    @Resource
+    private MineApiService mineApiService;
+    @Resource
+    private AuctionOrderService auctionOrderService;
+    @Resource
+    private ITzySysNoticeRecordService noticeRecordService;
+    @Resource
+    private IAppBaseUserService appBaseUserService;
+    @Resource
+    private CardGroupLivesConfigMapper cardGroupLivesConfigMapper;
+    @Autowired
+    private GroupApiService groupApiService;
+    @Autowired
+    private SkuService skuService;
+    @Autowired
+    private TzyShippingAddressMapper tzyShippingAddressMapper;
+    @Resource
+    private ICardGroupOrderInfoService cardGroupOrderInfoService;
+    @Resource
+    private ITzyMerchantInfoService tzyMerchantInfoService;
+    @Autowired
+    private MerchantApiService merchantApiService;
+    @Resource
+    private ICardGroupInfoService cardGroupInfoService;
+    @Resource
+    private AppUserDetailInfoService appUserDetailInfoService;
+
+    @PostMapping("/free/mallOrder/{orderId}")
+    public ResultDTO freeMallOrder(@PathVariable Long orderId) {
+        com.tzy.sportcard.group.domain.CardGroupOrderInfo cardGroupOrderInfo = cardGroupOrderInfoService.selectCardGroupOrderInfoById(orderId);
+        String orderNo = cardGroupOrderInfo.getOrderNo();
+        log.info("商城免单:{}", orderNo);
+        ResourceData resourceData = freePayBuild(orderNo, "商城免单");
+        if(cardGroupOrderInfo.getActualPayment().compareTo(BigDecimal.ZERO) <= 0
+                && cardGroupOrderInfo.getPoint() == 0
+                && cardGroupOrderInfo.getGiveOrderId() == null
+        ){
+            return groupApiService.mallOrderCallBack(resourceData, cardGroupOrderInfo)
+                    ? ResultDTO.buildEmptySuccess()
+                    : ResultDTO.buildErrorResult();
+        }
+        return ResultDTO.buildErrorResult();
+
+    }
+
+    private ResourceData freePayBuild(String orderNo, String payType) {
+        ResourceData resourceData = new ResourceData();
+        ResourceData.PayAmount payAmount = new ResourceData.PayAmount();
+        payAmount.setTotal(0);
+        payAmount.setPayer_total(0);
+        resourceData.setAmount(payAmount);
+        resourceData.setTrade_type(payType);
+        resourceData.setSubPaymentType(payType);
+        resourceData.setBank_type(payType);
+        resourceData.setOut_trade_no(orderNo);
+        resourceData.setTransaction_id(String.valueOf(System.currentTimeMillis()));
+        resourceData.setSuccess_time(DateUtils.dateTime(new Date()));
+        resourceData.setTrade_state("TRADE_SUCCESS");
+        resourceData.setTrade_state_desc("TRADE_SUCCESS");
+        return resourceData;
+    }
+
+    @PostMapping("/get/address/{userId}")
+    public ResultDTO address(@PathVariable Long userId) {
+        List<TzyShippingAddress> list = tzyShippingAddressMapper.findFirstAddressByUserId(userId);
+        return ResultDTO.buildSuccessResult(AddressDTO.builder().address(!CollectionUtils.isEmpty(list)).build());
+    }
+
+    @PostMapping("/get/explain/{liveId}")
+    public ResultDTO getLivingExplain(@PathVariable Long liveId) {
+        LivingExplainDTO livingExplainDTO =
+                suidRich.selectOne(LivingExplainDTO.builder().liveId(liveId).status(1).build());
+        return ResultDTO.buildSuccessResult(livingExplainDTO);
+    }
+
+    @PostMapping("/close/explain/{liveId}")
+    public ResultDTO closeLivingExplain(@PathVariable Long liveId) {
+        LivingExplainDTO livingExplainDTO =
+                suidRich.selectOne(LivingExplainDTO.builder().liveId(liveId).status(1).build());
+        if (Objects.nonNull(livingExplainDTO)) {
+            suidRich.update(LivingExplainDTO.builder().id(livingExplainDTO.getId()).status(2).build());
+        }
+        return ResultDTO.buildEmptySuccess();
+    }
+
+    @PostMapping("/get/sku/{skuId}")
+    public ResultDTO getSku(@PathVariable Integer skuId) {
+        Sku sku = skuService.selectSkuByIdAndStatus(skuId, 101L);
+        return ResultDTO.buildSuccessResult(sku);
+    }
+
+    @PostMapping("/get/live/{liveId}")
+    public ResultDTO findLive(@PathVariable Long liveId) {
+        CardGroupLivesConfig config = cardGroupLivesConfigMapper.selectCardGroupLivesConfigById(liveId);
+        return ResultDTO.buildSuccessResult(config);
+    }
+
+    @PostMapping("/get/live/list")
+    public ResultDTO findLive(@RequestBody LiveDTO liveDTO) {
+        List<CardGroupLivesConfig> list = Lists.newArrayList();
+        for (Long liveId : liveDTO.getIds()) {
+            CardGroupLivesConfig config = cardGroupLivesConfigMapper.selectCardGroupLivesConfigById(liveId);
+            if (Objects.nonNull(config)) {
+                if (!Objects.equals(config.getStatus(), 0L) && !Objects.equals(config.getStatus(), 1L)) {
+                    list.add(config);
+                }
+            }
+        }
+        return ResultDTO.buildSuccessResult(list);
+    }
+
+    @ApiOperation("竞价订单回调")
+    @PostMapping("/order/callback")
+    public ResultDTO orderCallBack(@RequestBody AuctionOrderDTO auctionOrderDTO){
+        List<OrderCallBackDTO> result = auctionOrderService.orderCallBack(auctionOrderDTO.getOrderIds());
+        return ResultDTO.buildSuccessResult(result);
+    }
+
+    @ApiOperation("竞价发放奖品优惠券")
+    @PostMapping("/send/coupon")
+    public ResultDTO sendCoupon(@RequestBody AuctionOrderDTO auctionOrderDTO){
+        auctionOrderService.sendCoupon(auctionOrderDTO);
+        return ResultDTO.buildEmptySuccess();
+    }
+
+    @ApiOperation("发送站内信")
+    @PostMapping("/send/notice")
+    public ResultDTO sendNotice(@RequestBody TzySysNoticeRecord noticeRecord){
+        noticeRecord.setFromUser("HOBBY STOCKS");
+        noticeRecord.setType(NoticeType.ACT);
+        int rs = noticeRecordService.insertTzySysNoticeRecord(noticeRecord);
+        if(rs == 0){
+            return ResultDTO.build500Error("竞价发送站内信失败:" + noticeRecord.getToUserid());
+        }
+        return ResultDTO.buildEmptySuccess();
+    }
+
+    @ApiOperation("发送极光推送")
+    @PostMapping("/send/jPush")
+    public ResultDTO jPush(@RequestBody AuctionJPushDTO auctionJPushDTO) {
+        List<String> smsRegisterList = mineApiService.searchUserInfoByIds(auctionJPushDTO.getUserIds()).stream()
+                .filter(appUserInfoDto -> Objects.nonNull(appUserInfoDto) && !StringUtils.isEmpty(appUserInfoDto.getSmsRegisterId()))
+                .map(AppUserInfoDto::getSmsRegisterId)
+                .distinct()
+                .collect(Collectors.toList());
+        Map<String, String> extrasMap = new HashMap<>();
+        extrasMap.put("url", auctionJPushDTO.getUrl());
+        asyncAppService.jpush(19, Constants.JPUSH_TYPE_ID, smsRegisterList, auctionJPushDTO.getParams(), extrasMap);
+        return ResultDTO.buildEmptySuccess();
+    }
+
+    @ApiOperation("竞价积分变更")
+    @PostMapping("/change/point")
+    public ResultDTO changePoint(@RequestBody UserPointDTO userPointDTO){
+        if (userPointDTO == null || userPointDTO.getPointRecords() == null) {
+            return ResultDTO.build500Error("参数为空");
+        }
+
+        userPointDTO.getPointRecords().forEach(record ->{
+            Long point = record.getChangePoint();
+            if(point < 0){
+                AppBaseUser appBaseUser = appBaseUserService.selectAppBaseUserById(userPointDTO.getUserId().longValue());
+                if(appBaseUser == null) {
+                    throw new ServiceException("用户不存在");
+                }
+                // 负数,检查积分是否足够
+                long pointsToDeduct = Math.abs(point); // 获取要扣除的积分值
+                if(appBaseUser.getPoint() < pointsToDeduct){
+                    throw new ServiceException("积分不足");
+                }
+            }
+
+            record.setType(Constants.POINT_TYPE_COMMON)
+                    .setChangePoint(record.getChangePoint())
+                    .setUserId(userPointDTO.getUserId().longValue())
+                    .setOrderId(record.getOrderId())
+                    .setOrderNo("抢拍活动")
+                    .setRefId(record.getRefId())
+                    .setCreateTime(new Date());
+        });
+        mineApiService.addPointsOfUser(userPointDTO.getUserId(), userPointDTO.getPointRecords());
+        return ResultDTO.buildEmptySuccess();
+    }
+
+    @ApiOperation("竞价下单")
+    @PostMapping("/order/submit")
+    public ResultDTO orderSubmit(@RequestBody AuctionOrderDTO auctionOrderDTO){
+        OrderSubmitDTO orderSubmitDTO = auctionOrderService.generateOrder(auctionOrderDTO);
+        return ResultDTO.buildSuccessResult(orderSubmitDTO);
+    }
+
+    @ResponseBody
+    @GetMapping(value = "/group/info/{id}")
+    //@ApiVersion(1.0)
+    @ApiOperation("获取组队信息")
+    public CardGroupInfoDTO getGroupInfo(@PathVariable("id") Long id) {
+        CardGroupInfoDTO info=new CardGroupInfoDTO();
+        info.setId(id);
+        return suidRich.selectOne(info);
+    }
+
+    @ResponseBody
+    @GetMapping(value = "/order/detail/{id}")
+    //@ApiVersion(1.0)
+    @ApiOperation("获取组队信息")
+    public OrderDTO getOrderDetail(@PathVariable("id") Long id) {
+        OrderDTO order=new OrderDTO();
+        order.setId(id);
+        order=suidRich.selectOne(order);
+        OrderListDTO condition=new OrderListDTO();
+        condition.setOrderId(id);
+        List<OrderListDTO> orderLists = suidRich.select(condition);
+        if(!orderLists.isEmpty()){
+            List<GoodsListDTO> list = orderLists.stream().filter(ol -> ol.getStatus()==100||ol.getStatus()==101)
+                    .map(ol -> new GoodsListDTO(ol.getQty(), ol.getSkuId(), ol.getSkuName())).collect(Collectors.toList());
+            order.setGoodsListDTOS(list);
+        }
+        return order;
+    }
+
+    @ResponseBody
+    //@PostMapping(value = "/order/allocate/callback")
+    //@ApiVersion(1.0)
+    @ApiOperation("卡密分配后回调")
+    public ResultDTO orderAllocateCallBack(@RequestBody AllocateResult result) {
+        if(result.getOrderId()==null){
+            return ResultDTO.buildErrorResult("参数缺失");
+        }
+        CardGroupOrderInfo order = new CardGroupOrderInfo();
+        order.setId(result.getOrderId());
+        CardGroupOrderInfo existOrder = suidRich.selectOne(order);
+        if(existOrder == null){
+            return ResultDTO.buildErrorResult("订单不存在");
+        }
+        order.setGoodsAllocate(1);
+        order.setProp2(result.getGuessCount()>0?result.getGuessCount().toString():"0");
+        order.setProp3(result.getMissCardCount()>0?result.getMissCardCount().toString():"0");
+        order.setUpdateTime(DateUtils.getTimestampNow());
+        suidRich.update(order);
+        allocateGoodsService.aftAllocateOrderGoods(existOrder.getGroupInfoId());
+        return ResultDTO.buildEmptySuccess();
+    }
+
+    @ResponseBody
+    @GetMapping(value = "/public/{actId}")
+    @ApiOperation("公布抽奖码")
+    public ResultDTO publicActCode(@PathVariable("actId") Integer actId, @RequestParam String code) {
+        String key="app_lucky_public_code_"+actId;
+        if(redisUtils.hasKey(key)){
+            return ResultDTO.buildErrorResult("短时间内请勿重复请求!");
+        }
+        log.info("接收到抽奖结果公布回调:活动id:{},code:{}",actId,code);
+        redisUtils.set(key,1,60);
+        List<PublicCodeResultDTO> resultDTOs = appActService.publicActCode(new PublicCodeParam(actId, code, null));
+        for (PublicCodeResultDTO resultDTO : resultDTOs) {
+            appActService.sendWinCodesPrize(resultDTO.getWinCodes(),resultDTO.getPrize());
+            String failMsg=String.format(NoticeMsgModel.LUCKY_ACT_FAIL_NOTICE, resultDTO.getPrize().getName());
+            //禁用发放默认奖品功能
+//            if(StringUtils.isNotEmpty(resultDTO.getDefaultPrizeConfig())){
+//                JSONObject prizeJson = JSON.parseObject(resultDTO.getDefaultPrizeConfig());
+//                failMsg=String.format(NoticeMsgModel.LUCKY_ACT_DEFAULT_PRIZE_NOTICE, resultDTO.getPrize().getName(),prizeJson.getString("name"));
+//                Integer prizeId = prizeJson.getInteger("prizeId");
+//                appActService.sendActDefaultCoupon(actId,prizeId);
+//            }
+            asyncAppService.noticeActUser(actId,2,failMsg, "活动揭晓记录",resultDTO.getActType());
+        }
+
+        redisUtils.del(key);
+        return ResultDTO.buildEmptySuccess();
+    }
+
+
+    @ApiLog(title = "重新申请抽奖码", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/luck/code/repeat/{userId}/{prizeRecordId}")
+    //@ApiVersion(1.0)
+    @ApiOperation("重新申请抽奖码")
+    public OutDTO repeat(@PathVariable("userId") Integer userId,@PathVariable("prizeRecordId") Integer prizeRecordId) {
+        if (prizeRecordId == null || userId == null) {
+            return OutDTO.error500("参数未传!");
+        }
+        appActService.checkLuckyCode(prizeRecordId, userId);
+        return OutDTO.ok();
+    }
+
+    @ResponseBody
+    @GetMapping(value = "/group/living/check/{id}")
+    @ApiOperation("拼团是否允许直播")
+    public ResultDTO allowedStartGroupLive(@PathVariable("id") Integer groupInfoId) {
+        GroupInfo groupInfo = groupApiService.getGroupInfoById(groupInfoId);
+        AppAssert.notNull(groupInfo, "拼团不存在!");
+        return ResultDTO.buildSuccessResult(groupApiService.allowedStartGroupLive(groupInfo));
+    }
+
+    @PostMapping("/merchant/avatars")
+    @ApiOperation("官网商家头像")
+    public ResultDTO getMerchantAvatars(@RequestBody MerchantAvatarsDTO merchantAvatars){
+        PageInfo<String> avatars = tzyMerchantInfoService.getAvatars(merchantAvatars);
+        return ResultDTO.buildSuccessResult(avatars);
+    }
+
+//    /**
+//     * 根据id集合查询拼团信息
+//     */
+//    @ResponseBody
+//    @GetMapping(value = "/groupInfoByIds")
+//    @ApiOperation("根据id集合查询拼团信息")
+//    public ResultDTO getGroupInfoByIds(@RequestParam("ids") String ids) {
+//        List<Integer> groupInfoIds = Arrays.stream(ids.split(",")).map(Integer::parseInt).collect(Collectors.toList());
+//        List<ProductPromGroupInfoDto> groupInfos = groupApiService.getGroupInfosByIds(groupInfoIds);
+//        return ResultDTO.buildSuccessResult(groupInfos);
+//    }
+
+
+    /**
+     * 获取店铺基本信息
+     *
+     * @return
+     */
+    @ApiLog(title = "根据id获取店铺基本信息", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @RequestMapping(value = "/getMerchantInfoByID", method = RequestMethod.POST)
+    public OutDTO getMerchantBasicInfoByID(@RequestBody InDto inDto) {
+        if (null == inDto) {
+            return OutDTO.error(10000, "参数不能为空");
+        }
+        Object idObj = inDto.get("id");
+        if (null == idObj) {
+            return OutDTO.error(10010, "参数[id]不能为空");
+        }
+        int targetMerId = Integer.parseInt(idObj.toString());
+        //查询商家信息
+        MerchantInfo merchantInfo = merchantApiService.getMerchantInfo(targetMerId);
+        if (null == merchantInfo) {
+            return OutDTO.error500("商家不存在");
+        }
+        return OutDTO.ok()
+                .put("merchantInfo", merchantInfo);
+    }
+
+    /**
+     * 根据id集合查询拼团状态信息
+     */
+    @ResponseBody
+    @PostMapping(value = "/groupInfoStatus")
+    @ApiOperation("根据id集合查询拼团信息")
+    public ResultDTO getGroupInfoStatus(@RequestBody List<Integer> editGroupIds) {
+        if (editGroupIds == null || editGroupIds.isEmpty()) {
+            return ResultDTO.buildErrorResult("参数为空!");
+        }
+        if (editGroupIds.size()>30) {
+            return ResultDTO.buildErrorResult("最多只能查询30条!");
+        }
+        List<GroupStatusInfoDto> groupInfos = groupApiService.getGroupStatusByIds(editGroupIds);
+        return ResultDTO.buildSuccessResult(groupInfos);
+    }
+
+    /**
+     * 统计打款信息
+     */
+    @ResponseBody
+    @PostMapping(value = "/generateGroupPaymentRecord")
+    @ApiOperation("统计打款信息")
+    public ResultDTO generateGroupClosePaymentRecord(@RequestBody Integer groupIds) {
+        if (groupIds == null) {
+            return ResultDTO.buildErrorResult("参数为空!");
+        }
+        cardGroupInfoService.checkAllActClosePaymentInfosWithoutChannel(groupIds);
+        return ResultDTO.buildSuccessResult("success");
+    }
+
+    /**
+     * 根据id集合查询拼团状态信息
+     */
+    @ResponseBody
+    @PostMapping(value = "/orderInfoStatus")
+    @ApiOperation("根据id集合查询拼团信息")
+    public ResultDTO getGroupOrderInfoStatus(@RequestBody List<Long> orderIds) {
+        if (orderIds == null || orderIds.isEmpty()) {
+            return ResultDTO.buildErrorResult("参数为空!");
+        }
+        if (orderIds.size()>30) {
+            return ResultDTO.buildErrorResult("最多只能查询30条!");
+        }
+        List<OrderStatusDTO> groupInfos = cardGroupOrderInfoService.getOrderInfoStatus(orderIds);
+        return ResultDTO.buildSuccessResult(groupInfos);
+    }
+    @ApiLog(title = "更新个人资料",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/user/inviteCode")
+    public ResultDTO getInviteCode(@RequestBody List<Long> userIds) {
+        if (userIds == null || userIds.isEmpty()) {
+            return ResultDTO.buildErrorResult("参数为空!");
+        }
+        if (userIds.size()>100) {
+            return ResultDTO.buildErrorResult("最多只能查询100条!");
+        }
+        //循环用户信息
+        for (Long userId : userIds) {
+            appUserDetailInfoService.getByUserId(userId.intValue());
+        }
+        return ResultDTO.buildSuccessResult(userIds.size());
+    }
+    @ResponseBody
+    @GetMapping("/guess/prize/{teamId}")
+    @ApiOperation("竞猜活动中奖用户自动参与区块链")
+    public ResultDTO guessPrize(@PathVariable("teamId")Long teamId){
+        try {
+            appActService.guessSendPrize(teamId);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return ResultDTO.build500Error(e.getLocalizedMessage());
+        }
+        return ResultDTO.buildEmptySuccess();
+    }
+}

+ 135 - 0
poyi-app/src/main/java/com/tzy/controller/group/ListCalendarController.java

@@ -0,0 +1,135 @@
+package com.tzy.controller.group;
+
+
+import com.github.pagehelper.PageInfo;
+import com.tzy.annotation.ApiLog;
+import com.tzy.common.base.AppBaseController;
+import com.tzy.common.dto.GoodsQuery;
+import com.tzy.common.dto.InDto;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.enums.BusinessType;
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.common.utils.bean.DozerUtils;
+import com.tzy.dto.SpuDTO;
+import com.tzy.pojo.item.Spu;
+import com.tzy.sportcard.api.bean.param.CalendarParam;
+import com.tzy.sportcard.api.domain.GoodsInfo;
+import com.tzy.sportcard.api.dto.group.CalendarSearchDTO;
+import com.tzy.sportcard.api.dto.group.GroupGoodsDTO;
+import com.tzy.sportcard.api.dto.group.ListSearchDTO;
+import com.tzy.sportcard.api.service.ChecklistCalendarService;
+import com.tzy.sportcard.api.service.GroupApiService;
+import com.tzy.sportcard.group.domain.CardGroupInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.teasoft.bee.osql.SuidRich;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author by po'yi
+ * @Classname ListCalendarController
+ * @Description checklist日历
+ * @Date 2022/11/15 14:17
+ */
+@Api("checklist日历api")
+@RestController
+@RequestMapping("/api/calendar")
+public class ListCalendarController extends AppBaseController {
+
+
+	@Autowired
+	private ChecklistCalendarService checklistCalendarService;
+	@Autowired
+	private GroupApiService groupApiService;
+	@Autowired
+	private SuidRich suidRich;
+
+	@ApiLog(title = "日历刷选条件", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@RequestMapping(value = "/{version}/search/param", method = RequestMethod.POST)
+	@ApiVersion(1.0)
+	@ApiOperation("日历刷选条件")
+	public OutDTO getSearchParam(@RequestBody InDto inDto) {
+		CalendarSearchDTO searchParams=checklistCalendarService.selectCalendarSearchParam();
+		return OutDTO.ok().put("searchParams",searchParams);
+	}
+
+	@ApiLog(title = "checklist刷选条件", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@RequestMapping(value = "/{version}/list/search/id", method = RequestMethod.POST)
+	@ApiVersion(1.0)
+	@ApiOperation("checklist刷选条件")
+	public OutDTO getListSearchParam(@RequestBody InDto inDto) {
+		ListSearchDTO searchDTO=checklistCalendarService.selectListSearchParam(Long.valueOf(inDto.getString("id")));
+		return OutDTO.ok().put("searchParams",searchDTO);
+	}
+
+	@ApiLog(title = "获取checklist日历", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@RequestMapping(value = "/{version}/list", method = RequestMethod.POST)
+	@ApiVersion(1.0)
+	@ApiOperation("获取checklist日历")
+	public OutDTO getCalendarList(@RequestBody InDto inDto) {
+		CalendarParam param=inDto.buildParam(new CalendarParam());
+		param.setPageNo(inDto.getPageNo());
+		param.setPageSize(inDto.getPageSize());
+		param.setUserId(inDto.getUserId());
+		return OutDTO.ok().put("calendars",checklistCalendarService.selectCalendarList(param));
+	}
+
+	@ApiLog(title = "查询已出卡密", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@RequestMapping(value = "/{version}/goods/id", method = RequestMethod.POST)
+	@ApiVersion(1.0)
+	@ApiOperation("查询已出卡密")
+	public OutDTO getListGoods(@RequestBody InDto inDto) {
+		CalendarParam param=inDto.buildParam(new CalendarParam());
+		if(param.getPaniniListId()==null){
+			return OutDTO.error500("参数为空!");
+		}
+		param.setPageNo(inDto.getPageNo());
+		param.setPageSize(inDto.getPageSize());
+		param.setUserId(inDto.getUserId());
+		PageInfo<GroupGoodsDTO> goods=checklistCalendarService.selectListGoods(param);
+		return OutDTO.ok().put("goods",goods);
+	}
+
+	@ApiLog(title = "推荐商品", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@RequestMapping(value = "/{version}/goods/recommend", method = RequestMethod.POST)
+	@ApiVersion(1.0)
+	@ApiOperation("推荐商品")
+	public OutDTO getRecommendGoods(@RequestBody InDto inDto) {
+		Long paniniListId = Long.valueOf(inDto.getString("paniniListId"));
+		CardGroupInfo cardGroupInfo = new CardGroupInfo();
+		cardGroupInfo.setShowApplet("1");
+		cardGroupInfo.setColumnsearch("and cgi.status=201 and cgi.panini_list_id= "+paniniListId);
+		List<GoodsInfo> groupInfo = groupApiService.findGroupInfo(inDto, cardGroupInfo);
+		Spu spu = new Spu();
+		spu.setPaniniListId(paniniListId);
+		spu.setStatus(201L);
+		spu.setShopType(1);
+		spu.setShowApplet(1);
+		List<SpuDTO> spuList = suidRich.select(spu).stream().map(s -> DozerUtils.map(s, SpuDTO.class)).collect(Collectors.toList());
+		return OutDTO.ok().put("groupInfos",groupInfo).put("spuList",spuList);
+	}
+
+	@ApiLog(title = "查询PaniniCheckList", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@RequestMapping(value = "/{version}/panini/goods/list", method = RequestMethod.POST)
+	@ApiVersion(1.0)
+	@ApiOperation("查询PaniniCheckList,参数,paniniListId,搜索:keyword")
+	public OutDTO getPaniniCheckList(@RequestBody InDto inDto) {
+		GoodsQuery param=inDto.buildParam(new GoodsQuery());
+		if(param.getPaniniListId()==null){
+			return OutDTO.error500("参数为空!");
+		}
+		param.setPageNo(inDto.getPageNo());
+		param.setPageSize(inDto.getPageSize());
+		return OutDTO.ok().put("goods",checklistCalendarService.getPaniniCheckList(param));
+	}
+}

+ 77 - 0
poyi-app/src/main/java/com/tzy/controller/ierp/PyErpRandomCodeController.java

@@ -0,0 +1,77 @@
+package com.tzy.controller.ierp;
+
+import com.tzy.annotation.ApiLimitRule;
+import com.tzy.annotation.RequireRoles;
+import com.tzy.ierp.domain.PyErpRandomCode;
+import com.tzy.ierp.dto.PyErpRandomCodeDto;
+import com.tzy.ierp.dto.PyErpRandomCodeReq;
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.utils.UserType;
+import com.tzy.common.utils.bean.BeanUtils;
+import com.tzy.framework.web.domain.LimitRule;
+import com.tzy.ierp.enums.PyRandomCodeEnums;
+import com.tzy.ierp.service.PyErpRandomCodeService;
+import com.tzy.valid.Select;
+import com.tzy.valid.Update;
+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.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Objects;
+
+/**
+ *
+ */
+@Api(tags = "随机码接口" , value = "随机码接口")
+@RestController
+@RequestMapping("/api/{version}/erpRandomCode")
+@Slf4j
+public class PyErpRandomCodeController {
+    @Autowired
+    private PyErpRandomCodeService pyErpRandomCodeService;
+
+    /**
+     * 生态购随机码 查询
+     */
+    @ApiOperation( value = "生态购随机码 查询")
+    @ApiVersion(1.0)
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁!")
+    @RequestMapping(value = "/query", method = RequestMethod.POST)
+    @RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_ECOLOGICAL_SHOPPING})
+    @ResponseBody
+    public OutDTO query(@Validated(Select.class) @RequestBody PyErpRandomCodeReq req) {
+        PyErpRandomCode randomCode = pyErpRandomCodeService.getPyErpRandomCode(req);
+        PyErpRandomCodeDto dto = new PyErpRandomCodeDto();
+        BeanUtils.copyProperties(randomCode, dto);
+        dto.setStatusMsg(PyRandomCodeEnums.getMsg(randomCode.getStatus()));
+        if(Objects.equals(dto.getStatus(), PyRandomCodeEnums.CANCEL.getCode())){
+            return OutDTO.error500("该核销码已作废!");
+        }
+        return OutDTO.ok()
+                .put("data", dto);
+    }
+
+    /**
+     * 生态购随机码 系统入库绑定
+     *
+     * @param req
+     * @return
+     */
+    @ApiOperation( value = "生态购随机码 系统入库绑定")
+    @ApiVersion(1.0)
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁!")
+    @RequestMapping(value = "/sysIn", method = RequestMethod.POST)
+    @RequireRoles(value = {UserType.USER_ROLE_ADMIN, UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_ECOLOGICAL_SHOPPING})
+    @ResponseBody
+    public OutDTO sysIn(@Validated(Update.class) @RequestBody PyErpRandomCodeReq req) {
+        if(!pyErpRandomCodeService.sysIn(req)){
+            return OutDTO.error500("入库绑定失败!")
+                    ;
+        }
+        return OutDTO.ok();
+    }
+}

+ 117 - 0
poyi-app/src/main/java/com/tzy/controller/living/GroupLivingController.java

@@ -0,0 +1,117 @@
+package com.tzy.controller.living;
+
+import com.tzy.annotation.ApiLog;
+import com.tzy.annotation.RequireRoles;
+import com.tzy.common.core.controller.BaseController;
+import com.tzy.common.dto.InDto;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.enums.BusinessType;
+import com.tzy.common.utils.StringUtils;
+import com.tzy.common.utils.UserType;
+import com.tzy.pojo.card.CardGroupLivesConfig;
+import com.tzy.sportcard.api.domain.AppUserInfoDto;
+import com.tzy.sportcard.api.service.MineApiService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.teasoft.bee.osql.Condition;
+import org.teasoft.bee.osql.OrderType;
+import org.teasoft.bee.osql.SuidRich;
+import org.teasoft.honey.osql.core.ConditionImpl;
+
+import java.util.List;
+
+
+/**
+ * 直播
+ * @author po'yi
+ */
+@Api("直播api")
+@RestController
+@RequestMapping("/api/{version}/live")
+public class GroupLivingController extends BaseController {
+
+    @Autowired
+    private SuidRich suidRich;
+    @Autowired
+    private MineApiService mineApiService;
+
+
+    @ApiOperation("根据code查询房间信息")
+    @ApiLog(title = "根据code查询房间信息", businessType = BusinessType.SEARCH)
+    @PostMapping("/info")
+    //@ApiVersion(1.0)
+    public OutDTO getRoomDetail(@RequestBody InDto inDto) {
+        CardGroupLivesConfig condition = new CardGroupLivesConfig();
+        String roomCode = inDto.getString("roomCode");
+        String groupInfoId = inDto.getString("groupInfoId");
+        if (StringUtils.isEmpty(roomCode) && StringUtils.isEmpty(groupInfoId)) {
+            return OutDTO.error(500, "参数错误");
+        }
+        condition.setCode(roomCode);
+        condition.setCategory(inDto.getString("category"));
+
+        if (groupInfoId != null) {
+            condition.setGroupInfoId(Long.valueOf(inDto.getString("groupInfoId")));
+        }
+        Condition beeCondition = new ConditionImpl();
+        beeCondition.orderBy("id", OrderType.DESC);
+        List<CardGroupLivesConfig> list = suidRich.select(condition, beeCondition);
+        return OutDTO.ok().put("lives", list.get(0));
+    }
+
+
+    @ApiLog(title = "获取我的直播", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping("/mine")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_ADMIN,UserType.USER_ROLE_LIVING})
+    public OutDTO getMineLives(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo= mineApiService.checkUserNew(inDto);
+        Object status = inDto.get("status");
+        CardGroupLivesConfig condition=new CardGroupLivesConfig();
+        condition.setAppUserId(userInfo.getId());
+        condition.setDelFlg(0);
+        condition.setCategory(inDto.getString("category"));
+        Condition beeCondition=new ConditionImpl();
+        beeCondition.start((inDto.getPageNo()-1)*inDto.getPageSize()).size(inDto.getPageSize());
+        if(status!=null){
+            beeCondition.orderBy("endTime", OrderType.DESC);
+            condition.setStatus(2L);
+        }else{
+            beeCondition.between("status",0,1);
+            beeCondition.orderBy("startTime", OrderType.ASC);
+        }
+
+        List<CardGroupLivesConfig> list = suidRich.select(condition,beeCondition);
+        return OutDTO.ok().put("lives", list);
+    }
+
+    //@ApiLog(title = "添加直播间聊天记录", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    //@ResponseBody
+    //@PostMapping("/chat/add")
+    //public OutDTO addChatRecord(@RequestBody InDto inDto) {
+    //    mineApiService.checkUserNew(inDto);
+    //    RoomChat roomChat = new RoomChat();
+    //    BeanUtil.populate(roomChat, inDto.getData());
+    //    roomChat.setCreateTime(DateUtils.getTimestampNow());
+    //    suidRich.insert(roomChat);
+    //    return OutDTO.ok();
+    //}
+    //
+    //@ApiLog(title = "查询直播间聊天记录", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    //@ResponseBody
+    //@PostMapping("/chat/query")
+    //public OutDTO queryChatRecord(@RequestBody InDto inDto) {
+    //    RoomChat roomChat = new RoomChat();
+    //    Condition beeCondition=new ConditionImpl();
+    //    beeCondition.start(inDto.getPageNo()-1).size(inDto.getPageSize())
+    //            .op("createTime", Op.ge, Timestamp.valueOf(inDto.getString("createTimeStart")))
+    //            .op("createTime", Op.le, Timestamp.valueOf(inDto.getString("createTimeEnd")))
+    //            .op("roomId", Op.eq,Long.valueOf(inDto.get("roomId").toString()));
+    //    List<RoomChat> list = suidRich.select(roomChat,beeCondition);
+    //    return OutDTO.ok().put("chats", list);
+    //}
+
+
+}

+ 366 - 0
poyi-app/src/main/java/com/tzy/controller/living/LivingApiController.java

@@ -0,0 +1,366 @@
+package com.tzy.controller.living;
+
+import com.beust.jcommander.internal.Lists;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.tzy.annotation.ApiLimitRule;
+import com.tzy.common.config.CommonConfig;
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.common.constant.Constants;
+import com.tzy.common.core.controller.BaseController;
+import com.tzy.common.dto.InDto;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.dto.UserInfo;
+import com.tzy.common.utils.UserType;
+import com.tzy.common.utils.UserUtils;
+import com.tzy.common.utils.bean.JSONTools;
+import com.tzy.common.utils.http.forest.CommonForestClient;
+import com.tzy.dto.*;
+import com.tzy.framework.util.RedisUtils;
+import com.tzy.liveConfig.service.LiveLikeDBUpdateService;
+import com.tzy.liveConfig.service.LiveLikePushService;
+import com.tzy.sportcard.api.dto.LiveMerchantDTO;
+import com.tzy.sportcard.api.dto.group.LiveListDTO;
+import com.tzy.sportcard.api.service.GroupApiService;
+import com.tzy.sportcard.group.domain.CardGroupLivesConfig;
+import com.tzy.sportcard.group.domain.CardGroupLivesLike;
+import com.tzy.sportcard.group.mapper.CardGroupLivesConfigMapper;
+import com.tzy.sportcard.group.mapper.CardGroupLivesLikeMapper;
+import com.tzy.sportcard.group.service.ICardGroupLivesConfigService;
+import com.tzy.sportcard.group.service.impl.GroupActService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.util.CollectionUtils;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.teasoft.bee.osql.SuidRich;
+
+import javax.annotation.Resource;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 直播-api
+ */
+@Api("直播-api")
+@Slf4j
+@RestController
+@RequestMapping("/api/living")
+public class LivingApiController extends BaseController {
+    @Resource
+    private SuidRich suidRich;
+    @Resource
+    private CardGroupLivesConfigMapper cardGroupLivesConfigMapper;
+    @Resource
+    private CardGroupLivesLikeMapper cardGroupLivesLikeMapper;
+    @Resource
+    private GroupApiService groupApiService;
+    @Resource
+    private LiveLikePushService liveLikePushService;
+    @Resource
+    private LiveLikeDBUpdateService liveLikeDBUpdateService;
+    @Resource
+    private ICardGroupLivesConfigService livesConfigService;
+    @Resource
+    private CommonForestClient commonForestClient;
+    @Value("${liveWebSocketUrl:https://im-dev.hobbystocks.cn/chat/handler}")
+    private String liveWebSocketUrl;
+    @Resource
+    private RedisUtils redisUtils;
+    @Resource
+    private GroupActService groupActService;
+
+    @PostMapping(value = "/details")
+    public OutDTO details(@RequestBody InDto inDto) {
+        Integer roomid = inDto.getIntegerParam("id");
+        if (null == roomid) return OutDTO.error(10040, "参数[id]不能为空!");
+        LivingRoomDTO cond = new LivingRoomDTO();
+        cond.setId(roomid);
+        LivingRoomDTO livingRoomDto = suidRich.selectOne(cond);
+        if (livingRoomDto == null) {
+            return OutDTO.error500("直播间不存在!");
+        }
+        return OutDTO.ok().put("livingRoomInfo", livingRoomDto);
+    }
+
+
+    @ApiOperation("获取直播间")
+    @PostMapping("/{version}/list/{type}/{refId}")
+    public OutDTO findMerchantLiving(@PathVariable("refId") Integer refId, @PathVariable("type") String type) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        Integer userId = user == null ? null : user.getId();
+        List<LiveListDTO> liveList = livesConfigService.findAllLiving(type, refId, userId);
+        if (CollectionUtils.isEmpty(liveList)) {
+            return OutDTO.ok().put("livingList", liveList);
+        }
+
+        boolean isShipping = user != null && UserType.USER_ROLE_SHIPPING.equals(user.getRoleCode());
+        // 判断当前登陆的用户是否是商家角色
+        Integer merchantId = isShipping && user.getMerchantId() != null ? user.getMerchantId() : null;
+        liveList.parallelStream().filter(living -> Constants.ORDER_TYPE_GROUP.equals(living.getCategory()))
+                .forEach(living -> {
+                    boolean confirmStatus = isShipping && Objects.equals(living.getMerchantId(), merchantId);
+                    living.setConfirmStatus(confirmStatus);
+                    groupApiService.setGroupData(userId, living);
+                });
+        return OutDTO.ok().put("livingList", liveList);
+    }
+
+    @ApiOperation("获取已结束直播")
+    @PostMapping("/{version}/end/list")
+    public OutDTO findEndLive(@RequestBody EndLiveParam endLiveParam) {
+        PageInfo<LiveListDTO> liveList = livesConfigService.findEndLives(endLiveParam);
+        return OutDTO.ok().put("livingList", liveList);
+    }
+
+
+    @ApiOperation("获取直播间用户信息")
+    @PostMapping("/{version}/user/{code}")
+    @ApiLimitRule(seconds = 1, limitCount = 30, msg = "网络失败,请重试!")
+    public OutDTO findLivingRoomUser(@PathVariable("code") String code) {
+        List<LivingRoomDTO> rooms = getRooms(code);
+        if (CollectionUtils.isEmpty(rooms)) {
+            return OutDTO.ok().put("users", new ArrayList<>());
+        }
+        Integer merchantId = rooms.get(0).getMerchantId();
+        String url = String.format(CommonConfig.baseconfig.getImBaseUrl() + CommonConfig.baseconfig.getImUserUrl(), code);
+        String result = commonForestClient.sendGet(url);
+        ImUserResp resp = JSONTools.jsonStr2obj(result, ImUserResp.class);
+        if (resp == null || resp.getCode() != 200 || CollectionUtils.isEmpty(resp.getData())) {
+            log.warn("查询直播间用户异常:{}", result);
+            return OutDTO.ok().put("users", new ArrayList<>());
+        }
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        boolean isOwnerMerchant = user != null && Objects.equals(merchantId, user.getMerchantId());
+        log.debug("查询直播间用户结果:{}", result);
+        List<ImUserDTO> users = livesConfigService.findLivingRoomUser(merchantId, resp.getData(), isOwnerMerchant, 1, 200);
+        return OutDTO.ok().put("users", users);
+    }
+
+    private List<LivingRoomDTO> getRooms(String code) {
+        LivingRoomDTO cond = new LivingRoomDTO();
+        cond.setCode(code);
+        cond.setDelFlg(0);
+        cond.setStatus(1);
+        return suidRich.select(cond);
+    }
+
+    private LivingRoomDTO checkRoomUser(ImParam param) {
+        if (StringUtils.isEmpty(param.getCode())) {
+            return null;
+        }
+        if (CollectionUtils.isEmpty(param.getUserIds())) {
+            return null;
+        }
+        List<LivingRoomDTO> rooms = getRooms(param.getCode());
+        if (CollectionUtils.isEmpty(rooms)) {
+            return null;
+        }
+        return rooms.get(0);
+    }
+
+    @ApiOperation("直播间用户变动")
+    @PostMapping("/{version}/user/change")
+    public OutDTO livingUserChange(@RequestBody ImParam param) {
+        LivingRoomDTO livingRoom = checkRoomUser(param);
+        if (livingRoom == null) {
+            return OutDTO.error(405, "直播间信息不存在");
+        }
+        log.debug("直播间用户变动:{}", param);
+        List<ImUserDTO> users = livesConfigService.getImUsers(livingRoom.getMerchantId(), param.getUserIds(), 3);
+        livesConfigService.setCachedLiveRoomUser(param.getCode(), param.getUserIds());
+
+        if (CollectionUtils.isEmpty(users)) {
+            return OutDTO.ok();
+        }
+//        if (!redisUtils.setIfAbsent(Constants.LIVING_USER_CHANGE_RECORD + param.getCode(), "1", 2, TimeUnit.SECONDS)) {
+//            return OutDTO.ok();
+//        }
+        //List<String> imgList = new ArrayList<>(3);
+        // StringJoiner stringJoiner = new StringJoiner(",");
+        // for(ImUserDTO user:users){
+        //     stringJoiner.add(user.getId().toString());
+        //     imgList.add(user.getAvatar());
+        // }
+        // String currentUserIds = stringJoiner.toString();
+        // String key=Constants.LIVING_ROOM_USER_KEY+param.getCode();
+        // Object existUserId = redisUtils.get(key);
+        // if (currentUserIds.equals(existUserId)) {
+        //     return OutDTO.ok();
+        // }
+        List<String> imgList = users.stream().map(ImUserDTO::getAvatar).collect(Collectors.toList());
+        Message message = buildImReq(param.getCode(), imgList, param.getUserIds());
+        //commonForestClient.sendPost(liveWebSocketUrl, Constants.JSON_HEADS, message);
+        //redisUtils.set(key,currentUserIds,60);
+        return OutDTO.ok().put("message",message);
+    }
+
+    private Message buildImReq(String code, List<String> imgList, List<Integer> userIdList) {
+        Map<String, Object> body = new HashMap<>(2);
+        body.put("imgList", imgList);
+        body.put("totalNum", userIdList.size());
+        return Message.builder().code("chat")
+                .messageType("chat_to_room")
+                .messageParam(
+                        Message.MessageParam.builder()
+                                .receiver(code)
+                                .payload(
+                                        Message.MessageParam.Payload.builder()
+                                                .contentType("CHANGES_NUM_PEOPLE")
+                                                .sender("app")
+                                                .content("user")
+                                                .extra(JSONTools.obj2json(body))
+                                                .build()
+                                ).build()).build();
+    }
+
+
+    @ApiOperation("获取直播间用户信息v2,分页")
+    @PostMapping("/{version}/user")
+    @ApiLimitRule(seconds = 1, limitCount = 30, msg = "网络失败,请重试!")
+    public OutDTO findLivingRoomUserV2(@Validated @RequestBody LivingUserParam param) {
+        String code = param.getCode();
+        if (StringUtils.isEmpty(code)) {
+            return OutDTO.error500("参数缺失");
+        }
+        List<LivingRoomDTO> rooms = getRooms(code);
+        if (CollectionUtils.isEmpty(rooms)) {
+            return OutDTO.ok().put("users", new ArrayList<>()).put("totalNum", 0);
+        }
+        Integer merchantId = rooms.get(0).getMerchantId();
+        // String url = String.format(CommonConfig.baseconfig.getImBaseUrl() + CommonConfig.baseconfig.getImUserUrl(), code);
+        // String result = commonForestClient.sendGet(url);
+        String result = livesConfigService.getCachedLiveRoomUser(param.getCode());
+        if (result == null) {
+            log.warn("查询直播间用户异常:{}", result);
+            return OutDTO.ok().put("users", new ArrayList<>()).put("totalNum", 0);
+        }
+        List<Integer> userIds = JSONTools.jsonStr2obj(result, List.class);
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        boolean isOwnerMerchant = user != null && Objects.equals(merchantId, user.getMerchantId());
+        log.debug("查询直播间用户结果:{}", result);
+        List<ImUserDTO> users = livesConfigService.findLivingRoomUser(merchantId, userIds, isOwnerMerchant, param.getPageNo(), param.getPageSize());
+        return OutDTO.ok().put("users", users).put("totalNum", userIds.size());
+    }
+
+    @ApiOperation("获取商城直播画面")
+    @PostMapping("/{version}/screen")
+    public OutDTO getlivingScreen() {
+        // 查询直播中的商城直播
+        List<CardGroupLivesConfig> shopLivings = livesConfigService.getShopLivings();
+        if(CollectionUtils.isEmpty(shopLivings)){
+            return OutDTO.ok().put("livingScreens", null);
+        }
+        List<LivingScreenDTO> livingScreens = Lists.newArrayList();
+        shopLivings.forEach(living ->{
+            String key = "simple_living_" + living.getCode();
+            if(redisUtils.hasKey(key)){
+                LivingScreenDTO livingScreenDTO = new LivingScreenDTO();
+                Map<Object, Object> playbackData = redisUtils.hmget(key);
+                livingScreenDTO.setCaptureTime(playbackData.get("capture_time").toString());
+                livingScreenDTO.setCaptureUrl(playbackData.get("capture_url").toString());
+                livingScreenDTO.setCode(living.getCode());
+                livingScreens.add(livingScreenDTO);
+            }
+        });
+        return OutDTO.ok().put("livingScreens", livingScreens);
+    }
+
+    @ApiOperation("获取直播间点赞")
+    @PostMapping("/{version}/like/{code}")
+    @ApiLimitRule(seconds = 1, limitCount = 30, msg = "网络失败,请重试!")
+    public OutDTO getLivingRoomLike(@PathVariable("code") String code) {
+        if (!redisUtils.hHasKey(Constants.LIVING_ROOM_LIKE_KEY, code)) {
+            List<CardGroupLivesConfig> livingRoomDto = cardGroupLivesConfigMapper.selectLivingRoomByCode(code);
+            // 写缓存
+            int liveLikeNum = 0;
+            if(livingRoomDto != null && !livingRoomDto.isEmpty()){
+                liveLikeNum = livingRoomDto.get(0).getLiveLikeNum();
+            }
+            redisUtils.hset(Constants.LIVING_ROOM_LIKE_KEY, code, liveLikeNum, 24 * 60 * 60);
+        }
+        return OutDTO.ok().put("count", redisUtils.hget(Constants.LIVING_ROOM_LIKE_KEY, code));
+    }
+
+    @ApiOperation("点赞直播间")
+    @PostMapping("/{version}/like")
+    @ApiLimitRule(seconds = 1, limitCount = 30, msg = "网络失败,请重试!")
+    public OutDTO likeLivingRoom(@Validated @RequestBody UserLikeParam param) {
+        //1000465 HS-APP【直播间竞价】并发场景下当前端传的num参数大于50时,则接口最大有效值为50(防止被恶意修改参数)
+        int likeNum = param.getNum() >= 50 ? 50 : param.getNum();
+        //region LIVING_ROOM_LIKE_KEY logic
+        int finalLikeNum = likeNum;
+        if (redisUtils.hHasKey(Constants.LIVING_ROOM_LIKE_KEY, param.getCode())) {
+            finalLikeNum = (int)redisUtils.hget(Constants.LIVING_ROOM_LIKE_KEY, param.getCode()) +finalLikeNum;
+        }
+        else{
+            List<CardGroupLivesConfig> livingRoomDtoList = cardGroupLivesConfigMapper.selectLivingRoomByCode(param.getCode());
+            if(livingRoomDtoList != null && !livingRoomDtoList.isEmpty()){
+                finalLikeNum = (livingRoomDtoList.get(0).getLiveLikeNum()==null?0:livingRoomDtoList.get(0).getLiveLikeNum()) + likeNum;
+            }
+        }
+        // 写LIVING_ROOM_LIKE_KEY缓存
+        redisUtils.hset(Constants.LIVING_ROOM_LIKE_KEY, param.getCode(), finalLikeNum, 24 * 60 * 60);
+        //endregion
+
+        //region LIVING_ROOM_LIKE_USER_KEY logic
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        // 写LIVING_ROOM_LIKE_USER_KEY缓存
+        int finalUserLikeNum = likeNum;
+        if (redisUtils.hHasKey(Constants.LIVING_ROOM_LIKE_USER_KEY, user.getId()+param.getCode())) {
+            finalUserLikeNum = (int)redisUtils.hget(Constants.LIVING_ROOM_LIKE_USER_KEY, user.getId()+param.getCode()) +finalUserLikeNum;
+        }
+        else{
+            CardGroupLivesLike livesLike = cardGroupLivesLikeMapper.selectCardGroupLivesLikeById(user.getId(),param.getCode());
+            if (livesLike != null) {
+                finalUserLikeNum = livesLike.getLike_num()==null?0:livesLike.getLike_num() + likeNum;
+            }
+        }
+        // 写LIVING_ROOM_LIKE_USER_KEY缓存
+        redisUtils.hset(Constants.LIVING_ROOM_LIKE_USER_KEY, user.getId()+param.getCode(), finalUserLikeNum, 24 * 60 * 60);
+        //endregion
+        // 定时推给db更新
+        liveLikeDBUpdateService.handleRequest(param.getCode(),user.getId());
+        // 定时推给im更新
+        liveLikePushService.handleRequest(param.getCode());
+
+
+        return OutDTO.ok().put("count", finalLikeNum);
+    }
+
+    @ApiOperation("首页直播商家排序")
+    @PostMapping("/{version}/sorts")
+    public OutDTO getLiveMerchantList(@RequestBody CardGroupLivesConfig cardGroupLivesConfig) {
+        if(cardGroupLivesConfig == null){
+            cardGroupLivesConfig = new CardGroupLivesConfig();
+        }
+        UserInfo userInfo = UserUtils.getSimpleUserInfo(false);
+        if(userInfo != null){
+            cardGroupLivesConfig.setAppUserId(userInfo.getId());
+        }
+        // 查询直播中的商家直播信息
+        List<LiveMerchantDTO> liveMerchantList = livesConfigService.getLiveMerchantList(cardGroupLivesConfig);
+        return OutDTO.ok().put("liveMerchantList", liveMerchantList);
+    }
+
+    @ApiVersion(1.0)
+    @ApiOperation("根据paniniListId查询直播中的商品/拍品")
+    @PostMapping("/{version}/panini/{paniniListId}")
+    public OutDTO getLiveByPaniniListId(@PathVariable Long paniniListId) {
+        // 根据paniniListId查询直播中的商品
+        List<LiveMerchantDTO> paniniLives = livesConfigService.getLiveByPaniniListId(paniniListId);
+        return OutDTO.ok().put("paniniLives", paniniLives);
+    }
+
+    @PostMapping("/{version}/main/place/list")
+    @ApiVersion(1.0)
+    @ApiOperation(value = "查询双11主会场直播列表")
+    public OutDTO getMainPlaceLiveConfigs(@RequestBody InDto inDto){
+        PageHelper.startPage(inDto.getPageNo(),inDto.getPageSize());
+        List<LiveListDTO> livesConfigList = livesConfigService.getLivesByStartTime();
+        return OutDTO.ok().put("livesConfigList",livesConfigList);
+    }
+}

+ 115 - 0
poyi-app/src/main/java/com/tzy/controller/mall/EvaluationController.java

@@ -0,0 +1,115 @@
+package com.tzy.controller.mall;
+
+import com.github.pagehelper.PageInfo;
+import com.tzy.annotation.ApiLog;
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.common.constant.Constants;
+import com.tzy.common.core.controller.BaseController;
+import com.tzy.common.dto.InDto;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.enums.BusinessType;
+import com.tzy.common.utils.StringUtils;
+import com.tzy.pojo.item.EvaluationRecord;
+import com.tzy.pojo.item.dto.EvaluationRecordDTO;
+import com.tzy.sportcard.api.service.MerchantApiService;
+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.util.CollectionUtils;
+import org.springframework.web.bind.annotation.*;
+import org.teasoft.bee.osql.Condition;
+import org.teasoft.bee.osql.Op;
+import org.teasoft.bee.osql.OrderType;
+import org.teasoft.bee.osql.SuidRich;
+import org.teasoft.honey.osql.core.ConditionImpl;
+
+import javax.annotation.Resource;
+import javax.persistence.Version;
+import java.util.List;
+
+/**
+ * @author by po'yi
+ * @Classname EvaluationController
+ * @Description Evaluation
+ * @Date 2022/2/28 11:56
+ */
+@Slf4j
+@Api("Evaluation")
+@RestController
+@RequestMapping("/api/{version}/sku")
+public class EvaluationController extends BaseController {
+
+	@Resource
+	private SuidRich suidRich;
+	@Resource
+	private MerchantApiService merchantApiService;
+
+	@ApiLog(title = "根据type和refId评论查询",businessType = BusinessType.UPDATE,indto = "{{inDto}}")
+	@ResponseBody
+	@ApiOperation("根据type和refId评论查询")
+	@RequestMapping(value = "/getEvaluation", method = RequestMethod.POST)
+	public OutDTO getEvaluation(@RequestBody InDto inDto){
+		EvaluationRecord evaluationRecord = new EvaluationRecord();
+		evaluationRecord.setType(inDto.getString("type"));
+		//组团id,订单id
+		if(Strings.isNotEmpty(inDto.getString("refId"))){
+			evaluationRecord.setRefId(Long.valueOf(inDto.getString("refId")));
+		}
+		int page=inDto.getPageNo()!=null&&inDto.getPageNo()>0?inDto.getPageNo():1;
+		int size=inDto.getPageSize()!=null&&inDto.getPageSize()>0?inDto.getPageSize():10;
+		//middle,bad,good
+		String level = inDto.getString("level");
+		Condition condition=new ConditionImpl();
+		if(Constants.EVALUATION_LEVEL_GOOD.equals(level)){
+			condition.op("value", Op.eq,5);
+		}else if(Constants.EVALUATION_LEVEL_BAD.equals(level)){
+			condition.op("value", Op.lt,3);
+		}else if (Constants.EVALUATION_LEVEL_MIDDLE.equals(level)){
+			condition.op("value", Op.gt,2);
+			condition.op("value", Op.lt,5);
+		}
+		int offSet=(page-1)*size;
+		condition.start(offSet).size(size);
+		condition.orderBy("id", OrderType.DESC);
+		evaluationRecord.setStatus(1); // 查询显示的评价
+		List<EvaluationRecord> evaluations = suidRich.select(evaluationRecord, condition);
+		if(!CollectionUtils.isEmpty(evaluations)){
+			evaluations.forEach(evaluation ->{
+				String nickname = evaluation.getNickName();
+				if(Strings.isNotEmpty(nickname)){
+					// 是否匿名:0否 1是
+					if(evaluation.getAnonymous() == 0){
+						evaluation.setNickName(StringUtils.desensitizeName(nickname));
+					}else if(evaluation.getAnonymous() == 1){
+						evaluation.setNickName("匿名用户");
+						evaluation.setAvatar("https://static.public.hobbystock.cn/applet/share/share_logo2.png");
+					}
+					//商家展示勾选未有文字内容的评价时,默认为:ta未作出评价内容
+					if(Strings.isEmpty(evaluation.getContent())){
+						evaluation.setContent("ta未作出评价内容");
+					}
+				}
+			});
+		}
+		return OutDTO.ok().put("evaluations",evaluations);
+	}
+
+	@ApiLog(title = "根据type和merchantId查询评论",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+	@ResponseBody
+	@ApiVersion(2.0)
+	@ApiOperation("根据type和merchantId查询评论")
+	@RequestMapping(value = "/getEvaluation", method = RequestMethod.POST)
+	public OutDTO getEvaluationV2(@RequestBody EvaluationRecordDTO evaluationRecordDTO){
+		// 商家id
+		if(evaluationRecordDTO == null || evaluationRecordDTO.getId() == null){
+			return OutDTO.error500("参数为空");
+		}
+		evaluationRecordDTO.setId(evaluationRecordDTO.getId());
+		int page = evaluationRecordDTO.getPageNo()!=null&&evaluationRecordDTO.getPageNo()>0?evaluationRecordDTO.getPageNo():1;
+		int size = evaluationRecordDTO.getPageSize()!=null&&evaluationRecordDTO.getPageSize()>0?evaluationRecordDTO.getPageSize():10;
+		PageInfo<EvaluationRecord> pageInfo = merchantApiService.getEvaluationV2(evaluationRecordDTO, page, size);
+		return OutDTO.ok().put("evaluations", pageInfo);
+	}
+
+}

+ 427 - 0
poyi-app/src/main/java/com/tzy/controller/mall/MallOrderController.java

@@ -0,0 +1,427 @@
+package com.tzy.controller.mall;
+
+import com.tzy.annotation.ApiLimitRule;
+import com.tzy.annotation.ApiLog;
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.common.constant.Constants;
+import com.tzy.common.constant.MqConstans;
+import com.tzy.common.core.controller.BaseController;
+import com.tzy.common.dto.InDto;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.enums.BusinessType;
+import com.tzy.common.exception.ServiceException;
+import com.tzy.common.utils.DateUtils;
+import com.tzy.common.utils.bean.JSONTools;
+import com.tzy.dto.EvaluationDTO;
+import com.tzy.dto.OrderReq;
+import com.tzy.framework.util.RedisUtils;
+import com.tzy.framework.web.domain.LimitRule;
+import com.tzy.member.benefits.mapper.MemberBenefitsRecordMapper;
+import com.tzy.pojo.item.EvaluationRecord;
+import com.tzy.pojo.item.OrderList;
+import com.tzy.pojo.item.Sku;
+import com.tzy.service.MallOrderService;
+import com.tzy.sportcard.api.domain.AppUserInfoDto;
+import com.tzy.sportcard.api.service.AsyncAppService;
+import com.tzy.sportcard.api.service.MineApiService;
+import com.tzy.sportcard.api.service.PayService;
+import com.tzy.sportcard.group.domain.CardGroupOrderInfo;
+import com.tzy.sportcard.group.service.ICardGroupOrderInfoService;
+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.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.web.bind.annotation.*;
+import org.teasoft.bee.osql.Condition;
+import org.teasoft.bee.osql.FunctionType;
+import org.teasoft.bee.osql.Op;
+import org.teasoft.bee.osql.SuidRich;
+import org.teasoft.honey.osql.core.ConditionImpl;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author by po'yi
+ * @Classname MallOrderController
+ * @Description 订单
+ * @Date 2022/3/18 11:56
+ */
+@Slf4j
+@Api("订单")
+@RestController
+@RequestMapping("/api/{version}/order")
+public class MallOrderController extends BaseController {
+
+	@Autowired
+	private MineApiService mineApiService;
+	@Autowired
+	private MallOrderService mallOrderService;
+	@Autowired
+	private ICardGroupOrderInfoService cardGroupOrderInfoService;
+	@Autowired
+	private SuidRich suidRich;
+	@Autowired
+	private RedisUtils redisUtils;
+	@Autowired
+	@Lazy
+	private AsyncAppService asyncAppService;
+	@Resource
+	private MemberBenefitsRecordMapper memberBenefitsRecordMapper;
+	@Resource
+	private  RabbitTemplate rabbitTemplate;
+	@Autowired
+	private PayService payService;
+
+
+	@ApiLog(title = "提交订单", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("提交订单")
+	@ApiLimitRule(seconds = 2,limitCount=10,type= LimitRule.ACT,msg="抱歉,抢购人数太多,请稍后再试!")
+	@PostMapping("/submit")
+	public OutDTO submitOrder(@RequestBody OrderReq inDto ){
+		return OutDTO.error500("请更新app最新版本");
+	}
+
+	@ApiLog(title = "预支付2", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("预支付2")
+	@PostMapping("/prePayNew")
+	public OutDTO orderPrePayNew(@RequestBody InDto inDto ){
+		return OutDTO.error500("请先升级app");
+	}
+
+	@ApiLog(title = "积分兑换", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("积分兑换 ")
+	@ApiLimitRule(seconds = 1,limitCount=1,type= LimitRule.USER,msg="操作拼豆,请稍后再试!")
+	@PostMapping("/buyOfPoint")
+	public OutDTO buyOfPoint(@RequestBody InDto inDto ){
+		return OutDTO.error500("请更新app最新版本");
+	}
+
+	@ApiLog(title = "积分兑换优惠劵", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("积分兑换优惠劵,根据spuId兑换")
+	@ApiLimitRule(seconds = 2,limitCount=10,type= LimitRule.ACT_TOKEN,msg="抱歉,抢购人数太多,请稍后再试!")
+	@PostMapping("/exchangeCouponByPoint")
+	public OutDTO exchangeCouponByPoint(@RequestBody InDto inDto ){
+		Object spuId = inDto.get("spuId");
+		if(spuId==null){
+			return OutDTO.error500("参数skuId为空");
+		}
+		Integer skuId=getCouponSkuId(Long.valueOf(spuId.toString()));
+		Integer purchaseCount=1;
+		if(inDto.get("purchaseCount")!=null){
+			//购买数量
+			purchaseCount = (Integer) inDto.get("purchaseCount");
+			if(purchaseCount<1 ){
+				return OutDTO.error500("请选择兑换数量");
+			}
+		}
+		AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+		return mallOrderService.buyOfPoint(userInfo.getId(),skuId,inDto.get("addressId"),purchaseCount);
+	}
+
+	private Integer getCouponSkuId(Long spuId){
+		Object o = redisUtils.get(Constants.SKU_COUPON_ID_CACHE + spuId);
+		Integer skuId;
+		if(o==null){
+			Sku sku = new Sku();
+			sku.setSpuId(spuId);
+			sku.setStatus(201L);
+			List<Sku> skus = suidRich.select(sku);
+			if(skus.isEmpty()||skus.size()!=1){
+				throw new ServiceException(500, "优惠劵数量异常,请联系管理员!");
+			}
+			skuId = skus.get(0).getId().intValue();
+			redisUtils.set(Constants.SKU_COUPON_ID_CACHE + spuId,skuId,Constants.ONE_HOUR);
+		}else{
+			skuId=(Integer)o;
+		}
+		return skuId;
+	}
+
+	@ApiLog(title = "取消订单",businessType = BusinessType.UPDATE,indto = "{{inDto}}")
+	@ApiOperation("取消订单")
+	@ResponseBody
+	@PostMapping(value = "/cancelOrder")
+	public OutDTO cancelOrder(@RequestBody InDto inDto){
+		mineApiService.checkUserNew(inDto);
+		Integer orderId = (Integer) inDto.get("orderId");
+		CardGroupOrderInfo cardGroupOrderInfo = cardGroupOrderInfoService.selectCardGroupOrderInfoById(orderId.longValue());
+		if(null == cardGroupOrderInfo ){
+			return OutDTO.error500("未找到订单信息");
+		}
+		//判断是否符合取消订单的条件
+		Long status = cardGroupOrderInfo.getStatus();
+		if(status != 100){
+			return OutDTO.error500("不符合取消订单的条件!");
+		}
+
+		// 唤起支付前做一个查询
+		if(cardGroupOrderInfoService.checkOrderIsPay(orderId.longValue())){
+			return OutDTO.error500("订单支付中,无法取消!");
+		}
+		// 抢拍订单不允许取消
+		String orderSubType = cardGroupOrderInfo.getOrderSubType();
+		if(Strings.isNotEmpty(orderSubType) && Constants.AUCTION_ORDER_COMMON_AMOUNT.equals(orderSubType)){
+			return OutDTO.error500("抢拍订单不能取消!");
+		}
+		//用户取消
+		cardGroupOrderInfo.setStatus(202L);
+		// 释放库存
+		if (Constants.ORDER_TYPE_SHOP.equals(cardGroupOrderInfo.getOrderType())) {
+			mallOrderService.cancelOrder(cardGroupOrderInfo);
+			// 如果是权益兑换订单  删除权益兑换记录
+			String prop3 = cardGroupOrderInfo.getProp3();
+			if (Constants.MEMBER_BENEFITS.equals(cardGroupOrderInfo.getOrderSubType()) && Strings.isNotEmpty(prop3)) {
+				// 根据权益兑换记录id删除权益兑换记录
+				memberBenefitsRecordMapper.deleteMemberBenefitsRecordById(Long.parseLong(prop3));
+			}
+			if (cardGroupOrderInfo.getGiveOrderId() != null) {
+				rabbitTemplate.convertAndSend(MqConstans.EXCHANGE_DELAYED_ORDER_EXPIRED, MqConstans.ROUTING_KEY_ORDER_EXPIRED, cardGroupOrderInfo.getGiveOrderId());
+			}
+		} else if (Constants.ORDER_TYPE_GIFT_CARD.equals(cardGroupOrderInfo.getOrderType())) {
+			CardGroupOrderInfo updateOrder = new CardGroupOrderInfo();
+			updateOrder.setId(orderId.longValue());
+			updateOrder.setStatus(202L);
+			cardGroupOrderInfoService.updateCardGroupOrderInfo(updateOrder);
+		} else {
+			cardGroupOrderInfoService.cancelOrder(cardGroupOrderInfo);
+		}
+		cardGroupOrderInfoService.returnCouponByOrderId(orderId.longValue());
+		//回退积分
+		mineApiService.addUserPoint(cardGroupOrderInfo, true, Constants.POINT_TYPE_COMMON_RETURN);
+		return OutDTO.ok();
+	}
+
+	@ApiLog(title = "用户申请售后",businessType = BusinessType.UPDATE,indto = "{{inDto}}")
+	@ApiOperation("用户申请售后,退款,换货")
+	@ResponseBody
+	@PostMapping(value = "/afterSale")
+	public OutDTO refundOrder(@RequestBody InDto inDto){
+		AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+		Integer orderId = (Integer) inDto.get("orderId");
+		CardGroupOrderInfo cardGroupOrderInfo = cardGroupOrderInfoService.getOrderByUserAndId(userInfo.getId(),orderId.longValue());
+		if(null == cardGroupOrderInfo ){
+			return OutDTO.error(500,"未找到订单信息");
+		}
+
+		if(cardGroupOrderInfo.getPoint()!=null&&cardGroupOrderInfo.getPoint()>0){
+			return OutDTO.error500("积分订单无法申请,请联系客服!");
+		}
+
+		//判断是否符合取消订单的条件
+		Long status = cardGroupOrderInfo.getStatus();
+		if(!Constants.refundOrderStatus.contains(status.intValue())){
+			return OutDTO.error500("订单不符合申请退款的条件");
+		}
+		// 抢拍订单不允许退款
+		String orderSubType = cardGroupOrderInfo.getOrderSubType();
+		if(Strings.isNotEmpty(orderSubType) && Constants.AUCTION_ORDER_COMMON_AMOUNT.equals(orderSubType)){
+			return OutDTO.error500("抢拍订单不能退款!");
+		}
+		OrderList orderList = new OrderList();
+		orderList.setOrderId(cardGroupOrderInfo.getId());
+		Condition beeCondition = new ConditionImpl();
+		beeCondition.op("liveId", Op.gt,0);
+		String living = suidRich.selectWithFun(orderList, FunctionType.COUNT, "*", beeCondition);
+		if(Integer.valueOf(living)>0){
+			return OutDTO.error500("订单正在直播中,不符合申请退款的条件");
+		}
+
+		String refundType =inDto.getString("refundType");
+		String refundReason =inDto.getString("refundReason");
+		String refundDesc =inDto.getString("refundDesc");
+		CardGroupOrderInfo updateOrder = new CardGroupOrderInfo();
+		updateOrder.setId(cardGroupOrderInfo.getId());
+		updateOrder.setUserRefundTime(DateUtils.getTimestampNow());
+		updateOrder.setRefundType(refundType);
+		updateOrder.setRefundReason(refundReason);
+		updateOrder.setRefundDesc(refundDesc);
+		updateOrder.setRefundStatus(1);
+		cardGroupOrderInfoService.updateCardGroupOrderInfo(updateOrder);
+		asyncAppService.sendMerchantRefundNotice(cardGroupOrderInfo);
+		return OutDTO.ok();
+	}
+
+
+	@ApiLog(title = "用户评价订单",businessType = BusinessType.UPDATE,indto = "{{inDto}}")
+	@ApiOperation("用户评价订单")
+	@ResponseBody
+	@PostMapping(value = "/evaluation")
+	public OutDTO evaluateOrder(@RequestBody InDto inDto){
+		AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+		Integer orderId = (Integer) inDto.get("orderId");
+		CardGroupOrderInfo cardGroupOrderInfo = cardGroupOrderInfoService.selectCardGroupOrderInfoById(orderId.longValue());
+		if(null == cardGroupOrderInfo ){
+			return OutDTO.error(10040,"未找到订单信息");
+		}
+
+		if(cardGroupOrderInfo.getStatus()!=301){
+			return OutDTO.error(500,"订单未签收!");
+		}
+		//json
+		String evaluation =inDto.getString("evaluation");
+		CardGroupOrderInfo updateOrder = new CardGroupOrderInfo();
+		updateOrder.setId(cardGroupOrderInfo.getId());
+		updateOrder.setEvaluation(evaluation);
+		cardGroupOrderInfoService.updateCardGroupOrderInfo(updateOrder);
+
+		EvaluationDTO evaluationDTO = JSONTools.jsonStr2obj(evaluation, EvaluationDTO.class);
+		EvaluationRecord evaluationRecord = new EvaluationRecord();
+		evaluationRecord.setCreateUserId(appUserInfoDto.getId());
+		evaluationRecord.setAvatar(appUserInfoDto.getAvatar());
+		evaluationRecord.setNickName(appUserInfoDto.getNickname());
+		evaluationRecord.setAnonymous(evaluationDTO.getAnonymous()?1:0);
+		evaluationRecord.setContent(evaluationDTO.getContent());
+		evaluationRecord.setImgUrl(evaluationDTO.getImgArrAll());
+		evaluationRecord.setValue(evaluationDTO.getValue());
+		evaluationRecord.setType("spu");
+		List<OrderList> orderLists = mallOrderService.getOrderListByOrderId(cardGroupOrderInfo.getId());
+		evaluationRecord.setRefId(orderLists.get(0).getSpuId());
+		evaluationRecord.setCreateTime(DateUtils.getTimestampNow());
+		suidRich.insert(evaluationRecord);
+		return OutDTO.ok();
+	}
+
+	@ApiLog(title = "用户填写退换货物流",businessType = BusinessType.UPDATE,indto = "{{inDto}}")
+	@ApiOperation("用户填写退换货物流")
+	@ResponseBody
+	@PostMapping(value = "/refundShip")
+	public OutDTO refundShip(@RequestBody InDto inDto){
+		mineApiService.checkUserNew(inDto);
+		Integer orderId = (Integer) inDto.get("orderId");
+		CardGroupOrderInfo cardGroupOrderInfo = cardGroupOrderInfoService.selectCardGroupOrderInfoById(orderId.longValue());
+		if(null == cardGroupOrderInfo ){
+			return OutDTO.error(10040,"未找到订单信息");
+		}
+		if(cardGroupOrderInfo.getRefundStatus()!=2){
+			return OutDTO.error(500,"请等待商家同意!");
+		}
+		String refundCurierCompany =inDto.getString("refundCurierCompany");
+		String refundCurierNum =inDto.getString("refundCurierNum");
+		CardGroupOrderInfo updateOrder = new CardGroupOrderInfo();
+		updateOrder.setId(cardGroupOrderInfo.getId());
+		updateOrder.setRefundCurierCompany(refundCurierCompany);
+		updateOrder.setRefundCourierNum(refundCurierNum);
+		updateOrder.setRefundShipTime(DateUtils.getTimestampNow());
+		updateOrder.setRefundStatus(4);
+		cardGroupOrderInfoService.updateCardGroupOrderInfo(updateOrder);
+		return OutDTO.ok();
+	}
+
+
+	@ApiLog(title = "售后客服介入或接受商家拒绝退款操作",businessType = BusinessType.UPDATE,indto = "{{inDto}}")
+	@ApiOperation("售后客服介入或接受商家拒绝退款操作")
+	@ResponseBody
+	@PostMapping(value = "/saleCustomerServiceOrNot")
+	public OutDTO saleCustomerService(@RequestBody InDto inDto){
+		mineApiService.checkUserNew(inDto);
+		Integer orderId = (Integer) inDto.get("orderId");
+		CardGroupOrderInfo cardGroupOrderInfo = cardGroupOrderInfoService.selectCardGroupOrderInfoById(orderId.longValue());
+		if(null == cardGroupOrderInfo ){
+			return OutDTO.error(10040,"未找到订单信息");
+		}
+
+		if(cardGroupOrderInfo.getRefundStatus()!=3){
+			return OutDTO.error(500,"请等待商家操作!");
+		}
+
+		CardGroupOrderInfo updateOrder = new CardGroupOrderInfo();
+		updateOrder.setId(cardGroupOrderInfo.getId());
+		if(inDto.get("refundStatus")==null){
+			updateOrder.setRefundStatus(6);
+		}else{
+			updateOrder.setRefundStatus((Integer)inDto.get("refundStatus"));
+		}
+		cardGroupOrderInfoService.updateCardGroupOrderInfo(updateOrder);
+		return OutDTO.ok();
+	}
+
+	@ApiLog(title = "商城支付方式", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+	@ResponseBody
+	@PostMapping(value = "/v1/checkPayCat")
+	public OutDTO checkPayCat(@RequestBody InDto inDto) {
+		AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+		return payService.checkGoodsPayCat( inDto, appUserInfoDto);
+	}
+
+	@ApiLog(title = "商城支付方式-v2 支持香港支付", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+	@ResponseBody
+	@PostMapping(value = "/v2/checkPayCat")
+	public OutDTO checkPayCatV2(@RequestBody InDto inDto) {
+		AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+		return payService.checkGoodsPayCatV2( inDto, appUserInfoDto);
+	}
+
+	@ApiLog(title = "商城支付方式-v3 用户标签重构", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+	@ResponseBody
+	@PostMapping(value = "/v3/checkPayCat")
+	public OutDTO checkPayCatV3(@RequestBody InDto inDto) {
+		AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+		return payService.checkGoodsPayCatV3( inDto, appUserInfoDto);
+	}
+
+	/**
+	 * @param inDto
+	 * @return
+	 */
+	@ApiLog(title = "对公转账上传", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("对公转账上传")
+	@PostMapping("/{version}/corporatePublicToPay")
+	public OutDTO corporatePublicToPay(@RequestBody InDto inDto ,@PathVariable("version") String version){
+		Object orderId = inDto.get("orderId");
+		if(Objects.isNull(orderId)){
+			OutDTO.error(500, "订单id不能为空!");
+		}
+		AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+		return payService.corporatePublicToPay(version,inDto,appUserInfoDto);
+	}
+
+
+	@ApiLog(title = "预支付3", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("预支付3")
+	@PostMapping("/v3/prePayNew")
+	public OutDTO orderPrePayNewV3(@RequestBody InDto inDto) {
+		Integer orderId = inDto.getIntegerParam("orderId");
+		if (orderId == null) {
+			return OutDTO.error500("id为空!");
+		}
+		AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+		return payService.orderPrePayV3(inDto, appUserInfoDto, orderId.longValue(), "goods");
+	}
+
+	/**
+	 * 订单预支付-新通道 新分配规则
+	 * @param inDto
+	 * @return
+	 */
+	@ApiLog(title = "预支付4【订单预支付-新通道 新分配规则】", businessType = BusinessType.SEARCH)
+	@ResponseBody
+	@ApiVersion(1.0)
+	@ApiOperation("预支付4")
+	@PostMapping("/v4/prePayNew")
+	public OutDTO orderPrePayNewV4(@RequestBody InDto inDto) {
+		Integer orderId = inDto.getIntegerParam("orderId");
+		if (orderId == null) {
+			return OutDTO.error500("id为空!");
+		}
+		AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+		return payService.orderPrePayV4(inDto, appUserInfoDto, orderId.longValue(), "goods");
+	}
+
+}

+ 1078 - 0
poyi-app/src/main/java/com/tzy/controller/merchant/MerchantControllerNew.java

@@ -0,0 +1,1078 @@
+package com.tzy.controller.merchant;
+
+import com.github.pagehelper.PageInfo;
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import com.google.gson.reflect.TypeToken;
+import com.tzy.annotation.ApiLog;
+import com.tzy.annotation.RequireRoles;
+import com.tzy.app.domain.AppUserPoint;
+import com.tzy.app.domain.TzyMerchantArchives;
+import com.tzy.app.dto.SimpleMerchantInfo;
+import com.tzy.app.dto.SimpleUserShipDTO;
+import com.tzy.app.dto.TypeCountDTO;
+import com.tzy.app.dto.group.GiftCardManage;
+import com.tzy.common.config.QuerySql;
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.common.constant.Constants;
+import com.tzy.common.constant.MsgConstants;
+import com.tzy.common.dto.InDto;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.dto.UserInfo;
+import com.tzy.common.dto.group.NonEmptyQuery;
+import com.tzy.common.dto.invoice.SimpleOrderDTO;
+import com.tzy.common.enums.BusinessType;
+import com.tzy.common.exception.AppAssert;
+import com.tzy.common.json.JSON;
+import com.tzy.common.utils.*;
+import com.tzy.common.utils.bean.DozerUtils;
+import com.tzy.common.utils.qiniu.QiniuUtil;
+import com.tzy.express.ExpressUtils;
+import com.tzy.express.service.ExpressService;
+import com.tzy.framework.util.RedisUtils;
+import com.tzy.pojo.app.AppMerchantFans;
+import com.tzy.pojo.app.SimpleUser;
+import com.tzy.pojo.card.CardGroupInfo;
+import com.tzy.pojo.item.EvaluationRecord;
+import com.tzy.sportcard.api.bean.invoice.AppUserInvoiceRecord;
+import com.tzy.sportcard.api.bean.param.ShippingQuery;
+import com.tzy.sportcard.api.domain.AppUserInfoDto;
+import com.tzy.sportcard.api.domain.MerchantInfo;
+import com.tzy.sportcard.api.domain.SysCashoutOrderList;
+import com.tzy.sportcard.api.domain.TzyMerchantCenter;
+import com.tzy.sportcard.api.dto.*;
+import com.tzy.sportcard.api.dto.merchant.CompositeRankDTO;
+import com.tzy.sportcard.api.dto.merchant.MerchantRankDetailDTO;
+import com.tzy.sportcard.api.dto.merchant.MerchantRankingsDTO;
+import com.tzy.sportcard.api.dto.merchant.MerchantScoreDTO;
+import com.tzy.sportcard.api.service.GroupApiService;
+import com.tzy.sportcard.api.service.MerchantApiService;
+import com.tzy.sportcard.api.service.MineApiService;
+import com.tzy.sportcard.api.service.TzyMerchantAssessService;
+import com.tzy.sportcard.group.domain.CardGroupOrderInfo;
+import com.tzy.sportcard.group.service.ICardGroupOrderInfoService;
+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.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.bind.annotation.*;
+import org.teasoft.bee.osql.Condition;
+import org.teasoft.bee.osql.OrderType;
+import org.teasoft.bee.osql.PreparedSql;
+import org.teasoft.bee.osql.SuidRich;
+import org.teasoft.honey.osql.core.ConditionImpl;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author by po'yi
+ * @Classname AppUserControllerNew
+ * @Description
+ * @Date 2022/3/3 13:24
+ */
+@Api(value = "app商户接口")
+@RestController
+@RequestMapping("/api/{version}/merchant")
+@Slf4j
+public class MerchantControllerNew {
+    @Autowired
+    private MineApiService mineApiService;
+    @Autowired
+    private SuidRich suidRich;
+    @Autowired
+    private PreparedSql preparedSql;
+    @Autowired
+    private GroupApiService groupApiService;
+    @Autowired
+    private ICardGroupOrderInfoService cardGroupOrderInfoService;
+    @Autowired
+    private MerchantApiService merchantApiService;
+    @Resource
+    private RedisUtils redisUtils;
+    @Resource
+    private TzyMerchantAssessService tzyMerchantAssessService;
+    @Autowired
+    private ExpressService expressService;
+
+    @ApiLog(title = "拒绝累积发货的用户订单数量", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/refuseWaitShipping", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("拒绝累积发货的用户订单数量")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_DELIVERY})
+    public OutDTO refuseWaitShipping(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        AppAssert.notNull(user,MsgConstants.NEED_LOGIN);
+        String sql = QuerySql.getQuerySql("com.tzy.app.dto.CardGoodsDTO.refuseWaitShipping");
+        String s = preparedSql.selectFun(sql, new Object[]{user.getMerchantId()});
+        return OutDTO.ok().put("refuseCount", Integer.valueOf(s));
+    }
+
+
+    @ResponseBody
+    @PostMapping(value = "/history/mall/order")
+    @ApiVersion(1)
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_DELIVERY})
+    @ApiOperation("用户历史待发货累积拼豆订单)")
+    public OutDTO historyMallOrderOfGroup(@RequestBody InDto inDto) {
+        UserInfo userInfo = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(userInfo, MsgConstants.NEED_LOGIN);
+        Integer userId = inDto.getIntegerParam("orderUserId");
+        String keyword = inDto.getString("keyword");
+        ShippingQuery query = new ShippingQuery().setMerchantId(userInfo.getMerchantId()).setUserId(userId)
+                .setKeyword(keyword).setPageNo(inDto.getPageNo()).setPageSize(inDto.getPageSize());
+        PageInfo<UserOrderDTO> orders = groupApiService.historyMallOrderOfGroup(query);
+        return OutDTO.ok().put("page", orders);
+    }
+
+
+    @ApiLog(title = "用户维度的发货(包含关联拼豆订单)", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/merchantShippingUser")
+    @ApiVersion(1)
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_DELIVERY})
+    @ApiOperation("用户维度的发货(包含关联拼豆订单)")
+    public OutDTO merchantShippingUserV2(@RequestBody InDto inDto) {
+        UserInfo userInfo = UserUtils.getSimpleUserInfo(true);
+        if (userInfo == null || userInfo.getMerchantId() == null) {
+            return OutDTO.error500("权限不足");
+        }
+        String ids = inDto.getString("ids");
+        List<Long> groupIds = null;
+        if (StringUtils.isNotEmpty(ids)) {
+            groupIds = Arrays.stream(ids.split(",")).map(Long::valueOf).collect(Collectors.toList());
+        }
+        // 1:未发货 2:已发货; 不传则全部
+        String shippingStatus = inDto.getString("shippingStatus");
+        Integer infoStatus = inDto.getIntegerParam("infoStatus");
+        boolean isOver = infoStatus != null && infoStatus == 301;
+        String keyword = inDto.getString("keyword");
+        String selfPickupCode = inDto.getString("selfPickupCode");
+        boolean sortByTeam = getMerchantDefaultSortValue(inDto.get("sortByTeam"), userInfo.getMerchantId());
+        int offSet = (inDto.getPageNo() - 1) * inDto.getPageSize();
+        ShippingQuery query = new ShippingQuery().setMerchantId(userInfo.getMerchantId()).setKeyword(keyword).setShippingStatus(shippingStatus).setGroupIds(groupIds)
+                .setOverFlag(isOver).setOffset(offSet).setPageSize(inDto.getPageSize()).setSelfPickupCode(selfPickupCode).setSortByTeam(sortByTeam);
+        List<UserWaitOrderDTO> userInfoList = groupApiService.getMerchantGroupUserV2(query);
+        buildShippingUserDataV3(userInfoList,query);
+        boolean isSendExc = StringUtils.isNotEmpty(ids) && groupApiService.findOrderIsShipOverNew(groupIds);
+        log.info("商家发货,id:{},状态:{}", userInfo.getMerchantId(),isSendExc);
+        userInfoList.forEach(user -> {
+            UserWaitOrderLog userLog = new UserWaitOrderLog();
+            BeanUtils.copyProperties(user,userLog);
+            log.info("商家发货用户信息:{}", JSON.marshalIgnoreNull(userLog));
+        });
+        return OutDTO.ok().put("userShippingOrders", userInfoList).put("isSendExc", isSendExc).put("userInfo",userInfo).put("sortByTeam",sortByTeam)
+                .put("limitPickUp", groupApiService.isLimitMerchantPickUp(userInfo.getMerchantId()));
+    }
+
+    private boolean getMerchantDefaultSortValue(Object sortByTeam, Integer merchantId) {
+        if (sortByTeam != null) {
+            redisUtils.hset("merchant_default_sort_value", merchantId.toString(), sortByTeam);
+        } else {
+            Object defaultSortValue = redisUtils.hget("merchant_default_sort_value", merchantId.toString());
+            if (defaultSortValue != null) {
+                sortByTeam = defaultSortValue;
+            } else {
+                sortByTeam = false;
+            }
+        }
+        return (boolean) sortByTeam;
+    }
+
+    private void buildShippingUserDataV3(List<UserWaitOrderDTO> userInfoList, ShippingQuery param) {
+        if (CollectionUtils.isEmpty(userInfoList)) {
+            return;
+        }
+        List<Long> userIds = userInfoList.stream().map(u -> u.getId().longValue()).collect(Collectors.toList());
+        List<Integer> addrIds = userInfoList.stream().map(UserWaitOrderDTO::getShippingAddressId).collect(Collectors.toList());
+        ShippingQuery query = new ShippingQuery().setMerchantId(param.getMerchantId()).setUserIds(userIds).setAddrIds(addrIds)
+                .setGroupIds(param.getGroupIds()).setOverFlag(param.isOverFlag()).setSelfPickupCode(param.getSelfPickupCode())
+                .setShippingStatus(param.getShippingStatus());
+        List<UserOrderDTO> orders = groupApiService.getUserShippingOrderV2(query);
+        ShippingQuery numQuery = new ShippingQuery().setMerchantId(param.getMerchantId()).setUserIds(userIds);
+        List<TypeCountDTO> userNums = groupApiService.getMallOrderNumOfOverGroup(numQuery);
+        Map<String, Integer> numData = userNums.stream().collect(Collectors.toMap(TypeCountDTO::getType, TypeCountDTO::getNum));
+        userInfoList.forEach(userOrder -> {
+            buildShippingUserData(userOrder, orders, param.isSortByTeam());
+            if (!CollectionUtils.isEmpty(userOrder.getOrders())) {
+                Integer num = numData.get(userOrder.getId().toString());
+                userOrder.setHistoryOrderNum(num == null ? 0 : num);
+            }
+        });
+    }
+
+    private void buildShippingUserData(UserWaitOrderDTO userOrder, List<UserOrderDTO> orderList, boolean sortByTeam) {
+        List<UserOrderDTO> userOrders = orderList.stream().filter(o -> o.getUserId() == userOrder.getId().intValue()
+                        && o.getShippingAddressId() == userOrder.getShippingAddressId().intValue())
+                .sorted(Comparator.comparing(o -> o.getGroupInfoId() == null))
+                .collect(Collectors.toList());
+        if (userOrders.isEmpty()) {
+            return;
+        }
+        if (StringUtils.isEmpty(userOrder.getAddress())) {
+            UserOrderDTO orderDTO = userOrders.get(0);
+            userOrder.setAddress(orderDTO.getAddress());
+            userOrder.setPhone(orderDTO.getPhone());
+            userOrder.setLinkname(orderDTO.getLinkname());
+        }
+        List<Integer> userOrderIds = userOrders.stream().map(UserOrderDTO::getId).collect(Collectors.toList());
+        List<Carmichae> allCardGoods = groupApiService.selectGoodsByOrderIds(userOrderIds, 1);
+        Map<String, UserOrderDTO> dataMap = new LinkedHashMap<>();
+        Map<String, UserOrderDTO> mallOrders = new LinkedHashMap<>();
+        Set<Integer> orderIds = new HashSet<>(userOrderIds);
+        boolean refuseWait = false;
+        userOrder.setSendExc(true);
+        long shipEndTimeStamp=0;
+        for (UserOrderDTO order : userOrders) {
+            order.setSortByTeam(sortByTeam);
+            boolean isMallOrder = order.getGroupInfoId() == null;
+            if (!isMallOrder) {
+                List<Carmichae> cardGoods = allCardGoods.stream().filter(c -> c.getUserOrderId() == order.getId().intValue()).collect(Collectors.toList());
+                if (CollectionUtils.isEmpty(cardGoods)) {
+                    continue;
+                }
+                order.setCarmichaels(cardGoods);
+            }
+            boolean needShipment = isMallOrder && order.getServeStatus() != null && (order.getServeStatus() == 120 || order.getServeStatus() == 130);
+            boolean isOrderRefuse = order.getRefuseStatus() != null && order.getRefuseStatus() == 1;
+            if (!refuseWait && (isOrderRefuse || needShipment)) {
+                // 显示红点
+                refuseWait = true;
+                userOrder.setRefuseWait(true);
+            }
+            if (!order.isSendExc()) {
+                userOrder.setSendExc(false);
+                userOrder.setRefuseStatus(0);
+            }
+            if (order.isHasPickUpCode()) {
+                userOrder.setHasPickUpCode(true);
+            }
+            if (StringUtils.isEmpty(userOrder.getPickUpType()) && StringUtils.isNotEmpty(order.getPickUpType())) {
+                userOrder.setPickUpType(order.getPickUpType());
+            }
+            if (StringUtils.isEmpty(userOrder.getCourierNum()) && StringUtils.isNotEmpty(order.getCourierNum())) {
+                userOrder.setPickUpType(order.getPickUpType());
+                userOrder.setCourierNum(order.getCourierNum());
+                userOrder.setCurierCompany(order.getCurierCompany());
+            }
+
+            String name;
+            if (isMallOrder) {
+                if (order.getShipEndTimeStamp() > 0 && order.getShipEndTimeStamp() > shipEndTimeStamp) {
+                    shipEndTimeStamp = order.getShipEndTimeStamp();
+                }
+                name = order.getName() + "-" + order.getSpecs();
+                if (mallOrders.containsKey(name)) {
+                    UserOrderDTO existTypeOrder = mallOrders.get(name);
+                    existTypeOrder.setPurchaseCount(existTypeOrder.getPurchaseCount() + order.getPurchaseCount());
+                    List<UserOrderDTO.SimpleOrder> list = existTypeOrder.getSimpleOrders();
+                    list.add(new UserOrderDTO.SimpleOrder(order.getOrderNo(), order.getPurchaseCount()));
+                    existTypeOrder.setSimpleOrders(list);
+                } else {
+                    List<UserOrderDTO.SimpleOrder> simpleOrders = new ArrayList<>();
+                    simpleOrders.add(new UserOrderDTO.SimpleOrder(order.getOrderNo(), order.getPurchaseCount()));
+                    order.setSimpleOrders(simpleOrders);
+                    mallOrders.put(name, order);
+                }
+            } else {
+                name = order.getName() + "-" + order.getCode();
+                if (dataMap.containsKey(name)) {
+                    UserOrderDTO existTypeOrder = dataMap.get(name);
+                    List<Carmichae> list = existTypeOrder.getCarmichaels();
+                    list.addAll(order.getCarmichaels());
+                    existTypeOrder.setCarmichaels(list);
+                } else {
+                    dataMap.put(name, order);
+                }
+            }
+        }
+        userOrder.setShipEndTimeStamp(shipEndTimeStamp);
+        userOrder.setUserOrderIds(orderIds);
+        userOrder.setOrders(dataMap);
+        userOrder.setMallOrders(mallOrders);
+    }
+
+    @ApiLog(title = "累积发货的用户订单信息(包含拼豆订单)", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/waitShippingUser")
+    @ApiVersion(1)
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING,UserType.USER_ROLE_DELIVERY})
+    @ApiOperation("累积发货的用户订单信息(包含拼豆订单)")
+    public OutDTO waitShippingUserV2(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(user, MsgConstants.NEED_LOGIN);
+        int offSet = (inDto.getPageNo() - 1) * inDto.getPageSize();
+        String keyword = inDto.getString("keyword");
+        boolean payed = inDto.getBooleanParam("payed");
+        boolean sortByTeam = getMerchantDefaultSortValue(inDto.get("sortByTeam"), user.getMerchantId());
+        ShippingQuery query = new ShippingQuery().setMerchantId(user.getMerchantId()).setKeyword(keyword)
+                .setPageSize(inDto.getPageSize()).setOffset(offSet).setSortByTeam(sortByTeam).setPayed(payed);
+        List<UserWaitOrderDTO> userList = groupApiService.getWaitShippingUser(query);
+        if(!CollectionUtils.isEmpty(userList)){
+            List<Long> userIds = userList.stream().map(u -> u.getId().longValue()).collect(Collectors.toList());
+            List<Integer> addrIds = userList.stream().map(UserWaitOrderDTO::getShippingAddressId).collect(Collectors.toList());
+            ShippingQuery orderQuery = new ShippingQuery().setMerchantId(user.getMerchantId()).setUserIds(userIds).setAddrIds(addrIds).setPayed(payed);
+            List<UserOrderDTO> orders = groupApiService.getUserWaitShippingOrder(orderQuery);
+            userList.forEach(order -> buildShippingUserData(order, orders, query.isSortByTeam()));
+        }
+        return OutDTO.ok().put("waitShippingOrders", userList).put("userInfo",user).put("sortByTeam",sortByTeam);
+    }
+
+
+    @ApiLog(title = "精美卡片发货", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/nonEmptySend", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_DELIVERY})
+    @ApiOperation("精美卡片发货")
+    public OutDTO nonEmptySend(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo =  mineApiService.checkUserNew(inDto);
+        String userOrderIds = inDto.getString("userOrderIds");
+        if (StringUtils.isEmpty(userOrderIds)) {
+            return OutDTO.error500("订单为空!");
+        }
+        String[] orderIds = userOrderIds.split(",");
+        String courierNum = inDto.getString("courierNum");
+        String courierCompany = inDto.getString("curierCompany");
+        //添加顺丰一键发货逻辑
+        if(StringUtils.isNotEmpty(courierCompany) && "顺丰一键发货".equals(courierCompany) ){
+            inDto.put("userInfo",userInfo);
+            inDto.put("orderIds",userOrderIds);
+            return merchantApiService.createSfOrder(inDto);
+        }
+        courierCompany = StringUtils.isEmpty(courierCompany) ? ExpressUtils.getCompanyName(courierNum) : courierCompany;//快递公司
+        if (!ExpressUtils.checkExpressCode(courierNum)) {
+            return OutDTO.error(10059, "快递单号不符合规范[" + courierNum + "]");
+        }
+        CardGroupOrderInfo orderInfoCondition = new CardGroupOrderInfo();
+        orderInfoCondition.setCourierNum(courierNum);
+        orderInfoCondition.setCurierCompany(courierCompany);
+        CardGroupOrderInfo existOrder = cardGroupOrderInfoService.selectCardGroupOrderInfoById(Long.valueOf(orderIds[0]));
+        orderInfoCondition.setColumnsearch(" and cgoi.user_id != " + existOrder.getUserId());
+        List<CardGroupOrderInfo> existOrders = merchantApiService.selectByCourier(orderInfoCondition);
+        if (!CollectionUtils.isEmpty(existOrders)) {
+            return OutDTO.error(10050, "其他订单已经使用了该物流单号!")
+                    .put("orderInfo", existOrders.get(0));
+        }
+        List<Long> orderIdList = Arrays.stream(orderIds).map(Long::new).collect(Collectors.toList());
+        CardGroupOrderInfo orderInfo = new CardGroupOrderInfo();
+        orderInfo.setPickUpType("2");
+        orderInfo.setCourierNum(courierNum);
+        orderInfo.setCurierCompany(courierCompany);
+        orderInfo.setStatus(104L);
+        cardGroupOrderInfoService.updateOrderCourierByOrderIds(orderInfo,orderIdList);
+        List<TzyMerchantCenter> tzyMerchantCenterList = groupApiService.checkMerchantCenterByCourier(courierNum);
+        // 查询订单是否违规、如果违规更新违规状态
+        if(org.apache.commons.collections4.CollectionUtils.isNotEmpty(tzyMerchantCenterList)){
+            tzyMerchantCenterList.forEach(center ->{
+                String waringType = center.getWaringType();
+                if ("exquisite24".equals(waringType) && 1 == center.getStatus()) { // 风险
+                    groupApiService.resetGroupWaringType(center.getId(), 3);
+                } else if ("exquisite72".equals(waringType) && 2 == center.getStatus()) { // 违规
+                    groupApiService.resetGroupWaringType(center.getId(), 4);
+                }
+            });
+        }
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "商家添加订单备注", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/orderRemark", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    @ApiOperation("商家添加订单备注")
+    public OutDTO orderRemark(@RequestBody InDto inDto) {
+        com.tzy.pojo.card.CardGroupOrderInfo order = new com.tzy.pojo.card.CardGroupOrderInfo();
+        Object orderId = inDto.get("orderId");
+        order.setId(Long.valueOf(orderId.toString()));
+        order.setRemark(inDto.getString("remark"));
+        order.setUpdateTime(DateUtils.getTimestampNow());
+        suidRich.update(order);
+        return OutDTO.ok();
+    }
+
+    /**
+     * 获取商家app用户id
+     *
+     * @return
+     */
+    @ApiLog(title = "获取商家app用户信息", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @PostMapping(value = "/getMerAppUserId")
+    public OutDTO getMerAppUserId(@RequestBody InDto inDto) {
+        Integer merchantId = inDto.getIntegerParam("merchantId");
+        if (merchantId == null) {
+            return OutDTO.error500("商户id为空");
+        }
+        SimpleUser simpleUser = mineApiService.selectAppUserByMerchantId(merchantId);
+        AppAssert.notNull(simpleUser, "商家用户不存在");
+        return OutDTO.ok().put("merchantUserId", simpleUser.getId()).put("merchantAppUser", simpleUser);
+    }
+
+    /**
+     * 商家隐藏评论
+     *
+     * @return
+     */
+    @ApiLog(title = "商家隐藏评论", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ResponseBody
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    @RequestMapping(value = "/deleteEvaluation", method = RequestMethod.POST)
+    public OutDTO deleteEvaluation(@RequestBody InDto inDto) {
+        mineApiService.checkUserNew(inDto);
+        Object id = inDto.get("id");
+        if(id==null){
+            return OutDTO.error500("id为空");
+        }
+        EvaluationRecord evaluationRecord = new EvaluationRecord();
+        evaluationRecord.setId(Integer.valueOf(id.toString()));
+        evaluationRecord.setStatus(0);
+        suidRich.update(evaluationRecord);
+        return OutDTO.ok();
+    }
+
+    /**
+     * 商家开票
+     */
+    @ApiLog(title = "商家开票",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("商家开票,参数:invoiceId")
+    @ResponseBody
+    @RequestMapping(value = "/openInvoice", method = RequestMethod.POST)
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    public OutDTO openInvoice(@RequestBody InDto inDto) {
+        mineApiService.checkUserNew(inDto);
+        Integer invoiceId = (Integer) inDto.get("invoiceId");
+        if (invoiceId == null) {
+            return OutDTO.error500("invoiceId为空");
+        }
+
+        AppUserInvoiceRecord condition = new AppUserInvoiceRecord();
+        condition.setId(invoiceId.longValue());
+        condition.setStatus(1);
+        suidRich.update(condition);
+        return OutDTO.ok();
+    }
+
+    /**
+     * 商家详情
+     */
+    @ApiLog(title = "商家详情",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("商家详情,参数:id")
+    @ResponseBody
+    @RequestMapping(value = "/detail", method = RequestMethod.POST)
+    //@RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    public OutDTO merchantDetail(@RequestBody InDto inDto) throws Exception {
+        if (inDto == null || inDto.get("id") == null) {
+            return OutDTO.error500("参数为空");
+        }
+        //mineApiService.checkUserNew(inDto);
+        Long id = Long.valueOf(inDto.getString("id")) ;
+        TzyMerchantArchives merchantArchives = new TzyMerchantArchives();
+        merchantArchives.setMerchantId(id);
+        merchantArchives.setDelFlag(0);
+        merchantArchives.setStatus(3);
+        Condition condition=new ConditionImpl();
+        condition.orderBy("id", OrderType.ASC);
+        List<TzyMerchantArchives> archivesList = suidRich.select(merchantArchives,condition);
+        TzyMerchantArchives merchantArchive=null;
+        if(!CollectionUtils.isEmpty(archivesList)){
+            List<TzyMerchantArchives> defaltList=archivesList.stream().filter(a ->a.getDefult()!=null&&a.getDefult()).collect(Collectors.toList());
+            if(!CollectionUtils.isEmpty(defaltList)){
+                merchantArchive=defaltList.get(0);
+            }else {
+                merchantArchive=archivesList.get(0);
+            }
+        }
+
+        if (merchantArchive != null && StringUtils.isNotEmpty(merchantArchive.getPicList())) {
+            merchantArchive.setPicList(AESUtil.encryptData(merchantArchive.getPicList(), Constants.AES_TOKEN_PASSWORD));
+        }
+        //boolean delFlg = Boolean.parseBoolean(inDto.getString("delFlg")); // 删除缓存标记
+        MerchantScoreDTO merchantScoreDTO = tzyMerchantAssessService.getMerchantMemberInfoV3(id);
+        return OutDTO.ok()
+                .put("merchantArchives",merchantArchive)
+                .put("merchantBond", merchantApiService.getMerchantBond(id))
+                .put("merchantScore", merchantScoreDTO);
+    }
+
+    /**
+     * 修改商家组团排序
+     */
+    @ApiLog(title = "修改商家排序",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("修改商家排序,参数:id,sortValue")
+    @ResponseBody
+    @RequestMapping(value = "/editMerchantSort", method = RequestMethod.POST)
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    public OutDTO editMerchantSort(@RequestBody InDto inDto) {
+        if (inDto==null||inDto.get("id") == null|| inDto.get("sortValue")==null) {
+            return OutDTO.error500("参数为空");
+        }
+
+        CardGroupInfo cardGroupInfo = new CardGroupInfo();
+        cardGroupInfo.setId(Long.valueOf(inDto.getString("id")));
+        cardGroupInfo.setMerchantSort((Integer) inDto.get("sortValue"));
+        suidRich.update(cardGroupInfo);
+        return  OutDTO.ok();
+    }
+
+    /**
+     * 商家拉黑用户
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "商家拉黑用户", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(1.0)
+    @ApiOperation("商家拉黑用户")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    @PostMapping("/pullBackUser")
+    public OutDTO pullBackUser(@RequestBody InDto inDto) {
+        if(inDto.get("userId")==null){
+            return OutDTO.error500("参数为空");
+        }
+        AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+        MerchantInfo merchantInfo = merchantApiService.getMerchantInfoByUsername(appUserInfoDto.getAccount());
+        AppMerchantFans appMerchantFans = new AppMerchantFans();
+        appMerchantFans.setUserId(Long.valueOf(inDto.getString("userId")));
+        appMerchantFans.setMerchantId(merchantInfo.getId().longValue());
+        appMerchantFans.setType(Constants.FANS_TYPE_MERCHANT_DISLIKE);
+        if(inDto.get("status")==null||Constants.STATUS_OK.equals(inDto.getString("status"))){
+            if(merchantApiService.checkUserHaveSoldOrder(merchantInfo.getId(),(Integer)inDto.get("userId"))){
+                return OutDTO.error500("存在订单未完成,无法屏蔽!");
+            }
+            List<AppMerchantFans> existFans = suidRich.select(appMerchantFans);
+            if(existFans.isEmpty()){
+                appMerchantFans.setCreateTime(new Date());
+                suidRich.insert(appMerchantFans);
+            }
+        }else{
+            suidRich.delete(appMerchantFans);
+        }
+        redisUtils.del("user_dislike_merchant:"+inDto.getString("userId"));
+        return OutDTO.ok();
+    }
+
+
+    /**
+     * 商家拉黑用户
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "商家拉黑用户[限制支付]", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.0)
+    @ApiOperation("商家拉黑用户-v2[限制支付]")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    @PostMapping("/v2/pullBackUser")
+    public OutDTO pullBackUserV2(@RequestBody InDto inDto) {
+        if(inDto.get("userId")==null){
+            return OutDTO.error500("参数为空");
+        }
+       return merchantApiService.pullBackUserV2(inDto);
+    }
+
+    /**
+     * 获取商家黑名单用户
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "获取商家黑名单用户", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(1.0)
+    @ApiOperation("获取商家黑名单用户")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    @PostMapping("/getBackUser")
+    public OutDTO getBackUser(@RequestBody InDto inDto) {
+        AppUserInfoDto appUserInfoDto = mineApiService.checkUserNew(inDto);
+        MerchantInfo merchantInfo = merchantApiService.getMerchantInfoByUsername(appUserInfoDto.getAccount());
+        List<AppUserInfoDto> users=mineApiService.getBackUserByMerchant(merchantInfo.getId(),inDto.getPageNo(),
+                inDto.getPageSize(),inDto.getString("keyword"));
+        return OutDTO.ok().put("users",users);
+    }
+
+    /**
+     * 获取商家黑名单用户
+     *
+     * @param inDto
+     * @return
+     */
+    @ApiLog(title = "获取商家黑名单用户-v2", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.0)
+    @ApiOperation("获取商家黑名单用户-v2")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    @PostMapping("/v2/getBackUser")
+    public OutDTO getBackUserV2(@RequestBody InDto inDto) {
+       return merchantApiService.getBackUserV2(inDto);
+    }
+
+    @ApiLog(title = "热门商家V2", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/hot")
+    @ApiOperation("热门商家")
+    @ApiVersion(1.0)
+    public OutDTO hotMerchantV2(@RequestBody InDto inDto) {
+        if(inDto.getString("ids")==null){
+            return OutDTO.error500("参数为空");
+        }
+        List<Integer> ids = Arrays.stream(inDto.getString("ids").split(",")).map(Integer::valueOf).collect(Collectors.toList());
+        List<SimpleMerchantInfo> merchants=merchantApiService.getHotMerchants(ids,true);
+        return OutDTO.ok().put("merchants",merchants);
+    }
+
+
+    @ApiLog(title = "根据条件(userId)查询商家id", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/id/user")
+    @ApiOperation("根据条件(userId)查询商家id")
+    public OutDTO getMerchantIdByUserId(@RequestBody InDto inDto) {
+        Integer userId = (Integer) inDto.get("userId");
+        if(userId ==null){
+            return OutDTO.error500("参数为空");
+        }
+        Integer merchantId=merchantApiService.getMerchantIdByUserId(userId);
+        return OutDTO.ok().put("merchantId",merchantId);
+    }
+
+    @ApiLog(title = "根据条件(userId)查询商家信息", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/info/user")
+    @ApiOperation("根据条件(userId)查询商家id")
+    public OutDTO getMerchantByUserId(@RequestBody InDto inDto) {
+        Integer userId = (Integer) inDto.get("userId");
+        if(userId ==null){
+            return OutDTO.error500("参数为空");
+        }
+        SimpleMerchantInfo merchant=merchantApiService.getMerchantByUserId(userId);
+        return OutDTO.ok().put("merchant",merchant);
+    }
+
+    @ApiLog(title = "根据type查询商家信息", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/type")
+    @ApiOperation("根据type查询商家信息")
+    public OutDTO getMerchantByHotType(@RequestBody InDto inDto) {
+        String hotType = inDto.getString("hotType");
+        List<SimpleMerchantInfo> merchants=merchantApiService.getMerchantByType(hotType);
+        return OutDTO.ok().put("merchants",merchants);
+    }
+
+    @ApiLog(title = "店铺综合评分(新)", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/info/assessNew")
+    @ApiOperation("店铺综合评分(新)")
+    public OutDTO getMerchantMemberInfoNew(@RequestBody InDto inDto) {
+        Integer merchantId = inDto.getIntegerParam("merchantId");
+        if(merchantId ==null){
+            return OutDTO.error500("merchantId为空");
+        }
+        MerchantScoreDTO merchantScoreDTO = tzyMerchantAssessService.getMerchantMemberInfoNew(merchantId.longValue());
+        return OutDTO.ok().put("merchantScoreDTO",merchantScoreDTO);
+    }
+
+    @ApiLog(title = "店铺综合评分", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/info/assess/v3")
+    @ApiOperation("店铺综合评分")
+    public OutDTO getMerchantMemberInfoV3(@RequestBody InDto inDto) {
+        if(inDto == null){
+            return OutDTO.error500("参数为空");
+        }
+        if(inDto.getIntegerParam("merchantId") == null){
+            return OutDTO.error500("merchantId为空");
+        }
+        Long merchantId = inDto.getIntegerParam("merchantId").longValue();
+        MerchantScoreDTO merchantScoreDTO = tzyMerchantAssessService.getMerchantMemberInfoV3(merchantId);
+        return OutDTO.ok().put("merchantScoreDTO",merchantScoreDTO);
+    }
+
+    @ApiLog(title = "热门商家", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/hotMerchant")
+    @ApiOperation("热门商家")
+    public OutDTO hotMerchantV3(@RequestBody InDto inDto) {
+        Integer limit = inDto.getIntegerDefault("limit", 20);
+        List<SimpleMerchantInfo> merchants = merchantApiService.getHotMerchantV3(limit);
+        return OutDTO.ok().put("merchants", merchants);
+    }
+
+    @ApiLog(title = "热门新商家", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(1.0)
+    @PostMapping(value = "/hotNew")
+    @ApiOperation("热门新商家")
+    public OutDTO hotNewMerchant(@RequestBody InDto inDto) {
+        Integer limit = inDto.getIntegerDefault("limit", 20);
+        List<SimpleMerchantInfo> merchants = merchantApiService.getHotNewMerchants(limit);
+        return OutDTO.ok().put("merchants", merchants);
+    }
+
+
+    @ApiLog(title = "需要发货(已发货)的精美卡片用户", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/gift/card")
+    @ApiVersion(2.3)
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_DELIVERY})
+    @ApiOperation("需要发货(已发货)的精美卡片用户")
+    public OutDTO getGiftCardUser(@RequestBody InDto inDto) {
+        UserInfo userInfo = UserUtils.getSimpleUserInfo();
+        if(userInfo ==null||userInfo.getMerchantId()==null){
+            return OutDTO.error500("权限不足");
+        }
+        NonEmptyQuery nonEmptyQuery = inDto.buildParam(new NonEmptyQuery());
+        nonEmptyQuery.setMerchantId(userInfo.getMerchantId()).setPageSize(inDto.getPageSize()).setOffset(inDto.getOffset());
+        List<SimpleUserShipDTO> userShips;
+        if(nonEmptyQuery.isWaitApply()){
+            userShips= cardGroupOrderInfoService.getWaitApplyUserCards(nonEmptyQuery);
+        }else {
+            if(nonEmptyQuery.isShippedFlag()){
+                userShips= cardGroupOrderInfoService.getShippedCardByUser(nonEmptyQuery);
+            }else {
+                userShips= cardGroupOrderInfoService.getNonEmptyCardByUserV3(nonEmptyQuery);
+            }
+        }
+        return OutDTO.ok().put("userShips",userShips);
+    }
+
+    @ApiLog(title = "商家名下精美卡片类型", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/card/select")
+    @ApiVersion(2.3)
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_DELIVERY, UserType.USER_ROLE_PUBLICITY})
+    @ApiOperation("商家名下精美卡片类型")
+    public OutDTO merchantSelectCard(@RequestBody InDto inDto) {
+        UserInfo userInfo = UserUtils.getSimpleUserInfo();
+        if(userInfo ==null||userInfo.getMerchantId()==null){
+            return OutDTO.error500("权限不足");
+        }
+        List<GiftCardManage> giftCards = merchantApiService.selectGiftCard(userInfo.getMerchantId(), null);
+        return OutDTO.ok().put("cards",giftCards);
+    }
+
+
+    @ApiLog(title = "商家申请发货", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/submit/apply")
+    @ApiVersion(2.3)
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING, UserType.USER_ROLE_DELIVERY})
+    @ApiOperation("商家申请发货")
+    public OutDTO submitApplyCard(@RequestBody InDto inDto) {
+        UserInfo userInfo = UserUtils.getSimpleUserInfo();
+        if(userInfo ==null||userInfo.getMerchantId()==null){
+            return OutDTO.error500("权限不足");
+        }
+        NonEmptyQuery nonEmptyQuery = inDto.buildParam(new NonEmptyQuery());
+        nonEmptyQuery.setMerchantId(userInfo.getMerchantId()).setPageSize(100).setOffset(0);
+        List<SimpleUserShipDTO> userShips= cardGroupOrderInfoService.getWaitApplyUserCards(nonEmptyQuery);
+        userShips.parallelStream().forEach(us -> {
+            try {
+                AppUserPoint shipRecord = new AppUserPoint().setUserId(us.getId()).setType(Constants.POINT_TYPE_GIFT_CARD_PRE + us.getCardId())
+                        .setMerchantId(userInfo.getMerchantId()).setRefId(us.getCardId());
+                cardGroupOrderInfoService.shippingPayV3(shipRecord, BigDecimal.ZERO, us.getWaitShippedNum(), null, null);
+            }catch (Exception e){
+                log.info("申请失败,需重试:{}",us,e);
+            }
+        });
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "商家标签绑定列表", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(1.0)
+    @PostMapping(value = "/getByTagIds")
+    @ApiOperation("商家标签绑定列表")
+    public OutDTO getByTagIds(@RequestBody InDto inDto) {
+        String tagIds = inDto.getString("tagIds"); // 商家标签ID 多个逗号分隔
+        if(Strings.isEmpty(tagIds)){
+            return OutDTO.error500("tagIds为空");
+        }
+        List<TzyMerchantTagDTO> merchantTagList = merchantApiService.getMerchantByTagIds(tagIds.split(","));
+        return OutDTO.ok().put("merchantTagList", merchantTagList);
+    }
+
+    @ApiLog(title = "商家标签top3", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(1.0)
+    @PostMapping(value = "/getMerchantTagTop3")
+    @ApiOperation("商家标签top3")
+    public OutDTO getMerchantTagTop3(@RequestBody InDto inDto) {
+        Integer merchantId = (Integer)inDto.get("merchantId"); // 商家ID
+        if(merchantId == null){
+            return OutDTO.error500("tagIds为空");
+        }
+        List<TzyMerchantTagDTO> merchantTagList = merchantApiService.getMerchantTagTop3(merchantId);
+        return OutDTO.ok().put("merchantTagList", merchantTagList);
+    }
+
+    @ApiLog(title = "新增商家拼豆名称", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(1.0)
+    //@PostMapping(value = "/edit/point/msg")
+    @ApiOperation("修改/新增商家拼豆名称")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    public OutDTO editMerPointMsg(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if (user == null) {
+            return OutDTO.error500("权限不足!");
+        }
+        String showMsg = inDto.getString("showMsg");
+        if (StringUtils.isEmpty(showMsg)) {
+            return OutDTO.error500("参数为空!");
+        }
+        if(!StringUtils.isValidChineseEnglishOnly(showMsg)){
+            return OutDTO.error500("拼豆名称不能包含特殊字符!");
+        }
+        if (StringUtils.isNotEmpty(showMsg) && !QiniuUtil.checkText(showMsg)) {
+            return OutDTO.error500("存在不合规的文字!");
+        }
+        merchantApiService.updatePointMsg(user.getMerchantId(), showMsg);
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "获取商家信息", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(1.0)
+    @PostMapping(value = "/info")
+    @ApiOperation("获取商家信息")
+    public OutDTO getMerchant(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if (user == null || Objects.isNull(user.getMerchantId())) {
+            return OutDTO.error500("权限不足!");
+        }
+        MerchantInfo merchantInfo = merchantApiService.getMerchantInfo(user.getMerchantId());
+        return OutDTO.ok()
+                .put("merchant",  DozerUtils.map(merchantInfo,SimpleMerchantInfo.class))
+                .put("shopAmount", merchantApiService.sumMerchantAmount(user.getMerchantId(), "shop"))
+                .put("oneKeyAmount", merchantApiService.sumMerchantAmount(user.getMerchantId(), "oneKey"))
+                .put("hasCourierCompany", expressService.checkMerCourierCompany(inDto));
+    }
+
+    @ApiLog(title = "批量修改商城订单累计", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.0)
+    @PostMapping(value = "/order/batch/waiting")
+    @ApiOperation("批量修改商城订单累计")
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    public OutDTO updateOrderWaitShipping(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if (user == null) {
+            return OutDTO.error500("权限不足!");
+        }
+        int num = merchantApiService.updateOrderWaitShipping(user.getMerchantId());
+        return OutDTO.ok().put("num",  num);
+    }
+
+    @ApiLog(title = "批量修改商城订单累计", businessType = BusinessType.SEARCH)
+    @ApiVersion(2.0)
+    @ResponseBody
+    @PostMapping(value = "/search")
+    public OutDTO searchMerchants(@RequestBody InDto inDto){
+        String keyword = inDto.getString("keyword");
+        List<SimpleMerchantInfo> merchants=merchantApiService.searchMerchants(keyword);
+        return OutDTO.ok().put("merchants",merchants);
+    }
+
+    @ApiLog(title = "获取生态购申请开票金额",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("获取生态购申请开票金额")
+    @ApiVersion(1.0)
+    @ResponseBody
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    @RequestMapping(value = "/getEcologyInvoice", method = RequestMethod.POST)
+    public OutDTO getEcologyInvoice(@RequestBody InDto inDto) {
+        UserInfo userInfo = UserUtils.getSimpleUserInfo(true);
+        if (userInfo == null || userInfo.getMerchantId()==null) {
+            return OutDTO.error500("权限不足!");
+        }
+        // 生态购开票总金额
+        BigDecimal invoiceAmount = cardGroupOrderInfoService.getEcologyAmount(userInfo.getId());
+        // 生态购开票订单
+        PageInfo<SimpleOrderDTO> orderPage = cardGroupOrderInfoService.getEcologyOrder(inDto.getPageNo(), inDto.getPageSize(), userInfo.getId());
+        return OutDTO.ok()
+                .put("invoiceAmount", invoiceAmount)
+                .put("orderPage", orderPage);
+    }
+
+    /**
+     * 生态购开票
+     */
+    @ApiLog(title = "生态购开票",businessType = BusinessType.SEARCH,indto = "{{inDto}}")
+    @ApiOperation("生态购开票")
+    @ResponseBody
+    @RequestMapping(value = "/openEcologyInvoice", method = RequestMethod.POST)
+    @RequireRoles(value = {UserType.USER_ROLE_SHIPPING})
+    public OutDTO openEcologyInvoice(@RequestBody InDto inDto) {
+        UserInfo userInfo = UserUtils.getSimpleUserInfo(true);
+        if (userInfo == null || userInfo.getMerchantId()==null) {
+            return OutDTO.error500("权限不足!");
+        }
+        if(inDto.get("orderList") == null){
+            return OutDTO.error500("开票订单为空!");
+        }
+        if(inDto.get("totalAmount") == null){
+            return OutDTO.error500("开票总金额为空!");
+        }
+        if(inDto.get("invoice") == null){
+            return OutDTO.error500("发票信息为空!");
+        }
+        //List<SysCashoutOrderList> orderList = (List<SysCashoutOrderList>) inDto.get("orderList");
+        Gson gson = new Gson();
+        JsonElement jsonElement = JsonParser.parseString(gson.toJson(inDto.get("orderList")));
+        List<SysCashoutOrderList> orderList = null;
+        if (jsonElement.isJsonArray()) {
+            JsonArray jsonArray = jsonElement.getAsJsonArray();
+
+            // 将 JsonArray 转换为 List<SysCashoutOrderList>
+            orderList = gson.fromJson(jsonArray, new TypeToken<List<SysCashoutOrderList>>(){}.getType());
+        }
+        BigDecimal totalAmount = new BigDecimal(inDto.get("totalAmount").toString());
+        String invoice = inDto.get("invoice").toString();
+        // 开票订单总数、总金额、开票信息
+        merchantApiService.openEcologyInvoice(userInfo.getMerchantId(), orderList, totalAmount, invoice);
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "商家详情排行榜",businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping("/rankings")
+    public OutDTO getMerchantRankings(@RequestBody MerchantInfo merchantInfo){
+        if(merchantInfo.getId() == null){
+            return OutDTO.error500("商家id为空");
+        }
+        MerchantRankingsDTO rankings = merchantApiService.getDetailRank(merchantInfo.getId());
+        return OutDTO.ok().put("rankings", rankings);
+    }
+
+    @ApiLog(title = "热门商家", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/hot")
+    @ApiOperation("热门商家")
+    @ApiVersion(3.2)
+    public OutDTO hotMerchantsV4() {
+        UserInfo userInfo = UserUtils.getSimpleUserInfo(false);
+        Long userId = null;
+        if(userInfo != null){
+            userId = userInfo.getId().longValue();
+        }
+        List<MerchantRankDetailDTO> hotMerchants = merchantApiService.getHotMerchantV4(userId);
+        return OutDTO.ok().put("hotMerchants", hotMerchants);
+    }
+
+    @ApiLog(title = "热门新商家", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/hotNew")
+    @ApiOperation("热门新商家")
+    @ApiVersion(3.2)
+    public OutDTO hotNewMerchantsV4() {
+        UserInfo userInfo = UserUtils.getSimpleUserInfo(false);
+        Long userId = null;
+        if(userInfo != null){
+            userId = userInfo.getId().longValue();
+        }
+        List<MerchantRankDetailDTO> newHotMerchants = merchantApiService.getHotNewMerchantsV4(userId);
+        return OutDTO.ok().put("newHotMerchants", newHotMerchants);
+    }
+
+    @ApiLog(title = "人气榜", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/popular")
+    @ApiOperation("人气榜")
+    @ApiVersion(3.0)
+    public OutDTO getPopularMerchantV4(@RequestBody CompositeRankDTO compositeRankDTO) {
+        UserInfo userInfo = UserUtils.getSimpleUserInfo(false);
+        Long userId = null;
+        if(userInfo != null){
+            userId = userInfo.getId().longValue();
+        }
+        if(compositeRankDTO == null || compositeRankDTO.getRuleId() == null){
+            return OutDTO.error500("ruleId为空!");
+        }
+        List<MerchantRankDetailDTO> popularMerchants = merchantApiService.getPopularMerchantsV4(userId, compositeRankDTO.getRuleId());
+        return OutDTO.ok().put("popularMerchants", popularMerchants);
+    }
+
+    @ApiLog(title = "人气榜", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/popular")
+    @ApiOperation("人气榜")
+    @ApiVersion(3.1)
+    public OutDTO getPopularMerchantV5(@RequestBody CompositeRankDTO compositeRankDTO) {
+        UserInfo userInfo = UserUtils.getSimpleUserInfo(false);
+        Long userId = null;
+        if(userInfo != null){
+            userId = userInfo.getId().longValue();
+        }
+        if(compositeRankDTO == null || compositeRankDTO.getRuleId() == null){
+            return OutDTO.error500("ruleId为空!");
+        }
+        List<MerchantRankDetailDTO> popularMerchants = merchantApiService.getPopularMerchantsV5(userId, compositeRankDTO.getRuleId());
+        return OutDTO.ok().put("popularMerchants", popularMerchants);
+    }
+
+    @ApiLog(title = "人气榜", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/popular")
+    @ApiOperation("人气榜")
+    @ApiVersion(3.2)
+    public OutDTO getPopularMerchantV6(@RequestBody CompositeRankDTO compositeRankDTO) {
+        UserInfo userInfo = UserUtils.getSimpleUserInfo(false);
+        Long userId = null;
+        if(userInfo != null){
+            userId = userInfo.getId().longValue();
+        }
+        if(compositeRankDTO == null || compositeRankDTO.getRuleId() == null){
+            return OutDTO.error500("ruleId为空!");
+        }
+        List<MerchantRankDetailDTO> popularMerchants = merchantApiService.getPopularMerchantsV6(userId, compositeRankDTO.getRuleId());
+        return OutDTO.ok().put("popularMerchants", popularMerchants);
+    }
+
+    @ApiLog(title = "商家详情排行榜",businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(3.1)
+    @PostMapping("/rankings")
+    public OutDTO getMerchantRankingsV5(@RequestBody MerchantInfo merchantInfo){
+        if(merchantInfo.getId() == null){
+            return OutDTO.error500("商家id为空");
+        }
+        MerchantRankingsDTO rankings = merchantApiService.getDetailRankV5(merchantInfo.getId());
+        return OutDTO.ok().put("rankings", rankings);
+    }
+
+    @ApiLog(title = "商家详情排行榜",businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(3.2)
+    @PostMapping("/rankings")
+    public OutDTO getMerchantRankingsV6(@RequestBody MerchantInfo merchantInfo){
+        if(merchantInfo.getId() == null){
+            return OutDTO.error500("商家id为空");
+        }
+        MerchantRankingsDTO rankings = merchantApiService.getDetailRankV6(merchantInfo.getId());
+        return OutDTO.ok().put("rankings", rankings);
+    }
+
+    @ApiLog(title = "商家中心统计",businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(1.0)
+    @PostMapping("/center/count")
+    public OutDTO getMerchantCenterCount(){
+        UserInfo userInfo = UserUtils.getSimpleUserInfo(true);
+        Integer merchantId = null;
+        if (userInfo != null && userInfo.getMerchantId() != null) {
+            merchantId = userInfo.getMerchantId();
+        }
+        MerchantCenterCountDTO count = merchantApiService.getMerchantCenterCount(merchantId);
+        return OutDTO.ok().put("count", count);
+    }
+}

+ 88 - 0
poyi-app/src/main/java/com/tzy/controller/pay/PaymentController.java

@@ -0,0 +1,88 @@
+package com.tzy.controller.pay;
+
+import com.tzy.annotation.ApiLog;
+import com.tzy.common.dto.InDto;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.enums.BusinessType;
+import com.tzy.pay.service.IPaymentBaseService;
+import com.tzy.sportcard.api.domain.AppUserInfoDto;
+import com.tzy.sportcard.api.service.MineApiService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 描述: 支付相关
+ */
+@Slf4j
+@RestController
+@RequestMapping("/api/payment")
+public class PaymentController {
+
+    @Autowired
+    private MineApiService mineApiService;
+
+    @Autowired
+    private IPaymentBaseService paymentBaseService;
+
+    /**
+     * 用户绑定银行卡信息列表
+     */
+    @ApiLog(title = "用户绑定银行卡信息列表:支持免密支付标记", businessType = BusinessType.INSERT)
+    @PostMapping( "/bindBankInfos")
+    @ResponseBody
+    public OutDTO bindBankInfos(@RequestBody InDto inDto) {
+        checkUser(inDto);
+        return paymentBaseService.bindBankInfos(inDto);
+    }
+
+    /**
+     * 是否有绑定免密支付标记的银行卡
+     * 如果有则返回绑定免密支付银行卡列表
+     */
+    @ApiLog(title = "是否有绑定免密支付标记的银行卡", businessType = BusinessType.SEARCH)
+    @PostMapping( "/hasBindBankFreePay")
+    @ResponseBody
+    public OutDTO hasBindBankFreePay(@RequestBody InDto inDto) {
+        checkUser(inDto);
+        return paymentBaseService.hasBindBankFreePay(inDto);
+    }
+    /**
+     * 用户绑定银行卡信息
+     */
+    @ApiLog(title = "用户绑定银行卡信息:支持免密支付标记", businessType = BusinessType.UPDATE)
+    @PostMapping( "/v2/bindBank")
+    @ResponseBody
+    public OutDTO bindBankV2(@RequestBody InDto inDto) {
+        checkUser(inDto);
+        return paymentBaseService.bindBankV2(inDto);
+    }
+    /**
+     * 用户绑定银行卡信息编辑
+     */
+    @ApiLog(title = "用户绑定银行卡信息编辑:支持免密支付标记", businessType = BusinessType.UPDATE)
+    @PostMapping( "/updateBankFreePay")
+    @ResponseBody
+    public OutDTO updateBankFreePay(@RequestBody InDto inDto) {
+        checkUser(inDto);
+        return paymentBaseService.updateBankFreePay(inDto);
+    }
+
+    /**
+     * 验证用户
+     * @param inDto
+     * @return
+     */
+    private void checkUser(InDto inDto) {
+        if (null == inDto){
+            throw new RuntimeException("参数不能为空");
+        }
+        OutDTO checkUser = mineApiService.checkUser(inDto);
+        if (!checkUser.isSuccess()){
+            throw new RuntimeException(checkUser.getMsg());
+        }
+        AppUserInfoDto appUserInfoDto = (AppUserInfoDto) checkUser.get("userInfo");
+        inDto.put("appUserInfoDto", appUserInfoDto);
+        inDto.setUserId(appUserInfoDto.getId());//重新设置userid
+    }
+}

+ 47 - 0
poyi-app/src/main/java/com/tzy/controller/permissions/AppMerPermissionsController.java

@@ -0,0 +1,47 @@
+package com.tzy.controller.permissions;
+
+
+import com.tzy.annotation.ApiLimitRule;
+import com.tzy.annotation.RequireRoles;
+import com.tzy.common.dto.OutDTO;
+import com.tzy.common.utils.UserType;
+import com.tzy.framework.web.domain.LimitRule;
+import com.tzy.permissions.service.AppMerPermissionsService;
+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.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * app商家权限
+ */
+@Api(value = "app商家权限")
+@RestController
+@RequestMapping("/api/mer/permissions")
+@Slf4j
+public class AppMerPermissionsController {
+
+    @Autowired
+    private AppMerPermissionsService appMerPermissionsService;
+
+    /**
+     * 商家权限查询
+     * @return
+     */
+    @ApiOperation( value = "商家权限查询")
+    @RequestMapping(value = "/query", method = RequestMethod.POST)
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁!")
+    @ResponseBody
+    public List<String> getMerPermissions() {
+       return appMerPermissionsService.getMerPermissions();
+    }
+
+
+
+}

+ 2314 - 0
poyi-app/src/main/java/com/tzy/controller/prize/AppActController.java

@@ -0,0 +1,2314 @@
+package com.tzy.controller.prize;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.github.pagehelper.PageInfo;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
+import com.tzy.annotation.ApiLimitRule;
+import com.tzy.annotation.ApiLog;
+import com.tzy.annotation.RequireRoles;
+import com.tzy.app.domain.act.AmountActResult;
+import com.tzy.app.domain.act.ShareActResult;
+import com.tzy.app.dto.order.OrderSubmitDTO;
+import com.tzy.app.dto.order.PrizeOrderParam;
+import com.tzy.common.annotation.SensitiveData;
+import com.tzy.common.config.handle.ApiVersion;
+import com.tzy.common.constant.Constants;
+import com.tzy.common.constant.MsgConstants;
+import com.tzy.common.constant.NoticeMsgModel;
+import com.tzy.common.core.domain.entity.SysDictData;
+import com.tzy.common.dto.*;
+import com.tzy.common.dto.act.*;
+import com.tzy.common.dto.group.ActReportDTO;
+import com.tzy.common.enums.BusinessType;
+import com.tzy.common.exception.AppAssert;
+import com.tzy.common.exception.ServiceException;
+import com.tzy.common.utils.*;
+import com.tzy.common.utils.bean.DozerUtils;
+import com.tzy.common.utils.bean.JSONTools;
+import com.tzy.common.utils.http.forest.SaasForestClient;
+import com.tzy.common.utils.http.forest.param.DrawOrderDTO;
+import com.tzy.common.utils.http.forest.param.PayReqParam;
+import com.tzy.common.utils.http.forest.param.ResultDTO;
+import com.tzy.coupon.card.service.ITzyCardBaseInfoService;
+import com.tzy.dto.SimplePrizeRecord;
+import com.tzy.dto.local.card.CardQuery;
+import com.tzy.framework.util.RedisUtils;
+import com.tzy.framework.web.domain.LimitRule;
+import com.tzy.service.MallOrderService;
+import com.tzy.sportcard.api.bean.act.*;
+import com.tzy.sportcard.api.bean.param.PointDetailParam;
+import com.tzy.sportcard.api.domain.AppUserInfoDto;
+import com.tzy.sportcard.api.domain.GroupInfo;
+import com.tzy.sportcard.api.dto.prize.AppActManageDTO;
+import com.tzy.sportcard.api.dto.prize.AppActPrizeDTO;
+import com.tzy.sportcard.api.dto.prize.PublicPrizeCodeDTO;
+import com.tzy.sportcard.api.dto.prize.UserActPointDTO;
+import com.tzy.sportcard.api.service.AsyncAppService;
+import com.tzy.sportcard.api.service.GroupApiService;
+import com.tzy.sportcard.api.service.MineApiService;
+import com.tzy.sportcard.base.service.CommonCacheService;
+import com.tzy.sportcard.group.domain.CardGroupOrderInfo;
+import com.tzy.sportcard.group.service.AppActService;
+import com.tzy.sportcard.group.service.ICardGroupOrderInfoService;
+import com.tzy.sportcard.group.service.impl.AppActServiceImpl;
+import com.tzy.sportcard.point.domain.AppUserPointRecord;
+import com.tzy.system.domain.TzyShippingAddress;
+import com.tzy.system.service.ITzyShippingAddressService;
+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.beans.factory.annotation.Value;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.bind.annotation.*;
+import org.teasoft.bee.osql.*;
+import org.teasoft.bee.osql.annotation.Ignore;
+import org.teasoft.honey.osql.core.ConditionImpl;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author by po'yi
+ * @Classname AppActController
+ * @Description
+ * @Date 2022/8/3 13:24
+ */
+@Api(value = "app活动相关")
+@RestController
+@RequestMapping("/api/{version}/act")
+@Slf4j
+@CrossOrigin(allowCredentials = "true")
+public class AppActController {
+    @Autowired
+    private MineApiService mineApiService;
+    @Autowired
+    private SuidRich suidRich;
+    @Autowired
+    private AppActService appActService;
+    @Autowired
+    private RedisUtils redisUtils;
+    @Autowired
+    private ICardGroupOrderInfoService cardGroupOrderInfoService;
+    @Autowired
+    private AsyncAppService asyncAppService;
+    @Autowired
+    private GroupApiService groupApiService;
+    @Resource
+    private CommonCacheService commonCacheService;
+    @Autowired
+    private MallOrderService mallOrderService;
+    @Resource
+    private SaasForestClient saasForestClient;
+    @Autowired
+    private ITzyShippingAddressService shippingAddressService;
+    @Resource
+    private ITzyCardBaseInfoService cardBaseInfoService;
+    @Value("${saasService.baseurl:http://poyee-api-saas}")
+    private String saasBaseUrl;
+    @Value("${saasService.userPrizeUrl:/api/v1/act/user/prize}")
+    private String userPrizeUrl;
+    @Value("${saasService.actDetailUrl:/api/v1/act/draw/detail}")
+    private String actDetailUrl;
+    @Value("${saasService.actPrizelUrl:/api/v1/act/draw/prize}")
+    private String actPrizeUrl;
+    @Value("${saasService.drawSubmitUrl:/api/v1/act/draw/submit}")
+    private String drawSubmitUrl;
+    @Value("${saasService.drawOrderListUrl:/api/v1/order/list}")
+    private String drawOrderListUrl;
+    @Value("${saasService.drawOrderDetailUrl:/api/v1/order/detail}")
+    private String drawOrderDetailUrl;
+    @Value("${saasService.drawPrizeSubmitUrl:/api/v1/order/prize/submit}")
+    private String drawPrizeSubmitUrl;
+    @Value("${saasService.drawOrderPrepayUrl:/api/v1/order/prepay}")
+    private String drawOrderPrepayUrl;
+    @Value("${saasService.drawPayCatUrl:/api/v1/order/payment/cat}")
+    private String drawPayCatUrl;
+    @Value("${saasService.localOrderDrawUrl:/local/order/draw}")
+    private String localOrderDrawUrl;
+    @Value("${saasService.drawSelectedUrl:/api/v1/act/draw/selected}")
+    private String drawSelectedUrl;
+    @Value("${saasService.editActOrderAddr:/api/v1/order/edit/address}")
+    private String editActOrderAddr;
+    @Value("${saasService.delActOrderUrl:/api/v1/order/del}")
+    private String delActOrderUrl;
+    @Value("${saasService.confirmActOrderUrl:/api/v1/order/express/confirm}")
+    private String confirmActOrderUrl;
+
+    private static final String GROUP_GIFT_618="group_gift_618";
+
+    @ApiLog(title = "获取活动类型", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/list", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("获取活动类型")
+    public OutDTO getPrize(@RequestBody InDto inDto) {
+        AppActManageDTO actManage = new AppActManageDTO();
+        actManage.setType(inDto.getString("type"));
+        actManage.setStatus(1);
+        List<AppActManageDTO> actList = suidRich.select(actManage);
+        return OutDTO.ok().put("actList", actList);
+    }
+
+    @ApiLog(title = "获取活动详情", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/simpleInfo", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("获取活动详情")
+    public OutDTO getSimpleActInfo(@RequestBody InDto inDto) {
+        return OutDTO.ok().put("actInfo", getActInfoById(inDto.get("actId")));
+    }
+
+
+    private AppActManageDTO getActInfoById(Object actIdObj) {
+        Integer actId = (Integer) actIdObj;
+        if (actId == null) {
+            throw new ServiceException(500, "活动参数未传!");
+        }
+        AppActManageDTO actManage = new AppActManageDTO();
+        actManage.setId(actId.longValue());
+        actManage.setStatus(1);
+        actManage = suidRich.selectOne(actManage);
+        if (actManage == null) {
+            throw new ServiceException(500, "活动不存在!");
+        }
+        actManage.setPrizeList(getPrizes(actId));
+        return actManage;
+    }
+
+    @ApiLog(title = "获取活动详情", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/info", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("获取活动详情")
+    public OutDTO getActInfo(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        AppActManageDTO actManage = getActInfoById(inDto.get("actId"));
+        actManage.setUserTimes(appActService.getUserActTimes(userInfo.getId(), actManage));
+        PayActDTO payAct = getPayAct();
+        Map<String, BigDecimal> actAmountData = ImmutableMap.of("frozen_amount", BigDecimal.ZERO, "consume_amount", BigDecimal.ZERO);
+        long userActPoint=0L;
+        if (payAct != null) {
+            actAmountData = cardGroupOrderInfoService.getActGroupAmount(DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, payAct.getStartTime()),
+                    DateUtils.dateTime(DateUtils.YYYYMMDDHHMMSS, payAct.getEndTime()), userInfo.getId(), null);
+        } else if (StringUtils.isNotEmpty(actManage.getPointType()) && !Constants.POINT_TYPE_COMMON.equals(actManage.getPointType())) {
+            userActPoint = appActService.getUserPointByType(userInfo.getId(), actManage.getPointType());
+            actAmountData = cardGroupOrderInfoService.getActGroupAmount(actManage.getStartTime(), actManage.getEndTime(), userInfo.getId(), actManage.getPointType());
+        }
+        int drawNum = actManage.getUserTimes();
+        if (actManage.getDayLimitNum() > 0) {
+            drawNum = getUserDrawCount(actManage, drawNum);
+            drawNum = Math.max(0, drawNum);
+        }
+        actManage.setRuleConfig(null);
+        return OutDTO.ok().put("actInfo", actManage).put("actAmount", actAmountData).put("drawNum",drawNum).put("userActPoint",userActPoint);
+    }
+
+    @ApiLog(title = "获取活动积分", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/points", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("获取活动积分")
+    public OutDTO getActCommonInfo(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        if(inDto == null || inDto.get("actType") == null){
+            return OutDTO.error500("参数为空");
+        }
+        String actType = inDto.getString("actType");
+        List<SysDictData> sysDictDatas = commonCacheService.getCommonDictData("app_hot_type_times_cache",
+                actType,"1", null, -1);
+        Map<String, BigDecimal> actAmountData = Maps.newHashMap();
+        if(!CollectionUtils.isEmpty(sysDictDatas)) {
+            JSONObject jsonObject = JSONTools.parseObject(sysDictDatas.get(0).getDictValue());
+            /*boolean hasType = jsonObject.getBoolean("hasType"); // 是否传积分类型查拼团
+            String pointType = null;G
+            if(hasType){
+                pointType = jsonObject.getString("pointType");
+            }*/
+            BigDecimal frozenAmount = cardGroupOrderInfoService.getActFrozenAmountV2(
+                    jsonObject.getDate("startTime"),
+                    jsonObject.getDate("endTime"),
+                    userInfo.getId()
+            );
+            BigDecimal rate = jsonObject.getBigDecimal("rate");
+            if(frozenAmount.compareTo(BigDecimal.ZERO) > 0){
+                frozenAmount = frozenAmount.divide(rate,0, RoundingMode.DOWN);
+            }
+            BigDecimal consumeAmount = cardGroupOrderInfoService.getActConsumeAmountV2(userInfo.getId(), jsonObject.getString("pointType"));
+            if(consumeAmount.compareTo(BigDecimal.ZERO) > 0){
+                consumeAmount = consumeAmount.divide(rate.multiply(new BigDecimal("100")),0, RoundingMode.DOWN);
+            }
+            actAmountData.put("frozen_amount", frozenAmount);
+            actAmountData.put("consume_amount", consumeAmount);
+        }
+        return OutDTO.ok().put("actAmount", actAmountData);
+    }
+
+    private int getUserDrawCount(AppActManageDTO actManage, int drawNum) {
+        if (StringUtils.isNotEmpty(actManage.getRuleConfig())) {
+            //小时范围内限购
+            DrawRuleConfig ruleConfig = JSON.parseObject(actManage.getRuleConfig(), DrawRuleConfig.class);
+            List<LimitConfigDTO> limitConfigs = ruleConfig.getLimitConfig();
+            if (!CollectionUtils.isEmpty(limitConfigs)) {
+                int curHour = DateUtils.getCurrentHour();
+                LimitConfigDTO limitConfig = limitConfigs.stream().filter(l -> curHour < l.getEndHour() && curHour >= l.getStartHour())
+                        .findFirst().orElse(null);
+                if (limitConfig != null) {
+                    int limitHourNum = limitConfig.getLimitNum() == null ? 0 : limitConfig.getLimitNum();
+                    int actHourCount = appActService.getActCount(actManage.getId().intValue(), false, limitConfig.getStartHour(), limitConfig.getEndHour());
+                    drawNum = limitHourNum - actHourCount;
+                }
+            }
+        } else {
+            int actDayCount = appActService.getActCount(actManage.getId().intValue(), true);
+            drawNum = actManage.getDayLimitNum() - actDayCount;
+        }
+        return drawNum;
+    }
+
+
+    private PayActDTO getPayAct() {
+        Object cache = redisUtils.get("pay_act_cache_turntable");
+        if (cache != null) {
+            return (PayActDTO) cache;
+        }
+        List<SysDictData> payActTypes = asyncAppService.getPayActs(PayActDTO.TYPE_PAY_AMOUNT_TURNTABLE);
+        if (CollectionUtils.isEmpty(payActTypes)) {
+            return null;
+        }
+        SysDictData actData = payActTypes.get(0);
+        PayActDTO payAct = JSONTools.jsonStr2obj(actData.getDictValue(), PayActDTO.class);
+        redisUtils.set("pay_act_cache_turntable_info", payAct, 600);
+        return payAct;
+    }
+
+
+    private List<AppActPrizeDTO> getPrizes(Integer actId) {
+        Object actCache = redisUtils.get(Constants.ACT_PRIZE_INFO_CACHE + actId);
+        List<AppActPrizeDTO> prizeList;
+        if (actCache == null) {
+            AppActPrizeDTO actPrizeDTO = new AppActPrizeDTO();
+            actPrizeDTO.setActId(actId.longValue());
+            actPrizeDTO.setStatus(1);
+            prizeList = suidRich.selectOrderBy(actPrizeDTO, "sortQuery", new OrderType[]{OrderType.DESC});
+            if (prizeList.isEmpty()) {
+                throw new ServiceException(500, "奖品信息异常,请联系管理员!");
+            }
+            redisUtils.set(Constants.ACT_PRIZE_INFO_CACHE + actId, prizeList);
+        } else {
+            prizeList = (List<AppActPrizeDTO>) actCache;
+        }
+        return prizeList;
+    }
+
+
+    @ApiLog(title = "获取用户参与活动记录", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/getUserActRecord", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("获取用户参与活动记录")
+    public OutDTO getUserActRecord(@RequestBody InDto inDto) {
+        Integer actId = (Integer) inDto.get("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        AppActPrizeRecord recordCondition = new AppActPrizeRecord();
+        recordCondition.setUserId(userInfo.getId());
+        recordCondition.setActId(actId.longValue());
+
+        Condition condition = new ConditionImpl();
+        condition.orderBy("id", OrderType.DESC);
+        condition.start((inDto.getPageNo() - 1) * inDto.getPageSize()).size(inDto.getPageSize());
+
+        List<AppActPrizeRecord> recordList = suidRich.select(recordCondition, condition);
+        return OutDTO.ok().put("recordList", recordList);
+    }
+
+
+    @ApiLog(title = "获取活动记录", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/getActRecord", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("获取活动记录")
+    public OutDTO getActRecord(@RequestBody InDto inDto) {
+        Integer actId = (Integer) inDto.get("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+
+        AppActPrizeRecord recordCondition = new AppActPrizeRecord();
+        recordCondition.setActId(actId.longValue());
+        recordCondition.setShowStatus(1);
+
+        Condition condition = new ConditionImpl();
+        condition.orderBy("id", OrderType.DESC);
+        condition.start(0).size(10);
+
+        List<AppActPrizeRecord> recordList = suidRich.select(recordCondition, condition);
+        List<SimplePrizeRecord> records = recordList.stream()
+                .map(r -> new SimplePrizeRecord(r.getPrizeName(), r.getNickname().substring(0, 1) + "***", r.getAvatar())).collect(Collectors.toList());
+        return OutDTO.ok().put("recordList", records);
+    }
+
+
+    @ApiLog(title = "大转盘抽奖", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/luckDraw", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("大转盘抽奖")
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER,lockCount = 3,lockTime = 120,msg = "操作频繁,请稍后再试!")
+    public OutDTO luckDraw(@RequestBody InDto inDto) {
+        Integer actId = inDto.getIntegerParam("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        checkIsInfoAct(actId, null);
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        AppActPrizeDTO userPrize = appActService.drawPrize(actId, userInfo, null);
+        OutDTO ok = OutDTO.ok();
+        if (Constants.SKU_ACT_TYPE_COUPON.equals(userPrize.getType())) {
+            ok.put("prizeInfo", cardBaseInfoService.getPrizeInfo(userPrize.getPrizeId()));
+        }
+        return ok.put("userPrize", userPrize);
+    }
+
+    @ApiLog(title = "大转盘抽奖(拼团拼团关联)", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/info/luckDraw", method = RequestMethod.POST)
+    @ApiVersion(2.0)
+    @ApiOperation("大转盘抽奖(拼团关联)")
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER,lockCount = 3,lockTime = 120,msg = "操作频繁,请稍后再试!")
+    public OutDTO infoLuckDraw(@RequestBody InDto inDto) {
+        Integer actId = inDto.getIntegerParam("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        Integer refId = inDto.getIntegerParam("refId");
+        checkIsInfoAct(actId,refId);
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        AppActPrizeDTO userPrize = appActService.drawPrize(actId, userInfo, refId);
+        OutDTO ok = OutDTO.ok();
+        if (Constants.SKU_ACT_TYPE_COUPON.equals(userPrize.getType())) {
+            ok.put("prizeInfo", cardBaseInfoService.getPrizeInfo(userPrize.getPrizeId()));
+        }
+        return ok.put("userPrize", userPrize);
+    }
+
+    private void checkIsInfoAct(Integer actId, Integer refId) {
+        List<SysDictData> typeData = commonCacheService.getCommonDictData(Constants.INFO_GIVE_DRAW, null, "1", Constants.INFO_GIVE_DRAW, 84600);
+        if (CollectionUtils.isEmpty(typeData)) {
+            return;
+        }
+        SysDictData data = typeData.get(0);
+        long refActId = data.getDictSort();
+        if (refActId != actId.longValue()) {
+            return;
+        }
+        if (refId == null) {
+            throw new ServiceException("活动参数未传!");
+        }
+        GroupInfo info = groupApiService.getGroupInfoById(refId);
+        AppAssert.notNull(info, "拼团不存在!");
+        if (info.getStatus() < 203 || info.getStatus() == 999) {
+            throw new ServiceException("拼团状态不符合要求!");
+        }
+        if (!GROUP_GIFT_618.equals(data.getDictValue()) && !Integer.valueOf(data.getDictValue()).equals(info.getPaniniListId())) {
+            throw new ServiceException("拼团未参与活动");
+        }
+    }
+
+    @ApiLog(title = "获取竞猜活动详情", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/guess/info", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("获取竞猜活动详情")
+    public OutDTO getGuessActInfo(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        Integer actId = (Integer) inDto.get("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        GuessActDTO actInfo = getGuessAct(actId);
+        List<GuessTeamDTO> guessTeams = appActService.selectGuessTeam(actInfo.getId(), userInfo.getId(), true);
+        actInfo.setGuessTeams(guessTeams);
+        AppActGuessTeam team = new AppActGuessTeam();
+        team.setActId(actId.longValue());
+        ConditionImpl condition = new ConditionImpl();
+        condition.and().op("guessResult", Op.gt, 0);
+        String count = suidRich.selectWithFun(team, FunctionType.COUNT, "*", condition);
+
+        return OutDTO.ok().put("actInfo", actInfo).put("hasRank", Integer.valueOf(count) > 0)
+                .put("hasRecord", appActService.getUserIsGuess(userInfo.getId(), actId))
+                .put("turntableNums", appActService.getUserActTurntableNums(userInfo.getId(), actId));
+    }
+
+    private GuessActDTO getGuessAct(Integer actId) {
+        AppActManageDTO actManage = new AppActManageDTO();
+        actManage.setId(actId.longValue());
+        actManage.setStatus(1);
+        actManage = suidRich.selectOne(actManage);
+        if (actManage == null) {
+            throw new ServiceException(500, "活动不存在!");
+        }
+
+        GuessActDTO actInfo = DozerUtils.map(actManage, GuessActDTO.class);
+        return actInfo;
+    }
+
+    @ApiLog(title = "获取竞猜日程", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/guess/team/list", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("获取竞猜日程")
+    public OutDTO getGuessActTeams(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        Integer actId = (Integer) inDto.get("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        List<GuessTeamDTO> guessTeams = appActService.selectGuessTeam(actId.longValue(), userInfo.getId(), false);
+        Map<String, List<GuessTeamDTO>> collect = guessTeams.stream().collect(Collectors.groupingBy(g -> DateUtils.dateTime(g.getMatchStartTime())));
+        return OutDTO.ok().put("guessTeams", new TreeMap<>(collect));
+    }
+
+    @ApiLog(title = "用户竞猜历史", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/guess/user/record", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("用户竞猜历史")
+    public OutDTO getUserGuessRecord(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        Integer actId = (Integer) inDto.get("actId");
+        if (actId == null) {
+            return OutDTO.error500("参数为空");
+        }
+        Integer guessStatus = (Integer) inDto.get("status");
+        GuessUserDTO userRank = appActService.getUserActRanking(actId, userInfo.getId()).getCurrentUser();
+        AppActGuessRecord param = new AppActGuessRecord();
+        param.setActId(actId.longValue());
+        param.setUserId(userInfo.getId().longValue());
+        String count = suidRich.selectWithFun(param, FunctionType.COUNT, "*");
+        userRank.setGuessTotalNums(Integer.valueOf(count));
+        List<GuessHistoryRecord> records = appActService.getUserGuessHistoryRecord(userInfo.getId(), actId, guessStatus);
+        return OutDTO.ok().put("userRank", userRank).put("records", records);
+    }
+
+    @ApiLog(title = "用户竞猜", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/guess/user/choice", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("用户竞猜")
+    public OutDTO userGuessTeam(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        Integer teamId = (Integer) inDto.get("teamId");
+        Integer userGuessResult = (Integer) inDto.get("userGuessResult");
+        if (teamId == null || userGuessResult == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        AppActGuessRecord param = new AppActGuessRecord();
+        param.setUserId(userInfo.getId().longValue());
+        param.setNickname(userInfo.getNickname());
+        param.setAvatar(userInfo.getAvatar());
+        param.setActTeamId(teamId.longValue());
+        param.setUserGuessResult(userGuessResult);
+        appActService.userGuessTeam(param);
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "参与用户竞猜数据", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/guess/team/user/nums", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("参与用户竞猜数据")
+    public OutDTO getTeamGuessNums(@RequestBody InDto inDto) {
+        Integer teamId = (Integer) inDto.get("teamId");
+        if (teamId == null) {
+            return OutDTO.error500("参数为空!");
+        }
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        AppActGuessTeam team = new AppActGuessTeam();
+        team.setId(teamId.longValue());
+        team = suidRich.selectOne(team);
+        GuessTeamDTO teamDTO = DozerUtils.map(team, GuessTeamDTO.class);
+        AppActGuessRecord param = new AppActGuessRecord();
+        param.setUserId(userInfo.getId().longValue());
+        param.setActTeamId(teamId.longValue());
+        List<AppActGuessRecord> records = appActService.getUserGuessRecord(param);
+        int userChoice = 0;
+        if (!records.isEmpty()) {
+            userChoice = records.get(0).getUserGuessResult();
+        }
+        List<TeamResultDTO> resultList = appActService.getTeamGuessNums(teamId);
+        Map<Integer, List<TeamResultDTO>> collect = resultList.stream().collect(Collectors.groupingBy(TeamResultDTO::getGuessResult));
+        List<TeamResultDTO> winData = collect.get(3);
+        List<TeamResultDTO> eqData = collect.get(2);
+        List<TeamResultDTO> loseData = collect.get(1);
+        int winCount = winData == null ? 0 : winData.get(0).getNums();
+        int eqCount = eqData == null ? 0 : eqData.get(0).getNums();
+        int loseCount = loseData == null ? 0 : loseData.get(0).getNums();
+        int total = winCount + eqCount + loseCount;
+        int winRate = 0;
+        int loseRate = 0;
+        int eqRate = 0;
+        if (total > 0) {
+            winRate = winCount == 0 ? 0 : (int) winCount * 100 / total;
+            loseRate = loseCount == 0 ? 0 : (int) loseCount * 100 / total;
+            eqRate = eqCount == 0 ? 0 : (int) eqCount * 100 / total;
+            int totalRate = eqRate + winRate + loseRate;
+            if (totalRate < 100) {
+                winRate += 100 - totalRate;
+            } else if (totalRate > 100) {
+                loseRate -= totalRate - 100;
+            }
+        }
+
+        return OutDTO.ok().put("team", teamDTO)
+                .put("userChoice", userChoice).put("total", total)
+                .put("winRate", winRate).put("winCount", winCount)
+                .put("loseRate", loseRate).put("loseCount", loseCount)
+                .put("eqRate", eqRate).put("eqCount", eqCount);
+    }
+
+    @ApiLog(title = "竞猜排行榜", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/guess/rank/list", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("竞猜排行榜")
+    public OutDTO getActRankList(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        Integer actId = (Integer) inDto.get("actId");
+        if (actId == null) {
+            return OutDTO.error500("参数为空");
+        }
+        return OutDTO.ok().put("rankList", appActService.getUserActRanking(actId, userInfo.getId()));
+    }
+
+
+    @ApiLog(title = "获取用户抽奖记录", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/getUserTurntableRecord", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("获取用户抽奖记录")
+    public OutDTO getUserTurntableRecord(@RequestBody InDto inDto) {
+        Integer actId = (Integer) inDto.get("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        List<AppActPrizeRecord> recordList = appActService.getUserTurntableRecord(actId, inDto.getUserId());
+        return OutDTO.ok().put("recordList", recordList);
+    }
+
+    @ApiLog(title = "获取瓜分奖励的人数", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/getPrizeQualifys", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("获取瓜分奖励的人数")
+    public OutDTO getPrizeQualifys(@RequestBody InDto inDto) {
+        Integer actId = (Integer) inDto.get("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        return OutDTO.ok().put("prizeQualifys", appActService.getPrizeQualifys(actId));
+    }
+
+
+    @ApiLog(title = "鸿运值兑换", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/luck/point/exchange", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("鸿运值兑换")
+    @ApiLimitRule(seconds = 5, limitCount = 25, type = LimitRule.ACT, msg = "抱歉,兑换人数太多,请稍后再试!")
+    public OutDTO luckPointExchange(@RequestBody InDto inDto) {
+        Integer actId = (Integer) inDto.get("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        Integer purchaseCount = (Integer) inDto.get("purchaseCount");
+        if (purchaseCount == null || purchaseCount < 1) {
+            return OutDTO.error500("兑换数量异常!");
+        }
+        Boolean anonymous = (Boolean) inDto.get("anonymous");
+        int isShow = anonymous != null && anonymous ? 0 : 1;
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        appActService.luckPointExchange(actId, purchaseCount, userInfo, isShow,true);
+        return OutDTO.ok();
+    }
+
+
+    @ApiLog(title = "重新申请抽奖码", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    //@RequestMapping(value = "/luck/code/repeat", method = RequestMethod.POST)
+    //@ApiVersion(1.0)
+    @ApiOperation("重新申请抽奖码")
+    public OutDTO repeat(@RequestBody InDto inDto) {
+        Integer prizeRecordId = (Integer) inDto.get("prizeRecordId");
+        if (prizeRecordId == null) {
+            return OutDTO.error500("参数未传!");
+        }
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        appActService.checkLuckyCode(prizeRecordId, userInfo.getId());
+        return OutDTO.ok();
+    }
+
+
+    /**
+     * 获取用户活动积分明细
+     */
+    @ApiLog(title = "获取用户活动积分明细", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ApiOperation("获取用户活动积分明细")
+    @ResponseBody
+    @RequestMapping(value = "/user/point/type", method = RequestMethod.POST)
+    public OutDTO getUserActPointByType(@RequestBody InDto inDto) {
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        PointDetailParam detailParam = inDto.buildParam(new PointDetailParam());
+        detailParam.setPageNo(inDto.getPageNo());
+        detailParam.setPageSize(inDto.getPageSize());
+        detailParam.setUserId(userInfo.getId());
+        UserActPointDTO userActPointDTO = appActService.getUserActPointByType(detailParam);
+        return OutDTO.ok().put("userActPoint", userActPointDTO);
+    }
+
+
+    @ApiLog(title = "新手指引记录", businessType = BusinessType.SEARCH, indto = "{{inDto}}")
+    @ApiOperation("新手指引记录")
+    @ResponseBody
+    @PostMapping(value = "/user/show")
+    public OutDTO getUserShow(@RequestBody InDto inDto) {
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        String type = inDto.getString("type");
+        if (StringUtils.isEmpty(type)) {
+            return OutDTO.error500(MsgConstants.PARAM_EMPTY);
+        }
+        if (Constants.ENFORCE_FACE_VERIFY_REMIND.equals(type)) {
+            String key = "user_show_" + type + user.getId();
+            if (redisUtils.hasKey(key)) {
+                return OutDTO.ok().put("status", 1);
+            } else {
+                redisUtils.set(key, 1, 600);
+                return OutDTO.ok().put("status", 0);
+            }
+        }
+        String key = "user_show_" + type;
+        if (redisUtils.hHasKey(key, user.getId().toString())) {
+            return OutDTO.ok().put("status", 1);
+        }
+        redisUtils.hset(key, user.getId().toString(), 1);
+        return OutDTO.ok().put("status", 0);
+    }
+
+    @ApiLog(title = "获取指定checklist收集信息", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/checklist")
+    //@ApiVersion(1.0)
+    @ApiOperation("获取指定checklist活动")
+    public OutDTO selectUserCollectListAct(@RequestBody InDto inDto) {
+        Integer paniniBaseId = (Integer) inDto.get("paniniBaseId");
+        if (paniniBaseId == null) {
+            return OutDTO.error500("参数【paniniBaseId】为空!");
+        }
+        String actType = inDto.getString("actType");
+        if (StringUtils.isEmpty(actType)) {
+            return OutDTO.error500("参数【actType】为空!");
+        }
+        Integer actId = inDto.getIntegerParam("actId");
+        if (actId == null) {
+            return OutDTO.error500("参数【actId】为空!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        UserListActDTO userList = appActService.buildUserListActData(user.getId(), paniniBaseId, actType, actId);
+        if (actType.endsWith(Constants.ACT_GOODS_TYPE_PLAYER) && !CollectionUtils.isEmpty(userList.getTeamPlayerList())) {
+            addPlayerData(paniniBaseId, userList.getTeamPlayerList());
+        }
+        return OutDTO.ok().put("userList", userList);
+    }
+
+    @ApiLog(title = "获取checklist活动", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/collect/id")
+    @ApiOperation("获取指定checklist活动")
+    public OutDTO selectListAct(@RequestBody InDto inDto) {
+        Integer paniniBaseId = (Integer) inDto.get("paniniBaseId");
+        if (paniniBaseId == null) {
+            return OutDTO.error500("参数为空!");
+        }
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        List<GoodsActRecord> actList = groupApiService.getUserListAct(paniniBaseId.longValue());
+        List<UserCollectListDTO> userActList = null;
+        boolean isActNum = false;
+        long userSelectNum = 0;
+        long frozenNum = 0;
+        if (!CollectionUtils.isEmpty(actList)) {
+            GoodsActRecord act = actList.get(0);
+            String actType = act.getActType();
+            isActNum = Constants.LIST_ACT_SELECT_NUM.equals(actType);
+            if (isActNum) {
+                userSelectNum = appActService.getUserPointByType(user.getId(), act.getActConfig().getExchangeActType());
+                frozenNum=groupApiService.getUserFrozenGoodsNum(user.getId(),paniniBaseId);
+                actList.forEach(a -> a.setExchangedAble(appActService.isActExchangeAble(user.getId(), a.getId().intValue())));
+            } else {
+                userActList = groupApiService.getUserCollectGoods(user.getId(), paniniBaseId, actType);
+                if (actType.endsWith(Constants.ACT_GOODS_TYPE_PLAYER) && !CollectionUtils.isEmpty(userActList)) {
+                    addPlayerData(paniniBaseId, userActList);
+                }
+            }
+        }
+        if (!isActNum) {
+            actList.forEach(a -> a.setUserListActDTO(appActService.buildUserListActData(user.getId(), paniniBaseId, a.getActType(), a.getId().intValue())));
+        }
+        return OutDTO.ok().put("actList", actList).put("userActList", userActList).put("userSelectNum", userSelectNum).put("frozenNum",frozenNum);
+    }
+
+    private void addPlayerData(Integer paniniBaseId, List<UserCollectListDTO> userActList) {
+        Map<String, UserCollectListDTO> playerDataById = groupApiService.selectPlayerRefData(paniniBaseId);
+        if (CollectionUtils.isEmpty(playerDataById)) {
+            return;
+        }
+        userActList.forEach(ua -> {
+            UserCollectListDTO playerData = playerDataById.get(ua.getPlayerId().toString());
+            if (playerData != null) {
+                ua.setRc(playerData.getRc());
+                ua.setTeamBg(playerData.getTeamBg());
+            }
+        });
+    }
+
+    @ApiLog(title = "获取checklist活动", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/exchange/list/prize")
+    //@ApiVersion(1.0)
+    @ApiOperation("获取checklist活动")
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public OutDTO exchangeListPrize(@RequestBody InDto inDto) {
+        Integer paniniBaseId = (Integer) inDto.get("paniniBaseId");
+        if (paniniBaseId == null) {
+            return OutDTO.error500("参数为空!");
+        }
+        String actType = inDto.getString("actType");
+        if (StringUtils.isEmpty(actType)) {
+            return OutDTO.error500("参数【actType】为空!");
+        }
+        Integer actId = inDto.getIntegerParam("actId");
+        if (actId == null) {
+            return OutDTO.error500("参数【actId】为空!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        appActService.exchangeListPrize(user.getId(), paniniBaseId, actType, actId);
+        appActService.delUserListActCache(paniniBaseId.longValue(), user.getId(), actId.longValue());
+        return OutDTO.ok();
+    }
+
+
+    @ApiLog(title = "消费达标活动", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/consume/detail")
+    //@ApiVersion(1.0)
+    @ApiOperation("消费达标活动")
+    public OutDTO consumeActDetail(@RequestBody InDto inDto) {
+        Integer actId = inDto.getIntegerParam("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        ConsumeActDTO actDTO = appActService.consumeDetailInfo(actId, user.getId());
+        return OutDTO.ok().put("act", actDTO);
+    }
+
+
+    @ApiLog(title = "消费达标奖励兑换", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/exchange/consume/prize")
+    //@ApiVersion(1.0)
+    @ApiOperation("消费达标奖励兑换")
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public OutDTO exchangeConsumePrize(@RequestBody InDto inDto) {
+        Integer actId = (Integer) inDto.get("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        String key = "exchange_consume_prize" + user.getId();
+        if (redisUtils.hasKey(key)) {
+            return OutDTO.error500("操作频繁,请稍后再试!");
+        }
+        redisUtils.set(key, 1, 10);
+        Integer prizeLevel = (Integer) inDto.get("prizeLevel");
+        appActService.exchangeConsumePrize(actId, user, prizeLevel);
+        redisUtils.del(key);
+        return OutDTO.ok();
+    }
+
+
+    @ApiLog(title = "抽卡机详情", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/card/draw/detail")
+    @ApiVersion(1.0)
+    @ApiOperation("抽卡机详情")
+    public OutDTO cardDrawActDetail(@RequestBody InDto inDto) {
+        Integer actId = (Integer) inDto.get("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        CardDrawActDTO act = appActService.getCardDrawActDetail(actId);
+        Long userPoint = appActService.getUserPointByType(user.getId(), act.getPointType());
+        act.setUserPoint(userPoint.doubleValue());
+        List<DrawActPrizeDTO> userDrawPrizes = appActService.getUserDrawPrize(null, user.getId(), null, actId, null, null);
+        if (!CollectionUtils.isEmpty(userDrawPrizes)) {
+            Map<Integer, DrawActPrizeDTO> userPrizeMap = userDrawPrizes.stream().collect(Collectors.toMap(DrawActPrizeDTO::getPrizeId, DrawActPrizeDTO -> DrawActPrizeDTO));
+            act.getPrizes().parallelStream().forEach(prize -> {
+                DrawActPrizeDTO existPrize = userPrizeMap.get(prize.getPrizeId());
+                prize.setTotalNum(existPrize == null ? 0 : existPrize.getTotalNum());
+            });
+            act.setUserCollectNum(userDrawPrizes.size());
+        }
+        return OutDTO.ok().put("act", act);
+    }
+
+
+    @ApiLog(title = "抽卡机详情", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/card/draw/detail")
+    @ApiVersion(2.4)
+    @ApiOperation("抽卡机详情")
+    public OutDTO cardDrawActDetailV2(@RequestBody InDto inDto) {
+        Integer actId = (Integer) inDto.get("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        JSONObject reqData = new JSONObject();
+        reqData.put("actId", actId);
+        JSONObject resData = reqSaas(saasBaseUrl + actDetailUrl, reqData, user.getBaseUserHeader());
+        return OutDTO.ok(resData);
+    }
+
+
+    @ApiLog(title = "抽卡机图鉴查询", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/card/draw/prize")
+    @ApiVersion(2.4)
+    @ApiOperation("抽卡机图鉴查询")
+    public OutDTO getDrawPrize(@RequestBody InDto inDto) {
+        CardQuery cardQuery = inDto.buildParam(new CardQuery());
+        if (cardQuery.getActId() == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        JSONObject reqData = JSON.parseObject(JSON.toJSONString(cardQuery));
+        ResultDTO resData = reqSaasResult(saasBaseUrl + actPrizeUrl, reqData, user.getBaseUserHeader());
+        return OutDTO.ok().put("actPrize", resData.getData());
+    }
+
+    @ApiLog(title = "抽卡机抽卡", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/card/draw")
+    @ApiVersion(1.0)
+    @ApiOperation("抽卡机抽卡")
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public OutDTO cardDrawByType(@RequestBody InDto inDto) {
+        Integer actId = (Integer) inDto.get("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        String type = inDto.getString("type");
+        if (StringUtils.isEmpty(type)) {
+            return OutDTO.error500("抽卡类型未传!");
+        }
+        CardDrawActDTO act = appActService.getCardDrawActDetail(actId);
+        Date now = new Date();
+        if (now.before(act.getStartTime()) || now.after(act.getActOverTime())) {
+            return OutDTO.error500("未处于活动有效期内!");
+        }
+        if (!act.getDrawTypes().contains(type)) {
+            return OutDTO.error500("抽卡类型不存在!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        String key = "user_draw_card_act" + user.getId();
+        if (redisUtils.hasKey(key)) {
+            return OutDTO.error500("操作频繁,请稍后再试!");
+        }
+        redisUtils.set(key, 1, 10);
+        Long userPoint = appActService.getUserPointByType(user.getId(), act.getPointType());
+        if (userPoint < act.getPoint()) {
+            redisUtils.del(key);
+            return OutDTO.error500("积分不足!");
+        }
+        List<ConsumePrizeDTO> prizeBySubType = appActService.userDrawCardAct(act, type, user);
+        redisUtils.del(key);
+        return OutDTO.ok().put("prizeByType", prizeBySubType);
+    }
+
+    @ApiLog(title = "抽卡机抽卡", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/card/draw")
+    @ApiVersion(2.4)
+    @ApiOperation("抽卡机抽卡")
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public OutDTO cardDrawByTypeV2(@RequestBody InDto inDto) {
+        Integer actId = inDto.getIntegerParam("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        String type = inDto.getString("type");
+        if (StringUtils.isEmpty(type)) {
+            return OutDTO.error500("抽卡类型未传!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        String key = "user_draw_card_act" + user.getId();
+        if (redisUtils.hasKey(key)) {
+            return OutDTO.error500("操作频繁,请稍后再试!");
+        }
+        JSONObject reqData1 = new JSONObject();
+        reqData1.put("actId", actId);
+        JSONObject resData1 = reqSaas(saasBaseUrl + actDetailUrl, reqData1, user.getBaseUserHeader());
+        if ("point".equals(resData1.getString("subType"))) {
+            Long userPoint = appActService.getUserPointByType(user.getId(), resData1.getString("pointType"));
+            if (userPoint < resData1.getIntValue("point")) {
+                redisUtils.del(key);
+                return OutDTO.error500("积分不足!");
+            }
+        }
+        JSONObject reqData = new JSONObject();
+        reqData.put("actId", actId);
+        reqData.put("drawType", type);
+        JSONObject resData = reqSaas(saasBaseUrl + drawSubmitUrl, reqData, user.getBaseUserHeader());
+        DrawOrderDTO drawOrder = JSON.parseObject(resData.toJSONString(), DrawOrderDTO.class);
+        if (drawOrder.getActualPayment() != null && drawOrder.getActualPayment().doubleValue() > 0) {
+            log.info("抽卡订单待支付:{}", resData);
+            redisUtils.del(key);
+            return OutDTO.ok(resData);
+        } else if (drawOrder.getPoint() != null && drawOrder.getPoint() > 0) {
+            AppUserPointRecord pointRecord = new AppUserPointRecord().setType(drawOrder.getPointType()).setChangePoint(-drawOrder.getPoint().longValue())
+                    .setUserId(user.getId().longValue()).setOrderId(drawOrder.getId().longValue()).setOrderNo(drawOrder.getOrderNo())
+                    .setCreateTime(new Date());
+            mineApiService.addUserPoint(pointRecord);
+            JSONObject reqData3 = new JSONObject();
+            reqData3.put("id", drawOrder.getId());
+            reqData3.put("tenantId", 1);
+            ResultDTO result = saasForestClient.sendJsonPost(saasBaseUrl + localOrderDrawUrl, user.getBaseUserHeader(), reqData3);
+            return OutDTO.ok().put("prizeByType", result.getData()).put("payWay", "free").put("price", 0);
+        } else {
+            redisUtils.del(key);
+            return OutDTO.error500("抽卡异常,请重试!");
+        }
+    }
+
+    @ApiLog(title = "获取用户抽卡奖品", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/user/draw/prize")
+    @ApiVersion(1.0)
+    @ApiOperation("查询用户抽卡奖品")
+    public OutDTO getUserDrawPrize(@RequestBody InDto inDto) {
+        List<String> actTypes = getDrawActTypes();
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        Integer status = (Integer) inDto.get("status");
+        status = status == null ? 0 : status;
+        List<DrawActPrizeDTO> drawPrizes = appActService.getUserDrawPrize(actTypes, user.getId(), null, null, status, inDto.getString("prizeType"));
+        return OutDTO.ok().put("prizeList", drawPrizes);
+    }
+
+
+    @ApiLog(title = "获取用户抽卡奖品", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/user/draw/prize")
+    @ApiVersion(2.4)
+    @ApiOperation("查询用户抽卡奖品")
+    public OutDTO getUserDrawPrizeV2(@RequestBody InDto inDto) {
+        Integer actId = inDto.getIntegerParam("actId");
+        if (actId == null) {
+            return OutDTO.error500("actId为空!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        JSONObject reqData = new JSONObject();
+        reqData.put("actId", actId);
+        reqData.put("pageNo", inDto.getPageNo());
+        reqData.put("pageSize", inDto.getPageSize());
+        JSONObject resData = reqSaas(saasBaseUrl + userPrizeUrl, reqData, user.getBaseUserHeader());
+        return OutDTO.ok(resData);
+    }
+
+    private List<String> getDrawActTypes() {
+        List<SysDictData> actTypeDict = commonCacheService.getCommonDictData(Constants.USER_DRAW_CARD_ACT, null, Constants.ONE, Constants.USER_DRAW_CARD_ACT, 3600);
+        List<String> actTypes;
+        if (CollectionUtils.isEmpty(actTypeDict)) {
+            actTypes = Collections.singletonList(Constants.ACT_TYPE_DRAW_CARD_GAME);
+        } else {
+            actTypes = actTypeDict.stream().map(SysDictData::getDictValue).collect(Collectors.toList());
+        }
+        return actTypes;
+    }
+
+    private BigDecimal getActShippingCost() {
+        List<SysDictData> actTypeDict = commonCacheService.getCommonDictData(Constants.ACT_BASE_SHIPPING_COST_KEY, null, null,
+                Constants.ACT_BASE_SHIPPING_COST_KEY, 3600);
+        if (CollectionUtils.isEmpty(actTypeDict)) {
+            return Constants.ACT_BASE_SHIPPING_COST;
+        }
+        return new BigDecimal(actTypeDict.get(0).getDictValue());
+    }
+
+    @ApiLog(title = "提交奖品订单,支付运费", businessType = BusinessType.UPDATE)
+    @ResponseBody
+    @PostMapping(value = "/submit/prize/order")
+    @ApiVersion(1.0)
+    @ApiOperation("提交奖品订单,支付运费")
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public OutDTO submitPrizeOrder(@RequestBody InDto inDto) {
+        String prizeIds = inDto.getString("prizeIds");
+        if (StringUtils.isEmpty(prizeIds)) {
+            return OutDTO.error500("奖品ID参数缺失!");
+        }
+        Integer addressId = (Integer) inDto.get("addressId");
+        if (addressId == null) {
+            return OutDTO.error500("地址信息缺失!");
+        }
+        List<Integer> prizeIdList = Arrays.stream(prizeIds.split(",")).map(Integer::valueOf).collect(Collectors.toList());
+        List<String> actTypes = getDrawActTypes();
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        String key = "user_draw_card_act" + user.getId();
+        if (redisUtils.hasKey(key)) {
+            return OutDTO.error500("操作频繁,请稍后再试!");
+        }
+        redisUtils.set(key, 1, 10);
+        List<DrawActPrizeDTO> drawPrizes = appActService.getUserDrawPrize(actTypes, user.getId(), prizeIdList, null, 0, null);
+        if (CollectionUtils.isEmpty(drawPrizes)) {
+            return OutDTO.error500("未查询到符合条件的奖品信息!");
+        }
+        PrizeOrderParam prizeOrderParam = new PrizeOrderParam().setPrizeIdList(prizeIdList).setActTypes(actTypes).setUser(user)
+                .setAddressId(addressId).setUserKey(key).setShippingCost(getActShippingCost()).setDrawPrizes(drawPrizes);
+        OrderSubmitDTO order = mallOrderService.submitPrizeOrder(prizeOrderParam);
+        redisUtils.del(key);
+        return OutDTO.ok().put("order", order);
+    }
+
+
+    @ApiLog(title = "提交奖品订单,支付运费", businessType = BusinessType.UPDATE)
+    @ResponseBody
+    @PostMapping(value = "/submit/prize/order")
+    @ApiVersion(2.4)
+    @ApiOperation("提交奖品订单,支付运费")
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER, msg = "操作频繁,请稍后再试!")
+    public OutDTO submitPrizeOrderV2(@RequestBody InDto inDto) {
+        String prizeIds = inDto.getString("prizeIds");
+        Object allFlag = inDto.get("allFlag");
+        boolean isAll = allFlag != null && (Boolean) allFlag;
+        if (StringUtils.isEmpty(prizeIds) && !isAll) {
+            return OutDTO.error500("奖品ID参数缺失!");
+        }
+        Integer addressId = inDto.getIntegerParam("addressId");
+        if (addressId == null) {
+            return OutDTO.error500("地址信息缺失!");
+        }
+        Integer actId = inDto.getIntegerParam("actId");
+        if (actId == null) {
+            return OutDTO.error500("actId缺失!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        TzyShippingAddress address = shippingAddressService.selectUserAddress(user.getId(), addressId);
+        if (address == null) {
+            return OutDTO.error500("地址信息异常!");
+        }
+        String key = "user_draw_card_act" + user.getId();
+        if (redisUtils.hasKey(key)) {
+            return OutDTO.error500("操作频繁,请稍后再试!");
+        }
+        redisUtils.set(key, 1, 10);
+        JSONObject reqData = new JSONObject();
+        reqData.put("prizeIds", prizeIds);
+        reqData.put("actId", actId);
+        reqData.put("allFlag", isAll);
+        reqData.put("linkName", address.getLinkname());
+        reqData.put("phone", address.getPhone());
+        reqData.put("address", address.getAddress() + address.getAddressMore());
+        ResultDTO resultDTO = reqSaasResult(saasBaseUrl + drawPrizeSubmitUrl, reqData, user.getBaseUserHeader());
+        redisUtils.del(key);
+        return OutDTO.ok().put("order", resultDTO.getData());
+    }
+
+    private JSONObject reqSaas(String url, JSONObject reqData, Map<String, Object> header) {
+        ResultDTO result = saasForestClient.sendJsonPost(url, header, reqData);
+        return JSON.parseObject(JSON.toJSONString(result.getData()));
+    }
+
+    private ResultDTO reqSaasResult(String url, JSONObject reqData, Map<String, Object> header) {
+        return saasForestClient.sendJsonPost(url, header, reqData);
+    }
+
+
+    @ApiLog(title = "获取活动兑换记录", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/list/exchange/record")
+    @ApiOperation("获取活动兑换记录")
+    public OutDTO getUserActExchangeRecord(@RequestBody InDto inDto) {
+        Integer actId = inDto.getIntegerParam("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        List<UserActTimes> userActTimesList = appActService.getUserActExchangeRecord(actId, user.getId());
+        return OutDTO.ok().put("records", userActTimesList);
+    }
+
+
+    @ApiLog(title = "获取抽卡记录", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/order/list")
+    @ApiOperation("获取抽卡记录")
+    public OutDTO getUserDrawOrder(@RequestBody InDto inDto) {
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        String status = inDto.getString("status");
+        String orderType = inDto.getString("orderType");
+        String orderSubType = inDto.getString("orderSubType");
+        if (StringUtils.isEmpty(status) || StringUtils.isEmpty(orderType) || StringUtils.isEmpty(orderSubType)) {
+            return OutDTO.error500("参数为空");
+        }
+        JSONObject reqData = new JSONObject();
+        reqData.put("orderType", orderType);
+        reqData.put("status", status);
+        reqData.put("orderSubType", orderSubType);
+        ResultDTO resultDTO = reqSaasResult(saasBaseUrl + drawOrderListUrl, reqData, user.getBaseUserHeader());
+        return OutDTO.ok().put("orderPage", resultDTO.getData());
+    }
+
+    @ApiLog(title = "获取抽卡订单明细", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/order/detail")
+    @ApiOperation("获取抽卡订单明细")
+    public OutDTO getUserDrawOrderDetail(@RequestBody InDto inDto) {
+        Integer id = inDto.getIntegerParam("id");
+        if (id == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        JSONObject reqData = new JSONObject();
+        reqData.put("id", id);
+        ResultDTO resultDTO = reqSaasResult(saasBaseUrl + drawOrderDetailUrl, reqData, user.getBaseUserHeader());
+        return OutDTO.ok().put("order", resultDTO.getData());
+    }
+
+
+    @ApiLog(title = "抽卡订单唤起支付", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/order/prepay")
+    @ApiOperation("抽卡订单唤起支付")
+    public OutDTO drawOrderPrepay(@RequestBody InDto inDto) throws Exception {
+        PayReqParam reqParam = inDto.buildParam(new PayReqParam());
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        reqParam.setCreateip(IpUtils.getHostIp()).setUserType(inDto.getUserType()).setUserId(user.getId()).setOrderType("draw");
+        if (StringUtils.isNotEmpty(user.getUserCertData())) {
+            String userCertData = AESUtil.decryptData(user.getUserCertData(), Constants.AES_USER_PASSWORD);
+            JSONObject json = JSON.parseObject(userCertData);
+            reqParam.setCertificateNo(json.getString("certNo")).setUserName(json.getString("certName"));
+
+        }
+        JSONObject res = reqSaas(saasBaseUrl + drawOrderPrepayUrl, JSON.parseObject(JSON.toJSONString(reqParam)), user.getBaseUserHeader());
+        return OutDTO.ok(res);
+    }
+
+    @ApiLog(title = "抽卡订单唤起支付", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/order/pay/cat")
+    @ApiOperation("抽卡订单唤起支付")
+    public OutDTO getOrderPayCat(@RequestBody InDto inDto) {
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        JSONObject reqData = new JSONObject();
+        reqData.put("orderType", "draw");
+        ResultDTO resultDTO = reqSaasResult(saasBaseUrl + drawPayCatUrl, reqData, user.getBaseUserHeader());
+        return OutDTO.ok().put("cat", resultDTO.getData());
+    }
+
+
+    @ApiLog(title = "获取奖品信息", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/prize/info")
+    @ApiOperation("获取奖品信息")
+    public OutDTO getPrizeInfo(@RequestBody InDto inDto) {
+        String type = inDto.getString("type");
+        Integer prizeId = inDto.getIntegerParam("prizeId");
+        if (StringUtils.isEmpty(type) || prizeId == null) {
+            return OutDTO.error500("参数缺失");
+        }
+        OutDTO ok = OutDTO.ok();
+        if (Constants.SKU_ACT_TYPE_COUPON.equals(type)) {
+            ok.put("prize", cardBaseInfoService.getPrizeInfo(prizeId));
+        }
+        return ok;
+    }
+
+    @ApiLog(title = "查询抽卡机selected类型", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @PostMapping(value = "/draw/selected")
+    @ApiVersion(2.4)
+    @ApiOperation("查询抽卡机selected类型")
+    public OutDTO getDrawSelectedType(@RequestBody InDto inDto) {
+        Integer actId = inDto.getIntegerParam("actId");
+        if (actId == null) {
+            return OutDTO.error500("actId为空!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        JSONObject reqData = new JSONObject();
+        reqData.put("actId", actId);
+        JSONObject resData = reqSaas(saasBaseUrl + drawSelectedUrl, reqData, user.getBaseUserHeader());
+        return OutDTO.ok(resData);
+    }
+
+    @ApiLog(title = "申请修改地址", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.4)
+    @PostMapping("/edit/address")
+    @ApiOperation("申请修改地址")
+    public OutDTO editAddress(@RequestBody InDto inDto) {
+        Integer id = inDto.getIntegerParam("id");
+        if (id == null) {
+            return OutDTO.error500("订单Id缺失!");
+        }
+        Integer addressId = inDto.getIntegerParam("addressId");
+        if (addressId == null) {
+            return OutDTO.error500("地址信息缺失!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        TzyShippingAddress address = shippingAddressService.selectUserAddress(user.getId(), addressId);
+        if (address == null) {
+            return OutDTO.error500("地址信息异常!");
+        }
+        JSONObject reqData = new JSONObject();
+        reqData.put("id", id);
+        reqData.put("addressId", addressId);
+        reqData.put("linkName", address.getLinkname());
+        reqData.put("phone", address.getPhone());
+        reqData.put("address", address.getAddress() + address.getAddressMore());
+        reqSaasResult(saasBaseUrl + editActOrderAddr, reqData, user.getBaseUserHeader());
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "删除活动订单", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.4)
+    @PostMapping("/order/del")
+    @ApiOperation("删除活动订单")
+    public OutDTO delActOrder(@RequestBody InDto inDto) {
+        Integer id = inDto.getIntegerParam("id");
+        if (id == null) {
+            return OutDTO.error500("订单Id缺失!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        JSONObject reqData = new JSONObject();
+        reqData.put("id", id);
+        reqSaasResult(saasBaseUrl + delActOrderUrl, reqData, user.getBaseUserHeader());
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "活动订单确认收货", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.4)
+    @PostMapping("/order/confirm")
+    @ApiOperation("活动订单确认收货")
+    public OutDTO confirmActOrder(@RequestBody InDto inDto) {
+        Integer id = inDto.getIntegerParam("id");
+        if (id == null) {
+            return OutDTO.error500("订单Id缺失!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        JSONObject reqData = new JSONObject();
+        reqData.put("id", id);
+        reqSaasResult(saasBaseUrl + confirmActOrderUrl, reqData, user.getBaseUserHeader());
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "删除活动订单", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.4)
+    @PostMapping("/order/cancel")
+    @ApiOperation("删除活动订单")
+    public OutDTO cancelActOrder(@RequestBody InDto inDto) {
+        Integer id = inDto.getIntegerParam("id");
+        if (id == null) {
+            return OutDTO.error500("订单Id缺失!");
+        }
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        CardGroupOrderInfo orderInfo = cardGroupOrderInfoService.getOrderByUserAndId(user.getId(), id.longValue());
+        if (orderInfo.getStatus() != 100) {
+            return OutDTO.error500("订单不可取消!");
+        }
+        if (Constants.ORDER_TYPE_DRAW.equals(orderInfo.getOrderType()) || Constants.ORDER_TYPE_GIFT_CARD.equals(orderInfo.getOrderType())) {
+            mallOrderService.cancelDrawOrder(orderInfo);
+        }
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "拼团活动列表", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.4)
+    @PostMapping("/info/gift")
+    @ApiOperation("拼团活动列表")
+    public OutDTO getInfoGiftAct(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if (user == null) {
+            return OutDTO.error500("请先登录!");
+        }
+        List<SysDictData> typeData = commonCacheService.getCommonDictData(Constants.INFO_GIVE_DRAW, null, "1", Constants.INFO_GIVE_DRAW, 84600);
+        if (CollectionUtils.isEmpty(typeData)) {
+            return OutDTO.ok();
+        }
+        SysDictData data = typeData.get(0);
+        String paniniBaseId = data.getDictValue();
+        long actId = data.getDictSort();
+        List<InfoGiveActDTO> acts = groupApiService.getInfoGiftAct(actId, Integer.valueOf(paniniBaseId), user.getId());
+        return OutDTO.ok().put("acts", acts);
+    }
+
+    @ApiLog(title = "拼团砍一刀活动列表", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.6)
+    @PostMapping("/group/amount")
+    @ApiOperation("拼团砍一刀活动列表")
+    public OutDTO getGroupAmountAct(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        List<GroupAmountActDTO> acts=appActService.getGroupAmountAct(user.getId(),inDto.getIntegerParam("actId"));
+        return OutDTO.ok().put("acts", acts);
+    }
+
+    @ApiLog(title = "参与拼团砍一刀", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.6)
+    @PostMapping("/group/amount/join")
+    @ApiLimitRule(seconds = 5, limitCount = 25, type = LimitRule.ACT, msg = "参数人数太多,请稍后再试!")
+    @ApiOperation("参与拼团砍一刀")
+    public OutDTO joinGroupAmountAct(@RequestBody InDto inDto) {
+        AppUserInfoDto user = mineApiService.checkUserNew(inDto);
+        Integer actId = inDto.getIntegerParam("actId");
+        if(actId==null){
+            return OutDTO.error500("活动Id缺失!");
+        }
+        AmountActResult result=appActService.joinGroupAmountAct(user,actId,inDto.getIntegerParam("shareUserId"));
+        return OutDTO.ok().put("actResult", result);
+    }
+
+    @ApiLog(title = "拼团砍一刀邀请记录", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.6)
+    @PostMapping("/group/share/record")
+    @ApiOperation("拼团砍一刀邀请记录")
+    @SensitiveData
+    public OutDTO userShareRecord(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        String actType = inDto.getString("actType");
+        actType = StringUtils.isEmpty(actType) ? Constants.ACT_GROUP_DECR_AMOUNT : actType;
+        ActCountParam param = new ActCountParam().setUserId(user.getId()).setActType(actType);
+        PageInfo<ShareRecordDTO> records=appActService.userShareRecords(param,inDto.getPageNo(),inDto.getPageSize());
+        return OutDTO.ok().put("records", records);
+    }
+
+    @ApiLog(title = "砍一刀分享回显", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.6)
+    @PostMapping("/share/apply")
+    @ApiOperation("砍一刀分享回显")
+    public OutDTO userApplyShare(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        Integer actId = inDto.getIntegerParam("actId");
+        AmountActResult shareResult = appActService.userApplyShare(actId, user);
+        return OutDTO.ok().put("shareResult",shareResult);
+    }
+
+    @ApiLog(title = "分享code查询", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.6)
+    @PostMapping("/share/search")
+    @ApiOperation("分享code查询")
+    public OutDTO searchUserShare(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        String code = inDto.getString("code");
+        if(StringUtils.isEmpty(code)){
+            return OutDTO.error500("code缺失!");
+        }
+        GroupAmountActDTO act=appActService.getActByShareCode(user.getId(),code);
+        return OutDTO.ok().put("act",act);
+    }
+
+    @ApiLog(title = "拼团砍一刀弹窗户", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.6)
+    @PostMapping("/group/popup")
+    @ApiOperation("拼团砍一刀弹窗户")
+    public OutDTO getGroupPopupAct(@RequestBody InDto inDto) {
+        return OutDTO.ok().put("act",null);
+    }
+
+    @ApiLog(title = "拼团砍一刀弹窗户", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.6)
+    @PostMapping("/v2/group/popup")
+    @ApiOperation("拼团砍一刀弹窗户")
+    public OutDTO getGroupPopupActV2(@RequestBody InDto inDto) {
+        ActPopUpDTO act = appActService.getGroupPopupAct();
+        return OutDTO.ok().put("act", act);
+    }
+
+    @ApiLog(title = "活动商品拆卡报告", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.6)
+    @PostMapping("/sku/report")
+    @ApiOperation("活动商品拆卡报告")
+    public OutDTO getActSkuReport(@RequestBody InDto inDto) {
+        String actType = inDto.getString("actType");
+        actType = StringUtils.isEmpty(actType) ? Constants.ACT_CARD_REMOVAL : actType;
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        boolean limitStatus = !UserType.USER_ROLE_ADMIN.equals(user.getRoleCode());
+        List<ActReportDTO> reports = appActService.getActSkuReport(actType, user.getId(), limitStatus, inDto.getOffset(), inDto.getPageSize());
+        return OutDTO.ok().put("reports",reports);
+    }
+
+    @ApiLog(title = "活动商品拆卡报告", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.6)
+    @PostMapping("/sku/report/like")
+    @ApiOperation("活动商品拆卡报告")
+    public OutDTO getLikeActSkuReport(@RequestBody InDto inDto) {
+        String actType = inDto.getString("actType");
+        actType = StringUtils.isEmpty(actType) ? Constants.ACT_CARD_REMOVAL : actType;
+        List<ActReportDTO> reports=appActService.getLikeActSkuReport(actType, inDto.getPageSize());
+        return OutDTO.ok().put("reports",reports);
+    }
+
+    @ApiLog(title = "精选卡密赠品", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.6)
+    @RequireRoles(UserType.USER_ROLE_ADMIN)
+    @PostMapping("/sku/report/prize")
+    @ApiOperation("精选卡密赠品")
+    public OutDTO sendLikeReportPrize(@RequestBody InDto inDto) {
+        Integer orderId = inDto.getIntegerParam("orderId");
+        Integer prizeId = inDto.getIntegerParam("prizeId");
+        //购买资格类型 reduction_buy_num
+        String prizeType = inDto.getStringDefault("prizeType",Constants.SKU_TYPE_GOODS);
+        //购买资格
+        Integer reductionNum = inDto.getIntegerDefault("reductionNum", 1);
+        if (prizeId == null) {
+            List<SysDictData> dataList = commonCacheService.getCommonDictData("act_report_prize", null, "1", "act_report_prize", 3600);
+            if (CollectionUtils.isEmpty(dataList)) {
+                return OutDTO.error500("未配置赠品!");
+            }
+            prizeId = Integer.valueOf(dataList.get(0).getDictValue());
+        }
+        appActService.sendLikeReportPrize(orderId.longValue(), prizeId,prizeType,reductionNum);
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "砍一刀红包", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(2.6)
+    @PostMapping("/amount/gift")
+    @ApiOperation("砍一刀红包")
+    public OutDTO getActGiftAct(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(user, MsgConstants.NEED_LOGIN);
+        List<InfoGiveActDTO> acts = groupApiService.getInfoGiftActByRef(user.getId());
+        return OutDTO.ok().put("acts", acts);
+    }
+
+
+    @ApiLog(title = "首页红包-字典表发放", businessType = BusinessType.SEARCH)
+    @ApiOperation("首页红包-字典表发放")
+    @ResponseBody
+    @ApiLimitRule(seconds = 1, limitCount = 5, type = LimitRule.USER, msg = "请勿频繁操作")
+    @ApiVersion(3.0)
+    @PostMapping("/home/draw")
+    public OutDTO getHomeDrawAct(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(user, MsgConstants.NEED_LOGIN);
+        List<AppActManageDTO> acts=appActService.getHomeDrawAct(user.getId());
+        return OutDTO.ok().put("acts", acts);
+    }
+
+    @ApiLog(title = "首页红包-字典表发放", businessType = BusinessType.SEARCH)
+    @ApiOperation("首页红包-字典表发放")
+    @ResponseBody
+    @ApiLimitRule(seconds = 1, limitCount = 5, type = LimitRule.USER, msg = "请勿频繁操作")
+    @ApiVersion(4.5)
+    @PostMapping("/home/draw")
+    public OutDTO getHomeDrawAct45(@RequestBody InDto inDto) {
+        return OutDTO.error(404,"4.5版本已下线");
+    }
+
+    @ApiLog(title = "首页红包-字典表发放", businessType = BusinessType.SEARCH)
+    @ApiOperation("首页红包-字典表发放")
+    @ResponseBody
+    @ApiLimitRule(seconds = 1, limitCount = 5, type = LimitRule.USER, msg = "请勿频繁操作")
+    @ApiVersion(4.6)
+    @PostMapping("/home/draw")
+    public OutDTO getHomeDrawAct46(@RequestBody InDto inDto) {
+        return OutDTO.error(404,"4.6版本已下线");
+    }
+
+    @ApiLog(title = "首页红包-字典表发放", businessType = BusinessType.SEARCH)
+    @ApiOperation("首页红包-字典表发放")
+    @ResponseBody
+    @ApiLimitRule(seconds = 1, limitCount = 5, type = LimitRule.USER, msg = "请勿频繁操作")
+    @ApiVersion(4.7)
+    @PostMapping("/home/draw")
+    public OutDTO getHomeDrawAct47(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppAssert.notNull(user, MsgConstants.NEED_LOGIN);
+        List<AppActManageDTO> acts=appActService.getHomeDrawAct(user.getId());
+        return OutDTO.ok().put("acts", acts);
+    }
+
+    //region 2025-618活动
+
+    @ApiLog(title = "2025-618砍一刀活动", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiLimitRule(seconds = 1, limitCount = 5, type = LimitRule.USER, msg = "请勿频繁操作")
+    @ApiVersion(3.8)
+    @PostMapping("/group/amount")
+    @ApiOperation("2025-618活动拼团砍一刀商品秒杀抢拍")
+    public OutDTO getGroupGoodsBidAct(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        List<GroupAmountActDTO> acts = appActService.getGroupAmountActV2(user.getId(),inDto.getIntegerParam("actId"));
+        return OutDTO.ok().put("acts", acts);
+    }
+
+    @ApiLog(title = "2025-618看视频领优惠活动", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(3.8)
+    @ApiLimitRule(seconds = 1, limitCount = 5, type = LimitRule.USER, msg = "请勿频繁操作")
+    @PostMapping("/watch/video")
+    @ApiOperation("2025-618看视频领优惠活动")
+    public OutDTO getWatchVideoAct(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppActManage act = appActService.getWatchVideoAct(user.getId());
+        boolean isComplete =appActService.isVideoTaskComplete(act.getRuleConfig());
+        boolean isPrizeSent =appActService.isActTaskPrizeSent(user,act);
+        return OutDTO.ok().put("acts", act).put("completed",isComplete).put("prizesent",isPrizeSent);
+    }
+
+    @ApiLog(title = "2025-618看视频领优惠活动", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(3.8)
+    @ApiLimitRule(seconds = 1, limitCount = 5, type = LimitRule.USER, msg = "请勿频繁操作")
+    @PostMapping("/watch/complete")
+    @ApiOperation("用户看完视频记录")
+    public OutDTO setWatchComplete(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppActManage act = appActService.setWatchComplete(user,inDto.getString("videoId"));
+        if(act==null){
+            return OutDTO.ok();
+        }
+        boolean isComplete =appActService.isVideoTaskComplete(act.getRuleConfig());
+        boolean isPrizeSent =appActService.isActTaskPrizeSent(user,act);
+        return OutDTO.ok().put("acts", act).put("completed",isComplete).put("prizesent",isPrizeSent);
+    }
+
+    @ApiLog(title = "2025-618领红包优惠活动", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(3.8)
+    @ApiLimitRule(seconds = 1, limitCount = 5, type = LimitRule.USER, msg = "请勿频繁操作")
+    @PostMapping("/coupon/list")
+    @ApiOperation("2025-618领红包优惠活动")
+    public OutDTO getCouponListAct(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        List<AppActManage> acts = appActService.getCouponFetchActList(user);
+        boolean hasnoInterrupt = appActService.checkInterrupt(user,acts);
+        Integer totalFetch = 0;
+        Integer totalUsed = 0;
+        Integer totalProgress = 0;
+        for (AppActManage act : acts) {
+            if(act.isPrizeFetched()){totalFetch += 1;}
+            if(act.isPrizeUsed()){totalUsed +=1;}
+            totalProgress = totalUsed;
+        }
+        return OutDTO.ok().put("acts", acts).put("hasInterrupt",!hasnoInterrupt).put("totalFetch",totalFetch).put("totalUsed",totalUsed).put("totalProgress",totalProgress);
+    }
+
+    @ApiLog(title = "2025-618领红包优惠活动", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(3.8)
+    @ApiLimitRule(seconds = 1, limitCount = 5, type = LimitRule.USER, msg = "请勿频繁操作")
+    @PostMapping("/coupon/fetch")
+    @ApiOperation("2025-618领红包")
+    public OutDTO getCouponFetchAct(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        List<AppActManage> actsFetch = appActService.getCouponFetchAct(user,inDto.getIntegerParam("actId"));
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "2025-618完善用户信息优惠活动", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(3.8)
+    @ApiLimitRule(seconds = 1, limitCount = 5, type = LimitRule.USER, msg = "请勿频繁操作")
+    @PostMapping("/complete/profile")
+    @ApiOperation("2025-618完善用户信息优惠活动")
+    public OutDTO getCompleteProfileAct(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppActManage act = appActService.getCompleteProfileAct(user.getId());
+        boolean isComplete =appActService.isProfileTaskComplete(act.getRuleConfig());
+        boolean isPrizeSent =appActService.isActTaskPrizeSent(user,act);
+        return OutDTO.ok().put("acts", act).put("completed",isComplete).put("prizesent",isPrizeSent);
+    }
+    @ApiLog(title = "2025-618完善用户信息优惠活动", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(3.8)
+    @ApiLimitRule(seconds = 1, limitCount = 5, type = LimitRule.USER, msg = "请勿频繁操作")
+    @PostMapping("/complete/type")
+    @ApiOperation("2025-618完善用户信息优惠活动")
+    public OutDTO setCompleteProfileType(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppActManage act = appActService.setCompleteProfileType(user,inDto.getString("type"));
+        if(act==null){
+            return OutDTO.ok();
+        }
+        boolean isComplete =appActService.isProfileTaskComplete(act.getRuleConfig());
+        boolean isPrizeSent =appActService.isActTaskPrizeSent(user,act);
+        return OutDTO.ok().put("acts", act).put("completed",isComplete).put("prizesent",isPrizeSent);
+    }
+
+    @ApiLog(title = "2025-618用户领取活动优惠", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(3.8)
+    @ApiLimitRule(seconds = 1, limitCount = 5, type = LimitRule.USER, msg = "请勿频繁操作")
+    @PostMapping("/get/prize")
+    @ApiOperation("2025-618用户领取活动优惠")
+    public OutDTO getActPrize(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo(true);
+        AppActManage act = appActService.getActPrize(user,inDto.getIntegerParam("actId"));
+        if(act.getType()=="complete_profile"){
+            boolean isComplete =appActService.isProfileTaskComplete(act.getRuleConfig());
+            boolean isPrizeSent =appActService.isActTaskPrizeSent(user,act);
+            return OutDTO.ok().put("acts", act).put("completed",isComplete).put("prizesent",isPrizeSent);
+        } else if (act.getType()=="watch_video") {
+            boolean isComplete =appActService.isVideoTaskComplete(act.getRuleConfig());
+            boolean isPrizeSent =appActService.isActTaskPrizeSent(user,act);
+            return OutDTO.ok().put("acts", act).put("completed",isComplete).put("prizesent",isPrizeSent);
+        }
+        return OutDTO.ok().put("acts", act);
+    }
+
+
+    @ApiLog(title = "拼团砍一刀弹窗户", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @ApiVersion(3.8)
+    @PostMapping("/group/popup")
+    @ApiOperation("拼团砍一刀弹窗户")
+    public OutDTO getGroupPopupActV3(@RequestBody InDto inDto) {
+        ActPopUpDTO act = appActService.getGroupPopupActV2();
+        return OutDTO.ok().put("act", act);
+    }
+    //endregion
+
+    //region 2025抽取拉卜卜活动
+
+    @ApiLog(title = "今天是否能参与labubu活动", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/luck/point/exchange/today", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("今天是否能参与labubu活动")
+    @ApiLimitRule(seconds = 1, limitCount = 5, type = LimitRule.COMMON, msg = "抱歉,兑换人数太多,请稍后再试!")
+    public OutDTO luckPointExchangeToday(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        inDto.setUserId(user.getId());
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        Boolean verifyUserActJoin = true;
+        Boolean completeOrderActJoin = true;
+        Boolean verifyUserActJoinRecord = true;
+        Boolean completeOrderActJoinRecord = true;
+        //检查今日已参加过
+        verifyUserActJoin = appActService.checkCurrentDayActJoin("verify_user_act",user.getId());
+        verifyUserActJoinRecord = verifyUserActJoin;
+        if(!verifyUserActJoin){
+            //没参加过检查实名状态
+            if(userInfo.getFaceVerify()<=0
+                    //||!userInfo.getPayInfoFlag()
+            ){
+                verifyUserActJoin = true;
+            }
+        }
+        //检查今日已参加过
+        completeOrderActJoin = appActService.checkCurrentDayActJoin("complete_order_act",user.getId());
+        completeOrderActJoinRecord = completeOrderActJoin;
+        if(!completeOrderActJoin){
+            //没参加过检查消费达标
+            completeOrderActJoin = !appActService.checkCurrentDayCompleteOrder(user.getId());
+        }
+        return OutDTO.ok("verify_user_act/complete_order_act 为true能参加活动").put("verify_user_act", !verifyUserActJoin).put("complete_order_act",
+                !completeOrderActJoin).put("verify_user_act_joined", verifyUserActJoinRecord).put("complete_order_act_joined",
+                completeOrderActJoinRecord);
+    }
+
+    @ApiLog(title = "参与兑换拉卜卜活动", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/luck/point/exchange", method = RequestMethod.POST)
+    @ApiVersion(4.1)
+    @ApiOperation("参与兑换拉卜卜活动")
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.COMMON, msg = "抱歉,兑换人数太多,请稍后再试!")
+    public OutDTO luckPointExchangeLabubu(@RequestBody InDto inDto) {
+        Integer actId = (Integer) inDto.get("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        Integer purchaseCount = (Integer) inDto.get("purchaseCount");
+        if (purchaseCount == null || purchaseCount < 1) {
+            return OutDTO.error500("兑换数量异常!");
+        }
+        Boolean anonymous = (Boolean) inDto.get("anonymous");
+        int isShow = anonymous != null && anonymous ? 0 : 1;
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        AppActManage act = appActService.getAppActManageByID(actId);
+        if(act==null){
+            return OutDTO.error500("活动不存在!");
+        }
+
+        if(act.getType().equals("verify_user_act")) {
+            //检查用户是否实名并且今天是否参加过
+            if(userInfo.getFaceVerify()<=0
+                //||!userInfo.getPayInfoFlag()
+            ){
+                return OutDTO.error500("未实名用户不能参加!");
+            }
+            Boolean verifyUserActJoin = appActService.checkCurrentDayActJoin("verify_user_act",userInfo.getId());
+            if(verifyUserActJoin){
+                return OutDTO.error500("今天已经参加过了!");
+            }
+            AppUserPointRecord pointRecord = new AppUserPointRecord();
+            pointRecord.setChangePoint(100L);
+            pointRecord.setType("verify_user_act");
+            pointRecord.setCreateTime(new Date());
+            pointRecord.setMerchantId(act.getMerchantId());
+            pointRecord.setUserId(userInfo.getId().longValue());
+            pointRecord.setRefId(actId+""+userInfo.getId());
+            mineApiService.addUserPoint(pointRecord);
+        }
+        if(act.getType().equals("complete_order_act")) {
+            //检查用户今天下单达标并且今天是否参加过
+            Boolean todayCompleteOrder = appActService.checkCurrentDayCompleteOrder(userInfo.getId());
+            if(!todayCompleteOrder){
+                return OutDTO.error500("今天未达到兑换条件!");
+            }
+            Boolean completeOrderActJoin = appActService.checkCurrentDayActJoin("complete_order_act",userInfo.getId());
+            if(completeOrderActJoin){
+                return OutDTO.error500("今天已经参加过了!");
+            }
+            AppUserPointRecord pointRecord = new AppUserPointRecord();
+            pointRecord.setChangePoint(100L);
+            pointRecord.setType("complete_order_act");
+            pointRecord.setCreateTime(new Date());
+            pointRecord.setMerchantId(act.getMerchantId());
+            pointRecord.setUserId(userInfo.getId().longValue());
+            pointRecord.setRefId(actId+""+userInfo.getId());
+            mineApiService.addUserPoint(pointRecord);
+        }
+        if(act.getType().equals("verify_user_act")||act.getType().equals("complete_order_act")){
+            appActService.luckPointExchange(actId, 1, userInfo, isShow,true);
+        }
+        else{
+            appActService.luckPointExchange(actId, purchaseCount, userInfo, isShow,true);
+        }
+
+        return OutDTO.ok();
+    }
+
+    //endregion
+
+    //region labubu 活动2.0 支持活动下添加任务
+    /// 传入字典类型时,根据字典查询出所有的几分类型,再根据活动绑定的积分类型查询出活动列表
+    /// 如果传入字典键值则查询出键值对应的活动
+    @ApiLog(title = "根据字典类型获取绑定过此奖品的所有活动列表", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/luck/point/exchange/labubu", method = RequestMethod.POST)
+    @ApiVersion(4.3)
+    @ApiOperation("根据字典类型获取绑定过此奖品的所有活动列表")
+    @ApiLimitRule(seconds = 1, limitCount = 10, type = LimitRule.COMMON, msg = "抱歉,兑换人数太多,请稍后再试!")
+    public OutDTO luckPointExchangeLabubuV2(@RequestBody InDto inDto) {
+        List<AppActManage> acts = new ArrayList<>();
+        String actType =inDto.getString("actDicType");
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        if(actType!=null){
+            List<SysDictData> sysDictDatas = commonCacheService.getCommonDictData("lucky_point",
+                    null,"1", null, -1);
+            List<SysDictData> result = sysDictDatas.stream()
+                    .filter(data -> actType.equals(data.getRemark()))
+                    .collect(Collectors.toList());
+            acts = appActService.getActListByPointType(result.stream().map(SysDictData::getDictValue).collect(Collectors.toList()));
+        }
+        else{
+                acts = appActService.getAppActManage("act_task",false);
+        }
+
+        if(acts==null||acts.size()<=0){
+            return OutDTO.error500("活动不存在!");
+        }
+        for (AppActManage act:acts) {
+            appActService.getActTaskTotalAmount(user,act.getId().intValue());
+        }
+        acts.sort((a, b) -> Long.compare(b.getId(), a.getId()));
+        return OutDTO.ok().put("acts",acts);
+    }
+
+    //获取活动和活动中的所有任务
+    @ApiLog(title = "获取活动", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/luck/point/exchange/labubu/act", method = RequestMethod.POST)
+    @ApiVersion(4.3)
+    @ApiOperation("获取活动和活动中的所有任务")
+    @ApiLimitRule(seconds = 1, limitCount = 20, type = LimitRule.COMMON, msg = "抱歉,兑换人数太多,请稍后再试!")
+    public OutDTO luckPointExchangeLabubuV2Act(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        inDto.setUserId(user.getId());
+        Integer actId = (Integer) inDto.get("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        AppActManage act = appActService.getAppActManageByID(actId);
+        //此活动的总参与次数
+        int totalPoint = appActService.getActTaskTotalPoint(user,actId);
+        //已点亮
+        List<AppActTaskPrizeRecord> joinedList = appActService.getJoinedPoint(actId,user.getId());
+        //剩余点亮数
+        List<AppActTaskPrizeRecord> notJoinList = appActService.getNotJoinedPoint(actId,user.getId());
+        if(act==null){
+            return OutDTO.error500("活动不存在!");
+        }
+        AppActManage refAct = appActService.getAppActManageAllStatusByID(act.getRefActId());
+        return OutDTO.ok().put("act",act).put("refAct",refAct).put("joinedList",joinedList).put("notJoinList",notJoinList).put("remainPoint",notJoinList.size()).put("totalPoint",totalPoint).put("joinedPoint",joinedList.size());
+    }
+
+    //获取活动和活动中的所有任务
+    @ApiLog(title = "获取活动和活动中的所有任务", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/luck/point/exchange/labubu/tasks", method = RequestMethod.POST)
+    @ApiVersion(4.3)
+    @ApiOperation("获取活动和活动中的所有任务")
+    @ApiLimitRule(seconds = 1, limitCount = 10, type = LimitRule.COMMON, msg = "抱歉,兑换人数太多,请稍后再试!")
+    public OutDTO luckPointExchangeLabubuV2AllTasks(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        Integer actId = (Integer) inDto.get("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        //查询当前活动下的所有任务
+        List<AppActTaskManage> appActTasks = appActService.getActTaskList(actId,user);
+        if(appActTasks==null||appActTasks.size()<=0){
+            return OutDTO.error500("活动下没有任务!");
+        }
+        appActTasks.sort((a, b) -> Long.compare(b.getId(), a.getId()));
+        return OutDTO.ok().put("tasks",appActTasks);
+    }
+
+    //兑换抽奖码(点亮)
+    @ApiLog(title = "参与兑换拉卜卜活动抽奖次数", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/luck/point/exchange/labubu/task/prize", method = RequestMethod.POST)
+    @ApiVersion(4.3)
+    @ApiOperation("参与兑换拉卜卜活动抽奖次数")
+    @ApiLimitRule(seconds = 1, limitCount = 10, type = LimitRule.COMMON, msg = "抱歉,兑换人数太多,请稍后再试!")
+    public OutDTO luckPointExchangeLabubuV2TasksPize(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        inDto.setUserId(user.getId());
+        Integer actId = (Integer) inDto.get("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        AppActManage act = appActService.getAppActManageByID(actId);
+        if(act==null){
+            return OutDTO.error500("活动不存在!");
+        }
+        if(act.getType().equals("act_task")) {
+            //查询当前活动下的所有任务
+            List<AppActTaskManage> appActTasks = appActService.getActTaskList(actId,user);
+            if(appActTasks==null||appActTasks.size()<=0){
+                return OutDTO.error500("活动下没有任务!");
+            }
+            ActTaskJoinDTO joinDTO = appActService.joinActTask(user,actId,act);
+            return OutDTO.ok().put("ActTaskJoin",joinDTO);
+        }
+
+        return OutDTO.ok();
+    }
+
+    //参与记录
+    @ApiLog(title = "查询拉卜卜活动参与记录", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/luck/point/exchange/labubu/task/record", method = RequestMethod.POST)
+    @ApiVersion(4.3)
+    @ApiOperation("查询拉卜卜活动参与记录")
+    @ApiLimitRule(seconds = 1, limitCount = 10, type = LimitRule.COMMON, msg = "抱歉,兑换人数太多,请稍后再试!")
+    public OutDTO luckPointExchangeLabubuV2TasksRecord(@RequestBody InDto inDto) {
+        List<AppActManage> acts = new ArrayList<>();
+        String actType =inDto.getString("actDicType");
+        if(actType!=null){
+            List<SysDictData> sysDictDatas = commonCacheService.getCommonDictData("lucky_point",
+                    null,"1", null, -1);
+            List<SysDictData> result = sysDictDatas.stream()
+                    .filter(data -> actType.equals(data.getRemark()))
+                    .collect(Collectors.toList());
+            acts = appActService.getActListByPointType(result.stream().map(SysDictData::getDictValue).collect(Collectors.toList()));
+        }
+        else{
+            acts = appActService.getAppActManage("act_task",false);
+        }
+        if(acts==null||acts.size()<=0){
+            return OutDTO.error500("活动不存在!");
+        }
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        inDto.setUserId(user.getId());
+        //map存储act和对应的records
+        Map<Integer,AppActManage> actRecordMap = new HashMap<>();
+        for(AppActManage act:acts){
+                //查询当前活动下的所有任务
+                //List<AppActTaskPrizeRecord> records = appActService.getActPrizeRecordList(act.getId().intValue(),user);
+                //actRecordMap.put(act.getId().intValue(),records);
+                List<PublicPrizeCodeDTO> records = appActService.getActPointPrizeRecordList(act.getRefActId(),user);
+                act.setPrizeCodeList(records);
+                actRecordMap.put(act.getId().intValue(),act);
+
+        }
+        return OutDTO.ok().put("actRecord",actRecordMap);
+    }
+
+    //生成助力分享信息
+    @ApiLog(title = "生成助力分享信息", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/luck/point/exchange/labubu/task/share/info", method = RequestMethod.POST)
+    @ApiVersion(4.3)
+    @ApiOperation("生成助力分享信息")
+    @ApiLimitRule(seconds = 1, limitCount = 10, type = LimitRule.COMMON, msg = "抱歉,兑换人数太多,请稍后再试!")
+    public OutDTO luckPointExchangeLabubuV2TasksShareInfo(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        Integer actId = (Integer) inDto.get("actId");
+        Integer taskId = (Integer) inDto.get("taskId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        AppActManage act = appActService.getAppActManageByID(actId);
+        if(act==null){
+            return OutDTO.error500("活动不存在!");
+        }
+        if(act.getType().equals("act_task")) {
+            //查询当前活动下的所有任务
+            List<AppActTaskManage> appActTasks = appActService.getActTaskList(actId,user);
+            if(appActTasks==null||appActTasks.size()<=0){
+                return OutDTO.error500("活动下没有任务!");
+            }
+            Optional<AppActTaskManage> task = appActTasks.stream()
+                    .filter(t -> t.getId().equals(taskId))
+                    .findFirst();
+            if (task.isPresent()) {
+                ShareActResult shareActResult = new ShareActResult();
+                shareActResult = appActService.getUserShareActResult(user,actId,task.get());
+                return OutDTO.ok().put("shareActResult",shareActResult);
+            } else {
+                return OutDTO.error500("活动不存在!");
+            }
+
+        }
+        return OutDTO.ok();
+    }
+
+    //校验助力分享信息并发送奖励
+    @ApiLog(title = "校验助力分享信息并发送奖励", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/luck/point/exchange/labubu/task/share/check", method = RequestMethod.POST)
+    @ApiVersion(4.3)
+    @ApiOperation("校验助力分享信息并发送奖励")
+    @ApiLimitRule(seconds = 1, limitCount = 10, type = LimitRule.COMMON, msg = "抱歉,兑换人数太多,请稍后再试!")
+    public OutDTO luckPointExchangeLabubuV2TasksShareCheck(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        Integer actId = (Integer) inDto.get("actId");
+        Integer taskId = (Integer) inDto.get("taskId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        AppActManage act = appActService.getAppActManageByID(actId);
+        if(act==null){
+            return OutDTO.error500("活动不存在!");
+        }
+        String code = inDto.getString("code");
+        if(act.getType().equals("act_task")) {
+            //查询当前活动下的所有任务
+            List<AppActTaskManage> appActTasks = appActService.getActTaskList(actId,user);
+            if(appActTasks==null||appActTasks.size()<=0){
+                return OutDTO.error500("活动下没有任务!");
+            }
+            Optional<AppActTaskManage> task = appActTasks.stream()
+                    .filter(t -> t.getId().equals(taskId))
+                    .findFirst();
+            if (task.isPresent()) {
+                ShareActResult shareActResult = appActService.getShareActResult(code);
+                appActService.checkUserShareActResult(user,actId,task.get(),shareActResult);
+                return OutDTO.ok().put("shareActResult",shareActResult);
+            } else {
+                return OutDTO.error500("活动不存在!");
+            }
+
+        }
+        return OutDTO.ok();
+    }
+
+    //执行助力
+    @ApiLog(title = "执行助力", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/luck/point/exchange/labubu/task/share/apply", method = RequestMethod.POST)
+    @ApiVersion(4.3)
+    @ApiOperation("执行助力")
+    @ApiLimitRule(seconds = 1, limitCount = 10, type = LimitRule.COMMON, msg = "抱歉,兑换人数太多,请稍后再试!")
+    public OutDTO luckPointExchangeLabubuV2TasksShareApply(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        String code = inDto.getString("code");
+        try {
+            appActService.applyActTaskShareRecord(user,code);
+            return OutDTO.ok("助力成功!");
+        }catch (ServiceException e){
+            log.error("助力失败: {}", e.getMessage());
+            return OutDTO.error500("助力失败!"+e.getMessage());
+        }
+    }
+
+    //参与助力邀请记录
+    @ApiLog(title = "参与助力邀请记录", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/luck/point/exchange/labubu/task/share/apply/record", method = RequestMethod.POST)
+    @ApiVersion(4.3)
+    @ApiOperation("参与助力邀请记录")
+    @ApiLimitRule(seconds = 1, limitCount = 10, type = LimitRule.COMMON, msg = "抱歉,兑换人数太多,请稍后再试!")
+    public OutDTO luckPointExchangeLabubuV2TasksShareApplyRecord(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        Integer actId = (Integer) inDto.get("actId");
+        Integer taskId = (Integer) inDto.get("taskId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        AppActManage act = appActService.getAppActManageByID(actId);
+        if(act==null){
+            return OutDTO.error500("活动不存在!");
+        }
+        if(act.getType().equals("act_task")) {
+            //查询当前活动下的所有任务
+            List<AppActTaskPrizeRecord> record = appActService.getActPrizeShareApplyRecordList(actId,taskId,user.getId());
+            return OutDTO.ok().put("record",record);
+        }
+
+        return OutDTO.ok();
+    }
+
+    //分享记录
+    @ApiLog(title = "分享记录", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/luck/point/exchange/labubu/task/share/record", method = RequestMethod.POST)
+    @ApiVersion(4.3)
+    @ApiOperation("分享记录")
+    @ApiLimitRule(seconds = 1, limitCount = 10, type = LimitRule.COMMON, msg = "抱歉,兑换人数太多,请稍后再试!")
+    public OutDTO luckPointExchangeLabubuV2TasksShareRecord(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        Integer actId = (Integer) inDto.get("actId");
+        Integer taskId = (Integer) inDto.get("taskId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        AppActManage act = appActService.getAppActManageByID(actId);
+        if(act==null){
+            return OutDTO.error500("活动不存在!");
+        }
+        if(act.getType().equals("act_task")) {
+            //查询当前活动下的所有任务
+            List<AppActTaskPrizeRecord> record = appActService.getActPrizeShareRecordList(actId,taskId,user.getId());
+            return OutDTO.ok().put("record",record);
+        }
+
+        return OutDTO.ok();
+    }
+
+    //参与助力分享h5回显
+    @ApiLog(title = "参与助力后信息展示", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/luck/point/exchange/labubu/task/share/disp", method = RequestMethod.POST)
+    @ApiVersion(4.3)
+    @ApiOperation("参与助力后信息展示")
+    @ApiLimitRule(seconds = 1, limitCount = 10, type = LimitRule.COMMON, msg = "抱歉,兑换人数太多,请稍后再试!")
+    public OutDTO luckPointExchangeLabubuV2TasksShareDisp(@RequestBody InDto inDto) {
+        String code = inDto.getString("code");
+        ShareActResult shareActResult = appActService.getShareActResult(code);
+        AppActManage act = appActService.getAppActManageByID(shareActResult.getActId());
+        if(act==null){
+            return OutDTO.error500("活动不存在!");
+        }
+        return OutDTO.ok().put("act",act).put("shareInfo",shareActResult);
+    }
+
+
+    //参与签到活动
+    @ApiLog(title = "参与签到活动", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/luck/point/exchange/labubu/task/checkin", method = RequestMethod.POST)
+    @ApiVersion(4.3)
+    @ApiOperation("参与签到活动")
+    @ApiLimitRule(seconds = 1, limitCount = 10, type = LimitRule.COMMON, msg = "抱歉,兑换人数太多,请稍后再试!")
+    public OutDTO luckPointExchangeLabubuV2TasksCheckIn(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        Integer actId = (Integer) inDto.get("actId");
+        Integer taskId = (Integer) inDto.get("taskId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        AppActManage act = appActService.getAppActManageByID(actId);
+        if(act==null){
+            return OutDTO.error500("活动不存在!");
+        }
+        if(act.getType().equals("act_task")) {
+            //查询当前活动下的所有任务
+            List<AppActTaskManage> appActTasks = appActService.getActTaskList(actId,user);
+            if(appActTasks==null||appActTasks.size()<=0){
+                return OutDTO.error500("活动下没有任务!");
+            }
+            Optional<AppActTaskManage> task = appActTasks.stream()
+                    .filter(t -> t.getId().equals(taskId) )
+                    .findFirst();
+            if (task.isPresent()) {
+                try {
+                    appActService.joinActTaskCheckIn(user,actId,task.get());
+                    return OutDTO.ok();
+                }catch (ServiceException e){
+                    log.error("失败: {}", e.getMessage());
+                    return OutDTO.error500("签到失败!"+e.getMessage());
+                }
+
+            } else {
+                return OutDTO.error500("活动不存在!");
+            }
+
+        }
+        return OutDTO.ok();
+    }
+
+    @ApiLog(title = "大转盘抽奖", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/luck/point/exchange/labubu/task/luckDraw", method = RequestMethod.POST)
+    @ApiVersion(1.0)
+    @ApiOperation("大转盘抽奖")
+    @ApiLimitRule(seconds = 1, limitCount = 1, type = LimitRule.USER,lockCount = 3,lockTime = 120,msg = "操作频繁,请稍后再试!")
+    public OutDTO labubuLuckDraw(@RequestBody InDto inDto) {
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        Integer actId = inDto.getIntegerParam("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        //已点亮
+        List<AppActTaskPrizeRecord> joinedList = appActService.getJoinedPoint(actId,user.getId());
+        AppUserInfoDto userInfo = mineApiService.checkUserNew(inDto);
+        AppActPrizeDTO userPrize = appActService.drawTaskPrize(actId, userInfo, joinedList);
+        return OutDTO.ok().put("userPrize", userPrize);
+    }
+    //endregion
+
+    //region 浏览指定页面时长
+    //浏览指定页面时长
+    @ApiLog(title = "浏览指定页面时长", businessType = BusinessType.SEARCH)
+    @ResponseBody
+    @RequestMapping(value = "/luck/point/exchange/labubu/task/view/page", method = RequestMethod.POST)
+    @ApiVersion(4.3)
+    @ApiOperation("浏览指定页面时长")
+    @ApiLimitRule(seconds = 1, limitCount = 10, type = LimitRule.COMMON, msg = "抱歉,参与人数太多,请稍后再试!")
+    public OutDTO luckPointExchangeLabubuV2TasksViewPage(@RequestBody InDto inDto) {
+
+        Integer actId = inDto.getIntegerParam("actId");
+        if (actId == null) {
+            return OutDTO.error500("活动参数未传!");
+        }
+        Integer taskId = (Integer) inDto.get("taskId");
+        if (taskId == null) {
+            return OutDTO.error500("任务参数未传!");
+        }
+        //校验用户参数上报的浏览地址是否存在
+        String pageUrl = inDto.getString("pageUrl");
+        if (StringUtils.isBlank(pageUrl)) {
+            return OutDTO.error500("页面参数未传!");
+        }
+        //校验用户浏览时长参数是否合法
+        Integer viewTime = inDto.getIntegerParam("viewTime");
+        if (viewTime == null || viewTime <= 0) {
+            log.info("浏览时长参数未传,actId: {}, taskId: {}, pageUrl: {}, viewTime: {}", actId, taskId, pageUrl, viewTime);
+            //return OutDTO.error500("浏览时长参数未传!");
+        }
+        AppActManage act = appActService.getAppActManageByID(actId);
+        if(act==null){
+            return OutDTO.error500("活动不存在!");
+        }
+        List<AppActTaskManage> appActTasks = appActService.getActTaskList(actId);
+        if(appActTasks==null||appActTasks.size()<=0){
+            return OutDTO.error500("活动下没有任务!");
+        }else {
+            if(!appActTasks.stream().anyMatch(t -> t.getId().equals(taskId))){
+                return OutDTO.error500("任务不存在!");
+            }
+        }
+        AppActTaskManage task = appActTasks.stream().filter(t -> t.getId().equals(taskId)).findFirst().orElse(null);
+        if(task==null){
+            return OutDTO.error500("任务不存在!");
+        }
+        UserInfo user = UserUtils.getSimpleUserInfo();
+        if(user==null){
+            return OutDTO.error500("请先登陆!");
+        }
+        //传入用户完成任务的活动id/浏览页地址等,校验是否完成了任务
+        try {
+            List<AppActTaskPrizeRecord> joinedList = appActService.joinActTaskViewPage(user,act,task,pageUrl,viewTime);
+            //根据joinedList 判断appActTasks中是否有已经参与过的任务
+            return OutDTO.ok()
+                    .put("acts", act)
+                    .put("completedTask",appActTasks.stream().filter(t -> joinedList.stream().anyMatch(j -> j.getTaskId().intValue()==(t.getId()))).collect(Collectors.toList()))
+                    .put("uncompletedTask",appActTasks.stream().filter(t -> !joinedList.stream().anyMatch(j -> j.getTaskId().intValue()==(t.getId()))).collect(Collectors.toList()));
+        }catch (ServiceException e){
+            log.error("失败: {}", e.getMessage());
+            return OutDTO.error500("浏览时长校验失败!"+e.getMessage());
+        }
+    }
+
+    //endregion
+}

+ 50 - 0
poyi-app/src/main/java/com/tzy/dto/AppActDTO.java

@@ -0,0 +1,50 @@
+package com.tzy.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @Description  
+ * @Author  poyee
+ * @Date 2022-10-10 
+ */
+
+@Data
+public class AppActDTO implements Serializable {
+
+	private static final long serialVersionUID =  8207660194957131175L;
+
+	private Long id;
+
+	/**
+	 * 优惠劵id集合,多个逗号拼接
+	 */
+	private String couponIds;
+
+	/**
+	 * 活动图片
+	 */
+	private String actImg;
+	/**
+	 * 图片:img,视频:video,动图:gif
+	 */
+	private String imgType;
+
+	/**
+	 * 跳转链接
+	 */
+	private String actUrl;
+
+	/**
+	 * 点击区域,默认0,任意点击,1区域点击
+	 */
+	private Integer clickType;
+
+	/**
+	 * 持续时间,默认5秒
+	 */
+	private Integer lastTime;
+
+	private String description;
+}

+ 20 - 0
poyi-app/src/main/java/com/tzy/dto/AuctionJPushDTO.java

@@ -0,0 +1,20 @@
+package com.tzy.dto;
+
+import lombok.*;
+
+import java.util.List;
+import java.util.Map;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@ToString
+public class AuctionJPushDTO {
+
+    private List<Long> userIds;
+
+    private List<String> params;
+
+    private String url;
+}

+ 21 - 0
poyi-app/src/main/java/com/tzy/dto/EvaluationDTO.java

@@ -0,0 +1,21 @@
+package com.tzy.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class EvaluationDTO {
+    private Integer id;
+    /**打分*/
+    private Integer value;
+    /**
+     * 图片(以逗号隔开)
+     */
+    private String imgArrAll;
+    /**内容*/
+    private String content;
+    /**是否匿名*/
+    private Boolean anonymous;
+
+}

+ 55 - 0
poyi-app/src/main/java/com/tzy/dto/LivingRoomDTO.java

@@ -0,0 +1,55 @@
+package com.tzy.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import javax.persistence.Table;
+import java.io.Serializable;
+import java.sql.Date;
+
+@Data
+@Table(name = "card_group_lives_config")
+public class LivingRoomDTO implements Serializable {
+    private Integer id;
+    private Integer groupInfoId;
+    private String name;
+    private String code;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date startTime;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date endTime;
+    private Integer totalDuration;
+    private Integer liveViewersNum;
+    private String playbackPath;
+    private Integer playbackWiewersNum;
+    private Integer playbackDuration;
+    private Integer status;
+    private String msg;
+    private String remark;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+    private String createBy;
+    private String anchorName;
+    private String anchorWechat;
+    private String type;
+    private Integer feedsPublic;
+    private Integer closeLike;
+    private Integer closeGoods;
+    private Integer closeComment;
+    private Integer closeReplay;
+    private Integer closeShare;
+    private Integer closeKf;
+    private String subAnchorWechat;
+    private String createrWechat;
+    private String coverImg;
+    private String shareImg;
+    private String feedsImg;
+    private String groupInfoName;
+    private Integer appUserId;
+    private Integer publicStatus;
+    private String category;
+    private Integer merchantId;
+    private String merchantName;
+    private Integer delFlg;
+    private Integer liveLikeNum;
+}

+ 22 - 0
poyi-app/src/main/java/com/tzy/dto/LivingRoomLikeDTO.java

@@ -0,0 +1,22 @@
+package com.tzy.dto;
+
+import lombok.Data;
+
+import javax.persistence.Table;
+import java.io.Serializable;
+
+@Data
+@Table(name = "card_group_lives_like")
+public class LivingRoomLikeDTO implements Serializable {
+    private Integer id;
+    // 直播间code
+    private String code;
+    // 点赞总数
+    private Integer likeNum;
+    // 商家id
+    private Integer merchantId;
+    //用户id
+    private Integer userId;
+    //直播类型: 商城/拼团
+    private String type;
+}

+ 10 - 0
poyi-app/src/main/java/com/tzy/dto/LivingScreenDTO.java

@@ -0,0 +1,10 @@
+package com.tzy.dto;
+
+import lombok.Data;
+
+@Data
+public class LivingScreenDTO {
+    private String code; // 直播code
+    private String captureUrl; // 直播回放url
+    private String captureTime; // 截取画面时间
+}

+ 21 - 0
poyi-app/src/main/java/com/tzy/dto/MineCountDTO.java

@@ -0,0 +1,21 @@
+package com.tzy.dto;
+
+import com.tzy.sportcard.api.domain.MerchantGoods;
+import com.tzy.sportcard.api.domain.MineCount;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class MineCountDTO implements Serializable {
+	/**我的个性化信息,中卡,优惠劵,赠送卡密等*/
+	private MineCount mineCount;
+	/**我的组团订单数量*/
+	private OrderCountDTO groupOrderCount;
+	/**我的商城订单数量*/
+	private OrderCountDTO shopOrderCount;
+	/**商家,我的组队信息*/
+	private MerchantGoods merchantGoods;
+	/**商家,我的商城信息*/
+	private OrderCountDTO merchantShopCount;
+}

+ 42 - 0
poyi-app/src/main/java/com/tzy/dto/OrderCountDTO.java

@@ -0,0 +1,42 @@
+package com.tzy.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @author by po'yi
+ * @Classname OrderDTO
+ * @Description 订单数量
+ * @Date 2022/8/29 15:40
+ */
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+@AllArgsConstructor
+@NoArgsConstructor
+public class OrderCountDTO implements Serializable {
+	/**订单状态-未支付*/
+	private Integer unPay=0;
+	/**待公示*/
+	private Integer waitPublic=0;
+	/**订单状态-待直播*/
+	private Integer waitLiving=0;
+	/**订单状态-待发货*/
+	private Integer waitShipping=0;
+	/**订单状态-待签收*/
+	private Integer waitReceive=0;
+	/**订单状态-退款*/
+	private Integer refund=0;
+	/**订单状态-售后*/
+	private Integer aftSale=0;
+	/**订单状态-取消*/
+	private Integer cancel=0;
+	/**商家上下架商品数量*/
+	private Integer skuCount=0;
+	/**商家旗下申请修改地址数量*/
+	private Integer editAddrCount=0;
+
+}

+ 10 - 0
poyi-app/src/main/java/com/tzy/dto/OrderReq.java

@@ -0,0 +1,10 @@
+package com.tzy.dto;
+
+import com.tzy.common.dto.InDto;
+import com.tzy.pojo.item.dto.OrderParam;
+import lombok.Data;
+
+@Data
+public class OrderReq extends InDto {
+    OrderParam orderParam;
+}

+ 22 - 0
poyi-app/src/main/java/com/tzy/dto/OrderStatusCountDTO.java

@@ -0,0 +1,22 @@
+package com.tzy.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author by po'yi
+ * @Classname OrderStatusCountDTO
+ * @Description TODO
+ * @Date 2022/9/13 14:05
+ */
+@Data
+public class OrderStatusCountDTO implements Serializable {
+	/**订单类型*/
+	private String orderType;
+	/**状态*/
+	private Integer status;
+	/**数量*/
+	private Integer num;
+
+}

+ 21 - 0
poyi-app/src/main/java/com/tzy/dto/SimplePrizeRecord.java

@@ -0,0 +1,21 @@
+package com.tzy.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import org.teasoft.bee.osql.annotation.Entity;
+
+import java.io.Serializable;
+
+/**
+ * @author by po'yi
+ * @Classname SimplePrizeRecord
+ * @Description TODO
+ * @Date 2022/8/19 16:45
+ */
+@Data
+@AllArgsConstructor
+public class SimplePrizeRecord implements Serializable {
+	private String prizeName;
+	private String nickname;
+	private String avatar;
+}

+ 25 - 0
poyi-app/src/main/java/com/tzy/dto/SkuDTO.java

@@ -0,0 +1,25 @@
+package com.tzy.dto;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+public class SkuDTO {
+    private Integer id;
+    private Long soldStock;
+    private String skuName;
+    private BigDecimal retailPrice;
+
+    /**
+     * 活动价
+     */
+    private BigDecimal actPrice;
+    /**
+     * 封面图
+     */
+    private String carouselImgUrl;
+    /**开售时间*/
+    private Date soldTime;
+}

+ 48 - 0
poyi-app/src/main/java/com/tzy/dto/SpuDTO.java

@@ -0,0 +1,48 @@
+package com.tzy.dto;
+
+import com.tzy.pojo.item.Sku;
+import com.tzy.pojo.item.Spu;
+import lombok.Data;
+import org.teasoft.bee.osql.annotation.Entity;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+@Data
+@Entity("spu")
+public class SpuDTO implements Serializable {
+    private Integer id;
+    private Long spuSoldStock;
+    private Long spuTotalStock;
+    private String spuName;
+    private String title;
+    private BigDecimal minSpuPrice;
+    /**
+     * 封面图
+     */
+    private String carouselImgUrl;
+    private String spuDesc;
+    private String secondCatName;
+    private String type;
+    private Integer minPoint;
+    private Long merchantId;
+    private String merchantName;
+    private String merchantAvatar;
+    private String unit;
+    private String actType;
+    /**
+     * 轮播图
+     */
+    private String detailImgUrl;
+    /**活动icon*/
+    private String icon_url;
+    /**开售时间*/
+    private Date soldTime;
+
+    /**明细*/
+    private List<Sku> skuList;
+    /**相关产品*/
+    private List<Spu> linkSpuList;
+}

+ 16 - 0
poyi-app/src/main/java/com/tzy/dto/local/AddressDTO.java

@@ -0,0 +1,16 @@
+package com.tzy.dto.local;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class AddressDTO {
+
+    private Boolean address;
+
+}

+ 16 - 0
poyi-app/src/main/java/com/tzy/dto/local/AllocateResult.java

@@ -0,0 +1,16 @@
+package com.tzy.dto.local;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class AllocateResult implements Serializable {
+    private Long orderId;
+    /**预测玩法猜中卡密数量*/
+    private Integer guessCount=0;
+    /**缺失卡密数量*/
+    private Integer missCardCount=0;
+}

+ 122 - 0
poyi-app/src/main/java/com/tzy/dto/local/CardGroupGoodsDTO.java

@@ -0,0 +1,122 @@
+package com.tzy.dto.local;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+import org.teasoft.bee.osql.annotation.Entity;
+
+import javax.persistence.Column;
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * @Description  卡密-信息表
+ * @Author  poyee
+ * @Date 2022-11-23 
+ */
+
+@Entity("card_group_goods" )
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class CardGroupGoodsDTO implements Serializable {
+
+	private static final long serialVersionUID =  2312379358938882522L;
+
+	@Column(name = "group_info_id" )
+	private Long groupInfoId;
+
+   	@Column(name = "no" )
+	private String no;
+
+   	@Column(name = "set_name" )
+	private String setName;
+
+   	@Column(name = "player_name" )
+	private String playerName;
+
+   	@Column(name = "team" )
+	private String team;
+
+	@Column(name = "zn_team" )
+	private String znTeam;
+
+	@Column(name = "zn_player_name" )
+	private String znPlayerName;
+
+   	@Column(name = "seq" )
+	private String seq;
+
+	@Column(name = "num" )
+	private String num;
+
+	@Column(name = "copies_type" )
+	private Integer copiesType;
+
+	@Column(name = "player_id" )
+	private Long playerId;
+
+	@Column(name = "team_id" )
+	private Long teamId;
+
+	@Column(name = "conference" )
+	private String conference;
+
+	@Column(name = "simple_team_name" )
+	private String simpleTeamName;
+
+   	@Column(name = "logo" )
+	private String logo;
+
+   	@Column(name = "picture" )
+	private String picture;
+	/**
+	 * 卡密动态图片
+	 */
+	@Column(name = "carmichael_img" )
+	private String carmichaelImg;
+
+   	@Column(name = "free_flag" )
+	private Integer freeFlag;
+
+   	@Column(name = "price" )
+	private BigDecimal price;
+
+   	@Column(name = "act_price" )
+	private BigDecimal actPrice;
+
+	/**
+	 * 关联活动id
+	 */
+	@Column(name = "act_id" )
+	private Long actId;
+
+	/**
+	 * 关联活动类型
+	 */
+	@Column(name = "act_type" )
+	private String actType;
+
+	/**
+	 * 活动描述,奖品信息
+	 */
+	@Column(name = "act_desc" )
+	private String actDesc;
+
+   	@Column(name = "parent_id" )
+	private Long parentId;
+
+   	@Column(name = "list_base_id" )
+	private Long listBaseId;
+
+   	@Column(name = "list_base_code" )
+	private String listBaseCode;
+
+   	@Column(name = "list_id" )
+	private Long listId;
+
+   	@Column(name = "category" )
+	private String category;
+
+   	@Column(name = "category_id" )
+	private Long categoryId;
+
+}

+ 110 - 0
poyi-app/src/main/java/com/tzy/dto/local/CardGroupInfoDTO.java

@@ -0,0 +1,110 @@
+package com.tzy.dto.local;
+
+import lombok.Data;
+import org.teasoft.bee.osql.annotation.Entity;
+
+import javax.persistence.Column;
+import java.io.Serializable;
+
+/**
+ * @Description  
+ * @Author  Hunter
+ * @Date 2022-02-16 
+ */
+
+@Entity("card_group_info" )
+@Data
+public class CardGroupInfoDTO  implements Serializable {
+
+	private static final long serialVersionUID =  3012799475873876829L;
+
+	/**
+	 * id
+	 */
+   	@Column(name = "id" )
+	private Long id;
+
+	/**
+	 * 商家id
+	 */
+   	@Column(name = "merchant_id" )
+	private Long merchantId;
+
+	/**
+	 * 名称
+	 */
+   	@Column(name = "name" )
+	private String name;
+
+	/**
+	 * 编码
+	 */
+   	@Column(name = "code" )
+	private String code;
+
+	/**
+	 * 状态
+	 */
+   	@Column(name = "status" )
+	private Long status;
+
+	/**
+	 * 商品规格
+	 */
+   	@Column(name = "specs" )
+	private String specs;
+
+	/**
+	 * 组团方式
+	 */
+   	@Column(name = "type" )
+	private String type;
+
+	/**
+	 * 随机方式
+	 */
+   	@Column(name = "random_type" )
+	private String randomType;
+
+	/**
+	 * 商品份数
+	 */
+   	@Column(name = "copies" )
+	private Long copies;
+
+	/**
+	 * 年份
+	 */
+   	@Column(name = "year" )
+	private String year;
+
+	/**
+	 * 运动
+	 */
+   	@Column(name = "sport" )
+	private String sport;
+
+	/**
+	 * 厂商
+	 */
+   	@Column(name = "manufacturer" )
+	private String manufacturer;
+
+	/**
+	 * 序列
+	 */
+   	@Column(name = "sets" )
+	private String sets;
+
+   	@Column(name = "mer_name" )
+	private String merName;
+
+	private Integer openCard;
+	//买对玩法,改变之后的组队方式
+	private String changeType;
+	//选队随机自分类
+	private String subType;
+	/**组合加倍,暂时仅支持随机分配*/
+	private Integer mixCopies;
+
+}

+ 20 - 0
poyi-app/src/main/java/com/tzy/dto/local/LivingExplainDTO.java

@@ -0,0 +1,20 @@
+package com.tzy.dto.local;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.teasoft.bee.osql.annotation.Entity;
+
+@Entity("card_group_live_explain")
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class LivingExplainDTO {
+
+    private Long id;
+    private Integer status;
+    private Long liveId;
+
+}

+ 46 - 0
poyi-app/src/main/java/com/tzy/dto/local/OrderDTO.java

@@ -0,0 +1,46 @@
+package com.tzy.dto.local;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.tzy.app.dto.mq.GoodsListDTO;
+import lombok.Data;
+import org.teasoft.bee.osql.annotation.Entity;
+import org.teasoft.bee.osql.annotation.Ignore;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author by po'yi
+ * @Classname OrderDTO
+ * @Description TODO
+ * @Date 2022/11/29 15:20
+ */
+@Entity("card_group_order_info")
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class OrderDTO implements Serializable {
+	private Long id;
+	/**卡密是否分配,默认0:未分配,1已分配*/
+	private Integer goodsAllocate;
+	/**
+	 * 组团信息id
+	 */
+	private Long groupInfoId;
+	/**
+	 * 用户id
+	 */
+	private Long userId;
+	private String appUserNickName;
+	private String appUserAvatar;
+	/** 购买数量 */
+	private Long purchaseCount;
+	/** 订单编码 */
+	private String orderNo;
+	//匿名
+	private boolean anonymous;
+	//买队优先订单
+	private String teamFirst;
+	/**卡密明细*/
+	@Ignore
+	private List<GoodsListDTO> goodsListDTOS;
+}

+ 84 - 0
poyi-app/src/main/java/com/tzy/dto/local/ResultDTO.java

@@ -0,0 +1,84 @@
+/**
+ *
+ */
+package com.tzy.dto.local;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 控制层统一返回数据格式
+ *
+ * @author poyee
+ *
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = 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;
+
+	/**
+	 * 构造错误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);
+	}
+
+}

+ 18 - 0
poyi-app/src/main/java/com/tzy/dto/local/UserPointDTO.java

@@ -0,0 +1,18 @@
+package com.tzy.dto.local;
+
+import com.tzy.sportcard.point.domain.AppUserPointRecord;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class UserPointDTO {
+    /*private Long userId;
+    private Integer point;
+    private String refId; // 参与记录id
+    private Long orderId; // 拍品id*/
+
+    private Integer userId;
+
+    private List<AppUserPointRecord> pointRecords;
+}

+ 31 - 0
poyi-app/src/main/java/com/tzy/dto/local/card/CardQuery.java

@@ -0,0 +1,31 @@
+package com.tzy.dto.local.card;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.tzy.common.base.BaseQuery;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+@Accessors(chain = true)
+public class CardQuery extends BaseQuery {
+
+	private Integer actId;
+	/**奖品类型*/
+	private String subType;
+	/**球队*/
+	private String team;
+	/**卡种*/
+	private String cardSet;
+	/**系列*/
+	private String sets;
+	/**星级*/
+	private String starLevel;
+	/**品类*/
+	private String cat;
+	/**是否拥有,1:有 2:未拥有*/
+	private Integer ownedStatus;
+}

+ 66 - 0
poyi-app/src/main/java/com/tzy/listener/mq/AppUserBrowseRecordConsumer.java

@@ -0,0 +1,66 @@
+package com.tzy.listener.mq;
+
+import com.rabbitmq.client.Channel;
+import com.tzy.browse.domain.AppUserBrowseRecord;
+import com.tzy.browse.mapper.AppUserBrowseRecordMapper;
+import com.tzy.common.constant.MqConstans;
+import com.tzy.common.utils.bean.JSONTools;
+import com.tzy.framework.util.RedisUtils;
+import lombok.extern.slf4j.Slf4j;
+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.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Component
+public class AppUserBrowseRecordConsumer {
+    @Resource
+    private AppUserBrowseRecordMapper appUserBrowseRecordMapper;
+    @Resource
+    private RedisUtils redisUtils;
+    @Resource
+    private RedisTemplate<String, String> redisTemplate;
+
+    @RabbitHandler
+    //@RabbitListener(queuesToDeclare = @Queue(MqConstans.QUEUE_USER_BROWSE_RECORD))
+    public void addUserBrowseRecord(String param, Channel channel, Message message) throws IOException {
+        log.debug("入库用户浏览记录:{}", param);
+        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
+        /*try{
+            List<AppUserBrowseRecord> records = JSONTools.parseObjectList(param, AppUserBrowseRecord.class);
+            records.forEach(record ->{
+                String key = "app_user_browse_" + record.getUserId();
+                Double timestamp = redisTemplate.opsForZSet().score(key, param);
+                record.setBrowseTime(new Date(timestamp.longValue()));
+                record.setBrowseDate(new Date(timestamp.longValue()));
+            });
+            appUserBrowseRecordMapper.batchSave(records);
+            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
+            // 处理完要删除这些浏览记录
+            Set<Long> userIds = redisUtils.sGet("app_user_set").stream()
+                    .map(obj -> Long.parseLong(obj.toString()))
+                    .collect(Collectors.toSet());
+            userIds.forEach(userId ->{
+                // 用户浏览记录存储 Key
+                String historyKey = "app_user_browse_history_" + userId;
+                redisUtils.del(historyKey);
+            });
+            redisUtils.del("app_user_set");
+            redisUtils.set("browse_queue_count", 0); // 全局计数器归零
+        }catch (Exception e){
+            log.error("入库用户浏览记录异常:{}", param, e);
+            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
+        }*/
+
+    }
+}

+ 39 - 0
poyi-app/src/main/java/com/tzy/listener/mq/CommunityNotifyConsumer.java

@@ -0,0 +1,39 @@
+package com.tzy.listener.mq;
+
+import com.alibaba.fastjson.JSON;
+import com.rabbitmq.client.Channel;
+import com.tzy.common.constant.MqConstans;
+import com.tzy.system.domain.TzySysNoticeRecord;
+import com.tzy.system.service.ITzySysNoticeRecordService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.core.Message;
+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 CommunityNotifyConsumer {
+
+	@Resource
+	private ITzySysNoticeRecordService noticeRecordService;
+
+	@RabbitHandler
+	@RabbitListener(queues = {MqConstans.QUEUE_COMMUNITY_NOTIFY})
+	public void notifyConsumer(String param, Channel channel, Message message) throws IOException {
+		log.debug("社区通知消息:{}", param);
+		try {
+			List<TzySysNoticeRecord> noticeRecords = JSON.parseArray(param, TzySysNoticeRecord.class);
+			noticeRecords.forEach(noticeRecord -> noticeRecordService.insertTzySysNoticeRecord(noticeRecord));
+		} catch (Exception e) {
+			log.error("社区通知消息异常,参数:{}", param, e);
+		}
+		channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
+	}
+
+}

+ 46 - 0
poyi-app/src/main/java/com/tzy/listener/mq/GiftCardConsumer.java

@@ -0,0 +1,46 @@
+package com.tzy.listener.mq;
+
+import com.alibaba.fastjson2.JSON;
+import com.rabbitmq.client.Channel;
+import com.tzy.common.constant.MqConstans;
+import com.tzy.common.dto.group.GroupActRecord;
+import com.tzy.sportcard.api.service.GroupApiService;
+import com.tzy.sportcard.api.service.MineApiService;
+import com.tzy.sportcard.point.domain.AppUserPointRecord;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.RabbitHandler;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.util.List;
+
+
+@Slf4j
+@Component
+public class GiftCardConsumer {
+
+
+	@Resource
+	private GroupApiService groupApiService;
+	@Autowired
+	private MineApiService mineApiService;
+
+	@RabbitHandler
+	@RabbitListener(queues = {MqConstans.QUEUE_GROUP_GIFT_CARD})
+	public void giftCardConsumer(String param, Channel channel, Message message) throws IOException {
+		log.info("精美卡片新增记录:{}", param);
+		try {
+			GroupActRecord actRecord = JSON.parseObject(param, GroupActRecord.class);
+			List<AppUserPointRecord> records = groupApiService.getUserGroupGiftCard(actRecord.getRefId());
+			records.forEach(r -> mineApiService.addUserPoint(r));
+		} catch (Exception e) {
+			log.error("精美卡片新增异常,参数:{}", param, e);
+		}
+		channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
+	}
+
+}

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor