import Big from 'big.js'; /** * 数字金额转中文大写(支持整数、小数) * @param num - 待转换的金额(支持数字或字符串格式) * @returns 中文大写金额字符串 */ export function convertToChineseCapital(num: number | string): string { // 中文数字映射 const digits: readonly string[] = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']; // 基本单位(个、拾、佰、仟) const units: readonly string[] = ['', '拾', '佰', '仟']; // 大单位(万、亿、万亿) const bigUnits: readonly string[] = ['', '万', '亿', '万亿']; // 1. 标准化输入:保留4位小数,分割整数与小数部分 const [intPartRaw, decPartRaw] = Number(num).toFixed(4).split('.'); // 去除整数前导零,若全零则保留一个 '0' const intPart: string = intPartRaw.replace(/^0+/, '') || '0'; let result: string = ''; // 2. 处理整数部分 if (intPart === '0') { result = '零元'; } else { // 从右向左,每4位分为一组(处理万、亿等大单位) const groups: string[] = []; let tempInt: string = intPart; while (tempInt.length > 0) { groups.unshift(tempInt.slice(-4)); tempInt = tempInt.slice(0, -4); } // 遍历每一组进行转换 groups.forEach((group: string, gIndex: number) => { let groupStr: string = ''; let needZero: boolean = false; // 标记是否需要补零 for (let i = 0; i < group.length; i++) { const digit: number = parseInt(group[i], 10); const unitPos: number = group.length - 1 - i; // 当前数字对应的单位位置 if (digit === 0) { needZero = true; } else { // 补零(如果前面有0) if (needZero) { groupStr += '零'; needZero = false; } groupStr += digits[digit] + units[unitPos]; } } // 拼接大单位(万、亿) if (groupStr) { result += groupStr + bigUnits[groups.length - 1 - gIndex]; } }); result += '元'; } // 3. 处理小数部分(仅保留角、分,忽略毫、厘) const jiao: number = parseInt(decPartRaw[0], 10); // 角(第1位小数) const fen: number = parseInt(decPartRaw[1], 10); // 分(第2位小数) if (jiao === 0 && fen === 0) { result += '整'; } else { // 处理“角” if (jiao > 0) { result += digits[jiao] + '角'; } else if (jiao === 0 && fen > 0) { result += '零'; } // 处理“分” if (fen > 0) { result += digits[fen] + '分'; } } return result; } /** * 标准化为Big实例,空/undefined/null转0 * @param num 数字 | 数字字符串 */ export function toBig(num: string | number | undefined | null): Big { if (num === null || num === undefined || num === '') return new Big(0); return new Big(num); } /** * 金额加法 * @param a 数值 * @param b 数值 * @returns 保留2位小数字符串 */ export function moneyAdd(a: number | string = 0, b: number | string = 0): string { return toBig(a).plus(b).toFixed(2); } // 数组高精度求和 export function sum(arr: Array): number { const total = arr.reduce((acc, cur) => acc.plus(toBig(cur)), new Big(0)); return Number(total); } // 取较大值 export function maxMoney(a: string | number, b: string | number): number { const bigA = toBig(a); const bigB = toBig(b); return Number(bigA.gt(bigB) ? bigA : bigB); } // 取较小值 export function minMoney(a: string | number, b: string | number): number { const bigA = toBig(a); const bigB = toBig(b); return Number(bigA.lt(bigB) ? bigA : bigB); } /** * 减法 a - b */ export function sub(a: string | number, b: string | number): number { return Number(toBig(a).minus(toBig(b))); } /** * 加法 a + b */ export function add(a: string | number, b: string | number): number { return Number(toBig(a).plus(toBig(b))); } /** * 乘法 a * b */ export function mul(a: string | number, b: string | number, decimal = 2): number { return Number(toBig(a).times(toBig(b)).round(decimal)); } /** * 除法 a / b * @throws 除数为0抛异常,业务try catch捕获 */ export function div(a: string | number, b: string | number): number { const bigB = toBig(b); if (bigB.eq(0)) throw new Error('除数不能为0'); return Number(toBig(a).div(bigB)); } /** * a > b */ export function gtMoney(a: string | number, b: string | number): boolean { return toBig(a).gt(toBig(b)); } /** * a >= b */ export function gteMoney(a: string | number, b: string | number): boolean { return toBig(a).gte(toBig(b)); } /** * a < b */ export function ltMoney(a: string | number, b: string | number): boolean { return toBig(a).lt(toBig(b)); } /** * a <= b */ export function lteMoney(a: string | number, b: string | number): boolean { return toBig(a).lte(toBig(b)); } /** * a === b 金额相等 */ export function eqMoney(a: string | number, b: string | number): boolean { return toBig(a).eq(toBig(b)); } /** * a !== b 金额不相等 */ export function neqMoney(a: string | number, b: string | number): boolean { return !toBig(a).eq(toBig(b)); } // 保留2位小数(金额专用) export function toFixed2(val) { return Number(val).toFixed(2); } // 判断 a 和 b 是否数值相等 export function eq(a: string | number, b: string | number): boolean { return toBig(a).eq(toBig(b)); } /** * 金额保留指定位小数(四舍五入,默认2位) * @param num 计算结果 * @param digit 保留位数 */ export function toFixedMoney(num: string | number, digit = 2): number { return Number(toBig(num).toFixed(digit, Big.roundHalfUp)); } /** * 智能金额格式化(带单位:元/万元/亿元) * 兼容:数字、字符串、null、undefined * @param {number|string} amount 金额 * @param {number} unitNumber 保留几个小数 默认 2位 * @returns {string} 格式化后带单位的金额 */ export function formatMoneyWithUnit(amount: number | string, unitNumber: number = 2): string { // 空值处理 if (amount == null || amount === '') return '0.00 元'; const num = Number(amount); if (isNaN(num)) return '0.00 元'; // 绝对值判断单位 const absNum = Math.abs(num); if (absNum >= 100000000) { // 亿元 return (num / 100000000).toFixed(unitNumber).replace(/\B(?=(\d{3})+(?!\d))/g, ',') + ' 亿元'; } else if (absNum >= 10000) { // 万元 return (num / 10000).toFixed(unitNumber).replace(/\B(?=(\d{3})+(?!\d))/g, ',') + ' 万元'; } else { // 元 return num.toFixed(unitNumber).replace(/\B(?=(\d{3})+(?!\d))/g, ',') + ' 元'; } } // 带货币符号(¥)版本 export function formatMoneyWithSymbol(amount) { return '¥' + formatMoneyWithUnit(amount); }