1.优化后台测试推送功能页面
2.优化开奖和实时对局页面
This commit is contained in:
@@ -4,10 +4,14 @@
|
||||
<el-alert :type="pushConnected ? 'success' : 'error'" :title="pushConnected ? t('game.live.push_connected') : t('game.live.push_disconnected')" show-icon class="mb-12" />
|
||||
|
||||
<el-card shadow="never" class="mb-12">
|
||||
<el-alert v-if="snapshot.is_payout_phase" type="warning" :title="t('game.live.payout_phase')" show-icon class="mb-12" />
|
||||
<div class="header-row">
|
||||
<div>
|
||||
<div>{{ t('game.live.current_record') }}: {{ snapshot.record?.period_no || '-' }}</div>
|
||||
<div>{{ t('game.live.ai_default_number') }}: {{ snapshot.ai_default_number ?? '-' }}</div>
|
||||
<div v-if="snapshot.pending_draw_number != null">
|
||||
{{ t('game.live.pending_draw') }}: {{ snapshot.pending_draw_number }}
|
||||
</div>
|
||||
<div>{{ t('game.live.countdown') }}: {{ countdownText }}</div>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
@@ -15,7 +19,7 @@
|
||||
<el-button :loading="calcLoading" :disabled="!snapshot.can_calculate" @click="onCalculate">
|
||||
{{ t('game.live.btn_calc') }}
|
||||
</el-button>
|
||||
<el-button type="primary" :loading="drawLoading" :disabled="!snapshot.can_draw" @click="onDraw">
|
||||
<el-button type="primary" :loading="drawLoading" :disabled="!snapshot.can_schedule_draw" @click="onDraw">
|
||||
{{ t('game.live.btn_draw') }}
|
||||
</el-button>
|
||||
<el-button :loading="loading" @click="loadSnapshot">{{ t('Refresh') }}</el-button>
|
||||
@@ -67,6 +71,7 @@ interface Snapshot {
|
||||
bets: anyObj[]
|
||||
candidate_numbers: anyObj[]
|
||||
ai_default_number: number | null
|
||||
pending_draw_number: number | null
|
||||
period_seconds?: number
|
||||
bet_seconds?: number
|
||||
pick_max_number_count?: number
|
||||
@@ -74,8 +79,12 @@ interface Snapshot {
|
||||
draw_number_max?: number
|
||||
remaining_seconds?: number
|
||||
bet_remaining_seconds?: number
|
||||
payout_remaining_seconds?: number
|
||||
is_payout_phase?: boolean
|
||||
can_calculate?: boolean
|
||||
can_draw?: boolean
|
||||
can_schedule_draw?: boolean
|
||||
server_time?: number
|
||||
}
|
||||
|
||||
const { t } = useI18n()
|
||||
@@ -87,14 +96,18 @@ const snapshot = reactive<Snapshot>({
|
||||
bets: [],
|
||||
candidate_numbers: [],
|
||||
ai_default_number: null,
|
||||
pending_draw_number: null,
|
||||
period_seconds: 30,
|
||||
bet_seconds: 20,
|
||||
pick_max_number_count: 10,
|
||||
draw_number_max: 36,
|
||||
remaining_seconds: 0,
|
||||
bet_remaining_seconds: 0,
|
||||
payout_remaining_seconds: 0,
|
||||
is_payout_phase: false,
|
||||
can_calculate: false,
|
||||
can_draw: false,
|
||||
can_schedule_draw: false,
|
||||
})
|
||||
const calcLoading = ref(false)
|
||||
const drawLoading = ref(false)
|
||||
@@ -102,6 +115,12 @@ const manualNumber = ref<number | null>(1)
|
||||
const calcResultNumber = ref<number | null>(null)
|
||||
const calcEstimatedLoss = ref<string>('0.0000')
|
||||
|
||||
/** 服务端 Unix 秒 − 本地 Unix 秒,用于派彩倒计时与服务器对齐 */
|
||||
const serverSkewSeconds = ref(0)
|
||||
/** 每秒递增,驱动派彩剩余秒本地刷新 */
|
||||
const clockTick = ref(0)
|
||||
let clockTimer: number | null = null
|
||||
|
||||
let pushClient: any = null
|
||||
let pushChannel: any = null
|
||||
let pollTimer: number | null = null
|
||||
@@ -113,6 +132,45 @@ function formatPicks(v: unknown): string {
|
||||
return '-'
|
||||
}
|
||||
|
||||
function syncServerClock(serverTime: unknown): void {
|
||||
if (typeof serverTime === 'number' && Number.isFinite(serverTime)) {
|
||||
serverSkewSeconds.value = serverTime - Math.floor(Date.now() / 1000)
|
||||
snapshot.server_time = serverTime
|
||||
}
|
||||
}
|
||||
|
||||
function readPayoutUntilUnix(rec: anyObj | null): number | null {
|
||||
if (!rec) {
|
||||
return null
|
||||
}
|
||||
const v = rec.payout_until
|
||||
if (v === null || v === undefined || v === '') {
|
||||
return null
|
||||
}
|
||||
if (typeof v === 'number' && Number.isFinite(v)) {
|
||||
return v
|
||||
}
|
||||
if (typeof v === 'string' && /^\d+$/.test(v)) {
|
||||
return parseInt(v, 10)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/** 派彩剩余秒:优先用 payout_until 与对时后的「服务器当前秒」计算,便于每秒递减 */
|
||||
const payoutRemainingLive = computed(() => {
|
||||
clockTick.value
|
||||
if (!snapshot.is_payout_phase) {
|
||||
return null
|
||||
}
|
||||
const until = readPayoutUntilUnix(snapshot.record)
|
||||
if (until !== null) {
|
||||
const serverNow = Math.floor(Date.now() / 1000) + serverSkewSeconds.value
|
||||
const diff = until - serverNow
|
||||
return diff > 0 ? diff : 0
|
||||
}
|
||||
return snapshot.payout_remaining_seconds ?? 0
|
||||
})
|
||||
|
||||
async function loadSnapshot() {
|
||||
loading.value = true
|
||||
try {
|
||||
@@ -122,14 +180,20 @@ async function loadSnapshot() {
|
||||
snapshot.bets = res.data.bets || []
|
||||
snapshot.candidate_numbers = res.data.candidate_numbers || []
|
||||
snapshot.ai_default_number = res.data.ai_default_number
|
||||
snapshot.pending_draw_number =
|
||||
typeof res.data.pending_draw_number === 'number' ? res.data.pending_draw_number : null
|
||||
snapshot.period_seconds = res.data.period_seconds ?? 30
|
||||
snapshot.bet_seconds = res.data.bet_seconds ?? 20
|
||||
snapshot.pick_max_number_count = res.data.pick_max_number_count ?? 10
|
||||
snapshot.draw_number_max = res.data.draw_number_max ?? 36
|
||||
snapshot.remaining_seconds = res.data.remaining_seconds ?? 0
|
||||
snapshot.bet_remaining_seconds = res.data.bet_remaining_seconds ?? 0
|
||||
snapshot.payout_remaining_seconds = res.data.payout_remaining_seconds ?? 0
|
||||
snapshot.is_payout_phase = !!res.data.is_payout_phase
|
||||
snapshot.can_calculate = !!res.data.can_calculate
|
||||
snapshot.can_draw = !!res.data.can_draw
|
||||
snapshot.can_schedule_draw = !!res.data.can_schedule_draw || !!res.data.can_draw
|
||||
syncServerClock(res.data.server_time)
|
||||
const dmax = res.data.draw_number_max ?? 36
|
||||
if (manualNumber.value === null || manualNumber.value < 1 || manualNumber.value > dmax) manualNumber.value = 1
|
||||
}
|
||||
@@ -172,14 +236,20 @@ async function initPush() {
|
||||
snapshot.bets = payload.bets || []
|
||||
snapshot.candidate_numbers = payload.candidate_numbers || []
|
||||
snapshot.ai_default_number = payload.ai_default_number ?? null
|
||||
snapshot.pending_draw_number =
|
||||
typeof payload.pending_draw_number === 'number' ? payload.pending_draw_number : null
|
||||
snapshot.period_seconds = payload.period_seconds ?? 30
|
||||
snapshot.bet_seconds = payload.bet_seconds ?? 20
|
||||
snapshot.pick_max_number_count = payload.pick_max_number_count ?? 10
|
||||
snapshot.draw_number_max = payload.draw_number_max ?? 36
|
||||
snapshot.remaining_seconds = payload.remaining_seconds ?? 0
|
||||
snapshot.bet_remaining_seconds = payload.bet_remaining_seconds ?? 0
|
||||
snapshot.payout_remaining_seconds = payload.payout_remaining_seconds ?? 0
|
||||
snapshot.is_payout_phase = !!payload.is_payout_phase
|
||||
snapshot.can_calculate = !!payload.can_calculate
|
||||
snapshot.can_draw = !!payload.can_draw
|
||||
snapshot.can_schedule_draw = !!payload.can_schedule_draw || !!payload.can_draw
|
||||
syncServerClock(payload.server_time)
|
||||
})
|
||||
} catch {
|
||||
pushConnected.value = false
|
||||
@@ -244,12 +314,19 @@ async function onDraw() {
|
||||
}
|
||||
|
||||
const countdownText = computed(() => {
|
||||
const total = snapshot.remaining_seconds ?? 0
|
||||
const bet = snapshot.bet_remaining_seconds ?? 0
|
||||
return `${t('game.live.bet_countdown')} ${bet}s / ${t('game.live.draw_countdown')} ${total}s`
|
||||
const draw = snapshot.remaining_seconds ?? 0
|
||||
let payoutPart = t('game.live.payout_na')
|
||||
if (snapshot.is_payout_phase && payoutRemainingLive.value !== null) {
|
||||
payoutPart = `${payoutRemainingLive.value}s`
|
||||
}
|
||||
return `${t('game.live.bet_countdown')} ${bet}s / ${t('game.live.draw_countdown')} ${draw}s / ${t('game.live.payout_countdown')} ${payoutPart}`
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
clockTimer = window.setInterval(() => {
|
||||
clockTick.value++
|
||||
}, 1000)
|
||||
await loadSnapshot()
|
||||
try {
|
||||
await initPush()
|
||||
@@ -269,6 +346,10 @@ onUnmounted(() => {
|
||||
}
|
||||
stopPolling()
|
||||
stopPushWatchdog()
|
||||
if (clockTimer !== null) {
|
||||
window.clearInterval(clockTimer)
|
||||
clockTimer = null
|
||||
}
|
||||
})
|
||||
|
||||
function startPolling() {
|
||||
|
||||
@@ -63,7 +63,7 @@ const logText = computed(() => {
|
||||
})
|
||||
|
||||
function appendLog(line: PushTestLogLine) {
|
||||
logs.value = [...logs.value, line].slice(-200)
|
||||
logs.value = [line, ...logs.value].slice(0, 200)
|
||||
}
|
||||
|
||||
function clearLogs() {
|
||||
|
||||
Reference in New Issue
Block a user