查看: 103|回复: 0

Abp Vnext扩展OrganizationUnit

[复制链接]

3

主题

8

帖子

14

积分

新手上路

Rank: 1

积分
14
发表于 2023-6-9 15:37:17 | 显示全部楼层 |阅读模式
前言

我们平时使用的abp框架默认是没有提供组织机构管理的相关页面和功能的。
但是组织机构管理这个功能在某些情况下是刚需,我们需要自定义它。
abp默认的包里面是包含了一部分关于组织机构管理的基础设施,包含:
Domain:OrganizationUnit相关实体定义、领域服务、仓储接口等内容。
Domain.Shared:OrgnaizationUnit相关的枚举常量等内容
EntityFrameworkCore:OrganizationUnit相关的仓储实现等。
由于Abp官方的开源库已经为我们实现了上述的一些基础功能,所以在我们实现自定义的OrganizationUnit的相关页面和功能时,实际上只需要考虑如下几方面的事情就可以了:
1、Application.Contracts,在这里需要定义OrganizationUnit的应用服务接口,各个DTO等。
2、Application,在这里需要实现在Application.Contracts层定义的接口。
3、HttpApi,在这里需要实现OrganizationUnit的Controller(如果需要的话)。
4、Web,在这里需要实现OrganizationUnit的UI设计。(当然如果你是前后端分离的话这块就不用弄了)
5、和OrganizationUnit相关的权限设置。由于OrganizationUnit在Abp里面属于Identity的范畴,所以围绕OrganizationUnit的权限需要处理好。
下面我们针对上面提出的四个方面逐一进行改造。
改造

一、Application.Contracts

首先是IOrganizationUnitAppService接口的定义:
public interface IOrganizationUnitAppService :
        ICrudAppService<OrganizationUnitDto,
                        Guid,
                        OrganizationUnitGetListInput,
                        OrganizationUnitCreateDto,
                        OrganizationUnitUpdateDto>
    {
        Task<ListResultDto<OrganizationUnitDto>> GetAllListAsync();

        Task<OrganizationUnitDto> GetLastChildOrNullAsync(Guid? parentId);

        Task MoveAsync(Guid id, OrganizationUnitMoveDto input);

        Task<ListResultDto<OrganizationUnitDto>> GetRootAsync();

        Task<ListResultDto<OrganizationUnitDto>> FindChildrenAsync(OrganizationUnitGetChildrenDto input);

        Task<ListResultDto<string>> GetRoleNamesAsync(Guid id);

        Task<PagedResultDto<IdentityRoleDto>> GetUnaddedRolesAsync(Guid id, OrganizationUnitGetUnaddedRoleListInput input);

        Task<PagedResultDto<IdentityRoleDto>> GetRolesAsync(Guid id, PagedAndSortedResultRequestDto input);

        Task AddRolesAsync(Guid id, OrganizationUnitAddRoleDto input);

        Task<PagedResultDto<IdentityUserDto>> GetUnaddedUsersAsync(Guid id, OrganizationUnitGetUnaddedUserListInput input);

        Task<PagedResultDto<IdentityUserDto>> GetUsersAsync(Guid id, GetIdentityUsersInput input);

        Task AddUsersAsync(Guid id, OrganizationUnitAddUserDto input);
        Task DeleteRoleAsync(Guid organizationUnitId, Guid roleId);
        Task DeleteUserAsync(Guid organizationUnitId, Guid userId);
    }
然后是针对上述接口的各个DTO的定义:
// OrganizationUnitAddRoleDto
public class OrganizationUnitAddRoleDto
    {
        [Required]
        public List<Guid> RoleIds { get; set; }
    }
//OrganizationUnitAddUserDto
public class OrganizationUnitAddUserDto
    {
        [Required]
        public List<Guid> UserIds { get; set; }
    }
//OrganizationUnitCreateDto
public class OrganizationUnitCreateDto : ExtensibleObject
    {
        [Required]
        [DynamicStringLength(typeof(OrganizationUnitConsts), nameof(OrganizationUnitConsts.MaxDisplayNameLength))]
        public string DisplayName { get; set; }

        public Guid? ParentId { get; set; }
    }
//OrganizationUnitDto
public class OrganizationUnitDto : ExtensibleAuditedEntityDto<Guid>
    {
        public Guid? ParentId { get; set; }
        public string Code { get; set; }
        public string DisplayName { get; set; }
    }
//OrganizationUnitGetChildrenDto
public class OrganizationUnitGetChildrenDto : IEntityDto<Guid>
    {
        [Required]
        public Guid Id { get; set; }
        public bool Recursive { get; set; }
    }
//OrganizationUnitGetListInput
public class OrganizationUnitGetListInput : FilterBase, IPagedAndSortedResultRequest
    {
        [CompareTo(nameof(OrganizationUnitDto.DisplayName))]
        [StringFilterOptions(AutoFilterer.Enums.StringFilterOption.Contains)]
        public string Filter { get; set; }
        public int SkipCount { get; set; }
        public int MaxResultCount { get; set; }
        public string Sorting { get; set; }
    }
//OrganizationUnitGetUnaddedRoleListInput
public class OrganizationUnitGetUnaddedRoleListInput : FilterBase, IPagedAndSortedResultRequest
    {
        public string Filter { get; set; }
        public int SkipCount { get; set; }
        public int MaxResultCount { get; set; }
        public string Sorting { get; set; }
    }
//OrganizationUnitGetUnaddedUserListInput
public class OrganizationUnitGetUnaddedUserListInput : FilterBase, IPagedAndSortedResultRequest
    {
        public string Filter { get; set; }
        public int SkipCount { get ; set ; }
        public int MaxResultCount { get ; set ; }
        public string Sorting { get ; set ; }
    }
//OrganizationUnitMoveDto
public class OrganizationUnitMoveDto
    {
        public Guid? ParentId { get; set; }
    }
//OrganizationUnitUpdateDto
public class OrganizationUnitUpdateDto : ExtensibleObject
    {
        public string DisplayName { get; set; }
    }
二、Application

这一层主要定义OrganizationUnitAppService,属于实现接口。
public class OrganizationUnitAppService : IdentityAppServiceBase, IOrganizationUnitAppService
    {
        protected OrganizationUnitManager OrganizationUnitManager { get; }
        protected IOrganizationUnitRepository OrganizationUnitRepository { get; }

        protected IdentityUserManager UserManager { get; }
        protected IIdentityRoleRepository RoleRepository { get; }
        protected IIdentityUserRepository UserRepository { get; }

        public OrganizationUnitAppService(
            IdentityUserManager userManager,
            IIdentityRoleRepository roleRepository,
            IIdentityUserRepository userRepository,
            OrganizationUnitManager organizationUnitManager,
            IOrganizationUnitRepository organizationUnitRepository)
        {
            UserManager = userManager;
            RoleRepository = roleRepository;
            UserRepository = userRepository;
            OrganizationUnitManager = organizationUnitManager;
            OrganizationUnitRepository = organizationUnitRepository;

            ObjectMapperContext = typeof(AbpIdentityApplicationModule);
        }

        public async virtual Task<OrganizationUnitDto> CreateAsync(OrganizationUnitCreateDto input)
        {
            var origanizationUnit = new OrganizationUnit(
                GuidGenerator.Create(), input.DisplayName, input.ParentId, CurrentTenant.Id)
            {
                CreationTime = Clock.Now
            };
            input.MapExtraPropertiesTo(origanizationUnit);

            await OrganizationUnitManager.CreateAsync(origanizationUnit);
            await CurrentUnitOfWork.SaveChangesAsync();

            return ObjectMapper.Map<OrganizationUnit, OrganizationUnitDto>(origanizationUnit);
        }

        public async virtual Task DeleteAsync(Guid id)
        {
            var origanizationUnit = await OrganizationUnitRepository.FindAsync(id);
            if (origanizationUnit == null)
            {
                return;
            }
            await OrganizationUnitManager.DeleteAsync(id);
        }

        public async virtual Task<ListResultDto<OrganizationUnitDto>> GetRootAsync()
        {
            var rootOriganizationUnits = await OrganizationUnitManager.FindChildrenAsync(null, recursive: false);

            return new ListResultDto<OrganizationUnitDto>(
                ObjectMapper.Map<List<OrganizationUnit>, List<OrganizationUnitDto>>(rootOriganizationUnits));
        }

        public async virtual Task<ListResultDto<OrganizationUnitDto>> FindChildrenAsync(OrganizationUnitGetChildrenDto input)
        {
            var origanizationUnitChildren = await OrganizationUnitManager.FindChildrenAsync(input.Id, input.Recursive);

            return new ListResultDto<OrganizationUnitDto>(
                ObjectMapper.Map<List<OrganizationUnit>, List<OrganizationUnitDto>>(origanizationUnitChildren));
        }

        public async virtual Task<OrganizationUnitDto> GetAsync(Guid id)
        {
            var origanizationUnit = await OrganizationUnitRepository.FindAsync(id);

            return ObjectMapper.Map<OrganizationUnit, OrganizationUnitDto>(origanizationUnit);
        }

        public async virtual Task<OrganizationUnitDto> GetLastChildOrNullAsync(Guid? parentId)
        {
            var origanizationUnitLastChildren = await OrganizationUnitManager.GetLastChildOrNullAsync(parentId);

            return ObjectMapper.Map<OrganizationUnit, OrganizationUnitDto>(origanizationUnitLastChildren);
        }

        public async virtual Task<ListResultDto<OrganizationUnitDto>> GetAllListAsync()
        {
            var origanizationUnits = await OrganizationUnitRepository.GetListAsync(false);

            return new ListResultDto<OrganizationUnitDto>(
                ObjectMapper.Map<List<OrganizationUnit>, List<OrganizationUnitDto>>(origanizationUnits));
        }

        public async virtual Task<PagedResultDto<OrganizationUnitDto>> GetListAsync(OrganizationUnitGetListInput input)
        {
            var origanizationUnitCount = await OrganizationUnitRepository.GetCountAsync();
            var origanizationUnits = await OrganizationUnitRepository
                .GetListAsync(input.Sorting, input.MaxResultCount, input.SkipCount, false);

            return new PagedResultDto<OrganizationUnitDto>(origanizationUnitCount,
                ObjectMapper.Map<List<OrganizationUnit>, List<OrganizationUnitDto>>(origanizationUnits));
        }

        public async virtual Task<ListResultDto<string>> GetRoleNamesAsync(Guid id)
        {
            var inOrignizationUnitRoleNames = await UserRepository.GetRoleNamesInOrganizationUnitAsync(id);
            return new ListResultDto<string>(inOrignizationUnitRoleNames);
        }

        public async virtual Task<PagedResultDto<IdentityRoleDto>> GetUnaddedRolesAsync(Guid id, OrganizationUnitGetUnaddedRoleListInput input)
        {
            var origanizationUnit = await OrganizationUnitRepository.GetAsync(id);

            var origanizationUnitRoleCount = await OrganizationUnitRepository
                .GetUnaddedRolesCountAsync(origanizationUnit, input.Filter);

            var origanizationUnitRoles = await OrganizationUnitRepository
                .GetUnaddedRolesAsync(origanizationUnit,
                input.Sorting, input.MaxResultCount,
                input.SkipCount, input.Filter);

            return new PagedResultDto<IdentityRoleDto>(origanizationUnitRoleCount,
                ObjectMapper.Map<List<IdentityRole>, List<IdentityRoleDto>>(origanizationUnitRoles));
        }

        public async virtual Task<PagedResultDto<IdentityRoleDto>> GetRolesAsync(Guid id, PagedAndSortedResultRequestDto input)
        {
            var origanizationUnit = await OrganizationUnitRepository.GetAsync(id);

            var origanizationUnitRoleCount = await OrganizationUnitRepository
                .GetRolesCountAsync(origanizationUnit);

            var origanizationUnitRoles = await OrganizationUnitRepository
                .GetRolesAsync(origanizationUnit,
                input.Sorting, input.MaxResultCount,
                input.SkipCount);

            return new PagedResultDto<IdentityRoleDto>(origanizationUnitRoleCount,
                ObjectMapper.Map<List<IdentityRole>, List<IdentityRoleDto>>(origanizationUnitRoles));
        }


        public async virtual Task<PagedResultDto<IdentityUserDto>> GetUnaddedUsersAsync(Guid id, OrganizationUnitGetUnaddedUserListInput input)
        {
            var origanizationUnit = await OrganizationUnitRepository.GetAsync(id);

            var origanizationUnitUserCount = await OrganizationUnitRepository
                .GetUnaddedUsersCountAsync(origanizationUnit, input.Filter);
            var origanizationUnitUsers = await OrganizationUnitRepository
                .GetUnaddedUsersAsync(origanizationUnit,
                input.Sorting, input.MaxResultCount,
                input.SkipCount, input.Filter);

            return new PagedResultDto<IdentityUserDto>(origanizationUnitUserCount,
                ObjectMapper.Map<List<IdentityUser>, List<IdentityUserDto>>(origanizationUnitUsers));
        }

        public async virtual Task<PagedResultDto<IdentityUserDto>> GetUsersAsync(Guid id, GetIdentityUsersInput input)
        {
            var origanizationUnit = await OrganizationUnitRepository.GetAsync(id);

            var origanizationUnitUserCount = await OrganizationUnitRepository
                .GetMembersCountAsync(origanizationUnit, input.Filter);
            var origanizationUnitUsers = await OrganizationUnitRepository
                .GetMembersAsync(origanizationUnit,
                input.Sorting, input.MaxResultCount,
                input.SkipCount, input.Filter);

            return new PagedResultDto<IdentityUserDto>(origanizationUnitUserCount,
                ObjectMapper.Map<List<IdentityUser>, List<IdentityUserDto>>(origanizationUnitUsers));
        }

        public async virtual Task MoveAsync(Guid id, OrganizationUnitMoveDto input)
        {
            await OrganizationUnitManager.MoveAsync(id, input.ParentId);
        }

        public async virtual Task<OrganizationUnitDto> UpdateAsync(Guid id, OrganizationUnitUpdateDto input)
        {
            var origanizationUnit = await OrganizationUnitRepository.GetAsync(id);
            origanizationUnit.DisplayName = input.DisplayName;
            input.MapExtraPropertiesTo(origanizationUnit);

            await OrganizationUnitManager.UpdateAsync(origanizationUnit);
            await CurrentUnitOfWork.SaveChangesAsync();

            return ObjectMapper.Map<OrganizationUnit, OrganizationUnitDto>(origanizationUnit);
        }

        public async virtual Task AddUsersAsync(Guid id, OrganizationUnitAddUserDto input)
        {
            var origanizationUnit = await OrganizationUnitRepository.GetAsync(id);

            foreach (var item in input.UserIds)
            {
                var user = await UserRepository.GetAsync(item);
                await UserManager.AddToOrganizationUnitAsync(user, origanizationUnit);
            }

            await CurrentUnitOfWork.SaveChangesAsync();
        }

        public async virtual Task AddRolesAsync(Guid id, OrganizationUnitAddRoleDto input)
        {
            var origanizationUnit = await OrganizationUnitRepository.GetAsync(id);

            foreach (var item in input.RoleIds)
            {
                var role = await RoleRepository.GetAsync(item);
                await OrganizationUnitManager.AddRoleToOrganizationUnitAsync(role, origanizationUnit);
            }

            await CurrentUnitOfWork.SaveChangesAsync();
        }

        public async virtual Task DeleteRoleAsync(Guid organizationUnitId, Guid roleId)
        {
            var origanizationUnit = await OrganizationUnitRepository.GetAsync(organizationUnitId);
            var role = await RoleRepository.GetAsync(roleId);
            await OrganizationUnitManager.RemoveRoleFromOrganizationUnitAsync(role, origanizationUnit);
        }

        public async virtual Task DeleteUserAsync(Guid organizationUnitId, Guid userId)
        {
            await UserManager.RemoveFromOrganizationUnitAsync(userId, organizationUnitId);
        }
    }
3、HttpApi

这一层主要定义OrganizationUnit的Controller,很简单,就需要它实现IOrganizationUnitAppService然后在方法内部继续调用IOrganizationUnitAppService的同名方法就可以了。
需要注意的是如果你的Abp开启了AutoController或者你是前后端分离,都不需要继续在这一层进行Controller的定义。
定义的过程很简单,就不放代码了。
4、Web

如果你的应用是Razor Page,那么需要在Web层定义Organization Unit的CRUD UI。
在Pages下面新建Identity/OrganizationUnits,分别定义如下razor pages:
Index:
//C#
namespace Wallee.FileManagement.Web.Pages.Identity.OrganizationUnits
{
    public class IndexModel : FileManagementPageModel
    {

        public void OnGet()
        {

        }
    }
}
//razor page
@page
@using Microsoft.AspNetCore.Authorization;
@using Microsoft.AspNetCore.Mvc.Localization;
@using Volo.Abp.AspNetCore.Mvc.UI.Layout;
@using Wallee.FileManagement.Localization;
@using Wallee.FileManagement.OrganizationUnits.Dtos;
@using Wallee.FileManagement.Permissions;
@using Wallee.FileManagement.Web.Pages.Identity.OrganizationUnits;
@model IndexModel
@inject IPageLayout PageLayout
@inject IAuthorizationService Authorization
@inject IHtmlLocalizer<FileManagementResource> L

@section scripts{
    <abp-script src="/Pages/Identity/OrganizationUnits/Index.js"></abp-script>
}
@section styles{
    <abp-style src="/Pages/Identity/OrganizationUnits/Index.css"></abp-style>
}
<abp-card>
    <abp-card-header>
        <abp-row>
            <abp-column size-md="_6">
                <abp-card-title>@L["OrganizationUnit"]</abp-card-title>
            </abp-column>
            <abp-column size-md="_6" class="text-end">

            </abp-column>
        </abp-row>
    </abp-card-header>
    <abp-card-body>
        <abp-row>
            <abp-column size-lg="_4">
                <abp-card>
                    <abp-card-header background="Light">
                        <div class="d-flex justify-content-between align-items-center">
                            <span>机构目录树</span>
                            @if (await Authorization.IsGrantedAsync(FileManagementPermissions.OrganizationUnits.Create))
                            {
                                <abp-button size="Small" button-type="Primary" icon="fas fa-plus" text="新增根机构" id="CreateNewOrganizationUnit"></abp-button>
                            }
                        </div>
                    </abp-card-header>
                    <abp-card-body>
                        <abp-table id="ousTable" class="nowrap" />
                    </abp-card-body>
                </abp-card>
            </abp-column>
            <abp-column size-lg="_8">
                <abp-tabs tab-style="Tab">
                    <abp-tab title="用户">
                        <abp-card id="userInfoEmpty" class="d-flex flex-column justify-content-center align-items-center">
                            <abp-card-body abp-rounded="Top" style="width:100%;" background="Light">
                                <abp-card-text>请点击左侧菜单选择机构进行用户相关操作</abp-card-text>
                            </abp-card-body>
                        </abp-card>
                        <abp-card id="userInfo">
                            <abp-card-header style="padding:0 0 10px 0;">
                                <div class="d-flex justify-content-between align-items-center">
                                    <abp-card-title class="text-primary" id="currentOuTitle_u"></abp-card-title>
                                    <abp-button button-type="Outline_Primary" icon="plus" id="addUserToOuBtn" text="新增用户"></abp-button>
                                </div>
                            </abp-card-header>
                            <abp-card-body style="padding:0 0 10px 0;">
                                <abp-table striped-rows="true" id="ouUsersTable" class="nowrap" />
                            </abp-card-body>
                        </abp-card>
                    </abp-tab>
                    <abp-tab title="角色">
                        <abp-card id="roleInfoEmpty" class="d-flex flex-column justify-content-center align-items-center">
                            <abp-card-body abp-rounded="Top" style="width:100%;" background="Light">
                                <abp-card-text>请点击左侧菜单选择机构进行角色相关操作</abp-card-text>
                            </abp-card-body>
                        </abp-card>
                        <abp-card id="roleInfo">
                            <abp-card-header style="padding:0 0 10px 0;">
                                <div class="d-flex justify-content-between align-items-center">
                                    <abp-card-title class="text-primary" id="currentOuTitle_r"></abp-card-title>
                                    <abp-button button-type="Outline_Primary" icon="plus" id="addRoleToOuBtn" text="新增角色"></abp-button>
                                </div>
                            </abp-card-header>
                            <abp-card-body style="padding:0 0 10px 0;">
                                <abp-table striped-rows="true" id="ouRolesTable" class="nowrap" />
                            </abp-card-body>
                        </abp-card>
                    </abp-tab>
                </abp-tabs>
            </abp-column>
        </abp-row>

    </abp-card-body>
</abp-card>

//javascript
$(function () {
    var l = abp.localization.getResource('FileManagement');
    var ouService = wallee.fileManagement.organizationUnits.organizationUnit;
    var createModal = new abp.ModalManager(abp.appPath + 'Identity/OrganizationUnits/CreateModal');
    var addRoleToOuModal = new abp.ModalManager(abp.appPath + "Identity/OrganizationUnits/AddRoleToOuModal");
    var addUserToOuModal = new abp.ModalManager(abp.appPath + "Identity/OrganizationUnits/AddUserToOuModal");
    var currentOu = null;
    var ouDataTable = null;
    var ouUserDataTable = null;
    var ouRoleDataTable = null;

    function initOuUserTable() {

        var inputAction = function (requestData, dataTableSettings) {
            return {
                filter: "",
            };
        };

        ouUserDataTable = $('#ouUsersTable').DataTable(abp.libs.datatables.normalizeConfiguration({
            processing: true,
            serverSide: true,
            paging: true,
            searching: false,
            autoWidth: false,
            scrollCollapse: true,
            order: [[0, "asc"]],
            ajax: abp.libs.datatables.createAjax(function () {
                return ouService.getUsers(currentOu, inputAction);
            }),
            columnDefs: [
                {
                    title: "登录名",
                    data: "userName",
                }, {
                    title: "用户名称",
                    data: "name",
                }, {
                    rowAction: {
                        items:
                            [
                                {
                                    text: "删除",
                                    visible: abp.auth.isGranted('FileManagement.OrganizationUnit.Delete'),
                                    confirmMessage: function (data) {
                                        return `确认删除当前用户吗?(${data.record.userName})`;
                                    },
                                    action: function (data) {
                                        ouService.deleteUser(currentOu, data.record.id)
                                            .then(function () {
                                                abp.notify.info(l('SuccessfullyDeleted'));
                                                ouUserDataTable.ajax.reload();
                                            });
                                    }
                                }
                            ]
                    }
                },
            ]
        }));
    }

    function initOuRoleTable() {

        var inputAction = function (requestData, dataTableSettings) {
            return {
                filter: "",
            };
        };

        ouRoleDataTable = $('#ouRolesTable').DataTable(abp.libs.datatables.normalizeConfiguration({
            processing: true,
            serverSide: true,
            paging: true,
            searching: false,
            autoWidth: false,
            scrollCollapse: true,
            order: [[0, "asc"]],
            ajax: abp.libs.datatables.createAjax(function () {
                return ouService.getRoles(currentOu, inputAction);
            }),
            columnDefs: [
                {
                    title: "角色名",
                    data: "name",
                }, {
                    rowAction: {
                        items:
                            [
                                {
                                    text: "删除",
                                    visible: abp.auth.isGranted('FileManagement.OrganizationUnit.Delete'),
                                    confirmMessage: function (data) {
                                        return `确认删除当前角色吗?(${data.record.name})`;
                                    },
                                    action: function (data) {
                                        ouService.deleteRole(currentOu, data.record.id)
                                            .then(function () {
                                                abp.notify.info(l('SuccessfullyDeleted'));
                                                ouRoleDataTable.ajax.reload();
                                            });
                                    }
                                }
                            ]
                    }
                },
            ]
        }));
    }

    function checkUserAndRoleInfoPanel() {
        if (!currentOu) {
            $("#userInfo").hide();
            $("#roleInfo").hide();
            $("#userInfoEmpty").show();
            $("#roleInfoEmpty").show();
        } else {
            $("#userInfoEmpty").remove();
            $("#roleInfoEmpty").remove();
            $("#userInfo").show();
            $("#roleInfo").show();
        }
    }

    function initOuDataTable() {
        ouDataTable = $('#ousTable').DataTable(abp.libs.datatables.normalizeConfiguration({
            processing: true,
            serverSide: true,
            paging: false,
            info: false,
            searching: false,//disable default searchbox
            autoWidth: false,
            scrollCollapse: true,
            order: [[0, "asc"]],
            ajax: abp.libs.datatables.createAjax(ouService.getAllList),
            columnDefs: [

                {
                    title: "机构名称",
                    data: "displayName",
                }, {
                    title: "操作",
                    rowAction: {
                        items:
                            [
                                {
                                    text: "查看",
                                    iconClass: "fas fa-search",
                                    displayNameHtml: false,
                                    visible: abp.auth.isGranted('FileManagement.OrganizationUnit'),
                                    action: function (data) {
                                        currentOu = data.record.id;
                                        $("#currentOuTitle_u").html(data.record.displayName);
                                        $("#currentOuTitle_r").html(data.record.displayName);
                                        checkUserAndRoleInfoPanel();
                                        if (!ouUserDataTable) {
                                            initOuUserTable();
                                        }
                                        else {
                                            ouUserDataTable.ajax.reload();
                                        }
                                        if (!ouRoleDataTable) {
                                            initOuRoleTable();
                                        }
                                        else {
                                            ouRoleDataTable.ajax.reload();
                                        }
                                    }
                                }, {
                                    text: l('Delete'),
                                    iconClass: "fas fa-trash",
                                    visible: abp.auth.isGranted('FileManagement.OrganizationUnit.Delete'),
                                    confirmMessage: function (data) {
                                        return l('FileDeletionConfirmationMessage', data.record.id);
                                    },
                                    action: function (data) {
                                        ouService.delete(data.record.id)
                                            .then(function () {
                                                abp.notify.info(l('SuccessfullyDeleted'));
                                                ouDataTable.ajax.reload();
                                            });
                                    }
                                }
                            ]
                    }
                },
            ]
        }));
    }

    initOuDataTable();

    checkUserAndRoleInfoPanel();

    $("#addUserToOuBtn").click(function (e) {
        addUserToOuModal.open({ organizationUnitId: currentOu });
    });

    $("#addRoleToOuBtn").click(function (e) {
        addRoleToOuModal.open({ organizationUnitId: currentOu });
    });

    $("#CreateNewOrganizationUnit").click(function () {
        createModal.open();
    });

    createModal.onResult(function (e, result) {
        ouDataTable.ajax.reload();
        abp.notify.success("操作成功");
    });

    addRoleToOuModal.onResult(function (e, result) {
        ouRoleDataTable.ajax.reload();
        abp.notify.success("操作成功");
    });

    addUserToOuModal.onResult(function (e, result) {
        ouUserDataTable.ajax.reload();
        abp.notify.success("操作成功");
    })
});


EditModal:
//C#
using Microsoft.AspNetCore.Mvc;
using System;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Volo.Abp.Identity;
using Volo.Abp.Validation;
using Wallee.FileManagement.OrganizationUnits;
using Wallee.FileManagement.OrganizationUnits.Dtos;

namespace Wallee.FileManagement.Web.Pages.Identity.OrganizationUnits
{
    public class EditModalModel : FileManagementPageModel
    {
        private readonly IOrganizationUnitAppService _organizationUnitAppService;

        [BindProperty(SupportsGet = true)]
        [HiddenInput]
        public Guid OrganizationUnitId { get; set; }

        [BindProperty]
        public OrganizationUnitUpdateViewModel ViewModel { get; set; }

        public EditModalModel(
            IOrganizationUnitAppService organizationUnitAppService)
        {
            _organizationUnitAppService = organizationUnitAppService;
        }
        public async Task OnGetAsync()
        {
            var dto = await _organizationUnitAppService.GetAsync(OrganizationUnitId);
            ViewModel = new OrganizationUnitUpdateViewModel { DisplayName = dto.DisplayName };
        }

        public async Task OnPostAsync()
        {
            var dto = ObjectMapper.Map<OrganizationUnitUpdateViewModel, OrganizationUnitUpdateDto>(ViewModel);
            await _organizationUnitAppService.UpdateAsync(OrganizationUnitId, dto);
        }
    }
    public class OrganizationUnitUpdateViewModel
    {
        [Display(Name = "机构名称")]
        [Required]
        [DynamicStringLength(typeof(OrganizationUnitConsts), nameof(OrganizationUnitConsts.MaxDisplayNameLength))]
        public string DisplayName { get; set; }
    }
}

//razor page
@page
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal;
@model Wallee.FileManagement.Web.Pages.Identity.OrganizationUnits.EditModalModel
@{
    Layout = null;
}
<abp-dynamic-form abp-model="ViewModel" data-ajaxForm="true" asp-page="EditModal">
    <abp-modal>
        <abp-modal-header title="新增机构"></abp-modal-header>
        <abp-modal-body>
            <abp-input asp-for="@Model.OrganizationUnitId"></abp-input>s
            <abp-form-content />
        </abp-modal-body>
        <abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer>
    </abp-modal>
</abp-dynamic-form>
CreateModal:
//C#
using System.ComponentModel.DataAnnotations;
using System;
using Volo.Abp.Identity;
using Volo.Abp.Validation;
using Wallee.FileManagement.OrganizationUnits.Dtos;
using Microsoft.AspNetCore.Mvc;
using Wallee.FileManagement.OrganizationUnits;
using System.Threading.Tasks;

namespace Wallee.FileManagement.Web.Pages.Identity.OrganizationUnits
{
    public class CreateModalModel : FileManagementPageModel
    {
        private readonly IOrganizationUnitAppService _organizationUnitAppService;

        [BindProperty]
        public OrganizationUnitCreateViewModel ViewModel { get; set; }

        [BindProperty(SupportsGet = true)]
        public Guid? ParentId { get; set; }

        public CreateModalModel(IOrganizationUnitAppService organizationUnitAppService)
        {
            _organizationUnitAppService = organizationUnitAppService;
        }
        public void OnGet()
        {
            ViewModel = new OrganizationUnitCreateViewModel
            {
                ParentId = ParentId
            };
        }

        public async Task OnPostAsync()
        {
            var dto = ObjectMapper.Map<OrganizationUnitCreateViewModel, OrganizationUnitCreateDto>(ViewModel);
            await _organizationUnitAppService.CreateAsync(dto);
        }
    }

    public class OrganizationUnitCreateViewModel
    {
        [Required]
        [Display(Name = "机构名称")]
        [DynamicStringLength(typeof(OrganizationUnitConsts), nameof(OrganizationUnitConsts.MaxDisplayNameLength))]
        public string DisplayName { get; set; }

        [HiddenInput]
        public Guid? ParentId { get; set; }
    }
}
//razor page
@page
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal;
@model Wallee.FileManagement.Web.Pages.Identity.OrganizationUnits.CreateModalModel
@{
    Layout = null;
}
<abp-dynamic-form abp-model="ViewModel" data-ajaxForm="true" asp-page="CreateModal">
    <abp-modal>
        <abp-modal-header title="新增机构"></abp-modal-header>
        <abp-modal-body>
            <abp-form-content />
        </abp-modal-body>
        <abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer>
    </abp-modal>
</abp-dynamic-form>
AddUserToOuModal:
//C#
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System;
using System.Threading.Tasks;
using Wallee.FileManagement.OrganizationUnits;
using Wallee.FileManagement.OrganizationUnits.Dtos;

namespace Wallee.FileManagement.Web.Pages.Identity.OrganizationUnits
{
    public class AddUserToOuModalModel : FileManagementPageModel
    {
        private readonly IOrganizationUnitAppService _organizationUnitAppService;

        [BindProperty(SupportsGet = true)]
        public Guid OrganizationUnitId { get; set; }
        [BindProperty]
        public OrganizationUnitDto OrganizationUnit { get; set; }
        public AddUserToOuModalModel(IOrganizationUnitAppService organizationUnitAppService)
        {
            _organizationUnitAppService = organizationUnitAppService;
        }
        public async Task OnGetAsync()
        {
            OrganizationUnit = await _organizationUnitAppService.GetAsync(OrganizationUnitId);
        }
    }
}
//razor page
@page
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal;
@model Wallee.FileManagement.Web.Pages.Identity.OrganizationUnits.AddUserToOuModalModel

@{
    Layout = null;
}

<abp-script src="/Pages/Identity/OrganizationUnits/AddUserToOuModal.js"></abp-script>

<script type="text/javascript">
    var organizationUnitId = "@Model.OrganizationUnitId";
</script>



<abp-modal size="Large">
    <abp-modal-header title="新增用户-@(Model.OrganizationUnit.DisplayName)"></abp-modal-header>
    <abp-modal-body>
        <abp-table id="unAddedUsersTable"></abp-table>
    </abp-modal-body>
    <form>
        <abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer>
    </form>
</abp-modal>

//javascript
$(function () {
    var ouService = wallee.fileManagement.organizationUnits.organizationUnit;

    var inputAction = function (requestData, dataTableSettings) {
        console.log(requestData);
        console.log(dataTableSettings);
        return {
            filter: "",
        };
    };
    function initOuUserTable() {
        ouUserDataTable = $('#unAddedUsersTable').DataTable(abp.libs.datatables.normalizeConfiguration({
            processing: true,
            serverSide: true,
            paging: true,
            searching: true,
            autoWidth: false,
            scrollCollapse: true,
            order: [[0, "asc"]],
            ajax: abp.libs.datatables.createAjax(function () {
                return ouService.getUnaddedUsers(organizationUnitId, inputAction);
            }),
            columnDefs: [
                {
                    title: "登录名",
                    data: "userName",
                }, {
                    title: "用户名",
                    data: "name",
                }, {
                    rowAction: {
                        items:
                            [
                                {
                                    text: "添加",
                                    visible: abp.auth.isGranted('FileManagement.OrganizationUnit.ManageUsers'),
                                    confirmMessage: function (data) {
                                        return `确认要添加该角色?(${data.record.name})`;
                                    },
                                    action: function (data) {
                                        ouService.addUsers(organizationUnitId, { UserIds: [data.record.id] })
                                    }
                                }
                            ]
                    }
                },
            ]
        }));
    }

    initOuUserTable();
})
AddRoleToOuModal:
//C#
using Microsoft.AspNetCore.Mvc;
using System;
using System.Threading.Tasks;
using Wallee.FileManagement.OrganizationUnits;
using Wallee.FileManagement.OrganizationUnits.Dtos;

namespace Wallee.FileManagement.Web.Pages.Identity.OrganizationUnits
{
    public class AddRoleToOuModalModel : FileManagementPageModel
    {
        private readonly IOrganizationUnitAppService _organizationUnitAppService;

        [BindProperty(SupportsGet = true)]
        public Guid OrganizationUnitId { get; set; }

        [BindProperty]
        public OrganizationUnitDto OrganizationUnit { get; set; }
        public AddRoleToOuModalModel(IOrganizationUnitAppService organizationUnitAppService)
        {
            _organizationUnitAppService = organizationUnitAppService;
        }

        public async Task OnGetAsync()
        {
            OrganizationUnit = await _organizationUnitAppService.GetAsync(OrganizationUnitId);
        }
    }
}

//razor page
@page
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal;
@using Wallee.FileManagement.Web.Pages.Identity.OrganizationUnits;
@model AddRoleToOuModalModel

@{
    Layout = null;
}

<abp-script src="/Pages/Identity/OrganizationUnits/AddRoleToOuModal.js"></abp-script>
<script type="text/javascript">
    var organizationUnitId = "@Model.OrganizationUnitId";
</script>
<abp-modal size="Large">
    <abp-modal-header title="新增角色-@(Model.OrganizationUnit.DisplayName)"></abp-modal-header>
    <abp-modal-body>
        <abp-table id="unAddedRoleTable"></abp-table>
    </abp-modal-body>
    <form>
        <abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer>
    </form>
</abp-modal>

//javascript
$(function () {
    var ouService = wallee.fileManagement.organizationUnits.organizationUnit;

    var inputAction = function (requestData, dataTableSettings) {
        console.log(requestData);
        console.log(dataTableSettings);
        return {
            filter: "",
        };
    };
    function initOuRoleTable() {
        ouRoleDataTable = $('#unAddedRoleTable').DataTable(abp.libs.datatables.normalizeConfiguration({
            processing: true,
            serverSide: true,
            paging: true,
            searching: false,
            autoWidth: false,
            scrollCollapse: true,
            order: [[0, "asc"]],
            ajax: abp.libs.datatables.createAjax(function () {
                return ouService.getUnaddedRoles(organizationUnitId, inputAction);
            }),
            columnDefs: [
                {
                    title: "角色名",
                    data: "name",
                }, {
                    rowAction: {
                        items:
                            [
                                {
                                    text: "添加",
                                    visible: abp.auth.isGranted('FileManagement.OrganizationUnit.ManageRoles'),
                                    confirmMessage: function (data) {
                                        return `确认要添加该角色?(${data.record.name})`;
                                    },
                                    action: function (data) {
                                        ouService.addRoles(organizationUnitId, { RoleIds: [data.record.id] })
                                    }
                                }
                            ]
                    }
                },
            ]
        }));
    }
    initOuRoleTable();
})5、权限

OrganizationUnit在Abp中属于Identity的范畴。Identity本身依赖于Abp的PermissionManagement模块,用于构建用户、角色以及机构和权限之间的关系。所以,在围绕OrganizationUnit构建它的权限之前,有必要对Abp的权限进行大概的说明。
Abp的权限基于http://asp.net core的授权流程,通过一系列的转换最终会转化为http://asp.net core中的以policy为基础进行授权的一种模式(详情:https://learn.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-7.0),每一个你在Abp中定义的PermissionDefinition都是一个asp.net core上的policy。
在Abp的Identity下面,我们可以通过以下途径为用户分配权限:
①、可以为用户定义专属于用户自身的权限;
②、可以为用户归属的角色定义该角色拥有的权限;
③、可以为用户归属的机构定义该机构拥有的角色,继而定义这个角色所拥有的权限
④、可以为用户归属的结构定义该机构拥有的权限;
那么,衡量一个用户到底拥有多少权限,就要从三个方面进行合并:①用户自身拥有的权限;②用户归属的角色所拥有的权限;③用户归属的组织机构所拥有的角色/权限。
拥有了上述的基础知识后,我们就可以进行下一步了。
首先我们了解一下Abp下面的权限的数据结构:
Abp关于权限的配置主要集中在两个命名空间下面:
①、Volo.Abp.Authorization
PermissionDefinitionProvider是用于定义你系统权限的一个基类,在你的Abp的启动项目下面的Application.Contracts中已经给你定义了一个默认的,比如XXXXPermissionDefinitionProvider,你在这个类中定义你的权限就可以了。
PermissionValueProvider是用于校验你是否能够访问一个API。Abp在Volo.Abp.Authorization里面内置了三个PermissionValueProvider:RolePermissionValueProvider、UserPermissionValueProvider以及ClientPermissionValueProvider。他们的逻辑基本都一样:在CheckAsync这个方法里面考量CurrentUser的相关的Claim的值,看看符不符合要求。
首先我们需要在Application.Contracts层定义我们的OrganizationUnit相关的权限:
//PermissionDefinitionProvider
var organizationUnitsPermission = myGroup.AddPermission(FileManagementPermissions.OrganizationUnits.Default, L("Permission:Organization"));
organizationUnitsPermission.AddChild(FileManagementPermissions.OrganizationUnits.Create, L("Permission:Create"));
organizationUnitsPermission.AddChild(FileManagementPermissions.OrganizationUnits.Update, L("Permission:Update"));
organizationUnitsPermission.AddChild(FileManagementPermissions.OrganizationUnits.Delete, L("Permission:Delete"));
organizationUnitsPermission.AddChild(FileManagementPermissions.OrganizationUnits.ManageRoles, L("Permission:OrganizationUnits:ManageRoles"));
organizationUnitsPermission.AddChild(FileManagementPermissions.OrganizationUnits.ManageUsers, L("Permission:OrganizationUnits:ManageUsers"));
然后我们新增一个OrganizationUnitPermissionVaueProvider:
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Authorization.Permissions;
using Wallee.FileManagement.Identity;

namespace Wallee.FileManagement.Authorization.Permissions;

public class OrganizationUnitPermissionValueProvider : PermissionValueProvider
{
    public const string ProviderName = "O";

    public override string Name => ProviderName;

    public OrganizationUnitPermissionValueProvider(
        IPermissionStore permissionStore)
        : base(permissionStore)
    {
    }

    public async override Task<PermissionGrantResult> CheckAsync(PermissionValueCheckContext context)
    {
        var organizationUnits = context.Principal?.FindAll(AbpOrganizationUnitClaimTypes.OrganizationUnit).Select(c => c.Value).ToArray();

        if (organizationUnits.IsNullOrEmpty())
        {
            return PermissionGrantResult.Undefined;
        }

        foreach (var organizationUnit in organizationUnits.Distinct())
        {
            if (await PermissionStore.IsGrantedAsync(context.Permission.Name, Name, organizationUnit))
            {
                return PermissionGrantResult.Granted;
            }
        }

        return PermissionGrantResult.Undefined;
    }

    public async override Task<MultiplePermissionGrantResult> CheckAsync(PermissionValuesCheckContext context)
    {
        var permissionNames = context.Permissions.Select(x => x.Name).Distinct().ToList();

        Check.NotNullOrEmpty(permissionNames, nameof(permissionNames));

        var result = new MultiplePermissionGrantResult(permissionNames.ToArray());

        var organizationUnits = context.Principal?.FindAll(AbpOrganizationUnitClaimTypes.OrganizationUnit).Select(c => c.Value).ToArray();

        if (organizationUnits.IsNullOrEmpty())
        {
            return result;
        }

        foreach (var organizationUnit in organizationUnits.Distinct())
        {
            var multipleResult = await PermissionStore.IsGrantedAsync(permissionNames.ToArray(), Name, organizationUnit);

            foreach (var grantResult in multipleResult.Result.Where(grantResult =>
                result.Result.ContainsKey(grantResult.Key) &&
                result.Result[grantResult.Key] == PermissionGrantResult.Undefined &&
                grantResult.Value != PermissionGrantResult.Undefined))
            {
                result.Result[grantResult.Key] = grantResult.Value;
                permissionNames.RemoveAll(x => x == grantResult.Key);
            }

            if (result.AllGranted || result.AllProhibited)
            {
                break;
            }

            if (permissionNames.IsNullOrEmpty())
            {
                break;
            }
        }

        return result;
    }
}
②、Volo.Abp.PermissionManagement
这个模块属于Abp的应用模块,用于持久化Abp的权限数据。Abp在这里定义了User和Role相关的Provider用于持久化,我们需要在这里定义OrganizationUnitPermissionManagementProvider:
using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy;
using Volo.Abp.PermissionManagement;
using Wallee.FileManagement.Authorization.Permissions;

namespace Wallee.FileManagement.PermissionManagement
{
    public class OrganizationUnitPermissionManagementProvider : PermissionManagementProvider
    {
        public override string Name => OrganizationUnitPermissionValueProvider.ProviderName;

        public OrganizationUnitPermissionManagementProvider(
            IPermissionGrantRepository permissionGrantRepository,
            IGuidGenerator guidGenerator,
            ICurrentTenant currentTenant)
            : base(
                permissionGrantRepository,
                guidGenerator,
                currentTenant)
        {
        }
    }
}
基于此,我们大概就完成了针对OrganizationUnit的自定义了。
需要注意的是我上面的代码没有完成针对OrganizationUnit的权限设置的改造,只是完成针对OrganizationUnit的角色绑定功能,有空/有需要的话我会对此进行升级。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表