网球详情页
This commit is contained in:
@@ -10,6 +10,7 @@ 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 { TennisScoreTable } from "@/components/match-detail/tennis/tennis-score-table";
|
||||
import { ThemedText } from "@/components/themed-text";
|
||||
import { ThemedView } from "@/components/themed-view";
|
||||
import { Colors } from "@/constants/theme";
|
||||
@@ -52,18 +53,21 @@ export default function MatchDetailScreen() {
|
||||
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 if (sportId === 3) {
|
||||
// 网球
|
||||
validTabs = ["info", "chat"];
|
||||
} else {
|
||||
// 默认
|
||||
validTabs = ["info", "h2h", "chat"];
|
||||
}
|
||||
|
||||
|
||||
// 如果当前 activeTab 不在有效标签列表中,重置为第一个
|
||||
if (!validTabs.includes(activeTab)) {
|
||||
setActiveTab(validTabs[0]);
|
||||
@@ -77,11 +81,11 @@ export default function MatchDetailScreen() {
|
||||
setError(null);
|
||||
const result = await fetchMatchDetail(id as string);
|
||||
setData(result);
|
||||
console.log("首发阵容" , result.match.players?.away_team);
|
||||
console.log("首发阵容", result.match.players?.away_team);
|
||||
console.log("红黄牌", result.events);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} catch (err: any) {
|
||||
setError(err.message || t("detail.fetch_failed"));
|
||||
} finally {
|
||||
@@ -130,6 +134,14 @@ export default function MatchDetailScreen() {
|
||||
<MatchInfoCard data={data} isDark={isDark} />
|
||||
</>
|
||||
);
|
||||
} else if (sportId === 3) {
|
||||
// 网球:显示 TennisScoreTable 和 MatchInfoCard
|
||||
return (
|
||||
<>
|
||||
<TennisScoreTable data={data} isDark={isDark} />
|
||||
<MatchInfoCard data={data} isDark={isDark} />
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
// 默认使用足球组件
|
||||
return (
|
||||
|
||||
@@ -65,6 +65,16 @@ export function MatchTabs({
|
||||
} else if (sportId === 2) {
|
||||
// 篮球
|
||||
return commonTabs;
|
||||
} else if (sportId === 3) {
|
||||
// 网球: 详情、聊天
|
||||
return [
|
||||
{
|
||||
id: "info",
|
||||
label: t("detail.tabs.info"),
|
||||
icon: "document-text-outline",
|
||||
},
|
||||
{ id: "chat", label: t("detail.tabs.chat"), icon: "chatbubbles-outline" },
|
||||
];
|
||||
}
|
||||
return commonTabs;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ThemedText } from "@/components/themed-text";
|
||||
import { IconSymbol } from "@/components/ui/icon-symbol";
|
||||
import { addFavorite, checkFavorite, removeFavorite } from "@/lib/api";
|
||||
import { getInitials, getLogoGradient } from "@/lib/avatar-utils";
|
||||
import { storage } from "@/lib/storage";
|
||||
import { MatchDetailData } from "@/types/api";
|
||||
import { LinearGradient } from "expo-linear-gradient";
|
||||
@@ -19,6 +20,7 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
const { match } = data;
|
||||
const isTennis = match.sportId === 3;
|
||||
|
||||
const [isFav, setIsFav] = useState(false);
|
||||
const [favLoading, setFavLoading] = useState(false);
|
||||
@@ -45,39 +47,45 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
||||
}
|
||||
}, [match.eventKey]);
|
||||
|
||||
// 检查主队收藏状态
|
||||
// 检查主队/第一球员收藏状态
|
||||
React.useEffect(() => {
|
||||
const loadHomeFav = async () => {
|
||||
const token = await storage.getAccessToken();
|
||||
if (!token) return;
|
||||
try {
|
||||
const res = await checkFavorite("team", match.homeTeamKey.toString());
|
||||
setIsHomeFav(res.isFavorite);
|
||||
const teamKey = isTennis ? match.firstPlayerKey : match.homeTeamKey;
|
||||
if (teamKey) {
|
||||
const res = await checkFavorite("team", teamKey.toString());
|
||||
setIsHomeFav(res.isFavorite);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Check home team favorite status error:", error);
|
||||
}
|
||||
};
|
||||
if (match.homeTeamKey) {
|
||||
if (isTennis ? match.firstPlayerKey : match.homeTeamKey) {
|
||||
loadHomeFav();
|
||||
}
|
||||
}, [match.homeTeamKey]);
|
||||
}, [match.homeTeamKey, match.firstPlayerKey, isTennis]);
|
||||
|
||||
// 检查客队收藏状态
|
||||
// 检查客队/第二球员收藏状态
|
||||
React.useEffect(() => {
|
||||
const loadAwayFav = async () => {
|
||||
const token = await storage.getAccessToken();
|
||||
if (!token) return;
|
||||
try {
|
||||
const res = await checkFavorite("team", match.awayTeamKey.toString());
|
||||
setIsAwayFav(res.isFavorite);
|
||||
const teamKey = isTennis ? match.secondPlayerKey : match.awayTeamKey;
|
||||
if (teamKey) {
|
||||
const res = await checkFavorite("team", teamKey.toString());
|
||||
setIsAwayFav(res.isFavorite);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Check away team favorite status error:", error);
|
||||
}
|
||||
};
|
||||
if (match.awayTeamKey) {
|
||||
if (isTennis ? match.secondPlayerKey : match.awayTeamKey) {
|
||||
loadAwayFav();
|
||||
}
|
||||
}, [match.awayTeamKey]);
|
||||
}, [match.awayTeamKey, match.secondPlayerKey, isTennis]);
|
||||
|
||||
const toggleFavorite = async () => {
|
||||
if (favLoading) return;
|
||||
@@ -111,7 +119,7 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
||||
const setFav = isHome ? setIsHomeFav : setIsAwayFav;
|
||||
const loading = isHome ? homeFavLoading : awayFavLoading;
|
||||
|
||||
if (loading) return;
|
||||
if (loading || !teamKey) return;
|
||||
setLoading(true);
|
||||
|
||||
const newFavState = !isTeamFav;
|
||||
@@ -137,6 +145,36 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
||||
}
|
||||
};
|
||||
|
||||
const getScoreDisplay = () => {
|
||||
if (isTennis) {
|
||||
const scores = (match.scores as any) || [];
|
||||
if (scores.length > 0) {
|
||||
const lastSet = scores[scores.length - 1];
|
||||
return `${lastSet.score_first || "0"}-${lastSet.score_second || "0"}`;
|
||||
}
|
||||
return match.eventGameResult && match.eventGameResult !== "-"
|
||||
? match.eventGameResult
|
||||
: "0-0";
|
||||
}
|
||||
return match.eventFinalResult && match.eventFinalResult !== "-"
|
||||
? match.eventFinalResult
|
||||
: "0-0";
|
||||
};
|
||||
|
||||
const firstPlayerName = isTennis ? match.eventFirstPlayer : match.eventHomeTeam;
|
||||
const secondPlayerName = isTennis ? match.eventSecondPlayer : match.eventAwayTeam;
|
||||
const firstPlayerLogo = isTennis ? match.eventFirstPlayerLogo : match.homeTeamLogo;
|
||||
const secondPlayerLogo = isTennis ? match.eventSecondPlayerLogo : match.awayTeamLogo;
|
||||
const firstPlayerKey = isTennis ? match.firstPlayerKey : match.homeTeamKey;
|
||||
const secondPlayerKey = isTennis ? match.secondPlayerKey : match.awayTeamKey;
|
||||
|
||||
const hasFirstLogo = firstPlayerLogo && firstPlayerLogo.trim() !== "" && !firstPlayerLogo.includes("placehold");
|
||||
const hasSecondLogo = secondPlayerLogo && secondPlayerLogo.trim() !== "" && !secondPlayerLogo.includes("placehold");
|
||||
const firstGradient = getLogoGradient(firstPlayerName || "");
|
||||
const secondGradient = getLogoGradient(secondPlayerName || "");
|
||||
const firstInitials = getInitials(firstPlayerName || "");
|
||||
const secondInitials = getInitials(secondPlayerName || "");
|
||||
|
||||
return (
|
||||
<LinearGradient
|
||||
colors={["#521e10", "#0e0e10"]}
|
||||
@@ -184,8 +222,12 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
||||
<View style={styles.teamInfo}>
|
||||
<View style={styles.teamLogoRow}>
|
||||
<TouchableOpacity
|
||||
onPress={() => toggleTeamFavorite(match.homeTeamKey, true)}
|
||||
disabled={homeFavLoading}
|
||||
onPress={() => {
|
||||
if (firstPlayerKey) {
|
||||
toggleTeamFavorite(firstPlayerKey, true);
|
||||
}
|
||||
}}
|
||||
disabled={homeFavLoading || !firstPlayerKey}
|
||||
style={styles.starBtnLeft}
|
||||
>
|
||||
<IconSymbol
|
||||
@@ -195,41 +237,69 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<View style={styles.logoContainer}>
|
||||
<Image
|
||||
source={{ uri: match.homeTeamLogo }}
|
||||
style={styles.teamLogo}
|
||||
/>
|
||||
{hasFirstLogo ? (
|
||||
<Image
|
||||
source={{ uri: firstPlayerLogo }}
|
||||
style={styles.teamLogo}
|
||||
/>
|
||||
) : (
|
||||
<LinearGradient
|
||||
colors={[firstGradient.color1, firstGradient.color2]}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
style={styles.teamLogoGradient}
|
||||
>
|
||||
<ThemedText style={styles.teamLogoText}>{firstInitials}</ThemedText>
|
||||
</LinearGradient>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
<ThemedText style={styles.teamName} numberOfLines={2}>
|
||||
{match.eventHomeTeam}
|
||||
{firstPlayerName}
|
||||
</ThemedText>
|
||||
</View>
|
||||
|
||||
<View style={styles.centerScore}>
|
||||
<View style={styles.scoreBox}>
|
||||
<ThemedText style={styles.scoreValue}>
|
||||
{match.eventFinalResult && match.eventFinalResult !== "-"
|
||||
? match.eventFinalResult
|
||||
: "0-0"}
|
||||
{getScoreDisplay()}
|
||||
</ThemedText>
|
||||
</View>
|
||||
<TouchableOpacity style={styles.fieldBtn}>
|
||||
<IconSymbol name="football-outline" size={16} color="#FFF" />
|
||||
<IconSymbol
|
||||
name={isTennis ? "tennisball-outline" : "football-outline"}
|
||||
size={16}
|
||||
color="#FFF"
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<View style={styles.teamInfo}>
|
||||
<View style={styles.teamLogoRow}>
|
||||
<View style={styles.logoContainer}>
|
||||
<Image
|
||||
source={{ uri: match.awayTeamLogo }}
|
||||
style={styles.teamLogo}
|
||||
/>
|
||||
{hasSecondLogo ? (
|
||||
<Image
|
||||
source={{ uri: secondPlayerLogo }}
|
||||
style={styles.teamLogo}
|
||||
/>
|
||||
) : (
|
||||
<LinearGradient
|
||||
colors={[secondGradient.color1, secondGradient.color2]}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
style={styles.teamLogoGradient}
|
||||
>
|
||||
<ThemedText style={styles.teamLogoText}>{secondInitials}</ThemedText>
|
||||
</LinearGradient>
|
||||
)}
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
onPress={() => toggleTeamFavorite(match.awayTeamKey, false)}
|
||||
disabled={awayFavLoading}
|
||||
onPress={() => {
|
||||
if (secondPlayerKey) {
|
||||
toggleTeamFavorite(secondPlayerKey, false);
|
||||
}
|
||||
}}
|
||||
disabled={awayFavLoading || !secondPlayerKey}
|
||||
style={styles.starBtnRight}
|
||||
>
|
||||
<IconSymbol
|
||||
@@ -240,7 +310,7 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<ThemedText style={styles.teamName} numberOfLines={2}>
|
||||
{match.eventAwayTeam}
|
||||
{secondPlayerName}
|
||||
</ThemedText>
|
||||
</View>
|
||||
</View>
|
||||
@@ -326,6 +396,19 @@ const styles = StyleSheet.create({
|
||||
width: 60,
|
||||
height: 60,
|
||||
resizeMode: "contain",
|
||||
borderRadius: 30,
|
||||
},
|
||||
teamLogoGradient: {
|
||||
width: 60,
|
||||
height: 60,
|
||||
borderRadius: 30,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
teamLogoText: {
|
||||
fontSize: 20,
|
||||
fontWeight: "700",
|
||||
color: "rgba(255, 255, 255, 0.92)",
|
||||
},
|
||||
teamName: {
|
||||
color: "#FFF",
|
||||
|
||||
205
components/match-detail/tennis/tennis-score-table.tsx
Normal file
205
components/match-detail/tennis/tennis-score-table.tsx
Normal 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",
|
||||
},
|
||||
});
|
||||
@@ -115,7 +115,8 @@
|
||||
"halftime": "Half Time",
|
||||
"full_time": "90'",
|
||||
"extra_time": "ET",
|
||||
"penalty": "Pen"
|
||||
"penalty": "Pen",
|
||||
"player": "Player"
|
||||
},
|
||||
"halftime": "Half: {{score}}",
|
||||
"empty_stats": "No statistics data",
|
||||
|
||||
@@ -111,7 +111,8 @@
|
||||
"halftime": "हाफ टाइम",
|
||||
"full_time": "90'",
|
||||
"extra_time": "अतिरिक्त समय",
|
||||
"penalty": "पेनल्टी"
|
||||
"penalty": "पेनल्टी",
|
||||
"player": "खिलाड़ी"
|
||||
},
|
||||
"halftime": "हाफ टाइम: {{score}}",
|
||||
"empty_stats": "कोई आँकड़े उपलब्ध नहीं",
|
||||
|
||||
@@ -111,7 +111,8 @@
|
||||
"halftime": "Babak Pertama",
|
||||
"full_time": "90'",
|
||||
"extra_time": "Perpanjangan",
|
||||
"penalty": "Adu Penalti"
|
||||
"penalty": "Adu Penalti",
|
||||
"player": "Pemain"
|
||||
},
|
||||
"halftime": "Babak Pertama: {{score}}",
|
||||
"empty_stats": "Tidak ada data statistik",
|
||||
|
||||
@@ -111,7 +111,8 @@
|
||||
"halftime": "Separuh Masa",
|
||||
"full_time": "90'",
|
||||
"extra_time": "Masa Tambahan",
|
||||
"penalty": "Sepakan Penalti"
|
||||
"penalty": "Sepakan Penalti",
|
||||
"player": "Pemain"
|
||||
},
|
||||
"halftime": "Separuh masa: {{score}}",
|
||||
"empty_stats": "Tiada data statistik",
|
||||
|
||||
@@ -111,7 +111,8 @@
|
||||
"halftime": "ครึ่งแรก",
|
||||
"full_time": "90'",
|
||||
"extra_time": "ต่อเวลา",
|
||||
"penalty": "จุดโทษ"
|
||||
"penalty": "จุดโทษ",
|
||||
"player": "ผู้เล่น"
|
||||
},
|
||||
"halftime": "ครึ่งแรก: {{score}}",
|
||||
"empty_stats": "ไม่มีข้อมูลสถิติ",
|
||||
|
||||
@@ -111,7 +111,8 @@
|
||||
"halftime": "Hiệp 1",
|
||||
"full_time": "90'",
|
||||
"extra_time": "Hiệp phụ",
|
||||
"penalty": "Luân lưu"
|
||||
"penalty": "Luân lưu",
|
||||
"player": "Cầu thủ"
|
||||
},
|
||||
"halftime": "Hiệp 1: {{score}}",
|
||||
"empty_stats": "Không có dữ liệu thống kê",
|
||||
|
||||
@@ -115,7 +115,8 @@
|
||||
"halftime": "半场",
|
||||
"full_time": "90分钟",
|
||||
"extra_time": "加时",
|
||||
"penalty": "点球"
|
||||
"penalty": "点球",
|
||||
"player": "球员"
|
||||
},
|
||||
"halftime": "半场: {{score}}",
|
||||
"empty_stats": "暂无统计数据",
|
||||
|
||||
72
temp.json
Normal file
72
temp.json
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"code": 0,
|
||||
"message": "ok",
|
||||
"data": {
|
||||
"match": {
|
||||
"ID": 250468,
|
||||
"CreatedAt": "2026-01-21T05:45:15.704+08:00",
|
||||
"UpdatedAt": "2026-01-21T05:45:15.704+08:00",
|
||||
"DeletedAt": null,
|
||||
"eventKey": "12097737",
|
||||
"eventDate": "2026-01-22",
|
||||
"eventTime": "03:00",
|
||||
"eventHomeTeam": "",
|
||||
"homeTeamKey": "",
|
||||
"homeTeamLogo": "",
|
||||
"eventAwayTeam": "",
|
||||
"awayTeamKey": "",
|
||||
"awayTeamLogo": "",
|
||||
"eventHalftimeResult": "",
|
||||
"eventFinalResult": "-",
|
||||
"eventFtResult": "",
|
||||
"eventPenaltyResult": "",
|
||||
"eventStatus": "1",
|
||||
"countryName": "Challenger Men Singles",
|
||||
"leagueName": "Phan Thiet",
|
||||
"leagueKey": "13614",
|
||||
"leagueRound": "Phan Thiet - 1/8-finals",
|
||||
"leagueSeason": "2026",
|
||||
"eventLive": "0",
|
||||
"eventStadium": "",
|
||||
"eventReferee": "",
|
||||
"eventCountryKey": "281",
|
||||
"leagueLogo": "",
|
||||
"countryLogo": "",
|
||||
"eventHomeFormation": "",
|
||||
"eventAwayFormation": "",
|
||||
"fkStageKey": "",
|
||||
"stageName": "",
|
||||
"leagueGroup": "",
|
||||
"sportId": 3,
|
||||
"eventQuarter": "",
|
||||
"eventSet": "",
|
||||
"eventType": "",
|
||||
"eventToss": "",
|
||||
"eventManOfMatch": "",
|
||||
"eventFirstPlayer": "O. Jasika",
|
||||
"firstPlayerKey": "1261",
|
||||
"eventSecondPlayer": "I. Simakin",
|
||||
"secondPlayerKey": "1238",
|
||||
"eventFirstPlayerLogo": "https://apiv2.allsportsapi.com/logo-tennis/1261_o-jasika.jpg",
|
||||
"eventSecondPlayerLogo": "https://apiv2.allsportsapi.com/logo-tennis/1238_i-simakin.jpg",
|
||||
"eventGameResult": "-",
|
||||
"eventServe": "",
|
||||
"eventWinner": "",
|
||||
"events": null,
|
||||
"players": null,
|
||||
"scores": [
|
||||
{
|
||||
"score_set": "1",
|
||||
"score_first": "0",
|
||||
"score_second": "0"
|
||||
}
|
||||
],
|
||||
"stats": null,
|
||||
"pointByPoint": null,
|
||||
"scorecard": null,
|
||||
"comments": null,
|
||||
"wickets": null,
|
||||
"extra": null
|
||||
}
|
||||
}
|
||||
}
|
||||
16
types/api.ts
16
types/api.ts
@@ -103,11 +103,11 @@ export interface LiveScoreMatch {
|
||||
substitutes?: {
|
||||
time: string;
|
||||
home_scorer:
|
||||
| { in: string; out: string; in_id: number; out_id: number }
|
||||
| any[];
|
||||
| { in: string; out: string; in_id: number; out_id: number }
|
||||
| any[];
|
||||
away_scorer:
|
||||
| { in: string; out: string; in_id: number; out_id: number }
|
||||
| any[];
|
||||
| { in: string; out: string; in_id: number; out_id: number }
|
||||
| any[];
|
||||
info: string;
|
||||
info_time: string;
|
||||
score: string;
|
||||
@@ -305,6 +305,14 @@ export interface MatchDetailData {
|
||||
eventType: string;
|
||||
eventToss: string;
|
||||
eventManOfMatch: string;
|
||||
eventFirstPlayer?: string;
|
||||
eventSecondPlayer?: string;
|
||||
eventFirstPlayerLogo?: string;
|
||||
eventSecondPlayerLogo?: string;
|
||||
firstPlayerKey?: string;
|
||||
secondPlayerKey?: string;
|
||||
eventGameResult?: string;
|
||||
scores?: any[];
|
||||
events?: MatchEvents;
|
||||
players?: {
|
||||
home_team?: Player[];
|
||||
|
||||
Reference in New Issue
Block a user