You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

147 lines
4.9 KiB
C#

// ============================================================================
// 【文件说明】TreeSelect.cs - 树形选择器 DTO
// ============================================================================
// 这是一个用于前端树形选择器的数据传输对象。
//
// 【业务场景】
// 前端需要展示树形选择器(如配置类型选择),数据格式要求:
// {
// "id": 1,
// "label": "产品配置",
// "children": [
// { "id": 11, "label": "硬件产品", "children": [] },
// { "id": 12, "label": "软件产品", "children": [] }
// ]
// }
//
// 这个类就是把数据库的树形实体转换成前端需要的格式。
// ============================================================================
namespace Admin.NET.Plugin.HwPortal;
/// <summary>
/// 树形选择器 DTO。
/// <para>
/// 【用途说明】
/// 用于前端树形选择器组件,如:
/// - Element UI 的 el-tree-select
/// - Ant Design 的 TreeSelect
///
/// 标准的树形选择器数据格式:
/// - id节点唯一标识
/// - label节点显示文本
/// - children子节点列表
/// </para>
/// <para>
/// 【与 Java 若依的对比】
/// 若依框架也有类似的 TreeSelect 类:
/// public class TreeSelect {
/// private Long id;
/// private String label;
/// private List&lt;TreeSelect&gt; children;
/// }
///
/// 完全相同的设计,因为这是前端组件的标准数据格式。
/// </para>
/// </summary>
public class TreeSelect
{
/// <summary>
/// 默认构造函数。
/// <para>
/// 【C# 语法知识点 - 构造函数】
/// public TreeSelect() { }
///
/// 无参构造函数用于:
/// 1. 反序列化时创建对象JSON 反序列化需要无参构造函数)
/// 2. 创建空对象后手动赋值
/// </para>
/// </summary>
public TreeSelect()
{
}
/// <summary>
/// 从配置类型实体创建树形选择器节点。
/// <para>
/// 【C# 语法知识点 - 转换构造函数】
/// public TreeSelect(HwPortalConfigType portalConfigType)
///
/// 这是一个"转换构造函数",用于从一种类型转换成另一种类型。
///
/// 对比 Java
/// Java 通常用静态工厂方法或工具类:
/// public static TreeSelect from(HwPortalConfigType entity) {
/// TreeSelect select = new TreeSelect();
/// select.setId(entity.getConfigTypeId());
/// select.setLabel(entity.getConfigTypeName());
/// ...
/// return select;
/// }
///
/// C# 的转换构造函数更直观,使用更方便:
/// TreeSelect select = new TreeSelect(configType);
/// </para>
/// <para>
/// 【递归构建子节点】
/// Children = portalConfigType.Children.Select(u => new TreeSelect(u)).ToList()
///
/// 这是一行递归代码:
/// 1. portalConfigType.Children 获取子节点列表
/// 2. .Select(u => new TreeSelect(u)) 对每个子节点创建 TreeSelect
/// 3. 递归:创建子节点时,子节点又会创建孙节点...
///
/// 对比 Java
/// Java 需要手写递归:
/// private void buildChildren(HwPortalConfigType entity, TreeSelect select) {
/// if (entity.getChildren() != null && !entity.getChildren().isEmpty()) {
/// select.setChildren(entity.getChildren().stream()
/// .map(child -> {
/// TreeSelect childSelect = new TreeSelect(child);
/// buildChildren(child, childSelect);
/// return childSelect;
/// })
/// .collect(Collectors.toList()));
/// }
/// }
///
/// C# 的 LINQ + 转换构造函数让递归变得非常简洁。
/// </para>
/// </summary>
/// <param name="portalConfigType">配置类型实体</param>
public TreeSelect(HwPortalConfigType portalConfigType)
{
// Id 和 Label 是树形选择器的标准字段。
Id = portalConfigType.ConfigTypeId;
Label = portalConfigType.ConfigTypeName;
// 【递归构建子节点】
// 对每个子节点递归调用构造函数,自动构建整个子树。
Children = portalConfigType.Children.Select(u => new TreeSelect(u)).ToList();
}
/// <summary>
/// 节点唯一标识。
/// </summary>
public long? Id { get; set; }
/// <summary>
/// 节点显示文本。
/// </summary>
public string Label { get; set; }
/// <summary>
/// 子节点列表。
/// <para>
/// 【集合初始化】
/// = new() 是 C# 9.0 的"目标类型 new"语法。
/// 等价于 = new List&lt;TreeSelect&gt;()。
///
/// 为什么初始化为空列表?
/// 1. 避免 null 引用异常
/// 2. 叶子节点不需要特殊处理Children.Count = 0
/// </para>
/// </summary>
public List<TreeSelect> Children { get; set; } = new();
}