Browse Source

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

zhongzewei 7 years ago
parent
commit
500e2c25a0

+ 5 - 3
config/gulpConfig.js

@@ -97,11 +97,13 @@ module.exports = {
         'web/building_saas/main/js/views/glj_view_contextMenu.js',
         'web/building_saas/main/js/views/calc_program_view.js',
         'web/building_saas/main/js/views/confirm_modal.js',
+        'public/web/rpt_tpl_def.js',
         'public/web/treeDataHelper.js',
         'public/web/ztree_common.js',
-        'public/web/rpt_tpl_def.js',
-        'web/building_saas/main/js/rpt/rpt_main.js',
-        'web/building_saas/main/js/rpt/rpt_cfg_const.js',
+        'web/building_saas/report/js/rpt_main.js',
+        'web/building_saas/report/js/rpt_cfg_const.js',
+        'web/building_saas/report/js/jpc_output_value_define.js',
+        'web/building_saas/report/js/jpc_output.js',
         'web/building_saas/main/js/views/character_content_view.js',
         'web/building_saas/main/js/views/glj_view.js',
         'web/building_saas/main/js/views/sub_view.js',

+ 1 - 1
modules/main/models/calc_program_model.js

@@ -14,7 +14,7 @@ let calcItemSchema = new Schema({
     compiledExpr: String,
     statement: String,
     feeRateID: Number,
-    feeRate: Number,
+    feeRate: String,
     labourCoeID: Number
 },{versionKey:false, _id: false});
 

+ 1 - 1
modules/main/models/labour_coe_model.js

@@ -8,7 +8,7 @@ let coeSchema = new Schema({
     ID: Number,
     ParentID: Number,
     name: String,
-    coe: Number,
+    coe: String,
     _id: false
 },{versionKey:false});
 

+ 2 - 2
modules/reports/rpt_component/jpc_ex.js

@@ -146,9 +146,9 @@ JpcExSrv.prototype.createNew = function(){
             } else {
                 //
             }
-            me.totalPages = me.flowTab.preSetupPages(rptTpl, dataObj, defProperties, dftPagingOption);
+            me.totalPages = me.flowTab.preSetupPages(rptTpl, dataObj, defProperties, dftPagingOption, me);
             if (me.flowTabEx) {
-                me.exTotalPages = me.flowTabEx.preSetupPages(rptTpl, dataObj, defProperties, dftPagingOption);
+                me.exTotalPages = me.flowTabEx.preSetupPages(rptTpl, dataObj, defProperties, dftPagingOption, me);
                 //console.log('ad-hoc flow pages: ' + me.exTotalPages);
             }
             me.totalPages += me.exTotalPages;

+ 154 - 16
modules/reports/rpt_component/jpc_flow_tab.js

@@ -11,14 +11,60 @@ let JpcCommonOutputHelper = require('./helper/jpc_helper_common_output');
 let JpcAreaHelper = require('./helper/jpc_helper_area');
 
 let JpcFlowTabSrv = function(){};
+//let grpPageInfo = {"segGrpRecStartIdx": 0, "insertedGrpRecAmt": 0, "preAddPageGrpInfo": null};
 JpcFlowTabSrv.prototype.createNew = function(){
-    function private_addPageValue(ValuedIdxLst, sortedSequence, preRec, nextRec,page_seg_map, segIdx, pageIdx) {
-        let vIdx = [];
-        for (let vi = 0; vi < nextRec; vi++) {
-            if (sortedSequence.length > preRec + vi) {
-                vIdx.push(sortedSequence[preRec + vi]);
+    function private_addPageValue(ValuedIdxLst, sortedSequence, grpSequenceInfo, startRecIdx, maxRecPerPage,page_seg_map, segIdx, pageIdx, grpPageInfo) {
+        let vIdx = [], preAmt = 0, insertedGrpAmt = 0, grp_lines = 0;
+        if (grpPageInfo) {
+            //grpPageInfo[JV.PROP_INSERTED_GRP_REC] = 0;
+            for (let grpLineIdx of grpPageInfo[JV.PROP_PRE_ADD_GRP_REC_INFO]) {
+                vIdx.push([JV.DISPLAY_VAL_TYPE_GROUP, grpPageInfo[JV.PROP_SEG_GRP_IDX], grpLineIdx]);
+            }
+            preAmt = grpPageInfo[JV.PROP_PRE_ADD_GRP_REC_INFO].length;
+            grpPageInfo[JV.PROP_PRE_ADD_GRP_REC_INFO] = [];
+            grp_lines = grpPageInfo[JV.PROP_GRP_LINES];
+        }
+        for (let vi = 0; (vi + insertedGrpAmt * grp_lines) < maxRecPerPage - preAmt; vi++) {
+            if (grpPageInfo) {
+                if ((startRecIdx + vi) === grpSequenceInfo[grpPageInfo[JV.PROP_SEG_GRP_IDX]]) {
+                    //表示这里要插入grouping信息啦!
+                    //1. 首先push正常的记录
+                    vIdx.push([JV.DISPLAY_VAL_TYPE_NORMAL, sortedSequence[startRecIdx + vi]]);
+                    //2. 然后就要push grouping记录了
+                    let hasFullGrp = true;
+                    for (let i = 0; i < grp_lines; i++) {
+                        if ( (vi + i + 1) >= (maxRecPerPage - preAmt)) {
+                            for (let j = i; j < grp_lines; j++) {
+                                grpPageInfo[JV.PROP_PRE_ADD_GRP_REC_INFO].push(j);
+                            }
+                            //准备要跳出去了
+                            hasFullGrp = false;
+                            break;
+                        } else {
+                            vIdx.push([JV.DISPLAY_VAL_TYPE_GROUP, grpPageInfo[JV.PROP_SEG_GRP_IDX], i]);
+                        }
+                    }
+                    //3. 进位下一个group信息所在位置
+                    if (hasFullGrp) {
+                        grpPageInfo[JV.PROP_INSERTED_GRP_REC]++;
+                        insertedGrpAmt++;
+                        grpPageInfo[JV.PROP_SEG_GRP_IDX]++;
+                    } else {
+                        break;
+                    }
+                } else {
+                    if (sortedSequence.length > startRecIdx + vi) {
+                        vIdx.push([JV.DISPLAY_VAL_TYPE_NORMAL, sortedSequence[startRecIdx + vi]]);
+                    } else {
+                        vIdx.push([JV.DISPLAY_VAL_TYPE_NORMAL, JV.BLANK_VALUE_INDEX]);
+                    }
+                }
             } else {
-                vIdx.push(JV.BLANK_VALUE_INDEX);
+                if (sortedSequence.length > startRecIdx + vi) {
+                    vIdx.push([JV.DISPLAY_VAL_TYPE_NORMAL, sortedSequence[startRecIdx + vi]]);
+                } else {
+                    vIdx.push([JV.DISPLAY_VAL_TYPE_NORMAL, JV.BLANK_VALUE_INDEX]);
+                }
             }
         }
         page_seg_map.push([pageIdx, segIdx]);
@@ -36,7 +82,13 @@ JpcFlowTabSrv.prototype.createNew = function(){
         me.seg_sum_fields_idx = [];
         me.seg_sum_tab_fields = [];
         me.page_sum_fields_idx = [];
-        me.group_fields_idx = [];
+
+        me.group_fields = [];
+        me.group_sum_fields = [];
+        me.group_sum_values = null;
+        me.group_node_info = null; //记录在哪个seg及到哪条记录后有group sum信息
+        me.group_lines_amt = 0;    //每group一次占用多少行,计算page信息会用到
+
         me.pageStatusLst = [];
         me.groupSumValLst = [];
         me.segSumValLst = [];
@@ -48,7 +100,8 @@ JpcFlowTabSrv.prototype.createNew = function(){
         let FLOW_NODE_STR = me.isEx?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;
         JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_SEG_SUM][JV.PROP_SUM_FIELDS], me.seg_sum_tab_fields, me.seg_sum_fields_idx, me.isEx);
         JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_PAGE_SUM][JV.PROP_SUM_FIELDS], null, me.page_sum_fields_idx, me.isEx);
-        JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_GROUP][JV.PROP_GROUP_FIELDS], null, me.group_fields_idx, me.isEx);
+        JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_GROUP][JV.PROP_GROUP_FIELDS], me.group_fields, null, me.isEx);
+        JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_GROUP][JV.PROP_SUM_FIELDS], me.group_sum_fields, null, me.isEx);
         for (let si = 0; si < dataSeq.length; si++) {
             me.segments.push(dataSeq[si].slice(0));
         }
@@ -74,8 +127,81 @@ JpcFlowTabSrv.prototype.createNew = function(){
 
         }
     };
-    JpcFlowTabResult.preSetupPages = function (rptTpl, dataOjb, defProperties, option) {
+    JpcFlowTabResult.sumUpGrp = function ($CURRENT_RPT, dataObj, segIdx, preGrpIdx, nexGrpIdx) {
+        let me = this, segDataIdx = me.segments[segIdx];
+        for (let j = 0; j < me.group_sum_fields.length; j++) {
+            let sum_field = JE.F(me.group_sum_fields[j][JV.PROP_FIELD_ID], $CURRENT_RPT);
+            if (sum_field) {
+                let data_field = null;
+                if (sum_field[JV.PROP_AD_HOC_DATA]) {
+                    data_field = sum_field[JV.PROP_AD_HOC_DATA]
+                } else {
+                    data_field = dataObj[sum_field.DataNodeName][sum_field.DataSeq];
+                }
+                let sumV = 0;
+                for (let si = preGrpIdx; si <= nexGrpIdx; si++) {
+                    sumV += JpcFieldHelper.getValue(data_field, segDataIdx[si]);
+                }
+                me.group_sum_values[segIdx][j].push(sumV);
+            }
+        }
+        me.group_node_info[segIdx].push(nexGrpIdx);
+    };
+    JpcFlowTabResult.setupGroupingData = function (rptTpl, dataObj, $CURRENT_RPT) {
+        let me = this;
+        if (me.group_fields.length > 0 && me.group_sum_fields.length > 0) {
+            me.group_sum_values = [];
+            me.group_node_info = [];
+            let CURRENT_FLOW_INFO = (me.isEx)?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;
+            me.group_lines_amt = rptTpl[CURRENT_FLOW_INFO][JV.NODE_FLOW_GROUP][JV.PROP_GROUP_LINES].length;
+            //
+            let preGrpIdx = 0, nexGrpIdx = 0;
+            for (let segIdx = 0; segIdx < me.segments.length; segIdx++) {
+                let segDataIdx = me.segments[segIdx];
+                me.group_sum_values.push([]);
+                me.group_node_info.push([]);
+                for (let j = 0; j < me.group_sum_fields.length; j++) {
+                    me.group_sum_values[segIdx].push([]);
+                    //me.group_node_info[segIdx].push([]);
+                }
+                for (let di = 1; di < segDataIdx.length; di++) {
+                    let hasDiff = false;
+                    for (let i = 0; i < me.group_fields.length; i++) {
+                        let grp_field = JE.F(me.group_fields[i][JV.PROP_FIELD_ID], $CURRENT_RPT);
+                        if (grp_field) {
+                            let data_field = null;
+                            if (grp_field[JV.PROP_AD_HOC_DATA]) {
+                                data_field = grp_field[JV.PROP_AD_HOC_DATA]
+                            } else {
+                                data_field = dataObj[grp_field.DataNodeName][grp_field.DataSeq];
+                            }
+                            let v1 = JpcFieldHelper.getValue(data_field, segDataIdx[di]), v2 = JpcFieldHelper.getValue(data_field, segDataIdx[di - 1]);
+                            if (v1 !== v2) {
+                                hasDiff = true;
+                                break;
+                            }
+                        }
+                    }
+                    if (hasDiff) {
+                        //then sum up the fields
+                        me.sumUpGrp($CURRENT_RPT, dataObj, segIdx, preGrpIdx, nexGrpIdx);
+                        nexGrpIdx = di;
+                        preGrpIdx = di;
+                        if (di === segDataIdx.length - 1) {
+                            me.sumUpGrp($CURRENT_RPT, dataObj, segIdx, preGrpIdx, nexGrpIdx);
+                        }
+                    } else if (di === segDataIdx.length - 1) {
+                        me.sumUpGrp($CURRENT_RPT, dataObj, segIdx, preGrpIdx, di);
+                    } else {
+                        nexGrpIdx = di;
+                    }
+                }
+            }
+        }
+    };
+    JpcFlowTabResult.preSetupPages = function (rptTpl, dataObj, defProperties, option, $CURRENT_RPT) {
         let me = this, rst = 1, counterRowRec = 0, maxRowRec = 1, pageIdx = 0;
+        me.setupGroupingData(rptTpl, dataObj, $CURRENT_RPT);
         me.paging_option = option||JV.PAGING_OPTION_NORMAL;
         let CURRENT_FLOW_INFO = (me.isEx)?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;
         JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[CURRENT_FLOW_INFO][JV.NODE_FLOW_CONTENT][JV.PROP_FLOW_FIELDS], null, me.disp_fields_idx, me.isEx);
@@ -91,7 +217,8 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 }
                 me.pageStatusLst.push(pageStatus.slice(0));
                 pageIdx++;
-                private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], 0, me.segments[segIdx].length, me.page_seg_map, segIdx, pageIdx);
+                let grpSeqInfo = (me.group_node_info)?me.group_node_info[segIdx]:null;
+                private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], grpSeqInfo, 0, me.segments[segIdx].length, me.page_seg_map, segIdx, pageIdx, null);
             }
         } else {
             let bands = JpcBand.createNew(rptTpl, defProperties);
@@ -106,10 +233,17 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 JpcBandHelper.setBandArea(bands, rptTpl, pageStatus, !me.isEx, me.isEx);
                 maxRowRec = JpcFlowTabHelper.getMaxRowsPerPage(bands, rptTpl, me.isEx);
             }
+            let grpPageInfo = {};
             for (let segIdx = 0; segIdx < me.segments.length; segIdx++) {
+                let grpSeqInfo = (me.group_node_info)?me.group_node_info[segIdx]:null;
+                grpPageInfo[JV.PROP_SEG_GRP_IDX] = 0;
+                grpPageInfo[JV.PROP_INSERTED_GRP_REC] = 0;
+                grpPageInfo[JV.PROP_PRE_ADD_GRP_REC_INFO] = [];
+                grpPageInfo[JV.PROP_GRP_LINES] = me.group_lines_amt;
                 private_resetBandArea();
                 let orgMaxRowRec = maxRowRec;
-                let rowSplitCnt = Math.ceil(1.0 * me.segments[segIdx].length / orgMaxRowRec);
+                let grpRecAmt = (grpSeqInfo)?(grpSeqInfo.length*me.group_lines_amt):0;
+                let rowSplitCnt = Math.ceil(1.0 * (me.segments[segIdx].length + grpRecAmt) / orgMaxRowRec);
                 pageStatus[JV.STATUS_SEGMENT_END] = true;
                 private_resetBandArea();
                 let hasAdHocRow = !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, me.segments, segIdx, (rowSplitCnt - 1) * orgMaxRowRec, maxRowRec, me.isEx);
@@ -117,14 +251,16 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 if (rowSplitCnt % me.multiCols > 0) {
                     rowSplitCnt++
                 }
-                for (let rowIdx = 0; rowIdx < rowSplitCnt; rowIdx++) {
-                    pageStatus[JV.STATUS_SEGMENT_END] = (rowIdx === (rowSplitCnt - 1));
+                for (let segPageIdx = 0; segPageIdx < rowSplitCnt; segPageIdx++) {
+                    pageStatus[JV.STATUS_SEGMENT_END] = (segPageIdx === (rowSplitCnt - 1));
                     if (pageIdx > 0) pageStatus[JV.STATUS_REPORT_START] = false;
                     private_resetBandArea();
                     me.pageStatusLst.push(pageStatus.slice(0));
                     pageIdx++;
-                    counterRowRec = orgMaxRowRec * rowIdx;
-                    private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], counterRowRec, maxRowRec,me.page_seg_map, segIdx, pageIdx);
+                    counterRowRec = orgMaxRowRec * segPageIdx - grpPageInfo[JV.PROP_INSERTED_GRP_REC];
+                    private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], grpSeqInfo, counterRowRec, maxRowRec,me.page_seg_map, segIdx, pageIdx, null);
+                    //private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], grpSeqInfo, counterRowRec, maxRowRec,me.page_seg_map, segIdx, pageIdx, grpPageInfo);
+                    //备注: 考虑到分组数据是临时融入的,所以需要知道这一页的数据融入了多少条group数据,并且得考虑边界条件情况(group数据可能跨页!)
                 }
                 pageStatus[JV.STATUS_SEGMENT_END] = false;
                 pageStatus[JV.STATUS_REPORT_START] = false;
@@ -225,7 +361,9 @@ JpcFlowTabSrv.prototype.createNew = function(){
                     }
                     if (!(tab_field[JV.PROP_HIDDEN])) {
                         for (let rowIdx = 0; rowIdx < contentValuesIdx.length; rowIdx++) {
-                            rst.push(me.outputTabField(band, tab_field, data_field, contentValuesIdx[rowIdx], -1, contentValuesIdx.length, rowIdx, 1, 0, unitFactor, true, controls, multiColIdx));
+                            // rst.push(me.outputTabField(band, tab_field, data_field, contentValuesIdx[rowIdx], -1, contentValuesIdx.length, rowIdx, 1, 0, unitFactor, true, controls, multiColIdx));
+                            //测试中
+                            rst.push(me.outputTabField(band, tab_field, data_field, contentValuesIdx[rowIdx][1], -1, contentValuesIdx.length, rowIdx, 1, 0, unitFactor, true, controls, multiColIdx));
                         }
                     }
                 }

+ 24 - 11
modules/reports/rpt_component/jpc_rte.js

@@ -65,18 +65,31 @@ let JE = {
     },
     getFieldValue: function (field, dataObj, valIdx, dftVal) {
         let rst = dftVal;
-        if (!field.DataNodeName) {
-            //that means this is a self-defined discrete field!
-            field.DataNodeName = JV.DATA_DISCRETE_DATA;
-            let len = dataObj[JV.DATA_DISCRETE_DATA];
-            field.DataSeq = len;
-            dataObj[JV.DATA_DISCRETE_DATA].push([]);
-        }
-        if (dataObj[field.DataNodeName][field.DataSeq].length > valIdx) {
-            rst = dataObj[field.DataNodeName][field.DataSeq][valIdx];
+        if (field.DataNodeName === "NA") {
+            if (!field[JV.PROP_AD_HOC_DATA]) {
+                field[JV.PROP_AD_HOC_DATA] = [];
+            }
+            if (field[JV.PROP_AD_HOC_DATA].length > valIdx) {
+                rst = field[JV.PROP_AD_HOC_DATA][valIdx];
+            } else {
+                if (dftVal === null && field[JV.PROP_AD_HOC_DATA].length > 0) {
+                    rst = field[JV.PROP_AD_HOC_DATA][field[JV.PROP_AD_HOC_DATA].length - 1];
+                }
+            }
         } else {
-            if (dftVal === null && dataObj[field.DataNodeName][field.DataSeq].length > 0) {
-                rst = dataObj[field.DataNodeName][field.DataSeq][dataObj[field.DataNodeName][field.DataSeq].length - 1];
+            if (!field.DataNodeName) {
+                //that means this is a self-defined discrete field!
+                field.DataNodeName = JV.DATA_DISCRETE_DATA;
+                let len = dataObj[JV.DATA_DISCRETE_DATA];
+                field.DataSeq = len;
+                dataObj[JV.DATA_DISCRETE_DATA].push([]);
+            }
+            if (dataObj[field.DataNodeName][field.DataSeq].length > valIdx) {
+                rst = dataObj[field.DataNodeName][field.DataSeq][valIdx];
+            } else {
+                if (dftVal === null && dataObj[field.DataNodeName][field.DataSeq].length > 0) {
+                    rst = dataObj[field.DataNodeName][field.DataSeq][dataObj[field.DataNodeName][field.DataSeq].length - 1];
+                }
             }
         }
         return rst;

+ 29 - 0
modules/reports/util/rpt_construct_data_util.js

@@ -53,6 +53,32 @@ class Rpt_Common{
         }
         return rst;
     };
+    MultiPlus(arrVal, fixFormat) {
+        let rst = [];
+        for (let i = 0; i < arrVal.length; i++) {
+            let valItem = arrVal[i];
+            if (i === 0) {
+                for (let dtl of valItem) {
+                    let value = parseFloat(dtl);
+                    if (fixFormat) value = value.toFixed(fixFormat);
+                    rst.push(value);
+                }
+            } else {
+                for (let j = 0; j < valItem.length; j++) {
+                    if (j < rst.length) {
+                        let value = rst[j] + valItem[j];
+                        if (fixFormat) value = value.toFixed(fixFormat);
+                        rst[j] = value;
+                    } else {
+                        let value = parseFloat(valItem[j]);
+                        if (fixFormat) value = value.toFixed(fixFormat);
+                        rst.push(value);
+                    }
+                }
+            }
+        }
+        return rst;
+    };
     Minus(val1, val2, fixFormat) {
         let rst = [], maxLen = val1.length, minLen = val2.length;
         if (minLen > maxLen) {
@@ -454,6 +480,9 @@ function ext_getFee(feeKey, dtlFeeKey) {
             }
         }
     }
+    for (let i = 0; i < rst.length; i++) {
+        rst[i] = parseFloat(rst[i]);
+    }
     return rst;
 }
 

+ 44 - 30
public/calc_util.js

@@ -5,9 +5,11 @@
  */
 
 // 需求说小数位数固定为2位,这里预留缓冲接口,防止以后需求变卦。
-const Digit_Calc_Program = -2;      // 这里指定计算程序用到的小数位数。
-function round(num) {
-    return scMathUtil.roundTo(num, Digit_Calc_Program);
+const Digit_Calc_Program = -2;              // 需求指定计算程序用到的小数位数。
+const Digit_Calc_Program_Default = -6;      // 需求末指定时默认用到的小数位数。
+function round(value, useDef = false) {
+    let digit = useDef ? Digit_Calc_Program_Default : Digit_Calc_Program;
+    return scMathUtil.roundTo(value, digit);
 };
 
 let executeObj = {
@@ -51,9 +53,11 @@ let executeObj = {
                                    price = md["base_price"];
                                    if (!price) price = 0;
                                    mdSum = mdSum +  round(md["consumption"] * price);
+                                   mdSum = round(mdSum, true);
                                }
                            };
-                           tmpSum = tmpSum + glj["quantity"] * mdSum;     // 这里不能四舍五入
+                           tmpSum = tmpSum + round(glj["quantity"] * mdSum, true);
+                           tmpSum = round(tmpSum, true);
                        }
                 };
             }else{
@@ -70,7 +74,7 @@ let executeObj = {
                             price = mprice - aprice;
                         };
                         if (!price) price = 0;
-                        tmpSum = tmpSum + glj["quantity"] * price;
+                        tmpSum = round(tmpSum + round(glj["quantity"] * price, true), true);
                     };
                 };
             };
@@ -227,9 +231,17 @@ class Calculation {
     // 先编译公用的基础数据
     compilePublics(feeRates, labourCoes, feeTypes, calcBases){
         let me = this;
+        me.compiledFeeRates = {};
+        me.compiledLabourCoes = {};
+        me.compiledTemplates = {};
+        me.compiledFeeTypes = {};
+        me.compiledFeeTypeNames = [];
+        me.compiledCalcBases = {};
+        me.saveForReports = [];
+        me.changed = false;
+
         let private_compile_feeRateFile = function() {
             if (feeRates) {
-                me.compiledFeeRates = {};
                 for (let rate of feeRates) {
                     me.compiledFeeRates["feeRate_" + rate.ID] = rate;
                 }
@@ -237,7 +249,6 @@ class Calculation {
         };
         let private_compile_labourCoeFile = function() {
             if (labourCoes) {
-                me.compiledLabourCoes = {};
                 for (let coe of labourCoes) {
                     me.compiledLabourCoes["LabourCoe_" + coe.ID] = coe;
                 }
@@ -245,8 +256,6 @@ class Calculation {
         };
         let private_compile_feeType = function() {
             if (feeTypes) {
-                me.compiledFeeTypes = {};
-                me.compiledFeeTypeNames = [];
                 for (let ft of feeTypes) {
                     me.compiledFeeTypes[ft.type] = ft.name;
                     me.compiledFeeTypes[ft.name] = ft.type;    // 中文预编译,可靠性有待验证
@@ -256,7 +265,6 @@ class Calculation {
         };
         let private_compile_calcBase = function() {
             if (calcBases) {
-                me.compiledCalcBases = {};
                 for (let cb of calcBases) {
                     me.compiledCalcBases[cb.dispName] = cb;         // 中文预编译,可靠性有待验证
                 }
@@ -267,8 +275,6 @@ class Calculation {
         private_compile_labourCoeFile();
         private_compile_feeType();
         private_compile_calcBase();
-        me.compiledTemplates = {};
-        me.saveForReports = [];
     };
 
     compileTemplate(template){
@@ -378,8 +384,6 @@ class Calculation {
         };
     };
 
-
-
     calculate($treeNode){
         let me = this;
         let templateID = $treeNode.data.programID;
@@ -396,6 +400,7 @@ class Calculation {
             if (!$treeNode.data.fees) {
                 $treeNode.data.fees = [];
                 $treeNode.data.feesIndex = {};
+                me.changed = true;
             };
 
             for (let idx of template.compiledSeq) {
@@ -411,23 +416,32 @@ class Calculation {
 
                 // 费用同步到定额
                 // 引入小麦的字段检测后,快速切换定额出现计算卡顿现象,过多的循环造成。这里把她的代码拆出来,减少微循环。
-                if (!$treeNode.data.feesIndex[calcItem.fieldName]){
-                    let fee = {
-                        'fieldName': calcItem.fieldName,
-                        'unitFee': calcItem.unitFee,
-                        'totalFee': calcItem.totalFee,
-                        'tenderUnitFee': 0,
-                        'tenderTotalFee': 0
-                    };
-                    $treeNode.data.fees.push(fee);
-                    $treeNode.data.feesIndex[calcItem.fieldName] = fee;
-                }
-                else{
-                    $treeNode.data.feesIndex[calcItem.fieldName].unitFee = calcItem.unitFee;
-                    $treeNode.data.feesIndex[calcItem.fieldName].totalFee = calcItem.totalFee;
-                }
-            }
+                if (calcItem.fieldName != '') {
+                    if (!$treeNode.data.feesIndex[calcItem.fieldName]){
+                        let fee = {
+                            'fieldName': calcItem.fieldName,
+                            'unitFee': calcItem.unitFee,
+                            'totalFee': calcItem.totalFee,
+                            'tenderUnitFee': 0,
+                            'tenderTotalFee': 0
+                        };
+                        $treeNode.data.fees.push(fee);
+                        $treeNode.data.feesIndex[calcItem.fieldName] = fee;
+                        me.changed = true;
+                    }
+                    else{
+                        if ($treeNode.data.feesIndex[calcItem.fieldName].unitFee != calcItem.unitFee){
+                            $treeNode.data.feesIndex[calcItem.fieldName].unitFee = calcItem.unitFee;
+                            me.changed = true;
+                        };
 
+                        if ($treeNode.data.feesIndex[calcItem.fieldName].totalFee != calcItem.totalFee){
+                            $treeNode.data.feesIndex[calcItem.fieldName].totalFee = calcItem.totalFee;
+                            me.changed = true;
+                        };
+                    }
+                };
+            };
         }
     }
 };

+ 12 - 1
public/web/rpt_value_define.js

@@ -100,7 +100,10 @@ const JV = {
     PROP_DISCRETE_FIELDS: "discrete_field_s",
     PROP_FLOW_FIELDS: "flow_field_s",
     PROP_BILL_FIELDS: "bill_field_s",
-    PROP_GROUP_FIELDS: "group_field_s",
+    PROP_GROUP_FIELDS: "group_field_s", //用来分组的指标(如按清单、定额etc...)
+    PROP_GROUP_LINES: "group_lines",    //显示分组行,因分组的特殊性,分组的数据当成流水数据一样(行高相同),group_lines里的每一条数据占用流水的一整行,里面再细分(指标/text)
+    PROP_GROUP_SUM_KEYS: "SumKey_S",
+    PROP_SUM_KEY: "SumKey",
     PROP_SUM_FIELDS: "sum_field_s",
     PROP_TEXTS: "text_s",
     PROP_TEXT: "text",
@@ -159,6 +162,11 @@ const JV = {
     BLANK_VALUE_INDEX: -100,
     BLANK_PAGE_VALUE_INDEX: -200,
 
+    PROP_SEG_GRP_IDX: "segGrpRecStartIdx",
+    PROP_PRE_ADD_GRP_REC_INFO: "preAddPageGrpInfo",
+    PROP_INSERTED_GRP_REC: "insertedGrpRecAmt",
+    PROP_GRP_LINES: "me.group_lines_amt",
+
     RUN_TYPE_BEFORE_PAGING: "before_paging",
     RUN_TYPE_BEFORE_OUTPUT: "before_output",
 
@@ -224,6 +232,9 @@ const JV = {
     PAGING_OPTION_NORMAL: 'normal',
     PAGING_OPTION_INFINITY: 'infinity',
 
+    DISPLAY_VAL_TYPE_NORMAL: 0,
+    DISPLAY_VAL_TYPE_GROUP: 1,
+
     PAGE_SELF_DEFINE: "自定义",
     PAGE_SPECIAL_MERGE_POS: "page_merge_pos",
 

+ 16 - 0
test/unit/reports/rpt_test_decimal.js

@@ -0,0 +1,16 @@
+/**
+ * Created by Tony on 2017/11/8.
+ */
+
+import mongoose from "mongoose";
+let Schema = mongoose.Schema;
+let MyDecimalSchema = new Schema({
+    "ID": Number,
+    "Value1" : Number,
+    "Value2": Number,
+    "Value3": Number
+});
+
+let Rpt_Decimal_Mdl = mongoose.model("rpt_decimal_test", MyDecimalSchema, "rpt_decimal_test");
+
+export {Rpt_Decimal_Mdl as default};

+ 55 - 15
test/unit/reports/test_tpl_09_1.js

@@ -118,21 +118,27 @@ test('测试 - 测试模板啦: ', function (t) {
         //正常应该根据报表模板定义的数据类型来请求数据
         rptTplDataFacade.prepareProjectData(userId_Dft, demoPrjId, filter, function (err, msg, rawDataObj) {
             if (!err) {
-                let tplData = rptDataUtil.assembleData(rawDataObj);
-                // fsUtil.wirteObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject.js");
-                //it's time to build the report!!!
-                let printCom = JpcEx.createNew();
-                rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = pagesize;
-                let defProperties = rpt_cfg;
-                let dftOption = JV.PAGING_OPTION_NORMAL;
-                printCom.initialize(rptTpl);
-                printCom.analyzeData(rptTpl, tplData, defProperties, dftOption);
-                let maxPages = printCom.totalPages;
-                let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
-                if (pageRst) {
-                    fsUtil.wirteObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult.js");
-                } else {
-                    console.log("oh! no pages were created!")
+                try {
+                    let tplData = rptDataUtil.assembleData(rawDataObj);
+                    // fsUtil.wirteObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject.js");
+                    //it's time to build the report!!!
+                    let printCom = JpcEx.createNew();
+                    rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = pagesize;
+                    let defProperties = rpt_cfg;
+                    let dftOption = JV.PAGING_OPTION_NORMAL;
+                    printCom.initialize(rptTpl);
+                    printCom.analyzeData(rptTpl, tplData, defProperties, dftOption);
+                    let maxPages = printCom.totalPages;
+                    let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
+                    if (pageRst) {
+                        //fsUtil.wirteObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult.js");
+                    } else {
+                        console.log("oh! no pages were created!")
+                    }
+                } catch (ex) {
+                    console.log(ex);
+                    t.pass('pass with exception!');
+                    t.end();
                 }
 
                 t.pass('pass succeeded!');
@@ -147,6 +153,40 @@ test('测试 - 测试模板啦: ', function (t) {
 });
 //*/
 
+/*/
+test('测试 - 保存小数位数问题: ', function (t) {
+    require('./rpt_test_decimal');
+    let rpt_decimal_mdl = mongoose.model("rpt_decimal_test");
+    let num = 300000;
+    let ID = 1;
+    for (let i = 0.0001; i < 1; (i+=0.0001)) {
+        let test_doc = {};
+        test_doc.ID = ID;
+        test_doc.Value1 = num + i;
+        test_doc.Value2 = num + i + 0.1 + 0.2;
+        test_doc.Value3 = parseFloat((num + i + 0.1 + 0.2).toFixed(5));
+        rpt_decimal_mdl.create(test_doc);
+        ID++;
+    }
+    t.pass('pass save decimal ok!');
+    t.end();
+});
+//*/
+/*/
+test('测试 - 显示保存小数位数问题: ', function (t) {
+    require('./rpt_test_decimal');
+    let rpt_decimal_mdl = mongoose.model("rpt_decimal_test");
+    rpt_decimal_mdl.find({}).then(function (rst) {
+        //console.log(rst);
+        if (rst.length > 0) {
+            fsUtil.wirteObjToFile(rst, "D:/GitHome/ConstructionCost/tmp/testDecimalResult.js");
+        }
+        t.pass('pass get decimal ok!');
+        t.end();
+    });
+});
+//*/
+
 test('close the connection', function (t) {
     setTimeout(function () {
         mongoose.disconnect();

+ 6 - 2
web/building_saas/main/js/calc/bills_calc.js

@@ -263,12 +263,13 @@ class BillsCalcHelper {
     };
     calcRationLeaf (node, fields, isIncre) {
         nodeCalcObj.node = node;
-        nodeCalcObj.digit = this.project.Decimal.unitFee;
+        nodeCalcObj.digit = this.project.Decimal.common.unitFee;
         calcFees.checkFields(node.data, fields);
         let nodeCalc = nodeCalcObj, virData= null, decimal = this.project.Decimal;
 
         // 清单单价:套用定额计算程序
-        if (this.project.calcFlag === billsPrice) {
+        // if (this.project.calcFlag === billsPrice) {
+        if (this.project.projSetting.billsCalcMode === billsPrice) {
             rationCalcObj.calcGljs = this.getBillsGLjs(node);
             console.log(rationCalcObj.calcGljs);
             rationCalcObj.calcFields = rationCalcFields;
@@ -352,6 +353,7 @@ class BillsCalcHelper {
         if (parent && parent.sourceType === this.project.Bills.getSourceType()) {
             calcFees.checkFields(parent.data, [field]);
             parent.data.feesIndex[field.type].totalFee = (parent.data.feesIndex[field.type].totalFee + Incre).toDecimal(this.project.Decimal.common.totalFee);
+            parent.data.feesIndex[field.type].unitFee = 0;   // AAAAA 临时补上,使存储 unitFee.toFixed(2) 时不出错
             this.updateParent(parent.parent, field, Incre);
         }
     };
@@ -359,9 +361,11 @@ class BillsCalcHelper {
         if (isIncre) {
             let incre = value - node.data.feesIndex[field.type].totalFee;
             node.data.feesIndex[field.type].totalFee = value;
+            node.data.feesIndex[field.type].unitFee = 0; // AAAAA 临时补上,使存储 unitFee.toFixed(2) 时不出错
             this.updateParent(node.parent, field, incre);
         } else {
             node.data.feesIndex[field.type].totalFee = value;
+            node.data.feesIndex[field.type].unitFee = 0; // AAAAA 临时补上,使存储 unitFee.toFixed(2) 时不出错
         }
     };
     converseCalc (node) {

+ 24 - 2
web/building_saas/main/js/models/calc_program.js

@@ -50,8 +50,30 @@ class CalcProgram {
     };
 
     calculate(treeNode){
-        treeNode.data.gljList = this.project.ration_glj.getGljArrByRation(treeNode.data.ID);
+        if (treeNode.sourceType === this.project.Ration.getSourceType()) {
+            treeNode.data.gljList = this.project.ration_glj.getGljArrByRation(treeNode.data.ID);
+        }
+        else if (treeNode.sourceType === this.project.Bills.getSourceType()) {
+             let rations = this.project.Ration.getBillsSortRation(treeNode.source.getID());
+            treeNode.data.gljList = this.project.ration_glj.getGatherGljArrByRations(rations);
+        };
+
         this.calc.calculate(treeNode);
-        projectObj.mainController.refreshTreeNode([treeNode]);
+
+        // 存储、刷新本结点、所有父结点
+        if (this.calc.changed){
+            let data = {ID: treeNode.data.ID, projectID: projectObj.project.ID(), fees: treeNode.data.fees};
+            let newDta = {'updateType': 'ut_update', 'updateData': data};
+            let newDataArr = [];
+            newDataArr.push(newDta);
+            projectObj.project.pushNow('', treeNode.sourceType, newDataArr);
+            projectObj.mainController.refreshTreeNode([treeNode]);
+
+            if (treeNode.parent) {
+                projectObj.converseCalculateBills(treeNode.parent);
+            }
+
+            this.calc.changed = false;
+        };
     }
 }

+ 8 - 5
web/building_saas/main/js/views/calc_program_view.js

@@ -228,16 +228,19 @@ let calcProgramObj = {
     showData: function (treeNode) {
         var me = this;
         me.treeNode = treeNode;
-        if (treeNode.sourceType === projectObj.project.Ration.getSourceType()) {
+
+        let isRation = treeNode.sourceType === projectObj.project.Ration.getSourceType();
+        let isBill = treeNode.sourceType === projectObj.project.Bills.getSourceType();
+        let isLeafBill = isBill && treeNode.source.children && treeNode.source.children.length === 0;
+        let isBillPriceCalc = projectObj.project.projSetting.billsCalcMode === billsPrice;
+
+        if (isRation || (isLeafBill && isBillPriceCalc)) {
             projectObj.project.calcProgram.calculate(treeNode);
-            if (treeNode.parent) {
-                projectObj.converseCalculateBills(treeNode.parent);
-            }
             me.datas = me.treeNode.data.calcTemplate.calcItems;
             sheetCommonObj.initSheet(me.sheet, me.setting, me.datas.length);
             sheetCommonObj.showData(me.sheet, me.setting, me.datas);
         }
-        else if (treeNode.sourceType === projectObj.project.Bills.getSourceType()) {
+        else if (isBill) {
             SheetDataHelper.loadSheetHeader(calcProgramSetting, me.sheet);
             SheetDataHelper.loadSheetData(calcProgramSetting, me.sheet, baseCalcField);
         }