Browse Source

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

zhongzewei 7 years ago
parent
commit
79d3656824

+ 2 - 1
.gitignore

@@ -3,4 +3,5 @@ node_modules/
 dist/
 .idea/
 tmp/
-test/unit/logs
+test/unit/logs
+*.log

+ 1 - 2
modules/complementary_glj_lib/models/gljModel.js

@@ -262,11 +262,10 @@ class GljDao {
      */
     async getComponent(gljId) {
         let result = [];
-        let libGljData = await complementaryGljModel.find({ID: gljId});
+        let libGljData = await complementaryGljModel.findOne({ID: gljId});
         if (libGljData === null || libGljData.component.length <= 0) {
             return result;
         }
-
         // 标准工料机库
         let componentIdListStd = [];
         // 补充工料机库

+ 22 - 11
modules/glj/models/glj_list_model.js

@@ -77,7 +77,7 @@ class GLJListModel extends BaseModel {
     async getListByProjectId(projectId, unitPriceFileId) {
         let gljData = null;
         let decimal =await decimal_facade.getProjectDecimal(projectId);
-        let quantity_decimal = decimal.glj.quantity?decimal.glj.quantity:6;//取消耗量保留小数据位,默认6位
+        let quantity_decimal = decimal&&decimal.glj.quantity?decimal.glj.quantity:6;//取消耗量保留小数据位,默认6位
         let mixRatioConnectData = {};
         let mixRationMap={};
         let keyMap={};
@@ -297,6 +297,7 @@ class GLJListModel extends BaseModel {
                 throw '没有对应的单价文件';
             }
             let CompositionGLJ=[];
+            let unitPriceModel = new UnitPriceModel();
             // 判断类型,如果是混凝土、砂浆或者配合比则查找对应的组成物(前提是没有对应的项目工料机数据)
             if (data.type === GLJTypeConst.CONCRETE || data.type === GLJTypeConst.MORTAR ||
                 data.type === GLJTypeConst.MIX_RATIO || data.type === GLJTypeConst.GENERAL_MACHINE) {
@@ -305,11 +306,20 @@ class GLJListModel extends BaseModel {
                     await this.compositionInit(data, unitPriceFileId);
                 }
                 CompositionGLJ=await this.getCompositionGLJByData(data,unitPriceFileId);
+                if(isAddProjectGLJ==false&&CompositionGLJ.length==0){//如果不是新增,并且是有组成物的类型但又没有发现组成物的情况下,有可能是错误数据,重新在库中查找一下组成物,有则插入
+                    await this.compositionInit(data, unitPriceFileId);
+                    CompositionGLJ=await this.getCompositionGLJByData(data,unitPriceFileId);
+
+                    if(CompositionGLJ.length>0){//如果这次发现又有组成物了,则把旧的单价数据删除,在后面的操作中会重新增加
+                        let de_condition ={unit_price_file_id: unitPriceFileId,code:data.code,name:data.name,unit:data.unit,type:data.type};
+                        data.specs!=null&&data.specs!=undefined&&data.specs!=""?de_condition.specs = data.specs:de_condition;
+                        await unitPriceModel.db.delete(de_condition);
+                    }
+                }
             }
             projectGljData.subList=CompositionGLJ;
 
             // 新增单价文件
-            let unitPriceModel = new UnitPriceModel();
             let [unitPriceInsertData, isAdd] = await unitPriceModel.addUnitPrice(data, unitPriceFileId);
 
             if (!unitPriceInsertData) {
@@ -550,7 +560,6 @@ class GLJListModel extends BaseModel {
         // 查找对应组成物的项目工料机数据
         let indexs=['code','name','specs','unit','type'];
         let [projectGljList, compositionGljList] = await this.getCompositionGLJList(gljId, projectId, indexs, fromTable);
-
         // 整理配合比待插入数据
         let mixRatioInsertData = [];
         for (let tmp of compositionGljList) {
@@ -572,13 +581,16 @@ class GLJListModel extends BaseModel {
 
         // 插入配合比表
         // 因为有可能项目工料机与单价数据已存在,但配合比数据不存在,所以先插入配合比,后续判断如果存在项目工料机则可以省下数据库操作
-        let mixRatioModel = new MixRatioModel();
-        let addMixRatioResult = await mixRatioModel.add(mixRatioInsertData);
-        if (!addMixRatioResult) {
-            throw '组成物插入单价数据失败!';
+        if(mixRatioInsertData.length>0){
+            let mixRatioModel = new MixRatioModel();
+            let addMixRatioResult = await mixRatioModel.add(mixRatioInsertData);
+            if (!addMixRatioResult) {
+                throw '组成物插入单价数据失败!';
+            }
         }
+        let pglj_length = projectGljList instanceof Array ? projectGljList.length:Object.getOwnPropertyNames(projectGljList).length;
         // 如果已经存在则后续操作停止
-        if(Object.getOwnPropertyNames(projectGljList).length === compositionGljList.length) {
+        if(pglj_length === compositionGljList.length) {
             return
         }
 
@@ -691,9 +703,8 @@ class GLJListModel extends BaseModel {
         // 获取对应的组成物数据
         let gljListModel = fromTable === 'std' ? new STDGLJLibGLJListModel() : new GljModel();
         let componentGljList = await gljListModel.getComponent(gljId);
-
         if (componentGljList.length <= 0) {
-            throw '不存在对应的组成物';
+            return [{},[]];
         }
 
         let codeList = [];
@@ -742,7 +753,7 @@ class GLJListModel extends BaseModel {
         let typeList = [];
         let unitList = [];
         if(mixRatios.length<=0){
-            throw  '不存在对应的组成物';
+            return [[],[],[]];
         }
         let mixRatioData={};
         for(let tmp of mixRatios) {

+ 12 - 8
modules/glj/models/unit_price_model.js

@@ -91,7 +91,7 @@ class UnitPriceModel extends BaseModel {
         let unitPrice=null;
         if(operation=='add'){//新增操作时,要把code也一起判断,是否完全一样
             unitPrice =  this.isPropertyInclude(unitPriceData,['code','name','specs','unit','type'],data);
-        }else {//修改操作时,code不用加入判,因为code是需要改变的
+        }else {//修改操作时,code不用加入判,因为code是需要改变的
             unitPrice =  this.isPropertyInclude(unitPriceData,['name','specs','unit','type'],data);
         }
         if(unitPrice){
@@ -328,21 +328,27 @@ class UnitPriceModel extends BaseModel {
         currentUnitList = JSON.parse(currentUnitList);
 
         let codeList = [];
+        let nameList =[];
         for (let tmp of currentUnitList) {
             if (codeList.indexOf(tmp.code) >= 0) {
                 continue;
             }
             codeList.push(tmp.code);
+            if(nameList.indexOf(tmp.name)>=0){
+                continue
+            }
+            nameList.push(tmp.name);
         }
 
-        // 查找即将更替的单价文件是否存在对应的工料机数据
-        let condition = {unit_price_file_id: changeUnitPriceId, code: {"$in": codeList}};
-        let targetUnitList = await this.findDataByCondition(condition, null, false, 'code');
+        // 查找即将更替的单价文件是否存在对应的工料机数据 -- (这里只根据code和名称初步过滤,因为其它的几项更改的概率不大,在下一步的比较中再精确匹配)
+        let condition = {unit_price_file_id: changeUnitPriceId, code: {"$in": codeList},name:{"$in": nameList}};
+        let targetUnitList = await this.findDataByCondition(condition, null, false, ['code','name','specs','unit','type']);
 
         // 如果没有重叠的数据则原有的数据都复制一份
         let insertData = [];
         for (let tmp of currentUnitList) {
-            if (targetUnitList !== null && targetUnitList[tmp.code] !== undefined) {
+            let t_index = this.getIndex(tmp,['code','name','specs','unit','type']);
+            if (targetUnitList !== null && targetUnitList[t_index] !== undefined) {
                 continue;
             }
             // 删除原有id信息
@@ -351,9 +357,7 @@ class UnitPriceModel extends BaseModel {
             tmp.unit_price_file_id = changeUnitPriceId;
             insertData.push(tmp);
         }
-
-        return insertData.length > 0 ? this.add(currentUnitList) : true;
-
+        return insertData.length > 0 ? this.add(insertData) : true;
     }
 
 

+ 1 - 1
modules/reports/controllers/rpt_controller.js

@@ -92,7 +92,7 @@ function getAllPagesCommon(user_id, prj_id, rpt_id, pageSize, option, cb) {
                     let maxPages = printCom.totalPages;
                     let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
                     if (pageRst) {
-                        //fsUtil.wirteObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult.js");
+                        //fsUtil.writeObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult.js");
                         cb(null, pageRst);
                     } else {
                         cb('Have errors while on going...', null);

+ 39 - 17
modules/reports/rpt_component/jpc_bill_tab.js

@@ -1,8 +1,6 @@
 let JV = require('./jpc_value_define');
 let JpcFieldHelper = require('./helper/jpc_helper_field');
 let JpcBandHelper = require('./helper/jpc_helper_band');
-let JpcBand = require('./jpc_band');
-let JpcFlowTabHelper = require('./helper/jpc_helper_flow_tab');
 let JpcCommonHelper = require('./helper/jpc_helper_common');
 let JpcDiscreteHelper = require('./helper/jpc_helper_discrete');
 let JpcTextHelper = require('./helper/jpc_helper_text');
@@ -20,11 +18,24 @@ JpcBillTabSrv.prototype.createNew = function(){
         let me = this;
         JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[JV.NODE_BILL_INFO][JV.NODE_BILL_CONTENT][JV.PROP_BILL_FIELDS], null, me.disp_fields_idx);
     };
-    JpcBillTabResult.paging = function(rptTpl) {
-        let me = this, rst = 0;
-        let detail_fields = rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS];
-        if (detail_fields && detail_fields.length > 0) {
-            rst = detail_fields[0].length;
+    JpcBillTabResult.paging = function(rptTpl, dataObj) {
+        let rst = 0;
+        function getDataLength(fields_str) {
+            let dataFields = dataObj[fields_str];
+            if (dataFields && dataFields.length > 0) {
+                rst = dataFields[0].length;
+            }
+        }
+        if (rptTpl[JV.NODE_FIELD_MAP]) {
+            if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS]) {
+                getDataLength(JV.DATA_DETAIL_DATA);
+            } else if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS]) {
+                getDataLength(JV.DATA_MASTER_DATA);
+            } else if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DISCRETE_FIELDS]) {
+                getDataLength(JV.DATA_DISCRETE_DATA);
+            } else if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DISCRETE_PARAMS]) {
+                rst = 1;
+            }
         }
         return rst;
     };
@@ -36,31 +47,42 @@ JpcBillTabSrv.prototype.createNew = function(){
         //2. start to output detail-part
         let unitFactor = JpcCommonHelper.getUnitFactor(rptTpl);
         //2.1 output content
-        tabRstLst.push(me.outputContent(rptTpl, dataObj, page, bands, unitFactor, controls, pageStatus));
+        tabRstLst.push(me.outputContent(rptTpl, dataObj, page, bands, unitFactor, controls, pageStatus, $CURRENT_RPT));
         //2.2 output discrete
         tabRstLst.push(JpcDiscreteHelper.outputDiscreteInfo(rptTpl[JV.NODE_BILL_INFO][JV.NODE_DISCRETE_INFO], bands, dataObj, unitFactor, pageStatus, page - 1, 1, 0, $CURRENT_RPT));
-    }
-    JpcBillTabResult.outputContent = function(rptTpl, dataObj, page, bands, unitFactor, controls, pageStatus) {
+        for (let i = 0; i < tabRstLst.length; i++) {
+            rst = rst.concat(tabRstLst[i]);
+            tabRstLst[i] = null;
+        }
+        return rst;
+    };
+    JpcBillTabResult.outputContent = function(rptTpl, dataObj, page, bands, unitFactor, controls, pageStatus, $CURRENT_RPT) {
         let me = this, rst = [];
         let tab = rptTpl[JV.NODE_BILL_INFO][JV.NODE_BILL_CONTENT];
         let band = bands[tab[JV.PROP_BAND_NAME]];
         if (band) {
-            if (pageStatus[band[JV.BAND_PROP_DISPLAY_TYPE]] == true) {
+            if (pageStatus[band[JV.BAND_PROP_DISPLAY_TYPE]]) {
                 let tab_fields = tab[JV.PROP_BILL_FIELDS];
-                let data_details = dataObj[JV.DATA_MASTER_DATA];
+                let data_details = null;
+                if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_DETAIL_FIELDS]) {
+                    data_details = dataObj[JV.DATA_DETAIL_DATA];
+                } else if (rptTpl[JV.NODE_FIELD_MAP][JV.NODE_MASTER_FIELDS]) {
+                    data_details = dataObj[JV.DATA_MASTER_DATA];
+                }
                 for (let i = 0; i < tab_fields.length; i++) {
                     let tab_field = tab_fields[i];
                     let data_field = null;
-                    if (me.disp_fields_idx[i] != JV.BLANK_FIELD_INDEX) {
+                    if (me.disp_fields_idx.length > i && me.disp_fields_idx[i] !== JV.BLANK_FIELD_INDEX) {
                         data_field = data_details[me.disp_fields_idx[i]];
                     } else {
-                        data_field = JE.F(tab_field[JV.PROP_FIELD_ID]);
+                        data_field = JE.F(tab_field[JV.PROP_FIELD_ID], $CURRENT_RPT);
                         if (data_field) {
                             data_field = data_field[JV.PROP_AD_HOC_DATA];
                         }
                     }
                     if (!(tab_field[JV.PROP_HIDDEN])) {
-                        let cellItem = JpcCommonOutputHelper.createCommonOutput(tab_field, JpcFieldHelper.getValue(data_field, page - 1), controls);
+                        let val = JpcFieldHelper.getValue(data_field, page - 1);
+                        let cellItem = JpcCommonOutputHelper.createCommonOutput(tab_field, val, controls);
                         cellItem[JV.PROP_AREA] = JpcAreaHelper.outputArea(tab_field[JV.PROP_AREA], band, unitFactor, 1, 0, 1, 0, 1, 0, true, false);
                         rst.push(cellItem);
                     }
@@ -79,8 +101,8 @@ JpcBillTabSrv.prototype.createNew = function(){
             }
         }
         return rst;
-    }
+    };
     return JpcBillTabResult;
-}
+};
 
 module.exports = new JpcBillTabSrv();

+ 19 - 13
modules/reports/rpt_component/jpc_data.js

@@ -10,17 +10,21 @@ let JpcData = {
             let private_analyse = function(MASTER_FIELD_STR, DETAIL_FIELD_STR, MASTER_DATA_STR, DETAIL_DATA_STR, dataSeqArr) {
                 //1. get ID fields
                 let masterIDs = [];
-                for (let i = 0; i < rptTpl[JV.NODE_FIELD_MAP][MASTER_FIELD_STR].length; i++) {
-                    let mstFieldObj = rptTpl[JV.NODE_FIELD_MAP][MASTER_FIELD_STR][i];
-                    if (jpc_common_helper.getBoolean(mstFieldObj[JV.PROP_IS_ID])) {
-                        masterIDs.push({"idx": i, "seq": mstFieldObj[JV.PROP_ID_SEQ]});
+                if (rptTpl[JV.NODE_FIELD_MAP][MASTER_FIELD_STR]) {
+                    for (let i = 0; i < rptTpl[JV.NODE_FIELD_MAP][MASTER_FIELD_STR].length; i++) {
+                        let mstFieldObj = rptTpl[JV.NODE_FIELD_MAP][MASTER_FIELD_STR][i];
+                        if (jpc_common_helper.getBoolean(mstFieldObj[JV.PROP_IS_ID])) {
+                            masterIDs.push({"idx": i, "seq": mstFieldObj[JV.PROP_ID_SEQ]});
+                        }
                     }
                 }
                 let detailIDs = [];
-                for (let i = 0; i < rptTpl[JV.NODE_FIELD_MAP][DETAIL_FIELD_STR].length; i++) {
-                    let dtlFieldObj = rptTpl[JV.NODE_FIELD_MAP][DETAIL_FIELD_STR][i];
-                    if (jpc_common_helper.getBoolean(dtlFieldObj[JV.PROP_IS_ID])) {
-                        detailIDs.push({"idx": i, "seq": dtlFieldObj[JV.PROP_ID_SEQ]});
+                if (rptTpl[JV.NODE_FIELD_MAP][DETAIL_FIELD_STR]) {
+                    for (let i = 0; i < rptTpl[JV.NODE_FIELD_MAP][DETAIL_FIELD_STR].length; i++) {
+                        let dtlFieldObj = rptTpl[JV.NODE_FIELD_MAP][DETAIL_FIELD_STR][i];
+                        if (jpc_common_helper.getBoolean(dtlFieldObj[JV.PROP_IS_ID])) {
+                            detailIDs.push({"idx": i, "seq": dtlFieldObj[JV.PROP_ID_SEQ]});
+                        }
                     }
                 }
                 //2. sort the ID fields
@@ -84,11 +88,13 @@ let JpcData = {
                         }
                     }
                 } else { //if no master data
-                    let field = dataObj[DETAIL_DATA_STR][0];
-                    //dataSeqArr = [[]];
-                    dataSeqArr.push([]);
-                    for (let i = 0; i < field.length; i++) {
-                        dataSeqArr[0].push(i);
+                    if (dataObj && dataObj[DETAIL_DATA_STR] && dataObj[DETAIL_DATA_STR].length > 0) {
+                        //may be bill type report which may only have discrete fields!
+                        let field = dataObj[DETAIL_DATA_STR][0];
+                        dataSeqArr.push([]);
+                        for (let i = 0; i < field.length; i++) {
+                            dataSeqArr[0].push(i);
+                        }
                     }
                 }
             };

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

@@ -125,6 +125,9 @@ JpcExSrv.prototype.createNew = function(){
                 me.flowTabEx.sorting(rptTpl, dataObj, dataHelper.exDataSeq.slice(0));
             }
         }
+        if (me.billTab) {
+            me.billTab.sorting(rptTpl, dataObj, dataHelper.dataSeq.slice(0));
+        }
         if (me.crossTab) {
             me.crossTab.sorting(rptTpl, dataObj, dataHelper.dataSeq.slice(0));
         }
@@ -155,7 +158,7 @@ JpcExSrv.prototype.createNew = function(){
             //me.totalPages = me.crossTab.preSetupPages(rptTpl, defProperties, dftPagingOption);
             me.totalPages = me.crossTab.preSetupPages(rptTpl, defProperties, JV.PAGING_OPTION_NORMAL); //infinity对交叉表来说无意义
         } else if (me.billTab) {
-            me.totalPages = me.billTab.paging();
+            me.totalPages = me.billTab.paging(rptTpl, dataObj);
         }
     };
     JpcResult.executeFormulas = function(runType, $CURRENT_TEMPLATE, $CURRENT_DATA, $CURRENT_RPT) {
@@ -244,7 +247,7 @@ JpcExSrv.prototype.createNew = function(){
             } else if (me.crossTab) {
                 rst[JV.PROP_CELLS] = me.crossTab.outputAsSimpleJSONPage(rptTpl, dataObj, page, bands, controls, me);
             } else if (me.billTab) {
-                //
+                rst[JV.PROP_CELLS] = me.billTab.outputAsSimpleJSONPage(rptTpl, dataObj, page, bands, controls, me);
             }
             if (!(me.flowTab && me.flowTab.paging_option === JV.PAGING_OPTION_INFINITY)) {
                 let pageMergeBorder = getPageMergeBorder();

+ 12 - 5
modules/reports/util/rpt_construct_data_util.js

@@ -143,6 +143,9 @@ class Rpt_Data_Extractor {
         pri_setup_filter(JV.NODE_DETAIL_FIELDS);
         pri_setup_filter(JV.NODE_MASTER_FIELDS_EX);
         pri_setup_filter(JV.NODE_DETAIL_FIELDS_EX);
+        if (rst.length === 0) {
+            rst.push(projectConst.RATION_ASS);
+        }
         return rst;
     };
 
@@ -263,7 +266,7 @@ function summaryData(sourceData, handleCfg, prjData){
     }
     delete sourceData.data;
     sourceData.data = rstArr;
-    // fsUtil.wirteObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/sumRst.js");
+    // fsUtil.writeObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/sumRst.js");
 }
 
 function filterData(sourceData, handleCfg, prjData) {
@@ -331,7 +334,7 @@ function filterData(sourceData, handleCfg, prjData) {
     }
     delete sourceData.data;
     sourceData.data = rstArr;
-    // fsUtil.wirteObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/filteredRst.js");
+    // fsUtil.writeObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/filteredRst.js");
 }
 
 function adjustData(sourceData, adjustCfg) {
@@ -527,13 +530,13 @@ function sortData(sourceData, sortCfg, prjData) {
             treeUtil.getFlatArray(rst, destArr);
             delete sourceData.data;
             sourceData.data = destArr;
-            // fsUtil.wirteObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/sortedAndFlattedRst.js");
+            // fsUtil.writeObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/sortedAndFlattedRst.js");
             break;
         case "normal":
             private_normal_sort(tempRstArr, sortCfg[JV.PROP_SORT_KEYS]);
             delete sourceData.data;
             sourceData.data = tempRstArr;
-            // fsUtil.wirteObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/normalSortedRst.js");
+            // fsUtil.writeObjToFile(sourceData.data, "D:/GitHome/ConstructionCost/tmp/normalSortedRst.js");
             break;
         case "accord_to_parent":
             let pcKey = sortCfg[JV.PROP_PARENT_CHILD_SORT_KEY];
@@ -625,7 +628,11 @@ function ext_mainGetPropety(propKey) {
     let dtObj = parentObj["myOwnRawDataObj"];
     if (propKey && dtObj) {
         if (dtObj.hasOwnProperty("property")) {
-            rst.push(dtObj["property"][propKey]);
+            if (!dtObj["property"][propKey] && dtObj[propKey]) {
+                rst.push(dtObj[propKey]);
+            } else {
+                rst.push(dtObj["property"][propKey]);
+            }
         } else  {
             rst.push(dtObj[propKey]);
         }

+ 7 - 2
modules/reports/util/rpt_excel_util.js

@@ -158,6 +158,9 @@ function writeStyles(stylesObj){
         if (strUtil.convertStrToBoolean(font[JV.FONT_PROPS[3]])) {
             rst.push('<b/>');
         }
+        if (strUtil.convertStrToBoolean(font[JV.FONT_PROPS[5]])) {
+            rst.push('<u/>');
+        }
         rst.push('<sz val="' + font.size + '"/>');
         rst.push('<color indexed="' + font.colorIdx + '"/>');
         rst.push('<name val="' + font[JV.FONT_PROPS[0]] + '"/>');
@@ -420,7 +423,8 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
         for (let i = 0; i < stylesObj.fonts.length; i++) {
             let font = stylesObj.fonts[i];
             if (sheetFont) {
-                if (font[JV.FONT_PROPS[0]] === sheetFont[JV.FONT_PROPS[0]] && font.size === Math.round(sheetFont[JV.FONT_PROPS[1]] * 3 / 4) && font[JV.FONT_PROPS[3]] == sheetFont[JV.FONT_PROPS[3]]) {
+                if (font[JV.FONT_PROPS[0]] === sheetFont[JV.FONT_PROPS[0]] && font.size === Math.round(sheetFont[JV.FONT_PROPS[1]] * 3 / 4)
+                    && font[JV.FONT_PROPS[3]] === sheetFont[JV.FONT_PROPS[3]] && font[JV.FONT_PROPS[5]] === sheetFont[JV.FONT_PROPS[5]]) {
                     hasFont = true;
                     rst = i;
                     break;
@@ -436,6 +440,7 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
             font.charset = 134;
             font.colorIdx = "8";
             font[JV.FONT_PROPS[3]] = sheetFont[JV.FONT_PROPS[3]]; //font bold
+            font[JV.FONT_PROPS[5]] = sheetFont[JV.FONT_PROPS[5]]; //font underline
             stylesObj.fonts.push(font);
             rst = stylesObj.fonts.length - 1;
         }
@@ -983,7 +988,7 @@ module.exports = {
             }
             //3. everything is ok, then call me
             me.exportExcel(newPageData, paperSize, fName, 'false', sheetNames, callback);
-            fsUtil.wirteObjToFile(newPageData, 'D:/GitHome/ConstructionOperation/tmp/combinedHeader.js');
+            fsUtil.writeObjToFile(newPageData, 'D:/GitHome/ConstructionOperation/tmp/combinedHeader.js');
         } catch (e) {
             console.log(e);
         }

+ 1 - 1
public/fsUtil.js

@@ -25,7 +25,7 @@ module.exports = {
             });
         }
     },
-    wirteObjToFile: function(obj, filePath) {
+    writeObjToFile: function(obj, filePath) {
         if (obj) {
             let arr = [];
             arr.push(JSON.stringify(obj));

+ 4 - 1
public/web/rpt_value_define.js

@@ -136,6 +136,7 @@ const JV = {
     PROP_CALCULATION: "CalculationType",
     PROP_H_CALCULATION: "H_CalculationType",
     PROP_V_CALCULATION: "V_CalculationType",
+    PROP_FIT_AREA: "isFitArea",
 
     IDX_LEFT: 0,
     IDX_TOP: 1,
@@ -236,7 +237,7 @@ const JV = {
     SIZE_16K: [7.75, 10.75],
     SIZE_EXECUTIVE: [7.25, 10.5],
 
-    OUTPUT_OFFSET: [2,1,2,3],
+    OUTPUT_OFFSET: [2,2,1,3],
     OFFSET_IDX_LEFT: 0,
     OFFSET_IDX_RIGHT: 1,
     OFFSET_IDX_TOP: 2,
@@ -265,6 +266,8 @@ const JV = {
 
     VERTICAL_ANGLE: "90",
     ANTI_VERTICAL_ANGLE: "-90",
+    VERTICAL_ANGLE_INT: 90,
+    ANTI_VERTICAL_ANGLE_INT: -90,
 
     LAST_DEF: ""
 };

+ 3 - 0
public/web/sheet/sheet_common.js

@@ -97,6 +97,9 @@ var sheetCommonObj = {
         //sheet.addRows(row, 1);
 
         sheet.clear(0, 0, sheet.getRowCount(), sheet.getColumnCount(), GC.Spread.Sheets.SheetArea.viewport, GC.Spread.Sheets.StorageType.data);
+        if(sheet.getRowCount()<data.length){
+            sheet.setRowCount(data.length);
+        }
         for (var col = 0; col < setting.header.length; col++) {
             var hAlign = "left", vAlign = "center";
             if (setting.header[col].hAlign) {

+ 116 - 0
test/unit/reports/test_cover_01.js

@@ -0,0 +1,116 @@
+/**
+ * Created by Tony on 2017/11/21.
+ */
+
+let test = require('tape');
+import JpcEx from "../../../modules/reports/rpt_component/jpc_ex";
+import JV from "../../../modules/reports/rpt_component/jpc_value_define";
+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();
+let consts = require('../../../modules/main/models/project_consts');
+let projectConsts = consts.projectConst;
+fileUtils.getGlobbedFiles('../../../modules/complementary_glj_lib/models/*.js').forEach(function(modelPath) {
+    require(path.resolve(modelPath));
+});
+
+fileUtils.getGlobbedFiles('../../../modules/ration_glj/models/*.js').forEach(function(modelPath) {
+    require(path.resolve(modelPath));
+});
+
+//引入报表模块
+fileUtils.getGlobbedFiles('../../../modules/reports/models/*.js').forEach(function(modelPath) {
+    require(path.resolve(modelPath));
+})
+
+//暂时引入其它模块的model
+require('../../../modules/fee_rates/models/fee_rates');
+// 引入人工系数模块
+require('../../../modules/main/models/labour_coe_model');
+require('../../../modules/main/models/calc_program_model');
+
+let fsUtil = require("../../../public/fsUtil");
+
+let prjMdl = require('../../../modules/pm/models/project_model');
+let projectDataMdl = require('../../../modules/main/models/project');
+let demoPrjId = - 1;
+let demoRptId = 223, pagesize = "A4";
+
+let userId_Leng = 1142; //小冷User Id
+// demoPrjId = 720; //QA: DW3
+demoPrjId = 838; //QA:
+/*/
+ let userId_Dft = userId_Leng;
+ /*/
+let userId_Dft = 76075;
+//*/
+
+let rptTplFacade = require("../../../modules/reports/facade/rpt_template_facade");
+let rptTplDataFacade = require("../../../modules/reports/facade/rpt_tpl_data_facade");
+
+import rptDataExtractor from "../../../modules/reports/util/rpt_construct_data_util";
+
+let fs = require('fs');
+//设置Date Format函数
+fs.readFile(__dirname.slice(0, __dirname.length - 18) + '/public/web/date_util.js', 'utf8', 'r', function (err, data) {
+    eval(data);
+});
+
+//*
+test('测试 - 打开模板: 封-1 ', function (t) {
+    rptTplFacade.getRptTemplate(demoRptId).then(function(rptTpl) {
+        let rptDataUtil = new rptDataExtractor();
+        rptDataUtil.initialize(rptTpl._doc);
+        let filter = rptDataUtil.getDataRequestFilter();
+        // console.log(filter);
+        //正常应该根据报表模板定义的数据类型来请求数据
+        rptTplDataFacade.prepareProjectData(userId_Dft, demoPrjId, filter, function (err, msg, rawDataObj) {
+            if (!err) {
+                try {
+                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject.js");
+                    let tplData = rptDataUtil.assembleData(rawDataObj);
+                    //build the report
+                    let printCom = JpcEx.createNew();
+                    rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = pagesize;
+                    let defProperties = rpt_cfg;
+                    let dftOption = JV.PAGING_OPTION_NORMAL;
+                    printCom.initialize(rptTpl);
+                    printCom.analyzeData(rptTpl, tplData, defProperties, dftOption);
+                    let maxPages = printCom.totalPages;
+                    let pageRst = printCom.outputAsSimpleJSONPageArray(rptTpl, tplData, 1, maxPages, defProperties);
+                    if (pageRst) {
+                        fsUtil.writeObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult.js");
+                    } else {
+                        console.log("oh! no pages were created!");
+                    }
+                } catch (ex) {
+                    console.log(ex);
+                    t.pass('pass with exception!');
+                    t.end();
+                }
+
+                t.pass('pass succeeded!');
+                t.end();
+            } else {
+                console.log(msg);
+                t.pass('pass with error!');
+                t.end();
+            }
+        })
+    });
+});
+//*/
+
+test('close the connection', function (t) {
+    setTimeout(function () {
+        mongoose.disconnect();
+        t.pass('closing db connection');
+        t.end();
+    }, 8000);
+    // mongoose.disconnect();
+    // t.pass('closing db connection');
+    // t.end();
+});

+ 6 - 6
test/unit/reports/test_tpl_09_1.js

@@ -62,7 +62,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.wirteObjToFile(result, "D:/GitHome/ConstructionCost/tmp/ProjectDataFullObject.js");
+            fsUtil.writeObjToFile(result, "D:/GitHome/ConstructionCost/tmp/ProjectDataFullObject.js");
             t.pass('pass succeeded!');
             t.end();
         } else {
@@ -91,8 +91,8 @@ test('测试 - 获取project部分数据: ', function (t) {
                     //     newData.push(JSON.stringify(item));
                     // }
                     // fsUtil.writeArrayToFile(newData, "D:/GitHome/ConstructionCost/tmp/getProjectData_partial.js");
-                    // fsUtil.wirteObjToFile(prjObj, "D:/GitHome/ConstructionCost/tmp/getProjectObjectNew.js");
-                    fsUtil.wirteObjToFile(results, "D:/GitHome/ConstructionCost/tmp/getProjectData_partialNew.js");
+                    // fsUtil.writeObjToFile(prjObj, "D:/GitHome/ConstructionCost/tmp/getProjectObjectNew.js");
+                    fsUtil.writeObjToFile(results, "D:/GitHome/ConstructionCost/tmp/getProjectData_partialNew.js");
                     t.pass('pass succeeded!');
                     t.end();
                 } else {
@@ -121,7 +121,7 @@ test('测试 - 测试模板啦: ', function (t) {
             if (!err) {
                 try {
                     let tplData = rptDataUtil.assembleData(rawDataObj);
-                    // fsUtil.wirteObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject.js");
+                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptTplRawDataObject.js");
                     //it's time to build the report!!!
                     let printCom = JpcEx.createNew();
                     rptTpl[JV.NODE_MAIN_INFO][JV.NODE_PAGE_INFO][JV.PROP_PAGE_SIZE] = pagesize;
@@ -134,7 +134,7 @@ test('测试 - 测试模板啦: ', function (t) {
                     if (pageRst) {
                         // fsUtil.wirteObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/testBuiltPageResult.js");
                     } else {
-                        console.log("oh! no pages were created!")
+                        console.log("oh! no pages were created!");
                     }
                 } catch (ex) {
                     console.log(ex);
@@ -180,7 +180,7 @@ test('测试 - 显示保存小数位数问题: ', function (t) {
     rpt_decimal_mdl.find({}).then(function (rst) {
         //console.log(rst);
         if (rst.length > 0) {
-            fsUtil.wirteObjToFile(rst, "D:/GitHome/ConstructionCost/tmp/testDecimalResult.js");
+            fsUtil.writeObjToFile(rst, "D:/GitHome/ConstructionCost/tmp/testDecimalResult.js");
         }
         t.pass('pass get decimal ok!');
         t.end();

+ 11 - 0
web/building_saas/glj/js/project_glj.js

@@ -179,6 +179,17 @@ $(document).ready(function () {
                     alert(msg);
                     return false;
                 }
+                projectObj.project.projectGLJ.loadData(function () {
+                    let projectGLJ = projectObj.project.projectGLJ;
+                    let data = projectGLJ.datas;
+                    projectGLJ.loadCacheData();
+                    let usedTenderList = data.usedTenderList !== undefined ? data.usedTenderList : [];
+                    let  usedUnitPriceInfo = data.constData.usedUnitPriceInfo !== undefined ?
+                        data.constData.usedUnitPriceInfo : {};
+
+                    unitPriceFileInit(usedUnitPriceInfo.name, usedTenderList);
+
+                });
                 $('#change-dj').modal("hide");
             }
         });

BIN
web/building_saas/img/NextPageSimple.cur


BIN
web/building_saas/img/PreviousPageSimple.cur


BIN
web/building_saas/img/baobiao.png


+ 2 - 0
web/building_saas/main/js/models/bills.js

@@ -182,6 +182,7 @@ var Bills = {
                     data.data.itemCharacter = stdBillsData.itemCharacter;
                     data.data.jobContentText = stdBillsData.jobContentText;
                     data.data.itemCharacterText = stdBillsData.itemCharacterText;
+                    data.data.programID = stdBillsData.engineering;
                     //zhong
                     newData = data.data;
                 }
@@ -332,6 +333,7 @@ var Bills = {
                 // 特征
                 node.data.itemCharacter = stdBillsData.itemCharacter;
                 node.data.itemCharacterText = stdBillsData.itemCharacterText;
+                node.data.programID = stdBillsData.engineering;
             }
             updateData.push({'updateType': 'ut_update', 'updateData': tools.formatBillsUpdateData(node.data)});
 

+ 72 - 42
web/building_saas/main/js/models/calc_program.js

@@ -272,39 +272,45 @@ let executeObj = {
 
             // 机上人工费:多一层
             if (isSubset(base.gljTypes, [gljType.MACHINE_LABOUR])) {
-                for (let glj of me.treeNode.data.gljList) {
-                    if (glj.type == gljType.GENERAL_MACHINE) {
-                        // 获取机械组成物
-                        let mds = projectObj.project.composition.getCompositionByCode(glj.code);
-                        if (!mds) mds = [];
-                        for (let md of mds){
-                            if (base.gljTypes.indexOf(md.glj_type) >= 0) {
-                                price = md["base_price"];
-                                if (!price) price = 0;
-                                mdSum = mdSum + (md["consumption"] * price).toDecimal(me.digit);
-                                mdSum = (mdSum).toDecimal(me.digitDefault);
-                            }
-                        };
-                        tmpSum = tmpSum + (glj["quantity"] * mdSum).toDecimal(me.digitDefault);
-                        tmpSum = (tmpSum).toDecimal(me.digitDefault);
-                    }
-                };
+                if (!me.treeNode.data.gljList) tmpSum = 0
+                else{
+                    for (let glj of me.treeNode.data.gljList) {
+                        if (glj.type == gljType.GENERAL_MACHINE) {
+                            // 获取机械组成物
+                            let mds = projectObj.project.composition.getCompositionByCode(glj.code);
+                            if (!mds) mds = [];
+                            for (let md of mds){
+                                if (base.gljTypes.indexOf(md.glj_type) >= 0) {
+                                    price = md["base_price"];
+                                    if (!price) price = 0;
+                                    mdSum = mdSum + (md["consumption"] * price).toDecimal(me.digit);
+                                    mdSum = (mdSum).toDecimal(me.digitDefault);
+                                }
+                            };
+                            tmpSum = tmpSum + (glj["quantity"] * mdSum).toDecimal(me.digitDefault);
+                            tmpSum = (tmpSum).toDecimal(me.digitDefault);
+                        }
+                    };
+                }
             }else{
-                for (let glj of me.treeNode.data.gljList) {
-                    if (base.gljTypes.indexOf(glj.type) >= 0) {
-                        if (base.calcType == baseCalc){ price = glj["basePrice"];}
-                        else if (base.calcType == adjustCalc){price = glj["adjustPrice"];}
-                        else if (base.calcType == budgetCalc){price = glj["marketPrice"];}
-                        else if (base.calcType == diffCalc){
-                            aprice = glj["adjustPrice"];
-                            if (!aprice) aprice = 0;
-                            mprice = glj["marketPrice"];
-                            if (!mprice) mprice = 0;
-                            price = mprice - aprice;
+                if (!me.treeNode.data.gljList) tmpSum = 0
+                else{
+                    for (let glj of me.treeNode.data.gljList) {
+                        if (base.gljTypes.indexOf(glj.type) >= 0) {
+                            if (base.calcType == baseCalc){ price = glj["basePrice"];}
+                            else if (base.calcType == adjustCalc){price = glj["adjustPrice"];}
+                            else if (base.calcType == budgetCalc){price = glj["marketPrice"];}
+                            else if (base.calcType == diffCalc){
+                                aprice = glj["adjustPrice"];
+                                if (!aprice) aprice = 0;
+                                mprice = glj["marketPrice"];
+                                if (!mprice) mprice = 0;
+                                price = mprice - aprice;
+                            };
+                            if (!price) price = 0;
+                            tmpSum = tmpSum + (glj["quantity"] * price).toDecimal(me.digitDefault);
+                            tmpSum = (tmpSum).toDecimal(me.digitDefault);
                         };
-                        if (!price) price = 0;
-                        tmpSum = tmpSum + (glj["quantity"] * price).toDecimal(me.digitDefault);
-                        tmpSum = (tmpSum).toDecimal(me.digitDefault);
                     };
                 };
             };
@@ -351,7 +357,9 @@ class CalcProgram {
         me.compiledFeeRates = {};
         me.compiledLabourCoes = {};
         me.compiledTemplates = {};
-        me.compiledFeeTypes = {};
+        me.compiledTemplateMaps = {};
+        me.compiledTemplateNames = [];
+        me.compiledFeeTypeMaps = {};
         me.compiledFeeTypeNames = [];
         me.compiledCalcBases = {};
         me.saveForReports = [];
@@ -391,8 +399,8 @@ class CalcProgram {
         }
 
         for (let ft of me.feeTypes) {
-            me.compiledFeeTypes[ft.type] = ft.name;
-            me.compiledFeeTypes[ft.name] = ft.type;    // 中文预编译,可靠性有待验证
+            me.compiledFeeTypeMaps[ft.type] = ft.name;
+            me.compiledFeeTypeMaps[ft.name] = ft.type;    // 中文预编译,可靠性有待验证
             me.compiledFeeTypeNames.push(ft.name);
         }
 
@@ -404,6 +412,9 @@ class CalcProgram {
     compileTemplate(template){
         let me = this;
         me.compiledTemplates[template.ID] = template;
+        me.compiledTemplateMaps[template.ID] = template.name;
+        me.compiledTemplateMaps[template.name] = template.ID;
+        me.compiledTemplateNames.push(template.name);
         template.hasCompiled = false;
         template.errs = [];
 
@@ -487,7 +498,7 @@ class CalcProgram {
                 };
 
                 // 字段名映射
-                item.displayFieldName = me.compiledFeeTypes[item.fieldName];
+                item.displayFieldName = me.compiledFeeTypeMaps[item.fieldName];
             }
         };
 
@@ -513,7 +524,7 @@ class CalcProgram {
         };
     };
 
-    // 内部调用,外部不能直接使用
+    // 仅内部调用。注意:外部不能直接使用
     InnerCalc(treeNode){
         let me = this;
         let project = me.project;
@@ -649,6 +660,7 @@ class CalcProgram {
             treeNode.calcType = treeNodeCalcType.ctRationCalcProgram
         else if (isLeafBill) {
             if (treeNode.children && treeNode.children.length > 0){
+                me.calcLeafBillChildren(treeNode);
                 if (treeNode.children[0].sourceType == me.project.Ration.getSourceType()){
                     if (isBillPriceCalc)                   // 清单单价计算模式下的叶子清单:取自己的计算程序ID,找到自己的计算程序计算
                         treeNode.calcType = treeNodeCalcType.ctBillCalcProgram;
@@ -696,7 +708,7 @@ class CalcProgram {
         me.saveNodes(nodesArr);
     };
 
-    // 待保存的树结点列表入库存储
+    // 多个树结点入库存储,刷新界面显示。
     saveNodes(treeNodes){
         if (treeNodes.length < 1) return;
 
@@ -709,6 +721,7 @@ class CalcProgram {
                     ID: node.data.ID,
                     projectID: me.project.ID(),
                     quantity: node.data.quantity,
+                    programID: node.data.programID,
                     fees: node.data.fees
                 };
                 let newData = {'updateType': 'ut_update', 'updateData': data};
@@ -719,13 +732,17 @@ class CalcProgram {
 
         for (let node of treeNodes){delete node.changed};
         projectObj.mainController.refreshTreeNode(treeNodes);
-    };
 
+        if (activeSubSheetIs(subSheetIndex.ssiCalcProgram)) {
+            calcProgramObj.showData(me.project.mainTree.selected, false);
+        };
+    };
 
-    // 参数取值如下:
-    // calcAllType.catAll       计算所有树结点 (不指定参数时的默认值)
-    // calcAllType.catBills     计算所有清单 (改变项目属性中清单取费算法时会用到)
-    // calcAllType.catRations   计算所有定额、工料机形式的定额、量价,因为它们都走自己的计算程序。 (改变人工系数、费率值、工料机单价时会用到)
+/*    计算所有树结点(分3种情况),并将发生计算改动的结点入库存储。
+    参数取值如下:
+    calcAllType.catAll       计算所有树结点 (不指定参数时的默认值)
+    calcAllType.catBills     计算所有清单 (改变项目属性中清单取费算法时会用到)
+    calcAllType.catRations   计算所有定额、工料机形式的定额、量价,因为它们都走自己的计算程序 (改变人工系数、费率值、工料机单价时会用到) */
     calcAllNodes(calcType = calcAllType.catAll){
         let me = this;
         let needSaveNodes = [];
@@ -746,4 +763,17 @@ class CalcProgram {
         calcNodes(me.project.mainTree.roots);
         me.saveNodes(needSaveNodes);
     };
+
+    // 重新计算叶子清单下的所有子结点:如定额、工料机定额等(calculate算法基于定额、工料机定额的计算结果是正确的,实际上有时它们的计算结果并不是最新的)
+    calcLeafBillChildren(treeNode){
+        let me = this;
+        if (treeNode.children && treeNode.children.length > 0) {
+            let needSaveNodes = [];
+            for (let child of treeNode.children){
+                me.calculate(child, false);
+                if (child.changed) needSaveNodes.push(child);
+            };
+            me.saveNodes(needSaveNodes);
+        };
+    };
 }

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

@@ -140,7 +140,6 @@ var ration_glj = {
             })
             _.forEach(doc, function(n, key) {
                 glj_list[glj_index][key] = n;
-                gljOprObj.sheetData[sheet_index][key]=n;
             });
             return glj_list[glj_index].rationID;
         };

+ 1 - 1
web/building_saas/main/js/views/calc_program_manage.js

@@ -33,7 +33,7 @@ let rationPM = {
         ],
         view:{
             comboBox:[],
-            lockColumns:[0,1,2,4,5,6],
+            lockColumns:[0,1,2,5,6],
             colHeaderHeight: CP_Col_Width.colHeader,
             rowHeaderWidth: CP_Col_Width.rowHeader
         }

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

@@ -14,6 +14,12 @@ let MainTreeCol = {
             } else if (node.sourceType === projectObj.project.ration_glj.getSourceType()) {
                 return '主';
             }
+        },
+
+        calcProgramName: function (node) {
+            let programID = node.data.programID;
+            if (!programID) return
+            else return projectObj.project.calcProgram.compiledTemplateMaps[programID];
         }
     },
     readOnly: {
@@ -69,6 +75,12 @@ let MainTreeCol = {
 
         feeRate: function () {
             return feeRateObject.getFeeRateEditCellType();
+        },
+
+        calcProgramName: function () {
+            var names = new GC.Spread.Sheets.CellTypes.ComboBox();
+            names.items(projectObj.project.calcProgram.compiledTemplateNames);
+            return names;
         }
      },
     getEvent: function (eventName) {

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

@@ -125,7 +125,11 @@ var projectObj = {
     checkSpreadEditingText: function (editingText, colSetting) {
         if (colSetting.data.field === 'quantity' || colSetting.data.field === 'feesIndex.common.unitFee') {
             return this.checkFormulaValidField(editingText, colSetting);
-        } else {
+        }
+        else if (colSetting.data.field === 'programID') {
+            return this.project.calcProgram.compiledTemplateMaps[editingText];
+        }
+        else {
             return this.checkCommonField(editingText, colSetting);
         }
     },
@@ -266,6 +270,7 @@ var projectObj = {
             } else if (fieldName === 'quantity' && project.quantity_detail.quantityEditChecking(value,node,fieldName)) {
                 if (value) {value = value.toDecimal(projectObj.project.Decimal.common.quantity);};
                 node.data.quantity = value;
+                node.changed = true;
                 project.calcProgram.calculate(node);
                 project.calcProgram.saveNode(node);
                 // projectObj.updateAndReCalculate(node, fieldName, value);
@@ -275,6 +280,11 @@ var projectObj = {
                 project.calcProgram.calculate(node);
                 project.calcProgram.saveNode(node);
                 // projectObj.updateAndReCalculate(node, fieldName, value);
+            } else if (fieldName === 'programID') {
+                node.data.programID = value;
+                node.changed = true;
+                project.calcProgram.calculate(node);
+                project.calcProgram.saveNode(node);
             } else if(fieldName ==='feeRate'){
                 project.FeeRate.updateFeeRateFromBills(value,node,fieldName);
             }else {
@@ -335,6 +345,7 @@ var projectObj = {
         this.project = PROJECT.createNew(scUrlUtil.GetQueryString('project'), userID);
         this.project.loadDatas(function (err) {
             if (!err) {
+                that.project.calcProgram.compileAllTemps();
                 that.project.calcFields = JSON.parse(JSON.stringify(feeType));
                 that.project.initCalcFields();
                 let str = JSON.stringify(that.project.projSetting.main_tree_col);
@@ -342,6 +353,13 @@ var projectObj = {
                 that.project.projSetting.mainGridSetting.frozenCols = 4;
                 TREE_SHEET_HELPER.initSetting($('#billsSpread')[0], that.project.projSetting.mainGridSetting);
                 that.project.projSetting.mainGridSetting.cols.forEach(function (col) {
+                    // for test.  后端没有绑定,暂时写死用于测试。
+                    if (col.data.field == '' && col.head.titleNames[0] == "取费专业") {
+                        col.data.field = 'programID';
+                        col.data.getText = 'getText.calcProgramName';
+                        col.data.cellType = 'cellType.calcProgramName';
+                    };
+
                     col.data.splitFields = col.data.field.split('.');
                     if (col.data.getText && Object.prototype.toString.apply(col.data.getText) === "[object String]") {
                         col.data.getText = MainTreeCol.getEvent(col.data.getText);
@@ -362,8 +380,6 @@ var projectObj = {
                     }
                 });
 
-                that.project.calcProgram.compileAllTemps();
-
                 that.mainController = TREE_SHEET_CONTROLLER.createNew(that.project.mainTree, that.mainSpread.getActiveSheet(), that.project.projSetting.mainGridSetting);
                 that.mainController.showTreeData();
                 that.mainController.bind('refreshBaseActn', that.refreshBaseActn);

+ 85 - 26
web/building_saas/report/js/jpc_output.js

@@ -17,26 +17,26 @@ let JpcCanvasOutput = {
 
         function private_setupAreaH(area, type, fontAngle, dftFontHeight, outputPoint) {
             let lType = type;
-            if (type != "left" && type != "right" && type != "center") lType = "left";
+            if (type !== "left" && type !== "right" && type !== "center") lType = "left";
             switch (lType) {
                 case "left":
-                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
                         outputPoint[1] = 1 * area[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
-                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
                         outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
                     } else outputPoint[0] = 1 * area[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
                     ctx.textAlign="start";
                     break;
                 case "right":
-                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
                         outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
-                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
                         outputPoint[1] = 1 * area[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
                     } else outputPoint[0] = 1 * area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
                     ctx.textAlign="end";
                     break;
                 case "center":
-                    if (fontAngle == JV.VERTICAL_ANGLE || fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT || fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
                         outputPoint[1] = (1 * area[JV.IDX_TOP] + 1 * area[JV.IDX_BOTTOM]) / 2;
                     } else outputPoint[0] = (1 * area[JV.IDX_LEFT] + 1 * area[JV.IDX_RIGHT]) / 2;
                     ctx.textAlign="center";
@@ -45,26 +45,26 @@ let JpcCanvasOutput = {
         }
         function private_setupAreaV(area, type, fontAngle, dftFontHeight, outputPoint) {
             let lType = type;
-            if (type != "top" && type != "bottom" && type != "center") lType = "top";
+            if (type !== "top" && type !== "bottom" && type !== "center") lType = "top";
             switch (lType) {
                 case "top":
-                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
                         outputPoint[0] = 1 * area[JV.IDX_RIGHT] - dftFontHeight - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
-                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
                         outputPoint[0] = 1 * area[JV.IDX_LEFT] + dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
                     } else outputPoint[1] = 1 * area[JV.IDX_TOP] + dftFontHeight + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
                     break;
                 case "bottom":
-                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
                         outputPoint[0] = 1 * area[JV.IDX_LEFT] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
-                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
                         outputPoint[0] = 1 * area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
                     } else outputPoint[1] = 1 * area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM];
                     break;
                 case "center":
-                    if (fontAngle == JV.VERTICAL_ANGLE) {
+                    if (fontAngle === JV.VERTICAL_ANGLE_INT) {
                         outputPoint[0] = (1 * area[JV.IDX_LEFT] + 1 * area[JV.IDX_RIGHT] - dftFontHeight) / 2;
-                    } else if (fontAngle == JV.ANTI_VERTICAL_ANGLE) {
+                    } else if (fontAngle === JV.ANTI_VERTICAL_ANGLE_INT) {
                         outputPoint[0] = (1 * area[JV.IDX_LEFT] + 1 * area[JV.IDX_RIGHT] + dftFontHeight) / 2;
                     } else outputPoint[1] = (1 * area[JV.IDX_TOP] + 1 * area[JV.IDX_BOTTOM] + dftFontHeight) / 2;
                     break;
@@ -74,31 +74,75 @@ let JpcCanvasOutput = {
             let dftFontHeight = 12;
             let output = [];
             if (font) {
-                dftFontHeight = 1 * font[JV.FONT_PROPS[1]];
+                dftFontHeight = parseFloat(font[JV.FONT_PROPS[1]]);
                 let dftOthers = "";
                 let dftFontBold = font[JV.FONT_PROPS[3]];
-                if (dftFontBold && dftFontBold == 'T') {
+                if (dftFontBold && dftFontBold === 'T') {
                     dftOthers = "bold " + dftOthers ;
                 }
                 let dftFontItalic = font[JV.FONT_PROPS[4]];
-                if (dftFontItalic && dftFontItalic == 'T') {
+                if (dftFontItalic && dftFontItalic === 'T') {
                     dftOthers = dftOthers + "italic ";
                 }
                 ctx.font = dftOthers + dftFontHeight + "px " + font[JV.PROP_NAME];
             }
             if (control) {
-                private_setupAreaH(area, control.Horizon, font.FontAngle, dftFontHeight, output);
-                private_setupAreaV(area, control.Vertical, font.FontAngle, dftFontHeight, output);
+                private_setupAreaH(area, control.Horizon, parseInt(font.FontAngle), dftFontHeight, output);
+                private_setupAreaV(area, control.Vertical, parseInt(font.FontAngle), dftFontHeight, output);
             } else {
-                private_setupAreaH(area, "left", font.FontAngle, dftFontHeight, output);
-                private_setupAreaV(area, "bottom", font.FontAngle, dftFontHeight, output);
+                private_setupAreaH(area, "left", parseInt(font.FontAngle), dftFontHeight, output);
+                private_setupAreaV(area, "bottom", parseInt(font.FontAngle), dftFontHeight, output);
             }
             let w = area[JV.IDX_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] - area[JV.IDX_LEFT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT];
-            if (font.FontAngle != "0") {
+            if ( parseInt(font.FontAngle) !== 0) {
                 w = area[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM] - area[JV.IDX_TOP] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP];
             }
+
+            function private_drawUnderline() {
+                //A. 暂不支持角度; B. 坐标已经translate
+                //1. 计算下划线的相关坐标
+                let width = ctx.measureText(val).width;
+                let height = dftFontHeight;
+                // let startX = area[JV.IDX_LEFT], startY = area[JV.IDX_TOP], endX = area[JV.IDX_RIGHT], endY = area[JV.IDX_BOTTOM];
+                let startX = 0, startY = 0, endX = width, endY = startY;
+                if (control.Horizon === "left") {
+                    // 无变化;
+                } else if (control.Horizon === "right") {
+                    startX = Math.round(startX - width);
+                } else {
+                    startX = Math.round(startX - width / 2);
+                }
+                endX = Math.round(startX + width);
+
+                if (control.Vertical === "top") {
+                    startY += JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
+                } else if (control.Vertical === "bottom") {
+                    // startY = Math.round(startY);
+                    startY += JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
+                } else {
+                    startY = Math.round(height / 2) - JV.OUTPUT_OFFSET[JV.IDX_TOP] - JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
+                    // startY += JV.OUTPUT_OFFSET[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
+                }
+                endY = Math.round(startY);
+                //2. 画线
+                // ctx.save();
+                if ( output[1] !== Math.round(output[1])) {
+                    ctx.translate(0,0.5);
+                }
+                ctx.beginPath();
+                ctx.moveTo(startX, startY);
+                ctx.lineWidth = 1;
+                ctx.strokeStyle = "BLACK";
+                ctx.lineTo(endX, endY);
+                ctx.stroke();
+                // ctx.restore();
+            }
+
             ctx.save();
             ctx.translate(output[0], output[1]);
+            if (font[JV.FONT_PROPS[5]] === 'T' && parseInt(font.FontAngle) === 0) {
+                private_drawUnderline();
+            }
             if (font.FontAngle === JV.VERTICAL_ANGLE) {
                 ctx.rotate(Math.PI/2);
             } else if (font.FontAngle === JV.ANTI_VERTICAL_ANGLE) {
@@ -121,8 +165,19 @@ let JpcCanvasOutput = {
         function private_drawCellText(cell, fonts, controls) {
             if (cell[JV.PROP_VALUE]) {
                 let values = ("" + cell[JV.PROP_VALUE]).split('|');
-                let font = fonts[cell[JV.PROP_FONT]];
-                let control = controls[cell[JV.PROP_CONTROL]];
+                let font = null;
+                if (typeof cell[JV.PROP_FONT] === "string") {
+                    font = fonts[cell[JV.PROP_FONT]];
+                } else {
+                    font = cell[JV.PROP_FONT];
+                }
+                //let control = controls[cell[JV.PROP_CONTROL]];
+                let control = null;
+                if (typeof cell[JV.PROP_CONTROL] === "string") {
+                    control = controls[cell[JV.PROP_CONTROL]];
+                } else {
+                    control = cell[JV.PROP_CONTROL];
+                }
                 if (control.ShowZero === "F") {
                     if (parseFloat(cell[JV.PROP_VALUE]) === 0.0) {
                         values = [""];
@@ -207,9 +262,7 @@ let JpcCanvasOutput = {
     },
     drawPageBorder: function(rptTpl, canvas, resolution) {
         let me = this;
-        let size = rptTpl[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE].slice(0);
-        size[0] = Math.round(resolution[0] * size[0]);
-        size[1] = Math.round(resolution[0] * size[1]);
+        let size = me.getReportSizeInPixel(rptTpl, resolution);
 
         let ctx = canvas.getContext("2d");
         ctx.save();
@@ -227,5 +280,11 @@ let JpcCanvasOutput = {
         ctx.fillStyle="black";
         ctx.fillRect(size[0] + me.offsetX,10 + me.offsetY,10,size[1]);
         ctx.fillRect(10 + me.offsetX,size[1] + me.offsetY,size[0],10);
+    },
+    getReportSizeInPixel: function(rptTpl, resolution) {
+        let rst = rptTpl[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE].slice(0);
+        rst[0] = Math.round(resolution[0] * rst[0]);
+        rst[1] = Math.round(resolution[0] * rst[1]);
+        return rst;
     }
 };

+ 3 - 1
web/building_saas/report/js/jpc_output_value_define.js

@@ -39,12 +39,14 @@ let JV = {
     PROP_COLOR: "Color",
     FONT_PROPS: ["Name", "FontHeight", "FontColor", "FontBold", "FontItalic", "FontUnderline", "FontStrikeOut", "FontAngle"],
 
-    OUTPUT_OFFSET: [2,1,2,3],
+    OUTPUT_OFFSET: [2,2,1,3],
     OFFSET_IDX_LEFT: 0,
     OFFSET_IDX_RIGHT: 1,
     OFFSET_IDX_TOP: 2,
     OFFSET_IDX_BOTTOM: 3,
 
+    VERTICAL_ANGLE_INT: 90,
+    ANTI_VERTICAL_ANGLE_INT: -90,
     VERTICAL_ANGLE: "90",
     ANTI_VERTICAL_ANGLE: "-90"
 };

+ 29 - 11
web/building_saas/report/js/rpt_main.js

@@ -67,7 +67,7 @@ let zTreeOprObj = {
         let canvas = document.getElementById("rptCanvas");
         if (treeNode.nodeType === TPL_TYPE_TEMPLATE && treeNode.refId > 0) {
             let params = {};
-            let pageSize = "A4";
+            let pageSize = rptHeaderObj.getCurrentPageSize();
             params.user_id = userID;
             params.pageSize = pageSize;
             params.rpt_tpl_id = treeNode.refId;
@@ -78,12 +78,12 @@ let zTreeOprObj = {
                         me.currentRptPageRst = pageRst;
                         me.maxPages = pageRst.items.length;
                         me.currentPage = 1;
-                        if (pageSize === "A4") {
-                            canvas.width = 1200;
-                            canvas.height = 900;
-                        } else if (pageSize === "A3") {
-                            canvas.width = 1880;
-                            canvas.height = 1200;
+                        let size = JpcCanvasOutput.getReportSizeInPixel(me.currentRptPageRst, getScreenDPI());
+                        canvas.width = size[0] + 20;
+                        if (size[1] > size[0]) {
+                            canvas.height = size[1] + 100;
+                        } else {
+                            canvas.height = size[1] + 50;
                         }
                         me.showPage(0, canvas);
                     }
@@ -107,10 +107,12 @@ let canvasOprObj = {
         let x = event.offsetX - JpcCanvasOutput.offsetX,
             canvas = event.originalTarget
         ;
-        if (x < 300) {
-            canvas.style.cursor = "e-resize";
-        } else if ((canvas.width - x) < 300) {
-            canvas.style.cursor = "w-resize";
+        if (x < 200) {
+            // canvas.style.cursor = "e-resize";
+            canvas.style.cursor = "url(/web/building_saas/img/PreviousPageSimple.cur), auto";
+        } else if ((canvas.width - x) < 200) {
+            // canvas.style.cursor = "w-resize";
+            canvas.style.cursor = "url(/web/building_saas/img/NextPageSimple.cur), auto";
         } else {
             canvas.style.cursor = "";
         }
@@ -126,3 +128,19 @@ let canvasOprObj = {
         }
     }
 };
+
+let rptHeaderObj = {
+    getCurrentPageSize: function() {
+        let rst = "A4";
+        //
+        return rst;
+    },
+    getCurrentOrientation: function() {
+        let rst = "横向";
+        //
+        return rst;
+    },
+    getExcel: function() {
+        //目前只支持当前打开报表
+    }
+};