目录
ToTree树结构数据转换
金额格式化
金额转中文
JS相加处理精度问题
根据自增数生成64进制id
重置分支点编号(适应于有子级,中间可随意添加节点的分支结构)
// 将数据集合转换为树形结构 function toTree({ arrayList, pidStr = 'parentId', idStr = 'id', childrenStr = 'children' }) { const listOjb = {}; // 用来储存{key: obj}格式的对象 const treeList = []; // 用来储存最终树形结构数据的数组 // 将数据变换成{key: obj}格式,方便下面处理数据 for (let i = 0; i < arrayList.length; i++) { listOjb[arrayList[i][idStr]] = arrayList[i]; } // 根据pid来将数据进行格式化 for (let j = 0; j < arrayList.length; j++) { // 判断父级是否存在 const haveParent = listOjb[arrayList[j][pidStr]]; if (haveParent) { // 如果有没有父级children字段,就创建一个children字段 !haveParent[childrenStr] && (haveParent[childrenStr] = []); // 在父级里插入子项 haveParent[childrenStr].push(arrayList[j]); } else { // 如果没有父级直接插入到最外层 treeList.push(arrayList[j]); } } return treeList; }
/* * 金额格式化: * number:要格式化的数字 * decimals:保留几位小数 * tdecPoint:小数点符号 * thousandsSep:千分位符号 * */ function numberFormat(number, decimals = 2, tdecPoint = '.', thousandsSep = ',') { number = (number + '').replace(/[^0-9+-Ee.]/g, ''); if (number.indexOf(',') > -1) { return number; } let n = !isFinite(+number) ? 0 : +number, prec = !isFinite(+decimals) ? 0 : Math.abs(decimals), sep = typeof thousandsSep === 'undefined' ? ',' : thousandsSep, dec = typeof tdecPoint === 'undefined' ? '.' : tdecPoint, s = '', toFixedFix = function(n, prec) { const k = Math.pow(10, prec); return '' + Math.ceil(n * k) / k; }; s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.'); const re = /(-?\d+)(\d{3})/; while (re.test(s[0])) { s[0] = s[0].replace(re, '$1' + sep + '$2'); } if ((s[1] || '').length < prec) { s[1] = s[1] || ''; s[1] += new Array(prec - s[1].length + 1).join('0'); } return s.join(dec); }
function getAmountChinese(val) { const amount = +val if (Number.isNaN(amount) || amount < 0) return '' const NUMBER = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'] const N_UNIT1 = ['', '拾', '佰', '仟'] const N_UNIT2 = ['', '万', '亿'] const D_UNIT = ['角', '分', '厘', '毫'] let [integer, decimal] = amount.toString().split('.') if (integer && integer.length > 12) return '金额过大无法计算' let res = '' // 整数部分 if (integer) { for (let i = 0, len = integer.length; i < len; i++) { const num = integer.charAt(i) const pos = len - i - 1 // 排除个位后 所处的索引位置 if (num === '0') { // 当前位 等于 0 且下一位也等于 0 则可跳过计算 if (i === len - 1) { if (integer.length === 1) res += '零' // 0.35 这种情况不可跳过计算 break } if (integer.charAt(i + 1) === '0') continue } res += NUMBER[num] if (parseInt(num)) res += N_UNIT1[(pos) % 4] if (pos % 4 === 0) res += N_UNIT2[Math.floor(pos / 4)] } } res += '圆' // 小数部分 if (parseInt(decimal)) { for (let i = 0; i < 4; i++) { const num = decimal.charAt(i) if (parseInt(num)) res += NUMBER[num] + D_UNIT[i] } } else { res += '整' } return res }
/** js数值计算,避免精度丢失,先扩大倍数,再缩小位数 * 示例:accAdd(1,2,3.01) */ function accAdd() { if (arguments.length === 0) return 0; const list = []; // 获取小数位最大精度 // for (const item of arguments) { // let tem = 0; // try { // if (tem) { // tem = item.toString().split('.')[1].length; // } // } catch (e) { // tem = 0; // } // list.push(tem); // } // 计算最大数度值,避免精度丢失,先扩大位数,再缩小 // const mPow = Math.pow(10, Math.max(...list)); const mPow = 100; // 默认2位小数 let total = 0; for (const item of arguments) { let tem = 0; if (item) { tem = parseFloat(item) ?? 0; // parseFloat处理,转化失败时给0 } total += tem * mPow; } // toFixed部分浏览器会用问题,toFixed它是一个四舍六入五成双的诡异的方法(也叫银行家算法),"四舍六入五成双"含义:对于位数很多的近似数,当有效位数确定后,其后面多余的数字应该舍去,只保留有效数字最末一位,这种修约(舍入)规则是“四舍六入五成双”,也即“4舍6入5凑偶”这里“四”是指≤4 时舍去,"六"是指≥6时进上,"五"指的是根据5后面的数字来定,当5后有数时,舍5入1;当5后无有效数字时,需要分两种情况来讲:①5前为奇数,舍5入1;②5前为偶数,舍5不进。(0是偶数) const res = (total / mPow).toFixed(2); // // 修复toFixed // const res = parseInt(total + 0.5, 10) / times; return res; }
/** * 根据自增数生成64进制id * @returns 64进制id字符串 */ function idGenerator() { let qutient = (new Date() - new Date('2021-12-05')) qutient += Math.ceil(Math.random() * 1000) // 防止重複 const chars = '0123456789ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz'; const charArr = chars.split("") const radix = chars.length; const res = [] do { let mod = qutient % radix; qutient = (qutient - mod) / radix; res.push(charArr[mod]) } while (qutient); return res.join('') }
/** 重置节点编号,因为中间可以添加、删除节点,导致节点的previd不准确 */ function reSetFlowNodeId(json) { function shiftNodeId(item, pid) { const id =idGenerator() // 此处调用随机不重复64进制id方法 item.nodeId = id item.prevId = pid if (item.childNode) { shiftNodeId(item.childNode, item.nodeId) } if (item.conditionNodes) { item.conditionNodes.forEach((element) => { shiftNodeId(element, item.nodeId) }) } return item } return shiftNodeId(json, 0) }