- 实现了完整的登录注册认证流程,包括密码验证和用户资料获取 - 集成了JWT令牌管理和自动刷新机制,支持设备ID生成和管理 - 添加了WebSocket连接配置和API基础URL环境变量设置 - 实现了API客户端的请求拦截器,包括令牌验证和错误处理逻辑 - 集成了MD5加密和认证令牌缓存机制,提升安全性 - 添加了多语言国际化支持,包括英语、中文、马来语和印尼语 - 实现了认证状态管理和本地存储持久化功能 - 添加了表单验证schema和错误处理机制,增强用户体验
159 lines
4.5 KiB
TypeScript
159 lines
4.5 KiB
TypeScript
import { DEFAULT_CHIP_AMOUNTS } from '@/constants'
|
|
import {
|
|
DEFAULT_ACTIVE_CHIP_ID,
|
|
DEFAULT_ANNOUNCEMENT_TTL_MS,
|
|
DEFAULT_GAME_CHIP_COLORS,
|
|
GAME_GRID_COLUMNS,
|
|
GAME_MAX_SELECTION_CELLS,
|
|
GAME_TOTAL_CELLS,
|
|
} from './constants'
|
|
import { deriveTrendEntries, getRoundCountdownMs } from './selectors'
|
|
import type {
|
|
AnnouncementState,
|
|
BetSelection,
|
|
Chip,
|
|
ConnectionState,
|
|
DashboardState,
|
|
GameBootstrapSnapshot,
|
|
GameCell,
|
|
HistoryEntry,
|
|
RoundSnapshot,
|
|
} from './types'
|
|
|
|
const MOCK_GAME_BASE_TIME = '2026-04-23T12:00:00.000Z'
|
|
const MOCK_HISTORY_RESULTS = [8, 12, 12, 4, 31, 9, 17, 22, 17, 5, 28, 13]
|
|
|
|
function offsetIso(baseIso: string, offsetMs: number) {
|
|
return new Date(Date.parse(baseIso) + offsetMs).toISOString()
|
|
}
|
|
|
|
export function createGameCells() {
|
|
return Array.from({ length: GAME_TOTAL_CELLS }, (_, index) => {
|
|
const id = index + 1
|
|
|
|
return {
|
|
column: (index % GAME_GRID_COLUMNS) + 1,
|
|
id,
|
|
label: String(id).padStart(2, '0'),
|
|
odds: 36,
|
|
row: Math.floor(index / GAME_GRID_COLUMNS) + 1,
|
|
} satisfies GameCell
|
|
})
|
|
}
|
|
|
|
export function createDefaultChips() {
|
|
return DEFAULT_CHIP_AMOUNTS.map((chip, index) => ({
|
|
amount: chip.amount,
|
|
color: DEFAULT_GAME_CHIP_COLORS[index],
|
|
id: chip.id,
|
|
isDefault: chip.id === DEFAULT_ACTIVE_CHIP_ID,
|
|
label: chip.amount >= 100 ? `${chip.amount / 100}x` : String(chip.amount),
|
|
})) satisfies Chip[]
|
|
}
|
|
|
|
export function createMockHistoryEntries(baseIso = MOCK_GAME_BASE_TIME) {
|
|
return MOCK_HISTORY_RESULTS.map((winningCellId, index) => {
|
|
const settledAt = offsetIso(baseIso, -(index + 1) * 30_000)
|
|
|
|
return {
|
|
payoutMultiplier: 36,
|
|
roundId: `round-${6200 - index}`,
|
|
settledAt,
|
|
totalPoolAmount: 12_000 + index * 850,
|
|
winningCellId,
|
|
} satisfies HistoryEntry
|
|
})
|
|
}
|
|
|
|
export function createMockRoundSnapshot(baseIso = MOCK_GAME_BASE_TIME) {
|
|
return {
|
|
bettingClosesAt: offsetIso(baseIso, 18_000),
|
|
id: 'round-6201',
|
|
phase: 'betting',
|
|
revealingAt: offsetIso(baseIso, 24_000),
|
|
settledAt: offsetIso(baseIso, 30_000),
|
|
startedAt: baseIso,
|
|
winningCellId: null,
|
|
} satisfies RoundSnapshot
|
|
}
|
|
|
|
export function createMockBetSelections() {
|
|
return [] satisfies BetSelection[]
|
|
}
|
|
|
|
export function createMockAnnouncementState(baseIso = MOCK_GAME_BASE_TIME) {
|
|
return {
|
|
activeAnnouncementId: 'announcement-maintenance',
|
|
items: [
|
|
{
|
|
createdAt: offsetIso(baseIso, -20_000),
|
|
expiresAt: offsetIso(baseIso, DEFAULT_ANNOUNCEMENT_TTL_MS),
|
|
id: 'announcement-maintenance',
|
|
isPinned: true,
|
|
isRead: false,
|
|
message: 'Realtime sync upgrades finish after the current cycle.',
|
|
title: 'Table maintenance',
|
|
tone: 'warning',
|
|
},
|
|
{
|
|
createdAt: offsetIso(baseIso, -55_000),
|
|
expiresAt: null,
|
|
id: 'announcement-promo',
|
|
isRead: true,
|
|
message: 'Warm-up round rebates are credited every 5 settled rounds.',
|
|
title: 'Reward window live',
|
|
tone: 'success',
|
|
},
|
|
],
|
|
lastUpdatedAt: offsetIso(baseIso, -10_000),
|
|
} satisfies AnnouncementState
|
|
}
|
|
|
|
export function createMockDashboardState(
|
|
baseIso = MOCK_GAME_BASE_TIME,
|
|
round = createMockRoundSnapshot(baseIso),
|
|
history = createMockHistoryEntries(baseIso),
|
|
) {
|
|
return {
|
|
countdownMs: getRoundCountdownMs(round, baseIso),
|
|
featuredCellId: history[0]?.winningCellId ?? null,
|
|
onlinePlayers: 1_284,
|
|
tableLimitMax: 5_000,
|
|
tableLimitMin: 10,
|
|
totalPoolAmount: 84_300,
|
|
updatedAt: baseIso,
|
|
} satisfies DashboardState
|
|
}
|
|
|
|
export function createMockConnectionState(baseIso = MOCK_GAME_BASE_TIME) {
|
|
return {
|
|
connectedAt: offsetIso(baseIso, -180_000),
|
|
lastError: null,
|
|
lastMessageAt: offsetIso(baseIso, -500),
|
|
latencyMs: 48,
|
|
reconnectAttempt: 0,
|
|
status: 'connected',
|
|
transport: 'websocket',
|
|
} satisfies ConnectionState
|
|
}
|
|
|
|
export function createMockGameBootstrapSnapshot(baseIso = MOCK_GAME_BASE_TIME) {
|
|
const cells = createGameCells()
|
|
const chips = createDefaultChips()
|
|
const history = createMockHistoryEntries(baseIso)
|
|
const round = createMockRoundSnapshot(baseIso)
|
|
|
|
return {
|
|
announcements: createMockAnnouncementState(baseIso),
|
|
cells,
|
|
chips,
|
|
connection: createMockConnectionState(baseIso),
|
|
dashboard: createMockDashboardState(baseIso, round, history),
|
|
history,
|
|
maxSelectionCount: GAME_MAX_SELECTION_CELLS,
|
|
round,
|
|
selections: createMockBetSelections(),
|
|
trends: deriveTrendEntries(history),
|
|
} satisfies GameBootstrapSnapshot
|
|
}
|