Просмотр исходного кода

feat: 设备购置树结构,工具栏等功能

zhangweicheng 4 лет назад
Родитель
Сommit
e4f28bd692

+ 2 - 0
modules/all_models/equipment_purchase.js

@@ -5,6 +5,8 @@ let mongoose = require('mongoose'),
 
 let equipment = {
     ID:String,
+    ParentID:String,
+    seq:Number,
     code:String,
     name:String,
     unit:String,

+ 1 - 1
modules/equipment_purchase/controllers/equipment_purchase_controller.js

@@ -14,7 +14,7 @@ let controller = {
     updateEquipments:async function(req){
         let data = req.body.data;
         data = JSON.parse(data);
-        return await equipment_purchase_facade.updateEquipments(data.projectID,data.updateData); 
+        return await equipment_purchase_facade.updateEquipments(data.projectID,data.updateData,data.total); 
     }
 }
 

+ 11 - 6
modules/equipment_purchase/facade/equipment_purchase_facade.js

@@ -27,14 +27,19 @@ async function insertData (projectID,data){
     return data
 }
 
-async function updateEquipments (projectID,updateData){
+async function updateEquipments (projectID,updateData,total){
     let tasks = [];
+    if(total !== undefined || total !== null) tasks.push({updateOne :{filter:{projectID},update:{$set:{total:total}}}});
     for(let data of updateData){
-        let task = {updateOne : {
-            filter:{projectID,'equipments.ID':data.ID},
-            update:{$set:getPreUpdate('equipments.$',data.doc)}
-        }}
-        tasks.push(task)
+        if(data.type === 'insert' ){
+            tasks.push({updateOne:{ filter:{projectID},update:{'$push':{equipments:{ $each: data.documents }}}}})
+        }else {
+            let task = {updateOne : {
+                filter:{projectID,'equipments.ID':data.ID},
+                update:{$set:getPreUpdate('equipments.$',data.doc)}
+            }}
+            tasks.push(task)
+        }   
     }
     if(tasks.length > 0) await equipmentPurchaseModel.bulkWrite(tasks);
     return updateData

+ 1 - 1
web/building_saas/js/global.js

@@ -24,7 +24,7 @@ function autoFlashHeight(){
     $(".main-data-full-fl").height($(window).height()-headerHeight-toolsbarHeight-37);
     $(".main-data-full-feeRate").height($(window).height()-headerHeight-78);
     $(".main-data-full-tender").height($(window).height()-headerHeight-btntoolsbarHeight-10-30);
-    $(".main-data-full-equipment").height($(window).height()-headerHeight);
+    $(".main-data-full-equipment").height($(window).height()-headerHeight-30);
     $(".main-data-not").height($(window).height()-headerHeight-1);
     $(".main-data-side-search").height($(window).height()-headerHeight-toolsbarHeight-64);
     $(".side-content").height($(window).height()-headerHeight );

+ 12 - 0
web/building_saas/main/html/equipment_purchase.html

@@ -1,6 +1,18 @@
 
 <div class="container-fluid">
     <div class="row">
+        <div class="toolsbar px-1 d-flex " style="width: 100%;height: 30px;">
+          <a href="javascript:void(0)" class="btn btn-light btn-sm" id="equipment_upLevel" data-toggle="tooltip"
+            data-placement="bottom" data-original-title="升级"><i class="fa fa-arrow-left" aria-hidden="true"></i></a>
+          <a href="javascript:void(0)" class="btn btn-light btn-sm" id="equipment_downLevel" data-toggle="tooltip"
+            data-placement="bottom" data-original-title="降级"><i class="fa fa-arrow-right"
+              aria-hidden="true"></i></a>
+          <a href="javascript:void(0)" class="btn btn-light btn-sm" id="equipment_upMove" data-toggle="tooltip"
+            data-placement="bottom" data-original-title="上移"><i class="fa fa-arrow-up" aria-hidden="true"></i></a>
+          <a href="javascript:void(0)" class="btn btn-light btn-sm" id="equipment_downMove" data-toggle="tooltip"
+            data-placement="bottom" data-original-title="下移"><i class="fa fa-arrow-down" aria-hidden="true"></i></a>
+          <label class="mx-2 form-inline py-1">设备购置费合计: <label id='equipment_total'></label></label>
+        </div>
         <div class="col-lg-12 p-0">
             <div class="main-data-full-equipment" id="equipmentSpread">
             </div>

+ 285 - 47
web/building_saas/main/js/views/equipment_purchase_view.js

@@ -2,22 +2,24 @@
 let unitOptions = ['m', 'm2', 'm3', 'km', 't', 'kg', '台班', '工日', '昼夜', '元', '项', '处', '个', '件',
 '根', '组', '系统', '台', '套', '株', '丛', '缸', '支', '只', '块', '座', '对', '份', '樘', '攒', '榀']
 let equipmentPurchaseObj  = {
+    IDMap:{},
+    parentMap:{},
     setting:{
         header: [
-            {headerName: "编号", headerWidth: 160, dataCode: "code", dataType: "String",formatter: "@"},
-            {headerName: "设备名称", headerWidth: 200, dataCode: "name", dataType: "String"},
-            {headerName: "设备价格-设备原价", headerWidth: 160, dataCode: "originalPrice", hAlign: "right", dataType: "Number",validator:'number'},
-            {headerName: "设备运杂费", headerWidth: 160, dataCode: "freight", hAlign: "right", dataType: "Number",validator:'number'},
-            {headerName: "备品备件费", headerWidth: 160, dataCode: "sparePartCost", hAlign: "right", dataType: "Number",validator:'number'},
-            {headerName: "单价", headerWidth: 160, dataCode: "unitPrice", hAlign: "right", dataType: "Number",validator:'number'},
-            {headerName: "单位", headerWidth: 60, dataCode: "unit",  dataType: "String",hAlign: "center",cellType:'comboBox',editable:true,options:unitOptions},
-            {headerName: "数量", headerWidth: 160, dataCode: "quantity", hAlign: "right", dataType: "Number",validator:'number'},
-            {headerName: "金额", headerWidth: 160, dataCode: "totalPrice", hAlign: "right", dataType: "Number"},
+            {headerName: "编号", headerWidth: 160, dataCode: "code", dataType: "String",formatter: "@",spanRows: [2]},
+            {headerName: "设备名称", headerWidth: 200, dataCode: "name", dataType: "String",spanRows: [2]},
+            {headerName: "单位", headerWidth: 60, dataCode: "unit",  dataType: "String",hAlign: "center",cellType:'comboBox',editable:true,options:unitOptions,spanRows: [2]},
+            {headerName: ["设备价格","设备原价"], headerWidth: 160, dataCode: "originalPrice", hAlign: "right", dataType: "Number",validator:'number',spanCols: [4,1]},
+            {headerName: ["","设备运杂费"], headerWidth: 160, dataCode: "freight", hAlign: "right", dataType: "Number",validator:'number',spanCols: [0,1]},
+            {headerName: ["","备品备件费"], headerWidth: 160, dataCode: "sparePartCost", hAlign: "right", dataType: "Number",validator:'number',spanCols: [0,1]},
+            {headerName: ["","单价"], headerWidth: 160, dataCode: "unitPrice", hAlign: "right", dataType: "Number",validator:'number',spanCols: [0,1]},
+            {headerName: "数量", headerWidth: 160, dataCode: "quantity", hAlign: "right", dataType: "Number",validator:'number',spanRows: [2]},
+            {headerName: "合价", headerWidth: 160, dataCode: "totalPrice", hAlign: "right", dataType: "Number",spanRows: [2]},
         ],
+        headRows:2,
         view: {
-            lockColumns: ["totalPrice"],
+            lockColumns: ["totalPrice",'unitPrice'],
             rowHeaderWidth:40,
-            colHeaderHeight:35
         }
     
     },
@@ -32,6 +34,7 @@ let equipmentPurchaseObj  = {
             this.sheet.bind(GC.Spread.Sheets.Events.RangeChanged, this.onSheetRangeChange);
             this.sheet.bind(GC.Spread.Sheets.Events.SelectionChanged, function (e,args) {
                 args.sheet.repaint();
+                equipmentPurchaseObj.checkBtn();
             });
             if (projectReadOnly) {
                 sheetCommonObj.disableSpread(this.spread);
@@ -40,14 +43,110 @@ let equipmentPurchaseObj  = {
               }
         }
     },
+    checkBtn:function(){
+        let me = equipmentPurchaseObj;
+        let selected = me.getSelected();
+        let preNode = me.getPreNode(selected);
+        let afterNode = me.getAfterNode(selected);
+        //工具栏按钮的有效性
+        me.validateBtn($('#equipment_upMove'),preNode);
+        me.validateBtn($('#equipment_downMove'),afterNode);
+        me.validateBtn($('#equipment_upLevel'),selected && selected.ParentID !=='-1');
+        me.validateBtn($('#equipment_downLevel'),preNode);
+       
+    },
+
+    validateBtn:function(btn,validate){
+        if(validate){
+            btn.removeClass('disabled');
+        }else{
+            btn.addClass('disabled');
+        }
+    },
+    getTreeData:function(){
+        let treeData = [];
+        let roots = this.parentMap['-1'];
+        let me = this;
+        getChildren(roots,treeData);
+        return treeData;
+        
+        function getChildren(nodes,data){
+           if(nodes){
+               for(let n of nodes){
+                data.push(n);
+                getChildren(me.parentMap[n.ID],data)
+               }
+           } 
+        }
+    },
+    getSelected:function(){
+        let sel = this.sheet.getSelections()[0];
+        let row = sel.row == -1 || sel.row == "" ? 0 : sel.row;
+        if(this.data && this.data.length>0){
+            return this.data[row];
+        }
+        return null;
+    },
+    getParentNode:function(node){
+       if(node.ParentID === '-1') return null; 
+       return this.IDMap[node.ParentID]; 
+    },
+    //取前兄弟节点
+    getPreNode:function(node){
+        if(node){
+            let nodes = this.parentMap[node.ParentID];
+            let index = nodes.indexOf(node);
+            return nodes[index-1]
+        }
+       return null;
+    },
+    //取后兄弟节点
+    getAfterNode:function(node){
+        if(node){
+            let nodes = this.parentMap[node.ParentID];
+            let index = nodes.indexOf(node);
+            return nodes[index+1]
+        }
+       return null;
+    },
+    //取所有后兄弟节点
+    getAllAfterNodes:function(node){
+       let brothers = this.parentMap[node.ParentID];
+       let index = brothers.indexOf(node);
+       if(brothers.length >= index + 2){
+        return brothers.slice(index+1);
+       }
+       return [];
+
+    },
+    //插入为最后一个子节点的序号
+    getLastChildrenSeq:function(node){
+        let seq = 1;
+        let children = this.parentMap[node.ID];
+        if(children && children.length > 0){
+            return children[children.length-1].seq +1
+        }
+        return seq;
+    },
     showData:function(){
         let equipment_purchase = projectObj.project.equipment_purchase;
-        this.data = equipment_purchase.datas.equipments;
-        _.sortBy(this.data,['code']);
-        sheetCommonObj.showData(this.sheet, this.setting,this.data);
-        this.sheet.setRowCount(this.data.length);
-    },
+        this.sourceData = equipment_purchase.datas;
+        let data = this.sourceData.equipments;
+        this.IDMap = {};
+        this.parentMap = {};
+        data = _.sortBy(data,'seq');
+        for(let d of data){
+            let node = ({...d,collapsed:false})
+            this.IDMap[node.ID] = node;
+            this.parentMap[node.ParentID] ?this.parentMap[node.ParentID].push(node):this.parentMap[node.ParentID]=[node];
+        }
+        let treeData = this.getTreeData();
 
+        this.data = treeData;
+        sheetCommonObj.showTreeData(this.sheet, this.setting,treeData);
+        this.checkBtn();
+        $('#equipment_total').text(this.sourceData.total);
+    },
     onValueChange:function (e,info) {
         let me = equipmentPurchaseObj,row = info.row, col = info.col;
         let dataCode = me.setting.header[col].dataCode;
@@ -59,31 +158,65 @@ let equipmentPurchaseObj  = {
             return me.showData();
         }
         let data = {doc:{},ID:equipment.ID};
-        if(dataCode == 'quantity' || dataCode == 'unitPrice'){
-            me.calcTotalPrice(value,dataCode,data.doc,equipment);
+        if(dataCode == 'quantity' || dataCode == 'originalPrice'|| dataCode == 'freight'|| dataCode == 'sparePartCost'){
+            value = me.calcTotalPrice(value,dataCode,data.doc,equipment);
         }
         if(equipment[dataCode] == value) return me.showData();
         data.doc[dataCode] = value;
         me.updateEquipments([data]);
     },
-    calcTotalPrice:function(newValue,dataCode,doc,equipment){
-        let unitPrice = equipment.unitPrice?scMathUtil.roundForObj(equipment.unitPrice,getDecimal('glj.unitPrice')):0;
-        let quantity = equipment.quantity?scMathUtil.roundForObj(equipment.quantity,getDecimal('glj.quantity')):0;
-        let quantity = equipment.quantity?scMathUtil.roundForObj(equipment.quantity,getDecimal('glj.quantity')):0;
+    calcTotalPrice:function(newValue=0,dataCode,doc,equipment){   
+        //设备原价
+        let originalPrice = equipment.originalPrice?scMathUtil.roundForObj(equipment.originalPrice,getDecimal('glj.unitPrice')):0;
+        //设备运杂费
+        let freight = equipment.freight?scMathUtil.roundForObj(equipment.freight,getDecimal('glj.unitPrice')):0;
+        //备品备件费
+        let sparePartCost = equipment.sparePartCost?scMathUtil.roundForObj(equipment.sparePartCost,getDecimal('glj.quantity')):0;
         let quantity = equipment.quantity?scMathUtil.roundForObj(equipment.quantity,getDecimal('glj.quantity')):0;
-        if(newValue){
-            if(gljUtil.isDef(doc.unitPrice)) unitPrice = doc.unitPrice;
-            if(gljUtil.isDef(doc.quantity)) quantity = doc.quantity;
-            if(dataCode === 'quantity') {
-                newValue =  scMathUtil.roundForObj(newValue,getDecimal('glj.quantity'));
-                quantity = newValue;
-            }
-            if(dataCode === 'unitPrice') {
-                newValue =  scMathUtil.roundForObj(newValue,getDecimal('glj.unitPrice'));
-                unitPrice = newValue;
-            }
-            doc.totalPrice = scMathUtil.roundForObj(quantity * unitPrice,getDecimal('glj.unitPrice'));
+        
+        let unitPrice = 0;
+
+        if(gljUtil.isDef(doc.originalPrice)) originalPrice = doc.originalPrice;
+        if(gljUtil.isDef(doc.freight)) freight = doc.freight;
+        if(gljUtil.isDef(doc.sparePartCost)) sparePartCost = doc.sparePartCost;
+        if(gljUtil.isDef(doc.quantity)) quantity = doc.quantity;
+        if(dataCode === 'quantity') {
+            newValue =  scMathUtil.roundForObj(newValue,getDecimal('glj.quantity'));
+            quantity = newValue;
         }
+        if(dataCode === 'originalPrice') {
+            newValue =  scMathUtil.roundForObj(newValue,getDecimal('glj.unitPrice'));
+            originalPrice = newValue;
+        }
+        if(dataCode === 'freight') {
+            newValue =  scMathUtil.roundForObj(newValue,getDecimal('glj.unitPrice'));
+            freight = newValue;
+        }
+        if(dataCode === 'sparePartCost') {
+            newValue =  scMathUtil.roundForObj(newValue,getDecimal('glj.unitPrice'));
+            sparePartCost = newValue;
+        }
+        
+        unitPrice = scMathUtil.roundForObj(originalPrice + freight,getDecimal('glj.unitPrice'));
+        unitPrice = scMathUtil.roundForObj(unitPrice + sparePartCost,getDecimal('glj.unitPrice'));
+        doc.unitPrice = unitPrice;
+        doc.totalPrice = scMathUtil.roundForObj(quantity * unitPrice,getDecimal('glj.unitPrice'));
+        return newValue;
+    },
+    //计算序列号,返回要改变的兄弟节点数据
+    calcSeq:function(ParentID,seq){
+      let data = [];  
+      let nodes = this.parentMap[ParentID];
+      let temSeq = seq+1;
+      if(nodes && nodes.length > 0){
+        for(let n of nodes){
+           if(n.seq >= seq){
+             data.push({doc:{seq:temSeq},ID:n.ID}) 
+             temSeq+=1;
+           } 
+        }
+      }
+        return data;
     },
     onSheetRangeChange:function(e,args){
         let updateMap = {};
@@ -99,8 +232,8 @@ let equipmentPurchaseObj  = {
                 return ;
             }
             let tem = updateMap[equipment.ID]?updateMap[equipment.ID]:{};
-            if(dataCode == 'quantity' || dataCode == 'unitPrice'){
-                me.calcTotalPrice(value,dataCode,tem,equipment);
+            if(dataCode == 'quantity' || dataCode == 'originalPrice'|| dataCode == 'freight'|| dataCode == 'sparePartCost'){
+                value = me.calcTotalPrice(value,dataCode,tem,equipment);
             } 
             tem[dataCode] = value;
             updateMap[equipment.ID] = tem;
@@ -111,20 +244,47 @@ let equipmentPurchaseObj  = {
         }
         if(updateData.length > 0)  me.updateEquipments(updateData);
     },
-    newEquipment:function(){
-        return {ID:uuid.v1()}
+    newEquipment:function(ParentID='-1',seq=0){
+        return {ID:uuid.v1(),ParentID,seq}
+    },
+    sumTotal: function(updateData){
+        let dataMap = _.indexBy(updateData, 'ID');
+        let total = 0;
+        for(let d of  this.data){
+            let totalPrice = d.totalPrice?scMathUtil.roundForObj(d.totalPrice,getDecimal('glj.unitPrice')):0;
+            let data = dataMap[d.ID];
+            if(data && gljUtil.isDef(data.doc.totalPrice))totalPrice = data.doc.totalPrice;
+            total =scMathUtil.roundForObj(total + totalPrice,getDecimal('glj.unitPrice')) 
+        }
+        return total;
+    },
+    //上移
+    moveUp:async function(node){
+       let preNode = this.getPreNode(node); 
+       if(preNode){
+        let updateData = [];
+         updateData.push({doc:{seq:node.seq},ID:preNode.ID});
+         updateData.push({doc:{seq:preNode.seq},ID:node.ID});
+        await this.updateEquipments(updateData);
+       }
     },
     updateEquipments:async function(updateData){
         try {
             $.bootstrapLoading.start();
             let projectID = projectObj.project.ID();
-            await ajaxPost('/equipmentPurchase/updateEquipments', { projectID, updateData });
+            let total = this.sumTotal(updateData);
+            await ajaxPost('/equipmentPurchase/updateEquipments', { projectID, updateData,total });
             for(let data of updateData){
-                let equipment = _.find(this.data,{ID:data.ID});
-                if(equipment){
-                    Object.assign(equipment,data.doc);
+                if(data.type === 'insert'){
+                    this.sourceData.equipments.push(...data.documents);  
+                }else{
+                    let equipment = _.find(this.sourceData.equipments,{ID:data.ID});
+                    if(equipment){
+                        Object.assign(equipment,data.doc);
+                    }
                 }
             }
+            projectObj.project.equipment_purchase.datas.total = total;
         } catch (error) {
             alert('更新失败,请重试');
         }
@@ -136,7 +296,7 @@ let equipmentPurchaseObj  = {
             $.bootstrapLoading.start();
             let projectID = projectObj.project.ID();
             await ajaxPost('/equipmentPurchase/insertData', { projectID, equipments });
-            this.data.push(...equipments)  
+            this.sourceData.equipments.push(...equipments)  
             this.showData();
         } catch (error) {
             alert('插入失败,请重试');
@@ -147,7 +307,7 @@ let equipmentPurchaseObj  = {
         try {
             let projectID = projectObj.project.ID();
             await ajaxPost('/equipmentPurchase/deleteEquipment', { projectID, ID });
-            _.remove(this.data,{ID});
+            _.remove( this.sourceData.equipments,{ID});
             this.showData();
         } catch (error) {
             alert('删除失败,请重试');
@@ -162,10 +322,27 @@ let equipmentPurchaseObj  = {
                 return;
             }  
             const newData = [];
+            let row = me.rightClickTarget.row;
+            let seq = 0;
+            let ParentID = '-1';
+            let brotherNodes = [];
+            if(row == undefined){//没有选中节点的情况,添加到最后
+                brotherNodes = me.parentMap['-1'];
+                if(brotherNodes && brotherNodes.length > 0){
+                    seq = brotherNodes[brotherNodes.length -1].seq;   
+                } 
+            }else{
+                let node = me.data[row];//选中节点时插入为选中的下一行
+                seq = node.seq;
+                ParentID = node.ParentID;
+            }
             for (let i = 0; i < number; i++) {
-                newData.push(me.newEquipment());
+                seq+=1;
+                newData.push(me.newEquipment(ParentID,seq));
             }
-            me.insertEquipments(newData)   
+            let updateData = me.calcSeq(ParentID,seq);
+            updateData.push({documents:newData,type:'insert'});
+            me.updateEquipments(updateData)   
         });
     },
 
@@ -173,8 +350,9 @@ let equipmentPurchaseObj  = {
         let me = this;
         $.contextMenu({
           selector: '#equipmentSpread',
-          build: function ($trigger, e) {
+          build: function ($trigger, e) { 
             me.rightClickTarget = SheetDataHelper.safeRightClickSelection($trigger, e, me.spread);
+            me.checkBtn();
             return me.rightClickTarget.hitTestType === GC.Spread.Sheets.SheetArea.viewport ||
               me.rightClickTarget.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
           },
@@ -212,4 +390,64 @@ $(function () {
         equipmentPurchaseObj.initSpread();
         equipmentPurchaseObj.showData();
     })
+
+    //降级
+    $('#equipment_downLevel').click(function(){
+        let me = equipmentPurchaseObj;
+        let selected = me.getSelected();
+        if(selected){
+            let preNode = me.getPreNode(selected);
+            if(preNode){
+                let seq = me.getLastChildrenSeq(preNode);
+                me.updateEquipments([{doc:{ParentID:preNode.ID,seq},ID:selected.ID}])
+            }
+        }
+    })
+
+     //升级  - 后兄弟节点变成子节点
+     $('#equipment_upLevel').click(function(){
+        let me = equipmentPurchaseObj;
+        let selected = me.getSelected();
+        if(selected){
+            let parentNode = me.getParentNode(selected);
+            if(parentNode){
+                let seq = parentNode.seq+1;
+                let updateData =  me.calcSeq(parentNode.ParentID,seq);
+                updateData.push({doc:{ParentID:parentNode.ParentID,seq},ID:selected.ID})
+                let brothers = me.getAllAfterNodes(selected);
+                let subSeq = 0;
+                //后兄弟节点变成子节点
+                for(let b of brothers){
+                    subSeq+=1;
+                    updateData.push({doc:{ParentID:selected.ID,seq:subSeq},ID:b.ID})
+                }
+                me.updateEquipments(updateData)
+            }
+        }
+    })
+    
+    //上移
+    $('#equipment_upMove').click(async function (){
+        let me = equipmentPurchaseObj;
+        let selected = me.getSelected();
+        if(selected){
+           let sel = me.sheet.getSelections()[0];
+           await me.moveUp(selected);
+           me.sheet.setSelection(sel.row -1 , sel.col, sel.rowCount, sel.colCount);
+        }
+    })
+     //下移
+     $('#equipment_downMove').click(async function(){
+        let me = equipmentPurchaseObj;
+        let selected = me.getSelected();
+        if(selected){
+            let sel = me.sheet.getSelections()[0];
+           let node = me.getAfterNode(selected);
+           if(node){
+            await me.moveUp(node);
+            me.sheet.setSelection(sel.row +1 , sel.col, sel.rowCount, sel.colCount);
+           }
+           
+        }
+    })
 })