篮球live详情

This commit is contained in:
xianyi
2026-01-22 18:27:09 +08:00
parent 6dc1170d1d
commit 91a25c5e6b
4 changed files with 205 additions and 27 deletions

View File

@@ -388,8 +388,8 @@ export default function HomeScreen() {
away: item.event_away_team,
homeTeamName: item.event_home_team,
awayTeamName: item.event_away_team,
homeTeamLogo: item.home_team_logo,
awayTeamLogo: item.away_team_logo,
homeTeamLogo: item.home_team_logo || "",
awayTeamLogo: item.away_team_logo || "",
scoreText: item.event_halftime_result || "0 - 0",
fav: false,
sportId: sportId,

View File

@@ -5,14 +5,17 @@ import { LiveScoreHeader } from "@/components/live-detail/live-score-header";
import { OddsCard } from "@/components/live-detail/odds-card";
import { OtherInfoCard } from "@/components/live-detail/other-info-card";
import { StatsCard } from "@/components/live-detail/stats-card";
import { BasketballOverallStats } from "@/components/match-detail/basketball/basketball-overall-stats";
import { BasketballScoreTable } from "@/components/match-detail/basketball/basketball-score-table";
import { BasketballStats } from "@/components/match-detail/basketball/basketball-stats";
import { ThemedText } from "@/components/themed-text";
import { ThemedView } from "@/components/themed-view";
import { Colors } from "@/constants/theme";
import { useTheme } from "@/context/ThemeContext";
import { fetchLiveScore } from "@/lib/api";
import { LiveScoreMatch } from "@/types/api";
import { LiveScoreMatch, MatchDetailData } from "@/types/api";
import { useLocalSearchParams } from "expo-router";
import React, { useEffect, useState } from "react";
import React, { useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import {
ActivityIndicator,
@@ -36,11 +39,72 @@ export default function LiveDetailScreen() {
const [loading, setLoading] = useState(true);
const [match, setMatch] = useState<LiveScoreMatch | null>(null);
const [activeTab, setActiveTab] = useState("detail"); // Default to detail to show all data
const [activeTab, setActiveTab] = useState("detail");
const convertToMatchDetailData = useMemo((): MatchDetailData | null => {
if (!match) return null;
return {
events: [],
match: {
ID: 0,
CreatedAt: "",
UpdatedAt: "",
DeletedAt: null,
eventKey: match.event_key.toString(),
eventDate: match.event_date,
eventTime: match.event_time,
eventHomeTeam: match.event_home_team,
homeTeamKey: match.home_team_key.toString(),
homeTeamLogo: match.home_team_logo || "",
eventAwayTeam: match.event_away_team,
awayTeamKey: match.away_team_key.toString(),
awayTeamLogo: match.away_team_logo || "",
eventHalftimeResult: match.event_halftime_result || "",
eventFinalResult: match.event_final_result,
eventFtResult: "",
eventPenaltyResult: "",
eventStatus: match.event_status,
countryName: match.country_name,
leagueName: match.league_name,
leagueKey: match.league_key.toString(),
leagueRound: match.league_round,
leagueSeason: match.league_season,
eventLive: match.event_live,
eventStadium: "",
eventReferee: "",
eventCountryKey: match.event_country_key?.toString() || "",
leagueLogo: match.league_logo || "",
countryLogo: match.country_logo || "",
eventHomeFormation: "",
eventAwayFormation: "",
fkStageKey: "",
stageName: "",
leagueGroup: "",
sportId: parseInt(sport_id || "1"),
eventQuarter: match.event_quarter || "",
eventSet: "",
eventType: "",
eventToss: "",
eventManOfMatch: "",
scores: match.scores,
stats: match.statistics,
players: match.player_statistics ? {
home_team: (match.player_statistics.home_team || []).map(p => ({
...p,
player_oncourt: p.player_oncourt || undefined,
})),
away_team: (match.player_statistics.away_team || []).map(p => ({
...p,
player_oncourt: p.player_oncourt || undefined,
})),
} : undefined,
},
};
}, [match, sport_id]);
useEffect(() => {
loadLiveDetail();
// 设置每 15 秒更新一次直播比分
const timer = setInterval(() => {
refreshLiveDetail();
}, 15000);
@@ -60,14 +124,12 @@ export default function LiveDetailScreen() {
const refreshLiveDetail = async () => {
try {
// Fetch live scores for the league
const sportId = parseInt(sport_id || "1");
const leagueId = parseInt(league_id || "0");
const liveData = await fetchLiveScore(sportId, leagueId);
if (liveData && Array.isArray(liveData)) {
// Find the specific match
const found = liveData.find((m) => m.event_key.toString() === id);
console.log("found", JSON.stringify(found, null, 2));
if (found) {
@@ -99,7 +161,37 @@ export default function LiveDetailScreen() {
}
const renderTabContent = () => {
if (!match) return null;
const numericSportId = parseInt(sport_id || "1");
if (numericSportId === 2 && convertToMatchDetailData) {
switch (activeTab) {
case "stats":
return <BasketballStats data={convertToMatchDetailData} isDark={isDark} />;
case "overall":
return <BasketballOverallStats data={convertToMatchDetailData} isDark={isDark} />;
case "odds":
return (
<OddsCard match={match} isDark={isDark} sportId={numericSportId} />
);
case "detail":
return (
<>
<BasketballScoreTable data={convertToMatchDetailData} isDark={isDark} />
</>
);
default:
return (
<View style={styles.center}>
<ThemedText style={{ opacity: 0.5 }}>
{t("detail.empty_stats")}
</ThemedText>
</View>
);
}
}
switch (activeTab) {
case "stats":
return <StatsCard match={match} isDark={isDark} />;
@@ -140,6 +232,7 @@ export default function LiveDetailScreen() {
activeTab={activeTab}
onTabChange={setActiveTab}
isDark={isDark}
sportId={parseInt(sport_id || "1")}
/>
{renderTabContent()}

View File

@@ -8,17 +8,36 @@ interface LiveMatchTabsProps {
activeTab: string;
onTabChange: (tab: string) => void;
isDark: boolean;
sportId?: number;
}
export function LiveMatchTabs({
activeTab,
onTabChange,
isDark,
sportId = 1,
}: LiveMatchTabsProps) {
const { t } = useTranslation();
const containerBg = isDark ? "#121212" : "#F5F5F5";
const tabs = [
const getTabs = () => {
if (sportId === 2) {
return [
{
id: "detail",
label: t("detail.tabs.info"),
icon: "document-text-outline",
},
{ id: "stats", label: t("detail.tabs.stats"), icon: "stats-chart-outline" },
{
id: "overall",
label: t("detail.tabs.overall"),
icon: "bar-chart-outline",
},
{ id: "odds", label: t("detail.tabs.odds"), icon: "cash-outline" },
];
}
return [
{
id: "detail",
label: t("detail.tabs.info"),
@@ -33,6 +52,9 @@ export function LiveMatchTabs({
icon: "pie-chart-outline",
},
];
};
const tabs = getTabs();
return (
<View style={[styles.container, { backgroundColor: containerBg }]}>

View File

@@ -52,10 +52,10 @@ export interface LiveScoreMatch {
event_time: string;
event_home_team: string;
home_team_key: number;
home_team_logo: string;
home_team_logo: string | null;
event_away_team: string;
away_team_key: number;
away_team_logo: string;
away_team_logo: string | null;
event_final_result: string;
event_halftime_result: string;
event_status: string;
@@ -68,6 +68,7 @@ export interface LiveScoreMatch {
country_name: string;
country_logo: string;
event_country_key: number;
event_quarter?: string;
// Tennis specific
event_first_player?: string;
event_first_player_logo?: string;
@@ -75,7 +76,12 @@ export interface LiveScoreMatch {
event_second_player_logo?: string;
event_serve?: string;
pointbypoint?: any[];
scores?: any[]; // LiveScoreMatch uses array for scores, Match uses string
scores?: any[] | {
"1stQuarter"?: Array<{ score_home: string; score_away: string }>;
"2ndQuarter"?: Array<{ score_home: string; score_away: string }>;
"3rdQuarter"?: Array<{ score_home: string; score_away: string }>;
"4thQuarter"?: Array<{ score_home: string; score_away: string }>;
};
goalscorers?: {
time: string;
home_scorer: string;
@@ -112,7 +118,64 @@ export interface LiveScoreMatch {
info_time: string;
score: string;
}[];
lineups?: unknown;
lineups?: {
home_team?: {
starting_lineups?: Array<{ player: string; player_id: number }>;
substitutes?: Array<{ player: string; player_id: number }>;
};
away_team?: {
starting_lineups?: Array<{ player: string; player_id: number }>;
substitutes?: Array<{ player: string; player_id: number }>;
};
};
player_statistics?: {
home_team?: Array<{
player: string;
player_id: number;
player_position?: string;
player_minutes?: string;
player_points?: string;
player_total_rebounds?: string;
player_offence_rebounds?: string;
player_defense_rebounds?: string;
player_assists?: string;
player_steals?: string;
player_blocks?: string;
player_turnovers?: string;
player_personal_fouls?: string;
player_plus_minus?: string;
player_field_goals_made?: string;
player_field_goals_attempts?: string;
player_threepoint_goals_made?: string;
player_threepoint_goals_attempts?: string;
player_freethrows_goals_made?: string;
player_freethrows_goals_attempts?: string;
player_oncourt?: string | null;
}>;
away_team?: Array<{
player: string;
player_id: number;
player_position?: string;
player_minutes?: string;
player_points?: string;
player_total_rebounds?: string;
player_offence_rebounds?: string;
player_defense_rebounds?: string;
player_assists?: string;
player_steals?: string;
player_blocks?: string;
player_turnovers?: string;
player_personal_fouls?: string;
player_plus_minus?: string;
player_field_goals_made?: string;
player_field_goals_attempts?: string;
player_threepoint_goals_made?: string;
player_threepoint_goals_attempts?: string;
player_freethrows_goals_made?: string;
player_freethrows_goals_attempts?: string;
player_oncourt?: string | null;
}>;
};
statistics?: {
type: string;
home: string;