From 15d067120db25ec5d624300fc893ee33a76d5b05 Mon Sep 17 00:00:00 2001 From: Dunqing Date: Mon, 27 Feb 2023 18:52:03 +0800 Subject: [PATCH] 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 --- .../block-provider/SharedFilterProvider.tsx | 6 ++- .../association-select/useServiceOptions.ts | 46 ++++++++--------- .../antd/remote-select/RemoteSelect.tsx | 49 +++++++++++-------- 3 files changed, 56 insertions(+), 45 deletions(-) diff --git a/packages/core/client/src/block-provider/SharedFilterProvider.tsx b/packages/core/client/src/block-provider/SharedFilterProvider.tsx index 1d3999824..6db854324 100644 --- a/packages/core/client/src/block-provider/SharedFilterProvider.tsx +++ b/packages/core/client/src/block-provider/SharedFilterProvider.tsx @@ -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 {}; } diff --git a/packages/core/client/src/schema-component/antd/association-select/useServiceOptions.ts b/packages/core/client/src/schema-component/antd/association-select/useServiceOptions.ts index 80755ee0a..1bf787da8 100644 --- a/packages/core/client/src/schema-component/antd/association-select/useServiceOptions.ts +++ b/packages/core/client/src/schema-component/antd/association-select/useServiceOptions.ts @@ -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(() => { diff --git a/packages/core/client/src/schema-component/antd/remote-select/RemoteSelect.tsx b/packages/core/client/src/schema-component/antd/remote-select/RemoteSelect.tsx index 979527f0d..1a7e2a996 100644 --- a/packages/core/client/src/schema-component/antd/remote-select/RemoteSelect.tsx +++ b/packages/core/client/src/schema-component/antd/remote-select/RemoteSelect.tsx @@ -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) {