improve select
This commit is contained in:
		
							parent
							
								
									15fca2b009
								
							
						
					
					
						commit
						9cc5363f49
					
				| @ -5,6 +5,7 @@ import { | ||||
|   Schema, | ||||
|   useFieldSchema, | ||||
|   observer, | ||||
|   SchemaExpressionScopeContext, | ||||
| } from '@formily/react'; | ||||
| import { SchemaRenderer, useDesignable } from '../DesignableSchemaField'; | ||||
| import get from 'lodash/get'; | ||||
| @ -40,6 +41,8 @@ function useDefaultValues() { | ||||
| } | ||||
| 
 | ||||
| export const Form: any = observer((props: any) => { | ||||
|   const scope = useContext(SchemaExpressionScopeContext); | ||||
| 
 | ||||
|   const { useValues = useDefaultValues } = props; | ||||
|   const values = useValues(); | ||||
|   const form = useMemo(() => { | ||||
| @ -67,6 +70,8 @@ export const Form: any = observer((props: any) => { | ||||
|   return ( | ||||
|     <div ref={ref} className={'nb-form'}> | ||||
|       <SchemaRenderer | ||||
|         scope={scope} | ||||
|         // components={options.components}
 | ||||
|         onRefresh={(subSchema: Schema) => { | ||||
|           designableSchema.properties = subSchema.properties; | ||||
|           refresh(); | ||||
|  | ||||
| @ -11,7 +11,10 @@ group: | ||||
| 
 | ||||
| # Select - 选择器 | ||||
| 
 | ||||
| ## 基本用法 | ||||
| 
 | ||||
| ## Select | ||||
| 
 | ||||
| ### 单选 | ||||
| 
 | ||||
| ```tsx | ||||
| import React from 'react'; | ||||
| @ -70,7 +73,7 @@ export default () => { | ||||
| }; | ||||
| ``` | ||||
| 
 | ||||
| ## 多选 | ||||
| ### 多选 | ||||
| 
 | ||||
| ```tsx | ||||
| import React from 'react'; | ||||
| @ -134,7 +137,7 @@ export default () => { | ||||
| }; | ||||
| ``` | ||||
| 
 | ||||
| ## 分组 | ||||
| ### 分组 | ||||
| 
 | ||||
| ```tsx | ||||
| import React from 'react'; | ||||
| @ -200,7 +203,11 @@ export default () => { | ||||
| }; | ||||
| ``` | ||||
| 
 | ||||
| ## 值为对象 | ||||
| ## Select.Object | ||||
| 
 | ||||
| 选项值为 Object 类型 | ||||
| 
 | ||||
| ### 单选 | ||||
| 
 | ||||
| ```tsx | ||||
| import React from 'react'; | ||||
| @ -233,12 +240,14 @@ const schema = { | ||||
|       'x-component': 'Select.Object', | ||||
|       'x-component-props': { | ||||
|         placeholder: 'please enter', | ||||
|         labelField: 'title', | ||||
|         valueField: 'id', | ||||
|         labelInValue: true, | ||||
|         // mode: 'tags', | ||||
|         fieldNames: { | ||||
|           label: 'title', | ||||
|           value: 'id', | ||||
|         }, | ||||
|       }, | ||||
|       'x-reactions': { | ||||
|         target: 'name2', | ||||
|         target: 'read', | ||||
|         fulfill: { | ||||
|           state: { | ||||
|             value: '{{$self.value}}', | ||||
| @ -250,16 +259,17 @@ const schema = { | ||||
|       interface: 'select', | ||||
|       type: 'string', | ||||
|       title: `阅读模式`, | ||||
|       required: true, | ||||
|       enum: dataSource, | ||||
|       'x-read-pretty': true, | ||||
|       'x-decorator': 'FormItem', | ||||
|       'x-component': 'Select.Object', | ||||
|       'x-component-props': { | ||||
|         placeholder: 'please enter', | ||||
|         labelField: 'title', | ||||
|         valueField: 'id', | ||||
|         labelInValue: true, | ||||
|         // mode: 'tags', | ||||
|         fieldNames: { | ||||
|           label: 'title', | ||||
|           value: 'id', | ||||
|         }, | ||||
|       }, | ||||
|     } | ||||
|   } | ||||
| @ -271,3 +281,281 @@ export default () => { | ||||
|   ); | ||||
| }; | ||||
| ``` | ||||
| 
 | ||||
| ### 多选 | ||||
| 
 | ||||
| ```tsx | ||||
| import React from 'react'; | ||||
| import { SchemaRenderer } from '../'; | ||||
| 
 | ||||
| const dataSource = [ | ||||
|   { | ||||
|     id: 1, | ||||
|     title: '标题1', | ||||
|   }, | ||||
|   { | ||||
|     id: 2, | ||||
|     title: '标题2', | ||||
|   }, | ||||
|   { | ||||
|     id: 3, | ||||
|     title: '标题3', | ||||
|   }, | ||||
| ]; | ||||
| 
 | ||||
| const schema = { | ||||
|   type: 'object', | ||||
|   properties: { | ||||
|     input: { | ||||
|       interface: 'select', | ||||
|       type: 'string', | ||||
|       title: `编辑模式`, | ||||
|       enum: dataSource, | ||||
|       'x-decorator': 'FormItem', | ||||
|       'x-component': 'Select.Object', | ||||
|       'x-component-props': { | ||||
|         placeholder: 'please enter', | ||||
|         mode: 'tags', | ||||
|         fieldNames: { | ||||
|           label: 'title', | ||||
|           value: 'id', | ||||
|         }, | ||||
|       }, | ||||
|       'x-reactions': { | ||||
|         target: 'read', | ||||
|         fulfill: { | ||||
|           state: { | ||||
|             value: '{{$self.value}}', | ||||
|           }, | ||||
|         }, | ||||
|       }, | ||||
|     }, | ||||
|     read: { | ||||
|       interface: 'select', | ||||
|       type: 'string', | ||||
|       title: `阅读模式`, | ||||
|       enum: dataSource, | ||||
|       'x-read-pretty': true, | ||||
|       'x-decorator': 'FormItem', | ||||
|       'x-component': 'Select.Object', | ||||
|       'x-component-props': { | ||||
|         placeholder: 'please enter', | ||||
|         mode: 'tags', | ||||
|         fieldNames: { | ||||
|           label: 'title', | ||||
|           value: 'id', | ||||
|         }, | ||||
|       }, | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| export default () => { | ||||
|   return ( | ||||
|     <SchemaRenderer schema={schema} /> | ||||
|   ); | ||||
| }; | ||||
| ``` | ||||
| 
 | ||||
| ## Select.Drawer | ||||
| 
 | ||||
| ```tsx | ||||
| import React from 'react'; | ||||
| import { SchemaRenderer } from '../'; | ||||
| import { useSelect } from './'; | ||||
| 
 | ||||
| console.log({ useSelect }) | ||||
| 
 | ||||
| const dataSource = [ | ||||
|   { | ||||
|     id: 1, | ||||
|     title: '标题1', | ||||
|   }, | ||||
|   { | ||||
|     id: 2, | ||||
|     title: '标题2', | ||||
|   }, | ||||
|   { | ||||
|     id: 3, | ||||
|     title: '标题3', | ||||
|   }, | ||||
| ]; | ||||
| 
 | ||||
| function useValues() { | ||||
|   return { | ||||
|     table: dataSource, | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| const schema = { | ||||
|   type: 'object', | ||||
|   properties: { | ||||
|     input: { | ||||
|       interface: 'select', | ||||
|       type: 'string', | ||||
|       title: `编辑模式`, | ||||
|       enum: dataSource, | ||||
|       default: [ | ||||
|         { | ||||
|           id: 1, | ||||
|           title: '标题1', | ||||
|         }, | ||||
|         { | ||||
|           id: 2, | ||||
|           title: '标题2', | ||||
|         }, | ||||
|       ], | ||||
|       'x-decorator': 'FormItem', | ||||
|       'x-component': 'Select.Drawer', | ||||
|       'x-component-props': { | ||||
|         placeholder: 'please enter', | ||||
|         mode: 'tags', | ||||
|         fieldNames: { | ||||
|           label: 'title', | ||||
|           value: 'id', | ||||
|         }, | ||||
|       }, | ||||
|       'x-reactions': { | ||||
|         target: 'read', | ||||
|         fulfill: { | ||||
|           state: { | ||||
|             value: '{{$self.value}}', | ||||
|           }, | ||||
|         }, | ||||
|       }, | ||||
|       properties: { | ||||
|         options: { | ||||
|           type: 'void', | ||||
|           'x-component': 'Select.Options', | ||||
|           properties: { | ||||
|             form: { | ||||
|               type: 'void', | ||||
|               'x-component': 'Form', | ||||
|               'x-component-props': { | ||||
|                 useValues: '{{ useValues }}', | ||||
|               }, | ||||
|               properties: { | ||||
|                 table: { | ||||
|                   type: 'array', | ||||
|                   'x-component': 'Table', | ||||
|                   properties: { | ||||
|                     actionbar: { | ||||
|                       type: 'void', | ||||
|                       'x-component': 'Table.ActionBar', | ||||
|                       'x-component-props': { | ||||
|                         align: 'bottom', | ||||
|                       }, | ||||
|                       properties: { | ||||
|                         action: { | ||||
|                           type: 'void', | ||||
|                           'x-component': 'Action', | ||||
|                           'x-component-props': { | ||||
|                             useAction: '{{ useSelect }}', | ||||
|                           }, | ||||
|                           title: '确定', | ||||
|                         }, | ||||
|                       }, | ||||
|                     }, | ||||
|                     column1: { | ||||
|                       type: 'void', | ||||
|                       title: '标题', | ||||
|                       'x-component': 'Table.Column', | ||||
|                       'x-component-props': { | ||||
|                         // title: 'z1', | ||||
|                       }, | ||||
|                       // 'x-designable-bar': 'Table.Column.DesignableBar', | ||||
|                       properties: { | ||||
|                         title: { | ||||
|                           type: 'string', | ||||
|                           required: true, | ||||
|                           'x-read-pretty': true, | ||||
|                           'x-decorator-props': { | ||||
|                             feedbackLayout: 'popover', | ||||
|                           }, | ||||
|                           'x-decorator': 'FormItem', | ||||
|                           'x-component': 'Input', | ||||
|                         }, | ||||
|                       }, | ||||
|                     }, | ||||
|                   }, | ||||
|                 }, | ||||
|               }, | ||||
|             }, | ||||
|           }, | ||||
|         }, | ||||
|       }, | ||||
|     }, | ||||
|     read: { | ||||
|       interface: 'select', | ||||
|       type: 'string', | ||||
|       title: `阅读模式`, | ||||
|       enum: dataSource, | ||||
|       default: [ | ||||
|         { | ||||
|           id: 1, | ||||
|           title: '标题1', | ||||
|         }, | ||||
|         { | ||||
|           id: 2, | ||||
|           title: '标题2', | ||||
|         }, | ||||
|       ], | ||||
|       'x-read-pretty': true, | ||||
|       'x-decorator': 'FormItem', | ||||
|       'x-component': 'Select.Drawer', | ||||
|       'x-component-props': { | ||||
|         placeholder: 'please enter', | ||||
|         mode: 'tags', | ||||
|         fieldNames: { | ||||
|           label: 'title', | ||||
|           value: 'id', | ||||
|         }, | ||||
|       }, | ||||
|       properties: { | ||||
|         option: { | ||||
|           type: 'void', | ||||
|           'x-component': 'Select.OptionTag', | ||||
|           properties: { | ||||
|             form: { | ||||
|               type: 'void', | ||||
|               'x-component': 'Form', | ||||
|               properties: { | ||||
|                 input: { | ||||
|                   type: 'string', | ||||
|                   'x-component': 'Input', | ||||
|                 }, | ||||
|               }, | ||||
|             }, | ||||
|           }, | ||||
|         }, | ||||
|       }, | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| export default () => { | ||||
|   return ( | ||||
|     <SchemaRenderer scope={{ useSelect, useValues }} schema={schema} /> | ||||
|   ); | ||||
| }; | ||||
| ``` | ||||
| 
 | ||||
| <!--  | ||||
| <Select /> | ||||
| <Select.Object /> | ||||
| <Select.Drawer> | ||||
|   <Select.Options> | ||||
|     <Table /> | ||||
|     <Action /> | ||||
|   <Select.Options> | ||||
|   <Select.ItemDetails> | ||||
|     <Form/> | ||||
|   </Select.ItemDetails> | ||||
| <Select.Drawer> | ||||
| 
 | ||||
| <Action /> | ||||
| 
 | ||||
| <Action> | ||||
|   <Drawer /> | ||||
| </Action> | ||||
|  --> | ||||
|  | ||||
| @ -1,38 +1,50 @@ | ||||
| import React from 'react'; | ||||
| import { connect, mapReadPretty, mapProps, useField } from '@formily/react'; | ||||
| import { Select as AntdSelect, Tag } from 'antd'; | ||||
| import { | ||||
|   connect, | ||||
|   mapReadPretty, | ||||
|   mapProps, | ||||
|   useField, | ||||
|   observer, | ||||
|   RecursionField, | ||||
|   useFieldSchema, | ||||
| } from '@formily/react'; | ||||
| import { Drawer, Select as AntdSelect, Tag } from 'antd'; | ||||
| import { PreviewText } from '@formily/antd'; | ||||
| import { LoadingOutlined } from '@ant-design/icons'; | ||||
| import { SelectProps } from 'antd/lib/select'; | ||||
| import { isArr, isValid } from '@formily/shared'; | ||||
| import { Field } from '@formily/core/esm/models/Field'; | ||||
| import { useAction } from '../../state'; | ||||
| import { Display } from '../display'; | ||||
| import { useRequest } from 'ahooks'; | ||||
| import uniq from 'lodash/uniq'; | ||||
| import { isArr, isValid, toArr } from '@formily/shared'; | ||||
| import { useState } from 'react'; | ||||
| import { useDesignable } from '../DesignableSchemaField'; | ||||
| import { createContext } from 'react'; | ||||
| import { useContext } from 'react'; | ||||
| import { useTableContext } from '../table'; | ||||
| 
 | ||||
| type ComposedSelect = React.FC<SelectProps<any>> & { | ||||
|   Object?: React.FC; | ||||
| }; | ||||
| 
 | ||||
| export const Select: ComposedSelect = connect( | ||||
| export const Select: any = connect( | ||||
|   (props) => { | ||||
|     const { options = [], ...others } = props; | ||||
|     return <AntdSelect {...others}> | ||||
|       {options.map((option: any, key: any) => { | ||||
|         if (option.children) { | ||||
|           return ( | ||||
|             <AntdSelect.OptGroup key={key} label={option.label}> | ||||
|               {option.children.map((child: any, childKey: any) => ( | ||||
|                 <AntdSelect.Option key={`${key}-${childKey}`} {...child}>{child.label}</AntdSelect.Option> | ||||
|               ))} | ||||
|             </AntdSelect.OptGroup> | ||||
|           ) | ||||
|         } else { | ||||
|           return <AntdSelect.Option key={key} {...option}>{option.label}</AntdSelect.Option> | ||||
|         } | ||||
|       })} | ||||
|     </AntdSelect> | ||||
|     return ( | ||||
|       <AntdSelect {...others}> | ||||
|         {options.map((option: any, key: any) => { | ||||
|           if (option.children) { | ||||
|             return ( | ||||
|               <AntdSelect.OptGroup key={key} label={option.label}> | ||||
|                 {option.children.map((child: any, childKey: any) => ( | ||||
|                   <AntdSelect.Option key={`${key}-${childKey}`} {...child}> | ||||
|                     {child.label} | ||||
|                   </AntdSelect.Option> | ||||
|                 ))} | ||||
|               </AntdSelect.OptGroup> | ||||
|             ); | ||||
|           } else { | ||||
|             return ( | ||||
|               <AntdSelect.Option key={key} {...option}> | ||||
|                 {option.label} | ||||
|               </AntdSelect.Option> | ||||
|             ); | ||||
|           } | ||||
|         })} | ||||
|       </AntdSelect> | ||||
|     ); | ||||
|   }, | ||||
|   mapProps( | ||||
|     { | ||||
| @ -54,9 +66,8 @@ export const Select: ComposedSelect = connect( | ||||
|   mapReadPretty((props) => { | ||||
|     const field = useField<any>(); | ||||
|     const dataSource = field.dataSource || []; | ||||
|     console.log('field.value', field.value, dataSource) | ||||
|     const value = Array.isArray(field.value) ? field.value : [field.value]; | ||||
|     const values = uniq(value); | ||||
|     console.log('field.value', field.value, dataSource); | ||||
|     const values = toArr(field.value); | ||||
|     const findOptions = (options: any[]) => { | ||||
|       let current = []; | ||||
|       for (const option of options) { | ||||
| @ -64,100 +75,96 @@ export const Select: ComposedSelect = connect( | ||||
|           current.push(option); | ||||
|         } | ||||
|         if (option.children) { | ||||
|           current = current.concat(findOptions(option.children)); | ||||
|           const children = findOptions(option.children); | ||||
|           current.push(...children); | ||||
|         } | ||||
|       } | ||||
|       return current; | ||||
|     } | ||||
|     }; | ||||
|     const options = findOptions(dataSource); | ||||
|     return ( | ||||
|       <div> | ||||
|         {options | ||||
|           .map((option, key) => ( | ||||
|             <Tag key={key} color={option.color}>{option.label}</Tag> | ||||
|           ))} | ||||
|         {options.map((option, key) => ( | ||||
|           <Tag key={key} color={option.color}> | ||||
|             {option.label} | ||||
|           </Tag> | ||||
|         ))} | ||||
|       </div> | ||||
|     ); | ||||
|   }), | ||||
| ); | ||||
| 
 | ||||
| function getFieldName(field: any) { | ||||
|   if (typeof field === 'string') { | ||||
|     return field; | ||||
|   } | ||||
|   if (typeof field === 'object') { | ||||
|     return field.name; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| Select.Object = connect( | ||||
|   (props) => { | ||||
|     const field = useField(); | ||||
|     const { | ||||
|       value, | ||||
|       onChange, | ||||
|       dataRequest, | ||||
|       labelField: lf, | ||||
|       valueField: vf, | ||||
|       fieldNames = { | ||||
|         label: 'label', | ||||
|         value: 'value', | ||||
|       }, | ||||
|       ...others | ||||
|     } = props; | ||||
|     const options = field?.['dataSource'] || props.options || []; | ||||
|     console.log({options}); | ||||
|     const labelField = getFieldName(lf); | ||||
|     const valueField = getFieldName(vf); | ||||
|     const { data = options, loading } = useRequest(() => dataRequest ? dataRequest : Promise.resolve(options), { | ||||
|       refreshDeps: [options] | ||||
|     }); | ||||
|     const getValues = () => { | ||||
|       if (!isValid(value)) { | ||||
|         return []; | ||||
|       } | ||||
|       return isArr(value) ? value : [value]; | ||||
|     } | ||||
|     const getOptionValue = () => { | ||||
|       const values = getValues().map((item) => { | ||||
|     let optionValue = undefined; | ||||
|     if (isArr(value)) { | ||||
|       optionValue = value.map((val) => { | ||||
|         return { | ||||
|           value: item[valueField], | ||||
|           label: item[labelField], | ||||
|           label: val[fieldNames.label], | ||||
|           value: val[fieldNames.value], | ||||
|         }; | ||||
|       }); | ||||
|       if (props.mode === 'multiple' || props.mode === 'tags') { | ||||
|         return values; | ||||
|       } | ||||
|       return values.length ? values[0] : null; | ||||
|     }; | ||||
|     const getOptions = () => { | ||||
|       return data.map(item => { | ||||
|         return { | ||||
|           value: item[valueField], | ||||
|           label: item[labelField], | ||||
|         }; | ||||
|       }) | ||||
|     } else if (value) { | ||||
|       optionValue = { | ||||
|         label: value[fieldNames.label], | ||||
|         value: value[fieldNames.value], | ||||
|       }; | ||||
|     } | ||||
|     return ( | ||||
|       <AntdSelect | ||||
|         allowClear | ||||
|         labelInValue | ||||
|         {...others} | ||||
|         loading={loading} | ||||
|         onChange={(option: any) => { | ||||
|           if (!isValid(option)) { | ||||
|         value={optionValue} | ||||
|         onChange={(selectValue: any) => { | ||||
|           if (!selectValue) { | ||||
|             onChange(null); | ||||
|           } | ||||
|           if (isArr(option)) { | ||||
|             const optionValues = option.map(item => item.value); | ||||
|             const selectValue = data.filter( | ||||
|               (item) => optionValues.includes(item[valueField]), | ||||
|             ); | ||||
|             onChange(selectValue); | ||||
|           if (isArr(selectValue)) { | ||||
|             const selectValues = selectValue.map((s) => s.value); | ||||
|             const values = {}; | ||||
|             if (isArr(value)) { | ||||
|               value.forEach((option) => { | ||||
|                 const val = option[fieldNames.value]; | ||||
|                 if (selectValues.includes(val)) { | ||||
|                   values[val] = option; | ||||
|                 } | ||||
|               }); | ||||
|             } | ||||
|             options.forEach((option) => { | ||||
|               const val = option[fieldNames.value]; | ||||
|               if (selectValues.includes(val)) { | ||||
|                 values[val] = option; | ||||
|               } | ||||
|             }); | ||||
|             console.log({ selectValue, values }); | ||||
|             onChange(Object.values(values)); | ||||
|           } else { | ||||
|             const selectValue = data.find( | ||||
|               (item) => item[valueField] === option.value, | ||||
|             // 这里不能用 undefined,需要用 null
 | ||||
|             onChange( | ||||
|               options.find( | ||||
|                 (option) => option[fieldNames.value] === selectValue.value, | ||||
|               ), | ||||
|             ); | ||||
|             onChange(selectValue); | ||||
|           } | ||||
|         }} | ||||
|         labelInValue | ||||
|         value={getOptionValue()} | ||||
|         options={getOptions()} | ||||
|         options={options.map((option) => { | ||||
|           return { | ||||
|             label: option[fieldNames.label], | ||||
|             value: option[fieldNames.value], | ||||
|           }; | ||||
|         })} | ||||
|       /> | ||||
|     ); | ||||
|   }, | ||||
| @ -179,7 +186,217 @@ Select.Object = connect( | ||||
|       }; | ||||
|     }, | ||||
|   ), | ||||
|   mapReadPretty(Display.ObjectSelect), | ||||
|   mapReadPretty( | ||||
|     observer((props: any) => { | ||||
|       const { value, fieldNames = { label: 'label' }, ...others } = props; | ||||
|       if (!value) { | ||||
|         return null; | ||||
|       } | ||||
|       const values = toArr(value); | ||||
|       return ( | ||||
|         <div> | ||||
|           {values.map((val) => | ||||
|             fieldNames.color ? ( | ||||
|               <Tag color={val[fieldNames.color]}>{val[fieldNames.label]}</Tag> | ||||
|             ) : ( | ||||
|               <Tag>{val[fieldNames.label]}</Tag> | ||||
|             ), | ||||
|           )} | ||||
|         </div> | ||||
|       ); | ||||
|     }), | ||||
|   ), | ||||
| ); | ||||
| 
 | ||||
| const OptionTagContext = createContext(null); | ||||
| 
 | ||||
| const SelectContext = createContext<any>({}); | ||||
| 
 | ||||
| Select.Drawer = connect( | ||||
|   (props) => { | ||||
|     const field = useField(); | ||||
|     const { | ||||
|       value, | ||||
|       onChange, | ||||
|       fieldNames = { | ||||
|         label: 'label', | ||||
|         value: 'value', | ||||
|       }, | ||||
|       ...others | ||||
|     } = props; | ||||
|     const [visible, setVisible] = useState(false); | ||||
|     const schema = useFieldSchema(); | ||||
|     const options = field?.['dataSource'] || props.options || []; | ||||
| 
 | ||||
|     let optionValue = undefined; | ||||
|     if (isArr(value)) { | ||||
|       optionValue = value.map((val) => { | ||||
|         return { | ||||
|           label: val[fieldNames.label], | ||||
|           value: val[fieldNames.value], | ||||
|         }; | ||||
|       }); | ||||
|     } else if (value) { | ||||
|       optionValue = { | ||||
|         label: value[fieldNames.label], | ||||
|         value: value[fieldNames.value], | ||||
|       }; | ||||
|     } | ||||
| 
 | ||||
|     const onFieldChange = (selectValue) => { | ||||
|       if (!isValid(selectValue)) { | ||||
|         onChange(null); | ||||
|         return; | ||||
|       } | ||||
|       if (isArr(selectValue)) { | ||||
|         const values = {}; | ||||
|         if (isArr(value)) { | ||||
|           value.forEach((option) => { | ||||
|             const val = option[fieldNames.value]; | ||||
|             if (selectValue.includes(val)) { | ||||
|               values[val] = option; | ||||
|             } | ||||
|           }); | ||||
|         } | ||||
|         options.forEach((option) => { | ||||
|           const val = option[fieldNames.value]; | ||||
|           if (selectValue.includes(val)) { | ||||
|             values[val] = option; | ||||
|           } | ||||
|         }); | ||||
|         onChange(Object.values(values)); | ||||
|       } else { | ||||
|         // 这里不能用 undefined,需要用 null
 | ||||
|         onChange( | ||||
|           options.find((option) => option[fieldNames.value] === selectValue), | ||||
|         ); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
|     return ( | ||||
|       <> | ||||
|         <AntdSelect | ||||
|           {...others} | ||||
|           labelInValue | ||||
|           open={false} | ||||
|           value={optionValue} | ||||
|           onClick={() => { | ||||
|             setVisible(true); | ||||
|           }} | ||||
|           onChange={(selectValue: any) => { | ||||
|             if (!selectValue) { | ||||
|               onChange(null); | ||||
|               return; | ||||
|             } | ||||
|             if (isArr(selectValue)) { | ||||
|               const selectValues = selectValue.map((s) => s.value); | ||||
|               onFieldChange(selectValues); | ||||
|             } else { | ||||
|               onFieldChange(selectValue.value); | ||||
|             } | ||||
|           }} | ||||
|         ></AntdSelect> | ||||
|         <Drawer | ||||
|           width={'50%'} | ||||
|           visible={visible} | ||||
|           onClose={() => setVisible(false)} | ||||
|         > | ||||
|           <SelectContext.Provider | ||||
|             value={{ | ||||
|               onChange(selectValue) { | ||||
|                 onFieldChange(selectValue); | ||||
|                 setVisible(false); | ||||
|               }, | ||||
|             }} | ||||
|           > | ||||
|             <RecursionField | ||||
|               onlyRenderProperties | ||||
|               schema={schema} | ||||
|               filterProperties={(s) => { | ||||
|                 return s['x-component'] === 'Select.Options'; | ||||
|               }} | ||||
|             /> | ||||
|           </SelectContext.Provider> | ||||
|         </Drawer> | ||||
|       </> | ||||
|     ); | ||||
|   }, | ||||
|   mapProps( | ||||
|     { | ||||
|       dataSource: 'options', | ||||
|       loading: true, | ||||
|     }, | ||||
|     (props, field) => { | ||||
|       return { | ||||
|         ...props, | ||||
|         options: field?.['dataSource'], | ||||
|         suffixIcon: | ||||
|           field?.['loading'] || field?.['validating'] ? ( | ||||
|             <LoadingOutlined /> | ||||
|           ) : ( | ||||
|             props.suffixIcon | ||||
|           ), | ||||
|       }; | ||||
|     }, | ||||
|   ), | ||||
|   mapReadPretty( | ||||
|     observer((props: any) => { | ||||
|       const field = useField<Formily.Core.Models.Field>(); | ||||
|       const { fieldNames = { label: 'label' }, ...others } = props; | ||||
|       const value = field.value || field.initialValue; | ||||
|       const schema = useFieldSchema(); | ||||
|       console.log({ field, value }); | ||||
|       if (!value) { | ||||
|         return null; | ||||
|       } | ||||
|       const values = toArr(value); | ||||
|       return ( | ||||
|         <div> | ||||
|           {values.map((data, index) => { | ||||
|             return ( | ||||
|               <OptionTagContext.Provider value={{ index, data, fieldNames }}> | ||||
|                 <RecursionField | ||||
|                   schema={schema} | ||||
|                   onlyRenderProperties | ||||
|                   filterProperties={(s) => { | ||||
|                     return s['x-component'] === 'Select.OptionTag'; | ||||
|                   }} | ||||
|                 /> | ||||
|               </OptionTagContext.Provider> | ||||
|             ); | ||||
|           })} | ||||
|         </div> | ||||
|       ); | ||||
|     }), | ||||
|   ), | ||||
| ); | ||||
| 
 | ||||
| Select.Options = observer((props) => { | ||||
|   return <>{props.children}</>; | ||||
| }); | ||||
| 
 | ||||
| export function useSelect() { | ||||
|   const { onChange } = useContext(SelectContext); | ||||
|   const { data, selectedRowKeys } = useTableContext(); | ||||
|   return { | ||||
|     async run() { | ||||
|       console.log({ data, selectedRowKeys }); | ||||
|       onChange && onChange(selectedRowKeys); | ||||
|     }, | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| Select.OptionTag = observer((props) => { | ||||
|   const [visible, setVisible] = useState(false); | ||||
|   const { data, fieldNames } = useContext(OptionTagContext); | ||||
|   return ( | ||||
|     <> | ||||
|       <Tag onClick={() => setVisible(true)}>{data[fieldNames.label]}</Tag> | ||||
|       <Drawer width={'50%'} visible={visible} onClose={() => setVisible(false)}> | ||||
|         {props.children} | ||||
|       </Drawer> | ||||
|     </> | ||||
|   ); | ||||
| }); | ||||
| 
 | ||||
| export default Select; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user