From d394c25d7ea3bb46b960e97ed1a9dc293b8ee083 Mon Sep 17 00:00:00 2001 From: zdl <3489966805@qq.com> Date: Fri, 19 Dec 2025 15:47:59 +0800 Subject: [PATCH] =?UTF-8?q?feat(MarketDataView):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=82=A1=E7=A5=A8=E8=A1=8C=E6=83=85=E9=AA=A8=E6=9E=B6=E5=B1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 创建 MarketDataSkeleton 组件(摘要卡片 + K线图表 + Tab) - 配置 Suspense fallback,点击时直接显示骨架屏 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/mocks/data/financial.js | 32 ++-- .../components/UnifiedFinancialTable.tsx | 5 +- .../hooks/useFinancialData.ts | 8 + .../FinancialPanorama/utils/tableTheme.ts | 15 +- .../components/MarketDataSkeleton.tsx | 140 ++++++++++++++++++ .../MarketDataView/components/index.ts | 1 + src/views/Company/config.ts | 2 + 7 files changed, 190 insertions(+), 13 deletions(-) create mode 100644 src/views/Company/components/MarketDataView/components/MarketDataSkeleton.tsx diff --git a/src/mocks/data/financial.js b/src/mocks/data/financial.js index 23188db2..6fdb1019 100644 --- a/src/mocks/data/financial.js +++ b/src/mocks/data/financial.js @@ -3,7 +3,21 @@ // 生成财务数据 export const generateFinancialData = (stockCode) => { - const periods = ['2024-09-30', '2024-06-30', '2024-03-31', '2023-12-31']; + // 12 期数据 - 用于财务指标表格(7个指标Tab) + const metricsPeriods = [ + '2024-09-30', '2024-06-30', '2024-03-31', '2023-12-31', + '2023-09-30', '2023-06-30', '2023-03-31', '2022-12-31', + '2022-09-30', '2022-06-30', '2022-03-31', '2021-12-31', + ]; + + // 8 期数据 - 用于财务报表(3个报表Tab) + const statementPeriods = [ + '2024-09-30', '2024-06-30', '2024-03-31', '2023-12-31', + '2023-09-30', '2023-06-30', '2023-03-31', '2022-12-31', + ]; + + // 兼容旧代码 + const periods = statementPeriods.slice(0, 4); return { stockCode, @@ -44,8 +58,8 @@ export const generateFinancialData = (stockCode) => { } }, - // 资产负债表 - 嵌套结构 - balanceSheet: periods.map((period, i) => ({ + // 资产负债表 - 嵌套结构(8期数据) + balanceSheet: statementPeriods.map((period, i) => ({ period, assets: { current_assets: { @@ -110,8 +124,8 @@ export const generateFinancialData = (stockCode) => { } })), - // 利润表 - 嵌套结构 - incomeStatement: periods.map((period, i) => ({ + // 利润表 - 嵌套结构(8期数据) + incomeStatement: statementPeriods.map((period, i) => ({ period, revenue: { total_operating_revenue: 162350 - i * 4000, @@ -166,8 +180,8 @@ export const generateFinancialData = (stockCode) => { } })), - // 现金流量表 - 嵌套结构 - cashflow: periods.map((period, i) => ({ + // 现金流量表 - 嵌套结构(8期数据) + cashflow: statementPeriods.map((period, i) => ({ period, operating_activities: { inflow: { @@ -193,8 +207,8 @@ export const generateFinancialData = (stockCode) => { } })), - // 财务指标 - 嵌套结构 - financialMetrics: periods.map((period, i) => ({ + // 财务指标 - 嵌套结构(12期数据) + financialMetrics: metricsPeriods.map((period, i) => ({ period, profitability: { roe: 16.23 - i * 0.3, diff --git a/src/views/Company/components/FinancialPanorama/components/UnifiedFinancialTable.tsx b/src/views/Company/components/FinancialPanorama/components/UnifiedFinancialTable.tsx index 6aebd60a..f039900d 100644 --- a/src/views/Company/components/FinancialPanorama/components/UnifiedFinancialTable.tsx +++ b/src/views/Company/components/FinancialPanorama/components/UnifiedFinancialTable.tsx @@ -108,8 +108,9 @@ const UnifiedFinancialTableInner: React.FC = ({ ); } - // 限制显示列数 - const maxColumns = type === 'metrics' ? 6 : 8; + // 固定显示期数: 财务指标 6 期, 财务报表 8 期 + const FIXED_PERIODS = { metrics: 6, statement: 8 }; + const maxColumns = FIXED_PERIODS[type]; const displayData = data.slice(0, Math.min(data.length, maxColumns)); // 构建表格数据 diff --git a/src/views/Company/components/FinancialPanorama/hooks/useFinancialData.ts b/src/views/Company/components/FinancialPanorama/hooks/useFinancialData.ts index 361542c2..25cd2d34 100644 --- a/src/views/Company/components/FinancialPanorama/hooks/useFinancialData.ts +++ b/src/views/Company/components/FinancialPanorama/hooks/useFinancialData.ts @@ -106,6 +106,14 @@ export const useFinancialData = ( const coreDataControllerRef = useRef(null); const tabDataControllerRef = useRef(null); + // 记录每种数据类型加载时使用的期数(用于 Tab 切换时判断是否需要重新加载) + const dataPeriodsRef = useRef>({ + balance: 0, + income: 0, + cashflow: 0, + metrics: 0, + }); + // 判断 Tab key 对应的数据类型 const getDataTypeForTab = (tabKey: DataTypeKey): 'balance' | 'income' | 'cashflow' | 'metrics' => { switch (tabKey) { diff --git a/src/views/Company/components/FinancialPanorama/utils/tableTheme.ts b/src/views/Company/components/FinancialPanorama/utils/tableTheme.ts index e1e8adbd..c12a400f 100644 --- a/src/views/Company/components/FinancialPanorama/utils/tableTheme.ts +++ b/src/views/Company/components/FinancialPanorama/utils/tableTheme.ts @@ -20,8 +20,10 @@ export const BLACK_GOLD_TABLE_THEME: ThemeConfig = { headerColor: '#D4AF37', rowHoverBg: 'rgba(212, 175, 55, 0.1)', borderColor: 'rgba(212, 175, 55, 0.15)', - cellPaddingBlock: 8, - cellPaddingInline: 12, + cellPaddingBlock: 6, + cellPaddingInline: 8, + // 表头紧凑样式 + headerSplitColor: 'transparent', }, }, }; @@ -40,6 +42,15 @@ export const getTableStyles = (className: string): string => ` border-bottom: 1px solid rgba(212, 175, 55, 0.3) !important; font-weight: 600; font-size: 13px; + padding: 4px 8px !important; + margin: 0 !important; + } + .${className} .ant-table-thead > tr { + margin: 0 !important; + } + .${className} .ant-table-header { + margin: 0 !important; + padding: 0 !important; } .${className} .ant-table-tbody > tr > td { border-bottom: 1px solid rgba(212, 175, 55, 0.1) !important; diff --git a/src/views/Company/components/MarketDataView/components/MarketDataSkeleton.tsx b/src/views/Company/components/MarketDataView/components/MarketDataSkeleton.tsx new file mode 100644 index 00000000..67ff83c4 --- /dev/null +++ b/src/views/Company/components/MarketDataView/components/MarketDataSkeleton.tsx @@ -0,0 +1,140 @@ +/** + * 股票行情骨架屏组件 + */ + +import React, { memo } from 'react'; +import { + Box, + Container, + VStack, + HStack, + Skeleton, + SkeletonText, + SimpleGrid, + Card, + CardBody, +} from '@chakra-ui/react'; + +// 黑金主题配色 +const SKELETON_COLORS = { + startColor: 'rgba(26, 32, 44, 0.6)', + endColor: 'rgba(212, 175, 55, 0.2)', +}; + +/** + * 股票摘要卡片骨架屏 + */ +const SummaryCardSkeleton: React.FC = memo(() => ( + + + + {/* 左侧:股票名称和价格 */} + + + + + + + + + + {/* 右侧:指标网格 */} + + {[1, 2, 3, 4, 5, 6, 7, 8].map((i) => ( + + + + + ))} + + + + +)); + +SummaryCardSkeleton.displayName = 'SummaryCardSkeleton'; + +/** + * K线图表骨架屏 + */ +const ChartSkeleton: React.FC = memo(() => ( + + + {/* 工具栏 */} + + + {[1, 2, 3, 4].map((i) => ( + + ))} + + + + + + + + {/* 图表区域 */} + + + +)); + +ChartSkeleton.displayName = 'ChartSkeleton'; + +/** + * Tab 区域骨架屏 + */ +const TabSkeleton: React.FC = memo(() => ( + + + {/* Tab 栏 */} + + {[1, 2, 3, 4].map((i) => ( + + ))} + + {/* Tab 内容 */} + + + + + +)); + +TabSkeleton.displayName = 'TabSkeleton'; + +/** + * 股票行情完整骨架屏 + */ +const MarketDataSkeleton: React.FC = memo(() => ( + + + + + + + + + +)); + +MarketDataSkeleton.displayName = 'MarketDataSkeleton'; + +export { MarketDataSkeleton }; +export default MarketDataSkeleton; diff --git a/src/views/Company/components/MarketDataView/components/index.ts b/src/views/Company/components/MarketDataView/components/index.ts index 0fe7d160..1a854d60 100644 --- a/src/views/Company/components/MarketDataView/components/index.ts +++ b/src/views/Company/components/MarketDataView/components/index.ts @@ -5,3 +5,4 @@ export { default as ThemedCard } from './ThemedCard'; export { default as MarkdownRenderer } from './MarkdownRenderer'; export { default as StockSummaryCard } from './StockSummaryCard'; export { default as AnalysisModal, AnalysisContent } from './AnalysisModal'; +export { MarketDataSkeleton } from './MarketDataSkeleton'; diff --git a/src/views/Company/config.ts b/src/views/Company/config.ts index 3f9c75a2..83fa7a52 100644 --- a/src/views/Company/config.ts +++ b/src/views/Company/config.ts @@ -11,6 +11,7 @@ import type { CompanyTheme, TabConfig } from './types'; // 骨架屏组件(同步导入,用于 Suspense fallback) import { FinancialPanoramaSkeleton } from './components/FinancialPanorama/components'; import { ForecastSkeleton } from './components/ForecastReport/components'; +import { MarketDataSkeleton } from './components/MarketDataView/components'; // ============================================ // 黑金主题配置 @@ -87,6 +88,7 @@ export const TAB_CONFIG: TabConfig[] = [ name: '股票行情', icon: TrendingUp, component: MarketDataView, + fallback: React.createElement(MarketDataSkeleton), }, { key: 'financial',