feat: table supports row drag and drop sorting

This commit is contained in:
chenos 2022-03-07 11:31:40 +08:00
parent b1aee77d10
commit 9ff0361336
5 changed files with 49 additions and 12 deletions

View File

@ -1,3 +1,4 @@
import { useField } from '@formily/react';
import { Result } from 'ahooks/lib/useRequest/src/types'; import { Result } from 'ahooks/lib/useRequest/src/types';
import React, { createContext, useContext, useEffect } from 'react'; import React, { createContext, useContext, useEffect } from 'react';
import { useCollectionManager } from '.'; import { useCollectionManager } from '.';
@ -5,20 +6,21 @@ import { CollectionProvider, useRecord } from '..';
import { useAPIClient, useRequest } from '../api-client'; import { useAPIClient, useRequest } from '../api-client';
export const ResourceActionContext = createContext< export const ResourceActionContext = createContext<
Result<any, any> & { state?: any; setState?: any; defaultRequest?: any } Result<any, any> & { state?: any; setState?: any; dragSort?: boolean; defaultRequest?: any }
>(null); >(null);
interface ResourceActionProviderProps { interface ResourceActionProviderProps {
type?: 'association' | 'collection'; type?: 'association' | 'collection';
collection?: any; collection?: any;
request?: any; request?: any;
dragSort?: boolean;
uid?: string; uid?: string;
} }
const ResourceContext = createContext<any>(null); const ResourceContext = createContext<any>(null);
const CollectionResourceActionProvider = (props) => { const CollectionResourceActionProvider = (props) => {
let { collection, request, uid } = props; let { collection, request, uid, dragSort } = props;
const api = useAPIClient(); const api = useAPIClient();
const record = useRecord(); const record = useRecord();
const actionName = request?.action; const actionName = request?.action;
@ -33,6 +35,7 @@ const CollectionResourceActionProvider = (props) => {
...others, ...others,
...request?.params, ...request?.params,
appends: collection.fields.filter((field) => field.target).map((field) => field.name), appends: collection.fields.filter((field) => field.target).map((field) => field.name),
sort: dragSort ? [collection.sortable === true ? 'sort' : collection.sortable] : request?.params?.sort,
}, },
}, },
{ uid }, { uid },
@ -40,7 +43,7 @@ const CollectionResourceActionProvider = (props) => {
const resource = api.resource(request.resource); const resource = api.resource(request.resource);
return ( return (
<ResourceContext.Provider value={{ type: 'collection', resource, collection }}> <ResourceContext.Provider value={{ type: 'collection', resource, collection }}>
<ResourceActionContext.Provider value={{ ...service, defaultRequest: request }}> <ResourceActionContext.Provider value={{ ...service, defaultRequest: request, dragSort }}>
<CollectionProvider collection={collection}>{props.children}</CollectionProvider> <CollectionProvider collection={collection}>{props.children}</CollectionProvider>
</ResourceActionContext.Provider> </ResourceActionContext.Provider>
</ResourceContext.Provider> </ResourceContext.Provider>
@ -48,7 +51,7 @@ const CollectionResourceActionProvider = (props) => {
}; };
const AssociationResourceActionProvider = (props) => { const AssociationResourceActionProvider = (props) => {
let { collection, association, request, uid } = props; let { collection, association, request, uid, dragSort } = props;
const api = useAPIClient(); const api = useAPIClient();
const record = useRecord(); const record = useRecord();
const resourceOf = record[association.sourceKey]; const resourceOf = record[association.sourceKey];
@ -69,7 +72,7 @@ const AssociationResourceActionProvider = (props) => {
const resource = api.resource(request.resource, resourceOf); const resource = api.resource(request.resource, resourceOf);
return ( return (
<ResourceContext.Provider value={{ type: 'association', resource, association }}> <ResourceContext.Provider value={{ type: 'association', resource, association }}>
<ResourceActionContext.Provider value={{ ...service, defaultRequest: request }}> <ResourceActionContext.Provider value={{ ...service, defaultRequest: request, dragSort }}>
<CollectionProvider collection={collection}>{props.children}</CollectionProvider> <CollectionProvider collection={collection}>{props.children}</CollectionProvider>
</ResourceActionContext.Provider> </ResourceActionContext.Provider>
</ResourceContext.Provider> </ResourceContext.Provider>
@ -97,9 +100,11 @@ export const useResourceActionContext = () => {
export const useDataSourceFromRAC = (options: any) => { export const useDataSourceFromRAC = (options: any) => {
const service = useContext(ResourceActionContext); const service = useContext(ResourceActionContext);
const field = useField();
useEffect(() => { useEffect(() => {
if (!service.loading) { if (!service.loading) {
options?.onSuccess(service.data); options?.onSuccess(service.data);
field.componentProps.dragSort = !!service.dragSort;
} }
}, [service.loading]); }, [service.loading]);
return service; return service;

View File

@ -148,11 +148,11 @@ export const useMoveAction = () => {
const { refresh } = useResourceActionContext(); const { refresh } = useResourceActionContext();
return { return {
async move(from, to) { async move(from, to) {
// await resource.move({ await resource.move({
// sourceId: from.id, sourceId: from.id,
// targetId: to.id, targetId: to.id,
// }); });
// refresh(); refresh();
}, },
}; };
}; };

View File

@ -13,8 +13,24 @@ export const TableVoidDesigner = () => {
const ctx = useResourceActionContext(); const ctx = useResourceActionContext();
const { dn } = useDesignable(); const { dn } = useDesignable();
const defaultFilter = fieldSchema?.['x-decorator-props']?.request?.params?.filter || {}; const defaultFilter = fieldSchema?.['x-decorator-props']?.request?.params?.filter || {};
const defaultSort = fieldSchema?.['x-decorator-props']?.request?.params?.sort || [];
return ( return (
<GeneralSchemaDesigner title={title || name}> <GeneralSchemaDesigner title={title || name}>
<SchemaSettings.SwitchItem
title={'启用手动排序'}
checked={field.decoratorProps.dragSort}
onChange={(dragSort) => {
field.decoratorProps.dragSort = dragSort;
fieldSchema['x-decorator-props'].dragSort = dragSort;
ctx.run({ ...ctx.params?.[0], sort: defaultSort });
dn.emit('patch', {
schema: {
['x-uid']: fieldSchema['x-uid'],
'x-decorator-props': fieldSchema['x-decorator-props'],
},
});
}}
/>
<SchemaSettings.ModalItem <SchemaSettings.ModalItem
title={'设置数据范围'} title={'设置数据范围'}
schema={ schema={

View File

@ -12,6 +12,7 @@ const createSchema = (collectionName) => {
'x-decorator': 'ResourceActionProvider', 'x-decorator': 'ResourceActionProvider',
'x-decorator-props': { 'x-decorator-props': {
collection: collectionName, collection: collectionName,
dragSort: false,
request: { request: {
resource: collectionName, resource: collectionName,
action: 'list', action: 'list',

View File

@ -2,7 +2,7 @@ import { FormDialog, FormLayout } from '@formily/antd';
import { GeneralField } from '@formily/core'; import { GeneralField } from '@formily/core';
import { ISchema, Schema, SchemaOptionsContext } from '@formily/react'; import { ISchema, Schema, SchemaOptionsContext } from '@formily/react';
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';
import { Dropdown, Menu, MenuItemProps, Modal, Select } from 'antd'; import { Dropdown, Menu, MenuItemProps, Modal, Select, Switch } from 'antd';
import React, { createContext, useContext, useState } from 'react'; import React, { createContext, useContext, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { ActionContext, Designable, SchemaComponent, SchemaComponentOptions, useActionContext } from '..'; import { ActionContext, Designable, SchemaComponent, SchemaComponentOptions, useActionContext } from '..';
@ -152,7 +152,22 @@ SchemaSettings.SelectItem = (props) => {
}; };
SchemaSettings.SwitchItem = (props) => { SchemaSettings.SwitchItem = (props) => {
return null; const { title, onChange, ...others } = props;
const [checked, setChecked] = useState(!!props.checked);
return (
<SchemaSettings.Item
{...others}
onClick={() => {
onChange?.(!checked);
setChecked(!checked);
}}
>
<div style={{ alignItems: 'center', display: 'flex', justifyContent: 'space-between' }}>
{title}
<Switch size={'small'} checked={checked} />
</div>
</SchemaSettings.Item>
);
}; };
SchemaSettings.PopupItem = (props) => { SchemaSettings.PopupItem = (props) => {