Ver código fonte

Merge remote-tracking branch 'origin/master' into lih

# Conflicts:
#	yt-common/src/main/java/com/ytpm/agent/model/YtApp.java
#	yt-common/src/main/java/com/ytpm/agent/view/AgentAppView.java
#	yt-common/src/main/java/com/ytpm/app/param/IosLoginParam.java
#	yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/controller/WxController.java
#	yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/dao/AdRecordMapper.java
#	yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/service/AdService.java
#	yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/service/impl/AdServiceImpl.java
#	yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/service/impl/AppUserServiceImpl.java
#	yt-middle/middle-platform/src/main/java/com/ytpm/middle/service/impl/ApkServiceImpl.java
#	yt-question/yt-question-service/src/main/java/com/ytpm/question/config/interceptor/HttpInterceptor.java
hidewnd 8 horas atrás
pai
commit
6ae80341d7
31 arquivos alterados com 1136 adições e 460 exclusões
  1. 131 8
      ReadMe.md
  2. 8 0
      yt-common/src/main/java/com/ytpm/agent/model/YtApp.java
  3. 33 0
      yt-common/src/main/java/com/ytpm/agent/model/YtAppConfigLog.java
  4. 4 0
      yt-common/src/main/java/com/ytpm/agent/view/AgentAppView.java
  5. 35 0
      yt-common/src/main/java/com/ytpm/annotation/BeanChange.java
  6. 5 3
      yt-common/src/main/java/com/ytpm/app/param/IosLoginParam.java
  7. 39 1
      yt-common/src/main/java/com/ytpm/app/view/WxDefaultConfig.java
  8. 85 0
      yt-common/src/main/java/com/ytpm/util/ResourceUtils.java
  9. 19 14
      yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/controller/AdController.java
  10. 3 2
      yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/controller/QuestionController.java
  11. 6 5
      yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/controller/UserController.java
  12. 120 90
      yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/controller/WxController.java
  13. 5 3
      yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/dao/AppUserMapper.java
  14. 1 1
      yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/dao/DitchMapper.java
  15. 76 57
      yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/redis/RedisService.java
  16. 2 1
      yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/service/AppUserService.java
  17. 38 46
      yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/service/impl/AdServiceImpl.java
  18. 188 194
      yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/service/impl/AppUserServiceImpl.java
  19. 1 2
      yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/service/impl/DitchServiceImpl.java
  20. 0 1
      yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/service/impl/QuestionServiceImpl.java
  21. 12 1
      yt-ios-lemon/lemon-ios-service/src/main/resources/mapper/AppUserMapper.xml
  22. 1 1
      yt-ios-lemon/lemon-ios-service/src/main/resources/mapper/DitchMapper.xml
  23. 11 0
      yt-middle/middle-platform/src/main/java/com/ytpm/middle/dao/AppMapper.java
  24. 91 14
      yt-middle/middle-platform/src/main/java/com/ytpm/middle/service/impl/ApkServiceImpl.java
  25. 1 1
      yt-middle/middle-platform/src/main/java/com/ytpm/middle/service/impl/AppServiceImpl.java
  26. 8 6
      yt-middle/middle-platform/src/main/java/com/ytpm/middle/service/impl/CountServiceImpl.java
  27. 103 0
      yt-middle/middle-platform/src/main/java/com/ytpm/middle/util/BeanChangeUtil.java
  28. 7 7
      yt-middle/middle-platform/src/main/resources/mapper/ApkMapper.xml
  29. 32 2
      yt-middle/middle-platform/src/main/resources/mapper/AppMapper.xml
  30. 25 0
      yt-question/yt-question-service/src/main/java/com/ytpm/question/config/interceptor/HttpInterceptor.java
  31. 46 0
      yt-question/yt-question-service/src/main/java/com/ytpm/question/config/redis/RedisCacheInitializer.java

+ 131 - 8
ReadMe.md

@@ -93,6 +93,8 @@ graphic             25833
 adventure           25834
 poetry              25835
 quick               25836
+relogic             25837
+colormatch          25838
 ###### IOS #######
 lemonios            25903
 gollumios           25929
@@ -102,6 +104,13 @@ linefunios          25102
 sortingios          25027
 guardios            25028
 deliveryios         25029
+journeyios          25030
+treeios             25031
+reheartios          25032
+cocoaios            25033
+yieldlogixios       25034
+chocomeltios        25035
+
 ```
 
 #### 核心服务
@@ -815,6 +824,33 @@ question-service.jar > quick.log 2>&1 &
 
 ```
 
+#### Android: 逆向思维王 relogic
+
+```shell
+# 逆向思维王 relogic-service
+# 10.206.16.10
+# 10.206.16.11
+nohup java -jar -Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
+-XX:+UseG1GC -XX:ConcGCThreads=2 -XX:InitiatingHeapOccupancyPercent=35 \
+-XX:G1ReservePercent=10 -XX:MaxGCPauseMillis=300 \
+-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/www/app/ytpm/service-relogic/relogic.hprof \
+question-service.jar > relogic.log 2>&1 &
+
+```
+
+#### Android: 涂色对对碰 colormatch
+
+```shell
+# 涂色对对碰 colormatch-service
+# 10.206.0.11
+nohup java -jar -Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
+-XX:+UseG1GC -XX:ConcGCThreads=2 -XX:InitiatingHeapOccupancyPercent=35 \
+-XX:G1ReservePercent=10 -XX:MaxGCPauseMillis=300 \
+-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/www/app/ytpm/service-colormatch/colormatch.hprof \
+question-service.jar > colormatch.log 2>&1 &
+
+```
+
 
 #### IOS: 青柠檬ios lemonios
 
@@ -822,7 +858,7 @@ question-service.jar > quick.log 2>&1 &
 # 青柠檬ios lemonios
 # 10.206.16.11  
 # 10.206.16.15
-nohup java -jar -Xms3072m -Xmx3072m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
+nohup java -jar -Xms1024m -Xmx3072m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
 -XX:+UseG1GC -XX:ConcGCThreads=2 -XX:InitiatingHeapOccupancyPercent=35 \
 -XX:G1ReservePercent=10 -XX:MaxGCPauseMillis=300 \
 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/www/app/ytpm/service-ios-lemon/lemonios.hprof \
@@ -833,14 +869,14 @@ lemonios-service.jar > lemonios.log 2>&1 &
 #### IOS: 咕噜日记ios gollumios
 
 ```shell
-# 咕噜日记ios gollumios
+# 咕噜日记ios gollumios-service
 # 10.206.16.11  
 # 10.206.16.15
 nohup java -jar -Xms2048m -Xmx2048m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
 -XX:+UseG1GC -XX:ConcGCThreads=2 -XX:InitiatingHeapOccupancyPercent=35 \
 -XX:G1ReservePercent=10 -XX:MaxGCPauseMillis=300 \
 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/www/app/ytpm/service-ios-gollum/gollumios.hprof \
-gollumios-service.jar > gollumios.log 2>&1 &
+lemonios-service.jar > gollumios.log 2>&1 &
 ```
 
 
@@ -848,7 +884,7 @@ gollumios-service.jar > gollumios.log 2>&1 &
 #### IOS: 盒小仓ios warehouseios
 
 ```shell
-# 盒小仓ios warehouseios
+# 盒小仓ios warehouseios-service
 # 10.206.0.3
 # 10.206.16.10
 nohup java -jar -Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
@@ -892,7 +928,7 @@ lemonios-service.jar > linefunios.log 2>&1 &
 #### IOS: IOSCelestial Sorting sortingios
 
 ```shell
-# sortingios sortingios
+# sortingios sortingios-service
 # 10.206.16.10
 # 10.206.16.15
 nohup java -jar -Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
@@ -901,13 +937,14 @@ nohup java -jar -Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=256M -XX:+UseCompressed
 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/www/app/ytpm/service-ios-sorting/sortingios.hprof \
 lemonios-service.jar > sortingios.log 2>&1 &
 
+
 ```
 
 
 #### IOS: IOSExpiryGuard guardios
 
 ```shell
-# guardios guardios
+# guardios guardios-service
 # 10.206.0.3
 # 10.206.16.15
 nohup java -jar -Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
@@ -919,10 +956,10 @@ lemonios-service.jar > guardios.log 2>&1 &
 ```
 
 
-#### IOS: [] deliveryios
+#### IOS: MyQuickDelivery deliveryios
 
 ```shell
-# deliveryios
+# deliveryios-service
 # 10.206.0.3
 # 10.206.16.10
 nohup java -jar -Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
@@ -933,6 +970,92 @@ lemonios-service.jar > deliveryios.log 2>&1 &
 
 ```
 
+#### IOS:Verbal Chain Journey
+
+```shell
+# journeyios-service 
+# 10.206.0.3
+# 10.206.16.15
+nohup java -jar -Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
+-XX:+UseG1GC -XX:ConcGCThreads=2 -XX:InitiatingHeapOccupancyPercent=35 \
+-XX:G1ReservePercent=10 -XX:MaxGCPauseMillis=300 \
+-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/www/app/ytpm/service-ios-journey/journey.hprof \
+lemonios-service.jar > journey.log 2>&1 &
+
+```
+
+#### IOS: 小树问答
+
+```shell
+# 小树问答 treeios-service
+# 10.206.0.3
+# 10.206.16.11
+nohup java -jar -Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
+-XX:+UseG1GC -XX:ConcGCThreads=2 -XX:InitiatingHeapOccupancyPercent=35 \
+-XX:G1ReservePercent=10 -XX:MaxGCPauseMillis=300 \
+-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/www/app/ytpm/service-ios-treeios/treeios.hprof \
+lemonios-service.jar > treeios.log 2>&1 &
+
+```
+
+#### IOS: 归心家校通
+
+```shell
+# reheartios-service
+# 10.206.16.10
+# 10.206.16.15
+nohup java -jar -Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
+-XX:+UseG1GC -XX:ConcGCThreads=2 -XX:InitiatingHeapOccupancyPercent=35 \
+-XX:G1ReservePercent=10 -XX:MaxGCPauseMillis=300 \
+-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/www/app/ytpm/service-ios-reheartios/reheartios.hprof \
+lemonios-service.jar > reheartios.log 2>&1 &
+
+```
+
+#### IOS: CocoaHarvest
+
+```shell
+# cocoaios-service
+# 10.206.16.10
+# 10.206.16.15
+nohup java -jar -Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
+-XX:+UseG1GC -XX:ConcGCThreads=2 -XX:InitiatingHeapOccupancyPercent=35 \
+-XX:G1ReservePercent=10 -XX:MaxGCPauseMillis=300 \
+-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/www/app/ytpm/service-ios-cocoaios/cocoaios.hprof \
+lemonios-service.jar > cocoaios.log 2>&1 &
+
+```
+
+#### IOS: YieldLogix
+
+```shell
+# yieldlogixios-service
+# 10.206.0.3
+# 10.206.16.10
+
+nohup java -jar -Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
+-XX:+UseG1GC -XX:ConcGCThreads=2 -XX:InitiatingHeapOccupancyPercent=35 \
+-XX:G1ReservePercent=10 -XX:MaxGCPauseMillis=300 \
+-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/www/app/ytpm/service-ios-yieldlogix/yieldlogixios.hprof \
+lemonios-service.jar > yieldlogixios.log 2>&1 &
+
+```
+
+#### ChocoMelt
+
+```shell
+# chocomeltios-service
+# 10.206.16.10
+# 10.206.16.15
+
+nohup java -jar -Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
+-XX:+UseG1GC -XX:ConcGCThreads=2 -XX:InitiatingHeapOccupancyPercent=35 \
+-XX:G1ReservePercent=10 -XX:MaxGCPauseMillis=300 \
+-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/www/app/ytpm/service-ios-chocomeltios/chocomeltios.hprof \
+lemonios-service.jar > chocomeltios.log 2>&1 &
+
+
+```
 
 ## 数据处理
 

+ 8 - 0
yt-common/src/main/java/com/ytpm/agent/model/YtApp.java

@@ -1,7 +1,10 @@
 package com.ytpm.agent.model;
 
+import com.ytpm.annotation.BeanChange;
 import lombok.Data;
 
+import java.util.Date;
+
 @Data
 public class YtApp {
     /**
@@ -51,6 +54,7 @@ public class YtApp {
     /**
      * 更新提示
      */
+    @BeanChange(name = "更新提示")
     private String updateTips;
     /**
      * 启用状态
@@ -110,6 +114,10 @@ public class YtApp {
      */
     private String superiorId;
 
+    /**
+     * 创建时间
+     */
+    private Date createTime;
     /**
      * 收益 显示比例
      */

+ 33 - 0
yt-common/src/main/java/com/ytpm/agent/model/YtAppConfigLog.java

@@ -0,0 +1,33 @@
+package com.ytpm.agent.model;
+
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @author lih
+ * @date 2025-11-03 15:43
+ */
+@Data
+@ApiModel("出包配置修改记录日志表")
+public class YtAppConfigLog {
+
+    @ApiModelProperty("记录Id")
+    private String recordId;
+
+    @ApiModelProperty("appId")
+    private String appId;
+
+    @ApiModelProperty("修改内容")
+    private String changeContent;
+
+    @ApiModelProperty("修改人")
+    private String changeBy;
+
+    @ApiModelProperty("修改时间")
+    private Date changeTime;
+
+}

+ 4 - 0
yt-common/src/main/java/com/ytpm/agent/view/AgentAppView.java

@@ -1,5 +1,6 @@
 package com.ytpm.agent.view;
 
+import com.ytpm.agent.model.YtAppConfigLog;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -189,6 +190,9 @@ public class AgentAppView {
     @ApiModelProperty("小说解锁定时(秒)")
     private Integer unlockTimer;
 
+    @ApiModelProperty("最近修改记录")
+    private YtAppConfigLog lastChangeLog;
+
     @ApiModelProperty("是否展示真实小说名称")
     private Integer canShowRealNovelName;
 

+ 35 - 0
yt-common/src/main/java/com/ytpm/annotation/BeanChange.java

@@ -0,0 +1,35 @@
+package com.ytpm.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Bean属性变化比较工具类
+ * 用于比较两个相同类型实体中被@BeanChange注解标记的属性变化
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface BeanChange {
+
+    /**
+     * 属性中文名称
+     */
+    String name();
+
+    /**
+     * 日期格式化格式
+     */
+    String dateFormat() default "yyyy-MM-dd HH:mm:ss";
+
+    /**
+     * 是否忽略
+     */
+    boolean ifIgnored() default false;
+
+    /**
+     * 是否值
+     */
+    boolean ifYesNo() default false;
+}

+ 5 - 3
yt-common/src/main/java/com/ytpm/app/param/IosLoginParam.java

@@ -1,16 +1,18 @@
 package com.ytpm.app.param;
 
-import com.ytpm.app.model.YtDyzAdRecord;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
+import lombok.EqualsAndHashCode;
 
 import java.util.Date;
 import java.util.List;
 
-@ApiModel("IOS登录参数")
+
 @Data
-public class IosLoginParam {
+@ApiModel("IOS登录参数")
+@EqualsAndHashCode(callSuper = true)
+public class IosLoginParam extends LoginParam {
     @ApiModelProperty(value = "IOSId")
     private String iosId;
     @ApiModelProperty(value = "手机号")

+ 39 - 1
yt-common/src/main/java/com/ytpm/app/view/WxDefaultConfig.java

@@ -1,6 +1,7 @@
 package com.ytpm.app.view;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.ytpm.annotation.BeanChange;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
@@ -20,62 +21,99 @@ public class WxDefaultConfig {
     private String platformAppId;
     @JsonIgnore
     private String platformAppSecret;
-    private int appType;
+    private Integer appType;
     private String userPath;
     private String loginPath;
     private String adPath;
     private String answerPath;
     private String powerPath;
+
     @ApiModelProperty("taku应用ID")
+    @BeanChange(name = "taku应用ID")
     private String takuAppId;
+
     @ApiModelProperty("taku应用key")
+    @BeanChange(name = "takuKey")
     private String takuKey;
+
     @ApiModelProperty("taku横幅")
+    @BeanChange(name = "taku横幅ID")
     private String takuBannerPid;
+
     @ApiModelProperty("taku原生")
+    @BeanChange(name = "taku原生ID")
     private String takuNativePid;
+
     @ApiModelProperty("taku激励")
+    @BeanChange(name = "taku激励ID")
     private String takuRewardPid;
+
     @ApiModelProperty("taku插屏")
+    @BeanChange(name = "taku插屏ID")
     private String takuInterstitialPid;
+
     @ApiModelProperty("taku插屏")
+    @BeanChange(name = "taku ScreenID")
     private String takuScreenPid;
+
     @ApiModelProperty("是否允许root")
+    @BeanChange(name = "是否允许root", ifYesNo = true)
     private Integer canUseRoot;
+
     @ApiModelProperty("是否允许adb")
+    @BeanChange(name = "是否允许adb", ifYesNo = true)
     private Integer canUseAdb;
+
     @ApiModelProperty("是否允许浮窗")
+    @BeanChange(name = "是否允许浮窗", ifYesNo = true)
     private Integer canUseFloat;
+
     @ApiModelProperty("是否允许累加体力")
+    @BeanChange(name = "是否允许累加体力", ifYesNo = true)
     private Integer canAccumulation;
+
     @ApiModelProperty("是否允许模拟器")
+    @BeanChange(name = "是否允许模拟器", ifYesNo = true)
     private Integer canSimulator;
+
     @ApiModelProperty("体力等待时间(秒)")
+    @BeanChange(name = "体力等待时间(秒)")
     private Integer powerWaitTime;
+
     @ApiModelProperty("插屏间隔时间(秒)")
+    @BeanChange(name = "插屏间隔时间(秒)")
     private Integer interstitialIntervalTime;
+
     @ApiModelProperty("渠道类型id")
+    @BeanChange(name = "渠道类型id")
     private String ditchId;
 
     @ApiModelProperty("用户低收益提示语")
+    @BeanChange(name = "用户低收益提示语")
     private String lowValueTip;
 
     @ApiModelProperty("刷子提示语")
+    @BeanChange(name = "刷子提示语")
     private String brushTip;
 
     @ApiModelProperty("原生(信息流)间隔时长(秒)")
+    @BeanChange(name = "原生(信息流)间隔时长(秒)")
     private Integer flowIntervalTime;
 
     @ApiModelProperty("体力不足提示语")
+    @BeanChange(name = "体力不足提示语")
     private String taskLimitTip;
 
     @ApiModelProperty("是否缓存激励视频")
+    @BeanChange(name = "是否缓存激励视频", ifYesNo = true)
     private Integer canCacheVideo;
 
     @ApiModelProperty("启动页等待时间(秒)")
+    @BeanChange(name = "启动页等待时间(秒)")
     private Integer startWaitTime;
 
     @ApiModelProperty("是否允许自动刷新")
+    @BeanChange(name = "是否允许自动刷新", ifYesNo = true)
     private Integer canAllowAutoRefresh;
 
     @ApiModelProperty("收益 显示比例")

+ 85 - 0
yt-common/src/main/java/com/ytpm/util/ResourceUtils.java

@@ -0,0 +1,85 @@
+package com.ytpm.util;
+
+
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.springframework.util.FileCopyUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author lih
+ * @date 2025-11-11 13:31
+ */
+public class ResourceUtils {
+
+
+    /**
+     * 优先读取JAR同级目录slogans.txt,不存在则读取resource目录
+     *
+     * @return 每行内容的List<String>(过滤空行)
+     * @throws IOException 外部和内部文件均读取失败时抛出
+     */
+    public static List<String> readFileToList(String fileName) throws IOException {
+        // 1. 构造JAR同级目录的外部文件路径
+        // user.dir = JAR所在的同级目录(执行java -jar命令的目录)
+        String externalFilePath = Paths.get(System.getProperty("user.dir"), fileName).toString();
+        File externalFile = new File(externalFilePath);
+
+        // 2. 优先读取外部文件(存在且可读)
+        if (externalFile.exists() && externalFile.canRead()) {
+            try {
+                return readFileToList(externalFile);
+            } catch (IOException e) {
+                // 外部文件存在但读取失败(如权限不足),降级读取内部文件
+            }
+        }
+
+        // 3. 读取内部resource目录文件(兜底方案)
+        Resource internalResource = new ClassPathResource(fileName);
+        if (!internalResource.exists()) {
+            throw new IOException("外部文件(" + externalFilePath + ")和内部resource文件均不存在");
+        }
+        return readFileToList(internalResource);
+    }
+
+    /**
+     * 读取本地File文件转为List<String>
+     */
+    private static List<String> readFileToList(File file) throws IOException {
+        try (InputStreamReader reader = new InputStreamReader(
+                Files.newInputStream(file.toPath()), StandardCharsets.UTF_8)) {
+            String content = FileCopyUtils.copyToString(reader);
+            return processContent(content);
+        }
+    }
+
+    /**
+     * 读取resource目录文件转为List<String>
+     */
+    private static List<String> readFileToList(Resource resource) throws IOException {
+        try (InputStreamReader reader = new InputStreamReader(
+                resource.getInputStream(), StandardCharsets.UTF_8)) {
+            String content = FileCopyUtils.copyToString(reader);
+            return processContent(content);
+        }
+    }
+
+    /**
+     * 处理文件内容:分割换行符、过滤空行、去除前后空白
+     */
+    private static List<String> processContent(String content) {
+        return Arrays.stream(content.split("\\r?\\n"))  // 兼容Windows/Linux换行符
+                .map(String::trim)                      // 去除每行前后空白(可选)
+                .filter(line -> !line.isEmpty())         // 过滤空行(可选)
+                .collect(Collectors.toList());
+    }
+}

+ 19 - 14
yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/controller/AdController.java

@@ -12,9 +12,14 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
 import io.swagger.annotations.ApiOperation;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.GetMapping;
+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.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 
+import javax.annotation.Resource;
 import java.math.BigDecimal;
 import java.util.List;
 import java.util.Map;
@@ -25,7 +30,7 @@ import java.util.Map;
 @RequestMapping("/ad")
 public class AdController {
 
-    @Autowired
+    @Resource
     private AdService adService;
 
     /**
@@ -33,7 +38,7 @@ public class AdController {
      */
     @ApiOperation("保存")
     @PostMapping("/saveRecord")
-    public Result<?> saveRecord(@RequestBody DyzAdRecordParam param){
+    public Result<?> saveRecord(@RequestBody DyzAdRecordParam param) {
         return adService.saveRecord(param);
     }
 
@@ -42,7 +47,7 @@ public class AdController {
      */
     @ApiOperation("根据应用ID查询广告数")
     @GetMapping("/getAdCount")
-    public Map<String, BigDecimal> getAdCount(@RequestParam(name = "appIds")String appIds){
+    public Map<String, BigDecimal> getAdCount(@RequestParam(name = "appIds") String appIds) {
         return adService.getAdCount(appIds);
     }
 
@@ -50,40 +55,40 @@ public class AdController {
      * 查询应用排行榜信息
      */
     @ApiImplicitParams({
-            @ApiImplicitParam(name = "sortBy", value = "排行榜排序规则",required = true),
-            @ApiImplicitParam(name = "limit", value = "排行榜显示数量",required = true),
+            @ApiImplicitParam(name = "sortBy", value = "排行榜排序规则", required = true),
+            @ApiImplicitParam(name = "limit", value = "排行榜显示数量", required = true),
     })
     @ApiOperation("查询应用排行榜信息")
     @GetMapping("/getAppRankingList")
-    public DashboardRankingListVO queryRankingList(@RequestParam(name = "sortBy")Integer sortBy,@RequestParam(name = "limit")Integer limit){
-        return adService.queryRankingList(sortBy,limit);
+    public DashboardRankingListVO queryRankingList(@RequestParam(name = "sortBy") Integer sortBy, @RequestParam(name = "limit") Integer limit) {
+        return adService.queryRankingList(sortBy, limit);
     }
 
     /**
      * 查询各渠道应用收益分时统计
      */
-    @ApiImplicitParam(name = "apkIds", value = "渠道应用ID(,拼接)",required = true)
+    @ApiImplicitParam(name = "apkIds", value = "渠道应用ID(,拼接)", required = true)
     @ApiOperation("查询各渠道应用收益分时统计")
     @GetMapping("/revenueStatics")
-    public DashboardRevenueVO revenueStatics(@RequestParam(name = "apkIds")String apkIds){
+    public DashboardRevenueVO revenueStatics(@RequestParam(name = "apkIds") String apkIds) {
         return adService.revenueStatics(apkIds);
     }
 
     @ApiOperation("查询渠道商顶部数据")
     @GetMapping("/getAppTopCount")
-    public AgentTopCountView getAppTopCount(@RequestParam(name = "appIds")String appIds){
+    public AgentTopCountView getAppTopCount(@RequestParam(name = "appIds") String appIds) {
         return adService.getAppTopCount(appIds);
     }
 
     @ApiOperation("查询用户风控分时数据统计")
     @GetMapping("/userStatics")
-    public DashboardRiskVO userStatics(@RequestParam(name = "appId")String appId){
+    public DashboardRiskVO userStatics(@RequestParam(name = "appId") String appId) {
         return adService.userStatics(appId);
     }
 
     @ApiOperation("查询代理商首页统计广告数据")
     @GetMapping("/getAgentProfit")
-    public List<AgentAdGroupStaticsVO> getAgentProfit(@RequestParam(name = "appIds")String appIds){
+    public List<AgentAdGroupStaticsVO> getAgentProfit(@RequestParam(name = "appIds") String appIds) {
         return adService.getAgentProfit(appIds);
     }
 }

+ 3 - 2
yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/controller/QuestionController.java

@@ -8,16 +8,17 @@ import com.ytpm.general.ResultTable;
 import com.ytpm.lemonios.service.QuestionService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
+import javax.annotation.Resource;
+
 
 @Api(tags = "题目管理模块")
 @RestController
 @RequestMapping("/question")
 public class QuestionController {
 
-    @Autowired
+    @Resource
     private QuestionService questionService;
 
     /**

+ 6 - 5
yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/controller/UserController.java

@@ -32,7 +32,6 @@ import com.ytpm.risk.view.RiskTemplateView;
 import com.ytpm.util.DateUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.validation.Errors;
 import org.springframework.web.bind.annotation.*;
 
 import java.math.BigDecimal;
@@ -201,7 +200,8 @@ public class UserController {
      * 查询用户的广告记录
      */
     @GetMapping("/adRecords")
-    public ResultTable<YtDyzAdRecord> adRecords(@RequestParam(name = "userId",required = true) String userId,@RequestParam(name = "adsourceType",required = false)Integer adsourceType) {
+    public ResultTable<YtDyzAdRecord> adRecords(@RequestParam(name = "userId",required = true) String userId,
+                                                @RequestParam(name = "adsourceType",required = false)Integer adsourceType) {
         List<YtDyzAdRecord> result = new ArrayList<>();
         List<YtDyzAdRecord> adrecords = adRecordMapper.getByUserId(userId, adsourceType);
         if(CollUtil.isNotEmpty(adrecords)){
@@ -256,7 +256,8 @@ public class UserController {
 
     @PostMapping("/queryUserByTime")
     public List<YtDyzUser> queryUserByTime(@RequestBody AppUserQueryParam appUserQueryParam) {
-        List<YtDyzUser> ytDyzUsers = appUserMapper.queryAllByTime(appUserQueryParam.getStartTime(), appUserQueryParam.getEndTime(),appUserQueryParam.getAppIdList());
+        List<YtDyzUser> ytDyzUsers = appUserMapper.queryAllByTime(appUserQueryParam.getStartTime(),
+                appUserQueryParam.getEndTime(),appUserQueryParam.getAppIdList());
         return ytDyzUsers;
     }
 
@@ -298,14 +299,14 @@ public class UserController {
     }
     @PostMapping("/queryTodayBanned")
     public List<YtDyzUser> queryTodayBanned(@RequestBody AppUserTodayBannedParam appUserTodayBannedParam){
-        return appUserMapper.queryTodayBanned(appUserTodayBannedParam.getStartTime(), appUserTodayBannedParam.getEndTime(), appUserTodayBannedParam.getUserIdList());
+        return appUserMapper.queryTodayBanned(appUserTodayBannedParam.getStartTime(),
+                appUserTodayBannedParam.getEndTime(), appUserTodayBannedParam.getUserIdList());
     }
     @PostMapping("/unLockUser")
     public void unLockUser(@RequestParam("userIds")String userIds){
         List<YtDyzUser> dyzUsers = appUserMapper.queryByUserIds(userIds);
         if(CollUtil.isNotEmpty(dyzUsers)){
             appUserMapper.unlockUser(userIds);
-            return;
         }
     }
     @GetMapping("/lockUser")

+ 120 - 90
yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/controller/WxController.java

@@ -65,7 +65,7 @@ import java.util.concurrent.TimeUnit;
 @RefreshScope
 @RequestMapping("/wx")
 public class WxController {
-    private final static String GRANT_TYPE = "authorization_code";
+
     @Resource
     private AppUserMapper appUserMapper;
     @Resource
@@ -80,8 +80,11 @@ public class WxController {
     private DitchMapper ditchMapper;
     @Resource
     private RedisService redisService;
+
     @Value("${yt.ios.appid:}")
     private String appId;
+    private final static String GRANT_TYPE = "authorization_code";
+
 
     @Deprecated
     @PostMapping("/login")
@@ -94,9 +97,10 @@ public class WxController {
             return new Result<>(StatusCode.ACCESS_ERR,"微信登录失败,未找到相应配置!");
         }
         param.setAppId(defaultConfig.getPlatformAppId());
-        WxLoginResult loginResult = getWechatLoginInfo(param.getWxCode(),param.getAppType(),defaultConfig.getAppId(),defaultConfig.getSecret());
-        if(Objects.isNull(loginResult)|| StrUtil.isBlank(loginResult.getOpenid())){
-            return new Result<>(StatusCode.ACCESS_ERR,"微信登录失败,请刷新授权码!");
+        WxLoginResult loginResult = getWechatLoginInfo(param.getWxCode(), param.getAppType(),
+                defaultConfig.getAppId(), defaultConfig.getSecret());
+        if (Objects.isNull(loginResult) || StrUtil.isBlank(loginResult.getOpenid())) {
+            return new Result<>(StatusCode.ACCESS_ERR, "微信登录失败,请刷新授权码!");
         }
         WxUserInfo wxUserInfo = getWechatUserInfo(loginResult.getAccess_token(),loginResult.getOpenid());
         if(Objects.isNull(wxUserInfo)) {
@@ -113,6 +117,34 @@ public class WxController {
         return Result.resultOk(RepMessage.LOGIN_SUCCESS, old);
     }
 
+    /**
+     * 获取微信用户信息
+     */
+    private WxUserInfo getWechatUserInfo(String accessToken, String openid) {
+        // 根据token和openid 获取用户信息
+        String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token={}&openid={}&lang=zh_CN";
+        userInfoUrl = StrUtil.format(userInfoUrl, accessToken, openid);
+        String curUser = HttpUtil.get(userInfoUrl);
+        WxUserInfo wxUserInfo = JSON.parseObject(curUser, WxUserInfo.class);
+        log.error("获取的用户信息:{}",wxUserInfo);
+        return wxUserInfo;
+    }
+
+
+    /**
+     * 微信登录
+     */
+    private WxLoginResult getWechatLoginInfo(String wxCode, int appType, String appId, String secret) {
+        String wxLoginUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={}&secret={}&code={}&grant_type={}";
+        wxLoginUrl = StrUtil.format(wxLoginUrl, appId, secret, wxCode, GRANT_TYPE);
+        //拿到授权码 请求微信登录返回access_token
+        String result = HttpUtil.get(wxLoginUrl);
+        WxLoginResult loginResult = JSON.parseObject(result, WxLoginResult.class);
+        log.error("授权码获取的登录结果:{}", loginResult);
+        return loginResult;
+    }
+
+
     @ApiOperation("获取IOS登陆幂等Token")
     @GetMapping("/get/requestId")
     public Result<String> getRequestId(@RequestParam("ditchId") String ditchId, @RequestParam("iosId") String iosId){
@@ -137,9 +169,64 @@ public class WxController {
         return Result.resultObjOk(requestId);
     }
 
-    @PostMapping("/iosLogin")
-    @ApiOperation("IOS登录")
+    @Deprecated
     @Transactional
+    @ApiOperation("IOS登录校验")
+    @PostMapping("/iosLoginCheck")
+    public Result<?> iosLoginCheck(@RequestBody IosLoginParam param) {
+        YtDyzUser user = appUserMapper.selectByIosId(param.getIosId());
+        if (user == null) {
+            IosUserInfo userInfo = setIosUserInfo(param);
+            user = appUserService.crudForNewTransIos(param, userInfo, LoginType.VISITOR);
+        }
+        //2.拿3条记录 设置到user
+        // TODO 当前仅截取最新三条记录,可能遗漏本次登陆前的风控记录(停落时间过长记录超过三条)
+        List<YtDyzAdRecord> adRecordList = recordMapper.getByIosIdBeforeLogin(param.getIosId());
+        user.setPreAdRecordList(adRecordList);
+        user.setLoginType(LoginType.VISITOR);
+        user.setAppId(appId);
+        Result<?> result = riskFeign.checkLoginRisk(user);
+        if (result.getCode() != 200) {
+            String errorMessage = result.getMessage();
+            if (user.getLoginType() == LoginType.VISITOR && RepMessage.RISK_VISITOR_LOWER_VALUE.equals(errorMessage)) {
+                WxDefaultConfig defaultConfig = appUserMapper.getLastDefaultConfig();
+                return Result.resultErr(StrUtil.emptyToDefault(defaultConfig.getLowValueTip(), errorMessage));
+            }
+            return Result.resultErr(errorMessage);
+        }
+        YtDyzUser newUser = new YtDyzUser();
+        newUser.setUserId(user.getUserId());
+        newUser.setUserStatus(UserStatusEnum.NORMAL.getCode());
+        appUserMapper.updateUser(newUser);
+        return Result.resultOk();
+    }
+
+    private IosUserInfo setIosUserInfo(IosLoginParam param){
+        IosUserInfo userInfo = new IosUserInfo();
+        userInfo.setOpenid(param.getIosId() ==  null ? "" : param.getIosId());
+        userInfo.setHeadimgurl(param.getIconUrl()  ==  null ? "" : param.getIconUrl());
+        if (StrUtil.isEmpty(param.getAlias())){
+            YtDyzUser user;
+            if (param.getDitchId() == null){
+                user = appUserMapper.selectByIosId(param.getIosId());
+            } else {
+                user = appUserMapper.getYtAppUserForIos(param.getIosId(), param.getDitchId());
+            }
+            if (user == null  || StrUtil.isEmpty(user.getNickName())) {
+                userInfo.setNickname("Tourists" + IdUtil.fastSimpleUUID().substring(0, 8));
+            } else {
+                userInfo.setNickname(user.getNickName());
+            }
+        } else {
+            userInfo.setNickname(param.getAlias());
+        }
+        return userInfo;
+    }
+
+
+    @ApiOperation("IOS登录")
+    @PostMapping("/iosLogin")
+    @Transactional(rollbackFor = Exception.class)
     public Result<YtDyzUser> iosLogin(@RequestBody IosLoginParam param, HttpServletRequest request) {
         //根据应用ID获取配置调用接口登录
         WxDefaultConfig defaultConfig = appUserMapper.getDefaultConfigByDitchId(param.getDitchId());
@@ -169,6 +256,29 @@ public class WxController {
         }
         IosUserInfo userInfo = setIosUserInfo(param);
         param.setLoginIp(HttpClientUtil.getClientIp(request));
+        // 获取或注册用户
+        YtDyzUser dyzUser = appUserService.crudForNewTransIos(param, userInfo, LoginType.IOS);
+        // 如果传入游客广告记录,执行游客登陆校验
+        if (CollUtil.isNotEmpty(param.getPreAdList())) {
+            dyzUser.setLoginType(LoginType.VISITOR);
+            List<YtDyzAdRecord> preAdRecordList = saveVisitorAdRecord(dyzUser, param);
+            dyzUser.setPreAdRecordList(preAdRecordList);
+            Result<?> result = riskFeign.checkLoginRisk(dyzUser);
+            if (result.getCode() != 200) {
+                String errorMessage = result.getMessage();
+                if (RepMessage.RISK_VISITOR_LOWER_VALUE.equals(errorMessage)) {
+                    errorMessage = StrUtil.emptyToDefault(defaultConfig.getLowValueTip(), errorMessage);
+                }
+                return new Result<>(StatusCode.ACCESS_ERR, errorMessage);
+            }
+        }
+        // 状态更新 游客登陆前风控 -> 正常
+        YtDyzUser newUser = new YtDyzUser();
+        newUser.setUserId(dyzUser.getUserId());
+        dyzUser.setUserStatus(UserStatusEnum.NORMAL.getCode());
+        newUser.setUserStatus(UserStatusEnum.NORMAL.getCode());
+        appUserMapper.updateUser(newUser);
+        param.setLoginIp(HttpClientUtil.getClientIp(request));
         YtDyzUser dyzUser = appUserService.crudForNewTransIos(param, userInfo, LoginType.IOS.getTypeName());
         // 游客登陆校验
         if (CollUtil.isNotEmpty(param.getPreAdList())) {
@@ -204,7 +314,7 @@ public class WxController {
         return Result.resultOk(RepMessage.LOGIN_SUCCESS, dyzUser);
     }
 
-    private void saveVisitorAdRecord(YtDyzUser ytDyzUser,IosLoginParam visitorLoginParam, WxDefaultConfig defaultConfig) {
+    private List<YtDyzAdRecord> saveVisitorAdRecord(YtDyzUser ytDyzUser, IosLoginParam visitorLoginParam) {
         List<DyzAdRecordParam> preAdList = visitorLoginParam.getPreAdList();
         // 保存登陆前传递的广告记录
         List<String> adRecordIds = new ArrayList<>();
@@ -225,41 +335,8 @@ public class WxController {
             log.info(StrUtil.format("[visitor adRecords]userId:{} recordCount:{} revenue:{}",
                     ytDyzUser.getUserId(), adRecordIds.size(), totalRevenue.toPlainString()));
         }
-        ytDyzUser.setPreAdRecordList(recordMapper.selectRecordByIds(AdRecordEnum.LOGIN_BEFORE.getCode(), adRecordIds));
-    }
-
-
-    @Deprecated
-    @PostMapping("/iosLoginCheck")
-    @ApiOperation("IOS登录校验")
-    @Transactional
-    public Result<?> iosLoginCheck(@RequestBody IosLoginParam param) {
-        YtDyzUser user = appUserMapper.selectByIosId(param.getIosId());
-        if (user == null) {
-            IosUserInfo userInfo = setIosUserInfo(param);
-            user = appUserService.crudForNewTransIos(param, userInfo, LoginType.VISITOR.getTypeName());
-        }
-        //2.拿3条记录 设置到user
-        // TODO 当前仅截取最新三条记录,可能遗漏本次登陆前的风控记录(停落时间过长记录超过三条)
-        List<YtDyzAdRecord> adRecordList = recordMapper.getByIosIdBeforeLogin(param.getIosId());
-
-        user.setPreAdRecordList(adRecordList);
-        user.setLoginType(LoginType.VISITOR);
-        user.setAppId(appId);
-        Result<?> result = riskFeign.checkLoginRisk(user);
-        if (result.getCode() != 200) {
-            String errorMessage = result.getMessage();
-            if (user.getLoginType() == LoginType.VISITOR && RepMessage.RISK_VISITOR_LOWER_VALUE.equals(errorMessage)) {
-                WxDefaultConfig defaultConfig = appUserMapper.getLastDefaultConfig();
-                return Result.resultErr(StrUtil.emptyToDefault(defaultConfig.getLowValueTip(), errorMessage));
-            }
-            return Result.resultErr(errorMessage);
-        }
-        YtDyzUser newUser = new YtDyzUser();
-        newUser.setUserId(user.getUserId());
-        newUser.setUserStatus(UserStatusEnum.NORMAL.getCode());
-        appUserMapper.updateUser(newUser);
-        return Result.resultObjOk(user);
+        return CollUtil.isEmpty(adRecordIds) ? new ArrayList<>()
+                : recordMapper.selectRecordByIds(AdRecordEnum.LOGIN_BEFORE.getCode(), adRecordIds);
     }
 
     @PostMapping("/getByDitchId")
@@ -278,53 +355,6 @@ public class WxController {
     }
 
 
-    /**
-     * 获取微信用户信息
-     */
-    private WxUserInfo getWechatUserInfo(String accessToken, String openid) {
-        // 根据token和openid 获取用户信息
-        String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token={}&openid={}&lang=zh_CN";
-        userInfoUrl = StrUtil.format(userInfoUrl, accessToken, openid);
-        String curUser = HttpUtil.get(userInfoUrl);
-        WxUserInfo wxUserInfo = JSON.parseObject(curUser, WxUserInfo.class);
-        log.error("获取的用户信息:{}",wxUserInfo);
-        return wxUserInfo;
-    }
-
-    private IosUserInfo setIosUserInfo(IosLoginParam param){
-        IosUserInfo userInfo = new IosUserInfo();
-        userInfo.setOpenid(param.getIosId() ==  null ? "" : param.getIosId());
-        userInfo.setHeadimgurl(param.getIconUrl()  ==  null ? "" : param.getIconUrl());
-        if (StrUtil.isEmpty(param.getAlias())){
-            YtDyzUser user;
-            if (param.getDitchId() == null){
-                user = appUserMapper.selectByIosId(param.getIosId());
-            } else {
-                user = appUserMapper.getYtAppUserForIos(param.getIosId(), param.getDitchId());
-            }
-            if (user == null  || StrUtil.isEmpty(user.getNickName())) {
-                userInfo.setNickname("Tourists" + IdUtil.fastSimpleUUID().substring(0, 8));
-            } else {
-                userInfo.setNickname(user.getNickName());
-            }
-        } else {
-            userInfo.setNickname(param.getAlias());
-        }
-        return userInfo;
-    }
-
-    /**
-     * 微信登录
-     */
-    private WxLoginResult getWechatLoginInfo(String wxCode, int appType, String appId, String secret) {
-        String wxLoginUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={}&secret={}&code={}&grant_type={}";
-        wxLoginUrl = StrUtil.format(wxLoginUrl, appId, secret, wxCode, GRANT_TYPE);
-        //拿到授权码 请求微信登录返回access_token
-        String result = HttpUtil.get(wxLoginUrl);
-        WxLoginResult loginResult = JSON.parseObject(result, WxLoginResult.class);
-        log.error("授权码获取的登录结果:{}", loginResult);
-        return loginResult;
-    }
 
     @Deprecated
     @ApiOperation("获取微信默认配置项")
@@ -334,7 +364,7 @@ public class WxController {
         if(Objects.isNull(config)){
             return Result.resultErr("应用类型有误!");
         }
-       return Result.resultObjOk(config);
+        return Result.resultObjOk(config);
     }
 
     @ApiOperation("体力增加")

+ 5 - 3
yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/dao/AppUserMapper.java

@@ -36,12 +36,12 @@ public interface AppUserMapper {
     /**
      * openid查询用户信息
      */
-    YtDyzUser getYtAppUser(@Param("openid")String openid,@Param("ditchId")long ditchId);
+    YtDyzUser getYtAppUser(@Param("openid")String openid,@Param("ditchId")Long ditchId);
 
     /**
      * openid查询用户信息
      */
-    YtDyzUser getYtAppUserForIos(@Param("iosId")String iosId,@Param("ditchId")long ditchId);
+    YtDyzUser getYtAppUserForIos(@Param("iosId")String iosId,@Param("ditchId")Long ditchId);
 
     /**
      * 主键查询
@@ -103,7 +103,7 @@ public interface AppUserMapper {
     /**
      * 根据应用类型查询应用默认配置
      */
-    WxDefaultConfig getDefaultConfig(@Param("appType") int appType);
+    WxDefaultConfig getDefaultConfig(@Param("appType") Integer appType);
 
     /**
      * 根据应用ID查询应用默认配置
@@ -231,4 +231,6 @@ public interface AppUserMapper {
     List<YtDyzUser> getMonthRegistryUser(@Param("appIds") String appIds, @Param("type") Integer type);
 
     void updateTotal(@Param("userId") String userId, @Param("videoCount") int videoCount, @Param("revenue") BigDecimal revenue);
+
+    YtDyzUser getYtAppUserAndDitchNull(@Param("iosId") String iosId);
 }

+ 1 - 1
yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/dao/DitchMapper.java

@@ -10,7 +10,7 @@ import java.util.List;
 public interface DitchMapper {
     List<AgentDitchView> ditchList(DitchListParam param);
 
-    List<AgentDitchView> ditchListForIos(@Param("appId") String appId);
+    List<AgentDitchView> ditchListByAppId(@Param("appId") String appId);
 
     Integer insertOne(YtDitch ytDitch);
 

+ 76 - 57
yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/redis/RedisService.java

@@ -15,22 +15,20 @@ import java.util.Calendar;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
+
 @Service
 public class RedisService {
+
     @Autowired
     StringRedisTemplate stringRedisTemplate;
 
-
-    @Resource(name = "stringRedisTemplate")
-    ValueOperations<String, String> valOpsStr;
-
     @Autowired
     RedisTemplate<Object, Object> redisTemplate;
 
     @Autowired(required = false)
-    public void setRedisTemplate(RedisTemplate redisTemplate) {
+    public void setRedisTemplate(RedisTemplate<Object, Object> redisTemplate) {
         //序列化key值,防止key值前面乱码
-        RedisSerializer stringSerializer = new StringRedisSerializer();
+        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
         redisTemplate.setKeySerializer(stringSerializer);
         redisTemplate.setHashKeySerializer(stringSerializer);
         this.redisTemplate = redisTemplate;
@@ -41,11 +39,12 @@ public class RedisService {
 
     /**
      * 根据指定key获取String
+     *
      * @param key
      * @return
      */
-    public String getStr(String key){
-        return valOpsStr.get(key);
+    public String getStr(String key) {
+        return stringRedisTemplate.opsForValue().get(key);
     }
 
 
@@ -58,24 +57,27 @@ public class RedisService {
 
     /**
      * 设置Str缓存
+     *
      * @param key
      * @param val
      */
-    public void setStr(String key, String val){
-        valOpsStr.set(key,val);
+    public void setStr(String key, String val) {
+        stringRedisTemplate.opsForValue().set(key, val);
     }
 
     /**
      * 设置Str缓存 timeOut单位  毫秒
+     *
      * @param key
      * @param val
      */
-    public void setTimeOutStr(String key, String val ,long timeOut){
-        valOpsStr.set(key,val,timeOut, TimeUnit.MILLISECONDS);
+    public void setTimeOutStr(String key, String val, long timeOut) {
+        stringRedisTemplate.opsForValue().set(key, val, timeOut, TimeUnit.MILLISECONDS);
     }
 
     /**
      * 判断是否存在key
+     *
      * @param key
      * @return
      */
@@ -85,38 +87,42 @@ public class RedisService {
 
     /**
      * 设置Str缓存 timeOut单位  小时
+     *
      * @param key
      * @param val
      * @param timeOut
      */
-    public void setTimeOutHoursStr(String key, String val ,long timeOut){
-        valOpsStr.set(key,val,timeOut, TimeUnit.HOURS);
+    public void setTimeOutHoursStr(String key, String val, long timeOut) {
+        stringRedisTemplate.opsForValue().set(key, val, timeOut, TimeUnit.HOURS);
     }
 
     /**
      * 设置Str缓存 timeOut单位  分钟
+     *
      * @param key
      * @param val
      * @param timeOut
      */
-    public void setTimeOutMinutesStr(String key, String val ,long timeOut){
-        valOpsStr.set(key,val,timeOut, TimeUnit.MINUTES);
+    public void setTimeOutMinutesStr(String key, String val, long timeOut) {
+        stringRedisTemplate.opsForValue().set(key, val, timeOut, TimeUnit.MINUTES);
     }
 
     public boolean setIfAbsent(String key, String val ,long timeOut, TimeUnit timeUnit){
-        return Boolean.TRUE.equals(valOpsStr.setIfAbsent(key, val, timeOut, timeUnit));
+        return Boolean.TRUE.equals(valOpsObj.setIfAbsent(key, val, timeOut, timeUnit));
     }
 
     /**
      * 删除指定key
+     *
      * @param key
      */
-    public void del(String key){
+    public void del(String key) {
         stringRedisTemplate.delete(key);
     }
 
     /**
      * 设置指定key值的超时时间
+     *
      * @param key
      */
     public void expire(String key, long timeOut) {
@@ -130,91 +136,103 @@ public class RedisService {
 
     /**
      * 根据前缀批量删除
+     *
      * @param keysPrefix
      */
-    public void delKeys(String keysPrefix){
+    public void delKeys(String keysPrefix) {
         Set<String> set = stringRedisTemplate.keys(keysPrefix);
         stringRedisTemplate.delete(set);
     }
 
 
-
     /**
      * 根据指定o获取Object
+     *
      * @param o
      * @return
      */
-    public Object getObj(Object o){
+    public Object getObj(Object o) {
         return valOpsObj.get(o);
     }
 
     /**
      * 设置obj缓存
+     *
      * @param o1
      * @param o2
      */
-    public void setObj(Object o1, Object o2){
+    public void setObj(Object o1, Object o2) {
         valOpsObj.set(o1, o2);
     }
+
     /**
      * 设置obj缓存
+     *
      * @param o1
      * @param o2
      */
-    public void setObj(Object o1, Object o2,long timeout){
-        valOpsObj.set(o1, o2,timeout);
+    public void setObj(Object o1, Object o2, long timeout) {
+        valOpsObj.set(o1, o2, timeout);
     }
 
 
     /**
      * 删除Obj缓存
+     *
      * @param o
      */
-    public void delObj(Object o){
+    public void delObj(Object o) {
         redisTemplate.delete(o);
     }
 
 
     /**
      * 自增1
+     *
      * @param key
      * @return
      */
-    public long incr(String key){
-        long num = valOpsStr.increment(key,1);
+    public long incr(String key) {
+        long num = stringRedisTemplate.opsForValue().increment(key, 1);
         return num;
     }
+
     /**
      * 自增1
+     *
      * @param key
      * @return
      */
-    public long incrByExp(String key,long timeout){
-        long num = valOpsStr.increment(key,1);
-        TimeUnit timeUnit=TimeUnit.MILLISECONDS;
-        stringRedisTemplate.expire(key,timeout, timeUnit);
+    public long incrByExp(String key, long timeout) {
+        long num = stringRedisTemplate.opsForValue().increment(key, 1);
+        TimeUnit timeUnit = TimeUnit.MILLISECONDS;
+        stringRedisTemplate.expire(key, timeout, timeUnit);
         return num;
     }
+
     /**
      * 自增
+     *
      * @param key
-     * @param delta  自增值
+     * @param delta 自增值
      * @return
      */
-    public long incrByExp(String key,int delta,long timeout){
-        long num = valOpsStr.increment(key,delta);
-        TimeUnit timeUnit=TimeUnit.MILLISECONDS;
-        stringRedisTemplate.expire(key,timeout, timeUnit);
+    public long incrByExp(String key, int delta, long timeout) {
+        long num = stringRedisTemplate.opsForValue().increment(key, delta);
+        TimeUnit timeUnit = TimeUnit.MILLISECONDS;
+        stringRedisTemplate.expire(key, timeout, timeUnit);
         return num;
     }
+
     /**
      * 自增
+     *
      * @param key
-     * @param delta  自增值
+     * @param delta 自增值
      * @return
      */
-    public long incr(String key,long delta){
-        return valOpsStr.increment(key,delta);
+    public long incr(String key, long delta) {
+        return stringRedisTemplate.opsForValue().increment(key, delta);
     }
 
     /**
@@ -226,58 +244,59 @@ public class RedisService {
         LocalDate yesterday = currentDate.minusDays(1);
         String todayKey = currentDate.format(formatter);
         String yesterdayKey = yesterday.format(formatter);
-        if(this.hasKey(todayKey)){
+        if (this.hasKey(todayKey)) {
             this.incr(todayKey);
             return this.getStr(todayKey);
         }
         this.del(yesterdayKey);
-        this.setStr(todayKey, todayKey+"00001");
+        this.setStr(todayKey, todayKey + "00001");
         return this.getStr(todayKey);
     }
 
-    public Long getDitchId(){
+    public Long getDitchId() {
         DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
         LocalDate currentDate = LocalDate.now();
         LocalDate yesterday = currentDate.minusDays(1);
         String todayKey = currentDate.format(formatter);
         String yesterdayKey = yesterday.format(formatter);
         String prefix = "Ditch_";
-        if(this.hasKey(prefix+todayKey)){
-            this.incr(prefix+todayKey);
-            return Long.parseLong(this.getStr(prefix+todayKey));
+        if (this.hasKey(prefix + todayKey)) {
+            this.incr(prefix + todayKey);
+            return Long.parseLong(this.getStr(prefix + todayKey));
         }
         this.del(yesterdayKey);
-        this.setStr(prefix+todayKey, todayKey+"01");
-        return Long.parseLong(this.getStr(prefix+todayKey));
+        this.setStr(prefix + todayKey, todayKey + "01");
+        return Long.parseLong(this.getStr(prefix + todayKey));
     }
 
     /**
      *
      * 生成业务单编号
+     *
      * @return
      */
-    public String generateOrderNo(String key){
+    public String generateOrderNo(String key) {
         Calendar cl = Calendar.getInstance();
         int year = cl.get(Calendar.YEAR);
         int month = cl.get(Calendar.MONTH) + 1;
         int day = cl.get(Calendar.DATE);
-        String orderNoPrefix = getTimeStr(year)+getTimeStr(month)+getTimeStr(day);
-        if(this.hasKey(key)){
+        String orderNoPrefix = getTimeStr(year) + getTimeStr(month) + getTimeStr(day);
+        if (this.hasKey(key)) {
             String old = this.getStr(key);
-            String sub = old.substring(0,8);
-            if(sub.equals(orderNoPrefix)){
+            String sub = old.substring(0, 8);
+            if (sub.equals(orderNoPrefix)) {
                 long incr = this.incr(key);
                 return String.valueOf(incr);
             }
         }
-        this.setStr(key,orderNoPrefix+"001");
-        return orderNoPrefix+"001";
+        this.setStr(key, orderNoPrefix + "001");
+        return orderNoPrefix + "001";
     }
 
-    private String getTimeStr(int num){
-        if(num>9) {
+    private String getTimeStr(int num) {
+        if (num > 9) {
             return String.valueOf(num);
         }
-        return "0"+num;
+        return "0" + num;
     }
 }

+ 2 - 1
yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/service/AppUserService.java

@@ -1,6 +1,7 @@
 package com.ytpm.lemonios.service;
 
 import com.ytpm.agent.model.YtDitch;
+import com.ytpm.app.enums.LoginType;
 import com.ytpm.app.model.YtDyzUser;
 import com.ytpm.app.param.IosLoginParam;
 import com.ytpm.app.param.WxLoginParam;
@@ -23,7 +24,7 @@ public interface AppUserService {
     /**
      * 子事务处理用户crud
      */
-    YtDyzUser crudForNewTransIos(IosLoginParam param, IosUserInfo userInfo, String loginType);
+    YtDyzUser crudForNewTransIos(IosLoginParam param, IosUserInfo userInfo, LoginType loginType);
 
     Result<?> addDefaultConfig(YtDitch param);
 

+ 38 - 46
yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/service/impl/AdServiceImpl.java

@@ -8,6 +8,7 @@ import cn.hutool.core.util.StrUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.ytpm.advertise.enums.AdPlatformTypeEnum;
 import com.ytpm.advertise.enums.AdSourceTypeEnum;
+import com.ytpm.agent.enums.AdRecordEnum;
 import com.ytpm.agent.enums.UserStatusEnum;
 import com.ytpm.agent.view.AgentAdGroupStaticsVO;
 import com.ytpm.agent.view.AgentTopCountView;
@@ -32,7 +33,6 @@ import com.ytpm.middle.view.DashboardRiskVO;
 import com.ytpm.middle.view.UserRankingListVO;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.stereotype.Service;
@@ -59,21 +59,20 @@ import java.util.stream.Collectors;
 @RefreshScope
 public class AdServiceImpl implements AdService {
 
-    @Autowired
+    @Resource
     private AdRecordMapper adRecordMapper;
-    @Autowired
+    @Resource
     private AppUserMapper appUserMapper;
+    @Resource
+    private RiskFeign riskFeign;
+    @Resource
+    private AppUserService appUserService;
 
     @Value(" ${risk.config.banned.tips}")
     private String tips;
-    @Autowired
-    private RiskFeign riskFeign;
     @Value("${yt.ios.appid:}")
     private String appId;
 
-    @Resource
-    private AppUserService appUserService;
-
     /**
      * 保存广告记录
      */
@@ -106,20 +105,48 @@ public class AdServiceImpl implements AdService {
         return Result.resultOk(RepMessage.SAVE_SUCCESS);
     }
 
+    /**
+     * 保存记录
+     *  始终创建新的事务以保障子方法的独立事务
+     */
+    @Override
+    public String saveRecordAndChangeUser(DyzAdRecordParam param, YtDyzUser user) {
+        //增加广告记录
+        handleParam(param);
+        String recordId = IdUtil.fastSimpleUUID();
+        YtDyzAdRecord adRecord = new YtDyzAdRecord();
+        BeanUtils.copyProperties(param, adRecord);
+        adRecord.setRecordId(recordId);
+        adRecord.setIosId(param.getIosId());
+        adRecord.setNetworkName(AdPlatformTypeEnum.getDesc(Integer.parseInt(param.getNetworkFormId())));
+        if (user == null || AdRecordEnum.LOGIN_BEFORE.getCode().equals(param.getLoginStatus())) {
+            if (user == null) {
+                adRecord.setAppId(appId);
+            }
+            adRecordMapper.addOneVisitor(adRecord);
+        } else {
+            adRecord.setAppId(user.getAppId());
+            adRecord.setUserId(user.getUserId());
+            adRecordMapper.addOne(adRecord);
+            if (param.getRevenue() == null) {
+                param.setRevenue(BigDecimal.ZERO);
+            }
+            appUserMapper.updateTotal(user.getUserId(), 1, param.getRevenue());
+        }
+        return recordId;
+    }
+
     /**
      * 统一处理入参时间
      */
     private void handleParam(DyzAdRecordParam param){
         String timeFormat = "yyyy-MM-dd HH:mm:ss";
         if (param.getBegintimestamp() != null && param.getFinishtimestamp() != null) {
-            // 处理 begintimestamp(兼容秒级和毫秒级)
             long beginTimestamp = param.getBegintimestamp();
             if (String.valueOf(beginTimestamp).length() == 10) { // 秒级时间戳(10位)
                 beginTimestamp *= 1000; // 转为毫秒级
             }
             param.setBeginTime(DateUtil.format(new Date(beginTimestamp), timeFormat));
-
-            // 处理 finishtimestamp(兼容秒级和毫秒级)
             long finishTimestamp = param.getFinishtimestamp();
             if (String.valueOf(finishTimestamp).length() == 10) { // 秒级时间戳(10位)
                 finishTimestamp *= 1000; // 转为毫秒级
@@ -145,41 +172,6 @@ public class AdServiceImpl implements AdService {
         }
     }
 
-    /**
-     * 保存记录
-     *  始终创建新的事务以保障子方法的独立事务
-     */
-//    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
-    @Override
-    public String saveRecordAndChangeUser(DyzAdRecordParam param, YtDyzUser user) {
-        //增加广告记录
-        //修改用户信息, 广告次数+1  总收益 + revenue
-//        YtDyzUser dyzUser = new YtDyzUser();
-//        dyzUser.setUserId(user.getUserId());
-//        dyzUser.setTotalVideo(Objects.isNull(user.getTotalVideo())?1:(user.getTotalVideo()+1));
-//        dyzUser.setTotalIncome(user.getTotalIncome().add(param.getRevenue()));
-//        appUserMapper.updateUser(dyzUser);
-        handleParam(param);
-        String recordId = IdUtil.fastSimpleUUID();
-        YtDyzAdRecord adRecord = new YtDyzAdRecord();
-        BeanUtils.copyProperties(param, adRecord);
-        adRecord.setRecordId(recordId);
-        adRecord.setIosId(param.getIosId());
-        adRecord.setNetworkName(AdPlatformTypeEnum.getDesc(Integer.parseInt(param.getNetworkFormId())));
-        if (user == null) {
-            adRecord.setAppId(appId);
-            adRecordMapper.addOneVisitor(adRecord);
-        } else {
-            adRecord.setAppId(user.getAppId());
-            adRecord.setUserId(user.getUserId());
-            adRecordMapper.addOne(adRecord);
-            if (param.getRevenue() == null) {
-                param.setRevenue(BigDecimal.ZERO);
-            }
-            appUserMapper.updateTotal(user.getUserId(), 1, param.getRevenue());
-        }
-        return recordId;
-    }
 
     private String getTipsMsg(){
         String[] split = tips.split(",");

+ 188 - 194
yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/service/impl/AppUserServiceImpl.java

@@ -6,8 +6,14 @@ import cn.hutool.core.util.RandomUtil;
 import cn.hutool.core.util.StrUtil;
 import com.ytpm.agent.enums.UserStatusEnum;
 import com.ytpm.agent.model.YtDitch;
-import com.ytpm.app.model.*;
+import com.ytpm.app.enums.LoginType;
+import com.ytpm.app.model.YtAppDefaultConfig;
+import com.ytpm.app.model.YtDyzAnswerRecord;
+import com.ytpm.app.model.YtDyzLoginRecord;
+import com.ytpm.app.model.YtDyzPowerRecord;
+import com.ytpm.app.model.YtDyzUser;
 import com.ytpm.app.param.IosLoginParam;
+import com.ytpm.app.param.LoginParam;
 import com.ytpm.app.param.WxLoginParam;
 import com.ytpm.app.view.IosUserInfo;
 import com.ytpm.app.view.WxDefaultConfig;
@@ -23,13 +29,13 @@ import com.ytpm.lemonios.dao.LoginRecordMapper;
 import com.ytpm.lemonios.dao.QuestionMapper;
 import com.ytpm.lemonios.redis.RedisService;
 import com.ytpm.lemonios.service.AppUserService;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
+import javax.annotation.Resource;
 import java.math.BigDecimal;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -41,18 +47,21 @@ import java.util.Objects;
 @RefreshScope
 public class AppUserServiceImpl implements AppUserService {
 
-    @Autowired
+    @Resource
     private AppUserMapper appUserMapper;
-    @Autowired
+    @Resource
     private LoginRecordMapper loginRecordMapper;
-    @Autowired
+    @Resource
     private QuestionMapper questionMapper;
-    @Autowired
+    @Resource
     private RedisService redisService;
+    @Resource
+    private DitchMapper ditchMapper;
+
     @Value("${risk.config.banned.tips}")
     private String tips;
-    @Autowired
-    private DitchMapper ditchMapper;
+    @Value("${yt.ios.appid:}")
+    private String appId;
 
     /**
      * openid查询用户信息
@@ -67,91 +76,103 @@ public class AppUserServiceImpl implements AppUserService {
     public YtDyzUser crudForNewTrans(WxLoginParam param, WxUserInfo wxUserInfo, WxLoginResult loginResult) {
         //处理用户注册或登录更新信息
         YtDyzUser old = appUserMapper.getYtAppUser(loginResult.getOpenid(), param.getDitchId());
-        if(Objects.isNull(old)) {
-            old = new YtDyzUser();
-            registryUser(param,wxUserInfo,loginResult, old);
-        }else{
-            deadWithUserCrud(old,wxUserInfo,param);
+        if (Objects.isNull(old)) {
+            old = registryUserByWx(param, wxUserInfo, loginResult);
+        } else {
+            deadWithUserCrud(old, wxUserInfo, param);
         }
         //设置最后一次答题问题ID、今日答题数、历史答题数
         setExtInfo(old,wxUserInfo.getHeadimgurl());
         // 添加用户登录记录
-        addLoginRecord(param,old.getUserId());
+        addLoginRecord(param,old.getUserId(), LoginType.WX);
         return old;
     }
 
-    @Override
-    public YtDyzUser crudForNewTransIos(IosLoginParam param, IosUserInfo userInfo, String loginType) {
-        YtDyzUser old = appUserMapper.selectByIosId(param.getIosId());
-        if(Objects.isNull(old)) {
-            old = new YtDyzUser();
-            registryUserForIos(param,userInfo, old);
-        }else{
-            deadWithUserCrudForIos(old,userInfo,param);
-        }
-        //设置最后一次答题问题ID、今日答题数、历史答题数
-        setExtInfoForIos(old, userInfo.getHeadimgurl());
-        // 添加用户登录记录
-        addLoginRecordForIos(param,old.getUserId(), loginType);
+    /**
+     * 微信渠道 注册用户
+     */
+    private YtDyzUser registryUserByWx(WxLoginParam param, WxUserInfo wxUserInfo, WxLoginResult loginResult) {
+        YtDyzUser old = new YtDyzUser();
+        old.setUserId(redisService.getAppUserId());
+        old.setPhone(param.getPhone());
+        old.setDeviceId(param.getDeviceId());
+        old.setNickName(wxUserInfo.getNickname());
+        old.setLastLoginTime(new Date());
+        old.setRegistryTime(new Date());
+        old.setLastLoginIp(param.getLoginIp());
+        old.setLoginDays(1);
+        old.setPower(0);
+        old.setTotalVideo(0);
+        old.setTotalIncome(BigDecimal.ZERO);
+        old.setRedPacketAmount(BigDecimal.ZERO);
+        old.setRedPacketBalance(BigDecimal.ZERO);
+        old.setPointsBalance(BigDecimal.ZERO);
+        old.setPointsTotal(BigDecimal.ZERO);
+        old.setWithdrawTotal(BigDecimal.ZERO);
+        old.setSignDays(0);
+        old.setDitchId(param.getDitchId());
+        old.setAppId(param.getAppId());
+        old.setUserStatus(UserStatusEnum.NORMAL.getCode());
+        old.setWxOpenId(loginResult.getOpenid());
+        old.setHeadImg(wxUserInfo.getHeadimgurl());
+        //根据设备ID获取平台ID 获取不到再生成平台ID
+        String platformId = appUserMapper.getByDeviceId(param.getDeviceId(),wxUserInfo.getOpenid());
+        old.setPlatformId(StrUtil.isBlank(platformId)?
+                (StrConstant.PLATFORM_ID_PREFIX + IdUtil.getSnowflakeNextIdStr()):platformId);
+        appUserMapper.addOne(old);
         return old;
     }
 
-    @Override
-    public Result<?> addDefaultConfig(YtDitch param) {
-        ditchMapper.insertOne(param);
-        WxDefaultConfig lastOne = appUserMapper.getLastOne(param.getAppId());
-        YtAppDefaultConfig appDefaultConfig = new YtAppDefaultConfig();
-        appDefaultConfig.setConfigName(param.getDitchName());
-        appDefaultConfig.setDitchId(param.getDitchId().toString());
-        appDefaultConfig.setOpenId("");
-        appDefaultConfig.setSecret(lastOne.getSecret());
-        appDefaultConfig.setAppKey("");
-        appDefaultConfig.setAppType(lastOne.getAppType());
-        appDefaultConfig.setAppId(lastOne.getAppId());
-        appDefaultConfig.setCanUseRoot(lastOne.getCanUseRoot());
-        appDefaultConfig.setCanUseAdb(lastOne.getCanUseAdb());
-        appDefaultConfig.setCanAccumulation(lastOne.getCanAccumulation());
-        appDefaultConfig.setCanSimulator(lastOne.getCanSimulator());
-        appDefaultConfig.setPowerWaitTime(lastOne.getPowerWaitTime());
-        appDefaultConfig.setInterstitialIntervalTime(lastOne.getInterstitialIntervalTime());
-        appUserMapper.saveAppConfig(appDefaultConfig);
-        return Result.resultOk(RepMessage.ADD_SUCCESS);
-    }
 
-    @Override
-    public void addPower(String userId) {
-        appUserMapper.addOnePower(userId);
-        YtDyzPowerRecord record = new YtDyzPowerRecord();
-        record.setUserId(userId);
-        record.setRecordId(IdUtil.fastSimpleUUID());
-        record.setAddTime(new Date());
-        record.setType(2);
-        record.setRemark("增加体力");
-        appUserMapper.addPowerRecord(record);
+    /**
+     * 处理用户数据
+     */
+    private void deadWithUserCrud(YtDyzUser old, WxUserInfo wxUserInfo, LoginParam param) {
+        //处于风控状态的用户不允许登录
+        if(!UserStatusEnum.NORMAL.getCode().equals(old.getUserStatus())
+                && !UserStatusEnum.VISITOR_LOCK.getCode().equals(old.getUserStatus())){
+            throw new CustomerException(getTipsMsg());
+        }
+        YtDyzUser newUser = new YtDyzUser();
+        newUser.setUserId(old.getUserId());
+        newUser.setNickName(wxUserInfo.getNickname());
+        newUser.setHeadImg(wxUserInfo.getHeadimgurl());
+        newUser.setLastLoginTime(new Date());
+        newUser.setLastLoginIp(param.getLoginIp());
+        newUser.setPhone(param.getPhone());
+        newUser.setDeviceId(param.getDeviceId());
+        setNewLoginDays(newUser, old);
+        appUserMapper.updateUser(newUser);
     }
 
+
     /**
-     * 设置扩展信息
+     * 更新登陆天数
      */
-    private void setExtInfo(YtDyzUser old, String headimgurl) {
-        old.setHeadImg(headimgurl);
-            old.setLastQuestionId(questionMapper.getLastQuestionId(old.getUserId()));
-        old.setTodayAnswerCount(questionMapper.getAnswerCount(old.getUserId(),1));
-        old.setHistoryAnswerCount(questionMapper.getAnswerCount(old.getUserId(),2));
-        old.setAnswerRecordList(questionMapper.getAnswerRecords(old.getUserId()));
-        old.setLoginRecordList(loginRecordMapper.getLoginRecords(old.getUserId()));
+    private void setNewLoginDays(YtDyzUser newUser, YtDyzUser dyzUser) {
+        YtDyzLoginRecord wxLoginRecord = loginRecordMapper.getLastLoginRecord(dyzUser.getUserId(), 0);
+        YtDyzLoginRecord visitorLoginRecord = loginRecordMapper.getLastLoginRecord(dyzUser.getUserId(), 1);
+        if (wxLoginRecord == null && visitorLoginRecord == null
+                || wxLoginRecord != null && wxLoginRecord.getLoginTime() != null
+                && DateUtil.compare(wxLoginRecord.getLoginTime(), newUser.getLastLoginTime(), "yyyy-MM-dd") < 0) {
+            newUser.setLoginDays(dyzUser.getLoginDays() + 1);
+        }
     }
 
+
     /**
      * 设置扩展信息
      */
-    private void setExtInfoForIos(YtDyzUser old, String headimgurl) {
-        old.setHeadImg(headimgurl);
+    private void setExtInfo(YtDyzUser old, String headImgUrl) {
+        old.setHeadImg(headImgUrl);
         old.setLastQuestionId(questionMapper.getLastQuestionId(old.getUserId()));
         old.setTodayAnswerCount(questionMapper.getAnswerCount(old.getUserId(),1));
         old.setHistoryAnswerCount(questionMapper.getAnswerCount(old.getUserId(),2));
+        old.setAnswerRecordList(questionMapper.getAnswerRecords(old.getUserId()));
+        old.setLoginRecordList(loginRecordMapper.getLoginRecords(old.getUserId()));
+        // 构建答题历史记录简易版
         List<YtDyzAnswerRecord> recordList = questionMapper.getAnswerRecords(old.getUserId());
-        List<String> viewList  = new ArrayList<>();
+        List<String> viewList = new ArrayList<>();
         int count = recordList.size();
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
         for (YtDyzAnswerRecord ytDyzAnswerRecord : recordList) {
@@ -160,31 +181,13 @@ public class AppUserServiceImpl implements AppUserService {
             viewList.add(timeStr);
         }
         old.setAnswerRecordTimeList(viewList);
-        old.setAnswerRecordList(questionMapper.getAnswerRecords(old.getUserId()));
-        old.setLoginRecordList(loginRecordMapper.getLoginRecords(old.getUserId()));
     }
 
-    /**
-     * 增加用户登录记录
-     */
-    private void addLoginRecord(WxLoginParam param,String userId) {
-        YtDyzLoginRecord loginRecord = new YtDyzLoginRecord();
-        loginRecord.setRecordId(IdUtil.fastSimpleUUID());
-        loginRecord.setUserId(userId);
-        loginRecord.setLoginTime(new Date());
-        loginRecord.setDeviceBrand(param.getBrand());
-        loginRecord.setDeviceModel(param.getModel());
-        loginRecord.setLoginIp(param.getLoginIp());
-        loginRecord.setOperator(param.getIpOperator());
-        loginRecord.setIpAddr(param.getIpLocation());
-        loginRecord.setPhoneJson(param.getPhoneJson());
-        loginRecordMapper.insertOne(loginRecord);
-    }
 
     /**
      * 增加用户登录记录
      */
-    private void addLoginRecordForIos(IosLoginParam param,String userId, String loginType) {
+    private void addLoginRecord(LoginParam param, String userId, LoginType loginType) {
         YtDyzLoginRecord loginRecord = new YtDyzLoginRecord();
         loginRecord.setRecordId(IdUtil.fastSimpleUUID());
         loginRecord.setUserId(userId);
@@ -195,115 +198,38 @@ public class AppUserServiceImpl implements AppUserService {
         loginRecord.setOperator(param.getIpOperator());
         loginRecord.setIpAddr(param.getIpLocation());
         loginRecord.setPhoneJson(param.getPhoneJson());
-        loginRecord.setLoginType(loginType);
+        loginRecord.setLoginType(loginType.getTypeName());
         loginRecordMapper.insertOne(loginRecord);
     }
 
-    private String getTipsMsg(){
-        String[] split = tips.split(",");
-        return split[RandomUtil.randomInt(split.length)];
-    }
-    /**
-     * 处理用户数据
-     */
-    private void deadWithUserCrud(YtDyzUser old, WxUserInfo wxUserInfo, WxLoginParam param) {
-        //处于风控状态的用户不允许登录
-        if(!old.getUserStatus().equals(UserStatusEnum.NORMAL.getCode())){
-            throw new CustomerException(getTipsMsg());
-        }
-        YtDyzUser newUser = new YtDyzUser();
-        newUser.setUserId(old.getUserId());
-        newUser.setNickName(wxUserInfo.getNickname());
-        newUser.setHeadImg(wxUserInfo.getHeadimgurl());
-        newUser.setLastLoginTime(new Date());
-        newUser.setLastLoginIp(param.getLoginIp());
-        newUser.setPhone(param.getPhone());
-        newUser.setDeviceId(param.getDeviceId());
-        YtDyzLoginRecord wxLoginRecord = loginRecordMapper.getLastLoginRecord(old.getUserId(), 0);
-        YtDyzLoginRecord visitorLoginRecord = loginRecordMapper.getLastLoginRecord(old.getUserId(), 1);
-        if (wxLoginRecord == null && visitorLoginRecord == null
-                || wxLoginRecord != null && wxLoginRecord.getLoginTime() != null
-                && DateUtil.compare(wxLoginRecord.getLoginTime(), newUser.getLastLoginTime(), "yyyy-MM-dd") < 0) {
-            newUser.setLoginDays(old.getLoginDays() + 1);
-        }
-        appUserMapper.updateUser(newUser);
-    }
 
-    /**
-     * 处理用户数据
-     */
-    private void deadWithUserCrudForIos(YtDyzUser old, IosUserInfo userInfo, IosLoginParam param) {
-        //处于风控状态的用户不允许登录
-        if(!old.getUserStatus().equals(UserStatusEnum.NORMAL.getCode())
-            && !old.getUserStatus().equals(UserStatusEnum.VISITOR_LOCK.getCode())){
-            throw new CustomerException(getTipsMsg());
-        }
-        YtDyzUser newUser = new YtDyzUser();
-        if (old.getDitchId() == null) {
-            newUser.setDitchId(param.getDitchId());
-            YtDitch ditch = ditchMapper.selectById(param.getDitchId());
-            newUser.setAppId(ditch.getAppId());
-        }
-        if (param.getDitchId() != null){
-            newUser.setDitchId(param.getDitchId());
-            YtDitch ditch = ditchMapper.selectById(param.getDitchId());
-            newUser.setAppId(ditch.getAppId());
-        }
 
-        newUser.setUserId(old.getUserId());
-        newUser.setNickName(userInfo.getNickname());
-        newUser.setHeadImg(userInfo.getHeadimgurl());
-        newUser.setLastLoginTime(new Date());
-        newUser.setLastLoginIp(param.getLoginIp());
-        newUser.setPhone(param.getPhone());
-        newUser.setDeviceId(param.getDeviceId());
-        YtDyzLoginRecord wxLoginRecord = loginRecordMapper.getLastLoginRecord(old.getUserId(), 0);
-        YtDyzLoginRecord visitorLoginRecord = loginRecordMapper.getLastLoginRecord(old.getUserId(), 1);
-        if (wxLoginRecord == null && visitorLoginRecord == null
-                || wxLoginRecord != null && wxLoginRecord.getLoginTime() != null
-                && DateUtil.compare(wxLoginRecord.getLoginTime(), newUser.getLastLoginTime(), "yyyy-MM-dd") < 0) {
-            newUser.setLoginDays(old.getLoginDays() + 1);
+    @Override
+    public YtDyzUser crudForNewTransIos(IosLoginParam param, IosUserInfo userInfo, LoginType loginType) {
+        YtDyzUser old = appUserMapper.getYtAppUserForIos(param.getIosId(), param.getDitchId());
+        // 旧包兼容 处理通过配置appid生成 ditchId为null的用户
+        if (old == null) {
+            old = appUserMapper.getYtAppUserAndDitchNull(param.getIosId());
         }
-        appUserMapper.updateUser(newUser);
+        if (Objects.isNull(old)) {
+            old = registryUserByIos(param, userInfo);
+        } else {
+            deadWithUserByIos(old, userInfo, param);
+            old = appUserMapper.getYtAppUserForIos(param.getIosId(), param.getDitchId());
+        }
+        //设置最后一次答题问题ID、今日答题数、历史答题数
+        setExtInfo(old, userInfo.getHeadimgurl());
+        // 添加用户登录记录
+        addLoginRecord(param,old.getUserId(), loginType);
+        return old;
     }
 
-    /**
-     * 注册用户
-     */
-    private void registryUser(WxLoginParam param,WxUserInfo wxUserInfo,WxLoginResult loginResult, YtDyzUser old) {
-        old.setUserId(redisService.getAppUserId());
-        old.setPhone(param.getPhone());
-        old.setDeviceId(param.getDeviceId());
-        old.setNickName(wxUserInfo.getNickname());
-        old.setLastLoginTime(new Date());
-        old.setRegistryTime(new Date());
-        old.setLastLoginIp(param.getLoginIp());
-        old.setLoginDays(1);
-        old.setPower(0);
-        old.setTotalVideo(0);
-        old.setTotalIncome(BigDecimal.ZERO);
-        old.setRedPacketAmount(BigDecimal.ZERO);
-        old.setRedPacketBalance(BigDecimal.ZERO);
-        old.setPointsBalance(BigDecimal.ZERO);
-        old.setPointsTotal(BigDecimal.ZERO);
-        old.setWithdrawTotal(BigDecimal.ZERO);
-        old.setDitchId(param.getDitchId());
-        old.setSignDays(0);
-        old.setAppId(param.getAppId());
-        old.setUserStatus(UserStatusEnum.NORMAL.getCode());
-        old.setWxOpenId(loginResult.getOpenid());
-        old.setHeadImg(wxUserInfo.getHeadimgurl());
-        //根据设备ID获取平台ID 获取不到再生成平台ID
-        String platformId = appUserMapper.getByDeviceId(param.getDeviceId(),wxUserInfo.getOpenid());
-        old.setPlatformId(StrUtil.isBlank(platformId)?
-                (StrConstant.PLATFORM_ID_PREFIX + IdUtil.getSnowflakeNextIdStr()):platformId);
-        appUserMapper.addOne(old);
-    }
 
     /**
      * 注册用户
      */
-    private void registryUserForIos(IosLoginParam param,IosUserInfo userInfo, YtDyzUser old) {
+    private YtDyzUser registryUserByIos(IosLoginParam param, IosUserInfo userInfo) {
+        YtDyzUser old = new YtDyzUser();
         old.setUserId(redisService.getAppUserId());
         old.setPhone(param.getPhone());
         old.setDeviceId(param.getDeviceId());
@@ -322,22 +248,90 @@ public class AppUserServiceImpl implements AppUserService {
         old.setWithdrawTotal(BigDecimal.ZERO);
         old.setDitchId(param.getDitchId());
         old.setSignDays(0);
-        YtDitch ditch;
-        if (param.getDitchId() == null){
-            old.setDitchId(2025062500193L);
-            old.setAppId("251be4dff0fd408fbc1fe2c47bf515eb");
-        } else {
-            ditch = ditchMapper.selectById(param.getDitchId());
-            old.setDitchId(param.getDitchId());
-            old.setAppId(ditch.getAppId());
-        }
         old.setUserStatus(UserStatusEnum.NORMAL.getCode());
         old.setIosId(param.getIosId());
         old.setHeadImg(userInfo.getHeadimgurl());
+        old.setAppId(appId);
+        if (param.getDitchId() != null){
+            YtDitch ditch = ditchMapper.selectById(param.getDitchId());
+            old.setDitchId(param.getDitchId());
+            old.setAppId(ditch.getAppId());
+        }
         //根据设备ID获取平台ID 获取不到再生成平台ID
         String platformId = appUserMapper.getByDeviceId(param.getDeviceId(),userInfo.getOpenid());
         old.setPlatformId(StrUtil.isBlank(platformId)?
                 (StrConstant.PLATFORM_ID_PREFIX + IdUtil.getSnowflakeNextIdStr()):platformId);
         appUserMapper.addOne(old);
+        return old;
+    }
+
+    /**
+     * 处理用户数据
+     */
+    private void deadWithUserByIos(YtDyzUser dyzUser, IosUserInfo userInfo, LoginParam param) {
+        //处于风控状态的用户不允许登录
+        if(!UserStatusEnum.NORMAL.getCode().equals(dyzUser.getUserStatus())
+                && !UserStatusEnum.VISITOR_LOCK.getCode().equals(dyzUser.getUserStatus())){
+            throw new CustomerException(getTipsMsg());
+        }
+        YtDyzUser newUser = new YtDyzUser();
+        newUser.setUserId(dyzUser.getUserId());
+        newUser.setNickName(userInfo.getNickname());
+        newUser.setHeadImg(userInfo.getHeadimgurl());
+        newUser.setLastLoginTime(new Date());
+        newUser.setLastLoginIp(param.getLoginIp());
+        newUser.setPhone(param.getPhone());
+        newUser.setDeviceId(param.getDeviceId());
+        // 更新用户渠道信息
+        if (param.getDitchId() != null){
+            newUser.setDitchId(param.getDitchId());
+            YtDitch ditch = ditchMapper.selectById(param.getDitchId());
+            newUser.setAppId(ditch.getAppId());
+        }
+        setNewLoginDays(newUser, dyzUser);
+        appUserMapper.updateUser(newUser);
+    }
+
+
+    @Override
+    public Result<?> addDefaultConfig(YtDitch param) {
+        ditchMapper.insertOne(param);
+        WxDefaultConfig lastOne = appUserMapper.getLastOne(param.getAppId());
+        YtAppDefaultConfig appDefaultConfig = new YtAppDefaultConfig();
+        appDefaultConfig.setConfigName(param.getDitchName());
+        appDefaultConfig.setDitchId(param.getDitchId().toString());
+        appDefaultConfig.setOpenId("");
+        appDefaultConfig.setSecret(lastOne.getSecret());
+        appDefaultConfig.setAppKey("");
+        appDefaultConfig.setAppType(lastOne.getAppType());
+        appDefaultConfig.setAppId(lastOne.getAppId());
+        appDefaultConfig.setCanUseRoot(lastOne.getCanUseRoot());
+        appDefaultConfig.setCanUseAdb(lastOne.getCanUseAdb());
+        appDefaultConfig.setCanAccumulation(lastOne.getCanAccumulation());
+        appDefaultConfig.setCanSimulator(lastOne.getCanSimulator());
+        appDefaultConfig.setPowerWaitTime(lastOne.getPowerWaitTime());
+        appDefaultConfig.setInterstitialIntervalTime(lastOne.getInterstitialIntervalTime());
+        appUserMapper.saveAppConfig(appDefaultConfig);
+        return Result.resultOk(RepMessage.ADD_SUCCESS);
+    }
+
+    @Override
+    public void addPower(String userId) {
+        appUserMapper.addOnePower(userId);
+        YtDyzPowerRecord record = new YtDyzPowerRecord();
+        record.setUserId(userId);
+        record.setRecordId(IdUtil.fastSimpleUUID());
+        record.setAddTime(new Date());
+        record.setType(2);
+        record.setRemark("增加体力");
+        appUserMapper.addPowerRecord(record);
     }
+
+
+    private String getTipsMsg(){
+        String[] split = tips.split(",");
+        return split[RandomUtil.randomInt(split.length)];
+    }
+
+
 }

+ 1 - 2
yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/service/impl/DitchServiceImpl.java

@@ -2,7 +2,6 @@ package com.ytpm.lemonios.service.impl;
 
 import com.ytpm.agent.model.YtApp;
 import com.ytpm.agent.model.YtDitch;
-import com.ytpm.agent.param.AppParam;
 import com.ytpm.agent.param.DitchListParam;
 import com.ytpm.agent.view.AgentDitchView;
 import com.ytpm.lemonios.dao.DitchMapper;
@@ -22,7 +21,7 @@ public class DitchServiceImpl implements DitchService {
 
     @Override
     public List<AgentDitchView> ditchList(DitchListParam param) {
-        return agentDitchMapper.ditchListForIos(param.getAppId());
+        return agentDitchMapper.ditchListByAppId(param.getAppId());
     }
 
     @Override

+ 0 - 1
yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/service/impl/QuestionServiceImpl.java

@@ -23,7 +23,6 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Objects;

+ 12 - 1
yt-ios-lemon/lemon-ios-service/src/main/resources/mapper/AppUserMapper.xml

@@ -282,6 +282,7 @@
             user_id, app_id,phone,device_id, ditch_id, nick_name,head_img, power, registry_time, last_login_time, last_login_ip, login_days, total_video, total_income, red_packet_balance, red_packet_amount, points_balance, points_total, withdraw_total, sign_days, user_status, risk_reason, wx_open_id, ios_id, platform_id
         from yt_dyz_user
         where ios_id = #{iosId}
+
         Limit 1
     </select>
     <select id="getYtAppUserForIos" resultType="com.ytpm.app.model.YtDyzUser">
@@ -289,7 +290,17 @@
             user_id, app_id,phone,device_id, ditch_id, nick_name,head_img, power, registry_time, last_login_time, last_login_ip, login_days, total_video, total_income, red_packet_balance, red_packet_amount, points_balance, points_total, withdraw_total, sign_days, user_status, risk_reason, wx_open_id, ios_id, platform_id
         from yt_dyz_user
         where ios_id = #{iosId}
-          and ditch_id = #{ditchId}
+        <if test="ditchId != null">
+            and ditch_id = #{ditchId}
+        </if>
+        limit 1
+    </select>
+    <select id="getYtAppUserAndDitchNull" resultType="com.ytpm.app.model.YtDyzUser">
+        select
+        user_id, app_id,phone,device_id, ditch_id, nick_name,head_img, power, registry_time, last_login_time, last_login_ip, login_days, total_video, total_income, red_packet_balance, red_packet_amount, points_balance, points_total, withdraw_total, sign_days, user_status, risk_reason, wx_open_id, ios_id, platform_id
+        from yt_dyz_user
+        where ios_id = #{iosId} and ditch_id is null
+        limit 1
     </select>
     <select id="queryAll" resultType="com.ytpm.app.view.YtAppUserListView">
         select

+ 1 - 1
yt-ios-lemon/lemon-ios-service/src/main/resources/mapper/DitchMapper.xml

@@ -33,7 +33,7 @@
         from yt_ditch
         where user_id = #{userId} and is_delete = 0
     </select>
-    <select id="ditchListForIos" resultType="com.ytpm.agent.view.AgentDitchView">
+    <select id="ditchListByAppId" resultType="com.ytpm.agent.view.AgentDitchView">
         select
         ditch_id, ditch_name, create_time
         from yt_ditch

+ 11 - 0
yt-middle/middle-platform/src/main/java/com/ytpm/middle/dao/AppMapper.java

@@ -1,5 +1,7 @@
 package com.ytpm.middle.dao;
 
+import com.ytpm.agent.model.YtApp;
+import com.ytpm.agent.model.YtAppConfigLog;
 import com.ytpm.agent.model.YtPlatformUserApp;
 import com.ytpm.middle.model.YtAppGrantRecord;
 import com.ytpm.middle.param.AppListParam;
@@ -66,4 +68,13 @@ public interface AppMapper {
      * @return
      */
     List<String> getAppListForSuperior(@Param("appId")String appId);
+
+    /**
+     * 保存出包配置修改记录
+     */
+    void insertConfigLog(YtAppConfigLog configLog);
+
+    List<YtAppConfigLog> selectLastConfigLog(@Param("appIds") String appIds);
+
+    YtApp selectByPrimaryId(@Param("appId")String appId);
 }

+ 91 - 14
yt-middle/middle-platform/src/main/java/com/ytpm/middle/service/impl/ApkServiceImpl.java

@@ -1,6 +1,7 @@
 package com.ytpm.middle.service.impl;
 
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.text.CharSequenceUtil;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.StrUtil;
@@ -9,6 +10,7 @@ import com.alibaba.fastjson.JSONArray;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import com.ytpm.agent.model.YtApp;
+import com.ytpm.agent.model.YtAppConfigLog;
 import com.ytpm.agent.model.YtPlatformUserApp;
 import com.ytpm.agent.param.AppListParam;
 import com.ytpm.agent.param.AppParam;
@@ -23,13 +25,15 @@ import com.ytpm.middle.dao.AppMapper;
 import com.ytpm.middle.dao.RiskMapper;
 import com.ytpm.middle.service.ApkService;
 import com.ytpm.middle.util.AliOSSUtil;
+import com.ytpm.middle.util.BeanChangeUtil;
 import com.ytpm.middle.util.FeignClientInvoker;
 import com.ytpm.middle.view.MiddleUserInfo;
 import com.ytpm.risk.model.YtRiskConfig;
 import com.ytpm.risk.model.YtRiskTemplate;
 import com.ytpm.risk.model.YtRiskTemplateConfig;
 import com.ytpm.util.DateUtil;
-import org.springframework.beans.factory.annotation.Autowired;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.stereotype.Service;
@@ -44,6 +48,7 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
+@Slf4j
 @Service
 @RefreshScope
 public class ApkServiceImpl implements ApkService {
@@ -52,6 +57,11 @@ public class ApkServiceImpl implements ApkService {
     private ApkMapper apkMapper;
     @Resource
     private RiskMapper riskMapper;
+    @Resource
+    private FeignClientInvoker feignInvoker;
+    @Resource
+    private AppMapper appMapper;
+
     @Value("${risk.config.initEcpm}")
     private String initEcpm;
     @Value("${risk.config.initRevenue}")
@@ -89,10 +99,7 @@ public class ApkServiceImpl implements ApkService {
     @Value(("${risk.config.visitor.initRidCount:10}"))
     private String initVisitorRidCount;
 
-    @Autowired
-    private FeignClientInvoker feignInvoker;
-    @Autowired
-    private AppMapper appMapper;
+
 
     /**
      * 查询应用列表
@@ -119,7 +126,14 @@ public class ApkServiceImpl implements ApkService {
         Map<String, Integer> countDownloadMap = AliOSSUtil.getCountDownload(
                 Math.toIntExact(DateUtil.getTodayStart().getTime() / 1000), (int) (System.currentTimeMillis() / 1000));
         WxDefaultConfig config;
+        // 查询配置修改记录
+        List<YtAppConfigLog> configLogs = appMapper.selectLastConfigLog(appIds);
+        Map<String, YtAppConfigLog> configLogMap = configLogs.stream().collect(Collectors.toMap(
+                YtAppConfigLog::getAppId, item-> item,
+                (o1,o2) -> o2
+        ));
         for (AgentAppView view : views) {
+            view.setLastChangeLog(configLogMap.get(view.getAppId()));
             if(appTypeMap.containsKey(view.getAppId())) {
                 config = appTypeMap.get(view.getAppId());
                 view.setAppCode(config.getAppType());
@@ -149,7 +163,9 @@ public class ApkServiceImpl implements ApkService {
                 view.setCanShowRealNovelName(config.getCanShowRealNovelName());
                 view.setCanShowRedPacket(config.getCanShowRedPacket());
             }
-            if(CharSequenceUtil.isBlank(view.getApkUrl()))continue;
+            if(CharSequenceUtil.isBlank(view.getApkUrl())) {
+                continue;
+            }
             String substring = view.getApkUrl().substring(view.getApkUrl().lastIndexOf("/")+1).toLowerCase(Locale.ENGLISH);
             if(countDownloadMap.containsKey(substring)){
                 view.setDownloadCount(countDownloadMap.get(substring));
@@ -164,17 +180,23 @@ public class ApkServiceImpl implements ApkService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Result<?> saveApp(AppParam param, MiddleUserInfo loginUser) {
+        YtPlatformUserApp app = appMapper.getByPrimary(param.getSuperiorId());
+        // 保存修改记录
+        saveConfigChangeLog(param, app, loginUser.getUserId());
         //数据库操作,有appId为修改, 没有时为新增
         changeDataAction(param, loginUser.getUserId());
         //出包修改 default_config
         changeDefaultConfig(param);
         if(CharSequenceUtil.isNotBlank(param.getAppId())){
             //修改时判断已生成风控配置,则说明出过包,仅需更换即可
-            YtRiskTemplate template =  riskMapper.getTemplateByAppId(param.getAppId());
+            YtRiskTemplate template = riskMapper.getTemplateByAppId(param.getAppId());
             if(Objects.isNull(template)){
+                YtApp ytApp = appMapper.selectByPrimaryId(param.getAppId());
+                if (ytApp != null) {
+                    param.setAppType(ytApp.getAppType());
+                }
                 generateRiskDefaultConfig(param,loginUser);
             }
-            return Result.resultOk(RepMessage.SAVE_SUCCESS);
         }
         return Result.resultOk(RepMessage.SAVE_SUCCESS);
     }
@@ -185,6 +207,8 @@ public class ApkServiceImpl implements ApkService {
     @Override
     public Result<?> changeConfig(AppParam param) {
         //出包修改 default_config
+        YtPlatformUserApp app = appMapper.getByPrimary(param.getSuperiorId());
+        saveConfigChangeLog(param, app, null);
         changeDefaultConfig(param);
         return Result.resultOk(RepMessage.SAVE_SUCCESS);
     }
@@ -194,6 +218,11 @@ public class ApkServiceImpl implements ApkService {
      */
     private void changeDefaultConfig(AppParam param) {
         YtPlatformUserApp app = appMapper.getByPrimary(param.getSuperiorId());
+        YtAppDefaultConfig config = convertToYtDefaultConfig(param, app);
+        feignInvoker.invoke(app.getServiceName(), "updateAppConfig", config);
+    }
+
+    private YtAppDefaultConfig convertToYtDefaultConfig(AppParam param, YtPlatformUserApp app){
         YtAppDefaultConfig config = new YtAppDefaultConfig();
         config.setAppId(param.getAppId());
         if(Objects.nonNull(param.getDitchId())){
@@ -222,6 +251,47 @@ public class ApkServiceImpl implements ApkService {
         config.setCanShowRealNovelName(param.getCanShowRealNovelName());
         config.setCanShowRedPacket(param.getCanShowRedPacket());
         feignInvoker.invoke(app.getServiceName(), "updateAppConfig", config);
+        return config;
+    }
+
+    private void saveConfigChangeLog(AppParam appParam, YtPlatformUserApp app, String loginUserId) {
+        StringBuilder changeContent = new StringBuilder();
+        try {
+            YtApp oldYtApp = appMapper.selectByPrimaryId(appParam.getAppId());
+            if (oldYtApp != null) {
+                YtApp newYtApp = new YtApp();
+                BeanUtil.copyProperties(appParam, newYtApp);
+                changeContent.append(BeanChangeUtil.compareBeans(oldYtApp, newYtApp));
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+        try {
+            Object object = feignInvoker.invoke(app.getServiceName(), "getConfigs", appParam.getAppId());
+            WxDefaultConfig oldDefault = null;
+            if (object != null) {
+                List<WxDefaultConfig> configList = JSONArray.parseArray(JSON.toJSONString(object), WxDefaultConfig.class);
+                oldDefault = CollUtil.isNotEmpty(configList) ? configList.get(0) : null;
+            }
+            if (oldDefault != null) {
+                // 变更记录修改
+                YtAppDefaultConfig config = convertToYtDefaultConfig(appParam, app);
+                WxDefaultConfig newConfig = new WxDefaultConfig();
+                BeanUtils.copyProperties(config, newConfig);
+                changeContent.append(BeanChangeUtil.compareBeans(oldDefault, newConfig));
+            }
+        }catch (Exception e){
+            log.error(e.getMessage(), e);
+        }
+        if (changeContent.length() > 0) {
+            YtAppConfigLog configLog = new YtAppConfigLog();
+            configLog.setRecordId(IdUtil.fastSimpleUUID());
+            configLog.setAppId(appParam.getAppId());
+            configLog.setChangeContent(changeContent.toString());
+            configLog.setChangeTime(new Date());
+            configLog.setChangeBy(loginUserId);
+            appMapper.insertConfigLog(configLog);
+        }
     }
 
     /**
@@ -320,11 +390,12 @@ public class ApkServiceImpl implements ApkService {
                 StrUtil.format("开屏广告、横幅、原生(信息流)总预估收益<{},", initVisitorRevenueLimit), initVisitorRevenueLimit, 4);
         configs.add(riskConfig);
         String templateId = IdUtil.getSnowflakeNextIdStr();
+        Integer enabled = 2 == param.getAppType() ? 0 : 1; // IOS默认关闭风控
         YtRiskTemplate template = new YtRiskTemplate(templateId, "游客用户总预估收益限制",
                 StrUtil.format("开屏广告、横幅、原生(信息流)总预估收益<{},", initVisitorRevenueLimit),
                 appId + "-344", agentId, 2, appId,
                 new Date(), loginUser.getUserId(), null, null,
-                1, 1, 1);
+                enabled, 1, 1);
         riskMapper.insertTemplate(template);
         // 风控模板关联配置项
         bindTempConfig(loginUser, template, configs);
@@ -367,11 +438,12 @@ public class ApkServiceImpl implements ApkService {
                 StrUtil.format("获得奖励的激励视频数>{}", initHourTaskLimit), initHourTaskLimit, 3);
         configs.add(riskConfig);
         String templateId = IdUtil.getSnowflakeNextIdStr();
+        Integer enabled = 2 == param.getAppType() ? 0 : 1; // IOS默认关闭风控
         YtRiskTemplate template = new YtRiskTemplate(templateId,"小时区间任务数完成限制",
                 StrUtil.format("{}小时内,获得奖励的激励视频数>{}", initHourCount, initHourTaskLimit),
                 appId + "-768", agentId, 2, appId,
                 currentDate, loginUser.getUserId(),null, null,
-                1,1,1);
+                enabled,1,1);
         riskMapper.insertTemplate(template);
         // 风控模板关联配置项
         bindTempConfig(loginUser, template, configs);
@@ -393,11 +465,12 @@ public class ApkServiceImpl implements ApkService {
                 StrUtil.format("获得奖励的激励视频数>{}", initMonthTaskLimit), initMonthTaskLimit, 3);
         configs.add(riskConfig);
         String templateId = IdUtil.getSnowflakeNextIdStr();
+        Integer enabled = 2 == param.getAppType() ? 0 : 1; // IOS默认关闭风控
         YtRiskTemplate template = new YtRiskTemplate(templateId,"月区间任务完成数限制",
                 StrUtil.format("{}月内,获得奖励的激励视频数>{}", initMonthCount, initMonthTaskLimit),
                 appId + "-767", agentId, 2, appId,
                 currentDate, loginUser.getUserId(),null, null,
-                1,1,1);
+                enabled,1,1);
         riskMapper.insertTemplate(template);
         // 风控模板关联配置项
         bindTempConfig(loginUser, template, configs);
@@ -424,10 +497,11 @@ public class ApkServiceImpl implements ApkService {
         String templateId = IdUtil.getSnowflakeNextIdStr();
         String templateContent = StrUtil.format("当日用户获得{}个获得奖励的激励视频,最后{}个获得奖励的激励视频平均收益<{}",
                 initAdCompletedCount, initFirstCount, initAverageRevenue);
+        Integer enabled = 2 == param.getAppType() ? 0 : 1; // IOS默认关闭风控
         YtRiskTemplate template = new YtRiskTemplate(templateId,"成本收益限制", templateContent,
                 appId + "-766", agentId, 2, appId,
                 currentDate, loginUser.getUserId(),null, null,
-                1,1,1);
+                enabled,1,1);
         riskMapper.insertTemplate(template);
         YtRiskTemplateConfig templateConfig;
         for (String itemId : configIds) {
@@ -457,10 +531,11 @@ public class ApkServiceImpl implements ApkService {
             templateConfig = new YtRiskTemplateConfig(templateId,itemId,loginUser.getUserId(),loginUser.getNickName(),new Date());
             riskMapper.insertTempConfig(templateConfig);
         }
+        Integer enabled = 2 == param.getAppType() ? 0 : 1; // IOS默认关闭风控
         YtRiskTemplate template = new YtRiskTemplate(templateId,"最低收益限制",
                 "当日前2条获得奖励的激励视频,总收益为<"+initRevenue,appId+"-746",agentId,
                 2,appId,new Date(),loginUser.getUserId(),null,
-                null,1,1,1);
+                null,enabled,1,1);
         riskMapper.insertTemplate(template);
         //风控模版关联应用
         riskMapper.relativeApp(appId,param.getAppName(),template.getTemplateId(),
@@ -489,10 +564,11 @@ public class ApkServiceImpl implements ApkService {
             templateConfig = new YtRiskTemplateConfig(templateId,itemId,loginUser.getUserId(),loginUser.getNickName(),new Date());
             riskMapper.insertTempConfig(templateConfig);
         }
+        Integer enabled = 2 == param.getAppType() ? 0 : 1; // IOS默认关闭风控
         YtRiskTemplate template = new YtRiskTemplate(templateId,"激励视频ecpm值控制",
                 "当日前4条激励视频,有2条,ecpm值为<"+initEcpm,appId+"-742",agentId,
                 2,appId,new Date(),loginUser.getUserId(),null,
-                null,1,1,1);
+                null,enabled,1,1);
         riskMapper.insertTemplate(template);
         //风控模版关联应用
         riskMapper.relativeApp(appId,param.getAppName(),template.getTemplateId(),
@@ -511,6 +587,7 @@ public class ApkServiceImpl implements ApkService {
             app.setAppId(IdUtil.fastSimpleUUID());
             app.setUserId(userId);
             app.setEnabled(1);
+            app.setCreateTime(new Date());
             apkMapper.insertOne(app);
         }
     }

+ 1 - 1
yt-middle/middle-platform/src/main/java/com/ytpm/middle/service/impl/AppServiceImpl.java

@@ -53,7 +53,7 @@ public class AppServiceImpl implements AppService {
     @Override
     public ResultTable<AppListVO> appList(AppListParam param) {
         PageHelper.startPage(param.getPage(), param.getLimit());
-        return ResultTable.resultTableOk(new PageInfo<AppListVO>(appMapper.getAppList(param)));
+        return ResultTable.resultTableOk(new PageInfo<>(appMapper.getAppList(param)));
     }
     /**
      * 新增上架应用

+ 8 - 6
yt-middle/middle-platform/src/main/java/com/ytpm/middle/service/impl/CountServiceImpl.java

@@ -153,17 +153,19 @@ public class CountServiceImpl implements CountService {
      */
     @Override
     public Result<DashboardRevenueVO> getRevenueStatics(String appId) {
-        List<AgentAppView> apkList =  apkMapper.queryBySuperiorId(appId);
+        List<AgentAppView> apkList = apkMapper.queryBySuperiorId(appId);
         String apkIds = apkList.stream().map(AgentAppView::getAppId).collect(Collectors.joining(","));
         YtPlatformUserApp appInfo = appMapper.getByPrimary(appId);
-        Object o = feignInvoker.invoke(appInfo.getServiceName(),"revenueStatics",apkIds);
+        Object o = feignInvoker.invoke(appInfo.getServiceName(), "revenueStatics", apkIds);
         DashboardRevenueVO vo = JSONObject.parseObject(JSON.toJSONString(o), DashboardRevenueVO.class);
-        Map<String, String> appNameMap = apkList.stream().collect(Collectors.toMap(AgentAppView::getAppId, AgentAppView::getAppName));
         List<DashboardAppRevenueVO> appRevenueList = vo.getAppRevenueList();
-        for (DashboardAppRevenueVO revenueVO : appRevenueList) {
-            revenueVO.setAppName(appNameMap.get(revenueVO.getAppId()));
+        if (CollUtil.isNotEmpty(appRevenueList)) {
+            Map<String, String> appNameMap = apkList.stream().collect(Collectors.toMap(AgentAppView::getAppId, AgentAppView::getAppName));
+            for (DashboardAppRevenueVO revenueVO : appRevenueList) {
+                revenueVO.setAppName(appNameMap.get(revenueVO.getAppId()));
+            }
+            vo.setAppRevenueList(appRevenueList);
         }
-        vo.setAppRevenueList(appRevenueList);
         return Result.resultObjOk(vo);
     }
 

+ 103 - 0
yt-middle/middle-platform/src/main/java/com/ytpm/middle/util/BeanChangeUtil.java

@@ -0,0 +1,103 @@
+package com.ytpm.middle.util;
+
+
+import cn.hutool.core.util.StrUtil;
+import com.ytpm.annotation.BeanChange;
+import lombok.extern.slf4j.Slf4j;
+
+import java.lang.reflect.Field;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Objects;
+
+/**
+ * @author lih
+ * @date 2025-11-03 15:55
+ */
+@Slf4j
+public class BeanChangeUtil<T> {
+
+
+    /**
+     * 比较两个实体对象中被@BeanChange注解标记的属性变化
+     *
+     * @param oldBean 旧对象
+     * @param newBean 新对象
+     * @return 变化描述字符串
+     */
+    public static <T> String compareBeans(T oldBean, T newBean) {
+        if (oldBean == null || newBean == null) {
+            return "";
+        }
+        if (!oldBean.getClass().equals(newBean.getClass())) {
+            throw new IllegalArgumentException("两个对象类型不一致");
+        }
+        StringBuilder changeLog = new StringBuilder();
+        Class<?> clazz = oldBean.getClass();
+        Field[] fields = clazz.getDeclaredFields();
+
+        // 遍历所有字段
+        for (Field field : fields) {
+            BeanChange annotation = field.getAnnotation(BeanChange.class);
+            if (annotation == null) {
+                continue;
+            }
+            field.setAccessible(true);
+            try {
+                Object oldValue = field.get(oldBean);
+                Object newValue = field.get(newBean);
+
+                // 比较值是否发生变化
+                if (!Objects.equals(oldValue, newValue)) {
+                    String fieldName = annotation.name();
+                    String formattedOldValue = formatValue(oldValue, annotation);
+                    String formattedNewValue = formatValue(newValue, annotation);
+
+                    // 拼接变化描述
+                    if (changeLog.length() > 0) {
+                        changeLog.append(" ");
+                    }
+                    changeLog.append(StrUtil.format("{}由'{}'修改为'{}';", fieldName, formattedOldValue, formattedNewValue));
+                }
+            } catch (IllegalAccessException e) {
+                // 记录访问异常,继续处理其他字段
+                System.err.println("访问字段失败: " + field.getName() + ", 错误: " + e.getMessage());
+            }
+        }
+
+        return changeLog.toString();
+    }
+
+
+    /**
+     * 格式化属性值
+     *
+     * @param value      属性值
+     * @return 格式化后的字符串
+     */
+    private static String formatValue(Object value, BeanChange annotation) {
+        if (value == null) {
+            return "空";
+        }
+        // 处理Date类型
+        if (value instanceof Date && StrUtil.isNotEmpty(annotation.dateFormat())) {
+            try {
+                SimpleDateFormat sdf = new SimpleDateFormat(annotation.dateFormat());
+                return sdf.format((Date) value);
+            } catch (Exception e) {
+                return value.toString(); // 格式化失败返回原始字符串
+            }
+        }
+        if (value instanceof Integer && annotation.ifYesNo()) {
+            switch ((Integer)value) {
+                case 0:
+                    return "否";
+                case 1:
+                    return "是";
+                default:
+                    return value.toString();
+            }
+        }
+        return value.toString();
+    }
+}

+ 7 - 7
yt-middle/middle-platform/src/main/resources/mapper/ApkMapper.xml

@@ -29,8 +29,7 @@
         ya.ditch_name,
         ya.ditch_id,
         u.nick_name
-        FROM
-        yt_app ya
+        FROM yt_app ya
         JOIN yt_platform_user_app pua on ya.superior_id = pua.app_id
         LEFT JOIN yt_app_channel_relative acr ON ya.app_id = acr.app_id
         LEFT JOIN yt_platform_user u ON ya.user_id = u.user_id
@@ -48,9 +47,8 @@
                 and ya.superior_id = #{superiorId}
             </if>
         </where>
-        GROUP BY
-        ya.app_id
-        ORDER BY ya.apk_url
+        GROUP BY ya.app_id
+        ORDER BY ya.create_time desc
     </select>
     <select id="countApk" resultType="java.lang.Integer">
         select
@@ -142,7 +140,8 @@
             ditch_id,
             ditch_name,
             superior_id,
-            enabled
+            enabled,
+            create_time
         )
         values
             (
@@ -168,7 +167,8 @@
                 #{ditchId},
                 #{ditchName},
                 #{superiorId},
-                #{enabled}
+                #{enabled},
+                #{createTime}
             )
     </insert>
     <update id="updateOne">

+ 32 - 2
yt-middle/middle-platform/src/main/resources/mapper/AppMapper.xml

@@ -77,6 +77,10 @@
          #{operateTime}
         );
     </insert>
+    <insert id="insertConfigLog">
+        insert into yt_app_config_log(record_id, app_id, change_content, change_by, change_time)
+        values (#{recordId}, #{appId}, #{changeContent}, #{changeBy}, #{changeTime})
+    </insert>
     <update id="updateById">
         update yt_platform_user_app
         <set>
@@ -189,8 +193,7 @@
                 and pua.app_name like concat('%', #{appName} ,'%')
             </if>
         </where>
-        order by
-        pua.issued_time
+        order by pua.create_time desc
     </select>
     <select id="getByPackName" resultType="com.ytpm.agent.model.YtPlatformUserApp">
         select
@@ -233,4 +236,31 @@
             #{item}
         </foreach>
     </select>
+    <select id="selectLastConfigLog" resultType="com.ytpm.agent.model.YtAppConfigLog">
+        SELECT
+            l.record_id,
+            l.app_id,
+            l.change_content,
+            l.change_by,
+            l.change_time
+        FROM yt_platform.yt_app_config_log l
+                 INNER JOIN (
+            SELECT
+                app_id,
+                MAX(change_time) as max_change_time
+            FROM yt_platform.yt_app_config_log
+            where app_id in
+            <foreach collection="appIds.split(',')" item="item" separator="," open="(" close=")">
+                #{item}
+            </foreach>
+            GROUP BY app_id
+        ) t ON l.app_id = t.app_id AND l.change_time = t.max_change_time;
+    </select>
+    <select id="selectByPrimaryId" resultType="com.ytpm.agent.model.YtApp">
+        select app_id, app_key, app_name, user_id, app_type, apk_url, qr_code, version_code, update_tips, enabled,
+               store_on_sale, store_type, store_url, package_name, domain, category, sub_category, coppa,
+               screen_orientation, ccpa, feign_path, ditch_id, ditch_name, superior_id, revenue_display_rate
+        from yt_app
+        where app_id = #{appId}
+    </select>
 </mapper>

+ 25 - 0
yt-question/yt-question-service/src/main/java/com/ytpm/question/config/interceptor/HttpInterceptor.java

@@ -1,6 +1,9 @@
 package com.ytpm.question.config.interceptor;
 
 import com.ytpm.util.HttpClientUtil;
+import cn.hutool.core.util.StrUtil;
+import com.ytpm.handle.CommonException;
+import com.ytpm.question.redis.RedisService;
 import lombok.NonNull;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Value;
@@ -8,20 +11,29 @@ import org.springframework.stereotype.Component;
 import org.springframework.web.servlet.HandlerInterceptor;
 import org.springframework.web.servlet.ModelAndView;
 
+import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import java.util.Arrays;
 import java.util.Date;
 
 @Slf4j
 @Component
 public class HttpInterceptor implements HandlerInterceptor {
 
+    @Resource
+    private RedisService redisService;
+
     @Value("${spring.application.name-zh:}")
     private String applicationNameZh;
 
+    @Value("${spring.application.name:}")
+    private String applicationName;
+
     @Override
     public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response,
                              @NonNull Object obj) {
+        checkBlackIp(request);
         // 获取客户端IP地址
         String clientIp = HttpClientUtil.getClientIp(request);
         String requestURI = request.getRequestURI();
@@ -29,6 +41,19 @@ public class HttpInterceptor implements HandlerInterceptor {
         return true;
     }
 
+    /**
+     * 黑名单校验
+     */
+    private void checkBlackIp(HttpServletRequest request) {
+        String clientIp = HttpClientUtil.getClientIp(request);
+        String requestURI = request.getRequestURI();
+        String serviceName = StrUtil.replace(applicationName, "-service", "");
+        String str = redisService.getStr(StrUtil.format("blackIps:{}", serviceName));
+        if (StrUtil.isNotEmpty(str) && Arrays.asList(str.split(",")).contains(clientIp)) {
+            log.warn(StrUtil.format("[{}] not allow request:{}", clientIp, requestURI));
+            throw new CommonException("not allow request");
+        }
+    }
 
     /**
      * 请求处理之后调用;在视图渲染之前,controller处理之后。

+ 46 - 0
yt-question/yt-question-service/src/main/java/com/ytpm/question/config/redis/RedisCacheInitializer.java

@@ -0,0 +1,46 @@
+package com.ytpm.question.config.redis;
+
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.ytpm.question.redis.RedisService;
+import com.ytpm.util.ResourceUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.event.ApplicationReadyEvent;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author lih
+ * @date 2025-11-11 14:00
+ */
+@Slf4j
+@Component
+public class RedisCacheInitializer {
+    @Resource
+    private RedisService redisService;
+
+    @Value("${spring.application.name:}")
+    private String applicationName;
+
+    @Value("${spring.config.black-ip.file-name:blackIpList.txt}")
+    private String configFileName;
+
+    @EventListener(ApplicationReadyEvent.class)
+    public void initRedisCache() {
+        try {
+            List<String> strings = ResourceUtils.readFileToList(configFileName);
+            if (CollectionUtils.isNotEmpty(strings)) {
+                String serviceName = StrUtil.replace(applicationName, "-service", "");
+                String cacheKey = StrUtil.format("blackIps:{}", serviceName);
+                redisService.setStr(cacheKey, String.join(",", strings));
+                log.info("已加载IP黑名单:{}", String.join(",", strings));
+            }
+        } catch (IOException ignored) {}
+    }
+}