Browse Source

Merge remote-tracking branch 'origin/master'

vian 5 years ago
parent
commit
5f75d1c4b4

File diff suppressed because it is too large
+ 2 - 0
lib/qiniu/qiniu.min.js


+ 20 - 0
modules/all_models/import_logs.js

@@ -0,0 +1,20 @@
+/**
+ * Created by zhang on 2019/12/27.
+ */
+import mongoose from "mongoose";
+
+let Schema = mongoose.Schema;
+let collectionName = 'import_logs';
+
+let modelSchema = {
+    // 日志类型
+    key: {type: String, index: true},
+    // 日志内容
+    userID: String,
+    // 关联用户id
+    status:String,
+    // 创建时间
+    create_time: Number,
+    errorMsg:""
+};
+mongoose.model(collectionName, new Schema(modelSchema, {versionKey: false, collection: collectionName}));

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

@@ -8,10 +8,8 @@ let logger = require("../../../logs/log_helper").logger;
 let pm_facade = require('../../pm/facade/pm_facade');
 let controller = {
     importProject:async function (req){
-        let data = req.body.data;
-        let sessionInfo = {session:req.body.session};
-        let fields = req.body.fields;
-        return await pm_facade.importProjects(data,sessionInfo,fields);
+        let data = req.body;
+        return await pm_facade.downLoadProjectFile(data);
     },
     exportProject:async function(req){
         let result={

+ 15 - 1
modules/main/models/bills.js

@@ -35,9 +35,23 @@ class billsModel extends baseModel {
     getQuery(projectID){
         return {'$or': [{projectID: projectID, deleteInfo: null}, {projectID: projectID, 'deleteInfo.deleted': {$in: [null, false]}}]}
     }
-     getData (projectID, callback) {
+     getData (projectID, callback, isReport = false) {
         this.model.find(this.getQuery(projectID), '-_id', function(err, datas){
             if (!err) {
+                if (isReport){
+                    for (let i = 0; i < datas.length; i++) {
+                       let fees = datas[i]._doc.fees;
+                       if (fees){
+                           for (let i = 0; i < fees.length; i++) {
+                               let doc = fees[i]._doc;
+                               if (doc){
+                                   if (doc.tenderTotalFee) doc.totalFee = doc.tenderTotalFee;
+                                   if (doc.tenderUnitFee) doc.unitFee = doc.tenderUnitFee;
+                               }
+                           }
+                       }
+                    }
+                };
                 callback(0, projectConsts.BILLS, datas);
             } else {
                 callback(1, projectConsts.BILLS, null);

+ 1 - 1
modules/main/models/project.js

@@ -138,7 +138,7 @@ Project.prototype.getFilterData = function (projectID, filter, callback) {
             if (moduleMap[moduleName]) {
                 moduleMap[moduleName].getData(projectID, function (err, name, data) {
                     cb(err, {'moduleName': name, 'data': data})
-                });
+                }, true);     // 所有报表只显示调价后的数据,这里传入一个标记true,子方法会将调价后的值赋给调价前的字段,这样报表可以不用动。
             } else if (moduleName === projectConsts.PROJECTGLJ) {
                 try {
                     if (isNaN(projectID) || projectID <= 0) {

+ 15 - 1
modules/main/models/ration.js

@@ -19,9 +19,23 @@ class rationModel extends baseModel {
     getQuery(projectID){
         return {'$or': [{projectID: projectID, deleteInfo: null}, {projectID: projectID, 'deleteInfo.deleted': {$in: [null, false]}}]}
     }
-    getData (projectID, callback) {
+    getData (projectID, callback, isReport = false) {
         ration.find(this.getQuery(projectID), '-_id', function(err, datas){
             if (!err) {
+                if (isReport){
+                    for (let i = 0; i < datas.length; i++) {
+                        let fees = datas[i]._doc.fees;
+                        if (fees){
+                            for (let i = 0; i < fees.length; i++) {
+                                let doc = fees[i]._doc;
+                                if (doc){
+                                    if (doc.tenderTotalFee) doc.totalFee = doc.tenderTotalFee;
+                                    if (doc.tenderUnitFee) doc.unitFee = doc.tenderUnitFee;
+                                }
+                            }
+                        }
+                    }
+                };
                 callback(0, projectConsts.RATION, datas);
             } else {
                 callback(1, '', null);

+ 40 - 22
modules/pm/controllers/pm_controller.js

@@ -731,28 +731,46 @@ module.exports = {
 
     },
     importProject:async function(req,res){
-        let form = new multiparty.Form({uploadDir: './tmp'});
-        let path = "";
-        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 '上传失败。';
-                };
-                path = file.path;
-                let data = fs.readFileSync(file.path,'utf-8');
-                let body = {data: data, fields:fields, session:req.session};
-                let result = await redirectToImportServer(body,"importProject",req);
-                res.json(result);
-            }catch (e){
-                console.log(e);
-                res.json({error:1,msg:"导入失败请检查文件!"})
-            }finally {
-                fs.unlinkSync(path);
-            }
-
-        })
+        let data = JSON.parse(req.body.data);
+        let result={
+            error:0
+        };
+        try {
+            data.session = req.session;
+            result = await redirectToImportServer(data,"importProject",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
+        };
+        try{
+            let data = JSON.parse(req.body.data);
+            result.data = await pm_facade.importProcessChecking(data);
+        } catch (err){
+            console.log(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        res.json(result);
+    },
+    getUploadToken:function (req,res) {
+        let result={
+            error:0
+        };
+        try {
+            result =pm_facade.uploadToken();
+        }catch (err){
+            console.log(err);
+            result.error=1;
+            result.message = err.message;
+        }
+        res.json(result);
     },
     getBasicInfo: async function(req, res) {
         try {

+ 102 - 8
modules/pm/facade/pm_facade.js

@@ -32,7 +32,10 @@ module.exports={
     getProjectPlaceholder: getProjectPlaceholder,
     exportProject:exportProject,
     importProjects:importProjects,//建筑这里重名了,这比养护加多了个s
-    initOverHeightItems: initOverHeightItems
+    initOverHeightItems: initOverHeightItems,
+    uploadToken:uploadToken,
+    downLoadProjectFile:downLoadProjectFile,
+    importProcessChecking:importProcessChecking
 };
 
 
@@ -77,13 +80,14 @@ let evaluateListModel = mongoose.model("evaluate_list");
 let bidListModel = mongoose.model("bid_evaluation_list");
 let contractorListModel = mongoose.model("contractor_list");
 let featureLibModel =  mongoose.model("std_project_feature_lib");
+let importLogsModel = mongoose.model("import_logs");
 const overHeightLibModel = mongoose.model('std_over_height_lib');
 let scMathUtil = require('../../../public/scMathUtil').getUtil();
 let counter = require('../../../public/counter/counter');
 import SectionTreeDao from '../../complementary_ration_lib/models/sectionTreeModel';
 let sectionTreeDao = new SectionTreeDao();
 import CounterModel from "../../glj/models/counter_model";
-import moment from 'moment';
+import moment from 'moment-timezone';
 import billsFlags from '../../common/const/bills_fixed';
 const notDeleted = [{deleteInfo: null}, {'deleteInfo.deleted': false}];
 import {
@@ -100,7 +104,18 @@ let mainColLibModel = mongoose.model('std_main_col_lib');
 import EngineeringLibModel from "../../users/models/engineering_lib_model";
 let installationFacade = require('../../main/facade/installation_facade');
 let cipher = require('../../../public/cipher');
-
+let qiniu = require("qiniu");
+let fs = require("fs");
+let path = require("path");
+let request = require("request");
+
+let qiniu_config = {
+    "AccessKey": "_gR1ed4vi1vT2G2YITGSf4_H0fJu_nRS9Tzk3T4z",
+    "SecretKey": "ty4zd0FHqgEDaiVzSLC8DfHlai99aS7bspLkw6s6",
+    "Bucket": "yun-update",
+    "Domain": "http://serverupdate.smartcost.com.cn"
+};
+let mac = new qiniu.auth.digest.Mac(qiniu_config.AccessKey, qiniu_config.SecretKey);
 
 //拷贝例题项目
 //@param {String}userID {Array}projIDs拷贝的例题项目ID(建设项目、文件夹)@return {Boolean}
@@ -201,13 +216,13 @@ async function copyProject(userID, compilationID,data,newProjectID = null) {
     //费率文件、单价文件重名检查
     let feeRate =  await feeRateFileModel.findOne({rootProjectID:originalProperty.rootProjectID,name:originalProperty.feeFile.name,deleteInfo:null});
     if(feeRate){//存在重名的文件
-        newFeeName = originalProperty.feeFile.name + '(' + moment(Date.now()).format('MM-DD HH:mm:ss') + '复制)';
+        newFeeName = originalProperty.feeFile.name + '(' + moment(Date.now()).tz("Asia/Shanghai").format('MM-DD HH:mm:ss') + '复制)';
         projectMap['copy'].document.property.feeFile.name = newFeeName;
     }
 
     let unitPriceFile =  await unitPriceFileModel.findOne({root_project_id: originalProperty.rootProjectID,name:originalProperty.unitPriceFile.name,deleteInfo: null});
     if(unitPriceFile){//存在重名的文件
-        newUnitName = originalProperty.unitPriceFile.name + '(' + moment(Date.now()).format('MM-DD HH:mm:ss') + '复制)';
+        newUnitName = originalProperty.unitPriceFile.name + '(' + moment(Date.now()).tz("Asia/Shanghai").format('MM-DD HH:mm:ss') + '复制)';
         projectMap['copy'].document.property.unitPriceFile.name = newUnitName;
     }
 
@@ -1736,7 +1751,70 @@ async function exportTenderData(data){
     return cipher.aesEncrypt(JSON.stringify(result));
 }
 
-async function importProjects(data,req,fields) {
+async function downLoadProjectFile(info) {
+    let result = {error:0};
+    let bucketManager2 = new qiniu.rs.BucketManager(mac, null);
+    let publicBucketDomain = qiniu_config.Domain;// "http://serverupdate.smartcost.com.cn";//这里不支持https
+    let deadline = parseInt(Date.now() / 1000) + 3600; // 1小时过期
+    let privateDownloadUrl = bucketManager2.privateDownloadUrl(publicBucketDomain, info.key, deadline);
+    console.log(privateDownloadUrl);
+    let data = {
+        key:info.key,
+        userID:info.session.sessionUser.id,
+        status:"start",
+        create_time:+new Date()
+    };
+    await importLogsModel.create(data);
+    doDownLoadAndImport(privateDownloadUrl,info);
+    return result;
+}
+
+async function doDownLoadAndImport(privateDownloadUrl,info) {
+    let stream = fs.createWriteStream(path.join(__dirname, "../../../tmp/"+info.key));//
+    request(privateDownloadUrl).pipe(stream).on("close", async function (err) {
+        console.log("文件[" + info.key + "]下载完毕");
+        let doc = {status:"finish"};
+        try {
+            let data = fs.readFileSync(stream.path,'utf-8');
+            let result = await importProjects(data,{session:info.session},info.updateData);
+            if(result.error == 1){
+                doc.errorMsg = result.msg;
+                doc.status = "error";
+            }
+        }catch (error){
+            console.log(error);
+            doc.errorMsg = "导入失败,请检查文件!";
+            doc.status = "error";
+        }finally {
+            await importLogsModel.update({key:info.key},doc);
+            fs.unlinkSync(stream.path);
+        }
+    });
+}
+
+async function importProcessChecking(data){
+    let result = {error:0};
+    let log = await importLogsModel.findOne({key:data.key});
+    if(log){
+        if(log.status == "finish"){
+            result.status = "complete";
+            await importLogsModel.remove({key:data.key});
+        }else if(log.status == "start"){
+            result.status = "processing";
+        }else if(log.status == "error"){
+            result.error = 1;
+            result.msg = log.errorMsg;
+            await importLogsModel.remove({key:data.key});
+        }
+    }else {
+        result.error = 1;
+        result.msg = `导入过程中发生错误!`;
+    }
+    return result;
+
+}
+
+async function importProjects(data,req,updateData) {
     let result = {error:0};
     let stringArr = data.split("|----|");
     let datas = [];
@@ -1755,7 +1833,7 @@ async function importProjects(data,req,fields) {
             result.error = 1;
             result.msg = `导入失败:您要导入的文件是由“${fileCompilationName}”导出,当前软件是“${curCompilationName}”,请选择正确的费用定额再进行操作!`;
         }else {
-            let [projectIDMap,labourCoeFileIDMap,calcProgramFileIDMap] = await handleMainProjectDatas(mainData,JSON.parse(fields.updateData[0]),req.session.sessionUser.id);
+            let [projectIDMap,labourCoeFileIDMap,calcProgramFileIDMap] = await handleMainProjectDatas(mainData,updateData,req.session.sessionUser.id);
             if(datas.length > 1 ){
                 for(let i = 1;i<datas.length;i++){
                     await handleEachProject(datas[i],projectIDMap,labourCoeFileIDMap,calcProgramFileIDMap)
@@ -1910,7 +1988,7 @@ async function handleMainProjectDatas(mainData,updateData,userID) {
             }
             //查看是否重名;
             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') + '导入)';
+            if(temp) p.name = p.name + '(' + moment(Date.now()).tz("Asia/Shanghai").format('MM-DD HH:mm:ss') + '导入)';
         }else {
             p.ParentID = projectIDMap[p.ParentID];
             p.NextSiblingID = projectIDMap[p.NextSiblingID];
@@ -2010,3 +2088,19 @@ async function initOverHeightItems(engineeringID) {
     const overHeightLib = await overHeightLibModel.findOne({ID: overHeightLibID});
     return overHeightLib ? overHeightLib.list : defaultData;
 }
+
+function uploadToken() {
+    let options = {
+        scope: qiniu_config.Bucket,
+        deleteAfterDays: 1,
+        returnBody:
+            '{"key":"$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}'
+    };
+    let putPolicy = new qiniu.rs.PutPolicy(options);
+    let token = putPolicy.uploadToken(mac);
+    let result = {
+        uptoken: token,
+        domain: qiniu_config.Domain
+    }
+    return result
+}

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

@@ -12,7 +12,7 @@ module.exports = function (app) {
     app.get('/pm', baseController.init, pmController.index);
 
     let pmRouter = express.Router();
-
+    pmRouter.get('/getUploadToken', pmController.getUploadToken);
     pmRouter.use(function (req, res, next) {
         if (/\/getNewProjectID/.test(req.originalUrl) ||/\/importProject/.test(req.originalUrl)|| pmController.checkRight(req, res)) {
             next();
@@ -63,6 +63,7 @@ module.exports = function (app) {
     pmRouter.post('/changeFile', pmController.changeFile);
     pmRouter.post('/exportProject', pmController.exportProject);
     pmRouter.post('/importProject', pmController.importProject);
+    pmRouter.post('/importProcessChecking', pmController.importProcessChecking);
     pmRouter.post('/getBasicInfo', pmController.getBasicInfo);
     pmRouter.post('/getProjectFeature', pmController.getProjectFeature);
     pmRouter.post('/getProjectByGranularity', pmController.getProjectByGranularity);

+ 52 - 1
modules/ration_glj/facade/ration_glj_facade.js

@@ -49,6 +49,7 @@ let logger = require("../../../logs/log_helper").logger;
 import stdgljutil  from "../../../public/cache/std_glj_type_util";
 import EngineeringLibModel from "../../users/models/engineering_lib_model";
 import GljDao from "../../complementary_glj_lib/models/gljModel";
+import gljType from "../../common/const/glj_type_const.js";
 const complementaryGljModel = mongoose.model('complementary_glj_lib');
 const stdGljModel = mongoose.model('std_glj_lib_gljList');
 const gljClassModel = mongoose.model('std_glj_lib_gljClass');
@@ -905,11 +906,61 @@ async function testError() {
     throw  new Error('test Error');
 }
 
-function getData(projectID, callback) {
+function getData(projectID, callback, isReport) {
+    function findRation(rations, ID) {
+        let ration = rations.find(function getElement(element) {
+            return element.ID == ID;
+        });
+        return ration._doc;
+    };
+
     ration_glj.find({'projectID': projectID}, (err, datas) => {
         if (err) {
             callback(1, '', null);
         } else {
+            if (isReport) {
+                ration.find({'projectID': projectID}, ['ID', 'code', 'name', 'quantityCoe', 'quantity', 'rationQuantityCoe'],
+                    function cbData(err, rations) {
+                        if (!err) {
+                            for (let i = 0; i < datas.length; i++) {
+                                let glj = datas[i]._doc;
+                                let ration = findRation(rations, glj.rationID);
+                                let coe = 1;
+                                if (ration && ration.quantityCoe){
+                                    if ([gljType.LABOUR].includes(glj.type)){
+                                        if (ration.quantityCoe._doc.labour)
+                                            coe = ration.quantityCoe._doc.labour;
+                                    }
+                                    else if ([gljType.GENERAL_MATERIAL,
+                                        gljType.CONCRETE,
+                                        gljType.MORTAR,
+                                        gljType.MIX_RATIO,
+                                        gljType.COMMERCIAL_CONCRETE,
+                                        gljType.COMMERCIAL_MORTAR].includes(glj.type)){
+                                        if (ration.quantityCoe._doc.material)
+                                            coe = ration.quantityCoe._doc.material;
+                                    }
+                                    else if ([gljType.GENERAL_MACHINE,
+                                        gljType.MACHINE_COMPOSITION,
+                                        gljType.MACHINE_LABOUR].includes(glj.type)){
+                                        if (ration.quantityCoe._doc.machine)
+                                            coe = ration.quantityCoe._doc.machine;
+                                    }
+                                    else if ([gljType.MAIN_MATERIAL].includes(glj.type)){
+                                        if (ration.quantityCoe._doc.main)
+                                            coe = ration.quantityCoe._doc.main;
+                                    }
+                                    else if ([gljType.EQUIPMENT].includes(glj.type)){
+                                        if (ration.quantityCoe._doc.equipment)
+                                            coe = ration.quantityCoe._doc.equipment;
+                                    };
+
+                                };
+                                glj.quantity = glj.quantity * coe;
+                            }
+                        }
+                    });
+            };
             callback(0, consts.projectConst.RATION_GLJ, datas);
         }
     })

+ 1 - 1
modules/reports/util/rpt_construct_data_util.js

@@ -268,7 +268,7 @@ class Rpt_Data_Extractor {
             let billsDatas = getModuleDataByKey(rawDataObj.prjData, "bills");
             let decimal = rawDataObj.prj.property.decimal.glj.quantity;
             if (projectGLJDatas && rationGLJDatas && rationDatas && billsDatas) {
-                gljUtil.calcProjectGLJQuantity(projectGLJDatas.data, rationGLJDatas.data, rationDatas.data, billsDatas.data, decimal);
+                gljUtil.calcProjectGLJQuantity(projectGLJDatas.data, rationGLJDatas.data, rationDatas.data, billsDatas.data, decimal, true);
             }
         }
         //还有汇总的...

+ 3 - 1
package.json

@@ -48,6 +48,7 @@
     "lz-string": "^1.4.4",
     "main-bower-files": "^2.5.0",
     "moment": "^2.18.1",
+    "moment-timezone": "^0.5.27",
     "multiparty": "^4.1.3",
     "node-schedule": "^1.3.0",
     "node-xlsx": "^0.11.2",
@@ -56,7 +57,8 @@
     "socket.io": "2.0.3",
     "ua-parser-js": "^0.7.14",
     "uuid": "^3.1.0",
-    "wiredep": "^2.2.2"
+    "wiredep": "^2.2.2",
+    "qiniu": "^7.1.1"
   },
   "scripts": {
     "start": "C:\\Users\\mai\\AppData\\Roaming\\npm\\babel-node.cmd server.js",

+ 13 - 0
public/web/common_ajax.js

@@ -190,6 +190,19 @@ async function ajaxPost(url, data, isPlainData = false) {
 }
 
 
+async function ajaxGet(url,data){
+    return new Promise(function (resolve, reject) {
+        $.get(url,data,function (result,status) {
+            if(status == 'success'){
+                resolve(result);
+            }else {
+                reject(result);
+            }
+        },"json")
+    })
+
+}
+
 /**
  * 在页面中任何嵌套层次的窗口中获取顶层窗口
  * @return 当前页面的顶层窗口对象

+ 34 - 9
public/web/gljUtil.js

@@ -4,7 +4,7 @@
 
 
 let gljUtil = {
-    calcProjectGLJQuantity:function (projectGLJDatas,rationGLJDatas,rationDatas,billsDatas,q_decimal,_,scMathUtil,isTender) {
+    calcProjectGLJQuantity:function (projectGLJDatas,rationGLJDatas,rationDatas,billsDatas,q_decimal,_,scMathUtil,isReport) {
         let project_gljs = projectGLJDatas.gljList;
         let mixRatioMap = projectGLJDatas.mixRatioMap;
         let rations = rationDatas;
@@ -13,9 +13,9 @@ let gljUtil = {
         let rationGljGroup = _.groupBy(rationGLJDatas,'projectGLJID');
         let IDarray =  this.getSubdivisionAndTechBillsLeavesID(billsDatas);//分别取分部分项和技术措施项目的所有叶子清单ID
         let billIDs = IDarray[0],tech_billIDS = IDarray[1];
-        let sField = isTender==true?"tenderSubdivisionQuantity":"subdivisionQuantity";
-        let tField = isTender==true?"tenderTechQuantity":"techQuantity";
-        let qField = isTender==true?"tenderQuantity":"quantity";
+        let sField = "subdivisionQuantity";
+        let tField = "techQuantity";
+        let qField = "quantity";
 
         for(let pglj of project_gljs ){
             let pg_index = this.getIndex(pglj,this.gljKeyArray);
@@ -23,7 +23,7 @@ let gljUtil = {
             pglj[tField] = 0;
             pglj[qField] = 0;
             let gljGroup = rationGljGroup[pglj.id]?rationGljGroup[pglj.id]:[];//定额工料机没有,有可能是定额类型的工料机
-            let result = this.getQuantityPerGLJ(gljGroup,rations,rationMap,pglj,billIDs,tech_billIDS,q_decimal,_,scMathUtil,isTender);
+            let result = this.getQuantityPerGLJ(gljGroup,rations,rationMap,pglj,billIDs,tech_billIDS,q_decimal,_,scMathUtil);
             pglj[sField] = result.subdivisionQuantity;
             pglj[tField] = result.techQuantity;
             pglj[qField] = result.quantity;
@@ -49,8 +49,14 @@ let gljUtil = {
                 }
             }
         }
+
+        if (isReport) {
+            for(let pglj of project_gljs ){
+                pglj[qField] = pglj.tenderQuantity;
+            }
+        }
     },
-    getQuantityPerGLJ : function (ration_glj_list,rations,rationMap,pglj,billIDs,tech_billIDS,q_decimal,_,scMathUtil,isTender) {
+    getQuantityPerGLJ : function (ration_glj_list,rations,rationMap,pglj,billIDs,tech_billIDS,q_decimal,_,scMathUtil) {
         let result={};
         let quantity_sum=0;//工料机汇总消耗量
         let sum = 0;//分部分项总消耗量
@@ -174,10 +180,14 @@ let gljUtil = {
     getFlag:function (b) {
         return _.find(b.flags,{"fieldName":"fixed"});
     },
-    getGLJPrice:function (glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,isRadio,_,scMathUtil,tenderCoe) {
+    getGLJPrice:function (glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,isRadio,_,scMathUtil,tenderCoe, isReport) {
         let result = {};
-        result.marketPrice = this.getMarketPrice(glj,projectGLJDatas,calcOptions,decimalObj,isRadio,_,scMathUtil);
-        result.tenderPrice = this.getMarketPrice(glj,projectGLJDatas,calcOptions,decimalObj,isRadio,_,scMathUtil,tenderCoe);
+        if(isReport){
+            result.marketPrice = this.getMarketPrice(glj,projectGLJDatas,calcOptions,decimalObj,isRadio,_,scMathUtil,tenderCoe);
+        }else {
+            result.marketPrice = this.getMarketPrice(glj,projectGLJDatas,calcOptions,decimalObj,isRadio,_,scMathUtil);
+            result.tenderPrice = this.getMarketPrice(glj,projectGLJDatas,calcOptions,decimalObj,isRadio,_,scMathUtil,tenderCoe);
+        }
         if(this.calcPriceDiff(glj,calcOptions)==true){//计取价差
             result.basePrice = this.getBasePrice(glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,isRadio,_,scMathUtil);
             result.adjustPrice = this.getAdjustPrice(glj,projectGLJDatas,calcOptions,labourCoeDatas,decimalObj,isRadio,_,scMathUtil);
@@ -322,6 +332,8 @@ let gljUtil = {
             quantity = (quantity == 0 || quantity == undefined || quantity == null || quantity == "") ? 0 : quantity;
             quantity = scMathUtil.roundForObj(quantity, rd);//计算前进行4舍5入
             glj.quantity = scMathUtil.roundForObj(glj.quantity, gd);
+            glj.tenderQuantity = this.getRationGLJTenderQuantity(glj, ration, gd, scMathUtil);
+
             return scMathUtil.roundToString(quantity * glj.quantity, gd);
         }
     },
@@ -557,6 +569,19 @@ let gljUtil = {
 
         return datas;
     },
+    getTenderPriceCoe : function(glj,tproperty){
+        let tenderCoe = 1;
+        let property = tproperty?tproperty:projectObj.project.property;
+        if (!glj.is_adjust_price&&property.tenderSetting && isDef(property.tenderSetting.gljPriceTenderCoe) ){
+            tenderCoe = parseFloat(property.tenderSetting.gljPriceTenderCoe);
+        }
+        return tenderCoe;
+
+        function isDef (v) {
+            return v !== undefined && v !== null;
+        }
+    },
+
     fixedFlag : {
         // 分部分项工程
         SUB_ENGINERRING: 1,

+ 21 - 6
public/web/sheet/sheet_common.js

@@ -19,8 +19,12 @@ var sheetCommonObj = {
     },
 
     initSheet: function(sheet, setting, rowCount) {
+
         var me = this;
         var spreadNS = GC.Spread.Sheets;
+        if(setting.headRows == 2){
+            return me.buildSpanHeader(sheet, setting, rowCount);//初始化合并表格列头
+        }
         sheet.suspendPaint();
         sheet.suspendEvent();
         if(setting.frozenCols)  sheet.frozenColumnCount(setting.frozenCols);//冻结列s
@@ -46,10 +50,6 @@ var sheetCommonObj = {
         sheet.showRowOutline(false);
         sheet.options.allowCellOverflow = false;
         me.buildHeader(sheet, setting);
-        if (rowCount > 0)
-            sheet.setRowCount(rowCount);
-        else
-            sheet.setRowCount(1);
         sheet.resumeEvent();
         sheet.resumePaint();
     },
@@ -63,6 +63,21 @@ var sheetCommonObj = {
         return spreadBook;
     },
 
+    buildSpanHeader:function (sheet, setting, rowCount) {
+        let temSetting = {
+            "emptyRows":0,
+            "headRows":2,
+            "headRowHeight":[21],
+            "defaultRowHeight": 21,
+            "treeCol": 0,
+            "cols":[]
+        };
+        let spanSetting =   sheetCommonObj.transferToTreeSetting(setting,temSetting);
+        TREE_SHEET_HELPER.loadSheetHeader(spanSetting,sheet,rowCount);
+
+    },
+
+
     buildHeader: function(sheet, setting){
         var me = this, ch = GC.Spread.Sheets.SheetArea.colHeader;
         for (var i = 0; i < setting.header.length; i++) {
@@ -177,7 +192,7 @@ var sheetCommonObj = {
                     if(setting.header[col].hasOwnProperty('decimalField')){
                         let decimal = getDecimal(setting.header[col].decimalField);
                         val =scMathUtil.roundToString(val,decimal);
-                        sheet.setFormatter(row, col,getFormatter(decimal), GC.Spread.Sheets.SheetArea.viewport);
+                        sheet.setFormatter(-1, col,getFormatter(decimal), GC.Spread.Sheets.SheetArea.viewport);
                     }else {
                         val =scMathUtil.roundToString(val,2);
                     }
@@ -275,7 +290,7 @@ var sheetCommonObj = {
             if (setting.header[col].formatter) {
                 sheet.setFormatter(-1, col, setting.header[col].formatter, GC.Spread.Sheets.SheetArea.viewport);
             }
-            if(setting.header[col].cellType === "checkBox"||setting.header[col].cellType === "button"){//clear and reset
+            if(setting.headRows != 2 &&  setting.header[col].cellType === "checkBox"||setting.header[col].cellType === "button"){//clear and reset   2019 - 11- 11 加入了多行列头的判断情况,排除多行列头时清空操作,先试运行看是否有问题
                 var me = this, header = GC.Spread.Sheets.SheetArea.colHeader;
                 sheet.deleteColumns(col,1);
                 sheet.addColumns(col, 1);

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

@@ -76,7 +76,7 @@
                 <li class="nav-item"><a data-toggle="tab" href="#fee_rates" id="tab_fee_rate" role="tab" >费率</a></li>
                 <li class="nav-item"><a data-toggle="tab" href="#calc_program_manage" id="tab_calc_program_manage" role="tab" style="display:none">总计算程序</a></li>
                 <!--<li class="nav-item"><a data-toggle="tab" href="#tender_price" id="tab_tender_price" role="tab" style="display:none">调价</a></li>-->
-              <!--  <li class="nav-item"><a data-toggle="tab" href="#tender_price" id="tab_tender_price" role="tab">调价</a></li>-->
+                <li class="nav-item"><a data-toggle="tab" href="#tender_price" id="tab_tender_price" role="tab">调价</a></li>
                 <li class="nav-item"><a data-toggle="tab" href="#reports" role="tab" id="tab_report" onclick="rptTplObj.iniPage();">报表</a></li>
                 <li class="nav-item"><a data-toggle="tab" href="#index" id="tab_index" role="tab" style="display:none">指标信息</a></li>
             </ul>

+ 6 - 0
web/building_saas/main/html/tender_price.html

@@ -20,6 +20,12 @@
             <button type="button" class="btn btn-outline-primary btn-sm" id = "tenderPrice">调价计算</button>
         </div>
         <button type="button" class="btn btn-outline-danger btn-sm" id = "cleanTender">清空调价</button>
+        <div class="form-check" style="margin-left:40px; margin-top:5px;">
+            <label class="form-check-label">
+                <input class="form-check-input" name="cbShowTenderFields" id="cbShowTenderFields" value="true" type="checkbox">
+                显示调价后数据(造价书人材机界面、人材机汇总界面)
+            </label>
+        </div>
     </div>
 </div>
 <div class="container-fluid">

+ 163 - 24
web/building_saas/main/js/models/calc_program.js

@@ -111,11 +111,14 @@ let calcTools = {
             treeNode.source.children &&
             treeNode.source.children.length > 0;
     },
-    isLeafBill: function(treeNode){
+    isLeafBill: function(treeNode){      // 下面挂有定额的清单也是叶子清单
         return this.isBill(treeNode) &&
             treeNode.source.children &&
             treeNode.source.children.length === 0;
     },
+    isLeafNode: function(treeNode){      // 最底层结点,如定额等。
+        return treeNode.children.length === 0;
+    },
     isBill_DXFY: function(treeNode){
         return this.isBill(treeNode) && treeNode.data.type == billType.DXFY;
     },
@@ -841,8 +844,20 @@ let calcTools = {
         if (this.isBill(treeNode))                 // 清单只有一个工程量,没有调整后工程量。
             return this.uiNodeQty(treeNode)
         else{
-            let qCoe = (treeNode.data.rationQuantityCoe == undefined || treeNode.data.rationQuantityCoe == null ||
-                treeNode.data.rationQuantityCoe == 0) ? 1 : treeNode.data.rationQuantityCoe;
+            let qCoe = 1;
+            /* 量价、工料机类型的定额,在反向调价之调整人材机消耗量系数时,因为他们没有工料机可调,调价结果没变,影响汇总后的父结点金额。
+            所以要特殊处理:此种情况下仍然要调量价的消耗量,即还是要像"子目工程量调整系数"方式那样调,但系数又不能在"子目工程量调整系数"
+            中显示出来,所以可以改变tenderQuantity达到同样的效果以瞒天过海。所以在取系数时,无论什么系数,只要能取到就算正确。 */
+            if (treeNode.data.type == rationType.volumePrice || treeNode.data.type == rationType.gljRation){
+                if (treeNode.data.rationQuantityCoe)
+                    qCoe = treeNode.data.rationQuantityCoe
+                else if (treeNode.data.quantityCoe && treeNode.data.quantityCoe.labour)
+                    qCoe = treeNode.data.quantityCoe.labour;
+            }
+            else {
+                if (treeNode.data.rationQuantityCoe)
+                    qCoe = treeNode.data.rationQuantityCoe;
+            };
             treeNode.data.tenderQuantity = (this.uiNodeQty(treeNode) * qCoe).toDecimal(decimalObj.decimal("quantity", treeNode));
             return treeNode.data.tenderQuantity;
         }
@@ -907,6 +922,12 @@ let calcTools = {
             return parseFloat(quantity).toDecimal(decimalObj.glj.quantity)
         else return 0;
     },
+    hasTargetTotalFee: function (treeNode){    // targetTotalFee 有时为字符串“0”,此种情况会执行if 条件引起逻辑错误。所以这里封闭成方法直接调用。
+        return (treeNode.data.targetTotalFee && parseFloat(treeNode.data.targetTotalFee));
+    },
+    hasQuantity: function (treeNode){
+        return (treeNode.data.quantity && parseFloat(treeNode.data.quantity));
+    },
     
     getRationsByProjectGLJ(PGLJID){
         let rationIDs = [];
@@ -1882,7 +1903,7 @@ class CalcProgram {
                     if (treeNode.data.marketTotalFee != mtf){
                         treeNode.data.marketTotalFee = mtf;
                         treeNode.changed = true;
-                    } ;
+                    };
                 };
             };
             // 2018-08-27   zhang  插入空定额的时候,取费专业也为空
@@ -1932,7 +1953,6 @@ class CalcProgram {
 
         if (treeNode.changed && !changedArr.includes(treeNode)) changedArr.push(treeNode);
     };
-
     // 存储、刷新零散的多个结点。
     saveNodes(treeNodes, callback){
         if (treeNodes.length < 1) {
@@ -1943,15 +1963,6 @@ class CalcProgram {
         }
 
         let me = this;
-        /*        me.project.beginUpdate('');
-                for (let node of treeNodes){
-                    if (node.changed){
-                        let data = calcTools.cutNodeForSave(node);
-                        let newData = {'updateType': 'ut_update', 'updateData': data};
-                        me.project.push(node.sourceType, [newData]);
-                    }
-                };
-                me.project.endUpdate();*/
 
         let dataArr = [];
         for (let node of treeNodes){
@@ -1976,7 +1987,7 @@ class CalcProgram {
                 callback(data);
             };
 
-            for (let node of treeNodes){delete node.changed};
+            for (let node of treeNodes) { delete node.changed };
             projectObj.mainController.refreshTreeNode(treeNodes);
 
             // 批量树结点计算后,计算程序早已物是人非,所以这里要重新计算一下。警告:第二个参数千万不能改成3,否则死循环!
@@ -1985,8 +1996,7 @@ class CalcProgram {
             $.bootstrapLoading.end();
         });
     };
-
-    // 计算本节点、所有父节点(默认,可选)、公式引用节点(默认,可选)。
+    // 计算本节点及所有会被影响到的节点,如:所有父节点(默认,可选)、公式引用节点(默认,可选)。修改一个树节点,实际上要计算和保存的是一批树结点:层层父结点、被其它结点(的公式)引用的公式结点。
     calculate(treeNode, calcParents = true, calcFormulas = true, tender){
         let me = this;
         let changedNodes = [];
@@ -2008,7 +2018,7 @@ class CalcProgram {
 
         return changedNodes;
     };
-    // 计算并保存一个树节点。(修改一个树节点,实际上要计算和保存的是一批树结点:层层父结点、被其它结点(的公式)引用的公式结点)
+    // 计算并保存本节点及所有会被影响到的节点。
     calcAndSave(treeNode, callback, tender){
         let changedNodes = this.calculate(treeNode, true, true, tender);
         this.saveNodes(changedNodes, callback);
@@ -2019,6 +2029,8 @@ class CalcProgram {
         calcAllType.catBills     计算所有清单 (改变项目属性中清单取费算法时会用到)
         calcAllType.catRations   计算所有定额、工料机形式的定额、量价,因为它们都走自己的计算程序 (改变人工系数、费率值、工料机单价时会用到)
                                  (calcAllType.catRations时程序中做了特殊处理,实际上是计算所有树结点!)
+        调价相关参数:
+        tender:                 null:不调价(普通计算)。 1: 正向调价   2:反向调价-调子目    3: 反向调价-调工料机
     */
     calcAllNodes(calcType = calcAllType.catAll, tender){
         let me = this;
@@ -2042,6 +2054,13 @@ class CalcProgram {
 
         calcNodes(me.project.mainTree.roots);
         me.calcFormulaNodes(changedNodes, tender);
+
+        if (tender){    // 普通计算不执行,只有3种调价计算才清。
+            for(let node of projectObj.project.mainTree.items){
+                this.clearTenderCache(node);
+            };
+        };
+
         return changedNodes;
     };
     // tender: null:不调价(普通计算)。 1: 正向调价   2:反向调价-调子目    3: 反向调价-调工料机
@@ -2170,7 +2189,7 @@ class CalcProgram {
                 treeNode.data.targetTotalFee = (treeNode.data.targetUnitFee * treeNode.data.quantity).toDecimal(decimalObj.decimal('totalPrice', treeNode));
                 treeNode.changed = true;
             }
-            else{    // 既没有目标金额也没有目标单价,此时要初始化使调价合价=原始综合合价,调价单价=原始综合单价。(交叉调价后,旧值会留下来)
+            else{    // 既没有目标金额也没有目标单价,此时要初始化使调价合价=原始综合合价,调价单价=原始综合单价。
                 if (treeNode.data.feesIndex.common.tenderUnitFee != treeNode.data.feesIndex.common.unitFee) {
                     treeNode.data.feesIndex.common.tenderUnitFee = treeNode.data.feesIndex.common.unitFee;
                     treeNode.changed = true;
@@ -2183,11 +2202,13 @@ class CalcProgram {
             }
         };
 
-        if (!treeNode.data.targetUnitFee)
-            treeNode.data.targetUnitFee = (treeNode.data.targetTotalFee / treeNode.data.quantity).toDecimal(decimalObj.decimal('unitPrice', treeNode));
+        if (!treeNode.data.targetUnitFee || (parseFloat(treeNode.data.targetUnitFee) == 0)){
+            if (calcTools.hasQuantity(treeNode))
+                treeNode.data.targetUnitFee = (treeNode.data.targetTotalFee / treeNode.data.quantity).toDecimal(decimalObj.decimal('unitPrice', treeNode));
+        }
+
         let coe = 1;
         if (treeNode.data.feesIndex.common.totalFee != 0)
-            // coe = (treeNode.data.targetTotalFee / treeNode.data.feesIndex.common.totalFee).toDecimal(decimalObj.process);
             coe = (treeNode.data.targetUnitFee / treeNode.data.feesIndex.common.unitFee).toDecimal(decimalObj.process);
 
         if (tender == tenderTypes.ttReverseRation){
@@ -2203,7 +2224,7 @@ class CalcProgram {
                 treeNode.changed = true;
             };
         }else if (tender == tenderTypes.ttReverseGLJ){
-            treeNode.data.tenderQuantity = treeNode.data.quantity;
+            //     treeNode.data.tenderQuantity = treeNode.data.quantity;   // 这句好像多余,因为调用calculate()时里面会重新计算tenderQuantity,有问题再放开AAAAA
             let qcObj = treeNode.data.quantityCoe;
             if (!qcObj || calcTools.isEmptyObject(qcObj)){
                 treeNode.data.quantityCoe = {labour: coe, material: coe, machine: coe, main: coe, equipment: coe};
@@ -2219,6 +2240,123 @@ class CalcProgram {
             projectObj.project.calcProgram.calculate(treeNode, false, false, tenderTypes.ttCalc);  // 再正向算
         };
     };
+
+    // 清理调价缓存数据
+    clearTenderCache(treeNode){
+        // 这些属性值为什么不定义在一个对象里?因为每次要判断对象是否存在,十分麻烦。不如直接写简单。分散书写,统一处理也很好用。
+        if (treeNode.data.tender_activeTotal) delete treeNode.data.tender_activeTotal;
+        if (treeNode.data.tender_activeTarget) delete treeNode.data.tender_activeTarget;
+        if (treeNode.data.tender_fullLoad) delete treeNode.data.tender_fullLoad;
+        if (treeNode.data.tender_distribute){
+            delete treeNode.data.targetTotalFee;
+            delete treeNode.data.targetUnitFee;
+            delete treeNode.data.tender_distribute;
+        };
+    };
+
+    // 调价:分摊前的准备工作。主要标记满载的结点。
+    prepareForDistribute(treeNode){
+        if (!treeNode) return;
+
+        if (treeNode.firstChild())
+            this.prepareForDistribute(treeNode.firstChild());
+
+        if (treeNode.children.length == 0){
+            // if (!treeNode.data.feesIndex['common'])
+            //     treeNode.data.tender_fullLoad = true
+            // else
+            //     treeNode.data.tender_fullLoad = false;
+        }
+        else{
+            let full = true;
+            for (let i = 0; i < treeNode.children.length; i++) {
+                let child = treeNode.children[i];
+                if (!child.data.tender_fullLoad && !calcTools.hasTargetTotalFee(child)){
+                    full = false;
+                    break;
+                };
+            }
+            if (full) {
+                let total = 0, target = 0;
+                for (let i = 0; i < treeNode.children.length; i++) {
+                    let child = treeNode.children[i];
+                    total = total + parseFloat(child.data.feesIndex['common'].totalFee);
+                    target = target + parseFloat(child.data.targetTotalFee);
+                };
+                treeNode.data.tender_activeTotal = total;
+                treeNode.data.tender_activeTarget = target;
+                treeNode.data.targetTotalFee = target;
+                treeNode.data.tender_distribute = 2;
+            };
+
+            treeNode.data.tender_fullLoad = full;
+        };
+
+        /*if (calcTools.isBill(treeNode) && (treeNode.data.tender_fullLoad != undefined)){
+            console.log(treeNode.data.name + ',tender_fullLoad: ' + treeNode.data.tender_fullLoad + ', target: ' + calcTools.hasTargetTotalFee(treeNode));
+        };*/
+
+/*        if (calcTools.isRationItem(treeNode)){
+            console.log(treeNode.data);
+        }*/
+
+        if (treeNode.nextSibling)
+            this.prepareForDistribute(treeNode.nextSibling);
+    };
+
+
+    // 调价之分摊目标合价:从父到子往下分摊。
+    distributeTargetTotalFee(treeNode){
+        if (!treeNode) return;
+
+        if (treeNode.data.feesIndex['common']){     // 空清单忽略
+            // 默认能够执行到这里时每个节点已经被初始化,缓存已删除
+            treeNode.data.tender_activeTotal = treeNode.data.feesIndex['common'].totalFee;
+
+            // 开始分摊:只分摊自有目标金额、从父结点分摊到的金额(不分摊子结点摊上来的金额)
+            if (calcTools.hasTargetTotalFee(treeNode) && !(treeNode.data.tender_distribute && treeNode.data.tender_distribute == 2)){
+                treeNode.data.tender_activeTarget = treeNode.data.targetTotalFee;
+
+                // 先把会破坏金额比例关系的孩子排除:1.有目标金额的 2.满载的(孙子全满,没有分摊空间,所以实质上该孩子的金额已被锁死无法分摊)
+                for (let i = 0; i < treeNode.children.length; i++) {
+                    let child = treeNode.children[i];
+                    if (!child.data.feesIndex['common']) continue;     // 无计算金额的(如空清单)当它不存在
+
+                    child.data.tender_activeTotal = child.data.feesIndex['common'].totalFee;
+
+                    if (calcTools.hasTargetTotalFee(child)){
+                        child.data.tender_activeTarget = child.data.targetTotalFee;
+                        console.log(treeNode.data.tender_activeTotal);
+                        console.log(child.data.tender_activeTotal);
+                        treeNode.data.tender_activeTotal = treeNode.data.tender_activeTotal - child.data.tender_activeTotal;
+                        treeNode.data.tender_activeTarget = treeNode.data.tender_activeTarget - child.data.tender_activeTarget;
+                    };
+                }
+
+                if (treeNode.data.tender_activeTotal != 0){
+                    let coe = (treeNode.data.tender_activeTarget / treeNode.data.tender_activeTotal).toDecimal(decimalObj.process);
+
+                    for (let i = 0; i < treeNode.children.length; i++) {
+                        let child = treeNode.children[i];
+                        if (!child.data.feesIndex['common']) continue;
+                        if (!calcTools.hasTargetTotalFee(child)){
+                            child.data.tender_activeTarget = (coe * child.data.tender_activeTotal).toDecimal(decimalObj.decimal('totalPrice', treeNode));
+                            child.data.targetTotalFee = child.data.tender_activeTarget;
+                            child.data.tender_distribute = 1;        // 1表示分摊金额来自父结点。2表示分摊金额来自孩子结点。
+                        }
+                    }
+                };
+
+            };
+        }
+
+        if (treeNode.firstChild())
+            this.distributeTargetTotalFee(treeNode.firstChild());
+
+        if (treeNode.nextSibling)
+            this.distributeTargetTotalFee(treeNode.nextSibling);
+    };
+
     setRationMap(){
         if(this.rationMap == null){
             this.rationMap = {};
@@ -2234,6 +2372,7 @@ class CalcProgram {
             this.pgljMap = _.indexBy(projectObj.project.projectGLJ.datas.gljList, 'id');
         }
     };
+
     getGljArrByRation(ration){
         if (ration.type == rationType.gljRation){
             let glj = JSON.parse(JSON.stringify(ration));
@@ -2248,7 +2387,7 @@ class CalcProgram {
             result = gljOprObj.combineWithProjectGlj(result,false,ration,this.pgljMap);
             return result;
         }
-    }
+    };
 };
 
 // export default analyzer;

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

@@ -869,12 +869,8 @@ ProjectGLJ.prototype.getTenderMarketPrice = function (glj,isRadio) {
     return gljUtil.getMarketPrice(glj,proGLJ.datas,calcOptions,decimalObj,isRadio,_,scMathUtil,tenderCoe);
 };
 
-ProjectGLJ.prototype.getTenderPriceCoe = function(glj){
-    let tenderCoe = 1;
-    if (!glj.is_adjust_price&&projectObj.project.property.tenderSetting && gljUtil.isDef(projectObj.project.property.tenderSetting.gljPriceTenderCoe) ){
-        tenderCoe = parseFloat(projectObj.project.property.tenderSetting.gljPriceTenderCoe);
-    }
-    return tenderCoe
+ProjectGLJ.prototype.getTenderPriceCoe = function(glj,tproperty){
+    return gljUtil.getTenderPriceCoe(glj,tproperty);
 };
 
 ProjectGLJ.prototype.isEstimateType = function(type){

+ 65 - 30
web/building_saas/main/js/views/glj_col.js

@@ -15,10 +15,13 @@ let gljCol = {
             {headerName: "定额价", headerWidth: 65, dataCode: "basePrice", dataType: "Number", hAlign: "right"},//, decimalField: "glj.unitPrice"
             {headerName: "定额消耗", headerWidth: 65, dataCode: "rationItemQuantity", dataType: "Number", hAlign: "right", decimalField: "glj.quantity"},   // dataType: "Number", formatter: "0.00"
             {headerName: "总消耗量", headerWidth: 80, dataCode: "totalQuantity", dataType: "Number", hAlign: "right", decimalField: "glj.quantity"},
-            {headerName: "暂估", headerWidth: 45, dataCode: "isEstimate", dataType: "String", hAlign: "center", vAlign: "center", cellType: "checkBox"}
+            {headerName: "暂估", headerWidth: 45, dataCode: "isEstimate", dataType: "String", hAlign: "center", vAlign: "center", cellType: "checkBox"},
+            {headerName: "调后市场价", headerWidth: 80, dataCode: "tenderPrice", dataType: "Number", hAlign: "right", visible: false},
+            {headerName: "调后消耗量", headerWidth: 80, dataCode: "tenderQuantity", dataType: "Number", hAlign: "right", visible: false}
         ],
         view: {
-            lockColumns: [ "adjustPrice", "rationItemQuantity", "quantity", "totalQuantity", "isEstimate"],//这里以后改成dataCode好一点
+            lockColumns: [ "adjustPrice", "rationItemQuantity", "quantity", "totalQuantity", "isEstimate",
+                "tenderPrice", "tenderQuantity"],//这里以后改成dataCode好一点
             rowHeaderWidth:25
         },
         getStyle:function (data) {
@@ -33,36 +36,39 @@ let gljCol = {
     },
     project_glj_setting:{
         header: [
-            {headerName: "编码", headerWidth: 80, dataCode: "code", dataType: "String"},
-            {headerName: "名称", headerWidth: 160, dataCode: "name", dataType: "String",cellType:'tipsCell'},
-            {headerName: "规格型号", headerWidth: 120, dataCode: "specs", hAlign: "left", dataType: "String",cellType:'tipsCell'},
-            {headerName: "单位", headerWidth: 45, dataCode: "unit", hAlign: "center", dataType: "String"},
-            {headerName: "类型", headerWidth: 45, dataCode: "short_name", hAlign: "center", dataType: "String"},
-            {headerName: "市场价", headerWidth: 70, dataCode: "marketPrice", hAlign: "right", dataType: "Number",validator:"number"},//,decimalField:"glj.unitPrice"
-            {headerName: "调整价", headerWidth: 70, dataCode: "adjustPrice", hAlign: "right", dataType: "Number"},//,decimalField:"glj.unitPrice"
-            {headerName: "定额价", headerWidth: 70, dataCode: "basePrice", hAlign: "right", dataType: "Number",validator:"number"},//decimalField:'glj.unitPrice',
-            {headerName: "总消耗量", headerWidth: 90, dataCode: "quantity", hAlign: "right", dataType: "Number",decimalField:'glj.quantity'},
-            {headerName: "暂估", headerWidth: 45, dataCode: "is_evaluate", hAlign: "center", dataType: "String",cellType:'checkBox'},
-            {headerName: "主要\n材料", headerWidth: 45, dataCode: "is_main_material", hAlign: "center", dataType: "String",cellType:'checkBox'},
-            {headerName: "不调价", headerWidth: 55, dataCode: "is_adjust_price", dataType: "String",cellType: "checkBox"},
-            {headerName: "不计税设备", headerWidth: 55, dataCode: "no_tax_eqp", dataType: "String",cellType: "checkBox"},
-            {headerName: "评标材料", headerWidth: 35, dataCode: "is_eval_material", dataType: "String",cellType: "checkBox"},
-            {headerName: "供货方式", headerWidth: 70, dataCode: "supply", hAlign: "center", dataType: "String",cellType:'comboBox',editorValueType:true,options:supplyComboMap},
-            {headerName: "甲供数量", headerWidth: 90, dataCode: "supply_quantity", hAlign: "right", dataType: "Number",validator:"number",decimalField:'glj.quantity'},
-            {headerName: "三材类别", headerWidth: 70, dataCode: "materialType", hAlign: "center", dataType: "String",cellType:'comboBox',editorValueType:true,options:materialComboMap},
-            {headerName: "三材系数", headerWidth: 70, dataCode: "materialCoe", hAlign: "right", dataType: "Number",validator:"number"},//,decimalField:'material'
-            {headerName: "交货方式", headerWidth: 70, dataCode: "delivery", hAlign: "left", dataType: "String"},
-            {headerName: "送达地点", headerWidth: 70, dataCode: "delivery_address", hAlign: "left", dataType: "String"},
-            {headerName: "产地", headerWidth: 80, dataCode: "originPlace", hAlign: "left", dataType: "String"},
-            {headerName: "厂家", headerWidth: 80, dataCode: "vender", hAlign: "left", dataType: "String"},
-            {headerName: "质量等级", headerWidth: 80, dataCode: "qualityGrace", hAlign: "left", dataType: "String"},
-            {headerName: "品牌", headerWidth: 80, dataCode: "brand", hAlign: "left", dataType: "String"},
-            {headerName: "备注", headerWidth: 100, dataCode: "remark", hAlign: "left", dataType: "String"}
+            {headerName: "编码", headerWidth: 80, dataCode: "code", dataType: "String",spanRows: [2]},
+            {headerName: "名称", headerWidth: 160, dataCode: "name", dataType: "String",cellType:'tipsCell',spanRows: [2]},
+            {headerName: "规格型号", headerWidth: 120, dataCode: "specs", hAlign: "left", dataType: "String",cellType:'tipsCell',spanRows: [2]},
+            {headerName: "单位", headerWidth: 45, dataCode: "unit", hAlign: "center", dataType: "String",spanRows: [2]},
+            {headerName: "类型", headerWidth: 45, dataCode: "short_name", hAlign: "center", dataType: "String",spanRows: [2]},
+            {headerName: "市场价", headerWidth: 70, dataCode: "marketPrice", hAlign: "right", dataType: "Number",validator:"number",spanRows: [2]},//,decimalField:"glj.unitPrice"
+            {headerName: "调整价", headerWidth: 70, dataCode: "adjustPrice", hAlign: "right", dataType: "Number",spanRows: [2]},//,decimalField:"glj.unitPrice"
+            {headerName: "定额价", headerWidth: 70, dataCode: "basePrice", hAlign: "right", dataType: "Number",validator:"number",spanRows: [2]},//decimalField:'glj.unitPrice',
+            {headerName: "总消耗量", headerWidth: 90, dataCode: "quantity", hAlign: "right", dataType: "Number",decimalField:'glj.quantity',spanRows: [2]},
+            {headerName: "暂估", headerWidth: 45, dataCode: "is_evaluate", hAlign: "center", dataType: "String",cellType:'checkBox',spanRows: [2]},
+            {headerName: "主要\n材料", headerWidth: 45, dataCode: "is_main_material", hAlign: "center", dataType: "String",cellType:'checkBox',spanRows: [2]},
+            {headerName: "不计税设备", headerWidth: 55, dataCode: "no_tax_eqp", dataType: "String",cellType: "checkBox",spanRows: [2]},
+            {headerName: "评标材料", headerWidth: 35, dataCode: "is_eval_material", dataType: "String",cellType: "checkBox",spanRows: [2]},
+            {headerName: "供货方式", headerWidth: 70, dataCode: "supply", hAlign: "center", dataType: "String",cellType:'comboBox',editorValueType:true,options:supplyComboMap,spanRows: [2]},
+            {headerName: "甲供数量", headerWidth: 90, dataCode: "supply_quantity", hAlign: "right", dataType: "Number",validator:"number",decimalField:'glj.quantity',spanRows: [2]},
+            {headerName: "三材类别", headerWidth: 70, dataCode: "materialType", hAlign: "center", dataType: "String",cellType:'comboBox',editorValueType:true,options:materialComboMap,spanRows: [2]},
+            {headerName: "三材系数", headerWidth: 70, dataCode: "materialCoe", hAlign: "right", dataType: "Number",validator:"number",spanRows: [2]},//,decimalField:'material'
+            {headerName: "交货方式", headerWidth: 70, dataCode: "delivery", hAlign: "left", dataType: "String",spanRows: [2]},
+            {headerName: "送达地点", headerWidth: 70, dataCode: "delivery_address", hAlign: "left", dataType: "String",spanRows: [2]},
+            {headerName: "产地", headerWidth: 80, dataCode: "originPlace", hAlign: "left", dataType: "String",spanRows: [2]},
+            {headerName: "厂家", headerWidth: 80, dataCode: "vender", hAlign: "left", dataType: "String",spanRows: [2]},
+            {headerName: "质量等级", headerWidth: 80, dataCode: "qualityGrace", hAlign: "left", dataType: "String",spanRows: [2]},
+            {headerName: "品牌", headerWidth: 80, dataCode: "brand", hAlign: "left", dataType: "String",spanRows: [2]},
+            {headerName: "备注", headerWidth: 100, dataCode: "remark", hAlign: "left", dataType: "String",spanRows: [2]},
+            {headerName: "不调价", headerWidth: 55, dataCode: "is_adjust_price", dataType: "String",cellType: "checkBox",spanRows: [2]},
+            {headerName: ["调价后","市场价"], headerWidth: 75, dataCode: "tenderPrice", hAlign: "right", dataType: "Number",validator:"number",spanCols: [2,1], visible: false},
+            {headerName: ["","总消耗量"], headerWidth: 90, dataCode: "tenderQuantity", hAlign: "right", dataType: "Number",decimalField:'glj.quantity',spanCols: [0,1], visible: false}
         ],
         view: {
             lockColumns: ["code","name","specs","unit","short_name","tenderPrice","adjustPrice","quantity","tenderQuantity"]
         },
-        frozenCols:4
+        frozenCols:4,
+        headRows:2
     },
     mixRatio_Setting:{
         header:[
@@ -232,19 +238,48 @@ let gljCol = {
             setting.view.lockColumns = newArray;
         }
     },
-    initGljCol:function (showAdjustPrice) {
+    initGljCol:function (showAdjustPrice, showTenderFields) {
         let me = gljCol;
         if(showAdjustPrice !== true){
             me.removeCol('adjustPrice',me.ration_glj_setting);
             me.removeCol('adjustPrice',me.project_glj_setting);
             me.removeCol('adjustPrice',me.mixRatio_Setting);
-        }
+        };
+        me.showTenderFields(showTenderFields, false);
+
         gljOprObj.setting = me.ration_glj_setting;
         projectGljObject.projectGljSetting = me.project_glj_setting;
         projectGljObject.mixRatioSetting = me.mixRatio_Setting;
         me.setScopeFormater();
         gljOprObj.scopeSetting = me.scopeSetting;
     },
+    showTenderFields: function (showFields = false, needRefresh = false){
+        let me = gljCol;
+
+        let PGLJHeader = me.project_glj_setting.header;
+        for (let e of PGLJHeader){
+            if (e.dataCode == 'tenderPrice' || e.dataCode == 'tenderQuantity'){
+                e.visible = showFields;
+            }
+        };
+
+        let RGLJHeader = me.ration_glj_setting.header;
+        for (let e of RGLJHeader){
+            if (e.dataCode == 'tenderPrice' || e.dataCode == 'tenderQuantity'){
+                e.visible = showFields;
+            }
+        };
+
+        if (needRefresh){
+            if(projectGljObject.projectGljSpread) {
+                projectGljObject.projectGljSheet = projectGljObject.projectGljSpread .getSheet(0);
+                projectGljObject.initSheet(projectGljObject.projectGljSheet, projectGljObject.projectGljSetting);
+            }
+            if (subSpread) {
+                gljOprObj.initSheet(subSpread.getSheet(0), false);
+            }
+        };
+    },
     setScopeFormater:function () {
         // 综合单价、综合合价,小数部分应补0对齐。  CSL
         for(let col of this.scopeSetting.cols){

+ 1 - 1
web/building_saas/main/js/views/project_glj_view.js

@@ -80,7 +80,7 @@ let projectGljObject={
         this.projectGljSheet.bind(GC.Spread.Sheets.Events.SelectionChanged,this.onProjectGljSelectionChange);
         this.projectGljSheet.bind(GC.Spread.Sheets.Events.EditStarting,this.onProjectGljEditStarting);
         this.projectGljSheet.name('projectGljSheet');
-        this.projectGljSheet.setRowHeight(0, 36, 1);
+        //this.projectGljSheet.setRowHeight(0, 36, 1);
     },
     initMixRatio:function () {
         let me = projectGljObject;

+ 61 - 28
web/building_saas/main/js/views/tender_price_view.js

@@ -48,7 +48,7 @@ let tender_obj={
         this.tenderSheet = this.tenderSpread.getSheet(0);
         this.tenderTree = cacheTree.createNew(this);
         this.tenderTreeSetting = this.createTenderTreeSetting();
-        console.log(this.tenderTreeSetting);
+        // console.log(this.tenderTreeSetting);
         TREE_SHEET_HELPER.initSetting($('#tenderSpread')[0], this.tenderTreeSetting );
         this.tenderTreeSetting.setAutoFitRow = MainTreeCol.getEvent("setAutoFitRow");
         this.tenderController = TREE_SHEET_CONTROLLER.createNew(this.tenderTree, this.tenderSheet, this.tenderTreeSetting);
@@ -176,11 +176,18 @@ let tender_obj={
         //在目标造价综合单价中输入数值,按项目属性中的清单单价精度取舍,并清空当前行的目标造价综合合价
         if(dataCode == 'targetUnitFee'){
             value = scMathUtil.roundForObj(value,getDecimal('unitPrice',node));
-            updateData?updateData.data["targetTotalFee"] = null:'';
+	    // updateData?updateData.data["targetTotalFee"] = null:'';
+            updateData?updateData.data["targetTotalFee"] = (value * node.data.quantity).toDecimal(decimalObj.decimal('totalPrice', node)):'';
         }
         if(dataCode == 'targetTotalFee'){
             value = scMathUtil.roundForObj(value,getDecimal('totalPrice',node));
-            updateData?updateData.data["targetUnitFee"] = null:'';
+            // updateData?updateData.data["targetUnitFee"] = null:'';
+            let rst = '';
+            if (updateData){
+                if (calcTools.hasQuantity(node))
+                   rst = (value / node.data.quantity).toDecimal(decimalObj.decimal('unitPrice', node));
+            };
+            updateData.data["targetUnitFee"] = rst;
         }
         updateData.data[dataCode] = value;
         updateNodes.push(updateData);
@@ -207,10 +214,10 @@ let tender_obj={
     },
     onEnterCell : function (sender,args) {
         let me = tender_obj, row = args.row, col = args.col;
-        if ([8, 9].includes(col)){
+        if ([7, 8].includes(col)){                                  // 目标单价、目标合价
             let node = me.tenderTree.items[row];
-            if (node.children && node.children.length > 0) {   // 父结点只读
-                me.tenderSheet.getCell(row, col).locked(true);// = true;
+            if (calcTools.isCalcBaseBill(node)){                    // 公式结点只读
+                me.tenderSheet.getCell(row, col).locked(true);
             }
         }
     },
@@ -255,26 +262,14 @@ let tender_obj={
             }
         }
     },
-    cleanCacheCoes: function (){
-        for(let node of tender_obj.tenderTree.items){
-            if (node.data.rationQuantityCoe) node.data.rationQuantityCoe = null;
-            let qcObj = node.data.quantityCoe;
-            if (qcObj){
-                for (let pn in qcObj){
-                    qcObj[pn] = null;
-                };
-            };
-        };
-    },
-
     calcOptionsChecking:function (option) {//调整选项检查,返回需要更新的数组
         let datas = [];
         let me = tender_obj;
         for(let node of me.tenderTree.items){
             let tem_updateData = {type:node.sourceType,data:{}};
-            if(option == 'coeBase') { //当值为“根据调整系数计算报价”时,清空目标报价。
+            if(option == 'coeBase') {                           // 正向:当值为“根据调整系数计算报价”时,清空目标报价。
                 me.cleanTargetPrice(tem_updateData,node);
-            }else if(option == 'priceBase'){//当值为“根据报价计算调整系数”时,清空调整系数。
+            }else if(option == 'priceBase'){                    // 反向:当值为“根据报价计算调整系数”时,清空调整系数。
                 me.cleanTenderCoe(tem_updateData,node);
             }
             if(!_.isEmpty(tem_updateData.data)){//如果需要更新
@@ -398,28 +393,60 @@ let tender_obj={
         let tenderSetting = projectObj.project.property.tenderSetting;
         let calcPriceOption = tenderSetting && tenderSetting.calcPriceOption? tenderSetting.calcPriceOption :"coeBase";
         let gljPriceTenderCoe = tenderSetting && tenderSetting.gljPriceTenderCoe?tenderSetting.gljPriceTenderCoe:1;
+        let showTenderFields = tenderSetting && tenderSetting.showTenderFields?tenderSetting.showTenderFields:false;
         $('#calcPriceOption').val(calcPriceOption);
         $('#gljPriceTenderCoe').val(gljPriceTenderCoe);
         if(calcPriceOption == 'coeBase'){
-            if(!projectReadOnly){
-                $('#tenderPrice').removeAttr("disabled");
-            }
+            $('#gljPriceTenderCoe').removeAttr("disabled");
             $('#tenderGLJQuantity').attr("disabled",true);
             $('#tenderRationQuantity').attr("disabled",true);
+            if(!projectReadOnly){
+                $('#tenderPrice').removeAttr("disabled");
+            };
         }else {
-            $('#tenderPrice').attr("disabled",true);
+            $('#gljPriceTenderCoe').attr("disabled",true);
             $('#tenderGLJQuantity').removeAttr("disabled");
             $('#tenderRationQuantity').removeAttr("disabled");
-        }
-        //gljPriceTenderCoe
+            $('#tenderPrice').attr("disabled",true);
+        };
+        $('#cbShowTenderFields').prop("checked", showTenderFields);
     },
     doTenderCalc: function(tender){
-        if (tender != tenderTypes.ttCalc)
-            tender_obj.cleanCacheCoes();
+        function initReverseTenderDatas (){
+            for(let node of tender_obj.tenderTree.items){
+                if (node.data.rationQuantityCoe) node.data.rationQuantityCoe = null;
+                let qcObj = node.data.quantityCoe;
+                if (qcObj){
+                    for (let pn in qcObj){
+                        qcObj[pn] = null;
+                    };
+                };
+                projectObj.project.calcProgram.clearTenderCache(node);
+            };
+            // 反向调价时人材机单价调整系数要归1:因为既可以调量又可以调价,以哪个为基准进行反调?过于复杂,仅以通用的调量逻辑为基准即可满足需求。
+            if (projectObj.project.property.tenderSetting && projectObj.project.property.tenderSetting.gljPriceTenderCoe
+                && (projectObj.project.property.tenderSetting.gljPriceTenderCoe != 1)){
+                projectObj.project.property.tenderSetting.gljPriceTenderCoe = 1;    // 修改缓存值,用于计算
+                projectObj.project.property.needRestoreGgljPriceTenderCoe = true;   // 标记:需保存入库
+            }
+
+        };
+
+        if (tender != tenderTypes.ttCalc) initReverseTenderDatas();
         let callback = function () {
             projectObj.project.saveProperty('hasTender', true);
+            if (projectObj.project.property.needRestoreGgljPriceTenderCoe){         // 入库存储,清理标记,刷新UI显示
+                projectObj.project.saveProperty('tenderSetting.gljPriceTenderCoe', 1);
+                delete projectObj.project.property.needRestoreGgljPriceTenderCoe;
+                $('#gljPriceTenderCoe').val(1);
+            }
+
             tender_obj.showTenderData();
         };
+        if (tender == tenderTypes.ttReverseGLJ || tender == tenderTypes.ttReverseRation){
+            projectObj.project.calcProgram.prepareForDistribute(tender_obj.tenderTree.roots[0]);
+            projectObj.project.calcProgram.distributeTargetTotalFee(tender_obj.tenderTree.roots[0]);
+        };
         projectObj.project.calcProgram.calcAllNodesAndSave(calcAllType.catAll, callback, tender);
     }
 };
@@ -494,4 +521,10 @@ $(function () {
         tender_obj.doTenderCalc(tenderTypes.ttReverseRation);
     });
 
+    $('#cbShowTenderFields').on('click', function () {
+        let showFields = $('#cbShowTenderFields').prop("checked");
+        projectObj.project.saveProperty('tenderSetting.showTenderFields', showFields);
+        gljCol.showTenderFields(showFields, true);
+    });
+
 });

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

@@ -934,6 +934,7 @@
 <!-- JS. -->
 <script src = "/lib/spreadjs/sheets/gc.spread.sheets.all.11.1.2.min.js"></script>
 <script src = "/lib/fileSaver/FileSaver.min.js"></script>
+<script src="/lib/qiniu/qiniu.min.js"></script>
 <script>GC.Spread.Sheets.LicenseKey = '<%- LicenseKey %>';</script>
 <script src="/lib/x2js/xml2json.min.js"></script>
 <script type="text/javascript" src="/lib/jquery-ui/jquery-ui-datepickerCN.js"></script>

+ 74 - 49
web/building_saas/pm/js/pm_newMain.js

@@ -471,10 +471,10 @@ const projTreeObj = {
              return false
              },*/
             callback: function (key, opt) {
-                //获取当前节点的建设项目ID
-                $("#import").modal('show');
 
-                // projTreeObj.exportProject(projTreeObj.tree.selected.data.ID);
+                $("#confirm-import").hide();
+                $("#import").modal('show');
+                projTreeObj.getUploadToken();
             }
         }
     },
@@ -1671,8 +1671,14 @@ const projTreeObj = {
         return {parentProjectID: parent && parent.data ? parent.data.ID : -1,
                 preProjectID: pre && pre.data ? pre.data.ID : -1,
                 nextProjectID: next && next.data ? next.data.ID : -1};
+    },
+    getUploadToken:async function () {
+        let result =await ajaxGet("/pm/api/getUploadToken");
+        $("#confirm-import").show();
+        projTreeObj.uptoken=result.uptoken;
     }
 
+
 };
 // 新建项目必填项提示框设置“ 比如:注:为响应重庆地区指标采集标准数据要求,以上工程信息及特征必填项为必填项,请正确填写。”
 function setupRequiredWarn(compilation) {
@@ -4673,56 +4679,75 @@ $("#confirm-import").click(function() {
         return;
     }
     STATE.importing = true;
-    const self = $(this);
-    try {
-        let formData = new FormData();
-        let file = $("input[name='import_project_data']")[0];
-        if (file.files.length <= 0) {
-            throw '请选择文件!';
-        }
-        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',
-            data: formData,
-            cache: false,
-            contentType: false,
-            processData: false,
-            beforeSend: function() {
-                self.attr('disabled', 'disabled');
-                self.text('上传中...');
-            },
-            success: function(response){
-                STATE.importing = false;
-                self.text('确定导入');
-                $.bootstrapLoading.progressEnd();
-                if(response.error == 1){
-                    alert(response.msg);
-                    setTimeout(function () {
-                        $.bootstrapLoading.progressEnd();//不做这个的话太快,页面不会自动关闭
-                    },500)
-                }else {
-                    refreshAllPage();
-                }
 
+    let input = $("input[name='import_project_data']")[0];
+    if (input.files.length <= 0) {
+        throw '请选择文件!';
+    }
+    let token = projTreeObj.uptoken;
+    $('#import').modal("hide");
+    $.bootstrapLoading.progressStart("上传文件中",true);
+    let file = input.files[0];
+    let key = uuid.v1() + ".ybp"; //file.name;
+    if (file) {
+        let config = {
+            useCdnDomain: true,
+            disableStatisticsReport: false,
+            retryCount: 6,
+            region: qiniu.region.z2
+        };
+        let putExtra = {
+            fname: "",
+            params: {"x:name":key.split(".")[0]},
+            mimeType: null
+        };
+        // 添加上传dom面板
+        let observable = qiniu.upload(file, key, token, putExtra, config);
+        observable.subscribe({
+            next:function (reponse) {
+                console.log(reponse);
             },
-            error:  function(response){
-                STATE.importing = false;
-                setTimeout(function () {
-                    self.text('确定导入');
-                    $.bootstrapLoading.progressEnd();
-                    alert("导入失败,请检查文件!");
-                },1000)
+            error:function (err) {
+                console.log(err);
+            },
+            complete:function(res){
+                console.log("complete")
+                $("#progress_modal_body").text("正在导入建设项目");
+                startImportProject(key);
+                projTreeObj.uptoken = null;
             }
         });
-    } catch(error) {
-        STATE.importing = false;
-        alert(error);
-        $.bootstrapLoading.end();
+    }
+
+    async function  startImportProject(key) {
+        try {
+            console.log("start Import");
+            let result = await ajaxPost("/pm/api/importProject",{key:key,updateData:projTreeObj.getImportProjectDate()});
+            setTimeout(importProcessChecking,2000);
+        }catch (error){
+            alert(error);
+            $.bootstrapLoading.end();
+        }finally {
+            STATE.importing = false;
+        }
+    }
+
+    async function importProcessChecking() {
+        let result = await ajaxPost("/pm/api/importProcessChecking",{key:key,user_id:userID});
+        if(result.error == 1){
+            let message = result.msg?result.msg:result.message;
+            setTimeout(function () {
+                $.bootstrapLoading.progressEnd();//不做这个的话太快,页面不会自动关闭
+            },500);
+            alert(message)
+        }else if(result.error == 0){
+            if(result.status == "processing"){
+                setTimeout(importProcessChecking,2000);
+            }else if(result.status == "complete"){
+                $.bootstrapLoading.progressEnd();
+                refreshAllPage();
+            }
+        }
     }
 });