FormDialogBuilder
使用 API 自定义渲染一个表单,并以对话框的形式打开。
FormDialogBuilder
FormDialogBuilder 是通过代码创建表单对话框的 API 对象,你可以通过 FormDialogBuilder 来组织表单项和布局,并且像开发一个表单一样,基于表单的相关事件编写个性化的逻辑。
| 类型 | 名称 | 参数类型 | 返回类型 | 说明 |
|---|---|---|---|---|
| 方法 | addFieldSet(options) | AddFieldSetOptions | FieldSet | 在表单默认布局中添加一个字段集合, 一个字段集合会渲染成一个带有标题的区域。 |
| 方法 | addSubGrid(options) | AddSubGridOptions | SubGrid | 在表单默认布局中添加一个明细表。 |
| 方法 | addSubTreeGrid(options) | AddSubTreeGridOptions | SubTreeGrid | 在表单默认布局中添加一个子树表。 |
| 方法 | addSubGridView(options) | AddSubGridViewOptions | SubGrid | 在表单默认布局中添加一个子表格视图。 |
| 方法 | addSubTreeGridView(options) | AddSubTreeGridOptions & {refFieldName: string} | SubTreeGrid | 在表单默认布局中添加一个子树表视图。 |
| 方法 | addTabs() | void | Tabs | 添加一个页签布局容器, 可以在页签布局下添加子页签。 |
| 方法 | addStackBlock(options) | AddStackBlockOptions | StackBlock | 添加一个流式布局容器,支持灵活的布局方式。 |
| 方法 | open(options) | OpenOptions | void | 初始化表单对话框 |
addFieldSet(options) 添加字段集合
addFieldSet 用于添加一个基于流式布局实现的字段集合组件。组件由两部分组成:标题区 和 字段内容区。
标题区会在左侧显示标题文字。
字段内容区中,字段按照从左到右、从上到下的顺序依次排列。通过 fieldsPerLine 属性可以设置每一行显示的字段个数。
单据中常见的表头字段的区块就是 FieldSet。
options 参数
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| title | string | 区域标题。为空时不显示标题区 | "" | |
| fieldsPerLine | number | 每行显示字段个数 | 4 |
返回值
语法
// 创建 builder
const formDialogBuilder = qiqi.builder.createDialogFormBuilder();
// 添加一个标题为 "基本信息" 的区域
const baseFieldSet = formDialogBuilder.addFieldSet({
title: '基本信息',
fieldsPerLine: 2
});
// 添加一个标题为"名称"的文本类型字段
baseFieldSet.addField({
id: "name",
title: "名称",
type: 'Text'
});
注意
如果不设置 title 属性或设置为空字符串 "",那么对应渲染的字段集合区域就不会显示标题区域。
addSubGrid(options) 添加明细表
addSubGrid 用于添加一个以表格展示的明细表组件。组件由两部分构成:标题区 和 表格区。
标题区会在左侧显示标题文字。
表格区中,表头按照字段顺序从左到右依次构建。明细表中的每一行数据会作为表格中的一行记录进行展示。表头可以分成多级分组,数字列也可以在表格底部合计,见 SubGrid 明细表。
单据中常见的明细表就是 SubGrid。
options 参数
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| id | string | 明细表字段名,对应表单数据上的 key | ☑️ | - |
| title | string | 明细表标题。为空时不显示标题区 | ☑️ | - |
| visible | boolean | 是否显示该明细表 | true | |
| actions | SubGridActions | 行操作:复制、删除,以及自定义行按钮 | - | |
| enableColumnFilter | boolean | 是否开启列筛选 | false | |
| suppressAutoHeight | boolean | 是否关闭按行数自动撑高 | false | |
| onRowSelectionChanged | (data) => void | 选中行变化时触发 | - | |
| style | React.CSSProperties | 区域样式 | - |
actions 参数
| 名称 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| disable | boolean | 为 true 时不显示行操作 | false |
| includes | string[] | 启用的行操作。内置值为 copy、delete | - |
| excludes | string[] | 禁用的行操作 | - |
| customActions | { key, title, icon?, onClick? }[] | 自定义行按钮 | - |
| resolveActions | (actions: string[]) => string[] | 按当前行返回最终要显示的操作 | - |
返回值
语法
// 创建 builder
const formDialogBuilder = qiqi.builder.createDialogFormBuilder();
// 添加一个标题为"人员明细"的明细表区域
const userGrid = formDialogBuilder.addSubGrid({
id: 'users',
title: "人员明细",
actions: {
includes: ['copy', 'delete']
}
});
// 在明细表中,添加一个标题为"人员"的外键字段,外键指向 User 表,并设置列宽为 200.
const user = userGrid.addField({
id: "user",
title: "人员",
type: "EntityRef",
source: 'User',
width: 200
});
// 在明细表中,添加一个标题为"天数"的数字字段,该字段会显示在"人员"右侧。
userGrid.addField({
id: "days",
title: "天数",
type: "Number",
width: 100
});
注意
明细表的数据 key 是 id,不是 fieldName。title 为空时不显示标题区。
addTabs(options) 添加页签容器
addTabs 用于添加一个页签模式的容器组件。如果我们创建的表单中,信息可以以某种明确的维度进行分组。那么我们可以使用页签布局来显示的表达这个分组,提高用户的体验。
单纯添加页签容器是无法工作的,页签容器(Tabs)需要页签(Tab)一起配合,才能完成一个完整的页签定义。
返回值
语法
// 创建 builder
const formDialogBuilder = qiqi.builder.createDialogFormBuilder();
// 添加一个页签分组
const tabs = formDialogBuilder.addTabs();
// 在页签分组下添加一个标题为"销售属性"的页签
const salesTab = tabs.addFieldSetTab({
title: "销售属性"
});
// 在"销售属性"页签中,添加"售价"字段
salesTab.addField({
id: "price",
title: "售价",
type: "Amount"
});
// 在 "销售属性" 右侧,添加一个标题为"库存属性"的页签,这个页签里显示一个明细表
const inventoryGrid = tabs.addSubGridTab({
title: "库存属性",
id: "inventories"
});
注意
- 如果页签容器下没有通过
addFieldSetTab、addSubGridTab等方法添加页签,那么最终这个页签容器不会进行渲染。 - 页签的
title属性必填。明细表页签的数据 key 是id。
open(options) 初始化表单对话框
在完成表单数据和布局定义后,可以通过 open 打开表单对话框。这会同步创建一个全新的表单实例,该表单拥有独立的运行空间、独立的生命周期及相关表单上下文。如果要在这个表单上使用 Client API,则需要通过 options 来传递相关的表单事件监听处理函数。
options 参数
| 名称 | 类型 | 说明 |
|---|---|---|
| title | String | 对话框标题 |
| size | String | 对话框大小,可选值:small、middle、large、largest, 默认值:largest |
| value | Object | 表单初始值 |
| formOnLoad | Function | 表单初始化后触发,详细介绍 |
| fieldOnChanged | Function | 表单中任一字段值发生改变时被触发,详细介绍 |
| subGridOnChanged | Function | 明细表数据发生变化时,对明细表的 添加、复制、删除 会触发,详细介绍 |
| subGridRowOnCreated | Function | 在明细行创建之后触发,详细介绍 |
| subGridRowOnInit | Function | 在明细行初始化之后触发,详细介绍 |
| dialogOnCancel | Function | 在用户点击 对话框右上角 或 底部取消按钮 时触发,详细介绍 |
| dialogOnConfirm | Function | 在用户点击 底部确认按钮 时触发,详细介绍 |
| extraButtons | FormDialogButton[] | 额外的按钮,添加在取消和确定中间 |
| suppressCancelButton | Boolean | 隐藏取消按钮,默认为false |
| suppressConfirmButton | Boolean | 隐藏确认按钮,默认为false |
FormDialogButton 类型
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| id | string | 按钮的唯一标识符 | ☑️ | - |
| text | string | 按钮显示的文本 | - | |
| title | string | 按钮的提示信息(tooltip) | - | |
| type | string | 按钮类型,可选值:flat、raised、outline、icon | - | |
| icon | string | 按钮图标 | - | |
| iconSize | number | 图标大小 | - | |
| onClick | Function | 按钮点击事件的处理函数,接收 FormExecutionCtx 作为参数 | ☑️ | - |
FieldSet 字段集合
FieldSet 是一个基于流式布局实现的字段集合,集合中的字段按照从左到右、从上到下的顺序依次排列。你可以通过 addField 给相应集合中添加字段。
| 类型 | 名称 | 参数类型 | 返回类型/类型 | 说明 |
|---|---|---|---|---|
| 方法 | addField(options) | AddFieldOptions | Field | 在字段集合中添加一个字段 |
addField(options) 添加字段
在字段集合 FieldSet 中添加一个字段。添加的多个字段会按照 addField 的调用顺序决定 FieldSet 中的展示顺序。
options 参数
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| id | string | 字段名称,对应数据 key | ☑️ | - |
| title | string | 字段标题 | ☑️ | - |
| type | FieldType | 字段类型 | ☑️ | - |
| readonly | boolean | (row) => boolean | 是否只读。明细列可以传函数,按当前行动态判断 | false | |
| hidden | boolean | 是否隐藏 | false | |
| required | boolean | 是否必填 | false | |
| labelDescription | string | 标题旁的说明 | - | |
| cascade | { valueExpr: string } | 只按表达式展示值,不创建真实字段,也不能作为提交字段 | - |
各类型特定参数说明
- Text、MultiText、Link、Mobile、Email
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| formatType | string | 文本格式化类型 | - | |
| initOptions | () => Promise<\{ options, labelKey?, valueKey?, onSearch? \}> | 把文本做成可搜索下拉。labelKey 默认 title,valueKey 默认 id | - |
- Number、Amount
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| decimal | number | 小数位精度 | 2 |
- Percent
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| decimal | number | 小数位精度 | 2 |
- RadioGroup
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| options | { text: string, value: any }[] | 单选项 | ☑️ | - |
- Select
选项直接写在 addField 上,不需要再调用 addSelectOption。
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| options | { text: string, value: any }[] | 下拉选项 | - | |
| placeholder | string | 占位提示 | - | |
| allowClear | boolean | 是否允许清空 | - |
- RichText
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| fieldNames | { text: string, json: string, html: string } | 纯文本、JSON、HTML 三个值分别写入的字段名 | ☑️ | - |
- EntityRef、EnumRef、MultiEntityRef、MultiEnumRef
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| source | string | 引用的档案或枚举名 | ☑️ | - |
- ForeignKeyLink
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| entityName | string | 链接指向的对象名 | - | |
| drillingInfo | { valueField?, objectTypeField? } | 穿透时取值字段和对象类型字段 | - | |
| originDef | object | 原始字段定义 | ☑️ | - |
- Color
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| model | any | 颜色选择模式 | - |
- Attachment
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| disableUpload | boolean | 是否禁用上传 | false | |
| disableDelete | boolean | 是否禁用删除 | false | |
| disableEdit | boolean | 是否禁用编辑 | false | |
| enableIncremental | boolean | 是否启用增量处理 | false | |
| compact | boolean | 是否紧凑模式 | false | |
| resourceId | string | 资源ID | - | |
| attachmentProps | object | 附件组件透传的额外Props | - |
- Image
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| maxUploadCount | number | 最大上传图片数量 | - | |
| maxUploadSize | number | 最大上传图片大小(单位:MB) | - | |
| disabledSetDefault | boolean | 是否禁用设置默认展示图片功能 | false | |
| hideDefaultTag | boolean | 是否隐藏默认图片标签 | false |
RichText 富文本字段
富文本字段在界面上渲染为一个富文本编辑器,支持段落、标题、加粗/斜体/下划线/删除线、文字颜色、链接、图片等内容。
一个富文本字段由 1 个富文本字段 和 3 个承载数据的字段 共同组成:
| 字段 | 值类型 | 说明 |
|---|---|---|
富文本字段(id) | - | 用于渲染编辑器,本身不保存内容。 |
| text 字段 | String | 富文本对应的纯文本,可用于列表展示、搜索、校验是否为空。 |
| json 字段 | Object | 富文本内容(Tiptap JSON),是富文本内容的唯一事实来源。 |
| html 字段 | Object | 由 json 派生的 HTML 存储值,结构为 { html, imageKeys, hasError, hasUploading }。 |
通过 fieldNames 告诉富文本字段这 3 个字段的字段名:
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| fieldNames | object | 富文本数据字段映射 | ☑️ | - |
| fieldNames.text | string | 纯文本字段名 | ☑️ | - |
| fieldNames.json | string | 富文本 JSON 字段名 | ☑️ | - |
| fieldNames.html | string | 富文本 HTML 字段名 | ☑️ | - |
注意
fieldNames中的 3 个字段不会自动创建,必须在同一个表单中通过addField显式添加,并设置hidden: true隐藏:text 字段类型为Text,json 和 html 字段类型为JsonObject。缺少这 3 个字段时,编辑器无法正常工作,field.richText也会返回undefined。fieldNames中填写的是字段名本身(即对应字段的id),不需要带任何路径前缀。- 富文本字段目前只能添加在字段集合
FieldSet中(包括页签、流式布局中的字段集合),不支持作为明细表、子树表的列。 - 富文本的内容请通过 field.richText 读写,不要直接给 json / html 字段赋值,否则 3 个字段的内容可能不一致。
// 创建 builder
const formDialogBuilder = qiqi.builder.createDialogFormBuilder();
const baseFieldSet = formDialogBuilder.addFieldSet({
title: '工作汇报',
fieldsPerLine: 1
});
// 1. 添加富文本字段,用于渲染编辑器
baseFieldSet.addField({
id: 'content',
title: '汇报内容',
type: 'RichText',
required: true,
fieldNames: {
text: 'contentTextStr',
json: 'contentTextJson',
html: 'contentTextHtml',
},
});
// 2. 添加富文本的 3 个数据字段,并隐藏
baseFieldSet.addField({ id: 'contentTextStr', title: '汇报内容', type: 'Text', hidden: true });
baseFieldSet.addField({ id: 'contentTextJson', title: '汇报内容', type: 'JsonObject', hidden: true });
baseFieldSet.addField({ id: 'contentTextHtml', title: '汇报内容', type: 'JsonObject', hidden: true });
formDialogBuilder.open({
title: '填写工作汇报',
size: 'large',
// 表单加载后写入初始内容
formOnLoad: (ctx) => {
const richText = ctx.getFormContext().form.getField('contentTextStr').richText;
richText.set([
{ type: 'heading', level: 2, content: '本周工作' },
{ type: 'paragraph', content: '1. ' },
{ type: 'heading', level: 2, content: '下周计划' },
{ type: 'paragraph', content: '1. ' },
]);
},
// 提交时读取内容
dialogOnConfirm: async (ctx) => {
const form = ctx.getFormContext().form;
const snapshot = form.getField('contentTextStr').richText.get();
if (!snapshot.text.trim()) {
qiqi.ui.message.showError('请填写汇报内容');
ctx.getEventArgs().cancel();
return;
}
// snapshot.document 为富文本 JSON,snapshot.html.html 为 HTML 字符串
console.log(snapshot.text, snapshot.document, snapshot.html);
},
});
更多读写方式请参考 field.richText 富文本 API。
语法
// 创建 builder
const formDialogBuilder = qiqi.builder.createDialogFormBuilder();
// 添加一个标题为 "基本信息" 的区域
const baseFieldSet = formDialogBuilder.addFieldSet({
title: '基本信息',
fieldsPerLine: 2
});
// 添加一个标题为"名称"的文本类型字段
baseFieldSet.addField({
id: "name",
title: "名称",
type: 'Text'
});
// 添加一个标题为"业务日期"的日期类型字段
baseFieldSet.addField({
id: "businessDate",
title: "业务日期",
type: "Date"
});
// 添加一个标题为"业务员"的外键类型字段,外键指向人员
const userField = baseFieldSet.addField({
id: "businessDate",
title: "业务员",
type: "EntityRef",
source: "User"
});
addSubTreeGrid(options) 添加子树表
addSubTreeGrid 用于在表单默认布局中添加一个子树表,支持树形数据的展示和操作。
options 参数
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| id | string | 子树表字段名 | ☑️ | - |
| title | string | 子树表显示名称 | ☑️ | - |
| parentIdFieldName | string | 父节点ID字段名 | ☑️ | - |
| idFieldName | string | 节点ID字段名 | ☑️ | - |
| hasChildrenFieldName | string | 是否包含子节点字段名 | ☑️ | - |
| visible | boolean | 是否可见 | true | |
| actions | SubGridActions | 行操作,含义与明细表相同 | - | |
| enableColumnFilter | boolean | 是否开启列筛选 | false | |
| suppressAutoHeight | boolean | 是否关闭按行数自动撑高 | false | |
| onRowSelectionChanged | (data) => void | 选中行变化时触发 | - | |
| style | React.CSSProperties | 样式配置 | - |
返回值
语法
// 创建 builder
const formDialogBuilder = qiqi.builder.createDialogFormBuilder();
// 添加子树表
const treeGrid = formDialogBuilder.addSubTreeGrid({
id: 'orgTree',
title: '组织架构',
parentIdFieldName: 'parentId',
idFieldName: 'id',
hasChildrenFieldName: 'hasChildren'
});
// 添加字段到子树表
treeGrid.addField({
id: 'name',
title: '名称',
type: 'Text',
width: 200
});
addSubGridView(options) 添加子表格视图
addSubGridView 用于在表单默认布局中添加一个子表格视图,通常用于显示关联的实体数据。
options 参数
AddSubGridViewOptions 继承自 AddSubGridOptions,并增加了以下额外属性:
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| refFieldName | string | 关联字段名 | ☑️ | - |
返回值
语法
// 创建 builder
const formDialogBuilder = qiqi.builder.createDialogFormBuilder();
// 添加子表格视图
const subGridView = formDialogBuilder.addSubGridView({
id: 'orderItems',
title: '订单明细',
refFieldName: 'orderId'
});
// 添加字段到子表格视图
subGridView.addField({
id: 'productName',
title: '产品名称',
type: 'Text',
width: 160
});
addSubTreeGridView(options) 添加子树表视图
addSubTreeGridView 用于在表单默认布局中添加一个子树表视图,通常用于显示关联的树形实体数据。
options 参数
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| id | string | 子树表字段名 | ☑️ | - |
| title | string | 子树表显示名称 | ☑️ | - |
| refFieldName | string | 关联字段名 | ☑️ | - |
| parentIdFieldName | string | 父节点ID字段名 | ☑️ | - |
| idFieldName | string | 节点ID字段名 | ☑️ | - |
| hasChildrenFieldName | string | 是否包含子节点字段名 | ☑️ | - |
| visible | boolean | 是否可见 | true | |
| actions | SubGridActions | 行操作,含义与明细表相同 | - | |
| enableColumnFilter | boolean | 是否开启列筛选 | false | |
| suppressAutoHeight | boolean | 是否关闭按行数自动撑高 | false | |
| onRowSelectionChanged | (data) => void | 选中行变化时触发 | - | |
| style | React.CSSProperties | 样式配置 | - |
返回值
语法
// 创建 builder
const formDialogBuilder = qiqi.builder.createDialogFormBuilder();
// 添加子树表视图
const treeGridView = formDialogBuilder.addSubTreeGridView({
id: 'categoryTree',
title: '产品分类',
refFieldName: 'productId',
parentIdFieldName: 'parentId',
idFieldName: 'id',
hasChildrenFieldName: 'hasChildren'
});
// 在子树表视图中添加字段
treeGridView.addField({
id: 'categoryName',
title: '分类名称',
type: 'Text',
width: 150
});
addStackBlock(options) 添加流式布局容器
addStackBlock 用于在表单默认布局中添加一个流式布局容器,支持水平和垂直方向的灵活布局。
options 参数
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| direction | 'horizontal' | 'vertical' | 布局方向,水平或垂直 | 'vertical' | |
| spacing | number | 子元素之间的间距 | - | |
| style | React.CSSProperties | 自定义样式 | - |
返回值
语法
// 创建 builder
const formDialogBuilder = qiqi.builder.createDialogFormBuilder();
// 添加水平流式布局
const horizontalStack = formDialogBuilder.addStackBlock({
direction: 'horizontal',
spacing: 16
});
// 在流式布局中添加字段集
const fieldSet1 = horizontalStack.addFieldSet({
title: '基本信息',
fieldsPerLine: 2
});
const fieldSet2 = horizontalStack.addFieldSet({
title: '扩展信息',
fieldsPerLine: 2
});
// 添加字段到字段集
fieldSet1.addField({
id: 'name',
title: '名称',
type: 'Text'
});
fieldSet2.addField({
id: 'description',
title: '描述',
type: 'TextArea'
});
Field 字段
Field 是单个字段的API对象。你可以通过 Field 给字段设置相关选项及参数。
| 类型 | 名称 | 返回类型/类型 | 说明 |
|---|---|---|---|
| 属性 | id | string(read-only) | 字段名,在调用 addField 时指定。在获取表单数据时, 该字段的值会以 id 作为父对象(表单或明细表行)的 key。 |
| 属性 | type | string(read-only) | 字段类型,在调用 addField 时指定。 不同字段类型的交互组件不同。具体可以参考 FieldType 类型集合 |
FieldType 字段类型
| 类型 | 值类型 | 说明 |
|---|---|---|
| Text | String | 单行文本。 |
| MultiText | String | 多行文本。 |
| Link | String | 链接。 |
| Mobile | String | 手机号。 |
| String | 邮箱。 | |
| Number | Number | 数字。 |
| Amount | Number | 金额。 |
| Percent | Number | 百分比。 |
| Year | Date | 年。 |
| YearMonth | Date | 年-月。 |
| DateMonth | Date | 月。 |
| Date | Date | 年-月-日。 |
| DateTime | Date | 年-月-日 时:分。 |
| DateTimeSecond | Date | 年-月-日 时:分:秒。 |
| Time | Date | 时:分:秒。 |
| Checkbox | Boolean | 勾选框。 |
| RadioGroup | any | 单选按钮组,选项由 options 提供。 |
| Select | any | 下拉选择,选项由 options 提供。 |
| EntityRef | Object | 档案、单据参照。 |
| EnumRef | Object | 枚举参照。 |
| MultiEntityRef | Array | 多选档案、单据参照。 |
| MultiEnumRef | Array | 多选枚举参照。 |
| ForeignKeyLink | Object | 外键链接,可穿透到关联数据。 |
| Image | Object | 图片上传。 |
| Attachment | Object | 附件上传。 |
| RichText | Object | 富文本,内容保存在 fieldNames 指定的 text / json / html 字段中,详细介绍。 |
| JsonObject | Object | JSON 数据字段,只用来承载数据,需配合 hidden: true 使用,例如富文本的 json / html 数据字段。 |
| Color | Object | 颜色选择。 |
| Geolocation | Object | 地理定位。 |
Tabs 页签容器
Tabs 是页签容器的API对象。你可以通过 Tabs 添加页签Tab。Tabs的页签展示顺序保持和 addFieldSetTab 、addSubGridTab 的调用顺序一致。
| 类型 | 名称 | 参数类型 | 返回类型/类型 | 说明 |
|---|---|---|---|---|
| 方法 | addFieldSetTab(options) | AddFieldSetTabOptions | FieldSet | 添加一个字段集合的子页签 |
| 方法 | addSubGridTab(options) | AddSubGridOptions | SubGrid | 添加一个明细表的子页签 |
| 方法 | addSubGridViewTab(options) | AddSubGridViewOptions | SubGrid | 添加一个子表格视图页签 |
| 方法 | addSubTreeGridTab(options) | AddSubTreeGridOptions | SubTreeGrid | 添加一个子树表的子页签 |
| 方法 | addSubTreeGridViewTab(options) | AddSubTreeGridOptions & {refFieldName: string} | SubTreeGrid | 添加一个子树表视图的子页签 |
注意
如果页签容器下没有通过 addFieldSetTab 或 addSubGridTab 来添加页签,那么最终这个页签容器不会进行渲染。
addFieldSetTab(options) 添加字段集合页签
addFieldSetTab 用于在页签容器中添加一个字段集合页签。
options 参数
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| title | string | 字段标题 | ☑️ | "" |
| fieldsPerLine | number | 每行显示字段个数 | 4 |
注意
addFieldSetTab 中,title 属性必填。
返回值
语法
// 创建 builder
const formDialogBuilder = qiqi.builder.createDialogFormBuilder();
// 添加一个页签分组
const tabs = formDialogBuilder.addTabs();
// 在页签分组下添加一个标题为"销售属性"的页签
const salesTab = tabs.addFieldSetTab({
title: "销售属性"
});
// 在"销售属性"页签中,添加"售价"字段
salesTab.addField({
id: "price",
title: "售价",
type: "Amount"
});
addSubGridTab(options) 添加明细表页签
addSubGridTab 用于在页签容器中添加一个明细表页签。
options 参数
参数与 AddSubGridOptions 相同。id、title 必填。
注意
addSubGridTab 中,title 和 id 必填。数据 key 是 id。
返回值
语法
// 创建 builder
const formDialogBuilder = qiqi.builder.createDialogFormBuilder();
// 添加一个页签分组
const tabs = formDialogBuilder.addTabs();
// 在 "销售属性" 右侧,添加一个标题为"库存属性"的页签,这个页签里显示一个明细表
const inventoryGrid = tabs.addSubGridTab({
title: "库存属性",
id: "inventories"
});
// 库存属性明细表中,添加一个标题为"存货"的列
inventoryGrid.addField({
id: 'product',
title: '存货',
type: 'EntityRef',
source: 'Product',
width: 160
})
addSubGridViewTab(options) 添加子表格视图页签
addSubGridViewTab 用于在页签中添加一个子表格视图。参数与 AddSubGridViewOptions 相同:在明细表参数之外,必须再传 refFieldName,表格展示的是该字段上的数据。
语法
const tabs = formDialogBuilder.addTabs();
const orderTab = tabs.addSubGridViewTab({
id: 'orderItems',
title: '订单明细',
refFieldName: 'orderId'
});
orderTab.addField({
id: 'productName',
title: '产品名称',
type: 'Text',
width: 160
});
addSubTreeGridTab(options) 添加子树表页签
addSubTreeGridTab 用于在页签容器中添加一个子树表页签。
options 参数
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| id | string | 子树表字段名 | ☑️ | - |
| title | string | 子树表显示名称 | ☑️ | - |
| parentIdFieldName | string | 父节点ID字段名 | ☑️ | - |
| idFieldName | string | 节点ID字段名 | ☑️ | - |
| hasChildrenFieldName | string | 是否包含子节点字段名 | ☑️ | - |
| visible | boolean | 是否可见 | true | |
| actions | SubGridActions | 行操作,含义与明细表相同 | - | |
| enableColumnFilter | boolean | 是否开启列筛选 | false | |
| suppressAutoHeight | boolean | 是否关闭按行数自动撑高 | false | |
| onRowSelectionChanged | (data) => void | 选中行变化时触发 | - | |
| style | React.CSSProperties | 样式配置 | - |
注意
addSubTreeGridTab 中,title 属性必填。
返回值
语法
// 创建 builder
const formDialogBuilder = qiqi.builder.createDialogFormBuilder();
// 添加一个页签分组
const tabs = formDialogBuilder.addTabs();
// 添加一个组织架构的子树表页签
const orgTreeTab = tabs.addSubTreeGridTab({
title: "组织架构",
id: "orgTree",
parentIdFieldName: "parentId",
idFieldName: "id",
hasChildrenFieldName: "hasChildren"
});
// 在子树表中添加字段
orgTreeTab.addField({
id: 'name',
title: '名称',
type: 'Text',
width: 200
});
addSubTreeGridViewTab(options) 添加子树表视图页签
addSubTreeGridViewTab 用于在页签容器中添加一个子树表视图页签,通常用于显示关联的实体数据。
options 参数
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| id | string | 子树表字段名 | ☑️ | - |
| title | string | 子树表显示名称 | ☑️ | - |
| refFieldName | string | 关联字段名 | ☑️ | - |
| parentIdFieldName | string | 父节点ID字段名 | ☑️ | - |
| idFieldName | string | 节点ID字段名 | ☑️ | - |
| hasChildrenFieldName | string | 是否包含子节点字段名 | ☑️ | - |
| visible | boolean | 是否可见 | true | |
| actions | SubGridActions | 行操作,含义与明细表相同 | - | |
| enableColumnFilter | boolean | 是否开启列筛选 | false | |
| suppressAutoHeight | boolean | 是否关闭按行数自动撑高 | false | |
| onRowSelectionChanged | (data) => void | 选中行变化时触发 | - | |
| style | React.CSSProperties | 样式配置 | - |
注意
addSubTreeGridViewTab 中,title 属性必填。
返回值
语法
// 创建 builder
const formDialogBuilder = qiqi.builder.createDialogFormBuilder();
// 添加一个页签分组
const tabs = formDialogBuilder.addTabs();
// 添加一个关联实体的子树表视图页签
const categoryTreeTab = tabs.addSubTreeGridViewTab({
title: "产品分类",
id: "categoryTree",
refFieldName: "productId",
parentIdFieldName: "parentId",
idFieldName: "id",
hasChildrenFieldName: "hasChildren"
});
// 在子树表视图中添加字段
categoryTreeTab.addField({
id: 'categoryName',
title: '分类名称',
type: 'Text',
width: 150
});
StackBlock 流式布局
StackBlock 是流式布局容器的API对象,提供灵活的布局方式。你可以通过 StackBlock 添加字段集、明细表、页签等组件,支持水平或垂直方向的布局。
| 类型 | 名称 | 参数类型 | 返回类型/类型 | 说明 |
|---|---|---|---|---|
| 方法 | addFieldSet(options) | AddFieldSetOptions | FieldSet | 添加一个字段集合 |
| 方法 | addSubGrid(options) | AddSubGridOptions | SubGrid | 添加一个明细表 |
| 方法 | addSubTreeGrid(options) | AddSubTreeGridOptions | SubTreeGrid | 添加一个子树表 |
| 方法 | addSubGridView(options) | AddSubGridViewOptions | SubGrid | 添加一个子表格视图 |
| 方法 | addSubTreeGridView(options) | AddSubTreeGridOptions & {refFieldName: string} | SubTreeGrid | 添加一个子树表视图 |
| 方法 | addTabs(options) | AddTabsOptions | Tabs | 添加一个页签容器 |
| 方法 | addStackItem(options) | {style?: React.CSSProperties} | StackBlock | 添加一个子流式布局区域 |
| 方法 | addStackBlock(options) | AddStackBlockOptions | StackBlock | 添加一个嵌套的流式布局区域 |
AddStackBlockOptions 流式布局配置选项
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| direction | 'horizontal' | 'vertical' | 布局方向,水平或垂直 | 'vertical' | |
| spacing | number | 子元素之间的间距 | - | |
| style | React.CSSProperties | 自定义样式 | - |
语法
// 创建 builder
const formDialogBuilder = qiqi.builder.createDialogFormBuilder();
// 添加一个水平流式布局
const stackBlock = formDialogBuilder.addStackBlock({
direction: 'horizontal',
spacing: 16
});
// 在流式布局中添加字段集
const fieldSet = stackBlock.addFieldSet({
title: '基本信息',
fieldsPerLine: 2
});
// 添加字段到字段集
fieldSet.addField({
id: 'name',
title: '名称',
type: 'Text'
});
// 添加另一个流式布局作为子项
const subStack = stackBlock.addStackItem({
style: { padding: 16 }
});
SubTreeGrid 子树表
SubTreeGrid 是子树表的API对象,支持树形数据的展示和操作。子树表以树形表格形式展示,支持树形数据的展开和折叠。
| 类型 | 名称 | 参数类型 | 返回类型/类型 | 说明 |
|---|---|---|---|---|
| 方法 | addParentLayout(options) | AddParentLayoutOptions | ColumnLayout | 添加列分组,用于多级表头 |
| 方法 | addField(options) | AddSubgridFieldOptions | Field | 在子树表中添加一个字段 |
| 方法 | removeParentLayout(layoutId) | string | boolean | 删除列分组,并删除其下的子分组和字段 |
| 方法 | removeField(fieldId) | string | boolean | 删除末级字段 |
| 方法 | changeRowSelection(mode) | 'single' | 'multiple' | 'none' | void | 修改行选择模式 |
| 方法 | getToolBar() | void | IDetailToolBar | 获取工具栏对象 |
| 方法 | rebuildColumns() | void | void | 改列后刷新列头,并同步行数据 |
列的添加、删除、多级表头和底部合计与 SubGrid 明细表 使用同一套接口。树形明细开启合计后,只按末级行计算:有子节点的父行不计入;hasChildren 为 true 时,即使子节点还没加载,也不当作末级。展开或折叠不改变合计结果,合计按全部末级数据计算。
AddSubTreeGridOptions 子树表配置选项
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| id | string | 子树表字段名 | ☑️ | - |
| title | string | 子树表显示名称 | ☑️ | - |
| parentIdFieldName | string | 父节点ID字段名 | ☑️ | - |
| idFieldName | string | 节点ID字段名 | ☑️ | - |
| hasChildrenFieldName | string | 是否包含子节点字段名 | ☑️ | - |
| visible | boolean | 是否可见 | true | |
| actions | SubGridActions | 行操作,含义与明细表相同 | - | |
| enableColumnFilter | boolean | 是否开启列筛选 | false | |
| suppressAutoHeight | boolean | 是否关闭按行数自动撑高 | false | |
| onRowSelectionChanged | (data) => void | 选中行变化时触发 | - | |
| style | React.CSSProperties | 样式配置 | - |
语法
// 创建 builder
const formDialogBuilder = qiqi.builder.createDialogFormBuilder();
// 添加子树表
const treeGrid = formDialogBuilder.addSubTreeGrid({
id: 'orgTree',
title: '组织架构',
parentIdFieldName: 'parentId',
idFieldName: 'id',
hasChildrenFieldName: 'hasChildren'
});
// 添加字段到子树表
treeGrid.addField({
id: 'name',
title: '名称',
type: 'Text',
width: 200
});
// 获取工具栏并添加按钮
const toolBar = treeGrid.getToolBar();
toolBar.addButton({
id: 'expandAll',
text: '展开全部',
onClick: () => {
console.log('展开全部');
}
});
IDetailToolBar 明细工具栏
IDetailToolBar 是明细表和子树表右上角工具栏。按钮配置与 FormDialogButton 相同:id、text、title、type、icon、iconSize、onClick。工具栏按钮没有 style、className。
| 类型 | 名称 | 参数类型 | 返回类型 | 说明 |
|---|---|---|---|---|
| 方法 | addButton(...buttons) | FormDialogButton | void | 添加一个或多个按钮。id 已存在时不会重复添加 |
| 方法 | removeButton(id) | string | void | 按按钮 id 删除 |
| 方法 | getButtons() | void | FormDialogButton[] | 返回当前按钮 |
| 方法 | addSearchInput(options) | SearchInputOptions | void | 添加搜索框 |
| 方法 | addSearchArea(options) | SearchAreaOptions | void | 添加搜索区域 |
SearchInputOptions
| 名称 | 类型 | 说明 | 必填 |
|---|---|---|---|
| id | string | 搜索框标识 | ☑️ |
| placeholder | string | 占位提示 | |
| onChange | (value: string) => void | 输入变化时触发 | |
| style | React.CSSProperties | 样式 |
SearchAreaOptions
| 名称 | 类型 | 说明 | 必填 |
|---|---|---|---|
| id | string | 搜索区域标识 | ☑️ |
| style | React.CSSProperties | 样式 |
语法
const toolBar = subGrid.getToolBar();
toolBar.addButton({
id: 'customAction',
text: '自定义操作',
icon: 'edit',
onClick: (formExecutionContext) => {
const form = formExecutionContext.getFormContext().form;
console.log(form.value);
}
});
toolBar.addSearchInput({
id: 'keyword',
placeholder: '搜索',
onChange: (value) => {
console.log(value);
}
});
toolBar.removeButton('customAction');
SubGrid 明细表
SubGrid 是明细表的 API 对象。你可以通过 SubGrid 给明细表定义列、多级表头和底部合计。SubTreeGrid 使用同一套列接口。
| 类型 | 名称 | 参数类型 | 返回类型/类型 | 说明 |
|---|---|---|---|---|
| 方法 | addParentLayout(options) | AddParentLayoutOptions | ColumnLayout | 添加列分组,只负责表头展示,不绑定数据 |
| 方法 | addField(options) | AddSubgridFieldOptions | Field | 添加末级字段列 |
| 方法 | removeParentLayout(layoutId) | string | boolean | 删除列分组,并删除其下的子分组和字段 |
| 方法 | removeField(fieldId) | string | boolean | 删除末级字段 |
| 方法 | changeRowSelection(mode) | 'single' \| 'multiple' \| 'none' | void | 修改行选择模式 |
| 方法 | getToolBar() | void | IDetailToolBar | 获取工具栏对象 |
| 方法 | rebuildColumns() | void | void | 改列后刷新列头,并同步子表 schema 与已有行数据 |
注意
如果 SubGrid 没有通过 addField 添加过字段,那么最终该明细表不会渲染,并且在表单中,也不会创建该明细表的数据模型对象。
表单已经打开之后再增删列,必须调用 rebuildColumns()。只在建表阶段把列搭好、打开后不再改列,则不必调用。
addField(options) 添加字段
在明细表中添加一个末级字段列。同级的 addField 和 addParentLayout 按调用顺序从左到右排列。
options 参数
明细列在 公共字段属性 之外,还支持下面这些参数。readonly 在明细列上可以传 (row) => boolean。
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| width | number | 列宽 | ☑️ | - |
| parentId | string | 归属列分组 id。不设则为顶层列 | - | |
| suppressFilter | boolean | 禁用该列筛选 | false | |
| enableBatchEdit | boolean | { checkAlso, lockedBy, rowFilter } | 表头批量勾选编辑。对象形式可配置连带勾选、锁定和参与批量赋值的行 | false | |
| enableSummary | boolean | 是否在表格底部显示该列合计 | false | |
| summaryType | 'Sum' \| 'Max' \| 'Min' \| 'Avg' \| 'Count' | 合计方式。开启合计后未指定时按 Sum | Sum |
enableBatchEdit 传对象时:
| 名称 | 类型 | 说明 |
|---|---|---|
| checkAlso | string[] | 勾选本列时连带勾选的字段 |
| lockedBy | string[] | 这些字段为 true 时,本列不可取消勾选 |
| rowFilter | (row) => boolean | 参与全选和批量赋值的行。未设置时包含全部行 |
返回值
语法
const formDialogBuilder = qiqi.builder.createDialogFormBuilder();
const userGrid = formDialogBuilder.addSubGrid({
id: 'users',
title: '人员明细'
});
userGrid.addField({
id: 'user',
title: '人员',
type: 'EntityRef',
source: 'User',
width: 200
});
userGrid.addField({
id: 'days',
title: '天数',
type: 'Number',
width: 100,
decimal: 2,
enableSummary: true,
summaryType: 'Sum'
});
addParentLayout(options) 多级表头
addParentLayout 添加的是表头分组。分组只负责展示,不产生数据列,也不参与校验和提交。只有末级 addField 才是可录入列。
分组可以多层嵌套:parentId 指向已添加的上级分组。不传 parentId 时,分组位于顶层。分组 id 在同一张表内不能与字段 id 重复。
options 参数
| 名称 | 类型 | 说明 | 必填 | 默认值 |
|---|---|---|---|---|
| id | string | 分组唯一标识 | ☑️ | - |
| title | string | 表头显示名称 | ☑️ | - |
| parentId | string | 上级分组 id。不设则为顶层分组 | - |
语法
const items = formDialogBuilder.addSubGrid({
id: 'items',
title: '明细'
});
items.addField({ id: 'code', title: '编码', type: 'Text', width: 120 });
items.addParentLayout({ id: 'amount', title: '金额' });
items.addParentLayout({ id: 'tax', title: '税额', parentId: 'amount' });
items.addField({
id: 'amountValue',
title: '金额',
type: 'Number',
width: 100,
decimal: 2,
parentId: 'amount',
enableSummary: true,
summaryType: 'Sum'
});
items.addField({
id: 'taxAmount',
title: '税额',
type: 'Number',
width: 100,
decimal: 2,
parentId: 'tax',
enableSummary: true,
summaryType: 'Sum'
});
items.addField({ id: 'remark', title: '备注', type: 'Text', width: 200 });
用户看到的表头结构是:
编码
金额(分组)
├─ 税额(分组)
│ └─ 税额
└─ 金额
备注
同级顺序等于 addField / addParentLayout 的调用顺序。上面示例的顶层顺序是「编码、金额分组、备注」。「金额」分组下先是「税额」分组,再是金额列;「税额」分组下只有税额列。分组本身不产生数据,只有最末级的编码、税额、金额、备注才写入行数据。
removeField / removeParentLayout 删除列
grid.removeField('amt_2026_01');
grid.removeParentLayout('year_2026');
grid.rebuildColumns();
removeField(fieldId)删除一个末级字段。removeParentLayout(layoutId)删除分组,并连带删除其下的子分组和字段。- 表单打开后再删除,必须接着调用
rebuildColumns()。删除后该列从表头消失,已有行上对应的值也会清掉。
rebuildColumns() 刷新列
表单打开后,用建表时拿到的明细表对象调用 addField、addParentLayout、removeField、removeParentLayout,最后必须调用 rebuildColumns()。运行时也可以通过 ctx.getFormContext().form.getSubGrid(path).rebuildColumns() 刷新。
rebuildColumns 会:
- 按当前字段同步子表 schema:新增列补上类型,删除列清掉行上的旧 key
- 刷新列头
- 让已有行数据与新列对齐
动态列的 id 必须和行数据的 key 一致。按月份展开金额时,一行上是多个金额格子,而不是一个月一行。
function rebuildAmountColumns(grid, months) {
grid.removeParentLayout('year_2026');
grid.addParentLayout({ id: 'year_2026', title: '2026' });
months.forEach((month) => {
const monthId = 'm_' + month;
const fieldId = 'amt_2026_' + String(month).padStart(2, '0');
grid.addParentLayout({ id: monthId, title: String(month), parentId: 'year_2026' });
grid.addField({
id: fieldId,
title: '金额',
type: 'Number',
width: 100,
decimal: 2,
parentId: monthId,
enableSummary: true,
summaryType: 'Sum'
});
});
grid.rebuildColumns();
}
formOnInit 时表单还没创建,不能在这个时机改列。列维护放在 formOnLoad 以及之后的事件里。
底部合计
在列上设置 enableSummary: true 后,表格底部固定一行显示该列的汇总值。行号位置显示「合计」。
| summaryType | 含义 | 适用列 |
|---|---|---|
| Sum | 求和 | 仅数字列:Number、Amount、Percent |
| Max | 最大值 | 数字或文本等 |
| Min | 最小值 | 数字或文本等 |
| Avg | 平均值 | 建议数字列 |
| Count | 非空格子的个数 | 任意类型 |
规则:
- 未设置
enableSummary的列,底部不显示合计。 - 开了合计但没写
summaryType,按Sum计算。 - 非数字列使用
Sum不会生效,需要改成Max、Min、Avg或Count。 - 空值、
null、空字符串不参与Sum、Avg、Max、Min。Count只统计有值的格子。 - 数字合计按列的
decimal四舍五入,未设置时按 2 位。 - 树形明细只合计末级行。父行上的金额不会再加一次。例如父节点数量是 10,两个末级分别是 4 和 6,合计是 10,不是 20。
items.addField({
id: 'qty',
title: '数量',
type: 'Number',
width: 100,
decimal: 2,
enableSummary: true,
summaryType: 'Sum'
});
items.addField({
id: 'remark',
title: '备注',
type: 'Text',
width: 160,
enableSummary: true,
summaryType: 'Count'
});
数量列底部是各行数量之和,备注列底部是填写了备注的行数。