ABPフロントとリアエンドの開発フレームワーク開発シリーズ---(11)動的管理メニュー

エッセイの前では「ABPシリーズを中心に開発許可終了の開発フレームワーク---(9)ABP管理制御フレームワーク」ABPベースのフレームワークで説明をので、Winフォームのクライアントサービス、ウェブAPIの呼び出しによって取得したクライアントデータを構築しましたここのメニューセクションを必要としない組織、役割、ユーザー、権限管理を実現し、このエッセイは、ABPメニュー管理フレームワークの実装について説明し、メニューはWinフォームまたはWebインターフェイスを動的に重要な要素を構築するようですが、また、など一部のリソースの役割の権限を制御します。

 1、リスト表示やメニュー管理

一般的に、複数のノードに分割することができる、収縮可能なノードを拡張することができるメニューツリーのリストを表示し、もちろん、異なるアイコンのノードがあります。これは、ツリー内のポイントのリストに機能統合の多くを置くことができ、ツリーのノードは、多くのレベル、多くのレベルに分けることができます

  

私たちは、ビジネスの範囲に基づいて区別したい場合は、以下のように、一緒に道のタブに似た複数のモジュールの表示、メニュー表示モジュールリストに分けることができます。

上記の私のWinフォームWinフォームインターフェース開発フレームワークとABPのためのメニューインタフェースの開発フレームワークで提供するハイブリッド開発フレームワークである、私たちは別のデータモードを取得し、カテゴリ管理業務も違いはありません、我々はサーバーに残っていますエンド・コンフィギュレーション・メニューシステムを記録し、その後、ABPのWinフォームインターフェイスに基づいて、コンテンツを管理します。

ここでは、リソース管理リストインターフェイスのメニューABPのフレームワークです。

私たちは、リストを表示上の正しい方法ページングコントロールを示し、それはかなり標準Winフォームインターフェース表示であるTreeListリストが残しました。

次に示すメニューインタフェースを編集または作成します。

ロールのメニューは、それはインターフェースのリソースは、ユーザーの設定メニューの対応するロールを介して管理することが可能でなければなりません。

 

論理的なメニューのモジュールを達成するために2、

メニューモジュールを開発するために、我々は、以下の表とリレーショナルテーブル定義のメニューロールメニューの中央に示すように、ストレージデータテーブルの良いメニューを定義する必要があります。

メニューモジュールは、Webとして配置され、メニュー表には、いくつかのより多くのフィールド情報を増やすようWinフォームは、共通しています。

データベース内の2つのテーブルが増加した後、コード生成ツールWinフォームインターフェースコードを生成し、フレームのコードを生成するために使用することができます。

生成框架后,对应的应用服务层类代码如下所示。

这个生成的类,默认具有基类的增删改查分页等接口方法,同时我们也会生成对应的Web API Caller层的类代码,代码如下所示。

Winform界面生成标准界面后进行布局的一定调整,左侧增加TreeList控件,设计界面如下所示。

获取列表数据的函数定义在GetData函数里面,函数代码如下所示。

        /// <summary>
        /// 获取数据
        /// </summary>
        /// <returns></returns>
        private async Task<IPagedResult<MenuDto>> GetData()
        {
            MenuPagedDto pagerDto = null;
            if (advanceCondition != null)
            {
                pagerDto = new MenuPagedDto(this.winGridViewPager1.PagerInfo);
                pagerDto = dlg.GetPagedResult(pagerDto);
            }
            else if(!IsNormalSearch && this.tree.FocusedNode != null)
            {
                //构建分页的条件和查询条件
                pagerDto = new MenuPagedDto(this.winGridViewPager1.PagerInfo)
                {
                    PID = string.Concat(this.tree.FocusedNode.GetValue(Id_FieldName))
                };
            }
            else
            {
                //构建分页的条件和查询条件
                pagerDto = new MenuPagedDto(this.winGridViewPager1.PagerInfo)
                {
                    //添加所需条件
                    Name = this.txtName.Text.Trim(),
                    WinformType = this.txtWinformType.Text.Trim()
                };
            }

            var result = await MenuApiCaller.Instance.GetAll(pagerDto);
            return result;
        }

分页控件的数据绑定代码如下所示,这些都是根据Winform界面配置自动生成的代码。

            this.winGridViewPager1.DisplayColumns = "EmbedIcon,Name,Seq,Visible,Expand,WinformType,Tag,CreationTime";
            this.winGridViewPager1.ColumnNameAlias = await MenuApiCaller.Instance.GetColumnNameAlias();//字段列显示名称转义

            //获取分页数据列表
            var result = await GetData();

            //设置所有记录数和列表数据源
            this.winGridViewPager1.PagerInfo.RecordCount = result.TotalCount; //需先于DataSource的赋值,更新分页信息
            this.winGridViewPager1.DataSource = result.Items;

而TreeList列表是我们后来增加上去的,需要额外进行数据的绑定和处理,初始化树列表处理代码如下所示。

        /// <summary>
        /// 初始化树控件
        /// </summary>
        private void InitTree()
        {
            this.tree.Columns.Clear();
            //控件扩展函数封装处理
            this.tree.CreateColumn("Name", "菜单名称", 160, true);
            this.tree.InitTree("Id", "PID", null, false, false);

            //设置树的图标集合及逐级图标
            this.tree.SelectImageList = this.imageCollection1;
            this.tree.CustomDrawNodeImages += (object sender, CustomDrawNodeImagesEventArgs e) =>
            {
                int maxCount = this.imageCollection1.Images.Count;
                var index = e.Node.Level < maxCount ? e.Node.Level : 0;
                e.SelectImageIndex = index;
            };
            //初始化树节点选择事件
            this.tree.FocusedNodeChanged += delegate (object sender, FocusedNodeChangedEventArgs e)
            {
                this.FocusedNodeChanged();
            };
        }

获取列表数据并绑定树列表的数据源如下所示

        /// <summary>
        /// 绑定树的数据源
        /// </summary>
        private async Task BindTree()
        {
            var pageDto = new MenuPagedDto();
            var result = await MenuApiCaller.Instance.GetAll(pageDto);

            this.tree.DataSource = result.Items;
            this.tree.ExpandAll();
        }

而界面显示的时候,加载并显示左侧树列表数据如下代码所示。

        private async void FrmMenu_Load(object sender, EventArgs e)
        {
            //列表信息
            InitTree();
            InitSearchControl();
            await BindTree();
        }

删除菜单的时候,我们一般想把当前菜单和下面的子菜单一并级联删除,实现这个方法,我们需要在服务端自定义实现,如下是应用服务层的实现方法。

        /// <summary>
        /// 移除节点和子节点
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [UnitOfWork]
        public virtual async Task DeleteWithSubNode(EntityDto<string> input)
        {
            var children = await _repository.GetAllListAsync(ou => ou.PID == input.Id);
            foreach (var child in children)
            {
                await DeleteWithSubNode(new EntityDto<string>(child.Id));//递归删除
            }

            await _repository.DeleteAsync(input.Id);
        }

我们这里显示声明了UnitOfWork标记,说明这个操作的原子性,全部成功就成功,否则失败的处理。

而客户端的Web API 封装调用类,对这个Web API接口的封装,根据上篇随笔《ABP开发框架前后端开发系列---(10)Web API调用类的简化处理》简化后的处理代码如下所示。

 

3、角色菜单管理

菜单的管理整体操作和常规的业务表处理一样,没有太多特殊的地方,下面介绍一下角色包含菜单的管理操作。

前面介绍了角色包含菜单的管理界面如下所示。

界面主要是列出所有菜单,并勾选上该角色可以使用的菜单。这个角色包含的菜单和角色包含的权限处理上比较相似。

首先我们需要定义一个角色DTO对象中的菜单集合属性,如下所示。

在界面上获取勾选上的权限和菜单ID集合,存储在对应的列表里面。

        /// <summary>
        /// 编辑或者保存状态下取值函数
        /// </summary>
        /// <param name="info"></param>
        private void SetInfo(RoleDto info)
        {
            info.DisplayName = txtDisplayName.Text;
            info.Name = txtName.Text;
            info.Description = txtDescription.Text;

            info.Permissions = GetNodeValues(this.tree, "Name");
            info.Menus = GetNodeValues(this.treeMenu, "Id");
        }

在应用服务层的RoleAppService类里面,我们创建或者更新角色的时候,需要更新它的权限和菜单资源,如下代码是创建角色的函数。

        /// <summary>
        /// 创建角色对象
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public override async Task<RoleDto> Create(CreateRoleDto input)
        {
            CheckCreatePermission();

            var role = ObjectMapper.Map<Role>(input);
            role.SetNormalizedName();

            CheckErrors(await _roleManager.CreateAsync(role));
            await CurrentUnitOfWork.SaveChangesAsync(); //It's done to get Id of the role.

            await UpdateGrantedPermissions(role, input.Permissions);
            await UpdateGrantedMenus(role, input.Menus);

            return MapToEntityDto(role);
        }

同理,更新角色一样处理这两个部分的资源

        /// <summary>
        /// 更新角色对象
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public override async Task<RoleDto> Update(RoleDto input)
        {
            CheckUpdatePermission();

            var role = await _roleManager.GetRoleByIdAsync(input.Id);

            ObjectMapper.Map(input, role);

            CheckErrors(await _roleManager.UpdateAsync(role));

            await UpdateGrantedPermissions(role, input.Permissions);
            await UpdateGrantedMenus(role, input.Menus);

            return MapToEntityDto(role);
        }

以上就是菜单的管理,和角色包含菜单的维护操作,整个开发过程主要就是使用代码生成工具来快速生成框架各个层的代码,以及Winform界面的代码,这样在进行一定的函数扩展以及界面布局调整,就可以非常方便、高效的完整一个业务模块的开发工作了。

 

おすすめ

転載: www.cnblogs.com/wuhuacong/p/11103268.html