This commit is contained in:
yuchenglong
2026-01-22 18:52:09 +08:00
16 changed files with 1115 additions and 77 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

@@ -8,14 +8,17 @@ import { StatsCard } from "@/components/live-detail/stats-card";
import { TennisPowerGraph } from "@/components/live-detail/tennis-power-graph";
import { TennisScoreboard } from "@/components/live-detail/tennis-scoreboard";
import { TennisStatsCard } from "@/components/live-detail/tennis-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,
@@ -39,11 +42,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);
@@ -63,15 +127,14 @@ 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) {
setMatch(found);
}
@@ -101,6 +164,8 @@ export default function LiveDetailScreen() {
}
const renderTabContent = () => {
if (!match) return null;
const numericSportId = parseInt(sport_id || "1");
// Tennis Check
const isTennis =
@@ -108,6 +173,33 @@ export default function LiveDetailScreen() {
(match.league_name &&
/ATP|WTA|ITF|Challenger/i.test(match.league_name || ""));
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 !isTennis ? (
@@ -165,6 +257,7 @@ export default function LiveDetailScreen() {
activeTab={activeTab}
onTabChange={setActiveTab}
isDark={isDark}
sportId={parseInt(sport_id || "1")}
/>
{renderTabContent()}

View File

@@ -1,5 +1,7 @@
import { OddsCard } from "@/components/live-detail/odds-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 { CardsCard } from "@/components/match-detail/football/cards-card";
import { FootballScoreTable } from "@/components/match-detail/football/football-score-table";
import { GoalsCard } from "@/components/match-detail/football/goals-card";
@@ -59,7 +61,7 @@ export default function MatchDetailScreen() {
validTabs = ["info", "stats", "odds", "h2h", "chat"];
} else if (sportId === 2) {
// 篮球
validTabs = ["info", "h2h", "chat"];
validTabs = ["info", "stats", "overall", "h2h", "chat"];
} else if (sportId === 3) {
// 网球
validTabs = ["info", "chat"];
@@ -81,8 +83,8 @@ 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.events);
// console.log("首发阵容", result.match.players?.away_team);
// console.log("红黄牌", result.events);
@@ -163,6 +165,9 @@ export default function MatchDetailScreen() {
<LineupsCard data={data} isDark={isDark} />
</>
);
} else if (sportId === 2) {
// 篮球:显示统计数据
return <BasketballStats data={data} isDark={isDark} />;
} else {
// 其他运动暂时显示空状态
return (
@@ -173,6 +178,8 @@ export default function MatchDetailScreen() {
</View>
);
}
case "overall":
return <BasketballOverallStats data={data} isDark={isDark} />;
case "odds":
// 将 MatchDetailData.match 转换为 LiveScoreMatch 格式
const matchForOdds = {