diff --git a/app/match-detail/[id].tsx b/app/match-detail/[id].tsx index 59ceec9..65a2cbc 100644 --- a/app/match-detail/[id].tsx +++ b/app/match-detail/[id].tsx @@ -1,15 +1,16 @@ +import { BasketballScoreTable } from "@/components/match-detail/basketball/basketball-score-table"; +import { FootballScoreTable } from "@/components/match-detail/football/football-score-table"; import { LeagueInfo } from "@/components/match-detail/league-info"; import { MatchInfoCard } from "@/components/match-detail/match-info-card"; import { MatchTabs } from "@/components/match-detail/match-tabs"; import { ScoreHeader } from "@/components/match-detail/score-header"; -import { ScoreTable } from "@/components/match-detail/score-table"; import { ThemedText } from "@/components/themed-text"; import { ThemedView } from "@/components/themed-view"; import { Colors } from "@/constants/theme"; import { useTheme } from "@/context/ThemeContext"; import { fetchMatchDetail } from "@/lib/api"; import { MatchDetailData } from "@/types/api"; -import { Stack, useLocalSearchParams, useRouter } from "expo-router"; +import { useLocalSearchParams, useRouter } from "expo-router"; import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { @@ -40,6 +41,30 @@ export default function MatchDetailScreen() { } }, [id]); + // 当数据加载完成且 sportId 变化时,检查并重置 activeTab + useEffect(() => { + if (data?.match?.sportId) { + const sportId = data.match.sportId; + let validTabs: string[] = []; + + if (sportId === 1) { + // 足球 + validTabs = ["info", "stats", "odds", "h2h", "chat"]; + } else if (sportId === 2) { + // 篮球 + validTabs = ["info", "h2h", "chat"]; + } else { + // 默认 + validTabs = ["info", "h2h", "chat"]; + } + + // 如果当前 activeTab 不在有效标签列表中,重置为第一个 + if (!validTabs.includes(activeTab)) { + setActiveTab(validTabs[0]); + } + } + }, [data?.match?.sportId]); + const loadMatchDetail = async () => { try { setLoading(true); @@ -73,13 +98,51 @@ export default function MatchDetailScreen() { } const renderTabContent = () => { + const sportId = data?.match?.sportId || 1; + switch (activeTab) { case "info": + // 根据 sportId 显示不同的详情组件 + if (sportId === 1) { + // 足球:显示 FootballScoreTable (半场/全场) 和 MatchInfoCard + return ( + <> + + + + ); + } else if (sportId === 2) { + // 篮球:显示 BasketballScoreTable (4节) 和 MatchInfoCard + return ( + <> + + + + ); + } else { + // 默认使用足球组件 + return ( + <> + + + + ); + } + case "stats": return ( - <> - - - + + + {t("detail.empty_stats")} + + + ); + case "odds": + return ( + + + {t("detail.empty_odds")} + + ); case "h2h": return ( @@ -115,6 +178,7 @@ export default function MatchDetailScreen() { activeTab={activeTab} onTabChange={setActiveTab} isDark={isDark} + sportId={data.match.sportId} /> {renderTabContent()} diff --git a/components/match-detail/score-table.tsx b/components/match-detail/basketball/basketball-score-table.tsx similarity index 71% rename from components/match-detail/score-table.tsx rename to components/match-detail/basketball/basketball-score-table.tsx index fc3801c..48fa7a4 100644 --- a/components/match-detail/score-table.tsx +++ b/components/match-detail/basketball/basketball-score-table.tsx @@ -4,45 +4,55 @@ import React from "react"; import { useTranslation } from "react-i18next"; import { Image, StyleSheet, View } from "react-native"; -interface ScoreTableProps { +interface BasketballScoreTableProps { data: MatchDetailData; isDark: boolean; } -export function ScoreTable({ data, isDark }: ScoreTableProps) { +export function BasketballScoreTable({ data, isDark }: BasketballScoreTableProps) { const { t } = useTranslation(); const { match } = data; const bgColor = isDark ? "#1C1C1E" : "#FFF"; const headerTextColor = isDark ? "#666" : "#999"; - // Mock quarters for demo purposes as seen in screenshot - // In real app, these would come from the API (e.g. match.eventQuarter or specific fields) + // 解析比分 - 篮球通常是 4 节 + const parseScore = (scoreString: string) => { + if (!scoreString || scoreString === "-") return [0, 0, 0, 0, 0]; + // 假设格式可能是 "25-20,30-28,22-25,28-26" 或类似 + // 这里简化处理,实际需要根据 API 返回格式解析 + return [0, 0, 0, 0, 0]; // total, q1, q2, q3, q4 + }; + + const homeScores = parseScore(match.eventFinalResult || "-"); + const awayScores = parseScore(match.eventFinalResult || "-"); + const headers = [ t("detail.score_table.team"), t("detail.score_table.total"), - "1", - "2", - "3", - "4", + "Q1", + "Q2", + "Q3", + "Q4", ]; + const rows = [ { logo: match.homeTeamLogo, name: match.eventHomeTeam, - total: 0, - q1: 0, - q2: 0, - q3: 0, - q4: 0, + total: homeScores[0], + q1: homeScores[1], + q2: homeScores[2], + q3: homeScores[3], + q4: homeScores[4], }, { logo: match.awayTeamLogo, name: match.eventAwayTeam, - total: 0, - q1: 0, - q2: 0, - q3: 0, - q4: 0, + total: awayScores[0], + q1: awayScores[1], + q2: awayScores[2], + q3: awayScores[3], + q4: awayScores[4], }, ]; @@ -70,6 +80,9 @@ export function ScoreTable({ data, isDark }: ScoreTableProps) { + + {row.name} + {row.total} {row.q1} @@ -87,7 +100,6 @@ const styles = StyleSheet.create({ margin: 16, borderRadius: 12, padding: 16, - // Shadow elevation: 2, shadowColor: "#000", shadowOffset: { width: 0, height: 2 }, @@ -117,12 +129,18 @@ const styles = StyleSheet.create({ flex: 3, flexDirection: "row", alignItems: "center", + gap: 8, }, teamLogo: { width: 24, height: 24, resizeMode: "contain", }, + teamName: { + flex: 1, + fontSize: 14, + fontWeight: "500", + }, cellText: { flex: 1, textAlign: "center", diff --git a/components/match-detail/football/football-score-table.tsx b/components/match-detail/football/football-score-table.tsx new file mode 100644 index 0000000..e64f8a0 --- /dev/null +++ b/components/match-detail/football/football-score-table.tsx @@ -0,0 +1,141 @@ +import { ThemedText } from "@/components/themed-text"; +import { MatchDetailData } from "@/types/api"; +import React from "react"; +import { useTranslation } from "react-i18next"; +import { Image, StyleSheet, View } from "react-native"; + +interface FootballScoreTableProps { + data: MatchDetailData; + isDark: boolean; +} + +// 解析足球比分字符串,例如 "2-1" 或 "1-0" +function parseFootballScore(scoreString: string): number[] { + if (!scoreString || scoreString === "-") return [0, 0]; + const parts = scoreString.split("-"); + if (parts.length === 2) { + return [parseInt(parts[0]) || 0, parseInt(parts[1]) || 0]; + } + return [0, 0]; +} + +export function FootballScoreTable({ data, isDark }: FootballScoreTableProps) { + const { t } = useTranslation(); + const { match } = data; + const bgColor = isDark ? "#1C1C1E" : "#FFF"; + const headerTextColor = isDark ? "#666" : "#999"; + + // 解析足球比分 + const finalScore = parseFootballScore(match.eventFinalResult || "-"); + const halftimeScore = parseFootballScore(match.eventHalftimeResult || "-"); + + const headers = [ + t("detail.score_table.team"), + t("detail.score_table.total"), + t("detail.score_table.halftime"), + ]; + + const rows = [ + { + logo: match.homeTeamLogo, + name: match.eventHomeTeam, + total: finalScore[0], + halftime: halftimeScore[0], + }, + { + logo: match.awayTeamLogo, + name: match.eventAwayTeam, + total: finalScore[1], + halftime: halftimeScore[1], + }, + ]; + + return ( + + + {headers.map((h, i) => ( + + {h} + + ))} + + + {rows.map((row, idx) => ( + + + + + {row.name} + + + {row.total} + {row.halftime} + + ))} + + ); +} + +const styles = StyleSheet.create({ + container: { + margin: 16, + borderRadius: 12, + padding: 16, + elevation: 2, + shadowColor: "#000", + shadowOffset: { width: 0, height: 2 }, + shadowOpacity: 0.1, + shadowRadius: 4, + }, + header: { + flexDirection: "row", + paddingBottom: 12, + borderBottomWidth: StyleSheet.hairlineWidth, + borderBottomColor: "rgba(150,150,150,0.2)", + }, + headerText: { + fontSize: 12, + fontWeight: "500", + }, + row: { + flexDirection: "row", + alignItems: "center", + paddingVertical: 12, + }, + rowBorder: { + borderBottomWidth: StyleSheet.hairlineWidth, + borderBottomColor: "rgba(150,150,150,0.1)", + }, + teamCell: { + flex: 3, + flexDirection: "row", + alignItems: "center", + gap: 8, + }, + teamLogo: { + width: 24, + height: 24, + resizeMode: "contain", + }, + teamName: { + flex: 1, + fontSize: 14, + fontWeight: "500", + }, + cellText: { + flex: 1, + textAlign: "center", + fontSize: 14, + fontWeight: "500", + }, +}); diff --git a/components/match-detail/match-tabs.tsx b/components/match-detail/match-tabs.tsx index eb37553..412829c 100644 --- a/components/match-detail/match-tabs.tsx +++ b/components/match-detail/match-tabs.tsx @@ -7,17 +7,41 @@ interface MatchTabsProps { activeTab: string; onTabChange: (tab: string) => void; isDark: boolean; + sportId: number; } -export function MatchTabs({ activeTab, onTabChange, isDark }: MatchTabsProps) { +export function MatchTabs({ activeTab, onTabChange, isDark, sportId }: MatchTabsProps) { const { t } = useTranslation(); const containerBg = isDark ? "#121212" : "#F8F8F8"; - const tabs = [ - { id: "info", label: t("detail.tabs.info") }, - { id: "h2h", label: t("detail.tabs.h2h") }, - { id: "chat", label: t("detail.tabs.chat") }, - ]; + // 根据 sportId 动态生成标签 + const getTabs = () => { + if (sportId === 1) { + // 足球: 详情、统计数据、赔率、交锋往绩、聊天 + return [ + { id: "info", label: t("detail.tabs.info") }, + { id: "stats", label: t("detail.tabs.stats") }, + { id: "odds", label: t("detail.tabs.odds") }, + { id: "h2h", label: t("detail.tabs.h2h") }, + { id: "chat", label: t("detail.tabs.chat") }, + ]; + } else if (sportId === 2) { + // 篮球: 详情、交锋往绩、聊天 + return [ + { id: "info", label: t("detail.tabs.info") }, + { id: "h2h", label: t("detail.tabs.h2h") }, + { id: "chat", label: t("detail.tabs.chat") }, + ]; + } + // 默认: 详情、交锋往绩、聊天 + return [ + { id: "info", label: t("detail.tabs.info") }, + { id: "h2h", label: t("detail.tabs.h2h") }, + { id: "chat", label: t("detail.tabs.chat") }, + ]; + }; + + const tabs = getTabs(); return ( diff --git a/i18n/locales/en.json b/i18n/locales/en.json index 0ded263..00819f6 100644 --- a/i18n/locales/en.json +++ b/i18n/locales/en.json @@ -37,6 +37,8 @@ "not_found": "Match data not found", "tabs": { "info": "Details", + "stats": "Statistics", + "odds": "Odds", "h2h": "H2H", "chat": "Chat" }, @@ -50,9 +52,12 @@ }, "score_table": { "team": "Team", - "total": "Total" + "total": "Full Time", + "halftime": "Half Time" }, "halftime": "Half: {{score}}", + "empty_stats": "No statistics data", + "empty_odds": "No odds data", "empty_h2h": "No H2H data", "empty_chat": "Chat is not available" }, diff --git a/i18n/locales/zh.json b/i18n/locales/zh.json index a7b2a68..ca26b6d 100644 --- a/i18n/locales/zh.json +++ b/i18n/locales/zh.json @@ -37,6 +37,8 @@ "not_found": "未找到比赛数据", "tabs": { "info": "详情", + "stats": "统计数据", + "odds": "赔率", "h2h": "交锋往绩", "chat": "聊天" }, @@ -50,9 +52,12 @@ }, "score_table": { "team": "球队", - "total": "Total" + "total": "全场", + "halftime": "半场" }, "halftime": "半场: {{score}}", + "empty_stats": "暂无统计数据", + "empty_odds": "暂无赔率数据", "empty_h2h": "暂无交锋数据", "empty_chat": "聊天功能暂未开启" },