Compare commits
2 Commits
f9eb3e9646
...
59eebb5736
| Author | SHA1 | Date | |
|---|---|---|---|
| 59eebb5736 | |||
| 1adaa38893 |
@ -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>
|
||||||
|
|||||||
@ -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">
|
||||||
|
|||||||
Reference in New Issue
Block a user