diff --git a/packages/client/src/components/Sortable/index.tsx b/packages/client/src/components/Sortable/index.tsx index 3248bf6de..9ca6ed4f4 100644 --- a/packages/client/src/components/Sortable/index.tsx +++ b/packages/client/src/components/Sortable/index.tsx @@ -38,13 +38,16 @@ export interface SortableItemProps {} export const SortableItemContext = createContext({}); -export function DragHandle() { +export function DragHandle(props) { + const { component, ...others } = props; + const Icon = component || DragOutlined; return ( {({ setDraggableNodeRef, attributes, listeners }) => setDraggableNodeRef && ( - diff --git a/packages/client/src/schemas/add-new/index.tsx b/packages/client/src/schemas/add-new/index.tsx index 7c0cd8633..7bba3ac11 100644 --- a/packages/client/src/schemas/add-new/index.tsx +++ b/packages/client/src/schemas/add-new/index.tsx @@ -236,22 +236,27 @@ function generateCardItemSchema(component) { 'x-component': 'Action.Dropdown', 'x-component-props': {}, properties: { - [uid()]: { - type: 'void', - title: '操作 1', - 'x-component': 'Menu.Action', - 'x-component-props': { - style: { - minWidth: 150, - }, - disabled: true, - }, - }, + // [uid()]: { + // type: 'void', + // title: '操作 1', + // 'x-component': 'Menu.Action', + // 'x-component-props': { + // style: { + // minWidth: 150, + // }, + // disabled: true, + // }, + // }, [uid()]: { type: 'void', name: 'action1', title: '查看', 'x-component': 'Menu.Action', + 'x-component-props': { + style: { + minWidth: 150, + }, + }, 'x-designable-bar': 'Table.Action.DesignableBar', 'x-action-type': 'view', properties: { diff --git a/packages/client/src/schemas/database-field/index.tsx b/packages/client/src/schemas/database-field/index.tsx index 1bc103a28..8e4e912d7 100644 --- a/packages/client/src/schemas/database-field/index.tsx +++ b/packages/client/src/schemas/database-field/index.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { forwardRef, useState } from 'react'; import { observer, connect, @@ -11,7 +11,7 @@ import { FormConsumer, } from '@formily/react'; import { ArrayCollapse, FormLayout } from '@formily/antd'; -import { uid } from '@formily/shared'; +import { uid, isValid } from '@formily/shared'; import '@formily/antd/lib/form-tab/style'; import { Collapse, @@ -32,6 +32,7 @@ import { DatabaseOutlined, PlusOutlined, CloseOutlined, + MenuOutlined, } from '@ant-design/icons'; import cls from 'classnames'; import './style.less'; @@ -39,8 +40,53 @@ import Modal from 'antd/lib/modal/Modal'; import { clone, cloneDeep, get } from 'lodash'; import { useEffect } from 'react'; import { useRequest } from 'ahooks'; -import { createOrUpdateCollection, deleteCollection } from '..'; +import { + collectionMoveToAfter, + createOrUpdateCollection, + deleteCollection, +} from '..'; import { useCollectionsContext } from '../../constate/Collections'; +import { + DragHandle, + SortableItem, + SortableItemContext, +} from '../../components/Sortable'; +import { DndContext, DragOverlay } from '@dnd-kit/core'; +import { createPortal } from 'react-dom'; + +interface SelectOptionProps { + id: any; + title: string; + data?: any; + onRemove?: any; + showRemove?: boolean; +} + +function SelectOption(props: SelectOptionProps) { + const { id, data, onRemove, showRemove } = props; + return ( + +
+ ((props, ref) => { + return ; + })} + /> + + {data.title} + {showRemove && ( + + )} +
+
+ ); +} export const DatabaseCollection = observer((props) => { const field = useField(); @@ -51,6 +97,7 @@ export const DatabaseCollection = observer((props) => { const form = useForm(); const [newValue, setNewValue] = useState(''); const { loading, refresh, collections = [] } = useCollectionsContext(); + const [dragOverlayContent, setDragOverlayContent] = useState(''); useEffect(() => { field.setValue(collections); @@ -87,101 +134,118 @@ export const DatabaseCollection = observer((props) => { }} title={
- { + setActiveIndex(value as any); + }} + open={open} + onDropdownVisibleChange={setOpen} + optionLabelProp={'label'} + dropdownRender={(menu) => { + return ( +
+ {menu} + +
+ } + value={newValue} + onChange={(e) => { + setNewValue(e.target.value); + }} + onSearch={async (value) => { + const data = { + name: `t_${uid()}`, + title: value, + fields: getDefaultFields(), + }; + field.push(data); + setActiveIndex(field.value.length - 1); + setOpen(false); + setNewValue(''); + await createOrUpdateCollection(data); + await refresh(); }} /> - )} +
- - ); - })} - + ); + }} + > + {field.value?.map((item, index) => { + return ( + + { + e.stopPropagation(); + field.remove(index); + if (field.value?.length === 0) { + field.push({ + name: `t_${uid()}`, + unsaved: true, + fields: getDefaultFields(), + }); + } + if (activeIndex === index) { + setActiveIndex(0); + } else if (activeIndex > index) { + setActiveIndex(activeIndex - 1); + } + if (item.name) { + await deleteCollection(item.name); + await refresh(); + } + }} + /> + + ); + })} + +
} visible={visible} @@ -228,88 +292,124 @@ export const DatabaseField: any = observer((props) => { } }, []); const [activeKey, setActiveKey] = useState(null); + const [dragOverlayContent, setDragOverlayContent] = useState(''); return (
- { - setActiveKey(key); + { + setDragOverlayContent(event.active?.data?.current?.title || ''); + }} + onDragEnd={async (event) => { + const fromIndex = event.active?.data?.current?.index; + const toIndex = event.over?.data?.current?.index; + if (isValid(fromIndex) && isValid(toIndex)) { + field.move(fromIndex, toIndex); + } }} - className={cls({ empty: !field.value?.length })} - accordion > - {field.value?.map((item, index) => { - if (!item.interface) { - return; - } - const schema = cloneDeep(interfaces.get(item.interface)); - if (!schema) { - console.error('schema invalid'); - return; - } - const path = field.address.concat(index); - const errors = field.form.queryFeedbacks({ - type: 'error', - address: `*(${path},${path}.*)`, - }); - return ( - - {(item.uiSchema && item.uiSchema.title) || ( - 未命名 - )}{' '} - + {dragOverlayContent} + , + document.body, + )} + { + setActiveKey(key); + }} + className={cls({ empty: !field.value?.length })} + accordion + > + {field.value?.map((item, index) => { + if (!item.interface) { + return; + } + const schema = cloneDeep(interfaces.get(item.interface)); + if (!schema) { + console.error('schema invalid'); + return; + } + const path = field.address.concat(index); + const errors = field.form.queryFeedbacks({ + type: 'error', + address: `*(${path},${path}.*)`, + }); + return ( + - {schema.title} - - - {item.name} - - - } - extra={ - item.privilege === 'undelete' - ? [] - : [ - , - { - e.stopPropagation(); - field.remove(index); - }} - />, - ] - } - key={item.key} - > - + {(item.uiSchema && item.uiSchema.title) || ( + 未命名 + )}{' '} + + {schema.title} + + + {item.name} + + } - /> - - ); - })} - + extra={ + item.privilege === 'undelete' + ? [] + : [ + , + { + e.stopPropagation(); + field.remove(index); + }} + />, + ] + } + key={item.key} + forceRender + > + + + ); + })} + + { if (!path1 || !path2) { return; } + if (path1.join('.') === path2.join('.')) { + return; + } const data = findPropertyByPath(root, path1); if (!data) { return; diff --git a/packages/plugin-collections/src/actions/index.ts b/packages/plugin-collections/src/actions/index.ts index c3e0cf845..38f6dd447 100644 --- a/packages/plugin-collections/src/actions/index.ts +++ b/packages/plugin-collections/src/actions/index.ts @@ -6,7 +6,7 @@ import { cloneDeep, omit } from 'lodash'; export const findAll = async (ctx: actions.Context, next: actions.Next) => { const Collection = ctx.db.getModel('collections'); const collections = await Collection.findAll(Collection.parseApiJson({ - sort: '-created_at', + sort: 'sort', })); const data = []; for (const collection of collections) { @@ -29,6 +29,14 @@ export const createOrUpdate = async (ctx: actions.Context, next: actions.Next) = } else { await collection.update(values); } + if (values.fields) { + values.fields = values.fields.map((field, index) => { + return { + ...field, + sort: index + 1, + } + }) + } await collection.updateAssociations(values); await collection.migrate(); } catch (error) {