feat: 添加 v-permission 指令实现按钮级权限控制
This commit is contained in:
@@ -0,0 +1,124 @@
|
|||||||
|
import { describe, it, expect, beforeEach } from 'vitest'
|
||||||
|
import { mount } from '@vue/test-utils'
|
||||||
|
import { createPinia, setActivePinia } from 'pinia'
|
||||||
|
import { permissionDirective } from '@/directives/permission'
|
||||||
|
import { usePermissionStore } from '@/stores/permission'
|
||||||
|
|
||||||
|
describe('v-permission 指令', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
setActivePinia(createPinia())
|
||||||
|
localStorage.clear()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('角色检查', () => {
|
||||||
|
it('有角色时应该显示元素', () => {
|
||||||
|
const store = usePermissionStore()
|
||||||
|
store.setPermissionData({
|
||||||
|
roles: ['admin'],
|
||||||
|
permissions: [],
|
||||||
|
menus: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const wrapper = mount({
|
||||||
|
template: '<button v-permission:role="\'admin\'">管理员按钮</button>',
|
||||||
|
directives: {
|
||||||
|
permission: permissionDirective
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(wrapper.find('button').isVisible()).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('无角色时应该隐藏元素', () => {
|
||||||
|
const store = usePermissionStore()
|
||||||
|
store.setPermissionData({
|
||||||
|
roles: ['user'],
|
||||||
|
permissions: [],
|
||||||
|
menus: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const wrapper = mount({
|
||||||
|
template: '<button v-permission:role="\'admin\'">管理员按钮</button>',
|
||||||
|
directives: {
|
||||||
|
permission: permissionDirective
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(wrapper.find('button').isVisible()).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('支持数组参数(满足任一即可)', () => {
|
||||||
|
const store = usePermissionStore()
|
||||||
|
store.setPermissionData({
|
||||||
|
roles: ['user'],
|
||||||
|
permissions: [],
|
||||||
|
menus: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const wrapper = mount({
|
||||||
|
template: '<button v-permission:role="[\'admin\', \'user\']">按钮</button>',
|
||||||
|
directives: {
|
||||||
|
permission: permissionDirective
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(wrapper.find('button').isVisible()).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('权限检查', () => {
|
||||||
|
it('有权限时应该显示元素', () => {
|
||||||
|
const store = usePermissionStore()
|
||||||
|
store.setPermissionData({
|
||||||
|
roles: [],
|
||||||
|
permissions: ['user:delete'],
|
||||||
|
menus: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const wrapper = mount({
|
||||||
|
template: '<button v-permission:permission="\'user:delete\'">删除用户</button>',
|
||||||
|
directives: {
|
||||||
|
permission: permissionDirective
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(wrapper.find('button').isVisible()).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('无权限时应该隐藏元素', () => {
|
||||||
|
const store = usePermissionStore()
|
||||||
|
store.setPermissionData({
|
||||||
|
roles: [],
|
||||||
|
permissions: ['user:read'],
|
||||||
|
menus: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const wrapper = mount({
|
||||||
|
template: '<button v-permission:permission="\'user:delete\'">删除用户</button>',
|
||||||
|
directives: {
|
||||||
|
permission: permissionDirective
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(wrapper.find('button').isVisible()).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('支持简写形式(默认权限检查)', () => {
|
||||||
|
const store = usePermissionStore()
|
||||||
|
store.setPermissionData({
|
||||||
|
roles: [],
|
||||||
|
permissions: ['user:create'],
|
||||||
|
menus: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const wrapper = mount({
|
||||||
|
template: '<button v-permission="\'user:create\'">创建用户</button>',
|
||||||
|
directives: {
|
||||||
|
permission: permissionDirective
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(wrapper.find('button').isVisible()).toBe(true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import type { Directive, DirectiveBinding } from 'vue'
|
||||||
|
import { usePermissionStore } from '@/stores/permission'
|
||||||
|
|
||||||
|
export const permissionDirective: Directive = {
|
||||||
|
mounted(el: HTMLElement, binding: DirectiveBinding) {
|
||||||
|
const permissionStore = usePermissionStore()
|
||||||
|
|
||||||
|
const { arg, value } = binding
|
||||||
|
const checkType = arg || 'permission'
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
console.warn('v-permission 指令需要提供权限值')
|
||||||
|
el.style.display = 'none'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let hasAccess = false
|
||||||
|
|
||||||
|
if (checkType === 'role') {
|
||||||
|
hasAccess = permissionStore.hasRole(value)
|
||||||
|
} else if (checkType === 'permission') {
|
||||||
|
hasAccess = permissionStore.hasPermission(value)
|
||||||
|
} else {
|
||||||
|
console.warn(`未知的权限检查类型: ${checkType}`)
|
||||||
|
el.style.display = 'none'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasAccess) {
|
||||||
|
el.style.display = 'none'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import 'element-plus/dist/index.css'
|
|||||||
import router from './router'
|
import router from './router'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import './assets/styles.css'
|
import './assets/styles.css'
|
||||||
|
import { permissionDirective } from './directives/permission'
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
const pinia = createPinia()
|
const pinia = createPinia()
|
||||||
@@ -16,4 +17,6 @@ app.use(ElementPlus, {
|
|||||||
locale: zhCn,
|
locale: zhCn,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
app.directive('permission', permissionDirective)
|
||||||
|
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
|
|||||||
Reference in New Issue
Block a user