/** * 金额格式化工具模块 * 提供千分位分隔、输入清洗、展示格式化、数值解析等功能 */ /** 字符串分段拼接千分位,禁止使用前瞻正则 */ 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 }