fix(player): 优化桌面快速下注 hover 并修复充值 API 重复方法

删除 deposit.service 中重复的 getPlayerDepositOrder,避免 API 编译失败引发 500;快速下注弹层按卡片实例激活,同场赛事不再多处联动,移入快速下注区域时保持 VS 动画;记录列表改为整行可点,编号统一中性色样式。
This commit is contained in:
2026-07-02 11:12:09 +08:00
parent 66ac69c7a7
commit 8000c23418
12 changed files with 122 additions and 102 deletions

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, computed } from 'vue';
import { ref, computed, getCurrentInstance } from 'vue';
import { useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { teamFlagUrl } from '../utils/teamFlag';
@@ -82,10 +82,15 @@ const liveScoreText = computed(() => {
const router = useRouter();
const slip = useBetSlipStore();
const auth = useAuthStore();
const { openAt, visible: popoverVisible, pendingItem, cancelClose, scheduleClose } = useDesktopBetPopover();
const { openAt, visible: popoverVisible, pendingItem, cancelClose, scheduleClose, isActiveForCard } = useDesktopBetPopover();
const cardRootId = `bet-card-${props.match.id}-${getCurrentInstance()?.uid ?? 0}`;
const isCardEngaged = computed(() => isActiveForCard(cardRootId));
function getHoveredSide() {
if (!popoverVisible.value || !pendingItem.value) return '';
if (!isActiveForCard(cardRootId)) return '';
if (String(pendingItem.value.matchId) !== String(props.match.id)) return '';
const selId = pendingItem.value.selectionId;
@@ -199,8 +204,15 @@ function goMatchDetail() {
<template>
<article
class="match-card"
:class="{ 'match-card--phase': phase !== 'open', 'no-quick-bet': noQuickBet }"
:data-bet-card-root="cardRootId"
:class="{
'match-card--phase': phase !== 'open',
'no-quick-bet': noQuickBet,
'match-card--engaged': isCardEngaged,
}"
@click="emit('bet', match.id)"
@mouseenter="cancelClose"
@mouseleave="scheduleClose()"
>
<span v-if="phase === 'open'" class="status-tag status-tag--open">{{ t('bet.status_open') }}</span>
<span v-else-if="phase === 'settled'" class="status-tag status-tag--settled">{{ phaseLabel }}</span>
@@ -250,7 +262,7 @@ function goMatchDetail() {
</button>
<!-- Morphing Quick Bet panel (Desktop Only, disabled when noQuickBet=true) -->
<div v-if="!noQuickBet" class="card-quick-bet" @click.stop @mouseenter="cancelClose" @mouseleave="scheduleClose()">
<div v-if="!noQuickBet" class="card-quick-bet" @click.stop>
<div class="quick-bet-tabs" v-if="getAvailableMarketsForMatch(match).length">
<button
v-for="m in getAvailableMarketsForMatch(match)"
@@ -486,36 +498,36 @@ function goMatchDetail() {
}
@media (hover: hover) {
.match-card:not(.no-quick-bet):hover {
.match-card:not(.no-quick-bet):is(:hover, .match-card--engaged) {
border-color: var(--border-gold);
box-shadow: var(--shadow-gold);
}
/* 整行保持原位,间距自然 */
.match-card:not(.no-quick-bet):hover .teams-row {
.match-card:not(.no-quick-bet):is(:hover, .match-card--engaged) .teams-row {
transform: translateY(0);
padding: 0 40px;
}
/* .team 取消自身 translateY */
.match-card:not(.no-quick-bet):hover .team {
.match-card:not(.no-quick-bet):is(:hover, .match-card--engaged) .team {
transform: translateY(0);
gap: 3px;
}
/* 旗帜缩小到 40×28 */
.match-card:not(.no-quick-bet):hover .team-flag {
.match-card:not(.no-quick-bet):is(:hover, .match-card--engaged) .team-flag {
width: 40px;
height: 28px;
}
.match-card:not(.no-quick-bet):hover .team-flag.flag-logo {
.match-card:not(.no-quick-bet):is(:hover, .match-card--engaged) .team-flag.flag-logo {
width: 28px;
height: 28px;
}
/* 队名缩小并禁止换行 */
.match-card:not(.no-quick-bet):hover .team-name {
.match-card:not(.no-quick-bet):is(:hover, .match-card--engaged) .team-name {
font-size: 10px;
white-space: nowrap;
overflow: hidden;
@@ -524,7 +536,7 @@ function goMatchDetail() {
}
/* 隐藏开赛时间 */
.match-card:not(.no-quick-bet):hover .kickoff {
.match-card:not(.no-quick-bet):is(:hover, .match-card--engaged) .kickoff {
opacity: 0;
height: 0;
margin: 0;
@@ -533,19 +545,19 @@ function goMatchDetail() {
}
/* VS / 比分 */
.match-card:not(.no-quick-bet):hover .vs,
.match-card:not(.no-quick-bet):hover .live-score {
.match-card:not(.no-quick-bet):is(:hover, .match-card--engaged) .vs,
.match-card:not(.no-quick-bet):is(:hover, .match-card--engaged) .live-score {
font-size: 16px;
}
/* 下注按钮淡出(保留布局空间避免高度抖动) */
.match-card:not(.no-quick-bet):hover .bet-btn {
.match-card:not(.no-quick-bet):is(:hover, .match-card--engaged) .bet-btn {
opacity: 0;
pointer-events: none;
}
/* 快速下注面板淡入 */
.match-card:not(.no-quick-bet):hover .card-quick-bet {
.match-card:not(.no-quick-bet):is(:hover, .match-card--engaged) .card-quick-bet {
opacity: 1;
pointer-events: auto;
transform: translateY(0);

View File

@@ -26,7 +26,7 @@ const emit = defineEmits<{
}>();
const { t } = useI18n();
const { scheduleClose, cancelClose } = useDesktopBetPopover();
const { cancelClose } = useDesktopBetPopover();
const columns = computed(() =>
groupCorrectScoreSelections(
@@ -51,14 +51,18 @@ function formatOdds(odds: string) {
</script>
<template>
<div class="cs-panel" :class="{ 'cs-panel--locked': locked, 'cs-panel--dense': dense }">
<div
class="cs-panel"
:class="{ 'cs-panel--locked': locked, 'cs-panel--dense': dense }"
@mouseenter="cancelClose"
>
<div class="cols-head">
<span>{{ t('bet.col_home') }}</span>
<span>{{ t('bet.col_draw') }}</span>
<span>{{ t('bet.col_away') }}</span>
</div>
<div class="cols-grid" @mouseenter="cancelClose" @mouseleave="scheduleClose()">
<div class="cols-grid">
<div v-for="colKey in ['home', 'draw', 'away'] as const" :key="colKey" class="col">
<button
v-for="sel in columns[colKey]"

View File

@@ -25,7 +25,7 @@ const props = defineProps<{
const emit = defineEmits<{ pick: [id: string, event?: MouseEvent] }>();
const { t } = useI18n();
const { scheduleClose, cancelClose } = useDesktopBetPopover();
const { cancelClose } = useDesktopBetPopover();
function label(sel: (typeof props.selections)[number]) {
if (sel.selectionDisplayName?.trim()) return sel.selectionDisplayName;
@@ -56,7 +56,7 @@ const panelStyle = computed(() =>
</script>
<template>
<div class="wrap" :class="{ compact, horizontal, desktopCard, locked }" @mouseenter="cancelClose" @mouseleave="scheduleClose()">
<div class="wrap" :class="{ compact, horizontal, desktopCard, locked }" @mouseenter="cancelClose">
<div
class="panel"
:class="{ horizontal, 'desktop-card': desktopCard }"