Pārlūkot izejas kodu

Merge branch 'package' of GameCenter/game-center into dev

zhimo 1 gadu atpakaļ
vecāks
revīzija
e0db761e0d
57 mainītis faili ar 2402 papildinājumiem un 450 dzēšanām
  1. 14 0
      game-data/game-data-serve/pom.xml
  2. 18 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/annotation/Log.java
  3. 74 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/aspectj/LogAspect.java
  4. 26 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/config/CheckConfig.java
  5. 43 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/config/KafkaConfig.java
  6. 36 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/config/ThreadPoolConfig.java
  7. 3 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/AdsPromotionDayController.java
  8. 14 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/GameMonitorAlarmController.java
  9. 2 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/RoleManageController.java
  10. 50 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/intercept/WebVisitLogIntercept.java
  11. 56 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/mangae/AsyncManager.java
  12. 35 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/mangae/factory/AsyncFactory.java
  13. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/GSGameServerDayDTO.java
  14. 1 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/GameDataDayTotalDTO.java
  15. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/GameDataTotalDTO.java
  16. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/GameDataWaterDTO.java
  17. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/OverallSummaryDTO.java
  18. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/PlayerDataListDTO.java
  19. 14 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/RoleRechargeRankingDTO.java
  20. 29 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/WebLogDTO.java
  21. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/entity/AdsAgentDayAgain.java
  22. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/entity/AdsEverydayWater.java
  23. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/entity/AdsGameDay.java
  24. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/entity/AdsGameDayAgain.java
  25. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/entity/AdsGameDayAgainNature.java
  26. 0 3
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/entity/AdsPitcherGameDayn.java
  27. 23 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/properties/SmsProperties.java
  28. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/FirstNewUserAgainTrendVO.java
  29. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/FlowMonitorVO.java
  30. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GSGameServerDayVO.java
  31. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameDataDayVO.java
  32. 0 2
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameDataH5VO.java
  33. 0 3
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameDataWaterVO.java
  34. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameMonitorAlarmVO.java
  35. 0 3
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GamePromoteDayTotalVO.java
  36. 0 3
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GamePromoteDayVO.java
  37. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GamePromoteTotalVO.java
  38. 0 2
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameRechargeRankingVO.java
  39. 0 2
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/PlayerRechargeRankingVO.java
  40. 3 3
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/RechargeTrendVO.java
  41. 22 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/IOrderCostMonitorAlarmService.java
  42. 7 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/IWebVisitLogService.java
  43. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/AccountListServiceImpl.java
  44. 0 2
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/AgentListServiceImpl.java
  45. 639 227
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GameDataServiceImpl.java
  46. 12 3
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GameMonitorAlarmServiceImpl.java
  47. 50 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/IWebVisitLogServiceImpl.java
  48. 187 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/OrderCostMonitorAlarmBySmsServiceImpl.java
  49. 464 164
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/RoleManageServiceImpl.java
  50. 5 4
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/task/GameMonitorAlarmTask.java
  51. 55 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/task/OrderCostMonitorAlarmTask.java
  52. 272 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/utils/RedisUtil.java
  53. 134 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/utils/SpringUtils.java
  54. 74 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/utils/Threads.java
  55. 1 1
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/ManageApplication.java
  56. 29 10
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/CpSendMsgLogServiceImpl.java
  57. 10 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/GameSupper.java

+ 14 - 0
game-data/game-data-serve/pom.xml

@@ -133,6 +133,20 @@
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
         </dependency>
+
+        <!--sms集成-->
+        <dependency>
+            <groupId>com.zanxiang.module</groupId>
+            <artifactId>zx-sms</artifactId>
+        </dependency>
+
+        <!-- kafka -->
+        <dependency>
+            <groupId>org.apache.kafka</groupId>
+            <artifactId>kafka-clients</artifactId>
+            <version>2.2.1</version>
+        </dependency>
+
     </dependencies>
 
     <build>

+ 18 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/annotation/Log.java

@@ -0,0 +1,18 @@
+package com.zanxiang.game.data.serve.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 自定义访问界面日志记录注解
+ */
+@Target({ ElementType.PARAMETER, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Log
+{
+    /**
+     * 标题
+     */
+    String title() default "";
+
+}

+ 74 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/aspectj/LogAspect.java

@@ -0,0 +1,74 @@
+package com.zanxiang.game.data.serve.aspectj;
+
+
+import com.zanxiang.erp.security.util.SecurityUtil;
+import com.zanxiang.game.data.serve.annotation.Log;
+import com.zanxiang.game.data.serve.mangae.AsyncManager;
+import com.zanxiang.game.data.serve.mangae.factory.AsyncFactory;
+import com.zanxiang.game.data.serve.pojo.dto.WebLogDTO;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Aspect;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * 日志切面
+ */
+@Aspect
+@Component
+public class LogAspect {
+    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
+
+    /**
+     * 处理完请求后执行
+     *
+     * @param joinPoint 切点
+     */
+    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
+    public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
+        handleLog(joinPoint, controllerLog, null, jsonResult);
+    }
+
+    /**
+     * 拦截异常操作
+     *
+     * @param joinPoint 切点
+     * @param e         异常
+     */
+    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
+    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
+        handleLog(joinPoint, controllerLog, e, null);
+    }
+
+    protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
+        try {
+            System.out.println("写入日志");
+
+            //获取当前用户id
+            Long sysUserId = SecurityUtil.getUserId();
+            //标题名称
+            WebLogDTO webLogDTO = new WebLogDTO();
+            webLogDTO.setTitle(controllerLog.title());
+            if(sysUserId!=null){
+                webLogDTO.setUserId(sysUserId.toString());
+            }
+            LocalDateTime now = LocalDateTime.now();
+            String dateTime = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+            webLogDTO.setVisitTime(dateTime);
+            // 发到kafka
+            AsyncManager.me().execute(AsyncFactory.webVisitLog(webLogDTO));
+        } catch (Exception exp) {
+            // 记录日志
+            log.error("==前置通知异常==");
+            log.error("异常信息:{}", exp.getMessage());
+            exp.printStackTrace();
+        }
+    }
+
+}

+ 26 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/config/CheckConfig.java

@@ -0,0 +1,26 @@
+package com.zanxiang.game.data.serve.config;
+
+import com.aliyun.tea.interceptor.RequestInterceptor;
+import com.zanxiang.game.data.serve.intercept.WebVisitLogIntercept;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class CheckConfig implements WebMvcConfigurer {
+
+    @Bean
+    public WebVisitLogIntercept getRequestInterceptor(){
+        return  new WebVisitLogIntercept();
+    }
+
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+
+        registry.addInterceptor(getRequestInterceptor())
+                .addPathPatterns("/**")
+                .excludePathPatterns("/swagger-ui.html/**");
+    }
+}

+ 43 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/config/KafkaConfig.java

@@ -0,0 +1,43 @@
+package com.zanxiang.game.data.serve.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.kafka.clients.producer.KafkaProducer;
+import org.apache.kafka.clients.producer.Producer;
+import org.apache.kafka.clients.producer.ProducerConfig;
+import org.apache.kafka.common.serialization.StringSerializer;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.net.InetAddress;
+import java.util.Properties;
+
+/**
+ * kafka配置
+ */
+@Slf4j
+@Configuration
+public class KafkaConfig {
+
+    @Value("${spring.kafka.game-data.bootstrap-servers}")
+    private String gameSdkKafkaSevers;
+
+    @Bean("gameDataKafkaProducer")
+    public Producer<String, String> gameKafkaProducer() {
+
+        String clientId = "UNKNOWN";
+        try {
+            clientId = InetAddress.getLocalHost().getHostAddress();
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+        Properties props = new Properties();
+        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, gameSdkKafkaSevers);
+        props.put(ProducerConfig.CLIENT_ID_CONFIG, clientId);
+        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+        return new KafkaProducer<>(props);
+    }
+
+
+}

+ 36 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/config/ThreadPoolConfig.java

@@ -0,0 +1,36 @@
+package com.zanxiang.game.data.serve.config;
+
+import com.zanxiang.game.data.serve.utils.Threads;
+import org.apache.commons.lang3.concurrent.BasicThreadFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * 线程池配置
+ **/
+@Configuration
+public class ThreadPoolConfig {
+    // 核心线程池大小
+    private final int corePoolSize = 10;
+
+
+    /**
+     * 执行周期性或定时任务
+     */
+    @Bean(name = "scheduledExecutorService")
+    protected ScheduledExecutorService scheduledExecutorService() {
+        return new ScheduledThreadPoolExecutor(corePoolSize,
+                new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
+                new ThreadPoolExecutor.CallerRunsPolicy()) {
+            @Override
+            protected void afterExecute(Runnable r, Throwable t) {
+                super.afterExecute(r, t);
+                Threads.printException(r, t);
+            }
+        };
+    }
+}

+ 3 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/AdsPromotionDayController.java

@@ -1,6 +1,7 @@
 package com.zanxiang.game.data.serve.controller;
 
 import com.zanxiang.erp.security.annotation.PreAuthorize;
+import com.zanxiang.game.data.serve.annotation.Log;
 import com.zanxiang.game.data.serve.pojo.dto.PromotionDayDTO;
 import com.zanxiang.game.data.serve.pojo.dto.PromotionDayTotalDTO;
 import com.zanxiang.game.data.serve.pojo.dto.TencentPromotionDayDTO;
@@ -35,6 +36,7 @@ public class AdsPromotionDayController {
     @Autowired
     private IAdsPromotionDayService adsPromotionDayService;
 
+//    @Log(title = "头条广告监控")
     @ApiOperation(value = "广告监控数据")
     @PreAuthorize(permissionKey = "promotionData:adsPromotionDay:day")
     @PostMapping("/day")
@@ -63,6 +65,7 @@ public class AdsPromotionDayController {
         return ResultVO.ok(adsPromotionDayService.getPromotionDayTotalData(dto));
     }
 
+//    @Log(title = "腾讯广告监控")
     @ApiOperation(value = "腾讯广告监控数据")
     @PreAuthorize(permissionKey = "promotionData:adsAdGroupDay:day")
     @PostMapping("/tencent/day")

+ 14 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/GameMonitorAlarmController.java

@@ -1,6 +1,7 @@
 package com.zanxiang.game.data.serve.controller;
 
 import com.zanxiang.game.data.serve.service.IGameMonitorAlarmService;
+import com.zanxiang.game.data.serve.service.IOrderCostMonitorAlarmService;
 import com.zanxiang.module.util.pojo.ResultVO;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -9,6 +10,8 @@ import org.springframework.web.bind.annotation.PutMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import javax.annotation.Resource;
+
 /**
  * @author tianhua
  * @version 1.0
@@ -22,6 +25,8 @@ public class GameMonitorAlarmController {
 
     @Autowired
     private IGameMonitorAlarmService gameMonitorAlarmService;
+    @Resource
+    private IOrderCostMonitorAlarmService orderCostMonitorAlarmService;
 
     @ApiOperation(value = "发送钉钉消息")
     @PutMapping("/sendMsg")
@@ -29,4 +34,13 @@ public class GameMonitorAlarmController {
         return ResultVO.ok(gameMonitorAlarmService.sendMsgToUser());
     }
 
+
+    @ApiOperation(value = "监控")
+    @PutMapping("/monitor")
+    public ResultVO<Boolean> monitor() {
+        orderCostMonitorAlarmService.testSendSms("测试短信");
+//        orderCostMonitorAlarmService.monitorTencentCostStatus();
+//        orderCostMonitorAlarmService.monitorDataStatus();
+        return ResultVO.ok();
+    }
 }

+ 2 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/RoleManageController.java

@@ -1,5 +1,6 @@
 package com.zanxiang.game.data.serve.controller;
 
+import com.zanxiang.game.data.serve.annotation.Log;
 import com.zanxiang.game.data.serve.pojo.dto.*;
 import com.zanxiang.game.module.base.pojo.vo.SendMsgResultVO;
 import com.zanxiang.game.module.base.pojo.vo.SendMsgVO;
@@ -30,6 +31,7 @@ public class RoleManageController {
     @Autowired
     private IRoleManageService roleManageService;
 
+//    @Log(title = "角色充值排行榜")
     @ApiOperation(value = "角色充值排行榜")
     @PreAuthorize(permissionKey = "roleManage:recharge:role")
     @PostMapping("/rechargeRanking")

+ 50 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/intercept/WebVisitLogIntercept.java

@@ -0,0 +1,50 @@
+package com.zanxiang.game.data.serve.intercept;
+
+import com.zanxiang.erp.security.util.SecurityUtil;
+import com.zanxiang.game.data.serve.mangae.AsyncManager;
+import com.zanxiang.game.data.serve.mangae.factory.AsyncFactory;
+import com.zanxiang.game.data.serve.pojo.dto.WebLogDTO;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * packageName com.zanxiang.game.data.serve.intercept
+ *
+ * @author ZhangXianyu
+ * @date 2024/3/22
+ * @description 接口请求日志记录拦截器
+ */
+@Component
+public class WebVisitLogIntercept implements HandlerInterceptor {
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        //获取当前请求的URL
+        String url = request.getRequestURI().toString();
+        //获取当前用户id
+        Long sysUserId = SecurityUtil.getUserId();
+        //标题名称
+        WebLogDTO webLogDTO = new WebLogDTO();
+        webLogDTO.setTitle(url);
+        if(sysUserId!=null){
+            webLogDTO.setUserId(sysUserId.toString());
+        }
+        LocalDateTime now = LocalDateTime.now();
+        String dateTime = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+        webLogDTO.setVisitTime(dateTime);
+        // 发到kafka
+        AsyncManager.me().execute(AsyncFactory.webVisitLog(webLogDTO));
+        return true;
+    }
+
+
+
+
+
+
+}

+ 56 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/mangae/AsyncManager.java

@@ -0,0 +1,56 @@
+package com.zanxiang.game.data.serve.mangae;
+
+
+
+import com.zanxiang.game.data.serve.utils.SpringUtils;
+import com.zanxiang.game.data.serve.utils.Threads;
+
+import java.util.TimerTask;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 异步任务管理器
+ */
+public class AsyncManager
+{
+    /**
+     * 操作延迟10毫秒
+     */
+    private final int OPERATE_DELAY_TIME = 10;
+
+    /**
+     * 异步操作任务调度线程池
+     */
+    private final ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
+
+    /**
+     * 单例模式
+     */
+    private AsyncManager(){}
+
+    private static final AsyncManager me = new AsyncManager();
+
+    public static AsyncManager me()
+    {
+        return me;
+    }
+
+    /**
+     * 执行任务
+     * 
+     * @param task 任务
+     */
+    public void execute(TimerTask task)
+    {
+        executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * 停止任务线程池
+     */
+    public void shutdown()
+    {
+        Threads.shutdownAndAwaitTermination(executor);
+    }
+}

+ 35 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/mangae/factory/AsyncFactory.java

@@ -0,0 +1,35 @@
+package com.zanxiang.game.data.serve.mangae.factory;
+
+
+import com.zanxiang.game.data.serve.pojo.dto.WebLogDTO;
+import com.zanxiang.game.data.serve.service.IWebVisitLogService;
+import com.zanxiang.game.data.serve.utils.SpringUtils;
+
+import java.util.TimerTask;
+
+/**
+ * 异步工厂(产生任务用)
+ * 
+ */
+public class AsyncFactory
+{
+
+    /**
+     * 界面访问记录
+     * 
+     * @param webLogDTO 界面访问记录对象
+     * @return 任务task
+     */
+    public static TimerTask webVisitLog(final WebLogDTO webLogDTO)
+    {
+        return new TimerTask()
+        {
+            @Override
+            public void run()
+            {
+                // 远程查询操作地点
+                SpringUtils.getBean(IWebVisitLogService.class).insertVisitlog(webLogDTO);
+            }
+        };
+    }
+}

+ 0 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/GSGameServerDayDTO.java

@@ -1,7 +1,6 @@
 package com.zanxiang.game.data.serve.pojo.dto;
 
 import com.zanxiang.game.data.serve.pojo.base.BasePage;
-import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 

+ 1 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/GameDataDayTotalDTO.java

@@ -66,6 +66,6 @@ public class GameDataDayTotalDTO {
      * 游戏维度:1-子游戏维度;2-父游戏维度;3-超父游戏维度
      */
     @ApiModelProperty(notes = "游戏维度:1-子游戏维度;2-父游戏维度;3-超父游戏维度")
-    private Long gameDimension;
+    private Long gameDimension = 1L;
 
 }

+ 0 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/GameDataTotalDTO.java

@@ -7,7 +7,6 @@ import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
-
 import java.time.LocalDate;
 import java.util.List;
 

+ 0 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/GameDataWaterDTO.java

@@ -7,7 +7,6 @@ import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
-
 import java.time.LocalDate;
 import java.util.List;
 

+ 0 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/OverallSummaryDTO.java

@@ -8,7 +8,6 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 import org.springframework.format.annotation.DateTimeFormat;
 
-
 import java.time.LocalDate;
 
 /**

+ 0 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/PlayerDataListDTO.java

@@ -7,7 +7,6 @@ import lombok.Data;
 import org.springframework.format.annotation.DateTimeFormat;
 
 import java.time.LocalDate;
-import java.time.LocalDateTime;
 import java.util.List;
 
 /**

+ 14 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/RoleRechargeRankingDTO.java

@@ -225,4 +225,18 @@ public class RoleRechargeRankingDTO extends BasePage {
      */
     @ApiModelProperty(value = "创角24小时以内累计充值金额范围单位(>=,<=,=,<,>)")
     private String rechargeTotalAmountWithin24hUnit = ">=";
+
+    /**
+     * 角色最近活跃时间开始时间
+     */
+    @ApiModelProperty(value = "角色最近活跃时间开始时间")
+    private LocalDate lastActiveTimeMin;
+
+    /**
+     * 角色最近活跃时间结束时间
+     */
+    @ApiModelProperty(value = "角色最近活跃时间结束时间")
+    private LocalDate lastActiveTimeMax;
+
+
 }

+ 29 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/WebLogDTO.java

@@ -0,0 +1,29 @@
+package com.zanxiang.game.data.serve.pojo.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @Description: web界面访问日志对象
+ */
+@Data
+public class WebLogDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 标题
+     */
+    private String title;
+
+    /**
+     * 用户id
+     */
+    private String userId;
+
+    /**
+     * 访问时间  YYYY-MM-DD HH:MM:SS
+     */
+    private String visitTime;
+
+}

+ 0 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/entity/AdsAgentDayAgain.java

@@ -8,7 +8,6 @@ import org.nutz.dao.entity.annotation.Column;
 import org.nutz.dao.entity.annotation.PK;
 import org.nutz.dao.entity.annotation.Table;
 
-
 import java.time.LocalDate;
 
 /**

+ 0 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/entity/AdsEverydayWater.java

@@ -1,6 +1,5 @@
 package com.zanxiang.game.data.serve.pojo.entity;
 
-import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;

+ 0 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/entity/AdsGameDay.java

@@ -10,7 +10,6 @@ import org.nutz.dao.entity.annotation.Table;
 
 import java.io.Serializable;
 import java.math.BigDecimal;
-
 import java.time.LocalDate;
 
 /**

+ 0 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/entity/AdsGameDayAgain.java

@@ -8,7 +8,6 @@ import org.nutz.dao.entity.annotation.Column;
 import org.nutz.dao.entity.annotation.PK;
 import org.nutz.dao.entity.annotation.Table;
 
-
 import java.time.LocalDate;
 
 /**

+ 0 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/entity/AdsGameDayAgainNature.java

@@ -8,7 +8,6 @@ import org.nutz.dao.entity.annotation.Column;
 import org.nutz.dao.entity.annotation.PK;
 import org.nutz.dao.entity.annotation.Table;
 
-
 import java.time.LocalDate;
 
 /**

+ 0 - 3
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/entity/AdsPitcherGameDayn.java

@@ -1,9 +1,6 @@
 package com.zanxiang.game.data.serve.pojo.entity;
 
-import lombok.AllArgsConstructor;
-import lombok.Builder;
 import lombok.Data;
-import lombok.NoArgsConstructor;
 import org.nutz.dao.entity.annotation.Column;
 import org.nutz.dao.entity.annotation.PK;
 import org.nutz.dao.entity.annotation.Table;

+ 23 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/properties/SmsProperties.java

@@ -0,0 +1,23 @@
+package com.zanxiang.game.data.serve.pojo.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@ConfigurationProperties(
+        prefix = "ali-sms"
+)
+@Data
+@Configuration
+public class SmsProperties {
+
+    public static final String CONFIG_PREFIX = "ali-sms";
+    private String accessKeyId;
+    private String accessKeySecret;
+    private String defaultSignName;
+    private String defaultStstemErrorTemplate;
+    private String msgParamName = "msg";
+    private String timeParamName = "time";
+
+
+}

+ 0 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/FirstNewUserAgainTrendVO.java

@@ -1,6 +1,5 @@
 package com.zanxiang.game.data.serve.pojo.vo;
 
-import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
 import lombok.Builder;

+ 0 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/FlowMonitorVO.java

@@ -1,6 +1,5 @@
 package com.zanxiang.game.data.serve.pojo.vo;
 
-import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 

+ 0 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GSGameServerDayVO.java

@@ -1,6 +1,5 @@
 package com.zanxiang.game.data.serve.pojo.vo;
 
-import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 

+ 0 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameDataDayVO.java

@@ -4,7 +4,6 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import java.math.BigDecimal;
-
 import java.time.LocalDate;
 
 /**

+ 0 - 2
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameDataH5VO.java

@@ -5,10 +5,8 @@ import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
-import org.nutz.dao.entity.annotation.Column;
 
 import java.math.BigDecimal;
-import java.time.LocalDate;
 import java.util.List;
 
 /**

+ 0 - 3
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameDataWaterVO.java

@@ -5,11 +5,8 @@ import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
-import org.nutz.dao.entity.annotation.Column;
 
 import java.math.BigDecimal;
-
-import java.time.LocalDate;
 import java.util.List;
 
 /**

+ 0 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameMonitorAlarmVO.java

@@ -4,7 +4,6 @@ import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
-import org.nutz.dao.entity.annotation.Column;
 
 import java.time.LocalDate;
 

+ 0 - 3
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GamePromoteDayTotalVO.java

@@ -1,10 +1,7 @@
 package com.zanxiang.game.data.serve.pojo.vo;
 
 import io.swagger.annotations.ApiModelProperty;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
 import lombok.Data;
-import lombok.NoArgsConstructor;
 
 import java.math.BigDecimal;
 

+ 0 - 3
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GamePromoteDayVO.java

@@ -1,10 +1,7 @@
 package com.zanxiang.game.data.serve.pojo.vo;
 
 import io.swagger.annotations.ApiModelProperty;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
 import lombok.Data;
-import lombok.NoArgsConstructor;
 
 import java.math.BigDecimal;
 import java.time.LocalDate;

+ 0 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GamePromoteTotalVO.java

@@ -7,7 +7,6 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 
 import java.math.BigDecimal;
-import java.time.LocalDate;
 
 @Data
 @NoArgsConstructor

+ 0 - 2
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameRechargeRankingVO.java

@@ -5,10 +5,8 @@ import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
-import org.nutz.dao.entity.annotation.Column;
 
 import java.math.BigDecimal;
-import java.time.LocalDate;
 
 @Data
 @NoArgsConstructor

+ 0 - 2
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/PlayerRechargeRankingVO.java

@@ -5,10 +5,8 @@ import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
-import org.nutz.dao.entity.annotation.Column;
 
 import java.math.BigDecimal;
-import java.time.LocalDate;
 import java.time.LocalDateTime;
 
 @Data

+ 3 - 3
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/RechargeTrendVO.java

@@ -26,19 +26,19 @@ public class RechargeTrendVO {
     private BigDecimal rechargeMoney;
 
     /**
-     * 增
+     * 增(第N天减第N-1天金额除总消耗)
      */
     @ApiModelProperty(notes = "增")
     private BigDecimal increase;
 
     /**
-     * 回
+     * 回(第N天的金额除总消耗)
      */
     @ApiModelProperty(notes = "回")
     private BigDecimal back;
 
     /**
-     * 倍
+     * 倍(第N天的金额除第一天的金额)
      */
     @ApiModelProperty(notes = "倍")
     private BigDecimal multiples;

+ 22 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/IOrderCostMonitorAlarmService.java

@@ -0,0 +1,22 @@
+package com.zanxiang.game.data.serve.service;
+
+import org.springframework.stereotype.Service;
+
+public interface IOrderCostMonitorAlarmService {
+    /**
+     * 监控数据状态
+     */
+    void monitorDataStatus();
+
+    /**
+     * 监控头条广告消耗表
+     */
+    void monitorHeadCostStatus();
+
+    /**
+     * 监控腾讯广告消耗表
+     */
+    void monitorTencentCostStatus();
+
+     boolean testSendSms(String content);
+}

+ 7 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/IWebVisitLogService.java

@@ -0,0 +1,7 @@
+package com.zanxiang.game.data.serve.service;
+
+import com.zanxiang.game.data.serve.pojo.dto.WebLogDTO;
+
+public interface IWebVisitLogService {
+    void insertVisitlog(WebLogDTO webLogDTO);
+}

+ 0 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/AccountListServiceImpl.java

@@ -2,7 +2,6 @@ package com.zanxiang.game.data.serve.service.impl;
 
 import com.zanxiang.game.data.serve.pojo.dto.ChoiceListDTO;
 import com.zanxiang.game.data.serve.pojo.vo.AccountListVO;
-import com.zanxiang.game.data.serve.pojo.vo.AgentListVO;
 import com.zanxiang.game.data.serve.service.IAccountListService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;

+ 0 - 2
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/AgentListServiceImpl.java

@@ -5,10 +5,8 @@ import com.zanxiang.game.data.serve.pojo.vo.AgentListVO;
 import com.zanxiang.game.data.serve.service.IAgentListService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
-import org.nutz.dao.Cnd;
 import org.nutz.dao.Dao;
 import org.nutz.dao.Sqls;
-import org.nutz.dao.sql.Criteria;
 import org.nutz.dao.sql.Sql;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 639 - 227
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GameDataServiceImpl.java


+ 12 - 3
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GameMonitorAlarmServiceImpl.java

@@ -6,6 +6,7 @@ import com.zanxiang.game.data.serve.pojo.entity.AdsMonitorAlarm;
 import com.zanxiang.game.data.serve.pojo.vo.GameMonitorAlarmVO;
 import com.zanxiang.game.data.serve.service.IGameMonitorAlarmService;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.dubbo.config.annotation.DubboReference;
 import org.nutz.dao.Chain;
 import org.nutz.dao.Cnd;
@@ -44,11 +45,19 @@ public class GameMonitorAlarmServiceImpl implements IGameMonitorAlarmService {
         dao.execute(sql);
         //结果
         try{
-            List<GameMonitorAlarmVO> list = sql.getList(GameMonitorAlarmVO.class).stream().map(vo -> {
+            List<GameMonitorAlarmVO> list1 = sql.getList(GameMonitorAlarmVO.class);
+            if (CollectionUtils.isEmpty(list1)){
+                log.info("没有告警信息");
+                return true;
+            }
+
+            for (GameMonitorAlarmVO vo : list1) {
                 String[] pitcherIds = vo.getPitcherId().split("-");
                 for (String pitcherId : pitcherIds) {
                     //发送给多个投手
+                    log.info("发送告警信息给投手:{}", pitcherId);
                     dingTalkMsgRpc.sendByUserId(Long.valueOf(pitcherId), alarmStr(vo));
+                    log.info("发送告警信息给投手:{}成功", pitcherId);
                 }
                 //更新的条件
                 Criteria cri = Cnd.cri();
@@ -65,8 +74,8 @@ public class GameMonitorAlarmServiceImpl implements IGameMonitorAlarmService {
                     cri.where().andEquals("userId", vo.getUserId());
                 }
                 dao.update(AdsMonitorAlarm.class, Chain.make("warn_status", 1), cri);
-                return vo;
-            }).toList();
+            }
+
         } catch (Exception e) {
             log.error("游戏监控告警出错,原因:{}", e.getMessage(), e);
         }

+ 50 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/IWebVisitLogServiceImpl.java

@@ -0,0 +1,50 @@
+package com.zanxiang.game.data.serve.service.impl;
+
+import com.alibaba.fastjson2.JSON;
+import com.zanxiang.game.data.serve.pojo.dto.WebLogDTO;
+import com.zanxiang.game.data.serve.service.IWebVisitLogService;
+import com.zanxiang.module.util.JsonUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.kafka.clients.producer.Producer;
+import org.apache.kafka.clients.producer.ProducerRecord;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+/**
+ * web访问日志记录
+ */
+@Service
+@Slf4j
+public class IWebVisitLogServiceImpl implements IWebVisitLogService {
+
+
+    @Value("${spring.kafka.game-data.webLogTopic}")
+    private String webLogTopic;
+
+    @Value("${spring.kafka.game-data.bootstrap-servers}")
+    private String gameSdkKafkaSevers;
+
+
+    @Autowired
+    @Qualifier("gameDataKafkaProducer")
+    private Producer<String, String> kafkaProducer;
+
+    /**
+     * 将数据发到kafka
+     * @param webLogDTO
+     */
+    @Override
+    public void insertVisitlog(WebLogDTO webLogDTO) {
+        System.out.println(gameSdkKafkaSevers);
+        String webLogJsonString = JSON.toJSONString(webLogDTO);
+        //将记录发到kafka记录
+        try {
+            kafkaProducer.send(new ProducerRecord<>(this.webLogTopic,webLogJsonString));
+            log.info("发送web访问日志到kafka成功,topic:{},数据为:{}",this.webLogTopic,webLogJsonString);
+        }catch (Exception e){
+            log.error("发送web访问日志到kafka失败,topic:{},数据为:{},异常为:{}",this.webLogTopic,webLogJsonString,e.toString());
+        }
+    }
+}

+ 187 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/OrderCostMonitorAlarmBySmsServiceImpl.java

@@ -0,0 +1,187 @@
+package com.zanxiang.game.data.serve.service.impl;
+
+import com.zanxiang.game.data.serve.pojo.properties.SmsProperties;
+import com.zanxiang.game.data.serve.service.IOrderCostMonitorAlarmService;
+import com.zanxiang.game.data.serve.utils.RedisUtil;
+import com.zanxiang.module.sms.pojo.SendResult;
+import com.zanxiang.module.sms.service.impl.AliSmsService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.nutz.dao.Cnd;
+import org.nutz.dao.Dao;
+import org.nutz.dao.Sqls;
+import org.nutz.dao.sql.Criteria;
+import org.nutz.dao.sql.Sql;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.util.*;
+
+@Service
+@Slf4j
+public class OrderCostMonitorAlarmBySmsServiceImpl implements IOrderCostMonitorAlarmService {
+
+    @Resource
+    private Dao dao;
+
+    @Resource
+    private RedisUtil<String> redisUtil;
+
+    @Resource
+    private AliSmsService aliSmsService;
+
+    @Resource
+    private SmsProperties smsProperties;
+
+    private final String modelName = "game_data_serve";
+
+    private final String HEADLINE_COST_COUNT = modelName + ":" + "headline_cost_count";
+
+    private final String TENCENT_COST_COUNT = modelName + ":" + "tencent_cost_count";
+
+    @Value("${phoneNumber}")
+    private String phoneNumber;
+
+    /**
+     * 10分钟扫一次,每次扫当前时间-半小时
+     */
+    @Override
+    public void monitorDataStatus() {
+        //获取当前时间前半小时的时间
+        LocalDateTime date = LocalDateTime.now().minusMinutes(30);
+        //查询订单表
+        Sql orderSql = getSql(getOrderCountSql(date));
+        int count = orderSql.getInt(0);
+        //如果为0直接告警
+        if (count == 0) {
+            String msg = "前半小时订单表数据为空,请检查";
+            log.info(msg);
+            if(!sendSms(msg)){
+                throw new RuntimeException("短信发送失败");
+            }
+        }
+    }
+
+    @Override
+    public void monitorHeadCostStatus() {
+        //获取当前时间前半小时的时间
+        LocalDateTime date = LocalDateTime.now().minusMinutes(30);
+        //查询头条广告表
+        Sql headCostSql = getSql(getheadCostCountSql(date));
+        int newHeadCostCount = headCostSql.getInt(0);
+        //从redis中取旧的消耗值
+        String oldHeadCostCount = redisUtil.getCache(HEADLINE_COST_COUNT);
+        if(StringUtils.isNotBlank(oldHeadCostCount)){
+            //如果不为空,则比较
+            if (newHeadCostCount - Integer.parseInt(oldHeadCostCount) == 0) {
+                //如果没期间没消耗就告警
+                String msg = "前半小时头条广告数据为空,请检查";
+                log.info(msg);
+                if(!sendSms(msg)){
+                    throw new RuntimeException("短信发送失败");
+                }
+            }
+        }
+        //将新数据存入redis  30分钟
+        redisUtil.setCache(HEADLINE_COST_COUNT, Integer.toString(newHeadCostCount), 60 * 30);
+
+    }
+
+    @Override
+    public void monitorTencentCostStatus() {
+        //获取当前时间前半小时的时间
+        LocalDateTime date = LocalDateTime.now().minusMinutes(30);
+        //查询腾讯广告表
+        Sql tencentCostSql = getSql(getTencentCostSqlSql(date));
+        int newTencentCostCount = tencentCostSql.getInt(0);
+        //从redis中取旧的消耗值
+        String oldTencentCostCount = redisUtil.getCache(TENCENT_COST_COUNT);
+        if(StringUtils.isNotBlank(oldTencentCostCount)){
+            if (newTencentCostCount - Integer.parseInt(oldTencentCostCount) == 0) {
+                String msg = "前半小时腾讯广告数据为空,请检查";
+                log.info(msg);
+                if(!sendSms(msg)){
+                    throw new RuntimeException("短信发送失败");
+                }
+            }
+        }
+        //将新数据存入redis  30分钟
+        redisUtil.setCache(TENCENT_COST_COUNT, Integer.toString(newTencentCostCount), 60 * 30);
+    }
+
+
+
+    /**
+     * 发送短信
+     * @param content 内容
+     * @return 是否发送成功
+     */
+    private Boolean sendSms(String content) {
+        Date date = new Date();
+        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Map<String, String> params = new HashMap<>();
+        params.put(smsProperties.getMsgParamName(), content);
+        params.put(smsProperties.getTimeParamName(),formatter.format(date));
+        //存储在配置文件
+        Set<String> numberList = new HashSet<>(Arrays.asList(phoneNumber.split(",")));
+
+        Map<String, SendResult> resultMap = aliSmsService.send(smsProperties.getDefaultSignName(), smsProperties.getDefaultStstemErrorTemplate(), params, numberList);
+        for (SendResult next : resultMap.values()) {
+            if (!next.isSuccess()) {
+                log.error("短信发送失败,失败原因:{}", next.getMsg());
+                return false;
+            }
+        }
+        return true;
+    }
+
+
+    public boolean testSendSms(String content) {
+        System.out.println(phoneNumber);
+        return false;
+//        return sendSms(content);
+    }
+
+
+
+    private Sql getSql(String sqlStr) {
+        Sql sql = Sqls.create(sqlStr);
+        sql.setCallback(Sqls.callback.integer());
+        dao.execute(sql);
+        return sql;
+    }
+
+    private String getTencentCostSqlSql(LocalDateTime date) {
+        Criteria cri = Cnd.cri();
+        cri.where().and("day", ">=", date.toLocalDate());
+        cri.where().and("hour", "=", date.getHour());
+        return """
+                select sum(cost) from ods_ad_tencent_data_game.t_gdt_adgroups_data_hour
+                """ + cri;
+    }
+
+    private String getheadCostCountSql(LocalDateTime date) {
+        Criteria cri = Cnd.cri();
+        cri.where().and("day", ">=", date.toLocalDate());
+        cri.where().and("hour", "=", date.getHour());
+        return """
+                select sum(cost) from ods_ad_byte_data_game.t_ad_data_hour
+                """ + cri;
+    }
+
+    private String getOrderCountSql(LocalDateTime localDateTime) {
+        Criteria criteria = Cnd.cri();
+        criteria.where().and("create_time", ">=", localDateTime);
+        criteria.where().and("source_system", "=", "ZX_ONE");
+        return """
+                  select count(*) from dm_game_order.t_game_order
+                """ + criteria;
+    }
+
+
+
+
+}

+ 464 - 164
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/RoleManageServiceImpl.java

@@ -1,19 +1,19 @@
 package com.zanxiang.game.data.serve.service.impl;
 
 import com.alibaba.fastjson2.JSON;
-import com.zanxiang.game.data.serve.pojo.dto.*;
-import com.zanxiang.game.module.base.pojo.params.SendMsgTaskResultParam;
-import com.zanxiang.game.module.base.pojo.vo.SendMsgResultVO;
-import com.zanxiang.game.module.base.pojo.vo.SendMsgVO;
 import com.zanxiang.erp.base.ErpServer;
 import com.zanxiang.erp.base.rpc.ISysUserRpc;
 import com.zanxiang.erp.security.util.SecurityUtil;
+import com.zanxiang.game.data.serve.pojo.dto.*;
 import com.zanxiang.game.data.serve.pojo.enums.OrderByEnum;
 import com.zanxiang.game.data.serve.service.IRoleManageService;
 import com.zanxiang.game.data.serve.utils.Page;
 import com.zanxiang.game.module.base.ServerInfo;
 import com.zanxiang.game.module.base.pojo.dto.SendMsgDTO;
 import com.zanxiang.game.module.base.pojo.params.SendMsgTaskParam;
+import com.zanxiang.game.module.base.pojo.params.SendMsgTaskResultParam;
+import com.zanxiang.game.module.base.pojo.vo.SendMsgResultVO;
+import com.zanxiang.game.module.base.pojo.vo.SendMsgVO;
 import com.zanxiang.game.module.base.rpc.ICPSendMsgRpc;
 import com.zanxiang.game.module.base.util.PageUtil;
 import com.zanxiang.module.util.exception.BaseException;
@@ -30,6 +30,7 @@ import org.nutz.dao.sql.Criteria;
 import org.nutz.dao.sql.Sql;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.util.StopWatch;
 
 import java.util.*;
 import java.util.function.Function;
@@ -61,11 +62,193 @@ public class RoleManageServiceImpl implements IRoleManageService {
      */
     @Override
     public Page<Map> getRoleRechargeRanking(RoleRechargeRankingDTO dto) {
+        //创建查询条件 给主表使用
+        Criteria criA = getSqlByQuery(dto);
+        //给充值时间查询条件
+        Criteria criTodayAmount = getDateSqlByQuery(dto);
+        //分页对象
+        Pager pager = dao.createPager(dto.getPageNum(), dto.getPageSize());
+
+        StopWatch watch=new StopWatch();
+        watch.start();
+        //查询总记录数
+        Sql countSql = Sqls.create(getCountNumSql2(criA, criTodayAmount));
+        countSql.setCallback(Sqls.callback.integer());
+        dao.execute(countSql);
+        watch.stop();
+
+        pager.setRecordCount(countSql.getInt());
+        //主表添加排序条件
+        if (StringUtils.isBlank(dto.getSortType())) {
+            dto.setSortType(OrderByEnum.DESC.getOrderType());
+        }
+        if (StringUtils.isBlank(dto.getSortFiled())) {
+            criA.getOrderBy().orderBy("amount", dto.getSortType());
+        } else {
+            criA.getOrderBy().orderBy(dto.getSortFiled(), dto.getSortType());
+        }
+        //创建sql
+        StopWatch watch2=new StopWatch();
+        watch2.start();
+        Sql sql = Sqls.create(getRoleRechargeRankingSql(criA, criTodayAmount));
+        sql.setCallback(Sqls.callback.maps());
+        sql.setPager(pager);
+        dao.execute(sql);
+        watch2.stop();
+        //查询结果
+        List<Map> list = sql.getList(Map.class);
+        //用户id列表
+        List<Long> userIds = new ArrayList<>();
+        for (Map map : list) {
+            //把投手id和运营id和GSID和客服人员ID 转成List
+            List<String> keys = Arrays.asList("put_user_id", "oper_user_id", "gs_id", "customer_service_id");
+            for (String key : keys) {
+                if (map.get(key) != null) {
+                    userIds.add(Long.valueOf(map.get(key).toString()));
+                }
+            }
+            //去掉字符串中的‘[]’
+            String str = (String) map.get("role_amount");
+            if(str!=null&&str.contains("[") && str.contains("]")){
+                map.put("role_amount", str.replaceAll("[\\[\\]]", ""));
+            }
+            //去除‘null’字符串
+            List<String> nullStringKeys = Arrays.asList("add_corp_user_id", "user_wechat", "remark", "user_phone", "country");
+            nullStringKeys.stream()
+                    .filter(key -> "null".equals(map.get(key)))
+                    .forEach(key -> map.put(key, null));
+        }
+        //去重userIds
+        userIds = userIds.stream().distinct().collect(Collectors.toList());
+        //发送RPC接口查询所有用户
+        ResultVO<Map<Long, String>> userMap = sysUserRpc.getUserNameByIds(userIds);
+
+        for (Map map : list) {
+            //投手名
+            updateUserName(map, "put_user_id", "put_user_name", userMap);
+            //运营人员名
+            updateUserName(map, "oper_user_id", "oper_user_name", userMap);
+            //GS人员名
+            updateUserName(map, "gs_id", "gs_name", userMap);
+            //客服人员名
+            updateUserName(map, "customer_service_id", "customer_service_name", userMap);
+        }
+        //返回结果
+        log.info("查询总记录数耗时:{}",watch.getTotalTimeMillis());
+        log.info("查询数据耗时:{}",watch2.getTotalTimeMillis());
+        return new Page<>(list, pager);
+    }
+
+
+    /**
+     * 角色充值排行榜(优化版)
+     * @param dto RoleRechargeRankingDTO
+     * @return Page<List<Map<String, Object>>>
+     */
+    public Page<Map> getRoleRechargeRanking2(RoleRechargeRankingDTO dto) {
+        //创建查询条件 给主表使用
+        Criteria criA = getSqlByQuery(dto);
+        //给充值时间查询条件
+        Criteria criTodayAmount = getDateSqlByQuery(dto);
+        //分页对象
+        Pager pager = dao.createPager(dto.getPageNum(), dto.getPageSize());
+
+        StopWatch watch=new StopWatch();
+        watch.start();
+        //查询总记录数
+        Sql countSql = Sqls.create(getCountNumSql2(criA, criTodayAmount));
+        countSql.setCallback(Sqls.callback.integer());
+        dao.execute(countSql);
+        watch.stop();
+
+        pager.setRecordCount(countSql.getInt());
+        //主表添加排序条件
+        if (StringUtils.isBlank(dto.getSortType())) {
+            dto.setSortType(OrderByEnum.DESC.getOrderType());
+        }
+        if (StringUtils.isBlank(dto.getSortFiled())) {
+            criA.getOrderBy().orderBy("amount", dto.getSortType());
+        } else {
+            criA.getOrderBy().orderBy(dto.getSortFiled(), dto.getSortType());
+        }
+        //创建sql
+        StopWatch watch2=new StopWatch();
+        watch2.start();
+        Sql sql = Sqls.create(getRoleRechargeRankingSql(criA, criTodayAmount));
+        sql.setCallback(Sqls.callback.maps());
+        sql.setPager(pager);
+        dao.execute(sql);
+        watch2.stop();
+        //查询结果
+        List<Map> list = sql.getList(Map.class);
+        //用户id列表
+        List<Long> userIds = new ArrayList<>();
+        for (Map map : list) {
+            //把投手id和运营id和GSID和客服人员ID 转成List
+            List<String> keys = Arrays.asList("put_user_id", "oper_user_id", "gs_id", "customer_service_id");
+            for (String key : keys) {
+                if (map.get(key) != null) {
+                    userIds.add(Long.valueOf(map.get(key).toString()));
+                }
+            }
+            //去掉字符串中的‘[]’
+            String str = (String) map.get("role_amount");
+            if(str!=null&&str.contains("[") && str.contains("]")){
+                map.put("role_amount", str.replaceAll("[\\[\\]]", ""));
+            }
+            //去除‘null’字符串
+            List<String> nullStringKeys = Arrays.asList("add_corp_user_id", "user_wechat", "remark", "user_phone", "country");
+            nullStringKeys.stream()
+                    .filter(key -> "null".equals(map.get(key)))
+                    .forEach(key -> map.put(key, null));
+        }
+        //去重userIds
+        userIds = userIds.stream().distinct().collect(Collectors.toList());
+        //发送RPC接口查询所有用户
+//        ResultVO<Map<Long, String>> userMap = sysUserRpc.getUserNameByIds(userIds);
+//
+//        for (Map map : list) {
+//            //投手名
+//            updateUserName(map, "put_user_id", "put_user_name", userMap);
+//            //运营人员名
+//            updateUserName(map, "oper_user_id", "oper_user_name", userMap);
+//            //GS人员名
+//            updateUserName(map, "gs_id", "gs_name", userMap);
+//            //客服人员名
+//            updateUserName(map, "customer_service_id", "customer_service_name", userMap);
+//        }
+        //返回结果
+        log.info("查询总记录数耗时:{}",watch.getTotalTimeMillis());
+        log.info("查询数据耗时:{}",watch2.getTotalTimeMillis());
+        return new Page<>(list, pager);
+    }
+
+    // 更新用户名称
+    private void updateUserName(Map<String, Object> map, String userIdKey, String userNameKey, ResultVO<Map<Long, String>> userMap) {
+        Object userIdObj = map.get(userIdKey);
+        if (userIdObj != null) {
+            try {
+                long userId = Long.parseLong(userIdObj.toString());
+                String userName = userMap.getData().get(userId);
+                if (userName != null) {
+                    map.put(userNameKey, userName);
+                }
+            } catch (NumberFormatException e) {
+                // 处理长整型转换异常
+                log.error("Error parsing user ID for key " + userIdKey + ": " + e.getMessage());
+            }
+        }
+    }
+
+
+    /**
+     * 根据条件生成查询sql条件
+     */
+    private Criteria getSqlByQuery(RoleRechargeRankingDTO dto){
         //默认查询不合服的数据
         if (dto.getIsMergeServer() == null) {
             dto.setIsMergeServer(Boolean.FALSE);
         }
-        //创建查询条件 给主表使用
         Criteria criA = Cnd.cri();
         if (CollectionUtils.isNotEmpty(dto.getGameId())) {
             //角色注册子游戏
@@ -74,10 +257,10 @@ public class RoleManageServiceImpl implements IRoleManageService {
 
         //拼接24内充值金额条件
         if(dto.getRechargeAmountWithin24h()!=null){
-            criA = spliceRechargeAmountWithin24h(dto, criA);
+            spliceRechargeAmountWithin24h(dto, criA);
         }
         if(dto.getRechargeTotalAmountWithin24h()!=null){
-            criA = spliceRechargeTotalAmountWithin24h(dto, criA);
+            spliceRechargeTotalAmountWithin24h(dto, criA);
         }
 
         if (CollectionUtils.isNotEmpty(dto.getParentGameIds())) {
@@ -208,7 +391,18 @@ public class RoleManageServiceImpl implements IRoleManageService {
                 criA.where().andEquals("is_add_corp_wechat", dto.getIsAddCorpWechat());
             }
         }
-        //给充值时间查询条件
+        //角色最近活跃时间
+        if(dto.getLastActiveTimeMax()!=null && dto.getLastActiveTimeMin()!=null){
+            criA.where().andBetween("DATE(role_active_time)", dto.getLastActiveTimeMin(), dto.getLastActiveTimeMax());
+        }
+
+        return criA;
+    }
+
+    /**
+     * 根据时间条件生成查询sql
+     */
+    private Criteria getDateSqlByQuery(RoleRechargeRankingDTO dto){
         Criteria criTodayAmount = Cnd.cri();
         //查询充值成功的
         criTodayAmount.where().andEquals("status", 2);
@@ -216,121 +410,22 @@ public class RoleManageServiceImpl implements IRoleManageService {
             //充值时间限制
             criTodayAmount.where().andBetween("DATE(pay_time)", dto.getRechargeBeginDate(), dto.getRechargeEndDate());
         }
-        //分页对象
-        Pager pager = dao.createPager(dto.getPageNum(), dto.getPageSize());
-        //查询总记录数
-        Sql countSql = Sqls.create(getCountNumSql(criA, criTodayAmount));
-        countSql.setCallback(Sqls.callback.integer());
-        dao.execute(countSql);
-        pager.setRecordCount(countSql.getInt());
-        //主表添加排序条件
-        if (StringUtils.isBlank(dto.getSortType())) {
-            dto.setSortType(OrderByEnum.DESC.getOrderType());
-        }
-        if (StringUtils.isBlank(dto.getSortFiled())) {
-            criA.getOrderBy().orderBy("amount", dto.getSortType());
-        } else {
-            criA.getOrderBy().orderBy(dto.getSortFiled(), dto.getSortType());
-        }
-        //创建sql
-        Sql sql = Sqls.create(getRoleRechargeRankingSql(criA, criTodayAmount));
-        sql.setCallback(Sqls.callback.maps());
-        sql.setPager(pager);
-        dao.execute(sql);
-        //查询结果
-        List<Map> list = sql.getList(Map.class);
-        //用户id列表
-        List<Long> userIds = new ArrayList<>();
-        for (Map map : list) {
-//            getNameById(map);
-            //把投手id和运营id和GSID和客服人员ID 转成List
-            if(map.get("put_user_id") != null){
-                userIds.add(Long.valueOf(map.get("put_user_id").toString()));
-            }
-            if(map.get("oper_user_id") != null){
-                userIds.add(Long.valueOf(map.get("oper_user_id").toString()));
-            }
-            if(map.get("gs_id") != null){
-                userIds.add(Long.valueOf(map.get("gs_id").toString()));
-            }
-            if(map.get("customer_service_id") != null){
-                userIds.add(Long.valueOf(map.get("customer_service_id").toString()));
-            }
-            String str = (String) map.get("role_amount");
-            if(str!=null&&str.contains("[") && str.contains("]")){
-                //去掉字符串中的‘[]’
-                map.put("role_amount", str.replaceAll("\\[|\\]", ""));
-            }
-
-            //去除‘null’字符串
-            if ("null".equals(map.get("add_corp_user_id"))) {
-                map.put("add_corp_user_id", null);
-            }
-            if ("null".equals(map.get("user_wechat"))) {
-                map.put("user_wechat", null);
-            }
-            if ("null".equals(map.get("remark"))) {
-                map.put("remark", null);
-            }
-            if ("null".equals(map.get("user_phone"))) {
-                map.put("user_phone", null);
-            }
-            if ("null".equals(map.get("country"))) {
-                map.put("country", null);
-            }
-        }
-        //去重userIds
-        userIds = userIds.stream().distinct().collect(Collectors.toList());
-        //发送RPC接口查询所有用户
-        ResultVO<Map<Long, String>> userMap = sysUserRpc.getUserNameByIds(userIds);
-
-        for (Map map : list) {
-            //投手名
-            updateUserName(map, "put_user_id", "put_user_name", userMap);
-            //运营人员名
-            updateUserName(map, "oper_user_id", "oper_user_name", userMap);
-            //GS人员名
-            updateUserName(map, "gs_id", "gs_name", userMap);
-            //客服人员名
-            updateUserName(map, "customer_service_id", "customer_service_name", userMap);
-        }
-        //返回结果
-        return new Page<>(list, pager);
-    }
-
-    // 更新用户名称
-    private void updateUserName(Map<String, Object> map, String userIdKey, String userNameKey, ResultVO<Map<Long, String>> userMap) {
-        Object userIdObj = map.get(userIdKey);
-        if (userIdObj != null) {
-            try {
-                long userId = Long.parseLong(userIdObj.toString());
-                String userName = userMap.getData().get(userId);
-                if (userName != null) {
-                    map.put(userNameKey, userName);
-                }
-            } catch (NumberFormatException e) {
-                // 处理长整型转换异常
-                log.error("Error parsing user ID for key " + userIdKey + ": " + e.getMessage());
-            }
-        }
+        return criTodayAmount;
     }
 
 
-    private Criteria spliceRechargeTotalAmountWithin24h(RoleRechargeRankingDTO dto, Criteria criA) {
+    private void spliceRechargeTotalAmountWithin24h(RoleRechargeRankingDTO dto, Criteria criA) {
         switch (dto.getRechargeTotalAmountWithin24hUnit()) {
             case ">" -> criA.where().andGT("role_total_amount", dto.getRechargeTotalAmountWithin24h());
             case ">=" -> criA.where().andGTE("role_total_amount", dto.getRechargeTotalAmountWithin24h());
             case "=" -> criA.where().andEquals("role_total_amount", dto.getRechargeTotalAmountWithin24h());
             case "<" -> criA.where().andLT("role_total_amount", dto.getRechargeTotalAmountWithin24h());
             case "<=" -> criA.where().andLTE("role_total_amount", dto.getRechargeTotalAmountWithin24h());
-            default -> {
-                criA.where().andGTE("role_total_amount", dto.getRechargeTotalAmountWithin24h());
-            }
+            default -> criA.where().andGTE("role_total_amount", dto.getRechargeTotalAmountWithin24h());
         }
-        return criA;
     }
 
-    private Criteria spliceRechargeAmountWithin24h(RoleRechargeRankingDTO dto, Criteria criA) {
+    private void spliceRechargeAmountWithin24h(RoleRechargeRankingDTO dto, Criteria criA) {
         switch (dto.getRechargeAmountWithin24hUnit()) {
             case ">" -> criA.where().andGT("max_amount", dto.getRechargeAmountWithin24h());
 //            case ">=" -> criA.where().andGTE("max_amount", dto.getRechargeAmountWithin24h());
@@ -338,11 +433,8 @@ public class RoleManageServiceImpl implements IRoleManageService {
             case "=" -> criA.where().andEquals("array_contains(role_amount,"+dto.getRechargeAmountWithin24h()+")", 1);
             case "<" -> criA.where().andLT("min_amount", dto.getRechargeAmountWithin24h());
 //            case "<=" -> criA.where().andLTE("max_amount", dto.getRechargeAmountWithin24h());
-            default -> {
-                criA.where().andGT("max_amount", dto.getRechargeAmountWithin24h());
-            }
+            default -> criA.where().andGT("max_amount", dto.getRechargeAmountWithin24h());
         }
-        return criA;
     }
 
     /**
@@ -386,7 +478,6 @@ public class RoleManageServiceImpl implements IRoleManageService {
 
     /**
      * 创建发送消息任务
-     * @param dto
      */
     @Override
     public void createSendMsgTask(SendMsgTaskDTO dto) {
@@ -439,8 +530,6 @@ public class RoleManageServiceImpl implements IRoleManageService {
 
     /**
      * 获取角色列表
-     * @param dto
-     * @return
      */
     @Override
     public List<Map> getRoleList(RoleRechargeRankingDTO dto) {
@@ -458,10 +547,10 @@ public class RoleManageServiceImpl implements IRoleManageService {
 
         //拼接24内充值金额条件
         if(dto.getRechargeAmountWithin24h()!=null){
-            criA = spliceRechargeAmountWithin24h(dto, criA);
+            spliceRechargeAmountWithin24h(dto, criA);
         }
         if(dto.getRechargeTotalAmountWithin24h()!=null){
-            criA = spliceRechargeTotalAmountWithin24h(dto, criA);
+            spliceRechargeTotalAmountWithin24h(dto, criA);
         }
 
         if (CollectionUtils.isNotEmpty(dto.getParentGameIds())) {
@@ -660,8 +749,6 @@ public class RoleManageServiceImpl implements IRoleManageService {
 
     /**
      * 获取创建人名称
-     * @param sendMsgTaskList
-     * @return
      */
     private Map<Long, String> getCreateByNameMap(PageUtil<SendMsgVO> sendMsgTaskList) {
         //取创建人id变成list
@@ -718,9 +805,7 @@ public class RoleManageServiceImpl implements IRoleManageService {
             List<TaskResultDTO> list = sql.getList(TaskResultDTO.class);
             //拼成map key为角色id
             HashMap<String, TaskResultDTO> taskResultMap = new HashMap<>();
-            list.forEach(item -> {
-                taskResultMap.put(item.getRoleId(), item);
-            });
+            list.forEach(item -> taskResultMap.put(item.getRoleId(), item));
             sendMsgTaskResultList.getRecords().forEach(item -> {
                 TaskResultDTO taskResultDto = taskResultMap.get(item.getRoleId());
                 if(taskResultDto!=null){
@@ -779,45 +864,6 @@ public class RoleManageServiceImpl implements IRoleManageService {
                 """;
     }
 
-    /**
-     * 通过id获取 GS、运营、客服人员、投手名字
-     * @param dataMap dataMap
-     * @return String
-     */
-    private Map<String, Object> getNameById(Map<String, Object> dataMap){
-
-        //投手名
-        if (dataMap.get("put_user_id") != null) {
-            if (sysUserRpc.getById(Long.valueOf((String) dataMap.get("put_user_id"))).getData() != null) {
-                dataMap.put("put_user_name",
-                        sysUserRpc.getById(Long.valueOf((String) dataMap.get("put_user_id"))).getData().getNickname());
-            }
-        }
-        //运营人员名
-        if (dataMap.get("oper_user_id") != null) {
-            if (sysUserRpc.getById((Long) dataMap.get("oper_user_id")).getData() != null) {
-                dataMap.put("oper_user_name",
-                        sysUserRpc.getById((Long) dataMap.get("oper_user_id")).getData().getNickname());
-            }
-        }
-        //GS人员名
-        if (dataMap.get("gs_id") != null) {
-            if (sysUserRpc.getById((Long) dataMap.get("gs_id")).getData() != null) {
-                dataMap.put("gs_name",
-                        sysUserRpc.getById((Long) dataMap.get("gs_id")).getData().getNickname());
-            }
-        }
-        //客服人员名
-        if (dataMap.get("customer_service_id") != null) {
-            if (sysUserRpc.getById((Long) dataMap.get("customer_service_id")).getData() != null) {
-                dataMap.put("customer_service_name",
-                        sysUserRpc.getById((Long) dataMap.get("customer_service_id")).getData().getNickname());
-            }
-        }
-
-        return dataMap;
-    }
-
     /**
      * 原始服-父游戏
      * @param dto RoleCombatRankingDTO
@@ -2163,6 +2209,260 @@ public class RoleManageServiceImpl implements IRoleManageService {
                 """ + criA;
     }
 
+    /**
+     * 查询记录数
+     * @param criA 主表条件
+     * @param criTodayAmount 今日充值条件
+     * @return String
+     */
+    private String getCountNumSql2(Criteria criA, Criteria criTodayAmount) {
+        return """
+                SELECT
+                    COUNT(1)
+                FROM (
+                    SELECT
+                        a.association_user_id as association_user_id, -- 来源的用户id
+                        a.source_system as source_system, -- sdk来源
+                        a.role_id as role_id, -- 角色id
+                        a.os as os, -- 角色操作系统
+                        b.role_name as role_name, -- 角色名
+                        a.create_time as role_create_time, -- 角色创建时间
+                        b.role_level as role_level, -- 角色等级
+                        IFNULL(c.amount, 0) as amount, -- 角色累计充值金额
+                        IFNULL(w.vip_level,
+                        (CASE
+                            WHEN c.amount >= 0 and c.amount < 2000 THEN '1'
+                            WHEN c.amount >= 2000 and c.amount < 5000 THEN '2'
+                            WHEN c.amount >= 5000 and c.amount < 10000 THEN '3'
+                            WHEN c.amount >= 10000 and c.amount < 20000 THEN '4'
+                            WHEN c.amount >= 20000 and c.amount < 50000 THEN '5'
+                            WHEN c.amount >= 50000 THEN '6'
+                            ELSE '0'
+                            END)) as vip_level, -- 角色vip等级
+                        a.game_id as role_reg_game_id, -- 角色注册游戏id
+                        IFNULL(d.parent_id, a.game_id) as role_reg_parent_game_id, -- 角色注册游戏的父游戏id
+                        IFNULL(d.super_game_id, a.game_id) as role_reg_super_game_id, -- 角色注册的超父游戏id
+                        a.server_id as server_id, -- 角色所在区服id
+                        t.server_name as source_server_name, -- 角色所在区服原始名
+                        IFNULL(f.real_amount, 0) as role_last_amount, -- 角色最近充值金额
+                        f.pay_time as role_last_pay_time, -- 角色最近充值时间
+                        g.update_time as role_active_time, -- 角色最近活跃时间
+                        TIMESTAMPDIFF(SECOND, g.update_time, NOW()) as role_active_until_now, -- 角色最近活跃距今
+                        IFNULL(h.real_amount, 0) as role_first_amount, -- 角色首次充值金额
+                        p.today_amount as today_amount, -- 角色当天充值金额
+                        TIMESTAMPDIFF(SECOND, a.create_time, f.pay_time) as role_reg_pay_time, -- 角色创建充值时间差(秒)
+                        TIMESTAMPDIFF(SECOND, f.pay_time, NOW()) as role_pay_until_now, -- 角色最近充值距今(秒)
+                        a.user_id as user_id, -- 玩家id
+                        x.agent_id as agent_id, -- 玩家注册渠道id
+                        IF(x.agent_id = 0 , '自然量', y.agent_name) as agent_name, -- 玩家注册渠道名
+                        y.put_user_id as put_user_id, -- 投手id
+                        IFNULL(j.is_send_mail, 0) as is_send_mail, -- 是否发送邮件
+                        j.send_gift_id as send_gift_id, -- 最新发送礼包id
+                        j.is_change_game_type as is_change_game_type, -- 是否转端 1-是;0-否
+                        j.is_add_corp_wechat as is_add_corp_wechat, -- 是否添加企微 1-是; 0-否
+                     
+                        IF(TIMESTAMPDIFF(HOUR, g.update_time, NOW()) > 72,
+                                        IF(TIMESTAMPDIFF(HOUR, f.pay_time, NOW()) < 72 , 0, 1) , 0) as is_remove_game_for_system, -- 是否退游 1-是;0-否(系统判定)
+                        j.is_remove_game as is_remove_game, -- 是否退游 1-是;0-否;null-代表未操作数据
+                        j.is_wake_up as is_wake_up, -- 是否唤醒 1-是;0-否
+                  
+                        j.gs_id as gs_id, -- GS_ID
+                        j.customer_service_id as customer_service_id, -- 客服ID
+                        j.oper_user_id as oper_user_id, -- 运营ID
+                        j.is_delete as is_delete, -- 是否删除 1-删除;0-正常
+                        ara.role_total_amount as role_total_amount, -- 创角24小时内总充值金额
+                		ara.max_amount as max_amount, -- 创角24小时内单笔最大充值金额
+                		ara.min_amount as min_amount, -- 创角24小时内单笔最小充值金额
+                		ara.role_amount as role_amount -- 角色充值数组
+                    FROM
+                    (
+                        SELECT
+                            *
+                        FROM
+                        (
+                            SELECT
+                                -- 角色所在子游戏id、区服id、合服id、角色id、角色名、角色创建时间、角色操作系统os(取创建时间最早的信息)
+                                b.association_user_id ,
+                                a.source_system,
+                                a.user_id,
+                                a.game_id,
+                                a.server_id,
+                                a.role_id,
+                                a.role_name,
+                                a.create_time,
+                                a.os,
+                                ROW_NUMBER()over(partition by a.role_id , a.source_system order by a.create_time asc, a.user_id asc) as num
+                            FROM dm_game_order.t_game_user_role a
+                            LEFT JOIN dm_game_order.t_game_user b on a.source_system = b.source_system AND a.user_id = b.id
+                        ) a
+                        WHERE num = 1
+                    ) a
+                    left join(
+                	    SELECT 
+                	        source_system,
+                	        role_id,
+                	        role_total_amount,
+                	        array_min(role_amount) min_amount,
+                	        array_max(role_amount) max_amount,
+                	        role_amount
+                	    FROM game_ads.ads_role_amount 
+                	) ara on a.role_id = ara.role_id and a.source_system = ara.source_system
+                    LEFT JOIN (
+                        SELECT
+                            -- 角色等级、角色攻击力(取最新的信息)
+                            source_system,
+                            role_id,
+                            role_name,
+                            role_level,
+                            ROW_NUMBER()over(partition by role_id , source_system order by update_time desc, user_id desc) as num
+                        FROM dm_game_order.t_game_user_role
+                    ) b on a.source_system = b.source_system AND a.role_id = b.role_id AND b.num = 1
+                    LEFT JOIN (
+                        SELECT
+                            -- 累计充值金额、累计充值次数
+                            role_id,
+                            source_system,
+                            SUM(real_amount) as amount
+                        FROM dm_game_order.t_game_order
+                        WHERE status =2
+                        GROUP BY role_id , source_system
+                    ) c on a.source_system = c.source_system AND a.role_id = c.role_id
+                    LEFT JOIN (
+                        SELECT
+                            -- 游戏名称、游戏类型、父游戏id、超父游戏id
+                            source_system,
+                            id,
+                            parent_id,
+                            super_game_id
+                        FROM dm_game_order.t_game
+                    ) d on a.source_system = d.source_system AND a.game_id = d.id
+                    LEFT JOIN (
+                        SELECT
+                            -- 父游戏名称
+                            source_system,
+                            id,
+                            game_name as parent_game_name
+                        FROM dm_game_order.t_game
+                    ) e on d.source_system = e.source_system AND d.parent_id = e.id
+                    LEFT JOIN (
+                        SELECT
+                            -- 角色最近充值时间、角色最近充值金额
+                            source_system,
+                            role_id,
+                            real_amount,
+                            pay_time,
+                            ROW_NUMBER()over(partition by role_id , source_system order by pay_time desc) as num
+                        FROM dm_game_order.t_game_order
+                        WHERE status =2
+                    ) f on a.source_system = f.source_system AND a.role_id = f.role_id AND f.num = 1
+                    LEFT JOIN (
+                        -- 角色最近活跃时间
+                        SELECT
+                            source_system ,
+                            role_id ,
+                            active_time as update_time ,
+                            ROW_NUMBER()over(partition by role_id , source_system order by active_time desc) as num
+                        FROM game_dw.dw_active_log
+                    ) g on a.source_system = g.source_system AND a.role_id = g.role_id AND g.num = 1
+                    LEFT JOIN (
+                        SELECT
+                            -- 角色首次充值金额
+                            source_system,
+                            role_id,
+                            real_amount,
+                            ROW_NUMBER()over(partition by role_id , source_system order by pay_time asc) as num
+                        FROM dm_game_order.t_game_order  WHERE status =2
+                    ) h on a.source_system = h.source_system AND a.role_id = h.role_id AND h.num = 1
+                    LEFT JOIN (
+                        SELECT
+                            -- 角色当天充值金额
+                            source_system,
+                            role_id,
+                            SUM(real_amount) as today_amount
+                        FROM dm_game_order.t_game_order
+                """ + criTodayAmount +
+                """
+                        GROUP BY role_id ,source_system
+                    ) p on a.source_system = p.source_system AND a.role_id = p.role_id
+                    LEFT JOIN (
+                        SELECT
+                            -- 操作表相关数据
+                            source_system,
+                            user_id,
+                            role_id,
+                            server_id,
+                            game_id,
+                            is_send_mail, -- 是否发送邮件
+                            send_gift_id, -- 最新发送礼包id
+                            is_change_game_type, -- 是否转端 1-是;0-否
+                            is_add_corp_wechat, -- 是否添加企微 1-是; 0-否
+                            is_remove_game, -- 是否退游 1-是;0-否
+                            is_wake_up, -- 是否唤醒 1-是;0-否
+                            gs_id, -- GS_ID
+                            customer_service_id, -- 客服ID
+                            oper_user_id, -- 运营ID
+                            is_delete -- 是否删除 1-删除;0-正常
+                        FROM dm_game_order.t_role_operate
+                    ) j on a.source_system = j.source_system AND a.association_user_id = j.user_id AND
+                    a.role_id = j.role_id AND a.server_id = j.server_id AND a.game_id = j.game_id
+                    LEFT JOIN (
+                        SELECT
+                            source_system ,
+                            id,
+                            name
+                        FROM dm_game_order.t_game_super
+                    ) s on d.source_system = s.source_system AND d.super_game_id = s.id
+                    LEFT JOIN (
+                        SELECT
+                            -- 原始服名
+                            source_system,
+                            game_id,
+                            server_id,
+                            server_name
+                        FROM dm_game_order.t_game_server_merge
+                        WHERE is_delete = 0
+                    ) t on a.source_system = t.source_system AND a.server_id = t.server_id AND d.super_game_id = t.game_id
+                    LEFT JOIN (
+                        SELECT
+                            -- vip等级
+                            source_system ,
+                            super_game_id ,
+                            parent_game_id ,
+                            recharge_money_min ,
+                            recharge_money_max ,
+                            vip_level ,
+                            is_delete
+                        FROM dm_game_order.t_game_vip
+                        WHERE is_delete = 0
+                    ) w on d.source_system = w.source_system AND IFNULL(d.parent_id, a.game_id) = w.parent_game_id
+                    AND IFNULL(d.super_game_id, a.game_id) = w.super_game_id
+                    AND c.amount >= w.recharge_money_min AND c.amount < recharge_money_max
+                    LEFT JOIN (
+                        SELECT
+                            source_system,
+                            id,
+                            create_time,
+                            end_time,
+                            agent_id,
+                            association_user_id
+                        FROM dm_game_order.t_game_user_burst
+                    ) x on a.source_system = x.source_system AND a.association_user_id = x.id
+                    AND a.create_time >= x.create_time AND a.create_time < x.end_time
+                    LEFT JOIN (
+                        SELECT
+                            -- 渠道名称、投手id
+                            source_system,
+                            id,
+                            agent_name,
+                            pitcher_id as put_user_id
+                        FROM dm_game_order.t_pitcher_agent
+                    ) y ON x.agent_id = y.id AND x.source_system = y.source_system
+                ) a
+                """ + criA;
+    }
+
+
+
     /**
      * 原始服-父游戏维度(区服相关信息)
      * @return String

+ 5 - 4
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/task/GameMonitorAlarmTask.java

@@ -26,18 +26,19 @@ public class GameMonitorAlarmTask {
     private boolean run;
 
     /**
-     * 任务每5分钟运行一次
+     * 任务每3分钟运行一次
      */
-    @Scheduled(cron = "0 0/5 * * * ? ")
+    @Scheduled(cron = "0 0/3 * * * ? ")
     public void run() {
         if (!run) {
             return;
         }
-        log.error("游戏监控告警定时任务开始.");
+        log.info("游戏监控告警定时任务开始.");
         try {
             gameMonitorAlarmService.sendMsgToUser();
+            log.info("游戏监控告警定时任务结束.");
         } catch (Exception e) {
-            log.error("定时任务游戏监控告警出错", e);
+            log.info("定时任务游戏监控告警出错", e);
         }
     }
 

+ 55 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/task/OrderCostMonitorAlarmTask.java

@@ -0,0 +1,55 @@
+package com.zanxiang.game.data.serve.task;
+
+import com.zanxiang.game.data.serve.service.IOrderCostMonitorAlarmService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+
+/**
+ * @author ZhangXianyu
+ * @version 1.0
+ * @description: 表监控告警定时任务 (监控订单表、头条广告消耗表、腾讯广告消耗表)
+ * @date 2024-03-20 15:25:44
+ */
+@Slf4j
+@Component
+public class OrderCostMonitorAlarmTask {
+
+    @Resource
+    private IOrderCostMonitorAlarmService  orderCostMonitorAlarmService;
+
+    @Value("${sys-config.task_is_run}")
+    private boolean run;
+
+    /**
+     * 任务每10分钟运行一次
+     */
+    @Scheduled(cron = "0 0/10 * * * ? ")
+    public void run() {
+        //本地不运行
+        if(!run){
+            return;
+        }
+        //0点0分到0点30分不执行
+        LocalDateTime now = LocalDateTime.now();
+        if(now.getHour() == 0 && now.getMinute() <= 30){
+            return;
+        }
+        log.info("订单与消耗监控告警定时任务开始.");
+        try {
+            //监控订单表
+            orderCostMonitorAlarmService.monitorDataStatus();
+            //监控头条广告消耗表
+            orderCostMonitorAlarmService.monitorHeadCostStatus();
+            //监控腾讯广告消耗表
+            orderCostMonitorAlarmService.monitorTencentCostStatus();
+            log.info("订单与消耗监控告警定时任务结束.");
+        } catch (Exception e) {
+            log.error("定时任务订单与消耗监控告警出错", e);
+        }
+    }
+}

+ 272 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/utils/RedisUtil.java

@@ -0,0 +1,272 @@
+package com.zanxiang.game.data.serve.utils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.*;
+import org.springframework.stereotype.Component;
+
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author : lingfeng
+ * @time : 2021-11-23
+ * @description : redis缓存通用前缀
+ */
+@Component
+@Slf4j
+public class RedisUtil<T> {
+
+    @Autowired
+    private RedisTemplate redisTemplate;
+
+    /**
+     * 设置缓存
+     *
+     * @param key  : 缓存key
+     * @param t    : 缓存对象
+     * @param time : 过期时间
+     * @return : 返回是否设置成功
+     */
+    public boolean setCache(String key, T t, long time) {
+        try {
+            ValueOperations<String, T> operations = redisTemplate.opsForValue();
+            operations.set(key, t, time, TimeUnit.SECONDS);
+            return true;
+        } catch (Exception e) {
+            log.error("缓存添加异常, key : {}, value : {}, e : {}", key, t, e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * 获取缓存方法
+     *
+     * @param key : 缓存key
+     * @return : 返回缓存对象
+     */
+    public T getCache(String key) {
+        try {
+            if (redisTemplate.hasKey(key)) {
+                ValueOperations<String, T> operations = redisTemplate.opsForValue();
+                return operations.get(key);
+            }
+        } catch (Exception e) {
+            log.error("获取缓存异常, key : {}, e : {}", key, e.getMessage());
+        }
+        return null;
+    }
+
+    /**
+     * redis 事物锁设置方法
+     *
+     * @param key  : 缓存key
+     * @param t    : 缓存对象
+     * @param time : 过期时间
+     * @return : 返回是否设置成功
+     */
+    public boolean setIfAbsent(String key, T t, long time) {
+        try {
+            ValueOperations<String, T> operations = redisTemplate.opsForValue();
+            return operations.setIfAbsent(key, t, time, TimeUnit.SECONDS);
+        } catch (Exception e) {
+            log.error("缓存添加异常, key : {}, value : {}, e : {}", key, t, e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * 删除缓存的方法
+     *
+     * @param key : 缓存key
+     * @return : 返回缓存对象
+     */
+    public boolean deleteCache(String key) {
+        try {
+            if (redisTemplate.hasKey(key)) {
+                return redisTemplate.delete(key);
+            }
+        } catch (Exception e) {
+            log.error("删除缓存异常, key : {}, e : {}", key, e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * set集合添加元素
+     *
+     * @param key : 缓存key
+     * @param t   : 需要添加的元素
+     * @return : 返回是否添加成功
+     */
+    public boolean addToSet(String key, T... t) {
+        try {
+            SetOperations<String, T> setOperations = redisTemplate.opsForSet();
+            Long add = setOperations.add(key, t);
+            return add != null && add >= 1;
+        } catch (Exception e) {
+            log.error("Set添加失败,key : {}, e : {}", key, e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * set集合删除元素
+     *
+     * @param key : 缓存key
+     * @param t   : 需要删除的元素
+     * @return : 返回是否删除成功
+     */
+    public boolean removeOfSet(String key, T... t) {
+        try {
+            SetOperations<String, T> setOperations = redisTemplate.opsForSet();
+            Long remove = setOperations.remove(key, t);
+            return remove != null && remove >= 1;
+        } catch (Exception e) {
+            log.error("Set删除失败,key : {}, e : {}", key, e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * 判断元素是否存在于set集合
+     *
+     * @param key : 缓存key
+     * @param t   : 需要判断的元素
+     * @return : 判断元素是否存在
+     */
+    public boolean isMemberInSet(String key, T t) {
+        try {
+            SetOperations<String, T> setOperations = redisTemplate.opsForSet();
+            return setOperations.isMember(key, t);
+        } catch (Exception e) {
+            log.error("Set元素是否存在判断异常, key : {}, e : {}", key, e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * 添加单个缓存到list
+     *
+     * @param key   : 缓存key
+     * @param t     : 缓存元素
+     * @param isTop : isTop :  真:前 假:后
+     * @return : 返回添加结果
+     */
+    public boolean setListCache(String key, T t, boolean isTop) {
+        try {
+            ListOperations<String, T> listOperations = redisTemplate.opsForList();
+            if (isTop) {
+                listOperations.leftPush(key, t);
+            } else {
+                listOperations.rightPush(key, t);
+            }
+            return true;
+        } catch (Exception e) {
+            log.error("redis添加队列元素失败,key : {}, e : {}", key, e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * 获取列表中的前or后的值
+     *
+     * @param key   : 缓存key
+     * @param isTop :  真:前 假:后
+     * @return : 返回缓存数据
+     */
+    public T getListOneCache(String key, boolean isTop) {
+        try {
+            if (redisTemplate.hasKey(key)) {
+                ListOperations<String, T> listOperations = redisTemplate.opsForList();
+                T t = null;
+                if (isTop) {
+                    t = listOperations.leftPop(key);
+                } else {
+                    t = listOperations.rightPop(key);
+                }
+                return t;
+            }
+
+        } catch (Exception e) {
+            log.error("redis获取队列元素失败,key : {}, e : {}", key, e.getMessage());
+        }
+        return null;
+    }
+
+    /**
+     * 添加单个元素进入有序集合
+     *
+     * @param key   : 缓存key
+     * @param t     : 缓存值
+     * @param score : 分数
+     * @return : 返回是否添加成功
+     */
+    public boolean addZSet(String key, T t, double score) {
+        try {
+            ZSetOperations zSet = redisTemplate.opsForZSet();
+            Boolean add = zSet.add(key, t, score);
+            return add == null ? false : add;
+        } catch (Exception e) {
+            log.error("ZSet添加失败元素失败, key : {}, t : {}, score : {}, e : {}", key, t.toString(), score, e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * 获取分数区间
+     *
+     * @param key : 缓存key
+     * @param min : 最小值
+     * @param max : 最大值
+     * @return {@link Set}<{@link T}>
+     */
+    public Set<T> getZSetByScore(String key, Double min, Double max) {
+        try {
+            ZSetOperations<String, T> zSet = redisTemplate.opsForZSet();
+            Set<T> set = zSet.rangeByScore(key, min, max);
+            return set;
+        } catch (Exception e) {
+            log.error("ZSet获取元素失败, key : {}, min : {}, max : {}, e : {}", key, min, max, e.getMessage());
+        }
+        return null;
+    }
+
+
+    /**
+     * 按照索引区间获取(按分数正序排序)
+     * (0, -1)表示获取全部
+     *
+     * @param key   : 缓存key
+     * @param start : 开始
+     * @param end   : 结束
+     * @return {@link Set}<{@link T}>
+     */
+    public Set<T> rangeZSet(String key, long start, long end) {
+        try {
+            ZSetOperations<String, T> zSet = redisTemplate.opsForZSet();
+            return zSet.range(key, start, end);
+        } catch (Exception e) {
+            log.error("ZSet获取元素失败, key : {}, start : {}, end : {}, e : {}", key, start, end, e.getMessage());
+        }
+        return null;
+    }
+
+    /**
+     * 按照缓存值删除
+     *
+     * @param key : 缓存key
+     * @param t   : 缓存值
+     * @return boolean : 删除结果
+     */
+    public boolean delZSetValue(String key, T t) {
+        try {
+            ZSetOperations<String, T> zSet = redisTemplate.opsForZSet();
+            Long remove = zSet.remove(key, t);
+            return remove != null && remove == 1;
+        } catch (Exception e) {
+            log.error("ZSet删除元素失败, key : {}, t : {}, , e : {}", key, t, e.getMessage());
+        }
+        return false;
+    }
+}

+ 134 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/utils/SpringUtils.java

@@ -0,0 +1,134 @@
+package com.zanxiang.game.data.serve.utils;
+
+import org.springframework.aop.framework.AopContext;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+/**
+ * spring工具类 方便在非spring管理环境中获取bean
+ */
+@Component
+public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware 
+{
+    /** Spring应用上下文环境 */
+    private static ConfigurableListableBeanFactory beanFactory;
+
+    private static ApplicationContext applicationContext;
+
+    @Override
+    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException 
+    {
+        SpringUtils.beanFactory = beanFactory;
+    }
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException 
+    {
+        SpringUtils.applicationContext = applicationContext;
+    }
+
+    /**
+     * 获取对象
+     *
+     * @param name
+     * @return Object 一个以所给名字注册的bean的实例
+     * @throws BeansException
+     *
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getBean(String name) throws BeansException
+    {
+        return (T) beanFactory.getBean(name);
+    }
+
+    /**
+     * 获取类型为requiredType的对象
+     *
+     * @param clz
+     * @return
+     * @throws BeansException
+     *
+     */
+    public static <T> T getBean(Class<T> clz) throws BeansException
+    {
+        T result = beanFactory.getBean(clz);
+        return result;
+    }
+
+    /**
+     * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
+     *
+     * @param name
+     * @return boolean
+     */
+    public static boolean containsBean(String name)
+    {
+        return beanFactory.containsBean(name);
+    }
+
+    /**
+     * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
+     *
+     * @param name
+     * @return boolean
+     * @throws NoSuchBeanDefinitionException
+     *
+     */
+    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException
+    {
+        return beanFactory.isSingleton(name);
+    }
+
+    /**
+     * @param name
+     * @return Class 注册对象的类型
+     * @throws NoSuchBeanDefinitionException
+     *
+     */
+    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException
+    {
+        return beanFactory.getType(name);
+    }
+
+    /**
+     * 如果给定的bean名字在bean定义中有别名,则返回这些别名
+     *
+     * @param name
+     * @return
+     * @throws NoSuchBeanDefinitionException
+     *
+     */
+    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
+    {
+        return beanFactory.getAliases(name);
+    }
+
+    /**
+     * 获取aop代理对象
+     * 
+     * @param invoker
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getAopProxy(T invoker)
+    {
+        return (T) AopContext.currentProxy();
+    }
+
+    /**
+     * 获取当前的环境配置,无配置返回null
+     *
+     * @return 当前的环境配置
+     */
+    public static String[] getActiveProfiles()
+    {
+        return applicationContext.getEnvironment().getActiveProfiles();
+    }
+
+
+}

+ 74 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/utils/Threads.java

@@ -0,0 +1,74 @@
+package com.zanxiang.game.data.serve.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.*;
+
+
+/**
+  * @author ZhangXianyu
+  * {@code @date} 2024/3/22
+  * {@code @description} 线程工具类
+ */
+public class Threads {
+    private static final Logger logger = LoggerFactory.getLogger(Threads.class);
+
+    /**
+     * sleep等待,单位为毫秒
+     */
+    public static void sleep(long milliseconds) {
+        try {
+            Thread.sleep(milliseconds);
+        } catch (InterruptedException e) {
+            return;
+        }
+    }
+
+    /**
+     * 停止线程池
+     * 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务.
+     * 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数.
+     * 如果仍然超時,則強制退出.
+     * 另对在shutdown时线程本身被调用中断做了处理.
+     */
+    public static void shutdownAndAwaitTermination(ExecutorService pool) {
+        if (pool != null && !pool.isShutdown()) {
+            pool.shutdown();
+            try {
+                if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
+                    pool.shutdownNow();
+                    if (!pool.awaitTermination(120, TimeUnit.SECONDS)) {
+                        logger.info("Pool did not terminate");
+                    }
+                }
+            } catch (InterruptedException ie) {
+                pool.shutdownNow();
+                Thread.currentThread().interrupt();
+            }
+        }
+    }
+
+    /**
+     * 打印线程异常信息
+     */
+    public static void printException(Runnable r, Throwable t) {
+        if (t == null && r instanceof Future<?>) {
+            try {
+                Future<?> future = (Future<?>) r;
+                if (future.isDone()) {
+                    future.get();
+                }
+            } catch (CancellationException ce) {
+                t = ce;
+            } catch (ExecutionException ee) {
+                t = ee.getCause();
+            } catch (InterruptedException ie) {
+                Thread.currentThread().interrupt();
+            }
+        }
+        if (t != null) {
+            logger.error(t.getMessage(), t);
+        }
+    }
+}

+ 1 - 1
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/ManageApplication.java

@@ -23,7 +23,7 @@ public class ManageApplication {
 
     public static void main(String[] args) {
         SpringApplication.run(ManageApplication.class, args);
-        System.out.println("赞象Manage服务启动成功 < (处理Websocket导致的token入侵问题02´・・)ノ(._.`) \n" +
+        System.out.println("赞象Manage服务启动成功 < (CP消息推送兼容配置修改´・・)ノ(._.`) \n" +
                 "___  ___  ___   _   _   ___  _____  _____ \n" +
                 "|  \\/  | / _ \\ | \\ | | / _ \\|  __ \\|  ___|\n" +
                 "| .  . |/ /_\\ \\|  \\| |/ /_\\ \\ |  \\/| |__  \n" +

+ 29 - 10
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/CpSendMsgLogServiceImpl.java

@@ -6,16 +6,17 @@ import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zanxiang.game.module.manage.enums.CpSendRoleResultEnum;
 import com.zanxiang.game.module.manage.pojo.dto.CpSendMsgResultDTO;
-import com.zanxiang.game.module.manage.service.ICpSendMsgLogService;
-import com.zanxiang.game.module.manage.service.ICpSendMsgResultService;
-import com.zanxiang.game.module.manage.service.IGameUserRoleService;
+import com.zanxiang.game.module.manage.pojo.dto.GameDTO;
+import com.zanxiang.game.module.manage.service.*;
 import com.zanxiang.game.module.mybatis.entity.CpSendMsgLog;
 import com.zanxiang.game.module.mybatis.entity.CpSendMsgResult;
+import com.zanxiang.game.module.mybatis.entity.GameSupper;
 import com.zanxiang.game.module.mybatis.entity.GameUserRole;
 import com.zanxiang.game.module.mybatis.mapper.CpSendMsgLogMapper;
 import com.zanxiang.module.util.JsonUtil;
 import com.zanxiang.module.util.exception.BaseException;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpEntity;
 import org.springframework.http.HttpHeaders;
@@ -41,14 +42,18 @@ public class CpSendMsgLogServiceImpl extends ServiceImpl<CpSendMsgLogMapper, CpS
 
     private static final String SIGN_MD5 = "MD5";
 
-    private static final String CP_API_KEY = "355b7f07125c1ef71cfd10166e0b90aa";
-
     @Autowired
     private TransactionTemplate transactionTemplate;
 
     @Autowired
     private RestTemplate restTemplate;
 
+    @Autowired
+    private IGameService gameService;
+
+    @Autowired
+    private IGameSupperService gameSupperService;
+
     @Autowired
     private IGameUserRoleService gameUserRoleService;
 
@@ -67,6 +72,20 @@ public class CpSendMsgLogServiceImpl extends ServiceImpl<CpSendMsgLogMapper, CpS
         CpSendMsgLog cpSendMsgLog = this.transform(taskId, gameId, msgId, gameUserRoleList.size());
         super.save(cpSendMsgLog);
         if (CollectionUtils.isEmpty(gameUserRoleList)) {
+            log.error("CP发送消息参数错误, 角色列表信息不存在! taskId : {}, gameId : {}, roleIdList : {}",
+                    taskId, gameId, JsonUtil.toString(roleIdList));
+            return;
+        }
+        GameDTO gameDTO = gameService.getById(gameId);
+        if (gameDTO == null) {
+            log.error("CP发送消息参数错误, 游戏信息不存在! taskId : {}, gameId : {}, roleIdList : {}",
+                    taskId, gameId, JsonUtil.toString(roleIdList));
+            return;
+        }
+        GameSupper gameSupper = gameSupperService.getById(gameDTO.getSuperGameId());
+        if (gameSupper == null || Strings.isBlank(gameSupper.getCpSendMsgUrl()) || Strings.isBlank(gameSupper.getCpSendMsgKey())) {
+            log.error("CP发送消息参数错误, 超父游戏信息不全! taskId : {}, gameId : {}, roleIdList : {}, gameSupper : {}",
+                    taskId, gameId, JsonUtil.toString(roleIdList), JsonUtil.toString(gameSupper));
             return;
         }
         //角色信息按区服分组
@@ -75,7 +94,7 @@ public class CpSendMsgLogServiceImpl extends ServiceImpl<CpSendMsgLogMapper, CpS
         serverIdRoleMap.forEach((serverId, roleList) -> {
             List<String> serverRoleIdList = roleList.stream().map(GameUserRole::getRoleId).collect(Collectors.toList());
             try {
-                CpSendMsgResultDTO result = this.cpSendMsgApi(msgId, serverId, serverRoleIdList, text);
+                CpSendMsgResultDTO result = this.cpSendMsgApi(gameSupper, msgId, serverId, text, serverRoleIdList);
                 this.resultHandle(cpSendMsgLog, result, serverId, serverRoleIdList);
             } catch (Exception e) {
                 log.error("CP消息发送API调用异常, serverId : {}, roleList : {}", serverId, roleList);
@@ -130,13 +149,14 @@ public class CpSendMsgLogServiceImpl extends ServiceImpl<CpSendMsgLogMapper, CpS
                 .build();
     }
 
-    private CpSendMsgResultDTO cpSendMsgApi(String msgId, String serverId, List<String> roleIdList, String text) throws Exception {
+    private CpSendMsgResultDTO cpSendMsgApi(GameSupper gameSupper, String msgId, String serverId, String text,
+                                            List<String> roleIdList) throws Exception {
         long time = System.currentTimeMillis() / 1000;
         Map<String, Object> param = new HashMap<>(8);
         param.put("msgId", msgId);
         param.put("strRan", msgId);
         param.put("time", time);
-        param.put("sign", this.MD5("key=" + CP_API_KEY + "&msgId=" + msgId + "&strRan=" + msgId + "&time=" + time));
+        param.put("sign", this.MD5("key=" + gameSupper.getCpSendMsgKey() + "&msgId=" + msgId + "&strRan=" + msgId + "&time=" + time));
         param.put("pushType", 1);
         param.put("serverid", serverId);
         param.put("roleIds", roleIdList);
@@ -153,8 +173,7 @@ public class CpSendMsgLogServiceImpl extends ServiceImpl<CpSendMsgLogMapper, CpS
         HttpEntity<String> request = new HttpEntity<>(JsonUtil.toString(param), headers);
         String result;
         try {
-            result = restTemplate.postForObject("https://ht.lttx.t5yx.cn/extapi?action=BgzszhSendTip",
-                    request, String.class);
+            result = restTemplate.postForObject(gameSupper.getCpSendMsgUrl(), request, String.class);
         } catch (Exception e) {
             System.out.println(e.getMessage());
             throw new BaseException("消息发送失败");

+ 10 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/GameSupper.java

@@ -40,6 +40,16 @@ public class GameSupper implements Serializable {
      */
     private String name;
 
+    /**
+     * CP发消息地址
+     */
+    private String cpSendMsgUrl;
+
+    /**
+     * CP发消息key
+     */
+    private String cpSendMsgKey;
+
     /**
      * 1 删除  0 正常
      */

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels