使用vue-next-admin框架后台修改动态路由

vue-next-admin框架是一个基于 Vue 3 和 Vite 构建的后台管理系统框架。它采用了最新的前端技术栈,旨在提供一个高效、灵活、现代化的管理后台解决方案。该框架主要用于构建功能丰富且易于定制的管理后台应用,适合各种中大型项目。

其主要特点包括:

  1. Vue 3 和 Composition API:使用 Vue 3 的新特性,如 Composition API,提高了代码的可读性和可维护性。
  2. Vite 构建工具:使用 Vite 作为构建工具,提供更快的热重载速度和更优化的构建性能。
  3. 现代化的前端技术栈:包括 Vue Router、Vuex(或 Pinia)、Element Plus(或其他 UI 组件库),以及 TypeScript 支持。
  4. 高度可定制的界面和功能:支持多种主题切换、权限管理、动态路由、国际化等功能,方便开发人员根据需求进行二次开发和定制。
  5. 响应式设计:适应不同屏幕尺寸和设备,提升用户体验。

总的来说,Vue Next Admin 是一个功能强大、灵活、易于扩展的后台管理框架,适合用来开发现代化的后台管理系统。

Vue 动态路由的实现思路主要依赖于 Vue Router,动态路由允许根据用户的权限、角色、页面状态或其他因素动态地生成或改变路由配置。

今天我们要使用vue-next-admin框架通过后端动态的修改路由。

步骤如下:

1.首先,路由在src/router文件夹中。在router文件夹中有四个文件

backEnd.ts是后台控制路由的文件,我们需要使用后台控制时,需要修改里面的内容。

frontEnd.ts 是前端控制路由的文件。
index.ts 文件中,告诉我们需要后端控制路由时:isRequestRoutes 为 true
而修改isRequestRoutes的文件在src/stores/themeConfig

而修改isRequestRoutes的文件在src/stores/themeConfig文件夹中。

需要找到isRequestRoutes改为true。

route.ts 这个是路由文件,不管是后端还是前端控制,只要是需要出现的页面,都需要在这个页面进行注册。

现在我们就可以后端的控制路由。

2. 现在需要修改**backEnd.ts文件中的内容。

获取路由菜单。**

1.需要先给前端的数据关了,然后自己添加
2.我们需要转换数据格式,将一维数据转换为多维数据。
3.数据转换完成后,需要对比路由

backEnd.ts页面代码如下:

javascript 复制代码
import { RouteRecordRaw } from 'vue-router';
import { storeToRefs } from 'pinia';
import pinia from '/@/stores/index';
import { useUserInfo } from '/@/stores/userInfo';
import { useRequestOldRoutes } from '/@/stores/requestOldRoutes';
import { Session } from '/@/utils/storage';
import { NextLoading } from '/@/utils/loading';
import { dynamicRoutes, notFoundAndNoPower } from '/@/router/route';
import { formatTwoStageRoutes, formatFlatteningRoutes, router } from '/@/router/index';
import { useRoutesList } from '/@/stores/routesList';
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
import { useMenuApi } from '/@/api/menu/index';
// import { console } from 'node:inspector';

// 后端控制路由

// 引入 api 请求接口
const menuApi = useMenuApi();

/**
 * 获取目录下的 .vue、.tsx 全部文件
 * @method import.meta.glob
 * @link 参考:https://cn.vitejs.dev/guide/features.html#json
 */
const layouModules: any = import.meta.glob('../layout/routerView/*.{vue,tsx}');
const viewsModules: any = import.meta.glob('../views/**/*.{vue,tsx}');
const dynamicViewsModules: Record<string, Function> = Object.assign({}, { ...layouModules }, { ...viewsModules });

/**
 * 后端控制路由:初始化方法,防止刷新时路由丢失
 * @method NextLoading 界面 loading 动画开始执行
 * @method useUserInfo().setUserInfos() 触发初始化用户信息 pinia
 * @method useRequestOldRoutes().setRequestOldRoutes() 存储接口原始路由(未处理component),根据需求选择使用
 * @method setAddRoute 添加动态路由
 * @method setFilterMenuAndCacheTagsViewRoutes 设置路由到 pinia routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
 */
export async function initBackEndControlRoutes() {
	// 界面 loading 动画开始执行
	if (window.nextLoading === undefined) NextLoading.start();
	// 无 token 停止执行下一步
	if (!Session.get('token')) return false;
	// 触发初始化用户信息 pinia
	// https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP
	await useUserInfo().setUserInfos();
	// 获取路由菜单数据
	const res = await getBackEndControlRoutes();
	console.log(backendRoutes(arrayToTree(res.data), dynamicRoutes[0].children));
	// return;
	if (res.code === 0) {
		// 存储接口原始路由(未处理component),根据需求选择使用
		useRequestOldRoutes().setRequestOldRoutes(JSON.parse(JSON.stringify(res.data)));
		// 处理路由(component),替换 dynamicRoutes(/@/router/route)第一个顶级 children 的路由
		dynamicRoutes[0].children = backendRoutes(arrayToTree(res.data), dynamicRoutes[0].children);
		// 添加动态路由
		await setAddRoute();
	}
	// 无登录权限时,添加判断
	// https://gitee.com/lyt-top/vue-next-admin/issues/I64HVO
	if (res.data.length <= 0) return Promise.resolve(true);
	await setFilterMenuAndCacheTagsViewRoutes();
	NextLoading.done();
}

// 对比路由
// routes 后端返回
//  dynamic 前端路由
function backendRoutes(routes, dynamic) {
	// 将dynamic转换为Map 以提高查找的效率
	const dynamicMap = new Map(dynamic.map((v) => [v.path, v]));
	const filteredRoutes = [];
	routes.forEach((item) => {
		const route = dynamicMap.get(item.path);
		if (route) {
			route.meta.title = item.title;
			route.meta.icon = item.icon;
			if (item.children && item.children.length > 0) {
				route.children = backendRoutes(item.children, route.children);
			}
			filteredRoutes.push(route);
		} else {
			console.warn('路由未定义:' + item.path);
		}
	});
	return filteredRoutes;
}
// 一维转树形
function arrayToTree(items) {
	// 存储最终的树形结构
	const result = [];
	// 用于快速查找节点
	const map = [];
	// 首先将所有节点放在map中,以id为键,值为节点
	items.forEach((item) => {
		map[item.id] = { ...item, children: [] };
	});
	// 然后遍历map,将子节点放在对应的父节点的children数组中
	items.forEach((item) => {
		if (item.pid === null || item.pid === 0 || item.pid === undefined) {
			// 如果父节点为0,则将当前节点放在result中
			result.push(map[item.id]);
		} else {
			// 否则,找到父节点并添加到当前节点的children数组中
			if (map[item.pid]) {
				map[item.pid].children.push(map[item.id]);
			}
		}
	});
	return result;
}
/**
 * 设置路由到 pinia routesList 中(已处理成多级嵌套路由)及缓存多级嵌套数组处理后的一维数组
 * @description 用于左侧菜单、横向菜单的显示
 * @description 用于 tagsView、菜单搜索中:未过滤隐藏的(isHide)
 */
export async function setFilterMenuAndCacheTagsViewRoutes() {
	const storesRoutesList = useRoutesList(pinia);
	storesRoutesList.setRoutesList(dynamicRoutes[0].children as any);
	setCacheTagsViewRoutes();
}

/**
 * 缓存多级嵌套数组处理后的一维数组
 * @description 用于 tagsView、菜单搜索中:未过滤隐藏的(isHide)
 */
export function setCacheTagsViewRoutes() {
	const storesTagsView = useTagsViewRoutes(pinia);
	storesTagsView.setTagsViewRoutes(formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes))[0].children);
}

/**
 * 处理路由格式及添加捕获所有路由或 404 Not found 路由
 * @description 替换 dynamicRoutes(/@/router/route)第一个顶级 children 的路由
 * @returns 返回替换后的路由数组
 */
export function setFilterRouteEnd() {
	let filterRouteEnd: any = formatTwoStageRoutes(formatFlatteningRoutes(dynamicRoutes));
	// notFoundAndNoPower 防止 404、401 不在 layout 布局中,不设置的话,404、401 界面将全屏显示
	// 关联问题 No match found for location with path 'xxx'
	filterRouteEnd[0].children = [...filterRouteEnd[0].children, ...notFoundAndNoPower];
	return filterRouteEnd;
}

/**
 * 添加动态路由
 * @method router.addRoute
 * @description 此处循环为 dynamicRoutes(/@/router/route)第一个顶级 children 的路由一维数组,非多级嵌套
 * @link 参考:https://next.router.vuejs.org/zh/api/#addroute
 */
export async function setAddRoute() {
	await setFilterRouteEnd().forEach((route: RouteRecordRaw) => {
		router.addRoute(route);
	});
}

/**
 * 请求后端路由菜单接口
 * @description isRequestRoutes 为 true,则开启后端控制路由
 * @returns 返回后端路由菜单数据
 */
export function getBackEndControlRoutes() {
	let list = JSON.parse(localStorage.getItem('menus') || '[]');
	return {
		code: 0,
		type: 'adminMenu',
		data: list,
	};
}

/**
 * 重新请求后端路由菜单接口
 * @description 用于菜单管理界面刷新菜单(未进行测试)
 * @description 路径:/src/views/system/menu/component/addMenu.vue
 */
export async function setBackEndControlRefreshRoutes() {
	await getBackEndControlRoutes();
}

/**
 * 后端路由 component 转换
 * @param routes 后端返回的路由表数组
 * @returns 返回处理成函数后的 component
 */
export function backEndComponent(routes: any) {
	if (!routes) return;
	return routes.map((item: any) => {
		if (item.component) item.component = dynamicImport(dynamicViewsModules, item.component as string);
		item.children && backEndComponent(item.children);
		return item;
	});
}

/**
 * 后端路由 component 转换函数
 * @param dynamicViewsModules 获取目录下的 .vue、.tsx 全部文件
 * @param component 当前要处理项 component
 * @returns 返回处理成函数后的 component
 */
export function dynamicImport(dynamicViewsModules: Record<string, Function>, component: string) {
	const keys = Object.keys(dynamicViewsModules);
	const matchKeys = keys.filter((key) => {
		const k = key.replace(/..\/views|../, '');
		return k.startsWith(`${component}`) || k.startsWith(`/${component}`);
	});
	if (matchKeys?.length === 1) {
		const matchKey = matchKeys[0];
		return dynamicViewsModules[matchKey];
	}
	if (matchKeys?.length > 1) {
		return false;
	}
}

现在,后端动态路由修改完成。大家可以自己手动尝试一次。

相关推荐
掘金安东尼18 分钟前
上周前端发生哪些新鲜事儿? #407
前端·面试·github
小谭鸡米花27 分钟前
ECharts各类炫酷图表/3D柱形图
前端·javascript·echarts·大屏端
郝晨妤32 分钟前
【鸿蒙5.0】向用户申请麦克风授权
linux·服务器·前端·华为·harmonyos·鸿蒙
神秘代码行者42 分钟前
使用 contenteditable 属性实现网页内容可编辑化
前端·html5
小鱼人爱编程43 分钟前
Look My Eyes 最新IDEA快速搭建Java Web工程的两种方式
java·前端·后端
郝晨妤44 分钟前
【鸿蒙5.0】鸿蒙登录界面 web嵌入(隐私页面加载)
前端·华为·harmonyos
小鱼人爱编程1 小时前
当上小组长的第3天,我裁掉了2年老员工
前端·后端·面试
晓得迷路了1 小时前
栗子前端技术周刊第 74 期 - 2025 Vue.js 现状报告、Element Plus X、Material UI v7...
前端·javascript·vue.js
知识分享小能手1 小时前
CSS3学习教程,从入门到精通, CSS3 变形效果(2D 和 3D)的详细语法知识点及案例代码(22)
前端·javascript·css·学习·3d·css3·html5