react-util-tools 1.0.0

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.
@@ -0,0 +1,335 @@
1
+ # Format 工具
2
+
3
+ 提供金额、数字、百分比等格式化和反格式化功能的工具函数集合。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install your-package-name
9
+ ```
10
+
11
+ ## 使用方法
12
+
13
+ ### 导入
14
+
15
+ ```typescript
16
+ import {
17
+ formatMoney,
18
+ parseMoney,
19
+ formatNumber,
20
+ formatMoneyToChinese,
21
+ formatPercent
22
+ } from 'your-package-name'
23
+ ```
24
+
25
+ ## API
26
+
27
+ ### formatMoney - 金额格式化
28
+
29
+ 将数字格式化为带货币符号和千分位的金额字符串。
30
+
31
+ **参数:**
32
+ - `amount`: 金额数字或字符串
33
+ - `options`: 格式化选项
34
+ - `decimals`: 小数位数,默认 2
35
+ - `symbol`: 货币符号,默认 '¥'
36
+ - `separator`: 千分位分隔符,默认 ','
37
+ - `decimalPoint`: 小数点符号,默认 '.'
38
+
39
+ **返回:** 格式化后的金额字符串
40
+
41
+ **示例:**
42
+
43
+ ```typescript
44
+ // 基础用法
45
+ formatMoney(1234.56)
46
+ // "¥1,234.56"
47
+
48
+ formatMoney(1234567.89)
49
+ // "¥1,234,567.89"
50
+
51
+ // 自定义小数位数
52
+ formatMoney(1234.5, { decimals: 0 })
53
+ // "¥1,235"
54
+
55
+ formatMoney(1234.5, { decimals: 3 })
56
+ // "¥1,234.500"
57
+
58
+ // 自定义货币符号
59
+ formatMoney(1234.56, { symbol: '$' })
60
+ // "$1,234.56"
61
+
62
+ formatMoney(1234.56, { symbol: '€' })
63
+ // "€1,234.56"
64
+
65
+ formatMoney(1234.56, { symbol: '' })
66
+ // "1,234.56"
67
+
68
+ // 自定义分隔符
69
+ formatMoney(1234.56, { separator: ' ', decimalPoint: ',' })
70
+ // "¥1 234,56"
71
+
72
+ // 处理负数
73
+ formatMoney(-1234.56)
74
+ // "-¥1,234.56"
75
+
76
+ // 字符串输入
77
+ formatMoney('1234.56')
78
+ // "¥1,234.56"
79
+ ```
80
+
81
+ ### parseMoney - 金额反格式化
82
+
83
+ 将格式化的金额字符串转换为数字。
84
+
85
+ **参数:**
86
+ - `formattedAmount`: 格式化的金额字符串
87
+
88
+ **返回:** 数字
89
+
90
+ **示例:**
91
+
92
+ ```typescript
93
+ parseMoney('¥1,234.56')
94
+ // 1234.56
95
+
96
+ parseMoney('$1,234,567.89')
97
+ // 1234567.89
98
+
99
+ parseMoney('€1 234,56')
100
+ // 1234.56
101
+
102
+ parseMoney('-¥1,234.56')
103
+ // -1234.56
104
+
105
+ parseMoney('1,234.56')
106
+ // 1234.56
107
+
108
+ // 处理无效输入
109
+ parseMoney('')
110
+ // 0
111
+
112
+ parseMoney('abc')
113
+ // 0
114
+ ```
115
+
116
+ ### formatNumber - 数字格式化(简化版)
117
+
118
+ 只添加千分位分隔符,不添加货币符号。
119
+
120
+ **参数:**
121
+ - `amount`: 数字或字符串
122
+ - `decimals`: 小数位数,默认 2
123
+
124
+ **返回:** 格式化后的数字字符串
125
+
126
+ **示例:**
127
+
128
+ ```typescript
129
+ formatNumber(1234.56)
130
+ // "1,234.56"
131
+
132
+ formatNumber(1234567.89)
133
+ // "1,234,567.89"
134
+
135
+ formatNumber(1234.5, 0)
136
+ // "1,235"
137
+
138
+ formatNumber(1234.5, 3)
139
+ // "1,234.500"
140
+ ```
141
+
142
+ ### formatMoneyToChinese - 金额转中文大写
143
+
144
+ 将金额数字转换为中文大写金额(常用于财务票据)。
145
+
146
+ **参数:**
147
+ - `amount`: 金额数字或字符串
148
+
149
+ **返回:** 中文大写金额字符串
150
+
151
+ **示例:**
152
+
153
+ ```typescript
154
+ formatMoneyToChinese(1234.56)
155
+ // "壹仟贰佰叁拾肆元伍角陆分"
156
+
157
+ formatMoneyToChinese(10000)
158
+ // "壹万元整"
159
+
160
+ formatMoneyToChinese(100000000)
161
+ // "壹亿元整"
162
+
163
+ formatMoneyToChinese(1234.50)
164
+ // "壹仟贰佰叁拾肆元伍角"
165
+
166
+ formatMoneyToChinese(1234.00)
167
+ // "壹仟贰佰叁拾肆元整"
168
+
169
+ formatMoneyToChinese(0.56)
170
+ // "零元伍角陆分"
171
+
172
+ formatMoneyToChinese(10086.08)
173
+ // "壹万零捌拾陆元零捌分"
174
+ ```
175
+
176
+ ### formatPercent - 格式化为百分比
177
+
178
+ 将数值格式化为百分比字符串。
179
+
180
+ **参数:**
181
+ - `value`: 数值
182
+ - `options`: 格式化选项
183
+ - `decimals`: 小数位数,默认 2
184
+ - `multiply`: 是否需要乘以 100,默认 true
185
+
186
+ **返回:** 百分比字符串
187
+
188
+ **示例:**
189
+
190
+ ```typescript
191
+ // 输入 0-1 的小数(默认会乘以 100)
192
+ formatPercent(0.1234)
193
+ // "12.34%"
194
+
195
+ formatPercent(0.5)
196
+ // "50.00%"
197
+
198
+ formatPercent(1)
199
+ // "100.00%"
200
+
201
+ // 自定义小数位数
202
+ formatPercent(0.1234, { decimals: 0 })
203
+ // "12%"
204
+
205
+ formatPercent(0.1234, { decimals: 4 })
206
+ // "12.3400%"
207
+
208
+ // 输入已经是百分比数值(不需要乘以 100)
209
+ formatPercent(12.34, { multiply: false })
210
+ // "12.34%"
211
+
212
+ formatPercent(50, { multiply: false, decimals: 0 })
213
+ // "50%"
214
+ ```
215
+
216
+ ## 实际应用场景
217
+
218
+ ### 电商价格显示
219
+
220
+ ```typescript
221
+ import { formatMoney } from 'your-package-name'
222
+
223
+ // 商品价格
224
+ const product = {
225
+ price: 1299.99,
226
+ originalPrice: 1599.00
227
+ }
228
+
229
+ console.log(`现价:${formatMoney(product.price)}`)
230
+ // "现价:¥1,299.99"
231
+
232
+ console.log(`原价:${formatMoney(product.originalPrice)}`)
233
+ // "原价:¥1,599.00"
234
+
235
+ // 美元价格
236
+ console.log(formatMoney(product.price, { symbol: '$' }))
237
+ // "$1,299.99"
238
+ ```
239
+
240
+ ### 表单输入处理
241
+
242
+ ```typescript
243
+ import { formatMoney, parseMoney } from 'your-package-name'
244
+
245
+ // 输入框失焦时格式化
246
+ input.addEventListener('blur', (e) => {
247
+ const value = e.target.value
248
+ const number = parseMoney(value)
249
+ e.target.value = formatMoney(number)
250
+ })
251
+
252
+ // 提交表单时获取原始数值
253
+ form.addEventListener('submit', (e) => {
254
+ const formattedValue = input.value // "¥1,234.56"
255
+ const actualValue = parseMoney(formattedValue) // 1234.56
256
+
257
+ // 提交到后端
258
+ submitData({ amount: actualValue })
259
+ })
260
+ ```
261
+
262
+ ### 财务报表
263
+
264
+ ```typescript
265
+ import { formatMoney, formatMoneyToChinese } from 'your-package-name'
266
+
267
+ const invoice = {
268
+ amount: 12345.67
269
+ }
270
+
271
+ console.log(`金额:${formatMoney(invoice.amount)}`)
272
+ // "金额:¥12,345.67"
273
+
274
+ console.log(`大写:${formatMoneyToChinese(invoice.amount)}`)
275
+ // "大写:壹万贰仟叁佰肆拾伍元陆角柒分"
276
+ ```
277
+
278
+ ### 数据统计展示
279
+
280
+ ```typescript
281
+ import { formatNumber, formatPercent } from 'your-package-name'
282
+
283
+ const stats = {
284
+ totalUsers: 1234567,
285
+ activeRate: 0.8523,
286
+ growthRate: 0.1234
287
+ }
288
+
289
+ console.log(`总用户数:${formatNumber(stats.totalUsers, 0)}`)
290
+ // "总用户数:1,234,567"
291
+
292
+ console.log(`活跃率:${formatPercent(stats.activeRate)}`)
293
+ // "活跃率:85.23%"
294
+
295
+ console.log(`增长率:${formatPercent(stats.growthRate, { decimals: 1 })}`)
296
+ // "增长率:12.3%"
297
+ ```
298
+
299
+ ### 购物车总价计算
300
+
301
+ ```typescript
302
+ import { formatMoney, parseMoney } from 'your-package-name'
303
+
304
+ const cartItems = [
305
+ { name: '商品A', price: '¥1,234.56', quantity: 2 },
306
+ { name: '商品B', price: '¥567.89', quantity: 1 }
307
+ ]
308
+
309
+ // 计算总价
310
+ const total = cartItems.reduce((sum, item) => {
311
+ return sum + parseMoney(item.price) * item.quantity
312
+ }, 0)
313
+
314
+ console.log(`总计:${formatMoney(total)}`)
315
+ // "总计:¥3,037.01"
316
+ ```
317
+
318
+ ## TypeScript 支持
319
+
320
+ 完整的 TypeScript 类型支持。
321
+
322
+ ```typescript
323
+ const formatted: string = formatMoney(1234.56)
324
+ const parsed: number = parseMoney('¥1,234.56')
325
+ const chinese: string = formatMoneyToChinese(1234.56)
326
+ const percent: string = formatPercent(0.5)
327
+ ```
328
+
329
+ ## 注意事项
330
+
331
+ - `formatMoney` 会自动处理四舍五入
332
+ - `parseMoney` 会移除所有非数字字符(除了小数点和负号)
333
+ - `formatMoneyToChinese` 只支持到兆位,超出范围可能显示不正确
334
+ - 所有格式化函数都会处理无效输入,返回合理的默认值
335
+ - 金额计算建议使用专门的货币库(如 dinero.js)以避免浮点数精度问题
@@ -0,0 +1,189 @@
1
+ /**
2
+ * 金额格式化:将数字格式化为金额字符串
3
+ * @param amount 金额数字
4
+ * @param options 格式化选项
5
+ * @returns 格式化后的金额字符串
6
+ */
7
+ export function formatMoney(
8
+ amount: number | string,
9
+ options: {
10
+ decimals?: number // 小数位数,默认 2
11
+ symbol?: string // 货币符号,默认 '¥'
12
+ separator?: string // 千分位分隔符,默认 ','
13
+ decimalPoint?: string // 小数点符号,默认 '.'
14
+ } = {}
15
+ ): string {
16
+ const {
17
+ decimals = 2,
18
+ symbol = '¥',
19
+ separator = ',',
20
+ decimalPoint = '.'
21
+ } = options
22
+
23
+ // 转换为数字
24
+ const num = typeof amount === 'string' ? parseFloat(amount) : amount
25
+
26
+ // 处理无效数字
27
+ if (isNaN(num)) {
28
+ return `${symbol}0${decimalPoint}${'0'.repeat(decimals)}`
29
+ }
30
+
31
+ // 处理负数
32
+ const isNegative = num < 0
33
+ const absNum = Math.abs(num)
34
+
35
+ // 固定小数位
36
+ const fixed = absNum.toFixed(decimals)
37
+ const [integerPart, decimalPart] = fixed.split('.')
38
+
39
+ // 添加千分位分隔符
40
+ const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, separator)
41
+
42
+ // 组合结果
43
+ let result = symbol + formattedInteger
44
+ if (decimals > 0 && decimalPart) {
45
+ result += decimalPoint + decimalPart
46
+ }
47
+
48
+ return isNegative ? `-${result}` : result
49
+ }
50
+
51
+ /**
52
+ * 金额反格式化:将格式化的金额字符串转换为数字
53
+ * @param formattedAmount 格式化的金额字符串
54
+ * @returns 数字
55
+ */
56
+ export function parseMoney(formattedAmount: string): number {
57
+ if (!formattedAmount || typeof formattedAmount !== 'string') {
58
+ return 0
59
+ }
60
+
61
+ // 移除所有非数字、小数点、负号的字符
62
+ const cleaned = formattedAmount.replace(/[^\d.-]/g, '')
63
+
64
+ // 转换为数字
65
+ const num = parseFloat(cleaned)
66
+
67
+ return isNaN(num) ? 0 : num
68
+ }
69
+
70
+ /**
71
+ * 金额格式化(简化版):只添加千分位分隔符
72
+ * @param amount 金额数字
73
+ * @param decimals 小数位数,默认 2
74
+ * @returns 格式化后的金额字符串(不含货币符号)
75
+ */
76
+ export function formatNumber(amount: number | string, decimals = 2): string {
77
+ const num = typeof amount === 'string' ? parseFloat(amount) : amount
78
+
79
+ if (isNaN(num)) {
80
+ return '0.' + '0'.repeat(decimals)
81
+ }
82
+
83
+ const fixed = num.toFixed(decimals)
84
+ const [integerPart, decimalPart] = fixed.split('.')
85
+
86
+ const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',')
87
+
88
+ return decimals > 0 && decimalPart
89
+ ? `${formattedInteger}.${decimalPart}`
90
+ : formattedInteger
91
+ }
92
+
93
+ /**
94
+ * 金额转中文大写
95
+ * @param amount 金额数字
96
+ * @returns 中文大写金额
97
+ */
98
+ export function formatMoneyToChinese(amount: number | string): string {
99
+ const num = typeof amount === 'string' ? parseFloat(amount) : amount
100
+
101
+ if (isNaN(num) || num < 0) {
102
+ return '零元整'
103
+ }
104
+
105
+ const digits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
106
+ const units = ['', '拾', '佰', '仟']
107
+ const bigUnits = ['', '万', '亿', '兆']
108
+ const decimalUnits = ['角', '分']
109
+
110
+ // 分离整数和小数部分
111
+ const [integerPart, decimalPart] = num.toFixed(2).split('.')
112
+ let result = ''
113
+
114
+ // 处理整数部分
115
+ if (integerPart === '0') {
116
+ result = '零元'
117
+ } else {
118
+ const integerStr = integerPart
119
+ const len = integerStr.length
120
+ let zeroCount = 0
121
+
122
+ for (let i = 0; i < len; i++) {
123
+ const digit = parseInt(integerStr[i])
124
+ const unitIndex = (len - i - 1) % 4
125
+ const bigUnitIndex = Math.floor((len - i - 1) / 4)
126
+
127
+ if (digit === 0) {
128
+ zeroCount++
129
+ } else {
130
+ if (zeroCount > 0) {
131
+ result += '零'
132
+ }
133
+ result += digits[digit] + units[unitIndex]
134
+ zeroCount = 0
135
+ }
136
+
137
+ if (unitIndex === 0 && bigUnitIndex > 0) {
138
+ if (result[result.length - 1] !== bigUnits[bigUnitIndex]) {
139
+ result += bigUnits[bigUnitIndex]
140
+ }
141
+ }
142
+ }
143
+
144
+ result += '元'
145
+ }
146
+
147
+ // 处理小数部分
148
+ if (decimalPart && decimalPart !== '00') {
149
+ const jiao = parseInt(decimalPart[0])
150
+ const fen = parseInt(decimalPart[1])
151
+
152
+ if (jiao > 0) {
153
+ result += digits[jiao] + decimalUnits[0]
154
+ } else if (fen > 0) {
155
+ result += '零'
156
+ }
157
+
158
+ if (fen > 0) {
159
+ result += digits[fen] + decimalUnits[1]
160
+ }
161
+ } else {
162
+ result += '整'
163
+ }
164
+
165
+ return result
166
+ }
167
+
168
+ /**
169
+ * 格式化为百分比
170
+ * @param value 数值(0-1 或 0-100)
171
+ * @param options 格式化选项
172
+ * @returns 百分比字符串
173
+ */
174
+ export function formatPercent(
175
+ value: number,
176
+ options: {
177
+ decimals?: number // 小数位数,默认 2
178
+ multiply?: boolean // 是否需要乘以 100,默认 true(当输入为 0-1 时)
179
+ } = {}
180
+ ): string {
181
+ const { decimals = 2, multiply = true } = options
182
+
183
+ if (isNaN(value)) {
184
+ return '0%'
185
+ }
186
+
187
+ const num = multiply ? value * 100 : value
188
+ return num.toFixed(decimals) + '%'
189
+ }
package/src/index.ts ADDED
@@ -0,0 +1,107 @@
1
+ // 按需导出:支持 Tree Shaking
2
+ export { throttle, debounce } from './throttle/index'
3
+ export { getQueryParam, getAllQueryParams, getQueryParamAll } from './address/index'
4
+ export {
5
+ getOS,
6
+ getBrowser,
7
+ getBrowserEngine,
8
+ getBrowserVersion,
9
+ isMobile,
10
+ isTablet,
11
+ isDesktop,
12
+ getDeviceType,
13
+ isIOS,
14
+ isAndroid,
15
+ isWeChat,
16
+ isTouchDevice,
17
+ getDevicePixelRatio,
18
+ getScreenResolution,
19
+ getViewportSize,
20
+ getDeviceInfo
21
+ } from './device/index'
22
+ export {
23
+ formatMoney,
24
+ parseMoney,
25
+ formatNumber,
26
+ formatMoneyToChinese,
27
+ formatPercent
28
+ } from './format/index'
29
+ export {
30
+ formatDate,
31
+ formatDateOnly,
32
+ formatTimeOnly,
33
+ formatRelativeTime,
34
+ parseDate,
35
+ isValidDate,
36
+ getDaysDiff,
37
+ getHoursDiff,
38
+ getMinutesDiff,
39
+ addDaysToDate,
40
+ subDaysFromDate,
41
+ addMonthsToDate,
42
+ subMonthsFromDate,
43
+ getStartOfDay,
44
+ getEndOfDay,
45
+ getStartOfWeek,
46
+ getEndOfWeek,
47
+ getStartOfMonth,
48
+ getEndOfMonth,
49
+ getStartOfYear,
50
+ getEndOfYear,
51
+ isBeforeDate,
52
+ isAfterDate,
53
+ isSameDayDate,
54
+ getTimestamp,
55
+ getTimestampInSeconds
56
+ } from './date/index'
57
+ export {
58
+ toUTC,
59
+ fromUTC,
60
+ formatUTC,
61
+ formatUTCDateOnly,
62
+ formatUTCTimeOnly,
63
+ toISOString,
64
+ getUTCNow,
65
+ getUTCTimestamp,
66
+ getUTCTimestampInSeconds,
67
+ getUTCStartOfDay,
68
+ getUTCEndOfDay,
69
+ getUTCStartOfMonth,
70
+ getUTCEndOfMonth,
71
+ addDaysUTC,
72
+ subDaysUTC,
73
+ addMonthsUTC,
74
+ subMonthsUTC,
75
+ getUTCDaysDiff,
76
+ getUTCHoursDiff,
77
+ getUTCMinutesDiff,
78
+ getTimezoneOffset,
79
+ getTimezoneOffsetHours,
80
+ getUTCYearStartTimestamp,
81
+ getUTCYearEndTimestamp,
82
+ getUTCYearStart,
83
+ getUTCYearEnd,
84
+ getUTCWeeksInYear,
85
+ getUTCWeekStart,
86
+ getUTCWeekEnd,
87
+ getUTCAllWeeksInYear,
88
+ getUTCWeekNumber
89
+ } from './date/utc/index'
90
+ export { Decimal } from './decimal/index'
91
+ export type { DecimalType } from './decimal/index'
92
+ export {
93
+ add,
94
+ subtract,
95
+ multiply,
96
+ divide,
97
+ equals,
98
+ greaterThan,
99
+ lessThan,
100
+ greaterThanOrEqual,
101
+ lessThanOrEqual,
102
+ round,
103
+ ceil,
104
+ floor,
105
+ abs,
106
+ negate
107
+ } from './decimal/utils/index'