后台管理不同的权限登录,后台的导航栏显示不同菜单
1.router.js
路由页面的配置
首先路由页面分两块,一块是默认的路由,无论用户的权限是什么,都会访问到的页面,也叫公共路由
另一块是需要用户权限才能查看的某些特定的页面
import Vue from 'vue'
import Router from 'vue-router'
const login=()=>import('@/components/login.vue')
const logon=()=>import('@/components/logon.vue')
const menu=()=>import('@/components/menu/menu.vue')
//...等等引入的页面路径
Vue.use(Router)
//默认的路由
let defaultRouter=[
{
path: '/',
hidden: true,
children: []
},
{
path: '/login',
name: '登录',
hidden: true,
component: login,
children: []
},
{
path: '/logon',
name: '注册',
hidden: true,
component: logon,
children: []
},
{
path: '/404',
name: '404',
hidden: true,
component: page404,
children: []
},
];
//404页面一定要放在最后
//需要权限的路由
let addRouter=[
{
path: '/safe',
name: 'safe',
component: menu,
meta:{title:'安全设置',role: ['user','admin']},//role代表用户的权限(user是一种用户,admin是一种用户)
children:[
{
path: 'safeFit',
name: 'safeFit',
meta:{title:'账号安全',role: ['user','admin']},
component: safeFit,
children: []
}
]
},
{
path: '/admin',
name: 'admin',
component: menu,
meta:{title:'管理员',role: ['admin']},
children:[
{
path: 'addAdmin',
name: 'addAdmin',
meta:{title:'新增管理员',role: ['admin']},
component: addAdmin,
children: []
},
{
path: 'administrators',
name: 'administrators',
meta:{title:'管理员名单',role: ['admin']},
component: administrators,
children: []
},
]
},
{
path: '/roster',
name: 'roster',
component: menu,
meta:{title:'黑白名单',role: ['user','admin']},
children:[
{
path: 'blackList',
name: 'blackList',
meta:{title:'黑名单',role: ['user']},
component: blackList,
children: []
},
{
path: 'whiteList',
name: 'whiteList',
meta:{title:'白名单',role: ['admin']},
component: whiteList,
children: []
},
]
}
];
export default new Router({
routes: defaultRouter
})
export {defaultRouter, addRouter}
2.登录页面
(因公司使用项目,所以贴出了与权限相关项目,其他的没有贴出)
import { mapMutations } from 'vuex';//使用到了状态管理器,下面3有贴出相关代码
import API from '../js/httpConfig';
export default {
data(){
var validatename=(rule, value, callback) => {
if(value===''){
if(this.changeType==2){
callback(new Error('请输入邮箱'));
}else{
callback(new Error('请输入手机号'));
}
}else{
var regEmail = /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/;
var regPhone=/^[1][3,4,5,7,8][0-9]{9}$/;
if(this.changeType==2){
if(regEmail.test(value)){
callback();
}else{
callback(new Error('邮箱输入有误'));
}
}else{
if(regPhone.test(value)){
callback();
}else{
callback(new Error('手机号输入有误'));
}
}
}
}
return {
imgLogo:require('../assets/image/logo.png'),//登录logo
changeType:'2',//选择邮箱或者手机号
phoneHead:'',//号码头
form:{//表单变量
name:'',//用户名
password:'',//密码
},
ruleForm:{//表单值验证
name: [
{validator: validatename, required: true, trigger: 'blur' },
],
password:[
{required: true, message: '请输入密码', trigger: 'blur'},
]
},
options:[
{
label:'1',
value:'1'
}
],
userToken:'',//用户token
}
},
methods:{
...mapMutations('routeJump',['changeLogin']),
submit(name){//登录
var _this=this;
this.$refs[name].validate((valid) => {
if (valid) {
if(this.changeType==1){
this.$axios({
method: 'post',
url: API.userLogin,
data: {
'registerType': this.changeType,
'password': this.form.password,
'phoneNum':this.form.name,
},
headers:{
"Authorization":" "
}
}).then(res => { //res是返回结果
if(res.data.code==0){
_this.userToken=res.data.data.token;
_this.changeLogin({ Authorization:this.userToken});//存到状态管理器里面
sessionStorage.setItem('name',this.form.name);
_this.getUser();//公司原因登录时是两个接口,第一次登录后端只返回了token,getUser是获取用户信息的
}else{
_this.$alert(res.data.msg, '提示', {
confirmButtonText: 'OK',
});
Object.assign(this.$data.form,this.$options.data().form);
}
}).catch(err => {
_this.$alert('服务器崩溃了,请联系管理员'+err, '提示', {
confirmButtonText: 'OK',
});
})
}else{
this.$axios({
method: 'post',
url: API.userLogin,
data: {
'registerType': this.changeType,
'password': this.form.password,
'email':this.form.name,
},
}).then(res => { //res是返回结果
if(res.data.code==0){
_this.userToken=res.data.data;
_this.changeLogin({ Authorization: this.userToken});
_this.getUser();
_this.$router.push('/park')
}else{
_this.$alert(res.data.msg, '提示', {
confirmButtonText: 'OK',
});
Object.assign(this.$data.form,this.$options.data().form);
}
}).catch(err => {
_this.$alert('服务器崩溃了,请联系管理员'+err, '提示', {
confirmButtonText: 'OK',
});
})
}
}
})
},
getUser(){
var _this=this;
this.$axios({
method: 'post',
url: API.getUserMsg,
}).then(res => { //res是返回结果
if(res.data.code==0){
sessionStorage.setItem('id',res.data.data.id);
sessionStorage.setItem('userType',res.data.data.userType);
_this.$router.push({path:'/safe/safeFit'});
}else{
_this.$alert(res.data.msg, '提示', {
confirmButtonText: 'OK',
});
Object.assign(this.$data.form,this.$options.data().form);
}
}).catch(err => {
_this.$alert('服务器崩溃了,请联系管理员'+err, '提示', {
confirmButtonText: 'OK',
});
})
}
}
}
</script>
3.store
状态管理器存储token及权限
index.js
import Vue from 'vue'
import Vuex from 'vuex'
import routeJump from './modules/RouteJump'
import routerData from './modules/routerData'
import role from './modules/role'
Vue.use(Vuex)
const store = new Vuex.Store({
getters: {
addRouters: state => state.routerData.addRouters,
info: state => state.role.info,
routers: state => state.routerData.routers,
token: state => state.routeJump.Authorization,
},
modules: {
routeJump,
routerData,
role
},
})
export default store
routeJump.js
(该页面是token的存储使用)
const state={
openTab: [], // 所有打开的路由
activeIndex: '/', // 激活状态
Authorization: sessionStorage.getItem('Authorization') ? sessionStorage.getItem('Authorization') : ''
}
const mutations={
// 添加tabs
add_tabs (state, data) {
state.openTab.push(data)
},
// 删除tabs
delete_tabs (state, route) {
let index = 0
for (let option of state.openTab) {
if (option.route === route) {
break
}
index++
}
state.openTab.splice(index, 1)
},
// 设置当前激活的tab
set_active_index (state, index) {
state.activeIndex = index
},
// 修改token,并将token存入localStorage
changeLogin (state, user) {
state.Authorization = user.Authorization
// console.log("store---到这里了!");
sessionStorage.setItem('Authorization', user.Authorization);
}
};
const actions={
changeLogin (ctx, Authorization) {
// alert(222)
ctx.commit('changeLogin', Authorization)
}
}
export default {
namespaced:true,//用于在全局引用此文件里的方法时标识这一个的文件名
state,
mutations,
actions
}
routerData.js
(对不同的用户进行路由的筛选)
import {defaultRouter, addRouter} from '@/router/index'
// console.log(addRouter)
const routerData = {
state: {
routers: [],
addRouters: []
},
mutations: {
setRouters: (state, routers) => {
state.addRouters = routers // 保存动态路由用来addRouter
state.routers = defaultRouter.concat(routers) // 所有有权限的路由表,用来生成菜单列表
}
},
actions: {
newRoutes ({commit}, role) {
// 通过递归路由表,删除掉没有权限的路由
function eachSelect (routers, userRole) {
var data=[...routers];
for (let j = 0; j < routers.length; j++) {
if (routers[j].meta && routers[j].meta.role.length>0 && routers[j].meta.role.indexOf(userRole) === -1) {
// console.log(routers[j])
routers.splice(j, 1)
j=j-1;
continue;
}
if (routers[j].children && routers[j].children.length>0) {
eachSelect(routers[j].children, userRole)
}
}
// console.log(routers)
}
eachSelect(addRouter, role)
commit('setRouters', addRouter)
}
}
}
export default routerData
role .js
import store from '../index'
import router from '../../router/index'
export default {
state: {
info: '' // 每次刷新都要通过token请求个人信息来筛选动态路由
},
mutations: {
getInfo (state, info) {
state.info = info
sessionStorage.setItem('info', JSON.stringify(store.getters.info))
},
},
actions: {
getInfo ({commit}, token) {
commit('getInfo', token)
},
}
}
4.main.js
该页面需要引入路由,store
import router from './router'
import store from './store/index'
router.beforeEach((to, from, next) => {
// debugger
if (sessionStorage.getItem('Authorization')) {//因为是后台管理,需要token验证
if (to.path === '/login') {
next()
} else {
if (!store.getters.info.role) {//在登录时把权限存在store里面
!async function getAddRouters () {
if(sessionStorage.getItem('userType')!=1){
await store.dispatch('getInfo', {
role: 'admin',
permissions: '超级管理员'
})
}else{
await store.dispatch('getInfo', {
role: 'user',
permissions: '用户'
})
}
await store.dispatch('newRoutes', store.getters.info.role)
store.getters.addRouters.push({//在动态路由最后追加*为404,若在router.js页面写的话当路由第一次跳转到需要权限的页面时会跳转到404页面
path: '*',
redirect: '/404',
hidden: true,
children: []})
await router.addRoutes(store.getters.addRouters)
if(to.path){
next({path:to.path})
}else{
next({path:'/safe/safeFit'})
}
}()
} else {
next()
}
}
} else {
if (to.path === '/login') {
next()
}else{
next({path: '/login'})
}
}
})
//一定要放在最后
new Vue({
el: '#app',
router,
store,
components: { App },
template: '<App/>'
})
以上是基本的配置,下面还剩menu的渲染了
menu.vue
<template>
<div class="menu park_css">
<div class="head">
<div>
<h1 style="text-align:center">xuperpark.com
<span class="el-icon-s-fold" @click="collapseData"></span>
</h1>
</div>
<div>
<div class="operation">
<div class="el-icon-switch-button logout" @click="logout">登出</div>
<div class="operation_select">
<el-dropdown>
<span class="el-dropdown-link">
{{userName}}
<!-- <i class="el-icon-arrow-down el-icon--right"></i> -->
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>Action 1</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</div>
</div>
<div class="content">
<el-aside :width="isCollapse ? '64px' : '200px'" class="asideCss">
<el-menu
default-active="2"
class="el-menu-vertical-demo"
background-color="#545c64"
text-color="#fff"
:collapse="isCollapse"
active-text-color="#ffd04b">
<fragment v-for="(item,index) in $store.getters.routers" :key="index">
<template v-if="!item.hidden">
<el-submenu v-if="item.children.length>0" :index="item.path">
<template slot="title">
<i class="el-icon-menu"></i>
<span slot="title"> {{item.meta.title}}</span>
</template>
<menu-tree :menuData="item.children" :menuParent="item.path"></menu-tree>
</el-submenu>
<el-menu-item :index="item.path" v-else >
<i class="el-icon-menu"></i>
<span slot="title">{{item.meta.title}}</span>
</el-menu-item>
</template>
</fragment>
</el-menu>
</el-aside>
<el-main class="content_box">
<div class="breadCrumb">
<el-breadcrumb separator=">">
<span class="crumbBox"></span>
<el-breadcrumb-item v-for="item in breadCrumbData" :key="item.path">
<router-link :to="item.path">{{item.title}}</router-link>
</el-breadcrumb-item>
</el-breadcrumb>
</div>
<div class="content_table">
<router-view></router-view>
</div>
</el-main>
</div>
</div>
</template>
<script>
import menuTree from './menuTree'//引入了子组件
export default {
data() {
return {
isCollapse: false,
breadCrumbData:[],//面包屑
userName:'',//用户名
screenWidth:''
};
},
components: {
menuTree,
},
methods: {
collapseData(){//有时候导航隐藏文字不消失或者延迟(此方法是比较省事,偷巧的)
this.isCollapse=!this.isCollapse;
if(this.isCollapse==true){
for(var i in document.querySelectorAll('.el-submenu .el-submenu__title span')){
document.querySelectorAll('.el-submenu .el-submenu__title span')[i].style.visibility='hidden';
}
}
},
},
watch:{
$route(to,from) {
this.path=to.path;
},
screenWidth(val){
this.screenWidth = val;
if(this.screenWidth<1200){
this.isCollapse=true;
}else{
this.isCollapse=false;
}
},
},
mounted(){
this.userName=sessionStorage.getItem('name');
}
}
</script>
<style lang="scss" scoped>
.menu{
height: 100%;
.head{
width: 96%;
height: 60px;
background-color:#57b0e3;
color: #ffffff;
display: flex;
flex: 1;
flex-direction: row;
justify-content:space-between;
padding: 0 2%;
h1{
line-height: 60px;
}
.operation{
div{
display: inline-block;
line-height: 60px;
}
.operation_select{
margin-left: 50px;
.el-dropdown{
color: #ffffff;
}
}
.logout{
cursor: pointer;
}
}
}
.content{
width: 100%;
height: calc(100% - 60px) ;
flex: 1;
flex-direction: row;
display: flex;
.el-menu{
background-color: #1689c9!important;
height: 100%;
li{
width: 100%;
text-align: left;
}
/deep/ .el-submenu__title,.el-menu-item{
color: #ffffff;
background-color: #1689c9 !important;
}
/deep/ .el-submenu__title:hover,.el-submenu__title:active,.el-menu-item:hover,.el-menu-item:active{
background-color: #2e75c3;
}
/deep/ .el-submenu__title i,.el-menu-item i{
color: #ffffff;
}
/deep/ .el-menu{
background-color: #000000;
.el-menu-item{
background-color: #000000!important;
}
.el-menu-item.is-active {
background-color: #2e75c3 !important;
}
}
}
.el-aside{
@media screen and (max-width: 700px) {
width: 64px!important;
}
}
.content_box{
background-color: #eee;
padding: 1%;
.breadCrumb{
background-color: #ffffff;
border-radius:5px;
padding-left: 1%;
position: relative;
div{
height: 35px;
line-height: 35px;
}
.crumbBox{
position: absolute;
display: inline-block;
background-color: #1689c9;
width: 5px;
height: 20px;
top: 8px;
left:5px;
}
}
.content_table{
margin-top: 10px;
height: 90%;
background-color: #ffffff;
}
}
}
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
min-height: 400px;
}
.asideCss{
overflow-x: hidden;
&::-webkit-scrollbar{
width: 5px;
}
&::-webkit-scrollbar-thumb {
border-radius: 10px;
box-shadow: inset 0 0 5px #999;
background-color: #eeeeee;
height: 30px;
}
}
}
</style>
menuTree .vue
<template>
<div>
<div v-for="(child,index) in menuData" :key="index">
<el-submenu v-if="child.children.length > 0" :index="child.path">
<template slot="title">
<span slot="title">{{ child.meta.title }}</span>
</template>
<menu-tree :menuData="child.children" :menuParent="ParentData(child.path,menuParent)"></menu-tree>
</el-submenu>
<el-menu-item v-else-if="!child.hidden" :index="child.path" @click="linkRouter(child.path)">
<span slot="title" >{{ child.meta.title }}</span>
</el-menu-item>
</div>
</div>
</template>
<script>
export default {
name: 'menuTree',
props: ['menuData',"menuParent"],
methods:{
linkRouter(data){
var path=this.menuParent+'/'+data
this.$router.push({path: path})
},
ParentData(current,pre){
return pre+'/'+current
}
},
mounted() {
}
}
</script>
以上就是全部了,本菜鸟也是第一次写权限方面的,网上百度了好久,参考了好多人的博客才写出来的,有大佬看见和你的有点类似也请见谅,(好不容易搞出来了,很多的博客是看完了就关上了,现在已经不知道参考的哪个了,你要是知道参考的网址,也可以告诉我哦,我再加上),代码上可能有很多不足的地方,欢迎提出,我会及时改正哒。。。大佬要是知道更简单易懂的也麻烦告诉我呀,好让身为菜鸟的我多学习学习,感谢感谢