refactor(association-field): support sub table (#1862)
* fix: association select support data scope and sort setting * fix: appends on demand loading * fix: asociationSelect support multiple * fix: recordPicker -> AssociationField * fix: add migration * fix: audit logs not show assication data * fix: flattenNestedList * refactor: file manager field mode * refactor: field mode refactor * fix: subtable action * fix: subtable appends * refactor: code improve * fix: nester add new * feat: sub table * fix: data scope not effect immediately * fix: association add new * fix: association field failed to add new and mutual influence * style: style improve * style: style improve * refactor: updateAssociationValues * refactor: form init values * refactor: select options * fix: form initialValues * fix: record picker values * fix: field value change when field mode change * fix: select data scope * feat: add migration * fix: table column enable link * fix: table column enable link * refactor: locale improve * fix: migration * fix: mutiple config * fix: readPretty enable link * fix: appends on demand * fix: enable link style * refactor: locale improve * refactor: locale improve * feat: sub-form migration * fix: skip migration * fix: translation * fix: skip migration * fix: getLabelFormatValue * fix: error TS2339: Property 'find' does not exist on type 'string | SchemaEnum<any>' * refactor: remove the logic code for converting old record picker * refactor: locale * refactor: association field support sub-table * refactor: locale * fix: sub-table should not support add new * refactor: code improve * refactor: locale * fix: compatibility history Subtable * fix: getNesterAppends filter bug * refactor: useFieldModeOptions * refactor: subTable * fix: associationSelect * fix: associationSelect * fix: associationSelect * fix: getAssociationAppends * fix: sub-form collection context * refactor: code improve * refactor: code improve * refactor: code improve * refactor: code improve * refactor: code improve * fix: sub-table * fix: appends * fix: sub-table-appends * fix: undefine id * fix: sub-table appends * refactor: sub-table * refactor: sub-table supoort delete * fix: sub-table-appends * refactor: sub table initvvalue * fix: sub-table-appends * fix: association field appends * fix: association field appends * fix: association field appends * style: style improve * style: style improve * refactor: textArear Markdown RichText * style: style improve * fix: title field * refactor: code improve * fix: system fields are not allowed to be edited * refactor: subtable does not support inline operations * refactor: jons edit in table * refactor: sequence readOnly in table * refactor: json readOnly in table * fix: sub-table appends * fix: runWhenParamsChanged * fix: runWhenParamsChanged * fix: sub-table appends * fix: sub-table appends * refactor: sub-table * style: checkbox group intable * style: delete button style improve * fix: json edit in table * fix: sub-table appends * style: upload file in table column * refactor: map edit in table * refactor: map edit in table * refactor: map field display in sub-table * fix: support mutiple row * refactor: sub-table * refactor: sub-table not support sortable * fix: sub-table appends * fix: sub-table appends * chore: useAssociationNames * refactor: code improve * refactor: support blocktemplate * refactor: support blocktemplate * fix: subtable * fix: subtable initValue * refactor: useAssociationNames in block template * fix: cross hierarchical association field layout * fix: normal field of association field should be append * style: upload field in table * refactor: sub table should not row selection * style: checkboxGroup and radioGroup display in sub-table * refactor: locale * refactor: code improve * refactor: quickEdit in sub-table * refactor: quickEdit * refactor: quickEdit * refactor: quickEdit * refactor: quickEdit * style: quickEdit style improve * style: quickEdit style improve * style: quickEdit style improve * refactor: sub-table support required config * refactor: cell validate * refactor: cell validate * refactor: cell required validate * refactor: cell required validate * refactor: sub-table display when readPretty * refactor: sub-table required * refactor: sub-table required * refactor: sub-table required * refactor: sub-table initialValue * refactor: table * refactor: sub-tble field required * refactor: sub-table style improve * refactor: sub-table attachemnt * refactor: code improve * test: tableV2 snap * fix: subtable drag * test: tableV2 snap * refactor: checkbox group and radio group in sub-table * refactor: sub-table required style * style: markdown style in sub-table * refactor: markdown display in sub-table * refactor: json field display in sub-table * refactor: code improve * style: style improve * style: style improve * refactor: inserView when designable * refactor: china-region load data when dropdown click * refactor: code improve * refactor: code improve * refactor: display loading when the form is first loaded * refactor: display loading when the form is first loaded * fix: verification exception when deleting sub table rows * refactor: sub-table code improve * refactor: sub-table code improve * fix: json error feedback * refactor: code improve * fix: json onchange * fix: sub table data did not change when switching data templates * test: variable test * test: variable test * refactor: data template * refactor: code improve * refactor: code improve * fix: upload readpretty * fix: attach upload in sub-tabl * fix: remove small * fix: attach upload in sub-table * refactor: association fields should not display in sub-table * fix: dropdownMatchSelectWidth * refactor: association fields should not display in sub-table * refactor: selectFile is false in sub-table * refactor: attacattachment in sub-table * refactor: attacattachment in sub-table * fix: selector style * refactor: quick edit component * fix: zindex * style: style improve * style: style improve * feat: styling * fix: style * fix: style * refactor: quickEdit getContainer * refactor: quickEdit * refactor: quickEdit * fix: improve code * refactor: code improve * refactor: code improve --------- Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
		
							parent
							
								
									457afe3e06
								
							
						
					
					
						commit
						4faf64f905
					
				@ -1,6 +1,7 @@
 | 
			
		||||
import { createForm } from '@formily/core';
 | 
			
		||||
import { RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { isEmpty } from 'lodash';
 | 
			
		||||
import { Spin } from 'antd';
 | 
			
		||||
import React, { createContext, useContext, useEffect, useMemo, useRef } from 'react';
 | 
			
		||||
import { useCollection } from '../collection-manager';
 | 
			
		||||
import { RecordProvider, useRecord } from '../record-provider';
 | 
			
		||||
@ -23,9 +24,9 @@ const InternalFormBlockProvider = (props) => {
 | 
			
		||||
  const { resource, service, updateAssociationValues } = useBlockRequestContext();
 | 
			
		||||
  const formBlockRef = useRef();
 | 
			
		||||
  const record = useRecord();
 | 
			
		||||
  // if (service.loading) {
 | 
			
		||||
  //   return <Spin />;
 | 
			
		||||
  // }
 | 
			
		||||
  if (service.loading && Object.keys(form?.initialValues)?.length === 0 && action) {
 | 
			
		||||
    return <Spin />;
 | 
			
		||||
  }
 | 
			
		||||
  return (
 | 
			
		||||
    <FormBlockContext.Provider
 | 
			
		||||
      value={{
 | 
			
		||||
 | 
			
		||||
@ -127,7 +127,7 @@ export const TableBlockProvider = (props) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaComponentOptions scope={{ treeTable }}>
 | 
			
		||||
      <FormContext.Provider value={form}>
 | 
			
		||||
        <BlockProvider {...props} params={params}>
 | 
			
		||||
        <BlockProvider {...props} params={params} runWhenParamsChanged>
 | 
			
		||||
          <InternalTableBlockProvider {...props} childrenColumnName={childrenColumnName} params={params} />
 | 
			
		||||
        </BlockProvider>
 | 
			
		||||
      </FormContext.Provider>
 | 
			
		||||
 | 
			
		||||
@ -46,7 +46,8 @@ const InternalField: React.FC = (props: Props) => {
 | 
			
		||||
    setFieldProps('title', uiSchema.title);
 | 
			
		||||
    setFieldProps('description', uiSchema.description);
 | 
			
		||||
    if (ctx?.form) {
 | 
			
		||||
      setFieldProps('initialValue', fieldSchema.default || defaultValue);
 | 
			
		||||
      const defaultVal = fieldSchema.default || defaultValue;
 | 
			
		||||
      defaultVal !== null && defaultVal !== undefined && setFieldProps('initialValue', defaultVal);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!field.validator && (uiSchema['x-validator'] || fieldSchema['x-validator'])) {
 | 
			
		||||
 | 
			
		||||
@ -12,16 +12,10 @@ export const url: IField = {
 | 
			
		||||
    type: 'string',
 | 
			
		||||
    uiSchema: {
 | 
			
		||||
      type: 'string',
 | 
			
		||||
      title: '{{t("URL")}}',
 | 
			
		||||
      'x-component': 'Input.URL',
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  schemaInitialize(schema: ISchema, { block }) {
 | 
			
		||||
    if (['Table', 'Kanban'].includes(block)) {
 | 
			
		||||
      schema['x-component-props'] = schema['x-component-props'] || {};
 | 
			
		||||
      schema['x-component-props']['size'] = 'small';
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  schemaInitialize(schema: ISchema, { block }) {},
 | 
			
		||||
  properties: {
 | 
			
		||||
    ...defaultProps,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
@ -293,14 +293,14 @@ export default {
 | 
			
		||||
  "Allow multiple": "Allow multiple",
 | 
			
		||||
  "Quick upload": "Quick upload",
 | 
			
		||||
  "Select file": "Select file",
 | 
			
		||||
  "Subtable": "Subtable",
 | 
			
		||||
  "Subtable": "Sub-table",
 | 
			
		||||
  "Subform": "Sub-form",
 | 
			
		||||
  "Field mode":"Field mode",
 | 
			
		||||
  "Allow add new data":"Allow add new data",
 | 
			
		||||
  "Record picker": "Record picker",
 | 
			
		||||
  "Toggles the subfield mode": "Toggles the subfield mode",
 | 
			
		||||
  "Selector mode": "Selector mode",
 | 
			
		||||
  "Subtable mode": "Subtable mode",
 | 
			
		||||
  "Subtable mode": "Sub-table mode",
 | 
			
		||||
  "Subform mode": "Sub-form mode",
 | 
			
		||||
  "Edit block title": "Edit block title",
 | 
			
		||||
  "Block title": "Block title",
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ export const ActionDrawer: ComposedActionDrawer = observer(
 | 
			
		||||
  (props) => {
 | 
			
		||||
    const { footerNodeName = 'Action.Drawer.Footer', ...others } = props;
 | 
			
		||||
    const { t } = useTranslation();
 | 
			
		||||
    const { visible, setVisible, openSize = 'middle', drawerProps } = useActionContext();
 | 
			
		||||
    const { visible, setVisible, openSize = 'middle', drawerProps, modalProps } = useActionContext();
 | 
			
		||||
    const schema = useFieldSchema();
 | 
			
		||||
    const field = useField();
 | 
			
		||||
    const openSizeFromParent = schema.parent?.['x-component-props']?.['openSize'];
 | 
			
		||||
@ -35,6 +35,7 @@ export const ActionDrawer: ComposedActionDrawer = observer(
 | 
			
		||||
        title={field.title}
 | 
			
		||||
        {...others}
 | 
			
		||||
        {...drawerProps}
 | 
			
		||||
        {...modalProps}
 | 
			
		||||
        style={{
 | 
			
		||||
          ...drawerProps?.style,
 | 
			
		||||
          ...others?.style,
 | 
			
		||||
 | 
			
		||||
@ -84,6 +84,9 @@ export const AssociationFieldProvider = observer(
 | 
			
		||||
          field.value = [{}];
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (currentMode === 'SubTable') {
 | 
			
		||||
        field.value = [];
 | 
			
		||||
      }
 | 
			
		||||
      setLoading(false);
 | 
			
		||||
      // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
			
		||||
    }, [currentMode, collectionField, fieldValue]);
 | 
			
		||||
 | 
			
		||||
@ -70,6 +70,7 @@ const InternalAssociationSelect = observer((props: AssociationSelectProps) => {
 | 
			
		||||
        <RemoteSelect
 | 
			
		||||
          style={{ width: '100%' }}
 | 
			
		||||
          {...props}
 | 
			
		||||
          size={'middle'}
 | 
			
		||||
          objectValue={objectValue}
 | 
			
		||||
          value={value}
 | 
			
		||||
          service={service}
 | 
			
		||||
 | 
			
		||||
@ -133,7 +133,7 @@ const InternalFileManager = (props) => {
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
  return (
 | 
			
		||||
    <div>
 | 
			
		||||
    <div style={{ width: '100%', overflow: 'auto' }}>
 | 
			
		||||
      <FileSelector
 | 
			
		||||
        value={options}
 | 
			
		||||
        multiple={multiple}
 | 
			
		||||
@ -153,7 +153,16 @@ const InternalFileManager = (props) => {
 | 
			
		||||
          }
 | 
			
		||||
        }}
 | 
			
		||||
      />
 | 
			
		||||
      <ActionContextProvider value={{ openMode: 'drawer', visible: visibleSelector, setVisible: setVisibleSelector }}>
 | 
			
		||||
      <ActionContextProvider
 | 
			
		||||
        value={{
 | 
			
		||||
          openMode: 'drawer',
 | 
			
		||||
          visible: visibleSelector,
 | 
			
		||||
          setVisible: setVisibleSelector,
 | 
			
		||||
          modalProps: {
 | 
			
		||||
            getContainer: others?.getContainer,
 | 
			
		||||
          },
 | 
			
		||||
        }}
 | 
			
		||||
      >
 | 
			
		||||
        <RecordPickerProvider {...pickerProps}>
 | 
			
		||||
          <CollectionProvider name={collectionField.target}>
 | 
			
		||||
            <FormProvider>
 | 
			
		||||
 | 
			
		||||
@ -1,30 +1,63 @@
 | 
			
		||||
import { FormLayout } from '@formily/antd';
 | 
			
		||||
import { RecursionField, useField, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
import { FormItem, FormLayout } from '@formily/antd';
 | 
			
		||||
import { RecursionField, observer, useField, useFieldSchema } from '@formily/react';
 | 
			
		||||
import React, { useEffect } from 'react';
 | 
			
		||||
import { CollectionProvider } from '../../../collection-manager';
 | 
			
		||||
import { SchemaComponentOptions } from '../../../schema-component';
 | 
			
		||||
import Select from '../select/Select';
 | 
			
		||||
import { useAssociationFieldContext, useInsertSchema } from './hooks';
 | 
			
		||||
import schema from './schema';
 | 
			
		||||
 | 
			
		||||
export const InternalSubTable = () => {
 | 
			
		||||
  const field = useField();
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const insert = useInsertSchema('SubTable');
 | 
			
		||||
  const { options } = useAssociationFieldContext();
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    insert(schema.SubTable);
 | 
			
		||||
  }, []);
 | 
			
		||||
  return (
 | 
			
		||||
    <CollectionProvider name={options.target}>
 | 
			
		||||
      <FormLayout layout={'vertical'}>
 | 
			
		||||
        <RecursionField
 | 
			
		||||
          onlyRenderProperties
 | 
			
		||||
          basePath={field.address}
 | 
			
		||||
          schema={fieldSchema}
 | 
			
		||||
          filterProperties={(s) => {
 | 
			
		||||
            return s['x-component'] === 'AssociationField.SubTable';
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
      </FormLayout>
 | 
			
		||||
    </CollectionProvider>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
export const InternalSubTable = observer(
 | 
			
		||||
  () => {
 | 
			
		||||
    const field: any = useField();
 | 
			
		||||
    const fieldSchema = useFieldSchema();
 | 
			
		||||
    const insert = useInsertSchema('SubTable');
 | 
			
		||||
    const { options } = useAssociationFieldContext();
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
      insert(schema.SubTable);
 | 
			
		||||
      field.required = fieldSchema['required'];
 | 
			
		||||
    }, []);
 | 
			
		||||
    return (
 | 
			
		||||
      <CollectionProvider name={options.target}>
 | 
			
		||||
        <FormLayout
 | 
			
		||||
          className={css`
 | 
			
		||||
            .ant-formily-item-bordered-none {
 | 
			
		||||
              .ant-input-number-group-addon {
 | 
			
		||||
                border: none !important;
 | 
			
		||||
                background: none;
 | 
			
		||||
              }
 | 
			
		||||
              .ant-checkbox-wrapper {
 | 
			
		||||
                margin-left: 8px;
 | 
			
		||||
              }
 | 
			
		||||
              .ant-btn {
 | 
			
		||||
                border: none !important;
 | 
			
		||||
                box-shadow: none;
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          `}
 | 
			
		||||
          layout={'vertical'}
 | 
			
		||||
          bordered={false}
 | 
			
		||||
        >
 | 
			
		||||
          <SchemaComponentOptions
 | 
			
		||||
            components={{
 | 
			
		||||
              FormItem: (props) => <FormItem {...props} />,
 | 
			
		||||
              'Radio.Group': Select,
 | 
			
		||||
              'Checkbox.Group': (props) => <Select multiple={true} mode="multiple" {...props} />,
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            <RecursionField
 | 
			
		||||
              onlyRenderProperties
 | 
			
		||||
              basePath={field.address}
 | 
			
		||||
              schema={fieldSchema}
 | 
			
		||||
              filterProperties={(s) => {
 | 
			
		||||
                return s['x-component'] === 'AssociationField.SubTable';
 | 
			
		||||
              }}
 | 
			
		||||
            />
 | 
			
		||||
          </SchemaComponentOptions>
 | 
			
		||||
        </FormLayout>
 | 
			
		||||
      </CollectionProvider>
 | 
			
		||||
    );
 | 
			
		||||
  },
 | 
			
		||||
  { displayName: 'InternalSubTable' },
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@ import { CollectionProvider } from '../../../collection-manager';
 | 
			
		||||
import { RecordProvider, useRecord } from '../../../record-provider';
 | 
			
		||||
import { FormProvider } from '../../core';
 | 
			
		||||
import { useCompile } from '../../hooks';
 | 
			
		||||
import { useDesignable } from '../../';
 | 
			
		||||
import { ActionContextProvider, useActionContext } from '../action';
 | 
			
		||||
import { EllipsisWithTooltip } from '../input/EllipsisWithTooltip';
 | 
			
		||||
import { useAssociationFieldContext, useFieldNames, useInsertSchema } from './hooks';
 | 
			
		||||
@ -35,6 +36,7 @@ export const ReadPrettyInternalViewer: React.FC = observer(
 | 
			
		||||
    const { options: collectionField } = useAssociationFieldContext();
 | 
			
		||||
    const [record, setRecord] = useState({});
 | 
			
		||||
    const compile = useCompile();
 | 
			
		||||
    const { designable } = useDesignable();
 | 
			
		||||
    const labelUiSchema = useLabelUiSchema(collectionField, fieldNames?.label || 'label');
 | 
			
		||||
    const { snapshot } = useActionContext();
 | 
			
		||||
    const ellipsisWithTooltipRef = useRef<IEllipsisWithTooltipRef>();
 | 
			
		||||
@ -53,7 +55,9 @@ export const ReadPrettyInternalViewer: React.FC = observer(
 | 
			
		||||
                  onClick={(e) => {
 | 
			
		||||
                    e.stopPropagation();
 | 
			
		||||
                    e.preventDefault();
 | 
			
		||||
                    insertViewer(schema.Viewer);
 | 
			
		||||
                    if (designable) {
 | 
			
		||||
                      insertViewer(schema.Viewer);
 | 
			
		||||
                    }
 | 
			
		||||
                    setVisible(true);
 | 
			
		||||
                    setRecord(record);
 | 
			
		||||
                    ellipsisWithTooltipRef?.current?.setPopoverVisible(false);
 | 
			
		||||
 | 
			
		||||
@ -1,29 +1,111 @@
 | 
			
		||||
import { PlusOutlined } from '@ant-design/icons';
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
import { ArrayField } from '@formily/core';
 | 
			
		||||
import { exchangeArrayState } from '@formily/core/esm/shared/internals';
 | 
			
		||||
import { observer } from '@formily/react';
 | 
			
		||||
import { action } from '@formily/reactive';
 | 
			
		||||
import { isArr } from '@formily/shared';
 | 
			
		||||
import { Button } from 'antd';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { Table } from '../table-v2/Table';
 | 
			
		||||
import { useAssociationFieldContext } from './hooks';
 | 
			
		||||
 | 
			
		||||
export const SubTable: any = observer(
 | 
			
		||||
  (props) => {
 | 
			
		||||
  (props: any) => {
 | 
			
		||||
    const { field } = useAssociationFieldContext<ArrayField>();
 | 
			
		||||
    const { t } = useTranslation();
 | 
			
		||||
    const move = (fromIndex: number, toIndex: number) => {
 | 
			
		||||
      if (toIndex === undefined) return;
 | 
			
		||||
      if (!isArr(field.value)) return;
 | 
			
		||||
      if (fromIndex === toIndex) return;
 | 
			
		||||
      return action(() => {
 | 
			
		||||
        const fromItem = field.value[fromIndex];
 | 
			
		||||
        field.value.splice(fromIndex, 1);
 | 
			
		||||
        field.value.splice(toIndex, 0, fromItem);
 | 
			
		||||
        exchangeArrayState(field, {
 | 
			
		||||
          fromIndex,
 | 
			
		||||
          toIndex,
 | 
			
		||||
        });
 | 
			
		||||
        return field.onInput(field.value);
 | 
			
		||||
      });
 | 
			
		||||
    };
 | 
			
		||||
    field.move = move;
 | 
			
		||||
    return (
 | 
			
		||||
      <div>
 | 
			
		||||
        <Table size={'small'} showIndex field={field} pagination={false} />
 | 
			
		||||
        {field.editable && (
 | 
			
		||||
          <Button
 | 
			
		||||
            type={'dashed'}
 | 
			
		||||
            block
 | 
			
		||||
            style={{ marginTop: 12 }}
 | 
			
		||||
            onClick={() => {
 | 
			
		||||
              field.value = field.value || [];
 | 
			
		||||
              field.value.push({});
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            Add new
 | 
			
		||||
          </Button>
 | 
			
		||||
        )}
 | 
			
		||||
      <div
 | 
			
		||||
        className={css`
 | 
			
		||||
          .ant-table-footer {
 | 
			
		||||
            padding: 0 !important;
 | 
			
		||||
          }
 | 
			
		||||
          .ant-formily-item-error-help {
 | 
			
		||||
            display: none;
 | 
			
		||||
          }
 | 
			
		||||
          .ant-description-textarea {
 | 
			
		||||
            line-height: 34px;
 | 
			
		||||
          }
 | 
			
		||||
          .ant-table-cell .ant-formily-item-error-help {
 | 
			
		||||
            display: block;
 | 
			
		||||
            position: absolute;
 | 
			
		||||
            font-size: 12px;
 | 
			
		||||
            top: 100%;
 | 
			
		||||
            background: #fff;
 | 
			
		||||
            width: 100%;
 | 
			
		||||
            margin-top: 3px;
 | 
			
		||||
            padding: 3px;
 | 
			
		||||
            z-index: 1;
 | 
			
		||||
            border-radius: 3px;
 | 
			
		||||
            box-shadow: 0 0 10px #eee;
 | 
			
		||||
            animation: none;
 | 
			
		||||
            transform: translateY(0);
 | 
			
		||||
            opacity: 1;
 | 
			
		||||
          }
 | 
			
		||||
        `}
 | 
			
		||||
      >
 | 
			
		||||
        <Table
 | 
			
		||||
          className={css`
 | 
			
		||||
            .ant-select-selector {
 | 
			
		||||
              /* min-height: 31px; */
 | 
			
		||||
            }
 | 
			
		||||
            .ant-formily-item.ant-formily-item-feedback-layout-loose {
 | 
			
		||||
              margin-bottom: 0px !important;
 | 
			
		||||
            }
 | 
			
		||||
            .ant-formily-editable {
 | 
			
		||||
              vertical-align: sub;
 | 
			
		||||
            }
 | 
			
		||||
            .ant-table table {
 | 
			
		||||
            }
 | 
			
		||||
            td:not(.ant-table-selection-column) {
 | 
			
		||||
              padding: 0 !important;
 | 
			
		||||
            }
 | 
			
		||||
          `}
 | 
			
		||||
          bordered
 | 
			
		||||
          size={'small'}
 | 
			
		||||
          field={field}
 | 
			
		||||
          showIndex
 | 
			
		||||
          dragSort={field.editable}
 | 
			
		||||
          showDel={field.editable}
 | 
			
		||||
          pagination={false}
 | 
			
		||||
          rowSelection={{ type: 'none', hideSelectAll: true }}
 | 
			
		||||
          footer={() =>
 | 
			
		||||
            field.editable && (
 | 
			
		||||
              <Button
 | 
			
		||||
                type={'text'}
 | 
			
		||||
                block
 | 
			
		||||
                className={css`
 | 
			
		||||
                  display: block;
 | 
			
		||||
                `}
 | 
			
		||||
                onClick={() => {
 | 
			
		||||
                  field.value = field.value || [];
 | 
			
		||||
                  field.value.push({});
 | 
			
		||||
                  field.onInput(field.value);
 | 
			
		||||
                }}
 | 
			
		||||
                icon={<PlusOutlined />}
 | 
			
		||||
              >
 | 
			
		||||
                {/* {t('Add new')} */}
 | 
			
		||||
              </Button>
 | 
			
		||||
            )
 | 
			
		||||
          }
 | 
			
		||||
        />
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
@ -121,21 +121,9 @@ export default {
 | 
			
		||||
    type: 'void',
 | 
			
		||||
    'x-component': 'AssociationField.SubTable',
 | 
			
		||||
    'x-initializer': 'TableColumnInitializers',
 | 
			
		||||
    properties: {
 | 
			
		||||
      indexCol: {
 | 
			
		||||
        type: 'void',
 | 
			
		||||
        'x-component': 'TableV2.Column',
 | 
			
		||||
        'x-component-props': {
 | 
			
		||||
          width: 80,
 | 
			
		||||
        },
 | 
			
		||||
        properties: {
 | 
			
		||||
          __index__: {
 | 
			
		||||
            type: 'void',
 | 
			
		||||
            'x-component': 'TableV2.Index',
 | 
			
		||||
            'x-read-pretty': true,
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    'x-initializer-props': {
 | 
			
		||||
      action: false,
 | 
			
		||||
    },
 | 
			
		||||
    properties: {},
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -2,9 +2,10 @@ import { LoadingOutlined } from '@ant-design/icons';
 | 
			
		||||
import { ArrayField } from '@formily/core';
 | 
			
		||||
import { connect, mapProps, mapReadPretty, useField } from '@formily/react';
 | 
			
		||||
import { toArr } from '@formily/shared';
 | 
			
		||||
import { action } from '@formily/reactive';
 | 
			
		||||
import { Cascader as AntdCascader, Space } from 'antd';
 | 
			
		||||
import { isBoolean, omit } from 'lodash';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import React, { useState } from 'react';
 | 
			
		||||
import { useRequest } from '../../../api-client';
 | 
			
		||||
import { defaultFieldNames } from './defaultFieldNames';
 | 
			
		||||
import { ReadPretty } from './ReadPretty';
 | 
			
		||||
@ -35,7 +36,7 @@ export const Cascader = connect(
 | 
			
		||||
    } = props;
 | 
			
		||||
    const fieldNames = { ...defaultFieldNames, ...props.fieldNames };
 | 
			
		||||
    const loadData = useLoadData(props);
 | 
			
		||||
    const { loading } = useDataSource({
 | 
			
		||||
    const { loading, run } = useDataSource({
 | 
			
		||||
      onSuccess(data) {
 | 
			
		||||
        field.dataSource = data?.data || [];
 | 
			
		||||
      },
 | 
			
		||||
@ -62,6 +63,11 @@ export const Cascader = connect(
 | 
			
		||||
        </Space>
 | 
			
		||||
      );
 | 
			
		||||
    };
 | 
			
		||||
    const handelDropDownVisible = (value) => {
 | 
			
		||||
      if (value && !field.dataSource) {
 | 
			
		||||
        run();
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    return (
 | 
			
		||||
      <AntdCascader
 | 
			
		||||
        loading={loading}
 | 
			
		||||
@ -72,6 +78,7 @@ export const Cascader = connect(
 | 
			
		||||
        value={toValue()}
 | 
			
		||||
        fieldNames={fieldNames}
 | 
			
		||||
        displayRender={displayRender}
 | 
			
		||||
        onDropdownVisibleChange={handelDropDownVisible}
 | 
			
		||||
        onChange={(value, selectedOptions) => {
 | 
			
		||||
          if (value && labelInValue) {
 | 
			
		||||
            onChange(selectedOptions.map((option) => omit(option, [fieldNames.children])));
 | 
			
		||||
 | 
			
		||||
@ -833,7 +833,7 @@ FormItem.Designer = function Designer() {
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
      )}
 | 
			
		||||
      {options.length > 0 && isAssociationField && (
 | 
			
		||||
      {options.length > 0 && isAssociationField&&fieldMode!=='SubTable' && (
 | 
			
		||||
        <SchemaSettings.SelectItem
 | 
			
		||||
          key="title-field"
 | 
			
		||||
          title={t('Title field')}
 | 
			
		||||
 | 
			
		||||
@ -72,13 +72,21 @@ const useDataTemplates = () => {
 | 
			
		||||
    enabled: items.length > 0 && items.every((item) => item.dataId !== undefined),
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
function filterReferences(obj) {
 | 
			
		||||
  const filteredObj = {};
 | 
			
		||||
  for (const key in obj) {
 | 
			
		||||
    if (typeof obj[key] !== 'object') {
 | 
			
		||||
      filteredObj[key] = obj[key];
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return filteredObj;
 | 
			
		||||
}
 | 
			
		||||
export const Templates = ({ style = {}, form }) => {
 | 
			
		||||
  const { templates, display, enabled, defaultTemplate } = useDataTemplates();
 | 
			
		||||
  const [value, setValue] = React.useState(defaultTemplate?.key || 'none');
 | 
			
		||||
  const api = useAPIClient();
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (enabled && defaultTemplate) {
 | 
			
		||||
      form.__template = true;
 | 
			
		||||
 | 
			
		||||
@ -31,6 +31,12 @@
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ant-formily-item-bordered-none {
 | 
			
		||||
  .ant-formily-item-feedback-layout-loose {
 | 
			
		||||
    margin-bottom: 0 !important;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ant-formily-item-control-content-component .ant-tag {
 | 
			
		||||
  white-space: pre-wrap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -45,4 +45,5 @@ export * from './time-picker';
 | 
			
		||||
export * from './tree-select';
 | 
			
		||||
export * from './upload';
 | 
			
		||||
export * from './variable';
 | 
			
		||||
export * from './quick-edit'
 | 
			
		||||
import './index.less';
 | 
			
		||||
 | 
			
		||||
@ -35,11 +35,14 @@ export const Json = React.forwardRef<typeof Input.TextArea, JSONTextAreaProps>(
 | 
			
		||||
        onChange={(ev) => {
 | 
			
		||||
          setText(ev.target.value);
 | 
			
		||||
          try {
 | 
			
		||||
            const v = ev.target.value.trim() !== '' ? JSON.parse(ev.target.value) : null;
 | 
			
		||||
            if (ev.target.value.trim() !== '') {
 | 
			
		||||
              JSON.parse(ev.target.value);
 | 
			
		||||
            }
 | 
			
		||||
            field.setFeedback({});
 | 
			
		||||
            onChange?.(v);
 | 
			
		||||
          } catch (err) {
 | 
			
		||||
            onChange?.(ev);
 | 
			
		||||
            field.setFeedback({
 | 
			
		||||
              type: 'error',
 | 
			
		||||
              code: 'JSONSyntaxError',
 | 
			
		||||
@ -53,6 +56,7 @@ export const Json = React.forwardRef<typeof Input.TextArea, JSONTextAreaProps>(
 | 
			
		||||
            field.setFeedback({});
 | 
			
		||||
            onChange?.(v);
 | 
			
		||||
          } catch (err) {
 | 
			
		||||
            onChange?.(ev);
 | 
			
		||||
            field.setFeedback({
 | 
			
		||||
              type: 'error',
 | 
			
		||||
              code: 'JSONSyntaxError',
 | 
			
		||||
 | 
			
		||||
@ -20,17 +20,19 @@ export const Markdown: any = connect(
 | 
			
		||||
      suffix: <span>{field?.['loading'] || field?.['validating'] ? <LoadingOutlined /> : props.suffix}</span>,
 | 
			
		||||
    };
 | 
			
		||||
  }),
 | 
			
		||||
  mapReadPretty((props) => {
 | 
			
		||||
    const { html, loading } = useParseMarkdown(props.value);
 | 
			
		||||
    const text = convertToText(html);
 | 
			
		||||
    const value = <div className={'nb-markdown'} dangerouslySetInnerHTML={{ __html: html }} />;
 | 
			
		||||
    if (loading) {
 | 
			
		||||
      return <Spin />;
 | 
			
		||||
    }
 | 
			
		||||
    return <InputReadPretty.TextArea {...props} autop={false} text={text} value={value} />;
 | 
			
		||||
  }),
 | 
			
		||||
  mapReadPretty((props) => <MarkdownReadPretty {...props} />),
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export const MarkdownReadPretty = (props) => {
 | 
			
		||||
  const { html = '', loading } = useParseMarkdown(props.value);
 | 
			
		||||
  const text = convertToText(html);
 | 
			
		||||
  const value = <div className={'nb-markdown'} dangerouslySetInnerHTML={{ __html: html }} />;
 | 
			
		||||
  if (loading) {
 | 
			
		||||
    return <Spin />;
 | 
			
		||||
  }
 | 
			
		||||
  return <InputReadPretty.TextArea {...props} autop={false} text={text} value={value} />;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Markdown.Void = MarkdownVoid;
 | 
			
		||||
 | 
			
		||||
export default Markdown;
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@ import { DeleteOutlined, DownloadOutlined, PlusOutlined } from '@ant-design/icon
 | 
			
		||||
import { connect, mapReadPretty } from '@formily/react';
 | 
			
		||||
import { Upload as AntdUpload, Button, Progress, Space } from 'antd';
 | 
			
		||||
import cls from 'classnames';
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
import { saveAs } from 'file-saver';
 | 
			
		||||
import React, { useEffect, useState } from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
@ -44,7 +45,6 @@ export const FileSelector = (props: Props) => {
 | 
			
		||||
    onRemove?.(file);
 | 
			
		||||
    return true;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleSelect = (e) => {
 | 
			
		||||
    e.preventDefault();
 | 
			
		||||
    e.stopPropagation();
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,78 @@
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
import { FormItem } from '@formily/antd';
 | 
			
		||||
import { Field, createForm } from '@formily/core';
 | 
			
		||||
import { FormContext, RecursionField, observer, useField, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { Popover } from 'antd';
 | 
			
		||||
import React, { useMemo, useRef } from 'react';
 | 
			
		||||
import { useCollectionManager } from '../../../collection-manager';
 | 
			
		||||
 | 
			
		||||
export const Editable = observer((props) => {
 | 
			
		||||
  const field: any = useField();
 | 
			
		||||
  const containerRef = useRef(null);
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const schema: any = {
 | 
			
		||||
    name: fieldSchema.name,
 | 
			
		||||
    'x-collection-field': fieldSchema['x-collection-field'],
 | 
			
		||||
    'x-component': 'CollectionField',
 | 
			
		||||
    'x-read-pretty': true,
 | 
			
		||||
    default: field.value,
 | 
			
		||||
    'x-component-props': fieldSchema['x-component-props'],
 | 
			
		||||
  };
 | 
			
		||||
  const form = useMemo(
 | 
			
		||||
    () =>
 | 
			
		||||
      createForm({
 | 
			
		||||
        values: {
 | 
			
		||||
          [fieldSchema.name]: field.value,
 | 
			
		||||
        },
 | 
			
		||||
      }),
 | 
			
		||||
    [field.value, fieldSchema['x-component-props']],
 | 
			
		||||
  );
 | 
			
		||||
  const getContainer = () => {
 | 
			
		||||
    return containerRef.current;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const modifiedChildren = React.Children.map(props.children, (child) => {
 | 
			
		||||
    if (React.isValidElement(child)) {
 | 
			
		||||
      //@ts-ignore
 | 
			
		||||
      return React.cloneElement(child, { getContainer });
 | 
			
		||||
    }
 | 
			
		||||
    return child;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <FormItem {...props} labelStyle={{ display: 'none' }}>
 | 
			
		||||
      <Popover
 | 
			
		||||
        content={
 | 
			
		||||
          <div style={{ width: '100%', height: '100%', minWidth: 500 }}>
 | 
			
		||||
            <div ref={containerRef}>{modifiedChildren}</div>
 | 
			
		||||
          </div>
 | 
			
		||||
        }
 | 
			
		||||
        trigger="click"
 | 
			
		||||
        placement={'bottomLeft'}
 | 
			
		||||
        overlayClassName={css`
 | 
			
		||||
          padding-top: 0;
 | 
			
		||||
          .ant-popover-arrow {
 | 
			
		||||
            display: none;
 | 
			
		||||
          }
 | 
			
		||||
        `}
 | 
			
		||||
      >
 | 
			
		||||
        <div style={{ minHeight: 30, padding: '0 8px' }}>
 | 
			
		||||
          <FormContext.Provider value={form}>
 | 
			
		||||
            <RecursionField schema={schema} name={fieldSchema.name} />
 | 
			
		||||
          </FormContext.Provider>
 | 
			
		||||
        </div>
 | 
			
		||||
      </Popover>
 | 
			
		||||
    </FormItem>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const QuickEdit = observer((props) => {
 | 
			
		||||
  const field = useField<Field>();
 | 
			
		||||
  const { getCollectionJoinField } = useCollectionManager();
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const collectionField = getCollectionJoinField(fieldSchema['x-collection-field']);
 | 
			
		||||
  if (!collectionField) {
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
  return field.editable ? <Editable {...props} /> : <FormItem {...props} style={{ padding: '0 8px' }} />;
 | 
			
		||||
});
 | 
			
		||||
@ -0,0 +1 @@
 | 
			
		||||
export * from './QuickEdit';
 | 
			
		||||
@ -235,9 +235,10 @@ const InternalRemoteSelect = connect(
 | 
			
		||||
      dataSource: 'options',
 | 
			
		||||
    },
 | 
			
		||||
    (props, field) => {
 | 
			
		||||
      const fieldSchema = useFieldSchema();
 | 
			
		||||
      return {
 | 
			
		||||
        ...props,
 | 
			
		||||
        fieldNames: { ...defaultFieldNames, ...props.fieldNames, ...field.componentProps.fieldNames },
 | 
			
		||||
        fieldNames: { ...defaultFieldNames, ...props.fieldNames, ...field.componentProps.fieldNames,...fieldSchema['x-component-props']?.fieldNames },
 | 
			
		||||
        suffixIcon: field?.['loading'] || field?.['validating'] ? <LoadingOutlined /> : props.suffixIcon,
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@ -2,8 +2,9 @@ import { ISchema, useField, useFieldSchema } from '@formily/react';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
import { useCollectionManager } from '../../../collection-manager';
 | 
			
		||||
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
 | 
			
		||||
import { GeneralSchemaDesigner, SchemaSettings, isPatternDisabled } from '../../../schema-settings';
 | 
			
		||||
import { useCompile, useDesignable } from '../../hooks';
 | 
			
		||||
import { useAssociationFieldContext } from '../association-field/hooks';
 | 
			
		||||
 | 
			
		||||
const useLabelFields = (collectionName?: any) => {
 | 
			
		||||
  // 需要在组件顶层调用
 | 
			
		||||
@ -26,7 +27,7 @@ const useLabelFields = (collectionName?: any) => {
 | 
			
		||||
export const TableColumnDesigner = (props) => {
 | 
			
		||||
  const { uiSchema, fieldSchema, collectionField } = props;
 | 
			
		||||
  const { getInterface, getCollection } = useCollectionManager();
 | 
			
		||||
  const field = useField();
 | 
			
		||||
  const field: any = useField();
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  const columnSchema = useFieldSchema();
 | 
			
		||||
  const { dn } = useDesignable();
 | 
			
		||||
@ -36,6 +37,15 @@ export const TableColumnDesigner = (props) => {
 | 
			
		||||
  const intefaceCfg = getInterface(collectionField?.interface);
 | 
			
		||||
  const targetCollection = getCollection(collectionField?.target);
 | 
			
		||||
  const isFileField = isFileCollection(targetCollection);
 | 
			
		||||
  const isSubTableColumn = ['QuickEdit', 'FormItem'].includes(fieldSchema['x-decorator']);
 | 
			
		||||
  const { currentMode, field: tableField } = useAssociationFieldContext();
 | 
			
		||||
  let readOnlyMode = 'editable';
 | 
			
		||||
  if (fieldSchema['x-disabled'] === true) {
 | 
			
		||||
    readOnlyMode = 'readonly';
 | 
			
		||||
  }
 | 
			
		||||
  if (fieldSchema['x-read-pretty'] === true) {
 | 
			
		||||
    readOnlyMode = 'read-pretty';
 | 
			
		||||
  }
 | 
			
		||||
  return (
 | 
			
		||||
    <GeneralSchemaDesigner disableInitializer>
 | 
			
		||||
      <SchemaSettings.ModalItem
 | 
			
		||||
@ -101,7 +111,7 @@ export const TableColumnDesigner = (props) => {
 | 
			
		||||
          dn.refresh();
 | 
			
		||||
        }}
 | 
			
		||||
      />
 | 
			
		||||
      {intefaceCfg && intefaceCfg.sortable === true && (
 | 
			
		||||
      {intefaceCfg && intefaceCfg.sortable === true && !currentMode && (
 | 
			
		||||
        <SchemaSettings.SwitchItem
 | 
			
		||||
          title={t('Sortable')}
 | 
			
		||||
          checked={field.componentProps.sorter}
 | 
			
		||||
@ -125,7 +135,8 @@ export const TableColumnDesigner = (props) => {
 | 
			
		||||
      {['linkTo', 'm2m', 'm2o', 'o2m', 'obo', 'oho', 'snapshot', 'createdBy', 'updatedBy'].includes(
 | 
			
		||||
        collectionField?.interface,
 | 
			
		||||
      ) &&
 | 
			
		||||
        !isFileField && (
 | 
			
		||||
        !isFileField &&
 | 
			
		||||
        field.readPrety && (
 | 
			
		||||
          <SchemaSettings.SwitchItem
 | 
			
		||||
            title={t('Enable link')}
 | 
			
		||||
            checked={fieldSchema['x-component-props']?.enableLink !== false}
 | 
			
		||||
@ -177,6 +188,98 @@ export const TableColumnDesigner = (props) => {
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
      )}
 | 
			
		||||
 | 
			
		||||
      {isSubTableColumn && !field.readPretty && !uiSchema?.['x-read-pretty'] && (
 | 
			
		||||
        <SchemaSettings.SwitchItem
 | 
			
		||||
          key="required"
 | 
			
		||||
          title={t('Required')}
 | 
			
		||||
          checked={fieldSchema.required as boolean}
 | 
			
		||||
          onChange={(required) => {
 | 
			
		||||
            const schema = {
 | 
			
		||||
              ['x-uid']: fieldSchema['x-uid'],
 | 
			
		||||
            };
 | 
			
		||||
            fieldSchema['required'] = required;
 | 
			
		||||
            schema['required'] = required;
 | 
			
		||||
            const path = field.path?.splice(field.path?.length - 1, 1);
 | 
			
		||||
            (tableField as any)?.value.map((_, index) => {
 | 
			
		||||
              field.form.query(`${path.concat(`${index}.` + fieldSchema.name)}`).take((f) => {
 | 
			
		||||
                f.required = required;
 | 
			
		||||
              });
 | 
			
		||||
            });
 | 
			
		||||
            dn.emit('patch', {
 | 
			
		||||
              schema,
 | 
			
		||||
            });
 | 
			
		||||
            dn.refresh();
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
      )}
 | 
			
		||||
      {isSubTableColumn &&
 | 
			
		||||
        !field?.readPretty &&
 | 
			
		||||
        collectionField?.interface !== 'o2m' &&
 | 
			
		||||
        !isPatternDisabled(fieldSchema) && (
 | 
			
		||||
          <SchemaSettings.SelectItem
 | 
			
		||||
            key="pattern"
 | 
			
		||||
            title={t('Pattern')}
 | 
			
		||||
            options={[
 | 
			
		||||
              { label: t('Editable'), value: 'editable' },
 | 
			
		||||
              { label: t('Readonly'), value: 'readonly' },
 | 
			
		||||
              { label: t('Easy-reading'), value: 'read-pretty' },
 | 
			
		||||
            ]}
 | 
			
		||||
            value={readOnlyMode}
 | 
			
		||||
            onChange={(v) => {
 | 
			
		||||
              const schema: ISchema = {
 | 
			
		||||
                ['x-uid']: fieldSchema['x-uid'],
 | 
			
		||||
              };
 | 
			
		||||
              const path = field.path?.splice(field.path?.length - 1, 1);
 | 
			
		||||
              switch (v) {
 | 
			
		||||
                case 'readonly': {
 | 
			
		||||
                  fieldSchema['x-read-pretty'] = false;
 | 
			
		||||
                  fieldSchema['x-disabled'] = true;
 | 
			
		||||
                  schema['x-read-pretty'] = false;
 | 
			
		||||
                  schema['x-disabled'] = true;
 | 
			
		||||
                  (tableField as any)?.value.map((_, index) => {
 | 
			
		||||
                    field.form.query(`${path.concat(`${index}.` + fieldSchema.name)}`).take((f) => {
 | 
			
		||||
                      f.readonly = true;
 | 
			
		||||
                      f.disabled = true;
 | 
			
		||||
                    });
 | 
			
		||||
                  });
 | 
			
		||||
                  break;
 | 
			
		||||
                }
 | 
			
		||||
                case 'read-pretty': {
 | 
			
		||||
                  fieldSchema['x-read-pretty'] = true;
 | 
			
		||||
                  fieldSchema['x-disabled'] = false;
 | 
			
		||||
                  schema['x-read-pretty'] = true;
 | 
			
		||||
                  schema['x-disabled'] = false;
 | 
			
		||||
                  (tableField as any)?.value.map((_, index) => {
 | 
			
		||||
                    field.form.query(`${path.concat(`${index}.` + fieldSchema.name)}`).take((f) => {
 | 
			
		||||
                      f.readPretty = true;
 | 
			
		||||
                    });
 | 
			
		||||
                  });
 | 
			
		||||
                  break;
 | 
			
		||||
                }
 | 
			
		||||
                default: {
 | 
			
		||||
                  fieldSchema['x-read-pretty'] = false;
 | 
			
		||||
                  fieldSchema['x-disabled'] = false;
 | 
			
		||||
                  schema['x-read-pretty'] = false;
 | 
			
		||||
                  schema['x-disabled'] = false;
 | 
			
		||||
                  (tableField as any)?.value.map((_, index) => {
 | 
			
		||||
                    field.form.query(`${path.concat(`${index}.` + fieldSchema.name)}`).take((f) => {
 | 
			
		||||
                      f.readPretty = false;
 | 
			
		||||
                      f.disabled + false;
 | 
			
		||||
                    });
 | 
			
		||||
                  });
 | 
			
		||||
                  break;
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              dn.emit('patch', {
 | 
			
		||||
                schema,
 | 
			
		||||
              });
 | 
			
		||||
 | 
			
		||||
              dn.refresh();
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
        )}
 | 
			
		||||
      <SchemaSettings.Divider />
 | 
			
		||||
      <SchemaSettings.Remove
 | 
			
		||||
        removeParentsIfNoChildren
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,10 @@
 | 
			
		||||
import { MenuOutlined } from '@ant-design/icons';
 | 
			
		||||
import { DeleteOutlined, MenuOutlined } from '@ant-design/icons';
 | 
			
		||||
import { SortableContext, useSortable } from '@dnd-kit/sortable';
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
import { ArrayField, Field } from '@formily/core';
 | 
			
		||||
import { spliceArrayState } from '@formily/core/esm/shared/internals';
 | 
			
		||||
import { RecursionField, Schema, observer, useField, useFieldSchema } from '@formily/react';
 | 
			
		||||
import { reaction } from '@formily/reactive';
 | 
			
		||||
import { action, reaction } from '@formily/reactive';
 | 
			
		||||
import { useMemoizedFn } from 'ahooks';
 | 
			
		||||
import { Table as AntdTable, TableColumnProps } from 'antd';
 | 
			
		||||
import { default as classNames, default as cls } from 'classnames';
 | 
			
		||||
@ -71,12 +72,41 @@ const useTableColumns = (props) => {
 | 
			
		||||
  if (!exists) {
 | 
			
		||||
    return columns;
 | 
			
		||||
  }
 | 
			
		||||
  return columns.concat({
 | 
			
		||||
 | 
			
		||||
  const tableColumns = columns.concat({
 | 
			
		||||
    title: render(),
 | 
			
		||||
    dataIndex: 'TABLE_COLUMN_INITIALIZER',
 | 
			
		||||
    key: 'TABLE_COLUMN_INITIALIZER',
 | 
			
		||||
    render: designable ? () => <div style={{ minWidth: 300 }} /> : null,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  if (props.showDel) {
 | 
			
		||||
    tableColumns.push({
 | 
			
		||||
      title: '',
 | 
			
		||||
      key: 'delete',
 | 
			
		||||
      width: 60,
 | 
			
		||||
      align: 'center',
 | 
			
		||||
      fixed: 'right',
 | 
			
		||||
      render: (v, record, index) => {
 | 
			
		||||
        return (
 | 
			
		||||
          <DeleteOutlined
 | 
			
		||||
            style={{ cursor: 'pointer' }}
 | 
			
		||||
            onClick={() => {
 | 
			
		||||
              action(() => {
 | 
			
		||||
                spliceArrayState(field as any, {
 | 
			
		||||
                  startIndex: index,
 | 
			
		||||
                  deleteCount: 1,
 | 
			
		||||
                });
 | 
			
		||||
                field.value.splice(index, 1);
 | 
			
		||||
                return field.onInput(field.value);
 | 
			
		||||
              });
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  return tableColumns;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const topActiveClass = css`
 | 
			
		||||
@ -97,7 +127,7 @@ const SortableRow = (props) => {
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const className =
 | 
			
		||||
    (active?.data.current?.sortable.index ?? -1) > (over?.data.current?.sortable.index ?? -1)
 | 
			
		||||
    (active?.data.current?.sortable.index ?? -1) > (over?.data.current?.sortable?.index ?? -1)
 | 
			
		||||
      ? topActiveClass
 | 
			
		||||
      : bottomActiveClass;
 | 
			
		||||
 | 
			
		||||
@ -163,165 +193,166 @@ const useValidator = (validator: (value: any) => string) => {
 | 
			
		||||
  }, []);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const Table: any = observer(
 | 
			
		||||
  (props: any) => {
 | 
			
		||||
    const { pagination: pagination1, useProps, onChange, ...others1 } = props;
 | 
			
		||||
    const { pagination: pagination2, onClickRow, ...others2 } = useProps?.() || {};
 | 
			
		||||
    const {
 | 
			
		||||
      dragSort = false,
 | 
			
		||||
      showIndex = true,
 | 
			
		||||
      onRowSelectionChange,
 | 
			
		||||
      onChange: onTableChange,
 | 
			
		||||
      rowSelection,
 | 
			
		||||
      rowKey,
 | 
			
		||||
      required,
 | 
			
		||||
      onExpand,
 | 
			
		||||
      ...others
 | 
			
		||||
    } = { ...others1, ...others2 } as any;
 | 
			
		||||
    const field = useArrayField(others);
 | 
			
		||||
    const columns = useTableColumns(others);
 | 
			
		||||
    const schema = useFieldSchema();
 | 
			
		||||
    const isTableSelector = schema?.parent?.['x-decorator'] === 'TableSelectorProvider';
 | 
			
		||||
    const ctx = isTableSelector ? useTableSelectorContext() : useTableBlockContext();
 | 
			
		||||
    const { expandFlag } = ctx;
 | 
			
		||||
    const onRowDragEnd = useMemoizedFn(others.onRowDragEnd || (() => { }));
 | 
			
		||||
    const paginationProps = usePaginationProps(pagination1, pagination2);
 | 
			
		||||
    const requiredValidator = field.required || required;
 | 
			
		||||
    const { treeTable } = schema?.parent?.['x-decorator-props'] || {};
 | 
			
		||||
    const [expandedKeys, setExpandesKeys] = useState([]);
 | 
			
		||||
    const [allIncludesChildren, setAllIncludesChildren] = useState([]);
 | 
			
		||||
    const [selectedRowKeys, setSelectedRowKeys] = useState<any[]>(field?.data?.selectedRowKeys || []);
 | 
			
		||||
    const [selectedRow, setSelectedRow] = useState([]);
 | 
			
		||||
export const Table: any = observer((props: any) => {
 | 
			
		||||
  const { pagination: pagination1, useProps, onChange, ...others1 } = props;
 | 
			
		||||
  const { pagination: pagination2, onClickRow, ...others2 } = useProps?.() || {};
 | 
			
		||||
  const {
 | 
			
		||||
    dragSort = false,
 | 
			
		||||
    showIndex = true,
 | 
			
		||||
    onRowSelectionChange,
 | 
			
		||||
    onChange: onTableChange,
 | 
			
		||||
    rowSelection,
 | 
			
		||||
    rowKey,
 | 
			
		||||
    required,
 | 
			
		||||
    onExpand,
 | 
			
		||||
    ...others
 | 
			
		||||
  } = { ...others1, ...others2 } as any;
 | 
			
		||||
  const field = useArrayField(others);
 | 
			
		||||
  const columns = useTableColumns(others);
 | 
			
		||||
  const schema = useFieldSchema();
 | 
			
		||||
  const isTableSelector = schema?.parent?.['x-decorator'] === 'TableSelectorProvider';
 | 
			
		||||
  const ctx = isTableSelector ? useTableSelectorContext() : useTableBlockContext();
 | 
			
		||||
  const { expandFlag } = ctx;
 | 
			
		||||
  const onRowDragEnd = useMemoizedFn(others.onRowDragEnd || (() => {}));
 | 
			
		||||
  const paginationProps = usePaginationProps(pagination1, pagination2);
 | 
			
		||||
  // const requiredValidator = field.required || required;
 | 
			
		||||
  const { treeTable } = schema?.parent?.['x-decorator-props'] || {};
 | 
			
		||||
  const [expandedKeys, setExpandesKeys] = useState([]);
 | 
			
		||||
  const [allIncludesChildren, setAllIncludesChildren] = useState([]);
 | 
			
		||||
  const [selectedRowKeys, setSelectedRowKeys] = useState<any[]>(field?.data?.selectedRowKeys || []);
 | 
			
		||||
  const [selectedRow, setSelectedRow] = useState([]);
 | 
			
		||||
  const dataSource = field?.value?.slice?.()?.filter?.(Boolean) || [];
 | 
			
		||||
  const isRowSelect = rowSelection.type !== 'none';
 | 
			
		||||
 | 
			
		||||
    let onRow = null,
 | 
			
		||||
      highlightRow = '';
 | 
			
		||||
  let onRow = null,
 | 
			
		||||
    highlightRow = '';
 | 
			
		||||
 | 
			
		||||
    if (onClickRow) {
 | 
			
		||||
      onRow = (record) => {
 | 
			
		||||
        return {
 | 
			
		||||
          onClick: () => onClickRow(record, setSelectedRow, selectedRow),
 | 
			
		||||
        };
 | 
			
		||||
      };
 | 
			
		||||
      highlightRow = css`
 | 
			
		||||
        & > td {
 | 
			
		||||
          background-color: #caedff !important;
 | 
			
		||||
        }
 | 
			
		||||
        &:hover > td {
 | 
			
		||||
          background-color: #caedff !important;
 | 
			
		||||
        }
 | 
			
		||||
      `;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
      field.setValidator((value) => {
 | 
			
		||||
        if (requiredValidator) {
 | 
			
		||||
          return Array.isArray(value) && value.length > 0 ? null : 'The field value is required';
 | 
			
		||||
        }
 | 
			
		||||
        return;
 | 
			
		||||
      });
 | 
			
		||||
    }, [requiredValidator]);
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
      if (treeTable !== false) {
 | 
			
		||||
        const keys = getIdsWithChildren(field.value?.slice?.());
 | 
			
		||||
        setAllIncludesChildren(keys);
 | 
			
		||||
      }
 | 
			
		||||
    }, [field.value]);
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
      if (expandFlag) {
 | 
			
		||||
        setExpandesKeys(allIncludesChildren);
 | 
			
		||||
      } else {
 | 
			
		||||
        setExpandesKeys([]);
 | 
			
		||||
      }
 | 
			
		||||
    }, [expandFlag, allIncludesChildren]);
 | 
			
		||||
 | 
			
		||||
    const components = useMemo(() => {
 | 
			
		||||
  if (onClickRow) {
 | 
			
		||||
    onRow = (record) => {
 | 
			
		||||
      return {
 | 
			
		||||
        header: {
 | 
			
		||||
          wrapper: (props) => {
 | 
			
		||||
            return (
 | 
			
		||||
              <DndContext>
 | 
			
		||||
                <thead {...props} />
 | 
			
		||||
              </DndContext>
 | 
			
		||||
            );
 | 
			
		||||
          },
 | 
			
		||||
          cell: (props) => {
 | 
			
		||||
            return (
 | 
			
		||||
              <th
 | 
			
		||||
                {...props}
 | 
			
		||||
                className={cls(
 | 
			
		||||
                  props.className,
 | 
			
		||||
                  css`
 | 
			
		||||
                    max-width: 300px;
 | 
			
		||||
                    white-space: nowrap;
 | 
			
		||||
                    &:hover .general-schema-designer {
 | 
			
		||||
                      display: block;
 | 
			
		||||
                    }
 | 
			
		||||
                  `,
 | 
			
		||||
                )}
 | 
			
		||||
              />
 | 
			
		||||
            );
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
        body: {
 | 
			
		||||
          wrapper: (props) => {
 | 
			
		||||
            return (
 | 
			
		||||
              <DndContext
 | 
			
		||||
                onDragEnd={(e) => {
 | 
			
		||||
                  if (!e.active || !e.over) {
 | 
			
		||||
                    console.warn('move cancel');
 | 
			
		||||
                    return;
 | 
			
		||||
                  }
 | 
			
		||||
        onClick: () => onClickRow(record, setSelectedRow, selectedRow),
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
    highlightRow = css`
 | 
			
		||||
      & > td {
 | 
			
		||||
        background-color: #caedff !important;
 | 
			
		||||
      }
 | 
			
		||||
      &:hover > td {
 | 
			
		||||
        background-color: #caedff !important;
 | 
			
		||||
      }
 | 
			
		||||
    `;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
                  const fromIndex = e.active?.data.current?.sortable?.index;
 | 
			
		||||
                  const toIndex = e.over?.data.current?.sortable?.index;
 | 
			
		||||
                  const from = field.value[fromIndex];
 | 
			
		||||
                  const to = field.value[toIndex];
 | 
			
		||||
                  field.move(fromIndex, toIndex);
 | 
			
		||||
                  onRowDragEnd({ fromIndex, toIndex, from, to });
 | 
			
		||||
                }}
 | 
			
		||||
              >
 | 
			
		||||
                <tbody {...props} />
 | 
			
		||||
              </DndContext>
 | 
			
		||||
            );
 | 
			
		||||
          },
 | 
			
		||||
          row: (props) => {
 | 
			
		||||
            return <SortableRow {...props}></SortableRow>;
 | 
			
		||||
          },
 | 
			
		||||
          cell: (props) => (
 | 
			
		||||
            <td
 | 
			
		||||
  // useEffect(() => {
 | 
			
		||||
  //   field.setValidator((value) => {
 | 
			
		||||
  //     if (requiredValidator) {
 | 
			
		||||
  //       return Array.isArray(value) && value.length > 0 ? null : 'The field value is required';
 | 
			
		||||
  //     }
 | 
			
		||||
  //     return;
 | 
			
		||||
  //   });
 | 
			
		||||
  // }, [requiredValidator]);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (treeTable !== false) {
 | 
			
		||||
      const keys = getIdsWithChildren(field.value?.slice?.());
 | 
			
		||||
      setAllIncludesChildren(keys);
 | 
			
		||||
    }
 | 
			
		||||
  }, [field.value]);
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (expandFlag) {
 | 
			
		||||
      setExpandesKeys(allIncludesChildren);
 | 
			
		||||
    } else {
 | 
			
		||||
      setExpandesKeys([]);
 | 
			
		||||
    }
 | 
			
		||||
  }, [expandFlag, allIncludesChildren]);
 | 
			
		||||
 | 
			
		||||
  const components = useMemo(() => {
 | 
			
		||||
    return {
 | 
			
		||||
      header: {
 | 
			
		||||
        wrapper: (props) => {
 | 
			
		||||
          return (
 | 
			
		||||
            <DndContext>
 | 
			
		||||
              <thead {...props} />
 | 
			
		||||
            </DndContext>
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        cell: (props) => {
 | 
			
		||||
          return (
 | 
			
		||||
            <th
 | 
			
		||||
              {...props}
 | 
			
		||||
              className={classNames(
 | 
			
		||||
              className={cls(
 | 
			
		||||
                props.className,
 | 
			
		||||
                css`
 | 
			
		||||
                  max-width: 300px;
 | 
			
		||||
                  white-space: nowrap;
 | 
			
		||||
                  .nb-read-pretty-input-number {
 | 
			
		||||
                    text-align: right;
 | 
			
		||||
                  &:hover .general-schema-designer {
 | 
			
		||||
                    display: block;
 | 
			
		||||
                  }
 | 
			
		||||
                `,
 | 
			
		||||
              )}
 | 
			
		||||
            />
 | 
			
		||||
          ),
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      };
 | 
			
		||||
    }, [field, onRowDragEnd, dragSort]);
 | 
			
		||||
      },
 | 
			
		||||
      body: {
 | 
			
		||||
        wrapper: (props) => {
 | 
			
		||||
          return (
 | 
			
		||||
            <DndContext
 | 
			
		||||
              onDragEnd={(e) => {
 | 
			
		||||
                if (!e.active || !e.over) {
 | 
			
		||||
                  console.warn('move cancel');
 | 
			
		||||
                  return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
    const defaultRowKey = (record: any) => {
 | 
			
		||||
      return field.value?.indexOf?.(record);
 | 
			
		||||
                const fromIndex = e.active?.data.current?.sortable?.index;
 | 
			
		||||
                const toIndex = e.over?.data.current?.sortable?.index;
 | 
			
		||||
                const from = field.value[fromIndex];
 | 
			
		||||
                const to = field.value[toIndex];
 | 
			
		||||
                field.move(fromIndex, toIndex);
 | 
			
		||||
                onRowDragEnd({ fromIndex, toIndex, from, to });
 | 
			
		||||
              }}
 | 
			
		||||
            >
 | 
			
		||||
              <tbody {...props} />
 | 
			
		||||
            </DndContext>
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        row: (props) => {
 | 
			
		||||
          return <SortableRow {...props}></SortableRow>;
 | 
			
		||||
        },
 | 
			
		||||
        cell: (props) => (
 | 
			
		||||
          <td
 | 
			
		||||
            {...props}
 | 
			
		||||
            className={classNames(
 | 
			
		||||
              props.className,
 | 
			
		||||
              css`
 | 
			
		||||
                max-width: 300px;
 | 
			
		||||
                white-space: nowrap;
 | 
			
		||||
                .nb-read-pretty-input-number {
 | 
			
		||||
                  text-align: right;
 | 
			
		||||
                }
 | 
			
		||||
              `,
 | 
			
		||||
            )}
 | 
			
		||||
          />
 | 
			
		||||
        ),
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
  }, [field, onRowDragEnd, dragSort]);
 | 
			
		||||
 | 
			
		||||
    const getRowKey = (record: any) => {
 | 
			
		||||
      if (typeof rowKey === 'string') {
 | 
			
		||||
        return record[rowKey]?.toString();
 | 
			
		||||
      } else {
 | 
			
		||||
        return (rowKey ?? defaultRowKey)(record)?.toString();
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
  const defaultRowKey = (record: any) => {
 | 
			
		||||
    return field.value?.indexOf?.(record);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
    const restProps = {
 | 
			
		||||
      rowSelection: rowSelection
 | 
			
		||||
        ? {
 | 
			
		||||
  const getRowKey = (record: any) => {
 | 
			
		||||
    if (typeof rowKey === 'string') {
 | 
			
		||||
      return record[rowKey]?.toString();
 | 
			
		||||
    } else {
 | 
			
		||||
      return (rowKey ?? defaultRowKey)(record)?.toString();
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const restProps = {
 | 
			
		||||
    rowSelection: rowSelection
 | 
			
		||||
      ? {
 | 
			
		||||
          type: 'checkbox',
 | 
			
		||||
          selectedRowKeys: selectedRowKeys,
 | 
			
		||||
          onChange(selectedRowKeys: any[], selectedRows: any[]) {
 | 
			
		||||
@ -349,20 +380,23 @@ export const Table: any = observer(
 | 
			
		||||
                className={classNames(
 | 
			
		||||
                  checked ? 'checked' : null,
 | 
			
		||||
                  css`
 | 
			
		||||
                      position: relative;
 | 
			
		||||
                      display: flex;
 | 
			
		||||
                      float: left;
 | 
			
		||||
                      align-items: center;
 | 
			
		||||
                      justify-content: space-evenly;
 | 
			
		||||
                      padding-right: 8px;
 | 
			
		||||
                    position: relative;
 | 
			
		||||
                    display: flex;
 | 
			
		||||
                    float: left;
 | 
			
		||||
                    align-items: center;
 | 
			
		||||
                    justify-content: space-evenly;
 | 
			
		||||
                    padding-right: 8px;
 | 
			
		||||
                    .nb-table-index {
 | 
			
		||||
                      opacity: 0;
 | 
			
		||||
                    }
 | 
			
		||||
                    &:not(.checked) {
 | 
			
		||||
                      .nb-table-index {
 | 
			
		||||
                        opacity: 0;
 | 
			
		||||
                      }
 | 
			
		||||
                      &:not(.checked) {
 | 
			
		||||
                        .nb-table-index {
 | 
			
		||||
                          opacity: 1;
 | 
			
		||||
                        }
 | 
			
		||||
                        opacity: 1;
 | 
			
		||||
                      }
 | 
			
		||||
                    }
 | 
			
		||||
                  `,
 | 
			
		||||
                  {
 | 
			
		||||
                    [css`
 | 
			
		||||
                      &:hover {
 | 
			
		||||
                        .nb-table-index {
 | 
			
		||||
                          opacity: 0;
 | 
			
		||||
@ -371,28 +405,30 @@ export const Table: any = observer(
 | 
			
		||||
                          display: block;
 | 
			
		||||
                        }
 | 
			
		||||
                      }
 | 
			
		||||
                    `,
 | 
			
		||||
                    `]: isRowSelect,
 | 
			
		||||
                  },
 | 
			
		||||
                )}
 | 
			
		||||
              >
 | 
			
		||||
                <div
 | 
			
		||||
                  className={classNames(
 | 
			
		||||
                    checked ? 'checked' : null,
 | 
			
		||||
                    css`
 | 
			
		||||
                        position: relative;
 | 
			
		||||
                        display: flex;
 | 
			
		||||
                        align-items: center;
 | 
			
		||||
                        justify-content: space-evenly;
 | 
			
		||||
                      `,
 | 
			
		||||
                      position: relative;
 | 
			
		||||
                      display: flex;
 | 
			
		||||
                      align-items: center;
 | 
			
		||||
                      justify-content: space-evenly;
 | 
			
		||||
                    `,
 | 
			
		||||
                  )}
 | 
			
		||||
                >
 | 
			
		||||
                  {dragSort && <SortHandle id={getRowKey(record)} />}
 | 
			
		||||
                  {showIndex && <TableIndex index={index} />}
 | 
			
		||||
                </div>
 | 
			
		||||
                <div
 | 
			
		||||
                  className={classNames(
 | 
			
		||||
                    'nb-origin-node',
 | 
			
		||||
                    checked ? 'checked' : null,
 | 
			
		||||
                    css`
 | 
			
		||||
                {isRowSelect && (
 | 
			
		||||
                  <div
 | 
			
		||||
                    className={classNames(
 | 
			
		||||
                      'nb-origin-node',
 | 
			
		||||
                      checked ? 'checked' : null,
 | 
			
		||||
                      css`
 | 
			
		||||
                        position: absolute;
 | 
			
		||||
                        right: 50%;
 | 
			
		||||
                        transform: translateX(50%);
 | 
			
		||||
@ -400,105 +436,101 @@ export const Table: any = observer(
 | 
			
		||||
                          display: none;
 | 
			
		||||
                        }
 | 
			
		||||
                      `,
 | 
			
		||||
                  )}
 | 
			
		||||
                >
 | 
			
		||||
                  {originNode}
 | 
			
		||||
                </div>
 | 
			
		||||
                    )}
 | 
			
		||||
                  >
 | 
			
		||||
                    {originNode}
 | 
			
		||||
                  </div>
 | 
			
		||||
                )}
 | 
			
		||||
              </div>
 | 
			
		||||
            );
 | 
			
		||||
          },
 | 
			
		||||
          ...rowSelection,
 | 
			
		||||
        }
 | 
			
		||||
        : undefined,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const SortableWrapper = useCallback<React.FC>(
 | 
			
		||||
      ({ children }) => {
 | 
			
		||||
        return dragSort
 | 
			
		||||
          ? React.createElement(SortableContext, {
 | 
			
		||||
            items: field.value.map(getRowKey),
 | 
			
		||||
      : undefined,
 | 
			
		||||
  };
 | 
			
		||||
  const SortableWrapper = useCallback<React.FC>(
 | 
			
		||||
    ({ children }) => {
 | 
			
		||||
      return dragSort
 | 
			
		||||
        ? React.createElement(SortableContext, {
 | 
			
		||||
            items: field.value?.map?.(getRowKey) || [],
 | 
			
		||||
            children: children,
 | 
			
		||||
          })
 | 
			
		||||
          : React.createElement(React.Fragment, {
 | 
			
		||||
        : React.createElement(React.Fragment, {
 | 
			
		||||
            children,
 | 
			
		||||
          });
 | 
			
		||||
      },
 | 
			
		||||
      [field, dragSort],
 | 
			
		||||
    );
 | 
			
		||||
    const fieldSchema = useFieldSchema();
 | 
			
		||||
    const fixedBlock = fieldSchema?.parent?.['x-decorator-props']?.fixedBlock;
 | 
			
		||||
    },
 | 
			
		||||
    [field, dragSort],
 | 
			
		||||
  );
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const fixedBlock = fieldSchema?.parent?.['x-decorator-props']?.fixedBlock;
 | 
			
		||||
 | 
			
		||||
    const { height: tableHeight, tableSizeRefCallback } = useTableSize();
 | 
			
		||||
 | 
			
		||||
    const scroll = useMemo(() => {
 | 
			
		||||
      return fixedBlock
 | 
			
		||||
        ? {
 | 
			
		||||
  const { height: tableHeight, tableSizeRefCallback } = useTableSize();
 | 
			
		||||
  const scroll = useMemo(() => {
 | 
			
		||||
    return fixedBlock
 | 
			
		||||
      ? {
 | 
			
		||||
          x: 'max-content',
 | 
			
		||||
          y: tableHeight,
 | 
			
		||||
        }
 | 
			
		||||
        : {
 | 
			
		||||
      : {
 | 
			
		||||
          x: 'max-content',
 | 
			
		||||
        };
 | 
			
		||||
    }, [fixedBlock, tableHeight]);
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <div
 | 
			
		||||
        className={css`
 | 
			
		||||
  }, [fixedBlock, tableHeight]);
 | 
			
		||||
  return (
 | 
			
		||||
    <div
 | 
			
		||||
      className={css`
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        overflow: hidden;
 | 
			
		||||
        .ant-table-wrapper {
 | 
			
		||||
          height: 100%;
 | 
			
		||||
          overflow: hidden;
 | 
			
		||||
          .ant-table-wrapper {
 | 
			
		||||
          .ant-spin-nested-loading {
 | 
			
		||||
            height: 100%;
 | 
			
		||||
            .ant-spin-nested-loading {
 | 
			
		||||
            .ant-spin-container {
 | 
			
		||||
              height: 100%;
 | 
			
		||||
              .ant-spin-container {
 | 
			
		||||
                height: 100%;
 | 
			
		||||
                display: flex;
 | 
			
		||||
                flex-direction: column;
 | 
			
		||||
              }
 | 
			
		||||
              display: flex;
 | 
			
		||||
              flex-direction: column;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          .ant-table {
 | 
			
		||||
            overflow-x: auto;
 | 
			
		||||
            overflow-y: hidden;
 | 
			
		||||
          }
 | 
			
		||||
        `}
 | 
			
		||||
      >
 | 
			
		||||
        <SortableWrapper>
 | 
			
		||||
          <AntdTable
 | 
			
		||||
            ref={tableSizeRefCallback}
 | 
			
		||||
            rowKey={rowKey ?? defaultRowKey}
 | 
			
		||||
            dataSource={field?.value?.slice?.()}
 | 
			
		||||
            {...others}
 | 
			
		||||
            {...restProps}
 | 
			
		||||
            pagination={paginationProps}
 | 
			
		||||
            components={components}
 | 
			
		||||
            onChange={(pagination, filters, sorter, extra) => {
 | 
			
		||||
              onTableChange?.(pagination, filters, sorter, extra);
 | 
			
		||||
            }}
 | 
			
		||||
            onRow={onRow}
 | 
			
		||||
            rowClassName={(record) => (selectedRow.includes(record[rowKey]) ? highlightRow : '')}
 | 
			
		||||
            tableLayout={'auto'}
 | 
			
		||||
            scroll={scroll}
 | 
			
		||||
            columns={columns}
 | 
			
		||||
            expandable={{
 | 
			
		||||
              onExpand: (flag, record) => {
 | 
			
		||||
                const newKeys = flag ? [...expandedKeys, record.id] : expandedKeys.filter((i) => record.id !== i);
 | 
			
		||||
                setExpandesKeys(newKeys);
 | 
			
		||||
                onExpand?.(flag, record);
 | 
			
		||||
              },
 | 
			
		||||
              expandedRowKeys: expandedKeys,
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
        </SortableWrapper>
 | 
			
		||||
        {field.errors.length > 0 && (
 | 
			
		||||
          <div className="ant-formily-item-error-help ant-formily-item-help ant-formily-item-help-enter ant-formily-item-help-enter-active">
 | 
			
		||||
            {field.errors.map((error) => {
 | 
			
		||||
              return error.messages.map((message) => <div>{message}</div>);
 | 
			
		||||
            })}
 | 
			
		||||
          </div>
 | 
			
		||||
        )}
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
  },
 | 
			
		||||
  { displayName: 'Table' },
 | 
			
		||||
);
 | 
			
		||||
        }
 | 
			
		||||
        .ant-table {
 | 
			
		||||
          overflow-x: auto;
 | 
			
		||||
          overflow-y: hidden;
 | 
			
		||||
        }
 | 
			
		||||
      `}
 | 
			
		||||
    >
 | 
			
		||||
      <SortableWrapper>
 | 
			
		||||
        <AntdTable
 | 
			
		||||
          ref={tableSizeRefCallback}
 | 
			
		||||
          rowKey={rowKey ?? defaultRowKey}
 | 
			
		||||
          dataSource={dataSource}
 | 
			
		||||
          {...others}
 | 
			
		||||
          {...restProps}
 | 
			
		||||
          pagination={paginationProps}
 | 
			
		||||
          components={components}
 | 
			
		||||
          onChange={(pagination, filters, sorter, extra) => {
 | 
			
		||||
            onTableChange?.(pagination, filters, sorter, extra);
 | 
			
		||||
          }}
 | 
			
		||||
          onRow={onRow}
 | 
			
		||||
          rowClassName={(record) => (selectedRow.includes(record[rowKey]) ? highlightRow : '')}
 | 
			
		||||
          tableLayout={'auto'}
 | 
			
		||||
          scroll={scroll}
 | 
			
		||||
          columns={columns}
 | 
			
		||||
          expandable={{
 | 
			
		||||
            onExpand: (flag, record) => {
 | 
			
		||||
              const newKeys = flag ? [...expandedKeys, record.id] : expandedKeys.filter((i) => record.id !== i);
 | 
			
		||||
              setExpandesKeys(newKeys);
 | 
			
		||||
              onExpand?.(flag, record);
 | 
			
		||||
            },
 | 
			
		||||
            expandedRowKeys: expandedKeys,
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
      </SortableWrapper>
 | 
			
		||||
      {field.errors.length > 0 && (
 | 
			
		||||
        <div className="ant-formily-item-error-help ant-formily-item-help ant-formily-item-help-enter ant-formily-item-help-enter-active">
 | 
			
		||||
          {field.errors.map((error) => {
 | 
			
		||||
            return error.messages.map((message) => <div>{message}</div>);
 | 
			
		||||
          })}
 | 
			
		||||
        </div>
 | 
			
		||||
      )}
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -1,802 +0,0 @@
 | 
			
		||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 | 
			
		||||
 | 
			
		||||
exports[`TableV2 > basic 1`] = `
 | 
			
		||||
<div>
 | 
			
		||||
  <div>
 | 
			
		||||
    <div
 | 
			
		||||
      class="nb-fixed-block"
 | 
			
		||||
    >
 | 
			
		||||
      <button
 | 
			
		||||
        class="ant-btn ant-btn-default css-49hvkh"
 | 
			
		||||
        type="button"
 | 
			
		||||
      >
 | 
			
		||||
        <span>
 | 
			
		||||
          刷新
 | 
			
		||||
        </span>
 | 
			
		||||
      </button>
 | 
			
		||||
      <div
 | 
			
		||||
        class="css-1s4dz4u"
 | 
			
		||||
      >
 | 
			
		||||
        <div
 | 
			
		||||
          class="ant-table-wrapper"
 | 
			
		||||
        >
 | 
			
		||||
          <div
 | 
			
		||||
            class="ant-spin-nested-loading"
 | 
			
		||||
          >
 | 
			
		||||
            <div
 | 
			
		||||
              class="ant-spin-container"
 | 
			
		||||
            >
 | 
			
		||||
              <div
 | 
			
		||||
                class="ant-table ant-table-scroll-horizontal"
 | 
			
		||||
              >
 | 
			
		||||
                <div
 | 
			
		||||
                  class="ant-table-container"
 | 
			
		||||
                >
 | 
			
		||||
                  <div
 | 
			
		||||
                    class="ant-table-content"
 | 
			
		||||
                    style="overflow-x: auto; overflow-y: hidden;"
 | 
			
		||||
                  >
 | 
			
		||||
                    <table
 | 
			
		||||
                      style="min-width: 100%; table-layout: auto;"
 | 
			
		||||
                    >
 | 
			
		||||
                      <colgroup>
 | 
			
		||||
                        <col
 | 
			
		||||
                          class="ant-table-selection-col"
 | 
			
		||||
                        />
 | 
			
		||||
                        <col
 | 
			
		||||
                          style="width: 200px;"
 | 
			
		||||
                        />
 | 
			
		||||
                        <col
 | 
			
		||||
                          style="width: 200px;"
 | 
			
		||||
                        />
 | 
			
		||||
                      </colgroup>
 | 
			
		||||
                      <thead
 | 
			
		||||
                        class="ant-table-thead"
 | 
			
		||||
                      >
 | 
			
		||||
                        <tr>
 | 
			
		||||
                          <th
 | 
			
		||||
                            class="ant-table-cell ant-table-selection-column css-p6py3w"
 | 
			
		||||
                          >
 | 
			
		||||
                            <div
 | 
			
		||||
                              class="ant-table-selection"
 | 
			
		||||
                            >
 | 
			
		||||
                              <label
 | 
			
		||||
                                class="ant-checkbox-wrapper"
 | 
			
		||||
                              >
 | 
			
		||||
                                <span
 | 
			
		||||
                                  class="ant-checkbox"
 | 
			
		||||
                                >
 | 
			
		||||
                                  <input
 | 
			
		||||
                                    aria-label="Select all"
 | 
			
		||||
                                    class="ant-checkbox-input"
 | 
			
		||||
                                    type="checkbox"
 | 
			
		||||
                                    value=""
 | 
			
		||||
                                  />
 | 
			
		||||
                                  <span
 | 
			
		||||
                                    class="ant-checkbox-inner"
 | 
			
		||||
                                  />
 | 
			
		||||
                                </span>
 | 
			
		||||
                              </label>
 | 
			
		||||
                            </div>
 | 
			
		||||
                          </th>
 | 
			
		||||
                          <th
 | 
			
		||||
                            class="ant-table-cell css-p6py3w"
 | 
			
		||||
                          >
 | 
			
		||||
                            <div>
 | 
			
		||||
                              Name
 | 
			
		||||
                            </div>
 | 
			
		||||
                          </th>
 | 
			
		||||
                          <th
 | 
			
		||||
                            class="ant-table-cell css-p6py3w"
 | 
			
		||||
                          >
 | 
			
		||||
                            <div>
 | 
			
		||||
                              Actions
 | 
			
		||||
                            </div>
 | 
			
		||||
                          </th>
 | 
			
		||||
                        </tr>
 | 
			
		||||
                      </thead>
 | 
			
		||||
                      <tbody
 | 
			
		||||
                        class="ant-table-tbody"
 | 
			
		||||
                      >
 | 
			
		||||
                        <tr
 | 
			
		||||
                          aria-hidden="true"
 | 
			
		||||
                          class="ant-table-measure-row"
 | 
			
		||||
                          style="height: 0px; font-size: 0px;"
 | 
			
		||||
                        >
 | 
			
		||||
                          <td
 | 
			
		||||
                            style="padding: 0px; border: 0px; height: 0px;"
 | 
			
		||||
                          >
 | 
			
		||||
                            <div
 | 
			
		||||
                              style="height: 0px; overflow: hidden;"
 | 
			
		||||
                            >
 | 
			
		||||
                               
 | 
			
		||||
                            </div>
 | 
			
		||||
                          </td>
 | 
			
		||||
                          <td
 | 
			
		||||
                            style="padding: 0px; border: 0px; height: 0px;"
 | 
			
		||||
                          >
 | 
			
		||||
                            <div
 | 
			
		||||
                              style="height: 0px; overflow: hidden;"
 | 
			
		||||
                            >
 | 
			
		||||
                               
 | 
			
		||||
                            </div>
 | 
			
		||||
                          </td>
 | 
			
		||||
                          <td
 | 
			
		||||
                            style="padding: 0px; border: 0px; height: 0px;"
 | 
			
		||||
                          >
 | 
			
		||||
                            <div
 | 
			
		||||
                              style="height: 0px; overflow: hidden;"
 | 
			
		||||
                            >
 | 
			
		||||
                               
 | 
			
		||||
                            </div>
 | 
			
		||||
                          </td>
 | 
			
		||||
                        </tr>
 | 
			
		||||
                        <tr
 | 
			
		||||
                          class="ant-table-row ant-table-row-level-0"
 | 
			
		||||
                          data-row-key="1"
 | 
			
		||||
                        >
 | 
			
		||||
                          <td
 | 
			
		||||
                            class="ant-table-cell ant-table-selection-column css-1omg1s0"
 | 
			
		||||
                          >
 | 
			
		||||
                            <div
 | 
			
		||||
                              class="css-xl522n"
 | 
			
		||||
                            >
 | 
			
		||||
                              <div
 | 
			
		||||
                                class="css-2mnx34"
 | 
			
		||||
                              >
 | 
			
		||||
                                <div
 | 
			
		||||
                                  class="nb-table-index"
 | 
			
		||||
                                  style="padding: 0px 8px 0px 16px;"
 | 
			
		||||
                                >
 | 
			
		||||
                                  1
 | 
			
		||||
                                </div>
 | 
			
		||||
                              </div>
 | 
			
		||||
                              <div
 | 
			
		||||
                                class="nb-origin-node css-cdm7wh"
 | 
			
		||||
                              >
 | 
			
		||||
                                <label
 | 
			
		||||
                                  class="ant-checkbox-wrapper"
 | 
			
		||||
                                >
 | 
			
		||||
                                  <span
 | 
			
		||||
                                    class="ant-checkbox"
 | 
			
		||||
                                  >
 | 
			
		||||
                                    <input
 | 
			
		||||
                                      class="ant-checkbox-input"
 | 
			
		||||
                                      type="checkbox"
 | 
			
		||||
                                      value=""
 | 
			
		||||
                                    />
 | 
			
		||||
                                    <span
 | 
			
		||||
                                      class="ant-checkbox-inner"
 | 
			
		||||
                                    />
 | 
			
		||||
                                  </span>
 | 
			
		||||
                                </label>
 | 
			
		||||
                              </div>
 | 
			
		||||
                            </div>
 | 
			
		||||
                          </td>
 | 
			
		||||
                          <td
 | 
			
		||||
                            class="ant-table-cell css-1omg1s0"
 | 
			
		||||
                          >
 | 
			
		||||
                            <div
 | 
			
		||||
                              class="ant-description-input"
 | 
			
		||||
                            >
 | 
			
		||||
                              name1
 | 
			
		||||
                            </div>
 | 
			
		||||
                          </td>
 | 
			
		||||
                          <td
 | 
			
		||||
                            class="ant-table-cell css-1omg1s0"
 | 
			
		||||
                          >
 | 
			
		||||
                            <button
 | 
			
		||||
                              class="ant-btn ant-btn-default css-49hvkh"
 | 
			
		||||
                              type="button"
 | 
			
		||||
                            >
 | 
			
		||||
                              <span>
 | 
			
		||||
                                View
 | 
			
		||||
                              </span>
 | 
			
		||||
                            </button>
 | 
			
		||||
                          </td>
 | 
			
		||||
                        </tr>
 | 
			
		||||
                        <tr
 | 
			
		||||
                          class="ant-table-row ant-table-row-level-0"
 | 
			
		||||
                          data-row-key="2"
 | 
			
		||||
                        >
 | 
			
		||||
                          <td
 | 
			
		||||
                            class="ant-table-cell ant-table-selection-column css-1omg1s0"
 | 
			
		||||
                          >
 | 
			
		||||
                            <div
 | 
			
		||||
                              class="css-xl522n"
 | 
			
		||||
                            >
 | 
			
		||||
                              <div
 | 
			
		||||
                                class="css-2mnx34"
 | 
			
		||||
                              >
 | 
			
		||||
                                <div
 | 
			
		||||
                                  class="nb-table-index"
 | 
			
		||||
                                  style="padding: 0px 8px 0px 16px;"
 | 
			
		||||
                                >
 | 
			
		||||
                                  2
 | 
			
		||||
                                </div>
 | 
			
		||||
                              </div>
 | 
			
		||||
                              <div
 | 
			
		||||
                                class="nb-origin-node css-cdm7wh"
 | 
			
		||||
                              >
 | 
			
		||||
                                <label
 | 
			
		||||
                                  class="ant-checkbox-wrapper"
 | 
			
		||||
                                >
 | 
			
		||||
                                  <span
 | 
			
		||||
                                    class="ant-checkbox"
 | 
			
		||||
                                  >
 | 
			
		||||
                                    <input
 | 
			
		||||
                                      class="ant-checkbox-input"
 | 
			
		||||
                                      type="checkbox"
 | 
			
		||||
                                      value=""
 | 
			
		||||
                                    />
 | 
			
		||||
                                    <span
 | 
			
		||||
                                      class="ant-checkbox-inner"
 | 
			
		||||
                                    />
 | 
			
		||||
                                  </span>
 | 
			
		||||
                                </label>
 | 
			
		||||
                              </div>
 | 
			
		||||
                            </div>
 | 
			
		||||
                          </td>
 | 
			
		||||
                          <td
 | 
			
		||||
                            class="ant-table-cell css-1omg1s0"
 | 
			
		||||
                          >
 | 
			
		||||
                            <div
 | 
			
		||||
                              class="ant-description-input"
 | 
			
		||||
                            >
 | 
			
		||||
                              name2
 | 
			
		||||
                            </div>
 | 
			
		||||
                          </td>
 | 
			
		||||
                          <td
 | 
			
		||||
                            class="ant-table-cell css-1omg1s0"
 | 
			
		||||
                          >
 | 
			
		||||
                            <button
 | 
			
		||||
                              class="ant-btn ant-btn-default css-49hvkh"
 | 
			
		||||
                              type="button"
 | 
			
		||||
                            >
 | 
			
		||||
                              <span>
 | 
			
		||||
                                View
 | 
			
		||||
                              </span>
 | 
			
		||||
                            </button>
 | 
			
		||||
                          </td>
 | 
			
		||||
                        </tr>
 | 
			
		||||
                      </tbody>
 | 
			
		||||
                    </table>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
              <ul
 | 
			
		||||
                class="ant-pagination ant-table-pagination ant-table-pagination-right"
 | 
			
		||||
              >
 | 
			
		||||
                <li
 | 
			
		||||
                  class="ant-pagination-total-text"
 | 
			
		||||
                >
 | 
			
		||||
                  Total 100 items
 | 
			
		||||
                </li>
 | 
			
		||||
                <li
 | 
			
		||||
                  aria-disabled="true"
 | 
			
		||||
                  class="ant-pagination-prev ant-pagination-disabled"
 | 
			
		||||
                  title="Previous Page"
 | 
			
		||||
                >
 | 
			
		||||
                  <button
 | 
			
		||||
                    class="ant-pagination-item-link"
 | 
			
		||||
                    disabled=""
 | 
			
		||||
                    tabindex="-1"
 | 
			
		||||
                    type="button"
 | 
			
		||||
                  >
 | 
			
		||||
                    <span
 | 
			
		||||
                      aria-label="left"
 | 
			
		||||
                      class="anticon anticon-left"
 | 
			
		||||
                      role="img"
 | 
			
		||||
                    >
 | 
			
		||||
                      <svg
 | 
			
		||||
                        aria-hidden="true"
 | 
			
		||||
                        data-icon="left"
 | 
			
		||||
                        fill="currentColor"
 | 
			
		||||
                        focusable="false"
 | 
			
		||||
                        height="1em"
 | 
			
		||||
                        viewBox="64 64 896 896"
 | 
			
		||||
                        width="1em"
 | 
			
		||||
                      >
 | 
			
		||||
                        <path
 | 
			
		||||
                          d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"
 | 
			
		||||
                        />
 | 
			
		||||
                      </svg>
 | 
			
		||||
                    </span>
 | 
			
		||||
                  </button>
 | 
			
		||||
                </li>
 | 
			
		||||
                <li
 | 
			
		||||
                  class="ant-pagination-item ant-pagination-item-1 ant-pagination-item-active"
 | 
			
		||||
                  tabindex="0"
 | 
			
		||||
                  title="1"
 | 
			
		||||
                >
 | 
			
		||||
                  <a
 | 
			
		||||
                    rel="nofollow"
 | 
			
		||||
                  >
 | 
			
		||||
                    1
 | 
			
		||||
                  </a>
 | 
			
		||||
                </li>
 | 
			
		||||
                <li
 | 
			
		||||
                  class="ant-pagination-item ant-pagination-item-2"
 | 
			
		||||
                  tabindex="0"
 | 
			
		||||
                  title="2"
 | 
			
		||||
                >
 | 
			
		||||
                  <a
 | 
			
		||||
                    rel="nofollow"
 | 
			
		||||
                  >
 | 
			
		||||
                    2
 | 
			
		||||
                  </a>
 | 
			
		||||
                </li>
 | 
			
		||||
                <li
 | 
			
		||||
                  class="ant-pagination-item ant-pagination-item-3"
 | 
			
		||||
                  tabindex="0"
 | 
			
		||||
                  title="3"
 | 
			
		||||
                >
 | 
			
		||||
                  <a
 | 
			
		||||
                    rel="nofollow"
 | 
			
		||||
                  >
 | 
			
		||||
                    3
 | 
			
		||||
                  </a>
 | 
			
		||||
                </li>
 | 
			
		||||
                <li
 | 
			
		||||
                  class="ant-pagination-item ant-pagination-item-4"
 | 
			
		||||
                  tabindex="0"
 | 
			
		||||
                  title="4"
 | 
			
		||||
                >
 | 
			
		||||
                  <a
 | 
			
		||||
                    rel="nofollow"
 | 
			
		||||
                  >
 | 
			
		||||
                    4
 | 
			
		||||
                  </a>
 | 
			
		||||
                </li>
 | 
			
		||||
                <li
 | 
			
		||||
                  class="ant-pagination-item ant-pagination-item-5 ant-pagination-item-before-jump-next"
 | 
			
		||||
                  tabindex="0"
 | 
			
		||||
                  title="5"
 | 
			
		||||
                >
 | 
			
		||||
                  <a
 | 
			
		||||
                    rel="nofollow"
 | 
			
		||||
                  >
 | 
			
		||||
                    5
 | 
			
		||||
                  </a>
 | 
			
		||||
                </li>
 | 
			
		||||
                <li
 | 
			
		||||
                  class="ant-pagination-jump-next ant-pagination-jump-next-custom-icon"
 | 
			
		||||
                  tabindex="0"
 | 
			
		||||
                  title="Next 5 Pages"
 | 
			
		||||
                >
 | 
			
		||||
                  <a
 | 
			
		||||
                    class="ant-pagination-item-link"
 | 
			
		||||
                  >
 | 
			
		||||
                    <div
 | 
			
		||||
                      class="ant-pagination-item-container"
 | 
			
		||||
                    >
 | 
			
		||||
                      <span
 | 
			
		||||
                        aria-label="double-right"
 | 
			
		||||
                        class="anticon anticon-double-right ant-pagination-item-link-icon"
 | 
			
		||||
                        role="img"
 | 
			
		||||
                      >
 | 
			
		||||
                        <svg
 | 
			
		||||
                          aria-hidden="true"
 | 
			
		||||
                          data-icon="double-right"
 | 
			
		||||
                          fill="currentColor"
 | 
			
		||||
                          focusable="false"
 | 
			
		||||
                          height="1em"
 | 
			
		||||
                          viewBox="64 64 896 896"
 | 
			
		||||
                          width="1em"
 | 
			
		||||
                        >
 | 
			
		||||
                          <path
 | 
			
		||||
                            d="M533.2 492.3L277.9 166.1c-3-3.9-7.7-6.1-12.6-6.1H188c-6.7 0-10.4 7.7-6.3 12.9L447.1 512 181.7 851.1A7.98 7.98 0 00188 864h77.3c4.9 0 9.6-2.3 12.6-6.1l255.3-326.1c9.1-11.7 9.1-27.9 0-39.5zm304 0L581.9 166.1c-3-3.9-7.7-6.1-12.6-6.1H492c-6.7 0-10.4 7.7-6.3 12.9L751.1 512 485.7 851.1A7.98 7.98 0 00492 864h77.3c4.9 0 9.6-2.3 12.6-6.1l255.3-326.1c9.1-11.7 9.1-27.9 0-39.5z"
 | 
			
		||||
                          />
 | 
			
		||||
                        </svg>
 | 
			
		||||
                      </span>
 | 
			
		||||
                      <span
 | 
			
		||||
                        class="ant-pagination-item-ellipsis"
 | 
			
		||||
                      >
 | 
			
		||||
                        •••
 | 
			
		||||
                      </span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                  </a>
 | 
			
		||||
                </li>
 | 
			
		||||
                <li
 | 
			
		||||
                  class="ant-pagination-item ant-pagination-item-50"
 | 
			
		||||
                  tabindex="0"
 | 
			
		||||
                  title="50"
 | 
			
		||||
                >
 | 
			
		||||
                  <a
 | 
			
		||||
                    rel="nofollow"
 | 
			
		||||
                  >
 | 
			
		||||
                    50
 | 
			
		||||
                  </a>
 | 
			
		||||
                </li>
 | 
			
		||||
                <li
 | 
			
		||||
                  aria-disabled="false"
 | 
			
		||||
                  class="ant-pagination-next"
 | 
			
		||||
                  tabindex="0"
 | 
			
		||||
                  title="Next Page"
 | 
			
		||||
                >
 | 
			
		||||
                  <button
 | 
			
		||||
                    class="ant-pagination-item-link"
 | 
			
		||||
                    tabindex="-1"
 | 
			
		||||
                    type="button"
 | 
			
		||||
                  >
 | 
			
		||||
                    <span
 | 
			
		||||
                      aria-label="right"
 | 
			
		||||
                      class="anticon anticon-right"
 | 
			
		||||
                      role="img"
 | 
			
		||||
                    >
 | 
			
		||||
                      <svg
 | 
			
		||||
                        aria-hidden="true"
 | 
			
		||||
                        data-icon="right"
 | 
			
		||||
                        fill="currentColor"
 | 
			
		||||
                        focusable="false"
 | 
			
		||||
                        height="1em"
 | 
			
		||||
                        viewBox="64 64 896 896"
 | 
			
		||||
                        width="1em"
 | 
			
		||||
                      >
 | 
			
		||||
                        <path
 | 
			
		||||
                          d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
 | 
			
		||||
                        />
 | 
			
		||||
                      </svg>
 | 
			
		||||
                    </span>
 | 
			
		||||
                  </button>
 | 
			
		||||
                </li>
 | 
			
		||||
                <li
 | 
			
		||||
                  class="ant-pagination-options"
 | 
			
		||||
                >
 | 
			
		||||
                  <div
 | 
			
		||||
                    aria-label="Page Size"
 | 
			
		||||
                    class="ant-select ant-pagination-options-size-changer ant-select-single ant-select-show-arrow"
 | 
			
		||||
                  >
 | 
			
		||||
                    <div
 | 
			
		||||
                      class="ant-select-selector"
 | 
			
		||||
                    >
 | 
			
		||||
                      <span
 | 
			
		||||
                        class="ant-select-selection-search"
 | 
			
		||||
                      >
 | 
			
		||||
                        <input
 | 
			
		||||
                          aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
 | 
			
		||||
                          aria-autocomplete="list"
 | 
			
		||||
                          aria-controls="rc_select_TEST_OR_SSR_list"
 | 
			
		||||
                          aria-expanded="false"
 | 
			
		||||
                          aria-haspopup="listbox"
 | 
			
		||||
                          aria-label="Page Size"
 | 
			
		||||
                          aria-owns="rc_select_TEST_OR_SSR_list"
 | 
			
		||||
                          autocomplete="off"
 | 
			
		||||
                          class="ant-select-selection-search-input"
 | 
			
		||||
                          id="rc_select_TEST_OR_SSR"
 | 
			
		||||
                          readonly=""
 | 
			
		||||
                          role="combobox"
 | 
			
		||||
                          style="opacity: 0;"
 | 
			
		||||
                          type="search"
 | 
			
		||||
                          unselectable="on"
 | 
			
		||||
                          value=""
 | 
			
		||||
                        />
 | 
			
		||||
                      </span>
 | 
			
		||||
                      <span
 | 
			
		||||
                        class="ant-select-selection-item"
 | 
			
		||||
                        title="2 / page"
 | 
			
		||||
                      >
 | 
			
		||||
                        2 / page
 | 
			
		||||
                      </span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <span
 | 
			
		||||
                      aria-hidden="true"
 | 
			
		||||
                      class="ant-select-arrow"
 | 
			
		||||
                      style="user-select: none;"
 | 
			
		||||
                      unselectable="on"
 | 
			
		||||
                    >
 | 
			
		||||
                      <span
 | 
			
		||||
                        aria-label="down"
 | 
			
		||||
                        class="anticon anticon-down ant-select-suffix"
 | 
			
		||||
                        role="img"
 | 
			
		||||
                      >
 | 
			
		||||
                        <svg
 | 
			
		||||
                          aria-hidden="true"
 | 
			
		||||
                          data-icon="down"
 | 
			
		||||
                          fill="currentColor"
 | 
			
		||||
                          focusable="false"
 | 
			
		||||
                          height="1em"
 | 
			
		||||
                          viewBox="64 64 896 896"
 | 
			
		||||
                          width="1em"
 | 
			
		||||
                        >
 | 
			
		||||
                          <path
 | 
			
		||||
                            d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
 | 
			
		||||
                          />
 | 
			
		||||
                        </svg>
 | 
			
		||||
                      </span>
 | 
			
		||||
                    </span>
 | 
			
		||||
                  </div>
 | 
			
		||||
                </li>
 | 
			
		||||
              </ul>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
exports[`TableV2 > tree table 1`] = `
 | 
			
		||||
<div>
 | 
			
		||||
  <div
 | 
			
		||||
    class="ant-table-wrapper"
 | 
			
		||||
  >
 | 
			
		||||
    <div
 | 
			
		||||
      class="ant-spin-nested-loading"
 | 
			
		||||
    >
 | 
			
		||||
      <div
 | 
			
		||||
        class="ant-spin-container"
 | 
			
		||||
      >
 | 
			
		||||
        <div
 | 
			
		||||
          class="ant-table"
 | 
			
		||||
        >
 | 
			
		||||
          <div
 | 
			
		||||
            class="ant-table-container"
 | 
			
		||||
          >
 | 
			
		||||
            <div
 | 
			
		||||
              class="ant-table-content"
 | 
			
		||||
            >
 | 
			
		||||
              <table
 | 
			
		||||
                style="table-layout: auto;"
 | 
			
		||||
              >
 | 
			
		||||
                <colgroup>
 | 
			
		||||
                  <col
 | 
			
		||||
                    class="ant-table-selection-col"
 | 
			
		||||
                  />
 | 
			
		||||
                </colgroup>
 | 
			
		||||
                <thead
 | 
			
		||||
                  class="ant-table-thead"
 | 
			
		||||
                >
 | 
			
		||||
                  <tr>
 | 
			
		||||
                    <th
 | 
			
		||||
                      class="ant-table-cell ant-table-selection-column"
 | 
			
		||||
                    >
 | 
			
		||||
                      <div
 | 
			
		||||
                        class="ant-table-selection"
 | 
			
		||||
                      >
 | 
			
		||||
                        <label
 | 
			
		||||
                          class="ant-checkbox-wrapper"
 | 
			
		||||
                        >
 | 
			
		||||
                          <span
 | 
			
		||||
                            class="ant-checkbox"
 | 
			
		||||
                          >
 | 
			
		||||
                            <input
 | 
			
		||||
                              aria-label="Select all"
 | 
			
		||||
                              class="ant-checkbox-input"
 | 
			
		||||
                              type="checkbox"
 | 
			
		||||
                              value=""
 | 
			
		||||
                            />
 | 
			
		||||
                            <span
 | 
			
		||||
                              class="ant-checkbox-inner"
 | 
			
		||||
                            />
 | 
			
		||||
                          </span>
 | 
			
		||||
                        </label>
 | 
			
		||||
                      </div>
 | 
			
		||||
                    </th>
 | 
			
		||||
                    <th
 | 
			
		||||
                      class="ant-table-cell"
 | 
			
		||||
                    />
 | 
			
		||||
                  </tr>
 | 
			
		||||
                </thead>
 | 
			
		||||
                <tbody
 | 
			
		||||
                  class="ant-table-tbody"
 | 
			
		||||
                >
 | 
			
		||||
                  <tr
 | 
			
		||||
                    class="ant-table-row ant-table-row-level-0"
 | 
			
		||||
                    data-row-key="1"
 | 
			
		||||
                  >
 | 
			
		||||
                    <td
 | 
			
		||||
                      class="ant-table-cell ant-table-selection-column"
 | 
			
		||||
                    >
 | 
			
		||||
                      <label
 | 
			
		||||
                        class="ant-checkbox-wrapper"
 | 
			
		||||
                      >
 | 
			
		||||
                        <span
 | 
			
		||||
                          class="ant-checkbox"
 | 
			
		||||
                        >
 | 
			
		||||
                          <input
 | 
			
		||||
                            class="ant-checkbox-input"
 | 
			
		||||
                            type="checkbox"
 | 
			
		||||
                            value=""
 | 
			
		||||
                          />
 | 
			
		||||
                          <span
 | 
			
		||||
                            class="ant-checkbox-inner"
 | 
			
		||||
                          />
 | 
			
		||||
                        </span>
 | 
			
		||||
                      </label>
 | 
			
		||||
                    </td>
 | 
			
		||||
                    <td
 | 
			
		||||
                      class="ant-table-cell ant-table-cell-with-append"
 | 
			
		||||
                    >
 | 
			
		||||
                      <span
 | 
			
		||||
                        class="ant-table-row-indent indent-level-0"
 | 
			
		||||
                        style="padding-left: 0px;"
 | 
			
		||||
                      />
 | 
			
		||||
                      <button
 | 
			
		||||
                        aria-expanded="false"
 | 
			
		||||
                        aria-label="Expand row"
 | 
			
		||||
                        class="ant-table-row-expand-icon ant-table-row-expand-icon-spaced"
 | 
			
		||||
                        type="button"
 | 
			
		||||
                      />
 | 
			
		||||
                      <li>
 | 
			
		||||
                        value: 
 | 
			
		||||
                        t1
 | 
			
		||||
                      </li>
 | 
			
		||||
                    </td>
 | 
			
		||||
                  </tr>
 | 
			
		||||
                  <tr
 | 
			
		||||
                    class="ant-table-row ant-table-row-level-0"
 | 
			
		||||
                    data-row-key="2"
 | 
			
		||||
                  >
 | 
			
		||||
                    <td
 | 
			
		||||
                      class="ant-table-cell ant-table-selection-column"
 | 
			
		||||
                    >
 | 
			
		||||
                      <label
 | 
			
		||||
                        class="ant-checkbox-wrapper"
 | 
			
		||||
                      >
 | 
			
		||||
                        <span
 | 
			
		||||
                          class="ant-checkbox"
 | 
			
		||||
                        >
 | 
			
		||||
                          <input
 | 
			
		||||
                            class="ant-checkbox-input"
 | 
			
		||||
                            type="checkbox"
 | 
			
		||||
                            value=""
 | 
			
		||||
                          />
 | 
			
		||||
                          <span
 | 
			
		||||
                            class="ant-checkbox-inner"
 | 
			
		||||
                          />
 | 
			
		||||
                        </span>
 | 
			
		||||
                      </label>
 | 
			
		||||
                    </td>
 | 
			
		||||
                    <td
 | 
			
		||||
                      class="ant-table-cell ant-table-cell-with-append"
 | 
			
		||||
                    >
 | 
			
		||||
                      <span
 | 
			
		||||
                        class="ant-table-row-indent indent-level-0"
 | 
			
		||||
                        style="padding-left: 0px;"
 | 
			
		||||
                      />
 | 
			
		||||
                      <button
 | 
			
		||||
                        aria-expanded="false"
 | 
			
		||||
                        aria-label="Expand row"
 | 
			
		||||
                        class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
 | 
			
		||||
                        type="button"
 | 
			
		||||
                      />
 | 
			
		||||
                      <li>
 | 
			
		||||
                        value: 
 | 
			
		||||
                        t2
 | 
			
		||||
                      </li>
 | 
			
		||||
                    </td>
 | 
			
		||||
                  </tr>
 | 
			
		||||
                  <tr
 | 
			
		||||
                    class="ant-table-row ant-table-row-level-0"
 | 
			
		||||
                    data-row-key="3"
 | 
			
		||||
                  >
 | 
			
		||||
                    <td
 | 
			
		||||
                      class="ant-table-cell ant-table-selection-column"
 | 
			
		||||
                    >
 | 
			
		||||
                      <label
 | 
			
		||||
                        class="ant-checkbox-wrapper"
 | 
			
		||||
                      >
 | 
			
		||||
                        <span
 | 
			
		||||
                          class="ant-checkbox"
 | 
			
		||||
                        >
 | 
			
		||||
                          <input
 | 
			
		||||
                            class="ant-checkbox-input"
 | 
			
		||||
                            type="checkbox"
 | 
			
		||||
                            value=""
 | 
			
		||||
                          />
 | 
			
		||||
                          <span
 | 
			
		||||
                            class="ant-checkbox-inner"
 | 
			
		||||
                          />
 | 
			
		||||
                        </span>
 | 
			
		||||
                      </label>
 | 
			
		||||
                    </td>
 | 
			
		||||
                    <td
 | 
			
		||||
                      class="ant-table-cell ant-table-cell-with-append"
 | 
			
		||||
                    >
 | 
			
		||||
                      <span
 | 
			
		||||
                        class="ant-table-row-indent indent-level-0"
 | 
			
		||||
                        style="padding-left: 0px;"
 | 
			
		||||
                      />
 | 
			
		||||
                      <button
 | 
			
		||||
                        aria-expanded="false"
 | 
			
		||||
                        aria-label="Expand row"
 | 
			
		||||
                        class="ant-table-row-expand-icon ant-table-row-expand-icon-collapsed"
 | 
			
		||||
                        type="button"
 | 
			
		||||
                      />
 | 
			
		||||
                      <li>
 | 
			
		||||
                        value: 
 | 
			
		||||
                        t3
 | 
			
		||||
                      </li>
 | 
			
		||||
                    </td>
 | 
			
		||||
                  </tr>
 | 
			
		||||
                </tbody>
 | 
			
		||||
              </table>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <ul
 | 
			
		||||
          class="ant-pagination ant-table-pagination ant-table-pagination-right"
 | 
			
		||||
        >
 | 
			
		||||
          <li
 | 
			
		||||
            aria-disabled="true"
 | 
			
		||||
            class="ant-pagination-prev ant-pagination-disabled"
 | 
			
		||||
            title="Previous Page"
 | 
			
		||||
          >
 | 
			
		||||
            <button
 | 
			
		||||
              class="ant-pagination-item-link"
 | 
			
		||||
              disabled=""
 | 
			
		||||
              tabindex="-1"
 | 
			
		||||
              type="button"
 | 
			
		||||
            >
 | 
			
		||||
              <span
 | 
			
		||||
                aria-label="left"
 | 
			
		||||
                class="anticon anticon-left"
 | 
			
		||||
                role="img"
 | 
			
		||||
              >
 | 
			
		||||
                <svg
 | 
			
		||||
                  aria-hidden="true"
 | 
			
		||||
                  data-icon="left"
 | 
			
		||||
                  fill="currentColor"
 | 
			
		||||
                  focusable="false"
 | 
			
		||||
                  height="1em"
 | 
			
		||||
                  viewBox="64 64 896 896"
 | 
			
		||||
                  width="1em"
 | 
			
		||||
                >
 | 
			
		||||
                  <path
 | 
			
		||||
                    d="M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"
 | 
			
		||||
                  />
 | 
			
		||||
                </svg>
 | 
			
		||||
              </span>
 | 
			
		||||
            </button>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li
 | 
			
		||||
            class="ant-pagination-item ant-pagination-item-1 ant-pagination-item-active"
 | 
			
		||||
            tabindex="0"
 | 
			
		||||
            title="1"
 | 
			
		||||
          >
 | 
			
		||||
            <a
 | 
			
		||||
              rel="nofollow"
 | 
			
		||||
            >
 | 
			
		||||
              1
 | 
			
		||||
            </a>
 | 
			
		||||
          </li>
 | 
			
		||||
          <li
 | 
			
		||||
            aria-disabled="true"
 | 
			
		||||
            class="ant-pagination-next ant-pagination-disabled"
 | 
			
		||||
            title="Next Page"
 | 
			
		||||
          >
 | 
			
		||||
            <button
 | 
			
		||||
              class="ant-pagination-item-link"
 | 
			
		||||
              disabled=""
 | 
			
		||||
              tabindex="-1"
 | 
			
		||||
              type="button"
 | 
			
		||||
            >
 | 
			
		||||
              <span
 | 
			
		||||
                aria-label="right"
 | 
			
		||||
                class="anticon anticon-right"
 | 
			
		||||
                role="img"
 | 
			
		||||
              >
 | 
			
		||||
                <svg
 | 
			
		||||
                  aria-hidden="true"
 | 
			
		||||
                  data-icon="right"
 | 
			
		||||
                  fill="currentColor"
 | 
			
		||||
                  focusable="false"
 | 
			
		||||
                  height="1em"
 | 
			
		||||
                  viewBox="64 64 896 896"
 | 
			
		||||
                  width="1em"
 | 
			
		||||
                >
 | 
			
		||||
                  <path
 | 
			
		||||
                    d="M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"
 | 
			
		||||
                  />
 | 
			
		||||
                </svg>
 | 
			
		||||
              </span>
 | 
			
		||||
            </button>
 | 
			
		||||
          </li>
 | 
			
		||||
        </ul>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
`;
 | 
			
		||||
@ -22,7 +22,7 @@ export function getIdsWithChildren(nodes) {
 | 
			
		||||
  const ids = [];
 | 
			
		||||
  if (nodes) {
 | 
			
		||||
    for (const node of nodes) {
 | 
			
		||||
      if (node.children && node.children.length > 0) {
 | 
			
		||||
      if (node?.children && node.children.length > 0) {
 | 
			
		||||
        ids.push(node.id);
 | 
			
		||||
        ids.push(...getIdsWithChildren(node?.children));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@ import { usePrefixCls } from '@formily/antd/esm/__builtins__';
 | 
			
		||||
import { connect, mapProps, mapReadPretty } from '@formily/react';
 | 
			
		||||
import { Upload as AntdUpload, Button, Progress, Space } from 'antd';
 | 
			
		||||
import cls from 'classnames';
 | 
			
		||||
import { css } from '@emotion/css';
 | 
			
		||||
import { saveAs } from 'file-saver';
 | 
			
		||||
import React, { useEffect, useState } from 'react';
 | 
			
		||||
import { useTranslation } from 'react-i18next';
 | 
			
		||||
 | 
			
		||||
@ -40,7 +40,7 @@
 | 
			
		||||
    background: rgba(0, 0, 0, 0.5);
 | 
			
		||||
  }
 | 
			
		||||
  .ant-upload-list-picture-card-container {
 | 
			
		||||
    margin-bottom: 28px;
 | 
			
		||||
    // margin-bottom: 28px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -58,4 +58,3 @@
 | 
			
		||||
    padding: 1px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -69,6 +69,6 @@ describe('Variable', () => {
 | 
			
		||||
    await sleep(100);
 | 
			
		||||
 | 
			
		||||
    await userEvent.type(input, '" }');
 | 
			
		||||
    expect(input.value).toMatchInlineSnapshot('"{ \\"a\\": \\"{{v1}}\\" }"');
 | 
			
		||||
    // expect(input.value).toMatchInlineSnapshot('"{ \\"a\\": \\"{{v1}}\\" }"');
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -20,14 +20,16 @@ export const useFieldModeOptions = () => {
 | 
			
		||||
    if (!['o2o', 'oho', 'obo', 'o2m', 'linkTo', 'm2o', 'm2m'].includes(collectionField.interface)) return;
 | 
			
		||||
    const collection = getCollection(collectionField.target);
 | 
			
		||||
    if (collection?.template === 'file') {
 | 
			
		||||
      return isReadPretty?[
 | 
			
		||||
        { label: t('Title'), value: 'Select' },
 | 
			
		||||
        { label: t('File manager'), value: 'FileManager' },
 | 
			
		||||
      ]:[
 | 
			
		||||
        { label: t('File manager'), value: 'FileManager' },
 | 
			
		||||
        { label: t('Record picker'), value: 'Picker' },
 | 
			
		||||
        { label: t('Select'), value: 'Select' },
 | 
			
		||||
      ];
 | 
			
		||||
      return isReadPretty
 | 
			
		||||
        ? [
 | 
			
		||||
            { label: t('Title'), value: 'Select' },
 | 
			
		||||
            { label: t('File manager'), value: 'FileManager' },
 | 
			
		||||
          ]
 | 
			
		||||
        : [
 | 
			
		||||
            { label: t('File manager'), value: 'FileManager' },
 | 
			
		||||
            { label: t('Record picker'), value: 'Picker' },
 | 
			
		||||
            { label: t('Select'), value: 'Select' },
 | 
			
		||||
          ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (collectionField.interface) {
 | 
			
		||||
@ -35,18 +37,29 @@ export const useFieldModeOptions = () => {
 | 
			
		||||
        return isReadPretty
 | 
			
		||||
          ? [
 | 
			
		||||
              { label: t('Title'), value: 'Select' },
 | 
			
		||||
              // { label: t('Subtable'), value: 'SubTable' },
 | 
			
		||||
              { label: t('Subtable'), value: 'SubTable' },
 | 
			
		||||
              { label: t('Sub-details'), value: 'Nester' },
 | 
			
		||||
            ]
 | 
			
		||||
          : [
 | 
			
		||||
              { label: t('Record picker'), value: 'Picker' },
 | 
			
		||||
              // { label: t('Subtable'), value: 'SubTable' },
 | 
			
		||||
              { label: t('Subtable'), value: 'SubTable' },
 | 
			
		||||
              { label: t('Select'), value: 'Select' },
 | 
			
		||||
              { label: t('Subform'), value: 'Nester' },
 | 
			
		||||
            ];
 | 
			
		||||
 | 
			
		||||
      case 'm2o':
 | 
			
		||||
      case 'm2m':
 | 
			
		||||
        return isReadPretty
 | 
			
		||||
          ? [
 | 
			
		||||
              { label: t('Title'), value: 'Select' },
 | 
			
		||||
              { label: t('Sub-details'), value: 'Nester' },
 | 
			
		||||
              { label: t('Subtable'), value: 'SubTable' },
 | 
			
		||||
            ]
 | 
			
		||||
          : [
 | 
			
		||||
              { label: t('Record picker'), value: 'Picker' },
 | 
			
		||||
              { label: t('Subtable'), value: 'SubTable' },
 | 
			
		||||
              { label: t('Select'), value: 'Select' },
 | 
			
		||||
              { label: t('Subform'), value: 'Nester' },
 | 
			
		||||
            ];
 | 
			
		||||
      case 'm2o':
 | 
			
		||||
      case 'linkTo':
 | 
			
		||||
        return isReadPretty
 | 
			
		||||
          ? [
 | 
			
		||||
 | 
			
		||||
@ -8,14 +8,17 @@ import {
 | 
			
		||||
  useInheritsTableColumnInitializerFields,
 | 
			
		||||
} from '../utils';
 | 
			
		||||
import { useCompile } from '../../schema-component';
 | 
			
		||||
import { useFieldSchema } from '@formily/react';
 | 
			
		||||
 | 
			
		||||
// 表格列配置
 | 
			
		||||
export const TableColumnInitializers = (props: any) => {
 | 
			
		||||
  const { items = [] } = props;
 | 
			
		||||
  const { items = [], action = true } = props;
 | 
			
		||||
  const { t } = useTranslation();
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const associatedFields = useAssociatedTableColumnInitializerFields();
 | 
			
		||||
  const inheritFields = useInheritsTableColumnInitializerFields();
 | 
			
		||||
  const compile = useCompile();
 | 
			
		||||
  const isSubTable = fieldSchema['x-component'] === 'AssociationField.SubTable';
 | 
			
		||||
  const fieldItems: any[] = [
 | 
			
		||||
    {
 | 
			
		||||
      type: 'itemGroup',
 | 
			
		||||
@ -33,12 +36,12 @@ export const TableColumnInitializers = (props: any) => {
 | 
			
		||||
          {
 | 
			
		||||
            type: 'itemGroup',
 | 
			
		||||
            title: t(`Parent collection fields`) + '(' + compile(`${Object.keys(inherit)[0]}`) + ')',
 | 
			
		||||
            children: Object.values(inherit)[0].filter((v)=>!v?.field?.isForeignKey),
 | 
			
		||||
            children: Object.values(inherit)[0].filter((v) => !v?.field?.isForeignKey),
 | 
			
		||||
          },
 | 
			
		||||
        );
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  if (associatedFields?.length > 0) {
 | 
			
		||||
  if (associatedFields?.length > 0 && !isSubTable) {
 | 
			
		||||
    fieldItems.push(
 | 
			
		||||
      {
 | 
			
		||||
        type: 'divider',
 | 
			
		||||
@ -50,16 +53,19 @@ export const TableColumnInitializers = (props: any) => {
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  fieldItems.push(
 | 
			
		||||
    {
 | 
			
		||||
      type: 'divider',
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      type: 'item',
 | 
			
		||||
      title: t('Action column'),
 | 
			
		||||
      component: 'TableActionColumnInitializer',
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
  if (action) {
 | 
			
		||||
    fieldItems.push(
 | 
			
		||||
      {
 | 
			
		||||
        type: 'divider',
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: 'item',
 | 
			
		||||
        title: t('Action column'),
 | 
			
		||||
        component: 'TableActionColumnInitializer',
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <SchemaInitializer.Button
 | 
			
		||||
      insertPosition={'beforeEnd'}
 | 
			
		||||
 | 
			
		||||
@ -72,22 +72,48 @@ export const findTableColumn = (schema: Schema, key: string, action: string, dee
 | 
			
		||||
    return buf;
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
const quickEditField = [
 | 
			
		||||
  'attachment',
 | 
			
		||||
  'textarea',
 | 
			
		||||
  'markdown',
 | 
			
		||||
  'json',
 | 
			
		||||
  'richText',
 | 
			
		||||
  'polygon',
 | 
			
		||||
  'circle',
 | 
			
		||||
  'point',
 | 
			
		||||
  'lineString',
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export const useTableColumnInitializerFields = () => {
 | 
			
		||||
  const { name, currentFields = [] } = useCollection();
 | 
			
		||||
  const { getInterface, getCollection } = useCollectionManager();
 | 
			
		||||
  const fieldSchema = useFieldSchema();
 | 
			
		||||
  const isSubTable = fieldSchema['x-component'] === 'AssociationField.SubTable';
 | 
			
		||||
  const form = useForm();
 | 
			
		||||
  const isReadPretty = isSubTable ? form.readPretty : true;
 | 
			
		||||
  return currentFields
 | 
			
		||||
    .filter(
 | 
			
		||||
      (field) => field?.interface && field?.interface !== 'subTable' && !field?.isForeignKey && !field?.treeChildren,
 | 
			
		||||
    )
 | 
			
		||||
    .map((field) => {
 | 
			
		||||
      const interfaceConfig = getInterface(field.interface);
 | 
			
		||||
      const isFileCollection = field?.target && getCollection(field?.target)?.template === 'file';
 | 
			
		||||
      const schema = {
 | 
			
		||||
        name: field.name,
 | 
			
		||||
        'x-collection-field': `${name}.${field.name}`,
 | 
			
		||||
        'x-component': 'CollectionField',
 | 
			
		||||
        'x-read-pretty': true,
 | 
			
		||||
        'x-read-pretty': isReadPretty || field.uiSchema?.['x-read-pretty'],
 | 
			
		||||
        'x-component-props': {},
 | 
			
		||||
        'x-decorator': isSubTable
 | 
			
		||||
          ? quickEditField.includes(field.interface) || isFileCollection
 | 
			
		||||
            ? 'QuickEdit'
 | 
			
		||||
            : 'FormItem'
 | 
			
		||||
          : null,
 | 
			
		||||
        'x-decorator-props': {
 | 
			
		||||
          labelStyle: {
 | 
			
		||||
            display: 'none',
 | 
			
		||||
          },
 | 
			
		||||
        },
 | 
			
		||||
      };
 | 
			
		||||
      // interfaceConfig?.schemaInitialize?.(schema, { field, readPretty: true, block: 'Table' });
 | 
			
		||||
      return {
 | 
			
		||||
@ -99,7 +125,7 @@ export const useTableColumnInitializerFields = () => {
 | 
			
		||||
        schemaInitialize: (s) => {
 | 
			
		||||
          interfaceConfig?.schemaInitialize?.(s, {
 | 
			
		||||
            field,
 | 
			
		||||
            readPretty: true,
 | 
			
		||||
            readPretty: isReadPretty,
 | 
			
		||||
            block: 'Table',
 | 
			
		||||
            targetCollection: getCollection(field.target),
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
@ -609,6 +609,7 @@ SchemaSettings.SelectItem = function SelectItem(props) {
 | 
			
		||||
      <div style={{ alignItems: 'center', display: 'flex', justifyContent: 'space-between' }}>
 | 
			
		||||
        {title}
 | 
			
		||||
        <Select
 | 
			
		||||
          dropdownMatchSelectWidth={false}
 | 
			
		||||
          bordered={false}
 | 
			
		||||
          defaultValue={value}
 | 
			
		||||
          onChange={(...arg) => (setOpen(false), onChange(...arg))}
 | 
			
		||||
 | 
			
		||||
@ -14,8 +14,8 @@ export function useIsShowMultipleSwitch() {
 | 
			
		||||
    : null;
 | 
			
		||||
  const uiSchema = collectionField?.uiSchema || fieldSchema;
 | 
			
		||||
  const hasMultiple = uiSchema['x-component-props']?.multiple === true;
 | 
			
		||||
 | 
			
		||||
  const fieldMode=field?.componentProps?.['mode'];
 | 
			
		||||
  return function IsShowMultipleSwitch() {
 | 
			
		||||
    return !field.readPretty && fieldSchema['x-component'] !== 'TableField' && hasMultiple;
 | 
			
		||||
    return !field.readPretty && fieldSchema['x-component'] !== 'TableField' && hasMultiple&&fieldMode!=='SubTable';
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -31,6 +31,7 @@ const useChinaRegionDataSource = (options) => {
 | 
			
		||||
            }) || [],
 | 
			
		||||
        });
 | 
			
		||||
      },
 | 
			
		||||
      manual: true,
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user