浏览代码

Merge branch 'budget' of http://192.168.1.41:3000/SmartCost/ConstructionCost into budget

chenshilong 4 年之前
父节点
当前提交
db31737634

+ 7 - 1
public/common_util.js

@@ -142,6 +142,11 @@ function deleteEmptyObject(arr) {
         return null;
     };
 
+    // 获取造价书树或概算汇总树
+    const getActiveTree = () => {
+        return $('#tab-budget-summary').hasClass('active') ? budgetSummaryObj.getTree() : projectObj.project.mainTree;
+    }
+
     return {
         isDef,
         isEmptyVal,
@@ -151,6 +156,7 @@ function deleteEmptyObject(arr) {
         getSortedTreeData,
         isNotEmptyObject,
         handleFullscreen,
-        getEngineeringFeeType
+        getEngineeringFeeType,
+        getActiveTree,
     };
 });

+ 148 - 17
web/building_saas/budget-summary/js/budgetSummarySheet.js

@@ -6,6 +6,8 @@ const budgetSummaryObj = (() => {
 
   // 原始数据
   let rawData = [];
+  // ID与原始数据映射表(主要是恢复用)
+  const orgMap = {};
   // 建设其他费表格对象
   let spread = null;
   // 建设其他费树
@@ -56,21 +58,63 @@ const budgetSummaryObj = (() => {
     return validator[item.data.type || 'text'];
   }
 
+  // 单元格文本转换处理
+  const textFactory = {
+    calcBase(node) {
+      if (node.data.calcBase && node.data.calcBase !== "") {
+        return cbParser.toFExpr(node.data.calcBase);
+      }
+    },
+    'feesIndex.common.unitFee': (node) => {
+      return _.get(node, 'data.feesIndex.common.unitFee', '') || '';
+    },
+    'feesIndex.common.totalFee': (node) => {
+      return _.get(node, 'data.feesIndex.common.totalFee', '') || '';
+    },
+    'feesIndex.building.totalFee': (node) => {
+      return _.get(node, 'data.feesIndex.building.totalFee', '') || '';
+    },
+    'feesIndex.installation.totalFee': (node) => {
+      return _.get(node, 'data.feesIndex.installation.totalFee', '') || '';
+    },
+    'feesIndex.equipment.totalFee': (node) => {
+      return _.get(node, 'data.feesIndex.equipment.totalFee', '') || '';
+    },
+    'feesIndex.other.totalFee': (node) => {
+      return _.get(node, 'data.feesIndex.other.totalFee', '') || '';
+    },
+  };
+
   /* 表格事件相关 */
-  // 恢复数据
-  const recover = (sheet, changedCells) => {
+  // 根据节点数据刷新表格数据
+  const refreshData = (sheet, changedCells) => {
     if (!tree) {
       return;
     }
-    changedCells.forEach(({ row, col }) => {
-      const node = tree.items[row];
-      const field = getFieldByCol(col);
-      if (!field || !node) {
-        return;
+    TREE_SHEET_HELPER.massOperationSheet(sheet, () => {
+      changedCells.forEach(({ row, col }) => {
+        const node = tree.items[row];
+        const field = getFieldByCol(col);
+        if (!field || !node) {
+          return;
+        }
+        const textFunc = textFactory[field];
+        const val = textFunc ? textFunc(node) : node.data[field];
+        sheet.setValue(row, col, val);
+      });
+    });
+  }
+
+  // 刷新整个表格
+  const refreshAll = (sheet) => {
+    const changedCells = [];
+    const colCount = budgetSummaryTreeSetting.cols.length;
+    for (let row = 0; row < tree.items.length; row++) {
+      for (let col = 0; col < colCount; col++) {
+        changedCells.push({ row, col })
       }
-      const orgVal = node.data[field];
-      sheet.setValue(row, col, orgVal);
-    })
+    }
+    refreshData(sheet, changedCells);
   }
 
   // 更新数据
@@ -90,9 +134,10 @@ const budgetSummaryObj = (() => {
     });
     // 验证不通过,恢复
     if (!isValid) {
-      recover(sheet, changedCells);
+      refreshData(sheet, changedCells);
     }
-    console.log(changedCells);
+    let needCalc = false;
+    const nodes = [];
     try {
       $.bootstrapLoading.start();
       const IDMap = {};
@@ -102,21 +147,92 @@ const budgetSummaryObj = (() => {
         if (!node) {
           return;
         }
+        if (!nodes.find(n => n.data.ID !== node.data.ID)) {
+          nodes.push(node);
+        }
         const field = getFieldByCol(col);
+        const value = sheet.getValue(row, col) || '';
         const data = (IDMap[node.data.ID] || (IDMap[node.data.ID] = {}));
-        data[field] = sheet.getValue(row, col);
+        if (['feesIndex.common.unitFee'].includes(field)) {
+          const fees = node.data.fees || [];
+          const feeItem = fees.find(item => item.fieldName === 'common');
+          if (feeItem) {
+            feeItem.unitFee = value;
+          } else {
+            fees.push({ fieldName: 'common', totalFee: 0, unitFee: +value });
+          }
+          data[field] = fees;
+          node.data[field] = fees;
+          node.data.feesIndex = getFeeIndex(node.data.fees);
+        } else {
+          data[field] = value;
+          node.data[field] = value;
+        }
+        if (field === 'calcBase') {
+          node.data.userCalcBase = value;
+          projectObj.project.calcBase.calculate(node, null, false);
+          if (!projectObj.project.calcBase.success) {
+            throw projectObj.project.calcBase.errMsg;
+          } else if (isEmptyVal(value)) {
+            // 删除清单基数,单价要清空
+            calcTools.setFieldValue(node, 'feesIndex.common.unitFee', 0);
+          }
+          data.calcBase = node.data.calcBase;
+          data.calcBaseValue = node.data.calcBaseValue;
+          data.tenderCalcBaseValue = node.data.tenderCalcBaseValue;
+        }
+        if (['quantity', 'feesIndex.common.unitFee', 'calcBase', 'feeRate'].includes(field)) {
+          needCalc = true;
+        }
+      });
+      // 重算节点
+      const dataArr = [];
+      if (needCalc && nodes.length) {
+        const changedNodes = projectObj.project.calcProgram.calcNodes(nodes, false, tree);
+        for (const node of changedNodes) {
+          nodes.push(node);
+          if (node.changed) {
+            const data = calcTools.cutNodeForSave(node);
+            dataArr.push(data);
+          }
+        }
+      }
+      dataArr.forEach(item => {
+        delete item.projectID;
+        const data = IDMap[item.ID];
+        if (data) {
+          Object.assign(data, item);
+        } else {
+          IDMap[item.ID] = item;
+        }
       });
+      // 保存节点
       Object
         .entries(IDMap)
         .forEach(([ID, data]) => {
           bulkData.push({ type: 'update', data: { ID, ...data } });
         });
       await bulkOperation(bulkData);
-      bulkData.forEach(item => {
-        const node = tree.findNode(item.data.ID);
-        Object.assign(node.data, item.data);
-      });
+      Object
+        .entries(IDMap)
+        .forEach(([ID, data]) => {
+          const node = tree.findNode(ID);
+          if (node) {
+            Object.assign(node.data, data);
+            node.data.feesIndex = getFeeIndex(node.data.fees);
+            orgMap[ID] = _.cloneDeep(node.data);
+          }
+        });
+      refreshAll(sheet);
     } catch (err) {
+      console.log(err);
+      nodes.forEach(node => {
+        const orgItem = orgMap[node.data.ID];
+        if (orgItem) {
+          Object.assign(node.data, orgItem);
+        }
+      });
+      refreshData(sheet, changedCells);
       alert(err);
     } finally {
       $.bootstrapLoading.end();
@@ -270,6 +386,11 @@ const budgetSummaryObj = (() => {
           const cellType = cellTypeFunc(node);
           sheet.getCell(row, col).cellType(cellType);
         }
+        // 单元格文本转换
+        const textFunc = textFactory[field];
+        if (textFunc) {
+          sheet.setValue(row, col, textFunc(node));
+        }
       });
     }
   }
@@ -321,13 +442,18 @@ const budgetSummaryObj = (() => {
     // 更新数据
     updateData.forEach(item => {
       if (item.type === 'new') {
+        orgMap[item.data.ID] = _.cloneDeep(item.data);
         rawData.push(item.data)
       } else if (item.type === 'update') {
+        if (orgMap[item.data.ID]) {
+          Object.assign(orgMap[item.data.ID], item.data);
+        }
         const node = tree.findNode(item.data.ID);
         if (node) {
           Object.assign(node.data, item.data);
         }
       } else {
+        delete orgMap[item.data.ID];
         const removeIndex = rawData.findIndex(d => d.ID === item.data.ID);
         if (removeIndex > -1) {
           rawData.splice(removeIndex, 1);
@@ -598,6 +724,9 @@ const budgetSummaryObj = (() => {
       });
       const spread = initSpread();
       const sheet = spread.getSheet(0);
+      rawData.forEach(item => {
+        orgMap[item.ID] = _.cloneDeep(item);
+      });
       initTree(rawData, sheet, budgetSummaryTreeSetting);
       calcBase.initBudget();
     } catch (err) {
@@ -685,7 +814,9 @@ const budgetSummaryObj = (() => {
   // 对外暴露
   return {
     getTree: () => tree,
+    getSheet: () => spread.getSheet(0),
     calcSetting,
+    edit,
   };
 
 })();

+ 42 - 10
web/building_saas/main/js/models/calc_base.js

@@ -61,8 +61,8 @@ let cbTools = {
     },
     //通过ID获取节点
     getNodeByID: function (ID) {
-        const nodes = $('#tab-budget-summary').hasClass('active') ? budgetSummaryObj.getTree().nodes : calcBase.project.mainTree.nodes;
-        return this.isDef(nodes['id_' + ID]) ? nodes['id_' + ID] : null;
+        const tree = commonUtil.getActiveTree();
+        return this.isDef(tree.nodes['id_' + ID]) ? tree.nodes['id_' + ID] : null;
     },
     //获取该节点所有父节点
     getParents: function (node) {
@@ -365,6 +365,7 @@ let cbTools = {
     },
     //获取清单(有基数计算)引用了的其他清单,(循环引用栈中的一块)
     getStackBlock: function (billID) {
+        const tree = commonUtil.getActiveTree();
         let tempBases = [], block = [];//存引用的清单ID
         let node = getBill(billID);
         if (!node) {
@@ -419,7 +420,7 @@ let cbTools = {
             }
         }
         function getBill(ID) {
-            let nodes = calcBase.project.mainTree.nodes;
+            let nodes = tree.nodes;
             let node = nodes['id_' + ID];
             if (cbTools.isDef(node) && node.sourceType === calcBase.project.Bills.getSourceType()) {
                 return node;
@@ -1177,6 +1178,14 @@ let baseFigureTemplate = {
     SJF: function () {
         return cbTools.getBillsFee(fixedFlag.DESIGN_FEE, 'common', 'totalFee');
     },
+    // 预备费: 取预备费行的金额
+    YBF: function () {
+        return cbTools.getBillsFee(fixedFlag.BUDGET_RESERVE, 'common', 'totalFee');
+    },
+    // 专项费用: 取专项费用行的金额
+    ZXFY: function () {
+        return cbTools.getBillsFee(fixedFlag.CONSTRUCTION_SPECIAL_FEE, 'common', 'totalFee');
+    },
     // 工程建设其他费用: 取工程建设其他费用的金额
     GCJSQTFY: function () {
         return cbTools.getBillsFee(fixedFlag.CONSTRUCTION_OTHER_FEE, 'common', 'totalFee');
@@ -1306,6 +1315,18 @@ const budgetFigureMap = {
         filter: [fixedFlag.DESIGN_COUNSEL_FEE],
         pick: true,
     },
+    '预备费': {
+        base: 'YBF',
+        fixedFlag: fixedFlag.BUDGET_RESERVE,
+        filter: [fixedFlag.BUDGET_RESERVE],
+        pick: false,
+    },
+    '专项费用': {
+        base: 'ZXFY',
+        fixedFlag: fixedFlag.CONSTRUCTION_SPECIAL_FEE,
+        filter: [fixedFlag.CONSTRUCTION_SPECIAL_FEE],
+        pick: false,
+    },
     '工程建设其他费用': {
         base: 'GCJSQTFY',
         fixedFlag: fixedFlag.CONSTRUCTION_OTHER_FEE,
@@ -1491,10 +1512,16 @@ let cbAnalyzer = {
         if (!this.arithmeticLegal(exp)) {
             throw '表达式含有无效字符';
         }
-        if (!this.baseLegal(cbTools.getFigure(node), exp)) {
-            throw '清单基数不合法';
+        if (node.tree === projectObj.project.mainTree) {
+            if (!this.baseLegal(cbTools.getFigure(node), exp)) {
+                throw '清单基数不合法';
+            }
+        } else if (node.tree === budgetSummaryObj.getTree()) {
+            if (!this.baseLegal(cbTools.getValidFigures(node), exp)) {
+                throw '清单基数不合法';
+            }
         }
-        if (!this.fLegal(calcBase.project.mainTree.items, exp)) {
+        if (!this.fLegal(node.tree.items, exp)) {
             throw '行引用不合法';
         }
         //转换成ID引用
@@ -1621,13 +1648,14 @@ let cbParser = {
     },
     //将行引用转换成ID引用
     toIDExpr: function (exp) {
+        const tree = commonUtil.getActiveTree();
         let exps = [];
         //获得行引用
         let fArr = this.getFArr(exp);
         for (let i = 0, len = fArr.length; i < len; i++) {
             let r = this.getXNum([fArr[i]]);
             if (r.length === 1) {
-                let node = cbTools.getBillByRow(calcBase.project.mainTree.items, r[0] - 1);
+                let node = cbTools.getBillByRow(tree.items, r[0] - 1);
                 if (cbTools.isUnDef(node)) {
                     //continue;
                     calcBase.errMsg = '行引用错误';
@@ -1647,13 +1675,14 @@ let cbParser = {
     },
     //将ID引用转换成行引用
     toFExpr: function (exp) {
+        const tree = commonUtil.getActiveTree();
         let exps = [];
         //获得ID引用
         let fidArr = this.getFIDArr(exp);
         for (let i = 0, len = fidArr.length; i < len; i++) {
             let id = this.getUID([fidArr[i]]);
             if (id.length === 1) {
-                let row = cbTools.getRowByID(calcBase.project.mainTree.items, id[0]);
+                let row = cbTools.getRowByID(tree.items, id[0]);
                 if (cbTools.isUnDef(row)) {
                     continue;
                 }
@@ -1813,6 +1842,7 @@ let calcBase = {
         cbTools.setFixedBills(budgetSummaryObj.getTree().items, this.fixedBills, this.fixedFlag);
         this.budgetFigures = budgetFigureMap;
         this.baseFigures = { ...this.baseFigures, ...budgetFigureMap };
+        cbTools.setBaseBills(this.budgetFigures, this.fixedBills);
         cbTools.setValidBaseMapping(this.budgetFigures, this.flagValidBase);
     },
     getBase: function (figure) {
@@ -1828,7 +1858,7 @@ let calcBase = {
     getBaseBill: function (node) {
         return cbTools.getBaseBill(node);
     },
-    calculate: function (node, reCalc = null) {
+    calculate: function (node, reCalc = null, alert = true) {
         let me = calcBase,
             $CBA = cbAnalyzer,
             $CBP = cbParser,
@@ -1876,7 +1906,9 @@ let calcBase = {
             if (node) {
                 err = `第${node.serialNo() + 1}行${err}`;
             }
-            alert(err);
+            if (alert) {
+                alert(err);
+            }
         }
     }
 };

+ 5 - 5
web/building_saas/main/js/models/calc_program.js

@@ -1026,7 +1026,7 @@ let calcTools = {
             let r = projectObj.project.FeeRate.getFeeRateByID(node.data.feeRateID);
             if (r) return scMathUtil.roundForObj(r.rate, decimal);
         };
-        if (node.data.feeRate || node.data.feeRate == 0)
+        if (node.data.feeRate || node.data.feeRate === 0 || node.data.feeRate === '0')
             return scMathUtil.roundForObj(node.data.feeRate,decimal);
 
         return 100;
@@ -2231,7 +2231,7 @@ class CalcProgram {
     // 计算零散的、混杂的树节点:清单、定额混合等(如:用到某一计算程序的定额和清单)。
     // 计算多条零散的定额,并计算他们所属的清单、父清单、引用清单。如:批量替换工料机后受影响的定额。
     // 计算多条零散的清单,并计算他们的父清单、引用清单。如:花选删除树结点(如花选清单、定额等,不区分树结点类型)。
-    calcNodes(nodes, tender){
+    calcNodes(nodes, tender, tree){
         let me = this, rationNodes = [], billNodes = [], leafBills = [], allChangedNodes = [];
         for (let node of nodes) {
             if (node.sourceType == ModuleNames.ration)
@@ -2255,7 +2255,7 @@ class CalcProgram {
             allChangedNodes.merge(changeBills);
         };
 
-        me.calcFormulaNodes(allChangedNodes, tender);
+        me.calcFormulaNodes(allChangedNodes, tender, tree);
         return allChangedNodes;
     };
 
@@ -2266,9 +2266,9 @@ class CalcProgram {
     };
 
     // 计算全部公式项。 (changedArr:将通过本方法后发生改变的节点存入changedArr中)
-    calcFormulaNodes(changedArr, tender){
+    calcFormulaNodes(changedArr, tender, tree = projectObj.project.mainTree){
         let me = this;
-        let formulaNodes = cbTools.getFormulaNodes(true);
+        let formulaNodes = cbTools.getFormulaNodes(true, tree);
         if (formulaNodes.length == 0) return;
         for (let formulaNode of formulaNodes){
             formulaNode.data.userCalcBase = formulaNode.data.calcBase;    // 这句不该出现,projectObj.project.calcBase中要改进。

+ 12 - 1
web/building_saas/main/js/views/calc_base_view.js

@@ -120,7 +120,7 @@ let calcBaseView = {
                 return;
             }
             let baseFigure = '';
-            if (me.curType == me.type.bills)
+            if (me.curType == me.type.bills || me.curType === 'budget')
                 baseFigure = `{${v}}`
             else if (me.curType == me.type.ration)
                 baseFigure = `[${v}]`;
@@ -329,6 +329,17 @@ let calcBaseView = {
                     //$('#qd-jsjs').modal('hide');
                     $('#calcBaseFeeRate').modal('hide');
                 }
+            } else if (me.curType === 'budget') {
+                const budgetSheet = budgetSummaryObj.getSheet();
+                const budgetTree = budgetSummaryObj.getTree();
+                const row = budgetTree.selected.serialNo();
+                const col = budgetSummaryTreeSetting.cols.findIndex(item => item.data.field === 'calcBase')
+                const changedCells = [{ row, col }];
+                budgetSheet.setValue(row, col, me.getInputExpr());
+                budgetSummaryObj.edit(budgetSheet, changedCells);
+                if (projectObj.project.calcBase.success || selected.data.calcBase === me.getInputExpr()) {
+                    $('#calcBaseFeeRate').modal('hide');
+                }
             }
             else if (me.curType === me.type.ration) {
                 let expr = me.inputExpr.val();