Procházet zdrojové kódy

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

zhongzewei před 7 roky
rodič
revize
9226002c0d
42 změnil soubory, kde provedl 1107 přidání a 611 odebrání
  1. 1 0
      modules/all_models/calc_program_model.js
  2. 19 2
      modules/glj/controllers/glj_controller.js
  3. 49 6
      modules/glj/models/unit_price_model.js
  4. 1 0
      modules/glj/routes/glj_router.js
  5. 1 1
      modules/main/facade/bill_facade.js
  6. 2 0
      modules/pm/models/project_property_template.js
  7. 2 2
      modules/reports/rpt_component/jpc_band.js
  8. 1 2
      modules/reports/rpt_component/jpc_field.js
  9. 74 79
      modules/reports/rpt_component/jpc_flow_tab.js
  10. 0 1
      modules/reports/rpt_component/jpc_function.js
  11. 1 2
      modules/reports/rpt_component/jpc_param.js
  12. 3 5
      modules/reports/rpt_component/jpc_rte.js
  13. 1 1
      public/web/sheet/sheet_common.js
  14. 8 0
      public/web/tree_sheet/tree_sheet_helper.js
  15. 204 197
      test/calculation/test_analyzer.js
  16. 5 4
      test/unit/reports/test_cover_01.js
  17. 5 4
      test/unit/reports/test_cover_02.js
  18. 10 8
      test/unit/reports/test_get_prj_data.js
  19. 3 2
      test/unit/reports/test_tpl_09.js
  20. 5 3
      test/unit/reports/test_tpl_09_1.js
  21. 1 1
      web/building_saas/css/main.css
  22. 21 13
      web/building_saas/fee_rates/fee_rate.html
  23. 13 8
      web/building_saas/js/global.js
  24. 14 2
      web/building_saas/main/html/main.html
  25. 17 7
      web/building_saas/main/js/main.js
  26. 135 83
      web/building_saas/main/js/models/calc_program.js
  27. 40 27
      web/building_saas/main/js/models/fee_rate.js
  28. 17 8
      web/building_saas/main/js/models/installation_fee.js
  29. 0 1
      web/building_saas/main/js/models/project.js
  30. 65 3
      web/building_saas/main/js/models/project_glj.js
  31. 6 2
      web/building_saas/main/js/models/ration.js
  32. 50 9
      web/building_saas/main/js/views/calc_base_view.js
  33. 23 7
      web/building_saas/main/js/views/calc_program_manage.js
  34. 128 50
      web/building_saas/main/js/views/fee_rate_view.js
  35. 1 20
      web/building_saas/main/js/views/glj_view.js
  36. 5 6
      web/building_saas/main/js/views/installation_fee_view.js
  37. 10 0
      web/building_saas/main/js/views/main_tree_col.js
  38. 52 15
      web/building_saas/main/js/views/project_glj_view.js
  39. 9 4
      web/building_saas/main/js/views/project_property_display_view.js
  40. 19 25
      web/building_saas/main/js/views/project_view.js
  41. 12 0
      web/building_saas/main/js/views/std_ration_lib.js
  42. 74 1
      web/building_saas/main/js/views/sub_fee_rate_views.js

+ 1 - 0
modules/all_models/calc_program_model.js

@@ -10,6 +10,7 @@ let calcItemSchema = new Schema({
     name: String,
     fieldName: String,
     dispExpr: String,
+    dispExprUser: String,
     expression: String,
     compiledExpr: String,
     statement: String,

+ 19 - 2
modules/glj/controllers/glj_controller.js

@@ -538,7 +538,7 @@ class GLJController extends BaseController {
         response.end('success');
     }
 
-    async  updateUnitPrice(req, res){
+    async updateUnitPrice(req, res){
         let result={
             error:0
         }
@@ -556,7 +556,24 @@ class GLJController extends BaseController {
         }
         res.json(result);
     }
-
+    async batchUpdatePrices(req, res){
+        let result={
+            error:0
+        }
+        try {
+            let data = req.body.data;
+            data = JSON.parse(data);
+            let unitPriceModel = new UnitPriceModel();
+            // 更新数据
+            let datas = await unitPriceModel.batchUpdatePrices(data);
+            result.data=datas;
+        }catch (err){
+            logger.err(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        res.json(result);
+    }
     async modifyKeyValue(req,res){//修改工料机关键的属性:名称、类型、规格、型号等
         let result={
             error:0

+ 49 - 6
modules/glj/models/unit_price_model.js

@@ -250,12 +250,18 @@ class UnitPriceModel extends BaseModel {
 
     async updateUnitPrice(data){
         //查找并更新单价
-        let doc={};
+        let doc={},newValueMap={};
         doc[data.field]=data.newval;
+        newValueMap[data.id]=doc;
         let unitPrice = await this.db.findAndModify({id:data.id},doc);
         if(!unitPrice){
             throw "没有找到对应的单价";
         }
+        let rList= this.checkAndUpdateParent(unitPrice,data.field,data.project_id,newValueMap);
+        return rList;
+    }
+
+    async checkAndUpdateParent(unitPrice,field,project_id,newValueMap,batchUpdate=false){//检查是否属于某个工料机的组成物,如果是,并且不是批量更新的情况下,直接更新,如果是批量更新,返回更新任务
         //查找是否是属于某个项目工料机的组成物
         let mixRatioModel = new MixRatioModel();
         let condition = {unit_price_file_id:unitPrice.unit_price_file_id, code:unitPrice.code,name: unitPrice.name, specs: unitPrice.specs,unit:unitPrice.unit,type:unitPrice.type};
@@ -266,15 +272,34 @@ class UnitPriceModel extends BaseModel {
         if(mixRatioList&&mixRatioList.length>0){
             for(let m of mixRatioList){
                 if(!connectKeyMap.hasOwnProperty(m.connect_key)){//为了去重复,组成物会与其它项目同步,所以有可能重复。
-                    rList.push(await this.updateParentUnitPrice(m,data.field,data.project_id));
+                    rList.push(await this.updateParentUnitPrice(m,field,project_id,newValueMap,batchUpdate));
                     connectKeyMap[m.connect_key]=true;
                 }
             }
         }
         return rList;
     }
+    async batchUpdatePrices(data){//批量更新
+        let tasks = [];
+        let parentTask = [];
+        let newValueMap = {};
+        for(let d of data){//第一次循环生成更新提交的记录,并生成一个新值的映射表,为更新父节点使用
+            let condition = {id:d.unit_price.id};
+            let doc = {};
+            doc[d.field]=d.newval;
+            newValueMap[d.unit_price.id] = doc;
+            tasks.push(this.generateUpdateTask(condition,doc));
+        }
+        for(let d of data){//第二次更新父节点
+           let rList = await this.checkAndUpdateParent(d.unit_price,d.field,d.project_id,newValueMap,true);
+           parentTask = parentTask.concat(rList);
+        }
+        tasks = tasks.concat(parentTask);
+        tasks.length>0?this.model.bulkWrite(tasks):'';
+        return parentTask;
+    }
 
-    async updateParentUnitPrice(mixRatio,fieid,project_id){
+    async updateParentUnitPrice(mixRatio,fieid,project_id,newValueMap,batchUpdate){//batchUpdate 批量更新标记,如果true,只生成task
         let  decimalObject =await decimal_facade.getProjectDecimal(project_id);
         let quantity_decimal = (decimalObject&&decimalObject.glj&&decimalObject.glj.quantity)?decimalObject.glj.quantity:3;
         let price_decimal = (decimalObject&&decimalObject.glj&&decimalObject.glj.unitPrice)?decimalObject.glj.unitPrice:2;
@@ -301,6 +326,9 @@ class UnitPriceModel extends BaseModel {
         for(let pk in priceMap){
             let price = scMathUtil.roundForObj(priceMap[pk][fieid],price_decimal);
             let consumption = scMathUtil.roundForObj(mixRatioMap[pk].consumption,quantity_decimal);
+            if(newValueMap[priceMap[pk].id]){//是需要更新的记录,取当前新的值
+                price = scMathUtil.roundForObj(newValueMap[priceMap[pk].id][fieid],price_decimal);
+            }
             sumPrice +=scMathUtil.roundForObj(price*consumption,price_decimal);
         }
         sumPrice= scMathUtil.roundForObj(sumPrice,price_decimal);
@@ -320,10 +348,25 @@ class UnitPriceModel extends BaseModel {
         }
         let doc={};
         doc[fieid]=sumPrice;
-        let uprice =  await this.db.findAndModify(pcondition,doc);
-        uprice[fieid]=sumPrice;
-        return uprice;
+        if(batchUpdate == true){
+            return this.generateUpdateTask(pcondition,doc);
+        }else {
+            let uprice =  await this.db.findAndModify(pcondition,doc,{new: true});
+            //uprice[fieid]=sumPrice;
+            return uprice;
+        }
     }
+
+    generateUpdateTask(condition,doc) {
+        let task = {
+            updateOne:{
+                filter:condition,
+                update:doc
+            }
+        };
+        return task
+}
+
     /**
      * 复制单价文件数据
      *

+ 1 - 0
modules/glj/routes/glj_router.js

@@ -22,6 +22,7 @@ router.post('/change-file', gljController.init, gljController.changeUnitPriceFil
 router.post('/save-as', gljController.init, gljController.unitPriceSaveAs);
 router.post('/get-composition', gljController.init, gljController.getComposition);
 router.post('/updatePrice', gljController.init, gljController.updateUnitPrice);
+router.post('/batchUpdatePrices', gljController.init, gljController.batchUpdatePrices);
 router.post('/modifyKeyValue',gljController.init, gljController.modifyKeyValue);
 
 router.get('/test', gljController.init, gljController.test);

+ 1 - 1
modules/main/facade/bill_facade.js

@@ -3,7 +3,7 @@
  */
 let mongoose = require('mongoose');
 let quantity_detail = require("./quantity_detail_facade");
-let Bills_Lib = mongoose.model('std_bills_lib_list');
+let Bills_Lib = mongoose.model('std_bills_lib_bills');
 let bill_Model = require('../models/bills').model;
 let _ = require("lodash");
 module.exports={

+ 2 - 0
modules/pm/models/project_property_template.js

@@ -13,6 +13,8 @@ const defaultDecimal = {
 };
 const displaySetting = {
     autoHeight:true,
+    billsAutoHeight:true,
+    rationAutoHeight:false,
     disPlayMainMaterial:true
 }
 

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

@@ -48,11 +48,11 @@ let JpcBand = {
                 }
             }
             parentObj[bandNode[JV.BAND_PROP_NAME]] = item;
-            if (item[JV.BAND_PROP_MERGE_BORDER] != null && item[JV.BAND_PROP_MERGE_BORDER] != undefined && item[JV.BAND_PROP_MERGE_BORDER] == 'T') {
+            if (item[JV.BAND_PROP_MERGE_BORDER] !== null && item[JV.BAND_PROP_MERGE_BORDER] !== undefined && item[JV.BAND_PROP_MERGE_BORDER] === 'T') {
                 parentObj[JV.BAND_PROP_MERGE_BAND] = item;
             }
         }
     }
-}
+};
 
 module.exports = JpcBand;

+ 1 - 2
modules/reports/rpt_component/jpc_field.js

@@ -43,7 +43,6 @@ let JpcField = {
         return JpcFieldResult;
     },
     createSingle: function(fieldNode, parentObj, rptTpl, dataNodeName, sequence) {
-        let me = this;
         if (fieldNode && fieldNode[JV.PROP_ID]) {
             let item = {};
             item[JV.PROP_ID] = fieldNode[JV.PROP_ID];
@@ -54,6 +53,6 @@ let JpcField = {
             parentObj[JV.PROP_ID + "_" + fieldNode[JV.PROP_ID]] = item;
         }
     }
-}
+};
 
 module.exports = JpcField;

+ 74 - 79
modules/reports/rpt_component/jpc_flow_tab.js

@@ -12,12 +12,11 @@ let JpcAreaHelper = require('./helper/jpc_helper_area');
 let PDFKit = require('pdfkit');
 
 let JpcFlowTabSrv = function(){};
-//let grpPageInfo = {"segGrpRecStartIdx": 0, "insertedGrpRecAmt": 0, "preAddPageGrpInfo": null};
 JpcFlowTabSrv.prototype.createNew = function(){
+    //grpPageInfo :{"segGrpRecStartIdx": 0, "insertedGrpRecAmt": 0, "preAddPageGrpInfo": null}; //纯属解释参数grpPageInfo结构
     function private_addPageValue(ValuedIdxLst, sortedSequence, grpSequenceInfo, startRecIdx, maxRecPerPage,page_seg_map, segIdx, pageIdx, grpPageInfo, isFollow, segAutoHeightInfo, prePageLeftAutoHeightRecAmt) {
         let vIdx = [], preAmt = 0, insertedGrpAmt = 0, grp_lines = 0, followMode = (isFollow)?JV.TYPE_FOLLOW_MODE:-1, nextPageAutoHeightRecAmt = 0;
         if (grpSequenceInfo && grpPageInfo) {
-            //grpPageInfo[JV.PROP_INSERTED_GRP_REC] = 0;
             if (grpPageInfo[JV.PROP_PRE_ADD_GRP_REC_INFO].length > 0) {
                 for (let grpLineIdx of grpPageInfo[JV.PROP_PRE_ADD_GRP_REC_INFO]) {
                     vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_GROUP, grpPageInfo[JV.PROP_SEG_GRP_IDX], grpLineIdx]);
@@ -36,9 +35,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 ttlValAmt = segAutoHeightInfo[segIdx][startRecIdx + vi];
             }
             if (prePageLeftAutoHeightRecAmt > 0 && vi === 0) {
-                // startIdx = ttlValAmt - prePageLeftAutoHeightRecAmt;
                 startIdx = prePageLeftAutoHeightRecAmt;
-                // autoHeightAmt += prePageLeftAutoHeightRecAmt;
             }
             for (let subValIdx = startIdx; subValIdx < ttlValAmt; subValIdx++) {
                 vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_AUTO_HEIGHT, sortedSequence[startRecIdx + vi], subValIdx, ttlValAmt]);
@@ -50,67 +47,68 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 }
             }
             return couldBreak;
-        }
+        };
+        let private_inner_add_grp_rec = function(vi) {
+            let hasFullGrp = true, couldBreak = false;
+            for (let i = 0; i < grp_lines; i++) {
+                if ( ((vi + insertedGrpAmt * grp_lines) + 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([followMode, 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 {
+                couldBreak = true;
+            }
+            return couldBreak;
+        };
+        let private_normal_add_rec = function(vi) {
+            let couldBreak = false;
+            if (segAutoHeightInfo && segAutoHeightInfo.length > 0) {
+                if (segAutoHeightInfo[segIdx].length > startRecIdx + vi) {
+                    couldBreak = private_addAutoHeightPageValue(vi);
+                    // if (couldBreak) break;
+                } else if (vIdx.length < maxRecPerPage) {
+                    vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_NORMAL, JV.BLANK_VALUE_INDEX]);
+                }
+            } else {
+                if (sortedSequence.length > startRecIdx + vi) {
+                    vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_NORMAL, sortedSequence[startRecIdx + vi]]);
+                } else {
+                    vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_NORMAL, JV.BLANK_VALUE_INDEX]);
+                }
+            }
+            return couldBreak;
+        };
         for (let vi = 0; (vi + insertedGrpAmt * grp_lines) < maxRecPerPage - preAmt; vi++) {
             if (grpSequenceInfo && grpPageInfo) {
                 if ((startRecIdx + vi) === grpSequenceInfo[grpPageInfo[JV.PROP_SEG_GRP_IDX]]) {
                     //表示这里要插入grouping信息啦!
-                    //1. 首先push正常的记录
-                    vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_NORMAL, sortedSequence[startRecIdx + vi]]);
-                    //2. 然后就要push grouping记录了
-                    let hasFullGrp = true;
-                    for (let i = 0; i < grp_lines; i++) {
-                        if ( ((vi + insertedGrpAmt * grp_lines) + 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([followMode, 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 {
+                    let couldBreak = false;
+                    //1. 首先push正常的记录(要考虑自动行高调整的分支)
                     if (segAutoHeightInfo && segAutoHeightInfo.length > 0) {
-                        if (segAutoHeightInfo[segIdx].length > startRecIdx + vi) {
-                            let couldBreak = private_addAutoHeightPageValue(vi);
-                            if (couldBreak) break;
-                        } else if (vIdx.length < maxRecPerPage) {
-                            vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_NORMAL, JV.BLANK_VALUE_INDEX]);
-                        }
+                        couldBreak = private_addAutoHeightPageValue(vi);
                     } else {
-                        if (sortedSequence.length > startRecIdx + vi) {
-                            vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_NORMAL, sortedSequence[startRecIdx + vi]]);
-                        } else {
-                            vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_NORMAL, JV.BLANK_VALUE_INDEX]);
-                        }
-                    }
-                }
-            } else {
-                if (segAutoHeightInfo && segAutoHeightInfo.length > 0) {
-                    if (segAutoHeightInfo[segIdx].length > startRecIdx + vi) {
-                        let couldBreak = private_addAutoHeightPageValue(vi);
-                        if (couldBreak) break;
-                    } else if (vIdx.length < maxRecPerPage) {
-                        vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_NORMAL, JV.BLANK_VALUE_INDEX]);
-                    }
-                } else {
-                    nextPageAutoHeightRecAmt = 0;
-                    if (sortedSequence.length > startRecIdx + vi) {
                         vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_NORMAL, sortedSequence[startRecIdx + vi]]);
-                    } else {
-                        vIdx.push([followMode, JV.DISPLAY_VAL_TYPE_NORMAL, JV.BLANK_VALUE_INDEX]);
                     }
+                    //2. 然后就要push grouping记录了
+                    if (private_inner_add_grp_rec(vi)) break;
+                    if (couldBreak) break;
+                } else {
+                    if (private_normal_add_rec(vi)) break;
                 }
+            } else {
+                if (private_normal_add_rec(vi)) break;
             }
         }
         page_seg_map.push([pageIdx, segIdx]);
@@ -283,7 +281,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                     }
                 }
                 return rst;
-            }
+            };
             let private_get_max_lines_of_the_record = function(theRecIdx) {
                 let rst = 1;
                 for (let loop = 0; loop < me.auto_height_fields_idx.length; loop++) {
@@ -414,8 +412,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 pageIdx++;
                 function private_chk_handle_rec_amt(dv, isEx) {
                     if ((dv[1] === JV.DISPLAY_VAL_TYPE_NORMAL) || (dv[1] === JV.DISPLAY_VAL_TYPE_AUTO_HEIGHT && dv[3] === dv[4] - 1)) {
-                        if (isEx) counterRowRecEx++
-                        else counterRowRec++;
+                        if (isEx) {counterRowRecEx++} else counterRowRec++;
                     } else if (dv[1] === JV.DISPLAY_VAL_TYPE_AUTO_HEIGHT) {
                         redundantRecAmt++;
                     }
@@ -439,7 +436,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                     }
                     me.dispValueIdxLst.splice(me.dispValueIdxLst.length - 1, 1);
                 } else if (isFollow) {
-                    prePageLeftAutoHeightRecAmt = private_addPageValue(me.dispValueIdxLst, followTabEx.segments[segIdx], null, counterRowRecEx, maxRowRec, me.page_seg_map, segIdx, pageIdx, null, true, me.auto_height_info, prePageLeftAutoHeightRecAmt);
+                    prePageLeftAutoHeightRecAmt = private_addPageValue(me.dispValueIdxLst, followTabEx.segments[segIdx], null, counterRowRecEx, maxRowRec, me.page_seg_map, segIdx, pageIdx, null, true, null, 0);
                     for (let dv of me.dispValueIdxLst[me.dispValueIdxLst.length - 1]) {
                         private_chk_handle_rec_amt(dv, true);
                     }
@@ -478,7 +475,6 @@ JpcFlowTabSrv.prototype.createNew = function(){
                         adHocAutoHeightAmt += (me.auto_height_info[segIdx][loop] - 1);
                         if (me.group_node_info && me.group_node_info[segIdx]) {
                             if (me.group_node_info[segIdx][adHocAutoHeightGrpStartIdx] === loop) {
-                                me.group_node_info[segIdx][adHocAutoHeightGrpStartIdx] = me.group_node_info[segIdx][adHocAutoHeightGrpStartIdx] + adHocAutoHeightAmt;
                                 adHocAutoHeightGrpStartIdx++;
                             }
                         }
@@ -486,34 +482,32 @@ JpcFlowTabSrv.prototype.createNew = function(){
                     ttlSegRecAmtNormal += adHocAutoHeightAmt;
                     ttlSegRecAmt += adHocAutoHeightAmt;
                 }
-                //自动行高调整暂时不支持多流水合并方式(后期需要再加)
+                //自动行高调整在多流水合并方式时,只支持前部分(后期需要再加)
                 while (true) {
                     if (currentRecAmt > 0) pageStatus[JV.STATUS_SEGMENT_START] = false;
                     if (pageIdx > 0) pageStatus[JV.STATUS_REPORT_START] = false;
                     //开始判断各种scenarios
                     adHocAutoHeightAmt = 0;
-                    let recAmtForAdHocAutoHeight = 0;
                     if (me.auto_height_fields_idx.length > 0) {
                         adHocAutoHeightAmt -= prePageLeftAutoHeightRecAmt;
                         //for (let loop = currentRecAmt; loop < me.auto_height_info[segIdx].length; loop++) {
                         for (let loop = currentRecAmt; loop < currentRecAmt + maxRowRec; loop++) {
                             if (me.auto_height_info[segIdx].length > loop) {
                                 adHocAutoHeightAmt += (me.auto_height_info[segIdx][loop] - 1);
-                                recAmtForAdHocAutoHeight++;
                             } else {
                                 break;
                             }
                         }
                     }
-                    if ((ttlSegRecAmtNormal < ttlSegRecAmt) || (followTabEx != null)) {
+                    if ((ttlSegRecAmtNormal < ttlSegRecAmt) || (followTabEx !== null)) {
                         //有流水拓展,并且是follow mode
-                        if (currentRecAmt + adHocAutoHeightAmt + recAmtForAdHocAutoHeight + maxRowRec > ttlSegRecAmtNormal) {
-                            if (currentRecAmt + adHocAutoHeightAmt + recAmtForAdHocAutoHeight >= ttlSegRecAmtNormal) {
+                        if (currentRecAmt + adHocAutoHeightAmt + maxRowRec > ttlSegRecAmtNormal) {
+                            if (currentRecAmt + adHocAutoHeightAmt >= ttlSegRecAmtNormal) {
                                 //纯 followTabEx 数据
-                                if (currentRecAmt + adHocAutoHeightAmt + recAmtForAdHocAutoHeight + maxRowRec >= ttlSegRecAmt) {
+                                if (currentRecAmt + adHocAutoHeightAmt + maxRowRec >= ttlSegRecAmt) {
                                     pageStatus[JV.STATUS_SEGMENT_END] = true;
                                     private_resetBandArea();
-                                    let hasAdHocRow = !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, ttlSegRecAmt, currentRecAmt + adHocAutoHeightAmt + recAmtForAdHocAutoHeight, maxRowRec, me.isEx);
+                                    let hasAdHocRow = !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, ttlSegRecAmt, currentRecAmt + adHocAutoHeightAmt, maxRowRec, me.isEx);
                                     if (hasAdHocRow) {
                                         //add page info(pre segment end)
                                         pageStatus[JV.STATUS_SEGMENT_END] = false;
@@ -527,10 +521,10 @@ JpcFlowTabSrv.prototype.createNew = function(){
                                 }
                             } else {
                                 //混合数据
-                                if (currentRecAmt + adHocAutoHeightAmt + recAmtForAdHocAutoHeight + maxRowRec >= ttlSegRecAmt) {
+                                if (currentRecAmt + adHocAutoHeightAmt + maxRowRec >= ttlSegRecAmt) {
                                     pageStatus[JV.STATUS_SEGMENT_END] = true;
                                     private_resetBandArea();
-                                    let hasAdHocRow = !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, ttlSegRecAmt, currentRecAmt + adHocAutoHeightAmt + recAmtForAdHocAutoHeight, maxRowRec, me.isEx);
+                                    let hasAdHocRow = !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, ttlSegRecAmt, currentRecAmt + adHocAutoHeightAmt, maxRowRec, me.isEx);
                                     if (hasAdHocRow) {
                                         //add page info(pre segment end)
                                         pageStatus[JV.STATUS_SEGMENT_END] = false;
@@ -538,7 +532,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                                     }
                                     //add page info
                                     pageStatus[JV.STATUS_SEGMENT_END] = true;
-                                    if (currentRecAmt + adHocAutoHeightAmt + recAmtForAdHocAutoHeight >= ttlSegRecAmtNormal) {
+                                    if (currentRecAmt + adHocAutoHeightAmt >= ttlSegRecAmtNormal) {
                                         //纯 followTabEx 数据啦
                                         private_addPage(segIdx, null, true, false, -1);
                                     } else {
@@ -554,14 +548,15 @@ JpcFlowTabSrv.prototype.createNew = function(){
                         }
                     } else {
                         //普通流水数据情况
-                        if ((currentRecAmt + adHocAutoHeightAmt + recAmtForAdHocAutoHeight + maxRowRec >= ttlSegRecAmt)
-                             && (recAmtForAdHocAutoHeight + adHocAutoHeightAmt < 2 * maxRowRec) ) {
+                        if ((currentRecAmt + adHocAutoHeightAmt + maxRowRec >= ttlSegRecAmt)
+                             //&& (adHocAutoHeightAmt < 2 * maxRowRec) ) {
+                             && ((currentRecAmt + adHocAutoHeightAmt + maxRowRec - ttlSegRecAmt) < maxRowRec) ) {
                             //备注: 理论上自动行高是没有上限的,有可能正常一页的数据可以拓展到3页及以上,在此极端情况下,必须做一些限制判断,否则会出现缺页情况。
                             pageStatus[JV.STATUS_SEGMENT_END] = true;
                             pageStatus[JV.STATUS_REPORT_END] = true;
                             private_resetBandArea();
-                            let hasAdHocRow = ((recAmtForAdHocAutoHeight + adHocAutoHeightAmt > maxRowRec) ||
-                                              !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, ttlSegRecAmt, currentRecAmt + adHocAutoHeightAmt + recAmtForAdHocAutoHeight, maxRowRec, me.isEx));
+                            let hasAdHocRow = ((adHocAutoHeightAmt > maxRowRec) ||
+                                              !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, ttlSegRecAmt, currentRecAmt + adHocAutoHeightAmt, maxRowRec, me.isEx));
                             if (hasAdHocRow) {
                                 //add page info(pre segment end)
                                 pageStatus[JV.STATUS_SEGMENT_END] = false;
@@ -591,7 +586,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                     }
                 }
             }
-            console.log(me.auto_height_info);
+            // console.log(me.auto_height_info);
             // console.log(me.dispValueIdxLst);
             rst = Math.ceil(pageIdx / me.multiCols);
         }
@@ -760,7 +755,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                         for (let grpIdx = 0; grpIdx < rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_GROUP][JV.PROP_GROUP_LINES].length; grpIdx++) {
                             if (contentValuesIdx[rowIdx][3] === grpIdx) {
                                 let grp_line = rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_GROUP][JV.PROP_GROUP_LINES][grpIdx];
-                                let lineRst = me.outputTabGrpLine(band, grp_line, page, contentValuesIdx[rowIdx], contentValuesIdx.length, rowIdx, 1, 0, unitFactor, true, controls, multiColIdx)
+                                let lineRst = me.outputTabGrpLine(band, grp_line, page, contentValuesIdx[rowIdx], contentValuesIdx.length, rowIdx, 1, 0, unitFactor, true, controls, multiColIdx);
                                 rst = rst.concat(lineRst);
                             }
                         }
@@ -887,7 +882,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
             let curSegGrpSum = me.group_sum_values[segIdx];
             for (let sumFieldNode of grp_line[JV.PROP_GROUP_SUM_KEYS]) {
                 let value = curSegGrpSum[sumFieldNode[JV.PROP_SUM_KEY]][grpValueIdx[2]];
-                let sumFldRst = JpcTextHelper.outputDirectValue(sumFieldNode, value,  band, unitFactor, rows, rowIdx, cols, colIdx, me.multiCols, multiColIdx)
+                let sumFldRst = JpcTextHelper.outputDirectValue(sumFieldNode, value,  band, unitFactor, rows, rowIdx, cols, colIdx, me.multiCols, multiColIdx);
                 rst.push(sumFldRst);
             }
         }

+ 0 - 1
modules/reports/rpt_component/jpc_function.js

@@ -1,7 +1,6 @@
 let JV = require('./jpc_value_define');
 let JpcFunc = {
     createNew: function (rptTpl) {
-        let me = this;
         let rst = [];
         if (rptTpl[JV.NODE_FORMULAS]) {
             for (let i = 0; i < rptTpl[JV.NODE_FORMULAS].length; i++) {

+ 1 - 2
modules/reports/rpt_component/jpc_param.js

@@ -11,7 +11,6 @@ let JpcParam = {
         return JpcParamResult;
     },
     createSingle: function(paramNode, parentObj, rptTpl, sequence) {
-        let me = this;
         if (paramNode && paramNode[JV.PROP_ID]) {
             let item = {};
             item[JV.PROP_ID] = paramNode[JV.PROP_ID];
@@ -22,6 +21,6 @@ let JpcParam = {
             parentObj[JV.PROP_ID + "_" + paramNode[JV.PROP_ID]] = item;
         }
     }
-}
+};
 
 module.exports = JpcParam;

+ 3 - 5
modules/reports/rpt_component/jpc_rte.js

@@ -56,8 +56,7 @@ let JE = {
         } else 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].length;
-            field.DataSeq = len;
+            field.DataSeq = dataObj[JV.DATA_DISCRETE_DATA].length;
             dataObj[JV.DATA_DISCRETE_DATA].push([]);
             dataObj[field.DataNodeName][field.DataSeq][valIdx] = newValue;
         } else {
@@ -81,8 +80,7 @@ let JE = {
             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;
+                field.DataSeq = dataObj[JV.DATA_DISCRETE_DATA];
                 dataObj[JV.DATA_DISCRETE_DATA].push([]);
             }
             if (dataObj[field.DataNodeName][field.DataSeq].length > valIdx) {
@@ -95,6 +93,6 @@ let JE = {
         }
         return rst;
     }
-}
+};
 
 module.exports = JE;

+ 1 - 1
public/web/sheet/sheet_common.js

@@ -159,7 +159,7 @@ var sheetCommonObj = {
                     val =scMathUtil.roundToString(val,decimal);
                     sheet.setFormatter(-1, col,getFormatter(decimal), GC.Spread.Sheets.SheetArea.viewport);
                 }else {
-                    val =scMathUtil.roundToString(val,2);
+                    val =val+'';
                 }
             }
             if(val!=null&&setting.header[col].cellType === "checkBox"){

+ 8 - 0
public/web/tree_sheet/tree_sheet_helper.js

@@ -156,6 +156,9 @@ var TREE_SHEET_HELPER = {
                 if (colSetting.data.cellType && Object.prototype.toString.apply(colSetting.data.cellType) !== "[object String]") {
                     cell.cellType(colSetting.data.cellType(node));
                 }
+                if(colSetting.data.autoHeight == true){
+                    colSetting.setAutoHeight(cell,node);
+                }
                 if(sheet.name()=='mainSheet'&&gljOprObj.isInstallationNode(node)){//如果是通过安装增加费自动生成的,都是只读类型
                     cell.locked(true);
                 }else if (colSetting.readOnly) {
@@ -343,10 +346,15 @@ var TREE_SHEET_HELPER = {
             let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, {sheet: hitinfo.sheet, row: hitinfo.row, col: hitinfo.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport});
             let cellWidth = hitinfo.sheet.getCell(-1, hitinfo.col).width();
             let dataField = setting.cols[hitinfo.col].data.field;
+
+            if(hitinfo.sheet.getCell(hitinfo.row,hitinfo.col).wordWrap()==true){
+                return;
+            }
             if(dataField === 'name' || dataField === 'itemCharacterText' || dataField === 'jobContentText' || dataField === 'adjustState'){
                 if(hitinfo.sheet.getParent() === projectObj.mainSpread && textLength <= cellWidth)
                  return;
             }
+
             if(dataField=="quantity"){
                 text = tag;
             }else if(tag !== undefined && tag) {

+ 204 - 197
test/calculation/test_analyzer.js

@@ -2,203 +2,204 @@
  * Created by CSL on 2017-09-01.
  */
 var test = require('tape');
-import analyzer from '../../public/calc_util';
+import analyzer from '../../web/building_saas/main/js/models/calc_program';
 
-test('解析测试', function(t){
-    let calcTemplate = {
-        ID: 1,
-        name: "建筑工程",
-        calcItems: [
-            {
-                ID: "101",
-                code: "1",
-                name: "基价直接工程费",
-                fieldName: "baseDirect",
-                dispExpr: "F2+F5+F6+F10",
-                expression: "@('2') + @('5') + @('6') + @('10')",
-                compiledExpr: "",
-                statement: "基价人工费+基价材料费+基价机械费+未计价材料费"
-            },
-            {
-                ID: "102",
-                code: "1.1",
-                name: "基价人工费",
-                fieldName: "baseLabour",
-                dispExpr: "F3+F4",
-                expression: "@('3') + @('4')",
-                compiledExpr: "",
-                statement: "定额基价人工费+定额人工单价(基价)调整"
-            },
-            {
-                ID: "103",
-                code: "1.1.1",
-                name: "定额基价人工费",
-                fieldName: "rationBaseLabour",
-                dispExpr: "[定额基价人工费]",
-                expression: "base('定额基价人工费').toFixed(2)",
-                compiledExpr: "",
-                statement: "定额基价人工费"
-            },
-            {
-                ID: "104",
-                code: "1.1.2",
-                name: "定额人工单价(基价)调整",
-                fieldName: "rationLabourFixed",
-                dispExpr: "F3*(L-1)",
-                expression: "@('3') * (L-1)",
-                labourCoeID: 22,
-                compiledExpr: "",
-                statement: "定额基价人工费*[定额人工单价(基价)调整系数-1]",
-                memo: "渝建发(2013)51"
-            },
-            {
-                ID: "105",
-                code: "1.2",
-                name: "基价材料费",
-                fieldName: "baseMaterial",
-                dispExpr: "[定额基价材料费]",
-                expression: "base('定额基价材料费')",
-                compiledExpr: "",
-                statement: "定额基价材料费"
-            },
-            {
-                ID: "106",
-                code: "1.3",
-                name: "基价机械费",
-                fieldName: "baseMachine",
-                dispExpr: "F7+F9",
-                expression: "@('7') + @('9')",
-                compiledExpr: "",
-                statement: "定额基价机械费+定额机上人工单价(基价)调整"
-            },
-            {
-                ID: "107",
-                code: "1.3.1",
-                name: "定额基价机械费",
-                fieldName: "rationBaseMachine",
-                dispExpr: "[定额基价机械费]",
-                expression: "base('定额基价机械费')",
-                compiledExpr: "",
-                statement: "定额基价机械费"
-            },
-            {
-                ID: "108",
-                code: "1.3.1.1",
-                name: "其中:定额基价机上人工费",
-                fieldName: "rationBaseMachineLabour",
-                dispExpr: "[定额基价机上人工费]",
-                expression: "base('定额基价机上人工费')",
-                compiledExpr: "",
-                statement: "定额基价机上人工费"
-            },
-            {
-                ID: "109",
-                code: "1.3.2",
-                name: "定额机上人工单价(基价)调整",
-                fieldName: "rationBaseMachineLabourFixed",
-                dispExpr: "F8*(L-1)",
-                expression: "@('8') * (L-1)",
-                labourCoeID: 24,
-                compiledExpr: "",
-                statement: "定额基价机上人工费*[定额机上人工单价(基价)调整系数-1]"
-            },
-            {
-                ID: "110",
-                code: "1.4",
-                name: "未计价材料费",
-                fieldName: "unPriceMaterial",
-                dispExpr: "[主材费]+[设备费]",
-                expression: "base('主材费') + base('设备费')",
-                compiledExpr: "",
-                statement: "主材费+设备费"
-            },
-            {
-                ID: "111",
-                code: "2",
-                name: "企业管理费",
-                fieldName: "manageFee",
-                dispExpr: "F3+F5+F7",
-                feeRateID: 101,
-                expression: "@('3') + @('5') + @('7')",
-                compiledExpr: "",
-                statement: "定额基价人工费",
-                memo: "渝建发[2014]27号"
-            },
-            {
-                ID: "112",
-                code: "3",
-                name: "利润",
-                fieldName: "profit",
-                dispExpr: "F3+F5+F7",
-                feeRateID: 301,
-                expression: "@('3') + @('5') + @('7')",
-                compiledExpr: "",
-                statement: "定额基价人工费"
-            },
-            {
-                ID: "113",
-                code: "4",
-                name: "风险因素",
-                fieldName: "risk",
-                dispExpr: "F3+F5+F7",
-                feeRateID: 701,
-                expression: "@('3') + @('5') + @('7')",
-                compiledExpr: "",
-                statement: "定额基价人工费",
-                memo: "同定额包干费"
-            },
-            {
-                ID: "114",
-                code: "5",
-                name: "人材机价差",
-                fieldName: "lmmDiff",
-                dispExpr: "F15+F16+F17",
-                expression: "@('15') + @('16') + @('17')",
-                compiledExpr: "",
-                statement: "人工费价差+材料费价差+机械费价差"
-            },
-            {
-                ID: "115",
-                code: "5.1",
-                name: "人工费价差",
-                fieldName: "labourDiff",
-                dispExpr: "[人工费价差]",
-                expression: "base('市场价格人工费') - base('定额基价人工费(调整后)')",
-                compiledExpr: "",
-                statement: "市场价格人工费-调整后的定额人工费(基价)"
-            },
-            {
-                ID: "116",
-                code: "5.2",
-                name: "材料费价差",
-                fieldName: "materialDiff",
-                dispExpr: "[材料费价差]",
-                expression: "base('市场价格材料费') - base('定额基价材料费(调整后)')",
-                compiledExpr: "",
-                statement: "市场价格材料费-定额基价材料费"
-            },
-            {
-                ID: "117",
-                code: "5.3",
-                name: "机械费价差",
-                fieldName: "machineDiff",
-                dispExpr: "[机械费价差]",
-                expression: "base('市场价格机械费') - base('定额基价机械费(调整后)')",
-                compiledExpr: "",
-                statement: "市场价格机械费-调整后的定额基价机械费(基价)"
-            },
-            {
-                ID: "118",
-                code: "6",
-                name: "综合单价",
-                fieldName: "common",
-                dispExpr: "F1+F11+F12+F13+F14",
-                expression: "@('1') + @('11') + @('12') + @('13') + @('14')",
-                compiledExpr: "",
-                statement: "基价直接工程费+企业管理费+利润+风险因素+人材机价差"
-            }
-        ]
-    };
+let calcTemplate = {
+    ID: 1,
+    name: "建筑工程",
+    calcItems: [
+        {
+            ID: "101",
+            code: "1",
+            name: "基价直接工程费",
+            fieldName: "baseDirect",
+            dispExpr: "F2+F5+F6+F10",
+            expression: "@('2') + @('5') + @('6') + @('10')",
+            compiledExpr: "",
+            statement: "基价人工费+基价材料费+基价机械费+未计价材料费"
+        },
+        {
+            ID: "102",
+            code: "1.1",
+            name: "基价人工费",
+            fieldName: "baseLabour",
+            dispExpr: "F3+F4",
+            expression: "@('3') + @('4')",
+            compiledExpr: "",
+            statement: "定额基价人工费+定额人工单价(基价)调整"
+        },
+        {
+            ID: "103",
+            code: "1.1.1",
+            name: "定额基价人工费",
+            fieldName: "rationBaseLabour",
+            dispExpr: "[定额基价人工费]",
+            expression: "base('定额基价人工费').toFixed(2)",
+            compiledExpr: "",
+            statement: "定额基价人工费"
+        },
+        {
+            ID: "104",
+            code: "1.1.2",
+            name: "定额人工单价(基价)调整",
+            fieldName: "rationLabourFixed",
+            dispExpr: "F3*(L-1)",
+            expression: "@('3') * (L-1)",
+            labourCoeID: 22,
+            compiledExpr: "",
+            statement: "定额基价人工费*[定额人工单价(基价)调整系数-1]",
+            memo: "渝建发(2013)51"
+        },
+        {
+            ID: "105",
+            code: "1.2",
+            name: "基价材料费",
+            fieldName: "baseMaterial",
+            dispExpr: "[定额基价材料费]",
+            expression: "base('定额基价材料费')",
+            compiledExpr: "",
+            statement: "定额基价材料费"
+        },
+        {
+            ID: "106",
+            code: "1.3",
+            name: "基价机械费",
+            fieldName: "baseMachine",
+            dispExpr: "F7+F9",
+            expression: "@('7') + @('9')",
+            compiledExpr: "",
+            statement: "定额基价机械费+定额机上人工单价(基价)调整"
+        },
+        {
+            ID: "107",
+            code: "1.3.1",
+            name: "定额基价机械费",
+            fieldName: "rationBaseMachine",
+            dispExpr: "[定额基价机械费]",
+            expression: "base('定额基价机械费')",
+            compiledExpr: "",
+            statement: "定额基价机械费"
+        },
+        {
+            ID: "108",
+            code: "1.3.1.1",
+            name: "其中:定额基价机上人工费",
+            fieldName: "rationBaseMachineLabour",
+            dispExpr: "[定额基价机上人工费]",
+            expression: "base('定额基价机上人工费')",
+            compiledExpr: "",
+            statement: "定额基价机上人工费"
+        },
+        {
+            ID: "109",
+            code: "1.3.2",
+            name: "定额机上人工单价(基价)调整",
+            fieldName: "rationBaseMachineLabourFixed",
+            dispExpr: "F8*(L-1)",
+            expression: "@('8') * (L-1)",
+            labourCoeID: 24,
+            compiledExpr: "",
+            statement: "定额基价机上人工费*[定额机上人工单价(基价)调整系数-1]"
+        },
+        {
+            ID: "110",
+            code: "1.4",
+            name: "未计价材料费",
+            fieldName: "unPriceMaterial",
+            dispExpr: "[主材费]+[设备费]",
+            expression: "base('主材费') + base('设备费')",
+            compiledExpr: "",
+            statement: "主材费+设备费"
+        },
+        {
+            ID: "111",
+            code: "2",
+            name: "企业管理费",
+            fieldName: "manageFee",
+            dispExpr: "F3+F5+F7",
+            feeRateID: 101,
+            expression: "@('3') + @('5') + @('7')",
+            compiledExpr: "",
+            statement: "定额基价人工费",
+            memo: "渝建发[2014]27号"
+        },
+        {
+            ID: "112",
+            code: "3",
+            name: "利润",
+            fieldName: "profit",
+            dispExpr: "F3+F5+F7",
+            feeRateID: 301,
+            expression: "@('3') + @('5') + @('7')",
+            compiledExpr: "",
+            statement: "定额基价人工费"
+        },
+        {
+            ID: "113",
+            code: "4",
+            name: "风险因素",
+            fieldName: "risk",
+            dispExpr: "F3+F5+F7",
+            feeRateID: 701,
+            expression: "@('3') + @('5') + @('7')",
+            compiledExpr: "",
+            statement: "定额基价人工费",
+            memo: "同定额包干费"
+        },
+        {
+            ID: "114",
+            code: "5",
+            name: "人材机价差",
+            fieldName: "lmmDiff",
+            dispExpr: "F15+F16+F17",
+            expression: "@('15') + @('16') + @('17')",
+            compiledExpr: "",
+            statement: "人工费价差+材料费价差+机械费价差"
+        },
+        {
+            ID: "115",
+            code: "5.1",
+            name: "人工费价差",
+            fieldName: "labourDiff",
+            dispExpr: "[人工费价差]",
+            expression: "base('市场价格人工费') - base('定额基价人工费(调整后)')",
+            compiledExpr: "",
+            statement: "市场价格人工费-调整后的定额人工费(基价)"
+        },
+        {
+            ID: "116",
+            code: "5.2",
+            name: "材料费价差",
+            fieldName: "materialDiff",
+            dispExpr: "[材料费价差]",
+            expression: "base('市场价格材料费') - base('定额基价材料费(调整后)')",
+            compiledExpr: "",
+            statement: "市场价格材料费-定额基价材料费"
+        },
+        {
+            ID: "117",
+            code: "5.3",
+            name: "机械费价差",
+            fieldName: "machineDiff",
+            dispExpr: "[机械费价差]",
+            expression: "base('市场价格机械费') - base('定额基价机械费(调整后)')",
+            compiledExpr: "",
+            statement: "市场价格机械费-调整后的定额基价机械费(基价)"
+        },
+        {
+            ID: "118",
+            code: "6",
+            name: "综合单价",
+            fieldName: "common",
+            dispExpr: "F1+F11+F12+F13+F14",
+            expression: "@('1') + @('11') + @('12') + @('13') + @('14')",
+            compiledExpr: "",
+            statement: "基价直接工程费+企业管理费+利润+风险因素+人材机价差"
+        }
+    ]
+};
+
+/*test('解析测试', function(t){
     let calcItem = {dispExpr: "12 +[人工费]*1.2+f13+ (F6+ f10) +F16+[人工费] + f6+[材料费]"};
     let target = "12+base('人工费')*1.2+@('113')+(@('106')+@('110'))+@('116')+base('人工费')+@('106')+base('材料费')";
     let rst = analyzer.analyzeUserExpr(calcTemplate, calcItem);
@@ -207,4 +208,10 @@ test('解析测试', function(t){
     console.log(calcItem.expression);
     t.equal(calcItem.expression, target);
     t.end();
-});
+});*/
+
+let expr = "F2+F5+F6+F10";
+let arr = analyzer.getFArr(expr);
+console.log(JSON.stringify(arr));
+let id = analyzer.getFID('F10', calcTemplate);
+console.log(JSON.stringify(id));

+ 5 - 4
test/unit/reports/test_cover_01.js

@@ -5,19 +5,20 @@
 let test = require('tape');
 import JpcEx from "../../../modules/reports/rpt_component/jpc_ex";
 import JV from "../../../modules/reports/rpt_component/jpc_value_define";
+let config = require("../../../config/config.js");
+config.setupDb(process.env.NODE_ENV);
 let mongoose = require("mongoose");
 let fileUtils = require("../../../modules/common/fileUtils");
 let path = require('path');
 let dbm = require("../../../config/db/db_manager");
 let rpt_cfg = require('./rpt_cfg');
-dbm.connect();
+dbm.connect(process.env.NODE_ENV);
 
 //统一引用models
 fileUtils.getGlobbedFiles('../../../modules/all_models/*.js').forEach(function(modelPath) {
     require(path.resolve(modelPath));
 });
 
-//config.setupCache();
 let cfgCacheUtil = require("../../../config/cacheCfg");
 cfgCacheUtil.setupDftCache();
 
@@ -56,7 +57,7 @@ test('测试 - 打开模板: 封-1 ', function (t) {
         rptTplDataFacade.prepareProjectData(userId_Dft, demoPrjId, filter, function (err, msg, rawDataObj) {
             if (!err) {
                 try {
-                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject.js");
+                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject.jsp");
                     let tplData = rptDataUtil.assembleData(rawDataObj);
                     //build the report
                     let printCom = JpcEx.createNew();
@@ -68,7 +69,7 @@ test('测试 - 打开模板: 封-1 ', function (t) {
                     let maxPages = printCom.totalPages;
                     let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
                     if (pageRst) {
-                        // fsUtil.writeObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult.js");
+                        // fsUtil.writeObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult.jsp");
                     } else {
                         console.log("oh! no pages were created!");
                     }

+ 5 - 4
test/unit/reports/test_cover_02.js

@@ -5,19 +5,20 @@
 let test = require('tape');
 import JpcEx from "../../../modules/reports/rpt_component/jpc_ex";
 import JV from "../../../modules/reports/rpt_component/jpc_value_define";
+let config = require("../../../config/config.js");
+config.setupDb(process.env.NODE_ENV);
 let mongoose = require("mongoose");
 let fileUtils = require("../../../modules/common/fileUtils");
 let path = require('path');
 let dbm = require("../../../config/db/db_manager");
 let rpt_cfg = require('./rpt_cfg');
-dbm.connect();
+dbm.connect(process.env.NODE_ENV);
 
 //统一引用models
 fileUtils.getGlobbedFiles('../../../modules/all_models/*.js').forEach(function(modelPath) {
     require(path.resolve(modelPath));
 });
 
-//config.setupCache();
 let cfgCacheUtil = require("../../../config/cacheCfg");
 cfgCacheUtil.setupDftCache();
 
@@ -56,7 +57,7 @@ test('测试 - 打开模板: 封-1 ', function (t) {
         rptTplDataFacade.prepareProjectData(userId_Dft, demoPrjId, filter, function (err, msg, rawDataObj) {
             if (!err) {
                 try {
-                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject.js");
+                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject.jsp");
                     let tplData = rptDataUtil.assembleData(rawDataObj);
                     //build the report
                     let printCom = JpcEx.createNew();
@@ -68,7 +69,7 @@ test('测试 - 打开模板: 封-1 ', function (t) {
                     let maxPages = printCom.totalPages;
                     let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
                     if (pageRst) {
-                        fsUtil.writeObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult.js");
+                        fsUtil.writeObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult.jsp");
                     } else {
                         console.log("oh! no pages were created!");
                     }

+ 10 - 8
test/unit/reports/test_get_prj_data.js

@@ -2,20 +2,22 @@
  * Created by Tony on 2018/3/23.
  */
 let test = require('tape');
+
+let config = require("../../../config/config.js");
+config.setupDb(process.env.NODE_ENV);
 let mongoose = require("mongoose");
 let fileUtils = require("../../../modules/common/fileUtils");
 let path = require('path');
 let dbm = require("../../../config/db/db_manager");
-dbm.connect();
 let consts = require('../../../modules/main/models/project_consts');
 let projectConsts = consts.projectConst;
+dbm.connect(process.env.NODE_ENV);
 
 //统一引用models
 fileUtils.getGlobbedFiles('../../../modules/all_models/*.js').forEach(function(modelPath) {
     require(path.resolve(modelPath));
 });
 
-
 //config.setupCache();
 let cfgCacheUtil = require("../../../config/cacheCfg");
 cfgCacheUtil.setupDftCache();
@@ -33,8 +35,8 @@ demoPrjId = 1626; //QA:
 let userId_Leng = 1142; //小冷User Id
 let userId_Dft = userId_Leng;
 /*/
-let userId_Dft = 76075;
-//*/
+ let userId_Dft = 76075;
+ //*/
 
 let fs = require('fs');
 //设置Date Format函数
@@ -46,7 +48,7 @@ fs.readFile(__dirname.slice(0, __dirname.length - 18) + '/public/web/date_util.j
 test('测试 - 获取project数据: ', function (t) {
     projectDataMdl.getData(demoPrjId, function (err, message, result) {
         if (!err) {
-            fsUtil.writeObjToFile(result, "D:/GitHome/ConstructionCost/tmp/ProjectDataFullObject.js");
+            fsUtil.writeObjToFile(result, "D:/GitHome/ConstructionCost/tmp/ProjectDataFullObject.jsp");
             t.pass('pass succeeded!');
             t.end();
         } else {
@@ -75,9 +77,9 @@ test('测试 - 获取project部分数据: ', function (t) {
                     // for (let item of results) {
                     //     newData.push(JSON.stringify(item));
                     // }
-                    // fsUtil.writeArrayToFile(newData, "D:/GitHome/ConstructionCost/tmp/getProjectData_partial.js");
-                    // fsUtil.writeObjToFile(prjObj, "D:/GitHome/ConstructionCost/tmp/getProjectObjectNew.js");
-                    fsUtil.writeObjToFile(results, "D:/GitHome/ConstructionCost/tmp/getProjectData_partialNew.js");
+                    // fsUtil.writeArrayToFile(newData, "D:/GitHome/ConstructionCost/tmp/getProjectData_partial.jsp");
+                    // fsUtil.writeObjToFile(prjObj, "D:/GitHome/ConstructionCost/tmp/getProjectObjectNew.jsp");
+                    fsUtil.writeObjToFile(results, "D:/GitHome/ConstructionCost/tmp/getProjectData_partialNew.jsp");
                     t.pass('pass succeeded!');
                     t.end();
                 } else {

+ 3 - 2
test/unit/reports/test_tpl_09.js

@@ -5,19 +5,20 @@
 let test = require('tape');
 import JpcEx from "../../../modules/reports/rpt_component/jpc_ex";
 import JV from "../../../modules/reports/rpt_component/jpc_value_define";
+let config = require("../../../config/config.js");
+config.setupDb(process.env.NODE_ENV);
 let mongoose = require("mongoose");
 let fileUtils = require("../../../modules/common/fileUtils");
 let path = require('path');
 let dbm = require("../../../config/db/db_manager");
 let rpt_cfg = require('./rpt_cfg');
-dbm.connect();
+dbm.connect(process.env.NODE_ENV);
 
 //统一引用models
 fileUtils.getGlobbedFiles('../../../modules/all_models/*.js').forEach(function(modelPath) {
     require(path.resolve(modelPath));
 });
 
-//config.setupCache();
 let cfgCacheUtil = require("../../../config/cacheCfg");
 cfgCacheUtil.setupDftCache();
 

+ 5 - 3
test/unit/reports/test_tpl_09_1.js

@@ -4,12 +4,14 @@
 let test = require('tape');
 import JpcEx from "../../../modules/reports/rpt_component/jpc_ex";
 import JV from "../../../modules/reports/rpt_component/jpc_value_define";
+let config = require("../../../config/config.js");
+config.setupDb(process.env.NODE_ENV);
 let mongoose = require("mongoose");
 let fileUtils = require("../../../modules/common/fileUtils");
 let path = require('path');
 let dbm = require("../../../config/db/db_manager");
 let rpt_cfg = require('./rpt_cfg');
-dbm.connect();
+dbm.connect(process.env.NODE_ENV);
 
 //统一引用models
 fileUtils.getGlobbedFiles('../../../modules/all_models/*.js').forEach(function(modelPath) {
@@ -56,7 +58,7 @@ test('测试 - 测试模板啦: ', function (t) {
         rptTplDataFacade.prepareProjectData(userId_Dft, demoPrjId, filter, function (err, msg, rawDataObj) {
             if (!err) {
                 try {
-                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject.js");
+                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject.jsp");
                     let tplData = rptDataUtil.assembleData(rawDataObj);
                     //it's time to build the report!!!
                     let printCom = JpcEx.createNew();
@@ -116,7 +118,7 @@ test('测试 - 显示保存小数位数问题: ', function (t) {
     rpt_decimal_mdl.find({}).then(function (rst) {
         //console.log(rst);
         if (rst.length > 0) {
-            fsUtil.writeObjToFile(rst, "D:/GitHome/ConstructionCost/tmp/testDecimalResult.js");
+            fsUtil.writeObjToFile(rst, "D:/GitHome/ConstructionCost/tmp/testDecimalResult.jsp");
         }
         t.pass('pass get decimal ok!');
         t.end();

+ 1 - 1
web/building_saas/css/main.css

@@ -103,7 +103,7 @@ body {
     margin-left: 29px;
     background: #fff
 }
-.toolsbar,.toolsbar-f {
+.toolsbar,.toolsbar-f,.toolsbar_feeRate {
     border-bottom: 1px solid #ccc
 }
 .tools-btn {

+ 21 - 13
web/building_saas/fee_rates/fee_rate.html

@@ -1,27 +1,35 @@
 
 
 <div >
-<div class="toolsbar px-1">
+<div class="toolsbar_feeRate px-1 ">
     <div class="form-inline py-1">
         <label class="mx-2" >当前使用:<span id="feeRateFileName">费率1</span>(<a href="#" id="pop-lv"><span id="projectCount">3</span> 单位工程使用</a>)
             <a class="btn btn-sm ml-1" href="#" data-toggle="modal" data-target="#change-lv" id="changFeeRateFile"><i class="fa fa-exchange"></i> 选择其他</a>
             <a class="btn btn-sm ml-1" href="#" data-toggle="modal" id="saveAs" data-target="#copy-lv"><i class="fa fa-files-o"></i> 另存单独用</a></label>
     </div>
 </div>
-<div class="container-fluid">
-        <div class="row">
-            <div class="main-content col-lg-8 p-0">
-                <div class="form-inline py-1">
-                    <label class="mx-2" >基于&nbsp;&nbsp;<span id="feeRateLibName">重庆渝建发[2016]35号</span></label>
-                    <a class="btn btn-sm ml-1" href="#" data-toggle="modal" data-target="#set-lv" id="setNewFeeRate"><i class="fa fa-cog"></i> 重选标准</a>
-                </div>
-                <div class=" grid  main-data-full-fl" id="divFee"></div>
-            </div>
-            <div class="col-lg-4 py-1">
-                <div class="py-1"><input type="checkbox" id="cascadeSet" checked >统一设置相同参数</div>
-                <div class="grid  main-data-full-fl" id="subRate"></div>
+<div class="toolsbar_feeRate px-1">
+    <div class="row" style="margin-left: 0px">
+        <div class="col-lg-8 p-0">
+            <div class="form-inline py-1">
+                <label class="mx-2" >基于&nbsp;&nbsp;<span id="feeRateLibName">重庆渝建发[2016]35号</span></label>
+                <a class="btn btn-sm ml-1" href="#" data-toggle="modal" data-target="#set-lv" id="setNewFeeRate"><i class="fa fa-cog"></i> 重选标准</a>
             </div>
         </div>
+        <div class="col-lg-4 p-0">
+            <div class="form-inline py-1" style="margin-top: 5px"><input type="checkbox" id="cascadeSet" checked >  <label class="mx-2" >统一设置相同参数</label></div>
+        </div>
+    </div>
+</div>
+<div class="container-fluid">
+    <div class="row ">
+        <div class="col-lg-8 p-0 ">
+            <div class="grid main-data-full-feeRate" id="divFee"></div>
+        </div>
+        <div class="col-lg-4 p-0">
+            <div class="grid main-data-full-feeRate" id="subRate"></div>
+        </div>
+    </div>
 </div>
 <!--弹出更换-->
 <div class="modal fade" id="change-lv" data-backdrop="static">

+ 13 - 8
web/building_saas/js/global.js

@@ -1,16 +1,21 @@
 /*全局自适应高度*/
 function autoFlashHeight(){
-    var headerHeight = $(".header").height();
-    var toolsbarHeight = $(".toolsbar").height();
-    var ftoolsbarHeight = $(".toolsbar-f").height();
-    var bottomContentHeight = $(".bottom-content").height();
-    var toolsBarHeightQ = $(".tools-bar-height-q").height();
-    var toolsBarHeightD = $(".tools-bar-height-d").height();
+    let headerHeight = $(".header").height();
+    let toolsbarHeight = $(".toolsbar").height();
+    let ftoolsbarHeight = $(".toolsbar-f").height();
+   // var feeRateToolsbarHeight = $(".toolsbar_feeRate").height();
+    let mainBottomContentHeight = $("#main .bottom-content").height();
+    let gljBottomContentHeight = $("#project-glj-main .bottom-content").height();
+    let toolsBarHeightQ = $(".tools-bar-height-q").height();
+    let toolsBarHeightD = $(".tools-bar-height-d").height();
     $(".main-data-side-q").height($(window).height()-headerHeight-toolsbarHeight-toolsBarHeightQ-302);
     $(".main-data-side-d").height($(window).height()-headerHeight-toolsbarHeight-toolsBarHeightD-302);
-    $(".main-data-top").height($(window).height()-headerHeight-toolsbarHeight-bottomContentHeight-1);
+    //$("#main .main-data-top").height($(window).height()-headerHeight-toolsbarHeight-bottomContentHeight-1);
+    $("#billsSpread").height($(window).height()-headerHeight-toolsbarHeight-mainBottomContentHeight-1);
+    $("#project_glj_sheet").height($(window).height()-headerHeight-toolsbarHeight-gljBottomContentHeight-25);
     $(".main-data-full").height($(window).height()-headerHeight-toolsbarHeight-1);
     $(".main-data-full-fl").height($(window).height()-headerHeight-toolsbarHeight-37);
+    $(".main-data-full-feeRate").height($(window).height()-headerHeight-78);
     $(".main-data-not").height($(window).height()-headerHeight-1);
     $(".main-data-side-search").height($(window).height()-headerHeight-toolsbarHeight-64);
     $(".side-content").height($(window).height()-headerHeight );
@@ -19,9 +24,9 @@ function autoFlashHeight(){
     $(".form-list").height($(window).height()-headerHeight-50 );
 
 };
-$(window).resize(autoFlashHeight);
 /*全局自适应高度结束*/
 $(function () {
+    $(window).resize(autoFlashHeight);
     /*侧滑*/
   /*  $(".open-sidebar").click(function () {
         $(".slide-sidebar").animate({width: "800"}).addClass("open");

+ 14 - 2
web/building_saas/main/html/main.html

@@ -480,11 +480,23 @@
                                 <div class="tab-pane fade" id="display-setting" role="tabpanel">
                                     <div class="modal-auto-height" style="overflow: hidden">
                                         <fieldset class="form-group">
-                                            <div class="form-check">
+                                           <!-- <div class="form-check">
                                                 <label class="form-check-label">
                                                     <input class="form-check-input" id="autoHeight" type="checkbox">
                                                     造价书表格自动调整行高
                                                 </label>
+                                            </div>-->
+                                            <div class="form-check">
+                                                <label class="form-check-label">
+                                                    <input class="form-check-input" id="billsAutoHeight" type="checkbox">
+                                                    工程量清单自动调整行高
+                                                </label>
+                                            </div>
+                                            <div class="form-check">
+                                                <label class="form-check-label">
+                                                    <input class="form-check-input" id="rationAutoHeight" type="checkbox">
+                                                    定额子目自动调整行高
+                                                </label>
                                             </div>
                                             <div class="form-check">
                                                 <label class="form-check-label">
@@ -1202,7 +1214,7 @@
         <!-- endinject -->
 
         <script type="text/javascript">
-            autoFlashHeight();
+           // autoFlashHeight();
         </script>
 
         <SCRIPT type="text/javascript">

+ 17 - 7
web/building_saas/main/js/main.js

@@ -21,7 +21,12 @@ $(function () {
         $(e.relatedTarget.hash).removeClass('active');
         $("#subItems").addClass('active');
         $(gljOprObj.activeTab).addClass('active');
-        // do something
+        autoFlashHeight();
+        projectObj.refreshMainSpread();
+        /*loadSize("main", function() {
+            projectObj.refreshMainSpread();
+            refreshSubSpread();
+        });*/
     });
 
     slideResize($("#main"), function() {
@@ -115,16 +120,21 @@ function loadSize(tag, callback) {
     if (tag === '') {
         return;
     }
+    let o_topHeight = $("#"+ tag +" .main-data-top").height();
+    let o_bottomHeight = $("#"+ tag +" .main-data-bottom").height();
     let topHeight = getLocalCache('topHeight:' + tag);
     let bottomHeight = getLocalCache('bottomHeight:' + tag);
     if (topHeight === null || bottomHeight === null) {
-        return;
+        $("#"+ tag +" .main-data-top").height(o_topHeight);
+        $("#"+ tag +" .main-data-bottom").height(o_bottomHeight);
+    }else {
+        const navHeight = $("#"+ tag +" .bottom-content").children('ul.nav').height() + 4;
+        topHeight = parseFloat(topHeight);
+        bottomHeight = parseFloat(bottomHeight);
+        $("#"+ tag +" .main-data-top").height(topHeight);
+        $("#"+ tag +" .main-data-bottom").height(bottomHeight - navHeight);
     }
-    const navHeight = $("#"+ tag +" .bottom-content").children('ul.nav').height() + 4;
-    topHeight = parseFloat(topHeight);
-    bottomHeight = parseFloat(bottomHeight);
-    $("#"+ tag +" .main-data-top").height(topHeight);
-    $("#"+ tag +" .main-data-bottom").height(bottomHeight - navHeight);
+
     // $("#"+ tag +" .bottom-content").height(bottomHeight);
     callback();
 }

+ 135 - 83
web/building_saas/main/js/models/calc_program.js

@@ -13,7 +13,6 @@ let defaultBillTemplate = {
             code: "1",
             name: "定额直接费",
             dispExpr: "F2+F3+F4",
-            expression: "@('2')+@('3')+@('4')",
             statement: "人工费+材料费+机械费",
             feeRate: null,
             memo: ''
@@ -23,7 +22,6 @@ let defaultBillTemplate = {
             code: "1.1",
             name: "人工费",
             dispExpr: "HJ",
-            expression: "HJ",
             statement: "合计",
             feeRate: 50,
             fieldName: 'labour',
@@ -34,7 +32,6 @@ let defaultBillTemplate = {
             code: "1.2",
             name: "材料费",
             dispExpr: "HJ",
-            expression: "HJ",
             statement: "合计",
             feeRate: 30,
             fieldName: 'material',
@@ -45,7 +42,6 @@ let defaultBillTemplate = {
             code: "1.3",
             name: "机械费",
             dispExpr: "HJ",
-            expression: "HJ",
             statement: "合计",
             feeRate: 20,
             fieldName: 'machine',
@@ -56,7 +52,6 @@ let defaultBillTemplate = {
             code: "2",
             name: "企业管理费",
             dispExpr: "F1",
-            expression: "@('1')",
             statement: "定额直接费",
             feeRate: null,
             fieldName: 'manage',
@@ -67,7 +62,6 @@ let defaultBillTemplate = {
             code: "3",
             name: "利润",
             dispExpr: "F1",
-            expression: "@('1')",
             statement: "定额直接费",
             feeRate: null,
             fieldName: 'profit',
@@ -78,7 +72,6 @@ let defaultBillTemplate = {
             code: "4",
             name: "风险费用",
             dispExpr: "F1",
-            expression: "@('1')",
             statement: "定额直接费",
             feeRate: null,
             fieldName: 'risk',
@@ -89,7 +82,6 @@ let defaultBillTemplate = {
             code: "5",
             name: "综合单价",
             dispExpr: "F1+F5+F6+F7",
-            expression: "@('1')+@('5')+@('6')+@('7')",
             statement: "定额直接费+企业管理费+利润+风险费用",
             feeRate: null,
             fieldName: 'common',
@@ -702,14 +694,13 @@ const rationCalcBases = {
 };
 
 let analyzer = {
-    calcTemplate: null,
-
     standard: function(expr){
         let str = expr;
         str = str.replace(/\s/g, "");               // 去空格、去中文空格
         str = str.replace(/(/g, "(");              // 中文括号"("换成英文括号"("
         str = str.replace(/)/g, ")");              // 中文括号")"换成英文括号")"
         str = str.replace(/f/g, "F");               // f换成F
+        str = str.replace(/l/g, "L");               // l换成L
         return str;
     },
     getFArr: function (expr) {
@@ -722,41 +713,38 @@ let analyzer = {
         let arr = expr.match(patt);
         return arr ? arr : [];
     },
-    getFID: function (FName) {          // F3、F22
-        let me = this;
+    getBaseArr: function (expr) {
+        let pattBase = new RegExp(/\[[\u4E00-\u9FA5]+\]/gi);
+        let arrBase = expr.match(pattBase);
+        return arrBase ? arrBase : [];
+    },
+
+    getFID: function (FName, calcTemplate) {          // F3、F22 → 4、99
         let idx = FName.slice(1) - 1;
-        let id = me.calcTemplate.calcItems[idx] ? me.calcTemplate.calcItems[idx].ID : null;
+        let id = calcTemplate.calcItems[idx] ? calcTemplate.calcItems[idx].ID : null;
         return id;
     },
-    getFItem: function (FName){
-        let me = this;
+    getFItem: function (FName, calcTemplate){      // F3 → calcItems[2] → {Object}
         let idx = FName.slice(1) - 1;
-        return me.calcTemplate.calcItems[idx];
+        return calcTemplate.calcItems[idx];
     },
-    isCycleCalc: function (expr) {     // @5+@6  这里已经是ID引用
-        let me = this;
-        
-        function isCycle(nodeExpr) {
-            let atIDArr = me.getAtIDArr(nodeExpr);
-            for (let atID of atIDArr){
-                let ID = atID.slice(1);
-                let item = me.calcTemplate.compiledCalcItems[ID];
-                if (item.expression.includes(atID)) {
-                    return true;
-                }
-                else {
-                    isCycle(item.expression);
-                }
-            };
-            return false;
-        };
+    isCycleCalc: function (expression, ID, template) {     // 这里判断expression,是ID引用: @5+@6
+        if (expression.includes(`@${ID}`))
+            return true;
 
-        return isCycle(expr);
-    },
-    isLegal: function (expr) {   // 调用前必须先标准化
-        let me = this;
+        let atIDs = analyzer.getAtIDArr(expression);
+        for (let atID of atIDs) {
+            let item = template.compiledCalcItems[atID.slice(1)];
+            if (analyzer.isCycleCalc(item.expression, ID, template))
+                return true;
+        }
 
-        let invalidChars = /[^0-9\u4e00-\u9fa5\+\-\*\/\(\)\.\[\]F%]/g;
+        return false;
+    },
+    isLegal: function (dispExpr, itemID, calcTemplate) {  // 检测包括:无效字符、基数是否中括号、基数是否定义、行引用、循环计算
+        let me = analyzer;
+        let expr = me.standard(dispExpr);
+        let invalidChars = /[^0-9\u4e00-\u9fa5\+\-\*\/\(\)\.\[\]FL%]/g;
         if (invalidChars.test(expr)){
             alert('表达式中含有无效的字符!');
             return false;
@@ -766,7 +754,11 @@ let analyzer = {
         let arrCn = expr.match(pattCn);
         let pattBase = new RegExp(/\[[\u4E00-\u9FA5]+\]/gi);
         let arrBase = expr.match(pattBase);
-        if (arrCn.length != arrBase.length){
+        if (arrCn && !arrBase){
+            alert('定额基数必须用中括号[]括起来!');
+            return false;
+        };
+        if (arrCn && arrBase && (arrCn.length != arrBase.length)){
             for (let cn of arrCn){
                 let tempBase = `[${cn}]`;
                   if (!arrBase.includes(tempBase)){
@@ -778,47 +770,76 @@ let analyzer = {
             alert('定额基数必须用中括号[]括起来!');
             return false;
         };
-
-        for (let base of arrBase){
-            let baseName = base.slice(1, -1);
-            if (!rationCalcBases[baseName]){
-                alert('定额基数 [' + baseName + '] 末定义!');
-                return false;
-            }
+        if (arrBase){
+            for (let base of arrBase){
+                let baseName = base.slice(1, -1);
+                if (!rationCalcBases[baseName]){
+                    alert('定额基数 [' + baseName + '] 末定义!');
+                    return false;
+                }
+            };
         };
 
-        // 行引用检测、行引用转ID引用
         let arrF = me.getFArr(expr);
         for (let F of arrF){
             let num = F.slice(1);
-            if (num > me.calcTemplate.calcItems.length){
+            if (num > calcTemplate.calcItems.length){
                 alert('表达式中 “F'+ num +'” 行号引用错误!');
                 return false;
             };
-            let id = me.getFID(F);
-            let fn = new RegExp(F, "g");
-            expr = expr.replace(fn, `@('${id}')`);
         };
 
-        // 循环计算
-        if (me.isCycleCalc(expr)){
+        let expression = me.getExpression(expr, calcTemplate);
+        if (me.isCycleCalc(expression, itemID, calcTemplate)){
             alert('表达式中有循环计算!');
             return false;
         }
 
-        return true;
+        return true;  // 表达式合法
     },
-    analyzeUserExpr: function(calcTemplate, calcItem){
-        let me = this;
-        me.calcTemplate = calcTemplate;
-        let expr = calcItem.dispExpr;
-        expr = me.standard(expr);
-        calcItem.dispExpr = expr;
-        if (me.isLegal(expr)){
-            calcItem.expression = expr;
-            return true;
-        }else
-            return false;
+    getExpression: function (dispExpr, calcTemplate) {
+        function refLineToID(expr, template) {
+            let rst = expr;
+            let fArr = me.getFArr(rst);
+            let IDArr = [];
+            for (let F of fArr){
+                let ID = me.getFID(F, template);
+                IDArr.push(ID);
+            };
+            for (let i = 0; i < fArr.length; i++) {
+                let patt = new RegExp(fArr[i]);
+                let val = `@${IDArr[i]}`;
+                rst = rst.replace(patt, val);
+            };
+            return rst;
+        };
+
+        let me = analyzer;
+        let expr = me.standard(dispExpr);
+        return refLineToID(expr, calcTemplate);
+    },
+    getDispExprUser: function (dispExpr, labourCoe) {   // labourCoe 是 str 类型
+        let me = analyzer;
+        let expr = me.standard(dispExpr);
+        expr = expr.replace(/L/g, labourCoe);
+        return expr;
+    },
+    getCompiledExpr: function (expression, labourCoe) {   // labourCoe 是 str 类型
+        let me = analyzer;
+        let rst = expression;
+        let atIDArr = me.getAtIDArr(rst);
+        let IDArr = atIDArr.map(function (atID) {
+            return atID.slice(1);
+        });
+        for (var i = 0; i < atIDArr.length; i++) {
+            let patt = new RegExp(atIDArr[i]);
+            let val = `$CE.at(${IDArr[i]})`;
+            rst = rst.replace(patt, val);
+        };
+        rst = rst.replace(/\[/g, "$CE.base('");
+        rst = rst.replace(/\]/g, "')");
+        rst = rst.replace(/L/g, labourCoe);
+        return rst;
     }
 };
 
@@ -950,7 +971,7 @@ class CalcProgram {
         template.hasCompiled = false;
         template.errs = [];
 
-        let private_extract_ID = function(str, idx){
+        /*let private_extract_ID = function(str, idx){
             let rst = '', lBracket = 0, rBracket = 0, firstIdx = idx, lastIdx = 0;
             for (let i = idx; i < str.length; i++) {
                 if (str[i] === '(') {
@@ -973,8 +994,8 @@ class CalcProgram {
                 }
             }
             return rst;
-        };
-        let private_parse_ref = function(item, itemIdx){
+        };*/
+        /*let private_parse_ref = function(item, itemIdx){
             let idx = item.expression.indexOf('@(', 0);
             while (idx >= 0) {
                 let ID = private_extract_ID(item.expression, idx);
@@ -996,28 +1017,55 @@ class CalcProgram {
             if (template.compiledSeq.indexOf(itemIdx) < 0) {
                 template.compiledSeq.push(itemIdx);
             }
+        };*/
+        let private_extract_ID = function(str, idx){
+            let subStr = str.slice(idx);
+            let patt = new RegExp(/@\d+/);
+            let atID = subStr.match(patt);
+            let ID = atID ? atID[0].slice(1) : null;
+            return ID;
+        };
+        let private_parse_ref = function(item, itemIdx){
+            let idx = item.expression.indexOf('@', 0);
+            while (idx >= 0) {
+                let ID = private_extract_ID(item.expression, idx);
+                let len = ID ? ID.toString().length : 0;
+                if (len) {
+                    let subItem = template.compiledCalcItems[ID];
+                    if (subItem) {
+                        if (subItem.ID !== item.ID) {
+                            private_parse_ref(subItem, template.compiledCalcItems[ID + "_idx"]);
+                        } else {
+                            template.errs.push("循环引用ID: " + ID);
+                        }
+                    } else {
+                        template.errs.push("找不到ID: " + ID);
+                        console.log('找不到ID: ' + ID);
+                    }
+                }
+                idx = item.expression.indexOf('@', idx + len + 1);
+            }
+            if (template.compiledSeq.indexOf(itemIdx) < 0) {
+                template.compiledSeq.push(itemIdx);
+            }
         };
         let private_compile_items = function() {
             for (let idx of template.compiledSeq) {
                 let item = template.calcItems[idx];
-                item.dispExprUser = item.dispExpr;    // 用于界面显示。disExpr是公式模板,不允许修改:人工系数占位符被修改后变成数值,第二次无法正确替换。
+
+                let lc = 0;
+                if (item.labourCoeID) lc = me.compiledLabourCoes[item.labourCoeID].coe.toString();
+                // 用于界面显示。disExpr是公式模板,不允许修改:人工系数占位符被修改后变成数值,第二次无法正确替换。
+                item.dispExprUser = analyzer.getDispExprUser(item.dispExpr, lc);
                 if (item.expression == 'HJ')
                     item.compiledExpr = '$CE.HJ()'
-                else{
-                    item.compiledExpr = item.expression.split('@(').join('$CE.at(');
-                    item.compiledExpr = item.compiledExpr.split('base(').join('$CE.base(');
-                };
-
-                if (item.labourCoeID){
-                    let lc = me.compiledLabourCoes[item.labourCoeID].coe;
-                    item.dispExprUser = item.dispExpr.replace(/L/gi, lc.toString());
-                    item.compiledExpr = item.compiledExpr.replace(/L/gi, lc.toString());
-                };
+                else
+                    item.compiledExpr = analyzer.getCompiledExpr(item.expression, lc);
 
                 if (item.feeRateID) {
                     let orgFeeRate = item.feeRate;
-                    let cmf = me.compiledFeeRates[item.feeRateID];
-                    item.feeRate = cmf?cmf.rate:100;
+                    let cfr = me.compiledFeeRates[item.feeRateID];
+                    item.feeRate = cfr ? cfr.rate : 100;
 
                     if (!orgFeeRate || (orgFeeRate && orgFeeRate != item.feeRate)){
                         me.saveForReports.push({templatesID: template.ID, calcItem: item});
@@ -1035,6 +1083,7 @@ class CalcProgram {
 
             for (let i = 0; i < template.calcItems.length; i++) {
                 let item = template.calcItems[i];
+                item.expression = analyzer.getExpression(item.dispExpr, template);
                 template.compiledCalcItems[item.ID] = item;
                 template.compiledCalcItems[item.ID + "_idx"] = i;
             }
@@ -1379,7 +1428,8 @@ class CalcProgram {
     /* 计算所有树结点(分3种情况),并返回发生变动的零散的多个树结点。参数取值如下:
         calcAllType.catAll       计算所有树结点 (不指定参数时的默认值)
         calcAllType.catBills     计算所有清单 (改变项目属性中清单取费算法时会用到)
-        calcAllType.catRations   计算所有定额、工料机形式的定额、量价,因为它们都走自己的计算程序 (改变人工系数、费率值、工料机单价时会用到)
+        calcAllType.catRations   计算所有定额、工料机形式的定额、量价,因为它们都走自己的计算程序 (改变人工系数、费率值、工料机单价时会用到)  不要用
+        缺陷:calcAllType.catRations 参数情况不会计算父结点。(calcAllType.catBills 可以,因为清单的父结点也是清单会计算)
     */
     calcAllNodes(calcType = calcAllType.catAll){
         let me = this;
@@ -1514,4 +1564,6 @@ class CalcProgram {
         baseNodes.push(calcTools.getNodeByFlag(fixedFlag.CHARGE));
         return me.getTotalFee(baseNodes, excludeNodes);
     };
-};
+};
+
+// export default analyzer;

+ 40 - 27
web/building_saas/main/js/models/fee_rate.js

@@ -144,11 +144,12 @@ var FeeRate = {
             var errCallBack=function () {
                 me.dataRecovery();
                 $.bootstrapLoading.end();
-            }
+            };
+            $.bootstrapLoading.start();
             CommonAjax.post('/feeRates/updateRates', data, function (result) {
                 _.forEach(items,function (t) {
-                     feeRateObject.mainViews.data.updateItem(t.rateIndex,t.rate);
-                 })
+                    feeRateObject.mainFeeRateSheet.setValue(t.rateIndex, 1, t.rate.rate);
+                 });
                  me.onFeeRateFileChange();
                 $.bootstrapLoading.end();
             },errCallBack);
@@ -191,7 +192,7 @@ var FeeRate = {
                     calcProgramObj.showData(node);
                 }
             }
-            project.calcProgram.calcAllNodesAndSave(calcAllType.catBills);
+            project.calcProgram.calcAllNodesAndSave(calcAllType.catAll);
             project.markUpdateProject({projectID:project.ID(),feeRateID:this.getActivateFeeRateFileID()},"feeRate");
             socket.emit('feeRateChangeNotify', this.getActivateFeeRateFileID());
         };
@@ -204,10 +205,11 @@ var FeeRate = {
                     calcProgramObj.showData(node);
                 }
             }
-            project.calcProgram.calcAllNodesAndSave(calcAllType.catBills);
+            project.calcProgram.calcAllNodesAndSave(calcAllType.catAll);
             if(socketObject.roomInfo){
                 //判断费率文件ID是否改变了
                 if(socketObject.roomInfo.feeRate == this.getActivateFeeRateFileID()){//如果没变,则是重选了标准
+                    project.markUpdateProject({projectID:project.ID(),feeRateID:this.getActivateFeeRateFileID()},"feeRate");
                     socket.emit('feeRateChangeNotify', socketObject.roomInfo.feeRate);
                 }else {
                     let data ={
@@ -215,7 +217,7 @@ var FeeRate = {
                         oldRoom:socketObject.roomInfo.feeRate,
                         newRoom:this.getActivateFeeRateFileID(),
                         name:'feeRate'
-                    }
+                    };
                     socket.emit('changeNewRoom',data);
                     socketObject.roomInfo.feeRate = this.getActivateFeeRateFileID();
                 }
@@ -273,14 +275,14 @@ var FeeRate = {
             calcProgramManage.refreshDetailSheet();
         };
         FeeRate.prototype.refreshBillsByRateID=function(rateID,value){
-            var nodes = _.filter(projectObj.project.mainTree.items,function (n) {
+            let nodes = _.filter(projectObj.project.mainTree.items,function (n) {
                 if(n.sourceType==ModuleNames.bills&&n.data.feeRateID==rateID){
                     n.data.feeRate=number_util.roundToString(value,getDecimal("feeRate"));
                     return true;
                 }else {
                     return false;
                 }
-            })
+            });
             if(nodes.length>0){
                 projectObj.mainController.refreshTreeNode(nodes)
             }
@@ -370,10 +372,7 @@ var FeeRate = {
                         if(data.hasOwnProperty('feeRate')){
                             rate.rate=fee_value;
                             me.onFeeRateChange(rate.ID,fee_value);
-                        }/*else {
-                            bill.feeRate=value;
-                            projectObj.mainController.refreshTreeNode([node])
-                        }*/
+                        }
                     });
                 }else {
                     projectObj.mainController.refreshTreeNode([node]);
@@ -385,7 +384,7 @@ var FeeRate = {
             var value= number_util.checkNumberValue(value,getDecimal("feeRate"));
             if(value){
                 if(editInfo.calcItem.feeRateID){
-                    var rate = projectObj.project.FeeRate.getFeeRateByID(editInfo.calcItem.feeRateID);
+                    var rate = this.getFeeRateByID(editInfo.calcItem.feeRateID);
                     if(rate!=undefined){
                         this.updateFeeRateByCalc(rate,value);
                         return;
@@ -407,20 +406,34 @@ var FeeRate = {
         };
         FeeRate.prototype.updateFeeRateByCalc=function (rate,value) {
             var me=this;
-            var data={
-                query:{
-                    'ID':this.getActivateFeeRateID(),
-                    'rates.ID':rate.ID
-                },
-                doc:{
-                    'rates.$.rate':value
-                }
-            }
-            CommonAjax.post('/feeRates/updateFeeRate', data, function (data) {
-                rate.rate=value;
+            me.updateFeeRateByID(rate.ID,{'rate':value},function () {
                 me.onFeeRateChange(rate.ID,value);
-            });
-        }
+            })
+        };
+
+        FeeRate.prototype.updateFeeRateByID = function (rateID,doc,callback) {
+          let me = this,preKey = 'rates.$.';
+          let data = {
+              query:{
+                  'ID':me.getActivateFeeRateID(),
+                  'rates.ID':rateID
+              },
+              doc:{}
+          };
+          for(let prop in doc){//做了个转换,加上前缀
+            data.doc[preKey+prop] = doc[prop];
+          }
+          CommonAjax.post('/feeRates/updateFeeRate', data, function (data) {
+              //更新缓存
+              let rate = me.getFeeRateByID(rateID);
+              for(let dkey in doc){
+                  rate[dkey] = doc[dkey];
+              }
+            if(callback){
+                callback();
+            }
+          });
+        };
 
         FeeRate.prototype.getfbUpdateData=function (rate,bill,value,editText) {
             var data=null;
@@ -486,7 +499,7 @@ var FeeRate = {
                             feeRateID:rate.ID
                         }
                     }
-                }
+                };
             this.setFeeRateToBill(data,callback);
         };
 

+ 17 - 8
web/building_saas/main/js/models/installation_fee.js

@@ -179,7 +179,7 @@ var installation_fee = {
             };
             return updateData;
         };
-        installation_fee.prototype.submitInstallationUpdate = function (updateData,rationInstallations,callback) {
+       installation_fee.prototype.submitInstallationUpdate = function (updateData,rationInstallations,callback) {
             if(updateData){
                 let data = {'projectID':projectInfoObj.projectInfo.ID,'updateData':updateData};
                 if(rationInstallations){//是否附带更新定额安装费
@@ -201,7 +201,7 @@ var installation_fee = {
                 })
             }
         };
-        installation_fee.prototype.calcInstallationFee=function(callback){
+       installation_fee.prototype.calcInstallationFee=function(callback){
             let project = projectObj.project,me = this;
             let engineering = projectInfoObj.projectInfo.property.engineering;
             let installSetting = projectInfoObj.projectInfo.property.installSetting;
@@ -302,12 +302,13 @@ var installation_fee = {
                         glj.quantity = ur.quantity;
                         glj.rationItemQuantity = ur.rationItemQuantity;
                     }
-
+                    let selectedNode = projectObj.project.mainTree.selected;
                     //对树节点的操作并删除、添加清单、删除添加定额、删除对应的定额工料机缓存
                     TREE_SHEET_HELPER.massOperationSheet(projectObj.mainController.sheet, function () {
                         deleteOldNodes(deleteRationNodes,deleteBillsNodes);
                         addNewNodes(updateData);
                     });
+                    setTreeSelection(selectedNode);
                     projectObj.project.projectGLJ.loadData(function () {
                         cbTools.refreshFormulaNodes();
                         if(callback){
@@ -363,11 +364,19 @@ var installation_fee = {
                     Bill.tree.delete(bd.source);
                     Bill.removeByID(bd.getID());
                 }
-                let sels = controller.sheet.getSelections();
-                controller.setTreeSelected(controller.tree.items[sels[0].row]);
             }
 
-            
+            function setTreeSelection(oldSelect) {
+                let controller = projectObj.mainController;
+                let sel = controller.sheet.getSelections()[0];
+                if(controller.tree.getNodeByID(oldSelect.getID())){//如果旧选中节点还存在
+                    controller.sheet.setSelection(oldSelect.serialNo(),sel.col,sel.rowCount,sel.colCount);
+                    controller.setTreeSelected(oldSelect)
+                }else {//选中节点已被删除,自动选中新的节点
+                    controller.setTreeSelected(controller.tree.items[sel.row]);
+                }
+            }
+
             function checkRation(oldRation,newRation) {//检查定额是否需要更新
                 let gljs = project.ration_glj.getGljByRationID(oldRation.ID);
                 let modify = false;
@@ -633,7 +642,7 @@ var installation_fee = {
                     'JXFTZ':{
                         rationID:data.ID,
                         billsItemID:data.billsItemID,
-                        shortName:project.projectGLJ.getShortNameByID(gljType.MACHINE_COMPOSITION),
+                        shortName:project.projectGLJ.getShortNameByID(gljType.GENERAL_MACHINE),
                         GLJID:-1,
                         projectID:data.projectID,
                         code:'JXFTZ',
@@ -641,7 +650,7 @@ var installation_fee = {
                         name:'机械费调整',
                         specs:'',
                         unit:'元',
-                        type:gljType.MACHINE_COMPOSITION,
+                        type:gljType.GENERAL_MACHINE,
                         basePrice:1,
                         adjCoe:null,
                         from:'std',

+ 0 - 1
web/building_saas/main/js/models/project.js

@@ -321,7 +321,6 @@ var PROJECT = {
         project.prototype.projectMarkChecking = function () {
             let  changeMark = projectInfoObj.projectInfo.changeMark;
             if(changeMark&&changeMark!=''){
-                $.bootstrapLoading.start();
                 this.Bills.getEngineeringCostNode(projectObj.mainController).changed = true;
                 this.calcProgram.calcAllNodesAndSave();
                 CommonAjax.post("/project/removeProjectMark",{projectID:this.ID()},function (data) {

+ 65 - 3
web/building_saas/main/js/models/project_glj.js

@@ -270,7 +270,7 @@ ProjectGLJ.prototype.updatePrice = function (recode, updateField, newval,from,cb
             }
             //更新回传的父节点项目工料机价格
            let gljs = me.getProjectGLJs(data);
-            me.refreshRationGLJPrice(glj);//刷新定额工料机列表的记录
+          //  me.refreshRationGLJPrice(glj);//刷新定额工料机列表的记录
             projectObj.project.projectGLJ.loadCacheData();//更新工料机汇总缓存和显示
             gljOprObj.showRationGLJSheetData();
             me.refreshTreeNodePriceIfNeed(glj);//刷新造价书中主树上的定额工料机;
@@ -293,6 +293,66 @@ ProjectGLJ.prototype.updatePrice = function (recode, updateField, newval,from,cb
     }
 };
 
+ProjectGLJ.prototype.batchUpdatePrice = function (changeInfo,callback) {
+    let me = this;
+    let projectGljs = me.datas.gljList;
+    let decimal = getDecimal('glj.unitPrice');
+    let updateData = [];
+    let newValueMap = {};
+    let gljs=[];
+    for(let ci of changeInfo){
+        let dataCode = projectGljObject.projectGljSetting.header[ci.col].dataCode;
+        let recode = projectGljObject.projectGljSheetData[ci.row];
+        if(dataCode=='basePrice'||dataCode=='marketPrice'){
+            let editField = dataCode === 'basePrice'?"base_price":"market_price";
+            let newValue= scMathUtil.roundForObj(ci.value,decimal);
+            let glj = _.find(projectGljs, {'id': recode.id});
+            if(glj&&glj.unit_price[editField]!=newValue){
+                updateData.push({unit_price: glj.unit_price, field: editField, newval: newValue,project_id:glj.project_id});
+                newValueMap[glj.id]={field:editField,value:newValue};
+                gljs.push(glj);
+            }
+        }
+    }
+    console.log(updateData);
+    if(updateData.length > 0){
+        $.bootstrapLoading.start();
+        CommonAjax.post("/glj/batchUpdatePrices", updateData, function (result) {
+            let parentData = [];
+            //更新缓存
+            for(let g of gljs){
+                g.unit_price[newValueMap[g.id].field] = newValueMap[g.id].value;
+                me.refreshTreeNodePriceIfNeed(g);//刷新造价书中主树上的定额工料机;
+            }
+            //更新父工料机价格
+            for(let r of result){
+                let pdata = r.updateOne.filter;
+                let set = r.updateOne.update.$set;
+                for(let skey in set){
+                    pdata[skey] = set[skey];
+                }
+                parentData.push(pdata);
+            }
+            let pgljs = me.getProjectGLJs(parentData);
+            gljs = gljs.concat(pgljs);
+            let nodes = me.getImpactRationNodes(gljs);//取到因为改变工料机价格而受影响的定额
+            projectObj.project.calcProgram.calcRationsAndSave(nodes);//触发计算程序
+            gljOprObj.showRationGLJSheetData();
+            socket.emit('unitFileChangeNotify', JSON.stringify(gljs));
+            projectObj.project.markUpdateProject({projectID:projectObj.project.ID(),'unitFileID':socketObject.getUnitFileRoomID()},"unitFile");
+            if(callback){
+                callback(gljs);
+            }
+            $.bootstrapLoading.end();
+        }, function (err) {
+            $.bootstrapLoading.end();
+        });
+    }
+
+
+};
+
+
 ProjectGLJ.prototype.pGljUpdate= function (data,callback) {
     let me = this;
     $.bootstrapLoading.start();
@@ -323,6 +383,8 @@ ProjectGLJ.prototype.getRatioData=function(id,callback){
             if(callback){
                 callback(ratios);
             }
+        },function () {//取不到组成物的情况
+            callback([]);
         })
     }else {
         if(callback){
@@ -474,8 +536,8 @@ ProjectGLJ.prototype.getProjectGLJs = function (data,refreshPrice=true) {
             let glj = _.find(projectGljs, condition);
             if (glj) {
                 if(refreshPrice==true){
-                    glj.unit_price.base_price = d.base_price;
-                    glj.unit_price.market_price = d.market_price;
+                    d.base_price?glj.unit_price.base_price = d.base_price:'';
+                    d.market_price?glj.unit_price.market_price = d.market_price:'';
                     this.setAdjustPrice(glj);
                     this.refreshRationGLJPrice(glj);
                     this.refreshTreeNodePriceIfNeed(glj);

+ 6 - 2
web/building_saas/main/js/models/ration.js

@@ -374,18 +374,22 @@ var Ration = {
             }
         };
         ration.prototype.updateRationCodes = function (recodes) {
-            let libID = projectInfoObj.projectInfo.engineeringInfo.ration_lib[0].id;
+            let libID =  rationLibObj.getCurrentStdRationLibID();
             let engineering = projectInfoObj.projectInfo.property.engineering;
             let projectID = projectInfoObj.projectInfo.ID;
             let project = projectObj.project;
             let mainTree = project.mainTree;
             let nodeInfo =[];
             let refershNodes = [];
+            if(libID == null){
+                return;
+            }
             for(let r of recodes){
                 let needInstall = false;
                 if(engineering==engineeringType.BUILD_IN) {//如果是安装工程,要看需不需要生成安装增加费
                     needInstall = project.Bills.isFBFX(r.node);
                 }
+                r.value = r.value.replace(/[\s\r\n]/g, "");//去掉空格回车换行等字符
                 nodeInfo.push({ID:r.node.data.ID,billsItemID:r.node.data.billsItemID,newCode:r.value,needInstall:needInstall});
                 refershNodes.push(r.node);
             }
@@ -503,7 +507,7 @@ var Ration = {
             projectObj.project.ration_glj.deleteByRation(ration);
             projectObj.project.ration_coe.deleteByRation(ration);
             projectObj.project.quantity_detail.deleteByRation(ration);
-            //to do 删除安装增加费
+            projectObj.project.ration_installation.deleteByRation(ration);
         };
         ration.prototype.replaceRation = function (ration, std) {
             this.project.beginUpdate('replaceRation');

+ 50 - 9
web/building_saas/main/js/views/calc_base_view.js

@@ -114,7 +114,11 @@ let calcBaseView = {
             if(!me.isDef(v)){
                 return;
             }
-            let baseFigure = `{${v}}`;
+            let baseFigure = '';
+            if(me.curType == me.type.bills)
+                baseFigure = `{${v}}`
+            else if (me.curType == me.type.ration)
+                baseFigure = `[${v}]`;
             if(baseFigure.trim() !== ''){
                 //在光标后面插入
                 let insertStr = me.insertStr(baseFigure);
@@ -161,7 +165,7 @@ let calcBaseView = {
         let me = calcBaseView;
         let showDatas;
         me.curType = type;
-        if(type === me.type.bills){//bills
+        if (type === me.type.bills) {
             //显示清单基数分类
             $('#cbClassList').show();
             $('#qd-jsjs .modal-content').css('width', '670px');
@@ -170,7 +174,7 @@ let calcBaseView = {
             //
             let node = projectObj.project.mainTree.selected;
             //输入框显示原本的
-            if(me.isDef(node.data.calcBase)){
+            if (me.isDef(node.data.calcBase)) {
                 me.inputExpr.val(cbParser.toFExpr(node.data.calcBase));
             }
             let baseObj = projectObj.project.calcBase.getBaseByClass(node);
@@ -178,24 +182,28 @@ let calcBaseView = {
             $('#cbClassList li .btn ').removeClass('btn btn-outline-secondary btn-sm active');
             $('#cb_ALL').addClass('btn btn-outline-secondary btn-sm active');
         }
-        else{//ration
+        else if (type == me.type.ration) {
             //去除清单基数分类
             $('#cbClassList').hide();
             $('#qd-jsjs .modal-content').css('width', '');
             $('#cbRowDiv').removeClass('row');
             $('#billsBaseSpread').removeClass('col-9');
 
+            let calcItem = calcProgramManage.getSelectionInfo().calcItem;
+            if (calcItem.dispExprUser) {
+                me.inputExpr.val(calcItem.dispExpr);
+            }
             let bnArr = Object.keys(rationCalcBases);
             let baseArr = [];
-            for (let bn of bnArr){
-                 baseArr.push({base: bn})
+            for (let bn of bnArr) {
+                baseArr.push({base: bn})
             };
             showDatas = baseArr;
         }
+
         me.buildSheet();
         me.showData(showDatas);
         $('#qd-jsjs').modal('show');
-
     },
 
     getInputExpr: function () {
@@ -262,9 +270,42 @@ let calcBaseView = {
                     $('#qd-jsjs').modal('hide');
                 }
             }
-            //ration
-            else{
+            else if (me.curType === me.type.ration) {
+                let expr = me.inputExpr.val();
+                expr = analyzer.standard(expr);
+                me.inputExpr.val(expr);
 
+                let template = calcProgramManage.getSelectionInfo().template;
+                let calcItem = calcProgramManage.getSelectionInfo().calcItem;
+
+                if (calcItem.dispExpr != expr){
+                    if (analyzer.isLegal(expr, calcItem.ID, template)){
+                        let cp = projectObj.project.calcProgram;
+                        let lc = 0;
+                        if (calcItem.labourCoeID)
+                            lc = cp.compiledLabourCoes[calcItem.labourCoeID].coe.toString();
+                        calcItem.dispExpr = expr;
+                        calcItem.dispExprUser = analyzer.getDispExprUser(expr, lc);
+                        calcItem.expression = analyzer.getExpression(expr, template);
+                        calcItem.compiledExpr = analyzer.getCompiledExpr(calcItem.expression, lc);
+
+                        let data = {
+                            'projectID': projectObj.project.ID(),
+                            'templatesID': template.ID,
+                            'calcItem': calcItem
+                        };
+                        calcProgramManage.saveCalcItem(data, function (rst) {
+                            if (rst){
+                                cp.compileTemplate(template);
+                                cp.calcAllNodesAndSave();
+                                calcProgramManage.refreshDetailSheet();
+                                $('#qd-jsjs').modal('hide');
+                            }
+                        });
+                    };
+                }
+                else
+                    $('#qd-jsjs').modal('hide');
             }
         });
     },

+ 23 - 7
web/building_saas/main/js/views/calc_program_manage.js

@@ -60,14 +60,15 @@ let calcProgramManage = {
 
         me.mainSpread.getSheet(0).bind(GC.Spread.Sheets.Events.EnterCell, me.onMainEnterCell);
         me.detailSpread.getSheet(0).bind(GC.Spread.Sheets.Events.CellChanged, me.onDetailCellChanged);
-        me.detailSpread.getSheet(0).bind(GC.Spread.Sheets.Events.EditEnded, me.onEditEnded);
+        me.detailSpread.getSheet(0).bind(GC.Spread.Sheets.Events.EditEnded, me.onDetailEditEnded);
+        me.detailSpread.getSheet(0).bind(GC.Spread.Sheets.Events.EnterCell, me.onEnterCell);
         let mSheet = me.mainSpread.getSheet(0);
         sheetCommonObj.showData(mSheet, me.mainSetting, me.datas);
 
         let dSheet = me.detailSpread.getSheet(0);
+        dSheet.name('calc_detail');
         feeRateObject.setFeeRateCellCol(dSheet,_.findIndex(me.detailSetting.header,{'dataCode':'feeRate'}));
         dSheet.getRange(-1, _.findIndex(me.detailSetting.header, {'dataCode': 'dispExprUser'}), -1, 1).cellType(calcBaseView.getCalcBaseCellType('ration'));
-        dSheet.name('calc_detail');
         sheetCommonObj.showData(dSheet, me.detailSetting, me.datas[0].calcItems);
     },
     onMainEnterCell: function(sender, args) {
@@ -81,21 +82,25 @@ let calcProgramManage = {
         sheetCommonObj.showData(dSheet, me.detailSetting, dData);
         me.detailSpread.resumePaint();
     },
-    onEditEnded: function(sender, args) {
+    onDetailEditEnded: function(sender, args) {
         $.bootstrapLoading.start();
 
         let me = calcProgramManage;
         let editInfo= me.getSelectionInfo();
-        if(me.detailSetting.header[args.col].dataCode == 'feeRate'){
+        if (me.detailSetting.header[args.col].dataCode == 'feeRate') {
             projectObj.project.FeeRate.updateFeeRateFromCalc(args.editingText,editInfo);
-        }else {
-            if(me.detailSetting.header[args.col].dataCode == 'displayFieldName'){
+        }
+        else {
+            if (me.detailSetting.header[args.col].dataCode == 'displayFieldName') {
                 if (editInfo.calcItem.displayFieldName == args.editingText) {
                     $.bootstrapLoading.end();
                     return;
                 }
                 editInfo.calcItem.fieldName = projectObj.project.calcProgram.compiledFeeTypeMaps[args.editingText];
                 editInfo.calcItem.displayFieldName = args.editingText;    // 这句不入库,仅用于切换后再切换回来时界面正确显示
+            }
+            else if (me.detailSetting.header[args.col].dataCode == 'dispExprUser'){  // 除非直接改单元格,弹窗不会走这里
+                alert(editInfo.calcItem.dispExprUser);
             };
 
             let data = {
@@ -110,6 +115,17 @@ let calcProgramManage = {
             });
         }
     },
+    onEnterCell: function (sender, args) {
+       /* let t = calcProgramManage.getSelectionInfo().template;
+        let c = calcProgramManage.getSelectionInfo().calcItem;
+        c.expression = analyzer.getExpression(c.dispExpr, t);
+        let lc = 0;
+        if (c.labourCoeID) lc = projectObj.project.calcProgram.compiledLabourCoes[c.labourCoeID].coe.toString();
+        c.compiledExpr = analyzer.getCompiledExpr(c.expression, lc);
+
+        let e = c.dispExpr + '  ' + c.expression + '  ' + c.compiledExpr;
+        projectObj.testDisplay('', e);*/
+    },
     saveCalcItem: function (data,callback) {//data
         let me = this;
         $.ajax({
@@ -142,7 +158,7 @@ let calcProgramManage = {
     },
     refreshDetailSheet:function () {
         var me=this;
-        if(me.mainSpread&&me.detailSpread){
+        if(me.mainSpread && me.detailSpread){
             var mainSheetIndex = me.mainSpread.getActiveSheet().getActiveRowIndex();
             sheetCommonObj.showData(me.detailSpread.getSheet(0), me.detailSetting,me.datas[mainSheetIndex].calcItems);
         }

+ 128 - 50
web/building_saas/main/js/views/fee_rate_view.js

@@ -5,6 +5,19 @@
 
 
 var feeRateObject={
+    mainFeeRateSpread:null,
+    mainFeeRateSheet:null,
+    mainFeeRateData:null,
+    mainFeeRateSetting:{
+        header: [
+            {headerName: "专业名称", headerWidth: 550, dataCode: "name", dataType: "String"},
+            {headerName: "值%", headerWidth: 250, dataCode: "rate", dataType: "Number",hAlign: "right",decimalField:"feeRate"},
+            {headerName: "备注", dataCode: "memo", dataType: "String"}
+        ],
+        view: {
+            lockColumns: [0]
+        }
+    },
     mainViews:null,
     datas:null,
     datasBackup:null,
@@ -19,7 +32,7 @@ var feeRateObject={
     sheetSetting: {
         header: [
             {headerName: "专业名称", headerWidth: 200, dataCode: "name", dataType: "String"},
-            {headerName: "值%", headerWidth: 150, dataCode: "rate", dataType: "Number",hAlign: "right",decimalField:"feeRate"},
+            {headerName: "值%", headerWidth: 120, dataCode: "rate", dataType: "Number",hAlign: "right",decimalField:"feeRate"},
             {headerName: "备注", dataCode: "memo", dataType: "String"}
         ],
         view: {
@@ -124,10 +137,7 @@ var feeRateObject={
         feeRateObject.feeRateSheet.bind(GC.Spread.Sheets.Events.CellClick,feeRateObject.onCellClick);
         feeRateObject.feeRateSheet.bind(GC.Spread.Sheets.Events.CellDoubleClick,feeRateObject.onCellDoubleClick);
     },
-    showSelectTree:function () {
-        var sheet= feeRateObject.feeRateSheet;
-        var setting=feeRateObject.sheetSetting;
-        var data = projectObj.project.FeeRate.getActivateFeeRate().rates;
+    showSelectTree:function (sheet,setting,data) {
         var ch = GC.Spread.Sheets.SheetArea.viewport;
         var groups=[];
         sheet.suspendPaint();
@@ -370,67 +380,132 @@ var feeRateObject={
         this.mainViews.invalidate();
         document.querySelector('#divFee').focus();
     },
+    initFeeRateSpread:function (rowCount) {
+        //初始化费用项表格
+        this.mainFeeRateSpread = sheetCommonObj.buildSheet($('#divFee')[0], this.mainFeeRateSetting,rowCount);
+        this.mainFeeRateSpread.options.scrollbarMaxAlign = true;
+        this.mainFeeRateSheet = this.mainFeeRateSpread.getSheet(0);
+        sheetCommonObj.lockCells(this.mainFeeRateSheet , this.mainFeeRateSetting);
+        this.mainFeeRateSheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onMainFeeRateSheetValueChange);
+        this.mainFeeRateSheet.bind(GC.Spread.Sheets.Events.SelectionChanged, this.onMainFeeRateSelectChanged);
+        this.mainFeeRateSheet.bind(GC.Spread.Sheets.Events.EditStarting, function (e,args) {
+            let me =feeRateObject, row = args.row;
+            let recode = me.mainFeeRateData[row];
+            let dataCode = me.mainFeeRateSetting.header[args.col].dataCode;
+            if(dataCode=="rate"&&me.getChildrenCount(recode.ID,me.mainFeeRateData)>0){//有子节点时不能编辑费率列
+                args.cancel = true;
+            }
+        });
+        this.mainFeeRateSheet.name('mainFeeRateSheet');
+    },
+    showMainFeeRateData:function () {
+        let me = this;
+        let selected = me.mainFeeRateSheet.getSelections()[0];
+        me.activateFeeRate = projectObj.project.FeeRate.getActivateFeeRate();
+        me.mainFeeRateData = projectObj.project.FeeRate.getActivateFeeRate().rates;
+        me.mainFeeRateSheet.setRowCount(0);
+        me.mainFeeRateSheet.setRowCount(me.mainFeeRateData.length);
+        me.showSelectTree(me.mainFeeRateSheet,me.mainFeeRateSetting,me.mainFeeRateData);
+        me.mainFeeRateSheet.setSelection(selected.row,selected.col,selected.rowCount,selected.colCount);
+    },
     reFreshRateViews:function() {
-        feeRateObject.createSpreadView();
+        //feeRateObject.createSpreadView();
+        feeRateObject.loadPageContent();
+        this.showMainFeeRateData();
+        if(subRateObject.subRateSpread){//如果子费率没有初始化过的话,不需要显示。
+            subRateObject.initSubRateSpread(this.mainFeeRateData[0]);
+        }
+    },
+    onMainFeeRateSheetValueChange:function (e,info) {
+        let me = feeRateObject,updateData = {},feeRate = projectObj.project.FeeRate;
+        let recode = me.mainFeeRateData[info.row];
+        let fieldID = me.mainFeeRateSetting.header[info.col].dataCode;
+        let value = info.newValue;
+        if(fieldID == 'rate'&&value != null){
+            eval('1+a');
+            if(number_util.isNumber(Number(value))){
+                value = scMathUtil.roundForObj(value,getDecimal("feeRate"));
+            }else {
+                alert('当前输入的数据类型不正确,请重新输入。');
+                me.mainFeeRateSheet.setValue(info.row, info.col, info.oldValue);
+                return;
+            }
+        }
+        if(recode[fieldID] == value){//没有改变
+            return;
+        }
+        updateData[fieldID] = value;
+        $.bootstrapLoading.start();
+         feeRate.updateFeeRateByID(recode.ID,updateData,function () {
+            if(fieldID == 'rate'){
+                feeRate.onFeeRateChange(recode.ID,value);
+            }
+            $.bootstrapLoading.end();
+        })
+    },
+
+    onMainFeeRateSelectChanged:function (e, info) {
+        let me = feeRateObject;
+        let row = info.newSelections[0].row;
+        if(row!=-1){
+            subRateObject.initSubRateSpread(me.mainFeeRateData[row]);
+        }
     },
     updateBySelect:function (rate,selectMap,mapID) {
-       var selected = this.mainViews.getSelections()[0];
+        let selected = this.mainFeeRateSheet.getSelections()[0];
         projectObj.project.FeeRate.backupDatas();
-       var item = this.datas[selected.sourceRow];
+        let item = this.mainFeeRateData[selected.row];
         item.rate = rate;
-        _.forEach(selectMap,function (value,key) {
-            var recode =  item.subFeeRate.recodes[key];
-            var optionList = recode.optionList;
-            _.forEach(optionList,function (o) {
-                if(o.value==value){
+        for(let key in selectMap){
+            let recode =  item.subFeeRate.recodes[key];
+            let optionList = recode.optionList;
+            for(let o of optionList){
+                if(o.value==selectMap[key]){
                     o.selected=true;
                 }else {
                     o.selected = false;
                 }
-            })
-        })
+            }
+        }
         if($('#cascadeSet').prop('checked')){
-            this.cascadeSetRates(item,selected.sourceRow,mapID,selectMap)
+            this.cascadeSetRates(item,selected.row,mapID,selectMap);
         }else {
-            this.mainViews.data.updateItem(selected.sourceRow,item);
+            projectObj.project.FeeRate.batchUpdateFeeRate([{rateIndex:selected.row,rate:item}],feeRateObject.activateFeeRate);
         }
-        //projectObj.project.FeeRate.synchronizeFeeRate();
-
-        //this.views.data.updateItem()
     },
     cascadeSetRates:function(selectedItem,sourceRow,mapID,selectMap){
-        var items=[];
+        let items=[];
         items.push({rateIndex:sourceRow,rate:selectedItem});
-        _.forEach(this.datas,function (recode,Index) {
+        _.forEach(this.mainFeeRateData,function (recode,Index) {
             if(Index!=sourceRow&&recode.subFeeRate){
-                var valueMaps = recode.subFeeRate.valueMaps;
-                var valueMap = _.find(valueMaps,{ID:mapID});
+                let valueMaps = recode.subFeeRate.valueMaps;
+                let valueMap = _.find(valueMaps,{ID:mapID});
                 if(valueMap){//选项完全一样的情况
                     if(valueMap.value==recode.rate){
                         return;
                     }else {
                         recode.rate = valueMap.value;
                         _.forEach(selectMap,function (value,key) {
-                            var tempRecode =  recode.subFeeRate.recodes[key];
-                            var optionList = tempRecode.optionList;
+                            let tempRecode =  recode.subFeeRate.recodes[key];
+                            let optionList = tempRecode.optionList;
                             _.forEach(optionList,function (o) {
                                 if(o.value==value){
-                                    o.selected=true;
+                                    o.selected = true;
                                 }else {
                                     o.selected = false;
                                 }
                             })
-                        })
+                        });
                         items.push({rateIndex:Index,rate:recode});
                     }
                 }else {//某条选项一样的情况
-                    var needUpdate = false;
-                    var selectList = mapID.split('-');
-                    var newList=[];
+                    let needUpdate = false;
+                    let selectList = mapID.split('-');
+                    let newList=[];
                     _.forEach(recode.subFeeRate.recodes,function (r) {
-                        var oList = r.optionList;
-                        var oldSelectIndex=0;
-                        var hasChange=false;
+                        let oList = r.optionList;
+                        let oldSelectIndex=0;
+                        let hasChange=false;
                         _.forEach(oList,function (o,key) {
                             if(o.selected){
                                 oldSelectIndex = key;
@@ -443,14 +518,14 @@ var feeRateObject={
                             }else {
                                 o.selected=false;
                             }
-                        })
+                        });
                         if(!hasChange){
                             oList[oldSelectIndex].selected=true;
                             newList.push(oList[oldSelectIndex].value)
                         }
-                    })
+                    });
                     if(needUpdate){
-                      var newValue =   _.find(valueMaps,{ID:newList.join("-")})//取出费率值并更新
+                      let newValue =   _.find(valueMaps,{ID:newList.join("-")})//取出费率值并更新
                         if(newValue){
                           if(recode.rate != newValue.value){
                               recode.rate = newValue.value
@@ -460,7 +535,7 @@ var feeRateObject={
                     }
                 }
             }
-        })
+        });
         projectObj.project.FeeRate.batchUpdateFeeRate(items,feeRateObject.activateFeeRate);
     },
     loadPageContent:function(){
@@ -493,10 +568,8 @@ var feeRateObject={
     changeFeeRateStandard:function(newVal){
         $.bootstrapLoading.start();
         var callback=function () {
-            feeRateObject.createSpreadView();
-            feeRateObject.loadPageContent();
-            projectObj.project.FeeRate.synchronizeFeeRate();
-            subRateObject.destorySpreadView();
+            feeRateObject.reFreshRateViews();
+            projectObj.project.FeeRate.onFeeRateFileChange();
             $.bootstrapLoading.end();
         };
         projectObj.project.FeeRate.changeFeeRateStandard(newVal,callback);
@@ -537,7 +610,7 @@ var feeRateObject={
                     feeRateObject.submitSaveAs(newName);
                 }
             }
-            projectObj.project.FeeRate.checkFeeRateName(newName,callback)
+            projectObj.project.FeeRate.checkFeeRateName(newName,callback);
         }else {
             feeRateObject.submitSaveAs(newName);
         }
@@ -595,8 +668,8 @@ var feeRateObject={
             name:name
         }
         var callback=function () {
-            feeRateObject.createSpreadView();
-            feeRateObject.loadPageContent();
+            //feeRateObject.createSpreadView();
+            feeRateObject.reFreshRateViews();
             projectObj.project.FeeRate.onFeeRateFileChange();
             $.bootstrapLoading.end();
         }
@@ -621,8 +694,7 @@ var feeRateObject={
     changeFeeRateFileConfirm:function(feeRateFileID,name){
         $.bootstrapLoading.start();
         var callback=function () {
-            feeRateObject.createSpreadView();
-            feeRateObject.loadPageContent();
+            feeRateObject.reFreshRateViews();
             projectObj.project.FeeRate.onFeeRateFileChange();
             $.bootstrapLoading.end();
         }
@@ -670,11 +742,13 @@ var feeRateObject={
         var data={'projectID': projectObj.project.ID(),'templatesID': calInfo.template.ID,'calcItem': calInfo.calcItem};
         $.bootstrapLoading.start();
         calcProgramManage.saveCalcItem(data,function (result) {
+            $.bootstrapLoading.end();
             calInfo.calcItem.feeRate=rate.rate;
             projectObj.project.calcProgram.compileAllTemps();
             projectObj.project.calcProgram.calcAllNodesAndSave();
             calcProgramManage.refreshDetailSheet();
             $("#fee_rate_tree").modal('hide');
+            $.bootstrapLoading.end();
         });
         console.log(calInfo);
     },
@@ -715,9 +789,13 @@ $(function(){
     );
 
     $('#tab_fee_rate').on('shown.bs.tab', function (e) {
+        let me = feeRateObject;
         $(e.relatedTarget.hash).removeClass('active');
-        feeRateObject.reFreshRateViews();
-        feeRateObject.loadPageContent();
+        if(me.mainFeeRateSpread == null){
+            me.initFeeRateSpread(0);
+        }
+        me.showMainFeeRateData();
+        me.loadPageContent();
     });
 
     $('#setNewFeeRate').bind('click', function () {
@@ -844,7 +922,7 @@ $(function(){
             feeRateObject.createSheet();
         }
         feeRateObject.feeRateSelection=null;
-        feeRateObject.showSelectTree();
+        feeRateObject.showSelectTree(feeRateObject.feeRateSheet,feeRateObject.sheetSetting,projectObj.project.FeeRate.getActivateFeeRate().rates);
     });
 
     $('#fee_rate_tree').on('hidden.bs.modal', function (e) {

+ 1 - 20
web/building_saas/main/js/views/glj_view.js

@@ -138,8 +138,6 @@ var gljOprObj = {
     },
     gljTreeSetting: {
         view: {
-            //addHoverDom: gljTypeTreeOprObj.addHoverDom,
-            //removeHoverDom: gljTypeTreeOprObj.removeHoverDom,
             expandSpeed: "",
             selectedMulti: false
         },
@@ -1103,23 +1101,6 @@ var gljOprObj = {
         installationFeeObj.rationInstallData = [];
         //this.detailData=[];
     },
-    /*   lockRationGLJCell:function(){
-     sheetCommonObj.lockCells(this.sheet,this.setting);
-     },
-     lockRationCoeCell:function () {
-     sheetCommonObj.lockCells(this.coeSheet,this.coeSetting);
-     /!*    if(this.coeSheetData){
-     for(var i =0;i<this.coeSheetData.length;i++){
-     if(this.coeSheetData[i].coeID==-1){
-     this.coeSheet.getCell(i, 1, GC.Spread.Sheets.SheetArea.viewport).locked(false);
-     }
-     }
-     }*!/
-
-     },
-     lockRationGLJCell:function(){
-     sheetCommonObj.lockCells(this.sheet,this.setting);
-     },*/
     updateRationGLJ: function (args) {
         var me = this;
         var updateField = me.setting.header[args.col].dataCode;
@@ -1649,7 +1630,7 @@ var gljOprObj = {
                 cellRect: cellRect,
                 sheetArea: context.sheetArea
             };
-        }
+        };
         TreeNodeCellType.prototype.processMouseDown = function (hitinfo) {
             var recode = data[hitinfo.row];
             if (recode && recode.hasOwnProperty('subList')) {

+ 5 - 6
web/building_saas/main/js/views/installation_fee_view.js

@@ -19,7 +19,7 @@ let installationFeeObj={
             {headerName: "记取位置", headerWidth: 200, dataCode: "position", hAlign: "left", dataType: "String",cellType:'selectButton',getText:'forPosition'}
         ],
         view: {
-            lockColumns: [0,1,3,4,5,6,7,8,9]
+            lockColumns: [0,1,3,4,5,6,7,8,9,10]
         },
         getText:{
             forPosition:function (item,val) {//记取位置转换
@@ -383,7 +383,7 @@ let installationFeeObj={
         sheetCommonObj.showData(this.modifyFeeRuleSheet, this.modifyFeeRuleSetting, this.modifyFeeRuleData);
         this.modifyFeeRuleSheet.setRowCount(this.modifyFeeRuleData.length);
         let positionCol = _.findIndex(this.modifyFeeRuleSetting.header,{ 'dataCode': "position"});
-        this.modifyFeeRuleSheet.getRange(-1,positionCol, -1, 1, GC.Spread.Sheets.SheetArea.viewport).locked(ration_install.feeType=='子目费用'||ration_install.unifiedSetting==1);//设置选取位置列只读
+        this.modifyFeeRuleSheet.getRange(-1,positionCol, -1, 1, GC.Spread.Sheets.SheetArea.viewport).locked(ration_install.feeType=='子目费用');//设置选取位置列只读
     },
     showRationInstallationData:function (node) {
         var installationList = [];
@@ -1110,7 +1110,6 @@ let installationFeeObj={
                 }
               me.refreshFeeDetailRow(info.row);
             }
-            //me.showFeeDetailData(feeDetail.libID,feeDetail.feeItemId);
         });
     },
     onDetailRangeChanged:function (e,info) {
@@ -1212,8 +1211,8 @@ let installationFeeObj={
                                          return
                                     }
                                     if (autoCreate == false){//不自动生成的时候才做检查
-                                        if(feeRule.billID&&feeRule.billID!=""){//先检查清单ID
-                                            let node = projectObj.project.mainTree.getNodeByID(item.billID);
+                                        if(feeRule.billID && feeRule.billID != ""){//先检查清单ID
+                                            let node = projectObj.project.mainTree.getNodeByID(feeRule.billID);
                                             if(!node){
                                                 let c = confirm("所选清单没有找到,需要自动生成吗?");
                                                 if(c){
@@ -1222,7 +1221,7 @@ let installationFeeObj={
                                                     return;
                                                 }
                                             }
-                                        }else if(feeRule.position && feeRule.position!=""){//再检查code
+                                        }else if(feeRule.position && feeRule.position != ""){//再检查code
                                             let bill = projectObj.project.Bills.getBillByCode(feeRule.position);
                                             if(!bill){
                                                 let c = confirm("所选清单没有找到,需要自动生成吗?");

+ 10 - 0
web/building_saas/main/js/views/main_tree_col.js

@@ -269,6 +269,16 @@ let MainTreeCol = {
                 return new GC.Spread.Sheets.CellTypes.CheckBox();
         }
     },
+    setAutoHeight:function (cell,node) {//设置自动行高
+        let displaySetting = projectObj.project.property.displaySetting;
+        let billsAutoH = displaySetting && displaySetting.billsAutoHeight?displaySetting.billsAutoHeight:false;
+        let rationAutoH = displaySetting && displaySetting.rationAutoHeight?displaySetting.rationAutoHeight:false;
+        if(node.sourceType === projectObj.project.Bills.getSourceType()){
+            cell.wordWrap(billsAutoH);
+        }else {
+            cell.wordWrap(rationAutoH);
+        }
+    },
     getEvent: function (eventName) {
         let names = eventName.split('.');
         let event = this;

+ 52 - 15
web/building_saas/main/js/views/project_glj_view.js

@@ -18,7 +18,7 @@ projectGljObject={
             {headerName: "市场价", headerWidth: 70, dataCode: "marketPrice", hAlign: "right", dataType: "Number",decimalField:"glj.unitPrice",validator:"number"},
             {headerName: "是否暂估", headerWidth: 60, dataCode: "is_evaluate", hAlign: "center", dataType: "String",cellType:'checkBox'},
             {headerName: "供货方式", headerWidth: 80, dataCode: "supply", hAlign: "center", dataType: "String",cellType:'comboBox',editorValueType:true,options:supplyComboMap},
-            {headerName: "甲供数量", headerWidth: 100, dataCode: "supply_quantity", hAlign: "right", dataType: "String",validator:"number"},
+            {headerName: "甲供数量", headerWidth: 100, dataCode: "supply_quantity", hAlign: "right", dataType: "Number",validator:"number"},
             {headerName: "交货方式", headerWidth: 90, dataCode: "delivery", hAlign: "left", dataType: "String"},
             {headerName: "送达地点", headerWidth: 100, dataCode: "delivery_address", hAlign: "left", dataType: "String"},
             {headerName: "不调价", headerWidth: 55, dataCode: "is_adjust_price", dataType: "String",cellType: "checkBox"}
@@ -56,6 +56,7 @@ projectGljObject={
         this.initSheet(this.projectGljSheet,this.projectGljSetting);
         this.projectGljSheet.bind(GC.Spread.Sheets.Events.SelectionChanged,this.onProjectGljSelectionChange);
         this.projectGljSheet.bind(GC.Spread.Sheets.Events.EditStarting,this.onProjectGljEditStarting);
+        this.projectGljSpread.bind(GC.Spread.Sheets.Events.RangeChanged, this.onProjectGljRangeChange);
         this.projectGljSheet.name('projectGljSheet');
     },
     initMixRatio:function () {
@@ -133,37 +134,71 @@ projectGljObject={
         let me = projectGljObject;
         let row = args.row;
         let col = args.col;
-        let dataCode = me.projectGljSetting.header[col].dataCode;
-        if(dataCode=='is_adjust_price'||dataCode=='is_evaluate'){
+        if(me.projectGljEditChecking(row,col)==false){
             args.cancel = true;
         }
     },
-    onProjectGljSelectionChange:function (sender, args) {
+    projectGljEditChecking:function (row,col) {//return false表示不能编码
         let me = projectGljObject;
-        let row = args.newSelections[0].row;
-        let col = args.newSelections[0].col;
         let data = me.projectGljSheetData[row];
         let dataCode = me.projectGljSetting.header[col].dataCode;
+        if(dataCode=='is_adjust_price'||dataCode=='is_evaluate'){
+            return false;
+        }
         if(dataCode=='basePrice'||dataCode=='marketPrice'||dataCode=='supply'){//有组成物时,市场单价、定额价、供货方式不能修改
-            let priceCell = false;
             if (data.ratio_data  && data.ratio_data.length > 0){
-                priceCell = true;
+               return false;
             }
-            if(priceCell==false&&dataCode=='basePrice'&&data.is_add!=1){//如果不是新增,定额价不可修改。
-                priceCell = true;
+            if(dataCode=='basePrice'&&data.is_add!=1){//如果不是新增,定额价不可修改。
+                return false;
             }
-            me.projectGljSheet.getCell(row, col,  GC.Spread.Sheets.SheetArea.viewport).locked(priceCell);
         }
         if(dataCode == 'supply_quantity'){
-            if (data.supply == 1) {// 如果为部分甲供则甲供数量需要可编辑
-                me.projectGljSheet.getCell(row, col,  GC.Spread.Sheets.SheetArea.viewport).locked(false);
-            }else {
-                me.projectGljSheet.getCell(row, col,  GC.Spread.Sheets.SheetArea.viewport).locked(true);
+            if (data.supply != 1) {// 如果为部分甲供则甲供数量需要可编辑,其它的都不能编辑
+               return false;
             }
         }
+        return true;
+    },
+
+    onProjectGljSelectionChange:function (sender, args) {
+        let me = projectGljObject;
         me.showMixRatioData();
         me.projectGljSheet.repaint();
     },
+    onProjectGljRangeChange:function (sender,info) {
+        let me = projectGljObject;
+        let changeInfo=[];
+        let canChange = true;
+        for(let c of info.changedCells){
+            let value=  info.sheet.getCell(c.row, c.col).text();
+            changeInfo.push({row:c.row,col:c.col,value:value});
+            if(me.projectGljEditChecking(c.row,c.col)==false){//如果不能编辑
+                canChange = false;
+             }
+            if (canChange==true&&!me.checkData(c.col,me.projectGljSetting,value)) {
+                alert('输入的数据类型不对,请重新输入!');
+                canChange = false;
+            }
+        }
+        if(canChange == false){//恢复原来的值
+            console.log('1');
+            me.showProjectGljData();
+        }else {
+             me.batchUpdatePrice(changeInfo);
+        }
+    },
+    batchUpdatePrice(changeInfo){
+        let projectGLJ = projectObj.project.projectGLJ;
+        let me = projectGljObject;
+        projectGLJ.batchUpdatePrice(changeInfo,function (impactList) {
+            let selected = me.projectGljSheet.getSelections()[0];
+            me.showProjectGljData();
+            me.projectGljSheet.setSelection(selected.row,selected.col,selected.rowCount,selected.colCount);
+        });
+    },
+
+
     showProjectGljData:function () {
         let projectGljSheetData = [];
         let gljList = projectObj.project.projectGLJ.datas.gljList;
@@ -470,6 +505,7 @@ $(function () {
         me.showProjectGljData();
         loadSize("project-glj-main", function () {
             me.projectGljSpread.refresh();
+            me.mixRatioSpread?me.mixRatioSpread.refresh():'';
         });
     });
     $('#ration_link').on('shown.bs.tab', function (e) {
@@ -491,6 +527,7 @@ $(function () {
     });
     slideResize($("#project-glj-main"), function () {
         projectGljObject.projectGljSpread.refresh();
+        projectGljObject.mixRatioSpread?projectGljObject.mixRatioSpread.refresh():'';
     });
     $('#pop-used-list').popover({
             placement: "bottom",

+ 9 - 4
web/building_saas/main/js/views/project_property_display_view.js

@@ -6,7 +6,9 @@ let projDisplayView = {
     init: function () {
         this.datas = projectInfoObj.projectInfo.property.displaySetting;
         this.datas = this.datas === undefined ? {autoHeight: true, disPlayMainMaterial: true} : this.datas;
-        $("#autoHeight").prop("checked", this.datas.autoHeight);
+        //$("#autoHeight").prop("checked", this.datas.autoHeight);
+        $("#billsAutoHeight").prop("checked", this.datas.billsAutoHeight);
+        $("#rationAutoHeight").prop("checked", this.datas.rationAutoHeight);
         $("#disPlayMainMaterial").prop("checked", this.datas.disPlayMainMaterial);
         //$('#disPlayMainMateria').prop('checked')
     },
@@ -22,10 +24,13 @@ let projDisplayView = {
         if (this.datas == null) {
             return;
         }
-        let autoHeight = $('#autoHeight').prop('checked');
+       // let autoHeight = $('#autoHeight').prop('checked');
+        let billsAutoHeight =  $("#billsAutoHeight").prop("checked");
+        let rationAutoHeight =  $("#rationAutoHeight").prop("checked");
         let disPlayMainMaterial = $('#disPlayMainMaterial').prop('checked');
-        if (this.datas.autoHeight !== autoHeight || this.datas.disPlayMainMaterial !== disPlayMainMaterial) {
-            this.datas.autoHeight = autoHeight;
+        if (this.datas.rationAutoHeight !== rationAutoHeight || this.datas.billsAutoHeight !== billsAutoHeight || this.datas.disPlayMainMaterial !== disPlayMainMaterial) {
+            this.datas.billsAutoHeight = billsAutoHeight;
+            this.datas.rationAutoHeight = rationAutoHeight;
             this.datas.disPlayMainMaterial = disPlayMainMaterial;
             // let updateData = {sourceType: 'properties', updateType: 'update', updateData: {ID: projectID, 'property.displaySetting':this.datas}};
             properties['property.displaySetting'] = this.datas;

+ 19 - 25
web/building_saas/main/js/views/project_view.js

@@ -14,7 +14,9 @@ var projectObj = {
     },
     // CSL, 2018-02-09 用于测试显示。使用示例:projectObj.testDisplay(‘总额’, 100);
     testDisplay: function (caption, value) {
-        let s = `&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[ ${caption}: ${value} ]`;
+        let c = '';
+        if (caption) c = caption + ': ';
+        let s = `&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;${c}${value}`;
         $('#testDisplay').html(s);
     },
     treeSelectedChanged: function (node) {
@@ -38,19 +40,11 @@ var projectObj = {
         // for test interface.  CSLAAAAA
         // projectObj.testDisplay('前四项累计值排除当前选中项' + projectObj.project.calcProgram.getBeforeTaxTotalFee([node]));
 
-        // 公式结果
-        /*        let t = projectObj.project.calcProgram.compiledTemplates[node.data.programID];
-                let c = t.calcItems[7];
-                c.dispExpr = '[定额基价人工费] + [定额基价材料费]  + F6 + [主材费]';
-                let rst = analyzer.analyzeUserExpr(t, c);
-                projectObj.testDisplay('结果', rst);*/
-
         // 基数
         // node.data.isSubcontract = true;
-        node.data.gljList = project.ration_glj.getGljArrByRation(node.data.ID);
-        let bname = '甲供定额基价材料费';
-        projectObj.testDisplay(bname, rationCalcBases[bname](node));
-
+        // node.data.gljList = project.ration_glj.getGljArrByRation(node.data.ID);
+        // let bname = '甲供定额基价材料费';
+        // projectObj.testDisplay(bname, rationCalcBases[bname](node));
     },
     refreshBaseActn: function (tree) {
         let setButtonValid = function (valid, btn) {
@@ -515,6 +509,8 @@ var projectObj = {
         let startTime = +new Date();
         console.log("开始加载-----"+startTime);
         this.project.loadDatas(function (err) {
+            let mTime = +new Date();
+            console.log(`get data时间——${mTime - startTime}`);
             if (!err) {
                 that.project.projectGLJ.calcQuantity();//计算分部分项和技术措施项目消耗量;
                 that.project.property = projectInfoObj.projectInfo.property;
@@ -526,8 +522,6 @@ var projectObj = {
                 that.project.projSetting.mainGridSetting = JSON.parse(str);
                 that.project.projSetting.mainGridSetting.frozenCols = 4;
                 TREE_SHEET_HELPER.initSetting($('#billsSpread')[0], that.project.projSetting.mainGridSetting);
-                const autoHeight = that.project.property.displaySetting !== undefined ?
-                    that.project.property.displaySetting.autoHeight : false;
                 that.project.projSetting.mainGridSetting.cols.forEach(function (col) {
                     col.data.splitFields = col.data.field.split('.');
                     if (col.data.getText && Object.prototype.toString.apply(col.data.getText) === "[object String]") {
@@ -547,17 +541,12 @@ var projectObj = {
                     if (col.data.field === 'code') {
                         col.data.formatter = '@';
                     }
-
-                    // 根据配置设置自动行高
+                    col.setAutoHeight = MainTreeCol.getEvent("setAutoHeight");
+                    // 根据配置设置自动行高,在这里先做个标记,然后对每个单元格单独配置
                     if (col.data.field === 'name' || col.data.field === 'itemCharacterText' ||
                         col.data.field === 'jobContentText' || col.data.field === 'adjustState') {
-                        if (!autoHeight) {
-                            col.showHint = true;
-                            col.data.wordWrap = false;
-                        } else {
-                            col.showHint = false;
-                            col.data.wordWrap = true;
-                        }
+                        col.data.autoHeight = true;
+                        col.showHint = true;
                     }
                     if(col.data.field ==='quantity'){
                         col.showHint = true;
@@ -572,9 +561,11 @@ var projectObj = {
                     // }
 
                 });
-
+                let startShowTime = +new Date();
                 that.mainController = TREE_SHEET_CONTROLLER.createNew(that.project.mainTree, that.mainSpread.getActiveSheet(), that.project.projSetting.mainGridSetting);
                 that.mainController.showTreeData();
+                let endShowTime = +new Date();
+                console.log(`show data时间——${endShowTime - startShowTime}`);
                 that.mainController.bind('refreshBaseActn', that.refreshBaseActn);
                 that.mainController.bind(TREE_SHEET_CONTROLLER.eventName.beforeTreeSelectedChange, that.beforeMainTreeSelectedChange);
                 that.mainController.bind(TREE_SHEET_CONTROLLER.eventName.treeSelectedChanged, that.treeSelectedChanged);
@@ -590,16 +581,19 @@ var projectObj = {
                 that.mainSpread.bind(GC.Spread.Sheets.Events.ClipboardChanged, that.msClipboardChanged);
                 that.mainSpread.bind(GC.Spread.Sheets.Events.ButtonClicked, that.onButtonClick);
                 that.mainSpread.bind(GC.Spread.Sheets.Events.CellDoubleClick, that.onCellDoubleClick);
+                let loadOtherStartTime = +new Date();
                 that.loadMainSpreadContextMenu();
                 that.loadFocusLocation();
                 let endTime = +new Date();
+                console.log(`其它时间——${endTime - loadOtherStartTime}`);
                 socketObject.connect();//连接socket服务器
                 console.log("加载完成-----"+endTime);
                 console.log(`时间——${endTime - startTime}`);
                 that.project.projectMarkChecking();//是否需要重新进行造价计算
                 installationFeeObj.engineeringTypeChecking();//检查是否安装工程
                 //初始需要触发一次点击表格事件,sheet.getAutoFitWidth值(获取单元格文本长度)才正确
-
+                autoFlashHeight();
+                projectObj.refreshMainSpread();
             }
             else {
 

+ 12 - 0
web/building_saas/main/js/views/std_ration_lib.js

@@ -256,7 +256,19 @@ var rationLibObj = {
                 "font":"Arial"
             }
         }]
+    },
+    getCurrentStdRationLibID:function () {
+        if(projectInfoObj.projectInfo.engineeringInfo.ration_lib.length === 0){
+            alert('当前项目无定额库,请添加定额库。');
+            return null;
+        }
+        if($('#stdRationLibSelect').val()){
+            return parseInt($('#stdRationLibSelect').val());
+        }else {
+            return projectInfoObj.projectInfo.engineeringInfo.ration_lib[0].id;
+        }
     }
+
 };
 
 addEventOnResize(rationLibObj.refreshSettingForHint);

+ 74 - 1
web/building_saas/main/js/views/sub_fee_rate_views.js

@@ -7,6 +7,23 @@ var subRateObject={
     datas:null,
     valueMap:null,
     canEdit:true,
+    subRateSpread:null,
+    subRateSheet:null,
+    subRateSetting:{
+        header: [
+            {headerName: "参数名称", headerWidth: 250, dataCode: "name", dataType: "String"},
+            {headerName: "参数值", headerWidth: 200, dataCode: "optionValue", dataType: "String",getText:'forOption'}
+        ],
+        view: {
+            lockColumns: [0]
+        },
+        getText:{
+            forOption:function (item,val) {
+                let o = _.find(item.optionList,{'selected':true});
+                return o?o.value:'';
+            }
+        }
+    },
     columns: [
         {
             id: 'name',
@@ -59,11 +76,48 @@ var subRateObject={
         this.addComboboxOption(this.datas);
 
     },
-       reFreshRateViews:function(sender,args) {
+    reFreshRateViews:function(sender,args) {
         subRateObject.datas = projectObj.project.FeeRate.getSubViewData(args.item);
         subRateObject.valueMap=projectObj.project.FeeRate.getValueMap(args.item);
         subRateObject.createSpreadView();
     },
+    initSubRateSpread:function (item) {
+        if(this.subRateSpread == null){
+            this.subRateSpread = SheetDataHelper.createNewSpread($("#subRate")[0]);
+            this.subRateSheet = this.subRateSpread.getSheet(0);
+            sheetCommonObj.initSheet(this.subRateSheet, this.subRateSetting, 30);
+            this.subRateSheet.bind(GC.Spread.Sheets.Events.SelectionChanged, this.onSubRateSelectChanged);
+            this.subRateSheet.bind(GC.Spread.Sheets.Events.ValueChanged, this.onSubRateValueChange);
+            //this.subRateSheet.bind(GC.Spread.Sheets.Events.ValueChanged, me.onSheetValueChange);
+            this.subRateSheet.name('subRateSheet');
+        }
+        subRateObject.datas = projectObj.project.FeeRate.getSubViewData(item);
+        subRateObject.valueMap=projectObj.project.FeeRate.getValueMap(item);
+        console.log(subRateObject.datas);
+        console.log(subRateObject.valueMap);
+        subRateObject.showSubRateData();
+    },
+    showSubRateData:function () {
+        this.subRateSheet.setRowCount(0);
+        sheetCommonObj.showData(this.subRateSheet, this.subRateSetting, this.datas);
+        this.subRateSheet.setRowCount(this.datas.length);
+        for(let row =0; row < this.datas.length;row++){
+            this.setComboOptionCell(row,1,this.datas[row],this.subRateSheet);
+        }
+    },
+    onSubRateSelectChanged:function (e,info) {
+        info.sheet.repaint();
+    },
+    setComboOptionCell:function(row,col,subRate,sheet){
+        let options=[];
+        for(let op of subRate.optionList){
+            options.push({text:op.name,value:op.value});
+        }
+        let dynamicCombo = sheetCommonObj.getDynamicCombo();//new GC.Spread.Sheets.CellTypes.ComboBox();
+        dynamicCombo.items(options);
+        dynamicCombo.editorValueType(GC.Spread.Sheets.CellTypes.EditorValueType.value);
+        sheet.setCellType(row, col, dynamicCombo, GC.Spread.Sheets.SheetArea.viewport);
+    },
     addComboboxOption:function (datas) {
         //<option value ="volvo">Volvo</option> <option value ="saab">Saab</option> <option value="opel">Opel</option> <option value="audi">Audi</option>
         _.forEach(datas,function (item) {
@@ -94,6 +148,25 @@ var subRateObject={
             feeRateObject.updateBySelect(rate,selectMap,mapID);
         }
     },
+    onSubRateValueChange:function (e,info) {
+        console.info(info);
+        let me = subRateObject, selectValueList=[],selectMap={};
+        if(me.datas&&me.datas.length>0){
+            _.forEach(me.datas,function (d,key) {
+                if(info.row == key){
+                    selectMap[key]=info.newValue;
+                }else {
+                    let o = _.find(d.optionList,{'selected':true});
+                    selectMap[key]=o.value;
+                }
+                selectValueList.push(selectMap[key]);
+            })
+            var mapID =selectValueList.join('-');
+            var rate = me.valueMap[mapID];
+            feeRateObject.updateBySelect(rate,selectMap,mapID);
+        }
+    },
+
     destorySpreadView:function () {
         if(this.views){
             this.views.destroy();