import { ThemedText } from "@/components/themed-text"; import { IconSymbol } from "@/components/ui/icon-symbol"; import { CardEvent, GoalEvent, MatchDetailData, Player, SubstituteEvent } from "@/types/api"; import React from "react"; import { useTranslation } from "react-i18next"; import { StyleSheet, View } from "react-native"; interface FootballEventsProps { data: MatchDetailData; isDark: boolean; } export function FootballEvents({ data, isDark }: FootballEventsProps) { const { t } = useTranslation(); const { match } = data; const bgColor = isDark ? "#1C1C1E" : "#FFF"; const borderColor = isDark ? "#2C2C2E" : "#EEE"; // events 可能在 data.events 或 match.events 中 const events = (data as any).events || (match as any).events; // 调试:打印 events 数据 if (__DEV__) { console.log("FootballEvents - events data:", events); } if (!events || typeof events !== "object") { if (__DEV__) { console.log("FootballEvents - No events data found"); } return null; } // 处理数组格式的 events(如果 events 是数组) let eventsObj = events; if (Array.isArray(events) && events.length > 0) { // 如果 events 是数组,取第一个元素 eventsObj = events[0]; } const goalscorers = eventsObj?.goalscorers || []; const cards = eventsObj?.cards || []; const substitutes = eventsObj?.substitutes || []; const players = (match as any).players || null; if (__DEV__) { console.log("FootballEvents - goalscorers:", goalscorers.length, "cards:", cards.length, "substitutes:", substitutes.length); } const hasEvents = goalscorers.length > 0 || cards.length > 0 || substitutes.length > 0; if (!hasEvents) { if (__DEV__) { console.log("FootballEvents - No events to display"); } return null; } const renderGoalEvent = (goal: GoalEvent, index: number) => { const isHome = !!goal.home_scorer; const scorerRaw = goal.home_scorer || goal.away_scorer || ""; const isPenalty = scorerRaw.includes("(pen.)"); const playerName = scorerRaw.replace("(pen.)", "").trim(); return ( {goal.time ? `${goal.time}'` : ""} {playerName && ( {playerName} )} {isPenalty && ( P )} {goal.score && ( {goal.score} )} ); }; const renderCardEvent = (card: CardEvent, index: number) => { const isHome = !!card.home_fault; const cardType = card.card?.toLowerCase() || ""; const isRed = cardType.includes("red"); const isYellow = cardType.includes("yellow"); const cardColor = isRed ? "#F44336" : isYellow ? "#FFC107" : "#9E9E9E"; const playerName = card.home_fault || card.away_fault || ""; return ( {card.time ? `${card.time}'` : ""} {playerName} {card.card && ( {isRed ? t("detail.events.red_card") : isYellow ? t("detail.events.yellow_card") : card.card} )} ); }; const renderSubstituteEvent = (sub: SubstituteEvent, index: number) => { // 辅助函数:从字段中提取字符串值(可能是字符串、数组或对象) const extractPlayerName = (value: any): string => { if (!value) return ""; // 如果是字符串,直接返回 if (typeof value === "string") return value; // 如果是数组,取第一个元素 if (Array.isArray(value)) { if (value.length === 0) return ""; const firstItem = value[0]; // 如果数组元素是对象,提取 in 或 out if (typeof firstItem === "object" && firstItem !== null) { return String(firstItem.in || firstItem.out || firstItem.player || ""); } return String(firstItem); } // 如果是对象,提取 in 或 out 字段 if (typeof value === "object" && value !== null) { return String(value.in || value.out || value.player || ""); } return String(value); }; // 提取换入和换出球员名称 let playerIn = ""; let playerOut = ""; let isHome = false; // 优先处理 home_scorer(可能是对象 {in, out} 或数组) const homeScorerData = (sub as any).home_scorer; if (homeScorerData) { isHome = true; if (typeof homeScorerData === "object" && !Array.isArray(homeScorerData) && "in" in homeScorerData) { // 对象格式:{in: "球员名", out: "球员名", in_id, out_id} playerIn = String(homeScorerData.in || ""); playerOut = String(homeScorerData.out || ""); } else if (Array.isArray(homeScorerData) && homeScorerData.length > 0) { // 数组格式:取第一个元素 const firstItem = homeScorerData[0]; if (typeof firstItem === "object" && firstItem !== null && "in" in firstItem) { playerIn = String(firstItem.in || ""); playerOut = String(firstItem.out || ""); } else { playerIn = extractPlayerName(firstItem); } } else { playerIn = extractPlayerName(homeScorerData); } } // 处理 away_scorer(可能是对象 {in, out} 或数组) const awayScorerData = (sub as any).away_scorer; if (awayScorerData && !playerIn) { isHome = false; if (typeof awayScorerData === "object" && !Array.isArray(awayScorerData) && "in" in awayScorerData) { // 对象格式:{in: "球员名", out: "球员名", in_id, out_id} playerIn = String(awayScorerData.in || ""); playerOut = String(awayScorerData.out || ""); } else if (Array.isArray(awayScorerData) && awayScorerData.length > 0) { // 数组格式:取第一个元素 const firstItem = awayScorerData[0]; if (typeof firstItem === "object" && firstItem !== null && "in" in firstItem) { playerIn = String(firstItem.in || ""); playerOut = String(firstItem.out || ""); } else { playerIn = extractPlayerName(firstItem); } } else { playerIn = extractPlayerName(awayScorerData); } } // 如果还没有提取到换出球员,尝试从其他字段获取 if (!playerOut) { playerOut = extractPlayerName(sub.home_scorer_out || sub.away_scorer_out || sub.home_assist || sub.away_assist); } return ( {sub.time ? `${sub.time}'` : ""} {playerOut ? ( <> {playerIn} {playerOut} ) : ( {playerIn} )} ); }; return ( {goalscorers.length > 0 && ( {t("detail.events.goals")} {goalscorers .filter((goal: GoalEvent) => goal.home_scorer || goal.away_scorer) .map((goal: GoalEvent, index: number) => renderGoalEvent(goal, index))} )} {cards.length > 0 && ( {t("detail.events.cards")} {cards .filter((card: CardEvent) => card.home_fault || card.away_fault) .map((card: CardEvent, index: number) => renderCardEvent(card, index))} )} {substitutes.length > 0 && ( {t("detail.events.substitutes")} {substitutes .filter((sub: SubstituteEvent) => sub.home_scorer || sub.away_scorer || sub.home_assist || sub.away_assist) .map((sub: SubstituteEvent, index: number) => renderSubstituteEvent(sub, index))} )} {players && (players.home_team || players.away_team) && ( {t("detail.events.lineups")} {players.home_team && Array.isArray(players.home_team) && players.home_team.length > 0 && ( {match.eventHomeTeam} {players.home_team.slice(0, 11).map((player: Player, idx: number) => ( {player.player_number || player.number || idx + 1} {player.player_name || player.player || player.name || ""} {player.position && ( {player.position} )} ))} )} {players.away_team && Array.isArray(players.away_team) && players.away_team.length > 0 && ( {match.eventAwayTeam} {players.away_team.slice(0, 11).map((player: Player, idx: number) => ( {player.player_number || player.number || idx + 1} {player.player_name || player.player || player.name || ""} {player.position && ( {player.position} )} ))} )} )} ); } const styles = StyleSheet.create({ container: { margin: 16, marginTop: 0, borderRadius: 12, padding: 16, borderWidth: 1, elevation: 2, shadowColor: "#000", shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, }, section: { marginBottom: 20, }, sectionTitle: { fontSize: 14, fontWeight: "600", marginBottom: 12, opacity: 0.7, }, eventRow: { flexDirection: "row", alignItems: "center", paddingVertical: 8, borderBottomWidth: StyleSheet.hairlineWidth, }, eventTime: { width: 40, alignItems: "center", }, timeText: { fontSize: 12, fontWeight: "500", opacity: 0.6, }, eventContent: { flex: 1, flexDirection: "row", alignItems: "center", gap: 8, paddingLeft: 12, }, homeEvent: { justifyContent: "flex-start", }, awayEvent: { justifyContent: "flex-end", flexDirection: "row-reverse", }, eventText: { fontSize: 13, fontWeight: "500", flex: 1, }, scoreText: { fontSize: 12, fontWeight: "600", opacity: 0.7, }, cardIcon: { width: 12, height: 16, borderRadius: 2, }, cardTypeText: { fontSize: 10, fontWeight: "600", textTransform: "uppercase", }, cardBadge: { paddingHorizontal: 6, paddingVertical: 2, borderRadius: 4, }, goalContent: { flex: 1, flexDirection: "row", alignItems: "center", gap: 6, }, penaltyBadge: { width: 18, height: 18, borderRadius: 9, backgroundColor: "#FF9800", alignItems: "center", justifyContent: "center", }, penaltyText: { fontSize: 10, fontWeight: "700", color: "#FFF", }, substituteContent: { flex: 1, flexDirection: "row", alignItems: "center", gap: 6, }, substituteIn: { fontSize: 13, fontWeight: "500", }, substituteArrow: { fontSize: 12, opacity: 0.5, }, substituteOut: { fontSize: 13, fontWeight: "500", opacity: 0.6, textDecorationLine: "line-through", }, teamLineup: { marginTop: 8, }, teamName: { fontSize: 13, fontWeight: "600", marginBottom: 8, opacity: 0.8, }, playerRow: { flexDirection: "row", alignItems: "center", paddingVertical: 4, gap: 8, }, playerNumber: { fontSize: 12, fontWeight: "600", width: 24, textAlign: "center", opacity: 0.6, }, playerName: { fontSize: 13, fontWeight: "500", flex: 1, }, playerPosition: { fontSize: 11, fontWeight: "500", opacity: 0.5, textTransform: "uppercase", }, });