mirror of
https://gitee.com/nocobase/nocobase.git
synced 2024-12-01 11:47:51 +08:00
improve filter & sort...
This commit is contained in:
parent
787d2b611f
commit
5fd8139767
@ -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}/`)}`;
|
||||
|
@ -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}/>
|
||||
});
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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) => ({
|
||||
|
@ -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}
|
||||
|
@ -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) => ({
|
||||
|
@ -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);
|
||||
}, {
|
||||
|
@ -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;
|
||||
|
@ -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: [
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user