فهرست منبع

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

Letianhua 1 سال پیش
والد
کامیت
6c19bb55dd
41فایلهای تغییر یافته به همراه2068 افزوده شده و 80 حذف شده
  1. 11 4
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/ChoiceListController.java
  2. 2 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/GameDataDayDTO.java
  3. 2 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/GameDataDayTotalDTO.java
  4. 3 2
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/PitcherGameDataDayDTO.java
  5. 3 2
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/PitcherGameDataDayTotalDTO.java
  6. 5 5
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/RoleRechargeRankingDTO.java
  7. 89 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/entity/TGameVip.java
  8. 6 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/AdsOrderDetailVO.java
  9. 7 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/IVipLevelService.java
  10. 18 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/AdsOrderDetailService.java
  11. 301 6
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GameDataServiceImpl.java
  12. 248 10
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/PitcherDataServiceImpl.java
  13. 3 3
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/PromotionDayServiceImpl.java
  14. 98 45
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/RoleManageServiceImpl.java
  15. 32 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/VipLevelServiceImpl.java
  16. 1 1
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/ManageApplication.java
  17. 19 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/config/RestTemplateConfig.java
  18. 54 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/controller/GamePolicyConfigController.java
  19. 49 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/controller/KfMsgController.java
  20. 74 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/enums/KfActionEnum.java
  21. 80 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/enums/KfApiEnum.java
  22. 57 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/dto/KfMsgResultDTO.java
  23. 56 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/params/GamePolicyConfigAddOrUpdateParam.java
  24. 31 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/params/GamePolicyConfigListParam.java
  25. 38 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/params/KfApiParam.java
  26. 30 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/vo/GamePolicyConfigInnerObjVO.java
  27. 104 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/vo/GamePolicyConfigListVO.java
  28. 37 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/vo/KfGameVO.java
  29. 21 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/IGamePolicyConfigService.java
  30. 31 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/IKfMsgContentService.java
  31. 21 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/IKfUserService.java
  32. 141 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/GamePolicyConfigServiceImpl.java
  33. 122 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/KfMsgContentServiceImpl.java
  34. 31 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/KfUserServiceImpl.java
  35. 75 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/GamePolicyConfig.java
  36. 83 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/KfMsgContent.java
  37. 53 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/KfUser.java
  38. 7 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/mapper/GamePolicyConfigMapper.java
  39. 12 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/mapper/KfMsgContentMapper.java
  40. 12 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/mapper/KfUserMapper.java
  41. 1 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/LoginServiceImpl.java

+ 11 - 4
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/ChoiceListController.java

@@ -6,10 +6,7 @@ import com.zanxiang.game.data.serve.pojo.vo.AccountListVO;
 import com.zanxiang.game.data.serve.pojo.vo.AgentListVO;
 import com.zanxiang.game.data.serve.pojo.vo.GameListVO;
 import com.zanxiang.game.data.serve.pojo.vo.PitcherListVO;
-import com.zanxiang.game.data.serve.service.IAccountListService;
-import com.zanxiang.game.data.serve.service.IAgentListService;
-import com.zanxiang.game.data.serve.service.IGameListService;
-import com.zanxiang.game.data.serve.service.IPitcherListService;
+import com.zanxiang.game.data.serve.service.*;
 import com.zanxiang.module.util.pojo.ResultVO;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -43,6 +40,9 @@ public class ChoiceListController {
     @Autowired
     private IPitcherListService pitcherListService;
 
+    @Autowired
+    private IVipLevelService vipLevelService;
+
     @ApiOperation(value = "所有游戏列表")
     @PreAuthorize(permissionKey = "gameData:choice:gameList")
     @PostMapping("/game/list")
@@ -71,4 +71,11 @@ public class ChoiceListController {
         return ResultVO.ok(pitcherListService.getPitcherList(dto));
     }
 
+    @ApiOperation(value = "最大VIP等级")
+    @PreAuthorize(permissionKey = "gameData:choice:maxVipLevel")
+    @GetMapping("/vip/level")
+    public ResultVO<Integer> getMaxVipLevel() {
+        return ResultVO.ok(vipLevelService.getMaxVipLevel());
+    }
+
 }

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

@@ -8,6 +8,7 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 
 import java.time.LocalDate;
+import java.util.List;
 
 /**
  * @author tianhua
@@ -30,7 +31,7 @@ public class GameDataDayDTO extends BasePage {
      * 游戏ID
      */
     @ApiModelProperty(notes = "游戏ID")
-    private Long gameId;
+    private List<Long> gameId;
 
     /**
      * 推广游戏应用类别

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

@@ -7,6 +7,7 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 
 import java.time.LocalDate;
+import java.util.List;
 
 /**
  * @author tianhua
@@ -29,7 +30,7 @@ public class GameDataDayTotalDTO {
      * 游戏ID
      */
     @ApiModelProperty(notes = "游戏ID")
-    private Long gameId;
+    private List<Long> gameId;
 
     /**
      * 推广游戏应用类别

+ 3 - 2
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/PitcherGameDataDayDTO.java

@@ -8,6 +8,7 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 
 import java.time.LocalDate;
+import java.util.List;
 
 /**
  * @author tianhua
@@ -42,13 +43,13 @@ public class PitcherGameDataDayDTO extends BasePage {
      * 投手ID
      */
     @ApiModelProperty(value = "投手ID")
-    private Long pitcherId;
+    private List<Long> pitcherId;
 
     /**
      * 游戏ID
      */
     @ApiModelProperty(value = "游戏ID")
-    private String gameId;
+    private List<Long> gameId;
 
     /**
      * 游戏CP方

+ 3 - 2
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/PitcherGameDataDayTotalDTO.java

@@ -7,6 +7,7 @@ import lombok.Data;
 import lombok.NoArgsConstructor;
 
 import java.time.LocalDate;
+import java.util.List;
 
 /**
  * @author tianhua
@@ -41,13 +42,13 @@ public class PitcherGameDataDayTotalDTO {
      * 投手ID
      */
     @ApiModelProperty(value = "投手ID")
-    private Long pitcherId;
+    private List<Long> pitcherId;
 
     /**
      * 游戏ID
      */
     @ApiModelProperty(value = "游戏ID")
-    private String gameId;
+    private List<Long> gameId;
 
     /**
      * 游戏CP方

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

@@ -85,7 +85,7 @@ public class RoleRechargeRankingDTO extends BasePage {
      * 角色VIP等级
      */
     @ApiModelProperty(value = "角色VIP等级")
-    private Integer vipLevel;
+    private List<Long> vipLevel;
 
     /**
      * 邮件是否发送
@@ -96,7 +96,7 @@ public class RoleRechargeRankingDTO extends BasePage {
     /**
      * 是否转端
      */
-    @ApiModelProperty(value = "是否转端: 1 -> 转端 ; 0 -> 不转端")
+    @ApiModelProperty(value = "是否转端: 1 -> 转端 ; 0 -> 不转端; 2-空(默认)")
     private Integer isChange;
 
     /**
@@ -168,7 +168,7 @@ public class RoleRechargeRankingDTO extends BasePage {
     /**
      * 是否退游
      */
-    @ApiModelProperty(notes = "是否退游:1->退游;0->未退游")
+    @ApiModelProperty(notes = "是否退游:1->退游;0->未退游; 2-空(默认)")
     private Integer isRemoveGame;
 
     /**
@@ -180,13 +180,13 @@ public class RoleRechargeRankingDTO extends BasePage {
     /**
      * 是否添加企微 1-是; 0-否
      */
-    @ApiModelProperty(notes = "是否添加企微 1-是; 0-否")
+    @ApiModelProperty(notes = "是否添加企微 1-是; 0-否; 2-空(默认)")
     private Integer isAddCorpWechat;
 
     /**
      * 是否唤醒 1-是;0-否
      */
-    @ApiModelProperty(notes = "是否唤醒 1-是;0-否")
+    @ApiModelProperty(notes = "是否唤醒 1-是;0-否; 2-空(默认)")
     private Integer isWakeUp;
 
 }

+ 89 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/entity/TGameVip.java

@@ -0,0 +1,89 @@
+package com.zanxiang.game.data.serve.pojo.entity;
+
+import lombok.Data;
+import org.nutz.dao.entity.annotation.Column;
+import org.nutz.dao.entity.annotation.PK;
+import org.nutz.dao.entity.annotation.Table;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * @author tianhua
+ */
+@Data
+@Table(TGameVip.TABLE_NAME)
+@PK({"sourceSystem", "id"})
+public class TGameVip implements Serializable {
+    private static final long serialVersionUID = 1L;
+    public static final String TABLE_NAME = "dm_game_order.t_game_vip";
+
+    /**
+     * SDK来源
+     */
+    private String sourceSystem;
+
+    /**
+    * 自增ID
+    */
+    private Long id;
+    
+    /**
+    * 超父游戏ID
+    */    
+    @Column
+    private Long superGameId;
+    
+    /**
+    * 父游戏ID
+    */    
+    @Column
+    private Long parentGameId;
+    
+    /**
+    * 充值金额最小
+    */    
+    @Column
+    private BigDecimal rechargeMoneyMin;
+
+    /**
+     * 充值金额最大
+     */
+    @Column
+    private BigDecimal rechargeMoneyMax;
+    
+    /**
+    * vip档位
+    */    
+    @Column
+    private Integer vipLevel;
+
+    
+    /**
+    * 创建时间
+    */    
+    @Column
+    private LocalDateTime createTime;
+
+    /**
+     * 创建者
+     */
+    @Column
+    private Long createBy;
+
+    /**
+    * 更新时间
+    */    
+    @Column
+    private LocalDateTime updateTime;
+
+    /**
+     * 更新者
+     */
+    @Column
+    private Long updateBy;
+  
+}
+
+

+ 6 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/AdsOrderDetailVO.java

@@ -178,4 +178,10 @@ public class AdsOrderDetailVO {
     @ApiModelProperty(notes = "广告ID")
     private String projectId;
 
+    /**
+     * 收款账户名
+     */
+    @ApiModelProperty(notes = "收款账户名")
+    private String merchantName;
+
 }

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

@@ -0,0 +1,7 @@
+package com.zanxiang.game.data.serve.service;
+
+public interface IVipLevelService {
+
+    Integer getMaxVipLevel();
+
+}

+ 18 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/AdsOrderDetailService.java

@@ -386,6 +386,7 @@ public class AdsOrderDetailService implements IAdsOrderDetailService {
                 		a.cp_status , -- cp通知状态
                 		a.last_notify_time as last_cp_notify_time , -- cp最后通知时间
                 		a.merchant_no as pay_account_id, -- 收款账户
+                		j.merchant_name , -- 收款账户名
                 		a.server_id , -- 角色所属游戏区服ID
                 		IFNULL(h.server_name, a.server_name) as source_server_name , -- 原始区服名
                 		a.server_name , -- 角色所属游戏区服名
@@ -425,6 +426,14 @@ public class AdsOrderDetailService implements IAdsOrderDetailService {
                 		FROM dm_game_order.t_game_order
                 		WHERE status = 2
                 	) i on a.source_system = i.source_system AND a.user_id = i.user_id AND i.num = 1
+                	LEFT JOIN (
+                		SELECT
+                			source_system,
+                			merchant_no,
+                			merchant_name
+                		FROM dm_game_order.t_pay_merchant
+                		WHERE is_delete = 0
+                	) j on a.source_system = j.source_system AND a.merchant_no = j.merchant_no
                 ) a
                 """;
     }
@@ -472,6 +481,7 @@ public class AdsOrderDetailService implements IAdsOrderDetailService {
                 		a.cp_status , -- cp通知状态
                 		a.last_notify_time as last_cp_notify_time , -- cp最后通知时间
                 		a.merchant_no as pay_account_id, -- 收款账户
+                		j.merchant_name , -- 收款账户名
                 		a.server_id , -- 角色所属游戏区服ID
                 		IFNULL(h.server_name, a.server_name) as source_server_name , -- 原始区服名
                 		a.server_name , -- 角色所属游戏区服名
@@ -511,6 +521,14 @@ public class AdsOrderDetailService implements IAdsOrderDetailService {
                 		FROM dm_game_order.t_game_order
                 		WHERE status = 2
                 	) i on a.source_system = i.source_system AND a.user_id = i.user_id AND i.num = 1
+                	LEFT JOIN (
+                		SELECT
+                			source_system,
+                			merchant_no,
+                			merchant_name
+                		FROM dm_game_order.t_pay_merchant
+                		WHERE is_delete = 0
+                	) j on a.source_system = j.source_system AND a.merchant_no = j.merchant_no
                 ) a
                 """;
     }

+ 301 - 6
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GameDataServiceImpl.java

@@ -16,6 +16,7 @@ import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.nutz.dao.Cnd;
@@ -32,7 +33,6 @@ import org.springframework.beans.BeanWrapper;
 import org.springframework.beans.BeanWrapperImpl;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import org.springframework.util.CollectionUtils;
 import reactor.util.function.Tuple2;
 import reactor.util.function.Tuples;
 
@@ -195,8 +195,12 @@ public class GameDataServiceImpl implements IGameDataService {
      */
     @Override
     public Page<GameDataDayVO> getGameDataDay(GameDataDayDTO dto) {
+        //如果不传游戏id,按照老的游戏每日数据查询数据
+        if (CollectionUtils.isEmpty(dto.getGameId())) {
+            return getGameDataDayForOld(dto);
+        }
         com.github.sd4324530.jtuple.Tuple2<List<Long>, List<Long>> poerInfo = dataPowerComponent.getPowerInfo(dto.getSourceSystem());
-        List<Long> gameIds = dto.getGameId() == null ? poerInfo.second : Collections.singletonList(dto.getGameId());
+        List<Long> gameIds = CollectionUtils.isEmpty(dto.getGameId()) ? poerInfo.second : dto.getGameId();
 
         //默认查询 total 总量数据
         if (StringUtils.isBlank(dto.getTableTypes())) {
@@ -208,7 +212,92 @@ public class GameDataServiceImpl implements IGameDataService {
             //拼接游戏名称查询条件
             cri.where().andEquals("game_name", dto.getGameName());
         }
-        if (gameIds != null) {
+        if (CollectionUtils.isNotEmpty(gameIds)) {
+            //拼接游戏id查询条件
+            cri.where().andInList("game_id", gameIds);
+        }
+        if (dto.getGameClassify() != null) {
+            //拼接游戏类型查询条件
+            cri.where().andEquals("game_classify", dto.getGameClassify());
+        }
+        if (dto.getRegisteredBeginDate() != null && dto.getRegisteredEndDate() != null) {
+            cri.where().andBetween("dt", dto.getRegisteredBeginDate(), dto.getRegisteredEndDate());
+        }
+        if (StringUtils.isNotBlank(dto.getSourceSystem())) {
+            //拼接SDK来源
+            cri.where().andEquals("source_system", dto.getSourceSystem());
+        }
+        //按时间分组
+        cri.getGroupBy().groupBy("dt", "source_system");
+        //拼接排序条件
+        if (StringUtils.isBlank(dto.getSortType())) {
+            dto.setSortType(OrderByEnum.DESC.getOrderType());
+        }
+        if (StringUtils.isBlank(dto.getSortFiled())) {
+            cri.getOrderBy().orderBy("cost_date", dto.getSortFiled());
+            cri.getOrderBy().orderBy("cost", dto.getSortFiled());
+        } else {
+            cri.getOrderBy().orderBy(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, dto.getSortFiled()), dto.getSortType());
+        }
+        //编写sql语句 拼接查询条件
+        Sql sql = Sqls.create(gameDataDayGroupByDtSql(dto.getTableTypes()) + cri);
+        //设置自定义回显对象
+        sql.setCallback(Sqls.callback.entities());
+        sql.setEntity(dao.getEntity(GameDataDayVO.class));
+        //设置pager对象
+        Pager pager = dao.createPager(dto.getPageNum(), dto.getPageSize());
+        sql.setPager(pager);
+        //执行sql
+        dao.execute(sql);
+        //得到结果集list
+        List<GameDataDayVO> list = sql.getList(GameDataDayVO.class);
+        //设置查询总数
+        Sql sqlCount = Sqls.create(
+                    """
+                    SELECT
+                    	COUNT(1)
+                    FROM (
+                    	SELECT
+                    		COUNT(1)
+                    	FROM game_ads.ads_game_day
+                    """ + cri +
+                    """
+                    ) a;
+                    """);
+        sqlCount.setCallback(Sqls.callback.integer());
+        dao.execute(sqlCount);
+        pager.setRecordCount(sqlCount.getInt());
+
+        List<GameDataDayVO> gameDataDayVOList = list.stream().map(vo -> {
+            formatDayNGroupByDt(vo);
+            return vo;
+        }).collect(Collectors.toList());
+
+        //返回list结果 封装到page对象里
+        return new Page<>(gameDataDayVOList, pager);
+    }
+
+    /**
+     * 游戏每日数据
+     *
+     * @param dto 前端传递查询参数
+     * @return 返回给前端的数据
+     */
+    private Page<GameDataDayVO> getGameDataDayForOld(GameDataDayDTO dto) {
+        com.github.sd4324530.jtuple.Tuple2<List<Long>, List<Long>> poerInfo = dataPowerComponent.getPowerInfo(dto.getSourceSystem());
+        List<Long> gameIds = CollectionUtils.isEmpty(dto.getGameId()) ? poerInfo.second : dto.getGameId();
+
+        //默认查询 total 总量数据
+        if (StringUtils.isBlank(dto.getTableTypes())) {
+            dto.setTableTypes("total");
+        }
+        //根据dto拼接查询条件
+        Criteria cri = Cnd.cri();
+        if (StringUtils.isNotBlank(dto.getGameName())) {
+            //拼接游戏名称查询条件
+            cri.where().andEquals("game_name", dto.getGameName());
+        }
+        if (CollectionUtils.isNotEmpty(gameIds)) {
             //拼接游戏id查询条件
             cri.where().andInList("game_id", gameIds);
         }
@@ -247,7 +336,6 @@ public class GameDataServiceImpl implements IGameDataService {
         List<GameDataDayVO> list = sql.getList(GameDataDayVO.class);
         //设置查询总数
         pager.setRecordCount(dao.count(AdsGameDay.class, cri));
-
         List<GameDataDayVO> gameDataDayVOList = list.stream().map(vo -> {
             formatDayN(vo);
             return vo;
@@ -265,7 +353,7 @@ public class GameDataServiceImpl implements IGameDataService {
      */
     public GameDataDayTotalVO getGameDataDayTotal(GameDataDayTotalDTO dto) {
         com.github.sd4324530.jtuple.Tuple2<List<Long>, List<Long>> poerInfo = dataPowerComponent.getPowerInfo(dto.getSourceSystem());
-        List<Long> gameIds = dto.getGameId() == null ? poerInfo.second : Collections.singletonList(dto.getGameId());
+        List<Long> gameIds = CollectionUtils.isEmpty(dto.getGameId()) ? poerInfo.second : dto.getGameId();
 
         //默认查询 total 总量数据
         if (StringUtils.isBlank(dto.getTableTypes())) {
@@ -273,7 +361,7 @@ public class GameDataServiceImpl implements IGameDataService {
         }
         //新增查询条件
         Criteria cri = Cnd.cri();
-        if (gameIds != null) {
+        if (CollectionUtils.isNotEmpty(gameIds)) {
             //拼接游戏id
             cri.where().andInList("game_id", gameIds);
         }
@@ -1314,6 +1402,44 @@ public class GameDataServiceImpl implements IGameDataService {
         });
     }
 
+    /**
+     * 通过反射赋值每日总计趋势(游戏每日按日期聚合数据)
+     *
+     */
+    private void formatDayNGroupByDt(GameDataDayVO vo) {
+        if (CollectionUtils.isEmpty(dayNFieldMapList)) {
+            return;
+        }
+        dayNFieldMapList.forEach(dayNTotalFieldMap -> {
+            try {
+                //得到需要计算的值
+                String[] temps = ((String) dayNTotalFieldMap.getT1().get(vo)).split("/");
+                //dn的金额总计
+                BigDecimal dNAmount = new BigDecimal(temps[0]);
+                //d1-dn的金额总计
+                BigDecimal d1ToDNTotalAmount = new BigDecimal(temps[1]);
+                //d1-dn的消耗总计(排除了未到时间的cost)
+                BigDecimal d1ToDNTotalCost = new BigDecimal(temps[3]);
+                //d1的金额总计(排除了未到时间的d1)
+                BigDecimal d1Amount = new BigDecimal(temps[4]);
+                //赋值
+                dayNTotalFieldMap.getT2().set(vo, RechargeTrendVO.builder()
+                        .rechargeMoney(dNAmount)
+                        .rechargeUserCount(Long.valueOf(temps[2]))
+                        .increase(d1ToDNTotalCost.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO :
+                                dNAmount.divide(d1ToDNTotalCost, 4, RoundingMode.HALF_UP))
+                        .back(d1ToDNTotalCost.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO :
+                                d1ToDNTotalAmount.divide(d1ToDNTotalCost, 4, RoundingMode.HALF_UP))
+                        .multiples(d1Amount.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO :
+                                d1ToDNTotalAmount.divide(d1Amount, 4, RoundingMode.HALF_UP))
+                        .build());
+
+            } catch (IllegalAccessException e) {
+                throw new RuntimeException(e);
+            }
+        });
+    }
+
     /**
      * 通过反射赋值每日总计趋势
      *
@@ -2034,6 +2160,175 @@ public class GameDataServiceImpl implements IGameDataService {
                 """;
     }
 
+    /**
+     * 游戏每日数据总计sql
+     *
+     * @param tableType 查询的类型
+     * @return String
+     */
+    private String gameDataDayGroupByDtSql(String tableType) {
+        if ("buy".equals(tableType)) {
+            return """
+                    SELECT
+                        dt as cost_date,
+                        source_system,
+                        GROUP_CONCAT(game_name) as game_name,
+                        IFNULL(SUM(cost), 0) cost,
+                        IFNULL(SUM(buy_reg_num), 0) reg_num,
+                    """
+                    + amountDay("buy_") +
+                    """
+                        IFNULL(SUM(buy_first_new_user_amount_count), 0) first_new_user_amount_count,
+                        IFNULL(SUM(buy_first_new_user_amount_num), 0) first_new_user_amount_num,
+                        IFNULL(SUM(buy_first_new_user_amount), 0) first_new_user_amount,
+                        IFNULL(SUM(buy_old_user_count), 0) old_user_count,
+                        IFNULL(SUM(buy_old_user_num), 0) old_user_num,
+                        IFNULL(SUM(buy_old_user_amount), 0) old_user_amount,
+                        IFNULL(SUM(buy_amount_count), 0) amount_count,
+                        IFNULL(SUM(buy_amount_num), 0) amount_num,
+                        IFNULL(SUM(buy_amount), 0) amount,
+                        IFNULL(SUM(buy_new_user_total_amount_count), 0) new_user_total_amount_count,
+                        IFNULL(SUM(buy_new_user_total_amount_num), 0) new_user_total_amount_num,
+                        IFNULL(SUM(buy_new_user_total_amount), 0) new_user_total_amount,
+                        round(if(SUM(cost) > 0 , SUM(buy_first_new_user_amount) / SUM(cost) ,0), 4) first_roi,
+                        round(if(SUM(buy_reg_num) > 0 , SUM(buy_first_new_user_amount_num) / SUM(buy_reg_num) ,0), 4) first_amount_rate,
+                        round(if(SUM(buy_reg_num) > 0, SUM(buy_new_user_total_amount_num) / SUM(buy_reg_num), 0) ,4) today_amount_rate,
+                        round(if(SUM(buy_amount_num) > 0 , SUM(buy_first_new_user_amount_num) / SUM(buy_amount_num) ,0), 4) new_user_rate,
+                        round(if(SUM(buy_first_new_user_amount_count) > 0, SUM(buy_first_new_user_amount) / SUM(buy_first_new_user_amount_count), 0), 2) first_avg_amount,
+                        round(if(SUM(buy_new_user_total_amount_count) > 0, SUM(buy_new_user_total_amount) / SUM(buy_new_user_total_amount_count), 0), 2) today_avg_amount,
+                        round(if(SUM(buy_amount_count) > 0, SUM(buy_amount) / SUM(buy_amount_count), 0), 2) avg_amount,
+                        round(if(SUM(buy_new_user_total_amount_num) > 0, SUM(buy_reg_order_user_again) / SUM(buy_new_user_total_amount_num), 0), 4) user_again_rate,
+                        round(if(SUM(buy_reg_num) > 0, SUM(buy_new_user_total_amount) / SUM(buy_reg_num), 0), 2) reg_user_arpu,
+                        round(if(SUM(buy_first_new_user_amount_num) > 0 , SUM(buy_first_new_user_amount) / SUM(buy_first_new_user_amount_num), 0), 2) first_amount_arpu,
+                        round(if(SUM(buy_new_user_total_amount_num) > 0 , SUM(buy_new_user_total_amount) / SUM(buy_new_user_total_amount_num), 0), 2) today_amount_arpu,
+                        round(if(SUM(buy_amount_num) > 0, SUM(buy_amount) / SUM(buy_amount_num), 0), 2) amount_arpu,
+                        round(if(SUM(buy_reg_num) > 0, SUM(cost) / SUM(buy_reg_num), 0), 2) reg_cost,
+                        round(if(SUM(buy_first_new_user_amount_num) > 0, SUM(cost) / SUM(buy_first_new_user_amount_num), 0), 2) first_new_user_recharge_cost,
+                        round(if(SUM(buy_new_user_total_amount_num) > 0, SUM(cost) / SUM(buy_new_user_total_amount_num), 0), 2) total_recharge_cost,
+                        round(if(SUM(cost) > 0, SUM(buy_new_user_total_amount) / SUM(cost), 0), 4) total_roi,
+                        IFNULL(SUM(buy_hundred_user_num), 0) hundred_user_num,
+                        round(IF(SUM(buy_hundred_user_num) > 0, SUM(cost) / SUM(buy_hundred_user_num), 0), 2) hundred_user_num_cost,
+                        IFNULL(SUM(buy_first_role_num), 0) first_role_num,
+                        IFNULL(SUM(buy_role_num), 0) role_num,
+                        IFNULL(SUM(buy_new_user_total_role_num), 0) new_user_total_role_num,
+                        round(IF(SUM(buy_first_role_num) > 0, SUM(cost) / SUM(buy_first_role_num), 0), 2) first_role_num_cost,
+                        round(IF(SUM(buy_role_num) > 0, SUM(cost) / SUM(buy_role_num), 0), 2) role_num_cost,
+                        round(IF(SUM(buy_new_user_total_role_num) >0, SUM(cost) / SUM(buy_new_user_total_role_num), 0), 2) new_user_total_role_num_cost,
+                        round(IF(SUM(buy_reg_num) >0, SUM(buy_first_role_num) / SUM(buy_reg_num), 0), 4) first_role_num_rate,
+                        round(IF(SUM(buy_reg_num) >0, SUM(buy_role_num) / SUM(buy_reg_num), 0), 4) role_num_rate,
+                        round(IF(SUM(buy_reg_num) >0, SUM(buy_new_user_total_role_num) / SUM(buy_reg_num), 0), 4) new_user_total_role_num_rate
+                    FROM
+                        ads_game_day
+                    """;
+        } else if ("nature".equals(tableType)) {
+            return """
+                    SELECT
+                        dt as cost_date,
+                        source_system,
+                        GROUP_CONCAT(game_name) as game_name,
+                        IFNULL(SUM(cost), 0) cost,
+                        IFNULL(SUM(nature_reg_num), 0) reg_num,
+                    """
+                    + amountDay("nature_") +
+                    """
+                        IFNULL(SUM(nature_first_new_user_amount_count), 0) first_new_user_amount_count,
+                        IFNULL(SUM(nature_first_new_user_amount_num), 0) first_new_user_amount_num,
+                        IFNULL(SUM(nature_first_new_user_amount), 0) first_new_user_amount,
+                        IFNULL(SUM(nature_old_user_count), 0) old_user_count,
+                        IFNULL(SUM(nature_old_user_num), 0) old_user_num,
+                        IFNULL(SUM(nature_old_user_amount), 0) old_user_amount,
+                        IFNULL(SUM(nature_amount_count), 0) amount_count,
+                        IFNULL(SUM(nature_amount_num), 0) amount_num,
+                        IFNULL(SUM(nature_amount), 0) amount,
+                        IFNULL(SUM(nature_new_user_total_amount_count), 0) new_user_total_amount_count,
+                        IFNULL(SUM(nature_new_user_total_amount_num), 0) new_user_total_amount_num,
+                        IFNULL(SUM(nature_new_user_total_amount), 0) new_user_total_amount,
+                        round(if(SUM(cost) > 0 , SUM(nature_first_new_user_amount) / SUM(cost) ,0), 4) first_roi,
+                        round(if(SUM(nature_reg_num) > 0 , SUM(nature_first_new_user_amount_num) / SUM(nature_reg_num) ,0), 4) first_amount_rate,
+                        round(if(SUM(nature_reg_num) > 0, SUM(nature_new_user_total_amount_num) / SUM(nature_reg_num), 0) ,4) today_amount_rate,
+                        round(if(SUM(nature_amount_num) > 0 , SUM(nature_first_new_user_amount_num) / SUM(nature_amount_num) ,0), 4) new_user_rate,
+                        round(if(SUM(nature_first_new_user_amount_count) > 0, SUM(nature_first_new_user_amount) / SUM(nature_first_new_user_amount_count), 0), 2) first_avg_amount,
+                        round(if(SUM(nature_new_user_total_amount_count) > 0, SUM(nature_new_user_total_amount) / SUM(nature_new_user_total_amount_count), 0), 2) today_avg_amount,
+                        round(if(SUM(nature_amount_count) > 0, SUM(nature_amount) / SUM(nature_amount_count), 0), 2) avg_amount,
+                        round(if(SUM(nature_new_user_total_amount_num) > 0, SUM(nature_reg_order_user_again) / SUM(nature_new_user_total_amount_num), 0), 4) user_again_rate,
+                        round(if(SUM(nature_reg_num) > 0, SUM(nature_new_user_total_amount) / SUM(nature_reg_num), 0), 2) reg_user_arpu,
+                        round(if(SUM(nature_first_new_user_amount_num) > 0 , SUM(nature_first_new_user_amount) / SUM(nature_first_new_user_amount_num), 0), 2) first_amount_arpu,
+                        round(if(SUM(nature_new_user_total_amount_num) > 0 , SUM(nature_new_user_total_amount) / SUM(nature_new_user_total_amount_num), 0), 2) today_amount_arpu,
+                        round(if(SUM(nature_amount_num) > 0, SUM(nature_amount) / SUM(nature_amount_num), 0), 2) amount_arpu,
+                        round(if(SUM(nature_reg_num) > 0, SUM(cost) / SUM(nature_reg_num), 0), 2) reg_cost,
+                        round(if(SUM(nature_first_new_user_amount_num) > 0, SUM(cost) / SUM(nature_first_new_user_amount_num), 0), 2) first_new_user_recharge_cost,
+                        round(if(SUM(nature_new_user_total_amount_num) > 0, SUM(cost) / SUM(nature_new_user_total_amount_num), 0), 2) total_recharge_cost,
+                        round(if(SUM(cost) > 0, SUM(nature_new_user_total_amount) / SUM(cost), 0), 4) total_roi,
+                        SUM(nature_hundred_user_num) hundred_user_num,
+                        round(IF(SUM(nature_hundred_user_num) > 0, SUM(cost) / SUM(nature_hundred_user_num), 0), 2) hundred_user_num_cost,
+                        SUM(nature_first_role_num) first_role_num,
+                        SUM(nature_role_num) role_num,
+                        SUM(nature_new_user_total_role_num) new_user_total_role_num,
+                        round(IF(SUM(nature_first_role_num) > 0, SUM(cost) / SUM(nature_first_role_num), 0), 2) first_role_num_cost,
+                        round(IF(SUM(nature_role_num) > 0, SUM(cost) / SUM(nature_role_num), 0), 2) role_num_cost,
+                        round(IF(SUM(nature_new_user_total_role_num) >0, SUM(cost) / SUM(nature_new_user_total_role_num), 0), 2) new_user_total_role_num_cost,
+                        round(IF(SUM(nature_reg_num) >0, SUM(nature_first_role_num) / SUM(nature_reg_num), 0), 4) first_role_num_rate,
+                        round(IF(SUM(nature_reg_num) >0, SUM(nature_role_num) / SUM(nature_reg_num), 0), 4) role_num_rate,
+                        round(IF(SUM(nature_reg_num) >0, SUM(nature_new_user_total_role_num) / SUM(nature_reg_num), 0), 4) new_user_total_role_num_rate
+                    FROM
+                        ads_game_day
+                    """;
+        }
+        //总量数据
+        return """
+                SELECT
+                    dt as cost_date,
+                    source_system,
+                    GROUP_CONCAT(game_name) as game_name,
+                    IFNULL(SUM(cost), 0) cost,
+                    IFNULL(SUM(reg_num), 0) reg_num,
+                """
+                + amountDay("") +
+                """
+                    IFNULL(SUM(first_new_user_amount_count), 0) first_new_user_amount_count,
+                    IFNULL(SUM(first_new_user_amount_num), 0) first_new_user_amount_num,
+                    IFNULL(SUM(first_new_user_amount), 0) first_new_user_amount,
+                    IFNULL(SUM(old_user_count), 0) old_user_count,
+                    IFNULL(SUM(old_user_num), 0) old_user_num,
+                    IFNULL(SUM(old_user_amount), 0) old_user_amount,
+                    IFNULL(SUM(amount_count), 0) amount_count,
+                    IFNULL(SUM(amount_num), 0) amount_num,
+                    IFNULL(SUM(amount), 0) amount,
+                    IFNULL(SUM(new_user_total_amount_count), 0) new_user_total_amount_count,
+                    IFNULL(SUM(new_user_total_amount_num), 0) new_user_total_amount_num,
+                    IFNULL(SUM(new_user_total_amount), 0) new_user_total_amount,
+                    round(if(SUM(cost) > 0 , SUM(first_new_user_amount) / SUM(cost) ,0), 4) first_roi,
+                    round(if(SUM(reg_num) > 0 , SUM(first_new_user_amount_num) / SUM(reg_num) ,0), 4) first_amount_rate,
+                    round(if(SUM(reg_num) > 0, SUM(new_user_total_amount_num) / SUM(reg_num), 0) ,4) today_amount_rate,
+                    round(if(SUM(amount_num) > 0 , SUM(first_new_user_amount_num) / SUM(amount_num) ,0), 4) new_user_rate,
+                    round(if(SUM(first_new_user_amount_count) > 0, SUM(first_new_user_amount) / SUM(first_new_user_amount_count), 0), 2) first_avg_amount,
+                    round(if(SUM(new_user_total_amount_count) > 0, SUM(new_user_total_amount) / SUM(new_user_total_amount_count), 0), 2) today_avg_amount,
+                    round(if(SUM(amount_count) > 0, SUM(amount) / SUM(amount_count), 0), 2) avg_amount,
+                    round(if(SUM(new_user_total_amount_num) > 0, SUM(reg_order_user_again) / SUM(new_user_total_amount_num), 0), 4) user_again_rate,
+                    round(if(SUM(reg_num) > 0, SUM(new_user_total_amount) / SUM(reg_num), 0), 2) reg_user_arpu,
+                    round(if(SUM(first_new_user_amount_num) > 0 , SUM(first_new_user_amount) / SUM(first_new_user_amount_num), 0), 2) first_amount_arpu,
+                    round(if(SUM(new_user_total_amount_num) > 0 , SUM(new_user_total_amount) / SUM(new_user_total_amount_num), 0), 2) today_amount_arpu,
+                    round(if(SUM(amount_num) > 0, SUM(amount) / SUM(amount_num), 0), 2) amount_arpu,
+                    round(if(SUM(reg_num) > 0, SUM(cost) / SUM(reg_num), 0), 2) reg_cost,
+                    round(if(SUM(first_new_user_amount_num) > 0, SUM(cost) / SUM(first_new_user_amount_num), 0), 2) first_new_user_recharge_cost,
+                    round(if(SUM(new_user_total_amount_num) > 0, SUM(cost) / SUM(new_user_total_amount_num), 0), 2) total_recharge_cost,
+                    round(if(SUM(cost) > 0, SUM(new_user_total_amount) / SUM(cost), 0), 4) total_roi,
+                    SUM(hundred_user_num) hundred_user_num,
+                    round(IF(SUM(hundred_user_num) > 0, SUM(cost) / SUM(hundred_user_num), 0), 2) hundred_user_num_cost,
+                    SUM(first_role_num) first_role_num,
+                    SUM(role_num) role_num,
+                    SUM(new_user_total_role_num) new_user_total_role_num,
+                    round(IF(SUM(first_role_num) > 0, SUM(cost) / SUM(first_role_num), 0), 2) first_role_num_cost,
+                    round(IF(SUM(role_num) > 0, SUM(cost) / SUM(role_num), 0), 2) role_num_cost,
+                    round(IF(SUM(new_user_total_role_num) >0, SUM(cost) / SUM(new_user_total_role_num), 0), 2) new_user_total_role_num_cost,
+                    round(IF(SUM(reg_num) >0, SUM(first_role_num) / SUM(reg_num), 0), 4) first_role_num_rate,
+                    round(IF(SUM(reg_num) >0, SUM(role_num) / SUM(reg_num), 0), 4) role_num_rate,
+                    round(IF(SUM(reg_num) >0, SUM(new_user_total_role_num) / SUM(reg_num), 0), 4) new_user_total_role_num_rate
+                FROM
+                    ads_game_day
+                """;
+    }
+
     /**
      * 游戏每日数据总计sql
      *

+ 248 - 10
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/PitcherDataServiceImpl.java

@@ -15,8 +15,9 @@ import com.zanxiang.game.data.serve.utils.Page;
 import com.zanxiang.module.util.DateUtil;
 import com.zanxiang.module.util.exception.BaseException;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.MapUtils;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.dubbo.common.utils.CollectionUtils;
 import org.nutz.dao.Cnd;
 import org.nutz.dao.Dao;
 import org.nutz.dao.Sqls;
@@ -486,9 +487,14 @@ public class PitcherDataServiceImpl implements IPitcherDataService {
      */
     @Override
     public Page<PitcherGameDataDayVO> getPitcherGameDataDay(PitcherGameDataDayDTO dto) {
+        //不选游戏,默认按照直接的投手游戏每日数据去查数据
+        if (CollectionUtils.isEmpty(dto.getGameId())) {
+            return getPitcherGameDataDayForOld(dto);
+        }
         com.github.sd4324530.jtuple.Tuple2<List<Long>, List<Long>> poerInfo = dataPowerComponent.getPowerInfo(dto.getSourceSystem());
-        List<Long> userIds = dto.getPitcherId() == null ? poerInfo.first : Collections.singletonList(dto.getPitcherId());
-        List<Long> gameIds = dto.getGameId() == null ? poerInfo.second : Collections.singletonList(Long.parseLong(dto.getGameId()));
+        List<Long> userIds = CollectionUtils.isEmpty(dto.getPitcherId()) ? poerInfo.first : dto.getPitcherId();
+        List<Long> gameIds = CollectionUtils.isEmpty(dto.getGameId()) ? poerInfo.second : dto.getGameId();
+
         //不传递时间,默认查询当天
         if (dto.getBeginDate() == null || dto.getEndDate() == null) {
             dto.setBeginDate(LocalDate.now());
@@ -496,10 +502,96 @@ public class PitcherDataServiceImpl implements IPitcherDataService {
         }
         //创建查询条件
         Criteria cri = Cnd.cri();
-        if (userIds != null) {
+        if (CollectionUtils.isNotEmpty(userIds)) {
             cri.where().andInList("pitcher_id", userIds);
         }
-        if (gameIds != null) {
+        if (CollectionUtils.isNotEmpty(gameIds)) {
+            cri.where().andInList("game_id", gameIds);
+        }
+        if (StringUtils.isNotBlank(dto.getSourceSystem())) {
+            cri.where().andEquals("source_system", dto.getSourceSystem());
+        }
+        if (dto.getBeginDate() != null && dto.getEndDate() != null) {
+            cri.where().andBetween("dt", dto.getBeginDate(), dto.getEndDate());
+        }
+        if (StringUtils.isNotBlank(dto.getGameCp())) {
+            cri.where().andEquals("game_cp", dto.getGameCp());
+        }
+        if (dto.getGameType() != null) {
+            cri.where().andEquals("game_type", dto.getGameType());
+        }
+        //按照日期,投手分组
+        cri.getGroupBy().groupBy("dt", "source_system", "pitcher_id");
+        //排序条件
+        //拼接排序条件,如果没有排序条件给默认值
+        if (StringUtils.isBlank(dto.getSortType())) {
+            dto.setSortType(OrderByEnum.DESC.getOrderType());
+        }
+        if (StringUtils.isBlank(dto.getSortFiled())) {
+            cri.getOrderBy().orderBy("dt", dto.getSortType());
+            cri.getOrderBy().orderBy("cost", dto.getSortType());
+        } else {
+            cri.getOrderBy().orderBy(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, dto.getSortFiled()), dto.getSortType());
+        }
+        //Pager对象
+        Pager pager = dao.createPager(dto.getPageNum(), dto.getPageSize());
+        //sql语句
+        Sql sql = Sqls.create(pitcherGameDataDayGroupByDtAndPitcherSql() + cri);
+        //设置回传对象
+        sql.setCallback(Sqls.callback.entities());
+        sql.setEntity(dao.getEntity(PitcherGameDataDayVO.class));
+        //设置pager
+        sql.setPager(pager);
+        //执行sql
+        dao.execute(sql);
+        //设置总记录数
+        Sql sqlCount = Sqls.create(
+                """
+                    SELECT
+                    	COUNT(1)
+                    FROM (
+                    	SELECT
+                    		COUNT(*)
+                    	FROM game_ads.ads_game_pitcher_day
+                """ + cri +
+                """
+                    ) a
+                """);
+        sqlCount.setCallback(Sqls.callback.integer());
+        dao.execute(sqlCount);
+        pager.setRecordCount(sqlCount.getInt());
+        //处理dayN数据
+        List<PitcherGameDataDayVO> tempList = sql.getList(PitcherGameDataDayVO.class);
+        List<PitcherGameDataDayVO> list = tempList.stream().map(vo -> {
+            formatPitcherGameDataDayGroupByDtAndPitcherDayN(vo);
+            return vo;
+        }).collect(Collectors.toList());
+        //返回结果
+        return new Page<>(list, pager);
+    }
+
+    /**
+     * 投手游戏每日数据
+     *
+     * @param dto PitcherGameDataDayDTO
+     * @return Page<PitcherGameDataDayVO>
+     */
+    public Page<PitcherGameDataDayVO> getPitcherGameDataDayForOld(PitcherGameDataDayDTO dto) {
+        com.github.sd4324530.jtuple.Tuple2<List<Long>, List<Long>> poerInfo = dataPowerComponent.getPowerInfo(dto.getSourceSystem());
+        List<Long> userIds = CollectionUtils.isEmpty(dto.getPitcherId()) ? poerInfo.first : dto.getPitcherId();
+        List<Long> gameIds = CollectionUtils.isEmpty(dto.getGameId()) ? poerInfo.second : dto.getGameId();
+
+        //不传递时间,默认查询当天
+        if (dto.getBeginDate() == null || dto.getEndDate() == null) {
+            dto.setBeginDate(LocalDate.now());
+            dto.setEndDate(LocalDate.now());
+        }
+        //创建查询条件
+        Criteria cri = Cnd.cri();
+        if (CollectionUtils.isNotEmpty(userIds)) {
+            cri.where().andInList("pitcher_id", userIds);
+        }
+        if (CollectionUtils.isNotEmpty(gameIds)) {
             cri.where().andInList("game_id", gameIds);
         }
         if (StringUtils.isNotBlank(dto.getSourceSystem())) {
@@ -557,8 +649,8 @@ public class PitcherDataServiceImpl implements IPitcherDataService {
     @Override
     public PitcherGameDataDayTotalVO getPitcherGameDataDayTotal(PitcherGameDataDayTotalDTO dto) {
         com.github.sd4324530.jtuple.Tuple2<List<Long>, List<Long>> poerInfo = dataPowerComponent.getPowerInfo(dto.getSourceSystem());
-        List<Long> userIds = dto.getPitcherId() == null ? poerInfo.first : Collections.singletonList(dto.getPitcherId());
-        List<Long> gameIds = dto.getGameId() == null ? poerInfo.second : Collections.singletonList(Long.parseLong(dto.getGameId()));
+        List<Long> userIds = CollectionUtils.isEmpty(dto.getPitcherId()) ? poerInfo.first : dto.getPitcherId();
+        List<Long> gameIds = CollectionUtils.isEmpty(dto.getGameId()) ? poerInfo.second : dto.getGameId();
         //不传递时间,默认查询当天
         if (dto.getBeginDate() == null || dto.getEndDate() == null) {
             dto.setBeginDate(LocalDate.now());
@@ -566,10 +658,10 @@ public class PitcherDataServiceImpl implements IPitcherDataService {
         }
         //创建查询条件
         Criteria cri = Cnd.cri();
-        if (userIds != null) {
+        if (CollectionUtils.isNotEmpty(userIds)) {
             cri.where().andInList("pitcher_id", userIds);
         }
-        if (gameIds != null) {
+        if (CollectionUtils.isNotEmpty(gameIds)) {
             cri.where().andInList("game_id", gameIds);
         }
         if (StringUtils.isNotBlank(dto.getSourceSystem())) {
@@ -666,7 +758,7 @@ public class PitcherDataServiceImpl implements IPitcherDataService {
             Map<String, String> gameIDToDayNData = pitcherGameDataTotalDayNMap.get(vo.getPitcherId().toString());
             //取到dayN数据
             String dayNStr;
-            if (CollectionUtils.isEmptyMap(gameIDToDayNData)) {
+            if (MapUtils.isEmpty(gameIDToDayNData)) {
                 dayNStr = "0.00-0";
             } else {
                 dayNStr = gameIDToDayNData.get(vo.getGameId());
@@ -1633,6 +1725,44 @@ public class PitcherDataServiceImpl implements IPitcherDataService {
         });
     }
 
+    /**
+     * 处理投手游戏每日的DayN(投手游戏每日按日期,投手聚合)
+     *
+     * @param vo PitcherGameDataDayTotalVO
+     */
+    private void formatPitcherGameDataDayGroupByDtAndPitcherDayN(PitcherGameDataDayVO vo) {
+        if (CollectionUtils.isEmpty(pitcherGameDayNFieldMapList)) {
+            return;
+        }
+        pitcherGameDayNFieldMapList.forEach(dayNTotalFieldMap -> {
+            try {
+                //得到需要计算的值
+                String[] temps = ((String) dayNTotalFieldMap.getT1().get(vo)).split("/");
+                //dn的金额总计
+                BigDecimal dNAmount = new BigDecimal(temps[0]);
+                //d1-dn的金额总计
+                BigDecimal d1ToDNTotalAmount = new BigDecimal(temps[1]);
+                //d1-dn的消耗总计(排除了未到时间的cost)
+                BigDecimal d1ToDNTotalCost = new BigDecimal(temps[3]);
+                //d1的金额总计(排除了未到时间的d1)
+                BigDecimal d1Amount = new BigDecimal(temps[4]);
+                //赋值
+                dayNTotalFieldMap.getT2().set(vo, RechargeTrendVO.builder()
+                        .rechargeMoney(dNAmount)
+                        .rechargeUserCount(Long.valueOf(temps[2]))
+                        .increase(d1ToDNTotalCost.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO :
+                                dNAmount.divide(d1ToDNTotalCost, 4, RoundingMode.HALF_UP))
+                        .back(d1ToDNTotalCost.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO :
+                                d1ToDNTotalAmount.divide(d1ToDNTotalCost, 4, RoundingMode.HALF_UP))
+                        .multiples(d1Amount.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO :
+                                d1ToDNTotalAmount.divide(d1Amount, 4, RoundingMode.HALF_UP))
+                        .build());
+            } catch (Exception e) {
+                throw new BaseException("映射出错");
+            }
+        });
+    }
+
     /**
      * 处理投手每日总计的DayN(投手每日总计)
      *
@@ -2123,6 +2253,114 @@ public class PitcherDataServiceImpl implements IPitcherDataService {
                 """;
     }
 
+    /**
+     * 查询投手游戏每日数据SQL(投手游戏每日按日期以及投手聚合)
+     *
+     * @return String
+     */
+    private String pitcherGameDataDayGroupByDtAndPitcherSql() {
+        return """
+                SELECT
+                    dt,
+                    source_system ,
+                    pitcher_id ,
+                    MAX(pitcher) pitcher ,
+                    GROUP_CONCAT(game_name) as game_name ,
+                    SUM(cost) as cost,
+                    SUM(plan_count) as plan_count,
+                    SUM(account_count) as account_count,
+                    SUM(agent_count) as agent_count,
+                    SUM(register_num) as register_num,
+                    ROUND(IF(SUM(register_num) > 0, SUM(cost) / SUM(register_num), 0), 2) as register_cost,
+                    SUM(first_role_num) as first_role_num,
+                    SUM(new_user_total_role_num) as new_user_total_role_num,
+                    SUM(role_num) as role_num,
+                    ROUND(IF(SUM(role_num) > 0 , SUM(cost) / SUM(role_num), 0), 2) as role_num_cost,
+                    ROUND(IF(SUM(first_role_num) > 0 , SUM(cost) / SUM(first_role_num), 0), 2) as first_role_cost,
+                    ROUND(IF(SUM(new_user_total_role_num) > 0 , SUM(cost) / SUM(new_user_total_role_num), 0), 2) as new_user_total_role_cost,
+                    ROUND(IF(SUM(register_num) > 0 , SUM(first_role_num) / SUM(register_num), 0), 4) as first_role_rate,
+                    ROUND(IF(SUM(register_num) > 0 , SUM(new_user_total_role_num) / SUM(register_num), 0), 4) as new_user_total_role_rate,
+                    ROUND(IF(SUM(register_num) > 0 , SUM(role_num) / SUM(register_num), 0), 4) as role_num_rate,
+                    SUM(first_new_user_amount_count) as first_new_user_amount_count,
+                    SUM(first_new_user_amount_num) as first_new_user_amount_num,
+                    SUM(first_new_user_amount) as first_new_user_amount,
+                    SUM(amount_count) as amount_count,
+                    SUM(amount_num) as amount_num,
+                    SUM(amount) as amount,
+                    SUM(old_amount_count) as old_amount_count,
+                    SUM(old_amount_num) as old_amount_num,
+                    SUM(old_amount) as old_amount,
+                    SUM(new_user_total_amount_count) as new_user_total_amount_count,
+                    SUM(new_user_total_amount_num) as new_user_total_amount_num,
+                    SUM(new_user_total_amount) as new_user_total_amount,
+                    SUM(buy_new_user_total_amount) as buy_new_user_total_amount,
+                    SUM(buy_new_user_total_amount_num) as buy_new_user_total_amount_num,
+                    SUM(buy_new_user_total_amount_count) as buy_new_user_total_amount_count,
+                    ROUND(IF(SUM(cost) > 0, SUM(first_new_user_amount) / SUM(cost), 0), 4) as first_roi,
+                    ROUND(IF(SUM(cost) > 0, SUM(buy_new_user_total_amount) / SUM(cost), 0), 4) as buy_roi,
+                    ROUND(IF(SUM(cost) > 0, SUM(new_user_total_amount) / SUM(cost), 0), 4) as today_roi,
+                    (SUM(new_user_total_amount) - SUM(cost)) as gross_profit,
+                    ROUND(IF(SUM(register_num) > 0, SUM(first_new_user_amount_num) / SUM(register_num), 0), 4) as first_rate,
+                    ROUND(IF(SUM(register_num) > 0, SUM(buy_new_user_total_amount_num) / SUM(register_num), 0), 4) as buy_user_rate,
+                    ROUND(IF(SUM(register_num) > 0, SUM(new_user_total_amount_num) / SUM(register_num), 0), 4) as today_rate,
+                    ROUND(IF(SUM(amount_num) > 0, SUM(first_new_user_amount_num) / SUM(amount_num), 0), 4) as new_user_amount_ratio,
+                    ROUND(IF(SUM(first_new_user_amount_count) > 0 , SUM(first_new_user_amount) / SUM(first_new_user_amount_count), 0), 2) as first_avg,
+                    ROUND(IF(SUM(buy_new_user_total_amount_count) > 0 , SUM(buy_new_user_total_amount) / SUM(buy_new_user_total_amount_count), 0), 2) as buy_avg,
+                    ROUND(IF(SUM(new_user_total_amount_count) > 0 , SUM(new_user_total_amount) / SUM(new_user_total_amount_count), 0), 2) as today_avg,
+                    ROUND(IF(SUM(amount_count) > 0 , SUM(amount) / SUM(amount_count), 0), 2) as paper_avg,
+                    ROUND(IF(SUM(first_new_user_amount_num) > 0 , SUM(cost) / SUM(first_new_user_amount_num), 0), 2) as first_amount_cost,
+                    ROUND(IF(SUM(buy_new_user_total_amount_num) > 0 , SUM(cost) / SUM(buy_new_user_total_amount_num), 0), 2) as buy_amount_cost,
+                    ROUND(IF(SUM(new_user_total_amount_num) > 0 , SUM(cost) / SUM(new_user_total_amount_num), 0), 2) as today_amount_cost,
+                    SUM(reg_order_user_again) as reg_order_user_again,
+                    ROUND(IF(SUM(new_user_total_amount_num) > 0 ,SUM(reg_order_user_again) / SUM(new_user_total_amount_num), 0), 4) as today_again_rate,
+                    ROUND(IF(SUM(register_num) > 0 , SUM(new_user_total_amount) / SUM(register_num), 0), 2) as new_reg_arpu,
+                    ROUND(IF(SUM(first_new_user_amount_num) > 0 , SUM(first_new_user_amount) / SUM(first_new_user_amount_num), 0), 2) as first_arpu,
+                    ROUND(IF(SUM(new_user_total_amount_num) > 0 , SUM(new_user_total_amount) / SUM(new_user_total_amount_num), 0), 2) as today_arpu,
+                    ROUND(IF(SUM(amount_num) > 0 , SUM(amount) / SUM(amount_num), 0), 2) as paper_arpu,
+                    SUM(hundred_user_num) as hundred_user_num,
+                    ROUND(IF(SUM(hundred_user_num) > 0 , SUM(cost) / SUM(hundred_user_num), 0), 2) as hundred_user_num_cost,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da1) / SUM(cost), 0), 4) as roi1,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da2) / SUM(cost), 0), 4) as roi2,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da3) / SUM(cost), 0), 4) as roi3,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da4) / SUM(cost), 0), 4) as roi4,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da5) / SUM(cost), 0), 4) as roi5,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da6) / SUM(cost), 0), 4) as roi6,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da7) / SUM(cost), 0), 4) as roi7,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da8) / SUM(cost), 0), 4) as roi8,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da9) / SUM(cost), 0), 4) as roi9,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da10) / SUM(cost), 0), 4) as roi10,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da11) / SUM(cost), 0), 4) as roi11,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da12) / SUM(cost), 0), 4) as roi12,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da13) / SUM(cost), 0), 4) as roi13,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da14) / SUM(cost), 0), 4) as roi14,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da15) / SUM(cost), 0), 4) as roi15,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da16) / SUM(cost), 0), 4) as roi16,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da17) / SUM(cost), 0), 4) as roi17,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da18) / SUM(cost), 0), 4) as roi18,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da19) / SUM(cost), 0), 4) as roi19,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da20) / SUM(cost), 0), 4) as roi20,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da21) / SUM(cost), 0), 4) as roi21,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da22) / SUM(cost), 0), 4) as roi22,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da23) / SUM(cost), 0), 4) as roi23,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da24) / SUM(cost), 0), 4) as roi24,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da25) / SUM(cost), 0), 4) as roi25,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da26) / SUM(cost), 0), 4) as roi26,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da27) / SUM(cost), 0), 4) as roi27,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da28) / SUM(cost), 0), 4) as roi28,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da29) / SUM(cost), 0), 4) as roi29,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da30) / SUM(cost), 0), 4) as roi30,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da60) / SUM(cost), 0), 4) as roi60,
+                    ROUND(IF(SUM(cost) > 0 , SUM(da90) / SUM(cost), 0), 4) as roi90,
+                    ROUND(IF(SUM(cost) > 0 , SUM(m6) / SUM(cost), 0), 4) as roi180,
+                    ROUND(IF(SUM(cost) > 0 , SUM(m12) / SUM(cost), 0), 4) as roi1yaer,
+                    ROUND(IF(SUM(cost) > 0 , SUM(total) / SUM(cost), 0), 4) as roi_total,
+                """ + getPitcherGameDataDayTotalDayNsql() +
+                """
+                FROM
+                    game_ads.ads_game_pitcher_day
+                """;
+    }
+
     /**
      * 查询投手每日数据总计SQL(投手每日总计)
      *

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

@@ -785,7 +785,7 @@ public class PromotionDayServiceImpl implements IAdsPromotionDayService {
             //推广账号类型
             cri.where().andEquals("account_type", dto.getAccountType());
         }
-        if (userIds != null) {
+        if (CollectionUtils.isNotEmpty(userIds)) {
             cri.where().andInList("pitcher_id", userIds);
         }
         if (CollectionUtils.isNotEmpty(dto.getAgentId())) {
@@ -794,7 +794,7 @@ public class PromotionDayServiceImpl implements IAdsPromotionDayService {
         if (StringUtils.isNotBlank(dto.getCpName())) {
             cri.where().andEquals("cp_name", dto.getCpName());
         }
-        if (gameIds != null) {
+        if (CollectionUtils.isNotEmpty(gameIds)) {
             cri.where().andInList("game_id", gameIds);
         }
         if (dto.getClassify() != null) {
@@ -1078,7 +1078,7 @@ public class PromotionDayServiceImpl implements IAdsPromotionDayService {
                 FROM(
                 	SELECT
                 		promotion_id,
-                		MAX(promotion_name) as promotion_name,
+                		MIN(promotion_name) as promotion_name,
                 		MAX(project_id) as project_id,
                 		MAX(project_name) as project_name,
                 		MAX(account_name) as account_name,

+ 98 - 45
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/RoleManageServiceImpl.java

@@ -82,15 +82,21 @@ public class RoleManageServiceImpl implements IRoleManageService {
             //角色创建时间
             criA.where().andBetween("DATE(role_create_time)", dto.getCreateRoleBeginDate(), dto.getCreateRoleEndDate());
         }
-        if (dto.getVipLevel() != null) {
-            criA.where().andEquals("vip_level", dto.getVipLevel());
+        if (CollectionUtils.isNotEmpty(dto.getVipLevel())) {
+            //角色vip等级
+            criA.where().andInList("vip_level", dto.getVipLevel());
         }
         if (dto.getIsSendMail() != null) {
             criA.where().andEquals("is_send_mail", dto.getIsSendMail());
         }
         if (dto.getIsChange() != null) {
-            //是否转端
-            criA.where().andEquals("is_change_game_type", dto.getIsChange());
+            if (dto.getIsChange() == 2) {
+                //是否转端
+                criA.where().andIsNull("is_change_game_type");
+            } else {
+                //是否转端
+                criA.where().andEquals("is_change_game_type", dto.getIsChange());
+            }
         }
         if (StringUtils.isNotBlank(dto.getWeChatCompany())) {
             //企业微信号
@@ -128,20 +134,35 @@ public class RoleManageServiceImpl implements IRoleManageService {
             criA.where().andLTE("amount", dto.getTotalRechargeMax());
         }
         if (dto.getIsRemoveGame() != null) {
-            //是否退游
-            criA.where().andEquals("is_remove_game", dto.getIsRemoveGame());
+            if (dto.getIsRemoveGame() == 2) {
+                //是否退游
+                criA.where().andIsNull("is_remove_game");
+            } else {
+                //是否退游
+                criA.where().andEquals("is_remove_game", dto.getIsRemoveGame());
+            }
         }
         if (dto.getIsRemoveGameForSystem() != null) {
             //是否退游(系统判定)
             criA.where().andEquals("is_remove_game_for_system", dto.getIsRemoveGameForSystem());
         }
         if (dto.getIsWakeUp() != null) {
-            //是否唤醒
-            criA.where().andEquals("is_wake_up", dto.getIsWakeUp());
+            if (dto.getIsWakeUp() == 2) {
+                //是否唤醒
+                criA.where().andIsNull("is_wake_up");
+            } else {
+                //是否唤醒
+                criA.where().andEquals("is_wake_up", dto.getIsWakeUp());
+            }
         }
         if (dto.getIsAddCorpWechat() != null) {
-            //是否添加企微
-            criA.where().andEquals("is_add_corp_wechat", dto.getIsAddCorpWechat());
+            if (dto.getIsAddCorpWechat() == 2) {
+                //是否添加企微
+                criA.where().andIsNull("is_add_corp_wechat");
+            } else {
+                //是否添加企微
+                criA.where().andEquals("is_add_corp_wechat", dto.getIsAddCorpWechat());
+            }
         }
         //给充值时间查询条件
         Criteria criTodayAmount = Cnd.cri();
@@ -809,6 +830,7 @@ public class RoleManageServiceImpl implements IRoleManageService {
                 		IFNULL(c.amount, 0) as amount, -- 角色累计充值金额
                 		IFNULL(c.amount_count, 0) as amount_count, -- 角色累计充值次数
                 		ROUND(IF(c.amount_count > 0, c.amount / c.amount_count, 0), 2) as avg_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'
@@ -817,7 +839,7 @@ public class RoleManageServiceImpl implements IRoleManageService {
                 			WHEN c.amount >= 20000 and c.amount < 50000 THEN '5'
                 			WHEN c.amount >= 50000 THEN '6'
                 			ELSE '0'
-                			END) as vip_level, -- 角色vip等级
+                			END)) as vip_level, -- 角色vip等级
                 		a.game_id as role_reg_game_id, -- 角色注册游戏id
                 		d.game_name as role_reg_game_name, -- 角色注册游戏名
                 		d.classify as role_reg_game_classify, -- 角色注册游戏类型
@@ -1178,6 +1200,21 @@ public class RoleManageServiceImpl implements IRoleManageService {
                 			FROM dm_game_order.t_game
                 		) b on a.source_system = b.source_system AND a.game_id = b.id
                 	) u on a.source_system = u.source_system AND a.role_id = u.role_id AND d.super_game_id = u.super_game_id AND u.num =1
+                	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
                 ) a
                 """ + criA;
     }
@@ -1206,6 +1243,7 @@ public class RoleManageServiceImpl implements IRoleManageService {
                         IFNULL(c.amount, 0) as amount, -- 角色累计充值金额
                         IFNULL(c.amount_count, 0) as amount_count, -- 角色累计充值次数
                         ROUND(IF(c.amount_count > 0, c.amount / c.amount_count, 0), 2) as avg_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'
@@ -1214,7 +1252,7 @@ public class RoleManageServiceImpl implements IRoleManageService {
                             WHEN c.amount >= 20000 and c.amount < 50000 THEN '5'
                             WHEN c.amount >= 50000 THEN '6'
                             ELSE '0'
-                            END) as vip_level, -- 角色vip等级
+                            END)) as vip_level, -- 角色vip等级
                         a.game_id as role_reg_game_id, -- 角色注册游戏id
                         d.game_name as role_reg_game_name, -- 角色注册游戏名
                         d.classify as role_reg_game_classify, -- 角色注册游戏类型
@@ -1459,19 +1497,19 @@ public class RoleManageServiceImpl implements IRoleManageService {
                         ) k ON i.user_reg_game_id = k.id AND i.source_system = k.source_system
                         LEFT JOIN (
                             -- 玩家最近活跃时间
-                            SELECT
-                                association_user_id,
-                                b.source_system,
-                                b.active_time as update_time,
-                                ROW_NUMBER()over(partition by association_user_id, b.source_system order by b.active_time desc) as num
-                            FROM dm_game_order.t_game_user a
-                            LEFT JOIN (
-                                SELECT
-                                    source_system ,
-                                    user_id,
-                                    active_time
-                                FROM game_dw.dw_active_log
-                            ) b ON a.source_system = b.source_system AND a.id = b.user_id
+                			SELECT
+                			    association_user_id,
+                			    b.source_system,
+                			    b.active_time as update_time,
+                			    ROW_NUMBER()over(partition by association_user_id, b.source_system order by b.active_time desc) as num
+                			FROM dm_game_order.t_game_user a
+                			LEFT JOIN (
+                			    SELECT
+                			    	source_system ,
+                			    	user_id,
+                			    	active_time
+                			    FROM game_dw.dw_active_log
+                			) b ON a.source_system = b.source_system AND a.id = b.user_id
                         ) l ON i.association_user_id = l.association_user_id AND i.source_system = l.source_system AND l.num = 1
                         LEFT JOIN (
                             -- 玩家最近充值游戏、玩家最近充值时间
@@ -1555,26 +1593,41 @@ public class RoleManageServiceImpl implements IRoleManageService {
                         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
-                            a.source_system,
-                            a.role_id,
-                            a.role_name,
-                            a.role_level,
-                            a.combat_num ,
-                            a.game_id ,
-                            b.parent_game_id,
-                            b.super_game_id ,
-                            ROW_NUMBER()over(partition by a.source_system , a.role_id, b.parent_game_id order by a.role_level desc,a.combat_num desc) as num
-                        FROM dm_game_order.t_game_user_role a
-                        LEFT JOIN (
-                            SELECT
-                                source_system,
-                                id,
-                                IFNULL(parent_id, id) as parent_game_id,
-                                IFNULL(super_game_id, id) as super_game_id
-                            FROM dm_game_order.t_game
-                        ) b on a.source_system = b.source_system AND a.game_id = b.id
-                    ) u on a.source_system = u.source_system AND a.role_id = u.role_id AND d.super_game_id = u.super_game_id AND u.num =1
+                		SELECT
+                			a.source_system,
+                			a.role_id,
+                			a.role_name,
+                			a.role_level,
+                			a.combat_num ,
+                			a.game_id ,
+                			b.parent_game_id,
+                			b.super_game_id ,
+                			ROW_NUMBER()over(partition by a.source_system , a.role_id, b.parent_game_id order by a.role_level desc,a.combat_num desc) as num
+                		FROM dm_game_order.t_game_user_role a
+                		LEFT JOIN (
+                			SELECT
+                				source_system,
+                				id,
+                				IFNULL(parent_id, id) as parent_game_id,
+                				IFNULL(super_game_id, id) as super_game_id
+                			FROM dm_game_order.t_game
+                		) b on a.source_system = b.source_system AND a.game_id = b.id
+                	) u on a.source_system = u.source_system AND a.role_id = u.role_id AND d.super_game_id = u.super_game_id AND u.num =1
+                	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
                 ) a
                 """ + criA;
     }

+ 32 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/VipLevelServiceImpl.java

@@ -0,0 +1,32 @@
+package com.zanxiang.game.data.serve.service.impl;
+
+import com.zanxiang.game.data.serve.pojo.entity.TGameVip;
+import com.zanxiang.game.data.serve.service.IVipLevelService;
+import lombok.extern.slf4j.Slf4j;
+import org.nutz.dao.Dao;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author tianhua
+ * @version 1.0
+ * @description: TODO
+ * @date 2023/11/24 11:01
+ */
+@Service
+@Slf4j
+public class VipLevelServiceImpl implements IVipLevelService {
+
+    @Autowired
+    private Dao dao;
+
+    /**
+     * 获得最大的vip等级
+     * @return Integer
+     */
+    @Override
+    public Integer getMaxVipLevel() {
+        return (Integer) dao.func2(TGameVip.class, "MAX", "vip_level");
+    }
+
+}

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

@@ -21,7 +21,7 @@ public class ManageApplication {
 
     public static void main(String[] args) {
         SpringApplication.run(ManageApplication.class, args);
-        System.out.println("赞象Manage服务启动成功 <bug修改2> ( ´・・)ノ(._.`) \n" +
+        System.out.println("赞象Manage服务启动成功 <客服系统04> ( ´・・)ノ(._.`) \n" +
                 "___  ___  ___   _   _   ___  _____  _____ \n" +
                 "|  \\/  | / _ \\ | \\ | | / _ \\|  __ \\|  ___|\n" +
                 "| .  . |/ /_\\ \\|  \\| |/ /_\\ \\ |  \\/| |__  \n" +

+ 19 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/config/RestTemplateConfig.java

@@ -0,0 +1,19 @@
+package com.zanxiang.game.module.manage.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author : lingfeng
+ * @time : 2021-08-18
+ * @description : redis配置
+ */
+@Configuration
+public class RestTemplateConfig {
+
+    @Bean
+    public RestTemplate restTemplate() {
+        return new RestTemplate();
+    }
+}

+ 54 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/controller/GamePolicyConfigController.java

@@ -0,0 +1,54 @@
+package com.zanxiang.game.module.manage.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.zanxiang.erp.security.annotation.PreAuthorize;
+import com.zanxiang.game.module.manage.pojo.params.GamePolicyConfigAddOrUpdateParam;
+import com.zanxiang.game.module.manage.pojo.params.GamePolicyConfigListParam;
+import com.zanxiang.game.module.manage.pojo.vo.GamePolicyConfigListVO;
+import com.zanxiang.game.module.manage.service.IGamePolicyConfigService;
+import com.zanxiang.module.util.pojo.ResultVO;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @author tianhua
+ * @version 1.0
+ * @description: 游戏策略配置控制器
+ * @date 2023/11/29 13:55
+ */
+@Api(tags = "游戏策略配置")
+@RestController
+@RequestMapping("/game/policy/config")
+@Slf4j
+public class GamePolicyConfigController {
+
+    @Autowired
+    private IGamePolicyConfigService gamePolicyConfigService;
+
+    @ApiOperation(value = "游戏策略配置新增或修改")
+    @PostMapping("/add/or/update")
+    @PreAuthorize(permissionKey = "manage:gamePolicy:addOrUpdate")
+    public ResultVO<Boolean> addOrUpdate(@Validated @RequestBody GamePolicyConfigAddOrUpdateParam param) {
+        return ResultVO.ok(gamePolicyConfigService.addOrUpdate(param));
+    }
+
+    @ApiOperation(value = "游戏策略配置删除")
+    @DeleteMapping("/deleteById/{id}")
+    @PreAuthorize(permissionKey = "manage:gamePolicy:delete")
+    public ResultVO<Boolean> deleteById(@PathVariable("id") Long id) {
+        return ResultVO.ok(gamePolicyConfigService.deleteById(id));
+    }
+
+    @ApiOperation(value = "游戏策略配置列表")
+    @PostMapping("/listOfPage")
+    @PreAuthorize(permissionKey = "manage:gamePolicy:listOfPage")
+    public ResultVO<IPage<GamePolicyConfigListVO>> listOfPage(@RequestBody GamePolicyConfigListParam param) {
+        return ResultVO.ok(gamePolicyConfigService.listOfPage(param));
+    }
+
+
+}

+ 49 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/controller/KfMsgController.java

@@ -0,0 +1,49 @@
+package com.zanxiang.game.module.manage.controller;
+
+import com.zanxiang.erp.security.annotation.PreAuthorize;
+import com.zanxiang.game.module.manage.pojo.params.KfApiParam;
+import com.zanxiang.game.module.manage.pojo.vo.CpVO;
+import com.zanxiang.game.module.manage.pojo.vo.KfGameVO;
+import com.zanxiang.game.module.manage.service.IKfMsgContentService;
+import com.zanxiang.module.util.pojo.ResultVO;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-11-29
+ * @description : 客服系统接口
+ */
+@Api(tags = {"客服系统接口"})
+@RestController
+@RequestMapping("/kf")
+@Slf4j
+public class KfMsgController {
+
+    @Autowired
+    private IKfMsgContentService kfMsgContentService;
+
+    @ApiOperation(value = "小游戏列表查询")
+    @GetMapping(value = "/game/list")
+    @PreAuthorize(permissionKey = "manage:kf:gameList")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = CpVO.class)})
+    public ResultVO<List<KfGameVO>> list() {
+        return ResultVO.ok(kfMsgContentService.getKfGameList());
+    }
+
+    @ApiOperation(value = "客服接口通用api")
+    @PostMapping(value = "/comm/api")
+    @PreAuthorize(permissionKey = "manage:kf:commApi")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = CpVO.class)})
+    public ResultVO<String> list(@Validated @RequestBody KfApiParam param) {
+        return ResultVO.ok(kfMsgContentService.kfApi(param));
+    }
+}

+ 74 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/enums/KfActionEnum.java

@@ -0,0 +1,74 @@
+package com.zanxiang.game.module.manage.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-11-29
+ * @description : 客服接口行为枚举
+ */
+@Getter
+@AllArgsConstructor
+public enum KfActionEnum {
+
+    /**
+     * 客服在线状态更改
+     */
+    UPDATE_KF_ACCT("update_kf_acct"),
+
+    /**
+     * 获取客服信息
+     */
+    GET_KF_ACCT("get_kf_acct"),
+
+    /**
+     * 获取待接入信息列表
+     */
+    BATCH_GET_NO_SESSION_EXTRA_INFO("batch_get_nosession_extra_info"),
+
+    /**
+     * 接入房间会话
+     */
+    ACCEPT_ROOM("accept_room"),
+
+    /**
+     * 初始化房间 可获取房间最近的msgID
+     */
+    GET_ROOM_INFO("get_room_info"),
+
+    /**
+     * 获取房间消息
+     */
+    GET_ROOM_MSG("get_room_msg"),
+
+    /**
+     * 获取房间用户标签
+     */
+    GET_USER_TAG("get_user_tag"),
+
+    /**
+     * 每次发送消息前获取msgID
+     */
+    GET_MSG_ID("get_msg_id"),
+
+    /**
+     * 发送会话
+     */
+    SEND_ROOM_MSG("send_room_msg"),
+
+    /**
+     * 结束房间会话
+     */
+    END_ROOM("end_room"),
+
+    /**
+     * 已接入列表
+     */
+    GET_SESSION_SUMMARY("get_session_summary");
+
+    /**
+     * 接口行为
+     */
+    private String value;
+}

+ 80 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/enums/KfApiEnum.java

@@ -0,0 +1,80 @@
+package com.zanxiang.game.module.manage.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-11-29
+ * @description : 客服接口API枚举
+ */
+@Getter
+@AllArgsConstructor
+public enum KfApiEnum {
+
+    /**
+     * 客服信息
+     */
+    ACCT("https://mpkf.weixin.qq.com/commkf/acct", new KfActionEnum[]{
+            KfActionEnum.UPDATE_KF_ACCT, KfActionEnum.GET_KF_ACCT
+    }),
+
+    /**
+     * 房间
+     */
+    ROOM("https://mpkf.weixin.qq.com/commkf/room", new KfActionEnum[]{
+            KfActionEnum.ACCEPT_ROOM, KfActionEnum.GET_ROOM_INFO, KfActionEnum.GET_USER_TAG
+    }),
+
+    /**
+     * 消息
+     */
+    MSG("https://mpkf.weixin.qq.com/commkf/msg", new KfActionEnum[]{
+            KfActionEnum.GET_ROOM_MSG, KfActionEnum.GET_MSG_ID, KfActionEnum.SEND_ROOM_MSG, KfActionEnum.END_ROOM
+    }),
+
+    /**
+     * 报告
+     */
+    REPORT("https://mpkf.weixin.qq.com/commkf/report", new KfActionEnum[]{
+            KfActionEnum.ACCEPT_ROOM
+    }),
+
+    /**
+     * 总汇表
+     */
+    SUMMARY("https://mpkf.weixin.qq.com/commkf/summary", new KfActionEnum[]{
+            KfActionEnum.BATCH_GET_NO_SESSION_EXTRA_INFO
+    });
+
+    /**
+     * 接口地址
+     */
+    private String apiUrl;
+
+    /**
+     * 行为枚举
+     */
+    private KfActionEnum[] kfActionEnums;
+
+    /**
+     * 根据行为获取api地址
+     *
+     * @param kfActionEnum : 接口行为枚举
+     * @return : 返回api地址
+     */
+    public static String getApiUrl(KfActionEnum kfActionEnum) {
+        for (KfApiEnum kfApiEnum : KfApiEnum.values()) {
+            KfActionEnum action = Arrays.stream(kfApiEnum.getKfActionEnums())
+                    .filter(actionEnum -> Objects.equals(kfActionEnum, actionEnum))
+                    .findFirst().orElse(null);
+            if (action != null) {
+                return kfApiEnum.getApiUrl();
+            }
+        }
+        return null;
+    }
+}

+ 57 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/dto/KfMsgResultDTO.java

@@ -0,0 +1,57 @@
+package com.zanxiang.game.module.manage.pojo.dto;
+
+import lombok.Data;
+
+import java.util.Objects;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-11-29
+ * @description : 客服接口返回
+ */
+@Data
+public class KfMsgResultDTO {
+
+    /**
+     * 请求成功
+     */
+    public static final Long SUCCESS = 0L;
+
+    /**
+     * 鉴权失败, token, cookie过期
+     */
+    public static final Long EXPIRE = 30000L;
+
+    /**
+     * 接口结果
+     */
+    private BaseRespBean base_resp;
+
+    @Data
+    public static class BaseRespBean {
+
+        /**
+         * 异常消息
+         */
+        private String err_msg;
+
+        /**
+         * 状态code
+         */
+        private Long ret;
+    }
+
+    public Boolean isSueecss() {
+        if (this.base_resp == null) {
+            return Boolean.FALSE;
+        }
+        return Objects.equals(this.base_resp.getRet(), KfMsgResultDTO.SUCCESS);
+    }
+
+    public Boolean isExpire() {
+        if (this.base_resp == null) {
+            return Boolean.FALSE;
+        }
+        return Objects.equals(this.base_resp.getRet(), KfMsgResultDTO.EXPIRE);
+    }
+}

+ 56 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/params/GamePolicyConfigAddOrUpdateParam.java

@@ -0,0 +1,56 @@
+package com.zanxiang.game.module.manage.pojo.params;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author tianhua
+ * @version 1.0
+ * @description: 游戏策略添加或修改参数
+ * @date 2023/11/29 14:32
+ */
+@Data
+public class GamePolicyConfigAddOrUpdateParam {
+
+    /**
+     * 传id为修改, 不传id为新增
+     */
+    @ApiModelProperty("传id为修改, 不传id为新增")
+    private Long id;
+
+    /**
+     * 超父游戏id
+     */
+    @NotNull(message = "超父游戏id不能为空")
+    @ApiModelProperty("超父游戏id")
+    private Long superGameId;
+
+    /**
+     * 策略类型
+     */
+    @NotNull(message = "策略类型不能为空")
+    @ApiModelProperty("策略类型")
+    private Long type;
+
+    /**
+     * 金额
+     */
+    @ApiModelProperty("金额")
+    private Long amount;
+
+    /**
+     * 时间(单位:小时)
+     */
+    @ApiModelProperty("时间(单位:小时)")
+    private Long time;
+
+    /**
+     * 配置说明
+     */
+    @NotNull(message = "配置说明不能为空")
+    @ApiModelProperty("配置说明:请写出具体的配置细节。如:首次充值金额大于500并且注册时间24小时内的用户,发送钉钉消息")
+    private String configExplain;
+
+}

+ 31 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/params/GamePolicyConfigListParam.java

@@ -0,0 +1,31 @@
+package com.zanxiang.game.module.manage.pojo.params;
+
+import com.zanxiang.game.module.mybatis.entity.GamePolicyConfig;
+import com.zanxiang.module.web.pojo.BaseListDTO;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author tianhua
+ * @version 1.0
+ * @description: 游戏策略列表参数
+ * @date 2023/11/29 14:32
+ */
+@Data
+public class GamePolicyConfigListParam extends BaseListDTO<GamePolicyConfig> {
+
+    /**
+     * 超父游戏id
+     */
+    @ApiModelProperty("超父游戏id")
+    private Long superGameId;
+
+    /**
+     * 策略类型
+     */
+    @ApiModelProperty("策略类型")
+    private Long type;
+
+}

+ 38 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/params/KfApiParam.java

@@ -0,0 +1,38 @@
+package com.zanxiang.game.module.manage.pojo.params;
+
+import com.zanxiang.game.module.manage.enums.KfActionEnum;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.util.Map;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-11-28
+ * @description : 客服接口参数
+ */
+@Data
+public class KfApiParam {
+
+    /**
+     * 游戏应用id
+     */
+    @NotBlank(message = "游戏应用参数不可为空")
+    @ApiModelProperty(notes = "游戏应用参数")
+    private String appId;
+
+    /**
+     * 行为动作
+     */
+    @NotNull(message = "接口行为")
+    @ApiModelProperty(notes = "行为动作")
+    private KfActionEnum action;
+
+    /**
+     * 接口body参数
+     */
+    @ApiModelProperty(notes = "接口body参数")
+    private Map<String, Object> param;
+}

+ 30 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/vo/GamePolicyConfigInnerObjVO.java

@@ -0,0 +1,30 @@
+package com.zanxiang.game.module.manage.pojo.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author tianhua
+ * @version 1.0
+ * @description: TODO
+ * @date 2023/11/29 15:10
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class GamePolicyConfigInnerObjVO {
+
+    /**
+     * 金额
+     */
+    private Long amount;
+
+    /**
+     * 时间(单位:小时)
+     */
+    private Long time;
+
+}

+ 104 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/vo/GamePolicyConfigListVO.java

@@ -0,0 +1,104 @@
+package com.zanxiang.game.module.manage.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.LocalDateTime;
+
+/**
+ * @author tianhua
+ * @version 1.0
+ * @description: TODO
+ * @date 2023/11/29 14:45
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class GamePolicyConfigListVO {
+
+    /**
+     * 主键id
+     */
+    @ApiModelProperty(notes = "主键id")
+    private Long id;
+
+    /**
+     * 超父游戏id
+     */
+    @ApiModelProperty("超父游戏id")
+    private Long superGameId;
+
+    /**
+     * 超父游戏名称
+     */
+    @ApiModelProperty("超父游戏名称")
+    private String superGameName;
+
+    /**
+     * 策略类型:1-追踪玩家;2-玩家流失;3-新用户追踪
+     * 1:单笔充值金额大于XX,并且注册时间在XX小时内的玩家
+     * 2:累计充值金额大于XX,并且最近游戏距今时间超过XX小时的玩家
+     * 3:新用户注册创角首日充值大于XX的用户
+     */
+    @ApiModelProperty("策略类型:1-追踪玩家策略;2-玩家流失策略;3-新用户追踪策略")
+    private Long type;
+
+    /**
+     * 金额
+     */
+    @ApiModelProperty("金额")
+    private Long amount;
+
+    /**
+     * 时间(单位:小时)
+     */
+    @ApiModelProperty("时间(单位:小时)")
+    private Long time;
+
+    /**
+     * 配置说明
+     */
+    private String configExplain;
+
+    /**
+     * 创建时间
+     */
+    @ApiModelProperty("创建时间")
+    private LocalDateTime createTime;
+
+    /**
+     * 创建者
+     */
+    @ApiModelProperty("创建者")
+    private Long createBy;
+
+    /**
+     * 创建者名称
+     */
+    @ApiModelProperty("创建者名称")
+    private String createName;
+
+    /**
+     * 更新时间
+     */
+    @ApiModelProperty("更新时间")
+    private LocalDateTime updateTime;
+
+    /**
+     * 更新者
+     */
+    @ApiModelProperty("更新者")
+    private Long updateBy;
+
+    /**
+     * 更新者名称
+     */
+    @ApiModelProperty("更新者名称")
+    private String updateName;
+
+}

+ 37 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/vo/KfGameVO.java

@@ -0,0 +1,37 @@
+package com.zanxiang.game.module.manage.pojo.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-11-29
+ * @description : 客服游戏
+ */
+@Data
+public class KfGameVO {
+
+    /**
+     * 应用id
+     */
+    @ApiModelProperty(notes = "应用id")
+    private String appId;
+
+    /**
+     * 应用名称
+     */
+    @ApiModelProperty(notes = "应用名称")
+    private String appName;
+
+    /**
+     * 是否授权
+     */
+    @ApiModelProperty(notes = "是否授权")
+    private Boolean isAuth;
+
+    /**
+     * 是否有效
+     */
+    @ApiModelProperty(notes = "是否有效, isAuth 为false未授权时, 该值为null")
+    private Boolean isValid;
+}

+ 21 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/IGamePolicyConfigService.java

@@ -0,0 +1,21 @@
+package com.zanxiang.game.module.manage.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.module.manage.pojo.params.GamePolicyConfigAddOrUpdateParam;
+import com.zanxiang.game.module.manage.pojo.params.GamePolicyConfigListParam;
+import com.zanxiang.game.module.manage.pojo.vo.GamePolicyConfigListVO;
+import com.zanxiang.game.module.mybatis.entity.GamePolicyConfig;
+
+/**
+ * @author tianhua
+ */
+public interface IGamePolicyConfigService extends IService<GamePolicyConfig> {
+
+    boolean addOrUpdate(GamePolicyConfigAddOrUpdateParam param);
+
+    boolean deleteById(Long id);
+
+    IPage<GamePolicyConfigListVO> listOfPage(GamePolicyConfigListParam param);
+
+}

+ 31 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/IKfMsgContentService.java

@@ -0,0 +1,31 @@
+package com.zanxiang.game.module.manage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.module.manage.pojo.params.KfApiParam;
+import com.zanxiang.game.module.manage.pojo.vo.KfGameVO;
+import com.zanxiang.game.module.mybatis.entity.KfMsgContent;
+
+import java.util.List;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-11-28
+ * @description :
+ */
+public interface IKfMsgContentService extends IService<KfMsgContent> {
+
+    /**
+     * 获取游戏列表
+     *
+     * @return : 返回游戏列表
+     */
+    List<KfGameVO> getKfGameList();
+
+    /**
+     * 腾讯通用api接口
+     *
+     * @param param : 请求参数
+     * @return : 返回结果
+     */
+    String kfApi(KfApiParam param);
+}

+ 21 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/IKfUserService.java

@@ -0,0 +1,21 @@
+package com.zanxiang.game.module.manage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.module.mybatis.entity.KfUser;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-11-28
+ * @description : 客服用户信息
+ */
+public interface IKfUserService extends IService<KfUser> {
+
+    /**
+     * 获取客服用户信息
+     *
+     * @param kfUserId : 用户id
+     * @param appId    : 应用id
+     * @return : 返回用户信息
+     */
+    KfUser getKfUser(Long kfUserId, String appId);
+}

+ 141 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/GamePolicyConfigServiceImpl.java

@@ -0,0 +1,141 @@
+package com.zanxiang.game.module.manage.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zanxiang.erp.base.ErpServer;
+import com.zanxiang.erp.base.rpc.ISysUserRpc;
+import com.zanxiang.erp.security.util.SecurityUtil;
+import com.zanxiang.game.module.manage.pojo.params.GamePolicyConfigAddOrUpdateParam;
+import com.zanxiang.game.module.manage.pojo.params.GamePolicyConfigListParam;
+import com.zanxiang.game.module.manage.pojo.vo.GamePolicyConfigInnerObjVO;
+import com.zanxiang.game.module.manage.pojo.vo.GamePolicyConfigListVO;
+import com.zanxiang.game.module.manage.service.IGamePolicyConfigService;
+import com.zanxiang.game.module.manage.service.IGameSupperService;
+import com.zanxiang.game.module.mybatis.entity.GamePolicyConfig;
+import com.zanxiang.game.module.mybatis.entity.GameSupper;
+import com.zanxiang.game.module.mybatis.mapper.GamePolicyConfigMapper;
+import com.zanxiang.module.util.JsonUtil;
+import com.zanxiang.module.util.exception.BaseException;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.util.Map;
+
+/**
+ * @author tianhua
+ * @version 1.0
+ * @description: TODO
+ * @date 2023/11/29 14:25
+ */
+@Service
+@Slf4j
+public class GamePolicyConfigServiceImpl extends ServiceImpl<GamePolicyConfigMapper, GamePolicyConfig> implements IGamePolicyConfigService {
+
+    @Autowired
+    private IGameSupperService gameSupperService;
+
+    @DubboReference(providedBy = ErpServer.SERVER_DUBBO_NAME)
+    private ISysUserRpc sysUserRpc;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean addOrUpdate(GamePolicyConfigAddOrUpdateParam param) {
+        if (param.getAmount() == null && param.getTime() == null) {
+            throw new BaseException("策略配置的金额和时间不能同时为空,请重新输入。");
+        }
+        //当前操作人员
+        Long sysUserId = SecurityUtil.getUserId();
+        //当前操作时间
+        LocalDateTime now = LocalDateTime.now();
+
+        //生成配置json字符串
+        String configParam = JsonUtil.toString(GamePolicyConfigInnerObjVO.builder()
+                .amount(param.getAmount())
+                .time(param.getTime())
+                .build());
+
+        int count = this.count(new LambdaQueryWrapper<GamePolicyConfig>()
+                .ne(param.getId() != null, GamePolicyConfig::getId, param.getId())
+                .eq(GamePolicyConfig::getSuperGameId, param.getSuperGameId())
+                .eq(GamePolicyConfig::getType, param.getType())
+                .eq(GamePolicyConfig::getConfigParam, configParam)
+                .eq(GamePolicyConfig::getEnabled, true));
+
+        if (count > 0) {
+            throw new BaseException("该游戏策略配置已经设置过,请勿重复设置");
+        }
+
+        GamePolicyConfig gamePolicyConfig = GamePolicyConfig.builder()
+                .superGameId(param.getSuperGameId())
+                .type(param.getType())
+                .configParam(configParam)
+                .configExplain(param.getConfigExplain())
+                .updateBy(sysUserId)
+                .updateTime(now)
+                .build();
+
+        if (param.getId() != null) {
+            //id不为空,表示修改配置
+            gamePolicyConfig.setId(param.getId());
+            return updateById(gamePolicyConfig);
+        }
+
+        //id为空,表示新增配置
+        gamePolicyConfig.setCreateBy(sysUserId);
+        gamePolicyConfig.setCreateTime(now);
+        return save(gamePolicyConfig);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean deleteById(Long id) {
+        //当前操作人员
+        Long sysUserId = SecurityUtil.getUserId();
+        return update(new LambdaUpdateWrapper<GamePolicyConfig>()
+                .set(GamePolicyConfig::getEnabled, false)
+                .set(GamePolicyConfig::getUpdateBy, sysUserId)
+                .set(GamePolicyConfig::getUpdateTime, LocalDateTime.now())
+                .eq(GamePolicyConfig::getId, id));
+    }
+
+    @Override
+    public IPage<GamePolicyConfigListVO> listOfPage(GamePolicyConfigListParam param) {
+        return page(param.toPage(), new LambdaQueryWrapper<GamePolicyConfig>()
+                .eq(param.getSuperGameId() != null, GamePolicyConfig::getSuperGameId, param.getSuperGameId())
+                .eq(param.getType() != null , GamePolicyConfig::getType, param.getType())
+                .eq(GamePolicyConfig::getEnabled, true))
+                .convert(this::toVO);
+    }
+
+    private GamePolicyConfigListVO toVO(GamePolicyConfig vo) {
+        //得到配置参数map
+        Map<String, String> configParam = JsonUtil.toMap(vo.getConfigParam(), Map.class, String.class);
+        String amount = configParam.get("amount");
+        String time = configParam.get("time");
+        GameSupper gameSupper = gameSupperService.getById(vo.getSuperGameId());
+        return GamePolicyConfigListVO.builder()
+                .id(vo.getId())
+                .superGameId(vo.getSuperGameId())
+                .superGameName(null == gameSupper ? null : gameSupper.getName())
+                .type(vo.getType())
+                .amount(amount == null ? null : Long.valueOf(amount))
+                .time(time == null ? null : Long.valueOf(time))
+                .configExplain(vo.getConfigExplain())
+                .createBy(vo.getCreateBy())
+                .createName(sysUserRpc.getById(vo.getCreateBy()).getData().getNickname())
+                .createTime(vo.getCreateTime())
+                .updateBy(vo.getUpdateBy())
+                .updateName(sysUserRpc.getById(vo.getUpdateBy()).getData().getNickname())
+                .updateTime(vo.getUpdateTime())
+                .build();
+    }
+
+
+
+}

+ 122 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/KfMsgContentServiceImpl.java

@@ -0,0 +1,122 @@
+package com.zanxiang.game.module.manage.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zanxiang.erp.security.util.SecurityUtil;
+import com.zanxiang.game.module.manage.enums.KfActionEnum;
+import com.zanxiang.game.module.manage.enums.KfApiEnum;
+import com.zanxiang.game.module.manage.pojo.dto.KfMsgResultDTO;
+import com.zanxiang.game.module.manage.pojo.params.KfApiParam;
+import com.zanxiang.game.module.manage.pojo.vo.KfGameVO;
+import com.zanxiang.game.module.manage.service.IGameAppletService;
+import com.zanxiang.game.module.manage.service.IGameAuthService;
+import com.zanxiang.game.module.manage.service.IKfMsgContentService;
+import com.zanxiang.game.module.manage.service.IKfUserService;
+import com.zanxiang.game.module.mybatis.entity.GameApplet;
+import com.zanxiang.game.module.mybatis.entity.GameAuth;
+import com.zanxiang.game.module.mybatis.entity.KfMsgContent;
+import com.zanxiang.game.module.mybatis.entity.KfUser;
+import com.zanxiang.game.module.mybatis.mapper.KfMsgContentMapper;
+import com.zanxiang.module.util.JsonUtil;
+import com.zanxiang.module.util.URIUtil;
+import com.zanxiang.module.util.bean.BeanUtil;
+import com.zanxiang.module.util.exception.BaseException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-11-27
+ * @description : 客服消息
+ */
+@Slf4j
+@Service
+public class KfMsgContentServiceImpl extends ServiceImpl<KfMsgContentMapper, KfMsgContent> implements IKfMsgContentService {
+
+    @Autowired
+    private RestTemplate restTemplate;
+
+    @Autowired
+    private IKfUserService kfUserService;
+
+    @Autowired
+    private IGameAuthService gameAuthService;
+
+    @Autowired
+    private IGameAppletService gameAppletService;
+
+    @Override
+    public List<KfGameVO> getKfGameList() {
+        List<GameAuth> gameAuthList = gameAuthService.list(new LambdaQueryWrapper<GameAuth>()
+                .eq(!SecurityUtil.isAdmin(), GameAuth::getUserId, SecurityUtil.getUserId()));
+        if (!SecurityUtil.isAdmin() && CollectionUtils.isEmpty(gameAuthList)) {
+            return Collections.emptyList();
+        }
+        return gameAppletService.list(new LambdaQueryWrapper<GameApplet>()
+                .eq(GameApplet::getType, 1)
+                .in(!SecurityUtil.isAdmin(), GameApplet::getGameId,
+                        gameAuthList.stream().map(GameAuth::getGameId).collect(Collectors.toSet()))
+        ).stream().map(this::toVO).collect(Collectors.toList());
+    }
+
+    private KfGameVO toVO(GameApplet gameApplet) {
+        KfGameVO kfGameVO = BeanUtil.copy(gameApplet, KfGameVO.class);
+        if (kfGameVO == null) {
+            return null;
+        }
+        //判断是否存在授权记录
+        KfUser kfUser = kfUserService.getOne(new LambdaQueryWrapper<KfUser>()
+                .eq(KfUser::getKfUserId, SecurityUtil.getUserId())
+                .eq(KfUser::getAppId, kfGameVO.getAppId()));
+        kfGameVO.setIsAuth(kfUser != null ? Boolean.TRUE : Boolean.FALSE);
+        if (kfUser == null) {
+            return kfGameVO;
+        }
+        //判断授权信息是否过期, 请求获取客服信息接口
+        String result = this.commKfApi(kfUser, KfActionEnum.GET_KF_ACCT.getValue(),
+                KfApiEnum.getApiUrl(KfActionEnum.GET_KF_ACCT), Collections.emptyMap());
+        KfMsgResultDTO kfMsgResultDTO = JsonUtil.toObj(result, KfMsgResultDTO.class);
+        kfGameVO.setIsValid(kfMsgResultDTO.isSueecss());
+        return kfGameVO;
+    }
+
+    @Override
+    public String kfApi(KfApiParam param) {
+        log.error("请求参数, param : {}", JsonUtil.toString(param));
+        //查询用户授权信息
+        KfUser kfUser = kfUserService.getKfUser(SecurityUtil.getUserId(), param.getAppId());
+        //请求调用腾讯接口
+        return this.commKfApi(kfUser, param.getAction().getValue(), KfApiEnum.getApiUrl(param.getAction()), param.getParam());
+    }
+
+    private String commKfApi(KfUser kfUser, String action, String url, Map<String, Object> param) {
+        Map<String, String> pathParam = new HashMap<>(3);
+        pathParam.put("action", action);
+        pathParam.put("f", "json");
+        pathParam.put("token", kfUser.getToken());
+        HttpHeaders headers = new HttpHeaders();
+        headers.add("cookie", kfUser.getCookie());
+        ResponseEntity<String> responseEntity;
+        try {
+            responseEntity = restTemplate.exchange(URIUtil.fillUrlParams(url, pathParam, Boolean.FALSE),
+                    HttpMethod.POST, new HttpEntity<>(param, headers), String.class);
+        } catch (Exception e) {
+            log.error("腾讯接口调用异常, e : {}", e.getMessage());
+            throw new BaseException("腾讯接口调用异常!");
+        }
+        return responseEntity.getBody();
+    }
+}

+ 31 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/KfUserServiceImpl.java

@@ -0,0 +1,31 @@
+package com.zanxiang.game.module.manage.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zanxiang.game.module.manage.service.IKfUserService;
+import com.zanxiang.game.module.mybatis.entity.KfUser;
+import com.zanxiang.game.module.mybatis.mapper.KfUserMapper;
+import com.zanxiang.module.util.exception.BaseException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-11-27
+ * @description : 客服用户信息
+ */
+@Slf4j
+@Service
+public class KfUserServiceImpl extends ServiceImpl<KfUserMapper, KfUser> implements IKfUserService {
+
+    @Override
+    public KfUser getKfUser(Long kfUserId, String appId) {
+        KfUser kfUser = super.getOne(new LambdaQueryWrapper<KfUser>()
+                .eq(KfUser::getKfUserId, kfUserId)
+                .eq(KfUser::getAppId, appId));
+        if (kfUser == null) {
+            throw new BaseException("参数错误, 客服用户信息不存在");
+        }
+        return kfUser;
+    }
+}

+ 75 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/GamePolicyConfig.java

@@ -0,0 +1,75 @@
+package com.zanxiang.game.module.mybatis.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author tianhua
+ * @version 1.0
+ * @description: 游戏策略具体配置表
+ * @date 2023/11/29 14:01
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@ToString
+@Builder
+@TableName("t_game_policy_config")
+public class GamePolicyConfig {
+
+    /**
+     * 主键id
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 超父游戏ID
+     */
+    private Long superGameId;
+
+    /**
+     * 策略类型:1-追踪玩家;2-玩家流失;3-新用户追踪
+     */
+    private Long type;
+
+    /**
+     * 游戏策略的配置参数,json数据:amount-金额;time-时间(小时)
+     */
+    private String configParam;
+
+    /**
+     * 配置说明
+     */
+    private String configExplain;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 创建者
+     */
+    private Long createBy;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 更新者
+     */
+    private Long updateBy;
+
+    /**
+     * 1 正常  0 删除
+     */
+    private Boolean enabled;
+
+}

+ 83 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/KfMsgContent.java

@@ -0,0 +1,83 @@
+package com.zanxiang.game.module.mybatis.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-11-27
+ * @description : 客服消息记录
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@ToString
+@Builder
+@TableName("t_kf_msg_content")
+public class KfMsgContent implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 消息id
+     */
+    private String msgId;
+
+    /**
+     * 消息类型
+     */
+    private Integer msgType;
+
+    /**
+     * 房间id
+     */
+    private String roomId;
+
+    /**
+     * 消息内容
+     */
+    private String msgKfContent;
+
+    /**
+     * 拓展信息
+     */
+    private String extraInfo;
+
+    /**
+     * 发送账号(客服消息才有值)
+     */
+    private String sendOpenAccount;
+
+    /**
+     * 发送者openid
+     */
+    private String sendOpenid;
+
+    /**
+     * 发送场景
+     */
+    private Integer sendScene;
+
+    /**
+     * session
+     */
+    private String sessionId;
+
+    /**
+     * 是否删除
+     */
+    private Integer isDelete;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 53 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/KfUser.java

@@ -0,0 +1,53 @@
+package com.zanxiang.game.module.mybatis.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-11-27
+ * @description : 客服用户
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@ToString
+@Builder
+@TableName("t_kf_user")
+public class KfUser implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 客服用户id
+     */
+    private Long kfUserId;
+
+    /**
+     * 应用id
+     */
+    private String appId;
+
+    /**
+     * 请求token
+     */
+    private String token;
+
+    /**
+     * 请求cookie
+     */
+    private String cookie;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 7 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/mapper/GamePolicyConfigMapper.java

@@ -0,0 +1,7 @@
+package com.zanxiang.game.module.mybatis.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zanxiang.game.module.mybatis.entity.GamePolicyConfig;
+
+public interface GamePolicyConfigMapper extends BaseMapper<GamePolicyConfig> {
+}

+ 12 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/mapper/KfMsgContentMapper.java

@@ -0,0 +1,12 @@
+package com.zanxiang.game.module.mybatis.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zanxiang.game.module.mybatis.entity.KfMsgContent;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-11-27
+ * @description :  ${description}
+ */
+public interface KfMsgContentMapper extends BaseMapper<KfMsgContent> {
+}

+ 12 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/mapper/KfUserMapper.java

@@ -0,0 +1,12 @@
+package com.zanxiang.game.module.mybatis.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zanxiang.game.module.mybatis.entity.KfUser;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-11-27
+ * @description : ${description}
+ */
+public interface KfUserMapper extends BaseMapper<KfUser> {
+}

+ 1 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/LoginServiceImpl.java

@@ -106,6 +106,7 @@ public class LoginServiceImpl implements IRegisterLoginService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public ResultVO<UserLoginVO> loginWxCode(LoginVxCodeParam param, UserData userData, HttpServletRequest request) {
+        log.error("登录请求参数 , param : {}, userData : {}", JsonUtil.toString(param), JsonUtil.toString(userData));
         //验证登录ip是否封禁
         if (ipBanService.checkIpBan(userData)) {
             return ResultVO.fail(HttpStatusEnum.IP_HALT.getMsg());