feat: action linkage rule support current form variables

This commit is contained in:
katherinehhh 2025-04-29 22:12:59 +08:00
parent 0965749f8c
commit 5e3b58d369
2 changed files with 80 additions and 58 deletions

View File

@ -48,8 +48,6 @@ export const BlockLinkageRuleProvider = (props) => {
useEffect(() => { useEffect(() => {
if (shouldCalculateFormLinkage) { if (shouldCalculateFormLinkage) {
const id = uid(); const id = uid();
const disposes = [];
// 延迟执行,防止一开始获取到的 form.values 值是旧的 // 延迟执行,防止一开始获取到的 form.values 值是旧的
setTimeout(() => { setTimeout(() => {
form.addEffects(id, () => { form.addEffects(id, () => {
@ -77,9 +75,6 @@ export const BlockLinkageRuleProvider = (props) => {
// 清理副作用 // 清理副作用
return () => { return () => {
form.removeEffects(id); form.removeEffects(id);
disposes.forEach((dispose) => {
dispose();
});
}; };
} }
}, [linkageRules, shouldCalculateFormLinkage]); }, [linkageRules, shouldCalculateFormLinkage]);

View File

@ -12,10 +12,13 @@ import { observer, Schema, useField, useFieldSchema, useForm } from '@formily/re
import { isPortalInBody } from '@nocobase/utils/client'; import { isPortalInBody } from '@nocobase/utils/client';
import { App, Button, Tooltip } from 'antd'; import { App, Button, Tooltip } from 'antd';
import classnames from 'classnames'; import classnames from 'classnames';
import { isEqual } from 'lodash';
import debounce from 'lodash/debounce'; import debounce from 'lodash/debounce';
import { reaction } from '@formily/reactive';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { ErrorBoundary } from 'react-error-boundary'; import { ErrorBoundary } from 'react-error-boundary';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { uid } from '@formily/shared';
import { ErrorFallback, StablePopover, TabsContextProvider, useActionContext } from '../..'; import { ErrorFallback, StablePopover, TabsContextProvider, useActionContext } from '../..';
import { useDesignable } from '../../'; import { useDesignable } from '../../';
import { useACLActionParamsContext } from '../../../acl'; import { useACLActionParamsContext } from '../../../acl';
@ -29,7 +32,6 @@ import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { Icon } from '../../../icon'; import { Icon } from '../../../icon';
import { TreeRecordProvider } from '../../../modules/blocks/data-blocks/table/TreeRecordProvider'; import { TreeRecordProvider } from '../../../modules/blocks/data-blocks/table/TreeRecordProvider';
import { VariablePopupRecordProvider } from '../../../modules/variable/variablesProvider/VariablePopupRecordProvider'; import { VariablePopupRecordProvider } from '../../../modules/variable/variablesProvider/VariablePopupRecordProvider';
import { RecordProvider } from '../../../record-provider';
import { useLocalVariables, useVariables } from '../../../variables'; import { useLocalVariables, useVariables } from '../../../variables';
import { SortableItem } from '../../common'; import { SortableItem } from '../../common';
import { useCompile, useComponent, useDesigner } from '../../hooks'; import { useCompile, useComponent, useDesigner } from '../../hooks';
@ -49,7 +51,11 @@ import { useGetAriaLabelOfAction } from './hooks/useGetAriaLabelOfAction';
import { ActionContextProps, ActionProps, ComposedAction } from './types'; import { ActionContextProps, ActionProps, ComposedAction } from './types';
import { linkageAction, setInitialActionState } from './utils'; import { linkageAction, setInitialActionState } from './utils';
import { NAMESPACE_UI_SCHEMA } from '../../../i18n/constant'; import { NAMESPACE_UI_SCHEMA } from '../../../i18n/constant';
import { BlockContext } from '../../../block-provider/BlockProvider'; import { forEachLinkageRule } from '../../../schema-settings/LinkageRules/forEachLinkageRule';
import {
getVariableValuesInCondition,
getVariableValuesInExpression,
} from '../../../schema-settings/LinkageRules/bindLinkageRulesToFiled';
// 这个要放到最下面,否则会导致前端单测失败 // 这个要放到最下面,否则会导致前端单测失败
import { useApp } from '../../../application'; import { useApp } from '../../../application';
@ -97,39 +103,62 @@ export const Action: ComposedAction = withDynamicSchemaProps(
const { designable } = useDesignable(); const { designable } = useDesignable();
const tarComponent = useComponent(component) || component; const tarComponent = useComponent(component) || component;
const variables = useVariables(); const variables = useVariables();
const localVariables = useLocalVariables({ const localVariables = useLocalVariables();
currentForm: { values: recordData, readPretty: false } as any,
});
const { visibleWithURL, setVisibleWithURL } = usePopupUtils(); const { visibleWithURL, setVisibleWithURL } = usePopupUtils();
const { setSubmitted } = useActionContext(); const { setSubmitted } = useActionContext();
const { getAriaLabel } = useGetAriaLabelOfAction(title); const { getAriaLabel } = useGetAriaLabelOfAction(title);
const parentRecordData = useCollectionParentRecordData(); const parentRecordData = useCollectionParentRecordData();
const app = useApp(); const app = useApp();
const { getAllDataBlocks } = useAllDataBlocks(); const { getAllDataBlocks } = useAllDataBlocks();
const form = useForm();
useEffect(() => { useEffect(() => {
if (field.stateOfLinkageRules) { if (field.stateOfLinkageRules) {
setInitialActionState(field); setInitialActionState(field);
} }
const id = uid();
const disposes = [];
// 如果不延迟执行,那么一开始获取到的 form.values 的值是旧的,会导致详情区块的联动规则出现一些问题
setTimeout(() => {
form.addEffects(id, () => {
forEachLinkageRule(linkageRules, (action, rule) => {
disposes.push(
reaction(
() => {
// 获取条件中的变量值
const variableValuesInCondition = getVariableValuesInCondition({ linkageRules, localVariables });
const result = [variableValuesInCondition].map((item) => JSON.stringify(item)).join(',');
return result;
},
() => {
console.log(action);
field.stateOfLinkageRules = {}; field.stateOfLinkageRules = {};
linkageRules
.filter((k) => !k.disabled)
.forEach((v) => {
v.actions?.forEach((h) => {
linkageAction( linkageAction(
{ {
operator: h.operator, operator: action.operator,
field, field,
condition: v.condition, condition: rule.condition,
variables, variables,
localVariables, localVariables,
conditionType: v.conditionType, conditionType: rule.conditionType,
}, },
app.jsonLogic, app.jsonLogic,
); );
},
{ fireImmediately: true, equals: isEqual },
),
);
}); });
}); });
}, [field, linkageRules, localVariables, variables]); });
return () => {
form.removeEffects(id);
disposes.forEach((dispose) => {
dispose();
});
};
}, [linkageRules]);
const handleMouseEnter = useCallback( const handleMouseEnter = useCallback(
(e) => { (e) => {
@ -162,7 +191,6 @@ export const Action: ComposedAction = withDynamicSchemaProps(
}, [onClick, fieldSchema, getAllDataBlocks]); }, [onClick, fieldSchema, getAllDataBlocks]);
return ( return (
<BlockContext.Provider value={{ name: 'action' }}>
<InternalAction <InternalAction
containerRefKey={containerRefKey} containerRefKey={containerRefKey}
fieldSchema={fieldSchema} fieldSchema={fieldSchema}
@ -193,7 +221,6 @@ export const Action: ComposedAction = withDynamicSchemaProps(
actionCallback={actionCallback} actionCallback={actionCallback}
{...others} {...others}
/> />
</BlockContext.Provider>
); );
}), }),
{ displayName: 'Action' }, { displayName: 'Action' },