refactor: performance optimization of association field data scope (#2113)
* refactor: performance optimization of association field data scope * refactor: disabled * refactor: disabled * refactor: code improve
This commit is contained in:
parent
ed9d716d7d
commit
a9aab8ed92
@ -13,7 +13,7 @@ export const ChildDynamicComponent = observer(
|
||||
const formVariabele = useFormVariable({ blockForm: form, rootCollection });
|
||||
const iterationVariabele = useIterationVariable({
|
||||
blockForm: form,
|
||||
collectionField,
|
||||
currentCollection: collectionField.collectionName,
|
||||
rootCollection,
|
||||
});
|
||||
|
||||
|
@ -11,11 +11,12 @@ interface GetOptionsParams {
|
||||
loadChildren?: (option: Option) => Promise<void>;
|
||||
getFilterOptions?: (collectionName: string) => any[];
|
||||
compile: (value: string) => any;
|
||||
schema?: any;
|
||||
}
|
||||
|
||||
const getChildren = (
|
||||
options: FieldOption[],
|
||||
{ depth, maxDepth, loadChildren, compile }: GetOptionsParams,
|
||||
{ depth, maxDepth, loadChildren, compile, schema }: GetOptionsParams,
|
||||
): Option[] => {
|
||||
const result = options
|
||||
.map((option): Option => {
|
||||
@ -25,6 +26,8 @@ const getChildren = (
|
||||
value: option.name,
|
||||
label: compile(option.title),
|
||||
depth,
|
||||
// TODO: 现在是通过组件的名称来过滤能够被选择的选项,这样的坏处是不够精确,后续可以优化
|
||||
disabled: schema?.['x-component'] !== option.schema?.['x-component'],
|
||||
};
|
||||
}
|
||||
|
||||
@ -50,11 +53,13 @@ export const useFormVariable = ({
|
||||
rootCollection,
|
||||
operator,
|
||||
level,
|
||||
schema,
|
||||
}: {
|
||||
blockForm?: any;
|
||||
rootCollection: string;
|
||||
operator?: any;
|
||||
level?: number;
|
||||
schema?: any;
|
||||
}) => {
|
||||
const compile = useCompile();
|
||||
const { t } = useTranslation();
|
||||
@ -82,6 +87,7 @@ export const useFormVariable = ({
|
||||
maxDepth: 4,
|
||||
loadChildren,
|
||||
compile,
|
||||
schema,
|
||||
}) || [];
|
||||
if (children.length === 0) {
|
||||
option.disabled = true;
|
||||
|
@ -1,94 +1,125 @@
|
||||
import { Schema } from '@formily/react';
|
||||
import { useMemo } from 'react';
|
||||
import { useCollectionManager } from '../../../collection-manager';
|
||||
import { useCompile, useGetFilterOptions } from '../../../schema-component';
|
||||
import { FieldOption, Option } from '../type';
|
||||
|
||||
interface GetOptionsParams {
|
||||
schema: any;
|
||||
depth: number;
|
||||
operator?: string;
|
||||
maxDepth: number;
|
||||
count?: number;
|
||||
getFilterOptions: (collectionName: string) => any[];
|
||||
loadChildren?: (option: Option) => Promise<void>;
|
||||
getFilterOptions?: (collectionName: string) => any[];
|
||||
compile: (value: string) => any;
|
||||
schema: any;
|
||||
}
|
||||
|
||||
const getChildren = (options: any[], { schema, operator, maxDepth, count = 1, getFilterOptions }: GetOptionsParams) => {
|
||||
if (count > maxDepth) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const result = options.map((option) => {
|
||||
if ((option.type !== 'belongsTo' && option.type !== 'hasOne') || !option.target) {
|
||||
const getChildren = (
|
||||
options: FieldOption[],
|
||||
{ depth, maxDepth, loadChildren, compile, schema }: GetOptionsParams,
|
||||
): Option[] => {
|
||||
const result = options
|
||||
.map((option): Option => {
|
||||
if (!option.target) {
|
||||
return {
|
||||
key: option.name,
|
||||
value: option.name,
|
||||
label: option.title,
|
||||
label: compile(option.title),
|
||||
depth,
|
||||
// TODO: 现在是通过组件的名称来过滤能够被选择的选项,这样的坏处是不够精确,后续可以优化
|
||||
// disabled: schema?.['x-component'] !== option.schema?.['x-component'],
|
||||
disabled: false,
|
||||
disabled: schema?.['x-component'] !== option.schema?.['x-component'],
|
||||
};
|
||||
}
|
||||
|
||||
const children =
|
||||
getChildren(getFilterOptions(option.target), {
|
||||
schema,
|
||||
operator,
|
||||
maxDepth,
|
||||
count: count + 1,
|
||||
getFilterOptions,
|
||||
}) || [];
|
||||
if (depth >= maxDepth) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
key: option.name,
|
||||
value: option.name,
|
||||
label: option.title,
|
||||
children,
|
||||
disabled: children.every((child) => child.disabled),
|
||||
label: compile(option.title),
|
||||
children: [],
|
||||
isLeaf: false,
|
||||
field: option,
|
||||
depth,
|
||||
loadChildren,
|
||||
};
|
||||
});
|
||||
|
||||
})
|
||||
.filter(Boolean);
|
||||
return result;
|
||||
};
|
||||
|
||||
export const useIterationVariable = ({
|
||||
blockForm,
|
||||
collectionField,
|
||||
currentCollection,
|
||||
operator,
|
||||
schema,
|
||||
level,
|
||||
rootCollection,
|
||||
}: {
|
||||
blockForm?: any;
|
||||
collectionField: any;
|
||||
currentCollection: string;
|
||||
rootCollection: string;
|
||||
operator?: any;
|
||||
schema?: any;
|
||||
level?: number;
|
||||
rootCollection?: string;
|
||||
}) => {
|
||||
const compile = useCompile();
|
||||
const getFilterOptions = useGetFilterOptions();
|
||||
const fields = getFilterOptions(collectionField?.collectionName);
|
||||
const children = useMemo(() => {
|
||||
const allowFields = fields.filter((field) => {
|
||||
return Object.keys(blockForm.fields).some((name) => name.includes(field.name));
|
||||
const loadChildren = (option: any): Promise<void> => {
|
||||
if (!option.field?.target) {
|
||||
return new Promise((resolve) => {
|
||||
resolve(void 0);
|
||||
});
|
||||
return (
|
||||
getChildren(allowFields, {
|
||||
schema,
|
||||
operator,
|
||||
maxDepth: level || 3,
|
||||
getFilterOptions,
|
||||
}) || []
|
||||
);
|
||||
}, [operator, schema, blockForm]);
|
||||
}
|
||||
|
||||
return useMemo(() => {
|
||||
return rootCollection !== collectionField?.collectionName && children.length > 0
|
||||
? compile({
|
||||
const collectionName = option.field.target;
|
||||
const fields = getFilterOptions(collectionName);
|
||||
const allowFields =
|
||||
option.depth === 0
|
||||
? fields.filter((field) => {
|
||||
return Object.keys(blockForm.fields).some((name) => name.includes(`.${field.name}`));
|
||||
})
|
||||
: fields;
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
const children =
|
||||
getChildren(allowFields, {
|
||||
depth: option.depth + 1,
|
||||
maxDepth: 4,
|
||||
loadChildren,
|
||||
compile,
|
||||
schema,
|
||||
}) || [];
|
||||
if (children.length === 0) {
|
||||
option.disabled = true;
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
option.children = children;
|
||||
resolve();
|
||||
|
||||
// 延迟 5 毫秒,防止阻塞主线程,导致 UI 卡顿
|
||||
}, 5);
|
||||
});
|
||||
};
|
||||
|
||||
const result = useMemo(() => {
|
||||
return (
|
||||
blockForm &&
|
||||
currentCollection !== rootCollection && {
|
||||
label: `{{t("Current object")}}`,
|
||||
value: '$iteration',
|
||||
key: '$iteration',
|
||||
disabled: children.every((option) => option.disabled),
|
||||
children: children,
|
||||
})
|
||||
: null;
|
||||
}, [children]);
|
||||
children: [],
|
||||
isLeaf: false,
|
||||
field: {
|
||||
target: currentCollection,
|
||||
},
|
||||
depth: 0,
|
||||
loadChildren,
|
||||
}
|
||||
);
|
||||
}, [currentCollection]);
|
||||
return result;
|
||||
};
|
||||
|
@ -9,8 +9,13 @@ export const useVariableOptions = ({ form, collectionField, rootCollection }: an
|
||||
const { operator, schema } = useValues();
|
||||
const userVariable = useUserVariable({ maxDepth: 3, schema });
|
||||
const dateVariable = useDateVariable({ operator, schema });
|
||||
const formVariabele = useFormVariable({ blockForm: form, rootCollection });
|
||||
const iterationVariabele = useIterationVariable({ blockForm: form, collectionField, schema, rootCollection });
|
||||
const formVariabele = useFormVariable({ blockForm: form, schema, rootCollection });
|
||||
const iterationVariabele = useIterationVariable({
|
||||
blockForm: form,
|
||||
currentCollection: collectionField.collectionName,
|
||||
schema,
|
||||
rootCollection,
|
||||
});
|
||||
|
||||
const result = useMemo(
|
||||
() => [userVariable, dateVariable, formVariabele, iterationVariabele].filter(Boolean),
|
||||
|
Loading…
Reference in New Issue
Block a user