Bladeren bron

calculation demo

TonyKang 8 jaren geleden
bovenliggende
commit
e4706ac748
4 gewijzigde bestanden met toevoegingen van 591 en 3 verwijderingen
  1. 164 0
      public/calc_util.js
  2. 8 3
      public/web/calculation/calc_util.js
  3. 362 0
      test/calculation/testCalc.js
  4. 57 0
      test/demo/stringTest.js

+ 164 - 0
public/calc_util.js

@@ -0,0 +1,164 @@
+/**
+ * Created by Tony on 2017/6/21.
+ */
+let calcBaseCodeCollection = ["定额基价材料费", "定额基价机械费", "定额基价人工费"
+    , "定额基价人工费(调整后)", "定额基价材料费(调整后)", "定额基价机械费(调整后)"
+    , "市场价格人工费", "市场价格材料费", "市场价格机械费"
+    , "定额基价机上人工费", "主材费", "设备费"
+];
+
+let executeObj = {
+    currentTpl : null,
+    currentRationItem: null,
+    currentFeeRateFile: null,
+    at: function(code) {
+        let me = executeObj,
+            rst = 0;
+        rst = me.currentTpl.compileAssistantObj[code].execRst;
+        return rst;
+    },
+    base: function(calcBaseCode) {
+        let me = executeObj, rst = -1,
+            idx = 10 + calcBaseCodeCollection.indexOf(calcBaseCode);
+        if (idx >= 0) {
+            //
+        } else {
+            //
+        }
+        rst = idx; //暂时返回值,测试用
+        return rst;
+    },
+    fee: function(feeID) {
+        let me = executeObj, rst = -1;
+        //
+        //rst = parseInt(feeID); //暂时返回值,测试用
+        rst = 0.89;
+        return rst;
+    },
+    factor: function(factorCode) {
+        let me = executeObj;
+        //
+    }
+};
+
+class calculation {
+    init(calcTpl, calFee){
+        let me = this;
+        me.calcTpl = calcTpl;
+        me.calFee = calFee;
+        me.hasCompiled = false;
+    };
+
+    compile(){
+        let me = this;
+        me.hasCompiled = false;
+        me.errs = [];
+        let private_extract_code = function(str, idx){
+            let rst = '', lBracket = 0, rBracket = 0, firstIdx = idx, lastIdx = 0;
+            for (let i = idx; i < str.length; i++) {
+                if (str[i] === '(') {
+                    lBracket++;
+                    if (lBracket == 1) firstIdx = i + 1;
+                }
+                if (str[i] === ')') {
+                    rBracket++;
+                    if (lBracket == rBracket) {
+                        lastIdx = i - 1;
+                        if (lastIdx > firstIdx) {
+                            if (str[firstIdx] === "'") firstIdx++;
+                            if (str[lastIdx] !== "'") lastIdx++;
+                            if (lastIdx > firstIdx) {
+                                rst = str.slice(firstIdx, lastIdx);
+                            }
+                        }
+                        break;
+                    }
+                }
+            }
+            return rst;
+        };
+        let private_parse_ref = function(item, itemIdx){
+            let expr = item.expression.split('at(').join('@(');
+            item.expression = expr;
+            //console.log('expression: ' + expr);
+            let idx = expr.indexOf('@(', 0);
+            while (idx >= 0) {
+                let code = private_extract_code(expr, idx);
+                //console.log('提取code: ' + code);
+                if (code.length > 0) {
+                    let subItem = me.compileAssistantObj[code];
+                    if (subItem) {
+                        if (subItem.code !== item.code) {
+                            private_parse_ref(subItem, me.compileAssistantObj[code + "_idx"]);
+                        } else {
+                            me.errs.push("There exists the self refer code: " + code);
+                        }
+                    } else {
+                        me.errs.push("There exists the invalid code by which could not find the item: " + code);
+                        console.log('invalid code: ' + code);
+                    }
+                }
+                idx = expr.indexOf('@(', idx + code.length + 3);
+            }
+            if (me.calcTpl.compiledSeq.indexOf(itemIdx) < 0) {
+                //console.log('the code ready to push: ' + item.code);
+                me.calcTpl.compiledSeq.push(itemIdx);
+            }
+        };
+        let private_setup_seq = function(item, itemIdx){
+            if (me.calcTpl.compiledSeq.indexOf(itemIdx) < 0) {
+                private_parse_ref(item, itemIdx);
+            }
+        };
+        let private_compile_items = function() {
+            for (let idx of me.calcTpl.compiledSeq) {
+                let item = me.calcTpl.calcItems[idx];
+                item.compiledExpr = item.expression.split('@(').join('$CE.at(');
+                item.compiledExpr = item.compiledExpr.split('base(').join('$CE.base(');
+                item.compiledExpr = item.compiledExpr.split('fee(').join('$CE.fee(');
+                item.compiledExpr = item.compiledExpr.split('factor(').join('$CE.factor(');
+                //console.log(item.compiledExpr);
+            }
+        };
+        if (me.calcTpl && me.calcTpl.calcItems && me.calcTpl.calcItems.length > 0) {
+            me.calcTpl.compiledSeq = [];
+            me.compileAssistantObj = {};
+            //1. first round -> prepare
+            for (let i = 0; i < me.calcTpl.calcItems.length; i++) {
+                let item = me.calcTpl.calcItems[i];
+                me.compileAssistantObj[item.code] = item;
+                me.compileAssistantObj[item.code + "_idx"] = i;
+            }
+            //2. second round -> go!
+            for (let i = 0; i < me.calcTpl.calcItems.length; i++) {
+                private_setup_seq(me.calcTpl.calcItems[i], i);
+            }
+            if (me.errs.length == 0) {
+                private_compile_items();
+                if (me.errs.length == 0) me.hasCompiled = true;
+            } else {
+                console.log('errors: ' + me.errs.toString());
+            }
+        }
+        //console.log(me.compileAssistantObj);
+        //console.log(me.calcTpl.compiledSeq);
+    };
+    calculate( $RATION){
+        let me = this;
+        if ($RATION && me.hasCompiled) {
+            let $CE = executeObj;
+            $CE.currentRationItem = $RATION;
+            $CE.currentTpl = me;
+            for (let idx of me.calcTpl.compiledSeq) {
+                let item = me.calcTpl.calcItems[idx];
+                item.execRst = eval(item.compiledExpr);
+            }
+            for (let idx of me.calcTpl.compiledSeq) {
+                let item = me.calcTpl.calcItems[idx];
+                console.log('code: ' + item.code + ' | expression: ' + item.compiledExpr +  ' | result: ' + item.execRst);
+            }
+        }
+    }
+}
+
+module.exports = new calculation();

+ 8 - 3
public/web/calculation/calc_util.js

@@ -3,16 +3,21 @@
  */
 
 class calculation {
-    constructor(calcTpl) {
+    init(calcTpl, calFee){
         let me = this;
         me.calcTpl = calcTpl;
+        me.calFee = calFee;
         me.hasCompiled = false;
     };
+
     compile(){
         let me = this;
         me.hasCompiled = false;
-        if (me.calcTpl && me.calcTpl.length > 0) {
-            //
+        if (me.calcTpl && me.calcTpl.calcItems && me.calcTpl.calcItems.length > 0) {
+            me.calcTpl.compiledSeq = [];
         }
+    };
+    calculate(){
+        //
     }
 }

+ 362 - 0
test/calculation/testCalc.js

@@ -0,0 +1,362 @@
+/**
+ * Created by Tony on 2017/6/21.
+ */
+var test = require('tape');
+var calcUtil = require('../../public/calc_util');
+
+let dummyFee = [
+    {
+        "ID" : 1,
+        "ParentID" : null,
+        "name" : "企业管理费",
+        "rate" : null,
+        "memo" : null
+    },
+    {
+        "ID" : 2,
+        "ParentID" : 1,
+        "name" : "建筑工程",
+        "rate" : null,
+        "memo" : null
+    },
+    {
+        "ID" : 3,
+        "ParentID" : 2,
+        "name" : "一类工程",
+        "rate" : 16.03,
+        "memo" : null
+    },
+    {
+        "ID" : 4,
+        "ParentID" : 2,
+        "name" : "二类工程",
+        "rate" : 14.95,
+        "memo" : null
+    },
+    {
+        "ID" : 5,
+        "ParentID" : 2,
+        "name" : "三类工程",
+        "rate" : 12.47,
+        "memo" : null
+    },
+    {
+        "ID" : 6,
+        "ParentID" : 2,
+        "name" : "四类工程",
+        "rate" : 9.3,
+        "memo" : null
+    },
+    {
+        "ID" : 7,
+        "ParentID" : 1,
+        "name" : "市政工程",
+        "rate" : null,
+        "memo" : null
+    },
+    {
+        "ID" : 8,
+        "ParentID" : 7,
+        "name" : "一类工程",
+        "rate" : 16.33,
+        "memo" : null
+    },
+    {
+        "ID" : 9,
+        "ParentID" : 7,
+        "name" : "二类工程",
+        "rate" : 15,
+        "memo" : null
+    },
+    {
+        "ID" : 10,
+        "ParentID" : 7,
+        "name" : "三类工程",
+        "rate" : 12.5,
+        "memo" : null
+    },
+    {
+        "ID" : 11,
+        "ParentID" : 7,
+        "name" : "四类工程",
+        "rate" : 9.5,
+        "memo" : null
+    },
+    {
+        "ID" : 12,
+        "ParentID" : 1,
+        "name" : "机械土石方",
+        "rate" : 15.5,
+        "memo" : null
+    },
+    {
+        "ID" : 13,
+        "ParentID" : 1,
+        "name" : "仿古建筑工程",
+        "rate" : 12,
+        "memo" : null
+    },
+    {
+        "ID" : 14,
+        "ParentID" : 1,
+        "name" : "建筑修缮工程",
+        "rate" : 12.47,
+        "memo" : null
+    },
+    {
+        "ID" : 15,
+        "ParentID" : 1,
+        "name" : "炉窑砌筑工程",
+        "rate" : null,
+        "memo" : null
+    },
+    {
+        "ID" : 16,
+        "ParentID" : 15,
+        "name" : "一类工程",
+        "rate" : 14.25,
+        "memo" : null
+    },
+    {
+        "ID" : 17,
+        "ParentID" : 15,
+        "name" : "二类工程",
+        "rate" : 12.47,
+        "memo" : null
+    },
+    {
+        "ID" : 18,
+        "ParentID" : 15,
+        "name" : "三类工程",
+        "rate" : 10.8,
+        "memo" : null
+    },
+    {
+        "ID" : 19,
+        "ParentID" : 15,
+        "name" : "四类工程",
+        "rate" : null,
+        "memo" : null
+    },
+    {
+        "ID" : 20,
+        "ParentID" : null,
+        "name" : "规费",
+        "rate" : null,
+        "memo" : null
+    },
+    {
+        "ID" : 21,
+        "ParentID" : 20,
+        "name" : "建筑工程",
+        "rate" : 4.87,
+        "memo" : null
+    },
+    {
+        "ID" : 22,
+        "ParentID" : 20,
+        "name" : "市政工程",
+        "rate" : 3.61,
+        "memo" : null
+    },
+    {
+        "ID" : 23,
+        "ParentID" : 20,
+        "name" : "机械土石方",
+        "rate" : 2.15,
+        "memo" : null
+    },
+    {
+        "ID" : 24,
+        "ParentID" : 20,
+        "name" : "仿古建筑工程",
+        "rate" : 2.84,
+        "memo" : null
+    },
+    {
+        "ID" : 25,
+        "ParentID" : 20,
+        "name" : "建筑修缮工程",
+        "rate" : 2.84,
+        "memo" : null
+    },
+    {
+        "ID" : 26,
+        "ParentID" : 20,
+        "name" : "炉窑砌筑工程",
+        "rate" : 3.61,
+        "memo" : null
+    },
+    {
+        "ID" : 27,
+        "ParentID" : null,
+        "name" : "利润",
+        "rate" : null,
+        "memo" : null
+    },
+    {
+        "ID" : 28,
+        "ParentID" : 27,
+        "name" : "建筑工程",
+        "rate" : null,
+        "memo" : null
+    },
+    {
+        "ID" : 29,
+        "ParentID" : 28,
+        "name" : "一类工程",
+        "rate" : 8.73,
+        "memo" : null
+    },
+    {
+        "ID" : 30,
+        "ParentID" : 28,
+        "name" : "二类工程",
+        "rate" : 6.94,
+        "memo" : null
+    }
+]
+
+let dummyCalcTpl = {
+    calType: 3,
+    calTypeName: "测试用_重庆",
+    compiledSeq: [],
+    intermediateRst: [],
+    calcItems: [{
+        code: "1",
+        name: "基价直接工程费",
+        dispExpr: "1.1+1.2+1.3+1.4",
+        expression: "@('1.1') + @('1.2') + @('1.3') + @('1.4')",
+        compiledExpr: "",
+        statement: "基价人工费+基价材料费+基价机械费+未计价材料费"
+    },{
+        code: "1.1",
+        name: "基价人工费",
+        dispExpr: "1.1.1+1.1.2",
+        expression: "@('1.1.1') + @('1.1.2')",
+        compiledExpr: "",
+        statement: "定额基价人工费+定额人工单价(基价)调整"
+    },{
+        code: "1.1.1",
+        name: "定额基价人工费",
+        dispExpr: "定额基价人工费",
+        expression: "base('定额基价人工费')",
+        compiledExpr: "",
+        statement: "定额基价人工费"
+    },{
+        code: "1.1.2",
+        name: "定额人工单价(基价)调整",
+        dispExpr: "1.1.1*[1.89-1]",
+        expression: "@('1.1.1') * fee('1')",
+        compiledExpr: "",
+        statement: "定额基价人工费*[定额人工单价(基价)调整系数-1]"
+    },{
+        code: "1.2",
+        name: "基价材料费",
+        dispExpr: "定额基价材料费",
+        expression: "base('定额基价材料费')",
+        compiledExpr: "",
+        statement: "定额基价材料费"
+    },{
+        code: "1.3",
+        name: "基价机械费",
+        dispExpr: "1.3.1+1.3.2",
+        expression: "@('1.3.1') + @('1.3.2')",
+        compiledExpr: "",
+        statement: "定额基价机械费+定额机上人工单价(基价)调整"
+    },{
+        code: "1.3.1",
+        name: "定额基价机械费",
+        dispExpr: "定额基价机械费",
+        expression: "base('定额基价机械费')",
+        compiledExpr: "",
+        statement: "定额基价机械费"
+    },{
+        code: "1.3.1.1",
+        name: "其中:定额基价机上人工费",
+        dispExpr: "定额基价机上人工费",
+        expression: "base('定额基价机上人工费')",
+        compiledExpr: "",
+        statement: "定额基价机上人工费"
+    },{
+        code: "1.3.2",
+        name: "定额人工单价(基价)调整",
+        dispExpr: "1.3.1.1*[1.89-1]",
+        expression: "@('1.3.1.1') * fee('1')",
+        compiledExpr: "",
+        statement: "定额基价人工费*[定额人工单价(基价)调整系数-1]"
+    },{
+        code: "1.4",
+        name: "未计价材料费",
+        dispExpr: "主材费+设备费",
+        expression: "base('主材费') + base('设备费')",
+        compiledExpr: "",
+        statement: "主材费+设备费"
+    },{
+        code: "2",
+        name: "企业管理费",
+        dispExpr: "1.1.1",
+        expression: "@('1.1.1')",
+        compiledExpr: "",
+        statement: "定额基价人工费"
+    },{
+        code: "3",
+        name: "利润",
+        dispExpr: "1.1.1",
+        expression: "@('1.1.1')",
+        compiledExpr: "",
+        statement: "定额基价人工费"
+    },{
+        code: "4",
+        name: "风险因素",
+        dispExpr: "",
+        expression: "0",
+        compiledExpr: "",
+        statement: ""
+    },{
+        code: "5",
+        name: "人材机价差",
+        dispExpr: "5.1+5.2+5.3",
+        expression: "@('5.1') + @('5.2') + @('5.3')",
+        compiledExpr: "",
+        statement: "人工费价差+材料费价差+机械费价差"
+    },{
+        code: "5.1",
+        name: "人工费价差",
+        dispExpr: "信息价或市场价格-调整后的定额人工费(基价)",
+        expression: "base('市场价格人工费') - base('定额基价人工费(调整后)')",
+        compiledExpr: "",
+        statement: "市场价格人工费-调整后的定额人工费(基价)"
+    },{
+        code: "5.2",
+        name: "材料费价差",
+        dispExpr: "信息价或市场价格-定额基价材料费",
+        expression: "base('市场价格材料费') - base('定额基价材料费(调整后)')",
+        compiledExpr: "",
+        statement: "市场价格材料费-定额基价材料费"
+    },{
+        code: "5.3",
+        name: "机械费价差",
+        dispExpr: "信息价或市场价格-调整后的定额基价机械费(基价)",
+        expression: "base('市场价格机械费') - base('定额基价机械费(调整后)')",
+        compiledExpr: "",
+        statement: "市场价格机械费-调整后的定额基价机械费(基价)"
+    },{
+        code: "6",
+        name: "综合单价",
+        dispExpr: "1+2+3+4+5",
+        expression: "@('1') + @('2') + @('3') + @('4') + @('5')",
+        compiledExpr: "",
+        statement: "基价直接工程费+企业管理费+利润+风险因素+人材机价差"
+    }
+    ]
+};
+
+test('计算式测试', function(t){
+    calcUtil.init(dummyCalcTpl, dummyFee);
+    calcUtil.compile();
+    calcUtil.calculate({});
+    t.pass('just pass for calculation initialization!');
+    t.end();
+})
+

+ 57 - 0
test/demo/stringTest.js

@@ -0,0 +1,57 @@
+/**
+ * Created by Tony on 2017/6/21.
+ */
+/**
+ * Created by Tony on 2017/6/21.
+ */
+var test = require('tape');
+
+test('string test1', function(t){
+    let str = "at('1.1') + at('1.2') + at('1.3') + at('1.4')";
+    //let re = /at(/g;
+    //let re = new RegExp("at\(", "g");
+    //let str1 = str.replaceAll('re', '@(');
+    //let str1 = str.replace('at(', '@(');
+    var str1 = str.split('at1(').join('@(');
+    //t.equal(str1, "@('1.1') + @('1.2') + @('1.3') + @('1.4')");
+    t.equal(str1, "at('1.1') + at('1.2') + at('1.3') + at('1.4')");
+    t.end();
+})
+
+test('string test1', function(t){
+    var str="hello(world)";
+    var nstr = str.replace(/\([^\)]*\)/g,"");
+
+    t.equal(nstr , "hello");
+    t.end();
+})
+
+test('test extract', function(t){
+    let private_extract_code = function(str, idx){
+        let rst = '', lBracket = 0, rBracket = 0, firstIdx = idx, lastIdx = 0;
+        for (let i = idx; i < str.length; i++) {
+            if (str[i] === '(') {
+                lBracket++;
+                if (lBracket == 1) firstIdx = i + 1;
+            }
+            if (str[i] === ')') {
+                rBracket++;
+                if (lBracket == rBracket) {
+                    lastIdx = i - 1;
+                    if (lastIdx > firstIdx) {
+                        if (str[firstIdx] === "'") firstIdx++;
+                        if (str[lastIdx] !== "'") lastIdx++;
+                        if (lastIdx > firstIdx) {
+                            rst = str.slice(firstIdx, lastIdx);
+                        }
+                    }
+                    break;
+                }
+            }
+        }
+        return rst;
+    };
+    let code = private_extract_code("at('1.1') + at('1.2')", 10);
+    t.equal(code , "1.2");
+    t.end();
+})