100 lines
2.8 KiB
Vue
100 lines
2.8 KiB
Vue
<template>
|
|
<template v-for="item in list" :key="item.path">
|
|
<template v-if="!item.children || !item.children.length || item.meta?.single">
|
|
<t-menu-item :name="item.path" :value="getPath(item)" :to="item.path">
|
|
<template #icon>
|
|
<component :is="menuIcon(item)" class="t-icon"></component>
|
|
</template>
|
|
{{ renderMenuTitle(item.title) }}
|
|
</t-menu-item>
|
|
</template>
|
|
<t-submenu v-else :name="item.path" :value="item.path" :title="renderMenuTitle(item.title)">
|
|
<template #icon>
|
|
<component :is="menuIcon(item)" class="t-icon"></component>
|
|
</template>
|
|
<menu-content v-if="item.children" :nav-data="item.children" />
|
|
</t-submenu>
|
|
</template>
|
|
</template>
|
|
<script setup lang="tsx">
|
|
import type { PropType } from 'vue';
|
|
import { computed } from 'vue';
|
|
|
|
import type { LocalizedTitle } from '@/locales';
|
|
import { useLocale } from '@/locales/useLocale';
|
|
import { getActive } from '@/router';
|
|
import type { MenuRoute } from '@/types/interface';
|
|
|
|
type ListItemType = MenuRoute;
|
|
|
|
const { navData } = defineProps({
|
|
navData: {
|
|
type: Array as PropType<MenuRoute[]>,
|
|
default: () => [],
|
|
},
|
|
});
|
|
|
|
const active = computed(() => getActive());
|
|
|
|
const { locale } = useLocale();
|
|
|
|
const list = computed(() => {
|
|
return getMenuList(navData);
|
|
});
|
|
|
|
const menuIcon = (item: ListItemType) => {
|
|
if (typeof item.icon === 'string') return <t-icon name={item.icon} />;
|
|
const RenderIcon = item.icon;
|
|
return RenderIcon;
|
|
};
|
|
|
|
const renderMenuTitle = (title?: LocalizedTitle) => {
|
|
if (!title) return '';
|
|
return title[locale.value as keyof LocalizedTitle] || '';
|
|
};
|
|
|
|
function getMenuList(list: MenuRoute[], basePath?: string): MenuRoute[] {
|
|
if (!list || list.length === 0) {
|
|
return [];
|
|
}
|
|
// 如果meta中有orderNo则按照从小到大排序
|
|
list.sort((a, b) => {
|
|
return (a.meta?.orderNo || 0) - (b.meta?.orderNo || 0);
|
|
});
|
|
return list
|
|
.map((item) => {
|
|
const path = !basePath
|
|
? item.path
|
|
: item.path === ''
|
|
? basePath
|
|
: item.path.startsWith('/')
|
|
? item.path
|
|
: `${basePath}/${item.path}`;
|
|
|
|
return {
|
|
path,
|
|
title: item.meta?.title as LocalizedTitle | undefined,
|
|
icon: item.meta?.icon,
|
|
children: getMenuList(item.children, path),
|
|
meta: item.meta,
|
|
redirect: item.redirect,
|
|
} as MenuRoute;
|
|
})
|
|
.filter((item) => item.meta && item.meta.hidden !== true);
|
|
}
|
|
|
|
const getPath = (item: ListItemType) => {
|
|
const activeLevel = active.value.split('/').length;
|
|
const pathLevel = item.path.split('/').length;
|
|
if (activeLevel > pathLevel && active.value.startsWith(item.path)) {
|
|
return active.value;
|
|
}
|
|
|
|
if (active.value === item.path) {
|
|
return active.value;
|
|
}
|
|
|
|
return item.meta?.single ? item.redirect || item.path : item.path;
|
|
};
|
|
</script>
|