feat: improve filter component
This commit is contained in:
parent
53900c1e9e
commit
20680d3bc7
@ -1,5 +1,6 @@
|
||||
import { createForm, onFieldValueChange } from '@formily/core';
|
||||
import { FieldContext, FormContext } from '@formily/react';
|
||||
import { merge } from '@formily/shared';
|
||||
import React, { useContext, useMemo } from 'react';
|
||||
import { SchemaComponent } from '../../core';
|
||||
import { useComponent } from '../../hooks';
|
||||
@ -27,6 +28,11 @@ export const DynamicComponent = (props) => {
|
||||
schema={{
|
||||
'x-component': 'Input',
|
||||
...props.schema,
|
||||
'x-component-props': merge(props?.schema?.['x-component-props'] || {}, {
|
||||
style: {
|
||||
minWidth: 150,
|
||||
},
|
||||
}),
|
||||
name: 'value',
|
||||
'x-read-pretty': false,
|
||||
'x-validator': undefined,
|
||||
|
@ -1,16 +1,66 @@
|
||||
import { ISchema, useField, useFieldSchema } from '@formily/react';
|
||||
import React from 'react';
|
||||
import { useDesignable } from '../..';
|
||||
import { useCollection, useCollectionManager } from '../../../collection-manager';
|
||||
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
||||
|
||||
export const useFilterableFields = (collectionName: string) => {
|
||||
const { getCollectionFields, getInterface } = useCollectionManager();
|
||||
const fields = getCollectionFields(collectionName);
|
||||
return fields?.filter?.((field) => {
|
||||
if (!field.interface) {
|
||||
return false;
|
||||
}
|
||||
const fieldInterface = getInterface(field.interface);
|
||||
if (!fieldInterface.filterable) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
export const FilterActionDesigner = (props) => {
|
||||
const initialValue = {};
|
||||
const field = useField();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { dn } = useDesignable();
|
||||
const isPopupAction = ['create', 'update', 'view'].includes(fieldSchema['x-action'] || '');
|
||||
const { name } = useCollection();
|
||||
const fields = useFilterableFields(name);
|
||||
const fieldNames = fieldSchema?.['x-component-props']?.fieldNames || [];
|
||||
return (
|
||||
<GeneralSchemaDesigner {...props}>
|
||||
<SchemaSettings.ItemGroup title={'可筛选字段'}>
|
||||
{fields.map((field) => {
|
||||
const checked = fieldNames.includes(field.name);
|
||||
return (
|
||||
<SchemaSettings.SwitchItem
|
||||
checked={checked}
|
||||
title={field?.uiSchema?.title}
|
||||
onChange={(value) => {
|
||||
fieldSchema['x-component-props'] = fieldSchema?.['x-component-props'] || {};
|
||||
const fieldNames = fieldSchema?.['x-component-props']?.fieldNames || [];
|
||||
console.log('fieldNames.checked', value)
|
||||
if (value) {
|
||||
fieldNames.push(field.name);
|
||||
} else {
|
||||
const index = fieldNames.indexOf(field.name);
|
||||
fieldNames.splice(index, 1);
|
||||
}
|
||||
fieldSchema['x-component-props'].fieldNames = fieldNames;
|
||||
dn.emit('patch', {
|
||||
schema: {
|
||||
['x-uid']: fieldSchema['x-uid'],
|
||||
'x-component-props': {
|
||||
...fieldSchema['x-component-props'],
|
||||
},
|
||||
},
|
||||
});
|
||||
dn.refresh();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</SchemaSettings.ItemGroup>
|
||||
<SchemaSettings.Divider />
|
||||
<SchemaSettings.ModalItem
|
||||
title={'编辑'}
|
||||
schema={
|
||||
@ -57,27 +107,6 @@ export const FilterActionDesigner = (props) => {
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{isPopupAction && (
|
||||
<SchemaSettings.SelectItem
|
||||
title={'打开方式'}
|
||||
options={[
|
||||
{ label: '抽屉', value: 'drawer' },
|
||||
{ label: '对话框', value: 'modal' },
|
||||
]}
|
||||
value={field.componentProps.openMode}
|
||||
onChange={(value) => {
|
||||
field.componentProps.openMode = value;
|
||||
fieldSchema['x-component-props']['openMode'] = value;
|
||||
dn.emit('patch', {
|
||||
schema: {
|
||||
'x-uid': fieldSchema['x-uid'],
|
||||
'x-component-props': fieldSchema['x-component-props'],
|
||||
},
|
||||
});
|
||||
dn.refresh();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<SchemaSettings.Divider />
|
||||
<SchemaSettings.Remove
|
||||
removeParentsIfNoChildren
|
||||
|
@ -17,7 +17,7 @@ export const FilterAction = observer((props: any) => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const { designable, dn } = useDesignable();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const form = useMemo<Form>(() => props.form || createForm(), [visible]);
|
||||
const form = useMemo<Form>(() => props.form || createForm(), []);
|
||||
const { options, onSubmit, onReset, ...others } = useProps(props);
|
||||
return (
|
||||
<FilterActionContext.Provider value={{ field, fieldSchema, designable, dn }}>
|
||||
@ -58,7 +58,7 @@ export const FilterAction = observer((props: any) => {
|
||||
<Button
|
||||
onClick={async () => {
|
||||
await form.reset();
|
||||
onReset?.();
|
||||
onReset?.(form.values);
|
||||
field.title = t('Filter');
|
||||
setVisible(false);
|
||||
}}
|
||||
@ -72,9 +72,6 @@ export const FilterAction = observer((props: any) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
onSubmit?.(form.values);
|
||||
const items = form.values?.filter?.$and || form.values?.filter?.$or;
|
||||
console.log('form.values.filter', form.values, items);
|
||||
field.title = t('{{count}} filter items', { count: items?.length || 0 });
|
||||
setVisible(false);
|
||||
}}
|
||||
>
|
||||
|
@ -4,7 +4,7 @@ import { ArrayField, connect, useField } from '@formily/react';
|
||||
import { Select, Space } from 'antd';
|
||||
import React, { useContext } from 'react';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { RemoveConditionContext } from './context';
|
||||
import { FilterLogicContext, RemoveConditionContext } from './context';
|
||||
import { FilterItems } from './FilterItems';
|
||||
|
||||
export const FilterGroup = connect((props) => {
|
||||
@ -16,10 +16,12 @@ export const FilterGroup = connect((props) => {
|
||||
const setLogic = (value) => {
|
||||
const obj = field.value || {};
|
||||
field.value = {
|
||||
[value]: obj[logic] || [],
|
||||
[value]: [...(obj[logic] || [])],
|
||||
};
|
||||
};
|
||||
console.log('logic', logic);
|
||||
return (
|
||||
<FilterLogicContext.Provider value={logic}>
|
||||
<div
|
||||
style={{
|
||||
position: 'relative',
|
||||
@ -84,5 +86,6 @@ export const FilterGroup = connect((props) => {
|
||||
</a>
|
||||
</Space>
|
||||
</div>
|
||||
</FilterLogicContext.Provider>
|
||||
);
|
||||
});
|
||||
|
@ -11,3 +11,4 @@ export interface FilterContextProps {
|
||||
|
||||
export const RemoveConditionContext = createContext(null);
|
||||
export const FilterContext = createContext<FilterContextProps>(null);
|
||||
export const FilterLogicContext = createContext(null);
|
@ -1,10 +1,19 @@
|
||||
import { Field } from '@formily/core';
|
||||
import { useField, useFieldSchema } from '@formily/react';
|
||||
import flat from 'flat';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useBlockRequestContext } from '../../../block-provider';
|
||||
import { useCollection, useCollectionManager } from '../../../collection-manager';
|
||||
|
||||
export const useFilterOptions = (collectionName: string) => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const fieldNames = fieldSchema?.['x-component-props']?.fieldNames || [];
|
||||
const { getCollectionFields, getInterface } = useCollectionManager();
|
||||
const fields = getCollectionFields(collectionName);
|
||||
const field2option = (field, nochildren) => {
|
||||
if (fieldNames.length && !nochildren && !fieldNames.includes(field.name)) {
|
||||
return;
|
||||
}
|
||||
if (!field.interface) {
|
||||
return;
|
||||
}
|
||||
@ -46,15 +55,45 @@ export const useFilterOptions = (collectionName: string) => {
|
||||
return getOptions(fields);
|
||||
};
|
||||
|
||||
const isEmpty = (obj) => {
|
||||
return obj && Object.keys(obj).length === 0 && Object.getPrototypeOf(obj) === Object.prototype;
|
||||
};
|
||||
|
||||
const removeNullCondition = (filter) => {
|
||||
const items = flat(filter);
|
||||
console.log('filter', items);
|
||||
const values = {};
|
||||
for (const key in items) {
|
||||
const value = items[key];
|
||||
if (value !== null && !isEmpty(value)) {
|
||||
values[key] = value;
|
||||
}
|
||||
}
|
||||
return flat.unflatten(values);
|
||||
};
|
||||
|
||||
export const useFilterActionProps = () => {
|
||||
const { name } = useCollection();
|
||||
const options = useFilterOptions(name);
|
||||
const { service } = useBlockRequestContext();
|
||||
const field = useField<Field>();
|
||||
const { t } = useTranslation();
|
||||
return {
|
||||
options,
|
||||
onSubmit({ filter }) {
|
||||
console.log('filter', filter)
|
||||
onSubmit(values) {
|
||||
const filter = removeNullCondition(values?.filter);
|
||||
service.run({ ...service.params?.[0], filter });
|
||||
const items = filter?.$and || filter?.$or;
|
||||
if (items?.length) {
|
||||
field.title = t('{{count}} filter items', { count: items?.length || 0 });
|
||||
} else {
|
||||
field.title = t('Filter');
|
||||
}
|
||||
},
|
||||
onReset(values) {
|
||||
const filter = removeNullCondition(values?.filter);
|
||||
service.run({ ...service.params?.[0], filter });
|
||||
field.title = t('Filter');
|
||||
},
|
||||
};
|
||||
};
|
||||
|
@ -3,7 +3,7 @@ import { merge } from '@formily/shared';
|
||||
import flat from 'flat';
|
||||
import get from 'lodash/get';
|
||||
import { useContext, useEffect } from 'react';
|
||||
import { FilterContext } from './context';
|
||||
import { FilterContext, FilterLogicContext } from './context';
|
||||
|
||||
// import { useValues } from './useValues';
|
||||
const findOption = (dataIndex = [], options) => {
|
||||
@ -21,6 +21,7 @@ const findOption = (dataIndex = [], options) => {
|
||||
|
||||
export const useValues = () => {
|
||||
const field = useField<any>();
|
||||
const logic = useContext(FilterLogicContext);
|
||||
const { options } = useContext(FilterContext);
|
||||
const data2value = () => {
|
||||
field.value = flat.unflatten({
|
||||
@ -55,7 +56,7 @@ export const useValues = () => {
|
||||
};
|
||||
useEffect(() => {
|
||||
value2data();
|
||||
}, []);
|
||||
}, [logic]);
|
||||
return {
|
||||
fields: options,
|
||||
...field.data,
|
||||
@ -75,7 +76,7 @@ export const useValues = () => {
|
||||
const operator = field.data?.operators?.find?.((item) => item.value === operatorValue);
|
||||
field.data.operator = operator;
|
||||
field.data.schema = merge(field.data.schema, operator.schema);
|
||||
field.data.value = null;
|
||||
field.data.value = operator.noValue ? true : null;
|
||||
data2value();
|
||||
console.log('setOperator', field.data);
|
||||
},
|
||||
|
@ -200,6 +200,10 @@ SchemaSettings.Item = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
SchemaSettings.ItemGroup = (props) => {
|
||||
return <Menu.ItemGroup {...props} />;
|
||||
};
|
||||
|
||||
SchemaSettings.SubMenu = (props) => {
|
||||
return <Menu.SubMenu {...props} />;
|
||||
};
|
||||
@ -245,7 +249,13 @@ SchemaSettings.SelectItem = (props) => {
|
||||
<SchemaSettings.Item {...others}>
|
||||
<div style={{ alignItems: 'center', display: 'flex', justifyContent: 'space-between' }}>
|
||||
{title}
|
||||
<Select bordered={false} defaultValue={value} onChange={onChange} options={options} style={{ textAlign: 'right', minWidth: 100 }} />
|
||||
<Select
|
||||
bordered={false}
|
||||
defaultValue={value}
|
||||
onChange={onChange}
|
||||
options={options}
|
||||
style={{ textAlign: 'right', minWidth: 100 }}
|
||||
/>
|
||||
</div>
|
||||
</SchemaSettings.Item>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user