NocoBase 下拉选择器字段:关系数据关联、数据范围、远程搜索与快速创建详解
2026/9/16 19:03:02 网站建设 项目流程

NocoBase 下拉选择器字段:关系数据关联、数据范围、远程搜索与快速创建详解

【免费下载链接】nocobaseNocoBase is an open-source AI + no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase

下拉选择器(AssociationSelect)是 NocoBase 界面搭建器中关系字段编辑态下的默认组件,用于从目标表已有数据中选取并建立关联,也支持边输入边新建目标表数据。本文基于文档docs/docs/cn/interface-builder/fields/specific/select.md展开,覆盖数据范围、排序规则、多条关联限制、标题字段与快速创建等全部配置项,并结合packages/core/client中的组件源码与端到端测试,说明每一项配置在底层如何转化为列表请求参数(filtersortfieldNames等),帮助你在配置下拉选择器时理解其实际行为与联动机制。

一、下拉选择器的定位:关系字段的默认编辑组件

NocoBase 的关系字段组件根据关系类型与目标表类型选择不同的默认组件。按照关系字段组件文档的说明:

  • 除了目标表为文件表的所有关系字段,编辑状态下的默认组件均为下拉选择器
  • 下拉选项显示的是标题字段的值,适用于“通过显示一个关键字段信息即可快速选取关联数据”的场景。

也就是说,当你在订单表(订单有多对一关系字段「Account」)的表单区块中添加关联字段时,默认得到的就是一个可搜索、可快速新建的下拉框。目标表为文件表时则应改用文件管理器;需要更精确选取时可切换为数据选择器等其它关系字段组件。

从源码结构看,下拉选择器由两层实现组成:

  • AssociationSelect.tsx(antd/association-select目录):负责设计器侧的设置面板(数据范围、排序、标题字段、允许多条等),运行时渲染委托给RemoteSelect
  • AssociationSelect.tsx(antd/association-field目录):关系字段形态的实现,额外支持addMode(快速创建)与联动重置逻辑。

其运行时选项请求由 useServiceOptions.ts 组装,最终统一发给目标表的list动作。这一“配置即请求参数”的模型,是理解下面所有配置项的关键。

二、设置数据范围:控制下拉列表可选哪些数据

设置数据范围用于控制下拉列表的数据范围,为关系数据设定默认的筛选条件。配置入口在字段设置面板中,配置结果写入x-component-props.service.params.filter。在 AssociationSelect.tsx 的设计器代码中可以看到这一项由SchemaSettingsDataScope组件承载,提交时执行:

<SchemaSettingsDataScope collectionName={collectionField?.target} // 目标表 defaultFilter={field.componentProps?.service?.params?.filter || {}} onSubmit={({ filter }) => { filter = removeNullCondition(filter); _.set(field.componentProps, 'service.params.filter', filter); // 写入列表请求的 filter ... }} />

完整用法参考设置数据范围,其中三类典型场景如下:

静态值

针对目标表字段设置固定筛选条件。示例:仅在未删除商品中可以选择关联(字段列表为关系字段目标表字段)。

变量值

筛选条件中可以使用变量,实现动态范围。示例:仅商品服务日期晚于订单日期的商品可以选择关联。变量体系详见变量。

关系字段联动

多个关系字段之间通过各自的数据范围实现级联过滤。示例:订单表有一对多关系字段「商机产品」和多对一关系字段「商机」,商机产品表有多对一关系字段「商机」;在订单表单区块中,「商机产品」的可选数据即为当前表单中所选商机关联的商机商品。

这一联动在源码中有明确实现与测试验证。AssociationSelect.tsx(association-field) 中的filterAnalyses会解析数据范围里形如{{$字段.id}}的变量表达式,提取出被引用的关系字段名;组件再通过 formily 的onFieldInputValueChange监听:当被引用的关系字段值变化时,自动把当前下拉字段的值重置为null,避免留下失效的关联(见同文件 L115-L139)。

端到端测试 dataScope.test.ts 验证了这一行为:未选择学校时,点击「班级」下拉发出的api/class:list请求参数为filter={"$and":[{"school":{"id":{"$eq":null}}}]};选择学校 id=1 后再次点击,请求变为{"$and":[{"school":{"id":{"$eq":1}}}]}。这证明数据范围最终落地为列表接口filter查询参数,联动是“请求级”的。

一多关系下“未关联优先”的默认行为

useServiceOptions中还内置了一段对一多/多对多关系(oho/o2m)的过滤合并逻辑(useServiceOptions.ts L46-L82):

  • 新建场景:追加{ [foreignKey]: { $is: null } },即默认优先展示尚未被关联的目标记录;
  • 编辑已有记录场景:追加{ [foreignKey]: { $eq: sourceValue } },保证当前已关联记录也在选项中;
  • 与已选值合并:已选中的值通过{ [fieldNames.value]: { $in: value } }$or并入过滤条件,防止选中项因范围变化而从下拉中“消失”。

从源码结构看,这套默认合并策略让一多关系的下拉在不开启任何自定义数据范围时,就呈现出“未占用记录在前、已关联记录仍可见”的合理默认行为。

三、设置排序规则:控制下拉选项的排序

下拉选择器支持设置默认排序规则,控制下拉列表数据的排序。文档示例:按服务日期倒序排序。

在 AssociationSelect.tsx 设计器 中,排序配置以“字段 + 方向(ASC/DESC)”的数组形式编辑,字段候选来自useSortFields(collectionField?.target)(目标表字段),提交时转换为紧凑的排序串写回组件属性:

onSubmit={({ sort }) => { const sortArr = sort.map((item) => { return item.direction === 'desc' ? `-${item.field}` : item.field; }); _.set(field.componentProps, 'service.params.sort', sortArr); // 例如 ['service_date' 的反向:'-service_date'] ... }}

反向读取时同样按-前缀解析为direction: 'desc'(同文件 L148-L158)。即“按服务日期倒序”在 schema 中表现为service.params.sort = ['-service_date'],随后作为sort参数发给目标表list请求。

四、允许添加/关联多条:限制一对多关系仅关联一条

文档中的「允许添加/关联多条」配置项用于限制对多的关系数据仅允许关联一条数据。关闭该开关后,即使关系类型是多对一/多对多,下拉也退化为单值选择。

对应源码为 AssociationSelect.tsx L402-L426:

{IsShowMultipleSwitch() ? ( <SchemaSettingsSwitchItem key="multiple" title={t('Allow multiple')} // 允许添加/关联多条 checked={ fieldSchema['x-component-props']?.multiple === undefined ? true // 默认允许多条 : fieldSchema['x-component-props'].multiple } onChange={(value) => { fieldSchema['x-component-props'].multiple = value; field.componentProps.multiple = value; ... }} /> ) : null}

两个实现细节值得注意:

  1. 该开关由useIsShowMultipleSwitch()钩子决定是否显示(hooks 文件),即只在与多条语义兼容的关系类型下才出现;
  2. multiple未显式设置时按true处理,因此一对多/多对多关系默认可关联多条,显式配置为false后才受“仅一条”限制。

五、标题字段:选项标签、显示组件与模糊搜索

标题字段是选项显示的标签字段,决定了目标表记录在下拉框中以什么身份呈现。完整规则参考标题字段:

  • 标题字段通常是关系字段组件中关联数据在界面上的显示标识;
  • 不同类型标题字段对应不同的展示组件:标题字段为日期字段时用日期组件展示,为文本字段时用文本组件,为选项字段时用选项组件。

标题字段有两个设置入口(标题字段文档):

入口生效范围优先级
数据表配置标题字段全局生效较低
关系字段组件配置标题字段仅区块内生效最高

在设计器源码中,标题字段选项由目标表字段过滤isTitleField(field)生成,切换时写入fieldNames.label

<SchemaSettingsSelectItem key="title-field" title={t('Title field')} options={options} // 目标表中可作为标题的字段 value={field?.componentProps?.fieldNames?.label} onChange={(label) => { const fieldNames = { ...field.componentProps.fieldNames, label }; fieldSchema['x-component-props']['fieldNames'] = fieldNames; ... }} />

fieldNames.label会被RemoteSelect用作 antdSelect的选项 label 映射,因此“支持根据标题字段快速检索”是成立的:在输入框键入文本时,组件以标题字段为关键词向目标表发起带搜索条件的list请求。

从 RemoteSelect.tsx 的实现可以看到搜索是服务端远程过滤而非前端内存过滤:

// 列表请求 useRequest({ action: 'list', ...service, params: { pageSize: 200, ...service?.params, filter: service?.params?.filter }, { manual, debounceWait: wait, ... } ), // antd Select <Select filterOption={false} // 关闭前端过滤,交由服务端 onSearch 请求 onSearch={onSearch} ... />

即默认每次拉取 200 条,带防抖的onSearch触发重新请求,实现文档所说的“下拉选项支持模糊搜索”。

六、快速创建:先添加数据,再选中该数据

当目标表中还没有合适的数据时,下拉选择器支持快速创建:为目标表新建数据后自动选中该数据,并在表单提交后完成关联。文档以“订单表有多对一关系字段「Account」”为例,提供了两种添加方式。

下拉菜单添加(quickAdd)

在下拉菜单底部直接输入新值回车,即可为目标表新建一条记录并自动选中。对应x-component-props.addMode === 'quickAdd',FormItem 设置面板 中该模式显示为 “Dropdown(下拉)”。

运行时逻辑见 association-field/AssociationSelect.tsx 的 handleCreateAction:

const handleCreateAction = async (props) => { const { search: value, callBack } = props; const { data: { data } } = await resource.create({ values: { [field?.componentProps?.fieldNames?.label || 'id']: value, // 以标题字段提交新值 }, }); if (data) { if (['m2m', 'o2m'].includes(collectionField?.interface) && multiple !== false) { const values = form.getValuesIn(field.path) || []; values.push(data); // 多值关系:追加到数组 form.setValuesIn(field.path, values); } else { form.setValuesIn(field.path, data); // 单值关系:直接赋值 } field.onInput(...); message.success(t('Saved successfully')); } };

可以看到:新建只写入标题字段的值(如「Account」的标题字段),创建成功后按关系类型自动填充表单——单值关系直接设为选中项,多值关系(m2m/o2m且允许多条)则 push 进数组;这与文档描述“新建数据后自动选中该数据并在表单提交后关联”完全一致。

RemoteSelect.tsx 中的dropdownRender负责在菜单中呈现这一项:当addMode === 'quickAdd'时,在搜索结果与分隔线下方渲染“快速新建”条目;若输入内容已与某选项标题完全匹配(isFullMatch)则不再显示新建入口,避免重复创建。

弹窗添加(modalAdd)

弹窗添加适用于较复杂的录入场景:它打开一个可配置的新增表单(而非仅采集标题字段),用户填完完整表单后再回到下拉选中该记录。对应addMode === 'modalAdd',两种模式在 AssociationSelectProps 中定义为联合类型:

export type AssociationSelectProps<P = any> = RemoteSelectProps<P> & { addMode?: 'quickAdd' | 'modalAdd'; action?: string; multiple?: boolean; };

选择建议:目标表只有一两个必填字段时用“下拉菜单添加”;目标表字段多、需要完整表单校验与关系子数据录入时用“弹窗添加”。

七、底层请求模型与其余可配置项

配置如何转化为列表请求

把前述配置串起来,下拉选择器的一次展开等价于一次目标表查询。useServiceOptions.ts 的最终返回:

return { resource: collectionField?.target, // 目标表 action: 'list', // 默认 list ...service, params: { ...service?.params, filter }, // filter = 内置规则 + 数据范围 合并 };

对应关系一览:

配置项落地位置请求参数
数据范围service.params.filterfilter(与内置“未关联优先”规则$or合并)
排序规则service.params.sortsort(如['-service_date']
标题字段fieldNames.label选项 label 映射与快速检索关键词
允许添加/关联多条multiple前端单选/多选行为
快速创建addMode触发resource.create(values 仅含标题字段)

默认值与模式

设计器还内建了设置默认值(源码 L306-L350,通过内嵌的AssociationSelect选单设定)和模式切换(editable/readonly/read-pretty,由x-disabledx-read-pretty控制)。阅读态下,组件经mapReadPretty切换为只读展示形态(AssociationSelect.tsx L99 的mapReadPretty(ReadPretty)),与标题组件衔接。

八、验证与延伸阅读

  • 联动与范围行为可用 e2e 测试复现:dataScope.test.ts 断言了api/class:list请求的filter在“未选择学校 → 选择学校”前后的变化,以及多层关系字段值参与数据范围时的选项联动。
  • 字段设置通用项:字段数据范围、标题字段、默认值、验证规则、模式。
  • 组件族总览:关系字段组件,其中还涵盖数据选择器、子表单、子表格等更复杂的关联维护形态——当下拉选择器的“标题字段单键选取”不够用时,可在这条组件链上逐级切换。

适用前提说明:本文基于当前仓库中packages/core/client(基于 Formily + antd 的 v1 客户端)的实现描述。配置项名称以界面翻译为准,例如“允许添加/关联多条”对应源码中的 “Allow multiple”、“下拉菜单添加/弹窗添加”对应addMode: quickAdd / modalAdd

【免费下载链接】nocobaseNocoBase is an open-source AI + no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询