feat: StockQuoteCard 根据股票代码获取真实行情数据

- 新增 useStockQuote Hook 获取股票行情
- Company 页面使用 Hook 并传递数据给 StockQuoteCard
- StockQuoteCard 处理 null 数据显示骨架屏
- 股票代码变化时自动刷新行情数据

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zdl
2025-12-10 11:00:03 +08:00
parent 0997cd9992
commit 8786fa7b06
3 changed files with 120 additions and 9 deletions

View File

@@ -0,0 +1,100 @@
// src/views/Company/hooks/useStockQuote.js
// 股票行情数据获取 Hook
import { useState, useEffect } from 'react';
import { stockService } from '@services/eventService';
import { logger } from '@utils/logger';
/**
* 将 API 响应数据转换为 StockQuoteCard 所需格式
*/
const transformQuoteData = (apiData, stockCode) => {
if (!apiData) return null;
return {
// 基础信息
name: apiData.name || apiData.stock_name || '未知',
code: apiData.code || apiData.stock_code || stockCode,
indexTags: apiData.index_tags || apiData.indexTags || [],
// 价格信息
currentPrice: apiData.current_price || apiData.currentPrice || apiData.close || 0,
changePercent: apiData.change_percent || apiData.changePercent || apiData.pct_chg || 0,
todayOpen: apiData.today_open || apiData.todayOpen || apiData.open || 0,
yesterdayClose: apiData.yesterday_close || apiData.yesterdayClose || apiData.pre_close || 0,
todayHigh: apiData.today_high || apiData.todayHigh || apiData.high || 0,
todayLow: apiData.today_low || apiData.todayLow || apiData.low || 0,
// 关键指标
pe: apiData.pe || apiData.pe_ttm || 0,
pb: apiData.pb || apiData.pb_mrq || 0,
marketCap: apiData.market_cap || apiData.marketCap || apiData.circ_mv || '0',
week52Low: apiData.week52_low || apiData.week52Low || 0,
week52High: apiData.week52_high || apiData.week52High || 0,
// 主力动态
mainNetInflow: apiData.main_net_inflow || apiData.mainNetInflow || 0,
institutionHolding: apiData.institution_holding || apiData.institutionHolding || 0,
buyRatio: apiData.buy_ratio || apiData.buyRatio || 50,
sellRatio: apiData.sell_ratio || apiData.sellRatio || 50,
// 更新时间
updateTime: apiData.update_time || apiData.updateTime || new Date().toLocaleString(),
};
};
/**
* 股票行情数据获取 Hook
*
* @param {string} stockCode - 股票代码
* @returns {Object} { data, isLoading, error, refetch }
*/
export const useStockQuote = (stockCode) => {
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
if (!stockCode) {
setData(null);
return;
}
const fetchQuote = async () => {
setIsLoading(true);
setError(null);
try {
logger.debug('useStockQuote', '获取股票行情', { stockCode });
const quotes = await stockService.getQuotes([stockCode]);
// API 返回格式: { [stockCode]: quoteData }
const quoteData = quotes?.[stockCode] || quotes;
const transformedData = transformQuoteData(quoteData, stockCode);
logger.debug('useStockQuote', '行情数据转换完成', { stockCode, hasData: !!transformedData });
setData(transformedData);
} catch (err) {
logger.error('useStockQuote', '获取行情失败', err);
setError(err);
setData(null);
} finally {
setIsLoading(false);
}
};
fetchQuote();
}, [stockCode]);
// 手动刷新
const refetch = () => {
if (stockCode) {
setData(null);
// 触发 useEffect 重新执行
}
};
return { data, isLoading, error, refetch };
};
export default useStockQuote;