diff --git a/apps/vben5/packages/@abp/identity/package.json b/apps/vben5/packages/@abp/identity/package.json index 237482ec3..0a1fad4a5 100644 --- a/apps/vben5/packages/@abp/identity/package.json +++ b/apps/vben5/packages/@abp/identity/package.json @@ -21,6 +21,7 @@ }, "dependencies": { "@abp/core": "workspace:*", + "@abp/permission": "workspace:*", "@abp/request": "workspace:*", "@abp/ui": "workspace:*", "@ant-design/icons-vue": "catalog:", diff --git a/apps/vben5/packages/@abp/identity/src/components/claim-types/ClaimTypeTable.vue b/apps/vben5/packages/@abp/identity/src/components/claim-types/ClaimTypeTable.vue index f8a67f1f9..97d2d3689 100644 --- a/apps/vben5/packages/@abp/identity/src/components/claim-types/ClaimTypeTable.vue +++ b/apps/vben5/packages/@abp/identity/src/components/claim-types/ClaimTypeTable.vue @@ -5,6 +5,7 @@ import type { IdentityClaimTypeDto } from '../../types/claim-types'; import { defineAsyncComponent, h } from 'vue'; +import { useAccess } from '@vben/access'; import { useVbenModal } from '@vben/common-ui'; import { createIconifyIcon } from '@vben/icons'; import { $t } from '@vben/locales'; @@ -14,6 +15,7 @@ import { DeleteOutlined, EditOutlined } from '@ant-design/icons-vue'; import { Button, Modal } from 'ant-design-vue'; import { deleteApi, getPagedListApi } from '../../api/claim-types'; +import { IdentityClaimTypePermissions } from '../../constants/permissions'; import { ValueType } from '../../types/claim-types'; defineOptions({ @@ -26,6 +28,8 @@ const ClaimTypeModal = defineAsyncComponent( const CheckIcon = createIconifyIcon('ant-design:check-outlined'); const CloseIcon = createIconifyIcon('ant-design:close-outlined'); +const { hasAccessByCodes } = useAccess(); + const formOptions: VbenFormProps = { // 默认展开 collapsed: false, @@ -102,6 +106,10 @@ const gridOptions: VxeGridProps = { fixed: 'right', slots: { default: 'action' }, title: $t('AbpUi.Actions'), + visible: hasAccessByCodes([ + IdentityClaimTypePermissions.Update, + IdentityClaimTypePermissions.Delete, + ]), width: 180, }, ], @@ -172,7 +180,7 @@ const handleDelete = (row: IdentityClaimTypeDto) => { + + diff --git a/apps/vben5/packages/@abp/identity/src/components/organization-units/OrganizationUnitUserTable.vue b/apps/vben5/packages/@abp/identity/src/components/organization-units/OrganizationUnitUserTable.vue index a172fc9bf..275a8498a 100644 --- a/apps/vben5/packages/@abp/identity/src/components/organization-units/OrganizationUnitUserTable.vue +++ b/apps/vben5/packages/@abp/identity/src/components/organization-units/OrganizationUnitUserTable.vue @@ -15,6 +15,7 @@ import { Button, Modal } from 'ant-design-vue'; import { addMembers, getUserListApi } from '../../api/organization-units'; import { removeOrganizationUnit } from '../../api/users'; +import { OrganizationUnitPermissions } from '../../constants/permissions'; defineOptions({ name: 'OrganizationUnitUserTable', @@ -33,7 +34,7 @@ const { hasAccessByCodes } = useAccess(); const getAddMemberEnabled = computed(() => { return ( props.selectedKey && - hasAccessByCodes(['AbpIdentity.OrganizationUnits.ManageUsers']) + hasAccessByCodes([OrganizationUnitPermissions.ManageUsers]) ); }); @@ -167,7 +168,7 @@ watch(() => props.selectedKey, onRefresh); :icon="h(DeleteOutlined)" danger type="link" - v-access:code="['AbpIdentity.OrganizationUnits.ManageUsers']" + v-access:code="[OrganizationUnitPermissions.ManageUsers]" @click="onDelete(row)" > {{ $t('AbpUi.Delete') }} diff --git a/apps/vben5/packages/@abp/identity/src/components/roles/RoleTable.vue b/apps/vben5/packages/@abp/identity/src/components/roles/RoleTable.vue index 6be353eb4..bab89aaa0 100644 --- a/apps/vben5/packages/@abp/identity/src/components/roles/RoleTable.vue +++ b/apps/vben5/packages/@abp/identity/src/components/roles/RoleTable.vue @@ -1,25 +1,45 @@ - + diff --git a/apps/vben5/packages/@abp/identity/src/components/security-logs/SecurityLogTable.vue b/apps/vben5/packages/@abp/identity/src/components/security-logs/SecurityLogTable.vue index 95e0ff9d2..40f260b76 100644 --- a/apps/vben5/packages/@abp/identity/src/components/security-logs/SecurityLogTable.vue +++ b/apps/vben5/packages/@abp/identity/src/components/security-logs/SecurityLogTable.vue @@ -13,6 +13,7 @@ import { DeleteOutlined } from '@ant-design/icons-vue'; import { Button, Modal } from 'ant-design-vue'; import { deleteApi, getPagedListApi } from '../../api/security-logs'; +import { SecurityLogPermissions } from '../../constants/permissions'; defineOptions({ name: 'SecurityLogTable', @@ -196,7 +197,7 @@ const handleDelete = (row: SecurityLogDto) => { block danger type="link" - v-access:code="['AbpAuditing.SecurityLog.Delete']" + v-access:code="[SecurityLogPermissions.Delete]" @click="handleDelete(row)" > {{ $t('AbpUi.Delete') }} diff --git a/apps/vben5/packages/@abp/identity/src/components/users/UserTable.vue b/apps/vben5/packages/@abp/identity/src/components/users/UserTable.vue index 0de52b423..55939d133 100644 --- a/apps/vben5/packages/@abp/identity/src/components/users/UserTable.vue +++ b/apps/vben5/packages/@abp/identity/src/components/users/UserTable.vue @@ -1,28 +1,47 @@ - + diff --git a/apps/vben5/packages/@abp/identity/src/constants/index.ts b/apps/vben5/packages/@abp/identity/src/constants/index.ts new file mode 100644 index 000000000..c85954d3e --- /dev/null +++ b/apps/vben5/packages/@abp/identity/src/constants/index.ts @@ -0,0 +1 @@ +export * from './permissions'; diff --git a/apps/vben5/packages/@abp/identity/src/constants/permissions.ts b/apps/vben5/packages/@abp/identity/src/constants/permissions.ts new file mode 100644 index 000000000..8ba622647 --- /dev/null +++ b/apps/vben5/packages/@abp/identity/src/constants/permissions.ts @@ -0,0 +1,47 @@ +/** 用户权限 */ +export const IdentityUserPermissions = { + /** 新增 */ + Create: 'AbpIdentity.Users.Create', + /** 删除 */ + Delete: 'AbpIdentity.Users.Delete', + /** 管理声明 */ + ManageClaims: 'AbpIdentity.Users.ManageClaims', + /** 管理权限 */ + ManagePermissions: 'AbpIdentity.Users.ManagePermissions', + /** 更新 */ + Update: 'AbpIdentity.Users.Update', +}; +/** 角色权限 */ +export const IdentitRolePermissions = { + /** 新增 */ + Create: 'AbpIdentity.Roles.Create', + /** 删除 */ + Delete: 'AbpIdentity.Roles.Delete', + /** 管理声明 */ + ManageClaims: 'AbpIdentity.Roles.ManageClaims', + /** 管理权限 */ + ManagePermissions: 'AbpIdentity.Roles.ManagePermissions', + /** 更新 */ + Update: 'AbpIdentity.Roles.Update', +}; +/** 声明类型权限 */ +export const IdentityClaimTypePermissions = { + /** 新增 */ + Create: 'AbpIdentity.IdentityClaimTypes.Create', + /** 删除 */ + Delete: 'AbpIdentity.IdentityClaimTypes.Delete', + /** 更新 */ + Update: 'AbpIdentity.IdentityClaimTypes.Update', +}; +/** 组织机构权限 */ +export const OrganizationUnitPermissions = { + /** 管理角色 */ + ManageRoles: 'AbpIdentity.OrganizationUnits.ManageRoles', + /** 管理用户 */ + ManageUsers: 'AbpIdentity.OrganizationUnits.ManageUsers', +}; +/** 安全日志权限 */ +export const SecurityLogPermissions = { + /** 删除 */ + Delete: 'AbpAuditing.SecurityLog.Delete', +}; diff --git a/apps/vben5/packages/@abp/identity/src/index.ts b/apps/vben5/packages/@abp/identity/src/index.ts index 195d95f59..c688f3a89 100644 --- a/apps/vben5/packages/@abp/identity/src/index.ts +++ b/apps/vben5/packages/@abp/identity/src/index.ts @@ -1,2 +1,3 @@ export * from './components'; +export * from './constants'; export * from './types'; diff --git a/apps/vben5/packages/@abp/permission/package.json b/apps/vben5/packages/@abp/permission/package.json new file mode 100644 index 000000000..b5adfecf3 --- /dev/null +++ b/apps/vben5/packages/@abp/permission/package.json @@ -0,0 +1,36 @@ +{ + "name": "@abp/permission", + "version": "8.3.2", + "homepage": "https://github.com/colinin/abp-next-admin", + "bugs": "https://github.com/colinin/abp-next-admin/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/colinin/abp-next-admin.git", + "directory": "packages/@abp/permission" + }, + "license": "MIT", + "type": "module", + "sideEffects": [ + "**/*.css" + ], + "exports": { + ".": { + "types": "./src/index.ts", + "default": "./src/index.ts" + } + }, + "dependencies": { + "@abp/core": "workspace:*", + "@abp/request": "workspace:*", + "@abp/ui": "workspace:*", + "@ant-design/icons-vue": "catalog:", + "@vben/access": "workspace:*", + "@vben/common-ui": "workspace:*", + "@vben/hooks": "workspace:*", + "@vben/icons": "workspace:*", + "@vben/layouts": "workspace:*", + "@vben/locales": "workspace:*", + "ant-design-vue": "catalog:", + "vue": "catalog:*" + } +} diff --git a/apps/vben5/packages/@abp/permission/src/api/permissions.ts b/apps/vben5/packages/@abp/permission/src/api/permissions.ts new file mode 100644 index 000000000..d4ad87c78 --- /dev/null +++ b/apps/vben5/packages/@abp/permission/src/api/permissions.ts @@ -0,0 +1,37 @@ +import type { + PermissionProvider, + PermissionResultDto, + PermissionsUpdateDto, +} from '../types/permissions'; + +import { requestClient } from '@abp/request'; + +/** + * 查询权限 + * @param provider + * @returns 权限实体数据传输对象 + */ +export function getApi( + provider: PermissionProvider, +): Promise { + return requestClient.get( + `/api/permission-management/permissions`, + { + params: provider, + }, + ); +} + +/** + * 更新权限 + * @param provider + * @param input + */ +export function updateApi( + provider: PermissionProvider, + input: PermissionsUpdateDto, +): Promise { + return requestClient.put(`/api/permission-management/permissions`, input, { + params: provider, + }); +} diff --git a/apps/vben5/packages/@abp/permission/src/components/definitions/groups/PermissionGroupDefinitionModal.vue b/apps/vben5/packages/@abp/permission/src/components/definitions/groups/PermissionGroupDefinitionModal.vue new file mode 100644 index 000000000..1017376d1 --- /dev/null +++ b/apps/vben5/packages/@abp/permission/src/components/definitions/groups/PermissionGroupDefinitionModal.vue @@ -0,0 +1,7 @@ + + + + + diff --git a/apps/vben5/packages/@abp/permission/src/components/definitions/groups/PermissionGroupDefinitionTable.vue b/apps/vben5/packages/@abp/permission/src/components/definitions/groups/PermissionGroupDefinitionTable.vue new file mode 100644 index 000000000..1017376d1 --- /dev/null +++ b/apps/vben5/packages/@abp/permission/src/components/definitions/groups/PermissionGroupDefinitionTable.vue @@ -0,0 +1,7 @@ + + + + + diff --git a/apps/vben5/packages/@abp/permission/src/components/definitions/permissions/PermissionDefinitionModal.vue b/apps/vben5/packages/@abp/permission/src/components/definitions/permissions/PermissionDefinitionModal.vue new file mode 100644 index 000000000..1017376d1 --- /dev/null +++ b/apps/vben5/packages/@abp/permission/src/components/definitions/permissions/PermissionDefinitionModal.vue @@ -0,0 +1,7 @@ + + + + + diff --git a/apps/vben5/packages/@abp/permission/src/components/definitions/permissions/PermissionDefinitionTable.vue b/apps/vben5/packages/@abp/permission/src/components/definitions/permissions/PermissionDefinitionTable.vue new file mode 100644 index 000000000..1017376d1 --- /dev/null +++ b/apps/vben5/packages/@abp/permission/src/components/definitions/permissions/PermissionDefinitionTable.vue @@ -0,0 +1,7 @@ + + + + + diff --git a/apps/vben5/packages/@abp/permission/src/components/index.ts b/apps/vben5/packages/@abp/permission/src/components/index.ts new file mode 100644 index 000000000..8187ea421 --- /dev/null +++ b/apps/vben5/packages/@abp/permission/src/components/index.ts @@ -0,0 +1,3 @@ +export { default as PermissionGroupDefinitionTable } from './definitions/groups/PermissionGroupDefinitionTable.vue'; +export { default as PermissionDefinitionTable } from './definitions/permissions/PermissionDefinitionTable.vue'; +export { default as PermissionModal } from './permissions/PermissionModal.vue'; diff --git a/apps/vben5/packages/@abp/permission/src/components/permissions/PermissionModal.vue b/apps/vben5/packages/@abp/permission/src/components/permissions/PermissionModal.vue new file mode 100644 index 000000000..7fe29479b --- /dev/null +++ b/apps/vben5/packages/@abp/permission/src/components/permissions/PermissionModal.vue @@ -0,0 +1,321 @@ + + + + + diff --git a/apps/vben5/packages/@abp/permission/src/index.ts b/apps/vben5/packages/@abp/permission/src/index.ts new file mode 100644 index 000000000..195d95f59 --- /dev/null +++ b/apps/vben5/packages/@abp/permission/src/index.ts @@ -0,0 +1,2 @@ +export * from './components'; +export * from './types'; diff --git a/apps/vben5/packages/@abp/permission/src/types/index.ts b/apps/vben5/packages/@abp/permission/src/types/index.ts new file mode 100644 index 000000000..c85954d3e --- /dev/null +++ b/apps/vben5/packages/@abp/permission/src/types/index.ts @@ -0,0 +1 @@ +export * from './permissions'; diff --git a/apps/vben5/packages/@abp/permission/src/types/permissions.ts b/apps/vben5/packages/@abp/permission/src/types/permissions.ts new file mode 100644 index 000000000..d90634a90 --- /dev/null +++ b/apps/vben5/packages/@abp/permission/src/types/permissions.ts @@ -0,0 +1,60 @@ +interface PermissionProvider { + providerKey?: string; + providerName: string; +} + +interface PermissionDto { + allowedProviders: string[]; + displayName: string; + grantedProviders: PermissionProvider[]; + isGranted: boolean; + name: string; + parentName?: string; +} + +interface PermissionGroupDto { + displayName: string; + name: string; + permissions: PermissionDto[]; +} + +interface PermissionUpdateDto { + /** 是否授权 */ + isGranted: boolean; + /** 权限名称 */ + name: string; +} + +interface PermissionsUpdateDto { + permissions: PermissionUpdateDto[]; +} + +interface PermissionResultDto { + entityDisplayName: string; + groups: PermissionGroupDto[]; +} + +interface PermissionTree { + /** 子节点 */ + children: PermissionTree[]; + /** 是否禁用 */ + disabled: boolean; + /** 显示名称 */ + displayName: string; + /** 是否授权 */ + isGranted?: boolean; + isRoot: boolean; + /** 权限标识 */ + name: string; + /** 父节点 */ + parentName?: string; +} + +export type { + PermissionDto, + PermissionGroupDto, + PermissionProvider, + PermissionResultDto, + PermissionsUpdateDto, + PermissionTree, +}; diff --git a/apps/vben5/packages/@abp/permission/src/utils/index.ts b/apps/vben5/packages/@abp/permission/src/utils/index.ts new file mode 100644 index 000000000..7e30e0aab --- /dev/null +++ b/apps/vben5/packages/@abp/permission/src/utils/index.ts @@ -0,0 +1,143 @@ +import type { + PermissionDto, + PermissionGroupDto, + PermissionTree, +} from '../types/permissions'; + +import { listToTree } from '@abp/core'; + +export function generatePermissionTree( + permissionGroups: PermissionGroupDto[], +): PermissionTree[] { + const trees: PermissionTree[] = []; + permissionGroups.forEach((g) => { + const tree: PermissionTree = { + disabled: false, + displayName: g.displayName, + isRoot: true, + name: g.name, + parentName: g.name, + children: [], + }; + tree.children = listToTree(g.permissions, { + id: 'name', + pid: 'parentName', + }); + trees.push(tree); + }); + return trees; +} + +export function findNode( + children: PermissionTree[], + key: string, +): PermissionTree | undefined { + let findC: PermissionTree | undefined; + for (const child of children) { + if (child.name === key) { + findC = child; + return findC; + } + findC = findNode(child.children, key); + if (findC) { + return findC; + } + } + return findC; +} + +export function getPermissionsCount(children: PermissionTree[]): number { + let count = 0; + children.forEach((c) => { + count += getPermissionCount(c); + }); + return count; +} + +export function getPermissionCount(tree: PermissionTree): number { + let count = tree.children.length; + tree.children.forEach((c) => { + count += getPermissionCount(c); + }); + return count; +} + +export function getGrantPermissionsCount(children: PermissionTree[]): number { + let count = 0; + children.forEach((c) => { + count += getGrantPermissionCount(c); + }); + return count; +} + +export function getGrantPermissionCount(tree: PermissionTree): number { + return getGrantedPermissionKeys(tree.children).length; +} + +export function getGrantedPermissionKeys(children: PermissionTree[]): string[] { + const keys: string[] = []; + children.forEach((c) => { + if (c.isGranted === true) { + keys.push(c.name); + } + keys.push(...getGrantedPermissionKeys(c.children)); + }); + return keys; +} + +export function getParentList( + children: PermissionTree[], + name: string, +): PermissionTree[] | undefined { + for (const child of children) { + if (child.name === name) { + return [child]; + } + if (child.children) { + const node = getParentList(child.children, name); + if (node) { + return [...node, child]; + } + } + } +} + +export function toPermissionList(treeList: PermissionTree[]) { + const permissions: PermissionDto[] = []; + for (const element of treeList) { + if (!element.isRoot && element.isGranted !== undefined) { + permissions.push({ + allowedProviders: [], + displayName: element.displayName, + grantedProviders: [], + isGranted: element.isGranted, + name: element.name, + }); + } + permissions.push(...toPermissionList(element.children)); + } + return permissions; +} + +export function updateParentGrant( + tree: PermissionTree, + name: string, + grant: boolean, +) { + const parentList = getParentList(tree.children, name); + if (parentList && Array.isArray(parentList)) { + for (const element of parentList) { + element.isGranted = grant; + } + } +} + +export function updateChildrenGrant( + children: PermissionTree[], + grant: boolean, +) { + for (const child of children) { + child.isGranted = grant; + updateChildrenGrant(child.children, grant); + } +} diff --git a/apps/vben5/packages/@abp/permission/tsconfig.json b/apps/vben5/packages/@abp/permission/tsconfig.json new file mode 100644 index 000000000..ce1a891fb --- /dev/null +++ b/apps/vben5/packages/@abp/permission/tsconfig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "@vben/tsconfig/web.json", + "include": ["src"], + "exclude": ["node_modules"] +} diff --git a/apps/vben5/vben-admin.code-workspace b/apps/vben5/vben-admin.code-workspace index 9b7519c1a..9bc930a45 100644 --- a/apps/vben5/vben-admin.code-workspace +++ b/apps/vben5/vben-admin.code-workspace @@ -192,5 +192,9 @@ "name": "@abp/account", "path": "packages/@abp/account", }, + { + "name": "@abp/permission", + "path": "packages/@abp/permission", + }, ], }