171 lines
3.4 KiB
Vue
171 lines
3.4 KiB
Vue
<script lang="ts" setup>
|
|
import type { NavMenuItem } from '@/components/nav-menu/type'
|
|
import { Search } from '@element-plus/icons-vue'
|
|
import { computed, nextTick, ref, watch } from 'vue'
|
|
import { useRoute } from 'vue-router'
|
|
import NavMenu from '@/components/nav-menu/index.vue'
|
|
|
|
const searchKey = ref('')
|
|
const route = useRoute()
|
|
|
|
const menuRef = ref()
|
|
|
|
const menuList: NavMenuItem [] = [
|
|
{
|
|
label: '资料设置',
|
|
index: '/settings/info',
|
|
icon: 'hugeicons:setting-07',
|
|
children: [
|
|
{
|
|
label: '公司信息设置',
|
|
index: '/settings/info/company',
|
|
icon: 'hugeicons:building-02',
|
|
},
|
|
{
|
|
label: '成员设置',
|
|
index: '/settings/info/company-user',
|
|
icon: 'hugeicons:user-settings-01',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
label: '创作者中心',
|
|
index: '/settings/forum',
|
|
icon: 'hugeicons:edit-01',
|
|
children: [
|
|
{
|
|
label: '首页',
|
|
index: '/settings/forum/home',
|
|
icon: 'hugeicons:home-03',
|
|
},
|
|
{
|
|
label: '写文章',
|
|
index: '/settings/forum/editor',
|
|
icon: 'hugeicons:edit-04',
|
|
},
|
|
{
|
|
label: '帖子管理',
|
|
index: '/settings/forum/post',
|
|
icon: 'hugeicons:material-and-texture',
|
|
},
|
|
],
|
|
},
|
|
]
|
|
|
|
/**
|
|
* 递归过滤菜单
|
|
*/
|
|
function filterMenu(
|
|
list: NavMenuItem[],
|
|
keyword: string,
|
|
): NavMenuItem[] {
|
|
if (!keyword)
|
|
return list
|
|
|
|
return list
|
|
.map((item) => {
|
|
const hitSelf = item.label.includes(keyword)
|
|
|
|
// 递归检查子节点是否命中(但不裁剪 children)
|
|
const hitChildren = item.children
|
|
? filterMenu(item.children, keyword).length > 0
|
|
: false
|
|
|
|
// 自己命中 或 任一子节点命中 → 保留整个节点
|
|
if (hitSelf || hitChildren) {
|
|
return item
|
|
}
|
|
|
|
return null
|
|
})
|
|
.filter(Boolean) as NavMenuItem[]
|
|
}
|
|
|
|
const filteredMenu = computed(() =>
|
|
filterMenu(menuList, searchKey.value.trim()),
|
|
)
|
|
function collectOpeneds(menu: NavMenuItem[], result: string[] = []) {
|
|
for (const item of menu) {
|
|
if (item.children?.length) {
|
|
result.push(item.index)
|
|
collectOpeneds(item.children, result)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
watch(searchKey, async (val) => {
|
|
await nextTick()
|
|
|
|
if (!menuRef.value)
|
|
return
|
|
|
|
if (val) {
|
|
const openeds = collectOpeneds(filteredMenu.value)
|
|
openeds.forEach((index) => {
|
|
menuRef.value!.open(index)
|
|
})
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="settings-wrapper">
|
|
<div class="left-menu">
|
|
<el-input
|
|
v-model="searchKey"
|
|
placeholder="搜索菜单"
|
|
size="large"
|
|
:prefix-icon="Search"
|
|
clearable
|
|
/>
|
|
|
|
<el-menu
|
|
ref="menuRef"
|
|
router
|
|
:default-active="route.path"
|
|
>
|
|
<NavMenu :menu="filteredMenu" />
|
|
</el-menu>
|
|
</div>
|
|
|
|
<div class="right-view">
|
|
<router-view />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.settings-wrapper {
|
|
display: flex;
|
|
gap: 40px;
|
|
margin-top: 30px;
|
|
padding: 0px 240px;
|
|
height: 800px;
|
|
|
|
.left-menu {
|
|
font-size: 16px;
|
|
overflow-y: auto;
|
|
width: 240px;
|
|
height: 100%;
|
|
background-color: #fff;
|
|
flex-shrink: 0;
|
|
:deep(.el-input__wrapper) {
|
|
margin: 12px 12px 4px 12px;
|
|
}
|
|
|
|
:deep(.el-menu) {
|
|
border-right: none;
|
|
}
|
|
}
|
|
|
|
.right-view {
|
|
width: 1200px;
|
|
flex-shrink: 0;
|
|
overflow-y: auto;
|
|
background-color: #fff;
|
|
border-radius: 4px;
|
|
}
|
|
}
|
|
</style>
|