From 192d4f243d033465ecefc88a1e557cc893a41741 Mon Sep 17 00:00:00 2001 From: iczer <1126263215@qq.com> Date: Fri, 28 Aug 2020 12:25:28 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20config=20of=20async=20router=20and?= =?UTF-8?q?=20guards=20of=20router;=20:star2:=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=EF=BC=9A=E5=BC=82=E6=AD=A5=E8=B7=AF=E7=94=B1=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=92=8C=E8=B7=AF=E7=94=B1=E5=AE=88=E5=8D=AB=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/bootstrap.js | 8 +- src/router/{ => async}/config.async.js | 0 src/router/async/router.map.js | 154 +++++++++++++++++++++++++ src/router/guards.js | 44 +++++++ src/router/index.js | 2 +- src/router/router.map.js | 59 ---------- src/utils/authority-utils.js | 50 ++++++++ src/utils/routerUtil.js | 106 ++++------------- src/utils/util.js | 14 +++ 9 files changed, 289 insertions(+), 148 deletions(-) rename src/router/{ => async}/config.async.js (100%) create mode 100644 src/router/async/router.map.js create mode 100644 src/router/guards.js delete mode 100644 src/router/router.map.js create mode 100644 src/utils/authority-utils.js diff --git a/src/bootstrap.js b/src/bootstrap.js index 6f779af..a101681 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -1,5 +1,6 @@ -import {loadRoutes, loginGuard, authorityGuard} from '@/utils/routerUtil' +import {loadRoutes, loadGuards} from '@/utils/routerUtil' import {loadInterceptors} from '@/utils/request' +import guards from '@/router/guards' import interceptors from '@/utils/axios-interceptors' /** @@ -14,9 +15,8 @@ function bootstrap({router, store, i18n, message}) { loadInterceptors(interceptors, {router, store, i18n, message}) // 加载路由 loadRoutes({router, store, i18n}) - // 添加路由守卫 - loginGuard(router) - authorityGuard(router, store) + // 加载路由守卫 + loadGuards(guards, {router, store, i18n, message}) } export default bootstrap diff --git a/src/router/config.async.js b/src/router/async/config.async.js similarity index 100% rename from src/router/config.async.js rename to src/router/async/config.async.js diff --git a/src/router/async/router.map.js b/src/router/async/router.map.js new file mode 100644 index 0000000..ebf3684 --- /dev/null +++ b/src/router/async/router.map.js @@ -0,0 +1,154 @@ +// 视图组件 +const view = { + tabs: () => import('@/layouts/tabs'), + blank: () => import('@/layouts/BlankView'), + page: () => import('@/layouts/PageView') +} + +// 路由组件注册 +const routerMap = { + login: { + authority: '*', + path: '/login', + component: () => import('@/pages/login') + }, + root: { + path: '/', + name: '首页', + redirect: '/login', + component: view.tabs + }, + dashboard: { + name: 'Dashboard', + component: view.blank + }, + workplace: { + name: '工作台', + component: () => import('@/pages/dashboard/workplace') + }, + analysis: { + name: '分析页', + component: () => import('@/pages/dashboard/analysis') + }, + form: { + name: '表单页', + icon: 'form', + component: view.page + }, + basicForm: { + path: 'basic', + name: '基础表单', + component: () => import('@/pages/form/basic') + }, + stepForm: { + path: 'step', + name: '分步表单', + component: () => import('@/pages/form/step') + }, + advanceForm: { + path: 'advance', + name: '高级表单', + component: () => import('@/pages/form/advance') + }, + list: { + name: '列表页', + icon: 'table', + component: view.page + }, + queryList: { + path: 'query', + name: '查询表格', + component: () => import('@/pages/list/QueryList') + }, + primaryList: { + path: 'primary', + name: '标准列表', + component: () => import('@/pages/list/StandardList') + }, + cardList: { + path: 'card', + name: '卡片列表', + component: () => import('@/pages/list/CardList') + }, + searchList: { + path: 'search', + name: '搜索列表', + component: () => import('@/pages/list/search/SearchLayout') + }, + article: { + name: '文章', + component: () => import('@/pages/list/search/ArticleList') + }, + application: { + name: '应用', + component: () => import('@/pages/list/search/ApplicationList') + }, + project: { + name: '项目', + component: () => import('@/pages/list/search/ProjectList') + }, + details: { + name: '详情页', + icon: 'profile', + component: view.blank + }, + basicDetails: { + path: 'basic', + name: '基础详情页', + component: () => import('@/pages/detail/BasicDetail') + }, + advanceDetails: { + path: 'advance', + name: '高级详情页', + component: () => import('@/pages/detail/AdvancedDetail') + }, + result: { + name: '结果页', + icon: 'check-circle-o', + component: view.page + }, + success: { + name: '成功', + component: () => import('@/pages/result/Success') + }, + error: { + name: '失败', + component: () => import('@/pages/result/Error') + }, + exception: { + name: '异常页', + icon: 'warning', + component: view.blank + }, + exp403: { + authority: '*', + name: 'exp403', + path: '403', + component: () => import('@/pages/exception/403') + }, + exp404: { + name: 'exp404', + path: '404', + component: () => import('@/pages/exception/404') + }, + exp500: { + name: 'exp500', + path: '500', + component: () => import('@/pages/exception/500') + }, + components: { + name: '小组件', + icon: 'appstore-o', + component: view.page + }, + taskCard: { + name: '任务卡片', + component: () => import('@/pages/components/TaskCard') + }, + palette: { + name: '颜色复选框', + component: () => import('@/pages/components/Palette') + } +} +export default routerMap + diff --git a/src/router/guards.js b/src/router/guards.js new file mode 100644 index 0000000..b8719f9 --- /dev/null +++ b/src/router/guards.js @@ -0,0 +1,44 @@ +import {hasPermission, hasRole} from '@/utils/authority-utils' +import {loginIgnore} from '@/router/index' +import {checkAuthorization} from '@/utils/request' + +/** + * 登录守卫 + * @param to + * @param form + * @param next + * @param options + */ +const loginGuard = (to, from, next, options) => { + const {message} = options + if (!loginIgnore.includes(to) && !checkAuthorization()) { + message.warning('登录已失效,请重新登录') + next({path: '/login'}) + } else { + next() + } +} + +/** + * 权限守卫 + * @param to + * @param form + * @param next + * @param options + */ +const authorityGuard = (to, from, next, options) => { + const {store, message} = options + const permissions = store.getters['account/permissions'] + const roles = store.getters['account/roles'] + if (!hasPermission(to, permissions) && !hasRole(to, roles)) { + message.warning(`对不起,您无权访问页面: ${to.fullPath},请联系管理员`) + next({path: '/403'}) + } else { + next() + } +} + +export default { + beforeEach: [loginGuard, authorityGuard], + afterEach: [] +} diff --git a/src/router/index.js b/src/router/index.js index 06b0ea3..3bdcc3c 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -24,7 +24,7 @@ const loginIgnore = { * @returns {VueRouter} */ function initRouter(isAsync) { - const options = isAsync ? require('./config.async').default : require('./config').default + const options = isAsync ? require('./async/config.async').default : require('./config').default formatAuthority(options.routes) return new Router(options) } diff --git a/src/router/router.map.js b/src/router/router.map.js deleted file mode 100644 index 1132ff2..0000000 --- a/src/router/router.map.js +++ /dev/null @@ -1,59 +0,0 @@ -// 视图组件 -const view = { - tabs: () => import('@/layouts/tabs'), - blank: () => import('@/layouts/BlankView'), - page: () => import('@/layouts/PageView') -} - -// 路由组件注册 -const routerMap = { - login: { - authority: '*', - path: '/login', - component: () => import('@/pages/login') - }, - demo: { - name: '演示页', - renderMenu: false, - component: () => import('@/pages/demo') - }, - exp403: { - authority: '*', - name: 'exp403', - path: '403', - component: () => import('@/pages/exception/403') - }, - exp404: { - name: 'exp404', - path: '404', - component: () => import('@/pages/exception/404') - }, - exp500: { - name: 'exp500', - path: '500', - component: () => import('@/pages/exception/500') - }, - root: { - path: '/', - name: '首页', - redirect: '/login', - component: view.tabs - }, - parent1: { - name: '父级路由1', - icon: 'dashboard', - component: view.blank - }, - parent2: { - name: '父级路由2', - icon: 'form', - component: view.page - }, - exception: { - name: '异常页', - icon: 'warning', - component: view.blank - } -} -export default routerMap - diff --git a/src/utils/authority-utils.js b/src/utils/authority-utils.js new file mode 100644 index 0000000..48dd2ea --- /dev/null +++ b/src/utils/authority-utils.js @@ -0,0 +1,50 @@ +/** + * 判断是否有路由的权限 + * @param route 路由 + * @param permissions 用户权限集合 + * @returns {boolean|*} + */ +function hasPermission(route, permissions) { + const authority = route.meta.authority || '*' + let required = '*' + if (typeof authority === 'string') { + required = authority + } else if (typeof authority === 'object') { + required = authority.permission + } + return required === '*' || (permissions && permissions.findIndex(item => item === required || item.id === required) !== -1) +} + +/** + * 判断是否有路由需要的角色 + * @param route 路由 + * @param roles 用户角色集合 + */ +function hasRole(route, roles) { + const authority = route.meta.authority || '*' + let required = undefined + if (typeof authority === 'object') { + required = authority.role + } + return authority === '*' || hasAnyRole(required, roles) +} + +/** + * 判断是否有需要的任意一个角色 + * @param required {String | Array[String]} 需要的角色,可以是单个角色或者一个角色数组 + * @param roles 拥有的角色 + * @returns {boolean} + */ +function hasAnyRole(required, roles) { + if (!required) { + return false + } else if(Array.isArray(required)) { + return roles.findIndex(role => { + return required.findIndex(item => item === role || item === role.id) !== -1 + }) !== -1 + } else { + return roles.findIndex(role => role === required || role.id === required) !== -1 + } +} + +export {hasPermission, hasRole} diff --git a/src/utils/routerUtil.js b/src/utils/routerUtil.js index 39355a1..7fc9160 100644 --- a/src/utils/routerUtil.js +++ b/src/utils/routerUtil.js @@ -1,8 +1,6 @@ -import routerMap from '@/router/router.map' +import routerMap from '@/router/async/router.map' import {mergeI18nFromRoutes} from '@/utils/i18n' import Router from 'vue-router' -import {loginIgnore} from '@/router' -import {checkAuthorization} from '@/utils/request' /** * 根据 路由配置 和 路由组件注册 解析路由 @@ -97,86 +95,6 @@ function mergeRoutes(target, source) { return Object.values(routesMap) } -/** - * 登录守卫 - * @param router 应用路由实例 - */ -function loginGuard(router) { - router.beforeEach((to, from, next) => { - if (!loginIgnore.includes(to) && !checkAuthorization()) { - next({path: '/login'}) - } else { - next() - } - }) -} - -/** - * 权限守卫 - * @param router 应用路由实例 - * @param store 应用的 vuex.store 实例 - */ -function authorityGuard(router, store) { - router.beforeEach((to, form, next) => { - const permissions = store.getters['account/permissions'] - const roles = store.getters['account/roles'] - if (!hasPermission(to, permissions) && !hasRole(to, roles)) { - next({path: '/403'}) - } else { - next() - } - }) -} - -/** - * 判断是否有路由的权限 - * @param route 路由 - * @param permissions 用户权限集合 - * @returns {boolean|*} - */ -function hasPermission(route, permissions) { - const authority = route.meta.authority || '*' - let required = '*' - if (typeof authority === 'string') { - required = authority - } else if (typeof authority === 'object') { - required = authority.permission - } - return required === '*' || (permissions && permissions.findIndex(item => item === required || item.id === required) !== -1) -} - -/** - * 判断是否有路由需要的角色 - * @param route 路由 - * @param roles 用户角色集合 - */ -function hasRole(route, roles) { - const authority = route.meta.authority || '*' - let required = undefined - if (typeof authority === 'object') { - required = authority.role - } - return authority === '*' || hasAnyRole(required, roles) -} - -/** - * 判断是否有需要的任意一个角色 - * @param required {String | Array[String]} 需要的角色,可以是单个角色或者一个角色数组 - * @param roles 拥有的角色 - * @returns {boolean} - */ -function hasAnyRole(required, roles) { - if (!required) { - return false - } else if(Array.isArray(required)) { - return roles.findIndex(role => { - return required.findIndex(item => item === role || item === role.id) !== -1 - }) !== -1 - } else { - return roles.findIndex(role => role === required || role.id === required) !== -1 - } -} - /** * 格式化路由的权限配置 * @param routes @@ -222,4 +140,24 @@ function getI18nKey(path) { return keys.join('.') } -export {parseRoutes, loadRoutes, loginGuard, authorityGuard, formatAuthority, getI18nKey} +/** + * 加载导航守卫 + * @param guards + * @param options + */ +function loadGuards(guards, options) { + const {beforeEach, afterEach} = guards + const {router} = options + beforeEach.forEach(guard => { + if (guard && typeof guard === 'function') { + router.beforeEach((to, from, next) => guard(to, from, next, options)) + } + }) + afterEach.forEach(guard => { + if (guard && typeof guard === 'function') { + router.afterEach((to, from) => guard(to, from, options)) + } + }) +} + +export {parseRoutes, loadRoutes, formatAuthority, getI18nKey, loadGuards} diff --git a/src/utils/util.js b/src/utils/util.js index 96b965c..4fb219e 100644 --- a/src/utils/util.js +++ b/src/utils/util.js @@ -1,3 +1,5 @@ +import enquireJs from 'enquire.js' + export function isDef (v){ return v !== undefined && v !== null } @@ -18,4 +20,16 @@ export function isRegExp (v) { return _toString.call(v) === '[object RegExp]' } +export function enquireScreen(call) { + const handler = { + match: function () { + call && call(true) + }, + unmatch: function () { + call && call(false) + } + } + enquireJs.register('only screen and (max-width: 767.99px)', handler) +} + const _toString = Object.prototype.toString