赞
踩
json中 除了 :id、parent 字段 以外其他字段都是 vue-router字段,和 router.js 文件json几乎一致
建议 刚开始开发先别 实现这个功能,因为这个功能后续实现 很简单很快,等全部功能开发好,直接把 路由 router.js 路由json 信息保存到数据库直接就可以用了
{ "code": 0, "msg": "请求成功", "data": { "menu": [ { "id": 1,// 这个字段是 数据库表ID "parent": 0, // 父级菜单ID,0 表示为一级菜单,没有父级 "children": [ { "id": 2, "parent": 1, "children": [], "name": "SN管理-SN字典管理", "path": "/dict/index", "component": "use/sn-manage/dict/index", "redirect": "", "meta": { "icon": "edit", "title": "字典管理" }, "hidden": false }, { "id": 3, "parent": 1, "children": [], "name": "SN管理-序列号生成", "path": "/generate/index", "component": "use/sn-manage/generate/index", "redirect": "", "meta": { "icon": "guide", "title": "序列号生成" }, "hidden": false, }, { "id": 8, "parent": 1, "children": [], "name": "SN管理-序列号列表", "path": "/generate/record", "component": "use/sn-manage/generate/record", "meta": { "icon": "user", "title": "序列号列表" }, "hidden": false } ], "name": "SN管理444", "path": "/sn-manage", "component": "Layout", "redirect": "/sn-manage", "meta": { "icon": "dashboard", "title": "SN管理" }, "hidden": false }, { "id": 4, "parent": 0, "children": [ { "id": 5, "parent": 4, "children": [], "name": "管理员列表", "path": "/pmsApi/admin/index", "component": "use/admin/index", "meta": { "icon": "edit", "title": "管理员列表" }, "hidden": false } ], "name": "管理员管理", "path": "/admin-manage", "component": "Layout", "redirect": "/admin-manage", "meta": { "icon": "user", "title": "管理员管理" }, "hidden": false, }, { "id": 9, "parent": 0, "children": [ { "id": 11, "parent": 9, "children": [], "name": "菜单管理", "path": "/system/menu/index", "component": "use/system-manage/menu/index", "meta": { "icon": "tree-table", "title": "菜单管理" }, "hidden": false }, { "id": 12, "parent": 9, "children": [], "name": "操作人员管理", "path": "/system/operator/index", "component": "use/system-manage/operator/index", "meta": { "icon": "list", "title": "操作人员管理" }, "hidden": false } ], "name": "系统管理", "path": "/system", "component": "Layout", "meta": { "icon": "tree", "title": "系统管理" }, "hidden": false, } ] } }
这一步作用是: 把 用户的菜单 json信息保存在 vuex中
修改 user.js, 路径:src/store/modules/user.js
里面有两个方法
方法一:actions 调用的是 login接口

方法二:getInfo 调用的是 info接口

登录成功后,逻辑代码 写在哪个方法都可以,这两个方法都是处理登录成功后的操作
我这边就写在 getinfo 里面
user.js 代码
import { login, logout, getInfo } from '@/api/user' import { getToken, setToken, removeToken } from '@/utils/auth' import router, { resetRouter } from '@/router' import { MessageBox, Message } from 'element-ui' import request from "@/utils/request.js"; const state = { token: getToken(), name: '', avatar: '', introduction: '', roles: [], isSuper: false, // 是否为超级管理员, menu: [], // } const mutations = { SET_MENU: (state, i) =>{ // 管理员菜单 state.menu = i }, SET_IS_SUPER: (state, i) =>{ // 设置是否为超级管理员 state.isSuper = i }, 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 login({ commit }, userInfo) { const { username, password, code } = userInfo return new Promise((resolve, reject) => { login({ username: username.trim(), password: password, code: code }).then(response => { // 验证登录逻辑 console.info('data', response) if(response.code !== 0){ Message({ message: response.msg, type: 'error', duration: 5 * 1000 }) reject({}) } let token = response.data.token; commit('SET_TOKEN', token) setToken(token) resolve() }).catch(error => { console.info('登录异常') reject(error) }) console.info('完成请求登录') }) }, getInfo({ commit, state }) { return new Promise((resolve, reject) => { //此方法是login登陆成功后执行用写死的数据代替返回值,注意框架结构! getInfo(state.token).then(response => { console.info('请求数据', response) const data = { roles: ['admin'], introduction: 'I am a super administrator', avatar: response.data.avatar, name: response.data.name, isSuperAdmin: response.data.isSuperAdmin, // 后端返回的 当前用户是否为超级管理员 menu: response.data.menu // 后端返回的 当前用户 菜单JSON数组 } if (!data) { reject('Verification failed, please Login again.') } const { roles, name, avatar, introduction, isSuperAdmin, menu} = data // roles must be a non-empty array if (!roles || roles.length <= 0) { reject('getInfo: roles must be a non-null array!') } commit('SET_ROLES', roles) commit('SET_NAME', name) commit('SET_AVATAR', avatar) commit('SET_INTRODUCTION', introduction) // 把 是否为超级管理员保存到 vuex中 commit('SET_IS_SUPER', isSuperAdmin) // 把 菜单JSON数组 保存到 vuex中 commit('SET_MENU', menu) resolve(data) }).catch(error => { reject(error) }) }) }, // user logout logout({ commit, state, dispatch }) { return new Promise((resolve, reject) => { logout(state.token).then(() => { commit('SET_TOKEN', '') commit('SET_ROLES', []) removeToken() resetRouter() // reset visited views and cached views // to fixed https://github.com/PanJiaChen/vue-element-admin/issues/2485 dispatch('tagsView/delAllViews', null, { root: true }) resolve() }).catch(error => { reject(error) }) }) }, // remove token resetToken({ commit }) { return new Promise(resolve => { commit('SET_TOKEN', '') commit('SET_ROLES', []) removeToken() resolve() }) }, // dynamically modify permissions async changeRoles({ commit, dispatch }, role) { 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 }) } } export default { namespaced: true, state, mutations, actions }
文件路径: src/store/modules/permission.js
这一步是最后一步,拿到vuex保存的 当前用户菜单JSON数组,实现 动态路由
重点 是 filterAsyncRouter 方法
permission.js 代码
import { asyncRoutes, constantRoutes } from '@/router' import store from '@/store' import Layout from '@/layout' import request from '@/utils/request' /** * Use meta.role to determine if the current user has permission * @param roles * @param route */ function hasPermission(roles, route) { console.info('hasPermission') if (route.meta && route.meta.roles) { return roles.some(role => route.meta.roles.includes(role)) } else { return true } } /** * Filter asynchronous routing tables by recursion * @param routes asyncRoutes * @param roles */ export function filterAsyncRoutes(routes, roles) { const res = [] console.info('filterAsyncRoutes') routes.forEach(route => { const tmp = { ...route } if (hasPermission(roles, tmp)) { if (tmp.children) { tmp.children = filterAsyncRoutes(tmp.children, roles) } res.push(tmp) } }) return res } const state = { routes: [], addRoutes: [] } const mutations = { SET_ROUTES: (state, routes) => { state.addRoutes = routes state.routes = constantRoutes.concat(routes) } } const actions = { generateRoutes({ commit }, roles) { return new Promise(resolve => { let accessedRoutes if (roles.includes('admin')) { accessedRoutes = asyncRoutes || [] } else { accessedRoutes = filterAsyncRoutes(asyncRoutes, roles) } let isSuper = store.state.user.isSuper console.info('当前登录用户是否为超级管理员', isSuper) let userRoutes = [] if (isSuper === false) { // 不是超级管理员 userRoutes = filterAsyncRouter(store.state.user.menu) commit('SET_ROUTES', userRoutes) resolve(userRoutes) }else{ // 超级管理员,全部权限 userRoutes = accessedRoutes commit('SET_ROUTES', userRoutes) resolve(userRoutes) } console.info('设置动态菜单权限', userRoutes) }) } } /** * 获取一个字符串值在指定字符串第n次出现的位置 * @param str 字符串 * @param cha 查找的字符 * @param num 第一次出现, 从0开始 * @returns {*} */ function find(str, cha, num) { var x = str.indexOf(cha) for (var i = 0; i < num; i++) { x = str.indexOf(cha, x + 1) } return x } /** * 将 用户菜单JSON信息 转换为 router 可识别的路由json信息 * @param t 管理员菜单JSON数组 * @returns {*} */ function filterAsyncRouter(t) { t.filter(index => { if (index.component === 'Layout') { index.component = Layout } else { // 不是路由菜单,转换对应 vue组件 // @/views/sn-manage/dict/index let component = index.component console.info(component) // /** * 截取 示例 @/views/sn-manage/dict/index 截取出 @/viesw/ 以外的字符,因为 拼接会异常 * 新逻辑: 创建页面的时候去掉 @/viesw/ * @type {*|string} * let test = component.substr(find(component, '/', 1) + 1) */ index.component = require(`@/views/${component}.vue`).default } // 递归子菜单 if (index.children && index.children.length) { index.children = filterAsyncRouter(index.children) } return true }) return t } export default { namespaced: true, state, mutations, actions }
这是我在 vue-element-admin 的基础上只修改了登录页面ui风格、PWA应用支持、动态权限实现,用于方便套过来使用,不需要再次去改


Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。