feat(client): improve the collection manager module
This commit is contained in:
		
							parent
							
								
									57c9524f34
								
							
						
					
					
						commit
						37be46aacb
					
				@ -5,6 +5,7 @@ import {
 | 
				
			|||||||
  AntdSchemaComponentProvider,
 | 
					  AntdSchemaComponentProvider,
 | 
				
			||||||
  APIClientProvider,
 | 
					  APIClientProvider,
 | 
				
			||||||
  AuthLayout,
 | 
					  AuthLayout,
 | 
				
			||||||
 | 
					  ChinaRegionProvider,
 | 
				
			||||||
  CollectionManagerShortcut,
 | 
					  CollectionManagerShortcut,
 | 
				
			||||||
  compose,
 | 
					  compose,
 | 
				
			||||||
  DesignableSwitch,
 | 
					  DesignableSwitch,
 | 
				
			||||||
@ -53,6 +54,7 @@ const providers = [
 | 
				
			|||||||
  RemoteCollectionManagerProvider,
 | 
					  RemoteCollectionManagerProvider,
 | 
				
			||||||
  [SchemaInitializerProvider, { initializers: { MenuItemInitializers } }],
 | 
					  [SchemaInitializerProvider, { initializers: { MenuItemInitializers } }],
 | 
				
			||||||
  AntdSchemaComponentProvider,
 | 
					  AntdSchemaComponentProvider,
 | 
				
			||||||
 | 
					  ChinaRegionProvider,
 | 
				
			||||||
  [DocumentTitleProvider, { addonAfter: 'NocoBase' }],
 | 
					  [DocumentTitleProvider, { addonAfter: 'NocoBase' }],
 | 
				
			||||||
  [
 | 
					  [
 | 
				
			||||||
    RouteSwitchProvider,
 | 
					    RouteSwitchProvider,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										76
									
								
								packages/client/src/china-region/index.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								packages/client/src/china-region/index.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					import { ArrayField } from '@formily/core';
 | 
				
			||||||
 | 
					import { useField } from '@formily/react';
 | 
				
			||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { SchemaComponentOptions } from '..';
 | 
				
			||||||
 | 
					import { useAPIClient, useRequest } from '../api-client';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useChinaRegionDataSource = (options) => {
 | 
				
			||||||
 | 
					  const field = useField<ArrayField>();
 | 
				
			||||||
 | 
					  const maxLevel = field.componentProps.maxLevel;
 | 
				
			||||||
 | 
					  return useRequest(
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      resource: 'chinaRegions',
 | 
				
			||||||
 | 
					      action: 'list',
 | 
				
			||||||
 | 
					      params: {
 | 
				
			||||||
 | 
					        sort: 'code',
 | 
				
			||||||
 | 
					        filter: {
 | 
				
			||||||
 | 
					          level: 1,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      ...options,
 | 
				
			||||||
 | 
					      onSuccess(data) {
 | 
				
			||||||
 | 
					        options?.onSuccess({
 | 
				
			||||||
 | 
					          data:
 | 
				
			||||||
 | 
					            data?.data?.map((item) => {
 | 
				
			||||||
 | 
					              if (maxLevel !== 1) {
 | 
				
			||||||
 | 
					                item.isLeaf = false;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              return item;
 | 
				
			||||||
 | 
					            }) || [],
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useChinaRegionLoadData = () => {
 | 
				
			||||||
 | 
					  const api = useAPIClient();
 | 
				
			||||||
 | 
					  const field = useField<ArrayField>();
 | 
				
			||||||
 | 
					  const maxLevel = field.componentProps.maxLevel;
 | 
				
			||||||
 | 
					  return (selectedOptions) => {
 | 
				
			||||||
 | 
					    const targetOption = selectedOptions[selectedOptions.length - 1];
 | 
				
			||||||
 | 
					    if (targetOption?.children?.length > 0) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    targetOption.loading = true;
 | 
				
			||||||
 | 
					    api
 | 
				
			||||||
 | 
					      .resource('chinaRegions')
 | 
				
			||||||
 | 
					      .list({
 | 
				
			||||||
 | 
					        sort: 'code',
 | 
				
			||||||
 | 
					        filter: {
 | 
				
			||||||
 | 
					          parentCode: targetOption.code,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .then(({ data }) => {
 | 
				
			||||||
 | 
					        targetOption.loading = false;
 | 
				
			||||||
 | 
					        targetOption.children =
 | 
				
			||||||
 | 
					          data?.data?.map((item) => {
 | 
				
			||||||
 | 
					            if (maxLevel > item.level) {
 | 
				
			||||||
 | 
					              item.isLeaf = false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return item;
 | 
				
			||||||
 | 
					          }) || [];
 | 
				
			||||||
 | 
					        field.dataSource = [...field.dataSource];
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const ChinaRegionProvider = (props) => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <SchemaComponentOptions scope={{ useChinaRegionDataSource, useChinaRegionLoadData }}>
 | 
				
			||||||
 | 
					      {props.children}
 | 
				
			||||||
 | 
					    </SchemaComponentOptions>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
import { Field } from '@formily/core';
 | 
					import { Field } from '@formily/core';
 | 
				
			||||||
import { connect, useField, useFieldSchema } from '@formily/react';
 | 
					import { connect, useField, useFieldSchema } from '@formily/react';
 | 
				
			||||||
import React, { useEffect } from 'react';
 | 
					import React, { useEffect } from 'react';
 | 
				
			||||||
import { useComponent } from '..';
 | 
					import { useCompile, useComponent } from '..';
 | 
				
			||||||
import { CollectionFieldProvider } from './CollectionFieldProvider';
 | 
					import { CollectionFieldProvider } from './CollectionFieldProvider';
 | 
				
			||||||
import { useCollectionField } from './hooks';
 | 
					import { useCollectionField } from './hooks';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -11,6 +11,7 @@ const InternalField: React.FC = (props) => {
 | 
				
			|||||||
  const fieldSchema = useFieldSchema();
 | 
					  const fieldSchema = useFieldSchema();
 | 
				
			||||||
  const { uiSchema } = useCollectionField();
 | 
					  const { uiSchema } = useCollectionField();
 | 
				
			||||||
  const component = useComponent(uiSchema?.['x-component']);
 | 
					  const component = useComponent(uiSchema?.['x-component']);
 | 
				
			||||||
 | 
					  const compile = useCompile();
 | 
				
			||||||
  const setFieldProps = (key, value) => {
 | 
					  const setFieldProps = (key, value) => {
 | 
				
			||||||
    field[key] = typeof field[key] === 'undefined' ? value : field[key];
 | 
					    field[key] = typeof field[key] === 'undefined' ? value : field[key];
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
@ -24,6 +25,7 @@ const InternalField: React.FC = (props) => {
 | 
				
			|||||||
    if (!uiSchema) {
 | 
					    if (!uiSchema) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    console.log('uiSchema', uiSchema);
 | 
				
			||||||
    setFieldProps('title', uiSchema.title);
 | 
					    setFieldProps('title', uiSchema.title);
 | 
				
			||||||
    setFieldProps('description', uiSchema.description);
 | 
					    setFieldProps('description', uiSchema.description);
 | 
				
			||||||
    setFieldProps('initialValue', uiSchema.default);
 | 
					    setFieldProps('initialValue', uiSchema.default);
 | 
				
			||||||
 | 
				
			|||||||
@ -32,7 +32,7 @@ export const RemoteCollectionManagerProvider = (props: any) => {
 | 
				
			|||||||
    resource: 'collections',
 | 
					    resource: 'collections',
 | 
				
			||||||
    action: 'list',
 | 
					    action: 'list',
 | 
				
			||||||
    params: {
 | 
					    params: {
 | 
				
			||||||
      pageSize: 999,
 | 
					      paginate: false,
 | 
				
			||||||
      appends: ['fields', 'fields.uiSchema'],
 | 
					      appends: ['fields', 'fields.uiSchema'],
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
				
			|||||||
@ -1,18 +1,29 @@
 | 
				
			|||||||
import { PlusOutlined } from '@ant-design/icons';
 | 
					import { PlusOutlined } from '@ant-design/icons';
 | 
				
			||||||
import { ArrayTable } from '@formily/antd';
 | 
					import { ISchema, useForm } from '@formily/react';
 | 
				
			||||||
import { ISchema } from '@formily/react';
 | 
					 | 
				
			||||||
import { uid } from '@formily/shared';
 | 
					import { uid } from '@formily/shared';
 | 
				
			||||||
import { Button, Dropdown, Menu } from 'antd';
 | 
					import { Button, Dropdown, Menu } from 'antd';
 | 
				
			||||||
 | 
					import { cloneDeep } from 'lodash';
 | 
				
			||||||
import React, { useState } from 'react';
 | 
					import React, { useState } from 'react';
 | 
				
			||||||
 | 
					import { useRequest } from '../../api-client';
 | 
				
			||||||
import { ActionContext, SchemaComponent, useCompile } from '../../schema-component';
 | 
					import { ActionContext, SchemaComponent, useCompile } from '../../schema-component';
 | 
				
			||||||
 | 
					import { useCreateAction } from '../action-hooks';
 | 
				
			||||||
import { useCollectionManager } from '../hooks';
 | 
					import { useCollectionManager } from '../hooks';
 | 
				
			||||||
import { IField } from '../interfaces/types';
 | 
					import { IField } from '../interfaces/types';
 | 
				
			||||||
 | 
					import { ArrayTable } from './ArrayTable';
 | 
				
			||||||
import { options } from './interfaces';
 | 
					import { options } from './interfaces';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getSchema = (schema: IField): ISchema => {
 | 
					const getSchema = (schema: IField): ISchema => {
 | 
				
			||||||
  if (!schema) {
 | 
					  if (!schema) {
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  const properties = cloneDeep(schema.properties) as any;
 | 
				
			||||||
 | 
					  const initialValue = {
 | 
				
			||||||
 | 
					    ...cloneDeep(schema.default),
 | 
				
			||||||
 | 
					    interface: schema.name,
 | 
				
			||||||
 | 
					    name: `f_${uid()}`,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  initialValue.uiSchema.title = schema.title;
 | 
				
			||||||
 | 
					  console.log('initialValue', initialValue);
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    type: 'object',
 | 
					    type: 'object',
 | 
				
			||||||
    properties: {
 | 
					    properties: {
 | 
				
			||||||
@ -21,16 +32,20 @@ const getSchema = (schema: IField): ISchema => {
 | 
				
			|||||||
        'x-component': 'Action.Drawer',
 | 
					        'x-component': 'Action.Drawer',
 | 
				
			||||||
        'x-decorator': 'Form',
 | 
					        'x-decorator': 'Form',
 | 
				
			||||||
        'x-decorator-props': {
 | 
					        'x-decorator-props': {
 | 
				
			||||||
          initialValue: {
 | 
					          useValues(options) {
 | 
				
			||||||
            interface: schema.name,
 | 
					            return useRequest(
 | 
				
			||||||
            ...schema.default,
 | 
					              () =>
 | 
				
			||||||
            name: `f_${uid()}`,
 | 
					                Promise.resolve({
 | 
				
			||||||
 | 
					                  data: initialValue,
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					              options,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        title: '{{ t("Add field") }}',
 | 
					        title: '{{ t("Add field") }}',
 | 
				
			||||||
        properties: {
 | 
					        properties: {
 | 
				
			||||||
          // @ts-ignore
 | 
					          // @ts-ignore
 | 
				
			||||||
          ...schema.properties,
 | 
					          ...properties,
 | 
				
			||||||
          footer: {
 | 
					          footer: {
 | 
				
			||||||
            type: 'void',
 | 
					            type: 'void',
 | 
				
			||||||
            'x-component': 'Action.Drawer.Footer',
 | 
					            'x-component': 'Action.Drawer.Footer',
 | 
				
			||||||
@ -47,7 +62,7 @@ const getSchema = (schema: IField): ISchema => {
 | 
				
			|||||||
                'x-component': 'Action',
 | 
					                'x-component': 'Action',
 | 
				
			||||||
                'x-component-props': {
 | 
					                'x-component-props': {
 | 
				
			||||||
                  type: 'primary',
 | 
					                  type: 'primary',
 | 
				
			||||||
                  useAction: '{{ cm.useCreateActionAndRefreshCM }}',
 | 
					                  useAction: '{{ useCreateCollectionField }}',
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
              },
 | 
					              },
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
@ -58,6 +73,30 @@ const getSchema = (schema: IField): ISchema => {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useCreateCollectionField = () => {
 | 
				
			||||||
 | 
					  const form = useForm();
 | 
				
			||||||
 | 
					  const { run } = useCreateAction();
 | 
				
			||||||
 | 
					  const { refreshCM } = useCollectionManager();
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    async run() {
 | 
				
			||||||
 | 
					      await form.submit();
 | 
				
			||||||
 | 
					      const options = form?.values?.uiSchema?.enum?.slice() || [];
 | 
				
			||||||
 | 
					      form.setValuesIn(
 | 
				
			||||||
 | 
					        'uiSchema.enum',
 | 
				
			||||||
 | 
					        options.map((option) => {
 | 
				
			||||||
 | 
					          return {
 | 
				
			||||||
 | 
					            value: uid(),
 | 
				
			||||||
 | 
					            ...option,
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      console.log('form.values', form.values);
 | 
				
			||||||
 | 
					      await run();
 | 
				
			||||||
 | 
					      await refreshCM();
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const AddFieldAction = () => {
 | 
					export const AddFieldAction = () => {
 | 
				
			||||||
  const { getInterface } = useCollectionManager();
 | 
					  const { getInterface } = useCollectionManager();
 | 
				
			||||||
  const [visible, setVisible] = useState(false);
 | 
					  const [visible, setVisible] = useState(false);
 | 
				
			||||||
@ -78,7 +117,6 @@ export const AddFieldAction = () => {
 | 
				
			|||||||
              return (
 | 
					              return (
 | 
				
			||||||
                <Menu.SubMenu title={compile(option.label)}>
 | 
					                <Menu.SubMenu title={compile(option.label)}>
 | 
				
			||||||
                  {option.children.map((child) => {
 | 
					                  {option.children.map((child) => {
 | 
				
			||||||
                    console.log(child);
 | 
					 | 
				
			||||||
                    return <Menu.Item key={child.name}>{compile(child.title)}</Menu.Item>;
 | 
					                    return <Menu.Item key={child.name}>{compile(child.title)}</Menu.Item>;
 | 
				
			||||||
                  })}
 | 
					                  })}
 | 
				
			||||||
                </Menu.SubMenu>
 | 
					                </Menu.SubMenu>
 | 
				
			||||||
@ -91,7 +129,7 @@ export const AddFieldAction = () => {
 | 
				
			|||||||
          添加字段
 | 
					          添加字段
 | 
				
			||||||
        </Button>
 | 
					        </Button>
 | 
				
			||||||
      </Dropdown>
 | 
					      </Dropdown>
 | 
				
			||||||
      <SchemaComponent schema={schema} components={{ ArrayTable }} />
 | 
					      <SchemaComponent schema={schema} components={{ ArrayTable }} scope={{ useCreateCollectionField }} />
 | 
				
			||||||
    </ActionContext.Provider>
 | 
					    </ActionContext.Provider>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					import { ArrayBase, ArrayTable as FormilyArrayTable } from '@formily/antd';
 | 
				
			||||||
 | 
					import { connect } from '@formily/react';
 | 
				
			||||||
 | 
					import React, { Fragment } from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const ArrayTable: any = connect((props) => {
 | 
				
			||||||
 | 
					  const { onChange } = props;
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <FormilyArrayTable
 | 
				
			||||||
 | 
					      {...props}
 | 
				
			||||||
 | 
					      onChange={(value) => {
 | 
				
			||||||
 | 
					        console.log('onChange', value);
 | 
				
			||||||
 | 
					        onChange(value);
 | 
				
			||||||
 | 
					      }}
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ArrayTable.displayName = 'ArrayTable'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ArrayTable.Column = () => {
 | 
				
			||||||
 | 
					  return <Fragment />
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ArrayBase.mixin(ArrayTable)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -23,6 +23,8 @@ const useCollectionValues = (options) => {
 | 
				
			|||||||
      Promise.resolve({
 | 
					      Promise.resolve({
 | 
				
			||||||
        data: {
 | 
					        data: {
 | 
				
			||||||
          name: `t_${uid()}`,
 | 
					          name: `t_${uid()}`,
 | 
				
			||||||
 | 
					          createdBy: true,
 | 
				
			||||||
 | 
					          updatedBy: true,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      }),
 | 
					      }),
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -38,7 +40,7 @@ const useCollectionValues = (options) => {
 | 
				
			|||||||
  }, [visible]);
 | 
					  }, [visible]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return result;
 | 
					  return result;
 | 
				
			||||||
}
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const ConfigurationTable = () => {
 | 
					export const ConfigurationTable = () => {
 | 
				
			||||||
  const { collections = [] } = useCollectionManager();
 | 
					  const { collections = [] } = useCollectionManager();
 | 
				
			||||||
@ -50,7 +52,7 @@ export const ConfigurationTable = () => {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
      <SchemaComponent schema={collectionSchema} scope={{ useCollectionValues, useAsyncDataSource, loadCollections }}/>
 | 
					      <SchemaComponent schema={collectionSchema} scope={{ useCollectionValues, useAsyncDataSource, loadCollections }} />
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,18 +1,22 @@
 | 
				
			|||||||
import { ISchema } from '@formily/react';
 | 
					import { ISchema, useForm } from '@formily/react';
 | 
				
			||||||
import { uid } from '@formily/shared';
 | 
					import { uid } from '@formily/shared';
 | 
				
			||||||
import cloneDeep from 'lodash/cloneDeep';
 | 
					import cloneDeep from 'lodash/cloneDeep';
 | 
				
			||||||
import React, { useState } from 'react';
 | 
					import React, { useState } from 'react';
 | 
				
			||||||
import { useTranslation } from 'react-i18next';
 | 
					import { useTranslation } from 'react-i18next';
 | 
				
			||||||
import { useAPIClient } from '../../api-client';
 | 
					import { useAPIClient, useRequest } from '../../api-client';
 | 
				
			||||||
import { useRecord } from '../../record-provider';
 | 
					import { useRecord } from '../../record-provider';
 | 
				
			||||||
import { ActionContext, SchemaComponent } from '../../schema-component';
 | 
					import { ActionContext, SchemaComponent } from '../../schema-component';
 | 
				
			||||||
 | 
					import { useUpdateAction } from '../action-hooks';
 | 
				
			||||||
import { useCollectionManager } from '../hooks';
 | 
					import { useCollectionManager } from '../hooks';
 | 
				
			||||||
import { IField } from '../interfaces/types';
 | 
					import { IField } from '../interfaces/types';
 | 
				
			||||||
 | 
					import { ArrayTable } from './ArrayTable';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const getSchema = (schema: IField): ISchema => {
 | 
					const getSchema = (schema: IField): ISchema => {
 | 
				
			||||||
  if (!schema) {
 | 
					  if (!schema) {
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  const properties = cloneDeep(schema.properties) as any;
 | 
				
			||||||
 | 
					  properties.name['x-disabled'] = true;
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    type: 'object',
 | 
					    type: 'object',
 | 
				
			||||||
    properties: {
 | 
					    properties: {
 | 
				
			||||||
@ -21,12 +25,20 @@ const getSchema = (schema: IField): ISchema => {
 | 
				
			|||||||
        'x-component': 'Action.Drawer',
 | 
					        'x-component': 'Action.Drawer',
 | 
				
			||||||
        'x-decorator': 'Form',
 | 
					        'x-decorator': 'Form',
 | 
				
			||||||
        'x-decorator-props': {
 | 
					        'x-decorator-props': {
 | 
				
			||||||
          initialValue: cloneDeep(schema.default),
 | 
					          useValues(options) {
 | 
				
			||||||
 | 
					            return useRequest(
 | 
				
			||||||
 | 
					              () =>
 | 
				
			||||||
 | 
					                Promise.resolve({
 | 
				
			||||||
 | 
					                  data: cloneDeep(schema.default),
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					              options,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        title: '{{ t("Edit field") }}',
 | 
					        title: '{{ t("Edit field") }}',
 | 
				
			||||||
        properties: {
 | 
					        properties: {
 | 
				
			||||||
          // @ts-ignore
 | 
					          // @ts-ignore
 | 
				
			||||||
          ...schema.properties,
 | 
					          ...properties,
 | 
				
			||||||
          footer: {
 | 
					          footer: {
 | 
				
			||||||
            type: 'void',
 | 
					            type: 'void',
 | 
				
			||||||
            'x-component': 'Action.Drawer.Footer',
 | 
					            'x-component': 'Action.Drawer.Footer',
 | 
				
			||||||
@ -43,7 +55,7 @@ const getSchema = (schema: IField): ISchema => {
 | 
				
			|||||||
                'x-component': 'Action',
 | 
					                'x-component': 'Action',
 | 
				
			||||||
                'x-component-props': {
 | 
					                'x-component-props': {
 | 
				
			||||||
                  type: 'primary',
 | 
					                  type: 'primary',
 | 
				
			||||||
                  useAction: '{{ cm.useUpdateActionAndRefreshCM }}',
 | 
					                  useAction: '{{ useUpdateCollectionField }}',
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
              },
 | 
					              },
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
@ -54,6 +66,29 @@ const getSchema = (schema: IField): ISchema => {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useUpdateCollectionField = () => {
 | 
				
			||||||
 | 
					  const form = useForm();
 | 
				
			||||||
 | 
					  const { run } = useUpdateAction();
 | 
				
			||||||
 | 
					  const { refreshCM } = useCollectionManager();
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    async run() {
 | 
				
			||||||
 | 
					      await form.submit();
 | 
				
			||||||
 | 
					      const options = form?.values?.uiSchema?.enum?.slice() || [];
 | 
				
			||||||
 | 
					      form.setValuesIn(
 | 
				
			||||||
 | 
					        'uiSchema.enum',
 | 
				
			||||||
 | 
					        options.map((option) => {
 | 
				
			||||||
 | 
					          return {
 | 
				
			||||||
 | 
					            value: uid(),
 | 
				
			||||||
 | 
					            ...option,
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      await run();
 | 
				
			||||||
 | 
					      await refreshCM();
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const EditFieldAction = (props) => {
 | 
					export const EditFieldAction = (props) => {
 | 
				
			||||||
  const record = useRecord();
 | 
					  const record = useRecord();
 | 
				
			||||||
  const { getInterface } = useCollectionManager();
 | 
					  const { getInterface } = useCollectionManager();
 | 
				
			||||||
@ -79,7 +114,7 @@ export const EditFieldAction = (props) => {
 | 
				
			|||||||
      >
 | 
					      >
 | 
				
			||||||
        {t('Edit')}
 | 
					        {t('Edit')}
 | 
				
			||||||
      </a>
 | 
					      </a>
 | 
				
			||||||
      <SchemaComponent schema={schema} />
 | 
					      <SchemaComponent schema={schema} components={{ ArrayTable }} scope={{ useUpdateCollectionField }} />
 | 
				
			||||||
    </ActionContext.Provider>
 | 
					    </ActionContext.Provider>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
import { useContext } from 'react';
 | 
					import { useContext } from 'react';
 | 
				
			||||||
import { useAPIClient } from '../../api-client';
 | 
					import { useAPIClient } from '../../api-client';
 | 
				
			||||||
import { useRecord } from '../../record-provider';
 | 
					import { useRecord } from '../../record-provider';
 | 
				
			||||||
 | 
					import { useCompile } from '../../schema-component';
 | 
				
			||||||
import { CollectionFieldContext } from '../context';
 | 
					import { CollectionFieldContext } from '../context';
 | 
				
			||||||
import { useCollection } from './useCollection';
 | 
					import { useCollection } from './useCollection';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -8,6 +9,7 @@ export const useCollectionField = () => {
 | 
				
			|||||||
  const collection = useCollection();
 | 
					  const collection = useCollection();
 | 
				
			||||||
  const record = useRecord();
 | 
					  const record = useRecord();
 | 
				
			||||||
  const api = useAPIClient();
 | 
					  const api = useAPIClient();
 | 
				
			||||||
 | 
					  const compile = useCompile();
 | 
				
			||||||
  const ctx = useContext(CollectionFieldContext);
 | 
					  const ctx = useContext(CollectionFieldContext);
 | 
				
			||||||
  if (!ctx) {
 | 
					  if (!ctx) {
 | 
				
			||||||
    return {} as any;
 | 
					    return {} as any;
 | 
				
			||||||
@ -16,6 +18,7 @@ export const useCollectionField = () => {
 | 
				
			|||||||
  const resource = api?.resource(resourceName, record[ctx.sourceKey]);
 | 
					  const resource = api?.resource(resourceName, record[ctx.sourceKey]);
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    ...ctx,
 | 
					    ...ctx,
 | 
				
			||||||
 | 
					    uiSchema: compile(ctx.uiSchema),
 | 
				
			||||||
    resource,
 | 
					    resource,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -16,8 +16,9 @@ export const attachment: IField = {
 | 
				
			|||||||
      type: 'array',
 | 
					      type: 'array',
 | 
				
			||||||
      // title,
 | 
					      // title,
 | 
				
			||||||
      'x-component': 'Upload.Attachment',
 | 
					      'x-component': 'Upload.Attachment',
 | 
				
			||||||
      'x-decorator': 'FormItem',
 | 
					      'x-component-props': {
 | 
				
			||||||
      'x-designable-bar': 'Upload.DesignableBar',
 | 
					        action: 'attachments:upload',
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  initialize: (values: any) => {
 | 
					  initialize: (values: any) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -20,6 +20,8 @@ export const chinaRegion: IField = {
 | 
				
			|||||||
      // title,
 | 
					      // title,
 | 
				
			||||||
      'x-component': 'Cascader',
 | 
					      'x-component': 'Cascader',
 | 
				
			||||||
      'x-component-props': {
 | 
					      'x-component-props': {
 | 
				
			||||||
 | 
					        useDataSource: '{{ useChinaRegionDataSource }}',
 | 
				
			||||||
 | 
					        useLoadData: '{{ useChinaRegionLoadData }}',
 | 
				
			||||||
        changeOnSelectLast: false,
 | 
					        changeOnSelectLast: false,
 | 
				
			||||||
        labelInValue: true,
 | 
					        labelInValue: true,
 | 
				
			||||||
        maxLevel: 3,
 | 
					        maxLevel: 3,
 | 
				
			||||||
 | 
				
			|||||||
@ -15,12 +15,12 @@ export const linkTo: IField = {
 | 
				
			|||||||
    uiSchema: {
 | 
					    uiSchema: {
 | 
				
			||||||
      type: 'array',
 | 
					      type: 'array',
 | 
				
			||||||
      // title,
 | 
					      // title,
 | 
				
			||||||
      'x-component': 'Select.Drawer',
 | 
					      'x-component': 'RecordPicker',
 | 
				
			||||||
      'x-component-props': {},
 | 
					      'x-component-props': {},
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  initialize: (values: any) => {
 | 
					  initialize: (values: any) => {
 | 
				
			||||||
    if (values.dataType === 'belongsToMany') {
 | 
					    if (values.type === 'belongsToMany') {
 | 
				
			||||||
      if (!values.through) {
 | 
					      if (!values.through) {
 | 
				
			||||||
        values.through = `t_${uid()}`;
 | 
					        values.through = `t_${uid()}`;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -34,13 +34,9 @@ export const linkTo: IField = {
 | 
				
			|||||||
        values.sourceKey = 'id';
 | 
					        values.sourceKey = 'id';
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (!values.targetKey) {
 | 
					      if (!values.targetKey) {
 | 
				
			||||||
        if (values.target === 'roles') {
 | 
					 | 
				
			||||||
          values.targetKey = 'name';
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
        values.targetKey = 'id';
 | 
					        values.targetKey = 'id';
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  properties: {
 | 
					  properties: {
 | 
				
			||||||
    ...defaultProps,
 | 
					    ...defaultProps,
 | 
				
			||||||
 | 
				
			|||||||
@ -15,7 +15,7 @@ export const updatedBy: IField = {
 | 
				
			|||||||
    uiSchema: {
 | 
					    uiSchema: {
 | 
				
			||||||
      type: 'object',
 | 
					      type: 'object',
 | 
				
			||||||
      title: '{{t("Last updated by")}}',
 | 
					      title: '{{t("Last updated by")}}',
 | 
				
			||||||
      'x-component': 'Select.Drawer',
 | 
					      'x-component': 'RecordPicker',
 | 
				
			||||||
      'x-component-props': {
 | 
					      'x-component-props': {
 | 
				
			||||||
        fieldNames: {
 | 
					        fieldNames: {
 | 
				
			||||||
          value: 'id',
 | 
					          value: 'id',
 | 
				
			||||||
 | 
				
			|||||||
@ -7,6 +7,7 @@ export * from './api-client';
 | 
				
			|||||||
export * from './application';
 | 
					export * from './application';
 | 
				
			||||||
export * from './async-data-provider';
 | 
					export * from './async-data-provider';
 | 
				
			||||||
export * from './board';
 | 
					export * from './board';
 | 
				
			||||||
 | 
					export * from './china-region';
 | 
				
			||||||
export * from './collection-manager';
 | 
					export * from './collection-manager';
 | 
				
			||||||
export * from './document-title';
 | 
					export * from './document-title';
 | 
				
			||||||
export * from './i18n';
 | 
					export * from './i18n';
 | 
				
			||||||
 | 
				
			|||||||
@ -131,7 +131,7 @@
 | 
				
			|||||||
  "Created at": "创建日期",
 | 
					  "Created at": "创建日期",
 | 
				
			||||||
  "Last updated at": "最后修改日期",
 | 
					  "Last updated at": "最后修改日期",
 | 
				
			||||||
  "Created by": "创建人",
 | 
					  "Created by": "创建人",
 | 
				
			||||||
  "Last updated by": "最后更新日期",
 | 
					  "Last updated by": "最后修改人",
 | 
				
			||||||
  "Add field": "添加字段",
 | 
					  "Add field": "添加字段",
 | 
				
			||||||
  "Field display name": "字段名称",
 | 
					  "Field display name": "字段名称",
 | 
				
			||||||
  "Field type": "字段类型",
 | 
					  "Field type": "字段类型",
 | 
				
			||||||
 | 
				
			|||||||
@ -5,10 +5,18 @@ import { toArr } from '@formily/shared';
 | 
				
			|||||||
import { Cascader as AntdCascader } from 'antd';
 | 
					import { Cascader as AntdCascader } from 'antd';
 | 
				
			||||||
import { isBoolean, omit } from 'lodash';
 | 
					import { isBoolean, omit } from 'lodash';
 | 
				
			||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { useRequest } from '../../../api-client';
 | 
				
			||||||
import { defaultFieldNames } from './defaultFieldNames';
 | 
					import { defaultFieldNames } from './defaultFieldNames';
 | 
				
			||||||
import { ReadPretty } from './ReadPretty';
 | 
					import { ReadPretty } from './ReadPretty';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const useDefLoadData = (props: any) => props.loadData;
 | 
					const useDefDataSource = (options) => {
 | 
				
			||||||
 | 
					  const field = useField<ArrayField>();
 | 
				
			||||||
 | 
					  return useRequest(() => Promise.resolve({ data: field.dataSource || [] }), options);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useDefLoadData = (props: any) => {
 | 
				
			||||||
 | 
					  return props?.loadData;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Cascader = connect(
 | 
					export const Cascader = connect(
 | 
				
			||||||
  (props: any) => {
 | 
					  (props: any) => {
 | 
				
			||||||
@ -18,6 +26,7 @@ export const Cascader = connect(
 | 
				
			|||||||
      onChange,
 | 
					      onChange,
 | 
				
			||||||
      labelInValue,
 | 
					      labelInValue,
 | 
				
			||||||
      fieldNames = defaultFieldNames,
 | 
					      fieldNames = defaultFieldNames,
 | 
				
			||||||
 | 
					      useDataSource = useDefDataSource,
 | 
				
			||||||
      useLoadData = useDefLoadData,
 | 
					      useLoadData = useDefLoadData,
 | 
				
			||||||
      changeOnSelectLast,
 | 
					      changeOnSelectLast,
 | 
				
			||||||
      changeOnSelect,
 | 
					      changeOnSelect,
 | 
				
			||||||
@ -25,6 +34,11 @@ export const Cascader = connect(
 | 
				
			|||||||
      ...others
 | 
					      ...others
 | 
				
			||||||
    } = props;
 | 
					    } = props;
 | 
				
			||||||
    const loadData = useLoadData(props);
 | 
					    const loadData = useLoadData(props);
 | 
				
			||||||
 | 
					    const { loading } = useDataSource({
 | 
				
			||||||
 | 
					      onSuccess(data) {
 | 
				
			||||||
 | 
					        field.dataSource = data?.data || [];
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    // 兼容值为 object[] 的情况
 | 
					    // 兼容值为 object[] 的情况
 | 
				
			||||||
    const toValue = () => {
 | 
					    const toValue = () => {
 | 
				
			||||||
      return toArr(value).map((item) => {
 | 
					      return toArr(value).map((item) => {
 | 
				
			||||||
@ -54,17 +68,11 @@ export const Cascader = connect(
 | 
				
			|||||||
        return <span key={option[fieldNames.value]}>{option[fieldNames.label]} / </span>;
 | 
					        return <span key={option[fieldNames.value]}>{option[fieldNames.label]} / </span>;
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    // if (loadData) {
 | 
					 | 
				
			||||||
    //   Object.assign(others, {
 | 
					 | 
				
			||||||
    //     loadData: (selectedOptions: any[]) => {
 | 
					 | 
				
			||||||
    //       // 将 field 传给 loadData
 | 
					 | 
				
			||||||
    //       loadData(selectedOptions, field);
 | 
					 | 
				
			||||||
    //     },
 | 
					 | 
				
			||||||
    //   });
 | 
					 | 
				
			||||||
    // }
 | 
					 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <AntdCascader
 | 
					      <AntdCascader
 | 
				
			||||||
 | 
					        loading={loading}
 | 
				
			||||||
        {...others}
 | 
					        {...others}
 | 
				
			||||||
 | 
					        options={field.dataSource}
 | 
				
			||||||
        loadData={loadData}
 | 
					        loadData={loadData}
 | 
				
			||||||
        changeOnSelect={isBoolean(changeOnSelectLast) ? !changeOnSelectLast : changeOnSelect}
 | 
					        changeOnSelect={isBoolean(changeOnSelectLast) ? !changeOnSelectLast : changeOnSelect}
 | 
				
			||||||
        value={toValue()}
 | 
					        value={toValue()}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user