feat: ui hasPermission (#3270)

This commit is contained in:
shaohuzhang1 2025-06-16 18:23:46 +08:00 committed by GitHub
parent 3540ad8550
commit 11dfcd4d60
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 167 additions and 16 deletions

View File

@ -1,4 +1,3 @@
import { ComplexPermission } from '@/utils/permission/type'
import { PermissionConst, RoleConst } from '@/utils/permission/data'
const ApplicationDetailRouter = {

View File

@ -46,6 +46,11 @@ export const routes: Array<RouteRecordRaw> = [
name: 'ResetPassword',
component: () => import('@/views/login/ResetPassword.vue'),
},
{
path: '/permission',
name: 'permission',
component: () => import('@/views/Permission.vue'),
},
// {
// path: '/:pathMatch(.*)',
// name: '404',

View File

@ -93,15 +93,27 @@ const useUserStore = defineStore('user', {
getPermissions() {
if (this.userInfo) {
if (this.isEE()) {
return [...this.userInfo?.permissions, 'x-pack-ee']
return [...this.userInfo?.permissions, 'X-PACK-EE']
} else if (this.isPE()) {
return [...this.userInfo?.permissions, 'x-pack-pe']
return [...this.userInfo?.permissions, 'X-PACK-PE']
}
return this.userInfo?.permissions
} else {
return []
}
},
getEdition() {
if (this.userInfo) {
if (this.isEE()) {
return 'X-PACK-EE'
} else if (this.isPE()) {
return 'X-PACK-PE'
} else {
return 'X-PACK-CE'
}
}
return 'X-PACK-CE'
},
getRole() {
if (this.userInfo) {
return this.userInfo?.role

View File

@ -1,4 +1,4 @@
import { Permission, Role } from '@/utils/permission/type'
import { Permission, Role, Edition } from '@/utils/permission/type'
const PermissionConst = {
USER_READ: new Permission('USER:READ'),
USER_CREATE: new Permission('USER:CREATE'),
@ -10,4 +10,9 @@ const RoleConst = {
WORKSPACE_MANAGE: new Role('WORKSPACE_MANAGE'),
USER: new Role('USER'),
}
export { PermissionConst, RoleConst }
const EditionConst = {
IS_PE: new Edition('X-PACK-PE'),
IS_EE: new Edition('X-PACK-EE'),
IS_CE: new Edition('X-PACK-CE'),
}
export { PermissionConst, RoleConst, EditionConst }

View File

@ -1,21 +1,30 @@
import useStore from '@/stores'
import { Role, Permission, ComplexPermission } from '@/utils/permission/type'
import {
Role,
Permission,
ComplexPermission,
Edition,
type PF,
type CPF,
type CRF,
} from '@/utils/permission/type'
import { isFunction } from '@/utils/common'
type PF = () => Role | string | Permission | ComplexPermission
/**
*
* @param permission
* @returns True false
*/
const hasPermissionChild = (permission: Role | string | Permission | ComplexPermission | PF) => {
const hasPermissionChild = (
permission: Role | string | Permission | ComplexPermission | Edition | PF,
) => {
const { user } = useStore()
const permissions = user.getPermissions()
const role: Array<string> = user.getRole()
const edition = user.getEdition()
if (!permission) {
return true
}
if (isFunction(permission)) {
permission = (permission as PF)()
}
@ -25,10 +34,22 @@ const hasPermissionChild = (permission: Role | string | Permission | ComplexPerm
if (permission instanceof Permission) {
return permissions.includes(permission.permission)
}
if (permission instanceof Edition) {
return permission.edition === edition
}
if (permission instanceof ComplexPermission) {
const permissionOk = permission.permissionList.some((p) => permissions.includes(p))
const roleOk = role.some((r) => permission.roleList.includes(r))
return permission.compare === 'AND' ? permissionOk && roleOk : permissionOk || roleOk
const permissionOk = permission.permissionList.some((p) =>
permissions.includes(isFunction(p) ? (p as CPF)().toString() : p.toString()),
)
const roleList = permission.roleList
const roleOk = roleList.some((r) =>
role.includes(isFunction(r) ? (r as CRF)().toString() : r.toString()),
)
const editionOK = permission.editionList.includes(edition.toString())
return permission.compare === 'AND'
? permissionOk && roleOk && editionOK
: (permissionOk || roleOk) && editionOK
}
if (typeof permission === 'string') {
return permissions.includes(permission)
@ -45,10 +66,11 @@ const hasPermissionChild = (permission: Role | string | Permission | ComplexPerm
*/
export const hasPermission = (
permission:
| Array<Role | string | Permission | ComplexPermission | PF>
| Array<Role | string | Permission | ComplexPermission | Edition | PF>
| Role
| string
| Permission
| Edition
| ComplexPermission
| PF,
compare: 'OR' | 'AND',

View File

@ -1,4 +1,7 @@
import useStore from '@/stores'
export type PF = () => Role | string | Permission | ComplexPermission
export type CRF = () => Role | string
export type CPF = () => Permission | string
/**
*
*/
@ -13,6 +16,13 @@ export class Role {
const { user } = useStore()
return new Role(`${this.role}:/WORKSPACE/${user.getWorkspaceId()}`)
}
getWorkspaceRoleString = () => {
const { user } = useStore()
return `${this.role}:/WORKSPACE/${user.getWorkspaceId()}`
}
toString() {
return this.role
}
}
/**
*
@ -43,20 +53,44 @@ export class Permission {
const { user } = useStore()
return `${this.permission}:/WORKSPACE/${user.getWorkspaceId()}/${resource}/${resource_id}`
}
toString() {
return this.permission
}
}
/**
*
*/
export class ComplexPermission {
roleList: Array<string>
roleList: Array<string | Role | CRF>
permissionList: Array<string>
permissionList: Array<string | Permission | CPF>
editionList: Array<string | Edition>
compare: 'OR' | 'AND'
constructor(roleList: Array<string>, permissionList: Array<string>, compare: 'OR' | 'AND') {
constructor(
roleList: Array<string | Role | CRF>,
permissionList: Array<string | Permission | CPF>,
editionList: Array<string | Edition>,
compare: 'OR' | 'AND',
) {
this.roleList = roleList
this.permissionList = permissionList
this.editionList = editionList
this.compare = compare
}
}
/**
*
*/
export class Edition {
edition: string
constructor(edition: string) {
this.edition = edition
}
toString() {
return this.edition
}
}

View File

@ -0,0 +1,74 @@
<template>
<div>说明: v-hasPermission 是使用v-show 本质上组件是渲染的 v-if="hasPermission('xxxx')"</div>
<div>这种方式组件不会渲染(用于比如像组件挂载的时候需要调用接口,不想让组件渲染)</div>
<div>比如工作空间的下拉列表组件使用v-if 示例 企业版组件:</div>
<button v-if="hasPermission(EditionConst.IS_CE, 'OR')">我是社区版组件</button>
<button v-hasPermission="EditionConst.IS_CE">我是社区版组件</button>
<!-- ================我是企业版组件================== -->
<button v-if="hasPermission(EditionConst.IS_EE, 'OR')">我是企业版组件</button>
<button v-hasPermission="EditionConst.IS_EE">我是企业版组件</button>
<!-- ================企业版组件 并且是ADMIN角色================== -->
<button v-if="hasPermission([EditionConst.IS_EE, RoleConst.ADMIN], 'AND')">
我是企业版并且是ADMIN角色
</button>
<button
v-hasPermission="new ComplexPermission([RoleConst.ADMIN], [], [EditionConst.IS_EE], 'AND')"
>
我是企业版并且是ADMIN角色
</button>
<!-- ================企业版组件 并且是当前工作空间管理员================== -->
<button
v-if="hasPermission([EditionConst.IS_EE, RoleConst.WORKSPACE_MANAGE.getWorkspaceRole], 'AND')"
>
我是企业版并且拥有当前工作空间管理员角色
</button>
<button
v-hasPermission="
new ComplexPermission(
[RoleConst.WORKSPACE_MANAGE.getWorkspaceRole],
[],
[EditionConst.IS_EE],
'OR',
)
"
>
我是企业版并且拥有当前工作空间管理员角色
</button>
<!-- ================企业版组件 并且是当前工作空间管理员 或者有用户只读================== -->
<button
v-if="
hasPermission(
new ComplexPermission(
[RoleConst.WORKSPACE_MANAGE.getWorkspaceRole],
[PermissionConst.USER_READ],
[EditionConst.IS_EE],
'OR',
),
'OR',
)
"
>
我是企业版 并且是当前工作空间管理员 或者有用户只读
</button>
<button
v-hasPermission="
new ComplexPermission(
[RoleConst.WORKSPACE_MANAGE.getWorkspaceRole],
[PermissionConst.USER_READ],
[EditionConst.IS_EE],
'OR',
)
"
>
我是企业版并且是当前工作空间管理员 或者有用户只读
</button>
</template>
<script setup lang="ts">
import { PermissionConst, EditionConst, RoleConst } from '@/utils/permission/data'
import { hasPermission } from '@/utils/permission/index'
import { ComplexPermission } from '@/utils/permission/type'
</script>
<style lang="scss" scoped></style>