Explorar o código

Merge branch 'master' of http://smartcost.f3322.net:3000/SmartCost/ConstructionCost

zhongzewei %!s(int64=7) %!d(string=hai) anos
pai
achega
d3f1ff2a16

+ 2 - 1
config/gulpConfig.js

@@ -43,8 +43,9 @@ module.exports = {
         'lib/jquery-ui/jquery-ui-datepickerCN.js',
         'lib/jquery-contextmenu/*.js',
         'lib/lodash/lodash.js',
-        'test/tmp_data/test_ration_calc/ration_calc_base.js',
+        // 'test/tmp_data/test_ration_calc/ration_calc_base.js',
         'web/building_saas/main/js/models/main_consts.js',
+        'public/web/common_util.js',
         'web/building_saas/glj/js/project_glj.js',
         'web/building_saas/glj/js/composition.js',
         'web/building_saas/glj/js/common_spread.js',

+ 2 - 1
modules/reports/util/rpt_construct_data_util.js

@@ -259,7 +259,8 @@ function summaryData(sourceData, handleCfg, prjData){
         } else {
             for (let sumKey of handleCfg[JV.PROP_SUM_SUM_KEYS]) {
                 if (dtl[sumKey]) {
-                    sumObj[grpKey][sumKey] += dtl[sumKey];
+                    // sumObj[grpKey][sumKey] += dtl[sumKey];
+                    sumObj[grpKey][sumKey] = parseFloat(sumObj[grpKey][sumKey]) + parseFloat(dtl[sumKey]);
                 }
             }
         }

+ 11 - 13
modules/reports/util/rpt_pdf_util.js

@@ -184,7 +184,7 @@ function export_pdf_file (pageData, paperSize, fName, callback) {
         }
 
         function private_drawUnderline() {
-            //A. 暂不支持角度; B. 坐标已经translate
+            //A. 暂不支持角度; B. PDF输出时,坐标没有translate
             let ctx = doc;
             //1. 计算下划线的相关坐标
             let width = ctx.widthOfString(val);
@@ -192,22 +192,20 @@ function export_pdf_file (pageData, paperSize, fName, callback) {
             let startX = area[JV.IDX_LEFT], startY = area[JV.IDX_TOP], endX = area[JV.IDX_RIGHT], endY = area[JV.IDX_BOTTOM];
             // let startX = 0, startY = 0, endX = width, endY = startY;
             if (control.Horizon === "left") {
-                // 无变化;
+                startX = Math.round(area[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.IDX_LEFT]);
             } else if (control.Horizon === "right") {
-                startX = Math.round(startX - width);
+                startX = Math.round(area[JV.IDX_RIGHT] - width - JV.OUTPUT_OFFSET[JV.IDX_RIGHT]);
             } else {
-                startX = Math.round(startX - width / 2);
+                startX = Math.round( area[JV.IDX_LEFT] + (area[JV.IDX_RIGHT] - area[JV.IDX_LEFT] - width) / 2);
             }
             endX = Math.round(startX + width);
 
             if (control.Vertical === "top") {
-                startY += JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
+                startY = Math.round(area[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM] + height);
             } else if (control.Vertical === "bottom") {
-                // startY = Math.round(startY);
-                startY += JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
+                startY = Math.round(area[JV.IDX_BOTTOM] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM]);
             } else {
-                startY = Math.round(height / 2) - JV.OUTPUT_OFFSET[JV.IDX_TOP] - JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
-                // startY += JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
+                startY = Math.round( area[JV.IDX_TOP] + (area[JV.IDX_BOTTOM] - area[JV.IDX_TOP] + height) / 2) + JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
             }
             endY = Math.round(startY);
             //2. 画线
@@ -226,13 +224,13 @@ function export_pdf_file (pageData, paperSize, fName, callback) {
 
         let rotateOptions;
         if (font[JV.FONT_PROPS[5]] === 'T' && parseInt(font.FontAngle) === 0) {
-            // private_drawUnderline();
+            private_drawUnderline();
         }
         if (parseInt(font.FontAngle) !== 0) {
             if (control){
-                rotateOptions=private_setupAreaRotateOption(area,w,control.Vertical,dftFontHeight, output);
-            }else {
-                rotateOptions=private_setupAreaRotateOption(area,w,"bottom",dftFontHeight, output);
+                rotateOptions = private_setupAreaRotateOption(area,w,control.Vertical,dftFontHeight, output);
+            } else {
+                rotateOptions = private_setupAreaRotateOption(area,w,"bottom",dftFontHeight, output);
             }
             doc.rotate(font.FontAngle,rotateOptions);
         }

+ 0 - 12
public/calc_util.js

@@ -1,12 +0,0 @@
-/**
- * Created by Tony on 2017/6/21.
- * Modified by CSL, 2017-08-01 引入多套计算程序、费率同步、人工系数同步、改进基数计算、费字段映射等。
- * added by CSL, 2017-09-01 增加公式解析对象analyzer,用于解析用户修改公式、自定义表达式。
- */
-
-class Calculation {
-
-};
-
-/*
-export default analyzer;*/

+ 0 - 20
public/common_util.js

@@ -1,20 +0,0 @@
-/**
- * Created by CSL on 2017-06-06.
- * public functions.
- */
-
-function deleteEmptyObject(arr) {
-    function isEmptyObject(e) {
-        var t;
-        for (t in e)
-            return !1;
-        return !0
-    };
-
-    for (var i = 0; i < arr.length; i++) {
-        if (isEmptyObject(arr[i])) {
-            arr.splice(i, 1);
-            i = i - 1;
-        };
-    };
-};

+ 0 - 28
public/debug.js

@@ -1,28 +0,0 @@
-/**
- * Created by CSL on 2017-05-19.
- * 用于展示未知对象的内容。如:debug.m(GC.Spread.Sheets.Events);
- */
-
-debug = {
-    m: function (flag, obj) {
-        alert(flag + this.objStr(obj));
-    },
-
-    d: function (flag, obj) {
-        alert(flag + JSON.stringify(obj));
-    },
-
-    objStr: function (obj) {
-        var str = "";
-        var spr = "";
-        for (var x in obj) {
-            if (obj.hasOwnProperty(x)) {
-                if (str == '') {
-                    spr = ''
-                } else { spr = ', ' } ;
-                str += spr + x + ':' + obj[x];
-            }
-        }
-        return str;
-    }
-}

+ 15 - 0
public/web/common_util.js

@@ -0,0 +1,15 @@
+/**
+ * Created by CSL on 2017-06-06.
+ * public functions for web.
+ */
+
+// 忽略大小写判断字符串是否和参数指定的字符串相同
+String.prototype.sameText = function (str) {
+    return this.toLowerCase() == str.toLowerCase();
+};
+
+// 忽略大小写判断字符串是否有参数指定的子串
+String.prototype.hasSubStr = function (str) {
+    return this.toLowerCase().indexOf(str.toLowerCase()) > -1;
+};
+

+ 3 - 90
test/tmp_data/test_ration_calc/ration_calc_base.js

@@ -3,97 +3,10 @@
  */
 "use strict";
 
-const baseCalc = 0, adjustCalc = 1, budgetCalc = 2, diffCalc = 3,  offerCalc = 4;
-
-const gljType = {
-    // 人工
-    LABOUR: 1,
-    // ==============材料类型=================
-    // 普通材料
-    GENERAL_MATERIAL: 201,
-    // 混凝土
-    CONCRETE: 202,
-    // 砂浆
-    MORTAR: 203,
-    // 配合比
-    MIX_RATIO: 204,
-    // 商品混凝土
-    COMMERCIAL_CONCRETE: 205,
-    // 商品砂浆
-    COMMERCIAL_MORTAR: 206,
-    // ==============材料类型=================
-    // ==============机械类型=================
-    // 普通机械
-    GENERAL_MACHINE: 301,
-    // 机械组成物
-    MACHINE_COMPOSITION: 302,
-    // 机上人工
-    MACHINE_LABOUR: 303,
-    // ==============机械类型=================
-    // 主材
-    MAIN_MATERIAL: 4,
-    // 设备
-    EQUIPMENT: 5
-};
-
-let rationCalcBase = [
-    {
-        'dispName': '定额基价人工费',
-        'calcFun': 'base',
-        'calcType': baseCalc,
-        'gljTypes': [gljType.LABOUR]
-    },
-    {
-        'dispName': '定额基价材料费',
-        'calcFun': 'base',
-        'calcType': baseCalc,
-        'gljTypes': [gljType.GENERAL_MATERIAL, gljType.CONCRETE, gljType.MORTAR, gljType.MIX_RATIO, gljType.COMMERCIAL_CONCRETE, gljType.COMMERCIAL_MORTAR]
-    },
-    {
-        'dispName': '定额基价机械费',
-        'calcFun': 'base',
-        'calcType': baseCalc,
-        'gljTypes': [gljType.GENERAL_MACHINE]
-    },
-    {
-        'dispName': '定额基价机上人工费',
-        'calcFun': 'base',
-        'calcType': baseCalc,
-        'gljTypes': [gljType.MACHINE_LABOUR]
-    },
-    {
-        'dispName': '人工费价差',
-        'calcFun': 'diff',
-        'calcType': diffCalc,
-        'gljTypes': [gljType.LABOUR]
-    },
-    {
-        'dispName': '材料费价差',
-        'calcFun': 'diff',
-        'calcType': diffCalc,
-        'gljTypes': [gljType.GENERAL_MATERIAL, gljType.CONCRETE, gljType.MORTAR, gljType.MIX_RATIO, gljType.COMMERCIAL_CONCRETE, gljType.COMMERCIAL_MORTAR]
-    },
-    {
-        'dispName': '机械费价差',
-        'calcFun': 'diff',
-        'calcType': diffCalc,
-        'gljTypes': [gljType.GENERAL_MACHINE]
-    },
-    {
-        'dispName': '主材费',
-        'calcFun': 'budget',
-        'calcType': budgetCalc,
-        'gljTypes': [gljType.MAIN_MATERIAL]
-    },
-    {
-        'dispName': '设备费',
-        'calcFun': 'budget',
-        'calcType': budgetCalc,
-        'gljTypes': [gljType.EQUIPMENT]
-    }
-];
+// 这里的代码分别移到main_costs.js中和calc_program.js中,目的是相关内容集中放置,减少重复声明,减少单元引用。
 
 // 该方法暂时不用,已使用中文预编译的方式代替,但可靠性有待验证,若有问题再用回来。
+/*
 function getRationCalcBase(dispName){
     for (let base of rationCalcBase) {
        if (base.dispName == dispName) {
@@ -101,4 +14,4 @@ function getRationCalcBase(dispName){
        };
     }
     return null;
-};
+};*/

+ 3 - 3
web/building_saas/main/html/main.html

@@ -621,8 +621,10 @@
 
 
         <!-- inject:js -->
-        <script type="text/javascript" src="/test/tmp_data/test_ration_calc/ration_calc_base.js"></script>
+        <!--<script type="text/javascript" src="/test/tmp_data/test_ration_calc/ration_calc_base.js"></script>-->
         <script type="text/javascript" src="/web/building_saas/main/js/models/main_consts.js"></script>
+        <script type="text/javascript" src="/public/web/common_util.js"></script>
+
         <script type="text/javascript" src="/web/building_saas/glj/js/project_glj.js"></script>
         <script type="text/javascript" src="/web/building_saas/glj/js/composition.js"></script>
         <script type="text/javascript" src="/web/building_saas/glj/js/common_spread.js"></script>
@@ -729,8 +731,6 @@
             autoFlashHeight();
         </script>
 
-        <script src="/public/debug.js"></script>
-
         <SCRIPT type="text/javascript">
             <!--
 //            var zNodes =[

+ 1 - 1
web/building_saas/main/js/calc/bills_calc.js

@@ -2,7 +2,7 @@
  * Created by Mai on 2017/7/5.
  */
 
-const rationContent = 0, rationPrice = 1, rationPriceConverse = 2, billsPrice = 3;
+// const rationContent = 0, rationPrice = 1, rationPriceConverse = 2, billsPrice = 3;
 
 // sumTotalFeeFlag: sum(child.totalFee), totalFeeFlag: bills.quantity × bills.unitFee
 const sumTotalFeeFlag = 0, totalFeeFlag = 1;

+ 1 - 0
web/building_saas/main/js/calc/calc_fees.js

@@ -18,6 +18,7 @@ let feeType = [
     {type: 'material', name: '材料费'},
     {type: 'machine', name: '机械费'},
     {type: 'mainMaterial', name: '主材费'},
+    {type: 'equipment', name: '设备费'},
     {type: 'manage', name: '企业管理费'},
     {type: 'profit', name: '利润'},
     {type: 'risk', name: '风险费'},

+ 139 - 41
web/building_saas/main/js/models/calc_program.js

@@ -100,6 +100,56 @@ let defaultBillTemplate = {
     ]
 };
 
+const baseCalcType = {baseCalc: 0, adjustCalc: 1, budgetCalc: 2, diffCalc: 3,  offerCalc: 4};
+
+let rationCalcBase = [
+    {
+        'dispName': '定额基价人工费',
+        'calcType': baseCalcType.baseCalc,
+        'gljTypes': [gljType.LABOUR]
+    },
+    {
+        'dispName': '定额基价材料费',
+        'calcType': baseCalcType.baseCalc,
+        'gljTypes': [gljType.GENERAL_MATERIAL, gljType.CONCRETE, gljType.MORTAR, gljType.MIX_RATIO, gljType.COMMERCIAL_CONCRETE, gljType.COMMERCIAL_MORTAR]
+    },
+    {
+        'dispName': '定额基价机械费',
+        'calcType': baseCalcType.baseCalc,
+        'gljTypes': [gljType.GENERAL_MACHINE]
+    },
+    {
+        'dispName': '定额基价机上人工费',
+        'calcType': baseCalcType.baseCalc,
+        'gljTypes': [gljType.MACHINE_LABOUR]
+    },
+    {
+        'dispName': '人工费价差',
+        'calcType': baseCalcType.diffCalc,
+        'gljTypes': [gljType.LABOUR]
+    },
+    {
+        'dispName': '材料费价差',
+        'calcType': baseCalcType.diffCalc,
+        'gljTypes': [gljType.GENERAL_MATERIAL, gljType.CONCRETE, gljType.MORTAR, gljType.MIX_RATIO, gljType.COMMERCIAL_CONCRETE, gljType.COMMERCIAL_MORTAR]
+    },
+    {
+        'dispName': '机械费价差',
+        'calcType': baseCalcType.diffCalc,
+        'gljTypes': [gljType.GENERAL_MACHINE]
+    },
+    {
+        'dispName': '主材费',
+        'calcType': baseCalcType.budgetCalc,
+        'gljTypes': [gljType.MAIN_MATERIAL]
+    },
+    {
+        'dispName': '设备费',
+        'calcType': baseCalcType.budgetCalc,
+        'gljTypes': [gljType.EQUIPMENT]
+    }
+];
+
 let analyzer = {
     calcTemplate: null,
     success: true,
@@ -277,12 +327,12 @@ let executeObj = {
                             if (base.gljTypes.indexOf(md.glj_type) >= 0) {
                                 let q = md["consumption"] ? md["consumption"] : 0;
                                 let p = md["base_price"] ? md["base_price"] : 0;
-                                mdSum = mdSum + (q * p).toDecimal(me.digit);
-                                mdSum = (mdSum).toDecimal(me.digitDefault);
+                                mdSum = mdSum + (q * p).toDecimal(decimalObj.process);
+                                mdSum = (mdSum).toDecimal(decimalObj.process);
                             }
                         };
-                        result = result + (glj["quantity"] * mdSum).toDecimal(me.digitDefault);
-                        result = (result).toDecimal(me.digitDefault);
+                        result = result + (glj["quantity"] * mdSum).toDecimal(decimalObj.process);
+                        result = (result).toDecimal(decimalObj.process);
                     };
                 };
                 return result;
@@ -293,16 +343,16 @@ let executeObj = {
                 for (let glj of me.treeNode.data.gljList) {
                     let price = 0;
                     if (base.gljTypes.indexOf(glj.type) >= 0) {
-                        if (base.calcType == baseCalc){ price = parseFloat(glj["basePrice"]);}
-                        else if (base.calcType == adjustCalc){price = parseFloat(glj["adjustPrice"]);}
-                        else if (base.calcType == budgetCalc){price = parseFloat(glj["marketPrice"]);}
-                        else if (base.calcType == diffCalc){
+                        if (base.calcType == baseCalcType.baseCalc){ price = parseFloat(glj["basePrice"]);}
+                        else if (base.calcType == baseCalcType.adjustCalc){price = parseFloat(glj["adjustPrice"]);}
+                        else if (base.calcType == baseCalcType.budgetCalc){price = parseFloat(glj["marketPrice"]);}
+                        else if (base.calcType == baseCalcType.diffCalc){
                             let aprice = glj["adjustPrice"] ? glj["adjustPrice"] : 0;
                             let mprice = glj["marketPrice"] ? glj["marketPrice"] : 0;
-                            price = (parseFloat(mprice) - parseFloat(aprice)).toDecimal(me.digitDefault);
+                            price = (parseFloat(mprice) - parseFloat(aprice)).toDecimal(decimalObj.process);
                         };
-                        result = result + (glj["quantity"] * price).toDecimal(me.digitDefault);
-                        result = (result).toDecimal(me.digitDefault);
+                        result = result + (glj["quantity"] * price).toDecimal(decimalObj.process);
+                        result = (result).toDecimal(decimalObj.process);
                     };
                 };
                 return result;
@@ -316,7 +366,7 @@ let executeObj = {
                     ( me.treeNode.data.subType === gljType.GENERAL_MACHINE && base.dispName === '定额基价机械费') ||
                     ( me.treeNode.data.subType === gljType.MAIN_MATERIAL && base.dispName === '主材费') ||
                     ( me.treeNode.data.subType === gljType.EQUIPMENT && base.dispName === '设备费')
-                ) result = me.treeNode.data.marketUnitFee;
+                ) result = me.treeNode.data.marketUnitFee ? me.treeNode.data.marketUnitFee : 0;
 
                 return result;
             };
@@ -338,7 +388,7 @@ let executeObj = {
         let me = this;
         let p = me.treeNode.data.calcBase ? me.treeNode.data.calcBase : 0;
         let q = me.treeNode.data.quantity ? me.treeNode.data.quantity : 1;
-        let u = (p / q).toDecimal(me.digit);
+        let u = (p / q).toDecimal(decimalObj.decimal('unitPrice', me.treeNode));
         return u;
     }
 };
@@ -368,9 +418,6 @@ class CalcProgram {
     // 经测试,全部编译一次耗时0.003~0.004秒。耗时基本忽略不计。
     compileAllTemps(){
         let me = this;
-        me.digit = 2;
-        me.digitDefault = 6;
-
         me.compiledFeeRates = {};
         me.compiledLabourCoes = {};
         me.compiledTemplates = {};
@@ -541,6 +588,13 @@ class CalcProgram {
         };
     };
 
+    isLeafBill(treeNode){
+        let me = this;
+        return treeNode.sourceType === me.project.Bills.getSourceType() &&
+               treeNode.source.children &&
+               treeNode.source.children.length === 0;
+    };
+
     // 仅内部调用。注意:外部不能直接使用,因为这里传入的树节点必须有一定的初始化。
     InnerCalc(treeNode){
         let me = this;
@@ -582,32 +636,76 @@ class CalcProgram {
             };
         };
 
+        function isBaseFeeType(type){
+            return ['labour', 'material', 'machine', 'mainMaterial', 'equipment'].indexOf(type) > -1;
+        };
+
         // 汇总定额或子清单的费用类别
-        if (treeNode.calcType == treeNodeCalcType.ctGatherRations || treeNode.calcType == treeNodeCalcType.ctGatherBills){
+        if (treeNode.calcType == treeNodeCalcType.ctGatherRationsFees || treeNode.calcType == treeNodeCalcType.ctGatherBillsFees){
             treeNode.data.programID = null;
             initFees(treeNode);
 
-            let objsArr = (treeNode.calcType == treeNodeCalcType.ctGatherRations) ? project.Ration.getRationsByNode(treeNode) : treeNode.children;
+            let objsArr = (treeNode.calcType == treeNodeCalcType.ctGatherRationsFees) ? project.Ration.getRationsByNode(treeNode) : treeNode.children;
             let rst = [];
             for (let ft of feeType) {
                 let ftObj = {};
                 ftObj.fieldName = ft.type;
                 ftObj.name = ft.name;
-                let uf = 0, tf = 0, tuf = 0, ttf = 0;
-                for (let item of objsArr) {
-                    let data = (treeNode.calcType == treeNodeCalcType.ctGatherRations) ? item : item.data;
-                    if (data.feesIndex && data.feesIndex[ft.type]) {
-                        uf = (uf + parseFloat(data.feesIndex[ft.type].unitFee)).toDecimal(me.digitDefault);
-                        tf = (tf + parseFloat(data.feesIndex[ft.type].totalFee)).toDecimal(me.digitDefault);
-                        tuf = (tuf + parseFloat(data.feesIndex[ft.type].tenderUnitFee)).toDecimal(me.digitDefault);
-                        ttf = (ttf + parseFloat(data.feesIndex[ft.type].tenderTotalFee)).toDecimal(me.digitDefault);
+                let buf = 0, btf = 0, btuf = 0, bttf = 0;
+
+                if (treeNode.calcType == treeNodeCalcType.ctGatherBillsFees){
+                    for (let item of objsArr) {
+                        let data = item.data;
+                        if (data.feesIndex && data.feesIndex[ft.type]) {
+                            buf = (buf + parseFloat(data.feesIndex[ft.type].unitFee)).toDecimal(decimalObj.process);
+                            btf = (btf + parseFloat(data.feesIndex[ft.type].totalFee)).toDecimal(decimalObj.process);
+                            btuf = (btuf + parseFloat(data.feesIndex[ft.type].tenderUnitFee)).toDecimal(decimalObj.process);
+                            bttf = (bttf + parseFloat(data.feesIndex[ft.type].tenderTotalFee)).toDecimal(decimalObj.process);
+                        };
+                    };
+                }
+                else if (treeNode.calcType == treeNodeCalcType.ctGatherRationsFees){     // 这里的算法要配合冷姐姐的神图才能看懂^_^
+                    let sum_rtf = 0, sum_rttf = 0;
+                    let bq = parseFloat(treeNode.data.quantity ? treeNode.data.quantity : 1);
+
+                    for (let data of objsArr) {
+                        let rq = parseFloat(data.quantity ? data.quantity : 0);
+
+                        let ruf = 0, rtuf = 0, rtf = 0, rttf = 0;
+                        if (data.feesIndex && data.feesIndex[ft.type]) {
+                            ruf = parseFloat(data.feesIndex[ft.type].unitFee);
+                            rtuf = parseFloat(data.feesIndex[ft.type].tenderUnitFee);
+                            rtf = parseFloat(data.feesIndex[ft.type].totalFee);
+                            rttf = parseFloat(data.feesIndex[ft.type].tenderTotalFee);
+                        };
+
+                        if (me.project.projSetting.billsCalcMode === leafBillGetFeeType.rationContent) {
+                            buf = (buf + (ruf * rq / bq).toDecimal(decimalObj.process)).toDecimal(decimalObj.process);
+                            btuf = (btuf + (rtuf * rq / bq).toDecimal(decimalObj.process)).toDecimal(decimalObj.process);
+                        };
+
+                        sum_rtf = (sum_rtf + rtf).toDecimal(decimalObj.process);
+                        sum_rttf = (sum_rttf + rttf).toDecimal(decimalObj.process);
+                    };
+
+                    if (me.project.projSetting.billsCalcMode === leafBillGetFeeType.rationPrice || me.project.projSetting.billsCalcMode === leafBillGetFeeType.rationPriceConverse) {
+                        buf = (sum_rtf / bq).toDecimal(decimalObj.process);
+                        btuf = (sum_rttf / bq).toDecimal(decimalObj.process);
+                    };
+                    if (isBaseFeeType(ft.type) || (me.project.projSetting.billsCalcMode === leafBillGetFeeType.rationPriceConverse && ft.type == "common")){
+                        btf = sum_rtf;
+                        bttf = sum_rttf;
+                    }
+                    else{
+                        btf = (buf * bq).toDecimal(decimalObj.process);
+                        bttf = (btuf * bq).toDecimal(decimalObj.process);
                     };
                 };
-                ftObj.unitFee = uf.toDecimal(me.digit);
-                ftObj.totalFee = tf.toDecimal(me.digit);
-                ftObj.tenderUnitFee = tuf.toDecimal(me.digit);
-                ftObj.tenderTotalFee = ttf.toDecimal(me.digit);
 
+                ftObj.unitFee = buf.toDecimal(decimalObj.bills.unitPrice);
+                ftObj.totalFee = btf.toDecimal(decimalObj.bills.totalPrice);
+                ftObj.tenderUnitFee = btuf.toDecimal(decimalObj.bills.unitPrice);
+                ftObj.tenderTotalFee = bttf.toDecimal(decimalObj.bills.totalPrice);
                 checkFee(treeNode, ftObj);
 
                 rst.push(ftObj);
@@ -628,7 +726,7 @@ class CalcProgram {
                     delete treeNode.data.gljList;
                     let muf = treeNode.data.marketUnitFee ? treeNode.data.marketUnitFee : 0;
                     let q = treeNode.data.quantity ? treeNode.data.quantity : 0;
-                    treeNode.data.marketTotalFee = (muf * q).toDecimal(me.digit);
+                    treeNode.data.marketTotalFee = (muf * q).toDecimal(decimalObj.ration.totalPrice);
                 }
                 else if (treeNode.data.type == rationType.gljRation){
 
@@ -666,45 +764,44 @@ class CalcProgram {
 
                     let feeRate = calcItem.feeRate;
                     if (!feeRate) feeRate = 100;    // 100%
-                    calcItem.unitFee = (eval(calcItem.compiledExpr) * feeRate * 0.01).toDecimal(me.digit);   // 如果eval()对清单树有影响,就换成小麦的Expression对象再试
+                    calcItem.unitFee = (eval(calcItem.compiledExpr) * feeRate * 0.01).toDecimal(decimalObj.decimal('unitPrice', treeNode));   // 如果eval()对清单树有影响,就换成小麦的Expression对象再试
 
                     let quantity = treeNode.data.quantity;
                     if (!quantity) quantity = 0;
-                    calcItem.totalFee = (calcItem.unitFee * quantity).toDecimal(me.digit);
+                    calcItem.totalFee = (calcItem.unitFee * quantity).toDecimal(decimalObj.decimal('totalPrice', treeNode));
 
                     checkFee(treeNode, calcItem);
                 };
             }
         };
-    }
+    };
 
     // 计算本节点(默认同时递归计算所有父节点,可选)
     calculate(treeNode, calcParents = true){
         let me = this;
-
         let isRation = treeNode.sourceType === me.project.Ration.getSourceType();
         let isBill = treeNode.sourceType === me.project.Bills.getSourceType();
-        let isLeafBill = isBill && treeNode.source.children && treeNode.source.children.length === 0;   // 是清单且其下没有子清单
-        let isBillPriceCalc = me.project.projSetting.billsCalcMode === billsPrice;
+        let isBillPriceCalc = me.project.projSetting.billsCalcMode === leafBillGetFeeType.billsPrice;
+        let isLeafBill = me.isLeafBill(treeNode);
 
         if (isRation){
             treeNode.calcType = treeNodeCalcType.ctRationCalcProgram;
         }
         else if (isLeafBill) {
             if (treeNode.children && treeNode.children.length > 0){
-                me.calcLeafBillChildren(treeNode);
+                // me.calcLeafBillChildren(treeNode);
 
-                if (isBillPriceCalc)                        // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算
+                if (isBillPriceCalc)                        // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算。(汇总清单所有定额的工料机)
                     treeNode.calcType = treeNodeCalcType.ctBillCalcProgram;
                 else                                        // 前三种计算模式下的叶子清单:汇总定额的计算程序的费用类别
-                    treeNode.calcType = treeNodeCalcType.ctGatherRations;
+                    treeNode.calcType = treeNodeCalcType.ctGatherRationsFees;
             }
             else{                                          // 公式计算
                 treeNode.calcType = treeNodeCalcType.ctCalcBaseValue;
             };
         }
         else if (isBill)                                 // 父清单:汇总子清单的费用类别
-            treeNode.calcType = treeNodeCalcType.ctGatherBills;
+            treeNode.calcType = treeNodeCalcType.ctGatherBillsFees;
 
         me.InnerCalc(treeNode);
 
@@ -792,6 +889,7 @@ class CalcProgram {
     // 重新计算叶子清单下的所有子结点:如定额、工料机定额等(calculate算法基于定额、工料机定额的计算结果是正确的,实际上有时它们的计算结果并不是最新的)
     calcLeafBillChildren(treeNode){
         let me = this;
+        if(!me.isLeafBill(treeNode)) return;
         if (treeNode.children && treeNode.children.length > 0) {
             let needSaveNodes = [];
             for (let child of treeNode.children){

+ 43 - 4
web/building_saas/main/js/models/main_consts.js

@@ -17,6 +17,37 @@ const ModuleNames = {
     calc_program: 'calc_program'
 };
 
+const gljType = {
+    // 人工
+    LABOUR: 1,
+    // ==============材料类型=================
+    // 普通材料
+    GENERAL_MATERIAL: 201,
+    // 混凝土
+    CONCRETE: 202,
+    // 砂浆
+    MORTAR: 203,
+    // 配合比
+    MIX_RATIO: 204,
+    // 商品混凝土
+    COMMERCIAL_CONCRETE: 205,
+    // 商品砂浆
+    COMMERCIAL_MORTAR: 206,
+    // ==============材料类型=================
+    // ==============机械类型=================
+    // 普通机械
+    GENERAL_MACHINE: 301,
+    // 机械组成物
+    MACHINE_COMPOSITION: 302,
+    // 机上人工
+    MACHINE_LABOUR: 303,
+    // ==============机械类型=================
+    // 主材
+    MAIN_MATERIAL: 4,
+    // 设备
+    EQUIPMENT: 5
+};
+
 const feeRate_consts={
     decimal:3
 };
@@ -38,9 +69,9 @@ const CP_Col_Width = {          // 多处计算程序界面的列宽统一设置
 
 const treeNodeCalcType = {
     ctRationCalcProgram: 1,
-    ctBillCalcProgram: 2,
-    ctGatherRations: 3,
-    ctGatherBills: 4,
+    ctBillCalcProgram: 2,       // 汇总清单下所有定额的工料机
+    ctGatherRationsFees: 3,     // 汇总定额的各个费
+    ctGatherBillsFees: 4,       // 汇总清单的各个费
     ctCalcBaseValue: 5
 };
 
@@ -84,4 +115,12 @@ const rationType = {
     ration: 1,
     volumePrice: 2,
     gljRation: 3
-};
+};
+
+const leafBillGetFeeType = {
+    rationContent: 0,
+    rationPrice: 1,
+    rationPriceConverse: 2,
+    billsPrice: 3
+};
+

+ 38 - 18
web/building_saas/main/js/views/main_tree_col.js

@@ -37,7 +37,7 @@ let MainTreeCol = {
         calcProgramName: function (node) {
             if (
                 node.sourceType === projectObj.project.Ration.getSourceType() ||
-                (node.sourceType === projectObj.project.Bills.getSourceType() && node.source.children && node.source.children.length === 0 && projectObj.project.projSetting.billsCalcMode === billsPrice)
+                (projectObj.project.calcProgram.isLeafBill(node) && projectObj.project.projSetting.billsCalcMode === leafBillGetFeeType.billsPrice)
             ) return false
             else return true;
         },
@@ -100,7 +100,7 @@ let MainTreeCol = {
         calcProgramName: function (node) {
             if (
                 node.sourceType === projectObj.project.Ration.getSourceType() ||
-                (node.sourceType === projectObj.project.Bills.getSourceType() && node.source.children && node.source.children.length === 0 && projectObj.project.projSetting.billsCalcMode === billsPrice)
+                (projectObj.project.calcProgram.isLeafBill(node) && projectObj.project.projSetting.billsCalcMode === leafBillGetFeeType.billsPrice)
             ) {
                 var names = new GC.Spread.Sheets.CellTypes.ComboBox();
                 names.items(projectObj.project.calcProgram.compiledTemplateNames);
@@ -138,22 +138,42 @@ let MainTreeCol = {
             return event;
         }
     },
-    getNumberFormatter: function (digit) {
-        switch (digit) {
-            case 1:
-                return '0.#';
-            case 2:
-                return '0.##';
-            case 3:
-                return '0.###';
-            case 4:
-                return '0.####';
-            case 5:
-                return '0.#####';
-            case 6:
-                return '0.######';
-            default:
-                return '0.##';
+    getNumberFormatter: function (digit, align) {    // CSL, 2017-11-30 扩展:小数点是否对齐。
+        if (align) {
+            switch (digit) {
+                case 1:
+                    return '0.0';
+                case 2:
+                    return '0.00';
+                case 3:
+                    return '0.000';
+                case 4:
+                    return '0.0000';
+                case 5:
+                    return '0.00000';
+                case 6:
+                    return '0.000000';
+                default:
+                    return '0.00';
+            };
+        }
+        else{
+            switch (digit) {
+                case 1:
+                    return '0.#';
+                case 2:
+                    return '0.##';
+                case 3:
+                    return '0.###';
+                case 4:
+                    return '0.####';
+                case 5:
+                    return '0.#####';
+                case 6:
+                    return '0.######';
+                default:
+                    return '0.##';
+            };
         }
     }
 };

+ 3 - 0
web/building_saas/main/js/views/project_property_decimal_view.js

@@ -22,6 +22,9 @@ decimalObj.decimal = function (field, node) {
         if(field === 'feeRate'){
             return this[field];
         }
+        else if (field.sameText('unitFee')) field = 'unitPrice'
+        else if (field.sameText('totalFee')) field = 'totalPrice';
+
         if(isDef(node)){
             if(node.sourceType === projectObj.project.Bills.getSourceType()){
                 if(field === 'quantity'){

+ 14 - 6
web/building_saas/main/js/views/project_view.js

@@ -361,11 +361,11 @@ var projectObj = {
                 TREE_SHEET_HELPER.initSetting($('#billsSpread')[0], that.project.projSetting.mainGridSetting);
                 that.project.projSetting.mainGridSetting.cols.forEach(function (col) {
                     // for test.  后端没有绑定,暂时写死用于测试。
-                    if (col.data.field == '' && col.head.titleNames[0] == "取费专业") {
+/*                    if (col.data.field == '' && col.head.titleNames[0] == "取费专业") {
                         col.data.field = 'programID';
                         col.data.getText = 'getText.calcProgramName';
                         col.data.cellType = 'cellType.calcProgramName';
-                    };
+                    };*/
 
                     col.data.splitFields = col.data.field.split('.');
                     if (col.data.getText && Object.prototype.toString.apply(col.data.getText) === "[object String]") {
@@ -378,13 +378,21 @@ var projectObj = {
                         let getCellType = MainTreeCol.getEvent(col.data.cellType);
                         col.data.cellType = getCellType;
                     }
-                    if (col.data.digit && Object.prototype.toString.apply(col.data.digit) === "[object String]") {
-                        col.data.decimal = that.project.getDecimal(col.data.digit);
-                        col.data.formatter = MainTreeCol.getNumberFormatter(col.data.decimal);
-                    }
+                    // if (col.data.digit && Object.prototype.toString.apply(col.data.digit) === "[object String]") {
+                    //     col.data.decimal = that.project.getDecimal(col.data.digit);
+                    //     col.data.formatter = MainTreeCol.getNumberFormatter(col.data.decimal);
+                    // }
                     if (col.data.field === 'code') {
                         col.data.formatter = '@';
                     }
+
+                    // for test digit. CSLAAAAA
+                    if (col.data.field.hasSubStr("totalFee"))
+                       col.data.formatter = MainTreeCol.getNumberFormatter(decimalObj.ration.totalPrice, true)
+                    else if (col.data.field.hasSubStr("unitFee"))
+                        col.data.formatter = MainTreeCol.getNumberFormatter(decimalObj.ration.unitPrice, true)
+                    else if (col.data.field == "quantity")
+                        col.data.formatter = MainTreeCol.getNumberFormatter(decimalObj.ration.quantity, true);
                 });
 
                 that.mainController = TREE_SHEET_CONTROLLER.createNew(that.project.mainTree, that.mainSpread.getActiveSheet(), that.project.projSetting.mainGridSetting);