import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { EChart } from "../charts/EChart.jsx"; import { createGeoOption } from "../charts/options/createGeoOption.js"; import { formatMoney, moneyMajor } from "../utils/format.js"; import { GlobeMap } from "./GlobeMap.jsx"; import { Panel } from "./Panel.jsx"; import { RankList } from "./RankList.jsx"; const MODAL_TRANSITION_MS = 180; export function GlobalOverviewPanel({ countryBreakdown, loading = false }) { const [globeOpen, setGlobeOpen] = useState(false); const rechargeCountries = useMemo(() => countryBreakdown.filter(hasRecharge), [countryBreakdown]); const rankedCountries = useMemo(() => rechargeCountries.slice(0, 4), [rechargeCountries]); return ( <> {loading ? : (
{rankedCountries.length ? :
暂无国家数据
}
)}
{globeOpen ? setGlobeOpen(false)} /> : null} ); } function GlobalOverviewSkeleton() { return (
{Array.from({ length: 4 }).map((_, index) => ( ))}
); } function CountryGlobeDialog({ items, onClose }) { const [closing, setClosing] = useState(false); const closeTimerRef = useRef(null); const requestClose = useCallback(() => { if (closing) { return; } setClosing(true); closeTimerRef.current = window.setTimeout(onClose, MODAL_TRANSITION_MS); }, [closing, onClose]); useEffect(() => () => { if (closeTimerRef.current) { window.clearTimeout(closeTimerRef.current); } }, []); useEffect(() => { const closeOnEscape = (event) => { if (event.key === "Escape") { requestClose(); } }; window.addEventListener("keydown", closeOnEscape); return () => window.removeEventListener("keydown", closeOnEscape); }, [requestClose]); return (
{ if (event.target === event.currentTarget) { requestClose(); } }} >

全部国家

{items.length} 个国家 / 按充值规模展示
); } function formatRankMoney(value) { const amount = moneyMajor(value); if (Math.abs(amount) >= 100_000) { return `$${(amount / 1_000_000).toFixed(2)}M`; } return formatMoney(value); } function hasRecharge(item) { return Number(item?.recharge_usd_minor) > 0; }