diff --git a/packages/core/client/src/schema-component/antd/action/Action.tsx b/packages/core/client/src/schema-component/antd/action/Action.tsx index bc03713be..b23c1e8b5 100644 --- a/packages/core/client/src/schema-component/antd/action/Action.tsx +++ b/packages/core/client/src/schema-component/antd/action/Action.tsx @@ -66,6 +66,7 @@ export const Action: ComposedAction = observer( let actionTitle = title || compile(fieldSchema.title); actionTitle = lodash.isString(actionTitle) ? t(actionTitle) : actionTitle; useEffect(() => { + field.linkageProperty = {}; linkageRules .filter((k) => !k.disabled) .forEach((v) => { diff --git a/packages/core/client/src/schema-component/antd/action/utils.ts b/packages/core/client/src/schema-component/antd/action/utils.ts index c43e27eea..3d282019a 100644 --- a/packages/core/client/src/schema-component/antd/action/utils.ts +++ b/packages/core/client/src/schema-component/antd/action/utils.ts @@ -1,7 +1,9 @@ import type { ISchema } from '@formily/react'; +import { last } from 'lodash'; import { ActionType } from '../../../schema-settings/LinkageRules/type'; import { VariableOption, VariablesContextType } from '../../../variables/types'; import { conditionAnalyses } from '../../common/utils/uitls'; + const validateJSON = { validator: `{{(value, rule)=> { if (!value) { @@ -84,54 +86,52 @@ export const linkageAction = async ({ variables: VariablesContextType; localVariables: VariableOption[]; }) => { - field.data = field.data || {}; + const disableResult = field?.linkageProperty?.disabled || [false]; + const displayResult = field?.linkageProperty?.display || ['visible']; switch (operator) { case ActionType.Visible: - reset(field); if (await conditionAnalyses({ rules: condition, formValues: values, variables, localVariables })) { - field._display = '_display' in field ? field._display : field.display; - field.display = operator; - } else { - field.display = field._display; + displayResult.push(operator); + field.data = field.data || {}; + field.data.hidden = false; } + field.linkageProperty = { + ...field.linkageProperty, + display: displayResult, + }; + field.display = last(displayResult); break; case ActionType.Hidden: - reset(field); if (await conditionAnalyses({ rules: condition, formValues: values, variables, localVariables })) { + field.data = field.data || {}; field.data.hidden = true; } else { + field.data = field.data || {}; field.data.hidden = false; } break; case ActionType.Disabled: - reset(field); if (await conditionAnalyses({ rules: condition, formValues: values, variables, localVariables })) { - field.data.disabled = true; - field.disabled = true; - } else { - field.data.disabled = false; - field.disabled = false; + disableResult.push(true); } + field.linkageProperty = { + ...field.linkageProperty, + disabled: disableResult, + }; + field.disabled = last(disableResult); break; case ActionType.Active: - reset(field); if (await conditionAnalyses({ rules: condition, formValues: values, variables, localVariables })) { - field.data.disabled = false; - field.disabled = false; - } else { - field.data.disabled = true; - field.disabled = true; + disableResult.push(false); } + field.linkageProperty = { + ...field.linkageProperty, + disabled: disableResult, + }; + field.disabled = last(disableResult); break; default: return null; } }; - -function reset(field: any) { - field.display = field._display; - field.data.hidden = false; - field.data.disabled = false; - field.disabled = false; -} diff --git a/packages/core/client/src/schema-component/antd/form-v2/Form.tsx b/packages/core/client/src/schema-component/antd/form-v2/Form.tsx index 2558c8370..35f048005 100644 --- a/packages/core/client/src/schema-component/antd/form-v2/Form.tsx +++ b/packages/core/client/src/schema-component/antd/form-v2/Form.tsx @@ -1,6 +1,6 @@ import { css } from '@emotion/css'; import { FormLayout } from '@formily/antd-v5'; -import { createForm, Field, Form as FormilyForm, onFieldInit, onFormInputChange } from '@formily/core'; +import { createForm, Field, Form as FormilyForm, onFieldChange, onFieldInit, onFormInputChange } from '@formily/core'; import { FieldContext, FormContext, observer, RecursionField, useField, useFieldSchema } from '@formily/react'; import { autorun } from '@formily/reactive'; import { uid } from '@formily/shared'; @@ -103,31 +103,32 @@ const WithForm = (props: WithFormProps) => { useEffect(() => { const id = uid(); const disposes = []; + const linkagefields = []; form.addEffects(id, () => { - linkageRules.forEach((v) => { + linkageRules.forEach((v, index) => { v.actions?.forEach((h) => { if (h.targetFields?.length) { const fields = h.targetFields.join(','); - - // 当 `linkageRules` 变更时,需要把 `field` 上之前已设置的值还原成初始值,以防止下面所述的情况: - // - // 1. 更改 `linkageRules`,使 a 字段满足条件时被隐藏 - // 2. 设置表单,使其满足条件,进而隐藏 a 字段 - // 3. 再次更改 `linkageRules`,使 a 字段满足条件时被禁用 - // 4. 设置表单,使其满足条件,会发现 a 字段还是隐藏状态,这里期望的是只显示禁用状态 - onFieldInit(`*(${fields})`, (field: any) => { - Object.keys(field).forEach((key) => { - if (key.startsWith('_') && field[key] !== undefined) { - field[key.slice(1)] = field[key]; - } - }); + onFieldInit(`*(${fields})`, (field: any, form) => { + field['initProperty'] = { + display: field.display, + required: field.required, + pattern: field.pattern, + value: field.value || field.initialValue, + }; + }); + onFieldChange(`*(${fields})`, ['value', 'required', 'pattern', 'display'], (field: any) => { + field.linkageProperty = { + display: field.linkageProperty?.display, + }; }); // `onFieldReact` 有问题,没有办法被取消监听,所以这里用 `onFieldInit` 代替 onFieldInit(`*(${fields})`, (field: any, form) => { disposes.push( autorun(() => { + linkagefields.push(field); linkageMergeAction({ operator: h.operator, value: h.value, @@ -137,6 +138,13 @@ const WithForm = (props: WithFormProps) => { variables, localVariables, }); + if (index === linkageRules.length - 1) { + setTimeout(() => + linkagefields.map((v) => { + v.linkageProperty = {}; + }), + ); + } }), ); }); @@ -151,7 +159,7 @@ const WithForm = (props: WithFormProps) => { dispose(); }); }; - }, [JSON.stringify(linkageRules)]); + }, [linkageRules]); return fieldSchema['x-decorator'] === 'FormV2' ? : ; }; diff --git a/packages/core/client/src/schema-component/antd/form-v2/utils.tsx b/packages/core/client/src/schema-component/antd/form-v2/utils.tsx index f21b60437..c7b5e79aa 100644 --- a/packages/core/client/src/schema-component/antd/form-v2/utils.tsx +++ b/packages/core/client/src/schema-component/antd/form-v2/utils.tsx @@ -1,7 +1,7 @@ import { Field } from '@formily/core'; import { evaluators } from '@nocobase/evaluators/client'; import { uid } from '@nocobase/utils'; -import _, { cloneDeep } from 'lodash'; +import _, { cloneDeep, last } from 'lodash'; import { ActionType } from '../../../schema-settings/LinkageRules/type'; import { VariableOption, VariablesContextType } from '../../../variables/types'; import { REGEX_OF_VARIABLE } from '../../../variables/utils/isVariable'; @@ -28,47 +28,62 @@ export const linkageMergeAction = async ({ variables, localVariables, }: Props) => { + const requiredResult = field?.linkageProperty?.required || [field?.initProperty?.required || false]; + const displayResult = field?.linkageProperty?.display || [field?.initProperty?.display]; + const patternResult = field?.linkageProperty?.pattern || [field?.initProperty?.pattern]; + const valueResult = field?.linkageProperty?.value || [field.value || field?.initProperty?.value]; const { evaluate } = evaluators.get('formula.js'); switch (operator) { case ActionType.Required: if (await conditionAnalyses({ rules: condition, formValues: values, variables, localVariables })) { - field.required = true; - } else { - field.required = false; + requiredResult.push(true); } + field.linkageProperty = { + ...field.linkageProperty, + required: requiredResult, + }; + field.required = last(field.linkageProperty?.required); break; case ActionType.InRequired: if (await conditionAnalyses({ rules: condition, formValues: values, variables, localVariables })) { - field.required = false; - } else { - field.required = true; + requiredResult.push(false); } + field.linkageProperty = { + ...field.linkageProperty, + required: requiredResult, + }; + field.required = last(field.linkageProperty?.required); break; case ActionType.Visible: case ActionType.None: case ActionType.Hidden: if (await conditionAnalyses({ rules: condition, formValues: values, variables, localVariables })) { - field._display = '_display' in field ? field._display : field.display; - field.display = operator; + displayResult.push(operator); } + field.linkageProperty = { + ...field.linkageProperty, + display: displayResult, + }; + field.display = last(field.linkageProperty?.display); break; case ActionType.Editable: case ActionType.ReadOnly: case ActionType.ReadPretty: if (await conditionAnalyses({ rules: condition, formValues: values, variables, localVariables })) { - field._pattern = '_pattern' in field ? field._pattern : field.pattern; - field.pattern = operator; - } else { - field.pattern = field._pattern; + patternResult.push(operator); } + field.linkageProperty = { + ...field.linkageProperty, + pattern: patternResult, + }; + field.pattern = last(field.linkageProperty.pattern); break; case ActionType.Value: if ( isConditionEmpty(condition) || (await conditionAnalyses({ rules: condition, formValues: values, variables, localVariables })) ) { - let result = null; if (value?.mode === 'express') { if ((value.value || value.result) == null) { return; @@ -84,19 +99,22 @@ export const linkageMergeAction = async ({ try { // 2. TODO: 需要把里面解析变量的逻辑删除,因为在上一步已经解析过了 - result = evaluate(exp, { ...scope, now: () => new Date().toString(), ...expScope }); + const result = evaluate(exp, { ...scope, now: () => new Date().toString(), ...expScope }); + valueResult.push(result); } catch (error) { console.error(error); } } else if (value?.mode === 'constant') { - result = value?.value || value; + valueResult.push(value?.value || value); } else { - result = null; + valueResult.push(null); } - field._value = '_value' in field ? field._value : field.value; - field.value = result === undefined ? field.value : result; - } else { - field.value = field._value; + + field.linkageProperty = { + ...field.linkageProperty, + value: valueResult, + }; + field.value = last(valueResult) === undefined ? field.value : last(valueResult); } break; default: diff --git a/packages/core/client/src/schema-initializer/components/CreateRecordAction.tsx b/packages/core/client/src/schema-initializer/components/CreateRecordAction.tsx index 3d5cd54ad..66c31c724 100644 --- a/packages/core/client/src/schema-initializer/components/CreateRecordAction.tsx +++ b/packages/core/client/src/schema-initializer/components/CreateRecordAction.tsx @@ -97,6 +97,7 @@ export const CreateRecordAction = observer( const localVariables = useLocalVariables({ currentForm: { values } as any }); useEffect(() => { + field.linkageProperty = {}; linkageRules .filter((k) => !k.disabled) .forEach((v) => { @@ -201,6 +202,7 @@ export const CreateAction = observer( }, [menuItems]); useEffect(() => { + field.linkageProperty = {}; linkageRules .filter((k) => !k.disabled) .forEach((v) => {