iview admin目前是沒有給我處理好權限這塊的邏輯。因此,權限這塊仍是得咱們本身去擼。(臉上笑嘻嘻、內心mmp!)前端
作權限,說到底就是爲了讓不一樣權限的用戶, 能夠訪問不一樣的功能模塊。好比我是admin權限, 我就能夠隨心所欲了,你服不服??? 那我若是是隻有某個權限,可能我只能使用某一個或者某幾個功能(也就是前端頁面)。頁面內的具體功能也是同樣的道理,舉個栗子:我是admin權限,我能夠對某個表格進行:增、刪、改、查、上傳等一系列操做。若是我不是,可能就收到權限的限制,只能進行查看和上傳,其餘的功能是無權限進行操做的。好了,大概的思路就是這樣的,光BB誰不會啊;那具體看一下基於iview admin的權限是如何實現。vue
咱們從上面的思路具體分析一下,首先,不一樣用戶能夠訪問不一樣的模塊(頁面),因此咱們要作到不一樣身份的用戶進入系統的時候,就會根據這個用戶的身份顯示不一樣的頁面,顯示不一樣的菜單。咱們的項目正常是路由(router.js)是在本地配置好的一個路由文件,因此,要想實現動態的路由,咱們就必須讓router.js實現動態生成。我選用的方案是vue-router 2.2版本新增了一個router.addRoutes(routes)方法去實現。(可能還有一些「巨佬」是用的其餘方案,'佩服三連')。那用了addRouter方法以後呢,實際上咱們本地的router.js是隻須要一些基本的路由了,其餘均可以刪掉了。感受有點囉嗦了,我先貼代碼壓壓驚吧。node
import Main from '@/components/main' /** * iview-admin中meta除了原生參數外可配置的參數: * meta: { * title: { String|Number|Function } * 顯示在側邊欄、麪包屑和標籤欄的文字 * 使用'{{ 多語言字段 }}'形式結合多語言使用,例子看多語言的路由配置; * 能夠傳入一個回調函數,參數是當前路由對象,例子看動態路由和帶參路由 * hideInBread: (false) 設爲true後此級路由將不會出如今麪包屑中,示例看QQ羣路由配置 * hideInMenu: (false) 設爲true後在左側菜單不會顯示該頁面選項 * notCache: (false) 設爲true後頁面在切換標籤後不會緩存,若是須要緩存,無需設置這個字段,並且須要設置頁面組件name屬性和路由配置的name一致 * access: (null) 可訪問該頁面的權限數組,當前路由設置的權限會影響子路由 * icon: (-) 該頁面在左側菜單、麪包屑和標籤導航處顯示的圖標,若是是自定義圖標,須要在圖標名稱前加下劃線'_' * beforeCloseName: (-) 設置該字段,則在關閉當前tab頁時會去'@/router/before-close.js'裏尋找該字段名對應的方法,做爲關閉前的鉤子函數 * } */ var Router = [{ path: '/', name: '_home', redirect: '/home', component: Main, meta: { icon: 'md-home', title: '首頁', hideInMenu: true }, children: [{ path: '/home', name: 'home', meta: { icon: 'md-home', title: '首頁' }, component: () => import('@/view/home/home.vue') }] }, { path: '/401', name: 'error_401', meta: { hideInMenu: true }, component: () => import('@/view/error-page/401.vue') }, { path: '/500', name: 'error_500', meta: { hideInMenu: true }, component: () => import('@/view/error-page/500.vue') }, { path: '*', name: 'error_404', meta: { hideInMenu: true }, component: () => import('@/view/error-page/404.vue') } ] export default Router吶~ 我本地路由文件只留下了這些基本的路由,!!!那我其餘的路由怎麼辦??--- 不慌,具體的業務路由代碼先不用管,交給addRouter這位兄dei和大家後端的兄dei就行了。你要作的就是拿到後端給你返回的list,而後用addRouter方法添加到router裏就行了。
接下來,你把你以前的路由文件原封不動的ctrl+c給後端的兄dei,就是你刪除掉的那些路由,這裏說明一下:(list的格式必須和router.js裏的格式一致,能夠和後端兄弟商量一下了,讓他幫你把格式造好直接返給你。)
接下來進入關鍵的一步了,終於又能夠貼代碼了!!!
在vuex的app.js我定義了一個獲取router文件的方法:vue-router
getUserRouters({ commit }) { const code = getParams(window.location.href).code return new Promise((resolve, reject) => { try { callBack(code).then(res => { let routers = backendMenusToRouters(res.data.resultData.route) commit('setRouters', routers) setToken(res.data.resultData.token) localSave('dataMenuList',JSON.stringify(res.data.resultData.route)) resolve(res.data.resultData.route) }).catch(err => { reject(err) }) } catch (error) { reject(error) } }) }
ok,我爲何沒有用iview admin的登錄邏輯呢,是由於咱們這邊的登錄會走一個平臺的驗證,公司統一的,其實和iview admin的 差很少的。---- 上面的函數裏,我在本地存了一下路由的文件,後面會用到。vuex
成功拿到路由文件以後,咱們就能夠再main.js裏讓addRouter兄dei登場了。代碼:npm
const token = getToken() const queryCode = getParams(window.location.href).code if (!token && !queryCode) { //調登錄邏輯 } else if (!token && queryCode) { //調用app.js裏的getUserRouters方法 store.dispatch('getUserRouters').then(res => { new Vue({ el: '#app', router, i18n, store, render: h => h(App), mounted() { const routers = backendMenusToRouters(res) router.addRoutes(routers) }, }) }) } else { //若是是登錄過的,後者是正常刷新操做,只要從localStorage裏拿數據就行了 router.addRoutes(backendMenusToRouters(JSON.parse(localRead('dataMenuList')))) new Vue({ el: '#app', router, i18n, store, render: h => h(App) }) }
上面的backendMenusToRouters函數我貼出來,這個函數就是爲了處理路由文件的,路由掛載component是一個函數,因此須要特殊處理。json
/** * @description 將後端菜單樹轉換爲路由樹 * @param {Array} menus * @returns {Array} */ export const backendMenusToRouters = (menus) => { let routers = [] forEach(menus, (menu) => { // 將後端數據轉換成路由數據 let route = backendMenuToRoute(menu) // 若是後端數據有下級,則遞歸處理下級 if (menu.children && menu.children.length !== 0) { route.children = backendMenusToRouters(menu.children) } routers.push(route) }) return routers } /** * @description 將後端菜單轉換爲路由 * @param {Object} menu * @returns {Object} */ const backendMenuToRoute = (menu) => { // 具體內容根據本身的數據結構來定,這裏須要注意的一點是 // 原先routers寫法是component: () => import('@/view/error-page/404.vue') // 通過json數據轉換,這裏會丟失,因此須要按照上面提過的作轉換,下面只寫了核心點,其餘自行處理 let route = Object.assign({}, menu) route.component = resolve => require([`@/${menu.component}`], resolve) return route }
關於處理component須要配置個依賴:
npm install babel-plugin-syntax-dynamic-import後端
.babelrc 增長
{
"plugins": ["syntax-dynamic-import"]
}數組
這裏加一句,vuex裏app.js的menuList方法需作稍稍的小改動:緩存
menuList: (state, getters, rootState) => getMenuByRouter(state.routers, rootState.user.access)
main.vue的menuList賦值:
menuList( ) { return this.$store.getters.menuList },
到這裏,你的動態路由能夠說已經完成了。
那又有同窗問了,那還有一些頁面是子頁面, 不須要在菜單裏顯示怎麼處理???別慌,我喝口水慢慢跟你說。
咱們能夠看一下路由的配置,在meta的對象裏,有個hideInMenu屬性,妥了,那咱們搞起來吧。其實iview admin已經幫我寫好了這塊的邏輯處理,代碼在util.js裏:
/** * @param {Array} list 經過路由列表獲得菜單列表 * @returns {Array} */ export const getMenuByRouter = (list, access) => { let res = [] forEach(list, item => { if (!item.meta || (item.meta && !item.meta.hideInMenu)) { let obj = { icon: (item.meta && item.meta.icon) || '', name: item.name, meta: item.meta } if ((hasChild(item) || (item.meta && item.meta.showAlways))) { obj.children = getMenuByRouter(item.children, access) } if (item.meta && item.meta.href) obj.href = item.meta.href // if (showThisMenuEle(item, access)) res.push(obj) res.push(obj) } }) return res }
-,- ok,大功告成! 慢着... 那若是我想對菜單進行增刪改操做怎麼辦??
好辦!你就前端寫頁面吧,這裏我推薦一個很成熟的方案,我目前項目就是參考他的作的。傳送門:xBoot管理系統
我的認爲他們的菜單管理作的真的很棒!!我又不要臉的借鑑了他們的功能權限,進行了咱們項目的功能權限管理的設計。
首先,每一個角色的具體功能權限是在meta的access裏攜帶進來的,access是一個數組,['del','add'....]我和後端定義好了每一個字段表明什麼功能權限。好比:'del'表明刪除按鈕、'upload'表明上傳功能等等... 當咱們進入不一樣的頁面的時候,根據access的功能列表給用戶設置不一樣的功能權限。這裏是借鑑了網上的實現邏輯,自定義一個指令,而後每一個按鈕根據功能綁定不一樣的字段,作是否remove動做。好了,又開始bb了,貼代碼吧,在libs定義一個hasPermission.js文件:
const hasPermission = { install (Vue, options) { Vue.directive('hasPermission', { inserted (el, binding, vnode) { let permissionList = vnode.context.$route.meta.access; if (!permissionList.includes(binding.value)) { el.remove() } } }); } }; export default hasPermission;
在main.js裏全局定義:
import hasPermission from '@/libs/hasPermission.js' Vue.use(hasPermission)
頁面中具體按鈕的使用:
<Icon type="md-cloud-download" v-hasPermission="'output'" @click="exportTaskExcel" />
注意:綁定的字段必須是字符串格式。具體頁面上的按鈕權限的分配在前端頁面是怎麼控制的,徹底能夠去xBoot裏借鑑。我也不知道我寫的你們看不看得懂,若是看不懂,再多看一遍,再看不懂歡迎留言或者加我QQ互相學習:602353272。最後,再BB一句,有巨佬有更好的方案歡迎賜教!