1.优化后台/admin/game/live
This commit is contained in:
@@ -82,7 +82,7 @@
|
||||
<div class="calc-result-bar">
|
||||
<span class="calc-result-bar__item">
|
||||
<span class="calc-result-bar__k">{{ t('game.live.calc_result_number') }}</span>
|
||||
<span class="calc-result-bar__v">{{ calcResultNumber ?? '—' }}</span>
|
||||
<span class="calc-result-bar__v">{{ displayResultNumber ?? '—' }}</span>
|
||||
</span>
|
||||
<span class="calc-result-bar__item">
|
||||
<span class="calc-result-bar__k">{{ t('game.live.calc_estimated_loss') }}</span>
|
||||
@@ -160,6 +160,11 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="total_amount" :label="t('game.live.total_amount')" width="92" align="center" header-align="center" />
|
||||
<el-table-column prop="win_amount" :label="t('game.live.win_amount')" width="92" align="center" header-align="center">
|
||||
<template #default="scope">
|
||||
<span class="mono">{{ formatWinAmount(scope.row) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
@@ -229,6 +234,8 @@ interface Snapshot {
|
||||
runtime_enabled?: boolean
|
||||
/** 完整维护 UI:关服且当前无进行中/未结清对局(派彩已全部完成) */
|
||||
maintenance_ui?: boolean
|
||||
/** 已开奖号码(status≥2 时有值) */
|
||||
result_number?: number | null
|
||||
}
|
||||
|
||||
const { t } = useI18n()
|
||||
@@ -252,6 +259,7 @@ const snapshot = reactive<Snapshot>({
|
||||
can_schedule_draw: false,
|
||||
runtime_enabled: true,
|
||||
maintenance_ui: false,
|
||||
result_number: null,
|
||||
})
|
||||
const calcLoading = ref(false)
|
||||
const drawLoading = ref(false)
|
||||
@@ -271,6 +279,7 @@ const clockTick = ref(0)
|
||||
let clockTimer: number | null = null
|
||||
let payoutStuckRefreshTimer: number | null = null
|
||||
let fallbackPollTimer: number | null = null
|
||||
let betStreamRefreshTimer: number | null = null
|
||||
/** 合并并发 snapshot 请求,避免 axios 重复请求取消导致控制台报错 */
|
||||
let snapshotLoadPromise: Promise<void> | null = null
|
||||
|
||||
@@ -333,6 +342,11 @@ function handleWsPayload(raw: unknown): void {
|
||||
return
|
||||
}
|
||||
if (event === 'admin.live.opened') {
|
||||
const opened = parsed.data as anyObj
|
||||
if (typeof opened.result_number === 'number') {
|
||||
snapshot.result_number = opened.result_number
|
||||
calcResultNumber.value = opened.result_number
|
||||
}
|
||||
void loadSnapshot({ force: true })
|
||||
return
|
||||
}
|
||||
@@ -360,13 +374,29 @@ function handleWsPayload(raw: unknown): void {
|
||||
return
|
||||
}
|
||||
if (event === 'bet.accepted' && parsed.data && typeof parsed.data === 'object') {
|
||||
if (!wsConnected.value) {
|
||||
void loadSnapshot()
|
||||
const betData = parsed.data as anyObj
|
||||
const periodNo = typeof betData.period_no === 'string' ? betData.period_no : ''
|
||||
const currentNo = typeof snapshot.record?.period_no === 'string' ? snapshot.record.period_no : ''
|
||||
if (periodNo !== '' && periodNo === currentNo) {
|
||||
scheduleBetStreamRefresh()
|
||||
} else if (!wsConnected.value) {
|
||||
void loadSnapshot({ force: true })
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
/** 有新下注时防抖拉取快照,补全 WS 每秒快照之间的下注列表 */
|
||||
function scheduleBetStreamRefresh(): void {
|
||||
if (betStreamRefreshTimer !== null) {
|
||||
window.clearTimeout(betStreamRefreshTimer)
|
||||
}
|
||||
betStreamRefreshTimer = window.setTimeout(() => {
|
||||
betStreamRefreshTimer = null
|
||||
void loadSnapshot({ force: true })
|
||||
}, 600)
|
||||
}
|
||||
|
||||
/** 用 period.tick 轻量字段刷新倒计时(不触发 HTTP,避免与 WS 每秒 snapshot 冲突) */
|
||||
function mergePeriodTickFields(periodData: anyObj): void {
|
||||
if (typeof periodData.server_time === 'number') {
|
||||
@@ -568,8 +598,49 @@ function isScheduledNumber(v: unknown): boolean {
|
||||
return snapshot.pending_draw_number === n
|
||||
}
|
||||
|
||||
const displayResultNumber = computed(() => {
|
||||
const fromSnap = numberValue(snapshot.result_number)
|
||||
if (fromSnap !== null) {
|
||||
return fromSnap
|
||||
}
|
||||
const fromRec = numberValue(snapshot.record?.result_number)
|
||||
if (fromRec !== null) {
|
||||
return fromRec
|
||||
}
|
||||
return calcResultNumber.value
|
||||
})
|
||||
|
||||
function updateCalcLossFromResultNumber(): void {
|
||||
const rn = displayResultNumber.value
|
||||
if (rn === null) {
|
||||
return
|
||||
}
|
||||
const row = snapshot.candidate_numbers.find((c) => numberValue(c?.number) === rn)
|
||||
if (row && row.estimated_loss !== undefined && row.estimated_loss !== null) {
|
||||
calcEstimatedLoss.value = String(row.estimated_loss)
|
||||
}
|
||||
}
|
||||
|
||||
function formatWinAmount(row: anyObj): string {
|
||||
const st = Number(row?.bet_status ?? 0)
|
||||
const win = row?.win_amount
|
||||
if (st === 2 || st === 5) {
|
||||
return win !== undefined && win !== null && String(win) !== '' ? String(win) : '0.00'
|
||||
}
|
||||
return '—'
|
||||
}
|
||||
|
||||
function candidateRowClassName(arg: { row: anyObj }): string {
|
||||
return isScheduledNumber(arg.row?.number) ? 'is-scheduled-row' : ''
|
||||
const classes: string[] = []
|
||||
if (isScheduledNumber(arg.row?.number)) {
|
||||
classes.push('is-scheduled-row')
|
||||
}
|
||||
const result = displayResultNumber.value
|
||||
const num = numberValue(arg.row?.number)
|
||||
if (result !== null && num !== null && num === result) {
|
||||
classes.push('is-result-row')
|
||||
}
|
||||
return classes.join(' ')
|
||||
}
|
||||
|
||||
async function onPickSwitchChange(val: boolean, rowNumber: unknown): Promise<void> {
|
||||
@@ -621,11 +692,29 @@ function toBool(v: unknown): boolean | null {
|
||||
}
|
||||
|
||||
function mergeLiveSnapshot(data: anyObj): void {
|
||||
const prevPeriodId = snapshot.record?.id != null ? Number(snapshot.record.id) : null
|
||||
let periodChanged = false
|
||||
|
||||
if (data.record !== undefined) {
|
||||
const nextId = data.record?.id != null ? Number(data.record.id) : null
|
||||
periodChanged = prevPeriodId !== null && nextId !== null && prevPeriodId !== nextId
|
||||
snapshot.record = data.record
|
||||
}
|
||||
snapshot.bets = data.bets || []
|
||||
snapshot.candidate_numbers = data.candidate_numbers || []
|
||||
|
||||
const incomingBets = Array.isArray(data.bets) ? data.bets : null
|
||||
if (incomingBets !== null) {
|
||||
if (incomingBets.length > 0 || periodChanged || prevPeriodId === null) {
|
||||
snapshot.bets = incomingBets
|
||||
}
|
||||
}
|
||||
|
||||
const incomingCandidates = Array.isArray(data.candidate_numbers) ? data.candidate_numbers : null
|
||||
if (incomingCandidates !== null) {
|
||||
if (incomingCandidates.length > 0 || periodChanged || prevPeriodId === null) {
|
||||
snapshot.candidate_numbers = incomingCandidates
|
||||
}
|
||||
}
|
||||
|
||||
snapshot.ai_default_number = data.ai_default_number ?? null
|
||||
snapshot.pending_draw_number = typeof data.pending_draw_number === 'number' ? data.pending_draw_number : null
|
||||
snapshot.period_seconds = data.period_seconds ?? 30
|
||||
@@ -654,6 +743,17 @@ function mergeLiveSnapshot(data: anyObj): void {
|
||||
snapshot.maintenance_ui = data.maintenance_ui
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof data.result_number === 'number') {
|
||||
snapshot.result_number = data.result_number
|
||||
calcResultNumber.value = data.result_number
|
||||
} else if (periodChanged) {
|
||||
snapshot.result_number = null
|
||||
calcResultNumber.value = null
|
||||
calcEstimatedLoss.value = '0.00'
|
||||
}
|
||||
|
||||
updateCalcLossFromResultNumber()
|
||||
syncServerClock(data.server_time)
|
||||
}
|
||||
|
||||
@@ -931,6 +1031,10 @@ onUnmounted(() => {
|
||||
window.clearTimeout(payoutStuckRefreshTimer)
|
||||
payoutStuckRefreshTimer = null
|
||||
}
|
||||
if (betStreamRefreshTimer !== null) {
|
||||
window.clearTimeout(betStreamRefreshTimer)
|
||||
betStreamRefreshTimer = null
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
@@ -1166,6 +1270,16 @@ onUnmounted(() => {
|
||||
background: var(--el-color-primary-light-9);
|
||||
}
|
||||
|
||||
.candidate-table :deep(.is-result-row td) {
|
||||
background: var(--el-color-success-light-9);
|
||||
}
|
||||
|
||||
.candidate-table :deep(.is-result-row .number-tag) {
|
||||
border-color: var(--el-color-success);
|
||||
color: var(--el-color-success);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.live-tables-row .el-col {
|
||||
margin-bottom: 12px;
|
||||
|
||||
Reference in New Issue
Block a user