feat: improve sub table
This commit is contained in:
		
							parent
							
								
									f5b2600640
								
							
						
					
					
						commit
						6d0978f2c2
					
				@ -1,8 +1,8 @@
 | 
				
			|||||||
import React, { createContext } from 'react';
 | 
					 | 
				
			||||||
import { I18nextProvider, useTranslation } from 'react-i18next';
 | 
					 | 
				
			||||||
import { ConfigProvider, Spin } from 'antd';
 | 
					import { ConfigProvider, Spin } from 'antd';
 | 
				
			||||||
import enUS from 'antd/lib/locale/en_US';
 | 
					import enUS from 'antd/lib/locale/en_US';
 | 
				
			||||||
import zhCN from 'antd/lib/locale/zh_CN';
 | 
					import zhCN from 'antd/lib/locale/zh_CN';
 | 
				
			||||||
 | 
					import React from 'react';
 | 
				
			||||||
 | 
					import { useTranslation } from 'react-i18next';
 | 
				
			||||||
import { useRequest } from '../api-client';
 | 
					import { useRequest } from '../api-client';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function AntdConfigProvider(props) {
 | 
					export function AntdConfigProvider(props) {
 | 
				
			||||||
@ -19,7 +19,7 @@ export function AntdConfigProvider(props) {
 | 
				
			|||||||
          i18n.changeLanguage(data?.data?.lang);
 | 
					          i18n.changeLanguage(data?.data?.lang);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      manual: !remoteLocale,
 | 
					      manual: true, // !remoteLocale,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
  if (loading) {
 | 
					  if (loading) {
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@ import { Result } from 'ahooks/lib/useRequest/src/types';
 | 
				
			|||||||
import React, { createContext, useContext } from 'react';
 | 
					import React, { createContext, useContext } from 'react';
 | 
				
			||||||
import { useRequest } from '../api-client';
 | 
					import { useRequest } from '../api-client';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const AsyncDataContext = createContext<Result<any, any>>(null);
 | 
					export const AsyncDataContext = createContext<Result<any, any> & { state?: any; setState?: any }>(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface AsyncDataProviderProps {
 | 
					export interface AsyncDataProviderProps {
 | 
				
			||||||
  value?: any;
 | 
					  value?: any;
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,138 @@
 | 
				
			|||||||
 | 
					import { PlusOutlined } from '@ant-design/icons';
 | 
				
			||||||
 | 
					import { ArrayTable } from '@formily/antd';
 | 
				
			||||||
 | 
					import { ISchema } from '@formily/react';
 | 
				
			||||||
 | 
					import { uid } from '@formily/shared';
 | 
				
			||||||
 | 
					import { Button, Dropdown, Menu } from 'antd';
 | 
				
			||||||
 | 
					import { cloneDeep } from 'lodash';
 | 
				
			||||||
 | 
					import React, { useState } from 'react';
 | 
				
			||||||
 | 
					import { useRequest } from '../../api-client';
 | 
				
			||||||
 | 
					import { ActionContext, SchemaComponent, useActionContext, useCompile, useFormBlockContext } from '../../schema-component';
 | 
				
			||||||
 | 
					import { useCollectionManager } from '../hooks';
 | 
				
			||||||
 | 
					import { IField } from '../interfaces/types';
 | 
				
			||||||
 | 
					import { options } from './interfaces';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getSchema = (schema: IField): ISchema => {
 | 
				
			||||||
 | 
					  if (!schema) {
 | 
				
			||||||
 | 
					    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 {
 | 
				
			||||||
 | 
					    type: 'object',
 | 
				
			||||||
 | 
					    properties: {
 | 
				
			||||||
 | 
					      [uid()]: {
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        'x-component': 'Action.Drawer',
 | 
				
			||||||
 | 
					        'x-decorator': 'Form',
 | 
				
			||||||
 | 
					        'x-decorator-props': {
 | 
				
			||||||
 | 
					          useValues(options) {
 | 
				
			||||||
 | 
					            return useRequest(
 | 
				
			||||||
 | 
					              () =>
 | 
				
			||||||
 | 
					                Promise.resolve({
 | 
				
			||||||
 | 
					                  data: initialValue,
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					              options,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        title: '{{ t("Add field") }}',
 | 
				
			||||||
 | 
					        properties: {
 | 
				
			||||||
 | 
					          // @ts-ignore
 | 
				
			||||||
 | 
					          ...properties,
 | 
				
			||||||
 | 
					          footer: {
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					            'x-component': 'Action.Drawer.Footer',
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              action1: {
 | 
				
			||||||
 | 
					                title: '{{ t("Cancel") }}',
 | 
				
			||||||
 | 
					                'x-component': 'Action',
 | 
				
			||||||
 | 
					                'x-component-props': {
 | 
				
			||||||
 | 
					                  useAction: '{{ cm.useCancelAction }}',
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              action2: {
 | 
				
			||||||
 | 
					                title: '{{ t("Submit") }}',
 | 
				
			||||||
 | 
					                'x-component': 'Action',
 | 
				
			||||||
 | 
					                'x-component-props': {
 | 
				
			||||||
 | 
					                  type: 'primary',
 | 
				
			||||||
 | 
					                  useAction: '{{ useCreateSubField }}',
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useCreateSubField = () => {
 | 
				
			||||||
 | 
					  // const form = useForm();
 | 
				
			||||||
 | 
					  const { form, parent } = useFormBlockContext();
 | 
				
			||||||
 | 
					  const ctx = useActionContext();
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    async run() {
 | 
				
			||||||
 | 
					      await form.submit();
 | 
				
			||||||
 | 
					      const children = parent.form.values?.children?.slice?.();
 | 
				
			||||||
 | 
					      children.push(cloneDeep(form.values));
 | 
				
			||||||
 | 
					      console.log('form.values', form.values, children);
 | 
				
			||||||
 | 
					      parent.form.setValuesIn('children', children);
 | 
				
			||||||
 | 
					      ctx.setVisible(false);
 | 
				
			||||||
 | 
					      // const options = form?.values?.uiSchema?.enum?.slice() || [];
 | 
				
			||||||
 | 
					      // form.setValuesIn(
 | 
				
			||||||
 | 
					      //   'uiSchema.enum',
 | 
				
			||||||
 | 
					      //   options.map((option) => {
 | 
				
			||||||
 | 
					      //     return {
 | 
				
			||||||
 | 
					      //       value: uid(),
 | 
				
			||||||
 | 
					      //       ...option,
 | 
				
			||||||
 | 
					      //     };
 | 
				
			||||||
 | 
					      //   }),
 | 
				
			||||||
 | 
					      // );
 | 
				
			||||||
 | 
					      // await run();
 | 
				
			||||||
 | 
					      // await refreshCM();
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const AddSubFieldAction = () => {
 | 
				
			||||||
 | 
					  const { getInterface } = useCollectionManager();
 | 
				
			||||||
 | 
					  const [visible, setVisible] = useState(false);
 | 
				
			||||||
 | 
					  const [schema, setSchema] = useState({});
 | 
				
			||||||
 | 
					  const compile = useCompile();
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <ActionContext.Provider value={{ visible, setVisible }}>
 | 
				
			||||||
 | 
					      <Dropdown
 | 
				
			||||||
 | 
					        overlay={
 | 
				
			||||||
 | 
					          <Menu
 | 
				
			||||||
 | 
					            onClick={(info) => {
 | 
				
			||||||
 | 
					              const schema = getSchema(getInterface(info.key));
 | 
				
			||||||
 | 
					              setSchema(schema);
 | 
				
			||||||
 | 
					              setVisible(true);
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            {options.map((option) => {
 | 
				
			||||||
 | 
					              return (
 | 
				
			||||||
 | 
					                <Menu.SubMenu title={compile(option.label)}>
 | 
				
			||||||
 | 
					                  {option.children.map((child) => {
 | 
				
			||||||
 | 
					                    return <Menu.Item key={child.name}>{compile(child.title)}</Menu.Item>;
 | 
				
			||||||
 | 
					                  })}
 | 
				
			||||||
 | 
					                </Menu.SubMenu>
 | 
				
			||||||
 | 
					              );
 | 
				
			||||||
 | 
					            })}
 | 
				
			||||||
 | 
					          </Menu>
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <Button icon={<PlusOutlined />} type={'primary'}>
 | 
				
			||||||
 | 
					          添加字段
 | 
				
			||||||
 | 
					        </Button>
 | 
				
			||||||
 | 
					      </Dropdown>
 | 
				
			||||||
 | 
					      <SchemaComponent schema={schema} components={{ ArrayTable }} scope={{ useCreateSubField }} />
 | 
				
			||||||
 | 
					    </ActionContext.Provider>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -1,9 +1,13 @@
 | 
				
			|||||||
 | 
					import { useForm } from '@formily/react';
 | 
				
			||||||
import { action } from '@formily/reactive';
 | 
					import { action } from '@formily/reactive';
 | 
				
			||||||
import { uid } from '@formily/shared';
 | 
					import { uid } from '@formily/shared';
 | 
				
			||||||
import React, { useEffect } from 'react';
 | 
					import React, { useEffect, useState } from 'react';
 | 
				
			||||||
import { useRequest } from '../../api-client';
 | 
					import { useRequest } from '../../api-client';
 | 
				
			||||||
 | 
					import { useRecord } from '../../record-provider';
 | 
				
			||||||
import { SchemaComponent, useActionContext } from '../../schema-component';
 | 
					import { SchemaComponent, useActionContext } from '../../schema-component';
 | 
				
			||||||
import { useCollectionManager } from '../hooks/useCollectionManager';
 | 
					import { useCollectionManager } from '../hooks/useCollectionManager';
 | 
				
			||||||
 | 
					import { AddSubFieldAction } from './AddSubFieldAction';
 | 
				
			||||||
 | 
					import { EditSubFieldAction } from './EditSubFieldAction';
 | 
				
			||||||
import { collectionSchema } from './schemas/collections';
 | 
					import { collectionSchema } from './schemas/collections';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const useAsyncDataSource = (service: any) => (field: any) => {
 | 
					const useAsyncDataSource = (service: any) => (field: any) => {
 | 
				
			||||||
@ -42,6 +46,33 @@ const useCollectionValues = (options) => {
 | 
				
			|||||||
  return result;
 | 
					  return result;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useSelectedRowKeys = () => {
 | 
				
			||||||
 | 
					  const [selectedRowKeys, setSelectedRowKeys] = useState([]);
 | 
				
			||||||
 | 
					  return [selectedRowKeys, setSelectedRowKeys];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useDestroySubField = () => {
 | 
				
			||||||
 | 
					  const record = useRecord();
 | 
				
			||||||
 | 
					  const form = useForm();
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    async run() {
 | 
				
			||||||
 | 
					      const children = form.values?.children?.slice?.();
 | 
				
			||||||
 | 
					      form.setValuesIn(
 | 
				
			||||||
 | 
					        'children',
 | 
				
			||||||
 | 
					        children.filter((child) => {
 | 
				
			||||||
 | 
					          return child.name !== record.name;
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useBulkDestroySubField = () => {
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    async run() {},
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const ConfigurationTable = () => {
 | 
					export const ConfigurationTable = () => {
 | 
				
			||||||
  const { collections = [] } = useCollectionManager();
 | 
					  const { collections = [] } = useCollectionManager();
 | 
				
			||||||
  const loadCollections = async (field: any) => {
 | 
					  const loadCollections = async (field: any) => {
 | 
				
			||||||
@ -52,7 +83,21 @@ export const ConfigurationTable = () => {
 | 
				
			|||||||
  };
 | 
					  };
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
      <SchemaComponent schema={collectionSchema} scope={{ useCollectionValues, useAsyncDataSource, loadCollections }} />
 | 
					      <SchemaComponent
 | 
				
			||||||
 | 
					        schema={collectionSchema}
 | 
				
			||||||
 | 
					        components={{
 | 
				
			||||||
 | 
					          AddSubFieldAction,
 | 
				
			||||||
 | 
					          EditSubFieldAction,
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					        scope={{
 | 
				
			||||||
 | 
					          useDestroySubField,
 | 
				
			||||||
 | 
					          useBulkDestroySubField,
 | 
				
			||||||
 | 
					          useSelectedRowKeys,
 | 
				
			||||||
 | 
					          useCollectionValues,
 | 
				
			||||||
 | 
					          useAsyncDataSource,
 | 
				
			||||||
 | 
					          loadCollections,
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -102,7 +102,7 @@ export const EditFieldAction = (props) => {
 | 
				
			|||||||
        onClick={async () => {
 | 
					        onClick={async () => {
 | 
				
			||||||
          const { data } = await api.resource('collections.fields', record.collectionName).get({
 | 
					          const { data } = await api.resource('collections.fields', record.collectionName).get({
 | 
				
			||||||
            filterByTk: record.name,
 | 
					            filterByTk: record.name,
 | 
				
			||||||
            appends: ['uiSchema'],
 | 
					            appends: record.interface === 'subTable' ? ['uiSchema', 'children'] : ['uiSchema'],
 | 
				
			||||||
          });
 | 
					          });
 | 
				
			||||||
          const schema = getSchema({
 | 
					          const schema = getSchema({
 | 
				
			||||||
            ...getInterface(record.interface),
 | 
					            ...getInterface(record.interface),
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,119 @@
 | 
				
			|||||||
 | 
					import { ArrayTable } from '@formily/antd';
 | 
				
			||||||
 | 
					import { ISchema } from '@formily/react';
 | 
				
			||||||
 | 
					import { uid } from '@formily/shared';
 | 
				
			||||||
 | 
					import cloneDeep from 'lodash/cloneDeep';
 | 
				
			||||||
 | 
					import React, { useState } from 'react';
 | 
				
			||||||
 | 
					import { useTranslation } from 'react-i18next';
 | 
				
			||||||
 | 
					import { useAPIClient, useRequest } from '../../api-client';
 | 
				
			||||||
 | 
					import { useRecord } from '../../record-provider';
 | 
				
			||||||
 | 
					import { ActionContext, SchemaComponent, useActionContext, useFormBlockContext } from '../../schema-component';
 | 
				
			||||||
 | 
					import { useCollectionManager } from '../hooks';
 | 
				
			||||||
 | 
					import { IField } from '../interfaces/types';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const getSchema = (schema: IField): ISchema => {
 | 
				
			||||||
 | 
					  if (!schema) {
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const properties = cloneDeep(schema.properties) as any;
 | 
				
			||||||
 | 
					  properties.name['x-disabled'] = true;
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    type: 'object',
 | 
				
			||||||
 | 
					    properties: {
 | 
				
			||||||
 | 
					      [uid()]: {
 | 
				
			||||||
 | 
					        type: 'void',
 | 
				
			||||||
 | 
					        'x-component': 'Action.Drawer',
 | 
				
			||||||
 | 
					        'x-decorator': 'Form',
 | 
				
			||||||
 | 
					        'x-decorator-props': {
 | 
				
			||||||
 | 
					          useValues(options) {
 | 
				
			||||||
 | 
					            return useRequest(
 | 
				
			||||||
 | 
					              () =>
 | 
				
			||||||
 | 
					                Promise.resolve({
 | 
				
			||||||
 | 
					                  data: cloneDeep(schema.default),
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					              options,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        title: '{{ t("Edit field") }}',
 | 
				
			||||||
 | 
					        properties: {
 | 
				
			||||||
 | 
					          // @ts-ignore
 | 
				
			||||||
 | 
					          ...properties,
 | 
				
			||||||
 | 
					          footer: {
 | 
				
			||||||
 | 
					            type: 'void',
 | 
				
			||||||
 | 
					            'x-component': 'Action.Drawer.Footer',
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              action1: {
 | 
				
			||||||
 | 
					                title: '{{ t("Cancel") }}',
 | 
				
			||||||
 | 
					                'x-component': 'Action',
 | 
				
			||||||
 | 
					                'x-component-props': {
 | 
				
			||||||
 | 
					                  useAction: '{{ cm.useCancelAction }}',
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              action2: {
 | 
				
			||||||
 | 
					                title: '{{ t("Submit") }}',
 | 
				
			||||||
 | 
					                'x-component': 'Action',
 | 
				
			||||||
 | 
					                'x-component-props': {
 | 
				
			||||||
 | 
					                  type: 'primary',
 | 
				
			||||||
 | 
					                  useAction: '{{ useUpdateSubField }}',
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useUpdateSubField = () => {
 | 
				
			||||||
 | 
					  const { form, parent } = useFormBlockContext();
 | 
				
			||||||
 | 
					  const ctx = useActionContext();
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    async run() {
 | 
				
			||||||
 | 
					      await form.submit();
 | 
				
			||||||
 | 
					      const children = parent.form.values?.children?.slice?.();
 | 
				
			||||||
 | 
					      parent.form.setValuesIn(
 | 
				
			||||||
 | 
					        'children',
 | 
				
			||||||
 | 
					        children.map((child) => {
 | 
				
			||||||
 | 
					          if (child.name === form.values.name) {
 | 
				
			||||||
 | 
					            return cloneDeep(form.values);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          return child;
 | 
				
			||||||
 | 
					        }),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      ctx.setVisible(false);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const EditSubFieldAction = (props) => {
 | 
				
			||||||
 | 
					  const record = useRecord();
 | 
				
			||||||
 | 
					  const { getInterface } = useCollectionManager();
 | 
				
			||||||
 | 
					  const [visible, setVisible] = useState(false);
 | 
				
			||||||
 | 
					  const [schema, setSchema] = useState({});
 | 
				
			||||||
 | 
					  const api = useAPIClient();
 | 
				
			||||||
 | 
					  const { t } = useTranslation();
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <ActionContext.Provider value={{ visible, setVisible }}>
 | 
				
			||||||
 | 
					      <a
 | 
				
			||||||
 | 
					        onClick={async () => {
 | 
				
			||||||
 | 
					          // const { data } = await api.resource('fields.children', record.key).get({
 | 
				
			||||||
 | 
					          //   filterByTk: record.name,
 | 
				
			||||||
 | 
					          //   appends: ['uiSchema'],
 | 
				
			||||||
 | 
					          // });
 | 
				
			||||||
 | 
					          const schema = getSchema({
 | 
				
			||||||
 | 
					            ...getInterface(record.interface),
 | 
				
			||||||
 | 
					            default: {
 | 
				
			||||||
 | 
					              ...record,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          setSchema(schema);
 | 
				
			||||||
 | 
					          setVisible(true);
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        {t('Edit')}
 | 
				
			||||||
 | 
					      </a>
 | 
				
			||||||
 | 
					      <SchemaComponent schema={schema} components={{ ArrayTable }} scope={{ useUpdateSubField }} />
 | 
				
			||||||
 | 
					    </ActionContext.Provider>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -31,6 +31,132 @@ export const subTable: IField = {
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  properties: {
 | 
					  properties: {
 | 
				
			||||||
    ...defaultProps,
 | 
					    ...defaultProps,
 | 
				
			||||||
 | 
					    subtable: {
 | 
				
			||||||
 | 
					      type: 'void',
 | 
				
			||||||
 | 
					      'x-component': 'div',
 | 
				
			||||||
 | 
					      properties: {
 | 
				
			||||||
 | 
					        actions: {
 | 
				
			||||||
 | 
					          type: 'void',
 | 
				
			||||||
 | 
					          'x-component': 'ActionBar',
 | 
				
			||||||
 | 
					          'x-component-props': {
 | 
				
			||||||
 | 
					            style: {
 | 
				
			||||||
 | 
					              marginBottom: 16,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          properties: {
 | 
				
			||||||
 | 
					            delete: {
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              title: '{{ t("Delete") }}',
 | 
				
			||||||
 | 
					              'x-component': 'Action',
 | 
				
			||||||
 | 
					              'x-component-props': {
 | 
				
			||||||
 | 
					                useAction: '{{ useBulkDestroySubField }}',
 | 
				
			||||||
 | 
					                confirm: {
 | 
				
			||||||
 | 
					                  title: "{{t('Delete record')}}",
 | 
				
			||||||
 | 
					                  content: "{{t('Are you sure you want to delete it?')}}",
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            create: {
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              title: '{{ t("Add new") }}',
 | 
				
			||||||
 | 
					              'x-component': 'AddSubFieldAction',
 | 
				
			||||||
 | 
					              'x-component-props': {
 | 
				
			||||||
 | 
					                type: 'primary',
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        children: {
 | 
				
			||||||
 | 
					          type: 'array',
 | 
				
			||||||
 | 
					          title: '{{t("Fields")}}',
 | 
				
			||||||
 | 
					          'x-decorator': 'FormItem',
 | 
				
			||||||
 | 
					          'x-component': 'Table.Array',
 | 
				
			||||||
 | 
					          'x-component-props': {
 | 
				
			||||||
 | 
					            pagination: false,
 | 
				
			||||||
 | 
					            rowKey: 'name',
 | 
				
			||||||
 | 
					            rowSelection: {
 | 
				
			||||||
 | 
					              type: 'checkbox',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            useSelectedRowKeys: '{{ useSelectedRowKeys }}',
 | 
				
			||||||
 | 
					            // scroll: { x: '100%' },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          properties: {
 | 
				
			||||||
 | 
					            column1: {
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              title: '{{ t("Field display name") }}',
 | 
				
			||||||
 | 
					              'x-component': 'Table.Column',
 | 
				
			||||||
 | 
					              properties: {
 | 
				
			||||||
 | 
					                'uiSchema.title': {
 | 
				
			||||||
 | 
					                  type: 'number',
 | 
				
			||||||
 | 
					                  'x-component': 'Input',
 | 
				
			||||||
 | 
					                  'x-read-pretty': true,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            column2: {
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              title: '{{ t("Field name") }}',
 | 
				
			||||||
 | 
					              'x-decorator': 'Table.Column.Decorator',
 | 
				
			||||||
 | 
					              'x-component': 'Table.Column',
 | 
				
			||||||
 | 
					              properties: {
 | 
				
			||||||
 | 
					                name: {
 | 
				
			||||||
 | 
					                  'x-component': 'Input',
 | 
				
			||||||
 | 
					                  'x-read-pretty': true,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            column3: {
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              title: '{{ t("Field interface") }}',
 | 
				
			||||||
 | 
					              'x-decorator': 'Table.Column.Decorator',
 | 
				
			||||||
 | 
					              'x-component': 'Table.Column',
 | 
				
			||||||
 | 
					              properties: {
 | 
				
			||||||
 | 
					                interface: {
 | 
				
			||||||
 | 
					                  'x-component': 'Input',
 | 
				
			||||||
 | 
					                  'x-read-pretty': true,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            column4: {
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              title: '{{ t("Actions") }}',
 | 
				
			||||||
 | 
					              'x-component': 'Table.Column',
 | 
				
			||||||
 | 
					              properties: {
 | 
				
			||||||
 | 
					                actions: {
 | 
				
			||||||
 | 
					                  type: 'void',
 | 
				
			||||||
 | 
					                  'x-component': 'Space',
 | 
				
			||||||
 | 
					                  'x-component-props': {
 | 
				
			||||||
 | 
					                    split: '|',
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                  properties: {
 | 
				
			||||||
 | 
					                    update: {
 | 
				
			||||||
 | 
					                      type: 'void',
 | 
				
			||||||
 | 
					                      title: '{{ t("Edit") }}',
 | 
				
			||||||
 | 
					                      'x-component': 'EditSubFieldAction',
 | 
				
			||||||
 | 
					                      'x-component-props': {
 | 
				
			||||||
 | 
					                        type: 'primary',
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    delete: {
 | 
				
			||||||
 | 
					                      type: 'void',
 | 
				
			||||||
 | 
					                      title: '{{ t("Delete") }}',
 | 
				
			||||||
 | 
					                      'x-component': 'Action.Link',
 | 
				
			||||||
 | 
					                      'x-component-props': {
 | 
				
			||||||
 | 
					                        useAction: '{{ useDestroySubField }}',
 | 
				
			||||||
 | 
					                        confirm: {
 | 
				
			||||||
 | 
					                          title: "{{t('Delete record')}}",
 | 
				
			||||||
 | 
					                          content: "{{t('Are you sure you want to delete it?')}}",
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    // children: {
 | 
					    // children: {
 | 
				
			||||||
    //   type: 'array',
 | 
					    //   type: 'array',
 | 
				
			||||||
    //   title: '{{t("Sub-table fields")}}',
 | 
					    //   title: '{{t("Sub-table fields")}}',
 | 
				
			||||||
 | 
				
			|||||||
@ -104,6 +104,7 @@
 | 
				
			|||||||
  "Edit": "编辑",
 | 
					  "Edit": "编辑",
 | 
				
			||||||
  "Edit collection": "编辑数据表",
 | 
					  "Edit collection": "编辑数据表",
 | 
				
			||||||
  "Configure fields": "配置字段",
 | 
					  "Configure fields": "配置字段",
 | 
				
			||||||
 | 
					  "Configure columns": "配置字段",
 | 
				
			||||||
  "Edit field": "编辑字段",
 | 
					  "Edit field": "编辑字段",
 | 
				
			||||||
  "Configure fields of {{title}}": "「{{title}}」的字段配置",
 | 
					  "Configure fields of {{title}}": "「{{title}}」的字段配置",
 | 
				
			||||||
  "Basic": "基本类型",
 | 
					  "Basic": "基本类型",
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,7 @@ import { createForm } from '@formily/core';
 | 
				
			|||||||
import { FieldContext, FormContext, observer, RecursionField, useField, useFieldSchema } from '@formily/react';
 | 
					import { FieldContext, FormContext, observer, RecursionField, useField, useFieldSchema } from '@formily/react';
 | 
				
			||||||
import { Options, Result } from 'ahooks/lib/useRequest/src/types';
 | 
					import { Options, Result } from 'ahooks/lib/useRequest/src/types';
 | 
				
			||||||
import { Spin } from 'antd';
 | 
					import { Spin } from 'antd';
 | 
				
			||||||
import React, { useMemo } from 'react';
 | 
					import React, { createContext, useContext, useMemo } from 'react';
 | 
				
			||||||
import { useAttach, useComponent } from '../..';
 | 
					import { useAttach, useComponent } from '../..';
 | 
				
			||||||
import { useRequest } from '../../../api-client';
 | 
					import { useRequest } from '../../../api-client';
 | 
				
			||||||
import { useCollection } from '../../../collection-manager';
 | 
					import { useCollection } from '../../../collection-manager';
 | 
				
			||||||
@ -75,9 +75,17 @@ const useDef = (opts: any = {}, props: FormProps = {}) => {
 | 
				
			|||||||
  return useRequest(useRequestProps(props), opts);
 | 
					  return useRequest(useRequestProps(props), opts);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const FormBlockContext = createContext<any>(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useFormBlockContext = () => {
 | 
				
			||||||
 | 
					  const ctx = useContext(FormBlockContext);
 | 
				
			||||||
 | 
					  return ctx;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Form: React.FC<FormProps> & { Designer?: any } = observer((props) => {
 | 
					export const Form: React.FC<FormProps> & { Designer?: any } = observer((props) => {
 | 
				
			||||||
  const { request, effects, initialValue, useValues = useDef, ...others } = props;
 | 
					  const { request, effects, initialValue, useValues = useDef, ...others } = props;
 | 
				
			||||||
  const fieldSchema = useFieldSchema();
 | 
					  const fieldSchema = useFieldSchema();
 | 
				
			||||||
 | 
					  const field = useField();
 | 
				
			||||||
  const form = useMemo(() => createForm({ effects }), []);
 | 
					  const form = useMemo(() => createForm({ effects }), []);
 | 
				
			||||||
  const result = useValues(
 | 
					  const result = useValues(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -89,7 +97,9 @@ export const Form: React.FC<FormProps> & { Designer?: any } = observer((props) =
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    props,
 | 
					    props,
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					  const parent = useContext(FormBlockContext);
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
 | 
					    <FormBlockContext.Provider value={{ parent, form, result, field, fieldSchema }}>
 | 
				
			||||||
      <Spin spinning={result?.loading || false}>
 | 
					      <Spin spinning={result?.loading || false}>
 | 
				
			||||||
        {fieldSchema['x-decorator'] === 'Form' ? (
 | 
					        {fieldSchema['x-decorator'] === 'Form' ? (
 | 
				
			||||||
          <FormDecorator form={form} {...others} />
 | 
					          <FormDecorator form={form} {...others} />
 | 
				
			||||||
@ -97,6 +107,7 @@ export const Form: React.FC<FormProps> & { Designer?: any } = observer((props) =
 | 
				
			|||||||
          <FormComponent form={form} {...others} />
 | 
					          <FormComponent form={form} {...others} />
 | 
				
			||||||
        )}
 | 
					        )}
 | 
				
			||||||
      </Spin>
 | 
					      </Spin>
 | 
				
			||||||
 | 
					    </FormBlockContext.Provider>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,11 @@
 | 
				
			|||||||
import { css } from '@emotion/css';
 | 
					import { css } from '@emotion/css';
 | 
				
			||||||
import { ArrayField } from '@formily/core';
 | 
					import { ArrayField, Field } from '@formily/core';
 | 
				
			||||||
import { observer, RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
 | 
					import { observer, RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
 | 
				
			||||||
import { Table, TableColumnProps } from 'antd';
 | 
					import { Table, TableColumnProps } from 'antd';
 | 
				
			||||||
import cls from 'classnames';
 | 
					import cls from 'classnames';
 | 
				
			||||||
import React from 'react';
 | 
					import React, { useState } from 'react';
 | 
				
			||||||
import { DndContext } from '../..';
 | 
					import { DndContext } from '../..';
 | 
				
			||||||
import { RecordProvider, useSchemaInitializer } from '../../../';
 | 
					import { RecordProvider, useRequest, useSchemaInitializer } from '../../../';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const isColumnComponent = (schema: Schema) => {
 | 
					const isColumnComponent = (schema: Schema) => {
 | 
				
			||||||
  return schema['x-component']?.endsWith('.Column') > -1;
 | 
					  return schema['x-component']?.endsWith('.Column') > -1;
 | 
				
			||||||
@ -83,13 +83,45 @@ export const components = {
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useDef = () => {
 | 
				
			||||||
 | 
					  const [selectedRowKeys, setSelectedRowKeys] = useState([]);
 | 
				
			||||||
 | 
					  return [selectedRowKeys, setSelectedRowKeys];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useDefDataSource = (options, props) => {
 | 
				
			||||||
 | 
					  const field = useField<Field>();
 | 
				
			||||||
 | 
					  return useRequest(() => {
 | 
				
			||||||
 | 
					    return Promise.resolve({
 | 
				
			||||||
 | 
					      data: field.value,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }, options);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const TableArray: React.FC<any> = observer((props) => {
 | 
					export const TableArray: React.FC<any> = observer((props) => {
 | 
				
			||||||
  const field = useField<ArrayField>();
 | 
					  const field = useField<ArrayField>();
 | 
				
			||||||
  const columns = useTableColumns();
 | 
					  const columns = useTableColumns();
 | 
				
			||||||
  const { onChange, ...others } = props;
 | 
					  const { useSelectedRowKeys = useDef, useDataSource = useDefDataSource, onChange, ...others } = props;
 | 
				
			||||||
 | 
					  const [selectedRowKeys, setSelectedRowKeys] = useSelectedRowKeys();
 | 
				
			||||||
 | 
					  useDataSource({
 | 
				
			||||||
 | 
					    onSuccess(data) {
 | 
				
			||||||
 | 
					      field.value = data?.data || [];
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  const restProps = {
 | 
				
			||||||
 | 
					    rowSelection: props.rowSelection
 | 
				
			||||||
 | 
					      ? {
 | 
				
			||||||
 | 
					          type: 'checkbox',
 | 
				
			||||||
 | 
					          selectedRowKeys,
 | 
				
			||||||
 | 
					          onChange(selectedRowKeys: any[]) {
 | 
				
			||||||
 | 
					            setSelectedRowKeys(selectedRowKeys);
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          ...props.rowSelection,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      : undefined,
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
      <Table {...others} components={components} columns={columns} dataSource={field.value?.slice()} />
 | 
					      <Table {...others} {...restProps} components={components} columns={columns} dataSource={field.value?.slice()} />
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,11 @@
 | 
				
			|||||||
import { useField, useFieldSchema } from '@formily/react';
 | 
					import { useField, useFieldSchema } from '@formily/react';
 | 
				
			||||||
import React, { useLayoutEffect } from 'react';
 | 
					import React, { useLayoutEffect } from 'react';
 | 
				
			||||||
import { designerCss, SortableItem, useCollection, useDesignable, useDesigner } from '../../../';
 | 
					import { SortableItem, useCollection, useCompile, useDesignable, useDesigner } from '../../../';
 | 
				
			||||||
 | 
					import { designerCss } from './Table.Column.ActionBar';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useColumnSchema = () => {
 | 
					export const useColumnSchema = () => {
 | 
				
			||||||
  const { getField } = useCollection();
 | 
					  const { getField } = useCollection();
 | 
				
			||||||
 | 
					  const compile = useCompile();
 | 
				
			||||||
  const columnSchema = useFieldSchema();
 | 
					  const columnSchema = useFieldSchema();
 | 
				
			||||||
  const fieldSchema = columnSchema.reduceProperties((buf, s) => {
 | 
					  const fieldSchema = columnSchema.reduceProperties((buf, s) => {
 | 
				
			||||||
    if (s['x-component'] === 'CollectionField') {
 | 
					    if (s['x-component'] === 'CollectionField') {
 | 
				
			||||||
@ -15,14 +17,15 @@ export const useColumnSchema = () => {
 | 
				
			|||||||
    return {};
 | 
					    return {};
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  const collectionField = getField(fieldSchema.name);
 | 
					  const collectionField = getField(fieldSchema.name);
 | 
				
			||||||
  return { columnSchema, fieldSchema, collectionField };
 | 
					  return { columnSchema, fieldSchema, uiSchema: compile(collectionField?.uiSchema) };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const TableColumnDecorator = (props) => {
 | 
					export const TableColumnDecorator = (props) => {
 | 
				
			||||||
  const Designer = useDesigner();
 | 
					  const Designer = useDesigner();
 | 
				
			||||||
  const field = useField();
 | 
					  const field = useField();
 | 
				
			||||||
  const { fieldSchema, collectionField } = useColumnSchema();
 | 
					  const { fieldSchema, uiSchema } = useColumnSchema();
 | 
				
			||||||
  const { refresh } = useDesignable();
 | 
					  const { refresh } = useDesignable();
 | 
				
			||||||
 | 
					  const compile = useCompile();
 | 
				
			||||||
  useLayoutEffect(() => {
 | 
					  useLayoutEffect(() => {
 | 
				
			||||||
    if (field.title) {
 | 
					    if (field.title) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
@ -30,16 +33,16 @@ export const TableColumnDecorator = (props) => {
 | 
				
			|||||||
    if (!fieldSchema) {
 | 
					    if (!fieldSchema) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (collectionField?.uiSchema?.title) {
 | 
					    if (uiSchema?.title) {
 | 
				
			||||||
      field.title = collectionField?.uiSchema?.title;
 | 
					      field.title = uiSchema?.title;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }, [collectionField?.uiSchema?.title]);
 | 
					  }, [uiSchema?.title]);
 | 
				
			||||||
  console.log('field.title', collectionField?.uiSchema?.title, field.title);
 | 
					  console.log('field.title', uiSchema?.title, field.title);
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <SortableItem className={designerCss}>
 | 
					    <SortableItem className={designerCss}>
 | 
				
			||||||
      <Designer />
 | 
					      <Designer />
 | 
				
			||||||
      {/* <RecursionField name={columnSchema.name} schema={columnSchema}/> */}
 | 
					      {/* <RecursionField name={columnSchema.name} schema={columnSchema}/> */}
 | 
				
			||||||
      {field.title || collectionField?.uiSchema?.title}
 | 
					      {field.title || compile(uiSchema?.title)}
 | 
				
			||||||
      {/* <div
 | 
					      {/* <div
 | 
				
			||||||
        onClick={() => {
 | 
					        onClick={() => {
 | 
				
			||||||
          field.title = uid();
 | 
					          field.title = uid();
 | 
				
			||||||
 | 
				
			|||||||
@ -4,12 +4,13 @@ import { Options, Result } from 'ahooks/lib/useRequest/src/types';
 | 
				
			|||||||
import { TablePaginationConfig, TableProps } from 'antd';
 | 
					import { TablePaginationConfig, TableProps } from 'antd';
 | 
				
			||||||
import { cloneDeep } from 'lodash';
 | 
					import { cloneDeep } from 'lodash';
 | 
				
			||||||
import React, { useMemo } from 'react';
 | 
					import React, { useMemo } from 'react';
 | 
				
			||||||
import { AsyncDataProvider, useRequest } from '../../../';
 | 
					import { AsyncDataProvider, useAsyncData, useRequest } from '../../../';
 | 
				
			||||||
import { useAttach } from '../../hooks';
 | 
					import { useAttach } from '../../hooks';
 | 
				
			||||||
import { TableArray } from './Table.Array';
 | 
					import { TableArray } from './Table.Array';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type TableVoidProps = TableProps<any> & {
 | 
					type TableVoidProps = TableProps<any> & {
 | 
				
			||||||
  request?: any;
 | 
					  request?: any;
 | 
				
			||||||
 | 
					  useSelectedRowKeys?: any;
 | 
				
			||||||
  useDataSource?: (
 | 
					  useDataSource?: (
 | 
				
			||||||
    options?: Options<any, any> & { uid?: string },
 | 
					    options?: Options<any, any> & { uid?: string },
 | 
				
			||||||
    props?: any,
 | 
					    props?: any,
 | 
				
			||||||
@ -69,8 +70,13 @@ const useDef = (options, props) => {
 | 
				
			|||||||
  return useRequest(useRequestProps(props), options);
 | 
					  return useRequest(useRequestProps(props), options);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const useDefSelectedRowKeys = () => {
 | 
				
			||||||
 | 
					  const result = useAsyncData();
 | 
				
			||||||
 | 
					  return [result?.state?.selectedRowKeys, (selectedRowKeys) => result?.setState?.({ selectedRowKeys })];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const TableVoid: React.FC<TableVoidProps> = observer((props) => {
 | 
					export const TableVoid: React.FC<TableVoidProps> = observer((props) => {
 | 
				
			||||||
  const { useDataSource = useDef } = props;
 | 
					  const { useDataSource = useDef, useSelectedRowKeys = useDefSelectedRowKeys } = props;
 | 
				
			||||||
  const field = useField<Field>();
 | 
					  const field = useField<Field>();
 | 
				
			||||||
  const fieldSchema = useFieldSchema();
 | 
					  const fieldSchema = useFieldSchema();
 | 
				
			||||||
  const form = useMemo(() => createForm(), []);
 | 
					  const form = useMemo(() => createForm(), []);
 | 
				
			||||||
@ -96,23 +102,16 @@ export const TableVoid: React.FC<TableVoidProps> = observer((props) => {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    props,
 | 
					    props,
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
  const others = {
 | 
					 | 
				
			||||||
    rowSelection: props.rowSelection
 | 
					 | 
				
			||||||
      ? {
 | 
					 | 
				
			||||||
          type: 'checkbox',
 | 
					 | 
				
			||||||
          ...props.rowSelection,
 | 
					 | 
				
			||||||
          selectedRowKeys: result?.state?.selectedRowKeys || [],
 | 
					 | 
				
			||||||
          onChange(selectedRowKeys: any[]) {
 | 
					 | 
				
			||||||
            result?.setState?.({ selectedRowKeys });
 | 
					 | 
				
			||||||
          },
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      : undefined,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <AsyncDataProvider value={result}>
 | 
					    <AsyncDataProvider value={result}>
 | 
				
			||||||
      <FormContext.Provider value={form}>
 | 
					      <FormContext.Provider value={form}>
 | 
				
			||||||
        <FieldContext.Provider value={f}>
 | 
					        <FieldContext.Provider value={f}>
 | 
				
			||||||
          <TableArray {...props} {...others} loading={result?.loading} pagination={usePaginationProps(props, result)} />
 | 
					          <TableArray
 | 
				
			||||||
 | 
					            {...props}
 | 
				
			||||||
 | 
					            useSelectedRowKeys={useSelectedRowKeys}
 | 
				
			||||||
 | 
					            loading={result?.loading}
 | 
				
			||||||
 | 
					            pagination={usePaginationProps(props, result)}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
        </FieldContext.Provider>
 | 
					        </FieldContext.Provider>
 | 
				
			||||||
      </FormContext.Provider>
 | 
					      </FormContext.Provider>
 | 
				
			||||||
    </AsyncDataProvider>
 | 
					    </AsyncDataProvider>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										181
									
								
								packages/client/src/schema-component/antd/table/demos/demo4.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								packages/client/src/schema-component/antd/table/demos/demo4.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,181 @@
 | 
				
			|||||||
 | 
					import { ISchema, observer } from '@formily/react';
 | 
				
			||||||
 | 
					import { uid } from '@formily/shared';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Action,
 | 
				
			||||||
 | 
					  Input,
 | 
				
			||||||
 | 
					  SchemaComponent,
 | 
				
			||||||
 | 
					  SchemaComponentProvider,
 | 
				
			||||||
 | 
					  Table,
 | 
				
			||||||
 | 
					  useRecord,
 | 
				
			||||||
 | 
					  useRequest
 | 
				
			||||||
 | 
					} from '@nocobase/client';
 | 
				
			||||||
 | 
					import React, { createContext, useContext, useState } from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const DataSourceContext = createContext(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const schema: ISchema = {
 | 
				
			||||||
 | 
					  type: 'object',
 | 
				
			||||||
 | 
					  properties: {
 | 
				
			||||||
 | 
					    context: {
 | 
				
			||||||
 | 
					      type: 'void',
 | 
				
			||||||
 | 
					      'x-component': 'Context',
 | 
				
			||||||
 | 
					      properties: {
 | 
				
			||||||
 | 
					        action1: {
 | 
				
			||||||
 | 
					          title: '提交',
 | 
				
			||||||
 | 
					          'x-component': 'Action',
 | 
				
			||||||
 | 
					          'x-component-props': {
 | 
				
			||||||
 | 
					            useAction() {
 | 
				
			||||||
 | 
					              const ctx = useContext(DataSourceContext);
 | 
				
			||||||
 | 
					              return {
 | 
				
			||||||
 | 
					                async run() {
 | 
				
			||||||
 | 
					                  console.log(ctx.dataSource);
 | 
				
			||||||
 | 
					                  const dataSource = ctx.dataSource || [];
 | 
				
			||||||
 | 
					                  dataSource.push({
 | 
				
			||||||
 | 
					                    id: uid(),
 | 
				
			||||||
 | 
					                    name: uid(),
 | 
				
			||||||
 | 
					                  });
 | 
				
			||||||
 | 
					                  ctx.setDataSource([...dataSource]);
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        action2: {
 | 
				
			||||||
 | 
					          title: '删除',
 | 
				
			||||||
 | 
					          'x-component': 'Action',
 | 
				
			||||||
 | 
					          'x-component-props': {
 | 
				
			||||||
 | 
					            useAction() {
 | 
				
			||||||
 | 
					              const ctx = useContext(DataSourceContext);
 | 
				
			||||||
 | 
					              const { selectedRowKeys, setSelectedRowKeys } = ctx;
 | 
				
			||||||
 | 
					              return {
 | 
				
			||||||
 | 
					                async run() {
 | 
				
			||||||
 | 
					                  const dataSource = ctx.dataSource || [];
 | 
				
			||||||
 | 
					                  ctx.setDataSource(
 | 
				
			||||||
 | 
					                    dataSource.filter((item) => {
 | 
				
			||||||
 | 
					                      return !selectedRowKeys.includes(item.id);
 | 
				
			||||||
 | 
					                    }),
 | 
				
			||||||
 | 
					                  );
 | 
				
			||||||
 | 
					                  setSelectedRowKeys([]);
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              };
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        input: {
 | 
				
			||||||
 | 
					          type: 'array',
 | 
				
			||||||
 | 
					          title: `编辑模式`,
 | 
				
			||||||
 | 
					          'x-component': 'Table.Array',
 | 
				
			||||||
 | 
					          'x-component-props': {
 | 
				
			||||||
 | 
					            rowKey: 'id',
 | 
				
			||||||
 | 
					            rowSelection: {
 | 
				
			||||||
 | 
					              type: 'checkbox',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            useSelectedRowKeys() {
 | 
				
			||||||
 | 
					              const ctx = useContext(DataSourceContext);
 | 
				
			||||||
 | 
					              return [ctx.selectedRowKeys, ctx.setSelectedRowKeys];
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            useDataSource(options) {
 | 
				
			||||||
 | 
					              const ctx = useContext(DataSourceContext);
 | 
				
			||||||
 | 
					              return useRequest(
 | 
				
			||||||
 | 
					                () => {
 | 
				
			||||||
 | 
					                  console.log('ctx.dataSource', ctx.dataSource);
 | 
				
			||||||
 | 
					                  return Promise.resolve({
 | 
				
			||||||
 | 
					                    data: ctx.dataSource,
 | 
				
			||||||
 | 
					                  });
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  ...options,
 | 
				
			||||||
 | 
					                  refreshDeps: [JSON.stringify(ctx.dataSource)],
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              );
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          properties: {
 | 
				
			||||||
 | 
					            column1: {
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              title: 'Name',
 | 
				
			||||||
 | 
					              'x-component': 'Table.Column',
 | 
				
			||||||
 | 
					              properties: {
 | 
				
			||||||
 | 
					                name: {
 | 
				
			||||||
 | 
					                  type: 'string',
 | 
				
			||||||
 | 
					                  'x-component': 'Input',
 | 
				
			||||||
 | 
					                  'x-read-pretty': true,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            column2: {
 | 
				
			||||||
 | 
					              type: 'void',
 | 
				
			||||||
 | 
					              title: 'Actions',
 | 
				
			||||||
 | 
					              'x-component': 'Table.Column',
 | 
				
			||||||
 | 
					              properties: {
 | 
				
			||||||
 | 
					                action: {
 | 
				
			||||||
 | 
					                  title: '删除',
 | 
				
			||||||
 | 
					                  'x-component': 'Action',
 | 
				
			||||||
 | 
					                  'x-component-props': {
 | 
				
			||||||
 | 
					                    useAction() {
 | 
				
			||||||
 | 
					                      const record = useRecord();
 | 
				
			||||||
 | 
					                      const ctx = useContext(DataSourceContext);
 | 
				
			||||||
 | 
					                      return {
 | 
				
			||||||
 | 
					                        async run() {
 | 
				
			||||||
 | 
					                          const dataSource = ctx.dataSource || [];
 | 
				
			||||||
 | 
					                          ctx.setDataSource(
 | 
				
			||||||
 | 
					                            dataSource.filter((item) => {
 | 
				
			||||||
 | 
					                              return record.id !== item.id;
 | 
				
			||||||
 | 
					                            }),
 | 
				
			||||||
 | 
					                          );
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                      };
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Context = observer((props) => {
 | 
				
			||||||
 | 
					  const [selectedRowKeys, setSelectedRowKeys] = useState([]);
 | 
				
			||||||
 | 
					  const [dataSource, setDataSource] = useState([]);
 | 
				
			||||||
 | 
					  const service = useRequest(
 | 
				
			||||||
 | 
					    () => {
 | 
				
			||||||
 | 
					      return Promise.resolve({
 | 
				
			||||||
 | 
					        data: [
 | 
				
			||||||
 | 
					          { id: 1, name: 'Name1' },
 | 
				
			||||||
 | 
					          { id: 2, name: 'Name2' },
 | 
				
			||||||
 | 
					          { id: 3, name: 'Name3' },
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      onSuccess(data) {
 | 
				
			||||||
 | 
					        setDataSource(data.data);
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					  console.log('dataSource1', dataSource);
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <DataSourceContext.Provider
 | 
				
			||||||
 | 
					      value={{
 | 
				
			||||||
 | 
					        service,
 | 
				
			||||||
 | 
					        dataSource,
 | 
				
			||||||
 | 
					        setDataSource,
 | 
				
			||||||
 | 
					        selectedRowKeys,
 | 
				
			||||||
 | 
					        setSelectedRowKeys,
 | 
				
			||||||
 | 
					      }}
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      {props.children}
 | 
				
			||||||
 | 
					    </DataSourceContext.Provider>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default () => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <SchemaComponentProvider components={{ Action, Context, Table, Input }}>
 | 
				
			||||||
 | 
					      <SchemaComponent schema={schema} />
 | 
				
			||||||
 | 
					    </SchemaComponentProvider>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -25,3 +25,5 @@ group:
 | 
				
			|||||||
## Table.RowSelection
 | 
					## Table.RowSelection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<code src="./demos/demo3.tsx" />
 | 
					<code src="./demos/demo3.tsx" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<code src="./demos/demo4.tsx" />
 | 
				
			||||||
 | 
				
			|||||||
@ -12,8 +12,8 @@ export const TableColumnInitializers = (props: any) => {
 | 
				
			|||||||
      wrap={(s) => {
 | 
					      wrap={(s) => {
 | 
				
			||||||
        return {
 | 
					        return {
 | 
				
			||||||
          type: 'void',
 | 
					          type: 'void',
 | 
				
			||||||
          'x-decorator': 'TableColumnDecorator',
 | 
					          'x-decorator': 'Table.Column.Decorator',
 | 
				
			||||||
          'x-designer': 'TableColumnDeigner',
 | 
					          'x-designer': 'Table.Column.Deigner',
 | 
				
			||||||
          'x-component': 'Table.Column',
 | 
					          'x-component': 'Table.Column',
 | 
				
			||||||
          properties: {
 | 
					          properties: {
 | 
				
			||||||
            [s.name]: {
 | 
					            [s.name]: {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user