diff --git a/packages/amis-core/__tests__/utils/math.test.ts b/packages/amis-core/__tests__/utils/math.test.ts index 8372dc405..96101a38a 100644 --- a/packages/amis-core/__tests__/utils/math.test.ts +++ b/packages/amis-core/__tests__/utils/math.test.ts @@ -1,4 +1,4 @@ -import {safeAdd, safeSub} from '../../src/utils/math'; +import {safeAdd, safeSub, numberFormatter} from '../../src/utils/math'; test(`math safeAdd:test`, () => { expect(safeAdd(0.1, 0.2)).toEqual(0.3); @@ -13,3 +13,14 @@ test(`math safeSub:test`, () => { expect(safeAdd(NaN, 1)).toEqual(NaN); expect(safeAdd(NaN, NaN)).toEqual(NaN); }); + +test('numberFormatter:test', () => { + expect(numberFormatter(0)).toEqual('0'); + expect(numberFormatter(0, 2)).toEqual('0.00'); + expect(numberFormatter(0, 8)).toEqual('0.00000000'); + expect(numberFormatter(123456)).toEqual('123,456'); + expect(numberFormatter(123456, 2)).toEqual('123,456.00'); + expect(numberFormatter(1234567890000)).toEqual('1,234,567,890,000'); + expect(numberFormatter(1234567890000, 4)).toEqual('1,234,567,890,000.0000'); + expect(numberFormatter(1000000000000000)).toEqual('1,000,000,000,000,000'); +}); diff --git a/packages/amis-core/src/utils/math.ts b/packages/amis-core/src/utils/math.ts index c16a41d79..d77c29027 100644 --- a/packages/amis-core/src/utils/math.ts +++ b/packages/amis-core/src/utils/math.ts @@ -30,3 +30,13 @@ export function safeSub(arg1: number, arg2: number) { maxDigits = Math.pow(10, Math.max(digits1, digits2)); return (arg1 * maxDigits - arg2 * maxDigits) / maxDigits; } + +export function numberFormatter(num: number | string, precision: number = 0) { + const ZERO = 0; + const number = +num; + if (typeof number === 'number' && !isNaN(number)) { + const regexp = precision ? /(\d)(?=(\d{3})+\.)/g : /(\d)(?=(\d{3})+$)/g; + return number.toFixed(precision).replace(regexp, '$1,'); + } + return ZERO.toFixed(precision); +} diff --git a/packages/amis/src/renderers/Form/InputNumber.tsx b/packages/amis/src/renderers/Form/InputNumber.tsx index cb98ddb7b..a7f78b268 100644 --- a/packages/amis/src/renderers/Form/InputNumber.tsx +++ b/packages/amis/src/renderers/Form/InputNumber.tsx @@ -13,6 +13,8 @@ import { filter, autobind, createObject, + numberFormatter, + safeSub, normalizeOptions, Option, PlainObject, @@ -96,8 +98,6 @@ export interface NumberControlSchema extends FormBaseControlSchema { displayMode?: 'base' | 'enhance'; } -const numberFormatter = new Intl.NumberFormat(); - export interface NumberProps extends FormControlProps { placeholder?: string; max?: number | string; @@ -150,6 +150,7 @@ interface NumberState { // 数字单位,将会影响输出 unit?: string; unitOptions?: Option[]; + inputing: boolean; } export type InputNumberRendererEvent = 'blur' | 'focus' | 'change'; @@ -163,7 +164,8 @@ export default class NumberControl extends React.Component< static defaultProps: Partial = { step: 1, resetValue: '', - clearValueOnEmpty: false + clearValueOnEmpty: false, + inputing: false }; constructor(props: NumberProps) { @@ -198,7 +200,7 @@ export default class NumberControl extends React.Component< } } - this.state = {unit, unitOptions}; + this.state = {unit, unitOptions, inputing: false}; } /** @@ -389,18 +391,17 @@ export default class NumberControl extends React.Component< id, env } = this.props; + const {inputing, unit} = this.state; const finalPrecision = this.filterNum(precision); - const unit = this.state?.unit; // 数据格式化 const formatter = kilobitSeparator || prefix || suffix ? (value: string | number) => { // 增加千分分隔 if (kilobitSeparator && value) { - value = numberFormatter.format(value as number); + value = numberFormatter(value, finalPrecision); } - - return (prefix ? prefix : '') + value + (suffix ? suffix : ''); + return `${prefix || ''}${value}${suffix || ''}`; } : undefined; // 将数字还原 @@ -436,7 +437,7 @@ export default class NumberControl extends React.Component< step={step} max={this.filterNum(max, big)} min={this.filterNum(min, big)} - formatter={formatter} + formatter={!inputing ? formatter : undefined} parser={parser} onChange={this.handleChange} disabled={disabled} @@ -445,8 +446,14 @@ export default class NumberControl extends React.Component< showSteps={showSteps} borderMode={borderMode} readOnly={readOnly} - onFocus={() => this.dispatchEvent('focus')} - onBlur={() => this.dispatchEvent('blur')} + onFocus={() => { + this.setState({inputing: true}); + this.dispatchEvent('focus'); + }} + onBlur={() => { + this.setState({inputing: false}); + this.dispatchEvent('blur'); + }} keyboard={keyboard} displayMode={displayMode} big={big}