vue 后台管理登录权限不同,不同的导航菜单

后台管理不同的权限登录,后台的导航栏显示不同菜单

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>

以上就是全部了,本菜鸟也是第一次写权限方面的,网上百度了好久,参考了好多人的博客才写出来的,有大佬看见和你的有点类似也请见谅,(好不容易搞出来了,很多的博客是看完了就关上了,现在已经不知道参考的哪个了,你要是知道参考的网址,也可以告诉我哦,我再加上),代码上可能有很多不足的地方,欢迎提出,我会及时改正哒。。。大佬要是知道更简单易懂的也麻烦告诉我呀,好让身为菜鸟的我多学习学习,感谢感谢

  • 12
    点赞
  • 107
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值