vue

vue+element后台系统 自己动手撸(一)权限及动态路由

2020-07-28  本文已影响0人  华子_tm

前言

公司计划改版一个后台管理系统,由于之前是不分离的项目,这次想做成分离项目。前期在技术选择上一直在纠结vue还是react。由于react没有专门的开发人员而且开发学习成本高所以选择了vue+element开发后台项目。

开始

vue+element分为两个Vue-Element-admin(成熟系统)和Vue-Element-Template(基础模板)。由于成熟系统很多功能用不上,所以使用了基础版本去开发。在开发过程中,花裤衩大神的手撸篇对我帮助不小。话不多说了。下面将记录一些自己在开发过程中的问题。

一、axios封装

一个项目对于请求的集中处理很重要。这里我对axios进行了封装以满足项目需求。这里主要对请求参数的类型做了区分,post上传用的form-data,而普通的post请求用的application/json,这里你可以根据自己的项目去封装。
src\utils\request.js

import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
import store from '@/store'
import { getToken } from '@/utils/auth'

// 创建一个AXIOS实例
const service = axios.create({
  // baseURL: process.env.VUE_APP_BASE_API
  // baseURL: 'http://aksdkadsk/api/' // 本地测试地址
})

// 请求拦截器
service.interceptors.request.use(
  config => {
    if (store.getters.token) {
      // 让每个请求携带令牌 “Token”是自定义头密钥
      config.headers['Token'] = getToken()
    }
    if (config.data && config.data.$_isFormData === true) {
      config.headers['Content-Type'] = 'multipart/form-data'
      config.data = config.data.form
    } else {
      config.headers['Content-Type'] = 'application/json'
    }
    return config
  },
  error => {
    return Promise.reject(error)
  }
)

// 响应拦截器
service.interceptors.response.use(
  // 如果您想要获取诸如头或状态之类的http信息 请返回response=>response
  response => {
    let res
    if (typeof (response.data) === 'string') {
      res = JSON.parse(response.data)
    } else if (typeof (response.data) === 'object') {
      res = response.data
    }
    if (res.Statu_Code === '200') {
      return res
    } else if (res.Statu_Code === '100') {
      return res
    } else {
      // 403:令牌过期;
      if (res.Statu_Code === '403') {
        // 重新登录
        MessageBox.confirm(res.Msg, '确认注销', {
          confirmButtonText: '重新登录',
          // cancelButtonText: '取消',
          showCancelButton: false,
          showClose: false,
          type: 'warning'
        }).then(() => {
          store.dispatch('user/resetToken').then(() => {
            location.reload()
          })
        })
        return Promise.reject(new Error(res.Msg || 'Error'))
      } else if (res.Statu_Code === '401') {
        // 重新登录
        MessageBox.confirm(res.Msg, '提示', {
          confirmButtonText: '重新登录',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          store.dispatch('user/resetToken').then(() => {
            location.reload()
          })
        })
        return Promise.reject(new Error(res.Msg || 'Error'))
      } else if (res.Statu_Code === '402') {
        // 重新登录
        MessageBox.confirm(res.Msg, '提示', {
          confirmButtonText: '确定',
          showCancelButton: false,
          type: 'warning'
        })
        return Promise.reject(new Error(res.Msg || 'Error'))
      } else {
        Message({
          message: res.Msg || 'Error',
          type: 'error',
          duration: 2 * 1000,
          offset: 100
        })
        return Promise.reject(new Error(res.Msg || 'Error'))
      }
    }
  },
  error => {
    console.log('err' + error) // for debug
    Message({
      message: error.message,
      type: 'error',
      duration: 2 * 1000,
      offset: 100
    })
    return Promise.reject(error)
  }
)

export default service

登录及权限菜单

一个后台系统的权限是很重要的,这里我们使用了动态路由,也就是按登录人的权限去后台返回对应的菜单,而前台只需要将后端传回的路由进行处理即可。这里主要看下权限处理,只写了路由守卫。
src\permission.js

router.beforeEach(async(to, from, next) => {
  NProgress.start()
  document.title = getPageTitle(to.meta.title)
  // 确定用户是否已登录
  if (getToken()) {
    if (to.path === '/login') {
      // 如果已登录,请重定向到主页
      next({ path: '/' })
      NProgress.done()
    } else {
      const hasGetUserInfo = store.getters.name
      if (hasGetUserInfo) {
        next()
      } else {
        store.dispatch('user/getInfo').then((res) => {
          const reData = {}
          if (res.ROLE_ID.length > 0) {
            reData.ROLE_ID = res.ROLE_ID
          } else {
            reData.ROLE_ID = []
          }
          // 这里去请求路由并处理
          store.dispatch('GenerateRoutes', reData).then(accessRoutes => {
            router.addRoutes([...accessRoutes, {
              path: '*',
              // redirect: '/404',
              component: () => import('@/views/404'),
              hidden: true
            }])
            next({ ...to, replace: true })
          })
          next()
        })
          .catch(error => {
            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) {
      // 在免费登录白名单中,直接进入
      next()
    } else {
      // 没有访问权限的其他页将重定向到登录页。
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
})

再来看看路由处理的关键代码,这里罗列了两种方式。注释掉的是一种。没注释掉的是另一种。
src\store\modules\permission.js

// const _import = require('../../router/_import_' + process.env.NODE_ENV)
import { constantRoutes } from '@/router'
import { getRouters } from '@/api/menu'
import Layout from '@/layout/index'

const permission = {
  state: {
    routes: [],
    addRoutes: []
  },
  mutations: {
    SET_ROUTES: (state, routes) => {
      state.addRoutes = routes
      state.routes = constantRoutes.concat(routes)
    }
  },
  actions: {
    // 生成路由
    GenerateRoutes({ commit }, reData) {
      return new Promise((resolve, reject) => {
        // 向后端请求路由数据
        getRouters(reData).then(res => {
          // console.log(res)
          if (res.Data === null || res.Data === '') {
            res.Data = []
          }
          const accessedRoutes = filterAsyncRouter(res.Data)
          commit('SET_ROUTES', accessedRoutes)
          resolve(accessedRoutes)
        }).catch(error => {
          reject(error)
        })
      })
    }
  }
}

// 遍历后台传来的路由字符串,转换为组件对象
function filterAsyncRouter(asyncRouterMap) {
  const accessedRouters = asyncRouterMap.filter(route => {
    if (route.component) {
      // Layout组件特殊处理
      if (route.component === 'Layout') {
        route.component = Layout
      } else {
        // route.component = _import(route.component)
        route.component = loadView(route.component)
      }
    }
    if (route.children != null && route.children && route.children.length) {
      route.children = filterAsyncRouter(route.children)
    }
    return true
  })
  return accessedRouters
}
// 这种可以正常去处理,页面正常加载
const loadView = (view) => {
  return (resolve) => require([`@/views${view}/`], resolve)
}
// 这种方式如果没有建立对应的文件会报错,并且页面加载不出来
// const loadView = (view) => { // 路由懒加载
//   return () => import(`@/views/${view}`)
// }

export default permission

以上就是我对这歌后台系统的一些踩坑之旅。后面还会更新在开发中遇到的一些问题。

上一篇下一篇

猜你喜欢

热点阅读