浏览代码

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

TonyKang 6 年之前
父节点
当前提交
9f6439a624

+ 2 - 2
modules/all_models/ration_glj.js

@@ -5,10 +5,10 @@ var mongoose = require('mongoose'),
     Schema = mongoose.Schema;
 
 var ration_glj = new Schema({
-    ID:String,
+    ID:{type: String, index: true},
     GLJID:Number,
     repositoryId:Number,
-    projectID: Number,
+    projectID: {type: Number, index: true},
     rationID:String,
     projectGLJID:Number,
     name:String,

+ 9 - 1
modules/main/controllers/ration_controller.js

@@ -8,6 +8,7 @@ let ration_facade = require('../facade/ration_facade');
 let bill_facade = require('../facade/bill_facade');
 let project_facade = require("../facade/project_facade");
 let logger = require("../../../logs/log_helper").logger;
+import GLJController from "../../glj/controllers/glj_controller";
 let controller = {
     insertGLJAsRation:async function (req){
         let data = req.body.data;
@@ -78,7 +79,14 @@ let controller = {
     updateCoeAdjust:async function(req){
         let data = req.body.data;
         data = JSON.parse(data);
-        return await ration_facade.updateCoeAdjust(data,req.session.sessionCompilation);
+        let result = await ration_facade.updateCoeAdjust(data,req.session.sessionCompilation);
+        //合并取项目工料机数据的情求,用于刷新项目工料机数据,当有添加、替换项目工料机的情况,才需要刷新
+        if(result.add.length > 0 || result.replace.length > 0){
+            let gljController = new GLJController();
+            let responseData = await gljController.getProjectGLJsByProjectID(data.projectID)
+            result.projectGLJDatas = responseData.data;
+        }
+        return result
 
     }
 

+ 0 - 1
modules/main/facade/ration_facade.js

@@ -485,7 +485,6 @@ async function updateCoeAdjust(data,compilation) {
             replace.push(await  ration_glj_facade.replaceGLJByData(r,compilation)) ;
         }
     }
-
     let cal_result = await glj_calculate_facade.calculateQuantity({projectID:data.projectID,rationID:data.rationID},null,true);
     let coe = {
         query:{ID:data.ID,projectID:data.projectID},

+ 9 - 21
modules/pm/controllers/pm_controller.js

@@ -683,36 +683,24 @@ module.exports = {
 
     },
     importProject:async function(req,res){
-        let form = new multiparty.Form({uploadDir: './public'});
+        let form = new multiparty.Form({uploadDir: './tmp'});
         let uploadFullName;
         form.parse(req, async function (err, fields, files) {
             try {
+                console.log(fields);
                 const file = typeof files.file !== 'undefined' ? files.file[0] : null;
                 if (err || !file) {
                     throw '上传失败。';
-                }
-                console.log(file);
+                };
                 let data = fs.readFileSync(file.path,'utf-8');
-                console.log(data);
+                let result = await pm_facade.importProject(data,req,fields);
+                fs.unlinkSync(file.path);
+                res.json(result);
             }catch (e){
-
+                console.log(e);
+                res.json({error:1,msg:"导入失败请检查文件!"})
             }
-            res.json({error:0})
-        })
-        /*let result={
-            error:0
-        };
-        try {
-            console.log(req.files[0]);
-           /!* let data = JSON.parse(req.body.data);
-            result.data = await pm_facade.exportProject(req.session.sessionUser.id, data);*!/
-        }catch (err){
-            console.log(err);
-            result.error=1;
-            result.message = err.message;
-        }
-        res.json(result);*/
-
 
+        })
     }
 };

+ 304 - 26
modules/pm/facade/pm_facade.js

@@ -27,7 +27,8 @@ module.exports={
     prepareInitialData: prepareInitialData,
     changeFile:changeFile,
     copyForSectionError: copyForSectionError,
-    exportProject:exportProject
+    exportProject:exportProject,
+    importProject:importProject
 };
 
 
@@ -293,35 +294,34 @@ async function copyProjectSetting(originalID,newProjectID) {
 async function copyBills(newProjectID,billMap) {
      let uuidMaping = billMap.uuidMaping;//做ID映射
      for(let doc of billMap.datas){
-         doc.projectID = newProjectID;
-         doc.ID = uuidMaping[doc.ID] ? uuidMaping[doc.ID] : -1;
-         doc.ParentID = uuidMaping[doc.ParentID] ? uuidMaping[doc.ParentID] : -1;
-         doc.NextSiblingID = uuidMaping[doc.NextSiblingID] ? uuidMaping[doc.NextSiblingID] : -1;
-         //对于有基数计算的节点,需要替换计算基数中引用的ID为新的ID
-         if(doc.calcBase && doc.calcBase != ""){
-             let idArr = scMathUtil.getFIDArr(doc.calcBase);
-             for(let re of idArr){
-                 let oID = re.substr(1);//去掉开头的@字符
-                 if(!uuidMaping[oID]) continue;
-                 doc.calcBase = doc.calcBase.replace(new RegExp(oID, "g"),uuidMaping[oID]);
-             }
-         }
+         doc = getCopyBillDatas(doc,newProjectID,uuidMaping)
      }
     await insertMany(billMap.datas,billsModel);
     return billMap.datas;
 }
 
+
+function getCopyBillDatas(doc,newProjectID,uuidMaping) {
+    doc.projectID = newProjectID;
+    doc.ID = uuidMaping[doc.ID] ? uuidMaping[doc.ID] : -1;
+    doc.ParentID = uuidMaping[doc.ParentID] ? uuidMaping[doc.ParentID] : -1;
+    doc.NextSiblingID = uuidMaping[doc.NextSiblingID] ? uuidMaping[doc.NextSiblingID] : -1;
+    //对于有基数计算的节点,需要替换计算基数中引用的ID为新的ID
+    if(doc.calcBase && doc.calcBase != ""){
+        let idArr = scMathUtil.getFIDArr(doc.calcBase);
+        for(let re of idArr){
+            let oID = re.substr(1);//去掉开头的@字符
+            if(!uuidMaping[oID]) continue;
+            doc.calcBase = doc.calcBase.replace(new RegExp(oID, "g"),uuidMaping[oID]);
+        }
+    }
+    return doc;
+}
+
 async function copyRations(newProjectID,billsIDMap,rationMap,projectGLJIDMap) {
     let uuidMaping = rationMap.uuidMaping;
     for(let doc of rationMap.datas){
-        doc.projectID = newProjectID;
-        doc.ID = uuidMaping[doc.ID] ? uuidMaping[doc.ID] : -1;
-        if(doc.billsItemID){
-            doc.billsItemID = billsIDMap[doc.billsItemID]?billsIDMap[doc.billsItemID]:-1;
-        }
-        if(doc.referenceRationID) doc.referenceRationID = uuidMaping[doc.referenceRationID]?uuidMaping[doc.referenceRationID]:undefined;
-        //绑定定类型的工料机 项目工料机ID
-        doc.type==3&&doc.projectGLJID&&projectGLJIDMap[doc.projectGLJID]?doc.projectGLJID = projectGLJIDMap[doc.projectGLJID]:'';
+        doc = getCopyRationData(doc,newProjectID,billsIDMap,uuidMaping,projectGLJIDMap);
     }
     if(rationMap.datas.length > 0){
         await insertMany(rationMap.datas,rationModel);
@@ -329,6 +329,20 @@ async function copyRations(newProjectID,billsIDMap,rationMap,projectGLJIDMap) {
     return rationMap.datas;
 }
 
+
+function getCopyRationData(doc,newProjectID,billsIDMap,uuidMaping,projectGLJIDMap){
+    doc.projectID = newProjectID;
+    doc.ID = uuidMaping[doc.ID] ? uuidMaping[doc.ID] : -1;
+    if(doc.billsItemID){
+        doc.billsItemID = billsIDMap[doc.billsItemID]?billsIDMap[doc.billsItemID]:-1;
+    }
+    if(doc.referenceRationID) doc.referenceRationID = uuidMaping[doc.referenceRationID]?uuidMaping[doc.referenceRationID]:undefined;
+    //绑定定类型的工料机 项目工料机ID
+    doc.type==3&&doc.projectGLJID&&projectGLJIDMap[doc.projectGLJID]?doc.projectGLJID = projectGLJIDMap[doc.projectGLJID]:'';
+    return doc;
+}
+
+
 async function copyProjectGLJ(gljList) {
     await insertMany(gljList,gljListModel);
 }
@@ -416,7 +430,8 @@ async function copyRationSubList(originalPID,newProjectID,billIDMap,rationIDMap,
     let subList = await model.find({projectID:originalPID}, '-_id');
     let newList =[];
     for(let s of subList){
-        s._doc.ID = uuidV1();
+        s._doc = getCopyRationSubData(s._doc,newProjectID,billIDMap,rationIDMap,projectGLJIDMap);
+   /*     s._doc.ID = uuidV1();
         s._doc.projectID = newProjectID;
         s._doc.rationID&&rationIDMap[s._doc.rationID]?s._doc.rationID = rationIDMap[s._doc.rationID]:'';
         s._doc.billID&&billIDMap[s._doc.billID]?s._doc.billID = billIDMap[s._doc.billID]:'';
@@ -427,12 +442,30 @@ async function copyRationSubList(originalPID,newProjectID,billIDMap,rationIDMap,
                 if(t.billID && billIDMap[t.billID]) t.billID =  billIDMap[t.billID];
                 if(t.fxID && billIDMap[t.fxID]) t.fxID =  billIDMap[t.fxID];
             }
-        }
+        }*/
         newList.push(s._doc);
     }
     await insertMany(newList,model);
 }
 
+function getCopyRationSubData(doc,newProjectID,billIDMap,rationIDMap,projectGLJIDMap){
+    doc.ID = uuidV1();
+    doc.projectID = newProjectID;
+    doc.rationID&&rationIDMap[doc.rationID]?doc.rationID = rationIDMap[doc.rationID]:'';
+    doc.billID&&billIDMap[doc.billID]?doc.billID = billIDMap[doc.billID]:'';
+    doc.billsItemID&&billIDMap[doc.billsItemID]?doc.billsItemID = billIDMap[doc.billsItemID]:'';
+    doc.projectGLJID&&projectGLJIDMap[doc.projectGLJID]?doc.projectGLJID = projectGLJIDMap[doc.projectGLJID]:'';
+    if(doc.templateList && doc.templateList.length > 0 ){
+        for(let t of doc.templateList){
+            if(t.billID && billIDMap[t.billID]) t.billID =  billIDMap[t.billID];
+            if(t.fxID && billIDMap[t.fxID]) t.fxID =  billIDMap[t.fxID];
+        }
+    }
+    return doc;
+}
+
+
+
 async function moveProject(data) {
     data = JSON.parse(data);
     let projectMap = data.projectMap,feeRateMap = data.feeRateMap,unitPriceMap = data.unitPriceMap;
@@ -465,7 +498,7 @@ async function moveProject(data) {
         }
     }
     if(!_.isEmpty(unitPriceMap)&&data.rootProjectID) {//如果单价文件有修改
-        let unitPriceFiles =  await unitPriceFileModel.find({root_project_id: data.rootProjectID, deleteInfo: null});
+        let unitPriceFiles = await unitPriceFileModel.find({root_project_id: data.rootProjectID, deleteInfo: null});
         for(let projectID in unitPriceMap){
             let checkUn = _.find(unitPriceFiles,{'name':unitPriceMap[projectID].name});
             let rename = unitPriceMap[projectID].name;
@@ -979,7 +1012,6 @@ async function changeFile(datas,userID,fileID,name,from,type){//from 费率或
 }
 
 async function exportProject(userID,data){//导出建设项目
-    console.log(data);
     if(data.type == 'main'){
         return await exportMainData(userID,data.projectID);
     }else {
@@ -1054,4 +1086,250 @@ async function exportTenderData(data){
     result.labourCoes = await labourCoesModel.findOne({projectID:data.projectID});
 
     return cipher.aesEncrypt(JSON.stringify(result));
+}
+
+
+async function importProject(data,req,fields) {
+    let result = {error:0};
+    let stringArr = data.split("|----|");
+    let datas = [];
+    for(let s of stringArr){
+        datas.push(JSON.parse(cipher.aesDecrypt(s)));
+    }
+    let mainData = datas.length > 0 ?datas[0]:null;
+    if(mainData){
+         if(mainData.compilationID != req.session.sessionCompilation._id){
+             result.error = 1;
+             result.msg = "编办不同,无法导入,请重新选择!";
+         }else {
+            let [projectIDMap,labourCoeFileIDMap,calcProgramFileIDMap] = await handleMainProjectDatas(mainData,JSON.parse(fields.updateData[0]),req.session.sessionUser.id);
+            if(datas.length > 1 ){
+                for(let i = 1;i<datas.length;i++){
+                    await handleEachProject(datas[i],projectIDMap,labourCoeFileIDMap,calcProgramFileIDMap)
+                }
+            }
+
+         }
+    }
+    return result;
+}
+
+async function handleEachProject(data,projectIDMap,labourCoeFileIDMap,calcProgramFileIDMap){
+    let bills = [],rations = [],projectGLJs = [],rationGLJs=[],rationCoes=[],quantityDetails=[],rationInstallations=[],rationTemplates=[];
+    let newProjectSetting =null,newCalcProgramsFile = null,newLabourCoe = null;
+    let billsIDMap = {},projectGLJIDMap={},rationIDMap = {};
+    let newProjectID = projectIDMap[data.projSetting.projectID];
+    //生成新的清单;
+    if(data.bills && data.bills.length > 0){
+        for(let b of data.bills){
+            billsIDMap[b.ID] = uuidV1();
+        }
+        for(let b of data.bills){
+            delete b._id;
+            b = getCopyBillDatas(b,newProjectID,billsIDMap);
+            bills.push(b);
+        }
+    }
+
+    //生成项目工料机数据
+    if(data.projectGLJs && data.projectGLJs.length > 0){
+        let gljCount = await counter.counterDAO.getIDAfterCountSync(counter.moduleName.glj_list, data.projectGLJs.length);
+        for(let i = 0; i < data.projectGLJs.length; i++){
+            let d = data.projectGLJs[i];
+            delete d._id;
+            let newID = gljCount.sequence_value - (data.projectGLJs.length - 1) + i;
+            projectGLJIDMap[d.id] = newID;
+            d.project_id = newProjectID;
+            d.id = newID;
+            projectGLJs.push(d);
+        }
+    }
+
+    //生成新的定额
+    if(data.rations && data.rations.length > 0){
+        for(let r of data.rations){
+            rationIDMap[r.ID] = uuidV1();
+        }
+        for(let r of data.rations){
+            delete r._id;
+            r = getCopyRationData(r,newProjectID,billsIDMap,rationIDMap,projectGLJIDMap);
+            rations.push(r);
+        }
+    }
+
+    //生成定额下挂的定额工料机等等数据
+    if(data.rationGLJs && data.rationGLJs.length > 0) rationGLJs = setRationSubList(data.rationGLJs,newProjectID,billsIDMap,rationIDMap,projectGLJIDMap);
+    if(data.rationCoes && data.rationCoes.length > 0) rationCoes = setRationSubList(data.rationCoes,newProjectID,billsIDMap,rationIDMap,projectGLJIDMap);
+    if(data.quantityDetails && data.quantityDetails.length > 0) quantityDetails = setRationSubList(data.quantityDetails,newProjectID,billsIDMap,rationIDMap,projectGLJIDMap);
+    if(data.rationInstallations && data.rationInstallations.length > 0) rationInstallations = setRationSubList(data.rationInstallations,newProjectID,billsIDMap,rationIDMap,projectGLJIDMap);
+    if(data.rationTemplates && data.rationTemplates.length > 0) rationTemplates = setRationSubList(data.rationTemplates,newProjectID,billsIDMap,rationIDMap,projectGLJIDMap);
+
+    //生成projectSetting 文件
+    if(data.projSetting){
+        data.projSetting.projectID =newProjectID;
+        newProjectSetting = data.projSetting;
+        delete newProjectSetting._id;
+    }
+
+    //生成计算程序文件,系数文件
+    if(data.calcProgramsFile && calcProgramFileIDMap[data.calcProgramsFile.ID]){
+        data.calcProgramsFile.ID = calcProgramFileIDMap[data.calcProgramsFile.ID];
+        data.calcProgramsFile.projectID = newProjectID;
+        newCalcProgramsFile =  data.calcProgramsFile;
+        delete newCalcProgramsFile._id;
+
+    }
+    if(data.labourCoes && labourCoeFileIDMap[data.labourCoes.ID]){
+        data.labourCoes.ID = labourCoeFileIDMap[data.labourCoes.ID];
+        data.labourCoes.projectID = newProjectID;
+        newLabourCoe = data.labourCoes;
+        delete newLabourCoe._id;
+    }
+
+    if(newProjectSetting) await projectSettingModel.create(newProjectSetting);
+    if(bills.length > 0) await insertMany(bills,billsModel);
+    if(rations.length > 0) await insertMany(rations,rationModel);
+    if(projectGLJs.length > 0) await insertMany(projectGLJs,gljListModel);
+    if(rationGLJs.length > 0) await insertMany(rationGLJs,rationGLJModel);
+    if(rationCoes.length > 0) await insertMany(rationCoes,rationCoeModel);
+    if(quantityDetails.length > 0) await insertMany(quantityDetails,quantityDetailModel);
+    if(rationInstallations.length > 0) await insertMany(rationInstallations,rationInstallationModel);
+    if(rationTemplates.length > 0) await insertMany(rationTemplates,rationTemplateModel);
+    if(newCalcProgramsFile) await calcProgramsModel.create(newCalcProgramsFile);
+    if(newLabourCoe) await labourCoesModel.create(newLabourCoe);
+
+
+}
+
+
+function setRationSubList(datas,newProjectID,billIDMap,rationIDMap,projectGLJIDMap) {
+    let arrs = [];
+    for(let d of datas){
+        delete d._id;
+        d = getCopyRationSubData(d,newProjectID,billIDMap,rationIDMap,projectGLJIDMap);
+        arrs.push(d);
+    }
+    return arrs;
+}
+
+async function handleMainProjectDatas(mainData,updateData,userID) {
+    let mainProjectID = -1;
+    let projectIDMap = {},feeRateFileIDMap={},unitPriceFileIDMap={},labourCoeFileIDMap={},calcProgramFileIDMap={};
+    let tasks = [];
+    //生成新的projectID
+    for(let p of mainData.projects){
+        let newProjectID = await getCounterID("projects");
+        projectIDMap[p.ID] = newProjectID;
+        if(p.projType == "Project") mainProjectID =  newProjectID;
+        if(p.projType == "Tender"){
+            if(p.property.calcProgramFile) calcProgramFileIDMap[p.property.calcProgramFile.ID] = uuidV1();//新的计算程序文件ID
+            if(p.property.labourCoeFile) labourCoeFileIDMap[p.property.labourCoeFile.ID] = uuidV1();//新的人工调整系数文件ID
+            if(p.property.feeFile) feeRateFileIDMap[p.property.feeFile.id] = uuidV1();//新的费率文件ID
+            if(p.property.unitPriceFile) unitPriceFileIDMap[p.property.unitPriceFile.id] = await getCounterID("unit_price_file");//新的单价文件ID
+        }
+    }
+    if(mainProjectID == -1) throw new Error("文件里面没包含建设项目信息!");
+
+    //处理项目信息  ----- 费率文件,单价文件ID信息要重新生成----to do
+    for(let p of mainData.projects){
+        delete p._id;
+        delete p.__v;
+        p.ID = projectIDMap[p.ID];
+        if(p.ID == mainProjectID){//对于建设项目,要父和下一节点ID要使用前端传入的位置ID
+            p.ParentID = updateData.self.ParentID;
+            p.NextSiblingID = updateData.self.NextSiblingID;
+            if(updateData.update){//树节构中的上一节点的下一节点设置为本建设项目ID;
+                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()).format('MM-DD HH:mm:ss') + '导入)';
+        }else {
+            p.ParentID = projectIDMap[p.ParentID];
+            p.NextSiblingID = projectIDMap[p.NextSiblingID];
+        }
+        p.userID =userID;
+        p.shareInfo=[];
+        if(p.projType == "Tender"){
+            if(p.property.calcProgramFile) p.property.calcProgramFile.ID = calcProgramFileIDMap[p.property.calcProgramFile.ID];
+            if(p.property.labourCoeFile) p.property.labourCoeFile.ID = labourCoeFileIDMap[p.property.labourCoeFile.ID];
+            if(p.property.feeFile) p.property.feeFile.id = feeRateFileIDMap[p.property.feeFile.id];
+            if(p.property.unitPriceFile) p.property.unitPriceFile.id = unitPriceFileIDMap[p.property.unitPriceFile.id];
+            p.property.rootProjectID = mainProjectID
+        }
+        tasks.push({insertOne: {document: p}})
+    }
+    //项目树节构数据生成:
+      await projectModel.bulkWrite(tasks);
+
+    //生成所有的费率文件
+    await importFeeRateFiles(mainData,projectIDMap,feeRateFileIDMap,userID);
+
+    //生成所有的单价文件
+    await importUnitPriceFiles(mainData,projectIDMap,unitPriceFileIDMap,userID);
+
+
+    return [projectIDMap,labourCoeFileIDMap,calcProgramFileIDMap]
+}
+
+
+async function importUnitPriceFiles(mainData,projectIDMap,unitPriceFileIDMap,userID) {
+    if(!mainData.files.unitFiles) return;
+    let unitFiles = [],unitPrices =[],mixRatios=[],freights=[],originals=[];
+    for(let f of mainData.files.unitFiles){
+        let file = f.unitFile,prices = f.unitPrices,mixs = f.mixRatios,fres = f.freights,ors = f.originals;
+        //生成单价文件
+        delete file._id;
+        file.id = unitPriceFileIDMap[file.id]?unitPriceFileIDMap[file.id]:await getCounterID("unit_price_file");
+        file.project_id = projectIDMap[file.project_id];
+        file.root_project_id = projectIDMap[file.root_project_id];
+        file.user_id = userID;
+        unitFiles.push(file);
+
+        //生成子数据
+        if(prices) await  setSubList(prices,unitPrices,file.id,unitPriceModel);
+        if(mixs) await setSubList(mixs,mixRatios,file.id,mixRatioModel);
+        if(fres) await setSubList(fres,freights,file.id,freightModel,true);
+        if(ors) await setSubList(ors,originals,file.id,originalModel,true);
+    }
+    if(unitFiles.length > 0) await insertMany(unitFiles,unitPriceFileModel);
+    if(unitPrices.length > 0) await insertMany(unitPrices,unitPriceModel);
+    if(mixRatios.length > 0) await insertMany(mixRatios,mixRatioModel);
+    if(freights.length > 0) await insertMany(freights,freightModel);
+    if(originals.length > 0) await insertMany(originals,originalModel);
+
+    async function setSubList(oList,nList,fileID,model,UUID=false) {
+        for(let o of oList){
+            delete o._id;
+            o.unit_price_file_id = fileID;
+            UUID == true?o.ID = uuidV1():o.id = await getCounterID(model.modelName);
+            nList.push(o)
+        }
+    }
+
+
+}
+
+
+async function importFeeRateFiles(mainData,projectIDMap,feeRateFileIDMap,userID) {
+    let feeRateFiles = [], feeRates = [];
+    if(!mainData.files.feeRateFiles) return;
+    for(let f of mainData.files.feeRateFiles){
+        //生成费率记录
+        let rate = f.feeRate;
+        delete rate._id;
+        rate.ID = uuidV1();
+        feeRates.push(rate);
+
+        //生成费率文件记录
+        let file = f.feeRateFile;
+        delete file._id;
+        file.ID = feeRateFileIDMap[file.ID]?feeRateFileIDMap[file.ID]:uuidV1();
+        file.userID = userID;
+        file.rootProjectID = projectIDMap[file.rootProjectID];
+        file.feeRateID = rate.ID;
+        feeRateFiles.push(file);
+    }
+    if(feeRateFiles.length > 0) await insertMany(feeRateFiles,feeRateFileModel);
+    if(feeRates.length > 0) await insertMany(feeRates,feeRateModel);
 }

+ 12 - 6
modules/ration_glj/facade/glj_calculate_facade.js

@@ -87,10 +87,10 @@ async function calculateQuantity(query,noNeedCal=null,refreshRationName = false)
         gljList = gljUtil.sortRationGLJ(gljList);
         for(let i =0;i<gljList.length;i++ ){
             let r = await calculateQuantityPerGLJ(gljList[i],gljList,coeList,assList,adjustState,mixRatioMap,noNeedCal);
-            result.glj_result.push(r);
+            if(quantityUpdateCheck(gljList[i],r) == true) result.glj_result.push(r);
         }
-         if(noNeedCal==null){
-            await ration_glj.bulkWrite(generateUpdateTasks(result.glj_result));
+         if(noNeedCal==null && result.glj_result.length > 0){
+             await ration_glj.bulkWrite(generateUpdateTasks(result.glj_result));
          }
          adjustState= _.sortByOrder(adjustState, ['index'], ['asc']);
          adjustState=_.map(adjustState, _.property('content'));
@@ -110,6 +110,13 @@ async function calculateQuantity(query,noNeedCal=null,refreshRationName = false)
     }
 }
 
+function quantityUpdateCheck(glj,r) {//检查,有改变的才更新
+    for(let key in r.doc){
+        if(glj._doc[key] != r.doc[key]) return true
+    }
+    return false
+}
+
 function generateRationName(ration,gljList) {
     let caption = ration.caption ? ration.caption:ration.name;
     let replaceList = [];
@@ -158,7 +165,7 @@ function generateUpdateTasks(result) {
                 filter: result[i].query,
                 update: result[i].doc
             }
-        }
+        };
         tasks.push(task);
     }
     return tasks;
@@ -179,8 +186,7 @@ async function calculateQuantityPerGLJ(glj,gljList,coeList,assList,adjustState,m
     let quantity =  scMathUtil.roundTo(parseFloat(glj.quantity),-decimal);
     let result={
         query:{
-            ID:glj.ID,
-            projectID:glj.projectID
+            ID:glj.ID
         },
         doc:{
             quantity: quantity

+ 43 - 1
public/web/PerfectLoad.js

@@ -83,5 +83,47 @@ jQuery.bootstrapLoading = {
     },
     end: function () {
         $("#loadingPage").remove();
+    },
+    progressStop:true,
+    progressStart:async function(title="导出文件",autoBar = false){
+        if($("#progressModal").length == 0){
+            let phtml =    `<div class="modal fade" id="progressModal" data-backdrop="static">
+                            <div class="modal-dialog" role="document">
+                                <div class="modal-content">
+                                    <div class="modal-header">
+                                         <h5 class="modal-title" id="progress_modal_title">${title}</h5>
+                                    </div>
+                                     <div class="modal-body">
+                                        <!--正在生成-->
+                                        <h5 class="my-3" id="progress_modal_body">正在${title}</h5>
+                                        <div class="progress mb-3">
+                                        <div id="progress_modal_bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100" style="width: 10%"></div>
+                                        </div>
+                                     </div>
+                                   </div>
+                                </div>
+                            </div>`;
+            $("body").append(phtml);
+        }else {
+            $("#progress_modal_title").text(title);
+            $("#progress_modal_body").text(`正在${title}`);
+         }
+        $("#progress_modal_bar").css('width','0%');
+        $("#progressModal").modal('show');
+        if(autoBar == true){//假的进度条
+            $.bootstrapLoading.progressStop = false;
+            let width = 0;
+            while ($.bootstrapLoading.progressStop == false){
+                await  setTimeoutSync(null,1000);
+                width += 5;
+                if(width > 90) width -= 50;
+                $("#progress_modal_bar").css('width',`${width}%`);
+            }
+        }
+    },
+    progressEnd:function () {
+        $("#progress_modal_bar").css('width','100%');
+        $.bootstrapLoading.progressStop = true;
+        $("#progressModal").modal('hide');
     }
-}
+};

+ 11 - 3
web/building_saas/complementary_glj_lib/js/glj.js

@@ -526,10 +526,18 @@ let repositoryGljObj = {
         }
     },
     onCellEditEnd: function(sender, args) {
-        let me = repositoryGljObj, that = gljComponentOprObj,
-            rObj = sheetOpr.combineRowData(me.workBook.getSheet(0), me.setting, args.row, me),
-            updateArr = [], addArr = [], updateBasePrcArr = [];
+        let me = repositoryGljObj, that = gljComponentOprObj;
+        // 输入编号、名称、规格时,如果输入回车符或粘贴回车符,提交时应转换为空格。
+        let deESCFields = ['code', 'name', 'specs'];
         let dataCode = me.setting.header[args.col].dataCode;
+        if(deESCFields.includes(dataCode)){
+            args.editingText = me.isDef(args.editingText) ? args.editingText.toString().replace(/[\r, \n]/g, ' ') : '';
+            args.sheet.setValue(args.row, args.col, args.editingText);
+        }
+        let rObj = sheetOpr.combineRowData(me.workBook.getSheet(0), me.setting, args.row, me),
+            updateArr = [],
+            addArr = [],
+            updateBasePrcArr = [];
         me.editingRowIdx = args.row;
         rObj.basePrice = rObj.basePrice ? rObj.basePrice : 0;
         //更新

+ 24 - 12
web/building_saas/complementary_ration_lib/js/ration.js

@@ -170,6 +170,9 @@ let rationOprObj = {
     isInt: function (num) {
         return !isNaN(num) && num % 1 === 0;
     },
+    isDef: function (v) {
+        return v !== undefined && v !== null;
+    },
     getCache: function() {
         let me = this, rst = me.currentRations["_SEC_ID_" + me.currentSectionId];
         if (!(rst)) {
@@ -417,13 +420,17 @@ let rationOprObj = {
         }
     },
     onCellEditEnd: function(sender, args) {
-        let edV = args.sheet.getValue(args.row, args.col);
-        if(edV){
-            args.sheet.setValue(args.row, args.col, edV.toString().trim());
-        }
-        let me = rationOprObj, rObj = sheetsOprObj.combineRationRowData(me.workBook.getSheet(0), me.setting, args.row),
-            updateArr = [], addArr = [];
+        let me = rationOprObj;
+        // 输入编号、名称、单位时,如果输入回车符或粘贴回车符,提交时应转换为空格。
         let dataCode = me.setting.header[args.col].dataCode;
+        let deESCFields = ['code', 'name', 'unit'];
+        if(deESCFields.includes(dataCode)){
+            args.editingText = me.isDef(args.editingText) ? args.editingText.toString().replace(/[\r, \n]/g, ' ') : '';
+            args.sheet.setValue(args.row, args.col, args.editingText);
+        }
+        let rObj = sheetsOprObj.combineRationRowData(me.workBook.getSheet(0), me.setting, args.row),
+            updateArr = [],
+            addArr = [];
         me.editingRowIdx = args.row;
         if (me.currentEditingRation["ID"]) {
             if((!args.editingText || args.editingText.toString().trim().length === 0) && args.col === 0){
@@ -498,16 +505,21 @@ let rationOprObj = {
         }
     },
     canPasted: function (beginCol, maxCol) {
-        let rst = false;
-        if(maxCol < 3 || beginCol > 6){
-            rst = true;
-        }
-        return rst;
+        let me = rationOprObj;
+        // 粘贴的列不可包含不可编辑的“基价”列
+        // 粘贴的最大列不可超出表格的最大列
+        if (me.canRations &&
+            (maxCol < 3 ||
+            (beginCol > 3 && maxCol <= me.setting.header.length - 1))
+        ) {
+            return true;
+        }
+        return false;
     },
     onClipboardPasting: function(sender, args) {
         let me = rationOprObj;
         let maxCol = args.cellRange.col + args.cellRange.colCount -1;
-        if(!me.canRations || !me.canPasted(args.cellRange.col, maxCol) || maxCol > me.setting.header.length - 1){
+        if (!me.canPasted(args.cellRange.col, maxCol)) {
             args.cancel = true;
         }
     },

+ 6 - 1
web/building_saas/js/global.js

@@ -156,4 +156,9 @@ function setTimeoutSync(handle, time) {
             resolve();
         }, time);
     });
-}
+}
+
+async function progressStart(title,autoProgress = false){
+
+}
+

+ 3 - 3
web/building_saas/main/html/main.html

@@ -160,9 +160,9 @@
                           </li>
 
                           <li class="nav-item dropdown">
-                              <a class="nav-link dropdown-toggle more" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false" style="display:none">更多</a>
+                              <a class="nav-link dropdown-toggle more" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false" style="display: none;">更多</a>
                               <div class="dropdown-menu" id="div_more_dropdown_right">
-                                  <!--<a class="dropdown-item  right-nav-link"  href="javascript:void(0)" id = 'locateTab' relaPanel="#locate">查找定位</a>-->
+                                  <a class="dropdown-item  right-nav-link"  href="javascript:void(0)" id = 'locateTab' relaPanel="#locate">查找定位</a>
                                   <!--<a class="dropdown-item" data-toggle="tab" href="#sqpz" role="tab">书签批注</a>-->
                                   <script>
                                       //2018-11-23  zhang 模板库移动到更多下拉框
@@ -334,7 +334,7 @@
                                   <div class="sidebar-tools-bar container-fluid tools-bar-height-y" id="searchPanel">
                                       <div class="p-1 row">
                                           <div class="input-group input-group-sm col-12">
-                                              <input type="text" class="form-control form-control-sm" placeholder="查找内容" value="">
+                                              <input type="text" class="form-control form-control-sm" placeholder="查找内容" id="locateInput" value="">
                                               <div class="input-group-append">
                                                   <button class="btn btn-secondary btn-sm" type="button" id="locate_btn"><i class="fa fa-search" aria-hidden="true"></i></button>
                                               </div>

+ 8 - 2
web/building_saas/main/js/models/project_glj.js

@@ -44,8 +44,7 @@ ProjectGLJ.prototype.loadData = function (callback = null,error=null) {
                 if(error) error();
                 return false;
             }
-            self.datas = response.data;
-            self.calcQuantity();
+            self.refreshByDatas(response.data);
             // 回调函数
             if (callback !== null) {
                 callback(response.data);
@@ -56,6 +55,13 @@ ProjectGLJ.prototype.loadData = function (callback = null,error=null) {
     });
 };
 
+//更新项目工料机数据和缓存
+ProjectGLJ.prototype.refreshByDatas = function(datas){
+    this.datas = datas;
+    this.calcQuantity();
+};
+
+
 ProjectGLJ.prototype.synLoadData = function () {
     return new Promise(function (resolve, reject) {
         projectObj.project.projectGLJ.loadData(function (data) {

+ 1 - 1
web/building_saas/main/js/models/ration_coe.js

@@ -197,7 +197,7 @@ var ration_coe = {
                 CommonAjax.post("/ration/updateCoeAdjust",updateData,function (result) {
                     $.bootstrapLoading.end();
                     me.refreshAfterUpdate(result.coe);
-                    zmhs_obj.refreshAfterUpdate(result,true)
+                    zmhs_obj.refreshAfterUpdate(result)
                 })
             });
 

+ 6 - 4
web/building_saas/main/js/views/character_content_view.js

@@ -204,11 +204,12 @@ let contentOprObj = {
         if(args.sheet.isEditing()){
             args.sheet.endEdit(true);
         }
+        let isChecked = args.sheet.getValue(args.row, args.col);
+        // 锁定清单值不变
         if(projectObj.project.projectInfo.property.lockBills && projectObj.project.withinBillsLocked(projectObj.project.mainTree.selected)){
-            args.sheet.setValue(args.row, args.col, 0);
+            args.sheet.setValue(args.row, args.col, !isChecked);
             return;
         }
-        let isChecked = args.sheet.getValue(args.row, args.col);
         if(me.currentCache.length > args.row){
             me.currentCache[args.row].isChecked = isChecked;
             me.save();
@@ -766,11 +767,12 @@ let characterOprObj = {
         if(args.sheet.isEditing()){
             args.sheet.endEdit(true);
         }
+        let isChecked = args.sheet.getValue(args.row, args.col);
+        // 锁定清单值不变
         if(projectObj.project.projectInfo.property.lockBills && projectObj.project.withinBillsLocked(projectObj.project.mainTree.selected)){
-            args.sheet.setValue(args.row, args.col, 0);
+            args.sheet.setValue(args.row, args.col, !isChecked);
             return;
         }
-        let isChecked = args.sheet.getValue(args.row, args.col);
         if(me.currentCache.length > args.row){
             me.currentCache[args.row].isChecked = isChecked;
             me.save();

+ 228 - 14
web/building_saas/main/js/views/locate_view.js

@@ -32,7 +32,7 @@ let locateObject={
         header:[
             {headerName: "编码", headerWidth: 120, dataCode: "code", dataType: "String"},
             {headerName: "名称", headerWidth: 80, dataCode: "name", dataType: "String"},
-            {headerName: "规格型号", headerWidth: 80, dataCode: "code", dataType: "String"},
+            {headerName: "规格型号", headerWidth: 80, dataCode: "specs", dataType: "String"},
             {headerName: "单位", headerWidth: 50, dataCode: "unit", dataType: "String",hAlign: "center"},
             {headerName: "市场价", headerWidth: 65, dataCode: "marketPrice", dataType: "Number", hAlign: "right"}
         ],
@@ -41,6 +41,7 @@ let locateObject={
             colHeaderHeight:30
         }
     },
+    datas:[],
     initMainSpread:function(){
         if(!this.mainSpread){
             this.mainSpread = SheetDataHelper.createNewSpread($("#locate_result")[0],3);
@@ -51,24 +52,24 @@ let locateObject={
         }
     },
     initMainSheet:function () {
-       // this.mainSheet = this.mainSpread .getSheet(0);
-        //this.spread.bind(GC.Spread.Sheets.Events.ButtonClicked, this.onReplaceButtonClick);
-       //初始化清单表格
+        //初始化清单表格
         sheetCommonObj.initSheet(this.mainSpread .getSheet(0),this.bills_setting);
         this.mainSpread .getSheet(0).setRowCount(0);
         //初始化定额表格
         sheetCommonObj.initSheet(this.mainSpread .getSheet(1),this.ration_setting);
         this.mainSpread .getSheet(1).setRowCount(0);
-
         //初始化人材机表格
         sheetCommonObj.initSheet(this.mainSpread.getSheet(2),this.ration_glj_setting);
         this.mainSpread .getSheet(2).setRowCount(0);
+        this.mainSpread.bind(GC.Spread.Sheets.Events.CellDoubleClick,this.onSheetDoubleClick);
+        this.mainSpread .getSheet(2).bind(GC.Spread.Sheets.Events.SelectionChanged,this.gljSelectionChange);
     },
     initSubSpread:function () {
         if(!this.subSpread){
             this.subSpread = SheetDataHelper.createNewSpread($("#locate_sub")[0]);
             sheetCommonObj.spreadDefaultStyle(this.subSpread);
             this.initSubSheet();
+            this.subSpread.bind(GC.Spread.Sheets.Events.CellDoubleClick,this.onSheetDoubleClick);
         }else {
             this.subSpread.refresh();
         }
@@ -85,14 +86,39 @@ let locateObject={
         this.subSheet = this.subSpread .getSheet(0);
         sheetCommonObj.initSheet( this.subSheet, this.ration_setting);
         this.subSheet.setRowCount(0);
-        //this.spread.bind(GC.Spread.Sheets.Events.ButtonClicked, this.onReplaceButtonClick);
         this.subSheet.name('locate_sub');
     },
-    showMainData:function () {
-        let datas = [];
-        //sheetCommonObj.showData(this.mainSheet,this.mainSettiong,datas);
+    initOutstanding:function () {
+        if(!projectObj.project.property.locateSetting) return;
+        let outstd = projectObj.project.property.locateSetting;
+        $("#outstanding").prop("checked",outstd.outstanding);
+        $("#outInp").val(parseFloat(outstd.outInp));
+    },
+    showMainData:function (datas,setting) {
+        sheetCommonObj.showData(this.mainSpread.getActiveSheet(),setting,datas);
         this.mainSpread.getActiveSheet().setRowCount(datas.length);
     },
+    showSubRateDatas:function () {
+        this.subRationDatas = this.getSubRationDatas();
+        sheetCommonObj.showData(this.subSheet,this.ration_setting,this.subRationDatas);
+        this.subSheet.setRowCount(this.subRationDatas.length);
+    },
+
+    getSubRationDatas:function () {
+        let datas = [];
+        let sheet = this.mainSpread.getActiveSheet();
+        let oldSel = sheet.getSelections()[0];
+        if(this.gljDatas && this.gljDatas.length > 0){
+            let glj = this.gljDatas[oldSel.row];
+            if(!glj) return datas;
+            let  nodes = projectObj.project.projectGLJ.getImpactRationNodes([glj.reference]);
+            for(let n of nodes){
+                datas.push(this.getShowRationDatas(n.data));
+            }
+        }
+        return datas;
+    },
+
     refreshView: function (options, refreshWorkBook) {
         let me = this;
         let mainHeight = $(window).height()-$(".header").height()-$(".toolsbar").height()-$("#searchPanel").height();
@@ -118,28 +144,200 @@ let locateObject={
             me.refreshView(options, false);
             me.initMainSpread();
             me.initSubSpread();
-            me.showMainData();
         };
+        if(options == "bills") me.initOutstanding();
         options == "bills"?$("#outstandingOptions").show(0,callback):$("#outstandingOptions").hide(0,callback);
 
     },
     findRecodes:function () {
-
+        let options = $("input[name='content_type']:checked").val();
+        let keyword = $("#locateInput").val();
+        switch (options){
+            case "bills":
+                this.billsDatas = this.findBills(keyword);
+                this.showMainData(this.billsDatas,this.bills_setting);
+                break;
+            case "ration":
+                this.rationDatas = this.findRations(keyword);
+                this.showMainData(this.rationDatas,this.ration_setting);
+                break;
+            case "ration_glj":
+                this.gljDatas = this.findGLJs(keyword);
+                this.showMainData(this.gljDatas,this.ration_glj_setting);
+                this.showSubRateDatas();
+                break;
+        }
     },
     onshow:function () {
         locateObject.init();
+    },
+    matchItem:function (keyword,i) {//true 匹配上,false匹配失败
+        let match = false;
+        if(keyword && keyword !="") {//如果keyword为空,匹配所有
+            if (i.code && i.code.indexOf(keyword) != -1) match = true;
+            if (i.name && i.name.indexOf(keyword) != -1) match = true;
+            if(match == false) return false
+        }
+        return true;
+    },
+    findGLJs:function(keyword){
+        let datas = [];
+        let gljList = projectObj.project.projectGLJ.datas.gljList;
+        gljList =  sortProjectGLJ(gljList);
+        for(let glj of gljList){
+            // if(glj.quantity == 0 || glj.quantity == '0') continue;  2019-07-01 需求改成消耗量为0也显示
+            let match = this.matchItem(keyword,glj);
+            if(match == false) continue;
+            let data = getGLJDatas(glj);
+            gljOprObj.setGLJPrice(data,glj);
+            datas.push(data);
+        }
+        return datas;
+        function getGLJDatas(tem) {
+            return{
+                ID:tem.id,
+                name:tem.name,
+                code:tem.code,
+                unit:tem.unit,
+                specs:tem.specs,
+                reference:tem
+            }
+        }
+
+    },
+    findRations:function (keyword) {
+        let datas = [];
+        let items = projectObj.project.mainTree.items;
+        for(let  i of items){
+            if(i.sourceType == ModuleNames.ration){
+                let match = this.matchItem(keyword,i.data);
+                if(match == false) continue;
+                let bills = this.getShowRationDatas(i.data);
+                datas.push(bills);
+            }
+        }
+        return datas;
+    },
+    getShowRationDatas:function(data){
+        return{
+            ID:data.ID,
+            name:data.name,
+            code:data.code,
+            unit:data.unit,
+            quantity:data.quantity
+        }
+    },
+    findBills:function(keyword){
+        let datas = [],priceMap={};
+        let items = projectObj.project.mainTree.items;
+        for(let  i of items){
+            if(i.sourceType == ModuleNames.bills){
+                let match = this.matchItem(keyword,i.data);
+                if(match == false) continue;
+                let bills = getBillData(i.data);
+                priceMap = setPriceMap(bills,priceMap);
+                datas.push(bills);
+            }
+        }
+        setBgColour(datas,priceMap);
+        datas =  _.sortByAll(datas,['code']);
+        return datas;
+
+
+        function setBgColour(bills,map) {
+            let outStd = $("#outstanding").prop("checked");
+            let outInp = $("#outInp").val();
+            if(outStd == true && outInp && outInp!=""){
+                for(let b of bills){
+                    if(b.code && b.code.length >= 9){
+                        let key = b.code.substr(0,9);
+                        if(map[key] && map[key].count > 1){
+                            let avg = map[key].total/map[key].count;
+                            let unitPrice = b.unitPrice?parseFloat(b.unitPrice):0;
+                            if(unitPrice ==0 ) continue;
+                            if(Math.abs(unitPrice - avg)/avg * 100  >= parseFloat(outInp)) b.bgColour = "#FFFACD"
+                        }
+                    }
+                }
+            }
+        }
+        function setPriceMap (bills,map) {
+            if(bills.code && bills.code.length >= 9){
+                let key = bills.code.substr(0,9);
+                let unitPrice = bills.unitPrice?parseFloat(bills.unitPrice):0;
+                if(map[key]){
+                    map[key].total += unitPrice;
+                    map[key].count ++;
+                }else {
+                    map[key] = {total:unitPrice,count:1}
+                }
+
+            }
+
+            return map;
+        }
+
+        function getBillData(data) {
+            return{
+                ID:data.ID,
+                name:data.name,
+                code:data.code,
+                unit:data.unit,
+                quantity:data.quantity,
+                unitPrice:data.feesIndex&&data.feesIndex.common?data.feesIndex.common.unitFee:"",
+                totalPrice:data.feesIndex&&data.feesIndex.common?data.feesIndex.common.totalFee:"",
+                bgColour:"white"
+            }
+        }
+    },
+    onSheetDoubleClick:function (e,args) {
+        let me = locateObject;
+        let options = $("input[name='content_type']:checked").val();
+        let sheetName = args.sheet.name()
+        if(options == "ration_glj"&&sheetName != "locate_sub" ) return;
+        let datas = options == "bills"? me.billsDatas:me.rationDatas;
+        if( args.sheet.name() == "locate_sub") datas = me.subRationDatas;
+        me.locateNode(datas[args.row].ID);
+    },
+    gljSelectionChange:function (e,args) {
+        let me = locateObject;
+        let newSel = args.newSelections[0];
+        let oldSel = args.oldSelections?args.oldSelections[0]:{};
+        if(newSel.row != oldSel.row){
+            me.showSubRateDatas();
+        }
+    },
+    locateNode:function (ID) {
+        let node =  projectObj.project.mainTree.findNode(ID);
+        if(node) projectObj.loadFocusLocation(node.serialNo(),1);
+    },
+    updateOutStanding:function (outstanding,outInp) {
+        let outstd = {outstanding:outstanding,outInp:outInp};
+        let updateData = {type:ModuleNames.project,data:{'ID' : projectObj.project.ID(),'property.locateSetting':outstd}};
+        projectObj.project.updateNodes([updateData],function () {
+            projectObj.project.property.locateSetting = outstd;
+        });
     }
-}
+
+};
 
 
 $("#locate_btn").click(function () {
     locateObject.findRecodes();
 });
 
+//回车键搜索
+$('#locateInput').bind('keypress', function (event) {
+    if(event.keyCode === 13){
+        $(this).blur();
+        locateObject.findRecodes();
+    }
+});
+
 $("input[name='content_type']").each(function(){
     $(this).click(function(){
-        let optins = $(this).val();
-        switch (optins){
+        let options = $(this).val();
+        switch (options){
             case "bills":
                 locateObject.mainSpread.setActiveSheetIndex(0);
                 break;
@@ -153,3 +351,19 @@ $("input[name='content_type']").each(function(){
         locateObject.init();
     });
 });
+
+
+$('#outInp').change(function(){
+    let me = locateObject;
+    let process = getDecimal('process');
+    var newVal = $(this).val();
+    let outInp = scMathUtil.roundForObj(newVal,process);
+    let outStd = $("#outstanding").prop("checked");
+    me.updateOutStanding(outStd,outInp);
+});
+$('#outstanding').change(function(){
+    let me = locateObject;
+    let outInp = $("#outInp").val();
+    let outStd = $("#outstanding").prop("checked");
+    me.updateOutStanding(outStd,scMathUtil.roundForObj(outInp,getDecimal('process')));
+});

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

@@ -1567,10 +1567,10 @@ var projectObj = {
     },
 
     // 获取上次退出时的焦点位置
-    loadFocusLocation: function() {
+    loadFocusLocation: function(orow,ocol) {
         const projectId = scUrlUtil.GetQueryString('project');
-        let row = getLocalCache('lastRow:' + projectId);
-        let col = getLocalCache('lastCol:' + projectId);
+        let row = gljUtil.isDef(orow)?orow:getLocalCache('lastRow:' + projectId);
+        let col = gljUtil.isDef(ocol)?ocol:getLocalCache('lastCol:' + projectId);
         if(row == null || col == null){
             //默认焦点定位到造价书的第一行“分项”。
             col = 1;

+ 7 - 10
web/building_saas/main/js/views/zmhs_view.js

@@ -203,9 +203,9 @@ let zmhs_obj = {
         this.assSheetData = assList;
         return assList;
     },
-    refreshAfterUpdate:function(result,reload){
+    refreshAfterUpdate:function(result){
         let ration_glj = projectObj.project.ration_glj;
-        let calcInstall = false;//是否记安装增加费
+        let calcInstall = false;//是否记安装增加费
         let nodes = projectObj.project.updateNodesCache([{type:ModuleNames.ration,data:result.ration}]);
         if(result.add && result.add.length > 0){//需添加定额工料机的情况
             ration_glj.datas = ration_glj.datas.concat(result.add);
@@ -223,14 +223,11 @@ let zmhs_obj = {
         projectObj.mainController.refreshTreeNode(nodes, false);
 
         let rationID= ration_glj.updateCacheAfterAdjust(result.ration_glj);
-        if(reload == true){//有添加、替换、工料机等需重新加载的情况
-            $.bootstrapLoading.start();
-            projectObj.project.projectGLJ.loadData(function () {
-                $.bootstrapLoading.end();
-                if(result.add && result.add.length > 0) ration_glj.addToMainTree(result.add);//这个方法有再去项目工料机那里取价格,所以要在回调里调用,不像替换工料的情况
-                ration_glj.reCalcWhenGLJChange({rationID:rationID});
-                if(result.delete && result.delete.length > 0 && calcInstall) installationFeeObj.calcInstallationFee();//如果是删除节点的话,
-            });
+        if(result.projectGLJDatas){//有添加、替换、工料机等需重新加载的情况
+            projectObj.project.projectGLJ.refreshByDatas(result.projectGLJDatas);
+            if(result.add && result.add.length > 0) ration_glj.addToMainTree(result.add);//这个方法有再去项目工料机那里取价格,所以要在回调里调用,不像替换工料的情况
+            ration_glj.reCalcWhenGLJChange({rationID:rationID});
+            if(result.delete && result.delete.length > 0 && calcInstall) installationFeeObj.calcInstallationFee();//如果是删除节点的话,
         }else {
             ration_glj.reCalcWhenGLJChange({rationID:rationID});
         }

+ 13 - 34
web/building_saas/pm/html/project-management.html

@@ -646,54 +646,33 @@
     </div>
 </div>
 
-<!--弹出 导出-->
-<div class="modal fade" id="export" 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">
-                <!--正在生成-->
-                <h5 class="my-3">正在生成文件</h5>
-                <div class="progress mb-3">
-                    <div id="export_progress_bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100" style="width: 10%"></div>
-                </div>
-            </div>
-        </div>
-    </div>
-</div>
 
-<!--弹出 导出-->
+
+<!--弹出 导入-->
 <div class="modal fade" id="import" data-backdrop="static">
-    <div class="modal-dialog" role="document">
+    <div class="modal-dialog" style="z-index: 800" 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>
+                <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">
-                <form>
-                    <div class="form-group">
-                        <label>请选择ybp格式文件</label>
-                        <input class="form-control-file" type="file" accept=".ybp" name="import_project_data"/>
-                    </div>
-                </form>
+                <div class="custom-file">
+                    <input type="file" class="custom-file-input" name="import_project_data" id="import_project_data" lang="zh" accept=".ybp">
+                    <label class="custom-file-label"  id="import_project_label" style="white-space: nowrap; overflow: hidden;">请选择建设项目文件</label>
+                </div>
             </div>
             <div class="modal-footer">
-                <button type="button" class="btn btn-primary" id="confirm-import">确定导入</button>
-                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                <button type="button" class="btn btn-primary " disabled id="confirm-import">确定导入</button>
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
             </div>
         </div>
     </div>
 </div>
 
 
-
 <!-- JS. -->
 <script src = "/lib/spreadjs/sheets/gc.spread.sheets.all.11.1.2.min.js"></script>
 <script src = "/lib/fileSaver/FileSaver.min.js"></script>

+ 88 - 27
web/building_saas/pm/js/pm_newMain.js

@@ -346,24 +346,33 @@ const projTreeObj = {
                 let selectedItem = projTreeObj.tree.selected;
                 return !(selectedItem && selectedItem.data.projType === projectType.project);
             },
-            visible:function () {
+           /* visible:function () {
                 return false
-            },
+            },*/
             callback: function (key, opt) {
                 //获取当前节点的建设项目ID
                 projTreeObj.exportProject(projTreeObj.tree.selected.data.ID,projTreeObj.tree.selected.data.name);
             }
         },
-        improtProject:{
+        importProject:{
             name: "导入建设项目",
             icon: 'fa-external-link',
             disabled: function () {
                 let selectedItem = projTreeObj.tree.selected;
-                return !(selectedItem && selectedItem.data.projType === projectType.project);
+                if(selectedItem){
+                    if(selectedItem.data.projType === projectType.project) return false;//如果是建设项目,可用
+                    if(selectedItem.data.projType === projectType.folder){//如果是文件夹
+                        if(selectedItem.children){
+                            if(selectedItem.children.length == 0) return false;//如果文件夹没有子项,可用
+                            if(selectedItem.children[0] .projType === projectType.project ) return false;//如果文件夹有子项,并且是建设项目,可用
+                        }
+                    }
+                }
+                return true;
             },
-            visible:function () {
+          /*  visible:function () {
               return false
-            },
+            },*/
             callback: function (key, opt) {
                 //获取当前节点的建设项目ID
                 $("#import").modal('show');
@@ -401,7 +410,7 @@ const projTreeObj = {
                 "manageFiles": me.contextMenuItems.manageFiles,
                 "refreshSummary": me.contextMenuItems.refreshSummary,
                 "exportProject":me.contextMenuItems.exportProject,
-                "importProject":me.contextMenuItems.improtProject
+                "importProject":me.contextMenuItems.importProject
             }
         });
     },
@@ -1474,13 +1483,13 @@ const projTreeObj = {
         this.refreshProjectData(projectID);
     },
      exportProject:async function(projectID,projectName){
-        $("#export_progress_bar").css('width','0%');
-        $("#export").modal('show');
+        $.bootstrapLoading.progressStart();
         let spString = "|----|";
         try {
             let sumString = "";
+            $("#progress_modal_bar").css('width','5%');
             let result = await getProjectInfo({projectID:projectID,type:"main",user_id: userID});
-            $("#export_progress_bar").css('width','10%');
+            $("#progress_modal_bar").css('width','10%');
             let result_arr = result.split(spString);
             sumString = result_arr[0];
             if(result_arr.length == 2){
@@ -1491,20 +1500,19 @@ const projTreeObj = {
                 for(let t of tenders){
                     let tenderString = await getProjectInfo({projectID:t,rootProjectID:projectID,type:"sub",user_id: userID});
                     width += each;
-                    $("#export_progress_bar").css('width',width+'%');
+                    $("#progress_modal_bar").css('width',width+'%');
                     await  setTimeoutSync(null,500);//设置间隔
                     sumString = sumString + spString +tenderString;
-                    console.log(JSON.parse(tenderString));
                 }
 
             }
-            $("#export_progress_bar").css('width','100%');
-            $("#export").modal('hide');
+            $.bootstrapLoading.progressEnd();
           //  console.log(JSON.parse(sumString));
 
             saveProjectFile(sumString);
 
         }catch (e){
+            alert("导出失败!请查看log.");
             console.log(e)
         }
 
@@ -1512,23 +1520,29 @@ const projTreeObj = {
         async function getProjectInfo(data) {
             let result = await ajaxPost("/pm/api/exportProject",data);
             return result;
-           // let blob = new Blob([result], {type: 'text/plain;charset=utf-8'});
-           // saveAs(blob, 'textName.ybp');
         }
 
         function saveProjectFile(data) {
             let blob = new Blob([data], {type: 'text/plain;charset=utf-8'});
             saveAs(blob, projectName+'.ybp');
         }
-
-       /* setTimeout(function(){
-            $("#progressbar").css('width','50%');
-            setTimeout(function(){
-                $("#export").modal('hide');
-            },1000)
-            //$("#export").modal('hide');
-        },1000)*/
+    },
+    getImportProjectDate:function () {//导入建设项目时,需要在现有的树节点中插入新的节点,这里是取插入所需的项目数据
+        let selectNode = projTreeObj.tree.selected;
+        let parent = null,next=null;
+        let updateData = {};
+        if(selectNode && selectNode.data.projType == projectType.folder){
+            parent = selectNode;
+            next = selectNode.firstChild();
+        }else if(selectNode &&  selectNode.data.projType == projectType.project){
+            parent = selectNode.parent;
+            next = selectNode.nextSibling;
+            updateData["update"] = {query:{ID:selectNode.id()}}
+        }
+        updateData["self"] ={ParentID:parent.id(),NextSiblingID:next?next.id():-1};
+        return updateData;
     }
+
 };
 
 $(document).ready(function() {
@@ -2093,11 +2107,11 @@ function initProjects(callback) {
  *
  * @return {void}
  */
-function init() {
+function init(refresh = false) {//refresh是刷新页面时才使用的
     billValuation = billValuation.replace(/\n/g, '\\n');
     rationValuation = rationValuation.replace(/\n/g, '\\n');
     //init spread and pmTree
-    socketObject.connect('pm');//socket 连接;
+    if(refresh == false) socketObject.connect('pm');//socket 连接;
     if (isFirst) {
         $('#progress').modal('show');
         let intervalTime = prepareInitialTimer();
@@ -2120,6 +2134,16 @@ function init() {
     engineering = engineeringList !== null && engineeringList !== undefined ? JSON.parse(engineeringList) : [];
 }
 
+function refreshAllPage(){
+    if(gcTreeObj.workBook){
+        gcTreeObj.workBook.destroy();
+        gcTreeObj.workBook = null;
+    }
+    gcTreeObj.tree = null;
+    init(true);
+}
+
+
 /**
  * 新增建设项目
  *
@@ -3575,6 +3599,7 @@ $('#otherProject').change(function(){
     }
 });
 
+
 //分享给...界面确认
 $('#shareToConfirm').click(function () {
     let selected = projTreeObj.tree.selected;
@@ -3596,6 +3621,9 @@ $("#confirm-import").click(function() {
         }
         formData.append('file', file.files[0]);
         formData.append('userID', userID);
+        formData.append("updateData",JSON.stringify(projTreeObj.getImportProjectDate()));
+        $('#import').modal("hide");
+        $.bootstrapLoading.progressStart("导入建设项目",true);
         $.ajax({
             url: '/pm/api/importProject',
             type: 'POST',
@@ -3608,10 +3636,21 @@ $("#confirm-import").click(function() {
                 self.text('上传中...');
             },
             success: function(response){
+                self.text('确定导入');
+                $.bootstrapLoading.progressEnd();
+                if(response.error == 1){
+                    alert(response.msg);
+                }else {
+                    refreshAllPage();
+                }
 
             },
             error: function(){
-
+                setTimeout(function () {
+                    self.text('确定导入');
+                    $.bootstrapLoading.progressEnd();
+                    alert("导入失败,请检查文件!");
+                },1000)
             }
         });
     } catch(error) {
@@ -3620,6 +3659,28 @@ $("#confirm-import").click(function() {
     }
 });
 
+$("#import_project_data").change(function(){
+    let file = $(this)[0];
+    let projectFile = file.files[0];
+    if(projectFile) {
+        let ybpReg = /ybp$/g;
+        if(projectFile.name && ybpReg.test(projectFile.name)){
+            $('#import_project_label').text(`${projectFile.name}`);
+            $('#confirm-import').removeAttr("disabled");
+        }else {
+            alert("请选择ybp项目文件");
+            $(this).val('');
+            $('#confirm-import').attr("disabled","disabled");
+        }
+    }
+});
+
+//清空导入清单选择文件
+$('#import').on('show.bs.modal', function(){
+    $('#import_project_data').val('');
+    $('.custom-file-label').text(`请选择建设项目文件`);
+});
+
 //设置分享给界面数据
 //@param {Object}selected @return {void}
 function setShareToModal(selected){

+ 3 - 2
web/over_write/js/chongqing_2018.js

@@ -315,7 +315,7 @@ if(typeof module !== 'undefined'){
 }
 
 function getCusCoeContent() {
-    return '人工×1,材料×1,施工机具×1,主材×1'
+    return '人工×1,材料×1,施工机具×1,主材×1,设备×1'//2019-07-08 bug 添加自定义系数添加设备
 }
 
 function getCustomerCoeData() {
@@ -324,6 +324,7 @@ function getCustomerCoeData() {
         { amount:1, operator:'*', gljCode:null, coeType:'人工'},
         { amount:1, operator:'*', gljCode:null, coeType:'材料'},
         { amount:1, operator:'*', gljCode:null, coeType:'施工机具'},
-        { amount:1, operator:'*', gljCode:null, coeType:'主材'}
+        { amount:1, operator:'*', gljCode:null, coeType:'主材'},
+        { amount:1, operator:'*', gljCode:null, coeType:'设备'}
     ]
 }