import { useEffect, useMemo, useState } from 'react' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { Loader2 } from 'lucide-react' import { api, type MinuteKlineRow } from '@/lib/api' import { QK } from '@/lib/queryKeys' import { klineMinuteQueryOptions, minuteRefetchInterval } from '@/lib/kline' import { EChartsIntraday } from '@/components/EChartsIntraday' interface Props { symbol: string date: string | null height?: number prevClose?: number className?: string onPriceHover?: (price: number | null) => void onPriceDoubleClick?: (price: number, currentPrice: number) => void currentPrice?: number priceLines?: { value: number; label?: string; color?: string }[] /** 自动刷新间隔(ms)。undefined/0 = 不轮询(默认)。个股对话框盘中实时刷新时传入。 */ refetchIntervalMs?: number } export function StockIntradayChart({ symbol, date, height = 520, prevClose, className, onPriceHover, onPriceDoubleClick, currentPrice, priceLines, refetchIntervalMs, }: Props) { const qc = useQueryClient() const [minuteDismissed, setMinuteDismissed] = useState(false) const minute = useQuery({ // 轮询上下文 (个股详情) 传 live: 当日盘中后端直接实时拉取最新K, // 避免读到分钟增量落盘的上一轮本地分区; 历史日期后端自行忽略 live。 ...klineMinuteQueryOptions(symbol, date ?? undefined, refetchIntervalMs != null), enabled: !!symbol && !!date, refetchInterval: minuteRefetchInterval(refetchIntervalMs), }) const fetchMinute = useMutation({ mutationFn: () => api.syncMinuteSingle(symbol), onSuccess: () => { qc.invalidateQueries({ queryKey: ['kline-minute', symbol] }) qc.invalidateQueries({ queryKey: QK.klineMinute(symbol, date ?? '') }) setMinuteDismissed(false) }, }) const minuteRows: MinuteKlineRow[] = useMemo(() => minute.data?.rows ?? [], [minute.data?.rows]) // source=none 表示本地无数据且 TickFlow 也拉不到 (停牌/复牌延迟/非交易日) // 此时不弹"是否获取"询问窗, 只做静态提示, 避免误导用户去拉明知拉不到的数据 const sourceIsNone = minute.data?.source === 'none' // 指数分钟K无本地存储且不支持落库获取 (后端 sync_minute_single 显式拒绝), 不显示获取按钮 const isIndex = minute.data?.asset_type === 'index' useEffect(() => { setMinuteDismissed(false) onPriceHover?.(null) }, [date, onPriceHover]) if (!symbol || !date) return null return (