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