feat: 日志优化
This commit is contained in:
@@ -34,6 +34,7 @@ import { InfoIcon, ViewIcon } from '@chakra-ui/icons';
|
||||
import ReactECharts from 'echarts-for-react';
|
||||
import { eventService } from '../../../services/eventService';
|
||||
import CitedContent from '../../../components/Citation/CitedContent';
|
||||
import { logger } from '../../../utils/logger';
|
||||
|
||||
// 节点样式配置 - 完全复刻Flask版本
|
||||
const NODE_STYLES = {
|
||||
@@ -67,40 +68,39 @@ const NODE_TYPE_LABELS = {
|
||||
|
||||
// 过滤孤立节点 - 完全复刻Flask版本
|
||||
function filterIsolatedNodes(nodes, edges) {
|
||||
console.log('开始过滤孤立节点');
|
||||
console.log('输入节点:', nodes);
|
||||
console.log('输入边:', edges);
|
||||
|
||||
logger.debug('TransmissionChain', '开始过滤孤立节点', {
|
||||
nodesCount: nodes?.length,
|
||||
edgesCount: edges?.length
|
||||
});
|
||||
|
||||
if (!nodes || !edges) {
|
||||
console.log('节点或边数据为空');
|
||||
logger.debug('TransmissionChain', '节点或边数据为空');
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
const connectedNodeIds = new Set();
|
||||
edges.forEach(edge => {
|
||||
console.log('处理边:', edge, '从', edge.source, '到', edge.target);
|
||||
connectedNodeIds.add(String(edge.source));
|
||||
connectedNodeIds.add(String(edge.target));
|
||||
});
|
||||
|
||||
console.log('连接的节点ID集合:', connectedNodeIds);
|
||||
|
||||
|
||||
// 如果图中只有一个节点且是主事件,也显示它
|
||||
const mainEventNode = nodes.find(n => n.extra?.is_main_event);
|
||||
console.log('主事件节点:', mainEventNode);
|
||||
|
||||
|
||||
if (mainEventNode) {
|
||||
connectedNodeIds.add(String(mainEventNode.id));
|
||||
console.log('添加主事件节点ID:', String(mainEventNode.id));
|
||||
}
|
||||
|
||||
|
||||
const filteredNodes = nodes.filter(node => {
|
||||
const shouldKeep = connectedNodeIds.has(String(node.id));
|
||||
console.log(`节点 ${node.name}(${node.id}[${String(node.id)}]): ${shouldKeep ? '保留' : '过滤'}`);
|
||||
return shouldKeep;
|
||||
return connectedNodeIds.has(String(node.id));
|
||||
});
|
||||
|
||||
console.log('过滤后的节点:', filteredNodes);
|
||||
|
||||
logger.debug('TransmissionChain', '过滤完成', {
|
||||
originalCount: nodes.length,
|
||||
filteredCount: filteredNodes.length,
|
||||
connectedNodesCount: connectedNodeIds.size
|
||||
});
|
||||
|
||||
return filteredNodes;
|
||||
}
|
||||
|
||||
@@ -146,30 +146,34 @@ function calculateEdgeWidth(strength) {
|
||||
|
||||
// 力导向图配置 - 完全复刻Flask版本
|
||||
function getGraphOption(data) {
|
||||
console.log('getGraphOption 被调用,输入数据:', data);
|
||||
|
||||
logger.debug('TransmissionChain', 'getGraphOption被调用', {
|
||||
hasData: !!data,
|
||||
nodesCount: data?.nodes?.length,
|
||||
edgesCount: data?.edges?.length
|
||||
});
|
||||
|
||||
if (!data || !data.nodes || !data.edges || data.nodes.length === 0) {
|
||||
console.log('数据为空或无效');
|
||||
return {
|
||||
logger.debug('TransmissionChain', '数据为空或无效');
|
||||
return {
|
||||
title: { text: '暂无传导链数据', left: 'center', top: 'center' },
|
||||
graphic: { type: 'text', left: 'center', top: '60%', style: { text: '当前事件暂无传导链分析数据', fontSize: 14 } }
|
||||
};
|
||||
}
|
||||
|
||||
console.log('原始节点数:', data.nodes.length);
|
||||
console.log('原始边数:', data.edges.length);
|
||||
|
||||
|
||||
const filteredNodes = filterIsolatedNodes(data.nodes, data.edges);
|
||||
console.log('过滤后节点数:', filteredNodes.length);
|
||||
console.log('过滤后的节点:', filteredNodes);
|
||||
|
||||
|
||||
// 进一步过滤:不显示事件类型的节点
|
||||
const nonEventNodes = filteredNodes.filter(node => node.extra?.node_type !== 'event');
|
||||
console.log('排除事件节点后:', nonEventNodes.length);
|
||||
|
||||
|
||||
logger.debug('TransmissionChain', '节点过滤结果', {
|
||||
originalCount: data.nodes.length,
|
||||
filteredCount: filteredNodes.length,
|
||||
nonEventCount: nonEventNodes.length
|
||||
});
|
||||
|
||||
if (nonEventNodes.length === 0) {
|
||||
console.log('过滤后没有有效节点');
|
||||
return {
|
||||
logger.debug('TransmissionChain', '过滤后没有有效节点');
|
||||
return {
|
||||
title: { text: '暂无有效节点数据', left: 'center', top: 'center' },
|
||||
graphic: { type: 'text', left: 'center', top: '60%', style: { text: '当前事件的传导链节点均为孤立节点', fontSize: 14 } }
|
||||
};
|
||||
@@ -180,17 +184,13 @@ function getGraphOption(data) {
|
||||
name: NODE_TYPE_LABELS[type] || type,
|
||||
itemStyle: { color: NODE_STYLES[type]?.color || NODE_STYLES.other.color }
|
||||
}));
|
||||
|
||||
console.log('节点类别:', categories);
|
||||
|
||||
// 构建图表节点数据 - 完全复刻Flask版本样式(排除事件节点)
|
||||
const chartNodes = nonEventNodes.map(node => {
|
||||
const nodeType = node.extra?.node_type || 'other';
|
||||
const nodeStyle = NODE_STYLES[nodeType] || NODE_STYLES['other'];
|
||||
const connectionCount = calculateNodeConnections(node.id, data.edges);
|
||||
|
||||
console.log(`节点 ${node.name} (${node.id}): 类型=${nodeType}, 连接数=${connectionCount}`);
|
||||
|
||||
|
||||
return {
|
||||
id: String(node.id),
|
||||
name: node.name,
|
||||
@@ -433,39 +433,46 @@ const TransmissionChainAnalysis = ({ eventId }) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
console.log('开始加载传导链数据,eventId:', eventId);
|
||||
logger.debug('TransmissionChain', '开始加载传导链数据', { eventId });
|
||||
const [graphRes, sankeyRes] = await Promise.all([
|
||||
eventService.getTransmissionChainAnalysis(eventId),
|
||||
eventService.getSankeyData(eventId)
|
||||
]);
|
||||
|
||||
console.log('传导链数据API响应:', graphRes);
|
||||
console.log('桑基图数据API响应:', sankeyRes);
|
||||
|
||||
|
||||
logger.debug('TransmissionChain', 'API响应', {
|
||||
graphSuccess: graphRes.success,
|
||||
graphNodesCount: graphRes.data?.nodes?.length,
|
||||
graphEdgesCount: graphRes.data?.edges?.length,
|
||||
sankeySuccess: sankeyRes.success
|
||||
});
|
||||
|
||||
if (graphRes.success && graphRes.data) {
|
||||
console.log('传导链节点数据:', graphRes.data.nodes);
|
||||
console.log('传导链边数据:', graphRes.data.edges);
|
||||
setGraphData(graphRes.data);
|
||||
} else {
|
||||
console.log('传导链数据加载失败:', graphRes);
|
||||
logger.warn('TransmissionChain', '传导链数据加载失败', {
|
||||
success: graphRes.success,
|
||||
eventId
|
||||
});
|
||||
setGraphData(null);
|
||||
}
|
||||
|
||||
|
||||
if (sankeyRes.success && sankeyRes.data) {
|
||||
console.log('桑基图数据:', sankeyRes.data);
|
||||
setSankeyData(sankeyRes.data);
|
||||
} else {
|
||||
console.log('桑基图数据加载失败:', sankeyRes);
|
||||
logger.warn('TransmissionChain', '桑基图数据加载失败', {
|
||||
success: sankeyRes.success,
|
||||
eventId
|
||||
});
|
||||
setSankeyData(null);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('传导链数据加载异常:', e);
|
||||
logger.error('TransmissionChain', 'fetchData', e, { eventId });
|
||||
setError('加载传导链数据失败');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (eventId) {
|
||||
fetchData();
|
||||
}
|
||||
@@ -509,28 +516,37 @@ const TransmissionChainAnalysis = ({ eventId }) => {
|
||||
if (result.success) {
|
||||
return result.data;
|
||||
} else {
|
||||
console.error('获取节点详情失败:', result.message);
|
||||
logger.error('TransmissionChain', 'getChainNodeDetail', new Error(result.message), {
|
||||
nodeId,
|
||||
eventId
|
||||
});
|
||||
return null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('API调用异常:', error);
|
||||
logger.error('TransmissionChain', 'getChainNodeDetail', error, {
|
||||
nodeId,
|
||||
eventId
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 力导向图节点点击事件
|
||||
const handleGraphNodeClick = async (params) => {
|
||||
console.log('点击事件详情:', params);
|
||||
|
||||
logger.debug('TransmissionChain', '图表节点点击', {
|
||||
dataType: params.dataType,
|
||||
componentType: params.componentType,
|
||||
hasData: !!params.data,
|
||||
nodeId: params.data?.id
|
||||
});
|
||||
|
||||
// 处理节点点击(包括节点本体和标签)
|
||||
if ((params.dataType === 'node' || params.componentType === 'series') && params.data && params.data.id) {
|
||||
console.log('点击图表节点:', params.data.id, 'dataType:', params.dataType, 'componentType:', params.componentType);
|
||||
|
||||
// 获取基本节点信息
|
||||
const clickedNode = graphData.nodes.find(n => String(n.id) === String(params.data.id));
|
||||
if (clickedNode) {
|
||||
setSelectedNode(clickedNode);
|
||||
|
||||
|
||||
// 计算传导路径
|
||||
const mainEventNode = graphData?.nodes?.find(n => n.extra?.is_main_event);
|
||||
if (mainEventNode && String(clickedNode.id) !== String(mainEventNode.id)) {
|
||||
@@ -539,36 +555,34 @@ const TransmissionChainAnalysis = ({ eventId }) => {
|
||||
} else {
|
||||
setTransmissionPath([]);
|
||||
}
|
||||
|
||||
|
||||
// 获取详细节点信息(包括parents和children)
|
||||
console.log('开始获取节点详情,节点ID:', params.data.id);
|
||||
logger.debug('TransmissionChain', '获取节点详情', {
|
||||
nodeId: params.data.id,
|
||||
nodeName: clickedNode.name
|
||||
});
|
||||
const detail = await getChainNodeDetail(params.data.id);
|
||||
console.log('获取到的节点详情:', detail);
|
||||
setNodeDetail(detail);
|
||||
|
||||
|
||||
// 打开弹窗
|
||||
setIsModalOpen(true);
|
||||
}
|
||||
}
|
||||
// 如果点击的是空白区域,也尝试查找最近的节点
|
||||
else if (params.componentType === 'series' && !params.data) {
|
||||
console.log('点击了图表空白区域');
|
||||
// 这里可以添加点击空白区域的处理逻辑
|
||||
}
|
||||
};
|
||||
|
||||
// 桑基图节点点击事件
|
||||
const handleSankeyNodeClick = async (params) => {
|
||||
if (params.dataType === 'node' && params.data && params.data.name) {
|
||||
console.log('点击桑基图节点:', params.data.name);
|
||||
|
||||
logger.debug('TransmissionChain', '桑基图节点点击', {
|
||||
nodeName: params.data.name
|
||||
});
|
||||
|
||||
// 通过名称在原始数据中查找对应的节点
|
||||
if (graphData && graphData.nodes) {
|
||||
const clickedNode = graphData.nodes.find(n => n.name === params.data.name);
|
||||
if (clickedNode) {
|
||||
console.log('找到对应节点:', clickedNode);
|
||||
setSelectedNode(clickedNode);
|
||||
|
||||
|
||||
// 计算传导路径
|
||||
const mainEventNode = graphData?.nodes?.find(n => n.extra?.is_main_event);
|
||||
if (mainEventNode && String(clickedNode.id) !== String(mainEventNode.id)) {
|
||||
@@ -577,17 +591,21 @@ const TransmissionChainAnalysis = ({ eventId }) => {
|
||||
} else {
|
||||
setTransmissionPath([]);
|
||||
}
|
||||
|
||||
|
||||
// 获取详细节点信息(包括parents和children)
|
||||
console.log('开始获取桑基图节点详情,节点ID:', clickedNode.id);
|
||||
logger.debug('TransmissionChain', '获取桑基图节点详情', {
|
||||
nodeId: clickedNode.id,
|
||||
nodeName: clickedNode.name
|
||||
});
|
||||
const detail = await getChainNodeDetail(clickedNode.id);
|
||||
console.log('获取到的桑基图节点详情:', detail);
|
||||
setNodeDetail(detail);
|
||||
|
||||
|
||||
// 打开弹窗
|
||||
setIsModalOpen(true);
|
||||
} else {
|
||||
console.log('未找到对应的节点数据');
|
||||
logger.warn('TransmissionChain', '未找到对应的节点数据', {
|
||||
nodeName: params.data.name
|
||||
});
|
||||
// 创建一个临时节点信息用于显示
|
||||
const tempNode = {
|
||||
id: params.data.name,
|
||||
@@ -601,7 +619,7 @@ const TransmissionChainAnalysis = ({ eventId }) => {
|
||||
setSelectedNode(tempNode);
|
||||
setTransmissionPath([]);
|
||||
setNodeDetail(null);
|
||||
|
||||
|
||||
// 打开弹窗
|
||||
setIsModalOpen(true);
|
||||
}
|
||||
@@ -710,19 +728,11 @@ const TransmissionChainAnalysis = ({ eventId }) => {
|
||||
{chartReady && (
|
||||
<>
|
||||
{viewMode === 'graph' ? (
|
||||
<ReactECharts
|
||||
<ReactECharts
|
||||
option={graphData ? getGraphOption(graphData) : {}}
|
||||
style={{ height: '100%', width: '100%' }}
|
||||
style={{ height: '100%', width: '100%' }}
|
||||
onEvents={{
|
||||
click: handleGraphNodeClick,
|
||||
// 添加更多事件以提高点击敏感性
|
||||
mouseover: (params) => {
|
||||
console.log('鼠标悬停:', params);
|
||||
// 可以在这里添加悬停效果
|
||||
},
|
||||
mouseout: (params) => {
|
||||
// 鼠标离开的处理
|
||||
}
|
||||
click: handleGraphNodeClick
|
||||
}}
|
||||
opts={{
|
||||
renderer: 'canvas',
|
||||
@@ -736,19 +746,11 @@ const TransmissionChainAnalysis = ({ eventId }) => {
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<ReactECharts
|
||||
<ReactECharts
|
||||
option={sankeyData ? getSankeyOption(sankeyData) : {}}
|
||||
style={{ height: '100%', width: '100%' }}
|
||||
onEvents={{
|
||||
click: handleSankeyNodeClick,
|
||||
// 添加更多事件以提高点击敏感性
|
||||
mouseover: (params) => {
|
||||
console.log('桑基图鼠标悬停:', params);
|
||||
// 可以在这里添加悬停效果
|
||||
},
|
||||
mouseout: (params) => {
|
||||
// 鼠标离开的处理
|
||||
}
|
||||
click: handleSankeyNodeClick
|
||||
}}
|
||||
opts={{
|
||||
renderer: 'canvas',
|
||||
|
||||
Reference in New Issue
Block a user