1.修复游戏实时对局/admin/game/live页面的报错
This commit is contained in:
@@ -57,7 +57,9 @@ class Live extends Backend
|
|||||||
'period.locked',
|
'period.locked',
|
||||||
'period.opened',
|
'period.opened',
|
||||||
'period.payout',
|
'period.payout',
|
||||||
|
'period.payout.tick',
|
||||||
'bet.accepted',
|
'bet.accepted',
|
||||||
|
'bet.win',
|
||||||
'wallet.changed',
|
'wallet.changed',
|
||||||
'auto.spin.progress',
|
'auto.spin.progress',
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
>
|
>
|
||||||
{{ t('game.live.void_btn') }}
|
{{ t('game.live.void_btn') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button :loading="loading" :disabled="asideOperationLocked" @click="loadSnapshot">{{ t('Refresh') }}</el-button>
|
<el-button :loading="loading" :disabled="asideOperationLocked" @click="loadSnapshot({ force: true })">{{ t('Refresh') }}</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -203,6 +203,7 @@
|
|||||||
import { computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
|
import { computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
|
import axios from 'axios'
|
||||||
import createAxios from '/@/utils/axios'
|
import createAxios from '/@/utils/axios'
|
||||||
|
|
||||||
interface Snapshot {
|
interface Snapshot {
|
||||||
@@ -270,6 +271,8 @@ const clockTick = ref(0)
|
|||||||
let clockTimer: number | null = null
|
let clockTimer: number | null = null
|
||||||
let payoutStuckRefreshTimer: number | null = null
|
let payoutStuckRefreshTimer: number | null = null
|
||||||
let fallbackPollTimer: number | null = null
|
let fallbackPollTimer: number | null = null
|
||||||
|
/** 合并并发 snapshot 请求,避免 axios 重复请求取消导致控制台报错 */
|
||||||
|
let snapshotLoadPromise: Promise<void> | null = null
|
||||||
|
|
||||||
const wsLoading = ref(false)
|
const wsLoading = ref(false)
|
||||||
const wsReady = ref(false)
|
const wsReady = ref(false)
|
||||||
@@ -330,7 +333,7 @@ function handleWsPayload(raw: unknown): void {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (event === 'admin.live.opened') {
|
if (event === 'admin.live.opened') {
|
||||||
void loadSnapshot()
|
void loadSnapshot({ force: true })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (event === 'jackpot.hit' && parsed.data && typeof parsed.data === 'object') {
|
if (event === 'jackpot.hit' && parsed.data && typeof parsed.data === 'object') {
|
||||||
@@ -341,19 +344,63 @@ function handleWsPayload(raw: unknown): void {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (event === 'period.payout.tick' && parsed.data && typeof parsed.data === 'object') {
|
||||||
|
mergePeriodPayoutTick(parsed.data as anyObj)
|
||||||
|
return
|
||||||
|
}
|
||||||
if (event === 'period.tick' && parsed.data && typeof parsed.data === 'object') {
|
if (event === 'period.tick' && parsed.data && typeof parsed.data === 'object') {
|
||||||
const periodData = parsed.data as anyObj
|
handlePeriodTickEvent(parsed.data as anyObj)
|
||||||
if (typeof periodData.server_time === 'number') {
|
return
|
||||||
syncServerClock(periodData.server_time)
|
}
|
||||||
}
|
if (event === 'bet.accepted' && parsed.data && typeof parsed.data === 'object') {
|
||||||
const status = typeof periodData.status === 'string' ? periodData.status : ''
|
if (!wsConnected.value) {
|
||||||
const periodNo = typeof periodData.period_no === 'string' ? periodData.period_no : ''
|
|
||||||
const currentNo = typeof snapshot.record?.period_no === 'string' ? snapshot.record.period_no : ''
|
|
||||||
if (status === 'betting' && periodNo !== '' && periodNo !== currentNo) {
|
|
||||||
void loadSnapshot()
|
|
||||||
} else if (status === 'finished' && snapshot.is_payout_phase) {
|
|
||||||
void loadSnapshot()
|
void loadSnapshot()
|
||||||
}
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 用 period.tick 轻量字段刷新倒计时(不触发 HTTP,避免与 WS 每秒 snapshot 冲突) */
|
||||||
|
function mergePeriodTickFields(periodData: anyObj): void {
|
||||||
|
if (typeof periodData.server_time === 'number') {
|
||||||
|
syncServerClock(periodData.server_time)
|
||||||
|
}
|
||||||
|
if (typeof periodData.countdown === 'number') {
|
||||||
|
snapshot.remaining_seconds = Math.max(0, periodData.countdown)
|
||||||
|
}
|
||||||
|
if (typeof periodData.bet_close_in === 'number') {
|
||||||
|
snapshot.bet_remaining_seconds = Math.max(0, periodData.bet_close_in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergePeriodPayoutTick(data: anyObj): void {
|
||||||
|
if (typeof data.server_time === 'number') {
|
||||||
|
syncServerClock(data.server_time)
|
||||||
|
}
|
||||||
|
const remain = numberValue(data.payout_remaining_seconds)
|
||||||
|
if (remain !== null) {
|
||||||
|
snapshot.payout_remaining_seconds = Math.max(0, remain)
|
||||||
|
snapshot.is_payout_phase = remain > 0 || snapshot.is_payout_phase === true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePeriodTickEvent(periodData: anyObj): void {
|
||||||
|
mergePeriodTickFields(periodData)
|
||||||
|
const status = typeof periodData.status === 'string' ? periodData.status : ''
|
||||||
|
const periodNo = typeof periodData.period_no === 'string' ? periodData.period_no : ''
|
||||||
|
const currentNo = typeof snapshot.record?.period_no === 'string' ? snapshot.record.period_no : ''
|
||||||
|
if (status === 'betting' && periodNo !== '' && periodNo !== currentNo) {
|
||||||
|
void loadSnapshot({ force: true })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (status === 'finished' && snapshot.is_payout_phase) {
|
||||||
|
if (!wsConnected.value) {
|
||||||
|
void loadSnapshot()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (currentNo === '' && periodNo !== '') {
|
||||||
|
void loadSnapshot({ force: true })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -643,16 +690,40 @@ const payoutRemainingLive = computed(() => {
|
|||||||
return snapshot.payout_remaining_seconds ?? 0
|
return snapshot.payout_remaining_seconds ?? 0
|
||||||
})
|
})
|
||||||
|
|
||||||
async function loadSnapshot() {
|
function isRequestCanceled(err: unknown): boolean {
|
||||||
loading.value = true
|
return axios.isCancel(err) || (err instanceof Error && err.name === 'CanceledError')
|
||||||
try {
|
}
|
||||||
const res = await createAxios({ url: '/admin/game.Live/snapshot', method: 'get', showCodeMessage: false })
|
|
||||||
if (res.code === 1 && res.data) {
|
async function loadSnapshot(options?: { force?: boolean }): Promise<void> {
|
||||||
mergeLiveSnapshot(res.data as anyObj)
|
if (!options?.force && wsConnected.value && snapshot.record) {
|
||||||
}
|
return
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
}
|
||||||
|
if (snapshotLoadPromise) {
|
||||||
|
return snapshotLoadPromise
|
||||||
|
}
|
||||||
|
snapshotLoadPromise = (async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const res = await createAxios({
|
||||||
|
url: '/admin/game.Live/snapshot',
|
||||||
|
method: 'get',
|
||||||
|
showCodeMessage: false,
|
||||||
|
showErrorMessage: false,
|
||||||
|
cancelDuplicateRequest: false,
|
||||||
|
})
|
||||||
|
if (res.code === 1 && res.data) {
|
||||||
|
mergeLiveSnapshot(res.data as anyObj)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
if (!isRequestCanceled(err)) {
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
snapshotLoadPromise = null
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
return snapshotLoadPromise
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onRuntimeSwitch(val: boolean | string | number): void {
|
async function onRuntimeSwitch(val: boolean | string | number): void {
|
||||||
@@ -679,10 +750,10 @@ async function onRuntimeSwitch(val: boolean | string | number): void {
|
|||||||
if (res.code === 1 && res.data) {
|
if (res.code === 1 && res.data) {
|
||||||
mergeLiveSnapshot(res.data as anyObj)
|
mergeLiveSnapshot(res.data as anyObj)
|
||||||
} else {
|
} else {
|
||||||
await loadSnapshot()
|
await loadSnapshot({ force: true })
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
await loadSnapshot()
|
await loadSnapshot({ force: true })
|
||||||
} finally {
|
} finally {
|
||||||
runtimeSwitchLoading.value = false
|
runtimeSwitchLoading.value = false
|
||||||
pendingRuntimeTarget.value = null
|
pendingRuntimeTarget.value = null
|
||||||
@@ -768,7 +839,7 @@ async function onDrawWithNumber(targetNumber: number) {
|
|||||||
},
|
},
|
||||||
showSuccessMessage: true,
|
showSuccessMessage: true,
|
||||||
})
|
})
|
||||||
await loadSnapshot()
|
await loadSnapshot({ force: true })
|
||||||
} finally {
|
} finally {
|
||||||
drawLoading.value = false
|
drawLoading.value = false
|
||||||
}
|
}
|
||||||
@@ -816,7 +887,9 @@ function schedulePayoutEndRefresh(delayMs: number): void {
|
|||||||
if (!snapshot.is_payout_phase) {
|
if (!snapshot.is_payout_phase) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
void loadSnapshot()
|
if (!wsConnected.value) {
|
||||||
|
void loadSnapshot({ force: true })
|
||||||
|
}
|
||||||
}, delayMs)
|
}, delayMs)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -827,11 +900,11 @@ onMounted(async () => {
|
|||||||
clockTick.value++
|
clockTick.value++
|
||||||
}, 1000)
|
}, 1000)
|
||||||
fallbackPollTimer = window.setInterval(() => {
|
fallbackPollTimer = window.setInterval(() => {
|
||||||
if (snapshot.is_payout_phase || snapshot.maintenance_ui) {
|
if (!wsConnected.value) {
|
||||||
void loadSnapshot()
|
void loadSnapshot({ force: true })
|
||||||
}
|
}
|
||||||
}, 5000)
|
}, 3000)
|
||||||
await loadSnapshot()
|
await loadSnapshot({ force: true })
|
||||||
await reloadWsConfig()
|
await reloadWsConfig()
|
||||||
connectWs()
|
connectWs()
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user