feat(FinancialPanorama): 新增 FinancialOverviewPanel 三模块布局
- 复用 MetricCard 组件构建三列布局 - 成长能力:利润增长、营收增长、预增标签 - 盈利与回报:ROE、净利率、毛利率 - 风险与运营:资产负债率、流动比率、研发费用率 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,188 @@
|
|||||||
|
/**
|
||||||
|
* 财务全景面板组件 - 三列布局
|
||||||
|
* 复用 MarketDataView 的 MetricCard 组件
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { memo } from 'react';
|
||||||
|
import { SimpleGrid, HStack, VStack, Text, Badge } from '@chakra-ui/react';
|
||||||
|
import { TrendingUp, Coins, Shield, TrendingDown, Activity, PieChart } from 'lucide-react';
|
||||||
|
import { formatUtils } from '@services/financialService';
|
||||||
|
|
||||||
|
// 复用 MarketDataView 的组件
|
||||||
|
import MetricCard from '../../MarketDataView/components/StockSummaryCard/MetricCard';
|
||||||
|
import { StatusTag } from '../../MarketDataView/components/StockSummaryCard/atoms';
|
||||||
|
import { darkGoldTheme } from '../../MarketDataView/constants';
|
||||||
|
|
||||||
|
import type { StockInfo, FinancialMetricsData } from '../types';
|
||||||
|
|
||||||
|
export interface FinancialOverviewPanelProps {
|
||||||
|
stockInfo: StockInfo | null;
|
||||||
|
financialMetrics: FinancialMetricsData[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取成长状态
|
||||||
|
*/
|
||||||
|
const getGrowthStatus = (value: number | undefined): { text: string; color: string } => {
|
||||||
|
if (value === undefined || value === null) return { text: '-', color: darkGoldTheme.textMuted };
|
||||||
|
if (value > 30) return { text: '高速增长', color: darkGoldTheme.green };
|
||||||
|
if (value > 10) return { text: '稳健增长', color: darkGoldTheme.gold };
|
||||||
|
if (value > 0) return { text: '低速增长', color: darkGoldTheme.orange };
|
||||||
|
if (value > -10) return { text: '小幅下滑', color: darkGoldTheme.orange };
|
||||||
|
return { text: '大幅下滑', color: darkGoldTheme.red };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 ROE 状态
|
||||||
|
*/
|
||||||
|
const getROEStatus = (value: number | undefined): { text: string; color: string } => {
|
||||||
|
if (value === undefined || value === null) return { text: '-', color: darkGoldTheme.textMuted };
|
||||||
|
if (value > 20) return { text: '优秀', color: darkGoldTheme.green };
|
||||||
|
if (value > 15) return { text: '良好', color: darkGoldTheme.gold };
|
||||||
|
if (value > 10) return { text: '一般', color: darkGoldTheme.orange };
|
||||||
|
return { text: '较低', color: darkGoldTheme.red };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取资产负债率状态
|
||||||
|
*/
|
||||||
|
const getDebtStatus = (value: number | undefined): { text: string; color: string } => {
|
||||||
|
if (value === undefined || value === null) return { text: '-', color: darkGoldTheme.textMuted };
|
||||||
|
if (value < 40) return { text: '安全', color: darkGoldTheme.green };
|
||||||
|
if (value < 60) return { text: '适中', color: darkGoldTheme.gold };
|
||||||
|
if (value < 70) return { text: '偏高', color: darkGoldTheme.orange };
|
||||||
|
return { text: '风险', color: darkGoldTheme.red };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 财务全景面板组件
|
||||||
|
*/
|
||||||
|
export const FinancialOverviewPanel: React.FC<FinancialOverviewPanelProps> = memo(({
|
||||||
|
stockInfo,
|
||||||
|
financialMetrics,
|
||||||
|
}) => {
|
||||||
|
if (!stockInfo && (!financialMetrics || financialMetrics.length === 0)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取最新一期财务指标
|
||||||
|
const latestMetrics = financialMetrics?.[0];
|
||||||
|
|
||||||
|
// 成长指标(来自 stockInfo)
|
||||||
|
const revenueGrowth = stockInfo?.growth_rates?.revenue_growth;
|
||||||
|
const profitGrowth = stockInfo?.growth_rates?.profit_growth;
|
||||||
|
const forecast = stockInfo?.latest_forecast;
|
||||||
|
|
||||||
|
// 盈利指标(来自 financialMetrics)
|
||||||
|
const roe = latestMetrics?.profitability?.roe;
|
||||||
|
const netProfitMargin = latestMetrics?.profitability?.net_profit_margin;
|
||||||
|
const grossMargin = latestMetrics?.profitability?.gross_margin;
|
||||||
|
|
||||||
|
// 风险与运营指标(来自 financialMetrics)
|
||||||
|
const assetLiabilityRatio = latestMetrics?.solvency?.asset_liability_ratio;
|
||||||
|
const currentRatio = latestMetrics?.solvency?.current_ratio;
|
||||||
|
const rdExpenseRatio = latestMetrics?.expense_ratios?.rd_expense_ratio;
|
||||||
|
|
||||||
|
// 计算状态
|
||||||
|
const growthStatus = getGrowthStatus(profitGrowth);
|
||||||
|
const roeStatus = getROEStatus(roe);
|
||||||
|
const debtStatus = getDebtStatus(assetLiabilityRatio);
|
||||||
|
|
||||||
|
// 格式化涨跌显示
|
||||||
|
const formatGrowth = (value: number | undefined) => {
|
||||||
|
if (value === undefined || value === null) return '-';
|
||||||
|
const sign = value >= 0 ? '+' : '';
|
||||||
|
return `${sign}${value.toFixed(2)}%`;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SimpleGrid columns={{ base: 1, md: 3 }} spacing={3}>
|
||||||
|
{/* 卡片1: 成长能力 */}
|
||||||
|
<MetricCard
|
||||||
|
title="成长能力"
|
||||||
|
subtitle="增长动力"
|
||||||
|
leftIcon={<TrendingUp size={14} />}
|
||||||
|
rightIcon={<Activity size={14} />}
|
||||||
|
mainLabel="利润增长"
|
||||||
|
mainValue={formatGrowth(profitGrowth)}
|
||||||
|
mainColor={profitGrowth !== undefined && profitGrowth >= 0 ? darkGoldTheme.green : darkGoldTheme.red}
|
||||||
|
subText={
|
||||||
|
<VStack align="start" spacing={1}>
|
||||||
|
<HStack spacing={1} flexWrap="wrap">
|
||||||
|
<Text>营收增长</Text>
|
||||||
|
<Text
|
||||||
|
fontWeight="bold"
|
||||||
|
color={revenueGrowth !== undefined && revenueGrowth >= 0 ? darkGoldTheme.green : darkGoldTheme.red}
|
||||||
|
>
|
||||||
|
{formatGrowth(revenueGrowth)}
|
||||||
|
</Text>
|
||||||
|
<StatusTag text={growthStatus.text} color={growthStatus.color} />
|
||||||
|
</HStack>
|
||||||
|
{forecast && (
|
||||||
|
<Badge
|
||||||
|
bg="rgba(212, 175, 55, 0.15)"
|
||||||
|
color={darkGoldTheme.gold}
|
||||||
|
fontSize="xs"
|
||||||
|
px={2}
|
||||||
|
py={0.5}
|
||||||
|
borderRadius="md"
|
||||||
|
>
|
||||||
|
{forecast.forecast_type} {forecast.content}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</VStack>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* 卡片2: 盈利与回报 */}
|
||||||
|
<MetricCard
|
||||||
|
title="盈利与回报"
|
||||||
|
subtitle="赚钱能力"
|
||||||
|
leftIcon={<Coins size={14} />}
|
||||||
|
rightIcon={<PieChart size={14} />}
|
||||||
|
mainLabel="ROE"
|
||||||
|
mainValue={formatUtils.formatPercent(roe)}
|
||||||
|
mainColor={darkGoldTheme.orange}
|
||||||
|
subText={
|
||||||
|
<VStack align="start" spacing={0.5}>
|
||||||
|
<Text color={roeStatus.color} fontWeight="medium">
|
||||||
|
{roeStatus.text}
|
||||||
|
</Text>
|
||||||
|
<HStack spacing={1} flexWrap="wrap">
|
||||||
|
<Text>净利率 {formatUtils.formatPercent(netProfitMargin)}</Text>
|
||||||
|
<Text>|</Text>
|
||||||
|
<Text>毛利率 {formatUtils.formatPercent(grossMargin)}</Text>
|
||||||
|
</HStack>
|
||||||
|
</VStack>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* 卡片3: 风险与运营 */}
|
||||||
|
<MetricCard
|
||||||
|
title="风险与运营"
|
||||||
|
subtitle="安全边际"
|
||||||
|
leftIcon={<Shield size={14} />}
|
||||||
|
rightIcon={<TrendingDown size={14} />}
|
||||||
|
mainLabel="资产负债率"
|
||||||
|
mainValue={formatUtils.formatPercent(assetLiabilityRatio)}
|
||||||
|
mainColor={debtStatus.color}
|
||||||
|
subText={
|
||||||
|
<VStack align="start" spacing={0.5}>
|
||||||
|
<Text color={debtStatus.color} fontWeight="medium">
|
||||||
|
{debtStatus.text}
|
||||||
|
</Text>
|
||||||
|
<HStack spacing={1} flexWrap="wrap">
|
||||||
|
<Text>流动比率 {currentRatio?.toFixed(2) ?? '-'}</Text>
|
||||||
|
<Text>|</Text>
|
||||||
|
<Text>研发费用率 {formatUtils.formatPercent(rdExpenseRatio)}</Text>
|
||||||
|
</HStack>
|
||||||
|
</VStack>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</SimpleGrid>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
FinancialOverviewPanel.displayName = 'FinancialOverviewPanel';
|
||||||
|
|
||||||
|
export default FinancialOverviewPanel;
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export { PeriodSelector } from './PeriodSelector';
|
export { PeriodSelector } from './PeriodSelector';
|
||||||
|
export { FinancialOverviewPanel } from './FinancialOverviewPanel';
|
||||||
|
// 保留旧组件导出(向后兼容)
|
||||||
export { KeyMetricsOverview } from './KeyMetricsOverview';
|
export { KeyMetricsOverview } from './KeyMetricsOverview';
|
||||||
export { StockInfoHeader } from './StockInfoHeader';
|
export { StockInfoHeader } from './StockInfoHeader';
|
||||||
export { BalanceSheetTable } from './BalanceSheetTable';
|
export { BalanceSheetTable } from './BalanceSheetTable';
|
||||||
|
|||||||
Reference in New Issue
Block a user