n20-common-lib 3.3.14 → 3.3.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<el-descriptions class="n20-descriptions" :column="
|
|
2
|
+
<el-descriptions class="n20-descriptions" :column="currentColumn" size="default" border>
|
|
3
3
|
<slot></slot>
|
|
4
|
-
<template v-if="this.$slots.default.length === 1">
|
|
5
|
-
<el-descriptions-item v-for="(item, index) in
|
|
4
|
+
<template v-if="this.$slots.default && this.$slots.default.length === 1">
|
|
5
|
+
<el-descriptions-item v-for="(item, index) in currentColumn - 1" :key="index" />
|
|
6
6
|
</template>
|
|
7
7
|
</el-descriptions>
|
|
8
8
|
</template>
|
|
@@ -20,28 +20,48 @@ export default {
|
|
|
20
20
|
default: true
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
this.
|
|
26
|
-
|
|
23
|
+
data() {
|
|
24
|
+
return {
|
|
25
|
+
currentColumn: this.column
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
watch: {
|
|
29
|
+
column(val) {
|
|
30
|
+
this.currentColumn = val
|
|
31
|
+
},
|
|
32
|
+
autoResize(val) {
|
|
33
|
+
if (val) {
|
|
34
|
+
this.createResize()
|
|
35
|
+
} else {
|
|
36
|
+
this.currentColumn = this.column
|
|
37
|
+
this.destroyResize()
|
|
38
|
+
}
|
|
27
39
|
}
|
|
28
40
|
},
|
|
41
|
+
created() {
|
|
42
|
+
if (!this.autoResize) return
|
|
43
|
+
this.createResize()
|
|
44
|
+
},
|
|
29
45
|
beforeDestroy() {
|
|
30
|
-
|
|
46
|
+
this.destroyResize()
|
|
31
47
|
},
|
|
32
48
|
methods: {
|
|
33
49
|
resize() {
|
|
34
50
|
let wW = document.documentElement.clientWidth
|
|
35
51
|
if (wW <= 1024) {
|
|
36
|
-
this.
|
|
52
|
+
this.currentColumn = 1
|
|
37
53
|
} else if (wW > 1024 && wW <= 1600) {
|
|
38
|
-
this.
|
|
54
|
+
this.currentColumn = 2
|
|
39
55
|
} else if (wW > 1600 && wW <= 1920) {
|
|
40
|
-
this.
|
|
56
|
+
this.currentColumn = 3
|
|
41
57
|
} else if (wW > 1920) {
|
|
42
|
-
this.
|
|
58
|
+
this.currentColumn = 4
|
|
43
59
|
}
|
|
44
60
|
},
|
|
61
|
+
createResize() {
|
|
62
|
+
this.resize()
|
|
63
|
+
window.addEventListener('resize', this.resize)
|
|
64
|
+
},
|
|
45
65
|
destroyResize() {
|
|
46
66
|
window.removeEventListener('resize', this.resize)
|
|
47
67
|
}
|
|
@@ -31,10 +31,11 @@
|
|
|
31
31
|
| disabled | Boolean | undefined | 是否禁用 |
|
|
32
32
|
| isClearable | Boolean | false | 是否可清空 |
|
|
33
33
|
| placeholder | String | '请输入' | 占位提示文本 |
|
|
34
|
-
| dNum | Number | undefined | 小数位数,优先级低于format
|
|
34
|
+
| dNum | Number | undefined | 小数位数,优先级低于format;超过15位时以字符串保持精度 |
|
|
35
35
|
| format | String | undefined | 格式化字符串,如'0.00'表示保留2位小数 |
|
|
36
36
|
| suffix | String | '%' | 后缀文本,仅在type='rate'时有效 |
|
|
37
37
|
| rangeAuto | Boolean | false | 是否自动处理范围值 |
|
|
38
|
+
| isString | Boolean | false | 是否始终以字符串回传 input/change 值;小数位超过15位时自动按 true 处理 |
|
|
38
39
|
|
|
39
40
|
## 类型说明
|
|
40
41
|
|
|
@@ -60,6 +61,8 @@
|
|
|
60
61
|
|
|
61
62
|
## 事件
|
|
62
63
|
|
|
64
|
+
当 `dNum` 或 `format` 设置为超过 15 位小数时,组件会强制按 `isString=true` 处理,即使未显式配置 `isString`,`input` 和 `change` 也会回传字符串,避免 JavaScript `Number` 丢失精度;失焦时会按最大位数四舍五入并移除尾部 `0`,例如 `0.200000` 会回传 `"0.2"`。设置 `isString` 为 `true` 后,无论小数位数多少,`input` 和 `change` 都回传字符串;清空时回传空字符串。
|
|
65
|
+
|
|
63
66
|
| 事件名 | 说明 | 回调参数 |
|
|
64
67
|
| ------ | ----------- | ---- |
|
|
65
68
|
| input | 值改变时触发 | 当前值 |
|
|
@@ -109,4 +112,3 @@
|
|
|
109
112
|
<!-- 启用步进严格模式 -->
|
|
110
113
|
<InputNumber v-model="value" type="number" :step="0.5" :stepStrictly="true" />
|
|
111
114
|
```
|
|
112
|
-
|
|
@@ -33,7 +33,9 @@
|
|
|
33
33
|
<script>
|
|
34
34
|
import emitter from '../../utils/element-ui-emitter'
|
|
35
35
|
import { $lc } from '../../utils/i18n/index'
|
|
36
|
-
import N from '../../utils/numberPor'
|
|
36
|
+
import N, { addDecimal, compareDecimal, decimalToFixed, normalizeDecimal } from '../../utils/numberPor'
|
|
37
|
+
|
|
38
|
+
const MAX_SAFE_DECIMAL_PLACES = 15
|
|
37
39
|
|
|
38
40
|
export default {
|
|
39
41
|
name: 'InputNumber',
|
|
@@ -103,6 +105,10 @@ export default {
|
|
|
103
105
|
rangeAuto: {
|
|
104
106
|
type: Boolean,
|
|
105
107
|
default: false
|
|
108
|
+
},
|
|
109
|
+
isString: {
|
|
110
|
+
type: Boolean,
|
|
111
|
+
default: false
|
|
106
112
|
}
|
|
107
113
|
},
|
|
108
114
|
data() {
|
|
@@ -155,6 +161,20 @@ export default {
|
|
|
155
161
|
watch: {
|
|
156
162
|
value: {
|
|
157
163
|
handler(val) {
|
|
164
|
+
if (this.isHighPrecision()) {
|
|
165
|
+
if (val === undefined || val === null || val === '') {
|
|
166
|
+
this.valueStr = ''
|
|
167
|
+
} else {
|
|
168
|
+
const normalized = normalizeDecimal(val)
|
|
169
|
+
if (!normalized) {
|
|
170
|
+
this.valueStr = ''
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
const formatted = this.normalizeHighPrecisionValue(normalized)
|
|
174
|
+
this.valueStr = this.type === 'number' ? formatted : N.addThousands(formatted)
|
|
175
|
+
}
|
|
176
|
+
return
|
|
177
|
+
}
|
|
158
178
|
// number类型不启用千分位格式化,但应用小数位限制
|
|
159
179
|
if (this.type === 'number') {
|
|
160
180
|
if (val === undefined || val === null) {
|
|
@@ -189,6 +209,23 @@ export default {
|
|
|
189
209
|
}
|
|
190
210
|
},
|
|
191
211
|
methods: {
|
|
212
|
+
isHighPrecision() {
|
|
213
|
+
return this.fNum > MAX_SAFE_DECIMAL_PLACES
|
|
214
|
+
},
|
|
215
|
+
// 高精度小数会强制使用字符串回传,即使 isString 未开启。
|
|
216
|
+
shouldEmitString() {
|
|
217
|
+
return this.isString || this.isHighPrecision()
|
|
218
|
+
},
|
|
219
|
+
normalizeHighPrecisionValue(value) {
|
|
220
|
+
const normalized = normalizeDecimal(value)
|
|
221
|
+
if (!normalized) return ''
|
|
222
|
+
|
|
223
|
+
const decimalPart = normalized.split('.')[1] || ''
|
|
224
|
+
const roundedValue = this.rangeAuto && decimalPart.length >= this.fNum
|
|
225
|
+
? normalized
|
|
226
|
+
: decimalToFixed(normalized, this.fNum)
|
|
227
|
+
return normalizeDecimal(roundedValue)
|
|
228
|
+
},
|
|
192
229
|
focusFn() {
|
|
193
230
|
this.isFocus = true
|
|
194
231
|
if (!this.disabled && this.valueStr) {
|
|
@@ -210,6 +247,24 @@ export default {
|
|
|
210
247
|
},
|
|
211
248
|
stepFn(ev) {
|
|
212
249
|
if ((ev.code === 'ArrowUp' || ev.code === 'ArrowDown') && !this.disabled) {
|
|
250
|
+
if (this.isHighPrecision()) {
|
|
251
|
+
const currentValue = normalizeDecimal(this.valueStr)
|
|
252
|
+
if (!currentValue) return
|
|
253
|
+
|
|
254
|
+
ev.preventDefault()
|
|
255
|
+
const stepValue = N.toString(this.step)
|
|
256
|
+
let nextValue = addDecimal(currentValue, ev.code === 'ArrowUp' ? stepValue : '-' + stepValue)
|
|
257
|
+
if (compareDecimal(nextValue, this.min) < 0) {
|
|
258
|
+
nextValue = normalizeDecimal(this.min)
|
|
259
|
+
} else if (compareDecimal(nextValue, this.max) > 0) {
|
|
260
|
+
nextValue = normalizeDecimal(this.max)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const formatted = this.normalizeHighPrecisionValue(nextValue)
|
|
264
|
+
this.valueStr = this.type === 'number' ? formatted : N.addThousands(formatted)
|
|
265
|
+
return
|
|
266
|
+
}
|
|
267
|
+
|
|
213
268
|
let val = N(this.valueStr)
|
|
214
269
|
if (!isNaN(val)) {
|
|
215
270
|
ev.preventDefault()
|
|
@@ -243,14 +298,51 @@ export default {
|
|
|
243
298
|
this.changeIng = false
|
|
244
299
|
})
|
|
245
300
|
|
|
301
|
+
if (this.isHighPrecision()) {
|
|
302
|
+
const normalized = normalizeDecimal(valStr)
|
|
303
|
+
if (!normalized) {
|
|
304
|
+
this.valueStr = ''
|
|
305
|
+
const oldValue = this.value
|
|
306
|
+
if (oldValue || oldValue === 0 || oldValue === '0') {
|
|
307
|
+
const emptyValue = this.shouldEmitString() ? '' : undefined
|
|
308
|
+
this.$emit('input', emptyValue)
|
|
309
|
+
this.$emit('change', emptyValue)
|
|
310
|
+
this.dispatch('ElFormItem', 'el.form.change', [emptyValue])
|
|
311
|
+
}
|
|
312
|
+
return
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
let nextValue = this.normalizeHighPrecisionValue(normalized)
|
|
316
|
+
|
|
317
|
+
if (compareDecimal(nextValue, this.min) < 0) {
|
|
318
|
+
nextValue = normalizeDecimal(this.min)
|
|
319
|
+
} else if (compareDecimal(nextValue, this.max) > 0) {
|
|
320
|
+
nextValue = normalizeDecimal(this.max)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const formatted = this.type === 'number' ? nextValue : N.addThousands(nextValue)
|
|
324
|
+
this.valueStr = formatted
|
|
325
|
+
this.$nextTick(() => {
|
|
326
|
+
const oldValue = normalizeDecimal(this.value)
|
|
327
|
+
const normalizedNextValue = normalizeDecimal(nextValue)
|
|
328
|
+
if (oldValue !== normalizedNextValue) {
|
|
329
|
+
this.$emit('input', nextValue)
|
|
330
|
+
this.$emit('change', nextValue)
|
|
331
|
+
this.dispatch('ElFormItem', 'el.form.change', [nextValue])
|
|
332
|
+
}
|
|
333
|
+
})
|
|
334
|
+
return
|
|
335
|
+
}
|
|
336
|
+
|
|
246
337
|
let val = N(valStr)
|
|
247
338
|
if (isNaN(val)) {
|
|
248
339
|
this.valueStr = ''
|
|
249
340
|
let oVal = this.value
|
|
250
341
|
if (oVal || oVal === 0) {
|
|
251
|
-
this
|
|
252
|
-
this.$emit('
|
|
253
|
-
this
|
|
342
|
+
const emptyValue = this.shouldEmitString() ? '' : undefined
|
|
343
|
+
this.$emit('input', emptyValue)
|
|
344
|
+
this.$emit('change', emptyValue)
|
|
345
|
+
this.dispatch('ElFormItem', 'el.form.change', [emptyValue])
|
|
254
346
|
}
|
|
255
347
|
return
|
|
256
348
|
}
|
|
@@ -294,10 +386,12 @@ export default {
|
|
|
294
386
|
this.$nextTick(() => {
|
|
295
387
|
let nVar = Number(nStr)
|
|
296
388
|
let oVal = this.value
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
this
|
|
389
|
+
const emittedValue = this.shouldEmitString() ? nStr : nVar
|
|
390
|
+
const valueChanged = this.shouldEmitString() ? String(oVal) !== nStr : oVal !== nVar
|
|
391
|
+
if (valueChanged) {
|
|
392
|
+
this.$emit('input', emittedValue)
|
|
393
|
+
this.$emit('change', emittedValue)
|
|
394
|
+
this.dispatch('ElFormItem', 'el.form.change', [emittedValue])
|
|
301
395
|
}
|
|
302
396
|
})
|
|
303
397
|
}
|
package/src/utils/numberPor.js
CHANGED
|
@@ -197,6 +197,198 @@ export const subFixed = function (n, decimal = 6) {
|
|
|
197
197
|
return XEUtils.toFixed(n, decimal)
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
|
+
|
|
201
|
+
const decimalPattern = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/
|
|
202
|
+
|
|
203
|
+
function padRight(value, length) {
|
|
204
|
+
return value + '0'.repeat(Math.max(0, length - value.length))
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function padLeft(value, length) {
|
|
208
|
+
return '0'.repeat(Math.max(0, length - value.length)) + value
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* 规范化十进制数字字符串,不经过 Number,避免高精度小数丢失精度。
|
|
213
|
+
* @param {number|string} value
|
|
214
|
+
* @returns {string}
|
|
215
|
+
*/
|
|
216
|
+
export const normalizeDecimal = function (value) {
|
|
217
|
+
if (value === undefined || value === null || value === '') return ''
|
|
218
|
+
|
|
219
|
+
const stringValue = toString(value).replace(/,/g, '').trim()
|
|
220
|
+
if (!decimalPattern.test(stringValue)) return ''
|
|
221
|
+
|
|
222
|
+
const sign = stringValue.charAt(0) === '-' ? '-' : ''
|
|
223
|
+
const unsignedValue = stringValue.replace(/^[+-]/, '')
|
|
224
|
+
let [integerPart = '0', decimalPart = ''] = unsignedValue.split('.')
|
|
225
|
+
integerPart = integerPart.replace(/^0+(?=\d)/, '') || '0'
|
|
226
|
+
decimalPart = decimalPart.replace(/0+$/, '')
|
|
227
|
+
|
|
228
|
+
return sign + integerPart + (decimalPart ? '.' + decimalPart : '')
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function compareUnsignedDecimal(a, b) {
|
|
232
|
+
let [aInteger = '0', aDecimal = ''] = a.split('.')
|
|
233
|
+
let [bInteger = '0', bDecimal = ''] = b.split('.')
|
|
234
|
+
aInteger = aInteger.replace(/^0+(?=\d)/, '') || '0'
|
|
235
|
+
bInteger = bInteger.replace(/^0+(?=\d)/, '') || '0'
|
|
236
|
+
|
|
237
|
+
if (aInteger.length !== bInteger.length) {
|
|
238
|
+
return aInteger.length > bInteger.length ? 1 : -1
|
|
239
|
+
}
|
|
240
|
+
if (aInteger !== bInteger) return aInteger > bInteger ? 1 : -1
|
|
241
|
+
|
|
242
|
+
const decimalLength = Math.max(aDecimal.length, bDecimal.length)
|
|
243
|
+
aDecimal = padRight(aDecimal, decimalLength)
|
|
244
|
+
bDecimal = padRight(bDecimal, decimalLength)
|
|
245
|
+
if (aDecimal === bDecimal) return 0
|
|
246
|
+
return aDecimal > bDecimal ? 1 : -1
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* 比较两个十进制数字字符串。
|
|
251
|
+
* @param {number|string} left
|
|
252
|
+
* @param {number|string} right
|
|
253
|
+
* @returns {number} -1、0、1
|
|
254
|
+
*/
|
|
255
|
+
export const compareDecimal = function (left, right) {
|
|
256
|
+
const a = normalizeDecimal(left)
|
|
257
|
+
const b = normalizeDecimal(right)
|
|
258
|
+
if (!a || !b) return NaN
|
|
259
|
+
|
|
260
|
+
const aNegative = a.charAt(0) === '-'
|
|
261
|
+
const bNegative = b.charAt(0) === '-'
|
|
262
|
+
const aUnsigned = a.replace(/^-/, '')
|
|
263
|
+
const bUnsigned = b.replace(/^-/, '')
|
|
264
|
+
|
|
265
|
+
if (aNegative !== bNegative) return aNegative ? -1 : 1
|
|
266
|
+
const result = compareUnsignedDecimal(aUnsigned, bUnsigned)
|
|
267
|
+
return aNegative ? -result : result
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function incrementUnsignedDecimal(value) {
|
|
271
|
+
const digits = value.split('')
|
|
272
|
+
for (let i = digits.length - 1; i >= 0; i -= 1) {
|
|
273
|
+
if (digits[i] === '9') {
|
|
274
|
+
digits[i] = '0'
|
|
275
|
+
} else {
|
|
276
|
+
digits[i] = String(Number(digits[i]) + 1)
|
|
277
|
+
return digits.join('')
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return '1' + digits.join('')
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* 使用字符串运算按指定小数位四舍五入,不经过 Number。
|
|
285
|
+
* @param {number|string} value
|
|
286
|
+
* @param {number} decimal
|
|
287
|
+
* @returns {string}
|
|
288
|
+
*/
|
|
289
|
+
export const decimalToFixed = function (value, decimal = 0) {
|
|
290
|
+
const normalized = normalizeDecimal(value)
|
|
291
|
+
if (!normalized) return ''
|
|
292
|
+
|
|
293
|
+
const precision = Math.max(0, Number(decimal) || 0)
|
|
294
|
+
const negative = normalized.charAt(0) === '-'
|
|
295
|
+
const unsignedValue = normalized.replace(/^-/, '')
|
|
296
|
+
let [integerPart = '0', decimalPart = ''] = unsignedValue.split('.')
|
|
297
|
+
const shouldRound = decimalPart.length > precision && decimalPart.charAt(precision) >= '5'
|
|
298
|
+
decimalPart = padRight(decimalPart.slice(0, precision), precision)
|
|
299
|
+
|
|
300
|
+
if (shouldRound) {
|
|
301
|
+
const incremented = incrementUnsignedDecimal(integerPart + decimalPart)
|
|
302
|
+
integerPart = incremented.slice(0, Math.max(1, incremented.length - precision))
|
|
303
|
+
decimalPart = precision ? padLeft(incremented.slice(-precision), precision) : ''
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return (negative ? '-' : '') + integerPart + (precision ? '.' + decimalPart : '')
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function addUnsignedDecimal(left, right) {
|
|
310
|
+
let [leftInteger = '0', leftDecimal = ''] = left.split('.')
|
|
311
|
+
let [rightInteger = '0', rightDecimal = ''] = right.split('.')
|
|
312
|
+
const decimalLength = Math.max(leftDecimal.length, rightDecimal.length)
|
|
313
|
+
leftDecimal = padRight(leftDecimal, decimalLength)
|
|
314
|
+
rightDecimal = padRight(rightDecimal, decimalLength)
|
|
315
|
+
|
|
316
|
+
let carry = 0
|
|
317
|
+
let result = ''
|
|
318
|
+
const leftDigits = (leftInteger + leftDecimal).split('')
|
|
319
|
+
const rightDigits = (rightInteger + rightDecimal).split('')
|
|
320
|
+
const length = Math.max(leftDigits.length, rightDigits.length)
|
|
321
|
+
for (let i = 0; i < length; i += 1) {
|
|
322
|
+
const leftDigit = Number(leftDigits[leftDigits.length - 1 - i] || 0)
|
|
323
|
+
const rightDigit = Number(rightDigits[rightDigits.length - 1 - i] || 0)
|
|
324
|
+
const sum = leftDigit + rightDigit + carry
|
|
325
|
+
result = String(sum % 10) + result
|
|
326
|
+
carry = Math.floor(sum / 10)
|
|
327
|
+
}
|
|
328
|
+
if (carry) result = String(carry) + result
|
|
329
|
+
|
|
330
|
+
const integerLength = result.length - decimalLength
|
|
331
|
+
const integerPart = result.slice(0, Math.max(1, integerLength))
|
|
332
|
+
const decimalPart = decimalLength ? result.slice(-decimalLength) : ''
|
|
333
|
+
return integerPart + (decimalPart ? '.' + decimalPart : '')
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function subtractUnsignedDecimal(left, right) {
|
|
337
|
+
let [leftInteger = '0', leftDecimal = ''] = left.split('.')
|
|
338
|
+
let [rightInteger = '0', rightDecimal = ''] = right.split('.')
|
|
339
|
+
const decimalLength = Math.max(leftDecimal.length, rightDecimal.length)
|
|
340
|
+
leftDecimal = padRight(leftDecimal, decimalLength)
|
|
341
|
+
rightDecimal = padRight(rightDecimal, decimalLength)
|
|
342
|
+
|
|
343
|
+
let borrow = 0
|
|
344
|
+
let result = ''
|
|
345
|
+
const leftDigits = (leftInteger + leftDecimal).split('')
|
|
346
|
+
const rightDigits = (rightInteger + rightDecimal).split('')
|
|
347
|
+
const length = Math.max(leftDigits.length, rightDigits.length)
|
|
348
|
+
for (let i = 0; i < length; i += 1) {
|
|
349
|
+
let leftDigit = Number(leftDigits[leftDigits.length - 1 - i] || 0) - borrow
|
|
350
|
+
const rightDigit = Number(rightDigits[rightDigits.length - 1 - i] || 0)
|
|
351
|
+
if (leftDigit < rightDigit) {
|
|
352
|
+
leftDigit += 10
|
|
353
|
+
borrow = 1
|
|
354
|
+
} else {
|
|
355
|
+
borrow = 0
|
|
356
|
+
}
|
|
357
|
+
result = String(leftDigit - rightDigit) + result
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const integerLength = result.length - decimalLength
|
|
361
|
+
const integerPart = result.slice(0, Math.max(1, integerLength)).replace(/^0+(?=\d)/, '') || '0'
|
|
362
|
+
const decimalPart = decimalLength ? result.slice(-decimalLength) : ''
|
|
363
|
+
return integerPart + (decimalPart ? '.' + decimalPart : '')
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* 高精度十进制加法,不经过 Number。
|
|
368
|
+
* @param {number|string} left
|
|
369
|
+
* @param {number|string} right
|
|
370
|
+
* @returns {string}
|
|
371
|
+
*/
|
|
372
|
+
export const addDecimal = function (left, right) {
|
|
373
|
+
const a = normalizeDecimal(left)
|
|
374
|
+
const b = normalizeDecimal(right)
|
|
375
|
+
if (!a || !b) return ''
|
|
376
|
+
|
|
377
|
+
const aNegative = a.charAt(0) === '-'
|
|
378
|
+
const bNegative = b.charAt(0) === '-'
|
|
379
|
+
const aUnsigned = a.replace(/^-/, '')
|
|
380
|
+
const bUnsigned = b.replace(/^-/, '')
|
|
381
|
+
|
|
382
|
+
if (aNegative === bNegative) {
|
|
383
|
+
const result = addUnsignedDecimal(aUnsigned, bUnsigned)
|
|
384
|
+
return (aNegative ? '-' : '') + normalizeDecimal(result)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const comparison = compareUnsignedDecimal(aUnsigned, bUnsigned)
|
|
388
|
+
if (comparison === 0) return '0'
|
|
389
|
+
if (comparison > 0) return (aNegative ? '-' : '') + normalizeDecimal(subtractUnsignedDecimal(aUnsigned, bUnsigned))
|
|
390
|
+
return (bNegative ? '-' : '') + normalizeDecimal(subtractUnsignedDecimal(bUnsigned, aUnsigned))
|
|
391
|
+
}
|
|
200
392
|
/**
|
|
201
393
|
* 将数字或字符串格式的数字转换为千位分隔符格式的字符串
|
|
202
394
|
* @param {number|string} number - 待转换的数字或字符串格式的数字
|