代码拉取完成,页面将自动刷新
import { isArray, isEmptyObject, isString, isUndefined, isObject } from './../utils/validate';
import { Directive, DirectiveBinding } from 'vue';
/**
* 自定义权限指令
*
* 第一个 * 表示角色 ,第二个 * 表示资源,第三个 * 表示具体权限
*
* 三指令用法 针对角色和权限的某一权限
*
* 任意角色都能访问 *:*:* v-permission.*:*:*="*:*:*" 一般省略,因为这样毫无意义!
* 具有 admin 角色才能访问 admin:*:* v-permission.admin:*:*="xxx"
* 具有 add 权限才能访问 *:*:add v-permission.*:*:add="*:*:xxx"
* 具有 xxx 资源下任意权限 *:xxx:* v-permission.*:blog:*="*:xxx"
* 具有 xxx 资源权限同时要有add权限 *:xx:add v-permission.admin:blog:add="xxx:yyy:zzz"
*
* 双指令写法,针对角色和资源 ,省略具体权限
*
* 某一个角色具有某一资源下所有权限 v-permission.admin:blog.user:blog
*
* 单指令写法,省略资源和具体权限
* 多个角色 连写形式 v-permission.admin.user.other admin | user | other 都能访问
*
*
*
* 对象式写法
* v-permission="[{ type: 'serve', role: [], resource: [], permission: [] }, { type: 'expect', role: ['admin'], resource: [], permission: ['add'] }]"
* 参数说明: type 指定为说明类型,默认可以不指定,第一个式前端接受类型,第二个期望式什么类型
* - 如果指定了类型,两个类型不能一致!,否则会覆盖!
* - expect 期望类型
* - serve 从服务端接受的权限
* role: 角色
* - 如果是一个字符串,可以省略 ["admin"] => "admin"
* - 多个角色使用数组形式 ["admin","user"]
* - 如果省略,默认式为 *
* resource: 资源
* - 同上
* permission: 具体权限
* - 同上
*
*
* 混合式写法
*
* 参考上面两种方式
* 只能通过 v-permission.xxxx:yyyy:zzz="{role: aaa, resource: bbbb, permission: cccc }"
* - role,resource,permission 省略表示 *
*
*
* 判断依据
* - 如果不指定对应资源默认值,初始化设置为 "*"
* - 如果一个资源权限对应设置为 "*",对于期望值来说,可以放行任意权限,对于服务器接收数据来说,表示具有任意权限
* - 例如 ["admin:*:*"] === ["*":"*":"add"] = >true
* - 例如 ["*:*:add"] === ["user":"*":"add"] = >true
* - 例如 ["*:*:add"] === ["user":"*":"delete"] = >false
* - 例如 ["*:account:add"] === ["user":"picture":"add"] = >false
*
*/
// 所有权限
const ANY_PERMISSION = "*"
// 权限连接符
const PERMISSION_CONNECTION = ":"
type PermssionTypeStr = string | string[] | undefined
/**
* 权限类型
*/
const RESOLVE_SERVE = 'server'
const RESOLVE_EXPECT = 'expect'
export type ResolvePermssionType = 'expect' | 'server' | undefined
interface Permssion {
role?: PermssionTypeStr
resource?: PermssionTypeStr
permission?: PermssionTypeStr
}
/**
* 权限对象式写法类型
*/
interface PermssionType extends Permssion {
type?: ResolvePermssionType
}
const initParams = (obj: Permssion) => {
if (isUndefined(obj?.role)) {
obj['role'] = ANY_PERMISSION
}
if (isUndefined(obj?.resource)) {
obj['resource'] = ANY_PERMISSION
}
if (isUndefined(obj?.permission)) {
obj['permission'] = ANY_PERMISSION
}
}
const compareArrayPermission = (expect: PermssionTypeStr, server: PermssionTypeStr) => {
if (isArray(expect) && isArray(server)) {
expect = expect as string[]
server = server as string[]
for (let i = 0; i < server.length; i++) {
// 如果用户具有 任意权限放行
// 如果资源对任意用户访问,放行
let index = expect.findIndex(item =>
(
item
&&
server
&&
item === (server as string[])[i])
||
item === ANY_PERMISSION
||
(server as string[])[i] === ANY_PERMISSION);
if (index !== -1) {
return true
}
}
return false
}
if (isArray(expect)) {
// 如果包含任意权限放行
if ((expect as string[]).find(e => e && (e as string) === ANY_PERMISSION) || (server as string) === ANY_PERMISSION) {
return true
}
// 从 s2 是否具有s1权限
return (expect as string[]).indexOf(server as string) > -1
}
if (isArray(server)) {
// 如果包含任意权限放行
if ((server as string[]).find(e => e && (e as string) === ANY_PERMISSION) || (expect as string) === ANY_PERMISSION) {
return true
}
// 从 s2 是否具有s1权限
return (server as string[]).indexOf(expect as string) > -1
}
return false
}
/**
* 单个权限比对
* @param expect 期望权限
* @param server 服务器接受权限
* @returns
*/
const hasPermission = (expect: PermssionTypeStr, server: PermssionTypeStr) => {
console.log('expect', expect, 'server', server)
// 如果具有多个权限或者角色
if ((isArray(expect) || isArray(server))) {
return compareArrayPermission(expect, server)
}
// 如果允许任意权限 或者具有任意权限
if (expect === ANY_PERMISSION || server === ANY_PERMISSION ) {
return true
}
return expect === server
}
/**
* 权限比对
* @param expect 期望权限
* @param server 接受权限
* @returns boolean
*/
const hasAllPermission = (expect: Permssion, server: Permssion) => hasPermission(expect?.role, server?.role) && hasPermission(expect?.resource, server?.resource) && hasPermission(expect?.permission, server?.permission)
const pa = (o: PermssionTypeStr): string => {
if (o && isArray(o)) {
return [o as string[]].join('|')
}
return o as string
}
const permssionStr = (p: Permssion) => `${pa(p.role)}${PERMISSION_CONNECTION}${pa(p.resource)}${PERMISSION_CONNECTION}${pa(p.permission)}`
const printPermission = (expect: Permssion, server: Permssion) => {
console.log('期望类型', permssionStr(expect), '服务器接受类型', permssionStr(server))
}
const alertPermission = (params1: Permssion, params2: Permssion) => {
let space = ' '
let a = {
'期望类型': space + permssionStr(params1) + space,
'接受类型': space + permssionStr(params2) + space
}
alert(JSON.stringify(a))
}
// 生成 权限对象
const getPermission = (params: string): Permssion => {
let arr = params.split(PERMISSION_CONNECTION)
if ((isArray(arr) && arr.length !== 3) || (!isArray(arr))) {
throw new Error('指令解析失败!')
}
let p: Permssion = {
role: arr[0],
resource: arr[1],
permission: arr[2]
}
return p
}
// 将字符串转换成 权限字符
const addPermission = (args: PermssionTypeStr): Permssion => {
if (isString(args)) {
let i = (args as string).match(new RegExp(PERMISSION_CONNECTION, "g"))
// 匹配到一个:
if (isArray(i) && i!.length == 1) {
args = args + PERMISSION_CONNECTION + ANY_PERMISSION
// 匹配到两个 :
} else if (isArray(i) && i!.length == 2) {
} else {
// 一个都没匹配到
args = `${args}${PERMISSION_CONNECTION}${ANY_PERMISSION}${PERMISSION_CONNECTION}${ANY_PERMISSION}`
}
return getPermission(args as string)
}
return {} as Permssion
}
// 生成权限
const genRoles = (args: PermssionTypeStr): Permssion[] => {
if (isString(args)) {
return [addPermission(args)]
} else if (isArray(args)) {
args = args as string[]
return args.map(arg => addPermission(arg as string));
} else {
return [] as Permssion[]
}
}
// 权限去重
const duplicateRemoval = (p: Permssion[]): Permssion => {
let roles = [] as string[]
let resources = [] as string[]
let permissions = [] as string[]
let obj: Permssion
p.forEach(item => {
roles.push(item['role'] as string)
resources.push(item['resource'] as string)
permissions.push(item['permission'] as string)
})
// set 去重
roles = [...new Set([...roles])]
resources = [...new Set([...resources])]
permissions = [...new Set([...permissions])]
// 是否存在最高权限
roles = roles.find(i => i === ANY_PERMISSION) ? [ANY_PERMISSION] : roles
resources = resources.find(i => i === ANY_PERMISSION) ? [ANY_PERMISSION] : resources
permissions = permissions.find(i => i === ANY_PERMISSION) ? [ANY_PERMISSION] : permissions
obj = {
role: roles,
resource: resources,
permission: permissions
}
return obj
}
// 连写形式
const ligature = (el: HTMLElement, binding: DirectiveBinding) => {
let args = binding.arg
let modifiers = binding.modifiers
let values = binding.value
let expects = [] as Permssion[]
let servers = [] as Permssion[]
if (args) {
// 如果是字符串 比如 "admin" = > "admin:*:*"
// 如果是数组 比如 ["admin","user","root"] = > ["admin:*:*","user:*:*","root:*:*"]
expects = [...genRoles(args.split(PERMISSION_CONNECTION))]
}
if (modifiers) {
// 三种形式
// user
// user:blog
// user:blog:add
expects = [...expects, ...genRoles(Object.keys(modifiers))]
}
// 服务器接收值
// 连写
let server: Permssion
if (isArray(values) || isString(values)) {
values = isArray(values) ? values.join(PERMISSION_CONNECTION) : values
servers = [...genRoles(values)]
server = duplicateRemoval(servers)
console.log('连写式写法', server)
// 对象式写法
} else if (isObject(values)) {
initParams(values as Permssion)
server = values
console.log('对象式写法', server)
}
// 权限去重与合并
let expect: Permssion = duplicateRemoval(expects)
// 判断权限
Promise.resolve().then(() => {
printPermission(expect, server)
alertPermission(expect, server)
if (!hasAllPermission(expect, server)) {
el.style.display = 'none'
return;
}
})
}
// 对象式写法
const bindingValueIsObject = (el: HTMLElement, binding: DirectiveBinding) => {
const values = binding.value
if (!isArray(values) || values.length !== 2) {
// throw new Error('v-permission对象式必须式两个对象类型!')
console.warn('v-permission对象式必须式两个对象类型!')
return;
}
let [params1, params2] = values as PermssionType[]
// console.log(params1, params2, !isUndefined(params1?.type), !isUndefined(params2?.type))
if (!isUndefined(params1?.type) && !isUndefined(params2?.type) && params1.type === params2.type) {
console.warn('两个类型不能一致!')
return;
}
// 两个参数均为 undefined
if (isUndefined(params1?.type) && isUndefined(params2?.type)) {
params1.type = RESOLVE_SERVE
params2.type = RESOLVE_EXPECT
}
// 参数一为 undefined
else if (isUndefined(params1?.type) && params2?.type) {
params2.type === RESOLVE_SERVE ? params1.type = RESOLVE_EXPECT : params1.type = RESOLVE_SERVE
}
// 参数二为 undefined
else if (isUndefined(params2?.type) && params1?.type) {
params1.type === RESOLVE_SERVE ? params2.type = RESOLVE_EXPECT : params2.type = RESOLVE_SERVE
}
// 参数初始化
initParams(params1)
initParams(params2)
// 交换,保证 期望值在前
console.log("before", params1.type, params2.type)
if (params1.type === 'server') {
let temp: PermssionType
temp = params1
params1 = params2
params2 = temp
}
console.log("after", params1.type, params2.type)
alertPermission(params1, params2)
printPermission(params1, params2)
if (!hasAllPermission(params1, params2)) {
el.style.display = 'none'
console.log('我需要隐藏了哦!')
}
}
/**
* 指令
*/
const vPermission: Directive = {
// 或事件监听器应用前调用
created(el: HTMLElement, binding: DirectiveBinding) {
// 下面会介绍各个参数的细节
const arg = binding.arg
const modifiers = binding.modifiers
const value = binding.value
if (isUndefined(value)) {
console.log('value is undefined ')
return;
}
if (isEmptyObject(value)) {
console.log('value is object but not any attr and value ')
return;
}
if (isArray(value) && value == 0) {
console.log('value is array but length equal 0 ')
return;
}
// 获取参数个数
el.addEventListener('click', () => {
console.log('======================')
console.log('arg', arg)
console.log('modifiers', modifiers)
console.log('value', value)
console.log('======================')
// 判断写法
// 对象式写法
if (!arg && isEmptyObject(modifiers)) {
bindingValueIsObject(el, binding)
}
// 连写式写法 | 混合式写法
else if (arg || !isEmptyObject(modifiers)) {
ligature(el, binding)
}
else {
console.log('绑定错误')
}
})
},
}
const permission = {
name: 'permission',
directive: vPermission
}
export default permission
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。