improve select
This commit is contained in:
		
							parent
							
								
									15fca2b009
								
							
						
					
					
						commit
						9cc5363f49
					
				| @ -5,6 +5,7 @@ import { | |||||||
|   Schema, |   Schema, | ||||||
|   useFieldSchema, |   useFieldSchema, | ||||||
|   observer, |   observer, | ||||||
|  |   SchemaExpressionScopeContext, | ||||||
| } from '@formily/react'; | } from '@formily/react'; | ||||||
| import { SchemaRenderer, useDesignable } from '../DesignableSchemaField'; | import { SchemaRenderer, useDesignable } from '../DesignableSchemaField'; | ||||||
| import get from 'lodash/get'; | import get from 'lodash/get'; | ||||||
| @ -40,6 +41,8 @@ function useDefaultValues() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const Form: any = observer((props: any) => { | export const Form: any = observer((props: any) => { | ||||||
|  |   const scope = useContext(SchemaExpressionScopeContext); | ||||||
|  | 
 | ||||||
|   const { useValues = useDefaultValues } = props; |   const { useValues = useDefaultValues } = props; | ||||||
|   const values = useValues(); |   const values = useValues(); | ||||||
|   const form = useMemo(() => { |   const form = useMemo(() => { | ||||||
| @ -67,6 +70,8 @@ export const Form: any = observer((props: any) => { | |||||||
|   return ( |   return ( | ||||||
|     <div ref={ref} className={'nb-form'}> |     <div ref={ref} className={'nb-form'}> | ||||||
|       <SchemaRenderer |       <SchemaRenderer | ||||||
|  |         scope={scope} | ||||||
|  |         // components={options.components}
 | ||||||
|         onRefresh={(subSchema: Schema) => { |         onRefresh={(subSchema: Schema) => { | ||||||
|           designableSchema.properties = subSchema.properties; |           designableSchema.properties = subSchema.properties; | ||||||
|           refresh(); |           refresh(); | ||||||
|  | |||||||
| @ -11,7 +11,10 @@ group: | |||||||
| 
 | 
 | ||||||
| # Select - 选择器 | # Select - 选择器 | ||||||
| 
 | 
 | ||||||
| ## 基本用法 | 
 | ||||||
|  | ## Select | ||||||
|  | 
 | ||||||
|  | ### 单选 | ||||||
| 
 | 
 | ||||||
| ```tsx | ```tsx | ||||||
| import React from 'react'; | import React from 'react'; | ||||||
| @ -70,7 +73,7 @@ export default () => { | |||||||
| }; | }; | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ## 多选 | ### 多选 | ||||||
| 
 | 
 | ||||||
| ```tsx | ```tsx | ||||||
| import React from 'react'; | import React from 'react'; | ||||||
| @ -134,7 +137,7 @@ export default () => { | |||||||
| }; | }; | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ## 分组 | ### 分组 | ||||||
| 
 | 
 | ||||||
| ```tsx | ```tsx | ||||||
| import React from 'react'; | import React from 'react'; | ||||||
| @ -200,7 +203,11 @@ export default () => { | |||||||
| }; | }; | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ## 值为对象 | ## Select.Object | ||||||
|  | 
 | ||||||
|  | 选项值为 Object 类型 | ||||||
|  | 
 | ||||||
|  | ### 单选 | ||||||
| 
 | 
 | ||||||
| ```tsx | ```tsx | ||||||
| import React from 'react'; | import React from 'react'; | ||||||
| @ -233,12 +240,14 @@ const schema = { | |||||||
|       'x-component': 'Select.Object', |       'x-component': 'Select.Object', | ||||||
|       'x-component-props': { |       'x-component-props': { | ||||||
|         placeholder: 'please enter', |         placeholder: 'please enter', | ||||||
|         labelField: 'title', |         // mode: 'tags', | ||||||
|         valueField: 'id', |         fieldNames: { | ||||||
|         labelInValue: true, |           label: 'title', | ||||||
|  |           value: 'id', | ||||||
|  |         }, | ||||||
|       }, |       }, | ||||||
|       'x-reactions': { |       'x-reactions': { | ||||||
|         target: 'name2', |         target: 'read', | ||||||
|         fulfill: { |         fulfill: { | ||||||
|           state: { |           state: { | ||||||
|             value: '{{$self.value}}', |             value: '{{$self.value}}', | ||||||
| @ -250,16 +259,17 @@ const schema = { | |||||||
|       interface: 'select', |       interface: 'select', | ||||||
|       type: 'string', |       type: 'string', | ||||||
|       title: `阅读模式`, |       title: `阅读模式`, | ||||||
|       required: true, |  | ||||||
|       enum: dataSource, |       enum: dataSource, | ||||||
|       'x-read-pretty': true, |       'x-read-pretty': true, | ||||||
|       'x-decorator': 'FormItem', |       'x-decorator': 'FormItem', | ||||||
|       'x-component': 'Select.Object', |       'x-component': 'Select.Object', | ||||||
|       'x-component-props': { |       'x-component-props': { | ||||||
|         placeholder: 'please enter', |         placeholder: 'please enter', | ||||||
|         labelField: 'title', |         // mode: 'tags', | ||||||
|         valueField: 'id', |         fieldNames: { | ||||||
|         labelInValue: true, |           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 React from 'react'; | ||||||
| import { connect, mapReadPretty, mapProps, useField } from '@formily/react'; | import { | ||||||
| import { Select as AntdSelect, Tag } from 'antd'; |   connect, | ||||||
|  |   mapReadPretty, | ||||||
|  |   mapProps, | ||||||
|  |   useField, | ||||||
|  |   observer, | ||||||
|  |   RecursionField, | ||||||
|  |   useFieldSchema, | ||||||
|  | } from '@formily/react'; | ||||||
|  | import { Drawer, Select as AntdSelect, Tag } from 'antd'; | ||||||
| import { PreviewText } from '@formily/antd'; | import { PreviewText } from '@formily/antd'; | ||||||
| import { LoadingOutlined } from '@ant-design/icons'; | import { LoadingOutlined } from '@ant-design/icons'; | ||||||
| import { SelectProps } from 'antd/lib/select'; | import { SelectProps } from 'antd/lib/select'; | ||||||
| import { isArr, isValid } from '@formily/shared'; | import { isArr, isValid, toArr } from '@formily/shared'; | ||||||
| import { Field } from '@formily/core/esm/models/Field'; | import { useState } from 'react'; | ||||||
| import { useAction } from '../../state'; | import { useDesignable } from '../DesignableSchemaField'; | ||||||
| import { Display } from '../display'; | import { createContext } from 'react'; | ||||||
| import { useRequest } from 'ahooks'; | import { useContext } from 'react'; | ||||||
| import uniq from 'lodash/uniq'; | import { useTableContext } from '../table'; | ||||||
| 
 | 
 | ||||||
| type ComposedSelect = React.FC<SelectProps<any>> & { | export const Select: any = connect( | ||||||
|   Object?: React.FC; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| export const Select: ComposedSelect = connect( |  | ||||||
|   (props) => { |   (props) => { | ||||||
|     const { options = [], ...others } = props; |     const { options = [], ...others } = props; | ||||||
|     return <AntdSelect {...others}> |     return ( | ||||||
|  |       <AntdSelect {...others}> | ||||||
|         {options.map((option: any, key: any) => { |         {options.map((option: any, key: any) => { | ||||||
|           if (option.children) { |           if (option.children) { | ||||||
|             return ( |             return ( | ||||||
|               <AntdSelect.OptGroup key={key} label={option.label}> |               <AntdSelect.OptGroup key={key} label={option.label}> | ||||||
|                 {option.children.map((child: any, childKey: any) => ( |                 {option.children.map((child: any, childKey: any) => ( | ||||||
|                 <AntdSelect.Option key={`${key}-${childKey}`} {...child}>{child.label}</AntdSelect.Option> |                   <AntdSelect.Option key={`${key}-${childKey}`} {...child}> | ||||||
|  |                     {child.label} | ||||||
|  |                   </AntdSelect.Option> | ||||||
|                 ))} |                 ))} | ||||||
|               </AntdSelect.OptGroup> |               </AntdSelect.OptGroup> | ||||||
|           ) |             ); | ||||||
|           } else { |           } else { | ||||||
|           return <AntdSelect.Option key={key} {...option}>{option.label}</AntdSelect.Option> |             return ( | ||||||
|  |               <AntdSelect.Option key={key} {...option}> | ||||||
|  |                 {option.label} | ||||||
|  |               </AntdSelect.Option> | ||||||
|  |             ); | ||||||
|           } |           } | ||||||
|         })} |         })} | ||||||
|       </AntdSelect> |       </AntdSelect> | ||||||
|  |     ); | ||||||
|   }, |   }, | ||||||
|   mapProps( |   mapProps( | ||||||
|     { |     { | ||||||
| @ -54,9 +66,8 @@ export const Select: ComposedSelect = connect( | |||||||
|   mapReadPretty((props) => { |   mapReadPretty((props) => { | ||||||
|     const field = useField<any>(); |     const field = useField<any>(); | ||||||
|     const dataSource = field.dataSource || []; |     const dataSource = field.dataSource || []; | ||||||
|     console.log('field.value', field.value, dataSource) |     console.log('field.value', field.value, dataSource); | ||||||
|     const value = Array.isArray(field.value) ? field.value : [field.value]; |     const values = toArr(field.value); | ||||||
|     const values = uniq(value); |  | ||||||
|     const findOptions = (options: any[]) => { |     const findOptions = (options: any[]) => { | ||||||
|       let current = []; |       let current = []; | ||||||
|       for (const option of options) { |       for (const option of options) { | ||||||
| @ -64,100 +75,96 @@ export const Select: ComposedSelect = connect( | |||||||
|           current.push(option); |           current.push(option); | ||||||
|         } |         } | ||||||
|         if (option.children) { |         if (option.children) { | ||||||
|           current = current.concat(findOptions(option.children)); |           const children = findOptions(option.children); | ||||||
|  |           current.push(...children); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       return current; |       return current; | ||||||
|     } |     }; | ||||||
|     const options = findOptions(dataSource); |     const options = findOptions(dataSource); | ||||||
|     return ( |     return ( | ||||||
|       <div> |       <div> | ||||||
|         {options |         {options.map((option, key) => ( | ||||||
|           .map((option, key) => ( |           <Tag key={key} color={option.color}> | ||||||
|             <Tag key={key} color={option.color}>{option.label}</Tag> |             {option.label} | ||||||
|  |           </Tag> | ||||||
|         ))} |         ))} | ||||||
|       </div> |       </div> | ||||||
|     ); |     ); | ||||||
|   }), |   }), | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| function getFieldName(field: any) { |  | ||||||
|   if (typeof field === 'string') { |  | ||||||
|     return field; |  | ||||||
|   } |  | ||||||
|   if (typeof field === 'object') { |  | ||||||
|     return field.name; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Select.Object = connect( | Select.Object = connect( | ||||||
|   (props) => { |   (props) => { | ||||||
|     const field = useField(); |     const field = useField(); | ||||||
|     const { |     const { | ||||||
|       value, |       value, | ||||||
|       onChange, |       onChange, | ||||||
|       dataRequest, |       fieldNames = { | ||||||
|       labelField: lf, |         label: 'label', | ||||||
|       valueField: vf, |         value: 'value', | ||||||
|  |       }, | ||||||
|       ...others |       ...others | ||||||
|     } = props; |     } = props; | ||||||
|     const options = field?.['dataSource'] || props.options || []; |     const options = field?.['dataSource'] || props.options || []; | ||||||
|     console.log({options}); |     let optionValue = undefined; | ||||||
|     const labelField = getFieldName(lf); |     if (isArr(value)) { | ||||||
|     const valueField = getFieldName(vf); |       optionValue = value.map((val) => { | ||||||
|     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) => { |  | ||||||
|         return { |         return { | ||||||
|           value: item[valueField], |           label: val[fieldNames.label], | ||||||
|           label: item[labelField], |           value: val[fieldNames.value], | ||||||
|         }; |         }; | ||||||
|       }); |       }); | ||||||
|       if (props.mode === 'multiple' || props.mode === 'tags') { |     } else if (value) { | ||||||
|         return values; |       optionValue = { | ||||||
|       } |         label: value[fieldNames.label], | ||||||
|       return values.length ? values[0] : null; |         value: value[fieldNames.value], | ||||||
|       }; |       }; | ||||||
|     const getOptions = () => { |  | ||||||
|       return data.map(item => { |  | ||||||
|         return { |  | ||||||
|           value: item[valueField], |  | ||||||
|           label: item[labelField], |  | ||||||
|         }; |  | ||||||
|       }) |  | ||||||
|     } |     } | ||||||
|     return ( |     return ( | ||||||
|       <AntdSelect |       <AntdSelect | ||||||
|  |         allowClear | ||||||
|  |         labelInValue | ||||||
|         {...others} |         {...others} | ||||||
|         loading={loading} |         value={optionValue} | ||||||
|         onChange={(option: any) => { |         onChange={(selectValue: any) => { | ||||||
|           if (!isValid(option)) { |           if (!selectValue) { | ||||||
|             onChange(null); |             onChange(null); | ||||||
|           } |           } | ||||||
|           if (isArr(option)) { |           if (isArr(selectValue)) { | ||||||
|             const optionValues = option.map(item => item.value); |             const selectValues = selectValue.map((s) => s.value); | ||||||
|             const selectValue = data.filter( |             const values = {}; | ||||||
|               (item) => optionValues.includes(item[valueField]), |             if (isArr(value)) { | ||||||
|             ); |               value.forEach((option) => { | ||||||
|             onChange(selectValue); |                 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 { |           } else { | ||||||
|             const selectValue = data.find( |             // 这里不能用 undefined,需要用 null
 | ||||||
|               (item) => item[valueField] === option.value, |             onChange( | ||||||
|  |               options.find( | ||||||
|  |                 (option) => option[fieldNames.value] === selectValue.value, | ||||||
|  |               ), | ||||||
|             ); |             ); | ||||||
|             onChange(selectValue); |  | ||||||
|           } |           } | ||||||
|         }} |         }} | ||||||
|         labelInValue |         options={options.map((option) => { | ||||||
|         value={getOptionValue()} |           return { | ||||||
|         options={getOptions()} |             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; | export default Select; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user