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,139 @@
|
||||
/**
|
||||
* DeepAnalysisTab 图表配置工具
|
||||
*
|
||||
* 生成雷达图和桑基图的 ECharts 配置
|
||||
*/
|
||||
|
||||
import type {
|
||||
ComprehensiveData,
|
||||
ValueChainData,
|
||||
RadarChartOption,
|
||||
SankeyChartOption,
|
||||
} from '../types';
|
||||
|
||||
/**
|
||||
* 生成竞争力雷达图配置
|
||||
* @param comprehensiveData - 综合分析数据
|
||||
* @returns ECharts 雷达图配置,或 null(数据不足时)
|
||||
*/
|
||||
export const getRadarChartOption = (
|
||||
comprehensiveData?: ComprehensiveData
|
||||
): RadarChartOption | null => {
|
||||
if (!comprehensiveData?.competitive_position?.scores) return null;
|
||||
|
||||
const scores = comprehensiveData.competitive_position.scores;
|
||||
const indicators = [
|
||||
{ name: '市场地位', max: 100 },
|
||||
{ name: '技术实力', max: 100 },
|
||||
{ name: '品牌价值', max: 100 },
|
||||
{ name: '运营效率', max: 100 },
|
||||
{ name: '财务健康', max: 100 },
|
||||
{ name: '创新能力', max: 100 },
|
||||
{ name: '风险控制', max: 100 },
|
||||
{ name: '成长潜力', max: 100 },
|
||||
];
|
||||
|
||||
const data = [
|
||||
scores.market_position || 0,
|
||||
scores.technology || 0,
|
||||
scores.brand || 0,
|
||||
scores.operation || 0,
|
||||
scores.finance || 0,
|
||||
scores.innovation || 0,
|
||||
scores.risk || 0,
|
||||
scores.growth || 0,
|
||||
];
|
||||
|
||||
return {
|
||||
tooltip: { trigger: 'item' },
|
||||
radar: {
|
||||
indicator: indicators,
|
||||
shape: 'polygon',
|
||||
splitNumber: 4,
|
||||
name: { textStyle: { color: '#666', fontSize: 12 } },
|
||||
splitLine: {
|
||||
lineStyle: { color: ['#e8e8e8', '#e0e0e0', '#d0d0d0', '#c0c0c0'] },
|
||||
},
|
||||
splitArea: {
|
||||
show: true,
|
||||
areaStyle: {
|
||||
color: ['rgba(250,250,250,0.3)', 'rgba(200,200,200,0.3)'],
|
||||
},
|
||||
},
|
||||
axisLine: { lineStyle: { color: '#ddd' } },
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '竞争力评分',
|
||||
type: 'radar',
|
||||
data: [
|
||||
{
|
||||
value: data,
|
||||
name: '当前评分',
|
||||
symbol: 'circle',
|
||||
symbolSize: 5,
|
||||
lineStyle: { width: 2, color: '#3182ce' },
|
||||
areaStyle: { color: 'rgba(49, 130, 206, 0.3)' },
|
||||
label: {
|
||||
show: true,
|
||||
formatter: (params: { value: number }) => params.value,
|
||||
color: '#3182ce',
|
||||
fontSize: 10,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 生成产业链桑基图配置
|
||||
* @param valueChainData - 产业链数据
|
||||
* @returns ECharts 桑基图配置,或 null(数据不足时)
|
||||
*/
|
||||
export const getSankeyChartOption = (
|
||||
valueChainData?: ValueChainData
|
||||
): SankeyChartOption | null => {
|
||||
if (
|
||||
!valueChainData?.value_chain_flows ||
|
||||
valueChainData.value_chain_flows.length === 0
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const nodes = new Set<string>();
|
||||
const links: Array<{
|
||||
source: string;
|
||||
target: string;
|
||||
value: number;
|
||||
lineStyle: { color: string; opacity: number };
|
||||
}> = [];
|
||||
|
||||
valueChainData.value_chain_flows.forEach((flow) => {
|
||||
if (!flow?.source?.node_name || !flow?.target?.node_name) return;
|
||||
nodes.add(flow.source.node_name);
|
||||
nodes.add(flow.target.node_name);
|
||||
links.push({
|
||||
source: flow.source.node_name,
|
||||
target: flow.target.node_name,
|
||||
value: parseFloat(flow.flow_metrics?.flow_ratio || '1') || 1,
|
||||
lineStyle: { color: 'source', opacity: 0.6 },
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
tooltip: { trigger: 'item', triggerOn: 'mousemove' },
|
||||
series: [
|
||||
{
|
||||
type: 'sankey',
|
||||
layout: 'none',
|
||||
emphasis: { focus: 'adjacency' },
|
||||
data: Array.from(nodes).map((name) => ({ name })),
|
||||
links: links,
|
||||
lineStyle: { color: 'gradient', curveness: 0.5 },
|
||||
label: { color: '#333', fontSize: 10 },
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user