refactor(Company): 统一所有 Tab 的 loading 状态组件
- 创建共享的 LoadingState 组件(黑金主题) - DeepAnalysisTab: 使用统一 LoadingState 替换蓝色 Spinner - FinancialPanorama: 使用 LoadingState 替换 Skeleton - MarketDataView: 使用 LoadingState 替换自定义 Spinner - ForecastReport: 使用 LoadingState 替换 Skeleton 骨架屏 所有一级 Tab 现在使用一致的金色 Spinner + 加载提示文案 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -11,9 +11,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { Card, CardBody, Center, VStack, Spinner, Text } from '@chakra-ui/react';
|
import { Card, CardBody } from '@chakra-ui/react';
|
||||||
import { FaBrain, FaBuilding, FaLink, FaHistory } from 'react-icons/fa';
|
import { FaBrain, FaBuilding, FaLink, FaHistory } from 'react-icons/fa';
|
||||||
import SubTabContainer, { type SubTabConfig } from '@components/SubTabContainer';
|
import SubTabContainer, { type SubTabConfig } from '@components/SubTabContainer';
|
||||||
|
import LoadingState from '../../LoadingState';
|
||||||
import { StrategyTab, BusinessTab, ValueChainTab, DevelopmentTab } from './tabs';
|
import { StrategyTab, BusinessTab, ValueChainTab, DevelopmentTab } from './tabs';
|
||||||
import type { DeepAnalysisTabProps, DeepAnalysisTabKey } from './types';
|
import type { DeepAnalysisTabProps, DeepAnalysisTabKey } from './types';
|
||||||
|
|
||||||
@@ -75,12 +76,7 @@ const DeepAnalysisTab: React.FC<DeepAnalysisTabProps> = ({
|
|||||||
componentProps={{}}
|
componentProps={{}}
|
||||||
themePreset="blackGold"
|
themePreset="blackGold"
|
||||||
/>
|
/>
|
||||||
<Center h="200px">
|
<LoadingState message="加载数据中..." height="200px" />
|
||||||
<VStack spacing={4}>
|
|
||||||
<Spinner size="xl" color="blue.500" />
|
|
||||||
<Text color="gray.400">加载数据中...</Text>
|
|
||||||
</VStack>
|
|
||||||
</Center>
|
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
Alert,
|
Alert,
|
||||||
AlertIcon,
|
AlertIcon,
|
||||||
Skeleton,
|
|
||||||
Modal,
|
Modal,
|
||||||
ModalOverlay,
|
ModalOverlay,
|
||||||
ModalContent,
|
ModalContent,
|
||||||
@@ -47,6 +46,7 @@ import { formatUtils } from '@services/financialService';
|
|||||||
|
|
||||||
// 通用组件
|
// 通用组件
|
||||||
import SubTabContainer, { type SubTabConfig } from '@components/SubTabContainer';
|
import SubTabContainer, { type SubTabConfig } from '@components/SubTabContainer';
|
||||||
|
import LoadingState from '../LoadingState';
|
||||||
|
|
||||||
// 内部模块导入
|
// 内部模块导入
|
||||||
import { useFinancialData, type DataTypeKey } from './hooks';
|
import { useFinancialData, type DataTypeKey } from './hooks';
|
||||||
@@ -278,7 +278,7 @@ const FinancialPanorama: React.FC<FinancialPanoramaProps> = ({ stockCode: propSt
|
|||||||
<VStack spacing={6} align="stretch">
|
<VStack spacing={6} align="stretch">
|
||||||
{/* 财务全景面板(三列布局:成长能力、盈利与回报、风险与运营) */}
|
{/* 财务全景面板(三列布局:成长能力、盈利与回报、风险与运营) */}
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<Skeleton height="100px" />
|
<LoadingState message="加载财务数据中..." height="300px" />
|
||||||
) : (
|
) : (
|
||||||
<FinancialOverviewPanel
|
<FinancialOverviewPanel
|
||||||
stockInfo={stockInfo}
|
stockInfo={stockInfo}
|
||||||
|
|||||||
@@ -3,15 +3,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useState, useEffect, useCallback } from 'react';
|
import React, { useState, useEffect, useCallback } from 'react';
|
||||||
import { Box, SimpleGrid, Skeleton } from '@chakra-ui/react';
|
import { Box, SimpleGrid } from '@chakra-ui/react';
|
||||||
import { stockService } from '@services/eventService';
|
import { stockService } from '@services/eventService';
|
||||||
import {
|
import {
|
||||||
IncomeProfitGrowthChart,
|
IncomeProfitGrowthChart,
|
||||||
EpsChart,
|
EpsChart,
|
||||||
PePegChart,
|
PePegChart,
|
||||||
DetailTable,
|
DetailTable,
|
||||||
ChartCard,
|
|
||||||
} from './components';
|
} from './components';
|
||||||
|
import LoadingState from '../LoadingState';
|
||||||
import { CHART_HEIGHT } from './constants';
|
import { CHART_HEIGHT } from './constants';
|
||||||
import type { ForecastReportProps, ForecastData } from './types';
|
import type { ForecastReportProps, ForecastData } from './types';
|
||||||
|
|
||||||
@@ -49,15 +49,9 @@ const ForecastReport: React.FC<ForecastReportProps> = ({ stockCode: propStockCod
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
{/* 加载骨架屏 */}
|
{/* 加载状态 */}
|
||||||
{loading && !data && (
|
{loading && !data && (
|
||||||
<SimpleGrid columns={{ base: 1, md: 3 }} spacing={4}>
|
<LoadingState message="加载盈利预测数据中..." height="300px" />
|
||||||
{[1, 2, 3].map((i) => (
|
|
||||||
<ChartCard key={i} title="加载中...">
|
|
||||||
<Skeleton height={`${CHART_HEIGHT}px`} />
|
|
||||||
</ChartCard>
|
|
||||||
))}
|
|
||||||
</SimpleGrid>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 图表区域 - 3列布局 */}
|
{/* 图表区域 - 3列布局 */}
|
||||||
|
|||||||
44
src/views/Company/components/LoadingState.tsx
Normal file
44
src/views/Company/components/LoadingState.tsx
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// src/views/Company/components/LoadingState.tsx
|
||||||
|
// 统一的加载状态组件 - 黑金主题
|
||||||
|
|
||||||
|
import React from "react";
|
||||||
|
import { Center, VStack, Spinner, Text } from "@chakra-ui/react";
|
||||||
|
|
||||||
|
// 黑金主题配置
|
||||||
|
const THEME = {
|
||||||
|
gold: "#D4AF37",
|
||||||
|
textSecondary: "gray.400",
|
||||||
|
};
|
||||||
|
|
||||||
|
interface LoadingStateProps {
|
||||||
|
message?: string;
|
||||||
|
height?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一的加载状态组件(黑金主题)
|
||||||
|
*
|
||||||
|
* 用于所有一级 Tab 的 loading 状态展示
|
||||||
|
*/
|
||||||
|
const LoadingState: React.FC<LoadingStateProps> = ({
|
||||||
|
message = "加载中...",
|
||||||
|
height = "300px",
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Center h={height}>
|
||||||
|
<VStack spacing={4}>
|
||||||
|
<Spinner
|
||||||
|
size="xl"
|
||||||
|
color={THEME.gold}
|
||||||
|
thickness="4px"
|
||||||
|
speed="0.65s"
|
||||||
|
/>
|
||||||
|
<Text fontSize="sm" color={THEME.textSecondary}>
|
||||||
|
{message}
|
||||||
|
</Text>
|
||||||
|
</VStack>
|
||||||
|
</Center>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LoadingState;
|
||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
Box,
|
Box,
|
||||||
Container,
|
Container,
|
||||||
CardBody,
|
CardBody,
|
||||||
Spinner,
|
|
||||||
Center,
|
Center,
|
||||||
VStack,
|
VStack,
|
||||||
Text,
|
Text,
|
||||||
@@ -39,6 +38,7 @@ import {
|
|||||||
UnusualPanel,
|
UnusualPanel,
|
||||||
PledgePanel,
|
PledgePanel,
|
||||||
} from './components/panels';
|
} from './components/panels';
|
||||||
|
import LoadingState from '../LoadingState';
|
||||||
import type { MarketDataViewProps, RiseAnalysis } from './types';
|
import type { MarketDataViewProps, RiseAnalysis } from './types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -163,18 +163,7 @@ const MarketDataView: React.FC<MarketDataViewProps> = ({ stockCode: propStockCod
|
|||||||
{loading ? (
|
{loading ? (
|
||||||
<ThemedCard theme={theme}>
|
<ThemedCard theme={theme}>
|
||||||
<CardBody>
|
<CardBody>
|
||||||
<Center h="400px">
|
<LoadingState message="数据加载中..." height="400px" />
|
||||||
<VStack spacing={4}>
|
|
||||||
<Spinner
|
|
||||||
thickness="4px"
|
|
||||||
speed="0.65s"
|
|
||||||
emptyColor={theme.bgDark}
|
|
||||||
color={theme.primary}
|
|
||||||
size="xl"
|
|
||||||
/>
|
|
||||||
<Text color={theme.textSecondary}>数据加载中...</Text>
|
|
||||||
</VStack>
|
|
||||||
</Center>
|
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</ThemedCard>
|
</ThemedCard>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
Reference in New Issue
Block a user