diff --git a/packages/core/client/src/schema-component/antd/form-item/hooks/useParseDefaultValue.ts b/packages/core/client/src/schema-component/antd/form-item/hooks/useParseDefaultValue.ts index 95887953d..c84da9bcf 100644 --- a/packages/core/client/src/schema-component/antd/form-item/hooks/useParseDefaultValue.ts +++ b/packages/core/client/src/schema-component/antd/form-item/hooks/useParseDefaultValue.ts @@ -2,8 +2,9 @@ import { Field } from '@formily/core'; import { useField, useFieldSchema } from '@formily/react'; import { reaction } from '@formily/reactive'; import _ from 'lodash'; -import { useEffect, useRef } from 'react'; +import { useEffect } from 'react'; import { useRecord, useRecordIndex } from '../../../../../src/record-provider'; +import { useFormBlockType } from '../../../../block-provider/FormBlockProvider'; import { useCollection } from '../../../../collection-manager'; import { useFlag } from '../../../../flag-provider'; import { DEBOUNCE_WAIT, useLocalVariables, useVariables } from '../../../../variables'; @@ -27,9 +28,7 @@ const useParseDefaultValue = () => { const { getField } = useCollection(); const { isSpecialCase, setDefaultValue } = useSpecialCase(); const index = useRecordIndex(); - - // 需要保存 record 的初始值,因为设置默认值的时候 record 会被修改,导致初始值丢失 - const recordRef = useRef(_.omit(record, '__parent')); + const { type: formBlockType } = useFormBlockType(); useEffect(() => { if ( @@ -37,8 +36,8 @@ const useParseDefaultValue = () => { isInSetDefaultValueDialog || isInFormDataTemplate || isSubMode(fieldSchema) || - // 根据 record 是否为空,判断当前是否是新建状态,编辑状态下不需要设置默认值,否则会覆盖用户输入的值,只有新建状态下才需要设置默认值 - (!_.isEmpty(recordRef.current) && isFromDatabase(record) && !isInAssignFieldValues) + // 编辑状态下不需要设置默认值,否则会覆盖用户输入的值,只有新建状态下才需要设置默认值 + (formBlockType === 'update' && isFromDatabase(record) && !isInAssignFieldValues) ) { return; } @@ -99,7 +98,16 @@ const useParseDefaultValue = () => { if (variableValue) { // 实现联动的效果,当依赖的变量变化时(如 `$nForm` 变量),重新解析默认值 const dispose = reaction(() => { - return _.get({ [variableName]: variableValue?.ctx }, getPath(fieldSchema.default)); + const obj = { [variableName]: variableValue?.ctx }; + const path = getPath(fieldSchema.default); + + // fix https://nocobase.height.app/T-2212 + if (_.get(obj, path) === undefined) { + // 返回一个随机值,确保能触发 run 函数 + return Math.random(); + } + + return _.get(obj, path); }, run); return dispose; 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 2ac53d1eb..f21b60437 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 @@ -70,6 +70,10 @@ export const linkageMergeAction = async ({ ) { let result = null; if (value?.mode === 'express') { + if ((value.value || value.result) == null) { + return; + } + const scope = cloneDeep(values); // 1. 解析如 `{{$user.name}}` 之类的变量 @@ -113,6 +117,10 @@ async function replaceVariables( const store = {}; const scope = {}; + if (value == null) { + return; + } + const waitForParsing = value.match(REGEX_OF_VARIABLE)?.map(async (item) => { const result = await variables.parseVariable(item, localVariables); diff --git a/packages/core/client/src/schema-settings/LinkageRules/index.tsx b/packages/core/client/src/schema-settings/LinkageRules/index.tsx index 7efe8bc50..20339674e 100644 --- a/packages/core/client/src/schema-settings/LinkageRules/index.tsx +++ b/packages/core/client/src/schema-settings/LinkageRules/index.tsx @@ -22,6 +22,10 @@ interface usePropsReturn { variables: VariablesContextType; localVariables: VariableOption | VariableOption[]; record: Record; + /** + * create 表示创建表单,update 表示更新表单 + */ + formBlockType: 'create' | 'update'; } interface Props { @@ -33,7 +37,8 @@ export const FormLinkageRules = observer( (props: Props) => { const fieldSchema = useFieldSchema(); const { useProps, dynamicComponent } = props; - const { options, defaultValues, collectionName, form, variables, localVariables, record } = useProps(); + const { options, defaultValues, collectionName, form, formBlockType, variables, localVariables, record } = + useProps(); const { getAllCollectionsInheritChain } = useCollectionManager(); const components = useMemo(() => ({ ArrayCollapse }), []); @@ -160,7 +165,7 @@ export const FormLinkageRules = observer( ); return ( - + diff --git a/packages/core/client/src/schema-settings/SchemaSettings.tsx b/packages/core/client/src/schema-settings/SchemaSettings.tsx index 7bddbb484..bb063cfc8 100644 --- a/packages/core/client/src/schema-settings/SchemaSettings.tsx +++ b/packages/core/client/src/schema-settings/SchemaSettings.tsx @@ -64,7 +64,7 @@ import { useRecord, useSortFields, } from '..'; -import { BlockRequestContext, useFormBlockContext, useTableBlockContext } from '../block-provider'; +import { BlockRequestContext, useFormBlockContext, useFormBlockType, useTableBlockContext } from '../block-provider'; import { FormActiveFieldsProvider, findFilterTargets, @@ -1154,6 +1154,7 @@ SchemaSettings.LinkageRules = function LinkageRules(props) { const variables = useVariables(); const localVariables = useLocalVariables(); const record = useRecord(); + const { type: formBlockType } = useFormBlockType(); const type = props?.type || ['Action', 'Action.Link'].includes(fieldSchema['x-component']) ? 'button' : 'field'; const gridSchema = findGridSchema(fieldSchema) || fieldSchema; const schema = useMemo( @@ -1176,6 +1177,7 @@ SchemaSettings.LinkageRules = function LinkageRules(props) { variables, localVariables, record, + formBlockType, }; }, }, diff --git a/packages/core/client/src/schema-settings/VariableInput/hooks/useVariableOptions.ts b/packages/core/client/src/schema-settings/VariableInput/hooks/useVariableOptions.ts index 3f5d957ae..3017f1848 100644 --- a/packages/core/client/src/schema-settings/VariableInput/hooks/useVariableOptions.ts +++ b/packages/core/client/src/schema-settings/VariableInput/hooks/useVariableOptions.ts @@ -1,7 +1,7 @@ import { Form } from '@formily/core'; import { ISchema, Schema } from '@formily/react'; -import _ from 'lodash'; import { useMemo } from 'react'; +import { useFormBlockType } from '../../../block-provider/FormBlockProvider'; import { CollectionFieldOptions } from '../../../collection-manager'; import { useFlag } from '../../../flag-provider'; import { useBlockCollection } from './useBlockCollection'; @@ -20,7 +20,7 @@ interface Props { /** * `useRecord` 返回的值 */ - record: Record; + record?: Record; /** * `Filter` 组件中选中的字段的 `uiSchema`,比如设置 `数据范围` 的时候在左侧选择的字段 */ @@ -40,7 +40,6 @@ interface Props { export const useVariableOptions = ({ collectionField, form, - record, uiSchema, operator, noDisabled, @@ -48,6 +47,7 @@ export const useVariableOptions = ({ }: Props) => { const { name: blockCollectionName } = useBlockCollection(); const { isInSetDefaultValueDialog } = useFlag() || {}; + const { type: formBlockType } = useFormBlockType(); const fieldCollectionName = collectionField?.collectionName; const userVariable = useUserVariable({ @@ -80,10 +80,6 @@ export const useVariableOptions = ({ targetFieldSchema, }); - // 保证下面的 `_.isEmpty(record)` 结果符合预期,如果存在 `__parent` 字段,需要删除 - record = { ...record }; - delete record.__parent; - return useMemo(() => { return [ userVariable, @@ -95,7 +91,7 @@ export const useVariableOptions = ({ fieldCollectionName !== blockCollectionName && isInSetDefaultValueDialog && iterationVariable, - !_.isEmpty(record) && currentRecordVariable, + formBlockType === 'update' && currentRecordVariable, ].filter(Boolean); }, [ userVariable, @@ -106,7 +102,6 @@ export const useVariableOptions = ({ blockCollectionName, isInSetDefaultValueDialog, iterationVariable, - record, currentRecordVariable, ]); };