263 lines
6.7 KiB
Vue
263 lines
6.7 KiB
Vue
<template>
|
|
<div ref="sideMenu" class="side-menu">
|
|
<div
|
|
v-for="(item, index) in menuItems"
|
|
:key="index"
|
|
:ref="(el) => setMenuItemRef(el, index)"
|
|
class="menu-item"
|
|
@mouseenter="showSubMenu(index)"
|
|
@mouseleave="hideSubMenu"
|
|
>
|
|
<!-- @click="handleSubmenuClick(item)" -->
|
|
{{ item.name }}
|
|
<!-- 悬浮浮窗 -->
|
|
<div v-if="activeIndex === index" class="submenu-panel" :style="{ top: submenuTop + 'px' }" @mouseenter="keepSubmenuVisible" @mouseleave="hideSubMenu">
|
|
<div class="submenu-content">
|
|
<!-- <div class="text-right">更多</div> -->
|
|
<div class="submenu-group">
|
|
<template v-for="group in item.children" :key="group.id">
|
|
<div class="submenu-group-title" @click.stop="handleSubmenuClick(group)">{{ group.name }}</div>
|
|
<div class="submenu-group-items">
|
|
<div v-for="sub in group.children" :key="sub.id" class="submenu-item" @click.stop="handleSubmenuClick(group, sub)">
|
|
{{ sub.name }}
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, onMounted } from 'vue'
|
|
import type { ComponentPublicInstance } from 'vue'
|
|
import { tab2 } from '~/api/home/index'
|
|
import type { ProjectDictNodeVO } from '~/api/home/type'
|
|
|
|
const activeIndex = ref(-1)
|
|
const submenuTop = ref(0)
|
|
// const submenuLeft = ref(0)
|
|
const sideMenu = ref()
|
|
const menuItemRefs = ref<HTMLElement[]>([])
|
|
|
|
const showSubMenu = (index: number) => {
|
|
// if (menuItems.value.length === index + 1) {
|
|
// return
|
|
// }
|
|
activeIndex.value = index
|
|
const dom = menuItemRefs.value[index].getBoundingClientRect()
|
|
console.log(dom)
|
|
// submenuTop.value = window.scrollY
|
|
}
|
|
|
|
const hideSubMenu = () => {
|
|
activeIndex.value = -1
|
|
}
|
|
|
|
const handleSubmenuClick = (primary?: ProjectDictNodeVO, secondary?: ProjectDictNodeVO, tertiary?: ProjectDictNodeVO) => {
|
|
const normal = { id: '0', name: '图纸库', isChildren: false }
|
|
const level = [primary, secondary, tertiary]
|
|
.filter(Boolean)
|
|
.map((item) => ({ id: item?.id, name: item?.name, isChildren: item?.children?.length ? false : true }))
|
|
if (primary?.id === '0') {
|
|
level[0].name = '图纸库'
|
|
} else {
|
|
level.unshift(normal)
|
|
}
|
|
|
|
navigateTo(`/drawe?level=${JSON.stringify(level)}`)
|
|
}
|
|
|
|
const keepSubmenuVisible = () => {
|
|
// activeIndex.value = activeIndex.value // 保持当前索引
|
|
}
|
|
|
|
const setMenuItemRef = (el: Element | ComponentPublicInstance | null, index: number) => {
|
|
if (el && 'offsetTop' in el) {
|
|
menuItemRefs.value[index] = el as HTMLElement
|
|
}
|
|
}
|
|
|
|
const menuItems = ref<ProjectDictNodeVO[]>([])
|
|
const getLabel = () => {
|
|
tab2().then((res) => {
|
|
const arr = []
|
|
for (let i = 0; i < res.data.length; i += 2) {
|
|
arr.push({
|
|
children: res.data.slice(i, i + 2),
|
|
name: getName(res.data.slice(i, i + 2)),
|
|
})
|
|
}
|
|
menuItems.value = arr
|
|
})
|
|
}
|
|
|
|
const getName = (arr: any[]) => {
|
|
if (arr.length === 1) {
|
|
return arr[0].name
|
|
} else {
|
|
return arr[0].name + ' / ' + arr[1].name
|
|
}
|
|
}
|
|
|
|
const init = () => {
|
|
// 获取标签
|
|
getLabel()
|
|
}
|
|
|
|
onMounted(() => {
|
|
init()
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.side-menu {
|
|
width: 221px;
|
|
background-color: #fff;
|
|
/* padding: 10px 0; */
|
|
/* box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); */
|
|
/* overflow: visible; */
|
|
box-sizing: border-box;
|
|
position: relative; /* 添加定位上下文 */
|
|
/* overflow-y: auto; */
|
|
/* 隐藏滚动条 */
|
|
scrollbar-width: none; /* Firefox */
|
|
-ms-overflow-style: none; /* IE and Edge */
|
|
z-index: 9;
|
|
/* padding-top: 10px; */
|
|
}
|
|
|
|
/* 隐藏 Webkit 浏览器的滚动条 */
|
|
.side-menu::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
|
|
/* 鼠标悬停时显示滚动条 */
|
|
.side-menu:hover {
|
|
scrollbar-width: none; /* Firefox */
|
|
-ms-overflow-style: none; /* IE and Edge */
|
|
}
|
|
|
|
/* .side-menu:hover::-webkit-scrollbar {
|
|
display: block;
|
|
width: 8px !important;
|
|
}
|
|
|
|
.side-menu:hover::-webkit-scrollbar-thumb {
|
|
background-color: #e6e8eb;
|
|
border-radius: 6px !important;
|
|
}
|
|
|
|
.side-menu:hover::-webkit-scrollbar-track {
|
|
background-color: #fff;
|
|
} */
|
|
|
|
.menu-item {
|
|
/* position: relative; */
|
|
text-align: center;
|
|
padding: 4px 24px;
|
|
cursor: pointer;
|
|
/* transition: all 0.3s ease; */
|
|
color: #333;
|
|
font-size: 14px;
|
|
border: 1px solid transparent;
|
|
z-index: 9;
|
|
}
|
|
|
|
.menu-item:hover {
|
|
background-color: #fff;
|
|
color: #1890ff;
|
|
border: 1px solid #1890ff;
|
|
border-right: transparent !important;
|
|
}
|
|
|
|
.submenu-panel {
|
|
position: absolute;
|
|
left: 220px;
|
|
top: 0;
|
|
width: 957px;
|
|
background: #fff;
|
|
/* box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); */
|
|
border: 1px solid #1890ff;
|
|
/* border-radius: 4px; */
|
|
display: flex;
|
|
padding: 20px;
|
|
z-index: -1;
|
|
box-sizing: border-box;
|
|
min-height: 480px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.submenu-panel::before {
|
|
/* content: '';
|
|
position: absolute;
|
|
left: -6px;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
width: 0;
|
|
height: 0;
|
|
border-top: 8px solid transparent;
|
|
border-bottom: 8px solid transparent;
|
|
border-right: 8px solid #fff;
|
|
filter: drop-shadow(-2px 0 2px rgba(0, 0, 0, 0.1)); */
|
|
}
|
|
|
|
.submenu-content {
|
|
/* flex: 1; */
|
|
/* display: grid; */
|
|
/* grid-template-columns: repeat(3, 1fr); */
|
|
/* gap: 15px; */
|
|
width: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
.submenu-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
flex-wrap: wrap;
|
|
-webkit-column-break-inside: avoid; /* 兼容webkit内核 */
|
|
/* border: 1px solid #e6e8eb; */
|
|
.submenu-group-title {
|
|
font-size: 15px;
|
|
/* font-weight: 700; */
|
|
padding: 10px 16px;
|
|
color: #000;
|
|
font-weight: 600;
|
|
transition: all 0.2s;
|
|
/* border-bottom: 1px solid #e6e8eb; */
|
|
}
|
|
.submenu-group-title:hover {
|
|
color: #1890ff;
|
|
/* border-bottom: 1px solid #e6e8eb; */
|
|
}
|
|
.submenu-group-items {
|
|
display: flex !important;
|
|
flex-direction: row;
|
|
align-items: flex-start;
|
|
flex-wrap: wrap;
|
|
color: #666;
|
|
padding: 0px 16px;
|
|
gap: 10px;
|
|
.submenu-item {
|
|
cursor: pointer;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.submenu-item {
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
display: inline-block; /* 改为行内块元素 */
|
|
/* padding: 8px 12px; */
|
|
padding-right: 12px;
|
|
/* padding-bottom: 8px; */
|
|
}
|
|
|
|
.submenu-item:hover {
|
|
color: #1890ff;
|
|
}
|
|
</style>
|