소스 검색

Merge branch 'refs/heads/master' into lih

# Conflicts:
#	yt-question/yt-question-service/src/main/java/com/ytpm/question/controller/UserController.java
hidewnd 3 주 전
부모
커밋
af23eabd1f
17개의 변경된 파일387개의 추가작업 그리고 100개의 파일을 삭제
  1. 40 2
      ReadMe.md
  2. 28 0
      yt-common/src/main/java/com/ytpm/app/param/DyzAdRecordDelayParam.java
  3. 1 1
      yt-common/src/main/java/com/ytpm/app/view/YtAppUserListView.java
  4. 8 0
      yt-ios-lemon/lemon-ios-feign/src/main/java/com/ytpm/lemonios/feign/feign/warehouseIosFeign.java
  5. 60 24
      yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/controller/UserController.java
  6. 3 6
      yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/controller/WxController.java
  7. 1 1
      yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/service/AppUserService.java
  8. 4 3
      yt-ios-lemon/lemon-ios-service/src/main/java/com/ytpm/lemonios/service/impl/AppUserServiceImpl.java
  9. 7 5
      yt-question/yt-question-service/src/main/java/com/ytpm/question/config/interceptor/HttpInterceptor.java
  10. 11 1
      yt-question/yt-question-service/src/main/java/com/ytpm/question/controller/AdController.java
  11. 55 45
      yt-question/yt-question-service/src/main/java/com/ytpm/question/controller/UserController.java
  12. 2 2
      yt-question/yt-question-service/src/main/java/com/ytpm/question/controller/WxController.java
  13. 4 0
      yt-question/yt-question-service/src/main/java/com/ytpm/question/dao/AdRecordMapper.java
  14. 4 1
      yt-question/yt-question-service/src/main/java/com/ytpm/question/service/AdService.java
  15. 70 9
      yt-question/yt-question-service/src/main/java/com/ytpm/question/service/impl/AdServiceImpl.java
  16. 2 0
      yt-question/yt-question-service/src/main/resources/bootstrap.yml
  17. 87 0
      yt-question/yt-question-service/src/main/resources/mapper/AdRecordMapper.xml

+ 40 - 2
ReadMe.md

@@ -52,25 +52,36 @@
 #### 核心服务
 
 ```shell
-# risk-manager
+# risk-manage
+# 10.206.0.3
+# 10.206.0.8
+# 10.206.0.11
+# 10.206.0.12
 nohup java -jar -Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
 -XX:+UseG1GC -XX:ConcGCThreads=2 -XX:InitiatingHeapOccupancyPercent=35 -XX:G1ReservePercent=10 \
 -XX:MaxGCPauseMillis=300 risk-manage.jar > risk.log 2>&1 &
 
 # yt-middle
+# 10.206.0.3
+# 10.206.0.8
 nohup java -jar -Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
 -XX:+UseG1GC -XX:ConcGCThreads=2 -XX:InitiatingHeapOccupancyPercent=35 \
 -XX:G1ReservePercent=10 -XX:MaxGCPauseMillis=300 yt-middle.jar > middle.log 2>&1 &
 
 # agent-service
+# 10.206.0.3
+# 10.206.0.8
 nohup java -jar -Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
 -XX:+UseG1GC -XX:ConcGCThreads=2 -XX:InitiatingHeapOccupancyPercent=35 -XX:G1ReservePercent=10 \
 -XX:MaxGCPauseMillis=300 agent-service.jar > agent.log 2>&1 &
 
 # gateway
+# 10.206.0.3
+# 10.206.0.8
 nohup java -jar -Xms512m -Xmx1024m yt-gateway.jar > /dev/null 2>&1 &
 
 # oauth
+# 10.206.0.8
 nohup java -Xms512m -Xmx1024m -jar -noverify yt-oauth.jar > oauth.log 2>&1 &
 ```
 
@@ -341,7 +352,7 @@ question-service.jar > adage.log 2>&1 &
 ```shell
 # 答题达人 answer-service
 # 10.206.0.8
-# 10.206.16.15
+# 10.206.16.10
 nohup java -jar -Xms3072m -Xmx3072m -XX:MaxMetaspaceSize=256M -XX:+UseCompressedOops \
 -XX:+UseG1GC -XX:ConcGCThreads=2 -XX:InitiatingHeapOccupancyPercent=35 \
 -XX:G1ReservePercent=10 -XX:MaxGCPauseMillis=300 \
@@ -669,6 +680,8 @@ question-service.jar > palaces.log 2>&1 &
 
 ```shell
 # 极速反应力 reactivity
+# 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 \
@@ -712,6 +725,7 @@ question-service.jar > graphic.log 2>&1 &
 ```shell
 # 色彩大冒险 adventure
 # 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 \
@@ -719,6 +733,20 @@ nohup java -jar -Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=256M -XX:+UseCompressed
 question-service.jar > adventure.log 2>&1 &
 ```
 
+#### 古诗填空秀 poetry
+
+```shell
+# 古诗填空秀 poetry-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-poetry/poetry.hprof \
+question-service.jar > poetry.log 2>&1 &
+
+```
+
 #### 青柠檬ios lemonios
 
 ```shell
@@ -742,7 +770,17 @@ nohup java -jar -Xms2048m -Xmx2048m -XX:MaxMetaspaceSize=256M -XX:+UseCompressed
 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/www/app/ytpm/service-ios-gollum/gollumios.hprof \
 gollumios-service.jar > gollumios.log 2>&1 &
 ```
+#### 盒小仓ios warehouseios
 
+```shell
+# 盒小仓ios warehouseios
+# 10.206.16.10
+nohup java -jar -Xms3072m -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-warehouse/warehouseios.hprof \
+warehouseios-service.jar > warehouseios.log 2>&1 &
+```
 
 
 ## 数据处理

+ 28 - 0
yt-common/src/main/java/com/ytpm/app/param/DyzAdRecordDelayParam.java

@@ -0,0 +1,28 @@
+package com.ytpm.app.param;
+
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author lih
+ * @date 2025-10-14 17:41
+ */
+@Data
+@ApiModel("延迟保存广告记录入参")
+public class DyzAdRecordDelayParam implements Serializable {
+
+    @ApiModelProperty("用户ID")
+    private String userId;
+
+    @ApiModelProperty("登陆前/登陆后")
+    private Integer loginStatus;
+
+    @ApiModelProperty("暂存广告记录")
+    private List<DyzAdRecordParam> adRecords;
+
+}

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

@@ -58,7 +58,7 @@ public class YtAppUserListView extends PageMeta {
     @CustomField(value = "user_status",desc = "用户状态", node = 1)
     @ApiModelProperty("用户状态")
     private Integer userStatus;
-    @ApiModelProperty("日视频播放数")
+    @ApiModelProperty("日视频播放数")
     private Integer todayVideo;
     @ApiModelProperty("视频总播放数")
     private Integer totalVideo;

+ 8 - 0
yt-ios-lemon/lemon-ios-feign/src/main/java/com/ytpm/lemonios/feign/feign/warehouseIosFeign.java

@@ -0,0 +1,8 @@
+package com.ytpm.lemonios.feign.feign;
+
+import com.ytpm.lemonios.feign.base.BaseFeign;
+import org.springframework.cloud.openfeign.FeignClient;
+
+@FeignClient(name = "warehouseios-service")
+public interface warehouseIosFeign extends BaseFeign {
+}

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

@@ -1,7 +1,7 @@
 package com.ytpm.lemonios.controller;
 
 import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.date.DateTime;
 import cn.hutool.core.util.StrUtil;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
@@ -28,6 +28,7 @@ import com.ytpm.lemonios.redis.RedisService;
 import com.ytpm.risk.enums.BannedTypeEnum;
 import com.ytpm.risk.view.RiskConfigView;
 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;
@@ -72,39 +73,74 @@ public class UserController {
         //查询主应用
         PageHelper.startPage(param.getPage(), param.getLimit());
         List<YtAppUserListView> result = appUserMapper.queryAll(param);
-        String collect = result.stream().map(YtAppUserListView::getUserId).collect(Collectors.joining(","));
-        List<YtDyzAdRecord> adRecords = adRecordMapper.getByUserIds(collect);
-        List<YtDyzLoginRecord> dyzLogins = loginRecordMapper.getLoginRecordByIds(collect);
-        Map<String, List<YtDyzAdRecord>> userAdMap = adRecords.stream().collect(
-                Collectors.groupingBy(YtDyzAdRecord::getUserId));
-        Map<String, List<YtDyzLoginRecord>> loginMap = dyzLogins.stream().collect(
-                Collectors.groupingBy(YtDyzLoginRecord::getUserId));
-        setUserExtInfo(result,userAdMap,loginMap);
+        setUserExtInfo(result,param);
         return ResultTable.resultTableOk(new PageInfo<>(result));
     }
 
     /**
-     * 设置视频记录和登录信息
+     * 记录用户额外信息<br>
+     * 1.查询用户过往登陆信息<br>
+     * 2.查询并计算用户当日收益、当日视频播放数、前三日收益<br>
      */
-    private void setUserExtInfo(List<YtAppUserListView> result, Map<String, List<YtDyzAdRecord>> userAdMap,Map<String, List<YtDyzLoginRecord>> loginMap) {
+    private void setUserExtInfo(List<YtAppUserListView> result,YtAppUserListParam param) {
+        String userIds = result.stream().map(YtAppUserListView::getUserId).collect(Collectors.joining(","));
+        List<YtDyzAdRecord> adRecords = adRecordMapper.getByUserIds(userIds);
+        List<YtDyzLoginRecord> dyzLogins = loginRecordMapper.getLoginRecordByIds(userIds);
+        Map<String, List<YtDyzAdRecord>> userAdMap = adRecords.stream()
+                .collect(Collectors.groupingBy(YtDyzAdRecord::getUserId));
+        Map<String, List<YtDyzLoginRecord>> loginMap = dyzLogins.stream()
+                .collect(Collectors.groupingBy(YtDyzLoginRecord::getUserId));
         for (YtAppUserListView user : result) {
-            if(loginMap.containsKey(user.getUserId())){
+            if (loginMap.containsKey(user.getUserId())) {
                 user.setLoginRecordList(loginMap.get(user.getUserId()));
             }
-            //获取今日收益 | 今日视频播放数
-            if (userAdMap.containsKey(user.getUserId())) {
-                List<YtDyzAdRecord> ytDyzAdRecords = userAdMap.get(user.getUserId());
-                List<YtDyzAdRecord> collect = ytDyzAdRecords.stream().filter(
-                        s -> DateUtil.isSameDay(DateUtil.date(),DateUtil.parseDate(s.getFinishTime()))).collect(Collectors.toList());
-                BigDecimal todayIncome = collect.stream().map(YtDyzAdRecord::getRevenue).reduce(BigDecimal.ZERO, BigDecimal::add);
-                user.setTodayVideo((int) collect.stream().filter(
-                        s->s.getAdSourceType()== AdSourceTypeEnum.rewarded_video.getAdSourceType()).count());
-                user.setTodayIncome(todayIncome);
-            } else {
-                user.setTodayIncome(BigDecimal.ZERO);
-                user.setTodayVideo(0);
+            computeTodayIncome(user, userAdMap.get(user.getUserId()), param);
+        }
+    }
+
+    /**
+     * 当日收益、当日视频播放数、前三日收益
+     */
+    private void computeTodayIncome(YtAppUserListView user, List<YtDyzAdRecord> adRecords, YtAppUserListParam param) {
+        //获取当日收益收益 | 当日收益视频播放数 = 统计筛选登陆时间段
+        int todayVideo = 0;
+        BigDecimal todayIncome = BigDecimal.ZERO;
+        DateTime currentDate = DateUtil.date();
+        if (CollUtil.isNotEmpty(adRecords)) {
+            // 默认筛选今日广告记录 并计算前三日收益
+            List<YtDyzAdRecord> ytDyzAdRecords = adRecords.stream()
+                    .filter(s -> DateUtil.isSameDay(currentDate, DateUtil.parseDate(s.getFinishTime())))
+                    .collect(Collectors.toList());
+            todayIncome = ytDyzAdRecords.stream().map(YtDyzAdRecord::getRevenue)
+                    .filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
+            // 统计4天-今日收益=前三日收益
+            if (user.getNearlyIncome() != null && user.getNearlyIncome().compareTo(todayIncome) >= 0) {
+                user.setNearlyIncome(user.getNearlyIncome().subtract(todayIncome));
+            }
+            // 如果传递时间段 则按时间段筛选广告记录
+            if(param.getLastLoginTimeBegin() != null || param.getLastLoginTimeEnd() != null) {
+                ytDyzAdRecords = adRecords;
+                if (param.getLastLoginTimeBegin() != null) {
+                    ytDyzAdRecords = ytDyzAdRecords.stream()
+                            .filter(record -> DateUtil.afterSameDay(
+                                    DateUtil.parseDate(record.getFinishTime()), param.getLastLoginTimeBegin()))
+                            .collect(Collectors.toList());
+                }
+                if (param.getLastLoginTimeEnd() != null) {
+                    ytDyzAdRecords = ytDyzAdRecords.stream()
+                            .filter(record -> DateUtil.beforeSameDay(
+                                    DateUtil.parseDate(record.getFinishTime()), param.getLastLoginTimeEnd()))
+                            .collect(Collectors.toList());
+                }
+                todayIncome = ytDyzAdRecords.stream().map(YtDyzAdRecord::getRevenue)
+                        .filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
             }
+            todayVideo = (int) ytDyzAdRecords.stream()
+                    .filter(record -> record.getAdSourceType() == AdSourceTypeEnum.rewarded_video.getAdSourceType())
+                    .count();
         }
+        user.setTodayVideo(todayVideo);
+        user.setTodayIncome(todayIncome);
     }
 
     /**

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

@@ -115,7 +115,7 @@ public class WxController {
         }
         IosUserInfo userInfo = setIosUserInfo(param);
         param.setLoginIp(getClientIp(request));
-        YtDyzUser old = appUserService.crudForNewTransIos(param, userInfo);
+        YtDyzUser old = appUserService.crudForNewTransIos(param, userInfo, LoginType.IOS.getTypeName());
         //调用风控服务校验默认风控配置
         old.setRiskCode("313");
         Result<?> result = riskFeign.checkRisk(old);
@@ -138,7 +138,7 @@ public class WxController {
         YtDyzUser user = appUserMapper.selectByIosId(param.getIosId());
         if (user == null) {
             IosUserInfo userInfo = setIosUserInfo(param);
-            user = appUserService.crudForNewTransIos(param, userInfo);
+            user = appUserService.crudForNewTransIos(param, userInfo, LoginType.VISITOR.getTypeName());
         }
         //2.拿3条记录 设置到user
         List<YtDyzAdRecord> adRecordList = recordMapper.getByIosIdBeforeLogin(param.getIosId());
@@ -156,10 +156,7 @@ public class WxController {
                 }
             }
         }
-        if (CollUtil.isEmpty(newAdRecordList) || newAdRecordList.size() < 3) {
-            WxDefaultConfig defaultConfig = appUserMapper.getLastDefaultConfig();
-            return Result.resultErr(defaultConfig.getLowValueTip());
-        }
+
         user.setPreAdRecordList(adRecordList);
         user.setLoginType(LoginType.VISITOR);
         user.setAppId(appId);

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

@@ -23,7 +23,7 @@ public interface AppUserService {
     /**
      * 子事务处理用户crud
      */
-    YtDyzUser crudForNewTransIos(IosLoginParam param, IosUserInfo userInfo);
+    YtDyzUser crudForNewTransIos(IosLoginParam param, IosUserInfo userInfo, String loginType);
 
     Result<?> addDefaultConfig(YtDitch param);
 }

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

@@ -83,7 +83,7 @@ public class AppUserServiceImpl implements AppUserService {
     }
 
     @Override
-    public YtDyzUser crudForNewTransIos(IosLoginParam param, IosUserInfo userInfo) {
+    public YtDyzUser crudForNewTransIos(IosLoginParam param, IosUserInfo userInfo, String loginType) {
         YtDyzUser old = appUserMapper.selectByIosId(param.getIosId());
         if(Objects.isNull(old)) {
             old = new YtDyzUser();
@@ -94,7 +94,7 @@ public class AppUserServiceImpl implements AppUserService {
         //设置最后一次答题问题ID、今日答题数、历史答题数
         setExtInfoForIos(old, userInfo.getHeadimgurl());
         // 添加用户登录记录
-        addLoginRecordForIos(param,old.getUserId());
+        addLoginRecordForIos(param,old.getUserId(), loginType);
         return old;
     }
 
@@ -174,7 +174,7 @@ public class AppUserServiceImpl implements AppUserService {
     /**
      * 增加用户登录记录
      */
-    private void addLoginRecordForIos(IosLoginParam param,String userId) {
+    private void addLoginRecordForIos(IosLoginParam param,String userId, String loginType) {
         YtDyzLoginRecord loginRecord = new YtDyzLoginRecord();
         loginRecord.setRecordId(IdUtil.fastSimpleUUID());
         loginRecord.setUserId(userId);
@@ -185,6 +185,7 @@ public class AppUserServiceImpl implements AppUserService {
         loginRecord.setOperator(param.getIpOperator());
         loginRecord.setIpAddr(param.getIpLocation());
         loginRecord.setPhoneJson(param.getPhoneJson());
+        loginRecord.setLoginType(loginType);
         loginRecordMapper.insertOne(loginRecord);
     }
 

+ 7 - 5
yt-question/yt-question-service/src/main/java/com/ytpm/question/config/interceptor/HttpInterceptor.java

@@ -1,5 +1,6 @@
 package com.ytpm.question.config.interceptor;
 
+import lombok.NonNull;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
@@ -18,11 +19,12 @@ public class HttpInterceptor implements HandlerInterceptor {
     private String applicationNameZh;
 
     @Override
-    public boolean preHandle(HttpServletRequest request,
-                             HttpServletResponse response, Object obj) throws Exception {
+    public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response,
+                             @NonNull Object obj) {
         // 获取客户端IP地址
         String clientIp = getClientIp(request);
-        log.info("{}收到来自客户端[{}]的用户请求", applicationNameZh, clientIp);
+        String requestURI = request.getRequestURI();
+        log.info("{}收到来自客户端[{}]的用户请求:{}", applicationNameZh, clientIp, requestURI);
         return true;
     }
 
@@ -38,8 +40,8 @@ public class HttpInterceptor implements HandlerInterceptor {
      * 请求处理之后调用;在视图渲染之前,controller处理之后。
      */
     @Override
-    public void postHandle(HttpServletRequest request,
-                           HttpServletResponse response, Object obj, ModelAndView mv)
+    public void postHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response,
+                           @NonNull Object obj, ModelAndView mv)
             throws Exception {
         response.setDateHeader("Expires", 0);
         response.setHeader("Buffer", "True");

+ 11 - 1
yt-question/yt-question-service/src/main/java/com/ytpm/question/controller/AdController.java

@@ -2,6 +2,7 @@ package com.ytpm.question.controller;
 
 import com.ytpm.agent.view.AgentAdGroupStaticsVO;
 import com.ytpm.agent.view.AgentTopCountView;
+import com.ytpm.app.param.DyzAdRecordDelayParam;
 import com.ytpm.app.param.DyzAdRecordParam;
 import com.ytpm.general.Result;
 import com.ytpm.middle.view.DashboardRankingListVO;
@@ -38,10 +39,19 @@ public class AdController {
      */
     @ApiOperation("保存")
     @PostMapping("/saveRecord")
-    public Result<?> saveRecord(@RequestBody DyzAdRecordParam param) {
+    public Result<String> saveRecord(@RequestBody DyzAdRecordParam param) {
         return adService.saveRecord(param);
     }
 
+    /**
+     * 保存广告记录
+     */
+    @ApiOperation("延迟保存广告记录")
+    @PostMapping("/saveRecord/delay")
+    public Result<String> delaySaveRecord(@RequestBody DyzAdRecordDelayParam param) {
+        return adService.delaySaveRecord(param);
+    }
+
     /**
      * 根据应用ID查询广告数
      */

+ 55 - 45
yt-question/yt-question-service/src/main/java/com/ytpm/question/controller/UserController.java

@@ -108,64 +108,74 @@ public class UserController {
         //查询主应用
         PageHelper.startPage(param.getPage(), param.getLimit());
         List<YtAppUserListView> result = appUserMapper.queryAll(param);
-        String collect = result.stream().map(YtAppUserListView::getUserId).collect(Collectors.joining(","));
-        List<YtDyzAdRecord> adRecords = adRecordMapper.getByUserIds(collect);
-        List<YtDyzLoginRecord> dyzLogins = loginRecordMapper.getLoginRecordByIds(collect);
-        Map<String, List<YtDyzAdRecord>> userAdMap = adRecords.stream().collect(
-                Collectors.groupingBy(YtDyzAdRecord::getUserId));
-        Map<String, List<YtDyzLoginRecord>> loginMap = dyzLogins.stream().collect(
-                Collectors.groupingBy(YtDyzLoginRecord::getUserId));
-        setUserExtInfo(result,param, userAdMap, loginMap);
+        setUserExtInfo(result, param);
         return ResultTable.resultTableOk(new PageInfo<>(result));
     }
 
     /**
-     * 设置视频记录和登录信息
+     * 记录用户额外信息<br>
+     * 1.查询用户过往登陆信息<br>
+     * 2.查询并计算用户当日收益、当日视频播放数、前三日收益<br>
      */
-    private void setUserExtInfo(List<YtAppUserListView> result,YtAppUserListParam param,
-                                Map<String, List<YtDyzAdRecord>> userAdMap, Map<String, List<YtDyzLoginRecord>> loginMap) {
-        List<YtDyzAdRecord> ytDyzAdRecords;
-        DateTime currentDate = DateUtil.date();
+    private void setUserExtInfo(List<YtAppUserListView> result,YtAppUserListParam param) {
+        String userIds = result.stream().map(YtAppUserListView::getUserId).collect(Collectors.joining(","));
+        List<YtDyzAdRecord> adRecords = adRecordMapper.getByUserIds(userIds);
+        List<YtDyzLoginRecord> dyzLogins = loginRecordMapper.getLoginRecordByIds(userIds);
+        Map<String, List<YtDyzAdRecord>> userAdMap = adRecords.stream()
+                .collect(Collectors.groupingBy(YtDyzAdRecord::getUserId));
+        Map<String, List<YtDyzLoginRecord>> loginMap = dyzLogins.stream()
+                .collect(Collectors.groupingBy(YtDyzLoginRecord::getUserId));
         for (YtAppUserListView user : result) {
             if (loginMap.containsKey(user.getUserId())) {
                 user.setLoginRecordList(loginMap.get(user.getUserId()));
             }
-            //获取当日收益收益 | 当日收益视频播放数 = 统计筛选登陆时间段
-            int todayVideo = 0;
-            BigDecimal todayIncome = BigDecimal.ZERO;
-            if (userAdMap.containsKey(user.getUserId())) {
-                // 默认筛选今日广告记录 并计算前三日收益
-                ytDyzAdRecords = userAdMap.get(user.getUserId()).stream()
-                        .filter(s -> DateUtil.isSameDay(currentDate, DateUtil.parseDate(s.getFinishTime())))
-                        .collect(Collectors.toList());
-                todayIncome = ytDyzAdRecords.stream().map(YtDyzAdRecord::getRevenue).reduce(BigDecimal.ZERO, BigDecimal::add);
-                // 统计4天-今日收益=前三日收益
-                if (user.getNearlyIncome() != null && user.getNearlyIncome().compareTo(todayIncome) >= 0) {
-                    user.setNearlyIncome(user.getNearlyIncome().subtract(todayIncome));
+            computeTodayIncome(user, userAdMap.get(user.getUserId()), param);
+        }
+    }
+
+    /**
+     * 当日收益、当日视频播放数、前三日收益
+     */
+    private void computeTodayIncome(YtAppUserListView user, List<YtDyzAdRecord> adRecords, YtAppUserListParam param) {
+        //获取当日收益收益 | 当日收益视频播放数 = 统计筛选登陆时间段
+        int todayVideo = 0;
+        BigDecimal todayIncome = BigDecimal.ZERO;
+        DateTime currentDate = DateUtil.date();
+        if (CollUtil.isNotEmpty(adRecords)) {
+            // 默认筛选今日广告记录 并计算前三日收益
+            List<YtDyzAdRecord> ytDyzAdRecords = adRecords.stream()
+                    .filter(s -> DateUtil.isSameDay(currentDate, DateUtil.parseDate(s.getFinishTime())))
+                    .collect(Collectors.toList());
+            todayIncome = ytDyzAdRecords.stream().map(YtDyzAdRecord::getRevenue)
+                    .filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
+            // 统计4天-今日收益=前三日收益
+            if (user.getNearlyIncome() != null && user.getNearlyIncome().compareTo(todayIncome) >= 0) {
+                user.setNearlyIncome(user.getNearlyIncome().subtract(todayIncome));
+            }
+            // 如果传递时间段 则按时间段筛选广告记录
+            if(param.getLastLoginTimeBegin() != null || param.getLastLoginTimeEnd() != null) {
+                ytDyzAdRecords = adRecords;
+                if (param.getLastLoginTimeBegin() != null) {
+                    ytDyzAdRecords = ytDyzAdRecords.stream()
+                            .filter(record -> DateUtil.afterSameDay(
+                                    DateUtil.parseDate(record.getFinishTime()), param.getLastLoginTimeBegin()))
+                            .collect(Collectors.toList());
                 }
-                // 如果传递时间段 则按时间段筛选广告记录
-                if(param.getLastLoginTimeBegin() != null || param.getLastLoginTimeEnd() != null) {
-                    if (param.getLastLoginTimeEnd() != null) {
-                        ytDyzAdRecords = userAdMap.get(user.getUserId()).stream()
-                                .filter(record -> DateUtil.afterSameDay(
-                                        param.getLastLoginTimeEnd(), DateUtil.parseDate(record.getFinishTime())))
-                                .collect(Collectors.toList());
-                    }
-                    if (param.getLastLoginTimeEnd() != null) {
-                        ytDyzAdRecords = ytDyzAdRecords.stream()
-                                .filter(record -> DateUtil.beforeSameDay(
-                                        param.getLastLoginTimeEnd(), DateUtil.parseDate(record.getFinishTime())))
-                                .collect(Collectors.toList());
-                    }
-                    todayIncome = ytDyzAdRecords.stream().map(YtDyzAdRecord::getRevenue).reduce(BigDecimal.ZERO, BigDecimal::add);
+                if (param.getLastLoginTimeEnd() != null) {
+                    ytDyzAdRecords = ytDyzAdRecords.stream()
+                            .filter(record -> DateUtil.beforeSameDay(
+                                    DateUtil.parseDate(record.getFinishTime()), param.getLastLoginTimeEnd()))
+                            .collect(Collectors.toList());
                 }
-                todayVideo = (int) ytDyzAdRecords.stream()
-                        .filter(record -> record.getAdSourceType() == AdSourceTypeEnum.rewarded_video.getAdSourceType())
-                        .count();
+                todayIncome = ytDyzAdRecords.stream().map(YtDyzAdRecord::getRevenue)
+                        .filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
             }
-            user.setTodayVideo(todayVideo);
-            user.setTodayIncome(todayIncome);
+            todayVideo = (int) ytDyzAdRecords.stream()
+                    .filter(record -> record.getAdSourceType() == AdSourceTypeEnum.rewarded_video.getAdSourceType())
+                    .count();
         }
+        user.setTodayVideo(todayVideo);
+        user.setTodayIncome(todayIncome);
     }
 
     /**

+ 2 - 2
yt-question/yt-question-service/src/main/java/com/ytpm/question/controller/WxController.java

@@ -113,7 +113,7 @@ public class WxController {
         String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openid + "&lang=zh_CN";
         String curUser = HttpUtil.get(userInfoUrl);
         WxUserInfo wxUserInfo = JSON.parseObject(curUser, WxUserInfo.class);
-        log.error("获取的用户信息:{}", wxUserInfo);
+        log.info("[wx Login]获取的用户信息:{}", wxUserInfo);
         return wxUserInfo;
     }
 
@@ -133,7 +133,7 @@ public class WxController {
         //拿到授权码 请求微信登录返回access_token
         String result = HttpUtil.get(wxLoginUrl);
         WxLoginResult loginResult = JSON.parseObject(result, WxLoginResult.class);
-        log.error("授权码获取的登录结果:{}", loginResult);
+        log.info("[wx Login]授权码获取的登录结果:{}", loginResult);
         return loginResult;
     }
 

+ 4 - 0
yt-question/yt-question-service/src/main/java/com/ytpm/question/dao/AdRecordMapper.java

@@ -19,11 +19,15 @@ public interface AdRecordMapper {
      */
     void addOne(YtDyzAdRecord adRecord);
 
+    void batchAdd(@Param("adRecords") List<YtDyzAdRecord> adRecords);
+
     /**
      * 保存游客广告记录
      */
     void addOneVisitor(YtDyzAdRecord adRecord);
 
+    void batchAddVisitor(@Param("adRecords") List<YtDyzAdRecord> adRecords);
+
     /**
      * 查询用户的广告记录
      */

+ 4 - 1
yt-question/yt-question-service/src/main/java/com/ytpm/question/service/AdService.java

@@ -4,6 +4,7 @@ import com.ytpm.agent.view.AgentAdGroupStaticsVO;
 import com.ytpm.agent.view.AgentTopCountView;
 import com.ytpm.app.model.YtDyzAdRecord;
 import com.ytpm.app.model.YtDyzUser;
+import com.ytpm.app.param.DyzAdRecordDelayParam;
 import com.ytpm.app.param.DyzAdRecordParam;
 import com.ytpm.general.Result;
 import com.ytpm.middle.view.DashboardRankingListVO;
@@ -18,7 +19,9 @@ public interface AdService {
     /**
      * 保存广告记录
      */
-    Result<?> saveRecord(DyzAdRecordParam param);
+    Result<String> saveRecord(DyzAdRecordParam param);
+
+    Result<String> delaySaveRecord(DyzAdRecordDelayParam param);
 
     /**
      * 根据应用查询广告数量

+ 70 - 9
yt-question/yt-question-service/src/main/java/com/ytpm/question/service/impl/AdServiceImpl.java

@@ -1,5 +1,7 @@
 package com.ytpm.question.service.impl;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.RandomUtil;
 import cn.hutool.core.util.StrUtil;
@@ -11,6 +13,7 @@ import com.ytpm.agent.view.AgentAdGroupStaticsVO;
 import com.ytpm.agent.view.AgentTopCountView;
 import com.ytpm.app.model.YtDyzAdRecord;
 import com.ytpm.app.model.YtDyzUser;
+import com.ytpm.app.param.DyzAdRecordDelayParam;
 import com.ytpm.app.param.DyzAdRecordParam;
 import com.ytpm.app.view.WxDefaultConfig;
 import com.ytpm.feign.RiskFeign;
@@ -70,15 +73,15 @@ public class AdServiceImpl implements AdService {
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public Result<?> saveRecord(DyzAdRecordParam param) {
+    public Result<String> saveRecord(DyzAdRecordParam param) {
         YtDyzUser user = appUserMapper.selectPrimaryKey(param.getUserId());
-        log.debug(StrUtil.format("[saveRecord] userId:{} revenue:{} ", param.getUserId(), param.getRevenue()));
         if (Objects.isNull(user)) {
             return Result.resultOk(RepMessage.SAVE_SUCCESS);
         }
         if (!UserStatusEnum.NORMAL.getCode().equals(user.getUserStatus())) {
             return new Result<>(StatusCode.ACCESS_ERR, getTipsMsg());
         }
+        log.debug(StrUtil.format("[saveRecord] userId:{} revenue:{} ", param.getUserId(), param.getRevenue()));
         saveRecordAndChangeUser(param, user);
         //调用风控广告校验
         if (AdSourceTypeEnum.rewarded_video.getAdSourceType() == param.getAdSourceType()) {
@@ -87,7 +90,7 @@ public class AdServiceImpl implements AdService {
             user.setPowerLimitTip(format);
             Result<?> result = riskFeign.checkAdRisk(user);
             if (result.getCode() != 200) {
-                Result<Object> resultObj = new Result<>(StatusCode.ACCESS_ERR, getTipsMsg());
+                Result<String> resultObj = new Result<>(StatusCode.ACCESS_ERR, getTipsMsg());
                 // 766处理
                 if ("766".contains(result.getMessage())) {
                     resultObj.setData(result.getMessage());
@@ -107,6 +110,69 @@ public class AdServiceImpl implements AdService {
         return split[RandomUtil.randomInt(split.length)];
     }
 
+
+
+    @Override
+    public Result<String> delaySaveRecord(DyzAdRecordDelayParam param) {
+        YtDyzUser user = appUserMapper.selectPrimaryKey(param.getUserId());
+        if (Objects.isNull(user)) {
+            return Result.resultOk(RepMessage.SAVE_SUCCESS);
+        }
+        if (!UserStatusEnum.NORMAL.getCode().equals(user.getUserStatus())) {
+            return new Result<>(StatusCode.ACCESS_ERR, getTipsMsg());
+        }
+        log.info("[delaySaveRecord] userId:{}", param.getUserId());
+        if (CollectionUtil.isNotEmpty(param.getAdRecords())) {
+            YtDyzAdRecord insertEntity;
+            List<YtDyzAdRecord> saveList = new ArrayList<>();
+            BigDecimal totalRevenue = BigDecimal.ZERO;
+            for (DyzAdRecordParam adParam : param.getAdRecords()) {
+                handleTimeNull(adParam);
+                insertEntity = new YtDyzAdRecord();
+                BeanUtils.copyProperties(adParam, insertEntity);
+                insertEntity.setRecordId(IdUtil.fastSimpleUUID());
+                insertEntity.setUserId(user.getUserId());
+                insertEntity.setNetworkName(AdPlatformTypeEnum.getDesc(Integer.parseInt(adParam.getNetworkFormId())));
+                saveList.add(insertEntity);
+                if (AdRecordEnum.LOGIN_BEFORE.getCode().equals(param.getLoginStatus())
+                        && AdSourceTypeEnum.rewarded_video.getAdSourceType() == adParam.getAdSourceType()) {
+                    continue;
+                }
+                if (insertEntity.getRevenue() != null) {
+                    totalRevenue = totalRevenue.add(insertEntity.getRevenue());
+                }
+            }
+            if (CollUtil.isNotEmpty(saveList)) {
+                if (param.getLoginStatus() != null && AdRecordEnum.LOGIN_BEFORE.getCode().equals(param.getLoginStatus())) {
+                    adRecordMapper.batchAddVisitor(saveList);
+                } else {
+                    adRecordMapper.batchAdd(saveList);
+                }
+            }
+            appUserMapper.updateTotal(user.getUserId(), saveList.size(), totalRevenue);
+        }
+        return Result.resultOk(RepMessage.SAVE_SUCCESS);
+    }
+
+    /**
+     * 处理传入广告记录 beginTime FinishTime可能为null的情况
+     */
+    private void handleTimeNull(DyzAdRecordParam param) {
+        param.setFinishTime(verifyTimeParam("finishTime", param.getFinishTime(), null));
+        param.setBeginTime(verifyTimeParam("beginTime", param.getBeginTime(), param.getFinishTime()));
+    }
+
+    private String verifyTimeParam(String fieldName, String value, String defaultValue) {
+        if (Objects.isNull(value) || "null".equals(value)) {
+            if ("null".equals(value)) {
+                log.warn("param[{}] value '{}' is null !", fieldName, value);
+            }
+            return StrUtil.isEmpty(defaultValue) ? DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss") : defaultValue;
+        }
+        return value;
+    }
+
+
     /**
      * 根据应用查询广告数量
      */
@@ -298,13 +364,8 @@ public class AdServiceImpl implements AdService {
 //    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
     public String saveRecordAndChangeUser(DyzAdRecordParam param, YtDyzUser user) {
         //增加广告记录
+        handleTimeNull(param);
         YtDyzAdRecord adRecord = new YtDyzAdRecord();
-        if (Objects.isNull(param.getBeginTime()) || "null".equals(param.getBeginTime())) {
-            if ("null".equals(param.getBeginTime())) {
-                log.warn("param beginTime is null !");
-            }
-            param.setBeginTime(param.getFinishTime());
-        }
         BeanUtils.copyProperties(param, adRecord);
         adRecord.setRecordId(IdUtil.fastSimpleUUID());
         adRecord.setNetworkName(AdPlatformTypeEnum.getDesc(Integer.parseInt(param.getNetworkFormId())));

+ 2 - 0
yt-question/yt-question-service/src/main/resources/bootstrap.yml

@@ -66,6 +66,8 @@ spring:
     #name-zh: '图形逻辑王'
     #name: adventure-service
     #name-zh: '色彩大冒险'
+    #name: poetry-service
+    #name-zh: '古诗填空秀'
   profiles:
     # 当前为本地模式
     active: local

+ 87 - 0
yt-question/yt-question-service/src/main/resources/mapper/AdRecordMapper.xml

@@ -42,6 +42,49 @@
                 #{appId}
             )
     </insert>
+
+    <insert id="batchAdd">
+        insert into yt_dyz_ad_record
+        (
+            record_id,
+            user_id,
+            nick_name,
+            placement_id,
+            ad_source_id,
+            revenue,
+            network_form_id,
+            network_name,
+            network_placement_id,
+            begin_time,
+            finish_time,
+            result_json,
+            ad_source_index,
+            ad_source_type,
+            ecpm,
+            app_id
+        )
+        values
+        <foreach collection="adRecords" item="item" separator=",">
+            (
+            #{item.recordId},
+            #{item.userId},
+            #{item.nickName},
+            #{item.placementId},
+            #{item.adSourceId},
+            #{item.revenue},
+            #{item.networkFormId},
+            #{item.networkName},
+            #{item.networkPlacementId},
+            ifnull(#{item.beginTime}, now()),
+            ifnull(#{item.finishTime}, now()),
+            #{item.resultJson},
+            #{item.adSourceIndex},
+            #{item.adSourceType},
+            #{item.ecpm},
+            #{item.appId}
+            )
+        </foreach>
+    </insert>
     <insert id="addOneVisitor">
         insert into yt_dyz_ad_record_visitor
         (
@@ -82,6 +125,50 @@
                 #{appId}
             )
     </insert>
+    <insert id="batchAddVisitor">
+        insert into yt_dyz_ad_record_visitor
+        (
+            record_id,
+            user_id,
+            nick_name,
+            placement_id,
+            ad_source_id,
+            revenue,
+            network_form_id,
+            network_name,
+            network_placement_id,
+            begin_time,
+            finish_time,
+            result_json,
+            ad_source_index,
+            ad_source_type,
+            ecpm,
+            app_id
+        )
+        values
+        <foreach collection="adRecords" item="item" separator=",">
+            (
+            #{item.recordId},
+            #{item.userId},
+            #{item.nickName},
+            #{item.placementId},
+            #{item.adSourceId},
+            #{item.revenue},
+            #{item.networkFormId},
+            #{item.networkName},
+            #{item.networkPlacementId},
+            ifnull(#{item.beginTime}, now()),
+            ifnull(#{item.finishTime}, now()),
+            #{item.resultJson},
+            #{item.adSourceIndex},
+            #{item.adSourceType},
+            #{item.ecpm},
+            #{item.appId}
+            )
+        </foreach>
+
+    </insert>
+
     <select id="countByAppIds" resultType="java.lang.Integer">
         select
         count(record_id)