improve code
This commit is contained in:
		
							parent
							
								
									754be7d1d1
								
							
						
					
					
						commit
						c23d2c5c3c
					
				@ -38,13 +38,16 @@ export interface SortableItemProps {}
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export const SortableItemContext = createContext<any>({});
 | 
					export const SortableItemContext = createContext<any>({});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function DragHandle() {
 | 
					export function DragHandle(props) {
 | 
				
			||||||
 | 
					  const { component, ...others } = props;
 | 
				
			||||||
 | 
					  const Icon = component || DragOutlined;
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <SortableItemContext.Consumer>
 | 
					    <SortableItemContext.Consumer>
 | 
				
			||||||
      {({ setDraggableNodeRef, attributes, listeners }) =>
 | 
					      {({ setDraggableNodeRef, attributes, listeners }) =>
 | 
				
			||||||
        setDraggableNodeRef && (
 | 
					        setDraggableNodeRef && (
 | 
				
			||||||
          <DragOutlined
 | 
					          <Icon
 | 
				
			||||||
            ref={setDraggableNodeRef}
 | 
					            ref={setDraggableNodeRef}
 | 
				
			||||||
 | 
					            {...others}
 | 
				
			||||||
            {...attributes}
 | 
					            {...attributes}
 | 
				
			||||||
            {...listeners}
 | 
					            {...listeners}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
 | 
				
			|||||||
@ -236,22 +236,27 @@ function generateCardItemSchema(component) {
 | 
				
			|||||||
                  'x-component': 'Action.Dropdown',
 | 
					                  'x-component': 'Action.Dropdown',
 | 
				
			||||||
                  'x-component-props': {},
 | 
					                  'x-component-props': {},
 | 
				
			||||||
                  properties: {
 | 
					                  properties: {
 | 
				
			||||||
                    [uid()]: {
 | 
					                    // [uid()]: {
 | 
				
			||||||
                      type: 'void',
 | 
					                    //   type: 'void',
 | 
				
			||||||
                      title: '操作 1',
 | 
					                    //   title: '操作 1',
 | 
				
			||||||
                      'x-component': 'Menu.Action',
 | 
					                    //   'x-component': 'Menu.Action',
 | 
				
			||||||
                      'x-component-props': {
 | 
					                    //   'x-component-props': {
 | 
				
			||||||
                        style: {
 | 
					                    //     style: {
 | 
				
			||||||
                          minWidth: 150,
 | 
					                    //       minWidth: 150,
 | 
				
			||||||
                        },
 | 
					                    //     },
 | 
				
			||||||
                        disabled: true,
 | 
					                    //     disabled: true,
 | 
				
			||||||
                      },
 | 
					                    //   },
 | 
				
			||||||
                    },
 | 
					                    // },
 | 
				
			||||||
                    [uid()]: {
 | 
					                    [uid()]: {
 | 
				
			||||||
                      type: 'void',
 | 
					                      type: 'void',
 | 
				
			||||||
                      name: 'action1',
 | 
					                      name: 'action1',
 | 
				
			||||||
                      title: '查看',
 | 
					                      title: '查看',
 | 
				
			||||||
                      'x-component': 'Menu.Action',
 | 
					                      'x-component': 'Menu.Action',
 | 
				
			||||||
 | 
					                      'x-component-props': {
 | 
				
			||||||
 | 
					                        style: {
 | 
				
			||||||
 | 
					                          minWidth: 150,
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
                      'x-designable-bar': 'Table.Action.DesignableBar',
 | 
					                      'x-designable-bar': 'Table.Action.DesignableBar',
 | 
				
			||||||
                      'x-action-type': 'view',
 | 
					                      'x-action-type': 'view',
 | 
				
			||||||
                      properties: {
 | 
					                      properties: {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
import React, { useState } from 'react';
 | 
					import React, { forwardRef, useState } from 'react';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  observer,
 | 
					  observer,
 | 
				
			||||||
  connect,
 | 
					  connect,
 | 
				
			||||||
@ -11,7 +11,7 @@ import {
 | 
				
			|||||||
  FormConsumer,
 | 
					  FormConsumer,
 | 
				
			||||||
} from '@formily/react';
 | 
					} from '@formily/react';
 | 
				
			||||||
import { ArrayCollapse, FormLayout } from '@formily/antd';
 | 
					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 '@formily/antd/lib/form-tab/style';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  Collapse,
 | 
					  Collapse,
 | 
				
			||||||
@ -32,6 +32,7 @@ import {
 | 
				
			|||||||
  DatabaseOutlined,
 | 
					  DatabaseOutlined,
 | 
				
			||||||
  PlusOutlined,
 | 
					  PlusOutlined,
 | 
				
			||||||
  CloseOutlined,
 | 
					  CloseOutlined,
 | 
				
			||||||
 | 
					  MenuOutlined,
 | 
				
			||||||
} from '@ant-design/icons';
 | 
					} from '@ant-design/icons';
 | 
				
			||||||
import cls from 'classnames';
 | 
					import cls from 'classnames';
 | 
				
			||||||
import './style.less';
 | 
					import './style.less';
 | 
				
			||||||
@ -39,8 +40,53 @@ import Modal from 'antd/lib/modal/Modal';
 | 
				
			|||||||
import { clone, cloneDeep, get } from 'lodash';
 | 
					import { clone, cloneDeep, get } from 'lodash';
 | 
				
			||||||
import { useEffect } from 'react';
 | 
					import { useEffect } from 'react';
 | 
				
			||||||
import { useRequest } from 'ahooks';
 | 
					import { useRequest } from 'ahooks';
 | 
				
			||||||
import { createOrUpdateCollection, deleteCollection } from '..';
 | 
					import {
 | 
				
			||||||
 | 
					  collectionMoveToAfter,
 | 
				
			||||||
 | 
					  createOrUpdateCollection,
 | 
				
			||||||
 | 
					  deleteCollection,
 | 
				
			||||||
 | 
					} from '..';
 | 
				
			||||||
import { useCollectionsContext } from '../../constate/Collections';
 | 
					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 (
 | 
				
			||||||
 | 
					    <SortableItem id={id} data={data}>
 | 
				
			||||||
 | 
					      <div
 | 
				
			||||||
 | 
					        style={{
 | 
				
			||||||
 | 
					          display: 'flex',
 | 
				
			||||||
 | 
					          // justifyContent: 'space-between',
 | 
				
			||||||
 | 
					          alignItems: 'center',
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <DragHandle
 | 
				
			||||||
 | 
					          component={forwardRef<any>((props, ref) => {
 | 
				
			||||||
 | 
					            return <MenuOutlined {...props} ref={ref} />;
 | 
				
			||||||
 | 
					          })}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					        <span style={{ width: 8 }} />
 | 
				
			||||||
 | 
					        {data.title}
 | 
				
			||||||
 | 
					        {showRemove && (
 | 
				
			||||||
 | 
					          <DeleteOutlined style={{ marginLeft: 'auto' }} onClick={onRemove} />
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </SortableItem>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const DatabaseCollection = observer((props) => {
 | 
					export const DatabaseCollection = observer((props) => {
 | 
				
			||||||
  const field = useField<Formily.Core.Models.ArrayField>();
 | 
					  const field = useField<Formily.Core.Models.ArrayField>();
 | 
				
			||||||
@ -51,6 +97,7 @@ export const DatabaseCollection = observer((props) => {
 | 
				
			|||||||
  const form = useForm();
 | 
					  const form = useForm();
 | 
				
			||||||
  const [newValue, setNewValue] = useState('');
 | 
					  const [newValue, setNewValue] = useState('');
 | 
				
			||||||
  const { loading, refresh, collections = [] } = useCollectionsContext();
 | 
					  const { loading, refresh, collections = [] } = useCollectionsContext();
 | 
				
			||||||
 | 
					  const [dragOverlayContent, setDragOverlayContent] = useState('');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
    field.setValue(collections);
 | 
					    field.setValue(collections);
 | 
				
			||||||
@ -87,101 +134,118 @@ export const DatabaseCollection = observer((props) => {
 | 
				
			|||||||
        }}
 | 
					        }}
 | 
				
			||||||
        title={
 | 
					        title={
 | 
				
			||||||
          <div style={{ textAlign: 'center' }}>
 | 
					          <div style={{ textAlign: 'center' }}>
 | 
				
			||||||
            <Select
 | 
					            <DndContext
 | 
				
			||||||
              loading={loading}
 | 
					              onDragStart={(event) => {
 | 
				
			||||||
              value={activeIndex}
 | 
					                setDragOverlayContent(event.active?.data?.current?.title || '');
 | 
				
			||||||
              style={{ minWidth: 300, textAlign: 'center' }}
 | 
					 | 
				
			||||||
              onChange={(value) => {
 | 
					 | 
				
			||||||
                setActiveIndex(value as any);
 | 
					 | 
				
			||||||
              }}
 | 
					              }}
 | 
				
			||||||
              open={open}
 | 
					              onDragEnd={async (event) => {
 | 
				
			||||||
              onDropdownVisibleChange={setOpen}
 | 
					                const sourceName = event.active?.data?.current?.name;
 | 
				
			||||||
              optionLabelProp={'label'}
 | 
					                const targetName = event.over?.data?.current?.name;
 | 
				
			||||||
              dropdownRender={(menu) => {
 | 
					                console.log({ sourceName, targetName });
 | 
				
			||||||
                return (
 | 
					                await collectionMoveToAfter(sourceName, targetName);
 | 
				
			||||||
                  <div>
 | 
					                await refresh();
 | 
				
			||||||
                    {menu}
 | 
					 | 
				
			||||||
                    <Divider style={{ margin: '5px 0 4px' }} />
 | 
					 | 
				
			||||||
                    <div
 | 
					 | 
				
			||||||
                      style={{
 | 
					 | 
				
			||||||
                        cursor: 'pointer',
 | 
					 | 
				
			||||||
                        padding: '5px 12px',
 | 
					 | 
				
			||||||
                      }}
 | 
					 | 
				
			||||||
                    >
 | 
					 | 
				
			||||||
                      <Input.Search
 | 
					 | 
				
			||||||
                        size={'middle'}
 | 
					 | 
				
			||||||
                        placeholder={'新增数据表'}
 | 
					 | 
				
			||||||
                        enterButton={<PlusOutlined />}
 | 
					 | 
				
			||||||
                        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();
 | 
					 | 
				
			||||||
                        }}
 | 
					 | 
				
			||||||
                      />
 | 
					 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                  </div>
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
              }}
 | 
					              }}
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              {field.value?.map((item, index) => {
 | 
					              {createPortal(
 | 
				
			||||||
                return (
 | 
					                <DragOverlay
 | 
				
			||||||
                  <Select.Option
 | 
					                  zIndex={2000}
 | 
				
			||||||
                    key={index}
 | 
					                  style={{ pointerEvents: 'none', whiteSpace: 'nowrap' }}
 | 
				
			||||||
                    value={index}
 | 
					                >
 | 
				
			||||||
                    label={`${item.title || '未命名'}${
 | 
					                  {dragOverlayContent}
 | 
				
			||||||
                      item.unsaved ? ' (未保存)' : ''
 | 
					                </DragOverlay>,
 | 
				
			||||||
                    }`}
 | 
					                document.body,
 | 
				
			||||||
                  >
 | 
					              )}
 | 
				
			||||||
                    <div
 | 
					              <Select
 | 
				
			||||||
                      style={{
 | 
					                loading={loading}
 | 
				
			||||||
                        display: 'flex',
 | 
					                value={activeIndex}
 | 
				
			||||||
                        justifyContent: 'space-between',
 | 
					                style={{ minWidth: 300, textAlign: 'center' }}
 | 
				
			||||||
                        alignItems: 'center',
 | 
					                onChange={(value) => {
 | 
				
			||||||
                      }}
 | 
					                  setActiveIndex(value as any);
 | 
				
			||||||
                    >
 | 
					                }}
 | 
				
			||||||
                      {item.title || '未命名'}{' '}
 | 
					                open={open}
 | 
				
			||||||
                      {item.unsaved ? '(未保存)' : ''}
 | 
					                onDropdownVisibleChange={setOpen}
 | 
				
			||||||
                      {item.privilege !== 'undelete' && (
 | 
					                optionLabelProp={'label'}
 | 
				
			||||||
                        <DeleteOutlined
 | 
					                dropdownRender={(menu) => {
 | 
				
			||||||
                          onClick={async (e) => {
 | 
					                  return (
 | 
				
			||||||
                            e.stopPropagation();
 | 
					                    <div>
 | 
				
			||||||
                            field.remove(index);
 | 
					                      {menu}
 | 
				
			||||||
                            if (field.value?.length === 0) {
 | 
					                      <Divider style={{ margin: '5px 0 4px' }} />
 | 
				
			||||||
                              field.push({
 | 
					                      <div
 | 
				
			||||||
                                name: `t_${uid()}`,
 | 
					                        style={{
 | 
				
			||||||
                                unsaved: true,
 | 
					                          cursor: 'pointer',
 | 
				
			||||||
                                fields: getDefaultFields(),
 | 
					                          padding: '5px 12px',
 | 
				
			||||||
                              });
 | 
					                        }}
 | 
				
			||||||
                            }
 | 
					                      >
 | 
				
			||||||
                            if (activeIndex === index) {
 | 
					                        <Input.Search
 | 
				
			||||||
                              setActiveIndex(0);
 | 
					                          size={'middle'}
 | 
				
			||||||
                            } else if (activeIndex > index) {
 | 
					                          placeholder={'新增数据表'}
 | 
				
			||||||
                              setActiveIndex(activeIndex - 1);
 | 
					                          enterButton={<PlusOutlined />}
 | 
				
			||||||
                            }
 | 
					                          value={newValue}
 | 
				
			||||||
                            if (item.name) {
 | 
					                          onChange={(e) => {
 | 
				
			||||||
                              await deleteCollection(item.name);
 | 
					                            setNewValue(e.target.value);
 | 
				
			||||||
                              await refresh();
 | 
					                          }}
 | 
				
			||||||
                            }
 | 
					                          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();
 | 
				
			||||||
                          }}
 | 
					                          }}
 | 
				
			||||||
                        />
 | 
					                        />
 | 
				
			||||||
                      )}
 | 
					                      </div>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                  </Select.Option>
 | 
					                  );
 | 
				
			||||||
                );
 | 
					                }}
 | 
				
			||||||
              })}
 | 
					              >
 | 
				
			||||||
            </Select>
 | 
					                {field.value?.map((item, index) => {
 | 
				
			||||||
 | 
					                  return (
 | 
				
			||||||
 | 
					                    <Select.Option
 | 
				
			||||||
 | 
					                      key={index}
 | 
				
			||||||
 | 
					                      value={index}
 | 
				
			||||||
 | 
					                      label={`${item.title || '未命名'}${
 | 
				
			||||||
 | 
					                        item.unsaved ? ' (未保存)' : ''
 | 
				
			||||||
 | 
					                      }`}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      <SelectOption
 | 
				
			||||||
 | 
					                        id={item.name}
 | 
				
			||||||
 | 
					                        title={item.title || '未命名'}
 | 
				
			||||||
 | 
					                        data={{
 | 
				
			||||||
 | 
					                          title: item.title,
 | 
				
			||||||
 | 
					                          name: item.name,
 | 
				
			||||||
 | 
					                        }}
 | 
				
			||||||
 | 
					                        showRemove={item.privilege !== 'undelete'}
 | 
				
			||||||
 | 
					                        onRemove={async (e) => {
 | 
				
			||||||
 | 
					                          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();
 | 
				
			||||||
 | 
					                          }
 | 
				
			||||||
 | 
					                        }}
 | 
				
			||||||
 | 
					                      />
 | 
				
			||||||
 | 
					                    </Select.Option>
 | 
				
			||||||
 | 
					                  );
 | 
				
			||||||
 | 
					                })}
 | 
				
			||||||
 | 
					              </Select>
 | 
				
			||||||
 | 
					            </DndContext>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        visible={visible}
 | 
					        visible={visible}
 | 
				
			||||||
@ -228,88 +292,124 @@ export const DatabaseField: any = observer((props) => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }, []);
 | 
					  }, []);
 | 
				
			||||||
  const [activeKey, setActiveKey] = useState(null);
 | 
					  const [activeKey, setActiveKey] = useState(null);
 | 
				
			||||||
 | 
					  const [dragOverlayContent, setDragOverlayContent] = useState('');
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
      <Collapse
 | 
					      <DndContext
 | 
				
			||||||
        activeKey={activeKey}
 | 
					        onDragStart={(event) => {
 | 
				
			||||||
        onChange={(key) => {
 | 
					          setDragOverlayContent(event.active?.data?.current?.title || '');
 | 
				
			||||||
          setActiveKey(key);
 | 
					        }}
 | 
				
			||||||
 | 
					        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) => {
 | 
					        {createPortal(
 | 
				
			||||||
          if (!item.interface) {
 | 
					          <DragOverlay
 | 
				
			||||||
            return;
 | 
					            zIndex={2000}
 | 
				
			||||||
          }
 | 
					            style={{ pointerEvents: 'none', whiteSpace: 'nowrap' }}
 | 
				
			||||||
          const schema = cloneDeep(interfaces.get(item.interface));
 | 
					          >
 | 
				
			||||||
          if (!schema) {
 | 
					            {dragOverlayContent}
 | 
				
			||||||
            console.error('schema invalid');
 | 
					          </DragOverlay>,
 | 
				
			||||||
            return;
 | 
					          document.body,
 | 
				
			||||||
          }
 | 
					        )}
 | 
				
			||||||
          const path = field.address.concat(index);
 | 
					        <Collapse
 | 
				
			||||||
          const errors = field.form.queryFeedbacks({
 | 
					          activeKey={activeKey}
 | 
				
			||||||
            type: 'error',
 | 
					          onChange={(key) => {
 | 
				
			||||||
            address: `*(${path},${path}.*)`,
 | 
					            setActiveKey(key);
 | 
				
			||||||
          });
 | 
					          }}
 | 
				
			||||||
          return (
 | 
					          className={cls({ empty: !field.value?.length })}
 | 
				
			||||||
            <Collapse.Panel
 | 
					          accordion
 | 
				
			||||||
              header={
 | 
					        >
 | 
				
			||||||
                <>
 | 
					          {field.value?.map((item, index) => {
 | 
				
			||||||
                  {(item.uiSchema && item.uiSchema.title) || (
 | 
					            if (!item.interface) {
 | 
				
			||||||
                    <i style={{ color: 'rgba(0, 0, 0, 0.25)' }}>未命名</i>
 | 
					              return;
 | 
				
			||||||
                  )}{' '}
 | 
					            }
 | 
				
			||||||
                  <Tag
 | 
					            const schema = cloneDeep(interfaces.get(item.interface));
 | 
				
			||||||
                    className={item.privilege ? cls(item.privilege) : undefined}
 | 
					            if (!schema) {
 | 
				
			||||||
 | 
					              console.error('schema invalid');
 | 
				
			||||||
 | 
					              return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            const path = field.address.concat(index);
 | 
				
			||||||
 | 
					            const errors = field.form.queryFeedbacks({
 | 
				
			||||||
 | 
					              type: 'error',
 | 
				
			||||||
 | 
					              address: `*(${path},${path}.*)`,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            return (
 | 
				
			||||||
 | 
					              <Collapse.Panel
 | 
				
			||||||
 | 
					                header={
 | 
				
			||||||
 | 
					                  <SortableItem
 | 
				
			||||||
 | 
					                    id={item.key}
 | 
				
			||||||
 | 
					                    className={'sortable-item'}
 | 
				
			||||||
 | 
					                    data={{
 | 
				
			||||||
 | 
					                      index,
 | 
				
			||||||
 | 
					                      title: item?.uiSchema?.title,
 | 
				
			||||||
 | 
					                    }}
 | 
				
			||||||
                  >
 | 
					                  >
 | 
				
			||||||
                    {schema.title}
 | 
					                    <DragHandle className={'drag-handle'} />
 | 
				
			||||||
                  </Tag>
 | 
					                    {(item.uiSchema && item.uiSchema.title) || (
 | 
				
			||||||
                  <span style={{ color: 'rgba(0, 0, 0, 0.25)', fontSize: 14 }}>
 | 
					                      <i style={{ color: 'rgba(0, 0, 0, 0.25)' }}>未命名</i>
 | 
				
			||||||
                    {item.name}
 | 
					                    )}{' '}
 | 
				
			||||||
                  </span>
 | 
					                    <Tag
 | 
				
			||||||
                </>
 | 
					                      className={
 | 
				
			||||||
              }
 | 
					                        item.privilege ? cls(item.privilege) : undefined
 | 
				
			||||||
              extra={
 | 
					                      }
 | 
				
			||||||
                item.privilege === 'undelete'
 | 
					                    >
 | 
				
			||||||
                  ? []
 | 
					                      {schema.title}
 | 
				
			||||||
                  : [
 | 
					                    </Tag>
 | 
				
			||||||
                      <Badge key={'1'} count={errors.length} />,
 | 
					                    <span
 | 
				
			||||||
                      <DeleteOutlined
 | 
					                      style={{ color: 'rgba(0, 0, 0, 0.25)', fontSize: 14 }}
 | 
				
			||||||
                        key={'2'}
 | 
					                    >
 | 
				
			||||||
                        onClick={(e) => {
 | 
					                      {item.name}
 | 
				
			||||||
                          e.stopPropagation();
 | 
					                    </span>
 | 
				
			||||||
                          field.remove(index);
 | 
					                  </SortableItem>
 | 
				
			||||||
                        }}
 | 
					 | 
				
			||||||
                      />,
 | 
					 | 
				
			||||||
                    ]
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
              key={item.key}
 | 
					 | 
				
			||||||
            >
 | 
					 | 
				
			||||||
              <RecursionField
 | 
					 | 
				
			||||||
                key={`${item.key}_${index}`}
 | 
					 | 
				
			||||||
                name={index}
 | 
					 | 
				
			||||||
                schema={
 | 
					 | 
				
			||||||
                  new Schema({
 | 
					 | 
				
			||||||
                    type: 'object',
 | 
					 | 
				
			||||||
                    properties: {
 | 
					 | 
				
			||||||
                      layout: {
 | 
					 | 
				
			||||||
                        type: 'void',
 | 
					 | 
				
			||||||
                        'x-component': 'FormLayout',
 | 
					 | 
				
			||||||
                        'x-component-props': {
 | 
					 | 
				
			||||||
                          layout: 'vertical',
 | 
					 | 
				
			||||||
                          // labelCol: 4,
 | 
					 | 
				
			||||||
                          // wrapperCol: 20,
 | 
					 | 
				
			||||||
                        },
 | 
					 | 
				
			||||||
                        properties: schema.properties,
 | 
					 | 
				
			||||||
                      },
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                  })
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              />
 | 
					                extra={
 | 
				
			||||||
            </Collapse.Panel>
 | 
					                  item.privilege === 'undelete'
 | 
				
			||||||
          );
 | 
					                    ? []
 | 
				
			||||||
        })}
 | 
					                    : [
 | 
				
			||||||
      </Collapse>
 | 
					                        <Badge key={'1'} count={errors.length} />,
 | 
				
			||||||
 | 
					                        <DeleteOutlined
 | 
				
			||||||
 | 
					                          key={'2'}
 | 
				
			||||||
 | 
					                          onClick={(e) => {
 | 
				
			||||||
 | 
					                            e.stopPropagation();
 | 
				
			||||||
 | 
					                            field.remove(index);
 | 
				
			||||||
 | 
					                          }}
 | 
				
			||||||
 | 
					                        />,
 | 
				
			||||||
 | 
					                      ]
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                key={item.key}
 | 
				
			||||||
 | 
					                forceRender
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <RecursionField
 | 
				
			||||||
 | 
					                  key={`${item.key}_${index}`}
 | 
				
			||||||
 | 
					                  name={index}
 | 
				
			||||||
 | 
					                  schema={
 | 
				
			||||||
 | 
					                    new Schema({
 | 
				
			||||||
 | 
					                      type: 'object',
 | 
				
			||||||
 | 
					                      properties: {
 | 
				
			||||||
 | 
					                        layout: {
 | 
				
			||||||
 | 
					                          type: 'void',
 | 
				
			||||||
 | 
					                          'x-component': 'FormLayout',
 | 
				
			||||||
 | 
					                          'x-component-props': {
 | 
				
			||||||
 | 
					                            layout: 'vertical',
 | 
				
			||||||
 | 
					                            // labelCol: 4,
 | 
				
			||||||
 | 
					                            // wrapperCol: 20,
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                          properties: schema.properties,
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              </Collapse.Panel>
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					          })}
 | 
				
			||||||
 | 
					        </Collapse>
 | 
				
			||||||
 | 
					      </DndContext>
 | 
				
			||||||
      <Dropdown
 | 
					      <Dropdown
 | 
				
			||||||
        placement={'bottomCenter'}
 | 
					        placement={'bottomCenter'}
 | 
				
			||||||
        overlayClassName={'all-fields'}
 | 
					        overlayClassName={'all-fields'}
 | 
				
			||||||
 | 
				
			|||||||
@ -25,4 +25,29 @@
 | 
				
			|||||||
.ant-tag.disabled {
 | 
					.ant-tag.disabled {
 | 
				
			||||||
  color: rgba(0, 0, 0, 0.25);
 | 
					  color: rgba(0, 0, 0, 0.25);
 | 
				
			||||||
  cursor: not-allowed;
 | 
					  cursor: not-allowed;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ant-collapse-header {
 | 
				
			||||||
 | 
					  position: relative;
 | 
				
			||||||
 | 
					  &:hover {
 | 
				
			||||||
 | 
					    .drag-handle {
 | 
				
			||||||
 | 
					      opacity: 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .drag-handle {
 | 
				
			||||||
 | 
					    opacity: 0;
 | 
				
			||||||
 | 
					    margin-right: 6px;
 | 
				
			||||||
 | 
					    background-color: #fafafa;
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					    z-index: 3;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .ant-collapse-arrow {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    top: 18px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .ant-collapse-extra {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    right: 16px;
 | 
				
			||||||
 | 
					    top: 12px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -60,6 +60,20 @@ export async function createSchema(schema: ISchema) {
 | 
				
			|||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function collectionMoveToAfter(source, target) {
 | 
				
			||||||
 | 
					  if (source && target) {
 | 
				
			||||||
 | 
					    return request(`collections:sort/${source}`, {
 | 
				
			||||||
 | 
					      method: 'post',
 | 
				
			||||||
 | 
					      data: {
 | 
				
			||||||
 | 
					        field: 'sort',
 | 
				
			||||||
 | 
					        target: {
 | 
				
			||||||
 | 
					          name: target,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export async function updateSchema(schema: ISchema) {
 | 
					export async function updateSchema(schema: ISchema) {
 | 
				
			||||||
  if (!schema) {
 | 
					  if (!schema) {
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
				
			|||||||
@ -46,6 +46,9 @@ export const Tabs: any = observer((props: any) => {
 | 
				
			|||||||
    if (!path1 || !path2) {
 | 
					    if (!path1 || !path2) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (path1.join('.') === path2.join('.')) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    const data = findPropertyByPath(root, path1);
 | 
					    const data = findPropertyByPath(root, path1);
 | 
				
			||||||
    if (!data) {
 | 
					    if (!data) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@ import { cloneDeep, omit } from 'lodash';
 | 
				
			|||||||
export const findAll = async (ctx: actions.Context, next: actions.Next) => {
 | 
					export const findAll = async (ctx: actions.Context, next: actions.Next) => {
 | 
				
			||||||
  const Collection = ctx.db.getModel('collections');
 | 
					  const Collection = ctx.db.getModel('collections');
 | 
				
			||||||
  const collections = await Collection.findAll(Collection.parseApiJson({
 | 
					  const collections = await Collection.findAll(Collection.parseApiJson({
 | 
				
			||||||
    sort: '-created_at',
 | 
					    sort: 'sort',
 | 
				
			||||||
  }));
 | 
					  }));
 | 
				
			||||||
  const data = [];
 | 
					  const data = [];
 | 
				
			||||||
  for (const collection of collections) {
 | 
					  for (const collection of collections) {
 | 
				
			||||||
@ -29,6 +29,14 @@ export const createOrUpdate = async (ctx: actions.Context, next: actions.Next) =
 | 
				
			|||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      await collection.update(values);
 | 
					      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.updateAssociations(values);
 | 
				
			||||||
    await collection.migrate();
 | 
					    await collection.migrate();
 | 
				
			||||||
  } catch (error) {
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user