feat(ForecastReport): 添加盈利预测骨架屏
- 创建 ForecastSkeleton 组件(图表卡片 + 表格) - 初始加载时显示骨架屏 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -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;
|
||||
@@ -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';
|
||||
|
||||
@@ -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 />;
|
||||
}
|
||||
|
||||
// 错误状态
|
||||
|
||||
Reference in New Issue
Block a user