diff --git a/app/live-detail/[id].tsx b/app/live-detail/[id].tsx
index 6b7938e..6219dcd 100644
--- a/app/live-detail/[id].tsx
+++ b/app/live-detail/[id].tsx
@@ -40,11 +40,26 @@ export default function LiveDetailScreen() {
useEffect(() => {
loadLiveDetail();
+ // 设置每 15 秒更新一次直播比分
+ const timer = setInterval(() => {
+ refreshLiveDetail();
+ }, 15000);
+ return () => clearInterval(timer);
}, [id, league_id]);
const loadLiveDetail = async () => {
try {
setLoading(true);
+ await refreshLiveDetail();
+ } catch (err) {
+ console.error(err);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ const refreshLiveDetail = async () => {
+ try {
// Fetch live scores for the league
const sportId = parseInt(sport_id || "1");
const leagueId = parseInt(league_id || "0");
@@ -59,9 +74,7 @@ export default function LiveDetailScreen() {
}
}
} catch (err) {
- console.error(err);
- } finally {
- setLoading(false);
+ console.error("Refresh live detail error:", err);
}
};
@@ -85,15 +98,18 @@ export default function LiveDetailScreen() {
}
const renderTabContent = () => {
+ const numericSportId = parseInt(sport_id || "1");
switch (activeTab) {
case "stats":
return ;
case "odds":
- return ;
+ return (
+
+ );
case "detail":
return (
<>
-
+
diff --git a/components/live-detail/odds-card.tsx b/components/live-detail/odds-card.tsx
index 503d912..74c42f0 100644
--- a/components/live-detail/odds-card.tsx
+++ b/components/live-detail/odds-card.tsx
@@ -1,23 +1,116 @@
import { ThemedText } from "@/components/themed-text";
import { ThemedView } from "@/components/themed-view";
-import { LiveScoreMatch } from "@/types/api";
-import React from "react";
+import { fetchOdds } from "@/lib/api";
+import { LiveScoreMatch, OddsItem } from "@/types/api";
+import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
-import { StyleSheet, View } from "react-native";
+import { ActivityIndicator, StyleSheet, View } from "react-native";
interface OddsCardProps {
match: LiveScoreMatch;
isDark: boolean;
+ sportId: number;
}
-export function OddsCard({ match, isDark }: OddsCardProps) {
+export function OddsCard({ match, isDark, sportId }: OddsCardProps) {
const { t } = useTranslation();
+ const [odds, setOdds] = useState(null);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ loadOdds();
+ // 设置每 30 秒自动更新一次
+ const interval = setInterval(loadOdds, 30000);
+ return () => clearInterval(interval);
+ }, [match.event_key, sportId]);
+
+ const loadOdds = async () => {
+ try {
+ const data = await fetchOdds(sportId, match.event_key);
+ const matchOdds = data[match.event_key.toString()];
+ if (matchOdds && matchOdds.data && matchOdds.data.length > 0) {
+ // 优先选择包含常见赔率项的博彩公司,这里暂取第一个
+ setOdds(matchOdds.data[0]);
+ }
+ } catch (error) {
+ console.error("Load odds error:", error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
// 提取队名缩写或前3个字母
const homeAbbr =
match.event_home_team?.substring(0, 3).toUpperCase() || "HOME";
const awayAbbr =
match.event_away_team?.substring(0, 3).toUpperCase() || "AWAY";
+ // 获取显示的盘口和赔率
+ const renderOddsContent = () => {
+ if (loading && !odds) {
+ return (
+
+
+
+ );
+ }
+
+ // 尝试寻找亚洲盘口 (AH) 或者 主客和 (1X2)
+ // 这里为了演示演示,优先寻找 AH 相关数据
+ const ahKey1 = Object.keys(odds || {}).find(
+ (k) => k.startsWith("ah") && k.endsWith("_1")
+ );
+ const ahKey2 = ahKey1 ? ahKey1.replace("_1", "_2") : null;
+
+ if (odds && ahKey1 && ahKey2) {
+ const handicapValue = ahKey1.replace("ah", "").replace("_1", "");
+ return (
+
+
+ {homeAbbr}
+ {odds[ahKey1] || "-"}
+
+
+ HDP
+ {handicapValue}
+
+
+ {awayAbbr}
+ {odds[ahKey2] || "-"}
+
+
+ );
+ }
+
+ // 如果没有 AH,显示 1X2
+ if (odds && odds.odd_1 && odds.odd_2) {
+ return (
+
+
+ {homeAbbr}
+ {odds.odd_1}
+
+
+ DRAW
+ {odds.odd_x || "-"}
+
+
+ {awayAbbr}
+ {odds.odd_2}
+
+
+ );
+ }
+
+ return (
+
+
+ {t("detail.empty_odds")}
+
+
+ );
+ };
+
return (
@@ -25,24 +118,13 @@ export function OddsCard({ match, isDark }: OddsCardProps) {
{t("detail.odds_card.title")}
- bet365
+
+ {odds?.odd_bookmakers || "bet365"}
+
-
-
- {homeAbbr}
- -0.93
-
-
- HDP
- 0/0.5
-
-
- {awayAbbr}
- 0.72
-
-
+ {renderOddsContent()}
{t("detail.odds_card.disclaimer")}
@@ -105,12 +187,12 @@ const styles = StyleSheet.create({
backgroundColor: "rgba(255,255,255,0.05)",
},
team: {
- fontSize: 16,
+ fontSize: 14,
fontWeight: "500",
},
odds: {
- fontSize: 16,
- fontWeight: "600",
+ fontSize: 14,
+ fontWeight: "700",
color: "#FF9800",
},
disclaimer: {
@@ -119,4 +201,14 @@ const styles = StyleSheet.create({
marginTop: 20,
textAlign: "center",
},
+ loadingContainer: {
+ height: 60,
+ justifyContent: "center",
+ alignItems: "center",
+ },
+ emptyContainer: {
+ height: 60,
+ justifyContent: "center",
+ alignItems: "center",
+ },
});
diff --git a/types/api.ts b/types/api.ts
index 88fef1c..d2b731b 100644
--- a/types/api.ts
+++ b/types/api.ts
@@ -265,7 +265,25 @@ export interface MatchDetailData {
};
}
-// 实时赔率(根据 sportId 可能是 LiveOdds 或 Odds 结构,暂时使用宽泛类型)
-export interface OddsData {
+// 实时赔率数据项结构
+export interface OddsItem {
+ odd_bookmakers: string;
+ odd_1?: number;
+ odd_x?: number;
+ odd_2?: number;
+ odd_12?: number;
+ odd_1x?: number;
+ odd_x2?: number;
+ "ah+1_1"?: number;
+ "ah+1_2"?: number;
+ "o+2.5"?: number;
+ "u+2.5"?: number;
[key: string]: any;
}
+
+// 实时赔率响应数据结构
+export interface OddsData {
+ [match_id: string]: {
+ data: OddsItem[];
+ };
+}