package gamemanagement import ( "strconv" "strings" gamev1 "hyapp.local/api/proto/game/v1" ) type platformDTO struct { AppCode string `json:"appCode"` PlatformCode string `json:"platformCode"` PlatformName string `json:"platformName"` Status string `json:"status"` APIBaseURL string `json:"apiBaseUrl"` // adapterType 决定服务端按哪家厂商协议拼启动 URL 和处理回调。 AdapterType string `json:"adapterType"` // callbackSecret 是后台配置页可见的厂商 key/AppSecret;只对有 game:view 权限的管理员返回。 CallbackSecret string `json:"callbackSecret"` CallbackSecretSet bool `json:"callbackSecretSet"` CallbackIPWhitelist []string `json:"callbackIpWhitelist"` // adapterConfigJson 承载 uid_mode/default_lang/token_ttl_seconds 等可热更新配置。 AdapterConfigJSON string `json:"adapterConfigJson"` SortOrder int32 `json:"sortOrder"` CreatedAtMS int64 `json:"createdAtMs"` UpdatedAtMS int64 `json:"updatedAtMs"` } type catalogDTO struct { AppCode string `json:"appCode"` GameID string `json:"gameId"` PlatformCode string `json:"platformCode"` ProviderGameID string `json:"providerGameId"` GameName string `json:"gameName"` Category string `json:"category"` IconURL string `json:"iconUrl"` CoverURL string `json:"coverUrl"` // launchUrl 只在厂商列表预览时返回,正式目录仍由 platform.adapterConfigJson.game_urls 按 providerGameId 解析。 LaunchURL string `json:"launchUrl,omitempty"` LaunchMode string `json:"launchMode"` Orientation string `json:"orientation"` SafeHeight int32 `json:"safeHeight"` MinCoin int64 `json:"minCoin"` Status string `json:"status"` SortOrder int32 `json:"sortOrder"` Tags []string `json:"tags"` CreatedAtMS int64 `json:"createdAtMs"` UpdatedAtMS int64 `json:"updatedAtMs"` } type diceConfigDTO struct { AppCode string `json:"appCode"` GameID string `json:"gameId"` Status string `json:"status"` StakeOptions []diceStakeDTO `json:"stakeOptions"` FeeBPS int32 `json:"feeBps"` PoolBPS int32 `json:"poolBps"` MinPlayers int32 `json:"minPlayers"` MaxPlayers int32 `json:"maxPlayers"` RobotEnabled bool `json:"robotEnabled"` RobotMatchWaitMS int64 `json:"robotMatchWaitMs"` PoolBalanceCoin int64 `json:"poolBalanceCoin"` CreatedAtMS int64 `json:"createdAtMs"` UpdatedAtMS int64 `json:"updatedAtMs"` } type diceStakeDTO struct { StakeCoin int64 `json:"stakeCoin"` Enabled bool `json:"enabled"` SortOrder int32 `json:"sortOrder"` } type dicePoolAdjustmentDTO struct { AdjustmentID string `json:"adjustmentId"` GameID string `json:"gameId"` StakeCoin int64 `json:"stakeCoin"` AmountCoin int64 `json:"amountCoin"` Direction string `json:"direction"` Reason string `json:"reason"` BalanceAfter int64 `json:"balanceAfter"` CreatedAtMS int64 `json:"createdAtMs"` } type selfGameStakePoolDTO struct { AppCode string `json:"appCode"` GameID string `json:"gameId"` StakeCoin int64 `json:"stakeCoin"` BalanceCoin int64 `json:"balanceCoin"` ReservedCoin int64 `json:"reservedCoin"` AvailableCoin int64 `json:"availableCoin"` TargetBalanceCoin int64 `json:"targetBalanceCoin"` SafeBalanceCoin int64 `json:"safeBalanceCoin"` WarningBalanceCoin int64 `json:"warningBalanceCoin"` DangerBalanceCoin int64 `json:"dangerBalanceCoin"` Status string `json:"status"` PoolLevel string `json:"poolLevel"` RequiredPoolCoin int64 `json:"requiredPoolCoin"` HumanWinCapacity int64 `json:"humanWinCapacity"` BotMatchEnabled bool `json:"botMatchEnabled"` BlackReason string `json:"blackReason"` CreatedAtMS int64 `json:"createdAtMs"` UpdatedAtMS int64 `json:"updatedAtMs"` } type selfGameNewUserPolicyDTO struct { AppCode string `json:"appCode"` GameID string `json:"gameId"` Enabled bool `json:"enabled"` ProtectionRounds int32 `json:"protectionRounds"` ProtectionHours int32 `json:"protectionHours"` MaxStakeCoin int64 `json:"maxStakeCoin"` LifetimeSubsidyQuotaCoin int64 `json:"lifetimeSubsidyQuotaCoin"` Day1SubsidyQuotaCoin int64 `json:"day1SubsidyQuotaCoin"` SingleRoundSubsidyCapCoin int64 `json:"singleRoundSubsidyCapCoin"` StrategyLevel string `json:"strategyLevel"` LoseStreakProtectionEnabled bool `json:"loseStreakProtectionEnabled"` LoseStreakTrigger int32 `json:"loseStreakTrigger"` NormalPhaseTargetWinRatePercent int32 `json:"normalPhaseTargetWinRatePercent"` BlackPoolRobotForceWinEnabled bool `json:"blackPoolRobotForceWinEnabled"` CreatedAtMS int64 `json:"createdAtMs"` UpdatedAtMS int64 `json:"updatedAtMs"` } type diceRobotDTO struct { AppCode string `json:"appCode"` GameID string `json:"gameId"` UserID string `json:"userId"` UserIDNumber int64 `json:"userIdNumber"` ShortID string `json:"shortId"` Nickname string `json:"nickname"` Avatar string `json:"avatar"` Status string `json:"status"` CreatedByAdminID int64 `json:"createdByAdminId"` CreatedAtMS int64 `json:"createdAtMs"` UpdatedAtMS int64 `json:"updatedAtMs"` } type roomRPSConfigDTO struct { AppCode string `json:"appCode"` GameID string `json:"gameId"` Status string `json:"status"` ChallengeTimeoutMS int64 `json:"challengeTimeoutMs"` RevealCountdownMS int64 `json:"revealCountdownMs"` StakeGifts []roomRPSStakeGiftDTO `json:"stakeGifts"` CreatedAtMS int64 `json:"createdAtMs"` UpdatedAtMS int64 `json:"updatedAtMs"` } type roomRPSStakeGiftDTO struct { GiftID string `json:"giftId"` GiftIDNumber int64 `json:"giftIdNumber"` GiftName string `json:"giftName"` GiftIconURL string `json:"giftIconUrl"` GiftAnimationURL string `json:"giftAnimationUrl"` GiftPriceCoin int64 `json:"giftPriceCoin"` Enabled bool `json:"enabled"` SortOrder int32 `json:"sortOrder"` } type roomRPSChallengeDTO struct { AppCode string `json:"appCode"` ChallengeID string `json:"challengeId"` RoomID string `json:"roomId"` RegionID int64 `json:"regionId"` Status string `json:"status"` StakeGiftID string `json:"stakeGiftId"` StakeGiftIDNumber int64 `json:"stakeGiftIdNumber"` StakeCoin int64 `json:"stakeCoin"` Initiator roomRPSPlayerDTO `json:"initiator"` Challenger roomRPSPlayerDTO `json:"challenger"` WinnerUserID string `json:"winnerUserId"` WinnerUserIDNumber int64 `json:"winnerUserIdNumber"` SettlementStatus string `json:"settlementStatus"` FailureReason string `json:"failureReason"` TimeoutAtMS int64 `json:"timeoutAtMs"` RevealAtMS int64 `json:"revealAtMs"` CreatedAtMS int64 `json:"createdAtMs"` MatchedAtMS int64 `json:"matchedAtMs"` SettledAtMS int64 `json:"settledAtMs"` UpdatedAtMS int64 `json:"updatedAtMs"` } type roomRPSPlayerDTO struct { UserID string `json:"userId"` UserIDNumber int64 `json:"userIdNumber"` Gesture string `json:"gesture"` Result string `json:"result"` BalanceAfter int64 `json:"balanceAfter"` JoinedAtMS int64 `json:"joinedAtMs"` } func platformFromProto(item *gamev1.GamePlatform) platformDTO { if item == nil { return platformDTO{} } return platformDTO{ AppCode: item.GetAppCode(), PlatformCode: item.GetPlatformCode(), PlatformName: item.GetPlatformName(), Status: item.GetStatus(), APIBaseURL: item.GetApiBaseUrl(), AdapterType: item.GetAdapterType(), CallbackSecret: item.GetCallbackSecret(), CallbackSecretSet: item.GetCallbackSecretSet(), CallbackIPWhitelist: item.GetCallbackIpWhitelist(), AdapterConfigJSON: item.GetAdapterConfigJson(), SortOrder: item.GetSortOrder(), CreatedAtMS: item.GetCreatedAtMs(), UpdatedAtMS: item.GetUpdatedAtMs(), } } func catalogFromProto(item *gamev1.GameCatalogItem) catalogDTO { if item == nil { return catalogDTO{} } return catalogDTO{ AppCode: item.GetAppCode(), GameID: item.GetGameId(), PlatformCode: item.GetPlatformCode(), ProviderGameID: item.GetProviderGameId(), GameName: item.GetGameName(), Category: item.GetCategory(), IconURL: item.GetIconUrl(), CoverURL: item.GetCoverUrl(), LaunchMode: item.GetLaunchMode(), Orientation: item.GetOrientation(), SafeHeight: item.GetSafeHeight(), MinCoin: item.GetMinCoin(), Status: item.GetStatus(), SortOrder: item.GetSortOrder(), Tags: item.GetTags(), CreatedAtMS: item.GetCreatedAtMs(), UpdatedAtMS: item.GetUpdatedAtMs(), } } func diceConfigFromProto(item *gamev1.DiceConfig) diceConfigDTO { if item == nil { return diceConfigDTO{} } options := make([]diceStakeDTO, 0, len(item.GetStakeOptions())) for _, option := range item.GetStakeOptions() { options = append(options, diceStakeDTO{ StakeCoin: option.GetStakeCoin(), Enabled: option.GetEnabled(), SortOrder: option.GetSortOrder(), }) } return diceConfigDTO{ AppCode: item.GetAppCode(), GameID: item.GetGameId(), Status: item.GetStatus(), StakeOptions: options, FeeBPS: item.GetFeeBps(), PoolBPS: item.GetPoolBps(), MinPlayers: item.GetMinPlayers(), MaxPlayers: item.GetMaxPlayers(), RobotEnabled: item.GetRobotEnabled(), RobotMatchWaitMS: item.GetRobotMatchWaitMs(), PoolBalanceCoin: item.GetPoolBalanceCoin(), CreatedAtMS: item.GetCreatedAtMs(), UpdatedAtMS: item.GetUpdatedAtMs(), } } func dicePoolAdjustmentFromProto(item *gamev1.DicePoolAdjustment) dicePoolAdjustmentDTO { if item == nil { return dicePoolAdjustmentDTO{} } return dicePoolAdjustmentDTO{ AdjustmentID: item.GetAdjustmentId(), GameID: item.GetGameId(), StakeCoin: item.GetStakeCoin(), AmountCoin: item.GetAmountCoin(), Direction: item.GetDirection(), Reason: item.GetReason(), BalanceAfter: item.GetBalanceAfter(), CreatedAtMS: item.GetCreatedAtMs(), } } func selfGameStakePoolFromProto(item *gamev1.SelfGameStakePool) selfGameStakePoolDTO { if item == nil { return selfGameStakePoolDTO{} } return selfGameStakePoolDTO{ AppCode: item.GetAppCode(), GameID: item.GetGameId(), StakeCoin: item.GetStakeCoin(), BalanceCoin: item.GetBalanceCoin(), ReservedCoin: item.GetReservedCoin(), AvailableCoin: item.GetAvailableCoin(), TargetBalanceCoin: item.GetTargetBalanceCoin(), SafeBalanceCoin: item.GetSafeBalanceCoin(), WarningBalanceCoin: item.GetWarningBalanceCoin(), DangerBalanceCoin: item.GetDangerBalanceCoin(), Status: item.GetStatus(), PoolLevel: item.GetPoolLevel(), RequiredPoolCoin: item.GetRequiredPoolCoin(), HumanWinCapacity: item.GetHumanWinCapacity(), BotMatchEnabled: item.GetBotMatchEnabled(), BlackReason: item.GetBlackReason(), CreatedAtMS: item.GetCreatedAtMs(), UpdatedAtMS: item.GetUpdatedAtMs(), } } func selfGameNewUserPolicyFromProto(item *gamev1.SelfGameNewUserPolicy) selfGameNewUserPolicyDTO { if item == nil { return selfGameNewUserPolicyDTO{} } return selfGameNewUserPolicyDTO{ AppCode: item.GetAppCode(), GameID: item.GetGameId(), Enabled: item.GetEnabled(), ProtectionRounds: item.GetProtectionRounds(), ProtectionHours: item.GetProtectionHours(), MaxStakeCoin: item.GetMaxStakeCoin(), LifetimeSubsidyQuotaCoin: item.GetLifetimeSubsidyQuotaCoin(), Day1SubsidyQuotaCoin: item.GetDay1SubsidyQuotaCoin(), SingleRoundSubsidyCapCoin: item.GetSingleRoundSubsidyCapCoin(), StrategyLevel: item.GetStrategyLevel(), LoseStreakProtectionEnabled: item.GetLoseStreakProtectionEnabled(), LoseStreakTrigger: item.GetLoseStreakTrigger(), NormalPhaseTargetWinRatePercent: item.GetNormalPhaseTargetWinRatePercent(), BlackPoolRobotForceWinEnabled: item.GetBlackPoolRobotForceWinEnabled(), CreatedAtMS: item.GetCreatedAtMs(), UpdatedAtMS: item.GetUpdatedAtMs(), } } func diceRobotFromProto(item *gamev1.DiceRobot) diceRobotDTO { if item == nil { return diceRobotDTO{} } return diceRobotDTO{ AppCode: item.GetAppCode(), GameID: item.GetGameId(), UserID: strconv.FormatInt(item.GetUserId(), 10), UserIDNumber: item.GetUserId(), Status: item.GetStatus(), CreatedByAdminID: item.GetCreatedByAdminId(), CreatedAtMS: item.GetCreatedAtMs(), UpdatedAtMS: item.GetUpdatedAtMs(), } } func roomRPSConfigFromProto(item *gamev1.RoomRPSConfig) roomRPSConfigDTO { if item == nil { return roomRPSConfigDTO{} } gifts := make([]roomRPSStakeGiftDTO, 0, len(item.GetStakeGifts())) for _, gift := range item.GetStakeGifts() { // 礼物详情由 game-service 结合礼物配置补齐;admin-server 只保持展示字段和 ID 双写,不重新查礼物表。 gifts = append(gifts, roomRPSStakeGiftDTO{ GiftID: roomRPSStakeGiftIDFromProto(gift), GiftIDNumber: gift.GetGiftId(), GiftName: gift.GetGiftName(), GiftIconURL: gift.GetGiftIconUrl(), GiftAnimationURL: gift.GetGiftAnimationUrl(), GiftPriceCoin: gift.GetGiftPriceCoin(), Enabled: gift.GetEnabled(), SortOrder: gift.GetSortOrder(), }) } // DTO 只做 proto 到后台 JSON 的字段命名转换;配置默认值和合法性已经在 game-service/admin request 层处理。 return roomRPSConfigDTO{ AppCode: item.GetAppCode(), GameID: item.GetGameId(), Status: item.GetStatus(), ChallengeTimeoutMS: item.GetChallengeTimeoutMs(), RevealCountdownMS: item.GetRevealCountdownMs(), StakeGifts: gifts, CreatedAtMS: item.GetCreatedAtMs(), UpdatedAtMS: item.GetUpdatedAtMs(), } } func roomRPSChallengeFromProto(item *gamev1.RoomRPSChallenge) roomRPSChallengeDTO { if item == nil { return roomRPSChallengeDTO{} } // 后台订单页要同时服务浏览器展示和问题排查:ID 用字符串保护前端精度,也保留 number 字段便于排序、复制和接口调试。 // 胜负、结算状态、失败原因全部按 game-service 返回值展示,admin-server 不根据手势重新计算,避免和真实结算事实分叉。 return roomRPSChallengeDTO{ AppCode: item.GetAppCode(), ChallengeID: item.GetChallengeId(), RoomID: item.GetRoomId(), RegionID: item.GetRegionId(), Status: item.GetStatus(), StakeGiftID: roomRPSChallengeStakeGiftIDFromProto(item), StakeGiftIDNumber: item.GetStakeGiftId(), StakeCoin: item.GetStakeCoin(), Initiator: roomRPSPlayerFromProto(item.GetInitiator()), Challenger: roomRPSPlayerFromProto(item.GetChallenger()), WinnerUserID: strconv.FormatInt(item.GetWinnerUserId(), 10), WinnerUserIDNumber: item.GetWinnerUserId(), SettlementStatus: item.GetSettlementStatus(), FailureReason: item.GetFailureReason(), TimeoutAtMS: item.GetTimeoutAtMs(), RevealAtMS: item.GetRevealAtMs(), CreatedAtMS: item.GetCreatedAtMs(), MatchedAtMS: item.GetMatchedAtMs(), SettledAtMS: item.GetSettledAtMs(), UpdatedAtMS: item.GetUpdatedAtMs(), } } func roomRPSStakeGiftIDFromProto(gift *gamev1.RoomRPSStakeGift) string { if gift == nil { return "" } if text := strings.TrimSpace(gift.GetGiftIdText()); text != "" { return text } if gift.GetGiftId() > 0 { return strconv.FormatInt(gift.GetGiftId(), 10) } return "" } func roomRPSChallengeStakeGiftIDFromProto(item *gamev1.RoomRPSChallenge) string { if item == nil { return "" } if text := strings.TrimSpace(item.GetStakeGiftIdText()); text != "" { return text } if item.GetStakeGiftId() > 0 { return strconv.FormatInt(item.GetStakeGiftId(), 10) } return "" } func roomRPSPlayerFromProto(item *gamev1.RoomRPSPlayer) roomRPSPlayerDTO { if item == nil { return roomRPSPlayerDTO{} } // 管理后台玩家 DTO 只展示订单内快照字段;头像昵称属于 App/IM 展示增强,后台如需用户资料应走独立用户查询。 return roomRPSPlayerDTO{ UserID: strconv.FormatInt(item.GetUserId(), 10), UserIDNumber: item.GetUserId(), Gesture: item.GetGesture(), Result: item.GetResult(), BalanceAfter: item.GetBalanceAfter(), JoinedAtMS: item.GetJoinedAtMs(), } }