diff --git a/packages/core/client/src/block-provider/BlockProvider.tsx b/packages/core/client/src/block-provider/BlockProvider.tsx index d5d75c871..e065ae818 100644 --- a/packages/core/client/src/block-provider/BlockProvider.tsx +++ b/packages/core/client/src/block-provider/BlockProvider.tsx @@ -5,7 +5,7 @@ import { useRequest } from 'ahooks'; import { Col, Row } from 'antd'; import merge from 'deepmerge'; import template from 'lodash/template'; -import React, { createContext, useContext, useEffect, useRef, useState } from 'react'; +import React, { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react'; import { Link } from 'react-router-dom'; import { TableFieldResource, @@ -285,7 +285,7 @@ export const RenderChildrenWithAssociationFilter: React.FC = (props) => { export const BlockProvider = (props) => { const { collection, association } = props; const resource = useResource(props); - const params = { ...props.params }; + const params = useMemo(() => ({ ...props.params }), [props.params]); const { appends, updateAssociationValues } = useAssociationNames(); if (!Object.keys(params).includes('appends')) { params['appends'] = appends; diff --git a/packages/core/client/src/block-provider/CalendarBlockProvider.tsx b/packages/core/client/src/block-provider/CalendarBlockProvider.tsx index 8dd155995..53ae0779d 100644 --- a/packages/core/client/src/block-provider/CalendarBlockProvider.tsx +++ b/packages/core/client/src/block-provider/CalendarBlockProvider.tsx @@ -1,8 +1,11 @@ import { ArrayField } from '@formily/core'; import { useField } from '@formily/react'; +import _ from 'lodash'; import React, { createContext, useContext, useEffect } from 'react'; +import { useRecord } from '../record-provider'; import { FixedBlockWrapper } from '../schema-component'; import { BlockProvider, useBlockRequestContext } from './BlockProvider'; +import { useParsedFilter } from './hooks'; export const CalendarBlockContext = createContext({}); @@ -10,6 +13,18 @@ const InternalCalendarBlockProvider = (props) => { const { fieldNames, showLunar } = props; const field = useField(); const { resource, service } = useBlockRequestContext(); + const record = useRecord(); + + const { filter } = useParsedFilter({ + filterOption: service?.params?.[0]?.filter, + currentRecord: { __parent: record, __collectionName: props.collection }, + }); + useEffect(() => { + if (!_.isEmpty(filter)) { + service?.run({ ...service?.params?.[0], filter }); + } + }, [JSON.stringify(filter)]); + // if (service.loading) { // return ; // } diff --git a/packages/core/client/src/block-provider/DetailsBlockProvider.tsx b/packages/core/client/src/block-provider/DetailsBlockProvider.tsx index df5b9bafd..ccbe773ca 100644 --- a/packages/core/client/src/block-provider/DetailsBlockProvider.tsx +++ b/packages/core/client/src/block-provider/DetailsBlockProvider.tsx @@ -1,9 +1,11 @@ import { createForm } from '@formily/core'; import { useField } from '@formily/react'; import { Spin } from 'antd'; +import _ from 'lodash'; import React, { createContext, useContext, useEffect, useMemo } from 'react'; -import { RecordProvider } from '../record-provider'; +import { RecordProvider, useRecord } from '../record-provider'; import { BlockProvider, useBlockRequestContext } from './BlockProvider'; +import { useParsedFilter } from './hooks'; export const DetailsBlockContext = createContext({}); @@ -18,21 +20,36 @@ const InternalDetailsBlockProvider = (props) => { [], ); const { resource, service } = useBlockRequestContext(); + const record = useRecord(); + const currentRecord = service?.data?.data?.[0] || {}; + const detailsBLockValue = useMemo(() => { + return { + action, + form, + field, + service, + resource, + }; + }, [action, field, form, resource, service]); + + const { filter } = useParsedFilter({ + filterOption: service?.params?.[0]?.filter, + currentRecord: { ...currentRecord, __parent: record, __collectionName: props.collection }, + }); + useEffect(() => { + if (!_.isEmpty(filter)) { + service?.run({ ...service?.params?.[0], filter }); + } + }, [JSON.stringify(filter)]); + if (service.loading && !field.loaded) { return ; } field.loaded = true; + return ( - - {props.children} + + {props.children} ); }; @@ -53,9 +70,12 @@ export const useDetailsBlockProps = () => { const ctx = useDetailsBlockContext(); useEffect(() => { if (!ctx.service.loading) { - ctx.form.reset().then(() => { - ctx.form.setValues(ctx.service?.data?.data?.[0] || {}); - }); + ctx.form + .reset() + .then(() => { + ctx.form.setValues(ctx.service?.data?.data?.[0] || {}); + }) + .catch(console.error); } }, [ctx.service.loading]); return { diff --git a/packages/core/client/src/block-provider/FormBlockProvider.tsx b/packages/core/client/src/block-provider/FormBlockProvider.tsx index 261b8bee2..671b55232 100644 --- a/packages/core/client/src/block-provider/FormBlockProvider.tsx +++ b/packages/core/client/src/block-provider/FormBlockProvider.tsx @@ -1,7 +1,7 @@ import { createForm } from '@formily/core'; import { RecursionField, Schema, useField, useFieldSchema } from '@formily/react'; import { Spin } from 'antd'; -import { isEmpty } from 'lodash'; +import _, { isEmpty } from 'lodash'; import React, { createContext, useContext, useEffect, useMemo, useRef } from 'react'; import { useCollection } from '../collection-manager'; import { RecordProvider, useRecord } from '../record-provider'; @@ -13,7 +13,7 @@ import { FormActiveFieldsProvider } from './hooks'; export const FormBlockContext = createContext({}); const InternalFormBlockProvider = (props) => { - const { action, readPretty, params } = props; + const { action, readPretty, params, association } = props; const field = useField(); const form = useMemo( () => @@ -25,38 +25,51 @@ const InternalFormBlockProvider = (props) => { const { resource, service, updateAssociationValues } = useBlockRequestContext(); const formBlockRef = useRef(); const record = useRecord(); + const formBlockValue = useMemo(() => { + return { + params, + action, + form, + // update 表示是表单编辑区块,create 表示是表单新增区块 + type: action === 'get' ? 'update' : 'create', + field, + service, + resource, + updateAssociationValues, + formBlockRef, + }; + }, [action, field, form, params, resource, service, updateAssociationValues]); + if (service.loading && Object.keys(form?.initialValues)?.length === 0 && action) { return ; } - return ( - - {readPretty ? ( - -
- -
-
- ) : ( -
- -
- )} -
+ let content = ( +
+ +
); + if (readPretty) { + content = ( + + {content} + + ); + } else if ( + formBlockValue.type === 'create' && + // 点击关系表格区块的 Add new 按钮,在弹窗中新增的表单区块,是不需要重置 record 的。在这里用 record 是否为空来判断 + !_.isEmpty(_.omit(record, ['__parent', '__collectionName'])) && + // association 不为空,说明是关系区块 + association + ) { + content = ( + + {content} + + ); + } + + return {content}; }; /** diff --git a/packages/core/client/src/block-provider/TableBlockProvider.tsx b/packages/core/client/src/block-provider/TableBlockProvider.tsx index 0125f0a3d..c591331e5 100644 --- a/packages/core/client/src/block-provider/TableBlockProvider.tsx +++ b/packages/core/client/src/block-provider/TableBlockProvider.tsx @@ -3,10 +3,11 @@ import { FormContext, useField, useFieldSchema } from '@formily/react'; import React, { createContext, useContext, useEffect, useMemo, useState } from 'react'; import { useCollectionManager } from '../collection-manager'; import { useFilterBlock } from '../filter-provider/FilterProvider'; +import { useRecord } from '../record-provider'; import { FixedBlockWrapper, SchemaComponentOptions, removeNullCondition } from '../schema-component'; import { BlockProvider, RenderChildrenWithAssociationFilter, useBlockRequestContext } from './BlockProvider'; import { mergeFilter } from './SharedFilterProvider'; -import { findFilterTargets } from './hooks'; +import { findFilterTargets, useParsedFilter } from './hooks'; export const TableBlockContext = createContext({}); export function getIdsWithChildren(nodes) { @@ -74,9 +75,11 @@ const InternalTableBlockProvider = (props: Props) => { export const TableBlockProvider = (props) => { const resourceName = props.resource; - const params = { ...props.params }; + const params = useMemo(() => ({ ...props.params }), [props.params]); const fieldSchema = useFieldSchema(); const { getCollection, getCollectionField } = useCollectionManager(); + const record = useRecord(); + const collection = getCollection(props.collection); const { treeTable } = fieldSchema?.['x-decorator-props'] || {}; if (props.dragSort) { @@ -99,12 +102,22 @@ export const TableBlockProvider = (props) => { } } const form = useMemo(() => createForm(), [treeTable]); + const { filter: parsedFilter } = useParsedFilter({ + filterOption: params?.filter, + currentRecord: { __parent: record, __collectionName: props.collection }, + }); + const paramsWithFilter = useMemo(() => { + return { + ...params, + filter: parsedFilter, + }; + }, [parsedFilter, params]); return ( - - + + diff --git a/packages/core/client/src/block-provider/hooks/index.ts b/packages/core/client/src/block-provider/hooks/index.ts index e2ece264f..a29e5d778 100644 --- a/packages/core/client/src/block-provider/hooks/index.ts +++ b/packages/core/client/src/block-provider/hooks/index.ts @@ -26,6 +26,7 @@ import { mergeFilter } from '../SharedFilterProvider'; import { TableFieldResource } from '../TableFieldProvider'; export * from './useFormActiveFields'; +export * from './useParsedFilter'; export const usePickActionProps = () => { const form = useForm(); @@ -587,8 +588,9 @@ export const useCustomizeBulkUpdateActionProps = () => { const actionField = useField(); const { modal } = App.useApp(); const variables = useVariables(); - const localVariables = useLocalVariables(); + const record = useRecord(); const { name, getField } = useCollection(); + const localVariables = useLocalVariables({ currentRecord: { __parent: record, __collectionName: name } }); return { async onClick() { diff --git a/packages/core/client/src/block-provider/hooks/useParsedFilter.ts b/packages/core/client/src/block-provider/hooks/useParsedFilter.ts new file mode 100644 index 000000000..0e7bf9f2f --- /dev/null +++ b/packages/core/client/src/block-provider/hooks/useParsedFilter.ts @@ -0,0 +1,45 @@ +import { reaction } from '@formily/reactive'; +import { flatten } 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 { isVariable } from '../../variables/utils/isVariable'; +import { useFormBlockContext } from '../FormBlockProvider'; + +export function useParsedFilter({ filterOption, currentRecord }: { filterOption: any; currentRecord?: any }) { + const { parseFilter } = useParseDataScopeFilter({ currentRecord }); + const [filter, setFilter] = useState({}); + const { form } = useFormBlockContext(); + + useEffect(() => { + if (!filterOption) return; + + const _run = async () => { + const result = await parseFilter(filterOption); + setFilter(result); + }; + _run(); + const run = _.debounce(_run, DEBOUNCE_WAIT); + + reaction(() => { + // 这一步主要是为了使 reaction 能够收集到依赖 + const flat = flatten(filterOption, { + breakOn({ key }) { + return key.startsWith('$') && key !== '$and' && key !== '$or'; + }, + transformValue(value) { + if (!isVariable(value)) { + return value; + } + const result = _.get({ $nForm: form?.values }, getPath(value)); + return result; + }, + }); + return flat; + }, run); + }, [JSON.stringify(filterOption)]); + + return { filter }; +} diff --git a/packages/core/client/src/collection-manager/Configuration/EditCollectionAction.tsx b/packages/core/client/src/collection-manager/Configuration/EditCollectionAction.tsx index f5dde621c..39589b3a6 100644 --- a/packages/core/client/src/collection-manager/Configuration/EditCollectionAction.tsx +++ b/packages/core/client/src/collection-manager/Configuration/EditCollectionAction.tsx @@ -79,7 +79,10 @@ const getSchema = (schema: IField, record: any, compile, getContainer): ISchema export const useValuesFromRecord = (options) => { const record = useRecord(); const result = useRequest( - () => Promise.resolve({ data: { ...omit(record, ['__parent']), category: record?.category.map((v) => v.id) } }), + () => + Promise.resolve({ + data: { ...omit(record, ['__parent', '__collectionName']), category: record?.category.map((v) => v.id) }, + }), { ...options, manual: true, diff --git a/packages/core/client/src/collection-manager/action-hooks.ts b/packages/core/client/src/collection-manager/action-hooks.ts index e58e1c864..b98d0d553 100644 --- a/packages/core/client/src/collection-manager/action-hooks.ts +++ b/packages/core/client/src/collection-manager/action-hooks.ts @@ -23,7 +23,7 @@ export const useCancelAction = () => { export const useValuesFromRecord = (options) => { const record = useRecord(); - const result = useRequest(() => Promise.resolve({ data: omit(record, ['__parent']) }), { + const result = useRequest(() => Promise.resolve({ data: omit(record, ['__parent', '__collectionName']) }), { ...options, manual: true, }); diff --git a/packages/core/client/src/filter-provider/FilterProvider.tsx b/packages/core/client/src/filter-provider/FilterProvider.tsx index 0265ca57b..64ffdffbc 100644 --- a/packages/core/client/src/filter-provider/FilterProvider.tsx +++ b/packages/core/client/src/filter-provider/FilterProvider.tsx @@ -61,6 +61,11 @@ export const FilterBlockProvider: React.FC = ({ children }) => { return {children}; }; +/** + * 用于收集记录当前页面中的数据区块的信息 + * @param param0 + * @returns + */ export const FilterBlockRecord = ({ children, params, diff --git a/packages/core/client/src/locale/en_US.ts b/packages/core/client/src/locale/en_US.ts index c025ca82d..f3bd76974 100644 --- a/packages/core/client/src/locale/en_US.ts +++ b/packages/core/client/src/locale/en_US.ts @@ -619,6 +619,7 @@ export default { "Dynamic value": "Dynamic value", "Current user": "Current user", "Current record": "Current record", + "Current parent record": "Current parent record", "Current time": "Current time", "System variables": "System variables", "Date variables": "Date variables", diff --git a/packages/core/client/src/locale/es_ES.ts b/packages/core/client/src/locale/es_ES.ts index 5fd0deedf..49c920dab 100644 --- a/packages/core/client/src/locale/es_ES.ts +++ b/packages/core/client/src/locale/es_ES.ts @@ -603,6 +603,7 @@ export default { "Dynamic value": "Valor dinámico", "Current user": "Usuario actual", "Current record": "Registro actual", + "Current parent record": "Registro padre actual", "Current time": "Hora actual", "System variables": "Variables del sistema", "Date variables": "Variables de fecha", diff --git a/packages/core/client/src/locale/fr_FR.ts b/packages/core/client/src/locale/fr_FR.ts index 72423ef4b..41d389d57 100644 --- a/packages/core/client/src/locale/fr_FR.ts +++ b/packages/core/client/src/locale/fr_FR.ts @@ -600,6 +600,7 @@ export default { "Dynamic value": "Valeur dynamique", "Current user": "Utilisateur actuel", "Current record": "Enregistrement actuel", + "Current parent record": "Enregistrement parent actuel", "Current time": "Heure actuelle", "System variables": "Variables système", "Date variables": "Variables de date", diff --git a/packages/core/client/src/locale/ja_JP.ts b/packages/core/client/src/locale/ja_JP.ts index c9fb96d5d..f80ddbbfb 100644 --- a/packages/core/client/src/locale/ja_JP.ts +++ b/packages/core/client/src/locale/ja_JP.ts @@ -502,6 +502,7 @@ export default { "Dynamic value": "動的値", "Current user": "現在のユーザー", "Current record": "現在のレコード", + "Current parent record": "現在の親レコード", "Popup close method": "ポップアップを閉じる方法", "Automatic close": "自動で閉じる", "Manually close": "手動で閉じる", diff --git a/packages/core/client/src/locale/pt_BR.ts b/packages/core/client/src/locale/pt_BR.ts index 0d665d472..325f7d20b 100644 --- a/packages/core/client/src/locale/pt_BR.ts +++ b/packages/core/client/src/locale/pt_BR.ts @@ -508,6 +508,7 @@ export default { "Single select and radio fields can be used as the grouping field": "Campos de seleção única e de rádio podem ser usados como o campo de agrupamento", "Tab name": "Nome da aba", "Current record blocks": "Blocos de registro atual", + "Current parent record": "Registro pai atual", "Popup message": "Mensagem pop-up", "Delete role": "Excluir função", "Role display name": "Nome de exibição da função", diff --git a/packages/core/client/src/locale/ru_RU.ts b/packages/core/client/src/locale/ru_RU.ts index ef1bc12c4..d3436c27f 100644 --- a/packages/core/client/src/locale/ru_RU.ts +++ b/packages/core/client/src/locale/ru_RU.ts @@ -439,6 +439,7 @@ export default { "Dynamic value": "Динамическое значение", "Current user": "Текущий пользователь", "Current record": "Текущая запись", + "Current parent record": "Текущая родительская запись", "Popup close method": "Метод закрытия всплывающего окна", "Automatic close": "Автоматическое закрытие", "Manually close": "Ручное закрытие", diff --git a/packages/core/client/src/locale/tr_TR.ts b/packages/core/client/src/locale/tr_TR.ts index a3bcc48b0..3355dc82a 100644 --- a/packages/core/client/src/locale/tr_TR.ts +++ b/packages/core/client/src/locale/tr_TR.ts @@ -438,6 +438,7 @@ export default { "Dynamic value": "Dinamik değer", "Current user": "Seçili kullanıcı", "Current record": "Seçili kayıt", + "Current parent record": "Seçili üst kayıt", "Popup close method": "Açılır pencere kapatma metodu", "Automatic close": "Otomatik kapat", "Manually close": "Manuel kapat", diff --git a/packages/core/client/src/locale/uk_UA.ts b/packages/core/client/src/locale/uk_UA.ts index 129e3ea14..de99b6561 100644 --- a/packages/core/client/src/locale/uk_UA.ts +++ b/packages/core/client/src/locale/uk_UA.ts @@ -620,6 +620,7 @@ export default { "Dynamic value": "Динамічне значення", "Current user": "Поточний користувач", "Current record": "Поточний запис", + "Current parent record": "Поточний батьківський запис", "Current time": "Поточний час", "System variables": "Системні змінні", "Date variables": "Змінні дати", diff --git a/packages/core/client/src/locale/zh_CN.ts b/packages/core/client/src/locale/zh_CN.ts index 5b3344e92..2e4638c18 100644 --- a/packages/core/client/src/locale/zh_CN.ts +++ b/packages/core/client/src/locale/zh_CN.ts @@ -661,6 +661,7 @@ export default { 'Dynamic value': '动态值', 'Current user': '当前用户', 'Current record': '当前记录', + "Current parent record": "当前父记录", 'Current time': '当前时间', Now: '现在', 'Popup close method': '弹窗关闭方式', diff --git a/packages/core/client/src/record-provider/index.tsx b/packages/core/client/src/record-provider/index.tsx index fd3cbf85b..e274ab2cf 100644 --- a/packages/core/client/src/record-provider/index.tsx +++ b/packages/core/client/src/record-provider/index.tsx @@ -1,14 +1,17 @@ import React, { createContext, useContext } from 'react'; +import { useCollection } from '../collection-manager'; import { useCurrentUserContext } from '../user'; export const RecordContext = createContext({}); export const RecordIndexContext = createContext(null); -export const RecordProvider: React.FC<{ record: any; parent?: any }> = (props) => { - const { record, children, parent = false } = props; +export const RecordProvider: React.FC<{ record: any; parent?: any; collectionName?: string }> = (props) => { + const { record, children, collectionName, parent = false } = props; + const { name: __collectionName } = useCollection(); const __parent = useContext(RecordContext); const value = { ...record }; value['__parent'] = parent ? parent : __parent; + value['__collectionName'] = collectionName || __collectionName; return {children}; }; 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 b23c1e8b5..f5e738d1c 100644 --- a/packages/core/client/src/schema-component/antd/action/Action.tsx +++ b/packages/core/client/src/schema-component/antd/action/Action.tsx @@ -8,7 +8,7 @@ import { useTranslation } from 'react-i18next'; import { useActionContext } from '../..'; import { useDesignable } from '../../'; import { Icon } from '../../../icon'; -import { useRecord } from '../../../record-provider'; +import { RecordProvider, useRecord } from '../../../record-provider'; import { useLocalVariables, useVariables } from '../../../variables'; import { SortableItem } from '../../common'; import { useCompile, useComponent, useDesigner } from '../../hooks'; @@ -52,7 +52,7 @@ export const Action: ComposedAction = observer( const fieldSchema = useFieldSchema(); const compile = useCompile(); const form = useForm(); - const values = useRecord(); + const record = useRecord(); const designerProps = fieldSchema['x-designer-props']; const openMode = fieldSchema?.['x-component-props']?.['openMode']; const disabled = form.disabled || field.disabled || field.data?.disabled || props.disabled; @@ -61,7 +61,12 @@ export const Action: ComposedAction = observer( const tarComponent = useComponent(component) || component; const { modal } = App.useApp(); const variables = useVariables(); - const localVariables = useLocalVariables({ currentForm: { values } as any }); + const localVariables = useLocalVariables({ currentForm: { values: record } as any }); + + // fix https://nocobase.height.app/T-2259 + const shouldResetRecord = ['create', 'customize:bulkUpdate', 'customize:bulkEdit', 'customize:create'].includes( + fieldSchema['x-action'], + ); let actionTitle = title || compile(fieldSchema.title); actionTitle = lodash.isString(actionTitle) ? t(actionTitle) : actionTitle; @@ -75,13 +80,13 @@ export const Action: ComposedAction = observer( operator: h.operator, field, condition: v.condition, - values, + values: record, variables, localVariables, }); }); }); - }, [JSON.stringify(linkageRules), values, designable, field]); + }, [JSON.stringify(linkageRules), record, designable, field]); const handleButtonClick = useCallback( (e: React.MouseEvent) => { @@ -142,7 +147,7 @@ export const Action: ComposedAction = observer( ); }; - return wrapSSR( + const result = ( , + + ); + + return wrapSSR( + shouldResetRecord ? ( + + {result} + + ) : ( + result + ), ); }, { displayName: 'Action' }, 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 2a790f0d8..40fff237c 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 @@ -15,7 +15,6 @@ import { DEBOUNCE_WAIT } from '../../../variables'; import { getPath } from '../../../variables/utils/getPath'; import { isVariable } from '../../../variables/utils/isVariable'; import { useDesignable } from '../../hooks'; -import { removeNullCondition } from '../filter'; import { AssociationFieldContext } from './context'; export const useInsertSchema = (component) => { diff --git a/packages/core/client/src/schema-component/antd/calendar/Calendar.Designer.tsx b/packages/core/client/src/schema-component/antd/calendar/Calendar.Designer.tsx index f46d7e0af..32e7ebf29 100644 --- a/packages/core/client/src/schema-component/antd/calendar/Calendar.Designer.tsx +++ b/packages/core/client/src/schema-component/antd/calendar/Calendar.Designer.tsx @@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next'; import { FixedBlockDesignerItem, removeNullCondition, useDesignable } from '../..'; import { useCalendarBlockContext, useFormBlockContext } from '../../../block-provider'; import { useCollection, useCollectionManager } from '../../../collection-manager'; +import { RecordProvider, useRecord } from '../../../record-provider'; import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings'; import { useSchemaTemplate } from '../../../schema-templates'; @@ -17,119 +18,122 @@ export const CalendarDesigner = () => { const { dn } = useDesignable(); const { t } = useTranslation(); const template = useSchemaTemplate(); + const record = useRecord(); const fieldNames = fieldSchema?.['x-decorator-props']?.['fieldNames'] || {}; const defaultResource = fieldSchema?.['x-decorator-props']?.resource; return ( - - - { - const fieldNames = field.decoratorProps.fieldNames || {}; - fieldNames['title'] = title; - field.decoratorProps.params = fieldNames; - fieldSchema['x-decorator-props']['params'] = fieldNames; - // Select切换option后value未按照预期切换,固增加以下代码 - fieldSchema['x-decorator-props']['fieldNames'] = fieldNames; - service.refresh(); - dn.emit('patch', { - schema: { - ['x-uid']: fieldSchema['x-uid'], - 'x-decorator-props': field.decoratorProps, - }, - }); - dn.refresh(); - }} - /> - { - field.decoratorProps.showLunar = v; - fieldSchema['x-decorator-props']['showLunar'] = v; - dn.emit('patch', { - schema: { - ['x-uid']: fieldSchema['x-uid'], - 'x-decorator-props': field.decoratorProps, - }, - }); - dn.refresh(); - }} - /> - - { - const fieldNames = field.decoratorProps.fieldNames || {}; - fieldNames['start'] = start; - field.decoratorProps.fieldNames = fieldNames; - fieldSchema['x-decorator-props']['fieldNames'] = fieldNames; - service.refresh(); - dn.emit('patch', { - schema: { - ['x-uid']: fieldSchema['x-uid'], - 'x-decorator-props': field.decoratorProps, - }, - }); - dn.refresh(); - }} - /> - { - const fieldNames = field.decoratorProps.fieldNames || {}; - fieldNames['end'] = end; - field.decoratorProps.fieldNames = fieldNames; - fieldSchema['x-decorator-props']['fieldNames'] = fieldNames; - service.refresh(); - dn.emit('patch', { - schema: { - ['x-uid']: fieldSchema['x-uid'], - 'x-decorator-props': field.decoratorProps, - }, - }); - dn.refresh(); - }} - /> - { - filter = removeNullCondition(filter); - const params = field.decoratorProps.params || {}; - params.filter = filter; - field.decoratorProps.params = params; - fieldSchema['x-decorator-props']['params'] = params; - service.run({ ...service?.params?.[0], filter }); - dn.emit('patch', { - schema: { - ['x-uid']: fieldSchema['x-uid'], - 'x-decorator-props': field.decoratorProps, - }, - }); - }} - /> - - - - - + + + + { + const fieldNames = field.decoratorProps.fieldNames || {}; + fieldNames['title'] = title; + field.decoratorProps.params = fieldNames; + fieldSchema['x-decorator-props']['params'] = fieldNames; + // Select切换option后value未按照预期切换,固增加以下代码 + fieldSchema['x-decorator-props']['fieldNames'] = fieldNames; + service.refresh(); + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-decorator-props': field.decoratorProps, + }, + }); + dn.refresh(); + }} + /> + { + field.decoratorProps.showLunar = v; + fieldSchema['x-decorator-props']['showLunar'] = v; + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-decorator-props': field.decoratorProps, + }, + }); + dn.refresh(); + }} + /> + + { + const fieldNames = field.decoratorProps.fieldNames || {}; + fieldNames['start'] = start; + field.decoratorProps.fieldNames = fieldNames; + fieldSchema['x-decorator-props']['fieldNames'] = fieldNames; + service.refresh(); + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-decorator-props': field.decoratorProps, + }, + }); + dn.refresh(); + }} + /> + { + const fieldNames = field.decoratorProps.fieldNames || {}; + fieldNames['end'] = end; + field.decoratorProps.fieldNames = fieldNames; + fieldSchema['x-decorator-props']['fieldNames'] = fieldNames; + service.refresh(); + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-decorator-props': field.decoratorProps, + }, + }); + dn.refresh(); + }} + /> + { + filter = removeNullCondition(filter); + const params = field.decoratorProps.params || {}; + params.filter = filter; + field.decoratorProps.params = params; + fieldSchema['x-decorator-props']['params'] = params; + service.run({ ...service?.params?.[0], filter }); + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-decorator-props': field.decoratorProps, + }, + }); + }} + /> + + + + + + ); }; diff --git a/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx b/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx index 0bc11af75..7d04b088f 100644 --- a/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx +++ b/packages/core/client/src/schema-component/antd/form-item/FormItem.tsx @@ -735,7 +735,7 @@ FormItem.FilterFormDesigner = FilterFormDesigner; function useIsAddNewForm() { const record = useRecord(); - const isAddNewForm = _.isEmpty(_.omit(record, '__parent')); + const isAddNewForm = _.isEmpty(_.omit(record, ['__parent', '__collectionName'])); return isAddNewForm; } diff --git a/packages/core/client/src/schema-component/antd/form-item/hooks/useLazyLoadAssociationFieldOfForm.ts b/packages/core/client/src/schema-component/antd/form-item/hooks/useLazyLoadAssociationFieldOfForm.ts index 96d63d1dd..263348145 100644 --- a/packages/core/client/src/schema-component/antd/form-item/hooks/useLazyLoadAssociationFieldOfForm.ts +++ b/packages/core/client/src/schema-component/antd/form-item/hooks/useLazyLoadAssociationFieldOfForm.ts @@ -39,6 +39,7 @@ const useLazyLoadAssociationFieldOfForm = () => { const cloneRecord = { ...record }; delete cloneRecord['__parent']; + delete cloneRecord['__collectionName']; if (_.isEmpty(cloneRecord) || !variables || record[schemaName] != null) { return; diff --git a/packages/core/client/src/schema-component/antd/grid-card/GridCard.Decorator.tsx b/packages/core/client/src/schema-component/antd/grid-card/GridCard.Decorator.tsx index 2c155e49d..8832f0ba9 100644 --- a/packages/core/client/src/schema-component/antd/grid-card/GridCard.Decorator.tsx +++ b/packages/core/client/src/schema-component/antd/grid-card/GridCard.Decorator.tsx @@ -2,7 +2,8 @@ import { FormLayout } from '@formily/antd-v5'; import { createForm } from '@formily/core'; import { FormContext, useField } from '@formily/react'; import React, { createContext, useContext, useEffect, useMemo } from 'react'; -import { BlockProvider, useBlockRequestContext } from '../../../block-provider'; +import { BlockProvider, useBlockRequestContext, useParsedFilter } from '../../../block-provider'; +import { useRecord } from '../../../record-provider'; import useStyles from './GridCard.Decorator.style'; export const GridCardBlockContext = createContext({}); @@ -41,8 +42,22 @@ const InternalGridCardBlockProvider = (props) => { }; export const GridCardBlockProvider = (props) => { + const { params } = props; + const record = useRecord(); + + const { filter: parsedFilter } = useParsedFilter({ + filterOption: params?.filter, + currentRecord: { __parent: record, __collectionName: props.collection }, + }); + const paramsWithFilter = useMemo(() => { + return { + ...params, + filter: parsedFilter, + }; + }, [parsedFilter, params]); + return ( - + ); diff --git a/packages/core/client/src/schema-component/antd/grid-card/GridCard.Designer.tsx b/packages/core/client/src/schema-component/antd/grid-card/GridCard.Designer.tsx index 6965a4777..8ce08171d 100644 --- a/packages/core/client/src/schema-component/antd/grid-card/GridCard.Designer.tsx +++ b/packages/core/client/src/schema-component/antd/grid-card/GridCard.Designer.tsx @@ -6,6 +6,7 @@ import React, { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { useFormBlockContext } from '../../../block-provider'; import { useCollection, useSortFields } from '../../../collection-manager'; +import { RecordProvider, useRecord } from '../../../record-provider'; import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings'; import { useSchemaTemplate } from '../../../schema-templates'; import { SchemaComponentOptions } from '../../core'; @@ -27,6 +28,7 @@ export const GridCardDesigner = () => { const field = useField(); const { dn } = useDesignable(); const sortFields = useSortFields(name); + const record = useRecord(); const defaultSort = fieldSchema?.['x-decorator-props']?.params?.sort || []; const defaultResource = fieldSchema?.['x-decorator-props']?.resource; const columnCount = field.decoratorProps.columnCount || defaultColumnCount; @@ -70,159 +72,162 @@ export const GridCardDesigner = () => { }; }); return ( - - - { - _.set(fieldSchema, 'x-decorator-props.columnCount', columnCount); - field.decoratorProps.columnCount = columnCount; - dn.emit('patch', { - schema: { - ['x-uid']: fieldSchema['x-uid'], - 'x-decorator-props': fieldSchema['x-decorator-props'], - }, - }); - }} - /> - { - filter = removeNullCondition(filter); - _.set(fieldSchema, 'x-decorator-props.params.filter', filter); - field.decoratorProps.params = { ...fieldSchema['x-decorator-props'].params }; - dn.emit('patch', { - schema: { - ['x-uid']: fieldSchema['x-uid'], - 'x-decorator-props': fieldSchema['x-decorator-props'], - }, - }); - }} - /> - + + + { + _.set(fieldSchema, 'x-decorator-props.columnCount', columnCount); + field.decoratorProps.columnCount = columnCount; + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-decorator-props': fieldSchema['x-decorator-props'], + }, + }); + }} + /> + { + filter = removeNullCondition(filter); + _.set(fieldSchema, 'x-decorator-props.params.filter', filter); + field.decoratorProps.params = { ...fieldSchema['x-decorator-props'].params }; + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-decorator-props': fieldSchema['x-decorator-props'], + }, + }); + }} + /> + { - const sortArr = sort.map((item) => { - return item.direction === 'desc' ? `-${item.field}` : item.field; - }); + } as ISchema + } + onSubmit={({ sort }) => { + const sortArr = sort.map((item) => { + return item.direction === 'desc' ? `-${item.field}` : item.field; + }); - _.set(fieldSchema, 'x-decorator-props.params.sort', sortArr); - field.decoratorProps.params = { ...fieldSchema['x-decorator-props'].params }; - dn.emit('patch', { - schema: { - ['x-uid']: fieldSchema['x-uid'], - 'x-decorator-props': fieldSchema['x-decorator-props'], - }, - }); - }} - /> - ({ value: v }))} - onChange={(pageSize) => { - _.set(fieldSchema, 'x-decorator-props.params.pageSize', pageSize); - field.decoratorProps.params = { ...fieldSchema['x-decorator-props'].params, page: 1 }; - dn.emit('patch', { - schema: { - ['x-uid']: fieldSchema['x-uid'], - 'x-decorator-props': fieldSchema['x-decorator-props'], - }, - }); - }} - /> - - - - - + _.set(fieldSchema, 'x-decorator-props.params.sort', sortArr); + field.decoratorProps.params = { ...fieldSchema['x-decorator-props'].params }; + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-decorator-props': fieldSchema['x-decorator-props'], + }, + }); + }} + /> + ({ value: v }))} + onChange={(pageSize) => { + _.set(fieldSchema, 'x-decorator-props.params.pageSize', pageSize); + field.decoratorProps.params = { ...fieldSchema['x-decorator-props'].params, page: 1 }; + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-decorator-props': fieldSchema['x-decorator-props'], + }, + }); + }} + /> + + + + + + ); }; diff --git a/packages/core/client/src/schema-component/antd/list/List.Decorator.tsx b/packages/core/client/src/schema-component/antd/list/List.Decorator.tsx index ffc8d3ceb..36f53428b 100644 --- a/packages/core/client/src/schema-component/antd/list/List.Decorator.tsx +++ b/packages/core/client/src/schema-component/antd/list/List.Decorator.tsx @@ -3,7 +3,8 @@ import { FormLayout } from '@formily/antd-v5'; import { createForm } from '@formily/core'; import { FormContext, useField } from '@formily/react'; import React, { createContext, useContext, useEffect, useMemo } from 'react'; -import { BlockProvider, useBlockRequestContext } from '../../../block-provider'; +import { BlockProvider, useBlockRequestContext, useParsedFilter } from '../../../block-provider'; +import { useRecord } from '../../../record-provider'; export const ListBlockContext = createContext({}); @@ -51,8 +52,22 @@ const InternalListBlockProvider = (props) => { }; export const ListBlockProvider = (props) => { + const { params } = props; + const record = useRecord(); + + const { filter: parsedFilter } = useParsedFilter({ + filterOption: params?.filter, + currentRecord: { __parent: record, __collectionName: props.collection }, + }); + const paramsWithFilter = useMemo(() => { + return { + ...params, + filter: parsedFilter, + }; + }, [parsedFilter, params]); + return ( - + ); diff --git a/packages/core/client/src/schema-component/antd/list/List.Designer.tsx b/packages/core/client/src/schema-component/antd/list/List.Designer.tsx index 0696edd50..1f5e4639e 100644 --- a/packages/core/client/src/schema-component/antd/list/List.Designer.tsx +++ b/packages/core/client/src/schema-component/antd/list/List.Designer.tsx @@ -5,6 +5,7 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; import { useFormBlockContext } from '../../../block-provider'; import { useCollection, useSortFields } from '../../../collection-manager'; +import { RecordProvider, useRecord } from '../../../record-provider'; import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings'; import { useSchemaTemplate } from '../../../schema-templates'; import { useDesignable } from '../../hooks'; @@ -19,6 +20,7 @@ export const ListDesigner = () => { const field = useField(); const { dn } = useDesignable(); const sortFields = useSortFields(name); + const record = useRecord(); const defaultSort = fieldSchema?.['x-decorator-props']?.params?.sort || []; const defaultResource = fieldSchema?.['x-decorator-props']?.resource; const sort = defaultSort?.map((item: string) => { @@ -33,142 +35,145 @@ export const ListDesigner = () => { }; }); return ( - - - { - filter = removeNullCondition(filter); - _.set(fieldSchema, 'x-decorator-props.params.filter', filter); - field.decoratorProps.params = { ...fieldSchema['x-decorator-props'].params, page: 1 }; - dn.emit('patch', { - schema: { - ['x-uid']: fieldSchema['x-uid'], - 'x-decorator-props': fieldSchema['x-decorator-props'], - }, - }); - }} - /> - + + + { + filter = removeNullCondition(filter); + _.set(fieldSchema, 'x-decorator-props.params.filter', filter); + field.decoratorProps.params = { ...fieldSchema['x-decorator-props'].params, page: 1 }; + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-decorator-props': fieldSchema['x-decorator-props'], + }, + }); + }} + /> + { - const sortArr = sort.map((item) => { - return item.direction === 'desc' ? `-${item.field}` : item.field; - }); + } as ISchema + } + onSubmit={({ sort }) => { + const sortArr = sort.map((item) => { + return item.direction === 'desc' ? `-${item.field}` : item.field; + }); - _.set(fieldSchema, 'x-decorator-props.params.sort', sortArr); - field.decoratorProps.params = { ...fieldSchema['x-decorator-props'].params, page: 1 }; - dn.emit('patch', { - schema: { - ['x-uid']: fieldSchema['x-uid'], - 'x-decorator-props': fieldSchema['x-decorator-props'], - }, - }); - }} - /> - { - _.set(fieldSchema, 'x-decorator-props.params.pageSize', pageSize); - field.decoratorProps.params = { ...fieldSchema['x-decorator-props'].params, page: 1 }; - dn.emit('patch', { - schema: { - ['x-uid']: fieldSchema['x-uid'], - 'x-decorator-props': fieldSchema['x-decorator-props'], - }, - }); - }} - /> - - - - + _.set(fieldSchema, 'x-decorator-props.params.sort', sortArr); + field.decoratorProps.params = { ...fieldSchema['x-decorator-props'].params, page: 1 }; + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-decorator-props': fieldSchema['x-decorator-props'], + }, + }); + }} + /> + { + _.set(fieldSchema, 'x-decorator-props.params.pageSize', pageSize); + field.decoratorProps.params = { ...fieldSchema['x-decorator-props'].params, page: 1 }; + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-decorator-props': fieldSchema['x-decorator-props'], + }, + }); + }} + /> + + + + + ); }; diff --git a/packages/core/client/src/schema-component/antd/table-v2/TableBlockDesigner.tsx b/packages/core/client/src/schema-component/antd/table-v2/TableBlockDesigner.tsx index faa4942f0..ac8bccfc1 100644 --- a/packages/core/client/src/schema-component/antd/table-v2/TableBlockDesigner.tsx +++ b/packages/core/client/src/schema-component/antd/table-v2/TableBlockDesigner.tsx @@ -7,6 +7,7 @@ import { mergeFilter } from '../../../block-provider/SharedFilterProvider'; import { useCollection, useCollectionManager } from '../../../collection-manager'; import { useSortFields } from '../../../collection-manager/action-hooks'; import { FilterBlockType } from '../../../filter-provider/utils'; +import { RecordProvider, useRecord } from '../../../record-provider'; import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings'; import { useSchemaTemplate } from '../../../schema-templates'; import { useDesignable } from '../../hooks'; @@ -23,6 +24,8 @@ export const TableBlockDesigner = () => { const { service } = useTableBlockContext(); const { t } = useTranslation(); const { dn } = useDesignable(); + const record = useRecord(); + const defaultSort = fieldSchema?.['x-decorator-props']?.params?.sort || []; const defaultResource = fieldSchema?.['x-decorator-props']?.resource; const supportTemplate = !fieldSchema?.['x-decorator-props']?.disableTemplate; @@ -64,182 +67,185 @@ export const TableBlockDesigner = () => { [dn, field.decoratorProps, fieldSchema, service], ); return ( - - - {collection?.tree && collectionField?.collectionName === collectionField?.target && ( - { - field.decoratorProps.treeTable = flag; - fieldSchema['x-decorator-props'].treeTable = flag; - const params = { - ...service.params?.[0], - tree: flag ? true : null, - }; - dn.emit('patch', { - schema: fieldSchema, - }); - dn.refresh(); - service.run(params); - }} + // fix https://nocobase.height.app/T-2259 + + + + {collection?.tree && collectionField?.collectionName === collectionField?.target && ( + { + field.decoratorProps.treeTable = flag; + fieldSchema['x-decorator-props'].treeTable = flag; + const params = { + ...service.params?.[0], + tree: flag ? true : null, + }; + dn.emit('patch', { + schema: fieldSchema, + }); + dn.refresh(); + service.run(params); + }} + /> + )} + {sortable && ( + { + field.decoratorProps.dragSort = dragSort; + fieldSchema['x-decorator-props'].dragSort = dragSort; + service.run({ ...service.params?.[0], sort: 'sort' }); + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-decorator-props': fieldSchema['x-decorator-props'], + }, + }); + }} + /> + )} + + - )} - {sortable && ( - { - field.decoratorProps.dragSort = dragSort; - fieldSchema['x-decorator-props'].dragSort = dragSort; - service.run({ ...service.params?.[0], sort: 'sort' }); - dn.emit('patch', { - schema: { - ['x-uid']: fieldSchema['x-uid'], - 'x-decorator-props': fieldSchema['x-decorator-props'], - }, - }); - }} - /> - )} - - - {!dragSort && ( - { - const sortArr = sort.map((item) => { - return item.direction === 'desc' ? `-${item.field}` : item.field; - }); + } as ISchema + } + onSubmit={({ sort }) => { + const sortArr = sort.map((item) => { + return item.direction === 'desc' ? `-${item.field}` : item.field; + }); + const params = field.decoratorProps.params || {}; + params.sort = sortArr; + field.decoratorProps.params = params; + fieldSchema['x-decorator-props']['params'] = params; + dn.emit('patch', { + schema: { + ['x-uid']: fieldSchema['x-uid'], + 'x-decorator-props': fieldSchema['x-decorator-props'], + }, + }); + service.run({ ...service.params?.[0], sort: sortArr }); + }} + /> + )} + { const params = field.decoratorProps.params || {}; - params.sort = sortArr; + params.pageSize = pageSize; field.decoratorProps.params = params; fieldSchema['x-decorator-props']['params'] = params; + service.run({ ...service.params?.[0], pageSize, page: 1 }); dn.emit('patch', { schema: { ['x-uid']: fieldSchema['x-uid'], 'x-decorator-props': fieldSchema['x-decorator-props'], }, }); - service.run({ ...service.params?.[0], sort: sortArr }); }} /> - )} - { - const params = field.decoratorProps.params || {}; - params.pageSize = pageSize; - field.decoratorProps.params = params; - fieldSchema['x-decorator-props']['params'] = params; - service.run({ ...service.params?.[0], pageSize, page: 1 }); - dn.emit('patch', { - schema: { - ['x-uid']: fieldSchema['x-uid'], - 'x-decorator-props': fieldSchema['x-decorator-props'], - }, - }); - }} - /> - - {supportTemplate && } - {supportTemplate && ( - - )} - - - + + {supportTemplate && } + {supportTemplate && ( + + )} + + + + ); }; diff --git a/packages/core/client/src/schema-settings/VariableInput/hooks/useParentRecordVariable.ts b/packages/core/client/src/schema-settings/VariableInput/hooks/useParentRecordVariable.ts new file mode 100644 index 000000000..4624d9826 --- /dev/null +++ b/packages/core/client/src/schema-settings/VariableInput/hooks/useParentRecordVariable.ts @@ -0,0 +1,29 @@ +import { Schema } from '@formily/json-schema'; +import { useTranslation } from 'react-i18next'; +import { CollectionFieldOptions } from '../../../collection-manager'; +import { useBaseVariable } from './useBaseVariable'; + +interface Props { + collectionField: CollectionFieldOptions; + schema: any; + collectionName: string; + noDisabled?: boolean; + /** 消费变量值的字段 */ + targetFieldSchema?: Schema; +} + +export const useParentRecordVariable = (props: Props) => { + const { t } = useTranslation(); + + const currentRecordVariable = useBaseVariable({ + collectionField: props.collectionField, + uiSchema: props.schema, + name: '$nParentRecord', + title: t('Current parent record'), + collectionName: props.collectionName, + noDisabled: props.noDisabled, + targetFieldSchema: props.targetFieldSchema, + }); + + return currentRecordVariable; +}; 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 192349ec5..1c407ed9a 100644 --- a/packages/core/client/src/schema-settings/VariableInput/hooks/useVariableOptions.ts +++ b/packages/core/client/src/schema-settings/VariableInput/hooks/useVariableOptions.ts @@ -1,13 +1,14 @@ 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, useCollection } from '../../../collection-manager'; import { useFlag } from '../../../flag-provider'; import { useBlockCollection } from './useBlockCollection'; import { useDateVariable } from './useDateVariable'; import { useFormVariable } from './useFormVariable'; import { useIterationVariable } from './useIterationVariable'; +import { useParentRecordVariable } from './useParentRecordVariable'; import { useRecordVariable } from './useRecordVariable'; import { useUserVariable } from './useUserVariable'; @@ -44,11 +45,12 @@ export const useVariableOptions = ({ operator, noDisabled, targetFieldSchema, + record, }: Props) => { - const { name: blockCollectionName } = useBlockCollection(); + const { name: blockCollectionName = record?.__collectionName } = useBlockCollection(); const { isInSubForm, isInSubTable } = useFlag() || {}; - const { type: formBlockType } = useFormBlockType(); const { name } = useCollection(); + const blockParentCollectionName = record?.__parent?.__collectionName; const userVariable = useUserVariable({ maxDepth: 3, uiSchema: uiSchema, @@ -78,6 +80,13 @@ export const useVariableOptions = ({ noDisabled, targetFieldSchema, }); + const currentParentRecordVariable = useParentRecordVariable({ + schema: uiSchema, + collectionName: blockParentCollectionName, + collectionField, + noDisabled, + targetFieldSchema, + }); return useMemo(() => { return [ @@ -85,7 +94,10 @@ export const useVariableOptions = ({ dateVariable, form && !form.readPretty && formVariable, (isInSubForm || isInSubTable) && iterationVariable, - formBlockType === 'update' && currentRecordVariable, + blockCollectionName && !_.isEmpty(_.omit(record, ['__parent', '__collectionName'])) && currentRecordVariable, + blockParentCollectionName && + !_.isEmpty(_.omit(record?.__parent, ['__parent', '__collectionName'])) && + currentParentRecordVariable, ].filter(Boolean); }, [ userVariable, @@ -95,6 +107,10 @@ export const useVariableOptions = ({ isInSubForm, isInSubTable, iterationVariable, + blockCollectionName, + record, currentRecordVariable, + blockParentCollectionName, + currentParentRecordVariable, ]); }; diff --git a/packages/core/client/src/schema-settings/hooks/useParseDataScopeFilter.ts b/packages/core/client/src/schema-settings/hooks/useParseDataScopeFilter.ts index c09bb3cfc..d87635417 100644 --- a/packages/core/client/src/schema-settings/hooks/useParseDataScopeFilter.ts +++ b/packages/core/client/src/schema-settings/hooks/useParseDataScopeFilter.ts @@ -9,14 +9,15 @@ interface Props { * 需要排除的变量名称,例如:['$user', '$date'] * 被排除的变量不会被解析,会按原值返回 */ - exclude: string[]; + exclude?: string[]; + currentRecord?: any; } // TODO: 建议变量名统一命名为 `$n` 开头,以防止与 formily 内置变量冲突 const defaultExclude = ['$user', '$date', '$nDate']; -const useParseDataScopeFilter = ({ exclude }: Props = { exclude: defaultExclude }) => { - const localVariables = useLocalVariables(); +const useParseDataScopeFilter = ({ exclude = defaultExclude, currentRecord }: Props = {}) => { + const localVariables = useLocalVariables({ currentRecord }); const variables = useVariables(); const parseFilter = useCallback( diff --git a/packages/core/client/src/variables/hooks/useLocalVariables.tsx b/packages/core/client/src/variables/hooks/useLocalVariables.tsx index b3b6c7b88..f640ecb3e 100644 --- a/packages/core/client/src/variables/hooks/useLocalVariables.tsx +++ b/packages/core/client/src/variables/hooks/useLocalVariables.tsx @@ -1,5 +1,4 @@ import { Form } from '@formily/core'; -import _ from 'lodash'; import React, { useContext, useMemo } from 'react'; import { useFormBlockContext } from '../../block-provider'; import { useCollection } from '../../collection-manager'; @@ -42,12 +41,6 @@ const useLocalVariables = (props?: Props) => { name = props.collectionName; } - let blockRecord = currentRecord; - // 获取到最顶层的 record,即当前区块所在的 record - while (!_.isEmpty(blockRecord.__parent)) { - blockRecord = blockRecord.__parent; - } - return useMemo(() => { return ( [ @@ -57,7 +50,7 @@ const useLocalVariables = (props?: Props) => { */ { name: 'currentRecord', - ctx: blockRecord, + ctx: currentRecord, collectionName: name, }, /** @@ -66,7 +59,7 @@ const useLocalVariables = (props?: Props) => { */ { name, - ctx: form?.values || blockRecord, + ctx: form?.values || currentRecord, collectionName: name, }, /** @@ -80,8 +73,13 @@ const useLocalVariables = (props?: Props) => { }, { name: '$nRecord', - ctx: blockRecord, - collectionName: name, + ctx: currentRecord, + collectionName: currentRecord?.__collectionName, + }, + { + name: '$nParentRecord', + ctx: currentRecord?.__parent, + collectionName: currentRecord?.__parent?.__collectionName, }, { name: '$nForm', @@ -91,7 +89,7 @@ const useLocalVariables = (props?: Props) => { iterationCtx && { name: '$iteration', ctx: iterationCtx, collectionName: currentCollectionName }, ] as VariableOption[] ).filter(Boolean); - }, [blockRecord, name, form?.values, iterationCtx, currentCollectionName]); // 尽量保持返回的值不变,这样可以减少接口的请求次数,因为关系字段会缓存到变量的 ctx 中 + }, [currentRecord, name, form?.values, iterationCtx, currentCollectionName]); // 尽量保持返回的值不变,这样可以减少接口的请求次数,因为关系字段会缓存到变量的 ctx 中 }; export default useLocalVariables; diff --git a/packages/plugins/@nocobase/plugin-workflow/src/client/triggers/form.tsx b/packages/plugins/@nocobase/plugin-workflow/src/client/triggers/form.tsx index 41b64c49a..6ad4217ca 100644 --- a/packages/plugins/@nocobase/plugin-workflow/src/client/triggers/form.tsx +++ b/packages/plugins/@nocobase/plugin-workflow/src/client/triggers/form.tsx @@ -148,7 +148,6 @@ export function useTriggerWorkflowsActionProps() { return { async onClick() { - const fieldNames = fields.map((field) => field.name); const { assignedValues: originalAssignedValues = {}, onSuccess,