效果图
在线地址:https://codesandbox.io/s/authorizedbyrole-yzy4r2?file=/src/util/directive.js
当前用户为非管理员角色
环境
vuetify@2.6.6 vuex javascript
事情经过
一般的系统,都是采用**RBAC模型:基于用户-角色-权限控制**
所以在菜单管理中给角色授权,就可以实现对应的操作
但是最近,我接到了一个需求,管理员角色创建的数据,非管理员无论前端授权情况,都不可操作
于是,我的想法是在v-has
控制授权按钮指令里面做操作
但是,我发现,无法拿到当条数据
于是,开始了投机取巧之类的想法
创建了一个admin
列,管理员角色创建的数据用图标mdi-alpha-a-circle
显示
判断当前行有没有mdi-alpha-a-circle
class类,来判断是不是管理员创建的数据
然后判断当前角色是不是非管理员,若是,删除节点
流程图
必要条件
- 有个
admin
列,管理员角色创建的数据用图标mdi-alpha-a-circle
显示 - 必须按照
tr
>td
>template>btn
DOM结构,如下
<template v-slot:item.actions="{ item }">
<v-btn v-has:edit icon @click.stop="edit(item)">
<v-icon size="1.25rem"> mdi-pencil </v-icon>
</v-btn>
<v-btn v-has:del icon>
<v-icon size="1.25rem" class="icon-hover-bg ml-2" @click.stop="del(item)"> mdi-delete </v-icon>
</v-btn>
</template>
实现思路
创建admin列
一般来说,接口是不可能把创建者所属角色返回的,一般返回的是userId
,userName
,所以必须根据角色查询所有userId
,存储在store
中,如userIdByAdminList
,判断当前用户是否是admin
角色
实现思路:
<template v-slot:item.createUser="{ item }">
<v-icon
v-if="$store.state.userIdByAdminList.includes(item.createUser)"
size="1.5rem"
color="primary"
>mdi-alpha-a-circle</v-icon
>
<span v-else>{{ item.createUser }}</span>
</template>
给按钮添加v-has
<template v-slot:item.actions="{ item }">
<v-btn v-has:edit icon @click.stop="edit(item)">
<v-icon size="1.25rem"> mdi-pencil </v-icon>
</v-btn>
<v-btn v-has:del icon>
<v-icon size="1.25rem" class="icon-hover-bg ml-2" @click.stop="del(item)"> mdi-delete </v-icon>
</v-btn>
</template>
v-has实现
递归寻找adminIcon
结束递归的条件:满足之一即可
- item.childNodes.length===0
- iconNode不为null
let iconNode = null
const getAdminIcon = (nodeList) => {
// console.log('nodeList', nodeList)
if(iconNode){
return iconNode
}
for (let i = 0; i < nodeList.length; i++) {
let item = nodeList[i]
let bool = item.classList && item.classList.contains('mdi-alpha-a-circle')
// console.log('item', item)
// console.log('bool', bool)
if (bool) {
iconNode = item
break
}
if (item.childNodes.length === 0) {
continue
}
iconNode = getAdminIcon(item.childNodes)
}
return iconNode
}
v-has指令实现
// v-has:search
const has = {
inserted(el, binding, vnode) {
let isForceDel = false
// 第一种实现方式
let trNodes = el.parentNode.parentNode.childNodes
if (trNodes) {
const iconEle = getAdminIcon(trNodes)
if (iconEle) {
console.log(iconEle) // 管理员创建的数据
let roleId = store.state.userInfo.roleId
isForceDel = roleId !== 'admin'
}
}
const value = binding.arg || binding.value || binding.value.arg
const permissions = vnode.context.$route.meta.buttons || []
if (value) {
if (!permissions.includes(value) || isForceDel) {
;(el.parentNode && el.parentNode.removeChild(el)) ||
(el.style.display = 'none')
}
}
}
}
第二种实现思路
传入当前记录函数:v-has:del = "item"
主要逻辑代码:
if (binding.value) {
let record = binding.value;
let isAdmin = store.state.userIdByAdminList.includes(record.createUser);
let userId = store.state.userInfo.userId;
if (isAdmin) {
isForceDel = !store.state.userIdByAdminList.includes(userId);
}
}
这样子做的一个不好的点就是,每个按钮都要传参,并且必须有createUser
字段,适合所有页面还没有授权的情况
踩坑记录
https://segmentfault.com/q/1010000044084082?_ea=312694630