@ -64,24 +64,34 @@
v-for = "item in currentList"
:key = "item.id"
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 >
< el-icon v-if = "item.children && item.children.length > 0" class="item-arrow" >
< ArrowRight / >
< / el-icon >
< / 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
v-if = "item.children && item.children.length > 0"
v-else
type = "primary"
link
size = "small"
@click.stop ="handleDrillDown(item)"
>
进入下级
< el-icon > < ArrowRight / > < / el-icon >
< / el-button >
< el-tag v-else type = "info" size = "small" > 末级 < / el-tag >
< / div >
< / li >
< / ul >
@ -136,6 +146,55 @@ const currentList = computed(() => {
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 ) => {
popoverVisible . value = visible
@ -173,6 +232,17 @@ const handleDrillDown = (item: WarehouseItem) => {
currentPath . value . push ( item )
}
// 点击列表项 - 左侧热区逻辑
const handleItemClick = ( item : WarehouseItem ) => {
if ( item . children && item . children . length > 0 ) {
// 有子节点:进入下一级
handleDrillDown ( item )
} else {
// 末级:直接选中
handleSelect ( item )
}
}
// 选择当前项
const handleSelect = ( item : WarehouseItem ) => {
emit ( 'update:modelValue' , item . full _path )
@ -234,7 +304,7 @@ const handleSelect = (item: WarehouseItem) => {
}
. selector - body {
max - height : 30 0 px ;
max - height : 32 0 px ;
overflow - y : auto ;
}
@ -254,33 +324,72 @@ const handleSelect = (item: WarehouseItem) => {
display : flex ;
align - items : center ;
justify - content : space - between ;
padding : 12 px 16 px ;
cursor : pointer ;
border - bottom : 1 px solid # f0f0f0 ;
transition : background 0.2 s ;
}
. location - item : last - child {
border - bottom : none ;
}
. location - item : hover {
background : # f5f7fa ;
}
. item - left {
/* 选中高亮样式 */
. location - item . is - selected {
background : rgba ( 64 , 158 , 255 , 0.1 ) ;
}
. location - item . is - selected . item - name {
color : # 409 eff ;
font - weight : 500 ;
}
/* 左侧主热区 - 占80%宽度 */
. item - main {
flex : 1 ;
display : flex ;
align - items : center ;
gap : 8 px ;
padding : 14 px 12 px ;
cursor : pointer ;
min - width : 0 ;
}
. item - left . el - ico n {
. item - main . has - childre n {
cursor : pointer ;
}
. item - main : hover {
background : rgba ( 64 , 158 , 255 , 0.08 ) ;
}
. item - icon {
color : # 409 eff ;
flex - shrink : 0 ;
}
. item - name {
font - size : 14 px ;
color : # 303133 ;
flex : 1 ;
overflow : hidden ;
text - overflow : ellipsis ;
white - space : nowrap ;
}
. item - right {
. item - arrow {
color : # c0c4cc ;
font - size : 12 px ;
flex - shrink : 0 ;
}
/* 右侧操作区 */
. item - actions {
display : flex ;
align - items : center ;
gap : 8 px ;
padding - right : 12 px ;
flex - shrink : 0 ;
}
< / style >