vue element admin 动态菜单_关于vue动态菜单的那点事

vue-element-admin4.0国内节点访问地址:https://panjiachen.gitee.io/vue-element-admin-site/zh/

本此使用的是https://github.com/PanJiaChen/vue-element-admin/tree/i18n 国际化分支的版本。说是除了国际化其他都一样。

本文主要介绍前台动态的使用资源权限。

  • 后台使用springboot2搭建项目就不说了,百度一下一大堆。
  • 前台开发前需要安装一下nodejs,这里注意一下nodejs和npm的版本要相互匹配,否则在编译的时候会报错。

打开项目后需要安装一下依赖的模块。

npm install

  • 1、全局请求配置的修改。

src/utils/request.js 当然也有用src/utils/request-axios.js的 修改方式大同小异zhe'li

import axios from 'axios'// import { MessageBox, Message } from 'element-ui'import { MessageBox, Message } from 'element-ui'import store from '@/store'import { getToken, removeToken } from '@/utils/auth' const qs = require('querystring') create an axios instanceconst service =    axios.create({  baseURL: process.env.VUE_APP_BASE_API,                  url = base url + request url                  withCredentials: true,                  send cookies when cross-domain requests  timeout: 5000,                  request timeout  jsonData: false}) request interceptorservice.interceptors.request.use(    config => {        if (store.getters.token) {          let each request carry token            ['X-Token'] is a custom headers key           please modify it according to the actual situation            config.headers['X-Token'] = getToken()    }         if (config.method.toLowerCase() === 'get') {            config.params = config.data    }    else if (config.method.toLowerCase() === 'post') {            if (config.jsonData) {               config.headers['Content-Type'] = 'application/json;charset=UTF-8'                config.data = JSON.stringify(config.data)      }       else {               config.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'               config.data = qs.stringify(config.data)      }       }       console.log(config) // for debug        return config  },  error => {          // do something with request error         console.log(error)       // for debug          return Promise.reject(error)  }) // response interceptorservice.interceptors.response.use(    /**   * If you want to get http information such as headers or status   *  Please return  response => response   */    /**   * Determine the request status by custom code   * Here is just an example     * You can also judge the status by HTTP Status Code   */  r  esponse => {    const res = response.data    // code==2000是业务逻辑成功,其他的返回code都是业务逻辑错误    if (res.code === 5002) {      // to re-login      // token过期或者密码被修改了都需要重新获取token      MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', {        confirmButtonText: 'Re-Login',        cancelButtonText: 'Cancel',        type: 'warning'      }).then(() => {        store.dispatch('user/resetToken').then(() => {          location.reload()        })      })    } else {      return res    }  },  error => {    // console.log('err' + error) // for debug    Message({      message: error.message,      type: 'error',      duration: 5 * 1000    })    removeToken()    if (error.response && error.response.status === 403) {      this.$router.push(`/login?redirect=${this.$route.fullPath}`)    }    return Promise.reject(error)  }) export default service

这个文件修改的主要是get、post请求传递参数的设置。

get使用params传递参数。post就data

还有就是form数据需要转化,使用qs.stringify来转换。转化成A=1&B=2&c=3这样的形式。

  • 2、后台接口路径的配置。

api请求都放在一个文件下面,这样以后维护比较方便

8a93775d11a4c07445d3b9eec92c4043.png
b190dd793d0722e9c0b6f345665e0ce6.png

至于请求后台方法每个界面一个方法,例如这样

96c44cec69740ca841b652e682888874.png

页面调用方法需要引用,类似这种

88995caaee49163982fa29a5eae76a27.png
export default {  name: 'user-list',  components: { Pagination },  directives: { waves },  filters: {    statusFilter(status) {      const statusMap = {        published: 'success',        draft: 'info',        deleted: 'danger'      }      return statusMap[status]    },    typeFilter(type) {      return calendarTypeKeyValue[type]    }  },  data() {    return {      tableKey: 0,      list: null,      total: 0,      listLoading: true,      listQuery: {        page: 1,        limit: 20,        importance: undefined,        title: undefined,        type: undefined,        username: undefined,        deptname: undefined,        rolename: undefined      },      calendarTypeOptions,      showReviewer: false,      temp: {        id: undefined,        remark: '',        username: '',        rolename: '',        deptid: '',        roleid: '',        password: ''      },      dialogFormVisible: false,      dialogCzmmVisible: false,      dialogStatus: '',      textMap: {        update: '修改用户',        create: '新增用户'      },      pvData: [],      rules: {        username: [{ required: true, message: '必填项', trigger: 'change' }],        loginname: [{ required: true, message: '必填项', trigger: 'change' }],        deptid: [{ required: true, message: '必选项', trigger: 'change' }],        roleid: [{ required: true, message: '必选项', trigger: 'change' }],        password: [{ required: true, message: '必选项', trigger: 'change' }, { min: 6, max: 30, message: '长度在 6 到 30 个字符', trigger: 'change' }]      },      downloadLoading: false,      deptOptions: [],      roleOptions: []    }  },  created() {    this.getList()  },  methods: {    getList() {      this.listLoading = true      fetchList(this.listQuery).then(response => {        debugger        this.list = response.attributes.list.list        this.total = response.attributes.list.total        this.listLoading = false      })    },    handleFilter() {      this.listQuery.page = 1      this.getList()    },    resetTemp() {      this.temp = {        id: undefined,        remark: '',        username: '',        rolename: '',        deptid: '',        roleid: '',        password: ''      }    },    handleCreate() {      this.resetTemp()      this.dialogStatus = 'create'      this.dialogFormVisible = true      this.$nextTick(() => {        this.$refs['dataForm'].clearValidate()      })      fetchRoleOptions().then(response => {        this.roleOptions = response.attributes.list      })      var aa = {        code: 'dept'      }      fetchDicePropOptions(aa).then(response => {        this.deptOptions = response.attributes.list      })    },    createData() {      this.$refs['dataForm'].validate((valid) => {        if (valid) {          const tempData = Object.assign({}, this.temp)          saveSysUser(qs.stringify(tempData)).then(() => {            this.dialogFormVisible = false            this.$notify({              title: '提示',              message: '保存成功!',              type: 'success',              duration: 2000            })            this.getList()          })        }      })    },    handleUpdate(row) {      this.temp = Object.assign({}, row) // copy obj      this.temp.roleid = Number(this.temp.roleid)      this.temp.deptid = Number(this.temp.deptid)      this.dialogStatus = 'update'      this.dialogFormVisible = true      this.$nextTick(() => {        this.$refs['dataForm'].clearValidate()      })      fetchRoleOptions().then(response => {        this.roleOptions = response.attributes.list      })      var aa = {        code: 'dept'      }      fetchDicePropOptions(aa).then(response => {        this.deptOptions = response.attributes.list      })    },    updateData() {      this.$refs['dataForm'].validate((valid) => {        if (valid) {          const tempData = Object.assign({}, this.temp)          updateSysUser(qs.stringify(tempData)).then(() => {            this.dialogFormVisible = false            this.$notify({              title: '提示',              message: '保存成功!',              type: 'success',              duration: 2000            })            this.getList()          })        }      })    },    handleDelete(row, index) {      deleteSysUser(row.id).then(response => {        this.dialogFormVisible = false        this.$notify({          title: '提示',          message: '删除成功!',          type: 'success',          duration: 2000        })        this.getList()      })    },    handleReloadPassword() {      if (this.temp.password === '') {        this.$notify({          title: '提示',          message: '密码不能为空!',          type: 'error',          duration: 2000        })        return      }      var date = {        id: this.temp.id,        password: this.temp.password      }      reloadPassword(date).then(response => {        if (response.code > 0) {          this.dialogCzmmVisible = false          this.$notify({            title: '提示',            message: '重置密码成功!',            type: 'success',            duration: 2000          })        }      })    },    handleRefresh() {      this.listQuery.username = ''      this.listQuery.rolename = ''      this.listQuery.deptname = ''    },    formatJson(filterVal) {      return this.list.map(v => filterVal.map(j => {        if (j === 'timestamp') {          return parseTime(v[j])        } else {          return v[j]        }      }))    },    indexMethod(index) {      return index + 1    },    handleCz(row) {      this.resetTemp()      this.dialogCzmmVisible = true      this.temp.id = row.id      this.$nextTick(() => {        this.$refs['dataFormCx'].clearValidate()      })    }  }}import qs from 'qs'

方法调用就像这种这么做就可以

3 、 登录设置角色信息、过滤路由(根据角色动态的生成菜单)

  • store/user.js
import { loginByPwd, logout, getLoginUserInfo } from '@/api/user'import { getToken, setToken, removeToken } from '@/utils/auth'import router, { resetRouter } from '@/router' const state = {    token: getToken(),    name: '',  avatar: '',   introduction: '',    roles: []} c  onst mutations = {  SET_TOKEN: (state, token) => {    state.token = token  },  SET_INTRODUCTION: (state, introduction) => {    state.introduction = introduction  },  SET_NAME: (state, name) => {    state.name = name  },  SET_AVATAR: (state, avatar) => {    state.avatar = avatar  },  SET_ROLES: (state, roles) => {    state.roles = roles  }} const actions = {  // user login  loginByPwd({ commit }, userInfo) {    const { userName, passWord } = userInfo     return new Promise((resolve, reject) => {      loginByPwd({ userName: userName.trim(), passWord: passWord }).then(response => {        if (response.code === 2000) {          commit('SET_TOKEN', response.data)          setToken(response.data)        }        resolve(response)      }).catch(error => {        reject(error)      })    })  },   // get user info  getLoginUserInfo({ commit, state }) {    return new Promise((resolve, reject) => {      getLoginUserInfo(state.token).then(response => {        // const { data } = response         // console.log('getLoginUserInfo', response)         if (!response) {          reject('Verification failed, please Login again.')        }         if (response.resultFlag) {          commit('SET_ROLES', response.data.roleList)          commit('SET_NAME', response.data.likeName)          commit('SET_AVATAR', response.data.imgUrl)          commit('SET_INTRODUCTION', '我是一个超级管理员哦')          // 一个用户可能有多个角色,这里返回的是角色的集合信息          // let allRole = response.data.roleList           resolve(response)        } else {          console.error('获取当前登录用户信息出错了')        }      }).catch(error => {        reject(error)      })    })  },   // user logout  logout({ commit, state }) {    return new Promise((resolve, reject) => {      logout(state.token).then(() => {        commit('SET_TOKEN', '')        commit('SET_ROLES', [])        removeToken()        resetRouter()        resolve()        location.reload()      }).catch(error => {        reject(error)      })    })  },   // remove token  resetToken({ commit }) {    return new Promise(resolve => {      commit('SET_TOKEN', '')      commit('SET_ROLES', [])      removeToken()      resolve()    })  },   // dynamically modify permissions  changeRoles({ commit, dispatch }, role) {    return new Promise(async resolve => {      const token = role + '-token'       commit('SET_TOKEN', token)      setToken(token)       const { roles } = await dispatch('getInfo')       resetRouter()       // generate accessible routes map based on roles      const accessRoutes = await dispatch('permission/generateRoutes', roles, { root: true })       // dynamically add accessible routes      router.addRoutes(accessRoutes)       // reset visited views and cached views      dispatch('tagsView/delAllViews', null, { root: true })       resolve()    })  }} export default {  // namespaced: true,  state,  mutations,  actions}

这个文件就是登录,成功后获取当前用户拥有的资源信息。

当然下载下来的这个文件菜单权限是写死的是直接使用roles来做的判断,就是在router.js文件中直接把菜单需要的角色设置在里边。

缺点是添加了角色就要修改代码打包发布。这简直是灾难。

所以这里面将原系统修改了一下实现动态菜单读取,就好多了

vue-element-admin-mastersrcouterindex.jsimport Vue from 'vue'import Router from 'vue-router'Vue.use(Router)/* Layout */import Layout from '@/layout'/* Router Modules */// import componentsRouter from './modules/components'// import chartsRouter from './modules/charts'// import tableRouter from './modules/table'// import nestedRouter from './modules/nested'export const constantRoutes = [  {    path: '/redirect',    component: Layout,    hidden: true,    children: [      {        path: '/redirect/:path*',        component: () => import('@/views/redirect/index')      }    ]  },  {    path: '/login',    component: () => import('@/views/login/index'),    hidden: true  },  {    path: '/auth-redirect',    component: () => import('@/views/login/auth-redirect'),    hidden: true  },  {    path: '/',    component: Layout,    redirect: '/dashboard',    children: [      {        path: 'dashboard',        component: () => import('@/views/dashboard/index'),        name: 'Dashboard',        meta: { title: 'dashboard', icon: 'dashboard', affix: true }      }    ]  }]/** * asyncRoutes * the routes that need to be dynamically loaded based on user roles */export const asyncRoutes = [  /** when your routing map is too long, you can split it into small modules **/  // componentsRouter,  // chartsRouter,  // nestedRouter,  // tableRouter,  // 404 page must be placed at the end !!!]const createRouter = () => new Router({  // mode: 'history', // require service support  mode: 'hash',  scrollBehavior: () => ({ y: 0 }),  routes: constantRoutes})const router = createRouter()// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465export function resetRouter() {  const newRouter = createRouter()  router.matcher = newRouter.matcher // reset router}export default router

首先先将静态路由调好,一些常用的不需要权限的先加上

然后找到srcpermission.js

import router, { resetRouter } from '@/router'import store from './store'import { Message } from 'element-ui'import NProgress from 'nprogress' // progress barimport 'nprogress/nprogress.css' // progress bar styleimport { getToken } from '@/utils/auth' // get token from cookieimport getPageTitle from '@/utils/get-page-title'NProgress.configure({ showSpinner: false }) // NProgress Configurationconst whiteList = ['/login', '/auth-redirect'] // no redirect whitelistlet add1 = falseconst matched1 = falserouter.beforeEach(async(to, from, next) => {  // start progress bar  NProgress.start()  // set page title  document.title = getPageTitle(to.meta.title)  // determine whether the user has logged in  const hasToken = getToken()  if (hasToken) {    if (to.path === '/login') {      // if is logged in, redirect to the home page      next({ path: '/' })      NProgress.done()    } else {      // determine whether the user has obtained his permission roles through getInfo      const hasRoles = store.getters.roles && store.getters.roles.length > 0      if (hasRoles) {        next()      } else {        try {          // get user info          // note: roles must be a object array! such as: ['admin'] or ,['developer','editor']          // const { roles } = await store.dispatch('user/getInfo')          // generate accessible routes map based on roles          debugger          // const fromPath = GetUrlRelativePath(window.location.href)          if (!add1) {            //注意在这里,将后台拼装好的功能菜单添加到当前路由中,切记一定要加变量控制            //不然会死循环,如果谁有好的解决办法请回复我谢谢            // router.resetRouter()            let accessRoutes = []            accessRoutes = await store.dispatch('permission/getAuthMenu')             router.addRoutes(accessRoutes)            add1 = true            // hack method to ensure that addRoutes is complete            // set the replace: true, so the navigation will not leave a history record            next({ ...to, replace: true })          } else {            // debugger            // if (to.matched.length === 0) {            //   router.resetRouter()            //   let accessRoutes = []            //   accessRoutes = await store.dispatch('permission/getAuthMenu')            //   router.addRoutes(accessRoutes)            //   next({ ...to, replace: true })            // } else {              next()            // }          }        } catch (error) {          // remove token and go to login page to re-login          await store.dispatch('user/resetToken')          Message.error(error || 'Has Error')          next(`/login?redirect=${to.path}`)          NProgress.done()        }      }    }  } else {    /* has no token*/    if (whiteList.indexOf(to.path) !== -1) {      // in the free login whitelist, go directly      next()    } else {      // other pages that do not have permission to access are redirected to the login page.      next(`/login?redirect=${to.path}`)      NProgress.done()    }  }})export function GetUrlRelativePath(url) {  var arrUrl = url.split('//')  var start = arrUrl[1].indexOf('/')  var relUrl = arrUrl[1].substring(start)  if (relUrl.indexOf('?') !== -1) {    relUrl = relUrl.split('?')[0]  }  return relUrl}router.afterEach(() => {  // finish progress bar  NProgress.done()})
import { asyncRoutes, constantRoutes } from '@/router'const state = {  routes: [],  roles: [],  username: '',  addRoutes: [],  isChange: false}const mutations = {  isChange: (state, isChanged) => {    state.isChange = isChanged  },  SET_USER: (state, username) => {    state.username = username  },  SET_ROLES: (state, roles) => {    state.roles = roles  },  SET_ROUTES: (state, routes) => {    state.addRoutes = routes    state.routes = constantRoutes.concat(routes)  }}export function formatMenus(routes, data) {  data.forEach(item => {    const menu = {}    menu.path = '/' + item.path    menu.name = item.name    menu.component = Layout    menu.redirect = '/'    menu.meta = { title: item.title, icon: 'excel', noCache: false }    if (item.children.length > 0) {      menu.children = []      item.children.forEach(item1 => {              if (item1.name === 'examinationInfo') {          const menu1 = {}          menu1.path = 'detail'          menu1.component = resolve => require(['@/views/' + item1.component + '/' + item1.path + '.vue'], resolve)          menu1.name = 'examinationInfo'          menu1.meta = { title: item1.title, noCache: false, activeMenu: '@/views/Examination/examination' }          menu1.hidden = true          menu.children.push(menu1)        }        else {          const menu1 = {}          menu1.path = item1.path          menu1.component = resolve => require(['@/views/' + item1.component + '/' + item1.path + '.vue'], resolve)          menu1.name = item1.name          menu1.meta = { title: item1.title }          menu.children.push(menu1)        }      })    }    debugger    routes.push(menu)  })}const actions = {  getAuthMenu({ commit }) {    return new Promise(resolve => {      getAuthMenu({}).then(response => {        const data = response.attributes.menus        const roles = response.attributes.rolesgetAuthMenu        const username = response.attributes.username        formatMenus(asyncRoutes, data)        commit('SET_ROUTES', asyncRoutes)        commit('SET_ROLES', roles)        commit('SET_USER', username)        // const isChanged = true        // commit('isChange', isChanged)        asyncRoutes.push({ path: '*', redirect: '/404', hidden: true })        //注意404界面一定要加载最后,不然会报错        resolve(asyncRoutes)      })    })  }}export default {  namespaced: true,  state,  mutations,  actions}import Layout from '@/layout'import { getAuthMenu } from '@/api/user'

在请求头部如果需要添加cookie

b4e5156dca2af15988034076c1298407.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值