diff --git a/ff-base/src/main/java/com/ff/base/constant/CacheConstants.java b/ff-base/src/main/java/com/ff/base/constant/CacheConstants.java index 676af5f..c943a1e 100644 --- a/ff-base/src/main/java/com/ff/base/constant/CacheConstants.java +++ b/ff-base/src/main/java/com/ff/base/constant/CacheConstants.java @@ -5,8 +5,7 @@ package com.ff.base.constant; * * @author ff */ -public class CacheConstants -{ +public class CacheConstants { /** * 登录用户 redis key */ @@ -45,43 +44,48 @@ public class CacheConstants /** * jili 游戏 */ - public static final String JILI_GAMES= "jili_games:"; + public static final String JILI_GAMES = "jili_games:"; /** * xk 游戏 */ - public static final String XK_GAMES= "xk_games:"; + public static final String XK_GAMES = "xk_games:"; /** * pgx游戏 */ - public static final String PGX_GAMES= "pgx_games:"; + public static final String PGX_GAMES = "pgx_games:"; /** * pg游戏 */ - public static final String PG_GAMES= "pg_games:"; + public static final String PG_GAMES = "pg_games:"; /** * fc游戏 */ - public static final String FC_GAMES= "fc_games:"; + public static final String FC_GAMES = "fc_games:"; /** * sa游戏 */ - public static final String SA_GAMES= "sa_games:"; + public static final String SA_GAMES = "sa_games:"; /** * dg游戏 */ - public static final String DG_GAMES= "dg_games:"; + public static final String DG_GAMES = "dg_games:"; /** * pg游戏投注货币 */ - public static final String PG_GAMES_BET_CURRENCY= "pg_games:bet:currency"; + public static final String PG_GAMES_BET_CURRENCY = "pg_games:bet:currency"; + /** + * 美天棋牌游戏 + */ + public static final String MeiTian_GAMES = "meitian_games:"; + } diff --git a/ff-base/src/main/java/com/ff/base/constant/Constants.java b/ff-base/src/main/java/com/ff/base/constant/Constants.java index cfb844f..180f339 100644 --- a/ff-base/src/main/java/com/ff/base/constant/Constants.java +++ b/ff-base/src/main/java/com/ff/base/constant/Constants.java @@ -219,6 +219,11 @@ public class Constants { */ public static final String SA_API_BASE_URL = "sa.api.base.url"; + /** + * 美天平台 + */ + public static final String MEITIAN_API_BASE_URL = "meitian.api.base.url"; + /** * 服务 */ diff --git a/ff-base/src/main/java/com/ff/base/enums/GamePlatforms.java b/ff-base/src/main/java/com/ff/base/enums/GamePlatforms.java index 6bd60a4..2b3e673 100644 --- a/ff-base/src/main/java/com/ff/base/enums/GamePlatforms.java +++ b/ff-base/src/main/java/com/ff/base/enums/GamePlatforms.java @@ -11,6 +11,8 @@ public enum GamePlatforms { FC("FC", "FC"), SA("SA", "SA"), DG("DG", "DG"), + MeiTIan("MeiTIan","美天棋牌") + , ; private final String code; diff --git a/ff-base/src/main/java/com/ff/base/enums/MeiTianGameType.java b/ff-base/src/main/java/com/ff/base/enums/MeiTianGameType.java new file mode 100644 index 0000000..c5ef5fa --- /dev/null +++ b/ff-base/src/main/java/com/ff/base/enums/MeiTianGameType.java @@ -0,0 +1,53 @@ +package com.ff.base.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Optional; +import java.util.stream.Stream; + +/** + * @author cengy + */ +@Getter +@AllArgsConstructor +public enum MeiTianGameType { + ELECTRON(4, 1, "电子"), + CHESS(2, 2, "棋牌"), + GAME_HALL(0, 3, "游戏大厅"), + CATCH_FISH(3, 4, "捕鱼") + //bai_ren(1, 5,"白人") + , + ; + private final Integer code; + private final Integer systemCode; + private final String info; + + /** + * 按代码查找系统 + * + * @param code 代码 + * @return {@link String } + */ + public static Integer findSystemByCode(Integer code) { + Optional system = Stream.of(MeiTianGameType.values()) + .filter(gameType -> gameType.getCode().equals(code)) + .map(MeiTianGameType::getSystemCode) + .findFirst(); + return system.orElse(null); + } + + /** + * 按代码查找信息 + * + * @param code 代码 + * @return {@link String } + */ + public static String findInfoByCode(Integer code) { + Optional system = Stream.of(MeiTianGameType.values()) + .filter(gameType -> gameType.getCode().equals(code)) + .map(MeiTianGameType::getInfo) + .findFirst(); + return system.orElse(null); + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/address/MeiTianAddressSource.java b/ff-game/src/main/java/com/ff/game/api/meitian/address/MeiTianAddressSource.java new file mode 100644 index 0000000..f0ccbee --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/address/MeiTianAddressSource.java @@ -0,0 +1,29 @@ +package com.ff.game.api.meitian.address; + +import com.dtflys.forest.callback.AddressSource; +import com.dtflys.forest.http.ForestAddress; +import com.dtflys.forest.http.ForestRequest; +import com.ff.base.constant.Constants; +import com.ff.base.system.service.ISysConfigService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + + +/** + * @author shi + * @date 2025/02/10 + */ +@Component +public class MeiTianAddressSource implements AddressSource { + + @Resource + private ISysConfigService configService; + + + @Override + public ForestAddress getAddress(ForestRequest request) { + String apiBaseUrl = configService.selectConfigByKey(Constants.MEITIAN_API_BASE_URL); + return new ForestAddress("https", apiBaseUrl, 443, "services"); + } +} \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/client/MeiTianClient.java b/ff-game/src/main/java/com/ff/game/api/meitian/client/MeiTianClient.java new file mode 100644 index 0000000..199e713 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/client/MeiTianClient.java @@ -0,0 +1,147 @@ +package com.ff.game.api.meitian.client; + +import com.dtflys.forest.annotation.Address; +import com.dtflys.forest.annotation.Body; +import com.dtflys.forest.annotation.Post; +import com.dtflys.forest.annotation.Var; +import com.ff.game.api.meitian.address.MeiTianAddressSource; +import com.ff.game.api.meitian.dto.*; + +/** + * jili 请求 + * + * @author shi + * @date 2025/02/10 + */ +@Address(source = MeiTianAddressSource.class) +public interface MeiTianClient { + + /** + * 创建会员 + * + * @param playerName + * @param merchantId + * @param pwd + * @return {@link MeiTianCreateMemberResponseDTO} + */ + @Post("/dg/player/playerCreate2/{playerName}/{merchantId}/{pwd}/{code}/{data}") + MeiTianCreateMemberResponseDTO createMember( + @Var("playerName") String playerName, + @Var("merchantId") String merchantId, + @Var("pwd") String pwd, + @Var("code") String code, + @Var("data") String data); + + /** + * 查询余额 + * + * @param playerName 用户名 + * @param merchantId 商户号 + * @return {@link MeiTianMemberInfoDTO} + */ + @Post("/dg/player/getPlayerBalance/{playerName}/{merchantId}") + MeiTianMemberInfoDTO getMemberInfo( + @Var("playerName") String playerName, + @Var("merchantId") String merchantId); + + /** + * 登录 + * + * @param merchantId 商户id + * @param playerName 玩家名 + * @return {@link MeiTianLoginResultDTO } + */ + @Post("/dg/player/playerPlatformUrl/{merchantId}/{playerName}/{pwd}/{code}/{data}") + MeiTianLoginResultDTO loginWithoutRedirect( + @Var("merchantId") String merchantId, + @Var("playerName") String playerName, + @Var("pwd") String pwd, + @Var("code") String code, + @Var("data") String data + ); + + + /** + * 转入 + * + * @param merchantId + * @param playerName + * @param coins + * @param extTransId + * @param code + * @param data + * @return {@link MeiTianExchangeMoneyResponseDTO} + */ + @Post("/dg/player/deposit2/{merchantId}/{playerName}/{coins}/{extTransId}/{code}/{data}") + MeiTianExchangeMoneyResponseDTO transferIn( + @Var("merchantId") String merchantId, + @Var("playerName") String playerName, + @Var("coins") String coins, + @Var("extTransId") String extTransId, + @Var("code") String code, + @Var("data") String data + ); + + + /** + * 转出 + * + * @param merchantId + * @param playerName + * @param coins + * @param extTransId + * @param code + * @param data + * @return {@link MeiTianExchangeMoneyResponseDTO} + */ + @Post("/dg/player/withdraw2/{merchantId}/{playerName}/{coins}/{extTransId}/{code}/{data}") + MeiTianExchangeMoneyResponseDTO transferOut( + @Var("merchantId") String merchantId, + @Var("playerName") String playerName, + @Var("coins") String coins, + @Var("extTransId") String extTransId, + @Var("code") String code, + @Var("data") String data + ); + + /** + * 按时间获取投注记录 + * + * @param parameters 参数 + * @param agentId 代理id + * @return {@link JILIBetRecordResponseDTO } + */ + @Post(url = "/GetBetRecordByTime?${parameters}") + JILIBetRecordResponseDTO getBetRecordByTime( + @Var("parameters") String parameters, + @Body("AgentId") String agentId); + + + /** + * 踢出 + * + * @param merchantId + * @param playerName + * @return {@link MeiTianLogoutDTO } + */ + @Post("/dg/player/logOutGame/{merchantId}/{playerName}") + MeiTianLogoutDTO kickMember( + @Var("merchantId") String merchantId, + @Var("playerName") String playerName + ); + + /** + * 获取游戏详情 + * + * @param merchantId + * @param code + * @param data + * @return {@link MeiTianGameRecordDetailDTO} + */ + @Post("dg/player/playCheckUrl/{merchantId}/{code}/{data}") + MeiTianGameRecordDetailDTO getGameDetail( + @Var("merchantId") String merchantId, + @Var("code") String code, + @Var("data") String data + ); +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/JILIBetRecordDataResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/JILIBetRecordDataResponseDTO.java new file mode 100644 index 0000000..8901da3 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/JILIBetRecordDataResponseDTO.java @@ -0,0 +1,89 @@ +package com.ff.game.api.meitian.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + + +/** + * JiLi游戏纪录查询返回数据类型 + * + * @author shi + * @date 2024/10/21 + */ +@NoArgsConstructor +@Data +public class JILIBetRecordDataResponseDTO { + /** + * 账户 + */ + @JsonProperty("Account") + private String account; + /** + * 投注id + */ + @JsonProperty("WagersId") + private String wagersId; + /** + * 游戏id + */ + @JsonProperty("GameId") + private String gameId; + /** + * 下注时间 + */ + @JsonProperty("WagersTime") + private Long wagersTime; + /** + * 投注金额 + */ + @JsonProperty("BetAmount") + private BigDecimal betAmount; + /** + * 回报时间 + */ + @JsonProperty("PayoffTime") + private Long payoffTime; + /** + * 支付金额 + */ + @JsonProperty("PayoffAmount") + private BigDecimal payoffAmount; + /** + * 注单状态 1: 赢 2: 输 3: 平局 + */ + @JsonProperty("Status") + private int status; + /** + * 结算时间 + */ + @JsonProperty("SettlementTime") + private Long settlementTime; + /** + * 游戏类别id + */ + @JsonProperty("GameCategoryId") + private int gameCategoryId; + /** + * 类型 + */ + @JsonProperty("Type") + private int type; + /** + * 代理id + */ + @JsonProperty("AgentId") + private String agentId; + /** + * 有效投注金额 + */ + @JsonProperty("Turnover") + private BigDecimal turnover; + /** + * 圆形指数 + */ + @JsonProperty("RoundIndex") + private long roundIndex; +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/JILIBetRecordResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/JILIBetRecordResponseDTO.java new file mode 100644 index 0000000..ae3975f --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/JILIBetRecordResponseDTO.java @@ -0,0 +1,62 @@ +package com.ff.game.api.meitian.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * JiLi游戏纪录查询返回值 + * + * @author shi + * @date 2024/10/21 + */ +@NoArgsConstructor +@Data +public class JILIBetRecordResponseDTO { + + + @JsonProperty("ErrorCode") + private int errorCode; + @JsonProperty("Message") + private String message; + @JsonProperty("Data") + private DataBean data; + + @NoArgsConstructor + @Data + public static class DataBean { + @JsonProperty("Result") + private List result; + @JsonProperty("Pagination") + private PaginationBean pagination; + + @NoArgsConstructor + @Data + public static class PaginationBean { + /** + * 当前页面 + */ + @JsonProperty("CurrentPage") + private int currentPage; + /** + * 总页数 + */ + @JsonProperty("TotalPages") + private int totalPages; + /** + * 页数限制 + */ + @JsonProperty("PageLimit") + private int pageLimit; + /** + * 总数 + */ + @JsonProperty("TotalNumber") + private int totalNumber; + } + + + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianCreateMemberResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianCreateMemberResponseDTO.java new file mode 100644 index 0000000..61a81df --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianCreateMemberResponseDTO.java @@ -0,0 +1,46 @@ +package com.ff.game.api.meitian.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + + +/** + * 创建成员响应dto + * + * @author shi + * @date 2024/10/22 + */ +@Data +public class MeiTianCreateMemberResponseDTO { + + /** + * 错误代码 + */ + @JsonProperty("resultCode") + private int resultCode; + + + @Getter + @AllArgsConstructor + public enum CreateMemberResultCode { + /** + * 成功 + */ + CreateException(0, "创建异常"), + CreateSuccess(1, "创建成功"), + MerchantNotExist(2, "商户不存在"), + MerchantInvalid(3, "商户无效"), + AlreadyRegistered(5, "商户用户已注册"), + IpLimit(15, "IP被限制"), + DecryptError(21, "解密错误"), + OptionalParameterError(32, "可选参数错误"), + Maintenance(40, "维护模式"), + ; + + private int code; + private String message; + + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianExchangeMoneyResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianExchangeMoneyResponseDTO.java new file mode 100644 index 0000000..c3a47b3 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianExchangeMoneyResponseDTO.java @@ -0,0 +1,118 @@ +package com.ff.game.api.meitian.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + +import java.math.BigDecimal; + +/** + * jiliexchange货币回应 + * + * @author shi + * @date 2024/10/22 + */ +@Data +public class MeiTianExchangeMoneyResponseDTO { + + + /** + * 错误代码 + */ + @JsonProperty("resultCode") + private int errorCode; + /** + * 交易序号,额度转移纪录唯一值, 长度上限 50 + */ + @JsonProperty("transId") + private String transactionId; + + /** + * 币种 + */ + @JsonProperty("currency") + private String currency; + + /** + * 余额 + */ + @JsonProperty("curBalance") + private BigDecimal balance; + + /** + * 时区(商户时区) GMT+8 + */ + @JsonProperty("timezone") + private String timezone; + + /** + * 交易时间 2018-08-08 12:23:44 + */ + @JsonProperty("date") + private String date; + + @Getter + @AllArgsConstructor + public enum TransferIn { + // 提现异常 + WITHDRAW_ERROR(0, "充值异常"), + // 提现成功 + WITHDRAW_SUCCESS(1, "充值成功"), + MERCHANT_NOT_EXIST(2, "商户不存在"), + MERCHANT_INVALID(3, "商户无效"), + MERCHANT_USER_NOT_EXIST(4, "商户用户不存在"), + MERCHANT_USER_SYSTEM_DISABLED(6, "商户用户系统禁用"), + MERCHANT_USER_GOLD_BALANCE_INSUFFICIENT(9, "商户用户金币余额不足"), + GAME_NOT_SETTLED(12, "游戏未结算"), + IP_LIMIT(15, "IP被限制"), + DECRYPT_ERROR(21, "解密错误"), + OPTIONAL_PARAMETER_ERROR(32, "可选参数错误"), + EXIST_UNPROCESSED_ORDER(36, "存在未处理订单"), + MAINTENANCE(40, "维护模式"), + Unknown(-1, "未知");; + private int code; + private String message; + + + public static TransferIn get(int code) { + for (TransferIn resultMessage : TransferIn.values()) { + if (resultMessage.code == code) { + return resultMessage; + } + } + return Unknown; + } + } + + @Getter + @AllArgsConstructor + public enum TransferOut { + WITHDRAW_ERROR(0, "提现异常"), + WITHDRAW_SUCCESS(1, "提现成功"), + MERCHANT_NOT_EXIST(2, "商户不存在"), + MERCHANT_INVALID(3, "商户无效"), + MERCHANT_USER_NOT_EXIST(4, "商户用户不存在"), + MERCHANT_USER_SYSTEM_DISABLED(6, "商户用户系统禁用"), + MERCHANT_USER_GOLD_BALANCE_INSUFFICIENT(9, "商户用户金币余额不足"), + GAME_NOT_SETTLED(12, "游戏未结算"), + IP_LIMIT(15, "IP被限制"), + DECRYPT_ERROR(21, "解密错误"), + OPTIONAL_PARAMETER_ERROR(32, "可选参数错误"), + EXIST_UNPROCESSED_ORDER(36, "存在未处理订单"), + MAINTENANCE(40, "维护模式"), + Unknown(-1, "未知");; + private int code; + private String message; + + + public static TransferOut get(int code) { + for (TransferOut resultMessage : TransferOut.values()) { + if (resultMessage.code == code) { + return resultMessage; + } + } + return Unknown; + } + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianGameDataDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianGameDataDTO.java new file mode 100644 index 0000000..2a89a6b --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianGameDataDTO.java @@ -0,0 +1,31 @@ +package com.ff.game.api.meitian.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * jiligames数据dto + * + * @author shi + * @date 2024/10/22 + */ +@NoArgsConstructor +@Data +@Builder +@AllArgsConstructor +public class MeiTianGameDataDTO { + + + /** + *自己系统游戏id + */ + private Long systemGameId; + private String gameId; + private String cnName; + private String enName; + private Integer gameCategoryId; + +} \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianGameRecordDetailDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianGameRecordDetailDTO.java new file mode 100644 index 0000000..c7d2bbd --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianGameRecordDetailDTO.java @@ -0,0 +1,51 @@ +package com.ff.game.api.meitian.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * 获取游戏详细信息请求dto + * + * @author shi + * @date 2024/11/12 + */ +@NoArgsConstructor +@Data +public class MeiTianGameRecordDetailDTO { + + @JsonProperty("resultCode") + private int errorCode; + + private String url; + private String currency; + + @Getter + @AllArgsConstructor + public enum ResultMessage { + QueryException(0, "查询异常"), + QuerySuccess(1, "查询成功"), + MerchantNotExist(2, "商户不存在"), + MerchantInvalid(3, "商户无效"), + IPLimited(15, "IP被限制"), + DecryptError(21, "解密错误"), + OptionalParameterError(32, "可选参数错误"), + MaintenanceMode(40, "维护模式"), + Unknown(-1, "未知错误"), + ; + private int code; + private String message; + } + + public static ResultMessage get(int code) { + for (ResultMessage resultMessage : ResultMessage.values()) { + if (resultMessage.getCode() == code) { + return resultMessage; + } + } + return ResultMessage.Unknown; + } + +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianGamesDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianGamesDTO.java new file mode 100644 index 0000000..606febf --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianGamesDTO.java @@ -0,0 +1,171 @@ +package com.ff.game.api.meitian.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 游戏 + * + * @author shi + * @date 2024/10/22 + */ + +@NoArgsConstructor +@Data +public class MeiTianGamesDTO { + + // 捕鱼:3棋牌:2街机:4百人:1全部:0或不传 + private List data; + + { + data = new java.util.ArrayList<>(); + // 捕鱼游戏数据列表 + String[][] buyu = { + {"PTG0056", "3D捕鱼", "3D Fishing", "3"}, + {"PTG0011", "李逵劈鱼", "Fishing Kui Lee", "3"}, + {"PTG0045", "金蟾捕鱼", "Golden Toad", "3"}, + {"PTG0100", "海王2", "Ocean King 2", "3"}, + {"PTG0094", "疯狂捕鱼", "Crazy Fishing", "3"}, + {"PTG0004", "捕鱼来了", "Fishing Joy", "3"}, + {"PTG0104", "疯狂魔鬼城", "Trick or Treat", "3"}, + {"PTG0125", "水果炸翻天", "Fruits Carnival", "3"}, + }; + + addGames(buyu, data); + + // 棋牌游戏数据列表 + String[][] qipai = { + {"PTG0042", "五人牛牛", "Beat Bullfight", "2"}, + {"PTG0022", "通比牛牛", "Mutual Bullfight", "2"}, + {"PTG0013", "二人牛牛", "Versus Niu-Niu", "2"}, + {"PTG0039", "十三水", "Winning Thirteen", "2"}, + {"PTG0062", "炸金花", "Fraud Jinhua", "2"}, + {"PTG0037", "德州扑克", "Texas Hold'em", "2"}, + {"PTG0006", "欢乐斗地主", "Fight the Landlord", "2"}, + {"PTG0023", "黑杰克", "Black Jack", "2"}, + {"PTG0017", "二人梭哈", "Show Hand", "2"}, + {"PTG0080", "抢庄牌九", "Pai Gow", "2"}, + {"PTG0082", "三公", "3-card poker", "2"}, + {"PTG0061", "明牌牛牛", "Spread Bullfight", "2"}, + {"PTG0084", "土豪百家乐", "Rich Baccarat", "2"}, + {"PTG0085", "推筒子", "versus 2-8 bar", "2"}, + {"PTG0086", "二人雀神", "Versus Mahjong", "2"}, + {"PTG0093", "血流成河", "Rivers of Blood", "2"}, + {"PTG0110", "看牌牛牛", "Royal Bull-fight", "2"}, + {"PTG0121", "越式13张", "TIEN LEN", "2"}, + {"PTG0127", "UNO", "UNO", "2"}, + {"PTG0122", "Dummy", "Dummy", "2"}, + {"PTG0123", "九鸡", "Jiu-Ji", "2"}, // 未分类 + {"PTG0124", "博丁", "Bo-Ding", "2"}, // 未分类 + {"PTG0126", "牌肯", "Card Ken", "2"}, + {"PTG0133", "泰式十三支", "Thai 13 Cards", "2"}, + {"PTG0134", "泰九牌", "Gao Gae Thai", "2"}, + {"PTG0136", "Dummy Speto", "Dummy Speto", "2"}, + {"PTG0137", "Gao Gae Sam Bai Thod", "Gao Gae Sam Bai Thod", "2"}, + {"PTG0138", "Slave Card", "Slave Card", "2"} + }; + addGames(qipai, data); + + // 百人场游戏数据列表 + String[][] bairenchang = { + {"PTG0058", "红黑大战", "King's Queen", "1"}, + {"PTG0044", "百人牛牛", "Hundred Niu-Niu", "1"}, + {"PTG0059", "百家乐", "Baccarat", "1"}, + {"PTG0008", "豪车漂移", "Drift Car Racing", "-1"}, // 未分类 + {"PTG0041", "龙虎斗", "The Chinese Boxer", "1"}, + {"PTG0007", "飞禽走兽", "Fowls and Beasts", "-1"}, // 未分类 + {"PTG0036", "五星宏辉", "Five Star Stud", "1"}, + {"PTG0064", "金鲨银鲨", "Golden Shark", "1"}, + {"PTG0020", "西游争霸", "Journey to the West", "1"}, + {"PTG0018", "港式赛马", "Horse Racing", "-1"}, // 未分类 + {"PTG0070", "二八杠", "2-8 Bar", "-1"}, // 未分类 + {"PTG0081", "骰宝", "Sic bo", "1"}, + {"PTG0067", "森林舞会", "Forest Party", "-1"}, // 未分类 + {"PTG0091", "鱼虾蟹", "Crab and Shrimp", "1"}, + {"PTG0092", "红包扫雷", "Minesweeping", "-1"}, // 未分类 + {"PTG0089", "动物跑跑跑", "Animal Running", "-1"}, // 未分类 + {"PTG0116", "越式鱼虾蟹", "Vietnamese Fish-Prawn-Crab", "-1"}, // 未分类 + {"PTG0102", "正版抢车位", "GA Car Parking", "-1"}, // 未分类 + {"PTG0120", "番摊", "FAN TAN", "1"}, + {"PTG2008", "西游争霸战无不胜", "Monkey King2 PLUS", "-1"}, // 未分类 + {"PTG0135", "泰式鱼虾蟹", "Thai Fish Prawn Crab", "-1"} // 未分类 + }; + addGames(bairenchang, data); + + // 街机游戏数据列表 + String[][] dianzi = { + {"PTG0060", "超级大亨", "Super Tycoon", "4"}, + {"PTG0069", "ATT金皇冠", "ATT Gold Crown", "4"}, + {"PTG0001", "水果机", "Super Frootz", "4"}, + {"PTG0010", "水浒传", "The Water Margin", "4"}, + {"PTG0066", "大满贯水果机", "Grand Slam Frootz", "4"}, + {"PTG0068", "泰山闯天关2", "Tarzan Adventure 2", "4"}, + {"PTG0083", "财神到", "Mammon", "4"}, + {"PTG0079", "不倒翁", "Happy tumbler", "4"}, + {"PTG0087", "醉西游", "Monkey King", "4"}, + {"PTG0090", "延禧攻略", "Story of Yanxi Palace", "4"}, + {"PTG0095", "连环夺宝", "Linking Jewels", "4"}, + {"PTG0098", "三只小猪", "Three Little Pigs", "4"}, + {"PTG0097", "招财猫", "Fortune Cat", "4"}, + {"PTG0099", "欲望魅影", "Sexy Succubus", "4"}, + {"PTG0096", "绝地求生", "Playerunknown's Battlegrounds", "4"}, + {"PTG0101", "埃及艳后", "Cleopatra's treasures", "4"}, + {"PTG0103", "年年有鱼", "Lucky boy", "4"}, + {"PTG0105", "天空之神", "God of Sky", "4"}, + {"PTG0107", "阿拉丁神灯", "PLUS ALADDIN'S GOLD", "4"}, + {"PTG0109", "武媚娘传奇", "Empress Wu Zetian", "4"}, + {"PTG0106", "亿万富翁", "Billionaire", "4"}, + {"PTG0115", "萝卜跳一跳", "Jump Hot", "4"}, + {"PTG0117", "宫心计", "Beyond The Realm Of Conscience", "4"}, + {"PTG2001", "恭喜发财", "Good Fortune", "4"}, + {"PTG2002", "新潘金莲", "Pan Jinlian", "4"}, + {"PTG2003", "宫本武藏", "Miyamoto Musashi", "4"}, + {"PTG2004", "武则天", "Empress of the Great Tang", "4"}, + {"PTG2005", "发发发", "Fa Fa Fa", "4"}, + {"PTG2007", "赏金船长", "Captain's Bounty", "4"}, + {"PTG2009", "爱尔兰精灵", "Leprechaun Riches", "4"}, + {"PTG2010", "水浒传豪华版", "Water Margin DELUXE", "4"}, + {"PTG2011", "金钱豹水果机", "Golden Jaguar", "4"}, + {"PTG0118", "疯狂猴子", "Crazy Monkey", "4"}, + {"PTG2015", "金刚", "King Kong", "4"}, + {"PTG2016", "福星献舞", "Dancing FU", "4"}, + {"PTG2017", "野蛮世界", "HUGA", "4"}, + {"PTG2018", "上海甜心", "Shanghai Honey", "4"}, + {"PTG2019", "美洲野牛", "Buffalo Gold", "4"}, + {"PTG2020", "白蛇传", "The Legend of White Snake", "4"}, + {"PTG2021", "笑弥勒", "Happys Prosperous", "4"}, + {"PTG2013", "招财推币机", "Fortune Coindozer", "4"}, + {"PTG2025", "东海之王", "Dragon Of The Eastern Ocean", "4"}, + {"PTG2028", "中国龙", "Dragon World", "4"}, + {"PTG2023", "秦皇传说", "Legend of Emperor Qin", "4"}, + {"PTG2026", "辣椒多多", "More Chilli", "4"}, + {"PTG2029", "财神驾到", "CHOY SUN DOA", "4"}, + {"PTG2030", "招财猫2", "Fortune Cat 2", "4"}, + {"PTG2031", "黄金城魅影", "Gold City Treasure Hunt", "4"}, + {"PTG2032", "亡灵宝藏", "WILD BANDITO", "4"}, + {"PTG2033", "麒麟献宝", "WAYS OF THE QILIN", "4"}, + {"PTG2034", "天将神兵", "Heavenly Warriors", "4"} + }; + + addGames(dianzi, data); + + } + + public void addGames(String[][] gameData, List dataList) { + // 添加数据到 List + for (String[] game : gameData) { + String gameId = game[0]; + String cnName = game[1]; + String enName = game[2]; + Integer categoryId = Integer.valueOf(game[3]); + dataList.add(MeiTianGameDataDTO.builder().gameId(gameId) + .cnName(cnName) + .enName(enName) + .gameCategoryId(categoryId) + .build()); + } + + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianLoginResultDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianLoginResultDTO.java new file mode 100644 index 0000000..cea3089 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianLoginResultDTO.java @@ -0,0 +1,52 @@ +package com.ff.game.api.meitian.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * 登录时不重定向响应dto + * + * @author shi + * @date 2024/10/22 + */ +@NoArgsConstructor +@Data +public class MeiTianLoginResultDTO { + + @JsonProperty("resultCode") + private int errorCode; + @JsonProperty("url") + private String url; + + @Getter + @AllArgsConstructor + public enum ResultMessage { + LoginException(0, "登录异常"), + LoginSuccess(1, "登录成功"), + MerchantNotExist(2, "商户不存在"), + MerchantInvalid(3, "商户无效"), + MerchantUserNotExist(4, "商户用户不存在"), + MerchantUserSystemDisabled(6, "商户用户系统禁用"), + PasswordError(7, "密码错误"), + IPLimited(15, "IP被限制"), + DecryptError(21, "解密错误"), + MerchantUserLoginDisabled(22, "商户用户登录禁用"), + OptionalParameterError(32, "可选参数错误"), + MaintenanceMode(40, "维护模式"), + Unknown(-1, "未知错误"); + private int code; + private String message; + } + + public static ResultMessage get(int errorCode) { + for (ResultMessage resultMessage : ResultMessage.values()) { + if (resultMessage.getCode() == errorCode) { + return resultMessage; + } + } + return ResultMessage.Unknown; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianLogoutDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianLogoutDTO.java new file mode 100644 index 0000000..103321c --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianLogoutDTO.java @@ -0,0 +1,43 @@ +package com.ff.game.api.meitian.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@Data +public class MeiTianLogoutDTO { + + @JsonProperty("resultCode") + private int errorCode; + + + @Getter + @AllArgsConstructor + public enum ResultMessage { + QueryException(0, "查询异常"), + QuerySuccess(1, "查询成功"), + MerchantNotExist(2, "商户不存在"), + MerchantInvalid(3, "商户无效"), + MerchantUserNotExist(4, "商户用户不存在"), + MerchantUserSystemDisabled(6, "商户用户系统禁用"), + MerchantUserGameOnline(12, "商户用户游戏在线"), + IPLimited(15, "IP被限制"), + MaintenanceMode(40, "维护模式"), + Unknown(-1, "未知错误") + ,; + private int code; + private String message; + } + + public static ResultMessage get(int errorCode) { + for (ResultMessage resultMessage : ResultMessage.values()) { + if (resultMessage.code == errorCode) { + return resultMessage; + } + } + return ResultMessage.Unknown; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianMemberInfoDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianMemberInfoDTO.java new file mode 100644 index 0000000..c28eea2 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianMemberInfoDTO.java @@ -0,0 +1,69 @@ +package com.ff.game.api.meitian.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +/** + * 会员信息dto + * + * @author shi + * @date 2024/10/30 + */ +@NoArgsConstructor +@Data +public class MeiTianMemberInfoDTO { + + /** + * 错误代码 + */ + @JsonProperty("resultCode") + private int errorCode; + /** + * 余额 + */ + @JsonProperty("coinBalance") + private BigDecimal balance; + + @JsonProperty("status") + private Integer status; + + @JsonProperty("currency") + private String currency; + + + @Getter + @AllArgsConstructor + public enum ResultMessage { + Excep(0,"查询异常"), + Success(1,"查询成功"), + // 商户不存在 + MerchantNotExist(2,"商户不存在"), + // 商户无效 + MerchantInvalid(3,"商户无效"), + // 商户用户不存在 + AccountNotExist(4,"商户用户不存在"), + // IP被限制 + IpLimit(15,"IP被限制"), + // 维护模式 + Maintenance(40,"维护模式"), + + Unknown(-1, "未知") + ,; + private int code; + private String message; + + public static ResultMessage getResultMessage(int code) { + for (ResultMessage resultMessage : ResultMessage.values()) { + if (resultMessage.code == code) { + return resultMessage; + } + } + return Unknown; + } + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/impl/MeiTianGameServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/meitian/impl/MeiTianGameServiceImpl.java new file mode 100644 index 0000000..2f4628c --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/impl/MeiTianGameServiceImpl.java @@ -0,0 +1,677 @@ +package com.ff.game.api.meitian.impl; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.NumberUtil; +import com.alibaba.fastjson2.JSON; +import com.ff.base.constant.CacheConstants; +import com.ff.base.constant.Constants; +import com.ff.base.core.redis.RedisCache; +import com.ff.base.enums.*; +import com.ff.base.exception.base.ApiException; +import com.ff.base.exception.base.BaseException; +import com.ff.base.system.service.ISysConfigService; +import com.ff.base.utils.DateUtils; +import com.ff.base.utils.sign.Md5Utils; +import com.ff.base.utils.uuid.IdUtils; +import com.ff.game.api.IGamesService; +import com.ff.game.api.meitian.client.MeiTianClient; +import com.ff.game.api.meitian.dto.*; +import com.ff.game.api.request.*; +import com.ff.game.domain.*; +import com.ff.game.dto.GameSecretKeyCurrencyDTO; +import com.ff.game.service.*; +import com.ff.member.domain.Member; +import com.ff.member.service.IMemberService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + + +/** + * 游戏数据解析服务 + * + * @author shi + * @date 2024/10/21 + */ +@Service("MeiTianService") +@Slf4j +public class MeiTianGameServiceImpl implements IGamesService { + + + @Resource + private ISysConfigService configService; + + @Resource + private RedisCache redisCache; + + @Resource + private IGameExchangeMoneyService gameExchangeMoneyService; + + @Resource + private IGamePlatformService gamePlatformService; + + + @Resource + private IGameService gameService; + + + @Resource + private IMemberService memberService; + + + @Resource + private IGameSecretKeyService gameSecretKeyService; + + @Resource + private MeiTianClient meiTianClient; + + @Resource + private IGameBettingDetailsService gameBettingDetailsService; + + @Resource + private IGameSecretKeyCurrencyService gameSecretKeyCurrencyService; + + @Resource + private IGameNameService gameNameService; + + /** + * 获得就是成功 + * + * @param errorCode 错误代码 + * @return {@link Boolean } + */ + private Boolean isSuccess(Integer errorCode) { + return 1 == errorCode; + } + + /** + * 创建成员 + * + * @param createMemberRequestDTO 创建成员请求dto + * @return {@link Boolean } + */ + @Override + public Boolean createMember(CreateMemberRequestDTO createMemberRequestDTO) { + GameSecretKey gameSecretKey = gameSecretKeyService.selectGameSecretKeyByCode(createMemberRequestDTO.getAgentId()); + + String playerName = createMemberRequestDTO.getAccount(); + String merchantId = createMemberRequestDTO.getAgentId(); + String md5Password = Md5Utils.md5New(gameSecretKey.getPassword()); + Map rawMap = new LinkedHashMap<>(); + rawMap.put("nickname", createMemberRequestDTO.getAccount()); + rawMap.put("playerLevel", "0"); + String rawData = JSON.toJSONString(rawMap); + String data = null; + try { + data = Base64.encode(rawData.getBytes(StandardCharsets.UTF_8)); + } catch (Exception e) { + log.error("[MeiTian] encode rawData failure", e); + throw new ApiException(ErrorCode.ERROR.getCode()); + } + String md5Code = Md5Utils.md5New(gameSecretKey.getKey() + rawData);//MD5(key+rawData); + MeiTianCreateMemberResponseDTO createMemberResponseDTO = + meiTianClient.createMember( + playerName, + merchantId, + md5Password, + md5Code, + data); + int errorCode = createMemberResponseDTO.getResultCode(); + log.info("[MeiTian]创建会员失败返回结果:{}", errorCode); + if (1 == errorCode) { + return Boolean.TRUE; + } + if (5 == errorCode) { + throw new ApiException(ErrorCode.GAME_ACCOUNT_CREATION_FAILED.getCode()); + } + //判断是否获取成功 + return Boolean.FALSE; + } + + + /** + * 获取会员信息 + * + * @param memberInfoRequestDTO 会员信息请求dto + * @return {@link MemberInfoResponseDTO } + */ + @Override + public MemberInfoResponseDTO getMemberInfo(MemberInfoRequestDTO memberInfoRequestDTO) { + + String playerName = memberInfoRequestDTO.getAccounts(); + String merchantId = memberInfoRequestDTO.getAgentId(); + MeiTianMemberInfoDTO memberInfoDTO = meiTianClient.getMemberInfo(playerName, merchantId); + //判断是否获取成功 + if (this.isSuccess(memberInfoDTO.getErrorCode())) { + return MemberInfoResponseDTO.builder() + .status(GameMemberStatus.UNKNOWN.getCode()) + .balance(memberInfoDTO.getBalance()) + .account(playerName) + .build(); + } else { + throw new BaseException(MeiTianMemberInfoDTO.ResultMessage.getResultMessage(memberInfoDTO.getErrorCode()).getMessage()); + } + } + + /** + * 无重定向登录 + * + * @param gamesLogin 游戏登录 + * @return {@link String } + */ + @Override + public String loginWithoutRedirect(GamesLogin gamesLogin) { + GameSecretKey gameSecretKey = gameSecretKeyService.selectGameSecretKeyByCode(gamesLogin.getAgentId()); + + String merchantId = gamesLogin.getAgentId(); + String playerName = gamesLogin.getAccount(); + String md5Password = Md5Utils.md5New(gameSecretKey.getPassword()); + Map rawMap = new LinkedHashMap<>(); + rawMap.put("gameHall ", gamesLogin.getGameType()); + /*rawMap.put("gameCode", gamesLogin.getGameId()); + rawMap.put("lang", gamesLogin.getLang()); + rawMap.put("roomID", "0");*/ + + String rawData = JSON.toJSONString(rawMap); + String data = null; + try { + data = Base64.encode(rawData.getBytes(StandardCharsets.UTF_8)); + } catch (Exception e) { + log.error("[MeiTian] encode rawData failure", e); + throw new ApiException(ErrorCode.ERROR.getCode()); + } + String code = Md5Utils.md5New(gameSecretKey.getKey() + rawData); + MeiTianLoginResultDTO loginWithoutRedirectResponseDTO = + meiTianClient.loginWithoutRedirect( + merchantId, + playerName, + md5Password, + code, + data + ); + //判断是否获取成功 + if (this.isSuccess(loginWithoutRedirectResponseDTO.getErrorCode())) { + return loginWithoutRedirectResponseDTO.getUrl(); + } else { + throw new BaseException(MeiTianLoginResultDTO.get(loginWithoutRedirectResponseDTO.getErrorCode()).getMessage()); + } + + } + + /** + * 获取游戏列表 + * + * @param gamesBaseRequestDTO 游戏请求dto + * @return {@link String } + */ + @Transactional + @Override + public String getGameList(GamesBaseRequestDTO gamesBaseRequestDTO) { + + List gamesDatas = redisCache.getCacheList(CacheConstants.MeiTian_GAMES); + if (!CollectionUtils.isEmpty(gamesDatas)) { + return CacheConstants.MeiTian_GAMES; + } + + MeiTianGamesDTO gameList = new MeiTianGamesDTO(); + + for (MeiTianGameDataDTO gamesDataDTO : gameList.getData()) { + GamePlatform gamePlatform = GamePlatform.builder() + .platformType(MeiTianGameType.findSystemByCode(gamesDataDTO.getGameCategoryId())) + .platformCode(GamePlatforms.MeiTIan.getCode()) + .build(); + List gamePlatforms = gamePlatformService.selectGamePlatformList(gamePlatform); + //没有此平台就新增一个平台 + if (CollectionUtils.isEmpty(gamePlatforms)) { + gamePlatform.setPlatformName(GamePlatforms.MeiTIan.getInfo() + MeiTianGameType.findInfoByCode(gamesDataDTO.getGameCategoryId())); + gamePlatform.setSortNo(gamePlatformService.selectMaxSortNo() + 1); + gamePlatform.setCreateBy(Constants.SYSTEM); + gamePlatformService.insertGamePlatform(gamePlatform); + } else { + gamePlatform = gamePlatforms.get(0); + } + Game game = Game.builder() + .platformId(gamePlatform.getId()) + .gameCode(String.valueOf(gamesDataDTO.getGameId())) + .build(); + List games = gameService.selectGameList(game); + //不存在这个游戏 + if (CollectionUtils.isEmpty(games)) { + game.setGameSourceType(String.valueOf(gamesDataDTO.getGameCategoryId())); + game.setFreespin(false); + game.setSortNo(gameService.selectMaxSortNoByPlatformId(gamePlatform.getId()) + 1); + game.setGameName(gamesDataDTO.getCnName()); + game.setCreateBy(Constants.SYSTEM); + gameService.insertGame(game); + } else { + game = games.get(0); + } + gamesDataDTO.setSystemGameId(game.getId()); + + List gameNames = gameNameService.selectGameNameList(GameName.builder().gameId(game.getId()).gameName(game.getGameName()).build()); + if (CollectionUtils.isEmpty(gameNames)) { + gameNameService.insertGameName(GameName.builder() + .gameId(game.getId()) + .gameName(game.getGameName()) + .langCode("zh-CN") + .createBy(Constants.SYSTEM) + .build()); +// + gameNameService.insertGameName(GameName.builder() + .gameId(game.getId()) + .gameName(gamesDataDTO.getEnName()) + .langCode("en-US") + .createBy(Constants.SYSTEM) + .build()); + } + + + } + + redisCache.deleteObject(CacheConstants.MeiTian_GAMES); + redisCache.setCacheList(CacheConstants.MeiTian_GAMES, gameList.getData()); + redisCache.expire(CacheConstants.MeiTian_GAMES, 5L, TimeUnit.HOURS); + + return CacheConstants.MeiTian_GAMES; + } + + /** + * 按代理id进行交换转账 + * + * @param exchangeTransferMoneyRequestDTO 外汇转账moeny dto + * @return {@link Long } + */ + @Override + @Transactional + public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO) { + GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() + .code(exchangeTransferMoneyRequestDTO.getAgentId()) + .currency(exchangeTransferMoneyRequestDTO.getCurrency()).build()); + + Member member = memberService.selectMemberByGameAccount(exchangeTransferMoneyRequestDTO.getAccount()); + String transactionId = GamePlatforms.MeiTIan.getCode() + IdUtils.simpleUUID(); + + List gameExchangeMonies = gameExchangeMoneyService.selectGameExchangeMoneyList( + GameExchangeMoney.builder() + .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) + .orderId(exchangeTransferMoneyRequestDTO.getOrderId()) + .build() + ); + Assert.isTrue(CollectionUtils.isEmpty(gameExchangeMonies), "订单号重复"); + + + //获取下一个自增id + GameExchangeMoney exchangeMoney = GameExchangeMoney + .builder() + .orderId(exchangeTransferMoneyRequestDTO.getOrderId()) + .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) + .quota(exchangeTransferMoneyRequestDTO.getQuota()) + .balance(exchangeTransferMoneyRequestDTO.getAmount()) + .exchangeType(exchangeTransferMoneyRequestDTO.getTransferType()) + .currencyCode(gameSecretKey.getSystemCurrency()) + .memberId(member.getId()) + .transactionId(transactionId) + .platformCode(GamePlatforms.MeiTIan.getCode()) + .build(); + exchangeMoney.setCreateBy(Constants.SYSTEM); + //接口限制限制50字符 + exchangeMoney.setTransactionId(transactionId); + + + String key = gameSecretKey.getKey(); + String merchantId = exchangeTransferMoneyRequestDTO.getAgentId(); + String playerName = exchangeTransferMoneyRequestDTO.getAccount(); + String coins = exchangeTransferMoneyRequestDTO.getAmount().setScale(4, RoundingMode.DOWN).toString(); + Map rawMap = new LinkedHashMap<>(); + rawMap.put("merchantId", merchantId); + rawMap.put("playerName", playerName); + rawMap.put("extTransId", transactionId); + rawMap.put("coins", coins); + String rawData = JSON.toJSONString(rawMap); + String data = null; + try { + data = Base64.encode(rawData.getBytes(StandardCharsets.UTF_8)); + } catch (Exception e) { + log.error("[MeiTian] base64 rawData failure", e); + throw new ApiException(ErrorCode.BALANCE_TRANSFER_FAILED.getCode()); + } + String md5Code = Md5Utils.md5New(key + rawData); + // 转入到游戏商 type == 2 + if (exchangeTransferMoneyRequestDTO.getTransferType().equals(TransferType.GAMES.getCode())) { + + MeiTianExchangeMoneyResponseDTO exchangeMoneyResponse = meiTianClient + .transferIn( + merchantId, + playerName, + coins, + transactionId, + md5Code, + data + ); + + //判断是否转移成功 + if (this.isSuccess(exchangeMoneyResponse.getErrorCode())) { + //更新数据 + exchangeMoney.setBalance(exchangeMoneyResponse.getBalance()); + BigDecimal transAmount = exchangeTransferMoneyRequestDTO.getAmount(); + exchangeMoney.setCoinBefore(exchangeMoneyResponse.getBalance().subtract(transAmount)); + exchangeMoney.setCoinAfter(exchangeMoneyResponse.getBalance()); + exchangeMoney.setCurrencyBefore(exchangeMoneyResponse.getBalance().subtract(transAmount)); + exchangeMoney.setCurrencyAfter(exchangeMoneyResponse.getBalance()); + exchangeMoney.setStatus(1); // SUCCESS + gameExchangeMoneyService.insertGameExchangeMoney(exchangeMoney); + + } else { + throw new BaseException(MeiTianExchangeMoneyResponseDTO.TransferIn.get(exchangeMoneyResponse.getErrorCode()).getMessage()); + } + + } else { + + MeiTianExchangeMoneyResponseDTO exchangeMoneyResponse = meiTianClient + .transferOut( + merchantId, + playerName, + coins, + transactionId, + md5Code, + data + ); + + //判断是否转移成功 + if (this.isSuccess(exchangeMoneyResponse.getErrorCode())) { + //更新数据 + exchangeMoney.setBalance(exchangeMoneyResponse.getBalance()); + BigDecimal transAmount = exchangeTransferMoneyRequestDTO.getAmount(); + exchangeMoney.setCoinBefore(exchangeMoneyResponse.getBalance().add(transAmount)); + exchangeMoney.setCoinAfter(exchangeMoneyResponse.getBalance()); + exchangeMoney.setCurrencyBefore(exchangeMoneyResponse.getBalance().add(transAmount)); + exchangeMoney.setCurrencyAfter(exchangeMoneyResponse.getBalance()); + exchangeMoney.setStatus(1); // SUCCESS + gameExchangeMoneyService.insertGameExchangeMoney(exchangeMoney); + } else { + throw new BaseException(MeiTianExchangeMoneyResponseDTO.TransferOut.get(exchangeMoneyResponse.getErrorCode()).getMessage()); + } + } + return exchangeMoney.getId(); + } + + /** + * 汇兑转移状态 + * + * @param exchangeTransferMoneyRequestDTO 兑换转账请求dto + * @return {@link Boolean } + */ + @Override + public Boolean exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { + return Boolean.TRUE; + } + + + /** + * 按时间获取投注记录 + * + * @param betRecordByTimeDTO 按时间dto投注记录 + * @return {@link Boolean } + */ + @Override + public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) { + + /*//获取key + JILIBetRecordResponseDTO betRecordJILIResponse = meiTianClient.getBetRecordByTime(query + "&Key=" + key, betRecordByTimeDTO.getAgentId()); + + //判断是否获取成功 + if (this.isSuccess(betRecordJILIResponse.getErrorCode())) { + //数据插入 + this.batchInsert(betRecordJILIResponse); + JILIBetRecordResponseDTO.DataBean dataBean = betRecordJILIResponse.getData(); + //获取下一页数据 + while (dataBean.getPagination().getCurrentPage() != dataBean.getPagination().getTotalPages() && dataBean.getPagination().getTotalPages() > 0) { + betRecordByTimeDTO.setPage(dataBean.getPagination().getCurrentPage() + 1); + //请求参数 + query = "StartTime=" + startTime + "&EndTime=" + endTime + "&Page=" + betRecordByTimeDTO.getPage() + "&PageLimit=" + betRecordByTimeDTO.getPageLimit() + "&AgentId=" + betRecordByTimeDTO.getAgentId(); + log.info("GamesJILIServiceImpl [getBetRecordByTime] 请求参数 {}", query); + betRecordByTimeDTO.setQuery(query); + key = this.getKey(betRecordByTimeDTO); + betRecordJILIResponse = meiTianClient.getBetRecordByTime(query + "&Key=" + key, betRecordByTimeDTO.getAgentId()); + dataBean = betRecordJILIResponse.getData(); + if (this.isSuccess(betRecordJILIResponse.getErrorCode())) { + //数据插入 + this.batchInsert(betRecordJILIResponse); + } else { + log.error("GameBettingDataJILIServiceImpl [getBetRecordByTime] 获取投注记录失败,错误代码{},错误信息{}", betRecordJILIResponse.getErrorCode(), betRecordJILIResponse.getMessage()); + } + } + } else { + return Boolean.FALSE; + }*/ + return Boolean.TRUE; + } + + + /** + * 按历史时间获取投注记录 + * + * @param betRecordByTimeDTO 按时间dto投注记录 + * @return {@link Boolean } + */ + @Override + public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { + return null; + } + + + /** + * 赠送免费局数 + * + * @param createFreeSpinRequest 创建自由旋转请求 + * @return {@link Boolean } + */ + @Override + public Boolean createFreeSpin(CreateFreeSpinRequestDTO createFreeSpinRequest) { + throw new BaseException("暂不支持免费局数"); + } + + /** + * 获取游戏详细信息 + * + * @param getGameDetailRequestDTO 获取游戏详细信息请求dto + * @return {@link GetGameDetailResponseDTO } + */ + @Override + public GetGameDetailResponseDTO getGameDetail(GetGameDetailRequestDTO getGameDetailRequestDTO) { + GameSecretKey gameSecretKey = gameSecretKeyService.selectGameSecretKeyByCode(getGameDetailRequestDTO.getAgentId()); + + String key = gameSecretKey.getKey(); + String merchantId = getGameDetailRequestDTO.getAgentId(); + Map rawMap = new LinkedHashMap<>(); + rawMap.put("rowID", getGameDetailRequestDTO.getWagersId()); + rawMap.put("lang", getGameDetailRequestDTO.getLang()); + + String rawData = JSON.toJSONString(rawMap); + String data = null; + try { + data = Base64.encode(rawData.getBytes("UTF-8")); + } catch (Exception e) { + log.error("[MeiTian] encode rawData failure", e); + throw new ApiException(ErrorCode.ERROR.getCode()); + } + String code = Md5Utils.md5New(data + key); + MeiTianGameRecordDetailDTO responseDTO = meiTianClient.getGameDetail(merchantId, code, data); + + //判断是否获取成功 + if (this.isSuccess(responseDTO.getErrorCode())) { + GetGameDetailResponseDTO getGameDetailResponseDTO = new GetGameDetailResponseDTO(); + getGameDetailResponseDTO.setUrl(responseDTO.getUrl()); + return getGameDetailResponseDTO; + } else { + throw new BaseException(MeiTianGameRecordDetailDTO.get(responseDTO.getErrorCode()).getMessage()); + } + } + + /** + * 强制会员从游戏注销 + * + * @param kickMemberRequestDTO 踢会员请求dto + * @return {@link Boolean } + */ + @Override + public Boolean kickMember(KickMemberRequestDTO kickMemberRequestDTO) { + + String merchantId = kickMemberRequestDTO.getAgentId(); + String playerName = kickMemberRequestDTO.getAccount(); + + MeiTianLogoutDTO jiliKickMemberDTO = meiTianClient.kickMember( + merchantId, + playerName); + //判断是否获取成功 + if (this.isSuccess(jiliKickMemberDTO.getErrorCode())) { + return Boolean.TRUE; + } else { + throw new BaseException(MeiTianLogoutDTO.get(jiliKickMemberDTO.getErrorCode()).getMessage()); + + } + } + + /** + * 踢成员全部 + * + * @param kickMemberAllDTO 踢成员全部dto + * @return {@link Boolean } + */ + @Override + public Boolean kickMemberAll(KickMemberAllDTO kickMemberAllDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 免费游戏玩家使用的纪录 + * + * @param getFreeSpinDashflowRequestDTO 获取自由旋转dashflow请求dto + * @return {@link List }<{@link GameFreeRecord }> + */ + @Override + public List getFreeSpinDashflow(GetFreeSpinDashflowRequestDTO getFreeSpinDashflowRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 取消赠送免费局数 + * + * @param cancelFreeSpinRequestDTO 取消免费旋转请求 + * @return {@link Boolean } + */ + @Override + public Boolean cancelFreeSpin(CancelFreeSpinRequestDTO cancelFreeSpinRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + + /** + * 批量插入 + * + * @param betRecordJILIResponse 投注记录jiliresponse + * @return {@link Integer } + */ + private void batchInsert(JILIBetRecordResponseDTO betRecordJILIResponse) { + List gameBettingDetails = new ArrayList<>(); + List wagersIds = new ArrayList<>(); + //数据组装 + JILIBetRecordResponseDTO.DataBean dataBean = betRecordJILIResponse.getData(); + //数据转化 + for (JILIBetRecordDataResponseDTO jiliBetRecordDataResponseDTO : dataBean.getResult()) { + GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder().data(jiliBetRecordDataResponseDTO).build()); + if (!ObjectUtils.isEmpty(bettingDetails)) { + bettingDetails.setId(IdUtil.getSnowflakeNextId()); + gameBettingDetails.add(bettingDetails); + } + wagersIds.add(jiliBetRecordDataResponseDTO.getWagersId()); + } + if (!CollectionUtils.isEmpty(gameBettingDetails)) { + //查询重复数据id + List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds); + //用steam流清除list中与wagersIds集合相同的数据 + gameBettingDetails = gameBettingDetails.stream() + .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) + .collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(gameBettingDetails)) { + gameBettingDetailsService.batchInsert(gameBettingDetails); + } + } + + } + + /** + * 数据构建 + * + * @param gamesDataBuildDTO 数据 + * @return {@link GameBettingDetails } + */ + @Override + public GameBettingDetails dataBuild(GamesDataBuildDTO gamesDataBuildDTO) { + + //转化类 + JILIBetRecordDataResponseDTO jiliBetRecordDataResponseDTO = (JILIBetRecordDataResponseDTO) gamesDataBuildDTO.getData(); + GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() + .code(jiliBetRecordDataResponseDTO.getAgentId()) + .platformCode(GamePlatforms.MeiTIan.getInfo()).build()); + + + Member member = memberService.selectMemberByGameAccount(jiliBetRecordDataResponseDTO.getAccount()); + if (ObjectUtils.isEmpty(member)) { + return null; + } + List gamesDatas = redisCache.getCacheList(CacheConstants.JILI_GAMES); + Map dataDTOMap = gamesDatas.stream().collect(Collectors.toMap(MeiTianGameDataDTO::getGameId, e -> e)); + MeiTianGameDataDTO gamesDataDTO = dataDTOMap.get(jiliBetRecordDataResponseDTO.getGameId()); + BigDecimal payoffAmount = BigDecimal.ZERO; + if (GameStatus.WIN.getCode().equals(jiliBetRecordDataResponseDTO.getStatus())) { + payoffAmount = NumberUtil.sub(jiliBetRecordDataResponseDTO.getPayoffAmount(), jiliBetRecordDataResponseDTO.getTurnover()); + } else if (GameStatus.FAIL.getCode().equals(jiliBetRecordDataResponseDTO.getStatus())) { + payoffAmount = NumberUtil.sub(jiliBetRecordDataResponseDTO.getPayoffAmount(), jiliBetRecordDataResponseDTO.getTurnover()).negate(); + } + + //数据构造 + GameBettingDetails gameBettingDetails = GameBettingDetails.builder() + .tenantKey(member.getTenantKey()) + //保存我们的币种id + .currencyCode(gameSecretKey.getSystemCurrency()) + .memberId(member.getId()) + .gameCode(jiliBetRecordDataResponseDTO.getGameId()) + .gameType(JILIGameType.findSystemByCode(jiliBetRecordDataResponseDTO.getGameCategoryId())) + .platformCode(GamePlatforms.MeiTIan.getCode()) + .gameId(gamesDataDTO.getSystemGameId()) + .gameName(gamesDataDTO.getCnName()) + .gameStatus(jiliBetRecordDataResponseDTO.getStatus()) + .gameStatusType(jiliBetRecordDataResponseDTO.getType()) + .gameCurrencyCode(jiliBetRecordDataResponseDTO.getAgentId()) + .account(String.valueOf(jiliBetRecordDataResponseDTO.getAccount())) + .wagersId(jiliBetRecordDataResponseDTO.getWagersId()) + .wagersTime(jiliBetRecordDataResponseDTO.getWagersTime()) + .betAmount(jiliBetRecordDataResponseDTO.getBetAmount().abs()) + .payoffTime(jiliBetRecordDataResponseDTO.getPayoffTime()) + .payoffAmount(payoffAmount) + .settlementTime(jiliBetRecordDataResponseDTO.getSettlementTime()) + .turnover(jiliBetRecordDataResponseDTO.getTurnover()) + .orderNo(String.valueOf(jiliBetRecordDataResponseDTO.getRoundIndex())) + .settlementStatus(SettlementStatusEnum.COMPLETED.getCode()) + .build(); + gameBettingDetails.setCreateBy(Constants.SYSTEM); + gameBettingDetails.setCreateTime(DateUtils.getNowDate()); + return gameBettingDetails; + } +}