不同的用户,访问管理系统的时候,是具有不同的权限,有些页面是可以访问一些页面不能访问。同时不同用户看到的系统菜单也有可能是不同的。
实现方式是前后端一起控制。 前端把所有的路由全部都列举出来,但是会给每个路由加一个权限的字段,来和后端给的数据做匹配。从而实现A用户登录后,访问A用户能访问的页面,展示A用户的对应的系统菜单。B用户对应B的。
代码实现:
1、配置路由文件
router 文件夹下,建一个routerData.js文件,存放路由数据。
commonRoutes 表示公共路由,和用户权限无关,每个用户都能访问的路由,一般放登录页面。
dynamicRoutes表示动态路由,前端写所有的页面路由在里面,后面改路由会和后端给的数据进行匹配。
js
import layout from '@/layout/index'
export const commonRoutes = [
{
path: '/login',
name: 'login',
component: () => import('@/views/Login.vue')
},
]
const dynamicRoutes = [
{
path: '/',
name: 'layout',
component: layout,
meta: {
title: '-',
permission: [2, 6, 7, 8, 9] //页面权限: 2:出单员、 6:管理岗 (管理权限)、 7:跟单员、 8:管理+出单员、 9:管理+跟单
},
children: [
{
path: '/system-set',
name: 'systemSet',
meta: {
title: '系统设置',
icon: 'li-icon-basic-settings',
permission: [2, 6, 7, 8, 9]
},
component: () => import('@/views/system-set'),
children: [
{
path: '/system-set/account-manage',
name: 'accountManage',
meta: {
title: '账号管理',
hidden: true,
permission: [6]
},
component: () => import('@/views/system-set/account-manage'),
},
{
path: '/system-set/person-center',
name: 'personCenter',
meta: {
title: '个人中心',
permission: [2, 6, 7, 8, 9]
},
component: () => import('@/views/system-set/person-center'),
},
]
}
],
}
]
export default dynamicRoutes
router 文件夹下的入口文件 index.js
js
//导入必要
import Vue from 'vue'
import VueRouter from 'vue-router'
//export defalut 导出的话就不需要{}符号
import dynamicRoutes from "./routerData.js";
//export 普通导出 需要使用{} 来表明导出的是哪个
import { commonRoutes } from "./routerData.js";
//挂载路由
Vue.use(VueRouter) , 才能使用
//匹配动态路由的方法
/**
dynamicRoutesVal:前端完整的动态路由
roleType:用户的权限角色
filter:不会改变原数组,会生成一个新数组,不过也是浅拷贝。(符合条件的被放进新数组里去)
*/
export const permissionRouter = function(dynamicRoutesVal, roleType) {
return dynamicRoutesVal?.filter(item => {
if(item.children){
//疑问?这边有三级路由时,子路由会不会受影响,动态减少
item.children = permissionRouter(item.children, roleType)
}
return item.meta.permission?.includes(roleType)
})
}
const router = new VueRouter({
scrollBehavior: () => ({ y: 0 }),
mode: 'history',
base: process.env.BASE_URL,
routes: commonRoutes
})
export function resetRouter() {
router.matcher = router.matcher // reset router
}
export default router
2、路由权限文件
1、在 utils 文件夹下创建一个 路由权限文件permission.js
js
import store from "@/store/index.js";
import dynamicRoutes from "@/router/routerData";
import router, {permissionRouter} from '@/router/index'
import { Loading,Message } from '@chehejia/liui';
router.beforeEach((to, from, next) => {
// 检查用户是否已登录
const hasToken = store.state.userToken;
// 如果用户已登录,则允许访问目标页面
if (hasToken) {
if(to.path === '/login') {
next()
}else {
const routeList = store.state.addRouters || []
if(routeList.length > 0) {
next()
}else {
const permissionRouterList = permissionRouter(dynamicRoutes, store.state.LiUser.roleCode)
permissionRouterList.map(item => {
router.addRoute(item)
})
store.commit('SET_ROUTERS', permissionRouterList);
next({...to, replace: true}) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave
}
}
} else {
if(to.path === '/login'){
next()
}else{
// 如果用户未登录,则重定向到登录页面
next("/login");
}
}
});
3、使用路由
在项目入口文件,main.js中
js
//导入路由文件
import router from './router'
import './utils/permission.js'
//创建一个vue实例,并使用配置的路由
new Vue({
router,
render: h => h(App)
}).$mount('#app')
4、登录成功拿到数据,加上该用户权限的动态路由
js
import dynamicRoutes from "@/router/routerData";
import router, {permissionRouter} from '@/router/index'
// 生成动态路由
const permissionRouterList = permissionRouter(dynamicRoutes, this.$store.state.LiUser.roleCode)
permissionRouterList.map(item => {
router.addRoute(item)
})
this.$store.commit('SET_ROUTERS', permissionRouterList);
js
mutations: {
SET_ROUTERS: (state,val) => {
state.addRouters = val
state.routers = commonRoutes.concat(val);
storage.set('addRouters', val)
storage.set('routers', commonRoutes.concat(val))
},
}
5、问题: 页面刷新后出现白屏的问题,(你新开一个窗口,输入刚才展示的地址,也是属于页面刷新)。 本质:刷新vue实例重构,路由没有被加上,找不到对应路由,所以页面空白。
问题详细说明: 此次使用loacalStorage实现持续话存储,但这个页面刷新出现白屏没有任何关系。 页面刷新vue实例会被重新构建,你用loacalStorage实现持续话存储,vuex数据问题是可以得到解决。但是vue实例重构,vue-router也会重构,所以动态匹配的路由没有被加到路由上去,所以所访问的url的路由找不到,导致页面空白。
解决方法:
在页面刷新后,重新在上匹配上的路由。 App.vue主组件,每次vue实例创建都会创建App.vue组件。所以我在该组件的created生命周期是重新加上了动态路由,代码如下:
js
<script>
import store from "@/store/index.js";
import dynamicRoutes from "@/router/routerData";
import router, {permissionRouter} from '@/router/index'
export default {
name: 'App',
data() {
return {}
},
created() {
// 页面刷新 生成动态路由
console.log('APP-created');
if (store.state.userToken && store.state.LiUser.roleCode) {
// 生成动态路由
const permissionRouterList = permissionRouter(dynamicRoutes, store.state.LiUser.roleCode)
permissionRouterList.map(item => {
router.addRoute(item)
})
store.commit('SET_ROUTERS', permissionRouterList);
}
}
}
</script>