mirror of
https://github.com/chansee97/nova-admin.git
synced 2025-04-05 19:41:59 +08:00
feat(menu): 修改菜单高亮自动更新
This commit is contained in:
parent
e4dc741844
commit
8a24e76d00
@ -5,79 +5,6 @@ const Random = Mock.Random;
|
||||
|
||||
const token = Random.string('upper', 32, 32);
|
||||
|
||||
const routeData = {
|
||||
admin: [
|
||||
{
|
||||
name: 'dashboard',
|
||||
path: '/dashboard',
|
||||
meta: {
|
||||
title: '分析页',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-park-outline:analysis',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'dashboard_workbench',
|
||||
path: '/dashboard/workbench',
|
||||
meta: {
|
||||
title: '工作台',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-park-outline:alarm',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'dashboard_monitor',
|
||||
path: '/dashboard/monitor',
|
||||
meta: {
|
||||
title: '监控页',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-park-outline:anchor',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'test',
|
||||
path: '/test',
|
||||
meta: {
|
||||
title: '测试专题',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-park-outline:ambulance',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'test1',
|
||||
path: '/test/test1',
|
||||
meta: {
|
||||
title: '测试专题1',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-park-outline:alarm',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'test2',
|
||||
path: '/test/test2',
|
||||
meta: {
|
||||
title: '测试专题2',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-park-outline:pic',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'test3',
|
||||
path: '/test/test3',
|
||||
meta: {
|
||||
title: '测试专题3',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-park-outline:tool',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
user: [],
|
||||
};
|
||||
|
||||
const userInfo = {
|
||||
userId: '1',
|
||||
userName: 'admin',
|
||||
@ -144,6 +71,19 @@ const userRoutes = [
|
||||
requiresAuth: true,
|
||||
icon: 'icon-park-outline:pic',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'test2_detail',
|
||||
path: '/test/test2/detail',
|
||||
meta: {
|
||||
title: '测试专题2的详情页',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-park-outline:tool',
|
||||
hide: true,
|
||||
activeMenu: '/test/test2',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'test3',
|
||||
@ -153,6 +93,17 @@ const userRoutes = [
|
||||
requiresAuth: true,
|
||||
icon: 'icon-park-outline:tool',
|
||||
},
|
||||
children: [
|
||||
{
|
||||
name: 'test4',
|
||||
path: '/test/test3/test4',
|
||||
meta: {
|
||||
title: '测试专题4',
|
||||
requiresAuth: true,
|
||||
icon: 'icon-park-outline:tool',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -10,9 +10,12 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useRouteStore } from '~/src/store';
|
||||
|
||||
const router = useRouter();
|
||||
const routeStore = useRouteStore();
|
||||
const routes = computed(() => {
|
||||
// return routeStore.createBreadcrumbInRoutes(router.currentRoute.value.name, routeStore.userRoutes);
|
||||
return router.currentRoute.value.matched.filter((item) => {
|
||||
return item.meta.title;
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="h-60px text-2xl flex-center overflow-hidden">
|
||||
<div class="h-60px text-2xl flex-center overflow-hidden cursor-pointer" @click="pushHome">
|
||||
<SvgIcon name="logo" :size="28" />
|
||||
<span v-show="!appStore.collapsed" class="mx-4">{{ appStore.title }}</span>
|
||||
</div>
|
||||
@ -7,7 +7,12 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useAppStore } from '@/store';
|
||||
import { useAppRouter } from '@/hook';
|
||||
const appStore = useAppStore();
|
||||
const { routerPush } = useAppRouter();
|
||||
const pushHome = () => {
|
||||
routerPush('/');
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
@ -5,6 +5,7 @@
|
||||
:collapsed-icon-size="24"
|
||||
:indent="20"
|
||||
:options="routesStore.menus"
|
||||
:value="routesStore.activeMenu"
|
||||
@update:value="handleClickMenu"
|
||||
/>
|
||||
</template>
|
||||
@ -13,12 +14,13 @@
|
||||
import { useAppStore } from '@/store';
|
||||
import { useAppRouter } from '@/hook';
|
||||
import { useRouteStore } from '~/src/store/modules/route';
|
||||
import type { MenuOption } from 'naive-ui';
|
||||
|
||||
const { routerPush } = useAppRouter();
|
||||
const appStore = useAppStore();
|
||||
const routesStore = useRouteStore();
|
||||
|
||||
const handleClickMenu = (key: string) => {
|
||||
const handleClickMenu = (key: string, item: MenuOption) => {
|
||||
routerPush(key);
|
||||
};
|
||||
</script>
|
||||
|
@ -37,6 +37,10 @@ export async function createDynamicRoutes(routes: AppRoute.Route[]) {
|
||||
name: 'appRoot',
|
||||
redirect: '/dashboard/workbench',
|
||||
component: BasicLayout,
|
||||
meta: {
|
||||
title: '首页',
|
||||
icon: 'icon-park-outline:home',
|
||||
},
|
||||
children: [],
|
||||
};
|
||||
// 根据角色过滤后的插入根路由中
|
||||
|
@ -13,7 +13,7 @@ export function setupRouterGuard(router: Router) {
|
||||
});
|
||||
router.afterEach((to) => {
|
||||
// 修改网页标题
|
||||
document.title = `${to.meta.title}——${appTitle}`;
|
||||
document.title = `${to.meta.title} — ${appTitle}`;
|
||||
// 结束 loadingBar
|
||||
window.$loadingBar?.finish();
|
||||
});
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { RouteLocationNormalized, NavigationGuardNext } from 'vue-router';
|
||||
import { getToken } from '@/utils/auth';
|
||||
import { useRouteStore } from '@/store';
|
||||
// import { setDynamicRoutes } from './dynamic';
|
||||
|
||||
export async function createPermissionGuard(
|
||||
to: RouteLocationNormalized,
|
||||
@ -26,7 +25,6 @@ export async function createPermissionGuard(
|
||||
return false;
|
||||
}
|
||||
// 有登录但是没有路由,初始化路由、侧边菜单等
|
||||
// await setDynamicRoutes();
|
||||
await routeStore.initAuthRoute();
|
||||
// 动态路由加载完回到根路由
|
||||
next({ name: 'root' });
|
||||
@ -37,6 +35,12 @@ export async function createPermissionGuard(
|
||||
// next({ name: 'not-found-page', replace: true });
|
||||
// }
|
||||
|
||||
// next({ name: 'root' });
|
||||
// 设置菜单高亮
|
||||
if (to.meta.activeMenu) {
|
||||
routeStore.setActiveMenu(to.meta.activeMenu);
|
||||
} else {
|
||||
routeStore.setActiveMenu(to.fullPath);
|
||||
}
|
||||
|
||||
next();
|
||||
}
|
||||
|
@ -8,7 +8,8 @@ import { fetchUserRoutes } from '@/service';
|
||||
interface RoutesStatus {
|
||||
isInitAuthRoute: boolean;
|
||||
menus: any;
|
||||
userRoutes: any;
|
||||
userRoutes: AppRoute.Route[];
|
||||
activeMenu: string | null;
|
||||
}
|
||||
export const useRouteStore = defineStore('route-store', {
|
||||
state: (): RoutesStatus => {
|
||||
@ -16,6 +17,7 @@ export const useRouteStore = defineStore('route-store', {
|
||||
userRoutes: [],
|
||||
isInitAuthRoute: false,
|
||||
menus: [],
|
||||
activeMenu: null,
|
||||
};
|
||||
},
|
||||
actions: {
|
||||
@ -27,10 +29,38 @@ export const useRouteStore = defineStore('route-store', {
|
||||
/* 删除后面添加的路由 */
|
||||
router.removeRoute('appRoot');
|
||||
},
|
||||
/* 根据当前路由的name生成面包屑数据 */
|
||||
createBreadcrumbInRoutes(name = '/', userRoutes: AppRoute.Route[]) {
|
||||
return userRoutes.filter((item) => {
|
||||
if (item.name === name) {
|
||||
return true;
|
||||
}
|
||||
if (item.children) {
|
||||
return this.hasNameInBreadcrumbsChildren(name, item.children);
|
||||
}
|
||||
});
|
||||
},
|
||||
/* 判断子路由中是否存在为name的路由 */
|
||||
hasNameInBreadcrumbsChildren(name: string, userRoutes: AppRoute.Route[]): boolean {
|
||||
return userRoutes.some((item) => {
|
||||
if (item.name === name) {
|
||||
return true;
|
||||
}
|
||||
if (item.children) {
|
||||
return this.hasNameInBreadcrumbsChildren(name, item.children);
|
||||
}
|
||||
});
|
||||
},
|
||||
/* 设置当前高亮的菜单key */
|
||||
setActiveMenu(key: string) {
|
||||
this.activeMenu = key;
|
||||
},
|
||||
/* 生成侧边菜单的数据 */
|
||||
createMenus(userRoutes: AppRoute.Route[]) {
|
||||
this.userRoutes = userRoutes;
|
||||
this.menus = this.transformAuthRoutesToMenus(userRoutes);
|
||||
},
|
||||
/* 初始化动态路由 */
|
||||
async initDynamicRoute() {
|
||||
// 根据用户id来获取用户的路由
|
||||
const { userId } = getUserInfo();
|
||||
@ -42,26 +72,34 @@ export const useRouteStore = defineStore('route-store', {
|
||||
// 插入路由表
|
||||
router.addRoute(appRoutes);
|
||||
},
|
||||
// 将返回的路由表渲染成侧边栏
|
||||
//* 将返回的路由表渲染成侧边栏 */
|
||||
transformAuthRoutesToMenus(userRoutes: AppRoute.Route[]): MenuOption[] {
|
||||
return userRoutes.map((item) => {
|
||||
const target: MenuOption = {
|
||||
label: item.meta.title,
|
||||
key: item.path,
|
||||
};
|
||||
// 判断有无图标
|
||||
if (item.meta.icon) {
|
||||
target.icon = renderIcon(item.meta.icon);
|
||||
}
|
||||
// 判断子元素
|
||||
if (item.children) {
|
||||
target.children = this.transformAuthRoutesToMenus(item.children);
|
||||
}
|
||||
return target;
|
||||
});
|
||||
return userRoutes
|
||||
.filter((item) => {
|
||||
return !item.meta.hide;
|
||||
})
|
||||
.map((item) => {
|
||||
const target: MenuOption = {
|
||||
label: item.meta.title,
|
||||
key: item.path,
|
||||
};
|
||||
// 判断有无图标
|
||||
if (item.meta.icon) {
|
||||
target.icon = renderIcon(item.meta.icon);
|
||||
}
|
||||
// 判断子元素
|
||||
if (item.children) {
|
||||
const children = this.transformAuthRoutesToMenus(item.children);
|
||||
// 只有子元素有且不为空时才添加
|
||||
if (children.length !== 0) {
|
||||
target.children = children;
|
||||
}
|
||||
}
|
||||
return target;
|
||||
});
|
||||
},
|
||||
|
||||
async initAuthRoute() {
|
||||
this.isInitAuthRoute = false;
|
||||
await this.initDynamicRoute();
|
||||
this.isInitAuthRoute = true;
|
||||
},
|
||||
|
8
src/types/business.d.ts
vendored
8
src/types/business.d.ts
vendored
@ -7,7 +7,6 @@ declare namespace Auth {
|
||||
* - user: 用户
|
||||
* - custom: 自定义角色
|
||||
*/
|
||||
// type RoleType = keyof typeof import('@/enum').EnumUserRole;
|
||||
|
||||
/** 用户信息 */
|
||||
interface loginToken {
|
||||
@ -28,11 +27,4 @@ declare namespace Auth {
|
||||
/* 密码 */
|
||||
password: string;
|
||||
}
|
||||
// interface userRoutes {
|
||||
// name: string;
|
||||
// path: string;
|
||||
// meta: AppRoute.RouteMeta;
|
||||
// children?: userRoutes[];
|
||||
// redirect: string;
|
||||
// }
|
||||
}
|
||||
|
7
src/views/test/test2/detail/index.vue
Normal file
7
src/views/test/test2/detail/index.vue
Normal file
@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<div text-center c-yellow>I prove that you have made the ju mp test2-deail.</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style scoped></style>
|
14
src/views/test/test3/test4/index.vue
Normal file
14
src/views/test/test3/test4/index.vue
Normal file
@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<div text-center c-red>
|
||||
I prove that you have made the jump test4.
|
||||
<n-button strong secondary type="success" @click="testMsg">testMsg</n-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const testMsg = () => {
|
||||
window.$message.error('Once upon a time you dressed so fine');
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
Loading…
x
Reference in New Issue
Block a user