diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx index bc34732..b7bfed3 100644 --- a/frontend/src/components/Layout.tsx +++ b/frontend/src/components/Layout.tsx @@ -141,7 +141,7 @@ function MonitorBadge({ active }: { active: boolean }) { ) } -function SidebarIndexQuotes({ rows, items }: { rows: IndexQuote[] | undefined; items: CoreIndex[] }) { +function SidebarIndexQuotes({ rows, items }: { rows: IndexQuote[] | undefined; items: readonly CoreIndex[] }) { if (items.length === 0) return null const quoteBySymbol = new Map((rows ?? []).map(q => [q.symbol, q])) return ( @@ -445,15 +445,12 @@ export function Layout() { return next }) } - const indicesPinned = prefs?.indices_nav_pinned ?? true - const sidebarIndexSymbols = prefs?.sidebar_index_symbols ?? CORE_INDEXES.map(p => p.symbol) - const sidebarIndexes = CORE_INDEXES.filter(item => sidebarIndexSymbols.includes(item.symbol)) - // 卡片数据:固定显示时也拉取(即使实时行情关闭) - const showSidebarQuotes = indicesPinned || realtimeEnabled + // 指数条: 固定核心四只 (产品契约, 不再可配置), 常驻显示 + const sidebarIndexes = CORE_INDEXES const { data: sidebarIndexQuotes } = useQuery({ - queryKey: [...QK.indexQuotes, 'sidebar', sidebarIndexSymbols.join(',')] as const, + queryKey: [...QK.indexQuotes, 'sidebar', 'core'] as const, queryFn: () => api.indexQuotes(sidebarIndexes.map(p => p.symbol)), - enabled: showSidebarQuotes && sidebarIndexes.length > 0, + enabled: sidebarIndexes.length > 0, placeholderData: (prev) => prev, }) @@ -877,7 +874,7 @@ export function Layout() { )} )} - {showSidebarQuotes && !isWatchlistMode && (!realtimeUnavailable || !!realtimeProviderName) && ( + {!isWatchlistMode && (!realtimeUnavailable || !!realtimeProviderName) && ( )} diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index a960d9f..86f603d 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -1595,7 +1595,6 @@ export interface WecomBotStatus { export interface Preferences { realtime_quotes_enabled: boolean - indices_nav_pinned: boolean watchlist_groups_in_nav: boolean minute_sync_enabled: boolean minute_sync_days: number @@ -1614,9 +1613,6 @@ export interface Preferences { data_source_long_job_timeout_s: number realtime_pull_stock?: boolean realtime_pull_etf?: boolean - realtime_pull_index?: boolean - realtime_index_mode?: 'core' | 'all' - realtime_index_symbols?: string[] pipeline_pull_a_share: boolean pipeline_pull_etf: boolean pipeline_pull_index: boolean @@ -1645,7 +1641,6 @@ export interface Preferences { wecom_bot_enabled?: boolean webhook_enabled_default?: boolean webhook_default_channels?: string[] - sidebar_index_symbols: string[] nav_order: string[] nav_hidden: string[] screener_auto_run: boolean @@ -1851,16 +1846,11 @@ export const api = { method: 'PUT', body: JSON.stringify({ realtime_quotes_enabled: enabled }), }), - updateRealtimeQuoteScope: (cfg: Partial>) => + updateRealtimeQuoteScope: (cfg: Partial>) => request>('/api/settings/preferences/realtime-quote-scope', { method: 'PUT', body: JSON.stringify(cfg), }), - updateIndicesNavPinned: (pinned: boolean) => - request<{ indices_nav_pinned: boolean }>('/api/settings/preferences/indices-nav-pinned', { - method: 'PUT', - body: JSON.stringify({ indices_nav_pinned: pinned }), - }), updateWatchlistGroupsInNav: (enabled: boolean) => request<{ watchlist_groups_in_nav: boolean }>('/api/settings/preferences/watchlist-groups-in-nav', { method: 'PUT', @@ -1904,7 +1894,6 @@ export const api = { sse_refresh_pages?: Record strategy_monitor_enabled?: boolean strategy_monitor_ids?: string[] - sidebar_index_symbols?: string[] screener_auto_run?: boolean minute_intraday_refresh?: boolean minute_intraday_refresh_interval?: number @@ -1914,7 +1903,6 @@ export const api = { sse_refresh_pages: Record strategy_monitor_enabled: boolean strategy_monitor_ids: string[] - sidebar_index_symbols: string[] screener_auto_run: boolean minute_intraday_refresh: boolean minute_intraday_refresh_interval: number @@ -2105,11 +2093,6 @@ export const api = { }>( `/api/kline/minute-range?symbol=${encodeURIComponent(symbol)}&days=${days}`, ), - indexList: () => request<{ results: IndexInstrument[]; count: number }>('/api/index/list'), - indexSearch: (q: string, limit = 20) => - request<{ results: IndexInstrument[] }>( - `/api/index/search?q=${encodeURIComponent(q)}&limit=${limit}`, - ), indexDaily: (symbol: string, days = 120, dateRange?: { start: string; end: string }) => request<{ symbol: string @@ -2126,7 +2109,6 @@ export const api = { request<{ symbol: string name?: string - index_info?: IndexInstrument date: string | null rows: MinuteKlineRow[] source?: string diff --git a/frontend/src/lib/queryKeys.ts b/frontend/src/lib/queryKeys.ts index a05eefd..50c4780 100644 --- a/frontend/src/lib/queryKeys.ts +++ b/frontend/src/lib/queryKeys.ts @@ -20,7 +20,6 @@ export const QK = { quoteInterval: ['quote-interval'] as const, overviewMarket: (asOf?: string) => ['overview-market', asOf ?? 'latest'] as const, indexQuotes: ['index-quotes'] as const, - indexList: ['index-list'] as const, // Watchlist watchlist: ['watchlist'] as const, @@ -86,9 +85,9 @@ export const QK = { klineMinuteRange: (symbol: string, days: number) => ['kline-minute-range', symbol, days] as const, indexDaily: (symbol: string, start: string, end: string) => - ['index-daily', symbol, start, end] as const, + ['index-daily', symbol, start, end] as const, indexMinute: (symbol: string, date: string) => - ['index-minute', symbol, date] as const, + ['index-minute', symbol, date] as const, // Schema extDataSchemaAll: ['ext-data-schema-all'] as const, diff --git a/frontend/src/pages/Data.tsx b/frontend/src/pages/Data.tsx index d3a8046..c2a88b2 100644 --- a/frontend/src/pages/Data.tsx +++ b/frontend/src/pages/Data.tsx @@ -162,7 +162,6 @@ export function Data() { mutationFn: () => api.syncIndexDaily(indexSyncDays), onSuccess: () => { qc.invalidateQueries({ queryKey: QK.dataStatus }) - qc.invalidateQueries({ queryKey: QK.indexList }) qc.invalidateQueries({ queryKey: QK.indexQuotes }) qc.invalidateQueries({ queryKey: ['index-daily'] }) }, diff --git a/frontend/src/pages/Indices.tsx b/frontend/src/pages/Indices.tsx index ae51cd3..e48a9f3 100644 --- a/frontend/src/pages/Indices.tsx +++ b/frontend/src/pages/Indices.tsx @@ -1,7 +1,7 @@ import { useEffect, useMemo, useState } from 'react' import { useSearchParams } from 'react-router-dom' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' -import { Activity, Loader2, Lock, RefreshCw, Search } from 'lucide-react' +import { Activity, Loader2, Lock, RefreshCw } from 'lucide-react' import { api, type IndexInstrument, type KlineRow, type MinuteKlineRow } from '@/lib/api' import { QK } from '@/lib/queryKeys' import { useCapabilities } from '@/lib/useSharedQueries' @@ -61,14 +61,9 @@ const PINNED_INDEXES = [ { symbol: '000680.SH', name: '科创综指' }, ] -function pinnedRank(item: IndexInstrument) { - return PINNED_INDEXES.findIndex(p => item.symbol === p.symbol || item.name === p.name) -} - export function Indices() { const qc = useQueryClient() const [searchParams, setSearchParams] = useSearchParams() - const [keyword, setKeyword] = useState('') const symbolParam = searchParams.get('symbol') ?? '' const [selected, setSelected] = useState(symbolParam) const [range, setRange] = useState(defaultRange) @@ -79,29 +74,12 @@ export function Indices() { const caps = useCapabilities() const hasMinuteCap = !!caps.data?.capabilities?.['kline.minute.batch'] - const list = useQuery({ - queryKey: QK.indexList, - queryFn: api.indexList, - }) + // 指数标的固定核心四只 (产品契约, 不再提供全指数搜索/浏览) + const topRows: IndexInstrument[] = PINNED_INDEXES.map(p => ({ + symbol: p.symbol, name: p.name, asset_type: 'index' as const, + })) - const search = useQuery({ - queryKey: ['index-search', keyword], - queryFn: () => api.indexSearch(keyword, 50), - enabled: keyword.trim().length > 0, - }) - - const rows: IndexInstrument[] = keyword.trim() - ? (search.data?.results ?? []) - : (list.data?.results ?? []) - const topRows = useMemo(() => { - const all = list.data?.results ?? [] - return PINNED_INDEXES.map(p => ( - all.find(item => item.symbol === p.symbol || item.name === p.name) ?? { symbol: p.symbol, name: p.name, asset_type: 'index' as const } - )) - }, [list.data?.results]) - const listRows = useMemo(() => rows.filter(item => pinnedRank(item) < 0), [rows]) - - const selectedSymbol = selected || topRows[0]?.symbol || listRows[0]?.symbol || '' + const selectedSymbol = selected || topRows[0]?.symbol || '' useEffect(() => { if (symbolParam && symbolParam !== selected) setSelected(symbolParam) @@ -132,18 +110,9 @@ export function Indices() { placeholderData: (prev) => prev, }) - const syncInstruments = useMutation({ - mutationFn: api.syncIndexInstruments, - onSuccess: () => { - qc.invalidateQueries({ queryKey: QK.indexList }) - qc.invalidateQueries({ queryKey: QK.indexQuotes }) - }, - }) - const syncDaily = useMutation({ mutationFn: () => api.syncIndexDaily(365), onSuccess: () => { - qc.invalidateQueries({ queryKey: QK.indexList }) qc.invalidateQueries({ queryKey: QK.indexQuotes }) qc.invalidateQueries({ queryKey: ['index-daily'] }) }, @@ -159,7 +128,7 @@ export function Indices() { const selectedQuotePct = selectedQuote?.change_pct ?? selectedQuote?.pct const chartRows = useMemo(() => toOHLC(daily.data?.rows ?? []), [daily.data?.rows]) - const selectedInfo = [...topRows, ...listRows].find(r => r.symbol === selectedSymbol) || daily.data?.index_info + const selectedInfo = topRows.find(r => r.symbol === selectedSymbol) || daily.data?.index_info const minuteRows: MinuteKlineRow[] = minute.data?.rows ?? [] const selectedIdx = selectedDate ? chartRows.findIndex(r => r.date === selectedDate) : -1 const prevClose = selectedIdx > 0 @@ -211,14 +180,6 @@ export function Indices() {

-
{/* ========== 右列 ========== */} diff --git a/frontend/src/router.tsx b/frontend/src/router.tsx index 36456f0..4c19bca 100644 --- a/frontend/src/router.tsx +++ b/frontend/src/router.tsx @@ -29,9 +29,9 @@ const IndustryAnalysis = lazy(() => import('./pages/IndustryAnalysis').then(m => const StockAnalysis = lazy(() => import('./pages/StockAnalysis').then(m => ({ default: m.StockAnalysis }))) const Review = lazy(() => import('./pages/Review').then(m => ({ default: m.Review }))) const LimitUpLadder = lazy(() => import('./pages/LimitUpLadder').then(m => ({ default: m.LimitUpLadder }))) +const Indices = lazy(() => import('./pages/Indices').then(m => ({ default: m.Indices }))) const Branding = lazy(() => import('./pages/Branding').then(m => ({ default: m.Branding }))) const Settings = lazy(() => import('./pages/Settings').then(m => ({ default: m.Settings }))) -const Indices = lazy(() => import('./pages/Indices').then(m => ({ default: m.Indices }))) const Regime = lazy(() => import('./pages/Regime').then(m => ({ default: m.Regime }))) const AbnormalMoves = lazy(() => import('./pages/AbnormalMoves').then(m => ({ default: m.AbnormalMoves }))) const Dev = lazy(() => import('./pages/Dev').then(m => ({ default: m.Dev })))