Skip to content
38 changes: 38 additions & 0 deletions src/api/role.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import request from '@/utils/request'

export function getRoutes() {
return request({
url: '/routes',
method: 'get'
})
}

export function getRoles() {
return request({
url: '/roles',
method: 'get'
})
}

export function deleteRole(id) {
return request({
url: `/roles/${id}`,
method: 'delete'
})
}

export function addRole(data) {
return request({
url: '/roles',
method: 'post',
data
})
}

export function updateRole(key, data) {
return request({
url: `/roles/${key}`,
method: 'put',
data
})
}
24 changes: 12 additions & 12 deletions src/components/HeaderSearch/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,19 @@ export default {
}
},
computed: {
routers() {
return this.$store.getters.permission_routers
routes() {
return this.$store.getters.permission_routes
},
lang() {
return this.$store.getters.language
}
},
watch: {
lang() {
this.searchPool = this.generateRouters(this.routers)
this.searchPool = this.generateRoutes(this.routes)
},
routers() {
this.searchPool = this.generateRouters(this.routers)
routes() {
this.searchPool = this.generateRoutes(this.routes)
},
searchPool(list) {
this.initFuse(list)
Expand All @@ -59,7 +59,7 @@ export default {
}
},
mounted() {
this.searchPool = this.generateRouters(this.routers)
this.searchPool = this.generateRoutes(this.routes)
},
methods: {
click() {
Expand Down Expand Up @@ -100,10 +100,10 @@ export default {
},
// Filter out the routes that can be displayed in the sidebar
// And generate the internationalized title
generateRouters(routers, basePath = '/', prefixTitle = []) {
generateRoutes(routes, basePath = '/', prefixTitle = []) {
let res = []

for (const router of routers) {
for (const router of routes) {
// skip hidden router
if (router.hidden) { continue }

Expand All @@ -125,11 +125,11 @@ export default {
}
}

// recursive child routers
// recursive child routes
if (router.children) {
const tempRouters = this.generateRouters(router.children, data.path, data.title)
if (tempRouters.length >= 1) {
res = [...res, ...tempRouters]
const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
if (tempRoutes.length >= 1) {
res = [...res, ...tempRoutes]
}
}
}
Expand Down
8 changes: 7 additions & 1 deletion src/lang/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export default {
guide: 'Guide',
permission: 'Permission',
pagePermission: 'Page Permission',
rolePermission: 'Role Permission',
directivePermission: 'Directive Permission',
icons: 'Icons',
components: 'Components',
Expand Down Expand Up @@ -86,9 +87,14 @@ export default {
github: 'Github Repository'
},
permission: {
addRole: 'New Role',
editPermission: 'Edit Permission',
roles: 'Your roles',
switchRoles: 'Switch roles',
tips: 'In some cases it is not suitable to use v-permission, such as element Tab component or el-table-column and other asynchronous rendering dom cases which can only be achieved by manually setting the v-if.'
tips: 'In some cases it is not suitable to use v-permission, such as element Tab component or el-table-column and other asynchronous rendering dom cases which can only be achieved by manually setting the v-if.',
delete: 'Delete',
confirm: 'Confirm',
cancel: 'Cancel'
},
guide: {
description: 'The guide page is useful for some people who entered the project for the first time. You can briefly introduce the features of the project. Demo is based on ',
Expand Down
8 changes: 7 additions & 1 deletion src/lang/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export default {
documentation: 'Documentación',
guide: 'Guía',
permission: 'Permisos',
rolePermission: 'Permisos de rol',
pagePermission: 'Permisos de la página',
directivePermission: 'Permisos de la directiva',
icons: 'Iconos',
Expand Down Expand Up @@ -86,9 +87,14 @@ export default {
github: 'Repositorio Github'
},
permission: {
addRole: 'Nuevo rol',
editPermission: 'Permiso de edición',
roles: 'Tus permisos',
switchRoles: 'Cambiar permisos',
tips: 'In some cases it is not suitable to use v-permission, such as element Tab component or el-table-column and other asynchronous rendering dom cases which can only be achieved by manually setting the v-if.'
tips: 'In some cases it is not suitable to use v-permission, such as element Tab component or el-table-column and other asynchronous rendering dom cases which can only be achieved by manually setting the v-if.',
delete: 'Borrar',
confirm: 'Confirmar',
cancel: 'Cancelar'
},
guide: {
description: 'The guide page is useful for some people who entered the project for the first time. You can briefly introduce the features of the project. Demo is based on ',
Expand Down
8 changes: 7 additions & 1 deletion src/lang/zh.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export default {
documentation: '文档',
guide: '引导页',
permission: '权限测试页',
rolePermission: '角色权限',
pagePermission: '页面权限',
directivePermission: '指令权限',
icons: '图标',
Expand Down Expand Up @@ -86,9 +87,14 @@ export default {
github: 'Github 地址'
},
permission: {
addRole: '新增角色',
editPermission: '编辑权限',
roles: '你的权限',
switchRoles: '切换权限',
tips: '在某些情况下,不适合使用 v-permission。例如:Element-UI 的 Tab 组件或 el-table-column 以及其它动态渲染 dom 的场景。你只能通过手动设置 v-if 来实现。'
tips: '在某些情况下,不适合使用 v-permission。例如:Element-UI 的 Tab 组件或 el-table-column 以及其它动态渲染 dom 的场景。你只能通过手动设置 v-if 来实现。',
delete: '删除',
confirm: '确定',
cancel: '取消'
},
guide: {
description: '引导页对于一些第一次进入项目的人很有用,你可以简单介绍下项目的功能。本 Demo 是基于',
Expand Down
8 changes: 8 additions & 0 deletions src/mock/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import loginAPI from './login'
import articleAPI from './article'
import remoteSearchAPI from './remoteSearch'
import transactionAPI from './transaction'
import roleAPI from './role'

// 修复在使用 MockJS 情况下,设置 withCredentials = true,且未被拦截的跨域请求丢失 Cookies 的问题
// https://github.com/nuysoft/Mock/issues/300
Expand All @@ -23,6 +24,13 @@ Mock.mock(/\/login\/login/, 'post', loginAPI.loginByUsername)
Mock.mock(/\/login\/logout/, 'post', loginAPI.logout)
Mock.mock(/\/user\/info\.*/, 'get', loginAPI.getUserInfo)

// 角色相关
Mock.mock(/\/routes/, 'get', roleAPI.getRoutes)
Mock.mock(/\/roles/, 'get', roleAPI.getRoles)
Mock.mock(/\/roles$/, 'post', roleAPI.addRole)
Mock.mock(/\/roles\/[A-Za-z0-9]+/, 'put', roleAPI.updateRole)
Mock.mock(/\/roles\/[A-Za-z0-9]+/, 'delete', roleAPI.deleteRole)

// 文章相关
Mock.mock(/\/article\/list/, 'get', articleAPI.getList)
Mock.mock(/\/article\/detail/, 'get', articleAPI.getArticle)
Expand Down
61 changes: 61 additions & 0 deletions src/mock/role.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import Mock from 'mockjs'
import { deepClone } from '@/utils'
import { filterAsyncRoutes } from '@/store/modules/permission'
import { asyncRoutes, constantRoutes } from '@/router'

const routes = deepClone([...constantRoutes, ...asyncRoutes])

const roles = [
{
key: 'admin',
name: 'admin',
description: 'Super Administrator. Have access to view all pages.',
routes: routes
},
{
key: 'editor',
name: 'editor',
description: 'Normal Editor. Can see all pages except permission page',
routes: filterAsyncRoutes(routes, ['editor'])
},
{
key: 'visitor',
name: 'visitor',
description: 'Just a visitor. Can only see the home page and the document page',
routes: [{
path: '',
redirect: 'dashboard',
children: [
{
path: 'dashboard',
name: 'Dashboard',
meta: { title: 'dashboard', icon: 'dashboard' }
}
]
}]
}
]

export default {
getRoutes() {
return routes
},
getRoles() {
return roles
},
addRole() {
return Mock.mock('@integer(300, 5000)')
},
updateRole() {
const res = {
data: 'success'
}
return res
},
deleteRole() {
const res = {
data: 'success'
}
return res
}
}
45 changes: 27 additions & 18 deletions src/permission.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,49 @@ 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' // getToken from cookie
import 'nprogress/nprogress.css' // progress bar style
import { getToken } from '@/utils/auth' // get token from cookie

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

// permission judge function
function hasPermission(roles, permissionRoles) {
if (roles.indexOf('admin') >= 0) return true // admin permission passed directly
if (roles.includes('admin')) return true // admin permission passed directly
if (!permissionRoles) return true
return roles.some(role => permissionRoles.indexOf(role) >= 0)
}

const whiteList = ['/login', '/auth-redirect']// no redirect whitelist
const whiteList = ['/login', '/auth-redirect'] // no redirect whitelist

router.beforeEach((to, from, next) => {
NProgress.start() // start progress bar
if (getToken()) { // determine if there has token
if (getToken()) {
// determine if there has token

/* has token*/
if (to.path === '/login') {
next({ path: '/' })
NProgress.done() // if current page is dashboard will not trigger afterEach hook, so manually handle it
} else {
if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
store.dispatch('GetUserInfo').then(res => { // 拉取user_info
const roles = res.data.roles // note: roles must be a array! such as: ['editor','develop']
store.dispatch('GenerateRoutes', { roles }).then(() => { // 根据roles权限生成可访问的路由表
router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
if (store.getters.roles.length === 0) {
// 判断当前用户是否已拉取完user_info信息
store
.dispatch('GetUserInfo')
.then(res => {
// 拉取user_info
const roles = res.data.roles // note: roles must be a object array! such as: [{id: '1', name: 'editor'}, {id: '2', name: 'developer'}]
store.dispatch('GenerateRoutes', { roles }).then(accessRoutes => {
// 根据roles权限生成可访问的路由表
router.addRoutes(accessRoutes) // 动态添加可访问路由表
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
})
})
}).catch((err) => {
store.dispatch('FedLogOut').then(() => {
Message.error(err)
next({ path: '/' })
.catch(err => {
store.dispatch('FedLogOut').then(() => {
Message.error(err)
next({ path: '/' })
})
})
})
} else {
// 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
if (hasPermission(store.getters.roles, to.meta.roles)) {
Expand All @@ -49,7 +57,8 @@ router.beforeEach((to, from, next) => {
}
} else {
/* has no token*/
if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
if (whiteList.indexOf(to.path) !== -1) {
// 在免登录白名单,直接进入
next()
} else {
next(`/login?redirect=${to.path}`) // 否则全部重定向到登录页
Expand Down
16 changes: 12 additions & 4 deletions src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import nestedRouter from './modules/nested'
affix: true if true, the tag will affix in the tags-view
}
**/
export const constantRouterMap = [
export const constantRoutes = [
{
path: '/redirect',
component: Layout,
Expand Down Expand Up @@ -81,7 +81,6 @@ export const constantRouterMap = [
{
path: '/documentation',
component: Layout,
redirect: '/documentation/index',
children: [
{
path: 'index',
Expand Down Expand Up @@ -109,10 +108,10 @@ export const constantRouterMap = [
export default new Router({
// mode: 'history', // require service support
scrollBehavior: () => ({ y: 0 }),
routes: constantRouterMap
routes: constantRoutes
})

export const asyncRouterMap = [
export const asyncRoutes = [
{
path: '/permission',
component: Layout,
Expand Down Expand Up @@ -141,6 +140,15 @@ export const asyncRouterMap = [
title: 'directivePermission'
// if do not set roles, means: this page does not require permission
}
},
{
path: 'role',
component: () => import('@/views/permission/role'),
name: 'RolePermission',
meta: {
title: 'rolePermission',
roles: ['admin']
}
}
]
},
Expand Down
4 changes: 2 additions & 2 deletions src/store/getters.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ const getters = {
status: state => state.user.status,
roles: state => state.user.roles,
setting: state => state.user.setting,
permission_routers: state => state.permission.routers,
addRouters: state => state.permission.addRouters,
permission_routes: state => state.permission.routes,
addRoutes: state => state.permission.addRoutes,
errorLogs: state => state.errorLog.logs
}
export default getters
Loading