From dbd4cb39ec6dc690f5b5e99803a8768eb69963ab Mon Sep 17 00:00:00 2001 From: zzlgreat Date: Wed, 17 Dec 2025 18:27:56 +0800 Subject: [PATCH] update pay ui --- .../DynamicTracking/components/NewsPanel.js | 73 +++--------- .../MarketDataView/hooks/useMarketData.ts | 107 ++++++++++-------- .../components/MarketDataView/types.ts | 1 + 3 files changed, 77 insertions(+), 104 deletions(-) diff --git a/src/views/Company/components/DynamicTracking/components/NewsPanel.js b/src/views/Company/components/DynamicTracking/components/NewsPanel.js index 983d7d63..e01310cf 100644 --- a/src/views/Company/components/DynamicTracking/components/NewsPanel.js +++ b/src/views/Company/components/DynamicTracking/components/NewsPanel.js @@ -6,30 +6,6 @@ import { logger } from '@utils/logger'; import axios from '@utils/axiosConfig'; import NewsEventsTab from '../../CompanyOverview/NewsEventsTab'; -/** - * 标准化股票代码(补全后缀) - * @param {string} code - 股票代码(可能不带后缀) - * @returns {string} 带后缀的股票代码 - */ -const normalizeStockCode = (code) => { - if (!code) return code; - // 已有后缀则直接返回 - if (code.includes('.')) return code; - - const pureCode = code.replace(/\D/g, ''); - if (pureCode.length !== 6) return code; - - const prefix = pureCode[0]; - // 上交所:6、9 开头 - if (prefix === '6' || prefix === '9') return `${pureCode}.SH`; - // 深交所:0、2、3 开头 - if (prefix === '0' || prefix === '2' || prefix === '3') return `${pureCode}.SZ`; - // 北交所:8、4 开头 - if (prefix === '8' || prefix === '4') return `${pureCode}.BJ`; - - return code; -}; - const NewsPanel = ({ stockCode }) => { const [newsEvents, setNewsEvents] = useState([]); const [loading, setLoading] = useState(false); @@ -42,39 +18,22 @@ const NewsPanel = ({ stockCode }) => { has_prev: false, }); const [searchQuery, setSearchQuery] = useState(''); - const [stockName, setStockName] = useState(''); - - // 获取股票名称 - const fetchStockName = useCallback(async () => { - try { - const { data: result } = await axios.get( - `/api/stock/${stockCode}/basic-info` - ); - if (result.success && result.data) { - const name = result.data.SECNAME || result.data.ORGNAME || stockCode; - setStockName(name); - return name; - } - return stockCode; - } catch (err) { - logger.error('NewsPanel', 'fetchStockName', err, { stockCode }); - return stockCode; - } - }, [stockCode]); // 加载新闻事件 const loadNewsEvents = useCallback( async (query, page = 1) => { setLoading(true); try { - // 优先使用自定义查询,否则用股票名称,最后用带后缀的股票代码 - const searchTerm = query || stockName || normalizeStockCode(stockCode); + // 优先使用自定义查询,否则用股票代码(6位纯数字即可) + const searchTerm = query || stockCode.replace(/\.\w+$/, ''); // 移除后缀如 .SZ const { data: result } = await axios.get( - `/api/events?q=${encodeURIComponent(searchTerm)}&page=${page}&per_page=10` + `/api/events?sort=new&importance=all&q=${encodeURIComponent(searchTerm)}&page=${page}&mode=vertical&per_page=10` ); if (result.success) { - setNewsEvents(result.data || []); + // API 返回结构: { data: { events: [...] }, pagination: {...} } + const events = result.data?.events || result.data || []; + setNewsEvents(events); setPagination({ page: result.pagination?.page || page, per_page: result.pagination?.per_page || 10, @@ -91,19 +50,15 @@ const NewsPanel = ({ stockCode }) => { setLoading(false); } }, - [stockCode, stockName] + [stockCode] ); - // 首次加载 + // 首次加载 - 直接用股票代码搜索 useEffect(() => { - const initLoad = async () => { - if (stockCode) { - const name = await fetchStockName(); - await loadNewsEvents(name, 1); - } - }; - initLoad(); - }, [stockCode, fetchStockName, loadNewsEvents]); + if (stockCode) { + loadNewsEvents(null, 1); + } + }, [stockCode, loadNewsEvents]); // 搜索处理 const handleSearchChange = (value) => { @@ -111,12 +66,12 @@ const NewsPanel = ({ stockCode }) => { }; const handleSearch = () => { - loadNewsEvents(searchQuery || stockName, 1); + loadNewsEvents(searchQuery || null, 1); }; // 分页处理 const handlePageChange = (page) => { - loadNewsEvents(searchQuery || stockName, page); + loadNewsEvents(searchQuery || null, page); }; return ( diff --git a/src/views/Company/components/MarketDataView/hooks/useMarketData.ts b/src/views/Company/components/MarketDataView/hooks/useMarketData.ts index 497502e9..092eca80 100644 --- a/src/views/Company/components/MarketDataView/hooks/useMarketData.ts +++ b/src/views/Company/components/MarketDataView/hooks/useMarketData.ts @@ -41,6 +41,9 @@ export const useMarketData = ( const [minuteData, setMinuteData] = useState(null); const [minuteLoading, setMinuteLoading] = useState(false); + // 涨幅分析懒加载状态 + const [analysisLoading, setAnalysisLoading] = useState(false); + // 记录是否已完成首次加载 const isInitializedRef = useRef(false); // 记录上一次的 stockCode,用于判断是否需要重新加载所有数据 @@ -49,15 +52,50 @@ export const useMarketData = ( const prevPeriodRef = useRef(period); /** - * 加载所有市场数据 + * 加载涨幅分析数据(懒加载) + * 需要 tradeData 来建立日期索引映射 + */ + const loadRiseAnalysis = useCallback(async (tradeDataForMapping: TradeDayData[]) => { + if (!stockCode || tradeDataForMapping.length === 0) return; + + logger.debug('useMarketData', '开始懒加载涨幅分析', { stockCode }); + setAnalysisLoading(true); + + try { + const riseAnalysisRes = await marketService.getRiseAnalysis(stockCode); + + if (riseAnalysisRes.success && riseAnalysisRes.data) { + const tempAnalysisMap: Record = {}; + riseAnalysisRes.data.forEach((analysis) => { + const dateIndex = tradeDataForMapping.findIndex( + (item) => item.date.substring(0, 10) === analysis.trade_date + ); + if (dateIndex !== -1) { + tempAnalysisMap[dateIndex] = analysis; + } + }); + setAnalysisMap(tempAnalysisMap); + logger.info('useMarketData', '涨幅分析加载成功', { stockCode, count: Object.keys(tempAnalysisMap).length }); + } + } catch (error) { + logger.error('useMarketData', 'loadRiseAnalysis', error, { stockCode }); + } finally { + setAnalysisLoading(false); + } + }, [stockCode]); + + /** + * 加载所有市场数据(涨幅分析延迟加载) */ const loadMarketData = useCallback(async () => { if (!stockCode) return; logger.debug('useMarketData', '开始加载市场数据', { stockCode, period }); setLoading(true); + setAnalysisMap({}); // 清空旧的分析数据 try { + // 先加载核心数据(不含涨幅分析) const [ summaryRes, tradeRes, @@ -65,7 +103,6 @@ export const useMarketData = ( bigDealRes, unusualRes, pledgeRes, - riseAnalysisRes, ] = await Promise.all([ marketService.getMarketSummary(stockCode), marketService.getTradeData(stockCode, period), @@ -73,7 +110,6 @@ export const useMarketData = ( marketService.getBigDealData(stockCode, 30), marketService.getUnusualData(stockCode, 30), marketService.getPledgeData(stockCode), - marketService.getRiseAnalysis(stockCode), ]); // 设置概览数据 @@ -82,8 +118,10 @@ export const useMarketData = ( } // 设置交易数据 + let loadedTradeData: TradeDayData[] = []; if (tradeRes.success) { - setTradeData(tradeRes.data); + loadedTradeData = tradeRes.data; + setTradeData(loadedTradeData); } // 设置融资融券数据 @@ -106,31 +144,18 @@ export const useMarketData = ( setPledgeData(pledgeRes.data); } - // 设置涨幅分析数据并创建映射 - if (riseAnalysisRes.success) { - const tempAnalysisMap: Record = {}; - - if (tradeRes.success && tradeRes.data && riseAnalysisRes.data) { - riseAnalysisRes.data.forEach((analysis) => { - const dateIndex = tradeRes.data.findIndex( - (item) => item.date.substring(0, 10) === analysis.trade_date - ); - if (dateIndex !== -1) { - tempAnalysisMap[dateIndex] = analysis; - } - }); - } - - setAnalysisMap(tempAnalysisMap); - } - logger.info('useMarketData', '市场数据加载成功', { stockCode }); + + // 核心数据加载完成后,异步加载涨幅分析(不阻塞界面) + if (loadedTradeData.length > 0) { + loadRiseAnalysis(loadedTradeData); + } } catch (error) { logger.error('useMarketData', 'loadMarketData', error, { stockCode, period }); } finally { setLoading(false); } - }, [stockCode, period]); + }, [stockCode, period, loadRiseAnalysis]); /** * 加载分钟K线数据 @@ -168,7 +193,7 @@ export const useMarketData = ( }, [stockCode]); /** - * 单独刷新日K线数据(只刷新交易数据和涨幅分析) + * 单独刷新日K线数据(涨幅分析懒加载) * 用于切换时间周期时,避免重新加载所有数据 */ const refreshTradeData = useCallback(async () => { @@ -176,40 +201,31 @@ export const useMarketData = ( logger.debug('useMarketData', '刷新日K线数据', { stockCode, period }); setTradeLoading(true); + setAnalysisMap({}); // 清空旧的分析数据 try { - // 并行获取交易数据和涨幅分析 - const [tradeRes, riseAnalysisRes] = await Promise.all([ - marketService.getTradeData(stockCode, period), - marketService.getRiseAnalysis(stockCode), - ]); + // 先加载交易数据 + const tradeRes = await marketService.getTradeData(stockCode, period); // 更新交易数据 + let loadedTradeData: TradeDayData[] = []; if (tradeRes.success && tradeRes.data) { - setTradeData(tradeRes.data); - - // 重建涨幅分析映射 - if (riseAnalysisRes.success && riseAnalysisRes.data) { - const tempAnalysisMap: Record = {}; - riseAnalysisRes.data.forEach((analysis) => { - const dateIndex = tradeRes.data.findIndex( - (item) => item.date.substring(0, 10) === analysis.trade_date - ); - if (dateIndex !== -1) { - tempAnalysisMap[dateIndex] = analysis; - } - }); - setAnalysisMap(tempAnalysisMap); - } + loadedTradeData = tradeRes.data; + setTradeData(loadedTradeData); } logger.info('useMarketData', '日K线数据刷新成功', { stockCode, period }); + + // K线数据加载完成后,异步加载涨幅分析(不阻塞界面) + if (loadedTradeData.length > 0) { + loadRiseAnalysis(loadedTradeData); + } } catch (error) { logger.error('useMarketData', 'refreshTradeData', error, { stockCode, period }); } finally { setTradeLoading(false); } - }, [stockCode, period]); + }, [stockCode, period, loadRiseAnalysis]); /** * 刷新所有数据 @@ -253,6 +269,7 @@ export const useMarketData = ( minuteData, minuteLoading, analysisMap, + analysisLoading, refetch, loadMinuteData, refreshTradeData, diff --git a/src/views/Company/components/MarketDataView/types.ts b/src/views/Company/components/MarketDataView/types.ts index 9087c156..8a133dd7 100644 --- a/src/views/Company/components/MarketDataView/types.ts +++ b/src/views/Company/components/MarketDataView/types.ts @@ -366,6 +366,7 @@ export interface UseMarketDataReturn { minuteData: MinuteData | null; minuteLoading: boolean; analysisMap: Record; + analysisLoading: boolean; refetch: () => Promise; loadMinuteData: () => Promise; refreshTradeData: () => Promise;