vue-admin-template后台管理的權限


 

在開發后台管理項目時,多用戶多角色不同權限的場景可以說是非常普遍的。從零開始手寫一個后台,要考慮的東西很多,這里直接拿網上大家比較熟悉的vue-admin-template后台模版來進行改造。

先來看下vue-admin-template這個模版的代碼目錄結構

├── build                      # 構建相關
├── mock                       # 項目mock 模擬數據
├── public                     # 靜態資源
│   │── favicon.ico            # favicon圖標
│   └── index.html             # html模板
├── src                        # 源代碼
│   ├── api                    # 所有請求
│   ├── assets                 # 主題 字體等靜態資源
│   ├── components             # 全局公用組件
│   ├── icons                  # 項目所有 svg icons
│   ├── layout                 # 全局 layout
│   ├── router                 # 路由
│   ├── store                  # 全局 store管理
│   ├── styles                 # 全局樣式
│   ├── utils                  # 全局公用方法
│   ├── views                  # views 所有頁面
│   ├── App.vue                # 入口頁面
│   ├── main.js                # 入口文件 加載組件 初始化等
│   └── permission.js          # 權限管理
├── tests                      # 測試
├── .env.xxx                   # 環境變量配置
├── .eslintrc.js               # eslint 配置項
├── .babelrc                   # babel-loader 配置
├── .travis.yml                # 自動化CI配置
├── vue.config.js              # vue-cli 配置
├── postcss.config.js          # postcss 配置
└── package.json               # package.json

 

login.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

image.png

比如我們用財務這個用戶去登錄一下后台,(先給財務這個角色分配一下權限)

 
image.png

比如給他分配 培訓認證全部的權限
 
image.png

然后管理員登錄后台,只渲染所擁有的權限動態渲染了側邊欄。
 
image.png

補充一下:這里是按鈕權限的設置,全局配置一個指令,到時候
v-permission='['add']'就可以實現按鈕是否顯示。
 
image.png

 

基本上就是這么個東西,先添加菜單,在新建一個角色,再給這個角色分配一下權限,然后在新建個用戶,賬號密碼配置一下,再給這個用戶分配一個角色,最后這個用戶登錄后台,就展示所擁有的權限動態去渲染側邊欄

第二步 : 我們先來啟動一下vue-admin-template這個模版,安裝依賴 cnpm install啟動:npm run dev

 
image.png

 
image.png

可以看到,全是英文的,我是受不了,(英文爛的一逼,看不懂),側邊欄是手寫的英文,刪掉就好了,element-ui 是英文的,這個要改一下配置。

修改路徑  src/main.js
// Vue.use(ElementUI, { locale })
// 如果想要中文版 element-ui,按如下方式聲明
Vue.use(ElementUI) 😄

 

當然要先實現正常登錄,我這里用下真實的登錄接口,修改一下src/api/user.js

 
                      image.png

.env.development
 
                                                  image.png

 

vue.config.js配置反向代理,然后重啟項目

 
image.png


箭頭標注的根據實際情況修改

 
image.png

 

這樣實際是觸發登錄接口了,為啥沒登錄進去呢,因為登錄成功后,會立即觸發getinfo 這個接口,這個接口請求出錯,就會清除token且又回到登錄頁了。
所以接下來要完善getinfo這個接口,先來看下邏輯
1.執行完登錄請求后,會走 permission.js中的邏輯

 
image.png

可以看到getinfo,所以就要完善getinfo這個接口,同樣換成真實的。
 
image.png

store/modules/user.js根據實際情況修改下getinfo這個方法,這里看自己公司要求,我們只是取到昵稱和頭像存起來,也可以在這個方法直接把該用戶所擁有的權限拿到並保存到vuex,建議在起一個接口,模擬的話我先在這個方法里把路由信息寫死,然后在定一個存儲到vuex的方法
const getDefaultState = () => { return { token: getToken(), name: '', avatar: '', menus: "",//新增 } } const mutations = { RESET_STATE: (state) => { Object.assign(state, getDefaultState()) }, SET_TOKEN: (state, token) => { state.token = token }, SET_NAME: (state, name) => { state.name = name }, SET_AVATAR: (state, avatar) => { state.avatar = avatar }, // 新增 SET_MENUS: (state, menus) => { state.menus = menus } } // get user info getInfo({ commit, state }) { return new Promise((resolve, reject) => { getInfo().then(response => { //用戶信息是根據token返回的, //我們把token放到header里自動帶過去了,這里就把state.token刪掉了 const { data } = response if (!data) { return reject('Verification failed, please Login again.') } const { nickname, avatar } = data // 模擬請求數據 const menus = [ { "path": "/system", "redirect": "/menu", "component": "Layout", "meta": { "title": "系統管理", "icon": "form" }, "children": [{ "path": "/menu", "name": "menu", "component": "menu/index", "meta": { "title": "菜單管理", "icon": "table", } }, { "path": "/roles", "name": "roles", "component": "roles/index", "meta": { "title": "角色管理", "icon": "table", } }, { "path": "/administrator", "name": "administrator", "component": "dashboard/index", "meta": { "title": "用戶管理", "icon": "table" } } ] } ] //如果需要404 頁面,請在此處添加 menus.push({ path: "/404", component: "404", hidden: true }, { path: "*", redirect: "/404", hidden: true }) commit('SET_NAME', nickname) commit('SET_AVATAR', avatar) commit("SET_MENUS", menus) // 觸發vuex SET_MENUS 保存路由表到vuex resolve(data) }).catch(error => { reject(error) }) }) }

 

getters.js
const getters = {
  sidebar: state => state.app.sidebar,
  device: state => state.app.device,
  token: state => state.user.token,
  avatar: state => state.user.avatar,
  name: state => state.user.name,
  menus: state => state.user.menus //新增
}
export default

 

 

登錄成功后,可以看到vuex里已經把昵稱和頭像和路由表信息存進去了。

image.png

下面把 router.js中的路由先刪掉,保留必要的路由。
export const constantRoutes = [
  {
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },
  {
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [{
      path: 'dashboard',
      name: 'Dashboard',
      component: () => import('@/views/dashboard/index'),
      meta: { title: 'Dashboard', icon: 'dashboard' }
    }]
  }
]

 

 
 
image.png

繼續,可以看到,后端返給我們的是 "component": "Layout",是一個字符串,我們要把過濾下這段路由表信息,並且addrouter到路由里去,並全局掛載一個global.antRouter ,渲染的時候會用到

先在router這個目錄下新建兩個js文件,開發環境和生產環境導入組件的方式略有不同

_import_development.js

// 開發環境導入組件
module.exports = file => require('@/views/' + file + '.vue').default // vue-loader at least v13.0.0+
 

_import_production.js

// 生產環境導入組件
module.exports = file => () => import('@/views/' + file + '.vue')

然后在permission.js中引入剛創建的js文件

const _import = require('./router/_import_' + process.env.NODE_ENV) // 獲取組件的方法
 

permission.js改造成下面這樣,不明白的地方看注釋

import router from './router'
import store from './store'
import {
  Message
} from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import {
  getToken
} from '@/utils/auth' // get token from cookie
import getPageTitle from '@/utils/get-page-title'
import Layout from '@/layout'
const _import = require('./router/_import_' + process.env.NODE_ENV) // 獲取組件的方法

NProgress.configure({
  showSpinner: false
}) // NProgress Configuration

const whiteList = ['/login'] // no redirect whitelist

router.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 {
      const hasGetUserInfo = store.getters.name
      if (hasGetUserInfo) {
        next()
      } else {
        try {
          // get user info
          await store.dispatch('user/getInfo') // 請求獲取用戶信息
          if (store.getters.menus.length < 1) {
            global.antRouter = []
            next()
          }
          const menus = filterAsyncRouter(store.getters.menus) // 1.過濾路由
          console.log(menus);
          
          router.addRoutes(menus) // 2.動態添加路由
          global.antRouter = menus // 3.將路由數據傳遞給全局變量,做側邊欄菜單渲染工作
          next({
            ...to,
            replace: true
          })
          // next()
        } catch (error) {
          // remove token and go to login page to re-login
          console.log(error);
          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()
    }
  }
})

router.afterEach(() => {
  // finish progress bar
  NProgress.done()
})
// // 遍歷后台傳來的路由字符串,轉換為組件對象
function filterAsyncRouter(asyncRouterMap) {
  const accessedRouters = asyncRouterMap.filter(route => {
    if (route.component) {
      if (route.component === 'Layout') {
        route.component = Layout
      } else {
        route.component = _import(route.component) // 導入組件
      }
    }
    if (route.children && route.children.length) {
      route.children = filterAsyncRouter(route.children)
    }
    return true
  })
  
  return accessedRouters
}

 

 

下面在改造下layout/components/Sidebar/index.vue

computed: {
    ...mapGetters([
      'sidebar'
    ]),
    routes() {
      //return this.$router.options.routes
      return this.$router.options.routes.concat(global.antRouter) //把路由concat進去
    },

這時候登錄成功會報錯


 
image.png

原因就是 沒有提前建好頁面。新建一下路由表內的幾個頁面就行了
然后就成功了 有木有!!


 
image.png



文章轉自:https://www.jianshu.com/p/09b2ac91fa91

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM