From dc4754750d916dcae87995682baf23684a64b36a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=AB=E9=9B=A8=E6=B0=B4=E8=BF=87=E6=BB=A4=E7=9A=84?= =?UTF-8?q?=E7=A9=BA=E6=B0=94-Rain?= <958414905@qq.com> Date: Sat, 21 Oct 2023 10:19:34 +0800 Subject: [PATCH] fix(variable): fix currentObject (#2887) * fix(variable): fix currentObject * refactor: rename --- .../antd/association-field/Nester.tsx | 46 ++++++++-------- .../antd/association-field/hooks.ts | 53 +++++++++++++------ .../form-item/hooks/useParseDefaultValue.ts | 5 +- .../schema-component/antd/table-v2/Table.tsx | 29 +++++----- 4 files changed, 82 insertions(+), 51 deletions(-) diff --git a/packages/core/client/src/schema-component/antd/association-field/Nester.tsx b/packages/core/client/src/schema-component/antd/association-field/Nester.tsx index 8c85bfe86..d32951028 100644 --- a/packages/core/client/src/schema-component/antd/association-field/Nester.tsx +++ b/packages/core/client/src/schema-component/antd/association-field/Nester.tsx @@ -19,7 +19,7 @@ import { } from '../../../schema-settings/hooks/useIsAllowToSetDefaultValue'; import { LocalVariablesProvider } from '../../../variables/hooks/useLocalVariables'; import { AssociationFieldContext } from './context'; -import { useAssociationFieldContext } from './hooks'; +import { SubFormProvider, useAssociationFieldContext } from './hooks'; export const Nester = (props) => { const { options } = useContext(AssociationFieldContext); @@ -78,13 +78,15 @@ const ToOneNester = (props) => { return ( - - - - {props.children} - - - + + + + + {props.children} + + + + ); }; @@ -186,19 +188,21 @@ const ToManyNester = observer( )} - - - - - - - - - + + + + + + + + + + + diff --git a/packages/core/client/src/schema-component/antd/association-field/hooks.ts b/packages/core/client/src/schema-component/antd/association-field/hooks.ts index 40fff237c..2296ae9fe 100644 --- a/packages/core/client/src/schema-component/antd/association-field/hooks.ts +++ b/packages/core/client/src/schema-component/antd/association-field/hooks.ts @@ -1,10 +1,10 @@ import { GeneralField } from '@formily/core'; import { useField, useFieldSchema } from '@formily/react'; import { reaction } from '@formily/reactive'; -import { flatten } from '@nocobase/utils/client'; +import { flatten, getValuesByPath } from '@nocobase/utils/client'; import _, { isString } from 'lodash'; import cloneDeep from 'lodash/cloneDeep'; -import { useCallback, useContext, useEffect, useMemo, useState } from 'react'; +import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'; import { useFormBlockContext } from '../../../block-provider'; import { mergeFilter } from '../../../block-provider/SharedFilterProvider'; import { useCollection, useCollectionManager } from '../../../collection-manager'; @@ -58,6 +58,7 @@ export default function useServiceOptions(props) { const { parseFilter } = useParseDataScopeFilter(); const [fieldServiceFilter, setFieldServiceFilter] = useState(null); const { form } = useFormBlockContext(); + const { formValue: subFormValue } = useSubFormValue(); useEffect(() => { const filterFromSchema = isString(fieldSchema?.['x-component-props']?.service?.params?.filter) @@ -72,7 +73,7 @@ export default function useServiceOptions(props) { _run(); - reaction(() => { + const dispose = reaction(() => { // 这一步主要是为了使 reaction 能够收集到依赖 const flat = flatten(filterFromSchema, { breakOn({ key }) { @@ -82,16 +83,28 @@ export default function useServiceOptions(props) { if (!isVariable(value)) { return value; } - const result = _.get({ $nForm: form?.values }, getPath(value)); + const result = getValuesByPath( + { + $nForm: form?.values, + $iteration: subFormValue, + }, + getPath(value), + ); return result; }, }); return flat; }, run); + + return dispose; }, [ field.componentProps?.service?.params?.filter, - fieldSchema?.['x-component-props']?.service?.params?.filter, + fieldSchema, + form?.values, + parseFilter, + record, service?.params?.filter, + subFormValue, ]); const normalizeValues = useCallback( @@ -160,16 +173,7 @@ export default function useServiceOptions(props) { ], '$or', ); - }, [ - collectionField?.interface, - collectionField?.foreignKey, - fieldSchema, - fieldServiceFilter, - sourceValue, - params?.filter, - value, - fieldNames?.value, - ]); + }, [collectionField?.interface, collectionField.foreignKey, fieldSchema, fieldServiceFilter, sourceValue]); return useMemo(() => { return { @@ -189,3 +193,22 @@ export const useFieldNames = (props) => { props.fieldNames; return { label: 'label', value: 'value', ...fieldNames }; }; + +const SubFormContext = createContext>(null); +export const SubFormProvider = SubFormContext.Provider; + +/** + * 用于获取子表单所对应的 form 对象,其应该保持响应性,即一个 Proxy 对象; + * + * ## 为什么要有这个方法? + * 1. 目前使用 useForm 方法获取到的是普通表单区块的 form 对象,无法通过简单的方法获取到子表单对应的 form 对象; + * 2. 虽然现在 useRecord 也可以获取到相同值的对象,但是这个对象不是响应式的(因其内部 copy 过一次),字段值变更时无法监听到; + * 3. 可能更好的方式是在 useForm 返回的 form 对象添加一个 parent 属性,但可能会影响其它部分的代码,所以暂时不做修改; + * @returns + */ +export const useSubFormValue = () => { + const context = useContext(SubFormContext); + return { + formValue: context, + }; +}; 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 c84da9bcf..33d3c9499 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 @@ -1,6 +1,7 @@ import { Field } from '@formily/core'; import { useField, useFieldSchema } from '@formily/react'; import { reaction } from '@formily/reactive'; +import { getValuesByPath } from '@nocobase/utils/client'; import _ from 'lodash'; import { useEffect } from 'react'; import { useRecord, useRecordIndex } from '../../../../../src/record-provider'; @@ -102,12 +103,12 @@ const useParseDefaultValue = () => { const path = getPath(fieldSchema.default); // fix https://nocobase.height.app/T-2212 - if (_.get(obj, path) === undefined) { + if (getValuesByPath(obj, path) === undefined) { // 返回一个随机值,确保能触发 run 函数 return Math.random(); } - return _.get(obj, path); + return getValuesByPath(obj, path); }, run); return dispose; diff --git a/packages/core/client/src/schema-component/antd/table-v2/Table.tsx b/packages/core/client/src/schema-component/antd/table-v2/Table.tsx index ed41f61c6..5ef064adb 100644 --- a/packages/core/client/src/schema-component/antd/table-v2/Table.tsx +++ b/packages/core/client/src/schema-component/antd/table-v2/Table.tsx @@ -24,6 +24,7 @@ import { import { useACLFieldWhitelist } from '../../../acl/ACLProvider'; import { LocalVariablesProvider } from '../../../variables/hooks/useLocalVariables'; import { useToken } from '../__builtins__'; +import { SubFormProvider } from '../association-field/hooks'; import { ColumnFieldProvider } from './components/ColumnFieldProvider'; import { extractIndex, isCollectionFieldComponent, isColumnComponent } from './utils'; @@ -62,19 +63,21 @@ const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) => render: (v, record) => { const index = field.value?.indexOf(record); return ( - - - - - - - - - + + + + + + + + + + + ); }, } as TableColumnProps;