📁 折叠与内嵌功能

编辑器提供了强大的折叠与内嵌功能,帮助用户在有限的屏幕空间内高效浏览和编辑复杂的配置数据。

🎯 功能概述

折叠功能

  • 任意非叶子节点都可以折叠(收起其所有叶子节点)
  • 通过折叠可以快速聚焦于特定数据分支
  • 支持手动折叠/展开,状态会自动保存

内嵌功能

  • 某些叶子节点可以内嵌到其父节点中显示
  • 内嵌后字段直接在父节点卡片中展示,不单独创建节点
  • 根据字段类型和数量智能判断是否可以内嵌

🔽 折叠功能 (Fold)

折叠功能允许用户收起不需要查看的节点分支,让界面更加清晰简洁。

操作方式

通过节点卡片操作

  1. 点击卡片左上角的折叠按钮
  2. 节点将被折叠,其所有子节点不再显示

折叠效果

折叠功能示例

图中说明

  • 折叠后的节点只显示核心信息
  • 子节点完全隐藏,但不影响数据
  • 再次点击可展开恢复显示

折叠状态保存

  • 折叠状态会自动保存到配置中
  • 下次打开相同记录时,折叠状态会自动恢复
  • 支持通过 $fold 字段在数据层面控制默认折叠状态

📌 内嵌功能 (Embed)

内嵌功能可以将满足特定条件的字段直接显示在父节点中,避免创建过多的节点,提升信息密度。

基本概念

内嵌前:每个字段都创建独立节点,树形结构庞大

父节点
├── 子节点1
├── 子节点2
└── 子节点3

内嵌后:字段直接在父节点卡片中显示

父节点 (包含子节点1、2、3的字段)

内嵌规则

自动过滤规则

空的 list 字段自动过滤

  • 如果某个 list 类型的字段值为空数组 []
  • 该字段不会在界面中显示
  • 减少无意义的信息干扰

Struct 内嵌条件

当字段类型为 struct 时,满足以下任一条件即可内嵌:

条件 描述 示例
条件1a struct 没有字段 空结构体 {}
条件1b struct 只有 1 个 primitive 字段 { name: string }
条件1c struct 只有 ≤3 个 number 字段 { x, y, z: int }
条件1d struct 只有 ≤4 个 bool 字段 { flag1, flag2, flag3, flag4: bool }
条件1e struct 只有 1 个 bool 字段和 1 个 number 字段 { enabled: bool, count: int }

primitive 类型包括:boolintlongfloatstrtext

Interface 内嵌条件

当字段类型为 interface 时,其 impl 需满足以下任一条件:

条件 描述 示例
条件2a interface 的 impl 没有字段 空实现 {}
条件2b interface 的 impl 只有 1 个 primitive 字段 { value: string }
条件2c interface 的 impl 只有 ≤2 个 number 字段 { x, y: float }
条件2d interface 的 impl 只有 ≤3 个 bool 字段 { a, b, c: bool }
条件2e interface 的 impl 只有 1 个 bool 字段和 1 个 number 字段 { active: bool, priority: int }

注意:interface 的内嵌条件比 struct 更严格,number 字段限制为 2 个(struct 为 3 个),bool 字段限制为 3 个(struct 为 4 个)。

List 内嵌条件

  • 父 node 中类型为 list 的 field,如果 list 只包含一项
  • 且该项满足上述 struct 或 interface 内嵌条件
  • 也可以内嵌显示

示例

// list 只有一个元素,且该元素满足内嵌条件
tags: [{ name: "重要" }]  // 可以内嵌

// list 有多个元素,即使单个元素满足条件也不内嵌
tags: [{ name: "重要" }, { name: "紧急" }]  // 不内嵌

内嵌效果展示

内嵌功能示例

图中说明

  • 内嵌后,字段直接在父节点中显示
  • 内嵌字段以紧凑的方式展示,节省空间

💡 Note 浮动提示

当字段包含注释(note)时,编辑器提供了友好的提示功能。

功能说明

黄色名称标识

  • 如果子节点有 note(注释)
  • 子节点的名称会以黄色显示
  • 快速识别哪些字段有详细说明

鼠标悬浮提示

  • 将鼠标悬停在黄色名称上
  • 会弹出浮动提示框
  • 显示完整的字段名称注释内容
  • 帮助用户理解字段的含义和用途

效果展示

Note 浮动提示

图中说明

  • 黄色高亮的字段名表示该字段有 note
  • 鼠标悬浮后显示完整的字段说明
  • 便于快速理解字段的业务含义

📊 内嵌规则详细对比

规则对比表

类型 无字段 单 primitive ≤2 number ≤3 number ≤3 bool ≤4 bool 1 bool + 1 number
Struct ✓ (1a) ✓ (1b) - ✓ (1c) - ✓ (1d) ✓ (1e)
Interface ✓ (2a) ✓ (2b) ✓ (2c) - ✓ (2d) - ✓ (2e)

使用场景建议

适合内嵌的场景

  • 简单配置项:如坐标、尺寸、开关等简单数据
  • 标识信息:如 ID、名称、类型等单字段数据
  • 状态标记:如多个 bool 开关组合
  • 元数据:如创建时间、更新时间等辅助信息

不适合内嵌的场景

  • 复杂对象:字段数量超过内嵌阈值
  • 嵌套结构:包含多层嵌套的复杂结构
  • 需要独立编辑:需要频繁修改的大型对象
  • 可视化重点:需要在图中突出显示的关键节点

⚙️ 技术实现细节

核心代码文件

内嵌功能的核心实现位于以下文件:

  • cfgeditor/src/routes/record/embedding/embeddingConfig.ts
    • 内嵌配置规则定义
    • 阈值和条件集中管理
    • 便于调整内嵌规则
  • cfgeditor/src/routes/record/embedding/embeddingChecker.ts
    • 字段类型分析器
    • 内嵌条件检查器
    • 空 list 字段过滤器
  • cfgeditor/src/flow/embedded/FoldStateHelper.tsx
    • Fold 状态管理助手
    • 统一 fold 状态获取逻辑
    • 消除代码重复

配置调整

如果需要修改内嵌规则,编辑 embeddingConfig.ts 文件:

export const EMBEDDING_CONFIG = {
  struct: {
    maxNumberFields: 3,      // 修改:struct 内嵌的 number 字段上限
    maxBoolFields: 4,        // 修改:struct 内嵌的 bool 字段上限
    // ...
  },
  interface: {
    maxNumberFields: 2,      // 修改:interface 内嵌的 number 字段上限
    maxBoolFields: 3,        // 修改:interface 内嵌的 bool 字段上限
    // ...
  },
}

修改后重新构建应用即可生效。


💻 最佳实践

1. 合理使用折叠

  • 按需折叠:只折叠当前不关注的分支
  • 保持上下文:不要折叠太多层级,避免迷失方向

3. Note 注释规范

  • 业务语境:提供业务含义,而非技术细节