import Vue from 'vue'; import store from '../store'; import VueRouter from 'vue-router'; import NProgress from 'nprogress'; import 'nprogress/nprogress.css'; import { Session } from '@/utils/storage'; import { PrevLoading } from '@/utils/loading.js'; import { useMenuApi } from '@/api/menu'; import adminbendirout from '../../public/admin'; const menuApi = useMenuApi(); // 解决 `element ui` 导航栏重复点菜单报错问题 const originalPush = VueRouter.prototype.push; VueRouter.prototype.push = function push(location) { return originalPush.call(this, location).catch((err) => err); }; // 安装 VueRouter 插件 Vue.use(VueRouter); // 定义动态路由 const dynamicRoutes = [ { path: '/', name: '/', component: 'layout/index', redirect: '/home', meta: { isKeepAlive: true, }, children: [], }, ]; // 定义静态路由 const staticRoutes = [ { path: '/login', name: 'login', component: () => import('@/views/login'), meta: { title: '登录', }, }, { path: '/404', name: 'notFound', component: () => import('@/views/error/404.vue'), meta: { title: 'message.staticRoutes.notFound', }, }, { path: '/401', name: 'noPower', component: () => import('@/views/error/401.vue'), meta: { title: 'message.staticRoutes.noPower', }, }, ]; // 加载静态路由 const createRouter = () => new VueRouter({ routes: staticRoutes, }); // 创建路由 const router = createRouter(); // 加载 loading PrevLoading.start(); // 多级嵌套数组处理成一维数组 export function formatFlatteningRoutes(arr) { if (arr.length <= 0) return false; for (let i = 0; i < arr.length; i++) { if (arr[i].children) { arr = arr.slice(0, i + 1).concat(arr[i].children, arr.slice(i + 1)); } } return arr; } // 处理 tagsViewList 数据,默认路由全部缓存 // isKeepAlive 处理 `name` 值,进行路由缓存 export function formatTwoStageRoutes(arr) { if (arr.length <= 0) return false; const newArr = []; const cacheList = []; arr.forEach((v) => { newArr.push({ ...v }); cacheList.push(v.name); store.dispatch('keepAliveNames/setCacheKeepAlive', cacheList); }); return newArr; } // 判断路由 meta.roles 中是否包含当前登录用户权限字段 export function hasAuth(roles, route) { if (route.meta && route.meta.roles) return roles.some((role) => route.meta.roles.includes(role)); else return true; } // 递归过滤有权限的路由 export function setFilterMenuFun(routes, role) { const menu = []; routes.forEach((route) => { const item = { ...route }; if (hasAuth(role, item)) { if (item.children) item.children = setFilterMenuFun(item.children, role); menu.push(item); } }); return menu; } // 缓存多级嵌套数组处理后的一维数组(tagsView、菜单搜索中使用:未过滤隐藏的(isHide)) export function setCacheTagsViewRoutes(arr) { // 先处理有权限的路由,否则 tagsView、菜单搜索中无权限的路由也将显示 let rolesRoutes = setFilterMenuFun(arr, store.state.userInfos.userInfos.roles); // 添加到 vuex setTagsViewRoutes 中 store.dispatch('tagsViewRoutes/setTagsViewRoutes', formatTwoStageRoutes(formatFlatteningRoutes(rolesRoutes))); } // 递归处理多余的 layout : ,让需要访问的组件保持在第一层 layout 层。 // 因为 `keep-alive` 只能缓存二级路由 // 默认初始化时就执行 export function keepAliveSplice(to) { if (to.matched && to.matched.length > 2) { to.matched.map((v, k) => { if (v.components.default instanceof Function) { v.components.default().then((components) => { if (components.default.name === 'parent') { to.matched.splice(k, 1); router.push({ path: to.path, query: to.query }); keepAliveSplice(to); } }); } else { if (v.components.default.name === 'parent') { to.matched.splice(k, 1); keepAliveSplice(to); } } }); } } // 处理后端返回的 `component` 路径,拼装实现懒加载 export function loadView(path) { /** * 打包成一个 js、一个 css */ // if (path.indexOf('layout') > -1) return () => Promise.resolve(require(`@/${path}`)); // else return () => Promise.resolve(require(`@/views/${path}`)); /** * 打包成多个 js、多个 css */ if (path.indexOf('layout') > -1) return () => import(`@/${path}`); else return () => import(`@/views/${path}`); } // 递归处理每一项 `component` 中的路径 export function dynamicRouter(routes) { return routes.map((view) => { if (view.component) view.component = loadView(view.component); if (view.children) dynamicRouter(view.children); return view; }); } // 添加路由,模拟数据与方法,可自行进行修改 admin // 添加动态路由,`{ path: '*', redirect: '/404' }` 防止页面刷新,静态路由丢失问题 // next({ ...to, replace: true }) 动态路由 addRoute 完毕后才放行,防止刷新时 NProgress 进度条加载2次 // 文档地址:https://router.vuejs.org/zh/api/#router-addroutes export function adminUser(router, to, next) { resetRouter(); // 发请求获取路由表操作 // menuApi // .getMenuAdmin() // .then(async (res) => { // // 获取路由表 // console.log(res.data); // // 读取用户信息,获取对应权限进行判断 // store.dispatch('userInfos/setUserInfos'); // store.dispatch('routesList/setRoutesList', setFilterMenuFun(res.data, store.state.userInfos.userInfos.roles)); // dynamicRoutes[0].children = res.data; // const awaitRoute = await dynamicRouter(dynamicRoutes); // [...awaitRoute, { path: '*', redirect: '/404' }].forEach((route) => { // router.addRoute({ ...route }); // }); // setCacheTagsViewRoutes(JSON.parse(JSON.stringify(res.data))); // next({ ...to, replace: true }); // }) // .catch(() => {}); // 本地数据路由表操作 console.log(adminbendirout); store.dispatch('userInfos/setUserInfos'); store.dispatch('routesList/setRoutesList', setFilterMenuFun(adminbendirout.data, store.state.userInfos.userInfos.roles)); dynamicRoutes[0].children = adminbendirout.data; const awaitRoute = dynamicRouter(dynamicRoutes); [...awaitRoute, { path: '*', redirect: '/404' }].forEach((route) => { router.addRoute({ ...route }); }); setCacheTagsViewRoutes(JSON.parse(JSON.stringify(adminbendirout.data))); next({ ...to, replace: true }); } // 添加路由,模拟数据与方法,可自行进行修改 test // 添加动态路由,`{ path: '*', redirect: '/404' }` 防止页面刷新,静态路由丢失问题 export function testUser(router, to, next) { resetRouter(); menuApi .getMenuTest() .then(async (res) => { // 读取用户信息,获取对应权限进行判断 store.dispatch('userInfos/setUserInfos'); store.dispatch('routesList/setRoutesList', setFilterMenuFun(res.data, store.state.userInfos.userInfos.roles)); dynamicRoutes[0].children = res.data; const awaitRoute = await dynamicRouter(dynamicRoutes); [...awaitRoute, { path: '*', redirect: '/404' }].forEach((route) => { router.addRoute({ ...route }); }); setCacheTagsViewRoutes(JSON.parse(JSON.stringify(res.data))); next({ ...to, replace: true }); }) .catch(() => {}); } // 重置路由 export function resetRouter() { router.matcher = createRouter().matcher; } // 延迟关闭进度条 export function delayNProgressDone(time = 300) { setTimeout(() => { NProgress.done(); }, time); } // 动态加载后端返回路由路由(模拟数据) export function getRouterList(router, to, next) { if (!Session.get('userInfo')) return false; if (Session.get('userInfo').userName === 'admin') adminUser(router, to, next); else if (Session.get('userInfo').userName === 'test') testUser(router, to, next); } // 路由加载前 router.beforeEach((to, from, next) => { keepAliveSplice(to); NProgress.configure({ showSpinner: false }); if (to.meta.title && to.path !== '/login') NProgress.start(); let token = Session.get('token'); if (to.path === '/login' && !token) { NProgress.start(); next(); delayNProgressDone(); } else { if (!token) { NProgress.start(); next('/login'); Session.clear(); delayNProgressDone(); } else if (token && to.path === '/login') { next('/home'); delayNProgressDone(); } else { if (Object.keys(store.state.routesList.routesList).length <= 0) { getRouterList(router, to, next); } else { next(); delayNProgressDone(0); } } } }); // 路由加载后 router.afterEach(() => { PrevLoading.done(); delayNProgressDone(); }); // 导出路由 export default router;