网球详情页

This commit is contained in:
xianyi
2026-01-22 14:05:39 +08:00
parent 9e7f8dadec
commit a279083252
13 changed files with 443 additions and 46 deletions

View File

@@ -0,0 +1,205 @@
import { ThemedText } from "@/components/themed-text";
import { MatchDetailData } from "@/types/api";
import { Image } from "expo-image";
import React from "react";
import { useTranslation } from "react-i18next";
import { StyleSheet, View } from "react-native";
import { LinearGradient } from "expo-linear-gradient";
import { getInitials, getLogoGradient } from "@/lib/avatar-utils";
interface TennisScoreTableProps {
data: MatchDetailData;
isDark: boolean;
}
export function TennisScoreTable({ data, isDark }: TennisScoreTableProps) {
const { t } = useTranslation();
const { match } = data;
const bgColor = isDark ? "#1C1C1E" : "#FFF";
const borderColor = isDark ? "#2C2C2E" : "rgba(0,0,0,0.06)";
const headerTextColor = isDark ? "#666" : "#999";
const textColor = isDark ? "#FFF" : "#000";
const isTennis = match.sportId === 3;
const scores = (match.scores as any) || [];
const firstPlayer = match.eventFirstPlayer || "";
const secondPlayer = match.eventSecondPlayer || "";
const firstPlayerLogo = match.eventFirstPlayerLogo || "";
const secondPlayerLogo = match.eventSecondPlayerLogo || "";
const hasFirstLogo = firstPlayerLogo && firstPlayerLogo.trim() !== "" && !firstPlayerLogo.includes("placehold");
const hasSecondLogo = secondPlayerLogo && secondPlayerLogo.trim() !== "" && !secondPlayerLogo.includes("placehold");
const firstGradient = getLogoGradient(firstPlayer);
const secondGradient = getLogoGradient(secondPlayer);
const firstInitials = getInitials(firstPlayer);
const secondInitials = getInitials(secondPlayer);
const headers = [t("detail.score_table.set") || "Set"];
scores.forEach((_, index) => {
headers.push(`${index + 1}`);
});
if (scores.length === 0) {
headers.push("1");
}
return (
<View style={[styles.container, { backgroundColor: bgColor, borderColor }]}>
<View style={[styles.header, { borderBottomColor: borderColor }]}>
<View style={styles.headerLeft}>
<ThemedText style={[styles.headerText, { color: headerTextColor }]}>
{t("detail.score_table.player") || "Player"}
</ThemedText>
</View>
{headers.slice(1).map((header, index) => (
<View key={index} style={styles.headerCell}>
<ThemedText style={[styles.headerText, { color: headerTextColor }]}>
{header}
</ThemedText>
</View>
))}
</View>
<View style={[styles.row, { borderBottomColor: borderColor }]}>
<View style={styles.playerCell}>
{hasFirstLogo ? (
<Image source={{ uri: firstPlayerLogo }} style={styles.playerLogo} />
) : (
<LinearGradient
colors={[firstGradient.color1, firstGradient.color2]}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
style={styles.playerLogoGradient}
>
<ThemedText style={styles.playerLogoText}>{firstInitials}</ThemedText>
</LinearGradient>
)}
<ThemedText style={[styles.playerName, { color: textColor }]} numberOfLines={1}>
{firstPlayer}
</ThemedText>
</View>
{scores.length > 0 ? (
scores.map((score: any, index: number) => (
<View key={index} style={styles.scoreCell}>
<ThemedText style={[styles.scoreText, { color: textColor }]}>
{score.score_first || "0"}
</ThemedText>
</View>
))
) : (
<View style={styles.scoreCell}>
<ThemedText style={[styles.scoreText, { color: textColor }]}>0</ThemedText>
</View>
)}
</View>
<View style={styles.row}>
<View style={styles.playerCell}>
{hasSecondLogo ? (
<Image source={{ uri: secondPlayerLogo }} style={styles.playerLogo} />
) : (
<LinearGradient
colors={[secondGradient.color1, secondGradient.color2]}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
style={styles.playerLogoGradient}
>
<ThemedText style={styles.playerLogoText}>{secondInitials}</ThemedText>
</LinearGradient>
)}
<ThemedText style={[styles.playerName, { color: textColor }]} numberOfLines={1}>
{secondPlayer}
</ThemedText>
</View>
{scores.length > 0 ? (
scores.map((score: any, index: number) => (
<View key={index} style={styles.scoreCell}>
<ThemedText style={[styles.scoreText, { color: textColor }]}>
{score.score_second || "0"}
</ThemedText>
</View>
))
) : (
<View style={styles.scoreCell}>
<ThemedText style={[styles.scoreText, { color: textColor }]}>0</ThemedText>
</View>
)}
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
marginHorizontal: 16,
marginTop: 12,
borderRadius: 16,
borderWidth: 1,
overflow: "hidden",
},
header: {
flexDirection: "row",
borderBottomWidth: 1,
paddingVertical: 12,
paddingHorizontal: 12,
},
headerLeft: {
flex: 1,
minWidth: 120,
},
headerCell: {
flex: 1,
alignItems: "center",
justifyContent: "center",
minWidth: 40,
},
headerText: {
fontSize: 12,
fontWeight: "600",
},
row: {
flexDirection: "row",
borderBottomWidth: 1,
paddingVertical: 12,
paddingHorizontal: 12,
alignItems: "center",
},
playerCell: {
flex: 1,
flexDirection: "row",
alignItems: "center",
minWidth: 120,
gap: 8,
},
playerLogo: {
width: 32,
height: 32,
borderRadius: 16,
},
playerLogoGradient: {
width: 32,
height: 32,
borderRadius: 16,
alignItems: "center",
justifyContent: "center",
},
playerLogoText: {
fontSize: 10,
fontWeight: "700",
color: "rgba(255, 255, 255, 0.92)",
},
playerName: {
flex: 1,
fontSize: 13,
fontWeight: "600",
},
scoreCell: {
flex: 1,
alignItems: "center",
justifyContent: "center",
minWidth: 40,
},
scoreText: {
fontSize: 15,
fontWeight: "700",
},
});