using MyHomePage.Api.Models.Entities; namespace MyHomePage.Api.Models.Dtos; /// 分类输出 DTO(包含二级子项) public class CategoryDto { public int Id { get; set; } public int ParentId { get; set; } public string Name { get; set; } = string.Empty; public string? Icon { get; set; } public int Sort { get; set; } public DateTime CreatedAt { get; set; } public DateTime UpdatedAt { get; set; } public List Children { get; set; } = new(); /// /// 把扁平的 Category 实体集合构建为树形 DTO 列表。 /// 规则:parentId == 0 → 顶级;其余 → 挂到对应父分类的 Children 下。 /// 若父分类在当前集合中不存在(孤儿),降级为顶级。 /// 子项按 Sort, Id 升序排列。 /// public static List BuildTree(IEnumerable entities) { var list = entities .Select(c => new CategoryDto { Id = c.Id, ParentId = c.ParentId, Name = c.Name, Icon = c.Icon, Sort = c.Sort, CreatedAt = c.CreatedAt, UpdatedAt = c.UpdatedAt }) .ToList(); return BuildTreeFromFlat(list); } /// /// 把扁平的 DTO 集合构建为树形 DTO 列表(按 Id 重新组织父子关系)。 /// public static List BuildTreeFromFlat(IEnumerable flat) { var all = flat.ToList(); var byId = all.ToDictionary(d => d.Id); var roots = new List(); // 重置所有 Children(防止调用方传入了预填的 Children 造成重复) foreach (var d in all) d.Children = new List(); foreach (var d in all.OrderBy(x => x.Sort).ThenBy(x => x.Id)) { if (d.ParentId == 0 || !byId.TryGetValue(d.ParentId, out var parent)) { // 顶级 OR 孤儿(父分类不存在)→ 降级为顶级 roots.Add(d); } else { parent.Children.Add(d); } } // 给每个父分类的 children 排序 foreach (var r in roots) { r.Children = r.Children.OrderBy(x => x.Sort).ThenBy(x => x.Id).ToList(); } return roots; } } /// 分类创建/更新入参 public class CategoryUpsertRequest { public int? Id { get; set; } public int ParentId { get; set; } public string Name { get; set; } = string.Empty; public string? Icon { get; set; } public int Sort { get; set; } }