跳到主要内容

布局器

布局器(LayoutEditor)是平台页面的可视化搭建工具,通过拖拽组件、调整列宽与嵌套容器,完成页面布局的配置。

概述​

在页面列表中点击页面名称即可进入布局器。布局器由顶部工具栏、左侧组件面板与中间画布三部分组成:

  • 顶部工具栏:切换编辑/预览模式、执行页面设置、加载模板、菜单配置、授权与预览、保存布局。
  • 左侧组件面板:按分类展示可拖拽的组件,支持关键字搜索。
  • 中间画布:展示当前布局,是组件的拖放目标区域。

布局配置最终以组件树(WidgetItem[])的形式保存到页面的 Layout 属性中。了解布局树的完整字段、嵌套规则与完整存储示例,参见 页面全局属性。

组件面板​

左侧组件面板按分类折叠展示,每个组件以卡片形式呈现,包含组件名称与说明。面板顶部提供组件搜索输入框,输入关键字后按组件名称过滤。

组件以拖拽的方式添加到画布:按住组件卡片拖动到画布的插入指示线位置松开即可插入。组件也可以从画布内的一个容器拖动到另一个容器,实现移动与嵌套。

单例组件

同一布局中只能使用一次的组件(例如占位组件)在添加到布局后,左侧面板中对应项会变为禁用状态。

画布与拖放​

画布本身是布局的根容器,顶层组件在画布中垂直排列。拖放时:

  • 画布会实时显示插入位置的指示线,松开后组件插入到指示位置。
  • 拖拽过程中,光标旁会浮出当前组件的名称标签。
  • 嵌套容器(如 Tab 页、Step 页、列)内部同样是可放置区域,支持多层嵌套。
  • 空布局时画布显示「从左侧组件库拖拽组件开始搭建布局」的占位提示。

组件操作​

选中画布中的组件后,组件右上角会浮出工具栏,提供以下操作(列容器除外):

操作说明
上移在当前容器内将组件上移一位
下移在当前容器内将组件下移一位
复制组件复制当前组件(含子组件)并插入到其后
移除此组件从布局中移除当前组件及其子组件
属性设置打开右侧属性抽屉,配置该组件属性(双击组件可快速打开)

列容器(Column)是结构性容器,不提供上移/下移/复制/移除操作,改为提供拆分列与删除列(详见 基础容器)。

属性配置抽屉​

组件的属性在右侧抽屉中配置,抽屉标题为组件类型名称,顶部额外提供上移、下移、复制、移除快捷操作。抽屉内容由组件自身的属性面板渲染,各组件可配置项参见各类组件文档。

属性修改会即时同步到布局中,但只有点击顶部保存布局并确认后,才会持久化到服务端。

顶部工具栏​

操作说明
编辑模式 / 预览模式开关切换,预览模式下按用户态渲染当前布局
跳转到平台页面列表返回当前应用的页面列表
最近修改时间展示页面布局的最近修改时间
页面设置打开页面全局属性配置抽屉,见 页面全局属性
菜单配置在新窗口打开菜单设置,将页面挂载到菜单
授权在新窗口打开应用授权,按页面资源分配访问权限
加载模板选择页面模板,将其布局导入到当前页面
预览在新窗口以用户态打开页面,部分依赖数据 ID 的页面无法正常预览
保存布局确认后保存当前布局到服务端
加载模板会覆盖当前布局

「加载模板」会将所选模板的布局替换为当前页面的布局,操作前请先确认当前布局已保存。

使用建议​

  1. 先使用布局组件(基础容器、Tab 容器、Step 容器)搭建页面骨架,再向内填充业务组件。
  2. 合理使用「自适应列数」与「单元格宽度」控制响应式表现,避免在窄屏下组件被挤压。
  3. 顶层组件垂直间距、页面内边距等整体留白通过 页面全局属性 统一设置,而非逐个组件调整。

下一步​

属性明细​

以下内容面向技术实现与 AI 检索,说明布局树的节点结构、嵌套规则与存储格式。完整的页面级存储示例见 页面全局属性。

布局节点结构(WidgetItem)​

布局是一棵树,树中的每个节点类型为 WidgetItem,节点字段固定如下:

属性名类型含义取值/存储值
idstring(GUID)节点唯一标识随机 GUID,拖拽 / 复制 / 拆分列时重新生成;同一布局内不重复
uidstring(GUID)组件固定标识按组件类型写死的 GUID,一经确定不再修改;同一布局内可能重复
dragTypestring拖拽分类侧边栏拖拽期间非真实类型;落位后归一为 originalType
originalTypestring原始分类组件真实分类:Row / Column / Widget
widgetTypestring部件类型取值见 WidgetType 枚举,如 Row、Column、Tab、MetaView、ChartBar
widgetTypeNamestring部件名称本地化展示名称
metaRecord<string, string> | null组件属性键值对,所有值以字符串存储(数值存 "5",布尔存 "true" / "false")
childrenWidgetItem[]子节点仅容器类组件使用

字段语义要点:

  • id 用于节点定位与上移 / 下移 / 复制 / 移除等操作,拖拽或复制时重新生成(复制通过 regenerateIds 为整棵子树生成新 id)。
  • uid 是组件类型级常量,拖拽多少次都不变,用于判断组件是否已被使用。
  • dragType 是拖拽箱分类:业务组件统一为 Widget,基础容器为 Row,布局列为 Column;从侧边栏拖入画布时数据先以侧边栏形态存在,落位后由 sidebarMetaToWidgetItem 令 dragType = originalType。
  • originalType 是组件真实分类,画布内拖动时以此为准(DragContainer 取 originalType ?? dragType)。

容器嵌套规则​

父节点允许的子节点依据
页面根 LayoutRowCONTAINER_ACCEPT_RULES.root = ["Row"]
RowColumn一行由若干列组成,列数范围 1 ~ ROW_MAX_COLUMNS(6)
Column任意组件(Row 或 Widget 分类)CONTAINER_ACCEPT_RULES.column = ["Row", "Widget"]
Tab / Step / SegmentedColumn每个子列即一个页签 / 步骤 / 分段,列 meta.Title 为标题

嵌套容器存储示例​

以「Tab 容器 + 两个带标题的列」为例,展示嵌套容器在 Layout 中的存储结构:

{
"id": "c1a2b3c4-0001-4a2b-8c3d-1234567890ab",
"uid": "f8c226b6-7b98-45a8-8c71-abeb21e2941a",
"dragType": "Widget",
"originalType": "Widget",
"widgetType": "Tab",
"widgetTypeName": "布局Tab页",
"meta": {
"DefaultActiveTab": "c1a2b3c4-0002-4a2b-8c3d-1234567890ab"
},
"children": [
{
"id": "c1a2b3c4-0002-4a2b-8c3d-1234567890ab",
"uid": "7b9a905e-83d4-452b-83c8-694a3e0935e3",
"dragType": "Column",
"originalType": "Column",
"widgetType": "Column",
"widgetTypeName": "布局列组件",
"meta": {
"Title": "Tab1",
"LayoutType": "vertical",
"Align": "default",
"ItemSpace": "5"
},
"children": []
},
{
"id": "c1a2b3c4-0003-4a2b-8c3d-1234567890ab",
"uid": "7b9a905e-83d4-452b-83c8-694a3e0935e3",
"dragType": "Column",
"originalType": "Column",
"widgetType": "Column",
"widgetTypeName": "布局列组件",
"meta": {
"Title": "Tab2",
"LayoutType": "vertical",
"Align": "default",
"ItemSpace": "5"
},
"children": []
}
]
}

单例组件判定​

布局器通过 widgetType 判定单例组件是否已使用:

  • SingleUseWidgetTypes 是一个 widgetType 字符串集合,当前包含 Placeholder1 ~ Placeholder20(共 20 个占位组件类型)。
  • 布局器编辑时遍历整棵布局树,收集所有 widgetType 命中 SingleUseWidgetTypes 的类型;命中后,左侧面板中对应组件项被置为禁用(不可拖拽)。
  • 此外,侧边栏配置项可设置 LimitOne:当布局树中已存在 uid 与该项 Meta.uid 相同的节点时,该项会被从面板中过滤掉。

各占位组件、部分布局组件的单例约束即由此生效。

相关接口​

接口说明
POST /api/MetaPage/SaveLayout保存页面布局
GET /api/DataSource/GetMetaPageTemplateDataSource获取可加载的页面模板数据源(分类为「页面构建模板」)