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
This commit is contained in:
katherinehhh 2024-04-05 09:52:08 +08:00 committed by GitHub
parent 4ac2875d51
commit aa96a16d1d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 433 additions and 3 deletions

View File

@ -2,17 +2,29 @@ import { connect, mapReadPretty } from '@formily/react';
import { InputNumber as AntdNumber, InputNumberProps } from 'antd'; import { InputNumber as AntdNumber, InputNumberProps } from 'antd';
import React from 'react'; import React from 'react';
import { ReadPretty } from './ReadPretty'; import { ReadPretty } from './ReadPretty';
import BigNumber from 'bignumber.js';
type ComposedInputNumber = React.ForwardRefExoticComponent< type ComposedInputNumber = React.ForwardRefExoticComponent<
Pick<Partial<any>, string | number | symbol> & React.RefAttributes<unknown> Pick<Partial<any>, string | number | symbol> & React.RefAttributes<unknown>
> & { > & {
ReadPretty?: React.FC<InputNumberProps>; ReadPretty?: React.FC<InputNumberProps>;
}; };
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) => { export const InputNumber: ComposedInputNumber = connect((props) => {
const { onChange, ...others } = props; const { onChange, ...others } = props;
const handleChange = (v) => { const handleChange = (v) => {
onChange(Number.isNaN(v) ? null : v); if (Number.isNaN(v)) {
onChange(null);
} else {
console.log(toSafeNumber(v));
onChange(toSafeNumber(v));
}
}; };
return <AntdNumber onChange={handleChange} {...others} />; return <AntdNumber onChange={handleChange} {...others} />;
}, mapReadPretty(ReadPretty)); }, mapReadPretty(ReadPretty));

View File

@ -20,7 +20,7 @@ const separators = {
'0.00': { thousands: '', decimal: '.' }, // 没有千位分隔符 '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; let number = value;
if (formatStyle) { if (formatStyle) {
number = Number(value); number = Number(value);

View File

@ -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');
});

View File

@ -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,
},
};