110 lines
3.7 KiB
TypeScript
110 lines
3.7 KiB
TypeScript
import { useState, useCallback, useEffect } from 'react';
|
|
import type { GraphData, Node, SearchNode } from '../types/graph';
|
|
import { graphApi } from '../services/graphApi';
|
|
import { SAMPLE_GRAPH_DATA } from '../config/sampleData';
|
|
import { resetColorAssignment } from '../config/colors';
|
|
|
|
/**
|
|
* 知识图谱数据管理 Hook
|
|
* 负责图谱数据的加载、搜索和节点选择
|
|
*/
|
|
export const useGraphData = () => {
|
|
const [graphData, setGraphData] = useState<GraphData>({ nodes: [], edges: [] });
|
|
const [selectedNode, setSelectedNode] = useState<Node | null>(null);
|
|
const [hoveredNode, setHoveredNode] = useState<Node | null>(null);
|
|
const [searchResults, setSearchResults] = useState<SearchNode[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
// 从后端加载图谱数据
|
|
const loadGraphData = useCallback(async () => {
|
|
try {
|
|
setLoading(true);
|
|
const data = await graphApi.getData();
|
|
|
|
// 重置颜色分配缓存,确保每次加载数据时颜色分配一致
|
|
resetColorAssignment();
|
|
|
|
// 如果后端返回空数据,使用示例数据
|
|
if (data.nodes.length === 0) {
|
|
setGraphData({ ...SAMPLE_GRAPH_DATA, id: `sample-${Date.now()}` });
|
|
} else {
|
|
setGraphData({ ...data, id: `data-${Date.now()}` });
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to load graph data:', error);
|
|
// 重置颜色分配缓存
|
|
resetColorAssignment();
|
|
// API 失败时使用示例数据作为降级方案
|
|
setGraphData({ ...SAMPLE_GRAPH_DATA, id: `fallback-${Date.now()}` });
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
// 搜索节点(前端过滤,可根据需要切换到后端搜索)
|
|
const handleSearch = useCallback((query: string) => {
|
|
const results = graphData.nodes
|
|
.filter((node: Node) =>
|
|
node.label.toLowerCase().includes(query.toLowerCase()) ||
|
|
node.id.toLowerCase().includes(query.toLowerCase())
|
|
)
|
|
.map((node: Node) => ({
|
|
id: node.id,
|
|
label: node.label,
|
|
type: node.type,
|
|
matched: true,
|
|
}));
|
|
setSearchResults(results);
|
|
}, [graphData]);
|
|
|
|
// 通过 ID 选择节点(用于搜索结果点击)
|
|
const handleNodeSelectById = useCallback((nodeId: string) => {
|
|
console.log('[useGraphData] handleNodeSelectById called with id:', nodeId);
|
|
const node = graphData.nodes.find((n: Node) => n.id === nodeId);
|
|
console.log('[useGraphData] Found node:', node);
|
|
if (node) {
|
|
console.log('[useGraphData] Setting selectedNode:', node);
|
|
setSelectedNode(node);
|
|
} else {
|
|
console.log('[useGraphData] Node not found with id:', nodeId);
|
|
}
|
|
}, [graphData.nodes]);
|
|
|
|
// 选择节点(用于图谱点击)
|
|
const handleNodeSelect = useCallback((node: Node | null) => {
|
|
console.log('[useGraphData] handleNodeSelect called with node:', node);
|
|
console.log('[useGraphData] About to call setSelectedNode');
|
|
setSelectedNode(node);
|
|
console.log('[useGraphData] setSelectedNode called');
|
|
}, []);
|
|
|
|
// 悬停节点(用于图谱悬停)
|
|
const handleNodeHover = useCallback((node: Node | null) => {
|
|
setHoveredNode(node);
|
|
}, []);
|
|
|
|
// 监听 selectedNode 变化,用于调试
|
|
useEffect(() => {
|
|
console.log('[useGraphData] selectedNode state changed:', selectedNode);
|
|
console.log('[useGraphData] selectedNode truthiness:', !!selectedNode);
|
|
}, [selectedNode]);
|
|
|
|
// 组件挂载时加载数据
|
|
useEffect(() => {
|
|
loadGraphData();
|
|
}, [loadGraphData]);
|
|
|
|
return {
|
|
graphData,
|
|
selectedNode,
|
|
hoveredNode,
|
|
searchResults,
|
|
loading,
|
|
setSelectedNode,
|
|
handleSearch,
|
|
handleNodeSelectById,
|
|
handleNodeSelect,
|
|
handleNodeHover,
|
|
};
|
|
};
|