添加网球相关数据映射和逻辑到 MatchCard 组件,优化比赛信息展示

This commit is contained in:
yuchenglong
2026-01-22 10:21:51 +08:00
parent ab071360f4
commit b36ab3b10d
4 changed files with 127 additions and 10 deletions

View File

@@ -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();

View File

@@ -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",
},
}); });

View File

@@ -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);

View File

@@ -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;
@@ -88,11 +103,11 @@ export interface LiveScoreMatch {
substitutes?: { substitutes?: {
time: string; time: string;
home_scorer: home_scorer:
| { in: string; out: string; in_id: number; out_id: number } | { in: string; out: string; in_id: number; out_id: number }
| any[]; | any[];
away_scorer: away_scorer:
| { in: string; out: string; in_id: number; out_id: number } | { in: string; out: string; in_id: number; out_id: number }
| any[]; | any[];
info: string; info: string;
info_time: string; info_time: string;
score: string; score: string;