Files
thebet365/apps/player/src/components/outright/OutrightEventSection.vue
Mars d2c0b575b7 feat(player): 统一移动端主题样式并优化多页面视觉一致性
将玩家端组件与核心页面全面切换为统一主题变量,优化卡片、按钮、弹窗、列表和盘口相关模块的视觉表现,并补充多语言文案以匹配新的交互与布局风格。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 15:55:28 +08:00

198 lines
4.2 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 OutrightOptionCard from './OutrightOptionCard.vue';
import saishiImg from '../../assets/images/saishi.webp';
import cardBg from '../../assets/images/card-bg.webp';
const matchCardBg = `url(${cardBg})`;
export interface OutrightSelection {
id: string;
teamCode: string;
teamName: string;
logoUrl?: string | null;
odds: string;
oddsVersion: string;
}
export interface OutrightEvent {
id: string;
leagueId: string;
leagueCode?: string;
leagueName: string;
title: string;
selectionCount?: number;
selections: OutrightSelection[];
}
const props = defineProps<{
event: OutrightEvent;
expanded: boolean;
}>();
const emit = defineEmits<{
toggle: [];
pick: [selection: OutrightSelection];
}>();
const { t } = useI18n();
const headTitle = computed(() => {
const raw = props.event.title.replace(/^\*+/, '').trim();
return raw || props.event.leagueName || t('bet.tab_outright');
});
const headMeta = computed(() => {
const total = props.event.selectionCount ?? props.event.selections.length;
return t('bet.outright_teams_count', { n: total });
});
</script>
<template>
<section class="event-block">
<button type="button" class="event-head" :class="{ 'is-expanded': expanded }" :aria-expanded="expanded" @click="emit('toggle')">
<span class="toggle-icon" :class="{ open: expanded }">
<span class="toggle-mark">{{ expanded ? '' : '+' }}</span>
</span>
<span class="event-head-text">
<span class="event-title">{{ headTitle }}</span>
<span v-if="event.leagueName && event.leagueName !== headTitle" class="event-league">
{{ event.leagueName }}
</span>
<span class="event-meta">{{ headMeta }}</span>
</span>
<img :src="saishiImg" alt="" class="event-saishi" />
</button>
<div v-show="expanded" class="options-scroll">
<div class="options-grid">
<OutrightOptionCard
v-for="sel in event.selections"
:key="sel.id"
:team-code="sel.teamCode"
:team-name="sel.teamName"
:logo-url="sel.logoUrl"
:odds="sel.odds"
@pick="emit('pick', sel)"
/>
</div>
</div>
</section>
</template>
<style scoped>
.event-block {
position: relative;
isolation: isolate;
margin-bottom: 12px;
border: 1px solid var(--border);
border-radius: 8px;
background: var(--bg-card);
overflow: hidden;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
.event-head {
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;
}
.event-head::before {
content: '';
position: absolute;
inset: 0;
background: v-bind(matchCardBg) center / 100% 100% no-repeat;
opacity: 0.04;
z-index: -1;
pointer-events: none;
}
.toggle-icon {
flex-shrink: 0;
width: 26px;
height: 26px;
border-radius: 50%;
background: var(--bg-elevated);
border: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: center;
transition: border-color 0.15s;
}
.toggle-icon.open {
border-color: var(--primary);
}
.toggle-mark {
color: var(--primary);
font-size: 17px;
font-weight: 900;
line-height: 1;
}
.event-head-text {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 2px;
}
.event-title {
font-size: 13px;
font-weight: 800;
color: var(--primary);
line-height: 1.35;
}
.event-league {
font-size: 11px;
font-weight: 600;
color: var(--text-muted);
line-height: 1.3;
}
.event-meta {
font-size: 11px;
font-weight: 600;
color: var(--text-muted);
}
.event-saishi {
flex-shrink: 0;
height: 44px;
width: auto;
max-width: 40px;
object-fit: contain;
padding-left: 8px;
border-left: 1px solid var(--border);
}
.options-scroll {
max-height: 408px;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
padding: 8px 2px 2px;
scrollbar-width: thin;
scrollbar-color: var(--border) transparent;
}
.options-grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 6px;
}
</style>