计算公式的函数:
/** * @desc 根据公式获取code * 1.code都需要加"[]"例如[a-1]+[b]+[c]就会返回["a-1",b,c]; * 2.不加[]会自行忽略 * @param {string} str 公式字符串 * @return {array} _arr code组成的数组 */ function formulaToCode(str){ var _arr=[]; if(!str){return _arr} _arr=str.match(/\[.+?\]/g).join('').replace(/\]/g,'').split(/\[/); _arr.shift(); return _arr; } /** * @desc 把请求到的单个code分散数据重新组合成按照公式的数据。 * @desc 这个方法对应的要求说明: * 1.没有计算公式的code不能含有[]字符 * 2.接口数据不能只有sname和data两个字段 * 3.code只能是字母或下划线(_)开头的字母、数字和下划线组成的字符串(即:符合javascript变量命名要求)后改成了没有限制(-)也行 * 4.不同设备不能使用相同的公式 * @param {Object} obj 用 “公式:设备对象”组成的对象。 * @param {Array} res 请求回来的数据数组对象,如:res.jsonList * @param {Array} other 根据请求回来的数据对象里面的键确定默认是【sname,data】,如果对象中还有其他的键需要加上,否则计算错误,因为是根据对象中每一个键都不同的时候来累加计算data的值 * @return {Array} resArr 数据数组对象 */ function evalFormulaToRes(obj,res,other){ other=other===undefined?['sname','data']:other; var resArr=[];//用于存放返回的数据对象 if(res.length==0){return resArr;}//没有数据 //1.解析res数组生成_tempO和_tempA for(var i=0,_tempO={},_tempA={};i<res.length;i++){ if(_tempO[res[i].sname]===undefined){ _tempO[res[i].sname]={}; _tempA[res[i].sname]=[]; } var keys=''; for(var k in res[i]){ if(other.indexOf(k)===-1){ keys+=''+res[i][k]; } } if(keys===''){keys='tempIndex'+i} _tempO[res[i].sname][keys]=res[i]; _tempA[res[i].sname].push(res[i]); } //2.外层循环每个公式 for(var k in obj){ if(k.split(/[\[\+\-\*\/]/g).length<3){//2.1.如果公式是单个code,不存在运算直接concat进resArr var key=k.replace(/\[|\]/g,''); if(_tempA[k]!==undefined){ resArr=resArr.concat(_tempA[k]); }else if(_tempA[key]!==undefined){ resArr=resArr.concat(_tempA[key]); } }else{//2.2.公式存在运算 //2.2.1.取出每个code var _arr=formulaToCode(k); //2.2.2.根据每个code找出数据对象,把找到的数据对象的所有属性tempResArr if(_arr.length>0){ for(var i=0,tempResArr={},len=0;i<_arr.length;i++){ if(_tempO[_arr[i]]!==undefined){ for(var n in _tempO[_arr[i]]){ tempResArr[n]=_tempO[_arr[i]][n]; } } } } //2.2.3.循环tempResArr找出里面,每个属性生成变量 for(var ks in tempResArr){ var to=JSON.parse(JSON.stringify(tempResArr[ks])) to.sname=k;to.data=formulaToData(_arr,_tempO,k,ks); if(isNaN(to.data)||to.data==Infinity||to.data==-Infinity){ console.error('错误:"'+k+'"数据除以0'); to.data=0; } resArr.push(to); } } } return resArr; } /** * @desc 将公式转换为数据 * @param {*} _arr * @param {*} _tempO * @param {*} k * @param {*} ks */ function formulaToData(_arr,_tempO,k,ks){ // var o={}; for(var i=0;i<_arr.length;i++){ var _str=''; var r= new RegExp('\\['+_arr[i]+'\\]',"g"); if(_tempO[_arr[i]]===undefined){//没有code // _str='var _'+_arr[i]+'_='+0; k=k.replace(r,0); }else{ var _to=_tempO[_arr[i]][ks];//有code没有某个属性 if(_to===undefined){ // _str='var _'+_arr[i]+'_='+0; k=k.replace(r,0); }else{ // _str='var _'+_arr[i]+'_='+_to.data; k=k.replace(r,_to.data); } } // eval(_str); } return eval('('+k+')')+''; }
特别说明:
other 根据请求回来的数据对象里面的键确定默认是【sname,data】,如果对象中还有其他的键需要加上,否则计算错误,因为是根据对象中每一个键都不同的时候来累加计算data的值
像这种就需再加上字段e,因为e有可能相同,如果相同,就会将data的值累加,导致计算的值的个数多与正确值
使用举例:
var obj={ "[a-r]*2+[b]+[c]":"" } var list=[ {sname:"a-r",time:'01',data:1,date:'2019-01-02'}, {sname:"b",time:'01',data:1,date:'2019-01-02'}, {sname:"c",time:'01',data:1,date:'2019-01-02'}, {sname:"a-r",time:'02',data:2,date:'2019-01-02'}, {sname:"b",time:'02',data:2,date:'2019-01-02'}, {sname:"c",time:'02',data:2,date:'2019-01-02'}, ] console.log(evalFormulaToRes(obj,list)); /* [ {sname: "[a-r]*2+[b]+[c]", time: "01", data: "4", date: "2019-01-02"}, {sname: "[a-r]*2+[b]+[c]", time: "02", data: "8", date: "2019-01-02"} ] */