import { Repeat2, Settings, Trash2 } from 'lucide-react' import chip1 from '@/assets/game/chip1.webp' import chip2 from '@/assets/game/chip2.webp' import chip3 from '@/assets/game/chip3.webp' import chip4 from '@/assets/game/chip4.webp' import chip5 from '@/assets/game/chip5.webp' import chip6 from '@/assets/game/chip6.webp' import controlLeft from '@/assets/game/control-left.webp' import controlMid from '@/assets/game/control-mid.webp' import controlRight from '@/assets/game/control-right.webp' import hallMusic from '@/assets/music/hall-music.mp3' import type { DepositWithdrawConfig } from '@/type' /** @description 游戏棋盘行数。 */ export const GAME_GRID_ROWS = 6 /** @description 游戏棋盘列数。 */ export const GAME_GRID_COLUMNS = 6 /** @description 游戏棋盘总格子数。 */ export const GAME_TOTAL_CELLS = GAME_GRID_ROWS * GAME_GRID_COLUMNS /** @description 游戏回合阶段枚举。 */ export const ROUND_PHASES = [ 'waiting', 'betting', 'locked', 'revealing', 'settled', ] as const /** @description 游戏格子在前端视图中的状态枚举。 */ export const CELL_STATUSES = [ 'idle', 'betting', 'selected', 'locked', 'won', 'lost', ] as const /** @description 游戏实时连接状态枚举。 */ export const CONNECTION_STATUSES = [ 'idle', 'connecting', 'connected', 'reconnecting', 'disconnected', ] as const /** @description 游戏实时连接传输方式枚举。 */ export const CONNECTION_TRANSPORTS = [ 'websocket', 'polling', 'offline', ] as const /** @description 游戏公告视觉语义枚举。 */ export const ANNOUNCEMENT_TONES = [ 'info', 'success', 'warning', 'critical', ] as const /** @description 下注来源枚举,用于区分本地未提交与服务端已确认下注。 */ export const BET_SOURCES = ['local', 'server'] as const /** @description 走势方向枚举。 */ export const TREND_DIRECTIONS = ['rising', 'steady', 'falling'] as const /** @description 默认筹码颜色,用于后端未返回筹码颜色时兜底。 */ export const DEFAULT_GAME_CHIP_COLORS = [ '#1D4ED8', '#0F766E', '#B45309', '#B91C1C', '#7C3AED', '#111827', ] as const /** @description 默认选中的筹码 ID。 */ export const DEFAULT_ACTIVE_CHIP_ID = 'chip-5' /** @description 游戏公告默认存活时间,单位为毫秒。 */ export const DEFAULT_ANNOUNCEMENT_TTL_MS = 90_000 /** @description 游戏最近开奖记录最大保留条数。 */ export const GAME_RECENT_HISTORY_LIMIT = 12 /** @description 单轮下注最多允许选择的格子数。 */ export const GAME_MAX_SELECTION_CELLS = 5 /** @description 筹码 ID 与图片资源的配置列表。 */ export const CHIP_IMAGE_OPTIONS = [ { id: 'chip-1', src: chip1 }, { id: 'chip-2', src: chip2 }, { id: 'chip-3', src: chip3 }, { id: 'chip-4', src: chip4 }, { id: 'chip-5', src: chip5 }, { id: 'chip-6', src: chip6 }, ] /** @description 按筹码 ID 快速取得筹码图片资源的映射表。 */ export const CHIP_IMAGE_MAP = new Map( CHIP_IMAGE_OPTIONS.map((chip) => [chip.id, chip.src] as const), ) /** @description 默认筹码面额与筹码 ID 配置。 */ export const DEFAULT_CHIP_AMOUNTS = [ { amount: 1, id: 'chip-1' }, { amount: 5, id: 'chip-2' }, { amount: 10, id: 'chip-3' }, { amount: 25, id: 'chip-4' }, { amount: 50, id: 'chip-5' }, { amount: 100, id: 'chip-6' }, ] as const /** @description 游戏控制栏动作按钮配置。 */ export const ACTION_OPTIONS = [ { id: 'clear', labelKey: 'gameDesktop.control.actions.clear', Icon: Trash2, bg: controlLeft, }, { id: 'repeat', labelKey: 'gameDesktop.control.actions.repeat', Icon: Repeat2, bg: controlMid, }, { id: 'auto-spin', labelKey: 'gameDesktop.control.actions.auto-spin', Icon: Settings, bg: controlRight, }, ] /** @description 游戏业务接口地址集合。 */ export const GAME_API_ENDPOINTS = { announcements: 'game/announcements', betMyOrders: 'api/game/betMyOrders', betPlaceLegacy: 'api/game/betPlace', bootstrap: 'game/bootstrap', lobbyInit: 'api/game/lobbyInit', noticeConfirm: 'api/notice/noticeConfirm', noticeDetail: 'api/notice/noticeDetail', noticeList: 'api/notice/noticeList', periodHistory: 'api/game/periodHistory', placeBet: 'api/game/placeBet', roundFeed: 'game/round-feed', } as const /** @description 充值提现业务接口地址集合。 */ export const FINANCE_API_ENDPOINTS = { depositCreate: 'api/finance/depositCreate', depositList: 'api/finance/depositList', depositTierList: 'api/finance/depositTierList', depositWithdrawConfig: 'api/finance/depositWithdrawConfig', legacyCashierConfig: 'api/finance/cashierConfig', walletRecordList: 'api/wallet/recordList', withdrawCreate: 'api/finance/withdrawCreate', withdrawList: 'api/finance/withdrawList', } as const /** @description 游戏实时接口不可用时的兜底轮询间隔,单位为毫秒。 */ export const FALLBACK_POLL_INTERVAL_MS = 10_000 /** @description 游戏实时通信主题集合。 */ export const GAME_SOCKET_TOPICS = { // 对局状态心跳。每秒推送当前期号、状态、倒计时、runtime_enabled 等。 periodTick: 'period.tick', // 本期封盘通知。用于前端立即停止下注。 periodLocked: 'period.locked', // 本期开奖通知。用于同步开奖号码、所属期号等阶段结果。 periodOpened: 'period.opened', // 本期派彩完成通知。用于结算阶段同步。 periodPayout: 'period.payout', // 当前玩家中奖通知。用于前端显示大奖/小奖开奖 Lottie 动画与中奖金额。 betWin: 'bet.win', // 当前玩家连胜与赔率信息。通常在结算后或演示帧刷新。 userStreak: 'user.streak', // 下注成功通知。仅当前用户可见,通常伴随扣款结果。 betAccepted: 'bet.accepted', // 余额变化通知。充值、下注、派彩都会走这条流。 walletChanged: 'wallet.changed', // 自动托管进度通知。包含托管开关、执行状态等。 autoSpinProgress: 'auto.spin.progress', // 全站大奖命中播报。用于公告栏展示中奖消息。 jackpotHit: 'jackpot.hit', // 后台实时页全量快照。仅 admin live 页面使用,当前 H5 前台不订阅。 adminLiveSnapshot: 'admin.live.snapshot', // 后台开奖结果通知。仅 admin live 页面使用,当前 H5 前台不订阅。 adminLiveOpened: 'admin.live.opened', } as const /** @description 游戏实时通信主题白名单。 */ export const GAME_SOCKET_TOPIC_VALUES = new Set( Object.values(GAME_SOCKET_TOPICS), ) /** @description 当前 H5 游戏页实际订阅的玩家侧实时主题。 */ export const PLAYER_SOCKET_TOPICS = [ GAME_SOCKET_TOPICS.periodTick, GAME_SOCKET_TOPICS.userStreak, GAME_SOCKET_TOPICS.periodOpened, GAME_SOCKET_TOPICS.periodLocked, GAME_SOCKET_TOPICS.periodPayout, GAME_SOCKET_TOPICS.betAccepted, GAME_SOCKET_TOPICS.walletChanged, GAME_SOCKET_TOPICS.autoSpinProgress, GAME_SOCKET_TOPICS.jackpotHit, GAME_SOCKET_TOPICS.betWin, ] as const /** @description 游戏实时连接延迟断开的等待时间,单位为毫秒。 */ export const SOCKET_DISCONNECT_DELAY_MS = 150 /** @description 游戏实时连接重连退避的最大等待时间,单位为毫秒。 */ export const MAX_RECONNECT_DELAY_MS = 10_000 /** @description 游戏实时连接延迟探测间隔,单位为毫秒。 */ export const LATENCY_PROBE_INTERVAL_MS = 3_000 /** @description 游戏实时连接延迟探测超时时间,单位为毫秒。 */ export const LATENCY_PROBE_TIMEOUT_MS = 10_000 /** @description 桌面端中奖动画遮罩展示时长,单位为毫秒。 */ export const REWARD_OVERLAY_DURATION_MS = 5_000 /** @description 入场公告确认时间戳在 localStorage 中使用的基础存储键。 */ export const ENTRY_NOTICE_LAST_CONFIRMED_AT_KEY = '36-character-flower:entry-notice:last-confirmed-at' /** @description 已登录用户重复展示入场公告的最小间隔,单位为毫秒。 */ export const ENTRY_NOTICE_CONFIRM_INTERVAL_MS = 24 * 60 * 60 * 1000 /** @description 游戏投注记录每页加载条数。 */ export const GAME_HISTORY_PAGE_SIZE = 20 /** @description 列表类接口默认分页条数,用于财务、钱包、公告、投注单等列表。 */ export const DEFAULT_LIST_PAGE_SIZE = 20 /** @description 财务配置类查询(充值提现配置、充值档位)缓存新鲜时间,单位为毫秒。 */ export const FINANCE_CONFIG_QUERY_STALE_TIME_MS = 5 * 60 * 1000 /** @description 提现表单默认币种代码。 */ export const DEFAULT_CURRENCY_CODE = 'MYR' /** @description 自动托管「单次中奖超过」停止规则的默认阈值。 */ export const AUTO_HOSTING_DEFAULT_SINGLE_WIN_THRESHOLD = 50_000 /** @description 全站大奖播报最大保留条数。 */ export const MAX_JACKPOT_BROADCAST_COUNT = 20 /** @description 实时连接延迟信号「优」阈值,单位为毫秒。 */ export const CONNECTION_LATENCY_GOOD_MS = 80 /** @description 实时连接延迟信号「良」阈值,同时用于判定连接是否健康,单位为毫秒。 */ export const CONNECTION_LATENCY_FAIR_MS = 150 /** @description 实时连接延迟信号「中」阈值,单位为毫秒。 */ export const CONNECTION_LATENCY_POOR_MS = 300 /** @description 提现收款邮箱校验正则。 */ export const WITHDRAW_EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ /** @description 提现收款手机号校验正则,6-20 位数字,允许前导 +。 */ export const WITHDRAW_PHONE_PATTERN = /^\+?\d{6,20}$/ /** @description 提现页快捷法币金额选项。 */ export const QUICK_FIAT_AMOUNTS = [3, 30, 50, 100, 200, 500] as const /** @description 后端提现配置缺失时使用的默认提现配置。 */ export const DEFAULT_WITHDRAW_CONFIG: DepositWithdrawConfig = { currencies: [ { code: 'MYR', depositCoinsPerFiat: '100', depositCoinsPerFiatValue: 100, label: 'MYR', withdrawCoinsPerFiat: '100', withdrawCoinsPerFiatValue: 100, }, ], payChannels: [], platformCoinLabel: '钻石', rates: [ { currency: 'MYR', diamondsPerFiatUnit: '100', diamondsPerFiatUnitValue: 100, }, ], withdraw: { banks: [], feeNote: 'RM10 - RM99.99 之间的交易将收取最低RM 1的提现手续费', minBank: '10', minEwallet: '10', processingNote: '30s即可到账', rateHint: '汇率为参考价格,实际以提现时为准。', rateMode: 'fixed', }, } /** @description 游戏状态栏各回合阶段的翻译 key 与颜色样式配置。 */ export const PHASE_META = { betting: { descriptionKey: 'gameDesktop.status.phase.betting.description', labelKey: 'gameDesktop.status.phase.betting.label', toneClassName: 'text-[#78FF7F]', }, locked: { descriptionKey: 'gameDesktop.status.phase.locked.description', labelKey: 'gameDesktop.status.phase.locked.label', toneClassName: 'text-[#FFE375]', }, revealing: { descriptionKey: 'gameDesktop.status.phase.revealing.description', labelKey: 'gameDesktop.status.phase.revealing.label', toneClassName: 'text-[#57E8FF]', }, settled: { descriptionKey: 'gameDesktop.status.phase.settled.description', labelKey: 'gameDesktop.status.phase.settled.label', toneClassName: 'text-[#FF9C6B]', }, waiting: { descriptionKey: 'gameDesktop.status.phase.waiting.description', labelKey: 'gameDesktop.status.phase.waiting.label', toneClassName: 'text-[#A7B6C7]', }, } as const /** @description 游戏音频资源 ID 枚举。 */ export type AudioAssetId = 'hall-bgm' /** @description 游戏音频资源配置结构。 */ export type AudioAssetDefinition = { id: AudioAssetId loop?: boolean src: string volume?: number } /** @description 游戏全局音频资源配置列表。 */ export const AUDIO_ASSET_DEFINITIONS: AudioAssetDefinition[] = [ { id: 'hall-bgm', src: hallMusic, loop: true, volume: 1, }, ]