Files
vf_react/src/views/Company/components/CompanyOverview/DeepAnalysisTab/utils/chartOptions.ts
zdl 32a73efb55 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>
2025-12-11 10:59:05 +08:00

140 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 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 },
},
],
};
};