优化实时游戏对局页面
This commit is contained in:
@@ -9,6 +9,8 @@ export default {
|
|||||||
payout_countdown: 'Payout left',
|
payout_countdown: 'Payout left',
|
||||||
payout_na: '—',
|
payout_na: '—',
|
||||||
payout_phase: 'Payout in progress',
|
payout_phase: 'Payout in progress',
|
||||||
|
action_panel: 'Actions',
|
||||||
|
manual_draw_number: 'Scheduled draw',
|
||||||
btn_calc: 'Calculate PnL',
|
btn_calc: 'Calculate PnL',
|
||||||
btn_draw: 'Schedule draw',
|
btn_draw: 'Schedule draw',
|
||||||
calc_result_number: 'Calculated number',
|
calc_result_number: 'Calculated number',
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ export default {
|
|||||||
payout_countdown: '派彩剩余',
|
payout_countdown: '派彩剩余',
|
||||||
payout_na: '—',
|
payout_na: '—',
|
||||||
payout_phase: '派彩中,请稍候',
|
payout_phase: '派彩中,请稍候',
|
||||||
btn_calc: '计算法盈亏',
|
action_panel: '操作区',
|
||||||
|
manual_draw_number: '预约开奖',
|
||||||
|
btn_calc: '计算盈亏',
|
||||||
btn_draw: '预约开奖',
|
btn_draw: '预约开奖',
|
||||||
calc_result_number: '计算开奖号码',
|
calc_result_number: '计算开奖号码',
|
||||||
calc_estimated_loss: '计算预估赔付',
|
calc_estimated_loss: '计算预估赔付',
|
||||||
|
|||||||
@@ -3,31 +3,75 @@
|
|||||||
<el-alert type="info" :title="t('game.live.tip')" show-icon class="mb-12" />
|
<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-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" />
|
<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 class="live-control-layout">
|
||||||
<div>
|
<div class="live-control-main">
|
||||||
<div>{{ t('game.live.current_record') }}: {{ snapshot.record?.period_no || '-' }}</div>
|
<el-descriptions :column="1" border size="small" class="live-desc">
|
||||||
<div>{{ t('game.live.ai_default_number') }}: {{ snapshot.ai_default_number ?? '-' }}</div>
|
<el-descriptions-item :label="t('game.live.current_record')">
|
||||||
<div v-if="snapshot.pending_draw_number != null">
|
<span class="period-no">{{ snapshot.record?.period_no || '—' }}</span>
|
||||||
{{ t('game.live.pending_draw') }}: {{ snapshot.pending_draw_number }}
|
</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>
|
||||||
<div>{{ t('game.live.countdown') }}: {{ countdownText }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
|
||||||
<el-input-number v-model="manualNumber" :min="1" :max="snapshot.draw_number_max ?? 36" :step="1" />
|
<aside class="live-control-aside">
|
||||||
<el-button :loading="calcLoading" :disabled="!snapshot.can_calculate" @click="onCalculate">
|
<div class="aside-title">{{ t('game.live.action_panel') }}</div>
|
||||||
{{ t('game.live.btn_calc') }}
|
<div class="aside-field">
|
||||||
</el-button>
|
<span class="aside-field__label">{{ t('game.live.manual_draw_number') }}</span>
|
||||||
<el-button type="primary" :loading="drawLoading" :disabled="!snapshot.can_schedule_draw" @click="onDraw">
|
<el-input-number
|
||||||
{{ t('game.live.btn_draw') }}
|
v-model="manualNumber"
|
||||||
</el-button>
|
class="aside-field__input"
|
||||||
<el-button :loading="loading" @click="loadSnapshot">{{ t('Refresh') }}</el-button>
|
:min="1"
|
||||||
</div>
|
:max="snapshot.draw_number_max ?? 36"
|
||||||
</div>
|
:step="1"
|
||||||
<div class="result-row">
|
controls-position="right"
|
||||||
<span>{{ t('game.live.calc_result_number') }}: {{ calcResultNumber ?? '-' }}</span>
|
/>
|
||||||
<span>{{ t('game.live.calc_estimated_loss') }}: {{ calcEstimatedLoss }}</span>
|
</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>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
@@ -313,14 +357,14 @@ async function onDraw() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const countdownText = computed(() => {
|
const countdownParts = computed(() => {
|
||||||
const bet = snapshot.bet_remaining_seconds ?? 0
|
const bet = snapshot.bet_remaining_seconds ?? 0
|
||||||
const draw = snapshot.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) {
|
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 () => {
|
onMounted(async () => {
|
||||||
@@ -394,20 +438,217 @@ function stopPushWatchdog() {
|
|||||||
.mb-12 {
|
.mb-12 {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
.header-row {
|
|
||||||
display: flex;
|
.live-control-card {
|
||||||
justify-content: space-between;
|
:deep(.el-card__body) {
|
||||||
align-items: center;
|
padding-top: 8px;
|
||||||
gap: 12px;
|
}
|
||||||
}
|
}
|
||||||
.header-actions {
|
|
||||||
|
.live-control-layout {
|
||||||
display: flex;
|
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;
|
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;
|
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;
|
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>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user