init
This commit is contained in:
206
src/router/index.ts
Normal file
206
src/router/index.ts
Normal file
@@ -0,0 +1,206 @@
|
||||
// import "@/utils/sso";
|
||||
import Cookies from "js-cookie";
|
||||
import { getConfig } from "@/config";
|
||||
import NProgress from "@/utils/progress";
|
||||
import { buildHierarchyTree } from "@/utils/tree";
|
||||
import remainingRouter from "./modules/remaining";
|
||||
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
|
||||
import { usePermissionStoreHook } from "@/store/modules/permission";
|
||||
import { isUrl, openLink, storageLocal, isAllEmpty } from "@pureadmin/utils";
|
||||
import {
|
||||
ascending,
|
||||
getTopMenu,
|
||||
initRouter,
|
||||
isOneOfArray,
|
||||
getHistoryMode,
|
||||
findRouteByPath,
|
||||
handleAliveRoute,
|
||||
formatTwoStageRoutes,
|
||||
formatFlatteningRoutes
|
||||
} from "./utils";
|
||||
import {
|
||||
type Router,
|
||||
createRouter,
|
||||
type RouteRecordRaw,
|
||||
type RouteComponent
|
||||
} from "vue-router";
|
||||
import {
|
||||
type DataInfo,
|
||||
userKey,
|
||||
removeToken,
|
||||
multipleTabsKey
|
||||
} from "@/utils/auth";
|
||||
|
||||
/** 自动导入全部静态路由,无需再手动引入!匹配 src/router/modules 目录(任何嵌套级别)中具有 .ts 扩展名的所有文件,除了 remaining.ts 文件
|
||||
* 如何匹配所有文件请看:https://github.com/mrmlnc/fast-glob#basic-syntax
|
||||
* 如何排除文件请看:https://cn.vitejs.dev/guide/features.html#negative-patterns
|
||||
*/
|
||||
const modules: Record<string, any> = import.meta.glob(
|
||||
["./modules/**/*.ts", "!./modules/**/remaining.ts"],
|
||||
{
|
||||
eager: true
|
||||
}
|
||||
);
|
||||
|
||||
/** 原始静态路由(未做任何处理) */
|
||||
const routes = [];
|
||||
|
||||
Object.keys(modules).forEach(key => {
|
||||
routes.push(modules[key].default);
|
||||
});
|
||||
|
||||
/** 导出处理后的静态路由(三级及以上的路由全部拍成二级) */
|
||||
export const constantRoutes: Array<RouteRecordRaw> = formatTwoStageRoutes(
|
||||
formatFlatteningRoutes(buildHierarchyTree(ascending(routes.flat(Infinity))))
|
||||
);
|
||||
|
||||
/** 用于渲染菜单,保持原始层级 */
|
||||
export const constantMenus: Array<RouteComponent> = ascending(
|
||||
routes.flat(Infinity)
|
||||
).concat(...remainingRouter);
|
||||
|
||||
/** 不参与菜单的路由 */
|
||||
export const remainingPaths = Object.keys(remainingRouter).map(v => {
|
||||
return remainingRouter[v].path;
|
||||
});
|
||||
|
||||
/** 创建路由实例 */
|
||||
export const router: Router = createRouter({
|
||||
history: getHistoryMode(import.meta.env.VITE_ROUTER_HISTORY),
|
||||
routes: constantRoutes.concat(...(remainingRouter as any)),
|
||||
strict: true,
|
||||
scrollBehavior(to, from, savedPosition) {
|
||||
return new Promise(resolve => {
|
||||
if (savedPosition) {
|
||||
return savedPosition;
|
||||
} else {
|
||||
if (from.meta.saveSrollTop) {
|
||||
const top: number =
|
||||
document.documentElement.scrollTop || document.body.scrollTop;
|
||||
resolve({ left: 0, top });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/** 重置路由 */
|
||||
export function resetRouter() {
|
||||
router.getRoutes().forEach(route => {
|
||||
const { name, meta } = route;
|
||||
if (name && router.hasRoute(name) && meta?.backstage) {
|
||||
router.removeRoute(name);
|
||||
router.options.routes = formatTwoStageRoutes(
|
||||
formatFlatteningRoutes(
|
||||
buildHierarchyTree(ascending(routes.flat(Infinity)))
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
usePermissionStoreHook().clearAllCachePage();
|
||||
}
|
||||
|
||||
/** 路由白名单 */
|
||||
const whiteList = ["/login"];
|
||||
|
||||
const { VITE_HIDE_HOME } = import.meta.env;
|
||||
|
||||
router.beforeEach((to: ToRouteType, _from, next) => {
|
||||
if (to.meta?.keepAlive) {
|
||||
handleAliveRoute(to, "add");
|
||||
// 页面整体刷新和点击标签页刷新
|
||||
if (_from.name === undefined || _from.name === "Redirect") {
|
||||
handleAliveRoute(to);
|
||||
}
|
||||
}
|
||||
const userInfo = storageLocal().getItem<DataInfo<number>>(userKey);
|
||||
NProgress.start();
|
||||
const externalLink = isUrl(to?.name as string);
|
||||
if (!externalLink) {
|
||||
to.matched.some(item => {
|
||||
if (!item.meta.title) return "";
|
||||
const Title = getConfig().Title;
|
||||
if (Title) document.title = `${item.meta.title} | ${Title}`;
|
||||
else document.title = item.meta.title as string;
|
||||
});
|
||||
}
|
||||
/** 如果已经登录并存在登录信息后不能跳转到路由白名单,而是继续保持在当前页面 */
|
||||
function toCorrectRoute() {
|
||||
whiteList.includes(to.fullPath) ? next(_from.fullPath) : next();
|
||||
}
|
||||
if (Cookies.get(multipleTabsKey) && userInfo) {
|
||||
// 无权限跳转403页面
|
||||
if (to.meta?.roles && !isOneOfArray(to.meta?.roles, userInfo?.roles)) {
|
||||
next({ path: "/error/403" });
|
||||
}
|
||||
// 开启隐藏首页后在浏览器地址栏手动输入首页welcome路由则跳转到404页面
|
||||
if (VITE_HIDE_HOME === "true" && to.fullPath === "/welcome") {
|
||||
next({ path: "/error/404" });
|
||||
}
|
||||
if (_from?.name) {
|
||||
// name为超链接
|
||||
if (externalLink) {
|
||||
openLink(to?.name as string);
|
||||
NProgress.done();
|
||||
} else {
|
||||
toCorrectRoute();
|
||||
}
|
||||
} else {
|
||||
// 刷新
|
||||
if (
|
||||
usePermissionStoreHook().wholeMenus.length === 0 &&
|
||||
to.path !== "/login"
|
||||
) {
|
||||
initRouter().then((router: Router) => {
|
||||
if (!useMultiTagsStoreHook().getMultiTagsCache) {
|
||||
const { path } = to;
|
||||
const route = findRouteByPath(
|
||||
path,
|
||||
router.options.routes[0].children
|
||||
);
|
||||
getTopMenu(true);
|
||||
// query、params模式路由传参数的标签页不在此处处理
|
||||
if (route && route.meta?.title) {
|
||||
if (isAllEmpty(route.parentId) && route.meta?.backstage) {
|
||||
// 此处为动态顶级路由(目录)
|
||||
const { path, name, meta } = route.children[0];
|
||||
useMultiTagsStoreHook().handleTags("push", {
|
||||
path,
|
||||
name,
|
||||
meta
|
||||
});
|
||||
} else {
|
||||
const { path, name, meta } = route;
|
||||
useMultiTagsStoreHook().handleTags("push", {
|
||||
path,
|
||||
name,
|
||||
meta
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// 确保动态路由完全加入路由列表并且不影响静态路由(注意:动态路由刷新时router.beforeEach可能会触发两次,第一次触发动态路由还未完全添加,第二次动态路由才完全添加到路由列表,如果需要在router.beforeEach做一些判断可以在to.name存在的条件下去判断,这样就只会触发一次)
|
||||
if (isAllEmpty(to.name)) router.push(to.fullPath);
|
||||
});
|
||||
}
|
||||
toCorrectRoute();
|
||||
}
|
||||
} else {
|
||||
if (to.path !== "/login") {
|
||||
if (whiteList.indexOf(to.path) !== -1) {
|
||||
next();
|
||||
} else {
|
||||
removeToken();
|
||||
next({ path: "/login" });
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
router.afterEach(() => {
|
||||
NProgress.done();
|
||||
});
|
||||
|
||||
export default router;
|
||||
36
src/router/modules/error.ts
Normal file
36
src/router/modules/error.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
export default {
|
||||
path: "/error",
|
||||
redirect: "/error/403",
|
||||
meta: {
|
||||
icon: "ri:information-line",
|
||||
// showLink: false,
|
||||
title: "异常页面",
|
||||
rank: 9
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/error/403",
|
||||
name: "403",
|
||||
component: () => import("@/views/error/403.vue"),
|
||||
meta: {
|
||||
title: "403"
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/error/404",
|
||||
name: "404",
|
||||
component: () => import("@/views/error/404.vue"),
|
||||
meta: {
|
||||
title: "404"
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/error/500",
|
||||
name: "500",
|
||||
component: () => import("@/views/error/500.vue"),
|
||||
meta: {
|
||||
title: "500"
|
||||
}
|
||||
}
|
||||
]
|
||||
} satisfies RouteConfigsTable;
|
||||
25
src/router/modules/home.ts
Normal file
25
src/router/modules/home.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
const { VITE_HIDE_HOME } = import.meta.env;
|
||||
const Layout = () => import("@/layout/index.vue");
|
||||
|
||||
export default {
|
||||
path: "/",
|
||||
name: "Home",
|
||||
component: Layout,
|
||||
redirect: "/welcome",
|
||||
meta: {
|
||||
icon: "ep:home-filled",
|
||||
title: "首页",
|
||||
rank: 0
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/welcome",
|
||||
name: "Welcome",
|
||||
component: () => import("@/views/welcome/index.vue"),
|
||||
meta: {
|
||||
title: "首页",
|
||||
showLink: VITE_HIDE_HOME === "true" ? false : true
|
||||
}
|
||||
}
|
||||
]
|
||||
} satisfies RouteConfigsTable;
|
||||
30
src/router/modules/remaining.ts
Normal file
30
src/router/modules/remaining.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
const Layout = () => import("@/layout/index.vue");
|
||||
|
||||
export default [
|
||||
{
|
||||
path: "/login",
|
||||
name: "Login",
|
||||
component: () => import("@/views/login/index.vue"),
|
||||
meta: {
|
||||
title: "登录",
|
||||
showLink: false,
|
||||
rank: 101
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/redirect",
|
||||
component: Layout,
|
||||
meta: {
|
||||
title: "加载中...",
|
||||
showLink: false,
|
||||
rank: 102
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/redirect/:path(.*)",
|
||||
name: "Redirect",
|
||||
component: () => import("@/layout/redirect.vue")
|
||||
}
|
||||
]
|
||||
}
|
||||
] satisfies Array<RouteConfigsTable>;
|
||||
408
src/router/utils.ts
Normal file
408
src/router/utils.ts
Normal file
@@ -0,0 +1,408 @@
|
||||
import {
|
||||
type RouterHistory,
|
||||
type RouteRecordRaw,
|
||||
type RouteComponent,
|
||||
createWebHistory,
|
||||
createWebHashHistory
|
||||
} from "vue-router";
|
||||
import { router } from "./index";
|
||||
import { isProxy, toRaw } from "vue";
|
||||
import { useTimeoutFn } from "@vueuse/core";
|
||||
import {
|
||||
isString,
|
||||
cloneDeep,
|
||||
isAllEmpty,
|
||||
intersection,
|
||||
storageLocal,
|
||||
isIncludeAllChildren
|
||||
} from "@pureadmin/utils";
|
||||
import { getConfig } from "@/config";
|
||||
import { buildHierarchyTree } from "@/utils/tree";
|
||||
import { userKey, type DataInfo } from "@/utils/auth";
|
||||
import { type menuType, routerArrays } from "@/layout/types";
|
||||
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
|
||||
import { usePermissionStoreHook } from "@/store/modules/permission";
|
||||
const IFrame = () => import("@/layout/frame.vue");
|
||||
// https://cn.vitejs.dev/guide/features.html#glob-import
|
||||
const modulesRoutes = import.meta.glob("/src/views/**/*.{vue,tsx}");
|
||||
|
||||
// 动态路由
|
||||
import { getAsyncRoutes } from "@/api/routes";
|
||||
|
||||
function handRank(routeInfo: any) {
|
||||
const { name, path, parentId, meta } = routeInfo;
|
||||
return isAllEmpty(parentId)
|
||||
? isAllEmpty(meta?.rank) ||
|
||||
(meta?.rank === 0 && name !== "Home" && path !== "/")
|
||||
? true
|
||||
: false
|
||||
: false;
|
||||
}
|
||||
|
||||
/** 按照路由中meta下的rank等级升序来排序路由 */
|
||||
function ascending(arr: any[]) {
|
||||
arr.forEach((v, index) => {
|
||||
// 当rank不存在时,根据顺序自动创建,首页路由永远在第一位
|
||||
if (handRank(v)) v.meta.rank = index + 2;
|
||||
});
|
||||
return arr.sort(
|
||||
(a: { meta: { rank: number } }, b: { meta: { rank: number } }) => {
|
||||
return a?.meta.rank - b?.meta.rank;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/** 过滤meta中showLink为false的菜单 */
|
||||
function filterTree(data: RouteComponent[]) {
|
||||
const newTree = cloneDeep(data).filter(
|
||||
(v: { meta: { showLink: boolean } }) => v.meta?.showLink !== false
|
||||
);
|
||||
newTree.forEach(
|
||||
(v: { children }) => v.children && (v.children = filterTree(v.children))
|
||||
);
|
||||
return newTree;
|
||||
}
|
||||
|
||||
/** 过滤children长度为0的的目录,当目录下没有菜单时,会过滤此目录,目录没有赋予roles权限,当目录下只要有一个菜单有显示权限,那么此目录就会显示 */
|
||||
function filterChildrenTree(data: RouteComponent[]) {
|
||||
const newTree = cloneDeep(data).filter((v: any) => v?.children?.length !== 0);
|
||||
newTree.forEach(
|
||||
(v: { children }) => v.children && (v.children = filterTree(v.children))
|
||||
);
|
||||
return newTree;
|
||||
}
|
||||
|
||||
/** 判断两个数组彼此是否存在相同值 */
|
||||
function isOneOfArray(a: Array<string>, b: Array<string>) {
|
||||
return Array.isArray(a) && Array.isArray(b)
|
||||
? intersection(a, b).length > 0
|
||||
? true
|
||||
: false
|
||||
: true;
|
||||
}
|
||||
|
||||
/** 从localStorage里取出当前登录用户的角色roles,过滤无权限的菜单 */
|
||||
function filterNoPermissionTree(data: RouteComponent[]) {
|
||||
const currentRoles =
|
||||
storageLocal().getItem<DataInfo<number>>(userKey)?.roles ?? [];
|
||||
const newTree = cloneDeep(data).filter((v: any) =>
|
||||
isOneOfArray(v.meta?.roles, currentRoles)
|
||||
);
|
||||
newTree.forEach(
|
||||
(v: any) => v.children && (v.children = filterNoPermissionTree(v.children))
|
||||
);
|
||||
return filterChildrenTree(newTree);
|
||||
}
|
||||
|
||||
/** 通过指定 `key` 获取父级路径集合,默认 `key` 为 `path` */
|
||||
function getParentPaths(value: string, routes: RouteRecordRaw[], key = "path") {
|
||||
// 深度遍历查找
|
||||
function dfs(routes: RouteRecordRaw[], value: string, parents: string[]) {
|
||||
for (let i = 0; i < routes.length; i++) {
|
||||
const item = routes[i];
|
||||
// 返回父级path
|
||||
if (item[key] === value) return parents;
|
||||
// children不存在或为空则不递归
|
||||
if (!item.children || !item.children.length) continue;
|
||||
// 往下查找时将当前path入栈
|
||||
parents.push(item.path);
|
||||
|
||||
if (dfs(item.children, value, parents).length) return parents;
|
||||
// 深度遍历查找未找到时当前path 出栈
|
||||
parents.pop();
|
||||
}
|
||||
// 未找到时返回空数组
|
||||
return [];
|
||||
}
|
||||
|
||||
return dfs(routes, value, []);
|
||||
}
|
||||
|
||||
/** 查找对应 `path` 的路由信息 */
|
||||
function findRouteByPath(path: string, routes: RouteRecordRaw[]) {
|
||||
let res = routes.find((item: { path: string }) => item.path == path);
|
||||
if (res) {
|
||||
return isProxy(res) ? toRaw(res) : res;
|
||||
} else {
|
||||
for (let i = 0; i < routes.length; i++) {
|
||||
if (
|
||||
routes[i].children instanceof Array &&
|
||||
routes[i].children.length > 0
|
||||
) {
|
||||
res = findRouteByPath(path, routes[i].children);
|
||||
if (res) {
|
||||
return isProxy(res) ? toRaw(res) : res;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function addPathMatch() {
|
||||
if (!router.hasRoute("pathMatch")) {
|
||||
router.addRoute({
|
||||
path: "/:pathMatch(.*)",
|
||||
name: "pathMatch",
|
||||
redirect: "/error/404"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** 处理动态路由(后端返回的路由) */
|
||||
function handleAsyncRoutes(routeList) {
|
||||
if (routeList.length === 0) {
|
||||
usePermissionStoreHook().handleWholeMenus(routeList);
|
||||
} else {
|
||||
formatFlatteningRoutes(addAsyncRoutes(routeList)).map(
|
||||
(v: RouteRecordRaw) => {
|
||||
// 防止重复添加路由
|
||||
if (
|
||||
router.options.routes[0].children.findIndex(
|
||||
value => value.path === v.path
|
||||
) !== -1
|
||||
) {
|
||||
return;
|
||||
} else {
|
||||
// 切记将路由push到routes后还需要使用addRoute,这样路由才能正常跳转
|
||||
router.options.routes[0].children.push(v);
|
||||
// 最终路由进行升序
|
||||
ascending(router.options.routes[0].children);
|
||||
if (!router.hasRoute(v?.name)) router.addRoute(v);
|
||||
const flattenRouters: any = router
|
||||
.getRoutes()
|
||||
.find(n => n.path === "/");
|
||||
router.addRoute(flattenRouters);
|
||||
}
|
||||
}
|
||||
);
|
||||
usePermissionStoreHook().handleWholeMenus(routeList);
|
||||
}
|
||||
if (!useMultiTagsStoreHook().getMultiTagsCache) {
|
||||
useMultiTagsStoreHook().handleTags("equal", [
|
||||
...routerArrays,
|
||||
...usePermissionStoreHook().flatteningRoutes.filter(
|
||||
v => v?.meta?.fixedTag
|
||||
)
|
||||
]);
|
||||
}
|
||||
addPathMatch();
|
||||
}
|
||||
|
||||
/** 初始化路由(`new Promise` 写法防止在异步请求中造成无限循环)*/
|
||||
function initRouter() {
|
||||
if (getConfig()?.CachingAsyncRoutes) {
|
||||
// 开启动态路由缓存本地localStorage
|
||||
const key = "async-routes";
|
||||
const asyncRouteList = storageLocal().getItem(key) as any;
|
||||
if (asyncRouteList && asyncRouteList?.length > 0) {
|
||||
return new Promise(resolve => {
|
||||
handleAsyncRoutes(asyncRouteList);
|
||||
resolve(router);
|
||||
});
|
||||
} else {
|
||||
return new Promise(resolve => {
|
||||
getAsyncRoutes().then(({ data }) => {
|
||||
handleAsyncRoutes(cloneDeep(data));
|
||||
storageLocal().setItem(key, data);
|
||||
resolve(router);
|
||||
});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return new Promise(resolve => {
|
||||
getAsyncRoutes().then(({ data }) => {
|
||||
handleAsyncRoutes(cloneDeep(data));
|
||||
resolve(router);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将多级嵌套路由处理成一维数组
|
||||
* @param routesList 传入路由
|
||||
* @returns 返回处理后的一维路由
|
||||
*/
|
||||
function formatFlatteningRoutes(routesList: RouteRecordRaw[]) {
|
||||
if (routesList.length === 0) return routesList;
|
||||
let hierarchyList = buildHierarchyTree(routesList);
|
||||
for (let i = 0; i < hierarchyList.length; i++) {
|
||||
if (hierarchyList[i].children) {
|
||||
hierarchyList = hierarchyList
|
||||
.slice(0, i + 1)
|
||||
.concat(hierarchyList[i].children, hierarchyList.slice(i + 1));
|
||||
}
|
||||
}
|
||||
return hierarchyList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 一维数组处理成多级嵌套数组(三级及以上的路由全部拍成二级,keep-alive 只支持到二级缓存)
|
||||
* https://github.com/pure-admin/vue-pure-admin/issues/67
|
||||
* @param routesList 处理后的一维路由菜单数组
|
||||
* @returns 返回将一维数组重新处理成规定路由的格式
|
||||
*/
|
||||
function formatTwoStageRoutes(routesList: RouteRecordRaw[]) {
|
||||
if (routesList.length === 0) return routesList;
|
||||
const newRoutesList: RouteRecordRaw[] = [];
|
||||
routesList.forEach((v: RouteRecordRaw) => {
|
||||
if (v.path === "/") {
|
||||
newRoutesList.push({
|
||||
component: v.component,
|
||||
name: v.name,
|
||||
path: v.path,
|
||||
redirect: v.redirect,
|
||||
meta: v.meta,
|
||||
children: []
|
||||
});
|
||||
} else {
|
||||
newRoutesList[0]?.children.push({ ...v });
|
||||
}
|
||||
});
|
||||
return newRoutesList;
|
||||
}
|
||||
|
||||
/** 处理缓存路由(添加、删除、刷新) */
|
||||
function handleAliveRoute({ name }: ToRouteType, mode?: string) {
|
||||
switch (mode) {
|
||||
case "add":
|
||||
usePermissionStoreHook().cacheOperate({
|
||||
mode: "add",
|
||||
name
|
||||
});
|
||||
break;
|
||||
case "delete":
|
||||
usePermissionStoreHook().cacheOperate({
|
||||
mode: "delete",
|
||||
name
|
||||
});
|
||||
break;
|
||||
case "refresh":
|
||||
usePermissionStoreHook().cacheOperate({
|
||||
mode: "refresh",
|
||||
name
|
||||
});
|
||||
break;
|
||||
default:
|
||||
usePermissionStoreHook().cacheOperate({
|
||||
mode: "delete",
|
||||
name
|
||||
});
|
||||
useTimeoutFn(() => {
|
||||
usePermissionStoreHook().cacheOperate({
|
||||
mode: "add",
|
||||
name
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
/** 过滤后端传来的动态路由 重新生成规范路由 */
|
||||
function addAsyncRoutes(arrRoutes: Array<RouteRecordRaw>) {
|
||||
if (!arrRoutes || !arrRoutes.length) return;
|
||||
const modulesRoutesKeys = Object.keys(modulesRoutes);
|
||||
arrRoutes.forEach((v: RouteRecordRaw) => {
|
||||
// 将backstage属性加入meta,标识此路由为后端返回路由
|
||||
v.meta.backstage = true;
|
||||
// 父级的redirect属性取值:如果子级存在且父级的redirect属性不存在,默认取第一个子级的path;如果子级存在且父级的redirect属性存在,取存在的redirect属性,会覆盖默认值
|
||||
if (v?.children && v.children.length && !v.redirect)
|
||||
v.redirect = v.children[0].path;
|
||||
// 父级的name属性取值:如果子级存在且父级的name属性不存在,默认取第一个子级的name;如果子级存在且父级的name属性存在,取存在的name属性,会覆盖默认值(注意:测试中发现父级的name不能和子级name重复,如果重复会造成重定向无效(跳转404),所以这里给父级的name起名的时候后面会自动加上`Parent`,避免重复)
|
||||
if (v?.children && v.children.length && !v.name)
|
||||
v.name = (v.children[0].name as string) + "Parent";
|
||||
if (v.meta?.frameSrc) {
|
||||
v.component = IFrame;
|
||||
} else {
|
||||
// 对后端传component组件路径和不传做兼容(如果后端传component组件路径,那么path可以随便写,如果不传,component组件路径会跟path保持一致)
|
||||
const index = v?.component
|
||||
? modulesRoutesKeys.findIndex(ev => ev.includes(v.component as any))
|
||||
: modulesRoutesKeys.findIndex(ev => ev.includes(v.path));
|
||||
v.component = modulesRoutes[modulesRoutesKeys[index]];
|
||||
}
|
||||
if (v?.children && v.children.length) {
|
||||
addAsyncRoutes(v.children);
|
||||
}
|
||||
});
|
||||
return arrRoutes;
|
||||
}
|
||||
|
||||
/** 获取路由历史模式 https://next.router.vuejs.org/zh/guide/essentials/history-mode.html */
|
||||
function getHistoryMode(routerHistory): RouterHistory {
|
||||
// len为1 代表只有历史模式 为2 代表历史模式中存在base参数 https://next.router.vuejs.org/zh/api/#%E5%8F%82%E6%95%B0-1
|
||||
const historyMode = routerHistory.split(",");
|
||||
const leftMode = historyMode[0];
|
||||
const rightMode = historyMode[1];
|
||||
// no param
|
||||
if (historyMode.length === 1) {
|
||||
if (leftMode === "hash") {
|
||||
return createWebHashHistory("");
|
||||
} else if (leftMode === "h5") {
|
||||
return createWebHistory("");
|
||||
}
|
||||
} //has param
|
||||
else if (historyMode.length === 2) {
|
||||
if (leftMode === "hash") {
|
||||
return createWebHashHistory(rightMode);
|
||||
} else if (leftMode === "h5") {
|
||||
return createWebHistory(rightMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取当前页面按钮级别的权限 */
|
||||
function getAuths(): Array<string> {
|
||||
return router.currentRoute.value.meta.auths as Array<string>;
|
||||
}
|
||||
|
||||
/** 是否有按钮级别的权限(根据路由`meta`中的`auths`字段进行判断)*/
|
||||
function hasAuth(value: string | Array<string>): boolean {
|
||||
if (!value) return false;
|
||||
/** 从当前路由的`meta`字段里获取按钮级别的所有自定义`code`值 */
|
||||
const metaAuths = getAuths();
|
||||
if (!metaAuths) return false;
|
||||
const isAuths = isString(value)
|
||||
? metaAuths.includes(value)
|
||||
: isIncludeAllChildren(value, metaAuths);
|
||||
return isAuths ? true : false;
|
||||
}
|
||||
|
||||
function handleTopMenu(route) {
|
||||
if (route?.children && route.children.length > 1) {
|
||||
if (route.redirect) {
|
||||
return route.children.filter(cur => cur.path === route.redirect)[0];
|
||||
} else {
|
||||
return route.children[0];
|
||||
}
|
||||
} else {
|
||||
return route;
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取所有菜单中的第一个菜单(顶级菜单)*/
|
||||
function getTopMenu(tag = false): menuType {
|
||||
const topMenu = handleTopMenu(
|
||||
usePermissionStoreHook().wholeMenus[0]?.children[0]
|
||||
);
|
||||
tag && useMultiTagsStoreHook().handleTags("push", topMenu);
|
||||
return topMenu;
|
||||
}
|
||||
|
||||
export {
|
||||
hasAuth,
|
||||
getAuths,
|
||||
ascending,
|
||||
filterTree,
|
||||
initRouter,
|
||||
getTopMenu,
|
||||
addPathMatch,
|
||||
isOneOfArray,
|
||||
getHistoryMode,
|
||||
addAsyncRoutes,
|
||||
getParentPaths,
|
||||
findRouteByPath,
|
||||
handleAliveRoute,
|
||||
formatTwoStageRoutes,
|
||||
formatFlatteningRoutes,
|
||||
filterNoPermissionTree
|
||||
};
|
||||
Reference in New Issue
Block a user