improve filter & sort...

This commit is contained in:
chenos 2020-12-13 00:09:25 +08:00
parent 787d2b611f
commit 5fd8139767
15 changed files with 134 additions and 67 deletions

View File

@ -1,3 +1,4 @@
import { values } from 'lodash';
import { stringify } from 'querystring';
import { request } from 'umi';
@ -28,7 +29,7 @@ class ApiClient {
const proxy: any = new Proxy({}, {
get(target, method, receiver) {
return (params: ActionParams = {}) => {
let { associatedKey, resourceKey, filter, sorter, sort = [], ...restParams } = params;
let { associatedKey, resourceKey, filter, sorter, sort = [], values, ...restParams } = params;
let url = `/${name}`;
sort = sort || [];
let options: any = {
@ -39,7 +40,7 @@ class ApiClient {
options.params = restParams;
} else {
options.method = 'post';
options.data = restParams;
options.data = values;
}
if (associatedKey) {
url = `/${name.split('.').join(`/${associatedKey}/`)}`;

View File

@ -30,7 +30,7 @@ export function FilterGroup(props: any) {
{' '}
<Select style={{width: 80}} onChange={(value) => {
onChange({...dataSource, andor: value});
onChange({type: 'group', list, andor: value});
}} defaultValue={'and'}>
<Select.Option value={'and'}></Select.Option>
<Select.Option value={'or'}></Select.Option>
@ -283,6 +283,24 @@ function toFilter(values: any) {
return filter;
}
function toValues(filter: any = {}) {
let values: any = {};
Object.keys(filter).forEach(key => {
const value = filter[key];
if (Array.isArray(value)) {
values['andor'] = key;
values['type'] = 'group';
values['list'] = value.map(v => toValues(v));
} else if (typeof value === 'object') {
values['type'] = 'item';
values['column'] = key;
values['op'] = Object.keys(value).shift();
values['value'] = Object.values(value).shift();
}
});
return values;
}
export const Filter = connect({
getProps: mapStyledProps,
})((props) => {
@ -295,7 +313,9 @@ export const Filter = connect({
],
};
const { value, onChange, ...restProps } = props;
return <FilterGroup dataSource={dataSource} onChange={(values) => {
console.log('valuevaluevaluevaluevaluevalue', value);
return <FilterGroup dataSource={value ? toValues(value) : dataSource} onChange={(values) => {
console.log(values);
onChange(toFilter(values));
}} {...restProps}/>
});

View File

@ -20,8 +20,9 @@ export const setup = () => {
time: TimePicker,
timerange: TimePicker.RangePicker,
transfer: Transfer,
boolean: Switch,
checkbox: Switch,
boolean: Checkbox,
switch: Switch,
checkbox: Checkbox,
array: ArrayCards,
cards: ArrayCards,
table: ArrayTable,

View File

@ -67,12 +67,12 @@ export const DrawerForm = forwardRef((props: any, ref) => {
await api.resource(name).update({
resourceKey,
associatedKey,
...values,
values,
});
} else {
await api.resource(name).create({
associatedKey,
...values,
values,
});
}
setVisible(false);

View File

@ -25,17 +25,18 @@ export function SimpleTable(props: SimpleTableProps) {
associatedName,
associatedKey,
} = props;
const { rowKey = 'id', fields = [], rowViewName, actions = [], paginated = true, defaultPageSize = 10 } = schema;
const { rowKey = 'id', fields = [], rowViewName, actions = [], paginated = true, defaultPerPage = 10 } = schema;
const { sourceKey = 'id' } = activeTab.field||{};
const drawerRef = useRef<any>();
const name = associatedName ? `${associatedName}.${resourceName}` : resourceName;
const { data, loading, pagination, mutate, refresh, params, run } = useRequest((params = {}) => {
const { current, pageSize, sorter, ...restParams } = params;
const { current, pageSize, sorter, filter, ...restParams } = params;
return api.resource(name).list({
associatedKey,
page: paginated ? current : 1,
perPage: paginated ? pageSize : -1,
sorter,
filter,
})
.then(({data = [], meta = {}}) => {
return {
@ -47,7 +48,7 @@ export function SimpleTable(props: SimpleTableProps) {
});
}, {
paginated,
defaultPageSize,
defaultPageSize: defaultPerPage,
});
console.log(schema, data);
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
@ -110,15 +111,17 @@ export function SimpleTable(props: SimpleTableProps) {
data,
mutate,
rowKey,
onMoved: async ({resourceKey, offset}) => {
onMoved: async ({resourceKey, target}) => {
await api.resource(name).sort({
associatedKey,
resourceKey,
field: 'sort',
offset,
values: {
field: 'sort',
target,
},
});
await refresh();
console.log({resourceKey, offset});
console.log({resourceKey, target});
}
})}
onRow={(record) => ({

View File

@ -30,6 +30,7 @@ export const components = ({data = {}, rowKey, mutate, onMoved}: Props) => {
helperClass="row-dragging"
onSortEnd={async ({ oldIndex, newIndex, ...restProps }) => {
if (oldIndex !== newIndex) {
const targetIndex = get(data.list, [newIndex, rowKey]);
const list = arrayMove([].concat(data.list), oldIndex, newIndex).filter(el => !!el);
console.log({oldIndex, newIndex, list});
mutate({
@ -37,7 +38,7 @@ export const components = ({data = {}, rowKey, mutate, onMoved}: Props) => {
list,
});
const resourceKey = get(list, [newIndex, rowKey]);
await onMoved({resourceKey, offset: newIndex - oldIndex});
await onMoved({resourceKey, target: {[rowKey]: targetIndex}});
}
}}
{...props}

View File

@ -41,7 +41,7 @@ export function Table(props: TableProps) {
associatedName,
associatedKey,
} = props;
const { fields, defaultTabName, rowKey = 'id', actions = [], paginated = true, defaultPageSize = 10 } = schema;
const { fields, defaultTabName, rowKey = 'id', actions = [], paginated = true, defaultPerPage = 10 } = schema;
// const { data, mutate } = useRequest(() => api.resource(name).list({
// associatedKey,
// }));
@ -67,7 +67,7 @@ export function Table(props: TableProps) {
});
}, {
paginated,
defaultPageSize,
defaultPageSize: defaultPerPage,
});
const { sourceKey = 'id' } = activeTab.field||{};
console.log(props);
@ -120,15 +120,17 @@ export function Table(props: TableProps) {
data,
mutate,
rowKey,
onMoved: async ({resourceKey, offset}) => {
onMoved: async ({resourceKey, target}) => {
await api.resource(name).sort({
associatedKey,
resourceKey,
field: 'sort',
offset,
values: {
field: 'sort',
target,
},
});
await refresh();
console.log({resourceKey, offset});
console.log({resourceKey, target});
}
})}
onRow={(data) => ({

View File

@ -49,11 +49,15 @@ export default function ViewFactory(props: ViewProps) {
mode,
reference,
} = props;
console.log('propspropspropspropspropspropsprops', props);
const { data = {}, loading } = useRequest(() => {
const params = {
resourceKey: viewName,
associatedName: associatedName,
mode,
values: {
associatedKey: associatedKey,
associatedName: associatedName,
mode
},
};
return api.resource(resourceName).getView(params);
}, {

View File

@ -10,8 +10,9 @@ export default {
fields: [
{
interface: 'sort',
type: 'integer',
type: 'sort',
name: 'sort',
scope: ['collection'],
title: '排序',
component: {
type: 'sort',
@ -149,13 +150,7 @@ export default {
detailsViewName: 'details',
updateViewName: 'form',
paginated: false,
},
{
type: 'table',
name: 'table',
title: '列表',
template: 'Table',
actionNames: ['create', 'destroy'],
draggable: true,
},
],
} as TableOptions;

View File

@ -11,7 +11,7 @@ export default {
fields: [
{
interface: 'sort',
type: 'integer',
type: 'sort',
name: 'sort',
title: '排序',
component: {
@ -295,6 +295,7 @@ export default {
template: 'Table',
actionNames: ['create', 'destroy'],
default: true,
draggable: true,
},
],
tabs: [

View File

@ -11,8 +11,9 @@ export default {
fields: [
{
interface: 'sort',
type: 'integer',
type: 'sort',
name: 'sort',
scope: ['collection'],
title: '排序',
defaultValue: 1,
component: {
@ -27,6 +28,7 @@ export default {
type: 'string',
name: 'title',
title: '字段名称',
required: true,
component: {
type: 'string',
className: 'drag-visible',
@ -42,6 +44,7 @@ export default {
title: '标识',
required: true,
createOnly: true,
developerMode: true,
component: {
type: 'string',
showInTable: true,
@ -383,13 +386,7 @@ export default {
detailsViewName: 'details',
updateViewName: 'form',
paginated: false,
},
{
type: 'table',
name: 'table',
title: '列表',
template: 'Table',
actionNames: ['create', 'destroy'],
draggable: true,
},
],
} as TableOptions;

View File

@ -10,8 +10,9 @@ export default {
fields: [
{
interface: 'sort',
type: 'integer',
type: 'sort',
name: 'sort',
scope: ['collection'],
title: '排序',
component: {
type: 'sort',
@ -51,6 +52,7 @@ export default {
type: 'string',
name: 'type',
title: '类型',
required: true,
dataSource: [
{ label: '详情数据', value: 'details' },
{ label: '相关数据', value: 'association', disabled: true },
@ -189,13 +191,7 @@ export default {
detailsViewName: 'details',
updateViewName: 'form',
paginated: false,
},
{
type: 'table',
name: 'table',
title: '列表',
template: 'Table',
actionNames: ['create', 'destroy'],
draggable: true,
},
],
} as TableOptions;

View File

@ -10,8 +10,9 @@ export default {
fields: [
{
interface: 'sort',
type: 'integer',
type: 'sort',
name: 'sort',
scope: ['collection'],
title: '排序',
component: {
type: 'sort',
@ -62,6 +63,25 @@ export default {
showInTable: true,
showInDetail: true,
showInForm: true,
"x-linkages": [
{
"type": "value:visible",
"target": "filter",
"condition": "{{ $self.value !== 'form' }}"
},
],
},
},
{
interface: 'json',
type: 'json',
name: 'filter',
title: '筛选数据',
developerMode: false,
mode: 'replace',
component: {
type: 'filter',
showInForm: true,
},
},
{
@ -234,13 +254,7 @@ export default {
detailsViewName: 'details',
updateViewName: 'form',
paginated: false,
},
{
type: 'table',
name: 'table',
title: '列表',
template: 'Table',
actionNames: ['create', 'destroy'],
draggable: true,
},
],
} as TableOptions;

View File

@ -82,8 +82,12 @@ export class BaseModel extends Model {
}
// 如果是 object 数据merge 处理
if (_.isPlainObject(value)) {
// @ts-ignore
value = merge(this.get(key)||{}, value);
// TODO 需要改进 JSON 字段的内部处理逻辑,暂时这里跳过了特殊的 filter 字段
if (key !== 'filter') {
// console.log(key, value);
// @ts-ignore
value = merge(this.get(key)||{}, value);
}
}
const [column, ...path] = key.split('.');
if (!options.raw) {

View File

@ -1,6 +1,6 @@
import { ResourceOptions } from '@nocobase/resourcer';
import { Model, ModelCtor } from '@nocobase/database';
import { get, set } from 'lodash';
import { Op } from 'sequelize';
const transforms = {
table: async (fields: Model[], context?: any) => {
@ -18,6 +18,7 @@ const transforms = {
return arr;
},
form: async (fields: Model[], ctx?: any) => {
const [Field] = ctx.db.getModels(['fields']) as ModelCtor<Model>[];
const mode = get(ctx.action.params, ['values', 'mode'], ctx.action.params.mode);
const schema = {};
for (const field of fields) {
@ -31,9 +32,26 @@ const transforms = {
title: field.title||field.name,
...(field.component||{}),
}
if (field.get('name') === 'filter' && field.get('collection_name') === 'views') {
const { values } = ctx.action.params;
const all = await Field.findAll({
where: {
collection_name: get(values, 'associatedKey'),
developerMode: ctx.state.developerMode,
},
order: [['sort', 'asc']],
});
set(prop, 'x-component-props.fields', all.filter(f => f.get('filterable')));
}
if (type === 'select') {
prop.type = 'string'
}
if (field.get('component.tooltip')) {
prop.description = field.get('component.tooltip');
}
if (field.get('required')) {
prop.required = true;
}
if (mode === 'update' && field.get('createOnly')) {
set(prop, 'x-component-props.disabled', true);
}
@ -44,6 +62,10 @@ const transforms = {
if (defaultValue) {
prop.default = defaultValue;
}
if (interfaceType === 'boolean') {
set(prop, 'x-component-props.children', prop.title);
delete prop.title;
}
if (['radio', 'select', 'checkboxes'].includes(interfaceType)) {
prop.enum = get(field.options, 'dataSource', []);
}
@ -71,9 +93,9 @@ const transforms = {
filter: {
type: 'filter',
'x-component-props': {
fields,
fields: fields.filter(field => field.get('filterable')),
},
}
},
}
return properties;
},
@ -100,10 +122,16 @@ export default async (ctx, next) => {
name: resourceName,
},
});
const where: any = {
developerMode: ctx.state.developerMode,
}
if (!view.get('draggable')) {
where.type = {
[Op.not]: 'sort',
};
}
const fields = await collection.getFields({
where: {
developerMode: ctx.state.developerMode,
},
where,
order: [
['sort', 'asc'],
]
@ -128,7 +156,7 @@ export default async (ctx, next) => {
if (view.get('updateViewName')) {
view.setDataValue('rowViewName', view.get('updateViewName'));
}
view.setDataValue('viewCollectionName', view.collection_name);
// view.setDataValue('viewCollectionName', view.collection_name);
let title = collection.get('title');
const mode = get(ctx.action.params, ['values', 'mode'], ctx.action.params.mode);
if (mode === 'update') {
@ -144,7 +172,7 @@ export default async (ctx, next) => {
actions: actions.filter(action => actionNames.includes(action.name)).map(action => ({
...action.toJSON(),
...action.options,
viewCollectionName: action.collection_name,
// viewCollectionName: action.collection_name,
})),
};
await next();