refactor: form data templates and depulicate action support sync from form fields (#2314)

* refactor: sync from form fields

* refactor: sync from form fields

* refactor: sync from form fields

* refactor: data fields

* refactor: traverseFields

* refactor: traverseFields

* refactor: locale improve

* fix: merge bug

* refactor: code improve

* refactor: code improve

* refactor: code improve

* refactor: depulicate action support sync form form fields

* refactor: code refactor

* refactor: direct duplicate support select all

* refactor: code improve

* refactor: code improve

* refactor: hasOne and hasMany avaliable for deplicate

* refactor:  code improve

* refactor: locale improve

* refactor: code improve

* refactor: code improve
This commit is contained in:
katherinehhh 2023-07-31 16:17:18 +08:00 committed by GitHub
parent c743d66b8e
commit 8f1d0d80af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 402 additions and 40 deletions

View File

@ -1100,8 +1100,7 @@ export const useAssociationFilterBlockProps = () => {
labelKey, labelKey,
}; };
}; };
export function getAssociationPath(str) {
function getAssociationPath(str) {
const lastIndex = str.lastIndexOf('.'); const lastIndex = str.lastIndexOf('.');
if (lastIndex !== -1) { if (lastIndex !== -1) {
return str.substring(0, lastIndex); return str.substring(0, lastIndex);

View File

@ -710,5 +710,8 @@ export default {
"Allow add new, update and delete actions":"Allow add new, update and delete actions", "Allow add new, update and delete actions":"Allow add new, update and delete actions",
"Date display format":"Date display format", "Date display format":"Date display format",
"Assign data scope for the template":"Assign data scope for the template", "Assign data scope for the template":"Assign data scope for the template",
"Table selected records":"Table selected records" "Table selected records":"Table selected records",
"Sync successfully":"Sync successfully",
"Sync from form fields":"Sync from form fields",
"Select all":"Select all"
}; };

View File

@ -621,4 +621,7 @@ export default {
"Allow add new, update and delete actions":"削除変更操作の許可", "Allow add new, update and delete actions":"削除変更操作の許可",
"Date display format":"日付表示形式", "Date display format":"日付表示形式",
"Assign data scope for the template":"テンプレートのデータ範囲の指定", "Assign data scope for the template":"テンプレートのデータ範囲の指定",
"Sync successfully":"同期成功",
"Sync from form fields":"フォームフィールドの同期",
"Select all":"すべて選択"
} }

View File

@ -795,5 +795,8 @@ export default {
"Allow add new, update and delete actions":"允许增删改操作", "Allow add new, update and delete actions":"允许增删改操作",
"Date display format":"日期显示格式", "Date display format":"日期显示格式",
"Assign data scope for the template":"为模板指定数据范围", "Assign data scope for the template":"为模板指定数据范围",
"Table selected records":"表格中选中的记录" "Table selected records":"表格中选中的记录",
"Sync successfully":"同步成功",
"Sync from form fields":"同步表单字段",
"Select all":"全选"
} }

View File

@ -1,8 +1,8 @@
import { connect, ISchema, mapProps, useField, useFieldSchema } from '@formily/react'; import { connect, ISchema, mapProps, useField, useFieldSchema, useForm } from '@formily/react';
import { isValid, uid } from '@formily/shared'; import { isValid, uid } from '@formily/shared';
import { Tree as AntdTree } from 'antd'; import { Tree as AntdTree } from 'antd';
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState, useMemo, useCallback } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useDesignable } from '../..'; import { useDesignable } from '../..';
import { useCollection, useCollectionManager } from '../../../collection-manager'; import { useCollection, useCollectionManager } from '../../../collection-manager';
@ -12,15 +12,21 @@ import { useCollectionState } from '../../../schema-settings/DataTemplates/hooks
import { useLinkageAction } from './hooks'; import { useLinkageAction } from './hooks';
import { requestSettingsSchema } from './utils'; import { requestSettingsSchema } from './utils';
import { useRecord } from '../../../record-provider'; import { useRecord } from '../../../record-provider';
import { useSyncFromForm } from '../../../schema-settings/DataTemplates/utils';
const Tree = connect( const Tree = connect(
AntdTree, AntdTree,
mapProps((props, field: any) => { mapProps((props, field: any) => {
const [checkedKeys, setCheckedKeys] = useState(props.defaultCheckedKeys || []);
const onCheck = (checkedKeys) => {
setCheckedKeys(checkedKeys);
field.value = checkedKeys;
};
field.onCheck = onCheck;
return { return {
...props, ...props,
onCheck: (checkedKeys) => { checkedKeys,
field.value = checkedKeys; onCheck,
},
}; };
}), }),
); );
@ -218,6 +224,28 @@ function SaveMode() {
); );
} }
const findFormBlock = (schema) => {
const formSchema = schema.reduceProperties((_, s) => {
if (s['x-decorator'] === 'FormBlockProvider') {
return s;
} else {
return findFormBlock(s);
}
}, null);
return formSchema;
};
const getAllkeys = (data, result) => {
for (let i = 0; i < data?.length; i++) {
const { children, ...rest } = data[i];
result.push(rest.key);
if (children) {
getAllkeys(children, result);
}
}
return result;
};
function DuplicationMode() { function DuplicationMode() {
const { dn } = useDesignable(); const { dn } = useDesignable();
const { t } = useTranslation(); const { t } = useTranslation();
@ -227,7 +255,27 @@ function DuplicationMode() {
const { collectionList, getEnableFieldTree, getOnLoadData, getOnCheck } = useCollectionState(name); const { collectionList, getEnableFieldTree, getOnLoadData, getOnCheck } = useCollectionState(name);
const duplicateValues = cloneDeep(fieldSchema['x-component-props'].duplicateFields || []); const duplicateValues = cloneDeep(fieldSchema['x-component-props'].duplicateFields || []);
const record = useRecord(); const record = useRecord();
const syncCallBack = useCallback((treeData, selectFields, form) => {
form.query('duplicateFields').take((f) => {
f.componentProps.treeData = treeData;
f.componentProps.defaultCheckedKeys = selectFields;
f.setInitialValue(selectFields);
f?.onCheck(selectFields);
form.setValues({ ...form.values, treeData });
});
}, []);
const useSelectAllFields = (form) => {
return {
async run() {
form.query('duplicateFields').take((f) => {
const selectFields = getAllkeys(f.componentProps.treeData, []);
f.componentProps.defaultCheckedKeys = selectFields;
f.setInitialValue(selectFields);
f?.onCheck(selectFields);
});
},
};
};
return ( return (
<SchemaSettings.ModalItem <SchemaSettings.ModalItem
title={t('Duplicate mode')} title={t('Duplicate mode')}
@ -238,6 +286,7 @@ function DuplicationMode() {
currentCollection: record?.__collection || name, currentCollection: record?.__collection || name,
getOnLoadData, getOnLoadData,
getOnCheck, getOnCheck,
treeData: fieldSchema['x-component-props']?.treeData,
}} }}
schema={ schema={
{ {
@ -278,11 +327,60 @@ function DuplicationMode() {
}, },
], ],
}, },
syncFromForm: {
type: 'void',
title: '{{ t("Sync from form fields") }}',
'x-component': 'Action.Link',
'x-component-props': {
type: 'primary',
style: { float: 'right', position: 'relative', zIndex: 1200 },
useAction: () => {
const formSchema = useMemo(() => findFormBlock(fieldSchema), [fieldSchema]);
return useSyncFromForm(
formSchema,
fieldSchema['x-component-props']?.duplicateCollection || record?.__collection || name,
syncCallBack,
);
},
},
'x-reactions': [
{
dependencies: ['.duplicateMode'],
fulfill: {
state: {
visible: `{{ $deps[0]!=="quickDulicate" }}`,
},
},
},
],
},
selectAll: {
type: 'void',
title: '{{ t("Select all") }}',
'x-component': 'Action.Link',
'x-reactions': [
{
dependencies: ['.duplicateMode'],
fulfill: {
state: {
visible: `{{ $deps[0]==="quickDulicate" }}`,
},
},
},
],
'x-component-props': {
type: 'primary',
style: { float: 'right', position: 'relative', zIndex: 1200 },
useAction: () => {
const from = useForm();
return useSelectAllFields(from);
},
},
},
duplicateFields: { duplicateFields: {
type: 'array', type: 'array',
title: '{{ t("Data fields") }}', title: '{{ t("Data fields") }}',
required: true, required: true,
default: duplicateValues,
description: t('Only the selected fields will be used as the initialization data for the form'), description: t('Only the selected fields will be used as the initialization data for the form'),
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': Tree, 'x-component': Tree,
@ -310,7 +408,7 @@ function DuplicationMode() {
state: { state: {
disabled: '{{ !$deps[0] }}', disabled: '{{ !$deps[0] }}',
componentProps: { componentProps: {
treeData: '{{ getEnableFieldTree($deps[0], $self) }}', treeData: '{{ getEnableFieldTree($deps[0], $self,treeData) }}',
}, },
}, },
}, },
@ -320,7 +418,7 @@ function DuplicationMode() {
}, },
} as ISchema } as ISchema
} }
onSubmit={({ duplicateMode, collection, duplicateFields }) => { onSubmit={({ duplicateMode, collection, duplicateFields, treeData }) => {
const fields = Array.isArray(duplicateFields) ? duplicateFields : duplicateFields.checked || []; const fields = Array.isArray(duplicateFields) ? duplicateFields : duplicateFields.checked || [];
field.componentProps.duplicateMode = duplicateMode; field.componentProps.duplicateMode = duplicateMode;
field.componentProps.duplicateFields = fields; field.componentProps.duplicateFields = fields;
@ -328,6 +426,7 @@ function DuplicationMode() {
fieldSchema['x-component-props'].duplicateMode = duplicateMode; fieldSchema['x-component-props'].duplicateMode = duplicateMode;
fieldSchema['x-component-props'].duplicateFields = fields; fieldSchema['x-component-props'].duplicateFields = fields;
fieldSchema['x-component-props'].duplicateCollection = collection; fieldSchema['x-component-props'].duplicateCollection = collection;
fieldSchema['x-component-props'].treeData = treeData;
dn.emit('patch', { dn.emit('patch', {
schema: { schema: {
['x-uid']: fieldSchema['x-uid'], ['x-uid']: fieldSchema['x-uid'],

View File

@ -163,7 +163,7 @@ export const Templates = ({ style = {}, form }) => {
{targetTemplate !== 'none' && ( {targetTemplate !== 'none' && (
<RemoteSelect <RemoteSelect
style={{ width: 220 }} style={{ width: 220 }}
fieldNames={{ label: template.titleField, value: 'id' }} fieldNames={{ label: template?.titleField, value: 'id' }}
target={template?.collection} target={template?.collection}
value={targetTemplateData} value={targetTemplateData}
objectValue objectValue

View File

@ -13,6 +13,7 @@ import { AsDefaultTemplate } from './components/AsDefaultTemplate';
import { ArrayCollapse } from './components/DataTemplateTitle'; import { ArrayCollapse } from './components/DataTemplateTitle';
import { getSelectedIdFilter } from './components/Designer'; import { getSelectedIdFilter } from './components/Designer';
import { useCollectionState } from './hooks/useCollectionState'; import { useCollectionState } from './hooks/useCollectionState';
import { useSyncFromForm } from './utils';
const Tree = connect( const Tree = connect(
AntdTree, AntdTree,
@ -48,7 +49,6 @@ export const FormDataTemplates = observer(
} = useCollectionState(collectionName); } = useCollectionState(collectionName);
const { getCollection, getCollectionField } = useCollectionManager(); const { getCollection, getCollectionField } = useCollectionManager();
const { t } = useTranslation(); const { t } = useTranslation();
// 不要在后面的数组中依赖 defaultValues否则会因为 defaultValues 的变化导致 activeData 响应性丢失 // 不要在后面的数组中依赖 defaultValues否则会因为 defaultValues 的变化导致 activeData 响应性丢失
const activeData = useMemo<ITemplate>( const activeData = useMemo<ITemplate>(
() => () =>
@ -61,7 +61,6 @@ export const FormDataTemplates = observer(
), ),
[], [],
); );
console.log(activeData);
const getTargetField = (collectionName: string) => { const getTargetField = (collectionName: string) => {
const collection = getCollection(collectionName); const collection = getCollection(collectionName);
return getCollectionField( return getCollectionField(
@ -170,6 +169,16 @@ export const FormDataTemplates = observer(
required: true, required: true,
'x-reactions': '{{useTitleFieldDataSource}}', 'x-reactions': '{{useTitleFieldDataSource}}',
}, },
syncFromForm: {
type: 'void',
title: '{{ t("Sync from form fields") }}',
'x-component': 'Action.Link',
'x-component-props': {
type: 'primary',
style: { float: 'right', position: 'relative', zIndex: 1200 },
useAction: () => useSyncFromForm(formSchema),
},
},
fields: { fields: {
type: 'array', type: 'array',
title: '{{ t("Data fields") }}', title: '{{ t("Data fields") }}',

View File

@ -48,8 +48,7 @@ const DataTemplateTitle = observer<{ index: number; item: any }>((props) => {
export interface IArrayCollapseProps extends CollapseProps { export interface IArrayCollapseProps extends CollapseProps {
defaultOpenPanelCount?: number; defaultOpenPanelCount?: number;
} }
type ComposedArrayCollapse = type ComposedArrayCollapse = React.FC<React.PropsWithChildren<IArrayCollapseProps>> & {
| React.FC<React.PropsWithChildren<IArrayCollapseProps>> & {
CollapsePanel?: React.FC<React.PropsWithChildren<CollapsePanelProps>>; CollapsePanel?: React.FC<React.PropsWithChildren<CollapsePanelProps>>;
}; };
@ -218,6 +217,9 @@ export const ArrayCollapse: ComposedArrayCollapse = observer(
onAdd={(index) => { onAdd={(index) => {
setActiveKeys(insertActiveKeys(activeKeys, index)); setActiveKeys(insertActiveKeys(activeKeys, index));
}} }}
onRemove={() => {
field.initialValue = field.value;
}}
> >
{renderEmpty()} {renderEmpty()}
{renderItems()} {renderItems()}

View File

@ -1,22 +1,12 @@
import { ArrayField } from '@formily/core'; import { ArrayField } from '@formily/core';
import { useField } from '@formily/react';
import React, { useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import { useCollectionManager } from '../../../collection-manager'; import { useCollectionManager } from '../../../collection-manager';
import { isTitleField } from '../../../collection-manager/Configuration/CollectionFields';
import { useCompile } from '../../../schema-component'; import { useCompile } from '../../../schema-component';
import { TreeNode } from '../TreeLabel'; import { TreeNode } from '../TreeLabel';
export const useCollectionState = (currentCollectionName: string) => {
const { getCollectionFields, getAllCollectionsInheritChain, getCollection, getInterface } = useCollectionManager();
const [collectionList] = useState(getCollectionList);
const compile = useCompile();
function getCollectionList() {
const collections = getAllCollectionsInheritChain(currentCollectionName);
return collections.map((name) => ({ label: getCollection(name)?.title, value: name }));
}
// 过滤掉系统字段 // 过滤掉系统字段
const systemKeys = [ export const systemKeys = [
// 'id', // 'id',
'sort', 'sort',
'createdById', 'createdById',
@ -25,7 +15,19 @@ export const useCollectionState = (currentCollectionName: string) => {
'updatedById', 'updatedById',
'updatedBy', 'updatedBy',
'updatedAt', 'updatedAt',
'password',
'sequence',
]; ];
export const useCollectionState = (currentCollectionName: string) => {
const { getCollectionFields, getAllCollectionsInheritChain, getCollection, getInterface } = useCollectionManager();
const [collectionList] = useState(getCollectionList);
const compile = useCompile();
const templateField: any = useField();
function getCollectionList() {
const collections = getAllCollectionsInheritChain(currentCollectionName);
return collections.map((name) => ({ label: getCollection(name)?.title, value: name }));
}
/** /**
* maxDepth: 0 0 1 * maxDepth: 0 0 1
@ -115,12 +117,25 @@ export const useCollectionState = (currentCollectionName: string) => {
}) })
.filter(Boolean); .filter(Boolean);
}; };
const parseTreeData = (data) => {
return data.map((v) => {
return {
...v,
title: React.createElement(TreeNode, { ...v, type: v.type }),
children: v.children ? parseTreeData(v.children) : null,
};
});
};
const getEnableFieldTree = useCallback((collectionName: string) => { const getEnableFieldTree = useCallback((collectionName: string, field, treeData?) => {
const index = field.index;
const targetTemplate = templateField.initialValue?.items?.[index];
if (!collectionName) { if (!collectionName) {
return []; return [];
} }
if (targetTemplate?.treeData || treeData) {
return parseTreeData(treeData || targetTemplate.treeData);
}
try { try {
return traverseFields(collectionName, { exclude: ['id', ...systemKeys], maxDepth: 1 }); return traverseFields(collectionName, { exclude: ['id', ...systemKeys], maxDepth: 1 });
} catch (error) { } catch (error) {
@ -242,9 +257,8 @@ function findNode(treeData, item) {
} }
function loadChildren({ node, traverseAssociations, traverseFields, systemKeys, fields }) { function loadChildren({ node, traverseAssociations, traverseFields, systemKeys, fields }) {
const activeNode = findNode(fields.componentProps.treeData, node); const activeNode = findNode(fields.dataSource || fields.componentProps.treeData, node);
let children = []; let children = [];
// 多对多和多对一只展示关系字段 // 多对多和多对一只展示关系字段
if (['belongsTo', 'belongsToMany'].includes(node.field.type)) { if (['belongsTo', 'belongsToMany'].includes(node.field.type)) {
children = traverseAssociations(node.field.target, { children = traverseAssociations(node.field.target, {

View File

@ -0,0 +1,232 @@
import { ArrayBase } from '@formily/antd-v5';
import { useForm } from '@formily/react';
import { message } from 'antd';
import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { getAssociationPath } from '../../block-provider/hooks';
import { useCollectionManager } from '../../collection-manager';
import { useCompile } from '../../schema-component';
import { TreeNode } from './TreeLabel';
import { systemKeys } from './hooks/useCollectionState';
import LRUCache from 'lru-cache';
export const useSyncFromForm = (fieldSchema, collection?, callBack?) => {
const { getCollectionJoinField, getCollectionFields } = useCollectionManager();
const array = ArrayBase.useArray();
const index = ArrayBase.useIndex();
const record = ArrayBase.useRecord();
const compile = useCompile();
const { t } = useTranslation();
const from = useForm();
const traverseFields = ((cache) => {
return (collectionName, { exclude = [], depth = 0, maxDepth, prefix = '', disabled = false }, formData) => {
const cacheKey = `${collectionName}-${exclude.join(',')}-${depth}-${maxDepth}-${prefix}`;
const cachedResult = cache.get(cacheKey);
if (cachedResult) {
return cachedResult;
}
if (depth > maxDepth) {
return [];
}
const result = getCollectionFields(collectionName)
.map((field) => {
if (exclude.includes(field.name)) {
return;
}
if (!field.interface) {
return;
}
if (['sort', 'password', 'sequence'].includes(field.type)) {
return;
}
const node = {
type: 'duplicate',
tag: compile(field.uiSchema?.title) || field.name,
};
const option = {
...node,
title: React.createElement(TreeNode, node),
key: prefix ? `${prefix}.${field.name}` : field.name,
isLeaf: true,
field,
disabled,
};
const tatgetFormField = formData.find((v) => v.name === field.name);
if (
['belongsTo', 'belongsToMany'].includes(field.type) &&
(!tatgetFormField || ['Select', 'Picker'].includes(tatgetFormField?.fieldMode))
) {
node['type'] = 'reference';
option['type'] = 'reference';
option['title'] = React.createElement(TreeNode, { ...node, type: 'reference' });
option.isLeaf = false;
option['children'] = traverseAssociations(field.target, {
depth: depth + 1,
maxDepth,
prefix: option.key,
exclude: systemKeys,
});
} else if (
['hasOne', 'hasMany'].includes(field.type) ||
['Nester', 'SubTable'].includes(tatgetFormField?.fieldMode)
) {
let childrenDisabled = false;
if (
['hasOne', 'hasMany'].includes(field.type) &&
['Select', 'Picker'].includes(tatgetFormField?.fieldMode)
) {
childrenDisabled = true;
}
option.disabled = true;
option.isLeaf = false;
option['children'] = traverseFields(
field.target,
{
depth: depth + 1,
maxDepth,
prefix: option.key,
exclude: ['id', ...systemKeys],
disabled: childrenDisabled,
},
formData,
);
}
return option;
})
.filter(Boolean);
cache.set(cacheKey, result);
return result;
};
})(
new LRUCache<string, any>({ max: 100 }),
);
const traverseAssociations = ((cache) => {
return (collectionName, { prefix, maxDepth, depth = 0, exclude = [] }) => {
const cacheKey = `${collectionName}-${exclude.join(',')}-${depth}-${maxDepth}-${prefix}`;
const cachedResult = cache.get(cacheKey);
if (cachedResult) {
return cachedResult;
}
if (depth > maxDepth) {
return [];
}
const result = getCollectionFields(collectionName)
.map((field) => {
if (!field.target || !field.interface) {
return;
}
if (exclude.includes(field.name)) {
return;
}
const option = {
type: 'preloading',
tag: compile(field.uiSchema?.title) || field.name,
};
const value = prefix ? `${prefix}.${field.name}` : field.name;
return {
type: 'preloading',
tag: compile(field.uiSchema?.title) || field.name,
title: React.createElement(TreeNode, option),
key: value,
isLeaf: false,
field,
children: traverseAssociations(field.target, {
prefix: value,
depth: depth + 1,
maxDepth,
exclude,
}),
};
})
.filter(Boolean);
cache.set(cacheKey, result);
return result;
};
})(
new LRUCache<string, any>({ max: 100 }),
);
const getEnableFieldTree = useCallback((collectionName: string, formData) => {
if (!collectionName) {
return [];
}
try {
return traverseFields(collectionName, { exclude: ['id', ...systemKeys], maxDepth: 1, disabled: false }, formData);
} catch (error) {
console.error(error);
return [];
}
}, []);
return {
async run() {
const formData = new Set([]);
const selectFields = new Set([]);
const getAssociationAppends = (schema, str) => {
schema.reduceProperties((pre, s) => {
const prefix = pre || str;
const collectionfield = s['x-collection-field'] && getCollectionJoinField(s['x-collection-field']);
const isAssociationSubfield = s.name.includes('.');
const isAssociationField =
collectionfield && ['hasOne', 'hasMany', 'belongsTo', 'belongsToMany'].includes(collectionfield.type);
const fieldPath = !isAssociationField && isAssociationSubfield ? getAssociationPath(s.name) : s.name;
const path = prefix === '' || !prefix ? fieldPath : prefix + '.' + fieldPath;
if (
collectionfield &&
!(
['hasOne', 'hasMany'].includes(collectionfield.type) ||
['SubForm', 'Nester'].includes(s['x-component-props']?.mode)
)
) {
selectFields.add(path);
}
if (collectionfield && (isAssociationField || isAssociationSubfield) && s['x-component'] !== 'TableField') {
formData.add({ name: path, fieldMode: s['x-component-props']['mode'] || 'Select' });
if (['Nester', 'SubTable'].includes(s['x-component-props']?.mode)) {
const bufPrefix = prefix && prefix !== '' ? prefix + '.' + s.name : s.name;
getAssociationAppends(s, bufPrefix);
}
} else if (
![
'ActionBar',
'Action',
'Action.Link',
'Action.Modal',
'Selector',
'Viewer',
'AddNewer',
'AssociationField.Selector',
'AssociationField.AddNewer',
'TableField',
].includes(s['x-component'])
) {
getAssociationAppends(s, str);
}
}, str);
};
getAssociationAppends(fieldSchema, '');
const treeData = getEnableFieldTree(record?.collection || collection, [...formData]);
if (callBack) {
callBack(treeData, [...selectFields], from);
} else {
array?.field.form.query(`fieldReaction.items.${index}.layout.fields`).take((f: any) => {
f.componentProps.treeData = [];
setTimeout(() => (f.componentProps.treeData = treeData));
});
array?.field.value.splice(index, 1, {
...array?.field?.value[index],
fields: [...selectFields],
treeData: treeData,
});
}
message.success(t('Sync successfully'));
},
};
};

View File

@ -1146,7 +1146,6 @@ SchemaSettings.DataTemplates = function DataTemplates(props) {
const { t } = useTranslation(); const { t } = useTranslation();
const formSchema = findFormBlock(fieldSchema) || fieldSchema; const formSchema = findFormBlock(fieldSchema) || fieldSchema;
const { templateData } = useDataTemplates(); const { templateData } = useDataTemplates();
const schema = useMemo( const schema = useMemo(
() => ({ () => ({
type: 'object', type: 'object',
@ -1171,7 +1170,6 @@ SchemaSettings.DataTemplates = function DataTemplates(props) {
); );
const onSubmit = useCallback((v) => { const onSubmit = useCallback((v) => {
const data = { ...(formSchema['x-data-templates'] || {}), ...v.fieldReaction }; const data = { ...(formSchema['x-data-templates'] || {}), ...v.fieldReaction };
// 当 Tree 组件开启 checkStrictly 属性时,会导致 checkedKeys 的值是一个对象,而不是数组,所以这里需要转换一下以支持旧版本 // 当 Tree 组件开启 checkStrictly 属性时,会导致 checkedKeys 的值是一个对象,而不是数组,所以这里需要转换一下以支持旧版本
data.items.forEach((item) => { data.items.forEach((item) => {
item.fields = Array.isArray(item.fields) ? item.fields : item.fields.checked; item.fields = Array.isArray(item.fields) ? item.fields : item.fields.checked;