根据计算公式求值

 

 计算公式的函数:

    /**
     * @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"}
    ]
    */
 
 
原文地址:https://www.cnblogs.com/pengfei25/p/10300315.html