Selaa lähdekoodia

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

zhangxianyu 9 kuukautta sitten
vanhempi
commit
6cbdf2e49f
100 muutettua tiedostoa jossa 4584 lisäystä ja 96 poistoa
  1. 37 0
      game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/dto/TencentAppApiUserAgentQueryRpcDTO.java
  2. 108 0
      game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/dto/TencentOrderAppApiRpcDTO.java
  3. 79 0
      game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/dto/TencentRoleRegisterAppApiRpcDTO.java
  4. 77 0
      game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/dto/TencentUserAppApiRpcDTO.java
  5. 6 0
      game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/dto/TtAppOrderBackQueryRpcDTO.java
  6. 6 0
      game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/dto/TtAppRoleRegisterBackQueryRpcDTO.java
  7. 37 0
      game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/dto/TtAppUserAgentQueryRpcDTO.java
  8. 6 0
      game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/dto/TtAppUserBackQueryRpcDTO.java
  9. 26 0
      game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/vo/OrderBackQueryRpcVO.java
  10. 23 0
      game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/rpc/ITencentAppApiBackRpc.java
  11. 2 0
      game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/rpc/ITencentAppBackRpc.java
  12. 4 1
      game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/rpc/ITtAppBackRpc.java
  13. 1 1
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/GameBackApplication.java
  14. 84 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/controller/TencentAppApiLogController.java
  15. 6 7
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/controller/api/TencentCallbackApi.java
  16. 7 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/dao/mapper/GameOceanengineAppOrderSplitLogMapper.java
  17. 7 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/dao/mapper/GameTencentAppApiBackLogMapper.java
  18. 7 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/dao/mapper/GameTencentAppApiOrderMapper.java
  19. 7 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/dao/mapper/GameTencentAppApiOrderSplitLogMapper.java
  20. 7 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/dao/mapper/GameTencentAppApiRoleRegisterMapper.java
  21. 7 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/dao/mapper/GameTencentAppApiUserMapper.java
  22. 93 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/TencentAppReport.java
  23. 1 1
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameOceanengineAppBackLog.java
  24. 4 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameOceanengineAppCallback.java
  25. 50 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameOceanengineAppOrderSplitLog.java
  26. 107 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameTencentAppApiBackLog.java
  27. 157 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameTencentAppApiOrder.java
  28. 85 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameTencentAppApiOrderSplitLog.java
  29. 113 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameTencentAppApiRoleRegister.java
  30. 113 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameTencentAppApiUser.java
  31. 4 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameTencentAppCallback.java
  32. 33 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/vo/GameTencentAppApiOrderSplitLogVO.java
  33. 210 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/rpc/impl/TencentAppApiBackRpcImpl.java
  34. 15 6
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/rpc/impl/TencentAppBackRpcImpl.java
  35. 76 25
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/rpc/impl/TtAppBackRpcImpl.java
  36. 2 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameOceanengineAppCallbackService.java
  37. 7 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameOceanengineAppOrderSplitLogService.java
  38. 7 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentAppApiBackLogService.java
  39. 18 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentAppApiOrderService.java
  40. 13 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentAppApiOrderSplitLogService.java
  41. 9 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentAppApiRoleRegisterService.java
  42. 13 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentAppApiUserService.java
  43. 2 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentAppCallbackService.java
  44. 42 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameOceanengineAppCallbackServiceImpl.java
  45. 29 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameOceanengineAppOrderLogServiceImpl.java
  46. 14 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameOceanengineAppOrderSplitLogServiceImpl.java
  47. 14 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentAppApiBackLogServiceImpl.java
  48. 456 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentAppApiOrderServiceImpl.java
  49. 49 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentAppApiOrderSplitLogServiceImpl.java
  50. 49 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentAppApiRoleRegisterServiceImpl.java
  51. 130 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentAppApiUserServiceImpl.java
  52. 32 14
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentAppCallbackServiceImpl.java
  53. 0 6
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentUserServiceImpl.java
  54. 113 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/task/TencentAppApiOrderSplitBackTask.java
  55. 3 1
      game-module/game-module-base/src/main/java/com/zanxiang/game/module/base/pojo/enums/AccountTypeEnum.java
  56. 4 0
      game-module/game-module-base/src/main/java/com/zanxiang/game/module/base/rpc/IAgentRpc.java
  57. 1 1
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/ManageApplication.java
  58. 18 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/rpc/impl/AgentRpcImpl.java
  59. 1 0
      game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/GameServerServiceImpl.java
  60. 84 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/CpPushErrorLog.java
  61. 16 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/Game.java
  62. 5 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/GameServerAssignLog.java
  63. 15 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/User.java
  64. 12 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/mapper/CpPushErrorLogMapper.java
  65. 1 1
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/SDKApplication.java
  66. 3 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/adapter/ArgumentAdapter.java
  67. 50 2
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/adapter/WebHandlerAdapter.java
  68. 14 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/annotation/PushDataCheck.java
  69. 14 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/constant/RedisKeyConstant.java
  70. 53 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/controller/CallBackController.java
  71. 53 2
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/controller/PushController.java
  72. 39 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/enums/CallBackTypeEnum.java
  73. 44 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/enums/CpPushDataEnum.java
  74. 31 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/CallBackControlParam.java
  75. 32 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/CpPushActiveParam.java
  76. 70 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/CpPushOrderParam.java
  77. 73 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/CpPushRoleParam.java
  78. 34 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/CpPushServerParam.java
  79. 62 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/CpPushUserParam.java
  80. 15 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/UserData.java
  81. 23 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/vo/CpPushResultVO.java
  82. 33 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/vo/CpPushUserVO.java
  83. 6 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/vo/UserLoginVO.java
  84. 11 2
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/ICallBackService.java
  85. 58 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/ICpPushDataService.java
  86. 32 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/ICpPushErrorLogService.java
  87. 12 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IGameServerService.java
  88. 11 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IGameService.java
  89. 12 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IGameSupperService.java
  90. 9 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IKafkaService.java
  91. 8 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IOrderService.java
  92. 9 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IUserShareService.java
  93. 5 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/AgentServiceImpl.java
  94. 240 23
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/CallBackServiceImpl.java
  95. 649 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/CpPushDataServiceImpl.java
  96. 57 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/CpPushErrorLogServiceImpl.java
  97. 18 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/GameServerServiceImpl.java
  98. 21 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/GameServiceImpl.java
  99. 18 0
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/GameSupperServiceImpl.java
  100. 1 3
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/GameUserRoleServiceImpl.java

+ 37 - 0
game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/dto/TencentAppApiUserAgentQueryRpcDTO.java

@@ -0,0 +1,37 @@
+package com.zanxiang.game.back.base.pojo.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class TencentAppApiUserAgentQueryRpcDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Long gameId;
+
+    /**
+     * 设备唯一编号IMEI
+     */
+    private String imei;
+
+    /**
+     * 设备OAID
+     */
+    private String oaid;
+
+    /**
+     * 安卓id, (仅安卓设备才有值)
+     */
+    private String androidId;
+
+    /**
+     * IOS设备IDFA
+     */
+    private String idfa;
+
+    /**
+     * IOS设备CAID
+     */
+    private String caid;
+}

+ 108 - 0
game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/dto/TencentOrderAppApiRpcDTO.java

@@ -0,0 +1,108 @@
+package com.zanxiang.game.back.base.pojo.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class TencentOrderAppApiRpcDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 回传策略ID
+     */
+    private Long backPolicyId;
+    /**
+     * sdk 里面的用户 id(要求唯一)
+     */
+    private String userId;
+    /**
+     * 游戏ID
+     */
+    private Long gameId;
+
+    /**
+     * 广告账号ID
+     */
+    private Long adAccountId;
+
+    /**
+     * 注册时间
+     */
+    private LocalDateTime registerTime;
+
+    /**
+     * 关注时间
+     */
+    private LocalDateTime subscribeTime;
+
+    /**
+     * 充值金额(分)
+     */
+    private Long rechargeMoney;
+
+    /**
+     * 充值时间
+     */
+    private LocalDateTime rechargeTime;
+
+    /**
+     * 订单ID
+     */
+    private String orderId;
+
+    /**
+     * 渠道号
+     */
+    private String channel;
+
+    /**
+     * 支付状态,0 : 预下单, 1 : 待支付,2 : 支付成功,-1 : 已取消
+     */
+    private Integer orderStatus;
+
+    /**
+     * 支付时间
+     */
+    private LocalDateTime payTime;
+
+    private String roleId;
+
+    private String roleName;
+
+    /**
+     * 用户设备mac地址
+     */
+    private String mac;
+
+    /**
+     * 设备唯一编号IMEI
+     */
+    private String imei;
+
+    /**
+     * 设备OAID
+     */
+    private String oaid;
+
+    /**
+     * 安卓id, (仅安卓设备才有值)
+     */
+    private String androidId;
+
+    /**
+     * IOS设备IDFA
+     */
+    private String idfa;
+
+    /**
+     * IOS设备CAID
+     */
+    private String caid;
+}

+ 79 - 0
game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/dto/TencentRoleRegisterAppApiRpcDTO.java

@@ -0,0 +1,79 @@
+package com.zanxiang.game.back.base.pojo.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class TencentRoleRegisterAppApiRpcDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+
+    /**
+     * 回传策略ID
+     */
+    private Long backPolicyId;
+    /**
+     * sdk 里面的用户 id(要求唯一)
+     */
+    private String userId;
+    /**
+     * 游戏ID
+     */
+    private Long gameId;
+
+    /**
+     * 广告账号ID
+     */
+    private Long adAccountId;
+    /**
+     * 注册时间
+     */
+    private LocalDateTime registerTime;
+
+    /**
+     * 渠道号
+     */
+    private String channel;
+
+    private String roleId;
+
+    private String roleName;
+
+    /**
+     * 用户设备mac地址
+     */
+    private String mac;
+
+    /**
+     * 设备唯一编号IMEI
+     */
+    private String imei;
+
+    /**
+     * 设备OAID
+     */
+    private String oaid;
+
+    /**
+     * 安卓id, (仅安卓设备才有值)
+     */
+    private String androidId;
+
+    /**
+     * IOS设备IDFA
+     */
+    private String idfa;
+
+    /**
+     * IOS设备CAID
+     */
+    private String caid;
+}

+ 77 - 0
game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/dto/TencentUserAppApiRpcDTO.java

@@ -0,0 +1,77 @@
+package com.zanxiang.game.back.base.pojo.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class TencentUserAppApiRpcDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 回传策略ID
+     */
+    private Long backPolicyId;
+    /**
+     * sdk 里面的用户 id(要求唯一)
+     */
+    private String userId;
+    /**
+     * 游戏ID
+     */
+    private Long gameId;
+
+    /**
+     * 广告账号ID
+     */
+    private Long adAccountId;
+    /**
+     * 注册时间
+     */
+    private LocalDateTime registerTime;
+
+    /**
+     * 关注时间
+     */
+    private LocalDateTime subscribeTime;
+
+    /**
+     * 渠道号
+     */
+    private String channel;
+    /**
+     * 用户设备mac地址
+     */
+    private String mac;
+
+    /**
+     * 设备唯一编号IMEI
+     */
+    private String imei;
+
+    /**
+     * 设备OAID
+     */
+    private String oaid;
+
+    /**
+     * 安卓id, (仅安卓设备才有值)
+     */
+    private String androidId;
+
+    /**
+     * IOS设备IDFA
+     */
+    private String idfa;
+
+    /**
+     * IOS设备CAID
+     */
+    private String caid;
+}

+ 6 - 0
game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/dto/TtAppOrderBackQueryRpcDTO.java

@@ -1,6 +1,9 @@
 package com.zanxiang.game.back.base.pojo.dto;
 
+import lombok.AllArgsConstructor;
+import lombok.Builder;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 
 import java.io.Serializable;
 
@@ -8,6 +11,9 @@ import java.io.Serializable;
  * 创角是否回传
  */
 @Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
 public class TtAppOrderBackQueryRpcDTO implements Serializable {
     private static final long serialVersionUID = 1L;
     /**

+ 6 - 0
game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/dto/TtAppRoleRegisterBackQueryRpcDTO.java

@@ -1,6 +1,9 @@
 package com.zanxiang.game.back.base.pojo.dto;
 
+import lombok.AllArgsConstructor;
+import lombok.Builder;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 
 import java.io.Serializable;
 
@@ -8,6 +11,9 @@ import java.io.Serializable;
  * 创角是否回传
  */
 @Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
 public class TtAppRoleRegisterBackQueryRpcDTO implements Serializable {
     private static final long serialVersionUID = 1L;
 

+ 37 - 0
game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/dto/TtAppUserAgentQueryRpcDTO.java

@@ -0,0 +1,37 @@
+package com.zanxiang.game.back.base.pojo.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class TtAppUserAgentQueryRpcDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Long gameId;
+
+    /**
+     * 设备唯一编号IMEI
+     */
+    private String imei;
+
+    /**
+     * 设备OAID
+     */
+    private String oaid;
+
+    /**
+     * 安卓id, (仅安卓设备才有值)
+     */
+    private String androidId;
+
+    /**
+     * IOS设备IDFA
+     */
+    private String idfa;
+
+    /**
+     * IOS设备CAID
+     */
+    private String caid;
+}

+ 6 - 0
game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/dto/TtAppUserBackQueryRpcDTO.java

@@ -1,6 +1,9 @@
 package com.zanxiang.game.back.base.pojo.dto;
 
+import lombok.AllArgsConstructor;
+import lombok.Builder;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 
 import java.io.Serializable;
 
@@ -8,6 +11,9 @@ import java.io.Serializable;
  * 创角是否回传
  */
 @Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
 public class TtAppUserBackQueryRpcDTO implements Serializable {
     private static final long serialVersionUID = 1L;
     /**

+ 26 - 0
game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/vo/OrderBackQueryRpcVO.java

@@ -0,0 +1,26 @@
+package com.zanxiang.game.back.base.pojo.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class OrderBackQueryRpcVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Boolean doBack;
+
+    private List<Long> backMoney;
+
+    /**
+     * 回传信息
+     */
+    private String backMsg;
+}

+ 23 - 0
game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/rpc/ITencentAppApiBackRpc.java

@@ -0,0 +1,23 @@
+package com.zanxiang.game.back.base.rpc;
+
+import com.zanxiang.game.back.base.pojo.dto.*;
+import com.zanxiang.module.util.pojo.ResultVO;
+
+/**
+ * 腾讯数据源回传
+ */
+public interface ITencentAppApiBackRpc {
+    /**
+     * 订单回传
+     */
+    ResultVO<Boolean> backOrder(TencentOrderAppApiRpcDTO dto);
+
+    /**
+     * 用户回传
+     */
+    ResultVO<Boolean> backUser(TencentUserAppApiRpcDTO dto);
+
+    ResultVO<Boolean> backRoleRegister(TencentRoleRegisterAppApiRpcDTO dto);
+
+    ResultVO<String> queryUserAgentFromCallback(TencentAppApiUserAgentQueryRpcDTO dto);
+}

+ 2 - 0
game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/rpc/ITencentAppBackRpc.java

@@ -18,4 +18,6 @@ public interface ITencentAppBackRpc {
     ResultVO<Boolean> backUser(TencentUserAppRpcDTO dto);
 
     ResultVO<Boolean> backRoleRegister(TencentRoleRegisterAppRpcDTO dto);
+
+    ResultVO<String> queryUserAgentFromCallback(TencentAppApiUserAgentQueryRpcDTO dto);
 }

+ 4 - 1
game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/rpc/ITtAppBackRpc.java

@@ -1,6 +1,7 @@
 package com.zanxiang.game.back.base.rpc;
 
 import com.zanxiang.game.back.base.pojo.dto.*;
+import com.zanxiang.game.back.base.pojo.vo.OrderBackQueryRpcVO;
 import com.zanxiang.module.util.pojo.ResultVO;
 
 /**
@@ -34,10 +35,12 @@ public interface ITtAppBackRpc {
     /**
      * 订单是否回传
      */
-    ResultVO<Boolean> orderBackQuery(TtAppOrderBackQueryRpcDTO dto);
+    ResultVO<OrderBackQueryRpcVO> orderBackQuery(TtAppOrderBackQueryRpcDTO dto);
 
     /**
      * 创角是否回传
      */
     ResultVO<Boolean> roleRegisterBackQuery(TtAppRoleRegisterBackQueryRpcDTO dto);
+
+    ResultVO<String> queryUserAgentFromCallback(TtAppUserAgentQueryRpcDTO dto);
 }

+ 1 - 1
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/GameBackApplication.java

@@ -18,7 +18,7 @@ public class GameBackApplication {
 
     public static void main(String[] args) {
         SpringApplication.run(GameBackApplication.class, args);
-        System.out.println("游戏回传服务启动成功, 腾讯小程序注册时间回传修改 ( ´・・)ノ(._.`)  \n" +
+        System.out.println("游戏回传服务启动成功, 修改头条APP回传的问题 ( ´・・)ノ(._.`)  \n" +
                 " ______  __     __     \n" +
                 "/_____/\\/__/\\ /__/\\    \n" +
                 "\\:::__\\/\\ \\::\\\\:.\\ \\   \n" +

+ 84 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/controller/TencentAppApiLogController.java

@@ -0,0 +1,84 @@
+package com.zanxiang.game.back.serve.controller;
+
+import com.zanxiang.erp.security.annotation.PreAuthorize;
+import com.zanxiang.game.back.serve.pojo.dto.OrderReportDTO;
+import com.zanxiang.game.back.serve.pojo.vo.GameTencentAppApiOrderSplitLogVO;
+import com.zanxiang.game.back.serve.service.*;
+import com.zanxiang.module.util.exception.BaseException;
+import com.zanxiang.module.util.pojo.ResultVO;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.math.BigDecimal;
+import java.util.Collections;
+import java.util.List;
+
+@RestController
+@RequestMapping("/tencentAppApi")
+@Api("腾讯APP API 回传")
+public class TencentAppApiLogController {
+    @Autowired
+    private IGameTencentAppApiUserService gameTencentAppApiUserService;
+    @Autowired
+    private IGameTencentAppApiOrderService gameTencentAppApiOrderService;
+    @Autowired
+    private IGameTencentAppApiOrderSplitLogService gameTencentAppApiOrderSplitLogService;
+
+
+    @PreAuthorize(permissionKey = "gameBack:tencentAppApi:orderSplits")
+    @GetMapping("/orderSplitList/{orderId}")
+    public ResultVO<List<GameTencentAppApiOrderSplitLogVO>> orderSplitList(@PathVariable("orderId") String orderId) {
+        return ResultVO.ok(gameTencentAppApiOrderSplitLogService.listByOrderNo(Collections.singletonList(orderId)));
+    }
+
+    @PreAuthorize(permissionKey = "gameBack:tencentAppApi:orderReport")
+    @PostMapping("/orderReport/{ids}/{backMoney}")
+    @ApiOperation(value = "腾讯订单手动上报")
+    public ResultVO<Boolean> tencentOrderReport(@PathVariable("ids") List<Long> ids, @PathVariable("backMoney") BigDecimal backMoney) {
+        OrderReportDTO dto = new OrderReportDTO();
+        dto.setOrderIds(ids);
+        dto.setSplitOrder(false);
+        dto.setBackMoney(backMoney);
+        return tencentOrderReport(dto);
+    }
+
+    @PreAuthorize(permissionKey = "gameBack:tencentAppApi:orderReport")
+    @PostMapping("/orderReport")
+    @ApiOperation(value = "腾讯订单手动上报")
+    public ResultVO<Boolean> tencentOrderReport(@Validated @RequestBody OrderReportDTO dto) {
+        if (CollectionUtils.isEmpty(dto.getOrderIds())) {
+            throw new BaseException("参数错误!");
+        }
+        if (dto.getSplitOrder()) {
+            if (CollectionUtils.isEmpty(dto.getSplitMoney())) {
+                throw new BaseException("回传金额错误!");
+            }
+            dto.getSplitMoney().forEach(backMoney -> {
+                if (backMoney.compareTo(BigDecimal.ZERO) <= 0) {
+                    throw new BaseException("回传金额错误!");
+                }
+            });
+            if (dto.getBetweenMinuteMin() == null || dto.getBetweenMinuteMax() == null
+                    || dto.getBetweenMinuteMin() < 1 || dto.getBetweenMinuteMax() < 1
+                    || dto.getBetweenMinuteMin().compareTo(dto.getBetweenMinuteMax()) >= 0) {
+                throw new BaseException("回传间隔时间错误!");
+            }
+        } else {
+            if (dto.getBackMoney().compareTo(BigDecimal.ZERO) <= 0) {
+                throw new BaseException("回传金额错误!");
+            }
+        }
+        return ResultVO.ok(gameTencentAppApiOrderService.tencentOrderReport(dto));
+    }
+
+    @PreAuthorize(permissionKey = "gameBack:tencentAppApi:userReport")
+    @PostMapping("/userReport/{ids}")
+    @ApiOperation(value = "腾讯用户手动上报")
+    public ResultVO<Boolean> tencentUserReport(@PathVariable("ids") List<Long> ids) {
+        return ResultVO.ok(gameTencentAppApiUserService.tencentUserReport(ids));
+    }
+}

+ 6 - 7
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/controller/api/TencentCallbackApi.java

@@ -21,13 +21,12 @@ public class TencentCallbackApi {
     private IGameTencentAppCallbackService gameTencentAppCallbackService;
 
     // https://api.zanxiangwl.com/gameBack/api/tencentCallback/callback
-    // ?click_id=__CLICK_ID__&click_time=__CLICK_TIME__&impressionTime=__IMPRESSION_TIME__&adgroup_id=__ADGROUP_ID__
-    // &dynamicCreativeId=__DYNAMIC_CREATIVE_ID__&marketing_asset_id=__MARKETING_ASSET_ID__&material_package_id=__MATERIAL_PACKAGE_ID__
-    // &ad_platform_type=__AD_PLATFORM_TYPE__&account_id=__ACCOUNT_ID__&agency_id=__AGENCY_ID__&click_sku_id=__CLICK_SKU_ID__&device_os_type=__DEVICE_OS_TYPE__
-    // &process_time=__PROCESS_TIME__&promotedObjectId=__PROMOTED_OBJECT_ID__&request_id=__REQUEST_ID__&impressionId=__IMPRESSION_ID__&muid=__MUID__
-    // &hash_android_id=__HASH_ANDROID_ID__&ip=__IP__&userAgent=__USER_AGENT__&callback=__CALLBACK__&encryptedPositionId=__ENCRYPTED_POSITION_ID__
-    // &ipv6=__IPV6__&hash_oaid=__HASH_OAID__&&caid=__QAID_CAA__&model=__MODEL__&ipMd5=__IP_MD5__&ipv6Md5=__IPV6_MD5__
-    // &channelPackageId=__CHANNEL_PACKAGE_ID__&deviceOsVersion=__DEVICE_OS_VERSION__
+    // ?clickId=__CLICK_ID__&clickTime=__CLICK_TIME__&adgroupId=__ADGROUP_ID__&dynamicCreativeId=__DYNAMIC_CREATIVE_ID__
+    // &marketingAssetId=__MARKETING_ASSET_ID__&materialPackageId=__MATERIAL_PACKAGE_ID__&adPlatformType=__AD_PLATFORM_TYPE__
+    // &accountId=__ACCOUNT_ID__&agencyId=__AGENCY_ID__&clickSkuId=__CLICK_SKU_ID__&deviceOsType=__DEVICE_OS_TYPE__
+    // &processTime=__PROCESS_TIME__&requestId=__REQUEST_ID__&impressionId=__IMPRESSION_ID__&muid=__MUID__
+    // &hashAndroidId=__HASH_ANDROID_ID__&ip=__IP__&userAgent=__USER_AGENT__&callback=__CALLBACK__
+    // &encryptedPositionId=__ENCRYPTED_POSITION_ID__&ipv6=__IPV6__&hashOaid=__HASH_OAID__&&caid=__QAID_CAA__&ipMd5=__IP_MD5__&ipv6Md5=__IPV6_MD5__
     @GetMapping("/callback")
     public ResultVO<Boolean> callback(GameTencentAppCallbackDTO dto) {
         log.info("腾讯监测链接:{}", JsonUtil.toString(dto));

+ 7 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/dao/mapper/GameOceanengineAppOrderSplitLogMapper.java

@@ -0,0 +1,7 @@
+package com.zanxiang.game.back.serve.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zanxiang.game.back.serve.pojo.entity.GameOceanengineAppOrderSplitLog;
+
+public interface GameOceanengineAppOrderSplitLogMapper extends BaseMapper<GameOceanengineAppOrderSplitLog> {
+}

+ 7 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/dao/mapper/GameTencentAppApiBackLogMapper.java

@@ -0,0 +1,7 @@
+package com.zanxiang.game.back.serve.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppApiBackLog;
+
+public interface GameTencentAppApiBackLogMapper extends BaseMapper<GameTencentAppApiBackLog> {
+}

+ 7 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/dao/mapper/GameTencentAppApiOrderMapper.java

@@ -0,0 +1,7 @@
+package com.zanxiang.game.back.serve.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppApiOrder;
+
+public interface GameTencentAppApiOrderMapper extends BaseMapper<GameTencentAppApiOrder> {
+}

+ 7 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/dao/mapper/GameTencentAppApiOrderSplitLogMapper.java

@@ -0,0 +1,7 @@
+package com.zanxiang.game.back.serve.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppApiOrderSplitLog;
+
+public interface GameTencentAppApiOrderSplitLogMapper extends BaseMapper<GameTencentAppApiOrderSplitLog> {
+}

+ 7 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/dao/mapper/GameTencentAppApiRoleRegisterMapper.java

@@ -0,0 +1,7 @@
+package com.zanxiang.game.back.serve.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppApiRoleRegister;
+
+public interface GameTencentAppApiRoleRegisterMapper extends BaseMapper<GameTencentAppApiRoleRegister> {
+}

+ 7 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/dao/mapper/GameTencentAppApiUserMapper.java

@@ -0,0 +1,7 @@
+package com.zanxiang.game.back.serve.dao.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppApiUser;
+
+public interface GameTencentAppApiUserMapper extends BaseMapper<GameTencentAppApiUser> {
+}

+ 93 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/TencentAppReport.java

@@ -0,0 +1,93 @@
+package com.zanxiang.game.back.serve.pojo;
+
+import com.zanxiang.advertising.tencent.base.pojo.dto.UserActionRpcDTO;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 腾讯 APP 回传 API
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class TencentAppReport implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private List<Action> actions;
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @Builder
+    public static class Action implements Serializable {
+        private static final long serialVersionUID = 1L;
+        /**
+         * 选填,若上报可能有重复请填写该id,系统会根据该ID进行去重,详见FAQ
+         */
+        private String outer_action_id;
+        /**
+         * 转化发生时间(单位 秒)
+         */
+        private Long action_time;
+
+        private UserId userr_id;
+
+        private String action_type;
+
+        private String trace;
+
+        private Map<String, Object> action_param;
+    }
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @Builder
+    public static class UserId implements Serializable {
+        private static final long serialVersionUID = 1L;
+        /**
+         * Android能获取到时必填,IMEI小写进行MD5编码,字段长度为32字节
+         */
+        private String hash_imei;
+        /**
+         * Android能获取到时必填,OAID原值进行MD5编码,字段长度为32字节
+         */
+        private String hash_oaid;
+        /**
+         * Android能获取到时必填,Android ID原值进行MD5编码,字段长度为32字节
+         */
+        private String hash_android_id;
+        /**
+         * iOS能获取到时必填,IDFA大写进行MD5编码,字段长度为32字节
+         */
+        private String hash_idfa;
+
+        /**
+         * 中国广告协会互联网广告标(CAA Advertising id);iOS能获取到时必填,建议上报最新的 caid 版本
+         */
+        private String caid;
+        /**
+         * iOS能获取到时必填,上报 CAID 时 caid_version 为必填项,建议上报最新的 CAID 版本。
+         * CAID版本对应关系:
+         * ○腾讯版本1004 对应 中广协版本20211207
+         * ○腾讯版本1005 对应 中广协版本20220111
+         */
+        private String caid_version;
+        /**
+         * IP地址原文,能获取到时强烈建议填写,支持IPV4和IPV6
+         */
+        private String ip;
+        /**
+         * User Agent原文,能获取到时强烈建议填写,支持IPV4和IPV6
+         */
+        private String user_agent;
+
+    }
+}

+ 1 - 1
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameOceanengineAppBackLog.java

@@ -18,7 +18,7 @@ import java.time.LocalDateTime;
 @NoArgsConstructor
 @AllArgsConstructor
 @Builder
-@TableName("t_game_ocenaengine_app_back_log")
+@TableName("t_game_oceanengine_app_back_log")
 public class GameOceanengineAppBackLog implements Serializable {
     private static final long serialVersionUID = 1L;
 

+ 4 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameOceanengineAppCallback.java

@@ -30,6 +30,10 @@ public class GameOceanengineAppCallback implements Serializable {
     @TableId(value = "id", type = IdType.AUTO)
     private Long id;
 
+    private String agentKey;
+
+    private Long gameId;
+
     /**
      * 时间发生日期
      */

+ 50 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameOceanengineAppOrderSplitLog.java

@@ -0,0 +1,50 @@
+package com.zanxiang.game.back.serve.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * 拆单回传
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@TableName("t_game_oceanengine_app_order_split_log")
+public class GameOceanengineAppOrderSplitLog implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    private LocalDate backDay;
+
+    private String orderNo;
+
+    private Integer backIndex;
+
+    private Integer backCount;
+
+    private Long splitMoney;
+
+    private LocalDateTime backTime;
+
+    private LocalDateTime executeTime;
+
+    private Integer backStatus;
+
+    private String backErrorMsg;
+
+    private LocalDateTime createTime;
+
+
+}

+ 107 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameTencentAppApiBackLog.java

@@ -0,0 +1,107 @@
+package com.zanxiang.game.back.serve.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 腾讯 APP回传日志表
+ * </p>
+ *
+ * @author wcc
+ * @since 2024-06-28
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@TableName(GameTencentAppApiBackLog.TABLE_NAME)
+public class GameTencentAppApiBackLog implements Serializable {
+    private static final long serialVersionUID = 1L;
+    public static final String TABLE_NAME = "t_game_tencent_app_api_back_log";
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    private String userId;
+
+    /**
+     * 游戏id
+     */
+    private Long gameId;
+
+    /**
+     * 广告账号ID
+     */
+    private Long adAccountId;
+
+    /**
+     * 行为发生时,客户端的时间点
+     */
+    private LocalDateTime actionTime;
+
+    /**
+     * 用户设备mac地址
+     */
+    private String mac;
+
+    /**
+     * 设备唯一编号IMEI
+     */
+    private String imei;
+
+    /**
+     * 设备OAID
+     */
+    private String oaid;
+
+    /**
+     * 安卓id, (仅安卓设备才有值)
+     */
+    private String androidId;
+
+    /**
+     * IOS设备IDFA
+     */
+    private String idfa;
+
+    /**
+     * IOS设备CAID
+     */
+    private String caid;
+
+    /**
+     * 行为类型:(REGISTER/PURCHASE/COMPLETE_ORDER)
+     */
+    private String actionType;
+
+    /**
+     * 订单ID
+     */
+    private String orderId;
+
+    /**
+     * 回传时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 回传日志
+     */
+    private String backLog;
+
+    /**
+     * 行为参数
+     */
+    private String actionParam;
+
+
+}

+ 157 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameTencentAppApiOrder.java

@@ -0,0 +1,157 @@
+package com.zanxiang.game.back.serve.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 游戏腾讯APP订单表
+ * </p>
+ *
+ * @author wcc
+ * @since 2024-06-28
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@TableName(GameTencentAppApiOrder.TABLE_NAME)
+public class GameTencentAppApiOrder implements Serializable {
+    private static final long serialVersionUID = 1L;
+    public static final String TABLE_NAME = "t_game_tencent_app_api_order";
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    private String userId;
+
+    /**
+     * 渠道号
+     */
+    private String channel;
+
+    /**
+     * 游戏ID
+     */
+    private Long gameId;
+
+    /**
+     * 广告账号ID
+     */
+    private Long adAccountId;
+
+    /**
+     * 注册时间
+     */
+    private LocalDateTime registerTime;
+
+    /**
+     * 关注时间
+     */
+    private LocalDateTime subscribeTime;
+
+    /**
+     * 充值金额(分)
+     */
+    private Long rechargeMoney;
+
+    /**
+     * 充值时间
+     */
+    private LocalDateTime rechargeTime;
+
+    /**
+     * 订单ID
+     */
+    private String orderId;
+
+    /**
+     * 用户设备mac地址
+     */
+    private String mac;
+
+    /**
+     * 设备唯一编号IMEI
+     */
+    private String imei;
+
+    /**
+     * 设备OAID
+     */
+    private String oaid;
+
+    /**
+     * 安卓id, (仅安卓设备才有值)
+     */
+    private String androidId;
+
+    /**
+     * IOS设备IDFA
+     */
+    private String idfa;
+
+    /**
+     * IOS设备CAID
+     */
+    private String caid;
+
+    /**
+     * 支付状态,0 : 预下单, 1 : 待支付,2 : 支付成功,-1 : 已取消
+     */
+    private Integer orderStatus;
+
+    /**
+     * 支付时间
+     */
+    private LocalDateTime payTime;
+
+    /**
+     * 0:未回传;1:回传
+     */
+    private Integer isBack;
+
+    private LocalDateTime createTime;
+
+    private LocalDateTime updateTime;
+
+    private Long updateBy;
+
+    /**
+     * 回传日志
+     */
+    private String backLog;
+
+    /**
+     * 回传策略id
+     */
+    private Long backPolicyId;
+
+    private String roleId;
+
+    private String roleName;
+
+    /**
+     * 是否是首单
+     */
+    private Boolean isFirstOrder;
+
+    /**
+     * 回传金额
+     */
+    private Long backMoney;
+
+    /**
+     * 回传信息
+     */
+    private String backMsg;
+
+
+}

+ 85 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameTencentAppApiOrderSplitLog.java

@@ -0,0 +1,85 @@
+package com.zanxiang.game.back.serve.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author wcc
+ * @since 2024-06-28
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@TableName(GameTencentAppApiOrderSplitLog.TABLE_NAME)
+public class GameTencentAppApiOrderSplitLog implements Serializable {
+    private static final long serialVersionUID = 1L;
+    public static final String TABLE_NAME = "t_game_tencent_app_api_order_split_log";
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    private String userId;
+
+    /**
+     * 回传日期
+     */
+    private LocalDate backDay;
+
+    /**
+     * 订单编号
+     */
+    private String orderNo;
+
+    /**
+     * 回传序号
+     */
+    private Integer backIndex;
+
+    /**
+     * 总计拆成几单
+     */
+    private Integer backCount;
+
+    /**
+     * 拆分的回传金额
+     */
+    private Long splitMoney;
+
+    /**
+     * 回传时间
+     */
+    private LocalDateTime backTime;
+
+    /**
+     * 真实的回传时间
+     */
+    private LocalDateTime executeTime;
+
+    /**
+     * 回传状态
+     */
+    private Integer backStatus;
+
+    private LocalDateTime createTime;
+
+    /**
+     * 回传失败消息
+     */
+    private String backErrorMsg;
+
+
+}

+ 113 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameTencentAppApiRoleRegister.java

@@ -0,0 +1,113 @@
+package com.zanxiang.game.back.serve.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 游戏腾讯APP角色创建表
+ * </p>
+ *
+ * @author wcc
+ * @since 2024-06-28
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@TableName(GameTencentAppApiRoleRegister.TABLE_NAME)
+public class GameTencentAppApiRoleRegister implements Serializable {
+    private static final long serialVersionUID = 1L;
+    public static final String TABLE_NAME = "t_game_tencent_app_api_role_register";
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    private String userId;
+
+    /**
+     * 渠道号
+     */
+    private String channel;
+
+    /**
+     * 游戏ID
+     */
+    private Long gameId;
+
+    /**
+     * 广告账号ID
+     */
+    private Long adAccountId;
+
+    /**
+     * 注册时间
+     */
+    private LocalDateTime registerTime;
+
+    /**
+     * 用户设备mac地址
+     */
+    private String mac;
+
+    /**
+     * 设备唯一编号IMEI
+     */
+    private String imei;
+
+    /**
+     * 设备OAID
+     */
+    private String oaid;
+
+    /**
+     * 安卓id, (仅安卓设备才有值)
+     */
+    private String androidId;
+
+    /**
+     * IOS设备IDFA
+     */
+    private String idfa;
+
+    /**
+     * IOS设备CAID
+     */
+    private String caid;
+
+    /**
+     * 0:未回传;1:回传
+     */
+    private Integer isBack;
+
+    private LocalDateTime createTime;
+
+    /**
+     * 回传日志
+     */
+    private String backLog;
+
+    /**
+     * 回传策略id
+     */
+    private Long backPolicyId;
+
+    private String roleId;
+
+    private String roleName;
+
+    /**
+     * 回传信息
+     */
+    private String backMsg;
+
+
+}

+ 113 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameTencentAppApiUser.java

@@ -0,0 +1,113 @@
+package com.zanxiang.game.back.serve.pojo.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 游戏腾讯 APP用户表
+ * </p>
+ *
+ * @author wcc
+ * @since 2024-06-28
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@TableName(GameTencentAppApiUser.TABLE_NAME)
+public class GameTencentAppApiUser implements Serializable {
+    private static final long serialVersionUID = 1L;
+    public static final String TABLE_NAME = "t_game_tencent_app_api_user";
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    private String userId;
+
+    /**
+     * 渠道号
+     */
+    private String channel;
+
+    /**
+     * 游戏ID
+     */
+    private Long gameId;
+
+    /**
+     * 广告账号ID
+     */
+    private Long adAccountId;
+
+    /**
+     * 注册时间
+     */
+    private LocalDateTime registerTime;
+
+    /**
+     * 关注时间
+     */
+    private LocalDateTime subscribeTime;
+
+    /**
+     * 用户设备mac地址
+     */
+    private String mac;
+
+    /**
+     * 设备唯一编号IMEI
+     */
+    private String imei;
+
+    /**
+     * 设备OAID
+     */
+    private String oaid;
+
+    /**
+     * 安卓id, (仅安卓设备才有值)
+     */
+    private String androidId;
+
+    /**
+     * IOS设备IDFA
+     */
+    private String idfa;
+
+    /**
+     * IOS设备CAID
+     */
+    private String caid;
+
+    /**
+     * 0:未回传;1:回传;-1:回传失败
+     */
+    private Integer isBack;
+
+    private LocalDateTime createTime;
+
+    private LocalDateTime updateTime;
+
+    private Long updateBy;
+
+    /**
+     * 回传日志
+     */
+    private String backLog;
+
+    /**
+     * 回传策略id
+     */
+    private Long backPolicyId;
+
+
+}

+ 4 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameTencentAppCallback.java

@@ -30,6 +30,10 @@ public class GameTencentAppCallback implements Serializable {
     @TableId(value = "id", type = IdType.AUTO)
     private Long id;
 
+    private String agentKey;
+
+    private Long gameId;
+
     /**
      * 时间发生日期
      */

+ 33 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/vo/GameTencentAppApiOrderSplitLogVO.java

@@ -0,0 +1,33 @@
+package com.zanxiang.game.back.serve.pojo.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+@Data
+public class GameTencentAppApiOrderSplitLogVO {
+    
+    private Long id;
+
+    private LocalDate backDay;
+
+    private String orderNo;
+
+    private Integer backIndex;
+
+    private Integer backCount;
+
+    private BigDecimal splitMoney;
+
+    private LocalDateTime backTime;
+
+    private LocalDateTime executeTime;
+
+    private Integer backStatus;
+
+    private String backErrorMsg;
+
+    private LocalDateTime createTime;
+}

+ 210 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/rpc/impl/TencentAppApiBackRpcImpl.java

@@ -0,0 +1,210 @@
+package com.zanxiang.game.back.serve.rpc.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.zanxiang.game.back.base.pojo.dto.*;
+import com.zanxiang.game.back.base.pojo.enums.OrderStatusEnum;
+import com.zanxiang.game.back.base.rpc.ITencentAppApiBackRpc;
+import com.zanxiang.game.back.base.rpc.ITencentAppBackRpc;
+import com.zanxiang.game.back.serve.pojo.entity.*;
+import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
+import com.zanxiang.game.back.serve.service.*;
+import com.zanxiang.module.util.JsonUtil;
+import com.zanxiang.module.util.encryption.Md5Util;
+import com.zanxiang.module.util.pojo.ResultVO;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.time.LocalDateTime;
+import java.util.Objects;
+
+@Slf4j
+@DubboService
+public class TencentAppApiBackRpcImpl implements ITencentAppApiBackRpc {
+    @Autowired
+    private IGameTencentAppApiUserService gameTencentAppApiUserService;
+    @Autowired
+    private IGameTencentAppApiRoleRegisterService gameTencentAppApiRoleRegisterService;
+    @Autowired
+    private IGameTencentAppApiOrderService gameTencentAppApiOrderService;
+    @Autowired
+    private IGameTencentAppCallbackService gameTencentAppCallbackService;
+
+    @Override
+    public ResultVO<Boolean> backUser(TencentUserAppApiRpcDTO dto) {
+        log.error("腾讯 APP-API 用户回传收到:{}", JsonUtil.toString(dto));
+        if (StringUtils.isBlank(dto.getMac())) {
+            dto.setMac("");
+        }
+        if(StringUtils.isBlank(dto.getImei())) {
+            dto.setImei("");
+        }
+        if(StringUtils.isBlank(dto.getOaid())) {
+            dto.setOaid("");
+        }
+        if(StringUtils.isBlank(dto.getAndroidId())) {
+            dto.setAndroidId("");
+        }
+        if(StringUtils.isBlank(dto.getIdfa())) {
+            dto.setIdfa("");
+        }
+        if(StringUtils.isBlank(dto.getCaid())) {
+            dto.setCaid("");
+        }
+        if(StringUtils.isBlank(dto.getImei())
+                && StringUtils.isBlank(dto.getOaid())
+                && StringUtils.isBlank(dto.getAndroidId())
+                && StringUtils.isBlank(dto.getIdfa())
+                && StringUtils.isBlank(dto.getCaid())) {
+            return ResultVO.fail("找不到用户唯一标识");
+        }
+        GameTencentAppApiUser gameTencentUser = GameTencentAppApiUser.builder()
+                .userId(dto.getUserId())
+                .adAccountId(dto.getAdAccountId())
+                .gameId(dto.getGameId())
+                .channel(dto.getChannel())
+                .subscribeTime(dto.getSubscribeTime())
+                .registerTime(dto.getRegisterTime())
+                .mac(dto.getMac())
+                .imei(dto.getImei())
+                .oaid(dto.getOaid())
+                .androidId(dto.getAndroidId())
+                .idfa(dto.getIdfa())
+                .caid(dto.getCaid())
+                .isBack(BackStatusEnum.NO.getBackStatus())
+                .createTime(LocalDateTime.now())
+                .build();
+        gameTencentAppApiUserService.save(gameTencentUser);
+        return ResultVO.ok(true);
+        // 激活现在默认不回传了,等创角的时候一起回传
+        // return ResultVO.ok(gameTencentAppApiUserService.userBack(gameTencentUser, false));
+    }
+
+    @Override
+    public ResultVO<Boolean> backRoleRegister(TencentRoleRegisterAppApiRpcDTO dto) {
+        log.error("腾讯 APP创角回传收到:{}", JsonUtil.toString(dto));
+        if (StringUtils.isBlank(dto.getMac())) {
+            dto.setMac("");
+        }
+        if(StringUtils.isBlank(dto.getImei())) {
+            dto.setImei("");
+        }
+        if(StringUtils.isBlank(dto.getOaid())) {
+            dto.setOaid("");
+        }
+        if(StringUtils.isBlank(dto.getAndroidId())) {
+            dto.setAndroidId("");
+        }
+        if(StringUtils.isBlank(dto.getIdfa())) {
+            dto.setIdfa("");
+        }
+        if(StringUtils.isBlank(dto.getCaid())) {
+            dto.setCaid("");
+        }
+        if(StringUtils.isBlank(dto.getImei())
+                && StringUtils.isBlank(dto.getOaid())
+                && StringUtils.isBlank(dto.getAndroidId())
+                && StringUtils.isBlank(dto.getIdfa())
+                && StringUtils.isBlank(dto.getCaid())) {
+            return ResultVO.fail("找不到用户唯一标识");
+        }
+        GameTencentAppApiRoleRegister roleRegister = GameTencentAppApiRoleRegister.builder()
+                .userId(dto.getUserId())
+                .backPolicyId(dto.getBackPolicyId())
+                .channel(dto.getChannel())
+                .gameId(dto.getGameId())
+                .adAccountId(dto.getAdAccountId())
+                .registerTime(dto.getRegisterTime())
+                .mac(dto.getMac())
+                .imei(dto.getImei())
+                .oaid(dto.getOaid())
+                .androidId(dto.getAndroidId())
+                .idfa(dto.getIdfa())
+                .caid(dto.getCaid())
+                .isBack(BackStatusEnum.NO.getBackStatus())
+                .createTime(LocalDateTime.now())
+                .roleId(dto.getRoleId())
+                .roleName(dto.getRoleName())
+                .build();
+        gameTencentAppApiRoleRegisterService.save(roleRegister);
+        return ResultVO.ok(gameTencentAppApiRoleRegisterService.roleRegisterBack(roleRegister));
+    }
+
+    @Override
+    public ResultVO<Boolean> backOrder(TencentOrderAppApiRpcDTO dto) {
+        if (Objects.equals(OrderStatusEnum.SUCCESS_PAY.getValue(), dto.getOrderStatus())) {
+            log.error("腾讯 APP订单回传收到:{}。", JsonUtil.toString(dto));
+        } else {
+            log.error("腾讯H5订单回传收到:{}。订单未支付,直接过滤", JsonUtil.toString(dto));
+            return ResultVO.ok(true);
+        }
+        if (StringUtils.isBlank(dto.getMac())) {
+            dto.setMac("");
+        }
+        if(StringUtils.isBlank(dto.getImei())) {
+            dto.setImei("");
+        }
+        if(StringUtils.isBlank(dto.getOaid())) {
+            dto.setOaid("");
+        }
+        if(StringUtils.isBlank(dto.getAndroidId())) {
+            dto.setAndroidId("");
+        }
+        if(StringUtils.isBlank(dto.getIdfa())) {
+            dto.setIdfa("");
+        }
+        if(StringUtils.isBlank(dto.getCaid())) {
+            dto.setCaid("");
+        }
+        if(StringUtils.isBlank(dto.getImei())
+                && StringUtils.isBlank(dto.getOaid())
+                && StringUtils.isBlank(dto.getAndroidId())
+                && StringUtils.isBlank(dto.getIdfa())
+                && StringUtils.isBlank(dto.getCaid())) {
+            return ResultVO.fail("找不到用户唯一标识");
+        }
+        boolean isFirstOrder = gameTencentAppApiOrderService.getOne(new LambdaQueryWrapper<GameTencentAppApiOrder>()
+                .select(GameTencentAppApiOrder::getOrderId)
+                .eq(GameTencentAppApiOrder::getGameId, dto.getGameId())
+                .eq(GameTencentAppApiOrder::getAdAccountId, dto.getAdAccountId())
+                .eq(GameTencentAppApiOrder::getUserId, dto.getUserId())
+                .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                .last("limit 1")
+        ) == null;
+        //订单保存
+        GameTencentAppApiOrder gameTencentOrder = GameTencentAppApiOrder.builder()
+                .userId(dto.getUserId())
+                .adAccountId(dto.getAdAccountId())
+                .gameId(dto.getGameId())
+                .orderId(dto.getOrderId())
+                .channel(dto.getChannel())
+                .rechargeMoney(dto.getRechargeMoney())
+                .rechargeTime(dto.getRechargeTime())
+                .subscribeTime(dto.getSubscribeTime())
+                .registerTime(dto.getRegisterTime())
+                .mac(dto.getMac())
+                .imei(dto.getImei())
+                .oaid(dto.getOaid())
+                .androidId(dto.getAndroidId())
+                .idfa(dto.getIdfa())
+                .caid(dto.getCaid())
+                .orderStatus(dto.getOrderStatus())
+                .payTime(dto.getPayTime())
+                .createTime(LocalDateTime.now())
+                .isBack(BackStatusEnum.NO.getBackStatus())
+                .backPolicyId(dto.getBackPolicyId())
+                .roleId(dto.getRoleId())
+                .roleName(dto.getRoleName())
+                .isFirstOrder(isFirstOrder)
+                .build();
+        gameTencentAppApiOrderService.save(gameTencentOrder);
+        return ResultVO.ok(gameTencentAppApiOrderService.orderBack(gameTencentOrder));
+    }
+
+    @Override
+    public ResultVO<String> queryUserAgentFromCallback(TencentAppApiUserAgentQueryRpcDTO dto) {
+        GameTencentAppCallback callback = gameTencentAppCallbackService.getUserCallback(dto.getGameId(), dto.getImei(), dto.getOaid(), dto.getAndroidId(), dto.getIdfa(), dto.getCaid());
+        return ResultVO.ok(callback == null ? null : callback.getAgentKey());
+    }
+}

+ 15 - 6
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/rpc/impl/TencentAppBackRpcImpl.java

@@ -6,6 +6,7 @@ import com.zanxiang.game.back.base.pojo.enums.OrderStatusEnum;
 import com.zanxiang.game.back.base.rpc.ITencentAppBackRpc;
 import com.zanxiang.game.back.serve.pojo.entity.*;
 import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
+import com.zanxiang.game.back.serve.service.IGameTencentAppCallbackService;
 import com.zanxiang.game.back.serve.service.IGameTencentAppOrderService;
 import com.zanxiang.game.back.serve.service.IGameTencentAppRoleRegisterService;
 import com.zanxiang.game.back.serve.service.IGameTencentAppUserService;
@@ -28,6 +29,8 @@ public class TencentAppBackRpcImpl implements ITencentAppBackRpc {
     private IGameTencentAppRoleRegisterService gameTencentAppRoleRegisterService;
     @Autowired
     private IGameTencentAppOrderService gameTencentAppOrderService;
+    @Autowired
+    private IGameTencentAppCallbackService gameTencentAppCallbackService;
 
     @Override
     public ResultVO<Boolean> backUser(TencentUserAppRpcDTO dto) {
@@ -50,8 +53,7 @@ public class TencentAppBackRpcImpl implements ITencentAppBackRpc {
         if(StringUtils.isBlank(dto.getCaid())) {
             dto.setCaid("");
         }
-        if(StringUtils.isBlank(dto.getMac())
-                && StringUtils.isBlank(dto.getImei())
+        if(StringUtils.isBlank(dto.getImei())
                 && StringUtils.isBlank(dto.getOaid())
                 && StringUtils.isBlank(dto.getAndroidId())
                 && StringUtils.isBlank(dto.getIdfa())
@@ -61,6 +63,7 @@ public class TencentAppBackRpcImpl implements ITencentAppBackRpc {
         GameTencentAppUser gameTencentUser = GameTencentAppUser.builder()
                 .adAccountId(dto.getAdAccountId())
                 .gameId(dto.getGameId())
+                .userId(dto.getUserId())
                 .channel(dto.getChannel())
                 .subscribeTime(dto.getSubscribeTime())
                 .registerTime(dto.getRegisterTime())
@@ -101,8 +104,7 @@ public class TencentAppBackRpcImpl implements ITencentAppBackRpc {
         if(StringUtils.isBlank(dto.getCaid())) {
             dto.setCaid("");
         }
-        if(StringUtils.isBlank(dto.getMac())
-                && StringUtils.isBlank(dto.getImei())
+        if(StringUtils.isBlank(dto.getImei())
                 && StringUtils.isBlank(dto.getOaid())
                 && StringUtils.isBlank(dto.getAndroidId())
                 && StringUtils.isBlank(dto.getIdfa())
@@ -112,6 +114,7 @@ public class TencentAppBackRpcImpl implements ITencentAppBackRpc {
         GameTencentAppRoleRegister roleRegister = GameTencentAppRoleRegister.builder()
                 .backPolicyId(dto.getBackPolicyId())
                 .channel(dto.getChannel())
+                .userId(dto.getUserId())
                 .gameId(dto.getGameId())
                 .adAccountId(dto.getAdAccountId())
                 .registerTime(dto.getRegisterTime())
@@ -158,8 +161,7 @@ public class TencentAppBackRpcImpl implements ITencentAppBackRpc {
         if(StringUtils.isBlank(dto.getCaid())) {
             dto.setCaid("");
         }
-        if(StringUtils.isBlank(dto.getMac())
-                && StringUtils.isBlank(dto.getImei())
+        if(StringUtils.isBlank(dto.getImei())
                 && StringUtils.isBlank(dto.getOaid())
                 && StringUtils.isBlank(dto.getAndroidId())
                 && StringUtils.isBlank(dto.getIdfa())
@@ -182,6 +184,7 @@ public class TencentAppBackRpcImpl implements ITencentAppBackRpc {
         //订单保存
         GameTencentAppOrder gameTencentOrder = GameTencentAppOrder.builder()
                 .adAccountId(dto.getAdAccountId())
+                .userId(dto.getUserId())
                 .gameId(dto.getGameId())
                 .orderId(dto.getOrderId())
                 .channel(dto.getChannel())
@@ -209,4 +212,10 @@ public class TencentAppBackRpcImpl implements ITencentAppBackRpc {
         return ResultVO.ok(true);
         // return ResultVO.ok(gameTencentAppOrderService.orderBack(gameTencentOrder));
     }
+
+    @Override
+    public ResultVO<String> queryUserAgentFromCallback(TencentAppApiUserAgentQueryRpcDTO dto) {
+        GameTencentAppCallback callback = gameTencentAppCallbackService.getUserCallback(dto.getGameId(), dto.getImei(), dto.getOaid(), dto.getAndroidId(), dto.getIdfa(), dto.getCaid());
+        return ResultVO.ok(callback == null ? null : callback.getAgentKey());
+    }
 }

+ 76 - 25
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/rpc/impl/TtAppBackRpcImpl.java

@@ -3,27 +3,30 @@ package com.zanxiang.game.back.serve.rpc.impl;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.zanxiang.game.back.base.pojo.dto.*;
 import com.zanxiang.game.back.base.pojo.enums.OrderStatusEnum;
+import com.zanxiang.game.back.base.pojo.vo.OrderBackQueryRpcVO;
 import com.zanxiang.game.back.base.rpc.ITtAppBackRpc;
 import com.zanxiang.game.back.serve.pojo.entity.*;
 import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
-import com.zanxiang.game.back.serve.service.IGameBackPolicyService;
-import com.zanxiang.game.back.serve.service.IGameOceanengineAppOrderLogService;
-import com.zanxiang.game.back.serve.service.IGameOceanengineAppRoleRegisterLogService;
-import com.zanxiang.game.back.serve.service.IGameOceanengineAppUserLogService;
+import com.zanxiang.game.back.serve.service.*;
 import com.zanxiang.game.module.base.ServerInfo;
 import com.zanxiang.game.module.base.rpc.IAgentRpc;
 import com.zanxiang.module.redis.service.IDistributedLockComponent;
 import com.zanxiang.module.util.JsonUtil;
 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.apache.dubbo.config.annotation.DubboService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
 
 import java.time.LocalDateTime;
+import java.util.Collections;
+import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 @Slf4j
 @DubboService
@@ -40,7 +43,13 @@ public class TtAppBackRpcImpl implements ITtAppBackRpc {
     @Autowired
     private IGameOceanengineAppOrderLogService gameOceanengineAppOrderLogService;
     @Autowired
+    private IGameOceanengineAppOrderSplitLogService gameOceanengineAppOrderSplitLogService;
+    @Autowired
     private IDistributedLockComponent distributedLockComponent;
+    @Autowired
+    private RedisTemplate<String, Object> redisTemplate;
+    @Autowired
+    private IGameOceanengineAppCallbackService gameOceanengineAppCallbackService;
 
     @Override
     public ResultVO<Boolean> userActiveReport(TtUserActiveAppRpcDTO dto) {
@@ -63,8 +72,7 @@ public class TtAppBackRpcImpl implements ITtAppBackRpc {
         if(StringUtils.isBlank(dto.getCaid())) {
             dto.setCaid("");
         }
-        if(StringUtils.isBlank(dto.getUserId()) || (StringUtils.isBlank(dto.getMac())
-                && StringUtils.isBlank(dto.getImei())
+        if(StringUtils.isBlank(dto.getUserId()) || (StringUtils.isBlank(dto.getImei())
                 && StringUtils.isBlank(dto.getOaid())
                 && StringUtils.isBlank(dto.getAndroidId())
                 && StringUtils.isBlank(dto.getIdfa())
@@ -117,8 +125,7 @@ public class TtAppBackRpcImpl implements ITtAppBackRpc {
         if(StringUtils.isBlank(dto.getCaid())) {
             dto.setCaid("");
         }
-        if(StringUtils.isBlank(dto.getUserId()) || (StringUtils.isBlank(dto.getMac())
-                && StringUtils.isBlank(dto.getImei())
+        if(StringUtils.isBlank(dto.getUserId()) || (StringUtils.isBlank(dto.getImei())
                 && StringUtils.isBlank(dto.getOaid())
                 && StringUtils.isBlank(dto.getAndroidId())
                 && StringUtils.isBlank(dto.getIdfa())
@@ -127,7 +134,8 @@ public class TtAppBackRpcImpl implements ITtAppBackRpc {
         }
         // 此处加锁防止 cp 方调用过快,导致查询回传结果时判断逻辑没走完
         String lockKey = com.zanxiang.game.back.base.ServerInfo.SERVER_NAME + ":TtAppOrderBack:" + dto.getGameId() + ":" + dto.getOrderId();
-        distributedLockComponent.doLock(lockKey, 0L, 60L, TimeUnit.SECONDS);
+        redisTemplate.opsForValue().set(lockKey, dto.getOrderId(), 2L, TimeUnit.MINUTES);
+        // distributedLockComponent.doLock(lockKey, 0L, 60L, TimeUnit.SECONDS);
         try {
             GameOceanengineAppOrderLog orderLog = GameOceanengineAppOrderLog.builder()
                     .userId(dto.getUserId())
@@ -162,7 +170,8 @@ public class TtAppBackRpcImpl implements ITtAppBackRpc {
             gameOceanengineAppOrderLogService.save(orderLog);
             return ResultVO.ok(gameOceanengineAppOrderLogService.callback(orderLog));
         } finally {
-            distributedLockComponent.unlock(lockKey);
+            redisTemplate.delete(lockKey);
+            // distributedLockComponent.unlock(lockKey);
         }
     }
 
@@ -187,8 +196,7 @@ public class TtAppBackRpcImpl implements ITtAppBackRpc {
         if(StringUtils.isBlank(dto.getCaid())) {
             dto.setCaid("");
         }
-        if(StringUtils.isBlank(dto.getUserId()) || (StringUtils.isBlank(dto.getMac())
-                && StringUtils.isBlank(dto.getImei())
+        if(StringUtils.isBlank(dto.getUserId()) || (StringUtils.isBlank(dto.getImei())
                 && StringUtils.isBlank(dto.getOaid())
                 && StringUtils.isBlank(dto.getAndroidId())
                 && StringUtils.isBlank(dto.getIdfa())
@@ -223,23 +231,33 @@ public class TtAppBackRpcImpl implements ITtAppBackRpc {
     }
 
     @Override
-    public ResultVO<Boolean> orderBackQuery(TtAppOrderBackQueryRpcDTO dto) {
+    public ResultVO<OrderBackQueryRpcVO> orderBackQuery(TtAppOrderBackQueryRpcDTO dto) {
         log.error("头条APP订单回传结果查询:{}", JsonUtil.toString(dto));
 
-        // 加锁最大等待 60s
-        String lockKey = com.zanxiang.game.back.base.ServerInfo.SERVER_NAME + ":TtAppOrderBack:" + dto.getGameId() + ":" + dto.getOrderId();
-        distributedLockComponent.doLock(lockKey, 60, 1L, TimeUnit.SECONDS);
-
-        GameOceanengineAppOrderLog orderLog = gameOceanengineAppOrderLogService.getOne(new LambdaQueryWrapper<GameOceanengineAppOrderLog>()
-                .eq(GameOceanengineAppOrderLog::getOrderNo, dto.getOrderId())
-                .eq(GameOceanengineAppOrderLog::getGameId, dto.getGameId())
-                .eq(GameOceanengineAppOrderLog::getAgentKey, dto.getAgentKey())
-                .eq(GameOceanengineAppOrderLog::getUserId, dto.getUserId())
-        );
+        GameOceanengineAppOrderLog orderLog = queryOrder(dto);
+        if (orderLog == null) {
+            try {
+                Thread.sleep(5 *  1000L);
+            } catch (Exception e) {
+                log.error(e.getMessage(), e);
+            }
+            orderLog = queryOrder(dto);
+        }
         if  (orderLog == null) {
-            return ResultVO.ok(Boolean.FALSE);
+            return ResultVO.ok(OrderBackQueryRpcVO.builder()
+                            .doBack(Boolean.FALSE)
+                            .backMsg("回传异常,找不到订单:" + dto.getOrderId())
+                    .build());
         }
-        return ResultVO.ok(BackStatusEnum.getByValue(orderLog.getBackStatus()) ==  BackStatusEnum.SUCCESS);
+        List<Long> splitMoney = gameOceanengineAppOrderSplitLogService.list(new LambdaQueryWrapper<GameOceanengineAppOrderSplitLog>()
+                .eq(GameOceanengineAppOrderSplitLog::getOrderNo, orderLog.getOrderNo())
+                .orderByAsc(GameOceanengineAppOrderSplitLog::getBackIndex)
+        ).stream().map(GameOceanengineAppOrderSplitLog::getSplitMoney).collect(Collectors.toList());
+        return ResultVO.ok(OrderBackQueryRpcVO.builder()
+                        .doBack(BackStatusEnum.getByValue(orderLog.getBackStatus()) ==  BackStatusEnum.SUCCESS)
+                        .backMoney(CollectionUtils.isEmpty(splitMoney) ? Collections.singletonList(orderLog.getBackMoney()) : splitMoney)
+                        .backMsg(orderLog.getBackMsg())
+                .build());
     }
 
     @Override
@@ -247,4 +265,37 @@ public class TtAppBackRpcImpl implements ITtAppBackRpc {
         log.error("头条APP创角回传结果查询:{}", JsonUtil.toString(dto));
         return ResultVO.ok(Boolean.TRUE);
     }
+
+    @Override
+    public ResultVO<String> queryUserAgentFromCallback(TtAppUserAgentQueryRpcDTO dto) {
+        GameOceanengineAppCallback callback = gameOceanengineAppCallbackService.getUserCallback(dto.getGameId(), dto.getImei(), dto.getOaid(), dto.getAndroidId(), dto.getIdfa(), dto.getCaid());
+        return ResultVO.ok(callback == null ? null : callback.getAgentKey());
+    }
+
+    private GameOceanengineAppOrderLog queryOrder(TtAppOrderBackQueryRpcDTO dto) {
+        String lockKey = com.zanxiang.game.back.base.ServerInfo.SERVER_NAME + ":TtAppOrderBack:" + dto.getGameId() + ":" + dto.getOrderId();
+        int maxCount = 0;
+        while (true) {
+            if (redisTemplate.opsForValue().get(lockKey) == null) {
+                break;
+            }
+            if (maxCount++ >= 120 / 10) {
+                break;
+            }
+            try {
+                Thread.sleep(10 * 1000L);
+            } catch (Exception e) {
+                log.error(e.getMessage(), e);
+            }
+        }
+        // 加锁最大等待 120s
+        // distributedLockComponent.doLock(lockKey, 60, 1L, TimeUnit.SECONDS);
+
+        return gameOceanengineAppOrderLogService.getOne(new LambdaQueryWrapper<GameOceanengineAppOrderLog>()
+                .eq(GameOceanengineAppOrderLog::getOrderNo, dto.getOrderId())
+                .eq(GameOceanengineAppOrderLog::getGameId, dto.getGameId())
+                .eq(GameOceanengineAppOrderLog::getAgentKey, dto.getAgentKey())
+                .eq(GameOceanengineAppOrderLog::getUserId, dto.getUserId())
+        );
+    }
 }

+ 2 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameOceanengineAppCallbackService.java

@@ -7,4 +7,6 @@ import com.zanxiang.game.back.serve.pojo.entity.GameOceanengineAppCallback;
 public interface IGameOceanengineAppCallbackService extends IService<GameOceanengineAppCallback> {
 
     boolean callback(GameOceanengineAppCallbackDTO dto);
+
+    GameOceanengineAppCallback getUserCallback(Long gameId, String imei, String oaid, String android, String idfa, String caid);
 }

+ 7 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameOceanengineAppOrderSplitLogService.java

@@ -0,0 +1,7 @@
+package com.zanxiang.game.back.serve.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.back.serve.pojo.entity.GameOceanengineAppOrderSplitLog;
+
+public interface IGameOceanengineAppOrderSplitLogService extends IService<GameOceanengineAppOrderSplitLog> {
+}

+ 7 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentAppApiBackLogService.java

@@ -0,0 +1,7 @@
+package com.zanxiang.game.back.serve.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppApiBackLog;
+
+public interface IGameTencentAppApiBackLogService extends IService<GameTencentAppApiBackLog> {
+}

+ 18 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentAppApiOrderService.java

@@ -0,0 +1,18 @@
+package com.zanxiang.game.back.serve.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.github.sd4324530.jtuple.Tuple2;
+import com.zanxiang.game.back.serve.pojo.dto.OrderReportDTO;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppApiOrder;
+import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
+
+import java.time.LocalDateTime;
+
+public interface IGameTencentAppApiOrderService extends IService<GameTencentAppApiOrder> {
+
+    boolean orderBack(GameTencentAppApiOrder orderLog);
+
+    boolean tencentOrderReport(OrderReportDTO dto);
+
+    Tuple2<BackStatusEnum, String> doCallback(GameTencentAppApiOrder orderLog, LocalDateTime backTime, Long backMoney);
+}

+ 13 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentAppApiOrderSplitLogService.java

@@ -0,0 +1,13 @@
+package com.zanxiang.game.back.serve.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppApiOrderSplitLog;
+import com.zanxiang.game.back.serve.pojo.vo.GameTencentAppApiOrderSplitLogVO;
+
+import java.util.Collection;
+import java.util.List;
+
+public interface IGameTencentAppApiOrderSplitLogService extends IService<GameTencentAppApiOrderSplitLog> {
+
+    List<GameTencentAppApiOrderSplitLogVO> listByOrderNo(Collection<String> orderNos);
+}

+ 9 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentAppApiRoleRegisterService.java

@@ -0,0 +1,9 @@
+package com.zanxiang.game.back.serve.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppApiRoleRegister;
+
+public interface IGameTencentAppApiRoleRegisterService extends IService<GameTencentAppApiRoleRegister> {
+
+    boolean roleRegisterBack(GameTencentAppApiRoleRegister roleRegisterLog);
+}

+ 13 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentAppApiUserService.java

@@ -0,0 +1,13 @@
+package com.zanxiang.game.back.serve.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppApiUser;
+
+import java.util.List;
+
+public interface IGameTencentAppApiUserService extends IService<GameTencentAppApiUser> {
+
+    boolean userBack(GameTencentAppApiUser userLog, boolean mustBack);
+
+    boolean tencentUserReport(List<Long> ids);
+}

+ 2 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentAppCallbackService.java

@@ -7,4 +7,6 @@ import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppCallback;
 public interface IGameTencentAppCallbackService extends IService<GameTencentAppCallback> {
 
     boolean callback(GameTencentAppCallbackDTO dto);
+
+    GameTencentAppCallback getUserCallback(Long gameId, String imei, String oaid, String android, String idfa, String caid);
 }

+ 42 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameOceanengineAppCallbackServiceImpl.java

@@ -1,14 +1,21 @@
 package com.zanxiang.game.back.serve.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zanxiang.game.back.serve.dao.mapper.GameOceanengineAppCallbackMapper;
 import com.zanxiang.game.back.serve.pojo.dto.GameOceanengineAppCallbackDTO;
 import com.zanxiang.game.back.serve.pojo.entity.GameOceanengineAppCallback;
 import com.zanxiang.game.back.serve.service.IGameOceanengineAppCallbackService;
+import com.zanxiang.game.module.base.ServerInfo;
+import com.zanxiang.game.module.base.pojo.vo.AgentRpcVO;
+import com.zanxiang.game.module.base.rpc.IAgentRpc;
 import com.zanxiang.module.util.DateUtil;
 import com.zanxiang.module.util.JsonUtil;
 import com.zanxiang.module.util.bean.BeanUtil;
+import com.zanxiang.module.util.encryption.Md5Util;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.dubbo.config.annotation.DubboReference;
 import org.apache.kafka.clients.producer.KafkaProducer;
 import org.apache.kafka.clients.producer.ProducerRecord;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -27,11 +34,24 @@ implements IGameOceanengineAppCallbackService {
     private String oceanengineAppCallbackTopic;
     @Autowired
     private KafkaProducer<String, String> kafkaProducer;
+    @DubboReference(providedBy = ServerInfo.SERVER_DUBBO_NAME)
+    private IAgentRpc agentRpc;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
     public boolean callback(GameOceanengineAppCallbackDTO dto) {
+        AgentRpcVO agent = agentRpc.getByByteAccountId(dto.getAdvertiserId()).getData();
+        if (agent == null) {
+            log.error("头条检测链接数据找不到渠道:{}", JsonUtil.toString(dto));
+        }
         GameOceanengineAppCallback appCallback = BeanUtil.copy(dto, GameOceanengineAppCallback.class);
+        if (agent != null) {
+            appCallback.setAgentKey(agent.getAgentKey());
+            appCallback.setGameId(agent.getGameId());
+        } else {
+            appCallback.setAgentKey("-");
+            appCallback.setGameId(-1L);
+        }
         appCallback.setDay(dto.getTs() == null || dto.getTs() < 1000 ? LocalDate.now() : DateUtil.milliToLocalDateTime(dto.getTs()).toLocalDate());
         save(appCallback);
         try {
@@ -41,4 +61,26 @@ implements IGameOceanengineAppCallbackService {
         }
         return true;
     }
+
+    @Override
+    public GameOceanengineAppCallback getUserCallback(Long gameId, String imei, String oaid, String android, String idfa, String caid) {
+        LambdaQueryWrapper<GameOceanengineAppCallback> qw = new LambdaQueryWrapper<GameOceanengineAppCallback>()
+                .eq(GameOceanengineAppCallback::getGameId, gameId)
+                .orderByDesc(GameOceanengineAppCallback::getTs)
+                .last("limit 1");
+        if (StringUtils.isNoneBlank(imei) || StringUtils.isNoneBlank(android) || StringUtils.isNoneBlank(oaid)) {
+            qw.and(and -> {
+                and.eq(StringUtils.isNoneBlank(imei), GameOceanengineAppCallback::getImei, StringUtils.isBlank(imei) ? null : Md5Util.encrypt32(imei).toLowerCase())
+                        .or().eq(StringUtils.isNoneBlank(android), GameOceanengineAppCallback::getAndroidid, StringUtils.isBlank(android) ? null : Md5Util.encrypt32(android).toLowerCase())
+                        .or().eq(StringUtils.isNoneBlank(oaid), GameOceanengineAppCallback::getOaid, oaid)
+                        .or().eq(StringUtils.isNoneBlank(oaid), GameOceanengineAppCallback::getOaidMd5, StringUtils.isBlank(oaid) ? null : Md5Util.encrypt32(oaid).toLowerCase());
+            });
+        } else if (StringUtils.isNoneBlank(idfa)) {
+            qw.and(and -> {
+                and.eq(GameOceanengineAppCallback::getIdfaMd5, StringUtils.isBlank(idfa) ? null : Md5Util.encrypt32(idfa).toLowerCase())
+                        .or().eq(GameOceanengineAppCallback::getIdfa, idfa);
+            });
+        }
+        return getOne(qw);
+    }
 }

+ 29 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameOceanengineAppOrderLogServiceImpl.java

@@ -34,6 +34,8 @@ implements IGameOceanengineAppOrderLogService {
     private IGameOceanengineAppUserLogService gameOceanengineAppUserLogService;
     @Autowired
     private IGameOceanengineAppBackLogService gameOceanengineAppBackLogService;
+    @Autowired
+    private IGameOceanengineAppOrderSplitLogService gameOceanengineAppOrderSplitLogService;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -75,6 +77,33 @@ implements IGameOceanengineAppOrderLogService {
                     .eq(GameOceanengineAppOrderLog::getId, orderLog.getId())
             );
         }
+        // 拆单
+        Tuple3<Boolean, Long, List<Tuple2<Long, LocalDateTime>>> splitResult = BackPolicyUtil.splitOrder(gameBackPolicy, backMoney);
+        if (splitResult.first) {
+            // 需要拆单
+            List<GameOceanengineAppOrderSplitLog> splitOrderLogList = new ArrayList<>(splitResult.third.size());
+            for (int i = 0; i < splitResult.third.size(); i++) {
+                Tuple2<Long, LocalDateTime> splitOrder = splitResult.third.get(i);
+                splitOrderLogList.add(GameOceanengineAppOrderSplitLog.builder()
+                        .backDay(splitOrder.second.toLocalDate())
+                        .orderNo(orderLog.getOrderNo())
+                        .backIndex(i + 1)
+                        .backCount(splitResult.third.size())
+                        .splitMoney(splitOrder.first)
+                        .backTime(splitOrder.second)
+                        .backStatus(BackStatusEnum.SUCCESS.getBackStatus())
+                        .createTime(LocalDateTime.now())
+                        .build()
+                );
+            }
+            gameOceanengineAppOrderSplitLogService.saveBatch(splitOrderLogList);
+            return update(new LambdaUpdateWrapper<GameOceanengineAppOrderLog>()
+                    .set(GameOceanengineAppOrderLog::getBackStatus, BackStatusEnum.SUCCESS.getBackStatus())
+                    .set(GameOceanengineAppOrderLog::getBackMoney, splitResult.second)
+                    .set(GameOceanengineAppOrderLog::getBackMsg, backMsg)
+                    .eq(GameOceanengineAppOrderLog::getId, orderLog.getId())
+            );
+        }
 
         Tuple2<BackStatusEnum, String> backResult = doCallback(orderLog, orderLog.getPayTime(), backMoney);
         if (StringUtils.isNotBlank(backResult.second)) {

+ 14 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameOceanengineAppOrderSplitLogServiceImpl.java

@@ -0,0 +1,14 @@
+package com.zanxiang.game.back.serve.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zanxiang.game.back.serve.dao.mapper.GameOceanengineAppOrderSplitLogMapper;
+import com.zanxiang.game.back.serve.pojo.entity.GameOceanengineAppOrderSplitLog;
+import com.zanxiang.game.back.serve.service.IGameOceanengineAppOrderSplitLogService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+public class GameOceanengineAppOrderSplitLogServiceImpl extends ServiceImpl<GameOceanengineAppOrderSplitLogMapper, GameOceanengineAppOrderSplitLog>
+implements IGameOceanengineAppOrderSplitLogService {
+}

+ 14 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentAppApiBackLogServiceImpl.java

@@ -0,0 +1,14 @@
+package com.zanxiang.game.back.serve.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zanxiang.game.back.serve.dao.mapper.GameTencentAppApiBackLogMapper;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppApiBackLog;
+import com.zanxiang.game.back.serve.service.IGameTencentAppApiBackLogService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+public class GameTencentAppApiBackLogServiceImpl extends ServiceImpl<GameTencentAppApiBackLogMapper, GameTencentAppApiBackLog>
+implements IGameTencentAppApiBackLogService {
+}

+ 456 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentAppApiOrderServiceImpl.java

@@ -0,0 +1,456 @@
+package com.zanxiang.game.back.serve.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.github.sd4324530.jtuple.Tuple2;
+import com.github.sd4324530.jtuple.Tuple3;
+import com.zanxiang.game.back.base.pojo.enums.OrderStatusEnum;
+import com.zanxiang.game.back.serve.dao.mapper.GameTencentAppApiOrderMapper;
+import com.zanxiang.game.back.serve.pojo.TencentAppReport;
+import com.zanxiang.game.back.serve.pojo.dto.OrderReportDTO;
+import com.zanxiang.game.back.serve.pojo.entity.*;
+import com.zanxiang.game.back.serve.pojo.enums.ActionTypeEnum;
+import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
+import com.zanxiang.game.back.serve.pojo.enums.BackUnitEnum;
+import com.zanxiang.game.back.serve.service.*;
+import com.zanxiang.game.back.serve.utils.BackPolicyUtil;
+import com.zanxiang.module.util.DateUtil;
+import com.zanxiang.module.util.NumberUtil;
+import com.zanxiang.module.util.URIUtil;
+import com.zanxiang.module.util.encryption.Md5Util;
+import com.zanxiang.module.util.exception.BaseException;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.RandomUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.client.RestTemplate;
+
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicLong;
+
+@Slf4j
+@Service
+public class GameTencentAppApiOrderServiceImpl extends ServiceImpl<GameTencentAppApiOrderMapper, GameTencentAppApiOrder>
+implements IGameTencentAppApiOrderService {
+
+    @Autowired
+    private IGameTencentAppApiBackLogService gameTencentAppApiBackLogService;
+    @Autowired
+    private IGameBackPolicyService gameBackPolicyService;
+    @Autowired
+    private IGameTencentAppApiUserService gameTencentAppApiUserService;
+    @Autowired
+    private IGameTencentAppApiOrderSplitLogService gameTencentAppApiOrderSplitLogService;
+    @Autowired
+    private RestTemplate restTemplate;
+    @Autowired
+    private IGameTencentAppCallbackService gameTencentAppCallbackService;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean orderBack(GameTencentAppApiOrder orderLog) {
+        if (!Objects.equals(orderLog.getOrderStatus(), OrderStatusEnum.SUCCESS_PAY.getValue())) {
+            // 只要回传 支付行为
+            return false;
+        }
+        GameTencentAppApiUser userLog = gameTencentAppApiUserService.getOne(new LambdaQueryWrapper<GameTencentAppApiUser>()
+                .eq(GameTencentAppApiUser::getGameId, orderLog.getGameId())
+                .eq(GameTencentAppApiUser::getUserId, orderLog.getUserId())
+                .eq(GameTencentAppApiUser::getAdAccountId, orderLog.getAdAccountId())
+                .orderByDesc(GameTencentAppApiUser::getCreateTime)
+                .last("limit 1")
+        );
+        if (userLog == null) {
+            return update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
+                    .set(GameTencentAppApiOrder::getIsBack, BackStatusEnum.FAILED.getBackStatus())
+                    .set(GameTencentAppApiOrder::getBackMoney, orderLog.getRechargeMoney())
+                    .set(GameTencentAppApiOrder::getBackMsg, "回传失败!找不到回传用户")
+                    .eq(GameTencentAppApiOrder::getId, orderLog.getId())
+            );
+        }
+
+        GameBackPolicy gameBackPolicy = gameBackPolicyService.getById(orderLog.getBackPolicyId());
+        Tuple3<Boolean, Long, String> backInfo = BackPolicyUtil.backOrder(orderLog.getOrderId(), gameBackPolicy, orderLog.getRechargeMoney(),
+                orderLog.getIsFirstOrder(),
+                orderLog.getPayTime(),
+                // 此处使用用户最近一次的重新染色时间
+                userLog.getCreateTime(),
+                orderLog.getUserId(),
+                new TencentOrderBackPolicyCheck(this, gameBackPolicy, userLog, orderLog));
+        boolean doBack = backInfo.first;
+        Long backMoney = backInfo.second;
+        String backMsg = backInfo.third;
+        if (!doBack) {
+            return update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
+                    .set(GameTencentAppApiOrder::getIsBack, BackStatusEnum.NO.getBackStatus())
+                    .set(GameTencentAppApiOrder::getBackMoney, backMoney)
+                    .set(GameTencentAppApiOrder::getBackMsg, backMsg)
+                    .eq(GameTencentAppApiOrder::getId, orderLog.getId())
+            );
+        }
+        // 拆单
+        Tuple3<Boolean, Long, List<Tuple2<Long, LocalDateTime>>> splitResult = BackPolicyUtil.splitOrder(gameBackPolicy, backMoney);
+        if (splitResult.first) {
+            // 需要拆单
+            List<GameTencentAppApiOrderSplitLog> splitOrderLogList = new ArrayList<>(splitResult.third.size());
+            for (int i = 0; i < splitResult.third.size(); i++) {
+                Tuple2<Long, LocalDateTime> splitOrder = splitResult.third.get(i);
+                splitOrderLogList.add(GameTencentAppApiOrderSplitLog.builder()
+                        .backDay(splitOrder.second.toLocalDate())
+                        .orderNo(orderLog.getOrderId())
+                        .backIndex(i + 1)
+                        .backCount(splitResult.third.size())
+                        .splitMoney(splitOrder.first)
+                        .backTime(splitOrder.second)
+                        .backStatus(BackStatusEnum.NO.getBackStatus())
+                        .createTime(LocalDateTime.now())
+                        .build());
+            }
+            gameTencentAppApiOrderSplitLogService.saveBatch(splitOrderLogList);
+            return update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
+                    .set(GameTencentAppApiOrder::getIsBack, BackStatusEnum.NO.getBackStatus())
+                    .set(GameTencentAppApiOrder::getBackMoney, splitResult.second)
+                    .set(GameTencentAppApiOrder::getBackMsg, backMsg)
+                    .eq(GameTencentAppApiOrder::getId, orderLog.getId())
+            );
+        }
+
+        Tuple2<BackStatusEnum, String> backResult = doCallback(orderLog, orderLog.getPayTime(), backMoney);
+        if (StringUtils.isNotBlank(backResult.second)) {
+            backMsg = backMsg + ("回传失败:" + backResult.second);
+        }
+        return update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
+                .set(GameTencentAppApiOrder::getIsBack, backResult.first.getBackStatus())
+                .set(GameTencentAppApiOrder::getBackMoney, backMoney)
+                .set(GameTencentAppApiOrder::getBackMsg, backMsg)
+                .eq(GameTencentAppApiOrder::getId, orderLog.getId())
+        );
+    }
+
+    @Override
+    public boolean tencentOrderReport(OrderReportDTO dto) {
+        listByIds(dto.getOrderIds()).stream()
+                .filter(order -> !Objects.equals(order.getIsBack(), BackStatusEnum.SUCCESS.getBackStatus()))
+                .forEach(orderLog -> {
+                    if (dto.getSplitOrder()) {
+                        AtomicLong total = new AtomicLong(0);
+                        dto.getSplitMoney().forEach(money -> {
+                            total.addAndGet(NumberUtil.multiply100(money).longValue());
+                        });
+                        if (!orderLog.getRechargeMoney().equals(total.get())) {
+                            throw new BaseException("订单充值金额和回传金额对不上");
+                        }
+                        log.error("手动拆单回传:{}-{}", orderLog.getId(), StringUtils.join(dto.getSplitMoney(), ","));
+                        List<GameTencentAppApiOrderSplitLog> splitOrderLogList = new ArrayList<>(dto.getSplitMoney().size());
+                        LocalDateTime beginTime = LocalDateTime.now();
+                        long backMoneyTotal = 0L;
+                        for (int i = 0; i < dto.getSplitMoney().size(); i++) {
+                            long backMoney = NumberUtil.multiply100(dto.getSplitMoney().get(i)).longValue();
+                            LocalDateTime backTime = beginTime;
+                            backMoneyTotal += backMoney;
+                            splitOrderLogList.add(GameTencentAppApiOrderSplitLog.builder()
+                                    .backDay(backTime.toLocalDate())
+                                    .orderNo(orderLog.getOrderId())
+                                    .backIndex(i + 1)
+                                    .backCount(dto.getSplitMoney().size())
+                                    .splitMoney(backMoney)
+                                    .backTime(backTime)
+                                    .backStatus(BackStatusEnum.NO.getBackStatus())
+                                    .createTime(LocalDateTime.now())
+                                    .build());
+                            beginTime = beginTime.plusMinutes(RandomUtils.nextInt(dto.getBetweenMinuteMin(), dto.getBetweenMinuteMax()));
+                        }
+                        gameTencentAppApiOrderSplitLogService.saveBatch(splitOrderLogList);
+                        update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
+                                .set(GameTencentAppApiOrder::getIsBack, BackStatusEnum.NO.getBackStatus())
+                                .set(GameTencentAppApiOrder::getBackMoney, backMoneyTotal)
+                                .set(GameTencentAppApiOrder::getBackMsg, "手动触发回传(拆单回传)")
+                                .eq(GameTencentAppApiOrder::getId, orderLog.getId())
+                        );
+                    } else {
+                        log.error("手动直接回传:{}-{}", orderLog.getId(), dto.getBackMoney());
+                        long backMoney = NumberUtil.multiply100(dto.getBackMoney()).longValue();
+                        Tuple2<BackStatusEnum, String> backResult = doCallback(orderLog, orderLog.getPayTime(), backMoney);
+                        String backMsg = "手动触发回传!";
+                        if (StringUtils.isNotBlank(backResult.second)) {
+                            backMsg += ("回传失败:" + backResult.second);
+                        }
+                        update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
+                                .set(GameTencentAppApiOrder::getIsBack, backResult.first.getBackStatus())
+                                .set(GameTencentAppApiOrder::getBackMoney, backMoney)
+                                .set(GameTencentAppApiOrder::getBackMsg, backMsg)
+                                .eq(GameTencentAppApiOrder::getId, orderLog.getId())
+                        );
+                    }
+                });
+        return true;
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Tuple2<BackStatusEnum, String> doCallback(GameTencentAppApiOrder orderLog, LocalDateTime backTime, Long backMoney) {
+
+        GameTencentAppCallback callback = gameTencentAppCallbackService.getUserCallback(orderLog.getGameId(), orderLog.getImei(), orderLog.getOaid(), orderLog.getAndroidId(), orderLog.getIdfa(), orderLog.getCaid());
+        if(callback == null) {
+            return Tuple2.with(BackStatusEnum.FAILED, "找不到监测链接");
+        }
+        String callbackUrl = URIUtil.decodeURIComponent(callback.getCallback());
+
+        Map<String, Object> actionParam = new HashMap<>(2);
+        actionParam.put("claim_type", 4);
+        actionParam.put("value", backMoney);
+        TencentAppReport reportData = TencentAppReport.builder()
+                .actions(Collections.singletonList(TencentAppReport.Action.builder()
+                        .action_time(DateUtil.localDateTimeToSecond(orderLog.getRegisterTime()))
+                        .userr_id(TencentAppReport.UserId.builder()
+                                .hash_imei(StringUtils.isBlank(orderLog.getImei()) ? null : Md5Util.encrypt32(orderLog.getImei().toLowerCase()).toLowerCase())
+                                .hash_oaid(StringUtils.isBlank(orderLog.getOaid()) ? null : Md5Util.encrypt32(orderLog.getOaid()).toLowerCase())
+                                .hash_android_id(StringUtils.isBlank(orderLog.getAndroidId()) ? null : Md5Util.encrypt32(orderLog.getAndroidId()).toLowerCase())
+                                .hash_idfa(StringUtils.isBlank(orderLog.getIdfa()) ? null : Md5Util.encrypt32(orderLog.getIdfa().toUpperCase()).toLowerCase())
+                                .caid(orderLog.getCaid())
+                                .build())
+                        .action_type("PURCHASE")
+                        .trace(callback.getClickId())
+                        .action_param(actionParam)
+                        .build()))
+                .build();
+
+
+        BackStatusEnum backStatus;
+        String backLog;
+        try {
+            ResponseEntity<String> response = restTemplate.postForEntity(callbackUrl, reportData, String.class);
+            if (response.getStatusCode().is2xxSuccessful()) {
+                backStatus = BackStatusEnum.SUCCESS;
+                backLog = "回传成功";
+            } else {
+                backStatus = BackStatusEnum.FAILED;
+                backLog = "回传识别,失败信息:" + response.getBody();
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            backStatus = BackStatusEnum.FAILED;
+            backLog = "回传识别,失败原因:" + e.getMessage();
+        }
+
+        String actionType = ActionTypeEnum.PURCHASE.getActionType();
+
+        GameTencentAppApiBackLog gameTencentBackLog = GameTencentAppApiBackLog.builder()
+                .gameId(orderLog.getGameId())
+                .userId(orderLog.getUserId())
+                .adAccountId(orderLog.getAdAccountId())
+                .actionTime(backTime)
+                .createTime(LocalDateTime.now())
+                .actionType(actionType)
+                .orderId(orderLog.getOrderId())
+                .imei(orderLog.getImei())
+                .oaid(orderLog.getOaid())
+                .androidId(orderLog.getAndroidId())
+                .idfa(orderLog.getIdfa())
+                .caid(orderLog.getCaid())
+                .backLog(backLog)
+                .actionParam(actionParam.toString())
+                .build();
+        gameTencentAppApiBackLogService.save(gameTencentBackLog);
+        return Tuple2.with(backStatus, gameTencentBackLog.getBackLog());
+    }
+
+    public static class TencentOrderBackPolicyCheck implements BackPolicyUtil.IBackPolicyCheck {
+        private final IGameTencentAppApiOrderService gameTencentAppApiOrderService;
+        private final GameBackPolicy gameBackPolicy;
+        private final GameTencentAppApiUser userLog;
+        private final GameTencentAppApiOrder orderLog;
+
+        public TencentOrderBackPolicyCheck(IGameTencentAppApiOrderService gameTencentAppApiOrderService,
+                                           GameBackPolicy gameBackPolicy,
+                                           GameTencentAppApiUser userLog,
+                                           GameTencentAppApiOrder orderLog) {
+            this.gameTencentAppApiOrderService = gameTencentAppApiOrderService;
+            this.gameBackPolicy = gameBackPolicy;
+            this.userLog = userLog;
+            this.orderLog = orderLog;
+
+        }
+
+        @Override
+        public long backCountForFixedRate(int numberOfRound, BackUnitEnum backUnit, Boolean firstPolicy) {
+            numberOfRound = numberOfRound - 1;
+            if (backUnit == BackUnitEnum.UNIT_ONCE) {
+                return gameTencentAppApiOrderService.list(new LambdaQueryWrapper<GameTencentAppApiOrder>()
+                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
+                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
+                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
+                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                        .eq(GameTencentAppApiOrder::getIsFirstOrder, firstPolicy)
+                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
+                        .orderByDesc(GameTencentAppApiOrder::getCreateTime)
+                        .last("limit " + numberOfRound)
+                ).stream().filter(log -> log.getIsBack().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+            } else if (backUnit == BackUnitEnum.UNIT_DAY) {
+                return gameTencentAppApiOrderService.list(new LambdaQueryWrapper<GameTencentAppApiOrder>()
+                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
+                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
+                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
+                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                        .apply(firstPolicy, "date(recharge_time) = date(pay_time)")
+                        .apply(!firstPolicy, "date(recharge_time) != date(pay_time)")
+                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
+                        .orderByDesc(GameTencentAppApiOrder::getCreateTime)
+                        .last("limit " + numberOfRound)
+                ).stream().filter(log -> log.getIsBack().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+            } else if (backUnit == BackUnitEnum.UNIT_TIME_DAY) {
+                return gameTencentAppApiOrderService.list(new LambdaQueryWrapper<GameTencentAppApiOrder>()
+                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
+                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
+                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
+                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) < 24")
+                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) >= 24")
+                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
+                        .orderByDesc(GameTencentAppApiOrder::getCreateTime)
+                        .last("limit " + numberOfRound)
+                ).stream().filter(log -> log.getIsBack().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+            } else if (backUnit == BackUnitEnum.UNIT_TIME_2DAY) {
+                return gameTencentAppApiOrderService.list(new LambdaQueryWrapper<GameTencentAppApiOrder>()
+                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
+                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
+                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
+                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) < 48")
+                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) >= 48")
+                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
+                        .orderByDesc(GameTencentAppApiOrder::getCreateTime)
+                        .last("limit " + numberOfRound)
+                ).stream().filter(log -> log.getIsBack().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+            } else if (backUnit == BackUnitEnum.LARGE_AMOUNT) {
+                return gameTencentAppApiOrderService.list(new LambdaQueryWrapper<GameTencentAppApiOrder>()
+                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
+                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
+                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
+                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
+                        .orderByDesc(GameTencentAppApiOrder::getCreateTime)
+                        .last("limit " + numberOfRound)
+                ).stream().filter(log -> log.getIsBack().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+            } else {
+                throw new RuntimeException("不支持的回传单位[" + backUnit.getValue() + "]");
+            }
+        }
+
+        @Override
+        public long backCountForUser(BackUnitEnum backUnit, String userId, Boolean firstPolicy) {
+            if (backUnit == BackUnitEnum.UNIT_ONCE) {
+                if (firstPolicy) {
+                    // 首单直接返回 0,必定回传
+                    return 0;
+                }
+                return gameTencentAppApiOrderService.count(new LambdaQueryWrapper<GameTencentAppApiOrder>()
+                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
+                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
+                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
+                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                        .eq(GameTencentAppApiOrder::getIsBack, BackStatusEnum.SUCCESS.getBackStatus())
+                        .eq(GameTencentAppApiOrder::getUserId, userId)
+                        .eq(GameTencentAppApiOrder::getIsFirstOrder, firstPolicy)
+                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
+                );
+            } else if (backUnit == BackUnitEnum.UNIT_DAY) {
+                return gameTencentAppApiOrderService.count(new LambdaQueryWrapper<GameTencentAppApiOrder>()
+                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
+                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
+                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
+                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                        .eq(GameTencentAppApiOrder::getIsBack, BackStatusEnum.SUCCESS.getBackStatus())
+                        .eq(GameTencentAppApiOrder::getUserId, userId)
+                        .apply(firstPolicy, "date(recharge_time) = date(pay_time)")
+                        .apply(!firstPolicy, "date(recharge_time) != date(pay_time)")
+                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
+                );
+            } else if (backUnit == BackUnitEnum.UNIT_TIME_DAY) {
+                return gameTencentAppApiOrderService.count(new LambdaQueryWrapper<GameTencentAppApiOrder>()
+                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
+                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
+                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
+                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                        .eq(GameTencentAppApiOrder::getIsBack, BackStatusEnum.SUCCESS.getBackStatus())
+                        .eq(GameTencentAppApiOrder::getUserId, userId)
+                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) < 24")
+                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) >= 24")
+                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
+                );
+            } else if (backUnit == BackUnitEnum.UNIT_TIME_2DAY) {
+                return gameTencentAppApiOrderService.count(new LambdaQueryWrapper<GameTencentAppApiOrder>()
+                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
+                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
+                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
+                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                        .eq(GameTencentAppApiOrder::getIsBack, BackStatusEnum.SUCCESS.getBackStatus())
+                        .eq(GameTencentAppApiOrder::getUserId, userId)
+                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) < 48")
+                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) >= 48")
+                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
+                );
+            } else if (backUnit == BackUnitEnum.LARGE_AMOUNT) {
+                return gameTencentAppApiOrderService.count(new LambdaQueryWrapper<GameTencentAppApiOrder>()
+                        .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
+                        .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
+                        .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
+                        .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                        .eq(GameTencentAppApiOrder::getIsBack, BackStatusEnum.SUCCESS.getBackStatus())
+                        .eq(GameTencentAppApiOrder::getUserId, userId)
+                        .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
+                );
+            } else {
+                throw new RuntimeException("不支持的回传单位[" + backUnit.getValue() + "]");
+            }
+        }
+
+        @Override
+        public long markUpOfFixedRate(int numberOfRound, Long markUpTime) {
+            numberOfRound = numberOfRound - 1;
+            return gameTencentAppApiOrderService.list(new LambdaQueryWrapper<GameTencentAppApiOrder>()
+                    .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
+                    .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
+                    .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
+                    .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                    .apply("TIMESTAMPDIFF(MINUTE, recharge_time, pay_time) > {0}", markUpTime)
+                    .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
+                    .orderByDesc(GameTencentAppApiOrder::getCreateTime)
+                    .last("limit " + numberOfRound)
+            ).stream().filter(log -> log.getIsBack().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+        }
+
+        @Override
+        public long markUpForUser(String userId, Long markUpTime) {
+            return gameTencentAppApiOrderService.count(new LambdaQueryWrapper<GameTencentAppApiOrder>()
+                    .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
+                    .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
+                    .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
+                    .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                    .eq(GameTencentAppApiOrder::getIsBack, BackStatusEnum.SUCCESS.getBackStatus())
+                    .eq(GameTencentAppApiOrder::getUserId, userId)
+                    .apply("TIMESTAMPDIFF(MINUTE, recharge_time, pay_time) > {0}", markUpTime)
+                    .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
+            );
+        }
+
+        @Override
+        public Long totalRechargeAmount() {
+            return gameTencentAppApiOrderService.count(new QueryWrapper<GameTencentAppApiOrder>()
+                    .select("ifnull(sum(recharge_money), 0) as recharge_money").lambda()
+                    .eq(GameTencentAppApiOrder::getGameId, orderLog.getGameId())
+                    .eq(GameTencentAppApiOrder::getAdAccountId, orderLog.getAdAccountId())
+                    .eq(GameTencentAppApiOrder::getBackPolicyId, gameBackPolicy.getId())
+                    .eq(GameTencentAppApiOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                    .eq(GameTencentAppApiOrder::getUserId, orderLog.getUserId())
+                    .ne(GameTencentAppApiOrder::getOrderId, orderLog.getOrderId())
+            );
+        }
+    }
+}

+ 49 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentAppApiOrderSplitLogServiceImpl.java

@@ -0,0 +1,49 @@
+package com.zanxiang.game.back.serve.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zanxiang.game.back.serve.dao.mapper.GameTencentAppApiOrderSplitLogMapper;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppApiOrderSplitLog;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentOrderSplitLog;
+import com.zanxiang.game.back.serve.pojo.vo.GameTencentAppApiOrderSplitLogVO;
+import com.zanxiang.game.back.serve.pojo.vo.GameTencentOrderSplitLogVO;
+import com.zanxiang.game.back.serve.service.IGameTencentAppApiOrderSplitLogService;
+import com.zanxiang.module.util.NumberUtil;
+import com.zanxiang.module.util.bean.BeanUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class GameTencentAppApiOrderSplitLogServiceImpl extends ServiceImpl<GameTencentAppApiOrderSplitLogMapper, GameTencentAppApiOrderSplitLog>
+implements IGameTencentAppApiOrderSplitLogService {
+
+    @Override
+    public List<GameTencentAppApiOrderSplitLogVO> listByOrderNo(Collection<String> orderNos) {
+        if (CollectionUtils.isEmpty(orderNos)) {
+            return Collections.emptyList();
+        }
+        return list(new LambdaQueryWrapper<GameTencentAppApiOrderSplitLog>()
+                .in(GameTencentAppApiOrderSplitLog::getOrderNo, orderNos)
+                .orderByAsc(GameTencentAppApiOrderSplitLog::getBackIndex)
+        ).stream().map(this::toVOSimple).collect(Collectors.toList());
+    }
+
+    private GameTencentAppApiOrderSplitLogVO toVOSimple(GameTencentAppApiOrderSplitLog log) {
+        if (log == null) {
+            return null;
+        }
+        GameTencentAppApiOrderSplitLogVO vo = BeanUtil.copy(log, GameTencentAppApiOrderSplitLogVO.class);
+        if (log.getSplitMoney() != null) {
+            vo.setSplitMoney(NumberUtil.divide100(new BigDecimal(log.getSplitMoney())));
+        }
+        return vo;
+    }
+}

+ 49 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentAppApiRoleRegisterServiceImpl.java

@@ -0,0 +1,49 @@
+package com.zanxiang.game.back.serve.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zanxiang.game.back.serve.dao.mapper.GameTencentAppApiRoleRegisterMapper;
+import com.zanxiang.game.back.serve.pojo.entity.*;
+import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
+import com.zanxiang.game.back.serve.service.*;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@Service
+public class GameTencentAppApiRoleRegisterServiceImpl extends ServiceImpl<GameTencentAppApiRoleRegisterMapper, GameTencentAppApiRoleRegister>
+implements IGameTencentAppApiRoleRegisterService {
+
+    @Autowired
+    private IGameTencentAppApiUserService gameTencentAppApiUserService;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean roleRegisterBack(GameTencentAppApiRoleRegister roleRegisterLog) {
+        BackStatusEnum backStatus = doCallback(roleRegisterLog);
+        return update(new LambdaUpdateWrapper<GameTencentAppApiRoleRegister>()
+                .set(GameTencentAppApiRoleRegister::getIsBack, backStatus.getBackStatus())
+                .eq(GameTencentAppApiRoleRegister::getId, roleRegisterLog.getId())
+        );
+    }
+
+
+    private BackStatusEnum doCallback(GameTencentAppApiRoleRegister roleRegisterLog) {
+        GameTencentAppApiUser user = gameTencentAppApiUserService.getOne(new LambdaQueryWrapper<GameTencentAppApiUser>()
+                .eq(GameTencentAppApiUser::getGameId, roleRegisterLog.getGameId())
+                .eq(GameTencentAppApiUser::getUserId, roleRegisterLog.getUserId())
+                .eq(GameTencentAppApiUser::getAdAccountId, roleRegisterLog.getAdAccountId())
+                .orderByDesc(GameTencentAppApiUser::getCreateTime)
+                .last("limit 1")
+        );
+        if (user != null) {
+            if (BackStatusEnum.NO.getBackStatus().equals(user.getIsBack())) {
+                gameTencentAppApiUserService.userBack(user, true);
+            }
+        }
+        return BackStatusEnum.NO;
+    }
+}

+ 130 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentAppApiUserServiceImpl.java

@@ -0,0 +1,130 @@
+package com.zanxiang.game.back.serve.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zanxiang.game.back.serve.dao.mapper.GameTencentAppApiUserMapper;
+import com.zanxiang.game.back.serve.pojo.TencentAppReport;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppApiBackLog;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppApiUser;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppCallback;
+import com.zanxiang.game.back.serve.pojo.enums.ActionTypeEnum;
+import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
+import com.zanxiang.game.back.serve.service.IGameTencentAppApiBackLogService;
+import com.zanxiang.game.back.serve.service.IGameTencentAppApiUserService;
+import com.zanxiang.game.back.serve.service.IGameTencentAppCallbackService;
+import com.zanxiang.module.util.DateUtil;
+import com.zanxiang.module.util.URIUtil;
+import com.zanxiang.module.util.encryption.Md5Util;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.client.RestTemplate;
+
+import java.time.LocalDateTime;
+import java.util.Collections;
+import java.util.List;
+
+@Slf4j
+@Service
+public class GameTencentAppApiUserServiceImpl extends ServiceImpl<GameTencentAppApiUserMapper, GameTencentAppApiUser>
+implements IGameTencentAppApiUserService {
+    @Autowired
+    private IGameTencentAppApiBackLogService gameTencentAppApiBackLogService;
+    @Autowired
+    private IGameTencentAppCallbackService gameTencentAppCallbackService;
+    @Autowired
+    private RestTemplate restTemplate;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean userBack(GameTencentAppApiUser userLog, boolean mustBack) {
+        BackStatusEnum backStatus = doCallback(userLog, mustBack);
+        return update(new LambdaUpdateWrapper<GameTencentAppApiUser>()
+                .set(GameTencentAppApiUser::getIsBack, backStatus.getBackStatus())
+                .eq(GameTencentAppApiUser::getId, userLog.getId())
+        );
+    }
+
+    @Override
+    public boolean tencentUserReport(List<Long> ids) {
+        listByIds(ids).forEach(userLog -> {
+            BackStatusEnum backStatus = doCallback(userLog, true);
+            update(new LambdaUpdateWrapper<GameTencentAppApiUser>()
+                    .set(GameTencentAppApiUser::getIsBack, backStatus.getBackStatus())
+                    .eq(GameTencentAppApiUser::getId, userLog.getId())
+            );
+        });
+        return true;
+    }
+
+
+    private BackStatusEnum doCallback(GameTencentAppApiUser userLog, boolean mustBack) {
+        boolean isBack = mustBack ? false : gameTencentAppApiBackLogService.count(new LambdaQueryWrapper<GameTencentAppApiBackLog>()
+                .eq(GameTencentAppApiBackLog::getGameId, userLog.getGameId())
+                .eq(GameTencentAppApiBackLog::getUserId, userLog.getUserId())
+                .eq(GameTencentAppApiBackLog::getAdAccountId, userLog.getAdAccountId())
+                .eq(GameTencentAppApiBackLog::getBackLog, "回传成功")
+        ) > 0;
+        if (isBack) {
+            return BackStatusEnum.NO;
+        }
+        GameTencentAppCallback callback = gameTencentAppCallbackService.getUserCallback(userLog.getGameId(), userLog.getImei(), userLog.getOaid(), userLog.getAndroidId(), userLog.getIdfa(), userLog.getCaid());
+        if(callback == null) {
+            return BackStatusEnum.FAILED;
+        }
+        String callbackUrl = URIUtil.decodeURIComponent(callback.getCallback());
+
+        TencentAppReport reportData = TencentAppReport.builder()
+                .actions(Collections.singletonList(TencentAppReport.Action.builder()
+                        .action_time(DateUtil.localDateTimeToSecond(userLog.getRegisterTime()))
+                        .userr_id(TencentAppReport.UserId.builder()
+                                .hash_imei(StringUtils.isBlank(userLog.getImei()) ? null : Md5Util.encrypt32(userLog.getImei().toLowerCase()).toLowerCase())
+                                .hash_oaid(StringUtils.isBlank(userLog.getOaid()) ? null : Md5Util.encrypt32(userLog.getOaid()).toLowerCase())
+                                .hash_android_id(StringUtils.isBlank(userLog.getAndroidId()) ? null : Md5Util.encrypt32(userLog.getAndroidId()).toLowerCase())
+                                .hash_idfa(StringUtils.isBlank(userLog.getIdfa()) ? null : Md5Util.encrypt32(userLog.getIdfa().toUpperCase()).toLowerCase())
+                                .caid(userLog.getCaid())
+                                .build())
+                        .action_type("ACTIVATE_APP")
+                        .trace(callback.getClickId())
+                        .build()))
+                .build();
+
+        BackStatusEnum backStatus;
+        String backLog;
+        try {
+            ResponseEntity<String> response = restTemplate.postForEntity(callbackUrl, reportData, String.class);
+            if (response.getStatusCode().is2xxSuccessful()) {
+                backStatus = BackStatusEnum.SUCCESS;
+                backLog = "回传成功";
+            } else {
+                backStatus = BackStatusEnum.FAILED;
+                backLog = "回传识别,失败信息:" + response.getBody();
+            }
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            backStatus = BackStatusEnum.FAILED;
+            backLog = "回传识别,失败原因:" + e.getMessage();
+        }
+
+        GameTencentAppApiBackLog gameTencentBackLog = GameTencentAppApiBackLog.builder()
+                .gameId(userLog.getGameId())
+                .userId(userLog.getUserId())
+                .adAccountId(userLog.getAdAccountId())
+                .actionTime(userLog.getRegisterTime())
+                .createTime(LocalDateTime.now())
+                .actionType(ActionTypeEnum.REGISTER.getActionType())
+                .imei(userLog.getImei())
+                .oaid(userLog.getOaid())
+                .androidId(userLog.getAndroidId())
+                .idfa(userLog.getIdfa())
+                .caid(userLog.getCaid())
+                .backLog(backLog)
+                .build();
+        gameTencentAppApiBackLogService.save(gameTencentBackLog);
+        return backStatus;
+    }
+}

+ 32 - 14
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentAppCallbackServiceImpl.java

@@ -6,12 +6,17 @@ import com.zanxiang.game.back.serve.dao.mapper.GameTencentAppCallbackMapper;
 import com.zanxiang.game.back.serve.pojo.dto.GameTencentAppCallbackDTO;
 import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppCallback;
 import com.zanxiang.game.back.serve.service.IGameTencentAppCallbackService;
+import com.zanxiang.game.module.base.ServerInfo;
+import com.zanxiang.game.module.base.pojo.vo.AgentRpcVO;
+import com.zanxiang.game.module.base.rpc.IAgentRpc;
 import com.zanxiang.module.util.DateUtil;
 import com.zanxiang.module.util.JsonUtil;
 import com.zanxiang.module.util.bean.BeanUtil;
 import com.zanxiang.module.util.encryption.Md5Util;
+import com.zanxiang.module.util.pojo.ResultVO;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.dubbo.config.annotation.DubboReference;
 import org.apache.kafka.clients.producer.KafkaProducer;
 import org.apache.kafka.clients.producer.ProducerRecord;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -30,12 +35,25 @@ implements IGameTencentAppCallbackService {
     private String tencentAppCallbackTopic;
     @Autowired
     private KafkaProducer<String, String> kafkaProducer;
+    @DubboReference(providedBy = ServerInfo.SERVER_DUBBO_NAME)
+    private IAgentRpc agentRpc;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
     public boolean callback(GameTencentAppCallbackDTO dto) {
+        AgentRpcVO agent = agentRpc.getByTencentAccountId(dto.getAccountId()).getData();
+        if (agent == null) {
+            log.error("腾讯检测链接数据找不到渠道:{}", JsonUtil.toString(dto));
+        }
         GameTencentAppCallback appCallback = BeanUtil.copy(dto, GameTencentAppCallback.class);
-        appCallback.setDay(dto.getClickTime() == null || dto.getClickTime() < 1000 ? LocalDate.now() : DateUtil.milliToLocalDateTime(dto.getClickTime()).toLocalDate());
+        if (agent != null) {
+            appCallback.setAgentKey(agent.getAgentKey());
+            appCallback.setGameId(agent.getGameId());
+        } else {
+            appCallback.setAgentKey("-");
+            appCallback.setGameId(-1L);
+        }
+        appCallback.setDay(dto.getClickTime() == null || dto.getClickTime() < 1000 ? LocalDate.now() : DateUtil.secondToLocalDate(dto.getClickTime()));
         save(appCallback);
         try {
             kafkaProducer.send(new ProducerRecord<>(tencentAppCallbackTopic, dto.getAccountId().toString(), JsonUtil.toString(appCallback)));
@@ -45,21 +63,21 @@ implements IGameTencentAppCallbackService {
         return true;
     }
 
-    public GameTencentAppCallback getUserClickInfo(String imei, String oaid, String android, String idfa, String caid) {
-        LambdaQueryWrapper<GameTencentAppCallback> qw = new LambdaQueryWrapper<>();
-        if (StringUtils.isNoneBlank(imei)) {
-            qw.or().eq(GameTencentAppCallback::getMuid, Md5Util.encrypt32(imei.toLowerCase()).toLowerCase());
+    @Override
+    public GameTencentAppCallback getUserCallback(Long gameId, String imei, String oaid, String android, String idfa, String caid) {
+        LambdaQueryWrapper<GameTencentAppCallback> qw = new LambdaQueryWrapper<GameTencentAppCallback>()
+                .eq(GameTencentAppCallback::getGameId, gameId)
+                .orderByDesc(GameTencentAppCallback::getClickTime)
+                .last("limit 1");
+        if (StringUtils.isNoneBlank(imei) || StringUtils.isNoneBlank(android) || StringUtils.isNoneBlank(oaid)) {
+            qw.and(and -> {
+                and.eq(StringUtils.isNoneBlank(imei), GameTencentAppCallback::getMuid, StringUtils.isBlank(imei) ? null : Md5Util.encrypt32(imei.toLowerCase()).toLowerCase())
+                        .or().eq(StringUtils.isNoneBlank(android), GameTencentAppCallback::getHashAndroidId, StringUtils.isBlank(android) ? null : Md5Util.encrypt32(android).toLowerCase())
+                        .or().eq(StringUtils.isNoneBlank(oaid), GameTencentAppCallback::getHashOaid, StringUtils.isBlank(oaid) ? null : Md5Util.encrypt32(oaid).toLowerCase());
+            });
         } else if (StringUtils.isNoneBlank(idfa)) {
-            qw.or().eq(GameTencentAppCallback::getMuid, Md5Util.encrypt32(idfa).toLowerCase());
+            qw.eq(GameTencentAppCallback::getMuid, Md5Util.encrypt32(idfa).toLowerCase());
         }
-        if(StringUtils.isNoneBlank(android)) {
-            qw.or().eq(GameTencentAppCallback::getHashAndroidId, Md5Util.encrypt32(android).toLowerCase());
-        }
-        if(StringUtils.isNoneBlank(oaid)) {
-            qw.or().eq(GameTencentAppCallback::getHashOaid, Md5Util.encrypt32(oaid).toLowerCase());
-        }
-        qw.orderByDesc(GameTencentAppCallback::getClickTime)
-                .last("limit 1");
         return getOne(qw);
     }
 }

+ 0 - 6
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentUserServiceImpl.java

@@ -9,16 +9,12 @@ import com.zanxiang.advertising.tencent.base.AdvertisingTencentServer;
 import com.zanxiang.advertising.tencent.base.pojo.dto.DataReportOfAppIdRpcDTO;
 import com.zanxiang.advertising.tencent.base.pojo.dto.UserActionRpcDTO;
 import com.zanxiang.advertising.tencent.base.rpc.IUserActionSetRpc;
-import com.zanxiang.erp.base.ErpServer;
-import com.zanxiang.erp.base.rpc.ISysUserRpc;
 import com.zanxiang.game.back.serve.dao.mapper.GameTencentUserMapper;
 import com.zanxiang.game.back.serve.pojo.dto.GameTencentUserDTO;
 import com.zanxiang.game.back.serve.pojo.entity.GameTencentBackLog;
-import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameUser;
 import com.zanxiang.game.back.serve.pojo.entity.GameTencentUser;
 import com.zanxiang.game.back.serve.pojo.enums.ActionTypeEnum;
 import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
-import com.zanxiang.game.back.serve.pojo.vo.GameTencentMiniGameUserVO;
 import com.zanxiang.game.back.serve.pojo.vo.GameTencentUserVO;
 import com.zanxiang.game.back.serve.service.IGameTencentBackLogService;
 import com.zanxiang.game.back.serve.service.IGameTencentUserService;
@@ -60,8 +56,6 @@ public class GameTencentUserServiceImpl extends ServiceImpl<GameTencentUserMappe
 
     @DubboReference(providedBy = AdvertisingTencentServer.SERVER_DUBBO_NAME)
     private IUserActionSetRpc userActionSetRpc;
-    @DubboReference(providedBy = ErpServer.SERVER_DUBBO_NAME)
-    private ISysUserRpc sysUserRpc;
     @Autowired
     private IGameTencentBackLogService gameTencentBackLogService;
     @DubboReference(providedBy = ServerInfo.SERVER_DUBBO_NAME)

+ 113 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/task/TencentAppApiOrderSplitBackTask.java

@@ -0,0 +1,113 @@
+package com.zanxiang.game.back.serve.task;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.github.sd4324530.jtuple.Tuple2;
+import com.zanxiang.game.back.base.ServerInfo;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppApiOrder;
+import com.zanxiang.game.back.serve.pojo.entity.GameTencentAppApiOrderSplitLog;
+import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
+import com.zanxiang.game.back.serve.service.*;
+import com.zanxiang.module.redis.service.IDistributedLockComponent;
+import com.zanxiang.module.util.DateUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 头条订单拆分回传任务
+ */
+@Slf4j
+@Component
+public class TencentAppApiOrderSplitBackTask {
+    public static final String KEY = ServerInfo.SERVER_NAME + ":tencentAppApiOrderSplitBack:";
+
+    @Autowired
+    private IGameTencentAppApiOrderService gameTencentAppApiOrderService;
+    @Autowired
+    private IGameTencentAppApiOrderSplitLogService gameTencentAppApiOrderSplitLogService;
+
+    @Autowired
+    private IDistributedLockComponent distributedLockComponent;
+    @Autowired
+    private IGameTencentAppApiBackLogService gameTencentAppApiBackLogService;
+
+    @Scheduled(cron = "0 * * * * ?")
+    public void execute() {
+        LocalDateTime now = LocalDateTime.now().withSecond(0).withNano(0);
+        if (!distributedLockComponent.doLock(KEY + DateUtil.formatLocalDateTime(now))) {
+            return;
+        }
+        List<GameTencentAppApiOrderSplitLog> orderSplitLogList = gameTencentAppApiOrderSplitLogService.list(new LambdaQueryWrapper<GameTencentAppApiOrderSplitLog>()
+                .in(GameTencentAppApiOrderSplitLog::getBackDay, Arrays.asList(LocalDate.now().minusDays(1), LocalDate.now()))
+                .lt(GameTencentAppApiOrderSplitLog::getBackTime, now.plusMinutes(1))
+                .eq(GameTencentAppApiOrderSplitLog::getBackStatus, BackStatusEnum.NO.getBackStatus())
+                .orderByAsc(GameTencentAppApiOrderSplitLog::getOrderNo)
+                .orderByAsc(GameTencentAppApiOrderSplitLog::getBackTime)
+        );
+        if (CollectionUtils.isEmpty(orderSplitLogList)) {
+            return;
+        }
+        log.error("准备回传分拆订单:{}", orderSplitLogList.size());
+        List<GameTencentAppApiOrder> orderList = gameTencentAppApiOrderService.list(new LambdaQueryWrapper<GameTencentAppApiOrder>()
+                .in(GameTencentAppApiOrder::getOrderId, orderSplitLogList.stream().map(GameTencentAppApiOrderSplitLog::getOrderNo).collect(Collectors.toSet()))
+        );
+        Map<String, GameTencentAppApiOrder> orderMap = new HashMap<>(orderList.size());
+        orderList.forEach(order -> orderMap.put(order.getOrderId(), order));
+
+        orderSplitLogList.forEach(orderSplitLog -> {
+            callback(orderMap.get(orderSplitLog.getOrderNo()), orderSplitLog);
+        });
+    }
+
+    private void callback(GameTencentAppApiOrder order, GameTencentAppApiOrderSplitLog orderSplitLog) {
+        log.error("开始回传拆分订单:{}-{}", orderSplitLog.getOrderNo(), orderSplitLog.getBackIndex());
+        try {
+            Tuple2<BackStatusEnum, String> backResult = gameTencentAppApiOrderService.doCallback(order, orderSplitLog.getBackTime(), orderSplitLog.getSplitMoney());
+            gameTencentAppApiOrderSplitLogService.update(new LambdaUpdateWrapper<GameTencentAppApiOrderSplitLog>()
+                    .set(GameTencentAppApiOrderSplitLog::getExecuteTime, LocalDateTime.now())
+                    .set(GameTencentAppApiOrderSplitLog::getBackStatus, backResult.first.getBackStatus())
+                    .set(GameTencentAppApiOrderSplitLog::getBackErrorMsg, backResult.second)
+                    .eq(GameTencentAppApiOrderSplitLog::getId, orderSplitLog.getId())
+            );
+            if (backResult.first == BackStatusEnum.SUCCESS) {
+                gameTencentAppApiOrderService.update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
+                        .set(GameTencentAppApiOrder::getIsBack, backResult.first.getBackStatus())
+                        .eq(GameTencentAppApiOrder::getId, order.getId())
+                );
+            } else {
+                gameTencentAppApiOrderService.update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
+                        .set(GameTencentAppApiOrder::getIsBack, BackStatusEnum.SUCCESS_PART.getBackStatus())
+                        .eq(GameTencentAppApiOrder::getId, order.getId())
+                );
+            }
+            log.error("订单回传完成:{}-{}, {}-{}", orderSplitLog.getOrderNo(), orderSplitLog.getBackIndex(), backResult.first, backResult.second);
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+            try {
+                gameTencentAppApiOrderSplitLogService.update(new LambdaUpdateWrapper<GameTencentAppApiOrderSplitLog>()
+                        .set(GameTencentAppApiOrderSplitLog::getExecuteTime, LocalDateTime.now())
+                        .set(GameTencentAppApiOrderSplitLog::getBackStatus, BackStatusEnum.FAILED.getBackStatus())
+                        .set(GameTencentAppApiOrderSplitLog::getBackErrorMsg, e.getMessage())
+                        .eq(GameTencentAppApiOrderSplitLog::getId, orderSplitLog.getId())
+                );
+                gameTencentAppApiOrderService.update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
+                        .set(GameTencentAppApiOrder::getIsBack, BackStatusEnum.SUCCESS_PART.getBackStatus())
+                        .eq(GameTencentAppApiOrder::getId, order.getId())
+                );
+            } catch (Exception ex) {
+                log.error(ex.getMessage(), ex);
+            }
+        }
+    }
+}

+ 3 - 1
game-module/game-module-base/src/main/java/com/zanxiang/game/module/base/pojo/enums/AccountTypeEnum.java

@@ -15,7 +15,9 @@ public enum AccountTypeEnum {
     // 腾讯APP
     TENCENT_APP(4),
     // 头条APP
-    BYTE_APP(5)
+    BYTE_APP(5),
+    // 腾讯APP(企微信链路)
+    TENCENT_APP_API(6),
     ;
 
     private final Integer value;

+ 4 - 0
game-module/game-module-base/src/main/java/com/zanxiang/game/module/base/rpc/IAgentRpc.java

@@ -8,4 +8,8 @@ import java.util.List;
 public interface IAgentRpc {
 
     ResultVO<List<AgentRpcVO>> getByAgentKeys(List<String> agentKeys);
+
+    ResultVO<AgentRpcVO>  getByByteAccountId(Long accountId);
+
+    ResultVO<AgentRpcVO>  getByTencentAccountId(Long accountId);
 }

+ 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服务启动成功 < (虚拟游戏更改为可接待03・・)ノ(._.`) \n" +
+        System.out.println("赞象Manage服务启动成功 < (服务器迁移, 修正DUBBO通信问题・・)ノ(._.`) \n" +
                 "___  ___  ___   _   _   ___  _____  _____ \n" +
                 "|  \\/  | / _ \\ | \\ | | / _ \\|  __ \\|  ___|\n" +
                 "| .  . |/ /_\\ \\|  \\| |/ /_\\ \\ |  \\/| |__  \n" +

+ 18 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/rpc/impl/AgentRpcImpl.java

@@ -1,6 +1,7 @@
 package com.zanxiang.game.module.manage.rpc.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.zanxiang.game.module.base.pojo.enums.AccountTypeEnum;
 import com.zanxiang.game.module.base.pojo.vo.AgentRpcVO;
 import com.zanxiang.game.module.base.rpc.IAgentRpc;
 import com.zanxiang.game.module.manage.service.IAgentService;
@@ -11,6 +12,7 @@ import org.apache.commons.collections4.CollectionUtils;
 import org.apache.dubbo.config.annotation.DubboService;
 import org.springframework.beans.factory.annotation.Autowired;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -19,6 +21,22 @@ public class AgentRpcImpl implements IAgentRpc {
     @Autowired
     private IAgentService agentService;
 
+    @Override
+    public ResultVO<AgentRpcVO>  getByByteAccountId(Long accountId) {
+        return ResultVO.ok(toVOSimple(agentService.getOne(new LambdaQueryWrapper<Agent>()
+                .eq(Agent::getAccountId, accountId)
+                .in(Agent::getAccountType, Arrays.asList(AccountTypeEnum.BYTE.getValue(), AccountTypeEnum.BYTE_APP.getValue()))
+        )));
+    }
+
+    @Override
+    public ResultVO<AgentRpcVO>  getByTencentAccountId(Long accountId) {
+        return ResultVO.ok(toVOSimple(agentService.getOne(new LambdaQueryWrapper<Agent>()
+                .eq(Agent::getAccountId, accountId)
+                .in(Agent::getAccountType, Arrays.asList(AccountTypeEnum.TENCENT_H5.getValue(), AccountTypeEnum.TENCENT_MINI_GAME.getValue(), AccountTypeEnum.TENCENT_APP.getValue(), AccountTypeEnum.TENCENT_APP_API.getValue()))
+        )));
+    }
+
     @Override
     public ResultVO<List<AgentRpcVO>> getByAgentKeys(List<String> agentKeys) {
         if (CollectionUtils.isEmpty(agentKeys)) {

+ 1 - 0
game-module/game-module-manage/src/main/java/com/zanxiang/game/module/manage/service/impl/GameServerServiceImpl.java

@@ -111,6 +111,7 @@ public class GameServerServiceImpl extends ServiceImpl<GameServerMapper, GameSer
                         GameServer::getCustomerIds, userIds));
         //新增保存指派记录
         gameServerAssignLogService.save(GameServerAssignLog.builder()
+                .gameId(gameServer.getGameId())
                 .serverId(gameServer.getServerId())
                 .assignType(param.getAssignType().getValue())
                 .oldUserIds(oldUserIds)

+ 84 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/CpPushErrorLog.java

@@ -0,0 +1,84 @@
+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-06-27
+ * @description : CP推送数据错误日志
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@ToString
+@Builder
+@TableName("t_cp_push_error_log")
+public class CpPushErrorLog implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    public final static Integer STATUS_VALID = 0;
+    public final static Integer STATUS_INVALID = 1;
+
+    /**
+     * id
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 数据分类
+     */
+    private String dataType;
+
+    /**
+     * 游戏id
+     */
+    private Long gameId;
+
+    /**
+     * 玩家应用唯一标识
+     */
+    private String openId;
+
+    /**
+     * 订单id
+     */
+    private String orderId;
+
+    /**
+     * 区服id
+     */
+    private String serverId;
+
+    /**
+     * 角色id
+     */
+    private String roleId;
+
+    /**
+     * 请求参数
+     */
+    private String param;
+
+    /**
+     * 异常消息
+     */
+    private String errorMsg;
+
+    /**
+     * 有效状态, 0 : 有效, 1 : 无效,可删除
+     */
+    private Integer status;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+}

+ 16 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/Game.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.*;
 import lombok.*;
 
 import java.io.Serializable;
+import java.math.BigDecimal;
 import java.time.LocalDateTime;
 
 /**
@@ -107,6 +108,11 @@ public class Game implements Serializable {
      */
     private String h5GameConfig;
 
+    /**
+     * 广告媒体sdk配置
+     */
+    private String adSdkConfig;
+
     /**
      * 超父游戏id
      */
@@ -137,4 +143,14 @@ public class Game implements Serializable {
      */
     private String appType;
 
+    /**
+     * 是否虚拟游戏
+     */
+    private Boolean isUnrealGame;
+
+    /**
+     * 充值折扣
+     */
+    private BigDecimal rechargeRebate;
+
 }

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

@@ -34,6 +34,11 @@ public class GameServerAssignLog implements Serializable {
      */
     private String assignType;
 
+    /**
+     * 游戏id
+     */
+    private Long gameId;
+
     /**
      * 区服id
      */

+ 15 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/User.java

@@ -151,11 +151,26 @@ public class User implements Serializable {
      */
     private String imei;
 
+    /**
+     * 设备OAID
+     */
+    private String oaid;
+
     /**
      * 安卓id, (仅安卓设备才有值)
      */
     private String androidId;
 
+    /**
+     * IOS设备IDFA
+     */
+    private String idfa;
+
+    /**
+     * IOS设备CAID
+     */
+    private String caid;
+
     /**
      * 注册时间
      */

+ 12 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/mapper/CpPushErrorLogMapper.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.CpPushErrorLog;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-06-27
+ * @description : CP推送数据错误日志
+ */
+public interface CpPushErrorLogMapper extends BaseMapper<CpPushErrorLog> {
+}

+ 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服务启动成功 <创角取消使用事件通知> ( ´・・)ノ(._.`) \n" +
+        System.out.println("赞象SDK服务启动成功 <斗罗归因判断问题解决01> ( ´・・)ノ(._.`) \n" +
                 " ___________ _   __\n" +
                 "/  ___|  _  \\ | / /\n" +
                 "\\ `--.| | | | |/ / \n" +

+ 3 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/adapter/ArgumentAdapter.java

@@ -72,7 +72,10 @@ public class ArgumentAdapter implements HandlerMethodArgumentResolver {
                 .deviceSystem(request.getHeader("os"))
                 .mac(request.getHeader("mac"))
                 .imei(request.getHeader("imei"))
+                .oaid(request.getHeader("oaid"))
                 .androidId(request.getHeader("androidId"))
+                .idfa(request.getHeader("idfa"))
+                .caid(request.getHeader("caid"))
                 .channel(request.getHeader("channel"))
                 .build();
         //不需要登录, token不存在

+ 50 - 2
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/adapter/WebHandlerAdapter.java

@@ -2,6 +2,7 @@ package com.zanxiang.game.module.sdk.adapter;
 
 import com.zanxiang.game.module.base.pojo.enums.HttpStatusEnum;
 import com.zanxiang.game.module.mybatis.entity.GameExt;
+import com.zanxiang.game.module.sdk.annotation.PushDataCheck;
 import com.zanxiang.game.module.sdk.annotation.UnSignCheck;
 import com.zanxiang.game.module.sdk.enums.DeviceTypeEnum;
 import com.zanxiang.game.module.sdk.service.IGameExtService;
@@ -36,9 +37,13 @@ public class WebHandlerAdapter implements HandlerInterceptor {
     @Override
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
         HandlerMethod handlerMethod = (HandlerMethod) handler;
-        //排除签名认证接口注解
-        UnSignCheck unSignCheck = handlerMethod.getMethod().getAnnotation(UnSignCheck.class);
+        //数据推送请求加密验证
+        PushDataCheck pushDataCheck = handlerMethod.getMethod().getAnnotation(PushDataCheck.class);
+        if (pushDataCheck != null) {
+            this.pushCheck(request);
+        }
         //接口签名验证
+        UnSignCheck unSignCheck = handlerMethod.getMethod().getAnnotation(UnSignCheck.class);
         if (unSignCheck == null) {
             return this.signCheck(request);
         }
@@ -77,4 +82,47 @@ public class WebHandlerAdapter implements HandlerInterceptor {
         }
         return Boolean.TRUE;
     }
+
+    private void pushCheck(HttpServletRequest request) throws Exception {
+        String sign = request.getParameter("sign");
+        String gameId = request.getParameter("gameId");
+        String timestamp = request.getParameter("timestamp");
+        String nonce = request.getParameter("nonce");
+        String server = request.getParameter("server");
+        //检查加密必传参数
+        if (StringUtils.isAnyBlank(gameId, timestamp, nonce, sign, server)) {
+            log.error("参数非法, 缺少必传参数");
+            throw new BaseException(HttpStatusEnum.INVALID_PARAMS.getMsg());
+        }
+        //判断时间戳是否有效
+//        if (Long.valueOf(timestamp) + 300L > System.currentTimeMillis() / 1000) {
+//            throw new BaseException(HttpStatusEnum.INVALID_PARAMS.getMsg());
+//        }
+        //签名验证
+        GameExt gameExt = gameExtService.getByGameAppId(gameId);
+        if (gameExt == null || Strings.isBlank(gameExt.getLoginKey())) {
+            throw new BaseException(HttpStatusEnum.INVALID_PARAMS.getMsg());
+        }
+        //密钥
+        String key = null;
+        String keyName = null;
+        if (Objects.equals(server, "0")) {
+            keyName = "appKey=";
+            key = gameExt.getAppKey();
+        }
+        if (Objects.equals(server, "1")) {
+            keyName = "loginKey=";
+            key = gameExt.getLoginKey();
+        }
+        if (StringUtils.isAnyBlank(key, keyName)) {
+            throw new BaseException(HttpStatusEnum.INVALID_PARAMS.getMsg());
+        }
+        String str = keyName + key + "&gameId=" + gameId + "&timestamp=" + timestamp + "&nonce=" + nonce + "&server=" + server;
+        String mySign = SignUtil.MD5(str);
+        //签名对比
+        if (!Objects.equals(mySign, sign)) {
+            log.error("非法参数, pushCheck签名错误, mySign : {}, sign : {}, str : {}", mySign, sign, str);
+            throw new BaseException(HttpStatusEnum.INVALID_PARAMS.getMsg());
+        }
+    }
 }

+ 14 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/annotation/PushDataCheck.java

@@ -0,0 +1,14 @@
+package com.zanxiang.game.module.sdk.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-06-25
+ * @description : 推送接口签名检测
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface PushDataCheck {
+}

+ 14 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/constant/RedisKeyConstant.java

@@ -72,4 +72,18 @@ public class RedisKeyConstant {
      */
     public static final String TOKEN_CREATE_LOCK = RedisKeyConstant.REDIS_PREFIX + "create_token_lock_";
 
+    /**
+     * 订单创建锁
+     */
+    public static final String ORDER_CREATE_LOCK = RedisKeyConstant.REDIS_PREFIX + "order_create_lock_";
+
+    /**
+     * 回调判断锁
+     */
+    public static final String CALL_BACK_JUDGE_LOCK = RedisKeyConstant.REDIS_PREFIX + "call_back_judge_lock_";
+
+    /**
+     * CP推送数据错误日志删除锁
+     */
+    public static final String CP_PUSH_ERROR_LOG_LOCK = RedisKeyConstant.REDIS_PREFIX + "cp_push_error_log_lock";
 }

+ 53 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/controller/CallBackController.java

@@ -0,0 +1,53 @@
+package com.zanxiang.game.module.sdk.controller;
+
+import com.zanxiang.game.module.sdk.annotation.ValidLogin;
+import com.zanxiang.game.module.sdk.pojo.param.CallBackControlParam;
+import com.zanxiang.game.module.sdk.pojo.param.UserData;
+import com.zanxiang.game.module.sdk.service.ICallBackService;
+import com.zanxiang.game.module.sdk.service.IGameService;
+import com.zanxiang.module.util.JsonUtil;
+import com.zanxiang.module.util.pojo.ResultVO;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-06-26
+ * @description : 回传相关接口
+ */
+@Api(tags = "回传控制相关接口")
+@RestController
+@Slf4j
+@RequestMapping(value = "/api/ad/back")
+public class CallBackController {
+
+    @Autowired
+    private IGameService gameService;
+
+    @Autowired
+    private ICallBackService callBackService;
+
+    @ApiOperation(value = "获取游戏广告媒体回传sdk配置")
+    @GetMapping("/ad/sdk/config")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = Map.class)})
+    public ResultVO<Map<String, Object>> getAdSdkConfig(UserData userData) {
+        return ResultVO.ok(gameService.getAdSdkConfig(userData));
+    }
+
+    @ApiOperation(value = "判断事件是否回传")
+    @PostMapping("/call/judge")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = Boolean.class)})
+    public ResultVO<Map<String, Object>> callBackJudge(@Validated @RequestBody CallBackControlParam param, @ValidLogin UserData userData) {
+        ResultVO<Map<String, Object>> ok = ResultVO.ok(callBackService.callBackJudge(param, userData));
+        log.error("事件回传判断结果, param : {}, 返回结果 ok : {}", JsonUtil.toString(param), JsonUtil.toString(ok));
+        return ok;
+    }
+}

+ 53 - 2
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/controller/PushController.java

@@ -1,8 +1,11 @@
 package com.zanxiang.game.module.sdk.controller;
 
+import com.zanxiang.game.module.sdk.annotation.PushDataCheck;
 import com.zanxiang.game.module.sdk.annotation.UnSignCheck;
-import com.zanxiang.game.module.sdk.pojo.param.GameRemitLogParam;
-import com.zanxiang.game.module.sdk.pojo.param.UserVisitLogParam;
+import com.zanxiang.game.module.sdk.pojo.param.*;
+import com.zanxiang.game.module.sdk.pojo.vo.CpPushResultVO;
+import com.zanxiang.game.module.sdk.pojo.vo.CpPushUserVO;
+import com.zanxiang.game.module.sdk.service.ICpPushDataService;
 import com.zanxiang.game.module.sdk.service.IGameRemitLogService;
 import com.zanxiang.game.module.sdk.service.IUserVisitLogService;
 import com.zanxiang.module.util.pojo.ResultVO;
@@ -26,6 +29,9 @@ import javax.servlet.http.HttpServletRequest;
 @RequestMapping(value = "/api")
 public class PushController {
 
+    @Autowired
+    private ICpPushDataService cpPushDataService;
+
     @Autowired
     private IGameRemitLogService gameRemitLogService;
 
@@ -50,4 +56,49 @@ public class PushController {
         return ResultVO.ok(userVisitLogService.visitLogCreate(param.getUrl(), userAgent, httpServletRequest));
     }
 
+    @UnSignCheck
+    @PushDataCheck
+    @ApiOperation(value = "玩家注册 / 登录信息推送")
+    @PostMapping("/cp/push/user")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = Boolean.class)})
+    public ResultVO<CpPushUserVO> cpPushUser(@RequestParam String gameId, @Validated @RequestBody CpPushUserParam param) {
+        return ResultVO.ok(cpPushDataService.pushUser(gameId, param));
+    }
+
+    @UnSignCheck
+    @PushDataCheck
+    @ApiOperation(value = "玩家角色信息推送")
+    @PostMapping("/cp/push/role")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = Boolean.class)})
+    public ResultVO<CpPushResultVO> cpPushRole(@RequestParam String gameId, @Validated @RequestBody CpPushRoleParam param) {
+        return ResultVO.ok(cpPushDataService.pushRole(gameId, param));
+    }
+
+    @UnSignCheck
+    @PushDataCheck
+    @ApiOperation(value = "玩家订单信息推送")
+    @PostMapping("/cp/push/order")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = Boolean.class)})
+    public ResultVO<CpPushResultVO> cpPushOrder(@RequestParam String gameId, @Validated @RequestBody CpPushOrderParam param) {
+        return ResultVO.ok(cpPushDataService.pushOrder(gameId, param));
+    }
+
+    @UnSignCheck
+    @PushDataCheck
+    @ApiOperation(value = "开服信息推送")
+    @PostMapping("/cp/push/server")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = Boolean.class)})
+    public ResultVO<CpPushResultVO> cpPushServer(@RequestParam String gameId, @Validated @RequestBody CpPushServerParam param) {
+        return ResultVO.ok(cpPushDataService.pushServer(gameId, param));
+    }
+
+    @UnSignCheck
+    @PushDataCheck
+    @ApiOperation(value = "玩家活跃信息推送")
+    @PostMapping("/cp/push/active")
+    @ApiResponses(value = {@ApiResponse(code = 200, message = "成功", response = Boolean.class)})
+    public ResultVO<CpPushResultVO> cpPushActive(@RequestParam String gameId, @Validated @RequestBody CpPushActiveParam param) {
+        return ResultVO.ok(cpPushDataService.pushActive(gameId, param));
+    }
+
 }

+ 39 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/enums/CallBackTypeEnum.java

@@ -0,0 +1,39 @@
+package com.zanxiang.game.module.sdk.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-06-26
+ * @description : 回传类型枚举
+ */
+@Getter
+@AllArgsConstructor
+public enum CallBackTypeEnum {
+
+    /**
+     * 注册(新创建账号)
+     */
+    CALL_BACK_REGISTER("CALL_BACK_REGISTER"),
+
+    /**
+     * 激活(创建角色)
+     */
+    CALL_BACK_ACTIVATE("CALL_BACK_ACTIVATE"),
+
+    /**
+     * 登录(老账号登录)
+     */
+    CALL_BACK_LOGIN_IN("CALL_BACK_LOGIN_IN"),
+
+    /**
+     * 支付
+     */
+    CALL_BACK_PAY_ORDER("CALL_BACK_PAY_ORDER");
+
+    /**
+     * 枚举值
+     */
+    private String value;
+}

+ 44 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/enums/CpPushDataEnum.java

@@ -0,0 +1,44 @@
+package com.zanxiang.game.module.sdk.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-06-27
+ * @description : CP推送数据类型枚举
+ */
+@Getter
+@AllArgsConstructor
+public enum CpPushDataEnum {
+
+    /**
+     * 玩家数据
+     */
+    CP_PUSH_DATA_USER("CP_PUSH_DATA_USER"),
+
+    /**
+     * 玩家角色数据
+     */
+    CP_PUSH_DATA_ROLE("CP_PUSH_DATA_ROLE"),
+
+    /**
+     * 玩家角色订单数据
+     */
+    CP_PUSH_DATA_ORDER("CP_PUSH_DATA_ORDER"),
+
+    /**
+     * 区服数据
+     */
+    CP_PUSH_DATA_SERVER("CP_PUSH_DATA_SERVER"),
+
+    /**
+     * 玩家活跃数据
+     */
+    CP_PUSH_DATA_ACTIVE("CP_PUSH_DATA_ACTIVE");
+
+    /**
+     * 枚举值
+     */
+    private String value;
+}

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

@@ -0,0 +1,31 @@
+package com.zanxiang.game.module.sdk.pojo.param;
+
+import com.zanxiang.game.module.sdk.enums.CallBackTypeEnum;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-06-26
+ * @description : 回传控制请求参数
+ */
+@Data
+public class CallBackControlParam {
+
+    /**
+     * 用户行为回传类型
+     */
+    @NotNull(message = "用户行为回传类型不可为空")
+    private CallBackTypeEnum callBackTypeEnum;
+
+    /**
+     * 订单id, 当行为类型为下单, 支付时, 则订单id必传
+     */
+    private String orderId;
+
+    /**
+     * 角色id, 当行为类型为激活(创建角色)时, 需要传
+     */
+    private String roleId;
+}

+ 32 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/CpPushActiveParam.java

@@ -0,0 +1,32 @@
+package com.zanxiang.game.module.sdk.pojo.param;
+
+import lombok.Data;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-06-25
+ * @description : CP推送玩家活跃数据
+ */
+@Data
+public class CpPushActiveParam {
+
+    /**
+     * 玩家应用唯一标识
+     */
+    private String openId;
+
+    /**
+     * 区服id
+     */
+    private String serverId;
+
+    /**
+     * 角色id
+     */
+    private String roleId;
+
+    /**
+     * 活跃类型 : 0 上线, 1 下线
+     */
+    private Integer activeType;
+}

+ 70 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/CpPushOrderParam.java

@@ -0,0 +1,70 @@
+package com.zanxiang.game.module.sdk.pojo.param;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-06-25
+ * @description : CP推送玩家订单数据
+ */
+@Data
+public class CpPushOrderParam {
+
+    /**
+     * 玩家应用唯一标识
+     */
+    private String openId;
+
+    /**
+     * 订单id
+     */
+    private String orderId;
+
+    /**
+     * 订单状态
+     */
+    private Integer status;
+
+    /**
+     * 支付时间
+     */
+    private LocalDateTime payTime;
+
+    /**
+     * 产品id
+     */
+    private String productId;
+
+    /**
+     * 产品名称
+     */
+    private String productName;
+
+    /**
+     * 订单金额
+     */
+    private BigDecimal amount;
+
+    /**
+     * 区服id
+     */
+    private String serverId;
+
+    /**
+     * 角色id
+     */
+    private String roleId;
+
+    /**
+     * 下单时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 扩展字段
+     */
+    private String extension;
+}

+ 73 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/CpPushRoleParam.java

@@ -0,0 +1,73 @@
+package com.zanxiang.game.module.sdk.pojo.param;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-06-24
+ * @description : CP推送角色数据
+ */
+@Data
+public class CpPushRoleParam {
+
+    /**
+     * 玩家唯一应用标识
+     */
+    @NotBlank(message = "玩家openId不可为空")
+    private String openId;
+
+    /**
+     * 角色id
+     */
+    @NotBlank(message = "角色id不可为空")
+    private String roleId;
+
+    /**
+     * 角色名称
+     */
+    @NotBlank(message = "角色名称不可为空")
+    private String roleName;
+
+    /**
+     * 角色等级
+     */
+    @NotNull(message = "角色等级不可为空")
+    private Long roleLevel;
+
+    /**
+     * 区服id
+     */
+    @NotBlank(message = "区服id不可为空")
+    private String serverId;
+
+    /**
+     * 区服名称
+     */
+    @NotBlank(message = "区服名称不可为空")
+    private String serverName;
+
+    /**
+     * 角色创建时间
+     */
+    @NotNull(message = "角色创建时间不可为空")
+    private LocalDateTime createTime;
+
+    /**
+     * 角色战力
+     */
+    private Long rolePower;
+
+    /**
+     * 角色VIP等级
+     */
+    private Long roleVipLevel;
+
+    /**
+     * 角色拓展信息
+     */
+    private Object extra;
+}

+ 34 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/CpPushServerParam.java

@@ -0,0 +1,34 @@
+package com.zanxiang.game.module.sdk.pojo.param;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-06-24
+ * @description : CP推送区服数据
+ */
+@Data
+public class CpPushServerParam {
+
+    /**
+     * 区服id
+     */
+    private String serverId;
+
+    /**
+     * 区服名称
+     */
+    private String serverName;
+
+    /**
+     * 开服时间
+     */
+    private LocalDateTime startTime;
+
+    /**
+     * 区服冠名
+     */
+    private String nickName;
+}

+ 62 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/CpPushUserParam.java

@@ -0,0 +1,62 @@
+package com.zanxiang.game.module.sdk.pojo.param;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-06-20
+ * @description : CP推送玩家数据
+ */
+@Data
+public class CpPushUserParam {
+
+    /**
+     * 玩家唯一应用标识
+     */
+    @NotBlank(message = "玩家openId不可为空")
+    private String openId;
+
+    /**
+     * 玩家注册时间
+     */
+    @NotNull(message = "玩家注册时间不可为空")
+    private LocalDateTime regTime;
+
+    /**
+     * 最近活跃时间
+     */
+    @NotNull(message = "最近活跃时间不可为空")
+    private LocalDateTime activeTime;
+
+    /**
+     * 广告渠道
+     */
+    @NotBlank(message = "广告渠道channel不可为空")
+    private String channel;
+
+    /**
+     * 网络IP
+     */
+    @NotBlank(message = "网络IP不可为空")
+    private String ip;
+
+    /**
+     * 请求UA
+     */
+    private String ua;
+
+    /**
+     * 操作系统
+     */
+    @NotBlank(message = "操作系统不可为空")
+    private String os;
+
+    /**
+     * 分享玩家openId
+     */
+    private String shareOpenId;
+}

+ 15 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/param/UserData.java

@@ -70,11 +70,26 @@ public class UserData implements Serializable {
      */
     private String imei;
 
+    /**
+     * 设备OAID
+     */
+    private String oaid;
+
     /**
      * 安卓id, (仅安卓设备才有值)
      */
     private String androidId;
 
+    /**
+     * IOS设备IDFA
+     */
+    private String idfa;
+
+    /**
+     * IOS设备CAID
+     */
+    private String caid;
+
     /**
      * 用户渠道唯一标识
      */

+ 23 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/vo/CpPushResultVO.java

@@ -0,0 +1,23 @@
+package com.zanxiang.game.module.sdk.pojo.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-06-24
+ * @description : 接口结果
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class CpPushResultVO {
+
+    /**
+     * 接口结果
+     */
+    private Boolean result;
+}

+ 33 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/vo/CpPushUserVO.java

@@ -0,0 +1,33 @@
+package com.zanxiang.game.module.sdk.pojo.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-06-20
+ * @description : CP推送玩家消息结果
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class CpPushUserVO {
+
+    /**
+     * sdk唯一用户标识
+     */
+    private Long userId;
+
+    /**
+     * 是否sdk用户
+     */
+    private Boolean sdkUser;
+
+    /**
+     * 买量渠道标识
+     */
+    private String channel;
+}

+ 6 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/pojo/vo/UserLoginVO.java

@@ -88,4 +88,10 @@ public class UserLoginVO {
      */
     @ApiModelProperty(notes = "小游戏壳包控制开关")
     private Integer appletShellSwitch;
+
+    /**
+     * 是否注册用户
+     */
+    @ApiModelProperty(notes = "是否注册用户")
+    private Boolean regUser;
 }

+ 11 - 2
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/ICallBackService.java

@@ -3,6 +3,7 @@ package com.zanxiang.game.module.sdk.service;
 import com.zanxiang.game.module.mybatis.entity.GameUserRole;
 import com.zanxiang.game.module.mybatis.entity.User;
 import com.zanxiang.game.module.sdk.pojo.dto.PlatformOrderDTO;
+import com.zanxiang.game.module.sdk.pojo.param.CallBackControlParam;
 import com.zanxiang.game.module.sdk.pojo.param.UserData;
 
 import java.util.Map;
@@ -14,6 +15,15 @@ import java.util.Map;
  */
 public interface ICallBackService {
 
+    /**
+     * 回传判断
+     *
+     * @param param    : 参数
+     * @param userData : 玩家信息
+     * @return : 返回是否回传
+     */
+    Map<String, Object> callBackJudge(CallBackControlParam param, UserData userData);
+
     /**
      * 用户回传
      *
@@ -26,9 +36,8 @@ public interface ICallBackService {
      * 创角回传
      *
      * @param gameUserRole : 角色信息
-     * @param userData     : 用户信息
      */
-    void roleCallBack(GameUserRole gameUserRole, UserData userData);
+    void roleCallBack(GameUserRole gameUserRole);
 
     /**
      * 订单回传

+ 58 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/ICpPushDataService.java

@@ -0,0 +1,58 @@
+package com.zanxiang.game.module.sdk.service;
+
+import com.zanxiang.game.module.sdk.pojo.param.*;
+import com.zanxiang.game.module.sdk.pojo.vo.CpPushResultVO;
+import com.zanxiang.game.module.sdk.pojo.vo.CpPushUserVO;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-06-20
+ * @description : CP推送数据
+ */
+public interface ICpPushDataService {
+
+    /**
+     * 订单信息推送
+     *
+     * @param gameAppId : 游戏唯一标识
+     * @param param     : 上报参数
+     * @return : 返回接口执行结果
+     */
+    CpPushResultVO pushOrder(String gameAppId, CpPushOrderParam param);
+
+    /**
+     * 活跃信息上报
+     *
+     * @param gameAppId : 游戏唯一标识
+     * @param param     : 上报参数
+     * @return : 返回接口执行结果
+     */
+    CpPushResultVO pushActive(String gameAppId, CpPushActiveParam param);
+
+    /**
+     * 游戏区服信息数据推送
+     *
+     * @param gameAppId : 游戏唯一标识
+     * @param param     : 接口参数
+     * @return : 返回接口执行结果
+     */
+    CpPushResultVO pushServer(String gameAppId, CpPushServerParam param);
+
+    /**
+     * 玩家角色信息数据推送
+     *
+     * @param gameAppId : 游戏唯一标识
+     * @param param     : 接口参数
+     * @return : 返回接口执行结果
+     */
+    CpPushResultVO pushRole(String gameAppId, CpPushRoleParam param);
+
+    /**
+     * 玩家信息数据推送
+     *
+     * @param gameAppId : 游戏唯一标识
+     * @param param     : 接口参数
+     * @return : 返回数据判定结果
+     */
+    CpPushUserVO pushUser(String gameAppId, CpPushUserParam param);
+}

+ 32 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/ICpPushErrorLogService.java

@@ -0,0 +1,32 @@
+package com.zanxiang.game.module.sdk.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.module.mybatis.entity.CpPushErrorLog;
+import com.zanxiang.game.module.sdk.enums.CpPushDataEnum;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-06-27
+ * @description : CP推送数据错误日志
+ */
+public interface ICpPushErrorLogService extends IService<CpPushErrorLog> {
+
+    /**
+     * CP推送数据错误日志保存
+     *
+     * @param gameId         : 游戏id
+     * @param cpPushDataEnum : 数据类型枚举
+     * @param param          : 参数
+     * @param errorMsg       : 错误信息
+     */
+    void createLog(Long gameId, CpPushDataEnum cpPushDataEnum, Object param, String errorMsg);
+
+    /**
+     * CP推送数据错误日志更新
+     *
+     * @param gameId         : 游戏id
+     * @param cpPushDataEnum : 数据类型枚举
+     * @param param          : 参数
+     */
+    void errorLogUpdate(Long gameId, CpPushDataEnum cpPushDataEnum, Object param);
+}

+ 12 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IGameServerService.java

@@ -0,0 +1,12 @@
+package com.zanxiang.game.module.sdk.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.module.mybatis.entity.GameServer;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-08-07
+ * @description : 游戏区服
+ */
+public interface IGameServerService extends IService<GameServer> {
+}

+ 11 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IGameService.java

@@ -2,6 +2,9 @@ package com.zanxiang.game.module.sdk.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.zanxiang.game.module.mybatis.entity.Game;
+import com.zanxiang.game.module.sdk.pojo.param.UserData;
+
+import java.util.Map;
 
 /**
  * @author : xufeng
@@ -9,4 +12,12 @@ import com.zanxiang.game.module.mybatis.entity.Game;
  * @description : 游戏管理
  */
 public interface IGameService extends IService<Game> {
+
+    /**
+     * 获取游戏广告媒体sdk配置
+     *
+     * @param userData : 玩家信息
+     * @return : 返回配置
+     */
+    Map<String, Object> getAdSdkConfig(UserData userData);
 }

+ 12 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IGameSupperService.java

@@ -0,0 +1,12 @@
+package com.zanxiang.game.module.sdk.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.module.mybatis.entity.GameSupper;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-09-12
+ * @description : 超父游戏
+ */
+public interface IGameSupperService extends IService<GameSupper> {
+}

+ 9 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IKafkaService.java

@@ -1,5 +1,6 @@
 package com.zanxiang.game.module.sdk.service;
 
+import com.zanxiang.game.module.mybatis.entity.GameUserRole;
 import com.zanxiang.game.module.sdk.enums.KafkaEventTrackEnum;
 import com.zanxiang.game.module.sdk.pojo.param.GameRoleActiveCallParam;
 import com.zanxiang.game.module.sdk.pojo.param.UserData;
@@ -26,4 +27,12 @@ public interface IKafkaService {
      * @param param    : 提交参数
      */
     void roleActiveTrack(UserData userData, GameRoleActiveCallParam param);
+
+    /**
+     * 角色活跃信息发送到卡夫卡
+     *
+     * @param gameUserRole : 角色信息
+     * @param activeType   : 活跃类型
+     */
+    void roleActiveTrack(GameUserRole gameUserRole, Integer activeType);
 }

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

@@ -33,4 +33,12 @@ public interface IOrderService extends IService<Order> {
      * @return {@link PlatformOrderDTO}
      */
     PlatformOrderDTO getByOrderId(String orderId);
+
+    /**
+     * 生成订单id
+     *
+     * @param userId : 玩家id
+     * @return : 返回订单id
+     */
+    String getOrderNum(Long userId);
 }

+ 9 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/IUserShareService.java

@@ -1,6 +1,7 @@
 package com.zanxiang.game.module.sdk.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.zanxiang.game.module.mybatis.entity.User;
 import com.zanxiang.game.module.mybatis.entity.UserShare;
 import com.zanxiang.game.module.sdk.pojo.param.UserData;
 import com.zanxiang.game.module.sdk.pojo.vo.GameShareVO;
@@ -27,4 +28,12 @@ public interface IUserShareService extends IService<UserShare> {
      * @return {@link GameShareVO}
      */
     GameShareVO getShowCard(UserData userData);
+
+    /**
+     * 创建保存分享记录
+     *
+     * @param user     : 玩家信息
+     * @param userData : 用户数据
+     */
+    void createShareLog(User user, UserData userData);
 }

+ 5 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/AgentServiceImpl.java

@@ -164,6 +164,11 @@ public class AgentServiceImpl extends ServiceImpl<AgentMapper, Agent> implements
     private Tuple3<Long, Map<String, String>, String> appChannelTransform(Game game, UserData userData) {
         //游戏拓展信息
         GameExt gameExt = gameExtService.getByGameId(userData.getGameId());
+        //直投的APP, 必定兼容了媒体的回传sdk
+        if (Strings.isNotBlank(game.getAdSdkConfig())) {
+            Agent agent = super.getOne(new LambdaQueryWrapper<Agent>().eq(Agent::getAgentKey, userData.getChannel()));
+            return Tuples.of(agent == null ? 0 : agent.getId(), Collections.singletonMap("agentKey", userData.getChannel()), Strings.EMPTY);
+        }
         //不投放, 不回传, 只归因渠道, -- 不投放, 且回传只存在于导量情况, 导量无注册行为
         if (Objects.equals(game.getIsPut(), Boolean.FALSE) && Objects.equals(gameExt.getAdCallBackSwitch(), Boolean.FALSE)) {
             //查询访问记录

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

@@ -4,15 +4,21 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.zanxiang.game.back.base.ServerInfo;
 import com.zanxiang.game.back.base.pojo.dto.*;
+import com.zanxiang.game.back.base.pojo.vo.OrderBackQueryRpcVO;
 import com.zanxiang.game.back.base.rpc.ITencentMiniGameBackRpc;
 import com.zanxiang.game.back.base.rpc.ITencentUserActionBackRpc;
+import com.zanxiang.game.back.base.rpc.ITtAppBackRpc;
 import com.zanxiang.game.back.base.rpc.ITtMiniGameBackRpc;
 import com.zanxiang.game.module.base.pojo.enums.AccountTypeEnum;
 import com.zanxiang.game.module.base.pojo.enums.GameCategoryEnum;
 import com.zanxiang.game.module.mybatis.entity.*;
+import com.zanxiang.game.module.sdk.constant.RedisKeyConstant;
+import com.zanxiang.game.module.sdk.enums.CallBackTypeEnum;
 import com.zanxiang.game.module.sdk.pojo.dto.PlatformOrderDTO;
+import com.zanxiang.game.module.sdk.pojo.param.CallBackControlParam;
 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 lombok.extern.slf4j.Slf4j;
 import org.apache.dubbo.config.annotation.DubboReference;
@@ -21,8 +27,9 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.time.LocalDateTime;
-import java.util.Map;
-import java.util.Objects;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 /**
  * @author : lingfeng
@@ -42,6 +49,9 @@ public class CallBackServiceImpl implements ICallBackService {
     @DubboReference(providedBy = ServerInfo.SERVER_DUBBO_NAME)
     private ITtMiniGameBackRpc ttMiniGameBackRpc;
 
+    @DubboReference(providedBy = ServerInfo.SERVER_DUBBO_NAME)
+    private ITtAppBackRpc ttAppBackRpc;
+
     @Autowired
     private IAgentService agentService;
 
@@ -57,9 +67,119 @@ public class CallBackServiceImpl implements ICallBackService {
     @Autowired
     private IGameExtService gameExtService;
 
+    @Autowired
+    private IOrderService orderService;
+
     @Autowired
     private IGameBackLogService gameBackLogService;
 
+    @Autowired
+    private IDistributedLockComponent distributedLockComponent;
+
+    @Override
+    public Map<String, Object> callBackJudge(CallBackControlParam param, UserData userData) {
+        log.error("事件回传判断请求, param : {},  userData : {}", JsonUtil.toString(param), JsonUtil.toString(userData));
+        Map<String, Object> resultMap = new HashMap<>(7);
+        resultMap.put("callBackTypeEnum", param.getCallBackTypeEnum().getValue());
+        resultMap.put("userId", userData.getUserId());
+        resultMap.put("gameId", userData.getGameId());
+        //事件类型枚举
+        CallBackTypeEnum callBackTypeEnum = param.getCallBackTypeEnum();
+        Game game = gameService.getById(userData.getGameId());
+        //判断游戏状态, 对接上包过程中, 全量回传
+        if (Objects.equals(game.getStatus(), 2)) {
+            resultMap.put("callBack", Boolean.TRUE);
+            if (Objects.equals(callBackTypeEnum, CallBackTypeEnum.CALL_BACK_PAY_ORDER)) {
+                PlatformOrderDTO platformOrderDTO = orderService.getByOrderId(param.getOrderId());
+                if (platformOrderDTO != null) {
+                    resultMap.put("amount", Collections.singletonList(platformOrderDTO.getAmount().intValue()));
+                }
+            }
+            return resultMap;
+        }
+        //线程锁
+        String lockKey = RedisKeyConstant.CALL_BACK_JUDGE_LOCK + callBackTypeEnum.getValue() + "_" + userData.getUserId();
+        if (Objects.equals(callBackTypeEnum, CallBackTypeEnum.CALL_BACK_ACTIVATE)) {
+            lockKey = lockKey + "_" + param.getRoleId();
+        }
+        if (Objects.equals(callBackTypeEnum, CallBackTypeEnum.CALL_BACK_PAY_ORDER)) {
+            lockKey = lockKey + "_" + param.getOrderId();
+        }
+        //上锁
+        if (!distributedLockComponent.doLock(lockKey, 0L, 1L, TimeUnit.MINUTES)) {
+            log.error("重复请求触发线程锁, 直接返回false, lockKey : {}", lockKey);
+            resultMap.put("callBack", Boolean.FALSE);
+            return resultMap;
+        }
+        //查询玩家
+        User user = userService.getById(userData.getUserId());
+        //不存在渠道
+        Agent agent = agentService.getById(user.getAgentId());
+        if (agent == null) {
+            resultMap.put("callBack", Boolean.FALSE);
+            return resultMap;
+        }
+        //判断回传
+        try {
+            this.checkCallBack(user.getId(), agent, callBackTypeEnum, resultMap, param);
+        } catch (Exception e) {
+            log.error("事件回传判断, 出现异常, param : {},  userData : {}, e : {}", JsonUtil.toString(param),
+                    JsonUtil.toString(userData), e.getMessage(), e);
+            resultMap.put("callBack", Boolean.FALSE);
+        }
+        //返回结果
+        return resultMap;
+    }
+
+    private void checkCallBack(Long userId, Agent agent, CallBackTypeEnum callBackTypeEnum, Map<String, Object> resultMap,
+                               CallBackControlParam param) {
+        switch (callBackTypeEnum) {
+            case CALL_BACK_REGISTER:
+                // 注册
+                TtAppUserBackQueryRpcDTO userTransform = this.transform(userId, agent);
+                resultMap.put("callBack", ttAppBackRpc.userBackQuery(userTransform).getData());
+                break;
+            case CALL_BACK_LOGIN_IN:
+                // 登录
+                resultMap.put("callBack", Boolean.FALSE);
+                break;
+            case CALL_BACK_ACTIVATE:
+                // 激活(创角)
+                if (Strings.isBlank(param.getRoleId())) {
+                    resultMap.put("callBack", Boolean.FALSE);
+                    resultMap.put("roleId", "unknown");
+                    break;
+                }
+                TtAppRoleRegisterBackQueryRpcDTO roleTransform = this.transform(userId, agent, param.getRoleId());
+                resultMap.put("roleId", param.getRoleId());
+                resultMap.put("callBack", ttAppBackRpc.roleRegisterBackQuery(roleTransform).getData());
+                break;
+            case CALL_BACK_PAY_ORDER:
+                // 支付
+                if (Strings.isBlank(param.getOrderId())) {
+                    resultMap.put("callBack", Boolean.FALSE);
+                    resultMap.put("orderId", "unknown");
+                    break;
+                }
+                TtAppOrderBackQueryRpcDTO orderTransform = this.transform(userId, param.getOrderId(), agent);
+                OrderBackQueryRpcVO orderBackQueryRpcVO = ttAppBackRpc.orderBackQuery(orderTransform).getData();
+                resultMap.put("orderId", param.getOrderId());
+                resultMap.put("callBack", orderBackQueryRpcVO.getDoBack());
+                resultMap.put("backMsg", orderBackQueryRpcVO.getBackMsg());
+                if (Objects.equals(orderBackQueryRpcVO.getDoBack(), Boolean.TRUE)) {
+                    //传过来的金额是分, 换算成元, 存在小数直接舍弃
+                    List<Long> backMoney = orderBackQueryRpcVO.getBackMoney()
+                            .stream().map(money -> money / 100)
+                            .collect(Collectors.toList());
+                    resultMap.put("amount", backMoney);
+                }
+                break;
+            default:
+                // 处理未知类型
+                resultMap.put("callBack", Boolean.FALSE);
+        }
+    }
+
     @Override
     public void userCallBack(User user, Map<String, String> urlParamMap) {
         //判断游戏是否开启广告回传, 未开启, 不回传
@@ -107,20 +227,26 @@ public class CallBackServiceImpl implements ICallBackService {
                     gameBackLogService.addLog(user.getId(), null, "头条用户回传提交", JsonUtil.toString(activeReportRpcDTO));
                 }
             }
+            //头条APP直投回传
+            if (CollectionUtils.isNotEmpty(urlParamMap) && Objects.equals(agent.getAccountType(), AccountTypeEnum.BYTE_APP.getValue())) {
+                TtUserActiveAppRpcDTO ttUserActiveAppRpcDTO = this.transform(user, agent);
+                ttAppBackRpc.userActiveReport(ttUserActiveAppRpcDTO);
+                gameBackLogService.addLog(user.getId(), null, "头条APP用户回传提交", JsonUtil.toString(ttUserActiveAppRpcDTO));
+            }
         } catch (Exception e) {
             log.error("用户回传异常, userId : {}, e : {}", user.getId(), e.getMessage());
         }
     }
 
     @Override
-    public void roleCallBack(GameUserRole gameUserRole, UserData userData) {
+    public void roleCallBack(GameUserRole gameUserRole) {
         //判断游戏是否开启广告回传, 未开启, 不回传
-        GameExt gameExt = gameExtService.getByGameId(userData.getGameId());
+        GameExt gameExt = gameExtService.getByGameId(gameUserRole.getGameId());
         if (!Objects.equals(gameExt.getAdCallBackSwitch(), Boolean.TRUE)) {
             return;
         }
         //用户信息
-        User user = userService.getById(userData.getUserId());
+        User user = userService.getById(gameUserRole.getUserId());
         //用户渠道信息
         Agent agent = agentService.getAgentByChannel(user.getChannel());
         if (agent == null) {
@@ -153,6 +279,12 @@ public class CallBackServiceImpl implements ICallBackService {
                     gameBackLogService.addLog(user.getId(), gameUserRole.getRoleId(), "头条创角回传提交", JsonUtil.toString(ttRoleRegisterRpcDTO));
                 }
             }
+            //头条APP直投回传
+            if (Objects.equals(agent.getAccountType(), AccountTypeEnum.BYTE_APP.getValue())) {
+                TtRoleRegisterAppRpcDTO ttRoleRegisterAppRpcDTO = this.transform(user, agent, gameUserRole);
+                ttAppBackRpc.roleRegisterReport(ttRoleRegisterAppRpcDTO);
+                gameBackLogService.addLog(user.getId(), gameUserRole.getRoleId(), "头条APP创角回传提交", JsonUtil.toString(ttRoleRegisterAppRpcDTO));
+            }
         } catch (Exception e) {
             log.error("创角回传异常, userId : {}, e : {}", user.getId(), e.getMessage());
         }
@@ -203,6 +335,12 @@ public class CallBackServiceImpl implements ICallBackService {
                     gameBackLogService.addLog(user.getId(), platformOrderDTO.getOrderId(), "头条订单回传提交", JsonUtil.toString(ttOrderRpcDTO));
                 }
             }
+            //头条APP直投回传
+            if (Objects.equals(agent.getAccountType(), AccountTypeEnum.BYTE_APP.getValue())) {
+                TtOrderAppRpcDTO ttOrderAppRpcDTO = this.transform(platformOrderDTO, user, agent);
+                ttAppBackRpc.orderReport(ttOrderAppRpcDTO);
+                gameBackLogService.addLog(user.getId(), platformOrderDTO.getOrderId(), "头条APP订单回传提交", JsonUtil.toString(ttOrderAppRpcDTO));
+            }
         } catch (Exception e) {
             log.error("订单回传异常, orderId : {}, e : {}", platformOrderDTO.getOrderId(), e.getMessage());
         }
@@ -224,15 +362,10 @@ public class CallBackServiceImpl implements ICallBackService {
     }
 
     private TtRoleRegisterRpcDTO transform(User user, Agent agent, GameUserRole gameUserRole, GameApplet gameApplet) {
-        TtAccountRpcDTO ttAccountRpcDTO = TtAccountRpcDTO.builder()
-                .accountId(agent.getAccountId())
-                .reportToken(agent.getReportToken())
-                .reportUrl(agent.getReportUrl())
-                .build();
         return TtRoleRegisterRpcDTO.builder()
                 .gameId(agent.getGameId())
                 .backPolicyId(agent.getBackPolicyId())
-                .accountReport(ttAccountRpcDTO)
+                .accountReport(this.transform(agent))
                 .wechatAppId(gameApplet == null ? null : gameApplet.getAppId())
                 .wechatOpenId(user.getOpenId())
                 .agentKey(agent.getAgentKey())
@@ -256,16 +389,11 @@ public class CallBackServiceImpl implements ICallBackService {
     }
 
     private TtUserActiveRpcDTO transform(User user, Agent agent, GameApplet gameApplet, Map<String, String> urlParamMap) {
-        TtAccountRpcDTO ttAccountRpcDTO = TtAccountRpcDTO.builder()
-                .accountId(agent.getAccountId())
-                .reportToken(agent.getReportToken())
-                .reportUrl(agent.getReportUrl())
-                .build();
         return TtUserActiveRpcDTO.builder()
                 .gameId(agent.getGameId())
                 .wechatAppId(gameApplet == null ? null : gameApplet.getAppId())
                 .wechatOpenId(user.getOpenId())
-                .accountReport(ttAccountRpcDTO)
+                .accountReport(this.transform(agent))
                 .agentKey(agent.getAgentKey())
                 .backPolicyId(agent.getBackPolicyId())
                 .activeTime(user.getCreateTime())
@@ -298,14 +426,9 @@ public class CallBackServiceImpl implements ICallBackService {
     }
 
     private TtOrderRpcDTO transform(PlatformOrderDTO platformOrderDTO, String openId, Agent agent, GameApplet gameApplet, LocalDateTime regTime) {
-        TtAccountRpcDTO ttAccountRpcDTO = TtAccountRpcDTO.builder()
-                .accountId(agent.getAccountId())
-                .reportToken(agent.getReportToken())
-                .reportUrl(agent.getReportUrl())
-                .build();
         return TtOrderRpcDTO.builder()
                 .gameId(agent.getGameId())
-                .accountReport(ttAccountRpcDTO)
+                .accountReport(this.transform(agent))
                 .wechatAppId(gameApplet == null ? null : gameApplet.getAppId())
                 .wechatOpenId(openId)
                 .orderId(platformOrderDTO.getOrderId())
@@ -320,4 +443,98 @@ public class CallBackServiceImpl implements ICallBackService {
                 .roleName(platformOrderDTO.getRoleName())
                 .build();
     }
+
+    private TtAccountRpcDTO transform(Agent agent) {
+        return TtAccountRpcDTO.builder()
+                .accountId(agent.getAccountId())
+                .reportToken(agent.getReportToken())
+                .reportUrl(agent.getReportUrl())
+                .build();
+    }
+
+    private TtUserActiveAppRpcDTO transform(User user, Agent agent) {
+        return TtUserActiveAppRpcDTO.builder()
+                .gameId(agent.getGameId())
+                .accountReport(this.transform(agent))
+                .agentKey(agent.getAgentKey())
+                .activeTime(user.getCreateTime())
+                .backPolicyId(agent.getBackPolicyId())
+                .userId(user.getId().toString())
+                .mac(user.getMac())
+                .imei(user.getImei())
+                .oaid(user.getOaid())
+                .androidId(user.getAndroidId())
+                .idfa(user.getIdfa())
+                .caid(user.getCaid())
+                .build();
+    }
+
+    private TtOrderAppRpcDTO transform(PlatformOrderDTO platformOrderDTO, User user, Agent agent) {
+        return TtOrderAppRpcDTO.builder()
+                .gameId(agent.getGameId())
+                .accountReport(this.transform(agent))
+                .userId(user.getId().toString())
+                .orderId(platformOrderDTO.getOrderId())
+                .agentKey(agent.getAgentKey())
+                .backPolicyId(agent.getBackPolicyId())
+                .rechargeMoney(platformOrderDTO.getAmount().longValue() * 100)
+                .orderStatus(platformOrderDTO.getStatus())
+                .regTime(user.getCreateTime())
+                .createTime(platformOrderDTO.getCreateTime())
+                .payTime(platformOrderDTO.getPayTime())
+                .roleId(platformOrderDTO.getRoleId())
+                .roleName(platformOrderDTO.getRoleName())
+                .mac(user.getMac())
+                .imei(user.getImei())
+                .oaid(user.getOaid())
+                .androidId(user.getAndroidId())
+                .idfa(user.getIdfa())
+                .caid(user.getCaid())
+                .build();
+    }
+
+    private TtRoleRegisterAppRpcDTO transform(User user, Agent agent, GameUserRole gameUserRole) {
+        return TtRoleRegisterAppRpcDTO.builder()
+                .gameId(agent.getGameId())
+                .userId(user.getId().toString())
+                .backPolicyId(agent.getBackPolicyId())
+                .accountReport(this.transform(agent))
+                .agentKey(agent.getAgentKey())
+                .roleId(gameUserRole.getRoleId())
+                .roleName(gameUserRole.getRoleName())
+                .registerTime(gameUserRole.getCreateTime())
+                .mac(user.getMac())
+                .imei(user.getImei())
+                .oaid(user.getOaid())
+                .androidId(user.getAndroidId())
+                .idfa(user.getIdfa())
+                .caid(user.getCaid())
+                .build();
+    }
+
+    private TtAppUserBackQueryRpcDTO transform(Long userId, Agent agent) {
+        return TtAppUserBackQueryRpcDTO.builder()
+                .gameId(agent.getGameId())
+                .userId(userId.toString())
+                .agentKey(agent.getAgentKey())
+                .build();
+    }
+
+    private TtAppOrderBackQueryRpcDTO transform(Long userId, String orderId, Agent agent) {
+        return TtAppOrderBackQueryRpcDTO.builder()
+                .gameId(agent.getGameId())
+                .userId(userId.toString())
+                .orderId(orderId)
+                .agentKey(agent.getAgentKey())
+                .build();
+    }
+
+    private TtAppRoleRegisterBackQueryRpcDTO transform(Long userId, Agent agent, String roleId) {
+        return TtAppRoleRegisterBackQueryRpcDTO.builder()
+                .gameId(agent.getGameId())
+                .userId(userId.toString())
+                .agentKey(agent.getAgentKey())
+                .roleId(roleId)
+                .build();
+    }
 }

+ 649 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/CpPushDataServiceImpl.java

@@ -0,0 +1,649 @@
+package com.zanxiang.game.module.sdk.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.zanxiang.game.module.base.pojo.enums.BanStatusEnum;
+import com.zanxiang.game.module.base.pojo.enums.DeleteEnum;
+import com.zanxiang.game.module.mybatis.entity.*;
+import com.zanxiang.game.module.sdk.constant.RedisKeyConstant;
+import com.zanxiang.game.module.sdk.enums.CpPushDataEnum;
+import com.zanxiang.game.module.sdk.enums.DeviceTypeEnum;
+import com.zanxiang.game.module.sdk.enums.KafkaEventTrackEnum;
+import com.zanxiang.game.module.sdk.pojo.dto.PlatformOrderDTO;
+import com.zanxiang.game.module.sdk.pojo.param.*;
+import com.zanxiang.game.module.sdk.pojo.vo.CpPushResultVO;
+import com.zanxiang.game.module.sdk.pojo.vo.CpPushUserVO;
+import com.zanxiang.game.module.sdk.service.*;
+import com.zanxiang.game.module.sdk.util.RegisterUtil;
+import com.zanxiang.module.redis.service.IDistributedLockComponent;
+import com.zanxiang.module.util.JsonUtil;
+import com.zanxiang.module.util.bean.BeanUtil;
+import com.zanxiang.module.util.exception.BaseException;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
+import org.json.JSONObject;
+import org.redisson.api.RLock;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionStatus;
+import reactor.util.function.Tuple2;
+import reactor.util.function.Tuple3;
+import reactor.util.function.Tuples;
+
+import java.time.LocalDateTime;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-06-20
+ * @description : CP推送数据
+ */
+@Slf4j
+@Service
+public class CpPushDataServiceImpl implements ICpPushDataService {
+
+    @Autowired
+    private IGameExtService gameExtService;
+
+    @Autowired
+    private IUserService userService;
+
+    @Autowired
+    private IAgentService agentService;
+
+    @Autowired
+    private IGameService gameService;
+
+    @Autowired
+    private ICallBackService callBackService;
+
+    @Autowired
+    private IUserAgentLogService userAgentLogService;
+
+    @Autowired
+    private IKafkaService kafkaService;
+
+    @Autowired
+    private IGameUserService gameUserService;
+
+    @Autowired
+    private IUserShareService userShareService;
+
+    @Autowired
+    private IGameUserRoleService gameUserRoleService;
+
+    @Autowired
+    private IGameServerService gameServerService;
+
+    @Autowired
+    private IOrderService orderService;
+
+    @Autowired
+    private TransactionDefinition transactionDefinition;
+
+    @Autowired
+    private ICpPushErrorLogService cpPushErrorLogService;
+
+    @Autowired
+    private DataSourceTransactionManager dataSourceTransactionManager;
+
+    @Autowired
+    private IDistributedLockComponent distributedLockComponent;
+
+    @Override
+    public CpPushResultVO pushOrder(String gameAppId, CpPushOrderParam param) {
+        //查询游戏
+        Game game = this.getGameByGameAppId(gameAppId);
+        //查询订单信息
+        Order order = orderService.getOne(new LambdaQueryWrapper<Order>()
+                .eq(Order::getGameId, game.getId())
+                .eq(Order::getCpOrderId, param.getOrderId()));
+        // 手动开启事务
+        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
+        try {
+            if (order == null) {
+                order = this.createOrder(game, param);
+            } else {
+                order.setStatus(param.getStatus());
+                order.setPayTime(param.getPayTime());
+                order.setUpdateTime(LocalDateTime.now());
+            }
+            //订单更新或者保存
+            orderService.saveOrUpdate(order);
+            // 提交事务
+            dataSourceTransactionManager.commit(transactionStatus);
+        } catch (Exception e) {
+            // 回滚事务
+            dataSourceTransactionManager.rollback(transactionStatus);
+            //保存错误日志
+            cpPushErrorLogService.createLog(game.getId(), CpPushDataEnum.CP_PUSH_DATA_ORDER, param, e.getMessage());
+            //抛出异常
+            throw new BaseException(e.getMessage());
+        }
+        //订单回传
+        callBackService.orderCallBack(BeanUtil.copy(order, PlatformOrderDTO.class));
+        //判断订单行为
+        if (Objects.equals(param.getStatus(), 2)) {
+            //支付
+            kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_ORDER_PAY, JsonUtil.toString(BeanUtil.copy(order, PlatformOrderDTO.class)));
+        } else {
+            //下单
+            kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_ORDER_PAY, JsonUtil.toString(order));
+        }
+        //日志更新
+        cpPushErrorLogService.errorLogUpdate(game.getId(), CpPushDataEnum.CP_PUSH_DATA_ORDER, param);
+        //构造返回
+        return CpPushResultVO.builder().result(Boolean.TRUE).build();
+    }
+
+    private Order createOrder(Game game, CpPushOrderParam param) {
+        String lockKey = RedisKeyConstant.ORDER_CREATE_LOCK + param.getOpenId() + "_" + param.getOrderId();
+        if (!distributedLockComponent.doLock(lockKey, 0L, 1L, TimeUnit.MINUTES)) {
+            log.error("[订单推送]正在创建中, param : {}", JsonUtil.toString(param));
+            throw new BaseException("接口调用订单正在创建中");
+        }
+        try {
+            //查询玩家信息
+            User user = userService.getOne(new LambdaQueryWrapper<User>()
+                    .eq(User::getOpenId, param.getOpenId())
+                    .eq(User::getGameId, game.getId()));
+            if (user == null) {
+                throw new BaseException("[订单推送]玩家信息不存在");
+            }
+            //玩家信息
+            GameUser gameUser = gameUserService.getOne(new LambdaQueryWrapper<GameUser>()
+                    .eq(GameUser::getUserId, user.getId()));
+            if (gameUser == null) {
+                throw new BaseException("[订单推送]游戏玩家信息不存在");
+            }
+            //角色信息
+            GameUserRole gameUserRole = gameUserRoleService.getOne(new LambdaQueryWrapper<GameUserRole>()
+                    .eq(GameUserRole::getGameId, game.getId())
+                    .eq(GameUserRole::getUserId, user.getId())
+                    .eq(GameUserRole::getRoleId, param.getRoleId()));
+            if (gameUserRole == null) {
+                throw new BaseException("[订单推送]角色信息不存在");
+            }
+            //构造订单
+            return this.transform(game, param, user, gameUser, gameUserRole);
+        } catch (Exception e) {
+            log.error("[订单推送]订单创建出现异常, game : {}, param : {}, e : {}", JsonUtil.toString(game), JsonUtil.toString(param), e.getMessage(), e);
+            throw new BaseException("[订单推送]订单创建出现异常!");
+        } finally {
+            RLock rLock = distributedLockComponent.getLock(lockKey);
+            if (rLock != null) {
+                distributedLockComponent.unlock(lockKey);
+            }
+        }
+    }
+
+    private Order transform(Game game, CpPushOrderParam param, User user, GameUser gameUser, GameUserRole gameUserRole) {
+        return Order.builder()
+                .orderId(orderService.getOrderNum(user.getId()))
+                .cpOrderId(param.getOrderId())
+                .agentId(user.getAgentId())
+                .cpId(game.getCpId())
+                .userId(user.getId())
+                .mgUserId(gameUser.getId())
+                .regTime(user.getCreateTime())
+                .gameId(game.getId())
+                .roleId(gameUserRole.getRoleId())
+                .roleName(gameUserRole.getRoleName())
+                .roleLevel(gameUserRole.getRoleLevel())
+                .roleVipLevel(gameUserRole.getRoleVipLevel())
+                .serverId(gameUserRole.getServerId())
+                .serverName(gameUserRole.getServerName())
+                .amount(param.getAmount())
+                .realAmount(param.getStatus() == 2 ? param.getAmount() : null)
+                .productId(param.getProductId())
+                .productName(param.getProductName())
+                .deviceSystem(user.getDeviceSystem())
+                .payWayId(0L)
+                .payDeviceId(0L)
+                .gamePayWayId(0L)
+                .ext(param.getExtension())
+                .status(param.getStatus())
+                .payTime(param.getPayTime())
+                .createTime(param.getCreateTime())
+                .updateTime(LocalDateTime.now())
+                .build();
+    }
+
+    @Override
+    public CpPushResultVO pushActive(String gameAppId, CpPushActiveParam param) {
+        //查询游戏
+        Game game = this.getGameByGameAppId(gameAppId);
+        try {
+            //查询玩家信息
+            User user = userService.getOne(new LambdaQueryWrapper<User>()
+                    .eq(User::getOpenId, param.getOpenId())
+                    .eq(User::getGameId, game.getId()));
+            if (user == null) {
+                throw new BaseException("[活跃推送]角色信息不存在");
+            }
+            //查询角色信息
+            GameUserRole gameUserRole = gameUserRoleService.getOne(new LambdaQueryWrapper<GameUserRole>()
+                    .eq(GameUserRole::getUserId, user.getId())
+                    .eq(GameUserRole::getGameId, game.getId())
+                    .eq(GameUserRole::getServerId, param.getServerId())
+                    .eq(GameUserRole::getRoleId, param.getRoleId())
+                    .orderByDesc(GameUserRole::getCreateTime)
+                    .last("limit 1"));
+            if (gameUserRole == null) {
+                throw new BaseException("[活跃推送]角色信息不存在");
+            }
+            //角色活跃信息上报到卡夫卡
+            kafkaService.roleActiveTrack(gameUserRole, param.getActiveType());
+        } catch (Exception e) {
+            //保存错误日志
+            cpPushErrorLogService.createLog(game.getId(), CpPushDataEnum.CP_PUSH_DATA_ACTIVE, param, e.getMessage());
+            //抛出异常
+            throw new BaseException(e.getMessage());
+        }
+        //日志更新
+        cpPushErrorLogService.errorLogUpdate(game.getId(), CpPushDataEnum.CP_PUSH_DATA_ACTIVE, param);
+        //构造返回
+        return CpPushResultVO.builder().result(Boolean.TRUE).build();
+    }
+
+    @Override
+    public CpPushResultVO pushServer(String gameAppId, CpPushServerParam param) {
+        //查询游戏
+        Game game = this.getGameByGameAppId(gameAppId);
+        boolean result;
+        // 手动开启事务
+        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
+        try {
+            //查询区服id
+            GameServer gameServer = gameServerService.getOne(new LambdaQueryWrapper<GameServer>()
+                    .eq(GameServer::getGameId, game.getSuperGameId())
+                    .eq(GameServer::getServerId, param.getServerId())
+            );
+            GameServer transform = this.transform(game.getSuperGameId(), 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());
+            }
+            //区服添加或者更新
+            result = gameServerService.saveOrUpdate(gameServer);
+            //提交事务
+            dataSourceTransactionManager.commit(transactionStatus);
+        } catch (Exception e) {
+            //回滚事务
+            dataSourceTransactionManager.rollback(transactionStatus);
+            //保存错误日志
+            cpPushErrorLogService.createLog(game.getId(), CpPushDataEnum.CP_PUSH_DATA_SERVER, param, e.getMessage());
+            //抛出异常
+            throw new BaseException(e.getMessage());
+        }
+        //日志更新
+        cpPushErrorLogService.errorLogUpdate(game.getId(), CpPushDataEnum.CP_PUSH_DATA_SERVER, param);
+        //构造返回
+        return CpPushResultVO.builder().result(result).build();
+    }
+
+    private GameServer transform(Long superGameId, CpPushServerParam param) {
+        return GameServer.builder()
+                .gameId(superGameId)
+                .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();
+    }
+
+    @Override
+    public CpPushResultVO pushRole(String gameAppId, CpPushRoleParam param) {
+        //查询游戏
+        Game game = this.getGameByGameAppId(gameAppId);
+        boolean result;
+        // 手动开启事务
+        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
+        try {
+            //查询玩家信息
+            User user = userService.getOne(new LambdaQueryWrapper<User>()
+                    .eq(User::getGameId, game.getId())
+                    .eq(User::getOpenId, param.getOpenId()));
+            if (user == null) {
+                throw new BaseException("[角色推送]玩家信息不存在");
+            }
+            //查询玩家角色信息
+            GameUserRole gameUserRole = gameUserRoleService.getOne(new LambdaQueryWrapper<GameUserRole>()
+                    .eq(GameUserRole::getUserId, user.getId())
+                    .eq(GameUserRole::getGameId, user.getGameId())
+                    .eq(GameUserRole::getRoleId, param.getRoleId()));
+            if (gameUserRole == null) {
+                result = this.gameRoleCreate(param, user);
+            } else {
+                result = this.gameRoleUpdate(param, gameUserRole, user);
+            }
+            // 提交事务
+            dataSourceTransactionManager.commit(transactionStatus);
+        } catch (Exception e) {
+            // 回滚事务
+            dataSourceTransactionManager.rollback(transactionStatus);
+            //保存错误日志
+            cpPushErrorLogService.createLog(game.getId(), CpPushDataEnum.CP_PUSH_DATA_ROLE, param, e.getMessage());
+            //抛出异常
+            throw new BaseException(e.getMessage());
+        }
+        //日志更新
+        cpPushErrorLogService.errorLogUpdate(game.getId(), CpPushDataEnum.CP_PUSH_DATA_ROLE, param);
+        //构造返回
+        return CpPushResultVO.builder().result(result).build();
+    }
+
+    private boolean gameRoleCreate(CpPushRoleParam param, User user) {
+        GameUser gameUser = gameUserService.getOne(new LambdaQueryWrapper<GameUser>()
+                .select(GameUser::getId)
+                .eq(GameUser::getGameId, user.getGameId())
+                .eq(GameUser::getUserId, user.getId()));
+        if (gameUser == null) {
+            throw new BaseException("[角色推送]游戏玩家信息不存在");
+        }
+        //上锁
+        if (!distributedLockComponent.doLock(RedisKeyConstant.ROLE_CREATE_LOCK + user.getGameId() + "_" + param.getRoleId(),
+                0L, 1L, TimeUnit.MINUTES)) {
+            log.error("[角色推送]角色正在创建中, param : {}, user : {}", JsonUtil.toString(param), JsonUtil.toString(user));
+            return Boolean.TRUE;
+        }
+        //创建角色
+        GameUserRole userRole = this.transform(param, gameUser, user);
+        boolean result = gameUserRoleService.save(userRole);
+        //更新用户创角数
+        userService.update(new LambdaUpdateWrapper<User>()
+                .setSql("role_count=role_count+" + 1)
+                .set(User::getUpdateTime, LocalDateTime.now())
+                .eq(User::getId, user.getId()));
+        //更新玩家创角数
+        gameUserService.update(new LambdaUpdateWrapper<GameUser>()
+                .setSql("role_count=role_count+" + 1)
+                .set(GameUser::getUpdateTime, LocalDateTime.now())
+                .eq(GameUser::getId, gameUser.getId()));
+        //用户创角回传
+        callBackService.roleCallBack(userRole);
+        //用户创角埋点数据发送到卡夫卡
+        kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_ROLE_CREATE, JsonUtil.toString(userRole));
+        return result;
+    }
+
+    private boolean gameRoleUpdate(CpPushRoleParam param, GameUserRole gameUserRole, User user) {
+        //更新频率限制, 20秒更新一次, 避免游戏实时战力高频上报
+        if (!distributedLockComponent.doLock(RedisKeyConstant.ROLE_LEVEL_UP + user.getGameId() + "_" + param.getRoleId(),
+                0L, 20L, TimeUnit.SECONDS)) {
+            return Boolean.TRUE;
+        }
+        //玩家角色信息更新
+        if (param.getExtra() != null && Strings.isNotBlank(JsonUtil.toString(param.getExtra()))) {
+            gameUserRole.setExtra(JsonUtil.toString(param.getExtra()));
+        }
+        if (gameUserRole.getServerId() == null) {
+            gameUserRole.setServerId(param.getServerId());
+        }
+        if (param.getRolePower() != null) {
+            gameUserRole.setRolePower(param.getRolePower());
+        }
+        if (param.getRoleVipLevel() != null) {
+            gameUserRole.setRoleVipLevel(param.getRoleVipLevel());
+        }
+        gameUserRole.setRoleName(param.getRoleName());
+        gameUserRole.setRoleLevel(param.getRoleLevel());
+        gameUserRole.setServerName(param.getServerName());
+        gameUserRole.setUpdateTime(LocalDateTime.now());
+        boolean result = gameUserRoleService.updateById(gameUserRole);
+        //角色更新数据埋点发送到卡夫卡
+        kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_ROLE_UPDATE, JsonUtil.toString(gameUserRole));
+        return result;
+    }
+
+    private GameUserRole transform(CpPushRoleParam param, GameUser gameUser, User user) {
+        String extraJson = JsonUtil.toString(param.getExtra());
+        return GameUserRole.builder()
+                .userId(user.getId())
+                .gameUserId(gameUser.getId())
+                .gameId(user.getGameId())
+                .serverId(param.getServerId())
+                .serverName(param.getServerName())
+                .roleId(param.getRoleId())
+                .roleName(param.getRoleName())
+                .roleLevel(param.getRoleLevel())
+                .roleVipLevel(param.getRoleVipLevel())
+                .rolePower(param.getRolePower())
+                .os(user.getDeviceSystem())
+                .regTime(user.getCreateTime())
+                .createTime(param.getCreateTime())
+                .updateTime(LocalDateTime.now())
+                .lastLoginTime(LocalDateTime.now())
+                .extra(param.getExtra() == null || Strings.isBlank(extraJson) ? null : extraJson)
+                .build();
+    }
+
+    @Override
+    public CpPushUserVO pushUser(String gameAppId, CpPushUserParam param) {
+        //查询游戏
+        Game game = this.getGameByGameAppId(gameAppId);
+        //结果信息
+        CpPushUserVO cpPushUserVO;
+        // 手动开启事务
+        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
+        try {
+            //中间数据
+            UserData userData = UserData.builder().gameId(game.getId()).channel(param.getChannel()).ip(param.getIp()).ua(param.getUa()).build();
+            //根据openId查询用户
+            User user = userService.getOne(new LambdaQueryWrapper<User>()
+                    .eq(User::getGameId, game.getId())
+                    .eq(User::getOpenId, param.getOpenId()));
+            //玩家信息不存在
+            if (user == null) {
+                cpPushUserVO = this.createUser(game, userData, param);
+            } else {
+                //玩家信息更新
+                Map<String, String> channelMap = this.updateUser(user, param, game, userData);
+                cpPushUserVO = CpPushUserVO.builder().userId(user.getId())
+                        .sdkUser(!Objects.equals(user.getAgentId(), Agent.DEFAULT_AGENT))
+                        .channel(JsonUtil.toString(channelMap))
+                        .build();
+            }
+            // 提交事务
+            dataSourceTransactionManager.commit(transactionStatus);
+        } catch (Exception e) {
+            // 回滚事务
+            dataSourceTransactionManager.rollback(transactionStatus);
+            //保存错误日志
+            cpPushErrorLogService.createLog(game.getId(), CpPushDataEnum.CP_PUSH_DATA_USER, param, e.getMessage());
+            //抛出异常
+            throw new BaseException(e.getMessage());
+        }
+        //日志更新
+        cpPushErrorLogService.errorLogUpdate(game.getId(), CpPushDataEnum.CP_PUSH_DATA_USER, param);
+        //返回结果
+        return cpPushUserVO;
+    }
+
+    private CpPushUserVO createUser(Game game, UserData userData, CpPushUserParam param) {
+        //游戏id
+        Long gameId = game.getId();
+        //线程锁Key
+        String lockKey = RedisKeyConstant.USER_CREATE + gameId + "_" + param.getOpenId();
+        //上锁
+        if (!distributedLockComponent.doLock(lockKey, 0L, 3L, TimeUnit.MINUTES)) {
+            log.error("[用户推送]用户正在创建中, param : {}, game : {}", JsonUtil.toString(param), JsonUtil.toString(game));
+            throw new BaseException("[用户推送]用户正在创建中");
+        }
+        //玩家信息
+        User user;
+        //渠道map
+        Map<String, String> channelMap = null;
+        try {
+            //判断是否分享玩家
+            if (Strings.isNotBlank(param.getShareOpenId())) {
+                User shareUser = userService.getOne(new LambdaQueryWrapper<User>()
+                        .eq(User::getGameId, gameId)
+                        .eq(User::getOpenId, param.getShareOpenId())
+                        .last("limit 1"));
+                user = this.transform(gameId, shareUser, param);
+            } else {
+                Tuple3<Long, Map<String, String>, String> tuple3 = this.getUserAgentChannel(game, userData);
+                user = this.transform(gameId, tuple3, param);
+                channelMap = tuple3.getT2();
+            }
+            userService.save(user);
+            gameUserService.createGameUser(user);
+            userAgentLogService.regAgentLog(user);
+            //非分享用户, 回传注册
+            if (Strings.isBlank(param.getShareOpenId())) {
+                callBackService.userCallBack(user, channelMap);
+            } else {
+                //记录分享信息, 用户不回传
+                userShareService.createShareLog(user, userData);
+            }
+            //注册信息埋点数据发送到卡夫卡
+            kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_REG, JsonUtil.toString(user));
+            //返回构造数据
+            return CpPushUserVO.builder().userId(user.getId())
+                    .sdkUser(!Objects.equals(user.getAgentId(), Agent.DEFAULT_AGENT))
+                    .channel(JsonUtil.toString(channelMap))
+                    .build();
+        } catch (Exception e) {
+            log.error("[用户推送]用户创建出现异常, gameId : {}, param : {}, e : {}", gameId, JsonUtil.toString(param), e.getMessage(), e);
+            throw new BaseException("[用户推送]用户创建出现异常");
+        } finally {
+            RLock rLock = distributedLockComponent.getLock(lockKey);
+            if (rLock != null) {
+                distributedLockComponent.unlock(lockKey);
+            }
+        }
+    }
+
+    private Map<String, String> updateUser(User user, CpPushUserParam param, Game game, UserData userData) {
+        //活跃间隔时长
+        long inactiveDay = 15L;
+        //判定不活跃时长是否达到限制
+        if (param.getActiveTime().plusDays(inactiveDay).isAfter(LocalDateTime.now())) {
+            return Collections.emptyMap();
+        }
+        //渠道id, 链接参数
+        Tuple3<Long, Map<String, String>, String> tuple3 = this.getUserAgentChannel(game, userData);
+        //查询渠道
+        Agent agent = agentService.getById(tuple3.getT1());
+        if (agent == null) {
+            return Collections.emptyMap();
+        }
+        //更新用户信息
+        user.setAgentId(agent.getId());
+        user.setChannel(userData.getChannel());
+        user.setUpdateTime(LocalDateTime.now());
+        userService.updateById(user);
+        //添加渠道变更记录
+        userAgentLogService.agentUpdateLog(user, agent.getId(), userData.getChannel());
+        //回传用户信息
+        callBackService.userCallBack(user, tuple3.getT2());
+        //渠道变更信息埋点数据发送到卡夫卡
+        kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_AGENT_UPDATE, JsonUtil.toString(user));
+        //返回更新的渠道信息
+        return tuple3.getT2();
+    }
+
+    private Tuple3<Long, Map<String, String>, String> getUserAgentChannel(Game game, UserData userData) {
+        //解析渠道信息
+        String channel = new String(Base64.getDecoder().decode(userData.getChannel()));
+        userData.setChannel(channel);
+        //没有携带渠道标识, 无法解析渠道信息, 判定为自然量
+        if (!channel.contains("agentKey") && !channel.contains("state")) {
+            return Tuples.of(0L, Collections.emptyMap(), channel);
+        }
+        Tuple2<Boolean, Boolean> jsonAndEmpty = this.isJsonAndEmpty(channel);
+        //channel渠道信息非json格式, 或者是空json
+        if (!jsonAndEmpty.getT1() || jsonAndEmpty.getT2()) {
+            //返回自然量渠道
+            return Tuples.of(0L, Collections.emptyMap(), channel);
+        }
+        //渠道id, 链接参数, 分享人id
+        Tuple3<Long, Map<String, String>, String> tuple3 = agentService.getUserAgentId(game, userData);
+        //返回渠道id, 渠道参数
+        return Tuples.of(tuple3.getT1(), tuple3.getT2(), channel);
+    }
+
+    private User transform(Long gameId, User shareUser, CpPushUserParam param) {
+        return User.builder()
+                .openId(param.getOpenId())
+                .regAgentId(shareUser.getRegAgentId())
+                .agentId(shareUser.getAgentId())
+                .channel(shareUser.getChannel())
+                .gameId(gameId)
+                .username(param.getOpenId())
+                .nickname(RegisterUtil.randomNickName(param.getOpenId()))
+                .deviceType(DeviceTypeEnum.DEVICE_TYPE_MINI_APP.getDeviceType())
+                .status(BanStatusEnum.NORMAL_STATUS.getStatus())
+                .authentication(0)
+                .createTime(param.getRegTime())
+                .updateTime(LocalDateTime.now())
+                .deviceSystem(param.getOs())
+                .ip(param.getIp())
+                .shareUserId(shareUser.getId())
+                .build();
+    }
+
+    private User transform(Long gameId, Tuple3<Long, Map<String, String>, String> tuple3, CpPushUserParam param) {
+        return User.builder()
+                .openId(param.getOpenId())
+                .regAgentId(tuple3.getT1())
+                .agentId(tuple3.getT1())
+                .channel(tuple3.getT2().isEmpty() ? tuple3.getT3() : JsonUtil.toString(tuple3.getT2()))
+                .gameId(gameId)
+                .username(param.getOpenId())
+                .nickname(RegisterUtil.randomNickName(param.getOpenId()))
+                .deviceType(DeviceTypeEnum.DEVICE_TYPE_MINI_APP.getDeviceType())
+                .status(BanStatusEnum.NORMAL_STATUS.getStatus())
+                .authentication(0)
+                .createTime(param.getRegTime())
+                .updateTime(LocalDateTime.now())
+                .deviceSystem(param.getOs())
+                .ip(param.getIp())
+                .build();
+    }
+
+    private Tuple2<Boolean, Boolean> isJsonAndEmpty(String str) {
+        try {
+            JSONObject jsonObject = new JSONObject(str);
+            return Tuples.of(Boolean.TRUE, jsonObject.keySet().isEmpty());
+        } catch (Exception e) {
+            return Tuples.of(Boolean.FALSE, Boolean.FALSE);
+        }
+    }
+
+    private Game getGameByGameAppId(String gameAppId) {
+        //游戏拓展信息
+        GameExt gameExt = gameExtService.getByGameAppId(gameAppId);
+        if (gameExt == null) {
+            log.error("参数错误, 游戏拓展信息配置不存在, gameAppId : {}", gameAppId);
+            throw new BaseException("参数错误, 游戏拓展信息配置不存在");
+        }
+        //查询游戏
+        Game game = gameService.getById(gameExt.getGameId());
+        if (game == null) {
+            log.error("参数错误, 游戏配置不存在, gameAppId : {}", gameAppId);
+            throw new BaseException("参数错误, 游戏配置不存在");
+        }
+        return game;
+    }
+}

+ 57 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/CpPushErrorLogServiceImpl.java

@@ -0,0 +1,57 @@
+package com.zanxiang.game.module.sdk.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zanxiang.game.module.mybatis.entity.CpPushErrorLog;
+import com.zanxiang.game.module.mybatis.mapper.CpPushErrorLogMapper;
+import com.zanxiang.game.module.sdk.enums.CpPushDataEnum;
+import com.zanxiang.game.module.sdk.service.ICpPushErrorLogService;
+import com.zanxiang.module.util.JsonUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.Map;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-06-27
+ * @description : CP推送数据错误日志
+ */
+@Slf4j
+@Service
+public class CpPushErrorLogServiceImpl extends ServiceImpl<CpPushErrorLogMapper, CpPushErrorLog> implements ICpPushErrorLogService {
+
+    @Override
+    public void createLog(Long gameId, CpPushDataEnum cpPushDataEnum, Object param, String errorMsg) {
+        String paramJsonStr = JsonUtil.toString(param);
+        Map<String, String> paramMap = JsonUtil.toMap(paramJsonStr, Map.class, String.class);
+        super.save(CpPushErrorLog.builder()
+                .dataType(cpPushDataEnum.getValue())
+                .gameId(gameId)
+                .openId(paramMap.get("openId"))
+                .orderId(paramMap.get("orderId"))
+                .serverId(paramMap.get("serverId"))
+                .roleId(paramMap.get("roleId"))
+                .param(paramJsonStr)
+                .errorMsg(errorMsg)
+                .status(CpPushErrorLog.STATUS_VALID)
+                .createTime(LocalDateTime.now())
+                .build());
+    }
+
+    @Override
+    public void errorLogUpdate(Long gameId, CpPushDataEnum cpPushDataEnum, Object param) {
+        Map<String, String> paramMap = JsonUtil.toMap(JsonUtil.toString(param), Map.class, String.class);
+        super.update(new LambdaUpdateWrapper<CpPushErrorLog>()
+                .set(CpPushErrorLog::getStatus, CpPushErrorLog.STATUS_INVALID)
+                .eq(CpPushErrorLog::getGameId, gameId)
+                .eq(CpPushErrorLog::getDataType, cpPushDataEnum.getValue())
+                .eq(Strings.isNotBlank(paramMap.get("openId")), CpPushErrorLog::getOpenId, paramMap.get("openId"))
+                .eq(Strings.isNotBlank(paramMap.get("orderId")), CpPushErrorLog::getOrderId, paramMap.get("orderId"))
+                .eq(Strings.isNotBlank(paramMap.get("serverId")), CpPushErrorLog::getServerId, paramMap.get("serverId"))
+                .eq(Strings.isNotBlank(paramMap.get("roleId")), CpPushErrorLog::getRoleId, paramMap.get("roleId"))
+        );
+    }
+}

+ 18 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/GameServerServiceImpl.java

@@ -0,0 +1,18 @@
+package com.zanxiang.game.module.sdk.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zanxiang.game.module.mybatis.entity.GameServer;
+import com.zanxiang.game.module.mybatis.mapper.GameServerMapper;
+import com.zanxiang.game.module.sdk.service.IGameServerService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-08-07
+ * @description : 游戏区服
+ */
+@Slf4j
+@Service
+public class GameServerServiceImpl extends ServiceImpl<GameServerMapper, GameServer> implements IGameServerService {
+}

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

@@ -3,10 +3,16 @@ package com.zanxiang.game.module.sdk.service.impl;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zanxiang.game.module.mybatis.entity.Game;
 import com.zanxiang.game.module.mybatis.mapper.GameMapper;
+import com.zanxiang.game.module.sdk.pojo.param.UserData;
 import com.zanxiang.game.module.sdk.service.IGameService;
+import com.zanxiang.module.util.JsonUtil;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.logging.log4j.util.Strings;
 import org.springframework.stereotype.Service;
 
+import java.util.Collections;
+import java.util.Map;
+
 /**
  * @author : lingfeng
  * @time : 2022-07-13
@@ -15,4 +21,19 @@ import org.springframework.stereotype.Service;
 @Slf4j
 @Service
 public class GameServiceImpl extends ServiceImpl<GameMapper, Game> implements IGameService {
+
+    @Override
+    public Map<String, Object> getAdSdkConfig(UserData userData) {
+
+        log.error("媒体初始化配置请求 userData : {}", JsonUtil.toString(userData));
+
+        Game game = super.getById(userData.getGameId());
+        if (Strings.isBlank(game.getAdSdkConfig())) {
+            return Collections.singletonMap("adSdk", 0);
+        }
+        Map<String, Object> map = JsonUtil.toMap(game.getAdSdkConfig(), Map.class, Object.class);
+
+        log.error("媒体初始化配置返回, map : {}", JsonUtil.toString(map));
+        return map;
+    }
 }

+ 18 - 0
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/GameSupperServiceImpl.java

@@ -0,0 +1,18 @@
+package com.zanxiang.game.module.sdk.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zanxiang.game.module.mybatis.entity.GameSupper;
+import com.zanxiang.game.module.mybatis.mapper.GameSupperMapper;
+import com.zanxiang.game.module.sdk.service.IGameSupperService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author : lingfeng
+ * @time : 2023-09-12
+ * @description : 超父游戏
+ */
+@Slf4j
+@Service
+public class GameSupperServiceImpl extends ServiceImpl<GameSupperMapper, GameSupper> implements IGameSupperService {
+}

+ 1 - 3
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/GameUserRoleServiceImpl.java

@@ -22,8 +22,6 @@ 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.context.ApplicationContext;
-import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.client.RestTemplate;
@@ -265,7 +263,7 @@ public class GameUserRoleServiceImpl extends ServiceImpl<GameUserRoleMapper, Gam
                 .set(User::getUpdateTime, LocalDateTime.now())
                 .eq(User::getId, user.getId()));
         //用户创角回传
-        callBackService.roleCallBack(userRole, userData);
+        callBackService.roleCallBack(userRole);
         //用户创角埋点数据发送到卡夫卡
         kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_ROLE_CREATE, JsonUtil.toString(userRole));
         //创建角色通知监听服务

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä