Skip to Content

记录选择器

用于从模型中选择单条记录的小型单选式选择器。设计用于对话框表单内 —— 通常是 ActionDialog —— 用户在提交前需先选一条记录(例如「将此版本部署到哪个环境」)。

两层组件:

组件适用场景
RecordPickerList需要受控(value / onChange)列表时。
RecordPickerField在 react-hook-form provider 内(如 ActionDialog 正文),希望选择器绑定表单字段并参与校验。

多数调用方使用 RecordPickerField。RecordPickerList 是更低层的逃生口。

快速开始(ActionDialog 内的 RecordPickerField)

import { RecordPickerField } from "@/components/views/shared/picker"; import { Server } from "lucide-react"; function DeployToEnvDialog() { return ( <ActionDialog title="Deploy to Environment"> <RecordPickerField name="envId" required="Pick an environment to deploy." modelName="DesignAppEnv" filters={["active", "=", true]} orders={["sequence", "ASC"]} icon={Server} titleField="name" badgeField="envType" descriptionField="currentVersionId" /> </ActionDialog> ); }

选择器将所选记录的 id 写入 envId。对话框提交 payload 变为 { envId: "<chosen-id>", ...other-form-fields }。若用户未选择就点确认,选择器下方显示 "Pick an environment to deploy."(校验会阻止 Confirm)。

展示语义

titleField / badgeField / descriptionField 是被选模型上的字段名。选择器从模型元数据读取各字段的 fieldType,选择正确的展示提取器:

字段类型提取器
Option / MultiOptionlabel(选项集本地化标签)
ManyToOne / OneToOne引用记录的 displayName
其他String(value)

因此,对选项集字段声明 titleField="status" 会渲染选项展示名,而非原始 itemCode。

titleField 默认为 "name"。模型使用其他展示字段时请覆盖。

组件

RecordPickerField

表单绑定。用 react-hook-form 的 <Controller> 包装 RecordPickerList,像其他表单字段一样暴露 name / required。

<RecordPickerField name="versionId" required // boolean — gates submit, no message modelName="DesignAppEnv" ... /> <RecordPickerField name="versionId" required="Please pick a version." // string — same gating, shows message modelName="DesignAppEnv" ... />
Prop类型必填默认值说明
namePath<TFormValues>是-react-hook-form 字段路径
requiredboolean | string否-true:必填,无行内消息。string:必填,提交时在 picker 下方显示消息
modelNamestring是-源模型
filtersFilterCondition否-应用于源查询的过滤
ordersOrderCondition否-应用于源查询的排序
limitSizenumber否50拉取记录上限(选择器面向短列表)
enabledboolean否true禁用底层查询(例如父值加载中)
iconLucideIcon否-每张卡片左侧图标
titleFieldstring否"name"卡片标题字段
badgeFieldstring否-标题右侧小徽章字段
descriptionFieldstring否-次要描述行字段
emptyMessagestring否"No records found."查询无结果时显示

用法需要外层 react-hook-form provider。ActionDialog 的 DialogForm 已提供 —— 可直接放在对话框正文中。

RecordPickerList

受控列表。无法引入 form provider 时使用,例如由组件 state 驱动的临时内联选择器。

const [pickedId, setPickedId] = React.useState<string>(); <RecordPickerList modelName="DesignAppEnv" filters={[["status", "=", "Sealed"]]} value={pickedId} onChange={(id) => setPickedId(id)} titleField="name" badgeField="envType" />
Prop类型必填默认值说明
modelNamestring是-源模型
filtersFilterCondition否-源查询过滤
ordersOrderCondition否-源查询排序
limitSizenumber否50拉取上限
enabledboolean否true禁用底层查询
valuestring | undefined是-已选记录 id
onChange(id: string, record: Record<string, unknown>) => void是-选择时触发
iconLucideIcon否-每卡左侧图标
titleFieldstring否"name"卡片标题字段
badgeFieldstring否-可选徽章字段
descriptionFieldstring否-可选描述字段
emptyMessagestring否"No records found."

加载态显示居中 spinner;空态显示 emptyMessage。

卡片视觉结构

┌──────────────────────────────────────┐ │ [icon] Title [badge] [check] │ ← header row │ Description text │ ← optional description └──────────────────────────────────────┘
  • [icon]:icon prop 设置时显示(LucideIcon 组件引用)
  • Title:来自 titleField;元数据感知提取器
  • [badge]:badgeField 小 chip;元数据感知提取器
  • [check]:仅选中行显示(CheckCircle2)
  • Description:来自 descriptionField;溢出截断

选中卡片为主色边框 + 轻微 ring + tinted 背景。未选中卡片 hover 高亮。

为何需要专用选择器(对比 ManyToOne 字段)?

在普通表单中选记录时,widgetType="ComboBox" 的 Field 更合适。选择器面向对话框流程:

  • 对话框是唯一表单(无外层 ModelForm)
  • 列表是小型、有排序的短列表(默认 ≤ 50 条)
  • 需要开箱即用的丰富展示(icon + badge + description)
  • 校验应用 Confirm 按钮并显示行内错误

数百条记录或嵌在 ModelForm 内时,请用 relation 类型的 Field,而非 picker。

何时用哪个

场景使用
ActionDialog 正文内的选择器RecordPickerField(表单绑定)
任意其他 react-hook-form provider 内RecordPickerField
本地 useState 驱动(无 form)RecordPickerList(受控)
普通 ModelForm 中的关联列普通 relation Field —— 不是 picker
最后更新于