refactor(DeepAnalysisTab): 模块化拆分为 21 个 TypeScript 文件
将 1,796 行单文件拆分为原子设计模式结构: **atoms/** - 原子组件 - DisclaimerBox: 免责声明警告框 - ScoreBar: 评分进度条 - BusinessTreeItem: 业务树形项 - KeyFactorCard: 关键因素卡片 **components/** - Card 容器组件 - CorePositioningCard: 核心定位 - CompetitiveAnalysisCard: 竞争地位分析(含雷达图) - BusinessStructureCard: 业务结构 - ValueChainCard: 产业链分析 - KeyFactorsCard: 关键因素 - TimelineCard: 发展时间线 - BusinessSegmentsCard: 业务板块详情 - StrategyAnalysisCard: 战略分析 **organisms/** - 复杂组件 - ValueChainNodeCard: 产业链节点(含 RelatedCompaniesModal) - TimelineComponent: 时间线(含 EventDetailModal) **utils/** - chartOptions.ts: ECharts 图表配置 优化效果:主文件从 1,796 行减少到 117 行(-93%) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* 业务结构树形项组件
|
||||
*
|
||||
* 递归显示业务结构层级
|
||||
* 使用位置:业务结构分析卡片
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Box, HStack, VStack, Text, Badge, Tag, TagLabel } from '@chakra-ui/react';
|
||||
import { formatPercentage, formatBusinessRevenue } from '@utils/priceFormatters';
|
||||
import type { BusinessTreeItemProps } from '../types';
|
||||
|
||||
const BusinessTreeItem: React.FC<BusinessTreeItemProps> = ({ business, depth = 0 }) => {
|
||||
const bgColor = 'gray.50';
|
||||
|
||||
// 获取营收显示
|
||||
const getRevenueDisplay = (): string => {
|
||||
const revenue = business.revenue || business.financial_metrics?.revenue;
|
||||
const unit = business.revenue_unit;
|
||||
if (revenue !== undefined && revenue !== null) {
|
||||
return formatBusinessRevenue(revenue, unit);
|
||||
}
|
||||
return '-';
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
ml={depth * 6}
|
||||
p={3}
|
||||
bg={bgColor}
|
||||
borderLeft={depth > 0 ? '4px solid' : 'none'}
|
||||
borderLeftColor="blue.400"
|
||||
borderRadius="md"
|
||||
mb={2}
|
||||
_hover={{ shadow: 'md' }}
|
||||
transition="all 0.2s"
|
||||
>
|
||||
<HStack justify="space-between">
|
||||
<VStack align="start" spacing={1}>
|
||||
<HStack>
|
||||
<Text fontWeight="bold" fontSize={depth === 0 ? 'md' : 'sm'}>
|
||||
{business.business_name}
|
||||
</Text>
|
||||
{business.financial_metrics?.revenue_ratio &&
|
||||
business.financial_metrics.revenue_ratio > 30 && (
|
||||
<Badge colorScheme="purple" size="sm">
|
||||
核心业务
|
||||
</Badge>
|
||||
)}
|
||||
</HStack>
|
||||
<HStack spacing={4} flexWrap="wrap">
|
||||
<Tag size="sm" variant="subtle">
|
||||
营收占比: {formatPercentage(business.financial_metrics?.revenue_ratio)}
|
||||
</Tag>
|
||||
<Tag size="sm" variant="subtle">
|
||||
毛利率: {formatPercentage(business.financial_metrics?.gross_margin)}
|
||||
</Tag>
|
||||
{business.growth_metrics?.revenue_growth !== undefined && (
|
||||
<Tag
|
||||
size="sm"
|
||||
colorScheme={
|
||||
business.growth_metrics.revenue_growth > 0 ? 'red' : 'green'
|
||||
}
|
||||
>
|
||||
<TagLabel>
|
||||
增长: {business.growth_metrics.revenue_growth > 0 ? '+' : ''}
|
||||
{formatPercentage(business.growth_metrics.revenue_growth)}
|
||||
</TagLabel>
|
||||
</Tag>
|
||||
)}
|
||||
</HStack>
|
||||
</VStack>
|
||||
<VStack align="end" spacing={0}>
|
||||
<Text fontSize="lg" fontWeight="bold" color="blue.500">
|
||||
{getRevenueDisplay()}
|
||||
</Text>
|
||||
<Text fontSize="xs" color="gray.500">
|
||||
营业收入
|
||||
</Text>
|
||||
</VStack>
|
||||
</HStack>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default BusinessTreeItem;
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 免责声明组件
|
||||
*
|
||||
* 显示 AI 分析内容的免责声明警告框
|
||||
* 使用位置:深度分析各 Card 底部(共 6 处)
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Alert, AlertIcon, Box, Text } from '@chakra-ui/react';
|
||||
|
||||
const DisclaimerBox: React.FC = () => {
|
||||
return (
|
||||
<Alert status="warning" variant="left-accent" mb={4}>
|
||||
<AlertIcon />
|
||||
<Box fontSize="xs" lineHeight="1.4">
|
||||
<Text fontWeight="medium" mb={1}>
|
||||
免责声明
|
||||
</Text>
|
||||
<Text>
|
||||
本内容由AI模型基于新闻、公告、研报等公开信息自动分析和生成,未经许可严禁转载。
|
||||
所有内容仅供参考,不构成任何投资建议,请投资者注意风险,独立审慎决策。
|
||||
</Text>
|
||||
</Box>
|
||||
</Alert>
|
||||
);
|
||||
};
|
||||
|
||||
export default DisclaimerBox;
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* 关键因素卡片组件
|
||||
*
|
||||
* 显示单个关键因素的详细信息
|
||||
* 使用位置:关键因素 Accordion 内
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
Card,
|
||||
CardBody,
|
||||
VStack,
|
||||
HStack,
|
||||
Text,
|
||||
Badge,
|
||||
Tag,
|
||||
Icon,
|
||||
} from '@chakra-ui/react';
|
||||
import { FaArrowUp, FaArrowDown } from 'react-icons/fa';
|
||||
import type { KeyFactorCardProps, ImpactDirection } from '../types';
|
||||
|
||||
/**
|
||||
* 获取影响方向对应的颜色
|
||||
*/
|
||||
const getImpactColor = (direction?: ImpactDirection): string => {
|
||||
const colorMap: Record<ImpactDirection, string> = {
|
||||
positive: 'red',
|
||||
negative: 'green',
|
||||
neutral: 'gray',
|
||||
mixed: 'yellow',
|
||||
};
|
||||
return colorMap[direction || 'neutral'] || 'gray';
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取影响方向的中文标签
|
||||
*/
|
||||
const getImpactLabel = (direction?: ImpactDirection): string => {
|
||||
const labelMap: Record<ImpactDirection, string> = {
|
||||
positive: '正面',
|
||||
negative: '负面',
|
||||
neutral: '中性',
|
||||
mixed: '混合',
|
||||
};
|
||||
return labelMap[direction || 'neutral'] || '中性';
|
||||
};
|
||||
|
||||
const KeyFactorCard: React.FC<KeyFactorCardProps> = ({ factor }) => {
|
||||
const impactColor = getImpactColor(factor.impact_direction);
|
||||
const bgColor = 'white';
|
||||
const borderColor = 'gray.200';
|
||||
|
||||
return (
|
||||
<Card bg={bgColor} borderColor={borderColor} size="sm">
|
||||
<CardBody p={3}>
|
||||
<VStack align="stretch" spacing={2}>
|
||||
<HStack justify="space-between">
|
||||
<Text fontWeight="medium" fontSize="sm">
|
||||
{factor.factor_name}
|
||||
</Text>
|
||||
<Badge colorScheme={impactColor} size="sm">
|
||||
{getImpactLabel(factor.impact_direction)}
|
||||
</Badge>
|
||||
</HStack>
|
||||
|
||||
<HStack spacing={2}>
|
||||
<Text fontSize="lg" fontWeight="bold" color={`${impactColor}.500`}>
|
||||
{factor.factor_value}
|
||||
{factor.factor_unit && ` ${factor.factor_unit}`}
|
||||
</Text>
|
||||
{factor.year_on_year !== undefined && (
|
||||
<Tag
|
||||
size="sm"
|
||||
colorScheme={factor.year_on_year > 0 ? 'red' : 'green'}
|
||||
>
|
||||
<Icon
|
||||
as={factor.year_on_year > 0 ? FaArrowUp : FaArrowDown}
|
||||
mr={1}
|
||||
boxSize={3}
|
||||
/>
|
||||
{Math.abs(factor.year_on_year)}%
|
||||
</Tag>
|
||||
)}
|
||||
</HStack>
|
||||
|
||||
{factor.factor_desc && (
|
||||
<Text fontSize="xs" color="gray.600" noOfLines={2}>
|
||||
{factor.factor_desc}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
<HStack justify="space-between">
|
||||
<Text fontSize="xs" color="gray.500">
|
||||
影响权重: {factor.impact_weight}
|
||||
</Text>
|
||||
{factor.report_period && (
|
||||
<Text fontSize="xs" color="gray.500">
|
||||
{factor.report_period}
|
||||
</Text>
|
||||
)}
|
||||
</HStack>
|
||||
</VStack>
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default KeyFactorCard;
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 评分进度条组件
|
||||
*
|
||||
* 显示带图标的评分进度条
|
||||
* 使用位置:竞争力分析区域(共 8 处)
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Box, HStack, Text, Badge, Progress, Icon } from '@chakra-ui/react';
|
||||
import type { ScoreBarProps } from '../types';
|
||||
|
||||
/**
|
||||
* 根据分数百分比获取颜色方案
|
||||
*/
|
||||
const getColorScheme = (percentage: number): string => {
|
||||
if (percentage >= 80) return 'purple';
|
||||
if (percentage >= 60) return 'blue';
|
||||
if (percentage >= 40) return 'yellow';
|
||||
return 'orange';
|
||||
};
|
||||
|
||||
const ScoreBar: React.FC<ScoreBarProps> = ({ label, score, icon }) => {
|
||||
const percentage = ((score || 0) / 100) * 100;
|
||||
const colorScheme = getColorScheme(percentage);
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<HStack justify="space-between" mb={1}>
|
||||
<HStack>
|
||||
{icon && (
|
||||
<Icon as={icon} boxSize={4} color={`${colorScheme}.500`} />
|
||||
)}
|
||||
<Text fontSize="sm" fontWeight="medium">
|
||||
{label}
|
||||
</Text>
|
||||
</HStack>
|
||||
<Badge colorScheme={colorScheme}>{score || 0}</Badge>
|
||||
</HStack>
|
||||
<Progress
|
||||
value={percentage}
|
||||
size="sm"
|
||||
colorScheme={colorScheme}
|
||||
borderRadius="full"
|
||||
hasStripe
|
||||
isAnimated
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default ScoreBar;
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* 原子组件导出
|
||||
*
|
||||
* DeepAnalysisTab 内部使用的基础 UI 组件
|
||||
*/
|
||||
|
||||
export { default as DisclaimerBox } from './DisclaimerBox';
|
||||
export { default as ScoreBar } from './ScoreBar';
|
||||
export { default as BusinessTreeItem } from './BusinessTreeItem';
|
||||
export { default as KeyFactorCard } from './KeyFactorCard';
|
||||
Reference in New Issue
Block a user