布局器
布局器(LayoutEditor)是平台页面的可视化搭建工具,通过拖拽组件、调整列宽与嵌套容器,完成页面布局的配置。
概述
在页面列表中点击页面名称即可进入布局器。布局器由顶部工具栏、左侧组件面板与中间画布三部分组成:
- 顶部工具栏:切换编辑/预览模式、执行页面设置、加载模板、菜单配置、授权与预览、保存布局。
- 左侧组件面板:按分类展示可拖拽的组件,支持关键字搜索。
- 中间画布:展示当前布局,是组件的拖放目标区域。
布局配置最终以组件树(WidgetItem[])的形式保存到页面的 Layout 属性中。了解布局树的完整字段、嵌套规则与完整存储示例,参见 页面全局属性。
组件面板
左侧组件面板按分类折叠展示,每个组件以卡片形式呈现,包含组件名称与说明。面板顶部提供组件搜索输入框,输入关键字后按组件名称过滤。
组件以拖拽的方式添加到画布:按住组件卡片拖动到画布的插入指示线位 置松开即可插入。组件也可以从画布内的一个容器拖动到另一个容器,实现移动与嵌套。
同一布局中只能使用一次的组件(例如占位组件)在添加到布局后,左侧面板中对应项会变为禁用状态。
画布与拖放
画布本身是布局的根容器,顶层组件在画布中垂直排列。拖放时:
- 画布会实时显示插入位置的指示线,松开后组件插入到指示位置。
- 拖拽过程中,光标旁会浮出当前组件的名称标签。
- 嵌套容器(如 Tab 页、Step 页、列)内部同样是可放置区域,支持多层嵌套。
- 空布局时画布显示「从左侧组件库拖拽组件开始搭建布局」的占位提示。
组件操作
选中画布中的组件后,组件右上角会浮出工具栏,提供以下操作(列容器除外):
| 操作 | 说明 |
|---|---|
| 上移 | 在当前容器内将组件上移一位 |
| 下移 | 在当前容器内将组件下移一位 |
| 复制组件 | 复制当前组件(含子组件)并插入到其后 |
| 移除此组件 | 从布局中移除当前组件及其子组件 |
| 属性设置 | 打开右侧属性抽屉,配置该组件属性(双击组件可快速打开) |
列容器(Column)是结构性容器,不提供上移/下移/复制/移除操作,改为提供拆分列与删除列(详见 基础容器)。
属性配置抽屉
组件的属性在右侧抽屉中配置,抽屉标题为组件类型名称,顶部额外提供上移、下移、复制、移除快捷操作。抽屉内容由组件自身的属性面板渲染,各组件可配置项参见各类组件文档。
属性修改会即时同步到布局中,但只有点击顶部保存布局并确认后,才会持久化到服务端。
顶部工具栏
| 操作 | 说明 |
|---|---|
| 编辑模式 / 预览模式 | 开关切换,预览模式下按用户态渲染当前布局 |
| 跳转到平台页面列表 | 返回当前应用的页面列表 |
| 最近修改时间 | 展示页面布局的最近修改时间 |
| 页面设置 | 打开页面全局属性配置抽屉,见 页面全局属性 |
| 菜单配置 | 在新窗口打开菜单设置,将页面挂载到菜单 |
| 授权 | 在新窗口打开应用授权,按页面资源分配访问权限 |
| 加载模板 | 选择页面模板,将其布局导入到当前页面 |
| 预览 | 在新窗口以用户态打开页面,部分依赖数据 ID 的页面无法正常预览 |
| 保存布局 | 确认后保存当前布局到服务端 |
「加载模板」会将所选模板的布局替换为当前页面的布局,操作前请先确认当前布局已保存。
使用建议
- 先使用布局组件(基础容器、Tab 容器、Step 容器)搭建页面骨架,再向内填充业务组件。
- 合理使用「自适应列数」与「单元格宽度」控制响应式表现,避免在窄屏下组件被挤压。
- 顶层组件垂直间距、页面内边距等整体留白通过 页面全局属性 统一设置,而非逐个组件调整。
下一步
属性明细
以下内容面向技术实现与 AI 检索,说明布局树的节点结构、嵌套规则与存储格式。完整的页面级存储示例见 页面全局属性。
布局节点结构(WidgetItem)
布局是一棵树,树中的每个节点类型为 WidgetItem,节点字段固定如下:
| 属性名 | 类型 | 含义 | 取值/存储值 |
|---|---|---|---|
id | string(GUID) | 节点唯一标识 | 随机 GUID,拖拽 / 复制 / 拆分列时重新生成;同一布局内不重复 |
uid | string(GUID) | 组件固定标识 | 按组件类型写死的 GUID,一经确定不再修改;同一布局内可能重复 |
dragType | string | 拖拽分类 | 侧边栏拖拽期间非真实类型;落位后归一为 originalType |
originalType | string | 原始分类 | 组件真实分类:Row / Column / Widget |
widgetType | string | 部件类型 | 取值见 WidgetType 枚举,如 Row、Column、Tab、MetaView、ChartBar |
widgetTypeName | string | 部件名称 | 本地化展示名称 |
meta | Record<string, string> | null | 组件属性 | 键值对,所有值以字符串存储(数值存 "5",布尔存 "true" / "false") |
children | WidgetItem[] | 子节点 | 仅容器类组件使用 |
字段语义要点:
id用于节点定位与上移 / 下移 / 复制 / 移除等操作,拖拽或复制时重新生成(复制通过regenerateIds为整棵子树生成新id)。uid是组件类型级常量,拖拽多少次都不变,用于判断组件是否已被使用。dragType是拖拽箱分类:业务组件统一为Widget,基础容器为Row,布局列为Column;从侧边栏拖入画布时数据先以侧边栏形态存在,落位后由sidebarMetaToWidgetItem令dragType = originalType。originalType是组件真实分类,画布内拖动时以此为准(DragContainer取originalType ?? dragType)。
容器嵌套规则
| 父节点 | 允许的子节点 | 依据 |
|---|---|---|
页面根 Layout | Row | CONTAINER_ACCEPT_RULES.root = ["Row"] |
Row | Column | 一行由若干列组成,列数范围 1 ~ ROW_MAX_COLUMNS(6) |
Column | 任意组件(Row 或 Widget 分类) | CONTAINER_ACCEPT_RULES.column = ["Row", "Widget"] |
Tab / Step / Segmented | Column | 每个子列即一个页签 / 步骤 / 分段,列 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 | 获取可加载的页面模板数据源(分类为「页面构建模板」) |