updates
This commit is contained in:
		
							parent
							
								
									97ca17bc10
								
							
						
					
					
						commit
						e8399e167e
					
				@ -17,7 +17,7 @@ import {
 | 
			
		||||
  useHistory,
 | 
			
		||||
  Redirect,
 | 
			
		||||
} from 'react-router-dom';
 | 
			
		||||
import { SchemaRenderer } from '../../schemas';
 | 
			
		||||
import { CollectionContextProvider, PageTitleContextProvider, SchemaRenderer, usePageTitleContext } from '../../schemas';
 | 
			
		||||
import { useRequest } from 'ahooks';
 | 
			
		||||
import './style.less';
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,7 @@ function LayoutWithMenu({ schema }) {
 | 
			
		||||
  const location = useLocation();
 | 
			
		||||
  const sideMenuRef = useRef();
 | 
			
		||||
  const [activeKey, setActiveKey] = useState(match.params.name);
 | 
			
		||||
  const [,setPageTitle] = usePageTitleContext();
 | 
			
		||||
  const onSelect = (info) => {
 | 
			
		||||
    console.log('LayoutWithMenu', info);
 | 
			
		||||
    if (!info.schema) {
 | 
			
		||||
@ -39,6 +40,9 @@ function LayoutWithMenu({ schema }) {
 | 
			
		||||
      setActiveKey(null);
 | 
			
		||||
    } else {
 | 
			
		||||
      setActiveKey(info.schema.key);
 | 
			
		||||
      if (info.schema.title) {
 | 
			
		||||
        setPageTitle(info.schema.title);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  console.log({ match });
 | 
			
		||||
@ -98,7 +102,13 @@ export function AdminLayout({ route }: any) {
 | 
			
		||||
    return <Spin />;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return <LayoutWithMenu schema={data} />;
 | 
			
		||||
  return (
 | 
			
		||||
    <CollectionContextProvider>
 | 
			
		||||
      <PageTitleContextProvider>
 | 
			
		||||
        <LayoutWithMenu schema={data} />
 | 
			
		||||
      </PageTitleContextProvider>
 | 
			
		||||
    </CollectionContextProvider>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default AdminLayout;
 | 
			
		||||
 | 
			
		||||
@ -46,8 +46,10 @@ import { TimePicker } from '../../schemas/time-picker';
 | 
			
		||||
import { Upload } from '../../schemas/upload';
 | 
			
		||||
import { FormItem } from '../../schemas/form-item';
 | 
			
		||||
import { BlockItem } from '../../schemas/block-item';
 | 
			
		||||
import { CardItem } from '../../schemas/card-item';
 | 
			
		||||
import { DragAndDrop } from '../../schemas/drag-and-drop';
 | 
			
		||||
import { TreeSelect } from '../../schemas/tree-select';
 | 
			
		||||
import { Page } from '../../schemas/page';
 | 
			
		||||
 | 
			
		||||
export const BlockContext = createContext({ dragRef: null });
 | 
			
		||||
 | 
			
		||||
@ -59,11 +61,14 @@ interface DesignableContextProps {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const SchemaField = createSchemaField({
 | 
			
		||||
  scope: {},
 | 
			
		||||
  scope: {
 | 
			
		||||
    Table,
 | 
			
		||||
  },
 | 
			
		||||
  components: {
 | 
			
		||||
    Card,
 | 
			
		||||
    Div,
 | 
			
		||||
    Space,
 | 
			
		||||
    Page,
 | 
			
		||||
 | 
			
		||||
    ArrayCollapse,
 | 
			
		||||
    ArrayTable,
 | 
			
		||||
@ -73,6 +78,7 @@ export const SchemaField = createSchemaField({
 | 
			
		||||
    DragAndDrop,
 | 
			
		||||
 | 
			
		||||
    BlockItem,
 | 
			
		||||
    CardItem,
 | 
			
		||||
    FormItem,
 | 
			
		||||
 | 
			
		||||
    Action,
 | 
			
		||||
@ -173,6 +179,14 @@ function setKeys(schema: ISchema, parentKey = null) {
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useSchemaComponent(component: string) {
 | 
			
		||||
  if (!component) {
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
  const options = useContext(SchemaOptionsContext);
 | 
			
		||||
  return get(options.components, component);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function useDesignable(path?: any) {
 | 
			
		||||
  const { schema = new Schema({}), refresh } = useContext(DesignableContext);
 | 
			
		||||
  const schemaPath = path || useSchemaPath();
 | 
			
		||||
 | 
			
		||||
@ -46,9 +46,17 @@ import {
 | 
			
		||||
  DownOutlined,
 | 
			
		||||
  DatabaseOutlined,
 | 
			
		||||
} from '@ant-design/icons';
 | 
			
		||||
import { createSchema, useDesignable, useSchemaPath } from '../';
 | 
			
		||||
import {
 | 
			
		||||
  createOrUpdateCollection,
 | 
			
		||||
  createSchema,
 | 
			
		||||
  request,
 | 
			
		||||
  useCollectionContext,
 | 
			
		||||
  useDesignable,
 | 
			
		||||
  useSchemaPath,
 | 
			
		||||
} from '../';
 | 
			
		||||
import { uid } from '@formily/shared';
 | 
			
		||||
import { request } from '../../demos/api';
 | 
			
		||||
import { useRequest } from 'ahooks';
 | 
			
		||||
import { SchemaField } from '../../components/schema-renderer';
 | 
			
		||||
 | 
			
		||||
const generateGridBlock = (schema: ISchema) => {
 | 
			
		||||
  const name = schema.name || uid();
 | 
			
		||||
@ -68,6 +76,10 @@ const generateGridBlock = (schema: ISchema) => {
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const isGrid = (schema: Schema) => {
 | 
			
		||||
  return schema['x-component'] === 'Grid';
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const isGridBlock = (schema: Schema) => {
 | 
			
		||||
  if (schema.parent['x-component'] !== 'Grid.Col') {
 | 
			
		||||
    return false;
 | 
			
		||||
@ -83,14 +95,519 @@ const isGridBlock = (schema: Schema) => {
 | 
			
		||||
  return true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function generateCardItemSchema(component) {
 | 
			
		||||
  const defaults = {
 | 
			
		||||
    Markdown: {
 | 
			
		||||
      type: 'string',
 | 
			
		||||
      default: '这是一段演示文字',
 | 
			
		||||
      'x-designable-bar': 'Markdown.DesignableBar',
 | 
			
		||||
      'x-decorator': 'CardItem',
 | 
			
		||||
      'x-read-pretty': true,
 | 
			
		||||
      'x-component': 'Markdown',
 | 
			
		||||
      'x-component-props': {
 | 
			
		||||
        savedInSchema: true,
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    Table: {
 | 
			
		||||
      type: 'array',
 | 
			
		||||
      'x-designable-bar': 'Table.DesignableBar',
 | 
			
		||||
      'x-decorator': 'CardItem',
 | 
			
		||||
      'x-component': 'Table',
 | 
			
		||||
      default: [
 | 
			
		||||
        { key: uid(), field1: uid(), field2: uid() },
 | 
			
		||||
        { key: uid(), field1: uid(), field2: uid() },
 | 
			
		||||
        { key: uid(), field1: uid(), field2: uid() },
 | 
			
		||||
        { key: uid(), field1: uid(), field2: uid() },
 | 
			
		||||
        { key: uid(), field1: uid(), field2: uid() },
 | 
			
		||||
        { key: uid(), field1: uid(), field2: uid() },
 | 
			
		||||
        { key: uid(), field1: uid(), field2: uid() },
 | 
			
		||||
        { key: uid(), field1: uid(), field2: uid() },
 | 
			
		||||
        { key: uid(), field1: uid(), field2: uid() },
 | 
			
		||||
        { key: uid(), field1: uid(), field2: uid() },
 | 
			
		||||
        { key: uid(), field1: uid(), field2: uid() },
 | 
			
		||||
        { key: uid(), field1: uid(), field2: uid() },
 | 
			
		||||
      ],
 | 
			
		||||
      'x-component-props': {
 | 
			
		||||
        rowKey: 'key',
 | 
			
		||||
      },
 | 
			
		||||
      properties: {
 | 
			
		||||
        [`action_bar_${uid()}`]: {
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          'x-component': 'Table.ActionBar',
 | 
			
		||||
          properties: {
 | 
			
		||||
            action1: {
 | 
			
		||||
              type: 'void',
 | 
			
		||||
              name: 'action1',
 | 
			
		||||
              title: '筛选',
 | 
			
		||||
              'x-component': 'Action',
 | 
			
		||||
              properties: {
 | 
			
		||||
                popover1: {
 | 
			
		||||
                  type: 'void',
 | 
			
		||||
                  title: '弹窗标题',
 | 
			
		||||
                  'x-decorator': 'Form',
 | 
			
		||||
                  'x-component': 'Action.Popover',
 | 
			
		||||
                  'x-component-props': {},
 | 
			
		||||
                  properties: {
 | 
			
		||||
                    filter: {
 | 
			
		||||
                      name: 'filter',
 | 
			
		||||
                      type: 'object',
 | 
			
		||||
                      'x-component': 'Filter',
 | 
			
		||||
                      properties: {
 | 
			
		||||
                        column1: {
 | 
			
		||||
                          type: 'void',
 | 
			
		||||
                          title: '字段1',
 | 
			
		||||
                          'x-component': 'Filter.Column',
 | 
			
		||||
                          'x-component-props': {
 | 
			
		||||
                            operations: [
 | 
			
		||||
                              { label: '等于', value: 'eq' },
 | 
			
		||||
                              { label: '不等于', value: 'ne' },
 | 
			
		||||
                            ],
 | 
			
		||||
                          },
 | 
			
		||||
                          properties: {
 | 
			
		||||
                            field1: {
 | 
			
		||||
                              type: 'string',
 | 
			
		||||
                              'x-component': 'Input',
 | 
			
		||||
                            },
 | 
			
		||||
                          },
 | 
			
		||||
                        },
 | 
			
		||||
                        column2: {
 | 
			
		||||
                          type: 'void',
 | 
			
		||||
                          title: '字段2',
 | 
			
		||||
                          'x-component': 'Filter.Column',
 | 
			
		||||
                          'x-component-props': {
 | 
			
		||||
                            operations: [
 | 
			
		||||
                              { label: '大于', value: 'gt' },
 | 
			
		||||
                              { label: '小于', value: 'lt' },
 | 
			
		||||
                              {
 | 
			
		||||
                                label: '非空',
 | 
			
		||||
                                value: 'notNull',
 | 
			
		||||
                                noValue: true,
 | 
			
		||||
                              },
 | 
			
		||||
                            ],
 | 
			
		||||
                          },
 | 
			
		||||
                          properties: {
 | 
			
		||||
                            field1: {
 | 
			
		||||
                              type: 'number',
 | 
			
		||||
                              'x-component': 'InputNumber',
 | 
			
		||||
                            },
 | 
			
		||||
                          },
 | 
			
		||||
                        },
 | 
			
		||||
                      },
 | 
			
		||||
                    },
 | 
			
		||||
                  },
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            action2: {
 | 
			
		||||
              type: 'void',
 | 
			
		||||
              name: 'action1',
 | 
			
		||||
              title: '新增',
 | 
			
		||||
              'x-component': 'Action',
 | 
			
		||||
              'x-designable-bar': 'Action.DesignableBar',
 | 
			
		||||
              properties: {
 | 
			
		||||
                drawer1: {
 | 
			
		||||
                  type: 'void',
 | 
			
		||||
                  title: '抽屉标题',
 | 
			
		||||
                  'x-decorator': 'Form',
 | 
			
		||||
                  'x-component': 'Action.Modal',
 | 
			
		||||
                  'x-component-props': {
 | 
			
		||||
                    useOkAction: '{{ Table.useTableCreateAction }}',
 | 
			
		||||
                  },
 | 
			
		||||
                  properties: {
 | 
			
		||||
                    field1: {
 | 
			
		||||
                      type: 'string',
 | 
			
		||||
                      title: '字段1',
 | 
			
		||||
                      'x-decorator': 'FormItem',
 | 
			
		||||
                      'x-component': 'Input',
 | 
			
		||||
                    },
 | 
			
		||||
                    field2: {
 | 
			
		||||
                      type: 'string',
 | 
			
		||||
                      title: '字段2',
 | 
			
		||||
                      'x-decorator': 'FormItem',
 | 
			
		||||
                      'x-component': 'Input',
 | 
			
		||||
                    },
 | 
			
		||||
                  },
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            action3: {
 | 
			
		||||
              type: 'void',
 | 
			
		||||
              name: 'action1',
 | 
			
		||||
              title: '删除',
 | 
			
		||||
              'x-component': 'Action',
 | 
			
		||||
              'x-component-props': {
 | 
			
		||||
                useAction: '{{ Table.useTableDestroyAction }}',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        [`a_${uid()}`]: {
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          'x-component': 'Table.ActionBar',
 | 
			
		||||
          'x-component-props': {
 | 
			
		||||
            align: 'bottom',
 | 
			
		||||
          },
 | 
			
		||||
          properties: {
 | 
			
		||||
            pagination: {
 | 
			
		||||
              type: 'void',
 | 
			
		||||
              'x-component': 'Table.Pagination',
 | 
			
		||||
              'x-component-props': {},
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        [`column_${uid()}`]: {
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          title: '排序',
 | 
			
		||||
          'x-component': 'Table.Column',
 | 
			
		||||
          properties: {
 | 
			
		||||
            sort: {
 | 
			
		||||
              type: 'void',
 | 
			
		||||
              'x-component': 'Table.SortHandle',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        [`column_${uid()}`]: {
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          title: '序号',
 | 
			
		||||
          'x-component': 'Table.Column',
 | 
			
		||||
          properties: {
 | 
			
		||||
            index: {
 | 
			
		||||
              type: 'void',
 | 
			
		||||
              'x-component': 'Table.Index',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        [`column_${uid()}`]: {
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          title: '字段1',
 | 
			
		||||
          'x-component': 'Table.Column',
 | 
			
		||||
          'x-component-props': {
 | 
			
		||||
            // title: 'z1',
 | 
			
		||||
          },
 | 
			
		||||
          'x-designable-bar': 'Table.Column.DesignableBar',
 | 
			
		||||
          properties: {
 | 
			
		||||
            field1: {
 | 
			
		||||
              type: 'string',
 | 
			
		||||
              required: true,
 | 
			
		||||
              'x-read-pretty': true,
 | 
			
		||||
              'x-decorator-props': {
 | 
			
		||||
                feedbackLayout: 'popover',
 | 
			
		||||
              },
 | 
			
		||||
              'x-decorator': 'FormItem',
 | 
			
		||||
              'x-component': 'Input',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        [`column_${uid()}`]: {
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          title: '字段2',
 | 
			
		||||
          'x-component': 'Table.Column',
 | 
			
		||||
          'x-designable-bar': 'Table.Column.DesignableBar',
 | 
			
		||||
          properties: {
 | 
			
		||||
            field2: {
 | 
			
		||||
              type: 'string',
 | 
			
		||||
              // title: '字段2',
 | 
			
		||||
              required: true,
 | 
			
		||||
              'x-read-pretty': true,
 | 
			
		||||
              'x-decorator-props': {
 | 
			
		||||
                feedbackLayout: 'popover',
 | 
			
		||||
              },
 | 
			
		||||
              'x-decorator': 'FormItem',
 | 
			
		||||
              'x-component': 'Input',
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        [`column_${uid()}`]: {
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          title: '操作',
 | 
			
		||||
          'x-component': 'Table.Column',
 | 
			
		||||
          properties: {
 | 
			
		||||
            [uid()]: {
 | 
			
		||||
              type: 'void',
 | 
			
		||||
              name: 'action1',
 | 
			
		||||
              title: '查看',
 | 
			
		||||
              'x-component': 'Action',
 | 
			
		||||
              'x-designable-bar': 'Table.Action.DesignableBar',
 | 
			
		||||
              properties: {
 | 
			
		||||
                drawer1: {
 | 
			
		||||
                  type: 'void',
 | 
			
		||||
                  title: '查看',
 | 
			
		||||
                  'x-component': 'Action.Modal',
 | 
			
		||||
                  'x-component-props': {},
 | 
			
		||||
                  properties: {
 | 
			
		||||
                    [uid()]: {
 | 
			
		||||
                      type: 'void',
 | 
			
		||||
                      'x-component': 'Tabs',
 | 
			
		||||
                      properties: {
 | 
			
		||||
                        tab1: {
 | 
			
		||||
                          type: 'void',
 | 
			
		||||
                          'x-component': 'Tabs.TabPane',
 | 
			
		||||
                          'x-component-props': {
 | 
			
		||||
                            tab: 'Tab1',
 | 
			
		||||
                          },
 | 
			
		||||
                          properties: {
 | 
			
		||||
                            aaa: {
 | 
			
		||||
                              type: 'string',
 | 
			
		||||
                              title: 'AAA',
 | 
			
		||||
                              'x-decorator': 'FormItem',
 | 
			
		||||
                              required: true,
 | 
			
		||||
                              'x-component': 'Input',
 | 
			
		||||
                            },
 | 
			
		||||
                          },
 | 
			
		||||
                        },
 | 
			
		||||
                        tab2: {
 | 
			
		||||
                          type: 'void',
 | 
			
		||||
                          'x-component': 'Tabs.TabPane',
 | 
			
		||||
                          'x-component-props': {
 | 
			
		||||
                            tab: 'Tab2',
 | 
			
		||||
                          },
 | 
			
		||||
                          properties: {
 | 
			
		||||
                            bbb: {
 | 
			
		||||
                              type: 'string',
 | 
			
		||||
                              title: 'BBB',
 | 
			
		||||
                              'x-decorator': 'FormItem',
 | 
			
		||||
                              required: true,
 | 
			
		||||
                              'x-component': 'Input',
 | 
			
		||||
                            },
 | 
			
		||||
                          },
 | 
			
		||||
                        },
 | 
			
		||||
                      },
 | 
			
		||||
                    },
 | 
			
		||||
                  },
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            [uid()]: {
 | 
			
		||||
              type: 'void',
 | 
			
		||||
              name: 'action1',
 | 
			
		||||
              title: '修改',
 | 
			
		||||
              'x-component': 'Action',
 | 
			
		||||
              'x-designable-bar': 'Table.Action.DesignableBar',
 | 
			
		||||
              properties: {
 | 
			
		||||
                drawer1: {
 | 
			
		||||
                  type: 'void',
 | 
			
		||||
                  title: '编辑表单',
 | 
			
		||||
                  'x-decorator': 'Form',
 | 
			
		||||
                  'x-decorator-props': {
 | 
			
		||||
                    useValues: '{{ Table.useTableRow }}',
 | 
			
		||||
                  },
 | 
			
		||||
                  'x-component': 'Action.Modal',
 | 
			
		||||
                  'x-component-props': {
 | 
			
		||||
                    useOkAction: '{{ Table.useTableUpdateAction }}',
 | 
			
		||||
                  },
 | 
			
		||||
                  properties: {
 | 
			
		||||
                    field1: {
 | 
			
		||||
                      type: 'string',
 | 
			
		||||
                      title: '字段1',
 | 
			
		||||
                      'x-decorator': 'FormItem',
 | 
			
		||||
                      'x-component': 'Input',
 | 
			
		||||
                    },
 | 
			
		||||
                    field2: {
 | 
			
		||||
                      type: 'string',
 | 
			
		||||
                      title: '字段2',
 | 
			
		||||
                      'x-decorator': 'FormItem',
 | 
			
		||||
                      'x-component': 'Input',
 | 
			
		||||
                    },
 | 
			
		||||
                  },
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
            [uid()]: {
 | 
			
		||||
              type: 'void',
 | 
			
		||||
              title: '删除',
 | 
			
		||||
              'x-component': 'Action',
 | 
			
		||||
              'x-component-props': {
 | 
			
		||||
                useAction: '{{ Table.useTableDestroyAction }}',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    Form: {
 | 
			
		||||
      type: 'void',
 | 
			
		||||
      name: uid(),
 | 
			
		||||
      'x-decorator': 'CardItem',
 | 
			
		||||
      'x-component': 'Form',
 | 
			
		||||
      'x-designable-bar': 'Form.DesignableBar',
 | 
			
		||||
      properties: {
 | 
			
		||||
        [uid()]: {
 | 
			
		||||
          type: 'void',
 | 
			
		||||
          'x-component': 'Grid',
 | 
			
		||||
          'x-component-props': {
 | 
			
		||||
            addNewComponent: 'AddNew.FormItem',
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
  return defaults[component];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function generateFormItemSchema(component) {
 | 
			
		||||
  const defaults = {
 | 
			
		||||
    Markdown: {
 | 
			
		||||
      type: 'string',
 | 
			
		||||
      title: uid(),
 | 
			
		||||
      'x-designable-bar': 'Markdown.DesignableBar',
 | 
			
		||||
      'x-decorator': 'FormItem',
 | 
			
		||||
      'x-component': 'Markdown',
 | 
			
		||||
      'x-component-props': {},
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
  return defaults[component];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const dbSchema = {
 | 
			
		||||
  type: 'object',
 | 
			
		||||
  properties: {
 | 
			
		||||
    title: {
 | 
			
		||||
      type: 'string',
 | 
			
		||||
      title: '数据表名称',
 | 
			
		||||
      required: true,
 | 
			
		||||
      'x-decorator': 'FormItem',
 | 
			
		||||
      'x-component': 'Input',
 | 
			
		||||
    },
 | 
			
		||||
    name: {
 | 
			
		||||
      type: 'string',
 | 
			
		||||
      title: '数据表标识',
 | 
			
		||||
      'x-decorator': 'FormItem',
 | 
			
		||||
      'x-component': 'Input',
 | 
			
		||||
      'x-read-pretty': true,
 | 
			
		||||
    },
 | 
			
		||||
    fields: {
 | 
			
		||||
      type: 'array',
 | 
			
		||||
      title: '数据表字段',
 | 
			
		||||
      'x-decorator': 'FormItem',
 | 
			
		||||
      'x-component': 'DatabaseField',
 | 
			
		||||
      default: [],
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const AddNew = () => null;
 | 
			
		||||
 | 
			
		||||
AddNew.CardItem = observer((props: any) => {
 | 
			
		||||
  const { ghost, defaultAction } = props;
 | 
			
		||||
  const { schema, insertBefore, insertAfter, appendChild } = useDesignable();
 | 
			
		||||
  const path = useSchemaPath();
 | 
			
		||||
  const { data: collections = [], loading, run } = useRequest('collections:findAll', {
 | 
			
		||||
    formatResult: (result) => result?.data,
 | 
			
		||||
  });
 | 
			
		||||
  console.log({ collections });
 | 
			
		||||
  return (
 | 
			
		||||
    <Dropdown
 | 
			
		||||
      overlayStyle={{
 | 
			
		||||
        minWidth: 200,
 | 
			
		||||
      }}
 | 
			
		||||
      onVisibleChange={(visible) => {
 | 
			
		||||
        if (visible) {
 | 
			
		||||
          run();
 | 
			
		||||
        }
 | 
			
		||||
        console.log('onVisibleChange', visible);
 | 
			
		||||
      }}
 | 
			
		||||
      placement={'bottomCenter'}
 | 
			
		||||
      overlay={
 | 
			
		||||
        <Menu
 | 
			
		||||
          onClick={async (info) => {
 | 
			
		||||
            let data: ISchema;
 | 
			
		||||
            if (['addNewTable', 'addNewForm'].includes(info.key)) {
 | 
			
		||||
              const values = await FormDialog(`新建数据表`, () => {
 | 
			
		||||
                return (
 | 
			
		||||
                  <FormLayout layout={'vertical'}>
 | 
			
		||||
                    <SchemaField schema={dbSchema} />
 | 
			
		||||
                  </FormLayout>
 | 
			
		||||
                );
 | 
			
		||||
              }).open({
 | 
			
		||||
                initialValues: {
 | 
			
		||||
                  name: `t_${uid()}`,
 | 
			
		||||
                  fields: [],
 | 
			
		||||
                },
 | 
			
		||||
              });
 | 
			
		||||
              await createOrUpdateCollection(values);
 | 
			
		||||
              data = generateCardItemSchema(
 | 
			
		||||
                info.key === 'addNewTable' ? 'Table' : 'Form',
 | 
			
		||||
              );
 | 
			
		||||
            } else if (info.key !== 'Markdown') {
 | 
			
		||||
              const keys = info.key.split('.');
 | 
			
		||||
              const component = keys.shift();
 | 
			
		||||
              const tableName = keys.join('.');
 | 
			
		||||
              data = generateCardItemSchema(component);
 | 
			
		||||
              console.log('info.keyPath', component, tableName);
 | 
			
		||||
            } else {
 | 
			
		||||
              data = generateCardItemSchema(info.key);
 | 
			
		||||
            }
 | 
			
		||||
            if (schema['key']) {
 | 
			
		||||
              data['key'] = uid();
 | 
			
		||||
            }
 | 
			
		||||
            if (isGridBlock(schema)) {
 | 
			
		||||
              path.pop();
 | 
			
		||||
              path.pop();
 | 
			
		||||
              data = generateGridBlock(data);
 | 
			
		||||
            } else if (isGrid(schema)) {
 | 
			
		||||
              data = generateGridBlock(data);
 | 
			
		||||
            }
 | 
			
		||||
            if (data) {
 | 
			
		||||
              let s;
 | 
			
		||||
              if (isGrid(schema)) {
 | 
			
		||||
                s = appendChild(data, [...path]);
 | 
			
		||||
              } else if (defaultAction === 'insertAfter') {
 | 
			
		||||
                s = insertAfter(data, [...path]);
 | 
			
		||||
              } else {
 | 
			
		||||
                s = insertBefore(data, [...path]);
 | 
			
		||||
              }
 | 
			
		||||
              await createSchema(s);
 | 
			
		||||
            }
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          <Menu.SubMenu key={'Table'} title={'新建表格'}>
 | 
			
		||||
            <Menu.ItemGroup key={'table-select'} title={'选择数据表'}>
 | 
			
		||||
              {collections.map((item) => (
 | 
			
		||||
                <Menu.Item key={`Table.${item.name}`}>{item.title}</Menu.Item>
 | 
			
		||||
              ))}
 | 
			
		||||
            </Menu.ItemGroup>
 | 
			
		||||
            <Menu.Divider></Menu.Divider>
 | 
			
		||||
            <Menu.Item key={'addNewTable'}>新建数据表</Menu.Item>
 | 
			
		||||
          </Menu.SubMenu>
 | 
			
		||||
          <Menu.SubMenu key={'Form'} title={'新建表单'}>
 | 
			
		||||
            <Menu.ItemGroup key={'form-select'} title={'选择数据表'}>
 | 
			
		||||
              {collections.map((item) => (
 | 
			
		||||
                <Menu.Item key={`Form.${item.name}`}>{item.title}</Menu.Item>
 | 
			
		||||
              ))}
 | 
			
		||||
            </Menu.ItemGroup>
 | 
			
		||||
            <Menu.Divider></Menu.Divider>
 | 
			
		||||
            <Menu.Item key={'addNewForm'}>新建数据表</Menu.Item>
 | 
			
		||||
          </Menu.SubMenu>
 | 
			
		||||
          <Menu.Item key={'Markdown'}>新建 Markdown</Menu.Item>
 | 
			
		||||
          <Menu.SubMenu key={'Ref'} title={'引用模板'}>
 | 
			
		||||
            <Menu.ItemGroup key={'form-select'} title={'选择模板'}>
 | 
			
		||||
              <Menu.Item key={'Ref.name1'}>模板1</Menu.Item>
 | 
			
		||||
            </Menu.ItemGroup>
 | 
			
		||||
            <Menu.Divider></Menu.Divider>
 | 
			
		||||
            <Menu.Item key={'addNewRef'}>新建模板</Menu.Item>
 | 
			
		||||
          </Menu.SubMenu>
 | 
			
		||||
        </Menu>
 | 
			
		||||
      }
 | 
			
		||||
    >
 | 
			
		||||
      {ghost ? (
 | 
			
		||||
        <PlusOutlined />
 | 
			
		||||
      ) : (
 | 
			
		||||
        <Button block type={'dashed'} icon={<PlusOutlined />}></Button>
 | 
			
		||||
      )}
 | 
			
		||||
    </Dropdown>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
AddNew.BlockItem = observer((props: any) => {
 | 
			
		||||
  const { ghost, defaultAction } = props;
 | 
			
		||||
  const { schema, insertBefore, insertAfter } = useDesignable();
 | 
			
		||||
  const path = useSchemaPath();
 | 
			
		||||
  return (
 | 
			
		||||
    <Dropdown
 | 
			
		||||
      overlayStyle={{
 | 
			
		||||
        minWidth: 200,
 | 
			
		||||
      }}
 | 
			
		||||
      placement={'bottomCenter'}
 | 
			
		||||
      overlay={
 | 
			
		||||
        <Menu>
 | 
			
		||||
          <Menu.SubMenu title={'新建表格'}>
 | 
			
		||||
@ -113,7 +630,7 @@ AddNew.BlockItem = observer((props: any) => {
 | 
			
		||||
                type: 'void',
 | 
			
		||||
                title: uid(),
 | 
			
		||||
                'x-designable-bar': 'BlockItem.DesignableBar',
 | 
			
		||||
                'x-decorator': 'BlockItem',
 | 
			
		||||
                'x-decorator': 'CardItem',
 | 
			
		||||
                'x-component': 'Markdown',
 | 
			
		||||
              };
 | 
			
		||||
              if (schema['key']) {
 | 
			
		||||
@ -141,7 +658,11 @@ AddNew.BlockItem = observer((props: any) => {
 | 
			
		||||
        </Menu>
 | 
			
		||||
      }
 | 
			
		||||
    >
 | 
			
		||||
      {ghost ? <PlusOutlined /> : <Button icon={<PlusOutlined />}></Button>}
 | 
			
		||||
      {ghost ? (
 | 
			
		||||
        <PlusOutlined />
 | 
			
		||||
      ) : (
 | 
			
		||||
        <Button block type={'dashed'} icon={<PlusOutlined />}></Button>
 | 
			
		||||
      )}
 | 
			
		||||
    </Dropdown>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
@ -152,6 +673,10 @@ AddNew.FormItem = observer((props: any) => {
 | 
			
		||||
  const path = useSchemaPath();
 | 
			
		||||
  return (
 | 
			
		||||
    <Dropdown
 | 
			
		||||
      overlayStyle={{
 | 
			
		||||
        minWidth: 200,
 | 
			
		||||
      }}
 | 
			
		||||
      placement={'bottomCenter'}
 | 
			
		||||
      overlay={
 | 
			
		||||
        <Menu>
 | 
			
		||||
          <Menu.ItemGroup title={'选择已有字段'}>
 | 
			
		||||
@ -159,25 +684,24 @@ AddNew.FormItem = observer((props: any) => {
 | 
			
		||||
              style={{
 | 
			
		||||
                minWidth: 150,
 | 
			
		||||
              }}
 | 
			
		||||
              onClick={() => {
 | 
			
		||||
                let data: ISchema = {
 | 
			
		||||
                  type: 'void',
 | 
			
		||||
                  title: uid(),
 | 
			
		||||
                  'x-designable-bar': 'FormItem.DesignableBar',
 | 
			
		||||
                  'x-decorator': 'FormItem',
 | 
			
		||||
                  'x-component': 'Markdown',
 | 
			
		||||
                };
 | 
			
		||||
              onClick={async () => {
 | 
			
		||||
                let data: ISchema = generateFormItemSchema('Markdown');
 | 
			
		||||
                if (schema['key']) {
 | 
			
		||||
                  data['key'] = uid();
 | 
			
		||||
                }
 | 
			
		||||
                if (isGridBlock(schema)) {
 | 
			
		||||
                  path.pop();
 | 
			
		||||
                  path.pop();
 | 
			
		||||
                  data = generateGridBlock(data);
 | 
			
		||||
                }
 | 
			
		||||
                if (data) {
 | 
			
		||||
                  let s;
 | 
			
		||||
                  if (defaultAction === 'insertAfter') {
 | 
			
		||||
                    insertAfter(data, [...path]);
 | 
			
		||||
                    s = insertAfter(data, [...path]);
 | 
			
		||||
                  } else {
 | 
			
		||||
                    insertBefore(data, [...path]);
 | 
			
		||||
                    s = insertBefore(data, [...path]);
 | 
			
		||||
                  }
 | 
			
		||||
                  await createSchema(s);
 | 
			
		||||
                }
 | 
			
		||||
              }}
 | 
			
		||||
            >
 | 
			
		||||
@ -219,7 +743,11 @@ AddNew.FormItem = observer((props: any) => {
 | 
			
		||||
        </Menu>
 | 
			
		||||
      }
 | 
			
		||||
    >
 | 
			
		||||
      {ghost ? <PlusOutlined /> : <Button icon={<PlusOutlined />}></Button>}
 | 
			
		||||
      {ghost ? (
 | 
			
		||||
        <PlusOutlined />
 | 
			
		||||
      ) : (
 | 
			
		||||
        <Button block type={'dashed'} icon={<PlusOutlined />}></Button>
 | 
			
		||||
      )}
 | 
			
		||||
    </Dropdown>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -113,17 +113,6 @@ export const BlockItem: any = observer((props) => {
 | 
			
		||||
  return React.createElement(uid ? DraggableBlock : Block, props);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// export const BlockItem: any = connect((props) => {
 | 
			
		||||
//   const { children, ...others } = props;
 | 
			
		||||
//   const { DesignableBar } = useDesignableBar();
 | 
			
		||||
//   return (
 | 
			
		||||
//     <div {...others} style={{marginBottom: 24}} className={'designable-form-item'}>
 | 
			
		||||
//       {children}
 | 
			
		||||
//       <DesignableBar />
 | 
			
		||||
//     </div>
 | 
			
		||||
//   );
 | 
			
		||||
// });
 | 
			
		||||
 | 
			
		||||
BlockItem.DesignableBar = () => {
 | 
			
		||||
  const field = useField();
 | 
			
		||||
  const { schema, refresh } = useDesignable();
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										32
									
								
								packages/client/src/schemas/card-item/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								packages/client/src/schemas/card-item/index.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
import React, { useContext, useState } from 'react';
 | 
			
		||||
import {
 | 
			
		||||
  connect,
 | 
			
		||||
  mapProps,
 | 
			
		||||
  mapReadPretty,
 | 
			
		||||
  observer,
 | 
			
		||||
  SchemaOptionsContext,
 | 
			
		||||
  useField,
 | 
			
		||||
  useFieldSchema,
 | 
			
		||||
} from '@formily/react';
 | 
			
		||||
import { FormItem as FormilyFormItem } from '@formily/antd';
 | 
			
		||||
import { Card, Dropdown, Menu, Space } from 'antd';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
 | 
			
		||||
// import './style.less';
 | 
			
		||||
import get from 'lodash/get';
 | 
			
		||||
import { GridBlockContext } from '../grid';
 | 
			
		||||
import { uid } from '@formily/shared';
 | 
			
		||||
import { useDesignable } from '../';
 | 
			
		||||
import { AddNew } from '../add-new';
 | 
			
		||||
import { BlockItem } from '../block-item';
 | 
			
		||||
import { DraggableBlockContext } from '../../components/drag-and-drop';
 | 
			
		||||
 | 
			
		||||
export const CardItem: any = connect((props) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <BlockItem>
 | 
			
		||||
      <Card bordered={false} {...props}>
 | 
			
		||||
        {props.children}
 | 
			
		||||
      </Card>
 | 
			
		||||
    </BlockItem>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
@ -39,7 +39,7 @@ 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 { createOrUpdateCollection, deleteCollection, useCollectionContext } from '..';
 | 
			
		||||
 | 
			
		||||
export const DatabaseCollection = observer((props) => {
 | 
			
		||||
  const field = useField<Formily.Core.Models.ArrayField>();
 | 
			
		||||
@ -49,6 +49,7 @@ export const DatabaseCollection = observer((props) => {
 | 
			
		||||
  const [activeIndex, setActiveIndex] = useState(0);
 | 
			
		||||
  const form = useForm();
 | 
			
		||||
  const [newValue, setNewValue] = useState('');
 | 
			
		||||
  const { refresh } = useCollectionContext();
 | 
			
		||||
 | 
			
		||||
  const { run, loading } = useRequest('collections:findAll', {
 | 
			
		||||
    formatResult: (result) => result?.data,
 | 
			
		||||
@ -125,6 +126,7 @@ export const DatabaseCollection = observer((props) => {
 | 
			
		||||
                          setOpen(false);
 | 
			
		||||
                          setNewValue('');
 | 
			
		||||
                          await createOrUpdateCollection(data);
 | 
			
		||||
                          await refresh();
 | 
			
		||||
                        }}
 | 
			
		||||
                      />
 | 
			
		||||
                    </div>
 | 
			
		||||
@ -166,6 +168,7 @@ export const DatabaseCollection = observer((props) => {
 | 
			
		||||
                          }
 | 
			
		||||
                          if (item.name) {
 | 
			
		||||
                            await deleteCollection(item.name);
 | 
			
		||||
                            await refresh();
 | 
			
		||||
                          }
 | 
			
		||||
                        }}
 | 
			
		||||
                      />
 | 
			
		||||
@ -188,6 +191,7 @@ export const DatabaseCollection = observer((props) => {
 | 
			
		||||
            await form.validate(`${field.address.entire}.${activeIndex}.*`);
 | 
			
		||||
            delete field.value[activeIndex]['unsaved'];
 | 
			
		||||
            await createOrUpdateCollection(field.value[activeIndex]);
 | 
			
		||||
            await refresh();
 | 
			
		||||
            message.success('保存成功');
 | 
			
		||||
          } catch (error) {}
 | 
			
		||||
        }}
 | 
			
		||||
 | 
			
		||||
@ -8,14 +8,18 @@ import {
 | 
			
		||||
  SchemaExpressionScopeContext,
 | 
			
		||||
  FormProvider,
 | 
			
		||||
  ISchema,
 | 
			
		||||
  useField,
 | 
			
		||||
} from '@formily/react';
 | 
			
		||||
import { useSchemaPath, SchemaField, useDesignable } from '../';
 | 
			
		||||
import { useSchemaPath, SchemaField, useDesignable, removeSchema } from '../';
 | 
			
		||||
import get from 'lodash/get';
 | 
			
		||||
import { Dropdown, Menu } from 'antd';
 | 
			
		||||
import { MenuOutlined } from '@ant-design/icons';
 | 
			
		||||
import { Dropdown, Menu, Space } from 'antd';
 | 
			
		||||
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
 | 
			
		||||
import cls from 'classnames';
 | 
			
		||||
import { FormLayout } from '@formily/antd';
 | 
			
		||||
import './style.less';
 | 
			
		||||
import AddNew from '../add-new';
 | 
			
		||||
import { DraggableBlockContext } from '../../components/drag-and-drop';
 | 
			
		||||
import { isGridRowOrCol } from '../grid';
 | 
			
		||||
 | 
			
		||||
export const Form: any = observer((props: any) => {
 | 
			
		||||
  const { useValues = () => ({}), ...others } = props;
 | 
			
		||||
@ -61,21 +65,59 @@ export const Form: any = observer((props: any) => {
 | 
			
		||||
 | 
			
		||||
Form.__Decorator = ({ children }) => children;
 | 
			
		||||
 | 
			
		||||
Form.DesignableBar = (props) => {
 | 
			
		||||
  const { active } = props;
 | 
			
		||||
Form.DesignableBar = observer((props) => {
 | 
			
		||||
  const field = useField();
 | 
			
		||||
  const { schema, refresh, deepRemove } = useDesignable();
 | 
			
		||||
  const [visible, setVisible] = useState(false);
 | 
			
		||||
  const { dragRef } = useContext(DraggableBlockContext);
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={cls('designable-bar', { active })}>
 | 
			
		||||
      <div className={'designable-bar-actions'}>
 | 
			
		||||
    <div className={cls('designable-bar', { active: visible })}>
 | 
			
		||||
      <span
 | 
			
		||||
        onClick={(e) => {
 | 
			
		||||
          e.stopPropagation();
 | 
			
		||||
        }}
 | 
			
		||||
        className={cls('designable-bar-actions', { active: visible })}
 | 
			
		||||
      >
 | 
			
		||||
        <Space size={'small'}>
 | 
			
		||||
          <AddNew.CardItem defaultAction={'insertAfter'} ghost />
 | 
			
		||||
          {dragRef && <DragOutlined ref={dragRef} />}
 | 
			
		||||
          <Dropdown
 | 
			
		||||
            trigger={['click']}
 | 
			
		||||
            visible={visible}
 | 
			
		||||
            onVisibleChange={(visible) => {
 | 
			
		||||
              setVisible(visible);
 | 
			
		||||
            }}
 | 
			
		||||
            overlay={
 | 
			
		||||
              <Menu>
 | 
			
		||||
              <Menu.Item>表单配置</Menu.Item>
 | 
			
		||||
                <Menu.Item
 | 
			
		||||
                  key={'update'}
 | 
			
		||||
                  onClick={() => {
 | 
			
		||||
                    field.readPretty = false;
 | 
			
		||||
                  }}
 | 
			
		||||
                >
 | 
			
		||||
                  编辑Markdown
 | 
			
		||||
                </Menu.Item>
 | 
			
		||||
                <Menu.Divider />
 | 
			
		||||
                <Menu.Item
 | 
			
		||||
                  key={'delete'}
 | 
			
		||||
                  onClick={async () => {
 | 
			
		||||
                    const removed = deepRemove();
 | 
			
		||||
                    // console.log({ removed })
 | 
			
		||||
                    const last = removed.pop();
 | 
			
		||||
                    if (isGridRowOrCol(last)) {
 | 
			
		||||
                      await removeSchema(last);
 | 
			
		||||
                    }
 | 
			
		||||
                  }}
 | 
			
		||||
                >
 | 
			
		||||
                  删除当前区块
 | 
			
		||||
                </Menu.Item>
 | 
			
		||||
              </Menu>
 | 
			
		||||
            }
 | 
			
		||||
          >
 | 
			
		||||
            <MenuOutlined />
 | 
			
		||||
          </Dropdown>
 | 
			
		||||
      </div>
 | 
			
		||||
        </Space>
 | 
			
		||||
      </span>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,9 @@ const schema: ISchema = {
 | 
			
		||||
  type: 'void',
 | 
			
		||||
  name: uid(),
 | 
			
		||||
  'x-component': 'Grid',
 | 
			
		||||
  "x-component-props": {
 | 
			
		||||
    addNewComponent: 'AddNew.CardItem',
 | 
			
		||||
  },
 | 
			
		||||
  properties: {
 | 
			
		||||
    [`row_${uid()}`]: {
 | 
			
		||||
      type: 'void',
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,7 @@ import {
 | 
			
		||||
  useDragDropUID,
 | 
			
		||||
  DragDropManagerProvider,
 | 
			
		||||
} from '../../components/drag-and-drop';
 | 
			
		||||
import { useSchemaComponent } from '../../components/schema-renderer';
 | 
			
		||||
 | 
			
		||||
const ColumnSizeContext = createContext(null);
 | 
			
		||||
 | 
			
		||||
@ -37,7 +38,7 @@ export const GridBlockContext = createContext({
 | 
			
		||||
  dragRef: null,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function isGridRowOrCol(schema: ISchema) {
 | 
			
		||||
export function isGridRowOrCol(schema: ISchema) {
 | 
			
		||||
  return ['Grid.Row', 'Grid.Col'].includes(schema['x-component']);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -81,11 +82,14 @@ const ColDivider = (props: any) => {
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const Grid: any = observer((props) => {
 | 
			
		||||
export const Grid: any = observer((props: any) => {
 | 
			
		||||
  const { addNewComponent } = props;
 | 
			
		||||
  const AddNewComponent = useSchemaComponent(addNewComponent);
 | 
			
		||||
  const ref = useRef();
 | 
			
		||||
  const schema = useFieldSchema();
 | 
			
		||||
  // const schema = useFieldSchema();
 | 
			
		||||
  const gridPath = useSchemaPath();
 | 
			
		||||
  const {
 | 
			
		||||
    schema,
 | 
			
		||||
    schema: designableSchema,
 | 
			
		||||
    insertAfter,
 | 
			
		||||
    prepend,
 | 
			
		||||
@ -162,6 +166,7 @@ export const Grid: any = observer((props) => {
 | 
			
		||||
            </>
 | 
			
		||||
          );
 | 
			
		||||
        })}
 | 
			
		||||
        {AddNewComponent && <AddNewComponent />}
 | 
			
		||||
      </div>
 | 
			
		||||
    </DragDropManagerProvider>
 | 
			
		||||
  );
 | 
			
		||||
@ -169,9 +174,10 @@ export const Grid: any = observer((props) => {
 | 
			
		||||
 | 
			
		||||
Grid.Row = observer((props) => {
 | 
			
		||||
  const field = useField();
 | 
			
		||||
  const schema = useFieldSchema();
 | 
			
		||||
  // const schema = useFieldSchema();
 | 
			
		||||
  const rowPath = useSchemaPath();
 | 
			
		||||
  const {
 | 
			
		||||
    schema,
 | 
			
		||||
    schema: designableSchema,
 | 
			
		||||
    refresh,
 | 
			
		||||
    insertAfter,
 | 
			
		||||
 | 
			
		||||
@ -1,18 +1,50 @@
 | 
			
		||||
import { ISchema } from '@formily/react';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { ISchema, observer, Schema, useField } from '@formily/react';
 | 
			
		||||
import constate from 'constate';
 | 
			
		||||
import { useState } from 'react';
 | 
			
		||||
import { createContext } from 'react';
 | 
			
		||||
 | 
			
		||||
import { extend } from 'umi-request';
 | 
			
		||||
import { isVoidField } from '@formily/core';
 | 
			
		||||
import { useRequest } from 'ahooks';
 | 
			
		||||
 | 
			
		||||
export * from '../components/schema-renderer';
 | 
			
		||||
 | 
			
		||||
export function mapReadPretty(component, readPrettyProps) {
 | 
			
		||||
  return function (target) {
 | 
			
		||||
    return observer(
 | 
			
		||||
      (props) => {
 | 
			
		||||
        const field = useField()
 | 
			
		||||
        if (!isVoidField(field) && field?.pattern === 'readPretty') {
 | 
			
		||||
          return React.createElement(component, {
 | 
			
		||||
            ...readPrettyProps,
 | 
			
		||||
            ...props,
 | 
			
		||||
          })
 | 
			
		||||
        }
 | 
			
		||||
        return React.createElement(target, props)
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        forwardRef: true,
 | 
			
		||||
      }
 | 
			
		||||
    )
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const VisibleContext = createContext(null);
 | 
			
		||||
export const DesignableBarContext = createContext(null);
 | 
			
		||||
 | 
			
		||||
const [PageTitleContextProvider, usePageTitleContext] = constate(() => {
 | 
			
		||||
  return useState(null);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export { PageTitleContextProvider, usePageTitleContext };
 | 
			
		||||
 | 
			
		||||
export function useDefaultAction() {
 | 
			
		||||
  return {
 | 
			
		||||
    async run () {}
 | 
			
		||||
  }
 | 
			
		||||
    async run() {},
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
import { extend } from 'umi-request';
 | 
			
		||||
 | 
			
		||||
export const request = extend({
 | 
			
		||||
  prefix: 'http://localhost:23003/api/',
 | 
			
		||||
  timeout: 1000,
 | 
			
		||||
@ -31,7 +63,7 @@ export async function deleteCollection(name) {
 | 
			
		||||
    params: {
 | 
			
		||||
      filter: {
 | 
			
		||||
        name,
 | 
			
		||||
      }
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
@ -44,7 +76,7 @@ export async function createSchema(schema: ISchema) {
 | 
			
		||||
    method: 'post',
 | 
			
		||||
    data: schema.toJSON(),
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function updateSchema(schema: ISchema) {
 | 
			
		||||
  if (!schema['key']) {
 | 
			
		||||
@ -52,9 +84,9 @@ export async function updateSchema(schema: ISchema) {
 | 
			
		||||
  }
 | 
			
		||||
  return await request(`ui_schemas:update/${schema.key}`, {
 | 
			
		||||
    method: 'post',
 | 
			
		||||
    data: schema.toJSON(),
 | 
			
		||||
    data: Schema.isSchemaInstance(schema) ? schema.toJSON() : schema,
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function removeSchema(schema: ISchema) {
 | 
			
		||||
  if (!schema['key']) {
 | 
			
		||||
@ -65,7 +97,15 @@ export async function removeSchema(schema: ISchema) {
 | 
			
		||||
    params: {
 | 
			
		||||
      filter: {
 | 
			
		||||
        key: schema['key'],
 | 
			
		||||
      }
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const [CollectionContextProvider, useCollectionContext] = constate(() => {
 | 
			
		||||
  return useRequest('collections:findAll', {
 | 
			
		||||
    formatResult: (result) => result?.data,
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export { CollectionContextProvider, useCollectionContext };
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,6 @@ const schema = {
 | 
			
		||||
  type: 'object',
 | 
			
		||||
  properties: {
 | 
			
		||||
    input: {
 | 
			
		||||
      interface: 'string',
 | 
			
		||||
      type: 'string',
 | 
			
		||||
      title: `编辑模式`,
 | 
			
		||||
      name: 'name1',
 | 
			
		||||
@ -76,3 +75,58 @@ export default () => {
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Markdown.DesignableBar
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```tsx
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { SchemaRenderer } from '../';
 | 
			
		||||
 | 
			
		||||
const schema1 = {
 | 
			
		||||
  type: 'object',
 | 
			
		||||
  properties: {
 | 
			
		||||
    markdown1: {
 | 
			
		||||
      type: 'string',
 | 
			
		||||
      title: `简易Markdown`,
 | 
			
		||||
      default: '这是一段示例文案',
 | 
			
		||||
      'x-read-pretty': true,
 | 
			
		||||
      'x-decorator': 'CardItem',
 | 
			
		||||
      'x-component': 'Markdown',
 | 
			
		||||
      'x-designable-bar': 'Markdown.DesignableBar',
 | 
			
		||||
      'x-component-props': {
 | 
			
		||||
        savedInSchema: true,
 | 
			
		||||
        // ellipsis: true,
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const schema2 = {
 | 
			
		||||
  type: 'object',
 | 
			
		||||
  properties: {
 | 
			
		||||
    markdown1: {
 | 
			
		||||
      type: 'string',
 | 
			
		||||
      title: `简易Markdown`,
 | 
			
		||||
      default: '这是一段示例文案',
 | 
			
		||||
      'x-read-pretty': true,
 | 
			
		||||
      'x-decorator': 'FormItem',
 | 
			
		||||
      'x-component': 'Markdown',
 | 
			
		||||
      'x-designable-bar': 'Markdown.DesignableBar',
 | 
			
		||||
      'x-component-props': {
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default () => {
 | 
			
		||||
  return (
 | 
			
		||||
    <div>
 | 
			
		||||
      <h3>区块项</h3>
 | 
			
		||||
      <SchemaRenderer schema={schema1} />
 | 
			
		||||
      <h3>表单项</h3>
 | 
			
		||||
      <SchemaRenderer schema={schema2} />
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
@ -1,15 +1,53 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { connect, mapProps, mapReadPretty, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { Input as AntdInput } from 'antd';
 | 
			
		||||
import {
 | 
			
		||||
  connect,
 | 
			
		||||
  mapProps,
 | 
			
		||||
  mapReadPretty,
 | 
			
		||||
  observer,
 | 
			
		||||
  useField,
 | 
			
		||||
  useFieldSchema,
 | 
			
		||||
} from '@formily/react';
 | 
			
		||||
import { Button, Dropdown, Input as AntdInput, Menu, Space } from 'antd';
 | 
			
		||||
import { InputProps, TextAreaProps } from 'antd/lib/input';
 | 
			
		||||
import { Display } from '../display';
 | 
			
		||||
import { LoadingOutlined } from '@ant-design/icons';
 | 
			
		||||
import { LoadingOutlined, MenuOutlined, DragOutlined } from '@ant-design/icons';
 | 
			
		||||
import micromark from 'micromark';
 | 
			
		||||
import { useDesignable } from '../../components/schema-renderer';
 | 
			
		||||
import { useContext, useState } from 'react';
 | 
			
		||||
import AddNew from '../add-new';
 | 
			
		||||
import cls from 'classnames';
 | 
			
		||||
import { DraggableBlockContext } from '../../components/drag-and-drop';
 | 
			
		||||
import { uid } from '@formily/shared';
 | 
			
		||||
import { removeSchema, updateSchema } from '..';
 | 
			
		||||
import { isGridRowOrCol } from '../grid';
 | 
			
		||||
 | 
			
		||||
export const Markdown = connect(
 | 
			
		||||
export const Markdown: any = connect(
 | 
			
		||||
  (props) => {
 | 
			
		||||
    const schema = useFieldSchema();
 | 
			
		||||
    return <AntdInput.TextArea defaultValue={schema.name} {...props}/>
 | 
			
		||||
    const { schema } = useDesignable();
 | 
			
		||||
    const field = useField<any>();
 | 
			
		||||
    const { savedInSchema, ...others } = props;
 | 
			
		||||
    console.log('Markdown', props);
 | 
			
		||||
    return savedInSchema ? (
 | 
			
		||||
      <div className={'mb-markdown'} style={{ position: 'relative' }}>
 | 
			
		||||
        <AntdInput.TextArea autoSize={{ minRows: 3 }} {...others} />
 | 
			
		||||
        <Button
 | 
			
		||||
          style={{ position: 'absolute', bottom: 5, right: 5 }}
 | 
			
		||||
          type={'primary'}
 | 
			
		||||
          onClick={async () => {
 | 
			
		||||
            field.readPretty = true;
 | 
			
		||||
            schema['default'] = field.value;
 | 
			
		||||
            await updateSchema({
 | 
			
		||||
              key: schema['key'],
 | 
			
		||||
              default: field.value,
 | 
			
		||||
            });
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          保存
 | 
			
		||||
        </Button>
 | 
			
		||||
      </div>
 | 
			
		||||
    ) : (
 | 
			
		||||
      <AntdInput.TextArea autoSize={{ minRows: 1 }} {...others} />
 | 
			
		||||
    );
 | 
			
		||||
  },
 | 
			
		||||
  mapProps((props: any, field) => {
 | 
			
		||||
    return {
 | 
			
		||||
@ -26,6 +64,7 @@ export const Markdown = connect(
 | 
			
		||||
    };
 | 
			
		||||
  }),
 | 
			
		||||
  mapReadPretty((props) => {
 | 
			
		||||
    console.log('Markdown', props);
 | 
			
		||||
    let text = props.value;
 | 
			
		||||
    let value = (
 | 
			
		||||
      <div dangerouslySetInnerHTML={{ __html: micromark(text || '') }} />
 | 
			
		||||
@ -34,4 +73,61 @@ export const Markdown = connect(
 | 
			
		||||
  }),
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
Markdown.DesignableBar = observer((props) => {
 | 
			
		||||
  const field = useField();
 | 
			
		||||
  const { schema, refresh, deepRemove } = useDesignable();
 | 
			
		||||
  const [visible, setVisible] = useState(false);
 | 
			
		||||
  const { dragRef } = useContext(DraggableBlockContext);
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={cls('designable-bar', { active: visible })}>
 | 
			
		||||
      <span
 | 
			
		||||
        onClick={(e) => {
 | 
			
		||||
          e.stopPropagation();
 | 
			
		||||
        }}
 | 
			
		||||
        className={cls('designable-bar-actions', { active: visible })}
 | 
			
		||||
      >
 | 
			
		||||
        <Space size={'small'}>
 | 
			
		||||
          <AddNew.CardItem defaultAction={'insertAfter'} ghost />
 | 
			
		||||
          {dragRef && <DragOutlined ref={dragRef} />}
 | 
			
		||||
          <Dropdown
 | 
			
		||||
            trigger={['click']}
 | 
			
		||||
            visible={visible}
 | 
			
		||||
            onVisibleChange={(visible) => {
 | 
			
		||||
              setVisible(visible);
 | 
			
		||||
            }}
 | 
			
		||||
            overlay={
 | 
			
		||||
              <Menu>
 | 
			
		||||
                <Menu.Item
 | 
			
		||||
                  key={'update'}
 | 
			
		||||
                  onClick={() => {
 | 
			
		||||
                    field.readPretty = false;
 | 
			
		||||
                  }}
 | 
			
		||||
                >
 | 
			
		||||
                  修改 Markdown
 | 
			
		||||
                </Menu.Item>
 | 
			
		||||
                <Menu.Divider />
 | 
			
		||||
                <Menu.Item
 | 
			
		||||
                  key={'delete'}
 | 
			
		||||
                  onClick={async () => {
 | 
			
		||||
                    const removed = deepRemove();
 | 
			
		||||
                    // console.log({ removed })
 | 
			
		||||
                    const last = removed.pop();
 | 
			
		||||
                    if (isGridRowOrCol(last)) {
 | 
			
		||||
                      await removeSchema(last);
 | 
			
		||||
                    }
 | 
			
		||||
                  }}
 | 
			
		||||
                >
 | 
			
		||||
                  删除当前区块
 | 
			
		||||
                </Menu.Item>
 | 
			
		||||
              </Menu>
 | 
			
		||||
            }
 | 
			
		||||
          >
 | 
			
		||||
            <MenuOutlined />
 | 
			
		||||
          </Dropdown>
 | 
			
		||||
        </Space>
 | 
			
		||||
      </span>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default Markdown;
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,8 @@
 | 
			
		||||
import { ISchema } from '@formily/react';
 | 
			
		||||
import { uid } from '@formily/shared';
 | 
			
		||||
 | 
			
		||||
export const defaultSchemas = {
 | 
			
		||||
export function generateDefaultSchema(component) {
 | 
			
		||||
  const defaultSchemas: { [key: string]: ISchema } = {
 | 
			
		||||
    MixMenu: {
 | 
			
		||||
      type: 'void',
 | 
			
		||||
      'x-component': 'Menu',
 | 
			
		||||
@ -25,32 +26,19 @@ export const defaultSchemas = {
 | 
			
		||||
      properties: {
 | 
			
		||||
        [uid()]: {
 | 
			
		||||
          type: 'void',
 | 
			
		||||
        name: uid(),
 | 
			
		||||
        'x-component': 'Grid',
 | 
			
		||||
        properties: {
 | 
			
		||||
          [`row_${uid()}`]: {
 | 
			
		||||
            type: 'void',
 | 
			
		||||
            'x-component': 'Grid.Row',
 | 
			
		||||
            'x-component-props': {
 | 
			
		||||
              locked: true,
 | 
			
		||||
            },
 | 
			
		||||
            properties: {
 | 
			
		||||
              [`col_${uid()}`]: {
 | 
			
		||||
                type: 'void',
 | 
			
		||||
                'x-component': 'Grid.Col',
 | 
			
		||||
          'x-component': 'Page',
 | 
			
		||||
          properties: {
 | 
			
		||||
            [uid()]: {
 | 
			
		||||
              type: 'void',
 | 
			
		||||
                    'x-component': 'AddNew.BlockItem',
 | 
			
		||||
              'x-component': 'Grid',
 | 
			
		||||
              'x-component-props': {
 | 
			
		||||
                addNewComponent: 'AddNew.CardItem',
 | 
			
		||||
              },
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
    'Menu.URL': {
 | 
			
		||||
      type: 'void',
 | 
			
		||||
      'x-designable-bar': 'Menu.DesignableBar',
 | 
			
		||||
@ -66,6 +54,6 @@ export const defaultSchemas = {
 | 
			
		||||
      'x-designable-bar': 'Menu.DesignableBar',
 | 
			
		||||
      'x-component': 'Menu.Action',
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default defaultSchemas;
 | 
			
		||||
  };
 | 
			
		||||
  return defaultSchemas[component];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -62,7 +62,7 @@ import './style.less';
 | 
			
		||||
import { Link } from 'react-router-dom';
 | 
			
		||||
import { findPropertyByPath, getSchemaPath, useSchemaPath } from '../../';
 | 
			
		||||
import { request } from '../';
 | 
			
		||||
import defaultSchemas from './defaultSchemas';
 | 
			
		||||
import { generateDefaultSchema } from './defaultSchemas';
 | 
			
		||||
import _, { cloneDeep, get, isNull } from 'lodash';
 | 
			
		||||
import { FormDialog, FormItem, FormLayout, Input } from '@formily/antd';
 | 
			
		||||
import deepmerge from 'deepmerge';
 | 
			
		||||
@ -369,7 +369,7 @@ Menu.AddNew = observer((props: any) => {
 | 
			
		||||
                    </FormLayout>
 | 
			
		||||
                  );
 | 
			
		||||
                }).open();
 | 
			
		||||
                const defaults = cloneDeep(defaultSchemas[info.key]);
 | 
			
		||||
                const defaults = generateDefaultSchema(info.key);
 | 
			
		||||
                const data = appendChild(deepmerge(defaults, values));
 | 
			
		||||
                await createSchema(data);
 | 
			
		||||
              }}
 | 
			
		||||
@ -568,7 +568,7 @@ Menu.DesignableBar = (props) => {
 | 
			
		||||
                  insertBefore,
 | 
			
		||||
                  appendChild,
 | 
			
		||||
                };
 | 
			
		||||
                const defaults = cloneDeep(defaultSchemas[type]);
 | 
			
		||||
                const defaults = generateDefaultSchema(type);
 | 
			
		||||
                const data = methods[method](deepmerge(defaults, values));
 | 
			
		||||
                await createSchema(data);
 | 
			
		||||
              }}
 | 
			
		||||
@ -711,11 +711,12 @@ Menu.DesignableBar = (props) => {
 | 
			
		||||
                    insertBefore,
 | 
			
		||||
                    appendChild,
 | 
			
		||||
                  };
 | 
			
		||||
                  const data = schema.toJSON();
 | 
			
		||||
                  remove();
 | 
			
		||||
                  const source = methods[values.method](
 | 
			
		||||
                    schema.toJSON(),
 | 
			
		||||
                    data,
 | 
			
		||||
                    values.path,
 | 
			
		||||
                  );
 | 
			
		||||
                  remove();
 | 
			
		||||
                  await updateSchema(source);
 | 
			
		||||
                }}
 | 
			
		||||
              >
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								packages/client/src/schemas/page/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								packages/client/src/schemas/page/index.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { PageHeader as AntdPageHeader } from 'antd';
 | 
			
		||||
import { observer } from '@formily/react';
 | 
			
		||||
import { usePageTitleContext } from '..';
 | 
			
		||||
 | 
			
		||||
export const Page = observer((props) => {
 | 
			
		||||
  const { children, ...others } = props;
 | 
			
		||||
  const [pageTitle] = usePageTitleContext();
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      <AntdPageHeader ghost={false} title={pageTitle} {...others} />
 | 
			
		||||
      <div style={{margin: 24}}>
 | 
			
		||||
        {children}
 | 
			
		||||
      </div>
 | 
			
		||||
    </>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
@ -25,7 +25,7 @@ import constate from 'constate';
 | 
			
		||||
import useRequest from '@ahooksjs/use-request';
 | 
			
		||||
import { BaseResult } from '@ahooksjs/use-request/lib/types';
 | 
			
		||||
import { uid, clone } from '@formily/shared';
 | 
			
		||||
import { MenuOutlined } from '@ant-design/icons';
 | 
			
		||||
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
 | 
			
		||||
import {
 | 
			
		||||
  SortableHandle,
 | 
			
		||||
  SortableContainer,
 | 
			
		||||
@ -34,6 +34,8 @@ import {
 | 
			
		||||
import cls from 'classnames';
 | 
			
		||||
import { getSchemaPath, useDesignable, useSchemaPath, VisibleContext } from '../';
 | 
			
		||||
import './style.less';
 | 
			
		||||
import { DraggableBlockContext } from '../../components/drag-and-drop';
 | 
			
		||||
import AddNew from '../add-new';
 | 
			
		||||
 | 
			
		||||
interface TableRowProps {
 | 
			
		||||
  index: number;
 | 
			
		||||
@ -633,3 +635,55 @@ Table.Action.DesignableBar = () => {
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Table.DesignableBar = observer((props) => {
 | 
			
		||||
  const field = useField();
 | 
			
		||||
  const { schema, refresh, deepRemove } = useDesignable();
 | 
			
		||||
  const [visible, setVisible] = useState(false);
 | 
			
		||||
  const { dragRef } = useContext(DraggableBlockContext);
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={cls('designable-bar', { active: visible })}>
 | 
			
		||||
      <span
 | 
			
		||||
        onClick={(e) => {
 | 
			
		||||
          e.stopPropagation();
 | 
			
		||||
        }}
 | 
			
		||||
        className={cls('designable-bar-actions', { active: visible })}
 | 
			
		||||
      >
 | 
			
		||||
        <Space size={'small'}>
 | 
			
		||||
          <AddNew.CardItem defaultAction={'insertAfter'} ghost />
 | 
			
		||||
          {dragRef && <DragOutlined ref={dragRef} />}
 | 
			
		||||
          <Dropdown
 | 
			
		||||
            trigger={['click']}
 | 
			
		||||
            visible={visible}
 | 
			
		||||
            onVisibleChange={(visible) => {
 | 
			
		||||
              setVisible(visible);
 | 
			
		||||
            }}
 | 
			
		||||
            overlay={
 | 
			
		||||
              <Menu>
 | 
			
		||||
                <Menu.Item
 | 
			
		||||
                  key={'update'}
 | 
			
		||||
                  onClick={() => {
 | 
			
		||||
                    field.readPretty = false;
 | 
			
		||||
                  }}
 | 
			
		||||
                >
 | 
			
		||||
                  编辑Markdown
 | 
			
		||||
                </Menu.Item>
 | 
			
		||||
                <Menu.Divider />
 | 
			
		||||
                <Menu.Item
 | 
			
		||||
                  key={'delete'}
 | 
			
		||||
                  onClick={() => {
 | 
			
		||||
                    deepRemove();
 | 
			
		||||
                  }}
 | 
			
		||||
                >
 | 
			
		||||
                  删除当前区块
 | 
			
		||||
                </Menu.Item>
 | 
			
		||||
              </Menu>
 | 
			
		||||
            }
 | 
			
		||||
          >
 | 
			
		||||
            <MenuOutlined />
 | 
			
		||||
          </Dropdown>
 | 
			
		||||
        </Space>
 | 
			
		||||
      </span>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
import _ from 'lodash';
 | 
			
		||||
import { Model } from '@nocobase/database';
 | 
			
		||||
import deepmerge from 'deepmerge';
 | 
			
		||||
 | 
			
		||||
export class UISchema extends Model {
 | 
			
		||||
  static async create(value?: any, options?: any): Promise<any> {
 | 
			
		||||
@ -33,7 +34,7 @@ export class UISchema extends Model {
 | 
			
		||||
    ];
 | 
			
		||||
    const attrs = _.pick(data, keys);
 | 
			
		||||
    const options = _.omit(data, keys);
 | 
			
		||||
    return { ...attrs, options: {...options, ...opts} };
 | 
			
		||||
    return { ...attrs, options: deepmerge(opts, options) };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static properties2children(properties = []) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user