routerUtil.js 6.48 KB
Newer Older
水落(YangLei)'s avatar
水落(YangLei) committed
1 2
import { mergeI18nFromRoutes } from '@/utils/i18nUtil';
import deepMerge from 'deepmerge';
wb-ct393452's avatar
wb-ct393452 committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28

//应用配置
let appOptions = {
    router: undefined,
    i18n: undefined,
    store: undefined,
};

/**
 * 设置应用配置
 * @param options
 */
function setAppOptions(options) {
    const { router, store, i18n } = options;
    appOptions.router = router;
    appOptions.store = store;
    appOptions.i18n = i18n;
}

/**
 * 根据 路由配置 和 路由组件注册 解析路由
 * @param routesConfig 路由配置
 * @param routerMap 本地路由组件注册配置
 */
function parseRoutes(routesConfig, routerMap) {
    let routes = [];
水落(YangLei)'s avatar
水落(YangLei) committed
29
    routesConfig.forEach(item => {
wb-ct393452's avatar
wb-ct393452 committed
30 31 32
        // 获取注册在 routerMap 中的 router,初始化 routeCfg
        let router = undefined,
            routeCfg = {};
水落(YangLei)'s avatar
水落(YangLei) committed
33
        if (typeof item === 'string') {
wb-ct393452's avatar
wb-ct393452 committed
34 35
            router = routerMap[item];
            routeCfg = { path: (router && router.path) || item, router: item };
水落(YangLei)'s avatar
水落(YangLei) committed
36
        } else if (typeof item === 'object') {
wb-ct393452's avatar
wb-ct393452 committed
37 38 39 40 41
            router = routerMap[item.router];
            routeCfg = item;
        }
        if (!router) {
            console.warn(`can't find register for router ${routeCfg.router}, please register it in advance.`);
水落(YangLei)'s avatar
水落(YangLei) committed
42
            router = typeof item === 'string' ? { path: item, name: item } : item;
wb-ct393452's avatar
wb-ct393452 committed
43 44 45 46 47 48 49 50 51
        }
        // 从 router 和 routeCfg 解析路由
        const route = {
            path: routeCfg.path || router.path || routeCfg.router,
            name: routeCfg.name || router.name,
            component: router.component,
            redirect: routeCfg.redirect || router.redirect,
            meta: {
                authority:
水落(YangLei)'s avatar
水落(YangLei) committed
52 53 54 55 56
                    routeCfg.authority ||
                    router.authority ||
                    routeCfg.meta?.authority ||
                    router.meta?.authority ||
                    '*',
wb-ct393452's avatar
wb-ct393452 committed
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
                icon: routeCfg.icon || router.icon || routeCfg.meta?.icon || router.meta?.icon,
                page: routeCfg.page || router.page || routeCfg.meta?.page || router.meta?.page,
                link: routeCfg.link || router.link || routeCfg.meta?.link || router.meta?.link,
            },
        };
        if (routeCfg.invisible || router.invisible) {
            route.meta.invisible = true;
        }
        if (routeCfg.children && routeCfg.children.length > 0) {
            route.children = parseRoutes(routeCfg.children, routerMap);
        }
        routes.push(route);
    });
    return routes;
}

/**
 * 加载路由
 * @param routesConfig {RouteConfig[]} 路由配置
 */
function loadRoutes(routesConfig) {
    // 应用配置
    const { router, store, i18n } = appOptions;

81
    routesConfig = store.getters['accountModule/routesConfig'];
水落(YangLei)'s avatar
水落(YangLei) committed
82

wb-ct393452's avatar
wb-ct393452 committed
83 84
    // 提取路由国际化数据
    mergeI18nFromRoutes(i18n, router.options.routes);
85

wb-ct393452's avatar
wb-ct393452 committed
86
    // 初始化Admin后台菜单数据
水落(YangLei)'s avatar
水落(YangLei) committed
87
    const rootRoute = router.options.routes.find(item => item.path === '/');
88

wb-ct393452's avatar
wb-ct393452 committed
89
    const menuRoutes = rootRoute && rootRoute.children;
90

wb-ct393452's avatar
wb-ct393452 committed
91
    if (menuRoutes) {
水落(YangLei)'s avatar
水落(YangLei) committed
92
        store.commit('settingModule/setMenuData', menuRoutes);
wb-ct393452's avatar
wb-ct393452 committed
93 94 95 96 97 98 99 100 101 102 103
    }
}

/**
 * 深度合并路由
 * @param target {Route[]}
 * @param source {Route[]}
 * @returns {Route[]}
 */
function deepMergeRoutes(target, source) {
    // 映射路由数组
水落(YangLei)'s avatar
水落(YangLei) committed
104
    const mapRoutes = routes => {
wb-ct393452's avatar
wb-ct393452 committed
105
        const routesMap = {};
水落(YangLei)'s avatar
水落(YangLei) committed
106
        routes.forEach(item => {
wb-ct393452's avatar
wb-ct393452 committed
107 108 109 110 111 112 113 114 115 116 117 118 119 120
            routesMap[item.path] = {
                ...item,
                children: item.children ? mapRoutes(item.children) : undefined,
            };
        });
        return routesMap;
    };
    const tarMap = mapRoutes(target);
    const srcMap = mapRoutes(source);

    // 合并路由
    const merge = deepMerge(tarMap, srcMap);

    // 转换为 routes 数组
水落(YangLei)'s avatar
水落(YangLei) committed
121 122
    const parseRoutesMap = routesMap => {
        return Object.values(routesMap).map(item => {
wb-ct393452's avatar
wb-ct393452 committed
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
            if (item.children) {
                item.children = parseRoutesMap(item.children);
            } else {
                delete item.children;
            }
            return item;
        });
    };
    return parseRoutesMap(merge);
}

/**
 * 格式化路由
 * @param routes 路由配置
 */
function formatRoutes(routes) {
水落(YangLei)'s avatar
水落(YangLei) committed
139
    routes.forEach(route => {
wb-ct393452's avatar
wb-ct393452 committed
140
        const { path } = route;
水落(YangLei)'s avatar
水落(YangLei) committed
141 142
        if (!path.startsWith('/') && path !== '*') {
            route.path = '/' + path;
wb-ct393452's avatar
wb-ct393452 committed
143 144 145 146 147 148 149 150 151 152 153
        }
    });
    formatAuthority(routes);
}

/**
 * 格式化路由的权限配置
 * @param routes 路由
 * @param pAuthorities 父级路由权限配置集合
 */
function formatAuthority(routes, pAuthorities = []) {
水落(YangLei)'s avatar
水落(YangLei) committed
154
    routes.forEach(route => {
wb-ct393452's avatar
wb-ct393452 committed
155
        const meta = route.meta;
水落(YangLei)'s avatar
水落(YangLei) committed
156
        const defaultAuthority = pAuthorities[pAuthorities.length - 1] || { permission: '*' };
wb-ct393452's avatar
wb-ct393452 committed
157 158 159 160
        if (meta) {
            let authority = {};
            if (!meta.authority) {
                authority = defaultAuthority;
水落(YangLei)'s avatar
水落(YangLei) committed
161
            } else if (typeof meta.authority === 'string') {
wb-ct393452's avatar
wb-ct393452 committed
162
                authority.permission = meta.authority;
水落(YangLei)'s avatar
水落(YangLei) committed
163
            } else if (typeof meta.authority === 'object') {
wb-ct393452's avatar
wb-ct393452 committed
164 165
                authority = meta.authority;
                const { role } = authority;
水落(YangLei)'s avatar
水落(YangLei) committed
166
                if (typeof role === 'string') {
wb-ct393452's avatar
wb-ct393452 committed
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
                    authority.role = [role];
                }
                if (!authority.permission && !authority.role) {
                    authority = defaultAuthority;
                }
            }
            meta.authority = authority;
        } else {
            const authority = defaultAuthority;
            route.meta = { authority };
        }
        route.meta.pAuthorities = pAuthorities;
        if (route.children) {
            formatAuthority(route.children, [...pAuthorities, route.meta.authority]);
        }
    });
}

/**
 * 从路由 path 解析 i18n key
 * @param path
 * @returns {*}
 */
function getI18nKey(path) {
水落(YangLei)'s avatar
水落(YangLei) committed
191 192 193
    const keys = path.split('/').filter(item => !item.startsWith(':') && item != '');
    keys.push('name');
    return keys.join('.');
wb-ct393452's avatar
wb-ct393452 committed
194 195 196 197 198 199 200 201 202 203
}

/**
 * 加载导航守卫
 * @param guards
 * @param options
 */
function loadGuards(guards, options) {
    const { beforeEach, afterEach } = guards;
    const { router } = options;
水落(YangLei)'s avatar
水落(YangLei) committed
204 205
    beforeEach.forEach(guard => {
        if (guard && typeof guard === 'function') {
wb-ct393452's avatar
wb-ct393452 committed
206 207 208
            router.beforeEach((to, from, next) => guard(to, from, next, options));
        }
    });
水落(YangLei)'s avatar
水落(YangLei) committed
209 210
    afterEach.forEach(guard => {
        if (guard && typeof guard === 'function') {
wb-ct393452's avatar
wb-ct393452 committed
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
            router.afterEach((to, from) => guard(to, from, options));
        }
    });
}

export {
    parseRoutes,
    loadRoutes,
    formatAuthority,
    getI18nKey,
    loadGuards,
    deepMergeRoutes,
    formatRoutes,
    setAppOptions,
};