74 lines
2.5 KiB
TypeScript
74 lines
2.5 KiB
TypeScript
/**
|
|
* 金额格式化工具模块
|
|
* 提供千分位分隔、输入清洗、展示格式化、数值解析等功能
|
|
*/
|
|
|
|
/** 字符串分段拼接千分位,禁止使用前瞻正则 */
|
|
export function addThousandSeparators(intStr: string): string {
|
|
if (!intStr) return ''
|
|
const isNegative = intStr.startsWith('-')
|
|
const absStr = isNegative ? intStr.slice(1) : intStr
|
|
const parts: string[] = []
|
|
const len = absStr.length
|
|
for (let i = len; i > 0; i -= 3) {
|
|
const start = Math.max(0, i - 3)
|
|
parts.unshift(absStr.slice(start, i))
|
|
}
|
|
const result = parts.join(',')
|
|
return isNegative ? `-${result}` : result
|
|
}
|
|
|
|
/** 输入清洗:去逗号、仅保留数字与一个点、截断小数位 */
|
|
export function sanitizeMoneyInput(value: string, precision = 2): string {
|
|
if (!value) return ''
|
|
// 去逗号
|
|
let cleaned = value.replace(/,/g, '')
|
|
// 去非数字非点字符
|
|
cleaned = cleaned.replace(/[^0-9.]/g, '')
|
|
// 只保留第一个小数点
|
|
const dotIndex = cleaned.indexOf('.')
|
|
if (dotIndex !== -1) {
|
|
const intPart = cleaned.slice(0, dotIndex + 1)
|
|
const decPart = cleaned.slice(dotIndex + 1).replace(/\./g, '')
|
|
cleaned = intPart + decPart
|
|
}
|
|
// 截断小数到 precision 位
|
|
if (dotIndex !== -1) {
|
|
const dotIdx = cleaned.indexOf('.')
|
|
const intPart = cleaned.slice(0, dotIdx + 1)
|
|
let decPart = cleaned.slice(dotIdx + 1)
|
|
if (decPart.length > precision) {
|
|
decPart = decPart.slice(0, precision)
|
|
}
|
|
cleaned = intPart + decPart
|
|
}
|
|
return cleaned
|
|
}
|
|
|
|
/** 展示:整数部分千分位 + 最多 precision 位小数 */
|
|
export function formatMoneyDisplay(
|
|
value: string | number | null | undefined,
|
|
precision = 2
|
|
): string {
|
|
if (value === null || value === undefined || value === '') return '0.00'
|
|
const num = typeof value === 'string' ? parseFloat(value) : value
|
|
if (isNaN(num)) return '0.00'
|
|
const isNegative = num < 0
|
|
const absNum = Math.abs(num)
|
|
const fixed = absNum.toFixed(precision)
|
|
const [intStr, decStr] = fixed.split('.')
|
|
const formatted = addThousandSeparators(intStr)
|
|
const result = `${formatted}.${decStr}`
|
|
return isNegative ? `-${result}` : result
|
|
}
|
|
|
|
/** 提交:number | null;空串 / 仅 '.' → null */
|
|
export function parseMoneyToNumber(value: string, precision = 2): number | null {
|
|
const sanitized = sanitizeMoneyInput(value, precision)
|
|
if (!sanitized || sanitized === '.') return null
|
|
const num = Number(sanitized)
|
|
if (isNaN(num)) return null
|
|
const factor = Math.pow(10, precision)
|
|
return Math.round(num * factor) / factor
|
|
}
|