diff --git a/components/match-detail/football/lineups-card.tsx b/components/match-detail/football/lineups-card.tsx index 675a142..970e1cf 100644 --- a/components/match-detail/football/lineups-card.tsx +++ b/components/match-detail/football/lineups-card.tsx @@ -21,62 +21,379 @@ export function LineupsCard({ data, isDark }: LineupsCardProps) { return null; } - const hasLineups = - (players.home_team && Array.isArray(players.home_team) && players.home_team.length > 0) || - (players.away_team && Array.isArray(players.away_team) && players.away_team.length > 0); + // 兼容两种结构: + // 1) home_team/away_team 直接是球员数组 + // 2) home_team/away_team 是对象,包含 starting_lineups/substitutes/coaches 等 + const getTeamData = (team: any) => { + const starting: any[] = []; + const subs: any[] = []; + let coachName: string | undefined; + let coachCountry: string | undefined; + + if (!team) { + return { starting, subs, coachName, coachCountry }; + } + + if (Array.isArray(team)) { + // 旧结构:直接数组 = 首发 + return { starting: team, subs, coachName, coachCountry }; + } + + if (Array.isArray(team.starting_lineups)) { + starting.push(...team.starting_lineups); + } + if (Array.isArray(team.substitutes)) { + subs.push(...team.substitutes); + } + if (Array.isArray(team.coaches) && team.coaches.length > 0) { + const c = team.coaches[0]; + coachName = c?.coache || c?.name; + coachCountry = c?.coache_country || c?.country; + } + + return { starting, subs, coachName, coachCountry }; + }; + + const home = getTeamData(players.home_team); + const away = getTeamData(players.away_team); + + const hasLineups = home.starting.length > 0 || away.starting.length > 0; if (!hasLineups) { return null; } + const getPlayerNumber = (p: any, idx: number) => + p?.player_number ?? p?.number ?? p?.playerNumber ?? idx + 1; + + const getPlayerName = (p: any) => + p?.player_name ?? p?.player ?? p?.name ?? p?.playerName ?? ""; + + const getPlayerPosition = (p: any) => + p?.position ?? p?.player_type ?? p?.player_position ?? ""; + + const splitByPosition = (list: any[]) => { + const gk: any[] = []; + const def: any[] = []; + const mid: any[] = []; + const fwd: any[] = []; + + list.forEach((p) => { + const pos = Number(p?.player_position ?? p?.positionCode ?? 0); + if (pos === 1) { + gk.push(p); + } else if (pos >= 2 && pos <= 5) { + def.push(p); + } else if (pos >= 6 && pos <= 8) { + mid.push(p); + } else if (pos >= 9 && pos <= 11) { + fwd.push(p); + } else { + // 没有合理编号的,放到中场组兜底 + mid.push(p); + } + }); + + return { gk, def, mid, fwd }; + }; + return ( {t("detail.events.lineups")} - {players.home_team && Array.isArray(players.home_team) && players.home_team.length > 0 && ( + {/* 主队首发 */} + {home.starting.length > 0 && ( {match.eventHomeTeam} - {players.home_team.slice(0, 11).map((player: Player, idx: number) => ( - - - {player.player_number || player.number || idx + 1} + {(() => { + const groups = splitByPosition(home.starting.slice(0, 11)); + return ( + <> + {groups.gk.length > 0 && ( + + + {t("detail.events.lineups_goalkeepers")} + + {groups.gk.map((player: Player, idx: number) => ( + + + {getPlayerNumber(player, idx)} + + + {getPlayerName(player)} + + {!!getPlayerPosition(player) && ( + + {String(getPlayerPosition(player))} + + )} + + ))} + + )} + {groups.def.length > 0 && ( + + + {t("detail.events.lineups_defenders")} + + {groups.def.map((player: Player, idx: number) => ( + + + {getPlayerNumber(player, idx)} + + + {getPlayerName(player)} + + {!!getPlayerPosition(player) && ( + + {String(getPlayerPosition(player))} + + )} + + ))} + + )} + {groups.mid.length > 0 && ( + + + {t("detail.events.lineups_midfielders")} + + {groups.mid.map((player: Player, idx: number) => ( + + + {getPlayerNumber(player, idx)} + + + {getPlayerName(player)} + + {!!getPlayerPosition(player) && ( + + {String(getPlayerPosition(player))} + + )} + + ))} + + )} + {groups.fwd.length > 0 && ( + + + {t("detail.events.lineups_forwards")} + + {groups.fwd.map((player: Player, idx: number) => ( + + + {getPlayerNumber(player, idx)} + + + {getPlayerName(player)} + + {!!getPlayerPosition(player) && ( + + {String(getPlayerPosition(player))} + + )} + + ))} + + )} + + ); + })()} + + {home.coachName && ( + + + {t("detail.events.lineups_coach")}: - - {player.player_name || player.player || player.name || ""} + + {home.coachName} + {home.coachCountry ? ` (${home.coachCountry})` : ""} - {player.position && ( - - {player.position} - - )} - ))} + )} + + {Array.isArray(home.subs) && home.subs.length > 0 && ( + + + {t("detail.events.lineups_subs")} + + {home.subs.map((p: any, idx: number) => ( + + + {getPlayerNumber(p, idx)} + + + {getPlayerName(p)} + + + ))} + + )} )} - {players.away_team && Array.isArray(players.away_team) && players.away_team.length > 0 && ( + {/* 客队首发 */} + {away.starting.length > 0 && ( - + {match.eventAwayTeam} - {players.away_team.slice(0, 11).map((player: Player, idx: number) => ( - - - {player.player_number || player.number || idx + 1} + {(() => { + const groups = splitByPosition(away.starting.slice(0, 11)); + return ( + <> + {groups.gk.length > 0 && ( + + + {t("detail.events.lineups_goalkeepers")} + + {groups.gk.map((player: Player, idx: number) => ( + + {!!getPlayerPosition(player) && ( + + {String(getPlayerPosition(player))} + + )} + + {getPlayerName(player)} + + + {getPlayerNumber(player, idx)} + + + ))} + + )} + {groups.def.length > 0 && ( + + + {t("detail.events.lineups_defenders")} + + {groups.def.map((player: Player, idx: number) => ( + + {!!getPlayerPosition(player) && ( + + {String(getPlayerPosition(player))} + + )} + + {getPlayerName(player)} + + + {getPlayerNumber(player, idx)} + + + ))} + + )} + {groups.mid.length > 0 && ( + + + {t("detail.events.lineups_midfielders")} + + {groups.mid.map((player: Player, idx: number) => ( + + {!!getPlayerPosition(player) && ( + + {String(getPlayerPosition(player))} + + )} + + {getPlayerName(player)} + + + {getPlayerNumber(player, idx)} + + + ))} + + )} + {groups.fwd.length > 0 && ( + + + {t("detail.events.lineups_forwards")} + + {groups.fwd.map((player: Player, idx: number) => ( + + {!!getPlayerPosition(player) && ( + + {String(getPlayerPosition(player))} + + )} + + {getPlayerName(player)} + + + {getPlayerNumber(player, idx)} + + + ))} + + )} + + ); + })()} + + {away.coachName && ( + + + {t("detail.events.lineups_coach")}: - - {player.player_name || player.player || player.name || ""} + + {away.coachName} + {away.coachCountry ? ` (${away.coachCountry})` : ""} - {player.position && ( - - {player.position} - - )} - ))} + )} + + {Array.isArray(away.subs) && away.subs.length > 0 && ( + + + {t("detail.events.lineups_subs")} + + {away.subs.map((p: any, idx: number) => ( + + + {getPlayerName(p)} + + + {getPlayerNumber(p, idx)} + + + ))} + + )} )} @@ -100,11 +417,11 @@ const styles = StyleSheet.create({ title: { fontSize: 14, fontWeight: "600", - marginBottom: 12, + marginBottom: 14, opacity: 0.7, }, content: { - gap: 0, + gap: 6, }, teamLineup: { marginTop: 8, @@ -115,12 +432,19 @@ const styles = StyleSheet.create({ marginBottom: 8, opacity: 0.8, }, + awayTeamName: { + textAlign: "right", + }, playerRow: { flexDirection: "row", alignItems: "center", paddingVertical: 4, gap: 8, }, + awayPlayerRow: { + flexDirection: "row", + justifyContent: "flex-end", + }, playerNumber: { fontSize: 12, fontWeight: "600", @@ -139,4 +463,44 @@ const styles = StyleSheet.create({ opacity: 0.5, textTransform: "uppercase", }, + awayText: { + textAlign: "right", + }, + awayNumber: { + textAlign: "right", + }, + // 每条线(守门员/后卫/中场/前锋)的容器 + lineGroup: { + marginBottom: 8, + }, + lineGroupTitle: { + fontSize: 12, + fontWeight: "600", + opacity: 0.7, + marginBottom: 6, + }, + // 主/客队教练行 + coachRow: { + flexDirection: "row", + alignItems: "center", + marginTop: 12, + gap: 6, + }, + coachLabel: { + fontSize: 12, + opacity: 0.7, + }, + coachValue: { + fontSize: 12, + fontWeight: "500", + }, + // 替补区 + subsSection: { + marginTop: 12, + }, + subsTitle: { + fontSize: 12, + opacity: 0.7, + marginBottom: 6, + }, }); diff --git a/i18n/locales/en.json b/i18n/locales/en.json index b8e4e75..03ad2c1 100644 --- a/i18n/locales/en.json +++ b/i18n/locales/en.json @@ -74,7 +74,14 @@ "substitutes": "Substitutes", "lineups": "Lineups", "red_card": "RED", - "yellow_card": "YELLOW" + "yellow_card": "YELLOW", + "lineups_goalkeepers": "Goalkeepers", + "lineups_defenders": "Defenders", + "lineups_midfielders": "Midfielders", + "lineups_forwards": "Forwards", + "lineups_coach": "Coach", + "lineups_subs": "Substitutes", + "lineups_missing": "Missing players" } }, "selection": { diff --git a/i18n/locales/zh.json b/i18n/locales/zh.json index 528e0c5..0bf677c 100644 --- a/i18n/locales/zh.json +++ b/i18n/locales/zh.json @@ -74,7 +74,14 @@ "substitutes": "换人", "lineups": "首发阵容", "red_card": "红牌", - "yellow_card": "黄牌" + "yellow_card": "黄牌", + "lineups_goalkeepers": "守门员", + "lineups_defenders": "后卫", + "lineups_midfielders": "中场", + "lineups_forwards": "前锋", + "lineups_coach": "主教练", + "lineups_subs": "替补球员", + "lineups_missing": "缺席球员" } }, "selection": {