优化实时游戏对局页面
This commit is contained in:
@@ -9,6 +9,8 @@ export default {
|
||||
payout_countdown: 'Payout left',
|
||||
payout_na: '—',
|
||||
payout_phase: 'Payout in progress',
|
||||
action_panel: 'Actions',
|
||||
manual_draw_number: 'Scheduled draw',
|
||||
btn_calc: 'Calculate PnL',
|
||||
btn_draw: 'Schedule draw',
|
||||
calc_result_number: 'Calculated number',
|
||||
|
||||
@@ -9,7 +9,9 @@ export default {
|
||||
payout_countdown: '派彩剩余',
|
||||
payout_na: '—',
|
||||
payout_phase: '派彩中,请稍候',
|
||||
btn_calc: '计算法盈亏',
|
||||
action_panel: '操作区',
|
||||
manual_draw_number: '预约开奖',
|
||||
btn_calc: '计算盈亏',
|
||||
btn_draw: '预约开奖',
|
||||
calc_result_number: '计算开奖号码',
|
||||
calc_estimated_loss: '计算预估赔付',
|
||||
|
||||
@@ -3,31 +3,75 @@
|
||||
<el-alert type="info" :title="t('game.live.tip')" show-icon class="mb-12" />
|
||||
<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-card shadow="never" class="mb-12 live-control-card">
|
||||
<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 class="live-control-layout">
|
||||
<div class="live-control-main">
|
||||
<el-descriptions :column="1" border size="small" class="live-desc">
|
||||
<el-descriptions-item :label="t('game.live.current_record')">
|
||||
<span class="period-no">{{ snapshot.record?.period_no || '—' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item :label="t('game.live.ai_default_number')">
|
||||
<span class="num-em">{{ snapshot.ai_default_number ?? '—' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item v-if="snapshot.pending_draw_number != null" :label="t('game.live.pending_draw')">
|
||||
<el-tag type="primary" effect="plain">{{ snapshot.pending_draw_number }}</el-tag>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<div class="countdown-block">
|
||||
<div class="countdown-block__title">{{ t('game.live.countdown') }}</div>
|
||||
<div class="countdown-cards">
|
||||
<div class="cd-card">
|
||||
<span class="cd-card__label">{{ t('game.live.bet_countdown') }}</span>
|
||||
<span class="cd-card__val">{{ countdownParts.bet }}s</span>
|
||||
</div>
|
||||
<div class="cd-card">
|
||||
<span class="cd-card__label">{{ t('game.live.draw_countdown') }}</span>
|
||||
<span class="cd-card__val">{{ countdownParts.draw }}s</span>
|
||||
</div>
|
||||
<div class="cd-card" :class="{ 'is-active': snapshot.is_payout_phase }">
|
||||
<span class="cd-card__label">{{ t('game.live.payout_countdown') }}</span>
|
||||
<span class="cd-card__val">{{ countdownParts.payout }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
<span class="calc-result-bar__item">
|
||||
<span class="calc-result-bar__k">{{ t('game.live.calc_estimated_loss') }}</span>
|
||||
<span class="calc-result-bar__v mono">{{ calcEstimatedLoss }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div>{{ t('game.live.countdown') }}: {{ countdownText }}</div>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<el-input-number v-model="manualNumber" :min="1" :max="snapshot.draw_number_max ?? 36" :step="1" />
|
||||
<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_schedule_draw" @click="onDraw">
|
||||
{{ t('game.live.btn_draw') }}
|
||||
</el-button>
|
||||
<el-button :loading="loading" @click="loadSnapshot">{{ t('Refresh') }}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-row">
|
||||
<span>{{ t('game.live.calc_result_number') }}: {{ calcResultNumber ?? '-' }}</span>
|
||||
<span>{{ t('game.live.calc_estimated_loss') }}: {{ calcEstimatedLoss }}</span>
|
||||
|
||||
<aside class="live-control-aside">
|
||||
<div class="aside-title">{{ t('game.live.action_panel') }}</div>
|
||||
<div class="aside-field">
|
||||
<span class="aside-field__label">{{ t('game.live.manual_draw_number') }}</span>
|
||||
<el-input-number
|
||||
v-model="manualNumber"
|
||||
class="aside-field__input"
|
||||
:min="1"
|
||||
:max="snapshot.draw_number_max ?? 36"
|
||||
:step="1"
|
||||
controls-position="right"
|
||||
/>
|
||||
</div>
|
||||
<div class="aside-btns">
|
||||
<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_schedule_draw" @click="onDraw">
|
||||
{{ t('game.live.btn_draw') }}
|
||||
</el-button>
|
||||
<el-button :loading="loading" @click="loadSnapshot">{{ t('Refresh') }}</el-button>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
@@ -313,14 +357,14 @@ async function onDraw() {
|
||||
}
|
||||
}
|
||||
|
||||
const countdownText = computed(() => {
|
||||
const countdownParts = computed(() => {
|
||||
const bet = snapshot.bet_remaining_seconds ?? 0
|
||||
const draw = snapshot.remaining_seconds ?? 0
|
||||
let payoutPart = t('game.live.payout_na')
|
||||
let payout = t('game.live.payout_na')
|
||||
if (snapshot.is_payout_phase && payoutRemainingLive.value !== null) {
|
||||
payoutPart = `${payoutRemainingLive.value}s`
|
||||
payout = `${payoutRemainingLive.value}s`
|
||||
}
|
||||
return `${t('game.live.bet_countdown')} ${bet}s / ${t('game.live.draw_countdown')} ${draw}s / ${t('game.live.payout_countdown')} ${payoutPart}`
|
||||
return { bet, draw, payout }
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -394,20 +438,217 @@ function stopPushWatchdog() {
|
||||
.mb-12 {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.header-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
||||
.live-control-card {
|
||||
:deep(.el-card__body) {
|
||||
padding-top: 8px;
|
||||
}
|
||||
}
|
||||
.header-actions {
|
||||
|
||||
.live-control-layout {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px 24px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.live-control-main {
|
||||
flex: 1 1 320px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.live-desc {
|
||||
margin-bottom: 16px;
|
||||
:deep(.el-descriptions__label) {
|
||||
width: 120px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.period-no {
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
word-break: break-all;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.num-em {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
.countdown-block {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.countdown-block__title {
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.countdown-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.cd-card {
|
||||
border: 1px solid var(--el-border-color-lighter);
|
||||
border-radius: 8px;
|
||||
padding: 10px 12px;
|
||||
background: var(--el-fill-color-blank);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* 移动端保持同一排,压缩间距与字号以省纵向空间 */
|
||||
@media (max-width: 768px) {
|
||||
.countdown-block {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.countdown-block__title {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.countdown-cards {
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.cd-card {
|
||||
padding: 6px 4px;
|
||||
border-radius: 6px;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.cd-card__label {
|
||||
font-size: 11px;
|
||||
line-height: 1.2;
|
||||
padding: 0 2px;
|
||||
}
|
||||
|
||||
.cd-card__val {
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.cd-card.is-active {
|
||||
border-color: var(--el-color-warning-light-5);
|
||||
background: var(--el-color-warning-light-9);
|
||||
}
|
||||
|
||||
.cd-card__label {
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.cd-card__val {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
font-variant-numeric: tabular-nums;
|
||||
color: var(--el-text-color-primary);
|
||||
}
|
||||
|
||||
.calc-result-bar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px 24px;
|
||||
padding: 10px 14px;
|
||||
border-radius: 8px;
|
||||
background: var(--el-fill-color-light);
|
||||
border: 1px solid var(--el-border-color-lighter);
|
||||
}
|
||||
|
||||
.calc-result-bar__item {
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
gap: 8px;
|
||||
}
|
||||
.result-row {
|
||||
margin-top: 12px;
|
||||
|
||||
.calc-result-bar__k {
|
||||
font-size: 13px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.calc-result-bar__v {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.calc-result-bar__v.mono {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||
}
|
||||
|
||||
.live-control-aside {
|
||||
flex: 0 0 240px;
|
||||
padding-left: 20px;
|
||||
border-left: 1px solid var(--el-border-color-lighter);
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.live-control-aside {
|
||||
flex: 1 1 100%;
|
||||
padding-left: 0;
|
||||
border-left: none;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid var(--el-border-color-lighter);
|
||||
}
|
||||
}
|
||||
|
||||
.aside-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--el-text-color-regular);
|
||||
}
|
||||
|
||||
.aside-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.aside-field__label {
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
}
|
||||
|
||||
.aside-field__input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.aside-btns {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
gap: 8px;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.aside-btns .el-button {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
margin-left: 0;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.aside-btns .el-button :deep(span) {
|
||||
white-space: normal;
|
||||
line-height: 1.25;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user