症状
lookup「浏览全部记录」记录选择器的筛选面板里,select 筛选项被选中后,写进 $filter 的永远是字符串。当该筛选项的选项值不是字符串(数字、布尔)时,查询条件与库里存的值类型不符,筛选结果为空 —— 界面上表现为「选了一个明明有记录的选项,列表却空了」。
定位(origin/main,commit 789fe3e)
packages/fields/src/widgets/RecordPickerDialog.tsx:
:779 SelectItem value={String(opt.value)} —— Radix Select 的 value 必须是 string,所以选项值在渲染时被 stringify(这一步本身没问题);
:772 onValueChange={v = 回调拿到的就是那个 string,直接 handleFilterChange(col.field, v) 存进 filterValues,没有再映射回作者写的原值;
:206 filterValuesToRecord 的 select 分支 result[col.field] = v; 原样透传,于是 $filter 里是 "3" 而不是 3。
产生非字符串选项值的来源是筛选列的自动派生:
:452 effectiveFilterColumns 从 lookupFilters 派生时,in / notIn 的数组值被直接当成选项值:options: (f.value as any[]).map(v = → { label: String(v), value: v },v 的类型完全由作者写的 lookup_filters 决定;LookupFilterDef.value 在 packages/types/src/field-types.ts:443 声明为 unknown。
复现路径:lookup 字段声明 lookup_filters: [{ field: 'level', operator: 'in', value: [1, 2, 3] }] → 打开记录选择器 → 筛选面板出现 level 下拉(选项 1/2/3)→ 选 1 → 下发 $filter: { level: "1" },而记录里 level 是数字 1。
影响范围与优先级说明(请 triage 复核)
参考修法
表单侧同类问题已有先例:#3090 引入了 matchOptionValue / toControlValue(packages/components/src/renderers/form/),职责正是「控件说 string,payload 还作者写的类型」。筛选面板可以复用同一对语义(在 handleFilterChange 处按 col.options 反查原值),而不是在 filterValuesToRecord 里做类型猜测式的 coerce —— 后者会把 "1" 和 1 的区分权交给消费端猜。
顺带可一并核对:col.type === 'number' 分支已经显式 Number(raw),boolean 分支显式 Boolean(val),只有 select 分支没有回映射,三者行为不一致本身也是个信号。
发现来源
实现 #3336(PR #3421)时顺带发现,已按 Prime Directive #10 另开、不带 pm:queue、未指派。
症状
lookup「浏览全部记录」记录选择器的筛选面板里,
select筛选项被选中后,写进$filter的永远是字符串。当该筛选项的选项值不是字符串(数字、布尔)时,查询条件与库里存的值类型不符,筛选结果为空 —— 界面上表现为「选了一个明明有记录的选项,列表却空了」。定位(origin/main,commit 789fe3e)
packages/fields/src/widgets/RecordPickerDialog.tsx::779SelectItem value={String(opt.value)}—— Radix Select 的 value 必须是 string,所以选项值在渲染时被 stringify(这一步本身没问题);:772onValueChange={v =回调拿到的就是那个 string,直接handleFilterChange(col.field, v)存进filterValues,没有再映射回作者写的原值;:206filterValuesToRecord的 select 分支result[col.field] = v;原样透传,于是$filter里是"3"而不是3。产生非字符串选项值的来源是筛选列的自动派生:
:452effectiveFilterColumns从lookupFilters派生时,in/notIn的数组值被直接当成选项值:options: (f.value as any[]).map(v =→{ label: String(v), value: v },v的类型完全由作者写的lookup_filters决定;LookupFilterDef.value在packages/types/src/field-types.ts:443声明为unknown。复现路径:lookup 字段声明
lookup_filters: [{ field: 'level', operator: 'in', value: [1, 2, 3] }]→ 打开记录选择器 → 筛选面板出现level下拉(选项 1/2/3)→ 选1→ 下发$filter: { level: "1" },而记录里level是数字 1。影响范围与优先级说明(请 triage 复核)
@objectstack/spec的SelectOptionSchema.value是string,所以 [fields] lookup 记录选择器筛选面板:select 类型筛选项不带 options,下拉为空 #3336(PR fix(fields): 记录选择器筛选面板的 select 筛选项改从引用对象 schema 取 options (#3336) #3421)新引入的「筛选项从 schema 取 options」这条路径下发的一定是字符串,是对的;lookup_filters自动派生路径,在 main 上早已存在,与 [fields] lookup 记录选择器筛选面板:select 类型筛选项不带 options,下拉为空 #3336 无关,不是 PR fix(fields): 记录选择器筛选面板的 select 筛选项改从引用对象 schema 取 options (#3336) #3421 引入的。故按纪律另开而不是搭车修。参考修法
表单侧同类问题已有先例:#3090 引入了
matchOptionValue/toControlValue(packages/components/src/renderers/form/),职责正是「控件说 string,payload 还作者写的类型」。筛选面板可以复用同一对语义(在handleFilterChange处按col.options反查原值),而不是在filterValuesToRecord里做类型猜测式的 coerce —— 后者会把"1"和1的区分权交给消费端猜。顺带可一并核对:
col.type === 'number'分支已经显式Number(raw),boolean分支显式Boolean(val),只有select分支没有回映射,三者行为不一致本身也是个信号。发现来源
实现 #3336(PR #3421)时顺带发现,已按 Prime Directive #10 另开、不带
pm:queue、未指派。