feat: improve filter action
This commit is contained in:
parent
c776229540
commit
2dbbe29223
@ -28,8 +28,9 @@ class ApiClient {
|
|||||||
const proxy: any = new Proxy({}, {
|
const proxy: any = new Proxy({}, {
|
||||||
get(target, method, receiver) {
|
get(target, method, receiver) {
|
||||||
return (params: ActionParams = {}) => {
|
return (params: ActionParams = {}) => {
|
||||||
const { associatedKey, resourceKey, filter, ...restParams } = params;
|
let { associatedKey, resourceKey, filter, sorter, sort = [], ...restParams } = params;
|
||||||
let url = `/${name}`;
|
let url = `/${name}`;
|
||||||
|
sort = sort || [];
|
||||||
let options: any = {
|
let options: any = {
|
||||||
params: {},
|
params: {},
|
||||||
};
|
};
|
||||||
@ -51,6 +52,21 @@ class ApiClient {
|
|||||||
if (filter) {
|
if (filter) {
|
||||||
options.params['filter'] = JSON.stringify(filter);
|
options.params['filter'] = JSON.stringify(filter);
|
||||||
}
|
}
|
||||||
|
if (sorter) {
|
||||||
|
const arr = Array.isArray(sorter) ? sorter : [sorter];
|
||||||
|
arr.forEach(({order, field}) => {
|
||||||
|
if (order === 'descend') {
|
||||||
|
sort.push(`-${field}`);
|
||||||
|
} else if (order === 'ascend') {
|
||||||
|
sort.push(field);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (sort.length === 0) {
|
||||||
|
delete options.params['sort'];
|
||||||
|
} else {
|
||||||
|
options.params['sort'] = sort.join(',');
|
||||||
|
}
|
||||||
console.log({url, params});
|
console.log({url, params});
|
||||||
return request(url, options);
|
return request(url, options);
|
||||||
};
|
};
|
||||||
|
@ -42,6 +42,7 @@ export function Filter(props) {
|
|||||||
<div className={'popover-button-mask'} onClick={() => setVisible(false)}></div>
|
<div className={'popover-button-mask'} onClick={() => setVisible(false)}></div>
|
||||||
<ViewFactory
|
<ViewFactory
|
||||||
{...props}
|
{...props}
|
||||||
|
setVisible={setVisible}
|
||||||
viewName={'filter'}
|
viewName={'filter'}
|
||||||
{...params}
|
{...params}
|
||||||
/>
|
/>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Button, Select, Input, Space, Form, InputNumber, DatePicker } from 'antd';
|
import { Button, Select, Input, Space, Form, InputNumber, DatePicker } from 'antd';
|
||||||
import { ArrowUpOutlined, ArrowDownOutlined } from '@ant-design/icons';
|
import { PlusCircleOutlined, CloseCircleOutlined } from '@ant-design/icons';
|
||||||
import useDynamicList from './useDynamicList';
|
import useDynamicList from './useDynamicList';
|
||||||
import { connect } from '@formily/react-schema-renderer'
|
import { connect } from '@formily/react-schema-renderer'
|
||||||
import { mapStyledProps } from '../shared'
|
import { mapStyledProps } from '../shared'
|
||||||
@ -13,8 +13,19 @@ export function FilterGroup(props: any) {
|
|||||||
type: 'item',
|
type: 'item',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
let style: any = {
|
||||||
|
position: 'relative',
|
||||||
|
};
|
||||||
|
if (showDeleteButton) {
|
||||||
|
style = {
|
||||||
|
...style,
|
||||||
|
marginBottom: 14,
|
||||||
|
padding: 14,
|
||||||
|
border: '1px dashed #dedede',
|
||||||
|
}
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div style={{marginBottom: 14, padding: 14, border: '1px dashed #dedede'}}>
|
<div style={style}>
|
||||||
<div style={{marginBottom: 14}}>
|
<div style={{marginBottom: 14}}>
|
||||||
满足组内
|
满足组内
|
||||||
{' '}
|
{' '}
|
||||||
@ -32,7 +43,7 @@ export function FilterGroup(props: any) {
|
|||||||
// console.log(item);
|
// console.log(item);
|
||||||
const Component = item.type === 'group' ? FilterGroup : FilterItem;
|
const Component = item.type === 'group' ? FilterGroup : FilterItem;
|
||||||
return (
|
return (
|
||||||
<div style={{marginBottom: 14}}>
|
<div style={{marginBottom: 8}}>
|
||||||
{<Component
|
{<Component
|
||||||
fields={fields}
|
fields={fields}
|
||||||
dataSource={item}
|
dataSource={item}
|
||||||
@ -58,7 +69,7 @@ export function FilterGroup(props: any) {
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Space>
|
<Space>
|
||||||
<Button onClick={() => {
|
<Button style={{padding: 0}} type={'link'} onClick={() => {
|
||||||
const data = {
|
const data = {
|
||||||
type: 'item'
|
type: 'item'
|
||||||
};
|
};
|
||||||
@ -67,28 +78,33 @@ export function FilterGroup(props: any) {
|
|||||||
newList.push(data);
|
newList.push(data);
|
||||||
onChange({...dataSource, list: newList});
|
onChange({...dataSource, list: newList});
|
||||||
}}>
|
}}>
|
||||||
添加条件
|
<PlusCircleOutlined /> 添加条件
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={() => {
|
{' '}
|
||||||
const data = {
|
<Button
|
||||||
type: 'group',
|
style={{padding: 0}}
|
||||||
list: [
|
type={'link'}
|
||||||
{
|
onClick={() => {
|
||||||
type: 'item',
|
const data = {
|
||||||
},
|
type: 'group',
|
||||||
],
|
list: [
|
||||||
};
|
{
|
||||||
push(data);
|
type: 'item',
|
||||||
const newList = [...list];
|
},
|
||||||
newList.push(data);
|
],
|
||||||
onChange({...dataSource, list: newList});
|
};
|
||||||
}}>
|
push(data);
|
||||||
添加条件组
|
const newList = [...list];
|
||||||
|
newList.push(data);
|
||||||
|
onChange({...dataSource, list: newList});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PlusCircleOutlined /> 添加条件组
|
||||||
</Button>
|
</Button>
|
||||||
{showDeleteButton && <Button onClick={(e) => {
|
{showDeleteButton && <Button style={{padding: 0, position: 'absolute', top: 0, right: 0, width: 32}} type={'link'} onClick={(e) => {
|
||||||
onDelete && onDelete(e);
|
onDelete && onDelete(e);
|
||||||
}}>
|
}}>
|
||||||
删除组
|
<CloseCircleOutlined />
|
||||||
</Button>}
|
</Button>}
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
@ -169,7 +185,9 @@ const op = {
|
|||||||
string: OP_MAP.string,
|
string: OP_MAP.string,
|
||||||
textarea: OP_MAP.string,
|
textarea: OP_MAP.string,
|
||||||
number: OP_MAP.number,
|
number: OP_MAP.number,
|
||||||
|
percent: OP_MAP.number,
|
||||||
datetime: OP_MAP.datetime,
|
datetime: OP_MAP.datetime,
|
||||||
|
date: OP_MAP.datetime,
|
||||||
};
|
};
|
||||||
|
|
||||||
const StringInput = (props) => {
|
const StringInput = (props) => {
|
||||||
@ -186,7 +204,7 @@ const controls = {
|
|||||||
textarea: StringInput,
|
textarea: StringInput,
|
||||||
number: InputNumber,
|
number: InputNumber,
|
||||||
// datetime: DatePicker,
|
// datetime: DatePicker,
|
||||||
datetime: (props) => {
|
date: (props) => {
|
||||||
const { value, onChange, ...restProps } = props;
|
const { value, onChange, ...restProps } = props;
|
||||||
const m = moment(value, 'YYYY-MM-DD HH:mm:ss');
|
const m = moment(value, 'YYYY-MM-DD HH:mm:ss');
|
||||||
return (
|
return (
|
||||||
@ -204,14 +222,15 @@ export function FilterItem(props: FilterItemProps) {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const field = fields.find(field => field.name === dataSource.column);
|
const field = fields.find(field => field.name === dataSource.column);
|
||||||
if (field) {
|
if (field) {
|
||||||
setType(field.interface);
|
setType(field.component.type);
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
dataSource,
|
dataSource,
|
||||||
]);
|
]);
|
||||||
|
console.log({type});
|
||||||
const ValueControl = controls[type]||controls.string;
|
const ValueControl = controls[type]||controls.string;
|
||||||
return (
|
return (
|
||||||
<Input.Group compact>
|
<Space>
|
||||||
<Select value={dataSource.column}
|
<Select value={dataSource.column}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
const field = fields.find(field => field.name === value);
|
const field = fields.find(field => field.name === value);
|
||||||
@ -220,7 +239,8 @@ export function FilterItem(props: FilterItemProps) {
|
|||||||
}
|
}
|
||||||
onChange({...dataSource, column: value});
|
onChange({...dataSource, column: value});
|
||||||
}}
|
}}
|
||||||
style={{ width: '30%' }} placeholder={'选择字段'}>
|
style={{ width: 120 }}
|
||||||
|
placeholder={'选择字段'}>
|
||||||
{fields.map(field => (
|
{fields.map(field => (
|
||||||
<Select.Option value={field.name}>{field.title}</Select.Option>
|
<Select.Option value={field.name}>{field.title}</Select.Option>
|
||||||
))}
|
))}
|
||||||
@ -236,16 +256,33 @@ export function FilterItem(props: FilterItemProps) {
|
|||||||
</Select>
|
</Select>
|
||||||
<ValueControl value={dataSource.value} onChange={(value) => {
|
<ValueControl value={dataSource.value} onChange={(value) => {
|
||||||
onChange({...dataSource, value: value});
|
onChange({...dataSource, value: value});
|
||||||
}} style={{ width: '30%' }}/>
|
}}
|
||||||
|
style={{ width: 180 }}
|
||||||
|
/>
|
||||||
{showDeleteButton && (
|
{showDeleteButton && (
|
||||||
<Button onClick={(e) => {
|
<Button type={'link'} style={{padding: 0}} onClick={(e) => {
|
||||||
onDelete && onDelete(e);
|
onDelete && onDelete(e);
|
||||||
}}>删除</Button>
|
}}><CloseCircleOutlined /></Button>
|
||||||
)}
|
)}
|
||||||
</Input.Group>
|
</Space>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toFilter(values: any) {
|
||||||
|
let filter: any;
|
||||||
|
const { type, andor = 'and', list = [], column, op, value } = values;
|
||||||
|
if (type === 'group') {
|
||||||
|
filter = {
|
||||||
|
[andor]: list.map(value => toFilter(value)).filter(Boolean)
|
||||||
|
}
|
||||||
|
} else if (type === 'item' && column && op) {
|
||||||
|
filter = {
|
||||||
|
[`${column}`]: {[op]: value},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
export const Filter = connect({
|
export const Filter = connect({
|
||||||
getProps: mapStyledProps,
|
getProps: mapStyledProps,
|
||||||
})((props) => {
|
})((props) => {
|
||||||
@ -257,7 +294,10 @@ export const Filter = connect({
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
return <FilterGroup dataSource={dataSource} {...props}/>
|
const { value, onChange, ...restProps } = props;
|
||||||
|
return <FilterGroup dataSource={dataSource} onChange={(values) => {
|
||||||
|
onChange(toFilter(values));
|
||||||
|
}} {...restProps}/>
|
||||||
});
|
});
|
||||||
|
|
||||||
export default Filter;
|
export default Filter;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Tooltip, Card } from 'antd';
|
import { Tooltip, Button } from 'antd';
|
||||||
import {
|
import {
|
||||||
SchemaForm,
|
SchemaForm,
|
||||||
SchemaMarkupField as Field,
|
SchemaMarkupField as Field,
|
||||||
@ -15,7 +15,8 @@ import {
|
|||||||
import { QuestionCircleOutlined } from '@ant-design/icons';
|
import { QuestionCircleOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
export function FilterForm(props: any) {
|
export function FilterForm(props: any) {
|
||||||
const actions = createFormActions();
|
const actions = createAsyncFormActions();
|
||||||
|
const { setVisible, onTrigger } = props;
|
||||||
const { title, fields: properties ={} } = props.schema||{};
|
const { title, fields: properties ={} } = props.schema||{};
|
||||||
return (
|
return (
|
||||||
<SchemaForm
|
<SchemaForm
|
||||||
@ -23,6 +24,15 @@ export function FilterForm(props: any) {
|
|||||||
layout={'vertical'}
|
layout={'vertical'}
|
||||||
initialValues={{}}
|
initialValues={{}}
|
||||||
actions={actions}
|
actions={actions}
|
||||||
|
onReset={() => {
|
||||||
|
setVisible && setVisible(false);
|
||||||
|
}}
|
||||||
|
onSubmit={async (values) => {
|
||||||
|
if (onTrigger) {
|
||||||
|
await onTrigger(values);
|
||||||
|
}
|
||||||
|
setVisible && setVisible(false);
|
||||||
|
}}
|
||||||
schema={{
|
schema={{
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties,
|
properties,
|
||||||
@ -44,10 +54,7 @@ export function FilterForm(props: any) {
|
|||||||
>
|
>
|
||||||
<FormButtonGroup>
|
<FormButtonGroup>
|
||||||
<Reset>取消</Reset>
|
<Reset>取消</Reset>
|
||||||
<Submit onClick={async () => {
|
<Submit>确定</Submit>
|
||||||
const { values = {} } = await actions.submit();
|
|
||||||
console.log(values);
|
|
||||||
}}>确定</Submit>
|
|
||||||
</FormButtonGroup>
|
</FormButtonGroup>
|
||||||
</SchemaForm>
|
</SchemaForm>
|
||||||
);
|
);
|
||||||
|
@ -4,7 +4,6 @@ import { Actions } from '@/components/actions';
|
|||||||
import ViewFactory from '@/components/views';
|
import ViewFactory from '@/components/views';
|
||||||
import { useRequest } from 'umi';
|
import { useRequest } from 'umi';
|
||||||
import api from '@/api-client';
|
import api from '@/api-client';
|
||||||
import get from 'lodash/get';
|
|
||||||
import { components, fields2columns } from './SortableTable';
|
import { components, fields2columns } from './SortableTable';
|
||||||
|
|
||||||
export interface SimpleTableProps {
|
export interface SimpleTableProps {
|
||||||
@ -30,12 +29,13 @@ export function SimpleTable(props: SimpleTableProps) {
|
|||||||
const { sourceKey = 'id' } = activeTab.field||{};
|
const { sourceKey = 'id' } = activeTab.field||{};
|
||||||
const drawerRef = useRef<any>();
|
const drawerRef = useRef<any>();
|
||||||
const name = associatedName ? `${associatedName}.${resourceName}` : resourceName;
|
const name = associatedName ? `${associatedName}.${resourceName}` : resourceName;
|
||||||
const { data, loading, pagination, mutate, refresh } = useRequest((params = {}) => {
|
const { data, loading, pagination, mutate, refresh, params, run } = useRequest((params = {}) => {
|
||||||
const { current, pageSize, ...restParams } = params;
|
const { current, pageSize, sorter, ...restParams } = params;
|
||||||
return api.resource(name).list({
|
return api.resource(name).list({
|
||||||
associatedKey,
|
associatedKey,
|
||||||
page: paginated ? current : 1,
|
page: paginated ? current : 1,
|
||||||
perPage: paginated ? pageSize : -1,
|
perPage: paginated ? pageSize : -1,
|
||||||
|
sorter,
|
||||||
})
|
})
|
||||||
.then(({data = [], meta = {}}) => {
|
.then(({data = [], meta = {}}) => {
|
||||||
return {
|
return {
|
||||||
@ -72,6 +72,11 @@ export function SimpleTable(props: SimpleTableProps) {
|
|||||||
refresh();
|
refresh();
|
||||||
}}
|
}}
|
||||||
onTrigger={{
|
onTrigger={{
|
||||||
|
async filter(values) {
|
||||||
|
console.log('filter', values);
|
||||||
|
// @ts-ignore
|
||||||
|
run({...params[0], filter: values.filter});
|
||||||
|
},
|
||||||
async destroy() {
|
async destroy() {
|
||||||
await api.resource(name).destroy({
|
await api.resource(name).destroy({
|
||||||
associatedKey,
|
associatedKey,
|
||||||
@ -81,7 +86,7 @@ export function SimpleTable(props: SimpleTableProps) {
|
|||||||
});
|
});
|
||||||
await refresh();
|
await refresh();
|
||||||
console.log('destroy.onTrigger', selectedRowKeys);
|
console.log('destroy.onTrigger', selectedRowKeys);
|
||||||
}
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ViewFactory
|
<ViewFactory
|
||||||
@ -98,6 +103,9 @@ export function SimpleTable(props: SimpleTableProps) {
|
|||||||
loading={loading}
|
loading={loading}
|
||||||
columns={fields2columns(fields)}
|
columns={fields2columns(fields)}
|
||||||
dataSource={data?.list||(data as any)}
|
dataSource={data?.list||(data as any)}
|
||||||
|
onChange={(pagination, filters, sorter, extra) => {
|
||||||
|
run({...params[0], sorter});
|
||||||
|
}}
|
||||||
components={components({
|
components={components({
|
||||||
data,
|
data,
|
||||||
mutate,
|
mutate,
|
||||||
|
@ -46,12 +46,16 @@ export function Table(props: TableProps) {
|
|||||||
// associatedKey,
|
// associatedKey,
|
||||||
// }));
|
// }));
|
||||||
const name = associatedName ? `${associatedName}.${resourceName}` : resourceName;
|
const name = associatedName ? `${associatedName}.${resourceName}` : resourceName;
|
||||||
const { data, loading, pagination, mutate, refresh } = useRequest((params = {}) => {
|
const { data, loading, pagination, mutate, refresh, run, params } = useRequest((params = {}, ...args) => {
|
||||||
const { current, pageSize, ...restParams } = params;
|
const { current, pageSize, sorter, filter, ...restParams } = params;
|
||||||
|
console.log('paramsparamsparamsparamsparams', params, args);
|
||||||
return api.resource(name).list({
|
return api.resource(name).list({
|
||||||
associatedKey,
|
associatedKey,
|
||||||
page: paginated ? current : 1,
|
page: paginated ? current : 1,
|
||||||
perPage: paginated ? pageSize : -1,
|
perPage: paginated ? pageSize : -1,
|
||||||
|
sorter,
|
||||||
|
filter,
|
||||||
|
// ...args2,
|
||||||
})
|
})
|
||||||
.then(({data = [], meta = {}}) => {
|
.then(({data = [], meta = {}}) => {
|
||||||
return {
|
return {
|
||||||
@ -88,6 +92,11 @@ export function Table(props: TableProps) {
|
|||||||
refresh();
|
refresh();
|
||||||
}}
|
}}
|
||||||
onTrigger={{
|
onTrigger={{
|
||||||
|
async filter(values) {
|
||||||
|
// @ts-ignore
|
||||||
|
run({...params[0], filter: values.filter});
|
||||||
|
console.log('filter', values);
|
||||||
|
},
|
||||||
async destroy() {
|
async destroy() {
|
||||||
await api.resource(name).destroy({
|
await api.resource(name).destroy({
|
||||||
associatedKey,
|
associatedKey,
|
||||||
@ -104,6 +113,9 @@ export function Table(props: TableProps) {
|
|||||||
rowKey={rowKey}
|
rowKey={rowKey}
|
||||||
columns={fields2columns(fields)}
|
columns={fields2columns(fields)}
|
||||||
dataSource={data?.list||(data as any)}
|
dataSource={data?.list||(data as any)}
|
||||||
|
onChange={(pagination, filters, sorter, extra) => {
|
||||||
|
run({...params[0], sorter});
|
||||||
|
}}
|
||||||
components={components({
|
components={components({
|
||||||
data,
|
data,
|
||||||
mutate,
|
mutate,
|
||||||
|
Loading…
Reference in New Issue
Block a user