refactor: move menu load and dump function to core/client
This commit is contained in:
		
							parent
							
								
									7d508d0fc4
								
							
						
					
					
						commit
						f06518a05c
					
				@ -8,12 +8,15 @@ import { createDesignable } from '../..';
 | 
				
			|||||||
import {
 | 
					import {
 | 
				
			||||||
  GeneralSchemaDesigner,
 | 
					  GeneralSchemaDesigner,
 | 
				
			||||||
  SchemaSettingsDivider,
 | 
					  SchemaSettingsDivider,
 | 
				
			||||||
 | 
					  SchemaSettingsItem,
 | 
				
			||||||
  SchemaSettingsModalItem,
 | 
					  SchemaSettingsModalItem,
 | 
				
			||||||
  SchemaSettingsRemove,
 | 
					  SchemaSettingsRemove,
 | 
				
			||||||
  SchemaSettingsSubMenu,
 | 
					  SchemaSettingsSubMenu,
 | 
				
			||||||
  useAPIClient,
 | 
					  useAPIClient,
 | 
				
			||||||
  useDesignable,
 | 
					  useDesignable,
 | 
				
			||||||
} from '../../../';
 | 
					} from '../../../';
 | 
				
			||||||
 | 
					import { message } from 'antd';
 | 
				
			||||||
 | 
					import { saveAs } from 'file-saver';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const toItems = (properties = {}) => {
 | 
					const toItems = (properties = {}) => {
 | 
				
			||||||
  const items = [];
 | 
					  const items = [];
 | 
				
			||||||
@ -52,6 +55,7 @@ const InsertMenuItems = (props) => {
 | 
				
			|||||||
  const { dn } = useDesignable();
 | 
					  const { dn } = useDesignable();
 | 
				
			||||||
  const fieldSchema = useFieldSchema();
 | 
					  const fieldSchema = useFieldSchema();
 | 
				
			||||||
  const isSubMenu = fieldSchema['x-component'] === 'Menu.SubMenu';
 | 
					  const isSubMenu = fieldSchema['x-component'] === 'Menu.SubMenu';
 | 
				
			||||||
 | 
					  const api = useAPIClient();
 | 
				
			||||||
  if (!isSubMenu && insertPosition === 'beforeEnd') {
 | 
					  if (!isSubMenu && insertPosition === 'beforeEnd') {
 | 
				
			||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -197,6 +201,45 @@ const InsertMenuItems = (props) => {
 | 
				
			|||||||
          });
 | 
					          });
 | 
				
			||||||
        }}
 | 
					        }}
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
 | 
					      <SchemaSettingsDivider />
 | 
				
			||||||
 | 
					      <SchemaSettingsModalItem
 | 
				
			||||||
 | 
					        eventKey={`${insertPosition}restore`}
 | 
				
			||||||
 | 
					        title={t('Load')}
 | 
				
			||||||
 | 
					        schema={
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            type: 'object',
 | 
				
			||||||
 | 
					            title: t('Load'),
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              title: {
 | 
				
			||||||
 | 
					                'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                'x-component': 'Input',
 | 
				
			||||||
 | 
					                title: t('Menu item title'),
 | 
				
			||||||
 | 
					                required: true,
 | 
				
			||||||
 | 
					                'x-component-props': {},
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              file: {
 | 
				
			||||||
 | 
					                type: 'object',
 | 
				
			||||||
 | 
					                title: '{{ t("File") }}',
 | 
				
			||||||
 | 
					                'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					                'x-component': 'Upload.Attachment',
 | 
				
			||||||
 | 
					                'x-component-props': {
 | 
				
			||||||
 | 
					                  action: 'attachments:create',
 | 
				
			||||||
 | 
					                  multiple: false,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          } as ISchema
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        onSubmit={async ({ title, file }) => {
 | 
				
			||||||
 | 
					          const { data } = await api.request({
 | 
				
			||||||
 | 
					            url: file.url,
 | 
				
			||||||
 | 
					            baseURL: '/',
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          const s = data ?? {};
 | 
				
			||||||
 | 
					          s.title = title;
 | 
				
			||||||
 | 
					          dn.insertAdjacent(insertPosition, s);
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
    </SchemaSettingsSubMenu>
 | 
					    </SchemaSettingsSubMenu>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -344,6 +387,26 @@ export const MenuDesigner = () => {
 | 
				
			|||||||
      <InsertMenuItems eventKey={'insertafterEnd'} title={t('Insert after')} insertPosition={'afterEnd'} />
 | 
					      <InsertMenuItems eventKey={'insertafterEnd'} title={t('Insert after')} insertPosition={'afterEnd'} />
 | 
				
			||||||
      <InsertMenuItems eventKey={'insertbeforeEnd'} title={t('Insert inner')} insertPosition={'beforeEnd'} />
 | 
					      <InsertMenuItems eventKey={'insertbeforeEnd'} title={t('Insert inner')} insertPosition={'beforeEnd'} />
 | 
				
			||||||
      <SchemaSettingsDivider />
 | 
					      <SchemaSettingsDivider />
 | 
				
			||||||
 | 
					      <SchemaSettingsItem
 | 
				
			||||||
 | 
					        title={t('Dump')}
 | 
				
			||||||
 | 
					        onClick={async () => {
 | 
				
			||||||
 | 
					          const deleteUid = (s: ISchema) => {
 | 
				
			||||||
 | 
					            delete s['name'];
 | 
				
			||||||
 | 
					            delete s['x-uid'];
 | 
				
			||||||
 | 
					            Object.keys(s.properties || {}).forEach((key) => {
 | 
				
			||||||
 | 
					              deleteUid(s.properties[key]);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          const { data } = await api.request({
 | 
				
			||||||
 | 
					            url: `/uiSchemas:getJsonSchema/${fieldSchema['x-uid']}?includeAsyncNode=true`,
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          const s = data?.data || {};
 | 
				
			||||||
 | 
					          deleteUid(s);
 | 
				
			||||||
 | 
					          const blob = new Blob([JSON.stringify(s, null, 2)], { type: 'application/json' });
 | 
				
			||||||
 | 
					          saveAs(blob, fieldSchema['x-uid'] + '.schema.json');
 | 
				
			||||||
 | 
					          message.success('Save successful!');
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
      <SchemaSettingsRemove
 | 
					      <SchemaSettingsRemove
 | 
				
			||||||
        confirm={{
 | 
					        confirm={{
 | 
				
			||||||
          title: t('Delete menu item'),
 | 
					          title: t('Delete menu item'),
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
import { Menu, Plugin, RemoteSchemaTemplateManagerProvider, EditTitleField, useCollection } from '@nocobase/client';
 | 
					import { Plugin, RemoteSchemaTemplateManagerProvider, EditTitleField, useCollection } from '@nocobase/client';
 | 
				
			||||||
import { remove } from 'lodash';
 | 
					import { remove } from 'lodash';
 | 
				
			||||||
import { useFieldSchema } from '@formily/react';
 | 
					import { useFieldSchema } from '@formily/react';
 | 
				
			||||||
import { isValid } from '@formily/shared';
 | 
					import { isValid } from '@formily/shared';
 | 
				
			||||||
@ -42,7 +42,7 @@ import {
 | 
				
			|||||||
  Expression,
 | 
					  Expression,
 | 
				
			||||||
  SignatureInput,
 | 
					  SignatureInput,
 | 
				
			||||||
} from './components';
 | 
					} from './components';
 | 
				
			||||||
import { AutoComplete, InternalPDFViewer, MenuDesigner } from './schema-components';
 | 
					import { AutoComplete, InternalPDFViewer } from './schema-components';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  CreateSubmitActionInitializer,
 | 
					  CreateSubmitActionInitializer,
 | 
				
			||||||
  FilterFormItem,
 | 
					  FilterFormItem,
 | 
				
			||||||
@ -176,11 +176,6 @@ export class PluginCoreClient extends Plugin {
 | 
				
			|||||||
      FilterFormItemCustom,
 | 
					      FilterFormItemCustom,
 | 
				
			||||||
      FilterItemCustomDesigner,
 | 
					      FilterItemCustomDesigner,
 | 
				
			||||||
      FilterVariableInput,
 | 
					      FilterVariableInput,
 | 
				
			||||||
      Menu: {
 | 
					 | 
				
			||||||
        ...Menu,
 | 
					 | 
				
			||||||
        // @ts-ignore
 | 
					 | 
				
			||||||
        Designer: MenuDesigner,
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      PDFViewerBlockInitializer,
 | 
					      PDFViewerBlockInitializer,
 | 
				
			||||||
      PDFViewerPrintActionInitializer,
 | 
					      PDFViewerPrintActionInitializer,
 | 
				
			||||||
      PDFViewerProvider,
 | 
					      PDFViewerProvider,
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
export * from './associated';
 | 
					export * from './AssociatedFieldInterface';
 | 
				
			||||||
export * from './calc';
 | 
					export * from './CalcFieldInterface';
 | 
				
			||||||
export * from './custom';
 | 
					export * from './CustomFieldInterface';
 | 
				
			||||||
export * from './customAssociated';
 | 
					export * from './CustomAssociatedFieldInterface';
 | 
				
			||||||
export * from './signatureSchema';
 | 
					export * from './SignaturePadFieldInterface';
 | 
				
			||||||
 | 
				
			|||||||
@ -1,416 +0,0 @@
 | 
				
			|||||||
import { TreeSelect } from '@formily/antd-v5';
 | 
					 | 
				
			||||||
import { Field, onFieldChange } from '@formily/core';
 | 
					 | 
				
			||||||
import { ISchema, Schema, useField, useFieldSchema } from '@formily/react';
 | 
					 | 
				
			||||||
import React from 'react';
 | 
					 | 
				
			||||||
import { useTranslation } from 'react-i18next';
 | 
					 | 
				
			||||||
import { message } from 'antd';
 | 
					 | 
				
			||||||
import { saveAs } from 'file-saver';
 | 
					 | 
				
			||||||
import {
 | 
					 | 
				
			||||||
  GeneralSchemaDesigner,
 | 
					 | 
				
			||||||
  SchemaSettingsDivider,
 | 
					 | 
				
			||||||
  SchemaSettingsItem,
 | 
					 | 
				
			||||||
  SchemaSettingsModalItem,
 | 
					 | 
				
			||||||
  SchemaSettingsRemove,
 | 
					 | 
				
			||||||
  SchemaSettingsSubMenu,
 | 
					 | 
				
			||||||
  createDesignable,
 | 
					 | 
				
			||||||
  findByUid,
 | 
					 | 
				
			||||||
  useAPIClient,
 | 
					 | 
				
			||||||
  useDesignable,
 | 
					 | 
				
			||||||
} from '@nocobase/client';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const toItems = (properties = {}) => {
 | 
					 | 
				
			||||||
  const items = [];
 | 
					 | 
				
			||||||
  for (const key in properties) {
 | 
					 | 
				
			||||||
    if (Object.prototype.hasOwnProperty.call(properties, key)) {
 | 
					 | 
				
			||||||
      const element = properties[key];
 | 
					 | 
				
			||||||
      const item = {
 | 
					 | 
				
			||||||
        label: element.title,
 | 
					 | 
				
			||||||
        value: `${element['x-uid']}||${element['x-component']}`,
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
      if (element.properties) {
 | 
					 | 
				
			||||||
        const children = toItems(element.properties);
 | 
					 | 
				
			||||||
        if (children?.length) {
 | 
					 | 
				
			||||||
          item['children'] = children;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      items.push(item);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return items;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const findMenuSchema = (fieldSchema: Schema) => {
 | 
					 | 
				
			||||||
  let parent = fieldSchema.parent;
 | 
					 | 
				
			||||||
  while (parent) {
 | 
					 | 
				
			||||||
    if (parent['x-component'] === 'Menu') {
 | 
					 | 
				
			||||||
      return parent;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    parent = parent.parent;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const InsertMenuItems = (props) => {
 | 
					 | 
				
			||||||
  const { eventKey, title, insertPosition } = props;
 | 
					 | 
				
			||||||
  const { t } = useTranslation();
 | 
					 | 
				
			||||||
  const { dn } = useDesignable();
 | 
					 | 
				
			||||||
  const fieldSchema = useFieldSchema();
 | 
					 | 
				
			||||||
  const isSubMenu = fieldSchema['x-component'] === 'Menu.SubMenu';
 | 
					 | 
				
			||||||
  const api = useAPIClient();
 | 
					 | 
				
			||||||
  if (!isSubMenu && insertPosition === 'beforeEnd') {
 | 
					 | 
				
			||||||
    return null;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  const serverHooks = [
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      type: 'onSelfCreate',
 | 
					 | 
				
			||||||
      method: 'bindMenuToRole',
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      type: 'onSelfSave',
 | 
					 | 
				
			||||||
      method: 'extractTextToLocale',
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  ];
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <SchemaSettingsSubMenu eventKey={eventKey} title={title}>
 | 
					 | 
				
			||||||
      <SchemaSettingsModalItem
 | 
					 | 
				
			||||||
        eventKey={`${insertPosition}group`}
 | 
					 | 
				
			||||||
        title={t('Group')}
 | 
					 | 
				
			||||||
        schema={
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            type: 'object',
 | 
					 | 
				
			||||||
            title: t('Add group'),
 | 
					 | 
				
			||||||
            properties: {
 | 
					 | 
				
			||||||
              title: {
 | 
					 | 
				
			||||||
                'x-decorator': 'FormItem',
 | 
					 | 
				
			||||||
                'x-component': 'Input',
 | 
					 | 
				
			||||||
                title: t('Menu item title'),
 | 
					 | 
				
			||||||
                required: true,
 | 
					 | 
				
			||||||
                'x-component-props': {},
 | 
					 | 
				
			||||||
                // description: `原字段标题:${collectionField?.uiSchema?.title}`,
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
              icon: {
 | 
					 | 
				
			||||||
                title: t('Icon'),
 | 
					 | 
				
			||||||
                'x-component': 'IconPicker',
 | 
					 | 
				
			||||||
                'x-decorator': 'FormItem',
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
          } as ISchema
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        onSubmit={({ title, icon }) => {
 | 
					 | 
				
			||||||
          dn.insertAdjacent(insertPosition, {
 | 
					 | 
				
			||||||
            type: 'void',
 | 
					 | 
				
			||||||
            title,
 | 
					 | 
				
			||||||
            'x-component': 'Menu.SubMenu',
 | 
					 | 
				
			||||||
            'x-decorator': 'ACLMenuItemProvider',
 | 
					 | 
				
			||||||
            'x-component-props': {
 | 
					 | 
				
			||||||
              icon,
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            'x-server-hooks': serverHooks,
 | 
					 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <SchemaSettingsModalItem
 | 
					 | 
				
			||||||
        eventKey={`${insertPosition}page`}
 | 
					 | 
				
			||||||
        title={t('Page')}
 | 
					 | 
				
			||||||
        schema={
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            type: 'object',
 | 
					 | 
				
			||||||
            title: t('Add page'),
 | 
					 | 
				
			||||||
            properties: {
 | 
					 | 
				
			||||||
              title: {
 | 
					 | 
				
			||||||
                'x-decorator': 'FormItem',
 | 
					 | 
				
			||||||
                'x-component': 'Input',
 | 
					 | 
				
			||||||
                title: t('Menu item title'),
 | 
					 | 
				
			||||||
                required: true,
 | 
					 | 
				
			||||||
                'x-component-props': {},
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
              icon: {
 | 
					 | 
				
			||||||
                title: t('Icon'),
 | 
					 | 
				
			||||||
                'x-component': 'IconPicker',
 | 
					 | 
				
			||||||
                'x-decorator': 'FormItem',
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
          } as ISchema
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        onSubmit={({ title, icon }) => {
 | 
					 | 
				
			||||||
          dn.insertAdjacent(insertPosition, {
 | 
					 | 
				
			||||||
            type: 'void',
 | 
					 | 
				
			||||||
            title,
 | 
					 | 
				
			||||||
            'x-component': 'Menu.Item',
 | 
					 | 
				
			||||||
            'x-decorator': 'ACLMenuItemProvider',
 | 
					 | 
				
			||||||
            'x-component-props': {
 | 
					 | 
				
			||||||
              icon,
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            'x-server-hooks': serverHooks,
 | 
					 | 
				
			||||||
            properties: {
 | 
					 | 
				
			||||||
              page: {
 | 
					 | 
				
			||||||
                type: 'void',
 | 
					 | 
				
			||||||
                'x-component': 'Page',
 | 
					 | 
				
			||||||
                'x-async': true,
 | 
					 | 
				
			||||||
                properties: {
 | 
					 | 
				
			||||||
                  grid: {
 | 
					 | 
				
			||||||
                    type: 'void',
 | 
					 | 
				
			||||||
                    'x-component': 'Grid',
 | 
					 | 
				
			||||||
                    'x-initializer': 'BlockInitializers',
 | 
					 | 
				
			||||||
                    properties: {},
 | 
					 | 
				
			||||||
                  },
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <SchemaSettingsModalItem
 | 
					 | 
				
			||||||
        eventKey={`${insertPosition}link`}
 | 
					 | 
				
			||||||
        title={t('Link')}
 | 
					 | 
				
			||||||
        schema={
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            type: 'object',
 | 
					 | 
				
			||||||
            title: t('Add link'),
 | 
					 | 
				
			||||||
            properties: {
 | 
					 | 
				
			||||||
              title: {
 | 
					 | 
				
			||||||
                title: t('Menu item title'),
 | 
					 | 
				
			||||||
                required: true,
 | 
					 | 
				
			||||||
                'x-component': 'Input',
 | 
					 | 
				
			||||||
                'x-decorator': 'FormItem',
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
              icon: {
 | 
					 | 
				
			||||||
                title: t('Icon'),
 | 
					 | 
				
			||||||
                'x-component': 'IconPicker',
 | 
					 | 
				
			||||||
                'x-decorator': 'FormItem',
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
              href: {
 | 
					 | 
				
			||||||
                title: t('Link'),
 | 
					 | 
				
			||||||
                'x-component': 'Input',
 | 
					 | 
				
			||||||
                'x-decorator': 'FormItem',
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
          } as ISchema
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        onSubmit={({ title, icon, href }) => {
 | 
					 | 
				
			||||||
          dn.insertAdjacent(insertPosition, {
 | 
					 | 
				
			||||||
            type: 'void',
 | 
					 | 
				
			||||||
            title,
 | 
					 | 
				
			||||||
            'x-component': 'Menu.URL',
 | 
					 | 
				
			||||||
            'x-decorator': 'ACLMenuItemProvider',
 | 
					 | 
				
			||||||
            'x-component-props': {
 | 
					 | 
				
			||||||
              icon,
 | 
					 | 
				
			||||||
              href,
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            'x-server-hooks': serverHooks,
 | 
					 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <SchemaSettingsDivider />
 | 
					 | 
				
			||||||
      <SchemaSettingsModalItem
 | 
					 | 
				
			||||||
        eventKey={`${insertPosition}restore`}
 | 
					 | 
				
			||||||
        title="加载……"
 | 
					 | 
				
			||||||
        schema={
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            type: 'object',
 | 
					 | 
				
			||||||
            title: '加载……',
 | 
					 | 
				
			||||||
            properties: {
 | 
					 | 
				
			||||||
              title: {
 | 
					 | 
				
			||||||
                'x-decorator': 'FormItem',
 | 
					 | 
				
			||||||
                'x-component': 'Input',
 | 
					 | 
				
			||||||
                title: t('Menu item title'),
 | 
					 | 
				
			||||||
                required: true,
 | 
					 | 
				
			||||||
                'x-component-props': {},
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
              file: {
 | 
					 | 
				
			||||||
                type: 'object',
 | 
					 | 
				
			||||||
                title: '文件',
 | 
					 | 
				
			||||||
                'x-decorator': 'FormItem',
 | 
					 | 
				
			||||||
                'x-component': 'Upload.Attachment',
 | 
					 | 
				
			||||||
                'x-component-props': {
 | 
					 | 
				
			||||||
                  action: 'attachments:create',
 | 
					 | 
				
			||||||
                  multiple: false,
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
          } as ISchema
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        onSubmit={async ({ title, file }) => {
 | 
					 | 
				
			||||||
          const { data } = await api.request({
 | 
					 | 
				
			||||||
            url: file.url,
 | 
					 | 
				
			||||||
            baseURL: '/',
 | 
					 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
          const s = data ?? {};
 | 
					 | 
				
			||||||
          s.title = title;
 | 
					 | 
				
			||||||
          dn.insertAdjacent(insertPosition, s);
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </SchemaSettingsSubMenu>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const MenuDesigner = () => {
 | 
					 | 
				
			||||||
  const field = useField();
 | 
					 | 
				
			||||||
  const fieldSchema = useFieldSchema();
 | 
					 | 
				
			||||||
  const api = useAPIClient();
 | 
					 | 
				
			||||||
  const { dn, refresh } = useDesignable();
 | 
					 | 
				
			||||||
  const { t } = useTranslation();
 | 
					 | 
				
			||||||
  const menuSchema = findMenuSchema(fieldSchema);
 | 
					 | 
				
			||||||
  const items = toItems(menuSchema?.properties);
 | 
					 | 
				
			||||||
  const effects = (form) => {
 | 
					 | 
				
			||||||
    onFieldChange('target', (field: Field) => {
 | 
					 | 
				
			||||||
      const [, component] = field?.value?.split?.('||') || [];
 | 
					 | 
				
			||||||
      field.query('position').take((f: Field) => {
 | 
					 | 
				
			||||||
        f.dataSource =
 | 
					 | 
				
			||||||
          component === 'Menu.SubMenu'
 | 
					 | 
				
			||||||
            ? [
 | 
					 | 
				
			||||||
                { label: t('Before'), value: 'beforeBegin' },
 | 
					 | 
				
			||||||
                { label: t('After'), value: 'afterEnd' },
 | 
					 | 
				
			||||||
                { label: t('Inner'), value: 'beforeEnd' },
 | 
					 | 
				
			||||||
              ]
 | 
					 | 
				
			||||||
            : [
 | 
					 | 
				
			||||||
                { label: t('Before'), value: 'beforeBegin' },
 | 
					 | 
				
			||||||
                { label: t('After'), value: 'afterEnd' },
 | 
					 | 
				
			||||||
              ];
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  const schema = {
 | 
					 | 
				
			||||||
    type: 'object',
 | 
					 | 
				
			||||||
    title: t('Edit menu item'),
 | 
					 | 
				
			||||||
    properties: {
 | 
					 | 
				
			||||||
      title: {
 | 
					 | 
				
			||||||
        title: t('Menu item title'),
 | 
					 | 
				
			||||||
        required: true,
 | 
					 | 
				
			||||||
        'x-decorator': 'FormItem',
 | 
					 | 
				
			||||||
        'x-component': 'Input',
 | 
					 | 
				
			||||||
        'x-component-props': {},
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      icon: {
 | 
					 | 
				
			||||||
        title: t('Menu item icon'),
 | 
					 | 
				
			||||||
        'x-component': 'IconPicker',
 | 
					 | 
				
			||||||
        'x-decorator': 'FormItem',
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  const initialValues = {
 | 
					 | 
				
			||||||
    title: field.title,
 | 
					 | 
				
			||||||
    icon: field.componentProps.icon,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  if (fieldSchema['x-component'] === 'Menu.URL') {
 | 
					 | 
				
			||||||
    schema.properties['href'] = {
 | 
					 | 
				
			||||||
      title: t('Link'),
 | 
					 | 
				
			||||||
      'x-component': 'Input',
 | 
					 | 
				
			||||||
      'x-decorator': 'FormItem',
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    initialValues['href'] = field.componentProps.href;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <GeneralSchemaDesigner>
 | 
					 | 
				
			||||||
      <SchemaSettingsModalItem
 | 
					 | 
				
			||||||
        title={t('Edit')}
 | 
					 | 
				
			||||||
        eventKey="edit"
 | 
					 | 
				
			||||||
        schema={schema as ISchema}
 | 
					 | 
				
			||||||
        initialValues={initialValues}
 | 
					 | 
				
			||||||
        onSubmit={({ title, icon, href }) => {
 | 
					 | 
				
			||||||
          const schema = {
 | 
					 | 
				
			||||||
            ['x-uid']: fieldSchema['x-uid'],
 | 
					 | 
				
			||||||
            'x-server-hooks': [
 | 
					 | 
				
			||||||
              {
 | 
					 | 
				
			||||||
                type: 'onSelfSave',
 | 
					 | 
				
			||||||
                method: 'extractTextToLocale',
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
          };
 | 
					 | 
				
			||||||
          if (title) {
 | 
					 | 
				
			||||||
            fieldSchema.title = title;
 | 
					 | 
				
			||||||
            field.title = title;
 | 
					 | 
				
			||||||
            schema['title'] = title;
 | 
					 | 
				
			||||||
            refresh();
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          field.componentProps.icon = icon;
 | 
					 | 
				
			||||||
          field.componentProps.href = href;
 | 
					 | 
				
			||||||
          schema['x-component-props'] = { icon, href };
 | 
					 | 
				
			||||||
          fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
 | 
					 | 
				
			||||||
          fieldSchema['x-component-props']['icon'] = icon;
 | 
					 | 
				
			||||||
          fieldSchema['x-component-props']['href'] = href;
 | 
					 | 
				
			||||||
          dn.emit('patch', {
 | 
					 | 
				
			||||||
            schema,
 | 
					 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <SchemaSettingsModalItem
 | 
					 | 
				
			||||||
        title={t('Move to')}
 | 
					 | 
				
			||||||
        eventKey="move-to"
 | 
					 | 
				
			||||||
        components={{ TreeSelect }}
 | 
					 | 
				
			||||||
        effects={effects}
 | 
					 | 
				
			||||||
        schema={
 | 
					 | 
				
			||||||
          {
 | 
					 | 
				
			||||||
            type: 'object',
 | 
					 | 
				
			||||||
            title: t('Move to'),
 | 
					 | 
				
			||||||
            properties: {
 | 
					 | 
				
			||||||
              target: {
 | 
					 | 
				
			||||||
                title: t('Target'),
 | 
					 | 
				
			||||||
                enum: items,
 | 
					 | 
				
			||||||
                required: true,
 | 
					 | 
				
			||||||
                'x-decorator': 'FormItem',
 | 
					 | 
				
			||||||
                'x-component': 'TreeSelect',
 | 
					 | 
				
			||||||
                'x-component-props': {},
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
              position: {
 | 
					 | 
				
			||||||
                title: t('Position'),
 | 
					 | 
				
			||||||
                required: true,
 | 
					 | 
				
			||||||
                enum: [
 | 
					 | 
				
			||||||
                  { label: t('Before'), value: 'beforeBegin' },
 | 
					 | 
				
			||||||
                  { label: t('After'), value: 'afterEnd' },
 | 
					 | 
				
			||||||
                ],
 | 
					 | 
				
			||||||
                default: 'afterEnd',
 | 
					 | 
				
			||||||
                'x-component': 'Radio.Group',
 | 
					 | 
				
			||||||
                'x-decorator': 'FormItem',
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
          } as ISchema
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        onSubmit={({ target, position }) => {
 | 
					 | 
				
			||||||
          const [uid] = target?.split?.('||') || [];
 | 
					 | 
				
			||||||
          if (!uid) {
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          const current = findByUid(menuSchema, uid);
 | 
					 | 
				
			||||||
          const dn = createDesignable({
 | 
					 | 
				
			||||||
            t,
 | 
					 | 
				
			||||||
            api,
 | 
					 | 
				
			||||||
            refresh,
 | 
					 | 
				
			||||||
            current,
 | 
					 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
          dn.loadAPIClientEvents();
 | 
					 | 
				
			||||||
          dn.insertAdjacent(position, fieldSchema);
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <SchemaSettingsDivider />
 | 
					 | 
				
			||||||
      <InsertMenuItems eventKey={'insertbeforeBegin'} title={t('Insert before')} insertPosition={'beforeBegin'} />
 | 
					 | 
				
			||||||
      <InsertMenuItems eventKey={'insertafterEnd'} title={t('Insert after')} insertPosition={'afterEnd'} />
 | 
					 | 
				
			||||||
      <InsertMenuItems eventKey={'insertbeforeEnd'} title={t('Insert inner')} insertPosition={'beforeEnd'} />
 | 
					 | 
				
			||||||
      <SchemaSettingsDivider />
 | 
					 | 
				
			||||||
      <SchemaSettingsItem
 | 
					 | 
				
			||||||
        title="保存……"
 | 
					 | 
				
			||||||
        onClick={async () => {
 | 
					 | 
				
			||||||
          const deleteUid = (s: ISchema) => {
 | 
					 | 
				
			||||||
            delete s['name'];
 | 
					 | 
				
			||||||
            delete s['x-uid'];
 | 
					 | 
				
			||||||
            Object.keys(s.properties || {}).forEach((key) => {
 | 
					 | 
				
			||||||
              deleteUid(s.properties[key]);
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
          };
 | 
					 | 
				
			||||||
          const { data } = await api.request({
 | 
					 | 
				
			||||||
            url: `/uiSchemas:getJsonSchema/${fieldSchema['x-uid']}?includeAsyncNode=true`,
 | 
					 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
          const s = data?.data || {};
 | 
					 | 
				
			||||||
          deleteUid(s);
 | 
					 | 
				
			||||||
          const blob = new Blob([JSON.stringify(s, null, 2)], { type: 'application/json' });
 | 
					 | 
				
			||||||
          saveAs(blob, 'export.json');
 | 
					 | 
				
			||||||
          message.success('保存成功');
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
      <SchemaSettingsRemove
 | 
					 | 
				
			||||||
        confirm={{
 | 
					 | 
				
			||||||
          title: t('Delete menu item'),
 | 
					 | 
				
			||||||
        }}
 | 
					 | 
				
			||||||
      />
 | 
					 | 
				
			||||||
    </GeneralSchemaDesigner>
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@ -1,4 +1,3 @@
 | 
				
			|||||||
export * from './auto-complete/AutoComplete';
 | 
					export * from './auto-complete/AutoComplete';
 | 
				
			||||||
export * from './blocks/GroupBlock';
 | 
					export * from './blocks/GroupBlock';
 | 
				
			||||||
export * from './blocks/PDFViewer';
 | 
					export * from './blocks/PDFViewer';
 | 
				
			||||||
export * from './deprecated/ExtendedMenuDesigner';
 | 
					 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user