diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuCreateInputVo.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuCreateInputVo.cs index ee5d658..1969e87 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuCreateInputVo.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuCreateInputVo.cs @@ -7,7 +7,10 @@ public class RbacMenuCreateInputVo { public string MenuName { get; set; } = string.Empty; - public Guid ParentId { get; set; } + /// + /// 父级ID(menu 表为字符串ID,可能是数字;根节点默认 0) + /// + public string ParentId { get; set; } = "0"; public int MenuType { get; set; } diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuGetListOutputDto.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuGetListOutputDto.cs index 6970d00..4a59a70 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuGetListOutputDto.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuGetListOutputDto.cs @@ -5,9 +5,9 @@ namespace FoodLabeling.Application.Contracts.Dtos.RbacMenu; /// public class RbacMenuGetListOutputDto { - public Guid Id { get; set; } + public string Id { get; set; } = string.Empty; - public Guid ParentId { get; set; } + public string ParentId { get; set; } = string.Empty; public string MenuName { get; set; } = string.Empty; diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuTreeDto.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuTreeDto.cs new file mode 100644 index 0000000..c0fbe0f --- /dev/null +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/Dtos/RbacMenu/RbacMenuTreeDto.cs @@ -0,0 +1,56 @@ +namespace FoodLabeling.Application.Contracts.Dtos.RbacMenu; + +/// +/// 权限树节点(返回菜单表全部字段) +/// +public class RbacMenuTreeDto +{ + public string Id { get; set; } = string.Empty; + + public bool IsDeleted { get; set; } + + public DateTime CreationTime { get; set; } + + public string? CreatorId { get; set; } + + public string? LastModifierId { get; set; } + + public DateTime? LastModificationTime { get; set; } + + public int OrderNum { get; set; } + + public bool State { get; set; } + + public string MenuName { get; set; } = string.Empty; + + public string? RouterName { get; set; } + + public int MenuType { get; set; } + + public string? PermissionCode { get; set; } + + public string ParentId { get; set; } = string.Empty; + + public string? MenuIcon { get; set; } + + public string? Router { get; set; } + + public bool IsLink { get; set; } + + public bool IsCache { get; set; } + + public bool IsShow { get; set; } + + public string? Remark { get; set; } + + public string? Component { get; set; } + + public int MenuSource { get; set; } + + public string? Query { get; set; } + + public string? ConcurrencyStamp { get; set; } + + public List? Children { get; set; } +} + diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IRbacMenuAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IRbacMenuAppService.cs index 2eba979..cf0e7c7 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IRbacMenuAppService.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application.Contracts/IServices/IRbacMenuAppService.cs @@ -1,6 +1,4 @@ using FoodLabeling.Application.Contracts.Dtos.RbacMenu; -using FoodLabeling.Application.Contracts.Dtos.Common; -using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; namespace FoodLabeling.Application.Contracts.IServices; @@ -11,14 +9,14 @@ namespace FoodLabeling.Application.Contracts.IServices; public interface IRbacMenuAppService : IApplicationService { /// - /// 权限分页列表 + /// 权限列表(不分页) /// - Task> GetListAsync(RbacMenuGetListInputVo input); + Task> GetListAsync(RbacMenuGetListInputVo input); /// /// 权限详情 /// - Task GetAsync(Guid id); + Task GetAsync(string id); /// /// 新增权限 @@ -28,11 +26,17 @@ public interface IRbacMenuAppService : IApplicationService /// /// 编辑权限 /// - Task UpdateAsync(Guid id, RbacMenuUpdateInputVo input); + Task UpdateAsync(string id, RbacMenuUpdateInputVo input); /// /// 删除权限(逻辑删除) /// - Task DeleteAsync(List ids); + Task DeleteAsync(List ids); + + /// + /// 获取全部权限树(GET) + /// + /// 树状权限列表 + Task> GetTreeAsync(); } diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/DbModels/MenuDbEntity.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/DbModels/MenuDbEntity.cs new file mode 100644 index 0000000..b5ed547 --- /dev/null +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/DbModels/MenuDbEntity.cs @@ -0,0 +1,58 @@ +using SqlSugar; + +namespace FoodLabeling.Application.Services.DbModels; + +/// +/// menu 表映射(兼容数字/字符串类型的 Id、ParentId) +/// +[SugarTable("menu")] +public class MenuDbEntity +{ + [SugarColumn(IsPrimaryKey = true)] + public string Id { get; set; } = string.Empty; + + public bool IsDeleted { get; set; } + + public DateTime CreationTime { get; set; } + + public string? CreatorId { get; set; } + + public string? LastModifierId { get; set; } + + public DateTime? LastModificationTime { get; set; } + + public int OrderNum { get; set; } + + public bool State { get; set; } + + public string MenuName { get; set; } = string.Empty; + + public string? RouterName { get; set; } + + public int MenuType { get; set; } + + public string? PermissionCode { get; set; } + + public string ParentId { get; set; } = "0"; + + public string? MenuIcon { get; set; } + + public string? Router { get; set; } + + public bool IsLink { get; set; } + + public bool IsCache { get; set; } + + public bool IsShow { get; set; } + + public string? Remark { get; set; } + + public string? Component { get; set; } + + public int MenuSource { get; set; } + + public string? Query { get; set; } + + public string? ConcurrencyStamp { get; set; } +} + diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/RbacMenuAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/RbacMenuAppService.cs index f4f8a4a..e23abcd 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/RbacMenuAppService.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/RbacMenuAppService.cs @@ -1,12 +1,10 @@ using FoodLabeling.Application.Contracts.Dtos.RbacMenu; -using FoodLabeling.Application.Contracts.Dtos.Common; using FoodLabeling.Application.Contracts.IServices; +using FoodLabeling.Application.Services.DbModels; using Microsoft.AspNetCore.Mvc; using SqlSugar; using Volo.Abp; using Volo.Abp.Application.Services; -using Volo.Abp.Domain.Entities; -using Yi.Framework.Rbac.Domain.Entities; using Yi.Framework.SqlSugarCore.Abstractions; namespace FoodLabeling.Application.Services; @@ -16,57 +14,44 @@ namespace FoodLabeling.Application.Services; /// public class RbacMenuAppService : ApplicationService, IRbacMenuAppService { - private readonly ISqlSugarRepository _menuRepository; + private readonly ISqlSugarDbContext _dbContext; - public RbacMenuAppService(ISqlSugarRepository menuRepository) + public RbacMenuAppService(ISqlSugarDbContext dbContext) { - _menuRepository = menuRepository; + _dbContext = dbContext; } /// - public async Task> GetListAsync([FromQuery] RbacMenuGetListInputVo input) + public async Task> GetListAsync([FromQuery] RbacMenuGetListInputVo input) { - RefAsync total = 0; - - var query = _menuRepository._DbQueryable + var query = _dbContext.SqlSugarClient.Queryable() .Where(x => x.IsDeleted == false) .WhereIF(!string.IsNullOrWhiteSpace(input.MenuName), x => x.MenuName.Contains(input.MenuName!.Trim())) .WhereIF(input.State is not null, x => x.State == input.State) - .WhereIF(input.MenuSource is not null, x => x.MenuSource == (Yi.Framework.Rbac.Domain.Shared.Enums.MenuSourceEnum)input.MenuSource!.Value) + .WhereIF(input.MenuSource is not null, x => x.MenuSource == input.MenuSource!.Value) .OrderBy(x => x.OrderNum, OrderByType.Desc); - var entities = await query.ToPageListAsync(input.SkipCount, input.MaxResultCount, total); + var entities = await query.ToListAsync(); - var items = entities.Select(x => new RbacMenuGetListOutputDto + return entities.Select(x => new RbacMenuGetListOutputDto { Id = x.Id, ParentId = x.ParentId, MenuName = x.MenuName ?? string.Empty, PermissionCode = x.PermissionCode, - MenuType = (int)x.MenuType, - MenuSource = (int)x.MenuSource, + MenuType = x.MenuType, + MenuSource = x.MenuSource, OrderNum = x.OrderNum, State = x.State }).ToList(); - - var pageSize = input.MaxResultCount <= 0 ? items.Count : input.MaxResultCount; - var pageIndex = pageSize <= 0 ? 1 : (input.SkipCount / pageSize) + 1; - var totalPages = pageSize <= 0 ? 0 : (int)Math.Ceiling(total / (double)pageSize); - - return new PagedResultWithPageDto - { - PageIndex = pageIndex, - PageSize = pageSize, - TotalCount = total, - TotalPages = totalPages, - Items = items - }; } /// - public async Task GetAsync(Guid id) + public async Task GetAsync(string id) { - var entity = await _menuRepository.GetSingleAsync(x => x.Id == id && x.IsDeleted == false); + var entity = await _dbContext.SqlSugarClient.Queryable() + .Where(x => x.Id == id && x.IsDeleted == false) + .SingleAsync(); if (entity is null) { throw new UserFriendlyException("权限不存在"); @@ -78,8 +63,8 @@ public class RbacMenuAppService : ApplicationService, IRbacMenuAppService ParentId = entity.ParentId, MenuName = entity.MenuName ?? string.Empty, PermissionCode = entity.PermissionCode, - MenuType = (int)entity.MenuType, - MenuSource = (int)entity.MenuSource, + MenuType = entity.MenuType, + MenuSource = entity.MenuSource, OrderNum = entity.OrderNum, State = entity.State }; @@ -94,28 +79,35 @@ public class RbacMenuAppService : ApplicationService, IRbacMenuAppService throw new UserFriendlyException("权限名称不能为空"); } - var entity = new MenuAggregateRoot + var entity = new MenuDbEntity { + Id = GuidGenerator.Create().ToString(), MenuName = name, - ParentId = input.ParentId, - MenuType = (Yi.Framework.Rbac.Domain.Shared.Enums.MenuTypeEnum)input.MenuType, - MenuSource = (Yi.Framework.Rbac.Domain.Shared.Enums.MenuSourceEnum)input.MenuSource, + ParentId = string.IsNullOrWhiteSpace(input.ParentId) ? "0" : input.ParentId.Trim(), + MenuType = input.MenuType, + MenuSource = input.MenuSource, PermissionCode = input.PermissionCode?.Trim(), Router = input.Router?.Trim(), Component = input.Component?.Trim(), OrderNum = input.OrderNum, - State = input.State + State = input.State, + IsDeleted = false, + CreationTime = DateTime.Now, + IsCache = false, + IsLink = false, + IsShow = true, + ConcurrencyStamp = string.Empty }; - EntityHelper.TrySetId(entity, () => GuidGenerator.Create()); - - await _menuRepository.InsertAsync(entity); + await _dbContext.SqlSugarClient.Insertable(entity).ExecuteCommandAsync(); return await GetAsync(entity.Id); } /// - public async Task UpdateAsync(Guid id, [FromBody] RbacMenuUpdateInputVo input) + public async Task UpdateAsync(string id, [FromBody] RbacMenuUpdateInputVo input) { - var entity = await _menuRepository.GetSingleAsync(x => x.Id == id && x.IsDeleted == false); + var entity = await _dbContext.SqlSugarClient.Queryable() + .Where(x => x.Id == id && x.IsDeleted == false) + .SingleAsync(); if (entity is null) { throw new UserFriendlyException("权限不存在"); @@ -128,30 +120,118 @@ public class RbacMenuAppService : ApplicationService, IRbacMenuAppService } entity.MenuName = name; - entity.ParentId = input.ParentId; - entity.MenuType = (Yi.Framework.Rbac.Domain.Shared.Enums.MenuTypeEnum)input.MenuType; - entity.MenuSource = (Yi.Framework.Rbac.Domain.Shared.Enums.MenuSourceEnum)input.MenuSource; + entity.ParentId = string.IsNullOrWhiteSpace(input.ParentId) ? "0" : input.ParentId.Trim(); + entity.MenuType = input.MenuType; + entity.MenuSource = input.MenuSource; entity.PermissionCode = input.PermissionCode?.Trim(); entity.Router = input.Router?.Trim(); entity.Component = input.Component?.Trim(); entity.OrderNum = input.OrderNum; entity.State = input.State; + entity.LastModificationTime = DateTime.Now; - await _menuRepository.UpdateAsync(entity); + await _dbContext.SqlSugarClient.Updateable(entity) + .Where(x => x.Id == entity.Id) + .ExecuteCommandAsync(); return await GetAsync(entity.Id); } /// - public async Task DeleteAsync([FromBody] List ids) + public async Task DeleteAsync([FromBody] List ids) { - var idList = ids?.Distinct().ToList() ?? new List(); + var idList = ids?.Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x.Trim()).Distinct().ToList() ?? new List(); if (idList.Count == 0) { return; } - // 权限表为软删(ISoftDelete) - await _menuRepository.DeleteAsync(x => idList.Contains(x.Id)); + await _dbContext.SqlSugarClient.Updateable() + .SetColumns(x => new MenuDbEntity { IsDeleted = true }) + .Where(x => idList.Contains(x.Id)) + .ExecuteCommandAsync(); + } + + /// + public async Task> GetTreeAsync() + { + // 返回所有字段,但过滤逻辑删除数据 + var menus = await _dbContext.SqlSugarClient.Queryable() + .Where(x => x.IsDeleted == false) + .OrderBy(x => x.OrderNum, OrderByType.Desc) + .ToListAsync(); + + var nodes = menus.Select(m => new RbacMenuTreeDto + { + Id = m.Id, + IsDeleted = m.IsDeleted, + CreationTime = m.CreationTime, + CreatorId = m.CreatorId, + LastModifierId = m.LastModifierId, + LastModificationTime = m.LastModificationTime, + OrderNum = m.OrderNum, + State = m.State, + MenuName = m.MenuName ?? string.Empty, + RouterName = m.RouterName, + MenuType = m.MenuType, + PermissionCode = m.PermissionCode, + ParentId = m.ParentId, + MenuIcon = m.MenuIcon, + Router = m.Router, + IsLink = m.IsLink, + IsCache = m.IsCache, + IsShow = m.IsShow, + Remark = m.Remark, + Component = m.Component, + MenuSource = m.MenuSource, + Query = m.Query, + ConcurrencyStamp = m.ConcurrencyStamp, + Children = new List() + }).ToList(); + + // TreeHelper 仅支持 Guid Id/ParentId,这里使用字符串 ParentId 自行构建树 + var nodeById = nodes + .Where(x => !string.IsNullOrWhiteSpace(x.Id)) + .GroupBy(x => x.Id) + .ToDictionary(g => g.Key, g => g.First()); + + foreach (var node in nodes) + { + node.Children ??= new List(); + var parentId = string.IsNullOrWhiteSpace(node.ParentId) ? "0" : node.ParentId.Trim(); + if (parentId == "0" || parentId == "00000000-0000-0000-0000-000000000000") + { + continue; + } + + if (nodeById.TryGetValue(parentId, out var parent)) + { + parent.Children ??= new List(); + parent.Children.Add(node); + } + } + + var roots = nodes + .Where(n => + { + var pid = string.IsNullOrWhiteSpace(n.ParentId) ? "0" : n.ParentId.Trim(); + return pid == "0" || pid == "00000000-0000-0000-0000-000000000000" || !nodeById.ContainsKey(pid); + }) + .ToList(); + + SortTree(roots); + return roots; + } + + private static void SortTree(List nodes) + { + nodes.Sort((a, b) => b.OrderNum.CompareTo(a.OrderNum)); + foreach (var node in nodes) + { + if (node.Children is { Count: > 0 }) + { + SortTree(node.Children); + } + } } }