diff --git a/app/(tabs)/live.tsx b/app/(tabs)/live.tsx
index 06f6fc1..df4659a 100644
--- a/app/(tabs)/live.tsx
+++ b/app/(tabs)/live.tsx
@@ -72,6 +72,13 @@ export default function LiveScreen() {
sportId: state.selectedSportId ?? undefined,
isLive: true,
date: item.event_date,
+ // Tennis specific mapping
+ eventFirstPlayer: item.event_first_player,
+ eventSecondPlayer: item.event_second_player,
+ eventFirstPlayerLogo: item.event_first_player_logo,
+ eventSecondPlayerLogo: item.event_second_player_logo,
+ eventServe: item.event_serve,
+ scores: item.scores ? JSON.stringify(item.scores) : undefined,
}));
const token = await storage.getAccessToken();
diff --git a/components/match-card.tsx b/components/match-card.tsx
index a7ce83a..160b080 100644
--- a/components/match-card.tsx
+++ b/components/match-card.tsx
@@ -106,6 +106,36 @@ export function MatchCard({
return !!match.isLive;
}, [match.isLive]);
+ // Tennis logic
+ const isTennis = match.sportId === 3 || match.sport === "tennis";
+ const homeName = isTennis
+ ? liveDetail?.event_first_player || match.eventFirstPlayer
+ : liveDetail?.event_home_team || match.homeTeamName || match.home;
+ const awayName = isTennis
+ ? liveDetail?.event_second_player || match.eventSecondPlayer
+ : liveDetail?.event_away_team || match.awayTeamName || match.away;
+ const homeLogo = isTennis
+ ? liveDetail?.event_first_player_logo || match.eventFirstPlayerLogo
+ : liveDetail?.home_team_logo || match.homeTeamLogo;
+ const awayLogo = isTennis
+ ? liveDetail?.event_second_player_logo || match.eventSecondPlayerLogo
+ : liveDetail?.away_team_logo || match.awayTeamLogo;
+
+ const tennisScores = React.useMemo(() => {
+ // 优先使用 liveDetail 中的 scores
+ if (isTennis && liveDetail?.scores && Array.isArray(liveDetail.scores)) {
+ return liveDetail.scores;
+ }
+
+ if (!isTennis || !match.scores) return [];
+ try {
+ const parsed = JSON.parse(match.scores);
+ return Array.isArray(parsed) ? parsed : [];
+ } catch {
+ return [];
+ }
+ }, [match.scores, isTennis, liveDetail]);
+
const timeLabel = React.useMemo(() => {
const raw = (match.time || "").trim();
if (!raw) return "";
@@ -121,7 +151,31 @@ export function MatchCard({
}, [match.leagueName, match.league]);
const scoreParts = React.useMemo(() => {
+ if (isTennis) {
+ if (tennisScores.length > 0) {
+ const last = tennisScores[tennisScores.length - 1];
+ const h = parseInt(last.score_first || "0");
+ const a = parseInt(last.score_second || "0");
+ return {
+ home: last.score_first || "0",
+ away: last.score_second || "0",
+ hasScore: true,
+ homeLead: h > a,
+ awayLead: a > h,
+ };
+ }
+ // 如果没有分数(如未开始),显示 0-0 或 -
+ return {
+ home: "0",
+ away: "0",
+ hasScore: true, // 保持 ScoreBox 显示,以便显示 0-0
+ homeLead: false,
+ awayLead: false,
+ };
+ }
+
const s = (match.scoreText || "").trim();
+
const m = s.match(/(\d+)\s*[-:]\s*(\d+)/);
if (m) {
const h = parseInt(m[1]);
@@ -271,7 +325,33 @@ export function MatchCard({
}
};
+ const renderTennisSetScores = (isHome: boolean) => {
+ // 显示除最后一盘之外的盘分 (当前盘分在右侧大框显示)
+ // 如果只有一盘,则这里不显示任何内容
+ if (tennisScores.length <= 1) return null;
+
+ const prevSets = tennisScores.slice(0, tennisScores.length - 1);
+
+ return (
+
+ {prevSets.map((s: any, i: number) => (
+
+ {isHome ? s.score_first : s.score_second}
+
+ ))}
+
+ );
+ };
+
const renderOddsRow = (bookmakerName: string, isHighlight: boolean) => {
+ if (isTennis) return renderTennisSetScores(isHighlight); // Reuse isHighlight param as 'isHome' (true for first player logic)
+
if (!oddsSettings.enabled || !bookmakerName) return null;
const item = odds.find((o) => o.odd_bookmakers === bookmakerName);
@@ -386,7 +466,7 @@ export function MatchCard({
- {match.homeTeamName || match.home}
+ {homeName}
- {renderCardsInline(cardsCount.homeYellow, cardsCount.homeRed)}
+ {!isTennis &&
+ renderCardsInline(cardsCount.homeYellow, cardsCount.homeRed)}
{renderOddsRow(oddsSettings.selectedBookmakers[0], true)}
@@ -410,7 +491,7 @@ export function MatchCard({
- {match.awayTeamName || match.away}
+ {awayName}
- {renderCardsInline(cardsCount.awayYellow, cardsCount.awayRed)}
+ {!isTennis &&
+ renderCardsInline(cardsCount.awayYellow, cardsCount.awayRed)}
{renderOddsRow(oddsSettings.selectedBookmakers[1], false)}
@@ -710,4 +792,16 @@ const styles = StyleSheet.create({
cardBadgeTextDark: {
color: "#000",
},
+ tennisScoresRow: {
+ flexDirection: "row",
+ gap: 12,
+ marginRight: 4,
+ alignItems: "center",
+ },
+ tennisScoreText: {
+ fontSize: 14,
+ fontWeight: "500",
+ minWidth: 14,
+ textAlign: "center",
+ },
});
diff --git a/lib/api.ts b/lib/api.ts
index e3e47d2..5772e33 100644
--- a/lib/api.ts
+++ b/lib/api.ts
@@ -182,6 +182,7 @@ export const fetchTodayMatches = async (options: {
{ params },
);
if (response.data.code === 0) {
+ // console.log("Fetched today matches:", JSON.stringify(response.data.data));
return response.data.data;
}
throw new Error(response.data.message);
diff --git a/types/api.ts b/types/api.ts
index aac8012..d57047a 100644
--- a/types/api.ts
+++ b/types/api.ts
@@ -37,6 +37,13 @@ export interface Match {
isLive?: boolean;
meta?: string;
odds?: OddsItem[];
+ // Tennis specific
+ eventFirstPlayer?: string;
+ eventSecondPlayer?: string;
+ eventFirstPlayerLogo?: string;
+ eventSecondPlayerLogo?: string;
+ scores?: string;
+ eventServe?: string;
}
export interface LiveScoreMatch {
@@ -61,6 +68,14 @@ export interface LiveScoreMatch {
country_name: string;
country_logo: string;
event_country_key: number;
+ // Tennis specific
+ event_first_player?: string;
+ event_first_player_logo?: string;
+ event_second_player?: string;
+ event_second_player_logo?: string;
+ event_serve?: string;
+ pointbypoint?: any[];
+ scores?: any[]; // LiveScoreMatch uses array for scores, Match uses string
goalscorers?: {
time: string;
home_scorer: string;
@@ -88,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;