Przeglądaj źródła

Merge branch 'master' of http://192.168.1.41:3000/SmartCost/ConstructionCost

zhangweicheng 3 lat temu
rodzic
commit
01e0ed86f1

+ 3 - 3
modules/pm/facade/pm_facade.js

@@ -2583,7 +2583,7 @@ async function doDownLoadAndImport(privateDownloadUrl, info) {
               }
           } catch (error) {
               console.log(error.message);
-              doc.errorMsg = "导入失败,请检查文件!";
+              doc.errorMsg = error.message || "导入失败,请检查文件!";
               doc.status = "error";
           } finally {
               await importLogsModel.update({ key: info.key }, doc);
@@ -2968,8 +2968,8 @@ async function handleMainProjectDatas(mainData,updateData,userID) {
                 tasks.push({updateOne:{filter : updateData.update.query, update : {NextSiblingID:mainProjectID}}});
             }
             //查看是否重名;
-            let temp = await projectModel.findOne({userID:userID,ParentID:p.ParentID,name:p.name});
-            if(temp) p.name = p.name + '(' + moment(Date.now()).tz("Asia/Shanghai").format('MM-DD HH:mm:ss') + '导入)';
+            let temp = await projectModel.findOne({userID:userID,ParentID:p.ParentID,name:p.name, $or: notDeleted});
+            if(temp) throw new Error(`已存在建设项目“${p.name}”`);
         }else {
             p.ParentID = projectIDMap[p.ParentID];
             p.NextSiblingID = projectIDMap[p.NextSiblingID];

+ 4 - 2
modules/reports/rpt_component/helper/jpc_helper_common.js

@@ -144,7 +144,8 @@ let JpcCommonHelper = {
             for (let sIdx = 0; sIdx < strVal.length; sIdx++) {
                 currentW = (strVal.charCodeAt(sIdx) > 127)?chnW:otherW;
                 txtWidth += currentW;
-                if (txtWidth > areaWidth) {
+                if (txtWidth > (areaWidth - 4)) {
+                    //减4个像素是考虑到导出excel的情况
                     rst++;
                     txtWidth = currentW;
                 }
@@ -166,7 +167,8 @@ let JpcCommonHelper = {
             for (let sIdx = 0; sIdx < strVal.length; sIdx++) {
                 currentW = (strVal.charCodeAt(sIdx) > 127)?chnW:otherW;
                 txtWidth += currentW;
-                if (txtWidth > areaWidth) {
+                if (txtWidth > (areaWidth - 4)) {
+                    //减4个像素是考虑到导出excel的情况
                     if (preSIdx < sIdx) {
                         rst.push(strVal.substr(preSIdx, sIdx - preSIdx));
                         preSIdx = sIdx;

+ 17 - 0
modules/reports/rpt_component/helper/jpc_helper_flow_tab.js

@@ -2,6 +2,23 @@ let JV = require('../jpc_value_define');
 let JpcCommonHelper = require('./jpc_helper_common');
 
 let JpcFlowTabHelper = {
+    getRowHeight: function(bands, rptTpl, isEx) {
+        let rst = 0;
+        let FLOW_INFO_STR = (!isEx)?JV.NODE_FLOW_INFO:JV.NODE_FLOW_INFO_EX;
+        let tab = rptTpl[FLOW_INFO_STR][JV.NODE_FLOW_CONTENT];
+        let band = bands[tab[JV.PROP_BAND_NAME]];
+        if (band) {
+            let maxFieldMeasure = 1.0;
+            if (JV.CAL_TYPE_ABSTRACT === JpcCommonHelper.getPosCalculationType(tab[JV.PROP_CALCULATION])) {
+                let unitFactor = JpcCommonHelper.getUnitFactor(rptTpl);
+                maxFieldMeasure = 1.0 * rptTpl[FLOW_INFO_STR][JV.NODE_FLOW_CONTENT][JV.PROP_CMN_HEIGHT] * unitFactor;
+            } else {
+                maxFieldMeasure = (band.Bottom - band.Top) * rptTpl[FLOW_INFO_STR][JV.NODE_FLOW_CONTENT][JV.PROP_CMN_HEIGHT] / JV.HUNDRED_PERCENT;
+            }
+            rst = maxFieldMeasure;
+        }
+        return rst;
+    },
     getMaxRowsPerPage: function(bands, rptTpl, isEx) {
         let rst = 1;
         let FLOW_INFO_STR = (!isEx)?JV.NODE_FLOW_INFO:JV.NODE_FLOW_INFO_EX;

+ 66 - 13
modules/reports/rpt_component/jpc_flow_tab.js

@@ -361,6 +361,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
             };
             let private_get_max_lines_of_the_record = function(theRecIdx) {
                 let rst = 1;
+                let maxAmt = 1;
                 for (let loop = 0; loop < me.auto_height_fields_idx.length; loop++) {
                     /*
                     let data_field = null;
@@ -384,28 +385,25 @@ JpcFlowTabSrv.prototype.createNew = function(){
                         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('\t', '');
-                            value = value.replace(reg1, '|').replace(reg2, '|').replace(reg3, '|').replace(reg4, '|');
+                            if (typeof value === "string") {
+                                value = value.replace('\t', '');
+                                value = value.replace(reg1, '|').replace(reg2, '|').replace(reg3, '|').replace(reg4, '|');
+                            } else {
+                                // console.log(`has other value: ${value}`);
+                                value = '' + value;
+                            }
                         } else {
                             value = '';
                         }
                         JpcFieldHelper.setValue(data_field, theRecIdx, value);
                         let values = value.split('|');
-                        if (values.length > rst) rst = values.length;
+                        // if (values.length > rst) rst = values.length; // 考虑到紧凑输出,不能那么快设置rst
                         let font = private_get_font(tab_field[JV.PROP_FONT]);
-                        // if (font) {
-                        //     let fontFile = __dirname.slice(0, __dirname.length - 14) + '/util/pdf_base_files/' + fontUtil.getActualFont(font[JV.FONT_PROPS[0]], (font[JV.FONT_PROPS[3]] === 'T'), (font[JV.FONT_PROPS[4]] === 'T')) + '.ttf';
-                        //     doc.font(fontFile);
-                        //     doc.fontSize(parseInt(font[JV.FONT_PROPS[JV.FONT_PROP_IDX_HEIGHT]]));
-                        // } else {
-                        //     doc.font(__dirname.slice(0, __dirname.length - 14) + '/util/pdf_base_files/Smart.ttf');
-                        //     doc.fontSize(12);
-                        // }
                         let chkFontName = '宋体';
                         let chkFontHeight = 12;
                         if (font) {
                             chkFontName = font[JV.FONT_PROPS[0]];
-                            chkFontHeight = font[JV.FONT_PROPS[JV.FONT_PROP_IDX_HEIGHT]];
+                            chkFontHeight = parseFloat(font[JV.FONT_PROPS[JV.FONT_PROP_IDX_HEIGHT]]);
                         }
                         let hasSplitStr = false, splitStrArr = [];
                         let accAmt = 0;
@@ -419,7 +417,18 @@ JpcFlowTabSrv.prototype.createNew = function(){
                                 splitStrArr.push(i);
                             }
                         }
-                        if (accAmt > rst) rst = accAmt;
+                        if (accAmt > 3) {
+                            // 新优化,计算实际能显示完的真正行数
+                            const rowHeight = JpcFlowTabHelper.getRowHeight(bands, rptTpl, me.isEx);
+                            let tmpFV = ((chkFontHeight + JV.CLOSE_OUTPUT_ROW_BUFFER) * accAmt) / rowHeight;
+                            let tmpAmt = Math.floor(tmpFV);
+                            if (Math.ceil(tmpFV) > tmpAmt) {
+                                tmpAmt++;
+                            }
+                            if (maxAmt < tmpAmt) maxAmt = tmpAmt;
+                        } else {
+                            if (maxAmt < accAmt) maxAmt = accAmt;
+                        }
                         // if (hasSplitStr && outputType !== JV.OUTPUT_TYPE_EXCEL) {
                         if (hasSplitStr) {
                             let newValArr = [];
@@ -438,6 +447,7 @@ JpcFlowTabSrv.prototype.createNew = function(){
                         //      根据最新需求,暂时不考虑excel类型输出,换回原来逻辑
                     }
                 }
+                if (rst < maxAmt) rst = maxAmt; // 最后才设置最大结果
                 return rst;
             };
             for (let tabField of tab_fields) {
@@ -1295,11 +1305,54 @@ JpcFlowTabSrv.prototype.createNew = function(){
             if (showText) {
                 textArr = textArr.concat(showText.split('|'));
             }
+            /*
             if (contentValInfo[3] < textArr.length && contentValInfo[3] >= 0) {
                 showText = textArr[contentValInfo[3]];
             } else {
                 showText = '';
             }
+            /*/
+            // 因新逻辑要优化自动行高,不再是一个折行占用1row,而是: 
+            // a. 根据实际情况,设置了一个实际的行数值(比如共有10行,根据行高情况,可能只设置了6行的高度,在setupAutoHeightData方法里处理)
+            // b. 这里最大的难题在于跨页分配(预估会有来回调整,目前采用按比例分配原则)
+            // c. 还有个问题就是多个自动行高指标的问题
+            const ACT_ROWS = contentValInfo[4]; //经实际计算,能容纳所有数据的实际行数
+            const CURRENT_ROW = contentValInfo[3]; //从0开始
+            const QUOTA_Rate = textArr.length / ACT_ROWS; //每行显示的加权系数(超过2的话,表示给的行高太多了,需要另外一些特殊处理,后期有需要再加)
+            if (textArr.length <= 3 || ACT_ROWS > textArr.length) {
+                //表示这个一定是附属的autoheight指标,或者数据就只有3行(假如数据3行精简成2行,但刚好处于分页状态,那么无论是前一页或后一页,显示上都很纠结(多出来的一行放哪好?),所以新逻辑的起点要3行以上,少了就不折腾了,老老实实地一个萝卜一个坑)
+                if (CURRENT_ROW < textArr.length && CURRENT_ROW >= 0) {
+                    showText = textArr[CURRENT_ROW];
+                } else {
+                    showText = '';
+                }
+            } else {
+                //这里不管是不是附属autoheight指标,有足够的条件单独处理
+                // console.log(`ACT_ROWS: ${ACT_ROWS}`);
+                // console.log(`QUOTA_Rate: ${QUOTA_Rate}`);
+                if (QUOTA_Rate >= 2) {
+                    //压缩超过一半空间的话,说明给的行高度太高了,需要另外一些特殊处理,后期有需要再加
+                    console.log('压缩率异常!!!!!');
+                } else {
+                    //正常的压缩比例
+                    let startIdx = 0, endIdx = 0;
+                    if (CURRENT_ROW > 0) {
+                        endIdx = Math.round((CURRENT_ROW + 1) * QUOTA_Rate) - 1;
+                        let preEndIdx = 0;
+                        if (CURRENT_ROW > 1) {
+                            //重定位 preEndIdx
+                            preEndIdx = Math.round(CURRENT_ROW * QUOTA_Rate) - 1;
+                        }
+                        startIdx = preEndIdx + 1;
+                    }
+                    //按比例分配
+                    showText = textArr[startIdx];
+                    for (let idx = startIdx + 1; idx <= endIdx; idx++) {
+                        showText += `|${textArr[idx]}`;
+                    }
+                }
+            }
+            //*/
             let rst = JpcCommonOutputHelper.createCommonOutput(tab_field, showText, controls);
             rst[JV.PROP_AREA] = JpcAreaHelper.outputArea(tab_field[JV.PROP_AREA], band, unitFactor, rows, rowIdx, cols, colIdx, me.multiCols, multiColIdx, true, false);
             rst[JV.PROP_IS_AUTO_HEIGHT] = true;

+ 28 - 1
modules/reports/rpt_component/jpc_rte.js

@@ -4,7 +4,7 @@
 let strUtil = require('../../../public/stringUtil');
 const scMathUtil = require('../../../public/scMathUtil').getUtil();
 let JV = require('./jpc_value_define');
-let JE = {
+const JE = {
     $STR_UTIL: strUtil,
     $SC_MATH_UTIL: scMathUtil,
     F: function(fID, $CURRENT_RPT) {
@@ -173,6 +173,33 @@ let JE = {
                 dataObj[field.DataNodeName][field.DataSeq][dataObj[field.DataNodeName][field.DataSeq].length] = newValue;
             }
         }
+    },
+    alignFieldDecimal: function(sourceID, destID, $CURRENT_RPT) {
+        // 把source指标的精度align到dest
+        const me = JE;
+        let sourceField = null;
+        if (isNaN(parseInt(sourceID))) {
+            sourceField = sourceID;
+        } else {
+            sourceField = me.F(sourceID,$CURRENT_RPT);
+        }
+        let destField = null;
+        if (isNaN(parseInt(destID))) {
+            destField = destID;
+        } else {
+            destField = me.F(destID,$CURRENT_RPT);
+        }
+        if (sourceField[JV.PROP_PRECISION]) {
+            destField[JV.PROP_PRECISION] = sourceField[JV.PROP_PRECISION];
+            destField[JV.PROP_FIXED_PRECISION_AMT] = sourceField[JV.PROP_FIXED_PRECISION_AMT];
+        }
+    },
+    batchIniFields: function(IDArr, $CURRENT_RPT) {
+        // 批处理查找指标
+        const me = JE;
+        for (let idxF = 0; idxF < IDArr.length; idxF++) {
+            IDArr[idxF] = me.F(IDArr[idxF],$CURRENT_RPT);
+        }
     }
 };
 

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

@@ -1002,6 +1002,58 @@ function addDummyData(sourceData, addCfg) {
     replaceActDataArr(sourceData, rstArr);
 }
 
+function getGLJBizType2018Ex(orgType, orgCode, orgName) {
+    let rst = orgType;
+    if (orgType === GLJ_TYPE.Labour) {
+        rst = 11;
+        if (orgCode === "000000") rst = 10;
+    } else if (orgType === GLJ_TYPE.Material || (orgType >= 200 && orgType < 300) || orgType === GLJ_TYPE.Main_Material || orgType === GLJ_TYPE.Equipment) {
+        //材料
+        if (orgCode === "000000") {
+            rst = 200; //2.材料
+        } else if (orgCode === "000000_0") {
+            rst = 220; //(0) 未计价材料
+        } else if (orgCode === "000000_1") {
+            rst = 230; //(1) 计价材料
+        } else if (orgCode === "000000_2") {
+            rst = 240; //(2) 其他材料费
+        } else {
+            if (orgType === GLJ_TYPE.OTHER_MATERIAL) {
+                //其他材料
+                rst = 245;
+            } else if (orgType === GLJ_TYPE.Main_Material || orgType === GLJ_TYPE.Equipment) {
+                rst = 225;
+            } else {
+                //计价材料
+                rst = 235;
+            }
+        }
+    } else if (orgType === GLJ_TYPE.Machine || (orgType >= 300 && orgType < 400)) {
+        //机械
+        if (orgCode === "000000") {
+            rst = 300; //3.机械
+        } else if (orgCode === "000000_1") {
+            rst = 330; //(1) 机上人工
+        } else if (orgCode === "000000_2") {
+            rst = 340; //(2) 燃油动力费
+        } else if (orgCode === "000000_3") {
+            rst = 350; //(2) 施工机具摊销费
+        } else {
+            if (orgType === GLJ_TYPE.MACHINE_LABOUR) {
+                //机上人工
+                rst = 335;
+            } else if (orgType === GLJ_TYPE.FUEL_POWER_FEE) {
+                //燃油动力费
+                rst = 345;
+            } else if (oprMachines.indexOf(orgType) >= 0) {
+                //施工机具摊销费
+                rst = 355 + oprMachines.indexOf(orgType);
+            }
+        }
+    }
+    return rst;
+}
+
 function getGLJBizType2018(orgType, orgCode, orgName) {
     let rst = orgType;
     if (orgType === GLJ_TYPE.Labour) {

+ 1 - 0
public/web/rpt_value_define.js

@@ -224,6 +224,7 @@ const JV = {
     CONTROL_PROP_IDX_VERTICAL_EXCEL: 5,
     CONTROL_PROP_IDX_SHRINK_FIRST: 6,
     CONTROL_PROP_IDX_CLOSE_OUTPUT: 7,
+    CLOSE_OUTPUT_ROW_BUFFER: 4,
     BORDER_STYLE_PROPS: ["LineWeight", "DashStyle", "Color"],
     PROP_LINE_WEIGHT: "LineWeight",
     PROP_DASH_STYLE: "DashStyle",

+ 2 - 1
web/building_saas/main/js/models/exportStdInterfaceBase.js

@@ -726,7 +726,8 @@ const XML_EXPORT_BASE = (() => {
                 ParentID: data.ParentID,
                 NextSiblingID: data.NextSiblingID,
                 name: data.name,
-                code: data.code || String(curCode++)
+                code: data.code || String(curCode++),
+                projType: data.projType
             };
         }
     }

+ 12 - 4
web/building_saas/main/js/views/export_view.js

@@ -32,6 +32,7 @@ const ExportView = (() => {
         confirming: false   //导出确认
     };
     let spread = null;
+    let sheetData = [];
     //初始化设置工程编号表格
     function initSpread(datas) {
         if (spread) {
@@ -44,12 +45,15 @@ const ExportView = (() => {
         sheetCommonObj.showTreeData(sheet, sheetSetting, datas);
     }
     //获取设置的工程编号
-    function getCodeFromSheet(sheet) {
+    function getCodeFromSheet(sheet, isTwoLevel) {
         let codeCol = 1;
         let rst = [];
         //排除建设项目行
         for (let row = 1; row < sheet.getRowCount(); row++) {
-            rst.push(sheet.getText(row, codeCol) || '');
+            const rowData = (sheetData||[])[row];
+            if (rowData && (!isTwoLevel || rowData.projType === 'Tender')) {
+                rst.push(sheet.getText(row, codeCol) || '');
+            }
         }
         return rst;
     }
@@ -234,12 +238,16 @@ const ExportView = (() => {
                 projectData = _cache.getItem('projectData');
                 $("#export_index_checkbox").hide();
             }
-            initSpread(XML_EXPORT_BASE.UTIL.getCodeSheetData(projectData));
+            const shtData = XML_EXPORT_BASE.UTIL.getCodeSheetData(projectData);
+            initSpread(shtData);
+            sheetData = shtData;
         });
         //设置完工程编号后,导出数据。如果选中多个文件,导出压缩包
         $('#exportCode-confirm').click(async function () {
             // 工程编号
-            let codes = getCodeFromSheet(spread.getSheet(0));
+            const projectData = _cache.getItem('projectData');
+            const isTwoLevel = projectData ? !!projectData.isTwoLevel : false;
+            let codes = getCodeFromSheet(spread.getSheet(0), isTwoLevel);
             if (codes.includes('')) {
                 alert('单项、单位工程工程编号不可为空。');
                 STATE.confirming = false;

+ 22 - 0
web/building_saas/pm/html/project-management-share.html

@@ -83,4 +83,26 @@
             </div>
         </div>
     </div>
+</div>
+<div class="modal fade" id="share-rename-dialog" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">已存在此建设项目,请重命名</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                    <div class="form-group">
+                        <input type="text" class="form-control" placeholder="输入名称" id="share-rename-input">
+                        <span class="form-text text-danger" id="share-rename-info" style="display: none;">已存在 “建筑工程1”</span>
+                    </div>
+            </div>
+            <div class="modal-footer">
+                <a href="javascript:void(0);" class="btn btn-primary" id="share-rename-confirm">确定</a>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+            </div>
+        </div>
+    </div>
 </div>

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

@@ -769,9 +769,10 @@
                     <div class="form-group row">
                         <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">建设项目</label>
                         <div class="col">
-                            <input type="text" class="form-control form-control-sm" value="建设项目名称" readonly="">
+                            <input type="text" id="import-construction-name" class="form-control form-control-sm" value="建设项目名称">
                         </div>
                     </div>
+                    <p class="form-text text-danger" id="import-construction-name-info" style="display: none;">已存在 “建筑工程1”</p>
                     <div class="form-group row">
                         <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">文件类型</label>
                         <div class="col">

+ 28 - 2
web/building_saas/pm/js/pm_import.js

@@ -276,9 +276,16 @@ const importView = (() => {
             feeFile: { name: curData.name, id: `newFeeRate@@${taxData.fee_lib.id}` }  //新建费率文件
         };
     }
+    function constructionExist() {
+        const name = $("#import-construction-name").val().trim();
+        const sameDepthProjs = getProjs(projTreeObj.tree.selected);
+        return sameDepthProjs.some(node => node.data.name === name);
+    }
+
     function eventListen() {
         //选择文件
         $('#customFile').change(async function () {
+            $("import-construction-name-info").hide();
             let file = $(this)[0].files[0];
             $('#import-confirm').prop('disabled', true);    //确认导入无效
             $('.custom-file-label').text(`${file ? file.name : ''}`);   //设置选择框文本
@@ -303,6 +310,11 @@ const importView = (() => {
                     $('.selFile input[name="fileKind-import"]:eq(0)').prop('checked', true);    //文件类型恢复成投标
                     $('#import-taxType').val('1');  //计税方法显示回默认的一般计税法
                     $('.selFile').show();   //显示建设项目、计价规则
+                    if (constructionExist()) {
+                        $('#import-construction-name').focus();
+                        $("#import-construction-name-info").show();
+                        $("#import-construction-name-info").text(`已存在 “${$("#import-construction-name").val().trim()}”`);
+                    }
                 } catch (err) {
                     console.log(err);
                     showUploadAlert(false, err);
@@ -322,11 +334,24 @@ const importView = (() => {
                 showUploadAlert(false, '不存在有效数据。');
                 return;
             }
-            let projectName = $('.selFile input:eq(0)').val();
-            if (!projectName) {
+            if (!xmlObj.name) {
                 showUploadAlert(false, '不存在有效建设项目。');
                 return;
             }
+
+            const constructionName = $("#import-construction-name").val().trim();
+            if (constructionExist()) {
+                $('#import-construction-name').focus();
+                $("#import-construction-name-info").show();
+                $("#import-construction-name-info").text(`已存在 “${constructionName}”`);
+                return;
+            }
+            if (!constructionName) {
+                $("#import-construction-name-info").text(`建设项目名不可为空`);
+                return;
+            }
+            $("#import-construction-name-info").hide();
+
             //文件类型
             let fileKind = $('.selFile input[name="fileKind-import"]:checked').val();
             if (!fileKind) {
@@ -420,6 +445,7 @@ const importView = (() => {
             }
             let pr = new SCComponent.InitProgressBar();
             try {
+                xmlObj.name = $("#import-construction-name").val().trim();
                 //建设项目设置选择的文件类型和选择的计税方法
                 xmlObj.property.fileKind = tbcObj.fileKind;
                 xmlObj.property.taxType = tbcObj.taxType;

+ 29 - 9
web/building_saas/pm/js/pm_share.js

@@ -812,10 +812,10 @@ const pmShare = (function () {
                       return !(selected && selected.data.allowCopy && selected.data.projType === projectType.project);
                   },
                   callback: function (key, opt) {
-                      if($(".p-title").text().includes('免费')){
+                      /* if($(".p-title").text().includes('免费')){
                         hintBox.versionBox('此功能仅在专业版中提供,免费版可选择单位工程进行拷贝');
                         return;
-                      }
+                      } */
                       copyContructionProject(tree.selected);
                   }
                 },
@@ -965,18 +965,19 @@ const pmShare = (function () {
         }
 
     }
-
+    let projectQueryResult = [];
     //拷贝分享的建设项目
     //@param {Object}selected 
-    async function copyContructionProject(selected){
+    async function copyContructionProject(selected, rename){
       try {
-        let newName = getCopyName(selected);
+        let newName = rename ? rename : getCopyName(selected);
         //获取单项工程的单位工程
         let projectQuery = {$or: [{deleteInfo: null}, {'deleteInfo.deleted': false}], userID: userID,projType: "Project"};
-        const rstData = await ajaxPost('/pm/api/getProjectsByQuery', {user_id: userID, query: projectQuery, options: '-_id -property'}, false, 10000);
-        for(let project of rstData){
+        projectQueryResult = await ajaxPost('/pm/api/getProjectsByQuery', {user_id: userID, query: projectQuery, options: '-_id -property'}, false, 10000);
+        for(let project of projectQueryResult){
             if(project.name === newName){
-                alert("已存在此建设项目");
+                $("#share-rename-dialog").modal('show');
+                $("#share-rename-input").val(newName);
                 return;
             }
         }
@@ -1007,7 +1008,7 @@ const pmShare = (function () {
             node = node.parent;
             userInfo = node.data.userInfo;
         }
-        return `${orgName} (${userInfo.name}分享拷贝)`;
+        return `${orgName}`;
     }
     //清除了该节点后,可能还有该节点的数据在树上(树允许有重复数据),需要更新分享信息
     function updateAfterCancel(userID, projectID) {
@@ -1184,6 +1185,25 @@ const pmShare = (function () {
                 $.bootstrapLoading.end();
             });
         });
+        // 拷贝重命名
+        $('#share-rename-dialog').on('show.bs.modal', () => {
+            $('#share-rename-info').hide();
+            setTimeout(() => {
+                $('#share-rename-input').focus();
+            }, 200)
+        });
+        $('#share-rename-confirm').click(function () {
+            const newName = $('#share-rename-input').val().trim();
+            for(let project of projectQueryResult){
+                if(project.name === newName){
+                    $('#share-rename-info').text(`已存在 “${newName}”`);
+                    $('#share-rename-info').show();
+                    return;
+                }
+            }
+            $("#share-rename-dialog").modal('hide');
+            copyContructionProject(tree.selected, newName);
+        });
     }
 
     return {

+ 36 - 17
web/building_saas/report/js/jpc_output.js

@@ -125,6 +125,13 @@ let JpcCanvasOutput = {
             }
             return rst;
         }
+        function _chkIfCloseOutput(control, actLines, area, fontHeight) {
+            let rst = false;
+            if (control.CloseOutput === 'T' && actLines > 1) {
+                rst = true;
+            }
+            return rst;
+        }
         function private_drawText(val, area, font, control) {
             let dftFontHeight = 12;
             let output = [];
@@ -275,10 +282,11 @@ let JpcCanvasOutput = {
             //根据control的 自动折行 及 缩放优先 这俩属性 来分解cell value
             if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_WRAP]] === 'T' && control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_SHRINK_FIRST]] !== 'T') {
                 let vals = [];
-                let validAreaTxtWidth = cell[JV.PROP_AREA][JV.PROP_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] - cell[JV.PROP_AREA][JV.PROP_LEFT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+                let validAreaTxtWidth = cell[JV.PROP_AREA][JV.PROP_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] - cell[JV.PROP_AREA][JV.PROP_LEFT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT] - 1;
                 for (let val of orgValues) {
                     let actW = ctx2D.measureText(val).width;
-                    if (actW > validAreaTxtWidth) {
+                    if (actW > (validAreaTxtWidth - 4)) {
+                        //减4个像素是考虑到导出excel的情况
                         vals = vals.concat(private_splitString(val, validAreaTxtWidth, ctx2D));
                     } else {
                         vals.push(val);
@@ -318,27 +326,38 @@ let JpcCanvasOutput = {
                     }
                 }
 
-                if (font) {
-                    let dftFontHeight = parseFloat(font[JV.FONT_PROPS[1]]);
-                    let dftOthers = "";
-                    let dftFontBold = font[JV.FONT_PROPS[3]];
-                    if (dftFontBold && dftFontBold === 'T') {
-                        dftOthers = "bold " + dftOthers ;
-                    }
-                    let dftFontItalic = font[JV.FONT_PROPS[4]];
-                    if (dftFontItalic && dftFontItalic === 'T') {
-                        dftOthers = dftOthers + "italic ";
-                    }
-                    dftFontHeight = me.scaleFactor * dftFontHeight;
-                    ctx.font = dftOthers + dftFontHeight + "px " + font[JV.PROP_NAME];
+                let dftFontHeight = parseFloat(font[JV.FONT_PROPS[1]]);
+                let dftOthers = "";
+                let dftFontBold = font[JV.FONT_PROPS[3]];
+                if (dftFontBold && dftFontBold === 'T') {
+                    dftOthers = "bold " + dftOthers ;
+                }
+                let dftFontItalic = font[JV.FONT_PROPS[4]];
+                if (dftFontItalic && dftFontItalic === 'T') {
+                    dftOthers = dftOthers + "italic ";
                 }
+                dftFontHeight = me.scaleFactor * dftFontHeight;
+                ctx.font = dftOthers + dftFontHeight + "px " + font[JV.PROP_NAME];
+            // if (font) {
+            //     }
                 _splitValues(cell, control, values, ctx);
 
                 let height = cell[JV.PROP_AREA][JV.PROP_BOTTOM] - cell[JV.PROP_AREA][JV.PROP_TOP];
                 let area = [cell[JV.PROP_AREA][JV.PROP_LEFT] + me.offsetX, cell[JV.PROP_AREA][JV.PROP_TOP] + me.offsetY, cell[JV.PROP_AREA][JV.PROP_RIGHT] + me.offsetX, cell[JV.PROP_AREA][JV.PROP_BOTTOM] + me.offsetY];
+                //这里增加 ‘紧密输出’ 处理:在cell的输出空间划分出上下空间,中间行的输出间隔只有4个像素(要考虑与导出excel一致性,不能少了)
+                const isCloseOutput = _chkIfCloseOutput(control, values.length, area, dftFontHeight);
+                let closeTopOffset = 0;
+                if (isCloseOutput) {
+                    closeTopOffset = (height - (dftFontHeight + 4) * values.length) / 2;
+                }
                 for (let i = 0; i < values.length; i++) {
-                    area[JV.IDX_TOP] = cell[JV.PROP_AREA][JV.PROP_TOP] + i * (height / values.length) + me.offsetY;
-                    area[JV.IDX_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_TOP] + (i + 1) * (height / values.length) + me.offsetY;
+                    if (isCloseOutput) {
+                        area[JV.IDX_TOP] = cell[JV.PROP_AREA][JV.PROP_TOP] + closeTopOffset + i *(dftFontHeight + 4) + me.offsetY;
+                        area[JV.IDX_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_TOP] + closeTopOffset + (i + 1) *(dftFontHeight + 4) + me.offsetY;
+                    } else {
+                        area[JV.IDX_TOP] = cell[JV.PROP_AREA][JV.PROP_TOP] + i * (height / values.length) + me.offsetY;
+                        area[JV.IDX_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_TOP] + (i + 1) * (height / values.length) + me.offsetY;
+                    }
                     if (values[i] === null || values[i] === undefined || values[i] === 'null') {
                         values[i] = "";
                     }

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

@@ -57,7 +57,7 @@ let JV = {
     PAGES_SIZE_IDX: [8, 9, 11, 13, 1, 5, 7, 93],
     PAGES_SIZE: [[11.69, 16.54], [8.27, 11.69], [5.83, 8.27], [6.93, 9.84], [8.5, 11.0], [8.5, 14.0], [7.25, 10.5], [7.25, 10.5]],
 
-    OUTPUT_OFFSET: [2,2,1,3],
+    OUTPUT_OFFSET: [1,1,1,1],
     OFFSET_IDX_LEFT: 0,
     OFFSET_IDX_RIGHT: 1,
     OFFSET_IDX_TOP: 2,

+ 35 - 15
web/building_saas/report/js/rpt_jspdf.js

@@ -143,10 +143,11 @@ let JpcJsPDFHelper = {
             //根据control的 自动折行 及 缩放优先 这俩属性 来分解cell value
             if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_WRAP]] === 'T' && control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_SHRINK_FIRST]] !== 'T') {
                 let vals = [];
-                let validAreaTxtWidth = cell[JV.PROP_AREA][JV.PROP_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] - cell[JV.PROP_AREA][JV.PROP_LEFT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+                let validAreaTxtWidth = cell[JV.PROP_AREA][JV.PROP_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] - cell[JV.PROP_AREA][JV.PROP_LEFT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT] - 1;
                 for (let val of orgValues) {
                     let actW = doc.getTextWidth(val);
-                    if (actW > validAreaTxtWidth) {
+                    if (actW > (validAreaTxtWidth - 4)) {
+                        //减4个像素是考虑到导出excel的情况
                         vals = vals.concat(private_splitString(val, validAreaTxtWidth, doc));
                     } else {
                         vals.push(val);
@@ -160,6 +161,14 @@ let JpcJsPDFHelper = {
             }
         }
 
+        function _chkIfCloseOutput(control, actLines, area, fontHeight) {
+            let rst = false;
+            if (control.CloseOutput === 'T' && actLines > 1) {
+                rst = true;
+            }
+            return rst;
+        }
+
         function private_drawCellText(doc, ctx, cell, fonts, controls) {
             if (cell[JV.PROP_VALUE] !== undefined && cell[JV.PROP_VALUE] !== null) {
                 // let values = ("" + cell[JV.PROP_VALUE]).split('|');
@@ -194,22 +203,33 @@ let JpcJsPDFHelper = {
                 let area = [cell[JV.PROP_AREA][JV.PROP_LEFT] + offsetX, cell[JV.PROP_AREA][JV.PROP_TOP] + offsetY, cell[JV.PROP_AREA][JV.PROP_RIGHT] + offsetX, cell[JV.PROP_AREA][JV.PROP_BOTTOM] + offsetY];
                 let ah = height;
                 let restTopH = 0, restBottomH = 0;
-                if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_CLOSE_OUTPUT]] === 'T') {
-                    ah = (parseFloat(font[JV.FONT_PROPS[1]]) + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM]) * values.length;
-                    let restH = height - ah;
-                    if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === 'center') {
-                        restTopH = restH / 2;
-                        restBottomH = restH / 2;
-                    } else if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === 'bottom') {
-                        restBottomH = restH;
-                    } else {
-                        restTopH = restH;
-                    }
+                let dftFontHeight = parseFloat(font[JV.FONT_PROPS[1]]);
+                const isCloseOutput = _chkIfCloseOutput(control, values.length, area, dftFontHeight);
+                let closeTopOffset = 0;
+                if (isCloseOutput) {
+                    closeTopOffset = (height - (dftFontHeight + 4) * values.length) / 2;
                 }
+                // if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_CLOSE_OUTPUT]] === 'T') {
+                //     ah = (parseFloat(font[JV.FONT_PROPS[1]]) + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_TOP] + JV.OUTPUT_OFFSET[JV.OFFSET_IDX_BOTTOM]) * values.length;
+                //     let restH = height - ah;
+                //     if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === 'center') {
+                //         restTopH = restH / 2;
+                //         restBottomH = restH / 2;
+                //     } else if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === 'bottom') {
+                //         restBottomH = restH;
+                //     } else {
+                //         restTopH = restH;
+                //     }
+                // }
                 let spaceIdxArr = [];
                 for (let i = 0; i < values.length; i++) {
-                    area[JV.IDX_TOP] = cell[JV.PROP_AREA][JV.PROP_TOP] + i * (ah / values.length) + offsetY + restTopH;
-                    area[JV.IDX_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_TOP] + (i + 1) * (ah / values.length) + offsetY + restBottomH;
+                    if (isCloseOutput) {
+                        area[JV.IDX_TOP] = cell[JV.PROP_AREA][JV.PROP_TOP] + closeTopOffset + i * (dftFontHeight + 4) + offsetY;
+                        area[JV.IDX_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_TOP] + closeTopOffset + (i + 1) * (dftFontHeight + 4) + offsetY;
+                    } else {
+                        area[JV.IDX_TOP] = cell[JV.PROP_AREA][JV.PROP_TOP] + i * (ah / values.length) + offsetY + restTopH;
+                        area[JV.IDX_BOTTOM] = cell[JV.PROP_AREA][JV.PROP_TOP] + (i + 1) * (ah / values.length) + offsetY + restBottomH;
+                    }
                     if (values[i] === null || values[i] === undefined || values[i] === 'null') {
                         values[i] = "";
                     }

+ 25 - 5
web/building_saas/report/js/rpt_print.js

@@ -195,10 +195,11 @@ function _splitValues(cell, control, orgValues, ctx2D) {
     //根据control的 自动折行 及 缩放优先 这俩属性 来分解cell value
     if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_WRAP]] === 'T' && control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_SHRINK_FIRST]] !== 'T') {
         let vals = [];
-        let validAreaTxtWidth = cell[JV.PROP_AREA][JV.PROP_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] - cell[JV.PROP_AREA][JV.PROP_LEFT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT];
+        let validAreaTxtWidth = cell[JV.PROP_AREA][JV.PROP_RIGHT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_RIGHT] - cell[JV.PROP_AREA][JV.PROP_LEFT] - JV.OUTPUT_OFFSET[JV.OFFSET_IDX_LEFT] - 1;
         for (let val of orgValues) {
             let actW = ctx2D.measureText(val).width;
-            if (actW > validAreaTxtWidth) {
+            if (actW > (validAreaTxtWidth - 4)) {
+                //减4个像素是考虑到导出excel的情况
                 vals = vals.concat(private_splitString(val, validAreaTxtWidth, ctx2D));
             } else {
                 vals.push(val);
@@ -279,7 +280,7 @@ function buildText(destRst, cell, font, control, offsetX, offsetY, adjustY, canv
             let innerDftFontHeight = (dftFontHeight * 3 / 4); //SVG的字体与canvas的字体大小的切换, 不用考虑取整
             if (control) {
                 if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === "top") {
-                    y = innerArea[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_TOP] + orgFontHeight;
+                    y = innerArea[JV.IDX_TOP] + JV.OUTPUT_OFFSET[JV.IDX_TOP];
                 } else if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === "bottom") {
                     y = innerArea[JV.IDX_BOTTOM] - JV.OUTPUT_OFFSET[JV.IDX_BOTTOM];
                 } else if (control[JV.CONTROL_PROPS[JV.CONTROL_PROP_IDX_VERTICAL]] === "center") {
@@ -335,13 +336,32 @@ function buildText(destRst, cell, font, control, offsetX, offsetY, adjustY, canv
             }
         }
     };
+
+    const isCloseOutput = _chkIfCloseOutput(control, values.length, area, orgFontHeight);
+    let closeTopOffset = 0;
+    if (isCloseOutput) {
+        closeTopOffset = (height - (orgFontHeight + 4) * values.length) / 2;
+    }
     for (let vidx = 0; vidx < values.length; vidx++) {
-        area[JV.IDX_TOP] = top + vidx * (height / values.length);
-        area[JV.IDX_BOTTOM] = top + (vidx + 1) * (height / values.length);
+        if (isCloseOutput) {
+            area[JV.IDX_TOP] = top + closeTopOffset + vidx *(orgFontHeight + 4);
+            area[JV.IDX_BOTTOM] = top + closeTopOffset + (vidx + 1) *(orgFontHeight + 4);
+        } else {
+            area[JV.IDX_TOP] = top + vidx * (height / values.length);
+            area[JV.IDX_BOTTOM] = top + (vidx + 1) * (height / values.length);
+        }
         inner_draw_text(values[vidx]);
     }
 }
 
+function _chkIfCloseOutput(control, actLines, area, fontHeight) {
+    let rst = false;
+    if (control.CloseOutput === 'T' && actLines > 1) {
+        rst = true;
+    }
+    return rst;
+}
+
 function private_splitString(strVal, areaWidth, ctx) {
     let rst = [];
     if (strVal) {

+ 15 - 6
web/over_write/js/chongqing_2018_export.js

@@ -2197,17 +2197,26 @@ const XMLStandard = (function () {
             let idx = 0;
             // 从建设项目元素中筛选出单项工程元素
             let engs = _util.getElementFromSrc(obj.data, '单项工程');
-            engs.forEach(eng => {
-                // 从属性中找到编号项
-                let codeItem = eng.attrs.find(attr => attr.name === '编号');
-                codeItem.value = codes[idx++];
+            if (engs.length) {
+                engs.forEach(eng => {
+                    // 从属性中找到编号项
+                    let codeItem = eng.attrs.find(attr => attr.name === '编号');
+                    codeItem.value = codes[idx++];
+                    // 从单项工程元素中筛选出单位工程元素
+                    let tenders = _util.getElementFromSrc(eng, '单位工程');
+                    tenders.forEach(tender => {
+                        let codeItem = tender.attrs.find(attr => attr.name === '编号');
+                        codeItem.value = codes[idx++];
+                    });
+                });
+            } else {
                 // 从单项工程元素中筛选出单位工程元素
-                let tenders = _util.getElementFromSrc(eng, '单位工程');
+                let tenders = _util.getElementFromSrc(obj.data, '单位工程');
                 tenders.forEach(tender => {
                     let codeItem = tender.attrs.find(attr => attr.name === '编号');
                     codeItem.value = codes[idx++];
                 });
-            });
+            }
         });
     }
 

+ 2 - 0
web/over_write/js/chongqing_2018_import.js

@@ -1319,6 +1319,8 @@ const importXML = (() => {
                     newBase.push(`@${rowCodeMap[base]}`);
                 } else if (CalcBaseMap[base]) { //基数字典
                     newBase.push(CalcBaseMap[base]);
+                } else if (!isNaN(base)) {
+                    newBase.push(base);
                 } else {    //都没匹配到,说明软件无法识别此基数
                     illegal = true;
                     break;