feat: data scope support variables for association fields (#2049)
* feat: association field support data scope * refactor: association data scope * refactor: association data scope local * refactor: association data scope * refactor: association data scope code improve * refactor: code improve * fix: useFormVariable * fix: useFormVariable * chore: useFormVariable * chore: useFormVariable * chore: useFormVariable * chore: useFormVariable * refactor: locale improve * refactor: locale improve --------- Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
parent
6eed9ac2bb
commit
cb52b80cf0
@ -703,5 +703,7 @@ export default {
|
|||||||
"First or create":"First or create",
|
"First or create":"First or create",
|
||||||
"Update or create":"Update or create",
|
"Update or create":"Update or create",
|
||||||
"Find by the following fields":"Find by the following fields",
|
"Find by the following fields":"Find by the following fields",
|
||||||
"Create":"Create"
|
"Create":"Create",
|
||||||
|
"Current form": "Current form",
|
||||||
|
"Current object":"Current object"
|
||||||
};
|
};
|
||||||
|
@ -614,5 +614,7 @@ export default {
|
|||||||
"First or create":"存在しない場合に追加",
|
"First or create":"存在しない場合に追加",
|
||||||
"Update or create":"存在しなければ新規、存在すれば更新",
|
"Update or create":"存在しなければ新規、存在すれば更新",
|
||||||
"Find by the following fields":"次のフィールドで検索",
|
"Find by the following fields":"次のフィールドで検索",
|
||||||
"Create":"新規のみ"
|
"Create":"新規のみ" ,
|
||||||
|
"Current form":"現在のフォーム",
|
||||||
|
"Current object":"現在のオブジェクト"
|
||||||
}
|
}
|
||||||
|
@ -782,6 +782,8 @@ export default {
|
|||||||
"Update or create":"不存在时新增,存在时更新",
|
"Update or create":"不存在时新增,存在时更新",
|
||||||
"Find by the following fields":"通过以下字段查找",
|
"Find by the following fields":"通过以下字段查找",
|
||||||
"Create":"仅新增",
|
"Create":"仅新增",
|
||||||
|
"Current form":"当前表单",
|
||||||
|
"Current object":"当前对象",
|
||||||
"Quick create": "快速创建",
|
"Quick create": "快速创建",
|
||||||
"Dropdown": "下拉菜单",
|
"Dropdown": "下拉菜单",
|
||||||
"Pop-up": "弹窗",
|
"Pop-up": "弹窗",
|
||||||
|
@ -104,6 +104,7 @@ FormItem.Designer = function Designer() {
|
|||||||
const { getCollectionFields, getInterface, getCollectionJoinField, getCollection } = useCollectionManager();
|
const { getCollectionFields, getInterface, getCollectionJoinField, getCollection } = useCollectionManager();
|
||||||
const { getField } = useCollection();
|
const { getField } = useCollection();
|
||||||
const { form } = useFormBlockContext();
|
const { form } = useFormBlockContext();
|
||||||
|
const ctx = useBlockRequestContext();
|
||||||
const field = useField<Field>();
|
const field = useField<Field>();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -111,7 +112,6 @@ FormItem.Designer = function Designer() {
|
|||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const variablesCtx = useVariablesCtx();
|
const variablesCtx = useVariablesCtx();
|
||||||
const IsShowMultipleSwitch = useIsShowMultipleSwitch();
|
const IsShowMultipleSwitch = useIsShowMultipleSwitch();
|
||||||
|
|
||||||
const collectionField = getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
const collectionField = getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
||||||
if (collectionField?.target) {
|
if (collectionField?.target) {
|
||||||
targetField = getCollectionJoinField(
|
targetField = getCollectionJoinField(
|
||||||
@ -447,11 +447,16 @@ FormItem.Designer = function Designer() {
|
|||||||
properties: {
|
properties: {
|
||||||
filter: {
|
filter: {
|
||||||
default: defaultFilter,
|
default: defaultFilter,
|
||||||
// title: '数据范围',
|
|
||||||
enum: dataSource,
|
enum: dataSource,
|
||||||
'x-component': 'Filter',
|
'x-component': 'Filter',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
dynamicComponent: (props) => FilterDynamicComponent({ ...props }),
|
dynamicComponent: (props) =>
|
||||||
|
FilterDynamicComponent({
|
||||||
|
...props,
|
||||||
|
form,
|
||||||
|
collectionField,
|
||||||
|
rootCollection: ctx.props.collection || ctx.props.resource,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -461,7 +466,6 @@ FormItem.Designer = function Designer() {
|
|||||||
filter = removeNullCondition(filter);
|
filter = removeNullCondition(filter);
|
||||||
_.set(field.componentProps, 'service.params.filter', filter);
|
_.set(field.componentProps, 'service.params.filter', filter);
|
||||||
fieldSchema['x-component-props'] = field.componentProps;
|
fieldSchema['x-component-props'] = field.componentProps;
|
||||||
field.componentProps = field.componentProps;
|
|
||||||
dn.emit('patch', {
|
dn.emit('patch', {
|
||||||
schema: {
|
schema: {
|
||||||
['x-uid']: fieldSchema['x-uid'],
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
@ -878,6 +882,11 @@ export function isFileCollection(collection: Collection) {
|
|||||||
return collection?.template === 'file';
|
return collection?.template === 'file';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extractFirstPart(path) {
|
||||||
|
const firstDotIndex = path.indexOf('.');
|
||||||
|
return firstDotIndex !== -1 ? path.slice(0, firstDotIndex) : path;
|
||||||
|
}
|
||||||
|
|
||||||
FormItem.FilterFormDesigner = FilterFormDesigner;
|
FormItem.FilterFormDesigner = FilterFormDesigner;
|
||||||
|
|
||||||
export function getFieldDefaultValue(fieldSchema: ISchema, collectionField: CollectionFieldOptions) {
|
export function getFieldDefaultValue(fieldSchema: ISchema, collectionField: CollectionFieldOptions) {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { LoadingOutlined } from '@ant-design/icons';
|
import { LoadingOutlined } from '@ant-design/icons';
|
||||||
import { connect, mapProps, mapReadPretty, useField, useFieldSchema } from '@formily/react';
|
import { connect, mapProps, mapReadPretty, useField, useFieldSchema, useForm } from '@formily/react';
|
||||||
import { SelectProps, Tag, Empty, Divider } from 'antd';
|
import { SelectProps, Tag, Empty, Divider } from 'antd';
|
||||||
import { uniqBy } from 'lodash';
|
import { uniqBy } from 'lodash';
|
||||||
|
import flat from 'flat';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { ResourceActionOptions, useRequest } from '../../../api-client';
|
import { ResourceActionOptions, useRequest } from '../../../api-client';
|
||||||
@ -9,7 +10,9 @@ import { mergeFilter } from '../../../block-provider/SharedFilterProvider';
|
|||||||
import { useCollection, useCollectionManager } from '../../../collection-manager';
|
import { useCollection, useCollectionManager } from '../../../collection-manager';
|
||||||
import { Select, defaultFieldNames } from '../select';
|
import { Select, defaultFieldNames } from '../select';
|
||||||
import { ReadPretty } from './ReadPretty';
|
import { ReadPretty } from './ReadPretty';
|
||||||
|
import { useBlockRequestContext } from '../../../block-provider/BlockProvider';
|
||||||
|
import { getInnermostKeyAndValue } from '../../common/utils/uitls';
|
||||||
|
import { parseVariables, extractFilterfield, generatePattern, extractValuesByPattern } from './utils';
|
||||||
const EMPTY = 'N/A';
|
const EMPTY = 'N/A';
|
||||||
|
|
||||||
export type RemoteSelectProps<P = any> = SelectProps<P, any> & {
|
export type RemoteSelectProps<P = any> = SelectProps<P, any> & {
|
||||||
@ -39,10 +42,12 @@ const InternalRemoteSelect = connect(
|
|||||||
...others
|
...others
|
||||||
} = props;
|
} = props;
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
const form = useForm();
|
||||||
const firstRun = useRef(false);
|
const firstRun = useRef(false);
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const isQuickAdd = fieldSchema['x-component-props']?.addMode === 'quickAdd';
|
const isQuickAdd = fieldSchema['x-component-props']?.addMode === 'quickAdd';
|
||||||
const field = useField();
|
const field = useField();
|
||||||
|
const ctx = useBlockRequestContext();
|
||||||
const { getField } = useCollection();
|
const { getField } = useCollection();
|
||||||
const searchData = useRef(null);
|
const searchData = useRef(null);
|
||||||
const { getCollectionJoinField, getInterface } = useCollectionManager();
|
const { getCollectionJoinField, getInterface } = useCollectionManager();
|
||||||
@ -115,6 +120,48 @@ const InternalRemoteSelect = connect(
|
|||||||
},
|
},
|
||||||
[targetField?.uiSchema, fieldNames],
|
[targetField?.uiSchema, fieldNames],
|
||||||
);
|
);
|
||||||
|
const parseFilter = (rules) => {
|
||||||
|
if (!rules) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const type = Object.keys(rules)[0] || '$and';
|
||||||
|
const conditions = rules[type];
|
||||||
|
const results = [];
|
||||||
|
conditions?.forEach((c) => {
|
||||||
|
const jsonlogic = getInnermostKeyAndValue(c);
|
||||||
|
const regex = /{{(.*?)}}/;
|
||||||
|
const matches = jsonlogic.value?.match?.(regex);
|
||||||
|
if (!matches || (!matches[1].includes('$form') && !matches[1].includes('$iteration'))) {
|
||||||
|
results.push(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const associationfield = extractFilterfield(matches[1]);
|
||||||
|
const filterCollectionField = getCollectionJoinField(`${ctx.props.collection}.${associationfield}`);
|
||||||
|
if (['o2m', 'm2m'].includes(filterCollectionField?.interface)) {
|
||||||
|
// 对多子表单
|
||||||
|
const pattern = generatePattern(matches?.[1], associationfield);
|
||||||
|
const parseValue: any = extractValuesByPattern(flat(form.values), pattern);
|
||||||
|
const filters = parseValue.map((v) => {
|
||||||
|
return JSON.parse(JSON.stringify(c).replace(jsonlogic.value, v));
|
||||||
|
});
|
||||||
|
results.push({ $or: filters });
|
||||||
|
} else {
|
||||||
|
const variablesCtx = { $form: form.values, $iteration: form.values };
|
||||||
|
let str = matches?.[1];
|
||||||
|
if (str.includes('$iteration')) {
|
||||||
|
const path = field.path.segments.concat([]);
|
||||||
|
path.pop();
|
||||||
|
str = str.replace('$iteration.', `$iteration.${path.join('.')}.`);
|
||||||
|
}
|
||||||
|
const parseValue = parseVariables(str, variablesCtx);
|
||||||
|
const filterObj = JSON.parse(
|
||||||
|
JSON.stringify(c).replace(jsonlogic.value, str.endsWith('id') ? parseValue ?? 0 : parseValue),
|
||||||
|
);
|
||||||
|
results.push(filterObj);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { [type]: results };
|
||||||
|
};
|
||||||
|
|
||||||
const { data, run, loading } = useRequest(
|
const { data, run, loading } = useRequest(
|
||||||
{
|
{
|
||||||
@ -123,9 +170,8 @@ const InternalRemoteSelect = connect(
|
|||||||
params: {
|
params: {
|
||||||
pageSize: 200,
|
pageSize: 200,
|
||||||
...service?.params,
|
...service?.params,
|
||||||
// fields: [fieldNames.label, fieldNames.value, ...(service?.params?.fields || [])],
|
|
||||||
// search needs
|
// search needs
|
||||||
filter: mergeFilter([field.componentProps?.service?.params?.filter || service?.params?.filter]),
|
filter: mergeFilter([parseFilter(field.componentProps?.service?.params?.filter) || service?.params?.filter]),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -183,15 +229,11 @@ const InternalRemoteSelect = connect(
|
|||||||
if (!data?.data?.length) {
|
if (!data?.data?.length) {
|
||||||
return value != null ? (Array.isArray(value) ? value : [value]) : [];
|
return value != null ? (Array.isArray(value) ? value : [value]) : [];
|
||||||
}
|
}
|
||||||
const valueOptions = (value != null && (Array.isArray(value) ? value : [value])) || [];
|
return uniqBy(data?.data || [], fieldNames.value);
|
||||||
return uniqBy(data?.data?.concat(valueOptions) || [], fieldNames.value);
|
|
||||||
}, [data?.data, value]);
|
}, [data?.data, value]);
|
||||||
const onDropdownVisibleChange = (visible) => {
|
const onDropdownVisibleChange = (visible) => {
|
||||||
setOpen(visible);
|
setOpen(visible);
|
||||||
searchData.current = null;
|
searchData.current = null;
|
||||||
if (firstRun.current && data?.data.length > 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
run();
|
run();
|
||||||
firstRun.current = true;
|
firstRun.current = true;
|
||||||
};
|
};
|
||||||
@ -238,7 +280,12 @@ const InternalRemoteSelect = connect(
|
|||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
return {
|
return {
|
||||||
...props,
|
...props,
|
||||||
fieldNames: { ...defaultFieldNames, ...props.fieldNames, ...field.componentProps.fieldNames,...fieldSchema['x-component-props']?.fieldNames },
|
fieldNames: {
|
||||||
|
...defaultFieldNames,
|
||||||
|
...props.fieldNames,
|
||||||
|
...field.componentProps.fieldNames,
|
||||||
|
...fieldSchema['x-component-props']?.fieldNames,
|
||||||
|
},
|
||||||
suffixIcon: field?.['loading'] || field?.['validating'] ? <LoadingOutlined /> : props.suffixIcon,
|
suffixIcon: field?.['loading'] || field?.['validating'] ? <LoadingOutlined /> : props.suffixIcon,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
import { get, isFunction } from 'lodash';
|
||||||
|
|
||||||
|
export const parseVariables = (str: string, ctx) => {
|
||||||
|
if (str) {
|
||||||
|
const result = get(ctx, str);
|
||||||
|
return isFunction(result) ? result() : result;
|
||||||
|
} else {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export function extractFilterfield(str) {
|
||||||
|
const match = str.match(/^\$form\.([^.[\]]+)/);
|
||||||
|
if (match) {
|
||||||
|
return match[1];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function extractValuesByPattern(obj, pattern) {
|
||||||
|
const regexPattern = new RegExp(pattern.replace(/\*/g, '\\d+'));
|
||||||
|
const result = [];
|
||||||
|
|
||||||
|
for (const key in obj) {
|
||||||
|
if (regexPattern.test(key)) {
|
||||||
|
const value = obj[key];
|
||||||
|
result.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
export function generatePattern(str, fieldName) {
|
||||||
|
const result = str.replace(`$form.${fieldName}.`, `${fieldName}.*.`);
|
||||||
|
return result;
|
||||||
|
}
|
@ -3,8 +3,8 @@ import { useVariableOptions } from '../../../schema-settings/VariableInput/hooks
|
|||||||
import { Variable } from '../variable';
|
import { Variable } from '../variable';
|
||||||
|
|
||||||
export function FilterDynamicComponent(props) {
|
export function FilterDynamicComponent(props) {
|
||||||
const { value, onChange, renderSchemaComponent } = props;
|
const { value, onChange, renderSchemaComponent, form, collectionField, ...other } = props;
|
||||||
const options = useVariableOptions();
|
const options = useVariableOptions({ form, collectionField, ...other });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Variable.Input value={value} onChange={onChange} scope={options}>
|
<Variable.Input value={value} onChange={onChange} scope={options}>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
import flat from 'flat';
|
import flat from 'flat';
|
||||||
import _, { every, findIndex, isArray, some } from 'lodash';
|
import _, { every, findIndex, isArray, some } from 'lodash';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
@ -13,7 +14,6 @@ type VariablesCtx = {
|
|||||||
|
|
||||||
export const useVariablesCtx = (): VariablesCtx => {
|
export const useVariablesCtx = (): VariablesCtx => {
|
||||||
const { data } = useCurrentUserContext() || {};
|
const { data } = useCurrentUserContext() || {};
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
return {
|
return {
|
||||||
$user: data?.data || {},
|
$user: data?.data || {},
|
||||||
@ -44,7 +44,7 @@ export const parseVariables = (str: string, ctx: VariablesCtx) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function getInnermostKeyAndValue(obj) {
|
export function getInnermostKeyAndValue(obj) {
|
||||||
if (typeof obj !== 'object' || obj === null) {
|
if (typeof obj !== 'object' || obj === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,118 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useCompile, useGetFilterOptions } from '../../../schema-component';
|
||||||
|
import { Schema } from '@formily/react';
|
||||||
|
import { FieldOption, Option } from '../type';
|
||||||
|
|
||||||
|
interface GetOptionsParams {
|
||||||
|
depth: number;
|
||||||
|
operator?: string;
|
||||||
|
maxDepth: number;
|
||||||
|
count?: number;
|
||||||
|
loadChildren?: (option: Option) => Promise<void>;
|
||||||
|
getFilterOptions?: (collectionName: string) => any[];
|
||||||
|
compile: (value: string) => any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getChildren = (
|
||||||
|
options: FieldOption[],
|
||||||
|
{ depth, maxDepth, loadChildren, compile }: GetOptionsParams,
|
||||||
|
): Option[] => {
|
||||||
|
const result = options
|
||||||
|
.map((option): Option => {
|
||||||
|
if (!option.target) {
|
||||||
|
return {
|
||||||
|
key: option.name,
|
||||||
|
value: option.name,
|
||||||
|
label: compile(option.title),
|
||||||
|
depth,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (depth >= maxDepth) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
key: option.name,
|
||||||
|
value: option.name,
|
||||||
|
label: compile(option.title),
|
||||||
|
children: [],
|
||||||
|
isLeaf: false,
|
||||||
|
field: option,
|
||||||
|
depth,
|
||||||
|
loadChildren,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
export const useFormVariable = ({
|
||||||
|
blockForm,
|
||||||
|
rootCollection,
|
||||||
|
operator,
|
||||||
|
schema,
|
||||||
|
level,
|
||||||
|
}: {
|
||||||
|
blockForm?: any;
|
||||||
|
rootCollection: string;
|
||||||
|
operator?: any;
|
||||||
|
schema: Schema;
|
||||||
|
level?: number;
|
||||||
|
}) => {
|
||||||
|
const compile = useCompile();
|
||||||
|
const getFilterOptions = useGetFilterOptions();
|
||||||
|
const loadChildren = (option: any): Promise<void> => {
|
||||||
|
if (!option.field?.target) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
resolve(void 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}) || [];
|
||||||
|
if (children.length === 0) {
|
||||||
|
option.disabled = true;
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
option.children = children;
|
||||||
|
resolve();
|
||||||
|
|
||||||
|
// 延迟 5 毫秒,防止阻塞主线程,导致 UI 卡顿
|
||||||
|
}, 5);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = useMemo(() => {
|
||||||
|
return (
|
||||||
|
blockForm && {
|
||||||
|
label: `{{t("Current form")}}`,
|
||||||
|
value: '$form',
|
||||||
|
key: '$form',
|
||||||
|
children: [],
|
||||||
|
isLeaf: false,
|
||||||
|
field: {
|
||||||
|
target: rootCollection,
|
||||||
|
},
|
||||||
|
depth: 0,
|
||||||
|
loadChildren,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}, [rootCollection]);
|
||||||
|
return result;
|
||||||
|
};
|
@ -0,0 +1,94 @@
|
|||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useCollectionManager } from '../../../collection-manager';
|
||||||
|
import { useCompile, useGetFilterOptions } from '../../../schema-component';
|
||||||
|
|
||||||
|
interface GetOptionsParams {
|
||||||
|
schema: any;
|
||||||
|
operator?: string;
|
||||||
|
maxDepth: number;
|
||||||
|
count?: number;
|
||||||
|
getFilterOptions: (collectionName: string) => 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) {
|
||||||
|
return {
|
||||||
|
key: option.name,
|
||||||
|
value: option.name,
|
||||||
|
label: option.title,
|
||||||
|
// TODO: 现在是通过组件的名称来过滤能够被选择的选项,这样的坏处是不够精确,后续可以优化
|
||||||
|
// disabled: schema?.['x-component'] !== option.schema?.['x-component'],
|
||||||
|
disabled: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const children =
|
||||||
|
getChildren(getFilterOptions(option.target), {
|
||||||
|
schema,
|
||||||
|
operator,
|
||||||
|
maxDepth,
|
||||||
|
count: count + 1,
|
||||||
|
getFilterOptions,
|
||||||
|
}) || [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
key: option.name,
|
||||||
|
value: option.name,
|
||||||
|
label: option.title,
|
||||||
|
children,
|
||||||
|
disabled: children.every((child) => child.disabled),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useIterationVariable = ({
|
||||||
|
blockForm,
|
||||||
|
collectionField,
|
||||||
|
operator,
|
||||||
|
schema,
|
||||||
|
level,
|
||||||
|
rootCollection,
|
||||||
|
}: {
|
||||||
|
blockForm?: any;
|
||||||
|
collectionField: any;
|
||||||
|
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));
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
getChildren(allowFields, {
|
||||||
|
schema,
|
||||||
|
operator,
|
||||||
|
maxDepth: level || 3,
|
||||||
|
getFilterOptions,
|
||||||
|
}) || []
|
||||||
|
);
|
||||||
|
}, [operator, schema, blockForm]);
|
||||||
|
|
||||||
|
return useMemo(() => {
|
||||||
|
return rootCollection !== collectionField?.collectionName && children.length > 0
|
||||||
|
? compile({
|
||||||
|
label: `{{t("Current object")}}`,
|
||||||
|
value: '$iteration',
|
||||||
|
key: '$iteration',
|
||||||
|
disabled: children.every((option) => option.disabled),
|
||||||
|
children: children,
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
}, [children]);
|
||||||
|
};
|
@ -2,13 +2,20 @@ import { useMemo } from 'react';
|
|||||||
import { useValues } from '../../../schema-component/antd/filter/useValues';
|
import { useValues } from '../../../schema-component/antd/filter/useValues';
|
||||||
import { useDateVariable } from './useDateVariable';
|
import { useDateVariable } from './useDateVariable';
|
||||||
import { useUserVariable } from './useUserVariable';
|
import { useUserVariable } from './useUserVariable';
|
||||||
|
import { useFormVariable } from './useFormVariable';
|
||||||
|
import { useIterationVariable } from './useIterationVariable';
|
||||||
|
|
||||||
export const useVariableOptions = () => {
|
export const useVariableOptions = ({ form, collectionField, rootCollection }) => {
|
||||||
const { operator, schema } = useValues();
|
const { operator, schema } = useValues();
|
||||||
const userVariable = useUserVariable({ maxDepth: 3, schema });
|
const userVariable = useUserVariable({ maxDepth: 3, schema });
|
||||||
const dateVariable = useDateVariable({ operator, schema });
|
const dateVariable = useDateVariable({ operator, schema });
|
||||||
|
const formVariabele = useFormVariable({ blockForm: form, rootCollection, schema });
|
||||||
|
const iterationVariabele = useIterationVariable({ blockForm: form, collectionField, schema, rootCollection });
|
||||||
|
|
||||||
const result = useMemo(() => [userVariable, dateVariable], [dateVariable, userVariable]);
|
const result = useMemo(
|
||||||
|
() => [userVariable, dateVariable, formVariabele, iterationVariabele].filter(Boolean),
|
||||||
|
[dateVariable, userVariable, formVariabele, iterationVariabele],
|
||||||
|
);
|
||||||
|
|
||||||
if (!operator || !schema) return [];
|
if (!operator || !schema) return [];
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user