From 921c8d664001a00f88e8afbea53fa0adedac1298 Mon Sep 17 00:00:00 2001 From: Wenjie Zhang Date: Tue, 26 Aug 2025 22:20:23 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E7=9F=A5=E8=AF=86=E5=9B=BE=E8=B0=B1):=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=BE=B9=E7=82=B9=E5=87=BB=E4=B8=8D=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E9=97=AE=E9=A2=98=E5=B9=B6=E4=BC=98=E5=8C=96=E9=9D=A2?= =?UTF-8?q?=E6=9D=BF=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 改进边数据查找逻辑,增加多种ID格式匹配方式 调整边面板位置逻辑,避免与节点面板重叠 增加边点击容差和悬停容差,提升交互体验 添加调试日志和错误处理,便于问题排查 --- docs/changelog/update.md | 4 +- web/src/components/KnowledgeGraphViewer.vue | 78 ++++++++++++++++++--- web/src/components/RefsComponent.vue | 6 +- web/src/stores/graphStore.js | 42 +++++++++-- 4 files changed, 109 insertions(+), 21 deletions(-) diff --git a/docs/changelog/update.md b/docs/changelog/update.md index 9b574035..18505ac1 100644 --- a/docs/changelog/update.md +++ b/docs/changelog/update.md @@ -5,8 +5,8 @@ - [ ] 添加对于上传文件的支持:这里的复杂的地方就在于如何和历史记录结合在一起(v0.2.3 版本实现,放在记忆管理后面) 🐛**BUGs** -- [ ] LlightRAG 知识库中,点击边,没有显示,但是在全屏的时候却又能够显示出来。 - +- [x] LlightRAG 知识库中,点击边,没有显示,但是在全屏的时候却又能够显示出来。 + 💯 **More**: 下面的功能**可能**会放在后续版本实现,暂时未定 diff --git a/web/src/components/KnowledgeGraphViewer.vue b/web/src/components/KnowledgeGraphViewer.vue index 080fbbd3..5ab90153 100644 --- a/web/src/components/KnowledgeGraphViewer.vue +++ b/web/src/components/KnowledgeGraphViewer.vue @@ -136,7 +136,7 @@
@@ -284,7 +284,7 @@ const loadingMessage = ref('加载图数据中...') // 面板拖拽相关 const nodePanelPosition = ref({ x: 12, y: 60 }) -const edgePanelPosition = ref({ x: 12, y: 320 }) +const edgePanelPosition = ref({ x: 12, y: 150 }) // 降低初始Y位置以适应紧凑模式 const dragging = ref({ active: false, type: '', startX: 0, startY: 0, initialX: 0, initialY: 0 }) // 数据库相关状态 @@ -309,6 +309,29 @@ const stats = computed(() => graphStore.stats) const selectedNodeData = computed(() => graphStore.selectedNodeData) const selectedEdgeData = computed(() => graphStore.selectedEdgeData) +// 智能边面板位置 - 确保在紧凑模式下也能正确显示 +const intelligentEdgePanelPosition = computed(() => { + if (!sigmaContainer.value) return edgePanelPosition.value + + const containerHeight = sigmaContainer.value.clientHeight + const panelHeight = 200 // 估计的面板高度 + const nodePanelBottom = selectedNodeData.value ? nodePanelPosition.value.y + 200 : 0 + + // 如果有节点面板显示,将边面板放在节点面板下方 + if (selectedNodeData.value) { + return { + x: edgePanelPosition.value.x + 260, // 在节点面板右侧 + y: Math.min(nodePanelPosition.value.y, containerHeight - panelHeight - 20) + } + } + + // 确保边面板在容器范围内 + return { + x: edgePanelPosition.value.x, + y: Math.min(edgePanelPosition.value.y, Math.max(60, containerHeight - panelHeight - 20)) + } +}) + // 获取节点显示名称 const getNodeDisplayName = (node) => { if (node.properties?.entity_id) { @@ -425,11 +448,11 @@ const sigmaSettings = { edgeLabelColor: { color: '#666' }, - minEdgeThickness: 3, // 增加最小边厚度,提高点击性 - maxEdgeThickness: 8, // 增加最大边厚度 + minEdgeThickness: 4, // 增加最小边厚度,提高点击性 + maxEdgeThickness: 10, // 增加最大边厚度 // 添加边点击相关配置 - edgeClickTolerance: 10, // 边点击容差,增加点击检测区域 - edgeHoverTolerance: 8, // 边悬停容差 + edgeClickTolerance: 15, // 增加边点击容差,增加点击检测区域 + edgeHoverTolerance: 12, // 增加边悬停容差 zoomToSizeRatioFunction: (x) => x, // 确保缩放时边的厚度保持合理 eventListenerOptions: { wheel: { passive: true }, @@ -522,18 +545,45 @@ const registerEvents = () => { // 边点击事件 sigmaInstance.on('clickEdge', ({ edge }) => { try { - console.log('边被点击:', edge) + console.log('边被点击 - Sigma边ID:', edge) const graph = sigmaInstance.getGraph() if (graph.hasEdge(edge)) { + // 获取Sigma边的属性,其中包含原始数据 + const sigmaEdgeData = graph.getEdgeAttributes(edge) + console.log('Sigma边属性:', sigmaEdgeData) + + // 立即设置选中的边 - 使用Sigma边ID graphStore.setSelectedEdge(edge) - const edgeData = graph.getEdgeAttributes(edge) - console.log('边数据:', edgeData) - message.success(`已选中边: ${edge}`) + + // 确保边面板显示 + nextTick(() => { + if (selectedEdgeData.value) { + console.log('边面板应该显示:', selectedEdgeData.value) + message.success(`已选中边: ${getEdgeDisplayName(selectedEdgeData.value)}`) + } else { + console.warn('selectedEdgeData为空,尝试使用Sigma边数据') + // 如果无法从rawGraph中找到,直接使用Sigma边的原始数据 + const fallbackData = sigmaEdgeData.originalData || { + id: edge, + source: graph.source(edge), + target: graph.target(edge), + properties: { + keywords: sigmaEdgeData.label || '', + description: sigmaEdgeData.label || '', + weight: sigmaEdgeData.originalWeight || 1 + } + } + console.log('使用回退边数据:', fallbackData) + message.success(`已选中边: ${getEdgeDisplayName(fallbackData)}`) + } + }) } else { console.warn('点击的边不存在于图中:', edge) + message.warning('点击的边不存在于图中') } } catch (error) { console.error('处理边点击事件时出错:', error) + message.error('处理边点击事件时出错') } }) @@ -1029,6 +1079,14 @@ watch(() => graphStore.selectedNodeData, (nodeData) => { console.log('Selected node data changed:', nodeData) }) +// 监听选中边数据变化,用于调试和确保面板显示 +watch(() => graphStore.selectedEdgeData, (edgeData) => { + console.log('Selected edge data changed:', edgeData) + if (edgeData) { + console.log('边面板应该显示,当前位置:', intelligentEdgePanelPosition.value) + } +}) + // 监听选中节点变化,移动相机 watch(() => graphStore.selectedNode, (nodeId) => { if (nodeId && graphStore.moveToSelectedNode && sigmaInstance) { diff --git a/web/src/components/RefsComponent.vue b/web/src/components/RefsComponent.vue index 3620fdcd..f7cf59fd 100644 --- a/web/src/components/RefsComponent.vue +++ b/web/src/components/RefsComponent.vue @@ -159,7 +159,7 @@ const dislikeThisResponse = (msg) => { gap: 10px; .item { - background: var(--gray-100); + background: var(--gray-50); color: var(--gray-700); padding: 2px 8px; border-radius: 8px; @@ -169,10 +169,10 @@ const dislikeThisResponse = (msg) => { &.btn { cursor: pointer; &:hover { - background: var(--gray-200); + background: var(--gray-100); } &:active { - background: var(--gray-300); + background: var(--gray-200); } } } diff --git a/web/src/stores/graphStore.js b/web/src/stores/graphStore.js index 0903bd0b..870f3a63 100644 --- a/web/src/stores/graphStore.js +++ b/web/src/stores/graphStore.js @@ -44,23 +44,53 @@ export const useGraphStore = defineStore('graph', { // 获取选中边的详细信息 selectedEdgeData: (state) => { if (!state.selectedEdge || !state.rawGraph) return null - // 首先尝试通过dynamicId匹配 + + console.log('查找边数据,选中边ID:', state.selectedEdge) + + // 首先尝试通过dynamicId匹配(Sigma使用的ID格式) let foundEdge = state.rawGraph.edges.find(edge => edge.dynamicId === state.selectedEdge) - if (foundEdge) return foundEdge + if (foundEdge) { + console.log('通过dynamicId找到边:', foundEdge) + return foundEdge + } // 如果没找到,尝试通过原始ID匹配 foundEdge = state.rawGraph.edges.find(edge => edge.id === state.selectedEdge) - if (foundEdge) return foundEdge + if (foundEdge) { + console.log('通过id找到边:', foundEdge) + return foundEdge + } + + // 对于格式为 source-target-index 的dynamicId,也尝试解析 + const dynamicIdPattern = /^(.+)-(.+)-(\d+)$/ + const match = state.selectedEdge.match(dynamicIdPattern) + if (match) { + const [, source, target, index] = match + foundEdge = state.rawGraph.edges.find(edge => + edge.source === source && edge.target === target + ) + if (foundEdge) { + console.log('通过解析dynamicId找到边:', foundEdge) + return foundEdge + } + } // 最后尝试通过source->target格式匹配 - const [source, target] = state.selectedEdge.split('->') - if (source && target) { + const arrowPattern = /^(.+)->(.+)$/ + const arrowMatch = state.selectedEdge.match(arrowPattern) + if (arrowMatch) { + const [, source, target] = arrowMatch foundEdge = state.rawGraph.edges.find(edge => edge.source === source.trim() && edge.target === target.trim() ) + if (foundEdge) { + console.log('通过箭头格式找到边:', foundEdge) + return foundEdge + } } - return foundEdge || null + console.warn('未找到匹配的边数据,选中边ID:', state.selectedEdge) + return null }, // 检查图是否为空