diff --git a/packages/core/client/src/block-provider/hooks/useParsedFilter.ts b/packages/core/client/src/block-provider/hooks/useParsedFilter.ts
index 0e7bf9f2f..8f7bd400b 100644
--- a/packages/core/client/src/block-provider/hooks/useParsedFilter.ts
+++ b/packages/core/client/src/block-provider/hooks/useParsedFilter.ts
@@ -1,17 +1,16 @@
import { reaction } from '@formily/reactive';
-import { flatten } from '@nocobase/utils/client';
+import { flatten, getValuesByPath } from '@nocobase/utils/client';
import _ from 'lodash';
import { useEffect, useState } from 'react';
import { useParseDataScopeFilter } from '../../schema-settings';
import { DEBOUNCE_WAIT } from '../../variables';
import { getPath } from '../../variables/utils/getPath';
+import { getVariableName } from '../../variables/utils/getVariableName';
import { isVariable } from '../../variables/utils/isVariable';
-import { useFormBlockContext } from '../FormBlockProvider';
export function useParsedFilter({ filterOption, currentRecord }: { filterOption: any; currentRecord?: any }) {
- const { parseFilter } = useParseDataScopeFilter({ currentRecord });
+ const { parseFilter, findVariable } = useParseDataScopeFilter({ currentRecord });
const [filter, setFilter] = useState({});
- const { form } = useFormBlockContext();
useEffect(() => {
if (!filterOption) return;
@@ -33,7 +32,19 @@ export function useParsedFilter({ filterOption, currentRecord }: { filterOption:
if (!isVariable(value)) {
return value;
}
- const result = _.get({ $nForm: form?.values }, getPath(value));
+ const variableName = getVariableName(value);
+ const variable = findVariable(variableName);
+
+ if (process.env.NODE_ENV !== 'production' && !variable) {
+ throw new Error(`useParsedFilter: can not find variable ${variableName}`);
+ }
+
+ const result = getValuesByPath(
+ {
+ [variableName]: variable?.ctx || {},
+ },
+ getPath(value),
+ );
return result;
},
});
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 d32951028..742105e26 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
@@ -17,7 +17,6 @@ import {
IsAllowToSetDefaultValueParams,
interfacesOfUnsupportedDefaultValue,
} from '../../../schema-settings/hooks/useIsAllowToSetDefaultValue';
-import { LocalVariablesProvider } from '../../../variables/hooks/useLocalVariables';
import { AssociationFieldContext } from './context';
import { SubFormProvider, useAssociationFieldContext } from './hooks';
@@ -80,11 +79,9 @@ const ToOneNester = (props) => {
-
-
- {props.children}
-
-
+
+ {props.children}
+
@@ -190,17 +187,15 @@ 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 2296ae9fe..94231dab6 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
@@ -5,7 +5,6 @@ import { flatten, getValuesByPath } from '@nocobase/utils/client';
import _, { isString } from 'lodash';
import cloneDeep from 'lodash/cloneDeep';
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';
import { isInFilterFormBlock } from '../../../filter-provider';
@@ -13,6 +12,7 @@ import { useRecord } from '../../../record-provider';
import { useParseDataScopeFilter } from '../../../schema-settings';
import { DEBOUNCE_WAIT } from '../../../variables';
import { getPath } from '../../../variables/utils/getPath';
+import { getVariableName } from '../../../variables/utils/getVariableName';
import { isVariable } from '../../../variables/utils/isVariable';
import { useDesignable } from '../../hooks';
import { AssociationFieldContext } from './context';
@@ -48,17 +48,14 @@ export function useAssociationFieldContext() {
}
export default function useServiceOptions(props) {
- const { action = 'list', service, fieldNames } = props;
- const params = service?.params || {};
+ const { action = 'list', service } = props;
const fieldSchema = useFieldSchema();
const field = useField();
const { getField } = useCollection();
const { getCollectionJoinField } = useCollectionManager();
const record = useRecord();
- const { parseFilter } = useParseDataScopeFilter();
+ const { parseFilter, findVariable } = useParseDataScopeFilter();
const [fieldServiceFilter, setFieldServiceFilter] = useState(null);
- const { form } = useFormBlockContext();
- const { formValue: subFormValue } = useSubFormValue();
useEffect(() => {
const filterFromSchema = isString(fieldSchema?.['x-component-props']?.service?.params?.filter)
@@ -83,10 +80,16 @@ export default function useServiceOptions(props) {
if (!isVariable(value)) {
return value;
}
+ const variableName = getVariableName(value);
+ const variable = findVariable(variableName);
+
+ if (process.env.NODE_ENV !== 'production' && !variable) {
+ throw new Error(`useServiceOptions: can not find variable ${variableName}`);
+ }
+
const result = getValuesByPath(
{
- $nForm: form?.values,
- $iteration: subFormValue,
+ [variableName]: variable?.ctx || {},
},
getPath(value),
);
@@ -100,39 +103,12 @@ export default function useServiceOptions(props) {
}, [
field.componentProps?.service?.params?.filter,
fieldSchema,
- form?.values,
+ findVariable,
parseFilter,
record,
service?.params?.filter,
- subFormValue,
]);
- const normalizeValues = useCallback(
- (obj) => {
- if (obj && typeof obj === 'object') {
- return obj[fieldNames?.value];
- }
- return obj;
- },
- [fieldNames?.value],
- );
-
- const value = useMemo(() => {
- if (props.value === undefined || props.value === null) {
- return;
- }
-
- let result: any[] = null;
-
- if (Array.isArray(props.value)) {
- result = props.value.map(normalizeValues);
- } else {
- result = [normalizeValues(props.value)];
- }
-
- return result.filter(Boolean);
- }, [props.value, normalizeValues]);
-
const collectionField = useMemo(() => {
return getField(fieldSchema.name) || getCollectionJoinField(fieldSchema?.['x-collection-field']);
}, [fieldSchema]);
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 33d3c9499..2a1c274b4 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
@@ -3,7 +3,7 @@ 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 { useCallback, useEffect } from 'react';
import { useRecord, useRecordIndex } from '../../../../../src/record-provider';
import { useFormBlockType } from '../../../../block-provider/FormBlockProvider';
import { useCollection } from '../../../../collection-manager';
@@ -31,6 +31,20 @@ const useParseDefaultValue = () => {
const index = useRecordIndex();
const { type: formBlockType } = useFormBlockType();
+ /**
+ * name: 如 $user
+ */
+ const findVariable = useCallback(
+ (name: string) => {
+ let result = variables?.getVariable(name);
+ if (!result) {
+ result = localVariables.find((item) => item.name === name);
+ }
+ return result;
+ },
+ [localVariables, variables],
+ );
+
useEffect(() => {
if (
fieldSchema.default == null ||
@@ -94,12 +108,16 @@ const useParseDefaultValue = () => {
if (isVariable(fieldSchema.default)) {
const variableName = getVariableName(fieldSchema.default);
- const variableValue = localVariables.find((item) => item.name === variableName);
+ const variable = findVariable(variableName);
- if (variableValue) {
+ if (process.env.NODE_ENV !== 'production' && !variable) {
+ throw new Error(`useParseDefaultValue: can not find variable ${variableName}`);
+ }
+
+ if (variable) {
// 实现联动的效果,当依赖的变量变化时(如 `$nForm` 变量),重新解析默认值
const dispose = reaction(() => {
- const obj = { [variableName]: variableValue?.ctx };
+ const obj = { [variableName]: variable?.ctx || {} };
const path = getPath(fieldSchema.default);
// fix https://nocobase.height.app/T-2212
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 5ef064adb..f11b6885e 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
@@ -22,7 +22,6 @@ import {
useTableSelectorContext,
} from '../../../';
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';
@@ -65,17 +64,15 @@ const useTableColumns = (props: { showDel?: boolean; isSubTable?: boolean }) =>
return (
-
-
-
-
-
-
-
+
+
+
+
+
);
diff --git a/packages/core/client/src/schema-settings/hooks/useParseDataScopeFilter.ts b/packages/core/client/src/schema-settings/hooks/useParseDataScopeFilter.ts
index d87635417..d6368c8a4 100644
--- a/packages/core/client/src/schema-settings/hooks/useParseDataScopeFilter.ts
+++ b/packages/core/client/src/schema-settings/hooks/useParseDataScopeFilter.ts
@@ -20,6 +20,20 @@ const useParseDataScopeFilter = ({ exclude = defaultExclude, currentRecord }: Pr
const localVariables = useLocalVariables({ currentRecord });
const variables = useVariables();
+ /**
+ * name: 如 $user
+ */
+ const findVariable = useCallback(
+ (name: string) => {
+ let result = variables?.getVariable(name);
+ if (!result) {
+ result = localVariables.find((item) => item.name === name);
+ }
+ return result;
+ },
+ [localVariables, variables],
+ );
+
const parseFilter = useCallback(
async (filterValue: any) => {
const flat = flatten(filterValue, {
@@ -52,7 +66,7 @@ const useParseDataScopeFilter = ({ exclude = defaultExclude, currentRecord }: Pr
[exclude, localVariables, variables?.parseVariable],
);
- return { parseFilter };
+ return { parseFilter, findVariable };
};
export default useParseDataScopeFilter;
diff --git a/packages/core/client/src/variables/hooks/useLocalVariables.tsx b/packages/core/client/src/variables/hooks/useLocalVariables.tsx
index f640ecb3e..471d824a9 100644
--- a/packages/core/client/src/variables/hooks/useLocalVariables.tsx
+++ b/packages/core/client/src/variables/hooks/useLocalVariables.tsx
@@ -1,8 +1,9 @@
import { Form } from '@formily/core';
-import React, { useContext, useMemo } from 'react';
+import { useMemo } from 'react';
import { useFormBlockContext } from '../../block-provider';
import { useCollection } from '../../collection-manager';
import { useRecord } from '../../record-provider';
+import { useSubFormValue } from '../../schema-component/antd/association-field/hooks';
import { useBlockCollection } from '../../schema-settings/VariableInput/hooks/useBlockCollection';
import { VariableOption } from '../types';
@@ -12,21 +13,9 @@ interface Props {
currentForm?: Form;
}
-const LocalVariablesContext = React.createContext<{ iterationCtx: Record }>(null);
-
-export const LocalVariablesProvider = ({
- children,
- iterationCtx,
-}: {
- iterationCtx: Record;
- children: React.ReactNode;
-}) => {
- return {children};
-};
-
const useLocalVariables = (props?: Props) => {
const { name: currentCollectionName } = useCollection();
- const { iterationCtx } = useContext(LocalVariablesContext) || {};
+ const { formValue: subFormValue } = useSubFormValue();
let { name } = useBlockCollection();
let currentRecord = useRecord();
let { form } = useFormBlockContext();
@@ -86,10 +75,10 @@ const useLocalVariables = (props?: Props) => {
ctx: form?.values,
collectionName: name,
},
- iterationCtx && { name: '$iteration', ctx: iterationCtx, collectionName: currentCollectionName },
+ subFormValue && { name: '$iteration', ctx: subFormValue, collectionName: currentCollectionName },
] as VariableOption[]
).filter(Boolean);
- }, [currentRecord, name, form?.values, iterationCtx, currentCollectionName]); // 尽量保持返回的值不变,这样可以减少接口的请求次数,因为关系字段会缓存到变量的 ctx 中
+ }, [currentRecord, name, form?.values, subFormValue, currentCollectionName]); // 尽量保持返回的值不变,这样可以减少接口的请求次数,因为关系字段会缓存到变量的 ctx 中
};
export default useLocalVariables;