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') => {
|
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 {};
|
||||||
}
|
}
|
||||||
|
@ -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,10 +41,9 @@ 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]: {
|
||||||
@ -52,8 +52,7 @@ export default function useServiceOptions(props) {
|
|||||||
}
|
}
|
||||||
: 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(() => {
|
||||||
|
@ -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,
|
service?.params?.filter,
|
||||||
].filter(Boolean),
|
]),
|
||||||
},
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user