|
|
@@ -41,8 +41,17 @@ const formRules = ref({
|
|
|
const handleRightClick = (event, data, node) => {
|
|
|
nodeInfo.value = { ...data }
|
|
|
event.preventDefault()
|
|
|
- menuX.value = event.clientX
|
|
|
- menuY.value = event.clientY
|
|
|
+ const nodeContent = (event.target as HTMLElement)?.closest(
|
|
|
+ '.el-tree-node__content'
|
|
|
+ ) as HTMLElement | null
|
|
|
+ if (nodeContent) {
|
|
|
+ const rect = nodeContent.getBoundingClientRect()
|
|
|
+ menuX.value = rect.right + 8
|
|
|
+ menuY.value = rect.top
|
|
|
+ } else {
|
|
|
+ menuX.value = event.clientX
|
|
|
+ menuY.value = event.clientY
|
|
|
+ }
|
|
|
selectedNode = data
|
|
|
parentId.value = data.id
|
|
|
|
|
|
@@ -246,7 +255,24 @@ watch(
|
|
|
}
|
|
|
)
|
|
|
|
|
|
+const handleClickOutside = (event) => {
|
|
|
+ if (menuVisible.value && contextMenuRef.value && !contextMenuRef.value.contains(event.target)) {
|
|
|
+ menuVisible.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+watch(menuVisible, (visible) => {
|
|
|
+ if (visible) {
|
|
|
+ document.addEventListener('click', handleClickOutside)
|
|
|
+ } else {
|
|
|
+ document.removeEventListener('click', handleClickOutside)
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
onMounted(getTreeInfo)
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ document.removeEventListener('click', handleClickOutside)
|
|
|
+})
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
@@ -294,13 +320,9 @@ onMounted(getTreeInfo)
|
|
|
class="custom-menu"
|
|
|
:style="{ left: menuX + 'px', top: menuY + 'px' }">
|
|
|
<ul>
|
|
|
- <li style="border-bottom: 1px solid #ccc" @click="handleMenuClick('add')"
|
|
|
- >新建目录</li
|
|
|
- >
|
|
|
+ <li @click="handleMenuClick('add')">新建目录</li>
|
|
|
|
|
|
- <li style="border-bottom: 1px solid #ccc" @click="handleMenuClick('edit')"
|
|
|
- >编辑</li
|
|
|
- >
|
|
|
+ <li @click="handleMenuClick('edit')">编辑</li>
|
|
|
|
|
|
<li @click="handleMenuClick('delete')">删除目录</li>
|
|
|
</ul>
|
|
|
@@ -401,6 +423,41 @@ onMounted(getTreeInfo)
|
|
|
white-space: nowrap;
|
|
|
}
|
|
|
|
|
|
+.custom-menu {
|
|
|
+ position: fixed;
|
|
|
+ min-width: 144px;
|
|
|
+ padding: 6px;
|
|
|
+ background: #fff;
|
|
|
+ border: 1px solid rgb(15 23 42 / 8%);
|
|
|
+ border-radius: 10px;
|
|
|
+ box-shadow: 0 14px 30px rgb(15 23 42 / 16%);
|
|
|
+ z-index: 3000;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-menu ul {
|
|
|
+ list-style: none;
|
|
|
+ padding: 0;
|
|
|
+ margin: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-menu li {
|
|
|
+ padding: 8px 12px;
|
|
|
+ margin: 0;
|
|
|
+ font-size: 13px;
|
|
|
+ line-height: 1.2;
|
|
|
+ color: #334155;
|
|
|
+ cursor: pointer;
|
|
|
+ border-radius: 8px;
|
|
|
+ transition:
|
|
|
+ background-color 0.18s ease,
|
|
|
+ color 0.18s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-menu li:hover {
|
|
|
+ color: #1677ff;
|
|
|
+ background: #eff6ff;
|
|
|
+}
|
|
|
+
|
|
|
.collapse-handle {
|
|
|
position: absolute;
|
|
|
top: 50%;
|