Jelajahi Sumber

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

TonyKang 7 tahun lalu
induk
melakukan
3249886130

+ 1 - 1
modules/main/routes/main_route.js

@@ -19,7 +19,7 @@ module.exports =function (app) {
                     {
                         userAccount: req.session.userAccount,
                         userID: req.session.sessionUser.id,
-                        projectData: projectData,
+                        projectData: projectData
                     });
             } else {
                 res.redirect('/pm');

+ 34 - 0
modules/pm/controllers/pm_controller.js

@@ -13,6 +13,8 @@ let fee_rate_facade = require("../../fee_rates/facade/fee_rates_facade");
 let billsModel = require('../../main/models/bills').model;
 let rationsModel = require('../../main/models/ration').model;
 let projectModel = mongoose.model('projects');
+let unitPriceFileModel = mongoose.model('unit_price_file');
+let feeRateFileModel = mongoose.model('fee_rate_file');
 let asyncTool = require('async');
 
 //统一回调函数
@@ -353,5 +355,37 @@ module.exports = {
         ProjectsData.recGC(userID, nodes, function (err, msg, data) {
             callback(request, response, err, msg, data);
         });
+    },
+
+    delGC: async function(request, response){
+        let data = JSON.parse(request.body.data);
+        let delDatas = data.delDatas;
+        let bulkProjs = [], bulkUFs = [], bulkFFs = [];
+        try{
+            for(let data of delDatas){
+                if(data.updateType === 'Project'){
+                    bulkProjs.push({deleteOne: {filter: {ID: data.ID}}});
+                }
+                else if(data.updateType === fileType.unitPriceFile){
+                    bulkUFs.push({deleteOne: {filter: {id: data.ID}}});
+                }
+                else{
+                    bulkFFs.push({deleteOne: {filter: {ID: data.ID}}});
+                }
+            }
+            if(bulkProjs.length > 0){
+                await projectModel.bulkWrite(bulkProjs);
+            }
+            if(bulkUFs.length > 0){
+                await unitPriceFileModel.bulkWrite(bulkUFs);
+            }
+            if(bulkFFs.length > 0){
+                await feeRateFileModel.bulkWrite(bulkFFs);
+            }
+            callback(request, response, 0, 'success', null);
+        }
+        catch(err){
+            callback(request, response, 1, err, null);
+        }
     }
 };

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

@@ -145,7 +145,8 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
                     if(parseInt(data.updateData.property.engineering)==4){
                         await installationFacade.copyInstallationFeeFromLib(data.updateData.ID,data.updateData.property.engineering_id);
                     }
-
+                    //锁定清单
+                    data.updateData.property.lockBills = false;
 
                 }
                 newProject = new Projects(data.updateData);

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

@@ -48,6 +48,7 @@ module.exports = function (app) {
     //GC
     pmRouter.post('/getGCDatas', pmController.getGCDatas);
     pmRouter.post('/recGC', pmController.recGC);
+    pmRouter.post('/delGC', pmController.delGC);
 
     app.use('/pm/api', pmRouter);
 };

+ 1 - 0
public/web/tree_sheet/tree_sheet_controller.js

@@ -16,6 +16,7 @@ var TREE_SHEET_CONTROLLER = {
         };
 
         controller.prototype.showTreeData = function () {
+            //
             var that = this;
             TREE_SHEET_HELPER.showTreeData(this.setting, this.sheet, this.tree);
             this.sheet.unbind(GC.Spread.Sheets.Events.SelectionChanged);

+ 6 - 3
public/web/tree_sheet/tree_sheet_helper.js

@@ -105,7 +105,7 @@ var TREE_SHEET_HELPER = {
         nodes.forEach(function (node) {
             let iRow = node.serialNo();
             if(typeof projectObj !== 'undefined'){
-                let nodeStyle = projectObj.getNodeColorStyle(node);
+                let nodeStyle = projectObj.getNodeColorStyle(sheet, node);
                 if(nodeStyle){
                     sheet.setStyle(iRow, -1, nodeStyle);
                 }
@@ -118,6 +118,7 @@ var TREE_SHEET_HELPER = {
                         sheet.setStyle(iRow, iCol, boldFontStyle);
                     }
                 }
+
                 // var getFieldText = function () {
                 //     var fields = colSetting.data.field.split('.');
                 //     var validField = fields.reduce(function (field1, field2) {
@@ -159,7 +160,7 @@ var TREE_SHEET_HELPER = {
                 if(colSetting.data.autoHeight == true){
                     colSetting.setAutoHeight(cell,node);
                 }
-                if(sheet.name()=='mainSheet'&&gljOprObj.isInstallationNode(node)){//如果是通过安装增加费自动生成的,都是只读类型
+                if(colSetting.editChecking&&colSetting.editChecking(node)){
                     cell.locked(true);
                 }else if (colSetting.readOnly) {
                     if (Object.prototype.toString.apply(colSetting.readOnly) === "[object Function]") {
@@ -171,7 +172,9 @@ var TREE_SHEET_HELPER = {
                     cell.locked(false);
                 }
             });
-            sheet.autoFitRow(node.serialNo());
+            if(setting.setAutoFitRow){
+                setting.setAutoFitRow(sheet,node)
+            }
             if (recursive) {
                 TREE_SHEET_HELPER.refreshTreeNodeData(setting, sheet, node.children, recursive);
             }

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

@@ -367,9 +367,9 @@ div.resize{
     width: 100%;
     cursor: s-resize;
 }
-.zlfb-check{
-    margin-left: 0;
-}
+/*.zlfb-check{
+    margin-left: 20px;
+}*/
 legend.legend{
     display:block;
     width:auto;

+ 11 - 4
web/building_saas/main/html/main.html

@@ -21,6 +21,7 @@
     <!-- endinject -->
     <script>
         // 这里的变量供页面调用
+        let lockBills = '<%- projectData.property.lockBills %>';
         let userAccount = '<%- userAccount %>';
         let userID = '<%- userID %>';
     </script>
@@ -63,9 +64,9 @@
                     <a href="javascript:void(0)" class="btn btn-sm" id="downLevel" title="降级"><i class="fa fa-arrow-right" aria-hidden="true"></i></a>
                     <a href="javascript:void(0)" class="btn btn-sm" id="downMove" title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a>
                     <a href="javascript:void(0)" class="btn btn-sm" id="upMove" title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a>
-                      <span>
-                  <a href="" class="btn btn-sm" data-toggle="dropdown"><b data-toggle="tooltip" data-placement="bottom">显示至...</b></a>
-                  <div class="dropdown-menu dropdown-menu-left" style="min-width: 6.5rem">
+                    <span>
+                      <a href="" class="btn btn-sm" data-toggle="dropdown"><b data-toggle="tooltip" data-placement="bottom">显示至...</b></a>
+                      <div class="dropdown-menu dropdown-menu-left" style="min-width: 6.5rem">
                       <a class="dropdown-item" href="javascript:void(0);" style="padding: 0rem 1.5rem" id="displayDXFY">大项费用</a>
                       <a class="dropdown-item" href="javascript:void(0);" style="padding: 0rem 1.5rem" id="displayFB1">一级分部</a>
                       <a class="dropdown-item" href="javascript:void(0);" style="padding: 0rem 1.5rem" id="displayFB2">二级分部</a>
@@ -75,7 +76,13 @@
                       <a class="dropdown-item" href="javascript:void(0);" style="padding: 0rem 1.5rem" id="displayZM">子目</a>
                       <a class="dropdown-item" href="javascript:void(0);" style="padding: 0rem 1.5rem" id="displayZD">最底层</a>
                   </div>
-                </span>
+                    </span>
+                      <% if (projectData.property.lockBills == true) { %>
+                      <a href="javascript:void(0)" class="btn btn-sm" name="lockBills"  title="解锁清单"> <i class="fa fa-unlock-alt" aria-hidden="true"></i> 解锁清单</a>
+                      <% } else { %>
+                      <a href="javascript:void(0)" class="btn btn-sm" name="lockBills"  title="锁定清单"> <i class="fa fa-lock" aria-hidden="true"></i> 锁定清单</a>
+                      <% } %>
+
                   </div>
                   <div class="tools-btn">
                       <a href="javacript:void(0);" data-toggle="modal" data-target="#column" class="btn btn-sm"><i class="fa fa-table" aria-hidden="true"></i> 列设置</a>

+ 1 - 1
web/building_saas/main/js/controllers/project_controller.js

@@ -30,7 +30,7 @@ ProjectController = {
             });
             for(let newNode of newNodes){
                 sc.sheet.addRows(newNode.serialNo(), 1);
-                TREE_SHEET_HELPER.refreshTreeNodeData(sc.setting, sc.sheet, [newNode], false);
+               // TREE_SHEET_HELPER.refreshTreeNodeData(sc.setting, sc.sheet, [newNode], false);
                 sc.setTreeSelected(newNode);
                 sc.sheet.setSelection(newNode.serialNo(), sels[0].col, 1, 1);
                 sc.sheet.showRow(newNode.serialNo(), GC.Spread.Sheets.VerticalPosition.center);

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

@@ -42,7 +42,6 @@ $(function () {
             setLocalCache('lastCol:' + projectId, info.col);
         }
     });
-
 });
 
 /**

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

@@ -349,11 +349,14 @@ var Bills = {
             return node.downLevel();
         };
 
-        bills.prototype.updateField = function (node, field, newValue) {
+        bills.prototype.updateField = function (node, field, newValue,toBX) {//当toBX为true时类型改为补项
             calcFees.setFee(node.data, field, newValue);
             let updateData = [];
             let data = {'ID': node.getID(), 'projectID': this.project.ID()};
             data[field] = newValue;
+            if(toBX == true){
+                data.type = billType.BX
+            }
             updateData.push({'updateType': 'ut_update', 'updateData': tools.formatBillsUpdateData(data)});
             this.project.pushNow('updateBills', this.getSourceType(), updateData);
         };
@@ -505,6 +508,12 @@ var Bills = {
                 return false;
             }
         };
+        bills.prototype.isBX = function (node) {//判读是否属于补项
+            if(node && node.sourceType == ModuleNames.bills&&node.data.type==billType.BX){
+                return  true;
+            }
+            return false;
+        };
         bills.prototype.isTechMeasure = function (node) {//判读是否属于技术措施项目部分
             let techMeasureCheck = function (checkNode) {
                 if(isFlag(checkNode.data)&&checkNode.data.flagsIndex.fixed.flag==fixedFlag.CONSTRUCTION_TECH){

+ 27 - 0
web/building_saas/main/js/models/project.js

@@ -328,6 +328,33 @@ var PROJECT = {
                 });
             }
         };
+        project.prototype.updateLockBills = function (value,callback) {
+            let mixDatas = {
+                projectID: projectObj.project.ID(),
+                updateType: 'update',
+                properties: {
+                    "property.lockBills":value
+                },
+                labourCoes: {},
+                rations: [],
+                bills: []
+            };
+            $.bootstrapLoading.start();
+            CommonAjax.post('/pm/api/updateMixDatas', {user_id: userID, mixDataArr: mixDatas}, function (rstData) {
+                projectInfoObj.projectInfo.property.lockBills = value;
+                if(callback){
+                    callback();
+                }
+                $.bootstrapLoading.end();
+            });
+        };
+        //返回清单是否被锁定
+        project.prototype.isBillsLocked =function(){
+            if(projectInfoObj.projectInfo.property.lockBills == true){
+                return true;
+            }
+            return false;
+        };
         project.prototype.updateNodes = function (datas,callback) {
           /*  let datas = [
                 {

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

@@ -571,7 +571,7 @@ var quantity_detail = {
             console.log(value);
             let needUpdateChildren = [];//需更新的子定额
             let gljNodes=[];//当定额工程量改变时需刷新的子工料机
-            if(node.children.length>0){//如果有子项
+            if(node.children.length>0){//如果有子项
                 for(let rationNode of node.children){
                     let EXPString = rationNode.data.quantityEXP+"";
                     if(EXPString.indexOf("QDL")!=-1){

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

@@ -317,7 +317,12 @@ var gljOprObj = {
     },
     detailSheetReadonly:function () {
         let selected = projectObj.project.mainTree.selected;
-        if(selected) {//是主材或者是设备时只读
+        if(selected) {
+            //清单锁定时只读
+            if(selected.sourceType == ModuleNames.bills && projectObj.project.isBillsLocked()){
+                return true;
+            }
+            //是主材或者是设备时只读
             if(selected.sourceType == ModuleNames.ration_glj){
                 return true;
             }else if(gljOprObj.isInstallationNode(selected)){//是补项或者是安装类型的定额时只读
@@ -375,7 +380,7 @@ var gljOprObj = {
         }
     },
     isInstallationNode:function(node){
-        if((node.sourceType == ModuleNames.ration&&node.data.type == rationType.install)||(node.sourceType == ModuleNames.bills&&node.data.type==billType.BX)){//是定额安装费类型或者补项
+        if(node.sourceType == ModuleNames.ration&&node.data.type == rationType.install){//是定额安装费类型时只读,原先是补项的时候也是控制只读的||(node.sourceType == ModuleNames.bills&&node.data.type==billType.BX)){//是定额安装费类型或者补项
             return true;
         }
         return false

+ 23 - 4
web/building_saas/main/js/views/main_tree_col.js

@@ -269,15 +269,34 @@ let MainTreeCol = {
                 return new GC.Spread.Sheets.CellTypes.CheckBox();
         }
     },
+    editChecking:function(node){
+        if(node.sourceType==projectObj.project.Bills.getSourceType()&&projectObj.project.isBillsLocked()){
+            return true;
+        }
+        if(gljOprObj.isInstallationNode(node)){//如果是通过安装增加费自动生成的,都是只读类型
+            return true;
+        }
+        return false;
+    },
     setAutoHeight:function (cell,node) {//设置自动行高
+        cell.wordWrap(MainTreeCol.needAutoFit(node));
+    },
+    setAutoFitRow:function (sheet,node) {
+        if(MainTreeCol.needAutoFit(node)){
+            sheet.autoFitRow(node.serialNo());
+        }
+    },
+    needAutoFit:function (node) {
         let displaySetting = projectObj.project.property.displaySetting;
         let billsAutoH = displaySetting && displaySetting.billsAutoHeight?displaySetting.billsAutoHeight:false;
         let rationAutoH = displaySetting && displaySetting.rationAutoHeight?displaySetting.rationAutoHeight:false;
-        if(node.sourceType === projectObj.project.Bills.getSourceType()){
-            cell.wordWrap(billsAutoH);
-        }else {
-            cell.wordWrap(rationAutoH);
+        if(node.sourceType === projectObj.project.Bills.getSourceType()&&billsAutoH == true){
+            return true;
+        }
+        if(node.sourceType !== projectObj.project.Bills.getSourceType()&& rationAutoH == true){
+            return true;
         }
+        return false;
     },
     getEvent: function (eventName) {
         let names = eventName.split('.');

+ 194 - 69
web/building_saas/main/js/views/project_view.js

@@ -21,6 +21,20 @@ var projectObj = {
     },
     treeSelectedChanged: function (node) {
         let project = projectObj.project;
+        //设置选中行底色和恢复前选中行底色
+        let refreshNodes = [node];
+        if(!project.mainTree.preSelected){
+            refreshNodes.push(project.mainTree.items[0]);
+        }
+        else {
+            refreshNodes.push(project.mainTree.preSelected);
+        }
+        project.mainTree.preSelected = node;
+        projectObj.setNodesStyle(projectObj.mainController.sheet, refreshNodes);
+   /*     TREE_SHEET_HELPER.massOperationSheet(projectObj.mainController.sheet, function () {
+            TREE_SHEET_HELPER.refreshTreeNodeData(projectObj.mainController.setting, projectObj.mainController.sheet, refreshNodes, false);
+        });*/
+
         subViewObj.loadComments(node);
         gljOprObj.showDataIfRationSelect(node);
         if (activeSubSheetIs(subSheetIndex.ssiCalcProgram)) {
@@ -36,7 +50,6 @@ var projectObj = {
                 pageCCOprObj.clearData();
             }
         }
-
         // for test interface.  CSLAAAAA
         // projectObj.testDisplay('前四项累计值排除当前选中项' + projectObj.project.calcProgram.getBeforeTaxTotalFee([node]));
 
@@ -60,6 +73,9 @@ var projectObj = {
             if(!node){
                 return false;
             }
+            if(projectObj.project.isBillsLocked()== true){
+                return false;
+            }
             if(node.depth()<=1){//焦点行是树结构的第一/二层节点,灰显。
                 return false;
             }
@@ -89,6 +105,9 @@ var projectObj = {
             if(!node){
                 return false;
             }
+            if(projectObj.project.isBillsLocked()== true){
+                return false;
+            }
             if(node.depth()==0){//焦点行是树结构的第一层节点,灰显。
                 return false;
             }
@@ -116,8 +135,13 @@ var projectObj = {
         };
         let canUpMove = function (node) {
             if(node&&node.preSibling){//有前兄弟
-                if(node.sourceType==that.project.Bills.getSourceType()&&node.data.type == billType.DXFY&&node.data.isAdd!==1){
-                    return false;
+                if(node.sourceType==that.project.Bills.getSourceType()){
+                    if(projectObj.project.isBillsLocked()== true){
+                        return false;
+                    }
+                    if(node.data.type == billType.DXFY&&node.data.isAdd!==1){
+                        return false;
+                    }
                 }
                 return true
             }
@@ -125,8 +149,13 @@ var projectObj = {
         };
         let canDownMove = function (node) {
             if(node&&node.nextSibling){
-                if(node.sourceType==that.project.Bills.getSourceType()&&node.data.type == billType.DXFY&&node.data.isAdd!==1){
-                    return false;
+                if(node.sourceType==that.project.Bills.getSourceType()){
+                    if(projectObj.project.isBillsLocked()== true){
+                        return false;
+                    }
+                    if(node.data.type == billType.DXFY&&node.data.isAdd!==1){
+                        return false;
+                    }
                 }
                 return true;
             }
@@ -235,19 +264,21 @@ var projectObj = {
         return rst;
     },
     updateBillsCode: function (node, value) {
-        let project = projectObj.project;
+        let project = projectObj.project,me = this;
         let stdMatchCode, formatCode, matchs;
         let searchStdBillsAndUpdate = function (stdCode, formatCode) {
             let orgCode = node.data.code?node.data.code.substr(0, 9):"";
             if (stdCode === orgCode || projectInfoObj.projectInfo.engineeringInfo.bill_lib.length === 0) {
-                project.Bills.updateField(node.source, 'code', formatCode, true);
-                projectObj.mainController.refreshTreeNode([node], false);
+                normalUpdate(node,value);
             } else if (projectInfoObj.projectInfo.engineeringInfo.bill_lib.length > 0) {
                 let libId = projectInfoObj.projectInfo.engineeringInfo.bill_lib[0].id;
                 CommonAjax.post('/stdBillsEditor/getStdBillsByCode', {userId: userID, billsLibId: libId, code: stdCode}, function (data) {
                     if (data) {
                         //data.itemCharacter = pageCCOprObj.safeItemCharater(data.itemCharacter);
                         node.data.name = data.name;
+                        if(node.data.type == billType.BX){//从清单库中找到标准清单的话,要把补项改成分项
+                            node.data.type = billType.FX;
+                        }
                         pageCCOprObj.setItemContentNode(node, data.jobContent, data.itemCharacter, node.data.name);
                         if (/\//.test(data.unit)) {
                             let existB = projectObj.project.Bills.sameStdCodeBillsData(data.code);
@@ -269,13 +300,12 @@ var projectObj = {
                             projectObj.mainController.refreshTreeNode([node], false);
                         }
                     } else {
-                        project.Bills.updateField(node.source, 'code', formatCode, true);
-                        projectObj.mainController.refreshTreeNode([node], false);
+                        normalUpdate(node,value);
                     }
                 });
             }
         }
-        if(node.data.type==billType.FX||(node.data.type==billType.BILL&&node.source.children.length==0)){//是分项或者叶子清单的情况下才需要查找替换
+        if(node.data.type==billType.FX||node.data.type==billType.BX||(node.data.type==billType.BILL&&node.source.children.length==0)){//是分项、补项或者叶子清单的情况下才需要查找替换
             if (value&&value.length === 9 && /^[\d]+$/.test(value)) {
                 stdMatchCode = value;
                 formatCode = project.Bills.newFormatCode(stdMatchCode);
@@ -286,16 +316,31 @@ var projectObj = {
                 matchs = project.Bills.sameStdCode(stdMatchCode, node.data.code);
                 if (matchs.indexOf(value) === -1) {
                     searchStdBillsAndUpdate(stdMatchCode, value);
-                } else if (confirm('已存在该编码的清单,是否继续?')) {
-                    formatCode = project.Bills.newFormatCode(stdMatchCode, node.data.code);
-                    searchStdBillsAndUpdate(stdMatchCode, formatCode);
                     return;
+                } else {
+                   if (confirm('已存在该编码的清单,是否继续?')) {
+                       // formatCode = project.Bills.newFormatCode(stdMatchCode, node.data.code);
+                        searchStdBillsAndUpdate(stdMatchCode, value);
+                        return;
+                    }else {
+                       this.mainController.refreshTreeNode([node], false);
+                       return;
+                   }
                 }
             }
         }
-        project.Bills.updateField(node.source, 'code', value, true);
-        this.mainController.refreshTreeNode([node], false);
+        normalUpdate(node,value);
 
+
+        function normalUpdate(billnode,codeValue) {//在标准库中没有找到清单时改分项为补项再更新
+            let toBX = false;
+            if(billnode.data.type == billType.FX){
+                billnode.data.type = billType.BX;
+                 toBX = true;
+            }
+            project.Bills.updateField(billnode.source, 'code', codeValue, toBX);
+            me.mainController.refreshTreeNode([billnode], false);
+        }
     },
     updateRationCode: function (node, value) {
         if(!isDef(node.data.code) && (!isDef(value) || value.toString().trim() == '')){
@@ -410,6 +455,35 @@ var projectObj = {
             projectObj.mainController.refreshTreeNode([node], false);
         }
     },
+    mainSpreadSlectionChanging: function (sender, info) {
+        console.log('bbbb');
+        let oldSel = info.oldSelections[0], newSel = info.newSelections[0];
+        let project = projectObj.project;
+        //设置选中行底色和恢复前选中行底色
+        let refreshNodes = [];
+        if(oldSel){
+            oldSel.row === -1 ? 0 : oldSel.row;
+            for(let i = 0; i < oldSel.rowCount; i++){
+                if(project.mainTree.items[i + oldSel.row]){
+                    refreshNodes.push(project.mainTree.items[i + oldSel.row]);
+                }
+            }
+        }
+        if(newSel){
+            newSel.row === -1 ? 0 : newSel.row;
+            for(let i = 0; i < newSel.rowCount; i++){
+                if(project.mainTree.items[i + newSel.row]){
+                    refreshNodes.push(project.mainTree.items[i + newSel.row]);
+                }
+            }
+        }
+        if(refreshNodes.length > 0){
+            projectObj.setNodesStyle(projectObj.mainController.sheet, refreshNodes, newSel);
+            /* TREE_SHEET_HELPER.massOperationSheet(projectObj.mainController.sheet, function () {
+             TREE_SHEET_HELPER.refreshTreeNodeData(projectObj.mainController.setting, projectObj.mainController.sheet, refreshNodes, false, true);
+             });*/
+        }
+    },
     mainSpreadLeaveCell: function (sender, info) {
         let colSetting = projectObj.mainController.setting.cols[info.col];
         projectObj.lastCol = colSetting;
@@ -524,6 +598,7 @@ var projectObj = {
                 that.project.projSetting.mainGridSetting = JSON.parse(str);
                 that.project.projSetting.mainGridSetting.frozenCols = 4;
                 TREE_SHEET_HELPER.initSetting($('#billsSpread')[0], that.project.projSetting.mainGridSetting);
+                that.project.projSetting.mainGridSetting.setAutoFitRow = MainTreeCol.getEvent("setAutoFitRow");
                 that.project.projSetting.mainGridSetting.cols.forEach(function (col) {
                     col.data.splitFields = col.data.field.split('.');
                     if (col.data.getText && Object.prototype.toString.apply(col.data.getText) === "[object String]") {
@@ -544,6 +619,7 @@ var projectObj = {
                         col.data.formatter = '@';
                     }
                     col.setAutoHeight = MainTreeCol.getEvent("setAutoHeight");
+                    col.editChecking = MainTreeCol.getEvent("editChecking");
                     // 根据配置设置自动行高,在这里先做个标记,然后对每个单元格单独配置
                     if (col.data.field === 'name' || col.data.field === 'itemCharacterText' ||
                         col.data.field === 'jobContentText' || col.data.field === 'adjustState') {
@@ -565,6 +641,7 @@ var projectObj = {
                 });
                 let startShowTime = +new Date();
                 that.mainController = TREE_SHEET_CONTROLLER.createNew(that.project.mainTree, that.mainSpread.getActiveSheet(), that.project.projSetting.mainGridSetting);
+
                 that.mainController.showTreeData();
                 let endShowTime = +new Date();
                 console.log(`show data时间——${endShowTime - startShowTime}`);
@@ -574,7 +651,6 @@ var projectObj = {
 
                 that.mainSpread.getActiveSheet().startEdit();
                 that.mainSpread.getActiveSheet().endEdit();
-
                 that.mainSpread.bind(GC.Spread.Sheets.Events.LeaveCell, that.mainSpreadLeaveCell);
                 that.mainSpread.bind(GC.Spread.Sheets.Events.EnterCell, that.mainSpreadEnterCell);
                 that.mainSpread.bind(GC.Spread.Sheets.Events.EditStarting, that.mainSpreadEditStarting);
@@ -586,7 +662,6 @@ var projectObj = {
                 //let loadOtherStartTime = +new Date();
                 that.loadMainSpreadContextMenu();
                 that.loadFocusLocation();
-
                 socketObject.connect();//连接socket服务器
                 let endTime = +new Date();
                 console.log(`其它时间——${endTime - endShowTime}`);
@@ -618,6 +693,7 @@ var projectObj = {
                     name: "插入大项费用",
                     icon: 'fa-sign-in',
                     disabled: function () {
+                        return projectObj.project.isBillsLocked();
                         //return project.mainTree.selected ? project.mainTree.selected.sourceType !== project.Bills.getSourceType() : false;
                     },
                     callback: function (key, opt) {
@@ -632,7 +708,7 @@ var projectObj = {
                     icon: 'fa-sign-in',
                     disabled: function () {
                         let selected = project.mainTree.selected;
-                        if(selected&&selected.sourceType==project.Bills.getSourceType()){
+                        if(projectObj.project.isBillsLocked()== false&&selected&&selected.sourceType==project.Bills.getSourceType()){
                             if(selected.data.type==billType.FB){
                                 return false;
                             }
@@ -662,7 +738,7 @@ var projectObj = {
                     icon: 'fa-sign-in',
                     disabled: function () {
                         let selected = project.mainTree.selected;
-                        if(selected&&selected.sourceType==project.Bills.getSourceType()){
+                        if(projectObj.project.isBillsLocked()== false&& selected&&selected.sourceType==project.Bills.getSourceType()){
                             if(selected.data.type==billType.FX){//焦点行是分项,有效显示
                                 return false
                             }
@@ -698,7 +774,11 @@ var projectObj = {
                     name: "插入清单",
                     icon: 'fa-sign-in',
                     disabled: function () {
-                        return project.mainTree.selected ? project.mainTree.selected.sourceType !== project.Bills.getSourceType() : false;
+                        let selected = project.mainTree.selected;
+                        if(projectObj.project.isBillsLocked()== false && selected && selected.sourceType === project.Bills.getSourceType()){
+                            return false
+                        }
+                        return true;
                     },
                     callback: function (key, opt) {
                         if(project.mainTree.selected.data.type == billType.DXFY){
@@ -798,7 +878,7 @@ var projectObj = {
                     name: "整理分部",
                     icon: 'fa-sign-in',
                     disabled: function () {
-                       return false;
+                       return projectObj.project.isBillsLocked();
                     },
                     callback: function (key, opt) {
                         zlfb_object.getSectionInfo();
@@ -876,13 +956,18 @@ var projectObj = {
         const projectId = scUrlUtil.GetQueryString('project');
         let row = getLocalCache('lastRow:' + projectId);
         let col = getLocalCache('lastCol:' + projectId);
-        if (row !== null && col !== null) {
-            row = parseInt(row);
-            col = parseInt(col);
-            const sheet = this.mainSpread.getActiveSheet();
-            sheet.setSelection(row, col, 1, 1);
-            this.mainController.setTreeSelected(this.mainController.tree.items[row]);//触发树节点选中事件
-        }
+        if(row == null || col == null){
+            row = 0;
+            col = 0;
+
+
+
+       }
+        row = parseInt(row);
+        col = parseInt(col);
+        const sheet = this.mainSpread.getActiveSheet();
+        sheet.setSelection(row, col, 1, 1);
+        this.mainController.setTreeSelected(this.mainController.tree.items[row]);//触发树节点选中事件
     },
     // 选中区域合计数字
     amountAreaNumber: function(e, info) {
@@ -970,9 +1055,9 @@ var projectObj = {
     },
 
     //根据节点获取行style(颜色、字体加粗)
-    getNodeColorStyle: function (node, colSetting) {
+    getNodeColorStyle: function (sheet, node, colSetting) {
         let colorSetting = optionsOprObj.getOption(optionsOprObj.optionsTypes.COLOROPTS);
-        let mapping = {DEFAULT: 'DEFAULT', DXFY: 'DXFY', FB: 'FB', UNLEAFBILL: 'UNLEAFBILL',
+        let mapping = {DEFAULT: 'DEFAULT', SELECTED: 'SELECTED', DXFY: 'DXFY', FB: 'FB', UNLEAFBILL: 'UNLEAFBILL',
             FX: 'FX', BX: 'BX', UNCBBILL: 'UNCBBILL', CBBILL: 'CBBILL', ZCSB: 'ZCSB'};
         let styleMap = null;
         //中文字段名,由于同一节点中,中文字体大小和数字字体大小不同
@@ -994,47 +1079,53 @@ var projectObj = {
         if(!isDef(node)){
             return null;
         }
-        //清单大类
-        if(node.sourceType === this.project.Bills.getSourceType()){
-            //大项费用
-            //大项费用
-            if(node.data.type === billType.DXFY){
-                styleMap = mapping.DXFY;
-            }
-            //分部
-            if(node.data.type === billType.FB){
-                styleMap = mapping.FB;
-            }
-            //分项
-            else if(node.data.type === billType.FX){
-                styleMap = mapping.FX;
-            }
-            //补项
-            else if(node.data.type === billType.BX){
-                styleMap = mapping.BX;
-            }
-            //清单
-            else if(node.data.type === billType.BILL){
-                //非叶子节点的清单
-                if(node.source.children.length > 0){
-                    styleMap = mapping.UNLEAFBILL;
+        //选中行
+        if(node === this.project.mainTree.selected){
+            styleMap = mapping.SELECTED;
+        }
+        //非选中行
+        else {
+            //清单大类
+            if(node.sourceType === this.project.Bills.getSourceType()){
+                //大项费用
+                if(node.data.type === billType.DXFY){
+                    styleMap = mapping.DXFY;
+                }
+                //分部
+                if(node.data.type === billType.FB){
+                    styleMap = mapping.FB;
+                }
+                //分项
+                else if(node.data.type === billType.FX){
+                    styleMap = mapping.FX;
                 }
-                //未使用基数计算的叶子节点的清单
-                else if(node.source.children.length === 0 && (!isDef(node.data.calcBase) || node.data.calcBase === '')){
-                    styleMap = mapping.UNCBBILL;
+                //补项
+                else if(node.data.type === billType.BX){
+                    styleMap = mapping.BX;
                 }
-                //使用基数计算的叶子节点的清单
-                else if(node.source.children.length === 0 && isDef(node.data.calcBase && node.data.calcBaseValue !== '')){
-                    styleMap = mapping.CBBILL;
+                //清单
+                else if(node.data.type === billType.BILL){
+                    //非叶子节点的清单
+                    if(node.source.children.length > 0){
+                        styleMap = mapping.UNLEAFBILL;
+                    }
+                    //未使用基数计算的叶子节点的清单
+                    else if(node.source.children.length === 0 && (!isDef(node.data.calcBase) || node.data.calcBase === '')){
+                        styleMap = mapping.UNCBBILL;
+                    }
+                    //使用基数计算的叶子节点的清单
+                    else if(node.source.children.length === 0 && isDef(node.data.calcBase && node.data.calcBaseValue !== '')){
+                        styleMap = mapping.CBBILL;
+                    }
                 }
             }
-        }
-        //定额下的主材、设备
-        else if(node.sourceType === this.project.ration_glj.getSourceType()){
-            styleMap = mapping.ZCSB;
-        }
-        else {
-            styleMap = mapping.DEFAULT;
+            //定额下的主材、设备
+            else if(node.sourceType === this.project.ration_glj.getSourceType()){
+                styleMap = mapping.ZCSB;
+            }
+            else {
+                styleMap = mapping.DEFAULT;
+            }
         }
         let styleSetting = colorSetting[styleMap];
         let defaultSetting = colorSetting[mapping.DEFAULT];
@@ -1090,8 +1181,27 @@ var projectObj = {
             style.font = 'bold 13px Arial';
         }
         return style;
+    },
+   //设置节点style
+    setNodesStyle: function (sheet, nodes) {
+        let me = this;
+        TREE_SHEET_HELPER.massOperationSheet(sheet, function () {
+            for(let node of nodes){
+                sheet.setStyle(node.serialNo(), -1, me.getNodeColorStyle(sheet, node));
+            }
+        });
+     
+},
+    loadLockBillsButton:function () {
+        if(projectInfoObj.projectInfo.property.lockBills == true){
+            $("a[name='lockBills']").prop("title","解锁清单");
+            $("a[name='lockBills']").html('<i class="fa fa-unlock-alt" aria-hidden="true"></i> 解锁清单');
+        }else {
+            $("a[name='lockBills']").prop("title","锁定清单");
+            $("a[name='lockBills']").html('<i class="fa fa-lock" aria-hidden="true"></i> 锁定清单');
+        }
     }
-    
+
 };
 // 点击合计框中的复制
 $("body").on("click", "#total-tips a", function() {
@@ -1177,6 +1287,18 @@ $('#downMove').click(function () {
         };
     }
 });
+$("a[name='lockBills']").click(function () {
+    let lockBills = projectInfoObj.projectInfo.property.lockBills;
+    lockBills = !lockBills;
+    projectObj.project.updateLockBills(lockBills,function () {
+        var controller = projectObj.mainController, project = projectObj.project;
+        var selected = controller.tree.selected;
+        let nodes = _.filter(project.mainTree.items,{'sourceType':ModuleNames.bills});
+        controller.refreshTreeNode(nodes);
+        projectObj.mainController.setTreeSelected(selected);//触发树节点选中事件
+        projectObj.loadLockBillsButton();
+    });
+});
 //显示至..
 let displayLevel = function(nodes, depth, type){
     let refreshNodes = [];
@@ -1495,6 +1617,9 @@ function ifCanDelete() {
                 if(node.data.type == billType.DXFY&&node.data.isAdd!=1){
                     return false;
                 }
+                if(projectObj.project.isBillsLocked()== true){
+                    return false;
+                }
             }
             if(m_selection!=true&&node.sourceType === projectObj.project.ration_glj.getSourceType()){//多选的时候不做这一项判断
                 return false;

+ 45 - 0
web/building_saas/pm/html/project-management-Recycle.html

@@ -31,6 +31,25 @@
         </div>
     </div>
 </div>
+<!--弹出清除项目-->
+<div class="modal fade" id="delPoj" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">清除 <i class="fa fa-cubes"></i> 建设项目</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>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                <a href="javascript:void(0);" class="btn btn-primary" data-dismiss="modal" id="delPojBtn">确定</a>
+            </div>
+        </div>
+    </div>
+</div>
 <!--弹出恢复文件-->
 <div class="modal fade" id="reFile" data-backdrop="static">
     <div class="modal-dialog" role="document">
@@ -57,3 +76,29 @@
         </div>
     </div>
 </div>
+<!--弹出清除文件-->
+<div class="modal fade" id="delFile" 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 modal-fixed-height">
+                <p>勾选需要恢复的文件,点“确定”按钮,确认从回收站中恢复。</p>
+                <table class="table table-hover table-sm mb-5">
+                    <thead><tr><th>名称</th><th>删除时间</th><th>勾选</th></tr></thead>
+                    <tbody>
+                    <tr><td>XX单价文件</td><td>2017-11-01<br>12:11:43</td><td><input type="checkbox"></td></tr>
+                    </tbody>
+                </table>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                <a href="javascript:void(0);" class="btn btn-primary" id="delFileBtn" data-dismiss="modal">确定</a>
+            </div>
+        </div>
+    </div>
+</div>

+ 257 - 48
web/building_saas/pm/js/pm_gc.js

@@ -174,9 +174,12 @@ const gcTreeObj = {
             {name: '工程列表', dataCode: 'name', width: 800, vAlign: 'center', hAlign: 'left'},
             {name: '删除日期', dataCode: 'deleteDateTime', width: 170, vAlign: 'center', hAlign: 'left'},
             {name: '创建日期', dataCode: 'createDateTime', width: 170, vAlign: 'center', hAlign: 'left'},
-            {name: '恢复', dataCode: 'recovery', width: 170, vAlign: 'center', hAlign: 'left'},
-            {name: '单价文件', dataCode: 'unitPriceFile', width: 170, vAlign: 'center', hAlign: 'left'},
-            {name: '费率文件', dataCode: 'feeRateFile', width: 170, vAlign: 'center', hAlign: 'left'}
+            {name: '恢复', dataCode: 'recovery', width: 100, vAlign: 'center', hAlign: 'left'},
+            {name: '清除', dataCode: 'delete', width: 100, vAlign: 'center', hAlign: 'left'},
+            {name: '单价文件', dataCode: 'unitPriceFile', width: 100, vAlign: 'center', hAlign: 'left'},
+            {name: '单价文件-清除', dataCode: 'unitPriceFile_delete', width: 100, vAlign: 'center', hAlign: 'left'},
+            {name: '费率文件', dataCode: 'feeRateFile', width: 100, vAlign: 'center', hAlign: 'left'},
+            {name: '费率文件-清除', dataCode: 'feeRateFile_delete', width: 100, vAlign: 'center', hAlign: 'left'}
         ],
         //选中行颜色
         style: {
@@ -221,8 +224,15 @@ const gcTreeObj = {
             sheet.setColumnCount(headers.length);
             sheet.setRowHeight(0, 40, GC.Spread.Sheets.SheetArea.colHeader);
             for(let i = 0, len = headers.length; i < len; i++){
-                sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
                 sheet.setColumnWidth(i, headers[i].width, GC.Spread.Sheets.SheetArea.colHeader);
+                if(headers[i].dataCode === 'unitPriceFile' || headers[i].dataCode === 'feeRateFile'){
+                    //合并列
+                    sheet.addSpan(0, i, 1, 2, GC.Spread.Sheets.SheetArea.colHeader);
+                }
+                if(headers[i].dataCode === 'unitPriceFile_delete' || headers[i].dataCode === 'feeRateFile_delete'){
+                    continue;
+                }
+                sheet.setValue(0, i, headers[i].name, GC.Spread.Sheets.SheetArea.colHeader);
             }
         };
         me.renderSheetFuc(sheet, fuc);
@@ -304,29 +314,49 @@ const gcTreeObj = {
         me.initSelection(args.newSelections[0], args.oldSelections[0]);
     },
     //点击恢复列,弹出恢复项目窗口
-    recoveryProj: function (node) {
+    oprProj: function (modalId, node) {
         let tenderNodes = m_getTenders(node);
-        $('#rePoj .modal-header').empty();
-        $('p', '#rePoj .modal-body').remove();
-        $('#rePoj .modal-header').html(v_getTitle(node));
-        $('#rePoj .modal-body').html(v_getMoBody(node, tenderNodes));
-        $('#rePoj').modal('show');
+        let type = modalId === '#rePoj' ? 'recovery' : 'delete';
+        $(`${modalId} .modal-header`).empty();
+        $('p', `${modalId} .modal-body`).remove();
+        $(`${modalId} .modal-header`).html(v_getTitle(type, node));
+        $(`${modalId} .modal-body`).html(v_getMoBody(type, node, tenderNodes));
+        $(`${modalId}`).modal('show');
     },
     //点击单价文件恢复,弹出恢复单价文件窗口
     recoveryUnitPrc: function (node) {
         let unitPriceFiles = node.data.unitPriceFiles;
+        let tenders = m_getTenders(node);
         $('#reFile h5').text('恢复单价文件');
         $('tr', '#reFile tbody').remove();
-        $('#reFile tbody').html(v_getFiles(fileType.unitPriceFile, unitPriceFiles));
+        $('#reFile tbody').html(v_getFiles(fileType.unitPriceFile, unitPriceFiles, tenders, 'recovery'));
         $('#reFile').modal('show');
     },
     recoveryFeeRate: function (node) {
         let feeRateFiles = node.data.feeRateFiles;
+        let tenders = m_getTenders(node);
         $('#reFile h5').text('恢复费率文件');
         $('tr', '#reFile tbody').remove();
-        $('#reFile tbody').html(v_getFiles(fileType.feeRateFile, feeRateFiles));
+        $('#reFile tbody').html(v_getFiles(fileType.feeRateFile, feeRateFiles, tenders, 'recovery'));
         $('#reFile').modal('show');
     },
+    //点击单价文件清除,弹出清除单价文件窗口
+    deleteUnitPrc: function (node) {
+        let unitPriceFiles = node.data.unitPriceFiles;
+        let tenders = m_getTenders(node);
+        $('#delFile h5').text('清除单价文件');
+        $('tr', '#delFile tbody').remove();
+        $('#delFile tbody').html(v_getFiles(fileType.unitPriceFile, unitPriceFiles, tenders, 'delete'));
+        $('#delFile').modal('show');
+    },
+    deleteFeeRate: function (node) {
+        let feeRateFiles = node.data.feeRateFiles;
+        let tenders = m_getTenders(node);
+        $('#delFile h5').text('清除费率文件');
+        $('tr', '#delFile tbody').remove();
+        $('#delFile tbody').html(v_getFiles(fileType.feeRateFile, feeRateFiles, tenders, 'delete'));
+        $('#delFile').modal('show');
+    },
     getTreeNodeCell: function (tree) {
         let indent = 20;
         let levelIndent = -5;
@@ -517,20 +547,35 @@ const gcTreeObj = {
                 zoom = hitinfo.sheet.zoom();
             let textLength = this.getAutoFitWidth(value, text, acStyle, zoom, {sheet: hitinfo.sheet, row: hitinfo.row, col: hitinfo.col, sheetArea: GC.Spread.Sheets.SheetArea.viewport});
             if(hitinfo.x - hitinfo.cellRect.x > 0 && hitinfo.x - hitinfo.cellRect.x < textLength){
+                //恢复
                 if(dataCode === 'recovery'){
-                    gcTreeObj.recoveryProj(node);
+                    gcTreeObj.oprProj('#rePoj', node);
+                }
+                //清除
+                else if(dataCode === 'delete'){
+                    gcTreeObj.oprProj('#delPoj', node)
                 }
+                //恢复单价文件
                 else if(dataCode === 'unitPriceFile'){
                     gcTreeObj.recoveryUnitPrc(node);
                 }
+                //清除单价文件
+                else if(dataCode === 'unitPriceFile_delete'){
+                    gcTreeObj.deleteUnitPrc(node);
+                }
+                //恢复费率文件
                 else if(dataCode === 'feeRateFile'){
                     gcTreeObj.recoveryFeeRate(node);
                 }
+                //清除费率文件
+                else if(dataCode === 'feeRateFile_delete'){
+                    gcTreeObj.deleteFeeRate(node);
+                }
             }
         };
         MyBaseCell.prototype.processMouseMove = function (hitInfo) {
             let dataCode = gcTreeObj.setting.header[hitInfo.col]['dataCode'];
-            if(dataCode === 'recovery' || dataCode === 'unitPriceFile' || dataCode === 'feeRateFile'){
+            if(dataCode === 'recovery' || dataCode === 'delete' || dataCode === 'unitPriceFile' || dataCode === 'unitPriceFile_delete' || dataCode === 'feeRateFile' || dataCode === 'feeRateFile_delete'){
                 let sheet = hitInfo.sheet;
                 let div = sheet.getParent().getHost();
                 let canvasId = div.id + "vp_vp";
@@ -569,16 +614,31 @@ const gcTreeObj = {
                 value = '恢复';
             }
         }
+        else if(dataCode === 'delete'){
+            if(deleted(node)){
+                value = '清除';
+            }
+        }
         else if(dataCode === 'unitPriceFile'){
             if(node.data.projType === projectType.project && node.data.unitPriceFiles !== undefined && node.data.unitPriceFiles.length > 0){
                 value = '恢复';
             }
         }
+        else if(dataCode === 'unitPriceFile_delete'){
+            if(node.data.projType === projectType.project && node.data.unitPriceFiles !== undefined && node.data.unitPriceFiles.length > 0){
+                value = '清除';
+            }
+        }
         else if(dataCode === 'feeRateFile'){
             if(node.data.projType === projectType.project && node.data.feeRateFiles !== undefined && node.data.feeRateFiles.length > 0){
                 value = '恢复';
             }
         }
+        else if(dataCode === 'feeRateFile_delete'){
+            if(node.data.projType === projectType.project && node.data.feeRateFiles !== undefined && node.data.feeRateFiles.length > 0){
+                value = '清除';
+            }
+        }
         else {
             value = node.data[dataCode] ? node.data[dataCode] : '';
         }
@@ -644,7 +704,9 @@ $(document).ready(function () {
         projTreeObj.tree = null;
     });
     e_recFiles($('#reFileBtn'));
+    e_delFiles($('#delFileBtn'));
     e_recProj($('#rePojBtn'));
+    e_delProj($('#delPojBtn'));
 });
 
 function gc_init(){
@@ -664,9 +726,9 @@ function gc_init(){
 }
 
 //项目恢复模态框标题
-function v_getTitle(node){
+function v_getTitle(type, node){
     let html = '';
-    html += '<h5 class="modal-title">恢复 ';
+    html += type === 'recovery' ? '<h5 class="modal-title">恢复 ' : '<h5 class="modal-title">清除 ';
     if(node.data.projType === projectType.project){
         html += '<i class="fa fa-cubes"></i>建设项目</h5>';
     }
@@ -681,48 +743,73 @@ function v_getTitle(node){
 }
 
 //项目恢复模态框主体
-function v_getMoBody(oprNode, nodes){
+function v_getMoBody(type, oprNode, nodes){
     let html = '';
-    if(oprNode.data.projType === projectType.tender){
-        decDate = '(' + new Date().Format('MM-dd hh:mm:ss') + '恢复)';
-        let recName = oprNode.data.name + decDate;
-        html += '<p>恢复后将重命名为 <b>' + recName + '</b></p>';
-    }
-    else {
-        if(oprNode.data.projType === projectType.project){
-            html += '<p><i class="fa fa-cubes"></i> ' + oprNode.data.name + '下的单位工程都将恢复都将恢复,恢复后将重命名为</p>';
-        }
-        else if(oprNode.data.projType === projectType.engineering){
-            html += '<p><i class="fa fa-cube"></i> ' + oprNode.data.name + '下的单位工程都将恢复都将恢复,恢复后将重命名为</p>';
+    if(type === 'recovery'){
+        if(oprNode.data.projType === projectType.tender){
+            decDate = '(' + new Date().Format('MM-dd hh:mm:ss') + '恢复)';
+            let recName = oprNode.data.name + decDate;
+            html += '<p>恢复后将重命名为 <b>' + recName + '</b></p>';
         }
-        html += ('<p>');
-        for(let i = 0, len = nodes.length; i < len; i++){
-            let recName = nodes[i].data.name + '(' + new Date().Format('MM-dd hh:mm:ss') +'恢复)';
-            html += '<b>' + recName + '</b>、';
+        else {
+            if(oprNode.data.projType === projectType.project){
+                html += '<p><i class="fa fa-cubes"></i> ' + oprNode.data.name + '下的单位工程都将恢复都将恢复,恢复后将重命名为</p>';
+            }
+            else if(oprNode.data.projType === projectType.engineering){
+                html += '<p><i class="fa fa-cube"></i> ' + oprNode.data.name + '下的单位工程都将恢复都将恢复,恢复后将重命名为</p>';
+            }
+            html += ('<p>');
+            for(let i = 0, len = nodes.length; i < len; i++){
+                let recName = nodes[i].data.name + '(' + new Date().Format('MM-dd hh:mm:ss') +'恢复)';
+                html += '<b>' + recName + '</b>、';
+            }
+            html = html.slice(0, html.length - 1);
+            html += ('</p>');
         }
-        html = html.slice(0, html.length - 1);
-        html += ('</p>');
-    }
 
-    html += ('<p>点“确定”按钮,确认从回收站中恢复</p>');
+        html += ('<p>点“确定”按钮,确认从回收站中恢复</p>');
+    }
+    else{
+        html += ('<p>点“确定”按钮,确认清除数据</p>');
+    }
     return html;
 }
 
 //单价、费率文件恢复弹出框数据
-function v_getFiles(type, files){
+function v_getFiles(type, files, tenders, opr = null){
     let html = '';
+    function hasTheFile(tenders, fileId, fileType){
+        for(let tender of tenders){
+            let fileAttr = fileType === 'UnitPriceFile' ? 'unitPriceFile' : 'feeFile';
+            if(tender.data.property[fileAttr]['id'] == fileId){
+                return true;
+            }
+        }
+        return false;
+    }
     for(let i = 0, len = files.length; i < len; i ++){
         let recName = type === fileType.unitPriceFile ?  files[i].name + '单价文件' : files[i].name + '费率文件';
         let fileId = type === fileType.unitPriceFile ? files[i].id : files[i].ID;
         let recTimeA = formatDate(new Date(files[i].deleteInfo.deleteDateTime), 'yyyy-MM-dd');
         let recTimeB = formatDate(new Date(files[i].deleteInfo.deleteDateTime), 'HH:mm:ss');
-        html += '<tr><td>'+ recName +'</td><td>' + recTimeA + '<br>' + recTimeB + '</td><td><input name="fileItems" type="checkbox" fileId = "' + fileId + '" fileType = "' + type + '"></td></tr>';
+        if(opr && opr === 'delete'){
+            //还被引用,不可删除
+            if(hasTheFile(tenders, fileId, type)){
+                html += '<tr><td>'+ recName +'</td><td>' + recTimeA + '<br>' + recTimeB + '</td><td><input disabled name="fileItems" type="checkbox" fileId = "' + fileId + '" fileType = "' + type + '"></td></tr>';
+            }
+            else {
+                html += '<tr><td>'+ recName +'</td><td>' + recTimeA + '<br>' + recTimeB + '</td><td><input name="fileItems" type="checkbox" fileId = "' + fileId + '" fileType = "' + type + '"></td></tr>';
+            }
+        }
+        else{
+            html += '<tr><td>'+ recName +'</td><td>' + recTimeA + '<br>' + recTimeB + '</td><td><input name="fileItems" type="checkbox" fileId = "' + fileId + '" fileType = "' + type + '"></td></tr>';
+        }
     }
     return html;
 }
 
-//恢复单价、费率文件后前端显示变化
-function v_recFiles(project, fileIds, type){
+//恢复或清除单价、费率文件后前端显示变化
+function v_refreshFiles(project, fileIds, type){
     let projFiles;
     if(type === fileType.unitPriceFile){
         projFiles = project.data.unitPriceFiles;
@@ -767,14 +854,16 @@ function v_removeNode(node){
     }
 }
 
-function v_refreshNode(node){
-    if(deleted(node)){
-        delete node.data.deleteInfo;
+function v_refreshNode(node, recovery = true){
+    if(recovery){
+        if(deleted(node)){
+            delete node.data.deleteInfo;
+        }
     }
     gcTreeObj.refreshNodeData(node);
     let parent = node.parent || null;
     if(parent && parent.data !== undefined){
-        v_refreshNode(parent);
+        v_refreshNode(parent, recovery);
     }
 }
 
@@ -930,6 +1019,49 @@ function m_getRecDatas(oprNode){
     return rst;
 }
 
+//获取清除的额数据
+function m_getDelDatas(oprNode){
+    let rst = [];
+    if(!oprNode){
+        return rst;
+    }
+    function getChild(node){
+        rst.push({updateType: 'Project', ID: node.data.ID});
+        if(node.children.length > 0){
+            for(let child of node.children){
+                getChild(child);
+            }
+        }
+    }
+    getChild(oprNode);
+    //父节点只有一个单位工程,则清除此单位工程的时候,父节点也清除,(建设项目单价、费率文件存在时不清除)
+    if(oprNode.data.projType === projectType.tender){
+        let eng = oprNode.parent, proj = null;
+        if(eng && deleted(eng)){
+            proj = eng.parent;
+            rst.push({updateType: 'Project', ID: eng.data.ID});
+        }
+        if(proj && deleted(proj) && fileEmpty(proj)){
+            rst.push({updateType: 'Project', ID: proj.data.ID})
+        }
+    }
+    else if(oprNode.data.projType === projectType.engineering){
+        let proj = oprNode.parent;
+        if(proj && deleted(proj) && fileEmpty(proj)){
+            rst.push({updateType: 'Project', ID: proj.data.ID});
+        }
+    }
+    else if(oprNode.data.projType === projectType.project){
+        for(let uf of oprNode.data.unitPriceFiles){
+            rst.push({updateType: fileType.unitPriceFile, ID: uf.id});
+        }
+        for(let ff of oprNode.data.feeRateFiles){
+            rst.push({updateType: fileType.feeRateFile, ID: ff.ID});
+        }
+    }
+    return rst;
+}
+
 //获得勾选的单价、费率文件的id
 function m_getFilesObjs(nodes){
     let rst = [];
@@ -989,7 +1121,7 @@ function e_recFiles(btn){
         function caller(){
             //front
             if(recIds.length > 0){
-                v_recFiles(selected, recIds, type);
+                v_refreshFiles(selected, recIds, type);
                 if(deleted(selected)){
                     delete selected.data.deleteInfo;
                 }
@@ -1004,6 +1136,39 @@ function e_recFiles(btn){
     });
 }
 
+//点击单价、费率文件的清除操作(确认)
+function e_delFiles(btn){
+    btn.bind('click', function () {
+        let selected = gcTreeObj.tree.selected;//project
+        let delObjs = m_getFilesObjs($('[name = "fileItems"]:checked'));
+        let type = $('[name = "fileItems"]:checked').attr('fileType');
+        let delDatas = [];
+        let delIds = [];
+        for(let delObj of delObjs){
+            delIds.push(delObj.id);
+            delDatas.push({updateType: type, ID: delObj.id});
+        }
+        //此操作造成了建设项目的文件为空,则清除建设项目
+        if(fileWillEmpty(selected, delIds, type)){
+            delDatas.push({updateType: 'Project', ID: selected.data.ID});
+        }
+        if(delDatas.length > 0){
+            //backend
+            a_delGC(delDatas, caller);
+            //front
+            function caller(){
+                v_refreshFiles(selected, delIds, type);
+                if(fileEmpty(selected) && selected.children.length === 0){
+                    gcTreeObj.remove(selected);
+                }
+                else {
+                    gcTreeObj.refreshNodeData(selected);
+                }
+            }
+        }
+    });
+}
+
 //点击项目下的恢复操作(确认)
 function e_recProj(btn){
     btn.bind('click', function () {
@@ -1018,14 +1183,30 @@ function e_recProj(btn){
             let project = m_project(selected);
             if(project){
                 if(fileObj[fileType.unitPriceFile].length > 0){
-                    v_recFiles(project, fileObj[fileType.unitPriceFile], fileType.unitPriceFile);
+                    v_refreshFiles(project, fileObj[fileType.unitPriceFile], fileType.unitPriceFile);
                 }
                 if(fileObj[fileType.feeRateFile].length > 0){
-                    v_recFiles(project, fileObj[fileType.feeRateFile], fileType.feeRateFile);
+                    v_refreshFiles(project, fileObj[fileType.feeRateFile], fileType.feeRateFile);
                 }
             }
             v_removeNode(selected);
-            v_refreshNode(selected);
+            v_refreshNode(selected, true);
+        }
+    });
+}
+
+function e_delProj(btn){
+    btn.bind('click', function () {
+        let selected  = gcTreeObj.tree.selected;
+        //backend
+        let delDatas = m_getDelDatas(selected);
+        if(delDatas.length > 0){
+            a_delGC(delDatas, caller);
+        }
+        //front
+        function caller() {
+            v_removeNode(selected);
+            v_refreshNode(selected, false);
         }
     });
 }
@@ -1046,6 +1227,14 @@ function a_rec(nodes, callback){
     });
 }
 
+function a_delGC(delDatas, callback){
+    CommonAjax.post('/pm/api/delGC', {user_id: userID, delDatas: delDatas}, function(rstData){
+        if(callback){
+            callback();
+        }
+    })
+}
+
 //去除重名,回收站不处理重名,只保证恢复到项目管理中不出现重名
 function deWeightName(datas){
     let rst = [];
@@ -1114,6 +1303,26 @@ function fIsExist(files, id, type){
     return isExist;
 }
 
+//删除的文件是否会导致建设项目不再存有文件
+function fileWillEmpty(proj, delIds, type){
+    let ufs = proj.data.unitPriceFiles,
+        ffs = proj.data.feeRateFiles;
+    let theFiles = type === fileType.unitPriceFile ? ufs : ffs;
+        otherFiles = type === fileType.unitPriceFile ? ffs : ufs;
+    let uniqIds = Array.from(new Set(delIds));
+    if(theFiles.length === delIds.length){
+        for(let id of uniqIds){
+            if(!fIsExist(theFiles, id, type)){
+                return false;
+            }
+        }
+    }
+    if(otherFiles.length === 0){
+        return true;
+    }
+    return false;
+}
+
 function getRecFileObj(files){
     let rst = Object.create(null);
     let rst_UF = [], rst_FF = [];

+ 1 - 1
web/building_saas/pm/js/pm_newMain.js

@@ -362,7 +362,7 @@ const projTreeObj = {
                             $(".slide-sidebar").animate({width: "0"}).removeClass("open")// 关闭处理
                         }
                     });
-                }, 100);
+                }, 500);
             }
             //单项文件,进入造价书界面
             else if(node.data.projType === projectType.tender && withingClickArea()){