Browse Source

1. 台账分解、计量台账,新增错漏增减相关数据列,根据显示设置显示,并处理编辑、删除、复制粘贴、计算等
2. 台账分解,批量插入部位明细、复制粘贴整块、导入Excel等,适应性修改
3. 导入excel,调整清单精度舍入相关

MaiXinRong 6 years ago
parent
commit
1f7fd07ca5

+ 207 - 46
app/const/spread.js

@@ -10,44 +10,144 @@
 
 const tzWithoutCols = ['deal_qty', 'deal_tp'];
 const dgnCols = ['dgn_qty1', 'dgn_qty2', 'dgn_price'];
-const posTzWithoutCols = ['add_stage'];
+const clCols = ['sjcl_qty', 'sjcl_tp', 'qtcl_qty', 'qtcl_tp', 'quantity', 'total_price'];
 
-const ledgerSpread = {
-    cols: [
-        {title: '项目节编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 150, formatter: '@', cellType: 'tree'},
-        {title: '清单编号', colSpan: '1', rowSpan: '2', field: 'b_code', hAlign: 0, width: 80, formatter: '@'},
-        {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 230, formatter: '@'},
-        {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 50, formatter: '@', cellType: 'unit'},
-        {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.unit_price'},
-        {title: '设计数量|数量1',  colSpan: '2|1', rowSpan: '1|1', field: 'dgn_qty1', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.dgnQty'},
-        {title: '|数量2',  colSpan: '|1', rowSpan: '|1', field: 'dgn_qty2', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.dgnQty'},
-        {title: '经济指标',  colSpan: '1', rowSpan: '2', field: 'dgn_price', hAlign: 2, width: 60, type: 'Number', readOnly: true},
-        {title: '签约|数量', colSpan: '2|1', rowSpan: '1|1', field: 'deal_qty', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.quantity'},
-        {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'deal_tp', hAlign: 2, width: 60, type: 'Number', readOnly: true},
-        {title: '施工图复核|数量', colSpan: '2|1', rowSpan: '1|1', field: 'quantity', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.quantity'},
-        {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'total_price', hAlign: 2, width: 60, type: 'Number', readOnly: true},
-        {title: '图(册)号', colSpan: '1', rowSpan: '2', field: 'drawing_code', hAlign: 0, width: 80, formatter: '@'},
-        {title: '备注', colSpan: '1', rowSpan: '2', field: 'memo', hAlign: 0, width: 100, formatter: '@'}
-    ],
-    emptyRows: 3,
-    headRows: 2,
-    headRowHeight: [40, 40],
-    defaultRowHeight: 21,
+const withCl = {
+    ledger: {
+        cols: [
+            {title: '项目节编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 150, formatter: '@', cellType: 'tree'},
+            {title: '清单编号', colSpan: '1', rowSpan: '2', field: 'b_code', hAlign: 0, width: 80, formatter: '@'},
+            {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 230, formatter: '@'},
+            {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 50, formatter: '@', cellType: 'unit'},
+            {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.unit_price'},
+            {title: '设计数量|数量1',  colSpan: '2|1', rowSpan: '1|1', field: 'dgn_qty1', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.dgnQty'},
+            {title: '|数量2',  colSpan: '|1', rowSpan: '|1', field: 'dgn_qty2', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.dgnQty'},
+            {title: '经济指标',  colSpan: '1', rowSpan: '2', field: 'dgn_price', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '签约|数量', colSpan: '2|1', rowSpan: '1|1', field: 'deal_qty', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.quantity'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'deal_tp', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '施工图复核|数量', colSpan: '2|1', rowSpan: '1|1', field: 'sgfh_qty', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.quantity'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'sgfh_tp', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '设计错漏增减|数量', colSpan: '2|1', rowSpan: '1|1', field: 'sjcl_qty', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.quantity'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'sjcl_tp', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '其他错漏增减|数量', colSpan: '2|1', rowSpan: '1|1', field: 'qtcl_qty', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.quantity'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'qtcl_tp', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '小计|数量', colSpan: '2|1', rowSpan: '1|1', field: 'quantity', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'total_price', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '图(册)号', colSpan: '1', rowSpan: '2', field: 'drawing_code', hAlign: 0, width: 80, formatter: '@'},
+            {title: '备注', colSpan: '1', rowSpan: '2', field: 'memo', hAlign: 0, width: 100, formatter: '@'}
+        ],
+        emptyRows: 3,
+        headRows: 2,
+        headRowHeight: [35, 35],
+        defaultRowHeight: 21,
+    },
+    pos: {
+        cols: [
+            {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 230, formatter: '@'},
+            {title: '数量|施工图复核', colSpan: '4|1', rowSpan: '1|1', field: 'sgfh_qty', hAlign: 2, width: 100, type: 'Number'},
+            {title: '数量|设计错漏增减', colSpan: '|1', rowSpan: '|1', field: 'sjcl_qty', hAlign: 2, width: 100, type: 'Number'},
+            {title: '数量|其他错漏增减', colSpan: '|1', rowSpan: '|1', field: 'qtcl_qty', hAlign: 2, width: 100, type: 'Number'},
+            {title: '|小计', colSpan: '|1', rowSpan: '|1', field: 'quantity', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '图册号', colSpan: '1', rowSpan: '2', field: 'drawing_code', hAlign: 0, width: 80, formatter: '@'},
+        ],
+        emptyRows: 3,
+        headRows: 2,
+        headRowHeight: [35, 35],
+        defaultRowHeight: 21,
+    }
 };
-
-const ledgerPosSpread = {
-    cols: [
-        {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 230, formatter: '@'},
-        {title: '数量', colSpan: '1', rowSpan: '1', field: 'quantity', hAlign: 2, width: 60, type: 'Number'},
-        {title: '图册号', colSpan: '1', rowSpan: '1', field: 'drawing_code', hAlign: 0, width: 80, formatter: '@'},
-    ],
-    emptyRows: 3,
-    headRows: 1,
-    headRowHeight: [40],
-    defaultRowHeight: 21,
+const withoutCl = {
+    ledger: {
+        cols: [
+            {title: '项目节编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 150, formatter: '@', cellType: 'tree'},
+            {title: '清单编号', colSpan: '1', rowSpan: '2', field: 'b_code', hAlign: 0, width: 80, formatter: '@'},
+            {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 230, formatter: '@'},
+            {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 50, formatter: '@', cellType: 'unit'},
+            {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.unit_price'},
+            {title: '设计数量|数量1',  colSpan: '2|1', rowSpan: '1|1', field: 'dgn_qty1', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.dgnQty'},
+            {title: '|数量2',  colSpan: '|1', rowSpan: '|1', field: 'dgn_qty2', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.dgnQty'},
+            {title: '经济指标',  colSpan: '1', rowSpan: '2', field: 'dgn_price', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '签约|数量', colSpan: '2|1', rowSpan: '1|1', field: 'deal_qty', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.quantity'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'deal_tp', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '施工图复核|数量', colSpan: '2|1', rowSpan: '1|1', field: 'sgfh_qty', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.quantity'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'sgfh_tp', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '图(册)号', colSpan: '1', rowSpan: '2', field: 'drawing_code', hAlign: 0, width: 80, formatter: '@'},
+            {title: '备注', colSpan: '1', rowSpan: '2', field: 'memo', hAlign: 0, width: 100, formatter: '@'}
+        ],
+        emptyRows: 3,
+        headRows: 2,
+        headRowHeight: [35, 35],
+        defaultRowHeight: 21,
+    },
+    pos: {
+        cols: [
+            {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 230, formatter: '@'},
+            {title: '施工图复核数量', colSpan: '1', rowSpan: '1', field: 'sgfh_qty', hAlign: 2, width: 120, type: 'Number'},
+            {title: '图册号', colSpan: '1', rowSpan: '2', field: 'drawing_code', hAlign: 0, width: 80, formatter: '@'},
+        ],
+        emptyRows: 3,
+        headRows: 1,
+        headRowHeight: [40],
+        defaultRowHeight: 21,
+    }
 };
-
-const stage = {
+// 期 -- 本期计量台账
+const stageTz = {
+    ledger: {
+        cols: [
+            {title: '项目节编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 150, formatter: '@', readOnly: true, cellType: 'tree'},
+            {title: '清单编号', colSpan: '1', rowSpan: '2', field: 'b_code', hAlign: 0, width: 80, formatter: '@', readOnly: true},
+            {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 230, formatter: '@', readOnly: true},
+            {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@', readOnly: true, cellType: 'unit'},
+            {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '台账|数量', colSpan: '2|1', rowSpan: '1|1', field: 'quantity', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'total_price', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '本期合同计量|数量', colSpan: '2|1', rowSpan: '1|1', field: 'contract_qty', hAlign: 2, width: 60, type: 'Number'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'contract_tp', hAlign: 2, width: 60, type: 'Number'},
+            {title: '本期数量变更|数量', colSpan: '2|1', rowSpan: '1|1', field: 'qc_qty', hAlign: 2, width: 60, type: 'Number',},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'qc_tp', hAlign: 2, width: 60, type: 'Number'},
+            {title: '本期完成计量|数量', colSpan: '2|1', rowSpan: '1|1', field: 'gather_qty', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'gather_tp', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '截止本期合同计量|数量', colSpan: '2|1', rowSpan: '1|1', field: 'end_contract_qty', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'end_contract_tp', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '截止本期数量变更|数量', colSpan: '2|1', rowSpan: '1|1', field: 'end_qc_qty', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'end_qc_tp', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '截止本期完成计量|数量', colSpan: '2|1', rowSpan: '1|1', field: 'end_gather_qty', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'end_gather_tp', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '合同|设计数量1',  colSpan: '2|1', rowSpan: '1|1', field: 'deal_dgn_qty1', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '|设计数量2',  colSpan: '|1', rowSpan: '|1', field: 'deal_dgn_qty2', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '变更|设计数量1',  colSpan: '2|1', rowSpan: '1|1', field: 'c_dgn_qty1', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '|数量2',  colSpan: '|1', rowSpan: '|1', field: 'c_dgn_qty2', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '经济指标',  colSpan: '1', rowSpan: '2', field: 'final_dgn_price', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '本期批注', colSpan: '1', rowSpan: '2', field: 'postil', hAlign: 0, width: 100, formatter: '@'},
+            {title: '图(册)号', colSpan: '1', rowSpan: '2', field: 'drawing_code', hAlign: 0, width: 80, formatter: '@', readOnly: true},
+            {title: '累计完成率(%)', colSpan: '1', rowSpan: '2', field: 'percent', hAlign: 0, width: 100, readOnly: true, type: 'Number'},
+        ],
+        emptyRows: 0,
+        headRows: 2,
+        headRowHeight: [32, 32],
+        defaultRowHeight: 21,
+    },
+    pos: {
+        cols: [
+            {title: '部位名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 180, formatter: '@', readOnly: true},
+            {title: '台账数量', colSpan: '1', rowSpan: '2', field: 'quantity', hAlign: 2, width: 60, formatter: '@', readOnly: true},
+            {title: '本期计量|合同', colSpan: '3|1', rowSpan: '1|1', field: 'contract_qty', hAlign: 2, width: 60, type: 'Number'},
+            {title: '|数量变更', colSpan: '|1', rowSpan: '|1', field: 'qc_qty', hAlign: 2, width: 80, type: 'Number'},
+            {title: '|完成', colSpan: '|1', rowSpan: '|1', field: 'gather_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '截止本期计量|合同', colSpan: '3|1', rowSpan: '1|1', field: 'end_contract_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '|数量变更', colSpan: '|1', rowSpan: '|1', field: 'end_qc_qty', hAlign: 2, width: 80, type: 'Number', readOnly: true},
+            {title: '|完成', colSpan: '|1', rowSpan: '|1', field: 'end_gather_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '本期批注', colSpan: '1', rowSpan: '2', field: 'postil', hAlign: 0, width: 80, formatter: '@'},
+            {title: '图册号', colSpan: '1', rowSpan: '2', field: 'drawing_code', hAlign: 0, width: 80, formatter: '@', readOnly: true},
+        ],
+        emptyRows: 3,
+        headRows: 2,
+        headRowHeight: [32, 32],
+        defaultRowHeight: 21,
+    }
+};
+const stageCl = {
     ledger: {
         cols: [
             {title: '项目节编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 150, formatter: '@', readOnly: true, cellType: 'tree'},
@@ -57,7 +157,7 @@ const stage = {
             {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
             {title: '签约|数量', colSpan: '2|1', rowSpan: '1|1', field: 'deal_qty', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
             {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'deal_tp', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
-            {title: '施工图复核|数量', colSpan: '2|1', rowSpan: '1|1', field: 'quantity', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '台账|数量', colSpan: '2|1', rowSpan: '1|1', field: 'quantity', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
             {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'total_price', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
             {title: '本期合同计量|数量', colSpan: '2|1', rowSpan: '1|1', field: 'contract_qty', hAlign: 2, width: 60, type: 'Number'},
             {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'contract_tp', hAlign: 2, width: 60, type: 'Number'},
@@ -87,8 +187,11 @@ const stage = {
     },
     pos: {
         cols: [
-            {title: '部位名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 180, formatter: '@', readOnly: true},
-            {title: '复核数量', colSpan: '1', rowSpan: '2', field: 'quantity', hAlign: 2, width: 60, formatter: '@'},
+            {title: '部位名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 180, formatter: '@'},
+            {title: '复核数量|施工图复核', colSpan: '4|1', rowSpan: '1|1', field: 'sgfh_qty', hAlign: 2, width: 60, type: 'Number'},
+            {title: '|设计错漏增减', colSpan: '1', rowSpan: '|1', field: 'sjcl_qty', hAlign: 2, width: 60, type: 'Number'},
+            {title: '|其他错漏增减', colSpan: '1', rowSpan: '|1', field: 'qtcl_qty', hAlign: 2, width: 60, type: 'Number'},
+            {title: '|小计', colSpan: '1', rowSpan: '|1', field: 'quantity', hAlign: 2, width: 60, readOnly: true},
             {title: '本期计量|合同', colSpan: '3|1', rowSpan: '1|1', field: 'contract_qty', hAlign: 2, width: 60, type: 'Number'},
             {title: '|数量变更', colSpan: '|1', rowSpan: '|1', field: 'qc_qty', hAlign: 2, width: 80, type: 'Number'},
             {title: '|完成', colSpan: '|1', rowSpan: '|1', field: 'gather_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true},
@@ -105,6 +208,65 @@ const stage = {
         defaultRowHeight: 21,
     }
 };
+const stageNoCl = {
+    ledger: {
+        cols: [
+            {title: '项目节编号', colSpan: '1', rowSpan: '2', field: 'code', hAlign: 0, width: 150, formatter: '@', readOnly: true, cellType: 'tree'},
+            {title: '清单编号', colSpan: '1', rowSpan: '2', field: 'b_code', hAlign: 0, width: 80, formatter: '@', readOnly: true},
+            {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 230, formatter: '@', readOnly: true},
+            {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@', readOnly: true, cellType: 'unit'},
+            {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '签约|数量', colSpan: '2|1', rowSpan: '1|1', field: 'deal_qty', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'deal_tp', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '施工图复核|数量', colSpan: '2|1', rowSpan: '1|1', field: 'quantity', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'total_price', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '本期合同计量|数量', colSpan: '2|1', rowSpan: '1|1', field: 'contract_qty', hAlign: 2, width: 60, type: 'Number'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'contract_tp', hAlign: 2, width: 60, type: 'Number'},
+            {title: '本期数量变更|数量', colSpan: '2|1', rowSpan: '1|1', field: 'qc_qty', hAlign: 2, width: 60, type: 'Number',},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'qc_tp', hAlign: 2, width: 60, type: 'Number'},
+            {title: '本期完成计量|数量', colSpan: '2|1', rowSpan: '1|1', field: 'gather_qty', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'gather_tp', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '截止本期合同计量|数量', colSpan: '2|1', rowSpan: '1|1', field: 'end_contract_qty', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'end_contract_tp', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '截止本期数量变更|数量', colSpan: '2|1', rowSpan: '1|1', field: 'end_qc_qty', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'end_qc_tp', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '截止本期完成计量|数量', colSpan: '2|1', rowSpan: '1|1', field: 'end_gather_qty', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'end_gather_tp', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '合同|设计数量1',  colSpan: '2|1', rowSpan: '1|1', field: 'deal_dgn_qty1', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '|设计数量2',  colSpan: '|1', rowSpan: '|1', field: 'deal_dgn_qty2', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '变更|设计数量1',  colSpan: '2|1', rowSpan: '1|1', field: 'c_dgn_qty1', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '|数量2',  colSpan: '|1', rowSpan: '|1', field: 'c_dgn_qty2', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '经济指标',  colSpan: '1', rowSpan: '2', field: 'final_dgn_price', hAlign: 2, width: 60, readOnly: true, type: 'Number'},
+            {title: '本期批注', colSpan: '1', rowSpan: '2', field: 'postil', hAlign: 0, width: 100, formatter: '@'},
+            {title: '图(册)号', colSpan: '1', rowSpan: '2', field: 'drawing_code', hAlign: 0, width: 80, formatter: '@', readOnly: true},
+            {title: '累计完成率(%)', colSpan: '1', rowSpan: '2', field: 'percent', hAlign: 0, width: 100, readOnly: true, type: 'Number'},
+        ],
+        emptyRows: 0,
+        headRows: 2,
+        headRowHeight: [32, 32],
+        defaultRowHeight: 21,
+    },
+    pos: {
+        cols: [
+            {title: '部位名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 180, formatter: '@'},
+            {title: '复核数量', colSpan: '1', rowSpan: '2', field: 'sgfh_qty', hAlign: 2, width: 60, type: 'Number'},
+            {title: '本期计量|合同', colSpan: '3|1', rowSpan: '1|1', field: 'sgfh_tp', hAlign: 2, width: 60, type: 'Number'},
+            {title: '|数量变更', colSpan: '|1', rowSpan: '|1', field: 'qc_qty', hAlign: 2, width: 80, type: 'Number'},
+            {title: '|完成', colSpan: '|1', rowSpan: '|1', field: 'gather_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '截止本期计量|合同', colSpan: '3|1', rowSpan: '1|1', field: 'end_contract_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '|数量变更', colSpan: '|1', rowSpan: '|1', field: 'end_qc_qty', hAlign: 2, width: 80, type: 'Number', readOnly: true},
+            {title: '|完成', colSpan: '|1', rowSpan: '|1', field: 'end_gather_qty', hAlign: 2, width: 60, type: 'Number', readOnly: true},
+            {title: '本期批注', colSpan: '1', rowSpan: '2', field: 'postil', hAlign: 0, width: 80, formatter: '@'},
+            {title: '图册号', colSpan: '1', rowSpan: '2', field: 'drawing_code', hAlign: 0, width: 80, formatter: '@', readOnly: true},
+            {title: '添加期数', colSpan: '1', rowSpan: '2', field: 'add_stage', hAlign:1, width: 80, readOnly: true},
+        ],
+        emptyRows: 3,
+        headRows: 2,
+        headRowHeight: [32, 32],
+        defaultRowHeight: 21,
+    }
+};
+// 期 -- 清单汇总
 const stageGather = {
     gcl: {
         cols: [
@@ -168,6 +330,7 @@ const stageGather = {
         font: '10pt 微软雅黑',
     }
 };
+// 期 -- 审核比较
 const stageCompare = {
     ledger: {
         baseCols: [
@@ -244,15 +407,13 @@ measure.compare.pos = {
 };
 
 module.exports = {
-    ledgerSpread,
-    ledgerPosSpread,
-    stage,
+    withCl,
+    withoutCl,
+    stageTz,
+    stageCl,
+    stageNoCl,
     stageGather,
     stageCompare,
-    filterCols: {
-        tzWithoutCols,
-        dgnCols,
-        posTzWithoutCols,
-    },
+    filterCols: { tzWithoutCols, dgnCols, clCols},
     measure,
 };

+ 1 - 0
app/const/tender_info.js

@@ -89,6 +89,7 @@ const defaultInfo = {
     display: {
         ledger: {
             dgnQty: false,
+            clQty: false,
         },
     },
     chapter: [

+ 3 - 2
app/controller/ledger_audit_controller.js

@@ -35,9 +35,10 @@ module.exports = app => {
                     return cols.indexOf(c.field) > -1;
                 });
             }
-            const ledger = JSON.parse(JSON.stringify(spreadConst.ledgerSpread));
-            const pos = JSON.parse(JSON.stringify(spreadConst.ledgerPosSpread));
             const tender = this.ctx.tender;
+            const setting = tender.info.display.ledger.clQty ? spreadConst.withCl : spreadConst.withoutCl;
+            const ledger = JSON.parse(JSON.stringify(setting.ledger));
+            const pos = JSON.parse(JSON.stringify(setting.pos));
             ledger.readOnly = true;
             pos.readOnly = true;
             if (tender.data.measure_type === measureType.tz.value) {

+ 11 - 3
app/controller/ledger_controller.js

@@ -60,6 +60,13 @@ module.exports = app => {
                     return cols.indexOf(c.field) > -1;
                 });
             }
+            function hideFieldCols(setting, cols) {
+                for (const c of setting.cols) {
+                    if (cols.indexOf(c.field) > -1) {
+                        c.visible = false;
+                    }
+                }
+            }
             function setColFormat(cols, field, formatter) {
                 const col = _.find(cols, function (c) {
                     return c.field === field;
@@ -68,14 +75,15 @@ module.exports = app => {
             }
             // const tpFormatter = this.ctx.helper.getNumberFormatter(this.ctx.tender.info.decimal.tp);
             // const upFormatter = this.ctx.helper.getNumberFormatter(this.ctx.tender.info.decimal.up);
-            const ledger = JSON.parse(JSON.stringify(spreadConst.ledgerSpread));
+            const tender = this.ctx.tender;
+            const setting = tender.info.display.ledger.clQty ? spreadConst.withCl : spreadConst.withoutCl;
+            const ledger = JSON.parse(JSON.stringify(setting.ledger));
             // setColFormat(ledger.cols, 'unit_price', upFormatter);
             // setColFormat(ledger.cols, 'dgn_price', upFormatter);
             // setColFormat(ledger.cols, 'total_price', tpFormatter);
             // setColFormat(ledger.cols, 'deal_tp', tpFormatter);
-            const pos = JSON.parse(JSON.stringify(spreadConst.ledgerPosSpread));
+            const pos = JSON.parse(JSON.stringify(setting.pos));
 
-            const tender = this.ctx.tender;
             if (this._ledgerReadOnly(tender.data)) {
                 ledger.readOnly = true;
                 pos.readOnly = true;

+ 5 - 16
app/controller/stage_controller.js

@@ -88,25 +88,14 @@ module.exports = app => {
             }
             // const tpFormatter = this.ctx.helper.getNumberFormatter(this.ctx.tender.info.decimal.tp);
             // const upFormatter = this.ctx.helper.getNumberFormatter(2);
-            const ledger = JSON.parse(JSON.stringify(spreadConst.stage.ledger));
+            const tender = this.ctx.tender, stage = this.ctx.stage;
+            const stageSetting = tender.data.measure_type === measureType.tz.value ? spreadConst.stageTz :
+                (tender.info.display.ledger.clQty ? spreadConst.stageCl : spreadConst.stageNoCl);
+            const ledger = JSON.parse(JSON.stringify(stageSetting.ledger));
             // setColFormat(ledger.cols, 'unit_price', upFormatter);
             // setColFormat(ledger.cols, 'total_price', tpFormatter);
             // setColFormat(ledger.cols, 'tp', tpFormatter);
-            const pos = JSON.parse(JSON.stringify(spreadConst.stage.pos));
-            const tender = this.ctx.tender, stage = this.ctx.stage;
-            if (this._stageReadOnly(stage)) {
-                ledger.readOnly = true;
-                pos.readOnly = true;
-            }
-            if (tender.data.measure_type === measureType.tz.value) {
-                removeFieldCols(ledger, spreadConst.filterCols.tzWithoutCols);
-                removeFieldCols(pos, spreadConst.filterCols.posTzWithoutCols);
-                const col = this.app._.find(pos.cols, {field: 'quantity'});
-                col.readOnly = true;
-            }
-            if (!tender.info.display.ledger.dgnQty) {
-                removeFieldCols(ledger, spreadConst.filterCols.dgnCols);
-            }
+            const pos = JSON.parse(JSON.stringify(stageSetting.pos));
             if (this.ctx.stage.readOnly) {
                 ledger.readOnly = true;
                 pos.readOnly = true;

+ 65 - 1
app/extend/helper.js

@@ -13,6 +13,7 @@ const path = require('path');
 const streamToArray = require('stream-to-array');
 const _ = require('lodash');
 const np = require('number-precision');
+np.enableBoundaryChecking(false);
 const math = require('mathjs');
 
 module.exports = {
@@ -654,5 +655,68 @@ module.exports = {
             result = this.plus(result, a);
         }
         return result;
-    }
+    },
+
+    // // 以下方法均使用js自有方法,保留10位小数
+    // /**
+    //  * 加法 num1 + num2
+    //  * @param num1
+    //  * @param num2
+    //  * @returns {number}
+    //  */
+    // plus(num1, num2) {
+    //     return _.round((num1 ? num1 : 0) + (num2 ? num2: 0), 10);
+    // },
+    // /**
+    //  * 减法 num1 - num2
+    //  * @param num1
+    //  * @param num2
+    //  * @returns {number}
+    //  */
+    // minus(num1, num2) {
+    //     return _.round((num1 ? num1 : 0) - (num2 ? num2: 0), 10);
+    // },
+    // /**
+    //  * 乘法 num1 * num2
+    //  * @param num1
+    //  * @param num2
+    //  * @returns {*}
+    //  */
+    // times(num1, num2) {
+    //     return _.round((num1 ? num1 : 0) * (num2 ? num2: 0), 10);
+    // },
+    // /**
+    //  * 除法 num1 / num2
+    //  * @param num1 - 被除数
+    //  * @param num2 - 除数
+    //  * @returns {*}
+    //  */
+    // divide(num1, num2) {
+    //     if (num2 && !this.checkZero(num2)) {
+    //         return _.round((num1 ? num1 : 0) / (num2 ? num2: 0), 10);
+    //     } else {
+    //         return null;
+    //     }
+    // },
+    // /**
+    //  * 四舍五入(统一,方便以后万一需要置换)
+    //  * @param {Number} value - 舍入的数字
+    //  * @param {Number} decimal - 要保留的小数位数
+    //  * @returns {*}
+    //  */
+    // round(value, decimal) {
+    //     return value ? _.round(value, decimal) : null;
+    // },
+    // /**
+    //  * 汇总
+    //  * @param array
+    //  * @returns {number}
+    //  */
+    // sum(array) {
+    //     let result = 0;
+    //     for (const a of array) {
+    //         result = this.plus(result, a);
+    //     }
+    //     return result;
+    // }
 };

+ 29 - 4
app/lib/analysis_excel.js

@@ -28,6 +28,7 @@ class ImportBaseTree {
 
         // 缓存
         this.finalNode = null;
+        this.finalPrecision = null;
         this.finalXmjNode = null;
         this.keyNodeId = 1;
 
@@ -118,6 +119,7 @@ class ImportBaseTree {
      */
     defineCacheData(node) {
         this.finalNode = node;
+        this.finalPrecision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, node.unit);
         if (node.code) {
             this.finalXmjNode = node;
         }
@@ -170,6 +172,8 @@ class ImportBaseTree {
         if (this.finalNode && this.finalNode.pos) {
             this.finalNode.pos.push(pos);
             this.pos.push(pos);
+            pos.sgfh_qty = this.ctx.helper.round(pos.sgfh_qty, this.finalPrecision.value);
+            pos.quantity = pos.sgfh_qty;
             return pos;
         }
     }
@@ -198,6 +202,13 @@ class ImportBaseTree {
         for (const node of this.items) {
             if (node.children && node.children.length > 0) { continue; }
             if (!node.pos || node.pos.length === 0) { continue; }
+            node.sgfh_qty = this.ctx.helper.sum(_.map(node.pos, 'sgfh_qty'));
+            if (node.sgfh_qty && node.unit_price) {
+                node.sgfh_tp = this.ctx.helper.round(this.ctx.helper.times(node.sgfh_qty, node.unit_price),
+                    this.ctx.tender.info.decimal.tp);
+            } else {
+                node.sgfh_tp = null;
+            }
             node.quantity = this.ctx.helper.sum(_.map(node.pos, 'quantity'));
             if (node.quantity && node.unit_price) {
                 node.total_price = this.ctx.helper.round(this.ctx.helper.times(node.quantity, node.unit_price),
@@ -222,7 +233,7 @@ class AnalysisExcelTree {
             pos: ['部位明细'],
             name: ['名称'],
             unit: ['单位'],
-            quantity: ['清单数量'], // 施工图复核数量
+            sgfh_qty: ['清单数量'], // 施工图复核数量
             dgn_qty1: ['设计数量1'],
             dgn_qty2: ['设计数量2'],
             unit_price: ['单价'],
@@ -247,12 +258,19 @@ class AnalysisExcelTree {
         node.code = row[this.colsDef.code];
         node.name = row[this.colsDef.name];
         node.unit = row[this.colsDef.unit];
-        node.quantity = this.toNumber(row[this.colsDef.quantity]);
+        const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, node.unit);
+        node.sgfh_qty = this.ctx.helper.round(this.toNumber(row[this.colsDef.sgfh_qty]), precision.value);
         node.dgn_qty1 = this.toNumber(row[this.colsDef.dgn_qty1]);
         node.dgn_qty2 = this.toNumber(row[this.colsDef.dgn_qty2]);
         node.unit_price = this.toNumber(row[this.colsDef.unit_price]);
         node.drawing_code = row[this.colsDef.drawing_code];
         node.memo = row[this.colsDef.memo];
+        if (node.sgfh_qty && node.unit_price) {
+            node.sgfh_tp = this.ctx.helper.round(this.ctx.helper.times(node.sgfh_qty, node.unit_price), this.ctx.tender.info.decimal.tp);
+        } else {
+            node.sgfh_tp = null;
+        }
+        node.quantity = node.sgfh_qty;
         if (node.quantity && node.unit_price) {
             node.total_price = this.ctx.helper.round(this.ctx.helper.times(node.quantity, node.unit_price), this.ctx.tender.info.decimal.tp);
         } else {
@@ -271,10 +289,17 @@ class AnalysisExcelTree {
         node.b_code = row[this.colsDef.b_code];
         node.name = row[this.colsDef.name];
         node.unit = row[this.colsDef.unit];
-        node.quantity = this.toNumber(row[this.colsDef.quantity]);
+        const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, node.unit);
+        node.sgfh_qty = this.ctx.helper.round(this.toNumber(row[this.colsDef.sgfh_qty]), precision.value);
         node.unit_price = this.toNumber(row[this.colsDef.unit_price]);
         node.drawing_code = row[this.colsDef.drawing_code];
         node.memo = row[this.colsDef.memo];
+        if (node.sgfh_qty && node.unit_price) {
+            node.sgfh_tp = this.ctx.helper.round(this.ctx.helper.times(node.sgfh_qty, node.unit_price), this.ctx.tender.info.decimal.tp);
+        } else {
+            node.sgfh_tp = null;
+        }
+        node.quantity = node.sgfh_qty;
         if (node.quantity && node.unit_price) {
             node.total_price = this.ctx.helper.round(this.ctx.helper.times(node.quantity, node.unit_price), this.ctx.tender.info.decimal.tp);
         } else {
@@ -291,7 +316,7 @@ class AnalysisExcelTree {
     _loadPos(row) {
         const pos = {};
         pos.name = row[this.colsDef.name];
-        pos.quantity = this.toNumber(row[this.colsDef.quantity]);
+        pos.sgfh_qty = this.toNumber(row[this.colsDef.sgfh_qty]);
         pos.drawing_code = row[this.colsDef.drawing_code];
         return this.cacheTree.addPos(pos);
     }

+ 34 - 13
app/public/js/ledger.js

@@ -28,9 +28,9 @@ $(document).ready(function() {
         preUrl: '/tender/' + getTenderId() + '/ledger',
     };
     if (checkTzMeasureType()) {
-        treeSetting.calcFields = ['total_price'];
+        treeSetting.calcFields = ['sgfh_tp', 'sjcl_tp', 'qtcl_tp', 'total_price'];
     } else {
-        treeSetting.calcFields = ['deal_tp', 'total_price'];
+        treeSetting.calcFields = ['deal_tp', 'sgfh_tp', 'sjcl_tp', 'qtcl_tp', 'total_price'];
     }
     treeSetting.calcFun = function (node) {
         node.dgn_price = ZhCalc.round(ZhCalc.divide(node.total_price, node.dgn_qty1), 2);
@@ -307,7 +307,9 @@ $(document).ready(function() {
                 }
                 // 台账模式,检查部位明细相关
                 if (checkTzMeasureType()) {
-                    if (col.field === 'quantity' || col.field === 'total_price') {
+                    if (col.field === 'sgfh_qty' || col.field === 'sgfh_tp' ||
+                        col.field === 'sjcl_qty' || col.field === 'sjcl_tp' ||
+                        col.field === 'qtcl_qty' || col.field === 'qtcl_tp') {
                         if (!node.children || node.children.length ===0) {
                             const lPos = pos.getLedgerPos(node.id);
                             if (lPos && lPos.length > 0) {
@@ -362,12 +364,24 @@ $(document).ready(function() {
                             const curCol = info.cellRange.col + iCol;
                             const colSetting = info.sheet.zh_setting.cols[curCol];
                             const value = info.sheet.getText(curRow, curCol).replace('\n', '');
-                            if (colSetting.field === 'b_code' && value === '') {
-                                if (!bHint) {
-                                    toast('清单含有部位明细,请先删除部位明细,再删除清单编号', 'warning');
-                                    bHint = true;
+                            const lPos = pos.getLedgerPos(node.id);
+                            if (lPos && lPos.length > 0) {
+                                if (value === '' && colSetting.field === 'b_code') {
+                                    if (!bHint) {
+                                        toast('清单含有部位明细,请先删除部位明细,再删除清单编号', 'warning');
+                                        bHint = true;
+                                    }
+                                    continue;
+                                }
+                                if (colSetting.field === 'sgfh_qty' || colSetting.field === 'sgfh_tp' ||
+                                    colSetting.field === 'sjcl_qty' || colSetting.field === 'sjcl_tp' ||
+                                    colSetting.field === 'qtcl_qty' || colSetting.field === 'qtcl_tp') {
+                                    if (!bHint) {
+                                        toast('清单含有部位明细,数量金额根据部位明细汇总计算所得,不可编辑', 'warning');
+                                        bHint = true;
+                                    }
+                                    continue;
                                 }
-                                continue;
                             }
                             data[colSetting.field] = value;
                             bPaste = true;
@@ -379,7 +393,6 @@ $(document).ready(function() {
                         }
                     }
                 }
-                console.log(JSON.stringify(datas));
                 if (datas.length > 0) {
                     info.sheet.zh_tree.update('/tender/' + getTenderId() + '/ledger/update', datas, function (result) {
                         if (result.update) {
@@ -387,10 +400,10 @@ $(document).ready(function() {
                         }
                         treeOperationObj.refreshTree(info.sheet, result);
                     }, function () {
-                        SpreadJsObj.reLoadRowData(sheet, info.cellRange.row, info.cellRange.rowCount);
+                        SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
                     });
                 } else {
-                    treeOperationObj.refreshTree(info.sheet, info.cellRange.row, info.cellRange.rowCount);
+                    SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
                 }
             }
         },
@@ -414,11 +427,17 @@ $(document).ready(function() {
                         const data = sheet.zh_tree.getNodeKeyData(node);
                         for (let iCol = sel.col; iCol < sel.col + sel.colCount; iCol++) {
                             const col = sheet.zh_setting.cols[iCol];
-                            if (col.field === 'b_code') {
+                            if (col.field === 'b_code' || col.field === 'sgfh_qty' || col.field === 'sgfh_tp' ||
+                                col.field === 'sjcl_qty' || col.field === 'sjcl_tp' ||
+                                col.field === 'qtcl_qty' || col.field === 'qtcl_tp') {
                                 const lPos = pos.getLedgerPos(node.id);
                                 if (lPos && lPos.length > 0) {
                                     if (!bHint) {
-                                        toast('清单含有部位明细,请先删除部位明细,再删除清单编号', 'warning');
+                                        if (col.field === 'code') {
+                                            toast('清单含有部位明细,请先删除部位明细,再删除清单编号', 'warning');
+                                        } else {
+                                            toast('清单含有部位明细,数量金额根据部位明细汇总计算所得,不可删除', 'warning');
+                                        }
                                         bHint = true;
                                     }
                                     continue;
@@ -855,6 +874,8 @@ $(document).ready(function() {
                     treeOperationObj.refreshTree(ledgerSpread.getActiveSheet(), loadResult);
                     posOperationObj.loadCurPosData();
                     treeOperationObj.refreshOperationValid(ledgerSpread.getActiveSheet());
+                }, function () {
+                    SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
                 });
             }
         },

+ 41 - 2
app/public/js/path_tree.js

@@ -1025,6 +1025,42 @@ const createNewPathTree = function (type, setting) {
          * @return {Array} 加载到树的数据
          * @privateA
          */
+        _updateData (datas) {
+            datas = datas instanceof Array ? datas : [datas];
+            let loadedData = [];
+            for (const data of datas) {
+                let node = this.getItems(data[this.setting.id]);
+                if (node) {
+                    for (const prop in node) {
+                        if (prop === this.setting.pid && data[prop] !== node[prop]) {
+
+                        }
+                        if (data[prop] !== undefined && data[prop] !== node[prop]) {
+                            if (prop === this.setting.pid) {
+                                loadedData.push(this.getItems(node[this.setting.pid]));
+                                loadedData.push(this.getItems(data[this.setting.pid]));
+                            }
+                            node[prop] = data[prop];
+                        }
+                    }
+                    loadedData.push(node);
+                }
+            }
+            loadedData = _.uniq(loadedData);
+            for (const node of loadedData) {
+                node.children = this.getChildren(node);
+                node.expanded = node.children.length === 0 ? true : node.children[0].visible;
+            }
+            this.sortTreeNode(true);
+            return loadedData;
+        };
+
+        /**
+         * 加载数据(动态),只加载不同部分
+         * @param {Array} datas
+         * @return {Array} 加载到树的数据
+         * @privateA
+         */
         _updateStageData (datas) {
             datas = datas instanceof Array ? datas : [datas];
             const loadedData = [];
@@ -1073,8 +1109,11 @@ const createNewPathTree = function (type, setting) {
          */
         loadPostStageData(data) {
             let result, parents = [];
-            if (data) {
-                result = this._updateStageData(data);
+            if (data.bills) {
+                this._updateData(data.bills);
+            }
+            if (data.curStageData) {
+                result = this._updateStageData(data.curStageData);
                 this._getNodesParents(parents, result);
             }
             result = result ? result.concat(parents) : parents;

+ 13 - 8
app/public/js/stage.js

@@ -18,7 +18,6 @@ function checkTzMeasureType () {
 function customColDisplay () {
     const defaultSetting = [
         { title: '签约合同', fields: ['deal_qty', 'deal_tp'], visible: true },
-        { title: '施工图复核', fields: ['quantity', 'total_price'], visible: true },
         { title: '本期计量合同', fields: ['contract_qty', 'contract_tp'], visible: true },
         { title: '本期数量变更', fields: ['qc_qty', 'qc_tp', 'qc_bgl'], visible: true },
         { title: '本期完成计量', fields: ['gather_qty', 'gather_tp'], visible: true },
@@ -29,7 +28,7 @@ function customColDisplay () {
         { title: '累计完成率(%)', fields: ['percent'], visible: true },
         { title: '备注', fields: ['memo'], visible: true },
     ];
-    const settingStr = Cookies.get('stage-col-visible');
+    const settingStr = Cookies.get('stage-col-visible-1.0.0');
     return settingStr ? JSON.parse(settingStr) : defaultSetting;
 }
 
@@ -622,7 +621,7 @@ $(document).ready(() => {
                         toast('部位名称不可为空', 'error', 'exclamation-circle');
                         info.cancel = true;
                         return;
-                    } else if (!pos) {
+                    } else if (!posData) {
                         if (info.editingText !== '') {
                             data.updateType = 'add';
                             data.updateData = {name: info.editingText, lid: node.id, tid: tender.id};
@@ -631,7 +630,7 @@ $(document).ready(() => {
                         }
                     } else {
                         data.updateType = 'update';
-                        data.updateData = {id: posData.id, name: info.editingText};
+                        data.updateData = {pid: posData.id, lid: posData.lid, name: info.editingText};
                     }
                 } else if (!posData) {
                     toast('新增部位请先输入名称', 'warning');
@@ -646,8 +645,8 @@ $(document).ready(() => {
                         stagePos.updateDatas(result.pos.pos);
                         stagePos.loadCurStageData(result.pos.curStageData);
                     }
-                    const nodes = stageTree.loadPostStageData(result.ledger.curStageData);
-                    stageTreeSpreadObj.refreshTreeNodes(slSpread.getActiveSheet(), nodes);
+                    const refreshData = stageTree.loadPostStageData(result.ledger);
+                    stageTreeSpreadObj.refreshTreeNodes(slSpread.getActiveSheet(), refreshData);
                     stagePosSpreadObj.loadCurPosData();
                 }, function () {
                     stagePosSpreadObj.loadCurPosData();
@@ -662,6 +661,9 @@ $(document).ready(() => {
                 const sortData = info.sheet.zh_data;
                 const range = info.cellRange;
                 const validField = ['contract_qty', 'qc_qty', 'postil'];
+                if (!checkTzMeasureType()) {
+                    validField.push('name', 'sgfh_qty', 'sjcl_qty', 'qtcl_qty');
+                }
                 for (let iCol = range.col; iCol < range.col + range.colCount; iCol++) {
                     const col = info.sheet.zh_setting.cols[iCol];
                     if (validField.indexOf(col.field) === -1) {
@@ -734,7 +736,7 @@ $(document).ready(() => {
                         stagePos.updateDatas(result.pos.pos);
                         stagePos.loadCurStageData(result.pos.curStageData);
                     }
-                    const nodes = stageTree.loadPostStageData(result.ledger.curStageData);
+                    const nodes = stageTree.loadPostStageData(result.ledger);
                     stageTreeSpreadObj.refreshTreeNodes(slSpread.getActiveSheet(), nodes);
                     stagePosSpreadObj.loadCurPosData();
                 }, function () {
@@ -779,7 +781,7 @@ $(document).ready(() => {
                             stagePos.updateDatas(result.pos.pos);
                             stagePos.loadCurStageData(result.pos.curStageData);
                         }
-                        const nodes = stageTree.loadPostStageData(result.ledger.curStageData);
+                        const nodes = stageTree.loadPostStageData(result.ledger);
                         stageTreeSpreadObj.refreshTreeNodes(slSpread.getActiveSheet(), nodes);
                         // todo 只加载改变项
                         stagePosSpreadObj.loadCurPosData();
@@ -819,6 +821,9 @@ $(document).ready(() => {
     spSpread.bind(spreadNS.Events.ClipboardPasted, stagePosSpreadObj.clipboardPasted);
     spSpread.bind(spreadNS.Events.EditStarting, stagePosSpreadObj.editStarting);
     SpreadJsObj.addDeleteBind(spSpread, stagePosSpreadObj.deletePress);
+    if (!checkTzMeasureType()) {
+
+    }
 
     $('#row-view').on('show.bs.modal', function () {
         const html = [], customDisplay = customColDisplay();

+ 2 - 2
app/public/js/tender.js

@@ -96,6 +96,7 @@ function loadDealProperty () {
 // 显示设置
 function loadDisplayProperty () {
     $('#ledger-dgn-qty')[0].checked = property.display.ledger.dgnQty;
+    $('#ledger-cl-qty')[0].checked = property.display.ledger.clQty;
 }
 // 设置某个div下全部的input、select是否只读
 function setReadOnly(obj, readOnly) {
@@ -464,11 +465,10 @@ $(document).ready(function() {
     $('#post-5').click(() => {
         const prop = {
             display: {
-                ledger: { dgnQty: $('#ledger-dgn-qty')[0].checked, },
+                ledger: { dgnQty: $('#ledger-dgn-qty')[0].checked, clQty: $('#ledger-cl-qty')[0].checked, },
             },
         };
         const tenderId = window.location.pathname.split('/')[2];
-        console.log(prop);
         postData('/tender/' + tenderId + '/save', prop, function (data) {
             setReadOnly('#v-pills-5', true);
             property.display = data.display;

+ 43 - 38
app/service/ledger.js

@@ -22,10 +22,10 @@ const keyFields = {
 };
 // 以下字段仅可通过树结构操作改变,不可直接通过update方式从接口提交,发现时过滤
 const readOnlyFields = ['id', 'tender_id', 'ledger_id', 'ledger_pid', 'order', 'level', 'full_path', 'is_leaf'];
-const calcFields = ['quantity', 'unit_price', 'total_price', 'deal_qty', 'deal_tp', 'dgn_qty1', 'dgn_qty2'];
+const calcFields = ['unit_price', 'sgfh_qty', 'sgfh_tp', 'sjcl_qty', 'sjcl_tp', 'qtcl_qty', 'qtcl_tp', 'deal_qty', 'deal_tp', 'dgn_qty1', 'dgn_qty2'];
 const upFields = ['unit_price'];
-const qtyFields = ['quantity', 'deal_qty', 'dgn_qty1', 'dgn_qty2'];
-const tpFields = ['total_price', 'deal_tp'];
+const qtyFields = ['sgfh_qty', 'sjcl_qty', 'qtcl_qty', 'quantity', 'deal_qty', 'dgn_qty1', 'dgn_qty2'];
+const tpFields = ['sgfh_tp', 'sjcl_tp', 'qtcl_tp', 'total_price', 'deal_tp'];
 const rootId = -1;
 const keyPre = 'tender_node_maxId:';
 
@@ -1647,8 +1647,10 @@ module.exports = app => {
                     }
                     let updateData;
                     if (row.unit) {
-                        if (!row.quantity) { row.quantity = updateNode.quantity; }
-                        if (!row.deal_qty) { row.deal_qty = updateNode.deal_qty; }
+                        if (row.sgfh_qty === undefined) { row.sgfh_qty = updateNode.sgfh_qty; }
+                        if (row.sjcl_qty === undefined) { row.sjcl_qty = updateNode.sjcl_qty; }
+                        if (row.qtcl_qty === undefined) { row.qtcl_qty = updateNode.qtcl_qty; }
+                        if (row.deal_qty === undefined) { row.deal_qty = updateNode.deal_qty; }
                     }
                     if (row.b_code) {
                         row.dgn_qty1 = null;
@@ -1661,36 +1663,35 @@ module.exports = app => {
                         this.ctx.helper.checkFieldPrecision(calcData, qtyFields, precision.value);
                         // 单位保留小数位数
                         this.ctx.helper.checkFieldPrecision(calcData, upFields, info.decimal.up);
+                        // 未提交单价则读取数据库单价
+                        if (row.unit_price === undefined) calcData.unit_price = updateNode.unit_price;
                         // 计算
-                        if (row.quantity !== undefined) {
-                            if (row.unit_price  !== undefined) {
-                                calcData.total_price = this.ctx.helper.round(
-                                    this.ctx.helper.times(calcData.quantity, calcData.unit_price), info.decimal.tp);
-                            } else {
-                                calcData.total_price = this.ctx.helper.round(
-                                    this.ctx.helper.times(calcData.quantity, updateNode.unit_price), info.decimal.tp);
-                            }
-                        } else if (row.unit_price !== undefined) {
-                            calcData.total_price = this.ctx.helper.round(
-                                this.ctx.helper.times(updateNode.quantity, calcData.unit_price), info.decimal.tp);
-                        }
-                        if (row.total_price !== undefined) {
-                            calcData.quantity = null;
-                        }
-                        if (row.deal_qty !== undefined) {
-                            if (row.unit_price !== undefined) {
-                                calcData.deal_tp = this.ctx.helper.round(
-                                    this.ctx.helper.times(calcData.deal_qty, calcData.unit_price), info.decimal.tp);
-                            } else {
-                                calcData.deal_tp = this.ctx.helper.round(
-                                    this.ctx.helper.times(calcData.deal_qty, updateNode.unit_price), info.decimal.tp);
-                            }
-                        } else if (row.unit_price !== undefined) {
+                        if (row.sgfh_qty !== undefined || row.sjcl_qty !== undefined || row.qtcl_qty !== undefined ||
+                            row.deal_qty !== undefined || row.unit_price) {
+                            if (row.sgfh_qty === undefined) calcData.sgfh_qty = updateNode.sgfh_qty;
+                            if (row.sjcl_qty === undefined) calcData.sjcl_qty = updateNode.sjcl_qty;
+                            if (row.qtcl_qty === undefined) calcData.qtcl_qty = updateNode.qtcl_qty;
+                            if (row.deal_qty === undefined) calcData.deal_qty = updateNode.deal_qty;
+                            calcData.quantity = this.ctx.helper.sum([calcData.sgfh_qty, calcData.sjcl_qty, calcData.qtcl_qty]);
+                            calcData.sgfh_tp = this.ctx.helper.round(
+                                this.ctx.helper.times(calcData.sgfh_qty, calcData.unit_price), info.decimal.tp);
+                            calcData.sjcl_tp = this.ctx.helper.round(
+                                this.ctx.helper.times(calcData.sjcl_qty, calcData.unit_price), info.decimal.tp);
+                            calcData.qtcl_tp = this.ctx.helper.round(
+                                this.ctx.helper.times(calcData.qtcl_qty, calcData.unit_price), info.decimal.tp);
                             calcData.deal_tp = this.ctx.helper.round(
-                                this.ctx.helper.times(updateNode.deal_qty, calcData.unit_price), info.decimal.tp);
-                        }
-                        if (row.deal_tp !== undefined) {
+                                this.ctx.helper.times(calcData.deal_qty, calcData.unit_price), info.decimal.tp);
+                        } else if (row.sgfh_tp !== undefined || row.sjcl_tp !== undefined || row.qtcl_tp !== undefined || row.deal_tp !== undefined) {
+                            calcData.sgfh_qty = null;
+                            calcData.sjcl_qty = null;
+                            calcData.qtcl_qty = null;
+                            calcData.quantity = null;
                             calcData.deal_qty = null;
+                            calcData.sgfh_tp = (row.sgfh_tp !== undefined) ? this.ctx.helper.round(calcData.row.sgfh_tp, info.decimal.tp) : updateNode.sgfh_tp;
+                            calcData.sjcl_tp = (row.sgfh_tp !== undefined) ? this.ctx.helper.round(calcData.row.sjcl_tp, info.decimal.tp) : updateNode.sjcl_tp;
+                            calcData.qtcl_tp = (row.sgfh_tp !== undefined) ? this.ctx.helper.round(calcData.row.qtcl_tp, info.decimal.tp) : updateNode.qtcl_tp;
+                            calcData.total_price = this.ctx.helper.sum([calcData.sgfh_tp, calcData.sjcl_tp, calcData.qtcl_tp]);
+                            calcData.qtcl_tp = (row.deal_tp !== undefined) ? this.ctx.helper.round(calcData.row.deal_tp, info.decimal.tp) : updateNode.deal_tp;
                         }
                         updateData = this._filterUpdateInvalidField(updateNode.id, calcData);
                     } else {
@@ -1824,11 +1825,11 @@ module.exports = app => {
                         unit_price: data[i].price,
                     };
                     qd.full_path = selectData.full_path + '.' + qd.ledger_id;
-                    const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, qd.unit);
                     const insertResult = await this.transaction.insert(this.tableName, qd);
                     qd.id = insertResult.insertId;
                     newIds.push(insertResult.insertId);
                     if (data[i].pos.length > 0) {
+                        console.log(qd);
                         await this.ctx.service.pos.insertLedgerPosData(this.transaction, tenderId, qd, data[i].pos);
                         await this._calcNode(qd, this.transaction);
                     }
@@ -1898,8 +1899,6 @@ module.exports = app => {
                         unit_price: data[i].price,
                     };
                     qd.full_path = parentData.full_path + '.' + qd.ledger_id;
-                    const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, qd.unit);
-                    this.ctx.helper.checkFieldPrecision(qd, qtyFields, precision.value);
                     const insertResult = await this.transaction.insert(this.tableName, qd);
                     qd.id = insertResult.insertId;
                     newIds.push(insertResult.insertId);
@@ -1933,10 +1932,16 @@ module.exports = app => {
             const info = this.ctx.tender.info;
             const precision = this.ctx.helper.findPrecision(info.precision, node.unit);
 
-            const calcQtySql = 'SELECT SUM(`quantity`) As quantity FROM ?? WHERE `lid` = ?';
+            const calcQtySql = 'SELECT SUM(`sgfh_qty`) As `sgfh_qty`, SUM(`sjcl_qty`) As `sjcl_qty`, SUM(`qtcl_qty`) As `qtcl_qty`, SUM(`quantity`) As `quantity` FROM ?? WHERE `lid` = ?';
             const data = await transaction.queryOne(calcQtySql, [this.ctx.service.pos.tableName, node.id]);
             data.id = node.id;
+            data.sgfh_qty = this.round(data.sgfh_qty, precision.value);
+            data.sjcl_qty = this.round(data.sjcl_qty, precision.value);
+            data.qtcl_qty = this.round(data.qtcl_qty, precision.value);
             data.quantity = this.round(data.quantity, precision.value);
+            data.sgfh_tp = this.round(this.ctx.helper.times(data.sgfh_qty, node.unit_price), info.decimal.tp);
+            data.sjcl_tp = this.round(this.ctx.helper.times(data.sjcl_qty, node.unit_price), info.decimal.tp);
+            data.qtcl_tp = this.round(this.ctx.helper.times(data.qtcl_qty, node.unit_price), info.decimal.tp);
             data.total_price = this.round(this.ctx.helper.times(data.quantity, node.unit_price), info.decimal.tp);
             const result = await transaction.update(this.tableName, data);
         }
@@ -1986,6 +1991,8 @@ module.exports = app => {
                 b_code: node.b_code,
                 name: node.name,
                 unit: node.unit,
+                sgfh_qty: node.sgfh_qty,
+                sgfh_tp: node.sgfh_tp,
                 quantity: node.quantity,
                 unit_price: node.unit_price,
                 total_price: node.total_price,
@@ -1994,8 +2001,6 @@ module.exports = app => {
                 memo: node.memo,
                 drawing_code: node.drawing_code,
             };
-            const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, data.unit);
-            this.ctx.helper.checkFieldPrecision(data, qtyFields, precision.value);
             const result = await transaction.insert(this.tableName, data);
             data.id = result.insertId;
             if (node.children && node.children.length > 0) {

+ 65 - 19
app/service/pos.js

@@ -25,10 +25,21 @@ module.exports = app => {
         async getPosData(condition) {
             return await this.db.select(this.tableName, {
                 where: condition,
-                columns: ['id', 'tid', 'lid', 'name', 'quantity', 'drawing_code'],
+                columns: ['id', 'tid', 'lid', 'name', 'quantity', 'drawing_code', 'sgfh_qty', 'sjcl_qty', 'qtcl_qty'],
             });
         }
 
+        async getPosDataByIds(ids) {
+            this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('id', {
+                operate: 'in',
+                value: ids
+            });
+            this.sqlBuilder.columns = ['id', 'tid', 'lid', 'name', 'quantity', 'drawing_code', 'sgfh_qty', 'sjcl_qty', 'qtcl_qty'];
+            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName)
+            return await this.db.query(sql, sqlParam);
+        }
+
         async _insertPosData(transaction, data, tid) {
             data.tid = tid;
             // todo 新增期
@@ -69,10 +80,25 @@ module.exports = app => {
                     const orgPos = await this.getPosData({tid: tid, id: this._.map(datas, 'id')});
                     for (const d of datas) {
                         const op = this._.find(orgPos, function (p) { return p.id = d.id; });
-                        if (d.quantity) {
+                        if (d.sgfh_qty !== undefined || d.qtcl_qty !== undefined || d.sjcl_qty !== undefined) {
                             const bills = await this.ctx.service.ledger.getDataById(op.lid);
                             const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
-                            d.quantity = this.round(d.quantity, precision.value);
+                            if (d.sgfh_qty !== undefined) {
+                                d.sgfh_qty = this.round(d.sgfh_qty, precision.value);
+                            } else if (op) {
+                                d.sgfh_qty = op.sgfh_qty;
+                            }
+                            if (d.sjcl_qty !== undefined) {
+                                d.sjcl_qty = this.round(d.sjcl_qty, precision.value);
+                            } else if (op) {
+                                d.sjcl_qty = op.sjcl_qty;
+                            }
+                            if (d.qtcl_qty) {
+                                d.qtcl_qty = this.round(d.qtcl_qty, precision.value);
+                            } else if (op) {
+                                d.qtcl_qty = op.qtcl_qty;
+                            }
+                            d.quantity = this.ctx.helper.sum([d.sgfh_qty, d.qtcl_qty, d.sjcl_qty]);
                         }
                         await transaction.update(this.tableName, d, {tid: tid, id: d.id});
                         if (d.quantity !== undefined && op && (result.ledger.update.indexOf(op.lid) === -1)) {
@@ -119,24 +145,42 @@ module.exports = app => {
 
             const transaction = await this.db.beginTransaction();
             const result = { ledger: {}, pos: null }, updateLid = [];
+            const orgPos = await this.getPosData({tid: tid, id: this._.map(data, 'id')});
+            let bills = null, precision = null;
             try {
                 for (const d of data) {
-                    if (d.quantity) {
-                        const bills = await this.ctx.service.ledger.getDataById(d.lid);
-                        const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
-                        d.quantity = this.round(d.quantity, precision.value);
-                        if (updateLid.indexOf(d.lid) === -1) {
+                    const op = d.id ? this._.find(orgPos, {id: d.id}) : null;
+                    if (d.sgfh_qty || d.sjcl_qty || d.qtcl_qty) {
+                        if (!bills || bills.id !== d.lid) {
+                            bills = await this.ctx.service.ledger.getDataById(d.lid);
+                            precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
                             updateLid.push(d.lid);
                         }
+                        if (d.sgfh_qty !== undefined) {
+                            d.sgfh_qty = this.round(d.sgfh_qty, precision.value);
+                        } else if (op) {
+                            d.sgfh_qty = op.sgfh_qty;
+                        }
+                        if (d.sjcl_qty !== undefined) {
+                            d.sjcl_qty = this.round(d.sjcl_qty, precision.value);
+                        } else if (op) {
+                            d.sjcl_qty = op.sjcl_qty;
+                        }
+                        if (d.qtcl_qty) {
+                            d.qtcl_qty = this.round(d.qtcl_qty, precision.value);
+                        } else if (op) {
+                            d.qtcl_qty = op.qtcl_qty;
+                        }
+                        d.quantity = this.ctx.helper.sum([d.sgfh_qty, d.qtcl_qty, d.sjcl_qty]);
                     }
                     if (d.id) {
                         await transaction.update(this.tableName, d);
                     } else {
                         this._insertPosData(transaction, d, tid);
                     }
-                    for (const lid of updateLid) {
-                        await this.ctx.service.ledger.calc(tid, lid, transaction);
-                    }
+                }
+                for (const lid of updateLid) {
+                    await this.ctx.service.ledger.calc(tid, lid, transaction);
                 }
                 await transaction.commit();
             } catch (err) {
@@ -190,18 +234,20 @@ module.exports = app => {
          */
         async insertLedgerPosData(transaction, tid, bills, data) {
             const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
+            const insertDatas = [];
             for (const d of data) {
-                d.tid = tid;
-                d.lid = bills.id;
-                // todo 新增期
-                d.add_stage = 0;
-                d.add_times = 0;
-                d.add_user = this.ctx.session.sessionUser.accountId;
+                const inD = {
+                    tid: tid, lid: bills.id,
+                    add_stage: 0, add_times: 0, add_user: this.ctx.session.sessionUser.accountId,
+                    name: d.name, drawing_code: d.drawing_code,
+                };
                 if (d.quantity) {
-                    d.quantity = this.round(d.quantity, precision.value);
+                    inD.sgfh_qty = this.round(d.quantity, precision.value);
+                    inD.quantity = inD.sgfh_qty;
                 }
+                insertDatas.push(inD);
             }
-            await transaction.insert(this.tableName, data);
+            await transaction.insert(this.tableName, insertDatas);
         }
     }
 

+ 92 - 52
app/service/stage_pos.js

@@ -101,46 +101,62 @@ module.exports = app => {
          * @private
          */
         async _addStagePosData(transaction, data) {
-            const bills = await this.ctx.service.ledger.getDataById(data.lid);
-            const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
-            const  result = {};
-            // 在主表pos中新增数据
-            const p = JSON.parse(JSON.stringify(data.updateData));
-            p.tid = this.ctx.tender.id;
-            p.add_stage = this.ctx.stage.id;
-            p.add_times = this.ctx.stage.curTimes;
-            p.add_user = this.ctx.session.sessionUser.accountId;
-            if (p.contract_qty) { delete p.contract_qty; }
-            if (p.qc_qty) { delete p.qc_qty; }
-            if (p.postil) { delete p.postil; }
-            if (p.quantity) {
-                p.quantity = this.round(p.quantity, precision.value);
+            let bills , precision;
+            const  result = {pos: [], ledger: []};
+            const datas = data instanceof Array ? data : [data], calcBills = [], calcStageBills = [];
+
+            for (const d of datas) {
+                if (d.sgfh_qty !== undefined || d.sjcl_qty !== undefined || d.qtcl_qty !== undefined) {
+                    if (!bills || bills.id !== data.lid) {
+                        bills = await this.ctx.service.ledger.getDataById(d.lid);
+                        precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
+                    }
+                }
+                // 在主表pos中新增数据
+                const p = {
+                    tid: this.ctx.tender.id, lid: d.lid, name: d.name,
+                    add_stage: this.ctx.stage.id,
+                    add_times: this.ctx.stage.curTimes,
+                    add_user: this.ctx.session.sessionUser.accountId,
+                };
+                if (d.sgfh_qty) p.sgfh_qty = this.round(d.sgfh_qty, precision.value);
+                if (d.sjcl_qty) p.sjcl_qty = this.round(d.sjcl_qty, precision.value);
+                if (d.qtcl_qty) p.qtcl_qty = this.round(d.qtcl_qty, precision.value);
+                p.quantity = this.ctx.helper.sum([p.sgfh_qty, p.sjcl_qty, p.qtcl_qty]);
+                const addRst = await transaction.insert(this.ctx.service.pos.tableName, p);
+                p.id = addRst.insertId;
+                result.pos.push(p.id);
+                // 如果存在复核数据,更新计算主表清单
+                if (p.sgfh_qty || p.sjcl_qty || p.qtcl_qty) {
+                    calcBills.push(p.lid);
+                    result.ledger.push(p.lid);
+                }
+                // 如果存在本期计算数据,更新计算清单本期计量数据
+                if (d.contract_qty || d.qc_qty || d.postil) {
+                    const ps = {
+                        pid: d.id,
+                        lid: d.lid,
+                        tid: this.ctx.tender.id,
+                        sid: this.ctx.stage.id,
+                        said: this.ctx.session.sessionUser.accountId,
+                        times: this.ctx.stage.curTimes,
+                        order: this.ctx.stage.curOrder,
+                    };
+                    if (d.contract_qty) ps.contract_qty = this.round(d.contract_qty, precision.value);
+                    if (d.qc_qty) ps.qc_qty = this.round(d.qc_qty, precision.value);
+                    if (d.postil) ps.postil = d.postil;
+                    await transaction.insert(ps);
+                    if (d.contract_qty || d.qc_qty) {
+                        calcStageBills.push(ps.lid);
+                    }
+                    result.stageUpdate = true;
+                }
             }
-            const addRst = await transaction.insert(this.ctx.service.pos.tableName, data.updateData);
-            p.id = addRst.insertId;
-            result.pos = p.id;
-            // 如果存在复核数据,更新计算主表清单
-            if (p.quantity) {
-                await this.ctx.service.ledger.calc(this.ctx.tender.id, p.lid, transaction);
-                result.ledger = p.lid;
+            for (const lid of calcBills) {
+                await this.ctx.service.ledger.calc(this.ctx.tender.id, lid, transaction);
             }
-            // 如果存在本期计算数据,更新计算清单本期计量数据
-            if (data.contract_qty || data.qc_qty || data.postil) {
-                const ps = {
-                    pid: p.id,
-                    lid: p.lid,
-                    tid: this.ctx.tender.id,
-                    sid: this.ctx.stage.id,
-                    said: this.ctx.session.sessionUser.accountId,
-                    times: this.ctx.stage.curTimes,
-                    order: this.ctx.stage.curOrder,
-                };
-                if (data.contract_qty) { ps.contract_qty = this.round(data.contract_qty, precision.value); }
-                if (data.qc_qty) { ps.qc_qty = this.round(data.qc_qty, precision.value); }
-                if (data.postil) { ps.postil = data.postil; }
-                await transaction.insert(ps);
-                await this.ctx.service.stageBills.calc(ctx.tender.id, ctx.stage.id, ps.lid, transaction);
-                result.stageUpdate = true;
+            for (const lid of calcStageBills) {
+                await this.ctx.service.stageBills.calc(ctx.tender.id, ctx.stage.id, lid, transaction);
             }
             return result;
         }
@@ -155,33 +171,57 @@ module.exports = app => {
          */
         async _updateStagePosData(transaction, data) {
             let bills, precision;
-            const result = {ledger: [], pos: [], stageUpdate: true};
+            const result = {ledger: [], pos: [], stageUpdate: true}, ledgerCalc = [];
             const datas = data instanceof Array ? data : [data];
+            const orgPos = await this.ctx.service.pos.getPosDataByIds(this._.map(datas, 'pid'));
             const orgStagePos = await this.getLastestStageData(this.ctx.tender.id, this.ctx.stage.id, this._.map(datas, 'pid'));
             for (const d of datas) {
-                const osp = this._.find(orgStagePos, function (p) { return p.pid === d.pid; });
-                if (d.contract_qty || d.qc_qty) {
+                if (d.sgfh_qty || d.qtcl_qty || d.sjcl_qty || d.contract_qty || d.qc_qty) {
                     if (!bills || bills.id !== data.lid) {
                         bills = await this.ctx.service.ledger.getDataById(d.lid);
                         precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, bills.unit);
                     }
-                    this.ctx.helper.checkFieldPrecision(d, this.qtyFields, precision.value);
                 }
-                if (osp && osp.times === this.ctx.stage.curTimes && osp.order === this.ctx.stage.curOrder) {
-                    await transaction.update(this.tableName, d, {where: {id: osp.id}});
-                } else {
-                    d.tid = this.ctx.tender.id;
-                    d.sid = this.ctx.stage.id;
-                    d.said = this.ctx.session.sessionUser.accountId;
-                    d.times = this.ctx.stage.curTimes;
-                    d.order = this.ctx.stage.curOrder;
-                    await transaction.insert(this.tableName, d);
+                if (d.name !== undefined || d.sgfh_qty !== undefined || d.qtcl_qty !== undefined || d.sjcl_qty !== undefined) {
+                    const p = {id: d.pid};
+                    if (d.name !== undefined) p.name = d.name;
+                    if (d.sgfh_qty !== undefined || d.qtcl_qty !== undefined || d.sjcl_qty !== undefined) {
+                        const op = this._.find(orgPos, {id: d.pid});
+                        p.sgfh_qty = d.sgfh_qty !== undefined ? d.sgfh_qty : op.sgfh_qty;
+                        p.sjcl_qty = d.sjcl_qty !== undefined ? d.sjcl_qty : op.sjcl_qty;
+                        p.qtcl_qty = d.qtcl_qty !== undefined ? d.qtcl_qty : op.qtcl_qty;
+                        p.quantity = this.ctx.helper.sum([p.sgfh_qty, p.sjcl_qty, p.qtcl_qty]);
+                        if (ledgerCalc.indexOf(op.lid) === -1) {
+                            ledgerCalc.push(op.lid);
+                        }
+                    }
+                    await transaction.update(this.ctx.service.pos.tableName, p);
+                }
+
+                if (d.contract_qty !== undefined || d.qc_qty !== undefined || d.postil !== undefined) {
+                    const sp = {pid: d.pid, lid: d.lid, contract_qty: d.contract_qty, qc_qty: d.qc_qty, postil: d.postil};
+                    const osp = this._.find(orgStagePos, function (p) { return p.pid === d.pid; });
+                    this.ctx.helper.checkFieldPrecision(sp, this.qtyFields, precision.value);
+                    if (osp && osp.times === this.ctx.stage.curTimes && osp.order === this.ctx.stage.curOrder) {
+                        await transaction.update(this.tableName, d, {where: {id: osp.id}});
+                    } else {
+                        sp.tid = this.ctx.tender.id;
+                        sp.sid = this.ctx.stage.id;
+                        sp.said = this.ctx.session.sessionUser.accountId;
+                        sp.times = this.ctx.stage.curTimes;
+                        sp.order = this.ctx.stage.curOrder;
+                        await transaction.insert(this.tableName, sp);
+                    }
                 }
                 result.pos.push(d.pid);
-                if ((d.contract_qty === undefined || d.qc_qty === undefined) && (result.ledger.indexOf(d.lid) === -1)) {
+                if ((d.sgfh_qty !== undefined || d.qtcl_qty !== undefined || d.sjcl_qty !== undefined ||
+                        d.contract_qty === undefined || d.qc_qty === undefined) && (result.ledger.indexOf(d.lid) === -1)) {
                     result.ledger.push(d.lid);
                 }
             }
+            for (const lid of ledgerCalc) {
+                await this.ctx.service.ledger.calc(this.ctx.tender.id, lid, transaction);
+            }
             for (const lid of result.ledger) {
                 await this.ctx.service.stageBills.calc(this.ctx.tender.id, this.ctx.stage.id, lid, transaction);
             }

+ 4 - 0
app/view/tender/detail.ejs

@@ -645,6 +645,10 @@
                                                         <input type="checkbox" class="form-check-input" id="ledger-dgn-qty" checked="">
                                                         <label class="form-check-label" for="ledger-dgn-qty">设计数量</label>
                                                     </div>
+                                                    <div class="form-group form-check">
+                                                        <input type="checkbox" class="form-check-input" id="ledger-cl-qty" checked="">
+                                                        <label class="form-check-label" for="ledger-cl-qty">错漏增减</label>
+                                                    </div>
                                                 </div>
                                             </div>
                                         </div>

+ 3 - 0
app/view/tender/manage_modal.ejs

@@ -80,6 +80,9 @@
         <div class="modal-content">
             <div class="modal-header">
                 <h5 class="modal-title">选择计量模式</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
             </div>
             <div class="modal-body">
                 <div class="row">

+ 8 - 1
test/app/lib/analysis_excel.test.js

@@ -107,7 +107,13 @@ describe('test/app/lib/analysis_excel.test.js', () => {
         // 检查第203-1-a的数量
         const xmj = result.codeNodes['1-2-2-1-1'];
         const gcl = xmj.children[0];
-        assert(gcl.quantity === 92954.75);
+        assert(gcl.sgfh_qty === 92954.72);
+        assert(gcl.quantity === 92954.72);
+        // 检查部位明细
+        const pos = result.pos[0];
+        assert(pos.name === 'K0+000-K1+000');
+        assert(pos.sgfh_qty === 11619.34);
+        assert(pos.quantity === 11619.34);
     });
     it('Analysis Excel Test Data And Import', function* () {
         const ctx = app.mockContext(mockData);
@@ -126,6 +132,7 @@ describe('test/app/lib/analysis_excel.test.js', () => {
         assert(result.items.length === 216);
         const xmj = result.codeNodes['1-2-3-1-2'];
         const gcl = xmj.children[0];
+        assert(gcl.sgfh_qty === 0);
         assert(gcl.quantity === 0);
         yield ctx.service.ledger.importExcel(sheetData);
     });

+ 2 - 8
test/app/service/ledger.test.js

@@ -7,7 +7,7 @@
  */
 'use strict';
 
-const excel = require('node-xlsx');
+const excel = require('js-xlsx');
 const _ = require('lodash');
 const mockData = {};
 
@@ -1159,13 +1159,7 @@ describe('test/app/service/ledger.test.js', () => {
         assert(result[0].code === '1-1-3');
     });
 
-    // it('test ImportExcelData', function* () {
-    //     const ctx = app.mockContext(mockData);
-    //
-    //     const file = ctx.app.baseDir + '/test/app/test_file/ledger-upload-test.xls';
-    //     const sheets = excel.parse(file);
-    //     const result = yield ctx.service.
-    // });
+    // 测试导入excel 在\lib\analysis_excel.test.js中进行单元测试
 
     // 小数位数策略示例:
     /*  先加总再保留3位小数:

BIN
test/app/test_file/deal-bills-emptyCalcField.xls