mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-11-11 19:23:41 +08:00
feat(components): 添加面包屑
This commit is contained in:
@@ -9,8 +9,8 @@ interface RouteMeta {
|
||||
title?: string;
|
||||
/** 页面100%视高 */
|
||||
fullPage?: boolean;
|
||||
/** 作为菜单 */
|
||||
asMenu?: boolean;
|
||||
/** 不作为菜单 */
|
||||
isNotMenu?: boolean;
|
||||
/** 菜单和面包屑对应的图标 */
|
||||
icon?: Component;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<n-breadcrumb class="px-12px">
|
||||
<template v-for="breadcrumb in breadcrumbList" :key="breadcrumb.key">
|
||||
<n-breadcrumb-item>
|
||||
<n-dropdown v-if="breadcrumb.hasChildren" :options="breadcrumb.children" @select="dropdownSelect">
|
||||
<span>{{ breadcrumb.label }}</span>
|
||||
</n-dropdown>
|
||||
<span v-else>{{ breadcrumb.label }}</span>
|
||||
</n-breadcrumb-item>
|
||||
</template>
|
||||
</n-breadcrumb>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { NBreadcrumb, NBreadcrumbItem, NDropdown } from 'naive-ui';
|
||||
import type { DropdownOption } from 'naive-ui';
|
||||
import type { RouteLocationMatched } from 'vue-router';
|
||||
import { EnumRoutePath } from '@/enum';
|
||||
import type { RoutePathKey } from '@/interface';
|
||||
|
||||
type Breadcrumb = DropdownOption & {
|
||||
key: string;
|
||||
label: string;
|
||||
disabled: boolean;
|
||||
routeName: RoutePathKey;
|
||||
hasChildren: boolean;
|
||||
children?: Breadcrumb[];
|
||||
};
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const breadcrumbList = computed<Breadcrumb[]>(() => generateBreadcrumb());
|
||||
|
||||
function generateBreadcrumb() {
|
||||
const { matched } = route;
|
||||
return recursionBreadcrumb(matched);
|
||||
}
|
||||
|
||||
/** 递归匹配路由获取面包屑数据 */
|
||||
function recursionBreadcrumb(routeMatched: RouteLocationMatched[]) {
|
||||
return routeMatched.map(item => {
|
||||
const routeName = item.name as RoutePathKey;
|
||||
const breadcrumItem: Breadcrumb = {
|
||||
key: routeName,
|
||||
label: (item.meta?.title as string) || '',
|
||||
disabled: item.path === EnumRoutePath.root,
|
||||
routeName,
|
||||
hasChildren: false
|
||||
};
|
||||
if (item.children && item.children.length) {
|
||||
breadcrumItem.hasChildren = true;
|
||||
breadcrumItem.children = recursionBreadcrumb(item.children as RouteLocationMatched[]);
|
||||
}
|
||||
return breadcrumItem;
|
||||
});
|
||||
}
|
||||
|
||||
function dropdownSelect(optionKey: string) {
|
||||
const key = optionKey as RoutePathKey;
|
||||
router.push({ name: key });
|
||||
}
|
||||
</script>
|
||||
<style scoped></style>
|
||||
@@ -1,3 +1,4 @@
|
||||
import GlobalBreadcrumb from './GlobalBreadcrumb.vue';
|
||||
import UserAvatar from './UserAvatar.vue';
|
||||
import MenuCollapse from './MenuCollapse.vue';
|
||||
import FullScreen from './FullScreen.vue';
|
||||
@@ -5,4 +6,4 @@ import SettingDrawerButton from './SettingDrawerButton.vue';
|
||||
import GihubSite from './GihubSite.vue';
|
||||
import HeaderItem from './HeaderItem.vue';
|
||||
|
||||
export { UserAvatar, MenuCollapse, FullScreen, SettingDrawerButton, GihubSite, HeaderItem };
|
||||
export { GlobalBreadcrumb, UserAvatar, MenuCollapse, FullScreen, SettingDrawerButton, GihubSite, HeaderItem };
|
||||
|
||||
@@ -5,7 +5,10 @@
|
||||
<div v-if="!theme.isVerticalNav" class="menu-width h-full">
|
||||
<global-logo />
|
||||
</div>
|
||||
<menu-collapse />
|
||||
<div class="flex-y-center h-full">
|
||||
<menu-collapse />
|
||||
<global-breadcrumb v-if="theme.crumbsStyle.visible" />
|
||||
</div>
|
||||
<div class="flex-1 flex justify-end h-full">
|
||||
<gihub-site />
|
||||
<full-screen />
|
||||
@@ -20,7 +23,7 @@
|
||||
import { computed } from 'vue';
|
||||
import { NLayoutHeader } from 'naive-ui';
|
||||
import { useThemeStore } from '@/store';
|
||||
import { UserAvatar, MenuCollapse, FullScreen, GihubSite, SettingDrawerButton } from './components';
|
||||
import { GlobalBreadcrumb, UserAvatar, MenuCollapse, FullScreen, GihubSite, SettingDrawerButton } from './components';
|
||||
import { GlobalLogo } from '../common';
|
||||
|
||||
defineProps({
|
||||
|
||||
@@ -31,7 +31,7 @@ export function transformRouteToMenu(routes: CustomRoute[]) {
|
||||
|
||||
/** 判断路由是否作为菜单 */
|
||||
function asMenu(route: CustomRoute) {
|
||||
return Boolean(route.meta?.asMenu);
|
||||
return !route.meta?.isNotMenu;
|
||||
}
|
||||
|
||||
/** 给菜单添加可选属性 */
|
||||
|
||||
@@ -91,7 +91,7 @@ export const customRoutes: CustomRoute[] = [
|
||||
path: EnumRoutePath.root,
|
||||
redirect: { name: RouteNameMap.get('dashboard-analysis') },
|
||||
meta: {
|
||||
asMenu: false
|
||||
isNotMenu: true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -101,7 +101,6 @@ export const customRoutes: CustomRoute[] = [
|
||||
redirect: { name: RouteNameMap.get('dashboard-analysis') },
|
||||
meta: {
|
||||
title: EnumRouteTitle.dashboard,
|
||||
asMenu: true,
|
||||
icon: Dashboard
|
||||
},
|
||||
children: [
|
||||
@@ -110,8 +109,7 @@ export const customRoutes: CustomRoute[] = [
|
||||
path: EnumRoutePath['dashboard-analysis'],
|
||||
component: () => import('@/views/dashboard/analysis/index.vue'),
|
||||
meta: {
|
||||
title: EnumRouteTitle['dashboard-analysis'],
|
||||
asMenu: true
|
||||
title: EnumRouteTitle['dashboard-analysis']
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -119,8 +117,7 @@ export const customRoutes: CustomRoute[] = [
|
||||
path: EnumRoutePath['dashboard-workbench'],
|
||||
component: () => import('@/views/dashboard/workbench/index.vue'),
|
||||
meta: {
|
||||
title: EnumRouteTitle['dashboard-workbench'],
|
||||
asMenu: true
|
||||
title: EnumRouteTitle['dashboard-workbench']
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -131,7 +128,6 @@ export const customRoutes: CustomRoute[] = [
|
||||
component: BasicLayout,
|
||||
meta: {
|
||||
title: EnumRouteTitle.exception,
|
||||
asMenu: true,
|
||||
icon: ExceptionOutlined
|
||||
},
|
||||
children: [
|
||||
@@ -141,8 +137,7 @@ export const customRoutes: CustomRoute[] = [
|
||||
component: () => import('@/views/system/exception/403.vue'),
|
||||
meta: {
|
||||
title: EnumRouteTitle['exception-403'],
|
||||
fullPage: true,
|
||||
asMenu: true
|
||||
fullPage: true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -151,8 +146,7 @@ export const customRoutes: CustomRoute[] = [
|
||||
component: () => import('@/views/system/exception/404.vue'),
|
||||
meta: {
|
||||
title: EnumRouteTitle['exception-404'],
|
||||
fullPage: true,
|
||||
asMenu: true
|
||||
fullPage: true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -161,8 +155,7 @@ export const customRoutes: CustomRoute[] = [
|
||||
component: () => import('@/views/system/exception/500.vue'),
|
||||
meta: {
|
||||
title: EnumRouteTitle['exception-500'],
|
||||
fullPage: true,
|
||||
asMenu: true
|
||||
fullPage: true
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user