feat: filter component finish
This commit is contained in:
parent
6f2069e918
commit
968a7ec80f
@ -16,6 +16,7 @@ export const useCollectionField = () => {
|
||||
}
|
||||
const resourceName = `${ctx?.collectionName || collection?.name}.${ctx.name}`;
|
||||
const resource = api?.resource(resourceName, record[ctx.sourceKey]);
|
||||
debugger;
|
||||
return {
|
||||
...ctx,
|
||||
uiSchema: compile(ctx.uiSchema),
|
||||
|
@ -1,14 +1,12 @@
|
||||
import { FormButtonGroup, Submit } from '@formily/antd';
|
||||
import { createForm } from '@formily/core';
|
||||
import { FormProvider, observer, useFieldSchema } from '@formily/react';
|
||||
import { Button, Popover } from 'antd';
|
||||
import { observer, useFieldSchema } from '@formily/react';
|
||||
import flatten from 'flat';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { SchemaComponent } from '../../core';
|
||||
import { useDesignable } from '../../hooks';
|
||||
import { useCompile } from '../../hooks/useCompile';
|
||||
import { IconPicker } from '../icon-picker';
|
||||
import { FilterContext } from '../filter/context';
|
||||
|
||||
export const Filter = observer((props: any) => {
|
||||
const { t } = useTranslation();
|
||||
@ -25,45 +23,19 @@ export const Filter = observer((props: any) => {
|
||||
properties[p.name] = p;
|
||||
});
|
||||
return (
|
||||
<Popover
|
||||
trigger={['click']}
|
||||
placement={'bottomLeft'}
|
||||
visible={visible}
|
||||
onVisibleChange={setVisible}
|
||||
content={
|
||||
<div>
|
||||
<FormProvider form={form}>
|
||||
<SchemaComponent
|
||||
schema={{
|
||||
type: 'object',
|
||||
properties: {
|
||||
filter: {
|
||||
type: 'object',
|
||||
'x-component': 'Filter',
|
||||
properties,
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<FormButtonGroup align={'right'}>
|
||||
<Submit
|
||||
onSubmit={() => {
|
||||
const { filter } = form.values;
|
||||
console.log('Table.Filter', form.values);
|
||||
setVisible(false);
|
||||
}}
|
||||
>
|
||||
{t('Submit')}
|
||||
</Submit>
|
||||
</FormButtonGroup>
|
||||
</FormProvider>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Button icon={<IconPicker type={icon} />}>
|
||||
{count > 0 ? t('{{count}} filter items', { count }) : compile(filedSchema.title)}
|
||||
<DesignableBar />
|
||||
</Button>
|
||||
</Popover>
|
||||
<FilterContext.Provider value={{ visible, setVisible }}>
|
||||
<SchemaComponent
|
||||
schema={{
|
||||
type: 'void',
|
||||
properties: {
|
||||
filter: {
|
||||
type: 'object',
|
||||
title: t('Filter'),
|
||||
'x-component': 'Filter.Action',
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</FilterContext.Provider>
|
||||
);
|
||||
});
|
||||
|
@ -7,6 +7,7 @@ import { uid } from '@formily/shared';
|
||||
import {
|
||||
AntdSchemaComponentProvider,
|
||||
CollectionField,
|
||||
CollectionManagerProvider,
|
||||
CollectionProvider,
|
||||
SchemaComponent,
|
||||
SchemaComponentProvider,
|
||||
@ -56,6 +57,13 @@ const schema = {
|
||||
'x-action': 'calendar:viewSelect',
|
||||
'x-align': 'right',
|
||||
},
|
||||
filter: {
|
||||
type: 'void',
|
||||
title: '过滤',
|
||||
'x-align': 'right',
|
||||
'x-component': 'Calendar.Filter',
|
||||
'x-action': 'calendar:filter',
|
||||
},
|
||||
},
|
||||
},
|
||||
event: {
|
||||
@ -98,9 +106,9 @@ const collection = {
|
||||
type: 'string',
|
||||
name: 'id',
|
||||
interface: 'input',
|
||||
title: 'id',
|
||||
uiSchema: {
|
||||
type: 'string',
|
||||
title: 'id',
|
||||
'x-component': 'Input',
|
||||
},
|
||||
},
|
||||
@ -108,9 +116,9 @@ const collection = {
|
||||
type: 'string',
|
||||
name: 'title',
|
||||
interface: 'input',
|
||||
title: '标题',
|
||||
uiSchema: {
|
||||
type: 'string',
|
||||
title: '标题',
|
||||
'x-component': 'Input',
|
||||
},
|
||||
},
|
||||
@ -118,9 +126,9 @@ const collection = {
|
||||
type: 'string',
|
||||
name: 'start',
|
||||
interface: 'datetime',
|
||||
title: '开始时间',
|
||||
uiSchema: {
|
||||
type: 'string',
|
||||
title: '开始时间',
|
||||
'x-component': 'DatePicker',
|
||||
'x-component-props': {
|
||||
dateFormat: 'YYYY-MM-DD',
|
||||
@ -131,9 +139,9 @@ const collection = {
|
||||
type: 'string',
|
||||
name: 'end',
|
||||
interface: 'datetime',
|
||||
title: '结束时间',
|
||||
uiSchema: {
|
||||
type: 'string',
|
||||
title: '结束时间',
|
||||
'x-component': 'DatePicker',
|
||||
'x-component-props': {
|
||||
dateFormat: 'YYYY-MM-DD',
|
||||
@ -144,14 +152,16 @@ const collection = {
|
||||
};
|
||||
export default () => {
|
||||
return (
|
||||
<CollectionProvider collection={collection}>
|
||||
<SchemaComponentProvider designable={true} components={{ CollectionField }}>
|
||||
<SchemaInitializerProvider>
|
||||
<AntdSchemaComponentProvider>
|
||||
<SchemaComponent schema={schema} />
|
||||
</AntdSchemaComponentProvider>
|
||||
</SchemaInitializerProvider>
|
||||
</SchemaComponentProvider>
|
||||
</CollectionProvider>
|
||||
<CollectionManagerProvider>
|
||||
<CollectionProvider collection={collection}>
|
||||
<SchemaComponentProvider designable={true} components={{ CollectionField }}>
|
||||
<SchemaInitializerProvider>
|
||||
<AntdSchemaComponentProvider>
|
||||
<SchemaComponent schema={schema} />
|
||||
</AntdSchemaComponentProvider>
|
||||
</SchemaInitializerProvider>
|
||||
</SchemaComponentProvider>
|
||||
</CollectionProvider>
|
||||
</CollectionManagerProvider>
|
||||
);
|
||||
};
|
||||
|
@ -2,33 +2,33 @@ import { get } from 'lodash';
|
||||
import { i18n } from '../../../i18n';
|
||||
|
||||
export const fieldsToFilterColumns = (fields: any[], options: any = {}) => {
|
||||
// const { fieldNames = [] } = options;
|
||||
// const properties = {};
|
||||
// fields.forEach((field, index) => {
|
||||
// if (fieldNames?.length && !fieldNames.includes(field.name)) {
|
||||
// return;
|
||||
// }
|
||||
// const fieldOption = interfaces.get(field.interface);
|
||||
// if (!fieldOption?.operations) {
|
||||
// return;
|
||||
// }
|
||||
// properties[`column${index}`] = {
|
||||
// type: 'void',
|
||||
// title: field?.uiSchema?.title,
|
||||
// 'x-component': 'Filter.Column',
|
||||
// 'x-component-props': {
|
||||
// operations: fieldOption.operations,
|
||||
// const { fieldNames = [] } = options;
|
||||
// const properties = {};
|
||||
// fields.forEach((field, index) => {
|
||||
// if (fieldNames?.length && !fieldNames.includes(field.name)) {
|
||||
// return;
|
||||
// }
|
||||
// const fieldOption = interfaces.get(field.interface);
|
||||
// if (!fieldOption?.operations) {
|
||||
// return;
|
||||
// }
|
||||
// properties[`column${index}`] = {
|
||||
// type: 'void',
|
||||
// title: field?.uiSchema?.title,
|
||||
// 'x-component': 'Filter.Column',
|
||||
// 'x-component-props': {
|
||||
// operations: fieldOption.operations,
|
||||
// },
|
||||
// properties: {
|
||||
// [field.name]: {
|
||||
// ...field.uiSchema,
|
||||
// 'x-decorator': 'FormilyFormItem',
|
||||
// title: null,
|
||||
// },
|
||||
// properties: {
|
||||
// [field.name]: {
|
||||
// ...field.uiSchema,
|
||||
// 'x-decorator': 'FormilyFormItem',
|
||||
// title: null,
|
||||
// },
|
||||
// },
|
||||
// };
|
||||
// });
|
||||
// return properties;
|
||||
// },
|
||||
// };
|
||||
// });
|
||||
// return properties;
|
||||
};
|
||||
|
||||
export const toEvents = (data: any[], fieldNames: any) => {
|
||||
|
@ -0,0 +1,86 @@
|
||||
import { FilterOutlined } from '@ant-design/icons';
|
||||
import { FormButtonGroup, Submit } from '@formily/antd';
|
||||
import { createForm } from '@formily/core';
|
||||
import { FieldContext, FormContext, observer, useFieldSchema } from '@formily/react';
|
||||
import { uid } from '@formily/shared';
|
||||
import { Button, Popover } from 'antd';
|
||||
import flatten from 'flat';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useCollection, useCollectionManager } from '../../../collection-manager';
|
||||
import { SchemaComponent } from '../../core';
|
||||
import { useDesignable } from '../../hooks';
|
||||
import { useCompile } from '../../hooks/useCompile';
|
||||
import { useFilterContext } from './hooks';
|
||||
|
||||
export const FilterAction = observer((props: any) => {
|
||||
const { t } = useTranslation();
|
||||
const compile = useCompile();
|
||||
const { DesignableBar } = useDesignable();
|
||||
const filedSchema = useFieldSchema();
|
||||
const form = useMemo(() => createForm(), []);
|
||||
const { visible, setVisible } = useFilterContext();
|
||||
const obj = flatten(form.values.filter || {});
|
||||
const count = Object.values(obj).filter((i) => (Array.isArray(i) ? i.length : i)).length;
|
||||
const { fields } = useCollection();
|
||||
const { getInterface } = useCollectionManager();
|
||||
const properties = {};
|
||||
fields?.forEach((field) => {
|
||||
const { operators } = getInterface(field.interface);
|
||||
properties[uid()] = {
|
||||
type: 'void',
|
||||
title: field?.uiSchema?.title ?? field.title,
|
||||
'x-component': 'Filter.Column',
|
||||
'x-component-props': {
|
||||
operations: [...operators],
|
||||
},
|
||||
properties: {
|
||||
[field.name ?? uid()]: { ...field?.uiSchema },
|
||||
},
|
||||
};
|
||||
});
|
||||
const schema = {
|
||||
type: 'void',
|
||||
properties: {
|
||||
filter: {
|
||||
type: 'array',
|
||||
'x-component': 'Filter',
|
||||
properties,
|
||||
},
|
||||
},
|
||||
};
|
||||
return (
|
||||
<Popover
|
||||
trigger={['click']}
|
||||
placement={'bottomLeft'}
|
||||
visible={visible}
|
||||
onVisibleChange={setVisible}
|
||||
content={
|
||||
<div>
|
||||
<FieldContext.Provider value={null}>
|
||||
<FormContext.Provider value={form}>
|
||||
<SchemaComponent schema={schema} name="filter" />
|
||||
<FormButtonGroup align={'right'}>
|
||||
<Submit
|
||||
onSubmit={() => {
|
||||
const { filter } = form.values;
|
||||
console.log('Table.Filter====', form.values);
|
||||
debugger;
|
||||
setVisible(false);
|
||||
}}
|
||||
>
|
||||
{t('Submit')}
|
||||
</Submit>
|
||||
</FormButtonGroup>
|
||||
</FormContext.Provider>
|
||||
</FieldContext.Provider>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Button icon={<FilterOutlined />}>
|
||||
{count > 0 ? t('{{count}} filter items', { count }) : compile(filedSchema.title)}
|
||||
<DesignableBar />
|
||||
</Button>
|
||||
</Popover>
|
||||
);
|
||||
});
|
@ -0,0 +1,61 @@
|
||||
import { createForm, onFieldValueChange } from '@formily/core';
|
||||
import type { ISchema, Schema } from '@formily/react';
|
||||
import { connect } from '@formily/react';
|
||||
import deepmerge from 'deepmerge';
|
||||
import React, { useMemo } from 'react';
|
||||
import { SchemaComponent } from '../../core';
|
||||
|
||||
interface DynamicValueProps {
|
||||
value?: any;
|
||||
onChange?: any;
|
||||
schema?: Schema;
|
||||
operation?: any;
|
||||
}
|
||||
|
||||
export const FilterDynamicValue = connect((props: DynamicValueProps) => {
|
||||
const { onChange, value, operation } = props;
|
||||
const fieldName = Object.keys(props?.schema?.properties || {}).shift() ?? 'value';
|
||||
const fieldSchema = Object.values(props?.schema?.properties || {}).shift();
|
||||
const form = useMemo(
|
||||
() =>
|
||||
createForm({
|
||||
initialValues: {
|
||||
[fieldName]: value,
|
||||
},
|
||||
effects(form) {
|
||||
onFieldValueChange(fieldName, (field) => {
|
||||
onChange(field.value);
|
||||
});
|
||||
},
|
||||
}),
|
||||
[],
|
||||
);
|
||||
const extra: ISchema = deepmerge(
|
||||
{
|
||||
required: false,
|
||||
'x-read-pretty': false,
|
||||
name: fieldName,
|
||||
default: value,
|
||||
'x-decorator': 'FormilyFormItem',
|
||||
'x-decorator-props': {
|
||||
asterisk: true,
|
||||
feedbackLayout: 'none',
|
||||
},
|
||||
'x-component-props': {
|
||||
style: {
|
||||
minWidth: '150px',
|
||||
},
|
||||
},
|
||||
},
|
||||
operation?.schema || {},
|
||||
);
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
[fieldName]: deepmerge(fieldSchema, extra, {
|
||||
arrayMerge: (target, source) => source,
|
||||
}) as any,
|
||||
},
|
||||
};
|
||||
return <SchemaComponent schema={schema} />;
|
||||
});
|
@ -1,14 +1,15 @@
|
||||
import { LoadingOutlined } from '@ant-design/icons';
|
||||
import { createForm, onFieldValueChange } from '@formily/core';
|
||||
import { connect, FieldContext, FormContext, ISchema, mapProps, mapReadPretty, Schema } from '@formily/react';
|
||||
import deepmerge from 'deepmerge';
|
||||
import React, { useMemo } from 'react';
|
||||
import { SchemaComponent } from '../../core';
|
||||
import { connect, mapProps, mapReadPretty } from '@formily/react';
|
||||
import React from 'react';
|
||||
import { FilterAction } from './Filter.Action';
|
||||
import { FilterDynamicValue } from './Filter.DynamicValue';
|
||||
import { FilterGroup } from './FilterGroup';
|
||||
import './style.less';
|
||||
|
||||
export const Filter: any = connect(
|
||||
(props) => <FilterGroup bordered={false} {...props} />,
|
||||
(props) => {
|
||||
return <FilterGroup bordered={false} {...props} />;
|
||||
},
|
||||
mapProps((props, field) => {
|
||||
return {
|
||||
...props,
|
||||
@ -20,65 +21,7 @@ export const Filter: any = connect(
|
||||
}),
|
||||
);
|
||||
|
||||
interface DynamicValueProps {
|
||||
value?: any;
|
||||
onChange?: any;
|
||||
schema?: Schema;
|
||||
operation?: any;
|
||||
}
|
||||
|
||||
Filter.DynamicValue = connect((props: DynamicValueProps) => {
|
||||
const { onChange, value, operation } = props;
|
||||
const fieldName = Object.keys(props?.schema?.properties || {}).shift() ?? 'value';
|
||||
const fieldSchema = Object.values(props?.schema?.properties || {}).shift();
|
||||
const form = useMemo(
|
||||
() =>
|
||||
createForm({
|
||||
initialValues: {
|
||||
[fieldName]: value,
|
||||
},
|
||||
effects(form) {
|
||||
onFieldValueChange(fieldName, (field) => {
|
||||
onChange(field.value);
|
||||
});
|
||||
},
|
||||
}),
|
||||
[],
|
||||
);
|
||||
const extra: ISchema = deepmerge(
|
||||
{
|
||||
required: false,
|
||||
'x-read-pretty': false,
|
||||
name: fieldName,
|
||||
default: value,
|
||||
'x-decorator': 'FormilyFormItem',
|
||||
'x-decorator-props': {
|
||||
asterisk: true,
|
||||
feedbackLayout: 'none',
|
||||
},
|
||||
'x-component-props': {
|
||||
style: {
|
||||
minWidth: '150px',
|
||||
},
|
||||
},
|
||||
},
|
||||
operation?.schema || {},
|
||||
);
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
[fieldName]: deepmerge(fieldSchema, extra, {
|
||||
arrayMerge: (target, source) => source,
|
||||
}) as any,
|
||||
},
|
||||
};
|
||||
return (
|
||||
<FieldContext.Provider value={null}>
|
||||
<FormContext.Provider value={form}>
|
||||
<SchemaComponent schema={schema} />
|
||||
</FormContext.Provider>
|
||||
</FieldContext.Provider>
|
||||
);
|
||||
});
|
||||
Filter.DynamicValue = FilterDynamicValue;
|
||||
Filter.Action = FilterAction;
|
||||
|
||||
export default Filter;
|
||||
|
@ -0,0 +1,8 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
export const FilterContext = createContext<FilterContextProps>({});
|
||||
|
||||
export interface FilterContextProps {
|
||||
visible?: boolean;
|
||||
setVisible?: (v: boolean) => void;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
import { useContext } from 'react';
|
||||
import { FilterContext } from './context';
|
||||
|
||||
export const useFilterContext = () => {
|
||||
const ctx = useContext(FilterContext);
|
||||
return {
|
||||
...ctx,
|
||||
};
|
||||
};
|
@ -65,6 +65,7 @@ export const IconPicker = connect(
|
||||
mapProps((props, field) => {
|
||||
return {
|
||||
...props,
|
||||
value: props.type,
|
||||
suffix: <span>{field?.['loading'] || field?.['validating'] ? <LoadingOutlined /> : props.suffix}</span>,
|
||||
};
|
||||
}),
|
||||
|
Loading…
Reference in New Issue
Block a user