基于vue实现路由鉴权

782 阅读3分钟

步骤1:登录后后端接口返回 如下结构数据:

{
"data":[
{"funcId":2,"funcName":"应用管理","parentId":1,"path":"/appBusinessManage","iconUrl":"d","sortId":1,"funcLevel":2,"children":[{"funcId":7,"funcName":"应用管理","parentId":2,"path":"/appBusinessManage/index","iconUrl":"a","sortId":1,"funcLevel":3,"children":null}]},
{"funcId":3,"funcName":"角色管理","parentId":1,"path":"/roleManagement","iconUrl":"f","sortId":2,"funcLevel":2,"children":[{"funcId":9,"funcName":"功能角色","parentId":3,"path":"/roleManagement/index","iconUrl":"a","sortId":1,"funcLevel":3,"children":null}]},
{"funcId":11,"funcName":"用户管理","parentId":1,"path":"/userManage","iconUrl":"a","sortId":3,"funcLevel":2,"children":[{"funcId":26,"funcName":"用户管理","parentId":11,"path":"/admin/listUser","iconUrl":null,"sortId":11,"funcLevel":3,"children":null}]},
{"funcId":24,"funcName":"科室管理","parentId":1,"path":"/departmentManage","iconUrl":null,"sortId":4,"funcLevel":2,"children":[{"funcId":25,"funcName":"科室管理","parentId":24,"path":"/departmentManage/index","iconUrl":null,"sortId":1,"funcLevel":3,"children":null}]}
],
"retCode":0
}

步骤2:将返回路由保存在store中 进行如下操作

saveAsyncRoutes(filterRoutes) {
  const routes = getAsyncRoute(filterRoutes);
  router.addRoutes(routes);
  setStorage("asyncRoutes", filterRoutes);      
 }

步骤3:路由文件前端写死内容

import Layout from "@/components/Layout";

const routerMap = [    {        path: "/dashboardManage",        component: Layout,        redirect: "/dashboard/index",        meta: {            title: "首页",            icon: "desktop",            name: "/dashboardManage"        },        children: [            {                path: "/dashboard/index",                component: () => import("@/views/dashboard/index.vue"),                meta: {                    title: "首页",                    name: "/dashboard/index",                    hidden: true                }            }        ]
    },
    {
        path: "/appBusinessManage",
        component: Layout,
        meta: {
            title: "应用管理",
            icon: "appstore",
            name: "/appBusinessManage"
        },
        redirect: "/appBusinessManage/index",
        children: [
            {
                path: "/appBusinessManage/index",
                component: () => import("@/views/appBusinessManage"),
                meta: {
                    title: "应用管理",
                    name: "/appBusinessManage/index"
                }
            },
        ]
    },
    {
        path: "/roleManagement",
        component: Layout,
        meta: {
            title: "角色管理",
            icon: "contacts",
            name: "/roleManagement"
        },
        redirect: "/roleManagement/index",
        children: [
            {
                path: "/roleManagement/index",
                component: () => import("@/views/roleManagement"),
                meta: {
                    title: "功能角色",
                    name: "/roleManagement/index"
                }
            },
            {
                path: "/roleApplication/index",
                component: () => import("@/views/roleApplication"),
                meta: {
                    title: "应用角色",
                    name: "/roleApplication/index"
                }
            }
        ]
    },

 
 
]
export default routerMap;

步骤4:数据处理,getAsyncRoute 在下面文件中进行处理,ValidationRole为一个配置开关,如果返回true,代表启动动态路由,如果返回false,直接走前端写死路由即可

import routerMaps from '@/router/router.map';
import router2Map from '@/router/appRouter.ts';
import { ValidationRole } from '@/config';
import { MenuStore } from '../store/menu';
/**
 * @param roleRoutes 权限路由集合
 * @param routerMap   待挂载的路由集合
 * @param children   树节点
 * @param key   唯一key
 * @returns 通过权限过滤后的路由
 */
// 系统管理路由
export function getAsyncRoute(roleRoutes, routerMap = routerMaps, children = 'children', key = 'path') {
    // 不需要权限验证时  直接返回完整路由
    if (!ValidationRole) {
        return routerMaps;
    }
    // 传来的权限路由不存在 则返回空[]
    if (!roleRoutes) {
        return [];
    }
    try {
        roleRoutes = JSON.parse(roleRoutes);
    } catch (error) { }
    //  对数组进行降维打击,将子路由children和父路由都放到一个维度的数组里面
    const afterSqueeze = squeeze(roleRoutes, children);
    console.log("afterSqueeze",afterSqueeze)
    // 所有权限路由path集合
    const pathList = afterSqueeze.map(r => r[key]);
    console.log("pathList",pathList)
    // 过滤权限路由
    console.log("routerMap",routerMap)
    const asyncRoute = filterRouter(routerMap, key);
    console.log("asyncRoute",asyncRoute)
    // 递归排序
    sortRoute(asyncRoute)
    return asyncRoute;


    /**
     * @default key =>'path'
     * @param key 服务端传来的路由的路径 通过此字段进行过滤
     * @param routes 待挂载的路由集合
     * @returns 过滤后的路由集合
     */
     前端写死的路由 根据 pathList 服务端返回的路由进行过滤,最终得到即将渲染的路由。  
    function filterRouter(routes, key = 'path') {
        return routes.filter(r => {
            if (pathList.includes(r.path)) {
                const meta = afterSqueeze.find((j) => j[key] === r.path);
                r.meta = { ...r.meta, ...meta };
                r.children && (r.children = filterRouter(r.children));
                return true;
            }
        });
    }
    /**
     *
     * @param routes 待排序的路由集合
     * 根据meta.sortOrder由小到大排序
     */
    function sortRoute(routes) {
        routes.sort((a, b) => {
            // tslint:disable: no-unused-expression
            a.children && sortRoute(a.children);
            b.children && sortRoute(b.children);
            // return a.meta.sortOrder - b.meta.sortOrder
            return 1;
        });
    }

}
/**
 * 数组降维
 * @param arr 待降维的数组
 * @param key 需要降维的字段
 * @returns  降维后的一维数组
 */
export function squeeze(arr, key = 'children') {
    const newArr = [];

    function fn(v) {
        v.map(r => {
            newArr.push(r);
            if (r[key]) {
                fn(r[key]);
            }
        });
    }
    fn(arr);
    return newArr;
}
//# sourceMappingURL=permission.js.map

步骤5:渲染导航

 menuItem(r) {
        let key = "";
        if (r.children && r.children.length > 0) {
            key = r.children[0].path;
        }
        else {
            key = r.path;
        }
        return (<a-menu-item key={key}>
            {r.meta.icon && (<a-icon type={r.meta.icon} style="font-size:16px" />)}
            <span class="padding-left">{r.meta.title}</span>
        </a-menu-item>);
    }
    subItem(r) {
        return (<a-sub-menu key={r.path} onTitleClick={this.titleClick} title={[
            <a-icon type={r.meta.icon} style="font-size:16px" />,
            <span class="padding-left" v-text={r.meta.title} />
        ]}>
            {r.children.map(i => this.menuItem(i))}
        </a-sub-menu>);
    }
    render() {
        return (
        <a-layout-sider collapsible trigger={null} v-model={this.$props.collapsed} width={256}>
                <a-menu onClick={this.menuClick} selectedKeys=
                {[this.$route.path]} openKeys={this.openkeys} mode="inline" 
                theme="light" style="height: 100%; ">
                <a-menu-item key="/dashboard/index">
                    <a-icon type="desktop" style="font-size:16px" />
                    <span class="padding-left">首页</span>
                </a-menu-item>
                    {this.routerMaps.map((r) => r.children.length > 1
                        ? this.subItem(r)
                        : this.menuItem(r))
                     }
                </a-menu> 
        </a-layout-sider>);
    }