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

Merge remote-tracking branch 'origin/package' into package

wcc 11 hónapja
szülő
commit
ee35f044c2
83 módosított fájl, 3375 hozzáadás és 1183 törlés
  1. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/config/CheckConfig.java
  2. 0 4
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/AdsGameServerController.java
  3. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/AdsPromotionDayController.java
  4. 8 3
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/GameMonitorAlarmController.java
  5. 61 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/GameUserConfigController.java
  6. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/RankingController.java
  7. 10 5
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/RoleManageController.java
  8. 37 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/GameUserConfigCreateOrUpdateDTO.java
  9. 23 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/GameUserConfigListDTO.java
  10. 1 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/RoleRechargeRankingDTO.java
  11. 30 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/entity/GameUserConfig.java
  12. 3 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/AdsOrderDetailVO.java
  13. 6 3
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GSGameServerDayVO.java
  14. 26 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GSServerRetentionVO.java
  15. 52 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameDataDayTotalVO.java
  16. 55 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameDataDayVO.java
  17. 51 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameDataTotalTotalVO.java
  18. 51 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameDataTotalVO.java
  19. 54 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameUserConfigListVO.java
  20. 7 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/IGameServerService.java
  21. 37 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/IGameUserConfigService.java
  22. 4 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/IRoleManageService.java
  23. 10 6
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/AdsOrderDetailServiceImpl.java
  24. 0 2
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GSGameServerTotalRVo.java
  25. 615 130
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GameDataServiceImpl.java
  26. 3 2
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GameListServiceImpl.java
  27. 113 31
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GameServerServiceImpl.java
  28. 176 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GameUserConfigServiceImpl.java
  29. 1 0
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/IActiveDataServiceImpl.java
  30. 0 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/IWebVisitLogServiceImpl.java
  31. 4 1
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/PitcherDataServiceImpl.java
  32. 505 471
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/RoleManageServiceImpl.java
  33. 61 24
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/task/GameMonitorAlarmTask.java
  34. 51 10
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/task/OrderCostMonitorAlarmTask.java
  35. 1 1
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/ManageApplication.java
  36. 8 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/controller/GameServerController.java
  37. 38 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/controller/api/AppletServerApi.java
  38. 46 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/controller/api/CpServerApi.java
  39. 40 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/enums/KfSessionFromEnum.java
  40. 3 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/handler/GlobalExceptionHandler.java
  41. 5 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/dto/KfAppletMsgDTO.java
  42. 53 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/params/ChatSubmitParam.java
  43. 65 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/params/OpenGameServerParam.java
  44. 51 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/params/UserAppletSubmitParam.java
  45. 4 17
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/rpc/impl/PayBoxRpcImpl.java
  46. 0 23
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/IAppletCheckService.java
  47. 28 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/IGameExtService.java
  48. 12 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/IKfAppletReplyService.java
  49. 18 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/IListenCallService.java
  50. 21 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/IUserAppletService.java
  51. 135 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/api/CpServerApiService.java
  52. 0 289
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/AppletCheckServiceImpl.java
  53. 3 17
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/CpSendMsgLogServiceImpl.java
  54. 29 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/GameExtServiceImpl.java
  55. 85 10
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/KfAppletMsgServiceImpl.java
  56. 18 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/KfAppletReplyServiceImpl.java
  57. 109 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/ListenCallServiceImpl.java
  58. 103 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/UserAppletServiceImpl.java
  59. 0 61
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/task/PayApplicationTask.java
  60. 37 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/utils/SignUtil.java
  61. 1 1
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/websocket/KfMsgWebsocketHandler.java
  62. 5 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/GameSupper.java
  63. 66 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/KfAppletReply.java
  64. 5 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/KfSessionUser.java
  65. 63 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/UserApplet.java
  66. 12 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/mapper/KfAppletReplyMapper.java
  67. 12 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/mapper/UserAppletMapper.java
  68. 1 1
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/SDKApplication.java
  69. 1 1
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/controller/PayController.java
  70. 10 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/controller/UserController.java
  71. 5 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/enums/KafkaEventTrackEnum.java
  72. 12 3
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/handler/GlobalExceptionHandler.java
  73. 57 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/GameUserRoleSubmitParam.java
  74. 0 31
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/GameUserRoleUpdateParam.java
  75. 8 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/vo/GameInitVO.java
  76. 8 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IGameUserRoleService.java
  77. 21 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IUserTokenService.java
  78. 9 1
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/AgentServiceImpl.java
  79. 12 12
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/CallBackServiceImpl.java
  80. 3 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/GameAppletServiceImpl.java
  81. 85 13
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/GameUserRoleServiceImpl.java
  82. 8 2
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/PerformOrderServiceImpl.java
  83. 4 2
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/UserTokenServiceImpl.java

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

@@ -1,6 +1,5 @@
 package com.zanxiang.game.data.serve.config;
 
-import com.aliyun.tea.interceptor.RequestInterceptor;
 import com.zanxiang.game.data.serve.intercept.WebVisitLogIntercept;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;

+ 0 - 4
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/AdsGameServerController.java

@@ -70,8 +70,4 @@ public class AdsGameServerController {
     public ResultVO<GSGameServerDayVO> getGSGameServerDataDayTotal(@RequestBody GSGameServerDayDTO dto) {
         return ResultVO.ok(gameServerService.getGSGameServerDataDayTotal(dto));
     }
-
-
-
-
 }

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

@@ -1,7 +1,6 @@
 package com.zanxiang.game.data.serve.controller;
 
 import com.zanxiang.erp.security.annotation.PreAuthorize;
-import com.zanxiang.game.data.serve.annotation.Log;
 import com.zanxiang.game.data.serve.pojo.dto.PromotionDayDTO;
 import com.zanxiang.game.data.serve.pojo.dto.PromotionDayTotalDTO;
 import com.zanxiang.game.data.serve.pojo.dto.TencentPromotionDayDTO;

+ 8 - 3
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/GameMonitorAlarmController.java

@@ -1,6 +1,7 @@
 package com.zanxiang.game.data.serve.controller;
 
 import com.zanxiang.game.data.serve.service.IGameMonitorAlarmService;
+import com.zanxiang.game.data.serve.service.IGameServerService;
 import com.zanxiang.game.data.serve.service.IOrderCostMonitorAlarmService;
 import com.zanxiang.module.util.pojo.ResultVO;
 import io.swagger.annotations.Api;
@@ -11,6 +12,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.annotation.Resource;
+import java.util.List;
 
 /**
  * @author tianhua
@@ -27,6 +29,8 @@ public class GameMonitorAlarmController {
     private IGameMonitorAlarmService gameMonitorAlarmService;
     @Resource
     private IOrderCostMonitorAlarmService orderCostMonitorAlarmService;
+    @Resource
+    private IGameServerService gameServerService;
 
     @ApiOperation(value = "发送钉钉消息")
     @PutMapping("/sendMsg")
@@ -35,10 +39,11 @@ public class GameMonitorAlarmController {
     }
 
 
-    @ApiOperation(value = "监控")
+    @ApiOperation(value = "测试")
     @PutMapping("/monitor")
-    public ResultVO<Boolean> monitor() {
-        orderCostMonitorAlarmService.testSendSms("测试短信");
+    public ResultVO<Boolean> test() {
+        List<String> serverIdByGSId = gameServerService.getServerIdByGSId(120L);
+        serverIdByGSId.forEach(System.out::println);
 //        orderCostMonitorAlarmService.monitorTencentCostStatus();
 //        orderCostMonitorAlarmService.monitorDataStatus();
         return ResultVO.ok();

+ 61 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/GameUserConfigController.java

@@ -0,0 +1,61 @@
+package com.zanxiang.game.data.serve.controller;
+
+import com.zanxiang.erp.security.annotation.PreAuthorize;
+import com.zanxiang.game.data.serve.pojo.dto.GameUserConfigCreateOrUpdateDTO;
+import com.zanxiang.game.data.serve.pojo.dto.GameUserConfigListDTO;
+import com.zanxiang.game.data.serve.pojo.vo.GameUserConfigListVO;
+import com.zanxiang.game.data.serve.service.IGameUserConfigService;
+import com.zanxiang.game.data.serve.utils.Page;
+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.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+
+/**
+ * packageName com.zanxiang.game.data.serve.controller
+ *
+ * @author ZhangXianyu
+ * @date 2024/4/18
+ * @description 有效创角配置管理
+ */
+@Api(tags = "有效创角配置管理")
+@RestController
+@RequestMapping("/gameUserConfig")
+@Slf4j
+public class GameUserConfigController {
+
+    @Resource
+    private IGameUserConfigService gameUserConfigService;
+
+    @ApiOperation(value = "有效创角配置列表")
+    @PreAuthorize(permissionKey = "roleManage:validRoleConfig:list")
+    @PostMapping(value = "/list")
+    public ResultVO<Page<GameUserConfigListVO>> validRoleConfigList(@Validated @RequestBody GameUserConfigListDTO dto) {
+        return ResultVO.ok(gameUserConfigService.validRoleConfigList(dto));
+    }
+
+    @ApiOperation(value = "新增有效创角配置")
+    @PreAuthorize(permissionKey = "roleManage:validRoleConfig:create")
+    @PostMapping(value = "/create")
+    public ResultVO<Boolean> create(@Validated @RequestBody GameUserConfigCreateOrUpdateDTO dto) {
+        return ResultVO.ok(gameUserConfigService.create(dto));
+    }
+    @ApiOperation(value = "修改有效创角配置")
+    @PreAuthorize(permissionKey = "roleManage:validRoleConfig:update")
+    @PostMapping(value = "/update")
+    public ResultVO<Boolean> update(@Validated @RequestBody GameUserConfigCreateOrUpdateDTO dto) {
+        return ResultVO.ok(gameUserConfigService.update(dto));
+    }
+
+    @ApiOperation(value = "删除有效创角配置")
+    @PreAuthorize(permissionKey = "roleManage:validRoleConfig:delete")
+    @PostMapping(value = "/delete")
+    public ResultVO<Boolean> delete(@RequestParam("id") Long id) {
+        return ResultVO.ok(gameUserConfigService.delete(id));
+    }
+
+}

+ 0 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/RankingController.java

@@ -3,7 +3,6 @@ package com.zanxiang.game.data.serve.controller;
 import com.zanxiang.erp.security.annotation.PreAuthorize;
 import com.zanxiang.game.data.serve.pojo.dto.AdsAccountRechargeRankingListDTO;
 import com.zanxiang.game.data.serve.pojo.dto.AdsAgentRechargeRankingListDTO;
-import com.zanxiang.game.data.serve.pojo.dto.GamePromoteDayDTO;
 import com.zanxiang.game.data.serve.pojo.dto.RechargeRankingDTO;
 import com.zanxiang.game.data.serve.pojo.vo.AdsAccountRechargeRankingVO;
 import com.zanxiang.game.data.serve.pojo.vo.AdsAgentRechargeRankingVO;

+ 10 - 5
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/controller/RoleManageController.java

@@ -1,18 +1,20 @@
 package com.zanxiang.game.data.serve.controller;
 
-import com.zanxiang.game.data.serve.annotation.Log;
-import com.zanxiang.game.data.serve.pojo.dto.*;
-import com.zanxiang.game.module.base.pojo.vo.SendMsgResultVO;
-import com.zanxiang.game.module.base.pojo.vo.SendMsgVO;
 import com.zanxiang.erp.security.annotation.PreAuthorize;
+import com.zanxiang.game.data.serve.pojo.dto.*;
 import com.zanxiang.game.data.serve.service.IRoleManageService;
 import com.zanxiang.game.data.serve.utils.Page;
+import com.zanxiang.game.module.base.pojo.vo.SendMsgResultVO;
+import com.zanxiang.game.module.base.pojo.vo.SendMsgVO;
 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.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
 import java.util.Map;
@@ -70,4 +72,7 @@ public class RoleManageController {
     }
 
 
+
+
+
 }

+ 37 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/GameUserConfigCreateOrUpdateDTO.java

@@ -0,0 +1,37 @@
+package com.zanxiang.game.data.serve.pojo.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * packageName com.zanxiang.game.data.serve.pojo.dto
+ *
+ * @author ZhangXianyu
+ * @date 2024/4/22
+ * @description 用户配置新增修改DTO
+ */
+@Data
+public class GameUserConfigCreateOrUpdateDTO {
+
+    /**
+     * 主键id
+     */
+    @ApiModelProperty(notes = "主键id, 传则是更新, 不传则是添加")
+    private Long id;
+
+    /**
+     * 游戏id
+     */
+    @NotNull(message = "游戏id不可为空, 必传")
+    @ApiModelProperty(notes = "游戏id")
+    private Long gameId;
+
+    /**
+     * 游戏角色等级
+     */
+    @NotNull(message = "游戏角色等级不可为空, 必传")
+    @ApiModelProperty(notes = "游戏角色等级")
+    private Long roleLevel;
+}

+ 23 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/dto/GameUserConfigListDTO.java

@@ -0,0 +1,23 @@
+package com.zanxiang.game.data.serve.pojo.dto;
+
+import com.zanxiang.game.data.serve.pojo.base.BasePage;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-08-09
+ * @description : 有效用户配置查询
+ */
+@Data
+public class GameUserConfigListDTO extends BasePage {
+
+    /**
+     * 游戏id
+     */
+    @ApiModelProperty(notes = "游戏id")
+    private Long gameId;
+
+    @ApiModelProperty(notes = "SDK")
+    private String sourceSystem;
+}

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

@@ -61,7 +61,7 @@ public class RoleRechargeRankingDTO extends BasePage {
      * 是否合服
      */
     @ApiModelProperty(value = "是否合服:true -> 合服 ; false -> 不合服")
-    private Boolean isMergeServer;
+    private Boolean isMergeServer = false;
 
     /**
      * 角色名

+ 30 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/entity/GameUserConfig.java

@@ -0,0 +1,30 @@
+package com.zanxiang.game.data.serve.pojo.entity;
+
+import lombok.Data;
+import org.nutz.dao.entity.annotation.Id;
+import org.nutz.dao.entity.annotation.Prev;
+import org.nutz.dao.entity.annotation.SQL;
+import org.nutz.dao.entity.annotation.Table;
+
+import java.time.LocalDateTime;
+
+/**
+ * packageName com.zanxiang.game.data.serve.pojo.entity
+ *
+ * @author ZhangXianyu
+ * @date 2024/4/22
+ * @description 游戏角色有效创角配置
+ */
+@Data
+@Table("dm_game_order.t_game_user_config")
+public class GameUserConfig {
+    @Prev( @SQL("SELECT IFNULL(MAX(id),0)+1 FROM dm_game_order.t_game_user_config") )
+    @Id(auto = false)
+    private Long id;
+    private String sourceSystem;
+    private Long gameId;
+    private Long roleLevel;
+    private LocalDateTime createTime;
+    private LocalDateTime updateTime;
+
+}

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

@@ -10,6 +10,9 @@ import java.time.LocalDateTime;
 @Data
 public class AdsOrderDetailVO {
 
+    @ApiModelProperty(value = "主键")
+    private Long id;
+
     @ApiModelProperty(notes = "订单创建日期")
     private LocalDate day;
 

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

@@ -2,12 +2,9 @@ package com.zanxiang.game.data.serve.pojo.vo;
 
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
-import org.ini4j.Reg;
-import org.nutz.dao.entity.annotation.Many;
 
 import java.io.Serializable;
 import java.time.LocalDate;
-import java.util.List;
 
 /**
  * @author ZhangXianyu
@@ -39,9 +36,15 @@ public class GSGameServerDayVO implements Serializable {
     @ApiModelProperty(value = "开服时间")
     private LocalDate dt;
 
+    @ApiModelProperty(value = "开服天数")
+    private Integer days;
+
     @ApiModelProperty(value = "gsIds")
     private String gsIds;
 
+    @ApiModelProperty(value = "gs名称")
+    private String gsNames;
+
 
     @ApiModelProperty(value = "新用户人数")
     private Long totalRegNum;

+ 26 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GSServerRetentionVO.java

@@ -49,4 +49,30 @@ public class GSServerRetentionVO {
      * 付费总人数
      */
     private String totalAmountNum;
+    /**
+     * 小r人数
+     */
+    private String smallRNum;
+    /**
+     * 中r人数
+     */
+    private String mediumRNum;
+    /**
+     * 大r人数
+     */
+    private String largeRNum;
+    /**
+     * 超大r人数
+     */
+    private String superRNum;
+    /**
+     * R总
+     */
+    private String rTotal;
+    /**
+     * R总留存率
+     */
+    private String rTotalRetention;
+
+
 }

+ 52 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameDataDayTotalVO.java

@@ -1117,4 +1117,56 @@ public class GameDataDayTotalVO {
     @ApiModelProperty(value = "da1的用户详情")
     private FirstNewUserAgainTrendVO userDetails;
 
+
+    @ApiModelProperty(value = "首日有效创角人数")
+    private Long firstEffectiveRoleNum;
+
+    @ApiModelProperty(value = "新用户累计有效创角人数")
+    private Long newUserTotalEffectiveRoleNum;
+
+    @ApiModelProperty(value =  "有效创角人数")
+    private Long effectiveRoleNum;
+
+    @ApiModelProperty(value = "首日有效创角率")
+    private BigDecimal firstEffectiveRoleRate;
+
+    @ApiModelProperty(value = "新用户累计有效创角率")
+    private BigDecimal newUserTotalEffectiveRoleNumRate;
+
+    @ApiModelProperty(value = "有效创角率")
+    private BigDecimal effectiveRoleNumRate;
+
+    @ApiModelProperty(value = "首日有效创角成本")
+    private Long firstEffectiveRoleNumCost;
+
+    @ApiModelProperty(value = "新用户累计有效创角成本")
+    private Long newUserTotalEffectiveRoleNumCost;
+
+    @ApiModelProperty(value = "有效创角成本")
+    private Long effectiveRoleNumCost;
+
+    @ApiModelProperty(value = "首日有效创角付费人数")
+    private Long firstEffectiveRoleAmountNum;
+
+    @ApiModelProperty(value = "新用户累计有效创角付费人数")
+    private Long newUserTotalEffectiveRoleAmountNum;
+
+    @ApiModelProperty(value = "首日有效创角付费成本")
+    private Long firstEffectiveRoleAmountNumCost;
+
+    @ApiModelProperty(value = "新用户累计有效创角付费成本")
+    private Long newUserTotalEffectiveRoleAmountNumCost;
+
+    @ApiModelProperty(value = "首日有效创角付费比")
+    private BigDecimal firstEffectiveRoleAmountNumRate;
+
+    @ApiModelProperty(value = "新用户累计有效创角付费比")
+    private BigDecimal newUserTotalEffectiveRoleAmountNumRate;
+
+    @ApiModelProperty(value = "首日有效创角ARPU")
+    private BigDecimal firstEffectiveRoleArpu;
+
+    @ApiModelProperty(value = "新用户累计有效创角XARPU")
+    private BigDecimal newUserTotalEffectiveRoleArpu;
+
 }

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

@@ -1142,4 +1142,59 @@ public class GameDataDayVO {
     @ApiModelProperty(value = "da1的用户详情")
     private FirstNewUserAgainTrendVO userDetails;
 
+
+    @ApiModelProperty(value = "首日有效创角人数")
+    private Long firstEffectiveRoleNum;
+
+    @ApiModelProperty(value = "新用户累计有效创角人数")
+    private Long newUserTotalEffectiveRoleNum;
+
+    @ApiModelProperty(value =  "有效创角人数")
+    private Long effectiveRoleNum;
+
+    @ApiModelProperty(value = "首日有效创角率")
+    private BigDecimal firstEffectiveRoleRate;
+
+    @ApiModelProperty(value = "新用户累计有效创角率")
+    private BigDecimal newUserTotalEffectiveRoleNumRate;
+
+    @ApiModelProperty(value = "有效创角率")
+    private BigDecimal effectiveRoleNumRate;
+
+    @ApiModelProperty(value = "首日有效创角成本")
+    private Long firstEffectiveRoleNumCost;
+
+    @ApiModelProperty(value = "新用户累计有效创角成本")
+    private Long newUserTotalEffectiveRoleNumCost;
+
+    @ApiModelProperty(value = "有效创角成本")
+    private Long effectiveRoleNumCost;
+
+    @ApiModelProperty(value = "首日有效创角付费人数")
+    private Long firstEffectiveRoleAmountNum;
+
+    @ApiModelProperty(value = "新用户累计有效创角付费人数")
+    private Long newUserTotalEffectiveRoleAmountNum;
+
+    @ApiModelProperty(value = "首日有效创角付费成本")
+    private Long firstEffectiveRoleAmountNumCost;
+
+    @ApiModelProperty(value = "新用户累计有效创角付费成本")
+    private Long newUserTotalEffectiveRoleAmountNumCost;
+
+    @ApiModelProperty(value = "首日有效创角付费比")
+    private BigDecimal firstEffectiveRoleAmountNumRate;
+
+    @ApiModelProperty(value = "新用户累计有效创角付费比")
+    private BigDecimal newUserTotalEffectiveRoleAmountNumRate;
+
+    @ApiModelProperty(value = "首日有效创角ARPU")
+    private BigDecimal firstEffectiveRoleArpu;
+
+    @ApiModelProperty(value = "新用户累计有效创角ARPU")
+    private BigDecimal newUserTotalEffectiveRoleArpu;
+
+
+
+
 }

+ 51 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameDataTotalTotalVO.java

@@ -278,4 +278,55 @@ public class GameDataTotalTotalVO {
     @ApiModelProperty(value = "新用户累计创角率(总量)")
     private BigDecimal newUserTotalRoleNumRate;
 
+    @ApiModelProperty(value = "首日有效创角人数")
+    private Long firstEffectiveRoleNum;
+
+    @ApiModelProperty(value = "新用户累计有效创角人数")
+    private Long newUserTotalEffectiveRoleNum;
+
+    @ApiModelProperty(value =  "有效创角人数")
+    private Long effectiveRoleNum;
+
+    @ApiModelProperty(value = "首日有效创角率")
+    private BigDecimal firstEffectiveRoleRate;
+
+    @ApiModelProperty(value = "新用户累计有效创角率")
+    private BigDecimal newUserTotalEffectiveRoleNumRate;
+
+    @ApiModelProperty(value = "有效创角率")
+    private BigDecimal effectiveRoleNumRate;
+
+    @ApiModelProperty(value = "首日有效创角成本")
+    private Long firstEffectiveRoleNumCost;
+
+    @ApiModelProperty(value = "新用户累计有效创角成本")
+    private Long newUserTotalEffectiveRoleNumCost;
+
+    @ApiModelProperty(value = "有效创角成本")
+    private Long effectiveRoleNumCost;
+
+    @ApiModelProperty(value = "首日有效创角付费人数")
+    private Long firstEffectiveRoleAmountNum;
+
+    @ApiModelProperty(value = "新用户累计有效创角付费人数")
+    private Long newUserTotalEffectiveRoleAmountNum;
+
+    @ApiModelProperty(value = "首日有效创角付费成本")
+    private Long firstEffectiveRoleAmountNumCost;
+
+    @ApiModelProperty(value = "新用户累计有效创角付费成本")
+    private Long newUserTotalEffectiveRoleAmountNumCost;
+
+    @ApiModelProperty(value = "首日有效创角付费比")
+    private BigDecimal firstEffectiveRoleAmountNumRate;
+
+    @ApiModelProperty(value = "新用户累计有效创角付费比")
+    private BigDecimal newUserTotalEffectiveRoleAmountNumRate;
+
+    @ApiModelProperty(value = "首日有效创角ARPU")
+    private BigDecimal firstEffectiveRoleArpu;
+
+    @ApiModelProperty(value = "新用户累计有效创角ARPU")
+    private BigDecimal newUserTotalEffectiveRoleArpu;
+
 }

+ 51 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameDataTotalVO.java

@@ -296,4 +296,55 @@ public class GameDataTotalVO {
     @ApiModelProperty(value = "新用户累计创角率(总量)")
     private BigDecimal newUserTotalRoleNumRate;
 
+    @ApiModelProperty(value = "首日有效创角人数")
+    private Long firstEffectiveRoleNum;
+
+    @ApiModelProperty(value = "新用户累计有效创角人数")
+    private Long newUserTotalEffectiveRoleNum;
+
+    @ApiModelProperty(value =  "有效创角人数")
+    private Long effectiveRoleNum;
+
+    @ApiModelProperty(value = "首日有效创角率")
+    private BigDecimal firstEffectiveRoleRate;
+
+    @ApiModelProperty(value = "新用户累计有效创角率")
+    private BigDecimal newUserTotalEffectiveRoleNumRate;
+
+    @ApiModelProperty(value = "有效创角率")
+    private BigDecimal effectiveRoleNumRate;
+
+    @ApiModelProperty(value = "首日有效创角成本")
+    private Long firstEffectiveRoleNumCost;
+
+    @ApiModelProperty(value = "新用户累计有效创角成本")
+    private Long newUserTotalEffectiveRoleNumCost;
+
+    @ApiModelProperty(value = "有效创角成本")
+    private Long effectiveRoleNumCost;
+
+    @ApiModelProperty(value = "首日有效创角付费人数")
+    private Long firstEffectiveRoleAmountNum;
+
+    @ApiModelProperty(value = "新用户累计有效创角付费人数")
+    private Long newUserTotalEffectiveRoleAmountNum;
+
+    @ApiModelProperty(value = "首日有效创角付费成本")
+    private Long firstEffectiveRoleAmountNumCost;
+
+    @ApiModelProperty(value = "新用户累计有效创角付费成本")
+    private Long newUserTotalEffectiveRoleAmountNumCost;
+
+    @ApiModelProperty(value = "首日有效创角付费比")
+    private BigDecimal firstEffectiveRoleAmountNumRate;
+
+    @ApiModelProperty(value = "新用户累计有效创角付费比")
+    private BigDecimal newUserTotalEffectiveRoleAmountNumRate;
+
+    @ApiModelProperty(value = "首日有效创角ARPU")
+    private BigDecimal firstEffectiveRoleArpu;
+
+    @ApiModelProperty(value = "新用户累计有效创角ARPU")
+    private BigDecimal newUserTotalEffectiveRoleArpu;
+
 }

+ 54 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/pojo/vo/GameUserConfigListVO.java

@@ -0,0 +1,54 @@
+package com.zanxiang.game.data.serve.pojo.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-08-09
+ * @description : 有效用户配置
+ */
+@Data
+public class GameUserConfigListVO {
+
+    @ApiModelProperty(notes = "来源系统")
+    private String sourceSystem;
+
+    /**
+     * 主键id
+     */
+    @ApiModelProperty(notes = "主键id")
+    private Long id;
+
+    /**
+     * 游戏id
+     */
+    @ApiModelProperty(notes = "游戏id")
+    private Long gameId;
+
+    /**
+     * 游戏名称
+     */
+    @ApiModelProperty(notes = "游戏名称")
+    private String gameName;
+
+    /**
+     * 游戏角色等级
+     */
+    @ApiModelProperty(notes = "游戏角色等级")
+    private Long roleLevel;
+
+    /**
+     * 创建时间
+     */
+    @ApiModelProperty(notes = "创建时间")
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    @ApiModelProperty(notes = "更新时间")
+    private LocalDateTime updateTime;
+}

+ 7 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/IGameServerService.java

@@ -1,6 +1,5 @@
 package com.zanxiang.game.data.serve.service;
 
-import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.zanxiang.game.data.serve.pojo.dto.*;
 import com.zanxiang.game.data.serve.pojo.vo.*;
 import com.zanxiang.game.data.serve.utils.Page;
@@ -51,6 +50,13 @@ public interface IGameServerService {
      */
     Page<GSGameServerDayVO> getGSGameServerDataDay(GSGameServerDayDTO dto);
 
+    /**
+     * 根据GSId得到区服列表
+     * @param gsId
+     * @return
+     */
+    public List<String> getServerIdByGSId(Long gsId);
+
     /**
      * GS区服总数据
      * @param dto

+ 37 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/IGameUserConfigService.java

@@ -0,0 +1,37 @@
+package com.zanxiang.game.data.serve.service;
+
+import com.zanxiang.game.data.serve.pojo.dto.GameUserConfigCreateOrUpdateDTO;
+import com.zanxiang.game.data.serve.pojo.dto.GameUserConfigListDTO;
+import com.zanxiang.game.data.serve.pojo.vo.GameUserConfigListVO;
+import com.zanxiang.game.data.serve.utils.Page;
+
+public interface IGameUserConfigService {
+
+    /**
+     * 有效创角配置列表
+     * @param dto
+     * @return
+     */
+    Page<GameUserConfigListVO> validRoleConfigList(GameUserConfigListDTO dto);
+
+    /**
+     * 新增有效创角配置
+     * @param dto
+     * @return
+     */
+    Boolean create(GameUserConfigCreateOrUpdateDTO dto);
+
+    /**
+     * 删除有效创角配置
+     * @param id
+     * @return
+     */
+    Boolean delete(Long id);
+
+    /**
+     * 修改有效创角配置
+     * @param dto
+     * @return
+     */
+    Boolean update(GameUserConfigCreateOrUpdateDTO dto);
+}

+ 4 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/IRoleManageService.java

@@ -1,6 +1,8 @@
 package com.zanxiang.game.data.serve.service;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.zanxiang.game.data.serve.pojo.dto.*;
+import com.zanxiang.game.data.serve.pojo.vo.GameUserConfigListVO;
 import com.zanxiang.game.module.base.pojo.vo.SendMsgResultVO;
 import com.zanxiang.game.module.base.pojo.vo.SendMsgVO;
 import com.zanxiang.game.data.serve.utils.Page;
@@ -41,4 +43,6 @@ public interface IRoleManageService {
      * @return
      */
     Page<SendMsgResultVO> getSendMsgResultList(MsgTaskResultDTO msgTaskResultDto);
+
+
 }

+ 10 - 6
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/AdsOrderDetailServiceImpl.java

@@ -147,8 +147,10 @@ public class AdsOrderDetailServiceImpl implements IAdsOrderDetailService {
             }
         }
         //添加判断,除去BG的数据 BG的数据在我们这找不到用户以及渠道
-        cri.where().andNotIsNull("agent_name");
-        cri.where().andNotIsNull("username");
+        if(StringUtils.isNotEmpty(dto.getSourceSystem())&&dto.getSourceSystem().contains("BG")){
+            cri.where().andNotIsNull("agent_name");
+            cri.where().andNotIsNull("username");
+        }
 
         //pager
         Pager pager = dto.toPage();
@@ -292,8 +294,10 @@ public class AdsOrderDetailServiceImpl implements IAdsOrderDetailService {
             }
         }
         //添加判断,除去BG的数据 BG的数据在我们这找不到用户以及渠道
-        cri.where().andNotIsNull("agent_name");
-        cri.where().andNotIsNull("username");
+        if(StringUtils.isNotEmpty(dto.getSourceSystem())&&dto.getSourceSystem().contains("BG")){
+            cri.where().andNotIsNull("agent_name");
+            cri.where().andNotIsNull("username");
+        }
 
         Sql sql = Sqls.create(getOrderDetailTotalSql() + cri);
         sql.setCallback(Sqls.callback.entity());
@@ -420,7 +424,7 @@ public class AdsOrderDetailServiceImpl implements IAdsOrderDetailService {
                  		l.back_table_name as back_table_name -- 回传表名
                 	FROM dm_game_order.t_game_order a
                 	LEFT JOIN dm_game_order.t_game_user_role ab
-                	on a.source_system = ab.source_system AND a.role_id = ab.role_id AND a.user_id = ab.user_id
+                	on a.source_system = ab.source_system AND a.role_id = ab.role_id AND a.user_id = ab.user_id and a.game_id = ab.game_id
                 	LEFT JOIN dm_game_order.t_game_user_burst b
                 	on a.source_system = b.source_system AND a.user_id = b.id AND ab.create_time >= b.create_time AND ab.create_time <b.end_time
                 	LEFT JOIN dm_game_order.t_pitcher_agent c on a.source_system = c.source_system AND a.agent_id = c.id
@@ -591,7 +595,7 @@ public class AdsOrderDetailServiceImpl implements IAdsOrderDetailService {
                  		l.back_table_name as back_table_name -- 回传表名
                 	FROM dm_game_order.t_game_order a
                 	LEFT JOIN dm_game_order.t_game_user_role ab
-                	on a.source_system = ab.source_system AND a.role_id = ab.role_id AND a.user_id = ab.user_id
+                	on a.source_system = ab.source_system AND a.role_id = ab.role_id AND a.user_id = ab.user_id and a.game_id = ab.game_id
                 	LEFT JOIN dm_game_order.t_game_user_burst b
                 	on a.source_system = b.source_system AND a.user_id = b.id AND ab.create_time >= b.create_time AND ab.create_time <b.end_time
                 	LEFT JOIN dm_game_order.t_pitcher_agent c on a.source_system = c.source_system AND a.agent_id = c.id

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

@@ -2,8 +2,6 @@ package com.zanxiang.game.data.serve.service.impl;
 
 import lombok.Data;
 
-import java.time.LocalDate;
-
 /**
  * packageName com.zanxiang.game.data.serve.service.impl
  *

+ 615 - 130
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GameDataServiceImpl.java

@@ -8,7 +8,6 @@ import com.zanxiang.game.data.serve.pojo.entity.*;
 import com.zanxiang.game.data.serve.pojo.enums.OrderByEnum;
 import com.zanxiang.game.data.serve.pojo.vo.*;
 import com.zanxiang.game.data.serve.service.IGameDataService;
-import com.zanxiang.game.data.serve.service.IRoleManageService;
 import com.zanxiang.game.data.serve.utils.Page;
 import com.zanxiang.module.util.DateUtil;
 import com.zanxiang.module.util.exception.BaseException;
@@ -750,7 +749,6 @@ public class GameDataServiceImpl implements IGameDataService {
     public Page<GameDataTotalVO> getGameDataTotal(GameDataTotalDTO 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();
-
         if (dto.getGameDimension() == null) {
             //默认查询子游戏维度
             dto.setGameDimension(1L);
@@ -896,7 +894,6 @@ public class GameDataServiceImpl implements IGameDataService {
     public GameDataTotalTotalVO getGameDataTotalTotal(GameDataTotalTotalDTO 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();
-
         if (dto.getGameDimension() == null) {
             //默认查询子游戏维度
             dto.setGameDimension(1L);
@@ -2678,7 +2675,30 @@ public class GameDataServiceImpl implements IGameDataService {
                                 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
+                                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,
+                                
+                                ANY_VALUE(buy_first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                                ANY_VALUE(buy_new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                                ANY_VALUE(buy_effective_role_num) as effective_role_num,  -- 有效创角人数
+                                
+                                round(ANY_VALUE(buy_first_effective_role_num_rate)*100,2) AS first_effective_role_rate, -- 首日有效创角率
+                                round(ANY_VALUE(buy_new_user_total_effective_role_num_rate)*100,2) as new_user_total_effective_role_num_rate, -- 新用户累计有效创角率
+                                round(ANY_VALUE(buy_effective_role_num_rate)*100,2) as effective_role_num_rate, -- 有效创角率
+                                
+                                ANY_VALUE(buy_first_effective_role_num_cost) AS first_effective_role_num_cost, -- 首日有效创角成本
+                                ANY_VALUE(buy_new_user_total_effective_role_num_cost) as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本
+                                ANY_VALUE(buy_effective_role_num_cost) as effective_role_num_cost,    -- 有效创角成本
+                                
+                                ANY_VALUE(buy_first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                                ANY_VALUE(buy_new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                                
+                                ANY_VALUE(buy_first_effective_role_amount_num_cost) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本
+                                ANY_VALUE(buy_new_user_total_effective_role_amount_num_cost) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本
+                                
+                                round(ANY_VALUE(buy_first_effective_role_amount_num_rate)*100,2) as first_effective_role_amount_num_rate, -- 首日有效创角付费比
+                                round(ANY_VALUE(buy_new_user_total_effective_role_amount_num_rate)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比
+                                ANY_VALUE(buy_first_effective_role_arpu) as first_effective_role_arpu, -- 首日有效创角ARPU
+                                ANY_VALUE(buy_new_user_total_effective_role_arpu) as new_user_total_effective_role_arpu -- 新用户累计有效创角ARPU
                             FROM
                                 ads_game_day
                             """;
@@ -2732,7 +2752,30 @@ public class GameDataServiceImpl implements IGameDataService {
                                 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
+                                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,
+                                
+                                ANY_VALUE(nature_first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                                ANY_VALUE(nature_new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                                ANY_VALUE(nature_effective_role_num) as effective_role_num,  -- 有效创角人数
+                                
+                                round(ANY_VALUE(nature_first_effective_role_num_rate)*100,2) AS first_effective_role_rate, -- 首日有效创角率
+                                round(ANY_VALUE(nature_new_user_total_effective_role_num_rate)*100,2) as new_user_total_effective_role_num_rate, -- 新用户累计有效创角率
+                                round(ANY_VALUE(nature_effective_role_num_rate)*100,2) as effective_role_num_rate, -- 有效创角率
+                                
+                                ANY_VALUE(nature_first_effective_role_num_cost) AS first_effective_role_num_cost, -- 首日有效创角成本
+                                ANY_VALUE(nature_new_user_total_effective_role_num_cost) as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本
+                                ANY_VALUE(nature_effective_role_num_cost) as effective_role_num_cost,    -- 有效创角成本
+                                
+                                ANY_VALUE(nature_first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                                ANY_VALUE(nature_new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                                
+                                ANY_VALUE(nature_first_effective_role_amount_num_cost) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本
+                                ANY_VALUE(nature_new_user_total_effective_role_amount_num_cost) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本
+                                
+                                round(ANY_VALUE(nature_first_effective_role_amount_num_rate)*100,2) as first_effective_role_amount_num_rate, -- 首日有效创角付费比
+                                round(ANY_VALUE(nature_new_user_total_effective_role_amount_num_rate)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比
+                                ANY_VALUE(nature_first_effective_role_arpu) as first_effective_role_arpu, -- 首日有效创角ARPU
+                                ANY_VALUE(nature_new_user_total_effective_role_arpu) as new_user_total_effective_role_arpu -- 新用户累计有效创角ARPU
                             FROM
                                 ads_game_day
                             """;
@@ -2787,7 +2830,29 @@ public class GameDataServiceImpl implements IGameDataService {
                             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
+                            round(IF(SUM(reg_num) >0, SUM(new_user_total_role_num) / SUM(reg_num), 0), 4) new_user_total_role_num_rate,
+                            
+                            ANY_VALUE(first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                            ANY_VALUE(new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                            ANY_VALUE(effective_role_num) as effective_role_num,  -- 有效创角人数
+                            
+                            round(ANY_VALUE(first_effective_role_num_rate)*100,2) AS first_effective_role_rate, -- 首日有效创角率
+                            round(ANY_VALUE(new_user_total_effective_role_num_rate)*100,2) as new_user_total_effective_role_num_rate, -- 新用户累计有效创角率
+                            round(ANY_VALUE(effective_role_num_rate)*100,2) as effective_role_num_rate, -- 有效创角率
+                                
+                            
+                            ANY_VALUE(first_effective_role_num_cost) AS first_effective_role_num_cost, -- 首日有效创角成本
+                            ANY_VALUE(new_user_total_effective_role_num_cost) as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本
+                            ANY_VALUE(effective_role_num_cost) as effective_role_num_cost,    -- 有效创角成本
+                            
+                            ANY_VALUE(first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                            ANY_VALUE(new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                            
+                            
+                             round(ANY_VALUE(first_effective_role_amount_num_rate)*100,2) as first_effective_role_amount_num_rate, -- 首日有效创角付费比
+                             round(ANY_VALUE(new_user_total_effective_role_amount_num_rate)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比
+                             ANY_VALUE(first_effective_role_arpu) as first_effective_role_arpu, -- 首日有效创角ARPU
+                             ANY_VALUE(new_user_total_effective_role_arpu) as new_user_total_effective_role_arpu -- 新用户累计有效创角ARPU
                         FROM
                             ads_game_day
                         """;
@@ -2850,7 +2915,30 @@ public class GameDataServiceImpl implements IGameDataService {
                                 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
+                                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,
+                                
+                                ANY_VALUE(buy_first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                                ANY_VALUE(buy_new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                                ANY_VALUE(buy_effective_role_num) as effective_role_num,  -- 有效创角人数
+                                
+                                round(ANY_VALUE(buy_first_effective_role_num_rate)*100,2) AS first_effective_role_rate, -- 首日有效创角率
+                                round(ANY_VALUE(buy_new_user_total_effective_role_num_rate)*100,2) as new_user_total_effective_role_num_rate, -- 新用户累计有效创角率
+                                round(ANY_VALUE(buy_effective_role_num_rate)*100,2) as effective_role_num_rate, -- 有效创角率
+                                
+                                ANY_VALUE(buy_first_effective_role_num_cost) AS first_effective_role_num_cost, -- 首日有效创角成本
+                                ANY_VALUE(buy_new_user_total_effective_role_num_cost) as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本
+                                ANY_VALUE(buy_effective_role_num_cost) as effective_role_num_cost,    -- 有效创角成本
+                                
+                                ANY_VALUE(buy_first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                                ANY_VALUE(buy_new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                                
+                                ANY_VALUE(buy_first_effective_role_amount_num_cost) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本
+                                ANY_VALUE(buy_new_user_total_effective_role_amount_num_cost) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本
+                                
+                                round(ANY_VALUE(buy_first_effective_role_amount_num_rate)*100,2) as first_effective_role_amount_num_rate, -- 首日有效创角付费比
+                                round(ANY_VALUE(buy_new_user_total_effective_role_amount_num_rate)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比
+                                ANY_VALUE(buy_first_effective_role_arpu) as first_effective_role_arpu, -- 首日有效创角ARPU
+                                ANY_VALUE(buy_new_user_total_effective_role_arpu) as new_user_total_effective_role_arpu -- 新用户累计有效创角ARPU
                             FROM
                                 game_ads_parent.ads_game_day_parent
                             """;
@@ -2904,7 +2992,30 @@ public class GameDataServiceImpl implements IGameDataService {
                                 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
+                                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,
+                                
+                                ANY_VALUE(nature_first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                                ANY_VALUE(nature_new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                                ANY_VALUE(nature_effective_role_num) as effective_role_num,  -- 有效创角人数
+                                
+                                round(ANY_VALUE(nature_first_effective_role_num_rate)*100,2) AS first_effective_role_rate, -- 首日有效创角率
+                                round(ANY_VALUE(nature_new_user_total_effective_role_num_rate)*100,2) as new_user_total_effective_role_num_rate, -- 新用户累计有效创角率
+                                round(ANY_VALUE(nature_effective_role_num_rate)*100,2) as effective_role_num_rate, -- 有效创角率
+                                
+                                ANY_VALUE(nature_first_effective_role_num_cost) AS first_effective_role_num_cost, -- 首日有效创角成本
+                                ANY_VALUE(nature_new_user_total_effective_role_num_cost) as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本
+                                ANY_VALUE(nature_effective_role_num_cost) as effective_role_num_cost,    -- 有效创角成本
+                                
+                                ANY_VALUE(nature_first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                                ANY_VALUE(nature_new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                                
+                                ANY_VALUE(nature_first_effective_role_amount_num_cost) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本
+                                ANY_VALUE(nature_new_user_total_effective_role_amount_num_cost) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本
+                                
+                                round(ANY_VALUE(nature_first_effective_role_amount_num_rate)*100,2) as first_effective_role_amount_num_rate, -- 首日有效创角付费比
+                                round(ANY_VALUE(nature_new_user_total_effective_role_amount_num_rate)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比
+                                ANY_VALUE(nature_first_effective_role_arpu) as first_effective_role_arpu, -- 首日有效创角ARPU
+                                ANY_VALUE(nature_new_user_total_effective_role_arpu) as new_user_total_effective_role_arpu -- 新用户累计有效创角ARPU
                             FROM
                                 game_ads_parent.ads_game_day_parent
                             """;
@@ -2959,7 +3070,29 @@ public class GameDataServiceImpl implements IGameDataService {
                             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
+                            round(IF(SUM(reg_num) >0, SUM(new_user_total_role_num) / SUM(reg_num), 0), 4) new_user_total_role_num_rate,
+                            
+                            ANY_VALUE(first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                            ANY_VALUE(new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                            ANY_VALUE(effective_role_num) as effective_role_num,  -- 有效创角人数
+                            
+                            round(ANY_VALUE(first_effective_role_num_rate)*100,2) AS first_effective_role_rate, -- 首日有效创角率
+                            round(ANY_VALUE(new_user_total_effective_role_num_rate)*100,2) as new_user_total_effective_role_num_rate, -- 新用户累计有效创角率
+                            round(ANY_VALUE(effective_role_num_rate)*100,2) as effective_role_num_rate, -- 有效创角率
+                                
+                            
+                            ANY_VALUE(first_effective_role_num_cost) AS first_effective_role_num_cost, -- 首日有效创角成本
+                            ANY_VALUE(new_user_total_effective_role_num_cost) as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本
+                            ANY_VALUE(effective_role_num_cost) as effective_role_num_cost,    -- 有效创角成本
+                            
+                            ANY_VALUE(first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                            ANY_VALUE(new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                            
+                            
+                             round(ANY_VALUE(first_effective_role_amount_num_rate)*100,2) as first_effective_role_amount_num_rate, -- 首日有效创角付费比
+                             round(ANY_VALUE(new_user_total_effective_role_amount_num_rate)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比
+                             ANY_VALUE(first_effective_role_arpu) as first_effective_role_arpu, -- 首日有效创角ARPU
+                             ANY_VALUE(new_user_total_effective_role_arpu) as new_user_total_effective_role_arpu -- 新用户累计有效创角ARPU
                         FROM
                             game_ads_parent.ads_game_day_parent
                         """;
@@ -3395,7 +3528,31 @@ public class GameDataServiceImpl implements IGameDataService {
                                 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
+                                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,
+                                
+                                sum(buy_first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                                sum(buy_new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                                SUM(buy_effective_role_num) as effective_role_num, -- 有效创角人数
+                                
+                                ROUND(IFNULL(SUM(buy_first_effective_role_num)/sum(buy_first_role_num),0)*100,2) as first_effective_role_rate,   -- 首日有效创角率 = 首日有效创角人数/首日创角人数
+                                round(IFNULL(SUM(buy_new_user_total_effective_role_num)/SUM(buy_new_user_total_role_num),0)*100,2) as new_user_total_effective_role_num_rate,         -- 新用户累计有效创角率 = 新用户累计有效创角人数/新用户累计创角人数
+                                round(IFNULL(SUM(buy_effective_role_num)/SUM(buy_role_num),0)*100,2) as effective_role_num_rate,        -- 有效创角率 = 有效创角人数/创角人数
+                                
+                                round(IFNULL(SUM(cost)/SUM(buy_first_effective_role_num),0),2) as first_effective_role_num_cost, -- 首日有效创角成本= 消耗/首日有效创角人数
+                                round(IFNULL(SUM(cost)/SUM(buy_new_user_total_effective_role_num),0),2)  as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本 = 消耗/新用户累计有效创角人数
+                                round(IFNULL(SUM(cost)/sum(buy_effective_role_num),0),2) as effective_role_num_cost, -- 有效创角成本 = 消耗/有效创角人数
+                                
+                                SUM(buy_first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                                sum(buy_new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                                
+                                round(IFNULL(SUM(cost)/sum(buy_first_effective_role_amount_num),0),2) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本=消耗/首日有效创角付费人数
+                                round(IFNULL(SUM(cost)/SUM(buy_new_user_total_effective_role_amount_num),0),2) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本=消耗/新用户累计有效创角付费人数
+                                
+                                round(IFNULL(SUM(buy_first_effective_role_amount_num)/SUM(buy_first_new_user_amount_count),0)*100,2) as first_effective_role_amount_num_rate,  -- 首日有效创角付费比=首日有效创角付费人数/首日新用户充值人数
+                                round(IFNULL(SUM(buy_new_user_total_effective_role_amount_num)/SUM(buy_new_user_total_amount_count),0)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比=新用户累计有效创角付费人数/新用户累计充值人数
+                                ROUND(IFNULL(SUM(buy_new_user_total_amount)/SUM(buy_new_user_total_effective_role_num),0),2) as first_effective_role_arpu,    -- 新用户累计有效创角ARPU=新用户累计充值金额/新用户累计有效创角人数
+                                ROUND(IFNULL(SUM(buy_first_new_user_amount)/SUM(buy_first_effective_role_num),0),2) as new_user_total_effective_role_arpu -- 首日有效创角ARPU=首日新用户充值金额/首日有效创角人数
+                                
                             FROM game_ads.ads_game_day as a
                                 LEFT JOIN game_dw.dw_game_amount_day_buy
                                 b on a.source_system = b.source_system
@@ -3447,7 +3604,30 @@ public class GameDataServiceImpl implements IGameDataService {
                                 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
+                                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,
+                                
+                                sum(nature_first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                                sum(nature_new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                                SUM(nature_effective_role_num) as effective_role_num, -- 有效创角人数
+                                
+                                ROUND(IFNULL(SUM(nature_first_effective_role_num)/sum(nature_first_role_num),0)*100,2) as first_effective_role_rate,   -- 首日有效创角率 = 首日有效创角人数/首日创角人数
+                                round(IFNULL(SUM(nature_new_user_total_effective_role_num)/SUM(nature_new_user_total_role_num),0)*100,2) as new_user_total_effective_role_num_rate,         -- 新用户累计有效创角率 = 新用户累计有效创角人数/新用户累计创角人数
+                                round(IFNULL(SUM(nature_effective_role_num)/SUM(nature_role_num),0)*100,2) as effective_role_num_rate,        -- 有效创角率 = 有效创角人数/创角人数
+                                
+                                round(IFNULL(SUM(cost)/SUM(nature_first_effective_role_num),0),2) as first_effective_role_num_cost, -- 首日有效创角成本= 消耗/首日有效创角人数
+                                round(IFNULL(SUM(cost)/SUM(nature_new_user_total_effective_role_num),0),2)  as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本 = 消耗/新用户累计有效创角人数
+                                round(IFNULL(SUM(cost)/sum(nature_effective_role_num),0),2) as effective_role_num_cost, -- 有效创角成本 = 消耗/有效创角人数
+                                
+                                SUM(nature_first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                                sum(nature_new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                                
+                                round(IFNULL(SUM(cost)/sum(nature_first_effective_role_amount_num),0),2) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本=消耗/首日有效创角付费人数
+                                round(IFNULL(SUM(cost)/SUM(nature_new_user_total_effective_role_amount_num),0),2) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本=消耗/新用户累计有效创角付费人数
+                                
+                                round(IFNULL(SUM(nature_first_effective_role_amount_num)/SUM(nature_first_new_user_amount_count),0)*100,2) as first_effective_role_amount_num_rate,  -- 首日有效创角付费比=首日有效创角付费人数/首日新用户充值人数
+                                round(IFNULL(SUM(nature_new_user_total_effective_role_amount_num)/SUM(nature_new_user_total_amount_count),0)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比=新用户累计有效创角付费人数/新用户累计充值人数
+                                ROUND(IFNULL(SUM(nature_new_user_total_amount)/SUM(nature_new_user_total_effective_role_num),0),2) as first_effective_role_arpu,    -- 新用户累计有效创角ARPU=新用户累计充值金额/新用户累计有效创角人数
+                                ROUND(IFNULL(SUM(nature_first_new_user_amount)/SUM(nature_first_effective_role_num),0),2) as new_user_total_effective_role_arpu -- 首日有效创角ARPU=首日新用户充值金额/首日有效创角人数
                             FROM game_ads.ads_game_day as a
                                 left join  game_dw.dw_game_amount_day_nature d
                                 on a.dt=d.dt and a.game_id = d.nature_game_id
@@ -3461,53 +3641,78 @@ public class GameDataServiceImpl implements IGameDataService {
                 """
                 + amountDayStr("") +
                 """
-                            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 game_ads.ads_game_day as a
-                        left join   game_dw.dw_game_amount_day
-                        b on a.dt=b.dt and a.game_id = b.game_id
-                      """;
+                              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,
+                              
+                              sum(first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                              sum(new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                              SUM(effective_role_num) as effective_role_num, -- 有效创角人数
+                          
+                              ROUND(IFNULL(SUM(first_effective_role_num)/sum(first_role_num),0)*100,2) as first_effective_role_rate,   -- 首日有效创角率 = 首日有效创角人数/首日创角人数
+                              round(IFNULL(SUM(new_user_total_effective_role_num)/SUM(new_user_total_role_num),0)*100,2) as new_user_total_effective_role_num_rate,         -- 新用户累计有效创角率 = 新用户累计有效创角人数/新用户累计创角人数
+                              round(IFNULL(SUM(effective_role_num)/SUM(role_num),0)*100,2) as effective_role_num_rate,        -- 有效创角率 = 有效创角人数/创角人数
+                          
+                              round(IFNULL(SUM(cost)/SUM(first_effective_role_num),0),2) as first_effective_role_num_cost, -- 首日有效创角成本= 消耗/首日有效创角人数
+                              round(IFNULL(SUM(cost)/SUM(new_user_total_effective_role_num),0),2)  as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本 = 消耗/新用户累计有效创角人数
+                              round(IFNULL(SUM(cost)/sum(effective_role_num),0),2) as effective_role_num_cost, -- 有效创角成本 = 消耗/有效创角人数
+                          
+                              SUM(first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                              sum(new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                          
+                          
+                              round(IFNULL(SUM(cost)/sum(first_effective_role_amount_num),0),2) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本=消耗/首日有效创角付费人数
+                              round(IFNULL(SUM(cost)/SUM(new_user_total_effective_role_amount_num),0),2) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本=消耗/新用户累计有效创角付费人数
+                          
+                              round(IFNULL(SUM(first_effective_role_amount_num)/SUM(first_new_user_amount_count),0)*100,2) as first_effective_role_amount_num_rate,  -- 首日有效创角付费比=首日有效创角付费人数/首日新用户充值人数
+                              round(IFNULL(SUM(new_user_total_effective_role_amount_num)/SUM(new_user_total_amount_count),0)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比=新用户累计有效创角付费人数/新用户累计充值人数
+                              ROUND(IFNULL(SUM(new_user_total_amount)/SUM(new_user_total_effective_role_num),0),2) as first_effective_role_arpu,    -- 新用户累计有效创角ARPU=新用户累计充值金额/新用户累计有效创角人数
+                              ROUND(IFNULL(SUM(first_new_user_amount)/SUM(first_effective_role_num),0),2) as new_user_total_effective_role_arpu -- 首日有效创角ARPU=首日新用户充值金额/首日有效创角人数
+                          FROM game_ads.ads_game_day as a
+                          left join   game_dw.dw_game_amount_day
+                          b on a.dt=b.dt and a.game_id = b.game_id
+                        """;
     }
 
     /**
      * 游戏每日数据总计sql - 父游戏维度 (新)
+     *
      * @param tableType 查询类型
      * @return
      */
@@ -3558,7 +3763,31 @@ public class GameDataServiceImpl implements IGameDataService {
                                 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
+                                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,
+                                
+                                sum(buy_first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                                sum(buy_new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                                SUM(buy_effective_role_num) as effective_role_num, -- 有效创角人数
+                                
+                                ROUND(IFNULL(SUM(buy_first_effective_role_num)/sum(buy_first_role_num),0)*100,2) as first_effective_role_rate,   -- 首日有效创角率 = 首日有效创角人数/首日创角人数
+                                round(IFNULL(SUM(buy_new_user_total_effective_role_num)/SUM(buy_new_user_total_role_num),0)*100,2) as new_user_total_effective_role_num_rate,         -- 新用户累计有效创角率 = 新用户累计有效创角人数/新用户累计创角人数
+                                round(IFNULL(SUM(buy_effective_role_num)/SUM(buy_role_num),0)*100,2) as effective_role_num_rate,        -- 有效创角率 = 有效创角人数/创角人数
+                                
+                                round(IFNULL(SUM(cost)/SUM(buy_first_effective_role_num),0),2) as first_effective_role_num_cost, -- 首日有效创角成本= 消耗/首日有效创角人数
+                                round(IFNULL(SUM(cost)/SUM(buy_new_user_total_effective_role_num),0),2)  as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本 = 消耗/新用户累计有效创角人数
+                                round(IFNULL(SUM(cost)/sum(buy_effective_role_num),0),2) as effective_role_num_cost, -- 有效创角成本 = 消耗/有效创角人数
+                                
+                                SUM(buy_first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                                sum(buy_new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                                
+                                
+                                round(IFNULL(SUM(cost)/sum(buy_first_effective_role_amount_num),0),2) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本=消耗/首日有效创角付费人数
+                                round(IFNULL(SUM(cost)/SUM(buy_new_user_total_effective_role_amount_num),0),2) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本=消耗/新用户累计有效创角付费人数
+                                
+                                round(IFNULL(SUM(buy_first_effective_role_amount_num)/SUM(buy_first_new_user_amount_count),0)*100,2) as first_effective_role_amount_num_rate,  -- 首日有效创角付费比=首日有效创角付费人数/首日新用户充值人数
+                                round(IFNULL(SUM(buy_new_user_total_effective_role_amount_num)/SUM(buy_new_user_total_amount_count),0)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比=新用户累计有效创角付费人数/新用户累计充值人数
+                                ROUND(IFNULL(SUM(buy_new_user_total_amount)/SUM(buy_new_user_total_effective_role_num),0),2) as first_effective_role_arpu,    -- 新用户累计有效创角ARPU=新用户累计充值金额/新用户累计有效创角人数
+                                ROUND(IFNULL(SUM(buy_first_new_user_amount)/SUM(buy_first_effective_role_num),0),2) as new_user_total_effective_role_arpu -- 首日有效创角ARPU=首日新用户充值金额/首日有效创角人数
                             FROM game_ads_parent.ads_game_day_parent as a
                             LEFT JOIN  game_dw_parent.dw_game_amount_day_buy_parent b
                             on a.source_system = b.source_system
@@ -3610,7 +3839,30 @@ public class GameDataServiceImpl implements IGameDataService {
                                 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
+                                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,
+                                
+                                sum(nature_first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                                sum(nature_new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                                SUM(nature_effective_role_num) as effective_role_num, -- 有效创角人数
+                                
+                                ROUND(IFNULL(SUM(nature_first_effective_role_num)/sum(nature_first_role_num),0)*100,2) as first_effective_role_rate,   -- 首日有效创角率 = 首日有效创角人数/首日创角人数
+                                round(IFNULL(SUM(nature_new_user_total_effective_role_num)/SUM(nature_new_user_total_role_num),0)*100,2) as new_user_total_effective_role_num_rate,         -- 新用户累计有效创角率 = 新用户累计有效创角人数/新用户累计创角人数
+                                round(IFNULL(SUM(nature_effective_role_num)/SUM(nature_role_num),0)*100,2) as effective_role_num_rate,        -- 有效创角率 = 有效创角人数/创角人数
+                                
+                                round(IFNULL(SUM(cost)/SUM(nature_first_effective_role_num),0),2) as first_effective_role_num_cost, -- 首日有效创角成本= 消耗/首日有效创角人数
+                                round(IFNULL(SUM(cost)/SUM(nature_new_user_total_effective_role_num),0),2)  as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本 = 消耗/新用户累计有效创角人数
+                                round(IFNULL(SUM(cost)/sum(nature_effective_role_num),0),2) as effective_role_num_cost, -- 有效创角成本 = 消耗/有效创角人数
+                                
+                                SUM(nature_first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                                sum(nature_new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                                
+                                round(IFNULL(SUM(cost)/sum(nature_first_effective_role_amount_num),0),2) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本=消耗/首日有效创角付费人数
+                                round(IFNULL(SUM(cost)/SUM(nature_new_user_total_effective_role_amount_num),0),2) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本=消耗/新用户累计有效创角付费人数
+                                
+                                round(IFNULL(SUM(nature_first_effective_role_amount_num)/SUM(nature_first_new_user_amount_count),0)*100,2) as first_effective_role_amount_num_rate,  -- 首日有效创角付费比=首日有效创角付费人数/首日新用户充值人数
+                                round(IFNULL(SUM(nature_new_user_total_effective_role_amount_num)/SUM(nature_new_user_total_amount_count),0)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比=新用户累计有效创角付费人数/新用户累计充值人数
+                                ROUND(IFNULL(SUM(nature_new_user_total_amount)/SUM(nature_new_user_total_effective_role_num),0),2) as first_effective_role_arpu,    -- 新用户累计有效创角ARPU=新用户累计充值金额/新用户累计有效创角人数
+                                ROUND(IFNULL(SUM(nature_first_new_user_amount)/SUM(nature_first_effective_role_num),0),2) as new_user_total_effective_role_arpu -- 首日有效创角ARPU=首日新用户充值金额/首日有效创角人数
                             FROM game_ads_parent.ads_game_day_parent as a
                                 left join   game_dw_parent.dw_game_amount_day_nature_parent d
                                 on a.dt=d.dt and a.parent_game_id = d.nature_parent_game_id
@@ -3624,49 +3876,73 @@ public class GameDataServiceImpl implements IGameDataService {
                 """
                 + amountDayStr("") +
                 """
-                            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 game_ads_parent.ads_game_day_parent as a
-                        left join   game_dw_parent.dw_game_amount_day_parent as b
-                        on a.dt = b.dt and a.parent_game_id = b.parent_game_id 
-                      """;
+                              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,
+                              
+                              sum(first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                              sum(new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                              SUM(effective_role_num) as effective_role_num, -- 有效创角人数
+                              
+                              ROUND(IFNULL(SUM(first_effective_role_num)/sum(first_role_num),0)*100,2) as first_effective_role_rate,   -- 首日有效创角率 = 首日有效创角人数/首日创角人数
+                              round(IFNULL(SUM(new_user_total_effective_role_num)/SUM(new_user_total_role_num),0)*100,2) as new_user_total_effective_role_num_rate,         -- 新用户累计有效创角率 = 新用户累计有效创角人数/新用户累计创角人数
+                              round(IFNULL(SUM(effective_role_num)/SUM(role_num),0)*100,2) as effective_role_num_rate,        -- 有效创角率 = 有效创角人数/创角人数
+                              
+                              round(IFNULL(SUM(cost)/SUM(first_effective_role_num),0),2) as first_effective_role_num_cost, -- 首日有效创角成本= 消耗/首日有效创角人数
+                              round(IFNULL(SUM(cost)/SUM(new_user_total_effective_role_num),0),2)  as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本 = 消耗/新用户累计有效创角人数
+                              round(IFNULL(SUM(cost)/sum(effective_role_num),0),2) as effective_role_num_cost, -- 有效创角成本 = 消耗/有效创角人数
+                              
+                              SUM(first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                              sum(new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                              
+                              
+                              round(IFNULL(SUM(cost)/sum(first_effective_role_amount_num),0),2) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本=消耗/首日有效创角付费人数
+                              round(IFNULL(SUM(cost)/SUM(new_user_total_effective_role_amount_num),0),2) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本=消耗/新用户累计有效创角付费人数
+                              
+                              round(IFNULL(SUM(first_effective_role_amount_num)/SUM(first_new_user_amount_count),0)*100,2) as first_effective_role_amount_num_rate,  -- 首日有效创角付费比=首日有效创角付费人数/首日新用户充值人数
+                              round(IFNULL(SUM(new_user_total_effective_role_amount_num)/SUM(new_user_total_amount_count),0)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比=新用户累计有效创角付费人数/新用户累计充值人数
+                              ROUND(IFNULL(SUM(new_user_total_amount)/SUM(new_user_total_effective_role_num),0),2) as first_effective_role_arpu,    -- 新用户累计有效创角ARPU=新用户累计充值金额/新用户累计有效创角人数
+                              ROUND(IFNULL(SUM(first_new_user_amount)/SUM(first_effective_role_num),0),2) as new_user_total_effective_role_arpu -- 首日有效创角ARPU=首日新用户充值金额/首日有效创角人数
+                          FROM game_ads_parent.ads_game_day_parent as a
+                          left join   game_dw_parent.dw_game_amount_day_parent as b
+                          on a.dt = b.dt and a.parent_game_id = b.parent_game_id 
+                        """;
     }
 
     /**
@@ -3929,21 +4205,21 @@ public class GameDataServiceImpl implements IGameDataService {
 
 
     /**
-     *  Dn的充值金额 / D1-Dn的充值总金额 / Dn的充值人数 /当前消耗(剔除不存在的天数数据) /D1充值金额总和(剔除不存在的天数数据)
+     * Dn的充值金额 / D1-Dn的充值总金额 / Dn的充值人数 /当前消耗(剔除不存在的天数数据) /D1充值金额总和(剔除不存在的天数数据)
      * 游戏每日总计趋势sql
      */
-    private static String amountDayStr(String type){
+    private static String amountDayStr(String type) {
         //拼接查询条件
         StringBuilder trendDay = new StringBuilder(StringUtils.EMPTY);
         trendDay.append("""
-                    CONCAT(
-                      SUM(IF(DATE_ADD(a.dt, INTERVAL 0 day) <= DATE(NOW()), %sda1, 0)),'/',
-                      IFNULL(sum(%sda1),0),'/', 
-                      sum(ifnull(%sda1_num,0)),'/',
-                      SUM(IF(DATE_ADD(a.dt, INTERVAL 0 day) <= DATE(NOW()), cost, 0)),'/',
-                      SUM(IF(DATE_ADD(a.dt, INTERVAL 0 day) <= DATE(NOW()), %sda1, 0))
-                    ) AS amount_d1 ,
-                    """.formatted(type, type, type, type));
+                CONCAT(
+                  SUM(IF(DATE_ADD(a.dt, INTERVAL 0 day) <= DATE(NOW()), %sda1, 0)),'/',
+                  IFNULL(sum(%sda1),0),'/', 
+                  sum(ifnull(%sda1_num,0)),'/',
+                  SUM(IF(DATE_ADD(a.dt, INTERVAL 0 day) <= DATE(NOW()), cost, 0)),'/',
+                  SUM(IF(DATE_ADD(a.dt, INTERVAL 0 day) <= DATE(NOW()), %sda1, 0))
+                ) AS amount_d1 ,
+                """.formatted(type, type, type, type));
 
         for (int day = 2; day < 90; day++) {
             trendDay.append("""
@@ -3954,19 +4230,19 @@ public class GameDataServiceImpl implements IGameDataService {
                       SUM(IF(DATE_ADD(a.dt, INTERVAL %d day) <= DATE(NOW()), cost, 0)),'/',
                       SUM(IF(DATE_ADD(a.dt, INTERVAL %d day) <= DATE(NOW()), %sda1, 0))
                     ) AS amount_d%s ,
-                    """.formatted( day - 1,type,day,type,day - 1,type, day, type, day, day - 1, day - 1, type, day));
+                    """.formatted(day - 1, type, day, type, day - 1, type, day, type, day, day - 1, day - 1, type, day));
         }
 
         //三月
         trendDay.append("""
-                    CONCAT(
-                      SUM(IF(DATE_ADD(a.dt, INTERVAL 2 month) <= DATE(NOW()), %sm3-%sda89, 0)),'/',
-                      IFNULL(sum(%sm3),0),'/',
-                      sum(ifnull(%sda90_num,0)),'/',
-                      SUM(IF(DATE_ADD(a.dt, INTERVAL 2 month) <= DATE(NOW()), cost, 0)),'/',
-                      SUM(IF(DATE_ADD(a.dt, INTERVAL 2 month) <= DATE(NOW()), %sda1, 0))
-                    ) AS amount_d90 ,
-                    """.formatted(type, type, type, type,type));
+                CONCAT(
+                  SUM(IF(DATE_ADD(a.dt, INTERVAL 2 month) <= DATE(NOW()), %sm3-%sda89, 0)),'/',
+                  IFNULL(sum(%sm3),0),'/',
+                  sum(ifnull(%sda90_num,0)),'/',
+                  SUM(IF(DATE_ADD(a.dt, INTERVAL 2 month) <= DATE(NOW()), cost, 0)),'/',
+                  SUM(IF(DATE_ADD(a.dt, INTERVAL 2 month) <= DATE(NOW()), %sda1, 0))
+                ) AS amount_d90 ,
+                """.formatted(type, type, type, type, type));
         for (int month = 4; month <= 12; month++) {
             trendDay.append("""
                     CONCAT(
@@ -3976,7 +4252,7 @@ public class GameDataServiceImpl implements IGameDataService {
                       SUM(IF(DATE_ADD(a.dt, INTERVAL %d month) <= DATE(NOW()), cost, 0)),'/',
                       SUM(IF(DATE_ADD(a.dt, INTERVAL %d month) <= DATE(NOW()), %sda1, 0))
                     ) AS amount_m%s ,
-                    """.formatted(month -1 , type,month,type,month - 1,type, month, type, month, month - 1,month - 1, type,month));
+                    """.formatted(month - 1, type, month, type, month - 1, type, month, type, month, month - 1, month - 1, type, month));
         }
 //        //拼接sum数据
         trendDay.append("""
@@ -4050,7 +4326,30 @@ public class GameDataServiceImpl implements IGameDataService {
                             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_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_new_user_total_role_num) / SUM(buy_reg_num), 0), 4) new_user_total_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,
+                            
+                            sum(buy_first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                            sum(buy_new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                            SUM(buy_effective_role_num) as effective_role_num, -- 有效创角人数
+                            
+                            ROUND(IFNULL(SUM(buy_first_effective_role_num)/sum(buy_first_role_num),0)*100,2) as first_effective_role_rate,   -- 首日有效创角率 = 首日有效创角人数/首日创角人数
+                            round(IFNULL(SUM(buy_new_user_total_effective_role_num)/SUM(buy_new_user_total_role_num),0)*100,2) as new_user_total_effective_role_num_rate,         -- 新用户累计有效创角率 = 新用户累计有效创角人数/新用户累计创角人数
+                            round(IFNULL(SUM(buy_effective_role_num)/SUM(buy_role_num),0)*100,2) as effective_role_num_rate,        -- 有效创角率 = 有效创角人数/创角人数
+                            
+                            round(IFNULL(SUM(cost)/SUM(buy_first_effective_role_num),0),2) as first_effective_role_num_cost, -- 首日有效创角成本= 消耗/首日有效创角人数
+                            round(IFNULL(SUM(cost)/SUM(buy_new_user_total_effective_role_num),0),2)  as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本 = 消耗/新用户累计有效创角人数
+                            round(IFNULL(SUM(cost)/sum(buy_effective_role_num),0),2) as effective_role_num_cost, -- 有效创角成本 = 消耗/有效创角人数
+                            
+                            SUM(buy_first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                            sum(buy_new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                            
+                            round(IFNULL(SUM(cost)/sum(buy_first_effective_role_amount_num),0),2) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本=消耗/首日有效创角付费人数
+                            round(IFNULL(SUM(cost)/SUM(buy_new_user_total_effective_role_amount_num),0),2) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本=消耗/新用户累计有效创角付费人数
+                            
+                            round(IFNULL(SUM(buy_first_effective_role_amount_num)/SUM(buy_first_new_user_amount_count),0)*100,2) as first_effective_role_amount_num_rate,  -- 首日有效创角付费比=首日有效创角付费人数/首日新用户充值人数
+                            round(IFNULL(SUM(buy_new_user_total_effective_role_amount_num)/SUM(buy_new_user_total_amount_count),0)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比=新用户累计有效创角付费人数/新用户累计充值人数
+                            ROUND(IFNULL(SUM(buy_new_user_total_amount)/SUM(buy_new_user_total_effective_role_num),0),2) as first_effective_role_arpu,    -- 新用户累计有效创角ARPU=新用户累计充值金额/新用户累计有效创角人数
+                            ROUND(IFNULL(SUM(buy_first_new_user_amount)/SUM(buy_first_effective_role_num),0),2) as new_user_total_effective_role_arpu -- 首日有效创角ARPU=首日新用户充值金额/首日有效创角人数
                         FROM
                             ads_game_day
                     """ + criA +
@@ -4176,7 +4475,30 @@ public class GameDataServiceImpl implements IGameDataService {
                             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_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_new_user_total_role_num) / SUM(nature_reg_num), 0), 4) new_user_total_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,
+                            
+                            sum(nature_first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                            sum(nature_new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                            SUM(nature_effective_role_num) as effective_role_num, -- 有效创角人数
+                            
+                            ROUND(IFNULL(SUM(nature_first_effective_role_num)/sum(nature_first_role_num),0)*100,2) as first_effective_role_rate,   -- 首日有效创角率 = 首日有效创角人数/首日创角人数
+                            round(IFNULL(SUM(nature_new_user_total_effective_role_num)/SUM(nature_new_user_total_role_num),0)*100,2) as new_user_total_effective_role_num_rate,         -- 新用户累计有效创角率 = 新用户累计有效创角人数/新用户累计创角人数
+                            round(IFNULL(SUM(nature_effective_role_num)/SUM(nature_role_num),0)*100,2) as effective_role_num_rate,        -- 有效创角率 = 有效创角人数/创角人数
+                            
+                            round(IFNULL(SUM(cost)/SUM(nature_first_effective_role_num),0),2) as first_effective_role_num_cost, -- 首日有效创角成本= 消耗/首日有效创角人数
+                            round(IFNULL(SUM(cost)/SUM(nature_new_user_total_effective_role_num),0),2)  as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本 = 消耗/新用户累计有效创角人数
+                            round(IFNULL(SUM(cost)/sum(nature_effective_role_num),0),2) as effective_role_num_cost, -- 有效创角成本 = 消耗/有效创角人数
+                            
+                            SUM(nature_first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                            sum(nature_new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                            
+                            round(IFNULL(SUM(cost)/sum(nature_first_effective_role_amount_num),0),2) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本=消耗/首日有效创角付费人数
+                            round(IFNULL(SUM(cost)/SUM(nature_new_user_total_effective_role_amount_num),0),2) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本=消耗/新用户累计有效创角付费人数
+                            
+                            round(IFNULL(SUM(nature_first_effective_role_amount_num)/SUM(nature_first_new_user_amount_count),0)*100,2) as first_effective_role_amount_num_rate,  -- 首日有效创角付费比=首日有效创角付费人数/首日新用户充值人数
+                            round(IFNULL(SUM(nature_new_user_total_effective_role_amount_num)/SUM(nature_new_user_total_amount_count),0)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比=新用户累计有效创角付费人数/新用户累计充值人数
+                            ROUND(IFNULL(SUM(nature_new_user_total_amount)/SUM(nature_new_user_total_effective_role_num),0),2) as first_effective_role_arpu,    -- 新用户累计有效创角ARPU=新用户累计充值金额/新用户累计有效创角人数
+                            ROUND(IFNULL(SUM(nature_first_new_user_amount)/SUM(nature_first_effective_role_num),0),2) as new_user_total_effective_role_arpu -- 首日有效创角ARPU=首日新用户充值金额/首日有效创角人数
                         FROM
                             ads_game_day
                     """ + criA +
@@ -4303,7 +4625,31 @@ public class GameDataServiceImpl implements IGameDataService {
                 		round(IF(SUM(first_role_num) > 0, SUM(cost) / SUM(first_role_num), 0), 2) first_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(new_user_total_role_num) / SUM(reg_num), 0), 4) new_user_total_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,
+                		
+                		sum(first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                        sum(new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                        SUM(effective_role_num) as effective_role_num, -- 有效创角人数
+                       
+                        ROUND(IFNULL(SUM(first_effective_role_num)/sum(first_role_num),0)*100,2) as first_effective_role_rate,   -- 首日有效创角率 = 首日有效创角人数/首日创角人数
+                        round(IFNULL(SUM(new_user_total_effective_role_num)/SUM(new_user_total_role_num),0)*100,2) as new_user_total_effective_role_num_rate,         -- 新用户累计有效创角率 = 新用户累计有效创角人数/新用户累计创角人数
+                        round(IFNULL(SUM(effective_role_num)/SUM(role_num),0)*100,2) as effective_role_num_rate,        -- 有效创角率 = 有效创角人数/创角人数
+                       
+                        round(IFNULL(SUM(cost)/SUM(first_effective_role_num),0),2) as first_effective_role_num_cost, -- 首日有效创角成本= 消耗/首日有效创角人数
+                        round(IFNULL(SUM(cost)/SUM(new_user_total_effective_role_num),0),2)  as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本 = 消耗/新用户累计有效创角人数
+                        round(IFNULL(SUM(cost)/sum(effective_role_num),0),2) as effective_role_num_cost, -- 有效创角成本 = 消耗/有效创角人数
+                       
+                        SUM(first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                        sum(new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                       
+                       
+                        round(IFNULL(SUM(cost)/sum(first_effective_role_amount_num),0),2) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本=消耗/首日有效创角付费人数
+                        round(IFNULL(SUM(cost)/SUM(new_user_total_effective_role_amount_num),0),2) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本=消耗/新用户累计有效创角付费人数
+                       
+                        round(IFNULL(SUM(first_effective_role_amount_num)/SUM(first_new_user_amount_count),0)*100,2) as first_effective_role_amount_num_rate,  -- 首日有效创角付费比=首日有效创角付费人数/首日新用户充值人数
+                        round(IFNULL(SUM(new_user_total_effective_role_amount_num)/SUM(new_user_total_amount_count),0)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比=新用户累计有效创角付费人数/新用户累计充值人数
+                        ROUND(IFNULL(SUM(new_user_total_amount)/SUM(new_user_total_effective_role_num),0),2) as first_effective_role_arpu,    -- 新用户累计有效创角ARPU=新用户累计充值金额/新用户累计有效创角人数
+                        ROUND(IFNULL(SUM(first_new_user_amount)/SUM(first_effective_role_num),0),2) as new_user_total_effective_role_arpu -- 首日有效创角ARPU=首日新用户充值金额/首日有效创角人数
                 	FROM
                 		ads_game_day
                 """ + criA +
@@ -4440,7 +4786,29 @@ public class GameDataServiceImpl implements IGameDataService {
                             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_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_new_user_total_role_num) / SUM(buy_reg_num), 0), 4) new_user_total_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,
+                              sum(buy_first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                            sum(buy_new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                            SUM(buy_effective_role_num) as effective_role_num, -- 有效创角人数
+                            
+                            ROUND(IFNULL(SUM(buy_first_effective_role_num)/sum(buy_first_role_num),0)*100,2) as first_effective_role_rate,   -- 首日有效创角率 = 首日有效创角人数/首日创角人数
+                            round(IFNULL(SUM(buy_new_user_total_effective_role_num)/SUM(buy_new_user_total_role_num),0)*100,2) as new_user_total_effective_role_num_rate,         -- 新用户累计有效创角率 = 新用户累计有效创角人数/新用户累计创角人数
+                            round(IFNULL(SUM(buy_effective_role_num)/SUM(buy_role_num),0)*100,2) as effective_role_num_rate,        -- 有效创角率 = 有效创角人数/创角人数
+                            
+                            round(IFNULL(SUM(cost)/SUM(buy_first_effective_role_num),0),2) as first_effective_role_num_cost, -- 首日有效创角成本= 消耗/首日有效创角人数
+                            round(IFNULL(SUM(cost)/SUM(buy_new_user_total_effective_role_num),0),2)  as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本 = 消耗/新用户累计有效创角人数
+                            round(IFNULL(SUM(cost)/sum(buy_effective_role_num),0),2) as effective_role_num_cost, -- 有效创角成本 = 消耗/有效创角人数
+                            
+                            SUM(buy_first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                            sum(buy_new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                            
+                            round(IFNULL(SUM(cost)/sum(buy_first_effective_role_amount_num),0),2) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本=消耗/首日有效创角付费人数
+                            round(IFNULL(SUM(cost)/SUM(buy_new_user_total_effective_role_amount_num),0),2) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本=消耗/新用户累计有效创角付费人数
+                            
+                            round(IFNULL(SUM(buy_first_effective_role_amount_num)/SUM(buy_first_new_user_amount_count),0)*100,2) as first_effective_role_amount_num_rate,  -- 首日有效创角付费比=首日有效创角付费人数/首日新用户充值人数
+                            round(IFNULL(SUM(buy_new_user_total_effective_role_amount_num)/SUM(buy_new_user_total_amount_count),0)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比=新用户累计有效创角付费人数/新用户累计充值人数
+                            ROUND(IFNULL(SUM(buy_new_user_total_amount)/SUM(buy_new_user_total_effective_role_num),0),2) as first_effective_role_arpu,    -- 新用户累计有效创角ARPU=新用户累计充值金额/新用户累计有效创角人数
+                            ROUND(IFNULL(SUM(buy_first_new_user_amount)/SUM(buy_first_effective_role_num),0),2) as new_user_total_effective_role_arpu -- 首日有效创角ARPU=首日新用户充值金额/首日有效创角人数
                         FROM
                             game_ads_parent.ads_game_day_parent
                     """ + criA +
@@ -4566,7 +4934,30 @@ public class GameDataServiceImpl implements IGameDataService {
                             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_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_new_user_total_role_num) / SUM(nature_reg_num), 0), 4) new_user_total_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,
+                            
+                            sum(nature_first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                            sum(nature_new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                            SUM(nature_effective_role_num) as effective_role_num, -- 有效创角人数
+                            
+                            ROUND(IFNULL(SUM(nature_first_effective_role_num)/sum(nature_first_role_num),0)*100,2) as first_effective_role_rate,   -- 首日有效创角率 = 首日有效创角人数/首日创角人数
+                            round(IFNULL(SUM(nature_new_user_total_effective_role_num)/SUM(nature_new_user_total_role_num),0)*100,2) as new_user_total_effective_role_num_rate,         -- 新用户累计有效创角率 = 新用户累计有效创角人数/新用户累计创角人数
+                            round(IFNULL(SUM(nature_effective_role_num)/SUM(nature_role_num),0)*100,2) as effective_role_num_rate,        -- 有效创角率 = 有效创角人数/创角人数
+                            
+                            round(IFNULL(SUM(cost)/SUM(nature_first_effective_role_num),0),2) as first_effective_role_num_cost, -- 首日有效创角成本= 消耗/首日有效创角人数
+                            round(IFNULL(SUM(cost)/SUM(nature_new_user_total_effective_role_num),0),2)  as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本 = 消耗/新用户累计有效创角人数
+                            round(IFNULL(SUM(cost)/sum(nature_effective_role_num),0),2) as effective_role_num_cost, -- 有效创角成本 = 消耗/有效创角人数
+                            
+                            SUM(nature_first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                            sum(nature_new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                            
+                            round(IFNULL(SUM(cost)/sum(nature_first_effective_role_amount_num),0),2) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本=消耗/首日有效创角付费人数
+                            round(IFNULL(SUM(cost)/SUM(nature_new_user_total_effective_role_amount_num),0),2) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本=消耗/新用户累计有效创角付费人数
+                            
+                            round(IFNULL(SUM(nature_first_effective_role_amount_num)/SUM(nature_first_new_user_amount_count),0)*100,2) as first_effective_role_amount_num_rate,  -- 首日有效创角付费比=首日有效创角付费人数/首日新用户充值人数
+                            round(IFNULL(SUM(nature_new_user_total_effective_role_amount_num)/SUM(nature_new_user_total_amount_count),0)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比=新用户累计有效创角付费人数/新用户累计充值人数
+                            ROUND(IFNULL(SUM(nature_new_user_total_amount)/SUM(nature_new_user_total_effective_role_num),0),2) as first_effective_role_arpu,    -- 新用户累计有效创角ARPU=新用户累计充值金额/新用户累计有效创角人数
+                            ROUND(IFNULL(SUM(nature_first_new_user_amount)/SUM(nature_first_effective_role_num),0),2) as new_user_total_effective_role_arpu -- 首日有效创角ARPU=首日新用户充值金额/首日有效创角人数
                         FROM
                             game_ads_parent.ads_game_day_parent
                     """ + criA +
@@ -4693,7 +5084,31 @@ public class GameDataServiceImpl implements IGameDataService {
                 		round(IF(SUM(first_role_num) > 0, SUM(cost) / SUM(first_role_num), 0), 2) first_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(new_user_total_role_num) / SUM(reg_num), 0), 4) new_user_total_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,
+                		
+                		sum(first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                        sum(new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                        SUM(effective_role_num) as effective_role_num, -- 有效创角人数
+                       
+                        ROUND(IFNULL(SUM(first_effective_role_num)/sum(first_role_num),0)*100,2) as first_effective_role_rate,   -- 首日有效创角率 = 首日有效创角人数/首日创角人数
+                        round(IFNULL(SUM(new_user_total_effective_role_num)/SUM(new_user_total_role_num),0)*100,2) as new_user_total_effective_role_num_rate,         -- 新用户累计有效创角率 = 新用户累计有效创角人数/新用户累计创角人数
+                        round(IFNULL(SUM(effective_role_num)/SUM(role_num),0)*100,2) as effective_role_num_rate,        -- 有效创角率 = 有效创角人数/创角人数
+                       
+                        round(IFNULL(SUM(cost)/SUM(first_effective_role_num),0),2) as first_effective_role_num_cost, -- 首日有效创角成本= 消耗/首日有效创角人数
+                        round(IFNULL(SUM(cost)/SUM(new_user_total_effective_role_num),0),2)  as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本 = 消耗/新用户累计有效创角人数
+                        round(IFNULL(SUM(cost)/sum(effective_role_num),0),2) as effective_role_num_cost, -- 有效创角成本 = 消耗/有效创角人数
+                       
+                        SUM(first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                        sum(new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                       
+                       
+                        round(IFNULL(SUM(cost)/sum(first_effective_role_amount_num),0),2) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本=消耗/首日有效创角付费人数
+                        round(IFNULL(SUM(cost)/SUM(new_user_total_effective_role_amount_num),0),2) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本=消耗/新用户累计有效创角付费人数
+                       
+                        round(IFNULL(SUM(first_effective_role_amount_num)/SUM(first_new_user_amount_count),0)*100,2) as first_effective_role_amount_num_rate,  -- 首日有效创角付费比=首日有效创角付费人数/首日新用户充值人数
+                        round(IFNULL(SUM(new_user_total_effective_role_amount_num)/SUM(new_user_total_amount_count),0)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比=新用户累计有效创角付费人数/新用户累计充值人数
+                        ROUND(IFNULL(SUM(new_user_total_amount)/SUM(new_user_total_effective_role_num),0),2) as first_effective_role_arpu,    -- 新用户累计有效创角ARPU=新用户累计充值金额/新用户累计有效创角人数
+                        ROUND(IFNULL(SUM(first_new_user_amount)/SUM(first_effective_role_num),0),2) as new_user_total_effective_role_arpu -- 首日有效创角ARPU=首日新用户充值金额/首日有效创角人数
                 	FROM
                 		game_ads_parent.ads_game_day_parent
                 """ + criA +
@@ -4811,7 +5226,31 @@ public class GameDataServiceImpl implements IGameDataService {
                         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_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_new_user_total_role_num) / SUM(buy_reg_num), 0), 4) new_user_total_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,
+                        
+                        sum(buy_first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                        sum(buy_new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                        SUM(buy_effective_role_num) as effective_role_num, -- 有效创角人数
+                        
+                        ROUND(IFNULL(SUM(buy_first_effective_role_num)/sum(buy_first_role_num),0)*100,2) as first_effective_role_rate,   -- 首日有效创角率 = 首日有效创角人数/首日创角人数
+                        round(IFNULL(SUM(buy_new_user_total_effective_role_num)/SUM(buy_new_user_total_role_num),0)*100,2) as new_user_total_effective_role_num_rate,         -- 新用户累计有效创角率 = 新用户累计有效创角人数/新用户累计创角人数
+                        round(IFNULL(SUM(buy_effective_role_num)/SUM(buy_role_num),0)*100,2) as effective_role_num_rate,        -- 有效创角率 = 有效创角人数/创角人数
+                        
+                        round(IFNULL(SUM(cost)/SUM(buy_first_effective_role_num),0),2) as first_effective_role_num_cost, -- 首日有效创角成本= 消耗/首日有效创角人数
+                        round(IFNULL(SUM(cost)/SUM(buy_new_user_total_effective_role_num),0),2)  as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本 = 消耗/新用户累计有效创角人数
+                        round(IFNULL(SUM(cost)/sum(buy_effective_role_num),0),2) as effective_role_num_cost, -- 有效创角成本 = 消耗/有效创角人数
+                        
+                        SUM(buy_first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                        sum(buy_new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                        
+                        
+                        round(IFNULL(SUM(cost)/sum(buy_first_effective_role_amount_num),0),2) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本=消耗/首日有效创角付费人数
+                        round(IFNULL(SUM(cost)/SUM(buy_new_user_total_effective_role_amount_num),0),2) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本=消耗/新用户累计有效创角付费人数
+                        
+                        round(IFNULL(SUM(buy_first_effective_role_amount_num)/SUM(buy_first_new_user_amount_count),0)*100,2) as first_effective_role_amount_num_rate,  -- 首日有效创角付费比=首日有效创角付费人数/首日新用户充值人数
+                        round(IFNULL(SUM(buy_new_user_total_effective_role_amount_num)/SUM(buy_new_user_total_amount_count),0)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比=新用户累计有效创角付费人数/新用户累计充值人数
+                        ROUND(IFNULL(SUM(buy_new_user_total_amount)/SUM(buy_new_user_total_effective_role_num),0),2) as first_effective_role_arpu,    -- 新用户累计有效创角ARPU=新用户累计充值金额/新用户累计有效创角人数
+                        ROUND(IFNULL(SUM(buy_first_new_user_amount)/SUM(buy_first_effective_role_num),0),2) as new_user_total_effective_role_arpu -- 首日有效创角ARPU=首日新用户充值金额/首日有效创角人数
                     FROM 
                     """ + tableName;
         } else if ("nature".equals(tableType)) {
@@ -4845,7 +5284,30 @@ public class GameDataServiceImpl implements IGameDataService {
                         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_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_new_user_total_role_num) / SUM(nature_reg_num), 0), 4) new_user_total_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,
+                        
+                        sum(nature_first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                        sum(nature_new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                        SUM(nature_effective_role_num) as effective_role_num, -- 有效创角人数
+                        
+                        ROUND(IFNULL(SUM(nature_first_effective_role_num)/sum(nature_first_role_num),0)*100,2) as first_effective_role_rate,   -- 首日有效创角率 = 首日有效创角人数/首日创角人数
+                        round(IFNULL(SUM(nature_new_user_total_effective_role_num)/SUM(nature_new_user_total_role_num),0)*100,2) as new_user_total_effective_role_num_rate,         -- 新用户累计有效创角率 = 新用户累计有效创角人数/新用户累计创角人数
+                        round(IFNULL(SUM(nature_effective_role_num)/SUM(nature_role_num),0)*100,2) as effective_role_num_rate,        -- 有效创角率 = 有效创角人数/创角人数
+                        
+                        round(IFNULL(SUM(cost)/SUM(nature_first_effective_role_num),0),2) as first_effective_role_num_cost, -- 首日有效创角成本= 消耗/首日有效创角人数
+                        round(IFNULL(SUM(cost)/SUM(nature_new_user_total_effective_role_num),0),2)  as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本 = 消耗/新用户累计有效创角人数
+                        round(IFNULL(SUM(cost)/sum(nature_effective_role_num),0),2) as effective_role_num_cost, -- 有效创角成本 = 消耗/有效创角人数
+                        
+                        SUM(nature_first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                        sum(nature_new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                        
+                        round(IFNULL(SUM(cost)/sum(nature_first_effective_role_amount_num),0),2) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本=消耗/首日有效创角付费人数
+                        round(IFNULL(SUM(cost)/SUM(nature_new_user_total_effective_role_amount_num),0),2) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本=消耗/新用户累计有效创角付费人数
+                        
+                        round(IFNULL(SUM(nature_first_effective_role_amount_num)/SUM(nature_first_new_user_amount_count),0)*100,2) as first_effective_role_amount_num_rate,  -- 首日有效创角付费比=首日有效创角付费人数/首日新用户充值人数
+                        round(IFNULL(SUM(nature_new_user_total_effective_role_amount_num)/SUM(nature_new_user_total_amount_count),0)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比=新用户累计有效创角付费人数/新用户累计充值人数
+                        ROUND(IFNULL(SUM(nature_new_user_total_amount)/SUM(nature_new_user_total_effective_role_num),0),2) as first_effective_role_arpu,    -- 新用户累计有效创角ARPU=新用户累计充值金额/新用户累计有效创角人数
+                        ROUND(IFNULL(SUM(nature_first_new_user_amount)/SUM(nature_first_effective_role_num),0),2) as new_user_total_effective_role_arpu -- 首日有效创角ARPU=首日新用户充值金额/首日有效创角人数
                     FROM 
                     """ + tableName;
         }
@@ -4880,7 +5342,30 @@ public class GameDataServiceImpl implements IGameDataService {
                     round(IF(SUM(first_role_num) > 0, SUM(cost) / SUM(first_role_num), 0), 2) first_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(new_user_total_role_num) / SUM(reg_num), 0), 4) new_user_total_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,
+                    
+                    sum(first_effective_role_num) as first_effective_role_num,  -- 首日有效创角人数
+                    sum(new_user_total_effective_role_num) as new_user_total_effective_role_num,  -- 新用户累计有效创角人数
+                    SUM(effective_role_num) as effective_role_num, -- 有效创角人数
+                    
+                    ROUND(IFNULL(SUM(first_effective_role_num)/sum(first_role_num),0)*100,2) as first_effective_role_rate,   -- 首日有效创角率 = 首日有效创角人数/首日创角人数
+                    round(IFNULL(SUM(new_user_total_effective_role_num)/SUM(new_user_total_role_num),0)*100,2) as new_user_total_effective_role_num_rate,         -- 新用户累计有效创角率 = 新用户累计有效创角人数/新用户累计创角人数
+                    round(IFNULL(SUM(effective_role_num)/SUM(role_num),0)*100,2) as effective_role_num_rate,        -- 有效创角率 = 有效创角人数/创角人数
+                    
+                    round(IFNULL(SUM(cost)/SUM(first_effective_role_num),0),2) as first_effective_role_num_cost, -- 首日有效创角成本= 消耗/首日有效创角人数
+                    round(IFNULL(SUM(cost)/SUM(new_user_total_effective_role_num),0),2)  as new_user_total_effective_role_num_cost, -- 新用户累计有效创角成本 = 消耗/新用户累计有效创角人数
+                    round(IFNULL(SUM(cost)/sum(effective_role_num),0),2) as effective_role_num_cost, -- 有效创角成本 = 消耗/有效创角人数
+                    
+                    SUM(first_effective_role_amount_num) as first_effective_role_amount_num, -- 首日有效创角付费人数
+                    sum(new_user_total_effective_role_amount_num) as new_user_total_effective_role_amount_num, -- 新用户累计有效创角付费人数
+                    
+                    round(IFNULL(SUM(cost)/sum(first_effective_role_amount_num),0),2) as first_effective_role_amount_num_cost, -- 首日有效创角付费成本=消耗/首日有效创角付费人数
+                    round(IFNULL(SUM(cost)/SUM(new_user_total_effective_role_amount_num),0),2) as new_user_total_effective_role_amount_num_cost, -- 新用户累计有效创角付费成本=消耗/新用户累计有效创角付费人数
+                    
+                    round(IFNULL(SUM(first_effective_role_amount_num)/SUM(first_new_user_amount_count),0)*100,2) as first_effective_role_amount_num_rate,  -- 首日有效创角付费比=首日有效创角付费人数/首日新用户充值人数
+                    round(IFNULL(SUM(new_user_total_effective_role_amount_num)/SUM(new_user_total_amount_count),0)*100,2) as new_user_total_effective_role_amount_num_rate, -- 新用户累计有效创角付费比=新用户累计有效创角付费人数/新用户累计充值人数
+                    ROUND(IFNULL(SUM(new_user_total_amount)/SUM(new_user_total_effective_role_num),0),2) as first_effective_role_arpu,    -- 新用户累计有效创角ARPU=新用户累计充值金额/新用户累计有效创角人数
+                    ROUND(IFNULL(SUM(first_new_user_amount)/SUM(first_effective_role_num),0),2) as new_user_total_effective_role_arpu -- 首日有效创角ARPU=首日新用户充值金额/首日有效创角人数
                 FROM 
                 """ + tableName;
     }
@@ -5694,9 +6179,9 @@ public class GameDataServiceImpl implements IGameDataService {
 
         //查询总记录数
         //默认子游戏
-        Sql countSql = Sqls.create(getCountNumSubgameSql2(cri, agentCri, subGameSql,yesterdayTotalAmountCri));
+        Sql countSql = Sqls.create(getCountNumSubgameSql2(cri, agentCri, subGameSql, yesterdayTotalAmountCri));
         if (dto.getGameDimension() == 2) {
-            countSql = Sqls.create(getCountNumSql(cri, agentCri,yesterdayTotalAmountCri));
+            countSql = Sqls.create(getCountNumSql(cri, agentCri, yesterdayTotalAmountCri));
         }
         countSql.setCallback(Sqls.callback.integer());
         dao.execute(countSql);

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

@@ -114,11 +114,12 @@ public class GameListServiceImpl implements IGameListService {
                 FROM (
                 	SELECT
                 		a.source_system ,
-                		IFNULL(a.super_game_id, a.id) as super_game_id ,
-                		IFNULL(b.name, a.game_name ) as super_game_name
+                		a.super_game_id as super_game_id ,
+                     	b.name as super_game_name
                 	FROM dm_game_order.t_game a
                 	LEFT JOIN dm_game_order.t_game_super b
                 	on a.source_system = b.source_system AND a.super_game_id = b.id
+                	where a.super_game_id is not null
                 ) a
                 """ + cri +
                 """

+ 113 - 31
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GameServerServiceImpl.java

@@ -1,8 +1,9 @@
 package com.zanxiang.game.data.serve.service.impl;
 
-import java.util.List;
-
 import com.google.common.base.CaseFormat;
+import com.zanxiang.erp.base.ErpServer;
+import com.zanxiang.erp.base.rpc.ISysUserRpc;
+import com.zanxiang.erp.security.util.SecurityUtil;
 import com.zanxiang.game.data.serve.component.DataPowerComponent;
 import com.zanxiang.game.data.serve.pojo.dto.*;
 import com.zanxiang.game.data.serve.pojo.entity.AdsGameServerDay;
@@ -13,22 +14,27 @@ import com.zanxiang.game.data.serve.pojo.enums.OrderByEnum;
 import com.zanxiang.game.data.serve.pojo.vo.*;
 import com.zanxiang.game.data.serve.service.IGameServerService;
 import com.zanxiang.game.data.serve.utils.Page;
+import com.zanxiang.game.module.base.ServerInfo;
+import com.zanxiang.game.module.base.pojo.enums.GameAuthEnum;
+import com.zanxiang.game.module.base.pojo.vo.GameAuthUserVO;
+import com.zanxiang.game.module.base.rpc.GameAuthRpc;
+import com.zanxiang.module.util.pojo.ResultVO;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.dubbo.config.annotation.DubboReference;
 import org.nutz.dao.Cnd;
 import org.nutz.dao.Dao;
 import org.nutz.dao.Sqls;
 import org.nutz.dao.pager.Pager;
 import org.nutz.dao.sql.Criteria;
 import org.nutz.dao.sql.Sql;
+import org.nutz.dao.util.cri.Static;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import org.springframework.util.StopWatch;
 import reactor.util.function.Tuple2;
 import reactor.util.function.Tuples;
 
-import javax.annotation.Resource;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.math.BigDecimal;
@@ -45,6 +51,12 @@ import java.util.stream.Collectors;
 @Service
 public class GameServerServiceImpl implements IGameServerService {
 
+    @DubboReference(providedBy = ErpServer.SERVER_DUBBO_NAME)
+    private ISysUserRpc sysUserRpc;
+
+    @DubboReference(providedBy = ServerInfo.SERVER_DUBBO_NAME)
+    private GameAuthRpc gameAuthRpc;
+
     //存储映射的List
     private static final List<Tuple2<Field, Field>> dayNFieldMapList;
     private static final List<Tuple2<Field, Field>> dayNTotalFieldMapList;
@@ -543,7 +555,15 @@ public class GameServerServiceImpl implements IGameServerService {
                 .filter(field -> field.getName().contains("daRetention"))
                 .peek(field -> field.setAccessible(true))
                 .toList();
-
+        //把所有gsIds取出来用,拼起来
+        String gsIds = vos.stream().filter(i -> StringUtils.isNotEmpty(i.getGsIds())).map(GSGameServerDayVO::getGsIds).collect(Collectors.joining(","));
+        ResultVO<Map<Long, String>> userMap = null;
+        if (StringUtils.isNotEmpty(gsIds)) {
+            //转换为Long类型
+            List<Long> userIds = Arrays.stream(gsIds.split(",")).map(Long::parseLong).toList();
+            //发送RPC接口查询所有用户
+            userMap = sysUserRpc.getUserNameByIds(userIds);
+        }
         for (GSGameServerDayVO vo : vos) {
             List<GSGameServerDayRVO> rDataList = collect.get(vo.getSourceSystem() + vo.getServerId() + vo.getParentGameId());
             for (int i = 0; i < fieldList.size(); i++) {
@@ -552,10 +572,12 @@ public class GameServerServiceImpl implements IGameServerService {
                     String value = (String) field.get(vo);
                     String rData;
                     if (rDataList != null && rDataList.size() >= i + 1) {
+                        //累计的充值人数,为了/r数据
+                        String[] split = value.split("/");
                         GSGameServerDayRVO gsGameServerDayRVO = rDataList.get(i);
-                        rData = getRDataStr(gsGameServerDayRVO, vo);
+                        rData = getRDataStr(gsGameServerDayRVO, Long.valueOf(split[split.length - 1]));
                     } else {
-                        rData = "0/0/0/0";
+                        rData = "0/0/0/0/0/0/0/0/0/0";
                     }
                     value += "/" + rData;
 //                    field.set(vo, value + "/" + rData);
@@ -565,20 +587,50 @@ public class GameServerServiceImpl implements IGameServerService {
                             .PaidRetentionRate(split[1])
                             .totalRegNum(split[2])
                             .totalAmountNum(split[3])
-                            .smallR(split[4])
-                            .mediumR(split[5])
-                            .largeR(split[6])
-                            .superR(split[7]).build();
+                            .smallR(split[5])
+                            .mediumR(split[6])
+                            .largeR(split[7])
+                            .superR(split[8])
+                            .smallRNum(split[9])
+                            .mediumRNum(split[10])
+                            .largeRNum(split[11])
+                            .superRNum(split[12])
+                            .rTotal(split[13])
+                            .rTotalRetention(split[14])
+                            .build();
                     fieldObjectList.get(i).set(vo, retentionVO);
                 } catch (IllegalAccessException e) {
                     throw new RuntimeException(e);
                 }
             }
+            if (userMap != null && userMap.getData() != null && StringUtils.isNotEmpty(vo.getGsIds())) {
+                Map<Long, String> data = userMap.getData();
+                List<Long> userIds = Arrays.stream(vo.getGsIds().split(",")).map(Long::parseLong).toList();
+                String gsNames = userIds.stream().map(data::get).collect(Collectors.joining(","));
+                vo.setGsNames(gsNames);
+            }
 
         }
         return new Page<>(vos, pager);
     }
 
+    @Override
+    public List<String> getServerIdByGSId(Long gsId) {
+        if (gsId == null) {
+            return null;
+        }
+        Sql sql = Sqls.create(getServerIdByGSIdSql(gsId));
+        sql.setCallback(Sqls.callback.strList());
+        dao.execute(sql);
+        List<String> list = sql.getList(String.class);
+        return list;
+    }
+
+    private String getServerIdByGSIdSql(Long gsId) {
+        String sql = "select server_id from dm_game_order.t_game_server_merge where find_in_set(" + gsId + ", gs_ids) ";
+        return sql;
+    }
+
 
     /**
      * 区服总数据
@@ -643,9 +695,10 @@ public class GameServerServiceImpl implements IGameServerService {
             Field field = fieldList.get(i);
             try {
                 String value = (String) field.get(vo);
+                //总的累计数据
+                String[] split1 = value.split("/");
                 GSGameServerDayRVO gsGameServerDayRVO = dayRVOMap.get(i);
-                String rData = getRDataStr(gsGameServerDayRVO, vo);
-
+                String rData = getRDataStr(gsGameServerDayRVO, Long.valueOf(split1[split1.length - 1]));
                 value += "/" + rData;
                 String[] split = value.split("/");
                 GSServerRetentionVO retentionVO = GSServerRetentionVO.builder()
@@ -653,10 +706,17 @@ public class GameServerServiceImpl implements IGameServerService {
                         .PaidRetentionRate(split[1])
                         .totalRegNum(split[2])
                         .totalAmountNum(split[3])
-                        .smallR(split[4])
-                        .mediumR(split[5])
-                        .largeR(split[6])
-                        .superR(split[7]).build();
+                        .smallR(split[5])
+                        .mediumR(split[6])
+                        .largeR(split[7])
+                        .superR(split[8])
+                        .smallRNum(split[9])
+                        .mediumRNum(split[10])
+                        .largeRNum(split[11])
+                        .superRNum(split[12])
+                        .rTotal(split[13])
+                        .rTotalRetention(split[14])
+                        .build();
                 fieldObjectList.get(i).set(vo, retentionVO);
 //                field.set(vo, value + "/" + rData);
             } catch (IllegalAccessException e) {
@@ -699,20 +759,27 @@ public class GameServerServiceImpl implements IGameServerService {
      * 拼接R留存率  (R/充值总人数)
      *
      * @param rvo
-     * @param vo
      * @return
      */
-    private String getRDataStr(GSGameServerDayRVO rvo, GSGameServerDayVO vo) {
-        if (rvo != null && vo.getTotalAmountNum() != null && vo.getTotalAmountNum() != 0) {
-            //充值总人数
-            BigDecimal totalAmountNum = new BigDecimal(vo.getTotalAmountNum());
-            BigDecimal smallR = new BigDecimal(rvo.getSmallR()).divide(totalAmountNum, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
-            BigDecimal mediumR = new BigDecimal(rvo.getMediumR()).divide(totalAmountNum, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
-            BigDecimal largeR = new BigDecimal(rvo.getLargeR()).divide(totalAmountNum, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
-            BigDecimal superR = new BigDecimal(rvo.getSuperR()).divide(totalAmountNum, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
-            return smallR + "/" + mediumR + "/" + largeR + "/" + superR;
+    private String getRDataStr(GSGameServerDayRVO rvo, Long totalNum) {
+        if (rvo != null && totalNum != null && totalNum != 0) {
+            //R人数
+            Long smallRCount = rvo.getSmallR();
+            Long mediumRCount = rvo.getMediumR();
+            Long largeRCont = rvo.getLargeR();
+            Long superRCount = rvo.getSuperR();
+            //R总
+            long rCount = smallRCount + mediumRCount + largeRCont + superRCount;
+            //R留存率
+            BigDecimal smallR = new BigDecimal(smallRCount).divide(new BigDecimal(totalNum), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.DOWN);
+            BigDecimal mediumR = new BigDecimal(mediumRCount).divide(new BigDecimal(totalNum), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.DOWN);
+            BigDecimal largeR = new BigDecimal(largeRCont).divide(new BigDecimal(totalNum), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.DOWN);
+            BigDecimal superR = new BigDecimal(superRCount).divide(new BigDecimal(totalNum), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.DOWN);
+            //R总留存
+            BigDecimal r = new BigDecimal(rCount).divide(new BigDecimal(totalNum), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.DOWN);
+            return smallR + "/" + mediumR + "/" + largeR + "/" + superR + "/" + smallRCount + "/" + mediumRCount + "/" + largeRCont + "/" + superRCount+"/"+rCount+"/"+r;
         } else {
-            return "0/0/0/0";
+            return "0/0/0/0/0/0/0/0/0/0";
         }
     }
 
@@ -764,8 +831,18 @@ public class GameServerServiceImpl implements IGameServerService {
 
 
     private Criteria getGameServerDayCriteria(GSGameServerDayDTO dto) {
+        GameAuthUserVO userGameInfo = gameAuthRpc.getGameAuthByUserIds().getData();
+        List<Long> serverIdByGS = null;
+        //判断是不是GS
+        if (GameAuthEnum.getByValue(userGameInfo.getGameAuthEnum().getValue()) != null) {
+            //查询GS管理的区服列表
+            serverIdByGS = getServerIdByGSId(SecurityUtil.getUserId()).stream().filter(StringUtils::isNotEmpty).map(Long::parseLong).collect(Collectors.toList());
+        }
         //创建查询条件
         Criteria cri = Cnd.cri();
+        if (CollectionUtils.isNotEmpty(serverIdByGS)) {
+            cri.where().andInList("a.server_id", serverIdByGS);
+        }
         if (StringUtils.isNotEmpty(dto.getSourceSystem())) {
             cri.where().andEquals("a.source_system", dto.getSourceSystem());
         }
@@ -781,6 +858,9 @@ public class GameServerServiceImpl implements IGameServerService {
         if (StringUtils.isNotEmpty(dto.getServerName())) {
             cri.where().andLike("a.server_name", dto.getServerName());
         }
+        if (dto.getGsId() != null) {
+            cri.where().and(new Static("find_in_set(" + dto.getGsId() + ",a.gs_ids)"));
+        }
         return cri;
     }
 
@@ -792,6 +872,7 @@ public class GameServerServiceImpl implements IGameServerService {
                 a.server_id,
                 a.server_name,
                 a.dt,
+                datediff(Date(now()),a.dt)+ 1 as days, -- 开服日期 要算当天所以+1
                 a.parent_game_id,
                 a.parent_game_classify,
                 a.parent_game_name,
@@ -824,13 +905,14 @@ public class GameServerServiceImpl implements IGameServerService {
 
     /**
      * 获取每天活跃留存率/付费留存率的sql
+     * -
      */
     private String getRemainDaySql() {
         StringBuilder sql = new StringBuilder(StringUtils.EMPTY);
         for (int i = 1; i <= 90; i++) {
             sql.append("""
-                    concat(ifnull(round(c.da%d_active_num / e.new_da%d_total_num ,4),0)*100,'/',round(ifnull((d.new_da%d_num + d.old_da%d_num) / d.new_da%d_total_num,0)*100,4),'/',IFNULL(c.da%d_reg_num,0),'/',IFNULL(c.da%d_num,0)) as da_str%d,
-                     """.formatted(i, i, i, i, i, i, i, i));
+                    concat(a.da%d,'/',IFNULL(c.da%d_role_num,0),'/',IFNULL(c.da%d_num,0),'/',IFNULL(c.da%d_total_num,0)) as da_str%d,
+                     """.formatted(i, i, i, i, i));
 
         }
         return sql.toString();
@@ -843,7 +925,7 @@ public class GameServerServiceImpl implements IGameServerService {
         StringBuilder sql = new StringBuilder(StringUtils.EMPTY);
         for (int i = 1; i <= 90; i++) {
             sql.append("""
-                    concat(ifnull(round((SUM(c.da%d_active_num) / SUM(e.new_da%d_total_num)*100) ,4),0),'/',ifnull(round(((SUM(d.new_da%d_num) + SUM(d.old_da%d_num)) / SUM(d.new_da%d_total_num))*100,4),0),'/',IFNULL(SUM(c.da%d_reg_num),0),'/',IFNULL(SUM(c.da%d_num),0)) as da_str%d,
+                    concat(ifnull(round(SUM(c.da%d_active_num) / SUM(e.new_da%d_total_num) ,4),0),'/',ifnull(round(sum(c.da%d_num)/sum(c.da%d_total_num),4),0),'/',IFNULL(SUM(c.da%d_role_num),0),'/',IFNULL(SUM(c.da%d_num),0),'/',IFNULL(sum(c.da%d_total_num),0)) as da_str%d,
                      """.formatted(i, i, i, i, i, i, i, i));
         }
         return sql.toString();

+ 176 - 0
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/GameUserConfigServiceImpl.java

@@ -0,0 +1,176 @@
+package com.zanxiang.game.data.serve.service.impl;
+
+import com.zanxiang.game.data.serve.pojo.dto.GameDTO;
+import com.zanxiang.game.data.serve.pojo.dto.GameUserConfigCreateOrUpdateDTO;
+import com.zanxiang.game.data.serve.pojo.dto.GameUserConfigListDTO;
+import com.zanxiang.game.data.serve.pojo.entity.GameUserConfig;
+import com.zanxiang.game.data.serve.pojo.vo.GameUserConfigListVO;
+import com.zanxiang.game.data.serve.service.IGameUserConfigService;
+import com.zanxiang.game.data.serve.utils.Page;
+import com.zanxiang.module.util.exception.BaseException;
+import org.apache.commons.lang3.StringUtils;
+import org.nutz.dao.Cnd;
+import org.nutz.dao.Dao;
+import org.nutz.dao.FieldFilter;
+import org.nutz.dao.Sqls;
+import org.nutz.dao.pager.Pager;
+import org.nutz.dao.sql.Criteria;
+import org.nutz.dao.sql.Sql;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * packageName com.zanxiang.game.data.serve.service.impl
+ *
+ * @author ZhangXianyu
+ * @date 2024/4/18
+ * @description 创角配置
+ */
+@Service
+public class GameUserConfigServiceImpl implements IGameUserConfigService {
+
+    @Autowired
+    private Dao dao;
+
+    @Override
+    public Page<GameUserConfigListVO> validRoleConfigList(GameUserConfigListDTO dto) {
+        Criteria criA = Cnd.cri();
+        if (dto.getGameId() != null) {
+            criA.where().andEquals("game_id", dto.getGameId());
+        }
+        if (StringUtils.isNotEmpty(dto.getSourceSystem())) {
+            criA.where().andEquals("source_system", dto.getSourceSystem());
+        }
+        //分页对象
+        Pager pager = dao.createPager(dto.getPageNum(), dto.getPageSize());
+        //查询总记录数
+        Sql countSql = Sqls.create(getGameUserConfigTotalSql() + criA);
+        countSql.setCallback(Sqls.callback.integer());
+        dao.execute(countSql);
+        pager.setRecordCount(countSql.getInt());
+
+        //创建sql
+        Sql sql = Sqls.create(getGameUserConfigSql(criA));
+        sql.setCallback(Sqls.callback.entities());
+        sql.setEntity(dao.getEntity(GameUserConfigListVO.class));
+        sql.setPager(pager);
+        dao.execute(sql);
+        //查询结果
+        List<GameUserConfigListVO> list = sql.getList(GameUserConfigListVO.class);
+        Map<Long, GameDTO> parentGameMap = getGameMap();
+        list.forEach(item -> {
+            GameDTO gameDTO = parentGameMap.get(item.getGameId());
+            if (gameDTO != null) {
+                item.setGameName(gameDTO.getGameName());
+            }
+        });
+        return new Page<>(list, pager);
+    }
+
+    @Override
+    public Boolean create(GameUserConfigCreateOrUpdateDTO dto) {
+        int gameId = dao.count(GameUserConfig.class, Cnd.where("game_id", "=", dto.getGameId()));
+        if (gameId > 0) {
+           throw new BaseException("该游戏已存在创角配置");
+        }
+        GameUserConfig gameUserConfig = new GameUserConfig();
+        gameUserConfig.setSourceSystem("ZX_ONE");
+        gameUserConfig.setGameId(dto.getGameId());
+        gameUserConfig.setRoleLevel(dto.getRoleLevel());
+        gameUserConfig.setCreateTime(LocalDateTime.now());
+        gameUserConfig.setUpdateTime(LocalDateTime.now());
+        dao.insert(gameUserConfig);
+        return true;
+    }
+
+    @Override
+    public Boolean delete(Long id) {
+        dao.delete(GameUserConfig.class, id);
+        return true;
+    }
+
+    @Override
+    public Boolean update(GameUserConfigCreateOrUpdateDTO dto) {
+        if(dto.getId()==null){
+            throw new BaseException("id不能为空");
+        }
+        int count = dao.count(GameUserConfig.class, Cnd.where("game_id", "=", dto.getGameId()).and("id", "!=", dto.getId()));
+        if (count > 0) {
+            throw new BaseException("该游戏已存在创角配置");
+        }
+        GameUserConfig old = dao.fetch(GameUserConfig.class, Cnd.where("id", "=", dto.getId()));
+        if (old == null) {
+            throw new BaseException("创角配置不存在");
+        }
+        old.setUpdateTime(LocalDateTime.now());
+        old.setGameId(dto.getGameId());
+        old.setRoleLevel(dto.getRoleLevel());
+        dao.update(old, FieldFilter.create(GameUserConfig.class, "gameId|roleLevel|updateTime"));
+        return true;
+    }
+
+    public String getGameUserConfigSql(Criteria criA) {
+        String sql = """
+                select 
+                 source_system,
+                 id,
+                 game_id,
+                 role_level,
+                 create_time,
+                 update_time
+                 from 
+                 dm_game_order.t_game_user_config   
+                 """ + criA + """
+                    order by create_time desc
+                """;
+        return sql;
+    }
+
+
+    public String getGameUserConfigTotalSql() {
+        String sql = """
+                select count(*) from dm_game_order.t_game_user_config
+                """;
+        return sql;
+    }
+
+
+    /**
+     * 获取游戏列表
+     */
+    private Map<Long, GameDTO> getGameMap() {
+        Sql sql = Sqls.create(getGameSql());
+        sql.setCallback(Sqls.callback.entities());
+        sql.setEntity(dao.getEntity(GameDTO.class));
+        dao.execute(sql);
+        List<GameDTO> gameDtoList = sql.getList(GameDTO.class);
+        //将游戏拼成map key为游戏id,value为游戏名称
+        return gameDtoList.stream().collect(Collectors.toMap(GameDTO::getId, Function.identity()));
+    }
+
+    /**
+     * 查询游戏sql
+     *
+     * @return String
+     */
+    private String getGameSql() {
+        return """
+                 SELECT
+                            -- 游戏名称、游戏类型、父游戏id、超父游戏id
+                            source_system,
+                            id,
+                            game_name,
+                            classify,
+                            parent_id,
+                            super_game_id
+                        FROM dm_game_order.t_game
+                        where source_system = 'ZX_ONE'
+                """;
+    }
+}

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

@@ -126,6 +126,7 @@ public class IActiveDataServiceImpl implements IActiveDataService {
     public Page<ActiveDataDayVO> getActiveDataDay(ActiveDataDayDTO dto) {
         com.github.sd4324530.jtuple.Tuple2<List<Long>, List<Long>> poerInfo = dataPowerComponent.getPowerInfo();
         List<Long> userGameIds = dto.getGameId() == null ? poerInfo.second : dto.getGameId();
+//        List<Long> userGameIds = dto.getGameId();
 
         //默认查询的字段及表名
         String gameColumn = "game_id";

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

@@ -3,7 +3,6 @@ package com.zanxiang.game.data.serve.service.impl;
 import com.alibaba.fastjson2.JSON;
 import com.zanxiang.game.data.serve.pojo.dto.WebLogDTO;
 import com.zanxiang.game.data.serve.service.IWebVisitLogService;
-import com.zanxiang.module.util.JsonUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.kafka.clients.producer.Producer;
 import org.apache.kafka.clients.producer.ProducerRecord;

+ 4 - 1
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/PitcherDataServiceImpl.java

@@ -4,7 +4,10 @@ import com.google.common.base.CaseFormat;
 import com.google.gson.Gson;
 import com.zanxiang.game.data.serve.component.DataPowerComponent;
 import com.zanxiang.game.data.serve.pojo.dto.*;
-import com.zanxiang.game.data.serve.pojo.entity.*;
+import com.zanxiang.game.data.serve.pojo.entity.AdsPitcherDay;
+import com.zanxiang.game.data.serve.pojo.entity.AdsPitcherDayParent;
+import com.zanxiang.game.data.serve.pojo.entity.AdsPitcherDayn;
+import com.zanxiang.game.data.serve.pojo.entity.AdsPitcherGameDayn;
 import com.zanxiang.game.data.serve.pojo.enums.OrderByEnum;
 import com.zanxiang.game.data.serve.pojo.vo.*;
 import com.zanxiang.game.data.serve.service.IPitcherDataService;

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 505 - 471
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/service/impl/RoleManageServiceImpl.java


+ 61 - 24
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/task/GameMonitorAlarmTask.java

@@ -1,16 +1,24 @@
 package com.zanxiang.game.data.serve.task;
 
+import com.zanxiang.game.data.serve.pojo.properties.SmsProperties;
 import com.zanxiang.game.data.serve.service.IGameMonitorAlarmService;
+import com.zanxiang.module.sms.service.impl.AliSmsService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
-import java.util.concurrent.*;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 
 /**
  * @author tianhua
@@ -26,7 +34,11 @@ public class GameMonitorAlarmTask {
     @Autowired
     private IGameMonitorAlarmService gameMonitorAlarmService;
 
-    private ExecutorService taskScheduler = Executors.newSingleThreadExecutor();
+    @Resource
+    private SmsProperties smsProperties;
+
+    @Resource
+    private AliSmsService aliSmsService;
 
 
     @Value("${sys-config.task_is_run}")
@@ -38,30 +50,55 @@ public class GameMonitorAlarmTask {
     @Scheduled(cron = "0 */5 * * * *")
     public void run() {
         log.info("游戏监控告警定时任务开始.");
-        Future<?> future =  taskScheduler.submit(()->{
-            try {
-                if (!run) {
-                    return;
-                }
-                try {
-                    log.info("进入告警方法");
-                    gameMonitorAlarmService.sendMsgToUser();
-                    log.info("游戏监控告警定时任务结束.");
-                } catch (Exception e) {
-                    log.info("定时任务游戏监控告警出错", e);
-                }
-            }catch (Exception e){
-                log.error("定时任务游戏监控告警出错", e);
-            }
-        });
+        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
+        Runnable task = ()->{
+           try {
+               log.info("游戏监控在线程里开始执行");
+               if (!run) {
+                   log.info("游戏监控告警定时任务本地不执行.");
+                   return;
+               }
+               try {
+                   log.info("进入告警方法");
+                   gameMonitorAlarmService.sendMsgToUser();
+                   log.info("游戏监控告警定时任务结束.");
+               } catch (Exception e) {
+                   log.info("定时任务游戏监控告警出错", e);
+               }
+           }catch (Exception e){
+
+               log.error("定时任务游戏监控告警出错", e);
+           }
+        };
+        scheduler.submit(task);
+        // 使用shutdown()优雅关闭
+        scheduler.shutdown();
         try {
-            //两分钟执行不完就超时
-            future.get(120, TimeUnit.SECONDS);
-        } catch (Exception e) {
-            log.error("定时任务游戏监控告警超时", e);
-            future.cancel(true);
+            // 等待所有任务完成,最多等待120秒
+            if (!scheduler.awaitTermination(120, TimeUnit.SECONDS)) {
+                log.info("线程池关闭超时,可能有任务未完成");
+            }
+        } catch (InterruptedException e) {
+            // 当前线程被中断,通常应重新中断自己
+            log.info("线程池关闭时当前线程被中断");
+            Thread.currentThread().interrupt();
+
         }
+
+        // 或使用shutdownNow()强制关闭
+        List<Runnable> notStartedTasks = scheduler.shutdownNow();
+        log.info("已取消 " + notStartedTasks.size() + " 个任务");
     }
 
+    private void sendMsg(String msg) {
+        log.info("发送告警消息:{}", msg);
+        Date date = new Date();
+        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Map<String, String> params = new HashMap<>();
+        params.put(smsProperties.getMsgParamName(), msg);
+        params.put(smsProperties.getTimeParamName(),formatter.format(date));
+        String number = "15765577867";
+        aliSmsService.send(smsProperties.getDefaultSignName(), smsProperties.getDefaultStstemErrorTemplate(), params, number);
+    }
 
 }

+ 51 - 10
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/task/OrderCostMonitorAlarmTask.java

@@ -4,15 +4,12 @@ import com.zanxiang.game.data.serve.service.IOrderCostMonitorAlarmService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
 import java.time.LocalDateTime;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
+import java.util.List;
+import java.util.concurrent.*;
 
 /**
  * @author ZhangXianyu
@@ -34,13 +31,11 @@ public class OrderCostMonitorAlarmTask {
 
 
 
-    /**
-     * 任务每10分钟运行一次
-     */
-    @Scheduled(cron = "0 0/10 * * * ? ")
+
+    @Deprecated
     public void run() {
+        log.info("订单与消耗监控告警定时任务开始.");
         Future<?> future =  taskScheduler.submit(() -> {
-            log.info("订单与消耗监控告警定时任务开始.");
             //本地不运行
             if (!run) {
                 return;
@@ -72,4 +67,50 @@ public class OrderCostMonitorAlarmTask {
         }
     }
 
+
+    /**
+     * 任务每10分钟运行一次
+     */
+    @Scheduled(cron = "0 0/10 * * * ? ")
+    public void runTask(){
+        log.info("订单与消耗监控告警定时任务开始.");
+        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
+        Runnable task = ()->{
+            try {
+                //0点0分到0点30分不执行
+                LocalDateTime now = LocalDateTime.now();
+                if (now.getHour() == 0 && now.getMinute() <= 30) {
+                    return;
+                }
+                //监控订单表
+                orderCostMonitorAlarmService.monitorDataStatus();
+                //监控头条广告消耗表
+                orderCostMonitorAlarmService.monitorHeadCostStatus();
+                //监控腾讯广告消耗表
+                orderCostMonitorAlarmService.monitorTencentCostStatus();
+                log.info("订单与消耗监控告警定时任务结束.");
+            }catch (Exception e){
+                log.error("定时任务订单与消耗监控告警超时", e);
+            }
+        };
+        scheduler.submit(task);
+        // 使用shutdown()优雅关闭
+        scheduler.shutdown();
+        try {
+            // 等待所有任务完成,最多等待120秒
+            if (!scheduler.awaitTermination(120, TimeUnit.SECONDS)) {
+                log.info("线程池关闭超时,可能有任务未完成");
+            }
+        } catch (InterruptedException e) {
+            // 当前线程被中断,通常应重新中断自己
+            log.info("线程池关闭时当前线程被中断");
+            Thread.currentThread().interrupt();
+
+        }
+
+        // 或使用shutdownNow()强制关闭
+        List<Runnable> notStartedTasks = scheduler.shutdownNow();
+        log.info("已取消 " + notStartedTasks.size() + " 个任务");
+    }
+
 }

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

@@ -23,7 +23,7 @@ public class ManageApplication {
 
     public static void main(String[] args) {
         SpringApplication.run(ManageApplication.class, args);
-        System.out.println("赞象Manage服务启动成功 < (客服消息已读状态在结束房间的时候更新´・・)ノ(._.`) \n" +
+        System.out.println("赞象Manage服务启动成功 < (客服接入玩家线程锁未释放bug修复´・・)ノ(._.`) \n" +
                 "___  ___  ___   _   _   ___  _____  _____ \n" +
                 "|  \\/  | / _ \\ | \\ | | / _ \\|  __ \\|  ___|\n" +
                 "| .  . |/ /_\\ \\|  \\| |/ /_\\ \\ |  \\/| |__  \n" +

+ 8 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/controller/GameServerController.java

@@ -107,6 +107,14 @@ public class GameServerController {
         return ResultVO.ok(gameServerService.getServerList(gameId, Boolean.FALSE));
     }
 
+    @ApiOperation(value = "获取参与合服的区服列表")
+    @GetMapping(value = "/merge/server/list")
+    @PreAuthorize(permissionKey = "manage:gameServer:mergeServerList")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = GameServerVO.class)})
+    public ResultVO<List<GameServerVO>> mergeServerList(@RequestParam Long gameId) {
+        return ResultVO.ok(gameServerService.getServerList(gameId, Boolean.TRUE));
+    }
+
     @ApiOperation(value = "获取所有区服列表(无分页)")
     @GetMapping(value = "/all/server/list")
     @PreAuthorize(permissionKey = "manage:gameServer:allServer")

+ 38 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/controller/api/AppletServerApi.java

@@ -0,0 +1,38 @@
+package com.zanxiang.game.module.manage.controller.api;
+
+import com.zanxiang.game.module.manage.pojo.params.UserAppletSubmitParam;
+import com.zanxiang.game.module.manage.service.IUserAppletService;
+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.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-04-29
+ * @description : 小程序接口
+ */
+@Api(tags = {"小程序接口"})
+@RestController
+@RequestMapping("/api/applet")
+@Slf4j
+public class AppletServerApi {
+
+    @Autowired
+    private IUserAppletService userAppletService;
+
+    @ApiOperation(value = "小程序登录信息提交")
+    @PostMapping(value = "/user/submit")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = Boolean.class)})
+    public ResultVO<Boolean> userAppletSubmit(@Validated @RequestBody UserAppletSubmitParam param) {
+        return ResultVO.ok(userAppletService.userAppletSubmit(param));
+    }
+}

+ 46 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/controller/api/CpServerApi.java

@@ -0,0 +1,46 @@
+package com.zanxiang.game.module.manage.controller.api;
+
+import com.zanxiang.game.module.manage.pojo.params.ChatSubmitParam;
+import com.zanxiang.game.module.manage.pojo.params.OpenGameServerParam;
+import com.zanxiang.game.module.manage.service.api.CpServerApiService;
+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.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-04-25
+ * @description : Cp服务端接口
+ */
+@Api(tags = {"Cp服务端接口"})
+@RestController
+@RequestMapping("/api")
+@Slf4j
+public class CpServerApi {
+
+    @Autowired
+    private CpServerApiService cpServerApiService;
+
+    @ApiOperation(value = "cp提交游戏聊天记录")
+    @PostMapping(value = "/chat/msg/submit")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = Boolean.class)})
+    public ResultVO<Boolean> chatMsgSubmit(@Validated @RequestBody ChatSubmitParam param) {
+        return ResultVO.ok(cpServerApiService.chatMsgSubmit(param));
+    }
+
+    @ApiOperation(value = "CP开服通知")
+    @PostMapping(value = "/open/game/server")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = Boolean.class)})
+    public ResultVO<Boolean> list(@Validated @RequestBody OpenGameServerParam param) {
+        return ResultVO.ok(cpServerApiService.openGameServer(param));
+    }
+}

+ 40 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/enums/KfSessionFromEnum.java

@@ -0,0 +1,40 @@
+package com.zanxiang.game.module.manage.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Objects;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-04-30
+ * @description : 消息来源
+ */
+@Getter
+@AllArgsConstructor
+public enum KfSessionFromEnum {
+
+    /**
+     * 来源广告
+     */
+    KF_SESSION_FROM_AD("KF_SESSION_FROM_AD"),
+
+    /**
+     * 来源平台
+     */
+    KF_SESSION_FROM_PLATFORM("KF_SESSION_FROM_PLATFORM");
+
+    /**
+     * 消息类型
+     */
+    private String value;
+
+    public static KfSessionFromEnum getKfSessionFrom(String sessionFrom) {
+        for (KfSessionFromEnum kfSessionFromEnum : KfSessionFromEnum.values()) {
+            if (Objects.equals(sessionFrom, kfSessionFromEnum.getValue())) {
+                return kfSessionFromEnum;
+            }
+        }
+        return null;
+    }
+}

+ 3 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/handler/GlobalExceptionHandler.java

@@ -30,6 +30,7 @@ public class GlobalExceptionHandler {
      */
     @ExceptionHandler(BaseException.class)
     public ResultVO<?> baseException(BaseException e) {
+        log.error(e.getMessage(), e);
         return ResultVO.fail(e.getMessage());
     }
 
@@ -50,6 +51,7 @@ public class GlobalExceptionHandler {
      */
     @ExceptionHandler(BindException.class)
     public ResultVO<?> validatedBindException(BindException e) {
+        log.error(e.getMessage(), e);
         String message = e.getAllErrors().get(0).getDefaultMessage();
         return ResultVO.fail(message);
     }
@@ -59,6 +61,7 @@ public class GlobalExceptionHandler {
      */
     @ExceptionHandler(MethodArgumentNotValidException.class)
     public ResultVO<?> validExceptionHandler(MethodArgumentNotValidException e) {
+        log.error(e.getMessage(), e);
         String message = e.getBindingResult().getFieldError().getDefaultMessage();
         return ResultVO.fail(message);
     }

+ 5 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/dto/KfAppletMsgDTO.java

@@ -102,4 +102,9 @@ public class KfAppletMsgDTO {
      * 小程序图片媒体id
      */
     private String ThumbMediaId;
+
+    /**
+     * 消息来源
+     */
+    private String SessionFrom;
 }

+ 53 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/params/ChatSubmitParam.java

@@ -0,0 +1,53 @@
+package com.zanxiang.game.module.manage.pojo.params;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.Map;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-04-25
+ * @description : 游戏聊天内容提交
+ */
+@Data
+public class ChatSubmitParam {
+
+    /**
+     * 加密标识
+     */
+    @NotNull(message = "加密标识不可为空")
+    @ApiModelProperty(notes = "加密标识")
+    private String sign;
+
+    /**
+     * 请求时间
+     */
+    @NotNull(message = "请求时间不可为空")
+    @ApiModelProperty(notes = "请求时间, 时间戳 : 13位")
+    private Long signTime;
+
+    /**
+     * 超父游戏id
+     */
+    @NotNull(message = "超父游戏id不可为空")
+    @ApiModelProperty(notes = "超父游戏id")
+    private Long gameId;
+
+    /**
+     * 区服id
+     */
+    @NotBlank(message = "区服id不可为空")
+    @ApiModelProperty(notes = "区服id, 必传")
+    private String serverId;
+
+    /**
+     * 聊天内容
+     */
+    @NotEmpty(message = "聊天内容不可为空")
+    @ApiModelProperty(notes = "聊天内容, 必传")
+    private Map<String, Object> chatContentMap;
+}

+ 65 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/params/OpenGameServerParam.java

@@ -0,0 +1,65 @@
+package com.zanxiang.game.module.manage.pojo.params;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-04-25
+ * @description : 开服参数
+ */
+@Data
+public class OpenGameServerParam {
+
+    /**
+     * 加密标识
+     */
+    @NotNull(message = "加密标识不可为空")
+    @ApiModelProperty(notes = "加密标识")
+    private String sign;
+
+    /**
+     * 请求时间
+     */
+    @NotNull(message = "请求时间不可为空")
+    @ApiModelProperty(notes = "请求时间, 时间戳 : 13位")
+    private Long signTime;
+
+    /**
+     * 超父游戏id
+     */
+    @NotNull(message = "超父游戏id不可为空")
+    @ApiModelProperty(notes = "超父游戏id")
+    private Long gameId;
+
+    /**
+     * 区服id
+     */
+    @NotBlank(message = "区服id不可为空")
+    @ApiModelProperty(notes = "区服id, 必传")
+    private String serverId;
+
+    /**
+     * 区服名称
+     */
+    @NotBlank(message = "区服名称不可为空")
+    @ApiModelProperty(notes = "区服名称, 必传")
+    private String serverName;
+
+    /**
+     * 开服时间
+     */
+    @NotNull(message = "开服时间不可为空")
+    @ApiModelProperty(notes = "开服时间, 必传")
+    private LocalDateTime startTime;
+
+    /**
+     * 区服冠名
+     */
+    @ApiModelProperty(notes = "区服冠名, 非必传")
+    private String nickName;
+}

+ 51 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/pojo/params/UserAppletSubmitParam.java

@@ -0,0 +1,51 @@
+package com.zanxiang.game.module.manage.pojo.params;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-04-29
+ * @description : 小程序用户信息提交
+ */
+@Data
+public class UserAppletSubmitParam {
+
+    /**
+     * 加密标识
+     */
+    @NotBlank(message = "加密标识不可为空")
+    @ApiModelProperty(notes = "加密标识")
+    private String sign;
+
+    /**
+     * 请求时间
+     */
+    @NotNull(message = "请求时间不可为空")
+    @ApiModelProperty(notes = "请求时间, 时间戳 : 13位")
+    private Long signTime;
+
+    /**
+     * 应用id
+     */
+    @NotBlank(message = "应用id不可为空")
+    @ApiModelProperty(notes = "应用id")
+    private String appId;
+
+    /**
+     * 授权登录code
+     */
+    @NotBlank(message = "授权登录code不可为空")
+    @ApiModelProperty(notes = "授权登录code")
+    private String code;
+
+    /**
+     * 渠道参数
+     */
+    @NotBlank(message = "渠道参数不可为空")
+    @ApiModelProperty(notes = "渠道参数")
+    private String channel;
+}

+ 4 - 17
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/rpc/impl/PayBoxRpcImpl.java

@@ -1,36 +1,23 @@
 package com.zanxiang.game.module.manage.rpc.impl;
 
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.zanxiang.game.module.base.rpc.IPayBoxRpc;
-import com.zanxiang.game.module.manage.service.IAppletCheckService;
-import com.zanxiang.game.module.manage.service.IPayApplicationService;
-import com.zanxiang.game.module.mybatis.entity.PayApplication;
 import com.zanxiang.module.util.pojo.ResultVO;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.dubbo.config.annotation.DubboService;
-import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * @author : lingfeng
  * @time : 2024-01-16
  * @description : 支付盒子
  */
+@Slf4j
 @DubboService
 public class PayBoxRpcImpl implements IPayBoxRpc {
 
-    @Autowired
-    private IAppletCheckService appletCheckService;
-
-    @Autowired
-    private IPayApplicationService payApplicationService;
-
     @Override
     public ResultVO<Boolean> payBoxBan(String appId) {
-        PayApplication payApplication = payApplicationService.getOne(new LambdaQueryWrapper<PayApplication>()
-                .eq(PayApplication::getAppId, appId));
-        if (payApplication == null) {
-            return ResultVO.ok(Boolean.FALSE);
-        }
-        appletCheckService.payApplicationCheck(payApplication);
+        log.error("监测到的 appId : {}", appId);
         return ResultVO.ok(Boolean.TRUE);
     }
+
 }

+ 0 - 23
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/IAppletCheckService.java

@@ -1,23 +0,0 @@
-package com.zanxiang.game.module.manage.service;
-
-import com.zanxiang.game.module.mybatis.entity.PayApplication;
-
-/**
- * @author : lingfeng
- * @time : 2024-01-20
- * @description : 小程序检查
- */
-public interface IAppletCheckService {
-
-    /**
-     * 小程序检查
-     */
-    void payApplicationCheck();
-
-    /**
-     * 小程序更新且通知
-     *
-     * @param payApplication : 支付应用
-     */
-    void payApplicationCheck(PayApplication payApplication);
-}

+ 28 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/IGameExtService.java

@@ -0,0 +1,28 @@
+package com.zanxiang.game.module.manage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.module.mybatis.entity.GameExt;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-09-23
+ * @description : 游戏密钥
+ */
+public interface IGameExtService extends IService<GameExt> {
+
+    /**
+     * 通过游戏id
+     *
+     * @param gameId 游戏id
+     * @return {@link GameExt}
+     */
+    GameExt getByGameId(Long gameId);
+
+    /**
+     * 通过游戏应用程序id
+     *
+     * @param appId 应用程序id
+     * @return {@link GameExt}
+     */
+    GameExt getByGameAppId(String appId);
+}

+ 12 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/IKfAppletReplyService.java

@@ -0,0 +1,12 @@
+package com.zanxiang.game.module.manage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.module.mybatis.entity.KfAppletReply;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-04-30
+ * @description : 小程序自动回复
+ */
+public interface IKfAppletReplyService extends IService<KfAppletReply> {
+}

+ 18 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/IListenCallService.java

@@ -10,4 +10,22 @@ import com.zanxiang.game.module.mybatis.entity.ListenCall;
  */
 public interface IListenCallService extends IService<ListenCall> {
 
+    /**
+     * 监测异常发送钉钉通知
+     *
+     * @param gameId  : 游戏id
+     * @param isSuper : 是否超父
+     * @param content : 通知内容
+     */
+    void sendDingTalkMsg(Long gameId, boolean isSuper, String content);
+
+    /**
+     * 监测异常电话通知
+     *
+     * @param gameId     : 游戏id
+     * @param isSuper    : 是否超父
+     * @param listenName : 模块名称
+     */
+    void sendPhoneTalkMsg(Long gameId, boolean isSuper, String listenName);
+
 }

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

@@ -0,0 +1,21 @@
+package com.zanxiang.game.module.manage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.module.manage.pojo.params.UserAppletSubmitParam;
+import com.zanxiang.game.module.mybatis.entity.UserApplet;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-04-29
+ * @description : 投放小程序用户信息
+ */
+public interface IUserAppletService extends IService<UserApplet> {
+
+    /**
+     * 小程序访问信息提交
+     *
+     * @param param : 提交参数
+     * @return : 返回结果
+     */
+    boolean userAppletSubmit(UserAppletSubmitParam param);
+}

+ 135 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/api/CpServerApiService.java

@@ -0,0 +1,135 @@
+package com.zanxiang.game.module.manage.service.api;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.zanxiang.game.module.base.pojo.enums.DeleteEnum;
+import com.zanxiang.game.module.manage.pojo.params.ChatSubmitParam;
+import com.zanxiang.game.module.manage.pojo.params.OpenGameServerParam;
+import com.zanxiang.game.module.manage.service.IGameServerService;
+import com.zanxiang.game.module.manage.service.IGameSupperService;
+import com.zanxiang.game.module.manage.service.IListenCallService;
+import com.zanxiang.game.module.manage.utils.SignUtil;
+import com.zanxiang.game.module.mybatis.entity.GameServer;
+import com.zanxiang.game.module.mybatis.entity.GameSupper;
+import com.zanxiang.module.util.JsonUtil;
+import com.zanxiang.module.util.exception.BaseException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.client.RestTemplate;
+
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-04-25
+ * @description : cp服务端交互
+ */
+@Slf4j
+@Service
+public class CpServerApiService {
+
+    @Autowired
+    private IGameServerService gameServerService;
+
+    @Autowired
+    private IGameSupperService gameSupperService;
+
+    @Autowired
+    private IListenCallService listenCallService;
+
+    @Autowired
+    private RestTemplate restTemplate;
+
+    public boolean chatMsgSubmit(ChatSubmitParam param) {
+        GameSupper gameSupper = gameSupperService.getById(param.getGameId());
+        if (gameSupper == null) {
+            throw new BaseException("参数错误");
+        }
+        this.signCheck(gameSupper.getCpServerKey(), param.getGameId(), param.getServerId(),
+                param.getSignTime(), param.getSign());
+        //查询区服信息
+        GameServer gameServer = gameServerService.getOne(new LambdaQueryWrapper<GameServer>()
+                .eq(GameServer::getGameId, param.getGameId())
+                .eq(GameServer::getServerId, param.getServerId())
+                .last("limit 1"));
+        //组装聊天参数
+        Map<String, Object> chatContentMap = param.getChatContentMap();
+        chatContentMap.put("game_name", gameSupper.getName());
+        if (gameServer != null) {
+            chatContentMap.put("server_name", gameServer.getServerName());
+        }
+        Map<String, Object> paramMap = new HashMap<>(1);
+        paramMap.put("data", chatContentMap);
+        //调武哥接口通知消息
+        try {
+            restTemplate.postForObject("http://47.99.157.216:9000/game/roleChat", paramMap, Object.class);
+        } catch (Exception e) {
+            log.error("调武哥接口通知消息异常, chatContentMap : {}, e : {}", JsonUtil.toString(paramMap), e.getMessage());
+        }
+        return Boolean.TRUE;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public boolean openGameServer(OpenGameServerParam param) {
+        GameSupper gameSupper = gameSupperService.getById(param.getGameId());
+        if (gameSupper == null) {
+            throw new BaseException("参数错误");
+        }
+        this.signCheck(gameSupper.getCpServerKey(), param.getGameId(), param.getServerId(),
+                param.getSignTime(), param.getSign());
+        //查询区服id
+        GameServer gameServer = gameServerService.getOne(new LambdaQueryWrapper<GameServer>()
+                .eq(GameServer::getGameId, param.getGameId())
+                .eq(GameServer::getServerId, param.getServerId())
+        );
+        GameServer transform = this.transform(param);
+        if (gameServer == null) {
+            gameServer = transform;
+        } else {
+            gameServer.setGameId(transform.getGameId());
+            gameServer.setServerId(transform.getServerId());
+            gameServer.setServerName(transform.getServerName());
+            gameServer.setNickName(transform.getNickName());
+            gameServer.setStartTime(transform.getStartTime());
+            gameServer.setUpdateTime(LocalDateTime.now());
+        }
+        //区服添加或者更新
+        gameServerService.saveOrUpdate(gameServer);
+        //钉钉通知
+        String content = LocalDateTime.now().toString() + "游戏开服通知\n游戏名称 : " + gameSupper.getName()
+                + "\n区服名称:" + param.getServerName() + "\n开服时间:" + param.getStartTime().toString();
+        listenCallService.sendDingTalkMsg(param.getGameId(), Boolean.TRUE, content);
+        return Boolean.TRUE;
+    }
+
+    private GameServer transform(OpenGameServerParam param) {
+        return GameServer.builder()
+                .gameId(param.getGameId())
+                .serverId(param.getServerId())
+                .serverName(param.getServerName())
+                .nickName(param.getNickName())
+                .startTime(param.getStartTime())
+                .isDelete(DeleteEnum.NO.getCode())
+                .createBy(0L)
+                .createTime(LocalDateTime.now())
+                .isSourceServer(Boolean.TRUE)
+                .isMerge(Boolean.FALSE)
+                .updateBy(0L)
+                .updateTime(LocalDateTime.now())
+                .build();
+    }
+
+    private void signCheck(String cpServerKey, Long gameId, String serverId, Long signTime, String sign) {
+        String signStr = "cpServerKey=" + cpServerKey + "gameId=" + gameId
+                + "serverId=" + serverId + "signTime=" + signTime;
+        String mySign = SignUtil.md5(signStr);
+        if (!Objects.equals(mySign.toUpperCase(), sign.toUpperCase())) {
+            log.error("加密验证失败, sign : {}, mySign : {}", sign, mySign);
+            throw new BaseException("加密标识错误");
+        }
+    }
+}

+ 0 - 289
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/AppletCheckServiceImpl.java

@@ -1,289 +0,0 @@
-package com.zanxiang.game.module.manage.service.impl;
-
-import cn.hutool.http.ContentType;
-import cn.hutool.http.HttpUtil;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
-import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
-import com.zanxiang.erp.base.ErpServer;
-import com.zanxiang.erp.base.rpc.IDingTalkMsgRpc;
-import com.zanxiang.game.module.base.ServerInfo;
-import com.zanxiang.game.module.base.pojo.enums.PayApplicationTypeEnum;
-import com.zanxiang.game.module.base.pojo.enums.StatusEnum;
-import com.zanxiang.game.module.base.rpc.IWxApiServiceRpc;
-import com.zanxiang.game.module.manage.constant.RedisKeyConstant;
-import com.zanxiang.game.module.manage.enums.ExpireTimeEnum;
-import com.zanxiang.game.module.manage.service.*;
-import com.zanxiang.game.module.manage.utils.RedisUtil;
-import com.zanxiang.game.module.mybatis.entity.GamePayWay;
-import com.zanxiang.game.module.mybatis.entity.ListenCall;
-import com.zanxiang.game.module.mybatis.entity.PayApplication;
-import com.zanxiang.game.module.mybatis.entity.PayBox;
-import com.zanxiang.module.redis.service.IDistributedLockComponent;
-import com.zanxiang.module.util.JsonUtil;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.dubbo.config.annotation.DubboReference;
-import org.apache.logging.log4j.util.Strings;
-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.util.LinkedMultiValueMap;
-import org.springframework.util.MultiValueMap;
-import org.springframework.web.client.RestTemplate;
-
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.util.*;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-/**
- * @author : lingfeng
- * @time : 2024-01-20
- * @description : 小程序检查
- */
-@Slf4j
-@Service
-public class AppletCheckServiceImpl implements IAppletCheckService {
-
-    @DubboReference(providedBy = ErpServer.SERVER_DUBBO_NAME)
-    private IDingTalkMsgRpc dingTalkMsgRpc;
-
-    @DubboReference(providedBy = ServerInfo.SERVER_SDK_DUBBO_NAME)
-    private IWxApiServiceRpc wxApiServiceRpc;
-
-    @Autowired
-    private RedisUtil<Integer> redisUtil;
-
-    @Autowired
-    private IPayBoxService payBoxService;
-
-    @Autowired
-    private IGamePayWayService gamePayWayService;
-
-    @Autowired
-    private IListenCallService listenCallService;
-
-    @Autowired
-    private IPayApplicationService payApplicationService;
-
-    @Autowired
-    private IDistributedLockComponent distributedLockComponent;
-
-    @Override
-    public void payApplicationCheck() {
-        List<PayApplication> payApplicationList = payApplicationService.list(new LambdaQueryWrapper<PayApplication>()
-                .eq(PayApplication::getStatus, StatusEnum.YES.getCode())
-                .eq(PayApplication::getType, PayApplicationTypeEnum.WX_MINI_APP.getType()));
-        if (CollectionUtils.isEmpty(payApplicationList)) {
-            return;
-        }
-        payApplicationList.forEach(payApplication -> {
-            String accessToken = null;
-            try {
-                accessToken = wxApiServiceRpc.getAccessToken(payApplication.getAppId(), payApplication.getAppSecret());
-            } catch (Exception e) {
-                log.error("获取小程序token异常, appName : {}, e : {}", payApplication.getAppName(), e.getMessage());
-            }
-            if (Strings.isBlank(accessToken) || !this.appletCheck(accessToken, payApplication.getAppName())) {
-                log.error("小程序判定封停或者禁用, appName : {}, accessToken : {}", payApplication.getAppName(), accessToken);
-                this.payApplicationCheck(payApplication);
-            }
-        });
-    }
-
-    @Override
-    public void payApplicationCheck(PayApplication payApplication) {
-        //异常计数器, 返回false的时候过滤
-        if (!this.countUpdate(payApplication.getAppId())) {
-            return;
-        }
-        //连续三次报警, 进行通知
-        try {
-            //更新游戏支付
-            this.gamePayUpdate(payApplication);
-        } catch (Exception e) {
-            log.error("支付应用异常更新游戏支付盒子失败, appName : {}, e : {}", payApplication.getAppName(), e.getMessage());
-        }
-        try {
-            //钉钉通知
-            this.sendDingTalkMsg(payApplication);
-        } catch (Exception e) {
-            log.error("支付应用异常钉钉通知失败, appName : {}, e : {}", payApplication.getAppName(), e.getMessage());
-        }
-        try {
-            //电话通知
-            this.sendPhoneTalkMsg(payApplication);
-        } catch (Exception e) {
-            log.error("支付应用异常电话通知失败, appName : {}, e : {}", payApplication.getAppName(), e.getMessage());
-        }
-    }
-
-    private boolean countUpdate(String appId) {
-        String key = RedisKeyConstant.APPLET_ERROR_COUNT + appId;
-        Integer count = redisUtil.getCache(key);
-        if (count != null && count >= 2) {
-            redisUtil.deleteCache(key);
-            return Boolean.TRUE;
-        }
-        if (count == null) {
-            count = 1;
-        } else {
-            count += 1;
-        }
-        redisUtil.setCache(key, count, ExpireTimeEnum.HALF_HOUR.getTime());
-        return Boolean.FALSE;
-    }
-
-    private void gamePayUpdate(PayApplication payApplication) {
-        //修改支付应用状态
-        log.error("支付应用异常 - 修改支付应用状态, appName : {}", payApplication.getAppName());
-        payApplicationService.update(new LambdaUpdateWrapper<PayApplication>()
-                .eq(PayApplication::getAppId, payApplication.getAppId())
-                .set(PayApplication::getStatus, StatusEnum.NO.getCode())
-                .set(PayApplication::getUpdateTime, LocalDateTime.now()));
-        //查询支付应用对应的盒子
-        List<PayBox> payBoxList = payBoxService.list(new LambdaQueryWrapper<PayBox>()
-                .eq(PayBox::getAppId, payApplication.getAppId())
-                .eq(PayBox::getStatus, StatusEnum.YES.getCode()));
-        if (CollectionUtils.isEmpty(payBoxList)) {
-            log.error("支付应用异常 - 支付应用不存在相关支付盒子, appName : {}", payApplication.getAppName());
-            return;
-        }
-        Set<Integer> payBoxIdList = payBoxList.stream().map(PayBox::getId).collect(Collectors.toSet());
-        //修改支付应用相关支付盒子状态
-        log.error("支付应用异常 - 修改支付盒子状态, appName : {}, payBoxIdList : {}", payApplication.getAppName(), payBoxIdList);
-        payBoxService.update(new LambdaUpdateWrapper<PayBox>()
-                .in(PayBox::getId, payBoxIdList)
-                .set(PayBox::getStatus, StatusEnum.NO.getCode())
-                .set(PayBox::getUpdateTime, LocalDateTime.now()));
-        //游戏支付应用修改
-//        this.gamePayWayUpdate(payApplication, payBoxIdList);
-    }
-
-    private void gamePayWayUpdate(PayApplication payApplication, Set<Integer> payBoxIdList) {
-        //查询相关盒子被使用到的游戏
-        List<GamePayWay> gamePayWayList = gamePayWayService.list(new LambdaQueryWrapper<GamePayWay>()
-                .in(GamePayWay::getPayBoxId, payBoxIdList));
-        if (CollectionUtils.isEmpty(gamePayWayList)) {
-            log.error("支付应用异常 - 支付应用不存在相关联游戏支付配置, appName : {}", payApplication.getAppName());
-            return;
-        }
-        //获取一个能用的支付盒子
-        PayBox payBox = payBoxService.getOne(new LambdaQueryWrapper<PayBox>()
-                .eq(PayBox::getType, payApplication.getType())
-                .eq(PayBox::getStatus, StatusEnum.YES.getCode())
-                .last("limit 1"));
-        if (payBox == null) {
-            log.error("支付应用异常 - 不存在正常可用的支付盒子, appName : {}", payApplication.getAppName());
-            return;
-        }
-        //相关游戏支付配置id列表
-        Set<Long> gamePayWayIdSet = gamePayWayList.stream().map(GamePayWay::getId).collect(Collectors.toSet());
-        //修改游戏支付配置
-        log.error("支付应用异常 - 修改游戏支付配置, appName : {}, gamePayWayIdSet : {}, payBoxId : {}", payApplication.getAppName(),
-                gamePayWayIdSet, payBox.getId());
-        gamePayWayService.update(new LambdaUpdateWrapper<GamePayWay>()
-                .in(GamePayWay::getId, gamePayWayIdSet)
-                .set(GamePayWay::getPayBoxId, payBox.getId())
-                .set(GamePayWay::getUpdateTime, LocalDateTime.now()));
-    }
-
-    private void sendDingTalkMsg(PayApplication payApplication) {
-        List<ListenCall> listenCallList = this.callListenUser();
-        if (CollectionUtils.isEmpty(listenCallList)) {
-            return;
-        }
-        String content = System.currentTimeMillis() + " 小程序 : <" + payApplication.getAppName() + "> 可能被封停或者禁用, 请注意验证";
-        Set<Long> userIdSet = listenCallList.stream().map(ListenCall::getUserId).collect(Collectors.toSet());
-        userIdSet.forEach(userId -> dingTalkMsgRpc.sendByUserId(userId, content));
-    }
-
-    private void sendPhoneTalkMsg(PayApplication payApplication) {
-        List<ListenCall> listenCallList = this.callListenUser();
-        if (CollectionUtils.isEmpty(listenCallList)) {
-            return;
-        }
-        String content = payApplication.getAppName() + "监测异常";
-        Set<String> phoneNumSet = listenCallList.stream().map(ListenCall::getPhoneNum).collect(Collectors.toSet());
-        phoneNumSet.forEach(phoneNum -> {
-            String lockKey = RedisKeyConstant.PHONE_CALL_LOCK + phoneNum;
-            if (!distributedLockComponent.doLock(lockKey, 0L, 1L, TimeUnit.MINUTES)) {
-                return;
-            }
-            this.phoneCall(content, phoneNum);
-        });
-    }
-
-    private List<ListenCall> callListenUser() {
-        List<ListenCall> listenCallList = listenCallService.list(new LambdaQueryWrapper<ListenCall>()
-                .eq(ListenCall::getStatus, StatusEnum.YES.getCode()));
-        if (CollectionUtils.isEmpty(listenCallList)) {
-            return Collections.emptyList();
-        }
-        Collection<ListenCall> collection = listenCallList.stream()
-                .collect(Collectors.toMap(ListenCall::getUserId, Function.identity(), (existing, replacement) -> existing))
-                .values();
-        return new ArrayList<>(collection);
-    }
-
-    private boolean appletCheck(String token, String appName) {
-        //参数对象
-        String dayTime = LocalDate.now().minusDays(3).toString();
-        Map<String, String> paramMap = new HashMap<>(2);
-        paramMap.put("begin_date", dayTime);
-        paramMap.put("end_date", dayTime);
-        String host = "https://api.weixin.qq.com/datacube/getweanalysisappiddailyretaininfo?access_token=" + token;
-        try {
-            // 带参POST请求
-            String result = HttpUtil.post(host, JsonUtil.toString(paramMap));
-            //结果为空, 判定腾讯接口返回错误, 不判定为封禁
-            if (Strings.isBlank(result)) {
-                return Boolean.TRUE;
-            }
-            //没有报错
-            if (!result.contains("errcode")) {
-                return Boolean.TRUE;
-            }
-            //结果返回错误
-            Map<String, Object> resultMap = JsonUtil.toMap(result, Map.class, Object.class);
-            //排除计算中的特殊报错
-            if (Objects.equals(resultMap.get("errcode").toString(), "61503")) {
-                return Boolean.TRUE;
-            }
-            log.error("小程序封停监测结果, appName : {}, result : {}", appName, result);
-        } catch (Exception e) {
-            log.error("小程序封停监测异常, appName : {},  e : {}", appName, e.getMessage());
-            return Boolean.FALSE;
-        }
-        return Boolean.FALSE;
-    }
-
-    private void phoneCall(String param, String mobile) {
-        RestTemplate restTemplate = new RestTemplate();
-        String appCode = "f395b1587fc04a49a975f908660fb1e9";
-        String host = "https://jumfixed.market.alicloudapi.com/voice-notify/send";
-        HttpHeaders headers = new HttpHeaders();
-        headers.set("Authorization", "APPCODE " + appCode);
-        headers.set("Content-Type", ContentType.FORM_URLENCODED.getValue());
-        //参数
-        MultiValueMap<String, String> requestParams = new LinkedMultiValueMap<>();
-        requestParams.add("mobile", mobile);
-        requestParams.add("templateId", "JMJNAWUQOJP9");
-        requestParams.add("param", param);
-        String result = null;
-        try {
-            ResponseEntity<String> responseEntity = restTemplate.exchange(host, HttpMethod.POST,
-                    new HttpEntity<>(requestParams, headers), String.class);
-            result = responseEntity.getBody();
-        } catch (Exception e) {
-            log.error("阿里语音呼叫失败, requestParams : {}, e : {}", JsonUtil.toString(requestParams), e.getMessage());
-        }
-        log.error("阿里语音呼叫结果, result : {}", result);
-    }
-
-}

+ 3 - 17
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/CpSendMsgLogServiceImpl.java

@@ -8,6 +8,7 @@ import com.zanxiang.game.module.manage.enums.CpSendRoleResultEnum;
 import com.zanxiang.game.module.manage.pojo.dto.CpSendMsgResultDTO;
 import com.zanxiang.game.module.manage.pojo.dto.GameDTO;
 import com.zanxiang.game.module.manage.service.*;
+import com.zanxiang.game.module.manage.utils.SignUtil;
 import com.zanxiang.game.module.mybatis.entity.CpSendMsgLog;
 import com.zanxiang.game.module.mybatis.entity.CpSendMsgResult;
 import com.zanxiang.game.module.mybatis.entity.GameSupper;
@@ -25,8 +26,6 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.support.TransactionTemplate;
 import org.springframework.web.client.RestTemplate;
 
-import java.nio.charset.StandardCharsets;
-import java.security.MessageDigest;
 import java.time.LocalDateTime;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -40,8 +39,6 @@ import java.util.stream.Collectors;
 @Service
 public class CpSendMsgLogServiceImpl extends ServiceImpl<CpSendMsgLogMapper, CpSendMsgLog> implements ICpSendMsgLogService {
 
-    private static final String SIGN_MD5 = "MD5";
-
     @Autowired
     private TransactionTemplate transactionTemplate;
 
@@ -149,14 +146,13 @@ public class CpSendMsgLogServiceImpl extends ServiceImpl<CpSendMsgLogMapper, CpS
                 .build();
     }
 
-    private CpSendMsgResultDTO cpSendMsgApi(GameSupper gameSupper, String msgId, String serverId, String text,
-                                            List<String> roleIdList) throws Exception {
+    private CpSendMsgResultDTO cpSendMsgApi(GameSupper gameSupper, String msgId, String serverId, String text, List<String> roleIdList) {
         long time = System.currentTimeMillis() / 1000;
         Map<String, Object> param = new HashMap<>(8);
         param.put("msgId", msgId);
         param.put("strRan", msgId);
         param.put("time", time);
-        param.put("sign", this.MD5("key=" + gameSupper.getCpSendMsgKey() + "&msgId=" + msgId + "&strRan=" + msgId + "&time=" + time));
+        param.put("sign", SignUtil.md5("key=" + gameSupper.getCpSendMsgKey() + "&msgId=" + msgId + "&strRan=" + msgId + "&time=" + time));
         param.put("pushType", 1);
         param.put("serverid", serverId);
         param.put("roleIds", roleIdList);
@@ -180,14 +176,4 @@ public class CpSendMsgLogServiceImpl extends ServiceImpl<CpSendMsgLogMapper, CpS
         }
         return JsonUtil.toObj(result, CpSendMsgResultDTO.class);
     }
-
-    private String MD5(String data) throws Exception {
-        java.security.MessageDigest md = MessageDigest.getInstance(SIGN_MD5);
-        byte[] array = md.digest(data.getBytes(StandardCharsets.UTF_8));
-        StringBuilder sb = new StringBuilder();
-        for (byte item : array) {
-            sb.append(Integer.toHexString((item & 0xFF) | 0x100), 1, 3);
-        }
-        return sb.toString();
-    }
 }

+ 29 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/GameExtServiceImpl.java

@@ -0,0 +1,29 @@
+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.IGameExtService;
+import com.zanxiang.game.module.mybatis.entity.GameExt;
+import com.zanxiang.game.module.mybatis.mapper.GameExtMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-09-23
+ * @description : 游戏密钥
+ */
+@Slf4j
+@Service
+public class GameExtServiceImpl extends ServiceImpl<GameExtMapper, GameExt> implements IGameExtService {
+
+    @Override
+    public GameExt getByGameId(Long gameId) {
+        return this.getOne(new LambdaQueryWrapper<GameExt>().eq(GameExt::getGameId, gameId));
+    }
+
+    @Override
+    public GameExt getByGameAppId(String appId) {
+        return this.getOne(new LambdaQueryWrapper<GameExt>().eq(GameExt::getAppId, appId));
+    }
+}

+ 85 - 10
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/KfAppletMsgServiceImpl.java

@@ -6,10 +6,7 @@ import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.zanxiang.erp.security.util.SecurityUtil;
 import com.zanxiang.game.back.base.pojo.enums.OrderStatusEnum;
 import com.zanxiang.game.module.manage.constant.RedisKeyConstant;
-import com.zanxiang.game.module.manage.enums.KfRoomMsgOwnerEnum;
-import com.zanxiang.game.module.manage.enums.KfRoomMsgTypeEnum;
-import com.zanxiang.game.module.manage.enums.KfWebSocketMsgEnum;
-import com.zanxiang.game.module.manage.enums.OrderStateEnum;
+import com.zanxiang.game.module.manage.enums.*;
 import com.zanxiang.game.module.manage.pojo.dto.KfAppletMsgDTO;
 import com.zanxiang.game.module.manage.pojo.dto.KfWebSocketMsgDTO;
 import com.zanxiang.game.module.manage.pojo.dto.PayApplicationDTO;
@@ -110,6 +107,12 @@ public class KfAppletMsgServiceImpl implements IKfAppletMsgService {
     @Autowired
     private IDistributedLockComponent distributedLockComponent;
 
+    @Autowired
+    private IKfAppletReplyService kfAppletReplyService;
+
+    @Autowired
+    private IUserAppletService userAppletService;
+
     @Override
     public void appletMsg(String postData) {
         KfAppletMsgDTO kfAppletMsgDTO = JsonUtil.toObj(postData, KfAppletMsgDTO.class);
@@ -155,6 +158,8 @@ public class KfAppletMsgServiceImpl implements IKfAppletMsgService {
         }
         //客服休息时间, 发送自动回复
         this.systemReplyHandle(gameApplet.getGameId(), kfAppletMsgDTO.getFromUserName(), kfRoom);
+        //小程序自动回复
+        this.appletReplyHandle(gameApplet.getGameId(), kfAppletMsgDTO.getFromUserName(), kfRoom, gameApplet.getAppId());
         //消息报警监测
         this.monitorWordHandle(gameApplet, kfAppletMsgDTO);
         //保存房间消息
@@ -165,6 +170,7 @@ public class KfAppletMsgServiceImpl implements IKfAppletMsgService {
                     .set(KfSessionUser::getIsWait, Boolean.TRUE)
                     .set(KfSessionUser::getWaitStartTime, LocalDateTime.now())
                     .set(KfSessionUser::getUpdateTime, LocalDateTime.now())
+                    .isNull(KfSessionUser::getSessionFrom)
                     .eq(KfSessionUser::getOpenId, kfAppletMsgDTO.getFromUserName())
                     .eq(KfSessionUser::getGameId, gameApplet.getGameId())
             );
@@ -173,6 +179,72 @@ public class KfAppletMsgServiceImpl implements IKfAppletMsgService {
         this.pushMessage(this.transform(kfRoom, gameApplet.getGameId(), kfAppletMsgDTO.getFromUserName(), kfRoomMsg, msgContent));
     }
 
+    private void appletReplyHandle(Long gameId, String openId, KfRoom kfRoom, String appId) {
+        //玩家信息
+        KfSessionUser kfSessionUser = kfSessionUserService.getById(openId, gameId);
+        //来源类型
+        KfSessionFromEnum kfSessionFrom = KfSessionFromEnum.getKfSessionFrom(kfSessionUser.getSessionFrom());
+        if (kfSessionFrom == null) {
+            return;
+        }
+        //获取自动回复配置
+        KfAppletReply kfAppletReply = kfAppletReplyService.getById(gameId);
+        if (kfAppletReply == null) {
+            return;
+        }
+        //判断是否来源与平台
+        if (Objects.equals(kfSessionFrom, KfSessionFromEnum.KF_SESSION_FROM_PLATFORM)) {
+            //回复默认消息
+            if (Strings.isNotBlank(kfAppletReply.getReplyDefault())) {
+                this.sysMsgSend(gameId, openId, kfAppletReply.getReplyDefault(), kfRoom);
+            }
+        }
+        //判断是否来源于广告
+        if (Objects.equals(kfSessionFrom, KfSessionFromEnum.KF_SESSION_FROM_AD)) {
+            //存在文本消息发送
+            if (Strings.isNotBlank(kfAppletReply.getReplyText())) {
+                this.sysMsgSend(gameId, openId, kfAppletReply.getReplyText(), kfRoom);
+            }
+            //存在图片发送
+            if (Strings.isNotBlank(kfAppletReply.getReplyImg())) {
+                this.sysImgMsgSend(gameId, openId, kfAppletReply.getReplyImg(), kfRoom);
+            }
+            //存在链接发送
+            if (Strings.isNotBlank(kfAppletReply.getReplyLink())) {
+                //链接消息参数转换
+                Map<String, String> linkMap = JsonUtil.toMap(kfAppletReply.getReplyLink(), Map.class, String.class);
+                String url = linkMap.get("url");
+                //链接拼接短链id
+                if (Strings.isNotBlank(url)) {
+                    UserApplet userApplet = userAppletService.getOne(new LambdaQueryWrapper<UserApplet>()
+                            .eq(UserApplet::getAppId, appId)
+                            .eq(UserApplet::getOpenId, openId)
+                            .orderByDesc(UserApplet::getCreateTime)
+                            .last("limit 1"));
+                    if (userApplet != null) {
+                        linkMap.put("url", url + "?customer_channel=" + userApplet.getId());
+                    }
+                }
+                this.sysLinkMsgSend(gameId, openId, kfRoom, linkMap);
+            }
+        }
+    }
+
+    private void sysLinkMsgSend(Long gameId, String openId, KfRoom kfRoom, Map<String, String> linkMap) {
+        //发送消息
+        Map<String, Object> msgParamMap = new HashMap<>(3);
+        msgParamMap.put("touser", openId);
+        msgParamMap.put("link", linkMap);
+        msgParamMap.put("msgtype", KfRoomMsgTypeEnum.KF_MSG_TYPE_LINK.getValue());
+        Tuple2<Long, String> tuple2 = kfWxApiService.sendCustomMessageApi(gameId, msgParamMap);
+        //发送失败
+        if (!Objects.equals(tuple2.getT1(), 0L)) {
+            return;
+        }
+        //保存发送的支付链接消息
+        kfRoomMsgService.save(this.transform(openId, gameId, kfRoom, KfRoomMsgTypeEnum.KF_MSG_TYPE_LINK, JsonUtil.toString(msgParamMap)));
+    }
+
     private void monitorWordHandle(GameApplet gameApplet, KfAppletMsgDTO kfAppletMsgDTO) {
         //非文本消息
         if (!Objects.equals(kfAppletMsgDTO.getMsgType(), KfRoomMsgTypeEnum.KF_MSG_TYPE_TEXT.getValue())) {
@@ -399,20 +471,22 @@ public class KfAppletMsgServiceImpl implements IKfAppletMsgService {
             return;
         }
         //不存在角色信息, 不做更新
-        if (gameUserRole == null) {
+        if (user == null && Strings.isBlank(kfAppletMsgDTO.getSessionFrom())) {
             return;
         }
         //存在, 更新玩家信息
         kfSessionUserService.update(new LambdaUpdateWrapper<KfSessionUser>()
-                .set(KfSessionUser::getUserId, user.getId())
-                .set(KfSessionUser::getLastRoleId, gameUserRole.getRoleId())
-                .set(KfSessionUser::getLastRoleName, gameUserRole.getRoleName())
-                .set(KfSessionUser::getServerId, gameUserRole.getServerId())
-                .set(KfSessionUser::getServerName, gameUserRole.getServerName())
+                .set(user != null, KfSessionUser::getUserId, user == null ? null : user.getId())
+                .set(gameUserRole != null, KfSessionUser::getLastRoleId, gameUserRole == null ? null : gameUserRole.getRoleId())
+                .set(gameUserRole != null, KfSessionUser::getLastRoleName, gameUserRole == null ? null : gameUserRole.getRoleName())
+                .set(gameUserRole != null, KfSessionUser::getServerId, gameUserRole == null ? null : gameUserRole.getServerId())
+                .set(gameUserRole != null, KfSessionUser::getServerName, gameUserRole == null ? null : gameUserRole.getServerName())
+                .set(Strings.isNotBlank(kfAppletMsgDTO.getSessionFrom()), KfSessionUser::getSessionFrom, kfAppletMsgDTO.getSessionFrom())
                 .set(KfSessionUser::getUpdateTime, LocalDateTime.now())
                 .eq(KfSessionUser::getOpenId, kfAppletMsgDTO.getFromUserName())
                 .eq(KfSessionUser::getGameId, gameApplet.getGameId())
         );
+        distributedLockComponent.unlock(lockKey);
     }
 
     private KfSessionUser transform(KfAppletMsgDTO kfAppletMsgDTO, GameApplet gameApplet, User user, GameUserRole gameUserRole) {
@@ -425,6 +499,7 @@ public class KfAppletMsgServiceImpl implements IKfAppletMsgService {
                 .lastRoleName(gameUserRole == null ? "神秘人[未创角]" : gameUserRole.getRoleName())
                 .serverId(gameUserRole == null ? null : gameUserRole.getServerId())
                 .serverName(gameUserRole == null ? null : gameUserRole.getServerName())
+                .sessionFrom(Strings.isBlank(kfAppletMsgDTO.getSessionFrom()) ? null : kfAppletMsgDTO.getSessionFrom())
                 .createTime(LocalDateTime.now())
                 .updateTime(LocalDateTime.now())
                 .build();

+ 18 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/KfAppletReplyServiceImpl.java

@@ -0,0 +1,18 @@
+package com.zanxiang.game.module.manage.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zanxiang.game.module.manage.service.IKfAppletReplyService;
+import com.zanxiang.game.module.mybatis.entity.KfAppletReply;
+import com.zanxiang.game.module.mybatis.mapper.KfAppletReplyMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-04-30
+ * @description : 小程序自动回复
+ */
+@Slf4j
+@Service
+public class KfAppletReplyServiceImpl extends ServiceImpl<KfAppletReplyMapper, KfAppletReply> implements IKfAppletReplyService {
+}

+ 109 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/ListenCallServiceImpl.java

@@ -1,11 +1,37 @@
 package com.zanxiang.game.module.manage.service.impl;
 
+import cn.hutool.http.ContentType;
+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.base.ErpServer;
+import com.zanxiang.erp.base.rpc.IDingTalkMsgRpc;
+import com.zanxiang.game.module.base.pojo.enums.StatusEnum;
+import com.zanxiang.game.module.manage.constant.RedisKeyConstant;
+import com.zanxiang.game.module.manage.service.IGameService;
 import com.zanxiang.game.module.manage.service.IListenCallService;
+import com.zanxiang.game.module.mybatis.entity.Game;
 import com.zanxiang.game.module.mybatis.entity.ListenCall;
 import com.zanxiang.game.module.mybatis.mapper.ListenCallMapper;
+import com.zanxiang.module.redis.service.IDistributedLockComponent;
+import com.zanxiang.module.util.JsonUtil;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.apache.logging.log4j.util.Strings;
+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.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * @author : lingfeng
@@ -15,4 +41,87 @@ import org.springframework.stereotype.Service;
 @Slf4j
 @Service
 public class ListenCallServiceImpl extends ServiceImpl<ListenCallMapper, ListenCall> implements IListenCallService {
+
+    @DubboReference(providedBy = ErpServer.SERVER_DUBBO_NAME)
+    private IDingTalkMsgRpc dingTalkMsgRpc;
+
+    @Autowired
+    private IDistributedLockComponent distributedLockComponent;
+
+    @Autowired
+    private IGameService gameService;
+
+    @Override
+    public void sendDingTalkMsg(Long gameId, boolean isSuper, String content) {
+        List<ListenCall> listenCallList = this.callListenUser(gameId, isSuper);
+        if (CollectionUtils.isEmpty(listenCallList)) {
+            return;
+        }
+        Set<Long> userIdSet = listenCallList.stream()
+                .filter(listenCall -> Strings.isNotBlank(listenCall.getDingTalkNum()))
+                .map(ListenCall::getUserId).collect(Collectors.toSet());
+        userIdSet.forEach(userId -> dingTalkMsgRpc.sendByUserId(userId, content));
+    }
+
+    @Override
+    public void sendPhoneTalkMsg(Long gameId, boolean isSuper, String listenName) {
+        List<ListenCall> listenCallList = this.callListenUser(gameId, isSuper);
+        if (CollectionUtils.isEmpty(listenCallList)) {
+            return;
+        }
+        String content = listenName + "监测异常";
+        Set<String> phoneNumSet = listenCallList.stream()
+                .filter(listenCall -> Strings.isNotBlank(listenCall.getPhoneNum()))
+                .map(ListenCall::getPhoneNum).collect(Collectors.toSet());
+        phoneNumSet.forEach(phoneNum -> {
+            String lockKey = RedisKeyConstant.PHONE_CALL_LOCK + phoneNum;
+            if (!distributedLockComponent.doLock(lockKey, 0L, 1L, TimeUnit.MINUTES)) {
+                return;
+            }
+            this.phoneCall(content, phoneNum);
+        });
+    }
+
+    private List<ListenCall> callListenUser(Long gameId, boolean isSuper) {
+        List<Long> gameIdList = new ArrayList<>();
+        if (isSuper) {
+            gameIdList = gameService.list(new LambdaQueryWrapper<Game>()
+                    .eq(Game::getSuperGameId, gameId)
+            ).stream().map(Game::getId).collect(Collectors.toList());
+        }
+        List<ListenCall> listenCallList = super.list(new LambdaQueryWrapper<ListenCall>()
+                .eq(!isSuper, ListenCall::getGameId, gameId)
+                .in(isSuper && CollectionUtils.isNotEmpty(gameIdList), ListenCall::getGameId, gameIdList)
+                .eq(ListenCall::getStatus, StatusEnum.YES.getCode()));
+        if (CollectionUtils.isEmpty(listenCallList)) {
+            return Collections.emptyList();
+        }
+        Collection<ListenCall> collection = listenCallList.stream()
+                .collect(Collectors.toMap(ListenCall::getUserId, Function.identity(), (existing, replacement) -> existing))
+                .values();
+        return new ArrayList<>(collection);
+    }
+
+    private void phoneCall(String param, String mobile) {
+        RestTemplate restTemplate = new RestTemplate();
+        String appCode = "f395b1587fc04a49a975f908660fb1e9";
+        String host = "https://jumfixed.market.alicloudapi.com/voice-notify/send";
+        HttpHeaders headers = new HttpHeaders();
+        headers.set("Authorization", "APPCODE " + appCode);
+        headers.set("Content-Type", ContentType.FORM_URLENCODED.getValue());
+        //参数
+        MultiValueMap<String, String> requestParams = new LinkedMultiValueMap<>();
+        requestParams.add("mobile", mobile);
+        requestParams.add("templateId", "JMJNAWUQOJP9");
+        requestParams.add("param", param);
+        String result = null;
+        try {
+            ResponseEntity<String> responseEntity = restTemplate.exchange(host, HttpMethod.POST,
+                    new HttpEntity<>(requestParams, headers), String.class);
+            result = responseEntity.getBody();
+        } catch (Exception e) {
+            log.error("阿里语音呼叫失败, requestParams : {}, e : {}", JsonUtil.toString(requestParams), e.getMessage());
+        }
+        log.error("阿里语音呼叫结果, result : {}", result);
+    }
 }

+ 103 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/UserAppletServiceImpl.java

@@ -0,0 +1,103 @@
+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.base.pojo.enums.DeleteEnum;
+import com.zanxiang.game.module.manage.pojo.params.UserAppletSubmitParam;
+import com.zanxiang.game.module.manage.service.IGameAppletService;
+import com.zanxiang.game.module.manage.service.IGameExtService;
+import com.zanxiang.game.module.manage.service.IUserAppletService;
+import com.zanxiang.game.module.manage.utils.SignUtil;
+import com.zanxiang.game.module.mybatis.entity.GameApplet;
+import com.zanxiang.game.module.mybatis.entity.GameExt;
+import com.zanxiang.game.module.mybatis.entity.UserApplet;
+import com.zanxiang.game.module.mybatis.mapper.UserAppletMapper;
+import com.zanxiang.module.util.JsonUtil;
+import com.zanxiang.module.util.URIUtil;
+import com.zanxiang.module.util.exception.BaseException;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-04-29
+ * @description : 投放小程序用户信息
+ */
+@Slf4j
+@Service
+public class UserAppletServiceImpl extends ServiceImpl<UserAppletMapper, UserApplet> implements IUserAppletService {
+
+    @Autowired
+    private IGameAppletService gameAppletService;
+
+    @Autowired
+    private IGameExtService gameExtService;
+
+    @Autowired
+    private RestTemplate restTemplate;
+
+    @Override
+    public boolean userAppletSubmit(UserAppletSubmitParam param) {
+        GameApplet gameApplet = gameAppletService.getOne(new LambdaQueryWrapper<GameApplet>()
+                .eq(GameApplet::getAppId, param.getAppId())
+                .last("limit 1"));
+        if (gameApplet == null) {
+            log.error("非法参数, 小程序信息不存在, param : {}", JsonUtil.toString(param));
+            throw new BaseException("非法参数, 小程序信息不存在");
+        }
+        GameExt gameExt = gameExtService.getByGameId(gameApplet.getGameId());
+        this.signCheck(gameExt.getLoginKey(), param);
+        //获取用户小程序 openId
+        String openId = this.getAppletOpenId(param.getCode(), param.getAppId(), gameApplet.getAppSecret());
+        //数据保存且返回结果
+        return super.save(this.transform(param, openId));
+    }
+
+    private UserApplet transform(UserAppletSubmitParam param, String openId) {
+        return UserApplet.builder()
+                .appId(param.getAppId())
+                .openId(openId)
+                .channel(param.getChannel())
+                .isDelete(DeleteEnum.NO.getCode())
+                .createTime(LocalDateTime.now())
+                .updateTime(LocalDateTime.now())
+                .build();
+    }
+
+    private void signCheck(String loginKey, UserAppletSubmitParam param) {
+        String signStr = "loginKey=" + loginKey + "appId=" + param.getAppId()
+                + "code=" + param.getCode() + "signTime=" + param.getSignTime();
+        String mySign = SignUtil.md5(signStr);
+        if (!Objects.equals(mySign.toUpperCase(), param.getSign().toUpperCase())) {
+            log.error("加密验证失败, sign : {}, mySign : {}", param.getSign(), mySign);
+            throw new BaseException("加密标识错误");
+        }
+    }
+
+    private String getAppletOpenId(String code, String appId, String secret) {
+        // 请求微信服务器,使用code获取openid
+        Map<String, String> paramMap = new HashMap<>(4);
+        paramMap.put("appid", appId);
+        paramMap.put("secret", secret);
+        paramMap.put("js_code", code);
+        paramMap.put("grant_type", "authorization_code");
+        // 发送请求
+        String url = URIUtil.fillUrlParams("https://api.weixin.qq.com/sns/jscode2session", paramMap, Boolean.FALSE);
+        String sr = restTemplate.getForObject(url, String.class);
+        // 解析相应内容(转换成json对象)
+        Map<String, String> resultMap = JsonUtil.toMap(sr, Map.class, String.class);
+        if (resultMap == null || Strings.isBlank(resultMap.get("openid"))) {
+            log.error("获取用户小程序/小游戏openId失败, appId : {}, resultMap : {}", appId, JsonUtil.toString(resultMap));
+            throw new BaseException("获取用户小程序/小游戏openId失败");
+        }
+        return resultMap.get("openid");
+    }
+}

+ 0 - 61
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/task/PayApplicationTask.java

@@ -1,61 +0,0 @@
-package com.zanxiang.game.module.manage.task;
-
-import com.zanxiang.game.module.manage.constant.RedisKeyConstant;
-import com.zanxiang.game.module.manage.service.IAppletCheckService;
-import com.zanxiang.module.redis.service.IDistributedLockComponent;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.scheduling.annotation.Scheduled;
-import org.springframework.stereotype.Component;
-
-import java.time.LocalDateTime;
-import java.util.concurrent.TimeUnit;
-
-/**
- * @author : lingfeng
- * @time : 2024-01-20
- * @description : 支付应用任务
- */
-@Slf4j
-@Component
-public class PayApplicationTask {
-
-    @Autowired
-    private IDistributedLockComponent distributedLockComponent;
-
-    @Autowired
-    private IAppletCheckService appletCheckService;
-
-    /**
-     * 服务器域名
-     */
-    @Value("${taskRun}")
-    private Boolean taskRun;
-
-    /**
-     * 小程序每10分钟检查
-     */
-    @Scheduled(cron = "0 0/10 * * * ?")
-    public void payApplicationCheck() {
-        if (!taskRun) {
-            return;
-        }
-        //上锁
-        if (!distributedLockComponent.doLock(RedisKeyConstant.PAY_APP_CHECK_LOCK, 0L, 15L, TimeUnit.MINUTES)) {
-            return;
-        }
-        log.error("小程序每10分钟封停监控定时器开始执行, startTime : {}", LocalDateTime.now().toString());
-        try {
-            //执行检测
-            appletCheckService.payApplicationCheck();
-        } catch (Exception e) {
-            log.error("小程序每10分钟封停监控异常, e : {}", e.getMessage());
-        } finally {
-            //释放锁
-            distributedLockComponent.unlock(RedisKeyConstant.PAY_APP_CHECK_LOCK);
-        }
-        log.error("小程序每10分钟封停监控定时器执行结束 , endTime  : {}", LocalDateTime.now().toString());
-    }
-
-}

+ 37 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/utils/SignUtil.java

@@ -0,0 +1,37 @@
+package com.zanxiang.game.module.manage.utils;
+
+import com.zanxiang.module.util.exception.BaseException;
+import lombok.extern.slf4j.Slf4j;
+
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+
+/**
+ * @author : lingfeng
+ * @time : 2022-09-23
+ * @description : 签名算法工具类
+ */
+@Slf4j
+public class SignUtil {
+
+    /**
+     * MD5加密
+     *
+     * @param data 待处理数据
+     * @return MD5结果
+     */
+    public static String md5(String data) {
+        try {
+            java.security.MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] array = md.digest(data.getBytes(StandardCharsets.UTF_8));
+            StringBuilder sb = new StringBuilder();
+            for (byte item : array) {
+                sb.append(Integer.toHexString((item & 0xFF) | 0x100), 1, 3);
+            }
+            return sb.toString();
+        } catch (Exception e) {
+            log.error("MD5加密异常, data : {}", data);
+            throw new BaseException("MD5加密异常");
+        }
+    }
+}

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

@@ -344,7 +344,7 @@ public class KfMsgWebsocketHandler implements WebSocketHandler {
                 .roomList(onlineRoomList)
                 .build());
         //以防锁依然存在, 尝试释放锁, 锁如果不存在, 会抛出异常, 直接捕获不处理
-        String lockKey = RedisKeyConstant.KF_MSG_USER_CONNECT_JOIN + kfRoom.getOpenId();
+        String lockKey = RedisKeyConstant.KF_MSG_USER_CONNECT_JOIN + kfRoom.getOpenId() + "_" + gameId;
         try {
             log.error("结束会话释放锁, key : {}", lockKey);
             redisUtil.deleteCache(lockKey);

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

@@ -50,6 +50,11 @@ public class GameSupper implements Serializable {
      */
     private String cpSendMsgKey;
 
+    /**
+     * CP服务端交互密钥
+     */
+    private String cpServerKey;
+
     /**
      * 1 删除  0 正常
      */

+ 66 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/KfAppletReply.java

@@ -0,0 +1,66 @@
+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.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-04-30
+ * @description : 小程序自动回复
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@ToString
+@Builder
+@TableName("t_kf_applet_reply")
+public class KfAppletReply implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 游戏
+     */
+    @TableId(value = "game_id", type = IdType.INPUT)
+    private Long gameId;
+
+    /**
+     * 应用id
+     */
+    private String appId;
+
+    /**
+     * 默认回复
+     */
+    private String replyDefault;
+
+    /**
+     * 文本回复
+     */
+    private String replyText;
+
+    /**
+     * 图片回复
+     */
+    private String replyImg;
+
+    /**
+     * 图文链接回复
+     */
+    private String replyLink;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 5 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/KfSessionUser.java

@@ -66,6 +66,11 @@ public class KfSessionUser implements Serializable {
      */
     private String serverName;
 
+    /**
+     * 消息来源
+     */
+    private String sessionFrom;
+
     /**
      * 创建时间
      */

+ 63 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/UserApplet.java

@@ -0,0 +1,63 @@
+package com.zanxiang.game.module.mybatis.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-04-29
+ * @description : 投放小程序用户信息
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@ToString
+@Builder
+@TableName("t_user_applet")
+public class UserApplet implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 应用id
+     */
+    private String appId;
+
+    /**
+     * 用户openId
+     */
+    private String openId;
+
+    /**
+     * 渠道参数
+     */
+    private String channel;
+
+    /**
+     * 1 伪删除  0正常
+     */
+    @TableLogic
+    private Integer isDelete;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 12 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/mapper/KfAppletReplyMapper.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.KfAppletReply;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-04-30
+ * @description : ${description}
+ */
+public interface KfAppletReplyMapper extends BaseMapper<KfAppletReply> {
+}

+ 12 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/mapper/UserAppletMapper.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.UserApplet;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-04-29
+ * @description : ${description}
+ */
+public interface UserAppletMapper extends BaseMapper<UserApplet> {
+}

+ 1 - 1
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/SDKApplication.java

@@ -23,7 +23,7 @@ public class SDKApplication {
 
     public static void main(String[] args) {
         SpringApplication.run(SDKApplication.class, args);
-        System.out.println("赞象SDK服务启动成功 <CP发送消息代码提交> ( ´・・)ノ(._.`) \n" +
+        System.out.println("赞象SDK服务启动成功 <删除调试日志> ( ´・・)ノ(._.`) \n" +
                 " ___________ _   __\n" +
                 "/  ___|  _  \\ | / /\n" +
                 "\\ `--.| | | | |/ / \n" +

+ 1 - 1
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/controller/PayController.java

@@ -60,7 +60,7 @@ public class PayController {
     @ApiOperation(value = "支付参数生成")
     @PostMapping(value = "/create")
     public ResultVO<Map> create(@Validated @RequestBody ProductPayParam product, @ValidLogin UserData userData) {
-        log.error("接收到支付请求, product : {}", JsonUtil.toString(product));
+        log.error("接收到支付请求, product : {}, userData : {}", JsonUtil.toString(product), JsonUtil.toString(userData));
         return ResultVO.ok(orderPayService.payCreate(product, userData));
     }
 

+ 10 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/controller/UserController.java

@@ -15,6 +15,7 @@ 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.*;
@@ -29,6 +30,7 @@ import java.util.Objects;
  */
 @Api(tags = "用户接口")
 @RestController
+@Slf4j
 @RequestMapping(value = "/api/user")
 public class UserController {
 
@@ -99,6 +101,14 @@ public class UserController {
         return ResultVO.ok(userService.getUserCustomer(userData));
     }
 
+    @UnSignCheck
+    @ApiOperation(value = "CP服务端上传角色信息")
+    @PostMapping("/cp/server/update/game/role")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = Boolean.class)})
+    public ResultVO<Boolean> updateUserGameRole(@Validated @RequestBody GameUserRoleSubmitParam param) {
+        return ResultVO.ok(gameUserRoleService.updateUserGameRole(param));
+    }
+
     @ApiOperation(value = "上传角色信息")
     @PostMapping("/update/game/role")
     @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = Boolean.class)})

+ 5 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/enums/KafkaEventTrackEnum.java

@@ -17,6 +17,11 @@ public enum KafkaEventTrackEnum {
      */
     KAFKA_EVENT_TRACK_REG("KAFKA_EVENT_TRACK_REG"),
 
+    /**
+     * 渠道变更
+     */
+    KAFKA_EVENT_TRACK_AGENT_UPDATE("KAFKA_EVENT_TRACK_AGENT_UPDATE"),
+
     /**
      * 登录
      */

+ 12 - 3
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/handler/GlobalExceptionHandler.java

@@ -46,6 +46,7 @@ public class GlobalExceptionHandler {
      */
     @ExceptionHandler(BindException.class)
     public ResultVO<?> validatedBindException(BindException e) {
+        log.error(e.getMessage(), e);
         String message = e.getAllErrors().get(0).getDefaultMessage();
         return ResultVO.fail(message);
     }
@@ -55,6 +56,7 @@ public class GlobalExceptionHandler {
      */
     @ExceptionHandler(MethodArgumentNotValidException.class)
     public ResultVO<?> validExceptionHandler(MethodArgumentNotValidException e) {
+        log.error(e.getMessage(), e);
         String message = e.getBindingResult().getFieldError().getDefaultMessage();
         return ResultVO.fail(message);
     }
@@ -70,13 +72,20 @@ public class GlobalExceptionHandler {
 
     /**
      * 参数类型不匹配导致转换异常
-     *
-     * @param e
-     * @return
      */
     @ExceptionHandler(MethodArgumentTypeMismatchException.class)
     public ResultVO<?> mismatchErrorHandler(MethodArgumentTypeMismatchException e) {
         log.error("方法:{},字段:{},参数:{},错误信息:{}", e.getParameter().getMethod(), e.getName(), e.getValue(), e.getMessage());
         return ResultVO.fail("请求参数异常,请勿非法操作");
     }
+
+    /**
+     * 空指针异常全局处理
+     */
+    @ExceptionHandler(NullPointerException.class)
+    public ResultVO<?> validExceptionHandler(NullPointerException e) {
+        log.error(e.getMessage(), e);
+        e.printStackTrace();
+        return ResultVO.fail("空指针异常,请勿非法操作");
+    }
 }

+ 57 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/GameUserRoleSubmitParam.java

@@ -0,0 +1,57 @@
+package com.zanxiang.game.module.sdk.pojo.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-04-17
+ * @description : 角色信息提交接口
+ */
+@Data
+public class GameUserRoleSubmitParam {
+
+    /**
+     * 游戏id
+     */
+    @ApiModelProperty("游戏id")
+    @NotBlank(message = "游戏id不可为空")
+    private String gameId;
+
+    /**
+     * 玩家id
+     */
+    @ApiModelProperty("玩家id")
+    @NotNull(message = "玩家id不可为空")
+    private Long userId;
+
+    /**
+     * 操作系统
+     */
+    @NotNull(message = "操作系统不可为空")
+    private String os;
+
+    /**
+     * 接口token
+     */
+    @ApiModelProperty("接口token")
+    @NotBlank(message = "接口token不可为空")
+    private String token;
+
+    /**
+     * 加密参数
+     */
+    @ApiModelProperty("加密参数")
+    @NotBlank(message = "加密参数不可为空")
+    private String sign;
+
+    /**
+     * 角色信息参数
+     */
+    @ApiModelProperty("角色信息")
+    @NotNull(message = "角色信息不可为null")
+    private GameUserRoleUpdateParam gameUserRoleParam;
+}

+ 0 - 31
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/GameUserRoleUpdateParam.java

@@ -5,7 +5,6 @@ import lombok.Data;
 
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotNull;
-import java.math.BigDecimal;
 
 /**
  * 游戏角色
@@ -44,24 +43,6 @@ public class GameUserRoleUpdateParam {
     @NotNull(message = "角色等级不可为空")
     private Long roleLevel;
 
-    /**
-     * 角色等级描述
-     */
-    @ApiModelProperty("角色等级描述")
-    private String roleGradeDesc;
-
-    /**
-     * 角色创建时间, 当TYPE_CREATE_ROLE为必须,时间戳
-     */
-    @ApiModelProperty("角色创建时间, 当TYPE_CREATE_ROLE为必须,时间戳")
-    private Long roleCreateTime;
-
-    /**
-     * 角色等级变化时间,时间戳
-     */
-    @ApiModelProperty("角色等级变化时间,时间戳")
-    private Long roleGradeUpdateTime;
-
     /**
      * 游戏服务器id
      */
@@ -88,18 +69,6 @@ public class GameUserRoleUpdateParam {
     @ApiModelProperty("玩家角色战力")
     private Long rolePower;
 
-    /**
-     * 角色余额
-     */
-    @ApiModelProperty("角色余额")
-    private BigDecimal platformCoin;
-
-    /**
-     * 游戏在线时长
-     */
-    @ApiModelProperty("游戏在线时长")
-    private Long totalOnlineTime;
-
     /**
      * 角色拓展属性
      */

+ 8 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/vo/GameInitVO.java

@@ -7,6 +7,8 @@ import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.util.Map;
+
 /**
  * @author : lingfeng
  * @time : 2023-06-29
@@ -47,4 +49,10 @@ public class GameInitVO {
      */
     @ApiModelProperty(notes = "H5游戏配置")
     private H5GameConfigDTO h5GameConfigDTO;
+
+    /**
+     * H5游戏配置新(老的字段 h5GameConfigDTO 保留, 但是新加的字段都只会在这个新字段中返回)
+     */
+    @ApiModelProperty(notes = "H5游戏配置新")
+    private Map<String, Object> h5GameConfigMap;
 }

+ 8 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IGameUserRoleService.java

@@ -4,12 +4,20 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.zanxiang.game.module.mybatis.entity.GameUserRole;
 import com.zanxiang.game.module.mybatis.entity.User;
 import com.zanxiang.game.module.sdk.pojo.param.GameRoleActiveCallParam;
+import com.zanxiang.game.module.sdk.pojo.param.GameUserRoleSubmitParam;
 import com.zanxiang.game.module.sdk.pojo.param.GameUserRoleUpdateParam;
 import com.zanxiang.game.module.sdk.pojo.param.UserData;
 
 
 public interface IGameUserRoleService extends IService<GameUserRole> {
 
+    /**
+     * CP 服务端玩家角色提交
+     *
+     * @param param : 提交参数
+     */
+    Boolean updateUserGameRole(GameUserRoleSubmitParam param);
+
     /**
      * 更新用户游戏角色
      *

+ 21 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IUserTokenService.java

@@ -1,11 +1,13 @@
 package com.zanxiang.game.module.sdk.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.module.mybatis.entity.GameExt;
 import com.zanxiang.game.module.mybatis.entity.UserToken;
 import com.zanxiang.game.module.sdk.pojo.dto.UserTokenDTO;
 import com.zanxiang.game.module.sdk.pojo.param.UserData;
 import com.zanxiang.game.module.sdk.pojo.vo.CpTokenCheckVO;
 import com.zanxiang.module.util.pojo.ResultVO;
+import reactor.util.function.Tuple2;
 
 /**
  * @author : lingfeng
@@ -36,6 +38,25 @@ public interface IUserTokenService extends IService<UserToken> {
      */
     ResultVO<Long> cpTokenCheck(String appId, Long userId, String token, String sign);
 
+    /**
+     * CP服务端加密方法
+     *
+     * @param gameExt : 游戏信息
+     * @param userId  : 玩家id
+     * @param token   : 令牌
+     * @return
+     */
+    Tuple2<String, String> getMySign(GameExt gameExt, Long userId, String token);
+
+    /**
+     * 获取玩家token
+     *
+     * @param userId : 玩家id
+     * @param token  : 令牌
+     * @return : 返回token信息
+     */
+    UserToken getCheckUserToken(Long userId, String token);
+
     /**
      * 用户活跃token更新
      *

+ 9 - 1
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/AgentServiceImpl.java

@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zanxiang.game.module.base.pojo.enums.GameCategoryEnum;
 import com.zanxiang.game.module.mybatis.entity.*;
 import com.zanxiang.game.module.mybatis.mapper.AgentMapper;
+import com.zanxiang.game.module.sdk.enums.KafkaEventTrackEnum;
 import com.zanxiang.game.module.sdk.pojo.param.UserData;
 import com.zanxiang.game.module.sdk.service.*;
 import com.zanxiang.module.util.DateUtil;
@@ -50,6 +51,9 @@ public class AgentServiceImpl extends ServiceImpl<AgentMapper, Agent> implements
     @Autowired
     private IGameExtService gameExtService;
 
+    @Autowired
+    private IKafkaService kafkaService;
+
     @Override
     public void userAgentUpdate(User user, String channel) {
         log.error("用户登录接收到的渠道参数 userId : {}, channel : {}", user.getId(), channel);
@@ -79,18 +83,22 @@ public class AgentServiceImpl extends ServiceImpl<AgentMapper, Agent> implements
             if (agent == null) {
                 return;
             }
+            LocalDateTime localDateTime = LocalDateTime.now();
             //更新用户信息
             userService.update(new LambdaUpdateWrapper<User>()
                     .set(User::getAgentId, agent.getId())
                     .set(User::getChannel, channel)
-                    .set(User::getUpdateTime, LocalDateTime.now())
+                    .set(User::getUpdateTime, localDateTime)
                     .eq(User::getId, user.getId()));
             //添加渠道变更记录
             userAgentLogService.agentUpdateLog(user, agent.getId(), channel);
             //回传用户信息
             user.setAgentId(agent.getId());
             user.setChannel(channel);
+            user.setUpdateTime(localDateTime);
             callBackService.userCallBack(user, urlParamMap);
+            //注册信息埋点数据发送到卡夫卡
+            kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_AGENT_UPDATE, JsonUtil.toString(user));
         } catch (Exception e) {
             log.error("用户渠道更新异常, userId : {}, channel : {}, e : {}", user.getId(), channel, e.getMessage());
         }

+ 12 - 12
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/CallBackServiceImpl.java

@@ -79,7 +79,7 @@ public class CallBackServiceImpl implements ICallBackService {
         }
         //查询小游戏信息或者H5游戏相关公众号信息
         GameApplet gameApplet = gameAppletService.getOne(new LambdaQueryWrapper<GameApplet>()
-                .eq(GameApplet::getGameId, user.getGameId()));
+                .eq(GameApplet::getGameId, agent.getGameId()));
         log.error("用户注册回传, userId : {}", user.getId());
         try {
             //腾讯H5回传
@@ -99,7 +99,7 @@ public class CallBackServiceImpl implements ICallBackService {
             }
             //头条回传
             if (CollectionUtils.isNotEmpty(urlParamMap) && Objects.equals(agent.getAccountType(), AccountTypeEnum.BYTE.getValue())) {
-                Game game = gameService.getById(user.getGameId());
+                Game game = gameService.getById(agent.getGameId());
                 //判断是微信小游戏
                 if (Objects.equals(game.getCategory(), GameCategoryEnum.CATEGORY_WX_APPLET.getId())) {
                     TtUserActiveRpcDTO activeReportRpcDTO = this.transform(user, agent, gameApplet, urlParamMap);
@@ -128,7 +128,7 @@ public class CallBackServiceImpl implements ICallBackService {
         }
         //查询小游戏信息或者H5游戏相关公众号信息
         GameApplet gameApplet = gameAppletService.getOne(new LambdaQueryWrapper<GameApplet>()
-                .eq(GameApplet::getGameId, user.getGameId()));
+                .eq(GameApplet::getGameId, agent.getGameId()));
         log.error("用户创角回传, userId : {}", user.getId());
         try {
             //腾讯H5回传
@@ -145,7 +145,7 @@ public class CallBackServiceImpl implements ICallBackService {
             }
             //头条回传
             if (Objects.equals(agent.getAccountType(), AccountTypeEnum.BYTE.getValue())) {
-                Game game = gameService.getById(user.getGameId());
+                Game game = gameService.getById(agent.getGameId());
                 //判断是微信小游戏
                 if (Objects.equals(game.getCategory(), GameCategoryEnum.CATEGORY_WX_APPLET.getId())) {
                     TtRoleRegisterRpcDTO ttRoleRegisterRpcDTO = this.transform(user, agent, gameUserRole, gameApplet);
@@ -175,7 +175,7 @@ public class CallBackServiceImpl implements ICallBackService {
         }
         //查询小游戏信息或者H5游戏相关公众号信息
         GameApplet gameApplet = gameAppletService.getOne(new LambdaQueryWrapper<GameApplet>()
-                .eq(GameApplet::getGameId, user.getGameId()));
+                .eq(GameApplet::getGameId, agent.getGameId()));
         log.error("用户订单回传, orderId : {}", platformOrderDTO.getOrderId());
         try {
             //腾讯H5回传
@@ -196,7 +196,7 @@ public class CallBackServiceImpl implements ICallBackService {
             //头条回传
             if (Objects.equals(agent.getAccountType(), AccountTypeEnum.BYTE.getValue())) {
                 //判断游戏类型
-                Game game = gameService.getById(platformOrderDTO.getGameId());
+                Game game = gameService.getById(agent.getGameId());
                 if (Objects.equals(game.getCategory(), GameCategoryEnum.CATEGORY_WX_APPLET.getId())) {
                     TtOrderRpcDTO ttOrderRpcDTO = this.transform(platformOrderDTO, user.getOpenId(), agent, gameApplet, user.getCreateTime());
                     ttMiniGameBackRpc.orderReport(ttOrderRpcDTO);
@@ -211,7 +211,7 @@ public class CallBackServiceImpl implements ICallBackService {
     private TencentRoleRegisterRpcDTO transform(User user, Agent agent, GameApplet gameApplet, GameUserRole gameUserRole) {
         return TencentRoleRegisterRpcDTO.builder()
                 .backPolicyId(agent.getBackPolicyId())
-                .gameId(gameUserRole.getGameId())
+                .gameId(agent.getGameId())
                 .adAccountId(agent.getAccountId())
                 .registerTime(gameUserRole.getCreateTime())
                 .channel(agent.getAgentKey())
@@ -230,7 +230,7 @@ public class CallBackServiceImpl implements ICallBackService {
                 .reportUrl(agent.getReportUrl())
                 .build();
         return TtRoleRegisterRpcDTO.builder()
-                .gameId(gameUserRole.getGameId())
+                .gameId(agent.getGameId())
                 .backPolicyId(agent.getBackPolicyId())
                 .accountReport(ttAccountRpcDTO)
                 .wechatAppId(gameApplet == null ? null : gameApplet.getAppId())
@@ -245,7 +245,7 @@ public class CallBackServiceImpl implements ICallBackService {
     private TencentUserDTO transform(User user, Agent agent, GameApplet gameApplet) {
         return TencentUserDTO.builder()
                 .backPolicyId(agent.getBackPolicyId())
-                .gameId(user.getGameId())
+                .gameId(agent.getGameId())
                 .adAccountId(agent.getAccountId())
                 .registerTime(user.getCreateTime())
                 .channel(agent.getAgentKey())
@@ -262,7 +262,7 @@ public class CallBackServiceImpl implements ICallBackService {
                 .reportUrl(agent.getReportUrl())
                 .build();
         return TtUserActiveRpcDTO.builder()
-                .gameId(user.getGameId())
+                .gameId(agent.getGameId())
                 .wechatAppId(gameApplet == null ? null : gameApplet.getAppId())
                 .wechatOpenId(user.getOpenId())
                 .accountReport(ttAccountRpcDTO)
@@ -279,7 +279,7 @@ public class CallBackServiceImpl implements ICallBackService {
     private TencentOrderDTO transform(PlatformOrderDTO platformOrderDTO, User user, Agent agent, GameApplet gameApplet) {
         return TencentOrderDTO.builder()
                 .backPolicyId(agent.getBackPolicyId())
-                .gameId(platformOrderDTO.getGameId())
+                .gameId(agent.getGameId())
                 .adAccountId(agent.getAccountId())
                 .registerTime(user.getCreateTime())
                 .rechargeMoney(platformOrderDTO.getAmount().longValue() * 100)
@@ -303,7 +303,7 @@ public class CallBackServiceImpl implements ICallBackService {
                 .reportUrl(agent.getReportUrl())
                 .build();
         return TtOrderRpcDTO.builder()
-                .gameId(platformOrderDTO.getGameId())
+                .gameId(agent.getGameId())
                 .accountReport(ttAccountRpcDTO)
                 .wechatAppId(gameApplet == null ? null : gameApplet.getAppId())
                 .wechatOpenId(openId)

+ 3 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/GameAppletServiceImpl.java

@@ -60,6 +60,7 @@ public class GameAppletServiceImpl extends ServiceImpl<GameAppletMapper, GameApp
 
     @Override
     public String appletMsgCheck(String appId, String signature, String timestamp, String nonce, String echoStr) throws Exception {
+        log.error("appId : {}, signature : {}, timestamp : {}, nonce : {}, echoStr : {}", appId, signature, timestamp, nonce, echoStr);
         GameAppletDTO gameAppletDTO = this.getByAppId(appId);
         GameAppletDTO.MsgConfigBean msgConfigBean = gameAppletDTO.getMsgConfigBean();
         if (msgConfigBean == null) {
@@ -167,6 +168,7 @@ public class GameAppletServiceImpl extends ServiceImpl<GameAppletMapper, GameApp
         GameApplet gameApplet = super.getOne(new LambdaQueryWrapper<GameApplet>()
                 .eq(GameApplet::getAppId, appId));
         if (gameApplet == null) {
+            log.error("参数错误, 游戏小程序信息不存在, appId : {}", appId);
             throw new BaseException("参数错误, 游戏小程序信息不存在");
         }
         return BeanUtil.copy(gameApplet, GameAppletDTO.class);
@@ -192,6 +194,7 @@ public class GameAppletServiceImpl extends ServiceImpl<GameAppletMapper, GameApp
                 .gameName(game.getName())
                 .isPut(game.getIsPut())
                 .h5GameConfigDTO(Strings.isBlank(h5GameConfig) ? null : JsonUtil.toObj(h5GameConfig, H5GameConfigDTO.class))
+                .h5GameConfigMap(Strings.isBlank(h5GameConfig) ? null : JsonUtil.toMap(h5GameConfig, Map.class, Object.class))
                 .build();
     }
 }

+ 85 - 13
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/GameUserRoleServiceImpl.java

@@ -4,26 +4,28 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.zanxiang.game.module.mybatis.entity.GameUser;
-import com.zanxiang.game.module.mybatis.entity.GameUserRole;
-import com.zanxiang.game.module.mybatis.entity.User;
+import com.zanxiang.game.module.mybatis.entity.*;
 import com.zanxiang.game.module.mybatis.mapper.GameUserRoleMapper;
 import com.zanxiang.game.module.sdk.constant.RedisKeyConstant;
 import com.zanxiang.game.module.sdk.enums.DataTypeEnum;
 import com.zanxiang.game.module.sdk.enums.KafkaEventTrackEnum;
 import com.zanxiang.game.module.sdk.enums.LoginTypeEnum;
 import com.zanxiang.game.module.sdk.pojo.param.GameRoleActiveCallParam;
+import com.zanxiang.game.module.sdk.pojo.param.GameUserRoleSubmitParam;
 import com.zanxiang.game.module.sdk.pojo.param.GameUserRoleUpdateParam;
 import com.zanxiang.game.module.sdk.pojo.param.UserData;
 import com.zanxiang.game.module.sdk.service.*;
 import com.zanxiang.module.redis.service.IDistributedLockComponent;
 import com.zanxiang.module.util.JsonUtil;
+import com.zanxiang.module.util.exception.BaseException;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.client.RestTemplate;
+import reactor.util.function.Tuple2;
 
 import java.time.LocalDateTime;
 import java.util.*;
@@ -64,6 +66,56 @@ public class GameUserRoleServiceImpl extends ServiceImpl<GameUserRoleMapper, Gam
     @Autowired
     private IDistributedLockComponent distributedLockComponent;
 
+    @Autowired
+    private IGameExtService gameExtService;
+
+    @Override
+    public Boolean updateUserGameRole(GameUserRoleSubmitParam param) {
+        //查询游戏信息
+        GameExt gameExt = gameExtService.getByGameAppId(param.getGameId());
+        if (gameExt == null || Strings.isBlank(gameExt.getLoginKey())) {
+            log.error("参数错误, 游戏信息不存在, param : {}", JsonUtil.toString(param));
+            throw new BaseException("参数错误, 游戏信息不存在");
+        }
+        //根据token检验
+        UserToken userToken = userTokenService.getCheckUserToken(param.getUserId(), param.getToken());
+        if (userToken == null) {
+            log.error("参数错误, token令牌无效, param : {}", JsonUtil.toString(param));
+            throw new BaseException("参数错误, token令牌无效");
+        }
+        //验证签名
+        Tuple2<String, String> tuple2 = userTokenService.getMySign(gameExt, param.getUserId(), param.getToken());
+        if (!Objects.equals(tuple2.getT2(), param.getSign())) {
+            log.error("参数错误 , str : {}, mySign : {}, sign : {}", tuple2.getT1(), tuple2.getT2(), param.getSign());
+            throw new BaseException("参数错误, sign验证失败");
+        }
+        //提交的角色信息
+        GameUserRoleUpdateParam gameUserRoleParam = param.getGameUserRoleParam();
+        //查询玩家信息, 调用方的userId不准确, 可能是导量的小程序userId
+        User user = userService.getById(userToken.getUserId());
+        //构建 userData
+        UserData userData = new UserData();
+        userData.setUserId(user.getId());
+        userData.setGameId(user.getGameId());
+        userData.setDeviceSystem(param.getOs());
+        //判断角色是否存在
+        GameUserRole gameUserRole = super.getOne(new LambdaQueryWrapper<GameUserRole>()
+                .eq(GameUserRole::getUserId, user.getId())
+                .eq(GameUserRole::getGameId, user.getGameId())
+                .eq(GameUserRole::getRoleId, gameUserRoleParam.getRoleId()));
+        //更新游戏角色
+        if (gameUserRole != null) {
+            this.gameRoleUpdate(gameUserRoleParam, gameUserRole, userData);
+            return Boolean.TRUE;
+        }
+        //新建游戏角色
+        this.gameRoleCreate(gameUserRoleParam, userData);
+        //创建角色通知监听服务
+        this.callListenIn(gameUserRoleParam, userData);
+        //返回结果
+        return Boolean.TRUE;
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public Boolean updateUserGameRole(GameUserRoleUpdateParam param, UserData userData) {
@@ -78,7 +130,8 @@ public class GameUserRoleServiceImpl extends ServiceImpl<GameUserRoleMapper, Gam
             //新建游戏角色
             this.gameRoleCreate(param, userData);
             //插入用户登录记录
-            return userLoginLogService.createRoleLoginLog(userData, param.getRoleId(), param.getRoleName(), LoginTypeEnum.LOGIN_IN.getLoginType());
+            return userLoginLogService.createRoleLoginLog(userData, param.getRoleId(), param.getRoleName(),
+                    LoginTypeEnum.LOGIN_IN.getLoginType());
         }
         //判断角色是否存在
         GameUserRole gameUserRole = super.getOne(new LambdaQueryWrapper<GameUserRole>()
@@ -97,7 +150,8 @@ public class GameUserRoleServiceImpl extends ServiceImpl<GameUserRoleMapper, Gam
         //进入游戏
         if (Objects.equals(dataType, DataTypeEnum.TYPE_ENTER_GAME.getDateType())) {
             //插入用户登录记录
-            return userLoginLogService.createRoleLoginLog(userData, param.getRoleId(), param.getRoleName(), LoginTypeEnum.LOGIN_IN.getLoginType());
+            return userLoginLogService.createRoleLoginLog(userData, param.getRoleId(), param.getRoleName(),
+                    LoginTypeEnum.LOGIN_IN.getLoginType());
         }
         //等级提升更新
         if (Objects.equals(dataType, DataTypeEnum.TYPE_LEVEL_UP.getDateType())) {
@@ -106,16 +160,22 @@ public class GameUserRoleServiceImpl extends ServiceImpl<GameUserRoleMapper, Gam
         //退出游戏
         if (Objects.equals(dataType, DataTypeEnum.TYPE_EXIT_GAME.getDateType())) {
             //插入用户退出记录
-            return userLoginLogService.createRoleLoginLog(userData, param.getRoleId(), param.getRoleName(), LoginTypeEnum.LOGIN_OUT.getLoginType());
+            return userLoginLogService.createRoleLoginLog(userData, param.getRoleId(), param.getRoleName(),
+                    LoginTypeEnum.LOGIN_OUT.getLoginType());
         }
         return Boolean.FALSE;
     }
 
     private boolean gameRoleUpdate(GameUserRoleUpdateParam param, GameUserRole gameUserRole, UserData userData) {
         //更新频率限制, 20秒更新一次, 避免游戏实时战力高频上报
-        if (!distributedLockComponent.doLock(RedisKeyConstant.ROLE_LEVEL_UP + userData.getUserId(), 0L, 20L, TimeUnit.SECONDS)) {
+        if (!distributedLockComponent.doLock(RedisKeyConstant.ROLE_LEVEL_UP + userData.getUserId(),
+                0L, 20L, TimeUnit.SECONDS)) {
             return Boolean.TRUE;
         }
+        //玩家信息
+        GameUser gameUser = gameUserService.getOne(new LambdaQueryWrapper<GameUser>()
+                .eq(GameUser::getGameId, userData.getGameId())
+                .eq(GameUser::getUserId, userData.getUserId()));
         //玩家角色信息更新
         if (gameUserRole.getServerId() == null) {
             gameUserRole.setServerId(param.getServerId());
@@ -126,9 +186,12 @@ public class GameUserRoleServiceImpl extends ServiceImpl<GameUserRoleMapper, Gam
         if (param.getRolePower() != null) {
             gameUserRole.setRolePower(param.getRolePower());
         }
-        if (param.getExtra() != null) {
+        if (param.getExtra() != null && Strings.isNotBlank(JsonUtil.toString(param.getExtra()))) {
             gameUserRole.setExtra(JsonUtil.toString(param.getExtra()));
         }
+        if (gameUser != null) {
+            gameUserRole.setGameUserId(gameUser.getId());
+        }
         gameUserRole.setRoleName(param.getRoleName());
         gameUserRole.setRoleLevel(param.getRoleLevel());
         gameUserRole.setServerName(param.getServerName());
@@ -142,20 +205,29 @@ public class GameUserRoleServiceImpl extends ServiceImpl<GameUserRoleMapper, Gam
     private void gameRoleCreate(GameUserRoleUpdateParam param, UserData userData) {
         //查询玩家角色信息
         GameUserRole userRole = this.getOne(new LambdaQueryWrapper<GameUserRole>()
+                .eq(GameUserRole::getUserId, userData.getUserId())
                 .eq(GameUserRole::getGameId, userData.getGameId())
                 .eq(GameUserRole::getRoleId, param.getRoleId()));
         if (userRole != null) {
             return;
         }
         //上锁
-        if (!distributedLockComponent.doLock(RedisKeyConstant.ROLE_CREATE_LOCK + param.getRoleId(), 0L, 3L, TimeUnit.MINUTES)) {
+        if (!distributedLockComponent.doLock(RedisKeyConstant.ROLE_CREATE_LOCK + param.getRoleId(),
+                0L, 3L, TimeUnit.MINUTES)) {
             return;
         }
         //查询玩家信息
-        User user = userService.getById(userData.getUserId());
+        User user = userService.getOne(new LambdaQueryWrapper<User>()
+                .eq(User::getId, userData.getUserId())
+                .eq(User::getGameId, userData.getGameId()));
         GameUser gameUser = gameUserService.getOne(new LambdaQueryWrapper<GameUser>()
                 .eq(GameUser::getGameId, userData.getGameId())
                 .eq(GameUser::getUserId, userData.getUserId()));
+        //参数不匹配
+        if (user == null || gameUser == null) {
+            log.error("上报参数不匹配,玩家信息为空! param : {}, userData : {}", JsonUtil.toString(param), JsonUtil.toString(userData));
+            return;
+        }
         //创建角色
         userRole = this.transform(param, userData, gameUser, user);
         super.save(userRole);
@@ -168,7 +240,7 @@ public class GameUserRoleServiceImpl extends ServiceImpl<GameUserRoleMapper, Gam
         userService.update(new LambdaUpdateWrapper<User>()
                 .setSql("role_count=role_count+" + 1)
                 .set(User::getUpdateTime, LocalDateTime.now())
-                .eq(User::getId, gameUser.getUserId()));
+                .eq(User::getId, user.getId()));
         //用户创角回传
         callBackService.roleCallBack(userRole, userData);
         //用户创角埋点数据发送到卡夫卡
@@ -188,11 +260,11 @@ public class GameUserRoleServiceImpl extends ServiceImpl<GameUserRoleMapper, Gam
                 .roleVipLevel(param.getRoleVipLevel())
                 .rolePower(param.getRolePower())
                 .os(userData.getDeviceSystem())
-                .regTime(user == null ? null : user.getCreateTime())
+                .regTime(user.getCreateTime())
                 .createTime(LocalDateTime.now())
                 .updateTime(LocalDateTime.now())
                 .lastLoginTime(LocalDateTime.now())
-                .extra(param.getExtra() == null ? null : JsonUtil.toString(param.getExtra()))
+                .extra(param.getExtra() == null || Strings.isBlank(JsonUtil.toString(param.getExtra())) ? null : JsonUtil.toString(param.getExtra()))
                 .build();
     }
 

+ 8 - 2
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/PerformOrderServiceImpl.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.zanxiang.game.module.base.pojo.enums.CpStatusEnum;
+import com.zanxiang.game.module.base.pojo.enums.GameCategoryEnum;
 import com.zanxiang.game.module.base.util.DateUtils;
 import com.zanxiang.game.module.mybatis.entity.*;
 import com.zanxiang.game.module.sdk.enums.OrderStateEnum;
@@ -69,6 +70,9 @@ public class PerformOrderServiceImpl implements IPerformOrderService {
     @Autowired
     private IGameAppletService gameAppletService;
 
+    @Autowired
+    private IGameService gameService;
+
     @Override
     @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
     public Boolean pushCp(PlatformOrderDTO orderInfo) {
@@ -82,12 +86,14 @@ public class PerformOrderServiceImpl implements IPerformOrderService {
             log.error("充值回调CP失败, 游戏拓展信息中的回调地址为空!");
             return false;
         }
+        //游戏信息
+        Game game = gameService.getById(orderInfo.getGameId());
         //用户信息
         User user = userService.getById(orderInfo.getUserId());
         //回调CP
         Map<String, String> map = new HashMap<>(9);
-        //用户存在关联用户id, 且游戏存在导量游戏id, 判定为导量用户, 提交CP原始用户id
-        if (user.getRelationUserId() != null) {
+        //用户存在关联用户id, 且不是微信小程序, 则判定为导量用户, 提交CP原始用户id
+        if (user.getRelationUserId() != null && !Objects.equals(game.getCategory(), GameCategoryEnum.CATEGORY_WX_APPLET.getId())) {
             map.put("userId", String.valueOf(user.getRelationUserId()));
         } else {
             map.put("userId", String.valueOf(orderInfo.getUserId()));

+ 4 - 2
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/UserTokenServiceImpl.java

@@ -125,7 +125,8 @@ public class UserTokenServiceImpl extends ServiceImpl<UserTokenMapper, UserToken
         return ResultVO.ok(userId);
     }
 
-    private Tuple2<String, String> getMySign(GameExt gameExt, Long userId, String token) {
+    @Override
+    public Tuple2<String, String> getMySign(GameExt gameExt, Long userId, String token) {
         //计算用户签名
         StringBuilder sb = new StringBuilder();
         sb.append("loginKey=").append(gameExt.getLoginKey());
@@ -142,7 +143,8 @@ public class UserTokenServiceImpl extends ServiceImpl<UserTokenMapper, UserToken
         return Tuples.of(sb.toString(), mySign);
     }
 
-    private UserToken getCheckUserToken(Long userId, String token) {
+    @Override
+    public UserToken getCheckUserToken(Long userId, String token) {
         //非导量用户
         UserToken userToken = super.getOne(new LambdaQueryWrapper<UserToken>()
                 .eq(UserToken::getToken, token)

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott