瀏覽代碼

Merge branch 'dev' of http://192.168.1.41:3000/maixinrong/Calculation into dev

Tony Kang 3 年之前
父節點
當前提交
193fbdcb3d
共有 84 個文件被更改,包括 2628 次插入885 次删除
  1. 22 2
      app/const/account_permission.js
  2. 0 18
      app/const/external_data.js
  3. 2 0
      app/const/page_show.js
  4. 12 1
      app/const/spread.js
  5. 12 0
      app/const/tender_info.js
  6. 0 1
      app/controller/ledger_controller.js
  7. 20 4
      app/controller/material_controller.js
  8. 35 0
      app/controller/measure_controller.js
  9. 31 4
      app/controller/revise_controller.js
  10. 2 0
      app/controller/setting_controller.js
  11. 10 1
      app/controller/stage_controller.js
  12. 1 1
      app/extend/helper.js
  13. 71 0
      app/lib/ledger.js
  14. 1 1
      app/lib/pm.js
  15. 298 0
      app/lib/revise_price.js
  16. 1 1
      app/lib/rm/material.js
  17. 3 2
      app/lib/spread_setting.js
  18. 6 4
      app/lib/stage_im.js
  19. 2 0
      app/lib/tender_info.js
  20. 3 1
      app/middleware/material_check.js
  21. 1 0
      app/middleware/revise_check.js
  22. 45 21
      app/public/css/main.css
  23. 2 1
      app/public/js/component/menu.js
  24. 2 1
      app/public/js/ledger.js
  25. 113 111
      app/public/js/material.js
  26. 8 0
      app/public/js/material_audit.js
  27. 10 5
      app/public/js/material_checklist.js
  28. 57 38
      app/public/js/material_exponent.js
  29. 476 387
      app/public/js/material_list.js
  30. 71 0
      app/public/js/path_tree.js
  31. 1 0
      app/public/js/revise.js
  32. 3 2
      app/public/js/revise_compare.js
  33. 437 0
      app/public/js/revise_price.js
  34. 6 0
      app/public/js/setting.js
  35. 4 4
      app/public/js/shares/cs_gcl_gather.js
  36. 13 1
      app/public/js/shares/sjs_setting.js
  37. 7 6
      app/public/js/stage.js
  38. 2 1
      app/public/js/stage_compare.js
  39. 9 7
      app/public/js/stage_gather.js
  40. 10 9
      app/public/js/stage_im.js
  41. 11 1
      app/public/js/stage_pay.js
  42. 37 1
      app/public/js/sub_menu.js
  43. 6 2
      app/router.js
  44. 13 37
      app/service/ledger_history.js
  45. 2 0
      app/service/ledger_revise.js
  46. 9 7
      app/service/material_bills.js
  47. 15 0
      app/service/material_list_notjoin.js
  48. 43 39
      app/service/material_list_self.js
  49. 30 32
      app/service/report_memory.js
  50. 4 2
      app/service/revise_audit.js
  51. 114 0
      app/service/revise_price.js
  52. 24 55
      app/service/rpt_gather_memory.js
  53. 4 0
      app/service/stage.js
  54. 6 0
      app/service/stage_audit.js
  55. 20 0
      app/service/stage_bills_final.js
  56. 79 0
      app/service/stage_bills_pc.js
  57. 8 8
      app/service/stage_change.js
  58. 1 1
      app/service/tender.js
  59. 13 6
      app/service/tender_info.js
  60. 1 1
      app/view/change/project.ejs
  61. 1 1
      app/view/change/project_modal.ejs
  62. 4 1
      app/view/change/sub_menu.ejs
  63. 4 4
      app/view/change/sub_mini_menu.ejs
  64. 1 0
      app/view/material/audit_modal.ejs
  65. 15 13
      app/view/material/exponent.ejs
  66. 1 0
      app/view/material/file.ejs
  67. 13 11
      app/view/material/info.ejs
  68. 4 0
      app/view/material/list.ejs
  69. 5 1
      app/view/material/material_sub_menu.ejs
  70. 4 3
      app/view/material/material_sub_mini_menu.ejs
  71. 43 0
      app/view/revise/price.ejs
  72. 6 3
      app/view/revise/sub_menu.ejs
  73. 1 0
      app/view/revise/sub_menu_list.ejs
  74. 5 5
      app/view/revise/sub_mini_menu.ejs
  75. 16 0
      app/view/setting/fun.ejs
  76. 11 5
      app/view/setting/user_permission_modal.ejs
  77. 18 0
      app/view/stage/manager.ejs
  78. 4 1
      app/view/stage/stage_sub_menu.ejs
  79. 4 4
      app/view/stage/stage_sub_mini_menu.ejs
  80. 6 1
      app/view/tender/detail_modal.ejs
  81. 4 1
      app/view/tender/tender_sub_menu.ejs
  82. 10 4
      app/view/tender/tender_sub_mini_menu.ejs
  83. 20 0
      config/web.js
  84. 179 0
      sql/update.sql

+ 22 - 2
app/const/account_permission.js

@@ -29,10 +29,29 @@ const permission = {
             { title: '创建标段', value: 1 },
             { title: '查阅所有标段', value: 2 },
             { title: '维护签约清单', value: 3, hint: '开启该选项,台账审批通过后,可上传签约清单', hintIcon: 'fa-question-circle' },
-            { title: '变更意向', value: 5, hint: '开启该选项,变更立项可新建变更意向书', hintIcon: 'fa-question-circle' },
-            { title: '材差清单设置', value: 4, hint: '开启该选项,当前账号可设置允许调差的清单', hintIcon: 'fa-question-circle' },
+            { title: '批量设置材差清单', value: 4, show: false, hint: '开启该选项,当前账号可设置允许调差的清单', hintIcon: 'fa-question-circle' },
+            { title: '变更意向', value: 5, show: false, hint: '开启该选项,变更立项可新建变更意向书', hintIcon: 'fa-question-circle' },
             { title: '查看项目管理报表数据', value: 6, hint: '开启该选项,当前账号在报表下可查看项目管理数据', hintIcon: 'fa-question-circle' },
         ],
+        tips: '勾选「创建标段」该用户默认具有「新建标段」及标段内「台账分解」「创建台账修订」「创建计量期」「创建工程变更」的权限。',
+    },
+    change: {
+        class: 'fa fa-retweet',
+        title: '工程变更',
+        type: 'checkbox',
+        children: [
+            { title: '变更意向', value: 1, hint: '开启该选项,变更立项可新建变更意向书', hintIcon: 'fa-question-circle' },
+        ],
+    },
+    material: {
+        class: 'fa fa-line-chart fa-fw',
+        title: '材料调差',
+        type: 'checkbox',
+        children: [
+            { title: '批量设置材差清单', value: 1, hint: '开启该选项,当前账号可设置允许调差的清单', hintIcon: 'fa-question-circle' },
+            { title: '修改调差工料消耗量', value: 2, hint: '开启该选项,可在新材差期修改工料的消耗量', hintIcon: 'fa-question-circle' },
+            // { title: '修改材料税税率', value: 3, hint: '开启该选项,可在新材差期修改材料税税率', hintIcon: 'fa-question-circle' },
+        ],
     },
     // cooperation: {
     //     class: '',
@@ -42,6 +61,7 @@ const permission = {
     //         { title: '启用', value: 1 },
     //         { title: '关闭', value: 0 },
     //     ],
+    //     tips: '启用「协作办公」,则该用户可以为他创建的标段添加其他用户进行协作办公。',
     // },
     project_msg: {
         class: '',

+ 0 - 18
app/const/external_data.js

@@ -1,18 +0,0 @@
-'use strict';
-
-/**
- *
- *
- * @author Mai
- * @date
- * @version
- */
-
-const Tag = {
-    FuLong: {
-        exType: 'fulong',
-        exFields: { wbsCode: 'wbs-code' }
-    }
-};
-
-module.exports = Tag;

+ 2 - 0
app/const/page_show.js

@@ -39,6 +39,8 @@ const defaultSetting = {
     closeWapYfSf: 0,
     openManagement: 0,
     openMaterialChecklist: 0,
+    openMaterialSelf: 0,
+    openMaterialEditForAudit: 0,
     close1stStageCheckDealParam: 0,
     openChangeProject: 0,
     openChangeApply: 0,

+ 12 - 1
app/const/spread.js

@@ -13,6 +13,7 @@ const dgnCols = ['dgn_qty1', 'dgn_qty2', 'dgn_price'];
 const clCols = ['sjcl_qty', 'sjcl_tp', 'qtcl_qty', 'qtcl_tp', 'quantity', 'total_price'];
 const stageDgnCols = ['deal_dgn_qty1', 'deal_dgn_qty2', 'c_dgn_qty1', 'c_dgn_qty2', 'final_dgn_price'];
 const realCompleteCols = ['real_qty', 'estimate_qty'];
+const priceDiffCols = ['org_price', 'pc_tp'];
 const thirdPartyCols = {
     gxby: ['gxby'],
     dagl: ['dagl']
@@ -203,6 +204,8 @@ const stageTz = {
             {title: '本期数量变更|数量', colSpan: '3|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', readOnly: true},
             {title: '|不计价', colSpan: '|1', rowSpan: '|1', field: 'qc_minus_qty', hAlign: 2, width: 60, type: 'Number'},
+            { title: '本期补差|原单价', colSpan: '2|1', rowSpan: '1|1', field: 'org_price', hAlign: 2, width: 60, type: 'Number' },
+            { title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'pc_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'},
@@ -284,6 +287,8 @@ const stageCl = {
             {title: '本期数量变更|数量', colSpan: '3|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', readOnly: true},
             {title: '|不计价', colSpan: '|1', rowSpan: '|1', field: 'qc_minus_qty', hAlign: 2, width: 60, type: 'Number'},
+            { title: '本期补差|原单价', colSpan: '2|1', rowSpan: '1|1', field: 'org_price', hAlign: 2, width: 60, type: 'Number' },
+            { title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'pc_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'},
@@ -367,6 +372,8 @@ const stageNoCl = {
             {title: '|不计价', colSpan: '|1', rowSpan: '|1', field: 'qc_minus_qty', 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: 'org_price', hAlign: 2, width: 60, type: 'Number' },
+            {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'pc_tp', hAlign: 2, width: 60, 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'},
@@ -446,6 +453,8 @@ const stageGather = {
             {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, type: 'Number'},
             {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'gather_tp', hAlign: 2, width: 60, type: 'Number'},
+            { title: '本期补差|原单价', colSpan: '2|1', rowSpan: '1|1', field: 'org_price', hAlign: 2, width: 60, type: 'Number' },
+            { title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'pc_tp', hAlign: 2, width: 60, type: 'Number' },
             {title: '截止本期合同计量|数量', colSpan: '2|1', rowSpan: '1|1', field: 'end_contract_qty', hAlign: 2, width: 60, type: 'Number'},
             {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'end_contract_tp', hAlign: 2, width: 60, type: 'Number'},
             {title: '截止本期数量变更|数量', colSpan: '2|1', rowSpan: '1|1', field: 'end_qc_qty', hAlign: 2, width: 60, type: 'Number'},
@@ -503,6 +512,8 @@ const stageCompare = {
             {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'},
+            { title: '本期补差|原单价', colSpan: '2|1', rowSpan: '1|1', field: 'org_price', hAlign: 2, width: 60, type: 'Number', },
+            { title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'pc_tp', hAlign: 2, width: 60, type: 'Number' },
         ],
         extraCols: [
             {title: '%s|数量', colSpan: '2|1', rowSpan: '1|1', field: 'gather_qty%s', hAlign: 2, width: 60, type: 'Number'},
@@ -603,7 +614,7 @@ module.exports = {
     stageNoCl,
     stageGather,
     stageCompare,
-    filterCols: { dealCols, dgnCols, clCols, stageDgnCols, realCompleteCols, thirdPartyCols, minusNoValueCols},
+    filterCols: { dealCols, dgnCols, clCols, stageDgnCols, realCompleteCols, thirdPartyCols, minusNoValueCols, priceDiffCols },
     measure,
     blank,
 };

+ 12 - 0
app/const/tender_info.js

@@ -115,6 +115,7 @@ const defaultInfo = {
         stage: {
             realComplete: false,
             correct: true,
+            priceDiff: false,
         },
         dayMode: false,
     },
@@ -179,9 +180,20 @@ const defaultInfo = {
         },
     },
 };
+const gclDefaultInfo = (function () {
+    const result = JSON.parse(JSON.stringify(defaultInfo));
+    result.display.ledger.deal = true;
+    return result;
+})(defaultInfo);
+const tzDefaultInfo = (function () {
+    const result = JSON.parse(JSON.stringify(defaultInfo));
+    return result;
+})(defaultInfo);
 
 module.exports = {
     parseInfo,
     arrayInfo,
     defaultInfo,
+    gclDefaultInfo,
+    tzDefaultInfo,
 };

+ 0 - 1
app/controller/ledger_controller.js

@@ -19,7 +19,6 @@ const auditConst = audit.ledger;
 const tenderMenu = require('../../config/menu').tenderMenu;
 const measureType = require('../const/tender').measureType;
 const shenpiConst = require('../const/shenpi');
-const externalDataConst = require('../const/external_data.js');
 const fs = require('fs');
 const LzString = require('lz-string');
 const accountGroup = require('../const/account_group').group;

+ 20 - 4
app/controller/material_controller.js

@@ -378,6 +378,7 @@ module.exports = app => {
             try {
                 await this._getMaterialAuditViewData(ctx);
                 const renderData = await this._getDefaultRenderData(ctx);
+                await this._setEditTaxPermission(ctx);
                 renderData.materialBillsData = await this._getMaterialBillsData(ctx);
                 // 取对应期的截取上期的调差金额和应耗数量
                 if (ctx.material.highOrder !== ctx.material.order) {
@@ -442,6 +443,7 @@ module.exports = app => {
             try {
                 await this._getMaterialAuditViewData(ctx);
                 const renderData = await this._getDefaultRenderData(ctx);
+                await this._setEditListPermission(ctx);
                 // 根据期判断需要获取的工料信息值表
                 const searchsql = { tid: ctx.tender.id };
                 let midList = [];
@@ -675,7 +677,7 @@ module.exports = app => {
                     }
                     renderData.ex_calc = ex_calc;
                 }
-
+                renderData.materialBillsData = await this._getMaterialBillsData(ctx);
                 renderData.materialExponentData = await this._getMaterialExponentData(ctx);
                 // 取对应期的截取上期的调差金额和应耗数量
                 if (ctx.material.highOrder !== ctx.material.order) {
@@ -710,6 +712,7 @@ module.exports = app => {
             try {
                 await this._getMaterialAuditViewData(ctx);
                 const renderData = await this._getDefaultRenderData(ctx);
+                renderData.materialBillsData = await this._getMaterialBillsData(ctx);
                 const whiteList = this.ctx.app.config.multipart.whitelist;
                 // 获取当前标段所有附件
                 // const searchsql = { tid: ctx.tender.id };
@@ -783,6 +786,10 @@ module.exports = app => {
                 if (ctx.session.sessionProject.page_show.openMaterialChecklist && ctx.app._.indexOf(notControlList, data.type) === -1) {
                     throw '清单设置功能已启动,请前往清单设置页操作清单内容';
                 }
+                const selfControlList = ['self', 'noself', 'add', 'del', 'update', 'paste'];
+                if (!ctx.session.sessionProject.page_show.openMaterialSelf && ctx.app._.indexOf(selfControlList, data.type) !== -1) {
+                    throw '单独设置工料功能已关闭,无法设置';
+                }
                 switch (data.type) {
                     case 'add':
                         responseData.data = await ctx.service.materialList.add(data.postData, data.ms_id);
@@ -813,7 +820,7 @@ module.exports = app => {
                         responseData.data = await ctx.service.materialListSelf.add(data.select);
                         break;
                     case 'noself':
-                        responseData.data = await ctx.service.materialListSelf.del(data.select.id, data.ms_id);
+                        responseData.data = await ctx.service.materialListSelf.del(data.select.id, data.ms_id, data.select.gather_qty);
                         break;
                     case 'paste':
                         await ctx.service.materialList.saveDatas(data.updateData, data.ms_id);
@@ -842,7 +849,6 @@ module.exports = app => {
                         break;
                     default: throw '参数有误';
                 }
-
                 ctx.body = responseData;
             } catch (err) {
                 this.log(err);
@@ -1426,12 +1432,22 @@ module.exports = app => {
             }
         }
 
+        async _setEditListPermission(ctx) {
+            const permission = ctx.session.sessionUser.permission;
+            ctx.material.editListPermission = permission && permission.material !== undefined && permission.material.indexOf('2') !== -1;
+        }
+
+        async _setEditTaxPermission(ctx) {
+            const permission = ctx.session.sessionUser.permission;
+            ctx.material.editTaxPermission = permission && permission.material !== undefined && permission.material.indexOf('3') !== -1;
+        }
+
         async _setChecklistPermission(ctx) {
             // 清单设置权限判断
             ctx.material.checklistPermission = false;
             if (ctx.session.sessionProject.page_show.openMaterialChecklist && ctx.material.highOrder === ctx.material.order && ctx.material.status !== auditConst.status.checked) {
                 const permission = ctx.session.sessionUser.permission;
-                if ((permission && permission.tender !== undefined && permission.tender.indexOf('4') !== -1) || (ctx.material.order === 1 && ctx.session.sessionUser.accountId === ctx.material.user_id && (ctx.material.status === auditConst.status.uncheck || ctx.material.status === auditConst.status.checkNo))) {
+                if ((permission && ((permission.tender !== undefined && permission.tender.indexOf('4') !== -1) || (permission.material !== undefined && permission.material.indexOf('1') !== -1))) || (ctx.material.order === 1 && ctx.session.sessionUser.accountId === ctx.material.user_id && (ctx.material.status === auditConst.status.uncheck || ctx.material.status === auditConst.status.checkNo))) {
                     ctx.material.checklistPermission = true;
                 }
             }

+ 35 - 0
app/controller/measure_controller.js

@@ -199,6 +199,37 @@ module.exports = app => {
             }
         }
 
+        joinData(main, idField, rela) {
+            const index = {},
+                indexPre = 'id_';
+            const loadFields = function(datas, fields, prefix, relaId) {
+                for (const d of datas) {
+                    const key = indexPre + d[relaId];
+                    let m = index[key];
+                    if (!m) {
+                        m = {};
+                        m[idField] = d[relaId];
+                        main.push(m);
+                        index[indexPre + d[relaId]] = m;
+                    }
+                    for (const f of fields) {
+                        if (d[f] !== undefined) {
+                            m[prefix + f] = d[f];
+                        }
+                    }
+                }
+            };
+            for (const m of main) {
+                index[indexPre + m[idField]] = m;
+                for (const r of rela) {
+                    if (r.defaultData) _.assignIn(m, r.defaultData);
+                }
+            }
+            for (const r of rela) {
+                loadFields(r.data, r.fields, r.prefix, r.relaId);
+            }
+        }
+
         /**
          * 多期比较 - 获取数据(Ajax)
          * @param ctx
@@ -221,6 +252,10 @@ module.exports = app => {
                         const data = { order, bills: [], pos: [] };
                         const stage = await this.ctx.service.stage.getDataByCondition({ tid: ctx.tender.id, order });
                         data.bills = await ctx.service.stageBills.getLastestStageData2(ctx.tender.id, stage.id);
+                        const bpcData = await ctx.service.stageBillsPc.getAllDataByCondition({ where: { sid: stage.id } });
+                        this.joinData(data.bills, 'lid', [
+                            { data: bpcData, fields: ['pc_tp'], prefix: '', relaId: 'lid' },
+                        ]);
                         data.pos = await ctx.service.stagePos.getLastestStageData2(ctx.tender.id, stage.id);
                         result.stages.push(data);
                     }

+ 31 - 4
app/controller/revise_controller.js

@@ -18,7 +18,6 @@ const accountGroup = require('../const/account_group').group;
 const tenderMenu = require('../../config/menu').tenderMenu;
 const measureType = require('../const/tender').measureType;
 const shenpiConst = require('../const/shenpi');
-const fs = require('fs');
 const LzString = require('lz-string');
 const stdConst = require('../const/standard');
 const spreadSetting = require('../lib/spread_setting');
@@ -417,7 +416,8 @@ module.exports = app => {
                     }
                 }
                 const ledgerTags = await this.ctx.service.ledgerTag.getDatas(ctx.tender.id);
-                ctx.body = { err: 0, msg: '', data: { bills: reviseBills, pos: revisePos, tags: ledgerTags } };
+                const price = !revise.readOnly ? await this.ctx.service.revisePrice.getAllDataByCondition({ where: { rid: revise.id } }) : [];
+                ctx.body = { err: 0, msg: '', data: { bills: reviseBills, pos: revisePos, tags: ledgerTags, price } };
             } catch (err) {
                 ctx.helper.log(err);
                 this.ajaxErrorBody(err, '加载台账修订数据错误');
@@ -813,7 +813,7 @@ module.exports = app => {
          */
         async check(ctx) {
             try {
-                const revise = await ctx.service.ledgerRevise.getLastestRevise(ctx.tender.id);
+                const revise = ctx.revise;
                 if (!revise || revise.status !== audit.revise.status.checking) throw '台账修订数据有误';
 
                 const curAudit = await ctx.service.reviseAudit.getCurAuditor(revise.id, revise.times);
@@ -822,7 +822,7 @@ module.exports = app => {
                 const checkType = parseInt(ctx.request.body.checkType);
                 if (!checkType || isNaN(checkType)) throw '提交数据错误';
 
-                await ctx.service.reviseAudit.check(revise, checkType, ctx.request.body.opinion, revise.times);
+                await ctx.service.reviseAudit.check(ctx.revise, checkType, ctx.request.body.opinion, revise.times);
 
                 ctx.redirect(ctx.request.headers.referer);
             } catch (err) {
@@ -948,6 +948,9 @@ module.exports = app => {
                     return spec;
                 case 'tags':
                     return await this.ctx.service.ledgerTag.getDatas(ctx.tender.id);
+                case 'price':
+                    return await this.ctx.service.revisePrice.getAllDataByCondition({ where: { rid: ctx.revise.id } });
+                default: throw '请求的数据不存在';
             }
         }
 
@@ -983,6 +986,30 @@ module.exports = app => {
             };
             await this.layout('revise/gcl_compare.ejs', renderData);
         }
+
+
+        async price(ctx) {
+            if (!ctx.revise) throw '台账修订数据有误';
+            const renderData = {
+                preUrl: ctx.url.replace('/price', ''),
+                revise: ctx.revise,
+                jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.revise.price),
+            };
+            await this.layout('revise/price.ejs', renderData);
+        }
+
+        async priceUpdate(ctx) {
+            try {
+                if (!ctx.revise) throw '台账修订数据有误';
+
+                const data = JSON.parse(ctx.request.body.data);
+                const result = await ctx.service.revisePrice.updateDatas(data);
+                ctx.body = { err: 0, msg: '', data: result };
+            } catch (err) {
+                ctx.log(err);
+                ctx.ajaxErrorBody(err, '保存数据失败');
+            }
+        }
     }
 
     return ReviseController;

+ 2 - 0
app/controller/setting_controller.js

@@ -954,6 +954,8 @@ module.exports = app => {
                 this.ctx.session.sessionProject.page_show.openChangePlan = data.openChangePlan ? 1 : 0;
                 this.ctx.session.sessionProject.page_show.openMaterialTax = data.openMaterialTax ? 1 : 0;
                 this.ctx.session.sessionProject.page_show.openMaterialChecklist = data.openMaterialChecklist ? 1 : 0;
+                this.ctx.session.sessionProject.page_show.openMaterialSelf = data.openMaterialSelf ? 1 : 0;
+                this.ctx.session.sessionProject.page_show.openMaterialEditForAudit = data.openMaterialEditForAudit ? 1 : 0;
                 const result2 = await ctx.service.project.updatePageshow(projectId);
                 if (!result2) throw '保存数据失败';
 

+ 10 - 1
app/controller/stage_controller.js

@@ -15,7 +15,6 @@ const spreadConst = require('../const/spread');
 const tenderConst = require('../const/tender');
 const shenpiConst = require('../const/shenpi');
 const payConst = require('../const/deal_pay.js');
-const externalDataConst = require('../const/external_data.js');
 const changeConst = require('../const/change');
 const measureType = tenderConst.measureType;
 const path = require('path');
@@ -221,6 +220,7 @@ module.exports = app => {
                 : await ctx.service.ledger.getAllDataByCondition({ columns: this.ledgerColumn, where: { tender_id: ctx.tender.id } });
             const dgnData = await ctx.service.stageBillsDgn.getDgnData(ctx.tender.id);
             const extraData = await ctx.service.ledgerExtra.getData(ctx.tender.id, this.ledgerExtraColumn);
+            const pcData = await ctx.service.stageBillsPc.getAllDataByCondition({ where: { sid: ctx.stage.id } });
             const importData = await ctx.service.stageImportChange.getImportLid(ctx.stage.id);
             let curStageData;
             // 当前操作人查看最新数据,其他人查看历史数据
@@ -241,6 +241,7 @@ module.exports = app => {
                 { data: importData, fields: ['is_import'], prefix: '', relaId: 'lid' },
                 { data: curStageData, fields: ['contract_qty', 'contract_expr', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty', 'postil'], prefix: '', relaId: 'lid' },
                 { data: preStageData, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty', 'used'], prefix: 'pre_', relaId: 'lid' },
+                { data: pcData, fields: ['contract_pc_tp', 'qc_pc_tp', 'pc_tp', 'org_price'], prefix: '', relaId: 'lid' },
             ]);
             return ledgerData;
         }
@@ -386,6 +387,7 @@ module.exports = app => {
                 checkData.checkBillsTp([
                     { qty: 'contract_qty', tp: 'contract_tp' }, { qty: 'qc_qty', tp: 'qc_tp' },
                 ], this.ctx.tender.info.decimal, x => { return x.is_tp; });
+                checkData.checkBillsQty(['contract_qty', 'qc_qty']);
                 ctx.body = { err: 0, msg: '', data: checkData.checkResult };
             } catch (err) {
                 this.log(err);
@@ -1370,6 +1372,13 @@ module.exports = app => {
                     result.main.ledger = ctx.stage.ledgerHis
                         ? await ctx.helper.loadLedgerDataFromOss(ctx.stage.ledgerHis.bills_file)
                         : await ctx.service.ledger.getData(ctx.tender.id);
+                    const bpcData = await ctx.service.stageBillsPc.getAllDataByCondition({ where: { sid: ctx.stage.id } });
+                    if (bpcData.length > 0) {
+                        this.ctx.helper.assignRelaData(result.main.ledger, [
+                            { data: bpcData, fields: ['pc_tp', 'org_price'], prefix: '', relaId: 'lid' },
+                        ]);
+                    }
+
                     result.main.pos = ctx.stage.ledgerHis
                         ? await ctx.helper.loadLedgerDataFromOss(ctx.stage.ledgerHis.pos_file)
                         : await ctx.service.pos.getPosData({ tid: ctx.tender.id });

+ 1 - 1
app/extend/helper.js

@@ -409,7 +409,7 @@ module.exports = {
      * @param {Number} value2
      * @return {boolean}
      */
-    checkNumberEqual(value1, value2) {
+    numEqual(value1, value2) {
         if (value1 && value2) {
             return Math.abs(value2 - value1) > zeroRange;
         }

+ 71 - 0
app/lib/ledger.js

@@ -944,6 +944,76 @@ class checkData {
     }
 }
 
+class reviseTree extends billsTree {
+    constructor (ctx, setting) {
+        super(ctx, setting);
+        this.price = [];
+    }
+    loadRevisePrice(price, decimal) {
+        this.decimal = decimal;
+        this.price = price || [];
+    }
+    checkRevisePrice(d) {
+        const helper = this.ctx.helper;
+        const p = this.price.find(x => {
+            return x.b_code === d.b_code &&
+                ((!x.name && !d.name) || x.name === d.name) &&
+                ((!x.unit && !d.unit) || x.unit === d.unit) &&
+                helper.checkZero(x.org_price - d.unit_price);
+        });
+        if (!p) return false;
+        d.org_price = p.org_price;
+        d.unit_price = p.new_price;
+        d.deal_tp = helper.mul(d.deal_qty, d.unit_price, this.decimal.tp);
+        d.sgfh_tp = helper.mul(d.sgfh_qty, d.unit_price, this.decimal.tp);
+        d.sjcl_tp = helper.mul(d.sjcl_qty, d.unit_price, this.decimal.tp);
+        d.qtcl_tp = helper.mul(d.qtcl_qty, d.unit_price, this.decimal.tp);
+        d.total_price = helper.mul(d.quantity, d.unit_price, this.decimal.tp);
+        return true;
+    }
+    loadDatas(datas) {
+        super.loadDatas(datas);
+        if (this.price.length > 0) {
+            for (const d of this.datas) {
+                if (d.children && d.children.length > 0) continue;
+                if (!d.b_code) continue;
+                this.checkRevisePrice(d);
+            }
+        }
+    }
+    getUpdateReviseData() {
+        return this.datas.map(x => {
+            if (x.children && x.children.length > 0) {
+                return {
+                    id: x.id, tender_id: x.tender_id, crid: x.crid,
+                    ledger_id: x.ledger_id, ledger_pid: x.ledger_pid, full_path: x.full_path, order: x.order, level: x.level, is_leaf: x.is_leaf,
+                    node_type: x.node_type, check_calc: x.check_calc,
+                    code: x.code, b_code: x.b_code, name: x.name, unit: x.unit, position: x.position,
+                    drawing_code: x.drawing_code, memo: x.memo, add_user: x.add_user, in_time: x.in_time,
+                    unit_price: 0, dgn_qty1: x.dgn_qty1, dgn_qty2: x.dgn_qty2,
+                    quantity: 0, total_price: 0,
+                    sgfh_qty: 0, sgfh_tp: 0, sgfh_expr: '',
+                    sjcl_qty: 0, sjcl_tp: 0, sjcl_expr: '',
+                    qtcl_qty: 0, qtcl_tp: 0, qtcl_expr: '',
+                };
+            } else {
+                return {
+                    id: x.id, tender_id: x.tender_id, crid: x.crid,
+                    ledger_id: x.ledger_id, ledger_pid: x.ledger_pid, full_path: x.full_path, order: x.order, level: x.level, is_leaf: x.is_leaf,
+                    node_type: x.node_type, check_calc: x.check_calc,
+                    code: x.code, b_code: x.b_code, name: x.name, unit: x.unit, position: x.position,
+                    drawing_code: x.drawing_code, memo: x.memo, add_user: x.add_user, in_time: x.in_time,
+                    unit_price: x.unit_price, dgn_qty1: x.dgn_qty1, dgn_qty2: x.dgn_qty2,
+                    quantity: x.quantity, total_price: x.total_price,
+                    sgfh_qty: x.sgfh_qty, sgfh_tp: x.sgfh_tp, sgfh_expr: x.sgfh_expr,
+                    sjcl_qty: x.sjcl_qty, sjcl_tp: x.sjcl_tp, sjcl_expr: x.sjcl_expr,
+                    qtcl_qty: x.qtcl_qty, qtcl_tp: x.qtcl_tp, qtcl_expr: x.qtcl_expr,
+                };
+            }
+        });
+    }
+}
+
 module.exports = {
     billsTree,
     pos,
@@ -951,4 +1021,5 @@ module.exports = {
     filterGatherTree,
     gatherTree,
     checkData,
+    reviseTree,
 };

+ 1 - 1
app/lib/pm.js

@@ -61,7 +61,7 @@ module.exports = {
 
         const url = ctx.app.config.managementProxyPath + dealDataApi;
         try {
-            const data = { code: pCode, token: pmUtils.getJwt(), key: ['contracts'], bidsectionid: selects };
+            const data = { code: pCode, token: pmUtils.getJwt(), key: ['contracts', 'tree_contracts'], bidsectionid: selects };
             return await pmUtils.postData(ctx, url, data);
         } catch (err) {
             ctx.log(err);

+ 298 - 0
app/lib/revise_price.js

@@ -0,0 +1,298 @@
+'use strict';
+
+/**
+ *
+ * 单价调整计算:
+ * 1. 台账修订上报,保存台账修订历史时,使用当前单价调整计算一次
+ * 2. 台账修订完成:计算台账、应用到未审完成期、应用到所有工程变更
+ * 3. 新增期:检查是否存在未应用的单价变更
+ * 4. 期审批完成:所有未应用的单价调整,记录应用到该期(记录revise_price.use_stage/use_stage_order) - 一条sql即可
+ * 5. 期重现审批:上一次应用的所有单价调整,回到未应用状态(revise_price.use_stage/use_stage_order均回到0) - 一条sql即可
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+const Ledger = require('./ledger');
+const audit = require('../const/audit');
+
+class revisePriceCalc {
+    constructor(ctx) {
+        this.ctx = ctx;
+    }
+
+    findPrice(b_code, name, unit, unit_price) {
+        const helper = this.ctx.helper;
+        return this.price.find(x => {
+            return b_code === x.b_code && name === x.name && unit === x.unit && helper.numEqual(unit_price, x.org_price);
+        });
+    }
+
+    /**
+     * 新增一期计量,检查单价调整
+     * @param {Object} newStage - 新计量期
+     * @param {Object} preStage - 上一计量期
+     * @return { inseretPosData, insertBillsData }
+     */
+    async newStagePriceChange(newStage, preStage, transaction) {
+        // 获取未执行的单价变更,无单价变更不执行
+        const price = await this.ctx.service.revisePrice.getAllDataByCondition({ where: { tid: newStage.tid, valid: 1, use_stage: 0 } });
+        if (price.length === 0) return;
+        // 无截止上期数据不执行
+        const preBillsData = await this.ctx.service.stageBillsFinal.getAllDataByCondition({ where: { sid: preStage.id } });
+        if (preBillsData.length === 0) return;
+
+        // 加载树结构
+        const bills = await this.ctx.service.ledger.getData(newStage.tid);
+        this.ctx.helper.assignRelaData(bills, [
+            { data: preBillsData, fields: ['id', 'contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'unit_price'], prefix: 'pre_', relaId: 'lid' },
+        ]);
+        const billsTree = new Ledger.billsTree(this.ctx, { id: 'ledger_id', pid: 'ledger_pid', order: 'order', level: 'level', rootId: -1, calcFields: [] });
+        billsTree.loadDatas(bills);
+
+        // 计算
+        const result = { ibData: [] };
+        const helper = this.ctx.helper;
+        const decimal = this.ctx.tender.info.decimal;
+        billsTree.calculateAll(node => {
+            if (!node.pre_id) return;
+            if (node.children && node.children.length > 0) return;
+            const priceDiff = helper.sub(node.unit_price, node.pre_unit_price);
+            if (!priceDiff) return;
+            node.contract_pc_tp = helper.sub(helper.mul(node.pre_contract_qty, node.unit_price, decimal.tp), node.pre_contract_tp);
+            node.qc_pc_tp = helper.sub(helper.mul(node.pre_qc_qty, node.unit_price, decimal.tp), node.pre_qc_tp);
+            node.pc_tp = helper.add(node.contract_pc_tp, node.qc_pc_tp);
+            result.ibData.push({
+                tid: newStage.tid, sid: newStage.id, sorder: newStage.order, lid: node.id, org_price: node.pre_unit_price,
+                contract_pc_tp: node.contract_pc_tp, qc_pc_tp: node.qc_pc_tp, pc_tp: node.pc_tp,
+            });
+        });
+        if (result.ibData.length > 0) await transaction.insert(this.ctx.service.stageBillsPc.tableName, result.ibData);
+
+        let contract_pc_tp = 0, qc_pc_tp = 0, pc_tp = 0;
+        for (const ibc of result.ibData) {
+            contract_pc_tp = helper.add(contract_pc_tp, ibc.contract_pc_tp);
+            qc_pc_tp = helper.add(qc_pc_tp, ibc.qc_pc_tp);
+            pc_tp = helper.add(pc_tp, ibc.pc_tp);
+        }
+        await transaction.update(this.ctx.service.stage.tableName, { id: newStage.id, contract_pc_tp, qc_pc_tp, pc_tp, check_calc: true, cache_time_l: new Date() });
+    }
+
+    /**
+     * 期,重新审批,检查单价调整
+     * @param {Object} stage - 期
+     * @param {Number} auditOrder - 重新审批,最新审批人序号
+     * @param {Object} transaction - 事务
+     */
+    async stageCheckAgainPriceChange(stage, auditOrder, transaction) {
+        // 获取未执行的单价变更,无单价变更不执行
+        const price = await this.ctx.service.revisePrice.getAllDataByCondition({ where: { tid: stage.tid, valid: 1, use_stage: 0 } });
+        if (price.length === 0) return;
+
+        const curBillsData = await this.ctx.service.stageBills.getLastestStageData2(stage.tid, stage.id);
+        const preBillsData = await this.ctx.service.stageBillsFinal.getAllDataByCondition({ where: { tid: stage.tid, sorder: stage.order - 1 } });
+
+        // 加载树结构
+        const bills = await this.ctx.service.ledger.getData(stage.tid);
+        this.ctx.helper.assignRelaData(bills, [
+            { data: curBillsData, fields: ['id', 'contract_qty', 'qc_qty', 'postil', 'times', 'order'], prefix: 'cur_', relaId: 'lid' },
+            { data: preBillsData, fields: ['id', 'contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'unit_price'], prefix: 'pre_', relaId: 'lid' },
+        ]);
+        const billsTree = new Ledger.billsTree(this.ctx, { id: 'ledger_id', pid: 'ledger_pid', order: 'order', level: 'level', rootId: -1, calcFields: [] });
+        billsTree.loadDatas(bills);
+
+
+        // 计算 insertBills billsPriceChange reCalcBillsCur/reCalcBillsPrice
+        const result = { ibData: [], bpcData: [] };
+        const helper = this.ctx.helper;
+        const decimal = this.ctx.tender.info.decimal;
+        const said = this.ctx.session.sessionUser.accountId;
+        billsTree.calculateAll(node => {
+            if (node.children && node.children.length > 0) return;
+            const priceDiff = helper.sub(node.unit_price, node.pre_unit_price);
+            if (!priceDiff) return;
+            if (node.cur_id) {
+                node.cur_contract_tp = helper.mul(node.cur_contract_qty, node.unit_price, decimal.tp);
+                node.cur_qc_tp = helper.mul(node.cur_qc_qty, node.unit_price, decimal.tp);
+                result.ibData.push({
+                    tid: stage.tid, sid: stage.id, said,
+                    lid: node.id,
+                    times: stage.times, order: auditOrder,
+                    contract_qty: node.cur_contract_qty, contract_tp: node.cur_contract_tp, qc_qty: node.cur_qc_qty, qc_tp: node.cur_qc_tp,
+                    postil: node.postil,
+                });
+            }
+            if (node.pre_id) {
+                node.contract_pc_tp = helper.sub(helper.mul(node.pre_contract_qty, node.unit_price, decimal.tp), node.pre_contract_tp);
+                node.qc_pc_tp = helper.sub(helper.mul(node.pre_qc_qty, node.unit_price, decimal.tp), node.pre_qc_tp);
+                node.pc_tp = helper.add(node.contract_pc_tp, node.qc_pc_tp);
+                result.bpcData.push({
+                    tid: stage.tid, sid: stage.id, sorder: stage.order, lid: node.lid, org_price: node.pre_unit_price,
+                    contract_pc_tp: node.contract_pc_tp, qc_pc_tp: node.qc_pc_tp, pc_tp: node.pc_tp,
+                });
+            }
+        });
+        if (result.ibData.length > 0) await transaction.insert(this.ctx.service.stageBills.tableName, result.ibData);
+        await transaction.delete(this.ctx.service.stageBillsPc.tableName, { sid: stage.id });
+        if (result.bpcData.length > 0) await transaction.insert(this.ctx.service.stageBillsPc.tableName, result.bpcData);
+
+        let contract_pc_tp = 0, qc_pc_tp = 0, pc_tp = 0;
+        for (const bpc of result.bpcData) {
+            contract_pc_tp = helper.add(contract_pc_tp, bpc.contract_pc_tp);
+            qc_pc_tp = helper.add(qc_pc_tp, bpc.qc_pc_tp);
+            pc_tp = helper.add(pc_tp, bpc.pc_tp);
+        }
+        await transaction.update(this.ctx.service.stage.tableName, { id: stage.id, contract_pc_tp, qc_pc_tp, pc_tp, check_calc: true, cache_time_l: new Date() });
+    }
+
+    /**
+     * 重算工程变更(调整单价)
+     * @param {Object} change - 工程变更
+     * @param {Object} transaction - 事务 (无则非事务提交)
+     */
+    async calcChange(change, transaction) {
+        const changeBills = await this.ctx.service.changeAuditList.getAllDataByCondition({ where: { cid: change.cid } });
+        const updateBills = [];
+        let total_price = 0;
+        for (const b of changeBills) {
+            const p = this.findPrice(b.code, b.name, b.unit, b.unit_price);
+            if (p) {
+                updateBills.push({ id: b.id, unit_price: p.new_price });
+                total_price = this.ctx.helper.add(total_price, this.ctx.helper.mul(p.new_price, b.spamount, change.tp_decimal));
+            } else {
+                total_price = this.ctx.helper.add(total_price, this.ctx.helper.mul(b.unit_price, b.spamount, change.tp_decimal));
+            }
+        }
+        if (updateBills.length > 0) {
+            const conn = transaction || this.ctx.sub_db;
+            await conn.updateRows(this.ctx.service.changeAuditList.tableName, updateBills);
+            await conn.update(this.ctx.service.change.tableName, { total_price }, { where: { cid: change.cid } });
+        }
+    }
+    /**
+     * 重算标段下所有工程变更(调整单价)
+     * @param {Number} tid - 标段id
+     * @param {Object} transaction - 事务 (无则非事务提交)
+     */
+    async calcAllChanges(tid, transaction) {
+        const change = await this.ctx.service.change.getAllDataByCondition({ where: { tid, valid: 1 } });
+        if (change.length === 0) return;
+        for (const c of change) {
+            await this.calcChange(c, transaction);
+        }
+    }
+    async _calcStage(stage, bills, transaction) {
+        // 无单价变更不执行
+        if (this.price.length === 0) return;
+
+        const curBillsData = await this.ctx.service.stageBills.getLastestStageData2(stage.tid, stage.id);
+        const preBillsData = await this.ctx.service.stageBillsFinal.getAllDataByCondition({ where: { tid: stage.tid, sorder: stage.order - 1 } });
+
+        // 加载树结构
+        this.ctx.helper.assignRelaData(bills, [
+            { data: curBillsData, fields: ['id', 'contract_qty', 'qc_qty', 'times', 'order', 'postil'], prefix: 'cur_', relaId: 'lid' },
+            { data: preBillsData, fields: ['id', 'contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'unit_price'], prefix: 'pre_', relaId: 'lid' },
+        ]);
+        const billsTree = new Ledger.billsTree(this.ctx, { id: 'ledger_id', pid: 'ledger_pid', order: 'order', level: 'level', rootId: -1, calcFields: [] });
+        billsTree.loadDatas(bills);
+
+        // 计算 insertBills/updateBills billsPriceChange
+        const result = { ibData: [], ubData: [], bpcData: [] };
+        const helper = this.ctx.helper;
+        const decimal = this.ctx.tender.info.decimal;
+        const said = this.ctx.session.sessionUser.accountId;
+        billsTree.calculateAll(node => {
+            if (node.children && node.children.length > 0) return;
+            const priceDiff = helper.sub(node.unit_price, node.pre_unit_price);
+            if (!priceDiff) return;
+            node.contract_pc_tp = helper.sub(helper.mul(node.pre_contract_qty, node.unit_price, decimal.tp), node.pre_contract_tp);
+            node.qc_pc_tp = helper.sub(helper.mul(node.pre_qc_qty, node.unit_price, decimal.tp), node.pre_qc_tp);
+            node.pc_tp = helper.add(node.contract_pc_tp, node.qc_pc_tp);
+            if (node.cur_id) {
+                node.cur_contract_tp = helper.mul(node.cur_contract_qty, node.unit_price, decimal.tp);
+                node.cur_qc_tp = helper.mul(node.cur_qc_qty, node.unit_price, decimal.tp);
+                if (node.cur_times === stage.times && node.cur_order === 0) {
+                    result.ubData.push({
+                        id: node.cur_id,
+                        contract_tp: node.cur_contract_tp, qc_tp: node.cur_qc_tp,
+                    });
+                } else {
+                    result.ibData.push({
+                        tid: stage.tid, sid: stage.id, said,
+                        lid: node.id, times: stage.times, order: 0,
+                        contract_qty: node.cur_contract_qty, contract_tp: node.cur_contract_tp, qc_qty: node.cur_qc_qty, qc_tp: node.cur_qc_tp,
+                        postil: node.cur_postil,
+                    });
+                }
+            }
+            if (node.pre_id) {
+                result.bpcData.push({
+                    tid: stage.tid, sid: stage.id, sorder: stage.order, lid: node.id, org_price: node.pre_unit_price,
+                    contract_pc_tp: node.contract_pc_tp, qc_pc_tp: node.qc_pc_tp, pc_tp: node.pc_tp,
+                });
+            }
+        });
+        if (result.ibData.length > 0) await transaction.insert(this.ctx.service.stageBills.tableName, result.ibData);
+        if (result.ubData.length > 0) await transaction.updateRows(this.ctx.service.stageBills.tableName, result.ubData);
+        await transaction.delete(this.ctx.service.stageBillsPc.tableName, { sid: stage.id });
+        if (result.bpcData.length > 0) await transaction.insert(this.ctx.service.stageBillsPc.tableName, result.bpcData);
+
+        let contract_pc_tp = 0, qc_pc_tp = 0, pc_tp = 0;
+        for (const bpc of result.bpcData) {
+            contract_pc_tp = helper.add(contract_pc_tp, bpc.contract_pc_tp);
+            qc_pc_tp = helper.add(qc_pc_tp, bpc.qc_pc_tp);
+            pc_tp = helper.add(pc_tp, bpc.pc_tp);
+        }
+        await transaction.update(this.ctx.service.stage.tableName, { id: stage.id, contract_pc_tp, qc_pc_tp, pc_tp, check_calc: true, cache_time_l: new Date() });
+    }
+    /**
+     * 计算修订台账
+     * @param {Object}revise - 最新一次台账修订(此处不检查)
+     * @param {Object} transaction - 事务 (无则非事务提交)
+     */
+    async calcReviseLedger(revise, transaction) {
+        const xmj = await this.ctx.helper.loadLedgerDataFromOss(revise.curHis.bills_file);
+        xmj.forEach(x => {
+            delete x.is_tp;
+            delete x.gxby_status;
+            delete x.gxby_limit;
+            delete x.gxby_ratio;
+            delete x.gxby_url;
+            delete x.dagl_status;
+            delete x.dagl_limit;
+            delete x.dagl_ratio;
+            delete x.dagl_url;
+        });
+        const pos = await this.ctx.helper.loadLedgerDataFromOss(revise.curHis.pos_file);
+        pos.forEach(p => {
+            p.in_time = new Date(p.in_time);
+            delete p.gxby_status;
+            delete p.gxby_limit;
+            delete p.gxby_ratio;
+            delete p.gxby_url;
+            delete p.dagl_status;
+            delete p.dagl_limit;
+            delete p.dagl_ratio;
+            delete p.dagl_url;
+        });
+        await transaction.delete(this.ctx.service.ledger.tableName, { tender_id: revise.tid });
+        if (xmj.length > 0) await transaction.insert(this.ctx.service.ledger.tableName, xmj);
+        await transaction.delete(this.ctx.service.pos.tableName, { tid: revise.tid });
+        if (pos.length > 0) await transaction.insert(this.ctx.service.pos.tableName, pos);
+
+        // 应用到未审完成期
+        const latestStage = await this.ctx.service.stage.getLastestStage(revise.tid, true);
+        if (latestStage && latestStage.status !== audit.stage.status.checked) await this._calcStage(latestStage, xmj, transaction);
+    }
+    async calcRevise(revise, transaction) {
+        if (revise.tid !== this.ctx.tender.id) throw '数据错误';
+
+        this.price = await this.ctx.service.revisePrice.getAllDataByCondition({ where: { rid: revise.id } });
+        await this.calcReviseLedger(revise, transaction);
+        // 引用到所有工程变更
+        await this.calcAllChanges(revise.tid, transaction);
+    }
+}
+
+module.exports = revisePriceCalc;

+ 1 - 1
app/lib/rm/material.js

@@ -243,7 +243,6 @@ class ReportMemoryMaterial {
         const material = await this.ctx.service.material.getDataByCondition({ tid: tender_id, order: material_order });
         const decimal = material.decimal ? JSON.parse(material.decimal) : materialConst.decimal;
         try {
-
             const billsData = await this.ctx.service.ledger.getData(tender_id);
             const curStageBills = await this.ctx.service.stageBills.getStagesData(tender_id, material.stage_id);
             this.ctx.helper.assignRelaData(billsData, [
@@ -278,6 +277,7 @@ class ReportMemoryMaterial {
                     const mnj = materialNotJoin.find(m => {
                         return m.gcl_id === x.org_gcl_id && m.xmj_id === x.id && (x.mx_id && x.mx_id !== x.id  ? x.mx_id === m.mx_id : true);
                     });
+                    x.is_join = !mnj;
                     if (mnj) continue;
                     const list = materialGl.filter(g => {
                         return g.gcl_id === x.org_gcl_id && g.xmj_id === x.id && (x.mx_id && x.mx_id !== x.id ? x.mx_id === g.mx_id : true);

+ 3 - 2
app/lib/spread_setting.js

@@ -65,8 +65,7 @@ const getLedgerSpreadSetting = async function(ctx, tid, readOnly) {
     const pos = setting.pos ? JSON.parse(JSON.stringify(setting.pos)) : spreadConst.blank;
     ledger.readOnly = readOnly;
     pos.readOnly = readOnly;
-    if (tender.data.measure_type === measureType.tz.value && !tender.info.display.ledger.deal)
-        removeFieldCols(ledger, spreadConst.filterCols.dealCols);
+    if (!tender.info.display.ledger.deal) removeFieldCols(ledger, spreadConst.filterCols.dealCols);
     if (!tender.info.display.ledger.dgnQty) removeFieldCols(ledger, spreadConst.filterCols.dgnCols);
 
     const sjsRela = await ctx.service.project.getTenderSjsRela(ctx.session.sessionProject.id, ctx.tender.info.display.exMemo);
@@ -101,6 +100,7 @@ const getStageSpreadSetting = async function (ctx, tid, readOnly, funInfo) {
         hiddenFieldCols(ledger, spreadConst.filterCols.minusNoValueCols);
         hiddenFieldCols(pos, spreadConst.filterCols.minusNoValueCols);
     }
+    if (!tender.info.display.stage.priceDiff) hiddenFieldCols(ledger, spreadConst.filterCols.priceDiffCols);
     ledger.readOnly = readOnly;
     pos.readOnly = readOnly;
 
@@ -117,6 +117,7 @@ const getStageGatherSpreadSetting = async function (ctx, tid) {
 
     // if (tender.data.measure_type === measureType.tz.value && !tender.info.display.ledger.deal)
     //     removeFieldCols(gcl, spreadConst.filterCols.dealCols);
+    if (tender.info.display.stage.priceDiff) removeFieldCols(leafXmj, spreadConst.filterCols.priceDiffCols);
 
     if (tender.data.measure_type === measureType.gcl.value) removeFieldCols(leafXmj, ['quantity']);
     return [gcl, leafXmj];

+ 6 - 4
app/lib/stage_im.js

@@ -27,7 +27,7 @@ class StageIm {
             rootId: -1,
             keys: ['id', 'tender_id', 'ledger_id'],
             stageId: 'id',
-            calcFields: ['deal_tp', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp'],
+            calcFields: ['deal_tp', 'total_price', 'contract_tp', 'qc_tp', 'contract_pc_tp', 'qc_pc_tp', 'pc_tp', 'gather_tp'],
             calc(node) {
                 if (node.children && node.children.length === 0) {
                     node.pre_gather_qty = self.ctx.helper.add(node.pre_contract_qty, node.pre_qc_qty);
@@ -38,9 +38,9 @@ class StageIm {
                     node.end_gather_qty = self.ctx.helper.add(node.pre_gather_qty, node.gather_qty);
                 }
                 node.pre_gather_tp = self.ctx.helper.add(node.pre_contract_tp, node.pre_qc_tp);
-                node.gather_tp = self.ctx.helper.add(node.contract_tp, node.qc_tp);
-                node.end_contract_tp = self.ctx.helper.add(node.pre_contract_tp, node.contract_tp);
-                node.end_qc_tp = self.ctx.helper.add(node.pre_qc_tp, node.qc_tp);
+                node.gather_tp = self.ctx.helper.sum([node.contract_tp, node.qc_tp, node.pc_tp]);
+                node.end_contract_tp = self.ctx.helper.sum([node.pre_contract_tp, node.contract_tp, node.contract_pc_tp]);
+                node.end_qc_tp = self.ctx.helper.sum([node.pre_qc_tp, node.qc_tp, node.qc_pc_tp]);
                 node.end_gather_tp = self.ctx.helper.add(node.pre_gather_tp, node.gather_tp);
             },
         });
@@ -76,10 +76,12 @@ class StageIm {
                 this.ctx.stage.id, this.ctx.stage.curTimes, this.ctx.stage.curOrder)
             : await this.ctx.service.stageBills.getLastestStageData2(this.ctx.tender.id, this.ctx.stage.id);
         const preStage = this.ctx.stage.order > 1 ? await this.ctx.service.stageBillsFinal.getFinalData(this.ctx.tender, this.ctx.stage.order - 1) : [];
+        const bpcStage = await this.ctx.service.stageBillsPc.getAllDataByCondition({ where: { sid: this.ctx.stage.id } });
 
         this.ctx.helper.assignRelaData(billsData, [
             { data: curStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty'], prefix: '', relaId: 'lid' },
             { data: preStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty'], prefix: 'pre_', relaId: 'lid' },
+            { data: bpcStage, fields: ['contract_pc_tp', 'qc_pc_tp', 'pc_tp'], prefix: '', relaId: 'lid' },
         ]);
         this.billsTree.loadDatas(billsData);
         this.billsTree.calculateAll();

+ 2 - 0
app/lib/tender_info.js

@@ -46,9 +46,11 @@ class TenderInfo {
                 : await this.ctx.service.stageBills.getLastestStageData2(this.tender.id, this.stage.id);
 
             const preStage = this.stage.order > 1 ? await this.ctx.service.stageBillsFinal.getFinalData(this.tender, this.stage.order - 1) : [];
+            const bpcStage = await this.ctx.service.stageBillsPc.getAllDataByCondition({ where: { sid: this.stage.id } });
             this.ctx.helper.assignRelaData(billsData, [
                 { data: curStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'], prefix: '', relaId: 'lid' },
                 { data: preStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'], prefix: 'pre_', relaId: 'lid' },
+                { data: bpcStage, fields: ['contract_pc_tp', 'qc_pc_tp', 'pc_tp'], prefix: '', relaId: 'lid' },
             ]);
         }
         return billsData;

+ 3 - 1
app/middleware/material_check.js

@@ -121,7 +121,9 @@ module.exports = options => {
                 tid: this.tender.id,
             });
             // 调差的readOnly 指表格和页面只能看不能改,和审批无关
-            material.readOnly = !((material.status === status.uncheck || material.status === status.checkNo) && accountId === material.user_id);
+            material.readOnly = !(((material.status === status.uncheck || material.status === status.checkNo) && accountId === material.user_id)
+                || (this.session.sessionProject.page_show.openMaterialEditForAudit && (material.status === status.checking || material.status === status.checkNoPre) && material.curAuditor.aid === accountId));
+            material.editForAudit = this.session.sessionProject.page_show.openMaterialEditForAudit && (material.status === status.checking || material.status === status.checkNoPre) && material.curAuditor.aid === accountId;
             material.decimal = material.decimal ? JSON.parse(material.decimal) : materialConst.decimal;
             this.material = material;
             // 根据状态判断是否需要更新审批人列表

+ 1 - 0
app/middleware/revise_check.js

@@ -37,6 +37,7 @@ module.exports = options => {
             }
             revise.readOnly = revise.uid !== this.session.sessionUser.accountId ||
                 revise.status === auditConst.status.checking || revise.status === auditConst.status.checked;
+            revise.priceCount = yield this.service.revisePrice.count({ rid: revise.id });
             this.revise = revise;
             yield next;
         } catch (err) {

+ 45 - 21
app/public/css/main.css

@@ -87,7 +87,7 @@ font-size: .875rem;
 }
 .custom-control-warning-input:checked ~ .custom-control-warning-label::before{
   border-color:#da9500 ;
-  background-color:#da9500 
+  background-color:#da9500
 }
 .custom-control-warning-label{
   color:#da9500;
@@ -195,23 +195,23 @@ input.nospin[type="number"]{-moz-appearance:textfield;}
 /*滚动条*/
 /* 滚动条 */
 /*水平滚动条的样式*/
-/*::-webkit-scrollbar-thumb:horizontal { 
+/*::-webkit-scrollbar-thumb:horizontal {
 	width: 5px;
 	background-color: #e9ecef;
 	-webkit-border-radius: 0;
 }*/
 /*滚动条的背景颜色,滚动条的圆角宽度*/
 /*::-webkit-scrollbar-track-piece {
-	background-color: #efefef; 
-	-webkit-border-radius: 0; 
+	background-color: #efefef;
+	-webkit-border-radius: 0;
 }*/
 /*滚动条的宽度,滚动条的高度*/
 /*::-webkit-scrollbar {
-	width: 14px; 
-	height: 14px; 
+	width: 14px;
+	height: 14px;
 }*/
 /*垂直滚动条的样式*/
-/*::-webkit-scrollbar-thumb:vertical { 
+/*::-webkit-scrollbar-thumb:vertical {
 	height: 50px;
 	background-color: #e9ecef;
 	-webkit-border-radius: 0;
@@ -220,7 +220,7 @@ input.nospin[type="number"]{-moz-appearance:textfield;}
 	border: 1px solid #ced4da;
 }*/
 /*滚动条的hover样式*/
-/*::-webkit-scrollbar-thumb:hover { 
+/*::-webkit-scrollbar-thumb:hover {
 	height: 50px;
 	background-color: #ced4da;
 	-webkit-border-radius: 0;
@@ -538,7 +538,7 @@ input.nospin[type="number"]{-moz-appearance:textfield;}
     box-sizing: border-box;
 }
 .panel-sidebar .scrollbar-auto {
-    height: calc(100vh - 100px);
+    height: calc(100vh - 50px);
     width: 100%;
     overflow-y: auto;
     position: static;
@@ -874,7 +874,7 @@ input.nospin[type="number"]{-moz-appearance:textfield;}
   font-size: 14px
 }
 .bd-toc {
-  
+
     position: sticky;
     top:3rem;
     height: calc(100vh - 10rem);
@@ -1032,7 +1032,7 @@ body{
   line-height: 30px;
 }
 .panel-title > .title-main .btn.pull-right {
-    margin: 5px 0 0 0 
+    margin: 5px 0 0 0
 }
 .panel-content{
   padding-top:35px;
@@ -1162,9 +1162,33 @@ legend {
 .min-side .side-menu{
   padding-bottom:10px;
 }
+.side-show {
+  position: absolute;
+  z-index:8;
+  right:0;
+  top: 0;
+  width: 15px;
+  height: calc(100vh);
+}
 .side-fold {
-  right:50px;
-  bottom:5px;
+  /*right:50px;*/
+  /*bottom:5px;*/
+  display:none;
+  z-index:9;
+  border-radius:2px;
+  right:0;
+  bottom:50%;
+  width:6px;
+  height:60px;
+  line-height:60px;
+  text-align:center;
+  cursor:pointer;
+  background-color: #2E6BE5;
+  color: #fff;
+}
+.side-fold i{
+  font-size: 20px;
+  vertical-align: text-bottom;
 }
 .side-fold a{
   font-size:24px;
@@ -1251,7 +1275,7 @@ a.maintain-icon .fa{
     }
 }
 
-a.maintain-icon:hover .fa{ 
+a.maintain-icon:hover .fa{
     animation-iteration-count:0
 }
 /*审批列表*/
@@ -1374,10 +1398,10 @@ overflow-y: auto;
   position: relative;
 }
 .circle{
-  width: 62px; 
+  width: 62px;
   height: 62px;
   border-radius: 50%;
-  background: none; 
+  background: none;
   border: 4px solid #D7B014;
 }
 .circle-num{
@@ -1918,8 +1942,8 @@ overflow-y: auto;
   font-size: 36px;
 }
 .list-text-vertical{
-  overflow:hidden; 
-  text-overflow:ellipsis; 
+  overflow:hidden;
+  text-overflow:ellipsis;
   white-space:nowrap;
 }
 .about-text i{
@@ -1943,12 +1967,12 @@ overflow-y: auto;
 }
 /*@media (min-width: 768px){
   .weixin-erweima img{
-    width:90%; 
+    width:90%;
     height:auto;
   }
 }*/
 .weixin-erweima img{
-  width:75%; 
+  width:75%;
   height:auto;
 }
 .weixin-erweima span{
@@ -2017,4 +2041,4 @@ animation:shake 1s .2s ease both;}
 }
 .card-gk-active .card-gk-bottom{
   display: inline-block;
-}
+}

+ 2 - 1
app/public/js/component/menu.js

@@ -1,7 +1,7 @@
 'use strict';
 // 导航栏
 Vue.component('nav-menu', {
-    props: ['title', 'url', 'active', 'tclass', 'icon', 'ml', 'hint'],
+    props: ['title', 'url', 'active', 'tclass', 'icon', 'ml', 'hint', 'hinticon'],
     template: '' +
     '<div class="nav-box" data-toggle="tooltip" data-placement="right" :data-original-title="[ hint ]">' +
         '<ul class="nav-list list-unstyled">' +
@@ -9,6 +9,7 @@ Vue.component('nav-menu', {
                 '<a :href="url" :class="[ tclass ]">' +
                     '<i v-if="icon" class="fa" :class="icon"></i>' +
                     '<span :class="[ \'ml-\' + ml ]">{{ title }}</span>' +
+                    '<i v-if="hinticon" class="fa text-danger ml-2" :class="hinticon"></i>' +
                 '</a>' +
             '</li>' +
         '</ul>' +

+ 2 - 1
app/public/js/ledger.js

@@ -1685,8 +1685,8 @@ $(document).ready(function() {
             }
         });
         sjsSettingObj.setGridSelectStyle(posSpreadSetting);
-        SpreadJsObj.initSheet(posSpread.getActiveSheet(), posSpreadSetting);
     }
+    SpreadJsObj.initSheet(posSpread.getActiveSheet(), posSpreadSetting);
     //绑定计量单元编辑事件
     const posOperationObj = {
         /**
@@ -2229,6 +2229,7 @@ $(document).ready(function() {
 
     postData(window.location.pathname + '/load', {}, function (data) {
         ledgerTree.loadDatas(data.bills);
+        console.log(data.bills.find(x => { return x.b_code === '102-4'}));
         treeCalc.calculateAll(ledgerTree);
         for (const t of data.tags) {
             t.node = ledgerTree.datas.find(x => {return x.id === t.lid});

+ 113 - 111
app/public/js/material.js

@@ -73,14 +73,14 @@ DatePickerCellType.prototype.updateEditor = function (editorContext, cellStyle,
 
 function resetTpTable() {
     $('#tp_set').find('td').eq(1).text(ZhCalc.round(m_tp, materialDecimal.tp));
-    $('#tp_set').find('td').eq(2).text(ZhCalc.round(ZhCalc.add(pre_tp, m_tp), materialDecimal.tp));
+    $('#tp_set').find('td').eq(2).text(ZhCalc.add(pre_tp, ZhCalc.round(m_tp, materialDecimal.tp)));
     if (materialTax) {
         $('#tax_rate_set').find('td').eq(1).text(ZhCalc.round(m_tax_tp, materialDecimal.tp));
-        $('#tax_rate_set').find('td').eq(2).text(ZhCalc.round(ZhCalc.add(m_tax_pre_tp, m_tax_tp), materialDecimal.tp));
+        $('#tax_rate_set').find('td').eq(2).text(ZhCalc.add(m_tax_pre_tp, ZhCalc.round(m_tax_tp, materialDecimal.tp)));
     } else {
         const rate = $('#rateInput').val();
         const bqhs = ZhCalc.round(ZhCalc.mul(m_tp, 1+rate/100), materialDecimal.tp);
-        const jzbqhs = ZhCalc.round(ZhCalc.add(pre_tp_hs, bqhs), materialDecimal.tp);
+        const jzbqhs = ZhCalc.add(pre_tp_hs, bqhs);
         $('#rate_set').find('td').eq(1).text(bqhs !== 0 ? bqhs : '');
         $('#rate_set').find('td').eq(2).text(jzbqhs !== 0 ? jzbqhs : '');
     }
@@ -136,7 +136,7 @@ $(document).ready(() => {
         {title: '工料分类', colSpan: '1', rowSpan: '2', field: 'm_type', hAlign: 1, width: 60, readOnly: 'readOnly.isEdit', cellType: 'customizeCombo', comboItems: materialType.m_type, cellTypeKey: 2},
     ];
     if (materialTax) {
-        materialSpreadSettingCols.push({title: '税率(%)', colSpan: '1', rowSpan: '2', field: 'm_tax', hAlign: 2, width: 50, type: 'Number', readOnly: 'readOnly.remark'});
+        materialSpreadSettingCols.push({title: '税率(%)', colSpan: '1', rowSpan: '2', field: 'm_tax', hAlign: 2, width: 50, type: 'Number', readOnly: editTaxPermission ? 'readOnly.isEdit' : 'readOnly.remark'});
     }
     materialSpreadSettingCols = _.concat(materialSpreadSettingCols, [
         {title: '上涨 幅度(%)', colSpan: '1', rowSpan: '2', field: 'm_up_risk', hAlign: 2, width: 50, type: 'Number', readOnly: 'readOnly.isEdit'},
@@ -820,6 +820,8 @@ $(document).ready(() => {
     materialSpread.bind(spreadNS.Events.SelectionChanged, materialSpreadObj.selectionChanged);
     materialSpread.bind(spreadNS.Events.ClipboardPasted, materialSpreadObj.clipboardPasted);
     SpreadJsObj.addDeleteBind(materialSpread, materialSpreadObj.deletePress);
+    materialSpread.bind(spreadNS.Events.EditEnded, materialSpreadObj.editEnded);
+    materialSpread.bind(spreadNS.Events.ButtonClicked, materialSpreadObj.buttonClicked);
     const sheet = materialSpread.getActiveSheet();
     sheet.suspendPaint();
     // const basic_range = sheet.getRange(-1, 8, -1, 1);
@@ -1152,6 +1154,7 @@ $(document).ready(() => {
 
     materialMonthSpread.bind(spreadNS.Events.ClipboardPasted, materialMonthSpreadObj.clipboardPasted);
     SpreadJsObj.addDeleteBind(materialMonthSpread, materialMonthSpreadObj.deletePress);
+    materialMonthSpread.bind(spreadNS.Events.EditEnded, materialMonthSpreadObj.editEnded);
 
     // 期切换
     $('#myTab a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
@@ -1171,112 +1174,7 @@ $(document).ready(() => {
         }, 1000);
     });
 
-    if (!readOnly) {
-        $('#add').click(materialSpreadObj.add);
-        $('#del').click(materialSpreadObj.del);
-        $('#up-move').click(materialSpreadObj.upMove);
-        $('#down-move').click(materialSpreadObj.downMove);
-        materialSpread.bind(spreadNS.Events.EditEnded, materialSpreadObj.editEnded);
-        materialSpread.bind(spreadNS.Events.ButtonClicked, materialSpreadObj.buttonClicked);
-        materialMonthSpread.bind(spreadNS.Events.EditEnded, materialMonthSpreadObj.editEnded);
-
-        // 右键菜单
-        $.contextMenu({
-            selector: '#material-spread',
-            build: function ($trigger, e) {
-                const target = SpreadJsObj.safeRightClickSelection($trigger, e, materialSpread);
-                return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
-            },
-            items: {
-                'create': {
-                    name: '新增材料',
-                    icon: 'fa-sign-in',
-                    callback: function (key, opt) {
-                        materialSpreadObj.add(materialSpread.getActiveSheet());
-                    },
-                },
-                'delete': {
-                    name: '删除材料',
-                    icon: 'fa-remove',
-                    callback: function (key, opt) {
-                        materialSpreadObj.del(materialSpread.getActiveSheet());
-                    },
-                    disabled: function (key, opt) {
-                        const sheet = materialSpread.getActiveSheet();
-                        const select = SpreadJsObj.getSelectObject(sheet);
-                        const sel = sheet.getSelections()[0];
-                        materialSpreadObj.refreshActn(sel.rowCount);
-                        if (!readOnly && select && materialBase.isUsed(select) && sel.rowCount === 1) {
-                            return false;
-                        } else {
-                            return true;
-                        }
-                    }
-                },
-            }
-        });
-        $('.changeRate').click(function () {
-            $('#rateInput').val(parseInt($(this).data('value')));
-            $('#rateInput').siblings('.dropdown-menu').hide();
-        });
-        $('#rateInput').click(function () {
-            $(this).siblings('.dropdown-menu').show();
-        })
-        // 回车提交
-        $('#rateInput').on('keypress', function () {
-            if(window.event.keyCode === 13) {
-                $(this).blur();
-            }
-        });
-        $('#rateInput').blur(function () {
-            const _self = $(this);
-            setTimeout(function () {
-                let rate = parseFloat(_self.val());
-                if (_.isNaN(rate)) {
-                    toastr.error('请输入0-100之前的整数值');
-                    $('#rateInput').val(materialRate);
-                    return;
-                }
-                rate = _.round(rate);
-                if(rate < 0 || rate > 100) {
-                    toastr.error('请输入0-100之前的整数值');
-                    $('#rateInput').val(materialRate);
-                    return;
-                }
-                $('#rateInput').siblings('.dropdown-menu').hide();
-                console.log(rate, materialRate);
-                if (rate !== materialRate) {
-                    postData(window.location.pathname + '/save', { type:'rate', rate: rate }, function (result) {
-                        const bqhs = ZhCalc.round(ZhCalc.mul(m_tp, 1+rate/100), materialDecimal.tp);
-                        // const exbqhs = ZhCalc.round(ZhCalc.mul(ex_tp, 1+rate/100), materialDecimal.tp);
-                        const jzbqhs = ZhCalc.round(ZhCalc.add(pre_tp_hs, bqhs), materialDecimal.tp);
-                        // const exjzbqhs = ZhCalc.round(ZhCalc.add(ex_pre_tp_hs, exbqhs), materialDecimal.tp);
-                        $('#rate_set').find('td').eq(1).text(bqhs !== 0 ? bqhs : '');
-                        $('#rate_set').find('td').eq(2).text(jzbqhs !== 0 ? jzbqhs : '');
-                        // $('#rate_set').find('td').eq(3).text(exbqhs !== 0 ? exbqhs : '');
-                        // $('#rate_set').find('td').eq(4).text(exjzbqhs !== 0 ? exjzbqhs : '');
-                        materialRate = rate;
-                        $('#rateInput').val(rate);
-                    });
-                } else {
-                    $('#rateInput').val(rate);
-                }
-            }, 500);
-        });
-        // $('#changeRate').change(function () {
-        //     const rate = parseInt($(this).val());
-        //     postData(window.location.pathname + '/save', { type:'rate', rate: rate }, function (result) {
-        //         const bqhs = ZhCalc.round(ZhCalc.mul(m_tp, 1+rate/100), materialDecimal.tp);
-        //         const exbqhs = ZhCalc.round(ZhCalc.mul(ex_tp, 1+rate/100), materialDecimal.tp);
-        //         const jzbqhs = ZhCalc.round(ZhCalc.add(pre_tp_hs, bqhs), materialDecimal.tp);
-        //         const exjzbqhs = ZhCalc.round(ZhCalc.add(ex_pre_tp_hs, exbqhs), materialDecimal.tp);
-        //         $('#rate_set').find('td').eq(1).text(bqhs !== 0 ? bqhs : '');
-        //         $('#rate_set').find('td').eq(2).text(jzbqhs !== 0 ? jzbqhs : '');
-        //         $('#rate_set').find('td').eq(3).text(exbqhs !== 0 ? exbqhs : '');
-        //         $('#rate_set').find('td').eq(4).text(exjzbqhs !== 0 ? exjzbqhs : '');
-        //     });
-        // });
-
+    if (!readOnly || editForAudit) {
         $('#expr_select button').on('click', function () {
             const code = $(this).text();
             // $('#expr').val($('#expr').val() + code);
@@ -1451,6 +1349,110 @@ $(document).ready(() => {
                 $('#bcyy').modal('hide');
             });
         });
+    }
+
+    if (!readOnly && !editForAudit) {
+        $('#add').click(materialSpreadObj.add);
+        $('#del').click(materialSpreadObj.del);
+        $('#up-move').click(materialSpreadObj.upMove);
+        $('#down-move').click(materialSpreadObj.downMove);
+
+        // 右键菜单
+        $.contextMenu({
+            selector: '#material-spread',
+            build: function ($trigger, e) {
+                const target = SpreadJsObj.safeRightClickSelection($trigger, e, materialSpread);
+                return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
+            },
+            items: {
+                'create': {
+                    name: '新增材料',
+                    icon: 'fa-sign-in',
+                    callback: function (key, opt) {
+                        materialSpreadObj.add(materialSpread.getActiveSheet());
+                    },
+                },
+                'delete': {
+                    name: '删除材料',
+                    icon: 'fa-remove',
+                    callback: function (key, opt) {
+                        materialSpreadObj.del(materialSpread.getActiveSheet());
+                    },
+                    disabled: function (key, opt) {
+                        const sheet = materialSpread.getActiveSheet();
+                        const select = SpreadJsObj.getSelectObject(sheet);
+                        const sel = sheet.getSelections()[0];
+                        materialSpreadObj.refreshActn(sel.rowCount);
+                        if (!readOnly && select && materialBase.isUsed(select) && sel.rowCount === 1) {
+                            return false;
+                        } else {
+                            return true;
+                        }
+                    }
+                },
+            }
+        });
+        $('.changeRate').click(function () {
+            $('#rateInput').val(parseInt($(this).data('value')));
+            $('#rateInput').siblings('.dropdown-menu').hide();
+        });
+        $('#rateInput').click(function () {
+            $(this).siblings('.dropdown-menu').show();
+        })
+        // 回车提交
+        $('#rateInput').on('keypress', function () {
+            if(window.event.keyCode === 13) {
+                $(this).blur();
+            }
+        });
+        $('#rateInput').blur(function () {
+            const _self = $(this);
+            setTimeout(function () {
+                let rate = parseFloat(_self.val());
+                if (_.isNaN(rate)) {
+                    toastr.error('请输入0-100之前的整数值');
+                    $('#rateInput').val(materialRate);
+                    return;
+                }
+                rate = _.round(rate);
+                if(rate < 0 || rate > 100) {
+                    toastr.error('请输入0-100之前的整数值');
+                    $('#rateInput').val(materialRate);
+                    return;
+                }
+                $('#rateInput').siblings('.dropdown-menu').hide();
+                console.log(rate, materialRate);
+                if (rate !== materialRate) {
+                    postData(window.location.pathname + '/save', { type:'rate', rate: rate }, function (result) {
+                        const bqhs = ZhCalc.round(ZhCalc.mul(m_tp, 1+rate/100), materialDecimal.tp);
+                        // const exbqhs = ZhCalc.round(ZhCalc.mul(ex_tp, 1+rate/100), materialDecimal.tp);
+                        const jzbqhs = ZhCalc.round(ZhCalc.add(pre_tp_hs, bqhs), materialDecimal.tp);
+                        // const exjzbqhs = ZhCalc.round(ZhCalc.add(ex_pre_tp_hs, exbqhs), materialDecimal.tp);
+                        $('#rate_set').find('td').eq(1).text(bqhs !== 0 ? bqhs : '');
+                        $('#rate_set').find('td').eq(2).text(jzbqhs !== 0 ? jzbqhs : '');
+                        // $('#rate_set').find('td').eq(3).text(exbqhs !== 0 ? exbqhs : '');
+                        // $('#rate_set').find('td').eq(4).text(exjzbqhs !== 0 ? exjzbqhs : '');
+                        materialRate = rate;
+                        $('#rateInput').val(rate);
+                    });
+                } else {
+                    $('#rateInput').val(rate);
+                }
+            }, 500);
+        });
+        // $('#changeRate').change(function () {
+        //     const rate = parseInt($(this).val());
+        //     postData(window.location.pathname + '/save', { type:'rate', rate: rate }, function (result) {
+        //         const bqhs = ZhCalc.round(ZhCalc.mul(m_tp, 1+rate/100), materialDecimal.tp);
+        //         const exbqhs = ZhCalc.round(ZhCalc.mul(ex_tp, 1+rate/100), materialDecimal.tp);
+        //         const jzbqhs = ZhCalc.round(ZhCalc.add(pre_tp_hs, bqhs), materialDecimal.tp);
+        //         const exjzbqhs = ZhCalc.round(ZhCalc.add(ex_pre_tp_hs, exbqhs), materialDecimal.tp);
+        //         $('#rate_set').find('td').eq(1).text(bqhs !== 0 ? bqhs : '');
+        //         $('#rate_set').find('td').eq(2).text(jzbqhs !== 0 ? jzbqhs : '');
+        //         $('#rate_set').find('td').eq(3).text(exbqhs !== 0 ? exbqhs : '');
+        //         $('#rate_set').find('td').eq(4).text(exjzbqhs !== 0 ? exjzbqhs : '');
+        //     });
+        // });
 
         // 创建月信息价
         $('#make-month').click(function() {
@@ -1538,7 +1540,7 @@ $(document).ready(() => {
 
     let gljLib;
     const gljLibCellDoubleClick = function (e, info) {
-        if (readOnly) return;
+        if (readOnly || editForAudit) return;
         const gljSheet = info.sheet;
         if (!gljSheet.zh_setting || !gljSheet.zh_tree) { return; }
 

+ 8 - 0
app/public/js/material_audit.js

@@ -224,6 +224,14 @@ function checkAuditorFrom () {
         }
         return false;
     }
+    // 判断是否存在工料编号不能为空的情况
+    const nullList = _.filter(materialBillsData, function (item) {
+        return item.code === '' || item.code === null;
+    });
+    if (nullList.length > 0) {
+        toastr.error('信息价调差存在编号为空的工料,请添加编号后再上报');
+        return false;
+    }
     $('#hide-all').show();
 }
 // texterea换行

+ 10 - 5
app/public/js/material_checklist.js

@@ -140,7 +140,9 @@ $(document).ready(() => {
             for (const [index, s] of result.ledgerListData.entries()) {
                 gclGatherModel.loadLedgerData(ledger, s);
                 gclGatherModel.loadPosData(pos, result.posListData[index]);
-                const oneGclGatherData = gclGatherModel.gatherGclData();
+                const oneGclGatherData = gclGatherModel.gatherGclData().filter(item => {
+                    return item.qc_qty || item.contract_qty
+                });
                 newGclGatherListData.push(oneGclGatherData);
             }
             gclGatherListData = newGclGatherListData;
@@ -419,7 +421,7 @@ $(document).ready(() => {
         const select = SpreadJsObj.getSelectObject(sheet);
         const gclIndex = _.findIndex(gclGatherData, { b_code: select.b_code, name: select.name, unit: select.unit, unit_price: select.unit_price });
         const gcl = gclGatherData[gclIndex].leafXmjs;
-        const ms_id = isStageSelf ? parseInt($('#myTab').find('.active').data('msid')) : null;
+        const ms_id = isStageSelf ? materialStageData[0].id : null;
         const index = materialChecklistData.indexOf(select);
         const datas = [];
         for (const xmj of gcl) {
@@ -482,16 +484,17 @@ $(document).ready(() => {
                 const gclIndex = _.findIndex(gclGatherData, { b_code: select.b_code, name: select.name, unit: select.unit, unit_price: select.unit_price });
                 const gcl = gclGatherData[gclIndex].leafXmjs;
                 const datas = [];
+                const ms_id = isStageSelf ? materialStageData[0].id : null;
                 for (const xmj of gcl) {
                     const data = {
                         xmj_id: xmj.id,
                         gcl_id: xmj.gcl_id,
                         mx_id: xmj.mx_id !== undefined ? xmj.mx_id : '',
                     };
+                    if (ms_id) data.ms_id = ms_id;
                     datas.push(data);
                 }
                 if (isStageSelf) {
-                    const ms_id = isStageSelf ? materialStageData[0].id : null;
                     // 取所有的gclGatherData才行,然后获取下的值
                     const gclData = gclGatherData[gclIndex];
                     for (const [index, ms] of materialStageData.entries()) {
@@ -591,16 +594,17 @@ $(document).ready(() => {
                     const gclIndex = _.findIndex(gclGatherData, { b_code: ledgerSelect.b_code, name: ledgerSelect.name, unit: ledgerSelect.unit, unit_price: ledgerSelect.unit_price });
                     const gcl = gclGatherData[gclIndex].leafXmjs;
                     const datas = [];
+                    const ms_id = isStageSelf ? materialStageData[0].id : null;
                     for (const xmj of gcl) {
                         const data = {
                             xmj_id: xmj.id,
                             gcl_id: xmj.gcl_id,
                             mx_id: xmj.mx_id !== undefined ? xmj.mx_id : '',
                         };
+                        if (ms_id) data.ms_id = ms_id;
                         datas.push(data);
                     }
                     if (isStageSelf) {
-                        const ms_id = isStageSelf ? materialStageData[0].id : null;
                         // 取所有的gclGatherData才行,然后获取下的值
                         const gclData = gclGatherData[gclIndex];
                         for (const [index, ms] of materialStageData.entries()) {
@@ -712,16 +716,17 @@ $(document).ready(() => {
                 const gclIndex = _.findIndex(gclGatherData, { b_code: ledgerSelect.b_code, name: ledgerSelect.name, unit: ledgerSelect.unit, unit_price: ledgerSelect.unit_price });
                 const gcl = gclGatherData[gclIndex].leafXmjs;
                 const datas = [];
+                const ms_id = isStageSelf ? materialStageData[0].id : null;
                 for (const xmj of gcl) {
                     const data2 = {
                         xmj_id: xmj.id,
                         gcl_id: xmj.gcl_id,
                         mx_id: xmj.mx_id !== undefined ? xmj.mx_id : '',
                     };
+                    if (ms_id) data2.ms_id = ms_id;
                     datas.push(data2);
                 }
                 if (isStageSelf) {
-                    const ms_id = isStageSelf ? materialStageData[0].id : null;
                     // 取所有的gclGatherData才行,然后获取下的值
                     const gclData = gclGatherData[gclIndex];
                     for (const [index, ms] of materialStageData.entries()) {

+ 57 - 38
app/public/js/material_exponent.js

@@ -15,9 +15,9 @@ function getPasteHint (str, row = '') {
 function resetExTpTable() {
     const rate = $('#rateInput').val();
     const bqhs = ZhCalc.round(ZhCalc.mul(ex_tp, 1+rate/100), materialDecimal.tp);
-    const jzbqhs = ZhCalc.round(ZhCalc.add(ex_pre_tp_hs, bqhs), materialDecimal.tp);
+    const jzbqhs = ZhCalc.add(ex_pre_tp_hs, bqhs);
     $('#tp_set').find('td').eq(3).text(ZhCalc.round(ex_tp, materialDecimal.tp));
-    $('#tp_set').find('td').eq(4).text(ZhCalc.round(ZhCalc.add(ex_pre_tp, ex_tp), materialDecimal.tp));
+    $('#tp_set').find('td').eq(4).text(ZhCalc.add(ex_pre_tp, ZhCalc.round(ex_tp, materialDecimal.tp)));
     $('#rate_set').find('td').eq(3).text(bqhs !== 0 ? bqhs : '');
     $('#rate_set').find('td').eq(4).text(jzbqhs !== 0 ? jzbqhs : '');
     // $('#ex_expr').html(ex_expr);
@@ -191,7 +191,7 @@ $(document).ready(() => {
                         validText = ZhCalc.round(num, 3);
                         num = ZhCalc.round(num, 3);
                     }
-                    const total_weight = ZhCalc.add(ZhCalc.sub(_.sumBy(materialExponentData, 'weight_num'), parseFloat(orgValue)), num);
+                    const total_weight = ZhCalc.add(ZhCalc.sub(ZhCalc.sum(_.map(materialExponentData, 'weight_num')), parseFloat(orgValue)), num);
                     if (total_weight > 1) {
                         toastr.error('加权系数总和不能大于1');
                         SpreadJsObj.reLoadRowData(info.sheet, info.row);
@@ -431,52 +431,53 @@ $(document).ready(() => {
         }
     };
     materialExponentSpreadObj.refreshActn();
-    materialExponentSpread.bind(spreadNS.Events.SelectionChanged, materialExponentSpreadObj.selectionChanged);
-
 
 
     if (!readOnly) {
         $('#add').click(materialExponentSpreadObj.add);
         $('#del').click(materialExponentSpreadObj.del);
+        materialExponentSpread.bind(spreadNS.Events.SelectionChanged, materialExponentSpreadObj.selectionChanged);
         materialExponentSpread.bind(spreadNS.Events.EditEnded, materialExponentSpreadObj.editEnded);
         materialExponentSpread.bind(spreadNS.Events.ButtonClicked, materialExponentSpreadObj.buttonClicked);
         materialExponentSpread.bind(spreadNS.Events.ClipboardPasted, materialExponentSpreadObj.clipboardPasted);
-        SpreadJsObj.addDeleteBind(materialExponentSpread, materialExponentSpreadObj.deletePress);
-        // 右键菜单
-        $.contextMenu({
-            selector: '#material-exponent-spread',
-            build: function ($trigger, e) {
-                const target = SpreadJsObj.safeRightClickSelection($trigger, e, materialExponentSpread);
-                return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
-            },
-            items: {
-                'create': {
-                    name: '新增',
-                    icon: 'fa-sign-in',
-                    callback: function (key, opt) {
-                        materialExponentSpreadObj.add(materialExponentSpread.getActiveSheet());
-                    },
+        if (!editForAudit) {
+            SpreadJsObj.addDeleteBind(materialExponentSpread, materialExponentSpreadObj.deletePress);
+            // 右键菜单
+            $.contextMenu({
+                selector: '#material-exponent-spread',
+                build: function ($trigger, e) {
+                    const target = SpreadJsObj.safeRightClickSelection($trigger, e, materialExponentSpread);
+                    return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
                 },
-                'delete': {
-                    name: '删除',
-                    icon: 'fa-remove',
-                    callback: function (key, opt) {
-                        materialExponentSpreadObj.del(materialExponentSpread.getActiveSheet());
+                items: {
+                    'create': {
+                        name: '新增',
+                        icon: 'fa-sign-in',
+                        callback: function (key, opt) {
+                            materialExponentSpreadObj.add(materialExponentSpread.getActiveSheet());
+                        },
                     },
-                    disabled: function (key, opt) {
-                        const sheet = materialExponentSpread.getActiveSheet();
-                        const select = SpreadJsObj.getSelectObject(sheet);
-                        const sel = sheet.getSelections()[0];
-                        materialExponentSpreadObj.refreshActn(sel.rowCount);
-                        if (!readOnly && select && materialExponentBase.isUsed(select) && sel.rowCount === 1) {
-                            return false;
-                        } else {
-                            return true;
+                    'delete': {
+                        name: '删除',
+                        icon: 'fa-remove',
+                        callback: function (key, opt) {
+                            materialExponentSpreadObj.del(materialExponentSpread.getActiveSheet());
+                        },
+                        disabled: function (key, opt) {
+                            const sheet = materialExponentSpread.getActiveSheet();
+                            const select = SpreadJsObj.getSelectObject(sheet);
+                            const sel = sheet.getSelections()[0];
+                            materialExponentSpreadObj.refreshActn(sel.rowCount);
+                            if (!readOnly && select && materialExponentBase.isUsed(select) && sel.rowCount === 1) {
+                                return false;
+                            } else {
+                                return true;
+                            }
                         }
-                    }
-                },
-            }
-        });
+                    },
+                }
+            });
+        }
 
         // 调差基数选中
         $('.calc_select').on('click', function () {
@@ -651,4 +652,22 @@ $(document).ready(() => {
     function getObjHeight(select) {
         return select.length > 0 ? select.height() : 0;
     }
+
+    $.subMenu({
+        menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
+        toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
+        key: 'menu.1.0.0',
+        miniHint: '#sub-mini-hint', hintKey: 'menu.hint.1.0.1',
+        callback: function (info) {
+            if (info.mini) {
+                $('.panel-title').addClass('fluid');
+                $('#sub-menu').removeClass('panel-sidebar');
+            } else {
+                $('.panel-title').removeClass('fluid');
+                $('#sub-menu').addClass('panel-sidebar');
+            }
+            autoFlashHeight();
+            materialExponentSpread.refresh();
+        }
+    });
 });

+ 476 - 387
app/public/js/material_list.js

@@ -525,7 +525,7 @@ $(document).ready(() => {
             // 是否本期添加的工料
             // return data.order === stage_order && !openMaterialChecklist;
             let flag = true;
-            if (type === 'del') {
+            if (type === 'del' || !editListPermission) {
                 flag = data.order === stage_order;
             }
             return flag && !openMaterialChecklist;
@@ -599,7 +599,7 @@ $(document).ready(() => {
             // 是否本期添加的工料
             // return data.order === stage_order && !openMaterialChecklist;
             let flag = true;
-            if (type === 'del') {
+            if (type === 'del' || !editListPermission) {
                 flag = data.order === stage_order;
             }
             return flag;
@@ -613,7 +613,7 @@ $(document).ready(() => {
                 // const select = SpreadJsObj.getSelectObject(sheet);
                 // const notx = findNotJoinLeafXmj(select);
                 // return !(!readOnly && notx === undefined && materialBase.isEdit(data));
-                return !(!readOnly && materialSelfBase.isEdit(data));
+                return openMaterialSelf && !(!readOnly && materialSelfBase.isEdit(data));
             },
         },
     };
@@ -804,171 +804,237 @@ $(document).ready(() => {
         }
         $('#materialBills').find('input:disabled').prop('checked', true);
     });
-    if (!readOnly) {
-        const leafXmjSpreadObj = {
-            getSelect : function () {
-                const sheet = ledgerSpread.getActiveSheet();
-                const select = SpreadJsObj.getSelectObject(sheet);
-                const index = gclGatherData.indexOf(select);
-                const leafXmjSheet = leafXmjSpread.getActiveSheet();
-                const leafXmjSelect = SpreadJsObj.getSelectObject(leafXmjSheet);
-                const iRow = gclGatherData[index].leafXmjs.indexOf(leafXmjSelect);
-                const leafXmjs = gclGatherData[index].leafXmjs.filter(item => {
-                    return item.qc_qty || item.contract_qty
-                });
-                const nRow = leafXmjs.indexOf(leafXmjSelect);
-                const leafXmjColor = findNotJoinLeafXmj(leafXmjSelect) ? '#d6d8db' : '';
-                return [index, iRow, nRow, leafXmjSheet, leafXmjSelect, leafXmjColor];
-            },
-            checkJoinMaterial: function (type) {
-                const [iGclRow, iRow, nRow, sheet, select] = leafXmjSpreadObj.getSelect();
-                const color = type === 'join' ? '' : '#d6d8db';
-                const data = {
-                    type: type,
-                    select: type === 'join' ? findNotJoinLeafXmj(select) : select,
-                    ms_id: $('#myTab').find('.active').data('msid') || null,
-                };
-                // 添加到
-                postData(window.location.pathname + '/save', data, function (result) {
-                    if (type === 'join') {
-                        const index = findNotJoinLeafXmj(select, 'index');
-                        notJoinList.splice(index, 1);
-                    } else {
-                        notJoinList.push(result);
-                    }
-                    gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(select);
-                    calculateJiaCha(gclGatherData, iGclRow);
-                    SpreadJsObj.reLoadRowData(sheet, nRow);
-                    sheet.getRange(nRow, -1, 1, -1).backColor(color);
-                    loadMaterialData(iGclRow);
-                    SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
-                });
-            },
-            checkSelfMaterial: function (type) {
-                const [iGclRow, iRow, nRow, sheet, select, color] = leafXmjSpreadObj.getSelect();
-                // const color = type === 'self' ? '' : '#d6d8db';
-                const data = {
-                    type: type,
-                    select: type === 'noself' ? findSelfLeafXmj(select) : select,
-                    ms_id: $('#myTab').find('.active').data('msid') || null,
-                };
-                // 添加到
-                postData(window.location.pathname + '/save', data, function (result) {
-                    if (type === 'noself') {
-                        const index = findSelfLeafXmj(select, 'index');
-                        selfList.splice(index, 1);
-                        materialListData = result;
-                        $('#cancel-self').modal('hide');
-                    } else {
-                        selfList.push(result);
-                    }
-                    gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(select);
-                    calculateJiaCha(gclGatherData, iGclRow);
-                    SpreadJsObj.reLoadRowData(sheet, nRow);
-                    sheet.getRange(nRow, -1, 1, -1).backColor(color);
-                    loadXmjMaterialData(iGclRow, nRow);
-                    SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
-                });
-            },
-        }
-        // leafXmj右键功能
-        $.contextMenu({
-            selector: '#leaf-xmj-spread',
-            build: function ($trigger, e) {
-                const target = SpreadJsObj.safeRightClickSelection($trigger, e, leafXmjSpread);
-                return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
-            },
-            items: {
-                'stop': {
-                    name: '不参与调差',
-                    icon: 'fa-remove',
-                    callback: function (key, opt) {
-                        leafXmjSpreadObj.checkJoinMaterial('notjoin');
-                    },
-                    visible: function (key, opt) {
-                        const sheet = leafXmjSpread.getActiveSheet();
-                        const select = SpreadJsObj.getSelectObject(sheet);
-                        const sel = sheet.getSelections()[0];
-                        if (!select || sel.rowCount !== 1) {
-                            return false;
-                        }
-                        const notx = findNotJoinLeafXmj(select);
-                        if (!readOnly && select && notx === undefined) {
-                            return true;
-                        } else {
-                            return false;
+    const leafXmjSpreadObj = {
+        getSelect : function () {
+            const sheet = ledgerSpread.getActiveSheet();
+            const select = SpreadJsObj.getSelectObject(sheet);
+            const index = gclGatherData.indexOf(select);
+            const leafXmjSheet = leafXmjSpread.getActiveSheet();
+            const leafXmjSelect = SpreadJsObj.getSelectObject(leafXmjSheet);
+            const iRow = gclGatherData[index].leafXmjs.indexOf(leafXmjSelect);
+            const leafXmjs = gclGatherData[index].leafXmjs.filter(item => {
+                return item.qc_qty || item.contract_qty
+            });
+            const nRow = leafXmjs.indexOf(leafXmjSelect);
+            const leafXmjColor = findNotJoinLeafXmj(leafXmjSelect) ? '#d6d8db' : '';
+            return [index, iRow, nRow, leafXmjSheet, leafXmjSelect, leafXmjColor];
+        },
+        checkJoinMaterial: function (type) {
+            const [iGclRow, iRow, nRow, sheet, select] = leafXmjSpreadObj.getSelect();
+            const color = type === 'join' ? '' : '#d6d8db';
+            const data = {
+                type: type,
+                select: type === 'join' ? findNotJoinLeafXmj(select) : select,
+                ms_id: $('#myTab').find('.active').data('msid') || null,
+            };
+            // 添加到
+            postData(window.location.pathname + '/save', data, function (result) {
+                if (type === 'join') {
+                    const index = findNotJoinLeafXmj(select, 'index');
+                    notJoinList.splice(index, 1);
+                } else {
+                    notJoinList.push(result);
+                }
+                gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(select);
+                calculateJiaCha(gclGatherData, iGclRow);
+                SpreadJsObj.reLoadRowData(sheet, nRow);
+                sheet.getRange(nRow, -1, 1, -1).backColor(color);
+                loadMaterialData(iGclRow);
+                SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
+            });
+        },
+        checkSelfMaterial: function (type) {
+            const [iGclRow, iRow, nRow, sheet, select, color] = leafXmjSpreadObj.getSelect();
+            // const color = type === 'self' ? '' : '#d6d8db';
+            const data = {
+                type: type,
+                select: type === 'noself' ? findSelfLeafXmj(select) : select,
+                ms_id: $('#myTab').find('.active').data('msid') || null,
+            };
+            if (type === 'noself') {
+                if (isStageSelf) {
+                    data.select.gather_qty = {};
+                    const ledgerSheet = ledgerSpread.getActiveSheet();
+                    const ledgerSelect = SpreadJsObj.getSelectObject(ledgerSheet);
+                    const index = gclGatherData.indexOf(ledgerSelect);
+                    // 取所有的gclGatherData才行,然后获取下的值
+                    const gclData = gclGatherData[index];
+                    for (const [index, ms] of materialStageData.entries()) {
+                        const gclOther = _.find(gclGatherListData[index], { b_code: gclData.b_code, name: gclData.name, unit: gclData.unit, unit_price: gclData.unit_price });
+                        let gather_qty = null;
+                        if (gclOther) {
+                            const leafXmjs = gclOther.leafXmjs.filter(item => item.gather_qty !== null && item.gather_qty !== undefined);
+                            const oneXmj = _.find(leafXmjs, function (item) {
+                                return item.gcl_id === select.gcl_id && item.id === select.id && (select.mx_id === undefined || item.mx_id === select.mx_id);
+                            });
+                            if (oneXmj) gather_qty = oneXmj.gather_qty;
                         }
+                        data.select.gather_qty['ms_id_' + ms.id] = gather_qty;
                     }
+                } else {
+                    data.select.gather_qty = select.gather_qty ? select.gather_qty : null;
+                }
+            }
+            console.log(data);
+            // 添加到
+            postData(window.location.pathname + '/save', data, function (result) {
+                if (type === 'noself') {
+                    const index = findSelfLeafXmj(select, 'index');
+                    selfList.splice(index, 1);
+                    materialListData = result;
+                    $('#cancel-self').modal('hide');
+                } else {
+                    selfList.push(result.info);
+                    materialListData = result.materialListData;
+                }
+                gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(select);
+                calculateJiaCha(gclGatherData, iGclRow);
+                SpreadJsObj.reLoadRowData(sheet, nRow);
+                sheet.getRange(nRow, -1, 1, -1).backColor(color);
+                loadXmjMaterialData(iGclRow, nRow);
+                SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
+            });
+        },
+    }
+    if (!readOnly) {
+        // leafXmj右键功能
+        if (!editForAudit) {
+            $.contextMenu({
+                selector: '#leaf-xmj-spread',
+                build: function ($trigger, e) {
+                    const target = SpreadJsObj.safeRightClickSelection($trigger, e, leafXmjSpread);
+                    return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
                 },
-                'start': {
-                    name: '参与调差',
-                    icon: 'fa-sign-in',
-                    callback: function (key, opt) {
-                        leafXmjSpreadObj.checkJoinMaterial('join');
-                    },
-                    visible: function (key, opt) {
-                        const sheet = leafXmjSpread.getActiveSheet();
-                        const select = SpreadJsObj.getSelectObject(sheet);
-                        const sel = sheet.getSelections()[0];
-                        if (!select || sel.rowCount !== 1) {
-                            return false;
-                        }
-                        const notx = findNotJoinLeafXmj(select);
-                        if (!readOnly && select && notx === undefined) {
-                            return false;
-                        } else {
-                            return true;
+                items: {
+                    'stop': {
+                        name: '不参与调差',
+                        icon: 'fa-remove',
+                        callback: function (key, opt) {
+                            leafXmjSpreadObj.checkJoinMaterial('notjoin');
+                        },
+                        visible: function (key, opt) {
+                            const sheet = leafXmjSpread.getActiveSheet();
+                            const select = SpreadJsObj.getSelectObject(sheet);
+                            const sel = sheet.getSelections()[0];
+                            if (!select || sel.rowCount !== 1) {
+                                return false;
+                            }
+                            const notx = findNotJoinLeafXmj(select);
+                            if (!readOnly && select && notx === undefined) {
+                                return true;
+                            } else {
+                                return false;
+                            }
                         }
                     },
-                },
-                'self': {
-                    name: '单独添加工料',
-                    icon: 'fa-sign-in',
-                    callback: function (key, opt) {
-                        leafXmjSpreadObj.checkSelfMaterial('self');
+                    'start': {
+                        name: '参与调差',
+                        icon: 'fa-sign-in',
+                        callback: function (key, opt) {
+                            leafXmjSpreadObj.checkJoinMaterial('join');
+                        },
+                        visible: function (key, opt) {
+                            const sheet = leafXmjSpread.getActiveSheet();
+                            const select = SpreadJsObj.getSelectObject(sheet);
+                            const sel = sheet.getSelections()[0];
+                            if (!select || sel.rowCount !== 1) {
+                                return false;
+                            }
+                            const notx = findNotJoinLeafXmj(select);
+                            if (!readOnly && select && notx === undefined) {
+                                return false;
+                            } else {
+                                return true;
+                            }
+                        },
                     },
-                    visible: function (key, opt) {
-                        const sheet = leafXmjSpread.getActiveSheet();
-                        const select = SpreadJsObj.getSelectObject(sheet);
-                        const sel = sheet.getSelections()[0];
-                        if (!select || sel.rowCount !== 1) {
-                            return false;
-                        }
-                        const notx = findSelfLeafXmj(select);
-                        if (!readOnly && select && notx === undefined) {
-                            return true;
-                        } else {
-                            return false;
+                    'self': {
+                        name: '单独添加工料',
+                        icon: 'fa-sign-in',
+                        callback: function (key, opt) {
+                            leafXmjSpreadObj.checkSelfMaterial('self');
+                        },
+                        visible: function (key, opt) {
+                            if (!openMaterialSelf) {
+                                return false;
+                            }
+                            const sheet = leafXmjSpread.getActiveSheet();
+                            const select = SpreadJsObj.getSelectObject(sheet);
+                            const sel = sheet.getSelections()[0];
+                            if (!select || sel.rowCount !== 1) {
+                                return false;
+                            }
+                            const notx = findSelfLeafXmj(select);
+                            if (!readOnly && select && notx === undefined) {
+                                return true;
+                            } else {
+                                return false;
+                            }
                         }
-                    }
-                },
-                'noself': {
-                    name: '取消单独添加工料',
-                    icon: 'fa-remove',
-                    callback: function (key, opt) {
-                        $('#cancel-self').modal('show');
-                        // leafXmjSpreadObj.checkSelfMaterial('noself');
                     },
-                    visible: function (key, opt) {
-                        const sheet = leafXmjSpread.getActiveSheet();
-                        const select = SpreadJsObj.getSelectObject(sheet);
-                        const sel = sheet.getSelections()[0];
-                        if (!select || sel.rowCount !== 1) {
-                            return false;
-                        }
-                        const notx = findSelfLeafXmj(select);
-                        if (!readOnly && select && notx === undefined) {
-                            return false;
-                        } else {
-                            return true;
-                        }
+                    'noself': {
+                        name: '取消单独添加工料',
+                        icon: 'fa-remove',
+                        callback: function (key, opt) {
+                            $('#cancel-self').modal('show');
+                            // leafXmjSpreadObj.checkSelfMaterial('noself');
+                        },
+                        visible: function (key, opt) {
+                            if (!openMaterialSelf) {
+                                return false;
+                            }
+                            const sheet = leafXmjSpread.getActiveSheet();
+                            const select = SpreadJsObj.getSelectObject(sheet);
+                            const sel = sheet.getSelections()[0];
+                            if (!select || sel.rowCount !== 1) {
+                                return false;
+                            }
+                            const notx = findSelfLeafXmj(select);
+                            if (!readOnly && select && notx === undefined) {
+                                return false;
+                            } else {
+                                return true;
+                            }
+                        },
+                        disabled: function (key, opt) {
+                            // const sheet = ledgerSpread.getActiveSheet();
+                            // const select = SpreadJsObj.getSelectObject(sheet);
+                            // const index = gclGatherData.indexOf(select);
+                            // const leafXmjSheet = leafXmjSpread.getActiveSheet();
+                            // const leafXmjSelect = SpreadJsObj.getSelectObject(leafXmjSheet);
+                            // const iRow = gclGatherData[index].leafXmjs.indexOf(leafXmjSelect);
+                            // const leafXmjs = gclGatherData[index].leafXmjs.filter(item => {
+                            //     return item.qc_qty || item.contract_qty
+                            // });
+                            // const nRow = leafXmjs.indexOf(leafXmjSelect);
+                            // const leafXmjColor = findNotJoinLeafXmj(leafXmjSelect) ? '#d6d8db' : '';
+                            // return [index, iRow, nRow, leafXmjSheet, leafXmjSelect, leafXmjColor];
+                            const [iGclRow, iRow, nRow, sheet, select, color] = leafXmjSpreadObj.getSelect();
+                            const gcl = gclGatherData[iGclRow];
+                            const leafXmjs = gcl && gcl.leafXmjs ? gcl.leafXmjs.filter(item => {
+                                return item.qc_qty || item.contract_qty
+                            }) : null;
+                            let flag = false;
+                            if (leafXmjs) {
+                                const xmj = leafXmjs[nRow];
+                                if (_.findIndex(selfList, { gcl_id: xmj.gcl_id, xmj_id: xmj.id, mx_id: (xmj.mx_id ? xmj.mx_id : '') }) != -1) {
+                                    for (const m of materialListData) {
+                                        if (m.gcl_id === xmj.gcl_id && m.xmj_id === xmj.id && ((xmj.mx_id !==undefined && m.mx_id === xmj.mx_id) || xmj.mx_id === undefined) && m.order !== stage_order) {
+                                            flag = true;
+                                            break;
+                                        }
+                                    }
+                                }
+                            }
+                            return flag;
+                        },
                     },
-                },
-            }
-        });
-        $('#cancelSelfBtn').click(function () {
-            leafXmjSpreadObj.checkSelfMaterial('noself');
-        });
+                }
+            });
+            $('#cancelSelfBtn').click(function () {
+                leafXmjSpreadObj.checkSelfMaterial('noself');
+            });
+        }
         // material-spread右键功能
         const materialSpreadObj = {
             del: function () {
@@ -1450,148 +1516,66 @@ $(document).ready(() => {
         materialSpread.bind(spreadNS.Events.ClipboardPasted, materialSpreadObj.clipboardPasted);
         SpreadJsObj.addDeleteBind(materialSpread, materialSpreadObj.deletePress);
         // material-spread右键功能
-        const materialSelfSpreadObj = {
-            del: function () {
-                const sheet = materialSelfSpread.getActiveSheet();
-                const select = SpreadJsObj.getSelectObject(sheet);
-                console.log(select);
-                postData(window.location.pathname + '/save', {type: 'del', id: select.id, mb_id: select.mb_id, ms_id: $('#myTab').find('.active').data('msid') || null}, function (result) {
-                    const index = materialListSelf.indexOf(select);
-                    materialListSelf.splice(index, 1);
-                    sheet.deleteRows(index, 1);
-                    SpreadJsObj.reLoadSheetData(materialSelfSpread.getActiveSheet());
-                    const sel = sheet.getSelections();
-                    sheet.setSelection(index > 0 ? index - 1 : 0, sel.length > 0 ? sel[0].col : 0, 1, 1);
-                    const materialListIndex = materialListData.indexOf(select);
-                    materialListData.splice(materialListIndex, 1);
-                    const [iGclRow, iRow, nRow, lsheet, lselect, color] = leafXmjSpreadObj.getSelect();
-                    gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(lselect);
-                    calculateJiaCha(gclGatherData, iGclRow);
-                    SpreadJsObj.reLoadRowData(lsheet, nRow);
-                    lsheet.getRange(nRow, -1, 1, -1).backColor(color);
-                    SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
-                });
-            },
-            deletePress: function (sheet) {
-                return;
-            },
-            editStarting: function (e, info) {
-                const col = info.sheet.zh_setting.cols[info.col];
-                const select = SpreadJsObj.getSelectObject(info.sheet);
-                if (col.field === 'quantity') {
-                    if (select.expr && select.expr !== '') {
-                        info.sheet.getCell(info.row, info.col).text(select.expr);
-                    }
-                }
-            },
-            editEnded: function (e, info) {
-                if (info.sheet.zh_setting) {
-                    const select = SpreadJsObj.getSelectObject(info.sheet);
-                    const col = info.sheet.zh_setting.cols[info.col];
-                    // 未改变值则不提交
-                    // const validText = info.editingText ? (typeof(info.editingText) === 'String' ? info.editingText.replace('\n', '') : info.editingText) : null;
-                    // const validText = is_numeric(info.editingText) ? parseFloat(info.editingText) : (info.editingText ? trimInvalidChar(info.editingText) : null);
-                    // let orgValue = select[col.field];
-                    const validText = info.editingText ? info.editingText.replace('\n', '') : null;
-                    let orgValue;
-                    if (col.field === 'quantity') {
-                        orgValue = validText && validText !== ''
-                            ? _.toNumber(validText) ? select.quantity : select.expr
-                            : (select.expr && select.expr !== '') ? select.expr : select.quantity;
-                    } else {
-                        orgValue = select[col.field];
-                    }
-                    if (orgValue == validText || ((!orgValue || orgValue === '') && (validText === '' || validText === null))) {
-                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                        return;
-                    }
-                    const exprQuantity = {
-                        expr: '',
-                        quantity: 0,
-                    };
-                    const [valid, msg] = materialSpreadObj._checkExpr(validText, exprQuantity);
-                    if (!valid) {
-                        toastr.error(msg);
-                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                        return;
-                    }
-                    if (isNaN(exprQuantity.quantity)) {
-                        toastr.error('不能输入其它非数字类型字符');
-                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                        return;
-                    }
-                    const num = parseFloat(exprQuantity.quantity);
-                    if (num < 0 || !/^\d+(\.\d{1,6})?$/.test(num)) {
-                        // toastr.error('数量值必须大于0并且小于6位小数的浮点数');
-                        // SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                        // return;
-                        toastr.warning('已保留6位小数');
-                        exprQuantity.quantity = ZhCalc.round(num, 6);
-                    }
-                    // 更新至服务器
-                    console.log(exprQuantity, select.mb_id);
-                    postData(window.location.pathname + '/save', { type:'update', updateData: { id: select.id, expr: exprQuantity.expr, quantity: exprQuantity.quantity, mb_id: select.mb_id }, ms_id: $('#myTab').find('.active').data('msid') || null }, function (result) {
+        if (openMaterialSelf) {
+            const materialSelfSpreadObj = {
+                del: function () {
+                    const sheet = materialSelfSpread.getActiveSheet();
+                    const select = SpreadJsObj.getSelectObject(sheet);
+                    console.log(select);
+                    postData(window.location.pathname + '/save', {
+                        type: 'del',
+                        id: select.id,
+                        mb_id: select.mb_id,
+                        ms_id: $('#myTab').find('.active').data('msid') || null
+                    }, function (result) {
+                        const index = materialListSelf.indexOf(select);
+                        materialListSelf.splice(index, 1);
+                        sheet.deleteRows(index, 1);
+                        SpreadJsObj.reLoadSheetData(materialSelfSpread.getActiveSheet());
+                        const sel = sheet.getSelections();
+                        sheet.setSelection(index > 0 ? index - 1 : 0, sel.length > 0 ? sel[0].col : 0, 1, 1);
                         const materialListIndex = materialListData.indexOf(select);
-                        const index = materialList.indexOf(select);
-                        select.quantity = exprQuantity.quantity;
-                        select.expr = exprQuantity.expr;
-                        materialListData.splice(materialListIndex, 1, select);
-                        materialList.indexOf(index, 1, select);
-                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
-                        const [iGclRow, iRow, nRow, sheet, lselect, color] = leafXmjSpreadObj.getSelect();
+                        materialListData.splice(materialListIndex, 1);
+                        const [iGclRow, iRow, nRow, lsheet, lselect, color] = leafXmjSpreadObj.getSelect();
                         gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(lselect);
                         calculateJiaCha(gclGatherData, iGclRow);
-                        SpreadJsObj.reLoadRowData(sheet, nRow);
-                        console.log(lselect, color);
-                        sheet.getRange(nRow, -1, 1, -1).backColor(color);
+                        SpreadJsObj.reLoadRowData(lsheet, nRow);
+                        lsheet.getRange(nRow, -1, 1, -1).backColor(color);
                         SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
-                    }, function () {
-                        SpreadJsObj.reLoadRowData(info.sheet, info.row);
                     });
-                }
-            },
-            clipboardPasted(e, info) {
-                const hint = {
-                    cellError: {type: 'error', msg: '粘贴内容超出了表格范围'},
-                    numberExpr: {type: 'error', msg: '不能粘贴其它非数字类型字符'},
-                    numberCan: {type: 'warning', msg: '已保留6位小数'},
-                };
-                const range = info.cellRange;
-                const sortData = info.sheet.zh_data || [];
-                if (range.row + range.rowCount > sortData.length) {
-                    toastMessageUniq(hint.cellError);
-                    SpreadJsObj.reLoadSheetHeader(materialSpread.getActiveSheet());
-                    SpreadJsObj.reLoadSheetData(materialSpread.getActiveSheet());
-                    return;
-                }
-                if (sortData.length > 0 && range.col + range.colCount > 5) {
-                    toastMessageUniq(hint.cellError);
-                    SpreadJsObj.reLoadSheetHeader(materialSpread.getActiveSheet());
-                    SpreadJsObj.reLoadSheetData(materialSpread.getActiveSheet());
+                },
+                deletePress: function (sheet) {
                     return;
-                }
-                const data = [];
-                for (let iRow = 0; iRow < range.rowCount; iRow++) {
-                    let bPaste = true;
-                    const curRow = range.row + iRow;
-                    const materialData = { id: sortData[curRow].id, mb_id: sortData[curRow].mb_id };
-                    const hintRow = range.rowCount > 1 ? curRow : '';
-                    let sameCol = 0;
-                    for (let iCol = 0; iCol < range.colCount; iCol++) {
-                        const curCol = range.col + iCol;
-                        const colSetting = info.sheet.zh_setting.cols[curCol];
-                        if (!colSetting) continue;
-
-                        // let validText = info.sheet.getText(curRow, curCol);
-                        // validText = is_numeric(validText) ? parseFloat(validText) : (validText ? trimInvalidChar(validText) : null);
-                        const validText = info.sheet.getText(curRow, curCol).replace('\n', '');
-                        const orgValue = sortData[curRow][colSetting.field];
-                        if (orgValue == validText || ((!orgValue || orgValue === '') && (validText === ''))) {
-                            sameCol++;
-                            if (range.colCount === sameCol)  {
-                                bPaste = false;
-                            }
-                            continue;
+                },
+                editStarting: function (e, info) {
+                    const col = info.sheet.zh_setting.cols[info.col];
+                    const select = SpreadJsObj.getSelectObject(info.sheet);
+                    if (col.field === 'quantity') {
+                        if (select.expr && select.expr !== '') {
+                            info.sheet.getCell(info.row, info.col).text(select.expr);
+                        }
+                    }
+                },
+                editEnded: function (e, info) {
+                    if (info.sheet.zh_setting) {
+                        const select = SpreadJsObj.getSelectObject(info.sheet);
+                        const col = info.sheet.zh_setting.cols[info.col];
+                        // 未改变值则不提交
+                        // const validText = info.editingText ? (typeof(info.editingText) === 'String' ? info.editingText.replace('\n', '') : info.editingText) : null;
+                        // const validText = is_numeric(info.editingText) ? parseFloat(info.editingText) : (info.editingText ? trimInvalidChar(info.editingText) : null);
+                        // let orgValue = select[col.field];
+                        const validText = info.editingText ? info.editingText.replace('\n', '') : null;
+                        let orgValue;
+                        if (col.field === 'quantity') {
+                            orgValue = validText && validText !== ''
+                                ? _.toNumber(validText) ? select.quantity : select.expr
+                                : (select.expr && select.expr !== '') ? select.expr : select.quantity;
+                        } else {
+                            orgValue = select[col.field];
+                        }
+                        if (orgValue == validText || ((!orgValue || orgValue === '') && (validText === '' || validText === null))) {
+                            SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                            return;
                         }
                         const exprQuantity = {
                             expr: '',
@@ -1599,56 +1583,213 @@ $(document).ready(() => {
                         };
                         const [valid, msg] = materialSpreadObj._checkExpr(validText, exprQuantity);
                         if (!valid) {
-                            toastMessageUniq(getPasteHint(msg, hintRow));
-                            bPaste = false;
-                            continue;
+                            toastr.error(msg);
+                            SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                            return;
                         }
                         if (isNaN(exprQuantity.quantity)) {
-                            toastMessageUniq(getPasteHint(hint.numberExpr, hintRow));
-                            bPaste = false;
-                            continue;
+                            toastr.error('不能输入其它非数字类型字符');
+                            SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                            return;
                         }
                         const num = parseFloat(exprQuantity.quantity);
                         if (num < 0 || !/^\d+(\.\d{1,6})?$/.test(num)) {
-                            toastMessageUniq(getPasteHint(hint.numberCan, hintRow));
-                            // bPaste = false;
-                            // continue;
+                            // toastr.error('数量值必须大于0并且小于6位小数的浮点数');
+                            // SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                            // return;
+                            toastr.warning('已保留6位小数');
                             exprQuantity.quantity = ZhCalc.round(num, 6);
                         }
-                        // materialData[colSetting.field] = validText;
-                        materialData.expr = exprQuantity.expr;
-                        materialData.quantity = exprQuantity.quantity;
+                        // 更新至服务器
+                        console.log(exprQuantity, select.mb_id);
+                        postData(window.location.pathname + '/save', {
+                            type: 'update',
+                            updateData: {
+                                id: select.id,
+                                expr: exprQuantity.expr,
+                                quantity: exprQuantity.quantity,
+                                mb_id: select.mb_id
+                            },
+                            ms_id: $('#myTab').find('.active').data('msid') || null
+                        }, function (result) {
+                            const materialListIndex = materialListData.indexOf(select);
+                            const index = materialList.indexOf(select);
+                            select.quantity = exprQuantity.quantity;
+                            select.expr = exprQuantity.expr;
+                            materialListData.splice(materialListIndex, 1, select);
+                            materialList.indexOf(index, 1, select);
+                            SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                            const [iGclRow, iRow, nRow, sheet, lselect, color] = leafXmjSpreadObj.getSelect();
+                            gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(lselect);
+                            calculateJiaCha(gclGatherData, iGclRow);
+                            SpreadJsObj.reLoadRowData(sheet, nRow);
+                            console.log(lselect, color);
+                            sheet.getRange(nRow, -1, 1, -1).backColor(color);
+                            SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
+                        }, function () {
+                            SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                        });
                     }
-                    if (bPaste) {
-                        data.push(materialData);
-                        // rowData.push(curRow);
-                    } else {
-                        SpreadJsObj.reLoadRowData(info.sheet, curRow);
+                },
+                clipboardPasted(e, info) {
+                    const hint = {
+                        cellError: {type: 'error', msg: '粘贴内容超出了表格范围'},
+                        numberExpr: {type: 'error', msg: '不能粘贴其它非数字类型字符'},
+                        numberCan: {type: 'warning', msg: '已保留6位小数'},
+                    };
+                    const range = info.cellRange;
+                    const sortData = info.sheet.zh_data || [];
+                    if (range.row + range.rowCount > sortData.length) {
+                        toastMessageUniq(hint.cellError);
+                        SpreadJsObj.reLoadSheetHeader(materialSpread.getActiveSheet());
+                        SpreadJsObj.reLoadSheetData(materialSpread.getActiveSheet());
+                        return;
+                    }
+                    if (sortData.length > 0 && range.col + range.colCount > 5) {
+                        toastMessageUniq(hint.cellError);
+                        SpreadJsObj.reLoadSheetHeader(materialSpread.getActiveSheet());
+                        SpreadJsObj.reLoadSheetData(materialSpread.getActiveSheet());
+                        return;
+                    }
+                    const data = [];
+                    for (let iRow = 0; iRow < range.rowCount; iRow++) {
+                        let bPaste = true;
+                        const curRow = range.row + iRow;
+                        const materialData = {id: sortData[curRow].id, mb_id: sortData[curRow].mb_id};
+                        const hintRow = range.rowCount > 1 ? curRow : '';
+                        let sameCol = 0;
+                        for (let iCol = 0; iCol < range.colCount; iCol++) {
+                            const curCol = range.col + iCol;
+                            const colSetting = info.sheet.zh_setting.cols[curCol];
+                            if (!colSetting) continue;
+
+                            // let validText = info.sheet.getText(curRow, curCol);
+                            // validText = is_numeric(validText) ? parseFloat(validText) : (validText ? trimInvalidChar(validText) : null);
+                            const validText = info.sheet.getText(curRow, curCol).replace('\n', '');
+                            const orgValue = sortData[curRow][colSetting.field];
+                            if (orgValue == validText || ((!orgValue || orgValue === '') && (validText === ''))) {
+                                sameCol++;
+                                if (range.colCount === sameCol) {
+                                    bPaste = false;
+                                }
+                                continue;
+                            }
+                            const exprQuantity = {
+                                expr: '',
+                                quantity: 0,
+                            };
+                            const [valid, msg] = materialSpreadObj._checkExpr(validText, exprQuantity);
+                            if (!valid) {
+                                toastMessageUniq(getPasteHint(msg, hintRow));
+                                bPaste = false;
+                                continue;
+                            }
+                            if (isNaN(exprQuantity.quantity)) {
+                                toastMessageUniq(getPasteHint(hint.numberExpr, hintRow));
+                                bPaste = false;
+                                continue;
+                            }
+                            const num = parseFloat(exprQuantity.quantity);
+                            if (num < 0 || !/^\d+(\.\d{1,6})?$/.test(num)) {
+                                toastMessageUniq(getPasteHint(hint.numberCan, hintRow));
+                                // bPaste = false;
+                                // continue;
+                                exprQuantity.quantity = ZhCalc.round(num, 6);
+                            }
+                            // materialData[colSetting.field] = validText;
+                            materialData.expr = exprQuantity.expr;
+                            materialData.quantity = exprQuantity.quantity;
+                        }
+                        if (bPaste) {
+                            data.push(materialData);
+                            // rowData.push(curRow);
+                        } else {
+                            SpreadJsObj.reLoadRowData(info.sheet, curRow);
+                        }
+                    }
+                    if (data.length === 0) {
+                        SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
+                        return;
+                    }
+                    console.log(data);
+                    postData(window.location.pathname + '/save', {
+                        type: 'paste',
+                        updateData: data,
+                        ms_id: $('#myTab').find('.active').data('msid') || null
+                    }, function (result) {
+                        materialListData = result;
+                        const [iGclRow, iRow, nRow, sheet, lselect] = leafXmjSpreadObj.getSelect();
+                        gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(lselect);
+                        calculateJiaCha(gclGatherData, iGclRow);
+                        SpreadJsObj.reLoadRowData(sheet, nRow);
+                        SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
+                        loadXmjMaterialData(iGclRow, nRow);
+                    }, function () {
+                        SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
+                    });
+                },
+            };
+            materialSelfSpread.bind(spreadNS.Events.EditStarting, materialSelfSpreadObj.editStarting);
+            materialSelfSpread.bind(spreadNS.Events.EditEnded, materialSelfSpreadObj.editEnded);
+            materialSelfSpread.bind(spreadNS.Events.ClipboardPasted, materialSelfSpreadObj.clipboardPasted);
+            SpreadJsObj.addDeleteBind(materialSelfSpread, materialSelfSpreadObj.deletePress);
+
+            if (!editForAudit) {
+                $.contextMenu({
+                    selector: '#material-self-spread',
+                    build: function ($trigger, e) {
+                        const target = SpreadJsObj.safeRightClickSelection($trigger, e, materialSelfSpread);
+                        return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
+                    },
+                    items: {
+                        'create': {
+                            name: '添加工料',
+                            icon: 'fa-sign-in',
+                            callback: function (key, opt) {
+                                // 获取已选清单
+                                changeMaterialTable('self');
+                                $('#add_type').val('self');
+                                $('#addgl').modal('show');
+                            },
+                            disabled: function (key, opt) {
+                                const sheet = leafXmjSpread.getActiveSheet();
+                                const select = SpreadJsObj.getSelectObject(sheet);
+                                // const notx = findNotJoinLeafXmj(select);
+                                if (!select) {
+                                    return true;
+                                }
+                                // if (!readOnly && notx === undefined) {
+                                //     return false;
+                                // } else {
+                                //     return true;
+                                // }
+                                return readOnly;
+                            },
+                        },
+                        'delete': {
+                            name: '删除工料',
+                            icon: 'fa-remove',
+                            callback: function (key, opt) {
+                                materialSelfSpreadObj.del(materialSelfSpread.getActiveSheet());
+                            },
+                            disabled: function (key, opt) {
+                                const sheet = materialSelfSpread.getActiveSheet();
+                                const select = SpreadJsObj.getSelectObject(sheet);
+                                if (!select) {
+                                    return true;
+                                }
+                                if (!readOnly && select && materialSelfBase.isEdit(select, 'del')) {
+                                    return false;
+                                } else {
+                                    return true;
+                                }
+                            }
+                        },
                     }
-                }
-                if (data.length === 0) {
-                    SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
-                    return;
-                }
-                console.log(data);
-                postData(window.location.pathname + '/save', { type:'paste', updateData: data, ms_id: $('#myTab').find('.active').data('msid') || null }, function (result) {
-                    materialListData = result;
-                    const [iGclRow, iRow, nRow, sheet, lselect] = leafXmjSpreadObj.getSelect();
-                    gclGatherData[iGclRow].leafXmjs[iRow].jiacha = calcOneBQJC(lselect);
-                    calculateJiaCha(gclGatherData, iGclRow);
-                    SpreadJsObj.reLoadRowData(sheet, nRow);
-                    SpreadJsObj.reLoadRowData(ledgerSpread.getActiveSheet(), iGclRow);
-                    loadXmjMaterialData(iGclRow, nRow);
-                }, function () {
-                    SpreadJsObj.reLoadRowData(info.sheet, info.cellRange.row, info.cellRange.rowCount);
                 });
-            },
-        };
-        materialSelfSpread.bind(spreadNS.Events.EditStarting, materialSelfSpreadObj.editStarting);
-        materialSelfSpread.bind(spreadNS.Events.EditEnded, materialSelfSpreadObj.editEnded);
-        materialSelfSpread.bind(spreadNS.Events.ClipboardPasted, materialSelfSpreadObj.clipboardPasted);
-        SpreadJsObj.addDeleteBind(materialSelfSpread, materialSelfSpreadObj.deletePress);
-        if (!openMaterialChecklist) {
+            }
+        }
+        if (!openMaterialChecklist && !editForAudit) {
             $.contextMenu({
                 selector: '#material-spread',
                 build: function ($trigger, e) {
@@ -1702,58 +1843,6 @@ $(document).ready(() => {
                 }
             });
         }
-        $.contextMenu({
-            selector: '#material-self-spread',
-            build: function ($trigger, e) {
-                const target = SpreadJsObj.safeRightClickSelection($trigger, e, materialSelfSpread);
-                return target.hitTestType === GC.Spread.Sheets.SheetArea.viewport || target.hitTestType === GC.Spread.Sheets.SheetArea.rowHeader;
-            },
-            items: {
-                'create': {
-                    name: '添加工料',
-                    icon: 'fa-sign-in',
-                    callback: function (key, opt) {
-                        // 获取已选清单
-                        changeMaterialTable('self');
-                        $('#add_type').val('self');
-                        $('#addgl').modal('show');
-                    },
-                    disabled: function (key, opt) {
-                        const sheet = leafXmjSpread.getActiveSheet();
-                        const select = SpreadJsObj.getSelectObject(sheet);
-                        // const notx = findNotJoinLeafXmj(select);
-                        if (!select) {
-                            return true;
-                        }
-                        // if (!readOnly && notx === undefined) {
-                        //     return false;
-                        // } else {
-                        //     return true;
-                        // }
-                        return readOnly;
-                    }
-                },
-                'delete': {
-                    name: '删除工料',
-                    icon: 'fa-remove',
-                    callback: function (key, opt) {
-                        materialSelfSpreadObj.del(materialSelfSpread.getActiveSheet());
-                    },
-                    disabled: function (key, opt) {
-                        const sheet = materialSelfSpread.getActiveSheet();
-                        const select = SpreadJsObj.getSelectObject(sheet);
-                        if (!select) {
-                            return true;
-                        }
-                        if (!readOnly && select) {
-                            return false;
-                        } else {
-                            return true;
-                        }
-                    }
-                },
-            }
-        });
     }
 
     // 应用调差工料至其他清单明细

+ 71 - 0
app/public/js/path_tree.js

@@ -1054,6 +1054,7 @@ const createNewPathTree = function (type, setting) {
     }
 
     class LedgerTree extends FxTree {
+
         /**
          *
          * @param parent
@@ -1128,6 +1129,10 @@ const createNewPathTree = function (type, setting) {
     }
 
     class ReviseTree extends LedgerTree {
+        constructor (setting) {
+            super(setting);
+            this.price = [];
+        }
         checkNodeUsed(node, pos) {
             if (node.children && node.children.length > 0) {
                 for (const child of node.children) {
@@ -1145,6 +1150,72 @@ const createNewPathTree = function (type, setting) {
             }
             return false;
         }
+        loadRevisePrice(price, decimal) {
+            this.decimal = decimal;
+            this.price = price || [];
+        }
+        checkRevisePrice(d) {
+            const p = this.price.find(x => {
+                return x.b_code === d.b_code &&
+                    ((!x.name && !d.name) || x.name === d.name) &&
+                    ((!x.unit && !d.unit) || x.unit === d.unit) &&
+                    checkZero(x.org_price - d.unit_price);
+            });
+            if (!p) return false;
+            d.org_price = p.org_price;
+            d.unit_price = p.new_price;
+            d.deal_tp = ZhCalc.mul(d.deal_qty, d.unit_price, this.decimal.tp);
+            d.sgfh_tp = ZhCalc.mul(d.sgfh_qty, d.unit_price, this.decimal.tp);
+            d.sjcl_tp = ZhCalc.mul(d.sjcl_qty, d.unit_price, this.decimal.tp);
+            d.qtcl_tp = ZhCalc.mul(d.qtcl_qty, d.unit_price, this.decimal.tp);
+            d.total_price = ZhCalc.mul(d.quantity, d.unit_price, this.decimal.tp);
+            return true;
+        }
+        loadDatas(datas) {
+            super.loadDatas(datas);
+            if (this.price.length > 0) {
+                for (const d of this.datas) {
+                    if (d.children && d.children.length > 0) continue;
+                    if (!d.b_code) continue;
+                    this.checkRevisePrice(d);
+                }
+            }
+        }
+        loadPostReivsePrice(data) {
+            let result = false;
+            if (!this.price) return result;
+            for (const d of data) {
+                if (!d.is_leaf || !d.b_code) continue;
+                if (this.checkRevisePrice(d)) result = true;
+            }
+            return result;
+        }
+        loadPostData(data) {
+            const result = {}, reCalcNodes = [];
+            if (!data) return result;
+            if (data.delete) {
+                result.delete = this._freeData(data.delete);
+                this._getReCalcNodes(reCalcNodes, result.delete);
+            }
+            if (data.create) {
+                result.create = this._loadData(data.create);
+                this.loadPostReivsePrice(result.create);
+                this._getReCalcNodes(reCalcNodes, result.create);
+            }
+            if (data.update) {
+                result.update = this._updateData(data.update);
+                this.loadPostReivsePrice(result.update);
+                this._getReCalcNodes(reCalcNodes, result.update);
+            }
+            reCalcNodes.sort((a, b) => {
+                return b.level - a.level;
+            });
+            for (const node of reCalcNodes) {
+                treeCalc.calculateNode(this, node, this.setting.calcFields, this.setting.calcFun);
+            }
+            result.update = result.update ? result.update.concat(reCalcNodes) : reCalcNodes;
+            return result;
+        }
     }
 
     class StageTree extends FxTree {

+ 1 - 0
app/public/js/revise.js

@@ -1942,6 +1942,7 @@ $(document).ready(() => {
 
     // 加载清单&计量单元数据
     postData(window.location.pathname + '/load', {}, function (result) {
+        billsTree.loadRevisePrice(result.price, decimal);
         billsTree.loadDatas(result.bills);
         treeCalc.calculateAll(billsTree);
         for (const t of result.tags) {

+ 3 - 2
app/public/js/revise_compare.js

@@ -247,7 +247,7 @@ $(document).ready(() => {
     };
 
     // 加载清单&计量单元数据
-    postData('load', {filter: 'bills;pos;reviseBills;revisePos'}, function (result) {
+    postData('load', {filter: 'bills;pos;reviseBills;revisePos;price'}, function (result) {
         const tenderTreeSetting = {
             id: 'ledger_id',
             pid: 'ledger_pid',
@@ -258,9 +258,10 @@ $(document).ready(() => {
             calcFields: ['deal_tp', 'sgfh_tp', 'sjcl_tp', 'qtcl_tp', 'total_price'],
         };
         const reviseLedger = {
-            billsTree: createNewPathTree('ledger', tenderTreeSetting),
+            billsTree: createNewPathTree('revise', tenderTreeSetting),
             pos: new PosData({ id: 'id', ledgerId: 'lid', }),
         };
+        reviseLedger.billsTree.loadRevisePrice(result.price, decimal);
         reviseLedger.billsTree.loadDatas(result.reviseBills);
         reviseLedger.pos.loadDatas(result.revisePos);
         const orgLedger = {

+ 437 - 0
app/public/js/revise_price.js

@@ -0,0 +1,437 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+const showSideTools = function (show) {
+    const left = $('#left-view'), right = $('#right-view'), parent = left.parent();
+    if (show) {
+        right.show();
+        autoFlashHeight();
+        const percent = 100 - right.outerWidth() /parent.width() * 100;
+        left.css('width', percent + '%');
+    } else {
+        left.width(parent.width());
+        right.hide();
+    }
+};
+
+const setPriceHint = function (show) {
+    const hinticon = show ? 'fa-bell' : undefined;
+    subMiniMenu.$children[2].hinticon = hinticon;
+    subMenu.$children[2].hinticon = hinticon;
+};
+
+$(document).ready(() => {
+    const ledgerGclSpreadSetting = {
+        cols: [
+            { title: '清单编号', colSpan: '1', rowSpan: '2', field: 'b_code', hAlign: 0, width: 80, formatter: '@' },
+            { title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 200, formatter: '@' },
+            { title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@' },
+            { title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 80, type: 'Number' },
+        ],
+        emptyRows: 0,
+        headRows: 1,
+        headRowHeight: [32],
+        headColWidth: [30],
+        defaultRowHeight: 21,
+        headerFont: '12px 微软雅黑',
+        font: '12px 微软雅黑',
+        readOnly: true,
+    };
+    const priceSpreadSetting = {
+        cols: [
+            { title: '清单编号', colSpan: '1', rowSpan: '2', field: 'b_code', hAlign: 0, width: 100, formatter: '@', readOnly: true },
+            { title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 210, formatter: '@', readOnly: true },
+            { title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@', readOnly: true },
+            { title: '当前单价', colSpan: '1', rowSpan: '2', field: 'org_price', hAlign: 2, width: 80, type: 'Number', readOnly: true },
+            { title: '调整后单价', colSpan: '1', rowSpan: '2', field: 'new_price', hAlign: 2, width: 80, type: 'Number' },
+            { title: '备注', colSpan: '1', rowSpan: '2', field: 'memo', hAlign: 2, width: 150, formatter: '@' },
+        ],
+        emptyRows: 0,
+        headRows: 1,
+        headRowHeight: [32],
+        headColWidth: [30],
+        defaultRowHeight: 21,
+        headerFont: '12px 微软雅黑',
+        font: '12px 微软雅黑',
+        readOnly,
+    };
+    autoFlashHeight();
+    const priceSpread = SpreadJsObj.createNewSpread($('#price-spread')[0]);
+    const priceSheet = priceSpread.getActiveSheet();
+
+    SpreadJsObj.initSheet(priceSheet, priceSpreadSetting);
+
+    class RevisePrice {
+        constructor () {
+            this.data = [];
+        }
+        resortData() {
+            this.data.sort(function (a, b) {
+                return a.order - b.order;
+            });
+        }
+        loadDatas(datas) {
+            this.data = datas;
+            this.resortData();
+        }
+        loadUpdateData(updateData) {
+            if (updateData.add) {
+                for (const a of updateData.add) {
+                    this.data.push(a);
+                }
+            }
+            if (updateData.update) {
+                for (const u of updateData.update) {
+                    const d = this.data.find(function (x) {
+                        return u.id === x.id;
+                    });
+                    if (d) {
+                        _.assign(d, u);
+                    } else {
+                        this.data.push(d);
+                    }
+                }
+            }
+            if (updateData.del) {
+                _.remove(this.data, function (d) {
+                    return updateData.del.indexOf(d.id) >= 0;
+                });
+            }
+            this.resortData();
+        }
+    }
+    const revisePrice = new RevisePrice();
+    const priceOprObj = {
+        addRevisePrice(data) {
+            const op = revisePrice.data.find(x => {
+                return x.b_code === data.b_code && x.name === x.name && x.unit === x.unit && checkZero(ZhCalc.sub(x.org_price, data.unit_price));
+            });
+            if (op) {
+                toastr.warning('已存在该单价调整');
+                SpreadJsObj.locateData(priceSheet, op);
+                return;
+            }
+            postData(window.location.pathname + '/update', { add: { b_code: data.b_code, name: data.name, unit: data.unit, unit_price: data.unit_price } }, result => {
+                revisePrice.loadUpdateData(result);
+                SpreadJsObj.reLoadSheetData(priceSheet);
+                setPriceHint(revisePrice.data.length > 0);
+            });
+        },
+        /**
+         * 删除按钮响应事件
+         * @param sheet
+         */
+        deletePress: function (sheet) {
+            if (!sheet.zh_setting || readOnly) return;
+
+            const sortData = sheet.zh_data;
+            const datas = [];
+            const sels = sheet.getSelections();
+            if (!sels || !sels[0]) return;
+
+            for (let iRow = sels[0].row; iRow < sels[0].row + sels[0].rowCount; iRow++) {
+                let bDel = false;
+                const node = sortData[iRow];
+                if (node) {
+                    const data = {id: node.id};
+                    for (let iCol = sels[0].col; iCol < sels[0].col + sels[0].colCount; iCol++) {
+                        const style = sheet.getStyle(iRow, iCol);
+                        if (!style.locked) {
+                            const colSetting = sheet.zh_setting.cols[iCol];
+                            data[colSetting.field] = null;
+                            bDel = true;
+                        }
+                    }
+                    if (bDel) {
+                        datas.push(data);
+                    }
+                }
+            }
+            if (datas.length > 0) {
+                postData(window.location.pathname + '/update', {update: datas}, function (result) {
+                    revisePrice.loadUpdateData(result);
+                    SpreadJsObj.reLoadSheetData(priceSheet);
+                }, function () {
+                    SpreadJsObj.reLoadSheetData(priceSheet);
+                });
+            }
+        },
+        delete: function (sheet) {
+            if (!sheet.zh_setting || readOnly) return;
+
+            const sortData = sheet.zh_data;
+            const datas = [];
+            const sels = sheet.getSelections();
+            if (!sels || !sels[0]) return;
+
+            for (let iRow = sels[0].row, iLen = sels[0].row + sels[0].rowCount; iRow < iLen; iRow++) {
+                const node = sortData[iRow];
+                datas.push(node.id);
+            }
+            if (datas.length > 0) {
+                postData(window.location.pathname + '/update', {del: datas}, function (result) {
+                    revisePrice.loadUpdateData(result);
+                    SpreadJsObj.reLoadSheetData(priceSheet);
+                    setPriceHint(revisePrice.data.length > 0);
+                }, function () {
+                    SpreadJsObj.reLoadSheetData(priceSheet);
+                });
+            }
+        },
+        editEnded: function (e, info) {
+            if (!info.sheet.zh_setting || !info.sheet.zh_data) return;
+
+            const node = info.sheet.zh_data[info.row];
+            if (!node) return;
+
+            const col = info.sheet.zh_setting.cols[info.col];
+            const data = { update: { id: node.id, org_price: node.org_price } };
+            const oldValue = node ? node[col.field] : null;
+            const newValue = trimInvalidChar(info.editingText);
+            if (oldValue == info.editingText || ((!oldValue || oldValue === '') && (newValue === ''))) {
+                SpreadJsObj.reLoadRowData(info.sheet, info.row);
+                return;
+            }
+            if (col.type === 'Number') {
+                const num = _.toNumber(newValue);
+                if (num) data.update[col.field] = num;
+            } else {
+                data.update[col.field] = newValue;
+            }
+
+            postData(window.location.pathname + '/update', data, function (result) {
+                revisePrice.loadUpdateData(result);
+                SpreadJsObj.reLoadSheetData(info.sheet);
+            }, function () {
+                SpreadJsObj.reLoadRowData(info.sheet, info.row);
+            });
+        },
+        clipboardPasting(e, info) {
+            const setting = info.sheet.zh_setting, sortData = info.sheet.zh_data;
+            info.cancel = true;
+
+            if (!setting || !sortData) return;
+            const pasteData = info.pasteData.html
+                ? SpreadJsObj.analysisPasteHtml(info.pasteData.html)
+                : (info.pasteData.text === ''
+                    ? SpreadJsObj.Clipboard.getAnalysisPasteText()
+                    : SpreadJsObj.analysisPasteText(info.pasteData.text));
+
+            const uDatas = [];
+            for (let iRow = 0; iRow < info.cellRange.rowCount; iRow++) {
+                const curRow = info.cellRange.row + iRow;
+                const node = sortData[curRow];
+
+                let bPaste = false;
+                const data = {};
+                for (let iCol = 0; iCol < info.cellRange.colCount; iCol++) {
+                    const curCol = info.cellRange.col + iCol;
+                    const colSetting = setting.cols[curCol];
+                    const value = trimInvalidChar(pasteData[iRow][iCol]);
+                    if (colSetting.type === 'Number') {
+                        const num = _.toNumber(value);
+                        if (num) {
+                            data[colSetting.field] = num;
+                            bPaste = true;
+                        }
+                    } else {
+                        data[colSetting.field] = value;
+                        bPaste = true;
+                    }
+                }
+                if (bPaste) {
+                    data.id = node.id;
+                    uDatas.push(data);
+                }
+            }
+            const updateData = {};
+            if (uDatas.length > 0) updateData.update = uDatas;
+            if (uDatas.length > 0) {
+                postData(window.location.pathname + '/update', updateData, function (result) {
+                    revisePrice.loadUpdateData(result);
+                    SpreadJsObj.reLoadSheetData(info.sheet);
+                });
+            } else {
+                SpreadJsObj.reLoadSheetData(info.sheet);
+            }
+        },
+        upMove: function () {
+            const sels = priceSheet.getSelections(), sortData = priceSheet.zh_data;
+            const node = sortData[sels[0].row];
+            const preNode = sortData[sels[0].row - 1];
+            const data = [
+                {id: node.id, order: preNode.order},
+                {id: preNode.id, order: node.order}
+            ];
+            postData(window.location.pathname + '/update', {update: data}, function (result) {
+                revisePrice.loadUpdateData(result);
+                SpreadJsObj.reLoadRowsData(priceSheet, [sels[0].row, sels[0].row - 1]);
+                priceSheet.setSelection(sels[0].row - 1, sels[0].col, sels[0].rowCount, sels[0].colCount);
+            });
+        },
+        downMove: function () {
+            const sels = priceSheet.getSelections(), sortData = priceSheet.zh_data;
+            const node = sortData[sels[0].row];
+            const nextNode = sortData[sels[0].row + 1];
+            const data = [
+                {id: node.id, order: nextNode.order},
+                {id: nextNode.id, order: node.order}
+            ];
+            postData(window.location.pathname + '/update', {update: data}, function (result) {
+                revisePrice.loadUpdateData(result);
+                SpreadJsObj.reLoadRowsData(priceSheet, [sels[0].row, sels[0].row + 1]);
+                priceSheet.setSelection(sels[0].row + 1, sels[0].col, sels[0].rowCount, sels[0].colCount);
+            });
+        }
+    };
+    if (!readOnly) {
+        priceSheet.bind(spreadNS.Events.EditEnded, priceOprObj.editEnded);
+        priceSheet.bind(spreadNS.Events.ClipboardPasting, priceOprObj.clipboardPasting);
+        SpreadJsObj.addDeleteBind(priceSpread, priceOprObj.deletePress);
+        $.contextMenu({
+            selector: '#price-spread',
+            build: function ($trigger, e) {
+                const target = SpreadJsObj.safeRightClickSelection($trigger, e, priceSpread);
+                return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
+            },
+            items: {
+                del: {
+                    name: '删除',
+                    icon: 'fa-remove',
+                    callback: function (key, opt) {
+                        priceOprObj.delete(priceSheet);
+                    },
+                    disabled: function (key, opt) {
+                        const node = SpreadJsObj.getSelectObject(priceSheet);
+                        return node === undefined || node === null;
+                    },
+                    visible: function (key, opt) {
+                        return !readOnly;
+                    }
+                },
+                sprDel: '------------',
+                upMove: {
+                    name: '上移',
+                    icon: 'fa-arrow-up',
+                    callback: function (key, opt) {
+                        priceOprObj.upMove();
+                    },
+                    disabled: function (key, opt) {
+                        const sels = priceSheet.getSelections();
+                        if (!sels || !sels[0] || sels[0].row === 0) return true;
+
+                        const row = sels[0].row;
+                        const node = revisePrice.data[row];
+                        return node === undefined || node === null;
+                    },
+                    visible: function (key, opt) {
+                        return !readOnly;
+                    }
+                },
+                downMove: {
+                    name: '下移',
+                    icon: 'fa-arrow-down',
+                    callback: function (key, opt) {
+                        priceOprObj.downMove();
+                    },
+                    disabled: function (key, opt) {
+                        const sels = priceSheet.getSelections();
+                        if (!sels || !sels[0] || sels[0].row >= revisePrice.data.length - 1) return true;
+
+                        const row = sels[0].row;
+                        const node = revisePrice.data[row];
+                        return node === undefined || node === null;
+                    },
+                    visible: function (key, opt) {
+                        return !readOnly;
+                    }
+                }
+            },
+        });
+    }
+
+    class LedgerGcl {
+        constructor(setting) {
+            this.setting = setting;
+            this.spread = SpreadJsObj.createNewSpread($(this.setting.selector)[0]);
+            this.sheet = this.spread.getActiveSheet();
+            SpreadJsObj.initSheet(this.sheet, this.setting.spreadSetting);
+            if (!readOnly) {
+                this.spread.bind(spreadNS.Events.CellDoubleClick, function (e, info) {
+                    const gcl = SpreadJsObj.getSelectObject(info.sheet);
+                    priceOprObj.addRevisePrice(gcl);
+                });
+            }
+        }
+        loadData(bills, pos) {
+            gclGatherModel.loadLedgerData(bills);
+            gclGatherModel.loadPosData(pos);
+            this.gcl = gclGatherModel.gatherGclData();
+            this.sheet && SpreadJsObj.loadSheetData(this.sheet, SpreadJsObj.DataType.Data, this.gcl);
+        }
+    }
+    const ledgerGcl = new LedgerGcl({
+        selector: '#ledger-gcl-spread',
+        spreadSetting: ledgerGclSpreadSetting
+    });
+
+    $.subMenu({
+        menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
+        toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
+        key: 'menu.1.0.0',
+        miniHint: '#sub-mini-hint', hintKey: 'menu.hint.1.0.1',
+        callback: function (info) {
+            if (info.mini) {
+                $('.panel-title').addClass('fluid');
+                $('#sub-menu').removeClass('panel-sidebar');
+            } else {
+                $('.panel-title').removeClass('fluid');
+                $('#sub-menu').addClass('panel-sidebar');
+            }
+            autoFlashHeight();
+            priceSpread.refresh();
+            ledgerGcl.spread.refresh();
+        }
+    });
+
+    $.divResizer({
+        select: '#revise-right-spr',
+        callback: function () {
+            priceSpread.refresh();
+            ledgerGcl.spread.refresh();
+        }
+    });
+
+    postData('load', { filter: 'bills;pos;price' }, result => {
+        revisePrice.loadDatas(result.price);
+        SpreadJsObj.loadSheetData(priceSheet, SpreadJsObj.DataType.Data, revisePrice.data);
+        ledgerGcl.loadData(result.bills, result.pos);
+        $("[content='#ledgerGcl']").click();
+    });
+
+    $('a', '#side-menu').bind('click', function (e) {
+        e.preventDefault();
+        const tab = $(this), tabPanel = $(tab.attr('content'));
+        // 展开工具栏、切换标签
+        if (!tab.hasClass('active')) {
+            $('a', '#side-menu').removeClass('active');
+            tab.addClass('active');
+            $('.tab-content .tab-pane').removeClass('active');
+            tabPanel.addClass('active');
+            showSideTools(tab.hasClass('active'));
+            ledgerGcl.spread.refresh();
+        } else {// 收起工具栏
+            tab.removeClass('active');
+            tabPanel.removeClass('active');
+            showSideTools(tab.hasClass('active'));
+        }
+        priceSpread.refresh();
+    });
+});

+ 6 - 0
app/public/js/setting.js

@@ -149,6 +149,12 @@ $(document).ready(() => {
                 } else {
                     $('#edit-user2 input[name="cooperation"]').attr('disabled', true);
                 }
+                if (pm === 'tender' && permission[pm].indexOf('5') !== -1) {
+                    $('#edit-user2 input:checkbox[id="change_1"]').prop('checked', true);
+                }
+                if (pm === 'tender' && permission[pm].indexOf('4') !== -1) {
+                    $('#edit-user2 input:checkbox[id="material_1"]').prop('checked', true);
+                }
                 if (allPermission[pm].type === 'checkbox') {
                     for (const index of permission[pm]) {
                         $('#edit-user2 input:checkbox[id="' + pm + '_' + index + '"]').prop('checked', true);

+ 4 - 4
app/public/js/shares/cs_gcl_gather.js

@@ -17,10 +17,10 @@
                 cols: [
                     {title: '清单编号', field: 'b_code', width: 80, formatter: '@'},
                     {title: '名称', field: 'name', width: 150, formatter: '@'},
-                    {title: '单位', field: 'unit', width: 50, formatter: '@'},
-                    {title: '单价', field: 'unit_price', width: 60, formatter: '@'},
-                    {title: '数量', field: 'quantity', width: 60, },
-                    {title: '数量', field: 'total_price', width: 60, },
+                    {title: '单位', field: 'unit', width: 50, formatter: '@', hAlign: 1, },
+                    {title: '单价', field: 'unit_price', width: 60, hAlign: 2, },
+                    {title: '数量', field: 'quantity', width: 60, hAlign: 2, },
+                    {title: '数量', field: 'total_price', width: 60, hAlign: 2, },
                 ],
                 emptyRows: 0,
                 headRows: 1,

+ 13 - 1
app/public/js/shares/sjs_setting.js

@@ -92,5 +92,17 @@ const sjsSettingObj = (function () {
             col.showImage = r.showImage;
         }
     };
-    return {setFxTreeStyle, FxTreeStyle, setGridSelectStyle, setTpThousandthFormat, setThousandthFormat, setTpColsThousandthFormat, setPropValue, set3FCols, setQcCols};
+    const setOrgPriceCol = function (cols, rela) {
+        for (const r of rela) {
+            const col = _.find(cols, {field: r.field});
+            if (col) {
+                col.getValue = function (data) { return data.contract_pc_tp || data.qc_pc_tp ? data.org_price : null; };
+            }
+        }
+    };
+    return {
+        setFxTreeStyle, FxTreeStyle, setGridSelectStyle,
+        setTpThousandthFormat, setThousandthFormat, setTpColsThousandthFormat,
+        setPropValue, set3FCols, setQcCols, setOrgPriceCol,
+    };
 })();

+ 7 - 6
app/public/js/stage.js

@@ -155,8 +155,8 @@ function getNodeList(node) {
     }
     $('#nodelist-table').html(html);
     $('#nodelist-table').on('click', 'tr', function() {
-        $('#nodelist-table tr').removeClass('bg-light')
-        $(this).addClass('bg-light')
+        $('#nodelist-table tr').removeClass('bg-light');
+        $(this).addClass('bg-light');
     })
 }
 
@@ -268,7 +268,7 @@ $(document).ready(() => {
     };
     // 台账树结构计算相关设置
     stageTreeSetting.updateFields = ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty', 'postil', 'used', 'contract_expr'];
-    stageTreeSetting.calcFields = ['deal_tp', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp',
+    stageTreeSetting.calcFields = ['deal_tp', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp', 'contract_pc_tp', 'qc_pc_tp', 'pc_tp',
         'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp', 'end_contract_tp', 'end_qc_tp', 'end_gather_tp', 'end_correct_tp', 'final_1_tp', 'end_final_1_tp'];
     stageTreeSetting.calcFun = function (node) {
         if (!node.children || node.children.length === 0) {
@@ -284,9 +284,9 @@ $(document).ready(() => {
             node.end_final_1_qty = ZhCalc.add(node.end_qc_qty, node.final_1_qty);
         }
         node.pre_gather_tp = ZhCalc.add(node.pre_contract_tp, node.pre_qc_tp);
-        node.gather_tp = ZhCalc.add(node.contract_tp, node.qc_tp);
-        node.end_contract_tp = ZhCalc.add(node.pre_contract_tp, node.contract_tp);
-        node.end_qc_tp = ZhCalc.add(node.pre_qc_tp, node.qc_tp);
+        node.gather_tp = ZhCalc.sum([node.contract_tp, node.qc_tp, node.pc_tp]);
+        node.end_contract_tp = ZhCalc.sum([node.pre_contract_tp, node.contract_tp, node.contract_pc_tp]);
+        node.end_qc_tp = ZhCalc.sum([node.pre_qc_tp, node.qc_tp, node.qc_pc_tp]);
         node.end_gather_tp = ZhCalc.add(node.pre_gather_tp, node.gather_tp);
         node.end_final_tp = ZhCalc.add(node.end_qc_tp, node.total_price);
         node.end_final_1_tp = ZhCalc.add(node.end_qc_tp, node.final_1_tp);
@@ -659,6 +659,7 @@ $(document).ready(() => {
         {field: 'qc_qty', showImage: qcColShowImage},
         {field: 'qc_minus_qty', showImage: qcColShowImage},
     ]);
+    sjsSettingObj.setOrgPriceCol(ledgerSpreadSetting.cols, [ {field: 'org_price'} ]);
     // const ratioCol = ledgerSpreadSetting.cols.find(x => {return x.field === 'end_gather_percent' || x.field === 'end_correct_percent'});
     // if (ratioCol) ratioCol.field = tenderInfo.display.stage.correct ? 'end_correct_percent' : 'end_gather_percent';
     const ratioCol = ledgerSpreadSetting.cols.find(x => {return x.field === 'end_final_1_percent' || x.field === 'end_correct_1_percent'});

+ 2 - 1
app/public/js/stage_compare.js

@@ -87,6 +87,7 @@ $(document).ready(function () {
     const ledgerSheet = ledgerSpread.getActiveSheet();
     sjsSettingObj.setFxTreeStyle(ledgerSpreadSetting, sjsSettingObj.FxTreeStyle.jz);
     if (thousandth) sjsSettingObj.setTpThousandthFormat(ledgerSpreadSetting);
+    sjsSettingObj.setOrgPriceCol(ledgerSpreadSetting.cols, [{ field: 'org_price' }]);
     SpreadJsObj.initSheet(ledgerSpread.getActiveSheet(), ledgerSpreadSetting);
     // 初始化部位
     const posSpread = SpreadJsObj.createNewSpread($('#pos-spread')[0]);
@@ -133,7 +134,7 @@ $(document).ready(function () {
         keys: ['id', 'tender_id', 'ledger_id'],
         masterId: 'id',
         minorId: 'lid',
-        calcFields: [],
+        calcFields: ['pc_tp'],
         autoExpand: 3,
     };
     const scTree = createNewPathTree('master', scTreeSetting);

+ 9 - 7
app/public/js/stage_gather.js

@@ -60,6 +60,7 @@ $(document).ready(function () {
         if (!data) return defaultColor;
         return data.overRange && hintOver ? spreadColor.stage.over : data.differ ? spreadColor.gcl.differ : defaultColor;
     };
+    sjsSettingObj.setOrgPriceCol(gclSpreadSetting.cols, [{ field: 'org_price' }]);
     if (thousandth) sjsSettingObj.setTpThousandthFormat(gclSpreadSetting);
     SpreadJsObj.initSheet(gclSpread.getActiveSheet(), gclSpreadSetting);
     // 初始化所属项目节
@@ -135,15 +136,15 @@ $(document).ready(function () {
         gclGatherData = gclGatherModel.gatherGclData();
         gclGatherModel.checkDiffer(gclGatherData);
         checkOverRange(gclGatherData);
-        // 加载清单数据        
+        // 加载清单数据
         SpreadJsObj.loadSheetData(gclSpread.getActiveSheet(), SpreadJsObj.DataType.Data, gclGatherData);
         loadLeafXmjData(0);
         // 章节合计
-        const chapterData = gclGatherModel.gatherChapterData(chapter, result.spec, ['total_price', 'contract_tp', 'qc_tp', 'pre_contract_tp', 'pre_qc_tp']);
+        const chapterData = gclGatherModel.gatherChapterData(chapter, result.spec, ['total_price', 'contract_tp', 'qc_tp', 'pre_contract_tp', 'pre_qc_tp', 'contract_pc_tp', 'qc_pc_tp', 'pc_tp']);
         for (const c of chapterData) {
-            c.gather_tp = ZhCalc.add(c.contract_tp, c.qc_tp);
-            c.end_contract_tp = ZhCalc.add(c.contract_tp, c.pre_contract_tp);
-            c.end_qc_tp = ZhCalc.add(c.qc_tp, c.pre_qc_tp);
+            c.gather_tp = ZhCalc.sum([c.contract_tp, c.qc_tp, c.pc_tp]);
+            c.end_contract_tp = ZhCalc.sum([c.contract_tp, c.pre_contract_tp, c.contract_pc_tp]);
+            c.end_qc_tp = ZhCalc.sum([c.qc_tp, c.pre_qc_tp, c.qc_pc_tp]);
             c.end_gather_tp = ZhCalc.add(c.end_contract_tp, c.end_qc_tp);
             c.end_final_tp = ZhCalc.add(c.end_qc_tp, c.total_price);
             c.end_final_ratio = ZhCalc.mul(ZhCalc.div(c.end_gather_tp, c.end_final_tp), 100, 2);
@@ -283,7 +284,7 @@ $(document).ready(function () {
                 end_qc_qty: gcl.end_qc_qty, end_qc_tp: gcl.end_qc_tp,
                 end_gather_qty: gcl.end_gather_qty, end_gather_tp: gcl.end_gather_tp,
                 end_gather_percent: gcl.end_gather_percent,
-                end_final_qty: gcl.end_final_qty, end_final_tp: gcl.end_final_tp,
+                end_final_qty: gcl.end_final_qty, end_final_tp: gcl.end_final_tp, end_final_1_percent: gcl.end_final_1_percent,
             });
             if (gcl.leafXmjs && gcl.leafXmjs.length > 0) {
                 for (const xmj of gcl.leafXmjs) {
@@ -295,6 +296,7 @@ $(document).ready(function () {
                         end_gather_qty: xmj.end_gather_qty, end_gather_percent: xmj.end_gather_percent,
                         dwgc: xmj.dwgc, fbgc: xmj.fbgc, fxgc: xmj.fxgc,
                         jldy: xmj.jldy, bwmx: xmj.bwmx, drawing_code: xmj.drawing_code,
+                        end_final_1_percent: xmj.end_final_1_percent,
                     });
                 }
             }
@@ -302,4 +304,4 @@ $(document).ready(function () {
 
         SpreadExcelObj.exportSimpleXlsxSheet(setting, data, $('.sidebar-title').attr('data-original-title') + "-清单汇总.xlsx");
     });
-});
+});

+ 10 - 9
app/public/js/stage_im.js

@@ -306,8 +306,8 @@ const stageIm = (function () {
                 (!data.code || data.code === d.code) &&
                 (!data.name || data.name === d.name) &&
                 (!data.unit || data.unit === d.unit) &&
-                (!data.pid || data.pid === d.pid) &&
-                (!data.pos_name || data.pos_name === d.pos_name);
+                ((!data.pid && !d.pid) || data.pid === d.pid) &&
+                ((!data.pos_name && !d.pos_name) || data.pos_name === d.pos_name);
         });
     }
     function findZlRela(rela, data) {
@@ -317,8 +317,8 @@ const stageIm = (function () {
                 (!data.name || data.name === d.name) &&
                 (!data.unit || data.unit === d.unit) &&
                 checkZero(ZhCalc.sub(data.unit_price, d.unit_price)) &&
-                (!data.pid || data.pid === d.pid) &&
-                (!data.pos_name || data.pos_name === d.pos_name);
+                ((!data.pid && !d.pid) || data.pid === d.pid) &&
+                ((!data.pos_name && !d.pos_name) || data.pos_name === d.pos_name);
         });
     }
 
@@ -329,19 +329,20 @@ const stageIm = (function () {
                 (!data.name || data.name === d.name) &&
                 (!data.unit || data.unit === d.unit) &&
                 checkZero(ZhCalc.sub(data.unit_price, d.unit_price)) &&
-                (!data.pid || data.pid === d.pid) &&
-                (!data.pos_name || data.pos_name === d.pos_name);
+                ((!data.pid && !d.pid) || data.pid === d.pid) &&
+                ((!data.pos_name && !d.pos_name) || data.pos_name === d.pos_name);
         });
     }
 
     function findBbRela(rela, data) {
-        return _.find(rela, function (d) {
+        const result = _.find(rela, function (d) {
             return data.lid === d.lid &&
                 (!data.name || data.name === d.name) &&
                 (!data.unit || data.unit === d.unit) &&
-                (!data.pid || data.pid === d.pid) &&
-                (!data.pos_name || data.pos_name === d.pos_name);
+                ((!data.pid && !d.pid) || data.pid === d.pid) &&
+                ((!data.pos_name && !d.pos_name) || data.pos_name === d.pos_name);
         });
+        return result;
     }
 
     function checkTzCustomDetail(im) {

+ 11 - 1
app/public/js/stage_pay.js

@@ -107,7 +107,17 @@ $(document).ready(() => {
 
     const paySpreadSetting = {
         cols: [
-            {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 150, formatter: '@', readOnly: 'readOnly.name'},
+            {
+                title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 150, formatter: '@'
+                , readOnly: 'readOnly.name', cellType: 'tip', getTip: function(data) {
+                    const tips = [];
+                    if (data) {
+                        if (data.pause) tips.push('当前项已停用');
+                        if (!data.is_yf) tips.push('当前项不参与本期应付计算');
+                    }
+                    return tips.join('<br/>');
+                }
+            },
             {title: '扣款', colSpan: '1', rowSpan: '1', field: 'minus', hAlign: 1, width: 50, cellType: 'checkbox', readOnly: 'readOnly.minus'},
             {title: '本期金额(表达式)', colSpan: '1', rowSpan: '1', field: 'tp', hAlign: 2, width: 120, readOnly: 'readOnly.tp', type: 'Number', /*cellType: 'tip', getTip: function (data) {return data ? data.expr : '';}*/},
             {title: '截止上期金额',  colSpan: '1', rowSpan: '1', field: 'pre_tp', hAlign: 2, width: 100, readOnly: true, type: 'Number',},

+ 37 - 1
app/public/js/sub_menu.js

@@ -47,6 +47,9 @@
             }
         });
         miniMenu.mouseenter(function () {
+            toMenu.show();
+            toMenu.siblings('i').hide();
+            // miniMenu.find('.side-switch i').addClass('fa-indent text-primary').removeClass('fa-bars');
             $(setting.miniMenuList).show();
 
             miniHint.popover('hide');
@@ -55,7 +58,40 @@
             }
         });
         miniMenu.mouseleave(function () {
+            toMenu.hide();
+            toMenu.siblings('i').show();
+            // miniMenu.find('.side-switch i').addClass('fa-bars').removeClass('fa-indent text-primary');
             $(setting.miniMenuList).hide();
         });
+        let timeMake = false;
+        $(setting.menu).find('.side-show').mouseenter(function () {
+            $(setting.menu).find('.side-fold').show();
+            timeMake = false;
+        });
+
+        $(setting.menu).find('.side-show').mouseleave(function () {
+            timeMake = true;
+            setTimeout(function () {
+                if (timeMake) {
+                    $(setting.menu).find('.side-fold').hide();
+                }
+            }, 500);
+
+        });
+
+        $(setting.menu).find('.side-fold').mouseenter(function () {
+            timeMake = false;
+            $(this).css('width', '15px');
+        });
+
+        $(setting.menu).find('.side-fold').mouseleave(function () {
+            timeMake = true;
+            setTimeout(function () {
+                if (timeMake) {
+                    $(setting.menu).find('.side-fold').hide();
+                }
+            }, 500);
+            $(this).css('width', '6px');
+        })
     }
-})(jQuery);
+})(jQuery);

+ 6 - 2
app/router.js

@@ -239,18 +239,22 @@ module.exports = app => {
     app.get('/tender/:id/revise/:rid/compare', sessionAuth, tenderCheck, uncheckTenderCheck, reviseCheck, reviseAuditCheck, 'reviseController.compare');
     app.get('/tender/:id/revise/:rid/gcl-compare', sessionAuth, tenderCheck, uncheckTenderCheck, reviseCheck, reviseAuditCheck, 'reviseController.gclCompare');
     app.post('/tender/:id/revise/:rid/load', sessionAuth, tenderCheck, uncheckTenderCheck, reviseCheck, reviseAuditCheck, 'reviseController.loadData');
+    // 单价调整
+    app.get('/tender/:id/revise/:rid/price', sessionAuth, tenderCheck, uncheckTenderCheck, reviseCheck, 'reviseController.price');
+    app.post('/tender/:id/revise/:rid/price/update', sessionAuth, tenderCheck, uncheckTenderCheck, reviseCheck, 'reviseController.priceUpdate');
 
     // 查看修订数据
     app.get('/tender/:id/revise/history/:rid/info', sessionAuth, tenderCheck, uncheckTenderCheck, reviseCheck, 'reviseController.history');
     app.post('/tender/:id/revise/history/:rid/load', sessionAuth, tenderCheck, uncheckTenderCheck, reviseCheck, 'reviseController.loadData');
     app.get('/tender/:id/revise/history/:rid/gcl-compare', sessionAuth, tenderCheck, uncheckTenderCheck, reviseCheck, 'reviseController.gclCompare');
     app.get('/tender/:id/revise/history/:rid/compare', sessionAuth, tenderCheck, uncheckTenderCheck, reviseCheck, 'reviseController.compare');
+    app.get('/tender/:id/revise/history/:rid/price', sessionAuth, tenderCheck, uncheckTenderCheck, reviseCheck, 'reviseController.price');
 
     // 修订审批
     app.post('/tender/:id/revise/audit/add', sessionAuth, tenderCheck, uncheckTenderCheck, 'reviseController.addAuditor');
     app.post('/tender/:id/revise/audit/remove', sessionAuth, tenderCheck, uncheckTenderCheck, 'reviseController.removeAuditor');
-    app.post('/tender/:id/revise/audit/start', sessionAuth, tenderCheck, uncheckTenderCheck, reviseAuditCheck, 'reviseController.start');
-    app.post('/tender/:id/revise/audit/check', sessionAuth, tenderCheck, uncheckTenderCheck, 'reviseController.check');
+    app.post('/tender/:id/revise/audit/start', sessionAuth, tenderCheck, uncheckTenderCheck, reviseCheck, reviseAuditCheck, 'reviseController.start');
+    app.post('/tender/:id/revise/audit/check', sessionAuth, tenderCheck, uncheckTenderCheck, reviseCheck, 'reviseController.check');
 
     // 签约清单
     app.post('/tender/:id/deal/get-data', sessionAuth, tenderCheck, uncheckTenderCheck, 'dealBillsController.getData');

+ 13 - 37
app/service/ledger_history.js

@@ -7,6 +7,7 @@
  * @date
  * @version
  */
+const Ledger = require('../lib/ledger');
 
 module.exports = app => {
 
@@ -107,13 +108,23 @@ module.exports = app => {
             const now = new Date();
             const timestamp = (now).getTime();
 
+            const price = await this.ctx.service.revisePrice.getAllDataByCondition({ where: { rid: revise.id } });
+
             const billsHis = `${this.ctx.session.sessionProject.id}/${revise.tid}/ledger/bills${timestamp}-r.json`;
             const bills = await this.ctx.service.reviseBills.getData(revise.tid);
-            await this.ctx.hisOss.put(this.ctx.hisOssPath + billsHis, Buffer.from(JSON.stringify(bills), 'utf8'));
 
             const posHis = `${this.ctx.session.sessionProject.id}/${revise.tid}/ledger/pos${timestamp}-r.json`;
             const pos = await this.ctx.service.revisePos.getData(revise.tid);
-            await this.ctx.hisOss.put(this.ctx.hisOssPath + posHis, Buffer.from(JSON.stringify(pos), 'utf8'));
+            if (price.length === 0) {
+                await this.ctx.hisOss.put(this.ctx.hisOssPath + billsHis, Buffer.from(JSON.stringify(bills), 'utf8'));
+                await this.ctx.hisOss.put(this.ctx.hisOssPath + posHis, Buffer.from(JSON.stringify(pos), 'utf8'));
+            } else {
+                const reviseTree = new Ledger.reviseTree(this.ctx, { id: 'ledger_id', pid: 'ledger_pid', order: 'order', level: 'level', rootId: -1 });
+                reviseTree.loadRevisePrice(price, this.ctx.tender.info.decimal);
+                reviseTree.loadDatas(bills);
+                await this.ctx.hisOss.put(this.ctx.hisOssPath + billsHis, Buffer.from(JSON.stringify(reviseTree.getUpdateReviseData()), 'utf8'));
+                await this.ctx.hisOss.put(this.ctx.hisOssPath + posHis, Buffer.from(JSON.stringify(pos), 'utf8'));
+            }
 
             const result = await this.db.insert(this.tableName, {
                 pid: this.ctx.session.sessionProject.id, tid: revise.tid,
@@ -125,41 +136,6 @@ module.exports = app => {
 
             return result.insertId;
         }
-
-        /**
-         * 备份 (预留功能)
-         * @param {Object} transaction - 事务
-         * @param {Object} change - 工程变更
-         * @param {Array} newBillsNode - 新增项目节节点
-         * @param {Array} newPosNode - 新增计量单元节点
-         * @return {Promise<void>} - 新增备份id
-         * @private
-         */
-        async backupChangeHistory(transaction, change, newBillsNodes, newPosNodes) {
-            if ((newBillsNodes || newBillsNodes === 0) && (newPosNodes || newPosNodes.length === 0)) return;
-            const now = new Date();
-            const timestamp = (now).getTime();
-
-            const billsHis = `${this.ctx.session.sessionProject.id}/${change.tid}/ledger/bills${timestamp}-c.json`;
-            const bills = await this.ctx.service.ledger.getData(change.tid);
-            if (newBillsNodes.length > 0) bills.push(...newBillsNodes);
-            await this.ctx.hisOss.put(this.ctx.hisOssPath + billsHis, Buffer.from(JSON.stringify(bills), 'utf8'));
-
-            const posHis = `${this.ctx.session.sessionProject.id}/${change.tid}/ledger/pos${timestamp}-c.json`;
-            const pos = await this.ctx.service.pos.getPosData({ tid: change.tid });
-            if (newPosNodes.length > 0) pos.push(...newPosNodes);
-            await this.ctx.hisOss.put(this.ctx.hisOssPath + posHis, Buffer.from(JSON.stringify(pos), 'utf8'));
-
-            const result = await transaction.insert(this.tableName, {
-                pid: this.ctx.session.sessionProject.id, tid: change.tid,
-                cid: change.cid,
-                in_time: now,
-                bills_file: billsHis, pos_file: posHis,
-                bills_count: bills.length, pos_count: pos.length,
-            });
-
-            return result.insertId;
-        }
     }
 
     return LedgerTag;

+ 2 - 0
app/service/ledger_revise.js

@@ -202,6 +202,8 @@ module.exports = app => {
                 if (revise.his_id > 0) await transaction.update(this.ctx.service.ledgerHistory.tableName, { id: revise.his_id, valid: 0 });
                 // 投资进度改变状态
                 await transaction.update(this.ctx.service.schedule.tableName, { revising: 0 }, { where: { tid: this.ctx.tender.id } });
+                // 作废单价调整
+                await transaction.update(this.ctx.service.revisePrice.tableName, { valid: 0 }, { where: { rid: revise.id } });
                 await transaction.commit();
                 return result.affectedRows === 1;
             } catch (err) {

+ 9 - 7
app/service/material_bills.js

@@ -617,12 +617,14 @@ module.exports = app => {
                     const updateStageBillsList = [];
                     for (const ms of materialStageList) {
                         const msb = await transaction.get(this.ctx.service.materialStageBills.tableName, { mid: this.ctx.material.id, mb_id: mb.id, ms_id: ms.id });
+                        msb.m_up_risk = mb.m_up_risk;
+                        msb.m_down_risk = mb.m_down_risk;
                         const updateStageBillData = {
                             id: msb.id,
                         };
                         if (newDecimalQty !== this.ctx.material.decimal.qty) {
                             // 通过管理重新算出quantity并保留小数位
-                            const sql = 'SELECT SUM(`gather_qty`*`quantity`) as quantity FROM ' + this.tableName + ' WHERE `mid`=? AND `mb_id`=? AND `ms_id`=? AND `is_join`=1';
+                            const sql = 'SELECT SUM(`gather_qty`*`quantity`) as quantity FROM ' + this.ctx.service.materialList.tableName + ' WHERE `mid`=? AND `mb_id`=? AND `ms_id`=? AND `is_join`=1';
                             const sqlParam = [this.ctx.material.id, mb.id, ms.id];
                             const mb_quantity = await transaction.queryOne(sql, sqlParam);
                             const newQuantity = this.ctx.helper.round(mb_quantity.quantity, newDecimalQty);
@@ -636,7 +638,7 @@ module.exports = app => {
                             msb.msg_tp = newmsg_tp;
                             const newbasic_price = this.ctx.helper.round(mb.basic_price, newDecimalUp);
                             const [newmsg_spread, newm_spread] = await this.getSpread(msb, msb.msg_tp, newDecimalUp, newbasic_price);
-                            mb.m_spread = newm_spread;
+                            msb.m_spread = newm_spread;
                             updateStageBillData.msg_tp = newmsg_tp;
                             updateStageBillData.msg_spread = newmsg_spread;
                             updateStageBillData.m_spread = newm_spread;
@@ -650,13 +652,13 @@ module.exports = app => {
                         const newbasic_price = this.ctx.helper.round(mb.basic_price, newDecimalUp);
                         updateData.basic_price = newbasic_price;
                     }
-                    const sql = 'SELECT SUM(`m_tp`) as total_price, SUM(IF(`m_tax_tp` is null, `m_tp`, `m_tax_tp`)) as tax_total_price FROM ' + this.tableName + ' WHERE `tid` = ? AND `mid` = ? AND `mb_id` = ? AND `is_summary` = 1';
+                    if (updateStageBillsList.length > 0) await transaction.updateRows(this.ctx.service.materialStageBills.tableName, updateStageBillsList);
+                    const sql = 'SELECT SUM(`m_tp`) as total_price, SUM(IF(`m_tax_tp` is null, `m_tp`, `m_tax_tp`)) as tax_total_price FROM ' + this.ctx.service.materialStageBills.tableName + ' WHERE `tid` = ? AND `mid` = ? AND `mb_id` = ? AND `is_summary` = 1';
                     const sqlParam = [this.ctx.tender.id, this.ctx.material.id, mb.id];
                     const tp = await transaction.queryOne(sql, sqlParam);
                     updateData.m_tp = this.ctx.helper.round(tp.total_price, newDecimalTp);
                     updateData.m_tax_tp = this.ctx.helper.round(tp.tax_total_price, newDecimalTp);
                     updateList.push(updateData);
-                    if (updateStageBillsList.length > 0) await transaction.updateRows(this.ctx.service.materialStageBills.tableName, updateStageBillsList);
                 } else {
                     if (newDecimalUp !== this.ctx.material.decimal.up) {
                         let newmsg_tp = this.ctx.helper.round(mb.msg_tp, newDecimalUp);
@@ -690,7 +692,7 @@ module.exports = app => {
                     }
                     if (newDecimalQty !== this.ctx.material.decimal.qty) {
                         // 通过管理重新算出quantity并保留小数位
-                        const sql = 'SELECT SUM(`gather_qty`*`quantity`) as quantity FROM ' + this.tableName + ' WHERE `mid`=? AND `mb_id`=? AND `is_join`=1';
+                        const sql = 'SELECT SUM(`gather_qty`*`quantity`) as quantity FROM ' + this.ctx.service.materialList.tableName + ' WHERE `mid`=? AND `mb_id`=? AND `is_join`=1';
                         const sqlParam = [this.ctx.material.id, mb.id];
                         const mb_quantity = await transaction.queryOne(sql, sqlParam);
                         const newQuantity = this.ctx.helper.round(mb_quantity.quantity, newDecimalQty);
@@ -703,13 +705,13 @@ module.exports = app => {
                     updateList.push(updateData);
                 }
             }
+            if (updateMonthList.length > 0) await transaction.updateRows(this.ctx.service.materialMonth.tableName, updateMonthList);
+            if (updateList.length > 0) await transaction.updateRows(this.tableName, updateList);
             if (this.ctx.material.is_stage_self) {
                 for (const ms of materialStageList) {
                     await this.ctx.service.materialStage.updateMtp(transaction, ms.id);
                 }
             }
-            if (updateMonthList.length > 0) await transaction.updateRows(this.ctx.service.materialMonth.tableName, updateMonthList);
-            if (updateList.length > 0) await transaction.updateRows(this.tableName, updateList);
         }
     }
 

+ 15 - 0
app/service/material_list_notjoin.js

@@ -146,6 +146,21 @@ module.exports = app => {
             // 复制上一期不参与调差的清单
             return notJoinlist.length > 0 ? await transaction.insert(this.tableName, notJoinlist) : true;
         }
+
+        async getJoinMsg(transaction, mid, datas) {
+            const searchData = {
+                tid: this.ctx.tender.id,
+                mid,
+                gcl_id: datas.gcl_id,
+                xmj_id: datas.xmj_id,
+                mx_id: datas.mx_id,
+            };
+            const info = await transaction.get(this.tableName, searchData);
+            if (info) {
+                return 0;
+            }
+            return 1;
+        }
     }
     return MaterialListNotJoin;
 };

+ 43 - 39
app/service/material_list_self.js

@@ -41,7 +41,7 @@ module.exports = app => {
                     in_time: new Date(),
                 };
                 // 更新list表为is_self为1
-                await transaction.update(this.ctx.service.materialList.tableName, { is_self: 1 }, {
+                await transaction.update(this.ctx.service.materialList.tableName, { is_self: 1, order: this.ctx.material.order, in_time: new Date() }, {
                     where: {
                         tid: this.ctx.tender.id,
                         mid: this.ctx.material.id,
@@ -59,7 +59,7 @@ module.exports = app => {
                     throw '新增不参与调差清单数据失败';
                 }
                 await transaction.commit();
-                return await this.getDataById(result.insertId);
+                return { info: await this.getDataById(result.insertId), materialListData: await this.ctx.service.materialList.getMaterialData(this.ctx.tender.id, this.ctx.material.id) };
             } catch (err) {
                 await transaction.rollback();
                 throw err;
@@ -71,13 +71,14 @@ module.exports = app => {
          * @param {int} id 工料id
          * @return {void}
          */
-        async del(id, ms_id = null,) {
+        async del(id, ms_id = null, gather_qty = null) {
             if (!this.ctx.tender || !this.ctx.material) {
                 throw '数据错误';
             }
             const transaction = await this.db.beginTransaction();
             try {
                 const selfInfo = await this.getDataById(id);
+                selfInfo.gather_qty = gather_qty;
                 await this.updateAllMaterials(transaction, selfInfo, ms_id);
                 // 判断是否可删
                 const result = await transaction.delete(this.tableName, { id });
@@ -108,8 +109,8 @@ module.exports = app => {
             const materialListData = await this.ctx.service.materialList.getAllDataByCondition({
                 where: searchSql,
             });
+            const mbIdList = [];
             if (materialListData && materialListData.length > 0) {
-                const mbIdList = [];
                 for (const ml of materialListData) {
                     if (mbIdList.indexOf(ml.mb_id) === -1) {
                         mbIdList.push(ml.mb_id);
@@ -122,16 +123,19 @@ module.exports = app => {
                     xmj_id: data.xmj_id,
                     mx_id: data.mx_id ? data.mx_id : '',
                 });
-                const materialListGclData = await this.ctx.service.materialListGcl.getAllDataByCondition({
-                    where: { tid: this.ctx.tender.id, gcl_id: data.gcl_id },
-                });
-                const insertList = [];
-                if (this.ctx.material.is_stage_self) {
-                    const materialStageList = await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: this.ctx.material.id } });
-                    for (const ms of materialStageList) {
-                        const oneML = this._.filter(materialListData, { ms_id: ms.id });
-                        const gather_qty = oneML[0].gather_qty;
-                        const is_join = oneML[0].is_join;
+            }
+            const materialListGclData = await this.ctx.service.materialListGcl.getAllDataByCondition({
+                where: { tid: this.ctx.tender.id, gcl_id: data.gcl_id },
+            });
+            const insertList = [];
+            const is_join = await this.ctx.service.materialListNotjoin.getJoinMsg(transaction, this.ctx.material.id, data);
+            if (this.ctx.material.is_stage_self) {
+                const materialStageList = await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: this.ctx.material.id } });
+                for (const ms of materialStageList) {
+                    // const oneML = this._.filter(materialListData, { ms_id: ms.id });
+                    // const gather_qty = oneML[0].gather_qty;
+                    // const is_join = oneML[0].is_join;
+                    if (data.gather_qty['ms_id_' + ms.id] !== null) {
                         for (const m of materialListGclData) {
                             insertList.push({
                                 tid: this.ctx.tender.id,
@@ -142,7 +146,7 @@ module.exports = app => {
                                 xmj_id: data.xmj_id,
                                 mx_id: data.mx_id,
                                 ms_id: ms.id,
-                                gather_qty,
+                                gather_qty: data.gather_qty['ms_id_' + ms.id],
                                 quantity: m.quantity,
                                 expr: m.expr,
                                 is_join,
@@ -151,33 +155,33 @@ module.exports = app => {
                             });
                         }
                     }
-                } else {
-                    const gather_qty = materialListData[0].gather_qty;
-                    const is_join = materialListData[0].is_join;
-                    for (const m of materialListGclData) {
-                        insertList.push({
-                            tid: this.ctx.tender.id,
-                            order: m.order,
-                            mid: this.ctx.material.id,
-                            mb_id: m.mb_id,
-                            gcl_id: data.gcl_id,
-                            xmj_id: data.xmj_id,
-                            mx_id: data.mx_id,
-                            gather_qty,
-                            quantity: m.quantity,
-                            expr: m.expr,
-                            is_join,
-                            is_self: 0,
-                            in_time: new Date(),
-                        });
-                    }
                 }
-                if (insertList.length > 0) await transaction.insert(this.ctx.service.materialList.tableName, insertList);
-                // 重新计算金额
-                for (const mb_id of mbIdList) {
-                    await this.service.materialList.calcQuantityByML(transaction, mb_id, ms_id, 'all');
+            } else {
+                // const gather_qty = materialListData[0].gather_qty;
+                // const is_join = materialListData[0].is_join;
+                for (const m of materialListGclData) {
+                    insertList.push({
+                        tid: this.ctx.tender.id,
+                        order: m.order,
+                        mid: this.ctx.material.id,
+                        mb_id: m.mb_id,
+                        gcl_id: data.gcl_id,
+                        xmj_id: data.xmj_id,
+                        mx_id: data.mx_id,
+                        gather_qty: data.gather_qty,
+                        quantity: m.quantity,
+                        expr: m.expr,
+                        is_join,
+                        is_self: 0,
+                        in_time: new Date(),
+                    });
                 }
             }
+            if (insertList.length > 0) await transaction.insert(this.ctx.service.materialList.tableName, insertList);
+            // 重新计算金额
+            for (const mb_id of mbIdList) {
+                await this.service.materialList.calcQuantityByML(transaction, mb_id, ms_id, 'all');
+            }
         }
 
         /**

+ 30 - 32
app/service/report_memory.js

@@ -107,7 +107,7 @@ module.exports = app => {
                 rootId: -1,
                 keys: ['id', 'tender_id', 'ledger_id'],
                 stageId: 'id',
-                calcFields: calcFields || ['deal_tp', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp', 'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp', 'final_1_tp'],
+                calcFields: calcFields || ['deal_tp', 'total_price', 'contract_tp', 'qc_tp', 'contract_pc_tp', 'qc_pc_tp', 'pc_tp', 'gather_tp', 'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp', 'final_1_tp'],
                 calc: function (node, helper, decimal) {
                     if (node.children && node.children.length === 0) {
                         node.pre_gather_qty = helper.add(node.pre_contract_qty, node.pre_qc_qty);
@@ -120,9 +120,9 @@ module.exports = app => {
                         node.end_final_1_qty = helper.add(node.final_1_qty, node.end_qc_qty);
                     }
                     node.pre_gather_tp = helper.add(node.pre_contract_tp, node.pre_qc_tp);
-                    node.gather_tp = helper.add(node.contract_tp, node.qc_tp);
-                    node.end_contract_tp = helper.add(node.pre_contract_tp, node.contract_tp);
-                    node.end_qc_tp = helper.add(node.pre_qc_tp, node.qc_tp);
+                    node.gather_tp = helper.sum([node.contract_tp, node.qc_tp, node.pc_tp]);
+                    node.end_contract_tp = helper.sum([node.pre_contract_tp, node.contract_tp, node.contract_pc_tp]);
+                    node.end_qc_tp = helper.sum([node.pre_qc_tp, node.qc_tp, node.qc_pc_tp]);
                     node.end_gather_tp = helper.add(node.pre_gather_tp, node.gather_tp);
 
                     node.final_tp = helper.add(node.total_price, node.end_qc_tp);
@@ -405,9 +405,13 @@ module.exports = app => {
                 if (this._checkFieldsExist(fields, billsFields.stageEnd)) {
                     preStage = this.ctx.stage.order > 1 ? await this.ctx.service.stageBillsFinal.getFinalData(this.ctx.tender, this.ctx.stage.order - 1) : [];
                 }
+                const bpcStage = await this.ctx.service.stageBillsPc.getAllDataByCondition({ where: { sid: this.ctx.stage.id } });
+                const endBpcStage = await this.ctx.service.stageBillsPc.getEndStageData(this.ctx.stage);
                 this.ctx.helper.assignRelaData(billsData, [
-                    {data: curStage, fields: ['contract_qty', 'contract_tp', 'contract_expr', 'qc_qty', 'qc_tp', 'qc_minus_qty', 'postil'], prefix: '', relaId: 'lid'},
-                    {data: preStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty'], prefix: 'pre_', relaId: 'lid'}
+                    { data: curStage, fields: ['contract_qty', 'contract_tp', 'contract_expr', 'qc_qty', 'qc_tp', 'qc_minus_qty', 'postil'], prefix: '', relaId: 'lid' },
+                    { data: preStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty'], prefix: 'pre_', relaId: 'lid' },
+                    { data: bpcStage, fields: ['contract_pc_tp', 'qc_pc_tp', 'pc_tp'], prefix: '', relaId: 'lid' },
+                    { data: endBpcStage, fields: ['end_contract_pc_tp', 'end_qc_pc_tp', 'end_pc_tp'], prefix: '', relaId: 'lid' },
                 ]);
 
                 const billsTree = this._getNewBillsTree();
@@ -549,12 +553,17 @@ module.exports = app => {
                     ]);
                 }
 
-                if (this._checkFieldsExist(fields, billsFields.stageEnd)) {
-                    const preStage = this.ctx.stage.order > 1 ? await this.ctx.service.stageBillsFinal.getFinalData(this.ctx.tender, this.ctx.stage.order - 1) : [];
-                    this.ctx.helper.assignRelaData(billsData, [
-                        {data: preStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty'], prefix: 'pre_', relaId: 'lid'}
-                    ]);
-                }
+                const bpcStage = await this.ctx.service.stageBillsPc.getAllDataByCondition({ where: { sid: this.ctx.stage.id } });
+                const endBpcStage = await this.ctx.service.stageBillsPc.getEndStageData(this.ctx.stage);
+                const preStage = this._checkFieldsExist(fields, billsFields.stageEnd) && this.ctx.stage.order > 1
+                    ? await this.ctx.service.stageBillsFinal.getFinalData(this.ctx.tender, this.ctx.stage.order - 1)
+                    : [];
+
+                this.ctx.helper.assignRelaData(billsData, [
+                    {data: preStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'qc_minus_qty'], prefix: 'pre_', relaId: 'lid'},
+                    { data: bpcStage, fields: ['contract_pc_tp', 'qc_pc_tp', 'pc_tp'], prefix: '', relaId: 'lid' },
+                    { data: endBpcStage, fields: ['end_contract_pc_tp', 'end_qc_pc_tp', 'end_pc_tp'], prefix: '', relaId: 'lid' },
+                ]);
                 const billsTree = this._getNewBillsTree();
                 billsTree.loadDatas(billsData);
 
@@ -575,7 +584,7 @@ module.exports = app => {
                     node.pre_gather_tp = helper.add(node.pre_contract_tp, node.pre_qc_tp);
                     for (const role of validRole) {
                         prefix = 'r' + role.flowOrder + '_';
-                        node[prefix + 'gather_tp'] = helper.add(node[prefix + 'contract_tp'], node[prefix + 'qc_tp']);
+                        node[prefix + 'gather_tp'] = helper.sum([node[prefix + 'contract_tp'], node[prefix + 'qc_tp'], node.pc_tp]);
                     }
                 });
 
@@ -584,25 +593,6 @@ module.exports = app => {
                 }
 
                 return billsTree.getDefaultDatas();
-                // return billsTree.getDatas([
-                //     'id', 'tender_id', 'ledger_id', 'ledger_pid', 'level', 'order', 'full_path', 'is_leaf',                 //8
-                //     'code', 'b_code', 'name', 'unit', 'unit_price',                                                         //5
-                //     'deal_qty', 'deal_tp', 'quantity', 'total_price', 'dgn_qty1', 'dgn_qty2',                               //6
-                //     'drawing_code', 'memo', 'node_type', 'is_tp',                                                           //4
-                //     'r0_contract_qty', 'r0_contract_tp', 'r0_qc_qty', 'r0_qc_tp', 'r0_gather_qty', 'r0_gather_tp',          //6
-                //     'r1_contract_qty', 'r1_contract_tp', 'r1_qc_qty', 'r1_qc_tp', 'r1_gather_qty', 'r1_gather_tp',
-                //     'r2_contract_qty', 'r2_contract_tp', 'r2_qc_qty', 'r2_qc_tp', 'r2_gather_qty', 'r2_gather_tp',
-                //     'r3_contract_qty', 'r3_contract_tp', 'r3_qc_qty', 'r3_qc_tp', 'r3_gather_qty', 'r3_gather_tp',
-                //     'r4_contract_qty', 'r4_contract_tp', 'r4_qc_qty', 'r4_qc_tp', 'r4_gather_qty', 'r4_gather_tp',
-                //     'r5_contract_qty', 'r5_contract_tp', 'r5_qc_qty', 'r5_qc_tp', 'r5_gather_qty', 'r5_gather_tp',
-                //     'r6_contract_qty', 'r6_contract_tp', 'r6_qc_qty', 'r6_qc_tp', 'r6_gather_qty', 'r6_gather_tp',
-                //     'r7_contract_qty', 'r7_contract_tp', 'r7_qc_qty', 'r7_qc_tp', 'r7_gather_qty', 'r7_gather_tp',
-                //     'r8_contract_qty', 'r8_contract_tp', 'r8_qc_qty', 'r8_qc_tp', 'r8_gather_qty', 'r8_gather_tp',
-                //     'r9_contract_qty', 'r9_contract_tp', 'r9_qc_qty', 'r9_qc_tp', 'r9_gather_qty', 'r9_gather_tp',
-                //     'r10_contract_qty', 'r10_contract_tp', 'r10_qc_qty', 'r10_qc_tp', 'r10_gather_qty', 'r10_gather_tp',
-                //     'pre_contract_qty', 'pre_contract_tp', 'pre_qc_qty', 'pre_qc_tp', 'pre_gather_qty', 'pre_gather_tp',
-                //     'chapter',                                                                                              //1
-                // ]);
             } catch (err) {
                 return [];
             }
@@ -1361,6 +1351,14 @@ module.exports = app => {
             this.pmDeal = await pm.dealData(this.ctx, this.ctx.session.sessionProject.code, selects);
 
             result = this.pmDeal.contracts ? this.pmDeal.contracts.filter(x => { return x.ContractsType === 2 }) : [];
+            const fields = ['Code', 'Name', 'ContractName', 'ContractCode', 'ContractPrice', 'ContractReturned', 'ContractsPaid', 'ContractStatus', 'ContractLocking', 'CreateTime'], self = this;
+            result.forEach(x => {
+                const treeNode = self.pmDeal.tree_contracts.find(y => { return x.TreeId === y.Id });
+                if (!treeNode) return;
+                for (const f of fields) {
+                    x['Tree_' + f] = treeNode[f];
+                }
+            });
             // 排序:标段-合同类别-创建时间
             result.sort((x, y) => {
                 const bidSort = selects.indexOf(x.BidsectionId + '') - selects.indexOf(y.BidsectionId + '');

+ 4 - 2
app/service/revise_audit.js

@@ -14,6 +14,7 @@ const SmsAliConst = require('../const/sms_alitemplate');
 const wxConst = require('../const/wechat_template');
 const shenpiConst = require('../const/shenpi');
 const pushType = require('../const/audit').pushType;
+const RevisePrice = require('../lib/revise_price');
 
 module.exports = app => {
     class ReviseAudit extends app.BaseService {
@@ -449,8 +450,9 @@ module.exports = app => {
                                 cache_time_r: cacheTime,
                             });
                         }
-                        // 拷贝修订数据至台账
-                        await this._replaceLedgerByRevise(transaction, revise);
+                        // 重算台账、计量、工程变更
+                        const reviseCalc = new RevisePrice(this.ctx);
+                        await reviseCalc.calcRevise(revise, transaction);
                         const sum = await this.ctx.service.reviseBills.addUp({
                             tender_id: revise.tid, /* , is_leaf: true*/
                         });

+ 114 - 0
app/service/revise_price.js

@@ -0,0 +1,114 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+module.exports = app => {
+
+    class RevisePrice extends app.BaseService {
+
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'revise_price';
+        }
+
+        async _addDatas(data) {
+            const datas = data instanceof Array ? data : [data];
+            const insertData = [];
+            const count = await this.db.count(this.tableName, { rid: this.ctx.revise.id });
+            for (const [i, d] of datas.entries()) {
+                if (!d.b_code) throw '新增单价调整,提交的数据错误';
+                const nd = {
+                    pid: this.ctx.session.sessionProject.id,
+                    tid: this.ctx.tender.id,
+                    rid: this.ctx.revise.id,
+                    order: count + i + 1,
+                    b_code: d.b_code,
+                    name: d.name,
+                    unit: d.unit,
+                    org_price: d.unit_price,
+                    new_price: d.unit_price,
+                    valid: 1,
+                    memo: d.memo || '',
+                };
+                insertData.push(nd);
+            }
+            const result = await this.db.insert(this.tableName, insertData);
+            for (const [i, d] of insertData.entries()) {
+                d.id = result.insertId + i;
+            }
+            return insertData;
+        }
+
+        async _delDatas(data) {
+            const datas = data instanceof Array ? data : [data];
+            await this.db.delete(this.tableName, { id: datas });
+            return datas;
+        }
+
+        async _updateDatas(data) {
+            const datas = data instanceof Array ? data : [data];
+
+            const uDatas = [];
+            for (const d of datas) {
+                const nd = { id: d.id };
+                if (d.order !== undefined) nd.order = d.order;
+                if (d.new_price !== undefined) {
+                    nd.new_price = this.ctx.helper.round(d.new_price, this.ctx.tender.info.decimal.up);
+                    nd.valid = !this.ctx.helper.checkZero(this.ctx.helper.sub(nd.new_price, d.org_price));
+                }
+                if (d.memo !== undefined) nd.memo = d.memo;
+                uDatas.push(nd);
+            }
+            if (uDatas.length > 0) {
+                await this.db.updateRows(this.tableName, uDatas);
+                return uDatas;
+            } else {
+                return [];
+            }
+        }
+
+        async updateDatas(data) {
+            const result = { add: [], del: [], update: [] };
+            try {
+                if (data.add) {
+                    result.add = await this._addDatas(data.add);
+                }
+                if (data.update) {
+                    result.update = await this._updateDatas(data.update);
+                }
+                if (data.del) {
+                    result.del = await this._delDatas(data.del);
+                }
+                return result;
+            } catch (err) {
+                throw err;
+            }
+        }
+
+        async doPriceUsed(stage, transaction) {
+            const sql = `Update ${this.tableName} Set use_stage = ${stage.id}, use_stage_order = ${stage.order}` +
+                ' Where tid = ? and use_stage = 0';
+            await transaction.query(sql, [stage.tid]);
+        }
+
+        async cancelPriceUsed(stage, transaction) {
+            const sql = `Update ${this.tableName} Set use_stage = 0, use_stage_order = 0` +
+                ' Where tid = ? and use_stage = ?';
+            await transaction.query(sql, [stage.tid, stage.id]);
+        }
+    }
+
+    return RevisePrice;
+};

+ 24 - 55
app/service/rpt_gather_memory.js

@@ -46,6 +46,7 @@ const gatherUtils = {
         gatherNode[prefix + "qc_tp"] = helper.add(gatherNode[prefix + "qc_tp"], sourceNode.qc_tp);
         gatherNode[prefix + "gather_qty"] = helper.add(gatherNode[prefix + "gather_qty"], sourceNode.gather_qty);
         gatherNode[prefix + "gather_tp"] = helper.add(gatherNode[prefix + "gather_tp"], sourceNode.gather_tp);
+        gatherNode[prefix + 'pc_tp'] = helper.add(gatherNode[prefix + 'pc_tp'], sourceNode.pc_tp);
 
         gatherNode[prefix + "pre_contract_qty"] = helper.add(gatherNode[prefix + "pre_contract_qty"], sourceNode.pre_contract_qty);
         gatherNode[prefix + "pre_contract_tp"] = helper.add(gatherNode[prefix + "pre_contract_tp"], sourceNode.pre_contract_tp);
@@ -115,6 +116,7 @@ const gatherUtils = {
         gatherNode[prefix + "qc_tp"] = helper.add(gatherNode[prefix + "qc_tp"], sourceNode.qc_tp);
         gatherNode[prefix + "gather_qty"] = helper.add(gatherNode[prefix + "gather_qty"], sourceNode.gather_qty);
         gatherNode[prefix + "gather_tp"] = helper.add(gatherNode[prefix + "gather_tp"], sourceNode.gather_tp);
+        gatherNode[prefix + 'pc_tp'] = helper.add(gatherNode[prefix + 'pc_tp'], sourceNode.pc_tp);
 
         gatherNode[prefix + "deal_dgn_qty1"] = helper.add(gatherNode[prefix + "deal_dgn_qty1"], sourceNode.deal_dgn_qty1);
         gatherNode[prefix + "deal_dgn_qty2"] = helper.add(gatherNode[prefix + "deal_dgn_qty2"], sourceNode.deal_dgn_qty2);
@@ -258,7 +260,7 @@ module.exports = app => {
                 rootId: -1,
                 keys: ['id', 'tender_id', 'ledger_id'],
                 stageId: 'id',
-                calcFields: ['deal_tp', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp', 'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp'],
+                calcFields: ['deal_tp', 'total_price', 'contract_tp', 'qc_tp', 'contract_pc_tp', 'qc_pc_tp', 'pc_tp', 'gather_tp', 'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp'],
                 calc: function (node) {
                     if (node.children && node.children.length === 0) {
                         node.pre_gather_qty = helper.add(node.pre_contract_qty, node.pre_qc_qty);
@@ -268,9 +270,9 @@ module.exports = app => {
                         node.end_gather_qty = helper.add(node.pre_gather_qty, node.gather_qty);
                     }
                     node.pre_gather_tp = helper.add(node.pre_contract_tp, node.pre_qc_tp);
-                    node.gather_tp = helper.add(node.contract_tp, node.qc_tp);
-                    node.end_contract_tp = helper.add(node.pre_contract_tp, node.contract_tp);
-                    node.end_qc_tp = helper.add(node.pre_qc_tp, node.qc_tp);
+                    node.gather_tp = helper.sum([node.contract_tp, node.qc_tp, node.pc_tp]);
+                    node.end_contract_tp = helper.sum([node.pre_contract_tp, node.contract_tp, node.contract_pc_tp]);
+                    node.end_qc_tp = helper.sum([node.pre_qc_tp, node.qc_tp, node.qc_pc_tp]);
                     node.end_gather_tp = helper.add(node.pre_gather_tp, node.gather_tp);
                 }
             });
@@ -284,39 +286,16 @@ module.exports = app => {
 
             if (stage) {
                 await this.ctx.service.stage.doCheckStage(stage);
-                if (stage.readOnly) {
-                    const curStage = await this.ctx.service.stageBills.getAuditorStageData2(tender.id,
-                        stage.id, stage.curTimes, stage.curOrder);
-                    this.ctx.helper.assignRelaData(billsData, [
-                        {
-                            data: curStage,
-                            fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'],
-                            prefix: '',
-                            relaId: 'lid'
-                        }
-                    ]);
-                } else {
-                    const curStage = await this.ctx.service.stageBills.getLastestStageData2(tender.id, stage.id);
-                    this.ctx.helper.assignRelaData(billsData, [
-                        {
-                            data: curStage,
-                            fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'],
-                            prefix: '',
-                            relaId: 'lid'
-                        }
-                    ]);
-                }
-                if (hasPre) {
-                    const preStage = stage.order > 1 ? await this.ctx.service.stageBillsFinal.getFinalData(tender, stage.order - 1) : [];
-                    this.ctx.helper.assignRelaData(billsData, [
-                        {
-                            data: preStage,
-                            fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'],
-                            prefix: 'pre_',
-                            relaId: 'lid'
-                        }
-                    ]);
-                }
+                const curStage = stage.readOnly
+                    ? await this.ctx.service.stageBills.getAuditorStageData2(tender.id, stage.id, stage.curTimes, stage.curOrder)
+                    : await this.ctx.service.stageBills.getLastestStageData2(tender.id, stage.id);
+                const preStage = hasPre && stage.order > 1 ? await this.ctx.service.stageBillsFinal.getFinalData(tender, stage.order - 1) : [];
+                const bpcStage = await this.ctx.service.stageBillsPc.getAllDataByCondition({ where: { sid: stage.id } });
+                this.ctx.helper.assignRelaData(billsData, [
+                    { data: curStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'], prefix: '', relaId: 'lid' },
+                    { data: preStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'], prefix: 'pre_', relaId: 'lid' },
+                    { data: bpcStage, fields: ['contract_pc_tp', 'qc_pc_tp', 'pc_tp'], prefix: '', relaId: 'lid' },
+                ]);
             }
             billsTree.loadDatas(billsData);
             billsTree.calculateAll();
@@ -383,24 +362,14 @@ module.exports = app => {
 
             for (const stage of stages) {
                 await this.ctx.service.stage.doCheckStage(stage);
-                if (stage.readOnly) {
-                    const curStage = await this.ctx.service.stageBills.getAuditorStageData2(tender.id,
-                        stage.id, stage.curTimes, stage.curOrder);
-                    sumAssignRelaData(billsIndexData, [{
-                        data: curStage,
-                        fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'],
-                        prefix: '',
-                        relaId: 'lid'
-                    }]);
-                } else {
-                    const curStage = await this.ctx.service.stageBills.getLastestStageData2(tender.id, stage.id);
-                    sumAssignRelaData(billsIndexData, [{
-                        data: curStage,
-                        fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'],
-                        prefix: '',
-                        relaId: 'lid'
-                    }]);
-                }
+                const curStage = stage.readOnly
+                    ? await this.ctx.service.stageBills.getAuditorStageData2(tender.id, stage.id, stage.curTimes, stage.curOrder)
+                    : await this.ctx.service.stageBills.getLastestStageData2(tender.id, stage.id);
+                const bpcStage = await this.ctx.service.stageBillsPc.getAllDataByCondition({ where: { sid: this.ctx.stage.id } });
+                sumAssignRelaData(billsIndexData, [
+                    {data: curStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'], prefix: '', relaId: 'lid'},
+                    { data: bpcStage, fields: ['contract_pc_tp', 'qc_pc_tp', 'pc_tp'], prefix: '', relaId: 'lid' },
+                ]);
             }
 
             billsTree.loadDatas(billsData);

+ 4 - 0
app/service/stage.js

@@ -16,6 +16,7 @@ const path = require('path');
 const _ = require('lodash');
 const projectLogConst = require('../const/project_log');
 const syncApiConst = require('../const/sync_api');
+const RevisePrice = require('../lib/revise_price');
 
 module.exports = app => {
     class Stage extends app.BaseService {
@@ -379,6 +380,9 @@ module.exports = app => {
                     if (!safeResult) throw '初始化其他台账数据失败';
                     const tempResult = await this.ctx.service.stageTempLand.addInitialStageData(newStage, preStage, transaction);
                     if (!tempResult) throw '初始化其他台账数据失败';
+
+                    const priceCalc = new RevisePrice(this.ctx);
+                    await priceCalc.newStagePriceChange(newStage, preStage, transaction);
                 }
                 // 新增期拷贝报表相关配置/签名角色 等
                 if (preStage) {

+ 6 - 0
app/service/stage_audit.js

@@ -18,6 +18,7 @@ const payConst = require('../const/deal_pay');
 const pushType = require('../const/audit').pushType;
 const syncApiConst = require('../const/sync_api');
 const measureType = require('../const/tender').measureType;
+const RevisePrice = require('../lib/revise_price');
 
 module.exports = app => {
     class StageAudit extends app.BaseService {
@@ -951,6 +952,11 @@ module.exports = app => {
                     cache_time_r: this.ctx.stage.cache_time_l,
                     tp_history: JSON.stringify(this.ctx.stage.tp_history),
                 });
+                // 已经引用到本期的单价变更,全部取消
+                await this.ctx.service.revisePrice.cancelPriceUsed(this.ctx.stage, transaction);
+                // 重算所有单价变更
+                const priceCalc = new RevisePrice(this.ctx);
+                await priceCalc.stageCheckAgainPriceChange(this.ctx.stage, audit.order + 2, transaction);
 
                 // 添加短信通知-需要审批提醒功能
                 // const smsUser = await this.ctx.service.projectAccount.getDataById(audit.aid);

+ 20 - 0
app/service/stage_bills_final.js

@@ -76,6 +76,7 @@ module.exports = app => {
                 throw '数据错误';
             }
             const cur = await this.ctx.service.stageBills.getLastestStageData2(tender.id, stage.id);
+            const curPc = await this.ctx.service.stageBillsPc.getAllDataByCondition({ where: { sid: stage.id } });
             const pre = await this.getFinalData(tender, stage.order - 1);
             if ((!cur || cur.length === 0) && (!pre || pre.length === 0)) return;
             for (const c of cur) {
@@ -89,6 +90,7 @@ module.exports = app => {
                     return x.lid === c.lid;
                 });
                 if (p) {
+                    c.unit_price = p.org_price;
                     c.contract_qty = this.ctx.helper.add(c.contract_qty, p.contract_qty);
                     c.contract_tp = this.ctx.helper.add(c.contract_tp, p.contract_tp);
                     c.qc_qty = this.ctx.helper.add(c.qc_qty, p.qc_qty);
@@ -101,12 +103,30 @@ module.exports = app => {
                     c.used = !this.ctx.helper.checkZero(c.contract_qty) || !this.ctx.helper.checkZero(c.qc_qty)
                         || !this.ctx.helper.checkZero(c.contract_tp) || ! this.ctx.helper.checkZero(c.qc_minus_qty);
                 }
+                const cp = curPc.find(x => { return x.lid === c.lid; });
+                if (cp) {
+                    c.unit_price = cp.org_price;
+                    c.contract_tp = this.ctx.helper.add(c.contract_tp, cp.contract_pc_tp);
+                    c.qc_tp = this.ctx.helper.add(c.qc_tp, cp.qc_pc_tp);
+                    curPc.splice(curPc.indexOf(cp), 1);
+                }
+                if (!c.org_price) {
+                    const bills = await this.ctx.service.ledger.getDataById(c.lid);
+                    c.unit_price = bills ? bills.unit_price || 0 : 0;
+                }
             }
 
             for (const p of pre) {
                 if (p.id !== undefined) delete p.id;
                 p.sid = stage.id;
                 p.sorder = stage.order;
+                const cp = curPc.find(x => { return x.lid === p.lid; });
+                if (cp) {
+                    p.unit_price = cp.org_price;
+                    p.contract_tp = this.ctx.helper.add(p.contract_tp, cp.contract_pc_tp);
+                    p.qc_tp = this.ctx.helper.add(p.qc_tp, cp.qc_pc_tp);
+                    curPc.splice(curPc.indexOf(cp), 1);
+                }
             }
             await transaction.delete(this.tableName, { tid: tender.id, sid: stage.id });
             await transaction.insert(this.tableName, cur ? cur.concat(pre) : pre);

+ 79 - 0
app/service/stage_bills_pc.js

@@ -0,0 +1,79 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+
+module.exports = app => {
+
+    class stageBillsPc extends app.BaseService {
+
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'stage_bills_pc';
+        }
+
+        async getSumTotalPrice(stage) {
+            const sql = 'SELECT Sum(`contract_pc_tp`) As `contract_pc_tp`, Sum(`qc_pc_tp`) As `qc_pc_tp`, Sum(`pc_tp`) As `pc_tp`' +
+                '  FROM ' + this.tableName + ' Where sid = ?';
+            const result = await this.db.queryOne(sql, [stage.id]);
+            return result;
+        }
+
+        async getSumTotalPriceByMaterial(stage_list) {
+            let contract_pc_tp = 0;
+            let qc_pc_tp = 0;
+            let pc_tp = 0;
+            for (const stage of stage_list) {
+                const result = await this.getSumTotalPrice(stage);
+                if (result) {
+                    contract_pc_tp = this.ctx.helper.add(contract_pc_tp, result.contract_pc_tp);
+                    qc_pc_tp = this.ctx.helper.add(qc_pc_tp, result.qc_pc_tp);
+                    pc_tp = this.ctx.helper.add(pc_tp, result.pc_tp);
+                }
+            }
+            return { contract_pc_tp, qc_pc_tp, pc_tp };
+        }
+
+        async getEndStageData(stage) {
+            const sql = 'SELECT lid, SUM(contract_pc_tp) AS end_contract_pc_tp, SUM(qc_pc_tp) AS end_qc_pc_tp, SUM(pc_tp) AS end_pc_tp' +
+                '  FROM ' + this.tableName + ' WHERE tid = ? and sorder <= ? GROUP BY lid';
+            const result = await this.db.query(sql, [stage.tid, stage.order]);
+            return result;
+        }
+
+        async getStagesData(tid, stage_id_list) {
+            const sids = stage_id_list.split(',');
+            const result = [];
+            for (const sid of sids) {
+                const pcData = await this.getAllDataByCondition({ where: { sid } });
+                for (const sp of pcData) {
+                    const rsp = result.find(x => { return x.lid === sp.lid; });
+                    if (rsp) {
+                        rsp.contract_pc_tp = this.ctx.helper.add(rsp.contract_pc_tp, sp.contract_pc_tp);
+                        rsp.pc_tp = this.ctx.helper.add(rsp.pc_tp, sp.pc_tp);
+                        rsp.qc_pc_tp = this.ctx.helper.add(rsp.qc_pc_tp, sp.qc_pc_tp);
+                    } else {
+                        result.push({
+                            id: sp.id, tid: sp.tid, lid: sp.lid,
+                            qc_pc_tp: sp.qc_pc_tp, contract_pc_tp: sp.contract_pc_tp, pc_tp: sp.pc_tp,
+                        });
+                    }
+                }
+            }
+            return result;
+        }
+    }
+
+    return stageBillsPc;
+};

+ 8 - 8
app/service/stage_change.js

@@ -177,9 +177,9 @@ module.exports = app => {
                 '  INNER JOIN ( ' +
                 '    SELECT MAX(`stimes` * ' + timesLen + ' + `sorder`) As `progress`, `lid`, `pid`, `sid`, `cid`, `cbid`, `no_value` From ' + this.tableName +
                 '      WHERE tid = ? And sid = ? And lid = ? And pid = ?' + filter +
-                '      GROUP By `lid`, `pid`, `cid`, `cbid`, `no_value`' +
+                '      GROUP By `lid`, `pid`, `cbid`, `no_value`' +
                 '  ) As m ' +
-                '  ON (c.stimes * ' + timesLen + ' + c.sorder) = m.progress And c.lid = m.lid And c.pid = m.pid And c.`sid` = m.`sid` And c.`cid` = m.`cid` And c.`cbid` = m.`cbid` And c.`no_value` = m.`no_value`' +
+                '  ON (c.stimes * ' + timesLen + ' + c.sorder) = m.progress And c.lid = m.lid And c.pid = m.pid And c.`sid` = m.`sid` And c.`cbid` = m.`cbid` And c.`no_value` = m.`no_value`' +
                 '  LEFT JOIN ' + this.ctx.service.change.tableName + ' As oc' +
                 '  ON c.cid = oc.cid' +
                 '  LEFT JOIN ' + this.ctx.service.changeAuditList.tableName + ' As ocb' +
@@ -208,9 +208,9 @@ module.exports = app => {
                 '  INNER JOIN ( ' +
                 '    SELECT MAX(`stimes` * ' + timesLen + ' + `sorder`) As `progress`, `lid`, `pid`, `sid`, `cid`, `cbid`, `no_value` From ' + this.tableName +
                 '      WHERE tid = ? And sid = ? And (`stimes` < ? OR (`stimes` = ? AND `sorder` <= ?)) And lid = ? And pid = ?' + filter +
-                '      GROUP By `lid`, `pid`, cid, cbid, no_value' +
+                '      GROUP By `lid`, `pid`, cbid, no_value' +
                 '  ) As m ' +
-                '  ON (c.stimes * ' + timesLen + ' + c.sorder) = m.progress And c.lid = m.lid And c.pid = m.pid And c.`sid` = m.`sid` And c.`cid` = m.`cid` And c.`cbid` = m.`cbid` And c.`no_value` = m.`no_value`' +
+                '  ON (c.stimes * ' + timesLen + ' + c.sorder) = m.progress And c.lid = m.lid And c.pid = m.pid And c.`sid` = m.`sid` And c.`cbid` = m.`cbid` And c.`no_value` = m.`no_value`' +
                 '  LEFT JOIN ' + this.ctx.service.change.tableName + ' As oc' +
                 '  ON c.cid = oc.cid' +
                 '  LEFT JOIN ' + this.ctx.service.changeAuditList.tableName + ' As ocb' +
@@ -228,9 +228,9 @@ module.exports = app => {
                 '  INNER JOIN ( ' +
                 '    SELECT MAX(`stimes` * ' + timesLen + ' + `sorder`) As `progress`, `lid`, `pid`, `sid`, `cid`, `cbid`, `no_value` From ' + this.tableName +
                 '      WHERE tid = ? And sid = ?' +
-                '      GROUP By `lid`, `pid`, cid, cbid, no_value' +
+                '      GROUP By `lid`, `pid`, cbid, no_value' +
                 '  ) As m ' +
-                '  ON (c.stimes * ' + timesLen + ' + c.sorder) = m.progress And c.lid = m.lid And c.pid = m.pid And c.`sid` = m.`sid` And c.`cid` = m.`cid` And c.`cbid` = m.`cbid` And c.`no_value` = m.`no_value`' +
+                '  ON (c.stimes * ' + timesLen + ' + c.sorder) = m.progress And c.lid = m.lid And c.pid = m.pid And c.`sid` = m.`sid` And c.`cbid` = m.`cbid` And c.`no_value` = m.`no_value`' +
                 '  LEFT JOIN ' + this.ctx.service.change.tableName + ' As oc' +
                 '  ON c.cid = oc.cid' +
                 '  LEFT JOIN ' + this.ctx.service.changeAuditList.tableName + ' As ocb' +
@@ -247,9 +247,9 @@ module.exports = app => {
                 '  INNER JOIN ( ' +
                 '    SELECT MAX(`stimes` * ' + timesLen + ' + `sorder`) As `progress`, `lid`, `pid`, `sid`, `cid`, `cbid`, `no_value` From ' + this.tableName +
                 '      WHERE tid = ? And sid = ? And (`stimes` < ? OR (`stimes` = ? AND `sorder` <= ?))' +
-                '      GROUP By `lid`, `pid`, cid, cbid, no_value' +
+                '      GROUP By `lid`, `pid`, cbid, no_value' +
                 '  ) As m ' +
-                '  ON (c.stimes * ' + timesLen + ' + c.sorder) = m.progress And c.lid = m.lid And c.pid = m.pid And c.`sid` = m.`sid` And c.`cid` = m.`cid` And c.`cbid` = m.`cbid` And c.`no_value` = m.`no_value`' +
+                '  ON (c.stimes * ' + timesLen + ' + c.sorder) = m.progress And c.lid = m.lid And c.pid = m.pid And c.`sid` = m.`sid` And c.`cbid` = m.`cbid` And c.`no_value` = m.`no_value`' +
                 '  LEFT JOIN ' + this.ctx.service.change.tableName + ' As oc' +
                 '  ON c.cid = oc.cid' +
                 '  LEFT JOIN ' + this.ctx.service.changeAuditList.tableName + ' As ocb' +

+ 1 - 1
app/service/tender.js

@@ -437,7 +437,7 @@ module.exports = app => {
 
         async getCheckTender(tid) {
             const tender = await this.ctx.service.tender.getTender(tid);
-            tender.info = await this.ctx.service.tenderInfo.getTenderInfo(tid);
+            if (tender.measure_type) tender.info = await this.ctx.service.tenderInfo.getTenderInfo(tid);
             return tender;
         }
 

+ 13 - 6
app/service/tender_info.js

@@ -11,10 +11,9 @@
 const infoConst = require('../const/tender_info');
 const parseInfo = infoConst.parseInfo;
 const arrayInfo = infoConst.arrayInfo;
-const defaultInfo = infoConst.defaultInfo;
 const advanceConst = require('../const/audit').advance;
 const auditConst = require('../const/audit');
-
+const measureType = require('../const/tender').measureType;
 
 module.exports = app => {
 
@@ -31,6 +30,11 @@ module.exports = app => {
             this.tableName = 'tender_info';
         }
 
+        async getDefaultInfo (tenderId) {
+            const tender = await this.ctx.service.tender.getTender(tenderId);
+            return tender.measure_type === measureType.tz.value ? infoConst.tzDefaultInfo : infoConst.gclDefaultInfo;
+        }
+
         /**
          * 新增 标段相关信息
          *
@@ -40,6 +44,7 @@ module.exports = app => {
          * @return {Promise<void>}
          */
         async addTenderInfo(tenderId, projectId, transaction) {
+            const defaultInfo = await this.getDefaultInfo(tenderId);
             const info = JSON.parse(JSON.stringify(defaultInfo));
             info.tid = tenderId;
             info.pid = projectId;
@@ -64,14 +69,13 @@ module.exports = app => {
          * @return {Promise<void>}
          */
         async getTenderInfo(tenderId) {
+            const defaultInfo = await this.getDefaultInfo(tenderId);
             let info = await this.getDataByCondition({ tid: tenderId });
             // 兼容不存在info的情况
-            if (!info) {
-                info = await this.addTenderInfo(tenderId, this.ctx.session.sessionProject.id);
-            }
+            if (!info) info = await this.addTenderInfo(tenderId, this.ctx.session.sessionProject.id);
             for (const pi of parseInfo) {
                 info[pi] = !info[pi] || info[pi] === '' ? (pi === 'shenpi' ? JSON.parse(JSON.stringify(defaultInfo[pi])) : defaultInfo[pi]) : JSON.parse(info[pi]);
-                this.ctx.helper._.defaults(info[pi], defaultInfo[pi]);
+                this.ctx.helper._.defaultsDeep(info[pi], defaultInfo[pi]);
             }
             for (const ai of arrayInfo) {
                 info[ai] = !info[ai] || info[ai] === '' ? defaultInfo[ai] : JSON.parse(info[ai]);
@@ -88,6 +92,7 @@ module.exports = app => {
          * @return {Promise<void>}
          */
         async getTenderInfoEx(tenderId) {
+            const defaultInfo = await this.getDefaultInfo(tenderId);
             const sql = 'select t2.name, t1.* from zh_tender_info t1 inner join zh_tender t2 on t2.id = t1.tid where t1.tid = ?';
             const sqlParam = [tenderId];
             const list = await this.db.query(sql, sqlParam);
@@ -190,6 +195,7 @@ module.exports = app => {
                         b.sjcl_qty = sjcl_qty;
                         b.qtcl_qty = qtcl_qty;
                         b.quantity = quantity;
+                        // this.ctx.helper.checkFieldPrecision(b, ['deal_qty'], precision.value);
                     } else {
                         this.ctx.helper.checkFieldPrecision(b, ['sgfh_qty', 'sjcl_qty', 'qtcl_qty', 'deal_qty'], precision.value);
                     }
@@ -378,6 +384,7 @@ module.exports = app => {
          * @return {Promise<void>}
          */
         async getTenderShenpiInfo(tenderId) {
+            const defaultInfo = await this.getDefaultInfo(tenderId);
             const info = await this.getDataByCondition({ tid: tenderId });
             // 还没选择模式的标段不应该可以选择审批流程设置
             if (!info) {

+ 1 - 1
app/view/change/project.ejs

@@ -52,7 +52,7 @@
                     </div>
                 </div>
             </div>
-            <% if (tender.user_id === uid || (userPermission !== null && userPermission.tender !== undefined && userPermission.tender.indexOf('5') !== -1)) { %>
+            <% if (tender.user_id === uid || (userPermission !== null && ((userPermission.tender !== undefined && userPermission.tender.indexOf('5') !== -1) || (userPermission.change !== undefined && userPermission.change.indexOf('1') !== -1)))) { %>
             <div class="ml-auto">
                 <a href="#add-bj" data-toggle="modal" data-target="#add-bj" class="btn btn-sm btn-primary pull-right ml-1">新建变更立项</a>
                 <a href="#setting" data-toggle="modal" data-target="#setting" class="btn btn-sm btn-outline-primary pull-right ml-1"><i class="fa fa-cog"></i></a>

+ 1 - 1
app/view/change/project_modal.ejs

@@ -18,7 +18,7 @@
     </div>
 </div>
 
-<% if (tender.user_id === uid || (userPermission !== null && userPermission.tender !== undefined && userPermission.tender.indexOf('5') !== -1)) { %>
+<% if (tender.user_id === uid || (userPermission !== null && ((userPermission.tender !== undefined && userPermission.tender.indexOf('5') !== -1) || (userPermission.change !== undefined && userPermission.change.indexOf('1') !== -1)))) { %>
 <!--弹出添加变更令-->
 <div class="modal fade" id="add-bj-modal" data-backdrop="static">
     <div class="modal-dialog" role="document">

+ 4 - 1
app/view/change/sub_menu.ejs

@@ -2,7 +2,10 @@
     <div class="sidebar-title" data-toggle="tooltip" data-placement="right" data-original-title="变更台账新增部位">变更台账新增部位</div>
     <div class="scrollbar-auto">
         <% include ./sub_menu_list.ejs %>
-        <div class="side-fold"><a href="javascript: void(0)" data-toggle="tooltip" data-placement="top" data-original-title="折叠侧栏" id="to-mini-menu"><i class="fa fa-upload fa-rotate-270"></i></a></div>
+        <div class="side-show"></div>
+        <div class="side-fold" data-toggle="tooltip" data-placement="top" data-original-title="折叠侧栏" id="to-mini-menu">
+            <i class="fa fa-angle-left"></i>
+        </div>
     </div>
     <script>
         new Vue({

+ 4 - 4
app/view/change/sub_mini_menu.ejs

@@ -1,8 +1,8 @@
 <!--折起的菜单-->
 <div class="min-side" id="sub-mini-menu" style="display: none;">
-    <div id="sub-mini-hint" class="side-switch" data-container="body" data-toggle="popover" data-placement="bottom" data-content="这里打开收起的菜单栏"></div>
-    <div class="side-switch">
-        <i class="fa fa-bars"></i>
+    <div class="side-switch" data-toggle="tooltip" data-placement="left" data-original-title="点击这里打开收起的菜单栏">
+        <i class="fa fa-bars mt-2"></i>
+        <i class="fa fa-indent mt-2 text-primary" style="display: none;cursor: pointer;" id="to-menu"></i>
     </div>
     <div class="side-menu" id="mini-menu-list" style="display: none">
         <% include ./sub_menu_list.ejs %>
@@ -13,4 +13,4 @@
     new Vue({
         el: '.side-menu',
     });
-</script>
+</script>

+ 1 - 0
app/view/material/audit_modal.ejs

@@ -849,6 +849,7 @@
     $('#cc-digits').on('shown.bs.modal', function () {
         $('#decimal_up').val(<%- material.decimal.up %>);
         $('#decimal_tp').val(<%- material.decimal.tp %>);
+        $('#decimal_qty').val(<%- material.decimal.qty %>);
     });
     // 小数位设置
     function checkSetDecimal() {

+ 15 - 13
app/view/material/exponent.ejs

@@ -22,7 +22,7 @@
             </div>
             <div class="ml-auto">
                 <% if (ctx.session.sessionProject.page_show.openMaterialChecklist && material.order === material.highOrder) { %>
-                    <a href="/tender/<%- ctx.tender.id %>/measure/material/<%- material.highOrder %>/checklist" class="btn btn-sm btn-outline-primary">清单设置</a>
+                    <a href="/tender/<%- ctx.tender.id %>/measure/material/<%- material.highOrder %>/checklist" class="btn btn-sm btn-outline-primary">批量设置调差清单</a>
                 <% } %>
             </div>
         </div>
@@ -43,8 +43,8 @@
                             <div class="input-group-prepend">
                                 <span class="input-group-text" id="basic-addon1">增值税税率</span>
                             </div>
-                            <input id="rateInput" class="form-control form-control-sm col-1" <% if (material.readOnly) { %>disabled<% } %> type="number" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" min="0" step="1" max="100" value="<%- material.exponent_rate %>">
-                            <% if (!material.readOnly) { %>
+                            <input id="rateInput" class="form-control form-control-sm col-1" <% if (material.readOnly || material.editForAudit) { %>disabled<% } %> type="number" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" min="0" step="1" max="100" value="<%- material.exponent_rate %>">
+                            <% if (!material.readOnly || !material.editForAudit) { %>
                                 <div class="dropdown-menu">
                                     <a class="dropdown-item changeRate" href="javascript:void(0);" data-value="9">9%</a>
                                     <a class="dropdown-item changeRate" href="javascript:void(0);" data-value="10">10%</a>
@@ -52,7 +52,7 @@
                                 </div>
                             <% } %>
                             <!--<select class="form-control form-control-sm col-1" id="changeRate">-->
-                                <!--<% if (!material.readOnly) { %>-->
+                                <!--<% if (!material.readOnly && !material.editForAudit) { %>-->
                                     <!--<option value="9" <% if(material.exponent_rate === 9) { %>selected<% } %>>9%</option>-->
                                     <!--<option value="10" <% if(material.exponent_rate === 10) { %>selected<% } %>>10%</option>-->
                                     <!--<option value="11" <% if(material.exponent_rate === 11) { %>selected<% } %>>11%</option>-->
@@ -73,15 +73,15 @@
                                         <th>截止本期金额</th></tr>
                                     <tr id="tp_set"><td>材料价差费用</td>
                                         <td class="text-center"><%= material.m_tp !== null ? ctx.helper.round(material.m_tp, material.decimal.tp) : null %></td>
-                                        <td class="text-center"><%= material.m_tp !== null || material.pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.pre_tp, material.m_tp), material.decimal.tp) : null %></td>
+                                        <td class="text-center"><%= material.m_tp !== null || material.pre_tp !== null ? ctx.helper.add(material.pre_tp, ctx.helper.round(material.m_tp, material.decimal.tp)) : null %></td>
                                         <td class="text-center"><%= material.ex_tp !== null ? ctx.helper.round(material.ex_tp, material.decimal.tp) : null %></td>
-                                        <td class="text-center"><%= material.ex_tp !== null || material.ex_pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.ex_pre_tp, material.ex_tp), material.decimal.tp) : null %></td>
+                                        <td class="text-center"><%= material.ex_tp !== null || material.ex_pre_tp !== null ? ctx.helper.add(material.ex_pre_tp, ctx.helper.round(material.ex_tp, material.decimal.tp)) : null %></td>
                                     </tr>
                                     <tr id="rate_set"><td>材料价差费用(含建筑税)</td>
                                         <td class="text-center"><%= material.m_tp !== null ? ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), material.decimal.tp) : null %></td>
-                                        <td class="text-center"><%= material.m_tp !== null || pre_tp_hs !== null ? ctx.helper.round(ctx.helper.add(pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), material.decimal.tp)), material.decimal.tp) : null %></td>
+                                        <td class="text-center"><%= material.m_tp !== null || pre_tp_hs !== null ? ctx.helper.add(pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), material.decimal.tp)) : null %></td>
                                         <td class="text-center"><%= material.ex_tp !== null ? ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.exponent_rate/100), material.decimal.tp) : null %></td>
-                                        <td class="text-center"><%= material.ex_tp !== null || ex_pre_tp_hs !== null ? ctx.helper.round(ctx.helper.add(ex_pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.exponent_rate/100), material.decimal.tp)), material.decimal.tp) : null %></td>
+                                        <td class="text-center"><%= material.ex_tp !== null || ex_pre_tp_hs !== null ? ctx.helper.add(ex_pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.exponent_rate/100), material.decimal.tp)) : null %></td>
                                     </tr>
                                 </table>
                             </div>
@@ -97,21 +97,21 @@
                                         <th>截止本期金额</th></tr>
                                     <tr id="tp_set"><td>材料价差费用</td>
                                         <td class="text-center"><%= material.m_tp !== null ? ctx.helper.round(material.m_tp, material.decimal.tp) : null %></td>
-                                        <td class="text-center"><%= material.m_tp !== null || material.pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.pre_tp, material.m_tp), material.decimal.tp) : null %></td>
+                                        <td class="text-center"><%= material.m_tp !== null || material.pre_tp !== null ? ctx.helper.add(material.pre_tp, ctx.helper.round(material.m_tp, material.decimal.tp)) : null %></td>
                                         <td class="text-center"><%= material.ex_tp !== null ? ctx.helper.round(material.ex_tp, material.decimal.tp) : null %></td>
-                                        <td class="text-center"><%= material.ex_tp !== null || material.ex_pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.ex_pre_tp, material.ex_tp), material.decimal.tp) : null %></td>
+                                        <td class="text-center"><%= material.ex_tp !== null || material.ex_pre_tp !== null ? ctx.helper.add(material.ex_pre_tp, ctx.helper.round(material.ex_tp, material.decimal.tp)) : null %></td>
                                     </tr>
                                     <!--<tr><td>材料价差费用(含材料税)</td>-->
                                         <!--<td class="text-center"><%= material.material_tax ? (material.m_tax_tp !== null ? material.m_tax_tp : null) : '-' %></td>-->
-                                        <!--<td class="text-center"><%= material.material_tax ? (material.m_tax_tp !== null || material.m_tax_pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.m_tax_pre_tp, material.m_tax_tp), material.decimal.tp) : null) : material.m_tax_pre_tp %></td>-->
+                                        <!--<td class="text-center"><%= material.material_tax ? (material.m_tax_tp !== null || material.m_tax_pre_tp !== null ? ctx.helper.add(material.m_tax_pre_tp, material.m_tax_tp) : null) : material.m_tax_pre_tp %></td>-->
                                         <!--<td class="text-center">-</td>-->
                                         <!--<td class="text-center">-</td>-->
                                     <!--</tr>-->
                                     <tr id="rate_set"><td>材料价差费用(含建筑税)</td>
                                         <td class="text-center"><%= !material.material_tax ? (material.m_tp !== null ? ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), material.decimal.tp) : null) : '-' %></td>
-                                        <td class="text-center"><%= !material.material_tax ? (material.m_tp !== null || pre_tp_hs !== null ? ctx.helper.round(ctx.helper.add(pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), material.decimal.tp)), material.decimal.tp) : null) : pre_tp_hs !== null ? pre_tp_hs : '-' %></td>
+                                        <td class="text-center"><%= !material.material_tax ? (material.m_tp !== null || pre_tp_hs !== null ? ctx.helper.add(pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), material.decimal.tp)) : null) : pre_tp_hs !== null ? pre_tp_hs : '-' %></td>
                                         <td class="text-center"><%= material.ex_tp !== null ? ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.exponent_rate/100), material.decimal.tp) : null %></td>
-                                        <td class="text-center"><%= material.ex_tp !== null || ex_pre_tp_hs !== null ? ctx.helper.round(ctx.helper.add(ex_pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.exponent_rate/100), material.decimal.tp)), material.decimal.tp) : null %></td>
+                                        <td class="text-center"><%= material.ex_tp !== null || ex_pre_tp_hs !== null ? ctx.helper.add(ex_pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.exponent_rate/100), material.decimal.tp)) : null %></td>
                                     </tr>
                                 </table>
                             </div>
@@ -161,6 +161,7 @@
     const materialID = <%- material.id %>;
     const materialTax = <%- material.material_tax %>;
     const materialOrder = <%- material.order %>;
+    const editForAudit = <%- material.editForAudit %>;
     const materialDecimal = JSON.parse(unescape('<%- escape(JSON.stringify(material.decimal)) %>'));
     const decimal = JSON.parse('<%- JSON.stringify(ctx.tender.info.decimal) %>');
     let m_tp = <%= material.m_tp !== null ? material.m_tp : 0 %>;
@@ -174,4 +175,5 @@
     let ex_expr = '<%- material.ex_expr %>';
     let materialRate = parseInt('<%- material.exponent_rate %>');
     let materialExponentData = JSON.parse(unescape('<%- escape(JSON.stringify(materialExponentData)) %>'));
+    const materialBillsData = JSON.parse(unescape('<%- escape(JSON.stringify(materialBillsData)) %>'));
 </script>

+ 1 - 0
app/view/material/file.ejs

@@ -134,4 +134,5 @@
   const tender = JSON.parse(unescape('<%- escape(JSON.stringify(tender)) %>'));
   const whiteList = JSON.parse('<%- JSON.stringify(whiteList) %>');
   let currPageFileData = [];
+  const materialBillsData = JSON.parse(unescape('<%- escape(JSON.stringify(materialBillsData)) %>'));
 </script>

+ 13 - 11
app/view/material/info.ejs

@@ -93,8 +93,8 @@
                             <div class="input-group-prepend">
                                 <span class="input-group-text" id="basic-addon1">建筑增值税</span>
                             </div>
-                            <input id="rateInput" class="form-control form-control-sm col-1" <% if (material.material_tax || material.readOnly) { %>disabled<% } %> type="number" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" min="0" step="1" max="100" value="<%- material.rate %>">
-                            <% if (!material.readOnly || !material.material_tax) { %>
+                            <input id="rateInput" class="form-control form-control-sm col-1" <% if (material.material_tax || material.readOnly || material.editForAudit) { %>disabled<% } %> type="number" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" min="0" step="1" max="100" value="<%- material.rate %>">
+                            <% if (!material.readOnly || !material.editForAudit || !material.material_tax) { %>
                             <div class="dropdown-menu">
                                 <a class="dropdown-item changeRate" href="javascript:void(0);" data-value="9">9%</a>
                                 <a class="dropdown-item changeRate" href="javascript:void(0);" data-value="10">10%</a>
@@ -125,15 +125,15 @@
                                                 <th>截止本期金额</th></tr>
                                             <tr id="tp_set"><td>材料价差费用</td>
                                                 <td class="text-center"><%= material.m_tp !== null ? ctx.helper.round(material.m_tp, material.decimal.tp) : null %></td>
-                                                <td class="text-center"><%= material.m_tp !== null || material.pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.pre_tp, material.m_tp), material.decimal.tp) : null %></td>
+                                                <td class="text-center"><%= material.m_tp !== null || material.pre_tp !== null ? ctx.helper.add(material.pre_tp, ctx.helper.round(material.m_tp, material.decimal.tp)) : null %></td>
                                                 <td class="text-center"><%= material.ex_tp !== null ? ctx.helper.round(material.ex_tp, material.decimal.tp) : null %></td>
-                                                <td class="text-center"><%= material.ex_tp !== null || material.ex_pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.ex_pre_tp, material.ex_tp), material.decimal.tp) : null %></td>
+                                                <td class="text-center"><%= material.ex_tp !== null || material.ex_pre_tp !== null ? ctx.helper.add(material.ex_pre_tp, ctx.helper.round(material.ex_tp, material.decimal.tp)) : null %></td>
                                             </tr>
                                             <tr id="rate_set"><td>材料价差费用(含建筑税)</td>
                                                 <td class="text-center"><%= material.m_tp !== null ? ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), material.decimal.tp) : null %></td>
-                                                <td class="text-center"><%= material.m_tp !== null || pre_tp_hs !== null ? ctx.helper.round(ctx.helper.add(pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), material.decimal.tp)), material.decimal.tp) : null %></td>
+                                                <td class="text-center"><%= material.m_tp !== null || pre_tp_hs !== null ? ctx.helper.add(pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), material.decimal.tp)) : null %></td>
                                                 <td class="text-center"><%= material.ex_tp !== null ? ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.exponent_rate/100), material.decimal.tp) : null %></td>
-                                                <td class="text-center"><%= material.ex_tp !== null || ex_pre_tp_hs !== null ? ctx.helper.round(ctx.helper.add(ex_pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.exponent_rate/100), material.decimal.tp)), material.decimal.tp) : null %></td>
+                                                <td class="text-center"><%= material.ex_tp !== null || ex_pre_tp_hs !== null ? ctx.helper.add(ex_pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.exponent_rate/100), material.decimal.tp)) : null %></td>
                                             </tr>
                                         </table>
                                     </div>
@@ -149,21 +149,21 @@
                                                 <th>截止本期金额</th></tr>
                                             <tr id="tp_set"><td>材料价差费用</td>
                                                 <td class="text-center"><%= material.m_tp !== null ? ctx.helper.round(material.m_tp, material.decimal.tp) : null %></td>
-                                                <td class="text-center"><%= material.m_tp !== null || material.pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.pre_tp, material.m_tp), material.decimal.tp) : null %></td>
+                                                <td class="text-center"><%= material.m_tp !== null || material.pre_tp !== null ? ctx.helper.add(material.pre_tp, ctx.helper.round(material.m_tp, material.decimal.tp)) : null %></td>
                                                 <td class="text-center"><%= material.ex_tp !== null ? ctx.helper.round(material.ex_tp, material.decimal.tp) : null %></td>
-                                                <td class="text-center"><%= material.ex_tp !== null || material.ex_pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.ex_pre_tp, material.ex_tp), material.decimal.tp) : null %></td>
+                                                <td class="text-center"><%= material.ex_tp !== null || material.ex_pre_tp !== null ? ctx.helper.add(material.ex_pre_tp, ctx.helper.round(material.ex_tp, material.decimal.tp)) : null %></td>
                                             </tr>
                                             <tr id="tax_rate_set"><td>材料价差费用(含材料税)</td>
                                                 <td class="text-center"><%= material.material_tax ? (material.m_tax_tp !== null ? material.m_tax_tp : null) : '-' %></td>
-                                                <td class="text-center"><%= material.material_tax ? (material.m_tax_tp !== null || material.m_tax_pre_tp !== null ? ctx.helper.round(ctx.helper.add(material.m_tax_pre_tp, material.m_tax_tp), material.decimal.tp) : null) : material.m_tax_pre_tp %></td>
+                                                <td class="text-center"><%= material.material_tax ? (material.m_tax_tp !== null || material.m_tax_pre_tp !== null ? ctx.helper.add(material.m_tax_pre_tp, material.m_tax_tp) : null) : material.m_tax_pre_tp %></td>
                                                 <td class="text-center">-</td>
                                                 <td class="text-center">-</td>
                                             </tr>
                                             <tr id="rate_set"><td>材料价差费用(含建筑税)</td>
                                                 <td class="text-center"><%= !material.material_tax ? (material.m_tp !== null ? ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), material.decimal.tp) : null) : '-' %></td>
-                                                <td class="text-center"><%= !material.material_tax ? (material.m_tp !== null || pre_tp_hs !== null ? ctx.helper.round(ctx.helper.add(pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), material.decimal.tp)), material.decimal.tp) : null) : pre_tp_hs !== null ? pre_tp_hs : '-' %></td>
+                                                <td class="text-center"><%= !material.material_tax ? (material.m_tp !== null || pre_tp_hs !== null ? ctx.helper.add(pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), material.decimal.tp)) : null) : pre_tp_hs !== null ? pre_tp_hs : '-' %></td>
                                                 <td class="text-center"><%= material.ex_tp !== null ? ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.exponent_rate/100), material.decimal.tp) : null %></td>
-                                                <td class="text-center"><%= material.ex_tp !== null || ex_pre_tp_hs !== null ? ctx.helper.round(ctx.helper.add(ex_pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.exponent_rate/100), material.decimal.tp)), material.decimal.tp) : null %></td>
+                                                <td class="text-center"><%= material.ex_tp !== null || ex_pre_tp_hs !== null ? ctx.helper.add(ex_pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.exponent_rate/100), material.decimal.tp)) : null %></td>
                                             </tr>
                                         </table>
                                     </div>
@@ -228,6 +228,8 @@
 <script>
     const materialType = JSON.parse('<%- materialType %>');
     const isStageSelf = parseInt('<%- material.is_stage_self %>');
+    const editTaxPermission = <%- material.editTaxPermission %>;
+    const editForAudit = <%- material.editForAudit %>;
     let materialBillsData = JSON.parse(unescape('<%- escape(JSON.stringify(materialBillsData)) %>'));
     let materialStageData = isStageSelf ? JSON.parse(unescape('<%- escape(JSON.stringify(materialStageData)) %>')) : [];
     let materialStageBillsData = isStageSelf ? JSON.parse(unescape('<%- escape(JSON.stringify(materialStageBillsData)) %>')) : [];

+ 4 - 0
app/view/material/list.ejs

@@ -99,10 +99,14 @@
 <script>
     const materialType = JSON.parse('<%- materialType %>');
     const isStageSelf = parseInt('<%- material.is_stage_self %>');
+    const editForAudit = <%- material.editForAudit %>;
     const materialBillsData = JSON.parse(unescape('<%- escape(JSON.stringify(materialBillsData)) %>'));
     const materialStageData = isStageSelf ? JSON.parse(unescape('<%- escape(JSON.stringify(materialStageData)) %>')) : [];
     const materialStageBillsData = isStageSelf ? JSON.parse(unescape('<%- escape(JSON.stringify(materialStageBillsData)) %>')) : [];
     const readOnly = <%- material.readOnly %>;
+    const openMaterialSelf = parseInt(<%- ctx.session.sessionProject.page_show.openMaterialSelf %>);
+    const editListPermission = <%- material.editListPermission %>;
+    console.log(editListPermission);
     const stage_order = <%- material.order %>;
     const materialID = <%- material.id %>;
     const tenderID = <%- tender.id %>;

+ 5 - 1
app/view/material/material_sub_menu.ejs

@@ -39,6 +39,10 @@
             </ul>
         </div>
         <% include ./audit_btn.ejs %>
-        <div class="side-fold"><a href="javascript: void(0)" data-toggle="tooltip" data-placement="top" data-original-title="折叠侧栏" id="to-mini-menu"><i class="fa fa-sign-out fa-flip-horizontal"></i></a></div>
+        <!--<div class="side-fold"><a href="javascript: void(0)" data-toggle="tooltip" data-placement="top" data-original-title="折叠侧栏" id="to-mini-menu"><i class="fa fa-sign-out fa-flip-horizontal"></i></a></div>-->
+    </div>
+    <div class="side-show"></div>
+    <div class="side-fold" data-toggle="tooltip" data-placement="top" data-original-title="折叠侧栏" id="to-mini-menu">
+        <i class="fa fa-angle-left"></i>
     </div>
 </div>

+ 4 - 3
app/view/material/material_sub_mini_menu.ejs

@@ -1,7 +1,8 @@
 <!--折起的菜单-->
 <div class="min-side" id="sub-mini-menu" style="display: none;">
-    <div class="side-switch">
-        <i class="fa fa-bars"></i>
+    <div class="side-switch" data-toggle="tooltip" data-placement="left" data-original-title="点击这里打开收起的菜单栏">
+        <i class="fa fa-bars mt-2"></i>
+        <i class="fa fa-indent mt-2 text-primary" style="display: none;cursor: pointer;" id="to-menu"></i>
     </div>
     <div class="side-menu" id="mini-menu-list" style="display: none">
         <% if (ctx.url !== '/tender/' + ctx.tender.id + '/measure/material/' + ctx.material.order + '/checklist') { %>
@@ -40,6 +41,6 @@
             </ul>
         </div>
         <% include ./audit_btn.ejs %>
-        <div class="side-fold"><a href="javascript: void(0);" data-toggle="tooltip" data-placement="top" data-original-title="展开侧栏" id="to-menu"><i class="fa fa-thumb-tack"></i></a></div>
+        <!--<div class="side-fold"><a href="javascript: void(0);" data-toggle="tooltip" data-placement="top" data-original-title="展开侧栏" id="to-menu"><i class="fa fa-thumb-tack"></i></a></div>-->
     </div>
 </div>

+ 43 - 0
app/view/revise/price.ejs

@@ -0,0 +1,43 @@
+<% include ./sub_menu.ejs %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main  d-flex">
+            <% include ./sub_mini_menu.ejs %>
+            单价调整
+        </div>
+    </div>
+    <div class="content-wrap row pr-46">
+        <div class="c-header p-0 col-12"></div>
+        <!--核心内容(两栏)-->
+        <div class="row w-100 sub-content">
+            <!--左栏-->
+            <div class="c-body" id="left-view" style="width: 100%">
+                <!--0号台账模式-->
+                <div class="sjs-height-0" style="overflow: hidden" id="price-spread">
+                </div>
+            </div>
+            <!--右栏-->
+            <div class="c-body" id="right-view" style="display: none; width: 33%;">
+                <div class="resize-x" id="revise-right-spr" r-Type="width" div1="#left-view" div2="#right-view" title="调整大小" a-type="percent"><!--调整左右高度条--></div>
+                <div class="tab-content">
+                    <div id="ledgerGcl" class="tab-pane">
+                        <div id="ledger-gcl-spread" class="sjs-sh"></div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <!--右侧菜单-->
+        <div class="side-menu">
+            <!--右侧菜单-->
+            <ul class="nav flex-column right-nav" id="side-menu">
+                <li class="nav-item">
+                    <a class="nav-link" content="#ledgerGcl" href="javascript: void(0);">台账清单</a>
+                </li>
+            </ul>
+        </div>
+    </div>
+</div>
+<script src="/public/js/moment/moment.min.js"></script>
+<script>
+    const readOnly = <%- ctx.revise.readOnly %>;
+</script>

+ 6 - 3
app/view/revise/sub_menu.ejs

@@ -2,11 +2,14 @@
     <div class="sidebar-title" data-toggle="tooltip" data-placement="right" data-original-title="<%- ctx.revise.corder %># 台账修订"><%- ctx.revise.corder %># 台账修订</div>
     <div class="scrollbar-auto">
         <% include ./sub_menu_list.ejs %>
-        <div class="side-fold"><a href="javascript: void(0)" data-toggle="tooltip" data-placement="top" data-original-title="折叠侧栏" id="to-mini-menu"><i class="fa fa-upload fa-rotate-270"></i></a></div>
+        <div class="side-show"></div>
+        <div class="side-fold" data-toggle="tooltip" data-placement="top" data-original-title="折叠侧栏" id="to-mini-menu">
+            <i class="fa fa-angle-left"></i>
+        </div>
     </div>
     <script>
-        new Vue({
+        const subMenu = new Vue({
             el: '.scrollbar-auto',
         });
     </script>
-</div>
+</div>

+ 1 - 0
app/view/revise/sub_menu_list.ejs

@@ -1,4 +1,5 @@
 <nav-menu title="返回" url="/tender/<%= ctx.tender.id %>/revise" tclass="text-primary" ml="1" icon="fa-chevron-left"></nav-menu>
 <nav-menu title="台账修订" url="<%= preUrl %>/info" ml="3" active="<%= ctx.url.indexOf('/info') %>"></nav-menu>
+<nav-menu title="单价调整" url="<%= preUrl %>/price" ml="3" active="<%= ctx.url.indexOf('/price') %>" <% if (ctx.revise.priceCount > 0) { %>hinticon="fa-bell"<% } %>></nav-menu>
 <nav-menu title="台账对比" url="<%= preUrl %>/compare" ml="3" active="<%= ctx.url.indexOf('/compare') %>"></nav-menu>
 <nav-menu title="清单对比" url="<%= preUrl %>/gcl-compare" ml="3" active="<%= ctx.url.indexOf('/gcl-compare') %>"></nav-menu>

+ 5 - 5
app/view/revise/sub_mini_menu.ejs

@@ -1,8 +1,8 @@
 <!--折起的菜单-->
 <div class="min-side" id="sub-mini-menu" style="display: none;">
-    <div id="sub-mini-hint" class="side-switch" data-container="body" data-toggle="popover" data-placement="bottom" data-content="这里打开收起的菜单栏"></div>
-    <div class="side-switch">
-        <i class="fa fa-bars"></i>
+    <div class="side-switch" data-toggle="tooltip" data-placement="left" data-original-title="点击这里打开收起的菜单栏">
+        <i class="fa fa-bars mt-2"></i>
+        <i class="fa fa-indent mt-2 text-primary" style="display: none;cursor: pointer;" id="to-menu"></i>
     </div>
     <div class="side-menu" id="mini-menu-list" style="display: none">
         <% include ./sub_menu_list.ejs %>
@@ -10,7 +10,7 @@
     </div>
 </div>
 <script>
-    new Vue({
+    const subMiniMenu = new Vue({
         el: '.side-menu',
     });
-</script>
+</script>

+ 16 - 0
app/view/setting/fun.ejs

@@ -100,6 +100,20 @@
                                                 <label class="form-check-label" for="openMaterialChecklist">开启「批量设置调差清单」添加调差工料功能</label>
                                             </div>
                                         </div>
+                                        <div class="form-group mb-1">
+                                            <div class="form-check form-check-inline">
+                                                <input class="form-check-input" type="checkbox" id="openMaterialSelf" <% if(ctx.session.sessionProject.page_show.openMaterialSelf) { %>checked<% } %> onchange="updateSetting();">
+                                                <label class="form-check-label" for="openMaterialSelf">开启调差清单-所属项目节「单独添加工料」功能
+                                                    <a href="javascript:void(0);"  data-toggle="tooltip" data-placement="bottom" title="" data-original-title="开启该选项,调差清单的所属项目节,允许单独添加工料"><i class="fa fa-question-circle "></i></a></label>
+                                            </div>
+                                        </div>
+                                        <div class="form-group mb-1">
+                                            <div class="form-check form-check-inline">
+                                                <input class="form-check-input" type="checkbox" id="openMaterialEditForAudit" <% if(ctx.session.sessionProject.page_show.openMaterialEditForAudit) { %>checked<% } %> onchange="updateSetting();">
+                                                <label class="form-check-label" for="openMaterialEditForAudit">开启「审核人修改数据」功能
+                                                    <a href="javascript:void(0);"  data-toggle="tooltip" data-placement="bottom" title="" data-original-title="开启该选项,审核人允许修改部分调差工料数据"><i class="fa fa-question-circle "></i></a></label>
+                                            </div>
+                                        </div>
                                     </div>
                                 </div>
                             </div>
@@ -155,6 +169,8 @@
             openChangePlan: $('#openChangePlan')[0].checked,
             openMaterialTax: $('#openMaterialTax')[0].checked,
             openMaterialChecklist: $('#openMaterialChecklist')[0].checked,
+            openMaterialSelf: $('#openMaterialSelf')[0].checked,
+            openMaterialEditForAudit: $('#openMaterialEditForAudit')[0].checked,
         });
     }
 </script>

+ 11 - 5
app/view/setting/user_permission_modal.ejs

@@ -84,6 +84,7 @@
                     <label><i <% if (permission[pm].class !== '') { %>class="<%= permission[pm].class %>"<% } %>></i> <%= permission[pm].title %> <sup><%= index %></sup></label>
                     <div>
                         <% for (const ip of permission[pm].children) { %>
+                        <% if (ip.show === undefined && ip.show !== false) { %>
                         <div class="form-check form-check-inline">
                             <input class="form-check-input" type="<%= permission[pm].type %>" id="<%= pm %>_<%= ip.value %>" name="<%= pm %><% if (permission[pm].type === 'checkbox') { %>[]<% } %>" value="<%= ip.value %>">
                             <label class="form-check-label" for="<%= pm %>_<%= ip.value %>"><%= ip.title %></label>
@@ -92,14 +93,19 @@
                             <% } %>
                         </div>
                         <% } %>
+                        <% } %>
+                    </div>
+                    <% if (permission[pm].tips) { %>
+                    <!--需要勾选  创建标段 ,协作办公才能勾选-->
+                    <div class="alert alert-secondary">
+                        <p class="mb-0"><%- permission[pm].tips %></p>
                     </div>
+                    <% } %>
                 </div>
+                <% if (ctx.helper._.size(permission) !== index) { %>
+                <hr>
+                <% } %>
                 <% } %>
-                <!--需要勾选  创建标段 ,协作办公才能勾选-->
-                <div class="alert alert-secondary">
-                    <p>1.勾选「创建标段」该用户默认具有「新建标段」及标段内「台账分解」「创建台账修订」「创建计量期」「创建工程变更」的权限。</p>
-                    <!--2.启用「协作办公」,则该用户可以为他创建的标段添加其他用户进行协作办公。-->
-                </div>
             </div>
             <div class="modal-footer">
                 <input type="hidden" name="id" value="">

+ 18 - 0
app/view/stage/manager.ejs

@@ -85,4 +85,22 @@
 </div>
 <script type="text/javascript">
     autoFlashHeight();
+    $(function () {
+        $.subMenu({
+            menu: '#sub-menu', miniMenu: '#sub-mini-menu', miniMenuList: '#mini-menu-list',
+            toMenu: '#to-menu', toMiniMenu: '#to-mini-menu',
+            key: 'menu.1.0.0',
+            miniHint: '#sub-mini-hint', hintKey: 'menu.hint.1.0.1',
+            callback: function (info) {
+                if (info.mini) {
+                    $('.panel-title').addClass('fluid');
+                    $('#sub-menu').removeClass('panel-sidebar');
+                } else {
+                    $('.panel-title').removeClass('fluid');
+                    $('#sub-menu').addClass('panel-sidebar');
+                }
+                autoFlashHeight();
+            }
+        });
+    })
 </script>

+ 4 - 1
app/view/stage/stage_sub_menu.ejs

@@ -94,6 +94,9 @@
         </div>
         <% } %>
         <% include ./audit_btn.ejs %>
-        <div class="side-fold"><a href="javascript: void(0)" data-toggle="tooltip" data-placement="top" data-original-title="折叠侧栏" id="to-mini-menu"><i class="fa fa-upload fa-rotate-270"></i></a></div>
+        <div class="side-show"></div>
+        <div class="side-fold" data-toggle="tooltip" data-placement="top" data-original-title="折叠侧栏" id="to-mini-menu">
+            <i class="fa fa-angle-left"></i>
+        </div>
     </div>
 </div>

+ 4 - 4
app/view/stage/stage_sub_mini_menu.ejs

@@ -1,8 +1,8 @@
 <!--折起的菜单-->
 <div class="min-side" id="sub-mini-menu" style="display: none;">
-    <div id="sub-mini-hint" class="side-switch" data-container="body" data-toggle="popover" data-placement="bottom" data-content="这里打开收起的菜单栏"></div>
-    <div class="side-switch">
-        <i class="fa fa-bars"></i>
+    <div class="side-switch" data-toggle="tooltip" data-placement="left" data-original-title="点击这里打开收起的菜单栏">
+        <i class="fa fa-bars mt-2"></i>
+        <i class="fa fa-indent mt-2 text-primary" style="display: none;cursor: pointer;" id="to-menu"></i>
     </div>
     <div class="side-menu" id="mini-menu-list" style="display: none">
         <div class="nav-box">
@@ -96,6 +96,6 @@
             </div>
         <% } %>
         <% include ./audit_btn.ejs %>
-        <div class="side-fold"><a href="javascript: void(0);" data-toggle="tooltip" data-placement="top" data-original-title="展开侧栏" id="to-menu"><i class="fa fa-upload fa-rotate-90"></i></a></div>
+        <!--<div class="side-fold"><a href="javascript: void(0);" data-toggle="tooltip" data-placement="top" data-original-title="展开侧栏" id="to-menu"><i class="fa fa-upload fa-rotate-90"></i></a></div>-->
     </div>
 </div>

+ 6 - 1
app/view/tender/detail_modal.ejs

@@ -715,6 +715,10 @@
                         <label class="custom-control-label" for="stage-rc">实际完成量与预计变更</label>
                     </div>
                     <div class="custom-control custom-checkbox mb-2">
+                        <input type="checkbox" class="custom-control-input" checked="" id="stage-priceDiff">
+                        <label class="custom-control-label" for="stage-priceDiff">显示“本期补差”列</label>
+                    </div>
+                    <div class="custom-control custom-checkbox mb-2">
                         <input type="checkbox" class="custom-control-input" checked="" id="stage-correct">
                         <label class="custom-control-label" for="stage-correct">使用数量纠正完成率</label>
                     </div>
@@ -1496,6 +1500,7 @@
         $('#ex-memo')[0].checked = property.display.exMemo;
         $('#thousandth')[0].checked = property.display.thousandth;
         $('#stage-rc')[0].checked = property.display.stage.realComplete;
+        $('#stage-priceDiff')[0].checked = property.display.stage.priceDiff;
         $('#stage-correct')[0].checked = property.display.stage.correct;
         $('#dayMode')[0].checked = property.display.dayMode;
     }
@@ -1508,7 +1513,7 @@
                 ledger: { deal: $('#ledger-deal')[0].checked, dgnQty: $('#ledger-dgn-qty')[0].checked, clQty: $('#ledger-cl-qty')[0].checked, },
                 exMemo: $('#ex-memo')[0].checked,
                 thousandth: $('#thousandth')[0].checked,
-                stage: { realComplete: $('#stage-rc')[0].checked, correct: $('#stage-correct')[0].checked },
+                stage: { realComplete: $('#stage-rc')[0].checked, correct: $('#stage-correct')[0].checked, priceDiff: $('#stage-priceDiff')[0].checked },
                 dayMode: $('#dayMode')[0].checked,
             },
         };

+ 4 - 1
app/view/tender/tender_sub_menu.ejs

@@ -82,6 +82,9 @@
             </ul>
         </div>
         <% } %>
-        <div class="side-fold"><a href="javascript: void(0)" data-toggle="tooltip" data-placement="top" data-original-title="折叠侧栏" id="to-mini-menu"><i class="fa fa-upload fa-rotate-270"></i></a></div>
+    </div>
+    <div class="side-show"></div>
+    <div class="side-fold" data-toggle="tooltip" data-placement="top" data-original-title="折叠侧栏" id="to-mini-menu">
+        <i class="fa fa-angle-left"></i>
     </div>
 </div>

+ 10 - 4
app/view/tender/tender_sub_mini_menu.ejs

@@ -1,8 +1,9 @@
 <!--折起的菜单-->
 <div class="min-side" id="sub-mini-menu" style="display: none;">
-    <div id="sub-mini-hint" class="side-switch" data-container="body" data-toggle="popover" data-placement="bottom" data-content="这里打开收起的菜单栏"></div>
-    <div class="side-switch">
-        <i class="fa fa-bars"></i>
+    <!--<div id="sub-mini-hint" class="side-switch" data-container="body" data-toggle="popover" data-placement="bottom" data-content="这里打开收起的菜单栏"></div>-->
+    <div class="side-switch" data-toggle="tooltip" data-placement="left" data-original-title="点击这里打开收起的菜单栏">
+        <i class="fa fa-bars mt-2"></i>
+        <i class="fa fa-indent mt-2 text-primary" style="display: none;cursor: pointer;" id="to-menu"></i>
     </div>
     <div class="side-menu" id="mini-menu-list" style="display: none">
         <div class="nav-box">
@@ -70,6 +71,11 @@
                 <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/report') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/report" class="h3"><i class="fa fa-file-text-o fa-fw"></i> <span>输出报表</span></a></li>
             </ul>
         </div>
+        <div class="nav-box">
+            <ul class="nav-list list-unstyled">
+                <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/archiveReport') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/archiveReport" class="h3"><i class="fa fa-archive fa-fw"></i> <span>归档报表</span></a></li>
+            </ul>
+        </div>
         <% if (ctx.session.sessionProject.page_show.openNetCaSign) { %>
             <div class="nav-box">
                 <ul class="nav-list list-unstyled">
@@ -77,6 +83,6 @@
                 </ul>
             </div>
         <% } %>
-        <div class="side-fold"><a href="javascript: void(0);" data-toggle="tooltip" data-placement="top" data-original-title="展开侧栏" id="to-menu"><i class="fa fa-upload fa-rotate-90"></i></a></div>
+        <!--<div class="side-fold"><a href="javascript: void(0);" data-toggle="tooltip" data-placement="top" data-original-title="展开侧栏" id="to-menu"><i class="fa fa-upload fa-rotate-90"></i></a></div>-->
     </div>
 </div>

+ 20 - 0
config/web.js

@@ -110,6 +110,7 @@ const JsFiles = {
                     '/public/js/PinYinOrder.bundle.js',
                     '/public/js/shares/tender_list_order.js',
                     '/public/js/tender_showhide.js',
+                    '/public/js/shares/show_level.js',
                     '/public/js/tender_copy_setting.js',
                     // "/public/js/tender.js",
                 ],
@@ -129,6 +130,7 @@ const JsFiles = {
                     '/public/js/path_tree.js',
                     '/public/js/shenpi.js',
                     '/public/js/tender_showhide.js',
+                    '/public/js/shares/show_level.js',
                 ],
                 mergeFile: 'tender_shenpi',
             },
@@ -252,6 +254,24 @@ const JsFiles = {
                 ],
                 mergeFile: 'revise',
             },
+            price: {
+                files: [
+                    '/public/js/spreadjs/sheets/v11/gc.spread.sheets.all.11.2.2.min.js',
+                    '/public/js/component/menu.js',
+                    '/public/js/decimal.min.js',
+                ],
+                mergeFiles: [
+                    '/public/js/sub_menu.js',
+                    '/public/js/div_resizer.js',
+                    '/public/js/spreadjs_rela/spreadjs_zh.js',
+                    '/public/js/shares/sjs_setting.js',
+                    '/public/js/zh_calc.js',
+                    '/public/js/path_tree.js',
+                    '/public/js/gcl_gather.js',
+                    '/public/js/revise_price.js',
+                ],
+                mergeFile: 'revise_price',
+            },
             history: {
                 files: ['/public/js/spreadjs/sheets/v11/gc.spread.sheets.all.11.2.2.min.js', '/public/js/decimal.min.js', '/public/js/component/menu.js'],
                 mergeFiles: [

+ 179 - 0
sql/update.sql

@@ -61,3 +61,182 @@ ADD COLUMN `invalid_time`  varchar(50) NOT NULL DEFAULT '' AFTER `wx_name`;
 ALTER TABLE `zh_valuation_list` ADD `glj_lib_id` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '(0号台账模式)zh_glj_lib_list id列表,逗号分隔' AFTER `chapter_id`;
 ALTER TABLE `zh_valuation_list` ADD `list_glj_lib_id` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '(工程量清单模式)zh_glj_lib_list id列表,逗号分隔' AFTER `list_chapter_id`;
 
+CREATE TABLE `zh_revise_price` (
+  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+  `pid` bigint(20) unsigned NOT NULL COMMENT '项目id',
+  `tid` bigint(20) unsigned NOT NULL COMMENT '标段id',
+  `rid` varchar(36) COLLATE utf8_unicode_ci NOT NULL COMMENT '台账修订id',
+  `order` int(11) unsigned NOT NULL COMMENT '排序',
+  `b_code` varchar(50) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '清单编号',
+  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '名称',
+  `unit` varchar(20) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '单位',
+  `org_price` decimal(24,8) NOT NULL DEFAULT '0.00000000' COMMENT '旧单价',
+  `new_price` decimal(24,8) NOT NULL DEFAULT '0.00000000' COMMENT '变更单价',
+  `memo` varchar(1000) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '备注',
+  `valid` tinyint(4) unsigned NOT NULL DEFAULT '1' COMMENT '是否有效',
+  `use_stage` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '使用期',
+  `use_stage_order` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '使用期序号',
+  PRIMARY KEY (`id`),
+  KEY `idx_rid` (`rid`) USING BTREE,
+  KEY `idx_tid_valid_stage` (`rid`,`valid`,`use_stage`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='台账修订-单价调整';
+
+CREATE TABLE `zh_stage_bills_pc` (
+  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+  `tid` int(11) unsigned NOT NULL COMMENT '标段id',
+  `sid` int(11) NOT NULL,
+  `lid` varchar(36) COLLATE utf8_unicode_ci NOT NULL COMMENT '项目节id',
+  `contract_pc_tp` decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)',
+  `qc_pc_tp` decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)',
+  `pc_tp` decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差',
+  PRIMARY KEY (`id`),
+  KEY `idx_sid` (`sid`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='期-项目节-补差数据';
+
+ALTER TABLE `zh_stage_bills_final_0`
+ADD COLUMN `unit_price`  decimal(24,8) UNSIGNED NOT NULL DEFAULT 0 COMMENT '本期单价' AFTER `contract_expr`,
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `used`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT  '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_bills_final_1`
+ADD COLUMN `unit_price`  decimal(24,8) UNSIGNED NOT NULL DEFAULT 0 COMMENT '本期单价' AFTER `contract_expr`,
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `used`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT  '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_bills_final_2`
+ADD COLUMN `unit_price`  decimal(24,8) UNSIGNED NOT NULL DEFAULT 0 COMMENT '本期单价' AFTER `contract_expr`,
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `used`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT  '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_bills_final_3`
+ADD COLUMN `unit_price`  decimal(24,8) UNSIGNED NOT NULL DEFAULT 0 COMMENT '本期单价' AFTER `contract_expr`,
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `used`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT  '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_bills_final_4`
+ADD COLUMN `unit_price`  decimal(24,8) UNSIGNED NOT NULL DEFAULT 0 COMMENT '本期单价' AFTER `contract_expr`,
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `used`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT  '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_bills_final_5`
+ADD COLUMN `unit_price`  decimal(24,8) UNSIGNED NOT NULL DEFAULT 0 COMMENT '本期单价' AFTER `contract_expr`,
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `used`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT  '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_bills_final_6`
+ADD COLUMN `unit_price`  decimal(24,8) UNSIGNED NOT NULL DEFAULT 0 COMMENT '本期单价' AFTER `contract_expr`,
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `used`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT  '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_bills_final_7`
+ADD COLUMN `unit_price`  decimal(24,8) UNSIGNED NOT NULL DEFAULT 0 COMMENT '本期单价' AFTER `contract_expr`,
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `used`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT  '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_bills_final_8`
+ADD COLUMN `unit_price`  decimal(24,8) UNSIGNED NOT NULL DEFAULT 0 COMMENT '本期单价' AFTER `contract_expr`,
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `used`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT  '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_bills_final_9`
+ADD COLUMN `unit_price`  decimal(24,8) UNSIGNED NOT NULL DEFAULT 0 COMMENT '本期单价' AFTER `contract_expr`,
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `used`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT  '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+
+ALTER TABLE `zh_stage_pos_final_0`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0  COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0  COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_1`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0  COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0  COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_2`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0  COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_3`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_4`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_5`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_6`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_7`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_8`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_9`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_10`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_11`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_12`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_13`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_14`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_15`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_16`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_17`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_18`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+ALTER TABLE `zh_stage_pos_final_19`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `unit_price`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;
+
+Update zh_stage_bills_final_0 sp LEFT JOIN zh_ledger_0 p on sp.lid = p.id Set sp.unit_price = IFNULL(p.unit_price, 0);
+Update zh_stage_bills_final_1 sp LEFT JOIN zh_ledger_1 p on sp.lid = p.id Set sp.unit_price = IFNULL(p.unit_price, 0);
+Update zh_stage_bills_final_2 sp LEFT JOIN zh_ledger_2 p on sp.lid = p.id Set sp.unit_price = IFNULL(p.unit_price, 0);
+Update zh_stage_bills_final_3 sp LEFT JOIN zh_ledger_3 p on sp.lid = p.id Set sp.unit_price = IFNULL(p.unit_price, 0);
+Update zh_stage_bills_final_4 sp LEFT JOIN zh_ledger_4 p on sp.lid = p.id Set sp.unit_price = IFNULL(p.unit_price, 0);
+Update zh_stage_bills_final_5 sp LEFT JOIN zh_ledger_5 p on sp.lid = p.id Set sp.unit_price = IFNULL(p.unit_price, 0);
+Update zh_stage_bills_final_6 sp LEFT JOIN zh_ledger_6 p on sp.lid = p.id Set sp.unit_price = IFNULL(p.unit_price, 0);
+Update zh_stage_bills_final_7 sp LEFT JOIN zh_ledger_7 p on sp.lid = p.id Set sp.unit_price = IFNULL(p.unit_price, 0);
+Update zh_stage_bills_final_8 sp LEFT JOIN zh_ledger_8 p on sp.lid = p.id Set sp.unit_price = IFNULL(p.unit_price, 0);
+Update zh_stage_bills_final_9 sp LEFT JOIN zh_ledger_9 p on sp.lid = p.id Set sp.unit_price = IFNULL(p.unit_price, 0);
+
+ALTER TABLE `zh_stage`
+ADD COLUMN `contract_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(合同)' AFTER `qc_tp`,
+ADD COLUMN `qc_pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差(变更)' AFTER `contract_pc_tp`,
+ADD COLUMN `pc_tp`  decimal(24,8) NOT NULL DEFAULT 0 COMMENT '本期补差' AFTER `qc_pc_tp`;