@@ -32,6 +32,7 @@ import { DraftNumberInput } from '@/components/ui/draft-number-input'
3232import { Input } from '@/components/ui/input'
3333import { Label } from '@/components/ui/label'
3434import { Card } from '@/components/ui/card'
35+ import { MultiSelect } from '@/components/ui/multi-select'
3536import { Switch } from '@/components/ui/switch'
3637import { Slider } from '@/components/ui/slider'
3738import {
@@ -52,6 +53,10 @@ export interface ItemFieldDefinition {
5253 label ?: string
5354 placeholder ?: string
5455 default ?: unknown
56+ /** select 是否允许多选 */
57+ multiple ?: boolean
58+ /** 当字段本身仍是数组时,描述其元素类型 */
59+ item_type ?: string
5560 /** select 类型的选项 */
5661 choices ?: unknown [ ]
5762 /** slider 类型的最小值 */
@@ -60,6 +65,12 @@ export interface ItemFieldDefinition {
6065 max ?: number
6166 /** slider 类型的步进 */
6267 step ?: number
68+ /** 嵌套数组为 object 时的字段定义 */
69+ item_fields ?: Record < string , ItemFieldDefinition >
70+ /** 嵌套数组最小项数 */
71+ min_items ?: number
72+ /** 嵌套数组最大项数 */
73+ max_items ?: number
6374}
6475
6576export interface ListFieldEditorProps {
@@ -263,27 +274,47 @@ function ObjectItemEditor({
263274
264275 // select
265276 if ( fieldDef . type === 'select' && fieldDef . choices ) {
277+ const selectedValues = Array . isArray ( fieldValue )
278+ ? fieldValue . map ( ( item ) => String ( item ) )
279+ : Array . isArray ( fieldDef . default )
280+ ? fieldDef . default . map ( ( item ) => String ( item ) )
281+ : [ ]
282+
266283 return (
267284 < div className = "space-y-1" >
268285 < Label className = "text-xs text-muted-foreground" >
269286 { fieldDef . label ?? fieldName }
270287 </ Label >
271- < Select
272- value = { String ( fieldValue ?? fieldDef . default ?? '' ) }
273- onValueChange = { ( v ) => handleFieldChange ( fieldName , v ) }
274- disabled = { disabled }
275- >
276- < SelectTrigger className = "h-8 text-sm" >
277- < SelectValue placeholder = { fieldDef . placeholder ?? '请选择' } />
278- </ SelectTrigger >
279- < SelectContent >
280- { fieldDef . choices . map ( ( choice ) => (
281- < SelectItem key = { String ( choice ) } value = { String ( choice ) } >
282- { String ( choice ) }
283- </ SelectItem >
284- ) ) }
285- </ SelectContent >
286- </ Select >
288+ {
289+ fieldDef . multiple ?
290+ < MultiSelect
291+ options = { fieldDef . choices . map ( ( choice ) => ( {
292+ label : String ( choice ) ,
293+ value : String ( choice ) ,
294+ } ) ) }
295+ selected = { selectedValues }
296+ onChange = { ( nextValue ) => handleFieldChange ( fieldName , nextValue ) }
297+ placeholder = { fieldDef . placeholder ?? '请选择' }
298+ compact
299+ disabled = { disabled }
300+ /> :
301+ < Select
302+ value = { String ( fieldValue ?? fieldDef . default ?? '' ) }
303+ onValueChange = { ( v ) => handleFieldChange ( fieldName , v ) }
304+ disabled = { disabled }
305+ >
306+ < SelectTrigger className = "h-8 text-sm" >
307+ < SelectValue placeholder = { fieldDef . placeholder ?? '请选择' } />
308+ </ SelectTrigger >
309+ < SelectContent >
310+ { fieldDef . choices . map ( ( choice ) => (
311+ < SelectItem key = { String ( choice ) } value = { String ( choice ) } >
312+ { String ( choice ) }
313+ </ SelectItem >
314+ ) ) }
315+ </ SelectContent >
316+ </ Select >
317+ }
287318 </ div >
288319 )
289320 }
@@ -310,6 +341,33 @@ function ObjectItemEditor({
310341 )
311342 }
312343
344+ // array
345+ if ( fieldDef . type === 'array' ) {
346+ const selectedValues = Array . isArray ( fieldValue )
347+ ? fieldValue
348+ : Array . isArray ( fieldDef . default )
349+ ? fieldDef . default
350+ : [ ]
351+
352+ return (
353+ < div className = "space-y-1" >
354+ < Label className = "text-xs text-muted-foreground" >
355+ { fieldDef . label ?? fieldName }
356+ </ Label >
357+ < ListFieldEditor
358+ value = { selectedValues }
359+ onChange = { ( nextValue ) => handleFieldChange ( fieldName , nextValue ) }
360+ itemType = { fieldDef . item_type ?? 'string' }
361+ itemFields = { fieldDef . item_fields }
362+ minItems = { fieldDef . min_items }
363+ maxItems = { fieldDef . max_items }
364+ disabled = { disabled }
365+ placeholder = { fieldDef . placeholder }
366+ />
367+ </ div >
368+ )
369+ }
370+
313371 // string (default)
314372 return (
315373 < div className = "space-y-1" >
0 commit comments