fix(知识图谱): 修复边点击不显示问题并优化面板布局

改进边数据查找逻辑,增加多种ID格式匹配方式
调整边面板位置逻辑,避免与节点面板重叠
增加边点击容差和悬停容差,提升交互体验
添加调试日志和错误处理,便于问题排查
This commit is contained in:
Wenjie Zhang 2025-08-26 22:20:23 +08:00
parent 7fc1673d11
commit 921c8d6640
4 changed files with 109 additions and 21 deletions

View File

@ -5,8 +5,8 @@
- [ ] 添加对于上传文件的支持这里的复杂的地方就在于如何和历史记录结合在一起v0.2.3 版本实现,放在记忆管理后面)
🐛**BUGs**
- [ ] LlightRAG 知识库中,点击边,没有显示,但是在全屏的时候却又能够显示出来。
- [x] LlightRAG 知识库中,点击边,没有显示,但是在全屏的时候却又能够显示出来。
💯 **More**:
下面的功能**可能**会放在后续版本实现,暂时未定

View File

@ -136,7 +136,7 @@
<div
v-if="selectedEdgeData"
class="detail-panel edge-panel"
:style="{ transform: `translate(${edgePanelPosition.x}px, ${edgePanelPosition.y}px)` }"
:style="{ transform: `translate(${intelligentEdgePanelPosition.x}px, ${intelligentEdgePanelPosition.y}px)` }"
@mousedown="startDragPanel('edge', $event)"
>
<div class="detail-header">
@ -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)
// - 使SigmaID
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) {

View File

@ -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);
}
}
}

View File

@ -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
},
// 检查图是否为空