From aa96a16d1d49064575ccd2fb9c592279356bdc70 Mon Sep 17 00:00:00 2001 From: katherinehhh Date: Fri, 5 Apr 2024 09:52:08 +0800 Subject: [PATCH] fix: formula field calculation error (#3929) * fix: formula field calculation error * fix: bug * fix: bug * fix: bug * fix: bug * fix: bug * fix: bug * test: foumula e2e test --- .../antd/input-number/InputNumber.tsx | 16 +- .../antd/input-number/ReadPretty.tsx | 2 +- .../src/client/__e2e__/form-create.test.ts | 24 ++ .../src/client/__e2e__/form-edit.test.ts | 0 .../src/client/__e2e__/utils.ts | 394 ++++++++++++++++++ 5 files changed, 433 insertions(+), 3 deletions(-) create mode 100644 packages/plugins/@nocobase/plugin-formula-field/src/client/__e2e__/form-create.test.ts delete mode 100644 packages/plugins/@nocobase/plugin-formula-field/src/client/__e2e__/form-edit.test.ts diff --git a/packages/core/client/src/schema-component/antd/input-number/InputNumber.tsx b/packages/core/client/src/schema-component/antd/input-number/InputNumber.tsx index 6d75dcdeb9..6467908f5a 100644 --- a/packages/core/client/src/schema-component/antd/input-number/InputNumber.tsx +++ b/packages/core/client/src/schema-component/antd/input-number/InputNumber.tsx @@ -2,17 +2,29 @@ import { connect, mapReadPretty } from '@formily/react'; import { InputNumber as AntdNumber, InputNumberProps } from 'antd'; import React from 'react'; import { ReadPretty } from './ReadPretty'; +import BigNumber from 'bignumber.js'; type ComposedInputNumber = React.ForwardRefExoticComponent< Pick, string | number | symbol> & React.RefAttributes > & { ReadPretty?: React.FC; }; - +function toSafeNumber(value) { + if (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER) { + return new BigNumber(value).toString(); + } else { + return value; + } +} export const InputNumber: ComposedInputNumber = connect((props) => { const { onChange, ...others } = props; const handleChange = (v) => { - onChange(Number.isNaN(v) ? null : v); + if (Number.isNaN(v)) { + onChange(null); + } else { + console.log(toSafeNumber(v)); + onChange(toSafeNumber(v)); + } }; return ; }, mapReadPretty(ReadPretty)); diff --git a/packages/core/client/src/schema-component/antd/input-number/ReadPretty.tsx b/packages/core/client/src/schema-component/antd/input-number/ReadPretty.tsx index 97c749ad4a..7e4954fc13 100644 --- a/packages/core/client/src/schema-component/antd/input-number/ReadPretty.tsx +++ b/packages/core/client/src/schema-component/antd/input-number/ReadPretty.tsx @@ -20,7 +20,7 @@ const separators = { '0.00': { thousands: '', decimal: '.' }, // 没有千位分隔符 }; //分隔符换算 -export function formatNumberWithSeparator(value, format = '0.00', step = 1, formatStyle) { +export function formatNumberWithSeparator(value, format = '0.00', step = 1, formatStyle?) { let number = value; if (formatStyle) { number = Number(value); diff --git a/packages/plugins/@nocobase/plugin-formula-field/src/client/__e2e__/form-create.test.ts b/packages/plugins/@nocobase/plugin-formula-field/src/client/__e2e__/form-create.test.ts new file mode 100644 index 0000000000..2d8c35afb9 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-formula-field/src/client/__e2e__/form-create.test.ts @@ -0,0 +1,24 @@ +import { T3879 } from './utils'; + +import { test, expect } from '@nocobase/test/e2e'; + +// https://nocobase.height.app/T-3529 +test('formula field calculation', async ({ page, mockPage }) => { + const nocoPage = await mockPage(T3879).waitForInit(); + await nocoPage.goto(); + await page.getByLabel('block-item-CardItem-general-').click(); + await page + .getByLabel('block-item-CollectionField-general-form-general.number1-number1') + .getByRole('spinbutton') + .click(); + await page + .getByLabel('block-item-CollectionField-general-form-general.number1-number1') + .getByRole('spinbutton') + .fill('3'); + await page.getByLabel('block-item-CollectionField-general-form-general.number2-number2').click(); + await page + .getByLabel('block-item-CollectionField-general-form-general.number2-number2') + .getByRole('spinbutton') + .fill('3'); + await expect(await page.locator('.nb-read-pretty-input-number').innerText()).toBe('6'); +}); diff --git a/packages/plugins/@nocobase/plugin-formula-field/src/client/__e2e__/form-edit.test.ts b/packages/plugins/@nocobase/plugin-formula-field/src/client/__e2e__/form-edit.test.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/plugins/@nocobase/plugin-formula-field/src/client/__e2e__/utils.ts b/packages/plugins/@nocobase/plugin-formula-field/src/client/__e2e__/utils.ts index e69de29bb2..ab7ee2bdf5 100644 --- a/packages/plugins/@nocobase/plugin-formula-field/src/client/__e2e__/utils.ts +++ b/packages/plugins/@nocobase/plugin-formula-field/src/client/__e2e__/utils.ts @@ -0,0 +1,394 @@ +import { PageConfig } from '@nocobase/test/e2e'; + +export const T3879: PageConfig = { + collections: [ + { + name: 'general', + fields: [ + { + key: 'ojv1s67810y', + name: 'id', + type: 'bigInt', + interface: 'integer', + description: null, + collectionName: 'general', + parentKey: null, + reverseKey: null, + autoIncrement: true, + primaryKey: true, + allowNull: false, + uiSchema: { + type: 'number', + title: '{{t("ID")}}', + 'x-component': 'InputNumber', + 'x-read-pretty': true, + }, + }, + { + key: '0ahsnha9s0i', + name: 'createdAt', + type: 'date', + interface: 'createdAt', + description: null, + collectionName: 'general', + parentKey: null, + reverseKey: null, + field: 'createdAt', + uiSchema: { + type: 'datetime', + title: '{{t("Created at")}}', + 'x-component': 'DatePicker', + 'x-component-props': {}, + 'x-read-pretty': true, + }, + }, + { + key: 'u8mym9tukph', + name: 'createdBy', + type: 'belongsTo', + interface: 'createdBy', + description: null, + collectionName: 'general', + parentKey: null, + reverseKey: null, + target: 'users', + foreignKey: 'createdById', + uiSchema: { + type: 'object', + title: '{{t("Created by")}}', + 'x-component': 'AssociationField', + 'x-component-props': { + fieldNames: { + value: 'id', + label: 'nickname', + }, + }, + 'x-read-pretty': true, + }, + targetKey: 'id', + }, + { + key: '1o03q1bmmpm', + name: 'updatedAt', + type: 'date', + interface: 'updatedAt', + description: null, + collectionName: 'general', + parentKey: null, + reverseKey: null, + field: 'updatedAt', + uiSchema: { + type: 'string', + title: '{{t("Last updated at")}}', + 'x-component': 'DatePicker', + 'x-component-props': {}, + 'x-read-pretty': true, + }, + }, + { + key: 'xhhbeil1yyd', + name: 'updatedBy', + type: 'belongsTo', + interface: 'updatedBy', + description: null, + collectionName: 'general', + parentKey: null, + reverseKey: null, + target: 'users', + foreignKey: 'updatedById', + uiSchema: { + type: 'object', + title: '{{t("Last updated by")}}', + 'x-component': 'AssociationField', + 'x-component-props': { + fieldNames: { + value: 'id', + label: 'nickname', + }, + }, + 'x-read-pretty': true, + }, + targetKey: 'id', + }, + { + key: 'z37glqjfxsu', + name: 'number1', + type: 'double', + interface: 'number', + description: null, + collectionName: 'general', + parentKey: null, + reverseKey: null, + uiSchema: { + 'x-component-props': { + step: '1', + stringMode: true, + }, + type: 'number', + 'x-component': 'InputNumber', + title: 'number1', + }, + }, + { + key: '9u6q4vycsiw', + name: 'number2', + type: 'double', + interface: 'number', + description: null, + collectionName: 'general', + parentKey: null, + reverseKey: null, + uiSchema: { + 'x-component-props': { + step: '1', + stringMode: true, + }, + type: 'number', + 'x-component': 'InputNumber', + title: 'number2', + }, + }, + { + key: 'sxy03y6frg3', + name: 'formula', + type: 'formula', + interface: 'formula', + description: null, + collectionName: 'general', + parentKey: null, + reverseKey: null, + dataType: 'double', + uiSchema: { + 'x-component-props': { + step: '1', + stringMode: true, + }, + type: 'string', + 'x-component': 'Formula.Result', + 'x-read-pretty': true, + title: 'formula', + }, + engine: 'math.js', + expression: '{{number1}}+{{number2}}', + }, + ], + }, + ], + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + '8hkd58b3qnq': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'page:addBlock', + properties: { + '52dyxddrvtm': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + i1kv7cehwlv: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + '4j1qw9tuuae': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: true, + }, + 'x-acl-action': 'general:create', + 'x-decorator': 'FormBlockProvider', + 'x-use-decorator-props': 'useCreateFormBlockDecoratorProps', + 'x-decorator-props': { + dataSource: 'main', + collection: 'general', + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:createForm', + 'x-component': 'CardItem', + properties: { + jj471ycbuz0: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-use-component-props': 'useCreateFormBlockProps', + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'form:configureFields', + properties: { + '860f2ujyhx2': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + thtymo9b987: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + number1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': 'FormItemSchemaToolbar', + 'x-settings': 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.number1', + 'x-component-props': {}, + 'x-uid': 'afjer0fjqx6', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ec4uvlevafy', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'bgjkklybgur', + 'x-async': false, + 'x-index': 1, + }, + ogiz7jghxo2: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + tn4unrkfwt7: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + number2: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': 'FormItemSchemaToolbar', + 'x-settings': 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.number2', + 'x-component-props': {}, + 'x-uid': 'terpf07giw3', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'h8igfdq7r9m', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '9p03cl31g6b', + 'x-async': false, + 'x-index': 2, + }, + n5en8fni23d: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + properties: { + i5ydxdhtbg1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + properties: { + formula: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': 'FormItemSchemaToolbar', + 'x-settings': 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': 'general.formula', + 'x-component-props': {}, + 'x-read-pretty': true, + 'x-uid': 's6wgood8gvh', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'vegea94g2p3', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 't3e5slk8oz0', + 'x-async': false, + 'x-index': 3, + }, + }, + 'x-uid': 'ch6n1991w36', + 'x-async': false, + 'x-index': 1, + }, + '58gw5mli2ch': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'createForm:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + 'x-uid': '2z5u3wiumtl', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': '2wsiciz1bzn', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '0qha4fhtb5c', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'zy5e2j75f5v', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '0cw0sjxwlli', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '13kkb5ow3ex', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'otwpz1wc0af', + 'x-async': true, + 'x-index': 1, + }, +};