Compare commits

2 Commits

2 changed files with 124 additions and 15 deletions

View File

@ -64,24 +64,34 @@
v-for="item in currentList" v-for="item in currentList"
:key="item.id" :key="item.id"
class="location-item" class="location-item"
@click="handleSelect(item)" :class="{ 'is-selected': item.full_path === modelValue }"
> >
<div class="item-left"> <!-- 左侧热区点击进入下级或选中 -->
<el-icon><Location /></el-icon> <div
class="item-main"
:class="{ 'has-children': item.children && item.children.length > 0 }"
@click="handleItemClick(item)"
>
<el-icon class="item-icon"><Location /></el-icon>
<span class="item-name">{{ item.name }}</span> <span class="item-name">{{ item.name }}</span>
<el-icon v-if="item.children && item.children.length > 0" class="item-arrow">
<ArrowRight />
</el-icon>
</div> </div>
<div class="item-right"> <!-- 右侧操作区 -->
<div class="item-actions">
<el-tag v-if="!item.children || item.children.length === 0" type="info" size="small">
末级
</el-tag>
<el-button <el-button
v-if="item.children && item.children.length > 0" v-else
type="primary" type="primary"
link
size="small" size="small"
@click.stop="handleDrillDown(item)" @click.stop="handleDrillDown(item)"
> >
进入下级 进入下级
<el-icon><ArrowRight /></el-icon> <el-icon><ArrowRight /></el-icon>
</el-button> </el-button>
<el-tag v-else type="info" size="small">末级</el-tag>
</div> </div>
</li> </li>
</ul> </ul>
@ -136,6 +146,55 @@ const currentList = computed(() => {
return lastNode?.children || [] return lastNode?.children || []
}) })
// 监听弹窗显示状态,恢复选中层级
watch(popoverVisible, (visible) => {
if (visible) {
restoreSelection()
}
})
// 根据 modelValue 恢复选择状态
const restoreSelection = () => {
if (!props.modelValue) {
// 无选中值,重置到顶层
currentPath.value = []
return
}
// 根据 full_path 查找父级路径
const path = findPathByFullPath(props.options, props.modelValue)
if (path) {
// 找到路径:还原 currentPath不包含最后一个节点因为它是当前选中的节点
currentPath.value = path
} else {
// 未找到(可能树结构已变化),重置到顶层
currentPath.value = []
}
}
// 根据 full_path 在树中查找从根到目标节点的路径
const findPathByFullPath = (
tree: WarehouseItem[],
targetFullPath: string,
currentPath: WarehouseItem[] = []
): WarehouseItem[] | null => {
for (const node of tree) {
// 检查当前节点是否匹配
if (node.full_path === targetFullPath) {
return currentPath
}
// 递归检查子节点
if (node.children && node.children.length > 0) {
const result = findPathByFullPath(node.children, targetFullPath, [...currentPath, node])
if (result) {
return result
}
}
}
return null
}
// 处理弹窗显示/隐藏 // 处理弹窗显示/隐藏
const handleVisibleChange = (visible: boolean) => { const handleVisibleChange = (visible: boolean) => {
popoverVisible.value = visible popoverVisible.value = visible
@ -173,6 +232,17 @@ const handleDrillDown = (item: WarehouseItem) => {
currentPath.value.push(item) currentPath.value.push(item)
} }
// 点击列表项 - 左侧热区逻辑
const handleItemClick = (item: WarehouseItem) => {
if (item.children && item.children.length > 0) {
// 有子节点:进入下一级
handleDrillDown(item)
} else {
// 末级:直接选中
handleSelect(item)
}
}
// 选择当前项 // 选择当前项
const handleSelect = (item: WarehouseItem) => { const handleSelect = (item: WarehouseItem) => {
emit('update:modelValue', item.full_path) emit('update:modelValue', item.full_path)
@ -234,7 +304,7 @@ const handleSelect = (item: WarehouseItem) => {
} }
.selector-body { .selector-body {
max-height: 300px; max-height: 320px;
overflow-y: auto; overflow-y: auto;
} }
@ -254,33 +324,72 @@ const handleSelect = (item: WarehouseItem) => {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 12px 16px; border-bottom: 1px solid #f0f0f0;
cursor: pointer;
transition: background 0.2s; transition: background 0.2s;
} }
.location-item:last-child {
border-bottom: none;
}
.location-item:hover { .location-item:hover {
background: #f5f7fa; background: #f5f7fa;
} }
.item-left { /* 选中高亮样式 */
.location-item.is-selected {
background: rgba(64, 158, 255, 0.1);
}
.location-item.is-selected .item-name {
color: #409eff;
font-weight: 500;
}
/* 左侧主热区 - 占80%宽度 */
.item-main {
flex: 1;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
padding: 14px 12px;
cursor: pointer;
min-width: 0;
} }
.item-left .el-icon { .item-main.has-children {
cursor: pointer;
}
.item-main:hover {
background: rgba(64, 158, 255, 0.08);
}
.item-icon {
color: #409eff; color: #409eff;
flex-shrink: 0;
} }
.item-name { .item-name {
font-size: 14px; font-size: 14px;
color: #303133; color: #303133;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} }
.item-right { .item-arrow {
color: #c0c4cc;
font-size: 12px;
flex-shrink: 0;
}
/* 右侧操作区 */
.item-actions {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; padding-right: 12px;
flex-shrink: 0;
} }
</style> </style>

View File

@ -78,7 +78,7 @@
node-key="id" node-key="id"
:props="treeProps" :props="treeProps"
:expand-on-click-node="false" :expand-on-click-node="false"
:default-expand-all="true" :default-expand-all="false"
> >
<template #default="{ node, data }"> <template #default="{ node, data }">
<div class="tree-node"> <div class="tree-node">