Kaynağa Gözat

feat: 概算汇总表相关

vian 4 yıl önce
ebeveyn
işleme
e8a354dd1d

+ 10 - 0
modules/main/controllers/bills_controller.js

@@ -278,6 +278,16 @@ module.exports = {
             console.log(err);
             callback(req, res, 1, err, null);
         }
+    },
+    bulkOperation: async function (req, res) {
+        const data = JSON.parse(req.body.data);
+        try {
+            await bill_facade.bulkOperation(data.bulkData);
+            callback(req, res, 0, 'success', null);
+        } catch (err) {
+            console.log(err);
+            callback(req, res, 1, err, null);
+        }
     }
 };
 

+ 28 - 4
modules/main/facade/bill_facade.js

@@ -19,7 +19,7 @@ let bill_Model = require('../models/bills').model;
 let billsLibDao = require("../../bills_lib/models/bills_lib_interfaces");
 const pmFacade = require('../../pm/facade/pm_facade');
 const { getSortedTreeData } = require('../../../public/common_util');
-const { constructionFeeNodeID, constructionEquipmentFeeNodeID, BudgetArea, fixedFlag } = require('../../../public/common_constants');
+const { billType, constructionFeeNodeID, constructionEquipmentFeeNodeID, BudgetArea, fixedFlag } = require('../../../public/common_constants');
 const uuidV1 = require('uuid/v1');
 
 const GLJController = require("../../glj/controllers/glj_controller");
@@ -127,15 +127,15 @@ module.exports={
             await bill_Model.bulkWrite(bulks);
         }
     },
-    // 获取概算汇总数据
+    // 获取概算汇总数据(拍好序的)
     getBudgetSummary: async function (constructionID) {
         // 获取建设项目清单数据(工程建设其他费用 - 建设项目总概算)部分
         const constructionOtherFeeBills = await bill_Model.find({ projectID: constructionID }).lean();
         const sortedOtherFeeBills = getSortedTreeData('-1', constructionOtherFeeBills);
-        constructionOtherFeeBills.forEach(item => item.area = BudgetArea.CONSTRUCTION_OTHER_FEE);
+        sortedOtherFeeBills.forEach(item => item.area = BudgetArea.CONSTRUCTION_OTHER_FEE);
         // 获取工程费用数据
         const constructionFeeBills = await this.getConstructionFeeData(constructionID, sortedOtherFeeBills[0].ID);
-        return [...constructionFeeBills, ...constructionOtherFeeBills];
+        return [...constructionFeeBills, ...sortedOtherFeeBills];
     },
     // 获取工程费用数据,作为概算汇总数据的拼接树数据
     getConstructionFeeData: async function (constructionID, nextID) {
@@ -164,11 +164,13 @@ module.exports={
             item.NextSiblingID = IDMap[item.NextSiblingID] || '-1';
             if (index === 0) {
                 curConstructionID = item.ID;
+                item.type = billType.DXFY;
                 item.flags = [{ fieldName: 'fixed', flag: fixedFlag.CONSTRUCTION_FEE }];
                 item.code = '1';
                 item.name = '工程费用';
                 item.NextSiblingID = nextID;
             } else {
+                item.type = billType.BILL;
                 if (item.ParentID === curConstructionID) {
                     latestSingleNode = item;
                     curSingleNo += 1;
@@ -184,6 +186,7 @@ module.exports={
         const constructionFeeNode = items[0];
         // 设备及工器具购置费
         const constructionEquipmentNode = {
+            type: billType.BILL,
             area: BudgetArea.CONSTRUCTION_FEE,
             flags: [{ fieldName: 'fixed', flag: fixedFlag.CONSTRUCTION_EQUIPMENT_FEE }],
             ID: constructionEquipmentFeeNodeID,
@@ -195,6 +198,27 @@ module.exports={
         latestSingleNode.NextSiblingID = constructionEquipmentNode.ID;
         items.push(constructionEquipmentNode);
         return items;
+    },
+    bulkOperation: async function (bulkData) {
+        const bulks = [];
+        bulkData.forEach(item => {
+            if (item.type === 'new') {
+                bulks.push({
+                    insertOne: { document: item.data }
+                });
+            } else if (item.type === 'update') {
+                bulks.push({
+                    updateOne: { filter: { ID: item.data.ID }, update: { $set: item.data } }
+                });
+            } else {
+                bulks.push({
+                    deleteOne: { filter: { ID: item.data.ID } }
+                });
+            }
+        });
+        if (bulks.length) {
+            await bill_Model.bulkWrite(bulks);
+        }
     }
 };
 

+ 1 - 0
modules/main/routes/bills_route.js

@@ -23,6 +23,7 @@ module.exports = function (app) {
     billsRouter.get('/downloadExamp', billsController.downloadExample);
     billsRouter.post('/insertBills', billsController.insertBills);
     billsRouter.post('/getBudgetSummary', billsController.getBudgetSummary);
+    billsRouter.post('/bulkOperation', billsController.bulkOperation);
     app.use('/bills', billsRouter);
 };
 

+ 75 - 8
modules/main/templates/constructionBillsTemplate.js

@@ -1,6 +1,6 @@
 const { billType, fixedFlag } = require('../../../public/common_constants');
-/* 建设其他费清单模板 */
-const constructionBillsTemplate = [
+/* 概算汇总,建筑安装工程,建设其他费清单模板 */
+const buildingTemplate = [
   { ID: 2, ParentID: -1, NextSiblingID: 3, code: '2', name: '工程建设其他费用', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: fixedFlag.CONSTRUCTION_OTHER_FEE }], type: billType.DXFY },
   { ID: 21, ParentID: 2, NextSiblingID: 22, code: '2.1', name: '前期费用', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
   { ID: 211, ParentID: 21, NextSiblingID: 212, code: '2.1.1', name: '土地征用及补偿费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
@@ -17,7 +17,7 @@ const constructionBillsTemplate = [
   { ID: 223, ParentID: 22, NextSiblingID: 224, code: '2.2.3', name: '工程建设监理费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
   { ID: 224, ParentID: 22, NextSiblingID: 225, code: '2.2.4', name: '招标代理服务费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
   { ID: 225, ParentID: 22, NextSiblingID: 226, code: '2.2.5', name: '招标交易服务费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
-  { ID: 226, ParentID: 22, NextSiblingID: -1, code: '2.2.6', name: '前期工作费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 226, ParentID: 22, NextSiblingID: 227, code: '2.2.6', name: '前期工作费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
   { ID: 2261, ParentID: 226, NextSiblingID: 2262, code: '2.2.6.1', name: '可行性研究费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
   { ID: 2262, ParentID: 226, NextSiblingID: 2263, code: '2.2.6.2', name: '环境影响评价费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
   { ID: 2263, ParentID: 226, NextSiblingID: 2264, code: '2.2.6.3', name: '节能评估费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
@@ -32,6 +32,7 @@ const constructionBillsTemplate = [
   { ID: 229, ParentID: 22, NextSiblingID: 2210, code: '2.2.9', name: '咨询费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
   { ID: 2291, ParentID: 229, NextSiblingID: 2292, code: '2.2.9.1', name: '设计咨询费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
   { ID: 2292, ParentID: 229, NextSiblingID: 2293, code: '2.2.9.2', name: '工程造价咨询费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2293, ParentID: 229, NextSiblingID: -1, code: '2.2.9.3', name: '施工图审查费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
   { ID: 2210, ParentID: 22, NextSiblingID: 2211, code: '2.2.10', name: '全过程工程咨询服务费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
   { ID: 2211, ParentID: 22, NextSiblingID: 2212, code: '2.2.11', name: '引进技术和设备其他费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
   { ID: 2212, ParentID: 22, NextSiblingID: 2213, code: '2.2.12', name: '专利及专有技术使用费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
@@ -42,9 +43,9 @@ const constructionBillsTemplate = [
   { ID: 2217, ParentID: 22, NextSiblingID: 2218, code: '2.2.17', name: '城市基础设施配套费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
   { ID: 2218, ParentID: 22, NextSiblingID: 2219, code: '2.2.18', name: '人防易地建设费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
   { ID: 2219, ParentID: 22, NextSiblingID: -1, code: '2.2.19', name: '其他费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
-  { ID: 23, ParentID: 2, NextSiblingID: -1, code: '2.3', name: '与试运行及生产有关的其他费用', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 23, ParentID: 2, NextSiblingID: -1, code: '2.3', name: '与试运行有关的其他费用', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
   { ID: 231, ParentID: 23, NextSiblingID: 232, code: '2.3.1', name: '综合联调及试运行费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
-  { ID: 232, ParentID: 23, NextSiblingID: -1, code: '2.3.2', name: '生产准备及开办费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 232, ParentID: 23, NextSiblingID: 233, code: '2.3.2', name: '生产准备及开办费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
   { ID: 2321, ParentID: 232, NextSiblingID: 2322, code: '2.3.2.1', name: '生产职工培训费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
   { ID: 2322, ParentID: 232, NextSiblingID: 2323, code: '2.3.2.2', name: '生产办公和生活家具用具购置费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
   { ID: 2323, ParentID: 232, NextSiblingID: -1, code: '2.3.2.3', name: '工器具购置费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
@@ -52,11 +53,77 @@ const constructionBillsTemplate = [
   { ID: 31, ParentID: 3, NextSiblingID: 32, code: '3.1', name: '基本预备费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: fixedFlag.BASIC_BUDGET_RESERVE }], type: billType.BILL },
   { ID: 32, ParentID: 3, NextSiblingID: -1, code: '3.2', name: '价差预备费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: fixedFlag.DIFF_BUDGET_RESERVE }], type: billType.BILL },
   { ID: 4, ParentID: -1, NextSiblingID: 5, code: '4', name: '专项费用', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: fixedFlag.CONSTRUCTION_SPECIAL_FEE }], type: billType.BILL },
-  { ID: 41, ParentID: 4, NextSiblingID: 42, code: '4.1', name: '建设期贷款利息', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
-  { ID: 42, ParentID: 4, NextSiblingID: -1, code: '4.2', name: '铺底流动资金', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 41, ParentID: 4, NextSiblingID: 42, code: '4.1', name: '车辆购置费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 42, ParentID: 4, NextSiblingID: 43, code: '4.2', name: '建设期贷款利息', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 43, ParentID: 4, NextSiblingID: -1, code: '4.3', name: '铺底流动资金', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 5, ParentID: -1, NextSiblingID: -1, code: '5', name: '建设项目总概算', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: fixedFlag.CONSTRUCTION_BUDGET }], type: billType.BILL },
+];
+
+/* 概算汇总,城市轨道交通工程,建设其他费清单模板 */
+const railTemplate = [
+  { ID: 2, ParentID: -1, NextSiblingID: 3, code: '2', name: '工程建设其他费用', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: fixedFlag.CONSTRUCTION_OTHER_FEE }], type: billType.DXFY },
+  { ID: 21, ParentID: 2, NextSiblingID: 22, code: '2.1', name: '前期费用', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 211, ParentID: 21, NextSiblingID: 212, code: '2.1.1', name: '土地征用及补偿费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2111, ParentID: 211, NextSiblingID: 2112, code: '2.1.1.1', name: '集体土地征地补偿安置费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2112, ParentID: 211, NextSiblingID: -1, code: '2.1.1.2', name: '国有土地上房屋征收与补偿费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 212, ParentID: 21, NextSiblingID: 213, code: '2.1.2', name: '临时占地费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 213, ParentID: 21, NextSiblingID: 214, code: '2.1.3', name: '树木及绿化赔偿费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 214, ParentID: 21, NextSiblingID: 215, code: '2.1.4', name: '道路及市政设施损坏赔偿费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 215, ParentID: 21, NextSiblingID: 216, code: '2.1.5', name: '管线迁改费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 216, ParentID: 21, NextSiblingID: -1, code: '2.1.6', name: '交通疏解费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 22, ParentID: 2, NextSiblingID: 23, code: '2.2', name: '与项目建设有关的其他费用', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 221, ParentID: 22, NextSiblingID: 222, code: '2.2.1', name: '场地准备费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 222, ParentID: 22, NextSiblingID: 223, code: '2.2.2', name: '项目建设管理费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 223, ParentID: 22, NextSiblingID: 224, code: '2.2.3', name: '建设工程监理费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 224, ParentID: 22, NextSiblingID: 225, code: '2.2.4', name: '招标代理服务费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 225, ParentID: 22, NextSiblingID: 226, code: '2.2.5', name: '招标交易服务费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 226, ParentID: 22, NextSiblingID: 227, code: '2.2.6', name: '前期工作费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2261, ParentID: 226, NextSiblingID: 2262, code: '2.2.6.1', name: '可行性研究费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2262, ParentID: 226, NextSiblingID: 2263, code: '2.2.6.2', name: '环境影响评价费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2263, ParentID: 226, NextSiblingID: 2264, code: '2.2.6.3', name: '客流预测报告编制费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2264, ParentID: 226, NextSiblingID: 2265, code: '2.2.6.4', name: '地震安全性评价费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2265, ParentID: 226, NextSiblingID: 2266, code: '2.2.6.5', name: '地质灾害危险性评估费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2266, ParentID: 226, NextSiblingID: 2267, code: '2.2.6.6', name: '节能评估费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2267, ParentID: 226, NextSiblingID: 2268, code: '2.2.6.7', name: '社会稳定风险评估费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2268, ParentID: 226, NextSiblingID: 2269, code: '2.2.6.8', name: '防洪评价费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2269, ParentID: 226, NextSiblingID: 22610, code: '2.2.6.9', name: '文物勘探及保护费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 22610, ParentID: 226, NextSiblingID: -1, code: '2.2.6.10', name: '其他前期工作费用', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 227, ParentID: 22, NextSiblingID: 228, code: '2.2.7', name: '研究试验费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 228, ParentID: 22, NextSiblingID: 229, code: '2.2.8', name: '勘察设计费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2281, ParentID: 228, NextSiblingID: 2282, code: '2.2.8.1', name: '勘察费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2282, ParentID: 228, NextSiblingID: -1, code: '2.2.8.2', name: '设计费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 229, ParentID: 22, NextSiblingID: 2210, code: '2.2.9', name: '咨询费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2291, ParentID: 229, NextSiblingID: 2292, code: '2.2.9.1', name: '设计咨询费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2292, ParentID: 229, NextSiblingID: 2293, code: '2.2.9.2', name: '工程造价咨询费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2293, ParentID: 229, NextSiblingID: -1, code: '2.2.9.3', name: '施工图审查费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2210, ParentID: 22, NextSiblingID: 2211, code: '2.2.10', name: '全过程工程咨询服务费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2211, ParentID: 22, NextSiblingID: 2212, code: '2.2.11', name: '引进技术和设备其他费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2212, ParentID: 22, NextSiblingID: 2213, code: '2.2.12', name: '专利及专有技术使用费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2213, ParentID: 22, NextSiblingID: 2214, code: '2.2.13', name: '特殊设备安全监督检验费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2214, ParentID: 22, NextSiblingID: 2215, code: '2.2.14', name: '工程保险费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2215, ParentID: 22, NextSiblingID: 2216, code: '2.2.15', name: '安全生产保障费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2216, ParentID: 22, NextSiblingID: 2217, code: '2.2.16', name: '配合辅助工程费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2217, ParentID: 22, NextSiblingID: -1, code: '2.2.17', name: '其他', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 23, ParentID: 2, NextSiblingID: -1, code: '2.3', name: '与试运行有关的其他费用', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 231, ParentID: 23, NextSiblingID: 232, code: '2.3.1', name: '生产准备及开办费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2311, ParentID: 231, NextSiblingID: 2312, code: '2.3.1.1', name: '生产职业培训费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2312, ParentID: 231, NextSiblingID: 2313, code: '2.3.1.2', name: '生产办公和生活家具用具购置费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2313, ParentID: 231, NextSiblingID: -1, code: '2.3.1.3', name: '工器具购置费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 232, ParentID: 23, NextSiblingID: 233, code: '2.3.2', name: '综合联调及试运行费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2321, ParentID: 232, NextSiblingID: 2322, code: '2.3.2.1', name: '综合联调费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 2322, ParentID: 232, NextSiblingID: -1, code: '2.3.2.2', name: '试运行费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 233, ParentID: 23, NextSiblingID: -1, code: '2.3.3', name: '试运营前安全评价费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 3, ParentID: -1, NextSiblingID: 4, code: '3', name: '预备费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: fixedFlag.BUDGET_RESERVE }], type: billType.DXFY },
+  { ID: 31, ParentID: 3, NextSiblingID: 32, code: '3.1', name: '基本预备费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: fixedFlag.BASIC_BUDGET_RESERVE }], type: billType.BILL },
+  { ID: 32, ParentID: 3, NextSiblingID: -1, code: '3.2', name: '价差预备费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: fixedFlag.DIFF_BUDGET_RESERVE }], type: billType.BILL },
+  { ID: 4, ParentID: -1, NextSiblingID: 5, code: '4', name: '专项费用', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: fixedFlag.CONSTRUCTION_SPECIAL_FEE }], type: billType.BILL },
+  { ID: 41, ParentID: 4, NextSiblingID: 42, code: '4.1', name: '车辆购置费', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 42, ParentID: 4, NextSiblingID: 43, code: '4.2', name: '建设期贷款利息', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
+  { ID: 43, ParentID: 4, NextSiblingID: -1, code: '4.3', name: '铺底流动资金', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: null }], type: billType.BILL },
   { ID: 5, ParentID: -1, NextSiblingID: -1, code: '5', name: '建设项目总概算', unit: '', calcBase: '', quantity: '', flags: [{ fieldName: 'fixed', flag: fixedFlag.CONSTRUCTION_BUDGET }], type: billType.BILL },
 ];
 
 module.exports = {
-  constructionBillsTemplate,
+  buildingTemplate,
+  railTemplate,
 };

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

@@ -50,7 +50,8 @@ let Projects = mongoose.model('projects');
 let mainColLibModel = mongoose.model('std_main_col_lib');
 let projSettingModel = mongoose.model('proj_setting');
 let optionModel = mongoose.model('options');
-const { constructionBillsTemplate } = require('../../main/templates/constructionBillsTemplate');
+const { buildingTemplate, railTemplate } = require('../../main/templates/constructionBillsTemplate');
+const { BudgetType } = require('../../../public/common_constants');
 
 let equipmentPurchaseModel = mongoose.model('equipment_purchase');
 function ProjectsDAO() {
@@ -246,7 +247,8 @@ ProjectsDAO.prototype.updateUserProjects = async function (userId, compilationId
                     }
                 }else if (data.updateData.projType === projectType.project) {
                     /* 创建概算清单 */
-                    await newProjController.copyBillsTemplate(data.updateData.ID, constructionBillsTemplate);
+                    const budgetTemplate = (data.updateData.property && data.updateData.property.budgetType || BudgetType.BUILDING) === BudgetType.BUILDING ? buildingTemplate : railTemplate;
+                    await newProjController.copyBillsTemplate(data.updateData.ID, budgetTemplate);
                     //更新基本信息
                     data.updateData.property.basicInformation.forEach(function (pData) {
                         pData.items.forEach(function (item) {

+ 7 - 0
public/common_constants.js

@@ -213,6 +213,12 @@
         CONSTRUCTION_OTHER_FEE: 2
     };
 
+    // 概算建设项目类型
+    const BudgetType = {
+        BUILDING: 1, // 建设安装工程
+        RAIL: 2, // 轨道工程
+    };
+
     return {
         fixedFlag,
         billType,
@@ -233,5 +239,6 @@
         constructionFeeNodeID,
         constructionEquipmentFeeNodeID,
         BudgetArea,
+        BudgetType,
     };
 });

+ 7 - 7
public/web/id_tree.js

@@ -842,34 +842,34 @@ var idTree = {
             return isValid(roots);
             function isValid(nodes) {
                 for (let node of nodes) {
-                    if (node.data.ParentID !== -1 &&
+                    if (node.data.ParentID != -1 &&
                         (!node.parent || node.parent.data.ID !== node.data.ParentID)) {
                         console.log(`${node.serialNo() + 1}:${node.data.name} parent对应错误`);
                         return false;
                     }
-                    if (node.data.ParentID === -1 && node.parent) {
+                    if (node.data.ParentID == -1 && node.parent) {
                         console.log(`${node.serialNo() + 1}:${node.data.name} 不应有parent`);
                         return false;
                     }
-                    if (node.data.NextSiblingID !== -1 &&
+                    if (node.data.NextSiblingID != -1 &&
                         (!node.nextSibling || node.nextSibling.data.ID !== node.data.NextSiblingID)) {
                         console.log(`${node.serialNo() + 1}:${node.data.name} next对应错误`);
                         return false;
                     }
-                    if (node.data.NextSiblingID === -1 && node.nextSibling) {
+                    if (node.data.NextSiblingID == -1 && node.nextSibling) {
                         console.log(`${node.serialNo() + 1}:${node.data.name} 不应有next`);
                         return false;
                     }
                     let sameDepthNodes = node.parent ? node.parent.children : roots,
                         nodeIdx = sameDepthNodes.indexOf(node),
                         nextIdx = sameDepthNodes.indexOf(node.nextSibling);
-                    if (nodeIdx !== -1 && nextIdx !== -1 && nodeIdx > nextIdx) {
+                    if (nodeIdx != -1 && nextIdx != -1 && nodeIdx > nextIdx) {
                         console.log(`${node.serialNo() + 1}:${node.data.name} node索引大于next索引`);
                         return false;
                     }
                      // nextSibling跟parent children的下一节点对应不上
-                    if (nodeIdx !== -1 && 
-                        (nodeIdx === sameDepthNodes.length - 1 && nextIdx !== -1) || 
+                    if (nodeIdx != -1 && 
+                        (nodeIdx === sameDepthNodes.length - 1 && nextIdx != -1) || 
                         (nodeIdx !== sameDepthNodes.length - 1 && nodeIdx + 1 !== nextIdx)) {
                         console.log(`${node.serialNo() + 1}:${node.data.name} nextSibling与树显示的下一节点对应不上`);
                         return false;

+ 75 - 7
web/building_saas/budget-summary/js/budgetSummarySetting.js

@@ -54,7 +54,7 @@ const budgetSummaryTreeSetting = {
             font: "Arial"
         }
     }, {
-        width: 140,
+        width: 70,
         head: {
             titleNames: ["数量"],
             spanCols: [1],
@@ -71,7 +71,7 @@ const budgetSummaryTreeSetting = {
             font: "Arial",
         }
     }, {
-        width: 140,
+        width: 100,
         head: {
             titleNames: ["单价"],
             spanCols: [1],
@@ -81,14 +81,14 @@ const budgetSummaryTreeSetting = {
             font: ["Arial"],
         },
         data: {
-            field: "common.unitFee",
+            field: "feesIndex.common.unitFee",
             type: 'number',
             vAlign: 1,
             hAlign: 2,
             font: "Arial"
         }
     }, {
-        width: 140,
+        width: 100,
         readOnly: true,
         head: {
             titleNames: ["金额"],
@@ -99,7 +99,7 @@ const budgetSummaryTreeSetting = {
             font: ["Arial"]
         },
         data: {
-            field: "common.totalFee",
+            field: "feesIndex.common.totalFee",
             vAlign: 1,
             hAlign: 2,
             font: "Arial"
@@ -121,9 +121,9 @@ const budgetSummaryTreeSetting = {
             font: "Arial"
         }
     }, {
-        width: 140,
+        width: 80,
         head: {
-            titleNames: ["费率"],
+            titleNames: ["费率(%)"],
             spanCols: [1],
             spanRows: [1],
             vAlign: [1],
@@ -138,6 +138,74 @@ const budgetSummaryTreeSetting = {
             font: "Arial"
         }
     }, {
+        width: 100,
+        readOnly: true,
+        head: {
+            titleNames: ["建筑工程费"],
+            spanCols: [1],
+            spanRows: [1],
+            vAlign: [1],
+            hAlign: [1],
+            font: ["Arial"]
+        },
+        data: {
+            field: "feesIndex.building.totalFee",
+            vAlign: 1,
+            hAlign: 2,
+            font: "Arial"
+        }
+    }, {
+        width: 100,
+        readOnly: true,
+        head: {
+            titleNames: ["安装工程费"],
+            spanCols: [1],
+            spanRows: [1],
+            vAlign: [1],
+            hAlign: [1],
+            font: ["Arial"]
+        },
+        data: {
+            field: "feesIndex.installation.totalFee",
+            vAlign: 1,
+            hAlign: 2,
+            font: "Arial"
+        }
+    }, {
+        width: 100,
+        readOnly: true,
+        head: {
+            titleNames: ["设备购置费"],
+            spanCols: [1],
+            spanRows: [1],
+            vAlign: [1],
+            hAlign: [1],
+            font: ["Arial"]
+        },
+        data: {
+            field: "feesIndex.equipment.totalFee",
+            vAlign: 1,
+            hAlign: 2,
+            font: "Arial"
+        }
+    }, {
+        width: 80,
+        readOnly: true,
+        head: {
+            titleNames: ["其他费用"],
+            spanCols: [1],
+            spanRows: [1],
+            vAlign: [1],
+            hAlign: [1],
+            font: ["Arial"]
+        },
+        data: {
+            field: "feesIndex.other.totalFee",
+            vAlign: 1,
+            hAlign: 2,
+            font: "Arial"
+        }
+    }, {
         width: 140,
         head: {
             titleNames: ["备注"],

+ 128 - 33
web/building_saas/budget-summary/js/budgetSummarySheet.js

@@ -67,8 +67,17 @@ const budgetSummaryObj = (() => {
       sheet.setValue(row, col, orgVal);
     })
   }
+
+  // 更新数据
+  const bulkOperation = async (bulkData) => {
+    await ajaxPost('/bills/bulkOperation', { bulkData });
+  };
+
   // 编辑相关
-  const edit = (sheet, changedCells) => {
+  const edit = async (sheet, changedCells) => {
+    if (!changedCells.length) {
+      return;
+    }
     // 单元格值验证
     const isValid = changedCells.every(({ row, col }) => {
       const val = sheet.getValue(row, col);
@@ -78,6 +87,35 @@ const budgetSummaryObj = (() => {
     if (!isValid) {
       recover(sheet, changedCells);
     }
+    console.log(changedCells);
+    try {
+      $.bootstrapLoading.start();
+      const IDMap = {};
+      const bulkData = [];
+      changedCells.forEach(({ row, col }) => {
+        const node = tree.items[row];
+        if (!node) {
+          return;
+        }
+        const field = getFieldByCol(col);
+        const data = (IDMap[node.data.ID] || (IDMap[node.data.ID] = {}));
+        data[field] = sheet.getValue(row, col);
+      });
+      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);
+      });
+    } catch (err) {
+      alert(err);
+    } finally {
+      $.bootstrapLoading.end();
+    }
   }
   const events = {
     EnterCell(sender, args) {
@@ -130,6 +168,10 @@ const budgetSummaryObj = (() => {
     tree = idTree.createNew({ id: 'ID', pid: 'ParentID', nid: 'NextSiblingID', rootId: -1, autoUpdate: true });
     const controller = TREE_SHEET_CONTROLLER.createNew(tree, sheet, setting, false);
     tree.loadDatas(data);
+    tree.items.forEach(node => {
+      node.source = node;
+      node.sourceType = ModuleNames.bills;
+    });
     controller.showTreeData();
     sheet.setRowCount(data.length);
     setUnitCombo(sheet, data);
@@ -159,43 +201,97 @@ const budgetSummaryObj = (() => {
     initTree(rawData, sheet, budgetSummaryTreeSetting);
   }
   // 插入
-  const insert = (sheet, selected) => {
-    const updateData = tree.getInsertData(selected.data.ParentID, selected.data.NextSiblingID, uuid.v1());
-    updateTree(sheet, updateData);
-    sheet.setActiveCell(sheet.getActiveRowIndex() + selected.posterityCount() + 1, sheet.getActiveColumnIndex())
+  const insert = async (sheet, selected) => {
+    try {
+      $.bootstrapLoading.start();
+      const updateData = tree.getInsertData(selected.data.ParentID, selected.data.NextSiblingID, uuid.v1());
+      const newData = updateData.filter(item => item.type === 'new');
+      newData.forEach(item => {
+        item.data.type = selected.data.type;
+        item.data.projectID = projectObj.project.property.rootProjectID;
+      });
+      await bulkOperation(updateData);
+      updateTree(sheet, updateData);
+      sheet.setActiveCell(sheet.getActiveRowIndex() + selected.posterityCount() + 1, sheet.getActiveColumnIndex())
+    } catch (err) {
+      alert(err);
+    } finally {
+      $.bootstrapLoading.end();
+    }
   }
   // 删除
-  const remove = (sheet, selected) => {
-    const updateData = tree.getDeleteData(selected);
-    updateTree(sheet, updateData);
+  const remove = async (sheet, selected) => {
+    try {
+      $.bootstrapLoading.start();
+      const updateData = tree.getDeleteData(selected);
+      await bulkOperation(updateData);
+      updateTree(sheet, updateData);
+    } catch (err) {
+      alert(err);
+    } finally {
+      $.bootstrapLoading.end();
+    }
   }
   // 升级
-  const upLevel = (sheet, selected) => {
-    const updateData = selected.getUpLevelData();
-    updateTree(sheet, updateData);
+  const upLevel = async (sheet, selected) => {
+    try {
+      $.bootstrapLoading.start();
+      const updateData = selected.getUpLevelData();
+      await bulkOperation(updateData);
+      updateTree(sheet, updateData);
+    } catch (err) {
+      alert(err);
+    } finally {
+      $.bootstrapLoading.end();
+    }
   }
   // 降级
-  const downLevel = (sheet, selected) => {
-    const updateData = selected.getDownLevelData();
-    updateTree(sheet, updateData);
+  const downLevel = async (sheet, selected) => {
+    try {
+      $.bootstrapLoading.start();
+      const updateData = selected.getDownLevelData();
+      await bulkOperation(updateData);
+      updateTree(sheet, updateData);
+    } catch (err) {
+      alert(err);
+    } finally {
+      $.bootstrapLoading.end();
+    }
   }
   // 上移
-  const upMove = (sheet, selected) => {
-    const updateData = selected.getUpMoveData();
-    updateTree(sheet, updateData);
-    const prev = selected.preSibling;
-    const row = sheet.getActiveRowIndex() - prev.posterityCount() - 1;
-    sheet.setActiveCell(row, sheet.getActiveColumnIndex());
-    sheet.showRow(row, GC.Spread.Sheets.VerticalPosition.center);
+  const upMove = async (sheet, selected) => {
+    try {
+      $.bootstrapLoading.start();
+      const updateData = selected.getUpMoveData();
+      await bulkOperation(updateData);
+      updateTree(sheet, updateData);
+      const prev = selected.preSibling;
+      const row = sheet.getActiveRowIndex() - prev.posterityCount() - 1;
+      sheet.setActiveCell(row, sheet.getActiveColumnIndex());
+      sheet.showRow(row, GC.Spread.Sheets.VerticalPosition.center);
+    } catch (err) {
+      alert(err);
+    } finally {
+      $.bootstrapLoading.end();
+    }
   }
   // 下移
-  const downMove = (sheet, selected) => {
-    const updateData = selected.getDownMoveData();
-    updateTree(sheet, updateData);
-    const next = selected.nextSibling;
-    const row = sheet.getActiveRowIndex() + next.posterityCount() + 1;
-    sheet.setActiveCell(row, sheet.getActiveColumnIndex())
-    sheet.showRow(row, GC.Spread.Sheets.VerticalPosition.center);
+  const downMove = async (sheet, selected) => {
+    try {
+      $.bootstrapLoading.start();
+      const updateData = selected.getDownMoveData();
+      await bulkOperation(updateData);
+      updateTree(sheet, updateData);
+      const next = selected.nextSibling;
+      const row = sheet.getActiveRowIndex() + next.posterityCount() + 1;
+      sheet.setActiveCell(row, sheet.getActiveColumnIndex())
+      sheet.showRow(row, GC.Spread.Sheets.VerticalPosition.center);
+    } catch (err) {
+      alert(err);
+    } finally {
+      $.bootstrapLoading.end();
+    }
+
   }
   // 是否是属于工程费用区域的节点
   const isConstructionFeeArea = (node) => {
@@ -230,7 +326,7 @@ const budgetSummaryObj = (() => {
           }
         },
         remove: {
-          name: '删除',
+          name: '删除',
           icon: 'fa-remove',
           disabled() {
             return !curNode || isConstructionFeeArea(curNode);
@@ -253,7 +349,7 @@ const budgetSummaryObj = (() => {
           name: '降级',
           icon: 'fa-arrow-right',
           disabled() {
-            return !curNode || !curNode.canDownLevel() || isConstructionFeeArea(curNode);
+            return !curNode || !curNode.canDownLevel() || isConstructionFeeArea(curNode) || isConstructionFeeArea(curNode.preSibling);
           },
           callback() {
             downLevel(sheet, curNode);
@@ -304,9 +400,9 @@ const budgetSummaryObj = (() => {
         if (item.flags) {
           item.flags.forEach((flag) => {
             item.flagsIndex[flag.fieldName] = flag;
-            });
+          });
         }
-    });
+      });
       const spread = initSpread();
       const sheet = spread.getSheet(0);
       initTree(rawData, sheet, budgetSummaryTreeSetting);
@@ -325,7 +421,6 @@ const budgetSummaryObj = (() => {
     }
   });
 
-
   // 对外暴露
   return {
     getTree: () => tree,

+ 13 - 0
web/building_saas/pm/html/project-management.html

@@ -294,6 +294,19 @@
                         </div>
                     </div>
                     <span class="form-text text-danger" id="taxType-info" style="display: none;">请选择计税方法</span>
+                    <div class="form-group row">
+                        <label for="staticEmail" class="col-auto col-form-label col-form-label-sm">项目类型</label>
+                        <div class="col">
+                            <div class="custom-control custom-radio custom-control-inline">
+                                <input type="radio" value="1" checked id="building" name="budgetType" class="custom-control-input">
+                                <label class="custom-control-label" for="building">建筑安装工程</label>
+                            </div>
+                             <div class="custom-control custom-radio custom-control-inline">
+                                 <input type="radio" value="2" id="rail" name="budgetType" class="custom-control-input">
+                                 <label class="custom-control-label" for="rail">城市轨道交通工程</label>
+                             </div>
+                        </div>
+                    </div>
                 </form>
                 <form id="projInfoStep" class="hidden-area"></form>
                 <p id="project-required-warn" class="text-muted hidden-area"><i class="fa fa-warning text-warning"></i> 注:为响应重庆地区指标采集标准数据要求,以上工程信息及特征为必填项,请正确填写。</p>

+ 2 - 0
web/building_saas/pm/js/pm_newMain.js

@@ -3107,6 +3107,7 @@ function AddProject() {
         setDangerInfo($('#taxType-info'));
         return false;
     }
+    const budgetType = +$('input[name="budgetType"]:checked').val() || commonConstants.BudgetType.BUILDING;
     $.bootstrapLoading.start();
     let existCallback = function () {
         setDangerInfo($('#project-name-info'), `已存在“${$("#project-name").val()}”`);
@@ -3141,6 +3142,7 @@ function AddProject() {
     let property = {basicInformation: needfulInfoData ? needfulInfoData : [],
         fileKind: fileKind,
         taxType: taxType,
+        budgetType,
         valuation: valuation,
         valuationName: valuationName,
         valuationType: curValutionType