前端路由方案

65 阅读1分钟

前端路由方案

1.router文件

import Vue from "vue";
import VueRouter from "vue-router";

Vue.use(VueRouter);

/* Layout */
import Layout from "@/layout";
import store from "@/store";

// 通用路由,不需要配置权限
export const constRouter = [
  {
    path: "/login",
    component: () => import("@/views/login/index"),
    hidden: true,
    meta: {
      roles: [],
    },
  },
  {
    path: "/404",
    component: () => import("@/views/404"),
    hidden: true,
    meta: {
      roles: [],
    },
  },
  {
    path: "/",
    component: Layout,
    redirect: "/dashboard",
    meta: {
      title: "个人中心",
      icon: "dashboard",
      roles: [],
    },
    children: [
      {
        path: "dashboard",
        name: "Dashboard",
        component: () => import("@/views/grgl/person"),
        meta: {
          title: "个人信息",
          icon: "dashboard",
          roles: [],
        },
      },
       {
        path: "/spgl/goodType",
        name: "GoodType",
        component: () => import("@/views/spgl/goodType"),
        meta: {
          title: "商品类型",
          icon: "nested",
          roles: ["goodType:list"],
        },
      },
    ]
  },
];
// 动态路由
export const constantRoutes = [
  {
    path: "/spgl",
    component: Layout,
    alwaysShow: true,
    meta: {
      title: "商品管理",
      icon: "nested",
      roles: ["goods:list","goodType:list"],
    },
    children: [
      {
        path: "/spgl/goods",
        name: "Goods",
        component: () => import("@/views/spgl/goods"),
        meta: {
          title: "商品列表",
          icon: "nested",
          roles: ["goods:list"],
        },
      },
    ],
  },
];

const createRouter = () =>
  new VueRouter({
    scrollBehavior: () => ({ y: 0 }),
    routes: constRouter,
  });

const router = createRouter();

export function resetRouter() {
  const newRouter = createRouter();
  router.matcher = newRouter.matcher; // reset router
}

export default router;

2.在仓库创建路由操作文件 permiss.js

import { constRouter, constantRoutes } from "@/router";
import router from "@/router/index";

const context = require.context("@/views/", true, /\.vue$/);
const state = {
  routes: [],
};

// 修改store
const mutations = {
  SET_ROUTES(state, routesAA) {
    state.routes = routesAA;
  },
};
const actions = {
  // 根据角色获取动态路由
  generateRoutes({ commit }, menuInfo) {
    return new Promise((resolve) => {
      let accessedRoutes;
      accessedRoutes = constantRoutes;

      // 获取接口--个人的所有菜单
      let arr = getFlatMenuList(menuInfo.menuList);
      // 将菜单添加进路由
      let newArr = filterAsyncRoutesEE(constantRoutes, arr);
      // 判断权限
      let lastArr = filterAsyncRoutes(newArr, menuInfo.permissions);
      // 拼接 基础路由 + 接口路由
      accessedRoutes = constRouter.concat(lastArr);

      commit("SET_ROUTES", accessedRoutes);
      resolve(accessedRoutes);
    });
  },
};
// 判断路由是否有权限
export const hasPermission = (roles, route) => {
  if (route.meta && route.meta.roles) {
    return roles.some((ele) => route.meta.roles.includes(ele));
  } else {
    return false;
  }
};
// 判断是否拥有权限
export const filterAsyncRoutes = (routes, roles) => {
  const res = [];
  routes.forEach((route) => {
    let temp = { ...route };
    // 判断子集权限
    if (hasPermission(roles, temp)) {
      if (temp.children) {
        temp.children = filterAsyncRoutes(temp.children, roles);
      }
      res.push(temp);
    }
  });
  return res;
};
// 从全部路由中过滤出 和后端数据一样的 路由
export const filterAsyncRoutesEE = (routes, menuList) => {
  const res = [];
  routes.forEach((route) => {
    let temp = { ...route };
    // 判断后端路由和前端路路径相同后 使用前端路由
    if (menuList.find((it) => it.path == temp.path)) {
      router.addRoute(temp); // 将菜单路由 添加进 路由中
      res.push(temp);
    }
  });
  return res;
};
/**
 * @description 使用递归扁平化菜单,方便添加动态路由
 * @param {Array} menuList 菜单列表
 * @returns {Array}
 */
export function getFlatMenuList(menuList) {
  let newMenuList = JSON.parse(JSON.stringify(menuList));
  return newMenuList.flatMap((item) => [
    item,
    ...(item.children ? getFlatMenuList(item.children) : []),
  ]);
}
// export function loadView(view){
//   return (resolve) => require(view, resolve)
// }

export default {
  namespaced: true,
  state,
  mutations,
  actions,
};

3.在登录后的 permission.js

import router from "./router";
import store from "./store";
import { Message } from "element-ui";
import NProgress from "nprogress"; // progress bar
import "nprogress/nprogress.css"; // progress bar style
import { getToken } from "@/utils/auth"; // get token from cookie
import getPageTitle from "@/utils/get-page-title";

NProgress.configure({ showSpinner: false }); // NProgress Configuration

const whiteList = ["/login"]; // no redirect whitelist

router.beforeEach(async (to, from, next) => {
  // start progress bar
  NProgress.start();

  // set page title
  document.title = getPageTitle(to.meta.title);

  // determine whether the user has logged in
  const hasToken = getToken();

  if (hasToken) {
    if (to.path === "/login") {
      // if is logged in, redirect to the home page
      next({ path: "/" });
      NProgress.done();
    } else {
      const hasGetUserInfo = store.getters.name;
      if (hasGetUserInfo) {
        next();
      } else {
        try {
          // 调用vuex方法
          // 获取菜单信息
          const menuInfo = await store.dispatch("user/getMenu");
          // 获取用户信息
          const data = await store.dispatch("user/getInfo");
          // 根据角色生成动态路由
          const accessRoutes = await store.dispatch( "permission/generateRoutes", menuInfo);
          
          next({ ...to, replace: true });
        } catch (error) {
          // remove token and go to login page to re-login
          await store.dispatch("user/resetToken");
          Message.error(error || "Has Error");
          next(`/login?redirect=${to.path}`);
          NProgress.done();
        }
      }
    }
  } else {
    /* has no token*/
    if (whiteList.indexOf(to.path) !== -1) {
      // in the free login whitelist, go directly
      next();
    } else {
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${to.path}`);
      NProgress.done();
    }
  }
});

router.afterEach(() => {
  // finish progress bar
  NProgress.done();
});