实现直播详情页赔率自动更新功能,优化赔率数据结构
This commit is contained in:
@@ -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<OddsItem | null>(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 (
|
||||
<View style={styles.loadingContainer}>
|
||||
<ActivityIndicator size="small" color="#FF9800" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
// 尝试寻找亚洲盘口 (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 (
|
||||
<View style={styles.row}>
|
||||
<View style={[styles.item, isDark && styles.darkItem]}>
|
||||
<ThemedText style={styles.team}>{homeAbbr}</ThemedText>
|
||||
<ThemedText style={styles.odds}>{odds[ahKey1] || "-"}</ThemedText>
|
||||
</View>
|
||||
<View style={[styles.item, isDark && styles.darkItem]}>
|
||||
<ThemedText style={styles.team}>HDP</ThemedText>
|
||||
<ThemedText style={styles.odds}>{handicapValue}</ThemedText>
|
||||
</View>
|
||||
<View style={[styles.item, isDark && styles.darkItem]}>
|
||||
<ThemedText style={styles.team}>{awayAbbr}</ThemedText>
|
||||
<ThemedText style={styles.odds}>{odds[ahKey2] || "-"}</ThemedText>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
// 如果没有 AH,显示 1X2
|
||||
if (odds && odds.odd_1 && odds.odd_2) {
|
||||
return (
|
||||
<View style={styles.row}>
|
||||
<View style={[styles.item, isDark && styles.darkItem]}>
|
||||
<ThemedText style={styles.team}>{homeAbbr}</ThemedText>
|
||||
<ThemedText style={styles.odds}>{odds.odd_1}</ThemedText>
|
||||
</View>
|
||||
<View style={[styles.item, isDark && styles.darkItem]}>
|
||||
<ThemedText style={styles.team}>DRAW</ThemedText>
|
||||
<ThemedText style={styles.odds}>{odds.odd_x || "-"}</ThemedText>
|
||||
</View>
|
||||
<View style={[styles.item, isDark && styles.darkItem]}>
|
||||
<ThemedText style={styles.team}>{awayAbbr}</ThemedText>
|
||||
<ThemedText style={styles.odds}>{odds.odd_2}</ThemedText>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.emptyContainer}>
|
||||
<ThemedText style={{ color: "#999" }}>
|
||||
{t("detail.empty_odds")}
|
||||
</ThemedText>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemedView style={[styles.container, isDark && styles.darkContainer]}>
|
||||
<View style={styles.header}>
|
||||
@@ -25,24 +118,13 @@ export function OddsCard({ match, isDark }: OddsCardProps) {
|
||||
{t("detail.odds_card.title")}
|
||||
</ThemedText>
|
||||
<View style={styles.badge}>
|
||||
<ThemedText style={styles.badgeText}>bet365</ThemedText>
|
||||
<ThemedText style={styles.badgeText}>
|
||||
{odds?.odd_bookmakers || "bet365"}
|
||||
</ThemedText>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.row}>
|
||||
<View style={[styles.item, isDark && styles.darkItem]}>
|
||||
<ThemedText style={styles.team}>{homeAbbr}</ThemedText>
|
||||
<ThemedText style={styles.odds}>-0.93</ThemedText>
|
||||
</View>
|
||||
<View style={[styles.item, isDark && styles.darkItem]}>
|
||||
<ThemedText style={styles.team}>HDP</ThemedText>
|
||||
<ThemedText style={styles.odds}>0/0.5</ThemedText>
|
||||
</View>
|
||||
<View style={[styles.item, isDark && styles.darkItem]}>
|
||||
<ThemedText style={styles.team}>{awayAbbr}</ThemedText>
|
||||
<ThemedText style={styles.odds}>0.72</ThemedText>
|
||||
</View>
|
||||
</View>
|
||||
{renderOddsContent()}
|
||||
|
||||
<ThemedText style={styles.disclaimer}>
|
||||
{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",
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user