目录
重置分支点编号(适应于有子级,中间可随意添加节点的分支结构)
ToTree树结构数据转换
// 将数据集合转换为树形结构
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相加处理精度问题
/** 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
/**
* 根据自增数生成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)
}