Browse Source

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

TonyKang 7 năm trước cách đây
mục cha
commit
8f275b58bd
32 tập tin đã thay đổi với 420 bổ sung129 xóa
  1. 2 1
      config/gulpConfig.js
  2. 2 2
      gulpfile.js
  3. 37 1
      modules/fee_rates/controllers/fee_rates_controller.js
  4. 3 1
      modules/fee_rates/facade/fee_rates_facade.js
  5. 2 0
      modules/fee_rates/routes/fee_rates_route.js
  6. 6 5
      modules/glj/models/glj_list_model.js
  7. 22 4
      modules/main/facade/labour_coe_facade.js
  8. 1 1
      modules/pm/models/project_model.js
  9. 18 8
      public/calc_util.js
  10. 1 1
      public/scMathUtil.js
  11. 82 0
      public/web/PerfectLoad.js
  12. 1 1
      public/web/scMathUtil.js
  13. 19 20
      public/web/sheet/sheet_common.js
  14. 2 2
      web/building_saas/glj/html/glj_index.html
  15. 6 6
      web/building_saas/main/html/calc_program_manage.html
  16. 13 8
      web/building_saas/main/js/controllers/project_controller.js
  17. 2 0
      web/building_saas/main/js/main.js
  18. 1 1
      web/building_saas/main/js/models/composition.js
  19. 99 13
      web/building_saas/main/js/models/fee_rate.js
  20. 1 1
      web/building_saas/main/js/models/labour_coe.js
  21. 16 1
      web/building_saas/main/js/models/main_consts.js
  22. 1 1
      web/building_saas/main/js/models/project.js
  23. 2 0
      web/building_saas/main/js/models/ration.js
  24. 14 12
      web/building_saas/main/js/views/calc_program_manage.js
  25. 11 9
      web/building_saas/main/js/views/calc_program_view.js
  26. 30 23
      web/building_saas/main/js/views/fee_rate_view.js
  27. 3 0
      web/building_saas/main/js/views/glj_view.js
  28. 3 0
      web/building_saas/main/js/views/main_tree_col.js
  29. 8 4
      web/building_saas/main/js/views/project_property_labour_coe_view.js
  30. 10 3
      web/building_saas/main/js/views/project_view.js
  31. 1 0
      web/building_saas/main/js/views/sub_fee_rate_views.js
  32. 1 0
      web/common/html/header.html

+ 2 - 1
config/gulpConfig.js

@@ -9,7 +9,8 @@ module.exports = {
         'lib/popper/popper.min.js',
         'lib/bootstrap/bootstrap.min.js',
         'web/building_saas/js/*.js',
-        'public/web/scMathUtil.js'
+        'public/web/scMathUtil.js',
+        'public/web/PerfectLoad.js'
     ],
     common_css:[
         'lib/bootstrap/css/bootstrap.min.css',

+ 2 - 2
gulpfile.js

@@ -81,7 +81,7 @@ function minify(options) {
     if(options.jspaths){
         return gulp.src(options.jspaths)
             .pipe($.plumber())
-           // .pipe(uglify())
+            .pipe(uglify())
             .pipe($.concat(options.concatName+"."+version+".js"))
             .pipe(gulp.dest(scriptsDest));
     }
@@ -110,7 +110,7 @@ function inject(options) {
 
 function htmlmin(options) {
     return gulp.src(options.htmlDest+'/*.html')
-    //  .pipe($.htmlmin({collapseWhitespace: true}))
+       // .pipe($.htmlmin({collapseWhitespace: true}))
         .pipe(gulp.dest(options.htmlDest));
 }
 

+ 37 - 1
modules/fee_rates/controllers/fee_rates_controller.js

@@ -55,7 +55,9 @@ module.exports = {
     changeFeeRateFileFromCurrent:changeFeeRateFileFromCurrent,
     changeFeeRateFileFromOthers:changeFeeRateFileFromOthers,
     setFeeRateToBill:setFeeRateToBill,
-    updateFeeRate:updateFeeRate
+    updateFeeRate:updateFeeRate,
+    updateRates:updateRates,
+    feeRateFileSaveAs:feeRateFileSaveAs
 }
 
 function libNames(req, res) {
@@ -211,3 +213,37 @@ async function updateFeeRate(req,res) {
     }
     res.json(result);
 }
+
+function updateRates(req,res){
+    let result={
+        error:0
+    }
+    let data = req.body.data;
+    data=JSON.parse(data);
+    feeRateFacde.updateRates(data.user_id,data)(function (err,re) {
+        if(err){
+            result.error=1;
+            result.message = err.message;
+        }else {
+            result.data = re;
+        }
+        res.json(result);
+    })
+}
+
+function feeRateFileSaveAs(req,res){
+    let result={
+        error:0
+    }
+    let data = req.body.data;
+    data=JSON.parse(data);
+    feeRateFacde.feeRateFileSaveAs(data.user_id,data)(function (err,re) {
+        if(err){
+            result.error=1;
+            result.message = err.message;
+        }else {
+            result.data = re;
+        }
+        res.json(result);
+    })
+}

+ 3 - 1
modules/fee_rates/facade/fee_rates_facade.js

@@ -29,7 +29,9 @@ module.exports={
     getFeeRatesByProject:getFeeRatesByProject,
     getGCFeeRateFiles: getGCFeeRateFiles ,
     setFeeRateToBill:setFeeRateToBill,
-    updateFeeRate:updateFeeRate
+    updateFeeRate:updateFeeRate,
+    updateRates:update_rates,
+    feeRateFileSaveAs:feeRateFileSaveAs
 };
 let operationMap={
     'ut_create':create_fee_rate,

+ 2 - 0
modules/fee_rates/routes/fee_rates_route.js

@@ -20,6 +20,8 @@ module.exports = function (app) {
     frRouter.post('/changeFeeRateFileFromOthers', frController.changeFeeRateFileFromOthers);
     frRouter.post('/setFeeRateToBill', frController.setFeeRateToBill);
     frRouter.post('/updateFeeRate', frController.updateFeeRate);
+    frRouter.post('/updateRates', frController.updateRates);
+    frRouter.post('/feeRateFileSaveAs', frController.feeRateFileSaveAs);
     app.use('/feeRates',frRouter);
 }
 

+ 6 - 5
modules/glj/models/glj_list_model.js

@@ -16,6 +16,7 @@ import STDGLJLibGLJListModel from "../../common/std/std_glj_lib_glj_list_model";
 import MixRatioModel from "./mix_ratio_model";
 import GljModel from "../../complementary_glj_lib/models/gljModel";
 const ProjectModel = require('../../pm/models/project_model').project;
+const scMathUtil = require('../../../public/scMathUtil').getUtil();
 
 class GLJListModel extends BaseModel {
 
@@ -130,7 +131,7 @@ class GLJListModel extends BaseModel {
                 for (let tmp of mixRatioList) {
                     totalComposition[tmp.connect_code] = totalComposition[tmp.connect_code] === undefined ? tmp.consumption :
                         totalComposition[tmp.connect_code] + tmp.consumption;
-                    totalComposition[tmp.connect_code] = Number(totalComposition[tmp.connect_code].toFixed(4));
+                    totalComposition[tmp.connect_code] = scMathUtil.roundTo(totalComposition[tmp.connect_code], -4);
 
                     if (mixRatioData[tmp.glj_id] !== undefined) {
                         mixRatioData[tmp.glj_id].push(tmp);
@@ -204,18 +205,18 @@ class GLJListModel extends BaseModel {
             glj.quantity = quantityList[projectGljId] !== undefined ? quantityList[projectGljId] : 0;
             glj.quantity = totalComposition[glj.code] !== undefined ? totalComposition[glj.code] : glj.quantity;
             glj.quantity = compositionConsumption[gljId] !== undefined ?  glj.quantity + compositionConsumption[gljId] : glj.quantity;
-            glj.quantity = parseFloat(glj.quantity).toFixed(3);
+            glj.quantity = scMathUtil.roundTo(parseFloat(glj.quantity), -3);
 
             // 组成物数据
             gljList[index].ratio_data = mixRatioData[gljId] !== undefined ? mixRatioData[gljId] : [];
 
-            glj.unit_price.base_price = parseFloat(glj.unit_price.base_price).toFixed(2);
-            glj.unit_price.market_price = parseFloat(glj.unit_price.market_price).toFixed(2);
+            glj.unit_price.base_price = scMathUtil.roundTo(parseFloat(glj.unit_price.base_price), -2);
+            glj.unit_price.market_price = scMathUtil.roundTo(parseFloat(glj.unit_price.market_price), -2);
             // 计算调整基价
             switch (glj.unit_price.type + '') {
                 // 人工: 调整基价=基价单价*调整系数
                 case GLJTypeConst.LABOUR:
-                    glj.adjust_price = parseFloat(glj.adjustment * glj.unit_price.base_price).toFixed(2);
+                    glj.adjust_price = scMathUtil.roundTo(parseFloat(glj.adjustment * glj.unit_price.base_price), -2);
                     break;
                 // 机械类型的算法
                 case GLJTypeConst.MACHINE:

+ 22 - 4
modules/main/facade/labour_coe_facade.js

@@ -83,20 +83,38 @@ function getData(projectID, callback) {
 };
 
 // 统一的 save() 方法供project调用
+// data 格式要求:{projectID: projectID, libID: libID, libName: libName, newItemArr: needUpdateDatas}
+// needUpdateDatas: [{ID: 5, value: 2.87}, {ID: 13, value: 2.91}]
 function save (data, callback) {
     let updateArr = [];
     let datas = JSON.parse(data);
-    for (let Item of datas.updateData) {
+
+    if (datas.libID){
+        let ItemObj = {
+            updateOne: {
+                filter: {projectID: datas.projectID},
+                update: { 'libID': datas.projectID, 'libName': datas.libName }
+            }
+        };
+        updateArr.push(ItemObj);
+    };
+
+    for (let Item of datas.newItemArr) {
          let ItemObj = {
              updateOne: {
                  filter: {projectID: datas.projectID, 'coes.ID': Item.ID},
-                 update: { 'coes.$.coe': Item.value }
+                 update: { 'coes.$.coe': Item.coe }
              }
          };
          updateArr.push(ItemObj);
     };
     // console.log(JSON.stringify(updateArr));
     projectLabourCoesModel.bulkWrite(updateArr)
-        .then(callback(0, '', null))
-        .catch(function (err) {callback(1, err, null)});
+        .then(function(){
+            logger.info(`Project LabourCoe saved successful : ${datas.projectID}`);
+            callback(0, '', null);
+        })
+        .catch(function (err) {
+            logger.err(err);
+            callback(1, err, null)});
 }

+ 1 - 1
modules/pm/models/project_model.js

@@ -77,7 +77,7 @@ ProjectsDAO.prototype.updateUserProjects = async function(userId, datas, callbac
                         name: data.updateData.name,
                         project_id: data.updateData.ID,
                         user_id: userId,
-                        root_project_id: data.property.rootProjectID
+                        root_project_id: data.updateData.property.rootProjectID
                     };
                     let addResult = await unitPriceFileModel.add(insertData);
                     if (!addResult) {

+ 18 - 8
public/calc_util.js

@@ -4,6 +4,12 @@
  * added by CSL, 2017-09-01 增加公式解析对象analyzer,用于解析用户修改公式、自定义表达式。
  */
 
+// 需求说小数位数固定为2位,这里预留缓冲接口,防止以后需求变卦。
+const Digit_Calc_Program = -2;      // 这里指定计算程序用到的小数位数。
+function round(num) {
+    return scMathUtil.roundTo(num, Digit_Calc_Program);
+};
+
 let executeObj = {
     treeNode: null,
     template: null,
@@ -22,7 +28,7 @@ let executeObj = {
             base = me.calcBase[calcBaseName];
 
         if (base != null) {
-            let price = 0, aprice = 0, mprice = 0, tmpSum = 0;
+            let price = 0, aprice = 0, mprice = 0, tmpSum = 0, mdSum = 0;
 
             function isSubset(sub, arr){
                 // if(!(sub instanceof Array) || !(arr instanceof Array)) return false;
@@ -39,13 +45,15 @@ let executeObj = {
                        if (glj.type == gljType.GENERAL_MACHINE) {
                             // 获取机械组成物
                            let mds = projectObj.project.composition.getCompositionByCode(glj.code);
+                           if (!mds) mds = [];
                            for (let md of mds){
                                if (base.gljTypes.indexOf(md.glj_type) >= 0) {
                                    price = md["base_price"];
                                    if (!price) price = 0;
-                                   tmpSum = tmpSum + glj["quantity"] * md["consumption"] * price;
+                                   mdSum = mdSum +  round(md["consumption"] * price);
                                }
                            };
+                           tmpSum = tmpSum + glj["quantity"] * mdSum;     // 这里不能四舍五入
                        }
                 };
             }else{
@@ -66,8 +74,10 @@ let executeObj = {
                     };
                 };
             };
-            rst = tmpSum;
+
+            rst = round(tmpSum);
         };
+
         return rst;
     }
 };
@@ -321,12 +331,12 @@ class Calculation {
         let private_compile_items = function() {
             for (let idx of template.compiledSeq) {
                 let item = template.calcItems[idx];
+                item.dispExprUser = item.dispExpr;    // 用于界面显示。disExpr是公式模板,不允许修改:人工系数占位符被修改后变成数值,第二次无法正确替换。
                 item.compiledExpr = item.expression.split('@(').join('$CE.at(');
                 item.compiledExpr = item.compiledExpr.split('base(').join('$CE.base(');
-
                 if (item.labourCoeID){
                     let lc = me.compiledLabourCoes["LabourCoe_" + item.labourCoeID].coe;
-                    item.dispExpr = item.dispExpr.replace(/L/gi, lc.toString());
+                    item.dispExprUser = item.dispExpr.replace(/L/gi, lc.toString());
                     item.compiledExpr = item.compiledExpr.replace(/L/gi, lc.toString());
                 };
 
@@ -364,7 +374,7 @@ class Calculation {
 
     calculate($treeNode){
         let me = this;
-        let templateID = $treeNode.data.calcTemplateID;
+        let templateID = $treeNode.data.programID;
         if (!templateID) templateID = 1;
         let template = me.compiledTemplates[templateID];
         $treeNode.data.calcTemplate = template;
@@ -385,11 +395,11 @@ class Calculation {
 
                 let feeRate = calcItem.feeRate;
                 if (!feeRate) feeRate = 100;    // 100%
-                calcItem.unitFee = eval(calcItem.compiledExpr) * feeRate * 0.01;   // 如果eval()对清单树有影响,就换成小麦的Expression对象再试
+                calcItem.unitFee = round(eval(calcItem.compiledExpr) * feeRate * 0.01);   // 如果eval()对清单树有影响,就换成小麦的Expression对象再试
 
                 let quantity = $treeNode.data.quantity;
                 if (!quantity) quantity = 0;
-                calcItem.totalFee = calcItem.unitFee * quantity;
+                calcItem.totalFee = round(calcItem.unitFee * quantity);
 
                 // 费用同步到定额
                 // 引入小麦的字段检测后,快速切换定额出现计算卡顿现象,过多的循环造成。这里把她的代码拆出来,减少微循环。

+ 1 - 1
public/scMathUtil.js

@@ -4,7 +4,7 @@
 const fs = require('fs');
 let scMath = null;
 
-getScMathUtil = function() {
+let getScMathUtil = function() {
     if (!(scMath)) {
         let data = fs.readFileSync(__dirname + '/web/scMathUtil.js', 'utf8', 'r');
         //console.log(data);

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 82 - 0
public/web/PerfectLoad.js


+ 1 - 1
public/web/scMathUtil.js

@@ -82,7 +82,7 @@ let scMathUtil = {
 
 Number.prototype.toDecimal = function (ADigit) {
     //return parseFloat(this.toFixed(ADigit));
-    digit = (ADigit && typeof(ADigit) === 'Number' && Number.isInteger(ADigit) && ADigit >= 0) ? -ADigit : -2;
+    digit = (ADigit && typeof(ADigit) === 'number' && Number.isInteger(ADigit) && ADigit >= 0) ? -ADigit : -2;
     // var s = scMathUtil.roundTo(this, digit);
     // console.log('Number: ' + this + '   Digit: ' + digit + '    Result: ' + s);
     // return parseFloat(s);

+ 19 - 20
public/web/sheet/sheet_common.js

@@ -4,12 +4,11 @@
 var sheetCommonObj = {
     // CSL.2017.06.05
     // createSpread、initSheet 在一个Spread多个Sheet分别调用时的情况下使用。
-    // buildSheet 在一个Spread、一个Sheet的情况下使用。
     createSpread: function(container, SheetCount){
         var me = this;
         var spreadBook = new GC.Spread.Sheets.Workbook(container, { sheetCount: SheetCount });
         spreadBook.options.tabStripVisible = false;
-         spreadBook.options.showHorizontalScrollbar = true;
+        spreadBook.options.showHorizontalScrollbar = true;
         spreadBook.options.allowCopyPasteExcelStyle = false;
         spreadBook.options.allowUserDragDrop = true;
         return spreadBook;
@@ -20,10 +19,24 @@ var sheetCommonObj = {
         var spreadNS = GC.Spread.Sheets;
         sheet.suspendPaint();
         sheet.suspendEvent();
+
         sheet.setRowCount(1, spreadNS.SheetArea.colHeader);
         sheet.setColumnCount(setting.header.length, spreadNS.SheetArea.viewport);
+
+        if (setting && setting.view && setting.view.colHeaderHeight) {
+            sheet.setRowHeight(0, setting.view.colHeaderHeight, spreadNS.SheetArea.colHeader);
+        };
+        if (setting && setting.view && setting.view.rowHeaderWidth) {
+            sheet.setColumnWidth(0, setting.view.rowHeaderWidth, spreadNS.SheetArea.rowHeader);
+        };
+
         sheet.options.colHeaderAutoTextIndex = 1;
         sheet.options.colHeaderAutoText = spreadNS.HeaderAutoText.numbers;
+
+        sheet.options.protectionOptions = {
+            allowResizeColumns: true
+        };
+
         sheet.showRowOutline(false);
         me.buildHeader(sheet, setting);
         if (rowCount > 0) sheet.setRowCount(rowCount);
@@ -31,29 +44,15 @@ var sheetCommonObj = {
         sheet.resumePaint();
     },
 
+    // buildSheet 在一个Spread、一个Sheet的情况下使用。
     buildSheet: function(container, setting, rowCount) {
         var me = this;
-        var spreadBook = new GC.Spread.Sheets.Workbook(container, { sheetCount: 1 });
-        spreadBook.options.tabStripVisible = false;
-        spreadBook.options.showHorizontalScrollbar = true;
-        var spreadNS = GC.Spread.Sheets;
+        var spreadBook = me.createSpread(container, { sheetCount: 1 });
         var sheet = spreadBook.getSheet(0);
-        sheet.suspendPaint();
-        sheet.suspendEvent();
-        //Set rowHeader count and columnHeader count.
-        sheet.setRowCount(1, spreadNS.SheetArea.colHeader);
-        sheet.setColumnCount(setting.header.length, spreadNS.SheetArea.viewport);
-        sheet.options.colHeaderAutoTextIndex = 1;
-        sheet.options.colHeaderAutoText = spreadNS.HeaderAutoText.numbers;
-        sheet.showRowOutline(false);
-        //setup column header
-        me.buildHeader(sheet, setting);
-        //setup cells
-        if (rowCount > 0) sheet.setRowCount(rowCount);
-        sheet.resumeEvent();
-        sheet.resumePaint();
+        me.initSheet(sheet, setting, rowCount);
         return spreadBook;
     },
+
     buildHeader: function(sheet, setting){
         var me = this, ch = GC.Spread.Sheets.SheetArea.colHeader;
         for (var i = 0; i < setting.header.length; i++) {

+ 2 - 2
web/building_saas/glj/html/glj_index.html

@@ -21,7 +21,7 @@
             <div class="bottom-content">
                 <ul class="nav nav-tabs" role="tablist">
                     <li class="nav-item">
-                        <a class="nav-link active" data-toggle="tab" data-name="ration" href="#de" role="tab">相关定额</a>
+                        <a class="nav-link active" data-toggle="tab" data-name="ration" href="#glj_de" role="tab">相关定额</a>
                     </li>
                     <li class="nav-item">
                         <a class="nav-link" data-toggle="tab" data-name="mix-ratio" href="#ph" role="tab">配合比表</a>
@@ -32,7 +32,7 @@
                 </ul>
                 <!-- Tab panes -->
                 <div class="tab-content">
-                    <div class="tab-pane active" id="de" role="tabpanel">
+                    <div class="tab-pane active" id="glj_de" role="tabpanel">
                         <div class="main-data-bottom ovf-hidden">
                             相关定额
                         </div>

+ 6 - 6
web/building_saas/main/html/calc_program_manage.html

@@ -15,16 +15,16 @@
     </div>
     <div class="container-fluid">
         <div class="row">
-        <div class="col-lg-3 p-0">
-            <div class="main-data-not" id="mainSpread">
+            <div class="col-lg-2 p-0">
+                <div class="main-data-not" id="mainSpread">
+                </div>
             </div>
-        </div>
-        <div class="col-lg-9 p-0">
-            <div class="main-data-not" id="detailSpread">
+            <div class="col-lg-10 p-0">
+                <div class="main-data-not" id="detailSpread">
+                </div>
             </div>
         </div>
     </div>
-    </div>
 
     <!--弹出 计算基数-->
 <div class="modal fade" id="jsjs" data-backdrop="static">

+ 13 - 8
web/building_saas/main/js/controllers/project_controller.js

@@ -18,17 +18,22 @@ ProjectController = {
         if (!project || !sheetController) { return null; }
 
         let target = project.getParentTarget(project.mainTree.selected, 'sourceType', project.Bills.getSourceType());
-        let newSource = null, newNode = null;
-        let parentID = target ? target.source.getParentID() : project.Bills.tree.setting.rootId;
-        let nextSiblingID = target ? target.source.getNextSiblingID() : project.Bills.tree.setting.rootId;
+        let newSource = null, newNode = null, parentID, nextSiblingID;
+        if (target) {
+            console.log(target.depth());
+            parentID = target.depth() === 0 ? target.source.getID() : target.source.getParentID();
+            nextSiblingID = target ? target.source.getNextSiblingID() : project.Bills.tree.setting.rootId;
 
-        if (std) {
-            let newCode = project.Bills.newFormatCode(std.code);
-            newSource = project.Bills.insertStdBills(parentID, nextSiblingID, std, newCode);
+            if (std) {
+                let newCode = project.Bills.newFormatCode(std.code);
+                newSource = project.Bills.insertStdBills(parentID, nextSiblingID, std, newCode);
+            } else {
+                newSource = project.Bills.insertBills(parentID, nextSiblingID);
+            }
+            newNode = project.mainTree.insert(target.depth() === 0 ? target.getID() : target.getParentID(), target.getNextSiblingID());
         } else {
-            newSource = project.Bills.insertBills(parentID, nextSiblingID);
+            alert('不可添加清单');
         }
-        newNode = project.mainTree.insert(target.getParentID(), target.getNextSiblingID());
 
         if (newNode) {
             newNode.source = newSource;

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

@@ -14,6 +14,8 @@ $(function () {
 
     $('#tab_zaojiashu').on('shown.bs.tab', function (e) {
         $(e.relatedTarget.hash).removeClass('active');
+        $("#subItems").addClass('active');
+
         // do something
     });
 

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

@@ -64,7 +64,7 @@ Composition.prototype.getCompositionByCode = function(code, gljType = 0) {
         return result;
     }
     if (gljType === 0) {
-        return this.datas[code];
+        return this.datas[code] !== undefined ? this.datas[code] : result;
     }
 
     for(let composition of this.datas[code]) {

+ 99 - 13
web/building_saas/main/js/models/fee_rate.js

@@ -8,6 +8,7 @@ var FeeRate = {
 
         function FeeRate(proj){
             this.datas = null;
+            this.datasBackup = null;
             this.sourceType = ModuleNames.feeRate;
             proj.registerModule(ModuleNames.feeRate, this);
         };
@@ -15,6 +16,14 @@ var FeeRate = {
             this.datas = datas;
             socketObject.connect();
         };
+        FeeRate.prototype.backupDatas=function () {
+          this.datasBackup = _.cloneDeep(this.datas);
+        };
+        FeeRate.prototype.dataRecovery=function () {
+            this.datas = this.datasBackup;
+            feeRateObject.activateFeeRate = this.getActivateFeeRate();
+            feeRateObject.datas = feeRateObject.activateFeeRate.rates;
+        };
         FeeRate.prototype.getActivateFeeRate = function () {
             var feeRate={
                 rates:[]
@@ -123,10 +132,25 @@ var FeeRate = {
         };
 
         FeeRate.prototype.batchUpdateFeeRate = function (items,feerate) {
-            var query={
-                ID:feerate.feeRateID
-            };
-            this.updateFeeRate(query,items);
+            var me = this;
+            var data={
+                query:{
+                    ID:feerate.feeRateID
+                },
+                doc:items,
+                user_id:userID
+            }
+            var errCallBack=function () {
+                me.dataRecovery();
+                $.bootstrapLoading.end();
+            }
+            CommonAjax.post('/feeRates/updateRates', data, function (result) {
+                _.forEach(items,function (t) {
+                     feeRateObject.mainViews.data.updateItem(t.rateIndex,t.rate);
+                 })
+                 me.onFeeRateFileChange();
+                $.bootstrapLoading.end();
+            },errCallBack);
         };
         FeeRate.prototype.updateFeeRate=function (query,doc) {
           var updateData = this.getUpdateData('ut_update',query,doc,'update_rates');
@@ -168,6 +192,55 @@ var FeeRate = {
             }
             socket.emit('feeRateChangeNotify', this.getActivateFeeRateFileID());
         };
+        FeeRate.prototype.onFeeRateFileChange=function () {
+            this.refreshCalProgramWhenFeeFileChange();
+            this.refreshBillsWhenFeeFileChange();
+            var node = project.mainTree.selected;
+            if(node){
+                if (node.sourceType==='ration' && calcProgramObj.sheet) {
+                    calcProgramObj.showData(node);
+                }
+            }
+            socket.emit('feeRateChangeNotify', this.getActivateFeeRateFileID());
+        };
+
+        FeeRate.prototype.refreshBillsWhenFeeFileChange=function(){
+            var me = this;
+            var nodes = _.filter(projectObj.project.mainTree.items,function (n) {
+                if(n.sourceType==ModuleNames.bills&&n.data.feeRateID){
+                    if(n.data.hasOwnProperty("feeRateID")&&n.data.feeRateID){
+                        var rate = me.getFeeRateByID(n.data.feeRateID);
+                        if(rate){
+                            n.data.feeRate=number_util.roundToString(rate.rate,feeRate_consts.decimal);
+                            return true;
+                        }else {
+                            n.data.feeRate=null;
+                            return true;
+                        }
+                    }
+                }
+                return false;
+            })
+            if(nodes.length>0){
+                projectObj.mainController.refreshTreeNode(nodes)
+            }
+        };
+        FeeRate.prototype.refreshCalProgramWhenFeeFileChange=function () {
+            var me = this;
+            var templates = project.calcProgram.datas.templates;
+            for(var i =0;i<templates.length;i++){
+                _.forEach(templates[i].calcItems,function (item) {
+                    if(item.hasOwnProperty("feeRateID")&&item.feeRateID){
+                        var rate = me.getFeeRateByID(item.feeRateID);
+                        if(rate){
+                            item.feeRate = rate.rate;
+                        }
+                    }
+                })
+            }
+            project.calcProgram.compileAllTemps();
+            rationPM.refreshDetailSheet();
+        }
         FeeRate.prototype.refreshCalProgramByRateID=function (rateID,value) {
             var templates = project.calcProgram.datas.templates;
             for(var i =0;i<templates.length;i++){
@@ -208,9 +281,11 @@ var FeeRate = {
                     me.datas.libName=data.libName;
                     me.datas.feeRateID=data.feeRateID;
                     me.datas.rates=data.rates;
-                    socket.emit('feeRateChangeNotify', me.getActivateFeeRateFileID());
+                    me.onFeeRateFileChange();
                     callback();
                 }
+            },function () {
+                $.bootstrapLoading.end();
             });
         };
         FeeRate.prototype.checkFeeRateName = function(newVal,callback){
@@ -224,17 +299,26 @@ var FeeRate = {
                 callback(data);
             });
         };
-        FeeRate.prototype.feeRateFileSaveAs = function (newName) {
+        FeeRate.prototype.feeRateFileSaveAs = function (newName,callback) {
+            var me = this;
+            $.bootstrapLoading.start();
+            this.backupDatas();
             this.datas.name = newName;
             this.datas.ID = uuid.v1();
             this.datas.feeRateID=uuid.v1();
             this.datas.usageProjects=[];
             this.datas.usageProjects.push({name:projectInfoObj.projectInfo.name,ID:projectInfoObj.projectInfo.ID});
-            var updateData = this.getUpdateData('ut_update',{projectID:projectInfoObj.projectInfo.ID},this.datas,'feeRateFileSaveAs');
-            project.pushNow('updateFeeRate',[this.sourceType],updateData);
-
-            socket.emit('feeRateChangeNotify', this.getActivateFeeRateFileID());
-            return  this.datas;
+            var data={
+                query:{projectID:projectInfoObj.projectInfo.ID},
+                doc:this.datas,
+                user_id:userID
+            }
+            CommonAjax.post('/feeRates/feeRateFileSaveAs', data, function (data) {
+                callback(me.datas);
+            },function () {
+                me.dataRecovery();
+                $.bootstrapLoading.end();
+            });
         };
         FeeRate.prototype.getChangeInfo = function (callback) {
            // var projectID = projectInfoObj.projectInfo.ID;
@@ -400,9 +484,10 @@ var FeeRate = {
             CommonAjax.post('/feeRates/changeFeeRateFileFromCurrent', data, function (data) {
                 if (data) {
                     me.datas=data;
-                    socket.emit('feeRateChangeNotify', me.getActivateFeeRateFileID());
                     callback();
                 }
+            },function () {
+                $.bootstrapLoading.end();
             });
         };
 
@@ -418,9 +503,10 @@ var FeeRate = {
             CommonAjax.post('/feeRates/changeFeeRateFileFromOthers', data, function (data) {
                 if (data) {
                     me.datas=data;
-                    socket.emit('feeRateChangeNotify', me.getActivateFeeRateFileID());
                     callback();
                 }
+            },function () {
+                $.bootstrapLoading.end();
             });
 
         };

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

@@ -32,7 +32,7 @@ class LabourCoe {
         for (let newItem of data.newItemArr){
               for (let oldItem of me.datas.coes){
                    if (oldItem.ID == newItem.ID){
-                       oldItem.coe = newItem.value;
+                       oldItem.coe = newItem.coe;
                        break;
                    }
               };

+ 16 - 1
web/building_saas/main/js/models/main_consts.js

@@ -16,6 +16,21 @@ const ModuleNames = {
     labour_coe: 'labour_coe',
     calc_program: 'calc_program'
 };
+
 const feeRate_consts={
     decimal:3
-}
+};
+
+const CP_Col_Width = {          // 多处计算程序界面的列宽统一设置
+    rowHeader: 30,
+    colHeader: 30,              // 这个是标题栏高度不是宽度,也写在一起
+    code: 70,
+    name: 200,
+    dispExprUser: 180,
+    feeRate: 60,
+    displayFieldName: 120,
+    statement: 380,
+    memo: 100,
+    unitFee: 100,
+    totalFee: 100
+};

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

@@ -84,7 +84,7 @@ var PROJECT = {
             this.composition.loadData();
             this.Decimal = {
                 common: {
-                    quantity: 3,
+                    quantity: 4,
                     unitFee: 2,
                     totalFee: 2
                 }

+ 2 - 0
web/building_saas/main/js/models/ration.js

@@ -174,6 +174,7 @@ var Ration = {
                         data.updateData.comments = std.chapter.explanation;
                         data.updateData.ruleText = std.chapter.ruleText;
                     }
+                    data.updateData.programID = std.feeType;
                     data.updateData.rationAssList =  projectObj.project.ration_ass.CreateNewAss(std);
                     // calculate ration Quantity
                     that.CalculateQuantity(data.updateData);
@@ -329,6 +330,7 @@ var Ration = {
                 ration.comments = std.chapter.explanation;
                 ration.ruleText = std.chapter.ruleText;
             }
+            ration.programID = std.feeType;
             ration.rationAssList = projectObj.project.ration_ass.CreateNewAss(std);
             // calculate ration Quantity
             this.CalculateQuantity(ration);

+ 14 - 12
web/building_saas/main/js/views/calc_program_manage.js

@@ -14,24 +14,28 @@ let rationPM = {
         ],
         view:{
             comboBox:[],
-            lockColumns:[0,1]
+            lockColumns:[0,1],
+            colHeaderHeight: CP_Col_Width.colHeader,
+            rowHeaderWidth: CP_Col_Width.rowHeader
         }
     },
 
     detailSetting: {
         header:[
             // {headerName:"ID",headerWidth:80,dataCode:"ID", hAlign: "center"},
-            {headerName:"费用代号",headerWidth:80,dataCode:"code", dataType: "String"},
-            {headerName:"费用名称",headerWidth:200,dataCode:"name", dataType: "String"},
-            {headerName:"计算基数",headerWidth:180,dataCode:"dispExpr", dataType: "String"},
-            {headerName:"基数说明",headerWidth:300,dataCode:"statement", dataType: "String"},
-            {headerName:"费率",headerWidth:80,dataCode:"feeRate", dataType: "Number",hAlign: "left",tofix:feeRate_consts.decimal},
-            {headerName:"字段名称",headerWidth:140,dataCode:"displayFieldName", dataType: "String", hAlign: "center"},
-            {headerName:"备注",headerWidth:100,dataCode:"memo", dataType: "String"}
+            {headerName:"费用代号",headerWidth:CP_Col_Width.code, dataCode:"code", dataType: "String"},
+            {headerName:"费用名称",headerWidth:CP_Col_Width.name, dataCode:"name", dataType: "String"},
+            {headerName:"计算基数",headerWidth:CP_Col_Width.dispExprUser, dataCode:"dispExprUser", dataType: "String"},
+            {headerName:"费率",headerWidth:CP_Col_Width.feeRate, dataCode:"feeRate", dataType: "Number",hAlign: "right",tofix: feeRate_consts.decimal},
+            {headerName:"费用类别",headerWidth:CP_Col_Width.displayFieldName, dataCode:"displayFieldName", dataType: "String", hAlign: "center"},
+            {headerName:"基数说明",headerWidth:CP_Col_Width.statement, dataCode:"statement", dataType: "String"},
+            {headerName:"备注",headerWidth:CP_Col_Width.memo, dataCode:"memo", dataType: "String"}
         ],
         view:{
             comboBox:[],
-            lockColumns:[0,1,2,3,6]
+            lockColumns:[0,1,2,3,6],
+            colHeaderHeight: CP_Col_Width.colHeader,
+            rowHeaderWidth: CP_Col_Width.rowHeader
         }
     },
 
@@ -51,8 +55,7 @@ let rationPM = {
 
         var fieldName = new GC.Spread.Sheets.CellTypes.ComboBox();
         fieldName.items(projectObj.project.calcProgram.calc.compiledFeeTypeNames);
-        // fieldName.items(["直接费","人工费","材料费","机械费","主材费","企业管理费","利润","风险费","人工价差","材料价差","机械价差","工程造价","调整人工费","调整机上人工费","甲供材料费"]);
-        me.detailSpread.getSheet(0).getRange(-1, 5, -1, 1).cellType(fieldName);
+        me.detailSpread.getSheet(0).getRange(-1, 4, -1, 1).cellType(fieldName);
 
         me.mainSpread.getSheet(0).bind(GC.Spread.Sheets.Events.EnterCell, me.onMainEnterCell);
         me.detailSpread.getSheet(0).bind(GC.Spread.Sheets.Events.CellChanged, me.onDetailCellChanged);
@@ -64,7 +67,6 @@ let rationPM = {
         feeRateObject.setFeeRateCellCol(dSheet,_.findIndex(me.detailSetting.header,{'dataCode':'feeRate'}));
         dSheet.name('calc_detail');
         sheetCommonObj.showData(dSheet, me.detailSetting, me.datas[0].calcItems);
-
     },
     onMainEnterCell: function(sender, args) {
         var me = rationPM;

+ 11 - 9
web/building_saas/main/js/views/calc_program_view.js

@@ -201,18 +201,20 @@ let calcProgramObj = {
 
     setting: {
         header: [
-            {headerName: "费用代号", headerWidth: 75, dataCode: "code", dataType: "String", hAlign: "left"},
-            {headerName: "费用名称", headerWidth: 200, dataCode: "name", dataType: "String"},
-            {headerName: "计算基数", headerWidth: 200, dataCode: "dispExpr", dataType: "String"},
-            {headerName: "基数说明", headerWidth: 400, dataCode: "statement", dataType: "String"},
-            {headerName: "费率", headerWidth: 80, dataCode: "feeRate", dataType: "Number"},   // precision: 3
-            {headerName: "单价", headerWidth: 100, dataCode: "unitFee", dataType: "Number"},  // execRst
-            {headerName: "合价", headerWidth: 100, dataCode: "totalFee", dataType: "Number"},
-            {headerName: "备注", headerWidth: 120, dataCode: "memo", dataType: "String"}
+            {headerName: "费用代号", headerWidth: CP_Col_Width.code, dataCode: "code", dataType: "String", hAlign: "left"},
+            {headerName: "费用名称", headerWidth: CP_Col_Width.name, dataCode: "name", dataType: "String"},
+            {headerName: "计算基数", headerWidth: CP_Col_Width.dispExprUser, dataCode: "dispExprUser", dataType: "String"},
+            {headerName: "基数说明", headerWidth: CP_Col_Width.statement, dataCode: "statement", dataType: "String"},
+            {headerName: "费率", headerWidth: CP_Col_Width.feeRate, dataCode: "feeRate", dataType: "Number"},   // precision: 3
+            {headerName: "单价", headerWidth: CP_Col_Width.unitFee, dataCode: "unitFee", dataType: "Number"},  // execRst
+            {headerName: "合价", headerWidth: CP_Col_Width.totalFee, dataCode: "totalFee", dataType: "Number"},
+            {headerName: "备注", headerWidth: CP_Col_Width.memo, dataCode: "memo", dataType: "String"}
         ],
         view: {
             comboBox: [],
-            lockColumns: [0, 1, 2, 3, 4, 5, 6, 7]
+            lockColumns: [0, 1, 2, 3, 4, 5, 6, 7],
+            colHeaderHeight: CP_Col_Width.colHeader,
+            rowHeaderWidth: CP_Col_Width.rowHeader
         }
     },
 

+ 30 - 23
web/building_saas/main/js/views/fee_rate_view.js

@@ -7,6 +7,7 @@
 var feeRateObject={
     mainViews:null,
     datas:null,
+    datasBackup:null,
     canEdit:false,
     activateFeeRate:null,
     needCascadeSet:false,
@@ -367,6 +368,7 @@ var feeRateObject={
     },
     updateBySelect:function (rate,selectMap,mapID) {
        var selected = this.mainViews.getSelections()[0];
+        projectObj.project.FeeRate.backupDatas();
        var item = this.datas[selected.sourceRow];
         item.rate = rate;
         _.forEach(selectMap,function (value,key) {
@@ -385,7 +387,7 @@ var feeRateObject={
         }else {
             this.mainViews.data.updateItem(selected.sourceRow,item);
         }
-        projectObj.project.FeeRate.synchronizeFeeRate();
+        //projectObj.project.FeeRate.synchronizeFeeRate();
 
         //this.views.data.updateItem()
     },
@@ -452,11 +454,6 @@ var feeRateObject={
                 }
             }
         })
-
-        _.forEach(items,function (t) {
-            feeRateObject.mainViews.data.updateItem(t.rateIndex,t.rate);
-        })
-
         projectObj.project.FeeRate.batchUpdateFeeRate(items,feeRateObject.activateFeeRate);
     },
     loadPageContent:function(){
@@ -487,11 +484,13 @@ var feeRateObject={
         });
     },
     changeFeeRateStandard:function(newVal){
+        $.bootstrapLoading.start();
         var callback=function () {
             feeRateObject.createSpreadView();
             feeRateObject.loadPageContent();
             projectObj.project.FeeRate.synchronizeFeeRate();
             subRateObject.destorySpreadView();
+            $.bootstrapLoading.end();
         };
         projectObj.project.FeeRate.changeFeeRateStandard(newVal,callback);
     },
@@ -511,7 +510,6 @@ var feeRateObject={
                 $('#saveAsConfirm').removeAttr("disabled");
                 $('#nameError').hide();
             }
-            console.log(data);
         };
         projectObj.project.FeeRate.checkFeeRateName(newVal,callback);
     },
@@ -538,9 +536,15 @@ var feeRateObject={
         }
     },
     submitSaveAs:function (newName) {
-        this.activateFeeRate =  projectObj.project.FeeRate.feeRateFileSaveAs(newName);
-        feeRateObject.loadPageContent();
-        $('#copy-lv').modal('hide');
+        var me = this;
+          projectObj.project.FeeRate.feeRateFileSaveAs(newName,function (result) {
+              me.activateFeeRate = result;
+              me.loadPageContent();
+              $('#copy-lv').modal('hide');
+              socket.emit('feeRateChangeNotify', projectObj.project.FeeRate.getActivateFeeRateFileID());
+              $.bootstrapLoading.end();
+        });
+
     },
     getChangeInfo:function () {
         var me = this;
@@ -573,6 +577,7 @@ var feeRateObject={
         }
     },
     changeFeeRateFileFromCurrent:function(){
+        $.bootstrapLoading.start();
         var newVal = $("#currentOptions").val();
         if($("#currentOptions").val()==this.activateFeeRate.ID){
             return;
@@ -585,7 +590,8 @@ var feeRateObject={
         var callback=function () {
             feeRateObject.createSpreadView();
             feeRateObject.loadPageContent();
-            projectObj.project.FeeRate.synchronizeFeeRate();
+            projectObj.project.FeeRate.onFeeRateFileChange();
+            $.bootstrapLoading.end();
         }
         projectObj.project.FeeRate.changeFeeRateFileFromCurrent(newFeeRateFile,callback);
     },
@@ -606,10 +612,12 @@ var feeRateObject={
         }
     },
     changeFeeRateFileConfirm:function(feeRateFileID,name){
+        $.bootstrapLoading.start();
         var callback=function () {
             feeRateObject.createSpreadView();
             feeRateObject.loadPageContent();
-            projectObj.project.FeeRate.synchronizeFeeRate();
+            projectObj.project.FeeRate.onFeeRateFileChange();
+            $.bootstrapLoading.end();
         }
         projectObj.project.FeeRate.changeFeeRateFileFromOthers(feeRateFileID,name,callback);
     },
@@ -764,16 +772,6 @@ $(function(){
     });
 
 
-    function changeFRadioClick() {
-        var radioV= $("input[name='chaneg-lv-Radio']:checked").val();
-        if(radioV==='0'){
-            $("#fromProject").show();
-            $("#fromOther").hide();
-        }else {
-            $("#fromProject").hide();
-            $("#fromOther").show();
-        }
-    }
     $('#changeFeeRateConfirm').bind('click',function (){
         var radioV= $("input[name='chaneg-lv-Radio']:checked").val();
         if(radioV==='0'){
@@ -849,7 +847,16 @@ $(function(){
     $('#fee_selected_conf').bind('click',function (){
         feeRateObject.submitFeeRateBySelect();
     })
-
 })
 
+function changeFRadioClick() {
+    var radioV= $("input[name='chaneg-lv-Radio']:checked").val();
+    if(radioV==='0'){
+        $("#fromProject").show();
+        $("#fromOther").hide();
+    }else {
+        $("#fromProject").hide();
+        $("#fromOther").show();
+    }
+}
 

+ 3 - 0
web/building_saas/main/js/views/glj_view.js

@@ -582,6 +582,9 @@ var gljOprObj = {
         details=_.sortBy(details,'seq');
         sheetCommonObj.showData(this.detailSheet,this.detailSetting,details);
         this.detailData = details;
+        if(MainTreeCol.readOnly.forQuantifyDetail(node)){
+            this.detailSheet.getRange(-1,0,-1,this.detailSetting.header.length).locked(true);
+        }
     },
     clearSheetData:function () {
         sheetCommonObj.showData(this.sheet,this.setting,[]);

+ 3 - 0
web/building_saas/main/js/views/main_tree_col.js

@@ -50,6 +50,9 @@ let MainTreeCol = {
         },
         forTotalFee: function (node) {
             return MainTreeCol.readOnly.non_bills(node) || MainTreeCol.readOnly.billsParent(node) || (MainTreeCol.readOnly.leafBillsWithDetail(node));
+        },
+        forQuantifyDetail:function (node) {
+            return !(node.sourceType==ModuleNames.ration||!MainTreeCol.readOnly.billsParent(node));
         }
     },
     cellType: {

+ 8 - 4
web/building_saas/main/js/views/project_property_labour_coe_view.js

@@ -57,7 +57,7 @@ let labourCoeView = {
         var me = labourCoeView;
         if (args.propertyName !== "value"){return;};
         let cell = me.sheet.getCell(args.row, args.col);
-        me.addNeedUpdateData({ID: cell.tag(), value: cell.value()});
+        me.addNeedUpdateData({ID: cell.tag(), coe: cell.value()});
     },
 
     addNeedUpdateData: function (data) {
@@ -66,7 +66,7 @@ let labourCoeView = {
         for (let el of me.needUpdateDatas){
              if (el.ID == data.ID){
                  isExist = true;
-                 el.value = data.value;
+                 el.coe = data.coe;
                  return;
              };
         };
@@ -134,14 +134,16 @@ let labourCoeView = {
     save(){
         let me = this;
         if (me.needUpdateDatas.length > 0){
-            let data = {projectID: projectInfoObj.projectInfo.ID, updateData: me.needUpdateDatas};
+            let projectID = projectInfoObj.projectInfo.ID;
             let libID = $("#std_labour_coe_files").children("option:selected").val();
             let libName = $("#std_labour_coe_files").children("option:selected").text();
+            let data = {projectID: projectID, libID: libID, libName: libName, newItemArr: me.needUpdateDatas};
             CommonAjax.post('/labourCoe/save', data, function (){
-                projectObj.project.labourCoe.refreshData({libID: libID, libName: libName, newItemArr: me.needUpdateDatas});
+                projectObj.project.labourCoe.refreshData(data);
                 me.needUpdateDatas.splice(0, me.needUpdateDatas.length);
                 projectObj.project.calcProgram.compileAllTemps();
                 rationPM.buildSheet();
+                $("#std_labour_coe_files").val('');
             });
         }
     }
@@ -163,6 +165,8 @@ $(document).ready(function(){
         CommonAjax.post('/labourCoe/getStdLabourCoe', {"ID": libID}, function (data) {
             labourCoeView.buildSheet();
             labourCoeView.loadData(data.coes);
+            labourCoeView.needUpdateDatas.splice(0, labourCoeView.needUpdateDatas.length);
+            labourCoeView.needUpdateDatas.push(...data.coes);
         });
     });
 });

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

@@ -89,7 +89,9 @@ var projectObj = {
         if (colSetting.data.decimal) {
             value = Number(editingText);
             if (number_util.isNumber(value)) {
-                value = value.toDecimal(colSetting.data.decimal);
+                if (colSetting.data.decimal) {
+                    value = value.toDecimal(colSetting.data.decimal);
+                }
             } else {
                 value = null;
                 alert('当前输入的数据类型不正确,请重新输入。');
@@ -111,7 +113,9 @@ var projectObj = {
             }
         }
         if (value) {
-            value = value.toDecimal(colSetting.data.decimal);
+            if (colSetting.data.decimal) {
+                value = value.toDecimal(colSetting.data.decimal);   
+            }
         } else if (editingText && editingText !== '') {
             value = null;
             alert('当前输入的数据类型不正确,请重新输入。');
@@ -135,6 +139,7 @@ var projectObj = {
             }
             return nodes;
         }
+        value = value.toDecimal(projectObj.project.Decimal.common.quantity);
         if (node.sourceType === projectObj.project.Bills.getSourceType()) {
             calcFees.setFee(node.data, fieldName, value);
             calc.calcNode(node, true);
@@ -273,8 +278,10 @@ var projectObj = {
                 }
                 projectObj.mainController.refreshTreeNode([node]);
             }
-        }else if(value==null&&fieldName ==='feeRate'){
+        } else if(value==null && fieldName ==='feeRate'){
             project.FeeRate.cleanFeeRateID(node);
+        } else {
+            projectObj.mainController.refreshTreeNode([node], false);
         }
     },
     checkMainSpread: function () {

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

@@ -83,6 +83,7 @@ var subRateObject={
         var selectValueList=[];
         var selectMap={};
         if(me.datas&&me.datas.length>0){
+            $.bootstrapLoading.start();
             _.forEach(me.datas,function (d,key) {
                 var selectValue = $('#'+d.ID).val();
                 selectValueList.push(selectValue);

+ 1 - 0
web/common/html/header.html

@@ -62,4 +62,5 @@
 <script type="text/javascript" src="/web/building_saas/js/moment.min.js"></script>
 <script type="text/javascript" src="/web/building_saas/js/message.js"></script>
 <script type="text/javascript" src="/public/web/scMathUtil.js"></script>
+<script type="text/javascript" src="/public/web/PerfectLoad.js"></script>
 <!-- endinject -->