refactor(StockQuoteCard): 数据下沉优化,Props 从 11 个精简为 4 个
- StockQuoteCard 使用内部 hooks 获取行情数据、基本信息和对比数据 - 更新 types.ts,简化 Props 接口 - Company/index.js 移除已下沉的数据获取逻辑(~40 行) - 删除 Company/hooks/useStockQuote.js(已移至组件内部) 优化收益: - Props 数量: 11 → 4 (-64%) - Company/index.js: ~172 → ~105 行 (-39%) - 组件可独立复用 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,8 @@
|
|||||||
*
|
*
|
||||||
* 展示股票的实时行情、关键指标和主力动态
|
* 展示股票的实时行情、关键指标和主力动态
|
||||||
* 采用原子组件拆分,提高可维护性和复用性
|
* 采用原子组件拆分,提高可维护性和复用性
|
||||||
|
*
|
||||||
|
* 优化:数据获取已下沉到组件内部,Props 从 11 个精简为 4 个
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
@@ -26,42 +28,46 @@ import {
|
|||||||
StockCompareModal,
|
StockCompareModal,
|
||||||
STOCK_CARD_THEME,
|
STOCK_CARD_THEME,
|
||||||
} from './components';
|
} from './components';
|
||||||
|
import { useStockQuoteData, useStockCompare } from './hooks';
|
||||||
import type { StockQuoteCardProps } from './types';
|
import type { StockQuoteCardProps } from './types';
|
||||||
|
|
||||||
const StockQuoteCard: React.FC<StockQuoteCardProps> = ({
|
const StockQuoteCard: React.FC<StockQuoteCardProps> = ({
|
||||||
data,
|
stockCode,
|
||||||
isLoading = false,
|
|
||||||
isInWatchlist = false,
|
isInWatchlist = false,
|
||||||
isWatchlistLoading = false,
|
isWatchlistLoading = false,
|
||||||
onWatchlistToggle,
|
onWatchlistToggle,
|
||||||
onShare,
|
}) => {
|
||||||
basicInfo,
|
// 内部获取行情数据和基本信息
|
||||||
// 对比相关
|
const { quoteData, basicInfo, isLoading } = useStockQuoteData(stockCode);
|
||||||
|
|
||||||
|
// 内部管理股票对比逻辑
|
||||||
|
const {
|
||||||
currentStockInfo,
|
currentStockInfo,
|
||||||
compareStockInfo,
|
compareStockInfo,
|
||||||
isCompareLoading = false,
|
isCompareLoading,
|
||||||
onCompare,
|
handleCompare: triggerCompare,
|
||||||
onCloseCompare,
|
clearCompare,
|
||||||
}) => {
|
} = useStockCompare(stockCode);
|
||||||
|
|
||||||
// 对比弹窗控制
|
// 对比弹窗控制
|
||||||
const { isOpen: isCompareModalOpen, onOpen: openCompareModal, onClose: closeCompareModal } = useDisclosure();
|
const { isOpen: isCompareModalOpen, onOpen: openCompareModal, onClose: closeCompareModal } = useDisclosure();
|
||||||
|
|
||||||
// 处理对比按钮点击
|
// 处理对比按钮点击
|
||||||
const handleCompare = (stockCode: string) => {
|
const handleCompare = (compareCode: string) => {
|
||||||
onCompare?.(stockCode);
|
triggerCompare(compareCode);
|
||||||
openCompareModal();
|
openCompareModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理关闭对比弹窗
|
// 处理关闭对比弹窗
|
||||||
const handleCloseCompare = () => {
|
const handleCloseCompare = () => {
|
||||||
closeCompareModal();
|
closeCompareModal();
|
||||||
onCloseCompare?.();
|
clearCompare();
|
||||||
};
|
};
|
||||||
|
|
||||||
const { cardBg, borderColor } = STOCK_CARD_THEME;
|
const { cardBg, borderColor } = STOCK_CARD_THEME;
|
||||||
|
|
||||||
// 加载中或无数据时显示骨架屏
|
// 加载中或无数据时显示骨架屏
|
||||||
if (isLoading || !data) {
|
if (isLoading || !quoteData) {
|
||||||
return (
|
return (
|
||||||
<Card bg={cardBg} shadow="sm" borderWidth="1px" borderColor={borderColor}>
|
<Card bg={cardBg} shadow="sm" borderWidth="1px" borderColor={borderColor}>
|
||||||
<CardBody>
|
<CardBody>
|
||||||
@@ -80,16 +86,15 @@ const StockQuoteCard: React.FC<StockQuoteCardProps> = ({
|
|||||||
<CardBody>
|
<CardBody>
|
||||||
{/* 顶部:股票名称 + 关注/分享按钮 + 更新时间 */}
|
{/* 顶部:股票名称 + 关注/分享按钮 + 更新时间 */}
|
||||||
<StockHeader
|
<StockHeader
|
||||||
name={data.name}
|
name={quoteData.name}
|
||||||
code={data.code}
|
code={quoteData.code}
|
||||||
industryL1={data.industryL1}
|
industryL1={quoteData.industryL1}
|
||||||
industry={data.industry}
|
industry={quoteData.industry}
|
||||||
indexTags={data.indexTags}
|
indexTags={quoteData.indexTags}
|
||||||
updateTime={data.updateTime}
|
updateTime={quoteData.updateTime}
|
||||||
isInWatchlist={isInWatchlist}
|
isInWatchlist={isInWatchlist}
|
||||||
isWatchlistLoading={isWatchlistLoading}
|
isWatchlistLoading={isWatchlistLoading}
|
||||||
onWatchlistToggle={onWatchlistToggle}
|
onWatchlistToggle={onWatchlistToggle}
|
||||||
onShare={onShare}
|
|
||||||
isCompareLoading={isCompareLoading}
|
isCompareLoading={isCompareLoading}
|
||||||
onCompare={handleCompare}
|
onCompare={handleCompare}
|
||||||
/>
|
/>
|
||||||
@@ -98,7 +103,7 @@ const StockQuoteCard: React.FC<StockQuoteCardProps> = ({
|
|||||||
<StockCompareModal
|
<StockCompareModal
|
||||||
isOpen={isCompareModalOpen}
|
isOpen={isCompareModalOpen}
|
||||||
onClose={handleCloseCompare}
|
onClose={handleCloseCompare}
|
||||||
currentStock={data.code}
|
currentStock={quoteData.code}
|
||||||
currentStockInfo={currentStockInfo || null}
|
currentStockInfo={currentStockInfo || null}
|
||||||
compareStock={compareStockInfo?.stock_code || ''}
|
compareStock={compareStockInfo?.stock_code || ''}
|
||||||
compareStockInfo={compareStockInfo || null}
|
compareStockInfo={compareStockInfo || null}
|
||||||
@@ -110,32 +115,32 @@ const StockQuoteCard: React.FC<StockQuoteCardProps> = ({
|
|||||||
{/* 左栏:价格信息 (flex=1) */}
|
{/* 左栏:价格信息 (flex=1) */}
|
||||||
<Box flex="1" minWidth="0">
|
<Box flex="1" minWidth="0">
|
||||||
<PriceDisplay
|
<PriceDisplay
|
||||||
currentPrice={data.currentPrice}
|
currentPrice={quoteData.currentPrice}
|
||||||
changePercent={data.changePercent}
|
changePercent={quoteData.changePercent}
|
||||||
/>
|
/>
|
||||||
<SecondaryQuote
|
<SecondaryQuote
|
||||||
todayOpen={data.todayOpen}
|
todayOpen={quoteData.todayOpen}
|
||||||
yesterdayClose={data.yesterdayClose}
|
yesterdayClose={quoteData.yesterdayClose}
|
||||||
todayHigh={data.todayHigh}
|
todayHigh={quoteData.todayHigh}
|
||||||
todayLow={data.todayLow}
|
todayLow={quoteData.todayLow}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{/* 右栏:关键指标 + 主力动态 (flex=2) */}
|
{/* 右栏:关键指标 + 主力动态 (flex=2) */}
|
||||||
<Flex flex="2" minWidth="0" gap={8} borderLeftWidth="1px" borderColor={borderColor} pl={8}>
|
<Flex flex="2" minWidth="0" gap={8} borderLeftWidth="1px" borderColor={borderColor} pl={8}>
|
||||||
<KeyMetrics
|
<KeyMetrics
|
||||||
pe={data.pe}
|
pe={quoteData.pe}
|
||||||
eps={data.eps}
|
eps={quoteData.eps}
|
||||||
pb={data.pb}
|
pb={quoteData.pb}
|
||||||
marketCap={data.marketCap}
|
marketCap={quoteData.marketCap}
|
||||||
week52Low={data.week52Low}
|
week52Low={quoteData.week52Low}
|
||||||
week52High={data.week52High}
|
week52High={quoteData.week52High}
|
||||||
/>
|
/>
|
||||||
<MainForceInfo
|
<MainForceInfo
|
||||||
mainNetInflow={data.mainNetInflow}
|
mainNetInflow={quoteData.mainNetInflow}
|
||||||
institutionHolding={data.institutionHolding}
|
institutionHolding={quoteData.institutionHolding}
|
||||||
buyRatio={data.buyRatio}
|
buyRatio={quoteData.buyRatio}
|
||||||
sellRatio={data.sellRatio}
|
sellRatio={quoteData.sellRatio}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
* StockQuoteCard 组件类型定义
|
* StockQuoteCard 组件类型定义
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { BasicInfo } from '../CompanyOverview/types';
|
// 注:BasicInfo 和 StockInfo 类型由内部 hooks 使用,不再在 Props 中传递
|
||||||
import type { StockInfo } from '../FinancialPanorama/types';
|
export type { StockInfo } from '../FinancialPanorama/types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 股票行情卡片数据
|
* 股票行情卡片数据
|
||||||
@@ -46,26 +46,18 @@ export interface StockQuoteCardData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* StockQuoteCard 组件 Props
|
* StockQuoteCard 组件 Props(优化后)
|
||||||
|
*
|
||||||
|
* 行情数据、基本信息、对比逻辑已下沉到组件内部 hooks 获取
|
||||||
|
* Props 从 11 个精简为 4 个
|
||||||
*/
|
*/
|
||||||
export interface StockQuoteCardProps {
|
export interface StockQuoteCardProps {
|
||||||
data?: StockQuoteCardData;
|
/** 股票代码 - 用于内部数据获取 */
|
||||||
isLoading?: boolean;
|
stockCode?: string;
|
||||||
// 自选股相关(与 WatchlistButton 接口保持一致)
|
/** 是否在自选股中(保留:涉及 Redux 和事件追踪回调) */
|
||||||
isInWatchlist?: boolean; // 是否在自选股中
|
isInWatchlist?: boolean;
|
||||||
isWatchlistLoading?: boolean; // 自选股操作加载中
|
/** 自选股操作加载中 */
|
||||||
onWatchlistToggle?: () => void; // 自选股切换回调
|
isWatchlistLoading?: boolean;
|
||||||
// 分享
|
/** 自选股切换回调 */
|
||||||
onShare?: () => void; // 分享回调
|
onWatchlistToggle?: () => void;
|
||||||
// 公司基本信息
|
|
||||||
basicInfo?: BasicInfo;
|
|
||||||
// 股票对比相关
|
|
||||||
currentStockInfo?: StockInfo; // 当前股票财务信息(用于对比)
|
|
||||||
compareStockInfo?: StockInfo; // 对比股票财务信息
|
|
||||||
isCompareLoading?: boolean; // 对比数据加载中
|
|
||||||
onCompare?: (stockCode: string) => void; // 触发对比回调
|
|
||||||
onCloseCompare?: () => void; // 关闭对比弹窗回调
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重新导出 StockInfo 类型以便外部使用
|
|
||||||
export type { StockInfo };
|
|
||||||
|
|||||||
@@ -1,103 +0,0 @@
|
|||||||
// 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 || [],
|
|
||||||
industry: apiData.industry || apiData.sw_industry_l2 || '',
|
|
||||||
industryL1: apiData.industry_l1 || apiData.sw_industry_l1 || '',
|
|
||||||
|
|
||||||
// 价格信息
|
|
||||||
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,
|
|
||||||
eps: apiData.eps || apiData.basic_eps || undefined,
|
|
||||||
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;
|
|
||||||
@@ -1,19 +1,17 @@
|
|||||||
// src/views/Company/index.js
|
// src/views/Company/index.js
|
||||||
// 公司详情页面入口 - 纯组合层
|
// 公司详情页面入口 - 纯组合层
|
||||||
|
//
|
||||||
|
// 优化:行情数据、基本信息、对比逻辑已下沉到 StockQuoteCard 内部
|
||||||
|
|
||||||
import React, { useEffect, useRef, useState, useCallback } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import { Container, VStack, useToast } from '@chakra-ui/react';
|
import { Container, VStack } from '@chakra-ui/react';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { loadAllStocks } from '@store/slices/stockSlice';
|
import { loadAllStocks } from '@store/slices/stockSlice';
|
||||||
import { financialService } from '@services/financialService';
|
|
||||||
import { logger } from '@utils/logger';
|
|
||||||
|
|
||||||
// 自定义 Hooks
|
// 自定义 Hooks
|
||||||
import { useCompanyStock } from './hooks/useCompanyStock';
|
import { useCompanyStock } from './hooks/useCompanyStock';
|
||||||
import { useCompanyWatchlist } from './hooks/useCompanyWatchlist';
|
import { useCompanyWatchlist } from './hooks/useCompanyWatchlist';
|
||||||
import { useCompanyEvents } from './hooks/useCompanyEvents';
|
import { useCompanyEvents } from './hooks/useCompanyEvents';
|
||||||
import { useStockQuote } from './hooks/useStockQuote';
|
|
||||||
import { useBasicInfo } from './components/CompanyOverview/hooks/useBasicInfo';
|
|
||||||
|
|
||||||
// 页面组件
|
// 页面组件
|
||||||
import CompanyHeader from './components/CompanyHeader';
|
import CompanyHeader from './components/CompanyHeader';
|
||||||
@@ -31,9 +29,8 @@ import CompanyTabs from './components/CompanyTabs';
|
|||||||
*/
|
*/
|
||||||
const CompanyIndex = () => {
|
const CompanyIndex = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const toast = useToast();
|
|
||||||
|
|
||||||
// 1. 先获取股票代码(不带追踪回调)
|
// 1. 获取股票代码(不带追踪回调)
|
||||||
const {
|
const {
|
||||||
stockCode,
|
stockCode,
|
||||||
inputCode,
|
inputCode,
|
||||||
@@ -47,64 +44,7 @@ const CompanyIndex = () => {
|
|||||||
dispatch(loadAllStocks());
|
dispatch(loadAllStocks());
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
// 2. 获取股票行情数据
|
// 2. 初始化事件追踪(传入 stockCode)
|
||||||
const { data: quoteData, isLoading: isQuoteLoading } = useStockQuote(stockCode);
|
|
||||||
|
|
||||||
// 2.1 获取公司基本信息
|
|
||||||
const { basicInfo } = useBasicInfo(stockCode);
|
|
||||||
|
|
||||||
// 5. 股票对比状态管理
|
|
||||||
const [currentStockInfo, setCurrentStockInfo] = useState(null);
|
|
||||||
const [compareStockInfo, setCompareStockInfo] = useState(null);
|
|
||||||
const [isCompareLoading, setIsCompareLoading] = useState(false);
|
|
||||||
|
|
||||||
// 加载当前股票财务信息(用于对比)
|
|
||||||
useEffect(() => {
|
|
||||||
const loadCurrentStockInfo = async () => {
|
|
||||||
if (!stockCode) return;
|
|
||||||
try {
|
|
||||||
const res = await financialService.getStockInfo(stockCode);
|
|
||||||
setCurrentStockInfo(res.data);
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('CompanyIndex', 'loadCurrentStockInfo', error, { stockCode });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
loadCurrentStockInfo();
|
|
||||||
// 清除对比数据
|
|
||||||
setCompareStockInfo(null);
|
|
||||||
}, [stockCode]);
|
|
||||||
|
|
||||||
// 处理股票对比
|
|
||||||
const handleCompare = useCallback(async (compareCode) => {
|
|
||||||
if (!compareCode) return;
|
|
||||||
|
|
||||||
logger.debug('CompanyIndex', '开始加载对比数据', { stockCode, compareCode });
|
|
||||||
setIsCompareLoading(true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await financialService.getStockInfo(compareCode);
|
|
||||||
setCompareStockInfo(res.data);
|
|
||||||
logger.info('CompanyIndex', '对比数据加载成功', { stockCode, compareCode });
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('CompanyIndex', 'handleCompare', error, { stockCode, compareCode });
|
|
||||||
toast({
|
|
||||||
title: '加载对比数据失败',
|
|
||||||
description: '请检查股票代码是否正确',
|
|
||||||
status: 'error',
|
|
||||||
duration: 3000,
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
setIsCompareLoading(false);
|
|
||||||
}
|
|
||||||
}, [stockCode, toast]);
|
|
||||||
|
|
||||||
// 关闭对比弹窗
|
|
||||||
const handleCloseCompare = useCallback(() => {
|
|
||||||
// 可选:清除对比数据
|
|
||||||
// setCompareStockInfo(null);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// 3. 再初始化事件追踪(传入 stockCode)
|
|
||||||
const {
|
const {
|
||||||
trackStockSearched,
|
trackStockSearched,
|
||||||
trackTabChanged,
|
trackTabChanged,
|
||||||
@@ -147,19 +87,12 @@ const CompanyIndex = () => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 股票行情卡片:价格、关键指标、主力动态、公司信息、股票对比 */}
|
{/* 股票行情卡片:价格、关键指标、主力动态、公司信息、股票对比 */}
|
||||||
|
{/* 优化:数据获取已下沉到组件内部,Props 从 11 个精简为 4 个 */}
|
||||||
<StockQuoteCard
|
<StockQuoteCard
|
||||||
data={quoteData}
|
stockCode={stockCode}
|
||||||
isLoading={isQuoteLoading}
|
|
||||||
isInWatchlist={isInWatchlist}
|
isInWatchlist={isInWatchlist}
|
||||||
isWatchlistLoading={isWatchlistLoading}
|
isWatchlistLoading={isWatchlistLoading}
|
||||||
onWatchlistToggle={handleWatchlistToggle}
|
onWatchlistToggle={handleWatchlistToggle}
|
||||||
basicInfo={basicInfo}
|
|
||||||
// 股票对比相关
|
|
||||||
currentStockInfo={currentStockInfo}
|
|
||||||
compareStockInfo={compareStockInfo}
|
|
||||||
isCompareLoading={isCompareLoading}
|
|
||||||
onCompare={handleCompare}
|
|
||||||
onCloseCompare={handleCloseCompare}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Tab 切换区域:概览、行情、财务、预测 */}
|
{/* Tab 切换区域:概览、行情、财务、预测 */}
|
||||||
|
|||||||
Reference in New Issue
Block a user