From a7c4e3f673e0358ec9c13d8e913f7509b1dd7017 Mon Sep 17 00:00:00 2001 From: hajimi Date: Mon, 3 Aug 2026 02:11:07 +0800 Subject: [PATCH] feat: add world cup schedule live entry --- .../components/WorldCupPanel.vue | 80 ++++++++++++++++++- 1 file changed, 76 insertions(+), 4 deletions(-) diff --git a/uniapp/src/packages_match/components/WorldCupPanel.vue b/uniapp/src/packages_match/components/WorldCupPanel.vue index 48bfd9e..fa95d35 100644 --- a/uniapp/src/packages_match/components/WorldCupPanel.vue +++ b/uniapp/src/packages_match/components/WorldCupPanel.vue @@ -111,6 +111,11 @@ {{ matchCenterText(match) }} {{ matchMetaText(match, index) }} + + + 看直播 + @@ -420,6 +425,7 @@ const hideLiveCardControlsOnAndroid = ref(false) const useLiveCardPosterMode = ref(false) const liveCards = ref([]) const liveCardsLoaded = ref(false) +let liveCardsRequest: Promise | null = null const oddsList = ref([]) const oddsLoading = ref(false) const oddsLoaded = ref(false) @@ -645,6 +651,36 @@ const liveStatusText = (live: WorldCupLiveCardItem) => { return '未开赛' } +const normalizeMatchName = (value: unknown) => { + return String(value || '') + .toLowerCase() + .replace(/[\s·•,,。.::;;'"“”‘’()()\[\]【】_-]/g, '') +} + +const resolveScheduleMatchLive = (match: any): WorldCupLiveCardItem | undefined => { + const scheduleIds = [match?.id, match?.match_id] + .map((item) => Number(item || 0)) + .filter((item) => item > 0) + + const matchedById = liveCards.value.find((live) => scheduleIds.includes(Number(live.match_id || live.id || 0))) + if (matchedById) return matchedById + + const homeTeam = normalizeMatchName(match?.home_team) + const awayTeam = normalizeMatchName(match?.away_team) + if (!homeTeam || !awayTeam) return undefined + + return liveCards.value.find((live) => { + const liveHome = normalizeMatchName(live.home_team) + const liveAway = normalizeMatchName(live.away_team) + const teamsMatch = (liveHome === homeTeam && liveAway === awayTeam) + || (liveHome === awayTeam && liveAway === homeTeam) + if (teamsMatch) return true + + const liveTitle = normalizeMatchName(live.title) + return !!liveTitle && liveTitle.includes(homeTeam) && liveTitle.includes(awayTeam) + }) +} + const flattenScheduleMatches = computed(() => { const matches: any[] = [] ; (scheduleData.value.schedule_rounds || []).forEach((round: any) => { @@ -730,13 +766,23 @@ const scheduleGroupAnchorId = (key: string) => `worldcup-schedule-group-${key}` const fetchWorldCupLiveCards = async () => { if (liveCardsLoaded.value) return - const data = await getWorldCupLiveCards() - liveCards.value = Array.isArray(data?.list) ? data.list : [] - liveCardsLoaded.value = true + if (!liveCardsRequest) { + liveCardsRequest = getWorldCupLiveCards().then((data) => { + liveCards.value = Array.isArray(data?.list) ? data.list : [] + liveCardsLoaded.value = true + }) + } + + try { + await liveCardsRequest + } finally { + liveCardsRequest = null + } } const fetchSchedule = async () => { - scheduleData.value = await getWorldCupSchedule() || { current_round_name: '', bracket_rounds: [], schedule_rounds: [] } + const [schedule] = await Promise.all([getWorldCupSchedule(), fetchWorldCupLiveCards()]) + scheduleData.value = schedule || { current_round_name: '', bracket_rounds: [], schedule_rounds: [] } if (activeTab.value === 'schedule') { void scrollScheduleToToday() } @@ -918,6 +964,15 @@ const openWorldCupLiveCard = (live: WorldCupLiveCardItem) => { } } +const watchScheduleMatchLive = async (match: any) => { + const live = resolveScheduleMatchLive(match) + if (!live) return + + activeTab.value = 'live' + await nextTick() + openWorldCupLiveCard(live) +} + const getWorldCupDisplayDate = (timestamp: number) => { return getLocalMatchDate(timestamp, WORLD_CUP_MATCH_CONTEXT) } @@ -1567,6 +1622,23 @@ onMounted(() => { gap: 4rpx; } +.wc-match-card__live-entry { + height: 36rpx; + margin-top: 4rpx; + padding: 0 12rpx; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 4rpx; + border-radius: 999rpx; + color: #ffffff; + background: linear-gradient(90deg, #176af6 0%, #0878f8 100%); + box-shadow: 0 4rpx 10rpx rgba(20, 104, 245, 0.18); + font-size: 20rpx; + font-weight: 600; + line-height: 1; +} + .wc-match-card__time { font-size: 32rpx; font-weight: 700;