添加网球相关数据映射和逻辑到 MatchCard 组件,优化比赛信息展示
This commit is contained in:
@@ -72,6 +72,13 @@ export default function LiveScreen() {
|
|||||||
sportId: state.selectedSportId ?? undefined,
|
sportId: state.selectedSportId ?? undefined,
|
||||||
isLive: true,
|
isLive: true,
|
||||||
date: item.event_date,
|
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();
|
const token = await storage.getAccessToken();
|
||||||
|
|||||||
@@ -106,6 +106,36 @@ export function MatchCard({
|
|||||||
return !!match.isLive;
|
return !!match.isLive;
|
||||||
}, [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 timeLabel = React.useMemo(() => {
|
||||||
const raw = (match.time || "").trim();
|
const raw = (match.time || "").trim();
|
||||||
if (!raw) return "";
|
if (!raw) return "";
|
||||||
@@ -121,7 +151,31 @@ export function MatchCard({
|
|||||||
}, [match.leagueName, match.league]);
|
}, [match.leagueName, match.league]);
|
||||||
|
|
||||||
const scoreParts = React.useMemo(() => {
|
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 s = (match.scoreText || "").trim();
|
||||||
|
|
||||||
const m = s.match(/(\d+)\s*[-:]\s*(\d+)/);
|
const m = s.match(/(\d+)\s*[-:]\s*(\d+)/);
|
||||||
if (m) {
|
if (m) {
|
||||||
const h = parseInt(m[1]);
|
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 (
|
||||||
|
<View style={styles.tennisScoresRow}>
|
||||||
|
{prevSets.map((s: any, i: number) => (
|
||||||
|
<ThemedText
|
||||||
|
key={i}
|
||||||
|
style={[
|
||||||
|
styles.tennisScoreText,
|
||||||
|
{ color: isDark ? "#CCC" : "#666" },
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{isHome ? s.score_first : s.score_second}
|
||||||
|
</ThemedText>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const renderOddsRow = (bookmakerName: string, isHighlight: boolean) => {
|
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;
|
if (!oddsSettings.enabled || !bookmakerName) return null;
|
||||||
|
|
||||||
const item = odds.find((o) => o.odd_bookmakers === bookmakerName);
|
const item = odds.find((o) => o.odd_bookmakers === bookmakerName);
|
||||||
@@ -386,7 +466,7 @@ export function MatchCard({
|
|||||||
<View style={styles.teamLogoPlaceholder}>
|
<View style={styles.teamLogoPlaceholder}>
|
||||||
<Image
|
<Image
|
||||||
source={{
|
source={{
|
||||||
uri: match.homeTeamLogo,
|
uri: homeLogo,
|
||||||
}}
|
}}
|
||||||
style={styles.teamLogo}
|
style={styles.teamLogo}
|
||||||
contentFit="contain"
|
contentFit="contain"
|
||||||
@@ -398,9 +478,10 @@ export function MatchCard({
|
|||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
ellipsizeMode="tail"
|
ellipsizeMode="tail"
|
||||||
>
|
>
|
||||||
{match.homeTeamName || match.home}
|
{homeName}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
{renderCardsInline(cardsCount.homeYellow, cardsCount.homeRed)}
|
{!isTennis &&
|
||||||
|
renderCardsInline(cardsCount.homeYellow, cardsCount.homeRed)}
|
||||||
</View>
|
</View>
|
||||||
{renderOddsRow(oddsSettings.selectedBookmakers[0], true)}
|
{renderOddsRow(oddsSettings.selectedBookmakers[0], true)}
|
||||||
</View>
|
</View>
|
||||||
@@ -410,7 +491,7 @@ export function MatchCard({
|
|||||||
<View style={styles.teamLogoPlaceholder}>
|
<View style={styles.teamLogoPlaceholder}>
|
||||||
<Image
|
<Image
|
||||||
source={{
|
source={{
|
||||||
uri: match.awayTeamLogo,
|
uri: awayLogo,
|
||||||
}}
|
}}
|
||||||
style={styles.teamLogo}
|
style={styles.teamLogo}
|
||||||
contentFit="contain"
|
contentFit="contain"
|
||||||
@@ -422,9 +503,10 @@ export function MatchCard({
|
|||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
ellipsizeMode="tail"
|
ellipsizeMode="tail"
|
||||||
>
|
>
|
||||||
{match.awayTeamName || match.away}
|
{awayName}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
{renderCardsInline(cardsCount.awayYellow, cardsCount.awayRed)}
|
{!isTennis &&
|
||||||
|
renderCardsInline(cardsCount.awayYellow, cardsCount.awayRed)}
|
||||||
</View>
|
</View>
|
||||||
{renderOddsRow(oddsSettings.selectedBookmakers[1], false)}
|
{renderOddsRow(oddsSettings.selectedBookmakers[1], false)}
|
||||||
</View>
|
</View>
|
||||||
@@ -710,4 +792,16 @@ const styles = StyleSheet.create({
|
|||||||
cardBadgeTextDark: {
|
cardBadgeTextDark: {
|
||||||
color: "#000",
|
color: "#000",
|
||||||
},
|
},
|
||||||
|
tennisScoresRow: {
|
||||||
|
flexDirection: "row",
|
||||||
|
gap: 12,
|
||||||
|
marginRight: 4,
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
tennisScoreText: {
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: "500",
|
||||||
|
minWidth: 14,
|
||||||
|
textAlign: "center",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -182,6 +182,7 @@ export const fetchTodayMatches = async (options: {
|
|||||||
{ params },
|
{ params },
|
||||||
);
|
);
|
||||||
if (response.data.code === 0) {
|
if (response.data.code === 0) {
|
||||||
|
// console.log("Fetched today matches:", JSON.stringify(response.data.data));
|
||||||
return response.data.data;
|
return response.data.data;
|
||||||
}
|
}
|
||||||
throw new Error(response.data.message);
|
throw new Error(response.data.message);
|
||||||
|
|||||||
15
types/api.ts
15
types/api.ts
@@ -37,6 +37,13 @@ export interface Match {
|
|||||||
isLive?: boolean;
|
isLive?: boolean;
|
||||||
meta?: string;
|
meta?: string;
|
||||||
odds?: OddsItem[];
|
odds?: OddsItem[];
|
||||||
|
// Tennis specific
|
||||||
|
eventFirstPlayer?: string;
|
||||||
|
eventSecondPlayer?: string;
|
||||||
|
eventFirstPlayerLogo?: string;
|
||||||
|
eventSecondPlayerLogo?: string;
|
||||||
|
scores?: string;
|
||||||
|
eventServe?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LiveScoreMatch {
|
export interface LiveScoreMatch {
|
||||||
@@ -61,6 +68,14 @@ export interface LiveScoreMatch {
|
|||||||
country_name: string;
|
country_name: string;
|
||||||
country_logo: string;
|
country_logo: string;
|
||||||
event_country_key: number;
|
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?: {
|
goalscorers?: {
|
||||||
time: string;
|
time: string;
|
||||||
home_scorer: string;
|
home_scorer: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user