Преглед изворни кода

Merge branch '1.0.0_online' of http://192.168.1.41:3000/SmartCost/ConstructionCost into 1.0.0_online

zhangweicheng пре 6 година
родитељ
комит
2ac42feada

+ 1 - 0
modules/all_models/projects.js

@@ -18,6 +18,7 @@ const ProjectSchema = new Schema({
     "ParentID": Number,
     "NextSiblingID": Number,
     "userID": String,
+    "code": {type: String, default: ''},
     "name": String,
     "projType": String,
     "recentDateTime": Date,

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

@@ -371,6 +371,15 @@ var sheetCommonObj = {
                 sheet.getRange(-1,col, -1, 1, GC.Spread.Sheets.SheetArea.viewport).locked(true);
             }
         }
+        if (setting && Array.isArray(setting.view.lockRows) && setting.view.lockRows.length) {
+            if (!setting.view.lockColumns || !setting.view.lockColumns.length) {
+                sheet.options.isProtected = true;
+                sheet.getRange(-1, 0, -1, setting.header.length, GC.Spread.Sheets.SheetArea.viewport).locked(false);
+            }
+            setting.view.lockRows.forEach(row => {
+                sheet.getRange(row, -1, 1, -1, GC.Spread.Sheets.SheetArea.viewport).locked(true);
+            });
+        }
     },
     setCheckBoxCell(row,col,sheet,val){
         var c = this.getCheckBox();

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

@@ -2087,10 +2087,11 @@
             <div class="modal-body">
                 <div class="modal-auto-height" style="overflow: hidden" id="exportSpread">
                 </div>
+                <p>*工程编号作为单项、单位工程的标识,要求在建设项目下唯一。</p>
             </div>
             <div class="modal-footer">
+                <button type="button" class="btn btn-primary" id="exportCode-confirm">确定</button>
                 <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
-                <button type="button" class="btn btn-primary" data-dismiss="modal" id="exportCode-confirm">确定</button>
             </div>
         </div>
     </div>

+ 113 - 41
web/building_saas/main/js/models/exportStandardInterface.js

@@ -181,6 +181,7 @@ const XMLStandard = (function () {
             exportKind = ExportKind.Tender;
         }
         this.exportKind = exportKind;
+        this.originalDatas = []; //未转换为xml字符串的数据
         this.fileDatas = [];
         /*
          * 检查
@@ -195,7 +196,7 @@ const XMLStandard = (function () {
             let rst = {failHints: [], filterAttrs: []};
             let dateReg = /([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8])))/;
             for (let data of datas) {
-                data.value = typeof data.value === 'undefined' || data.value === null ? '' : data.value.toString();
+                data.value = typeof data.value === 'undefined' || data.value === null ? '' : String(data.value);
                 if (data.whiteSpace && data.whiteSpace === WHITE_SPACE.COLLAPSE) {  //处理空格相关
                     data.value = data.value.replace(/[\r,\n,\t]/g, ' ');
                     data.value = data.value.trim();
@@ -250,7 +251,7 @@ const XMLStandard = (function () {
                     } else if (!data.value.length || (data.value.split('.').length > 1 && data.value.split('.')[1].length > 2)){
                         isFail = true;
                     }
-                } else if (data.type && data.type === TYPE.BOOL && !['true', 'false'].includes(data.value.toString())) {
+                } else if (data.type && data.type === TYPE.BOOL && !['true', 'false'].includes(String(data.value))) {
                     isFail = true;
                     tempFail = data.failHint
                         ? `${data.failHint}必须为true或false。`
@@ -533,22 +534,22 @@ const XMLStandard = (function () {
         function FXbills(source) {
             let attrs = [
                 {name: '项目编码', value: source.code, required: true, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE,
-                    failHint: `第${source.row}行清单分项-“编码”`},
+                    failHint: `第${source.row}行清单-“编码”`},
                 {name: '项目名称', value: source.name, required: true, minLen: 1, maxLen: 500, whiteSpace: WHITE_SPACE.COLLAPSE,
-                    failHint: `第${source.row}行清单分项-“名称”`},
+                    failHint: `第${source.row}行清单-“名称”`},
                 {name: '单位', value: source.unit, required: true, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE,
-                    failHint: `第${source.row}行清单分项-“单位”`},
+                    failHint: `第${source.row}行清单-“单位”`},
                 {name: '工程量', value: source.quantity, required: true, type: TYPE.DECIMAL,
-                    failHint: `第${source.row}行清单分项-“工程量”`},
+                    failHint: `第${source.row}行清单-“工程量”`},
                 {name: '综合单价', value: exportKind === ExportKind.Tender ? getFee(source.fees, 'common.unitFee') : '0', required: true, type: TYPE.DECIMAL},
                 {name: '综合合价', value: exportKind === ExportKind.Tender ? getFee(source.fees, 'common.totalFee') : '0', required: true, type: TYPE.NUM2},
                 {name: '其中暂估价', value: exportKind === ExportKind.Tender ? getFee(source.fees, 'estimate.totalFee') : '0', required: true, type: TYPE.NUM2},
                 {name: '主要清单标志', value: !!source.mainBills, type: TYPE.BOOL,
-                    failHint: `第${source.row}行清单分项-“主要清单标志”`},
+                    failHint: `第${source.row}行清单-“主要清单标志”`},
                 {name: '暂估清单标志', value: !!source.isEstimate, type: TYPE.BOOL,
-                    failHint: `第${source.row}行清单分项-“暂估清单标志”`},
+                    failHint: `第${source.row}行清单-“暂估清单标志”`},
                 {name: '最高限价', value: exportKind === ExportKind.Control ? source.maxPrice : '0', type: TYPE.NUM2,
-                    failHint: `第${source.row}行清单分项-“最高限价”`},
+                    failHint: `第${source.row}行清单-“最高限价”`},
                 {name: '备注', value: source.remark},
             ];
             element.call(this, '清单项目', attrs);
@@ -615,7 +616,7 @@ const XMLStandard = (function () {
             let attrs = [
                 {name: '人材机代码', value: source.code, required: true, minLen: 1, maxLen: 20, whiteSpace: WHITE_SPACE.COLLAPSE},
                 {name: '消耗量', value: source.quantity, required: true, type: TYPE.DECIMAL},
-                {name: '总消耗量', value: source.totalQuantity, required: true, type: TYPE.DECIMAL},
+                {name: '量', value: source.totalQuantity, required: true, type: TYPE.DECIMAL},
                 {name: '数量计算方式', value: 1, required: true, type: TYPE.INT, enumeration: ['1', '2']},
             ];
             element.call(this, '人材机含量', attrs);
@@ -633,8 +634,8 @@ const XMLStandard = (function () {
                 {name: '基价机械费合价', value: getFee(source.fees, 'machine.totalFee'), type: TYPE.NUM2, required: true},
                 {name: '定额机上人工基价调整单价', value: 0, type: TYPE.DECIMAL, required: true},
                 {name: '定额机上人工基价调整合价', value: 0, type: TYPE.NUM2, required: true},
-                {name: '未计材料单价', value: getFee(source.fees, 'unratedMaterial.unitFee'), type: TYPE.DECIMAL, required: true},
-                {name: '未计材料合价', value: getFee(source.fees, 'unratedMaterial.totalFee'), type: TYPE.NUM2, required: true},
+                {name: '未计材料单价', value: getFee(source.fees, 'unratedMaterial.unitFee'), type: TYPE.DECIMAL, required: true},
+                {name: '未计材料合价', value: getFee(source.fees, 'unratedMaterial.totalFee'), type: TYPE.NUM2, required: true},
                 {name: '人材机价差单价', value: scMathUtil.roundForObj(getFee(source.fees, 'labourDiff.unitFee') +
                     getFee(source.fees, 'materialDiff.unitFee') + getFee(source.fees, 'machineDiff.unitFee'), 2),
                     type: TYPE.DECIMAL, required: true},   //人材机价差通过人工、材料、机械价差相加得出
@@ -1283,7 +1284,7 @@ const XMLStandard = (function () {
             if (!expr) {
                 return '';
             }
-            expr = expr.toString();
+            expr = String(expr);
             //提取基数
             let bases = expr.split(/[\+\-\*\/]/g);
             //提取操作符
@@ -1322,7 +1323,6 @@ const XMLStandard = (function () {
             }
             return newExpr;
         }
-
         //获取需要导出的项目数据
         //@param {Number}tenderID(当前界面的单位工程ID,后台根据这个单位工程,去找其建设项目下所有数据)
         //@return {Object}(eleObj)
@@ -1795,11 +1795,11 @@ const XMLStandard = (function () {
                 failList.push('不存在分部分项清单');
                 return fbfxBills;
             }
+            //是否有清单分类,分部分项下,清单分类和清单项目不可同层存在,如果有了清单分类,则提示其他清单项目:
+            //清单xx行应是清单分类,其下必须有清单项目
+            let hasBillsClass = subEngNode.children && subEngNode.children.some(node => node.children && node.children.length);
             for (let node of subEngNode.children) {
                 if (node.data.type === billType.FB) {
-                    if (node.children.length === 0) {
-                        failList.push('清单分部下至少要有一条清单项目');
-                    }
                     //创建清单分部节点
                     let fbSource = {
                         row: detail.mainTree.nodes[detail.mainTree.prefix + node.data.ID].serialNo() + 1,
@@ -1808,14 +1808,23 @@ const XMLStandard = (function () {
                         fees: node.data.fees,
                         remark: node.data.remark
                     };
+                    if (node.children.length === 0) {
+                        failList.push(`第${fbSource.row}行清单分部下至少要有一条清单项目。`);
+                    }
                     let fbBills = new FBBills(fbSource);
                     fbfxBills.children.push(fbBills);
                     //创建清单项目节点
                     for (let subNode of node.children) {
+                        //detail.mainTree.nodes[detail.mainTree.prefix + node.data.ID].serialNo() + 1,
                         let fx = loadBills(subNode, detail);
                         fbBills.children.push(fx);
                     }
                 } else {
+                    //第一层有了分部,不能有分项
+                    if (hasBillsClass) {
+                        let row = detail.mainTree.nodes[detail.mainTree.prefix + node.data.ID].serialNo() + 1;
+                        failList.push(`第${row}行清单应是清单分部,其下必须有清单项目。<span style="color: red">(错误清单结构)</span>`);
+                    }
                     let fxBills = loadBills(node, detail);
                     fbfxBills.children.push(fxBills);
                 }
@@ -1856,6 +1865,8 @@ const XMLStandard = (function () {
             }
             return csxmBills;
             function loadZZCS(parent, nodes) {
+                let hasBillsClass = nodes && nodes.some(node => node.children && node.children.length);
+                //组织措施分类和公式计算措施项不能出现在同层中
                 for (let node of nodes) {
                     if (node.children.length > 0) {    //组织措施分类
                         let classSource = {
@@ -1880,9 +1891,9 @@ const XMLStandard = (function () {
                             feeType: FEE_TYPE[getNodeFlag(node)] || FEE_TYPE['0']
                         };
                         source.calcBaseState = transformCalcBaseState(detail, source.calcBase);
-                        /*if (source.feeType === '1800') {
-                            debugger;
-                        }*/
+                        if (hasBillsClass) {
+                            failList.push(`第${source.row}行清单应是清单分类,其下必须有清单项目。<span style="color: red">(错误清单结构)</span>`);
+                        }
                         let formula = new FormulaCalcMeasure(source);
                         parent.children.push(formula);
                     }
@@ -1895,6 +1906,7 @@ const XMLStandard = (function () {
                 }
             }
             function loadJSCS(parent, nodes) {
+                let hasBillsClass = nodes && nodes.some(node => node.children && node.children.length);
                 for (let node of nodes) {
                     if (node.children.length > 0) {    //技术措施分类
                         let classSource = {
@@ -1906,6 +1918,10 @@ const XMLStandard = (function () {
                         parent.children.push(jscsClass);
                         loadJSCS(jscsClass, node.children);
                     } else {    //清单项目
+                        if (hasBillsClass) {
+                            let row = detail.mainTree.nodes[detail.mainTree.prefix + node.data.ID].serialNo() + 1;
+                            failList.push(`第${row}行清单应是清单分类,其下必须有清单项目。<span style="color: red">(错误清单结构)</span>`);
+                        }
                         parent.children.push(loadBills(node, detail));
                     }
                 }
@@ -2079,6 +2095,7 @@ const XMLStandard = (function () {
             }
             //加载服务费项
             function loadService(parent, nodes) {
+                let hasBillsClass = nodes && nodes.some(node => node.children && node.children.length);
                 for (let node of nodes) {
                     if (node.children.length > 0) {    //总承包服务费分类
                         let classSource = {
@@ -2101,6 +2118,9 @@ const XMLStandard = (function () {
                             fees: node.data.fees,
                             remark: node.data.remark
                         };
+                        if (hasBillsClass) {
+                            failList.push(`第${source.row}行清单应是清单分类,其下必须有清单项目。<span style="color: red">(错误清单结构)</span>`);
+                        }
                         parent.children.push(new TurnKeyContractItem(source));
                     }
                 }
@@ -2260,7 +2280,7 @@ const XMLStandard = (function () {
                     let adjPrice = gljUtil.getAdjustPrice(glj, detail.projectGLJ.datas,
                         curPMData.tender.property.calcOptions, detail.labourCoe.datas, curPMData.tender.property.decimal, false, _, scMathUtil);
                     //获取人材机费用类别: 1=人工费 2=材料费 3=机械费 4=未计价费
-                    let feeType = glj.type.toString()[0];
+                    let feeType = String(glj.type)[0];
                     if (feeType && !['1', '2', '3'].includes(feeType)) {
                         feeType = '4';
                     }
@@ -2346,9 +2366,7 @@ const XMLStandard = (function () {
                     //如果是有[]的基数则转换为其简称,如“[定额人工费]”对应的检查是"RGF"
                     let calcBase = calcItem.dispExpr.replace(/\[[\u4e00-\u9fa5]+\]/g, str => rationBaseShort[str] ? rationBaseShort[str] : '');
                     let feeType = calcProgram.feeTypes.find(data => data.type === calcItem.fieldName);
-                    if (feeType) {
-                        feeType = feeType.code;
-                    }
+                    feeType = feeType ? feeType.code : '1800';
                     let source = {
                         serialNo: idx + 1,
                         rowCode: `F${idx + 1}`,
@@ -2430,6 +2448,55 @@ const XMLStandard = (function () {
                 return output.join('');
             }
         }
+        //获取工程编号表格相关数据(导出需要弹出工程编号让用户选择)
+        this.getSheetData = function (PMData) {
+            let curCode = '0';
+            let sheetData = [];
+            sheetData.push(getObj(PMData));
+            PMData.children.forEach(eng => {
+                sheetData.push(getObj(eng));
+                eng.children.forEach(tender => {
+                    sheetData.push(getObj(tender));
+                });
+            });
+            //建设项目父ID设置为-1
+            if (sheetData.length) {
+                sheetData[0].ParentID = -1;
+                sheetData[0].code = '';
+            }
+            return sheetData;
+            function getObj(data) {
+                return {
+                    collapsed: false,
+                    ID: data.ID,
+                    ParentID: data.ParentID,
+                    NextSiblingID: data.NextSiblingID,
+                    name: data.name,
+                    code: data.code || String(curCode++)
+                };
+            }
+        };
+        //从srcNode节点中获取为target实例的节点
+        function getNodeFromSrc(srcNode, target) {
+            if (!srcNode || !srcNode.children || !srcNode.children.length) {
+                return [];
+            }
+            return srcNode.children.filter(node => node instanceof target);
+        }
+        //设置完工程编号后,更新原始数据
+        this.setupCode = function (codeDatas) {
+            this.originalDatas.forEach(orgData => {
+                let curIdx = 0;
+                let engs = getNodeFromSrc(orgData.data, Engineering);
+                engs.forEach(eng => {
+                    eng.attrs.find(attr => attr.name === '编号').value = codeDatas[curIdx++];
+                    let tenders = getNodeFromSrc(eng, Tender);
+                    tenders.forEach(tender => {
+                        tender.attrs.find(attr => attr.name === '编号').value = codeDatas[curIdx++];
+                    });
+                });
+            });
+        };
         /*
          * 导出数据
          * @param {Number}tenderID(当前界面的单位工程ID,后台根据这个单位工程,根据导出粒度去找其建设项目下相关数据)
@@ -2442,33 +2509,38 @@ const XMLStandard = (function () {
             }
             let eleData = await loadProject(tenderID);
             this.datas = eleData;
+            this.PMData = curPMData.project;
             if (!eleData) {
                 return;
             }
-            //转换成xml字符串
-            let xmlStr = toXMLStr([eleData]);
-            //加上xml声明
-            xmlStr = `<?xml version="1.0" encoding="utf-8"?>${xmlStr}`;
-            //格式化
-            xmlStr = formatXml(xmlStr);
-            let blob = new Blob([xmlStr], {type: 'text/plain;charset=utf-8'});
-            failList = [];
-            this.fileDatas.push({blob: blob, fileName: `重庆标准交换数据(${FILE_KIND[exportKind]}).QTF`});
-            return blob;
-            saveAs(blob, '重庆标准交换数据.QTF');
-        }
+            this.originalDatas.push({data: this.datas, fileName: `重庆标准交换数据(${FILE_KIND[exportKind]}).QTF`});
+        };
         //导出文件
         this.exportFile = async function () {
-            if (this.fileDatas.length === 1) {  //导出文件
-                saveAs(this.fileDatas[0].blob, this.fileDatas[0].fileName);
-            } else if (this.fileDatas.length > 1) { //导出压缩包
+            let fileDatas = [];
+            //源数据转换成blob
+            for (let orgData of this.originalDatas) {
+                //转换成xml字符串
+                let xmlStr = toXMLStr([orgData.data]);
+                //加上xml声明
+                xmlStr = `<?xml version="1.0" encoding="utf-8"?>${xmlStr}`;
+                //格式化
+                xmlStr = formatXml(xmlStr);
+                let blob = new Blob([xmlStr], {type: 'text/plain;charset=utf-8'});
+                fileDatas.push({blob: blob, fileName: orgData.fileName});
+            }
+            //导出文件
+            if (fileDatas.length === 1) {
+                saveAs(fileDatas[0].blob, fileDatas[0].fileName);
+            } else if (fileDatas.length > 1) { //导出压缩包
                 let zip = new JSZip();
-                for (let file of this.fileDatas) {
+                for (let file of fileDatas) {
                     zip.file(file.fileName, file.blob, {binary: true});
                 }
                 let zipFile = await zip.generateAsync({type: 'blob'});
                 saveAs(zipFile, '重庆标准交换数据.zip');
             }
-        }
+        };
+
     }
 })();

+ 5 - 1
web/building_saas/main/js/models/importStandardInterface.js

@@ -242,6 +242,7 @@ const ImportXML = (() => {
                 return {
                     projType: ProjectType.Engineering,
                     name: getValue(src, ['_名称']),
+                    code: getValue(src, ['_编号']),
                     tenders: loadTender(src)
                 };
             });
@@ -254,6 +255,7 @@ const ImportXML = (() => {
                 return {
                     projType: ProjectType.Tender,
                     name: getValue(src, ['_名称']),
+                    code: getValue(src, ['_编号']),
                     engineering: getValue(src, ['_专业']),    //可能跟我们软件里的工程专业对应不上
                     projectFeature: loadProjectFeature(src),
                     feeSummary: loadFeeSummary(src),     //单位工程费汇总
@@ -1291,7 +1293,7 @@ const ImportXML = (() => {
             };
             for (let i = 0; i < xmlObj.engs.length; i++) {
                 let curEng = xmlObj.engs[i],
-                    preEng = xmlObj.engs[i - 1];
+                    preEng = postConstructData.engs[i - 1];
                 curEng.ID = IDPlaceholder.project++;
                 curEng.ParentID = xmlObj.ID;
                 curEng.NextSiblingID = -1;
@@ -1302,6 +1304,7 @@ const ImportXML = (() => {
                     ID: curEng.ID,
                     ParentID: curEng.ParentID,
                     NextSiblingID: curEng.NextSiblingID,
+                    code: curEng.code,
                     name: curEng.name,
                     projType: curEng.projType,
                     shareInfo: [],
@@ -1336,6 +1339,7 @@ const ImportXML = (() => {
                 ID: tenderData.ID,
                 ParentID: tenderData.ParentID,
                 NextSiblingID: tenderData.NextSiblingID,
+                code: tenderData.code,
                 name: tenderData.name,
                 projType: tenderData.projType,
                 property: tenderData.property,

+ 114 - 14
web/building_saas/main/js/views/export_view.js

@@ -15,14 +15,40 @@ const ExportView = (() => {
         header: [
             {headerName: '名称', headerWidth: 200, dataCode: 'name', dataType: 'String'},
             {headerName: '工程编号', headerWidth: 200, dataCode: 'code', dataType: 'String'},
-        ]
+        ],
+        view: {
+            lockColumns: ['name'],
+            lockRows: [0]
+        }
     };
+    //操作状态
+    const STATE = {
+        checking: false,    //自检
+        exporting: false,   //导出
+        confirming: false   //导出确认
+    };
+    let spread = null;
     //初始化设置工程编号表格
-    function initSpread() {
-        let spread = SheetDataHelper.createNewSpread($("#exportSpread")[0], 1);
+    function initSpread(datas) {
+        if (spread) {
+            return;
+        }
+        spread = SheetDataHelper.createNewSpread($("#exportSpread")[0], 1);
         sheetCommonObj.spreadDefaultStyle(spread);
         let sheet = spread.getSheet(0);
         sheetCommonObj.initSheet(sheet, sheetSetting, 30);
+        sheet.setRowCount(datas.length);
+        sheetCommonObj.showTreeData(sheet, sheetSetting, datas);
+    }
+    //获取设置的工程编号
+    function getCodeFromSheet(sheet) {
+        let codeCol = 1;
+        let rst = [];
+        //排除建设项目行
+        for (let row = 1; row < sheet.getRowCount(); row++) {
+            rst.push(sheet.getValue(row, codeCol) || '');
+        }
+        return rst;
     }
     //事件监听
     function exportListener() {
@@ -32,10 +58,14 @@ const ExportView = (() => {
             if (!checkedDatas.length) {
                 return;
             }
+            if (STATE.checking) {
+                return;
+            }
+            STATE.checking = true;
             let pr = new SCComponent.InitProgressBar();
-            pr.start('导出数据接口', '正在自检,请稍候……');
             try {
-                if (!xmlObj || !xmlObj.fileDatas.length) {
+                if (!xmlObj || !xmlObj.originalDatas.length) {
+                    pr.start('导出数据接口', '正在自检,请稍候……');
                     xmlObj = new XMLStandard(userID, 1);
                     for (let checkedData of checkedDatas) {
                         let fileKind = $(checkedData).val();
@@ -53,50 +83,120 @@ const ExportView = (() => {
                 alert(err);
             }
             pr.end();
+            setTimeout(() => {
+                STATE.checking = false;
+            }, 300);
         });
 
-        //导出接口,如果选中多个文件,导出压缩包
+        //导出接口,如果没有错误,弹出工程编号设置窗口
         $('#export-confirm').click(async function () {
             let checkedDatas = $('#export input[type="checkbox"]:checked');
             if (!checkedDatas.length) {
                 return;
             }
+            if (STATE.exporting) {
+                return;
+            }
+            STATE.exporting = true;
             let pr = new SCComponent.InitProgressBar();
-            pr.start('导出数据接口', '正在导出文件,请稍候……')
             try {
-                if (!xmlObj || !xmlObj.fileDatas.length) {
+                let isPring = false;    //是否调用了进度条(控制工程窗口什么时候显示,优化交互)
+                if (!xmlObj || !xmlObj.originalDatas.length) {
+                    isPring = true;
+                    pr.start('导出数据接口', '正在导出文件,请稍候……');
                     xmlObj = new XMLStandard(userID, 1);
                     for (let checkedData of checkedDatas) {
                         let fileKind = $(checkedData).val();
                         await xmlObj.toXml(projectObj.project.ID(), fileKind);
                     }
+                    pr.end();
                 }
-                console.log(xmlObj);
-                //设置提示弹窗
+                //错误-设置提示弹窗
                 if (xmlObj.failList.length * 20 > 400) {
                     $('#hintBox_caption').addClass('export-check');
                 }
                 if (xmlObj.failList.length) {
                     throw xmlObj.failList.join('<br/>');
                 }
-                //可能先执行过自检了,已经有组装好的数据了,可以直接导出
+                //弹出工程编号设置窗口
+                if (isPring) {
+                    setTimeout(() => {
+                        $('#exportCode').modal('show');
+                    }, 300);
+                } else {
+                    $('#exportCode').modal('show');
+                }
+            } catch (err) {
                 pr.end();
+                alert(err);
+            }
+            setTimeout(() => {
+                STATE.exporting = false;
+            }, 300);
+        });
+        //工程编号设置窗口-----
+        //设置工程编号
+        $('#exportCode').on('shown.bs.modal', function () {
+            if (!xmlObj) {
+                alert('数据错误!');
+                $(this).modal('hide');
+                return false;
+            }
+            initSpread(xmlObj.getSheetData(xmlObj.PMData));
+        });
+        //设置完工程编号后,导出数据。如果选中多个文件,导出压缩包
+        $('#exportCode-confirm').click(async function () {
+            if (!spread || !xmlObj) {
+                return false;
+            }
+            if (STATE.confirming) {
+                return;
+            }
+            STATE.confirming = true;
+            let pr = new SCComponent.InitProgressBar();
+            try {
+                let codeDatas = getCodeFromSheet(spread.getSheet(0));
+                if (codeDatas.includes('')) {
+                    alert('单项、单位工程工程编号不可为空。');
+                    STATE.confirming = false;
+                    return false;
+                }
+                if ([...new Set(codeDatas)].length !== codeDatas.length) {
+                    alert('单项、单位工程工程编号必须唯一。');
+                    STATE.confirming = false;
+                    return false;
+                }
+                xmlObj.setupCode(codeDatas);
+                pr.start('导出数据接口', '正在导出文件,请稍候……');
                 await xmlObj.exportFile();
-                console.log(xmlObj);
-                $('#export').modal('hide');
             } catch (err) {
-                pr.end();
                 alert(err);
             }
+            console.log(xmlObj);
+            pr.end();
+            $('#exportCode').modal('hide');
+            $('#export').modal('hide');
+            setTimeout(() => {
+                STATE.confirming = false;
+            }, 300);
+
         });
+        //导出窗口--------
         $('#export').on('show.bs.modal', function () {
             xmlObj = null;
         });
         $('#export').on('hide.bs.modal', function() {
             xmlObj = null;
+            STATE.checking = false;
+            STATE.exporting = false;
+            STATE.confirming = false;
             //恢复设置提示弹窗 因为是共用的alert
             $('#hintBox_caption').removeClass('export-check');
             $('#export input[type="checkbox"]:eq(0)').prop('checked', true);
+            if (spread) {
+                spread.destroy();
+                spread = null;
+            }
         });
         $('#export input[type="checkbox"]').click(function () {
             xmlObj = null;

+ 7 - 1
web/building_saas/pm/js/pm_ajax.js

@@ -24,7 +24,7 @@ var GetAllProjectData = function (callback) {
     });
 }
 // 更新数据到服务器
-var UpdateProjectData = function (updateData, callback) {
+var UpdateProjectData = function (updateData, callback, errCB) {
     $.ajax({
         type:"POST",
         url: '/pm/api/updateProjects',
@@ -36,10 +36,16 @@ var UpdateProjectData = function (updateData, callback) {
             if (result.error === 0) {
                 callback(result.data);
             } else {
+                if (errCB) {
+                    errCB();
+                }
                 alert('error: ' + result.message);
             }
         },
         error: function(jqXHR, textStatus, errorThrown){
+            if (errCB) {
+                errCB();
+            }
             alert('error ' + textStatus + " " + errorThrown);
         }
     });

+ 12 - 3
web/building_saas/pm/js/pm_import.js

@@ -435,6 +435,10 @@ const importView = (() => {
         });
         //确认导入
         $('#import-confirm').click(async function () {
+            if (STATE.importing) {
+                return;
+            }
+            STATE.importing = true;
             if (tbcObj && tbcObj.checkValid()) {
                 return;
             }
@@ -467,9 +471,9 @@ const importView = (() => {
                 }
                 //console.log(xmlObj);
                 $('#importInterface').modal('hide');
-                //let importData = await importXML.transformData(xmlObj);
+                /*let importData = await importXML.transformData(xmlObj);
+                console.log(importData);*/
                 pr.start('导入文件', '正在生成文件,请稍候……');
-
                 let importData = await importXML.transformData(xmlObj);
                 let blob = new Blob([JSON.stringify(importData)], {type: 'text/plain;charset=utf-8'});
                 console.log(blob);
@@ -488,6 +492,9 @@ const importView = (() => {
                             doAfterImport(response.data);
                         }
                         pr.end();
+                        setTimeout(function () {
+                            STATE.importing = false;
+                        }, 500);
                     },
                     error: function(jqXHR){
                         pr.end();
@@ -495,7 +502,9 @@ const importView = (() => {
                     }
                 });
             } catch (err) {
-                console.log(err);
+                setTimeout(function () {
+                    STATE.importing = false;
+                }, 500);
                 pr.end();
                 alert(err);
             }

+ 128 - 48
web/building_saas/pm/js/pm_newMain.js

@@ -65,6 +65,15 @@ function delayKeyup(callback) {
     }, delayTime);
 }
 const addPath = {p_e_t: 'p_e_t', e_t: 'e_t', t: 't'};
+//操作状态
+const STATE = {
+    addingTender: false,
+    addingEng: false,
+    addingProject: false,
+    addingFolder: false,
+    deleting: false,
+    importing: false
+};
 const projTreeObj = {
     tree: null,
     workBook: null,
@@ -1630,10 +1639,17 @@ $(document).ready(function() {
         if (!validRequiredData($('#projInfoStep'))) {
             return;
         }
+        if (STATE.addingProject) {
+            return;
+        }
+        STATE.addingProject = true;
         if (needfulInfoData && Array.isArray(needfulInfoData)) {
             updateRequiredData($('#projInfoStep'), needfulInfoData);
         }
-        AddProject();
+        let suc = AddProject();
+        if (suc === false) {
+            STATE.addingProject = false;
+        }
     });
     //新建建设项目-下一步
     $('#add-proj-next').click(function () {
@@ -1811,7 +1827,14 @@ $(document).ready(function() {
 
     // 新增单项工程操作
     $("#add-engineering-confirm").click(function() {
-        AddEngineering();
+        if (STATE.addingEng) {
+            return;
+        }
+        STATE.addingEng = true;
+        let suc = AddEngineering();
+        if (suc === false) {
+            STATE.addingEng = false;
+        }
     });
 
     //新建单位工程-建设项目提示
@@ -2142,10 +2165,11 @@ $(document).ready(function() {
             let opts = data.options.split('@');
             $cell = $(`<select name="${data.key}" class="form-control form-control-sm"><option>请选择</option></select>`);
             for (let opt of opts) {
-                $cell.append($(`<option value="${opt}">${opt}</option>`));
+                $cell.append($(`<option ${data.value === opt ? 'selected' : ''} value="${opt}">${opt}</option>`));
             }
         } else {
-            $cell = $(`<input type="${cellType}" ${cellType === 'number' ? 'min="0"' : ''} name="${data.key}" class="form-control form-control-sm" placeholder="请输入">`);
+            $cell = $(`<input type="${cellType}" ${cellType === 'number' ? 'min="0"' : ''} name="${data.key}"
+                       value="${data.value}" class="form-control form-control-sm" placeholder="请输入">`);
         }
         let $row = $(`<div class="form-group row"></div>`),
             $col = $(`<div class="col"></div>`);
@@ -2205,12 +2229,16 @@ $(document).ready(function() {
 
     // 新增单位工程
     $("#add-tender-confirm").click(function() {
+        if (STATE.addingTender) {
+            return;
+        }
         if (getAddPath() === addPath.p_e_t && !validRequiredData($('#infoStep'))) {
             return;
         }
         if (!validRequiredData($('#featureStep'))) {
             return;
         }
+        STATE.addingTender = true;
         if (needfulInfoData && Array.isArray(needfulInfoData)) {
             updateRequiredData($('#infoStep'), needfulInfoData);
         }
@@ -2219,13 +2247,20 @@ $(document).ready(function() {
         }
         let suc = AddTender();
         if(suc === false){
-            $('#add-tender-confirm').removeClass('disabled');
+            STATE.addingTender = false;
         }
     });
 
     // 新增文件夹操作
     $("#add-folder-confirm").click(function() {
-        AddFolder();
+        if (STATE.addingFolder) {
+            return;
+        }
+        STATE.addingFolder = true;
+        let suc = AddFolder();
+        if (suc === false) {
+            STATE.addingFolder = false;
+        }
     });
 
     // 删除时文字替换
@@ -2264,9 +2299,13 @@ $(document).ready(function() {
 
     // 删除操作
     $('#delete-confirm').click(function () {
+        if (STATE.deleting) {
+            return;
+        }
+        STATE.deleting = true;
         let updateData = null;
         let dialog = $('#del');
-        if (projTreeObj.tree) {
+        if (projTreeObj.tree && projTreeObj.tree.selected) {
             updateData = GetDeleteUpdateData(projTreeObj.tree.selected);
             UpdateProjectData(updateData, function () {
                 dialog.modal('hide');
@@ -2283,6 +2322,14 @@ $(document).ready(function() {
                 if(selected.data.projType == projectType.tender||selected.data.projType == projectType.engineering){
                     projTreeObj.refreshNodeData(refreshNodes);//刷新工程造价信息
                 }
+                //快速点击时,第一个项目删除成功了,可能会删除多项目
+                setTimeout(function () {
+                    STATE.deleting = false;
+                }, 500);
+            }, function () {
+                setTimeout(function () {
+                    STATE.deleting = false;
+                }, 500);
             });
         }
     });
@@ -2696,11 +2743,21 @@ function AddProject() {
     }
     let existCallback = function () {
         setDangerInfo($('#project-name-info'), `已存在“${$("#project-name").val()}”`);
+        STATE.addingProject = false;
     };
     let sucCallback = function () {
+        $('#addProjOk').removeClass('disabled');
         $('#add-project-dialog').modal('hide');
         $('#project-name').val('');
         setDangerInfo($('#project-name-info'), '', false);
+        setTimeout(function () {
+            STATE.addingProject = false;
+        }, 500);
+    };
+    let errCB = function () {
+        setTimeout(function () {
+            STATE.addingProject = false;
+        }, 500);
     };
     let selectedItem = projTreeObj.tree.selected;
 
@@ -2718,18 +2775,18 @@ function AddProject() {
         valuationType: curValutionType
     };
     if(!selectedItem){
-        AddSiblingsItem(selectedItem, name, property, projectType.project, existCallback, sucCallback);
+        AddSiblingsItem(selectedItem, name, property, projectType.project, existCallback, sucCallback, errCB);
     }
     else {
         if(selectedItem.data.projType === projectType.project){
-            AddSiblingsItem(selectedItem, name, property, projectType.project, existCallback, sucCallback);
+            AddSiblingsItem(selectedItem, name, property, projectType.project, existCallback, sucCallback, errCB);
         }
         else if(selectedItem.data.projType === projectType.engineering || selectedItem.data.projType === projectType.tender){
             let proj = selectedItem.parent.data.projType === projectType.project ? selectedItem.parent : selectedItem.parent.parent;
-            AddSiblingsItem(proj, name, property, projectType.project, existCallback, sucCallback);
+            AddSiblingsItem(proj, name, property, projectType.project, existCallback, sucCallback, errCB);
         }
         else if(selectedItem.data.projType === projectType.folder){
-            AddChildrenItem(selectedItem, name, property, projectType.project, existCallback, sucCallback);
+            AddChildrenItem(selectedItem, name, property, projectType.project, existCallback, sucCallback, errCB);
         }
     }
 }
@@ -2788,7 +2845,7 @@ function getAddPath() {
     }
 }
 
-function AddTenderItems(selected, projName, engName, tenderName, property, callback){
+function AddTenderItems(selected, projName, engName, tenderName, property, callback, errCB){
     let path, updateDatas = [];
     let tempProjs = getProjs(selected);
     let tempProj = getNodeByName(projName, tempProjs);
@@ -2857,8 +2914,8 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
                 let engNode = projTreeObj.insert(engData, pojNode, null);
                 projTreeObj.insert(tenderData, engNode, null);
                 callback();
-            });
-        });
+            }, errCB);
+        }, errCB);
     }
     else if(path === addPath.e_t){
         GetNewProjectId(2, function (IDs) {
@@ -2895,8 +2952,8 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
                 let engNode = projTreeObj.insert(engData, tempProj, next);
                 projTreeObj.insert(tenderData, engNode, null);
                 callback();
-            });
-        });
+            }, errCB);
+        }, errCB);
     }
     else if(path === addPath.t){
         GetNewProjectId(1, function (IDs) {
@@ -2917,8 +2974,8 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
                     }
                 });
                 callback();
-            });
-        });
+            }, errCB);
+        }, errCB);
     }
 }
 
@@ -2930,7 +2987,7 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
  * @param {function} callback
  * @return {void}
  */
-function AddChildrenItem(selected, name, property, type, existCallback, sucCallback) {
+function AddChildrenItem(selected, name, property, type, existCallback, sucCallback, errCB) {
     if(!selected){
         selected = projTreeObj.tree.selected;
     }
@@ -2956,8 +3013,8 @@ function AddChildrenItem(selected, name, property, type, existCallback, sucCallb
                     }
                 });
                 sucCallback();
-            });
-        });
+            }, errCB);
+        }, errCB);
     }
 }
 
@@ -2969,14 +3026,13 @@ function AddChildrenItem(selected, name, property, type, existCallback, sucCallb
  * @param {function} callback
  * @return {void}
  */
-function AddSiblingsItem(selected, name, property, type, existCallback, sucCallback) {
+function AddSiblingsItem(selected, name, property, type, existCallback, sucCallback, errCB) {
     if(!selected){
         selected = projTreeObj.tree.selected;
     }
     let parent = selected ? selected.parent : projTreeObj.tree._root;
     let next = selected ? selected.nextSibling : projTreeObj.tree.firstNode();
     if(existName(name, parent.children, type)){
-        //alert('同级目录已存在相同名称数据.');
         existCallback();
     }
     else {
@@ -2995,8 +3051,8 @@ function AddSiblingsItem(selected, name, property, type, existCallback, sucCallb
                     }
                 });
                 sucCallback();
-            });
-        });
+            }, errCB);
+        }, errCB);
     }
 }
 
@@ -3337,24 +3393,33 @@ function AddEngineering() {
     name = whiteSpaceCollapse(name);
     let existCallback = function () {
         setDangerInfo($('#engineering-name-info'), `已存在“${$("#engineering-name").val()}”`);
+        STATE.addingEng = false;
     };
     let sucCallback = function () {
         $('#add-engineering-dialog').modal('hide');
         $('#engineering-name').val('');
         setDangerInfo($('#engineering-name-info'), '', false);
+        setTimeout(function () {
+            STATE.addingEng = false;
+        }, 500);
+    };
+    let errCB = function () {
+        setTimeout(function () {
+            STATE.addingEng = false;
+        }, 500);
     };
     let selectedItem = projTreeObj.tree.selected;
     // 如果选择的是单项工程则新增同级数据
     if(selectedItem){
         if(selectedItem.data.projType === projectType.project){
-            AddChildrenItem(selectedItem, name, null, projectType.engineering, existCallback, sucCallback);
+            AddChildrenItem(selectedItem, name, null, projectType.engineering, existCallback, sucCallback, errCB);
         }
         else if(selectedItem.data.projType === projectType.engineering){
-            AddSiblingsItem(selectedItem, name, null, projectType.engineering, existCallback, sucCallback);
+            AddSiblingsItem(selectedItem, name, null, projectType.engineering, existCallback, sucCallback, errCB);
         }
         else if(selectedItem.data.projType === projectType.tender){
             let proj = selectedItem.parent;
-            AddSiblingsItem(proj, name, null, projectType.engineering, existCallback, sucCallback);
+            AddSiblingsItem(proj, name, null, projectType.engineering, existCallback, sucCallback, errCB);
         }
     }
 }
@@ -3366,7 +3431,6 @@ function AddEngineering() {
  */
 function AddTender() {
     try {
-        $('#add-tender-confirm').addClass('disabled');
         let projName = $("#poj-name").val().trim();
         if(projName === ''){
             replaceClass($('#poj-name-info'), 'text-info', 'text-danger');
@@ -3442,7 +3506,7 @@ function AddTender() {
         let libs = getEngineeringLib(engineeringName + feeName, engineeringList);
         if(!libs){
             alert('数据错误,无法确定工程专业库!');
-            return;
+            return false;
         }
         // 一个项目里面,这两个文件必须得有,而界面又没有像费率、单价文件那样给出可选项。所以这里给出提示。
         if (!libs.artificial_lib)  throw '编办没有绑定人工系数标准文件';
@@ -3454,18 +3518,24 @@ function AddTender() {
         let calcProgramName = $('#tender-calcProgram').children("option:selected").text();
 
         let callback = function() {
-            $('#add-tender-confirm').removeClass('disabled');
-            $("#add-tender-dialog").modal("hide");
-            $('#tender-name').val('');
-            $("#tender-fee-rate").children("option").removeAttr("selected");
-            $("#tender-engineering").children("option").removeAttr("selected");
-            $("#tender-calcProgram").children("option").removeAttr("selected");
-            $("#poj-name").val('');
-            $("#poj-name-info").hide();
-            $("#eng-name").val('');
-            $("#eng-name-info").hide();
-
-        };
+                $("#add-tender-dialog").modal("hide");
+                $('#tender-name').val('');
+                $("#tender-fee-rate").children("option").removeAttr("selected");
+                $("#tender-engineering").children("option").removeAttr("selected");
+                $("#tender-calcProgram").children("option").removeAttr("selected");
+                $("#poj-name").val('');
+                $("#poj-name-info").hide();
+                $("#eng-name").val('');
+                $("#eng-name-info").hide();
+                setTimeout(function () {
+                    STATE.addingTender = false;
+                }, 500);
+            },
+            errCB = function () {
+                setTimeout(function () {
+                    STATE.addingTender = false;
+                }, 500);
+            };
         let selectedItem = projTreeObj.tree.selected;
         //地区
         let region = $('#regionDiv').find('select').val() || '全省';
@@ -3498,9 +3568,10 @@ function AddTender() {
         if(libs.main_quantity_lib && libs.main_quantity_lib.length > 0) tenderInfo.mainQuantityLibID = libs.main_quantity_lib[0].id;
         if(libs.material_lib && libs.material_lib.length > 0) tenderInfo.materialLibID = libs.material_lib[0].id;
 
-        AddTenderItems(selectedItem, projName, engName, tenderName, tenderInfo, callback);
+        AddTenderItems(selectedItem, projName, engName, tenderName, tenderInfo, callback, errCB);
 
     } catch (error) {
+        ('#add-tender-confirm').removeClass('disabled');
         alert(error);
     }
 }
@@ -3552,11 +3623,20 @@ function AddFolder() {
     let selectedItem = projTreeObj.tree.selected;
     let existCallback = function () {
         setDangerInfo($('#folder-name-info'), `已存在“${$("#folder-name").val()}”`);
+        STATE.addingFolder = false;
     };
     let sucCallback = function () {
         $('#add-folder-dialog').modal('hide');
         $('#folder-name').val('');
         setDangerInfo($('#folder-name-info'), '', false);
+        setTimeout(function () {
+            STATE.addingFolder = false;
+        }, 500);
+    };
+    let errCB = function () {
+        setTimeout(function () {
+            STATE.addingFolder = false;
+        }, 500);
     };
     if (selectedItem) {
         // 判断是否超过3层
@@ -3565,14 +3645,14 @@ function AddFolder() {
             return false;
         }
         if(selectedItem.data.projType === projectType.folder || selectedItem.data.projType === projectType.project){
-            AddSiblingsItem(null, name, null, projectType.folder, existCallback, sucCallback);
+            AddSiblingsItem(null, name, null, projectType.folder, existCallback, sucCallback, errCB);
         }
         else if(selectedItem.data.projType === projectType.engineering || selectedItem.data.projType === projectType.tender){
             let proj = selectedItem.parent.data.projType === projectType.project ? selectedItem.parent : selectedItem.parent.parent;
-            AddSiblingsItem(proj, name, null, projectType.folder, existCallback, sucCallback);
+            AddSiblingsItem(proj, name, null, projectType.folder, existCallback, sucCallback, errCB);
         }
     } else {
-        AddSiblingsItem(null, name, null, projectType.folder, existCallback, sucCallback);
+        AddSiblingsItem(null, name, null, projectType.folder, existCallback, sucCallback, errCB);
     }
 }
 
@@ -3725,10 +3805,10 @@ function GetNeedUpdatePreNode(parent, next) {
  * @param {function} callback
  * @return {void}
  */
-function GetNewProjectId(count, callback) {
+function GetNewProjectId(count, callback, errCB) {
     CommonAjax.post('/pm/api/getNewProjectID', {count: count}, function(data) {
         callback(data);
-    });
+    }, errCB);
 }
 
 /**