• 造轮子之菜单管理


    前面完成了基础管理的相关API,接下来就得做一个菜单管理了,用于对接管理后台前端界面。

    设计菜单结构#

    菜单是一个多级结构,所以我们得设计一个树形的。包含自己上级和下级的属性。同时预留Permission用于做可选的权限限制。

    namespace Wheel.Domain.Menus
    {
        /// 
        /// 菜单
        /// 
        public class Menu : Entity<Guid>
        {
            /// 
            /// 名称
            /// 
            public string Name { get; set; }
            /// 
            /// 显示名称
            /// 
            public string DisplayName { get; set; }
            /// 
            /// 菜单类型
            /// 
            public MenuType MenuType { get; set; }
            /// 
            /// 菜单路径
            /// 
            public string? Path { get; set; }
            /// 
            /// 权限名称
            /// 
            public string? Permission { get; set; }
            /// 
            /// 图标
            /// 
            public string? Icon { get; set; }
            /// 
            /// 排序
            /// 
            public int Sort { get; set; }
            /// 
            /// 上级菜单Id
            /// 
            public virtual Guid? ParentId { get; set; }
            /// 
            /// 上级菜单
            /// 
            public virtual Menu? Parent { get; set; }
            /// 
            /// 子菜单
            /// 
            public virtual List Children { get; set; }
        }
    }
    
    

    然后菜单和角色关联。创建RoleMenu表。

    namespace Wheel.Domain.Menus
    {
        public class RoleMenu
        {
            public virtual string RoleId { get; set; }
            public virtual Role Role { get; set; }
            public virtual Guid MenuId { get; set; }
            public virtual Menu Menu { get; set; }
        }
    }
    

    修改DbContext#

    接下来还是老套路,修改WheelDbContext
    添加代码:

    #region Menu
    public DbSet Menus { get; set; }
    public DbSet RoleMenus { get; set; }
    #endregion
    
    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
    
        ConfigureIdentity(builder);
        ConfigureLocalization(builder);
        ConfigurePermissionGrants(builder);
        ConfigureMenus(builder);
    }
    
    void ConfigureMenus(ModelBuilder builder)
    {
        builder.Entity(b =>
        {
            b.HasKey(o => o.Id);
            b.Property(o => o.Permission).HasMaxLength(128);
            b.Property(o => o.Path).HasMaxLength(128);
            b.Property(o => o.Name).HasMaxLength(128);
            b.Property(o => o.Icon).HasMaxLength(128);
            b.Property(o => o.DisplayName).HasMaxLength(128);
            b.HasMany(o => o.Children).WithOne(o => o.Parent);
            b.HasIndex(o => o.ParentId);
        });
        builder.Entity(b =>
        {
            b.HasKey(o => new { o.MenuId, o.RoleId });
            b.Property(o => o.RoleId).HasMaxLength(36);
        });
    }
    

    然后执行数据库迁移命令即可完成表创建。

    实现菜单管理#

    接下来就可以来实现我们的菜单管理相关功能了。

    实现MenuAppService#

    IMenuAppService

    namespace Wheel.Services.Menus
    {
        public interface IMenuAppService : ITransientDependency
        {
            Task Create(CreateOrUpdateMenuDto dto);
            Task Update(Guid id, CreateOrUpdateMenuDto dto);
            Task Delete(Guid id);
            Task> GetById(Guid id);
            Task>> GetList();
            Task>> GetRoleMenuList(string roleId);
            Task>> GetCurrentMenu();
            Task UpdateRoleMenu(string roleId, UpdateRoleMenuDto dto);
        }
    }
    

    MenuAppService

    namespace Wheel.Services.Menus
    {
        public class MenuAppService : WheelServiceBase, IMenuAppService
        {
            private readonly IBasicRepository _menuRepository;
            private readonly IBasicRepositorystring> _roleRepository;
            private readonly IBasicRepository _roleMenuRepository;
    
            public MenuAppService(IBasicRepository menuRepository)
            {
                _menuRepository = menuRepository;
            }
    
            public async Task Create(CreateOrUpdateMenuDto dto)
            {
                var menu = Mapper.Map(dto);
                menu.Id = GuidGenerator.Create();
                await _menuRepository.InsertAsync(menu, true);
                return new R();
            }
    
            public async Task Update(Guid id,CreateOrUpdateMenuDto dto)
            {
                var menu = await _menuRepository.FindAsync(id);
                if(menu != null) 
                {
                    Mapper.Map(dto, menu);
                    await _menuRepository.UpdateAsync(menu, true);
                }
                return new R();
            }
            public async Task Delete(Guid id)
            {
                await _menuRepository.DeleteAsync(id, true);
                return new R();
            }
            public async Task> GetById(Guid id)
            {
                var menu = await _menuRepository.FindAsync(id);
    
                var dto = Mapper.Map(menu);
                return new R(dto);
            }
            public async Task>> GetList()
            {
                var items = await _menuRepository.GetListAsync(
                    a => a.ParentId == null,
                    propertySelectors: a=>a.Children
                    );
                items.ForEach(a => a.Children = a.Children.OrderBy(b => b.Sort).ToList());
                items = items.OrderBy(a => a.Sort).ToList();
                var resultItems = Mapper.Map>(items);
                return new R>(resultItems);
            }
            public async Task UpdateRoleMenu(string roleId, UpdateRoleMenuDto dto)
            {
                using (var uow = await UnitOfWork.BeginTransactionAsync())
                {
                    if (await _roleMenuRepository.AnyAsync(a => a.RoleId == roleId))
                    {
                        await _roleMenuRepository.DeleteAsync(a => a.RoleId == roleId);
                    }
                    if(dto.MenuIds.Any())
                    {
                        var roleMenus = dto.MenuIds.Select(a => new RoleMenu { RoleId = roleId, MenuId = a });
                        await _roleMenuRepository.InsertManyAsync(roleMenus.ToList());
                    }
                    await uow.CommitAsync();
                }
                return new R();
            }
            public async Task>> GetRoleMenuList(string roleId)
            {
                var items = await _roleMenuRepository.SelectListAsync(a => a.RoleId == roleId && a.Menu.ParentId == null, a => a.Menu, propertySelectors: a => a.Menu.Children);
                items.ForEach(a => a.Children = a.Children.OrderBy(b => b.Sort).ToList());
                items = items.OrderBy(a => a.Sort).ToList();
                var resultItems = Mapper.Map>(items);
                return new R>(resultItems);
            }
    
            public async Task>> GetCurrentMenu()
            {
                if (CurrentUser.IsInRoles("admin"))
                {
                    var menus = await _menuRepository.GetListAsync(a => a.ParentId == null);
                    return new R>(MaptoAntdMenu(menus));
                }
                else
                {
                    var roleIds = await _roleRepository.SelectListAsync(a => CurrentUser.Roles.Contains(a.Name), a => a.Id);
                    var menus = await _roleMenuRepository.SelectListAsync(a => roleIds.Contains(a.RoleId) && a.Menu.ParentId == null, a => a.Menu, propertySelectors: a => a.Menu.Children);
    
                    return new R>(MaptoAntdMenu(menus.DistinctBy(a=>a.Id).ToList()));
                }
            }
    
            private List MaptoAntdMenu(List menus)
            {
                return menus.OrderBy(m => m.Sort).Select(m =>
                {
                    var result = new AntdMenuDto
                    {
                        Name = m.Name,
                        Icon = m.Icon,
                        Path = m.Path,
                        Access = m.Permission
                    };
                    if(m.Children != null && m.Children.Count > 0)
                    {
                        result.Children = MaptoAntdMenu(m.Children);
                    }
                    return result;
                }).ToList();
            }
        }
    }
    

    实现MenuController#

    namespace Wheel.Controllers
    {
        /// 
        /// 菜单管理
        /// 
        [Route("api/[controller]")]
        [ApiController]
        public class MenuController : WheelControllerBase
        {
            private readonly IMenuAppService _menuAppService;
    
            public MenuController(IMenuAppService menuAppService)
            {
                _menuAppService = menuAppService;
            }
            /// 
            /// 新增菜单
            /// 
            /// 
            /// 
            [HttpPost()]
            public Task Create(CreateOrUpdateMenuDto dto)
            {
                return _menuAppService.Create(dto);
            }
            /// 
            /// 删除菜单
            /// 
            /// 
            /// 
            [HttpDelete("{id}")]
            public Task Delete(Guid id)
            {
                return _menuAppService.Delete(id);
            }
            /// 
            /// 获取单个菜单详情
            /// 
            /// 
            /// 
            [HttpGet("{id}")]
            public Task> GetById(Guid id)
            {
                return _menuAppService.GetById(id);
            }
            /// 
            /// 查询菜单列表
            /// 
            /// 
            [HttpGet]
            public Task>> GetList()
            {
                return _menuAppService.GetList();
            }
            /// 
            /// 修改菜单
            /// 
            /// 
            /// 
            /// 
            [HttpPut("{id}")]
            public Task Update(Guid id, CreateOrUpdateMenuDto dto)
            {
                return _menuAppService.Update(id, dto);
            }
            /// 
            /// 修改角色菜单
            /// 
            /// 
            /// 
            /// 
            [HttpPut("role/{roleId}")]
            public Task UpdateRoleMenu(string roleId, UpdateRoleMenuDto dto)
            {
                return _menuAppService.UpdateRoleMenu(roleId, dto);
            }
            /// 
            /// 获取角色菜单列表
            /// 
            /// 
            /// 
            [HttpGet("role/{roleId}")]
            public Task>> GetRoleMenuList(string roleId)
            {
                return _menuAppService.GetRoleMenuList(roleId);
            }
        }
    }
    

    就这样我们就完成了菜单管理相关的API功能,包含菜单的增删查改和角色菜单绑定功能。
    到这里我们最基础的后台管理功能API基本开发完成。

    轮子仓库地址https://github.com/Wheel-Framework/Wheel
    欢迎进群催更。

    image.png

  • 相关阅读:
    Linq to SQL语句之Top/Bottom和Paging分页和SqlMethods
    船舶单独安装的双频GNSS的PPP解算
    spark 窗口滑动用于在不同的数据块之间执行操作
    Linux阻塞IO(高级字符设备二)
    算法功能:边缘缺陷检测
    Xamarin实现App展示启动界面
    mac下nodejs的卸载与安装
    Raft 共识算法
    qt day5 数据库,tcp
    怎么选择一款安心的墙布产品?-江南爱窗帘十大品牌
  • 原文地址:https://www.cnblogs.com/fanshaoO/p/17759180.html