perf: 优化各 Tab 数据加载为按需请求

MarketDataView (股票行情):
- 初始只加载 summary + tradeData(2个接口)
- funding/bigDeal/unusual/pledge 数据在切换 Tab 时按需加载
- 新增 loadDataByType 方法支持懒加载

FinancialPanorama (财务全景):
- 初始只加载 stockInfo + metrics + comparison + mainBusiness(4个接口)
- 从9个接口优化到4个接口

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zdl
2025-12-18 18:32:14 +08:00
parent 3953efc2ed
commit 5331bc64b4
21 changed files with 368 additions and 123 deletions

View File

@@ -0,0 +1,40 @@
/**
* ECharts 包装组件
*
* 基于 echarts-for-react使用按需引入的 echarts 实例
* 减少打包体积约 500KB
*
* @example
* ```tsx
* import ECharts from '@components/Charts/ECharts';
*
* <ECharts option={chartOption} style={{ height: 300 }} />
* ```
*/
import React, { forwardRef } from 'react';
import ReactEChartsCore from 'echarts-for-react/lib/core';
import { echarts } from '@lib/echarts';
// Re-export ReactEChartsCore props type
import type { EChartsReactProps } from 'echarts-for-react';
export type EChartsProps = Omit<EChartsReactProps, 'echarts'>;
/**
* ECharts 图表组件
* 自动使用按需引入的 echarts 实例
*/
const ECharts = forwardRef<ReactEChartsCore, EChartsProps>((props, ref) => {
return (
<ReactEChartsCore
ref={ref}
echarts={echarts}
{...props}
/>
);
});
ECharts.displayName = 'ECharts';
export default ECharts;

View File

@@ -1,7 +1,7 @@
// src/components/Charts/Stock/MiniTimelineChart.js
import React, { useState, useEffect, useMemo, useRef, useCallback } from 'react';
import ReactECharts from 'echarts-for-react';
import * as echarts from 'echarts';
import { echarts } from '@lib/echarts';
import dayjs from 'dayjs';
import {
fetchKlineData,

View File

@@ -3,7 +3,7 @@
import React, { useEffect, useRef } from 'react';
import { Box, useColorModeValue } from '@chakra-ui/react';
import * as echarts from 'echarts';
import { echarts } from '@lib/echarts';
/**
* ECharts 图表渲染组件

View File

@@ -2,7 +2,8 @@
import React, { useEffect, useRef, useState, useCallback } from 'react';
import { createPortal } from 'react-dom';
import { useSelector } from 'react-redux';
import * as echarts from 'echarts';
import { echarts } from '@lib/echarts';
import type { ECharts } from '@lib/echarts';
import dayjs from 'dayjs';
import { stockService } from '@services/eventService';
import { selectIsMobile } from '@store/slices/deviceSlice';

View File

@@ -2,7 +2,7 @@
import React, { useState, useEffect, useRef } from 'react';
import { Modal, Button, Spin, Typography } from 'antd';
import ReactECharts from 'echarts-for-react';
import * as echarts from 'echarts';
import { echarts } from '@lib/echarts';
import dayjs from 'dayjs';
import { stockService } from '../../services/eventService';
import CitedContent from '../Citation/CitedContent';

View File

@@ -17,7 +17,7 @@ import {
Alert,
AlertIcon,
} from '@chakra-ui/react';
import * as echarts from 'echarts';
import { echarts, type ECharts, type EChartsOption } from '@lib/echarts';
import dayjs from 'dayjs';
import { klineDataCache, getCacheKey, fetchKlineData } from '@utils/stock/klineDataCache';
import { selectIsMobile } from '@store/slices/deviceSlice';

View File

@@ -31,6 +31,8 @@ import {
HStack,
Text,
Spacer,
Center,
Spinner,
} from '@chakra-ui/react';
import type { ComponentType } from 'react';
import type { IconType } from 'react-icons';
@@ -311,7 +313,18 @@ const SubTabContainer: React.FC<SubTabContainerProps> = memo(({
return (
<TabPanel key={tab.key} p={0}>
{shouldRender && Component ? (
<Suspense fallback={null}>
<Suspense
fallback={
<Center py={20}>
<Spinner
size="lg"
color={DEEP_SPACE.textGold}
thickness="3px"
speed="0.8s"
/>
</Center>
}
>
<Component {...componentProps} />
</Suspense>
) : null}