diff --git a/src/routes/sectors.tsx b/src/routes/sectors.tsx index 2f7e0da..9d3db24 100644 --- a/src/routes/sectors.tsx +++ b/src/routes/sectors.tsx @@ -1,14 +1,15 @@ -import { createFileRoute } from "@tanstack/react-router"; -import { useState, useEffect, useMemo, useRef } from "react"; +import { createFileRoute, Link } from "@tanstack/react-router"; +import { useState, useMemo } from "react"; +import { useQuery } from "@tanstack/react-query"; import { fetchSectors, type SectorItem, type SectorType } from "@/lib/stock-api"; import { Card, CardContent } from "@/components/ui/card"; import { ArrowLeft, TrendingUp, TrendingDown, RefreshCw } from "lucide-react"; -import { Link } from "@tanstack/react-router"; export const Route = createFileRoute("/sectors")({ component: SectorsPage, }); +/* ── Tab 定义 ── */ const TABS: { key: SectorType; label: string }[] = [ { key: "industry", label: "行业板块" }, { key: "concept", label: "概念板块" }, @@ -16,38 +17,28 @@ const TABS: { key: SectorType; label: string }[] = [ type SortMode = "mainNetInflow" | "changePercent"; +/* ── 页面组件 ── */ function SectorsPage() { const [tab, setTab] = useState("industry"); - const [data, setData] = useState([]); - const [loading, setLoading] = useState(true); const [sort, setSort] = useState("mainNetInflow"); - const abortRef = useRef(null); - const loadData = (t: SectorType) => { - // 取消上次未完成的请求 - abortRef.current?.abort(); - const controller = new AbortController(); - abortRef.current = controller; - setLoading(true); - fetchSectors(t, controller.signal).then((items) => { - if (!controller.signal.aborted) { - setData(items); - setLoading(false); - } - }); - }; + // 使用 useQuery:queryKey 包含 tab,切换 tab 时 queryKey 变化 + // React Query 自动隔离 industry / concept 的数据,不会混用 + const { data = [], isLoading, isFetching, refetch } = useQuery({ + queryKey: ["sectors", tab], + queryFn: ({ signal }) => fetchSectors(tab, signal), + staleTime: 30_000, + retry: false, + }); - useEffect(() => { - loadData(tab); - return () => abortRef.current?.abort(); - }, [tab]); - - const sorted = useMemo(() => { - return [...data].sort((a, b) => { - if (sort === "mainNetInflow") return b.mainNetInflow - a.mainNetInflow; - return (b.changePercent ?? 0) - (a.changePercent ?? 0); - }); - }, [data, sort]); + const sorted = useMemo( + () => + [...data].sort((a, b) => { + if (sort === "mainNetInflow") return b.mainNetInflow - a.mainNetInflow; + return (b.changePercent ?? 0) - (a.changePercent ?? 0); + }), + [data, sort], + ); return (
@@ -61,27 +52,21 @@ function SectorsPage() {

板块资金流向

- {/* Tab + Sorting 切换 */} + {/* Tab + 排序切换 */}
{TABS.map((t) => (
- - + + > + 涨幅 +
- {/* 数据信息 */} + {/* 数据概览 */}

- 含 {sorted.length} 个板块 · 按{sort === "mainNetInflow" ? "主力净流入" : "涨跌幅"}降序 + 共 {sorted.length} 个板块 · 按{sort === "mainNetInflow" ? "主力净流入" : "涨跌幅"}降序

- {/* 卡片网格 */} + {/* 卡片列表 */}
- {loading ? ( + {isLoading ? (
{Array.from({ length: 20 }).map((_, i) => (
))}
+ ) : sorted.length === 0 ? ( +
暂无数据
) : (
{sorted.map((item) => ( @@ -137,6 +130,7 @@ function SectorsPage() { ); } +/* ── 工具函数 ── */ function formatInflow(val: number | null | undefined): string { if (val == null) return "--"; const abs = Math.abs(val); @@ -145,6 +139,7 @@ function formatInflow(val: number | null | undefined): string { return val.toFixed(0); } +/* ── 资金流向横条 ── */ function FundFlowBar({ value, maxAbs }: { value: number | null | undefined; maxAbs: number }) { if (value == null) return null; const pct = maxAbs > 0 ? (value / maxAbs) * 100 : 0; @@ -159,15 +154,18 @@ function FundFlowBar({ value, maxAbs }: { value: number | null | undefined; maxA style={{ width: `${Math.min(Math.abs(pct), 100)}%`, marginLeft: isPos ? "50%" : undefined }} />
- + {formatInflow(value)}
); } +/* ── 单个板块卡片 ── */ function SectorBlock({ item }: { item: SectorItem }) { const inflow = item.mainNetInflow; const isPositive = inflow >= 0; @@ -178,7 +176,7 @@ function SectorBlock({ item }: { item: SectorItem }) { Math.abs(item.largeInflow ?? 0), Math.abs(item.mediumInflow ?? 0), Math.abs(item.smallInflow ?? 0), - 1 + 1, ); return ( @@ -196,7 +194,7 @@ function SectorBlock({ item }: { item: SectorItem }) { )}
- {/* 涨跌幅 */} + {/* 涨跌幅 + 成交额 */}
{change != null ? ( -- )} - - {formatInflow(item.turnover)} - + {formatInflow(item.turnover)}
- {/* 主力净流入 */} + {/* 主力净流入 + 明细 */}
主力净流入 - - {isPositive ? "+" : ""}{formatInflow(inflow)} + + {isPositive ? "+" : ""} + {formatInflow(inflow)}
- {/* 资金流向明细条 */}