Files
workspace/code/link56/link56-frontend-new/src/views/settings/index.vue
T
2025-12-17 22:31:53 +08:00

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>