优化后台实时对局页面
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="default-main">
|
||||
<el-alert type="info" :title="t('game.live.tip')" show-icon class="mb-12" />
|
||||
<el-alert type="info" :title="t('game.live.push_disconnected')" show-icon class="mb-12" />
|
||||
<el-alert :type="wsConnected ? 'success' : 'warning'" :title="wsConnected ? t('game.live.ws_connected') : t('game.live.ws_disconnected')" show-icon class="mb-12" />
|
||||
<el-alert
|
||||
v-if="snapshot.runtime_enabled === false && !snapshot.maintenance_ui"
|
||||
type="warning"
|
||||
@@ -255,7 +255,101 @@ const serverSkewSeconds = ref(0)
|
||||
const clockTick = ref(0)
|
||||
let clockTimer: number | null = null
|
||||
|
||||
let pollTimer: number | null = null
|
||||
const wsLoading = ref(false)
|
||||
const wsReady = ref(false)
|
||||
const wsConnected = ref(false)
|
||||
const wsUrl = ref('')
|
||||
const wsTopics = ref<string[]>([])
|
||||
const wsClient = ref<WebSocket | null>(null)
|
||||
|
||||
async function reloadWsConfig(): Promise<void> {
|
||||
wsLoading.value = true
|
||||
try {
|
||||
const res = await createAxios({
|
||||
url: '/admin/game.Live/wsConfig',
|
||||
method: 'get',
|
||||
showCodeMessage: true,
|
||||
})
|
||||
if (res.code !== 1 || !res.data) {
|
||||
wsReady.value = false
|
||||
return
|
||||
}
|
||||
wsUrl.value = String(res.data.ws_url || '')
|
||||
if (Array.isArray(res.data.subscribe_topics)) {
|
||||
wsTopics.value = res.data.subscribe_topics.filter((topic: unknown): topic is string => typeof topic === 'string' && topic.trim() !== '')
|
||||
} else {
|
||||
wsTopics.value = []
|
||||
}
|
||||
wsReady.value = wsUrl.value !== ''
|
||||
} finally {
|
||||
wsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleWsPayload(raw: unknown): void {
|
||||
let parsed: anyObj | null = null
|
||||
if (typeof raw === 'string') {
|
||||
try {
|
||||
parsed = JSON.parse(raw)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
} else if (raw && typeof raw === 'object') {
|
||||
parsed = raw as anyObj
|
||||
}
|
||||
if (!parsed) {
|
||||
return
|
||||
}
|
||||
const event = typeof parsed.event === 'string' ? parsed.event : ''
|
||||
if (event === 'admin.live.snapshot' && parsed.data && typeof parsed.data === 'object') {
|
||||
mergeLiveSnapshot(parsed.data as anyObj)
|
||||
return
|
||||
}
|
||||
if (event === 'period.tick' && parsed.data && typeof parsed.data === 'object') {
|
||||
const periodData = parsed.data as anyObj
|
||||
if (typeof periodData.server_time === 'number') {
|
||||
syncServerClock(periodData.server_time)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function connectWs(): void {
|
||||
if (!wsReady.value || !wsUrl.value) {
|
||||
return
|
||||
}
|
||||
disconnectWs()
|
||||
const socket = new WebSocket(wsUrl.value)
|
||||
wsClient.value = socket
|
||||
socket.onopen = () => {
|
||||
wsConnected.value = true
|
||||
const topics = wsTopics.value
|
||||
const payload = JSON.stringify({ action: 'subscribe', topics })
|
||||
socket.send(payload)
|
||||
}
|
||||
socket.onmessage = (event) => {
|
||||
handleWsPayload(event.data)
|
||||
}
|
||||
socket.onerror = () => {
|
||||
wsConnected.value = false
|
||||
}
|
||||
socket.onclose = () => {
|
||||
wsConnected.value = false
|
||||
wsClient.value = null
|
||||
window.setTimeout(() => {
|
||||
if (!wsConnected.value) {
|
||||
connectWs()
|
||||
}
|
||||
}, 1200)
|
||||
}
|
||||
}
|
||||
|
||||
function disconnectWs(): void {
|
||||
if (wsClient.value) {
|
||||
wsClient.value.close()
|
||||
wsClient.value = null
|
||||
}
|
||||
wsConnected.value = false
|
||||
}
|
||||
|
||||
function formatPicks(v: unknown): string {
|
||||
if (Array.isArray(v)) return JSON.stringify(v)
|
||||
@@ -359,6 +453,10 @@ async function loadSnapshot() {
|
||||
|
||||
async function onRuntimeSwitch(val: boolean | string | number): void {
|
||||
const on = val === true || val === 'true' || val === 1
|
||||
// 防止某些场景下 model-value 变化触发重复 change 事件,造成 runtime 接口循环调用
|
||||
if (on === !!snapshot.runtime_enabled) {
|
||||
return
|
||||
}
|
||||
runtimeSwitchLoading.value = true
|
||||
try {
|
||||
const res = await createAxios({
|
||||
@@ -471,33 +569,18 @@ onMounted(async () => {
|
||||
clockTick.value++
|
||||
}, 1000)
|
||||
await loadSnapshot()
|
||||
startPolling()
|
||||
await reloadWsConfig()
|
||||
connectWs()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
stopPolling()
|
||||
disconnectWs()
|
||||
if (clockTimer !== null) {
|
||||
window.clearInterval(clockTimer)
|
||||
clockTimer = null
|
||||
}
|
||||
})
|
||||
|
||||
function startPolling() {
|
||||
if (pollTimer !== null) {
|
||||
return
|
||||
}
|
||||
pollTimer = window.setInterval(() => {
|
||||
void loadSnapshot()
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
function stopPolling() {
|
||||
if (pollTimer !== null) {
|
||||
window.clearInterval(pollTimer)
|
||||
pollTimer = null
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
Reference in New Issue
Block a user