From 3853150e9d21d69597c11d26feaf1984faba905f Mon Sep 17 00:00:00 2001 From: shi Date: Mon, 24 Mar 2025 20:05:22 +0800 Subject: [PATCH 1/4] =?UTF-8?q?feat(game):=20=E6=B7=BB=E5=8A=A0=20FC=20?= =?UTF-8?q?=E6=B8=B8=E6=88=8F=E5=B9=B3=E5=8F=B0=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 FCClient 接口和 GamesFCServiceImpl 实现类 - 添加与 FC游戏平台交互所需的 DTO 类- 实现了创建成员、获取会员信息、登录、游戏列表获取等功能 - 集成了兑换转账和状态查询功能 -支持按时间获取和处理投注记录 --- .../java/com/ff/base/constant/Constants.java | 5 + .../api/fc/address/MyFCAddressSource.java | 24 + .../com/ff/game/api/fc/client/FCClient.java | 114 +++ .../com/ff/game/api/fc/dto/ApiFCResult.java | 19 + .../com/ff/game/api/fc/dto/ApiKeyRequest.java | 68 ++ .../game/api/fc/impl/GamesFCServiceImpl.java | 864 ++++++++++++++++++ 6 files changed, 1094 insertions(+) create mode 100644 ff-game/src/main/java/com/ff/game/api/fc/address/MyFCAddressSource.java create mode 100644 ff-game/src/main/java/com/ff/game/api/fc/client/FCClient.java create mode 100644 ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCResult.java create mode 100644 ff-game/src/main/java/com/ff/game/api/fc/dto/ApiKeyRequest.java create mode 100644 ff-game/src/main/java/com/ff/game/api/fc/impl/GamesFCServiceImpl.java 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 a41b811..1a3a390 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 @@ -188,6 +188,11 @@ public class Constants { */ public static final String NG_API_BASE_URL = "ng.api.base.url"; + /** + * fc-api基本url + */ + public static final String FC_API_BASE_URL = "fc.api.base.url"; + /** * 吉利测试地址 */ diff --git a/ff-game/src/main/java/com/ff/game/api/fc/address/MyFCAddressSource.java b/ff-game/src/main/java/com/ff/game/api/fc/address/MyFCAddressSource.java new file mode 100644 index 0000000..cc1fe63 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fc/address/MyFCAddressSource.java @@ -0,0 +1,24 @@ +package com.ff.game.api.fc.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; + +@Component +public class MyFCAddressSource implements AddressSource { + + @Resource + private ISysConfigService configService; + + + @Override + public ForestAddress getAddress(ForestRequest request) { + String apiBaseUrl = configService.selectConfigByKey(Constants.NG_API_BASE_URL); + return new ForestAddress("https",apiBaseUrl, 443,""); + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/fc/client/FCClient.java b/ff-game/src/main/java/com/ff/game/api/fc/client/FCClient.java new file mode 100644 index 0000000..d74c4a0 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fc/client/FCClient.java @@ -0,0 +1,114 @@ +package com.ff.game.api.fc.client; + + +import com.dtflys.forest.annotation.Address; +import com.dtflys.forest.annotation.Header; +import com.dtflys.forest.annotation.JSONBody; +import com.dtflys.forest.annotation.Post; +import com.ff.game.api.fc.dto.ApiFCResult; +import com.ff.game.api.fc.address.MyFCAddressSource; +import com.ff.game.api.fc.dto.ApiKeyRequest; +import com.ff.game.api.ng.dto.*; + +import java.util.List; +import java.util.Map; + +/** + * ng客户端 + * + * @author shi + * @date 2025/03/11 + */ +@Address(source = MyFCAddressSource.class) +public interface FCClient { + + @Post("/Key") + ApiKeyRequest key(@JSONBody Map parameters); + + + /** + * 创建成员 + * + * @param parameters 参数 + * @return {@link String } + */ + @Post("/AddMember") + ApiFCResult createMember(@JSONBody Map parameters); + + /** + * 获取会员信息 + * + * @param parameters 范围 + * @param headerMap 标题映射 + * @return {@link ApiNGResponseDTO }<{@link String }> + */ + @Post("/server/balance") + ApiNGResponseDTO getMemberInfo(@JSONBody Map parameters, @Header Map headerMap); + + + /** + * 获取游戏列表 + * + * @param parameters 范围 + * @param headerMap 标题映射 + * @return {@link ApiNGResponseDTO }<{@link List }> + */ + @Post("/server/gameCode") + ApiNGResponseDTO> getGameList(@JSONBody Map parameters, @Header Map headerMap); + + + /** + * 无重定向登录 + * + * @param parameters 范围 + * @param headerMap 标题映射 + * @return {@link ApiNGResponseDTO }<{@link ApiLoginResponseDTO }> + */ + @Post("/server/gameUrl") + ApiNGResponseDTO loginWithoutRedirect(@JSONBody Map parameters, @Header Map headerMap); + + + /** + * 按代理id进行交换转账 + * + * @param parameters 范围 + * @param headerMap 标题映射 + * @return {@link ApiNGResponseDTO }<{@link ApiLoginResponseDTO }> + */ + @Post(url = "/server/transfer",connectTimeout = 70000) + ApiNGResponseDTO exchangeTransferByAgentId(@JSONBody Map parameters, @Header Map headerMap); + + + /** + * 汇兑转移状态 + * + * @param parameters 范围 + * @param headerMap 标题映射 + * @return {@link ApiNGResponseDTO }<{@link ApiExchangeTransferStatusResponseDTO }> + */ + @Post(url = "/server/transferStatus") + ApiNGResponseDTO exchangeTransferStatus(@JSONBody Map parameters, @Header Map headerMap); + + + /** + * 按时间获取投注记录 + * + * @param parameters 范围 + * @param headerMap 标题映射 + * @return {@link ApiNGResponseDTO }<{@link ApiGameBetRecordPageResponseDTO }> + */ + @Post(url = "server/recordAll") + ApiNGResponseDTO getBetRecordByTime(@JSONBody Map parameters, @Header Map headerMap); + + /** + * 按历史时间获取投注记录 + * + * @param parameters 范围 + * @param headerMap 标题映射 + * @return {@link ApiNGResponseDTO }<{@link ApiGameBetRecordPageResponseDTO }> + */ + @Post(url = "server/recordHistory") + ApiNGResponseDTO getBetRecordByHistoryTime(@JSONBody Map parameters, @Header Map headerMap); + + +} diff --git a/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCResult.java b/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCResult.java new file mode 100644 index 0000000..646206b --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCResult.java @@ -0,0 +1,19 @@ +package com.ff.game.api.fc.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 红蜜蜂 + * + * @author shi + * @date 2025/03/24 + */ +@Data +public class ApiFCResult { + /** + * 操作结果,0 表示成功,其他值表示失败 + */ + @JsonProperty("Result") + private int result; +} diff --git a/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiKeyRequest.java b/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiKeyRequest.java new file mode 100644 index 0000000..9b96e39 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiKeyRequest.java @@ -0,0 +1,68 @@ +package com.ff.game.api.fc.dto; + +import lombok.Data; +import java.util.List; + +/** + * 通用 API 请求对象 + */ +@Data +public class ApiKeyRequest { + + /** + * 加密参数 + */ + private String params; + + /** + * 请求参数对象,包含多个子字段 + */ + private ReParams reParams; + + /** + * 签名 + */ + private String sign; + + /** + * 内部类,表示嵌套的 ReParams 参数 + */ + @Data + public static class ReParams { + + /** + * 用户账户 + */ + private String memberAccount; + + /** + * 游戏ID + */ + private int gameID; + + /** + * 语言ID + */ + private int languageID; + + /** + * 首页链接 + */ + private String homeUrl; + + /** + * 奖池状态 + */ + private boolean jackpotStatus; + + /** + * 是否登录游戏大厅 + */ + private boolean loginGameHall; + + /** + * 游戏大厅的游戏类型列表 + */ + private List gameHallGameType; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/fc/impl/GamesFCServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/fc/impl/GamesFCServiceImpl.java new file mode 100644 index 0000000..0d12e23 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fc/impl/GamesFCServiceImpl.java @@ -0,0 +1,864 @@ +package com.ff.game.api.fc.impl; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.NumberUtil; +import com.alibaba.druid.support.json.JSONUtils; +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.SleepUtil; +import com.ff.base.utils.StringUtils; +import com.ff.base.utils.sign.Md5Utils; +import com.ff.config.KeyConfig; +import com.ff.game.api.IGamesService; +import com.ff.game.api.fc.dto.ApiFCResult; +import com.ff.game.api.fc.client.FCClient; +import com.ff.game.api.ng.dto.*; +import com.ff.game.api.request.*; +import com.ff.game.domain.*; +import com.ff.game.dto.GameBettingDetailsDTO; +import com.ff.game.dto.GameDTO; +import com.ff.game.dto.GameSecretKeyCurrencyDTO; +import com.ff.game.dto.GameSecretKeyLangDTO; +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.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +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 javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + + +/** + * 游戏数据解析服务 + * + * @author shi + * @date 2024/10/21 + */ +@Service("FCService") +@Slf4j +public class GamesFCServiceImpl 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 IGameFreeRecordService gameFreeRecordService; + + @Resource + private IGameSecretKeyService gameSecretKeyService; + + @Resource + private FCClient FCClient; + + + @Resource + private KeyConfig keyConfig; + + @Resource + private IGameBettingDetailsService gameBettingDetailsService; + + @Resource + private IGameSecretKeyCurrencyService gameSecretKeyCurrencyService; + + @Resource + private IGameNameService gameNameService; + + + @Resource + private IGameSecretKeyLangService gameSecretKeyLangService; + + + @Autowired + @Qualifier("threadPoolTaskExecutor") + private ThreadPoolTaskExecutor threadPoolTaskExecutor; + + /** + * 获得就是成功 + * + * @param errorCode 错误代码 + * @return {@link Boolean } + */ + private Boolean getIsSuccess(Integer errorCode) { + ApiException.isTrue(10009 != errorCode, ErrorCode.FREQUENT_INTERFACE_REQUESTS.getCode()); + + return 10000 == errorCode; + } + + + /** + * 获取密钥 + * + * @param paramsMap 参数图 + * @param agentKey 代理密钥 + * @return {@link String } + */ + private static String getKey(Map paramsMap, String agentKey) { + try { + Base64.Encoder encoder = Base64.getEncoder(); + SecretKeySpec keySpec = new SecretKeySpec(agentKey.getBytes(StandardCharsets.UTF_8), "AES"); + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, keySpec); + return encoder.encodeToString(cipher.doFinal(JSONUtils.toJSONString(paramsMap).getBytes(StandardCharsets.UTF_8))); + } catch (Exception e) { + throw new BaseException("加密失败"); + } + + } + + public static void main(String[] args) { + Map paramsMap =new HashMap<>(); + paramsMap.put("MemberAccount","5hajptaA"); + System.out.printf(getKey(paramsMap,"pySJ3DRpW2Zj2A9C")); + } + + /** + * 获取密钥映射 + * + * @param paramsMap 参数图 + * @param agentKey 代理密钥 + * @param currency 货币 + * @return {@link Map }<{@link String },{@link Object }> + */ + private Map getKeyMap(Map paramsMap,String agentKey,String currency){ + Map keyMap = new HashMap<>(); + String key = getKey(paramsMap, agentKey); + keyMap.put("Sign", Md5Utils.md5New(JSONUtils.toJSONString(paramsMap))); + keyMap.put("AgentCode", "FCXTU3042"); + keyMap.put("Currency", currency); + keyMap.put("Params",key); + return keyMap; + + } + + /** + * 解密密钥 + * + * @param gamesBaseRequestDTO 游戏基础请求dto + * @return {@link String } + */ + private String decryptKey(GamesBaseRequestDTO gamesBaseRequestDTO) { + try { + String val="SBF6G5gFvW5n4aFSFCar9Im0CHgBMyU7OxFTuuB6InmRkm6Qt4K2pfktU="; + Base64.Decoder decoder = Base64.getDecoder(); + SecretKeySpec keySpec = new SecretKeySpec("gamesBaseRequestDTO.getAgentKey()".getBytes(), "AES"); + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, keySpec); + return new String(cipher.doFinal(decoder.decode(val))); + } catch (Exception e) { + throw new BaseException("解密失败"); + } + + } + + /** + * 创建成员 + * + * @param createMemberRequestDTO 创建成员请求dto + * @return {@link Boolean } + */ + @Override + public Boolean createMember(CreateMemberRequestDTO createMemberRequestDTO) { + log.info("GamesNGServiceImpl [createMember] 请求参数 {}", createMemberRequestDTO); + Map paramsMap = new HashMap<>(); + paramsMap.put("MemberAccount", createMemberRequestDTO.getAccount()); + paramsMap.putAll(getKeyMap(paramsMap, createMemberRequestDTO.getAgentKey(), createMemberRequestDTO.getCurrency())); + ApiFCResult apiFCResult = FCClient.createMember(paramsMap); + int errorCode = apiFCResult.getResult(); + if (10000 == errorCode) { + return Boolean.TRUE; + } + if (10002 == 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) { + log.info("GamesNGServiceImpl [getMemberInfo] 请求参数 {}", memberInfoRequestDTO); + Map paramsMap = new HashMap<>(); + paramsMap.put("playerId", memberInfoRequestDTO.getAccounts()); + paramsMap.put("platType", NGPlatforms.PG.getCode()); + paramsMap.put("currency", memberInfoRequestDTO.getCurrency()); + //这个接口请求稍微重复一次就报错 + SleepUtil.sleep(500); + ApiNGResponseDTO apiNGResponseDTO = FCClient.getMemberInfo(paramsMap, null); + int errorCode = apiNGResponseDTO.getCode(); + if (this.getIsSuccess(errorCode)) { + return MemberInfoResponseDTO.builder().account(memberInfoRequestDTO.getAccounts()).balance(apiNGResponseDTO.getData().getBalance()).status(GameMemberStatus.UNKNOWN.getCode()).build(); + } else { + throw new BaseException(apiNGResponseDTO.getMsg()); + } + } + + /** + * 无重定向登录 + * + * @param gamesLogin 游戏登录 + * @return {@link String } + */ + @Override + public String loginWithoutRedirect(GamesLogin gamesLogin) { + log.info("GamesNGServiceImpl [loginWithoutRedirect] 请求参数 {}", gamesLogin); + Map paramsMap = new HashMap<>(); + paramsMap.put("playerId", gamesLogin.getAccount()); + paramsMap.put("platType", NGPlatforms.PG.getCode()); + paramsMap.put("currency", gamesLogin.getCurrency()); + paramsMap.put("gameType", gamesLogin.getGameType()); + paramsMap.put("lang", gamesLogin.getLang()); + paramsMap.put("gameCode", gamesLogin.getGameId()); + paramsMap.put("returnUrl", gamesLogin.getHomeUrl()); + paramsMap.put("ingress", PlatformHomeType.WEB.getValue().equals(gamesLogin.getPlatform()) ? IngressType.PC_WEB.getValue() : IngressType.MOBILE_WEB.getValue()); + Map headerMap =new HashMap<>(); + ApiNGResponseDTO apiLoginResponseDTOApiNGResponseDTO = FCClient.loginWithoutRedirect(paramsMap, headerMap); + if (this.getIsSuccess(apiLoginResponseDTOApiNGResponseDTO.getCode())) { + return apiLoginResponseDTOApiNGResponseDTO.getData().getUrl(); + } else { + throw new BaseException(apiLoginResponseDTOApiNGResponseDTO.getMsg()); + } + } + + + /** + * 获取游戏列表 + * + * @param gamesBaseRequestDTO 游戏请求dto + * @return {@link String } + */ + @Transactional + @Override + public String getGameList(GamesBaseRequestDTO gamesBaseRequestDTO) { + List apiGameInfoResponseDTOS = redisCache.getCacheList(CacheConstants.PG_GAMES); + if (!CollectionUtils.isEmpty(apiGameInfoResponseDTOS)) { + return CacheConstants.PG_GAMES; + } + + + log.info("GamesNGServiceImpl [getGameList] 请求参数 {}", gamesBaseRequestDTO); + Map paramsMap = new HashMap<>(); + paramsMap.put("platType", NGPlatforms.PG.getCode()); + Map headerMap =new HashMap<>(); + ApiNGResponseDTO> gameList = FCClient.getGameList(paramsMap, headerMap); + if (this.getIsSuccess(gameList.getCode())) { + for (ApiGameInfoResponseDTO apiGameInfoResponseDTO : gameList.getData()) { + GamePlatform gamePlatform = GamePlatform.builder() + .platformType(NGGameType.findSystemByCode(apiGameInfoResponseDTO.getGameType())) + .platformCode(GamePlatforms.PG.getCode()) + .build(); + List gamePlatforms = gamePlatformService.selectGamePlatformList(gamePlatform); + //没有此平台就新增一个平台 + if (CollectionUtils.isEmpty(gamePlatforms)) { + gamePlatform.setPlatformName(GamePlatforms.PG.getInfo() + NGGameType.findInfoByCode(apiGameInfoResponseDTO.getGameType())); + 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(apiGameInfoResponseDTO.getGameCode()) + .build(); + List games = gameService.selectGameList(game); + //不存在这个游戏 + if (CollectionUtils.isEmpty(games)) { + game.setGameSourceType(apiGameInfoResponseDTO.getGameType()); + game.setFreespin(Boolean.FALSE); + game.setDemoStatus(Boolean.TRUE); + game.setSortNo(gameService.selectMaxSortNoByPlatformId(gamePlatform.getId()) + 1); + game.setGameName(apiGameInfoResponseDTO.getGameName().get("zh-hans")); + game.setCreateBy(Constants.SYSTEM); + gameService.insertGame(game); + } else { + game = games.get(0); + } + apiGameInfoResponseDTO.setSystemGameId(game.getId()); + Map gameName = apiGameInfoResponseDTO.getGameName(); + for (String key : gameName.keySet()) { + String name = gameName.get(key); + List gameNames = gameNameService.selectGameNameList(GameName.builder().gameId(game.getId()).gameName(name).build()); + if (CollectionUtils.isEmpty(gameNames)) { + if ("zh-hans".equals(key)) { + gameNameService.insertGameName(GameName.builder() + .gameId(game.getId()) + .gameName(name) + .langCode("zh-CN") + .createBy(Constants.SYSTEM) + .build()); + } else if (!"zh-hant".equals(key)) { + GameSecretKeyLangDTO gameSecretKeyLangDTO = gameSecretKeyLangService.findGameSecretKeyLangDTO(GameSecretKeyLangDTO.builder() + .platformCode(GamePlatforms.PG.getCode()) + .lang(key) + .build()); + gameNameService.insertGameName(GameName.builder() + .gameId(game.getId()) + .gameName(name) + .langCode(gameSecretKeyLangDTO.getSystemLangCode()) + .createBy(Constants.SYSTEM) + .build()); + } + } + } + + + } + + redisCache.deleteObject(CacheConstants.PG_GAMES); + redisCache.setCacheList(CacheConstants.PG_GAMES, gameList.getData()); + redisCache.expire(CacheConstants.PG_GAMES, 5L, TimeUnit.HOURS); + } else { + throw new BaseException(gameList.getMsg()); + } + return CacheConstants.PG_GAMES; + } + + /** + * 按代理id进行交换转账 + * + * @param exchangeTransferMoneyRequestDTO 外汇转账moeny dto + * @return {@link Long } + */ + @Override + @Transactional + public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO) { + log.info("GamesNGServiceImpl [exchangeTransferByAgentId] 请求参数 {}", exchangeTransferMoneyRequestDTO); + + GameSecretKeyCurrency currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() + .platformCode(GamePlatforms.PG.getCode()) + .code(exchangeTransferMoneyRequestDTO.getAgentId()) + .currency(exchangeTransferMoneyRequestDTO.getCurrency()) + .build()); + + Member member = memberService.selectMemberByGameAccount(exchangeTransferMoneyRequestDTO.getAccount()); + String transactionId = gameExchangeMoneyService.getTransactionId(GamePlatforms.PG.getCode(), 32); + List gameExchangeMonies = gameExchangeMoneyService.selectGameExchangeMoneyList( + GameExchangeMoney.builder() + .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) + .orderId(exchangeTransferMoneyRequestDTO.getOrderId()) + .build() + ); + Assert.isTrue(CollectionUtils.isEmpty(gameExchangeMonies), "订单号重复"); + + //获取下一个自增id + GameExchangeMoney exchangeMoney = GameExchangeMoney + .builder() + .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) + .orderId(exchangeTransferMoneyRequestDTO.getOrderId()) + .quota(exchangeTransferMoneyRequestDTO.getQuota()) + .balance(exchangeTransferMoneyRequestDTO.getAmount()) + .exchangeType(exchangeTransferMoneyRequestDTO.getTransferType()) + .currencyCode(currencyDTO.getSystemCurrency()) + .memberId(member.getId()) + .transactionId(transactionId) + .platformCode(GamePlatforms.PG.getCode()) + .build(); + exchangeMoney.setCreateBy(Constants.SYSTEM); + + //获取余额 + String type = TransferType.ALL.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType()) ? NGTransferType.TRANSFER_OUT.getValue() : NGTransferType.TRANSFER_IN.getValue(); + //获取当前游戏币 + MemberInfoRequestDTO gamesBaseRequestDTO = MemberInfoRequestDTO.builder() + .accounts(member.getGameAccount()) + .agentId(exchangeTransferMoneyRequestDTO.getAgentId()) + .agentKey(exchangeTransferMoneyRequestDTO.getAgentKey()) + .currency(currencyDTO.getCurrency()) + .build(); + MemberInfoResponseDTO memberInfo = this.getMemberInfo(gamesBaseRequestDTO); + //判断是不是转出 + if (NGTransferType.TRANSFER_OUT.getValue().equals(type)) { + exchangeTransferMoneyRequestDTO.setAmount(memberInfo.getBalance()); + } + + + Map paramsMap = new HashMap<>(); + paramsMap.put("platType", NGPlatforms.PG.getCode()); + paramsMap.put("playerId", exchangeTransferMoneyRequestDTO.getAccount()); + paramsMap.put("currency", currencyDTO.getCurrency()); + paramsMap.put("type", type); + paramsMap.put("amount", exchangeTransferMoneyRequestDTO.getAmount()); + paramsMap.put("orderId", transactionId); + + + Map key =new HashMap<>(); + ApiNGResponseDTO apiNGResponseDTO = FCClient.exchangeTransferByAgentId(paramsMap, key); + if (this.getIsSuccess(apiNGResponseDTO.getCode())) { + //更新数据 + exchangeMoney.setBalance(exchangeTransferMoneyRequestDTO.getAmount()); + exchangeMoney.setStatus(StatusType.IN_PROGRESS.getValue()); + gameExchangeMoneyService.insertGameExchangeMoney(exchangeMoney); + ExchangeTransferStatusRequestDTO exchangeTransferStatusRequestDTO = new ExchangeTransferStatusRequestDTO(); + exchangeTransferStatusRequestDTO.setAccount(exchangeTransferMoneyRequestDTO.getAccount()); + exchangeTransferStatusRequestDTO.setCurrency(currencyDTO.getCurrency()); + exchangeTransferStatusRequestDTO.setOrderId(transactionId); + exchangeTransferStatusRequestDTO.setAgentId(exchangeTransferMoneyRequestDTO.getAgentId()); + exchangeTransferStatusRequestDTO.setAgentKey(exchangeTransferMoneyRequestDTO.getAgentKey()); + this.exchangeTransferStatus(exchangeTransferStatusRequestDTO); + } else { + log.error("GamesPGServiceImpl [exchangeTransferByAgentId] 金额转移失败,错误代码{},错误信息{}", apiNGResponseDTO.getCode(), apiNGResponseDTO.getMsg()); + throw new BaseException(apiNGResponseDTO.getMsg()); + } + return exchangeMoney.getId(); + } + + /** + * 汇兑转移状态 + * + * @param exchangeTransferMoneyRequestDTO 兑换转账请求dto + * @return {@link Boolean } + */ + @Override + public Boolean exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { + + + Map paramsMap = new HashMap<>(); + paramsMap.put("playerId", exchangeTransferMoneyRequestDTO.getAccount()); + paramsMap.put("currency", exchangeTransferMoneyRequestDTO.getCurrency()); + paramsMap.put("orderId", exchangeTransferMoneyRequestDTO.getOrderId()); + Map key =new HashMap<>(); + ApiNGResponseDTO apiNGResponseDTO = FCClient.exchangeTransferStatus(paramsMap, key); + if (this.getIsSuccess(apiNGResponseDTO.getCode())) { + ApiExchangeTransferStatusResponseDTO apiNGResponseDTOData = apiNGResponseDTO.getData(); + List gameExchangeMonies = gameExchangeMoneyService.selectGameExchangeMoneyList( + GameExchangeMoney.builder() + .platformCode(GamePlatforms.PG.getCode()) + .transactionId(exchangeTransferMoneyRequestDTO.getOrderId()) + .build() + ); + + for (GameExchangeMoney exchangeMoney : gameExchangeMonies) { + //更新数据 + exchangeMoney.setBalance(apiNGResponseDTOData.getAmount().abs()); + exchangeMoney.setCoinBefore(NumberUtil.sub(apiNGResponseDTOData.getAfterBalance(), apiNGResponseDTOData.getAmount())); + exchangeMoney.setCoinAfter(apiNGResponseDTOData.getAfterBalance()); + exchangeMoney.setCurrencyBefore(exchangeMoney.getCoinBefore()); + exchangeMoney.setCurrencyAfter(exchangeMoney.getCoinAfter()); + exchangeMoney.setStatus(apiNGResponseDTOData.getStatus()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + } + return Boolean.TRUE; + } else { + log.error("GamesPGServiceImpl [exchangeTransferStatus]错误代码{},错误信息{}", apiNGResponseDTO.getCode(), apiNGResponseDTO.getMsg()); + return Boolean.FALSE; + } + + + } + + + /** + * 按时间获取投注记录 + * + * @param betRecordByTimeDTO 按时间dto投注记录 + * @return {@link Boolean } + */ + @Override + public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) { + + GameSecretKeyCurrencyDTO gameSecretKeyDTO = new GameSecretKeyCurrencyDTO(); + gameSecretKeyDTO.setPlatformCodes(NGPlatforms.getAllPlatforms()); + List currencyDTOList = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTOList(gameSecretKeyDTO); + List currencys = currencyDTOList.stream() + .map(GameSecretKeyCurrencyDTO::getCurrency) + .distinct() + .collect(Collectors.toList()); + + + Set cacheSet = redisCache.getCacheSet(CacheConstants.PG_GAMES_BET_CURRENCY); + if (CollectionUtils.isEmpty(cacheSet)) { + cacheSet = new HashSet<>(); + } + //如果长度一致则清空缓存循环币种 + if (cacheSet.size() >= currencys.size()) { + cacheSet = new HashSet<>(); + redisCache.deleteObject(CacheConstants.PG_GAMES_BET_CURRENCY); + } + //去掉重复的 + currencys.removeAll(cacheSet); + + String firstCurrency = currencys.get(0); + + GameSecretKeyCurrencyDTO currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() + .platformCode(GamePlatforms.PG.getCode()) + .currency(firstCurrency) + .build()); + + + betRecordByTimeDTO.setAgentId(currencyDTO.getCode()); + betRecordByTimeDTO.setAgentKey(currencyDTO.getKey()); + int pageNo = 1; + int pageSize = 2000; + Map paramsMap = new HashMap<>(); + paramsMap.put("currency", currencyDTO.getCurrency()); + paramsMap.put("pageNo", pageNo); + paramsMap.put("pageSize", pageSize); + Map key = new HashMap<>(); + + + ApiNGResponseDTO betRecordByTime = FCClient.getBetRecordByTime(paramsMap, key); + + if (this.getIsSuccess(betRecordByTime.getCode())) { + cacheSet.add(firstCurrency); + redisCache.setCacheSet(CacheConstants.PG_GAMES_BET_CURRENCY, cacheSet); + + ApiNGResponseDTO result = betRecordByTime; + AtomicInteger pageNoAtomic = new AtomicInteger(pageNo); + + + ApiGameBetRecordPageResponseDTO data = result.getData(); + //数据组装 + this.batchInsert(data); + + //总页数 + // 计算总页数,确保不会遗漏 + int totalPage = (int) Math.ceil((double) data.getTotal() / pageSize); + + // 获取下一页数据 + while (pageNoAtomic.get() < totalPage && data.getTotal() > 0) { + pageNoAtomic.incrementAndGet(); + //请求参数 + Map paramMap = new HashMap<>(); + paramMap.put("currency", currencyDTO.getCurrency()); + paramMap.put("pageNo", pageNoAtomic.get()); + paramMap.put("pageSize", pageSize); + SleepUtil.sleep(10000); + ApiNGResponseDTO betRecordByTimePage = FCClient.getBetRecordByTime(paramMap, key); + data = betRecordByTimePage.getData(); + //数据组装 + this.batchInsert(data); + } + + + } + getBetRecordByHistoryTime(betRecordByTimeDTO, currencyDTO); + return Boolean.TRUE; + } + + /** + * 按历史时间获取投注记录 + * + * @param betRecordByTimeDTO 按时间dto投注记录 + * @param currencyDTO 货币dto + */ + private void getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO, GameSecretKeyCurrencyDTO currencyDTO) { + + //捞取指定30分钟前的数据 + Long startTimes = DateUtils.addOrSubtractMinutes(DateUtils.getNowDate(), -30); + Long endTimes = DateUtils.getNowDate(); + betRecordByTimeDTO.setStartTime(startTimes); + betRecordByTimeDTO.setEndTime(endTimes); + + + int currentMinute = java.time.LocalTime.now().getMinute(); + // 判断当前分钟是否是 20 分、40 分或 0 分,如果不是,跳过当前执行 + if (currentMinute != 20 && currentMinute != 40 && currentMinute != 0) { + // 当前时间不是 20 分、40 分、0 分,跳过执行 + return; + } + + + String startTime = DateTimeFormatter + .ofPattern("yyyy-MM-dd HH:mm:ss") + .withZone(ZoneId.of("Asia/Shanghai")) + .format(Instant.ofEpochMilli(betRecordByTimeDTO.getStartTime())); + + String endTime = DateTimeFormatter + .ofPattern("yyyy-MM-dd HH:mm:ss") + .withZone(ZoneId.of("Asia/Shanghai")) + .format(Instant.ofEpochMilli(betRecordByTimeDTO.getEndTime())); + + + betRecordByTimeDTO.setAgentId(currencyDTO.getCode()); + betRecordByTimeDTO.setAgentKey(currencyDTO.getKey()); + int pageNo = 1; + int pageSize = 2000; + Map paramsMap = new HashMap<>(); + paramsMap.put("currency", currencyDTO.getCurrency()); + paramsMap.put("pageNo", pageNo); + paramsMap.put("pageSize", pageSize); + paramsMap.put("startTime", startTime); + paramsMap.put("endTime", endTime); + Map key =new HashMap<>(); + + + ApiNGResponseDTO betRecordByTime = FCClient.getBetRecordByHistoryTime(paramsMap, key); + + if (this.getIsSuccess(betRecordByTime.getCode())) { + ApiNGResponseDTO result = betRecordByTime; + AtomicInteger pageNoAtomic = new AtomicInteger(pageNo); + + threadPoolTaskExecutor.execute(() -> { + + ApiGameBetRecordPageResponseDTO data = result.getData(); + //数据组装 + this.batchInsert(data); + + //总页数 + // 计算总页数,确保不会遗漏 + int totalPage = (int) Math.ceil((double) data.getTotal() / pageSize); + + // 获取下一页数据 + while (pageNoAtomic.get() < totalPage && data.getTotal() > 0) { + pageNoAtomic.incrementAndGet(); + //请求参数 + Map paramMap = new HashMap<>(); + paramMap.put("currency", currencyDTO.getCurrency()); + paramMap.put("pageNo", pageNoAtomic.get()); + paramMap.put("pageSize", pageSize); + paramMap.put("startTime", startTime); + paramMap.put("endTime", endTime); + SleepUtil.sleep(10000); + ApiNGResponseDTO betRecordByTimePage = FCClient.getBetRecordByTime(paramMap, key); + data = betRecordByTimePage.getData(); + //数据组装 + this.batchInsert(data); + } + }); + + + } + } + + + /** + * 赠送免费局数 + * + * @param createFreeSpinRequest 创建自由旋转请求 + * @return {@link Boolean } + */ + @Override + public Boolean createFreeSpin(CreateFreeSpinRequestDTO createFreeSpinRequest) { + + + return null; + } + + /** + * 获取游戏详细信息 + * + * @param getGameDetailRequestDTO 获取游戏详细信息请求dto + * @return {@link GetGameDetailResponseDTO } + */ + @Override + public GetGameDetailResponseDTO getGameDetail(GetGameDetailRequestDTO getGameDetailRequestDTO) { + + List gameBettingDetails = gameBettingDetailsService.selectGameBettingDetailsList(GameBettingDetailsDTO.builder().wagersId(getGameDetailRequestDTO.getWagersId()).build()); + if (!CollectionUtils.isEmpty(gameBettingDetails)) { + GetGameDetailResponseDTO getGameDetailResponseDTO = new GetGameDetailResponseDTO(); + getGameDetailResponseDTO.setUrl(gameBettingDetails.get(0).getBetContent()); + return getGameDetailResponseDTO; + } + return null; + } + + /** + * 强制会员从游戏注销 + * + * @param kickMemberRequestDTO 踢会员请求dto + * @return {@link Boolean } + */ + @Override + public Boolean kickMember(KickMemberRequestDTO kickMemberRequestDTO) { + + return null; + } + + /** + * 踢成员全部 + * + * @param kickMemberAllDTO 踢成员全部dto + * @return {@link Boolean } + */ + @Override + public Boolean kickMemberAll(KickMemberAllDTO kickMemberAllDTO) { + + return null; + } + + /** + * 免费游戏玩家使用的纪录 + * + * @param getFreeSpinDashflowRequestDTO 获取自由旋转dashflow请求dto + * @return {@link List }<{@link GameFreeRecord }> + */ + @Override + public List getFreeSpinDashflow(GetFreeSpinDashflowRequestDTO getFreeSpinDashflowRequestDTO) { + + + return Collections.emptyList(); + } + + /** + * 取消赠送免费局数 + * + * @param cancelFreeSpinRequestDTO 取消免费旋转请求 + * @return {@link Boolean } + */ + @Override + public Boolean cancelFreeSpin(CancelFreeSpinRequestDTO cancelFreeSpinRequestDTO) { + + return null; + } + + + /** + * 数据构建 + * + * @param gamesDataBuildDTO 数据 + * @return {@link GameBettingDetails } + */ + @Override + public GameBettingDetails dataBuild(GamesDataBuildDTO gamesDataBuildDTO) { + + //转化类 + ApiGameBetRecordPageResponseDTO.GameBetRecord resultBean = (ApiGameBetRecordPageResponseDTO.GameBetRecord) gamesDataBuildDTO.getData(); + + NGPlatforms ngPlatforms = NGPlatforms.getByCode(resultBean.getPlatType()); + if (ObjectUtils.isEmpty(ngPlatforms)) { + return null; + } + + String platform = ngPlatforms.getPlatform(); + List games = gameService.selectGameDTOList(GameDTO.builder().gameName(resultBean.getGameName()).platformCode(platform).build()); + if (CollectionUtils.isEmpty(games)) { + return null; + } + Game gamesDataDTO = games.get(0); + GameSecretKeyCurrency currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() + .platformCodes(NGPlatforms.getAllPlatforms()) + .currency(resultBean.getCurrency()) + .build()); + + Member member = memberService.selectMemberByGameAccount(resultBean.getPlayerId()); + if (ObjectUtils.isEmpty(member)) { + return null; + } + GameDTO gameDTO = new GameDTO(); + gameDTO.setPlatformCodes(NGPlatforms.getAllPlatforms()); + + int gameStatus = GameStatus.FLAT.getCode(); + if (BigDecimal.ZERO.compareTo(resultBean.getSettledAmount()) > 0) { + gameStatus = GameStatus.FAIL.getCode(); + } else if (BigDecimal.ZERO.compareTo(resultBean.getSettledAmount()) < 0) { + gameStatus = GameStatus.WIN.getCode(); + } + + //数据构造 + GameBettingDetails gameBettingDetails = GameBettingDetails.builder() + .tenantKey(member.getTenantKey()) + //保存我们的币种id + .currencyCode(currencyDTO.getSystemCurrency()) + .memberId(member.getId()) + .gameCode(gamesDataDTO.getGameCode()) + .gameType(NGGameType.findSystemByCode(resultBean.getGameType())) + .platformCode(NGPlatforms.getByCode(resultBean.getPlatType()).getPlatform()) + .gameId(gamesDataDTO.getId()) + .gameName(gamesDataDTO.getGameName()) + .gameStatus(gameStatus) + .gameStatusType(1) + .gameCurrencyCode(resultBean.getCurrency()) + .account(resultBean.getPlayerId()) + .wagersId(resultBean.getGameOrderId()) + .wagersTime(resultBean.getBetTime().getTime()) + .betAmount(resultBean.getBetAmount().abs()) + .payoffTime(resultBean.getLastUpdateTime().getTime()) + .payoffAmount(resultBean.getSettledAmount().abs()) + .settlementTime(resultBean.getLastUpdateTime().getTime()) + .turnover(resultBean.getValidAmount()) + .orderNo(StringUtils.isNotEmpty(resultBean.getRound()) ? String.valueOf(resultBean.getRound()) : null) + .settlementStatus(NGSettlementStatusEnum.fromStatus(resultBean.getStatus()).getCode()) + .round(resultBean.getRound()) + .table(resultBean.getTable()) + .seat(resultBean.getSeat()) + .betContent(resultBean.getBetContent()) + .build(); + gameBettingDetails.setCreateBy(Constants.SYSTEM); + gameBettingDetails.setCreateTime(DateUtils.getNowDate()); + return gameBettingDetails; + + } + + /** + * 批量插入 + * + * @param data 数据 + */ + private synchronized void batchInsert(ApiGameBetRecordPageResponseDTO data) { + List gameBettingDetails = new ArrayList<>(); + List wagersIds = new ArrayList<>(); + //数据转化 + for (ApiGameBetRecordPageResponseDTO.GameBetRecord bean : data.getList()) { + GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder().data(bean).build()); + if (!ObjectUtils.isEmpty(bettingDetails)) { + bettingDetails.setId(IdUtil.getSnowflakeNextId()); + gameBettingDetails.add(bettingDetails); + } + wagersIds.add(bean.getGameOrderId()); + } + 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)) { + List wagersId = gameBettingDetails.stream().map(GameBettingDetails::getWagersId).collect(Collectors.toList()); + gameBettingDetailsService.deleteGameBettingDetailsByWagersId(wagersId); + gameBettingDetailsService.batchInsert(gameBettingDetails); + } + } + + } + +} From 8edbda429ed41cb841bf486c8e8d301051783112 Mon Sep 17 00:00:00 2001 From: shi Date: Tue, 25 Mar 2025 10:33:33 +0800 Subject: [PATCH 2/4] =?UTF-8?q?fix(game):=20=E4=BF=AE=E6=94=B9=20FC=20?= =?UTF-8?q?=E5=9C=B0=E5=9D=80=E6=BA=90=E7=9A=84=E5=8D=8F=E8=AE=AE=E5=92=8C?= =?UTF-8?q?=E7=AB=AF=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将协议从 https 改为 http - 将端口从 443 改为80 - 更新了配置键名,从 NG_API_BASE_URL改为 FC_API_BASE_URL --- .../java/com/ff/game/api/fc/address/MyFCAddressSource.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ff-game/src/main/java/com/ff/game/api/fc/address/MyFCAddressSource.java b/ff-game/src/main/java/com/ff/game/api/fc/address/MyFCAddressSource.java index cc1fe63..24bcefd 100644 --- a/ff-game/src/main/java/com/ff/game/api/fc/address/MyFCAddressSource.java +++ b/ff-game/src/main/java/com/ff/game/api/fc/address/MyFCAddressSource.java @@ -18,7 +18,7 @@ public class MyFCAddressSource implements AddressSource { @Override public ForestAddress getAddress(ForestRequest request) { - String apiBaseUrl = configService.selectConfigByKey(Constants.NG_API_BASE_URL); - return new ForestAddress("https",apiBaseUrl, 443,""); + String apiBaseUrl = configService.selectConfigByKey(Constants.FC_API_BASE_URL); + return new ForestAddress("http",apiBaseUrl, 80,""); } } From c9797d57c5eaba322e425a5fb7adde3a659a1b80 Mon Sep 17 00:00:00 2001 From: shi Date: Tue, 25 Mar 2025 11:07:01 +0800 Subject: [PATCH 3/4] =?UTF-8?q?fix(game):=20=E4=BF=AE=E6=94=B9=E4=BB=A3?= =?UTF-8?q?=E7=90=86=E7=A0=81=E5=B9=B6=E7=A7=BB=E9=99=A4=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将代理码从 "FCXTU3042" 修改为 "TTCS" - 移除了 GamesFCServiceImpl 类中的测试代码 --- .../java/com/ff/game/api/fc/impl/GamesFCServiceImpl.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ff-game/src/main/java/com/ff/game/api/fc/impl/GamesFCServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/fc/impl/GamesFCServiceImpl.java index 0d12e23..d7eea10 100644 --- a/ff-game/src/main/java/com/ff/game/api/fc/impl/GamesFCServiceImpl.java +++ b/ff-game/src/main/java/com/ff/game/api/fc/impl/GamesFCServiceImpl.java @@ -148,11 +148,7 @@ public class GamesFCServiceImpl implements IGamesService { } - public static void main(String[] args) { - Map paramsMap =new HashMap<>(); - paramsMap.put("MemberAccount","5hajptaA"); - System.out.printf(getKey(paramsMap,"pySJ3DRpW2Zj2A9C")); - } + /** * 获取密钥映射 @@ -166,7 +162,7 @@ public class GamesFCServiceImpl implements IGamesService { Map keyMap = new HashMap<>(); String key = getKey(paramsMap, agentKey); keyMap.put("Sign", Md5Utils.md5New(JSONUtils.toJSONString(paramsMap))); - keyMap.put("AgentCode", "FCXTU3042"); + keyMap.put("AgentCode", "TTCS"); keyMap.put("Currency", currency); keyMap.put("Params",key); return keyMap; From c7b001d667a6d3988a695db51e64ad2c2ecdddeb Mon Sep 17 00:00:00 2001 From: shi Date: Tue, 25 Mar 2025 17:04:25 +0800 Subject: [PATCH 4/4] =?UTF-8?q?feat(game):=20=E6=B7=BB=E5=8A=A0=20FC=20?= =?UTF-8?q?=E6=B8=B8=E6=88=8F=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 FC游戏平台支持 - 添加 FC 游戏列表、登录、余额转移等接口 - 实现 FC 投注记录获取功能 - 增加 FC 游戏类型和传输类型枚举 - 优化游戏注单 ID 处理,改为字符串类型 --- .../com/ff/base/constant/CacheConstants.java | 7 + .../java/com/ff/base/enums/ErrorCode.java | 6 +- .../java/com/ff/base/enums/FCGameType.java | 68 +++ .../com/ff/base/enums/FCTransferType.java | 23 + .../java/com/ff/base/enums/GamePlatforms.java | 1 + .../java/com/ff/base/enums/PlatformType.java | 30 + .../java/com/ff/base/enums/TransferType.java | 3 +- .../java/com/ff/base/utils/DateUtils.java | 21 + .../ff/api/controller/ApiGameController.java | 18 +- .../ff/api/request/GameGetDetailRequest.java | 4 +- .../java/com/ff/game/api/IGamesService.java | 8 + .../api/fc/address/MyFCAddressSource.java | 2 +- .../com/ff/game/api/fc/client/FCClient.java | 79 ++- .../dto/ApiCFBalanceTransferResponseDTO.java | 47 ++ .../api/fc/dto/ApiFCBetRecordResponseDTO.java | 166 +++++ .../api/fc/dto/ApiFCGameListResponseDTO.java | 67 ++ .../api/fc/dto/ApiFCLoginResponseDTO.java | 24 + .../api/fc/dto/ApiFCUserInfoResponseDTO.java | 35 ++ .../game/api/fc/impl/GamesFCServiceImpl.java | 575 +++++++----------- .../dto/JILIBetRecordDataResponseDTO.java | 2 +- .../service/impl/GamesJILIServiceImpl.java | 17 +- .../ng/service/impl/GamesPGServiceImpl.java | 20 +- .../game/api/request/GamesDataBuildDTO.java | 9 + .../api/request/GetGameDetailRequestDTO.java | 2 +- .../xk/service/impl/GamesXKServiceImpl.java | 19 +- .../ff/game/domain/GameBettingDetails.java | 3 +- .../java/com/ff/game/domain/GamePlatform.java | 2 +- .../game/mapper/GameBettingDetailsMapper.java | 4 +- .../service/IGameBettingDetailsService.java | 4 +- .../impl/GameBettingDetailsServiceImpl.java | 4 +- .../java/com/ff/quartz/task/GameTask.java | 92 ++- .../mapper/game/GameBettingDetailsMapper.xml | 2 +- 32 files changed, 926 insertions(+), 438 deletions(-) create mode 100644 ff-base/src/main/java/com/ff/base/enums/FCGameType.java create mode 100644 ff-base/src/main/java/com/ff/base/enums/FCTransferType.java create mode 100644 ff-base/src/main/java/com/ff/base/enums/PlatformType.java create mode 100644 ff-game/src/main/java/com/ff/game/api/fc/dto/ApiCFBalanceTransferResponseDTO.java create mode 100644 ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCBetRecordResponseDTO.java create mode 100644 ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCGameListResponseDTO.java create mode 100644 ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCLoginResponseDTO.java create mode 100644 ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCUserInfoResponseDTO.java 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 57d0452..08791ae 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 @@ -57,6 +57,13 @@ public class CacheConstants */ public static final String PG_GAMES= "pg_games:"; + + /** + * fc游戏 + */ + public static final String FC_GAMES= "fc_games:"; + + /** * pg游戏投注货币 */ diff --git a/ff-base/src/main/java/com/ff/base/enums/ErrorCode.java b/ff-base/src/main/java/com/ff/base/enums/ErrorCode.java index 943cbe6..99cb218 100644 --- a/ff-base/src/main/java/com/ff/base/enums/ErrorCode.java +++ b/ff-base/src/main/java/com/ff/base/enums/ErrorCode.java @@ -23,7 +23,11 @@ public enum ErrorCode { FREQUENT_INTERFACE_REQUESTS (1007, "接口请求频繁"), BALANCE_TRANSFER_FAILED (1008, "余额转移失败"), LANG_NOT_EXIST(1009, "游戏平台不支持的语言"), - ORDER_NOT_EXIST(1010, "订单不存在") + ORDER_NOT_EXIST(1010, "订单不存在"), + PLAYERS_ARE_PLAYING(1011, "玩家游玩中"), + INSUFFICIENT_PLAYER_BALANCE(1012, "玩家余额不足"), + KICK_OUT_AILED(1013, "玩家踢出失败"), + ACCOUNT_NOT_ONLINE(1014, "账号不在线"), ; // 获取错误码 diff --git a/ff-base/src/main/java/com/ff/base/enums/FCGameType.java b/ff-base/src/main/java/com/ff/base/enums/FCGameType.java new file mode 100644 index 0000000..0fb07ec --- /dev/null +++ b/ff-base/src/main/java/com/ff/base/enums/FCGameType.java @@ -0,0 +1,68 @@ +package com.ff.base.enums; + + +import lombok.Getter; + +import java.util.HashMap; +import java.util.Optional; +import java.util.stream.Stream; + + +/** + * xkgame类型 + * + * @author shi + * @date 2024/11/13 + */ +@Getter +public enum FCGameType { + + CATCH_FISH("fishing", 4,"捕鱼"), + ARCADE("arcade",1, "电子"), + SLOT("slot",1, "电子"), + TABLE("table", 1,"电子"), + CATCH_FISH_MEMBER("1", 4,"捕鱼"), + ARCADE_MEMBER("2", 1,"电子"), + SLOT_MEMBER("7", 1,"电子"), + TABLE_MEMBER("8", 1,"电子"), + ; + + private final String code; + private final Integer systemCode; + private final String info; + FCGameType(String code, Integer systemCode, String info) + { + this.code = code; + this.systemCode = systemCode; + this.info = info; + } + + + /** + * 按代码查找系统 + * + * @param code 代码 + * @return {@link String } + */ + public static Integer findSystemByCode(String code) { + Optional system = Stream.of(FCGameType.values()) + .filter(gameType -> gameType.getCode().equals(code)) + .map(FCGameType::getSystemCode) + .findFirst(); + return system.orElse(null); + } + + /** + * 按代码查找信息 + * + * @param code 代码 + * @return {@link String } + */ + public static String findInfoByCode(String code) { + Optional system = Stream.of(FCGameType.values()) + .filter(gameType -> gameType.getCode().equals(code)) + .map(FCGameType::getInfo) + .findFirst(); + return system.orElse(null); + } +} diff --git a/ff-base/src/main/java/com/ff/base/enums/FCTransferType.java b/ff-base/src/main/java/com/ff/base/enums/FCTransferType.java new file mode 100644 index 0000000..76efc91 --- /dev/null +++ b/ff-base/src/main/java/com/ff/base/enums/FCTransferType.java @@ -0,0 +1,23 @@ +package com.ff.base.enums; + +import lombok.Getter; + +/** + * 长传输类型 + * + * @author shi + * @date 2025/03/12 + */ +@Getter +public enum FCTransferType { + TRANSFER_OUT("0", "不全部提领(默认值)"), + TRANSFER_OUT_ALL("1", "全部提领(包含所有小数字金额)"); + + private final String value; + private final String description; + + FCTransferType(String value, String description) { + this.value = value; + this.description = description; + } +} 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 6701f6f..2cf8761 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 @@ -7,6 +7,7 @@ public enum GamePlatforms { JILI("JILI", "JILI"), XK("XK", "XK"), PG("PG", "PG"), + FC("FC", "FC"), ; private final String code; diff --git a/ff-base/src/main/java/com/ff/base/enums/PlatformType.java b/ff-base/src/main/java/com/ff/base/enums/PlatformType.java new file mode 100644 index 0000000..272c646 --- /dev/null +++ b/ff-base/src/main/java/com/ff/base/enums/PlatformType.java @@ -0,0 +1,30 @@ +package com.ff.base.enums; + + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 平台类型 + * + * @author shi + * @date 2025/03/25 + */ +@Getter +@AllArgsConstructor +public enum PlatformType { + ELECTRONIC(1, "电子"), + CARD_GAME(2, "棋牌"), + GAME_HALL(3, "游戏大厅"), + FISHING(4, "捕鱼"), + BETTING_MACHINE(5, "押分机 (含宾果)"), + VIDEO(6, "视讯"), + LOTTERY(7, "彩票"), + SPORTS(8, "体育"), + HUNTING(9, "捕猎"); + + private final int code; + private final String name; + + +} diff --git a/ff-base/src/main/java/com/ff/base/enums/TransferType.java b/ff-base/src/main/java/com/ff/base/enums/TransferType.java index ccbd915..6ebbfac 100644 --- a/ff-base/src/main/java/com/ff/base/enums/TransferType.java +++ b/ff-base/src/main/java/com/ff/base/enums/TransferType.java @@ -9,8 +9,7 @@ package com.ff.base.enums; */ public enum TransferType { ALL(1, "从游戏商转移额度到平台商(不看amount值,全部转出"), - GAMES(2, "从平台商转移额度到游戏商"), - SYSTEM(3, "从游戏商转移额度到平台商 无用"); + GAMES(2, "从平台商转移额度到游戏商"); private final Integer code; private final String info; diff --git a/ff-base/src/main/java/com/ff/base/utils/DateUtils.java b/ff-base/src/main/java/com/ff/base/utils/DateUtils.java index 3015c0f..49e7441 100644 --- a/ff-base/src/main/java/com/ff/base/utils/DateUtils.java +++ b/ff-base/src/main/java/com/ff/base/utils/DateUtils.java @@ -202,6 +202,27 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils { return zdt.format(formatter); } + /** + * 将毫秒时间戳转换为指定时区的时间,并按指定格式输出 + * + * @param timestampInMillis 毫秒级时间戳 + * @param timeZone 时区(例如:America/New_York) + * @param format 时间格式(例如:yyyy-MM-dd HH:mm:ss) + * @return 格式化后的时间字符串 + */ + public static String convertTimeZone(long timestampInMillis, String timeZone, String format) { + // 将毫秒时间戳转换为 Instant + Instant instant = Instant.ofEpochMilli(timestampInMillis); + + // 将 UTC 时间转换为指定时区的时间 + ZonedDateTime zonedDateTime = instant.atZone(ZoneId.of(timeZone)); + + // 格式化输出为指定格式的时间字符串 + return zonedDateTime.format(DateTimeFormatter.ofPattern(format)); + } + + + /** * 增加 LocalDate ==> Date */ diff --git a/ff-game/src/main/java/com/ff/api/controller/ApiGameController.java b/ff-game/src/main/java/com/ff/api/controller/ApiGameController.java index dd8fb37..cfaa77b 100644 --- a/ff-game/src/main/java/com/ff/api/controller/ApiGameController.java +++ b/ff-game/src/main/java/com/ff/api/controller/ApiGameController.java @@ -151,7 +151,7 @@ public class ApiGameController extends BaseController { GameSecretKeyCurrencyDTO secretKeyCurrencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() .platformCode(gamePlatform.getPlatformCode()) .systemCurrency(memberCreateApiRequest.getCurrencyCode()).build()); - ApiException.notNull(secretKeyCurrencyDTO, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + ApiException.notNull(secretKeyCurrencyDTO, ErrorCode.CURRENCY_NOT_EXIST.getCode()); GameSecretKeyLangDTO gameSecretKeyLangDTO = gameSecretKeyLangService.findGameSecretKeyLangDTO(GameSecretKeyLangDTO.builder() .platformCode(gamePlatform.getPlatformCode()) @@ -161,7 +161,7 @@ public class ApiGameController extends BaseController { Member member = memberService.selectMemberByAccount(memberCreateApiRequest.getAccount(), memberCreateApiRequest.getCurrencyCode(), gamePlatform.getPlatformCode()); - ApiException.notNull(member, ErrorCode.ACCOUNT_NOT_EXIST.getCode()); + ApiException.notNull(member, ErrorCode.ACCOUNT_NOT_EXIST.getCode()); GamesLogin gamesLogin = GamesLogin.builder() .agentId(secretKeyCurrencyDTO.getCode()) @@ -198,7 +198,7 @@ public class ApiGameController extends BaseController { TenantSecretKey tenantSecretKey = keyConfig.get(); - GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() + GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() .platformCode(gameExchangeBalanceRequest.getPlatformCode()) .systemCurrency(gameExchangeBalanceRequest.getCurrencyCode()).build()); @@ -261,7 +261,6 @@ public class ApiGameController extends BaseController { } - /** * 赠送免费局数 * @@ -352,7 +351,6 @@ public class ApiGameController extends BaseController { public AjaxResult getDetail(@Validated @RequestBody GameGetDetailRequest gameGetDetailRequest) { - GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() .platformCode(gameGetDetailRequest.getPlatformCode()) .systemCurrency(gameGetDetailRequest.getCurrencyCode()).build()); @@ -365,7 +363,6 @@ public class ApiGameController extends BaseController { ApiException.notNull(iGamesService, ErrorCode.PLATFORM_NOT_EXIST.getCode()); - GameSecretKeyLangDTO gameSecretKeyLang = gameSecretKeyLangService.findGameSecretKeyLangDTO(GameSecretKeyLangDTO.builder() .platformCode(gameGetDetailRequest.getPlatformCode()) .systemLangCode(gameGetDetailRequest.getLangCode()) @@ -373,7 +370,6 @@ public class ApiGameController extends BaseController { ApiException.notNull(gameSecretKeyLang, ErrorCode.LANG_NOT_EXIST.getCode()); - GetGameDetailResponseDTO gameDetail = iGamesService.getGameDetail(GetGameDetailRequestDTO.builder() .wagersId(gameGetDetailRequest.getWagersId()) .lang(gameSecretKeyLang.getLang()) @@ -397,7 +393,6 @@ public class ApiGameController extends BaseController { ApiException.notNull(gameSecretKey, ErrorCode.CURRENCY_NOT_EXIST.getCode()); - Member member = memberService.selectMemberByAccount(gameKickMemeberRequest.getAccount(), gameKickMemeberRequest.getCurrencyCode(), gameKickMemeberRequest.getPlatformCode()); ApiException.notNull(member, ErrorCode.ACCOUNT_NOT_EXIST.getCode()); @@ -409,6 +404,7 @@ public class ApiGameController extends BaseController { return AjaxResult.success(iGamesService.kickMember(KickMemberRequestDTO.builder() .account(member.getGameAccount()) .agentId(gameSecretKey.getCode()) + .currency(gameSecretKey.getCurrency()) .agentKey(gameSecretKey.getKey()) .build())); } @@ -424,9 +420,12 @@ public class ApiGameController extends BaseController { IGamesService iGamesService = gamesService.get(gameKickMemeberAllRequest.getPlatformCode() + Constants.SERVICE); ApiException.notNull(iGamesService, ErrorCode.PLATFORM_NOT_EXIST.getCode()); + + KickMemberAllDTO kickMemberAllDTO = KickMemberAllDTO.builder() .agentId(gameSecretKey.getCode()) .agentKey(gameSecretKey.getKey()) + .currency(gameSecretKey.getCurrency()) .build(); if (!ObjectUtils.isEmpty(gameKickMemeberAllRequest.getGameId())) { Game game = gameService.selectGameById(gameKickMemeberAllRequest.getGameId()); @@ -508,9 +507,6 @@ public class ApiGameController extends BaseController { TenantSecretKey tenantSecretKey = keyConfig.get(); - - - List gameSecretKeys = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTOList(GameSecretKeyCurrencyDTO.builder() .systemCurrency(gameExchangeBalanceAllRequest.getCurrencyCode()).build()); diff --git a/ff-game/src/main/java/com/ff/api/request/GameGetDetailRequest.java b/ff-game/src/main/java/com/ff/api/request/GameGetDetailRequest.java index 7034369..678be05 100644 --- a/ff-game/src/main/java/com/ff/api/request/GameGetDetailRequest.java +++ b/ff-game/src/main/java/com/ff/api/request/GameGetDetailRequest.java @@ -39,8 +39,8 @@ public class GameGetDetailRequest implements Serializable { /** * 投注id */ - @NotNull(message = "wagersId不能为空") - private Long wagersId; + @NotBlank(message = "wagersId不能为空") + private String wagersId; /** * 语言代码 diff --git a/ff-game/src/main/java/com/ff/game/api/IGamesService.java b/ff-game/src/main/java/com/ff/game/api/IGamesService.java index d567300..4d7c6f3 100644 --- a/ff-game/src/main/java/com/ff/game/api/IGamesService.java +++ b/ff-game/src/main/java/com/ff/game/api/IGamesService.java @@ -80,6 +80,14 @@ public interface IGamesService { Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO); + /** + * 按历史时间获取投注记录 部分平台需要两个接口同时跑投注记录 + * + * @param betRecordByTimeDTO 按时间dto投注记录 + * @return {@link Boolean } + */ + Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO); + /** * 赠送免费局数 * diff --git a/ff-game/src/main/java/com/ff/game/api/fc/address/MyFCAddressSource.java b/ff-game/src/main/java/com/ff/game/api/fc/address/MyFCAddressSource.java index 24bcefd..e67a7f0 100644 --- a/ff-game/src/main/java/com/ff/game/api/fc/address/MyFCAddressSource.java +++ b/ff-game/src/main/java/com/ff/game/api/fc/address/MyFCAddressSource.java @@ -19,6 +19,6 @@ public class MyFCAddressSource implements AddressSource { @Override public ForestAddress getAddress(ForestRequest request) { String apiBaseUrl = configService.selectConfigByKey(Constants.FC_API_BASE_URL); - return new ForestAddress("http",apiBaseUrl, 80,""); + return new ForestAddress("https",apiBaseUrl, 443,""); } } diff --git a/ff-game/src/main/java/com/ff/game/api/fc/client/FCClient.java b/ff-game/src/main/java/com/ff/game/api/fc/client/FCClient.java index d74c4a0..cdb3e12 100644 --- a/ff-game/src/main/java/com/ff/game/api/fc/client/FCClient.java +++ b/ff-game/src/main/java/com/ff/game/api/fc/client/FCClient.java @@ -2,15 +2,12 @@ package com.ff.game.api.fc.client; import com.dtflys.forest.annotation.Address; -import com.dtflys.forest.annotation.Header; import com.dtflys.forest.annotation.JSONBody; import com.dtflys.forest.annotation.Post; -import com.ff.game.api.fc.dto.ApiFCResult; +import com.ff.game.api.fc.dto.*; import com.ff.game.api.fc.address.MyFCAddressSource; -import com.ff.game.api.fc.dto.ApiKeyRequest; import com.ff.game.api.ng.dto.*; -import java.util.List; import java.util.Map; /** @@ -22,8 +19,7 @@ import java.util.Map; @Address(source = MyFCAddressSource.class) public interface FCClient { - @Post("/Key") - ApiKeyRequest key(@JSONBody Map parameters); + /** @@ -35,80 +31,83 @@ public interface FCClient { @Post("/AddMember") ApiFCResult createMember(@JSONBody Map parameters); + + /** + * 踢腿队员 + * + * @param parameters 范围 + * @return {@link ApiFCResult } + */ + @Post("/KickOut") + ApiFCResult kickMember(@JSONBody Map parameters); + + + /** + * 踢成员全部 + * + * @param parameters 范围 + * @return {@link ApiFCResult } + */ + @Post("/KickoutAll") + ApiFCResult kickMemberAll(@JSONBody Map parameters); /** * 获取会员信息 * * @param parameters 范围 - * @param headerMap 标题映射 * @return {@link ApiNGResponseDTO }<{@link String }> */ - @Post("/server/balance") - ApiNGResponseDTO getMemberInfo(@JSONBody Map parameters, @Header Map headerMap); + @Post("/SearchMember") + ApiFCUserInfoResponseDTO getMemberInfo(@JSONBody Map parameters); /** * 获取游戏列表 * * @param parameters 范围 - * @param headerMap 标题映射 - * @return {@link ApiNGResponseDTO }<{@link List }> + * @return {@link ApiFCGameListResponseDTO } */ - @Post("/server/gameCode") - ApiNGResponseDTO> getGameList(@JSONBody Map parameters, @Header Map headerMap); + @Post("/GetGameIconList") + ApiFCGameListResponseDTO getGameList(@JSONBody Map parameters); /** * 无重定向登录 * * @param parameters 范围 - * @param headerMap 标题映射 - * @return {@link ApiNGResponseDTO }<{@link ApiLoginResponseDTO }> + * @return {@link ApiFCLoginResponseDTO } */ - @Post("/server/gameUrl") - ApiNGResponseDTO loginWithoutRedirect(@JSONBody Map parameters, @Header Map headerMap); + @Post("/Login") + ApiFCLoginResponseDTO loginWithoutRedirect(@JSONBody Map parameters); /** * 按代理id进行交换转账 * * @param parameters 范围 - * @param headerMap 标题映射 - * @return {@link ApiNGResponseDTO }<{@link ApiLoginResponseDTO }> */ - @Post(url = "/server/transfer",connectTimeout = 70000) - ApiNGResponseDTO exchangeTransferByAgentId(@JSONBody Map parameters, @Header Map headerMap); - - - /** - * 汇兑转移状态 - * - * @param parameters 范围 - * @param headerMap 标题映射 - * @return {@link ApiNGResponseDTO }<{@link ApiExchangeTransferStatusResponseDTO }> - */ - @Post(url = "/server/transferStatus") - ApiNGResponseDTO exchangeTransferStatus(@JSONBody Map parameters, @Header Map headerMap); + @Post(url = "/SetPoints",connectTimeout = 70000) + ApiCFBalanceTransferResponseDTO exchangeTransferByAgentId(@JSONBody Map parameters); /** * 按时间获取投注记录 * * @param parameters 范围 - * @param headerMap 标题映射 - * @return {@link ApiNGResponseDTO }<{@link ApiGameBetRecordPageResponseDTO }> */ - @Post(url = "server/recordAll") - ApiNGResponseDTO getBetRecordByTime(@JSONBody Map parameters, @Header Map headerMap); + @Post(url = "/GetRecordList") + ApiFCBetRecordResponseDTO getBetRecordByTime(@JSONBody Map parameters); + /** * 按历史时间获取投注记录 * * @param parameters 范围 - * @param headerMap 标题映射 - * @return {@link ApiNGResponseDTO }<{@link ApiGameBetRecordPageResponseDTO }> + * @return {@link ApiFCBetRecordResponseDTO } */ - @Post(url = "server/recordHistory") - ApiNGResponseDTO getBetRecordByHistoryTime(@JSONBody Map parameters, @Header Map headerMap); + @Post(url = "/GetHistoryRecordList") + ApiFCBetRecordResponseDTO getBetRecordByHistoryTime(@JSONBody Map parameters); + + } diff --git a/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiCFBalanceTransferResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiCFBalanceTransferResponseDTO.java new file mode 100644 index 0000000..be296f3 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiCFBalanceTransferResponseDTO.java @@ -0,0 +1,47 @@ +package com.ff.game.api.fc.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; + + +/** + * api余额传输响应dto + * + * @author shi + * @date 2025/03/25 + */ +@Data +public class ApiCFBalanceTransferResponseDTO { + + /** + * 操作结果,0 表示成功,其他值表示失败 + */ + @JsonProperty("Result") + private int result; + + /** + * 银行ID + */ + @JsonProperty("BankID") + private int bankID; + + /** + * 交易ID + */ + @JsonProperty("TrsID") + private String trsID; + + /** + * 转账后余额 + */ + @JsonProperty("AfterPoint") + private BigDecimal afterPoint; + + /** + * 转账金额 + */ + @JsonProperty("Points") + private BigDecimal points; +} diff --git a/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCBetRecordResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCBetRecordResponseDTO.java new file mode 100644 index 0000000..42e6e6a --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCBetRecordResponseDTO.java @@ -0,0 +1,166 @@ +package com.ff.game.api.fc.dto; + +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Date; +import java.util.List; +import lombok.Data; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 投注记录返回实体类 + */ +@Data +public class ApiFCBetRecordResponseDTO { + + /** + * 操作结果,0 表示成功,其他值表示失败 + */ + @JsonProperty("Result") + private int Result; + + /** + * 投注记录列表 + */ + @JsonProperty("Records") + private List Records; + + /** + * 投注记录实体类 + */ + @Data + public static class BetRecord { + + /** + * 下注点数 + */ + @JsonProperty("bet") + private BigDecimal bet; + + /** + * 有效投注 (除 Lucky9 游戏,其余游戏 Bet = validBet) + */ + @JsonProperty("validBet") + private BigDecimal validBet; + + /** + * 赢分点数 + */ + @JsonProperty("prize") + private BigDecimal prize; + + /** + * 退还金额 (除 Lucky9 游戏,其余游戏 refund = win) + */ + @JsonProperty("refund") + private BigDecimal refund; + + /** + * 净输赢点数,等于 prize - validBet + */ + @JsonProperty("winlose") + private BigDecimal winlose; + + /** + * 抽水金额 (除 Lucky9 游戏,其余游戏为 0) + */ + @JsonProperty("commission") + private BigDecimal commission; + + /** + * 游戏前点数 + */ + @JsonProperty("before") + private BigDecimal before; + + /** + * 游戏后点数 + */ + @JsonProperty("after") + private BigDecimal after; + + /** + * 彩金抽水 (支持到小数第六位) + */ + @JsonProperty("jptax") + private BigDecimal jptax; + + /** + * 彩金点数 + */ + @JsonProperty("jppoints") + private BigDecimal jppoints; + + /** + * 游戏内彩金贡献 + */ + @JsonProperty("inGameJptax") + private BigDecimal inGameJptax; + + /** + * 游戏内中奖彩金 + */ + @JsonProperty("inGameJppoints") + private BigDecimal inGameJppoints; + + /** + * 游戏记录编号 (唯一码),24 字符 + */ + @JsonProperty("recordID") + private String recordID; + + /** + * 玩家账号 + */ + @JsonProperty("account") + private String account; + + /** + * 游戏编号 + */ + @JsonProperty("gameID") + private String gameID; + + /** + * 游戏类型 + */ + @JsonProperty("gametype") + private String gametype; + + /** + * 彩金模式 + */ + @JsonProperty("jpmode") + private int jpmode; + + /** + * 游戏内彩金模式 + */ + @JsonProperty("inGameJpmode") + private int inGameJpmode; + + /** + * 下注时间 + */ + @JsonProperty("bdate") + private Date bdate; + + /** + * 是否购买免费游戏 + */ + @JsonProperty("isBuyFeature") + private boolean isBuyFeature; + + /** + * 用于确认此注单是否有获得免费游戏或其他红利游戏 + */ + @JsonProperty("gameMode") + private int gameMode; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCGameListResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCGameListResponseDTO.java new file mode 100644 index 0000000..784fd18 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCGameListResponseDTO.java @@ -0,0 +1,67 @@ +package com.ff.game.api.fc.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.Map; + +/** + * 游戏列表 API 响应 DTO + */ +@Data +public class ApiFCGameListResponseDTO { + + /** + * 操作结果,0 表示成功,其他值表示失败 + */ + @JsonProperty("Result") + private int result; + + /** + * 获取游戏图标列表 + */ + @JsonProperty("GetGameIconList") + private Map> getGameIconList; + + /** + * 游戏详情 + */ + @Data + public static class GameDetails { + + /** + * 游戏状态 + */ + private String status; + + /** + * 系统游戏id + */ + private Long systemGameId; + /** + * 游戏id + */ + private String gameId; + + + /** + * 中文游戏名称 + */ + private String gameNameOfChinese; + + /** + * 英文游戏名称 + */ + private String gameNameOfEnglish; + + /** + * 英文图标URL + */ + private String enUrl; + + /** + * 中文图标URL + */ + private String cnUrl; + } +} \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCLoginResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCLoginResponseDTO.java new file mode 100644 index 0000000..ac447ff --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCLoginResponseDTO.java @@ -0,0 +1,24 @@ +package com.ff.game.api.fc.dto; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 登录返回信息 API 响应 DTO + */ +@Data +public class ApiFCLoginResponseDTO { + + /** + * 操作结果,0 表示成功,其他值表示失败 + */ + @JsonProperty("Result") + private int result; + + /** + * 登录跳转 URL + */ + @JsonProperty("Url") + private String url; +} \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCUserInfoResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCUserInfoResponseDTO.java new file mode 100644 index 0000000..423d7d7 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCUserInfoResponseDTO.java @@ -0,0 +1,35 @@ +package com.ff.game.api.fc.dto; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * 用户信息 API 响应 DTO + * + * @author shi + * @date 2025/03/25 + */ +@Data +public class ApiFCUserInfoResponseDTO { + + /** + * 操作结果,0 表示成功,其他值表示失败 + */ + @JsonProperty("Result") + private int result; + + /** + * 在线类型 + */ + @JsonProperty("OnlineType") + private int onlineType; + + /** + * 积分 + */ + @JsonProperty("Points") + private BigDecimal points; +} \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/fc/impl/GamesFCServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/fc/impl/GamesFCServiceImpl.java index d7eea10..0326211 100644 --- a/ff-game/src/main/java/com/ff/game/api/fc/impl/GamesFCServiceImpl.java +++ b/ff-game/src/main/java/com/ff/game/api/fc/impl/GamesFCServiceImpl.java @@ -11,20 +11,16 @@ 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.SleepUtil; -import com.ff.base.utils.StringUtils; import com.ff.base.utils.sign.Md5Utils; import com.ff.config.KeyConfig; import com.ff.game.api.IGamesService; -import com.ff.game.api.fc.dto.ApiFCResult; +import com.ff.game.api.fc.dto.*; import com.ff.game.api.fc.client.FCClient; -import com.ff.game.api.ng.dto.*; +import com.ff.game.api.ng.client.NGClient; import com.ff.game.api.request.*; import com.ff.game.domain.*; import com.ff.game.dto.GameBettingDetailsDTO; -import com.ff.game.dto.GameDTO; import com.ff.game.dto.GameSecretKeyCurrencyDTO; -import com.ff.game.dto.GameSecretKeyLangDTO; import com.ff.game.service.*; import com.ff.member.domain.Member; import com.ff.member.service.IMemberService; @@ -43,12 +39,8 @@ import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.math.BigDecimal; import java.nio.charset.StandardCharsets; -import java.time.Instant; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @@ -122,9 +114,10 @@ public class GamesFCServiceImpl implements IGamesService { * @return {@link Boolean } */ private Boolean getIsSuccess(Integer errorCode) { - ApiException.isTrue(10009 != errorCode, ErrorCode.FREQUENT_INTERFACE_REQUESTS.getCode()); - - return 10000 == errorCode; + ApiException.isTrue(503 != errorCode, ErrorCode.PLAYERS_ARE_PLAYING.getCode()); + ApiException.isTrue(203 != errorCode, ErrorCode.INSUFFICIENT_PLAYER_BALANCE.getCode()); + ApiException.isTrue(504 != errorCode, ErrorCode.ACCOUNT_NOT_ONLINE.getCode()); + return 0 == errorCode; } @@ -149,7 +142,6 @@ public class GamesFCServiceImpl implements IGamesService { } - /** * 获取密钥映射 * @@ -158,14 +150,14 @@ public class GamesFCServiceImpl implements IGamesService { * @param currency 货币 * @return {@link Map }<{@link String },{@link Object }> */ - private Map getKeyMap(Map paramsMap,String agentKey,String currency){ + private Map getKeyMap(Map paramsMap, String agentKey, String currency, String agentId) { Map keyMap = new HashMap<>(); String key = getKey(paramsMap, agentKey); keyMap.put("Sign", Md5Utils.md5New(JSONUtils.toJSONString(paramsMap))); - keyMap.put("AgentCode", "TTCS"); + keyMap.put("AgentCode", agentId); keyMap.put("Currency", currency); - keyMap.put("Params",key); - return keyMap; + keyMap.put("Params", key); + return keyMap; } @@ -177,7 +169,7 @@ public class GamesFCServiceImpl implements IGamesService { */ private String decryptKey(GamesBaseRequestDTO gamesBaseRequestDTO) { try { - String val="SBF6G5gFvW5n4aFSFCar9Im0CHgBMyU7OxFTuuB6InmRkm6Qt4K2pfktU="; + String val = "SBF6G5gFvW5n4aFSFCar9Im0CHgBMyU7OxFTuuB6InmRkm6Qt4K2pfktU="; Base64.Decoder decoder = Base64.getDecoder(); SecretKeySpec keySpec = new SecretKeySpec("gamesBaseRequestDTO.getAgentKey()".getBytes(), "AES"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); @@ -185,6 +177,7 @@ public class GamesFCServiceImpl implements IGamesService { return new String(cipher.doFinal(decoder.decode(val))); } catch (Exception e) { throw new BaseException("解密失败"); + } } @@ -197,18 +190,15 @@ public class GamesFCServiceImpl implements IGamesService { */ @Override public Boolean createMember(CreateMemberRequestDTO createMemberRequestDTO) { - log.info("GamesNGServiceImpl [createMember] 请求参数 {}", createMemberRequestDTO); + log.info("GamesFCServiceImpl [createMember] 请求参数 {}", createMemberRequestDTO); Map paramsMap = new HashMap<>(); paramsMap.put("MemberAccount", createMemberRequestDTO.getAccount()); - paramsMap.putAll(getKeyMap(paramsMap, createMemberRequestDTO.getAgentKey(), createMemberRequestDTO.getCurrency())); + paramsMap.putAll(getKeyMap(paramsMap, createMemberRequestDTO.getAgentKey(), createMemberRequestDTO.getCurrency(), createMemberRequestDTO.getAgentId())); ApiFCResult apiFCResult = FCClient.createMember(paramsMap); int errorCode = apiFCResult.getResult(); - if (10000 == errorCode) { + if (0 == errorCode) { return Boolean.TRUE; } - if (10002 == errorCode) { - throw new ApiException(ErrorCode.GAME_ACCOUNT_CREATION_FAILED.getCode()); - } //判断是否获取成功 return Boolean.FALSE; } @@ -222,19 +212,18 @@ public class GamesFCServiceImpl implements IGamesService { */ @Override public MemberInfoResponseDTO getMemberInfo(MemberInfoRequestDTO memberInfoRequestDTO) { - log.info("GamesNGServiceImpl [getMemberInfo] 请求参数 {}", memberInfoRequestDTO); + log.info("GamesFCServiceImpl [getMemberInfo] 请求参数 {}", memberInfoRequestDTO); Map paramsMap = new HashMap<>(); - paramsMap.put("playerId", memberInfoRequestDTO.getAccounts()); - paramsMap.put("platType", NGPlatforms.PG.getCode()); - paramsMap.put("currency", memberInfoRequestDTO.getCurrency()); - //这个接口请求稍微重复一次就报错 - SleepUtil.sleep(500); - ApiNGResponseDTO apiNGResponseDTO = FCClient.getMemberInfo(paramsMap, null); - int errorCode = apiNGResponseDTO.getCode(); + paramsMap.put("MemberAccount", memberInfoRequestDTO.getAccounts()); + paramsMap.putAll(getKeyMap(paramsMap, memberInfoRequestDTO.getAgentKey(), memberInfoRequestDTO.getCurrency(), memberInfoRequestDTO.getAgentId())); + ApiFCUserInfoResponseDTO apiFCUserInfoResponseDTO = FCClient.getMemberInfo(paramsMap); + int errorCode = apiFCUserInfoResponseDTO.getResult(); if (this.getIsSuccess(errorCode)) { - return MemberInfoResponseDTO.builder().account(memberInfoRequestDTO.getAccounts()).balance(apiNGResponseDTO.getData().getBalance()).status(GameMemberStatus.UNKNOWN.getCode()).build(); + return MemberInfoResponseDTO.builder().account(memberInfoRequestDTO.getAccounts()) + .balance(apiFCUserInfoResponseDTO.getPoints()) + .status(apiFCUserInfoResponseDTO.getOnlineType() != 0 ? GameMemberStatus.ONLINE.getCode() : GameMemberStatus.OFFLINE.getCode()).build(); } else { - throw new BaseException(apiNGResponseDTO.getMsg()); + throw new ApiException(ErrorCode.ACCOUNT_NOT_EXIST.getCode()); } } @@ -246,22 +235,18 @@ public class GamesFCServiceImpl implements IGamesService { */ @Override public String loginWithoutRedirect(GamesLogin gamesLogin) { - log.info("GamesNGServiceImpl [loginWithoutRedirect] 请求参数 {}", gamesLogin); + log.info("GamesFCServiceImpl [loginWithoutRedirect] 请求参数 {}", gamesLogin); Map paramsMap = new HashMap<>(); - paramsMap.put("playerId", gamesLogin.getAccount()); - paramsMap.put("platType", NGPlatforms.PG.getCode()); - paramsMap.put("currency", gamesLogin.getCurrency()); - paramsMap.put("gameType", gamesLogin.getGameType()); - paramsMap.put("lang", gamesLogin.getLang()); - paramsMap.put("gameCode", gamesLogin.getGameId()); - paramsMap.put("returnUrl", gamesLogin.getHomeUrl()); - paramsMap.put("ingress", PlatformHomeType.WEB.getValue().equals(gamesLogin.getPlatform()) ? IngressType.PC_WEB.getValue() : IngressType.MOBILE_WEB.getValue()); - Map headerMap =new HashMap<>(); - ApiNGResponseDTO apiLoginResponseDTOApiNGResponseDTO = FCClient.loginWithoutRedirect(paramsMap, headerMap); - if (this.getIsSuccess(apiLoginResponseDTOApiNGResponseDTO.getCode())) { - return apiLoginResponseDTOApiNGResponseDTO.getData().getUrl(); + paramsMap.put("MemberAccount", gamesLogin.getAccount()); + paramsMap.put("GameID", gamesLogin.getGameId()); + paramsMap.put("LanguageID", gamesLogin.getLang()); + paramsMap.put("HomeUrl", gamesLogin.getHomeUrl()); + paramsMap.putAll(getKeyMap(paramsMap, gamesLogin.getAgentKey(), gamesLogin.getCurrency(), gamesLogin.getAgentId())); + ApiFCLoginResponseDTO apiFCLoginResponseDTO = FCClient.loginWithoutRedirect(paramsMap); + if (this.getIsSuccess(apiFCLoginResponseDTO.getResult())) { + return apiFCLoginResponseDTO.getUrl(); } else { - throw new BaseException(apiLoginResponseDTOApiNGResponseDTO.getMsg()); + throw new ApiException(ErrorCode.ACCOUNT_NOT_EXIST.getCode()); } } @@ -275,88 +260,92 @@ public class GamesFCServiceImpl implements IGamesService { @Transactional @Override public String getGameList(GamesBaseRequestDTO gamesBaseRequestDTO) { - List apiGameInfoResponseDTOS = redisCache.getCacheList(CacheConstants.PG_GAMES); + List apiGameInfoResponseDTOS = redisCache.getCacheList(CacheConstants.FC_GAMES); if (!CollectionUtils.isEmpty(apiGameInfoResponseDTOS)) { - return CacheConstants.PG_GAMES; + return CacheConstants.FC_GAMES; } - - log.info("GamesNGServiceImpl [getGameList] 请求参数 {}", gamesBaseRequestDTO); + gamesBaseRequestDTO.setCurrency("CNY"); + log.info("GamesFCServiceImpl [getGameList] 请求参数 {}", gamesBaseRequestDTO); Map paramsMap = new HashMap<>(); - paramsMap.put("platType", NGPlatforms.PG.getCode()); - Map headerMap =new HashMap<>(); - ApiNGResponseDTO> gameList = FCClient.getGameList(paramsMap, headerMap); - if (this.getIsSuccess(gameList.getCode())) { - for (ApiGameInfoResponseDTO apiGameInfoResponseDTO : gameList.getData()) { + paramsMap.putAll(getKeyMap(paramsMap, gamesBaseRequestDTO.getAgentKey(), gamesBaseRequestDTO.getCurrency(), gamesBaseRequestDTO.getAgentId())); + ApiFCGameListResponseDTO gameList = FCClient.getGameList(paramsMap); + if (this.getIsSuccess(gameList.getResult())) { + + List gameDetailsList = new ArrayList<>(); + + for (String gameTypeKey : gameList.getGetGameIconList().keySet()) { + Map integerGameDetailsMap = gameList.getGetGameIconList().get(gameTypeKey); GamePlatform gamePlatform = GamePlatform.builder() - .platformType(NGGameType.findSystemByCode(apiGameInfoResponseDTO.getGameType())) - .platformCode(GamePlatforms.PG.getCode()) + .platformType(FCGameType.findSystemByCode(gameTypeKey)) + .platformCode(GamePlatforms.FC.getCode()) .build(); List gamePlatforms = gamePlatformService.selectGamePlatformList(gamePlatform); //没有此平台就新增一个平台 if (CollectionUtils.isEmpty(gamePlatforms)) { - gamePlatform.setPlatformName(GamePlatforms.PG.getInfo() + NGGameType.findInfoByCode(apiGameInfoResponseDTO.getGameType())); + gamePlatform.setPlatformName(GamePlatforms.FC.getInfo() + FCGameType.findInfoByCode(gameTypeKey)); 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(apiGameInfoResponseDTO.getGameCode()) - .build(); - List games = gameService.selectGameList(game); - //不存在这个游戏 - if (CollectionUtils.isEmpty(games)) { - game.setGameSourceType(apiGameInfoResponseDTO.getGameType()); - game.setFreespin(Boolean.FALSE); - game.setDemoStatus(Boolean.TRUE); - game.setSortNo(gameService.selectMaxSortNoByPlatformId(gamePlatform.getId()) + 1); - game.setGameName(apiGameInfoResponseDTO.getGameName().get("zh-hans")); - game.setCreateBy(Constants.SYSTEM); - gameService.insertGame(game); - } else { - game = games.get(0); - } - apiGameInfoResponseDTO.setSystemGameId(game.getId()); - Map gameName = apiGameInfoResponseDTO.getGameName(); - for (String key : gameName.keySet()) { - String name = gameName.get(key); - List gameNames = gameNameService.selectGameNameList(GameName.builder().gameId(game.getId()).gameName(name).build()); - if (CollectionUtils.isEmpty(gameNames)) { - if ("zh-hans".equals(key)) { - gameNameService.insertGameName(GameName.builder() - .gameId(game.getId()) - .gameName(name) - .langCode("zh-CN") - .createBy(Constants.SYSTEM) - .build()); - } else if (!"zh-hant".equals(key)) { - GameSecretKeyLangDTO gameSecretKeyLangDTO = gameSecretKeyLangService.findGameSecretKeyLangDTO(GameSecretKeyLangDTO.builder() - .platformCode(GamePlatforms.PG.getCode()) - .lang(key) - .build()); - gameNameService.insertGameName(GameName.builder() - .gameId(game.getId()) - .gameName(name) - .langCode(gameSecretKeyLangDTO.getSystemLangCode()) - .createBy(Constants.SYSTEM) - .build()); - } + + //新增游戏 + for (String gameIdKey : integerGameDetailsMap.keySet()) { + + ApiFCGameListResponseDTO.GameDetails gameDetails = integerGameDetailsMap.get(gameIdKey); + Game game = Game.builder() + .platformId(gamePlatform.getId()) + .gameCode(gameIdKey) + .build(); + List games = gameService.selectGameList(game); + //不存在这个游戏 + if (CollectionUtils.isEmpty(games)) { + game.setGameSourceType(PlatformType.ELECTRONIC.getCode()); + game.setFreespin(Boolean.FALSE); + game.setDemoStatus(Boolean.TRUE); + game.setSortNo(gameService.selectMaxSortNoByPlatformId(gamePlatform.getId()) + 1); + game.setGameName(gameDetails.getGameNameOfChinese()); + game.setCreateBy(Constants.SYSTEM); + gameService.insertGame(game); + } else { + game = games.get(0); } + gameDetails.setSystemGameId(game.getId()); + + List gameNames = gameNameService.selectGameNameList(GameName.builder().gameId(game.getId()).gameName(gameDetails.getGameNameOfChinese()).build()); + if (CollectionUtils.isEmpty(gameNames)) { + gameNameService.insertGameName(GameName.builder() + .gameId(game.getId()) + .gameName(gameDetails.getGameNameOfChinese()) + .langCode("zh-CN") + .createBy(Constants.SYSTEM) + .build()); + } + gameNames = gameNameService.selectGameNameList(GameName.builder().gameId(game.getId()).gameName(gameDetails.getGameNameOfEnglish()).build()); + if (CollectionUtils.isEmpty(gameNames)) { + gameNameService.insertGameName(GameName.builder() + .gameId(game.getId()) + .gameName(gameDetails.getGameNameOfEnglish()) + .langCode("en-US") + .createBy(Constants.SYSTEM) + .build()); + } + + gameDetails.setGameId(gameIdKey); + gameDetailsList.add(gameDetails); } } - - redisCache.deleteObject(CacheConstants.PG_GAMES); - redisCache.setCacheList(CacheConstants.PG_GAMES, gameList.getData()); - redisCache.expire(CacheConstants.PG_GAMES, 5L, TimeUnit.HOURS); + redisCache.deleteObject(CacheConstants.FC_GAMES); + redisCache.setCacheList(CacheConstants.FC_GAMES, gameDetailsList); + redisCache.expire(CacheConstants.FC_GAMES, 5L, TimeUnit.HOURS); } else { - throw new BaseException(gameList.getMsg()); + throw new ApiException(ErrorCode.ERROR.getCode()); } - return CacheConstants.PG_GAMES; + return CacheConstants.FC_GAMES; } /** @@ -368,16 +357,16 @@ public class GamesFCServiceImpl implements IGamesService { @Override @Transactional public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO) { - log.info("GamesNGServiceImpl [exchangeTransferByAgentId] 请求参数 {}", exchangeTransferMoneyRequestDTO); + log.info("GamesFCServiceImpl [exchangeTransferByAgentId] 请求参数 {}", exchangeTransferMoneyRequestDTO); GameSecretKeyCurrency currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(GamePlatforms.PG.getCode()) + .platformCode(GamePlatforms.FC.getCode()) .code(exchangeTransferMoneyRequestDTO.getAgentId()) .currency(exchangeTransferMoneyRequestDTO.getCurrency()) .build()); Member member = memberService.selectMemberByGameAccount(exchangeTransferMoneyRequestDTO.getAccount()); - String transactionId = gameExchangeMoneyService.getTransactionId(GamePlatforms.PG.getCode(), 32); + String transactionId = gameExchangeMoneyService.getTransactionId(GamePlatforms.FC.getCode(), 30); List gameExchangeMonies = gameExchangeMoneyService.selectGameExchangeMoneyList( GameExchangeMoney.builder() .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) @@ -397,12 +386,17 @@ public class GamesFCServiceImpl implements IGamesService { .currencyCode(currencyDTO.getSystemCurrency()) .memberId(member.getId()) .transactionId(transactionId) - .platformCode(GamePlatforms.PG.getCode()) + .platformCode(GamePlatforms.FC.getCode()) .build(); exchangeMoney.setCreateBy(Constants.SYSTEM); //获取余额 - String type = TransferType.ALL.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType()) ? NGTransferType.TRANSFER_OUT.getValue() : NGTransferType.TRANSFER_IN.getValue(); + String type = TransferType.ALL.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType()) ? FCTransferType.TRANSFER_OUT_ALL.getValue() : FCTransferType.TRANSFER_OUT.getValue(); + + + BigDecimal amount = exchangeTransferMoneyRequestDTO.getAmount(); + + //获取当前游戏币 MemberInfoRequestDTO gamesBaseRequestDTO = MemberInfoRequestDTO.builder() .accounts(member.getGameAccount()) @@ -418,31 +412,28 @@ public class GamesFCServiceImpl implements IGamesService { Map paramsMap = new HashMap<>(); - paramsMap.put("platType", NGPlatforms.PG.getCode()); - paramsMap.put("playerId", exchangeTransferMoneyRequestDTO.getAccount()); - paramsMap.put("currency", currencyDTO.getCurrency()); - paramsMap.put("type", type); - paramsMap.put("amount", exchangeTransferMoneyRequestDTO.getAmount()); - paramsMap.put("orderId", transactionId); + paramsMap.put("MemberAccount", exchangeTransferMoneyRequestDTO.getAccount()); + paramsMap.put("TrsID", transactionId); + paramsMap.put("AllOut", type); + paramsMap.put("Points", amount); + paramsMap.putAll(getKeyMap(paramsMap, gamesBaseRequestDTO.getAgentKey(), gamesBaseRequestDTO.getCurrency(), gamesBaseRequestDTO.getAgentId())); - Map key =new HashMap<>(); - ApiNGResponseDTO apiNGResponseDTO = FCClient.exchangeTransferByAgentId(paramsMap, key); - if (this.getIsSuccess(apiNGResponseDTO.getCode())) { + ApiCFBalanceTransferResponseDTO transferResponseDTO = FCClient.exchangeTransferByAgentId(paramsMap); + if (this.getIsSuccess(transferResponseDTO.getResult())) { //更新数据 - exchangeMoney.setBalance(exchangeTransferMoneyRequestDTO.getAmount()); + exchangeMoney.setBalance(transferResponseDTO.getPoints().abs()); exchangeMoney.setStatus(StatusType.IN_PROGRESS.getValue()); + exchangeMoney.setCoinBefore(NumberUtil.sub(transferResponseDTO.getAfterPoint(), exchangeMoney.getBalance()).abs()); + exchangeMoney.setCoinAfter(transferResponseDTO.getAfterPoint()); + exchangeMoney.setCurrencyBefore(exchangeMoney.getCoinBefore()); + exchangeMoney.setCurrencyAfter(exchangeMoney.getCoinAfter()); + exchangeMoney.setStatus(StatusType.SUCCESS.getValue()); + gameExchangeMoneyService.insertGameExchangeMoney(exchangeMoney); - ExchangeTransferStatusRequestDTO exchangeTransferStatusRequestDTO = new ExchangeTransferStatusRequestDTO(); - exchangeTransferStatusRequestDTO.setAccount(exchangeTransferMoneyRequestDTO.getAccount()); - exchangeTransferStatusRequestDTO.setCurrency(currencyDTO.getCurrency()); - exchangeTransferStatusRequestDTO.setOrderId(transactionId); - exchangeTransferStatusRequestDTO.setAgentId(exchangeTransferMoneyRequestDTO.getAgentId()); - exchangeTransferStatusRequestDTO.setAgentKey(exchangeTransferMoneyRequestDTO.getAgentKey()); - this.exchangeTransferStatus(exchangeTransferStatusRequestDTO); } else { - log.error("GamesPGServiceImpl [exchangeTransferByAgentId] 金额转移失败,错误代码{},错误信息{}", apiNGResponseDTO.getCode(), apiNGResponseDTO.getMsg()); - throw new BaseException(apiNGResponseDTO.getMsg()); + log.error("GamesFCServiceImpl [exchangeTransferByAgentId] 金额转移失败,错误代码{}", transferResponseDTO.getResult()); + throw new ApiException(ErrorCode.BALANCE_TRANSFER_FAILED.getCode()); } return exchangeMoney.getId(); } @@ -456,38 +447,7 @@ public class GamesFCServiceImpl implements IGamesService { @Override public Boolean exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { - - Map paramsMap = new HashMap<>(); - paramsMap.put("playerId", exchangeTransferMoneyRequestDTO.getAccount()); - paramsMap.put("currency", exchangeTransferMoneyRequestDTO.getCurrency()); - paramsMap.put("orderId", exchangeTransferMoneyRequestDTO.getOrderId()); - Map key =new HashMap<>(); - ApiNGResponseDTO apiNGResponseDTO = FCClient.exchangeTransferStatus(paramsMap, key); - if (this.getIsSuccess(apiNGResponseDTO.getCode())) { - ApiExchangeTransferStatusResponseDTO apiNGResponseDTOData = apiNGResponseDTO.getData(); - List gameExchangeMonies = gameExchangeMoneyService.selectGameExchangeMoneyList( - GameExchangeMoney.builder() - .platformCode(GamePlatforms.PG.getCode()) - .transactionId(exchangeTransferMoneyRequestDTO.getOrderId()) - .build() - ); - - for (GameExchangeMoney exchangeMoney : gameExchangeMonies) { - //更新数据 - exchangeMoney.setBalance(apiNGResponseDTOData.getAmount().abs()); - exchangeMoney.setCoinBefore(NumberUtil.sub(apiNGResponseDTOData.getAfterBalance(), apiNGResponseDTOData.getAmount())); - exchangeMoney.setCoinAfter(apiNGResponseDTOData.getAfterBalance()); - exchangeMoney.setCurrencyBefore(exchangeMoney.getCoinBefore()); - exchangeMoney.setCurrencyAfter(exchangeMoney.getCoinAfter()); - exchangeMoney.setStatus(apiNGResponseDTOData.getStatus()); - gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); - } - return Boolean.TRUE; - } else { - log.error("GamesPGServiceImpl [exchangeTransferStatus]错误代码{},错误信息{}", apiNGResponseDTO.getCode(), apiNGResponseDTO.getMsg()); - return Boolean.FALSE; - } - + return Boolean.TRUE; } @@ -501,82 +461,29 @@ public class GamesFCServiceImpl implements IGamesService { @Override public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) { - GameSecretKeyCurrencyDTO gameSecretKeyDTO = new GameSecretKeyCurrencyDTO(); - gameSecretKeyDTO.setPlatformCodes(NGPlatforms.getAllPlatforms()); - List currencyDTOList = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTOList(gameSecretKeyDTO); - List currencys = currencyDTOList.stream() - .map(GameSecretKeyCurrencyDTO::getCurrency) - .distinct() - .collect(Collectors.toList()); - - Set cacheSet = redisCache.getCacheSet(CacheConstants.PG_GAMES_BET_CURRENCY); - if (CollectionUtils.isEmpty(cacheSet)) { - cacheSet = new HashSet<>(); - } - //如果长度一致则清空缓存循环币种 - if (cacheSet.size() >= currencys.size()) { - cacheSet = new HashSet<>(); - redisCache.deleteObject(CacheConstants.PG_GAMES_BET_CURRENCY); - } - //去掉重复的 - currencys.removeAll(cacheSet); - - String firstCurrency = currencys.get(0); - - GameSecretKeyCurrencyDTO currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(GamePlatforms.PG.getCode()) - .currency(firstCurrency) + List gameSecretKeyCurrencies = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTOList(GameSecretKeyCurrencyDTO.builder() + .platformCode(GamePlatforms.FC.getCode()) .build()); + for (GameSecretKeyCurrency gameSecretKeyCurrency : gameSecretKeyCurrencies) { + String startTime = DateUtils.convertTimeZone(betRecordByTimeDTO.getStartTime(), "America/New_York", DateUtils.YYYY_MM_DD_HH_MM_SS); + String endTime = DateUtils.convertTimeZone(betRecordByTimeDTO.getEndTime(), "America/New_York", DateUtils.YYYY_MM_DD_HH_MM_SS); + Map paramsMap = new HashMap<>(); + paramsMap.put("StartDate", startTime); + paramsMap.put("EndDate", endTime); + paramsMap.putAll(getKeyMap(paramsMap, betRecordByTimeDTO.getAgentKey(), gameSecretKeyCurrency.getCurrency(), betRecordByTimeDTO.getAgentId())); - betRecordByTimeDTO.setAgentId(currencyDTO.getCode()); - betRecordByTimeDTO.setAgentKey(currencyDTO.getKey()); - int pageNo = 1; - int pageSize = 2000; - Map paramsMap = new HashMap<>(); - paramsMap.put("currency", currencyDTO.getCurrency()); - paramsMap.put("pageNo", pageNo); - paramsMap.put("pageSize", pageSize); - Map key = new HashMap<>(); + ApiFCBetRecordResponseDTO betRecordByTime = FCClient.getBetRecordByTime(paramsMap); - - ApiNGResponseDTO betRecordByTime = FCClient.getBetRecordByTime(paramsMap, key); - - if (this.getIsSuccess(betRecordByTime.getCode())) { - cacheSet.add(firstCurrency); - redisCache.setCacheSet(CacheConstants.PG_GAMES_BET_CURRENCY, cacheSet); - - ApiNGResponseDTO result = betRecordByTime; - AtomicInteger pageNoAtomic = new AtomicInteger(pageNo); - - - ApiGameBetRecordPageResponseDTO data = result.getData(); - //数据组装 - this.batchInsert(data); - - //总页数 - // 计算总页数,确保不会遗漏 - int totalPage = (int) Math.ceil((double) data.getTotal() / pageSize); - - // 获取下一页数据 - while (pageNoAtomic.get() < totalPage && data.getTotal() > 0) { - pageNoAtomic.incrementAndGet(); - //请求参数 - Map paramMap = new HashMap<>(); - paramMap.put("currency", currencyDTO.getCurrency()); - paramMap.put("pageNo", pageNoAtomic.get()); - paramMap.put("pageSize", pageSize); - SleepUtil.sleep(10000); - ApiNGResponseDTO betRecordByTimePage = FCClient.getBetRecordByTime(paramMap, key); - data = betRecordByTimePage.getData(); + if (this.getIsSuccess(betRecordByTime.getResult())) { //数据组装 - this.batchInsert(data); + this.batchInsert(betRecordByTime, gameSecretKeyCurrency.getSystemCurrency(), gameSecretKeyCurrency.getCurrency()); + } } - getBetRecordByHistoryTime(betRecordByTimeDTO, currencyDTO); return Boolean.TRUE; } @@ -584,85 +491,41 @@ public class GamesFCServiceImpl implements IGamesService { * 按历史时间获取投注记录 * * @param betRecordByTimeDTO 按时间dto投注记录 - * @param currencyDTO 货币dto + * @return {@link Boolean } */ - private void getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO, GameSecretKeyCurrencyDTO currencyDTO) { + @Override + public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { + List gameSecretKeyCurrencies = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTOList(GameSecretKeyCurrencyDTO.builder() + .platformCode(GamePlatforms.FC.getCode()) + .build()); - //捞取指定30分钟前的数据 - Long startTimes = DateUtils.addOrSubtractMinutes(DateUtils.getNowDate(), -30); - Long endTimes = DateUtils.getNowDate(); - betRecordByTimeDTO.setStartTime(startTimes); - betRecordByTimeDTO.setEndTime(endTimes); + for (GameSecretKeyCurrency gameSecretKeyCurrency : gameSecretKeyCurrencies) { + //必须两个小时之前的数据 + long startTimeLong = DateUtils.addOrSubtractMinutes(betRecordByTimeDTO.getStartTime(), -120); + long endTimeLong = DateUtils.addOrSubtractMinutes(betRecordByTimeDTO.getEndTime(), -120); + //查询一个小时内的数据一次最多15分钟 + int timeWheel = 60; + while (timeWheel > 0) { + String startTime = DateUtils.convertTimeZone(startTimeLong, "America/New_York", DateUtils.YYYY_MM_DD_HH_MM_SS); + String endTime = DateUtils.convertTimeZone(endTimeLong, "America/New_York", DateUtils.YYYY_MM_DD_HH_MM_SS); + Map paramsMap = new HashMap<>(); + paramsMap.put("StartDate", startTime); + paramsMap.put("EndDate", endTime); + paramsMap.putAll(getKeyMap(paramsMap, betRecordByTimeDTO.getAgentKey(), gameSecretKeyCurrency.getCurrency(), betRecordByTimeDTO.getAgentId())); - int currentMinute = java.time.LocalTime.now().getMinute(); - // 判断当前分钟是否是 20 分、40 分或 0 分,如果不是,跳过当前执行 - if (currentMinute != 20 && currentMinute != 40 && currentMinute != 0) { - // 当前时间不是 20 分、40 分、0 分,跳过执行 - return; - } + ApiFCBetRecordResponseDTO betRecordByTime = FCClient.getBetRecordByHistoryTime(paramsMap); - - String startTime = DateTimeFormatter - .ofPattern("yyyy-MM-dd HH:mm:ss") - .withZone(ZoneId.of("Asia/Shanghai")) - .format(Instant.ofEpochMilli(betRecordByTimeDTO.getStartTime())); - - String endTime = DateTimeFormatter - .ofPattern("yyyy-MM-dd HH:mm:ss") - .withZone(ZoneId.of("Asia/Shanghai")) - .format(Instant.ofEpochMilli(betRecordByTimeDTO.getEndTime())); - - - betRecordByTimeDTO.setAgentId(currencyDTO.getCode()); - betRecordByTimeDTO.setAgentKey(currencyDTO.getKey()); - int pageNo = 1; - int pageSize = 2000; - Map paramsMap = new HashMap<>(); - paramsMap.put("currency", currencyDTO.getCurrency()); - paramsMap.put("pageNo", pageNo); - paramsMap.put("pageSize", pageSize); - paramsMap.put("startTime", startTime); - paramsMap.put("endTime", endTime); - Map key =new HashMap<>(); - - - ApiNGResponseDTO betRecordByTime = FCClient.getBetRecordByHistoryTime(paramsMap, key); - - if (this.getIsSuccess(betRecordByTime.getCode())) { - ApiNGResponseDTO result = betRecordByTime; - AtomicInteger pageNoAtomic = new AtomicInteger(pageNo); - - threadPoolTaskExecutor.execute(() -> { - - ApiGameBetRecordPageResponseDTO data = result.getData(); - //数据组装 - this.batchInsert(data); - - //总页数 - // 计算总页数,确保不会遗漏 - int totalPage = (int) Math.ceil((double) data.getTotal() / pageSize); - - // 获取下一页数据 - while (pageNoAtomic.get() < totalPage && data.getTotal() > 0) { - pageNoAtomic.incrementAndGet(); - //请求参数 - Map paramMap = new HashMap<>(); - paramMap.put("currency", currencyDTO.getCurrency()); - paramMap.put("pageNo", pageNoAtomic.get()); - paramMap.put("pageSize", pageSize); - paramMap.put("startTime", startTime); - paramMap.put("endTime", endTime); - SleepUtil.sleep(10000); - ApiNGResponseDTO betRecordByTimePage = FCClient.getBetRecordByTime(paramMap, key); - data = betRecordByTimePage.getData(); + if (this.getIsSuccess(betRecordByTime.getResult())) { //数据组装 - this.batchInsert(data); + this.batchInsert(betRecordByTime, gameSecretKeyCurrency.getSystemCurrency(), gameSecretKeyCurrency.getCurrency()); } - }); + timeWheel -= 15; + } } + return Boolean.TRUE; } @@ -705,8 +568,16 @@ public class GamesFCServiceImpl implements IGamesService { */ @Override public Boolean kickMember(KickMemberRequestDTO kickMemberRequestDTO) { - - return null; + log.info("GamesFCServiceImpl [kickMember] 请求参数 {}", kickMemberRequestDTO); + Map paramsMap = new HashMap<>(); + paramsMap.put("MemberAccount", kickMemberRequestDTO.getAccount()); + paramsMap.putAll(getKeyMap(paramsMap, kickMemberRequestDTO.getAgentKey(), kickMemberRequestDTO.getCurrency(), kickMemberRequestDTO.getAgentId())); + ApiFCResult apiFCResult = FCClient.kickMember(paramsMap); + if (this.getIsSuccess(apiFCResult.getResult())) { + return Boolean.TRUE; + } else { + throw new ApiException(ErrorCode.KICK_OUT_AILED.getCode()); + } } /** @@ -717,8 +588,15 @@ public class GamesFCServiceImpl implements IGamesService { */ @Override public Boolean kickMemberAll(KickMemberAllDTO kickMemberAllDTO) { - - return null; + log.info("GamesFCServiceImpl [kickMemberAll] 请求参数 {}", kickMemberAllDTO); + Map paramsMap = new HashMap<>(); + paramsMap.putAll(getKeyMap(paramsMap, kickMemberAllDTO.getAgentKey(), kickMemberAllDTO.getCurrency(), kickMemberAllDTO.getAgentId())); + ApiFCResult apiFCResult = FCClient.kickMemberAll(paramsMap); + if (this.getIsSuccess(apiFCResult.getResult())) { + return Boolean.TRUE; + } else { + throw new ApiException(ErrorCode.KICK_OUT_AILED.getCode()); + } } /** @@ -743,7 +621,7 @@ public class GamesFCServiceImpl implements IGamesService { @Override public Boolean cancelFreeSpin(CancelFreeSpinRequestDTO cancelFreeSpinRequestDTO) { - return null; + return Boolean.FALSE; } @@ -757,66 +635,49 @@ public class GamesFCServiceImpl implements IGamesService { public GameBettingDetails dataBuild(GamesDataBuildDTO gamesDataBuildDTO) { //转化类 - ApiGameBetRecordPageResponseDTO.GameBetRecord resultBean = (ApiGameBetRecordPageResponseDTO.GameBetRecord) gamesDataBuildDTO.getData(); + ApiFCBetRecordResponseDTO.BetRecord resultBean = (ApiFCBetRecordResponseDTO.BetRecord) gamesDataBuildDTO.getData(); - NGPlatforms ngPlatforms = NGPlatforms.getByCode(resultBean.getPlatType()); - if (ObjectUtils.isEmpty(ngPlatforms)) { - return null; - } - String platform = ngPlatforms.getPlatform(); - List games = gameService.selectGameDTOList(GameDTO.builder().gameName(resultBean.getGameName()).platformCode(platform).build()); - if (CollectionUtils.isEmpty(games)) { - return null; - } - Game gamesDataDTO = games.get(0); - GameSecretKeyCurrency currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCodes(NGPlatforms.getAllPlatforms()) - .currency(resultBean.getCurrency()) - .build()); - - Member member = memberService.selectMemberByGameAccount(resultBean.getPlayerId()); + Member member = memberService.selectMemberByGameAccount(resultBean.getAccount()); if (ObjectUtils.isEmpty(member)) { return null; } - GameDTO gameDTO = new GameDTO(); - gameDTO.setPlatformCodes(NGPlatforms.getAllPlatforms()); + List gamesDatas = redisCache.getCacheList(CacheConstants.FC_GAMES); + Map dataDTOMap = gamesDatas.stream().collect(Collectors.toMap(ApiFCGameListResponseDTO.GameDetails::getGameId, e -> e)); + ApiFCGameListResponseDTO.GameDetails gamesDataDTO = dataDTOMap.get(resultBean.getGameID()); - int gameStatus = GameStatus.FLAT.getCode(); - if (BigDecimal.ZERO.compareTo(resultBean.getSettledAmount()) > 0) { + // 判断输赢 + Integer gameStatus = GameStatus.FLAT.getCode(); + if (BigDecimal.ZERO.compareTo(resultBean.getWinlose()) > 0) { gameStatus = GameStatus.FAIL.getCode(); - } else if (BigDecimal.ZERO.compareTo(resultBean.getSettledAmount()) < 0) { + } else if (BigDecimal.ZERO.compareTo(resultBean.getWinlose()) < 0) { gameStatus = GameStatus.WIN.getCode(); } + //数据构造 GameBettingDetails gameBettingDetails = GameBettingDetails.builder() .tenantKey(member.getTenantKey()) //保存我们的币种id - .currencyCode(currencyDTO.getSystemCurrency()) + .currencyCode(gamesDataBuildDTO.getSystemCurrencyCode()) .memberId(member.getId()) - .gameCode(gamesDataDTO.getGameCode()) - .gameType(NGGameType.findSystemByCode(resultBean.getGameType())) - .platformCode(NGPlatforms.getByCode(resultBean.getPlatType()).getPlatform()) - .gameId(gamesDataDTO.getId()) - .gameName(gamesDataDTO.getGameName()) + .gameCode(resultBean.getGameID()) + .gameType(FCGameType.findSystemByCode(resultBean.getGametype())) + .platformCode(GamePlatforms.FC.getCode()) + .gameId(gamesDataDTO.getSystemGameId()) + .gameName(gamesDataDTO.getGameNameOfChinese()) .gameStatus(gameStatus) .gameStatusType(1) - .gameCurrencyCode(resultBean.getCurrency()) - .account(resultBean.getPlayerId()) - .wagersId(resultBean.getGameOrderId()) - .wagersTime(resultBean.getBetTime().getTime()) - .betAmount(resultBean.getBetAmount().abs()) - .payoffTime(resultBean.getLastUpdateTime().getTime()) - .payoffAmount(resultBean.getSettledAmount().abs()) - .settlementTime(resultBean.getLastUpdateTime().getTime()) - .turnover(resultBean.getValidAmount()) - .orderNo(StringUtils.isNotEmpty(resultBean.getRound()) ? String.valueOf(resultBean.getRound()) : null) - .settlementStatus(NGSettlementStatusEnum.fromStatus(resultBean.getStatus()).getCode()) - .round(resultBean.getRound()) - .table(resultBean.getTable()) - .seat(resultBean.getSeat()) - .betContent(resultBean.getBetContent()) + .gameCurrencyCode(gamesDataBuildDTO.getCurrencyCode()) + .account(resultBean.getAccount()) + .wagersId(resultBean.getRecordID()) + .wagersTime(resultBean.getBdate().getTime()) + .betAmount(resultBean.getBet()) + .payoffTime(resultBean.getBdate().getTime()) + .payoffAmount(resultBean.getWinlose().abs()) + .settlementTime(resultBean.getBdate().getTime()) + .turnover(resultBean.getValidBet()) + .settlementStatus(SettlementStatusEnum.COMPLETED.getCode()) .build(); gameBettingDetails.setCreateBy(Constants.SYSTEM); gameBettingDetails.setCreateTime(DateUtils.getNowDate()); @@ -824,33 +685,33 @@ public class GamesFCServiceImpl implements IGamesService { } + /** * 批量插入 * - * @param data 数据 + * @param data 数据 + * @param systemCurrencyCode 系统货币代码 */ - private synchronized void batchInsert(ApiGameBetRecordPageResponseDTO data) { + private synchronized void batchInsert(ApiFCBetRecordResponseDTO data, String systemCurrencyCode, String currencyCode) { List gameBettingDetails = new ArrayList<>(); - List wagersIds = new ArrayList<>(); + List wagersIds = new ArrayList<>(); //数据转化 - for (ApiGameBetRecordPageResponseDTO.GameBetRecord bean : data.getList()) { - GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder().data(bean).build()); + for (ApiFCBetRecordResponseDTO.BetRecord bean : data.getRecords()) { + GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder().data(bean).currencyCode(currencyCode).systemCurrencyCode(systemCurrencyCode).build()); if (!ObjectUtils.isEmpty(bettingDetails)) { bettingDetails.setId(IdUtil.getSnowflakeNextId()); gameBettingDetails.add(bettingDetails); } - wagersIds.add(bean.getGameOrderId()); + wagersIds.add(bean.getRecordID()); } if (!CollectionUtils.isEmpty(gameBettingDetails)) { //查询重复数据id - List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds); + List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds); //用steam流清除list中与wagersIds集合相同的数据 gameBettingDetails = gameBettingDetails.stream() .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) .collect(Collectors.toList()); if (!CollectionUtils.isEmpty(gameBettingDetails)) { - List wagersId = gameBettingDetails.stream().map(GameBettingDetails::getWagersId).collect(Collectors.toList()); - gameBettingDetailsService.deleteGameBettingDetailsByWagersId(wagersId); gameBettingDetailsService.batchInsert(gameBettingDetails); } } diff --git a/ff-game/src/main/java/com/ff/game/api/jili/dto/JILIBetRecordDataResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/jili/dto/JILIBetRecordDataResponseDTO.java index a37c1e1..56cd4ce 100644 --- a/ff-game/src/main/java/com/ff/game/api/jili/dto/JILIBetRecordDataResponseDTO.java +++ b/ff-game/src/main/java/com/ff/game/api/jili/dto/JILIBetRecordDataResponseDTO.java @@ -25,7 +25,7 @@ public class JILIBetRecordDataResponseDTO { * 投注id */ @JsonProperty("WagersId") - private long wagersId; + private String wagersId; /** * 游戏id */ diff --git a/ff-game/src/main/java/com/ff/game/api/jili/service/impl/GamesJILIServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/jili/service/impl/GamesJILIServiceImpl.java index ecc1537..edf1863 100644 --- a/ff-game/src/main/java/com/ff/game/api/jili/service/impl/GamesJILIServiceImpl.java +++ b/ff-game/src/main/java/com/ff/game/api/jili/service/impl/GamesJILIServiceImpl.java @@ -436,6 +436,19 @@ public class GamesJILIServiceImpl implements IGamesService { return Boolean.TRUE; } + + /** + * 按历史时间获取投注记录 + * + * @param betRecordByTimeDTO 按时间dto投注记录 + * @return {@link Boolean } + */ + @Override + public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { + return null; + } + + /** * 赠送免费局数 * @@ -688,7 +701,7 @@ public class GamesJILIServiceImpl implements IGamesService { */ private void batchInsert(JILIBetRecordResponseDTO betRecordJILIResponse) { List gameBettingDetails = new ArrayList<>(); - List wagersIds = new ArrayList<>(); + List wagersIds = new ArrayList<>(); //数据组装 JILIBetRecordResponseDTO.DataBean dataBean = betRecordJILIResponse.getData(); //数据转化 @@ -702,7 +715,7 @@ public class GamesJILIServiceImpl implements IGamesService { } if (!CollectionUtils.isEmpty(gameBettingDetails)) { //查询重复数据id - List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds); + List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds); //用steam流清除list中与wagersIds集合相同的数据 gameBettingDetails = gameBettingDetails.stream() .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) diff --git a/ff-game/src/main/java/com/ff/game/api/ng/service/impl/GamesPGServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/ng/service/impl/GamesPGServiceImpl.java index f6ba994..a966684 100644 --- a/ff-game/src/main/java/com/ff/game/api/ng/service/impl/GamesPGServiceImpl.java +++ b/ff-game/src/main/java/com/ff/game/api/ng/service/impl/GamesPGServiceImpl.java @@ -637,6 +637,16 @@ public class GamesPGServiceImpl implements IGamesService { } } + /** + * 按历史时间获取投注记录 + * + * @param betRecordByTimeDTO 按时间dto投注记录 + * @return {@link Boolean } + */ + @Override + public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { + return null; + } /** @@ -777,7 +787,7 @@ public class GamesPGServiceImpl implements IGamesService { .gameStatusType(1) .gameCurrencyCode(resultBean.getCurrency()) .account(resultBean.getPlayerId()) - .wagersId(resultBean.getGameOrderId()) + .wagersId(String.valueOf(resultBean.getGameOrderId())) .wagersTime(resultBean.getBetTime().getTime()) .betAmount(resultBean.getBetAmount().abs()) .payoffTime(resultBean.getLastUpdateTime().getTime()) @@ -804,7 +814,7 @@ public class GamesPGServiceImpl implements IGamesService { */ private synchronized void batchInsert(ApiGameBetRecordPageResponseDTO data) { List gameBettingDetails = new ArrayList<>(); - List wagersIds = new ArrayList<>(); + List wagersIds = new ArrayList<>(); //数据转化 for (ApiGameBetRecordPageResponseDTO.GameBetRecord bean : data.getList()) { GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder().data(bean).build()); @@ -812,17 +822,17 @@ public class GamesPGServiceImpl implements IGamesService { bettingDetails.setId(IdUtil.getSnowflakeNextId()); gameBettingDetails.add(bettingDetails); } - wagersIds.add(bean.getGameOrderId()); + wagersIds.add(String.valueOf(bean.getGameOrderId())); } if (!CollectionUtils.isEmpty(gameBettingDetails)) { //查询重复数据id - List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds); + List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds); //用steam流清除list中与wagersIds集合相同的数据 gameBettingDetails = gameBettingDetails.stream() .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) .collect(Collectors.toList()); if (!CollectionUtils.isEmpty(gameBettingDetails)) { - List wagersId = gameBettingDetails.stream().map(GameBettingDetails::getWagersId).collect(Collectors.toList()); + List wagersId = gameBettingDetails.stream().map(GameBettingDetails::getWagersId).collect(Collectors.toList()); gameBettingDetailsService.deleteGameBettingDetailsByWagersId(wagersId); gameBettingDetailsService.batchInsert(gameBettingDetails); } diff --git a/ff-game/src/main/java/com/ff/game/api/request/GamesDataBuildDTO.java b/ff-game/src/main/java/com/ff/game/api/request/GamesDataBuildDTO.java index 2c33345..7b87918 100644 --- a/ff-game/src/main/java/com/ff/game/api/request/GamesDataBuildDTO.java +++ b/ff-game/src/main/java/com/ff/game/api/request/GamesDataBuildDTO.java @@ -24,6 +24,15 @@ public class GamesDataBuildDTO */ private Object data; + /** + * 系统货币代码 + */ + private String systemCurrencyCode; + + /** + * 货币代码 + */ + private String currencyCode; } diff --git a/ff-game/src/main/java/com/ff/game/api/request/GetGameDetailRequestDTO.java b/ff-game/src/main/java/com/ff/game/api/request/GetGameDetailRequestDTO.java index 055be35..214fd5e 100644 --- a/ff-game/src/main/java/com/ff/game/api/request/GetGameDetailRequestDTO.java +++ b/ff-game/src/main/java/com/ff/game/api/request/GetGameDetailRequestDTO.java @@ -23,7 +23,7 @@ public class GetGameDetailRequestDTO extends GamesBaseRequestDTO { /** * 投注id */ - private Long wagersId; + private String wagersId; /** * 郎 */ diff --git a/ff-game/src/main/java/com/ff/game/api/xk/service/impl/GamesXKServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/xk/service/impl/GamesXKServiceImpl.java index 6bad116..f402b87 100644 --- a/ff-game/src/main/java/com/ff/game/api/xk/service/impl/GamesXKServiceImpl.java +++ b/ff-game/src/main/java/com/ff/game/api/xk/service/impl/GamesXKServiceImpl.java @@ -444,6 +444,17 @@ public class GamesXKServiceImpl implements IGamesService { } + /** + * 按历史时间获取投注记录 + * + * @param betRecordByTimeDTO 按时间dto投注记录 + * @return {@link Boolean } + */ + @Override + public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { + return null; + } + /** * 赠送免费局数 * @@ -532,7 +543,7 @@ public class GamesXKServiceImpl implements IGamesService { */ private void batchInsert(XKBetRecordResponseDTO xkBetRecordResponseDTO) { List gameBettingDetails = new ArrayList<>(); - List wagersIds = new ArrayList<>(); + List wagersIds = new ArrayList<>(); //数据组装 XKBetRecordResponseDTO.DataBean dataBean = xkBetRecordResponseDTO.getData(); //数据转化 @@ -542,11 +553,11 @@ public class GamesXKServiceImpl implements IGamesService { bettingDetails.setId(IdUtil.getSnowflakeNextId()); gameBettingDetails.add(bettingDetails); } - wagersIds.add(bean.getWagersId()); + wagersIds.add(String.valueOf(bean.getWagersId())); } if (!CollectionUtils.isEmpty(gameBettingDetails)) { //查询重复数据id - List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds); + List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds); //用steam流清除list中与wagersIds集合相同的数据 gameBettingDetails = gameBettingDetails.stream() .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) @@ -603,7 +614,7 @@ public class GamesXKServiceImpl implements IGamesService { .gameStatusType(resultBean.getType()) .gameCurrencyCode(resultBean.getAgentId()) .account(String.valueOf(resultBean.getAccount())) - .wagersId(resultBean.getWagersId()) + .wagersId(String.valueOf(resultBean.getWagersId())) .wagersTime(resultBean.getWagersTime()) .betAmount(resultBean.getBetAmount().abs()) .payoffTime(resultBean.getPayoffTime()) diff --git a/ff-game/src/main/java/com/ff/game/domain/GameBettingDetails.java b/ff-game/src/main/java/com/ff/game/domain/GameBettingDetails.java index fe832d8..f384d10 100644 --- a/ff-game/src/main/java/com/ff/game/domain/GameBettingDetails.java +++ b/ff-game/src/main/java/com/ff/game/domain/GameBettingDetails.java @@ -116,8 +116,7 @@ public class GameBettingDetails extends BaseEntity /** 游戏注单唯一值 */ @Excel(name = "游戏注单唯一值") - @JsonSerialize(using = ToStringSerializer.class) - private Long wagersId; + private String wagersId; /** 投注时间 (Unix 时间戳) */ @Excel(name = "投注时间 (Unix 时间戳)") diff --git a/ff-game/src/main/java/com/ff/game/domain/GamePlatform.java b/ff-game/src/main/java/com/ff/game/domain/GamePlatform.java index 03e00c6..2d2ee66 100644 --- a/ff-game/src/main/java/com/ff/game/domain/GamePlatform.java +++ b/ff-game/src/main/java/com/ff/game/domain/GamePlatform.java @@ -36,7 +36,7 @@ public class GamePlatform extends BaseEntity @Excel(name = "平台编码") private String platformCode; - /** 平台类型 ff_game_type 字典 */ + /** 平台类型 ff_game_platform_type 字典 */ @Excel(name = "平台类型 ff_game_platform_type 字典") private Integer platformType; diff --git a/ff-game/src/main/java/com/ff/game/mapper/GameBettingDetailsMapper.java b/ff-game/src/main/java/com/ff/game/mapper/GameBettingDetailsMapper.java index b36844a..a5ca8cb 100644 --- a/ff-game/src/main/java/com/ff/game/mapper/GameBettingDetailsMapper.java +++ b/ff-game/src/main/java/com/ff/game/mapper/GameBettingDetailsMapper.java @@ -29,7 +29,7 @@ public interface GameBettingDetailsMapper * @param wagersIds 投注ID * @return {@link List }<{@link Long }> */ - List selectGameBettingDetailsByWagersId(@Param("wagersIds") List wagersIds); + List selectGameBettingDetailsByWagersId(@Param("wagersIds") List wagersIds); /** @@ -87,5 +87,5 @@ public interface GameBettingDetailsMapper * @param wagersIds 投注id * @return int */ - int deleteGameBettingDetailsByWagersId(@Param("wagersIds") List wagersIds); + int deleteGameBettingDetailsByWagersId(@Param("wagersIds") List wagersIds); } diff --git a/ff-game/src/main/java/com/ff/game/service/IGameBettingDetailsService.java b/ff-game/src/main/java/com/ff/game/service/IGameBettingDetailsService.java index 3e3b6c3..7f7135d 100644 --- a/ff-game/src/main/java/com/ff/game/service/IGameBettingDetailsService.java +++ b/ff-game/src/main/java/com/ff/game/service/IGameBettingDetailsService.java @@ -29,7 +29,7 @@ public interface IGameBettingDetailsService * @param wagersIds 投注ID * @return {@link List }<{@link Long }> */ - List selectGameBettingDetailsByWagersId(List wagersIds); + List selectGameBettingDetailsByWagersId(List wagersIds); @@ -89,5 +89,5 @@ public interface IGameBettingDetailsService * @param wagersId 投注id * @return int */ - int deleteGameBettingDetailsByWagersId(List wagersId); + int deleteGameBettingDetailsByWagersId(List wagersId); } diff --git a/ff-game/src/main/java/com/ff/game/service/impl/GameBettingDetailsServiceImpl.java b/ff-game/src/main/java/com/ff/game/service/impl/GameBettingDetailsServiceImpl.java index 8dd5b2c..2c41c68 100644 --- a/ff-game/src/main/java/com/ff/game/service/impl/GameBettingDetailsServiceImpl.java +++ b/ff-game/src/main/java/com/ff/game/service/impl/GameBettingDetailsServiceImpl.java @@ -43,7 +43,7 @@ public class GameBettingDetailsServiceImpl implements IGameBettingDetailsService * @return {@link List }<{@link Long }> */ @Override - public List selectGameBettingDetailsByWagersId(List wagersIds) { + public List selectGameBettingDetailsByWagersId(List wagersIds) { return gameBettingDetailsMapper.selectGameBettingDetailsByWagersId(wagersIds); } @@ -128,7 +128,7 @@ public class GameBettingDetailsServiceImpl implements IGameBettingDetailsService * @return int */ @Override - public int deleteGameBettingDetailsByWagersId(List wagersId) { + public int deleteGameBettingDetailsByWagersId(List wagersId) { return gameBettingDetailsMapper.deleteGameBettingDetailsByWagersId(wagersId); } } diff --git a/ff-game/src/main/java/com/ff/quartz/task/GameTask.java b/ff-game/src/main/java/com/ff/quartz/task/GameTask.java index b92e41e..6675502 100644 --- a/ff-game/src/main/java/com/ff/quartz/task/GameTask.java +++ b/ff-game/src/main/java/com/ff/quartz/task/GameTask.java @@ -5,6 +5,7 @@ import com.ff.base.core.redis.RedisCache; import com.ff.base.datasource.DynamicDataSourceContextHolder; import com.ff.base.enums.GamePlatforms; import com.ff.base.enums.NGPlatforms; +import com.ff.base.enums.PlatformType; import com.ff.base.enums.StatusType; import com.ff.base.utils.DateUtils; import com.ff.game.api.IGamesService; @@ -91,7 +92,8 @@ public class GameTask { for (String gameKey : gamesService.keySet()) { String platformCode = gameKey.replace(Constants.SERVICE, ""); - if (NGPlatforms.exists(platformCode)) { + //特殊的平台跳过 + if (NGPlatforms.exists(platformCode)|| GamePlatforms.FC.getInfo().equals(platformCode)) { continue; } @@ -120,6 +122,94 @@ public class GameTask { } + /** + * 插入游戏cfbetting详细信息 + */ + public void insertGameCFBettingDetails(Integer backTime) { + + + try { + //捞取指定分钟前的数据 + Long startTime = DateUtils.addOrSubtractMinutes(DateUtils.getNowDate(), backTime); + Long endTime = DateUtils.getNowDate(); + + for (String gameKey : gamesService.keySet()) { + String platformCode = gameKey.replace(Constants.SERVICE, ""); + //不是特殊的平台跳过 + if (!GamePlatforms.FC.getInfo().equals(platformCode)) { + continue; + } + List gameSecretKeys = gameSecretKeyService.selectGameSecretKeyList(GameSecretKey.builder().platform(platformCode).build()); + for (GameSecretKey gameSecretKey : gameSecretKeys) { + try { + gamesService.get(gameKey).getGameList(GamesBaseRequestDTO.builder() + .agentId(gameSecretKey.getCode()) + .agentKey(gameSecretKey.getKey()) + .build()); + BetRecordByTimeDTO betRecordByTimeDTO = new BetRecordByTimeDTO(); + betRecordByTimeDTO.setGamePlatform(gameSecretKey.getPlatform()); + betRecordByTimeDTO.setStartTime(startTime); + betRecordByTimeDTO.setEndTime(endTime); + betRecordByTimeDTO.setPage(1); + betRecordByTimeDTO.setPageLimit(1000); + betRecordByTimeDTO.setAgentId(gameSecretKey.getCode()); + betRecordByTimeDTO.setAgentKey(gameSecretKey.getKey()); + gamesService.get(gameKey).getBetRecordByTime(betRecordByTimeDTO); + } catch (Exception e) { + log.error("查询 平台 {} 投注记录失败,错误信息 {}", gameSecretKey.getCode(), e); + } + } + + } + } catch (Exception e) { + log.error("查询 FC 投注记录失败,错误信息 {}", e); + + } + + } + + /** + * 插入历史游戏投注详细信息 部分平台使用 + * + * @param backTime 返回时间 + */ + public void insertHistoryGameBettingDetails(Integer backTime) { + + //捞取指定分钟前的数据 + Long startTime = DateUtils.addOrSubtractMinutes(DateUtils.getNowDate(), backTime); + Long endTime = DateUtils.getNowDate(); + + + for (String gameKey : gamesService.keySet()) { + String platformCode = gameKey.replace(Constants.SERVICE, ""); + + List gameSecretKeys = gameSecretKeyService.selectGameSecretKeyList(GameSecretKey.builder().platform(platformCode).build()); + for (GameSecretKey gameSecretKey : gameSecretKeys) { + try { + gamesService.get(gameKey).getGameList(GamesBaseRequestDTO.builder() + .agentId(gameSecretKey.getCode()) + .agentKey(gameSecretKey.getKey()) + .build()); + BetRecordByTimeDTO betRecordByTimeDTO = new BetRecordByTimeDTO(); + betRecordByTimeDTO.setGamePlatform(gameSecretKey.getPlatform()); + betRecordByTimeDTO.setStartTime(startTime); + betRecordByTimeDTO.setEndTime(endTime); + betRecordByTimeDTO.setPage(1); + betRecordByTimeDTO.setPageLimit(1000); + betRecordByTimeDTO.setAgentId(gameSecretKey.getCode()); + betRecordByTimeDTO.setAgentKey(gameSecretKey.getKey()); + gamesService.get(gameKey).getBetRecordByHistoryTime(betRecordByTimeDTO); + } catch (Exception e) { + log.error("查询 平台 {} 投注记录失败,错误信息 {}", gameSecretKey.getCode(), e); + } + } + + } + + } + + + /** * 插入游戏ngbetting详细信息 */ diff --git a/ff-game/src/main/resources/mapper/game/GameBettingDetailsMapper.xml b/ff-game/src/main/resources/mapper/game/GameBettingDetailsMapper.xml index 290a6c2..9600ffc 100644 --- a/ff-game/src/main/resources/mapper/game/GameBettingDetailsMapper.xml +++ b/ff-game/src/main/resources/mapper/game/GameBettingDetailsMapper.xml @@ -89,7 +89,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select wagers_id from ff_game_betting_details where wagers_id in