fix: 修复知识图谱节点信息无法正常渲染问题

This commit is contained in:
hhs
2026-04-05 15:28:25 +08:00
parent 1d0fbde066
commit 882e14a47b
4 changed files with 128 additions and 43 deletions
+90 -40
View File
@@ -26,85 +26,134 @@ export const GraphView = ({
if (!containerRef.current) return; if (!containerRef.current) return;
try { try {
const graphData = { console.log('🎨 GraphView - Initializing graph with data:', data);
nodes: data.nodes.map((node: Node) => ({ console.log('🎨 GraphView - Container dimensions:', {
...node, width: containerRef.current.clientWidth,
id: node.id, height: height
})), });
edges: data.edges.map((edge: Edge) => ({
...edge,
id: edge.id,
source: edge.source,
target: edge.target,
})),
};
if (graphRef.current) { if (graphRef.current) {
try {
graphRef.current.destroy(); graphRef.current.destroy();
} catch (e) {
console.log('🎨 GraphView - Destroy error:', e);
}
graphRef.current = null; graphRef.current = null;
} }
const processedGraphData = { const processedGraphData = {
nodes: graphData.nodes.map((node: any) => { nodes: data.nodes.map((node: Node) => {
const typeColors: Record<string, Record<string, string>> = { const typeColors: Record<string, { fill: string; stroke: string }> = {
'概念': { fill: '#4ECDC4', stroke: '#45B7B0', text: '#2C3E50' }, '概念': { fill: '#4ECDC4', stroke: '#45B7B0' },
'工具': { fill: '#FFA07A', stroke: '#FF7F50', text: '#2C3E50' }, '工具': { fill: '#FFA07A', stroke: '#FF7F50' },
'应用': { fill: '#2ECC71', stroke: '#27AE60', text: '#2C3E50' }, '应用': { fill: '#2ECC71', stroke: '#27AE60' },
}; };
const colors = typeColors[node.type] || { fill: '#C6E5FF', stroke: '#5B8FF9', text: '#2C3E50' }; const colors = typeColors[node.type] || { fill: '#C6E5FF', stroke: '#5B8FF9' };
return { return {
...node, id: node.id,
type: 'circle', data: {
id: node.id,
label: node.label,
type: node.type,
properties: node.properties,
style: node.style,
},
style: { style: {
size: 40,
fill: colors.fill, fill: colors.fill,
stroke: colors.stroke, stroke: colors.stroke,
lineWidth: 2, lineWidth: 2,
cursor: 'pointer', labelText: node.label,
}, labelFill: '#2C3E50',
data: { labelFontSize: 14,
...node, labelFontWeight: 'bold',
originalType: node.type, labelPlacement: 'bottom',
colors,
}, },
}; };
}), }),
edges: graphData.edges.map((edge: any) => ({ edges: data.edges.map((edge: Edge) => ({
...edge, id: edge.id,
type: 'cubic-vertical', source: edge.source,
target: edge.target,
label: edge.label,
data: {
source: edge.source,
target: edge.target,
label: edge.label,
type: edge.type,
properties: edge.properties,
},
style: { style: {
stroke: '#95A5A6', stroke: '#95A5A6',
lineWidth: 2, lineWidth: 2,
cursor: 'pointer', labelText: edge.label,
labelFill: '#666',
labelFontSize: 10,
}, },
})), })),
}; };
const graph = new Graph({ console.log('🎨 GraphView - Processed graph data nodes:', processedGraphData.nodes.length);
console.log('🎨 GraphView - Processed graph data edges:', processedGraphData.edges.length);
const graphConfig: any = {
container: containerRef.current, container: containerRef.current,
width: containerRef.current.clientWidth, width: containerRef.current.clientWidth,
height: height, height: height,
data: processedGraphData as any, data: processedGraphData,
autoFit: 'view', autoFit: 'view',
node: {
type: 'circle',
style: {
size: 50,
lineWidth: 2,
},
},
edge: {
type: 'line',
style: {
lineWidth: 1,
endArrow: true,
},
},
layout: { layout: {
type: layout.type, type: layout.type,
nodeSize: 60,
preventOverlap: true, preventOverlap: true,
nodeSize: layout.nodeSize || 30, linkDistance: 150,
linkDistance: layout.linkDistance || 100,
}, },
behaviors: ['drag-canvas', 'zoom-canvas', 'drag-element', 'hover-activate'], behaviors: ['drag-canvas', 'zoom-canvas', 'drag-element'],
}); };
console.log('🎨 GraphView - Creating graph with config:', graphConfig);
const graph = new Graph(graphConfig);
graphRef.current = graph; graphRef.current = graph;
graph.render();
console.log('🎨 GraphView - Starting render');
graph.render()
.then(() => {
console.log('🎨 GraphView - Graph rendered successfully');
})
.catch((renderError) => {
console.error('🎨 GraphView - Render error:', renderError);
});
graph.on('node:click', (evt) => { graph.on('node:click', (evt) => {
if (evt.itemId && onNodeClick) { console.log('🔗 G6 - Node clicked, evt:', evt);
const nodeData = data.nodes.find((n: Node) => n.id === evt.itemId); const nodeId = evt.itemId;
console.log('🔗 G6 - Node ID:', nodeId);
if (nodeId && onNodeClick) {
const nodeData = data.nodes.find((n: Node) => n.id === nodeId);
console.log('🔗 G6 - Found node data:', nodeData);
if (nodeData) { if (nodeData) {
console.log('🔗 G6 - Node properties:', nodeData.properties);
onNodeClick(nodeData); onNodeClick(nodeData);
} else {
console.log('🔗 G6 - Node data not found for ID:', nodeId);
} }
} }
}); });
@@ -154,6 +203,7 @@ export const GraphView = ({
onNodeClick, onNodeClick,
onEdgeClick, onEdgeClick,
onNodeHover, onNodeHover,
data,
]); ]);
useEffect(() => { useEffect(() => {
+27 -1
View File
@@ -8,6 +8,11 @@ interface NodePanelProps {
export const NodePanel = ({ node, onClose }: NodePanelProps) => { export const NodePanel = ({ node, onClose }: NodePanelProps) => {
if (!node) return null; if (!node) return null;
console.log('📋 NodePanel - Rendering node:', node);
console.log('📋 NodePanel - Node properties:', node.properties);
console.log('📋 NodePanel - Has properties:', !!node.properties);
console.log('📋 NodePanel - Properties keys:', node.properties ? Object.keys(node.properties) : []);
return ( return (
<div className="w-80 bg-white border-l border-gray-200 shadow-lg overflow-y-auto"> <div className="w-80 bg-white border-l border-gray-200 shadow-lg overflow-y-auto">
<div className="p-4 border-b border-gray-200 flex justify-between items-center"> <div className="p-4 border-b border-gray-200 flex justify-between items-center">
@@ -46,9 +51,30 @@ export const NodePanel = ({ node, onClose }: NodePanelProps) => {
</div> </div>
)} )}
{node.properties && Object.keys(node.properties).length > 0 && ( {!node.properties && (
<div> <div>
<div className="text-xs text-gray-500 uppercase tracking-wide mb-2">属性</div> <div className="text-xs text-gray-500 uppercase tracking-wide mb-2">属性</div>
<div className="text-sm text-gray-400 italic">
暂无属性数据
</div>
<div className="text-xs text-gray-300 italic mt-1">
Debug: Node ID: {node.id}, Has properties?: {node.properties ? 'Yes' : 'No'}
</div>
</div>
)}
{node.properties && Object.keys(node.properties).length === 0 && (
<div>
<div className="text-xs text-gray-500 uppercase tracking-wide mb-2">属性</div>
<div className="text-sm text-gray-400 italic">
属性对象存在但为空
</div>
</div>
)}
{node.properties && Object.keys(node.properties).length > 0 && (
<div>
<div className="text-xs text-gray-500 uppercase tracking-wide mb-2">属性 ({Object.keys(node.properties).length})</div>
<div className="space-y-2"> <div className="space-y-2">
{Object.entries(node.properties).map(([key, value]) => ( {Object.entries(node.properties).map(([key, value]) => (
<div key={key} className="flex justify-between items-start"> <div key={key} className="flex justify-between items-start">
+7 -1
View File
@@ -49,8 +49,13 @@ export const KnowledgeGraph = () => {
setLoading(true); setLoading(true);
const data = await graphApi.getData(); const data = await graphApi.getData();
console.log('🎯 KnowledgeGraph - Received data:', data);
console.log('🎯 KnowledgeGraph - Node count:', data.nodes.length);
console.log('🎯 KnowledgeGraph - First node properties:', data.nodes[0]?.properties);
// 添加一些示例数据,如果 API 返回空数据 // 添加一些示例数据,如果 API 返回空数据
if (data.nodes.length === 0) { if (data.nodes.length === 0) {
console.log('⚠️ API returned empty data, using sample data');
const sampleData: GraphData = { const sampleData: GraphData = {
nodes: [ nodes: [
{ id: '1', label: '人工智能', type: '概念', properties: { importance: 1 } }, { id: '1', label: '人工智能', type: '概念', properties: { importance: 1 } },
@@ -74,10 +79,11 @@ export const KnowledgeGraph = () => {
}; };
setGraphData(sampleData); setGraphData(sampleData);
} else { } else {
console.log('✅ Setting graph data from API');
setGraphData(data); setGraphData(data);
} }
} catch (error) { } catch (error) {
console.error('Failed to load graph data:', error); console.error('❌ Failed to load graph data:', error);
} finally { } finally {
setLoading(false); setLoading(false);
} }
+3
View File
@@ -15,6 +15,9 @@ export const graphApi = {
async getData(): Promise<GraphData> { async getData(): Promise<GraphData> {
try { try {
const response = await apiClient.get<GraphData>('/graph'); const response = await apiClient.get<GraphData>('/graph');
console.log('🔍 API Response - Graph Data:', JSON.stringify(response.data, null, 2));
console.log('🔍 API Response - First Node:', response.data.nodes[0]);
console.log('🔍 API Response - First Node Properties:', response.data.nodes[0]?.properties);
return response.data; return response.data;
} catch (error) { } catch (error) {
console.error('Error fetching graph data:', error); console.error('Error fetching graph data:', error);