Browse Source

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

zhangweicheng 7 năm trước cách đây
mục cha
commit
a6ff1d1341

+ 1 - 0
config/gulpConfig.js

@@ -100,6 +100,7 @@ module.exports = {
         'web/building_saas/main/js/views/project_property_decimal_view.js',
         'web/building_saas/main/js/views/project_property_basicInfo.js',
         'web/building_saas/main/js/views/project_property_projFeature.js',
+        'web/building_saas/main/js/views/project_property_indicativeInfo.js',
         'web/building_saas/main/js/views/project_property_display_view.js',
         'web/building_saas/main/js/main_ajax.js',
         'web/building_saas/main/js/main.js',

+ 1 - 0
modules/reports/rpt_component/helper/jpc_helper_common.js

@@ -70,6 +70,7 @@ let JpcCommonHelper = {
         let me = this, arrDPI = [];
         if (!me.commonConstant.resolution) {
             arrDPI = [96,96];
+            // arrDPI = [100,100];
             me.commonConstant.resolution = arrDPI;
         } else {
             arrDPI = me.commonConstant.resolution;

+ 20 - 0
modules/reports/rpt_component/helper/jpc_helper_field.js

@@ -20,6 +20,7 @@ let JpcFieldHelper = {
         }
     },
     findAndPutDataFieldIdx: function (rptTpl, tab_fields, rstFields, rstFieldsIdx, isEx) {
+        //通过FieldID找到相关映射指标的位置IDX并记录下来,方便后续引用
         if (tab_fields) {
             let DTL_STR = isEx?JV.NODE_DETAIL_FIELDS_EX:JV.NODE_DETAIL_FIELDS;
             let detail_fields = rptTpl[JV.NODE_FIELD_MAP][DTL_STR];
@@ -39,6 +40,25 @@ let JpcFieldHelper = {
                 }
             }
         }
+    },
+    findAutoHeightFieldIdx: function(rptTpl, tab_fields, rstFieldsIdx, isEx) {
+        if (tab_fields) {
+            let DTL_STR = isEx?JV.NODE_DETAIL_FIELDS_EX:JV.NODE_DETAIL_FIELDS;
+            let detail_fields = rptTpl[JV.NODE_FIELD_MAP][DTL_STR];
+            for (let i = 0; i < tab_fields.length; i++) {
+                if (tab_fields[i][JV.PROP_IS_AUTO_HEIGHT]) {
+                    for (let j = 0; j < detail_fields.length; j++) {
+                        if (tab_fields[i]["FieldID"] === detail_fields[j]["ID"]) {
+                            let item = [];
+                            item[0] = j;
+                            item[1] = tab_fields[i];
+                            rstFieldsIdx.push(item);
+                            break;
+                        }
+                    }
+                }
+            }
+        }
     }
 };
 

+ 53 - 97
modules/reports/rpt_component/jpc_flow_tab.js

@@ -9,6 +9,7 @@ let JpcDiscreteHelper = require('./helper/jpc_helper_discrete');
 let JpcTextHelper = require('./helper/jpc_helper_text');
 let JpcCommonOutputHelper = require('./helper/jpc_helper_common_output');
 let JpcAreaHelper = require('./helper/jpc_helper_area');
+let PDFKit = require('pdfkit');
 
 let JpcFlowTabSrv = function(){};
 //let grpPageInfo = {"segGrpRecStartIdx": 0, "insertedGrpRecAmt": 0, "preAddPageGrpInfo": null};
@@ -87,6 +88,8 @@ JpcFlowTabSrv.prototype.createNew = function(){
         me.page_sum_fields_idx = [];
         me.page_sum_tab_fields = [];
 
+        me.auto_height_fields_idx = [];//那些被标记为判断自动行高的指标集合
+        me.auto_height_info = [];
         me.group_fields = [];
         me.group_sum_fields = [];
         me.group_sum_values = null;
@@ -107,6 +110,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
         JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_PAGE_SUM][JV.PROP_SUM_FIELDS], me.page_sum_tab_fields, me.page_sum_fields_idx, me.isEx);
         JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_GROUP][JV.PROP_GROUP_FIELDS], me.group_fields, null, me.isEx);
         JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_GROUP][JV.PROP_SUM_FIELDS], me.group_sum_fields, null, me.isEx);
+        JpcFieldHelper.findAutoHeightFieldIdx(rptTpl, rptTpl[FLOW_NODE_STR][JV.NODE_FLOW_CONTENT][JV.PROP_FLOW_FIELDS], me.auto_height_fields_idx, me.isEx);
         for (let si = 0; si < dataSeq.length; si++) {
             me.segments.push(dataSeq[si].slice(0));
         }
@@ -209,6 +213,49 @@ JpcFlowTabSrv.prototype.createNew = function(){
             }
         }
     };
+    JpcFlowTabResult.setupAutoHeightData = function(bands, segIdx, rptTpl, dataObj, $CURRENT_RPT) {
+        let me = this;
+        let CURRENT_FLOW_INFO = (me.isEx)?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;
+        let band = bands[rptTpl[CURRENT_FLOW_INFO][JV.NODE_FLOW_CONTENT][JV.BAND_PROP_NAME]];
+        let data_details = me.isEx?dataObj[JV.DATA_DETAIL_DATA_EX]:dataObj[JV.DATA_DETAIL_DATA];
+        let reg1 = new RegExp('\n\r','g'), reg2 = new RegExp('\r\n','g'),
+            reg3 = new RegExp('\n','g'), reg4 = new RegExp('\r','g');
+        let doc = new PDFKit({autoFirstPage: false});
+        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++) {
+                let data_field = null;
+                let tab_field = me.auto_height_fields_idx[loop][1];
+                if (me.auto_height_fields_idx[loop][0] !== JV.BLANK_FIELD_INDEX) {
+                    data_field = data_details[me.auto_height_fields_idx[loop][0]];
+                }
+                if (data_field) {
+                    let value = JpcFieldHelper.getValue(data_field, theRecIdx);
+                    let area = JpcAreaHelper.outputArea(tab_field[JV.PROP_AREA], band, 1, 1, 0, 1, 0, 1, 0, false, false);
+                    if (value !== null && value !== undefined) {
+                        value = value.replace(reg1, '|').replace(reg2, '|').replace(reg3, '|').replace(reg4, '|');
+                    } else {
+                        value = '';
+                    }
+                    let values = value.split('|');
+                    if (values.length > rst) rst = values.length;
+                }
+            }
+            return rst;
+        };
+        if (me.auto_height_fields_idx.length > 0 && me.auto_height_info.length === segIdx) {
+            //自动行高功能,需要考虑以下情况:
+            //1. 每一Segment的需要增加行的数量
+            me.auto_height_info.push([]);
+            //rst[JV.PROP_AREA] = JpcAreaHelper.outputArea(textNode[JV.PROP_AREA], band, unitFactor, rows, rowIdx, cols, colIdx, multiCols, multiColIdx, false, false);
+            let segArr = me.segments[segIdx];
+            for (let i = 0; i < segArr.length; i++) {
+                //
+            }
+            //2.
+            //rptTpl[CURRENT_FLOW_INFO][JV.NODE_FLOW_GROUP][JV.PROP_GROUP_LINES].length;
+        }
+    };
 
     JpcFlowTabResult.preSetupPages = function (rptTpl, dataObj, defProperties, option, $CURRENT_RPT, followTabEx) {
         //换一种思路来整理流水式数据
@@ -302,13 +349,14 @@ JpcFlowTabSrv.prototype.createNew = function(){
                 currentRecAmt = 0;
                 counterRowRec = 0;
                 counterRowRecEx = 0;
-                let ttlSegRecAmtNormal = me.segments[segIdx].length + grpRecAmt;
-                let ttlSegRecAmt = (followTabEx)?(me.segments[segIdx].length + grpRecAmt + followTabEx.segments[segIdx].length + grpRecAmtEx):(me.segments[segIdx].length + grpRecAmt);
+                let ttlSegRecAmtNormal = me.segments[segIdx].length + grpRecAmt; //正常的segment下的数据长度累计(含grouping data)
+                let ttlSegRecAmt = (followTabEx)?(me.segments[segIdx].length + grpRecAmt + followTabEx.segments[segIdx].length + grpRecAmtEx):(me.segments[segIdx].length + grpRecAmt); //所有的segment下的数据长度累计(包括ex部分)
                 while (true) {
                     if (currentRecAmt > 0) pageStatus[JV.STATUS_SEGMENT_START] = false;
                     if (pageIdx > 0) pageStatus[JV.STATUS_REPORT_START] = false;
                     //开始判断各种scenarios
                     if (ttlSegRecAmtNormal < ttlSegRecAmt) {
+                        //有流水拓展,并且是follow mode
                         if (currentRecAmt + maxRowRec > ttlSegRecAmtNormal) {
                             if (currentRecAmt >= ttlSegRecAmtNormal) {
                                 //纯 followTabEx 数据
@@ -355,6 +403,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                             private_addPage(segIdx, grpSeqInfo, false, false, -1);
                         }
                     } else {
+                        //普通流水数据情况
                         if (currentRecAmt + maxRowRec >= ttlSegRecAmt) {
                             pageStatus[JV.STATUS_SEGMENT_END] = true;
                             pageStatus[JV.STATUS_REPORT_END] = true;
@@ -379,9 +428,9 @@ JpcFlowTabSrv.prototype.createNew = function(){
                         //备注:这里必须得考虑多栏的情况,否则会造成pageStatus出界的问题
                         break;
                     }
-                    //控制阀值,超过阀值则强制退出,防止死循环
+                    //控制阈值,超过阈值则强制退出,防止死循环
                     threshold++;
-                    if (threshold > 500) {
+                    if (threshold > 1000) {
                         console.log("Hey! There may be a dead loop here!!!");
                         break;
                     }
@@ -394,99 +443,6 @@ JpcFlowTabSrv.prototype.createNew = function(){
         return rst;
     };
 
-    JpcFlowTabResult.preSetupPages_Org = function (rptTpl, dataObj, defProperties, option, $CURRENT_RPT, followTabEx) {
-        let me = this, rst = 1, counterRowRec = 0, maxRowRec = 1, pageIdx = 0;
-        me.setupGroupingData(rptTpl, dataObj, $CURRENT_RPT);
-        if (followTabEx) {
-            followTabEx.setupGroupingData(rptTpl, dataObj, $CURRENT_RPT);
-        }
-        //console.log(me.group_sum_values);
-        me.paging_option = option||JV.PAGING_OPTION_NORMAL;
-        let CURRENT_FLOW_INFO = (me.isEx)?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;
-        JpcFieldHelper.findAndPutDataFieldIdx(rptTpl, rptTpl[CURRENT_FLOW_INFO][JV.NODE_FLOW_CONTENT][JV.PROP_FLOW_FIELDS], null, me.disp_fields_idx, me.isEx);
-        if (me.paging_option === JV.PAGING_OPTION_INFINITY) {
-            rst = me.segments.length;
-            let pageStatus = [true, true, false, true, true, true, false, false];
-            for (let segIdx = 0; segIdx < me.segments.length; segIdx++) {
-                if (segIdx === me.segments.length - 1) {
-                    pageStatus[JV.STATUS_REPORT_END] = true;
-                }
-                if (segIdx > 0) {
-                    pageStatus[JV.STATUS_REPORT_START] = false;
-                }
-                me.pageStatusLst.push(pageStatus.slice(0));
-                pageIdx++;
-                let grpSeqInfo = (me.group_node_info)?me.group_node_info[segIdx]:null;
-                private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], grpSeqInfo, 0, me.segments[segIdx].length, me.page_seg_map, segIdx, pageIdx, null, false);
-                if (followTabEx) {
-                    //
-                }
-            }
-        } else {
-            let bands = JpcBand.createNew(rptTpl, defProperties);
-            let pageStatus = [true, true, false, true, false, false, false, false];
-            if (me.isEx) {
-                pageStatus[JV.STATUS_REPORT_START] = false;
-            }
-            if (rptTpl[CURRENT_FLOW_INFO][JV.PROP_MULTI_COLUMN]) {
-                me.multiCols = 1 * rptTpl[CURRENT_FLOW_INFO][JV.PROP_MULTI_COLUMN];
-            }
-            function private_resetBandArea() {
-                JpcBandHelper.setBandArea(bands, rptTpl, pageStatus, !me.isEx, me.isEx);
-                maxRowRec = JpcFlowTabHelper.getMaxRowsPerPage(bands, rptTpl, me.isEx);
-            }
-            let grpPageInfo = {};
-            for (let segIdx = 0; segIdx < me.segments.length; segIdx++) {
-                let grpSeqInfo = (me.group_node_info)?me.group_node_info[segIdx]:null;
-                grpPageInfo[JV.PROP_SEG_GRP_IDX] = 0;
-                grpPageInfo[JV.PROP_INSERTED_GRP_REC] = 0;
-                grpPageInfo[JV.PROP_PRE_ADD_GRP_REC_INFO] = [];
-                grpPageInfo[JV.PROP_GRP_LINES] = me.group_lines_amt;
-                private_resetBandArea();
-                let orgMaxRowRec = maxRowRec;
-                let grpRecAmt = (grpSeqInfo)?(grpSeqInfo.length*me.group_lines_amt):0;
-                let grpRecAmtEx = 0;
-                let rowSplitCnt = Math.ceil(1.0 * (me.segments[segIdx].length + grpRecAmt) / orgMaxRowRec);
-                let rowSplitCntEx = rowSplitCnt;
-                if (followTabEx) {
-                    rowSplitCntEx = Math.ceil(1.0 * (me.segments[segIdx].length + grpRecAmt + followTabEx.segments[segIdx].length + grpRecAmtEx) / orgMaxRowRec);
-                }
-                pageStatus[JV.STATUS_SEGMENT_END] = true;
-                private_resetBandArea();
-                let len = (followTabEx)?(me.segments[segIdx].length + grpRecAmt + followTabEx.segments[segIdx].length + grpRecAmtEx):(me.segments[segIdx].length + grpRecAmt);
-                //let hasAdHocRow = !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, me.segments[segIdx].length, (rowSplitCntEx - 1) * orgMaxRowRec, maxRowRec, me.isEx);
-                let hasAdHocRow = !JpcFlowTabHelper.chkSegEnd(bands, rptTpl, len, (rowSplitCntEx - 1) * orgMaxRowRec, maxRowRec, me.isEx);
-                if (hasAdHocRow) rowSplitCntEx++;
-                if (rowSplitCntEx % me.multiCols > 0) {
-                    rowSplitCntEx++
-                }
-                counterRowRec = 0;
-                for (let segPageIdx = 0; segPageIdx < rowSplitCntEx; segPageIdx++) {
-                    pageStatus[JV.STATUS_SEGMENT_END] = (segPageIdx === (rowSplitCntEx - 1));
-                    if (pageIdx > 0) pageStatus[JV.STATUS_REPORT_START] = false;
-                    private_resetBandArea();
-                    me.pageStatusLst.push(pageStatus.slice(0));
-                    pageIdx++;
-                    if (followTabEx) {
-                        //
-                    } else {
-                        //
-                    }
-                    private_addPageValue(me.dispValueIdxLst, me.segments[segIdx], grpSeqInfo, counterRowRec, maxRowRec,me.page_seg_map, segIdx, pageIdx, grpPageInfo, false);
-                    //备注: 考虑到分组数据是临时融入的,所以需要知道这一页的数据融入了多少条group数据,并且得考虑边界条件情况(group数据可能跨页!)
-                    for (let dv of me.dispValueIdxLst[me.dispValueIdxLst.length - 1]) {
-                        if (dv[1] === JV.DISPLAY_VAL_TYPE_NORMAL) counterRowRec++;
-                    }
-                }
-                pageStatus[JV.STATUS_SEGMENT_END] = false;
-                pageStatus[JV.STATUS_REPORT_START] = false;
-            }
-            // console.log(me.dispValueIdxLst);
-            rst = Math.ceil(pageIdx / me.multiCols);
-        }
-        me.pagesAmt = rst;
-        return rst;
-    };
     JpcFlowTabResult.outputAsSimpleJSONPage = function (rptTpl, dataObj, page, bands, controls, adHocMergePos, $CURRENT_RPT) {
         let me = this, rst = [], tabRstLst = [];
         let FLOW_NODE_STR = me.isEx?JV.NODE_FLOW_INFO_EX:JV.NODE_FLOW_INFO;

+ 19 - 65
modules/reports/util/rpt_excel_util.js

@@ -339,7 +339,6 @@ function writeSheets(pageData, paperSize, sharedStrList, stylesObj, isSinglePage
 }
 function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
     let rst = [], xPos = [], yPos = [], yMultiPos = [], headerStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
-    let cacheBorderCell = {};
     let currentPageMergePos = null; //在 JV.PAGING_OPTION_INFINITY 场合应用
     let private_pre_analyze_pos = function(){
         let cell, pos;
@@ -380,11 +379,16 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
             yPos.sort(private_array_sort);
         } else {
             //total data in one sheet
+            let marginBottomPos = Math.round( (pageData[JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][1] - parseFloat(pageData[JV.NODE_PAGE_INFO][JV.NODE_MARGINS][JV.PROP_BOTTOM]) / 2.54 ) * DPI);
             for (let shtItemData of pageData.items) {
                 let tmpPos = [];
                 tmpPos.push(0);
                 self_analyze_sheet_pos(shtItemData, xPos, tmpPos);
                 tmpPos.sort(private_array_sort);
+                if (marginBottomPos - tmpPos[tmpPos.length - 1] > 10) {
+                    //此逻辑是为了防止打印跨页(假设有些报表模板高度设置离底部margin还好远,导出excel后预览时会发现跨页现象(即下一页的某几行数据会挪到前一页来预览))
+                    tmpPos.push(marginBottomPos - 10);
+                }
                 yMultiPos.push(tmpPos);
             }
             xPos.sort(private_array_sort);
@@ -627,20 +631,12 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
         //remark: 1 excel unit width = 2.117 mm
         rst.push('<cols>');
         let w = 0;
-        /*
         for (let i = 1; i < xPos.length - 1; i++) {
             w = 1.0 * (xPos[i + 1] - xPos[i]) / DPI * 25.4 / 2.117;
             w = Math.round(w * 1000) / 1000;
             rst.push('<col min="' + i +'" max="' + i +'" width="' + w + '" customWidth="1"/>');
         }
-        /*/
-        for (let i = 1; i < xPos.length - 2; i++) {
-            w = 1.0 * (xPos[i + 1] - xPos[i]) / DPI * 25.4 / 2.117;
-            w = Math.round(w * 1000) / 1000;
-            rst.push('<col min="' + i +'" max="' + i +'" width="' + w + '" customWidth="1"/>');
-        }
         rst.push('<col min="' + (xPos.length - 1) +'" max="' + (xPos.length - 1) +'" width="' + 10 + '" customWidth="1"/>');
-        //*/
         rst.push('</cols>');
     };
     let private_setMergedCells = function() {
@@ -674,58 +670,11 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
         rst[startIdx] = '<mergeCells count="' + cnt + '">';
         rst.push('</mergeCells>');
     };
-    let private_chkIfNeedCacheCell = function(cell){
-        let rst = false;
-        if (cell[JV.PROP_AREA][JV.PROP_LEFT] === pageData[JV.BAND_PROP_MERGE_BAND][JV.PROP_LEFT] ||
-            cell[JV.PROP_AREA][JV.PROP_RIGHT] === pageData[JV.BAND_PROP_MERGE_BAND][JV.PROP_RIGHT] ||
-            cell[JV.PROP_AREA][JV.PROP_TOP] === pageData[JV.BAND_PROP_MERGE_BAND][JV.PROP_TOP] ||
-            cell[JV.PROP_AREA][JV.PROP_BOTTOM] === pageData[JV.BAND_PROP_MERGE_BAND][JV.PROP_BOTTOM]){
-            if (cell[JV.PROP_AREA][JV.PROP_LEFT] >= pageData[JV.BAND_PROP_MERGE_BAND][JV.PROP_LEFT] &&
-                cell[JV.PROP_AREA][JV.PROP_RIGHT] <= pageData[JV.BAND_PROP_MERGE_BAND][JV.PROP_RIGHT] &&
-                cell[JV.PROP_AREA][JV.PROP_TOP] >= pageData[JV.BAND_PROP_MERGE_BAND][JV.PROP_TOP] &&
-                cell[JV.PROP_AREA][JV.PROP_BOTTOM] <= pageData[JV.BAND_PROP_MERGE_BAND][JV.PROP_BOTTOM]) {
-                rst = true;
-            }
-        }
-        return rst;
-    };
-    let private_cacheMergeBandBorderIdxs = function() {
-        let cell, idxR, idxL, idxT, idxB;
-        let self_cachMergeIdxs = function (theData, theYPos, offsetY) {
-            for (let i = 0; i < theData.cells.length; i++) {
-                cell = theData.cells[i];
-                idxR = xPos.indexOf(cell[JV.PROP_AREA][JV.PROP_RIGHT]);
-                idxL = xPos.indexOf(cell[JV.PROP_AREA][JV.PROP_LEFT]);
-                idxB = theYPos.indexOf(cell[JV.PROP_AREA][JV.PROP_BOTTOM]);
-                idxT = theYPos.indexOf(cell[JV.PROP_AREA][JV.PROP_TOP]);
-                if (idxR - idxL > 1 || idxB - idxT > 1) {
-                    if (private_chkIfNeedCacheCell(cell)) {
-                        for (let xi = idxL; xi < idxR; xi++) {
-                            for (let yj = idxT; yj < idxB; yj++) {
-                                cacheBorderCell[private_getCellIdxStr(xi - 1) + (yj + offsetY)] = cell;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        if (sheetData) {
-            self_cachMergeIdxs(sheetData, yPos, 0);
-        } else {
-            let osY = 0;
-            for (let i = 0; i < pageData.items.length; i++) {
-                let shtItemData = pageData.items[i];
-                let tmpPos = yMultiPos[i];
-                self_cachMergeIdxs(shtItemData, tmpPos, osY);
-                osY += tmpPos.length - 2;
-            }
-        }
-    };
     let private_setSheetData = function(){
         //remark: 1 excel unit height = 0.3612 mm
         rst.push('<sheetData>');
         let spanX = xPos.length - 2, cellIdx = 0, h = 0
-            ;
+        ;
         let self_setDataEx = function (theShtData, theYPos, offsetY) {
             let rows = [];
             //1. build full set of blank rows/cells
@@ -791,7 +740,6 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
             //4. maybe need to dispose the memory
             //...
         };
-        //private_cacheMergeBandBorderIdxs();
         if (sheetData) {
             //current sheet data
             currentPageMergePos = sheetData[JV.PAGE_SPECIAL_MERGE_POS];
@@ -825,7 +773,9 @@ function writeSheet(pageData, sheetData, paperSize, sharedStrList, stylesObj){
     private_setSheetData();
     private_setMergedCells();
     rst.push('<phoneticPr fontId="1" type="noConversion"/>');
-    rst.push('<pageMargins left="0.315" right="0.215" top="0.315" bottom="0.315" header="0" footer="0"/>');
+    // rst.push('<pageMargins left="0.315" right="0.215" top="0.315" bottom="0.315" header="0" footer="0"/>');
+    rst.push('<pageMargins left="' + (parseFloat(pageData[JV.NODE_PAGE_INFO][JV.NODE_MARGINS][JV.PROP_LEFT]) * 0.39375) +
+        '" right="0.215" top="0.315" bottom="0.315" header="0" footer="0"/>');
     let paperSizeIdx = JV.PAGES_SIZE_STR.indexOf(paperSize);
     let pStr = '';
     if (paperSizeIdx >= 0) {
@@ -936,12 +886,12 @@ module.exports = {
             zip.generateNodeStream({type:'nodebuffer',streamFiles:true})
                 .pipe(fs.createWriteStream(__dirname.slice(0, __dirname.length - 21) + '/tmp/' + newName + '.xlsx'))
                 .on('finish', function () {
-                    // JSZip generates a readable stream with a "end" event,
-                    // but is piped here in a writable stream which emits a "finish" event.
-                    console.log(newName + ".xlsx was written.");
-                    if (callback) callback(newName);
-                }
-            );
+                        // JSZip generates a readable stream with a "end" event,
+                        // but is piped here in a writable stream which emits a "finish" event.
+                        console.log(newName + ".xlsx was written.");
+                        if (callback) callback(newName);
+                    }
+                );
         } else {
             //return zip.generateNodeStream({type:'nodebuffer',streamFiles:true});
             return zip;
@@ -1001,7 +951,11 @@ module.exports = {
                         pageDataArray[i].items[j].cells[k][JV.PROP_AREA][JV.PROP_BOTTOM] += offsetY;
                         pageDataArray[i].items[j].cells[k][JV.PROP_AREA][JV.PROP_TOP] += offsetY;
                     }
+                    let bottomGap = Math.round( (pageDataArray[i][JV.NODE_PAGE_INFO][JV.NODE_PAGE_SIZE][1] - parseFloat(pageDataArray[i][JV.NODE_PAGE_INFO][JV.NODE_MARGINS][JV.PROP_BOTTOM]) / 2.54 ) * DPI) - maxY;
                     offsetY += (maxY - minY);
+                    if (bottomGap > 10) {
+                        offsetY += (bottomGap - 10);
+                    }
                 }
             }
             //2. newPageData的items属性

+ 1 - 0
public/web/rpt_value_define.js

@@ -107,6 +107,7 @@ const JV = {
     PROP_POSITION: "Position",
     PROP_HIDDEN: "Hidden",
     PROP_IS_SERIAL: "isSerial",
+    PROP_IS_AUTO_HEIGHT: "isAutoHeight",
     PROP_FONT: "font",
     PROP_CONTROL: "control",
     PROP_STYLE: "style",

+ 17 - 33
public/web/sheet/sheet_common.js

@@ -395,7 +395,7 @@ var sheetCommonObj = {
     },
     //设置系统粘贴板数据,需要用户触发事件,直接调用会失败
     copyTextToClipboard: function(text) {
-        var textArea = document.createElement("textarea");
+        let textArea = document.createElement("textarea");
         textArea.style.position = 'fixed';
         textArea.style.top = 0;
         textArea.style.left = 0;
@@ -410,8 +410,8 @@ var sheetCommonObj = {
         document.body.appendChild(textArea);
         textArea.select();
         try {
-            var successful = document.execCommand('copy');
-            var msg = successful ? 'successful' : 'unsuccessful';
+            let successful = document.execCommand('copy');
+            let msg = successful ? 'successful' : 'unsuccessful';
             console.log('Copying text command was ' + msg);
         } catch (err) {
             console.log('Oops, unable to copy');
@@ -422,38 +422,22 @@ var sheetCommonObj = {
     getTableData: function (sheet, colSettings = null) {
         let rst = '';
         let sel = sheet.getSelections()[0];
-        let vRows = [];
-        for(let i = sel.row, len = sel.row + sel.rowCount; i < len; i++){
-            if(sheet.getCell(i, -1).visible()){
-                vRows.push(i);
-            }
-        }
-        for(let row of vRows){
-            rst += '\n';
-            for(let j = 0, jLen = sel.colCount; j <jLen; j++){
+        let pasteText = [];
+        for(let row = sel.row; row < sel.row + sel.rowCount; row++){
+            if(!sheet.getCell(row, -1).visible())
+                continue;
+            let rowText = [];
+            for(let j = 0; j < sel.colCount; j++){
                 let col = sel.col + j;
-                if(sheet.getCell(-1, col).visible()){
-                    let v = '';
-                    if(colSettings && (colSettings[col]['data']['field'] === 'itemCharacterText' || colSettings[col]['data']['field'] === 'jobContentText')){
-                       // v += sheet.getText(row, col) ? sheet.getText(row, col).replace(new RegExp('\n', 'g'), '\v') : '';
-                        v += sheet.getText(row, col) ? `"${sheet.getText(row, col)}"` : '';
-                        if(j !== jLen - 1){
-                            v += '\t';
-                        }
-                    }
-                    else {
-                        if(j === jLen - 1){
-                            v += sheet.getText(row, col) ? sheet.getText(row, col).replace('\n', '') : '';
-                        }
-                        else {
-                            v += sheet.getText(row, col) ? sheet.getText(row, col).replace('\n', '') + '\t' : '\t';
-                        }
-                    }
-                    rst += v;
-                }
+                if(!sheet.getCell(-1, col).visible())
+                    continue;
+                if(colSettings && (colSettings[col]['data']['field'] === 'itemCharacterText' || colSettings[col]['data']['field'] === 'jobContentText'))
+                    rowText.push(sheet.getText(row, col) ? `"${sheet.getText(row, col)}"` : '');
+                else
+                    rowText.push(sheet.getText(row, col) ? sheet.getText(row, col): '');
             }
+            pasteText.push(rowText.join('\t'));
         }
-        rst = rst.replace('\n', '');
-        return rst;
+        return pasteText.join('\n');
     }
 }

+ 11 - 1
public/web/tree_sheet/tree_sheet_helper.js

@@ -334,8 +334,18 @@ var TREE_SHEET_HELPER = {
         };
         TipCellType.prototype.processMouseEnter = function (hitinfo) {
             let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
+            let value = hitinfo.sheet.getValue(hitinfo.row, hitinfo.col);
             let tag = hitinfo.sheet.getTag(hitinfo.row, hitinfo.col);
-            if(setting.cols[hitinfo.col].data.field=="quantity"){
+            let acStyle = hitinfo.sheet.getActualStyle(hitinfo.row, hitinfo.col),
+                zoom = hitinfo.sheet.zoom();
+            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(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) {
                 text = tag;

+ 67 - 6
public/web/tree_table/tree_table.js

@@ -232,14 +232,14 @@
  			_view._removeNodesRowDom([node]);
  		};
 
- 		Tree.prototype.loadData = function (arrData) {
+ 		/*Tree.prototype.loadData = function (arrData) {
  			var i, that = this;
 			var createTempNode = function (id, setting) {
 				var tempData = {};
 				tempData[setting.tree.id] = id;
 				return new Node(that, tempData);
 			};
-			var loadNode = function (data, setting) {
+			var loadNode = function (data, setting) {//mark
 				var	node = that.findNode(data[setting.tree.id]) || null,
  					parent = that.findNode(data[setting.tree.pid]) || null,
  					next = that.findNode(data[setting.tree.nid]) || null,
@@ -282,8 +282,8 @@
  						parent.children.splice(parent.childIndex(next), 0, node);
  					}
  				} else if (node.nextSibling && parent.childIndex(node) !== parent.childIndex(node.nextSibling) - 1) {
-					parent.children.splice(parent.childIndex(node), 1);
-					parent.children.splice(parent.childIndex(next), 0, node);
+					parent.children.splice(parent.childIndex(next), 1);
+					parent.children.splice(parent.childIndex(node) + 1, 0, next);
 				};
 				let pre = that.findNodeByNid(node.data.ID) || null;
 				if(pre && parent.childIndex(pre) !== parent.childIndex(node) - 1){
@@ -295,7 +295,67 @@
  			for (i = 0; i < arrData.length; i++){
  				loadNode(arrData[i], this.setting);
  			}
- 		};
+ 		};*/
+
+		Tree.prototype.loadData = function (arrData) {
+			let i, that = this;
+			let nodesIndex = {};
+			function getPreNode(id){
+				for(let index in nodesIndex){
+					let node = nodesIndex[index];
+					if(node['data'][node.setting.tree.nid] === id){
+						return node;
+					}
+				}
+				return null;
+			}
+			function loadNode (data, setting) {//mark
+				var	node = nodesIndex[data[setting.tree.id]] || null,
+					parent = nodesIndex[data[setting.tree.pid]] || that._root,
+					next = nodesIndex[data[setting.tree.nid]] || null,
+					pre = getPreNode(data[setting.tree.id]) || null,
+					tempData;
+
+				if (!node) {
+					node = new Node(that, data);
+				}
+				that.maxNodeId(node.id());
+				if(parent.childIndex(node) === -1){
+					if(pre && parent.childIndex(pre) !== -1){
+						parent.children.splice(parent.childIndex(pre) + 1, 0, node);
+					}
+					else if(next && parent.childIndex(next) !== -1){
+						parent.children.splice(parent.childIndex(next), 0, node);
+					}
+					else {
+						parent.children.push(node);
+					}
+				}
+				if(pre && parent.childIndex(pre) === -1){
+					parent.children.splice(parent.childIndex(node), 0, pre);
+				}
+				if(next && parent.childIndex(next) === -1){
+					parent.children.splice(parent.childIndex(node) + 1, 0, next);
+				}
+				if(pre && parent.childIndex(pre) !== parent.childIndex(node) - 1){
+					parent.children.splice(parent.childIndex(pre), 1);
+					parent.children.splice(parent.childIndex(node), 0, pre);
+				}
+				if(next && parent.childIndex(next) !== parent.childIndex(node) + 1){
+					parent.children.splice(parent.childIndex(next), 1);
+					parent.children.splice(parent.childIndex(node) + 1, 0, next);
+				}
+				node.parent = parent;
+				node.nextSibling = next;
+			}
+			//建立索引
+			for(let data of arrData){
+				nodesIndex[data.ID] = new Node(that, data);
+			}
+			for (i = 0; i < arrData.length; i++){
+				loadNode(arrData[i], this.setting);
+			}
+		};
 
     	Tree.prototype.refreshNodesDom = function (nodes, recurse){
 			var that = this;
@@ -346,7 +406,8 @@
  						if (iIndex > 0){
  							pre = parent.children[iIndex - 1];
  							pre.setNextSibling(node);
- 							parent.children.splice(iIndex - 1, 0, node);
+ 							//parent.children.splice(iIndex - 1, 0, node);
+ 							parent.children.splice(iIndex, 0, node);
  						} else {
  							parent.children.splice(0, 0, node);
  						}

+ 8 - 6
test/unit/reports/test_tpl_09.js

@@ -44,12 +44,12 @@ let demoRptId = 232, pagesize = "A4";
 
 let userId_Leng = 1142; //小冷User Id
 // demoPrjId = 720; //QA: DW3
-demoPrjId = 1348; //QA:
-/*/
+demoPrjId = 1626; //QA:
+//*/
 let userId_Dft = userId_Leng;
 /*/
- let userId_Dft = 76075;
- //*/
+let userId_Dft = 76075;
+//*/
 
 let rptTplFacade = require("../../../modules/reports/facade/rpt_template_facade");
 let rptTplDataFacade = require("../../../modules/reports/facade/rpt_tpl_data_facade");
@@ -124,7 +124,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();
@@ -132,11 +132,13 @@ test('测试 - 测试模板啦: ', function (t) {
                     let defProperties = rpt_cfg;
                     let dftOption = JV.PAGING_OPTION_NORMAL;
                     printCom.initialize(rptTpl);
+                    // fsUtil.writeObjToFile(tplData, "D:/GitHome/ConstructionCost/tmp/rptAssembledData.jsp");
+                    // fsUtil.writeObjToFile(rawDataObj, "D:/GitHome/ConstructionCost/tmp/rptRawDataAfterAssembled.jsp");
                     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");
+                        // fsUtil.writeObjToFile(pageRst, "D:/GitHome/ConstructionCost/tmp/rptPageResult.jsp");
                     } else {
                         console.log("oh! no pages were created!");
                     }

+ 5 - 6
web/building_saas/main/html/main.html

@@ -289,7 +289,7 @@
                             <ul class="nav flex-column nav-pills" role="tablist">
                                 <li class="nav-item"><a class="nav-link active" data-toggle="pill" href="#poj-settings-basicInfo" role="tab" id="tab_poj-settings-basicInfo">基本信息</a></li>
                                 <li class="nav-item"><a class="nav-link" data-toggle="pill" href="#poj-settings-projFeature" id="tab_poj-settings-projFeature" role="tab">工程特征</a></li>
-                                <li class="nav-item"><a class="nav-link" data-toggle="pill" href="#poj-settings-3" role="tab">指标信息</a></li>
+                                <li class="nav-item"><a class="nav-link" data-toggle="pill" href="#poj-settings-indicativeInfo" id="tab_poj-settings-indicativeInfo" role="tab">指标信息</a></li>
                                 <li class="nav-item"><a class="nav-link" data-toggle="pill" href="#poj-settings-4" id="about-calc" role="tab">关于计算</a></li>
                                 <li class="nav-item"><a class="nav-link" data-toggle="pill" href="#poj-settings-billsQuanDecimal" id="tab_poj-settings-bqDecimal" role="tab">清单工程量精度</a></li>
                                 <li class="nav-item"><a class="nav-link" data-toggle="pill" href="#poj-settings-decimal" role="tab" id="tab_poj-settings-decimal">小数位数</a></li>
@@ -307,13 +307,11 @@
                                 <!--工程特征-->
                                 <div class="tab-pane fade" id="poj-settings-projFeature" role="tabpanel">
                                     <div class="modal-auto-height" style="overflow: hidden" id="projFeatureSpread">
-                                        工程特征
                                     </div>
                                 </div>
                                 <!--指标信息-->
-                                <div class="tab-pane fade" id="poj-settings-3" role="tabpanel">
-                                    <div class="modal-auto-height">
-                                        指标信息
+                                <div class="tab-pane fade" id="poj-settings-indicativeInfo" role="tabpanel">
+                                    <div class="modal-auto-height" style="overflow:hidden" id="indicativeInfoSpread">
                                     </div>
                                 </div>
                                 <!--关于计算-->
@@ -544,7 +542,7 @@
         <div class="modal-dialog" role="document">
             <div class="modal-content">
                 <div class="modal-header">
-                    <h5 class="modal-title"><i class="fa fa-superscript"></i> 请选择清单计量单位</h5>
+                    <h5 class="modal-title">请选择清单计量单位</h5>
                     <button type="button" class="close" id='std_bills_unit_close' aria-label="Close">
                         <span aria-hidden="true">&times;</span>
                     </button>
@@ -1128,6 +1126,7 @@
         <script type="text/javascript" src="/web/building_saas/main/js/views/project_property_decimal_view.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/project_property_basicInfo.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/project_property_projFeature.js"></script>
+        <script type="text/javascript" src="/web/building_saas/main/js/views/project_property_indicativeInfo.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/views/project_property_display_view.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/main_ajax.js"></script>
         <script type="text/javascript" src="/web/building_saas/main/js/main.js"></script>

+ 37 - 40
web/building_saas/main/js/models/calc_program.js

@@ -403,76 +403,73 @@ let calcTools = {
         }
         return result;
     },
-    supplyABFee: function (treeNode, baseName) {
+    partASupplyFee: function (treeNode, baseName) {
         if (!treeNode.data.gljList) return 0;
         let projectGLJ = projectObj.project.projectGLJ;
 
         let supplyT = [];
         if (baseName.includes('甲供'))
-            supplyT = [supplyType.BFJG, supplyType.WQJG]  // 字段中存储的是汉字!
-            // supplyT = ['部分甲供', '完全甲供']
+            supplyT = [supplyType.BFJG, supplyType.WQJG]  // 字段中存储的是汉字、数字混杂!
         else if (baseName.includes('甲定'))
             supplyT = [supplyType.JDYG];
-            // supplyT = ['甲定乙供'];
 
-        let gljT = [], compositionTypesArr = [];
+        let gljT = [], compT = [];
         if (baseName == calcBaseNames.JGDEJJRGF || baseName == calcBaseNames.JDDEJJRGF){
             gljT = [gljType.LABOUR];
         }
         else if (baseName == calcBaseNames.JGDEJJCLF || baseName == calcBaseNames.JDDEJJCLF){
             gljT = baseMaterialTypes;
-            compositionTypesArr = compositionTypes;
+            compT = compositionTypes;
         }
         else if (baseName == calcBaseNames.JGDEJJJXF || baseName == calcBaseNames.JDDEJJJXF){
             gljT = baseMachineTypes;
-            compositionTypesArr = [gljType.GENERAL_MACHINE];
+            compT = [gljType.GENERAL_MACHINE];
         }
         else if (baseName == calcBaseNames.JGZCF || baseName == calcBaseNames.JDZCF){
             gljT = [gljType.MAIN_MATERIAL];
-            compositionTypesArr = [gljType.MAIN_MATERIAL];
+            compT = [gljType.MAIN_MATERIAL];
         }
         else if (baseName == calcBaseNames.JGSBF || baseName == calcBaseNames.JDSBF){
             gljT = [gljType.EQUIPMENT];
         };
         // alert(JSON.stringify(projectGLJ.testGLJs()));
-        let supplyProjectGLJs = projectGLJ.getGLJsBySupply(supplyT, gljT);
-        if (supplyProjectGLJs.length == 0) return 0;
-
-        let pGLJIdx = {};
-        for (let pglj of supplyProjectGLJs){pGLJIdx[pglj.id] = pglj};
+        let supplyGLJs = projectGLJ.getGLJsBySupply(supplyT, gljT);
+        if (supplyGLJs.length == 0) return 0;
+        let supplyGLJsIdx = {};
+        for (let sglj of supplyGLJs){supplyGLJsIdx[sglj.id] = sglj};
+
+        function isSupply(composition, supplies) {
+            for (let supply of supplies){
+                if(supply.code == composition.code && supply.name == composition.name && supply.unit == composition.unit &&
+                    supply.specs == composition.specs && supply.type == composition.type ){
+                    composition.basePrice = supply.unit_price.base_price;
+                    return true;
+                }
+            };
+            return false;
+        };
 
         let sum = 0;
         for (let glj of treeNode.data.gljList){
             // 组成物的母体。母体如果有组成物,则母体无法作为甲供材料,无法设置,此时要看其组成物是否是甲供材料;母体如果没有组成物,则母体有可能成为甲供材料。
-            if (compositionTypesArr.includes(glj.type)) {
-                if (pGLJIdx[glj.projectGLJID]) {  // 组成物的母体是甲供材料
+            if (compT.includes(glj.type)) {
+                if (supplyGLJsIdx[glj.projectGLJID]) {  // 组成物的母体是甲供材料
                     sum = (sum + glj.basePrice * glj.quantity).toDecimal(decimalObj.process);
                 }
                 else{  // 组成物明细
                     let pGLJ = projectGLJ.getDataByID(glj.projectGLJID);
                     let compositions = pGLJ.ratio_data;
                     if (compositions.length > 0){
-                        function isSupply(composition, supplies) {
-                            for (let supply of supplies){
-                                if(supply.code == composition.code && supply.name == composition.name && supply.unit == composition.unit &&
-                                    supply.specs == composition.specs && supply.type == composition.type ){
-                                    composition.basePrice = supply.unit_price.base_price;
-                                    return true;
-                                }
-                            };
-                            return false;
-                        };
-
-                        for (let composition of compositions){
-                            if (isSupply(composition, supplyProjectGLJs)) {
-                                sum = (sum + composition.basePrice * composition.consumption * glj.quantity).toDecimal(decimalObj.process);
+                        for (let c of compositions){
+                            if (isSupply(c, supplyGLJs)) {
+                                sum = (sum + c.basePrice * c.consumption * glj.quantity).toDecimal(decimalObj.process);
                             }
                         };
                     }
                 }
             }
             else {
-                if (pGLJIdx[glj.projectGLJID]) {
+                if (supplyGLJsIdx[glj.projectGLJID]) {
                     sum = (sum + glj.basePrice * glj.quantity).toDecimal(decimalObj.process);
                 }
             };
@@ -635,34 +632,34 @@ const rationCalcBases = {
         return rst.toDecimal(decimalObj.glj.quantity);
     },
     '甲供定额基价人工费': function (node) {
-        return calcTools.supplyABFee(node, calcBaseNames.JGDEJJRGF);
+        return calcTools.partASupplyFee(node, calcBaseNames.JGDEJJRGF);
     },
     '甲供定额基价材料费': function (node) {
-        return calcTools.supplyABFee(node, calcBaseNames.JGDEJJCLF);
+        return calcTools.partASupplyFee(node, calcBaseNames.JGDEJJCLF);
     },
     '甲供定额基价机械费': function (node) {
-        return calcTools.supplyABFee(node, calcBaseNames.JGDEJJJXF);
+        return calcTools.partASupplyFee(node, calcBaseNames.JGDEJJJXF);
     },
     '甲供主材费': function (node) {
-        return calcTools.supplyABFee(node, calcBaseNames.JGZCF);
+        return calcTools.partASupplyFee(node, calcBaseNames.JGZCF);
     },
     '甲供设备费': function (node) {
-        return calcTools.supplyABFee(node, calcBaseNames.JGSBF);
+        return calcTools.partASupplyFee(node, calcBaseNames.JGSBF);
     },
     '甲定定额基价人工费': function (node) {
-        return calcTools.supplyABFee(node, calcBaseNames.JDDEJJRGF);
+        return calcTools.partASupplyFee(node, calcBaseNames.JDDEJJRGF);
     },
     '甲定定额基价材料费': function (node) {
-        return calcTools.supplyABFee(node, calcBaseNames.JDDEJJCLF);
+        return calcTools.partASupplyFee(node, calcBaseNames.JDDEJJCLF);
     },
     '甲定定额基价机械费': function (node) {
-        return calcTools.supplyABFee(node, calcBaseNames.JDDEJJJXF);
+        return calcTools.partASupplyFee(node, calcBaseNames.JDDEJJJXF);
     },
     '甲定主材费': function (node) {
-        return calcTools.supplyABFee(node, calcBaseNames.JDZCF);
+        return calcTools.partASupplyFee(node, calcBaseNames.JDZCF);
     },
     '甲定设备费': function (node) {
-        return calcTools.supplyABFee(node, calcBaseNames.JDSBF);
+        return calcTools.partASupplyFee(node, calcBaseNames.JDSBF);
     },
     '暂估材料费': function (node) {
         return calcTools.estimateFee(node, true);

+ 3 - 1
web/building_saas/main/js/views/main_tree_col.js

@@ -381,7 +381,9 @@ $('#column').on('hide.bs.modal', function () {
         projectObj.project.projSetting.main_tree_col.cols[iRow].visible = sheet.getValue(iRow, 0);
         projectObj.project.projSetting.mainGridSetting.cols[iRow].visible = sheet.getValue(iRow, 0);
     }
-    SheetDataHelper.refreshColumnVisible(projectObj.project.projSetting.mainGridSetting, projectObj.mainSpread.getActiveSheet());
+    SheetDataHelper.massOperationSheet(projectObj.mainSpread.getActiveSheet(), function () {
+        SheetDataHelper.refreshColumnVisible(projectObj.project.projSetting.mainGridSetting, projectObj.mainSpread.getActiveSheet());
+    });
     //refresh nodes to autoFitRow
     projectObj.mainController.refreshTreeNode(projectObj.project.mainTree.roots, true);
     projectObj.project.pushNow('editColSetting', projectObj.project.projSetting.moduleName, {

+ 177 - 0
web/building_saas/main/js/views/project_property_indicativeInfo.js

@@ -0,0 +1,177 @@
+/**
+ * Created by Zhong on 2018/3/7.
+ */
+let indicativeInfoObj = {
+    feeType: {common: 'common', labour: 'labour', material: 'material', machine: 'machine', mainMaterial: 'mainMaterial', equipment: 'equipment',
+        labourDiff: 'labourDiff', materialDiff: 'materialDiff', machineDiff: 'machineDiff', manage: 'manage', profit: 'profit'},
+    workBook: null,
+    setting:{
+        header: [
+            {name: '名称', dataCode: 'name', width: 200, vAlign: 'center', hAlign: 'left'},
+            {name: '金额', dataCode: 'price', width: 120, vAlign: 'center', hAlign: 'right'},
+            {name: '占造价比例(%)', dataCode: 'rate', width: 100, vAlign: 'center', hAlign: 'right'},
+            {name: '单方造价', dataCode: 'perCentiare', width: 80, vAlign: 'center', hAlign: 'right'}
+        ],
+        options: {
+            tabStripVisible:  false,
+            allowCopyPasteExcelStyle : false,
+            allowExtendPasteRange: false,
+            allowUserDragDrop : false,
+            allowUserDragFill: false,
+            scrollbarMaxAlign : true
+        }
+    },
+
+    renderSheetFuc: function (sheet, fuc) {
+        sheet.suspendPaint();
+        sheet.suspendEvent();
+        fuc();
+        sheet.resumePaint();
+        sheet.resumeEvent();
+    },
+
+    setOptions: function (workbook, opts) {
+        for(let opt in opts){
+            workbook.options[opt] = opts[opt];
+        }
+    },
+
+    buildHeader: function (sheet, headers) {
+        let me = projFeatureView;
+        let fuc = function () {
+            sheet.setColumnCount(headers.length);
+            sheet.setRowHeight(0, 40, GC.Spread.Sheets.SheetArea.colHeader);
+            for(let i = 0, len = headers.length; i < len; i++){
+                sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
+                sheet.setColumnWidth(i, headers[i].width, GC.Spread.Sheets.SheetArea.colHeader);
+            }
+        };
+        me.renderSheetFuc(sheet, fuc);
+    },
+
+    buildSheet: function () {
+        if(!this.workBook){
+            this.workBook = new GC.Spread.Sheets.Workbook($('#indicativeInfoSpread')[0], {sheetCount: 1});
+            this.setOptions(this.workBook, this.setting.options);
+            this.workBook.getSheet(0).options.isProtected = true;
+            this.buildHeader(this.workBook.getActiveSheet(), this.setting.header);
+        }
+    },
+    showData(datas){
+        let sheet = this.workBook.getActiveSheet();
+        let cols = this.setting.header;
+        let fuc = function () {
+            sheet.setRowCount(datas.length);
+            for(let col = 0, cLen = cols.length; col < cLen; col++){
+                sheet.getRange(-1, col, -1, 1, GC.Spread.Sheets.SheetArea.viewport).hAlign(GC.Spread.Sheets.HorizontalAlign[cols[col]['hAlign']]);
+                sheet.getRange(-1, col, -1, 1, GC.Spread.Sheets.SheetArea.viewport).vAlign(GC.Spread.Sheets.VerticalAlign[cols[col]['vAlign']]);
+                for(let row = 0, rLen = datas.length; row < rLen; row++){
+                    sheet.setValue(row, col, datas[row][cols[col]['dataCode']]);
+                }
+            }
+        };
+        this.renderSheetFuc(sheet, fuc);
+    },
+    //是清单
+    isBills: function (node) {
+        return node && node.sourceType === projectObj.project.Bills.getSourceType();
+    },
+    //是大项费用
+    isDXFY: function (node) {
+        return this.isBills(node) && node.data.type === billType.DXFY;
+    },
+    //是分部分项工程
+    isFBFX: function (node) {
+        return this.isDXFY(node) && node.data.flagsIndex && node.data.flagsIndex.fixed && node.data.flagsIndex.fixed.flag === fixedFlag.SUB_ENGINERRING;
+    },
+    //是措施项目
+    isCSXM: function (node) {
+        return this.isDXFY(node) && node.data.flagsIndex && node.data.flagsIndex.fixed && node.data.flagsIndex.fixed.flag === fixedFlag.MEASURE;
+    },
+    //是工程造价
+    isEngieeringCost: function (node) {
+        return this.isDXFY(node) && node.data.flagsIndex && node.data.flagsIndex.fixed && node.data.flagsIndex.fixed.flag === fixedFlag.ENGINEERINGCOST;
+    },
+    //存在某个费用
+    fee: function (node, feeType) {
+        return node && node.data.feesIndex && node.data.feesIndex[feeType] ? node.data.feesIndex[feeType].totalFee : 0;
+    },
+    //根据固定行ID获取固定行清单节点
+    getFixedBill: function (flag) {
+        for(let node of projectObj.project.mainTree.items){
+            if(node && node.data.flagsIndex && node.data.flagsIndex.fixed && node.data.flagsIndex.fixed.flag === flag){
+                return node;
+            }
+        }
+        return null;
+    },
+    getDXFY: function (node) {
+        if(!node) return null;
+        let dxfy = Object.create(null);
+        let engCostFee = this.fee(this.getFixedBill(fixedFlag.ENGINEERINGCOST), this.feeType.common);
+        let commonFee = this.fee(node, this.feeType.common);
+        let buildingArea = projFeatureView.getFeature('projFeature', 'buildingArea');
+        let areaNum = !buildingArea.value || buildingArea.value == '' || isNaN(buildingArea.value) ? 0 : buildingArea.value;
+        dxfy.name = node.data.name;
+        dxfy.price = commonFee ? parseFloat(commonFee).toDecimal(decimalObj.bills.totalPrice) : 0;
+        dxfy.rate = engCostFee == 0 || this.isEngieeringCost(node) ? '' : parseFloat(dxfy.price/engCostFee*100).toDecimal(2);
+        dxfy.perCentiare = areaNum == 0 ? '' : parseFloat(dxfy.price/areaNum).toDecimal(decimalObj.bills.totalPrice);
+        return dxfy;
+    },
+    getIndicativeInfo: function () {
+        let rst = [];
+        for(let node of projectObj.project.mainTree.items){
+            if(this.isDXFY(node)){
+                let dxfy = this.getDXFY(node);
+                if(!dxfy) continue;
+                if(this.isFBFX(node)){
+                    rst.push(dxfy);
+                    rst.push({name: '其中:', price: '', rate: '', perCentiare: ''});
+                    rst.push({name: '       人工费', price: parseFloat(this.fee(node, this.feeType.labour)).toDecimal(decimalObj.bills.totalPrice), rate: '', perCentiare: ''});
+                    rst.push({name: '       材料费', price: parseFloat(this.fee(node, this.feeType.material)).toDecimal(decimalObj.bills.totalPrice), rate: '', perCentiare: ''});
+                    rst.push({name: '       机械费', price: parseFloat(this.fee(node, this.feeType.machine)).toDecimal(decimalObj.bills.totalPrice), rate: '', perCentiare: ''});
+                    rst.push({name: '       主材费', price: parseFloat(this.fee(node, this.feeType.mainMaterial)).toDecimal(decimalObj.bills.totalPrice), rate: '', perCentiare: ''});
+                    rst.push({name: '       设备费', price: parseFloat(this.fee(node, this.feeType.equipment)).toDecimal(decimalObj.bills.totalPrice), rate: '', perCentiare: ''});
+                    let labourDiff = this.fee(node, this.feeType.labourDiff),
+                        materialDiff = this.fee(node, this.feeType.materialDiff),
+                        machineDiff = this.fee(node, this.feeType.machineDiff),
+                        rcjDiff = labourDiff + materialDiff + machineDiff;
+                    rst.push({name: '人材机价差', price: parseFloat(rcjDiff).toDecimal(decimalObj.bills.totalPrice), rate: '', perCentiare: ''});
+                    rst.push({name: '企业管理费', price: parseFloat(this.fee(node, this.feeType.manage)).toDecimal(decimalObj.bills.totalPrice), rate: '', perCentiare: ''});
+                    rst.push({name: '利润', price: parseFloat(this.fee(node, this.feeType.profit)).toDecimal(decimalObj.bills.totalPrice), rate: '', perCentiare: ''});
+                }
+                else if(this.isCSXM(node)){
+                    rst.push(dxfy);
+                    rst.push({name: '其中:', price: '', rate: '', perCentiare: ''});
+                    let safeConst = this.getDXFY(this.getFixedBill(fixedFlag.SAFETY_CONSTRUCTION));
+                    if(safeConst){
+                        safeConst.name = `      ${safeConst.name}`;
+                        rst.push(safeConst);
+                    }
+                }
+                else{
+                    rst.push(dxfy);
+                }
+            }
+        }
+        return rst;
+    }
+};
+
+$(document).ready(function () {
+    $('#poj-set').on('shown.bs.modal', function () {
+        indicativeInfoObj.buildSheet();
+        indicativeInfoObj.showData(indicativeInfoObj.getIndicativeInfo());
+    });
+
+    $('#poj-set').on('hidden.bs.modal', function () {
+       if(indicativeInfoObj.workBook){
+           indicativeInfoObj.workBook.destroy();
+           indicativeInfoObj.workBook = null;
+       }
+    });
+
+    $('#tab_poj-settings-indicativeInfo').on('shown.bs.tab', function () {
+        indicativeInfoObj.workBook.refresh();
+    });
+});

+ 17 - 10
web/building_saas/main/js/views/project_property_projFeature.js

@@ -9,7 +9,7 @@ let projFeatureView = {
     setting:{
         header: [
             {name: '属性', dataCode: 'dispName', width: 200, vAlign: 'center', hAlign: 'left'},
-            {name: '值', dataCode: 'value', width: 120, vAlign: 'center', hAlign: 'left'}
+            {name: '值', dataCode: 'value', width: 120, vAlign: 'center', hAlign: 'center'}
         ],
         options: {
             tabStripVisible:  false,
@@ -25,7 +25,7 @@ let projFeatureView = {
             {row: 3, key: 'baseType', items: ['带基', '框排架柱距6m以内', '框排架柱距6m以外', '满基筏式', '满基板式', '满基箱式', '独立基础']},
             {row: 4, key: 'buildingFeature', items: ['点式', '凹式', '凸式', 'Y式', '其他']}
         ],
-        numRows: [5, 6, 7, 8, 9, 10, 11, 12, 13, 14],
+        numRows: [5, 6, 7, 8, 9, 10, 11, 12, 13],
         dateRows: [],
         locked: {
             rows: [0],
@@ -110,7 +110,7 @@ let projFeatureView = {
             }
             for(let col = 0, cLen = cols.length; col < cLen; col++){
                 sheet.getRange(-1, col, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[cols[col]['hAlign']]);
-                sheet.getRange(-1, col, -1, 1).hAlign(GC.Spread.Sheets.VerticalAlign[cols[col]['vAlign']]);
+                sheet.getRange(-1, col, -1, 1).vAlign(GC.Spread.Sheets.VerticalAlign[cols[col]['vAlign']]);
                 for(let row = 0, rLen = datas.length; row < rLen; row++){
                     sheet.setValue(row, col, datas[row][cols[col]['dataCode']]);
                 }
@@ -136,7 +136,7 @@ let projFeatureView = {
             if(me.setting.numRows.indexOf(args.row) !== -1){//控制数值
                 if(!me.isNum(v)){
                     alert('只能输入数值');
-                    args.sheet.setValue(args.row, args.col, me.datas[args.row].value ? me.datas[args.row].value : '');
+                    args.sheet.setValue(args.row, args.col, me.datas[args.row].value && me.isNum(me.datas[args.row].value) ? me.datas[args.row].value : '');
                 }
             }
             me.datas[args.row].value = v;
@@ -188,6 +188,19 @@ let projFeatureView = {
         }
     },
 
+    getFeature: function (featureType, eigenKey) {
+        for(let feature of this.orgDatas){
+            if(feature.key === featureType){
+                for(let eigen of feature.items){
+                    if(eigen.key === eigenKey){
+                        return eigen;
+                    }
+                }
+            }
+        }
+        return null;
+    },
+
     isDef: function (v) {
         return v !== undefined && v !== null;
     },
@@ -402,10 +415,4 @@ $(document).ready(function () {
     $('#tab_poj-settings-projFeature').on('shown.bs.tab', function () {
         projFeatureView.workBook.refresh();
     });
-
-    /*$('#property_ok').bind('click', function () {
-        if(projFeatureView.toUpdate(projFeatureView.orgDatas, projFeatureView.datas)){
-           projFeatureView.a_updateInfo(projFeatureView.toSaveDatas(projFeatureView.datas));
-        }
-    });*/
 });

+ 16 - 5
web/building_saas/main/js/views/project_view.js

@@ -256,12 +256,20 @@ var projectObj = {
                         node.data.name = data.name;
                         pageCCOprObj.setItemContentNode(node, data.jobContent, data.itemCharacter, node.data.name);
                         if (/\//.test(data.unit)) {
-                            ConfirmModal.stdBillsUnit.check(data, function (std) {
-                                project.Bills.replaceBills(node.source, std, formatCode);
+                            let existB = projectObj.project.Bills.sameStdCodeBillsData(data.code);
+                            if (existB) {
+                                data.unit = existB.unit;
+                                //
+                                project.Bills.replaceBills(node.source, data, formatCode);
                                 projectObj.mainController.refreshTreeNode([node], false);
-                            }, function () {
-                                projectObj.mainController.refreshTreeNode([node], false);
-                            });
+                            } else {
+                                ConfirmModal.stdBillsUnit.check(data, function (std) {
+                                    project.Bills.replaceBills(node.source, std, formatCode);
+                                    projectObj.mainController.refreshTreeNode([node], false);
+                                }, function () {
+                                    projectObj.mainController.refreshTreeNode([node], false);
+                                });
+                            }
                         } else {
                             project.Bills.replaceBills(node.source, data, formatCode);
                             projectObj.mainController.refreshTreeNode([node], false);
@@ -573,6 +581,9 @@ var projectObj = {
                 console.log(`时间——${endTime - startTime}`);
                 that.project.projectMarkChecking();//是否需要重新进行造价计算
                 installationFeeObj.engineeringTypeChecking();//检查是否安装工程
+                //初始需要触发一次点击表格事件,sheet.getAutoFitWidth值(获取单元格文本长度)才正确
+                that.mainSpread.getActiveSheet().startEdit();
+                that.mainSpread.getActiveSheet().endEdit();
             }
             else {
 

+ 2 - 0
web/building_saas/pm/html/project-management.html

@@ -347,10 +347,12 @@
                     <div class="form-group">
                         <label>计价规则</label>
                         <select class="form-control" id="valuation"><option value="">请选择计价规则</option></select>
+                        <span class="form-text text-danger" id="valuation-info" style="display: none;">请选择计价规则</span>
                     </div>
                     <div class="form-group">
                         <label>工程专业</label>
                         <select class="form-control" id="tender-engineering"><option value="">请选择对应的工程专业</option></select>
+                        <span class="form-text text-danger" id="engineering-info" style="display: none;">请选择工程专业</span>
                     </div>
                 </form>
             </div>

+ 73 - 67
web/building_saas/pm/js/pm_main.js

@@ -269,6 +269,7 @@ $(document).ready(function() {
         let engineeringList = getEngineeringList();
         let engineeringHtml = getEngineeringHtml(engineeringList);
         $("#tender-engineering").html(engineeringHtml);
+        $('#valuation-info').hide();
     });
 
     // 新增单项项目点击
@@ -301,8 +302,10 @@ $(document).ready(function() {
         let nameList = getNameList($('#poj-name-list').children());
         let isExist = hasListName(nameList, pojName);
         if(!isExist){
-            $('#poj-name-info').text('新建 “' + pojName + '”');
-            $('#poj-name-info').show();
+            if(pojName !== ''){
+                replaceClass($('#poj-name-info'), 'text-danger', 'text-info');
+                setDangerInfo($('#poj-name-info'), `新建“${pojName}”`);
+            }
             //清空单项工程下拉和文件下拉
             setEngOptions(null);
             setFileOptions(null);
@@ -318,8 +321,10 @@ $(document).ready(function() {
         let nameList = getNameList($('#eng-name-list').children());
         let isExist = hasListName(nameList, engName);
         if(!isExist){
-            $('#eng-name-info').text('新建 “' + engName + '”');
-            $('#eng-name-info').show();
+            if(engName !== ''){
+                replaceClass($('#eng-name-info'), 'text-danger', 'text-info');
+                setDangerInfo($('#eng-name-info'), `新建“${engName}”`);
+            }
         }
         else {
             $('#eng-name-info').hide();
@@ -334,8 +339,8 @@ $(document).ready(function() {
         let tenderName = $('#tender-name').val().trim();
         let isExist = hasTender(selected, pojName, engName, tenderName);
         if(isExist){
-            $('#tender-name-info').text('已存在 “' + tenderName + '”');
-            $('#tender-name-info').show();
+            if(tenderName !== '')
+                setDangerInfo($('#tender-name-info'), `已存在“${tenderName}”`);
         }
         else {
             $('#tender-name-info').hide();
@@ -367,6 +372,8 @@ $(document).ready(function() {
         $('#eng-name-info').hide();
         $('#tender-name-info').hide();
         $('#tender-name').val('');
+        $('#valuation-info').hide();
+        $('#engineering-info').hide();
         //获取建设项目
         let selected = Tree.selected();
         let projs = getProjs(selected);
@@ -461,8 +468,7 @@ $(document).ready(function() {
         let newName = $('#rename-name').val();
         let dialog = $('#rename-dialog');
         if (newName === '') {
-            $('#rename-name-info').text('请输入重命名名称');
-            $('#rename-name-info').show();
+            setDangerInfo($('#rename-name-info'), '请输入重命名');
             return false;
         }
 
@@ -471,8 +477,7 @@ $(document).ready(function() {
             return false;
         }
         RenameProject(select.id(), newName, select.data.ParentID, function () {
-            $('#rename-name-info').text('');
-            $('#rename-name-info').hide();
+            setDangerInfo($('#rename-name-info'), '', false);
             dialog.modal('hide');
             select.data.name = newName;
             Tree.refreshNodesDom([select]);
@@ -634,6 +639,7 @@ $(document).ready(function() {
 
     // 选择工程专业后动态更改费率文件等数据
     $("#tender-engineering").change(function() {
+        $('#engineering-info').hide();
         let engineeringList = getEngineeringList();
         if(engineeringList.length === 0){
             return false;
@@ -689,19 +695,16 @@ function init() {
 function AddProject() {
     let name = $('#project-name').val().trim();
     if (name === '') {
-        $('#project-name-info').text('请填写建设项目名称');
-        $('#project-name-info').show();
+        setDangerInfo($('#project-name-info'), '请填写建设项目名称');
         return false;
     }
     let existCallback = function () {
-        $('#project-name-info').text(`已存在“${$("#project-name").val()}”`);
-        $('#project-name-info').show();
+        setDangerInfo($('#project-name-info'), `已存在“${$("#project-name").val()}”`);
     };
     let sucCallback = function () {
         $('#add-project-dialog').modal('hide');
         $('#project-name').val('');
-        $('#project-name-info').text('');
-        $('#project-name-info').hide();
+        setDangerInfo($('#project-name-info'), '', false);
     };
     let selectedItem = Tree.selected();
 
@@ -731,23 +734,19 @@ function AddProject() {
 //新建建设项目、新建单项工程、新建文件夹、重命名弹窗隐藏事件
 function bindModalsHidden(projDialog, engDialog, folderDialog, renameDialog){
     projDialog.on('hidden.bs.modal', function () {
-        $('#project-name-info').text('');
-        $('#project-name-info').hide();
+        setDangerInfo($('#project-name-info'), '', false);
         $('#project-name').val('');
     });
     engDialog.on('hidden.bs.modal', function () {
-        $('#engineering-name-info').text('');
-        $('#engineering-name-info').hide();
+        setDangerInfo($('#engineering-name-info'), '', false);
         $('#engineering-name').val('');
     });
     folderDialog.on('hidden.bs.modal', function () {
-        $('#folder-name-info').text('');
-        $('#folder-name-info').hide();
+        setDangerInfo($('#folder-name-info'), '', false);
         $('#folder-name').val('');
     });
     renameDialog.on('hidden.bs.modal', function () {
-        $('#rename-name-info').text('');
-        $('#rename-name-info').hide();
+        setDangerInfo($('#rename-name-info'), '', false);
         $('#rename-name').val('');
     });
 }
@@ -760,31 +759,24 @@ function bindInputs(projInput, engInput, foldInput, renameInput){
             return false;
         }
     });
-    //projInput.bind('change', getChangedFunc(projInput, $('#project-name-info')));
-
     engInput.bind('keypress', function (event) {
         if(event.keyCode === 13){
             $('#add-engineering-confirm').click();
             return false;
         }
     });
-    //engInput.bind('change', getChangedFunc(engInput, $('#engineering-name-info')));
-
     foldInput.bind('keypress', function (event) {
         if(event.keyCode === 13){
             $('#add-folder-confirm').click();
             return false;
         }
     });
-   // foldInput.bind('change', getChangedFunc(foldInput, $('#folder-name-info')));
-
     renameInput.bind('keypress', function (event) {
         if(event.keyCode === 13){
             $('#rename-confirm').click();
             return false;
         }
     });
-    //renameInput.bind('change', getChangedFunc(renameInput, $('#rename-name-info')));
 }
 //新建建设项目、单项工程、文件夹、重命名提示(文本改变,暂时不需要)
 function getChangedFunc(input, nameInfo){
@@ -825,7 +817,7 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
         let parent, pre, next;
         GetNewProjectId(3, function (IDs) {
             let projID = IDs.lowID, engID = IDs.lowID + 1, tenderID = IDs.lowID + 2;
-            if(!selected || selected && selected.data.projType === projectType.project){
+            if(!selected || selected.data.projType === projectType.project){
                 parent = selected ? selected.parent : Tree._root;
                 pre = selected;
                 next = selected ? selected.nextSibling : Tree.firstNode();
@@ -863,7 +855,8 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
                         }
                     }
                 });
-                let pojNode = Tree.addNodeData(projData, parent, pre && pre.nextSibling ? pre.nextSibling : null);
+                //let pojNode = Tree.addNodeData(projData, parent, pre && pre.nextSibling ? pre.nextSibling : null);
+                let pojNode = Tree.addNodeData(projData, parent, next);
                 let engNode = Tree.addNodeData(engData, pojNode, null);
                 Tree.addNodeData(tenderData, engNode, null);
                 callback();
@@ -900,6 +893,8 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
                         }
                     }
                 });
+                console.log(tempProj);
+                console.log(next);
                 let engNode = Tree.addNodeData(engData, tempProj, next);
                 Tree.addNodeData(tenderData, engNode, null);
                 callback();
@@ -1043,25 +1038,25 @@ function getProjs(selected){
     let temp;
     let firstNode;
     if(!selected){
-        temp = Tree._root.children;
-        firstNode = temp[0];
+        temp = Tree._root;
+        firstNode = temp.children[0];
     }
     else if(selected.data.projType === projectType.folder){
-        temp = selected.children;
-        firstNode = temp[0];
+        temp = selected;
+        firstNode = temp.children[0];
     }
     else if(selected.data.projType === projectType.project){
-        temp = selected.parent.children;
-        firstNode = temp[0];
+        temp = selected.parent;
+        firstNode = temp.children[0];
     }
     else if(selected.data.projType === projectType.engineering || selected.data.projType === projectType.tender){
         let proj = selected.parent.data.projType === projectType.project ? selected.parent : selected.parent.parent;
-        temp = proj.parent.children;
+        temp = proj.parent;
         firstNode = proj;
     }
-    for(let i = 0, len = temp.length; i < len; i++){
-        if(temp[i].data.projType === projectType.project){
-            rst.push(temp[i]);
+    for(let childNode of temp.children){
+        if(childNode.data.projType === projectType.project){
+            rst.push(childNode);
         }
     }
     //firstNode to first place
@@ -1148,7 +1143,7 @@ function setEngOptions(projID){
     $("#eng-name-list").empty();
     $("#eng-name").val("");
     if(proj){
-        let engineerings = proj.children;
+        let engineerings = [].concat(proj.children);
         //set selected engineering to first place
         let selected = Tree.selected();
         let firstNode = null;
@@ -1202,6 +1197,20 @@ function hasTender(selected, pojName, engName, tenderName){
     return isExist;
 }
 
+//替换class
+function replaceClass(selector, orgClass, newClass){
+    selector.removeClass(orgClass);
+    selector.addClass(newClass);
+}
+//设置提示信息
+function setDangerInfo(area, info, show = true){
+    area.text(info);
+    if(show)
+        area.show();
+    else
+        area.hide();
+}
+
 /**
  * 新增单项工程
  *
@@ -1210,19 +1219,16 @@ function hasTender(selected, pojName, engName, tenderName){
 function AddEngineering() {
     let name = $('#engineering-name').val().trim();
     if (name === '') {
-        $('#engineering-name-info').text('请填写单项工程名称');
-        $('#engineering-name-info').show();
+        setDangerInfo($('#engineering-name-info'), '请填写单项工程名称');
         return false;
     }
     let existCallback = function () {
-        $('#engineering-name-info').text(`已存在“${$("#engineering-name").val()}”`);
-        $('#engineering-name-info').show();
+        setDangerInfo($('#engineering-name-info'), `已存在“${$("#engineering-name").val()}”`);
     };
     let sucCallback = function () {
         $('#add-engineering-dialog').modal('hide');
         $('#engineering-name').val('');
-        $('#engineering-name-info').text('');
-        $('#engineering-name-info').hide();
+        setDangerInfo($('#engineering-name-info'), '', false);
     };
     let selectedItem = Tree.selected();
     // 如果选择的是单项工程则新增同级数据
@@ -1249,39 +1255,43 @@ function AddTender() {
     try {
         let projName = $("#poj-name").val().trim();
         if(projName === ''){
-            throw '请填写建设项目名称';
+            replaceClass($('#poj-name-info'), 'text-info', 'text-danger');
+            setDangerInfo($('#poj-name-info'), '请填写建设项目名称');
+            return false;
         }
         let engName = $("#eng-name").val().trim();
         if(engName === ''){
-            throw '请填写单项工程名称';
+            replaceClass($('#eng-name-info'), 'text-info', 'text-danger');
+            setDangerInfo($('#eng-name-info'), '请填写单项工程名称');
+            return false;
         }
 
         let tenderName = $('#tender-name').val();
         if (tenderName === '') {
-            throw '请填写单位工程名称';
+            setDangerInfo($('#tender-name-info'), '请填写单位工程名称');
+            return false;
         }
 
         if(hasTender(Tree.selected(), projName, engName, tenderName)){
-            throw '已存在单位工程';
+            return false;
         }
 
         let unitPriceFile = $("#unit-price").val();
         let unitPriceName = unitPriceFile !== '' ? $("#unit-price").children("option:selected").text() : tenderName;
 
         let feeFile = $("#tender-fee-rate").val();
-       /* if (feeFile === '') {
-            throw '请选择费率文件';
-        }*/
         let feeFileName = $("#tender-fee-rate").children("option:selected").text();
 
         let valuation = $("#valuation").val();
         if(valuation === ''){
-            throw '请选择计价规则'
+            setDangerInfo($('#valuation-info'), '请选择计价规则');
+            return false;
         }
 
         let engineering = $("#tender-engineering").val();
         if (engineering === '') {
-            throw '请选择工程专业';
+            setDangerInfo($('#engineering-info'), '请选择工程专业');
+            return false;
         }
 
         let valuationName = $("#valuation").children("option:selected").text();
@@ -1347,21 +1357,18 @@ function AddTender() {
 function AddFolder() {
     let name = $('#folder-name').val().trim();
     if (name === '') {
-        $('#folder-name-info').text('请填写文件夹名称');
-        $('#folder-name-info').show();
+        setDangerInfo($('#folder-name-info'), '请填写文件夹名称');
         return false;
     }
 
     let selectedItem = Tree.selected();
     let existCallback = function () {
-        $('#folder-name-info').text(`已存在“${$("#folder-name").val()}”`);
-        $('#folder-name-info').show();
+        setDangerInfo($('#folder-name-info'), `已存在“${$("#folder-name").val()}”`);
     };
     let sucCallback = function () {
         $('#add-folder-dialog').modal('hide');
         $('#folder-name').val('');
-        $('#folder-name-info').text('');
-        $('#folder-name-info').hide();
+        setDangerInfo($('#folder-name-info'), '', false);
     };
     if (selectedItem !== null) {
         // 判断是否超过3层
@@ -1558,8 +1565,7 @@ function RenameProject(projectId, newName, parentID, callback) {
                 callback();
             } else {
                 if(result.message === '同级目录已存在相同名称数据'){
-                    $('#rename-name-info').text(`已存在“${newName}”`);
-                    $('#rename-name-info').show();
+                    setDangerInfo($('#rename-name-info'), `已存在“${newName}”`);
                 }
             }
         },

BIN
web/dest/css/images/ui-icons_444444_256x240.png


BIN
web/dest/css/images/ui-icons_555555_256x240.png


BIN
web/dest/css/images/ui-icons_777620_256x240.png


BIN
web/dest/css/images/ui-icons_777777_256x240.png


BIN
web/dest/css/images/ui-icons_cc0000_256x240.png


BIN
web/dest/css/images/ui-icons_ffffff_256x240.png