import Big from 'big.js' import dayjs from 'dayjs' import { MONEY_BIGUNITS, MONEY_DECIMAL_SHOWNAME, MONEY_DIGITS, MONEY_INT_SHOWNAME, MONEY_NUMS, MONEY_POSTFIX } from './consts' import { isEmpty } from './validate' /** * 从末尾开始插入 * @param str 需要处理的字符串 * @param space 间隔 * @param insertStr 要插入的内容 * @returns */ function reverseInsert (str: string, space: number, insertStr: string) { if (space <= 0) return str const chars = str.split('') const len = chars.length - 1 return chars .reduceRight((collect, int, index) => { const resverIndex = len - index collect.push(int) if (index !== 0 && resverIndex !== 0 && ((resverIndex + 1) % space === 0)) collect.push(insertStr) return collect }, [] as string[]) .reverse() .join('') } /** * 格式化金额 * @param value 数字 * @param decimalLen 保留小数位数 * @param splitStr 间隔符 * @returns */ export function formatAmt (value?: string|number, decimalLen = 2, splitStr = ',') { if (splitStr === '.') throw new Error('splitStr not allowed to be smae as decimal point') if (isEmpty(value)) return '' const num = new Big(value).round(decimalLen).toFixed(decimalLen) let [integer = '', decimal = ''] = num.split('.') if (!isEmpty(splitStr)) { integer = reverseInsert(integer, 3, splitStr) } if (decimalLen === 0) return integer decimal = decimal.padEnd(decimalLen, '0') return `${integer}.${decimal}` } /** * 去格式化金额 * @param val 需要格式化金额的值 * @param splitStr 去除的分割符 * @returns 去格式化 */ export function unFormatAmt (val?: string|number, splitStr = ',') { return typeof val === 'number' ? String(val) : isEmpty(val) ? '0' : val.replace(new RegExp(splitStr, 'g'), '') } function getIntegerUnits (index: number, reset: number) { const units: string[] = [] const len = MONEY_BIGUNITS.length const last = MONEY_BIGUNITS[len - 1] while (index >= len) { units.push(last) index -= len } units.push(MONEY_BIGUNITS[index]) units.push(MONEY_DIGITS[reset]) return units } /** * 转大写金额 * @param val 需要转换的值 * @returns 大写金额 */ export function formatUpperAmt (val?: number|string) { if (isEmpty(val)) return '' let [integer, decimal] = unFormatAmt(val).split('.') const isAllZero = (str: string) => /^0+$/.test(str) const zeroStr = MONEY_NUMS[0] if (!isEmpty(integer)) { integer = isAllZero(integer) ? '' : integer .split('') .reverse() .reduce((collect, char, index) => { const rest = index % 4 const cIndex = (index - rest) / 4 if (rest === 0) collect[cIndex] = [] if (char === '0') { if (collect[cIndex].length > 0 && collect[cIndex][rest - 1] !== '0') { collect[cIndex].push(MONEY_NUMS[0]) } } else { collect[cIndex].push(...getIntegerUnits(cIndex, rest)) collect[cIndex].push(MONEY_NUMS[Number(char)]) } return collect }, [] as string[][]) .flat() .reverse() .join('') } if (!isEmpty(decimal)) { decimal = isAllZero(decimal) ? '' : decimal .padEnd(2, '0') .slice(0, 2) .split('') .map((char, index) => char === '0' ? '' : `${MONEY_NUMS[Number(char)]}${MONEY_DECIMAL_SHOWNAME[index]}`) .join('') } const isIntEmpty = isEmpty(integer) const inDecimalEmpty = isEmpty(decimal) if (isIntEmpty && inDecimalEmpty) return `${zeroStr}${MONEY_INT_SHOWNAME}${MONEY_POSTFIX}` if (!isIntEmpty) { integer += MONEY_INT_SHOWNAME } if (inDecimalEmpty) { integer += MONEY_POSTFIX } return `${integer ?? ''}${decimal ?? ''}` .replace(new RegExp(`(${zeroStr})+`, 'g'), zeroStr) .replace(new RegExp(`(^${zeroStr}|${zeroStr}$)`, 'g'), '') } /** * 格式化时间 * @param date 时间 * @param pattern 格式化规则 默认 “YYYY-MM-DD” */ export function formatDate (date?: dayjs.ConfigType, pattern = 'YYYY-MM-DD') { return dayjs(date).format(pattern) } /** * 将输入串转化为全角字符 * @param str 需要转换的字符串 * @returns 转换后的全角字符 */ export function formatDBC (str: string) { return str.split('') .reduce((tmp, cur) => { const charCode = cur.charCodeAt(0) if (charCode === 32) { tmp = tmp + String.fromCharCode(12288) } if (charCode < 127) { tmp = tmp + String.fromCharCode(charCode + 65248) } return tmp }, '') } /** * 格式化账号 * @param accNo 需要格式化的账号 * @returns */ export function formatAccount (accNo?: number|string) { const str = String(accNo ?? '').replace(/^\s|\s$/g, '') return reverseInsert(str, 4, ' ') }