浏览代码

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

TonyKang 7 年之前
父节点
当前提交
46a86b9fa9

+ 24 - 0
modules/main/controllers/installation_controller.js

@@ -0,0 +1,24 @@
+/**
+ * Created by zhang on 2018/2/5.
+ */
+var installation_facade = require('../facade/installation_facade');
+let logger = require("../../../logs/log_helper").logger;
+module.exports={
+    updateInstallationFee:updateInstallationFee
+}
+async function  updateInstallationFee(req, res) {
+    let result={
+        error:0
+    }
+    try {
+        let data = req.body.data;
+        data = JSON.parse(data);
+        let datas= await installation_facade.updateInstallationFee(data.projectID,data.updateData);
+        result.data=datas;
+    }catch (err){
+        logger.err(err);
+        result.error=1;
+        result.message = err.message;
+    }
+    res.json(result);
+}

+ 62 - 5
modules/main/facade/installation_facade.js

@@ -9,8 +9,60 @@ let consts = require('../../main/models/project_consts')
 
 module.exports={
     copyInstallationFeeFromLib:copyInstallationFeeFromLib,
+    updateInstallationFee:updateInstallationFee,
     getData:getData
 };
+async function updateInstallationFee(projectID,updateData) {
+    let result = {};
+    let tasks = generateUpdateTask(projectID,updateData);
+    if(tasks.length>0){
+         result =await installationFeeModel.bulkWrite(tasks);
+    }
+    return result;
+}
+
+function generateUpdateTask(projectID,updateData) {
+    let tasks = [];
+    if(updateData){
+        if(updateData instanceof Array){
+            for(let ud of updateData){
+                let [uquery,udoc] = createUpdateQuery(projectID,ud);
+                let task={
+                    updateOne:{
+                        filter:uquery,
+                        update :udoc
+                    }
+                };
+                tasks.push(task);
+            }
+        } else {
+            let [query,doc] = createUpdateQuery(projectID,updateData);
+            let task={
+                updateOne:{
+                    filter:query,
+                    update :doc
+                }
+            };
+            tasks.push(task);
+        }
+    }
+    return tasks;
+
+}
+
+function createUpdateQuery(projectID,data) {
+    let updateKey = data.type+'.ID';
+    let query = {
+        projectID:projectID,
+        ID:data.ID,
+    };
+    query[updateKey] = data.itemID;
+    let udoc = {};
+    for(let property in data.doc){
+        udoc[data.type+'.$.'+property] = data.doc[property];
+    }
+    return [query,udoc];
+}
 
 async function copyInstallationFeeFromLib(projectID,engineering_id) {
 
@@ -21,6 +73,7 @@ async function copyInstallationFeeFromLib(projectID,engineering_id) {
     for(let rl of ration_lib){
        let installFeeItems = await installFeeItemModel.find({'rationRepId':rl.id});
        let installSections = await installSectionModel.find({'rationRepId':rl.id});
+       let positionMap = {};
        let newInstallationFee = {
            libID:rl.id,
            libName:rl.name,
@@ -38,6 +91,7 @@ async function copyInstallationFeeFromLib(projectID,engineering_id) {
                     position:ifee.position,
                     ID:ifee.ID
                 };
+               positionMap[ifee.ID] = ifee.position;//设置选取位置对应表,为给规项赋值
                tem_installFeeItem.push(tem_fee);
            }
            newInstallationFee.installFeeItem = tem_installFeeItem;
@@ -50,8 +104,8 @@ async function copyInstallationFeeFromLib(projectID,engineering_id) {
            for(let isect of installSections){
                 let tem_sec={
                     ID:isect.ID,
-                    feeItemId:isect.feeItemId,
-                    name:isect.name
+                    name:isect.name,
+                    feeItemId:isect.feeItemId
                 };
                 if(isect.feeRule && isect.feeRule.length > 0){//规则项
                     tem_sec.feeRuleId = isect.feeRule[0].ID; //选中第一个
@@ -64,12 +118,15 @@ async function copyInstallationFeeFromLib(projectID,engineering_id) {
                             feeRate: ifeeR.feeRate,
                             labour: ifeeR.labour,
                             material: ifeeR.material,
-                            machine: ifeeR.machine
+                            machine: ifeeR.machine,
+                            sectionId:isect.ID,
+                            feeItemId:isect.feeItemId,
+                            position:positionMap[isect.feeItemId]
                         };
-                        tem_feeRule.sectionId = isect.ID;
-                        tem_feeRule.feeItemId = isect.feeItemId;
                         tem_feeRules.push(tem_feeRule);
                     }
+                }else {
+                    tem_sec.feeRuleId = "";
                 }
                tem_installSections.push(tem_sec);
            }

+ 7 - 4
modules/main/models/installation_fee.js

@@ -15,7 +15,9 @@ let feeRuleSchema = new Schema({
     feeRate: Number,
     labour: Number,
     material: Number,
-    machine: Number
+    machine: Number,
+    position: String,//记取位置
+    billID:String//记取位置对应的清单ID
 });
 
 //安装增加费-分册章节
@@ -23,8 +25,7 @@ let installSectionSchema = new Schema({
     ID: String,
     feeItemId: String,
     feeRuleId: String,
-    name: String,
-    position: String//记取位置
+    name: String
 });
 
 //安装增加费-费用项
@@ -32,7 +33,9 @@ let installFeeItemSchema = new Schema({
     ID: String,
     feeItem: String, //费用项
     feeType: String, //费用类型
-    position: String//记取位置
+    position: String,//记取位置
+    billID:String,//记取位置对应的清单ID
+    isCal: {type: Number,default:0}//是否记取0:false 1:true
 });
 
 let installationFeeSchema = new Schema({

+ 15 - 0
modules/main/routes/installation_route.js

@@ -0,0 +1,15 @@
+/**
+ * Created by zhang on 2018/2/5.
+ */
+
+let express = require('express');
+let installationController = require('../controllers/installation_controller');
+
+module.exports = function (app) {
+    let installationRouter = express.Router();
+
+    installationRouter.post('/updateInstallationFee', installationController.updateInstallationFee);
+
+
+    app.use('/installation',installationRouter);
+};

+ 4 - 1
public/web/id_tree.js

@@ -664,7 +664,10 @@ var idTree = {
         Tree.prototype.bind = function (eventName, eventFun) {
             this.event[eventName] = eventFun;
         };
-
+        Tree.prototype.getNodeByID = function (ID) {
+            let node = this.nodes[this.prefix+ID];
+            return node;
+        };
         return new Tree(setting);
     },
     updateType: {update: 'update', new: 'new', delete: 'delete'}

+ 134 - 31
public/web/sheet/sheet_common.js

@@ -135,42 +135,62 @@ var sheetCommonObj = {
                 sheet.setValue(0, col, setting.header[col].headerName, header);
                 sheet.setColumnWidth(col, setting.header[col].headerWidth?setting.header[col].headerWidth:100);
             }
-            for (var row = 0; row < data.length; row++) {
-                //var cell = sheet.getCell(row, col, GC.Spread.Sheets.SheetArea.viewport);
-                var val = data[row][setting.header[col].dataCode];
-                if(val&&setting.header[col].dataType === "Number"){
-                    if(setting.header[col].hasOwnProperty('tofix')){
-                        val =scMathUtil.roundToString(val,setting.header[col].tofix);
-                    }
-                    else if(setting.header[col].hasOwnProperty('decimalField')){
-                        var decimal = getDecimal(setting.header[col].decimalField);
-                        val =scMathUtil.roundToString(val,decimal);
-                        sheet.setFormatter(-1, col,getFormatter(decimal), GC.Spread.Sheets.SheetArea.viewport);
-                    }else {
-                        val =scMathUtil.roundToString(val,2);
-                    }
-                }
-                if(val!=null&&setting.header[col].cellType === "checkBox"){
-                    this.setCheckBoxCell(row,col,sheet,val)
-                 }
-                 if(setting.owner==='gljTree'){
-                    if(setting.header[col].cellType === "checkBox"){
-                        val==1?val:0;
-                        this.setCheckBoxCell(row,col,sheet,val);
-                    }
-                    if(setting.header[col].dataCode === 'gljType' && data[row].gljType){
-                        let distTypeVal =  distTypeTree.distTypes[distTypeTree.prefix + data[row].gljType].data.fullName;
-                        val=distTypeVal;
-                    }
-                 }
-                sheet.setValue(row, col, val, ch);
-            }
+        }
+        for (var row = 0; row < data.length; row++) {
+            //var cell = sheet.getCell(row, col, GC.Spread.Sheets.SheetArea.viewport);
+            this.showRowData(sheet,setting,row,data,distTypeTree);
         }
         this.lockCells(sheet,setting);
         sheet.resumeEvent();
         sheet.resumePaint();
         //me.shieldAllCells(sheet);
     },
+    showRowData:function (sheet,setting,row,data,distTypeTree=null) {
+        let ch = GC.Spread.Sheets.SheetArea.viewport;
+        for (var col = 0; col < setting.header.length; col++) {
+            //var cell = sheet.getCell(row, col, GC.Spread.Sheets.SheetArea.viewport);
+            var val = data[row][setting.header[col].dataCode];
+            if(val&&setting.header[col].dataType === "Number"){
+                if(setting.header[col].hasOwnProperty('tofix')){
+                    val =scMathUtil.roundToString(val,setting.header[col].tofix);
+                }
+                else if(setting.header[col].hasOwnProperty('decimalField')){
+                    var decimal = getDecimal(setting.header[col].decimalField);
+                    val =scMathUtil.roundToString(val,decimal);
+                    sheet.setFormatter(-1, col,getFormatter(decimal), GC.Spread.Sheets.SheetArea.viewport);
+                }else {
+                    val =scMathUtil.roundToString(val,2);
+                }
+            }
+            if(val!=null&&setting.header[col].cellType === "checkBox"){
+                this.setCheckBoxCell(row,col,sheet,val)
+            }
+            if(setting.header[col].cellType === "comboBox"){
+                this.setComboBox(row,col,sheet,setting.header[col].options);
+            }
+            if(setting.header[col].cellType === "selectButton"){
+                this.setSelectButton(row,col,sheet,setting.header[col]);
+            }
+            if(setting.owner==='gljTree'){
+                if(setting.header[col].cellType === "checkBox"){
+                    val==1?val:0;
+                    this.setCheckBoxCell(row,col,sheet,val);
+                }
+                if(setting.header[col].dataCode === 'gljType' && data[row].gljType){
+                    let distTypeVal =  distTypeTree.distTypes[distTypeTree.prefix + data[row].gljType].data.fullName;
+                    val=distTypeVal;
+                }
+            }
+            if(setting.header[col].getText){
+                val = setting.getText[setting.header[col].getText](data[row],val)
+            }
+            sheet.setValue(row, col, val, ch);
+        }
+        if(setting.autoFit==true){
+            sheet.getRange(row, -1, 1, -1, GC.Spread.Sheets.SheetArea.viewport).wordWrap(true);
+            sheet.autoFitRow(row);
+        }
+    },
     analyzePasteData: function(setting, pastedInfo) {
         var rst = [], propId = pastedInfo.cellRange.col, preStrIdx = 0, itemObj = {};//propId = 0 to proId = pastedInfo.cellRange.col, update by zhong
         for (var i = 0; i < pastedInfo.pasteData.text.length; i++) {
@@ -227,6 +247,90 @@ var sheetCommonObj = {
         sheet.getCell(row, col).hAlign(GC.Spread.Sheets.HorizontalAlign.center);
 
     },
+    setComboBox(row,col,sheet,options){
+        //let combo = new GC.Spread.Sheets.CellTypes.ComboBox();
+        let dynamicCombo = sheetCommonObj.getDynamicCombo(true);
+        dynamicCombo.itemHeight(options.length).items(options);
+        sheet.setCellType(row, col,dynamicCombo,GC.Spread.Sheets.SheetArea.viewport);
+    },
+    setSelectButton(row,col,sheet,header){
+        let getSelectButton = function (cellWidth=100) {
+            function moreButton() {
+
+            }
+            moreButton.prototype = new GC.Spread.Sheets.CellTypes.Button();
+            moreButton.prototype.paint = function (ctx, value, x, y, w, h, style, options){
+                GC.Spread.Sheets.CellTypes.Button.prototype.paint.call(this, ctx, value, x, y, w, h, style, options);
+                let buttonW = cellWidth/5;
+                let endX = x+w-2;
+                if(value){
+                    let textWidth = ctx.measureText(value).width;
+                    let spaceWidth = cellWidth - buttonW;
+                    let textEndX = x+2+textWidth;
+                    if(spaceWidth<textWidth){
+                        for(let i = value.length-1;i>1;i--){
+                            let newValue = value.substr(0,i);
+                            let newTestWidth =  ctx.measureText(newValue).width;
+                            if(spaceWidth>newTestWidth){
+                                value = newValue;
+                                textEndX = x+2+newTestWidth;
+                                break;
+                            }
+                        }
+                    }
+                    ctx.fillText(value,textEndX,y+h-5);
+                }
+
+                //画三个点
+                ctx.save();
+                ctx.beginPath();
+                ctx.arc(endX-buttonW/2,y+h/2,1,0,360,false);
+                ctx.arc(endX-buttonW/2-4,y+h/2,1,0,360,false);
+                ctx.arc(endX-buttonW/2+4,y+h/2,1,0,360,false);
+                ctx.fillStyle="black";//填充颜色,默认是黑色
+                ctx.fill();//画实心圆
+                ctx.closePath();
+                ctx.restore();
+            };
+
+            moreButton.prototype.processMouseLeave= function (hitinfo) {
+                let newCell = new selectButton();
+                hitinfo.sheet.setCellType(hitinfo.row, hitinfo.col, newCell, GC.Spread.Sheets.SheetArea.viewport);
+                hitinfo.sheet.getCell(hitinfo.row, hitinfo.col).locked(false);
+            };
+
+            function selectButton() {
+            }
+
+            selectButton.prototype = new GC.Spread.Sheets.CellTypes.Text();
+
+            selectButton.prototype.paint = function (ctx, value, x, y, w, h, style, options){
+                GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this,arguments);
+            };
+            selectButton.prototype.getHitInfo = function (x, y, cellStyle, cellRect, context) {
+                return {
+                    x: x,
+                    y: y,
+                    row: context.row,
+                    col: context.col,
+                    cellStyle: cellStyle,
+                    cellRect: cellRect,
+                    sheetArea: context.sheetArea
+                };
+            };
+            selectButton.prototype.processMouseDown = function (hitinfo){
+                if(hitinfo.sheet.getCell(hitinfo.row,hitinfo.col).locked()!=true){
+                    let b1 = new moreButton();
+                    b1.marginLeft(cellWidth*4/5);
+                    hitinfo.sheet.setCellType(hitinfo.row, hitinfo.col, b1, GC.Spread.Sheets.SheetArea.viewport);
+                    hitinfo.sheet.getCell(hitinfo.row, hitinfo.col).locked(true);
+                }
+            };
+            return new selectButton();
+        };
+        sheet.setCellType(row, col,getSelectButton(header.headerWidth),GC.Spread.Sheets.SheetArea.viewport);
+
+    },
     chkIfEmpty: function(rObj, setting) {
         var rst = true;
         if (rObj) {
@@ -258,7 +362,6 @@ var sheetCommonObj = {
             let sheet = options.sheet;
             if (options.row === sheet.getActiveRowIndex() && options.col === sheet.getActiveColumnIndex() && (!forLocked || forLocked && !sheet.getCell(options.row, options.col).locked())) {
                 return GC.Spread.Sheets.CellTypes.ComboBox.prototype.getHitInfo.apply(this, arguments);
-
             } else {
                 return GC.Spread.Sheets.CellTypes.Base.prototype.getHitInfo.apply(this, arguments);
             }

+ 8 - 0
web/building_saas/css/main.css

@@ -337,4 +337,12 @@ div.resize{
 }
 .zlfb-check{
     margin-left: 0;
+}
+
+legend.legend{
+    display:block;
+    width:auto;
+    font-size:0.9rem;
+    top:-15px;
+    background: white;
 }

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

@@ -8,9 +8,9 @@
 </head>
 
 <body>
-<div style="">
-    <img id="f_btn" src="/web/dest/css/img/feeRate_btn.jpg" alt="" style="display: none" />
-</div>
+    <div style="">
+        <img id="f_btn" src="/web/dest/css/img/feeRate_btn.jpg" alt="" style="display: none" />
+    </div>
     <div class="toolsbar px-1">
     </div>
     <div class="container-fluid">
@@ -25,69 +25,6 @@
             </div>
         </div>
     </div>
-
-    <!--弹出 计算基数-->
-<div class="modal fade" id="jsjs" data-backdrop="static">
-        <div class="modal-dialog" role="document">
-            <div class="modal-content">
-                <div class="modal-header">
-                  <h5 class="modal-title">计算基础选择</h5>
-                  <button type="button" class="close" data-dismiss="modal" aria-label="Close">
-                    <span aria-hidden="true">&times;</span>
-                  </button>
-                </div>
-                <div class="modal-body">
-                  <div class="form-group">
-                    <input class="form-control" value="分部分项工程费+100">
-                    <p class="form-text">
-                      <button class="btn btn-secondary btn-sm">+</button>
-                      <button class="btn btn-secondary btn-sm">-</button>
-                      <button class="btn btn-secondary btn-sm">*</button>
-                      <button class="btn btn-secondary btn-sm">/</button>
-                      <button class="btn btn-secondary btn-sm">(</button>
-                      <button class="btn btn-secondary btn-sm">)</button>
-                    </p>
-                  </div>
-                  <div class=" modal-auto-height">
-                    <table class="table table-sm table-bordered">
-                      <thead>
-                        <tr><th></th><th>计算基础名称</th><th>金额</th></tr>
-                      </thead>
-                      <tbody>
-                        <tr>
-                          <td>1</td><td><button class="btn btn-secondary btn-sm">分部分项工程费</button></td><td>1000.16</td>
-                        </tr>
-                        <tr>
-                          <td>2</td><td><button class="btn btn-secondary btn-sm">分部分项基价直接工程费</button></td><td>600.16</td>
-                        </tr>
-                        <tr>
-                          <td>3</td><td><button class="btn btn-secondary btn-sm">分部分项基价人工费</button></td><td>100.16</td>
-                        </tr>
-                        <tr>
-                          <td>4</td><td><button class="btn btn-secondary btn-sm">分部分项基价材料费</button></td><td>200.16</td>
-                        </tr>
-                        <tr>
-                          <td>5</td><td><button class="btn btn-secondary btn-sm">分部分项基价机械费</button></td><td>300.16</td>
-                        </tr>
-                        <tr>
-                          <td>6</td><td><button class="btn btn-secondary btn-sm">分部分项调整人工费</button></td><td>100.16</td>
-                        </tr>
-                        <tr>
-                          <td>7</td><td><button class="btn btn-secondary btn-sm">分部分项调整机人工费</button></td><td>50.16</td>
-                        </tr>
-                      </tbody>
-                    </table>
-                    <p></p>
-                      <p></p>
-                  </div>
-                </div>
-                <div class="modal-footer">
-                    <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
-                    <a href="" class="btn btn-primary">确定</a>
-                </div>
-            </div>
-        </div>
-    </div>
 </body>
 
 

+ 120 - 38
web/building_saas/main/html/main.html

@@ -718,7 +718,7 @@
     <!--弹出 清单 计算基数-->
     <div class="modal fade" id="qd-jsjs" data-backdrop="static">
         <div class="modal-dialog" role="document">
-            <div class="modal-content">
+            <div class="modal-content" style="width:670px;">
                 <div class="modal-header">
                     <h5 class="modal-title">计算基础选择</h5>
                     <button type="button" class="close" data-dismiss="modal" aria-label="Close">
@@ -737,8 +737,42 @@
                             <button class="btn btn-secondary btn-sm" id="rightOpr">)</button>
                         </p>
                     </div>
-                    <div class=" modal-auto-height" style="overflow: hidden" id="billsBaseSpread">
+                    <div class="row" id="cbRowDiv">
+                        <div class="col-3" id="cbClassList">
+                            <ul class="list-unstyled">
+                                <li class="py-1" style="margin-left: 50px;">
+                                    <a id="cb_ALL" class="btn btn-outline-secondary btn-sm active" href="javascript:void(0)">所有</a>
+                                </li>
+                                <li class="py-1" style="margin-left: 50px;">
+                                    <a id="cb_FBFX"  href="javascript:void(0);">分部分项</a>
+                                </li>
+                                <li class="py-1" style="margin-left: 50px;">
+                                    <a id="cb_CSXM" href="javascript:void(0)">措施项目</a>
+                                </li>
+                                <li class="py-1" style="margin-left: 50px;">
+                                    <a id="cb_QTXM" href="javascript:void(0)">其他项目</a>
+                                </li>
+                                <li class="py-1" style="margin-left: 50px;">
+                                    <a id="cb_FBF" href="javascript:void(0)">分包费</a>
+                                </li>
+                                <li class="py-1" style="margin-left: 50px;">
+                                    <a id="cb_RCJ" href="javascript:void(0)">人材机</a>
+                                </li>
+                                <li class="py-1" style="margin-left: 50px;">
+                                    <a id="cb_GF" href="javascript:void(0)">规费</a>
+                                </li>
+                                <li class="py-1" style="margin-left: 50px;">
+                                    <a id="cb_SJ" href="javascript:void(0)">税金</a>
+                                </li>
+                                <li class="py-1" style="margin-left: 50px;">
+                                    <a id="cb_SQGCZJ" href="javascript:void(0)">税前工程造价</a>
+                                </li>
+                            </ul>
+                        </div>
+                        <div class=" modal-auto-height col-9" style="overflow: hidden" id="billsBaseSpread">
+                        </div>
                     </div>
+
                 </div>
                 <div class="modal-footer">
                     <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
@@ -863,57 +897,105 @@
 
     <!--弹出 计取安装费用-->
     <div class="modal fade" id="calc_installation_fee" data-backdrop="static">
-        <div class="modal-dialog modal-lg" role="document">
-            <div class="modal-content">
+        <div class="modal-dialog modal-lg" style="max-width: 1100px" role="document">
+            <div class="modal-content" style="width: 1100px">
                 <div class="modal-header">
                     <h5 class="modal-title">统一设置计取安装费用</h5>
-                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <button type="button" class="close" id="calc_installation_fee_close" aria-label="Close">
                         <span aria-hidden="true">&times;</span>
                     </button>
                 </div>
                 <div class="modal-body">
-                    <div style="height:200px"><!--sjs id设置在这个div-->
-                        <div class="row">
-                            <div class="modal-auto-height col-8" style="overflow: hidden" id="feeItemSheet">
-                                test ....
+                    <div class="row" style="height:300px"><!--sjs id设置在这个div-->
+                        <div class=" col-8" style="overflow: hidden" id="feeItemSheet">
+                        </div>
+                        <div class=" col-4" style="overflow: hidden" id="install_setting">
+                            <div style="height: 100px;" >
+                                <!--<div class="setting_title">整个项目统一计取</div>-->
+                                <fieldset class="form-group"  style="border:1px solid #b3b3b3;padding: 15px">
+                                    <legend class="legend" >分项费用:</legend>
+                                    <div class="form-check">
+                                        <label class="form-check-label">
+                                            <input class="form-check-input" name="install_setting_radios" id="all_project_calc" value="0" checked type="radio">
+                                            整个项目统一计取
+                                        </label>
+                                    </div>
+                                    <div class="form-check">
+                                        <label class="form-check-label">
+                                            <input class="form-check-input" name="install_setting_radios" id="FB_calc" value="1" type="radio">
+                                            每个分部单独计取
+                                        </label>
+                                    </div>
+                                </fieldset>
                             </div>
-                            <div class="modal-auto-height col-4" style="overflow: hidden" id="install_setting">
-                                <div style="height: 100px;border:1px solid #f00" >
-                                    <fieldset class="form-group" >
-                                        <h5>分项费用</h5>
-                                        <div class="form-check">
-                                            <label class="form-check-label">
-                                                <input class="form-check-input" name="install_setting_radios" id="all_project_calc" value="0" type="radio">
-                                                整个项目统一计取
-                                            </label>
-                                        </div>
-                                        <div class="form-check">
-                                            <label class="form-check-label">
-                                                <input class="form-check-input" name="install_setting_radios" id="FB_calc" value="1" type="radio">
-                                                每个分部单独计取
-                                            </label>
-                                        </div>
-                                    </fieldset>
+                        </div>
+                    </div>
+                    <br>
+                    <div class="row" style="height:400px"><!--sjs id设置在这个div-->
+                        <div class="col-12" style="overflow: hidden" id="feeDetailSheet"></div>
+                    </div>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-link" >恢复默认值</button>
+                  <!--  <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>-->
+                    <button  class="btn btn-primary" id="calc_installation_fee_confirm">确定</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!--弹出 指定具体位置(计取安装费用)-->
+    <div class="modal fade" id="calc_position" data-backdrop="static">
+        <input type="hidden" id ='calc_position_from'>
+        <div class="modal-dialog modal-lg"  role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">指定具体位置</h5>
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                        <span aria-hidden="true">&times;</span>
+                    </button>
+                </div>
+                <div class="modal-body">
+                    <div class="row mb-2">
+                        <div class="col-8">
+                            <div class="input-group input-group-sm">
+                                <input type="text" class="form-control" placeholder="输入编码 或 名称 " id="filterKeyword" aria-describedby="basic-addon2">
+                                <div class="input-group-append">
+                                    <button class="btn btn-secondary" id="positionSheetFilter" type="button"><i class="fa fa-search"></i> 过滤</button>
+                                    <button class="btn btn-outline-secondary" id="cancelFilter" type="button">取消过滤</button>
                                 </div>
                             </div>
                         </div>
-                        <!--<table class="table table-sm table-bordered m-0">
-                            <thead><tr><th></th><th>计取</th><th>费用项</th><th>费用类型</th><th>记取位置</th></tr></thead>
-                            <tr><td>1</td><td></td><td>重庆市安装工程计价定额(2008)</td><td></td><td></td></tr>
-                            <tr><td>2</td><td><input type="checkbox"></td><td>-高层增加费</td><td>子目费用</td><td><a href="javacript:void(0);" data-toggle="modal" data-target="#jqaz-wz">点击</a></td></tr>
-                        </table>-->
                     </div>
-                    <div style="height:200px"><!--sjs id设置在这个div-->
-                        <table class="table table-sm table-bordered m-0">
-                            <thead><tr><th></th><th>分册章节</th><th>费用规则</th><th>编码</th><th>基数</th><th>费率(%)</th><th>其中人工(%)</th><th>其中材料(%)</th><th>其中机械(%)</th><th>记取位置</th></tr></thead>
-                            <tr><td>1</td><td>第一册 机械设备安装工程1~6、8~16章节</td><td>超高费(标高15m以内(第一册 机械设备安装工程1~6章节))</td><td>AZFY1</td><td>人材机乘系数</td><td></td><td>25</td><td></td><td>25</td><td><a href="javacript:void(0);" data-toggle="modal" data-target="#jqaz-wz">点击</a></td></tr>
-                        </table>
+                    <div class="row" style="height:400px"><!--sjs id设置在这个div-->
+                        <div class="col-12" style="overflow: hidden" id="positionSpread"></div>
                     </div>
                 </div>
                 <div class="modal-footer">
-                    <button type="button" class="btn btn-link" >恢复默认值</button>
                     <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
-                    <a href="" class="btn btn-primary">确定</a>
+                    <button class="btn btn-primary" id="select_position_confirm">确定</button>
+                </div>
+            </div>
+        </div>
+    </div>
+
+    <!--弹出 查询安装费用-->
+    <div class="modal fade" id="more_feeRule" data-backdrop="static">
+        <div class="modal-dialog modal-lg" style="max-width: 950px" role="document">
+            <div class="modal-content">
+                <div class="modal-header">
+                    <h5 class="modal-title">查询安装费用</h5>
+                    <button type="button" class="close" data-dismiss="modal" aria-label="Close" id="more_feeRule_close">
+                        <span aria-hidden="true">&times;</span>
+                    </button>
+                </div>
+                <div class="modal-body">
+                    <div class="modal-fixed-height" id="moreFeeRuleSpread"><!--sjs ID设置此div--->
+                    </div>
+                </div>
+                <div class="modal-footer">
+                    <button type="button" class="btn btn-secondary" id="more_feeRule_concel" data-dismiss="modal">取消</button>
+                    <button class="btn btn-primary" id="more_feeRule_confirm">确定</button>
                 </div>
             </div>
         </div>

+ 8 - 1
web/building_saas/main/js/models/bills.js

@@ -512,7 +512,14 @@ var Bills = {
                 }
             }
         };
-
+        bills.prototype.getMeasureNode = function (controller) {//取措施项目工程节点
+            let roots =  controller.tree.roots;
+            for(let root of roots){
+                if(isFlag(root.data)&&root.data.flagsIndex.fixed.flag==fixedFlag.MEASURE){
+                    return root;
+                }
+            }
+        };
         bills.prototype.deleteSelectedNode=function(){//删除选中单行时的节点
             let controller = projectObj.mainController, project = projectObj.project;
             let selected = controller.tree.selected, parent = selected.parent;

+ 102 - 82
web/building_saas/main/js/models/calc_base.js

@@ -379,7 +379,7 @@ let baseFigureTemplate = {
         }
         return rst;
     },
-    'FBFXGCLQDJJZJGCF': function () {
+    'FBFXDEJJZJGCF': function () {
         return (this['FBFXDEJJRGF']() + this['FBFXDEJJCLF']() + this['FBFXDEJJJXF']()).toDecimal(decimalObj.bills.totalPrice);
     },
     'CSXMF': function () {
@@ -476,9 +476,9 @@ let baseFigureTemplate = {
                 }
             }
         }
-        return 0;
+        return rst;
     },
-    'JSCSXMQDDEJJZJGCF': function () {
+    'JSCSXMDEJJZJGCF': function () {
         return (this['JSCSXMDEJJRGF']() + this['JSCSXMDEJJCLF']() + this['JSCSXMDEJJJXF']()).toDecimal(decimalObj.bills.totalPrice);
     },
     'QTXMF': function () {
@@ -577,7 +577,7 @@ let baseFigureTemplate = {
                 let adjPrc = calcBase.project.projectGLJ.getAdjustPrice(glj);
                 //价差
                 let dffPrc = parseFloat(glj.unit_price.market_price - adjPrc).toDecimal(decimalObj.glj.unitPrice);
-                rst = (rst + parseFloat(glj.quantity * dffPrc).toDecimal(2)).toDecimal(2);
+                rst = (rst + parseFloat(glj.subdivisionQuantity * dffPrc).toDecimal(2)).toDecimal(2);
             }
         }
         return rst;
@@ -776,9 +776,7 @@ let baseFigureTemplate = {
         let projGljs = calcBase.project.projectGLJ.datas.gljList;
         for(let glj of projGljs){
             if(baseMachineTypes.includes(glj.type) && glj.ratio_data.length === 0 && glj.supply === supplyType.JDYG){
-                console.log(glj);
                 rst = (rst + parseFloat(glj.quantity * glj.unit_price.market_price).toDecimal(2)).toDecimal(2);
-                console.log(rst);
             }
         }
         return rst;
@@ -874,14 +872,14 @@ let baseFigureTemplate = {
     },
     'FBRGGR': function () {//分包人工工日
         let rst = 0;
-        let rationIds = [];//查找定额工料机
+        let rationObjs = [];//查找定额工料机
         let rations = calcBase.project.Ration.datas;
         let rationGljs = calcBase.project.ration_glj.datas;
         for(let ration of rations){
             if(ration.isSubcontract){
                 //定额
                 if(ration.type === rationType.ration){
-                    rationIds.push(ration.ID);
+                    rationObjs.push({ID: ration.ID, quantity: ration.quantity});
                 }
                 //量人 type 2, subType 1
                 else if(ration.type === rationType.volumePrice && ration.subType === volumePriceMaps['量人']){
@@ -893,10 +891,10 @@ let baseFigureTemplate = {
                 }
             }
         }
-        for(let rationID of rationIds){
+        for(let ration of rationObjs){
             for(let glj of rationGljs){
-                if(rationID === glj.rationID){
-                    rst = parseFloat(rst + glj.quantity).toDecimal(decimalObj.glj.quantity);
+                if(ration.ID === glj.rationID && glj.type === gljType.LABOUR){
+                    rst = parseFloat(rst + parseFloat(glj.quantity * ration.quantity).toDecimal(decimalObj.glj.quantity)).toDecimal(decimalObj.glj.quantity);
                 }
             }
         }
@@ -904,79 +902,79 @@ let baseFigureTemplate = {
     }
 };
 
-//基数的值不是通过清单节点获得的,则该基数的fixedBill为空,如价差、甲供、分包
+//基数的值不是通过清单节点获得的,则该基数的fixedBill为空,如价差、甲供、分包; class:分类,用于基数选择界面分类显示
 let baseFigureMap = {
     //与清单直接关联=======
-    '分部分项工程费': {base: 'FBFXGCF', fixedFlag: fixedFlag.SUB_ENGINERRING},
-    '分部分项定额基价人工费': {base: 'FBFXDEJJRGF', fixedFlag: fixedFlag.SUB_ENGINERRING},
-    '分部分项定额基价材料费': {base: 'FBFXDEJJCLF', fixedFlag: fixedFlag.SUB_ENGINERRING},
-    '分部分项定额基价机械费': {base: 'FBFXDEJJJXF', fixedFlag: fixedFlag.SUB_ENGINERRING},
-    '分部分项调整人工费': {base: 'FBFXTZRGF', fixedFlag: fixedFlag.SUB_ENGINERRING},
-    '分部分项调整机上人工费': {base: 'FBFXTZJSRGF', fixedFlag: fixedFlag.SUB_ENGINERRING},
-    '分部分项主材费': {base: 'FBFXZCF', fixedFlag: fixedFlag.SUB_ENGINERRING},
-    '分部分项设备费': {base: 'FBFXSBF', fixedFlag: fixedFlag.SUB_ENGINERRING},
-    '分部分项未计价材料费': {base: 'FBFXWJJCLF', fixedFlag: fixedFlag.SUB_ENGINERRING},
-    '分部分项人工工日': {base: 'FBFXRGGR', fixedFlag: fixedFlag.SUB_ENGINERRING},
-    '分部分项工程量清单中的基价直接工程费': {base: 'FBFXGCLQDJJZJGCF', fixedFlag: fixedFlag.SUB_ENGINERRING},
-    '措施项目费': {base: 'CSXMF', fixedFlag: fixedFlag.MEASURE},
-    '组织措施项目费': {base: 'ZZCSXMF', fixedFlag: fixedFlag.CONSTRUCTION_ORGANIZATION},
-    '组织措施项目定额基价直接工程费': {base: 'ZZCSXMDEJJZJGCF', fixedFlag: fixedFlag.CONSTRUCTION_ORGANIZATION},
-    '组织措施项目定额基价人工费': {base: 'ZZCSXMDEJJRGF', fixedFlag: fixedFlag.CONSTRUCTION_ORGANIZATION},
-    '组织措施项目定额基价材料费': {base: 'ZZCSXMDEJJCLF', fixedFlag: fixedFlag.CONSTRUCTION_ORGANIZATION},
-    '组织措施项目定额基价机械费': {base: 'ZZCSXMDEJJJXF', fixedFlag: fixedFlag.CONSTRUCTION_ORGANIZATION},
-    '技术措施项目费': {base: 'JSCSXMF', fixedFlag: fixedFlag.CONSTRUCTION_TECH},
-    '技术措施项目定额基价人工费': {base: 'JSCSXMDEJJRGF', fixedFlag: fixedFlag.CONSTRUCTION_TECH},
-    '技术措施项目定额基价材料费': {base: 'JSCSXMDEJJCLF', fixedFlag: fixedFlag.CONSTRUCTION_TECH},
-    '技术措施项目定额基价机械费': {base: 'JSCSXMDEJJJXF', fixedFlag: fixedFlag.CONSTRUCTION_TECH},
-    '技术措施项目调整人工费': {base: 'JSCSXMTZRGF', fixedFlag: fixedFlag.CONSTRUCTION_TECH},
-    '技术措施项目调整机上人工费': {base: 'JSCSXMTZJSRGF', fixedFlag: fixedFlag.CONSTRUCTION_TECH},
-    '技术措施项目主材费': {base: 'JSCSXMZCF', fixedFlag: fixedFlag.CONSTRUCTION_TECH},
-    '技术措施项目设备费': {base: 'JSCSXMSBF', fixedFlag: fixedFlag.CONSTRUCTION_TECH},
-    '技术措施项目未计价材料费': {base: 'JSCSXMWJJCLF', fixedFlag: fixedFlag.CONSTRUCTION_TECH},
-    '技术措施项目人工工日': {base: 'JSCSXMRGGR', fixedFlag: fixedFlag.CONSTRUCTION_TECH},
-    '技术措施项目清单中的定额基价直接工程费': {base: 'JSCSXMQDDEJJZJGCF', fixedFlag: fixedFlag.CONSTRUCTION_TECH},
-    '其他项目费': {base: 'QTXMF',  fixedFlag: fixedFlag.OTHER},
-    '规费': {base: 'GF', fixedFlag: fixedFlag.CHARGE},
-    '税金': {base: 'SJ', fixedFlag: fixedFlag.TAX},
-    '税前工程造价': {base: 'SQGCZJ', fixedFlag: fixedFlag.SAFETY_CONSTRUCTION},//安全文明施工专项费用使用
+    '分部分项工程费': {base: 'FBFXGCF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
+    '分部分项定额基价人工费': {base: 'FBFXDEJJRGF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
+    '分部分项定额基价材料费': {base: 'FBFXDEJJCLF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
+    '分部分项定额基价机械费': {base: 'FBFXDEJJJXF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
+    '分部分项调整人工费': {base: 'FBFXTZRGF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
+    '分部分项调整机上人工费': {base: 'FBFXTZJSRGF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
+    '分部分项主材费': {base: 'FBFXZCF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
+    '分部分项设备费': {base: 'FBFXSBF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
+    '分部分项未计价材料费': {base: 'FBFXWJJCLF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
+    '分部分项人工工日': {base: 'FBFXRGGR', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
+    '分部分项定额基价直接工程费': {base: 'FBFXDEJJZJGCF', fixedFlag: fixedFlag.SUB_ENGINERRING, class: 'FBFX'},
+    '措施项目费': {base: 'CSXMF', fixedFlag: fixedFlag.MEASURE, class: 'CSXM'},
+    '组织措施项目费': {base: 'ZZCSXMF', fixedFlag: fixedFlag.CONSTRUCTION_ORGANIZATION, class: 'CSXM'},
+    '组织措施项目定额基价直接工程费': {base: 'ZZCSXMDEJJZJGCF', fixedFlag: fixedFlag.CONSTRUCTION_ORGANIZATION, class: 'CSXM'},
+    '组织措施项目定额基价人工费': {base: 'ZZCSXMDEJJRGF', fixedFlag: fixedFlag.CONSTRUCTION_ORGANIZATION, class: 'CSXM'},
+    '组织措施项目定额基价材料费': {base: 'ZZCSXMDEJJCLF', fixedFlag: fixedFlag.CONSTRUCTION_ORGANIZATION, class: 'CSXM'},
+    '组织措施项目定额基价机械费': {base: 'ZZCSXMDEJJJXF', fixedFlag: fixedFlag.CONSTRUCTION_ORGANIZATION, class: 'CSXM'},
+    '技术措施项目费': {base: 'JSCSXMF', fixedFlag: fixedFlag.CONSTRUCTION_TECH, class: 'CSXM'},
+    '技术措施项目定额基价人工费': {base: 'JSCSXMDEJJRGF', fixedFlag: fixedFlag.CONSTRUCTION_TECH, class: 'CSXM'},
+    '技术措施项目定额基价材料费': {base: 'JSCSXMDEJJCLF', fixedFlag: fixedFlag.CONSTRUCTION_TECH, class: 'CSXM'},
+    '技术措施项目定额基价机械费': {base: 'JSCSXMDEJJJXF', fixedFlag: fixedFlag.CONSTRUCTION_TECH, class: 'CSXM'},
+    '技术措施项目调整人工费': {base: 'JSCSXMTZRGF', fixedFlag: fixedFlag.CONSTRUCTION_TECH, class: 'CSXM'},
+    '技术措施项目调整机上人工费': {base: 'JSCSXMTZJSRGF', fixedFlag: fixedFlag.CONSTRUCTION_TECH, class: 'CSXM'},
+    '技术措施项目主材费': {base: 'JSCSXMZCF', fixedFlag: fixedFlag.CONSTRUCTION_TECH, class: 'CSXM'},
+    '技术措施项目设备费': {base: 'JSCSXMSBF', fixedFlag: fixedFlag.CONSTRUCTION_TECH, class: 'CSXM'},
+    '技术措施项目未计价材料费': {base: 'JSCSXMWJJCLF', fixedFlag: fixedFlag.CONSTRUCTION_TECH, class: 'CSXM'},
+    '技术措施项目人工工日': {base: 'JSCSXMRGGR', fixedFlag: fixedFlag.CONSTRUCTION_TECH, class: 'CSXM'},
+    '技术措施项目定额基价直接工程费': {base: 'JSCSXMDEJJZJGCF', fixedFlag: fixedFlag.CONSTRUCTION_TECH, class: 'CSXM'},
+    '其他项目费': {base: 'QTXMF',  fixedFlag: fixedFlag.OTHER, class: 'QTXM'},
+    '规费': {base: 'GF', fixedFlag: fixedFlag.CHARGE, class: 'GF'},
+    '税金': {base: 'SJ', fixedFlag: fixedFlag.TAX, class: 'SJ'},
     //不于清单直接关联==========
-    '人材机价差': {base: 'RCJJC'},
-    '人工价差': {base: 'RGJC'},
-    '材料价差': {base: 'CLJC'},
-    '机械价差': {base: 'JXJC'},
-    '分部分项人材机价差': {base: 'FBFXRCJJC'},
-    '分部分项人工价差': {base: 'FBFXRGJC'},
-    '分部分项材料价差': {base: 'FBFXCLJC'},
-    '分部分项机械价差': {base: 'FBFXJXJC'},
-    '技术措施项目人材机价差': {base: 'JSCSXMRCJJC'},
-    '技术措施项目人工价差': {base: 'JSCSXMRGJC'},
-    '技术措施项目材料价差': {base: 'JSCSXMCLJC'},
-    '技术措施项目机械价差': {base: 'JSCSXMJXJC'},
-    '甲供定额基价人工费': {base: 'JGDEJJRGF'},
-    '甲供定额基价材料费': {base: 'JGDEJJCLF'},
-    '甲供定额基价机械费': {base: 'JGDEJJJXF'},
-    '甲供人工费': {base: 'JGRGF'},
-    '甲供材料费': {base: 'JGCLF'},
-    '甲供机械费': {base: 'JGJXF'},
-    '甲供主材费': {base: 'JGZCF'},
-    '甲供设备费': {base: 'JGSBF'},
-    '甲定定额基价人工费': {base: 'JDDEJJRGF'},
-    '甲定定额基价材料费': {base: 'JDDEJJCLF'},
-    '甲定定额基价机械费': {base: 'JDDEJJJXF'},
-    '甲定人工费': {base: 'JDRGF'},
-    '甲定材料费': {base: 'JDCLF'},
-    '甲定机械费': {base: 'JDJXF'},
-    '甲定主材费': {base: 'JDZCF'},
-    '甲定设备费': {base: 'JDSBF'},
-    '暂估材料费(从子目汇总)': {base: 'ZGCLFFZM'},
-    '暂估材料费(从工料机汇总表汇总)': {base: 'ZGCLFFGLJ'},
-    '分包费': {base: 'FBF'},
-    '分包定额基价人工费': {base: 'FBDEJJRGF'},
-    '分包定额基价材料费': {base: 'FBDEJJCLF'},
-    '分包定额基价机械费': {base: 'FBDEJJJXF'},
-    '分包主材费': {base: 'FBZCF'},
-    '分包设备费': {base: 'FBSBF'},
-    '分包人工工日': {base: 'FBRGGR'}
+    '税前工程造价': {base: 'SQGCZJ', class: 'SQGCZJ'},//安全文明施工专项费用使用
+    '人材机价差': {base: 'RCJJC', class: 'RCJ'},
+    '人工价差': {base: 'RGJC', class: 'RCJ'},
+    '材料价差': {base: 'CLJC', class: 'RCJ'},
+    '机械价差': {base: 'JXJC', class: 'RCJ'},
+    '分部分项人材机价差': {base: 'FBFXRCJJC', class: 'RCJ'},
+    '分部分项人工价差': {base: 'FBFXRGJC', class: 'RCJ'},
+    '分部分项材料价差': {base: 'FBFXCLJC', class: 'RCJ'},
+    '分部分项机械价差': {base: 'FBFXJXJC', class: 'RCJ'},
+    '技术措施项目人材机价差': {base: 'JSCSXMRCJJC', class: 'RCJ'},
+    '技术措施项目人工价差': {base: 'JSCSXMRGJC', class: 'RCJ'},
+    '技术措施项目材料价差': {base: 'JSCSXMCLJC', class: 'RCJ'},
+    '技术措施项目机械价差': {base: 'JSCSXMJXJC', class: 'RCJ'},
+    '甲供定额基价人工费': {base: 'JGDEJJRGF', class: 'RCJ'},
+    '甲供定额基价材料费': {base: 'JGDEJJCLF', class: 'RCJ'},
+    '甲供定额基价机械费': {base: 'JGDEJJJXF', class: 'RCJ'},
+    '甲供人工费': {base: 'JGRGF', class: 'RCJ'},
+    '甲供材料费': {base: 'JGCLF', class: 'RCJ'},
+    '甲供机械费': {base: 'JGJXF', class: 'RCJ'},
+    '甲供主材费': {base: 'JGZCF', class: 'RCJ'},
+    '甲供设备费': {base: 'JGSBF', class: 'RCJ'},
+    '甲定定额基价人工费': {base: 'JDDEJJRGF', class: 'RCJ'},
+    '甲定定额基价材料费': {base: 'JDDEJJCLF', class: 'RCJ'},
+    '甲定定额基价机械费': {base: 'JDDEJJJXF', class: 'RCJ'},
+    '甲定人工费': {base: 'JDRGF', class: 'RCJ'},
+    '甲定材料费': {base: 'JDCLF', class: 'RCJ'},
+    '甲定机械费': {base: 'JDJXF', class: 'RCJ'},
+    '甲定主材费': {base: 'JDZCF', class: 'RCJ'},
+    '甲定设备费': {base: 'JDSBF', class: 'RCJ'},
+    '暂估材料费(从子目汇总)': {base: 'ZGCLFFZM', class: 'RCJ'},
+    '暂估材料费(从工料机汇总表汇总)': {base: 'ZGCLFFGLJ', class: 'RCJ'},
+    '分包费': {base: 'FBF', class: 'FBF'},
+    '分包定额基价人工费': {base: 'FBDEJJRGF', class: 'FBF'},
+    '分包定额基价材料费': {base: 'FBDEJJCLF', class: 'FBF'},
+    '分包定额基价机械费': {base: 'FBDEJJJXF', class: 'FBF'},
+    '分包主材费': {base: 'FBZCF', class: 'FBF'},
+    '分包设备费': {base: 'FBSBF', class: 'FBF'},
+    '分包人工工日': {base: 'FBRGGR', class: 'FBF'}
 };
 
 //输入式分析器
@@ -1164,8 +1162,19 @@ let cbParser = {
         let rst = [];
         let cnRex = /[^\u4e00-\u9fa5]/;
         let temp = expr.split(cnRex);
+        //暂估材料费特殊处理:CN(CN)
+        let isZG = false;
         for(let i = 0, len = temp.length; i < len; i++){
             if(temp[i] !== '' && rst.indexOf(temp[i]) === -1){
+                if(temp[i] === '暂估材料费'){//处理暂估材料基数
+                    isZG = true;
+                    continue;
+                }
+                if(isZG){//上一个是暂估材料费
+                    //拼接成完整的暂估材料费(CN);
+                    temp[i] = `${temp[i-1]}(${temp[i]})`;
+                    isZG = false;
+                }
                 rst.push(temp[i]);
             }
         }
@@ -1278,7 +1287,17 @@ let cbParser = {
         v = v.replace(/[{, }]/g, '');
         for(let i = 0, len = exps.length;i < len; i++){
             exps[i].compileExp = '$CBC.base(\'' + exps[i].orgExp + '\')';
-            v = v.replace(new RegExp(exps[i].orgExp, 'g'), exps[i].compileExp);
+            //暂估材料费作特殊处理
+            if(exps[i].orgExp === '暂估材料费(从子目汇总)' || exps[i].orgExp === '暂估材料费(从工料机汇总表汇总)'){
+                let reCount = v.split(exps[i].orgExp).length - 1;
+                while (reCount > 0){
+                    v = v.replace(exps[i].orgExp, exps[i].compileExp);
+                    reCount --;
+                }
+            }
+            else {
+                v = v.replace(new RegExp(exps[i].orgExp, 'g'), exps[i].compileExp);
+            }
         }
         //行引用
         let fidArr = this.getFIDArr(v);
@@ -1384,6 +1403,7 @@ let calcBase = {
             me.success = true;
             node.data.calcBase = exp;
             node.data.calcBaseValue = parseFloat(calcBaseValue).toDecimal(decimalObj.decimal('totalPrice', node));
+            node.changed = true;
         }
         catch (err){
             alert(me.errMsg);

+ 166 - 33
web/building_saas/main/js/models/calc_program.js

@@ -97,7 +97,6 @@ let defaultBillTemplate = {
         }
     ]
 };*/
-
 let calcTools = {
     getNodeByFlag: function (flag) {
         let bill = cbTools.findBill(flag);
@@ -204,26 +203,40 @@ let calcTools = {
     rationBaseFee: function (treeNode, gljTypes, priceType){
         if (!treeNode.data.gljList) return 0;
         let me = this, result = 0;
+        let price = 0, temp = 0, temp2 = 0;
         for (let glj of treeNode.data.gljList) {
-            let price = 0, temp = 0;
             if (gljTypes.indexOf(glj.type) >= 0) {
+/*                if (priceType == priceTypes.ptDiffPrice){
+                    let aprice = me.uiGLJPrice(glj["adjustPrice"]);
+                    let mprice = me.uiGLJPrice(glj["marketPrice"]);
+                    temp = (me.uiGLJQty(glj["quantity"]) * mprice).toDecimal(decimalObj.process) - (me.uiGLJQty(glj["quantity"]) * aprice).toDecimal(decimalObj.process);
+                    temp = temp.toDecimal(decimalObj.process);
+                }*/
                 if (priceType == priceTypes.ptDiffPrice){
                     let aprice = me.uiGLJPrice(glj["adjustPrice"]);
                     let mprice = me.uiGLJPrice(glj["marketPrice"]);
-                    temp = (me.uiGLJQty(glj["quantity"]) * mprice).toDecimal(decimalObj.ration.unitPrice) - (me.uiGLJQty(glj["quantity"]) * aprice).toDecimal(decimalObj.ration.unitPrice);
-                    temp = temp.toDecimal(decimalObj.ration.unitPrice);
+                    if (aprice != mprice){
+                        temp = (temp + (me.uiGLJQty(glj["quantity"]) * mprice).toDecimal(decimalObj.process)).toDecimal(decimalObj.process);
+                        temp2 = (temp2 + (me.uiGLJQty(glj["quantity"]) * aprice).toDecimal(decimalObj.process)).toDecimal(decimalObj.process);
+                    }
                 }
                 else {
                     if (priceType == priceTypes.ptBasePrice){ price = me.uiGLJPrice(glj["basePrice"]);}
                     else if (priceType == priceTypes.ptAdjustPrice){price = me.uiGLJPrice(glj["adjustPrice"]);}
                     else if (priceType == priceTypes.ptMarketPrice){price = me.uiGLJPrice(glj["marketPrice"]);}
                     temp = (me.uiGLJQty(glj["quantity"]) * price).toDecimal(decimalObj.process);
+                    result = (result + temp).toDecimal(decimalObj.process);
                 };
-                result = (result + temp).toDecimal(decimalObj.process);
             };
         };
 
-        result = result.toDecimal(decimalObj.ration.unitPrice);
+        if (priceType == priceTypes.ptDiffPrice){
+            result = (temp.toDecimal(decimalObj.ration.unitPrice) - temp2.toDecimal(decimalObj.ration.unitPrice)).toDecimal(decimalObj.ration.unitPrice);
+        }
+        else{
+            result = result.toDecimal(decimalObj.ration.unitPrice);
+        };
+
         return result;
     },
     machineLabourFee: function (gljArr) {
@@ -249,9 +262,10 @@ let calcTools = {
         }
         return result;
     },
+    // 父清单暂估费的汇总计算走计算程序逻辑,不在这里。这里的小数取舍比较复杂,必须严格遵循需求,不能随意改动,否则计算结果会有误差:如差1分钱。
     estimateFee: function (treeNode, isBase = false){
         let me = this, sumU = 0, sumT = 0;
-        // 父清单暂估费的汇总计算走计算程序逻辑,不在这里。
+        // 总造价暂估费
         if (me.isTotalCostBill(treeNode)){
             let nodes = projectObj.project.mainTree.roots;
             for (let node of nodes){
@@ -313,7 +327,8 @@ let calcTools = {
                         for (let md of mds){
                             if (md.isEstimate){
                                 let isExist = false;
-                                let mdQ = (rq * me.uiGLJQty(glj.quantity) * me.uiGLJQty(md.consumption)).toDecimal(decimalObj.process);
+                                let totalQ = (rq * me.uiGLJQty(glj.quantity)).toDecimal(decimalObj.glj.quantity);
+                                let mdQ = (totalQ * me.uiGLJQty(md.consumption)).toDecimal(decimalObj.process);
 
                                 for (let obj of GLJObjs){
                                     if (gljOprObj.getIndex(md, gljKeyArray) == gljOprObj.getIndex(obj, gljKeyArray)){
@@ -331,7 +346,7 @@ let calcTools = {
                 };
 
                 for (let obj of GLJObjs){
-                    sumT = sumT + (obj.quantity * me.uiGLJPrice(obj.marketPrice)).toDecimal(decimalObj.process);
+                    sumT = sumT + (me.uiGLJQty(obj.quantity) * me.uiGLJPrice(obj.marketPrice)).toDecimal(decimalObj.process);
                     sumT = sumT.toDecimal(decimalObj.process);
                 };
                 sumT = sumT.toDecimal(decimalObj.bills.totalPrice);
@@ -346,17 +361,19 @@ let calcTools = {
         if (treeNode.data.type != rationType.volumePrice && treeNode.data.type != rationType.gljRation) return;
         let result = 0, me = this;
         if (
-            (treeNode.data.subType === gljType.LABOUR && baseName === '定额基价人工费') ||
-            (baseMaterialTypes.includes(treeNode.data.subType) && baseName === '定额基价材料费') ||
-            (treeNode.data.subType === gljType.GENERAL_MACHINE && baseName === '定额基价机械费') ||
-            (treeNode.data.subType === gljType.MAIN_MATERIAL && baseName === '主材费') ||
-            (treeNode.data.subType === gljType.EQUIPMENT && baseName === '设备费')) {
+            (treeNode.data.subType === gljType.LABOUR && baseName === calcBaseNames.DEJJRGF) ||
+            (baseMaterialTypes.includes(treeNode.data.subType) && baseName === calcBaseNames.DEJJCLF) ||
+            (treeNode.data.subType === gljType.GENERAL_MACHINE && baseName === calcBaseNames.DEJJJXF) ||
+            (treeNode.data.subType === gljType.MAIN_MATERIAL && baseName === calcBaseNames.ZCF) ||
+            (treeNode.data.subType === gljType.EQUIPMENT && baseName === calcBaseNames.SBF)) {
             if (treeNode.data.type == rationType.volumePrice)
                 result = treeNode.data.marketUnitFee ? parseFloat(treeNode.data.marketUnitFee).toDecimal(decimalObj.ration.unitPrice) : 0
             else if (treeNode.data.type == rationType.gljRation)
-                result = treeNode.data.basePrice ? parseFloat(treeNode.data.basePrice).toDecimal(decimalObj.ration.unitPrice) : 0;
+                // result = treeNode.data.basePrice ? parseFloat(treeNode.data.basePrice).toDecimal(decimalObj.ration.unitPrice) : 0;
+                // 这里因为是算基数所以要取基价,但不能直接取basePrice,受限于项目属性的三个选项。
+                result = gljOprObj.getBasePrice(treeNode);
         }
-        else if (treeNode.data.subType === gljType.GENERAL_MACHINE && baseName === '定额基价机上人工费') {
+        else if (treeNode.data.subType === gljType.GENERAL_MACHINE && baseName === calcBaseNames.DEJJJSRGF) {
             let glj = {
                 'code': treeNode.data.code,
                 'name': treeNode.data.name,
@@ -369,9 +386,9 @@ let calcTools = {
         }
         else if (
             (treeNode.data.type == rationType.gljRation) &&
-            ((treeNode.data.subType === gljType.LABOUR && baseName === '人工费价差') ||
-                (baseMaterialTypes.includes(treeNode.data.subType) && baseName === '材料费价差') ||
-                (treeNode.data.subType === gljType.GENERAL_MACHINE && baseName === '机械费价差'))
+            ((treeNode.data.subType === gljType.LABOUR && baseName === calcBaseNames.RGFJC) ||
+                (baseMaterialTypes.includes(treeNode.data.subType) && baseName === calcBaseNames.CLFJC) ||
+                (treeNode.data.subType === gljType.GENERAL_MACHINE && baseName === calcBaseNames.JXFJC))
         ) {
             let aprice = me.uiGLJPrice(treeNode.data.adjustPrice);
             let mprice = me.uiGLJPrice(treeNode.data.marketUnitFee);
@@ -379,6 +396,84 @@ let calcTools = {
         }
         return result;
     },
+    supplyABFee: function (treeNode, baseName) {
+        if (!treeNode.data.gljList) return 0;
+        let projectGLJ = projectObj.project.projectGLJ;
+
+        let supplyT = [];
+        if (baseName.includes('甲供'))
+            supplyT = [supplyType.BFJG, supplyType.WQJG]  // 字段中存储的是汉字!
+            // supplyT = ['部分甲供', '完全甲供']
+        else if (baseName.includes('甲定'))
+            supplyT = [supplyType.JDYG];
+            // supplyT = ['甲定乙供'];
+
+        let gljT = [], compositionTypesArr = [];
+        if (baseName == calcBaseNames.JGDEJJRGF || baseName == calcBaseNames.JDDEJJRGF){
+            gljT = [gljType.LABOUR];
+        }
+        else if (baseName == calcBaseNames.JGDEJJCLF || baseName == calcBaseNames.JDDEJJCLF){
+            gljT = baseMaterialTypes;
+            compositionTypesArr = compositionTypes;
+        }
+        else if (baseName == calcBaseNames.JGDEJJJXF || baseName == calcBaseNames.JDDEJJJXF){
+            gljT = baseMachineTypes;
+            compositionTypesArr = [gljType.GENERAL_MACHINE];
+        }
+        else if (baseName == calcBaseNames.JGZCF || baseName == calcBaseNames.JDZCF){
+            gljT = [gljType.MAIN_MATERIAL];
+            compositionTypesArr = [gljType.MAIN_MATERIAL];
+        }
+        else if (baseName == calcBaseNames.JGSBF || baseName == calcBaseNames.JDSBF){
+            gljT = [gljType.EQUIPMENT];
+        };
+
+        let supplyProjectGLJs = projectGLJ.getGLJsBySupply(supplyT, gljT);
+        if (supplyProjectGLJs.length == 0) return 0;
+
+        let pGLJIdx = {};
+        for (let pglj of supplyProjectGLJs){pGLJIdx[pglj.id] = pglj};
+
+        let sum = 0;
+        for (let glj of treeNode.data.gljList){
+            // 组成物的母体。母体如果有组成物,则母体无法作为甲供材料,无法设置,此时要看其组成物是否是甲供材料;母体如果没有组成物,则母体有可能成为甲供材料。
+            if (compositionTypesArr.includes(glj.type)) {
+                if (pGLJIdx[glj.projectGLJID]) {  // 组成物的母体是甲供材料
+                    sum = (sum + glj.basePrice * glj.quantity).toDecimal(decimalObj.process);
+                }
+                else{  // 组成物明细
+                    let pGLJ = projectGLJ.getDataByID(glj.projectGLJID);
+                    let compositions = pGLJ.ratio_data;
+                    if (compositions.length > 0){
+                        function isSupply(composition, supplies) {
+                            for (let supply of supplies){
+                                if(supply.code == composition.code && supply.name == composition.name && supply.unit == composition.unit &&
+                                    supply.specs == composition.specs && supply.type == composition.type ){
+                                    composition.basePrice = supply.unit_price.base_price;
+                                    return true;
+                                }
+                            };
+                            return false;
+                        };
+
+                        for (let composition of compositions){
+                            if (isSupply(composition, supplyProjectGLJs)) {
+                                sum = (sum + composition.basePrice * composition.consumption * glj.quantity).toDecimal(decimalObj.process);
+                            }
+                        };
+                    }
+                }
+            }
+            else {
+                if (pGLJIdx[glj.projectGLJID]) {
+                    sum = (sum + glj.basePrice * glj.quantity).toDecimal(decimalObj.process);
+                }
+            };
+
+        };
+        sum = sum.toDecimal(decimalObj.ration.unitPrice);
+        return sum;
+    },
     getCalcType: function (treeNode) {
         if (this.isRationCategory(treeNode)){
             return treeNodeCalcType.ctRationCalcProgram;
@@ -463,6 +558,36 @@ let calcTools = {
     }
 };
 
+const calcBaseNames = {
+    DEJJRGF: '定额基价人工费',
+    DEJJCLF: '定额基价材料费',
+    DEJJJXF: '定额基价机械费',
+    DEJJJSRGF: '定额基价机上人工费',
+    RGFJC: '人工费价差',
+    CLFJC: '材料费价差',
+    JXFJC: '机械费价差',
+    ZCF: '主材费',
+    SBF: '设备费',
+    RGGR: '人工工日',
+    JGDEJJRGF: '甲供定额基价人工费',
+    JGDEJJCLF: '甲供定额基价材料费',
+    JGDEJJJXF: '甲供定额基价机械费',
+    JGZCF: '甲供主材费',
+    JGSBF: '甲供设备费',
+    JDDEJJRGF: '甲定定额基价人工费',
+    JDDEJJCLF: '甲定定额基价材料费',
+    JDDEJJJXF: '甲定定额基价机械费',
+    JDZCF: '甲定主材费',
+    JDSBF: '甲定设备费',
+    ZGCLF: '暂估材料费',
+    FBDEJJRGF: '分包定额基价人工费',
+    FBDEJJCLF: '分包定额基价材料费',
+    FBDEJJJXF: '分包定额基价机械费',
+    FBZCF: '分包主材费',
+    FBSBF: '分包设备费',
+    FBRGGR: '分包人工工日'
+};
+
 const rationCalcBases = {
     '定额基价人工费': function (node) {
         return calcTools.rationBaseFee(node, [gljType.LABOUR], priceTypes.ptBasePrice);
@@ -503,24 +628,34 @@ const rationCalcBases = {
         return rst.toDecimal(decimalObj.glj.quantity);
     },
     '甲供定额基价人工费': function (node) {
+        return calcTools.supplyABFee(node, calcBaseNames.JGDEJJRGF);
     },
     '甲供定额基价材料费': function (node) {
+        return calcTools.supplyABFee(node, calcBaseNames.JGDEJJCLF);
     },
     '甲供定额基价机械费': function (node) {
+        return calcTools.supplyABFee(node, calcBaseNames.JGDEJJJXF);
     },
     '甲供主材费': function (node) {
+        return calcTools.supplyABFee(node, calcBaseNames.JGZCF);
     },
     '甲供设备费': function (node) {
+        return calcTools.supplyABFee(node, calcBaseNames.JGSBF);
     },
     '甲定定额基价人工费': function (node) {
+        return calcTools.supplyABFee(node, calcBaseNames.JDDEJJRGF);
     },
     '甲定定额基价材料费': function (node) {
+        return calcTools.supplyABFee(node, calcBaseNames.JDDEJJCLF);
     },
     '甲定定额基价机械费': function (node) {
+        return calcTools.supplyABFee(node, calcBaseNames.JDDEJJJXF);
     },
     '甲定主材费': function (node) {
+        return calcTools.supplyABFee(node, calcBaseNames.JDZCF);
     },
     '甲定设备费': function (node) {
+        return calcTools.supplyABFee(node, calcBaseNames.JDSBF);
     },
     '暂估材料费': function (node) {
         return calcTools.estimateFee(node, true);
@@ -978,7 +1113,7 @@ class CalcProgram {
             let nodes = (treeNode.calcType == treeNodeCalcType.ctGatherBillsFees) ? treeNode.children : me.project.Ration.getRationNodes(treeNode);
             let rst = [];
             for (let ft of cpFeeTypes) {
-                let isEstimate = ft.name == '暂估费';
+                let isEstimate = ft.type == 'estimate';
                 let ftObj = {};
                 ftObj.fieldName = ft.type;
                 ftObj.name = ft.name;
@@ -1002,14 +1137,14 @@ class CalcProgram {
                         let rq = calcTools.uiNodeQty(node) ? calcTools.uiNodeQty(node) : 0;
                         let ruf = 0, rtuf = 0, rtf = 0, rttf = 0;
                         if (node.data.feesIndex && node.data.feesIndex[ft.type]) {
-                            ruf = parseFloat(node.data.feesIndex[ft.type].unitFee);
-                            rtuf = parseFloat(node.data.feesIndex[ft.type].tenderUnitFee);
-                            rtf = parseFloat(node.data.feesIndex[ft.type].totalFee);
-                            rttf = parseFloat(node.data.feesIndex[ft.type].tenderTotalFee);
+                            ruf = parseFloatPlus(node.data.feesIndex[ft.type].unitFee).toDecimal(decimalObj.bills.unitPrice);
+                            rtuf = parseFloatPlus(node.data.feesIndex[ft.type].tenderUnitFee).toDecimal(decimalObj.bills.unitPrice);
+                            rtf = parseFloatPlus(node.data.feesIndex[ft.type].totalFee).toDecimal(decimalObj.bills.totalPrice);
+                            rttf = parseFloatPlus(node.data.feesIndex[ft.type].tenderTotalFee).toDecimal(decimalObj.bills.totalPrice);
                         };
                         if (me.project.property.billsCalcMode === leafBillGetFeeType.rationContent) {
-                            buf = (buf + (ruf * rq / bq).toDecimal(decimalObj.bills.unitFee)).toDecimal(decimalObj.bills.unitFee);
-                            btuf = (btuf + (rtuf * rq / bq).toDecimal(decimalObj.bills.unitFee)).toDecimal(decimalObj.bills.unitFee);
+                            buf = (buf + (ruf * parseFloatPlus(node.data.contain)).toDecimal(decimalObj.bills.unitPrice)).toDecimal(decimalObj.process);
+                            btuf = (btuf + (rtuf * parseFloatPlus(node.data.contain)).toDecimal(decimalObj.bills.unitPrice)).toDecimal(decimalObj.process);
                         };
                         sum_rtf = (sum_rtf + rtf).toDecimal(decimalObj.process);
                         sum_rttf = (sum_rttf + rttf).toDecimal(decimalObj.process);
@@ -1091,11 +1226,12 @@ class CalcProgram {
             }
 
             let f = treeNode.data.feeRate ? treeNode.data.feeRate : 100;
-            let q = calcTools.uiNodeQty(treeNode) ? calcTools.uiNodeQty(treeNode) : 1;
             let b = treeNode.data.calcBaseValue ? treeNode.data.calcBaseValue : 0;
-            let uf = (b * f * q / 100).toDecimal(decimalObj.bills.unitPrice);
+            let q = calcTools.uiNodeQty(treeNode) ? calcTools.uiNodeQty(treeNode) : 1;
+            let uf = (b * f * 0.01 / q).toDecimal(decimalObj.bills.unitPrice);
             let tuf = uf;
-            let tf = (me.project.property.billsCalcMode === leafBillGetFeeType.rationPrice) ? (b * f / 100).toDecimal(decimalObj.bills.totalPrice) : (uf * q).toDecimal(decimalObj.bills.totalPrice);
+            let tf = (me.project.property.billsCalcMode === leafBillGetFeeType.rationPrice) ? (b * f / 100) : (uf * q);
+            tf = tf.toDecimal(decimalObj.bills.totalPrice);
             let ttf = tf;
             deleteUselessFees(treeNode);
             calcTools.checkFeeField(treeNode, {'fieldName': 'common', 'unitFee': uf, 'totalFee': tf});
@@ -1117,15 +1253,12 @@ class CalcProgram {
         else{
             let fnArr = [];
             if (treeNode.calcType == treeNodeCalcType.ctRationCalcProgram) {
-                if (treeNode.data.type == rationType.volumePrice){
+                if (treeNode.data.type == rationType.volumePrice || treeNode.data.type == rationType.gljRation){
                     delete treeNode.data.gljList;
                     let muf = treeNode.data.marketUnitFee ? treeNode.data.marketUnitFee : 0;
                     let q = calcTools.uiNodeQty(treeNode) ? calcTools.uiNodeQty(treeNode) : 0;
                     treeNode.data.marketTotalFee = (muf * q).toDecimal(decimalObj.ration.totalPrice);
                 }
-                else if (treeNode.data.type == rationType.gljRation){
-
-                }
                 else{
                     treeNode.data.gljList = me.project.ration_glj.getGljArrByRation(treeNode.data.ID);
                     // 计算程序里没有暂估费的计算规则,会漏掉,所以这里要专门算。

+ 35 - 1
web/building_saas/main/js/models/installation_fee.js

@@ -22,7 +22,41 @@ var installation_fee = {
         installation_fee.prototype.loadData = function (datas) {
             this.datas = datas;
         };
-
+        installation_fee.prototype.getInstallationFeeByLibID=function(libID){
+            return _.find(this.datas,{'libID':libID});
+        };
+        installation_fee.prototype.getFeeRuleByFeeItem = function (feeItem) {
+            let installFee = projectObj.project.installation_fee.getInstallationFeeByLibID(feeItem.libID);
+            let impacRules = _.filter(installFee.feeRule,{'feeItemId':feeItem.ID});
+            return impacRules;
+        };
+        installation_fee.prototype.getFeeRuleBySection = function (section) {
+            let installFee = projectObj.project.installation_fee.getInstallationFeeByLibID(section.libID);
+            let impacRules = _.filter(installFee.feeRule,{'sectionId':section.ID});
+            return impacRules;
+        };
+        installation_fee.prototype.getInstallSectionsByfeeItemID=function(libID,feeItemId){
+            let installationFee = this.getInstallationFeeByLibID(libID);
+            let installSections = _.filter(installationFee.installSection,{'feeItemId':feeItemId});
+            return installSections;
+        };
+        installation_fee.prototype.getFeeItemByID = function(libID,ID){
+            let installFee = projectObj.project.installation_fee.getInstallationFeeByLibID(libID);
+            return _.find(installFee.installFeeItem,{'ID':ID});
+        };
+        installation_fee.prototype.getInstallSectionByID = function(libID,ID){
+            let installFee = projectObj.project.installation_fee.getInstallationFeeByLibID(libID);
+            return _.find(installFee.installSection,{'ID':ID});
+        };
+        installation_fee.prototype.getFeeRuleBySectionID=function(libID,sectionId){
+            let installationFee = this.getInstallationFeeByLibID(libID);
+            let feeRules = _.filter(installationFee.feeRule,{'sectionId':sectionId});
+            return feeRules;
+        };
+        installation_fee.prototype.getFeeRuleByID = function (libID,feeRuleID) {
+            let installationFee = this.getInstallationFeeByLibID(libID);
+            return _.find(installationFee.feeRule,{'ID':feeRuleID});
+        };
         // 提交数据后返回数据处理
         installation_fee.prototype.doAfterUpdate = function(err, data){
 

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

@@ -55,6 +55,7 @@ const baseMaterialTypes = [
     gljType.COMMERCIAL_CONCRETE,
     gljType.COMMERCIAL_MORTAR
 ];
+// 计算基数 [定额基价机械费] 要用到的机械类型。
 const baseMachineTypes = [
     gljType.GENERAL_MACHINE,
     gljType.MACHINE_COMPOSITION,
@@ -76,7 +77,9 @@ const compositionTypes = [
     gljType.MAIN_MATERIAL,
     gljType.CONCRETE,
     gljType.MORTAR,
-    gljType.MIX_RATIO];
+    gljType.MIX_RATIO
+];
+
 const notEditType = [
     gljType.CONCRETE,
     gljType.MORTAR,
@@ -283,3 +286,6 @@ const engineeringType = {
     // 安装修缮工程
     BUILD_IN_REPAIR: 14
 };
+
+const installFeeType = ['子目费用','分项费用','措施费用'];
+const installSectionBase = ['分别按人材机乘系数','人工','材料','机械'];

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

@@ -64,25 +64,15 @@ ProjectGLJ.prototype.loadToCache = function (data) {
  * @param {String} code
  * @return {Object}
  */
-ProjectGLJ.prototype.getDataByCode = function (code) {
-    let result = {};
-    if (this.datas === null) {
-        return result;
-    }
-
-    let gljList = this.datas.gljList;
-    if (gljList === undefined) {
-        return result;
-    }
-
-    for (let tmp of gljList) {
-        if (tmp.code === code) {
-            result = tmp;
-            break;
-        }
-    }
+ProjectGLJ.prototype.getDataByID = function (ID) {//根据项目工料机ID取工料机信息
+   return _.find(this.datas.gljList, {'id': ID});
+};
 
-    return result;
+// CSL, 2018-02-08 甲供、甲定。
+ProjectGLJ.prototype.getGLJsBySupply = function (supplyTypeArr, gljTypeArr) {
+    return _.filter(this.datas.gljList, function (glj) {
+        return supplyTypeArr.includes(glj.supply) && gljTypeArr.includes(glj.type);
+    });
 };
 
 /**

+ 111 - 40
web/building_saas/main/js/views/calc_base_view.js

@@ -2,19 +2,25 @@
  * Created by Zhong on 2017/12/1.
  */
 /*
-* 清单计算基数
+* 计算基数,清单、定额统一ui
 * */
 let calcBaseView = {
     //可用计算基数的清单固定列映射(与fixedFlag)
     inputExpr: $('#calcBaseExp'),
     confirmBtn: $('#calcBaseConf'),
+    type: {bills: 'bills', ration: 'ration'},
+    billsCBClass:{ALL: [], FBFX: [], CSXM: [], QTXM: [], FBF: [], RCJ: [], GF: [], SJ: [], SQGCZJ: []},
+    curType: null,
     editingCell: null,
     workBook: null,
     setting:{
-        header: [
+        billsHeader: [
             {name: '计算基础名称', dataCode: 'base', width: 280, vAlign: 'center', hAlign: 'left'},
             {name: '金额', dataCode: 'price', width: 120, vAlign: 'center', hAlign: 'right'}
         ],
+        rationHeader: [
+            {name: '定额计算程序基数名称', dataCode: 'base', width: 400, vAlign: 'center', hAlign: 'left'}
+        ],
         options: {
             tabStripVisible:  false,
             allowCopyPasteExcelStyle : false,
@@ -25,7 +31,7 @@ let calcBaseView = {
         },
         locked: {
             rows: [],
-            cols: [0, 1]
+            cols: [0]
         }
     },
 
@@ -62,6 +68,14 @@ let calcBaseView = {
         if(!this.workBook){
             this.workBook = new GC.Spread.Sheets.Workbook($('#billsBaseSpread')[0], {sheetCount: 1});
             this.setOptions(this.workBook, this.setting.options);
+            //bills
+            if(this.curType === this.type.bills){
+                this.setting.header = this.setting.billsHeader;
+            }
+            //ration
+            else {
+                this.setting.header = this.setting.rationHeader;
+            }
             this.buildHeader(this.workBook.getActiveSheet(), this.setting.header);
             this.bindEvent(this.workBook);
         }
@@ -79,9 +93,8 @@ let calcBaseView = {
         let cols = this.setting.header;
         let fuc = function () {
             sheet.setRowCount(datas.length);
-            //sheet.setFormatter(-1, 1, '@');
             let style = new GC.Spread.Sheets.Style();
-            style.formatter = MainTreeCol.getNumberFormatter(decimalObj.bills.totalPrice, true);
+            //style.formatter = MainTreeCol.getNumberFormatter(decimalObj.bills.totalPrice, true);
             sheet.setStyle(-1, 1, style);
             for(let col = 0, cLen = cols.length; col < cLen; col++){
                 sheet.getRange(-1, col, -1, 1).hAlign(GC.Spread.Sheets.HorizontalAlign[cols[col]['hAlign']]);
@@ -97,7 +110,11 @@ let calcBaseView = {
     onCellDoubleClick: function (sender, args) {
         let me = calcBaseView;
         if(args.col === 0){
-            let baseFigure = '{' + args.sheet.getValue(args.row, args.col) + '}';
+            let v = args.sheet.getValue(args.row, args.col);
+            if(!me.isDef(v)){
+                return;
+            }
+            let baseFigure = `{${v}}`;
             if(baseFigure.trim() !== ''){
                 //在光标后面插入
                 let insertStr = me.insertStr(baseFigure);
@@ -109,17 +126,23 @@ let calcBaseView = {
     isDef: function (v) {
         return v !== undefined && v !== null;
     },
-    isFlag: function (v) {
-        return this.isDef(v.flagsIndex) && this.isDef(v.flagsIndex.fixed);
-    },
     ifEdit: function () {
         var selected = projectObj.project.mainTree.selected;
         return MainTreeCol.readOnly.forCalcBase(selected)?false:true;
     },
-    canBase: function (node) {
-        return node.sourceType === projectObj.project.Bills.getSourceType() && node.children.length === 0;
+    bindClassBtn: function () {
+        let me = this;
+        for(let clas in me.billsCBClass){
+            let jqS = `#cb_${clas}`;
+            $(jqS).click(function () {
+                sheetCommonObj.cleanData(me.workBook.getSheet(0), me.setting, -1);
+                me.showData(me.billsCBClass[clas]);
+                $('#cbClassList li .btn ').removeClass('btn btn-outline-secondary btn-sm active');
+                $(this).addClass('btn btn-outline-secondary btn-sm active');
+            });
+        }
     },
-    //计算基数转换为显示数据Obj to Array
+    //计算基数转换为显示数据Obj to Array, 给清单基数分类赋值
     toViewData: function (obj) {
         let rst = [];
         for(let figure in obj){
@@ -127,20 +150,51 @@ let calcBaseView = {
             figureObj.base = figure;
             figureObj.price = projectObj.project.calcBase.getBase(figure);
             rst.push(figureObj);
+            //set class datas
+            this.billsCBClass.ALL.push(figureObj);
+            this.billsCBClass[obj[figure]['class']].push(figureObj);
         }
-        return rst;
+        return this.billsCBClass.ALL;
     },
 
-    initCalctor: function (node) {
+    initCalctor: function (type) {//type = bills、ration
         let me = calcBaseView;
-        //输入框显示原本的
-        if(me.isDef(node.data.calcBase)){
-            me.inputExpr.val(cbParser.toFExpr(node.data.calcBase));
+        let showDatas;
+        me.curType = type;
+        if(type === me.type.bills){//bills
+            //显示清单基数分类
+            $('#cbClassList').show();
+            $('#qd-jsjs .modal-content').css('width', '670px');
+            $('#cbRowDiv').addClass('row');
+            $('#billsBaseSpread').addClass('col-9');
+            //
+            let node = projectObj.project.mainTree.selected;
+            //输入框显示原本的
+            if(me.isDef(node.data.calcBase)){
+                me.inputExpr.val(cbParser.toFExpr(node.data.calcBase));
+            }
+            let baseObj = projectObj.project.calcBase.getBaseByClass(node);
+            showDatas = me.toViewData(baseObj);
+            $('#cbClassList li .btn ').removeClass('btn btn-outline-secondary btn-sm active');
+            $('#cb_ALL').addClass('btn btn-outline-secondary btn-sm active');
+        }
+        else{//ration
+            //去除清单基数分类
+            $('#cbClassList').hide();
+            $('#qd-jsjs .modal-content').css('width', '');
+            $('#cbRowDiv').removeClass('row');
+            $('#billsBaseSpread').removeClass('col-9');
+
+            let bnArr = Object.keys(rationCalcBases);
+            let baseArr = [];
+            for (let bn of bnArr){
+                 baseArr.push({base: bn})
+            };
+            showDatas = baseArr;
         }
         me.buildSheet();
-        let baseObj = projectObj.project.calcBase.getBaseByClass(node);
-        // console.log(baseObj);
-        me.showData(me.toViewData(baseObj));
+        me.showData(showDatas);
+        $('#qd-jsjs').modal('show');
 
     },
 
@@ -200,31 +254,38 @@ let calcBaseView = {
     calcBaseConf: function () {
         let me = calcBaseView;
         me.confirmBtn.bind('click', function () {
-            let selected = projectObj.project.mainTree.selected;
-            projectObj.updateCellValue(selected, me.getInputExpr(), {data: {field: 'calcBase'}});
-            if(projectObj.project.calcBase.success){
-                $('#qd-jsjs').modal('hide');
+            //bills
+            if(me.curType === me.type.bills){
+                let selected = projectObj.project.mainTree.selected;
+                projectObj.updateCellValue(selected, me.getInputExpr(), {data: {field: 'calcBase'}});
+                if(projectObj.project.calcBase.success){
+                    $('#qd-jsjs').modal('hide');
+                }
+            }
+            //ration
+            else{
+
             }
         });
     },
 
-    getCalcBaseCellType:function () {
+    getCalcBaseCellType:function (type) {
         var ns = GC.Spread.Sheets;
         function CalcBaseCellType() {
             var init=false;
         }
         CalcBaseCellType.prototype = new ns.CellTypes.Text();
         CalcBaseCellType.prototype.paint = function (ctx, value, x, y, w, h, style, options) {
-          //  if(value!=null){
-               // ctx.fillText(value,x+3+ctx.measureText(value).width,y+h-3);
-               // ctx.fillText(value,x+w-3,y+h-3);
-                GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
-           // }
+            //  if(value!=null){
+            // ctx.fillText(value,x+3+ctx.measureText(value).width,y+h-3);
+            // ctx.fillText(value,x+w-3,y+h-3);
+            GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments);
+            // }
             if(calcBaseView.editingCell){
                 if(calcBaseView.editingCell.row==options.row&&calcBaseView.editingCell.col==options.col){
                     var image = document.getElementById('f_btn'),imageMagin = 3;
                     var imageHeight = h-2*imageMagin;
-                    var imageWidth = w*2/7;
+                    var imageWidth = w*2/(type=='bills'?7:20);
                     var imageX = x + w - imageWidth- imageMagin, imageY = y + h / 2 - imageHeight / 2;
                     ctx.save();
                     ctx.drawImage(image, imageX, imageY,imageWidth,imageHeight);
@@ -252,6 +313,7 @@ let calcBaseView = {
         };
         CalcBaseCellType.prototype.processMouseDown = function (hitinfo) {
             let me=calcBaseView;
+            me.pmLeave = false;
             if(me.editingCell==null){
                 var showSelectBtn = true;
                 if(hitinfo.sheet.name()!='calc_detail'){
@@ -271,30 +333,36 @@ let calcBaseView = {
                 var imageHeight = hitinfo.cellRect.height-2*imageMagin;
                 var imageWidth = hitinfo.cellRect.width*2/7;
                 if(hitinfo.x<offset&&hitinfo.x>offset-imageWidth){
-                    $('#qd-jsjs').modal({show: true});
+                    calcBaseView.initCalctor(type);
                 }
             }
         };
         CalcBaseCellType.prototype.processMouseLeave = function (hitinfo) {
-            calcBaseView.editingCell=null;
-            hitinfo.sheet.invalidateLayout();
-            hitinfo.sheet.repaint();
+            if(!calcBaseView.pmLeave){
+                calcBaseView.editingCell=null;
+                hitinfo.sheet.invalidateLayout();
+                hitinfo.sheet.repaint();
+                calcBaseView.pmLeave = true;
+            }
         }
         return new CalcBaseCellType();
     },
 };
 
 $(document).ready(function () {
-   $('#qd-jsjs').on('shown.bs.modal', function () {
-       calcBaseView.initCalctor(projectObj.project.mainTree.selected);
-       calcBaseView.workBook.refresh();
-   });
+    $('#qd-jsjs').on('shown.bs.modal', function () {
+        calcBaseView.workBook.refresh();
+    });
 
     $('#qd-jsjs').on('hidden.bs.modal', function () {
         //清空输入框
         calcBaseView.inputExpr.val('');
         calcBaseView.workBook.destroy();
         calcBaseView.workBook = null;
+        //清空清单分类数据
+        for(let attr in calcBaseView.billsCBClass){
+            calcBaseView.billsCBClass[attr] = [];
+        }
     });
 
     //bind operator click function
@@ -305,4 +373,7 @@ $(document).ready(function () {
 
     //confirmBtn
     calcBaseView.calcBaseConf();
-});
+
+    //class btn
+    calcBaseView.bindClassBtn();
+});

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

@@ -66,6 +66,7 @@ let calcProgramManage = {
 
         let dSheet = me.detailSpread.getSheet(0);
         feeRateObject.setFeeRateCellCol(dSheet,_.findIndex(me.detailSetting.header,{'dataCode':'feeRate'}));
+        dSheet.getRange(-1, _.findIndex(me.detailSetting.header, {'dataCode': 'dispExprUser'}), -1, 1).cellType(calcBaseView.getCalcBaseCellType('ration'));
         dSheet.name('calc_detail');
         sheetCommonObj.showData(dSheet, me.detailSetting, me.datas[0].calcItems);
     },

+ 7 - 3
web/building_saas/main/js/views/fee_rate_view.js

@@ -287,6 +287,7 @@ var feeRateObject={
         };
         FeeRateEditCellType.prototype.processMouseDown = function (hitinfo) {
             var me=feeRateObject;
+            me.pmLeave = false;
             if(me.editingCell==null){
                 var showSelectBtn = true;
                 if(hitinfo.sheet.name()!='calc_detail'){
@@ -311,9 +312,12 @@ var feeRateObject={
             }
         };
         FeeRateEditCellType.prototype.processMouseLeave = function (hitinfo) {
-            feeRateObject.editingCell=null;
-            hitinfo.sheet.invalidateLayout();
-            hitinfo.sheet.repaint();
+            if(!feeRateObject.pmLeave){
+                feeRateObject.editingCell=null;
+                hitinfo.sheet.invalidateLayout();
+                hitinfo.sheet.repaint();
+                feeRateObject.pmLeave = true;
+            }
         }
         return new FeeRateEditCellType();
     },

+ 10 - 2
web/building_saas/main/js/views/glj_view.js

@@ -659,7 +659,6 @@ var gljOprObj = {
                 me.updateRationAss(args);
             }
         }
-        ;
     },
     generateHtmlString: function () {
 //        return "<div id='edit'><div>";
@@ -902,6 +901,15 @@ var gljOprObj = {
         return data;
 
     },
+    getBasePrice:function (treeNode) {//造价书中的工料机修改的节点要用到
+        let proGLJ =  projectObj.project.projectGLJ;
+        let glj =_.find(proGLJ.datas.gljList, {'id': treeNode.data.projectGLJID});
+        if(this.calcPriceDiff(glj)==true){
+            return proGLJ.getBasePrice(glj);
+        }else {
+            return scMathUtil.roundForObj(treeNode.data.marketUnitFee,getDecimal("glj.unitPrice"));
+        }
+    },
     calcPriceDiff:function (glj) {
         let calcOptions=projectInfoObj.projectInfo.property.calcOptions;
         if(glj.is_evaluate==1){//先按是否暂估判断
@@ -1178,8 +1186,8 @@ var gljOprObj = {
     },
     showLibGLJSheetData: function () {
         this.gljLibSheetData = _.sortBy(this.gljLibSheetData, 'code');
-        this.gljLibSheet.setRowCount(this.gljLibSheetData.length);
         sheetCommonObj.showData(this.gljLibSheet, this.gljLibSheetSetting, this.gljLibSheetData, gljOprObj.distTypeTree);
+        this.gljLibSheet.setRowCount(this.gljLibSheetData.length);
     },
     filterLibGLJSheetData: function () {
         let me = this;

+ 882 - 17
web/building_saas/main/js/views/installation_fee_view.js

@@ -3,25 +3,163 @@
  */
 let installationFeeObj={
     rationInstallSheet:null,
-    installationFeeSpread:null,
-    rationInstallsetting: {
+    feeItemSpread:null,
+    feeItemSheet:null,
+    feeItemData:null,
+    feeItemSetting:{
         header: [
-            {headerName: "按统一设置", headerWidth: 100, dataCode: "name", dataType: "String"},
-            {headerName: "费用项", headerWidth: 120, dataCode: "stdValue", hAlign: "right", dataType: "String"},
-            {headerName: "费用规则", headerWidth: 120, dataCode: "actualValue", hAlign: "right", dataType: "String"},
-            {headerName: "编码", headerWidth: 120, dataCode: "actualValue", hAlign: "right", dataType: "String"},
-            {headerName: "基数", headerWidth: 120, dataCode: "actualValue", hAlign: "right", dataType: "String"},
-            {headerName: "费率(%)", headerWidth: 120, dataCode: "actualValue", hAlign: "right", dataType: "String"},
-            {headerName: "其中人工(%)", headerWidth: 120, dataCode: "actualValue", hAlign: "right", dataType: "String"},
-            {headerName: "其中材料(%)", headerWidth: 120, dataCode: "actualValue", hAlign: "right", dataType: "String"},
-            {headerName: "其中机械(%)", headerWidth: 120, dataCode: "actualValue", hAlign: "right", dataType: "String"},
-            {headerName: "费用类型", headerWidth: 120, dataCode: "actualValue", hAlign: "right", dataType: "String"},
-            {headerName: "记取位置", headerWidth: 120, dataCode: "actualValue", hAlign: "right", dataType: "String"}
+            {headerName: "计取", headerWidth: 90, dataCode: "isCal", dataType: "String",cellType: "checkBox"},
+            {headerName: "费用项", headerWidth: 300, dataCode: "feeItem", hAlign: "left", dataType: "String"},
+            {headerName: "费用类型", headerWidth: 100, dataCode: "feeType", hAlign: "center", dataType: "String",cellType:'comboBox',options:installFeeType},
+            {headerName: "记取位置", headerWidth: 140, dataCode: "displayPosition", hAlign: "left", dataType: "String",cellType:'selectButton'}
         ],
         view: {
-            lockColumns: [0, 1]
+            lockColumns: [0,1]
         }
     },
+    feeDetailSpread:null,
+    feeDetailSheet:null,
+    feeDetailData:null,
+    feeDetailSetting: {
+        header: [
+            {headerName: "分册章节", headerWidth: 150, dataCode: "name", dataType: "String"},
+            {headerName: "费用规则", headerWidth: 220, dataCode: "rule", hAlign: "left", dataType: "String",getText:'forRule'},
+            {headerName: "编码", headerWidth: 70, dataCode: "code", hAlign: "left", dataType: "String"},
+            {headerName: "基数", headerWidth: 80, dataCode: "base", hAlign: "left", dataType: "String",cellType:'comboBox',options:installSectionBase},
+            {headerName: "费率(%)", headerWidth: 80, dataCode: "feeRate", hAlign: "right", dataType: "String"},
+            {headerName: "其中人工(%)", headerWidth: 100, dataCode: "labour", hAlign: "right", dataType: "String"},
+            {headerName: "其中材料(%)", headerWidth: 100, dataCode: "material", hAlign: "right", dataType: "String"},
+            {headerName: "其中机械(%)", headerWidth: 100, dataCode: "machine", hAlign: "right", dataType: "String"},
+            {headerName: "记取位置", headerWidth: 100, dataCode: "position", hAlign: "left", dataType: "String",cellType:'selectButton'}
+        ],
+        view: {
+            lockColumns: [0, 2]
+        },
+        autoFit:true,
+        getText:{
+            forRule:function (item,val) {
+                if(item.feeRuleId&&item.feeRuleId!=""){
+                    let subRule = _.find(item.impactRules,{'ID':item.feeRuleId});
+                    if(!subRule){
+                        val = item.ruleName;
+                    }
+                }
+                return val;
+            }
+        }
+    },
+    positionSpread:null,
+    positionSheet:null,
+    positionData:null,
+    moreFeeRuleSpread:null,
+    moreFeeRuleSheet:null,
+    moreFeeRuleData:null,
+    moreFeeRuleSetting:{
+        header: [
+            {headerName: "编码", headerWidth: 70, dataCode: "code", hAlign: "left", dataType: "String"},
+            {headerName: "费用规则", headerWidth: 320, dataCode: "rule", hAlign: "left", dataType: "String"},
+            {headerName: "基数", headerWidth: 140, dataCode: "base", hAlign: "center", dataType: "String"},
+            {headerName: "费率(%)", headerWidth: 80, dataCode: "feeRate", hAlign: "right", dataType: "String"},
+            {headerName: "人工(%)", headerWidth: 80, dataCode: "labour", hAlign: "right", dataType: "String"},
+            {headerName: "材料(%)", headerWidth: 80, dataCode: "material", hAlign: "right", dataType: "String"},
+            {headerName: "机械(%)", headerWidth: 80, dataCode: "machine", hAlign: "right", dataType: "String"}
+        ],
+        view: {
+            lockColumns: [0,1,2,3,4,5,6]
+        }
+    },
+    selectionTree:null,
+    selectionTreeController:null,
+    positionSetting:{
+        "emptyRows":0,
+        "headRows":1,
+        "headRowHeight":[30],
+        "defaultRowHeight": 21,
+        "treeCol": 0,
+        "cols":[
+            {
+                "width":250,
+                "readOnly": true,
+                "head":{
+                    "titleNames":["编码"],
+                    "spanCols":[1],
+                    "spanRows":[1],
+                    "vAlign":[1],
+                    "hAlign":[1],
+                    "font":["Arial"]
+                },
+                "data":{
+                    "field":"code",
+                    "vAlign":1,
+                    "hAlign":0,
+                    "font":"Arial"
+                }
+             },
+            {
+                "width":100,
+                "readOnly": true,
+                "head":{
+                    "titleNames":["类别"],
+                    "spanCols":[1],
+                    "spanRows":[1],
+                    "vAlign":[1],
+                    "hAlign":[1],
+                    "font":["Arial"]
+                },
+                "data":{
+                    "field":"type",
+                    "vAlign":1,
+                    "hAlign":1,
+                    "font":"Arial"
+                }
+            },
+            {
+                "width":250,
+                "readOnly": true,
+                "head":{
+                    "titleNames":["名称"],
+                    "spanCols":[1],
+                    "spanRows":[1],
+                    "vAlign":[1],
+                    "hAlign":[1],
+                    "font":["Arial"]
+                },
+                "data":{
+                    "field":"name",
+                    "vAlign":0,
+                    "hAlign":0,
+                    "font":"Arial"
+                }
+            },
+            {
+                "width":100,
+                "readOnly": true,
+                "head":{
+                    "titleNames":["具体位置"],
+                    "spanCols":[1],
+                    "spanRows":[1],
+                    "vAlign":[1],
+                    "hAlign":[1],
+                    "font":["Arial"]
+                },
+                "data":{
+                    "field":"selected",
+                    "vAlign":1,
+                    "hAlign":1,
+                    "font":"Arial",
+                    "cellType":function (node) {
+                        if(node.data.canSelect == true){
+                            return new GC.Spread.Sheets.CellTypes.CheckBox();
+                        }
+                    }
+                }
+            }
+        ]
+
+    },
+    positionData:null,
+    positionSelectedObject:null,
+    L_M_M:null,
     showCalcInstallSettingDiv:function () {
         $("#calc_installation_fee").modal({show:true});
     },
@@ -31,17 +169,744 @@ let installationFeeObj={
         if(engineering==engineeringType.BUILD_IN){//如果是安装工程,则显示
             $('#AZZJF_div').show();
         }
+    },
+    initInstallationFeeSpread:function(){
+        //初始化费用项表格
+      this.feeItemSpread = SheetDataHelper.createNewSpread($("#feeItemSheet")[0]);
+      this.feeItemSheet = this.feeItemSpread.getSheet(0);
+      this.initSheet(this.feeItemSheet,this.feeItemSetting);
+      this.feeItemSheet.name('feeItemSheet');
+
+      this.feeItemSheet.bind(GC.Spread.Sheets.Events.SelectionChanged, this.onFeeItemSelectionChange);
+      this.feeItemSpread.bind(GC.Spread.Sheets.Events.ButtonClicked, this.onSelectButtonClick);
+      this.showFeeItemData();
+
+      //初始化章节项表格
+       this.feeDetailSpread = SheetDataHelper.createNewSpread($("#feeDetailSheet")[0]);
+       this.feeDetailSheet = this.feeDetailSpread.getSheet(0);
+       this.initSheet(this.feeDetailSheet,this.feeDetailSetting);
+       this.feeDetailSheet.bind(GC.Spread.Sheets.Events.SelectionChanged,this.onFeeDetailSelectionChange);
+       this.feeDetailSheet.bind(GC.Spread.Sheets.Events.RangeChanged, this.onDetailRangeChanged);
+       this.feeDetailSpread.bind(GC.Spread.Sheets.Events.ButtonClicked, this.onSelectButtonClick);
+       this.feeDetailSheet.name('feeDetailSheet');
+       this.feeDetailSheet.setRowCount(0);
+    },
+    onFeeItemSelectionChange:function (e, info) {
+        console.log('fee item selection change');
+        console.log(info);
+        let me = installationFeeObj;
+        let newSelections = info.newSelections;
+        let row = newSelections[0].row;
+        let selected = me.feeItemData[row];
+        let canChange = me.detailResultCheck(info);
+        if(canChange == false){
+            let os = info.oldSelections[0];
+            setTimeout(function () {//这里是因为费用项名字的单元格是自定义的树结构,点击这一列单元格切换行时,如果不设置延时的话,selectionChange事件会触发两次
+                info.sheet.setSelection(os.row,os.col,os.rowCount,os.colCount);
+            },200);
+        }else {
+            if(selected&&selected.libID){//说明是选中了费用项
+                me.positionButtonChecking(row,selected);
+                me.showFeeDetailData(selected.libID,selected.ID);
+            }else {
+                me.showFeeDetailData();
+            }
+        }
+       // me.feeItemSheet.repaint();
+    },
+    onFeeDetailSelectionChange:function (e,info) {
+        console.log('detail selection change');
+        let me = installationFeeObj;
+        if(me.detailReloadSelection){
+            info.sheet.setSelection(me.detailReloadSelection.row,me.detailReloadSelection.col,1,1);
+            me.detailReloadSelection=null;
+        }else {
+            let canChange = me.detailResultCheck(info);
+            if(canChange == false){
+                let os = info.oldSelections[0];
+                info.sheet.setSelection(os.row,os.col,os.rowCount,os.colCount);
+            }
+        }
+        me.feeDetailSheet.repaint();
+    },
+    positionButtonChecking:function (row,recode) {//按钮有效性检查
+        if(recode.feeType){
+            installationFeeObj.feeItemSheet.getCell(row,3).locked(recode.feeType=='子目费用');
+        }
+    },
+    onSelectButtonClick:function (e,info) {
+        let sheet = info.sheet, row = info.row, col = info.col;
+        let cellType = sheet.getCellType(row, col);
+        if(cellType instanceof GC.Spread.Sheets.CellTypes.Button){
+            installationFeeObj.onPositionButtonClick(e,info);
+        }else {
+            installationFeeObj.onCalcCheckBoxClick(e,info);
+        }
+    },
+    onPositionButtonClick : function(e,info){//选取位置按钮
+        $('#calc_position_from').val(info.sheetName);
+        $('#calc_position').modal({show:true});
+    },
+    onCalcCheckBoxClick: function(e,info){
+        let me = installationFeeObj;
+        var checkboxValue = info.sheet.getCell(info.row, info.col).value();
+        var newval = 0;
+        if (checkboxValue) {
+            newval = 0;
+            info.sheet.getCell(info.row, info.col).value(newval);
+        } else {
+            newval = 1;
+            info.sheet.getCell(info.row, info.col).value(newval);
+        }
+        info.newValue = newval;
+        me.onFeeItemValueChange(e,info);
+    },
+    showFeeItemData:function () {
+        this.feeItemData = this.getFeeItemData(projectObj.project.installation_fee.datas);
+        this.feeItemSheet.setRowCount(0);
+        this.feeItemSheet.getRange(-1, 1, -1, 1).cellType(gljOprObj.getTreeNodeCellType(this.feeItemData));
+        sheetCommonObj.showData(this.feeItemSheet, this.feeItemSetting, this.feeItemData);
+        this.feeItemSheet.setRowCount(this.feeItemData.length);
+        for(let i =0 ;i < this.feeItemData.length;i++){
+            let data = this.feeItemData[i];
+            if(data.hasOwnProperty('subList')){//根节点不可编辑
+                this.feeItemSheet.getRange(i,-1, 1, -1, GC.Spread.Sheets.SheetArea.viewport).locked(true);//this.feeItemSheet.getCell(i, 2).locked(true);
+                this.feeItemSheet.getRange(i,2,1,2).cellType(new GC.Spread.Sheets.CellTypes.Text());//费用类型、记取位置两列替换成普通的单元格;
+            }
+        }
+
+    },
+    showFeeDetailData:function (libID,feeItemId) {
+        this.feeDetailSheet.setRowCount(0);
+        if(libID&&feeItemId){
+            this.feeDetailData = this.getFeeDetailData(libID,feeItemId);
+        }else {
+            this.feeDetailData = []
+        }
+        sheetCommonObj.showData(this.feeDetailSheet, this.feeDetailSetting, this.feeDetailData);
+        this.feeDetailSheet.setRowCount(this.feeDetailData.length);
+        if(this.feeDetailData.length>0){
+            this.feeDetailSheet.suspendPaint();
+            this.feeDetailSheet.suspendEvent();
+            this.feeDetailSheet.getRange(0, -1, this.feeDetailData.length, -1, GC.Spread.Sheets.SheetArea.viewport).wordWrap(true);
+            let feeItem = this.feeItemData[this.feeItemSheet.getSelections()[0].row];
+            for(let i =0;i<this.feeDetailData.length;i++){
+                this.feeDetailSheet.autoFitRow(i);
+                this.setDetailRuleCell(i,this.feeDetailData[i]);//设置费用规则下拉选项
+                this.lockDetailSheet(i,this.feeDetailData[i],feeItem);
+            }
+            this.feeDetailSheet.resumeEvent();
+            this.feeDetailSheet.resumePaint();
+        }
+    },
+    showMoreFeeRule:function () {
+        this.moreFeeRuleData = this.getMoreFeeRuleData();
+        this.moreFeeRuleSheet.setRowCount(0);
+        sheetCommonObj.showData(this.moreFeeRuleSheet, this.moreFeeRuleSetting, this.moreFeeRuleData);
+        this.moreFeeRuleSheet.setRowCount(this.moreFeeRuleData.length);
+        this.moreFeeRuleSheet.clearSelection();
+    },
+    refreshFeeDetailRow:function (row) {
+        let detail = this.feeDetailData[row];
+        let section = projectObj.project.installation_fee.getInstallSectionByID(detail.libID,detail.ID);
+        this.feeDetailData[row] = this.getDetailRowDataBySection(section,detail.libID);
+        sheetCommonObj.showRowData(this.feeDetailSheet, this.feeDetailSetting,row,this.feeDetailData);
+        let feeItem = projectObj.project.installation_fee.getFeeItemByID(detail.libID,detail.feeItemId);
+        this.lockDetailSheet(row,this.feeDetailData[row],feeItem);
+    },
+    lockDetailSheet:function(row,detail,feeItem){
+        if(detail.feeRuleId){//选中了规则项
+            for(let col=0;col<this.feeDetailSetting.header.length;col++) {
+                let header = this.feeDetailSetting.header[col];
+                if(header.dataCode=='feeRate'){
+                    let baseIndex = installSectionBase.indexOf(detail.base);
+                    this.feeDetailSheet.getCell(row,col).locked(baseIndex<1);//当基数是“人材机乘系数”时,“费率(%)”列只读。
+                }
+                if(header.dataCode=='position'){
+                    this.feeDetailSheet.getCell(row,col).locked(feeItem.feeType=='子目费用');
+                }
+            }
+        }else {//没有规则项则相关的单元格都锁定
+            this.feeDetailSheet.getRange(row, 3, 1, this.feeDetailSetting.header.length-3, GC.Spread.Sheets.SheetArea.viewport).locked(true);
+        }
+    },
+    setDetailRuleCell:function(row,detail){
+        let options=[{text:"无",value:""}];
+        for(let ir of detail.impactRules){
+            options.push({text:ir.rule,value:ir.ID});
+        }
+        options.push({text:"更多",value:'more'});
+        let dynamicCombo = sheetCommonObj.getDynamicCombo();//new GC.Spread.Sheets.CellTypes.ComboBox();
+        dynamicCombo.items(options);
+        dynamicCombo.editorValueType(GC.Spread.Sheets.CellTypes.EditorValueType.value);
+        this.feeDetailSheet.setCellType(row, 1, dynamicCombo, GC.Spread.Sheets.SheetArea.viewport);
+    },
+    getFeeItemData:function (datas) {
+        let feeItemShowArray = [];
+        for(let d of datas){
+            let tem_Lib = {
+                feeItem:d.libName,
+                subList:d.installFeeItem,
+                collapsed:false
+            };
+            feeItemShowArray.push(tem_Lib);
+            if(d.installFeeItem && d.installFeeItem.length > 0){
+                for(let t_if of d.installFeeItem){
+                    t_if.installFeeID = d.ID,
+                    t_if.libID = d.libID;
+                    t_if.isMixRatio = true;
+                    t_if.displayPosition = this.getDisplayText(t_if);
+                    feeItemShowArray.push(t_if);
+                }
+            }
+        }
+        return feeItemShowArray;
+    },
+    getDisplayText:function (item) {
+        if(item.billID){
+            let node = projectObj.project.mainTree.getNodeByID(item.billID);
+            if(node){
+                return node.data.code +" "+node.data.name;
+            }
+
+        }
+        return  item.position;
+    },
+    getFeeDetailData : function(libID,feeItemId){
+        let me = installationFeeObj;
+        let feeDetailArr = [];
+        let installSections =projectObj.project.installation_fee.getInstallSectionsByfeeItemID(libID,feeItemId);
+        for(let is of installSections){
+            let tem_detail = me.getDetailRowDataBySection(is,libID);
+            feeDetailArr.push(tem_detail);
+        }
+        return feeDetailArr;
+    },
+    getMoreFeeRuleData:function () {
+        let me = installationFeeObj;
+        let fee_select = me.feeItemSheet.getSelections()[0];
+        let feeItem = me.feeItemData[fee_select.row];
+        let feeRules =  projectObj.project.installation_fee.getFeeRuleByFeeItem(feeItem);
+        return feeRules;
+    },
+    getDetailRowDataBySection(is,libID){
+        let me = this;
+        let tem_detail = {
+            ID:is.ID,
+            feeItemId:is.feeItemId,
+            name:is.name,
+            feeRuleId:is.feeRuleId,
+            libID:libID,
+            rule:is.feeRuleId,
+        };
+        if(is.feeRuleId){
+            let feeRule = projectObj.project.installation_fee.getFeeRuleByID(libID,is.feeRuleId);
+            if(feeRule){
+                tem_detail.code = feeRule.code;
+                tem_detail.base = feeRule.base;
+                tem_detail.feeRate = feeRule.feeRate;
+                tem_detail.labour = feeRule.labour;
+                tem_detail.material = feeRule.material;
+                tem_detail.machine = feeRule.machine;
+                tem_detail.position = me.getDisplayText(feeRule);
+                tem_detail.billID = feeRule.billID;
+                tem_detail.ruleName = feeRule.rule;
+            }
+        }
+        tem_detail.impactRules = projectObj.project.installation_fee.getFeeRuleBySection(tem_detail);
+        return tem_detail;
+    },
+    initSheet: function (sheet,setting) {
+        var me = this;
+        sheetCommonObj.initSheet(sheet, setting, 30);
+        sheet.bind(GC.Spread.Sheets.Events.ValueChanged, me.onSheetValueChange);
+    },
+    initPositionSpread:function () {
+        this.positionSpread = SheetDataHelper.createNewSpread($('#positionSpread')[0]);
+        this.selectionTree = idTree.createNew({id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: false});
+        this.selectionTreeController = TREE_SHEET_CONTROLLER.createNew(this.selectionTree, this.positionSpread.getActiveSheet(), this.positionSetting);
+        this.positionSheet = this.positionSpread.getActiveSheet();
+        this.positionSpread.bind(GC.Spread.Sheets.Events.ButtonClicked, this.onPositionCheckBoxClick);
+    },
+    initMoreFeeRuleSpread:function () {
+        this.moreFeeRuleSpread = SheetDataHelper.createNewSpread($("#moreFeeRuleSpread")[0]);
+        this.moreFeeRuleSheet = this.moreFeeRuleSpread.getSheet(0);
+        this.initSheet(this.moreFeeRuleSheet,this.moreFeeRuleSetting);
+        this.moreFeeRuleSheet.bind(GC.Spread.Sheets.Events.CellDoubleClick, this.onFeeRuleDoubleClick);
+        this.moreFeeRuleSheet.selectionUnit(1);//0 cell,1 row,2 col;
+        this.moreFeeRuleSheet.name('moreFeeRuleSheet');
+    },
+    onFeeRuleDoubleClick:function (e,info) {
+        if(info.row){
+            installationFeeObj.updateFeeRuleToSection(info.row);
+        }else {
+            return;
+        }
+        $('#more_feeRule').modal('hide');
+    },
+    onPositionCheckBoxClick:function (e,args) {
+        let me = installationFeeObj;
+        var checkboxValue = args.sheet.getCell(args.row, args.col).value();
+        var newval = 0;
+        if (checkboxValue) {
+            newval = 0;
+            args.sheet.getCell(args.row, args.col).value(newval);
+        } else {
+            newval = 1;
+            args.sheet.getCell(args.row, args.col).value(newval);
+        }
+        if(me.positionSelectedObject==null){//如果之前没选中任何一条记录,则记住选中位置
+            me.positionSelectedObject ={
+               row : args.row,
+               col: args.col,
+               recode:me.positionData[args.row]
+           }
+        }else {
+            if(args.row==me.positionSelectedObject.row){//如果是在已选中的记录中再点一次选中复框,则去掉选中记录
+                me.positionSelectedObject = null;
+            }else {//切换选中记录
+                //去掉之前选中位置的打勾
+                args.sheet.getCell(me.positionSelectedObject.row, me.positionSelectedObject.col).value(0);
+                me.positionSelectedObject ={
+                    row : args.row,
+                    col: args.col,
+                    recode:me.positionData[args.row]
+                }
+            }
+        }
+
+    },
+    loadSelectionNodes : function () {
+        this.positionData =this.getBillDataForSelect();
+        this.selectionTree.loadDatas(this.positionData);
+        this.selectionTreeController.showTreeData();
+    },
+    filterSelectionNodes:function () {
+        let keyword = $('#filterKeyword').val();
+        let resultData =[], newTreeIDs=[], newDatas = [];
+        let allPositionData = this.getBillDataForSelect();
+        if(keyword&&keyword!=""){//按关键字过滤出结果
+            resultData = _.filter(allPositionData,function (item) {
+                if(item.canSelect == true){
+                    if(item.code.indexOf(keyword)!=-1||item.name.indexOf(keyword)!=-1){
+                        return true;
+                    }
+                }
+            });
+        }
+        for(let tem of resultData){//取出所有父节点ID
+            let temNode = projectObj.project.mainTree.getNodeByID(tem.ID);
+            if(temNode){
+                getParentIDs(temNode,newTreeIDs);
+            }
+        }
+        if(newTreeIDs.length > 0){//生成过滤后的记录
+            for(let p_tem of allPositionData){
+                if(_.includes(newTreeIDs,p_tem.ID)){
+                    newDatas.push(p_tem);
+                }
+            }
+        }
+        this.positionData = newDatas;
+        this.selectionTree.loadDatas(this.positionData);
+        this.selectionTreeController.showTreeData();
+
+        function getParentIDs(temNode,idArrays) {
+            idArrays.push(temNode.data.ID);
+            if(temNode.parent!=null){
+                getParentIDs(temNode.parent,idArrays);
+            }
+        }
+    },
+    getBillDataForSelect:function () {
+        let controller = projectObj.mainController, project = projectObj.project;
+        let selection = this.feeItemSheet.getSelections()[0];
+        let from = $('#calc_position_from').val();
+        let feeItem = this.feeItemData[selection.row];
+        let rootNode = null;
+        let allNodes = [];
+        let datas = [];
+        let billID = null;
+        if(from =="feeItemSheet"){
+            if(feeItem.billID){
+                billID = feeItem.billID;
+            }
+        }
+        if(from =="feeDetailSheet") {
+            let detailSelection = this.feeDetailSheet.getSelections()[0];
+            let detail = this.feeDetailData[detailSelection.row];
+            if(detail.billID){
+                billID = detail.billID;
+            }
+        }
+
+        if(feeItem.feeType=='措施费用'){
+            rootNode = project.Bills.getMeasureNode(controller);
+        }else if(feeItem.feeType=='分项费用'){
+            rootNode = project.Bills.getFBFXNode(controller);
+        }
+        allNodes.push(rootNode);
+        controller.tree.getAllSubNode(rootNode.source,allNodes);
+        for(let n of allNodes){
+            let temData = {
+                ID:n.data.ID,
+                NextSiblingID:n.data.NextSiblingID,
+                ParentID:n.data.ParentID,
+                type : billText[n.data.type],
+                code : n.data.code,
+                name : n.data.name
+            };
+            //project.mainTree.selected.data.calcBase&&project.mainTree.selected.data.calcBase!=""
+            if(n.data.type == billType.FX){//分项才能选
+                temData.canSelect = true;
+            }else if(n.data.type == billType.BILL){//如果是清单类型,则是叶子节点并且没有使用基数计算的清单
+                if (n.children.length==0&&!(n.data.calcBase&&n.data.calcBase!="")){
+                    temData.canSelect = true;
+                }
+            }
+            if(billID&&n.data.ID == billID){
+                temData.selected = 1;
+                this.positionSelectedObject ={
+                    row : datas.length,
+                    col: 3,
+                    recode:temData
+                }
+            }
+            datas.push(temData);
+        }
+        return datas;
+    },
+    selectPositionConfirm:function () {
+        let pobj = this.positionSelectedObject;
+        let from = $('#calc_position_from').val();
+        if(pobj){
+            if(from=='feeItemSheet'){
+                this.updateFeeItemPosition(pobj.recode);
+            }else if(from=='feeDetailSheet'){
+                this.updateFeeRulePosition(pobj.recode);
+            }
+        }
+        $("#calc_position").modal('hide');
+    },
+    updateFeeRulePosition:function (recode) {
+        let me = this;
+        let itemSelection  = this.feeItemSheet.getSelections()[0];
+        let feeItem = this.feeItemData[itemSelection.row];
+        let detailSelection = this.feeDetailSheet.getSelections()[0];
+        let detail = this.feeDetailData[detailSelection.row];
+        let itemUpdateData = null;
+        let updateData = null;
+        if(detail.billID ==recode.ID ){//和原来的位置没变
+            return;
+        }
+        let detailUpdateData = me.getDetailUpdateData(detail,{position:recode.code,billID:recode.ID},'feeRule');
+        if(recode.ID!=feeItem.billID){//不一样的情况下要清空费用项的选取位置
+            itemUpdateData = me.getFeeItemUpdateData(feeItem,{ position: "", billID:""});
+        }
+        itemUpdateData==null?updateData = detailUpdateData:updateData=[detailUpdateData,itemUpdateData];
+        $.bootstrapLoading.start();
+        me.submitInstallationUpdate(updateData,function (data) {
+            //更新缓存
+            if(itemUpdateData){
+                feeItem.position ="";
+                feeItem.billID = "";
+                feeItem.displayPosition = "";
+                me.feeItemSheet.getCell(itemSelection.row, 3).value(feeItem.displayPosition);
+            }
+            let feeRule = projectObj.project.installation_fee.getFeeRuleByID(feeItem.libID,detail.feeRuleId);
+            feeRule.position = recode.code;
+            feeRule.billID = recode.ID;
+            me.showFeeDetailData(feeItem.libID,feeItem.ID);
+            $.bootstrapLoading.end();
+        });
+    },
+    updateFeeRuleToSection:function (row) {
+        let me = this;
+        let feeRule = me.moreFeeRuleData[row];
+        let detailSelection = me.feeDetailSheet.getSelections()[0];
+        let detail = this.feeDetailData[detailSelection.row];
+        let updateData = me.getDetailUpdateData(detail,{"feeRuleId":feeRule.ID},'installSection');
+        $.bootstrapLoading.start();
+        me.submitInstallationUpdate(updateData,function (data) {
+            let install_fee = projectObj.project.installation_fee;
+            let section = install_fee.getInstallSectionByID(detail.libID,detail.ID);
+            section.feeRuleId = feeRule.ID;
+            me.refreshFeeDetailRow(detailSelection.row);
+            $.bootstrapLoading.end();
+        });
+    },
+    updateFeeItemPosition:function(recode){
+        let me = this;
+        let selection = this.feeItemSheet.getSelections()[0];
+        let feeItem = this.feeItemData[selection.row];
+        if(feeItem.billID ==recode.ID ){//和原来的位置没变
+            return;
+        }
+        let updateData = me.getFeeItemUpdateData(feeItem,{ position: recode.code, billID:recode.ID});
+        let [dataArray,impacRules] = me.getFeeRuleUpdateData(feeItem,recode);
+        dataArray.push(updateData);
+        $.bootstrapLoading.start();
+        me.submitInstallationUpdate(dataArray,function (data) {
+            //更新缓存
+            feeItem.position =recode.code;
+            feeItem.billID = recode.ID;
+            feeItem.displayPosition = recode.code + ' '+recode.name;
+            me.feeItemSheet.getCell(selection.row, selection.col).value(feeItem.displayPosition);
+            for(let ir of impacRules){
+                ir.position = recode.code;
+                ir.billID  = recode.ID;
+            }
+            me.showFeeDetailData(feeItem.libID,feeItem.ID);
+            $.bootstrapLoading.end();
+        });
+    },
+    getFeeRuleUpdateData : function (feeItem,recode) {
+        let dataArray = [];
+        let impacRules = projectObj.project.installation_fee.getFeeRuleByFeeItem(feeItem);
+        for(let ir of impacRules){
+            let tem_data = {
+                ID:feeItem.installFeeID,
+                itemID:ir.ID,
+                type:'feeRule',
+                doc:{position: recode.code, billID:recode.ID}
+            };
+            dataArray.push(tem_data);
+        }
+        return [dataArray,impacRules]
+    },
+    onSheetValueChange:function (e,info) {
+        if(info.sheetName=='feeItemSheet'){
+            installationFeeObj.onFeeItemValueChange(e,info);
+        }
+        if(info.sheetName == 'feeDetailSheet'){
+            installationFeeObj.onFeeDetailValueChange(e,info);
+        }
+    },
+    onFeeItemValueChange:function (e,info) {
+        let me = installationFeeObj;
+        let feeItem = this.feeItemData[info.row];
+        let header = this.feeItemSetting.header[info.col];
+        let doc={};
+        doc[header.dataCode] = info.newValue;
+        let updateData = installationFeeObj.getFeeItemUpdateData(feeItem,doc);
+        $.bootstrapLoading.start();
+        me.submitInstallationUpdate(updateData,function (data) {
+            //更新缓存
+            feeItem[header.dataCode]=info.newValue;
+            me.feeItemSheet.getCell(info.row, info.col).value(info.newValue);
+            $.bootstrapLoading.end();
+        });
+    },
+    onFeeDetailValueChange:function (e,info) {
+        if(info.newValue==info.oldValue){
+            return;
+        }
+        let me = installationFeeObj;
+        let feeDetail = this.feeDetailData[info.row];
+        let header = this.feeDetailSetting.header[info.col];
+        let fieldID = header.dataCode;
+        let updateData = null;
+        if(fieldID == 'rule'){//选择新的规则项
+            if(info.newValue=="more"){//选择的是更多
+                $("#more_feeRule").modal({show:true});
+                return;
+            }
+            updateData = me.getDetailUpdateData(feeDetail,{"feeRuleId":info.newValue},'installSection');
+        }else if(fieldID == 'base'){
+            if(info.newValue == null){//如果基数为空,重新刷新显示
+                me.refreshFeeDetailRow(info.row);
+            }else {
+                let doc ={base:info.newValue};
+                if(installSectionBase.indexOf(info.newValue)===0){//如果选择的是“人材机乘系数”时,清空“费率(%)”列的值
+                    doc.feeRate = null;
+                }
+                updateData = me.getDetailUpdateData(feeDetail,doc,'feeRule');
+            }
+
+        }else {
+            if(info.newValue != null){
+                if(number_util.isNumber(info.newValue)){
+                    info.newValue = scMathUtil.roundForObj(info.newValue,getDecimal("feeRate"));
+                }else {
+                    alert('当前输入的数据类型不正确,请重新输入。');
+                    me.showFeeDetailData(feeDetail.libID,feeDetail.feeItemId);
+                    me.detailReloadSelection={row:info.row,col:info.col};
+                    return;
+                }
+            }
+            let doc = {};
+            doc[fieldID] = info.newValue;
+            feeDetail[fieldID] = info.newValue;
+            updateData = me.getDetailUpdateData(feeDetail,doc,'feeRule');
+        }
+        me.submitInstallationUpdate(updateData,function (data) {
+            let install_fee = projectObj.project.installation_fee;
+            if(updateData){
+                if(updateData.type=="installSection"){
+                    let section = install_fee.getInstallSectionByID(feeDetail.libID,feeDetail.ID);
+                    section.feeRuleId = info.newValue;
+                }
+                if(updateData.type=="feeRule"){
+                    let feeRule = install_fee.getFeeRuleByID(feeDetail.libID,feeDetail.feeRuleId);
+                    let updateDoc = updateData.doc;
+                    for(let key in updateDoc){
+                        feeRule[key] = updateDoc[key];
+                    }
+                }
+              me.refreshFeeDetailRow(info.row);
+            }
+            //me.showFeeDetailData(feeDetail.libID,feeDetail.feeItemId);
+        });
+    },
+    onDetailRangeChanged:function (e,info) {
+        let me = installationFeeObj;
+        if (info.action == GC.Spread.Sheets.RangeChangedAction.clear) {
+            let header = me.feeDetailSetting.header[info.col];
+            info.oldValue = me.feeDetailData[info.row][header.dataCode];
+            info.newValue = null;
+           me.onFeeDetailValueChange(e,info);
+        }
+    },
+    detailResultCheck:function (info) {
+        let me = installationFeeObj;
+        let canChange = true;
+        let os = null;
+        if(info.newSelections[0].row == info.oldSelections[0].row){//没有换行
+            return canChange;
+        }
+        if(info.sheetName=='feeDetailSheet'){
+            os = info.oldSelections[0];
+        }
+        if(info.sheetName=='feeItemSheet'){
+            os = me.feeDetailSheet.getSelections()[0];
+        }
+        if(this.feeDetailData&&this.feeDetailData.length>0&&this.feeDetailData[os.row]){
+            let detail = this.feeDetailData[os.row];
+            if(detail.base&&installSectionBase.indexOf(detail.base)>0){
+                let sum = detail.labour+detail.material+detail.machine;//三项的和要等于100
+                if(sum!=100){
+                    setTimeout(function () {//这里须用延时执行的办法,不然的弹窗确认窗口会和spreadjs 的事件有冲突,造成定额工料机数据不会根据树结点更新的问题
+                        alert("人工、材料、机械的和应等于100,请重新输入。");
+                    }, 200);
+                    canChange = false;
+                }
+            }
+        }
+        return canChange;
+    },
+    getDetailUpdateData : function (detail,doc,type) {//type:installSection/feeRule
+        let installationFee = projectObj.project.installation_fee.getInstallationFeeByLibID(detail.libID);
+        let updateData = {
+            ID:installationFee.ID,
+            itemID:type=="installSection"?detail.ID:detail.feeRuleId,
+            type:type,
+            doc:doc
+        };
+        return updateData;
+    },
+    getFeeItemUpdateData : function (item,doc) {
+        let updateData = {
+            ID:item.installFeeID,
+            itemID:item.ID,
+            type:'installFeeItem',
+            doc:doc
+        };
+        return updateData;
+    },
+    submitInstallationUpdate:function (updateData,callback) {
+        if(updateData){
+            CommonAjax.post('/installation/updateInstallationFee',{'projectID':projectInfoObj.projectInfo.ID,'updateData':updateData},function (data) {
+                callback(data);
+            })
+        }
     }
 };
 
+
 $(function () {
     $('#calc_installation_fee').on('shown.bs.modal',function () {
-        if(installationFeeObj.installationFeeSpread == null){//初始化显示
-
+        if(installationFeeObj.feeItemSpread == null){//初始化显示
+            installationFeeObj.initInstallationFeeSpread();
+        }else {
+            installationFeeObj.showFeeItemData();
+            installationFeeObj.showFeeDetailData();
+        }
+    });
+    $('#calc_position').on('shown.bs.modal',function () {
+        installationFeeObj.positionSelectedObject = null;
+        if (!installationFeeObj.positionSpread) {
+            installationFeeObj.initPositionSpread();
+        }
+        installationFeeObj.loadSelectionNodes();
+    });
+    $('#more_feeRule').on('shown.bs.modal',function () {
+        if(installationFeeObj.moreFeeRuleSpread == null){//初始化显示
+            installationFeeObj.initMoreFeeRuleSpread();
         }
+        installationFeeObj.showMoreFeeRule();
+    });
 
-    })
+   /* $('#calc_position').on('hidden.bs.modal',function () {
 
+    });*/
+    $('#positionSheetFilter').click(function (){
+        installationFeeObj.positionSelectedObject = null;//清空选中记录
+        installationFeeObj.filterSelectionNodes();
+    });
 
+    $('#cancelFilter').click(function (){
+        installationFeeObj.positionSelectedObject = null;//清空选中记录
+        installationFeeObj.loadSelectionNodes();
+    });
+    $('#select_position_confirm').click(function (){
+        installationFeeObj.selectPositionConfirm();
+    });
+    $('#calc_installation_fee_confirm').click(function (){
+        let me = installationFeeObj;
+        let info = {
+            sheetName:'feeDetailSheet',
+            newSelections:[{row:-1}],
+            oldSelections: me.feeDetailSheet.getSelections()
+        };
+        let canChange = me.detailResultCheck(info);
+        if(canChange==false){
+            return;
+        }
+        let val = $('input[name="install_setting_radios"]:checked').val();
+        console.log(val);
+
+    });
+    $('#calc_installation_fee_close').click(function (){
+        let me = installationFeeObj;
+        let info = {
+            sheetName:'feeDetailSheet',
+            newSelections:[{row:-1}],
+            oldSelections: me.feeDetailSheet.getSelections()
+        }
+        let canChange = me.detailResultCheck(info);
+        if(canChange==false){
+            return;
+        }
+        $('#calc_installation_fee').modal('hide');
+    });
+
+    $('#more_feeRule_confirm').click(function (){
+        let me = installationFeeObj;
+        let selections = me.moreFeeRuleSheet.getSelections();
+        $('#more_feeRule').modal('hide');
+        if(selections.length>0){
+            me.updateFeeRuleToSection(selections[0].row);
+        }else {
+            me.refreshFeeDetailRow(me.feeDetailSheet.getSelections()[0].row);
+        }
+    });
+    $('#more_feeRule_concel').click(function () {
+        let me = installationFeeObj;
+        me.refreshFeeDetailRow(me.feeDetailSheet.getSelections()[0].row);
+    });
+    $('#more_feeRule_close').click(function () {
+        let me = installationFeeObj;
+        me.refreshFeeDetailRow(me.feeDetailSheet.getSelections()[0].row);
+    });
 
 });

+ 1 - 2
web/building_saas/main/js/views/main_tree_col.js

@@ -205,7 +205,7 @@ let MainTreeCol = {
         },
 
         calcBase: function () {
-            return calcBaseView.getCalcBaseCellType();
+            return calcBaseView.getCalcBaseCellType('bills');
         },
 
         // CSL, 2017-11-28
@@ -243,7 +243,6 @@ let MainTreeCol = {
                 }
             }
         },
-
         isSubcontract: function (node){
             if (calcTools.isRationCategory(node))
                 return new GC.Spread.Sheets.CellTypes.CheckBox();

+ 20 - 9
web/building_saas/main/js/views/project_view.js

@@ -12,6 +12,11 @@ var projectObj = {
             subViewObj.saveComments(node);
         }*/
     },
+    // CSL, 2018-02-09 用于测试显示。使用示例:projectObj.testDisplay(‘总额’, 100);
+    testDisplay: function (caption, value) {
+        let s = `&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[ ${caption}: ${value} ]`;
+        $('#testDisplay').html(s);
+    },
     treeSelectedChanged: function (node) {
         let project = projectObj.project;
         subViewObj.loadComments(node);
@@ -31,19 +36,20 @@ var projectObj = {
         }
 
         // for test interface.  CSLAAAAA
-/*        node.data.gljList = project.ration_glj.getGljArrByRation(node.data.ID);
-        node.data.isSubcontract = true;
-        let bname = '分包人工工日';
-        alert(bname + ': ' + rationCalcBases[bname](node));*/
+        // projectObj.testDisplay('前四项累计值排除当前选中项' + projectObj.project.calcProgram.getBeforeTaxTotalFee([node]));
 
-/*        let value = projectObj.project.calcProgram.getBeforeTaxTotalFee([node]);
-        alert('前四项累计值排除当前选中项:' + value);*/
+        // 基数
+/*        node.data.isSubcontract = true;
+        node.data.gljList = project.ration_glj.getGljArrByRation(node.data.ID);
+        let bname = '甲供定额基价材料费';
+        projectObj.testDisplay(bname, rationCalcBases[bname](node));*/
 
+        // 公式结果
 /*        let t = projectObj.project.calcProgram.compiledTemplates[node.data.programID];
         let c = t.calcItems[7];
         c.dispExpr = '[定额基价人工费] + [定额基价材料费]  + F6 + [主材费]';
         let rst = analyzer.analyzeUserExpr(t, c);
-        alert(`${rst}: ` + JSON.stringify(c));*/
+        projectObj.testDisplay('结果', rst);*/
     },
     refreshBaseActn: function (tree) {
         let setButtonValid = function (valid, btn) {
@@ -247,6 +253,9 @@ var projectObj = {
 
     },
     updateRationCode: function (node, value) {
+        if(!isDef(node.data.code) && (!isDef(value) || value.toString().trim() == '')){
+            return;
+        }
         if (projectInfoObj.projectInfo.engineeringInfo.ration_lib.length === 0) {
             alert('当前项目无定额库,请添加定额库。');
             this.mainController.refreshTreeNode([node], false);
@@ -317,7 +326,7 @@ var projectObj = {
                     }
                     // if (value) {value = parseFloat(value).toDecimal(decimalObj.decimal("totalPrice", node))};
                 };
-
+                //计算基数赋值要经过解析和标准化,已在calculate里赋值
                 if(fieldName !== 'calcBase'){
                     node.data[fieldName] = value;
                     node.changed = true;
@@ -359,9 +368,11 @@ var projectObj = {
         let colSetting = projectObj.mainController.setting.cols[info.col];
         projectObj.lastCol = colSetting;
     },
+    //repaint 动态下拉框
     mainSpreadEnterCell: function (sender, info) {
         let colSetting = projectObj.mainController.setting.cols[info.col];
-        if(colSetting.data.field === 'unit' || projectObj.lastCol.data.field === 'unit'||colSetting.data.field ==='subType'|| projectObj.lastCol.data.field === 'subType'){
+        if(colSetting.data.field === 'unit' || projectObj.lastCol.data.field === 'unit'||colSetting.data.field ==='subType'
+            || projectObj.lastCol.data.field === 'subType' || colSetting.data.field === 'programID' ||projectObj.lastCol.data.field === 'programID'){
             info.sheet.repaint();
         }
     },

+ 4 - 2
web/building_saas/pm/html/project-management.html

@@ -122,7 +122,6 @@
                 <table class="table table-bordered table-hover table-sm" id="summary-project-table">
                     <thead>
                     <tr>
-                        <th rowspan="2"></th>
                         <th rowspan="2" style="text-align:center;vertical-align:middle;">序号</th>
                         <th rowspan="2" style="text-align:center;vertical-align:middle;">单位工程名称</th>
                         <th rowspan="2" style="text-align:center;vertical-align:middle;">金额(元)</th>
@@ -167,7 +166,6 @@
                 <table class="table table-bordered table-hover table-sm" id="summary-engineering-table">
                     <thead>
                     <tr>
-                        <th rowspan="2"></th>
                         <th rowspan="2" style="text-align:center;vertical-align:middle">序号</th>
                         <th rowspan="2" style="text-align:center;vertical-align:middle">单位工程名称</th>
                         <th rowspan="2" style="text-align:center;vertical-align:middle">金额(元)</th>
@@ -240,6 +238,7 @@
                     <div class="form-group">
                         <label>建设项目</label>
                         <input type="text" class="form-control" placeholder="输入建设项目名称" id="project-name">
+                        <span class="form-text text-danger" id="project-name-info" style="display: none;">已存在 “建筑工程1”</span>
                     </div>
                 </form>
             </div>
@@ -266,6 +265,7 @@
                     <div class="form-group">
                         <label>单项工程</label>
                         <input type="text" class="form-control" placeholder="输入单项工程名称" id="engineering-name">
+                        <span class="form-text text-danger" id="engineering-name-info" style="display: none;">已存在 “建筑工程1”</span>
                     </div>
                 </form>
             </div>
@@ -376,6 +376,7 @@
                     <div class="form-group">
                         <label>文件夹</label>
                         <input type="text" class="form-control" placeholder="输入文件夹名称" id="folder-name">
+                        <span class="form-text text-danger" id="folder-name-info" style="display: none;">已存在 “建筑工程1”</span>
                         <span class="form-text text-muted">Smartcost目前最多支持3层文件夹。</span>
                     </div>
                 </form>
@@ -401,6 +402,7 @@
                 <form>
                     <div class="form-group">
                         <input type="text" class="form-control" placeholder="输入名称" id="rename-name">
+                        <span class="form-text text-danger" id="rename-name-info" style="display: none;">已存在 “建筑工程1”</span>
                     </div>
                 </form>
             </div>

+ 3 - 0
web/building_saas/pm/js/pm_gc.js

@@ -162,6 +162,9 @@ let gcTreeSetting = {
 
 $(document).ready(function () {
     $('#tab_pm_gc').on('show.bs.tab', function () {
+        //侧滑隐藏
+        $('.slide-sidebar').removeClass('open');
+        $('.slide-sidebar').css('width', '0');
         $('#gc_waiting').show();
         gc_init();
         Tree = null;

+ 143 - 37
web/building_saas/pm/js/pm_main.js

@@ -232,6 +232,11 @@ $(document).ready(function() {
             });
         }
     });
+    //绑定新建建设项目、新建单项工程、新建文件夹、重命名Enter键事件
+    bindInputs($('#project-name'), $('#engineering-name'), $('#folder-name'), $('#rename-name'));
+
+    //绑定新建建设项目、新建单项工程、新建文件夹、重命名弹窗隐藏事件
+    bindModalsHidden($('#add-project-dialog'), $('#add-engineering-dialog'), $('#add-folder-dialog'), $('#rename-dialog'));
 
     // 新增建设项目点击
     $('#add-project-btn').click(function () {
@@ -456,7 +461,8 @@ $(document).ready(function() {
         let newName = $('#rename-name').val();
         let dialog = $('#rename-dialog');
         if (newName === '') {
-            alert('请输入重命名的名称');
+            $('#rename-name-info').text('请输入重命名名称');
+            $('#rename-name-info').show();
             return false;
         }
 
@@ -465,6 +471,8 @@ $(document).ready(function() {
             return false;
         }
         RenameProject(select.id(), newName, select.data.ParentID, function () {
+            $('#rename-name-info').text('');
+            $('#rename-name-info').hide();
             dialog.modal('hide');
             select.data.name = newName;
             Tree.refreshNodesDom([select]);
@@ -681,12 +689,19 @@ function init() {
 function AddProject() {
     let name = $('#project-name').val().trim();
     if (name === '') {
-        alert('请填写建设项目名称');
+        $('#project-name-info').text('请填写建设项目名称');
+        $('#project-name-info').show();
         return false;
     }
-    let callback = function() {
-        $("#add-project-dialog").modal("hide");
-        $("#project-name").val('');
+    let existCallback = function () {
+        $('#project-name-info').text(`已存在“${$("#project-name").val()}”`);
+        $('#project-name-info').show();
+    };
+    let sucCallback = function () {
+        $('#add-project-dialog').modal('hide');
+        $('#project-name').val('');
+        $('#project-name-info').text('');
+        $('#project-name-info').hide();
     };
     let selectedItem = Tree.selected();
 
@@ -697,18 +712,93 @@ function AddProject() {
      (4)、当前定位在单项工程或单位工程,新建项目为当前所属建设项目的后兄弟。
     * */
     if(!selectedItem){
-        AddSiblingsItem(selectedItem, name, null, projectType.project, callback);
+        AddSiblingsItem(selectedItem, name, null, projectType.project, existCallback, sucCallback);
     }
     else {
         if(selectedItem.data.projType === projectType.project){
-            AddSiblingsItem(selectedItem, name, null, projectType.project, callback);
+            AddSiblingsItem(selectedItem, name, null, projectType.project, existCallback, sucCallback);
         }
         else if(selectedItem.data.projType === projectType.engineering || selectedItem.data.projType === projectType.tender){
             let proj = selectedItem.parent.data.projType === projectType.project ? selectedItem.parent : selectedItem.parent.parent;
-            AddSiblingsItem(proj, name, null, projectType.project, callback);
+            AddSiblingsItem(proj, name, null, projectType.project, existCallback, sucCallback);
         }
         else if(selectedItem.data.projType === projectType.folder){
-            AddChildrenItem(selectedItem, name, null, projectType.project, callback);
+            AddChildrenItem(selectedItem, name, null, projectType.project, existCallback, sucCallback);
+        }
+    }
+}
+
+//新建建设项目、新建单项工程、新建文件夹、重命名弹窗隐藏事件
+function bindModalsHidden(projDialog, engDialog, folderDialog, renameDialog){
+    projDialog.on('hidden.bs.modal', function () {
+        $('#project-name-info').text('');
+        $('#project-name-info').hide();
+        $('#project-name').val('');
+    });
+    engDialog.on('hidden.bs.modal', function () {
+        $('#engineering-name-info').text('');
+        $('#engineering-name-info').hide();
+        $('#engineering-name').val('');
+    });
+    folderDialog.on('hidden.bs.modal', function () {
+        $('#folder-name-info').text('');
+        $('#folder-name-info').hide();
+        $('#folder-name').val('');
+    });
+    renameDialog.on('hidden.bs.modal', function () {
+        $('#rename-name-info').text('');
+        $('#rename-name-info').hide();
+        $('#rename-name').val('');
+    });
+}
+
+//绑定新建建设项目、新建单项工程、新建文件夹、重命名回车键功能
+function bindInputs(projInput, engInput, foldInput, renameInput){
+    projInput.bind('keypress', function (event) {
+        if(event.keyCode === 13){
+            $('#addProjOk').click();
+            return false;
+        }
+    });
+    //projInput.bind('change', getChangedFunc(projInput, $('#project-name-info')));
+
+    engInput.bind('keypress', function (event) {
+        if(event.keyCode === 13){
+            $('#add-engineering-confirm').click();
+            return false;
+        }
+    });
+    //engInput.bind('change', getChangedFunc(engInput, $('#engineering-name-info')));
+
+    foldInput.bind('keypress', function (event) {
+        if(event.keyCode === 13){
+            $('#add-folder-confirm').click();
+            return false;
+        }
+    });
+   // foldInput.bind('change', getChangedFunc(foldInput, $('#folder-name-info')));
+
+    renameInput.bind('keypress', function (event) {
+        if(event.keyCode === 13){
+            $('#rename-confirm').click();
+            return false;
+        }
+    });
+    //renameInput.bind('change', getChangedFunc(renameInput, $('#rename-name-info')));
+}
+//新建建设项目、单项工程、文件夹、重命名提示(文本改变,暂时不需要)
+function getChangedFunc(input, nameInfo){
+    return function () {
+        let selected = Tree.selected();
+        let parent = selected ? selected.parent : Tree._root;
+        let name = input.val();
+        if(existName(name, parent.children)){
+            nameInfo.text(`已存在“${name}”`);
+            nameInfo.show();
+        }
+        else {
+            nameInfo.text('');
+            nameInfo.hide();
         }
     }
 }
@@ -846,15 +936,15 @@ function AddTenderItems(selected, projName, engName, tenderName, property, callb
  * @param {function} callback
  * @return {void}
  */
-function AddChildrenItem(selected, name, property, type, callback) {
+function AddChildrenItem(selected, name, property, type, existCallback, sucCallback) {
     if(!selected){
         selected = Tree.selected();
     }
     let parent = selected ? selected : Tree._root;
     let pre = selected ? selected.lastChild() : Tree.firstNode();
     if(existName(name, parent.children)){
-        alert('同级目录已存在相同名称数据.');
-        callback();
+        //alert('同级目录已存在相同名称数据.');
+        existCallback();
     }
     else {
         GetNewProjectId(1, function(IDs) {
@@ -870,7 +960,7 @@ function AddChildrenItem(selected, name, property, type, callback) {
                         Tree.addNodeData(data.updateData, parent, null);
                     }
                 });
-                callback();
+                sucCallback();
             });
         });
     }
@@ -884,15 +974,15 @@ function AddChildrenItem(selected, name, property, type, callback) {
  * @param {function} callback
  * @return {void}
  */
-function AddSiblingsItem(selected, name, property, type, callback) {
+function AddSiblingsItem(selected, name, property, type, existCallback, sucCallback) {
     if(!selected){
         selected = Tree.selected();
     }
     let parent = selected ? selected.parent : Tree._root;
     let next = selected ? selected.nextSibling : Tree.firstNode();
     if(existName(name, parent.children)){
-        alert('同级目录已存在相同名称数据.');
-        callback();
+        //alert('同级目录已存在相同名称数据.');
+        existCallback();
     }
     else {
         GetNewProjectId(1, function(IDs) {
@@ -908,7 +998,7 @@ function AddSiblingsItem(selected, name, property, type, callback) {
                         Tree.addNodeData(data.updateData, parent, next);
                     }
                 });
-                callback();
+                sucCallback();
             });
         });
     }
@@ -1120,25 +1210,32 @@ function hasTender(selected, pojName, engName, tenderName){
 function AddEngineering() {
     let name = $('#engineering-name').val().trim();
     if (name === '') {
-        alert('请填写单项工程名称');
+        $('#engineering-name-info').text('请填写单项工程名称');
+        $('#engineering-name-info').show();
         return false;
     }
-    let callback = function() {
-        $("#add-engineering-dialog").modal("hide");
-        $("#engineering-name").val('');
+    let existCallback = function () {
+        $('#engineering-name-info').text(`已存在“${$("#engineering-name").val()}”`);
+        $('#engineering-name-info').show();
+    };
+    let sucCallback = function () {
+        $('#add-engineering-dialog').modal('hide');
+        $('#engineering-name').val('');
+        $('#engineering-name-info').text('');
+        $('#engineering-name-info').hide();
     };
     let selectedItem = Tree.selected();
     // 如果选择的是单项工程则新增同级数据
     if(selectedItem){
         if(selectedItem.data.projType === projectType.project){
-            AddChildrenItem(selectedItem, name, null, projectType.engineering, callback);
+            AddChildrenItem(selectedItem, name, null, projectType.engineering, existCallback, sucCallback);
         }
         else if(selectedItem.data.projType === projectType.engineering){
-            AddSiblingsItem(selectedItem, name, null, projectType.engineering, callback);
+            AddSiblingsItem(selectedItem, name, null, projectType.engineering, existCallback, sucCallback);
         }
         else if(selectedItem.data.projType === projectType.tender){
             let proj = selectedItem.parent;
-            AddSiblingsItem(proj, name, null, projectType.engineering, callback);
+            AddSiblingsItem(proj, name, null, projectType.engineering, existCallback, sucCallback);
         }
     }
 }
@@ -1250,14 +1347,21 @@ function AddTender() {
 function AddFolder() {
     let name = $('#folder-name').val().trim();
     if (name === '') {
-        alert('请填写文件夹名称');
+        $('#folder-name-info').text('请填写文件夹名称');
+        $('#folder-name-info').show();
         return false;
     }
 
     let selectedItem = Tree.selected();
-    let callback = function() {
-        $("#add-folder-dialog").modal("hide");
-        $("#folder-name").val('');
+    let existCallback = function () {
+        $('#folder-name-info').text(`已存在“${$("#folder-name").val()}”`);
+        $('#folder-name-info').show();
+    };
+    let sucCallback = function () {
+        $('#add-folder-dialog').modal('hide');
+        $('#folder-name').val('');
+        $('#folder-name-info').text('');
+        $('#folder-name-info').hide();
     };
     if (selectedItem !== null) {
         // 判断是否超过3层
@@ -1266,14 +1370,14 @@ function AddFolder() {
             return false;
         }
         if(selectedItem.data.projType === projectType.folder || selectedItem.data.projType === projectType.project){
-            AddSiblingsItem(null, name, null, projectType.folder, callback);
+            AddSiblingsItem(null, name, null, projectType.folder, existCallback, sucCallback);
         }
         else if(selectedItem.data.projType === projectType.engineering || selectedItem.data.projType === projectType.tender){
             let proj = selectedItem.parent.data.projType === projectType.project ? selectedItem.parent : selectedItem.parent.parent;
-            AddSiblingsItem(proj, name, null, projectType.folder, callback);
+            AddSiblingsItem(proj, name, null, projectType.folder, existCallback, sucCallback);
         }
     } else {
-        AddSiblingsItem(null, name, null, projectType.folder, callback);
+        AddSiblingsItem(null, name, null, projectType.folder, existCallback, sucCallback);
     }
 }
 
@@ -1453,7 +1557,10 @@ function RenameProject(projectId, newName, parentID, callback) {
             if (result.error === 0) {
                 callback();
             } else {
-                alert('error' + result.message);
+                if(result.message === '同级目录已存在相同名称数据'){
+                    $('#rename-name-info').text(`已存在“${newName}”`);
+                    $('#rename-name-info').show();
+                }
             }
         },
         error: function(iqXHR, textStatus, errorThrown){
@@ -1654,6 +1761,7 @@ function setDataToSideBar() {
     /*if (selectedItem.children.length <= 0) {
         return;
     }*/
+    $(target + '-table tbody').empty();
     if(selectedItem.children.length > 0){
         // CSL, 2018-01-11 汇总单项工程、建设项目。
         function calcNode(node){
@@ -1679,15 +1787,14 @@ function setDataToSideBar() {
         };
 
         // 建设项目相关
-        let counter = 1;
+        let counter = 0;
         let html = '';
 
         calcNode(selectedItem);
         for(let tmp of selectedItem.children) {
-
+            counter ++;
             html += '<tr>' +
                 '<td>'+ counter +'</td>' +
-                '<td>'+ counter +'</td>' +
                 '<td>'+ tmp.data.name +'</td>' +
                 '<td style="text-align:right">'+ tmp.data.summaryFees.totalFee + '</td>' +
                 '<td style="text-align:right">'+ tmp.data.summaryFees.estimateFee + '</td>' +
@@ -1699,7 +1806,6 @@ function setDataToSideBar() {
 
         html += '<tr>' +
             '<td>'+ (counter + 1) +'</td>' +
-            '<td> </td>' +
             '<td>合计</td>' +
             '<td style="text-align:right">'+ selectedItem.data.summaryFees.totalFee + '</td>' +
             '<td style="text-align:right">'+ selectedItem.data.summaryFees.estimateFee + '</td>' +
@@ -1896,7 +2002,7 @@ function set_file_table(target, poj_tenders, fileList, type){
             + '</span>'
             + '</div></td>';
         let fileTypeStr = type === fileType.unitPriceFile ? '单价文件' : '费率文件';
-        let fileHtml = '<tr><td>' + fileCounter + '</td><td id="file_' + fileId + '"><div>' + fileList[i].name + fileTypeStr + hoverHtml + renHtml + usedHtml + '</tr>';
+        let fileHtml = '<tr><td>' + fileCounter + '</td><td id="file_' + fileId + '"><div>' + fileList[i].name + hoverHtml + renHtml + usedHtml + '</tr>';
         fileCounter++;
         let targetBody = type === fileType.unitPriceFile ? target + '-unit-price-table tbody' : target + '-fee-table tbody';
         $(targetBody).append(fileHtml);

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

@@ -33,6 +33,7 @@
         <!--<span class="text-truncate"><a href="/pm">项目管理</a></span>-->
         <% } %>
     </div>
+    <div id="testDisplay" style="color:#ff7e0e;">&nbsp;&nbsp;</div>
     <div class="ml-auto navbar-text p-0">
         <div class="dropdown d-inline-block navbar-nav">
             <button class="btn btn-link btn-sm dropdown-toggle" type="button" data-toggle="dropdown"><%= sessionUser.real_name === '' ? sessionUser.email : sessionUser.real_name %></button>