fix(association-select): filter without data scope not work (#1509)
* fix(association-select): filter without data scope not work * fix: update * fix: use merge filter * refactor: better logic * fix: option has hidden * fix: hidden, disabled * fix: update * fix: merge filter doesn't handle array
This commit is contained in:
		
							parent
							
								
									ecf618783e
								
							
						
					
					
						commit
						15d067120d
					
				| @ -18,7 +18,11 @@ export type SharedFilterContextValue = { | ||||
| }; | ||||
| 
 | ||||
| export const mergeFilter = (filters: any[], op = '$and') => { | ||||
|   const items = filters.filter(Boolean); | ||||
|   const items = filters.filter((f) => { | ||||
|     if (f && typeof f === 'object' && !Array.isArray(f)) { | ||||
|       return Object.values(f).filter((v) => v !== undefined).length; | ||||
|     } | ||||
|   }); | ||||
|   if (items.length === 0) { | ||||
|     return {}; | ||||
|   } | ||||
|  | ||||
| @ -1,5 +1,7 @@ | ||||
| import { useFieldSchema } from '@formily/react'; | ||||
| import { useCallback, useMemo } from 'react'; | ||||
| import { useFormBlockContext } from '../../../block-provider'; | ||||
| import { mergeFilter } from '../../../block-provider/SharedFilterProvider'; | ||||
| import { useCollection, useCollectionManager } from '../../../collection-manager'; | ||||
| import { useRecord } from '../../../record-provider'; | ||||
| 
 | ||||
| @ -10,7 +12,6 @@ export default function useServiceOptions(props) { | ||||
|   const { getField } = useCollection(); | ||||
|   const { getCollectionFields } = useCollectionManager(); | ||||
|   const record = useRecord(); | ||||
|   const recordValue = record[fieldSchema.name]; | ||||
| 
 | ||||
|   const normalizeValues = useCallback( | ||||
|     (obj) => { | ||||
| @ -23,15 +24,15 @@ export default function useServiceOptions(props) { | ||||
|   ); | ||||
| 
 | ||||
|   const value = useMemo(() => { | ||||
|     if (recordValue === undefined || recordValue === null) { | ||||
|     if (props.value === undefined || props.value === null) { | ||||
|       return; | ||||
|     } | ||||
|     if (Array.isArray(recordValue)) { | ||||
|       return recordValue.map(normalizeValues); | ||||
|     if (Array.isArray(props.value)) { | ||||
|       return props.value.map(normalizeValues); | ||||
|     } else { | ||||
|       return normalizeValues(recordValue); | ||||
|       return [normalizeValues(props.value)]; | ||||
|     } | ||||
|   }, [recordValue, normalizeValues]); | ||||
|   }, [props.value, normalizeValues]); | ||||
| 
 | ||||
|   const collectionField = useMemo(() => { | ||||
|     return getField(fieldSchema.name); | ||||
| @ -40,20 +41,18 @@ export default function useServiceOptions(props) { | ||||
|   const sourceValue = record?.[collectionField?.sourceKey]; | ||||
|   const filter = useMemo(() => { | ||||
|     const isOToAny = ['oho', 'o2m'].includes(collectionField?.interface); | ||||
|     return { | ||||
|       $or: [ | ||||
|         { | ||||
|           $and: [ | ||||
|             isOToAny | ||||
|               ? { | ||||
|                   [collectionField.foreignKey]: { | ||||
|                     $is: null, | ||||
|                   }, | ||||
|                 } | ||||
|               : null, | ||||
|             params?.filter, | ||||
|           ], | ||||
|         }, | ||||
|     return mergeFilter( | ||||
|       [ | ||||
|         mergeFilter([ | ||||
|           isOToAny | ||||
|             ? { | ||||
|                 [collectionField.foreignKey]: { | ||||
|                   $is: null, | ||||
|                 }, | ||||
|               } | ||||
|             : null, | ||||
|           params?.filter, | ||||
|         ]), | ||||
|         isOToAny && sourceValue !== undefined && sourceValue !== null | ||||
|           ? { | ||||
|               [collectionField.foreignKey]: { | ||||
| @ -61,15 +60,16 @@ export default function useServiceOptions(props) { | ||||
|               }, | ||||
|             } | ||||
|           : null, | ||||
|         value | ||||
|         params?.filter && value | ||||
|           ? { | ||||
|               [fieldNames.value]: { | ||||
|                 [Array.isArray(value) ? '$in' : '$eq']: value, | ||||
|                 ['$in']: value, | ||||
|               }, | ||||
|             } | ||||
|           : null, | ||||
|       ], | ||||
|     }; | ||||
|       '$or', | ||||
|     ); | ||||
|   }, [params?.filter, getCollectionFields, collectionField, sourceValue, value, fieldNames.value]); | ||||
| 
 | ||||
|   return useMemo(() => { | ||||
|  | ||||
| @ -1,8 +1,10 @@ | ||||
| import { LoadingOutlined } from '@ant-design/icons'; | ||||
| import { connect, mapProps, mapReadPretty } from '@formily/react'; | ||||
| import { SelectProps } from 'antd'; | ||||
| import Item from 'antd/lib/list/Item'; | ||||
| import React, { useCallback, useEffect, useMemo, useRef } from 'react'; | ||||
| import { ResourceActionOptions, useRequest } from '../../../api-client'; | ||||
| import { mergeFilter } from '../../../block-provider/SharedFilterProvider'; | ||||
| import { useCompile } from '../../hooks'; | ||||
| import { defaultFieldNames, Select } from '../select'; | ||||
| import { ReadPretty } from './ReadPretty'; | ||||
| @ -30,9 +32,7 @@ const InternalRemoteSelect = connect( | ||||
|           ...service?.params, | ||||
|           // fields: [fieldNames.label, fieldNames.value, ...(service?.params?.fields || [])],
 | ||||
|           // search needs
 | ||||
|           filter: { | ||||
|             $and: [service?.params?.filter].filter(Boolean), | ||||
|           }, | ||||
|           filter: mergeFilter([service?.params?.filter]), | ||||
|         }, | ||||
|       }, | ||||
|       { | ||||
| @ -59,27 +59,39 @@ const InternalRemoteSelect = connect( | ||||
| 
 | ||||
|     const onSearch = async (search) => { | ||||
|       run({ | ||||
|         filter: { | ||||
|           $and: [ | ||||
|             { | ||||
|               [fieldNames.label]: { | ||||
|                 $includes: search, | ||||
|               }, | ||||
|         filter: mergeFilter([ | ||||
|           { | ||||
|             [fieldNames.label]: { | ||||
|               $includes: search, | ||||
|             }, | ||||
|             service?.params?.filter, | ||||
|           ].filter(Boolean), | ||||
|         }, | ||||
|           }, | ||||
|           service?.params?.filter, | ||||
|         ]), | ||||
|       }); | ||||
|     }; | ||||
| 
 | ||||
|     const getOptionsByFieldNames = useCallback( | ||||
|       (item) => { | ||||
|         return Object.keys(fieldNames).reduce((obj, key) => { | ||||
|           const value = item[fieldNames[key]]; | ||||
|           if (value) { | ||||
|             // support hidden, disabled, etc.
 | ||||
|             obj[['label', 'value', 'options'].includes(key) ? fieldNames[key] : key] = | ||||
|               key === 'label' ? compile(value) : value; | ||||
|           } | ||||
|           return obj; | ||||
|         }, {} as any); | ||||
|       }, | ||||
|       [fieldNames], | ||||
|     ); | ||||
|     const normalizeOptions = useCallback( | ||||
|       (obj) => { | ||||
|         if (objectValue || typeof obj === 'object') { | ||||
|           return { ...obj, [fieldNames.label]: compile(obj[fieldNames.label]) }; | ||||
|           return getOptionsByFieldNames(obj); | ||||
|         } | ||||
|         return { [fieldNames.value]: obj, [fieldNames.label]: obj }; | ||||
|       }, | ||||
|       [objectValue, fieldNames.value], | ||||
|       [objectValue, getOptionsByFieldNames], | ||||
|     ); | ||||
| 
 | ||||
|     const options = useMemo(() => { | ||||
| @ -90,13 +102,8 @@ const InternalRemoteSelect = connect( | ||||
|             : [normalizeOptions(value)] | ||||
|           : []; | ||||
|       } | ||||
|       return ( | ||||
|         data?.data?.map((item) => ({ | ||||
|           ...item, | ||||
|           [fieldNames.label]: compile(item[fieldNames.label]), | ||||
|         })) || [] | ||||
|       ); | ||||
|     }, [data, fieldNames.label, objectValue, value]); | ||||
|       return data?.data?.map(getOptionsByFieldNames) || []; | ||||
|     }, [data?.data, getOptionsByFieldNames, normalizeOptions, value]); | ||||
| 
 | ||||
|     const onDropdownVisibleChange = () => { | ||||
|       if (firstRun.current) { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user