zhangweicheng %!s(int64=5) %!d(string=hai) anos
pai
achega
0367f5578e

+ 4 - 0
modules/import/controllers/import_controller.js

@@ -17,6 +17,10 @@ let controller = {
         let data = req.body;
         return await pm_facade.importChongqingProject(data);
     },
+    copyConstructionProject:async function(req){
+      let data = req.body;
+      return await pm_facade.copyConstructionProject(data);
+    },
     prepareInitialData: async function(req) {
         const data = req.body;
         return await pm_facade.prepareInitialData(data.userID, data.compilationID, data.example);

+ 1 - 0
modules/import/routes/import_route.js

@@ -13,6 +13,7 @@ module.exports = function (app) {
     importRouter.post('/getDataForInterface',importController.action);
     importRouter.post('/loadSEIProjectData',importController.action);
     importRouter.post('/importChongqingProject',importController.action);
+    importRouter.post('/copyConstructionProject',importController.action);
     importRouter.post('/prepareInitialData',importController.action);
     importRouter.get('/test',function (req,res) {
         res.json("hello word");

+ 16 - 1
modules/pm/controllers/pm_controller.js

@@ -873,7 +873,7 @@ module.exports = {
         };
         try {
             data.session = req.session;
-            result = await redirectToImportServer(data, "importChongqingProject", req);
+            result.data = await redirectToImportServer(data, "importChongqingProject", req);
         } catch (err) {
             console.log(err);
             result.error = 1;
@@ -881,6 +881,21 @@ module.exports = {
         }
         res.json(result);
     },
+    copyConstructionProject: async function (req, res) {
+      let data = JSON.parse(req.body.data);
+      let result = {
+          error: 0
+      };
+      try {
+          data.session = req.session;
+          result.data = await redirectToImportServer(data, "copyConstructionProject", req);
+      } catch (err) {
+          console.log(err);
+          result.error = 1;
+          result.message = err.message;
+      }
+      res.json(result);
+    },
     importProcessChecking: async function (req, res) {
         let result = {
             error: 0

+ 39 - 1
modules/pm/facade/pm_facade.js

@@ -52,6 +52,7 @@ module.exports={
     downLoadProjectFile:downLoadProjectFile,
     importChongqingProject:importChongqingProject,
     importProcessChecking:importProcessChecking,
+    copyConstructionProject,
     importInterface,
     isTenderOverrun,
     getWelcomeInfo:getWelcomeInfo
@@ -442,7 +443,7 @@ async function getShareInfoAfterChangePermission(permissionType, receiver, proje
 
 //拷贝例题项目
 //@param {String}userID {Array}projIDs拷贝的例题项目ID(建设项目、文件夹)@return {Boolean}
-async function copyExample(userID, compilation, projIDs){
+async function copyExample(userID, compilation, projIDs,nameMap){
     let allProjs = [],
         IDMapping = {},
         projMapping = {};
@@ -462,6 +463,7 @@ async function copyExample(userID, compilation, projIDs){
         if (i === parentExample.length - 1) {
             data.NextSiblingID = -1;
         }
+        if(nameMap && nameMap[data.ID]) data.name = nameMap[data.ID];
     }
     //获取所有的子项目
     let posterityProjs = await getPosterityProjects(projIDs);
@@ -1656,6 +1658,42 @@ async function isFirst(userId, compilationId) {
     return first;
 }
 
+async function copyConstructionProject(data){
+  let log_data = {
+    key:data.key,
+    content: '正在复制建设项目,请稍候……',
+    userID:data.user_id,
+    compilationID: data.session.sessionCompilation._id,
+    status:"start",
+    create_time:+new Date()
+  };
+
+  await importLogsModel.create(log_data);
+  doCopy(data.user_id,data.session.sessionCompilation._id,data.projectID,data.newName,data.key);
+
+  return "start copy";
+  async function doCopy(user_id,compilationId,projectID,newName,key) {
+      let doc = {status:"finish"};
+      try {
+          let nameMap={};
+          nameMap[projectID] = newName
+          let r = await copyExample(user_id,compilationId,[projectID],nameMap);
+          if(r == false){
+              doc.errorMsg = "复制失败,请检查项目是否存在!";
+              doc.status = "error";
+          }
+      }catch (error){
+          console.log(error);
+          doc.errorMsg = "复制失败,请检查项目是否存在!";
+          doc.status = "error";
+      }finally {
+          await importLogsModel.update({key:key},doc);
+      }
+  }
+
+
+}
+
 async function importChongqingProject(data) {
 
     let log_data = {

+ 1 - 0
modules/pm/routes/pm_route.js

@@ -66,6 +66,7 @@ module.exports = function (app) {
     pmRouter.post('/exportProject', pmController.exportProject);
     pmRouter.post('/importProject', pmController.importProject);
     pmRouter.post('/importChongqingProject', pmController.importChongqingProject);
+    pmRouter.post('/copyConstructionProject',systemMiddleware.tenderNumberChecking,pmController.copyConstructionProject);
     pmRouter.post('/importProcessChecking', pmController.importProcessChecking);
     pmRouter.post('/getBasicInfo', pmController.getBasicInfo);
     pmRouter.post('/getProjectFeature', pmController.getProjectFeature);

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

@@ -333,7 +333,7 @@ var sheetCommonObj = {
 
         for (var col = 0; col < setting.header.length; col++) {
             //var cell = sheet.getCell(row, col, GC.Spread.Sheets.SheetArea.viewport);
-            var val = data[row][setting.header[col].dataCode];
+            var val = _.get(data[row],setting.header[col].dataCode);
             let style = null;
             if(data[row].foreColor && data[row].styleCol == col){
                 style = {foreColor: data[row].foreColor};

+ 7 - 3
web/building_saas/glj/html/project_glj.html

@@ -80,12 +80,16 @@
             <div class="resize-y" id="projectGljResize"></div>
             <div class="bottom-content" id="projectGljBottom">
                 <ul class="nav nav-tabs" role="tablist">
+                  <li class="nav-item">
+                    <a class="nav-link active show" id="mixRatio-nav" data-toggle="tab" href="#ph_div" role="tab" aria-selected="false">组成物计算</a>
+                  </li>
+                  <li class="nav-item">
+                    <a class="nav-link " id="ration-nav" data-toggle="tab" href="#ph_div" role="tab" aria-selected="true">相关定额</a>
+                  </li>
                   <!--  <li class="nav-item">
                         <a class="nav-link active" data-toggle="tab" data-name="ration_sheet" id="ration_link" href="#glj_de_div" role="tab">相关定额</a>
                     </li>-->
-                   <!-- <li class="nav-item">
-                        <a class="nav-link active" data-toggle="tab" data-name="mix_ratio_sheet" id="mix_ratio_link" href="#ph_div" role="tab">组成物</a> 配合比、机械单价表合并
-                    </li>-->
+                   
                    <!-- <li class="nav-item">
                         <a class="nav-link" data-toggle="tab" data-name="machine_sheet" id="machine_ratio_link" href="#ph_div" role="tab">机械单价</a>
                     </li>-->

+ 2 - 2
web/building_saas/main/js/main.js

@@ -24,7 +24,7 @@ $(function () {
         rationLibObj.refreshSpread();
         subObj.initGljSubTab();
         subObj.initQDSubTab();
-        refreshSubSpread();
+        //refreshSubSpread();
     });
 
     $('#tab_report').on('shown.bs.tab', function(e){
@@ -80,7 +80,7 @@ function loadMainSize() {//加载造价书页面各高度
     let mainResizeEles = getMainResizeEles();
     SlideResize.loadVerticalHeight(mainResizeEles.eleObj.module, mainResizeEles.eleObj, mainResizeEles.limit, function () {
         refreshSubSpread();
-        zmhs_obj.refresh();
+        //zmhs_obj.refresh();
         $("#tzCharacterText").height($("#tzSubDiv").height()-30);
     });
 }

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

@@ -13,6 +13,19 @@ let projectGljObject={
     materialTreeSheet:null,
     projectGljSheetData:[],
     mixRatioSetting:{},
+    relatedRationSetting:{
+      header:[
+        {headerName: "编码", headerWidth: 100, dataCode: "code", dataType: "String"},
+        {headerName: "名称", headerWidth: 180, dataCode: "name", dataType: "String"},
+        {headerName: "单位", headerWidth: 50, dataCode: "unit", dataType: "String",hAlign: "center"},
+        {headerName: "工程量", headerWidth: 65, dataCode: "quantity", dataType: "Number", hAlign: "right",decimalField: "ration.quantity"},
+        {headerName: "单价", headerWidth: 65, dataCode: "feesIndex.common.unitFee", dataType: "Number", hAlign: "right",decimalField: "ration.unitPrice"}
+    ],
+    view: {
+        lockColumns: [0,1,2,3,4]//,
+        //colHeaderHeight:30
+      }
+    },
     materialTreeSetting:{
         "emptyRows":0,
         "headRows":1,
@@ -94,12 +107,14 @@ let projectGljObject={
         }
     },
     initMixRatioSpread:function () {
-        this.mixRatioSpread = SheetDataHelper.createNewSpread($("#mix_ratio_sheet")[0]);
+        this.mixRatioSpread = SheetDataHelper.createNewSpread($("#mix_ratio_sheet")[0],2);
         sheetCommonObj.spreadDefaultStyle(this.mixRatioSpread);
         this.mixRatioSheet = this.mixRatioSpread .getSheet(0);
         this.initSheet(this.mixRatioSheet,this.mixRatioSetting);
         this.mixRatioSheet.name('mixRatioSheet');
         this.mixRatioSheet.bind(GC.Spread.Sheets.Events.RangeChanged, this.onMixRatioRangeChange);
+        this.initRelatedRationSheet();
+
         if(projectReadOnly){
             if(this.mixRatioSetting.view.lockColumns){
                 this.mixRatioSetting.view.lockColumns = null;
@@ -107,6 +122,13 @@ let projectGljObject={
             disableSpread(this.mixRatioSpread);
         }
     },
+    initRelatedRationSheet:function(){
+      this.relatedRationSheet = this.mixRatioSpread.getSheet(1); 
+      sheetCommonObj.initSheet(this.relatedRationSheet, this.relatedRationSetting, 30);
+      this.relatedRationSheet.name('relatedRation');
+      this.relatedRationSheet.bind(GC.Spread.Sheets.Events.CellDoubleClick, this.onRelatedRationDoubleClick);
+      //this.mixRatioSheet.bind(GC.Spread.Sheets.Events.RangeChanged, this.onMixRatioRangeChange);
+    },
     initMaterialTreeSheet:function () {
         this.materialTreeSheet = this.projectGljSpread.getSheet(1);
         this.materialTreeSetting = this.createMaterialTreeSheetSetting();
@@ -268,6 +290,8 @@ let projectGljObject={
     },
     showMixRatioData:function () {
         let me = this,gljId = null,gljType = null;
+        if(!$('#mixRatio-nav').hasClass('active')) return;
+        me.mixRatioSpread.setActiveSheetIndex(0);
         if(!me.projectGljSpread) return;
         let sheet = me.projectGljSpread.getActiveSheet();
         let oldSel = me.mixRatioSheet.getSelections()[0];
@@ -303,6 +327,28 @@ let projectGljObject={
           me.mixRatioSheet.setSelection(oldSel.row==-1?0:oldSel.row,oldSel.col,oldSel.rowCount,oldSel.colCount);
         })
     },
+    showRelatedRationDatas:function(){
+      let me = this;
+      if(!$('#ration-nav').hasClass('active')) return;
+      me.mixRatioSpread.setActiveSheetIndex(1);
+      let projectGLJData = me.getProjectGLJSelected();
+      let rationIDMap = {};
+      let rations = [];
+      if(projectGLJData){
+         for(let rg of projectObj.project.ration_glj.datas){
+            if(rg.projectGLJID == projectGLJData.id) rationIDMap[rg.rationID] = true;
+         } 
+         for(let r of projectObj.project.Ration.datas){
+            if(rationIDMap[r.ID] || (r.type == rationType.gljRation && r.projectGLJID== projectGLJData.id)){
+              rations.push(r);
+            } 
+         } 
+      }
+      this.relatedRationSheetData = rations;
+      sheetCommonObj.showData(me.relatedRationSheet, me.relatedRationSetting,rations);
+      me.relatedRationSheet.setRowCount(rations.length);
+    },
+
     getMixRatioSheetData:function (glj) {
         let data ={
             id:glj.id,
@@ -374,6 +420,12 @@ let projectGljObject={
         me.showMixRatioData();
         me.materialTreeSheet.repaint();
     },
+    onRelatedRationDoubleClick:function (sender,args) {
+      let me = projectGljObject;
+      let record = me.relatedRationSheetData[args.row];
+      $("#tab_zaojiashu").click();
+      locateObject.locateNode(record.ID);
+    },
     onProjectGljSelectionChange:function (sender, args) {
         let me = projectGljObject;
         let newSel = args.newSelections[0];
@@ -405,6 +457,7 @@ let projectGljObject={
         sel.rowCount = 1;
         sel.colCount = 1;
         me.showMixRatioData();
+        me.showRelatedRationDatas();
     },
     rightClickCallback:function (row) {
         let me = projectGljObject;
@@ -678,6 +731,7 @@ let projectGljObject={
         }else {
             me.showProjectGljData();
             me.showMixRatioData(); 
+            me.showRelatedRationDatas();
         }
     },
     createMaterialTree:function (gljList) {
@@ -871,6 +925,7 @@ let projectGljObject={
             me.projectGljSheetData.splice(row,1);
             me.projectGljSheet.deleteRows(row,1);
             me.showMixRatioData();
+            me.showRelatedRationDatas();
         }
         //me.projectGljSheetData[row] = me.getSheetDataByGLJ(glj);
     },
@@ -1105,20 +1160,20 @@ let projectGljObject={
         return sheetCommonObj.checkData(col,setting, value);
     },
     getProjectGLJSelected:function () {
-        let me = projectGljObject;
-        let sheet = me.projectGljSpread.getActiveSheet();
-        let selectedProjectGLJ = null;
-        if(sheet.name() == 'projectGljSheet'){//projectGljSheet/materialSheet 工料机汇总和三材汇总表
-            let sel = me.projectGljSheet.getSelections()[0];
-            if(sel.row != -1 && me.projectGljSheetData.length>sel.row){
-                selectedProjectGLJ = me.projectGljSheetData[sel.row]
-            }
-        }else if(sheet.name() == 'materialTreeSheet' ){
-            if(me.materialTree.selected){
-                selectedProjectGLJ = me.materialTree.selected.data;
-            }
-        }
-        return selectedProjectGLJ;
+      let me = this,data = null;
+      let sheet = me.projectGljSpread.getActiveSheet();
+      if(sheet.name() == 'projectGljSheet'){//projectGljSheet/materialSheet 工料机汇总和三材汇总表
+          let sel = me.projectGljSheet.getSelections()[0];
+          let srow = sel.row == -1||sel.row == ""?0:sel.row;
+          if(me.projectGljSheetData.length>srow){
+              data = me.projectGljSheetData[srow];
+          }
+      }else if(sheet.name() == 'materialTreeSheet'){
+          if(this.materialTree.selected){
+              data = this.materialTree.selected.data;
+          }
+      }
+      return data;
     },
     initRightClick : function() {
         let activeSheet = this.mixRatioSheet;
@@ -1544,6 +1599,16 @@ $(function () {
         me.refreshViewsData();
         loadProjectGljSize();
     });
+
+    $("#mixRatio-nav").on('shown.bs.tab', function () {
+      projectGljObject.mixRatioSpread.refresh();
+      projectGljObject.showMixRatioData();
+  });
+
+    $("#ration-nav").on('shown.bs.tab', function () {
+      projectGljObject.mixRatioSpread.refresh();
+      projectGljObject.showRelatedRationDatas();
+    });
 });
 
 

+ 0 - 1
web/building_saas/main/js/views/zmhs_view.js

@@ -259,7 +259,6 @@ let zmhs_obj = {
     refresh:function () {
         $('#coeSpread').is(':visible')&&this.coeSpread?this.coeSpread.refresh():'';
         $('#coeSpread').is(':visible')&&this.coeSpread?this.showDatas():'';//这里combobox下拉框要重新加载一下
-        $('#coeSpread').is(':visible')&&this.coeSpread?this.coeSpread.refresh():'';
         $('#cusSpread').is(':visible')&&this.cusSpread?this.cusSpread.refresh():'';
         $('#assSpread').is(':visible')&&this.assSpread?this.assSpread.refresh():'';
     },

+ 50 - 2
web/building_saas/pm/js/pm_share.js

@@ -424,7 +424,7 @@ const pmShare = (function () {
             let node = tree.items[options.row];
             // Draw Text
             GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
-            if (node && node.data.projType === projectType.tender) {
+            if (node && (node.data.projType === projectType.tender||node.data.projType === projectType.project)) {
                 let text = options.sheet.getText(options.row, options.col);
                 let acStyle = options.sheet.getActualStyle(options.row, options.col),
                     zoom = options.sheet.zoom();
@@ -745,6 +745,7 @@ const pmShare = (function () {
         //data.allowCopy与shareInfo里allowCopy的区别:
         //data.allowCopy为该单位实际的权限(跟着最新的分享信息走,可能随着父项)
         for (let data of datas) {
+            if(data.projType == projectType.project) data.allowCopy = isAllowCopy(userID, data); //20200715 专业版要求能复制建设项目
             if (data.projType === projectType.tender) {
                 data.allowCopy = isAllowCopy(userID, data);
                 data.allowCooperate = isAllowCoop(userID, data);
@@ -796,12 +797,27 @@ const pmShare = (function () {
                     icon: 'fa-copy',
                     disabled: function () {
                         let selected = tree.selected;
-                        return !(selected && selected.data.allowCopy);
+                        return !(selected && selected.data.allowCopy && selected.data.projType === projectType.tender);
                     },
                     callback: function (key, opt) {
                         $('#copyShare').modal('show');
                     }
                 },
+                "copyProject": {
+                  name: "拷贝建设项目",
+                  icon: 'fa-copy',
+                  disabled: function () {
+                      let selected = tree.selected;
+                      return !(selected && selected.data.allowCopy && selected.data.projType === projectType.project);
+                  },
+                  callback: function (key, opt) {
+                      if($(".p-title").text().includes('免费')){
+                        hintBox.versionBox('此功能仅在专业版中提供,免费公用版可选择单个分段进行拷贝');
+                        return;
+                      }
+                      copyContructionProject(tree.selected);
+                  }
+                },
                 "cancel": {
                     name: "清除",
                     icon: 'fa-remove',
@@ -943,6 +959,38 @@ const pmShare = (function () {
         }
 
     }
+
+    //拷贝分享的建设项目
+    //@param {Object}selected 
+    async function copyContructionProject(selected){
+      try {
+        let newName = 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){
+            if(project.name === newName){
+                alert("已存在此建设项目");
+                return;
+            }
+        }
+        let tenderCount = 0;
+        if(selected.children) {
+          for(let c of selected.children){
+            if(c.children) tenderCount += c.children.length;
+          }
+        }
+        let key = uuid.v1();
+        $.bootstrapLoading.progressStart('拷贝建设项目', true);
+        $("#progress_modal_body").text('正在拷贝建设项目,请稍候……');
+        await ajaxPost('/pm/api/copyConstructionProject', {user_id: userID, tenderCount: tenderCount,key:key,projectID:selected.data.actualTreeInfo.ID,newName:newName});
+        importProcessChecking(key, null, projTreeObj.emitTreeChange);
+      } catch (error) {
+        console.log(error);
+      }
+    }
+
+
     //获取拷贝后的名称
     //@param {Object}node @return {String}
     function getCopyName(node) {