1.优化实时游戏对局页面样式
This commit is contained in:
@@ -283,9 +283,16 @@ let snapshotLoadPromise: Promise<void> | null = null
|
|||||||
const wsLoading = ref(false)
|
const wsLoading = ref(false)
|
||||||
const wsReady = ref(false)
|
const wsReady = ref(false)
|
||||||
const wsConnected = ref(false)
|
const wsConnected = ref(false)
|
||||||
|
/** 同一期只提示一次“中大奖”,避免 bet.win/jackpot.hit 连续触发刷屏 */
|
||||||
|
const lastJackpotTipPeriodNo = ref<string>('')
|
||||||
|
const lastJackpotTipAtMs = ref<number>(0)
|
||||||
const wsUrl = ref('')
|
const wsUrl = ref('')
|
||||||
const wsTopics = ref<string[]>([])
|
const wsTopics = ref<string[]>([])
|
||||||
const wsClient = ref<WebSocket | null>(null)
|
const wsClient = ref<WebSocket | null>(null)
|
||||||
|
let wsReconnectTimer: number | null = null
|
||||||
|
let wsReconnectAttempt = 0
|
||||||
|
let wsLastConfigReloadAtMs = 0
|
||||||
|
let wsManualClosing = false
|
||||||
const isMobile = ref(false)
|
const isMobile = ref(false)
|
||||||
const candidateSort = ref<{ prop: string; order: 'ascending' | 'descending' | null }>({ prop: 'estimated_loss', order: 'ascending' })
|
const candidateSort = ref<{ prop: string; order: 'ascending' | 'descending' | null }>({ prop: 'estimated_loss', order: 'ascending' })
|
||||||
|
|
||||||
@@ -376,7 +383,7 @@ function handleWsPayload(raw: unknown): void {
|
|||||||
if (event === 'bet.win' && parsed.data && typeof parsed.data === 'object') {
|
if (event === 'bet.win' && parsed.data && typeof parsed.data === 'object') {
|
||||||
const winData = parsed.data as anyObj
|
const winData = parsed.data as anyObj
|
||||||
if (winData.is_jackpot === true) {
|
if (winData.is_jackpot === true) {
|
||||||
ElMessage.success(t('game.live.jackpot_hit_tip'))
|
showJackpotTipOnce(readString(winData.period_no) || readString(snapshot.record?.period_no))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -384,7 +391,7 @@ function handleWsPayload(raw: unknown): void {
|
|||||||
const jackpotData = parsed.data as anyObj
|
const jackpotData = parsed.data as anyObj
|
||||||
const hits = Array.isArray(jackpotData.hits) ? jackpotData.hits : []
|
const hits = Array.isArray(jackpotData.hits) ? jackpotData.hits : []
|
||||||
if (hits.length > 0) {
|
if (hits.length > 0) {
|
||||||
ElMessage.success(t('game.live.jackpot_hit_tip'))
|
showJackpotTipOnce(readString(jackpotData.period_no) || readString(snapshot.record?.period_no))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -397,6 +404,27 @@ function handleWsPayload(raw: unknown): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readString(v: any): string {
|
||||||
|
return typeof v === 'string' ? v : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function showJackpotTipOnce(periodNo: string): void {
|
||||||
|
const key = String(periodNo || '')
|
||||||
|
const now = Date.now()
|
||||||
|
// 同一期只提示一次;同时加 2s 防抖,避免同一瞬间 bet.win + jackpot.hit 连续触发刷屏
|
||||||
|
if (key !== '' && lastJackpotTipPeriodNo.value === key) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (now - lastJackpotTipAtMs.value < 2000) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (key !== '') {
|
||||||
|
lastJackpotTipPeriodNo.value = key
|
||||||
|
}
|
||||||
|
lastJackpotTipAtMs.value = now
|
||||||
|
ElMessage.success(t('game.live.jackpot_hit_tip'))
|
||||||
|
}
|
||||||
|
|
||||||
/** 用 period.tick 轻量字段刷新倒计时(不触发 HTTP,避免与 WS 每秒 snapshot 冲突) */
|
/** 用 period.tick 轻量字段刷新倒计时(不触发 HTTP,避免与 WS 每秒 snapshot 冲突) */
|
||||||
function mergePeriodTickFields(periodData: anyObj): void {
|
function mergePeriodTickFields(periodData: anyObj): void {
|
||||||
if (typeof periodData.server_time === 'number') {
|
if (typeof periodData.server_time === 'number') {
|
||||||
@@ -445,11 +473,17 @@ function connectWs(): void {
|
|||||||
if (!wsReady.value || !wsUrl.value) {
|
if (!wsReady.value || !wsUrl.value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (wsReconnectTimer !== null) {
|
||||||
|
window.clearTimeout(wsReconnectTimer)
|
||||||
|
wsReconnectTimer = null
|
||||||
|
}
|
||||||
|
wsManualClosing = false
|
||||||
disconnectWs()
|
disconnectWs()
|
||||||
const socket = new WebSocket(wsUrl.value)
|
const socket = new WebSocket(wsUrl.value)
|
||||||
wsClient.value = socket
|
wsClient.value = socket
|
||||||
socket.onopen = () => {
|
socket.onopen = () => {
|
||||||
wsConnected.value = true
|
wsConnected.value = true
|
||||||
|
wsReconnectAttempt = 0
|
||||||
const topics = wsTopics.value
|
const topics = wsTopics.value
|
||||||
const payload = JSON.stringify({ action: 'subscribe', topics })
|
const payload = JSON.stringify({ action: 'subscribe', topics })
|
||||||
socket.send(payload)
|
socket.send(payload)
|
||||||
@@ -463,24 +497,42 @@ function connectWs(): void {
|
|||||||
socket.onclose = () => {
|
socket.onclose = () => {
|
||||||
wsConnected.value = false
|
wsConnected.value = false
|
||||||
wsClient.value = null
|
wsClient.value = null
|
||||||
|
if (wsManualClosing) {
|
||||||
|
return
|
||||||
|
}
|
||||||
// 断线后:先刷新 wsConfig 拿新的 admin_ws_token(避免握手 token 已过期反复失败),再重连
|
// 断线后:先刷新 wsConfig 拿新的 admin_ws_token(避免握手 token 已过期反复失败),再重连
|
||||||
window.setTimeout(async () => {
|
const attempt = wsReconnectAttempt
|
||||||
|
wsReconnectAttempt = Math.min(wsReconnectAttempt + 1, 10)
|
||||||
|
const baseDelay = Math.min(30_000, 1200 * Math.pow(2, attempt))
|
||||||
|
const delay = Math.max(1200, Math.floor(baseDelay + Math.random() * 400))
|
||||||
|
wsReconnectTimer = window.setTimeout(async () => {
|
||||||
|
wsReconnectTimer = null
|
||||||
if (wsConnected.value) {
|
if (wsConnected.value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await reloadWsConfig()
|
const now = Date.now()
|
||||||
|
// 避免断线风暴下疯狂请求 wsConfig(后台会报错且浏览器控制台刷屏)
|
||||||
|
if (!wsLoading.value && now - wsLastConfigReloadAtMs > 8000) {
|
||||||
|
wsLastConfigReloadAtMs = now
|
||||||
|
await reloadWsConfig()
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
/* ignore;下次重连时再试 */
|
/* ignore;下次重连时再试 */
|
||||||
}
|
}
|
||||||
if (!wsConnected.value) {
|
if (!wsConnected.value) {
|
||||||
connectWs()
|
connectWs()
|
||||||
}
|
}
|
||||||
}, 1200)
|
}, delay)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function disconnectWs(): void {
|
function disconnectWs(): void {
|
||||||
|
wsManualClosing = true
|
||||||
|
if (wsReconnectTimer !== null) {
|
||||||
|
window.clearTimeout(wsReconnectTimer)
|
||||||
|
wsReconnectTimer = null
|
||||||
|
}
|
||||||
if (wsClient.value) {
|
if (wsClient.value) {
|
||||||
wsClient.value.close()
|
wsClient.value.close()
|
||||||
wsClient.value = null
|
wsClient.value = null
|
||||||
|
|||||||
Reference in New Issue
Block a user