feat: improve filter action

This commit is contained in:
chenos 2020-12-12 16:32:18 +08:00
parent c776229540
commit 2dbbe29223
6 changed files with 128 additions and 44 deletions

View File

@ -28,8 +28,9 @@ class ApiClient {
const proxy: any = new Proxy({}, {
get(target, method, receiver) {
return (params: ActionParams = {}) => {
const { associatedKey, resourceKey, filter, ...restParams } = params;
let { associatedKey, resourceKey, filter, sorter, sort = [], ...restParams } = params;
let url = `/${name}`;
sort = sort || [];
let options: any = {
params: {},
};
@ -51,6 +52,21 @@ class ApiClient {
if (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});
return request(url, options);
};

View File

@ -42,6 +42,7 @@ export function Filter(props) {
<div className={'popover-button-mask'} onClick={() => setVisible(false)}></div>
<ViewFactory
{...props}
setVisible={setVisible}
viewName={'filter'}
{...params}
/>

View File

@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
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 { connect } from '@formily/react-schema-renderer'
import { mapStyledProps } from '../shared'
@ -13,8 +13,19 @@ export function FilterGroup(props: any) {
type: 'item',
},
]);
let style: any = {
position: 'relative',
};
if (showDeleteButton) {
style = {
...style,
marginBottom: 14,
padding: 14,
border: '1px dashed #dedede',
}
}
return (
<div style={{marginBottom: 14, padding: 14, border: '1px dashed #dedede'}}>
<div style={style}>
<div style={{marginBottom: 14}}>
{' '}
@ -32,7 +43,7 @@ export function FilterGroup(props: any) {
// console.log(item);
const Component = item.type === 'group' ? FilterGroup : FilterItem;
return (
<div style={{marginBottom: 14}}>
<div style={{marginBottom: 8}}>
{<Component
fields={fields}
dataSource={item}
@ -58,7 +69,7 @@ export function FilterGroup(props: any) {
</div>
<div>
<Space>
<Button onClick={() => {
<Button style={{padding: 0}} type={'link'} onClick={() => {
const data = {
type: 'item'
};
@ -67,28 +78,33 @@ export function FilterGroup(props: any) {
newList.push(data);
onChange({...dataSource, list: newList});
}}>
<PlusCircleOutlined />
</Button>
<Button onClick={() => {
const data = {
type: 'group',
list: [
{
type: 'item',
},
],
};
push(data);
const newList = [...list];
newList.push(data);
onChange({...dataSource, list: newList});
}}>
{' '}
<Button
style={{padding: 0}}
type={'link'}
onClick={() => {
const data = {
type: 'group',
list: [
{
type: 'item',
},
],
};
push(data);
const newList = [...list];
newList.push(data);
onChange({...dataSource, list: newList});
}}
>
<PlusCircleOutlined />
</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);
}}>
<CloseCircleOutlined />
</Button>}
</Space>
</div>
@ -169,7 +185,9 @@ const op = {
string: OP_MAP.string,
textarea: OP_MAP.string,
number: OP_MAP.number,
percent: OP_MAP.number,
datetime: OP_MAP.datetime,
date: OP_MAP.datetime,
};
const StringInput = (props) => {
@ -186,7 +204,7 @@ const controls = {
textarea: StringInput,
number: InputNumber,
// datetime: DatePicker,
datetime: (props) => {
date: (props) => {
const { value, onChange, ...restProps } = props;
const m = moment(value, 'YYYY-MM-DD HH:mm:ss');
return (
@ -204,14 +222,15 @@ export function FilterItem(props: FilterItemProps) {
useEffect(() => {
const field = fields.find(field => field.name === dataSource.column);
if (field) {
setType(field.interface);
setType(field.component.type);
}
}, [
dataSource,
]);
console.log({type});
const ValueControl = controls[type]||controls.string;
return (
<Input.Group compact>
<Space>
<Select value={dataSource.column}
onChange={(value) => {
const field = fields.find(field => field.name === value);
@ -220,7 +239,8 @@ export function FilterItem(props: FilterItemProps) {
}
onChange({...dataSource, column: value});
}}
style={{ width: '30%' }} placeholder={'选择字段'}>
style={{ width: 120 }}
placeholder={'选择字段'}>
{fields.map(field => (
<Select.Option value={field.name}>{field.title}</Select.Option>
))}
@ -236,16 +256,33 @@ export function FilterItem(props: FilterItemProps) {
</Select>
<ValueControl value={dataSource.value} onChange={(value) => {
onChange({...dataSource, value: value});
}} style={{ width: '30%' }}/>
}}
style={{ width: 180 }}
/>
{showDeleteButton && (
<Button onClick={(e) => {
<Button type={'link'} style={{padding: 0}} onClick={(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({
getProps: mapStyledProps,
})((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;

View File

@ -1,5 +1,5 @@
import React from 'react';
import { Tooltip, Card } from 'antd';
import { Tooltip, Button } from 'antd';
import {
SchemaForm,
SchemaMarkupField as Field,
@ -15,7 +15,8 @@ import {
import { QuestionCircleOutlined } from '@ant-design/icons';
export function FilterForm(props: any) {
const actions = createFormActions();
const actions = createAsyncFormActions();
const { setVisible, onTrigger } = props;
const { title, fields: properties ={} } = props.schema||{};
return (
<SchemaForm
@ -23,6 +24,15 @@ export function FilterForm(props: any) {
layout={'vertical'}
initialValues={{}}
actions={actions}
onReset={() => {
setVisible && setVisible(false);
}}
onSubmit={async (values) => {
if (onTrigger) {
await onTrigger(values);
}
setVisible && setVisible(false);
}}
schema={{
type: 'object',
properties,
@ -44,10 +54,7 @@ export function FilterForm(props: any) {
>
<FormButtonGroup>
<Reset></Reset>
<Submit onClick={async () => {
const { values = {} } = await actions.submit();
console.log(values);
}}></Submit>
<Submit></Submit>
</FormButtonGroup>
</SchemaForm>
);

View File

@ -4,7 +4,6 @@ import { Actions } from '@/components/actions';
import ViewFactory from '@/components/views';
import { useRequest } from 'umi';
import api from '@/api-client';
import get from 'lodash/get';
import { components, fields2columns } from './SortableTable';
export interface SimpleTableProps {
@ -30,12 +29,13 @@ export function SimpleTable(props: SimpleTableProps) {
const { sourceKey = 'id' } = activeTab.field||{};
const drawerRef = useRef<any>();
const name = associatedName ? `${associatedName}.${resourceName}` : resourceName;
const { data, loading, pagination, mutate, refresh } = useRequest((params = {}) => {
const { current, pageSize, ...restParams } = params;
const { data, loading, pagination, mutate, refresh, params, run } = useRequest((params = {}) => {
const { current, pageSize, sorter, ...restParams } = params;
return api.resource(name).list({
associatedKey,
page: paginated ? current : 1,
perPage: paginated ? pageSize : -1,
sorter,
})
.then(({data = [], meta = {}}) => {
return {
@ -72,6 +72,11 @@ export function SimpleTable(props: SimpleTableProps) {
refresh();
}}
onTrigger={{
async filter(values) {
console.log('filter', values);
// @ts-ignore
run({...params[0], filter: values.filter});
},
async destroy() {
await api.resource(name).destroy({
associatedKey,
@ -81,7 +86,7 @@ export function SimpleTable(props: SimpleTableProps) {
});
await refresh();
console.log('destroy.onTrigger', selectedRowKeys);
}
},
}}
/>
<ViewFactory
@ -98,6 +103,9 @@ export function SimpleTable(props: SimpleTableProps) {
loading={loading}
columns={fields2columns(fields)}
dataSource={data?.list||(data as any)}
onChange={(pagination, filters, sorter, extra) => {
run({...params[0], sorter});
}}
components={components({
data,
mutate,

View File

@ -46,12 +46,16 @@ export function Table(props: TableProps) {
// associatedKey,
// }));
const name = associatedName ? `${associatedName}.${resourceName}` : resourceName;
const { data, loading, pagination, mutate, refresh } = useRequest((params = {}) => {
const { current, pageSize, ...restParams } = params;
const { data, loading, pagination, mutate, refresh, run, params } = useRequest((params = {}, ...args) => {
const { current, pageSize, sorter, filter, ...restParams } = params;
console.log('paramsparamsparamsparamsparams', params, args);
return api.resource(name).list({
associatedKey,
page: paginated ? current : 1,
perPage: paginated ? pageSize : -1,
sorter,
filter,
// ...args2,
})
.then(({data = [], meta = {}}) => {
return {
@ -88,6 +92,11 @@ export function Table(props: TableProps) {
refresh();
}}
onTrigger={{
async filter(values) {
// @ts-ignore
run({...params[0], filter: values.filter});
console.log('filter', values);
},
async destroy() {
await api.resource(name).destroy({
associatedKey,
@ -104,6 +113,9 @@ export function Table(props: TableProps) {
rowKey={rowKey}
columns={fields2columns(fields)}
dataSource={data?.list||(data as any)}
onChange={(pagination, filters, sorter, extra) => {
run({...params[0], sorter});
}}
components={components({
data,
mutate,