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') => {
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 {};
}

View File

@ -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(() => {

View File

@ -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) {