feat(ForecastReport): 添加盈利预测骨架屏

- 创建 ForecastSkeleton 组件(图表卡片 + 表格)
- 初始加载时显示骨架屏

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zdl
2025-12-19 15:18:00 +08:00
parent 57f4645f4d
commit 2851644b9c
5 changed files with 90 additions and 272 deletions

View File

@@ -0,0 +1,79 @@
/**
* 盈利预测骨架屏组件
*/
import React, { memo } from 'react';
import {
Box,
SimpleGrid,
Skeleton,
SkeletonText,
Card,
CardBody,
VStack,
} from '@chakra-ui/react';
// 黑金主题配色
const SKELETON_COLORS = {
startColor: 'rgba(26, 32, 44, 0.6)',
endColor: 'rgba(212, 175, 55, 0.2)',
};
/**
* 图表卡片骨架屏
*/
const ChartCardSkeleton: React.FC = memo(() => (
<Card bg="gray.900" border="1px solid" borderColor="rgba(212, 175, 55, 0.3)">
<CardBody>
<Skeleton height="20px" width="100px" mb={4} {...SKELETON_COLORS} />
<Skeleton height="200px" borderRadius="md" {...SKELETON_COLORS} />
</CardBody>
</Card>
));
ChartCardSkeleton.displayName = 'ChartCardSkeleton';
/**
* 表格骨架屏
*/
const TableSkeleton: React.FC = memo(() => (
<Card bg="gray.900" border="1px solid" borderColor="rgba(212, 175, 55, 0.3)">
<CardBody>
<Skeleton height="20px" width="120px" mb={4} {...SKELETON_COLORS} />
<VStack align="stretch" spacing={3}>
{/* 表头 */}
<Skeleton height="40px" {...SKELETON_COLORS} />
{/* 表格行 */}
{[1, 2, 3, 4, 5].map((i) => (
<Skeleton key={i} height="36px" {...SKELETON_COLORS} />
))}
</VStack>
</CardBody>
</Card>
));
TableSkeleton.displayName = 'TableSkeleton';
/**
* 盈利预测完整骨架屏
*/
const ForecastSkeleton: React.FC = memo(() => (
<Box>
{/* 图表区域 - 3列布局 */}
<SimpleGrid columns={{ base: 1, md: 3 }} spacing={4}>
<ChartCardSkeleton />
<ChartCardSkeleton />
<ChartCardSkeleton />
</SimpleGrid>
{/* 详细数据表格 */}
<Box mt={4}>
<TableSkeleton />
</Box>
</Box>
));
ForecastSkeleton.displayName = 'ForecastSkeleton';
export { ForecastSkeleton };
export default ForecastSkeleton;

View File

@@ -9,3 +9,4 @@ export { default as IncomeProfitGrowthChart } from './IncomeProfitGrowthChart';
export { default as EpsChart } from './EpsChart';
export { default as PePegChart } from './PePegChart';
export { default as DetailTable } from './DetailTable';
export { ForecastSkeleton } from './ForecastSkeleton';

View File

@@ -11,16 +11,16 @@ import {
EpsChart,
PePegChart,
DetailTable,
ForecastSkeleton,
} from './components';
import LoadingState from '../LoadingState';
import type { ForecastReportProps } from './types';
const ForecastReport: React.FC<ForecastReportProps> = ({ stockCode }) => {
const { data, isLoading, error, refetch } = useForecastData(stockCode);
// 加载状态
// 加载状态 - 显示骨架屏
if (isLoading && !data) {
return <LoadingState message="加载盈利预测数据中..." height="300px" />;
return <ForecastSkeleton />;
}
// 错误状态