Forráskód Böngészése

修改内容:游戏区服添加留存数据

lth 1 éve
szülő
commit
87ced4ec77

+ 3 - 2
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/AdsGameServerController.java

@@ -1,5 +1,6 @@
 package com.zanxiang.game.data.serve.controller;
 
+import com.zanxiang.erp.security.annotation.PreAuthorize;
 import com.zanxiang.game.data.serve.pojo.dto.GameServerDayDTO;
 import com.zanxiang.game.data.serve.pojo.dto.GameServerDayTotalDTO;
 import com.zanxiang.game.data.serve.pojo.vo.GameServerDayTotalVO;
@@ -31,14 +32,14 @@ public class AdsGameServerController {
     private IGameServerService gameServerService;
 
     @ApiOperation(value = "游戏区服数据")
-    //@PreAuthorize(permissionKey = "gameServer:adsGameServerDay:day")
+    @PreAuthorize(permissionKey = "gameServer:adsGameServerDay:day")
     @PostMapping("/day")
     public ResultVO<Page<GameServerDayVO>> getGameServerDataDay(@RequestBody GameServerDayDTO dto) {
         return ResultVO.ok(gameServerService.getGameServerDataDay(dto));
     }
 
     @ApiOperation(value = "游戏区服数据总计一栏")
-    //@PreAuthorize(permissionKey = "gameServer:adsGameServerDay:dayTotal")
+    @PreAuthorize(permissionKey = "gameServer:adsGameServerDay:dayTotal")
     @PostMapping("/day/total")
     public ResultVO<GameServerDayTotalVO> getGameServerDataDayTotal(@RequestBody GameServerDayTotalDTO dto) {
         return ResultVO.ok(gameServerService.getGameServerDataDayTotal(dto));

+ 486 - 29
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GameServerServiceImpl.java

@@ -193,6 +193,10 @@ public class GameServerServiceImpl implements IGameServerService {
     @Override
     public GameServerDayTotalVO getGameServerDataDayTotal(GameServerDayTotalDTO dto) {
         List<Long> gameIds = dto.getGameId() == null ? dataPowerComponent.getSubGameIdList() : Collections.singletonList(dto.getGameId());
+        //默认查询注册留存数据
+        if (StringUtils.isBlank(dto.getActiveTypes())) {
+            dto.setActiveTypes("reg");
+        }
         //创建查询条件
         Criteria cri = Cnd.cri();
         if (gameIds != null) {
@@ -216,7 +220,7 @@ public class GameServerServiceImpl implements IGameServerService {
             cri.where().andEquals("source_system", dto.getSourceSystem());
         }
         //创建sql语句查询数据
-        Sql sql = Sqls.create(gameServerDayTotalSql() + cri);
+        Sql sql = Sqls.create(gameServerDayTotalSql(dto.getActiveTypes()) + cri);
         //设置自定义回传对象
         sql.setCallback(Sqls.callback.entity());
         sql.setEntity(dao.getEntity(GameServerDayTotalVO.class));
@@ -225,7 +229,7 @@ public class GameServerServiceImpl implements IGameServerService {
         //得到查询的结果
         GameServerDayTotalVO vo = sql.getObject(GameServerDayTotalVO.class);
         if (StringUtils.isNotBlank(vo.getDa1())) {
-            formatTotalDayN(vo);
+            formatTotalDayN(vo, dto.getActiveTypes());
         }
         //返回结果
         return vo;
@@ -276,32 +280,99 @@ public class GameServerServiceImpl implements IGameServerService {
     /**
      * 将vo中的原始String数据修改为一个对象
      * @param vo 展示给前端的游戏区服数据总计
+     * @param activeType 查询的留存类型 reg -> 注册留存 ; role -> 角色留存 ; amount -> 付费留存
      */
-    private void formatTotalDayN(GameServerDayTotalVO vo) {
+    private void formatTotalDayN(GameServerDayTotalVO vo, String activeType) {
         if (CollectionUtils.isEmpty(dayNTotalFieldMapList)) {
             return;
         }
         dayNTotalFieldMapList.forEach(dayNTotalFieldMap -> {
             try {
+                /*注册人数0/创角人数1/活跃人数2/付费人数3/付费金额4/滚服人数5/滚服付费人数6/滚服付费金额7/ (游戏区服数据)*/
                 String[] temps = ((String) dayNTotalFieldMap.getT1().get(vo)).split("/");
                 //付费金额
                 BigDecimal amount = new BigDecimal(temps[4]);
                 //滚服付费金额
                 BigDecimal rollServerAmount = new BigDecimal(temps[7]);
-                //设置trend对象
-                dayNTotalFieldMap.getT2().set(vo, GameServerTrendVO.builder()
-                        .regNum(Long.parseLong(temps[0]))
-                        .roleNum(Long.parseLong(temps[1]))
-                        .activeNum(Long.parseLong(temps[2]))
-                        .amountNum(Long.parseLong(temps[3]))
-                        .amount(amount)
-                        .rollServerNum(Long.parseLong(temps[5]))
-                        .rollServerAmountNum(Long.parseLong(temps[6]))
-                        .rollServerAmount(rollServerAmount)
-                        .rollServerAmountRate(amount.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO :
-                                rollServerAmount.divide(amount, 4, RoundingMode.HALF_UP))
-                        .build()
-                );
+                //不同留存数据
+                if ("reg".equals(activeType)) {
+                    //注册留存
+                    /* DayN活跃人数8/ (注册留存数据)/ 注册人数9(去除时间未到的数据)*/
+                    //活跃人数(注册留存数据)
+                    Long regActiveNum = Long.valueOf(temps[8]);
+                    //注册人数(注册留存数据)
+                    Long regNum = Long.valueOf(temps[9]);
+                    //设置trend对象
+                    dayNTotalFieldMap.getT2().set(vo, GameServerTrendVO.builder()
+                            .regNum(Long.parseLong(temps[0]))
+                            .roleNum(Long.parseLong(temps[1]))
+                            .activeNum(Long.parseLong(temps[2]))
+                            .amountNum(Long.parseLong(temps[3]))
+                            .amount(amount)
+                            .rollServerNum(Long.parseLong(temps[5]))
+                            .rollServerAmountNum(Long.parseLong(temps[6]))
+                            .rollServerAmount(rollServerAmount)
+                            .rollServerAmountRate(amount.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO :
+                                    rollServerAmount.divide(amount, 4, RoundingMode.HALF_UP))
+                            .regActiveNum(regActiveNum)
+                            .regActiveRate(regNum == 0L ? BigDecimal.ZERO :
+                                    BigDecimal.valueOf(regActiveNum.doubleValue() / regNum.doubleValue()).setScale(4, RoundingMode.HALF_UP))
+                            .build());
+                } else if ("amount".equals(activeType)) {
+                    //付费留存
+                    /* 第N天的新增付费用户8/第N天的老活跃用户9/第N天的累计付费用户10/第N天的累计活跃用户11/(付费留存数据)*/
+                    //累计到第N天的付费人数(付费留存数据)
+                    Long amountTotalNum = Long.parseLong(temps[10]);
+                    //累计到第N天的活跃人数(付费留存数据)
+                    Long amountActiveTotalNum = Long.valueOf(temps[11]);
+                    //设置trend对象
+                    dayNTotalFieldMap.getT2().set(vo, GameServerTrendVO.builder()
+                            .regNum(Long.parseLong(temps[0]))
+                            .roleNum(Long.parseLong(temps[1]))
+                            .activeNum(Long.parseLong(temps[2]))
+                            .amountNum(Long.parseLong(temps[3]))
+                            .amount(amount)
+                            .rollServerNum(Long.parseLong(temps[5]))
+                            .rollServerAmountNum(Long.parseLong(temps[6]))
+                            .rollServerAmount(rollServerAmount)
+                            .rollServerAmountRate(amount.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO :
+                                    rollServerAmount.divide(amount, 4, RoundingMode.HALF_UP))
+                            .newUserAmountNum(Long.parseLong(temps[8]))
+                            .oldActiveUserNum(Long.valueOf(temps[9]))
+                            .newUserTotalAmountNum(amountTotalNum)
+                            .newActiveUserTotalNum(amountActiveTotalNum)
+                            .amountActiveRate(amountTotalNum == 0L ? BigDecimal.ZERO :
+                                    BigDecimal.valueOf(amountActiveTotalNum.doubleValue() / amountTotalNum.doubleValue())
+                                            .setScale(4, RoundingMode.HALF_UP))
+                            .build());
+                } else {
+                    /* 第N天的新增创角用户8/第N天的老活跃用户9/第N天的累计创角用户10/第N天的累计活跃用户11/(创角留存数据)*/
+                    //创角留存
+                    //累计到第N天的创角用户数
+                    Long roleActiveTotalNum = Long.valueOf(temps[10]);
+                    //累计到第N天的活跃人数(活跃人数)
+                    Long roleActiveUserNum = Long.valueOf(temps[11]);
+                    //设置trend对象
+                    dayNTotalFieldMap.getT2().set(vo, GameServerTrendVO.builder()
+                            .regNum(Long.parseLong(temps[0]))
+                            .roleNum(Long.parseLong(temps[1]))
+                            .activeNum(Long.parseLong(temps[2]))
+                            .amountNum(Long.parseLong(temps[3]))
+                            .amount(amount)
+                            .rollServerNum(Long.parseLong(temps[5]))
+                            .rollServerAmountNum(Long.parseLong(temps[6]))
+                            .rollServerAmount(rollServerAmount)
+                            .rollServerAmountRate(amount.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO :
+                                    rollServerAmount.divide(amount, 4, RoundingMode.HALF_UP))
+                            .roleNewUserNum(Long.valueOf(temps[8]))
+                            .roleOldActiveUserNum(Long.valueOf(temps[9]))
+                            .roleNewUserTotalNum(roleActiveTotalNum)
+                            .roleNewActiveUserTotalNum(roleActiveUserNum)
+                            .roleActiveRate(roleActiveTotalNum == 0L ? BigDecimal.ZERO :
+                                    BigDecimal.valueOf(roleActiveUserNum.doubleValue() / roleActiveTotalNum.doubleValue())
+                                            .setScale(4, RoundingMode.HALF_UP))
+                            .build());
+                }
             } catch (IllegalAccessException e) {
                 e.printStackTrace();
             }
@@ -311,9 +382,8 @@ public class GameServerServiceImpl implements IGameServerService {
 
     /**
      * 计算总计一栏的daN数据
-     * @return String
      * 注册人数/创角人数/活跃人数/付费人数/付费金额/滚服人数/滚服付费人数/滚服付费金额/ (游戏区服数据)
-     * DayN活跃人数/ (注册留存数据)
+     * DayN活跃人数/ (注册留存数据)/ 注册人数(去除时间未到的数据)
      * 第N天的新增付费用户/第N天的老活跃用户/第N天的累计付费用户/第N天的累计活跃用户/ (付费留存数据)
      * 第N天的新增创角用户/第N天的老活跃用户/第N天的累计创角用户/第N天的累计活跃用户/ (创角留存数据)
      */
@@ -330,9 +400,15 @@ public class GameServerServiceImpl implements IGameServerService {
                     	SUM(SPLIT_PART(da%s, '/', 5)), '/',
                     	SUM(SPLIT_PART(da%s, '/', 6)), '/',
                     	SUM(SPLIT_PART(da%s, '/', 7)), '/',
-                    	SUM(SPLIT_PART(da%s, '/', 8))
+                    	SUM(SPLIT_PART(da%s, '/', 8)), '/',
+                    	SUM(SPLIT_PART(da%s, '/', 10)), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s day) <= Local.now(), total_reg_num, 0)), '/',
+                        SUM(SPLIT_PART(da%s, '/', 12)), '/',
+                        SUM(SPLIT_PART(da%s, '/', 13)), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s day) <= Local.now(), SPLIT_PART(da%s, '/', 14), 0)), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s day) <= Local.now(), SPLIT_PART(da%s, '/', 15), 0))
                     ) as da%s ,
-                    """.formatted(i, i, i, i, i, i, i, i, i));
+                    """.formatted(i, i, i, i, i, i, i, i, i, i-1,i ,i, i-1, i, i-1, i, i ));
         }
         //拼接m4-m12 sql
         for (int i = 4; i <= 12; i++) {
@@ -345,9 +421,15 @@ public class GameServerServiceImpl implements IGameServerService {
                     	SUM(SPLIT_PART(m%s, '/', 5)), '/',
                     	SUM(SPLIT_PART(m%s, '/', 6)), '/',
                     	SUM(SPLIT_PART(m%s, '/', 7)), '/',
-                    	SUM(SPLIT_PART(m%s, '/', 8))
+                    	SUM(SPLIT_PART(m%s, '/', 8)), '/',
+                    	SUM(SPLIT_PART(m%s, '/', 10)), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s month) <= Local.now(), total_reg_num, 0)), '/',
+                        SUM(SPLIT_PART(m%s, '/', 12)), '/',
+                        SUM(SPLIT_PART(m%s, '/', 13)), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s month) <= Local.now(), SPLIT_PART(m%s, '/', 14), 0)), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s month) <= Local.now(), SPLIT_PART(m%s, '/', 15), 0))
                     ) as m%s ,
-                    """.formatted(i, i, i, i, i, i, i, i, i));
+                    """.formatted(i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i));
         }
         //拼接total
         daySql.append("""
@@ -359,9 +441,264 @@ public class GameServerServiceImpl implements IGameServerService {
                     	SUM(SPLIT_PART(total, '/', 5)), '/',
                     	SUM(SPLIT_PART(total, '/', 6)), '/',
                     	SUM(SPLIT_PART(total, '/', 7)), '/',
-                    	SUM(SPLIT_PART(total, '/', 8))
+                    	SUM(SPLIT_PART(total, '/', 8)), '/',
+                    	SUM(SPLIT_PART(total, '/', 10)), '/',
+                        SUM(total_reg_num), '/',
+                        SUM(SPLIT_PART(total, '/', 12)), '/',
+                        SUM(SPLIT_PART(total, '/', 13)), '/',
+                        SUM(SPLIT_PART(total, '/', 14)), '/',
+                        SUM(SPLIT_PART(total, '/', 15))
+                    ) as total
+                    """);
+
+        return daySql.toString();
+    }
+
+    private String trendDayDemo1() {
+        StringBuilder daySql = new StringBuilder(StringUtils.EMPTY);
+        //拼接da1-da90 sql
+        for (int i = 1; i <= 90; i++) {
+            daySql.append("""
+                    CONCAT(
+                    	SUM(da%s[1]), '/',
+                    	SUM(da%s[2]), '/',
+                    	SUM(da%s[3]), '/',
+                    	SUM(da%s[4]), '/',
+                    	SUM(da%s[5]), '/',
+                    	SUM(da%s[6]), '/',
+                    	SUM(da%s[7]), '/',
+                    	SUM(da%s[8]), '/',
+                    	SUM(da%s[10]), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s day) <= Local.now(), total_reg_num, 0)), '/',
+                        SUM(da%s[12]), '/',
+                        SUM(da%s[13]), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s day) <= Local.now(), da%s[14], 0)), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s day) <= Local.now(), da%s[15], 0))
+                    ) as da%s ,
+                    """.formatted(i, i, i, i, i, i, i, i, i, i-1,i ,i, i-1, i, i-1, i, i ));
+        }
+        //拼接m4-m12 sql
+        for (int i = 4; i <= 12; i++) {
+            daySql.append("""
+                    CONCAT(
+                    	SUM(m%s[1]), '/',
+                    	SUM(m%s[2]), '/',
+                    	SUM(m%s[3]), '/',
+                    	SUM(m%s[4]), '/',
+                    	SUM(m%s[5]), '/',
+                    	SUM(m%s[6]), '/',
+                    	SUM(m%s[7]), '/',
+                    	SUM(m%s[8]), '/',
+                    	SUM(m%s[10]), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s month) <= Local.now(), total_reg_num, 0)), '/',
+                        SUM(m%s[12]), '/',
+                        SUM(m%s[13]), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s month) <= Local.now(), m%s[14], 0)), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s month) <= Local.now(), m%s[15], 0))
+                    ) as m%s ,
+                    """.formatted(i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i, i));
+        }
+        //拼接total
+        daySql.append("""
+                    CONCAT(
+                    	SUM(total[1]), '/',
+                    	SUM(total[2]), '/',
+                    	SUM(total[3]), '/',
+                    	SUM(total[4]), '/',
+                    	SUM(total[5]), '/',
+                    	SUM(total[6]), '/',
+                    	SUM(total[7]), '/',
+                    	SUM(total[8]), '/',
+                    	SUM(total[10]), '/',
+                        SUM(total_reg_num), '/',
+                        SUM(total[12]), '/',
+                        SUM(total[13]), '/',
+                        SUM(total[14]), '/',
+                        SUM(total[15])
+                    ) as total
+                    """);
+
+        return daySql.toString();
+    }
+
+    /**
+     * 计算总计一栏的daN数据
+     * 注册人数/创角人数/活跃人数/付费人数/付费金额/滚服人数/滚服付费人数/滚服付费金额/ (游戏区服数据)
+     * DayN活跃人数/ (注册留存数据)/ 注册人数(去除时间未到的数据)
+     * 第N天的新增付费用户/第N天的老活跃用户/第N天的累计付费用户/第N天的累计活跃用户/ (付费留存数据)
+     * 第N天的新增创角用户/第N天的老活跃用户/第N天的累计创角用户/第N天的累计活跃用户/ (创角留存数据)
+     * @param activeType reg -> 注册留存 ; role -> 角色留存 ; amount -> 付费留存
+     *
+     * @return String
+     */
+    private String trendDayDemo2(String activeType) {
+        StringBuilder daySql = new StringBuilder(StringUtils.EMPTY);
+        //注册留存数据
+        if ("reg".equals(activeType)) {
+            //拼接da1-da90 sql
+            for (int i = 1; i <= 90; i++) {
+                daySql.append("""
+                    CONCAT(
+                    	SUM(da%s[1]), '/',
+                    	SUM(da%s[2]), '/',
+                    	SUM(da%s[3]), '/',
+                    	SUM(da%s[4]), '/',
+                    	SUM(da%s[5]), '/',
+                    	SUM(da%s[6]), '/',
+                    	SUM(da%s[7]), '/',
+                    	SUM(da%s[8]), '/',
+                    	SUM(da%s[10]), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s day) <= Local.now(), total_reg_num, 0))
+                    ) as da%s ,
+                    """.formatted(i, i, i, i, i, i, i, i, i, i-1, i));
+            }
+            //拼接m4-m12 sql
+            for (int i = 4; i <= 12; i++) {
+                daySql.append("""
+                    CONCAT(
+                    	SUM(m%s[1]), '/',
+                    	SUM(m%s[2]), '/',
+                    	SUM(m%s[3]), '/',
+                    	SUM(m%s[4]), '/',
+                    	SUM(m%s[5]), '/',
+                    	SUM(m%s[6]), '/',
+                    	SUM(m%s[7]), '/',
+                    	SUM(m%s[8]), '/',
+                    	SUM(m%s[10]), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s month) <= Local.now(), total_reg_num, 0))
+                    ) as m%s ,
+                    """.formatted(i, i, i, i, i, i, i, i, i, i, i));
+            }
+            //拼接total
+            daySql.append("""
+                    CONCAT(
+                    	SUM(total[1]), '/',
+                    	SUM(total[2]), '/',
+                    	SUM(total[3]), '/',
+                    	SUM(total[4]), '/',
+                    	SUM(total[5]), '/',
+                    	SUM(total[6]), '/',
+                    	SUM(total[7]), '/',
+                    	SUM(total[8]), '/',
+                    	SUM(total[10]), '/',
+                        SUM(total_reg_num)
                     ) as total
                     """);
+        } else if ("amount".equals(activeType)) {
+            //付费留存数据
+            //拼接da1-da90 sql
+            for (int i = 1; i <= 90; i++) {
+                daySql.append("""
+                    CONCAT(
+                    	SUM(da%s[1]), '/',
+                    	SUM(da%s[2]), '/',
+                    	SUM(da%s[3]), '/',
+                    	SUM(da%s[4]), '/',
+                    	SUM(da%s[5]), '/',
+                    	SUM(da%s[6]), '/',
+                    	SUM(da%s[7]), '/',
+                    	SUM(da%s[8]), '/',
+                        SUM(da%s[12]), '/',
+                        SUM(da%s[13]), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s day) <= Local.now(), da%s[14], 0)), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s day) <= Local.now(), da%s[15], 0))
+                    ) as da%s ,
+                    """.formatted(i, i, i, i, i, i, i, i, i ,i, i-1, i, i-1, i, i ));
+            }
+            //拼接m4-m12 sql
+            for (int i = 4; i <= 12; i++) {
+                daySql.append("""
+                    CONCAT(
+                    	SUM(m%s[1]), '/',
+                    	SUM(m%s[2]), '/',
+                    	SUM(m%s[3]), '/',
+                    	SUM(m%s[4]), '/',
+                    	SUM(m%s[5]), '/',
+                    	SUM(m%s[6]), '/',
+                    	SUM(m%s[7]), '/',
+                    	SUM(m%s[8]), '/',
+                        SUM(m%s[12]), '/',
+                        SUM(m%s[13]), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s month) <= Local.now(), m%s[14], 0)), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s month) <= Local.now(), m%s[15], 0))
+                    ) as m%s ,
+                    """.formatted(i, i, i, i, i, i, i, i, i, i, i, i, i, i, i));
+            }
+            //拼接total
+            daySql.append("""
+                    CONCAT(
+                    	SUM(total[1]), '/',
+                    	SUM(total[2]), '/',
+                    	SUM(total[3]), '/',
+                    	SUM(total[4]), '/',
+                    	SUM(total[5]), '/',
+                    	SUM(total[6]), '/',
+                    	SUM(total[7]), '/',
+                    	SUM(total[8]), '/',
+                        SUM(total[12]), '/',
+                        SUM(total[13]), '/',
+                        SUM(total[14]), '/',
+                        SUM(total[15])
+                    ) as total
+                    """);
+        } else {
+            //创角留存数据
+            //拼接da1-da90 sql
+            for (int i = 1; i <= 90; i++) {
+                daySql.append("""
+                    CONCAT(
+                    	SUM(da%s[1]), '/',
+                    	SUM(da%s[2]), '/',
+                    	SUM(da%s[3]), '/',
+                    	SUM(da%s[4]), '/',
+                    	SUM(da%s[5]), '/',
+                    	SUM(da%s[6]), '/',
+                    	SUM(da%s[7]), '/',
+                    	SUM(da%s[8]), '/',
+                        SUM(da%s[17]), '/',
+                        SUM(da%s[18]), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s day) <= Local.now(), da%s[19], 0)), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s day) <= Local.now(), da%s[20], 0))
+                    ) as da%s ,
+                    """.formatted(i, i, i, i, i, i, i, i, i ,i, i-1, i, i-1, i, i ));
+            }
+            //拼接m4-m12 sql
+            for (int i = 4; i <= 12; i++) {
+                daySql.append("""
+                    CONCAT(
+                    	SUM(m%s[1]), '/',
+                    	SUM(m%s[2]), '/',
+                    	SUM(m%s[3]), '/',
+                    	SUM(m%s[4]), '/',
+                    	SUM(m%s[5]), '/',
+                    	SUM(m%s[6]), '/',
+                    	SUM(m%s[7]), '/',
+                    	SUM(m%s[8]), '/',
+                        SUM(m%s[17]), '/',
+                        SUM(m%s[18]), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s month) <= Local.now(), m%s[19], 0)), '/',
+                        SUM(IF(DATE_ADD(dt, INTERVAL %s month) <= Local.now(), m%s[20], 0))
+                    ) as m%s ,
+                    """.formatted(i, i, i, i, i, i, i, i, i, i, i, i, i, i, i));
+            }
+            //拼接total
+            daySql.append("""
+                    CONCAT(
+                    	SUM(total[1]), '/',
+                    	SUM(total[2]), '/',
+                    	SUM(total[3]), '/',
+                    	SUM(total[4]), '/',
+                    	SUM(total[5]), '/',
+                    	SUM(total[6]), '/',
+                    	SUM(total[7]), '/',
+                    	SUM(total[8]), '/',
+                        SUM(total[17]), '/',
+                        SUM(total[18]), '/',
+                        SUM(total[19]), '/',
+                        SUM(total[20])
+                    ) as total
+                    """);
+        }
 
         return daySql.toString();
     }
@@ -495,9 +832,11 @@ public class GameServerServiceImpl implements IGameServerService {
 
     /**
      * 游戏区服数据总计SQL
+     * @param activeType 查询的留存类型 reg -> 注册留存 ; role -> 角色留存 ; amount -> 付费留存
+     *
      * @return String
      */
-    private String gameServerDayTotalSql() {
+    private String gameServerDayTotalSql(String activeType) {
         return """
                 SELECT
                     IFNULL(SUM(out_total_num), 0) as out_total_num,
@@ -508,11 +847,129 @@ public class GameServerServiceImpl implements IGameServerService {
                     IFNULL(SUM(total_reg_num), 0) as total_reg_num,
                     IFNULL(SUM(total_amount_num), 0) as total_amount_num,
                     IFNULL(SUM(total_amount), 0) as total_amount,
-                """ + trendDay() +
+                """ + trendDayDemo2(activeType) +
                 """
-                FROM
-                    game_ads.ads_game_server_day
-                """;
+                FROM (
+                    SELECT
+                        dt,
+                        source_system,
+                        server_id,
+                        server_name,
+                        game_id,
+                        game_name,
+                        classify,
+                        out_total_num,
+                        out_total_amount_num,
+                        out_total_amount,
+                        out_total_rate,
+                        total_role_num,
+                        total_reg_num,
+                        total_amount_num,
+                        total_amount,
+                        SPLIT(da1, '/') as da1,
+                        SPLIT(da2, '/') as da2,
+                        SPLIT(da3, '/') as da3,
+                        SPLIT(da4, '/') as da4,
+                        SPLIT(da5, '/') as da5,
+                        SPLIT(da6, '/') as da6,
+                        SPLIT(da7, '/') as da7,
+                        SPLIT(da8, '/') as da8,
+                        SPLIT(da9, '/') as da9,
+                        SPLIT(da10, '/') as da10,
+                        SPLIT(da11, '/') as da11,
+                        SPLIT(da12, '/') as da12,
+                        SPLIT(da13, '/') as da13,
+                        SPLIT(da14, '/') as da14,
+                        SPLIT(da15, '/') as da15,
+                        SPLIT(da16, '/') as da16,
+                        SPLIT(da17, '/') as da17,
+                        SPLIT(da18, '/') as da18,
+                        SPLIT(da19, '/') as da19,
+                        SPLIT(da20, '/') as da20,
+                        SPLIT(da21, '/') as da21,
+                        SPLIT(da22, '/') as da22,
+                        SPLIT(da23, '/') as da23,
+                        SPLIT(da24, '/') as da24,
+                        SPLIT(da25, '/') as da25,
+                        SPLIT(da26, '/') as da26,
+                        SPLIT(da27, '/') as da27,
+                        SPLIT(da28, '/') as da28,
+                        SPLIT(da29, '/') as da29,
+                        SPLIT(da30, '/') as da30,
+                        SPLIT(da31, '/') as da31,
+                        SPLIT(da32, '/') as da32,
+                        SPLIT(da33, '/') as da33,
+                        SPLIT(da34, '/') as da34,
+                        SPLIT(da35, '/') as da35,
+                        SPLIT(da36, '/') as da36,
+                        SPLIT(da37, '/') as da37,
+                        SPLIT(da38, '/') as da38,
+                        SPLIT(da39, '/') as da39,
+                        SPLIT(da40, '/') as da40,
+                        SPLIT(da41, '/') as da41,
+                        SPLIT(da42, '/') as da42,
+                        SPLIT(da43, '/') as da43,
+                        SPLIT(da44, '/') as da44,
+                        SPLIT(da45, '/') as da45,
+                        SPLIT(da46, '/') as da46,
+                        SPLIT(da47, '/') as da47,
+                        SPLIT(da48, '/') as da48,
+                        SPLIT(da49, '/') as da49,
+                        SPLIT(da50, '/') as da50,
+                        SPLIT(da51, '/') as da51,
+                        SPLIT(da52, '/') as da52,
+                        SPLIT(da53, '/') as da53,
+                        SPLIT(da54, '/') as da54,
+                        SPLIT(da55, '/') as da55,
+                        SPLIT(da56, '/') as da56,
+                        SPLIT(da57, '/') as da57,
+                        SPLIT(da58, '/') as da58,
+                        SPLIT(da59, '/') as da59,
+                        SPLIT(da60, '/') as da60,
+                        SPLIT(da61, '/') as da61,
+                        SPLIT(da62, '/') as da62,
+                        SPLIT(da63, '/') as da63,
+                        SPLIT(da64, '/') as da64,
+                        SPLIT(da65, '/') as da65,
+                        SPLIT(da66, '/') as da66,
+                        SPLIT(da67, '/') as da67,
+                        SPLIT(da68, '/') as da68,
+                        SPLIT(da69, '/') as da69,
+                        SPLIT(da70, '/') as da70,
+                        SPLIT(da71, '/') as da71,
+                        SPLIT(da72, '/') as da72,
+                        SPLIT(da73, '/') as da73,
+                        SPLIT(da74, '/') as da74,
+                        SPLIT(da75, '/') as da75,
+                        SPLIT(da76, '/') as da76,
+                        SPLIT(da77, '/') as da77,
+                        SPLIT(da78, '/') as da78,
+                        SPLIT(da79, '/') as da79,
+                        SPLIT(da80, '/') as da80,
+                        SPLIT(da81, '/') as da81,
+                        SPLIT(da82, '/') as da82,
+                        SPLIT(da83, '/') as da83,
+                        SPLIT(da84, '/') as da84,
+                        SPLIT(da85, '/') as da85,
+                        SPLIT(da86, '/') as da86,
+                        SPLIT(da87, '/') as da87,
+                        SPLIT(da88, '/') as da88,
+                        SPLIT(da89, '/') as da89,
+                        SPLIT(da90, '/') as da90,
+                        SPLIT(m4, '/') as m4,
+                        SPLIT(m5, '/') as m5,
+                        SPLIT(m6, '/') as m6,
+                        SPLIT(m7, '/') as m7,
+                        SPLIT(m8, '/') as m8,
+                        SPLIT(m9, '/') as m9,
+                        SPLIT(m10, '/') as m10,
+                        SPLIT(m11, '/') as m11,
+                        SPLIT(m12, '/') as m12,
+                        SPLIT(total, '/') as total
+                    FROM
+                        game_ads.ads_game_server_day
+                ) a
+                        """;
     }