diff --git a/packages/core/client/src/modules/form-creation/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/form-creation/__e2e__/schemaSettings.test.ts index c7cd813d2..6773dffec 100644 --- a/packages/core/client/src/modules/form-creation/__e2e__/schemaSettings.test.ts +++ b/packages/core/client/src/modules/form-creation/__e2e__/schemaSettings.test.ts @@ -9,7 +9,7 @@ import { oneTableBlockWithAddNewAndViewAndEditAndBasicFields, test, } from '@nocobase/test/e2e'; -import { T2165, T2174 } from './templatesOfBug'; +import { T2165, T2174, T3251 } from './templatesOfBug'; const clickOption = async (page: Page, optionName: string) => { await page.getByLabel('block-item-CardItem-general-form').hover(); @@ -211,7 +211,7 @@ test.describe('creation form block schema settings', () => { ).toHaveValue('123'); }); - // fix https://nocobase.height.app/T-2165 + // https://nocobase.height.app/T-2165 test('variable labels should be displayed normally', async ({ page, mockPage }) => { await mockPage(T2165).goto(); @@ -222,6 +222,38 @@ test.describe('creation form block schema settings', () => { await expect(page.getByText('Current form / Nickname')).toBeVisible(); await expect(page.getByText('Current form / Phone')).toBeVisible(); }); + + // https://nocobase.height.app/T-3251 + test('nested conditions', async ({ page, mockPage }) => { + await mockPage(T3251).goto(); + + // 一开始 email 字段是可编辑的 + await expect( + page.getByLabel('block-item-CollectionField-users-form-users.email-Email').getByRole('textbox'), + ).toBeEditable(); + + // 满足联动规则条件时,email 字段应该是禁用的 + await page + .getByLabel('block-item-CollectionField-users-form-users.nickname-Nickname') + .getByRole('textbox') + .fill('nickname'); + await page + .getByLabel('block-item-CollectionField-users-form-users.username-Username') + .getByRole('textbox') + .fill('username'); + await expect( + page.getByLabel('block-item-CollectionField-users-form-users.email-Email').getByRole('textbox'), + ).toBeDisabled(); + + // 再次改成不满足条件时,email 字段应该是可编辑的 + await page + .getByLabel('block-item-CollectionField-users-form-users.nickname-Nickname') + .getByRole('textbox') + .clear(); + await expect( + page.getByLabel('block-item-CollectionField-users-form-users.email-Email').getByRole('textbox'), + ).toBeEditable(); + }); }); test('Save as block template & convert reference to duplicate', async ({ page, mockPage }) => { diff --git a/packages/core/client/src/modules/form-creation/__e2e__/templatesOfBug.ts b/packages/core/client/src/modules/form-creation/__e2e__/templatesOfBug.ts index 69a53bcd9..9f77d8448 100644 --- a/packages/core/client/src/modules/form-creation/__e2e__/templatesOfBug.ts +++ b/packages/core/client/src/modules/form-creation/__e2e__/templatesOfBug.ts @@ -5246,3 +5246,248 @@ export const T3106: PageConfig = { 'x-async': true, }, }; + +export const T3251: PageConfig = { + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + wthxmf7a7vt: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + properties: { + xovhjqo0uig: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + e6ltgswudd5: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + zhip07zf2sk: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + 'x-acl-action': 'users:create', + 'x-decorator': 'FormBlockProvider', + 'x-decorator-props': { + resource: 'users', + collection: 'users', + }, + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-component-props': {}, + properties: { + o14tnfwmiah: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + properties: { + grid: { + 'x-uid': 'fcczneadfb7', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + 'x-linkage-rules': [ + { + condition: { + $and: [ + { + nickname: { + $includes: 'nickname', + }, + }, + { + $and: [ + { + username: { + $includes: 'username', + }, + }, + ], + }, + ], + }, + actions: [ + { + targetFields: ['email'], + operator: 'disabled', + }, + ], + }, + ], + properties: { + gjzekanhi3t: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + ql3al6wtn1j: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + nickname: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'users.nickname', + 'x-component-props': {}, + 'x-uid': 'by956vuuq17', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '67iwm2hgafu', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '66ccfjw2mqq', + 'x-async': false, + 'x-index': 1, + }, + iw013a1ahid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + frgfw52u7q1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + username: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'users.username', + 'x-component-props': {}, + 'x-uid': 'en26umyz49e', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'oc78q5uf599', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xf0m0i82wx6', + 'x-async': false, + 'x-index': 2, + }, + xeop5qaq5wo: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + x1uk4pvrsrj: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + email: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'users.email', + 'x-component-props': {}, + 'x-uid': 'ow19p5g3ed3', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '25jhpf6i8mi', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ujz8f344x8l', + 'x-async': false, + 'x-index': 3, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + c1nzoyb7v3f: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'FormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + 'x-uid': 'vnkbks8htxa', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'kwjha09k4k3', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '8zffjdnv1ps', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'j2l9f3xw0j9', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'tqovgfp1kw0', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'kwi4lems81c', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'zq9yecy6wri', + 'x-async': true, + 'x-index': 1, + }, +}; diff --git a/packages/core/client/src/schema-component/antd/form-v2/Form.tsx b/packages/core/client/src/schema-component/antd/form-v2/Form.tsx index 1643db46c..3a423398e 100644 --- a/packages/core/client/src/schema-component/antd/form-v2/Form.tsx +++ b/packages/core/client/src/schema-component/antd/form-v2/Form.tsx @@ -298,15 +298,24 @@ function getFieldNameByOperator(operator: ActionType) { function getFieldValuesInCondition({ linkageRules, formValues }) { return linkageRules.map((rule) => { - const type = Object.keys(rule.condition)[0] || '$and'; - const conditions = rule.condition[type]; + const run = (condition) => { + const type = Object.keys(condition)[0] || '$and'; + const conditions = condition[type]; - return conditions - .map((condition) => { - const path = getTargetField(condition).join('.'); - return getValuesByPath(formValues, path); - }) - .filter(Boolean); + return conditions + .map((condition) => { + // fix https://nocobase.height.app/T-3251 + if ('$and' in condition || '$or' in condition) { + return run(condition); + } + + const path = getTargetField(condition).join('.'); + return getValuesByPath(formValues, path); + }) + .filter(Boolean); + }; + + return run(rule.condition); }); }