fix: 修复层级分析树形视图显示问题

- 修复父子关系判断逻辑,支持parent_id和path推断
- 改用路径优先排序,确保子组件紧跟父组件显示
- 添加多层级展开检查,确保所有祖先节点展开才显示
- 添加缩进显示层级关系

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
sladro 2025-09-21 08:54:24 +08:00
parent fe2276259d
commit c1cb907ab4

View File

@ -73,11 +73,26 @@
<h4>层级树状结构</h4>
</div>
<div class="tree-container">
<div v-for="component in hierarchyData" :key="component.id" v-show="component.level === 0 || expandedNodes.has(getParentId(component))" class="tree-node" :class="`safety-${component.deletion_safety}`">
<div class="node-header">
<div class="node-toggle" :class="{ expanded: expandedNodes.has(component.id) }" @click="toggleNode(component)">
<div
v-for="component in sortedHierarchyData"
:key="component.id"
v-show="shouldShowNode(component)"
class="tree-node"
:class="`safety-${component.deletion_safety}`"
>
<div class="node-header" :style="{ paddingLeft: (component.level * 20) + 'px' }">
<div
class="node-toggle"
:class="{
expanded: expandedNodes.has(component.id),
'has-children': hasChildren(component.id)
}"
@click="toggleNode(component)"
v-if="hasChildren(component.id)"
>
<i class="fas fa-chevron-right"></i>
</div>
<div v-else class="node-toggle-placeholder"></div>
<div class="node-icon">
<i class="fas fa-cube"></i>
</div>
@ -237,6 +252,7 @@ const hierarchyData = computed(() => {
})
const getSafetyLabel = (safety) => {
const labels = {
safe: '安全',
@ -246,13 +262,58 @@ const getSafetyLabel = (safety) => {
return labels[safety] || safety
}
//
const getParentId = (component) => {
// level-1
const parentLevel = component.level - 1
if (parentLevel < 0) return null
// parent_id 使
if (component.parent_id) return component.parent_id
const parent = hierarchyData.value.find(comp => comp.level === parentLevel)
return parent ? parent.id : null
// path
if (component.path) {
const pathParts = component.path.split('/')
if (pathParts.length > 1) {
const parentPath = pathParts.slice(0, -1).join('/')
const parent = hierarchyData.value.find(c => c.path === parentPath)
return parent ? parent.id : null
}
}
return null
}
//
const sortedHierarchyData = computed(() => {
return [...hierarchyData.value].sort((a, b) => {
//
const pathA = a.path || a.id || ''
const pathB = b.path || b.id || ''
return pathA.localeCompare(pathB)
})
})
//
const hasChildren = (nodeId) => {
return hierarchyData.value.some(comp => getParentId(comp) === nodeId)
}
//
const shouldShowNode = (component) => {
//
if (component.level === 0) return true
//
let current = component
while (current && current.level > 0) {
const parentId = getParentId(current)
if (!parentId) return false //
//
if (!expandedNodes.value.has(parentId)) return false
//
current = hierarchyData.value.find(c => c.id === parentId)
}
return true
}
const toggleNode = (component) => {
@ -571,6 +632,16 @@ const continueToDeleteConfig = () => {
transform: rotate(90deg);
}
.node-toggle-placeholder {
width: 20px;
height: 20px;
margin-right: var(--spacing-sm);
}
.node-toggle.has-children {
cursor: pointer;
}
.node-icon {
width: 24px;
height: 24px;