diff --git a/src/layout/components/Navbar.vue b/src/layout/components/Navbar.vue index 4eb7cc1..7300708 100644 --- a/src/layout/components/Navbar.vue +++ b/src/layout/components/Navbar.vue @@ -47,7 +47,8 @@ export default { }, async logout() { await this.$store.dispatch('user/logout') - this.$router.push(`/login?redirect=${this.$route.fullPath}`) + // 不进行重定向防止权限问题 ?redirect=${this.$route.fullPath} + this.$router.push(`/login`) } } } diff --git a/src/layout/components/Sidebar/index.vue b/src/layout/components/Sidebar/index.vue index da39034..a11f7a9 100644 --- a/src/layout/components/Sidebar/index.vue +++ b/src/layout/components/Sidebar/index.vue @@ -28,10 +28,11 @@ export default { components: { SidebarItem, Logo }, computed: { ...mapGetters([ + 'permission_routes', 'sidebar' ]), routes() { - return this.$router.options.routes + return this.permission_routes.filter(route => !route.hidden) }, activeMenu() { const route = this.$route diff --git a/src/permission.js b/src/permission.js index fa1ea19..23ba3a7 100644 --- a/src/permission.js +++ b/src/permission.js @@ -11,6 +11,7 @@ NProgress.configure({ showSpinner: false }) // NProgress Configuration const whiteList = ['/login'] // no redirect whitelist router.beforeEach(async(to, from, next) => { + console.log('router.beforeEach from: ', from.path, ', to: ', to.path) // start progress bar NProgress.start() @@ -26,16 +27,23 @@ router.beforeEach(async(to, from, next) => { next({ path: '/' }) NProgress.done() } else { - const hasGetUserInfo = store.getters.name - if (hasGetUserInfo) { + const hasRoles = store.getters.roles && store.getters.roles.length > 0 + if (hasRoles) { next() } else { try { // get user info - await store.dispatch('user/getInfo') - - next() + const { roles } = await store.dispatch('user/getInfo') + console.log('router.beforeEach 当前用户角色:', ...roles) + const accessRoutes = await store.dispatch('permission/generateRoutes', roles) + if (accessRoutes && accessRoutes.length > 0) { + console.log('router.beforeEach 添加动态路由:', accessRoutes) + } + // 动态添加可访问路由 + router.addRoutes(accessRoutes) + next({ ...to, replace: true }) } catch (error) { + console.error('get user role error', error) // remove token and go to login page to re-login await store.dispatch('user/resetToken') Message.error(error || 'Has Error') @@ -51,6 +59,7 @@ router.beforeEach(async(to, from, next) => { // in the free login whitelist, go directly next() } else { + console.log('router.beforeEach 没有token,跳转到登录页面') // other pages that do not have permission to access are redirected to the login page. next(`/login?redirect=${to.path}`) NProgress.done() diff --git a/src/router/index.js b/src/router/index.js index 0b58605..7d3ff53 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -54,69 +54,6 @@ export const constantRoutes = [ meta: { title: '主页', icon: 'dashboard' } }] }, - - { - path: '/teacher', - component: Layout, - redirect: '/teacher/table', - name: 'Example', - meta: { title: '教师', icon: 'el-icon-s-help' }, - children: [ - { - path: 'table', - name: 'Table', - component: () => import('@/views/student/index'), - meta: { title: '学生管理', icon: 'table' } - }, - { - path: 'class', - name: 'Class', - component: () => import('@/views/class/index'), - meta: { title: '班级管理', icon: 'table' } - }, - { - path: 'subject', - name: 'Subject', - component: () => import('@/views/subject/index'), - meta: { title: '科目管理', icon: 'table' } - }, - { - path: 'score', - name: 'Score', - component: () => import('@/views/score/index'), - meta: { title: '成绩管理', icon: 'table' } - } - // { - // path: 'tree', - // name: 'Tree', - // component: () => import('@/views/tree/index'), - // meta: { title: 'Tree', icon: 'tree' } - // } - ] - }, - - { - path: '/student', - component: Layout, - redirect: '/student/query', - name: 'Example', - meta: { title: '学生', icon: 'el-icon-s-help' }, - children: [ - { - path: 'score', - name: 'Score', - component: () => import('@/views/query/index'), - meta: { title: '成绩查询', icon: 'table' } - }, - { - path: 'class', - name: 'Class', - component: () => import('@/views/user/index'), - meta: { title: '个人信息', icon: 'table' } - } - ] - }, - { path: '/form', component: Layout, @@ -227,6 +164,64 @@ export const constantRoutes = [ { path: '*', redirect: '/404', hidden: true } ] +export const asyncRoutes = [ + { + path: '/teacher', + component: Layout, + redirect: '/teacher/table', + name: 'teacher', + meta: { title: '教师', icon: 'el-icon-s-help', roles: ['admin', 'teacher'] }, + children: [ + { + path: 'table', + name: 'Table', + component: () => import('@/views/student/index'), + meta: { title: '学生管理', icon: 'table' } + }, + { + path: 'class', + name: 'Class', + component: () => import('@/views/class/index'), + meta: { title: '班级管理', icon: 'table' } + }, + { + path: 'subject', + name: 'Subject', + component: () => import('@/views/subject/index'), + meta: { title: '科目管理', icon: 'table' } + }, + { + path: 'score', + name: 'Score', + component: () => import('@/views/score/index'), + meta: { title: '成绩管理', icon: 'table' } + } + ] + }, + + { + path: '/student', + component: Layout, + redirect: '/student/query', + name: 'student', + meta: { title: '学生', icon: 'el-icon-s-help', roles: ['student'] }, + children: [ + { + path: 'query', + name: 'query', + component: () => import('@/views/query/index'), + meta: { title: '成绩查询', icon: 'table' } + }, + { + path: 'info', + name: 'info', + component: () => import('@/views/user/index'), + meta: { title: '个人信息', icon: 'table' } + } + ] + } +] + const createRouter = () => new Router({ // mode: 'history', // require service support scrollBehavior: () => ({ y: 0 }), diff --git a/src/store/getters.js b/src/store/getters.js index 5ab7b4c..bb84f0a 100644 --- a/src/store/getters.js +++ b/src/store/getters.js @@ -3,6 +3,9 @@ const getters = { device: state => state.app.device, token: state => state.user.token, avatar: state => state.user.avatar, - name: state => state.user.name + name: state => state.user.name, + roles: state => state.user.roles, + permission_routes: state => state.permission.routes, + addRoutes: state => state.permission.addRoutes } export default getters diff --git a/src/store/index.js b/src/store/index.js index 6be466a..f725a23 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -4,6 +4,7 @@ import getters from './getters' import app from './modules/app' import settings from './modules/settings' import user from './modules/user' +import permission from './modules/permission' Vue.use(Vuex) @@ -11,7 +12,8 @@ const store = new Vuex.Store({ modules: { app, settings, - user + user, + permission }, getters }) diff --git a/src/store/modules/permission.js b/src/store/modules/permission.js new file mode 100644 index 0000000..5bab740 --- /dev/null +++ b/src/store/modules/permission.js @@ -0,0 +1,69 @@ +import { asyncRoutes, constantRoutes } from '@/router' + +/** + * 使用meta.role确定当前用户是否有权限 + * @param roles + * @param route + */ +function hasPermission(roles, route) { + if (route.meta && route.meta.roles) { + return roles.some(role => route.meta.roles.includes(role)) + } else { + return true + } +} + +/** + * 递归过滤异步路由表 + * @param routes asyncRoutes + * @param roles + */ +export function filterAsyncRoutes(routes, roles) { + const res = [] + + 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) + } + commit('SET_ROUTES', accessedRoutes) + resolve(accessedRoutes) + }) + } +} + +export default { + namespaced: true, + state, + mutations, + actions +} diff --git a/src/store/modules/user.js b/src/store/modules/user.js index a48ea75..12306bd 100644 --- a/src/store/modules/user.js +++ b/src/store/modules/user.js @@ -6,7 +6,8 @@ const getDefaultState = () => { return { token: getToken(), name: '', - avatar: '' + avatar: '', + roles: [] } } @@ -27,6 +28,9 @@ const mutations = { }, SET_UID: (state, uid) => { state.uid = uid + }, + SET_ROLES: (state, roles) => { + state.roles = roles } } @@ -75,13 +79,16 @@ const actions = { return new Promise((resolve, reject) => { getInfo().then(response => { const { result } = response - + console.log('getInfo-userInfo', result) if (!result) { return reject('Verification failed, please Login again.') } - const { username, userId } = result - + const { roles, username, userId } = result + if (!roles || roles.length <= 0) { + reject('用户必须至少有一个角色!') + } + commit('SET_ROLES', roles) commit('SET_NAME', username) commit('SET_UID', userId) resolve(result) diff --git a/src/views/class/index.vue b/src/views/class/index.vue index 6903efa..badef02 100644 --- a/src/views/class/index.vue +++ b/src/views/class/index.vue @@ -17,12 +17,12 @@ - + 筛选 - + 新增 diff --git a/src/views/login/index.vue b/src/views/login/index.vue index af132af..f6d004d 100644 --- a/src/views/login/index.vue +++ b/src/views/login/index.vue @@ -44,8 +44,8 @@ Login
- username: admin - password: any + username: 1000、10001、10002 + password: admin、teacher、student
@@ -106,6 +106,8 @@ export default { if (valid) { this.loading = true this.$store.dispatch('user/login', this.loginForm).then(() => { + console.log('login success, this.redirect', this.redirect) + // 固定登录成功后跳转的页面 this.$router.push({ path: this.redirect || '/' }) this.loading = false }).catch(() => { diff --git a/src/views/subject/index.vue b/src/views/subject/index.vue index 4487f88..87b207c 100644 --- a/src/views/subject/index.vue +++ b/src/views/subject/index.vue @@ -20,12 +20,12 @@
- + 筛选 - + 新增