mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 14:26:36 +00:00
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:
parent
4ac2875d51
commit
aa96a16d1d
@ -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));
|
||||||
|
@ -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);
|
||||||
|
@ -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');
|
||||||
|
});
|
@ -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,
|
||||||
|
},
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user