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:
Dunqing 2023-02-27 18:52:03 +08:00 committed by GitHub
parent ecf618783e
commit 15d067120d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 45 deletions

View File

@ -18,7 +18,11 @@ export type SharedFilterContextValue = {
}; };
export const mergeFilter = (filters: any[], op = '$and') => { 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) { if (items.length === 0) {
return {}; return {};
} }

View File

@ -1,5 +1,7 @@
import { useFieldSchema } from '@formily/react'; import { useFieldSchema } from '@formily/react';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { useFormBlockContext } from '../../../block-provider';
import { mergeFilter } from '../../../block-provider/SharedFilterProvider';
import { useCollection, useCollectionManager } from '../../../collection-manager'; import { useCollection, useCollectionManager } from '../../../collection-manager';
import { useRecord } from '../../../record-provider'; import { useRecord } from '../../../record-provider';
@ -10,7 +12,6 @@ export default function useServiceOptions(props) {
const { getField } = useCollection(); const { getField } = useCollection();
const { getCollectionFields } = useCollectionManager(); const { getCollectionFields } = useCollectionManager();
const record = useRecord(); const record = useRecord();
const recordValue = record[fieldSchema.name];
const normalizeValues = useCallback( const normalizeValues = useCallback(
(obj) => { (obj) => {
@ -23,15 +24,15 @@ export default function useServiceOptions(props) {
); );
const value = useMemo(() => { const value = useMemo(() => {
if (recordValue === undefined || recordValue === null) { if (props.value === undefined || props.value === null) {
return; return;
} }
if (Array.isArray(recordValue)) { if (Array.isArray(props.value)) {
return recordValue.map(normalizeValues); return props.value.map(normalizeValues);
} else { } else {
return normalizeValues(recordValue); return [normalizeValues(props.value)];
} }
}, [recordValue, normalizeValues]); }, [props.value, normalizeValues]);
const collectionField = useMemo(() => { const collectionField = useMemo(() => {
return getField(fieldSchema.name); return getField(fieldSchema.name);
@ -40,20 +41,18 @@ export default function useServiceOptions(props) {
const sourceValue = record?.[collectionField?.sourceKey]; const sourceValue = record?.[collectionField?.sourceKey];
const filter = useMemo(() => { const filter = useMemo(() => {
const isOToAny = ['oho', 'o2m'].includes(collectionField?.interface); const isOToAny = ['oho', 'o2m'].includes(collectionField?.interface);
return { return mergeFilter(
$or: [ [
{ mergeFilter([
$and: [ isOToAny
isOToAny ? {
? { [collectionField.foreignKey]: {
[collectionField.foreignKey]: { $is: null,
$is: null, },
}, }
} : null,
: null, params?.filter,
params?.filter, ]),
],
},
isOToAny && sourceValue !== undefined && sourceValue !== null isOToAny && sourceValue !== undefined && sourceValue !== null
? { ? {
[collectionField.foreignKey]: { [collectionField.foreignKey]: {
@ -61,15 +60,16 @@ export default function useServiceOptions(props) {
}, },
} }
: null, : null,
value params?.filter && value
? { ? {
[fieldNames.value]: { [fieldNames.value]: {
[Array.isArray(value) ? '$in' : '$eq']: value, ['$in']: value,
}, },
} }
: null, : null,
], ],
}; '$or',
);
}, [params?.filter, getCollectionFields, collectionField, sourceValue, value, fieldNames.value]); }, [params?.filter, getCollectionFields, collectionField, sourceValue, value, fieldNames.value]);
return useMemo(() => { return useMemo(() => {

View File

@ -1,8 +1,10 @@
import { LoadingOutlined } from '@ant-design/icons'; import { LoadingOutlined } from '@ant-design/icons';
import { connect, mapProps, mapReadPretty } from '@formily/react'; import { connect, mapProps, mapReadPretty } from '@formily/react';
import { SelectProps } from 'antd'; import { SelectProps } from 'antd';
import Item from 'antd/lib/list/Item';
import React, { useCallback, useEffect, useMemo, useRef } from 'react'; import React, { useCallback, useEffect, useMemo, useRef } from 'react';
import { ResourceActionOptions, useRequest } from '../../../api-client'; import { ResourceActionOptions, useRequest } from '../../../api-client';
import { mergeFilter } from '../../../block-provider/SharedFilterProvider';
import { useCompile } from '../../hooks'; import { useCompile } from '../../hooks';
import { defaultFieldNames, Select } from '../select'; import { defaultFieldNames, Select } from '../select';
import { ReadPretty } from './ReadPretty'; import { ReadPretty } from './ReadPretty';
@ -30,9 +32,7 @@ const InternalRemoteSelect = connect(
...service?.params, ...service?.params,
// fields: [fieldNames.label, fieldNames.value, ...(service?.params?.fields || [])], // fields: [fieldNames.label, fieldNames.value, ...(service?.params?.fields || [])],
// search needs // search needs
filter: { filter: mergeFilter([service?.params?.filter]),
$and: [service?.params?.filter].filter(Boolean),
},
}, },
}, },
{ {
@ -59,27 +59,39 @@ const InternalRemoteSelect = connect(
const onSearch = async (search) => { const onSearch = async (search) => {
run({ run({
filter: { filter: mergeFilter([
$and: [ {
{ [fieldNames.label]: {
[fieldNames.label]: { $includes: search,
$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( const normalizeOptions = useCallback(
(obj) => { (obj) => {
if (objectValue || typeof obj === 'object') { if (objectValue || typeof obj === 'object') {
return { ...obj, [fieldNames.label]: compile(obj[fieldNames.label]) }; return getOptionsByFieldNames(obj);
} }
return { [fieldNames.value]: obj, [fieldNames.label]: obj }; return { [fieldNames.value]: obj, [fieldNames.label]: obj };
}, },
[objectValue, fieldNames.value], [objectValue, getOptionsByFieldNames],
); );
const options = useMemo(() => { const options = useMemo(() => {
@ -90,13 +102,8 @@ const InternalRemoteSelect = connect(
: [normalizeOptions(value)] : [normalizeOptions(value)]
: []; : [];
} }
return ( return data?.data?.map(getOptionsByFieldNames) || [];
data?.data?.map((item) => ({ }, [data?.data, getOptionsByFieldNames, normalizeOptions, value]);
...item,
[fieldNames.label]: compile(item[fieldNames.label]),
})) || []
);
}, [data, fieldNames.label, objectValue, value]);
const onDropdownVisibleChange = () => { const onDropdownVisibleChange = () => {
if (firstRun.current) { if (firstRun.current) {