@nstc-business/imes 1.0.35 → 1.0.36
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
|
@@ -85,8 +85,9 @@
|
|
|
85
85
|
|
|
86
86
|
<script>
|
|
87
87
|
import { InputNumber } from './ui'
|
|
88
|
-
import {
|
|
88
|
+
import { addThousands } from '../common'
|
|
89
89
|
import { formatScoreText } from './helpers'
|
|
90
|
+
import { formatFixedDecimal } from './ui/numberFormat'
|
|
90
91
|
|
|
91
92
|
export default {
|
|
92
93
|
name: 'MeasureStatCell',
|
|
@@ -120,9 +121,9 @@ export default {
|
|
|
120
121
|
originalValue(cell) {
|
|
121
122
|
const val = cell.indicatorResult
|
|
122
123
|
if (val === '' || val == null) return ''
|
|
123
|
-
let text =
|
|
124
|
+
let text = formatFixedDecimal(val, this.digits)
|
|
124
125
|
if (cell.showStyle === 2) {
|
|
125
|
-
text = addThousands(
|
|
126
|
+
text = addThousands(text)
|
|
126
127
|
}
|
|
127
128
|
const suffix = cell.displayStyle === 1 && (val || val === 0) ? '%' : ''
|
|
128
129
|
return text + suffix
|
|
@@ -144,9 +145,9 @@ export default {
|
|
|
144
145
|
const val = cell.value
|
|
145
146
|
if (val === '' || val == null) return ''
|
|
146
147
|
if (typeof val === 'object' && val.scoreText) return val.scoreText
|
|
147
|
-
let text = val || val === 0 ?
|
|
148
|
+
let text = val || val === 0 ? formatFixedDecimal(val, this.digits) : ''
|
|
148
149
|
if (cell.showStyle === 2 && text) {
|
|
149
|
-
text = addThousands(
|
|
150
|
+
text = addThousands(text)
|
|
150
151
|
}
|
|
151
152
|
const suffix = cell.displayStyle === 1 && (val || val === 0) ? '%' : ''
|
|
152
153
|
return text + suffix
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
import { N } from 'n20-common-lib'
|
|
12
12
|
import { addThousands } from '../common'
|
|
13
13
|
import { resolveManualFillValue, statItemChildren } from './statModelHelper'
|
|
14
|
+
import { formatFixedDecimal } from './ui/numberFormat'
|
|
14
15
|
|
|
15
16
|
export const ITEM_TYPE = {
|
|
16
17
|
CALC_MODEL: 11,
|
|
@@ -239,7 +240,7 @@ export function formatModelResultText(val, modelWrap, options = {}) {
|
|
|
239
240
|
if (val === '' || val == null) return ''
|
|
240
241
|
const num = Number(val)
|
|
241
242
|
if (Number.isNaN(num)) return String(val)
|
|
242
|
-
let text = num
|
|
243
|
+
let text = formatFixedDecimal(num, modelResultDigits(modelWrap))
|
|
243
244
|
if (options.thousands) {
|
|
244
245
|
text = addThousands(text)
|
|
245
246
|
}
|
|
@@ -255,7 +256,7 @@ export function formatScoreText(val, options = {}) {
|
|
|
255
256
|
if (val === '' || val == null) return ''
|
|
256
257
|
const num = Number(val)
|
|
257
258
|
if (Number.isNaN(num)) return String(val)
|
|
258
|
-
let text = num
|
|
259
|
+
let text = formatFixedDecimal(num, SCORE_DIGITS)
|
|
259
260
|
if (options.thousands) {
|
|
260
261
|
text = addThousands(text)
|
|
261
262
|
}
|
|
@@ -396,7 +397,7 @@ export function indicatorResultText(row, modelWrap) {
|
|
|
396
397
|
const suffix =
|
|
397
398
|
row.displayStyle === 1 && (raw || raw === 0) ? '%' : ''
|
|
398
399
|
if (raw || raw === 0) {
|
|
399
|
-
value =
|
|
400
|
+
value = formatFixedDecimal(raw, digitsCalc(row, modelWrap))
|
|
400
401
|
if (row.showStyle === 2) {
|
|
401
402
|
value = addThousands(value)
|
|
402
403
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 测算数字展示格式化
|
|
3
|
+
* 时间:2026-09-14
|
|
4
|
+
* 人员:AI && 徐红飞
|
|
5
|
+
* 入参:val 原始值;digits 小数位数
|
|
6
|
+
* 出参:指定小数位的十进制字符串
|
|
7
|
+
* 方法内容:不用 Number.toFixed。JS 二进制浮点会把 132898923.63 格式化成 132898923.6299999952
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 按指定小数位四舍五入格式化数字
|
|
12
|
+
* 时间:2026-09-14
|
|
13
|
+
* 人员:AI && 徐红飞
|
|
14
|
+
* 入参:val 数字或数字字符串;digits 小数位数
|
|
15
|
+
* 出参:格式化后的字符串;空值返回 '';非数字字符串原样返回
|
|
16
|
+
* 方法内容:先转最短十进制串再按位四舍五入补零,避开原生 toFixed 的精度噪声
|
|
17
|
+
*/
|
|
18
|
+
export function formatFixedDecimal(val, digits) {
|
|
19
|
+
if (val === '' || val == null) return ''
|
|
20
|
+
const raw = typeof val === 'string' ? val.replace(/,/g, '').trim() : val
|
|
21
|
+
if (raw === '') return ''
|
|
22
|
+
if (typeof raw === 'string' && Number.isNaN(Number(raw))) {
|
|
23
|
+
return String(val)
|
|
24
|
+
}
|
|
25
|
+
const n = typeof raw === 'number' ? raw : Number(raw)
|
|
26
|
+
if (Number.isNaN(n)) return String(val)
|
|
27
|
+
const d = digits == null || digits === '' ? 2 : Number(digits)
|
|
28
|
+
if (!Number.isFinite(d) || d < 0) return String(n)
|
|
29
|
+
return roundPlainDecimal(numberToPlainString(n), d)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 把 Number 转成普通十进制字符串(处理科学计数法)
|
|
34
|
+
* 时间:2026-09-14
|
|
35
|
+
* 人员:AI && 徐红飞
|
|
36
|
+
* 入参:n 有限数字
|
|
37
|
+
* 出参:不含 e 的十进制字符串
|
|
38
|
+
* 方法内容:String(n) 遇到科学计数法时按指数展开
|
|
39
|
+
*/
|
|
40
|
+
function numberToPlainString(n) {
|
|
41
|
+
const s = String(n)
|
|
42
|
+
if (!/[eE]/.test(s)) return s
|
|
43
|
+
const sign = s.charAt(0) === '-' ? '-' : ''
|
|
44
|
+
const body = sign ? s.slice(1) : s
|
|
45
|
+
const [coeff, expStr] = body.split(/[eE]/)
|
|
46
|
+
let exp = Number(expStr)
|
|
47
|
+
const digits = coeff.replace('.', '')
|
|
48
|
+
const decLen = (coeff.split('.')[1] || '').length
|
|
49
|
+
exp -= decLen
|
|
50
|
+
if (exp >= 0) {
|
|
51
|
+
return sign + digits + '0'.repeat(exp)
|
|
52
|
+
}
|
|
53
|
+
const zeros = Math.abs(exp) - 1
|
|
54
|
+
return sign + '0.' + '0'.repeat(zeros) + digits
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 对普通十进制字符串按小数位四舍五入并补零
|
|
59
|
+
* 时间:2026-09-14
|
|
60
|
+
* 人员:AI && 徐红飞
|
|
61
|
+
* 入参:str 十进制字符串;digits 小数位数
|
|
62
|
+
* 出参:补齐小数位后的字符串
|
|
63
|
+
* 方法内容:用整数进位避免浮点乘法误差
|
|
64
|
+
*/
|
|
65
|
+
function roundPlainDecimal(str, digits) {
|
|
66
|
+
const neg = str.charAt(0) === '-'
|
|
67
|
+
if (neg) str = str.slice(1)
|
|
68
|
+
let [intPart, frac = ''] = str.split('.')
|
|
69
|
+
intPart = intPart || '0'
|
|
70
|
+
if (digits === 0) {
|
|
71
|
+
const roundUp = (frac.charAt(0) || '0') >= '5'
|
|
72
|
+
let i = BigInt(intPart)
|
|
73
|
+
if (roundUp) i += 1n
|
|
74
|
+
return (neg && i !== 0n ? '-' : '') + i.toString()
|
|
75
|
+
}
|
|
76
|
+
frac = frac.padEnd(digits + 1, '0')
|
|
77
|
+
const keep = frac.slice(0, digits)
|
|
78
|
+
const next = frac.charAt(digits)
|
|
79
|
+
if (next >= '5') {
|
|
80
|
+
const width = intPart.length + digits
|
|
81
|
+
const asInt = BigInt(intPart + keep) + 1n
|
|
82
|
+
let s = asInt.toString()
|
|
83
|
+
if (s.length < width) s = s.padStart(width, '0')
|
|
84
|
+
intPart = s.slice(0, s.length - digits) || '0'
|
|
85
|
+
frac = s.slice(s.length - digits)
|
|
86
|
+
} else {
|
|
87
|
+
frac = keep
|
|
88
|
+
}
|
|
89
|
+
return (neg ? '-' : '') + intPart + '.' + frac
|
|
90
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 数字展示精度:禁止 Number.toFixed 把 132898923.63 显示成 132898923.6299999952
|
|
3
|
+
*/
|
|
4
|
+
const fs = require('fs')
|
|
5
|
+
const path = require('path')
|
|
6
|
+
|
|
7
|
+
const src = fs
|
|
8
|
+
.readFileSync(path.join(__dirname, 'numberFormat.js'), 'utf8')
|
|
9
|
+
.replace(/export /g, '')
|
|
10
|
+
const exportsFromSrc = {}
|
|
11
|
+
new Function('exports', src + '\nexports.formatFixedDecimal = formatFixedDecimal')(
|
|
12
|
+
exportsFromSrc
|
|
13
|
+
)
|
|
14
|
+
const { formatFixedDecimal } = exportsFromSrc
|
|
15
|
+
|
|
16
|
+
const nativeBug = (132898923.63).toFixed(10)
|
|
17
|
+
if (nativeBug !== '132898923.6299999952') {
|
|
18
|
+
throw new Error('用例前提变化:原生 toFixed(10) 不再复现 6299999952,实际: ' + nativeBug)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const padded = formatFixedDecimal(132898923.63, 10)
|
|
22
|
+
if (padded !== '132898923.6300000000') {
|
|
23
|
+
throw new Error('10 位应补零为 132898923.6300000000,实际: ' + padded)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const two = formatFixedDecimal(132898923.63, 2)
|
|
27
|
+
if (two !== '132898923.63') {
|
|
28
|
+
throw new Error('2 位应为 132898923.63,实际: ' + two)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const empty = formatFixedDecimal(null, 10)
|
|
32
|
+
if (empty !== '') {
|
|
33
|
+
throw new Error('空值应返回空字符串,实际: ' + empty)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const text = formatFixedDecimal('abc', 2)
|
|
37
|
+
if (text !== 'abc') {
|
|
38
|
+
throw new Error('非数字字符串应原样返回,实际: ' + text)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const rounded = formatFixedDecimal(1.239, 2)
|
|
42
|
+
if (rounded !== '1.24') {
|
|
43
|
+
throw new Error('四舍五入 1.239 保留 2 位应为 1.24,实际: ' + rounded)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log('numberFormat.test.js passed')
|