Explorar o código

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

TonyKang %!s(int64=6) %!d(string=hai) anos
pai
achega
0164c78ee9

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

@@ -543,5 +543,15 @@ module.exports = {
         catch (err){
             callback(req, res, 1, err, null);
         }
-    }
+    },
+    getSummaryInfo: async function(req, res){
+        try{
+            let data = JSON.parse(req.body.data);
+            let summaryInfo = await pm_facade.getSummaryInfo(data.projectIDs);
+            callback(req, res, 0, 'success', summaryInfo);
+        }
+        catch (err){
+            callback(req, res, 1, err, null);
+        }
+    },
 };

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

@@ -23,13 +23,22 @@ let rationGLJModel = mongoose.model('ration_glj');
 let rationCoeModel = mongoose.model('ration_coe');
 let rationInstallationModel = mongoose.model('ration_installation');
 let quantityDetailModel = mongoose.model('quantity_detail');
+let scMathUtil = require('../../../public/scMathUtil').getUtil();
 import CounterModel from "../../glj/models/counter_model";
 import moment from 'moment';
+import billsFlags from '../../common/const/bills_fixed';
+const projectType = {
+    folder: 'Folder',
+    tender: 'Tender',
+    project: 'Project',
+    engineering: 'Engineering',
+};
 
 
 module.exports={
     moveProject:moveProject,
-    copyProject:copyProject
+    copyProject:copyProject,
+    getSummaryInfo: getSummaryInfo
 };
 
 async function copyProject(userID, compilationID,data) {
@@ -447,4 +456,128 @@ function setProperty(Obj,updateData) {
     }
 
 
+}
+
+function isDef(v){
+    return typeof v !== 'undefined' && v !== null;
+}
+
+function getCommonTotalFee(bills) {
+    if(!isDef(bills)){
+        return 0;
+    }
+    if(!isDef(bills.fees) || bills.fees.length <= 0){
+        return 0;
+    }
+    for(let fee of bills.fees){
+        if(isDef(fee.fieldName) && fee.fieldName === 'common'){
+            return isDef(fee.totalFee) ? fee.totalFee : 0;
+        }
+    }
+    return 0;
+}
+
+function summarizeToParent(parent, child) {
+    const decimal = -2;
+    parent.engineeringCost = scMathUtil.roundTo(parseFloat(parent.engineeringCost) + parseFloat(child.engineeringCost), decimal);
+    parent.subEngineering = scMathUtil.roundTo(parseFloat(parent.subEngineering) + parseFloat(child.subEngineering), decimal);
+    parent.measure = scMathUtil.roundTo(parseFloat(parent.measure) + parseFloat(child.measure), decimal);
+    parent.safetyConstruction = scMathUtil.roundTo(parseFloat(parent.safetyConstruction) + parseFloat(child.safetyConstruction), decimal);
+    parent.other = scMathUtil.roundTo(parseFloat(parent.other) + parseFloat(child.other), decimal);
+    parent.charge = scMathUtil.roundTo(parseFloat(parent.charge) + parseFloat(child.charge), decimal);
+    parent.tax = scMathUtil.roundTo(parseFloat(parent.tax) + parseFloat(child.tax), decimal);
+}
+
+function getBuildingArea(projFeature){
+    if(!projFeature || projFeature.length === 0){
+        return null;
+    }
+    for(let f of projFeature){
+        if(f.key === 'buildingArea'){
+            return f.value;
+        }
+    }
+    return null;
+}
+
+async function getSummaryInfo(projectIDs){
+    //ID与汇总信息映射
+    let IDMapping = {};
+    //固定清单类别与汇总金额字段映射
+    let flagFieldMapping = {};
+    flagFieldMapping[billsFlags.ENGINEERINGCOST] = 'engineeringCost';
+    flagFieldMapping[billsFlags.SUB_ENGINERRING] = 'subEngineering';
+    flagFieldMapping[billsFlags.MEASURE] = 'measure';
+    flagFieldMapping[billsFlags.SAFETY_CONSTRUCTION] = 'safetyConstruction';
+    flagFieldMapping[billsFlags.OTHER] = 'other';
+    flagFieldMapping[billsFlags.CHARGE] = 'charge';
+    flagFieldMapping[billsFlags.TAX] = 'tax';
+    for(let projectID of projectIDs){
+        IDMapping[projectID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, rate: 0, buildingArea: '', perCost: ''};
+    }
+    //let projects = await projectModel.find({ID: {$in : projectIDs}, projType: projectType.project, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]});
+    //单项工程
+    let engineerings = await projectModel.find({ParentID: {$in : projectIDs}, projType: projectType.engineering, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]});
+    //单位工程
+    let tenders = [];
+    let engIDs = [];
+    for(let eng of engineerings){
+        engIDs.push(eng.ID);
+        IDMapping[eng.ID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, rate: 0, buildingArea: '', perCost: ''};
+    }
+    if(engIDs.length > 0){
+        tenders = await projectModel.find({ParentID: {$in : engIDs}, projType: projectType.tender, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]});
+    }
+    let tenderIDs = [];
+    if(tenders.length > 0){
+        for(let tender of tenders){
+            tenderIDs.push(tender.ID);
+            IDMapping[tender.ID] = {engineeringCost: 0, subEngineering: 0, measure: 0, safetyConstruction: 0, other: 0, charge: 0, tax: 0, rate: 0, buildingArea: '', perCost: ''};
+            let buildingArea = getBuildingArea(tender.property.projectFeature);
+            if(buildingArea){
+                IDMapping[tender.ID]['buildingArea'] = buildingArea;
+            }
+        }
+        //需要获取的清单固定类别综合合价:工程造价、分部分项、措施项目、安全文明施工专项、规费、其他项目、税金
+        let needFlags = [billsFlags.ENGINEERINGCOST, billsFlags.SUB_ENGINERRING, billsFlags.MEASURE,
+            billsFlags.SAFETY_CONSTRUCTION, billsFlags.CHARGE, billsFlags.OTHER, billsFlags.TAX];
+        //获取单位工程汇总金额需要用到的所有清单
+        let allBills = await billsModel.find({projectID: {$in: tenderIDs}, 'flags.flag': {$in: needFlags}, $or: [{deleteInfo: null}, {'deleteInfo.deleted': false}]},
+                                            '-_id projectID fees flags');
+        //进行单位工程级别的汇总
+        for(let bills of allBills){
+            let billsFlag = bills.flags[0]['flag'];
+            let costField = flagFieldMapping[billsFlag];
+            IDMapping[bills.projectID][costField] = getCommonTotalFee(bills);
+        }
+        //进行单项工程级别的汇总
+        for(let tender of tenders){
+            summarizeToParent(IDMapping[tender.ParentID], IDMapping[tender.ID]);
+        }
+        //进行建设项目级别的汇总
+        for(let eng of engineerings){
+            summarizeToParent(IDMapping[eng.ParentID], IDMapping[eng.ID]);
+        }
+        //占造价比例、单方造价
+        const rateDecimal = -2;
+        const perCostDecimal = -2;
+        for(let tender of tenders){
+            let tenderInfo = IDMapping[tender.ID];
+            let engInfo = IDMapping[tender.ParentID];
+            tenderInfo.rate = engInfo.engineeringCost == 0 ? 0 : scMathUtil.roundTo(tenderInfo.engineeringCost * 100 / engInfo.engineeringCost, rateDecimal);
+            //单方造价
+            tenderInfo.perCost = tenderInfo.buildingArea.toString().trim() === '' || tenderInfo.buildingArea == 0 ?
+                                 tenderInfo.buildingArea.toString().trim() : scMathUtil.roundTo(tenderInfo.engineeringCost / tenderInfo.buildingArea, perCostDecimal);
+        }
+        for(let eng of engineerings){
+            let engInfo = IDMapping[eng.ID];
+            let projInfo = IDMapping[eng.ParentID];
+            engInfo.rate = !isDef(projInfo) || projInfo.engineeringCost == 0 ? 0 : scMathUtil.roundTo(engInfo.engineeringCost * 100 / projInfo.engineeringCost, rateDecimal);
+        }
+        for(let projectID of projectIDs){
+            IDMapping[projectID].rate = 100;
+        }
+    }
+    console.log(IDMapping);
+    return IDMapping;
 }

+ 24 - 8
modules/pm/models/project_model.js

@@ -24,6 +24,7 @@ let feeRateFacade = require('../../fee_rates/facade/fee_rates_facade');
 let labourCoeFacade = require('../../main/facade/labour_coe_facade');
 let calcProgramFacade = require('../../main/facade/calc_program_facade');
 let installationFacade = require('../../main/facade/installation_facade');
+let pmFacade = require('../facade/pm_facade');
 let logger = require("../../../logs/log_helper").logger;
 let BillsModel = require("../../main/models/bills").model;
 let _ = require('lodash');
@@ -46,7 +47,7 @@ let ProjectsDAO = function () {
 let G_FILE_VER = '1.0.1';
 
 ProjectsDAO.prototype.getUserProjects = async function (userId, compilation, callback) {
-    try {
+    try {//
         let projects = await Projects.find({
             '$or': [{
                 'userID': userId,
@@ -55,14 +56,29 @@ ProjectsDAO.prototype.getUserProjects = async function (userId, compilation, cal
             }, {'userID': userId, 'compilation': compilation, 'deleteInfo.deleted': {'$in': [null, false]}}]
         }, '-_id');
         let projIDs= [];
-        let projIndex = {};
-        for(let proj of projects){
-            projIDs.push(proj.ID);
-            projIndex[proj.ID] = proj;
+        for(let project of projects){
+            if(project.projType === projectType.project){
+                projIDs.push(project.ID);
+            }
         }
-        let bills = await BillsModel.find({projectID: {$in : projIDs}, 'flags.flag': fixedFlag.ENGINEERINGCOST, 'fees.totalFee': {$exists: true}}, 'projectID fees');
-        for(let bill of bills){
-            projIndex[bill.projectID]._doc.engineeringCost = bill.fees[0].totalFee;
+        //test
+        let summaryInfo = await pmFacade.getSummaryInfo(projIDs);
+        //test
+        //设置汇总字段
+        for(let proj of projects){
+            let summaryProj = summaryInfo[proj.ID];
+            if(summaryProj){
+                proj._doc.engineeringCost = summaryProj.engineeringCost;
+                proj._doc.subEngineering = summaryProj.subEngineering;
+                proj._doc.measure = summaryProj.measure;
+                proj._doc.safetyConstruction = summaryProj.safetyConstruction;
+                proj._doc.other = summaryProj.other;
+                proj._doc.charge = summaryProj.charge;
+                proj._doc.tax = summaryProj.tax;
+                proj._doc.rate = summaryProj.rate;
+                proj._doc.buildingArea = summaryProj.buildingArea;
+                proj._doc.perCost = summaryProj.perCost;
+            }
         }
         callback(0, '', projects);
     }

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

@@ -25,6 +25,7 @@ module.exports = function (app) {
      req.body = {data: '{user_id}'}
      */
     pmRouter.post('/getProjects', pmController.getProjects);
+    pmRouter.post('/getSummaryInfo', pmController.getSummaryInfo);
 
     /*
      req.body = {data: '{user_id: user_id, updateData: [{updateType, updateData}]}'}

+ 6 - 0
public/web/common_util.js

@@ -50,4 +50,10 @@ function seqString(num,length){
         numstr = "0" + numstr;
     }
     return numstr;
+};
+
+function customRowHeader(sheet, dataLength) {
+    for (let i = 0; i < dataLength; i++) {
+        sheet.setValue(i, 0, `F${i + 1}`, GC.Spread.Sheets.SheetArea.rowHeader);
+    }
 }

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

@@ -42,6 +42,7 @@ var sheetCommonObj = {
         };
 
         sheet.showRowOutline(false);
+        sheet.options.allowCellOverflow = false;
         me.buildHeader(sheet, setting);
         if (rowCount > 0)
             sheet.setRowCount(rowCount);
@@ -567,6 +568,9 @@ var sheetCommonObj = {
                     let row = sheet.getActiveRowIndex();
                     let col = sheet.getActiveColumnIndex();
                     let orgV = sheet.getValue(row, col);
+                    let orgText = sheet.getText(row, col);
+                    console.log(`orgV: ${orgV}`);
+                    console.log(`orgText: ${orgText}`);
                     if(!isDef(orgV)){
                         orgV = '';
                     }

+ 31 - 12
web/building_saas/complementary_ration_lib/js/installation.js

@@ -13,9 +13,9 @@ let feeItemObj = {
     currentFeeItem: null,
     setting: {
         header:[
-            {headerName:"费用项",headerWidth:120,dataCode:"feeItem", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"},
-            {headerName:"费用类型",headerWidth:260,dataCode:"feeType", dataType: "String", hAlign: "center", vAlign: "center"},
-            {headerName:"记取位置",headerWidth:260,dataCode:"position", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"}
+            {headerName:"费用项",headerWidth:200,dataCode:"feeItem", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"},
+            {headerName:"费用类型",headerWidth:80,dataCode:"feeType", dataType: "String", hAlign: "center", vAlign: "center"},
+            {headerName:"记取位置",headerWidth:100,dataCode:"position", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"}
         ],
         view: {lockColumns: []},
         options: {
@@ -215,13 +215,13 @@ let feeRuleObj = {
     cache: [],
     setting: {
         header:[
-            {headerName:"编码",headerWidth:120,dataCode:"code", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"},
-            {headerName:"费用规则",headerWidth:240,dataCode:"rule", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"},
-            {headerName:"基数",headerWidth:120,dataCode:"base", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"},
-            {headerName:"费率(%)",headerWidth:120,dataCode:"feeRate", dataType: "String", formatter: "@", hAlign: "center", vAlign: "center"},
-            {headerName:"其中人工(%)",headerWidth:120,dataCode:"labour", dataType: "String", formatter: "@", hAlign: "center", vAlign: "center"},
-            {headerName:"其中材料(%)",headerWidth:120,dataCode:"material", dataType: "String", formatter: "@", hAlign: "center", vAlign: "center"},
-            {headerName:"其中机械(%)",headerWidth:120,dataCode:"machine", dataType: "String", formatter: "@", hAlign: "center", vAlign: "center"}
+            {headerName:"编码",headerWidth:80,dataCode:"code", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center", span:{row: 0, rowCount: 2, colCount: 1}},
+            {headerName:"费用规则",headerWidth:280,dataCode:"rule", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center", span:{row: 0, rowCount: 2, colCount: 1}},
+            {headerName:"基数",headerWidth:140,dataCode:"base", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center", span:{row: 0, rowCount: 2, colCount: 1}},
+            {headerName:"费率(%)",headerWidth:70,dataCode:"feeRate", dataType: "String", formatter: "@", hAlign: "center", vAlign: "center", span:{row: 0, rowCount: 2, colCount: 1}},
+            {headerName:"人工(%)",headerWidth:70,dataCode:"labour", dataType: "String", formatter: "@", hAlign: "center", vAlign: "center", span:{row: 1, rowCount: 1, colCount: 1}},
+            {headerName:"材料(%)",headerWidth:70,dataCode:"material", dataType: "String", formatter: "@", hAlign: "center", vAlign: "center", span:{row: 1, rowCount: 1, colCount: 1}},
+            {headerName:"机械(%)",headerWidth:70,dataCode:"machine", dataType: "String", formatter: "@", hAlign: "center", vAlign: "center", span:{row: 1, rowCount: 1, colCount: 1}}
         ],
         view: {lockColumns: []},
         options: {
@@ -242,12 +242,31 @@ let feeRuleObj = {
             workbook.options[opt] = opts[opt];
         }
     },
+    buildHeader: function () {
+        if(!this.sheet){
+            return;
+        }
+        this.sheet.suspendPaint();
+        this.sheet.suspendEvent();
+        let ch = GC.Spread.Sheets.SheetArea.colHeader;
+        this.sheet.setRowCount(2, ch);
+        for(let i = 0; i < this.setting.header.length; i++){
+            let header = this.setting.header[i];
+            this.sheet.addSpan(header.span.row, i, header.span.rowCount, header.span.colCount, ch);
+            this.sheet.setValue(header.span.row, i, header.headerName, ch);
+            if(header.dataCode === 'feeRate'){
+                this.sheet.addSpan(header.span.row, i + 1, 1, 3, ch);
+                this.sheet.setValue(header.span.row, i + 1, '其中', ch);
+            }
+        }
+        this.sheet.resumePaint();
+        this.sheet.resumeEvent();
+    },
     buildSheet: function () {
         if(!this.isDef(this.workBook)){
             this.workBook = sheetCommonObj.buildSheet($('#instFeeRuleSpread')[0], this.setting, 10);
-            console.log(`this.workBook`);
-            console.log(this.workBook);
             this.sheet = this.workBook.getActiveSheet();
+            this.buildHeader();
             this.setOptions(this.workBook, this.setting.options);
             this.bindEvents(this.sheet);
         }

+ 6 - 6
web/building_saas/complementary_ration_lib/js/repository_glj.js

@@ -42,12 +42,12 @@ repositoryGljObj = {
     distTypeTree: null,//add
     setting: {
         header:[
-            {headerName:"编码",headerWidth:120,dataCode:"code", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"},
-            {headerName:"名称",headerWidth:260,dataCode:"name", dataType: "String", hAlign: "left", vAlign: "center"},
-            {headerName:"规格型号",headerWidth:260,dataCode:"specs", dataType: "String", hAlign: "left", vAlign: "center"},
-            {headerName:"单位",headerWidth:120,dataCode:"unit", dataType: "String", hAlign: "center", vAlign: "center"},
-            {headerName:"定额价",headerWidth:120,dataCode:"basePrice", dataType: "Number", formatter: "0.00", hAlign: "right", vAlign: "center"},
-            {headerName:"类型",headerWidth:120,dataCode:"gljType", dataType: "String", hAlign: "center", vAlign: "center"}
+            {headerName:"编码",headerWidth:90,dataCode:"code", dataType: "String", formatter: "@", hAlign: "left", vAlign: "center"},
+            {headerName:"名称",headerWidth:200,dataCode:"name", dataType: "String", hAlign: "left", vAlign: "center"},
+            {headerName:"规格型号",headerWidth:110,dataCode:"specs", dataType: "String", hAlign: "left", vAlign: "center"},
+            {headerName:"单位",headerWidth:60,dataCode:"unit", dataType: "String", hAlign: "center", vAlign: "center"},
+            {headerName:"定额价",headerWidth:80,dataCode:"basePrice", dataType: "Number", formatter: "0.00", hAlign: "right", vAlign: "center"},
+            {headerName:"类型",headerWidth:90,dataCode:"gljType", dataType: "String", hAlign: "center", vAlign: "center"}
         ],
         view:{
             comboBox:[

+ 5 - 0
web/building_saas/css/custom.css

@@ -55,3 +55,8 @@ legend.legend{
 #gljPriceTenderCoe {
     -moz-appearance: textfield;
 }
+
+.modal-quantity-edit-height {
+    height: 200px;
+    overflow-y: auto;
+}

+ 35 - 17
web/building_saas/main/html/main.html

@@ -587,13 +587,17 @@
                                             <div class="row m-0">
                                                 <div class="col-sm-3">
                                                     <div class="input-group input-group-sm mb-2">
-                                                        <div class="input-group-addon">单价</div>
+                                                        <div class="input-group-prepend">
+                                                            <span class="input-group-text">单价</span>
+                                                        </div>
                                                         <input type="number" name="bills-unitPrice" class="form-control" value="2" step="1" max="6" min="0">
                                                     </div>
                                                 </div>
                                                 <div class="col-sm-3">
                                                     <div class="input-group input-group-sm mb-2">
-                                                        <div class="input-group-addon">合价</div>
+                                                        <div class="input-group-prepend">
+                                                            <span class="input-group-text">合价</span>
+                                                        </div>
                                                         <input type="number" name="bills-totalPrice" class="form-control" value="2" step="1" max="6" min="0">
                                                     </div>
                                                 </div>
@@ -602,40 +606,52 @@
                                             <div class="row m-0">
                                                 <div class="col-sm-3">
                                                     <div class="input-group input-group-sm mb-2">
-                                                        <div class="input-group-addon">工程量</div>
+                                                        <div class="input-group-prepend">
+                                                            <span class="input-group-text">工程量</span>
+                                                        </div>
                                                         <input type="number" name="ration-quantity" class="form-control" value="2" step="1" max="6" min="0">
                                                     </div>
                                                 </div>
                                                 <div class="col-sm-3">
                                                     <div class="input-group input-group-sm mb-2">
-                                                        <div class="input-group-addon">单价</div>
+                                                        <div class="input-group-prepend">
+                                                            <span class="input-group-text">单价</span>
+                                                        </div>
                                                         <input type="number" name="ration-unitPrice" class="form-control" value="2" step="1" max="6" min="0">
                                                     </div>
                                                 </div>
                                                 <div class="col-sm-3">
                                                     <div class="input-group input-group-sm mb-2">
-                                                        <div class="input-group-addon">合价</div>
+                                                        <div class="input-group-prepend">
+                                                            <span class="input-group-text">合价</span>
+                                                        </div>
                                                         <input type="number" name="ration-totalPrice" class="form-control" value="2" step="1" max="6" min="0">
                                                     </div>
                                                 </div>
                                             </div>
-                                            <h5 class="mt-3">人材机</h5>
+                                            <h5 class="mt-3">工料机</h5>
                                             <div class="row m-0">
-                                                <div style="width: 23.3%;">
-                                                    <div style="width:120px;" class="input-group input-group-sm mb-2">
-                                                        <div class="input-group-addon">消耗量</div>
+                                                <div class="col-sm-3">
+                                                    <div class="input-group input-group-sm mb-2">
+                                                        <div class="input-group-prepend">
+                                                            <span class="input-group-text">消耗量</span>
+                                                        </div>
                                                         <input type="number" name="glj-quantity" class="form-control" value="2" step="1" max="6" min="0">
                                                     </div>
                                                 </div>
-                                                <div  style="width: 38.3%;">
-                                                    <div style="width:190px;" class="input-group input-group-sm mb-2">
-                                                        <div class="input-group-addon">单价(有组成物)</div>
+                                                <div class="col-sm-4">
+                                                    <div class="input-group input-group-sm mb-2">
+                                                        <div class="input-group-prepend">
+                                                            <span class="input-group-text">单价<small class="text-muted">(有组成物)</small></span>
+                                                        </div>
                                                         <input type="number" name="glj-unitPriceHasMix" class="form-control" value="2" step="1" max="6" min="0">
                                                     </div>
                                                 </div>
-                                                <div style="width: 38.3%;">
-                                                    <div  style="width:190px;" class="input-group input-group-sm mb-2">
-                                                        <div class="input-group-addon">单价(无组成物)</div>
+                                                <div class="col-sm-4">
+                                                    <div class="input-group input-group-sm mb-2">
+                                                        <div class="input-group-prepend">
+                                                            <span class="input-group-text">单价<small class="text-muted">(无组成物)</small></span>
+                                                        </div>
                                                         <input type="number" name="glj-unitPrice" class="form-control" value="2" step="1" max="6" min="0">
                                                     </div>
                                                 </div>
@@ -644,7 +660,9 @@
                                             <div class="row m-0">
                                                 <div class="col-sm-3">
                                                     <div class="input-group input-group-sm mb-2">
-                                                        <div class="input-group-addon">费率</div>
+                                                        <div class="input-group-prepend">
+                                                            <span class="input-group-text">费率</span>
+                                                        </div>
                                                         <input type="number" name="feeRate" class="form-control" value="2" step="1" max="6" min="0">
                                                     </div>
                                                 </div>
@@ -1292,7 +1310,7 @@
                         </p>
                     </div>
                     <div class="row" >
-                        <div class=" col-12" style="overflow: hidden" id="quantityEditSpread">
+                        <div class="modal-quantity-edit-height col-12" style="overflow: hidden" id="quantityEditSpread">
                         </div>
                     </div>
 

+ 6 - 6
web/building_saas/main/js/models/calc_base.js

@@ -135,16 +135,16 @@ let cbTools = {
         mapObj['TAX'] = Object.create(null);
         mapObj['OTHERS'] = Object.create(null);
         mapObj['ENGINEERINGCOST'] = Object.create(null);
-        let filter = ['CSXMF', 'ZZCSXMF', 'ZZCSXMDEJJZJGCF', 'ZZCSXMDEJJRGF', 'ZZCSXMDEJJCLF', 'ZZCSXMDEJJJXF', 'QTXMF', 'GF', 'SJ', 'SQGCZJ', 'AQWMSGZXFY'];
+        let filter = ['CSXMF', 'ZZCSXMF', 'ZZCSXMDEJJZJGCF', 'ZZCSXMDEJJRGF', 'ZZCSXMDEJJCLF', 'ZZCSXMDEJJJXF', 'QTXMF', 'GF', 'SJ', 'SQGCZJ', 'AQWMSGZXF'];
         //安全文明施工专项费用只有税金和工程造价能用
         for(let figure in baseFigures){
             if(filter.indexOf(baseFigures[figure]['base']) === -1){
                 mapObj['CONSTRUCTION_ORGANIZATION'][figure] = baseFigures[figure];
             }
-            if(baseFigures[figure]['base'] !== 'QTXMF' && baseFigures[figure]['base'] !== 'SQGCZJ' && baseFigures[figure]['base'] !== 'AQWMSGZXFY'){
+            if(baseFigures[figure]['base'] !== 'QTXMF' && baseFigures[figure]['base'] !== 'SQGCZJ' && baseFigures[figure]['base'] !== 'AQWMSGZXF'){
                 mapObj['OTHER'][figure] = baseFigures[figure];
             }
-            if(baseFigures[figure]['base'] !== 'GF' && baseFigures[figure]['base'] !== 'SQGCZJ' && baseFigures[figure]['base'] !== 'AQWMSGZXFY'){
+            if(baseFigures[figure]['base'] !== 'GF' && baseFigures[figure]['base'] !== 'SQGCZJ' && baseFigures[figure]['base'] !== 'AQWMSGZXF'){
                 mapObj['CHARGE'][figure] = baseFigures[figure];
             }
             if(baseFigures[figure]['base'] !== 'SJ' && baseFigures[figure]['base'] !== 'SQGCZJ'){
@@ -153,7 +153,7 @@ let cbTools = {
             if(baseFigures[figure]['base'] !== 'SQGCZJ'){
                 mapObj['ENGINEERINGCOST'][figure] = baseFigures[figure];
             }
-            if(baseFigures[figure]['base'] !== 'SQGCZJ' && baseFigures[figure]['base'] !== 'AQWMSGZXFY'){
+            if(baseFigures[figure]['base'] !== 'SQGCZJ' && baseFigures[figure]['base'] !== 'AQWMSGZXF'){
                 mapObj['OTHERS'][figure] = baseFigures[figure];
             }
             if(baseFigures[figure]['base'] === 'SQGCZJ'){
@@ -553,7 +553,7 @@ let baseFigureTemplate = {
         if(cbTools.isUnDef(bill.feesIndex) || Object.keys(bill.feesIndex).length === 0) return 0;
         return cbTools.isDef(bill.feesIndex.common) && cbTools.isDef(bill.feesIndex.common[totalFeeType]) ? bill.feesIndex.common[totalFeeType] : 0;
     },
-    'AQWMSGZXFY': function (tender) {
+    'AQWMSGZXF': function (tender) {
         const totalFeeType = tender ? 'tenderTotalFee' : 'totalFee';
         let bill = calcBase.fixedBills[calcBase.fixedFlag.SAFETY_CONSTRUCTION]['bill'];
         if(cbTools.isUnDef(bill) || cbTools.isUnDef(bill.ID)) return 0;
@@ -1041,7 +1041,7 @@ let baseFigureMap = {
     '其他项目费': {base: 'QTXMF',  fixedFlag: fixedFlag.OTHER, class: 'QTXM'},
     '规费': {base: 'GF', fixedFlag: fixedFlag.CHARGE, class: 'GF'},
     '税金': {base: 'SJ', fixedFlag: fixedFlag.TAX, class: 'SJ'},
-    '安全文明施工专项费': {base: 'AQWMSGZXFY', fixedFlag: fixedFlag.SAFETY_CONSTRUCTION, class: 'CSXM'},
+    '安全文明施工专项费': {base: 'AQWMSGZXF', fixedFlag: fixedFlag.SAFETY_CONSTRUCTION, class: 'CSXM'},
     //不于清单直接关联==========
     '建筑面积': {base: 'JZMJ', class: 'FBFX'},
     '税前工程造价': {base: 'SQGCZJ', class: 'SQGCZJ'},//安全文明施工专项费用使用

+ 1 - 0
web/building_saas/main/js/models/quantity_detail.js

@@ -742,6 +742,7 @@ var quantity_detail = {
                             }
                             rationNode.data.quantity = scMathUtil.roundForObj(ration_value / times,getDecimal("quantity",rationNode));
                             rationNode.data.contain = scMathUtil.roundForObj(rationNode.data.quantity/value,getDecimal("process"));
+                            rationNode.changed = true;
                             needUpdateChildren.push(rationNode);
                             if (rationNode.children.length>0){//如果有子工料机
                                 gljNodes = gljNodes.concat(rationNode.children);

+ 14 - 1
web/building_saas/main/js/models/ration.js

@@ -664,7 +664,7 @@ var Ration = {
             }
 
             if(node.data.quantityEXP=="GCLMXHJ"){//如果定额工程量是来自工程量明细
-                hintBox.infoBox('操作确认', '已有工程量明细,是否清空明细表,采用手工输入的表达式?', 2, function () {
+                hintBox.infoBox('操作确认', '已有工程量明细,是否清空明细表?', 2, function () {
                     node.data.isFromDetail=0;
                     project.quantity_detail.cleanQuantityDetail(node,true);
                     me.doContainUpdate(value,node);
@@ -715,6 +715,19 @@ var Ration = {
             }
             return true;
         };
+        ration.prototype.canAdd = function (node) {     // CSL.2018.07.23
+            if (!node) return false;
+            if (calcTools.isRationCategory(node)) return true;
+            if (calcTools.isBill(node)){
+                if (node.data.type == billType.FX || node.data.type == billType.BX) return true;  // 分项、补项
+                if (calcTools.isLeafBill(node)
+                    && (node.data.type != billType.DXFY)
+                    && (node.data.type != billType.FB)
+                    && !project.Bills.isMeasure(node)) return true;  // 叶子清单项
+            };
+
+            return false;
+        }
         ration.prototype.getAllInstallTypeRation = function () {//取所有计取安装增加费生成的定额
             return _.filter(this.datas,{'type':rationType.install});
         };

+ 7 - 4
web/building_saas/main/js/views/calc_program_manage.js

@@ -70,7 +70,7 @@ let calcProgramManage = {
         feeRateObject.setFeeRateCellCol(dSheet,_.findIndex(me.detailSetting.header,{'dataCode':'feeRate'}));
         dSheet.getRange(-1, _.findIndex(me.detailSetting.header, {'dataCode': 'dispExprUser'}), -1, 1).cellType(calcBaseView.getCalcBaseCellType('ration'));
         sheetCommonObj.showData(dSheet, me.detailSetting, me.datas[0].calcItems);
-
+        customRowHeader(dSheet, me.datas[0].calcItems.length);
         if(!projectReadOnly){
             me.loadMainContextMenu();
             me.loadDetailContextMenu();
@@ -111,6 +111,7 @@ let calcProgramManage = {
         var dData = me.datas[row].calcItems;
         dSheet.setRowCount(dData.length, GC.Spread.Sheets.SheetArea.viewport);
         sheetCommonObj.showData(dSheet, me.detailSetting, dData);
+        customRowHeader(dSheet, dData.length);
         me.detailSpread.resumePaint();
     },
     onRangeChanged:function (sender,args) {
@@ -502,17 +503,19 @@ let calcProgramManage = {
             let detailSheet = me.detailSpread.getActiveSheet();
             detailSheet.setRowCount(calcItems.length);
             sheetCommonObj.showData(detailSheet, me.detailSetting, calcItems);
+            customRowHeader(detailSheet, calcItems.length);
         }
     }
-
 };
 
 $(document).ready(function(){
     $('#tab_calc_program_manage').on('shown.bs.tab', function (e) {
         sessionStorage.setItem('mainTab', '#tab_calc_program_manage');
         $(e.relatedTarget.hash).removeClass('active');
-        calcProgramManage.buildSheet();
-        // calcProgramManage.getStdCalcProgramFiles();
+        if (!calcProgramManage.mainSpread)
+            calcProgramManage.buildSheet()
+        else
+            calcProgramManage.mainSpread.refresh();
     });
 
     $("#calcProgramFileSelect").change(function() {

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

@@ -62,12 +62,14 @@ let calcProgramObj = {
         me.datas = treeNode.data.calcTemplate ? treeNode.data.calcTemplate.calcItems : [];
         sheetCommonObj.initSheet(me.sheet, me.setting, me.datas.length);
         sheetCommonObj.showData(me.sheet, me.setting, me.datas);
+        customRowHeader(me.sheet, me.datas.length);
     },
 
     clearData: function (){
         var me = this;
         me.treeNode = null;
         sheetCommonObj.cleanSheet(me.sheet, me.setting, -1);
+        customRowHeader(me.sheet, me.datas.length);
     }
 };
 

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

@@ -76,6 +76,9 @@ let ConfirmModal = {
             if (!this.spread) {
                 this.spread = SheetDataHelper.createNewSpread($('#std_bills_unit_spread')[0], {sheetCount: 1});
                 this.spread.options.showScrollTip = GC.Spread.Sheets.ShowScrollTip.vertical;
+                this.spread.bind(GC.Spread.Sheets.Events.CellDoubleClick, function (sender, args) {
+                    ConfirmModal.stdBillsUnit.okObj.click();
+                });
                 SheetDataHelper.loadSheetHeader(this.setting, this.spread.getActiveSheet());
             }
             let sheet = ConfirmModal.stdBillsUnit.spread.getActiveSheet();

+ 6 - 1
web/building_saas/main/js/views/fee_rate_view.js

@@ -198,7 +198,12 @@ var feeRateObject={
     },
     locate: function(){   // CSL,2018.07.18
         let sheet = feeRateObject.feeRateSpreads.getSheet(0);
-        let fID = calcProgramManage.getSelectionInfo().calcItem.feeRateID;
+
+        let fID = 0;
+        if ($("#calc_program_manage").is(":visible"))
+           fID = calcProgramManage.getSelectionInfo().calcItem.feeRateID
+        else if ($("#zaojiashu").is(":visible"))
+           fID = projectObj.project.mainTree.selected.data.feeRateID;
         let rates = projectObj.project.FeeRate.getActivateFeeRate().rates;
         let rowIdx = 0, pID = 0;
 

+ 7 - 1
web/building_saas/main/js/views/glj_view.js

@@ -883,7 +883,13 @@ var gljOprObj = {
     filterLibGLJByType: function () {
         var me = this;
         var selected = me.sheetData[gljContextMenu.selectedRow];
-        me.gljLibSheetData = _.filter(me.gljLibSheetData, {'gljType': selected.type});
+        //当前人材机类型是“混凝土、砂浆、配合比、商品混凝土、商品砂浆”时,筛选的可替换的人材机类型应是“混凝土、或砂浆、或配合比、或商品混凝土、或商品砂浆”。
+        let materialTypes = [202, 203, 204, 205, 206];//除了普通材料
+        let filterTypes = materialTypes.includes(selected.type) ? materialTypes : [selected.type];
+        me.gljLibSheetData = _.filter(me.gljLibSheetData, function (data) {
+            return filterTypes.includes(data.gljType);
+        });
+        //me.gljLibSheetData = _.filter(me.gljLibSheetData, {'gljType': selected.type});
     },
     getComboData: function (gljDistType) {
         let me = this;

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

@@ -42,6 +42,9 @@ let MainTreeCol = {
             }
         },
         code: function (node) {
+            if(!isDef(node)){
+                return '';
+            }
             if(node.sourceType === projectObj.project.Ration.getSourceType() && node.data.type === rationType.ration
                 && isDef(node.data.code) && isDef(node.data.prefix) && node.data.prefix !== ''){
                 return node.data.prefix + node.data.code.replace(new RegExp(node.data.prefix, 'g'), '');

+ 66 - 38
web/building_saas/main/js/views/project_view.js

@@ -160,7 +160,7 @@ var projectObj = {
             return false
         };
 
-        setButtonValid(canInsertRationNode(selected), $('#insertRation'));
+        setButtonValid(projectObj.project.Ration.canAdd(selected), $('#insertRation'));
         setButtonValid(ifCanDelete(), $('#delete'));
         setButtonValid(canUpLevel(selected), $('#upLevel'));
         setButtonValid(canDownLevel(selected), $('#downLevel'));
@@ -531,12 +531,6 @@ var projectObj = {
         let newV;
         if(node && node.sourceType === projectObj.project.Ration.getSourceType() && node.data.type === rationType.ration
             && isDef(node.data.code) && isDef(node.data.prefix) && node.data.prefix !== rationPrefix.none && fieldName === 'code'){
-/*            if(node.data.prefix === rationPrefix.complementary){
-                newV = orgV.replace(new RegExp(rationPrefix.complementary), '');
-            }
-            if(node.data.prefix === rationPrefix.borrow){
-                newV = orgV.replace(new RegExp(rationPrefix.borrow), '');
-            }*/
             if(node.data.prefix){
                 newV = orgV.replace(new RegExp(node.data.prefix), '');
             }
@@ -708,9 +702,9 @@ var projectObj = {
                 that.mainController.bind(TREE_SHEET_CONTROLLER.eventName.beforeTreeSelectedChange, that.beforeMainTreeSelectedChange);
                 that.mainController.bind(TREE_SHEET_CONTROLLER.eventName.treeSelectedChanged, that.treeSelectedChanged);
                 if(!projectReadOnly){
+                    that.mainSpreadEscKey(that.mainSpread, that.mainSpreadEditStarting, that.mainSpreadEditEnded);
                     sheetCommonObj.bindEnterKey(that.mainSpread, that.mainSpreadEnterKey);
                 }
-                sheetCommonObj.bindEscKey(that.mainSpread, [{sheet: that.mainSpread.getSheet(0), editStarting: that.mainSpreadEditStarting, editEnded: that.mainSpreadEditEnded}]);
                 setTimeout(function () {
                     that.mainSpread.getActiveSheet().startEdit();//这两句需要挺多时间,而又需要在editend 事件前触发,而这些又不影响计算,所以这里用异步的方法
                     that.mainSpread.getActiveSheet().endEdit();
@@ -756,6 +750,48 @@ var projectObj = {
         });
 
     },
+    //mainSpread有一些单元格进入编辑状态后,会动态改变值,公用的bindEscKey方法不适用
+    mainSpreadEscKey: function (workBook, editStarting = null, editEnded = null) {
+        workBook.commandManager().register('myEsc', function () {
+            let sheet = workBook.getActiveSheet();
+            if(editStarting){
+                sheet.unbind(GC.Spread.Sheets.Events.EditStarting);
+            }
+            if(editEnded){
+                sheet.unbind(GC.Spread.Sheets.Events.EditEnded);
+            }
+            let row = sheet.getActiveRowIndex();
+            let col = sheet.getActiveColumnIndex();
+            let orgV = sheet.getValue(row, col);
+            let node = projectObj.project.mainTree.items[row];
+            let field = colSettingObj.getFieldByCol(col);
+            //进入编辑状态后改变了单元格值的时候特殊处理
+            if(isDef(field) && field === 'code'){
+                if(node && node.sourceType === projectObj.project.Ration.getSourceType() && node.data.type === rationType.ration
+                    && isDef(node.data.code) && isDef(node.data.prefix) && node.data.prefix !== rationPrefix.none){
+                    orgV = node.data.prefix + orgV;
+                }
+            }
+            else if(isDef(field) && field === 'quantity'){
+                orgV = isDef(node) && isDef(node.data.quantity) ? node.data.quantity : '';
+            }
+            if(!isDef(orgV)){
+                orgV = '';
+            }
+            if(sheet.isEditing()){
+                sheet.endEdit();
+                sheet.setValue(row, col, orgV);
+            }
+            if(editStarting){
+                sheet.bind(GC.Spread.Sheets.Events.EditStarting, editStarting);
+            }
+            if(editEnded){
+                sheet.bind(GC.Spread.Sheets.Events.EditEnded, editEnded);
+            }
+        });
+        workBook.commandManager().setShortcutKey(null, GC.Spread.Commands.Key.esc, false, false, false, false);
+        workBook.commandManager().setShortcutKey('myEsc', GC.Spread.Commands.Key.esc, false, false, false, false);
+    },
     mainSpreadEnterKey: function () {
         let me = projectObj;
         let sheet = me.mainSpread.getActiveSheet();
@@ -982,47 +1018,52 @@ var projectObj = {
                          }
                      }
                 },
+                "spr1": '--------',
                 "insertRation": {
                     name: "插入定额",
                     icon: 'fa-sign-in',
                     disabled: function () {
-                        var selected = project.mainTree.selected;
-                        return project.Ration.addRationChecking(selected);  // Vincent, 2018-01-02
+                        // var selected = project.mainTree.selected;
+                        // return project.Ration.addRationChecking(selected);  // Vincent, 2018-01-02
+                        // 工具栏要加按钮,且不能隐藏。菜单可以隐藏,两者又必须统一,所以启用新规则。怕以后又要改回来,所以保留。 CSL, 2018-01-02
+                        return !project.Ration.canAdd(project.mainTree.selected);
                     },
                     callback: function (key, opt) {
                         project.Ration.addNewRation(null,rationType.ration);
                        // ProjectController.addRation(project, controller, rationType.ration);
-                    },
+                    }/*,
                     visible: function(key, opt){
                         var selected = project.mainTree.selected;
                         return canInsertRationNode(selected);
-                    }
+                    }*/
                 },
                 "insertLJ": {
                     name: "插入量价",
                     icon: 'fa-sign-in',
                     disabled: function () {
-                        var selected = project.mainTree.selected;
-                        return project.Ration.addRationChecking(selected);  // Vincent, 2018-01-02
+                        // var selected = project.mainTree.selected;
+                        // return project.Ration.addRationChecking(selected);  // Vincent, 2018-01-02
+                        return !project.Ration.canAdd(project.mainTree.selected);
                     },
                     callback: function (key, opt) {
                         project.Ration.addNewRation(null,rationType.volumePrice);
                        // ProjectController.addRation(project, controller, rationType.volumePrice);
-                    },
+                    }/*,
                     visible: function(key, opt){
                         var selected = project.mainTree.selected;
                         if(selected){
                            return canInsertRationNode(selected);
                         }
                        return false;
-                    }
+                    }*/
                 },
                 "insertGLJ": {
                     name: "插入人材机",
                     icon: 'fa-sign-in',
                     disabled: function () {
-                        var selected = project.mainTree.selected;
-                        return project.Ration.addRationChecking(selected);  // Vincent, 2018-01-02
+                        // var selected = project.mainTree.selected;
+                        // return project.Ration.addRationChecking(selected);  // Vincent, 2018-01-02
+                        return !project.Ration.canAdd(project.mainTree.selected);
                     },
                     callback: function (key, opt) {
                         var selected = project.mainTree.selected;
@@ -1035,15 +1076,16 @@ var projectObj = {
                             }
                         }
                         getGLJData('insert');// ProjectController.addRation(project, controller, rationType.volumePrice);
-                    },
+                    }/*,
                     visible: function(key, opt){
                         var selected = project.mainTree.selected;
                         if(selected){
                           return canInsertRationNode(selected);
                         }
                         return false;
-                    }
+                    }*/
                 },
+                "spr2": '--------',
                 "calc_installation_fee": {
                     name: "计取安装费用",
                     icon: 'fa-sign-in',
@@ -1058,7 +1100,6 @@ var projectObj = {
                         return engineering==engineeringType.BUILD_IN;
                     }
                 },
-                "spr1": '--------',
                 "delete": {
                     name: '删除',
                     icon: 'fa-remove',
@@ -1074,14 +1115,13 @@ var projectObj = {
                         }
                     }
                 },
-                "spr2":'--------',
                 "calculateAll_RationContent": {
                     name: '造价计算',
                     callback: function () {
                         project.calcProgram.calcAllNodesAndSave();
                     }
                 },
-                "spr2":'--------',
+                "spr4":'--------',
                 "copyBlock": {
                     name: '复制整块',
                     icon: 'fa-copy',
@@ -1109,7 +1149,6 @@ var projectObj = {
 
                     }
                 },
-                "spr2":'--------',
                 "pasteBlock": {
                     name: '粘贴整块',
                     icon: 'fa-paste',
@@ -1627,6 +1666,9 @@ $('#downLevel').click(function () {
         projectObj.converseCalculateBills(selected.parent);
     }
 });
+$('#insertRation').click(function () {
+    projectObj.project.Ration.addNewRation(null,rationType.ration);
+});
 $('#upMove').click(function () {
     var controller = projectObj.mainController, project = projectObj.project;
     var selected = controller.tree.selected, pre = selected.preSibling, preSerialNo;
@@ -2139,20 +2181,6 @@ function canInsertRationNode(selected) {//判断是否能插入定额、量价
     else {
         return true
     }
-
-/*    if (selected) {// Vincent, 2018-01-02
-        if(selected.sourceType === project.Ration.getSourceType()){ // 焦点行是定额/量价/工料机,有效显示。
-            return false;
-        }else if(selected.sourceType === project.Bills.getSourceType()){
-            if(selected.data.type == billType.FX || selected.data.type == billType.BX){//焦点行是分项,有效显示。
-                return false
-            }
-            if(selected.data.type == billType.BILL && selected.source.children.length === 0){//焦点行是清单,且没有子项,有效显示。
-                return false
-            }
-        }
-    }
-    return true;*/
 }
 
 //导入类型(09表、广联达)

+ 23 - 10
web/building_saas/main/js/views/quantity_edit_view.js

@@ -17,6 +17,8 @@ let quantityEditObj = {
         if(!this.spread){
             this.spread = SheetDataHelper.createNewSpread($("#quantityEditSpread")[0]);
             this.initSheet();
+        }else {
+            this.spread.refresh();
         }
         this.showData();
     },
@@ -172,30 +174,42 @@ let quantityEditObj = {
         if(project.isBillsLocked() && project.withinBillsLocked(project.mainTree.selected)){
             return;
         }
+        this.initModalContent();
         $("#quantityEXPEdit").modal({show:true});
     },
+    initModalContent:function () {
+        let selected = projectObj.project.mainTree.selected;
+        if(selected.sourceType == ModuleNames.ration){//暂时只有定额才有基数选择,所以其它的先隐藏表格
+            $("#quantityEditSpread").show();//quantityEditSpread
+        }else {
+            $("#quantityEditSpread").hide();
+        }
+        $("#quantityEXPValue").val(selected.data.quantityEXP);
+    },
     checkingAndUpdate(quantityEXP,node){
         let me = this;
-        quantityEXP = quantityEXP.toUpperCase();
+        quantityEXP = quantityEXP?quantityEXP.toUpperCase():'';//非空判断
         if(quantityEXP === node.data.quantityEXP){ //没有变化,不做任何操作
             projectObj.mainController.refreshTreeNode([node]);
-            return;
+            return true;
         }
         let value = me.evalQuantityExp(quantityEXP,node);
         if(value!=='evalError'){
             if(node.data.hasOwnProperty('isFromDetail')&&node.data.isFromDetail==1){
-                hintBox.infoBox('操作确认', '已有工程量明细,是否清空明细表,采用手工输入的表达式?', 2, function () {
+                hintBox.infoBox('操作确认', '已有工程量明细,是否清空明细表?', 2, function () {
                     node.data.isFromDetail=0;
                     me.updateQuantityEXP(value,quantityEXP,node);
                 }, function () {
                     projectObj.mainController.refreshTreeNode([node]);
                 },['确定','取消'],false);
-                return;
+                return true;
             }
             me.updateQuantityEXP(value,quantityEXP,node);
+            return true;
         }else {
             projectObj.mainController.refreshTreeNode([node]);
         }
+        return false;
     },
     evalQuantityExp(quantityEXP,node){
         let evalString = quantityEXP;
@@ -209,7 +223,7 @@ let quantityEditObj = {
             return value;
         }catch (error){
             alert("输入的表达式有误,请重新输入!");
-            return "evalError"
+            return "evalError";
         }
     },
     updateQuantityEXP:function (value,quantityEXP,node) {
@@ -217,7 +231,6 @@ let quantityEditObj = {
         quantity_detail.cleanQuantityDetail(node,true);
         if(node.sourceType === ModuleNames.bills){
             quantity_detail.updateBillQuantity(value,node,quantityEXP,quantityEXP);
-            //me.updateBillQuantity(value,node,null,editingText);
         }else {
             quantity_detail.updateRationQuantity(value,node,quantityEXP,quantityEXP);
         }
@@ -226,8 +239,6 @@ let quantityEditObj = {
 };
 $(function(){
     $('#quantityEXPEdit').on('shown.bs.modal', function (e) {
-        let selected = projectObj.project.mainTree.selected;
-        $("#quantityEXPValue").val(selected.data.quantityEXP);
         quantityEditObj.initSpread();
     });
 
@@ -239,8 +250,10 @@ $(function(){
 
     $("#quantityEditConf").bind('click',function () {
         let selected = projectObj.project.mainTree.selected;
-        quantityEditObj.checkingAndUpdate($("#quantityEXPValue").val(),selected);
-        $("#quantityEXPEdit").modal('hide');
+        let result = quantityEditObj.checkingAndUpdate($("#quantityEXPValue").val(),selected);
+        if(result == true){
+            $("#quantityEXPEdit").modal('hide');
+        }
     })
 
 

+ 36 - 0
web/building_saas/main/js/views/sub_view.js

@@ -140,6 +140,40 @@ $("#linkTZJNR").click(function () {
     gljOprObj.activeTab='#linkTZJNR';
 });
 
+//应用到选中清单、应用到所有,添加位置列如果隐藏了,则重新显示
+function colSettingAddPosition(addPosition){
+    let settingMapping = {1: 'itemCharacterText', 2: 'name', 3: 'jobContentText', 4: 'both'};
+    let settingInfo = settingMapping[addPosition];
+    if(!settingInfo){
+        return;
+    }
+    let fields = [];
+    if(settingInfo === 'both'){
+        fields = [settingMapping['1'], settingMapping['3']];
+    }
+    else{
+        fields = [settingInfo];
+    }
+    let needToUpdate = false;
+    let showItemCharacter = false;
+    for(let field of fields){
+        let colVisible = colSettingObj.getVisible(field);
+        if(field === settingMapping['1'] && !colVisible){
+            showItemCharacter = true;
+        }
+        if(!colVisible){
+            colSettingObj.setVisible(field, true);
+            needToUpdate = true;
+        }
+    }
+    if(showItemCharacter){
+        switchTznrHtml(false);
+    }
+    if(needToUpdate){
+       colSettingObj.updateColSetting(true);
+    }
+}
+
 // 应用到选中清单
 let isSaving = false;
 $("#use-to-current").click(function() {
@@ -150,6 +184,7 @@ $("#use-to-current").click(function() {
         return false;
     }
     const setting = getAddRuleSetting();
+    colSettingAddPosition(setting.position);
     isSaving = true;
     const self = $(this);
     self.attr('disabled', 'disabled');
@@ -177,6 +212,7 @@ $("#use-to-all").click(function() {
     }
     let treeNode = projectObj.mainController.tree;
     const setting = getAddRuleSetting();
+    colSettingAddPosition(setting.position);
     if (treeNode.items === undefined || treeNode.items.length <= 0) {
         return false;
     }

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

@@ -417,11 +417,11 @@ $(function () {
         $(e.relatedTarget.hash).removeClass('active');
         if(!tender_obj.tenderSpread){
             tender_obj.initTenderSpread();
+            tender_obj.showTenderData();
+            tender_obj.initPageContent();
         }
         autoFlashHeight();
         tender_obj.tenderSpread.refresh();
-        tender_obj.showTenderData();
-        tender_obj.initPageContent();
     });
 
     $('#tenderGLJQuantity').bind('click',function () {

+ 110 - 17
web/building_saas/pm/js/pm_newMain.js

@@ -29,6 +29,10 @@ let taxTypeMap = {
     2:"简易计税"
 };
 
+function isDef(v) {
+    return typeof v !== 'undefined' && v !== null;
+}
+
 const projTreeObj = {
     tree: null,
     workBook: null,
@@ -43,12 +47,22 @@ const projTreeObj = {
             rootId: -1,
             autoUpdate: false
         },
+        //0.48 0.13 0.15 0.15 0.09
         header: [
-            {name: '工程列表', dataCode: 'name', width: 0.48, vAlign: 'center', hAlign: 'left'},
-            {name: '工程造价', dataCode: 'engineeringCost', width: 0.13, vAlign: 'center', hAlign: 'right'},
-            {name: '单价文件', dataCode: 'unitPriceFile', width: 0.15, vAlign: 'center', hAlign: 'left'},
-            {name: '费率文件', dataCode: 'feeRateFile', width: 0.15, vAlign: 'center', hAlign: 'left'},
-            {name: '创建日期', dataCode: 'createDateTime', width: 0.09, vAlign: 'center', hAlign: 'center'}
+            {name: '工程列表', dataCode: 'name', width: 300, vAlign: 'center', hAlign: 'left'},
+            {name: '工程造价', dataCode: 'engineeringCost', width: 120, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
+            {name: '分部分项合计', dataCode: 'subEngineering', width: 120, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
+            {name: '措施项目合计', dataCode: 'measure', width: 120, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
+            {name: '其他项目合计', dataCode: 'other', width: 120, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
+            {name: '安全文明施工费', dataCode: 'safetyConstruction', width: 120, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
+            {name: '规费', dataCode: 'charge', width: 120, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
+            {name: '税金', dataCode: 'tax', width: 120, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
+            {name: '占造价比例(%)', dataCode: 'rate', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
+            {name: '建筑面积', dataCode: 'buildingArea', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
+            {name: '单方造价', dataCode: 'perCost', width: 100, vAlign: 'center', hAlign: 'right', formatter: '0.00'},
+            {name: '单价文件', dataCode: 'unitPriceFile', width: 140, vAlign: 'center', hAlign: 'left'},
+            {name: '费率文件', dataCode: 'feeRateFile', width: 140, vAlign: 'center', hAlign: 'left'},
+            {name: '创建日期', dataCode: 'createDateTime', width: 100, vAlign: 'center', hAlign: 'center'}
         ],
         //选中行颜色
         style: {
@@ -118,8 +132,11 @@ const projTreeObj = {
             let workBookWidth = getWorkBookWidth();
             for(let i = 0, len = headers.length; i < len; i++){
                 sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
-                let width = workBookWidth * headers[i].width;
+                let width = headers[i].width;
                 sheet.setColumnWidth(i, width, GC.Spread.Sheets.SheetArea.colHeader);
+                if (headers[i].formatter) {
+                    sheet.setFormatter(-1, i, headers[i].formatter, GC.Spread.Sheets.SheetArea.viewport);
+                }
             }
         };
         me.renderSheetFuc(sheet, fuc);
@@ -307,6 +324,30 @@ const projTreeObj = {
                             });
                         }, 500);
                     }
+                },
+                "refreshSummary": {
+                    name: "刷新当前项目造价",
+                    icon: 'fa-refresh',
+                    disabled: function () {
+                        let selectedItem = projTreeObj.tree.selected;
+                        return !(selectedItem && selectedItem.data.projType !== projectType.folder);
+                    },
+                    callback: function (key, opt) {
+                        //获取当前节点的建设项目ID
+                        let project = projTreeObj.tree.selected;
+                        while (project.data.projType !== projectType.project && project.parent){
+                            project = project.parent;
+                        }
+                        if(project && project.data.ID){
+                            $.bootstrapLoading.start();
+                            CommonAjax.post('/pm/api/getSummaryInfo', {user_id: userID, projectIDs: [project.data.ID]}, function (summaryInfo) {
+                                refreshProjSummary(project, summaryInfo);
+                                $.bootstrapLoading.end();
+                            }, function () {
+                                $.bootstrapLoading.start();
+                            });
+                        }
+                    }
                 }
             }
         });
@@ -819,13 +860,7 @@ const projTreeObj = {
         const {row, col} = cell;
         let dataCode = this.setting.header[col]['dataCode'];
         let value = '';
-        if(dataCode === 'engineeringCost'){
-            if(node.data.projType !== projectType.folder){//显示除了文件夹节点的工程造价结果 -- vincent
-                value =  node.data.engineeringCost ? node.data.engineeringCost : '0.00';
-                value = scMathUtil.roundToString(value,2);
-            }
-        }
-        else if(dataCode === 'unitPriceFile'){
+        if(dataCode === 'unitPriceFile'){
             if(node.data.projType === projectType.tender){
                 value = node.data.property && node.data.property.unitPriceFile && node.data.property.unitPriceFile.name ? node.data.property.unitPriceFile.name : '';
             }
@@ -839,7 +874,7 @@ const projTreeObj = {
             value = node.data.createDateTime ? new Date(node.data.createDateTime).Format('yyyy-MM-dd') : '';
         }
         else {
-            value = node.data[dataCode] ? node.data[dataCode] : '';
+            value = isDef(node.data[dataCode]) ? node.data[dataCode] : '';
         }
         sheet.setValue(row, col, value);
     },
@@ -1028,7 +1063,7 @@ const projTreeObj = {
 $(document).ready(function() {
     //列宽随着屏幕改变
     $(window).resize(function () {
-        autoPmWdith(projTreeObj.workBook, projTreeObj.setting.header);
+        //autoPmWdith(projTreeObj.workBook, projTreeObj.setting.header);
         autoPmWdith(gcTreeObj.workBook, gcTreeObj.setting.header);
         autoPmWdith(pmShare.spreadObj.workBook, pmShare.headers)
 
@@ -1672,12 +1707,30 @@ function getChangedFunc(input, nameInfo){
             nameInfo.show();
         }
         else {
-            nameInfo.text('');N
+            nameInfo.text('');
             nameInfo.hide();
         }
     }
 }
 
+//新增节点,初始化汇总数值
+function setInitSummaryData(data) {
+    if(data.projType === projectType.folder){
+        return;
+    }
+    //just for View
+    data.engineeringCost = 0;
+    data.subEngineering = 0;
+    data.measure = 0;
+    data.safetyConstruction = 0;
+    data.other = 0;
+    data.charge = 0;
+    data.tax = 0;
+    data.rate = data.projType === projectType.project ? 100 : 0;
+    data.buildingArea = '';
+    data.perCost = '';
+}
+
 function AddTenderItems(selected, projName, engName, tenderName, property, callback){
     const addPath = {p_e_t: 'p_e_t', e_t: 'e_t', t: 't'};
     let path, updateDatas = [];
@@ -1727,6 +1780,7 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
                 let projData, engData, tenderData;
                 datas.forEach(function (data) {
                     if (data.updateType === 'new') {
+                        setInitSummaryData(data.updateData);
                         if(data.updateData.projType === projectType.project){
                             projData = data.updateData;
                         }
@@ -1767,6 +1821,7 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
                 let engData, tenderData;
                 datas.forEach(function (data) {
                     if (data.updateType === 'new') {
+                        setInitSummaryData(data.updateData);
                         if(data.updateData.projType === projectType.engineering){
                             engData = data.updateData;
                         }
@@ -1794,6 +1849,7 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
             UpdateProjectData(updateDatas, function (datas) {
                 datas.forEach(function (data) {
                     if(data.updateType === 'new') {
+                        setInitSummaryData(data.updateData);
                         projTreeObj.insert(data.updateData, tempEng, null);
                     }
                 });
@@ -1832,6 +1888,7 @@ function AddChildrenItem(selected, name, property, type, existCallback, sucCallb
             UpdateProjectData(updateData, function(datas){
                 datas.forEach(function (data) {
                     if (data.updateType === 'new') {
+                        setInitSummaryData(data.updateData);
                         projTreeObj.insert(data.updateData, parent, null);
                     }
                 });
@@ -1870,6 +1927,7 @@ function AddSiblingsItem(selected, name, property, type, existCallback, sucCallb
             UpdateProjectData(updateData, function(datas){
                 datas.forEach(function (data) {
                     if (data.updateType === 'new') {
+                        setInitSummaryData(data.updateData);
                         projTreeObj.insert(data.updateData, parent, next);
                     }
                 });
@@ -2291,7 +2349,11 @@ function getAddTenderFile(tenderName, selected, options){
     //选择的是新建单价/费率文件
     if(selValue === ''){
         //若新建的单位工程名称与建设项目下文件重名,则引用该文件
-        for(let option of options){
+        for(let i = 0; i < options.length; i++){
+            if(i === 0){
+                continue;
+            }
+            let option = options[i];
             if($(option).text() === tenderName){
                 rst.id = $(option).val();
                 break;
@@ -3097,3 +3159,34 @@ $('#allowCopy').change(function () {
         $('#allowCopyHint').hide();
     }
 });
+
+//刷新建设项目汇总金额信息
+function refreshProjSummary(project, summaryInfo) {
+    let refreshNodes = [];
+    refreshNodes.push(project);
+    getNodes(project);
+    function getNodes(node) {
+        if(node.children.length > 0){
+            refreshNodes = refreshNodes.concat(node.children);
+            for(let cNode of node.children){
+                getNodes(cNode);
+            }
+        }
+    }
+    for(let node of refreshNodes){
+        let nodeInfo = summaryInfo[node.data.ID];
+        if(nodeInfo){
+            node.data.engineeringCost = nodeInfo.engineeringCost;
+            node.data.subEngineering = nodeInfo.subEngineering;
+            node.data.measure = nodeInfo.measure;
+            node.data.safetyConstruction = nodeInfo.safetyConstruction;
+            node.data.other = nodeInfo.other;
+            node.data.charge = nodeInfo.charge;
+            node.data.tax = nodeInfo.tax;
+            node.data.rate = nodeInfo.rate;
+            node.data.buildingArea = nodeInfo.buildingArea;
+            node.data.perCost = nodeInfo.perCost;
+        }
+    }
+    projTreeObj.refreshNodeData(refreshNodes);
+}