diff --git a/src/views/Company/components/ForecastReport/components/IncomeProfitGrowthChart.tsx b/src/views/Company/components/ForecastReport/components/IncomeProfitGrowthChart.tsx new file mode 100644 index 00000000..492a724a --- /dev/null +++ b/src/views/Company/components/ForecastReport/components/IncomeProfitGrowthChart.tsx @@ -0,0 +1,144 @@ +/** + * 营业收入、净利润趋势与增长率分析 - 合并图表 + */ + +import React, { useMemo } from 'react'; +import ReactECharts from 'echarts-for-react'; +import ChartCard from './ChartCard'; +import { CHART_COLORS, BASE_CHART_CONFIG, THEME } from '../constants'; +import type { IncomeProfitTrend, GrowthBars } from '../types'; + +interface IncomeProfitGrowthChartProps { + incomeProfitData: IncomeProfitTrend; + growthData: GrowthBars; +} + +const IncomeProfitGrowthChart: React.FC = ({ + incomeProfitData, + growthData, +}) => { + const option = useMemo(() => ({ + ...BASE_CHART_CONFIG, + tooltip: { + ...BASE_CHART_CONFIG.tooltip, + trigger: 'axis', + axisPointer: { + type: 'cross', + crossStyle: { + color: 'rgba(212, 175, 55, 0.5)', + }, + }, + }, + legend: { + ...BASE_CHART_CONFIG.legend, + data: ['营业总收入', '归母净利润', '营收增长率'], + bottom: 0, + }, + grid: { + left: 60, + right: 60, + bottom: 50, + top: 40, + containLabel: false, + }, + xAxis: { + ...BASE_CHART_CONFIG.xAxis, + type: 'category', + data: incomeProfitData.years, + }, + yAxis: [ + { + ...BASE_CHART_CONFIG.yAxis, + type: 'value', + name: '金额(百万元)', + position: 'left', + nameTextStyle: { color: THEME.textSecondary }, + axisLabel: { + color: THEME.textSecondary, + formatter: (value: number) => { + if (Math.abs(value) >= 1000) { + return (value / 1000).toFixed(0) + 'k'; + } + return value.toFixed(0); + }, + }, + }, + { + ...BASE_CHART_CONFIG.yAxis, + type: 'value', + name: '增长率(%)', + position: 'right', + nameTextStyle: { color: THEME.textSecondary }, + axisLabel: { + color: THEME.textSecondary, + formatter: '{value}%', + }, + splitLine: { + show: false, + }, + }, + ], + series: [ + { + name: '营业总收入', + type: 'bar', + data: incomeProfitData.income, + itemStyle: { + color: CHART_COLORS.income, + }, + barMaxWidth: 30, + }, + { + name: '归母净利润', + type: 'line', + data: incomeProfitData.profit, + smooth: true, + lineStyle: { width: 2, color: CHART_COLORS.profit }, + itemStyle: { color: CHART_COLORS.profit }, + areaStyle: { + color: { + type: 'linear', + x: 0, + y: 0, + x2: 0, + y2: 1, + colorStops: [ + { offset: 0, color: 'rgba(246, 173, 85, 0.3)' }, + { offset: 1, color: 'rgba(246, 173, 85, 0.05)' }, + ], + }, + }, + }, + { + name: '营收增长率', + type: 'line', + yAxisIndex: 1, + data: growthData.revenue_growth_pct, + smooth: true, + lineStyle: { width: 2, type: 'dashed', color: '#10B981' }, + itemStyle: { + color: (params: { value: number }) => + params.value >= 0 ? THEME.positive : THEME.negative, + }, + label: { + show: true, + position: 'top', + color: THEME.textSecondary, + fontSize: 10, + formatter: (params: { value: number }) => + params.value !== null && params.value !== undefined + ? `${params.value.toFixed(1)}%` + : '', + }, + }, + ], + }), [incomeProfitData, growthData]); + + return ( + + + + ); +}; + +export default IncomeProfitGrowthChart; diff --git a/src/views/Company/components/ForecastReport/components/index.ts b/src/views/Company/components/ForecastReport/components/index.ts index 8a4e8261..e31ad54b 100644 --- a/src/views/Company/components/ForecastReport/components/index.ts +++ b/src/views/Company/components/ForecastReport/components/index.ts @@ -5,6 +5,7 @@ export { default as ChartCard } from './ChartCard'; export { default as IncomeProfitChart } from './IncomeProfitChart'; export { default as GrowthChart } from './GrowthChart'; +export { default as IncomeProfitGrowthChart } from './IncomeProfitGrowthChart'; export { default as EpsChart } from './EpsChart'; export { default as PePegChart } from './PePegChart'; export { default as DetailTable } from './DetailTable'; diff --git a/src/views/Company/components/ForecastReport/index.tsx b/src/views/Company/components/ForecastReport/index.tsx index e15eef63..25c89ef7 100644 --- a/src/views/Company/components/ForecastReport/index.tsx +++ b/src/views/Company/components/ForecastReport/index.tsx @@ -7,8 +7,7 @@ import { Box, SimpleGrid, HStack, Heading, Skeleton, IconButton } from '@chakra- import { RefreshCw } from 'lucide-react'; import { stockService } from '@services/eventService'; import { - IncomeProfitChart, - GrowthChart, + IncomeProfitGrowthChart, EpsChart, PePegChart, DetailTable, @@ -94,12 +93,20 @@ const ForecastReport: React.FC = ({ stockCode: propStockCod {/* 图表区域 */} {data && ( - - - - - - + <> + {/* 合并图表:营收/利润/增长率 */} + + + + {/* EPS 和 PE/PEG */} + + + + + )} {/* 详细数据表格 */}