Files
thebet365/apps/player/src/components/LeagueAccordionItem.vue
Mars cb4e48b9f4 feat(player): ???????????????
???????????????????????????????????????????????????????????

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 16:10:11 +08:00

204 lines
4.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import MatchBetCard from './MatchBetCard.vue';
import saishiImg from '../assets/images/saishi.webp';
import cardBg from '../assets/images/card-bg.webp';
const matchCardBg = `url(${cardBg})`;
const props = defineProps<{
leagueId: string;
leagueName: string;
leagueLogoUrl?: string | null;
expanded: boolean;
matches: {
id: string;
homeTeamName: string;
awayTeamName: string;
homeTeamCode?: string;
awayTeamCode?: string;
homeTeamLogoUrl?: string | null;
awayTeamLogoUrl?: string | null;
startTime: string;
bettingOpen?: boolean;
matchPhase?: import('../utils/matchPhase').MatchPhase;
score?: {
htHome: number | null;
htAway: number | null;
ftHome: number | null;
ftAway: number | null;
homeCorners?: number | null;
awayCorners?: number | null;
homeYellowCards?: number | null;
awayYellowCards?: number | null;
homeRedCards?: number | null;
awayRedCards?: number | null;
homeCards?: number | null;
awayCards?: number | null;
} | null;
}[];
}>();
const emit = defineEmits<{ toggle: []; bet: [id: string] }>();
const { t } = useI18n();
const totalCount = computed(() => props.matches.length);
const liveCount = computed(() => props.matches.filter(m => m.matchPhase === 'closed_pending').length);
const openCount = computed(() => props.matches.filter(m => m.matchPhase === 'open').length);
</script>
<template>
<section class="league-block">
<button type="button" class="league-row" :aria-expanded="expanded" @click="emit('toggle')">
<span class="toggle-icon" :class="{ open: expanded }" aria-hidden="true">
<span class="toggle-mark">{{ expanded ? '' : '+' }}</span>
</span>
<span class="league-info">
<span class="league-title">*{{ leagueName }}</span>
<span class="league-stats">
<span class="stat-item">{{ totalCount }} {{ t('bet.match_unit') }}</span>
<span v-if="liveCount > 0" class="stat-item stat-live">{{ liveCount }} {{ t('bet.status_live') }}</span>
<span v-if="openCount > 0" class="stat-item stat-open">{{ openCount }} {{ t('bet.status_open') }}</span>
</span>
</span>
<img
:src="leagueLogoUrl || saishiImg"
alt=""
class="league-saishi"
loading="lazy"
decoding="async"
/>
</button>
<div v-show="expanded" class="match-panel">
<div class="match-grid">
<MatchBetCard
v-for="match in matches"
:key="match.id"
:match="match"
@bet="emit('bet', $event)"
/>
</div>
</div>
</section>
</template>
<style scoped>
.league-block {
position: relative;
isolation: isolate;
margin-bottom: 10px;
border: 1px solid #CBD5E1;
border-radius: 8px;
background: #FFFFFF;
overflow: hidden;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
}
.league-row {
position: relative;
z-index: 1;
width: 100%;
display: flex;
align-items: center;
gap: 10px;
padding: 12px 16px;
background: none;
border: none;
border-radius: 0;
text-align: left;
cursor: pointer;
}
.league-row::before {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg, rgba(0, 61, 107, 0.02) 0%, transparent 60%);
z-index: -1;
pointer-events: none;
}
.league-row:active {
opacity: 0.92;
}
.toggle-icon {
flex-shrink: 0;
width: 26px;
height: 26px;
border-radius: 50%;
background: #003D6B;
border: none;
display: flex;
align-items: center;
justify-content: center;
}
.toggle-mark {
color: #FFFFFF;
font-size: 17px;
font-weight: 700;
line-height: 1;
margin-top: -1px;
}
.league-info {
flex: 1;
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
}
.league-title {
font-size: 13px;
font-weight: 700;
color: #1A1A2E;
line-height: 1.35;
min-width: 0;
}
.league-stats {
display: flex;
align-items: center;
gap: 6px;
font-size: 11px;
color: #6B7280;
line-height: 1.2;
}
.stat-live {
color: #059669;
}
.stat-open {
color: #D97706;
}
.league-saishi {
flex-shrink: 0;
height: 44px;
width: auto;
max-width: 40px;
object-fit: contain;
margin-left: 4px;
padding-left: 10px;
border-left: 1px solid #CBD5E1;
}
.match-panel {
padding: 8px 0 4px;
background: #F0F2F6;
border-top: 1px solid #D1D5DB;
}
.match-grid {
display: grid;
grid-template-columns: repeat(1, minmax(0, 1fr));
gap: 8px;
padding: 0 4px;
}
</style>