@nstc-business/imes 1.0.37 → 1.0.38

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@nstc-business/imes",
3
- "version": "1.0.37",
3
+ "version": "1.0.38",
4
4
  "private": false,
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -0,0 +1,126 @@
1
+ /**
2
+ * 数字框十进制步进
3
+ * 时间:2026-09-15
4
+ * 人员:AI && 徐红飞
5
+ * 入参:raw 当前精确数字文本;delta 步进值(可正可负)
6
+ * 出参:相加后的十进制字符串;空入参返回 ''
7
+ * 方法内容:用字符串对齐小数位后 BigInt 加减,避免 Number 累加丢精度(如 0.1+0.2)
8
+ */
9
+
10
+ /**
11
+ * 十进制字符串加减
12
+ * 时间:2026-09-15
13
+ * 人员:AI && 徐红飞
14
+ * 入参:raw 数字或数字字符串;delta 步进值
15
+ * 出参:结果字符串
16
+ * 方法内容:两侧都转普通十进制串后对齐相加,去掉结果小数尾零
17
+ */
18
+ export function addDecimalText(raw, delta) {
19
+ if (raw === '' || raw == null) return ''
20
+ const left = toPlainDecimal(raw)
21
+ const right = toPlainDecimal(delta)
22
+ if (left == null || right == null) return String(raw)
23
+ return addPlainDecimals(left, right)
24
+ }
25
+
26
+ /**
27
+ * 转普通十进制字符串
28
+ * 时间:2026-09-15
29
+ * 人员:AI && 徐红飞
30
+ * 入参:val 数字或字符串
31
+ * 出参:普通十进制串;非法返回 null
32
+ * 方法内容:去千分位;科学计数法则按指数展开
33
+ */
34
+ function toPlainDecimal(val) {
35
+ if (val === '' || val == null) return null
36
+ if (typeof val === 'number') {
37
+ if (!Number.isFinite(val)) return null
38
+ return expandScientific(String(val))
39
+ }
40
+ let s = String(val).replace(/,/g, '').trim()
41
+ if (!s || s === '-' || s === '.' || s === '+' || s === '-.') return null
42
+ if (/[eE]/.test(s)) {
43
+ const n = Number(s)
44
+ if (!Number.isFinite(n)) return null
45
+ return expandScientific(String(n))
46
+ }
47
+ if (!/^[+-]?(\d+(\.\d*)?|\.\d+)$/.test(s)) return null
48
+ if (s.charAt(0) === '+') s = s.slice(1)
49
+ if (s.charAt(0) === '.') s = '0' + s
50
+ if (s.startsWith('-.')) s = '-0' + s.slice(1)
51
+ return s
52
+ }
53
+
54
+ /**
55
+ * 展开科学计数法字符串
56
+ * 时间:2026-09-15
57
+ * 人员:AI && 徐红飞
58
+ * 入参:s Number 的 String 结果
59
+ * 出参:不含 e 的十进制串
60
+ * 方法内容:按指数移动小数点
61
+ */
62
+ function expandScientific(s) {
63
+ if (!/[eE]/.test(s)) return s
64
+ const sign = s.charAt(0) === '-' ? '-' : ''
65
+ const body = sign ? s.slice(1) : s
66
+ const [coeff, expStr] = body.split(/[eE]/)
67
+ let exp = Number(expStr)
68
+ const digits = coeff.replace('.', '')
69
+ const decLen = (coeff.split('.')[1] || '').length
70
+ exp -= decLen
71
+ if (exp >= 0) {
72
+ return sign + digits + '0'.repeat(exp)
73
+ }
74
+ const zeros = Math.abs(exp) - 1
75
+ return sign + '0.' + '0'.repeat(zeros) + digits
76
+ }
77
+
78
+ /**
79
+ * 两个普通十进制串相加
80
+ * 时间:2026-09-15
81
+ * 人员:AI && 徐红飞
82
+ * 入参:a、b 普通十进制串
83
+ * 出参:和的十进制串(去掉小数尾零)
84
+ * 方法内容:对齐小数位后用有符号 BigInt 相加
85
+ */
86
+ function addPlainDecimals(a, b) {
87
+ const pa = parseParts(a)
88
+ const pb = parseParts(b)
89
+ const scale = Math.max(pa.frac.length, pb.frac.length)
90
+ const ia = toScaledInt(pa, scale)
91
+ const ib = toScaledInt(pb, scale)
92
+ const sum = ia + ib
93
+ return formatScaledInt(sum, scale)
94
+ }
95
+
96
+ function parseParts(str) {
97
+ const neg = str.charAt(0) === '-'
98
+ if (neg) str = str.slice(1)
99
+ let [intPart, frac = ''] = str.split('.')
100
+ intPart = intPart || '0'
101
+ return { neg, intPart, frac }
102
+ }
103
+
104
+ function toScaledInt(parts, scale) {
105
+ const frac = parts.frac.padEnd(scale, '0')
106
+ const digits = (parts.intPart + frac).replace(/^0+(?=\d)/, '') || '0'
107
+ const n = BigInt(digits)
108
+ return parts.neg ? -n : n
109
+ }
110
+
111
+ function formatScaledInt(n, scale) {
112
+ const neg = n < 0n
113
+ let s = (neg ? -n : n).toString()
114
+ if (scale === 0) {
115
+ return (neg && s !== '0' ? '-' : '') + s
116
+ }
117
+ if (s.length <= scale) {
118
+ s = s.padStart(scale + 1, '0')
119
+ }
120
+ let intPart = s.slice(0, s.length - scale) || '0'
121
+ let frac = s.slice(s.length - scale)
122
+ frac = frac.replace(/0+$/, '')
123
+ const body = frac ? `${intPart}.${frac}` : intPart
124
+ if (body === '0') return '0'
125
+ return (neg ? '-' : '') + body
126
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * 数字步进:十进制字符串加减
3
+ * 上下键步进用,禁止 Number 累加丢精度
4
+ */
5
+ const fs = require('fs')
6
+ const path = require('path')
7
+
8
+ const src = fs
9
+ .readFileSync(path.join(__dirname, 'numberStep.js'), 'utf8')
10
+ .replace(/export /g, '')
11
+ const exportsFromSrc = {}
12
+ new Function('exports', src + '\nexports.addDecimalText = addDecimalText')(
13
+ exportsFromSrc
14
+ )
15
+ const { addDecimalText } = exportsFromSrc
16
+
17
+ const cases = [
18
+ ['1', 1, '2'],
19
+ ['1.5', 1, '2.5'],
20
+ ['160835267.0579509644', 1, '160835268.0579509644'],
21
+ ['0.1', 0.2, '0.3'],
22
+ ['-1', 1, '0'],
23
+ ['10', -3, '7'],
24
+ ['1.00', 1, '2'],
25
+ ['', 1, ''],
26
+ [null, 1, '']
27
+ ]
28
+
29
+ for (const [raw, delta, expected] of cases) {
30
+ const actual = addDecimalText(raw, delta)
31
+ if (actual !== expected) {
32
+ throw new Error(
33
+ `addDecimalText(${JSON.stringify(raw)}, ${delta}) 期望 ${expected},实际 ${actual}`
34
+ )
35
+ }
36
+ }
37
+
38
+ console.log('numberStep.test.js passed')