Browse Source

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

Tony Kang 2 years ago
parent
commit
a051cb5cd5
47 changed files with 2154 additions and 493 deletions
  1. 1 0
      app/const/tender_info.js
  2. 1 1
      app/controller/change_controller.js
  3. 1 1
      app/controller/ledger_audit_controller.js
  4. 3 3
      app/controller/ledger_controller.js
  5. 73 33
      app/controller/material_controller.js
  6. 2 2
      app/controller/revise_controller.js
  7. 9 7
      app/controller/stage_controller.js
  8. 2 2
      app/lib/spread_setting.js
  9. 7 4
      app/public/js/ledger.js
  10. 179 42
      app/public/js/material.js
  11. 111 4
      app/public/js/material_checklist.js
  12. 356 106
      app/public/js/material_list.js
  13. 177 78
      app/public/js/measure_material.js
  14. 4 4
      app/public/js/revise.js
  15. 54 0
      app/public/js/shares/show_level.js
  16. 126 0
      app/public/js/spreadjs_rela/spreadjs_zh.js
  17. 14 7
      app/public/js/stage.js
  18. 5 2
      app/public/js/stage_bwtz.js
  19. 15 0
      app/public/js/stage_compare.js
  20. 1 0
      app/public/js/tender_list.js
  21. 1 0
      app/public/js/tender_list_info.js
  22. 1 0
      app/public/js/tender_list_manage.js
  23. 1 0
      app/public/js/tender_list_progress.js
  24. 75 2
      app/public/js/tender_showhide.js
  25. 35 4
      app/service/material.js
  26. 275 57
      app/service/material_bills.js
  27. 82 21
      app/service/material_list.js
  28. 6 6
      app/service/material_list_notjoin.js
  29. 49 22
      app/service/material_list_self.js
  30. 38 0
      app/service/material_stage.js
  31. 208 0
      app/service/material_stage_bills.js
  32. 8 0
      app/service/project.js
  33. 1 1
      app/service/stage.js
  34. 1 1
      app/view/dashboard/index.ejs
  35. 13 0
      app/view/material/audit_modal.ejs
  36. 4 1
      app/view/material/checklist.ejs
  37. 1 1
      app/view/material/file.ejs
  38. 130 69
      app/view/material/info.ejs
  39. 5 2
      app/view/material/info_modal.ejs
  40. 15 3
      app/view/material/list.ejs
  41. 13 0
      app/view/material/modal.ejs
  42. 1 1
      app/view/setting/fun.ejs
  43. 1 0
      app/view/stage/compare.ejs
  44. 6 0
      app/view/tender/detail_modal.ejs
  45. 1 5
      app/view/tender/sub_menu.ejs
  46. 4 0
      config/web.js
  47. 38 1
      sql/update.sql

+ 1 - 0
app/const/tender_info.js

@@ -109,6 +109,7 @@ const defaultInfo = {
             dgnQty: false,
             clQty: false,
         },
+        exMemo: true,
         thousandth: false,
         stage: {
             realComplete: false,

+ 1 - 1
app/controller/change_controller.js

@@ -1617,7 +1617,7 @@ module.exports = app => {
 
         async _getDefaultReviseInfoData(ctx, change, edit) {
             const [ledgerSpread, posSpread] = this._getSpreadSetting(change, edit);
-            const sjsRela = await this.ctx.service.project.getSjsRela(ctx.session.sessionProject.id);
+            const sjsRela = await this.ctx.service.project.getTenderSjsRela(ctx.session.sessionProject.id);
             this.ctx.helper.refreshSpreadShow(sjsRela.ledgerCol, [ledgerSpread, posSpread]);
             const [stdBills, stdChapters] = await this.ctx.service.valuation.getValuationStdList(
                 ctx.tender.data.valuation, ctx.tender.data.measure_type);

+ 1 - 1
app/controller/ledger_audit_controller.js

@@ -69,7 +69,7 @@ module.exports = app => {
                     measureType,
                 };
                 const [ledgerSpread, posSpread] = this._getSpreadSetting();
-                const sjsRela = await this.ctx.service.project.getSjsRela(ctx.session.sessionProject.id);
+                const sjsRela = await this.ctx.service.project.getTenderSjsRela(ctx.session.sessionProject.id);
                 this.ctx.helper.refreshSpreadShow(sjsRela.ledgerCol, [ledgerSpread, posSpread]);
 
                 const curAuditor = await ctx.service.ledgerAudit.getCurAuditor(ctx.tender.id, ctx.tender.data.ledger_times);

+ 3 - 3
app/controller/ledger_controller.js

@@ -141,7 +141,7 @@ module.exports = app => {
             try {
                 const tender = ctx.tender;
                 const [ledgerSpread, posSpread] = await this._getSpreadSetting();
-                const sjsRela = await this.ctx.service.project.getSjsRela(ctx.session.sessionProject.id);
+                const sjsRela = await this.ctx.service.project.getTenderSjsRela(ctx.session.sessionProject.id);
                 this.ctx.helper.refreshSpreadShow(sjsRela.ledgerCol, [ledgerSpread, posSpread]);
                 const times = tender.data.ledger_status === auditConst.status.checkNo ? tender.data.ledger_times - 1 : tender.data.ledger_times;
 
@@ -481,7 +481,7 @@ module.exports = app => {
          */
         async loadExplodeData(ctx) {
             try {
-                const sjsRela = await this.ctx.service.project.getSjsRela(ctx.session.sessionProject.id);
+                const sjsRela = await ctx.service.project.getTenderSjsRela(ctx.session.sessionProject.id);
                 const [ledgerColumn, posColumn] = this._getLedgerColumn(sjsRela);
                 const ledgerData = ctx.tender.ledgerReadOnly && ctx.tender.his
                     ? await ctx.helper.loadLedgerDataFromOss(ctx.tender.his.bills_file)
@@ -692,7 +692,7 @@ module.exports = app => {
          */
         async bwtz(ctx) {
             try {
-                const sjsRela = await this.ctx.service.project.getSjsRela(ctx.session.sessionProject.id);
+                const sjsRela = await ctx.service.project.getTenderSjsRela(ctx.session.sessionProject.id);
                 const renderData = {
                     tender: ctx.tender.data,
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.ledger.bwtz),

+ 73 - 33
app/controller/material_controller.js

@@ -395,6 +395,20 @@ module.exports = app => {
                 // if (!ctx.material.readOnly) {
                 const stage_list = await ctx.service.stage.getStageMsgByStageId(ctx.material.stage_id);
                 renderData.calcBase = await ctx.service.stage.getMaterialCalcBase(stage_list, ctx.tender.info);
+
+                renderData.materialStageData = ctx.material.is_stage_self ? await ctx.service.materialStage.getAllDataByCondition({ where: { tid: ctx.tender.id, mid: ctx.material.id } }) : [];
+                renderData.materialStageBillsData = ctx.material.is_stage_self ? await ctx.service.materialStageBills.getAllDataByCondition({ where: { tid: ctx.tender.id, mid: ctx.material.id } }) : [];
+                if (ctx.material.is_stage_self) {
+                    const calcBaseList = [];
+                    for (const ms of renderData.materialStageData) {
+                        const stage_info = await ctx.service.stage.getStageMsgByStageId(ms.sid);
+                        calcBaseList.push({
+                            ms_id: ms.id,
+                            calcBase: await ctx.service.stage.getMaterialCalcBase(stage_info, ctx.tender.info),
+                        });
+                    }
+                    renderData.calcBase = calcBaseList;
+                }
                 // }
 
                 // 取当前期截止上期含税金额
@@ -448,6 +462,9 @@ module.exports = app => {
                         });
                     }
                 }
+
+                renderData.materialStageData = ctx.material.is_stage_self ? await ctx.service.materialStage.getAllDataByCondition({ where: { tid: ctx.tender.id, mid: ctx.material.id } }) : [];
+                renderData.materialStageBillsData = ctx.material.is_stage_self ? await ctx.service.materialStageBills.getAllDataByCondition({ where: { tid: ctx.tender.id, mid: ctx.material.id } }) : [];
                 // 取所有已被调用的工料清单表
                 // renderData.materialListData = await ctx.service.materialList.getMaterialData(ctx.tender.id, ctx.material.id);
                 // renderData.materialNotJoinListData = await ctx.service.materialListNotjoin.getAllDataByCondition({ where: { tid: ctx.tender.id, mid: ctx.material.id } });
@@ -473,7 +490,7 @@ module.exports = app => {
          */
         async loadListsData(ctx) {
             try {
-                // const data = JSON.parse(ctx.request.body.data);
+                const data = JSON.parse(ctx.request.body.data);
                 // const filter = data.filter.split(';');
                 const responseData = { err: 0, msg: '', data: {} };
                 // 取所有已被调用的工料清单表
@@ -484,8 +501,21 @@ module.exports = app => {
                 responseData.data.ledger = await ctx.service.ledger.getData(ctx.tender.id);
                 responseData.data.pos = await ctx.service.pos.getPosData({ tid: ctx.tender.id });
                 // 获取所选期数据并合并相加同类清单项
-                responseData.data.curLedgerData = await ctx.service.stageBills.getStagesData(ctx.tender.id, ctx.material.stage_id);
-                responseData.data.curPosData = await ctx.service.stagePos.getStagesData(ctx.tender.id, ctx.material.stage_id, 'list');
+                if (ctx.material.is_stage_self && data.sid) {
+                    responseData.data.curLedgerData = await ctx.service.stageBills.getStagesData(ctx.tender.id, data.sid.toString());
+                    responseData.data.curPosData = await ctx.service.stagePos.getStagesData(ctx.tender.id, data.sid.toString(), 'list');
+                    const ledgerListData = [];
+                    const posListData = [];
+                    for (const s of ctx.material.stage_id.split(',')) {
+                        ledgerListData.push(await ctx.service.stageBills.getStagesData(ctx.tender.id, s.toString()));
+                        posListData.push(await ctx.service.stagePos.getStagesData(ctx.tender.id, s.toString(), 'list'));
+                    }
+                    responseData.data.ledgerListData = ledgerListData;
+                    responseData.data.posListData = posListData;
+                } else {
+                    responseData.data.curLedgerData = await ctx.service.stageBills.getStagesData(ctx.tender.id, ctx.material.stage_id);
+                    responseData.data.curPosData = await ctx.service.stagePos.getStagesData(ctx.tender.id, ctx.material.stage_id, 'list');
+                }
                 // 获取清单设置已选清单
                 const materialChecklistData = await ctx.service.materialChecklist.getAllDataByCondition({ where: { tid: ctx.tender.id } });
                 responseData.data.materialChecklistData = materialChecklistData.sort(function(a, b) {
@@ -551,9 +581,20 @@ module.exports = app => {
                 responseData.data.ledger = await ctx.service.ledger.getData(ctx.tender.id);
                 responseData.data.pos = await ctx.service.pos.getPosData({ tid: ctx.tender.id });
                 // 获取所选期数据并合并相加同类清单项
-                responseData.data.curLedgerData = await ctx.service.stageBills.getStagesData(ctx.tender.id, data.stage_id.join(','));
-                responseData.data.curPosData = await ctx.service.stagePos.getStagesData(ctx.tender.id, data.stage_id.join(','), 'list');
-
+                if (data.is_stage_self) {
+                    const stage_id_list = data.stage_id;
+                    const curLedgerData = [];
+                    const curPosData = [];
+                    for (const sid of stage_id_list) {
+                        curLedgerData.push({ sid, ledgerData: await ctx.service.stageBills.getLastestStageData2(ctx.tender.id, sid) });
+                        curPosData.push({ sid, posData: await ctx.service.stagePos.getLastestStageData2(ctx.tender.id, sid) });
+                    }
+                    responseData.data.curLedgerData = curLedgerData;
+                    responseData.data.curPosData = curPosData;
+                } else {
+                    responseData.data.curLedgerData = await ctx.service.stageBills.getStagesData(ctx.tender.id, data.stage_id.join(','));
+                    responseData.data.curPosData = await ctx.service.stagePos.getStagesData(ctx.tender.id, data.stage_id.join(','), 'list');
+                }
                 // 获取gclidlist值
                 const lastMaterial = await ctx.service.material.getLastestCompleteMaterial(ctx.tender.id);
                 // responseData.data.materialListData = await ctx.service.materialList.getMaterialData(ctx.tender.id, lastMaterial.id);
@@ -697,16 +738,20 @@ module.exports = app => {
                 }
                 const newDecimalUp = parseInt(data.up);
                 const newDecimalTp = parseInt(data.tp);
+                const newDecimalQty = parseInt(data.qty);
                 if (ctx.app._.isNaN(newDecimalUp) || newDecimalUp > 6 || newDecimalUp < 0) {
                     throw '单价小数位数设置不能大于6或小于0';
                 }
                 if (ctx.app._.isNaN(newDecimalTp) || newDecimalTp > 6 || newDecimalTp < 0) {
                     throw '金额小数位数设置不能大于6或小于0';
                 }
-                if (ctx.material.decimal.up === newDecimalUp && ctx.material.decimal.tp === newDecimalTp) {
+                if (ctx.app._.isNaN(newDecimalQty) || newDecimalQty > 6 || newDecimalQty < 0) {
+                    throw '数量小数位数设置不能大于6或小于0';
+                }
+                if (ctx.material.decimal.up === newDecimalUp && ctx.material.decimal.tp === newDecimalTp && ctx.material.decimal.qty === newDecimalQty) {
                     throw '小数位数设置未发生变化';
                 }
-                const result = await ctx.service.material.saveDecimal(newDecimalUp, newDecimalTp);
+                const result = await ctx.service.material.saveDecimal(newDecimalUp, newDecimalTp, newDecimalQty);
                 if (!result) {
                     throw '小数位数设置失败';
                 }
@@ -738,10 +783,10 @@ module.exports = app => {
                 }
                 switch (data.type) {
                     case 'add':
-                        responseData.data = await ctx.service.materialList.add(data.postData);
+                        responseData.data = await ctx.service.materialList.add(data.postData, data.ms_id);
                         break;
                     case 'del':
-                        await ctx.service.materialList.del(data.id, data.mb_id);
+                        await ctx.service.materialList.del(data.id, data.mb_id, data.ms_id);
                         break;
                     case 'update':
                         if (data.updateData.quantity === '' || data.updateData.quantity === null) {
@@ -751,25 +796,25 @@ module.exports = app => {
                         if (isNaN(data.updateData.quantity)) {
                             throw '不能输入其它非数字类型字符';
                         }
-                        await ctx.service.materialList.save(data.updateData);
+                        await ctx.service.materialList.save(data.updateData, data.ms_id);
                         break;
                     case 'useOther':
                         responseData.data = await ctx.service.materialList.addOther(data.postData);
                         break;
                     case 'join':
-                        await ctx.service.materialListNotjoin.del(data.select.id);
+                        await ctx.service.materialListNotjoin.del(data.select.id, data.ms_id);
                         break;
                     case 'notjoin':
-                        responseData.data = await ctx.service.materialListNotjoin.add(data.select);
+                        responseData.data = await ctx.service.materialListNotjoin.add(data.select, data.ms_id);
                         break;
                     case 'self':
                         responseData.data = await ctx.service.materialListSelf.add(data.select);
                         break;
                     case 'noself':
-                        responseData.data = await ctx.service.materialListSelf.del(data.select.id);
+                        responseData.data = await ctx.service.materialListSelf.del(data.select.id, data.ms_id);
                         break;
                     case 'paste':
-                        await ctx.service.materialList.saveDatas(data.updateData);
+                        await ctx.service.materialList.saveDatas(data.updateData, data.ms_id);
                         // 取所有工料表
                         responseData.data = await ctx.service.materialList.getMaterialData(ctx.tender.id, ctx.material.id);
                         break;
@@ -777,7 +822,7 @@ module.exports = app => {
                         responseData.data = await ctx.service.materialList.adds(data.postData);
                         break;
                     case 'dels':
-                        responseData.data = await ctx.service.materialList.dels(data.postData);
+                        responseData.data = await ctx.service.materialList.dels(data.postData, false, false, data.ms_id);
                         break;
                     case 'updates':
                         if (data.updateData.quantity === '' || data.updateData.quantity === null) {
@@ -787,10 +832,10 @@ module.exports = app => {
                         if (isNaN(data.updateData.quantity)) {
                             throw '不能输入其它非数字类型字符';
                         }
-                        responseData.data = await ctx.service.materialList.saves(data.updateData);
+                        responseData.data = await ctx.service.materialList.saves(data.updateData, false, data.ms_id);
                         break;
                     case 'pastes':
-                        responseData.data = await ctx.service.materialList.savePastes(data.updateData);
+                        responseData.data = await ctx.service.materialList.savePastes(data.updateData, false, data.ms_id);
                         // 取所有工料表
                         break;
                     default: throw '参数有误';
@@ -821,7 +866,7 @@ module.exports = app => {
                         responseData.data = await ctx.service.materialBills.add();
                         break;
                     case 'del':
-                        responseData.data.m_tp = await ctx.service.materialBills.del(data.id);
+                        responseData.data = await ctx.service.materialBills.del(data.id);
                         break;
                     case 'changeOrder':
                         await ctx.service.materialBills.changeOrder(data.id1, data.id2);
@@ -842,7 +887,7 @@ module.exports = app => {
                         if (billData.length > 1 || (billData.length > 0 && billData[0].id !== data.updateData.id)) {
                             throw '该编号已存在,请重新输入。';
                         }
-                        responseData.data.m_tp = await ctx.service.materialBills.save(data.updateData);
+                        responseData.data = await ctx.service.materialBills.save(data.updateData, data.ms_id);
                         break;
                     case 'rate':
                         // 判断数量是否为数字
@@ -855,18 +900,10 @@ module.exports = app => {
                         await ctx.service.material.changeRate(data.rate);
                         break;
                     case 'expr':
-                        const materialCalculator = new MaterialCalculator(ctx, ctx.material.stage_id, ctx.tender.info);
-                        const quantity = await materialCalculator.calculateExpr(data.expr);
-                        // 更新quantity值并重新返回计算本期金额,截止本期金额
-                        const updateData = {
-                            id: data.id,
-                            quantity: quantity !== 0 ? ctx.helper.round(quantity, ctx.material.decimal.qty) : null,
-                            expr: data.expr,
-                        };
-                        responseData.data = await ctx.service.materialBills.updateFYQuantity(updateData);
+                        responseData.data = await ctx.service.materialBills.updateFYQuantity(data);
                         break;
                     case 'paste':
-                        responseData.data.m_tp = await ctx.service.materialBills.saveDatas(data.updateData);
+                        responseData.data = await ctx.service.materialBills.saveDatas(data.updateData, data.ms_id);
                         // 根据期判断需要获取的工料信息值
                         // const searchsql = { tid: ctx.tender.id };
                         // if (ctx.material.highOrder !== ctx.material.order) {
@@ -1427,6 +1464,9 @@ module.exports = app => {
                         });
                     }
                 }
+
+                renderData.materialStageData = ctx.material.is_stage_self ? await ctx.service.materialStage.getAllDataByCondition({ where: { tid: ctx.tender.id, mid: ctx.material.id } }) : [];
+                renderData.materialStageBillsData = ctx.material.is_stage_self ? await ctx.service.materialStageBills.getAllDataByCondition({ where: { tid: ctx.tender.id, mid: ctx.material.id } }) : [];
                 // 取所有已被调用的工料清单表
                 // renderData.materialListData = await ctx.service.materialList.getMaterialData(ctx.tender.id, ctx.material.id);
                 // renderData.materialNotJoinListData = await ctx.service.materialListNotjoin.getAllDataByCondition({ where: { tid: ctx.tender.id, mid: ctx.material.id } });
@@ -1471,7 +1511,7 @@ module.exports = app => {
                         responseData.data = await ctx.service.materialList.adds(data.postData, data.checklist);
                         break;
                     case 'dels':
-                        responseData.data = await ctx.service.materialList.dels(data.postData, data.checklist, true);
+                        responseData.data = await ctx.service.materialList.dels(data.postData, data.checklist, true, data.ms_id);
                         break;
                     case 'updates':
                         if (data.updateData.quantity === '' || data.updateData.quantity === null) {
@@ -1481,10 +1521,10 @@ module.exports = app => {
                         if (isNaN(data.updateData.quantity)) {
                             throw '不能输入其它非数字类型字符';
                         }
-                        responseData.data = await ctx.service.materialList.saves(data.updateData, true);
+                        responseData.data = await ctx.service.materialList.saves(data.updateData, true, data.ms_id);
                         break;
                     case 'pastes':
-                        responseData.data = await ctx.service.materialList.savePastes(data.updateData, true);
+                        responseData.data = await ctx.service.materialList.savePastes(data.updateData, true, data.ms_id);
                         // 取所有工料表
                         break;
                     case 'resetChecklist':

+ 2 - 2
app/controller/revise_controller.js

@@ -290,7 +290,7 @@ module.exports = app => {
 
         async _getDefaultReviseInfoData(ctx, revise) {
             const [ledgerSpread, posSpread] = this._getSpreadSetting(revise);
-            const sjsRela = await this.ctx.service.project.getSjsRela(ctx.session.sessionProject.id);
+            const sjsRela = await ctx.service.project.getTenderSjsRela(ctx.session.sessionProject.id);
             this.ctx.helper.refreshSpreadShow(sjsRela.ledgerCol, [ledgerSpread, posSpread]);
             const [stdBills, stdChapters] = await this.ctx.service.valuation.getValuationStdList(
                 ctx.tender.data.valuation, ctx.tender.data.measure_type);
@@ -487,7 +487,7 @@ module.exports = app => {
                 const revise = ctx.revise;
 
                 const [ledgerSpread, posSpread] = this._getSpreadSetting(revise);
-                const sjsRela = await this.ctx.service.project.getSjsRela(ctx.session.sessionProject.id);
+                const sjsRela = await ctx.service.project.getTenderSjsRela(ctx.session.sessionProject.id);
                 this.ctx.helper.refreshSpreadShow(sjsRela.ledgerCol, [ledgerSpread, posSpread]);
                 ledgerSpread.readOnly = true;
                 posSpread.readOnly = true;

+ 9 - 7
app/controller/stage_controller.js

@@ -183,7 +183,7 @@ module.exports = app => {
                 const projectFunInfo = await this.ctx.service.project.getFunRela(ctx.session.sessionProject.id);
                 renderData.minusNoValue = projectFunInfo.minusNoValue && ctx.tender.info.fun_rela.stage_change.minusNoValue;
                 [renderData.ledgerSpread, renderData.posSpread] = this._getSpreadSetting({minusNoValue: renderData.minusNoValue});
-                const sjsRela = await this.ctx.service.project.getSjsRela(ctx.session.sessionProject.id);
+                const sjsRela = await this.ctx.service.project.getTenderSjsRela(ctx.session.sessionProject.id);
                 this.ctx.helper.refreshSpreadShow(sjsRela.ledgerCol, [renderData.ledgerSpread, renderData.posSpread]);
                 renderData.changeConst = changeConst;
                 renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.index);
@@ -256,10 +256,12 @@ module.exports = app => {
             if (this.ctx.session.sessionProject.dagl) this.posExtraColumn.push('dagl_status', 'dagl_url', 'dagl_limit');
 
             if (!sjsRela) return;
-            for (const field of sjsRela.ledgerCol) {
-                if (field.show) {
-                    this.ledgerColumn.push(field.field);
-                    this.posColumn.push(field.field);
+            if (sjsRela) {
+                for (const field of sjsRela.ledgerCol) {
+                    if (field.show) {
+                        this.ledgerColumn.push(field.field);
+                        this.posColumn.push(field.field);
+                    }
                 }
             }
         }
@@ -340,7 +342,7 @@ module.exports = app => {
                 const filter = data.filter.split(';');
                 const responseData = { err: 0, msg: '', data: {}, hpack: [] };
                 const hpack = true;
-                const sjsRela = await this.ctx.service.project.getSjsRela(ctx.session.sessionProject.id);
+                const sjsRela = await this.ctx.service.project.getTenderSjsRela(ctx.session.sessionProject.id);
                 this._getLedgerColumn(sjsRela);
                 for (const f of filter) {
                     switch (f) {
@@ -1463,7 +1465,7 @@ module.exports = app => {
                 await this._getStageAuditViewData(ctx);
                 const renderData = await this._getDefaultRenderData(ctx);
                 renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.bwtz);
-                const sjsRela = await this.ctx.service.project.getSjsRela(ctx.session.sessionProject.id);
+                const sjsRela = await this.ctx.service.project.getTenderSjsRela(ctx.session.sessionProject.id);
                 renderData.ex_memo1 = sjsRela.ledgerCol.find(x => { return x.field === 'ex_memo1'; });
                 renderData.ex_memo2 = sjsRela.ledgerCol.find(x => { return x.field === 'ex_memo2'; });
                 renderData.ex_memo3 = sjsRela.ledgerCol.find(x => { return x.field === 'ex_memo3'; });

+ 2 - 2
app/lib/spread_setting.js

@@ -66,7 +66,7 @@ const getLedgerSpreadSetting = async function(ctx, tid, readOnly) {
     if (tender.data.measure_type === measureType.tz.value) removeFieldCols(ledger, spreadConst.filterCols.tzWithoutCols);
     if (!tender.info.display.ledger.dgnQty) removeFieldCols(ledger, spreadConst.filterCols.dgnCols);
 
-    const sjsRela = await ctx.service.project.getSjsRela(ctx.session.sessionProject.id);
+    const sjsRela = await ctx.service.project.getTenderSjsRela(ctx.session.sessionProject.id);
     refreshSpreadShow(sjsRela.ledgerCol, [ledger, pos]);
 
     return [ledger, pos];
@@ -101,7 +101,7 @@ const getStageSpreadSetting = async function (ctx, tid, readOnly, funInfo) {
     ledger.readOnly = readOnly;
     pos.readOnly = readOnly;
 
-    const sjsRela = await ctx.service.project.getSjsRela(ctx.session.sessionProject.id);
+    const sjsRela = await ctx.service.project.getTenderSjsRela(ctx.session.sessionProject.id);
     refreshSpreadShow(sjsRela.ledgerCol, [ledger, pos]);
 
     return [ledger, pos];

+ 7 - 4
app/public/js/ledger.js

@@ -1070,16 +1070,19 @@ $(document).ready(function() {
     ledgerSpread.bind(spreadNS.Events.SelectionChanged, treeOperationObj.selectionChanged);
     ledgerSpread.bind(spreadNS.Events.TopRowChanged, treeOperationObj.topRowChanged);
 
+    console.log(ledgerSpread.options);
+    ledgerSpread.bind(spreadNS.Events.ClipboardChanging, function (e, info) {
+        const copyText = SpreadJsObj.getFilterCopyText(info.sheet);
+        SpreadJsObj.Clipboard.setCopyData(copyText);
+        info.copyData.text = copyText;
+        info.copyData.html = SpreadJsObj.getFilterCopyHTML(info.sheet);
+    });
     if (!ledgerSpreadSetting.readOnly) {
         ledgerSpread.bind(spreadNS.Events.SelectionChanged, function (e, info) {
             treeOperationObj.refreshOperationValid(info.sheet, info.newSelections);
         });
         ledgerSpread.bind(spreadNS.Events.EditEnded, treeOperationObj.editEnded);
         SpreadJsObj.addDeleteBind(ledgerSpread, treeOperationObj.deletePress);
-        ledgerSpread.bind(spreadNS.Events.ClipboardChanging, function (e, info) {
-            const copyText = SpreadJsObj.getFilterCopyText(info.sheet);
-            SpreadJsObj.Clipboard.setCopyData(copyText);
-        });
         ledgerSpread.bind(spreadNS.Events.ClipboardPasting, treeOperationObj.clipboardPasting);
         ledgerSpread.bind(spreadNS.Events.EditStarting, treeOperationObj.editStarting);
         SpreadJsObj.addCutEvents(ledgerSpread, treeOperationObj.cut);

+ 179 - 42
app/public/js/material.js

@@ -84,6 +84,21 @@ function resetTpTable() {
         $('#rate_set').find('td').eq(1).text(bqhs !== 0 ? bqhs : '');
         $('#rate_set').find('td').eq(2).text(jzbqhs !== 0 ? jzbqhs : '');
     }
+
+    if (isStageSelf) {
+        let html = '';
+        for (const ms of materialStageData) {
+            const taxHtml = materialTax ? '                                        <td class="text-center">' + ms.m_tax_tp + '</td>\n' : '';
+            html += '<tr><td>第' + ms.order + '期</td><td class="text-center">' + ms.m_tp + '</td>\n' +
+                taxHtml +
+                '                                </tr>';
+        }
+        const allTaxHtml = materialTax ? '                                        <td class="text-center">' + m_tax_tp + '</td>\n' : '';
+        html += '<tr><td>合计</td><td class="text-center">' + m_tp + '</td>\n' +
+            allTaxHtml +
+            '                                </tr>';
+        $('#materialStageTable').html(html);
+    }
 }
 function getPasteHint (str, row = '') {
     let returnObj = str;
@@ -124,7 +139,8 @@ $(document).ready(() => {
         materialSpreadSettingCols.push({title: '税率(%)', colSpan: '1', rowSpan: '2', field: 'm_tax', hAlign: 2, width: 50, type: 'Number', readOnly: 'readOnly.remark'});
     }
     materialSpreadSettingCols = _.concat(materialSpreadSettingCols, [
-        {title: '本期应耗数量', colSpan: '1', rowSpan: '2', field: 'quantity', hAlign: 2, width: 90, type: 'Number', readOnly: true},
+        {title: '上涨 幅度(%)', colSpan: '1', rowSpan: '2', field: 'm_up_risk', hAlign: 2, width: 50, type: 'Number', readOnly: 'readOnly.isEdit'},
+        {title: '下跌 幅度(%)', colSpan: '1', rowSpan: '2', field: 'm_down_risk', hAlign: 2, width: 50, type: 'Number', readOnly: 'readOnly.isEdit'},
         {title: '基准价', colSpan: '1', rowSpan: '2', field: 'basic_price', hAlign: 2, width: 50, type: 'Number', readOnly: 'readOnly.isEdit'},
         {title: '基准时间', colSpan: '1', rowSpan: '2', field: 'basic_times', hAlign: 0, width: 70, formatter: '@', readOnly: 'readOnly.isEdit'},
         {title: '本期信息价|单价', colSpan: '3|1', rowSpan: '1|1', field: 'msg_tp', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.msg_tp'},
@@ -133,9 +149,8 @@ $(document).ready(() => {
     );
     if (materialTax) {
         materialSpreadSettingCols = _.concat(materialSpreadSettingCols, [
-            {title: '本期材料调差|上涨 幅度(%)', colSpan: '5|1', rowSpan: '1|1', field: 'm_up_risk', hAlign: 2, width: 50, type: 'Number', readOnly: 'readOnly.isEdit'},
-            {title: '|下跌 幅度(%)', colSpan: '|1', rowSpan: '|1', field: 'm_down_risk', hAlign: 2, width: 50, type: 'Number', readOnly: 'readOnly.isEdit'},
-            {title: '|有效价差', colSpan: '|1', rowSpan: '|1', field: 'm_spread', hAlign: 2, width: 60, type: 'Number', readOnly: true, getValue: 'getValue.m_spread'},
+            {title: '本期材料调差|有效价差', colSpan: '4|1', rowSpan: '1|1', field: 'm_spread', hAlign: 2, width: 60, type: 'Number', readOnly: true, getValue: 'getValue.m_spread'},
+            {title: '|本期应耗数量', colSpan: '|1', rowSpan: '|1', field: 'quantity', hAlign: 2, width: 90, type: 'Number', readOnly: true},
             {title: '|调差金额', colSpan: '|1', rowSpan: '|1', field: 'm_tp', hAlign: 2, width: 100, type: 'Number', readOnly: true, getValue: 'getValue.m_tp'},
             {title: '|调差金额(材料税)', colSpan: '|1', rowSpan: '|1', field: 'm_tax_tp', hAlign: 2, width: 100, type: 'Number', readOnly: true, getValue: 'getValue.m_tax_tp'},
             {title: '截止上期|调差金额', colSpan: '2|1', rowSpan: '1|1', field: 'pre_tp', hAlign: 2, width: 100, type: 'Number', readOnly: true},
@@ -145,9 +160,8 @@ $(document).ready(() => {
         ])
     } else {
         materialSpreadSettingCols = _.concat(materialSpreadSettingCols, [
-            {title: '本期材料调差|上涨 幅度(%)', colSpan: '4|1', rowSpan: '1|1', field: 'm_up_risk', hAlign: 2, width: 50, type: 'Number', readOnly: 'readOnly.isEdit'},
-            {title: '|下跌 幅度(%)', colSpan: '|1', rowSpan: '|1', field: 'm_down_risk', hAlign: 2, width: 50, type: 'Number', readOnly: 'readOnly.isEdit'},
-            {title: '|有效价差', colSpan: '|1', rowSpan: '|1', field: 'm_spread', hAlign: 2, width: 80, type: 'Number', readOnly: true, getValue: 'getValue.m_spread'},
+            {title: '本期材料调差|有效价差', colSpan: '3|1', rowSpan: '1|1', field: 'm_spread', hAlign: 2, width: 60, type: 'Number', readOnly: true, getValue: 'getValue.m_spread'},
+            {title: '|本期应耗数量', colSpan: '|1', rowSpan: '|1', field: 'quantity', hAlign: 2, width: 90, type: 'Number', readOnly: true},
             {title: '|调差金额', colSpan: '|1', rowSpan: '|1', field: 'm_tp', hAlign: 2, width: 100, type: 'Number', readOnly: true, getValue: 'getValue.m_tp'},
             {title: '截止上期|调差金额', colSpan: '1|1', rowSpan: '1|1', field: 'pre_tp', hAlign: 2, width: 100, type: 'Number', readOnly: true},
             {title: '备注', colSpan: '1', rowSpan: '2', field: 'remark', hAlign: 0, width: 50, formatter: '@', readOnly: 'readOnly.remark'},
@@ -239,13 +253,69 @@ $(document).ready(() => {
             }
         },
     };
-    SpreadJsObj.initSpreadSettingEvents(materialSpreadSetting, materialCol);
-    SpreadJsObj.initSheet(materialSpread.getActiveSheet(), materialSpreadSetting);
-    SpreadJsObj.loadSheetData(materialSpread.getActiveSheet(), SpreadJsObj.DataType.Data, materialBillsData);
+
+    const needUpdateArray = ['quantity', 'msg_tp', 'msg_times', 'msg_spread', 'm_spread', 'm_tp', 'm_tax_tp', 'is_summary', 'remark'];
 
     const materialSpreadObj = {
+        getMaterialBillsData: function () {
+            if (isStageSelf) {
+                // 当前选中nav id
+                const ms_id = $('#myTab').find('.active').data('msid');
+                const msbList = _.filter(materialStageBillsData, { ms_id });
+                for (const mb of materialBillsData) {
+                    mb.ms_id = ms_id;
+                    const msbInfo = _.find(msbList, { mb_id: mb.mb_id ? mb.mb_id : mb.id });
+                    if (msbInfo) {
+                        for (const nu of needUpdateArray) {
+                            mb[nu] = msbInfo[nu];
+                        }
+                    }
+                }
+            }
+            return materialBillsData;
+        },
+        updateOneMaterialBill: function (data) {
+            const ms_id = $('#myTab').find('.active').data('msid');
+            const msbInfo = _.find(materialStageBillsData, { ms_id, mb_id: data.id });
+            console.log(msbInfo);
+            data.ms_id = ms_id;
+            for (const nu of needUpdateArray) {
+                data[nu] = msbInfo[nu];
+            }
+            return data;
+        },
+        updateMaterialData: function (datas) {
+            if (datas.stageData && datas.stageData.length > 0) {
+                if (datas.stageData.length === materialStageData.length) {
+                    // 全体替换
+                    materialStageData = datas.stageData;
+                } else {
+                    // 替换对应的stage数据
+                    for (const s of datas.stageData) {
+                        const index = _.findIndex(materialStageData, { id: s.id });
+                        materialStageData.splice(index, 1, s);
+                    }
+                }
+            }
+            if (datas.pushStageBillsData && datas.pushStageBillsData.length > 0) {
+                materialStageBillsData = _.concat(materialStageBillsData, datas.pushStageBillsData);
+            }
+            if (datas.stageBillsData && datas.stageBillsData.length > 0) {
+                if (datas.stageBillsData.length === materialStageBillsData.length) {
+                    // 全体替换
+                    materialStageBillsData = datas.stageBillsData;
+                } else {
+                    // 替换对应的stage数据
+                    for (const s of datas.stageBillsData) {
+                        const index = _.findIndex(materialStageBillsData, { id: s.id });
+                        materialStageBillsData.splice(index, 1, s);
+                    }
+                }
+            }
+        },
         materialSheetReset: function () {
             let newMaterialBillsData = materialBillsData;
+            console.log(materialBillsData);
             if($('#bills0_list').is(':checked')) {
                 newMaterialBillsData = _.filter(materialBillsData, function (item) {
                     return item.quantity !== null && item.quantity !== 0;
@@ -273,7 +343,11 @@ $(document).ready(() => {
             const sheet = materialSpread.getActiveSheet();
             postData(window.location.pathname + '/save', {type: 'add'}, function (result) {
                 if (result) {
-                    materialBillsData.push(result);
+                    materialBillsData.push(result.info);
+                    if (isStageSelf) {
+                        materialSpreadObj.updateMaterialData(result);
+                        materialSpreadObj.getMaterialBillsData();
+                    }
                     // sheet.addRows(materialBillsData.length - 1, 1);
                     // SpreadJsObj.reLoadRowData(sheet, materialBillsData.length - 1);
                     let newMaterialBillsData = materialBillsData;
@@ -312,7 +386,7 @@ $(document).ready(() => {
                 if (materialTax) {
                     m_tax_tp = result.m_tax_tp;
                 }
-                resetTpTable();
+
                 const index = materialBillsData.indexOf(select);
                 let newMaterialBillsData = materialBillsData;
                 let newIndex = index;
@@ -324,6 +398,11 @@ $(document).ready(() => {
                 }
                 materialBillsData.splice(index, 1);
                 sheet.deleteRows(newIndex, 1);
+                if (isStageSelf) {
+                    materialSpreadObj.updateMaterialData(result);
+                    materialSpreadObj.getMaterialBillsData();
+                }
+                resetTpTable();
                 // SpreadJsObj.reLoadSheetData(materialSpread.getActiveSheet());
                 const sel = sheet.getSelections();
                 sheet.setSelection(newIndex > 0 ? newIndex - 1 : 0, sel.length > 0 ? sel[0].col : 0, 1, 1);
@@ -414,6 +493,7 @@ $(document).ready(() => {
             materialSpreadObj.refreshActn(sel.rowCount);
             const data = SpreadJsObj.getSelectObject(info.sheet);
             materialSpreadObj.setReadOnly(true);
+            console.log(data);
         },
         editEnded: function (e, info) {
             if (info.sheet.zh_setting) {
@@ -487,11 +567,14 @@ $(document).ready(() => {
                 // console.log(select);
 
                 // 更新至服务器
-                postData(window.location.pathname + '/save', { type:'update', updateData: select }, function (result) {
+                postData(window.location.pathname + '/save', { type:'update', updateData: select, ms_id: $('#myTab').find('.active').data('msid') || null }, function (result) {
                     m_tp = result.m_tp;
                     if (materialTax) {
                         m_tax_tp = result.m_tax_tp;
                     }
+                    if (isStageSelf) {
+                        materialSpreadObj.updateMaterialData(result);
+                    }
                     resetTpTable();
                     SpreadJsObj.reLoadRowData(info.sheet, info.row);
                     // 判断如果是更改了编号,名称,单位,月信息价需要跟着改变值
@@ -520,11 +603,14 @@ $(document).ready(() => {
                     select.is_summary = info.sheet.getValue(info.row, info.col) ? 1 : 0;
                     delete select.waitingLoading;
                     // 更新至服务器
-                    postData(window.location.pathname + '/save', { type:'update', updateData: select }, function (result) {
+                    postData(window.location.pathname + '/save', { type:'update', updateData: select, ms_id: $('#myTab').find('.active').data('msid') || null }, function (result) {
                         m_tp = result.m_tp;
                         if (materialTax) {
                             m_tax_tp = result.m_tax_tp;
                         }
+                        if (isStageSelf) {
+                            materialSpreadObj.updateMaterialData(result);
+                        }
                         resetTpTable();
                         SpreadJsObj.reLoadRowData(info.sheet, info.row);
                     }, function () {
@@ -651,8 +737,16 @@ $(document).ready(() => {
             }
             // console.log(data);
             // 更新至服务器
-            postData(window.location.pathname + '/save', { type:'paste', updateData: data }, function (result) {
+            postData(window.location.pathname + '/save', { type:'paste', updateData: data, ms_id: $('#myTab').find('.active').data('msid') || null }, function (result) {
                 materialBillsData = result.info;
+                m_tp = result.m_tp;
+                if (materialTax) {
+                    m_tax_tp = result.m_tax_tp;
+                }
+                if (isStageSelf) {
+                    materialSpreadObj.updateMaterialData(result);
+                    materialSpreadObj.getMaterialBillsData();
+                }
                 // SpreadJsObj.reLoadSheetData(materialSpread.getActiveSheet());
                 materialSpreadObj.materialSheetReset();
                 // SpreadJsObj.loadSheetData(materialSpread.getActiveSheet(), SpreadJsObj.DataType.Data, materialBillsData);
@@ -671,10 +765,6 @@ $(document).ready(() => {
                     monthFunGather.monthsListSet();
                     // SpreadJsObj.reLoadSheetData(materialMonthSpread.getActiveSheet());
                 }
-                m_tp = result.m_tp;
-                if (materialTax) {
-                    m_tax_tp = result.m_tax_tp;
-                }
                 resetTpTable();
                 // materialSpreadObj.refreshActn();
             }, function () {
@@ -895,23 +985,23 @@ $(document).ready(() => {
             //         toastr.warning('请勿同时删除多行或多列数据');
             //     }
             //     console.log(sel, select, col);
-                // if (orgValue === null || col.field === 'type' || col.field === 'is_summary') {
-                //     return;
-                // }
-                // select[col.field] = null;
-                // select.calc_num = materialExponentCol.getValue.calc_num(select);
-                // console.log(select);
-                // 更新至服务器
-                // postData(window.location.pathname + '/save', { type:'update', updateData: select }, function (result) {
-                //     ex_tp = result.ex_tp;
-                //     ex_expr = result.ex_expr;
-                //     resetExTpTable();
-                //     SpreadJsObj.reLoadRowData(sheet, sel.row);
-                //     materialExponentData.splice(sel.row, 1, select);
-                // }, function () {
-                //     select[col.field] = orgValue;
-                //     SpreadJsObj.reLoadRowData(sheet, sel.row);
-                // });
+            // if (orgValue === null || col.field === 'type' || col.field === 'is_summary') {
+            //     return;
+            // }
+            // select[col.field] = null;
+            // select.calc_num = materialExponentCol.getValue.calc_num(select);
+            // console.log(select);
+            // 更新至服务器
+            // postData(window.location.pathname + '/save', { type:'update', updateData: select }, function (result) {
+            //     ex_tp = result.ex_tp;
+            //     ex_expr = result.ex_expr;
+            //     resetExTpTable();
+            //     SpreadJsObj.reLoadRowData(sheet, sel.row);
+            //     materialExponentData.splice(sel.row, 1, select);
+            // }, function () {
+            //     select[col.field] = orgValue;
+            //     SpreadJsObj.reLoadRowData(sheet, sel.row);
+            // });
             // }
             return;
         },
@@ -1016,9 +1106,32 @@ $(document).ready(() => {
         },
     };
 
+    SpreadJsObj.initSpreadSettingEvents(materialSpreadSetting, materialCol);
+    SpreadJsObj.initSheet(materialSpread.getActiveSheet(), materialSpreadSetting);
+    materialSpreadObj.getMaterialBillsData();
+    SpreadJsObj.loadSheetData(materialSpread.getActiveSheet(), SpreadJsObj.DataType.Data, materialBillsData);
+
     materialMonthSpread.bind(spreadNS.Events.ClipboardPasted, materialMonthSpreadObj.clipboardPasted);
     SpreadJsObj.addDeleteBind(materialMonthSpread, materialMonthSpreadObj.deletePress);
 
+    // 期切换
+    $('#myTab a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
+        e.preventDefault();
+        showWaitingView();
+        setTimeout(function () {
+            materialSpreadObj.getMaterialBillsData();
+            SpreadJsObj.reLoadSheetData(materialSpread.getActiveSheet());
+            // 消耗量表格更新
+            let html = '';
+            calcBase = _.find(calcBaseList, { ms_id: $('#myTab').find('.active').data('msid') }).calcBase;
+            for (let iBase = 0; iBase < calcBase.length; iBase++) {
+                html += '<tr><td>' + calcBase[iBase].name + '</td><td>' + calcBase[iBase].code + '</td><td>' + calcBase[iBase].value + '</td></tr>';
+            }
+            $('#calcBase').html(html);
+            closeWaitingView();
+        }, 1000);
+    });
+
     if (!readOnly) {
         $('#add').click(materialSpreadObj.add);
         $('#del').click(materialSpreadObj.del);
@@ -1274,11 +1387,17 @@ $(document).ready(() => {
                 if (materialTax) {
                     m_tax_tp = result.m_tax_tp;
                 }
-                resetTpTable();
+
                 const sheet = materialSpread.getActiveSheet();
                 const select = SpreadJsObj.getSelectObject(sheet);
                 const index = materialBillsData.indexOf(select);
+                console.log(select, index, result.info);
                 let newIndex = index;
+                if (isStageSelf) {
+                    materialSpreadObj.updateMaterialData(result);
+                    result.info = materialSpreadObj.updateOneMaterialBill(result.info);
+                    console.log(result.info);
+                }
                 if($('#bills0_list').is(':checked')) {
                     const newMaterialBillsData = _.filter(materialBillsData, function (item) {
                         return item.quantity !== null && item.quantity !== 0;
@@ -1289,6 +1408,7 @@ $(document).ready(() => {
                 }
                 materialBillsData.splice(index, 1, result.info);
                 SpreadJsObj.reLoadRowData(sheet, newIndex);
+                resetTpTable();
                 $('#bcyy').modal('hide');
             });
         });
@@ -1408,9 +1528,15 @@ $(document).ready(() => {
     $.divResizer({
         select: '#main-resize',
         callback: function () {
+            let bcontent = $(".bcontent-wrap") ? $(".bcontent-wrap").height() : 0;
+            $(".sp-wrap").height(bcontent-30);
+            const height = $('.bcontent-wrap').height();
+            const cutHeight = isStageSelf ? getObjHeight($('#myTab')) : 0;
+            $('.sjs-height-material').height($('.sjs-height-1').height() - cutHeight);
+            $('.sjs-height-material-month').height($('.sjs-height-1').height() - getObjHeight($('.sjs-bar-1')));
+            $('.material-table-height').height($('.bcontent-wrap').height() - getObjHeight($('.bc-bar')));
             materialSpread.refresh();
             materialMonthSpread.refresh();
-            const height = $('#material-spread').height();
             setLocalCache('material_bills_' + materialID, height);
         }
     });
@@ -1440,7 +1566,7 @@ $(document).ready(() => {
         materialMonthSpread.refresh();
     });
     // 根据浏览器记录展开收起
-    if (getLocalCache('material_month_' + materialID)) {
+    if (getLocalCache('material_month_' + materialID) && !isStageSelf) {
         const tab = $('.right-nav a[content="#month-tab"]'), tabPanel = $(tab.attr('content'));
         $('a', '.side-menu').removeClass('active');
         $('.tab-content .tab-select-show').removeClass('active');
@@ -1451,11 +1577,22 @@ $(document).ready(() => {
         materialSpread.refresh();
         materialMonthSpread.refresh();
     }
+    const cutHeight = isStageSelf ? getObjHeight($('#myTab')) : 0;
     if (getLocalCache('material_bills_' + materialID)) {
-        $('#material-spread').height(getLocalCache('material_bills_' + materialID));
+        $('.bcontent-wrap').height(getLocalCache('material_bills_' + materialID));
         const cHeader = getObjHeight($(".c-header"));
-        const sjs1 = getObjHeight($('.sjs-height-1'));
-        $(".bcontent-wrap").height($(window).height()-cHeader-sjs1-90+53);
+        const bcontent = $(".bcontent-wrap") ? $(".bcontent-wrap").height() : 0;
+        $(".sp-wrap").height(bcontent-30);
+        $('.sjs-height-1').height($(window).height()-cHeader-bcontent-90+53);
+        $('.sjs-height-material').height($('.sjs-height-1').height() - cutHeight);
+        $('.sjs-height-material-month').height($('.sjs-height-1').height() - getObjHeight($('.sjs-bar-1')));
+        $('.material-table-height').height($('.bcontent-wrap').height() - getObjHeight($('.bc-bar')));
+        materialSpread.refresh();
+        materialMonthSpread.refresh();
+    } else {
+        $('.sjs-height-material').height($('.sjs-height-1').height() - cutHeight);
+        $('.sjs-height-material-month').height($('.sjs-height-1').height() - getObjHeight($('.sjs-bar-1')));
+        $('.material-table-height').height($('.bcontent-wrap').height() - getObjHeight($('.bc-bar')));
         materialSpread.refresh();
         materialMonthSpread.refresh();
     }

+ 111 - 4
app/public/js/material_checklist.js

@@ -125,7 +125,7 @@ $(document).ready(() => {
     SpreadJsObj.initSheet(ledgerSpread.getActiveSheet(), ledgerSpreadSetting);
 
     // 加载清单数据 - 暂时统一加载,如有需要,切换成动态加载并缓存
-    postData(window.location.pathname + '/load', {}, function (result) {
+    postData(window.location.pathname + '/load', { sid: isStageSelf ? materialStageData[0].sid : null }, function (result) {
         ledger = result.ledger;
         curLedgerData = result.curLedgerData;
         pos = result.pos;
@@ -134,6 +134,17 @@ $(document).ready(() => {
         notJoinList = result.materialNotJoinListData;
         materialChecklistData = result.materialChecklistData;
         gclList = result.gclList;
+        if (isStageSelf) {
+            // updateBillsData(ms_id);
+            const newGclGatherListData = [];
+            for (const [index, s] of result.ledgerListData.entries()) {
+                gclGatherModel.loadLedgerData(ledger, s);
+                gclGatherModel.loadPosData(pos, result.posListData[index]);
+                const oneGclGatherData = gclGatherModel.gatherGclData();
+                newGclGatherListData.push(oneGclGatherData);
+            }
+            gclGatherListData = newGclGatherListData;
+        }
         // 解析清单汇总数据
         gclGatherModel.loadLedgerData(ledger, curLedgerData);
         gclGatherModel.loadPosData(pos, curPosData);
@@ -408,6 +419,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 index = materialChecklistData.indexOf(select);
         const datas = [];
         for (const xmj of gcl) {
@@ -419,8 +431,33 @@ $(document).ready(() => {
                 gather_qty: xmj.gather_qty,
                 is_join: notx === undefined ? 1 : 0,
             };
+            if (ms_id) data.ms_id = ms_id;
             datas.push(data);
         }
+        if (isStageSelf) {
+            // 取所有的gclGatherData才行,然后获取下的值
+            const gclData = gclGatherData[gclIndex];
+            for (const [index, ms] of materialStageData.entries()) {
+                if (ms.id !== ms_id) {
+                    const gclOther = _.find(gclGatherListData[index], { b_code: gclData.b_code, name: gclData.name, unit: gclData.unit, unit_price: gclData.unit_price });
+                    if (gclOther) {
+                        const leafXmjs = gclOther.leafXmjs.filter(item => item.gather_qty !== null && item.gather_qty !== undefined);
+                        for (const xmj of leafXmjs) {
+                            const notx = findNotJoinLeafXmj(xmj);
+                            const data = {
+                                xmj_id: xmj.id,
+                                gcl_id: xmj.gcl_id,
+                                mx_id: xmj.mx_id ? xmj.mx_id : '',
+                                gather_qty: xmj.gather_qty,
+                                is_join: notx === undefined ? 1 : 0,
+                                ms_id: ms.id,
+                            };
+                            datas.push(data);
+                        }
+                    }
+                }
+            }
+        }
         // 上传到数据库
         console.log(datas, gcl);
         postData(window.location.pathname + '/save', {type: 'adds', checklist: { id: select.id, had_bills: 1 }, postData: {xmjs: datas, mbIds: mb_id}}, function (result) {
@@ -453,6 +490,29 @@ $(document).ready(() => {
                     };
                     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()) {
+                        if (ms.id !== ms_id) {
+                            const gclOther = _.find(gclGatherListData[index], { b_code: gclData.b_code, name: gclData.name, unit: gclData.unit, unit_price: gclData.unit_price });
+                            if (gclOther) {
+                                const leafXmjs = gclOther.leafXmjs.filter(item => item.gather_qty !== null && item.gather_qty !== undefined);
+                                for (const xmj of leafXmjs) {
+                                    const data = {
+                                        xmj_id: xmj.id,
+                                        gcl_id: xmj.gcl_id,
+                                        mx_id: xmj.mx_id ? xmj.mx_id : '',
+                                    };
+                                    if (_.indexOf(datas, data) === -1) {
+                                        datas.push(data);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
                 const xmj = gcl[0];
                 const materialCount = _.size(_.filter(gclList, function (m) {
                     return m.gcl_id === xmj.gcl_id;
@@ -468,7 +528,7 @@ $(document).ready(() => {
                     }
                 }
                 console.log(datas, materialSelect.mb_id, checklist);
-                postData(window.location.pathname + '/save', {type: 'dels', checklist, postData: { xmjs: datas, mb_id: materialSelect.mb_id }}, function (result) {
+                postData(window.location.pathname + '/save', {type: 'dels', checklist, postData: { xmjs: datas, mb_id: materialSelect.mb_id }, ms_id: isStageSelf ? materialStageData[0].id : null }, function (result) {
                     // materialListData = result;
                     gclList = result;
                     if (checklist) materialChecklistData[index].had_bills = checklist.had_bills;
@@ -539,8 +599,31 @@ $(document).ready(() => {
                         };
                         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()) {
+                            if (ms.id !== ms_id) {
+                                const gclOther = _.find(gclGatherListData[index], { b_code: gclData.b_code, name: gclData.name, unit: gclData.unit, unit_price: gclData.unit_price });
+                                if (gclOther) {
+                                    const leafXmjs = gclOther.leafXmjs.filter(item => item.gather_qty !== null && item.gather_qty !== undefined);
+                                    for (const xmj of leafXmjs) {
+                                        const data = {
+                                            xmj_id: xmj.id,
+                                            gcl_id: xmj.gcl_id,
+                                            mx_id: xmj.mx_id ? xmj.mx_id : '',
+                                        };
+                                        if (_.indexOf(datas, data) === -1) {
+                                            datas.push(data);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
                     console.log(exprQuantity, datas, select.mb_id);
-                    postData(window.location.pathname + '/save', { type:'updates', updateData: { xmjs: datas, expr: exprQuantity.expr, quantity: exprQuantity.quantity, mb_id: select.mb_id } }, function (result) {
+                    postData(window.location.pathname + '/save', { type:'updates', updateData: { xmjs: datas, expr: exprQuantity.expr, quantity: exprQuantity.quantity, mb_id: select.mb_id }, ms_id: isStageSelf ? materialStageData[0].id : null }, function (result) {
                         // materialListData = result;
                         gclList = result;
                         loadMaterialData(gclIndex, 0);
@@ -637,9 +720,33 @@ $(document).ready(() => {
                     };
                     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()) {
+                        if (ms.id !== ms_id) {
+                            const gclOther = _.find(gclGatherListData[index], { b_code: gclData.b_code, name: gclData.name, unit: gclData.unit, unit_price: gclData.unit_price });
+                            console.log(gclOther);
+                            if (gclOther) {
+                                const leafXmjs = gclOther.leafXmjs.filter(item => item.gather_qty !== null && item.gather_qty !== undefined);
+                                for (const xmj of leafXmjs) {
+                                    const data = {
+                                        xmj_id: xmj.id,
+                                        gcl_id: xmj.gcl_id,
+                                        mx_id: xmj.mx_id ? xmj.mx_id : '',
+                                    };
+                                    if (_.indexOf(datas, data) === -1) {
+                                        datas.push(data);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
                 console.log(data, datas);
                 // 更新至服务器
-                postData(window.location.pathname + '/save', { type:'pastes', updateData: { xmjs: datas, pasteData: data } }, function (result) {
+                postData(window.location.pathname + '/save', { type:'pastes', updateData: { xmjs: datas, pasteData: data }, ms_id: isStageSelf ? materialStageData[0].id : null }, function (result) {
                     // materialListData = result;
                     gclList = result;
                     loadMaterialData(gclIndex, 0);

+ 356 - 106
app/public/js/material_list.js

@@ -43,8 +43,9 @@ function getMpSpreadByMBData(id) {
 
 function getMaterialListByLeafXmj(gcl_id, xmj_id, mx_id = '') {
     const list = [];
+    const ms_id = isStageSelf ? parseInt($('#myTab').find('.active').data('msid')) : null;
     for (const ml of materialListData) {
-        if (gcl_id === ml.gcl_id && xmj_id === ml.xmj_id && (mx_id === '' || mx_id === ml.mx_id)) {
+        if (gcl_id === ml.gcl_id && xmj_id === ml.xmj_id && (mx_id === '' || mx_id === ml.mx_id) && (ms_id === null || ms_id === ml.ms_id)) {
             list.push(ml);
         }
     }
@@ -232,113 +233,256 @@ $(document).ready(() => {
             },
         ],
     };
-    // 加载清单数据 - 暂时统一加载,如有需要,切换成动态加载并缓存
-    postData(window.location.pathname + '/load', {}, async function (result) {
-        ledger = result.ledger;
-        curLedgerData = result.curLedgerData;
-        pos = result.pos;
-        curPosData = result.curPosData;
-        materialListData = result.materialListData;
-        gclList = result.gclList;
-        notJoinList = result.materialNotJoinListData;
-        selfList = result.materialSelfListData;
-        materialChecklistData = result.materialChecklistData;
-        // 解析清单汇总数据
-        gclGatherModel.loadLedgerData(ledger, curLedgerData);
-        gclGatherModel.loadPosData(pos, curPosData);
-        gclGatherData = gclGatherModel.gatherGclData();
-        console.log(gclGatherData);
-        if (openMaterialChecklist) {
-            const hadBillsidList = _.uniq(_.map(gclList, 'gcl_id'));
-            console.log(hadBillsidList);
-            // 判断是否有修订影响到本次数据,并有几率修改清单设置页的值
-            const pushData = [];
-            const updateData = [];
-            for (const hb of hadBillsidList) {
-                const gcl = _.find(gclGatherData, function (item) {
-                    return item.leafXmjs && item.leafXmjs.length > 0 && _.findIndex(item.leafXmjs, { gcl_id : hb }) !== -1;
+    const needUpdateArray = ['quantity', 'msg_tp', 'msg_times', 'msg_spread', 'm_spread', 'm_tp', 'm_tax_tp', 'is_summary', 'remark'];
+
+    function getGclList() {
+        if (gclGatherListData) {
+            return gclGatherListData;
+        } else {
+            const newGclGatherListData = [];
+            for (const [index,s] of ledgerListData.entries()) {
+                console.log(index, s);
+                gclGatherModel.loadLedgerData(ledger, s);
+                gclGatherModel.loadPosData(pos, posListData[index]);
+                const oneGclGatherData = gclGatherModel.gatherGclData().filter(item => {
+                    return item.qc_qty || item.contract_qty
                 });
-                if (gcl) {
-                    const mc = _.find(materialChecklistData, { b_code: gcl.b_code, name: gcl.name, unit: gcl.unit, unit_price: gcl.unit_price });
-                    // const newOrder = _.indexOf(gclGatherData, gcl);
-                    // console.log(newOrder);
-                    if (!mc && _.findIndex(pushData, { b_code: gcl.b_code, name: gcl.name, unit: gcl.unit, unit_price: gcl.unit_price }) === -1) {
-                        pushData.push({ b_code: gcl.b_code, name: gcl.name, unit: gcl.unit, unit_price: gcl.unit_price, quantity: (gcl.quantity ? gcl.quantity : null), total_price: (gcl.total_price ? gcl.total_price : null), had_bills: 1 });
+                newGclGatherListData.push(oneGclGatherData);
+            }
+            return newGclGatherListData;
+        }
+    }
+    let first = true;
+    function setListsData(sid = null, ms_id = null) {
+        if (first) {
+            // 加载清单数据 - 暂时统一加载,如有需要,切换成动态加载并缓存
+            postData(window.location.pathname + '/load', {sid}, async function (result) {
+                ledger = result.ledger;
+                curLedgerData = result.curLedgerData;
+                pos = result.pos;
+                curPosData = result.curPosData;
+                materialListData = result.materialListData;
+                gclList = result.gclList;
+                notJoinList = result.materialNotJoinListData;
+                selfList = result.materialSelfListData;
+                materialChecklistData = result.materialChecklistData;
+                if (isStageSelf) {
+                    updateBillsData(ms_id);
+                    const newGclGatherListData = [];
+                    for (const [index, s] of result.ledgerListData.entries()) {
+                        gclGatherModel.loadLedgerData(ledger, s);
+                        gclGatherModel.loadPosData(pos, result.posListData[index]);
+                        const oneGclGatherData = gclGatherModel.gatherGclData().filter(item => {
+                            return item.qc_qty || item.contract_qty
+                        });
+                        newGclGatherListData.push(oneGclGatherData);
                     }
+                    gclGatherListData = newGclGatherListData;
                 }
-            }
-            const removeData = [];
-            for (const mc of materialChecklistData) {
-                const gcl = _.find(gclGatherData, { b_code: mc.b_code, name: mc.name, unit: mc.unit, unit_price: mc.unit_price });
-                // 判断是否已不存在工料清单,台账修改过后删除之
-                if (!gcl) {
-                    removeData.push(mc.id);
-                } else {
-                    // 更新had_bills值
-                    const updateObj = { id: mc.id };
-                    const gcl_ids = gcl.leafXmjs ? _.uniq(_.map(gcl.leafXmjs, 'gcl_id')) : [];
-                    const jiaoji = _.intersection(gcl_ids, hadBillsidList);
-                    if (mc.had_bills === 1) {
-                        if (jiaoji.length === 0) {
-                            updateObj.mid = materialID;
-                            updateObj.had_bills = 0;
-                            // updateData.push({ id: mc.id, mid: materialID, had_bills: 0 });
+                // 解析清单汇总数据
+                gclGatherModel.loadLedgerData(ledger, curLedgerData);
+                gclGatherModel.loadPosData(pos, curPosData);
+                gclGatherData = gclGatherModel.gatherGclData();
+                console.log(gclGatherData);
+
+                if (openMaterialChecklist) {
+                    const hadBillsidList = _.uniq(_.map(gclList, 'gcl_id'));
+                    console.log(hadBillsidList);
+                    // 判断是否有修订影响到本次数据,并有几率修改清单设置页的值
+                    const pushData = [];
+                    const updateData = [];
+                    for (const hb of hadBillsidList) {
+                        const gcl = _.find(gclGatherData, function (item) {
+                            return item.leafXmjs && item.leafXmjs.length > 0 && _.findIndex(item.leafXmjs, {gcl_id: hb}) !== -1;
+                        });
+                        if (gcl) {
+                            const mc = _.find(materialChecklistData, {
+                                b_code: gcl.b_code,
+                                name: gcl.name,
+                                unit: gcl.unit,
+                                unit_price: gcl.unit_price
+                            });
+                            // const newOrder = _.indexOf(gclGatherData, gcl);
+                            // console.log(newOrder);
+                            if (!mc && _.findIndex(pushData, {
+                                b_code: gcl.b_code,
+                                name: gcl.name,
+                                unit: gcl.unit,
+                                unit_price: gcl.unit_price
+                            }) === -1) {
+                                pushData.push({
+                                    b_code: gcl.b_code,
+                                    name: gcl.name,
+                                    unit: gcl.unit,
+                                    unit_price: gcl.unit_price,
+                                    quantity: (gcl.quantity ? gcl.quantity : null),
+                                    total_price: (gcl.total_price ? gcl.total_price : null),
+                                    had_bills: 1
+                                });
+                            }
                         }
-                    } else if (mc.had_bills === 0) {
-                        if (jiaoji.length !== 0) {
-                            updateObj.had_bills = 1;
+                    }
+                    const removeData = [];
+                    for (const mc of materialChecklistData) {
+                        const gcl = _.find(gclGatherData, {
+                            b_code: mc.b_code,
+                            name: mc.name,
+                            unit: mc.unit,
+                            unit_price: mc.unit_price
+                        });
+                        // 判断是否已不存在工料清单,台账修改过后删除之
+                        if (!gcl) {
+                            removeData.push(mc.id);
+                        } else {
+                            // 更新had_bills值
+                            const updateObj = {id: mc.id};
+                            const gcl_ids = gcl.leafXmjs ? _.uniq(_.map(gcl.leafXmjs, 'gcl_id')) : [];
+                            const jiaoji = _.intersection(gcl_ids, hadBillsidList);
+                            if (mc.had_bills === 1) {
+                                if (jiaoji.length === 0) {
+                                    updateObj.mid = materialID;
+                                    updateObj.had_bills = 0;
+                                    // updateData.push({ id: mc.id, mid: materialID, had_bills: 0 });
+                                }
+                            } else if (mc.had_bills === 0) {
+                                if (jiaoji.length !== 0) {
+                                    updateObj.had_bills = 1;
+                                }
+                            }
+                            // 更新工程量及台账金额
+                            if (mc.quantity !== (gcl.quantity ? gcl.quantity : null)) {
+                                updateObj.quantity = gcl.quantity ? gcl.quantity : null;
+                                updateObj.total_price = gcl.total_price ? gcl.total_price : null;
+                            }
+                            if (!_.isEqual(updateObj, {id: mc.id})) updateData.push(updateObj);
                         }
                     }
-                    // 更新工程量及台账金额
-                    if (mc.quantity !== (gcl.quantity ? gcl.quantity : null)) {
-                        updateObj.quantity = gcl.quantity ? gcl.quantity : null;
-                        updateObj.total_price = gcl.total_price ? gcl.total_price : null;
+                    console.log(pushData, removeData, updateData);
+                    if (pushData.length > 0 || removeData.length > 0 || updateData.length > 0) {
+                        // materialChecklistData = await postDataAsync('/tender/'+ tenderID +'/measure/material/'+ stage_order +'/checklist/save', { type: 'resetChecklist', pushData, removeData, updateData })
                     }
-                    if(!_.isEqual(updateObj,{ id: mc.id })) updateData.push(updateObj);
-                }
-            }
-            console.log(pushData, removeData, updateData);
-            if (pushData.length > 0 || removeData.length > 0 || updateData.length > 0) {
-                // materialChecklistData = await postDataAsync('/tender/'+ tenderID +'/measure/material/'+ stage_order +'/checklist/save', { type: 'resetChecklist', pushData, removeData, updateData })
-            }
-            gclGatherData = gclGatherData.filter(item => {
-                return item.qc_qty || item.contract_qty
-            });
-            // 取交集
-            const selfListGcl = _.uniq(_.map(selfList, 'gcl_id'));
-            gclGatherData = _.filter(gclGatherData, function (item) {
-                if(_.find(materialChecklistData, { b_code: item.b_code, name: item.name, unit: item.unit, unit_price: item.unit_price })) {
-                    return true;
+                    gclGatherData = gclGatherData.filter(item => {
+                        return item.qc_qty || item.contract_qty
+                    });
+                    // 取交集
+                    const selfListGcl = _.uniq(_.map(selfList, 'gcl_id'));
+                    gclGatherData = _.filter(gclGatherData, function (item) {
+                        if (_.find(materialChecklistData, {
+                            b_code: item.b_code,
+                            name: item.name,
+                            unit: item.unit,
+                            unit_price: item.unit_price
+                        })) {
+                            return true;
+                        } else {
+                            const gcl_ids = item.leafXmjs ? _.uniq(_.map(item.leafXmjs, 'gcl_id')) : [];
+                            const jiaoji = _.intersection(gcl_ids, selfListGcl);
+                            if (jiaoji.length > 0) {
+                                return true;
+                            }
+                        }
+                    });
                 } else {
-                    const gcl_ids = item.leafXmjs ? _.uniq(_.map(item.leafXmjs, 'gcl_id')) : [];
-                    const jiaoji = _.intersection(gcl_ids, selfListGcl);
-                    if (jiaoji.length > 0) {
-                        return true;
-                    }
+                    gclGatherData = gclGatherData.filter(item => {
+                        return item.qc_qty || item.contract_qty
+                    });
                 }
+                calculateJiaCha(gclGatherData);
+                SpreadJsObj.initSheet(leafXmjSpread.getActiveSheet(), leafXmjSpreadSetting);
+                // 加载清单数据
+                SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), SpreadJsObj.DataType.Data, gclGatherData);
+                loadLeafXmjData(0);
+                loadMaterialData(0);
+                loadXmjMaterialData(0, 0);
+                const sheet = materialSpread.getActiveSheet();
+                sheet.suspendPaint();
+                sheet.setCellType(1, 3, new TipCellType(), spreadNS.SheetArea.colHeader);
+                sheet.resumePaint();
+                const selfSheet = materialSelfSpread.getActiveSheet();
+                selfSheet.suspendPaint();
+                selfSheet.setCellType(1, 3, new TipCellType(), spreadNS.SheetArea.colHeader);
+                selfSheet.resumePaint();
+                checkNotJoinMaterialData();
+                first = false;
             });
         } else {
-            gclGatherData = gclGatherData.filter(item => {
-                return item.qc_qty || item.contract_qty
-            });
+            // 解析清单汇总数据
+            // const ms_id = $('#myTab').find('.active').data('msid');
+            updateBillsData(ms_id);
+            const i = _.findIndex(materialStageData, { sid });
+            gclGatherData = gclGatherListData[i];
+            if (openMaterialChecklist) {
+                gclGatherData = gclGatherData.filter(item => {
+                    return item.qc_qty || item.contract_qty
+                });
+                // 取交集
+                const selfListGcl = _.uniq(_.map(selfList, 'gcl_id'));
+                gclGatherData = _.filter(gclGatherData, function (item) {
+                    if (_.find(materialChecklistData, {
+                        b_code: item.b_code,
+                        name: item.name,
+                        unit: item.unit,
+                        unit_price: item.unit_price
+                    })) {
+                        return true;
+                    } else {
+                        const gcl_ids = item.leafXmjs ? _.uniq(_.map(item.leafXmjs, 'gcl_id')) : [];
+                        const jiaoji = _.intersection(gcl_ids, selfListGcl);
+                        if (jiaoji.length > 0) {
+                            return true;
+                        }
+                    }
+                });
+            } else {
+                gclGatherData = gclGatherData.filter(item => {
+                    return item.qc_qty || item.contract_qty
+                });
+            }
+            console.log(gclGatherData);
+            calculateJiaCha(gclGatherData);
+            SpreadJsObj.initSheet(leafXmjSpread.getActiveSheet(), leafXmjSpreadSetting);
+            // 加载清单数据
+            SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), SpreadJsObj.DataType.Data, gclGatherData);
+            loadLeafXmjData(0);
+            loadMaterialData(0);
+            loadXmjMaterialData(0, 0);
+            const sheet = materialSpread.getActiveSheet();
+            sheet.suspendPaint();
+            sheet.setCellType(1, 3, new TipCellType(), spreadNS.SheetArea.colHeader);
+            sheet.resumePaint();
+            const selfSheet = materialSelfSpread.getActiveSheet();
+            selfSheet.suspendPaint();
+            selfSheet.setCellType(1, 3, new TipCellType(), spreadNS.SheetArea.colHeader);
+            selfSheet.resumePaint();
+            checkNotJoinMaterialData();
         }
-        calculateJiaCha(gclGatherData);
-        SpreadJsObj.initSheet(leafXmjSpread.getActiveSheet(), leafXmjSpreadSetting);
-        // 加载清单数据
-        SpreadJsObj.loadSheetData(ledgerSpread.getActiveSheet(), SpreadJsObj.DataType.Data, gclGatherData);
-        loadLeafXmjData(0);
-        loadMaterialData(0);
-        loadXmjMaterialData(0, 0);
-        const sheet = materialSpread.getActiveSheet();
-        sheet.suspendPaint();
-        sheet.setCellType(1, 3, new TipCellType(), spreadNS.SheetArea.colHeader);
-        sheet.resumePaint();
-        const selfSheet = materialSelfSpread.getActiveSheet();
-        selfSheet.suspendPaint();
-        selfSheet.setCellType(1, 3, new TipCellType(), spreadNS.SheetArea.colHeader);
-        selfSheet.resumePaint();
-        checkNotJoinMaterialData();
+    }
+
+    function updateBillsData(ms_id) {
+        const msbList = _.filter(materialStageBillsData, { ms_id });
+        for (const mb of materialBillsData) {
+            mb.ms_id = ms_id;
+            const msbInfo = _.find(msbList, { mb_id: mb.id });
+            for (const nu of needUpdateArray) {
+                mb[nu] = msbInfo[nu];
+            }
+        }
+    }
+
+    setListsData(isStageSelf ? materialStageData[0].sid : null, isStageSelf ? materialStageData[0].id : null);
+
+    // 期切换
+    $('#myTab a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
+        e.preventDefault();
+        const ms_id = $('#myTab').find('.active').data('msid');
+        const msInfo = _.find(materialStageData, { id: ms_id });
+        showWaitingView();
+        setTimeout(function () {
+            setListsData(msInfo.sid, ms_id);
+            closeWaitingView();
+        }, 500);
     });
+
     // const leafXmjCol = {
     //     getValue: {
     //         jiacha: function (data) {
@@ -485,8 +629,9 @@ $(document).ready(() => {
             console.log(xmj, iLXmjRow);
             materialListSelf = [];
             if (_.findIndex(selfList, { gcl_id: xmj.gcl_id, xmj_id: xmj.id, mx_id: (xmj.mx_id ? xmj.mx_id : '') }) != -1) {
+                const ms_id = isStageSelf ? parseInt($('#myTab').find('.active').data('msid')) : null;
                 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)) {
+                    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) && (ms_id === null || ms_id === m.ms_id)) {
                         materialListSelf.push(m);
                     }
                 }
@@ -576,6 +721,7 @@ $(document).ready(() => {
             const select = SpreadJsObj.getSelectObject(sheet);
             const index = gclGatherData.indexOf(select);
             const gcl = gclGatherData[index].leafXmjs.filter(item => item.gather_qty !== null && item.gather_qty !== undefined);
+            const ms_id = isStageSelf ? parseInt($('#myTab').find('.active').data('msid')) : null;
             const datas = [];
             for (const xmj of gcl) {
                 const notx = findNotJoinLeafXmj(xmj);
@@ -586,10 +732,35 @@ $(document).ready(() => {
                     gather_qty: xmj.gather_qty,
                     is_join: notx === undefined ? 1 : 0,
                 };
+                if (ms_id) data.ms_id = ms_id;
                 datas.push(data);
             }
+            if (isStageSelf) {
+                // 取所有的gclGatherData才行,然后获取下的值
+                const gclData = gclGatherData[index];
+                for (const [index, ms] of materialStageData.entries()) {
+                    if (ms.id !== ms_id) {
+                        const gclOther = _.find(gclGatherListData[index], { b_code: gclData.b_code, name: gclData.name, unit: gclData.unit, unit_price: gclData.unit_price });
+                        if (gclOther) {
+                            const leafXmjs = gclOther.leafXmjs.filter(item => item.gather_qty !== null && item.gather_qty !== undefined);
+                            for (const xmj of leafXmjs) {
+                                const notx = findNotJoinLeafXmj(xmj);
+                                const data = {
+                                    xmj_id: xmj.id,
+                                    gcl_id: xmj.gcl_id,
+                                    mx_id: xmj.mx_id ? xmj.mx_id : '',
+                                    gather_qty: xmj.gather_qty,
+                                    is_join: notx === undefined ? 1 : 0,
+                                    ms_id: ms.id,
+                                };
+                                datas.push(data);
+                            }
+                        }
+                    }
+                }
+            }
             console.log(datas, gcl, mb_id);
-            postData(window.location.pathname + '/save', {type: 'adds', postData: {xmjs: datas, mbIds: mb_id}}, function (result) {
+            postData(window.location.pathname + '/save', {type: 'adds', postData: {xmjs: datas, mbIds: mb_id} }, function (result) {
                 materialListData = result.materialListData;
                 gclList = result.gclList;
                 // toastr.success('已成功应用');
@@ -623,7 +794,7 @@ $(document).ready(() => {
                 is_join: notx === undefined ? 1 : 0,
             };
             console.log(data);
-            postData(window.location.pathname + '/save', {type: 'add', postData: data}, function (result) {
+            postData(window.location.pathname + '/save', {type: 'add', postData: data, ms_id: $('#myTab').find('.active').data('msid') || null }, function (result) {
                 // 添加到materialList里
                 materialListData = result;
                 loadXmjMaterialData(index, leafXmjIndex);
@@ -654,6 +825,7 @@ $(document).ready(() => {
                 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) {
@@ -677,6 +849,7 @@ $(document).ready(() => {
                 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) {
@@ -816,8 +989,31 @@ $(document).ready(() => {
                     };
                     datas.push(data);
                 }
+                if (isStageSelf) {
+                    const ms_id = isStageSelf ? parseInt($('#myTab').find('.active').data('msid')) : null;
+                    // 取所有的gclGatherData才行,然后获取下的值
+                    const gclData = gclGatherData[index];
+                    for (const [index, ms] of materialStageData.entries()) {
+                        if (ms.id !== ms_id) {
+                            const gclOther = _.find(gclGatherListData[index], { b_code: gclData.b_code, name: gclData.name, unit: gclData.unit, unit_price: gclData.unit_price });
+                            if (gclOther) {
+                                const leafXmjs = gclOther.leafXmjs.filter(item => item.gather_qty !== null && item.gather_qty !== undefined);
+                                for (const xmj of leafXmjs) {
+                                    const data = {
+                                        xmj_id: xmj.id,
+                                        gcl_id: xmj.gcl_id,
+                                        mx_id: xmj.mx_id ? xmj.mx_id : '',
+                                    };
+                                    if (_.indexOf(datas, data) === -1) {
+                                        datas.push(data);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
                 console.log(datas, materialSelect.mb_id);
-                postData(window.location.pathname + '/save', {type: 'dels', postData: { xmjs: datas, mb_id: materialSelect.mb_id }}, function (result) {
+                postData(window.location.pathname + '/save', {type: 'dels', postData: { xmjs: datas, mb_id: materialSelect.mb_id }, ms_id: $('#myTab').find('.active').data('msid') || null}, function (result) {
                     materialListData = result.materialListData;
                     gclList = result.gclList;
                     calculateJiaCha(gclGatherData);
@@ -918,8 +1114,31 @@ $(document).ready(() => {
                         };
                         datas.push(data);
                     }
+                    if (isStageSelf) {
+                        const ms_id = isStageSelf ? parseInt($('#myTab').find('.active').data('msid')) : null;
+                        // 取所有的gclGatherData才行,然后获取下的值
+                        const gclData = gclGatherData[index];
+                        for (const [index, ms] of materialStageData.entries()) {
+                            if (ms.id !== ms_id) {
+                                const gclOther = _.find(gclGatherListData[index], { b_code: gclData.b_code, name: gclData.name, unit: gclData.unit, unit_price: gclData.unit_price });
+                                if (gclOther) {
+                                    const leafXmjs = gclOther.leafXmjs.filter(item => item.gather_qty !== null && item.gather_qty !== undefined);
+                                    for (const xmj of leafXmjs) {
+                                        const data = {
+                                            xmj_id: xmj.id,
+                                            gcl_id: xmj.gcl_id,
+                                            mx_id: xmj.mx_id ? xmj.mx_id : '',
+                                        };
+                                        if (_.indexOf(datas, data) === -1) {
+                                            datas.push(data);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
                     console.log(exprQuantity, datas, select.mb_id);
-                    postData(window.location.pathname + '/save', { type:'updates', updateData: { xmjs: datas, expr: exprQuantity.expr, quantity: exprQuantity.quantity, mb_id: select.mb_id } }, function (result) {
+                    postData(window.location.pathname + '/save', { type:'updates', updateData: { xmjs: datas, expr: exprQuantity.expr, quantity: exprQuantity.quantity, mb_id: select.mb_id }, ms_id: $('#myTab').find('.active').data('msid') || null }, function (result) {
                         materialListData = result.materialListData;
                         gclList = result.gclList;
                         calculateJiaCha(gclGatherData);
@@ -1047,9 +1266,33 @@ $(document).ready(() => {
                     };
                     datas.push(data2);
                 }
+                if (isStageSelf) {
+                    const ms_id = isStageSelf ? parseInt($('#myTab').find('.active').data('msid')) : null;
+                    // 取所有的gclGatherData才行,然后获取下的值
+                    const gclData = gclGatherData[index];
+                    for (const [index, ms] of materialStageData.entries()) {
+                        if (ms.id !== ms_id) {
+                            const gclOther = _.find(gclGatherListData[index], { b_code: gclData.b_code, name: gclData.name, unit: gclData.unit, unit_price: gclData.unit_price });
+                            console.log(gclOther);
+                            if (gclOther) {
+                                const leafXmjs = gclOther.leafXmjs.filter(item => item.gather_qty !== null && item.gather_qty !== undefined);
+                                for (const xmj of leafXmjs) {
+                                    const data = {
+                                        xmj_id: xmj.id,
+                                        gcl_id: xmj.gcl_id,
+                                        mx_id: xmj.mx_id ? xmj.mx_id : '',
+                                    };
+                                    if (_.indexOf(datas, data) === -1) {
+                                        datas.push(data);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
                 console.log(data, datas);
                 // 更新至服务器
-                postData(window.location.pathname + '/save', { type:'pastes', updateData: { xmjs: datas, pasteData: data } }, function (result) {
+                postData(window.location.pathname + '/save', { type:'pastes', updateData: { xmjs: datas, pasteData: data }, ms_id: $('#myTab').find('.active').data('msid') || null }, function (result) {
                     materialListData = result.materialListData;
                     gclList = result.gclList;
                     calculateJiaCha(gclGatherData);
@@ -1211,7 +1454,7 @@ $(document).ready(() => {
                 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}, function (result) {
+                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);
@@ -1286,7 +1529,7 @@ $(document).ready(() => {
                     }
                     // 更新至服务器
                     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 } }, function (result) {
+                    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;
@@ -1387,7 +1630,7 @@ $(document).ready(() => {
                     return;
                 }
                 console.log(data);
-                postData(window.location.pathname + '/save', { type:'paste', updateData: data }, function (result) {
+                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);
@@ -1677,10 +1920,12 @@ $(document).ready(() => {
     $.divResizer({
         select: '#main-resize',
         callback: function () {
-            materialSpread.refresh();
-            ledgerSpread.refresh();
             let bcontent = $(".bcontent-wrap") ? $(".bcontent-wrap").height() : 0;
+            const cutHeight = isStageSelf ? getObjHeight($('#myTab')) : 0;
+            $('.sjs-height-material').height($('.sjs-height-1').height() - cutHeight);
             $(".sp-wrap").height(bcontent-30);
+            materialSpread.refresh();
+            ledgerSpread.refresh();
             leafXmjSpread.refresh();
             materialSelfSpread.refresh();
             const height = $('.bcontent-wrap').height();
@@ -1725,16 +1970,21 @@ $(document).ready(() => {
         // leafXmjSpread.refresh();
         materialSpread.refresh();
     }
+    const cutHeight = isStageSelf ? getObjHeight($('#myTab')) : 0;
     if (getLocalCache('material_list2_' + materialID)) {
         $('.bcontent-wrap').height(getLocalCache('material_list2_' + materialID));
         const cHeader = getObjHeight($(".c-header"));
         const bcontent = $(".bcontent-wrap") ? $(".bcontent-wrap").height() : 0;
         $(".sp-wrap").height(bcontent-30);
         $('.sjs-height-1').height($(window).height()-cHeader-bcontent-90+53);
+        $('.sjs-height-material').height($('.sjs-height-1').height() - cutHeight);
         materialSpread.refresh();
         ledgerSpread.refresh();
         leafXmjSpread.refresh();
         materialSelfSpread.refresh();
+    } else {
+        $('.sjs-height-material').height($('.sjs-height-1').height() - cutHeight);
+        ledgerSpread.refresh();
     }
     function getObjHeight(select) {
         return select.length > 0 ? select.height() : 0;

+ 177 - 78
app/public/js/measure_material.js

@@ -233,6 +233,12 @@ $(function () {
             $('#show_order').html('第<b class="mx-2">' + order_array.join(',') + '</b>期');
             $('#show_order').show();
             $('#s_order').val(order_array.join(','));
+            if (stageList.length > 1) {
+                $('#material_unitPrice').show();
+            } else {
+                $('#material_unitPrice').hide();
+                $('#unitPrice_gy').prop('checked', true);
+            }
         }
     });
     let interval;
@@ -251,110 +257,203 @@ $(function () {
         $('#add-qi input[name="stage_id[]"]:checked').each(function () {
             stage_id.push(parseInt($(this).val()));
         });
+        const is_stage_self = parseInt($('input[name="is_stage_self"]:checked').val());
         const newMaterialData = {
             s_order: $('#s_order').val(),
             period: $('#add-qi input[name="period"]').val(),
             stage_id,
+            is_stage_self,
         };
         if (lastMaterialListNum === 0) {
             console.log(newMaterialData);
-            postData(preUrl + '/measure/material/add', newMaterialData, function (result) {
-                window.location.href = preUrl + '/measure/material/' + result.order;
-            }, function () {
+            // postData(preUrl + '/measure/material/add', newMaterialData, function (result) {
+            //     window.location.href = preUrl + '/measure/material/' + result.order;
+            // }, function () {
                 _self.attr('disabled', false).text('确认添加');
-            });
+            // });
             return;
         }
         $('#add-qi').modal('hide');
         $('#okedit').modal('show');
         interval = setInterval(progress, 50);
-        postData(preUrl + '/measure/material/gcl/load', { stage_id }, function (result) {
+        postData(preUrl + '/measure/material/gcl/load', { stage_id, is_stage_self }, function (result) {
             // console.log(result);
             const ledger = result.ledger;
-            const curLedgerData = result.curLedgerData;
             const pos = result.pos;
-            const curPosData = result.curPosData;
             const gclList = result.gclList;
             const selfList = result.selfList;
-            const materialListForSelf = result.materialListForSelf;
-            gclGatherModel.loadLedgerData(ledger, curLedgerData);
-            gclGatherModel.loadPosData(pos, curPosData);
-            const gclGatherData = gclGatherModel.gatherGclData();
-            // const gclGatherData = gclGatherModel.gatherGclData().filter(item => {
-            //     return item.qc_qty || item.contract_qty
-            // });
-            // 获取需要新增的工料关联清单
-            const insertGcl = [];
-            const removeGclList = [];
+            // 整理material,针对上期是独立单价并多个不同值的单独设置值进行部分值去除
+            const materialListForSelf = _.uniqWith(_.orderBy(result.materialListForSelf, ['ms_id'], ['desc']), function(item1, item2) {
+                return item1.xmj_id === item2.xmj_id && item1.gcl_id === item2.gcl_id && item1.mx_id === item2.mx_id && item1.mb_id === item2.mb_id;
+            });
+            console.log(materialListForSelf, result.materialListForSelf);
+            const insertGclList = [];
+            const insertList = [];
             const insertSelfList = [];// 需要单独添加的明细清单工料含量列表
-            for (const g of gclList) {
-                const gcl = _.find(gclGatherData, function (item) {
-                    return item.leafXmjs && item.leafXmjs.length > 0 && _.findIndex(item.leafXmjs, { gcl_id : g.gcl_id }) !== -1;
-                });
-                if (gcl) {
-                    const ig = _.find(insertGcl, { gcl });
-                    if (ig) {
-                        if(_.findIndex(ig.bills, { mb_id: g.mb_id }) === -1) {
-                            ig.bills.push(g);
+            const removeGclList = [];
+            const hadQtySelfList = [];
+            if (is_stage_self) {
+                for (const sid of stage_id) {
+                    const curLedger = _.find(result.curLedgerData, {sid: sid});
+                    const curPos = _.find(result.curPosData, {sid: sid});
+                    gclGatherModel.loadLedgerData(ledger, curLedger.ledgerData);
+                    gclGatherModel.loadPosData(pos, curPos.posData);
+                    const gclGatherData = gclGatherModel.gatherGclData();
+                    // console.log(gclGatherData);
+                    const insertGcl = [];
+                    for (const g of gclList) {
+                        const gcl = _.find(gclGatherData, function (item) {
+                            return item.leafXmjs && item.leafXmjs.length > 0 && _.findIndex(item.leafXmjs, {gcl_id: g.gcl_id}) !== -1;
+                        });
+                        if (gcl) {
+                            const ig = _.find(insertGcl, {gcl});
+                            if (ig) {
+                                if (_.findIndex(ig.bills, {mb_id: g.mb_id}) === -1) {
+                                    ig.bills.push(g);
+                                }
+                            } else {
+                                insertGcl.push({
+                                    bills: [g],
+                                    gcl,
+                                    leafXmjs: _.filter(gcl.leafXmjs, function (item) {
+                                        return item.gather_qty !== undefined && item.gather_qty !== null
+                                    }),
+                                })
+                            }
+                        } else {
+                            removeGclList.push(g);
+                        }
+                    }
+                    for (const one of insertGcl) {
+                        if (one.leafXmjs && one.leafXmjs.length > 0) {
+                            for (const xmj of one.leafXmjs) {
+                                const is_self = _.findIndex(selfList, { gcl_id: xmj.gcl_id, xmj_id: xmj.id, mx_id: xmj.mx_id ? xmj.mx_id : null }) !== -1;// 区分单独计量的明细工料含量
+                                if (is_self) {
+                                    const billsList = _.filter(materialListForSelf, { gcl_id: xmj.gcl_id, xmj_id: xmj.id, mx_id: xmj.mx_id ? xmj.mx_id : null });
+                                    for (const bill of billsList) {
+                                        if (!_.find(hadQtySelfList, bill)) {
+                                            hadQtySelfList.push(bill);
+                                        }
+                                        insertSelfList.push({
+                                            gcl_id: xmj.gcl_id,
+                                            mx_id: xmj.mx_id ? xmj.mx_id : '',
+                                            xmj_id: xmj.id ? xmj.id : null,
+                                            gather_qty: xmj.gather_qty,
+                                            quantity: bill.quantity,
+                                            expr: bill.expr,
+                                            mb_id: bill.mb_id,
+                                            order: bill.order,
+                                            sid,
+                                        });
+                                    }
+                                } else {
+                                    const newgcl = _.find(gclList, { gcl_id: xmj.gcl_id });
+                                    for (const bill of one.bills) {
+                                        insertList.push({
+                                            gcl_id: xmj.gcl_id,
+                                            mx_id: xmj.mx_id ? xmj.mx_id : '',
+                                            xmj_id: xmj.id ? xmj.id : null,
+                                            gather_qty: xmj.gather_qty,
+                                            quantity: bill.quantity,
+                                            expr: bill.expr,
+                                            mb_id: bill.mb_id,
+                                            order: bill.order,
+                                            sid,
+                                        });
+                                        if (!newgcl) {
+                                            if (_.findIndex(insertGclList, { gcl_id: xmj.gcl_id }) === -1) {
+                                                insertGclList.push({
+                                                    gcl_id: xmj.gcl_id,
+                                                    quantity: bill.quantity,
+                                                    expr: bill.expr,
+                                                    old_quantity: bill.quantity,
+                                                    old_expr: bill.expr,
+                                                    mb_id: bill.mb_id,
+                                                    order: bill.order,
+                                                });
+                                            }
+                                        }
+                                    }
+                                }
+                            }
                         }
-                    } else {
-                        insertGcl.push({
-                            bills: [g],
-                            gcl,
-                            leafXmjs: _.filter(gcl.leafXmjs, function(item) { return item.gather_qty !== undefined && item.gather_qty !== null }),
-                        })
                     }
-                } else {
-                    removeGclList.push(g);
                 }
-            }
-            const insertList = [];
-            const insertGclList = [];
-            const hadQtySelfList = [];
-            for (const one of insertGcl) {
-                if (one.leafXmjs && one.leafXmjs.length > 0) {
-                    for (const xmj of one.leafXmjs) {
-                        const is_self = _.findIndex(selfList, { gcl_id: xmj.gcl_id, xmj_id: xmj.id, mx_id: xmj.mx_id ? xmj.mx_id : null }) !== -1;// 区分单独计量的明细工料含量
-                        if (is_self) {
-                            const billsList = _.filter(materialListForSelf, { gcl_id: xmj.gcl_id, xmj_id: xmj.id, mx_id: xmj.mx_id ? xmj.mx_id : null });
-                            console.log(billsList);
-                            for (const bill of billsList) {
-                                hadQtySelfList.push(bill);
-                                insertSelfList.push({
-                                    gcl_id: xmj.gcl_id,
-                                    mx_id: xmj.mx_id ? xmj.mx_id : '',
-                                    xmj_id: xmj.id ? xmj.id : null,
-                                    gather_qty: xmj.gather_qty,
-                                    quantity: bill.quantity,
-                                    expr: bill.expr,
-                                    mb_id: bill.mb_id,
-                                    order: bill.order,
-                                });
+            } else {
+                const curLedgerData = result.curLedgerData;
+                const curPosData = result.curPosData;
+                gclGatherModel.loadLedgerData(ledger, curLedgerData);
+                gclGatherModel.loadPosData(pos, curPosData);
+                const gclGatherData = gclGatherModel.gatherGclData();
+                const insertGcl = [];
+                for (const g of gclList) {
+                    const gcl = _.find(gclGatherData, function (item) {
+                        return item.leafXmjs && item.leafXmjs.length > 0 && _.findIndex(item.leafXmjs, {gcl_id: g.gcl_id}) !== -1;
+                    });
+                    if (gcl) {
+                        const ig = _.find(insertGcl, {gcl});
+                        if (ig) {
+                            if (_.findIndex(ig.bills, {mb_id: g.mb_id}) === -1) {
+                                ig.bills.push(g);
                             }
                         } else {
-                            const newgcl = _.find(gclList, { gcl_id: xmj.gcl_id });
-                            for (const bill of one.bills) {
-                                insertList.push({
-                                    gcl_id: xmj.gcl_id,
-                                    mx_id: xmj.mx_id ? xmj.mx_id : '',
-                                    xmj_id: xmj.id ? xmj.id : null,
-                                    gather_qty: xmj.gather_qty,
-                                    quantity: bill.quantity,
-                                    expr: bill.expr,
-                                    mb_id: bill.mb_id,
-                                    order: bill.order,
-                                });
-                                if (!newgcl) {
-                                    insertGclList.push({
+                            insertGcl.push({
+                                bills: [g],
+                                gcl,
+                                leafXmjs: _.filter(gcl.leafXmjs, function (item) {
+                                    return item.gather_qty !== undefined && item.gather_qty !== null
+                                }),
+                            })
+                        }
+                    } else {
+                        removeGclList.push(g);
+                    }
+                }
+                for (const one of insertGcl) {
+                    if (one.leafXmjs && one.leafXmjs.length > 0) {
+                        for (const xmj of one.leafXmjs) {
+                            const is_self = _.findIndex(selfList, { gcl_id: xmj.gcl_id, xmj_id: xmj.id, mx_id: xmj.mx_id ? xmj.mx_id : null }) !== -1;// 区分单独计量的明细工料含量
+                            if (is_self) {
+                                const billsList = _.filter(materialListForSelf, { gcl_id: xmj.gcl_id, xmj_id: xmj.id, mx_id: xmj.mx_id ? xmj.mx_id : null });
+                                console.log(billsList);
+                                for (const bill of billsList) {
+                                    hadQtySelfList.push(bill);
+                                    insertSelfList.push({
                                         gcl_id: xmj.gcl_id,
+                                        mx_id: xmj.mx_id ? xmj.mx_id : '',
+                                        xmj_id: xmj.id ? xmj.id : null,
+                                        gather_qty: xmj.gather_qty,
                                         quantity: bill.quantity,
                                         expr: bill.expr,
-                                        old_quantity: bill.quantity,
-                                        old_expr: bill.expr,
                                         mb_id: bill.mb_id,
                                         order: bill.order,
                                     });
                                 }
+                            } else {
+                                const newgcl = _.find(gclList, { gcl_id: xmj.gcl_id });
+                                for (const bill of one.bills) {
+                                    insertList.push({
+                                        gcl_id: xmj.gcl_id,
+                                        mx_id: xmj.mx_id ? xmj.mx_id : '',
+                                        xmj_id: xmj.id ? xmj.id : null,
+                                        gather_qty: xmj.gather_qty,
+                                        quantity: bill.quantity,
+                                        expr: bill.expr,
+                                        mb_id: bill.mb_id,
+                                        order: bill.order,
+                                    });
+                                    if (!newgcl) {
+                                        insertGclList.push({
+                                            gcl_id: xmj.gcl_id,
+                                            quantity: bill.quantity,
+                                            expr: bill.expr,
+                                            old_quantity: bill.quantity,
+                                            old_expr: bill.expr,
+                                            mb_id: bill.mb_id,
+                                            order: bill.order,
+                                        });
+                                    }
+                                }
                             }
                         }
                     }
@@ -387,11 +486,11 @@ $(function () {
                 window.location.href = preUrl + '/measure/material/' + result.order;
             }, function () {
                 stop = true;
-                // clearInterval(interval);
-                // console.log(_self.parents('div[id="add-qi"]'));
-                // $('#add-qi').modal('show');
-                // $('#okedit').modal('hide');
-                // _self.parents('div[id="add-qi"]').modal('show');
+                clearInterval(interval);
+                console.log(_self.parents('div[id="add-qi"]'));
+                $('#add-qi').modal('show');
+                $('#okedit').modal('hide');
+                _self.parents('div[id="add-qi"]').modal('show');
                 _self.attr('disabled', false).text('确认添加');
             });
             return;

+ 4 - 4
app/public/js/revise.js

@@ -1027,13 +1027,13 @@ $(document).ready(() => {
         billsSpread.bind(spreadNS.Events.EditStarting, billsTreeSpreadObj.editStarting);
         billsSpread.bind(spreadNS.Events.EditEnded, billsTreeSpreadObj.editEnded);
         billsSpread.bind(spreadNS.Events.ClipboardPasting, billsTreeSpreadObj.clipboardPasting);
-        billsSpread.bind(spreadNS.Events.ClipboardChanging, function (e, info) {
-            const copyText = SpreadJsObj.getFilterCopyText(info.sheet);
-            SpreadJsObj.Clipboard.setCopyData(copyText);
-        });
         SpreadJsObj.addDeleteBind(billsSpread, billsTreeSpreadObj.deletePress);
         SpreadJsObj.addCutEvents(billsSpread, billsTreeSpreadObj.cut);
     }
+    billsSpread.bind(spreadNS.Events.ClipboardChanging, function (e, info) {
+        const copyText = SpreadJsObj.getFilterCopyText(info.sheet);
+        SpreadJsObj.Clipboard.setCopyData(copyText);
+    });
     // 右键菜单
     let batchInsertObj;
     $.contextMenu.types.batchInsert = function (item, opt, root) {

+ 54 - 0
app/public/js/shares/show_level.js

@@ -0,0 +1,54 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date
+ * @version
+ */
+$.cs_showLevel = function (setting) {
+    const sortTitle = ['第一层', '第二层', '第三层','第四层', '第五层'];
+    if (!setting.selector) throw '未指定模块';
+    if (!setting.levels) {
+        setting.levels = [
+            { type: 'sort', count: 5, },
+            { type: 'last', title: '最底层' },
+            // { type: 'leafXmj', title: '只显示项目节' },
+            // { type: 'curMeasure', title: '只显示本期计量' },
+        ];
+    }
+
+    const initShowLevel = function () {
+        const obj = $(setting.selector);
+        const html = [];
+        html.push('<button class="btn btn-sm btn-light dropdown-toggle text-primary" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">' +
+            '<i class="fa fa-list-ol"></i> 显示层级</button>');
+        html.push('<div class="dropdown-menu" aria-labelledby="dropdownMenuButton" id="showLevelList">');
+        for (const l of setting.levels) {
+            if (l.type === 'sort') {
+                let count = typeof l.count === 'function' ? l.count() : l.count;
+                count = Math.min(count, 5);
+                for (let i = 1; i <= count; ++i) {
+                    html.push(`<a class="dropdown-item" name="showLevel" tag="${i}" href="javascript: void(0);">${sortTitle[i-1]}</a>`);
+                }
+            } else {
+                html.push(`<a class="dropdown-item" name="showLevel" tag="${l.type}" href="javascript: void(0);">${l.title}</a>`);
+            }
+        }
+        html.push('</div>');
+        obj.html(html.join(''));
+
+
+        $('a[name=showLevel]').click(function () {
+            setTimeout(() => {
+                const tag = $(this).attr('tag');
+                showWaitingView();
+                setting.showLevel(tag);
+                closeWaitingView();
+            });
+        });
+    };
+
+    return { initShowLevel } ;
+};

+ 126 - 0
app/public/js/spreadjs_rela/spreadjs_zh.js

@@ -660,6 +660,12 @@ const SpreadJsObj = {
             }
             sheet.getRange(-1, col, -1, 1).cellType(sheet.extendCellType.autoTip);
         }
+        if (colSetting.cellType === 'delayTip') {
+            if (!sheet.extendCellType.tip) {
+                sheet.extendCellType.tip = this.CellType.getDelayTipCellType();
+            }
+            sheet.getRange(-1, col, -1, 1).cellType(sheet.extendCellType.tip);
+        }
         if (colSetting.cellType === 'checkbox') {
             if (!sheet.extendCellType.checkbox) {
                 sheet.extendCellType.checkbox = new spreadNS.CellTypes.CheckBox();
@@ -1565,6 +1571,104 @@ const SpreadJsObj = {
 
             return new AutoTipCellType();
         },
+        getDelayTipCellType: function () {
+            const maxHintWidth = 200, indent = 15, borderIndent = 10;
+            const TipCellType = function () {};
+            // 继承 SpreadJs定义的 普通的TextCellType
+            TipCellType.prototype = new spreadNS.CellTypes.Text();
+            const proto = TipCellType.prototype;
+            proto.getTextDisplayWidth = function(hitinfo, str, font) {
+                const xs = hitinfo.sheet.getParent().xs;
+                const ctx = xs.childNodes[0].getContext("2d");
+                if (font && font !== '') {
+                    ctx.font = font;
+                } else {
+                    ctx.font = hitinfo.cellStyle.font;
+                }
+                return ctx.measureText(str).width;
+            };
+            proto.showTip = function (hitinfo, text) {
+                return text && text !== '';
+            };
+            /**
+             * 获取点击信息
+             * @param {Number} x
+             * @param {Number} y
+             * @param {Object} cellStyle
+             * @param {Object} cellRect
+             * @param {Object} context
+             * @returns {{x: *, y: *, row: *, col: *|boolean|*[]|number|{}|UE.dom.dtd.col, cellStyle: *, cellRect: *, sheet: *|StyleSheet, sheetArea: *}}
+             */
+            proto.getHitInfo = function (x, y, cellStyle, cellRect, context) {
+                return {
+                    x: x,
+                    y: y,
+                    row: context.row,
+                    col: context.col,
+                    cellStyle: cellStyle,
+                    cellRect: cellRect,
+                    sheet: context.sheet,
+                    sheetArea: context.sheetArea,
+                    ctx: context.sheet.getParent().xs,
+                };
+            };
+            /**
+             * 鼠标进入单元格事件 - 显示悬浮提示
+             * @param {Object} hitinfo - 见getHitInfo返回值
+             */
+            proto.processMouseEnter = function (hitinfo) {
+                let text = hitinfo.sheet.getText(hitinfo.row, hitinfo.col);
+                const col = hitinfo.sheet.zh_setting.cols[hitinfo.col];
+                if (col.getTip && Object.prototype.toString.apply(col.getTip) === "[object Function]") {
+                    const sortData = SpreadJsObj.getSortData(hitinfo.sheet);
+                    text = col.getTip(sortData[hitinfo.row]);
+                }
+                const pos = SpreadJsObj.getObjPos(hitinfo.sheet.getParent().qo);
+                if (pos && this.showTip(hitinfo, text)) {
+                    if (!this._toolTipElement) {
+                        let div = $('#autoTip')[0];
+                        if (!div) {
+                            div = document.createElement("div");
+                            $(div).css("position", "absolute")
+                                .css("border", "1px #C0C0C0 solid")
+                                .css("box-shadow", "1px 2px 5px rgba(0,0,0,0.4)")
+                                .css("font", "9pt Arial")
+                                .css("background", "white")
+                                .css("padding", 5)
+                                .css("z-index", 999)
+                                .css("max-width", maxHintWidth)
+                                .css("word-wrap", "break-word")
+                                .attr("id", 'autoTip');
+                            document.body.insertBefore(div, null);
+                        }
+                        const validWidth = $(window).width() - (pos.x + hitinfo.x + indent) - borderIndent;
+                        const textWidth = this.getTextDisplayWidth(hitinfo, text, "9pt Arial");
+                        if (validWidth >= maxHintWidth || textWidth <= validWidth) {
+                            $(div).html(text).css("top", pos.y + hitinfo.y + indent).css("left", pos.x + hitinfo.x + indent);
+                        } else if (textWidth > maxHintWidth) {
+                            $(div).html(text).css("top", pos.y + hitinfo.y + indent).css("left", pos.x + hitinfo.x - indent - maxHintWidth);
+                        } else {
+                            $(div).html(text).css("top", pos.y + hitinfo.y + indent).css("left", pos.x + hitinfo.x - indent - textWidth);
+                        }
+                        this._toolTipElement = div;
+                        const self = this;
+                        setTimeout(()=>{ if (self._toolTipElement) $(self._toolTipElement).show("fast");}, 300);
+                    }
+                }
+            };
+            /**
+             * 鼠标移出单元格事件 - 隐藏悬浮提示
+             * @param {Object} hitinfo - 见getHitInfo返回值
+             */
+            proto.processMouseLeave = function (hitinfo) {
+                if (this._toolTipElement) {
+                    $(this._toolTipElement).hide();
+                    this._toolTipElement = null;
+                }
+            };
+
+            return new TipCellType();
+        },
         /**
          * 获取 带图片的cellType(图片需在document中定义好img,并写入col的img属性)
          *
@@ -2634,10 +2738,32 @@ const SpreadJsObj = {
         const getAnalysisPasteHtml = function () {
             return SpreadJsObj.analysisPasteHtml(cHtml);
         };
+        const setSysClipboard = function(text) {
+            let textArea = document.createElement("textarea");
+            textArea.style.position = 'fixed';
+            textArea.style.top = 0;
+            textArea.style.left = 0;
+            textArea.style.width = '2em';
+            textArea.style.height = '2em';
+            textArea.style.padding = 0;
+            textArea.style.border = 'none';
+            textArea.style.outline = 'none';
+            textArea.style.boxShadow = 'none';
+            textArea.style.background = 'transparent';
+            textArea.value = text;
+            document.body.appendChild(textArea);
+            textArea.select();
+            try {
+                document.execCommand('copy');
+            } catch (err) {
+            }
+            document.body.removeChild(textArea);
+        };
         return {
             setCopyData, getPasteData, clearData,
             setSheetFilterCopyData,
             getAnalysisPasteText, getAnalysisPasteHtml,
+            setSysClipboard
         }
     })(),
 };

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

@@ -1503,6 +1503,13 @@ $(document).ready(() => {
             return target.hitTestType === spreadNS.SheetArea.viewport || target.hitTestType === spreadNS.SheetArea.rowHeader;
         },
         items: {
+            copyDisplay: {
+                name: '仅复制可见数据',
+                callback: function (key, opt) {
+
+                }
+            },
+            copySpr: '----',
             'locateZjjl': {
                 name: '定位至中间计量',
                 icon: 'fa-sign-in',
@@ -3722,13 +3729,13 @@ $(document).ready(() => {
 
             this.changeBillsSpreadSetting = {
                 cols: [
-                    {title: '清单编号', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 80, formatter: '@', cellType: 'tip', getTip: getTipText},
-                    {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 150, type: 'Number', cellType: 'tip', getTip: getTipText},
-                    {title: '单位', colSpan: '1', rowSpan: '1', field: 'unit', hAlign: 1, width: 50, formatter: '@', cellType: 'tip', getTip: getTipText},
-                    {title: '单价', colSpan: '1', rowSpan: '1', field: 'unit_price', hAlign: 2, width: 60, type: 'Number', cellType: 'tip', getTip: getTipText},
-                    {title: '数量', colSpan: '1', rowSpan: '1', field: 'qty', hAlign: 2, width: 60, formatter: '@', cellType: 'tip', getTip: getTipText},
-                    {title: '金额', colSpan: '1', rowSpan: '1', field: 'tp', hAlign: 2, width: 60, formatter: '@', cellType: 'tip', getTip: getTipText},
-                    {title: '变更部位', colSpan: '1', rowSpan: '1', field: 'bwmx', hAlign: 0, width: 100, formatter: '@', cellType: 'tip', getTip: getTipText},
+                    {title: '清单编号', colSpan: '1', rowSpan: '1', field: 'code', hAlign: 0, width: 80, formatter: '@'},
+                    {title: '名称', colSpan: '1', rowSpan: '1', field: 'name', hAlign: 0, width: 150, type: 'Number', cellType: 'delayTip', getTip: getTipText},
+                    {title: '单位', colSpan: '1', rowSpan: '1', field: 'unit', hAlign: 1, width: 50, formatter: '@'},
+                    {title: '单价', colSpan: '1', rowSpan: '1', field: 'unit_price', hAlign: 2, width: 60, type: 'Number'},
+                    {title: '数量', colSpan: '1', rowSpan: '1', field: 'qty', hAlign: 2, width: 60, formatter: '@'},
+                    {title: '金额', colSpan: '1', rowSpan: '1', field: 'tp', hAlign: 2, width: 60, formatter: '@'},
+                    {title: '变更部位', colSpan: '1', rowSpan: '1', field: 'bwmx', hAlign: 0, width: 100, formatter: '@'},
                 ],
                 emptyRows: 0,
                 headRows: 1,

+ 5 - 2
app/public/js/stage_bwtz.js

@@ -90,8 +90,11 @@ $(document).ready(() => {
     xmjSpread.bind(spreadNS.Events.SelectionChanged, function (e, info) {
         unitTreeObj.loadCurUnitData();
     });
-    unitSpread.bind(spreadNS.Events.SelectionChanged, function (e, info) {
-        console.log(SpreadJsObj.getSelectObject(info.sheet));
+    xmjSpread.bind(spreadNS.Events.ClipboardChanged, function (e, info) {
+        SpreadJsObj.Clipboard.setSysClipboard(SpreadJsObj.getFilterCopyText(info.sheet));
+    });
+    unitSpread.bind(spreadNS.Events.ClipboardChanged, function (e, info) {
+        SpreadJsObj.Clipboard.setSysClipboard(SpreadJsObj.getFilterCopyText(info.sheet));
     });
     const loadData = function (dataType) {
         postData(window.location.pathname + '/load', {filter: dataType}, function (result) {

+ 15 - 0
app/public/js/stage_compare.js

@@ -275,6 +275,7 @@ $(document).ready(function () {
             $('#select-qi').modal('hide');
         }
     });
+
     // 显示层次
     (function (select, sheet) {
         $(select).click(function () {
@@ -304,6 +305,20 @@ $(document).ready(function () {
                         tree.expandByCalcFields();
                         SpreadJsObj.refreshTreeRowVisible(sheet);
                         break;
+                    case "hasDiffer":
+                        tree.expandByCustom((data) => {
+                            const fieldSufs = sheet.zh_setting.fieldSufs;
+                            if (fieldSufs.length <= 1) return false;
+                            const field = (!data.children || data.children.length === 0) && !data.is_tp ? 'gather_qty' : 'gather_tp';
+                            const base = data[field + fieldSufs[0]];
+                            for (let i = 1; i< fieldSufs.length; i++) {
+                                const compare = data[field + fieldSufs[i]];
+                                if ((base || compare) && (compare !== base)) return true;
+                            }
+                            return false;
+                        });
+                        SpreadJsObj.refreshTreeRowVisible(sheet);
+                        break;
                 }
                 closeWaitingView();
             }, 100);

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

@@ -369,6 +369,7 @@ $(document).ready(() => {
     // initTenderTree();
     // $('.c-body').html(getTenderTreeHtml());
     bindTenderUrl();
+    tenderTreeShowLevel.initShowLevel();
     // localHideList();
 
     // 分类

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

@@ -448,6 +448,7 @@ $(document).ready(() => {
     $('.c-body').html(getTenderTreeHtml());
     bindTenderUrl();
     localHideList();
+    tenderTreeShowLevel.initShowLevel();
     // 分类
     $('#cate-set').on('show.bs.modal', function () {
         createTree();

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

@@ -384,6 +384,7 @@ $(document).ready(() => {
     $('.c-body').html(getTenderTreeHtml());
     bindTenderUrl();
     localHideList();
+    tenderTreeShowLevel.initShowLevel();
     // 分类
     $('#cate-set').on('show.bs.modal', function () {
         createTree();

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

@@ -420,6 +420,7 @@ $(document).ready(() => {
     $('.c-body').html(getTenderTreeHtml());
     bindTenderUrl();
     localHideList();
+    tenderTreeShowLevel.initShowLevel();
     // 分类
     $('#cate-set').on('show.bs.modal', function () {
         createTree();

+ 75 - 2
app/public/js/tender_showhide.js

@@ -18,7 +18,7 @@ const findTenderTreeNode = function(sortId, tree) {
             findTenderTreeNode(sortId, item.children);
         }
     });
-}
+};
 
 function removeValueToCate(cate) {
     const changeCate = JSON.parse(JSON.stringify(cate));
@@ -29,6 +29,40 @@ function removeValueToCate(cate) {
     }
     return newCate;
 }
+
+function recursiveExpand(nodes, parent, checkFun) {
+    for (const node of nodes) {
+        const expanded = checkFun(node);
+        if (!expanded && node.sort_id) hideList.push({sort_id: node.sort_id});
+        if (node.expanded !== expanded) {
+            node.expanded = expanded;
+            if (node.sort_id) {
+                if (node.expanded) {
+                    $('.c-body tr td span[cid="' + node.sort_id + '"]').children('i').removeClass('fa-plus-square-o').addClass('fa-minus-square-o');
+                    $('.c-body tr td span[cid="' + node.sort_id + '"]').attr('title', '收起');
+                } else {
+                    $('.c-body tr td span[cid="' + node.sort_id + '"]').children('i').removeClass('fa-minus-square-o').addClass('fa-plus-square-o');
+                    $('.c-body tr td span[cid="' + node.sort_id + '"]').attr('title', '展开');
+                }
+                doTrStatus(node, node.expanded ? 'show' : 'hide');
+            }
+        }
+        node.visible = parent ? (parent.expanded && parent.visible) : true;
+        if (node.children) recursiveExpand(node.children, node, checkFun);
+    }
+}
+function expandByCustom(checkFun) {
+    hideList = [];
+    recursiveExpand(tenderTree, null, checkFun);
+}
+
+function expandByLevel(level) {
+    expandByCustom(function (n) {
+        return n.level < level;
+    });
+    setLocalCache(uphlname, JSON.stringify(hideList));
+}
+
 // 根据标段类别设置排序
 function sortTenderTree(teTree = tenderTree) {
     for (const tender of teTree) {
@@ -120,6 +154,8 @@ function doTrStatus(node, status, all = '') {
     }
 }
 
+let tenderTreeShowLevel;
+
 $(document).ready(() => {
     // 展开和收起
     $('body').on('click', '.fold-switch', function () {
@@ -169,7 +205,44 @@ $(document).ready(() => {
             }
         }
         setTopTr();
-    })
+    });
+
+    tenderTreeShowLevel = $.cs_showLevel({
+        selector: '#show-level',
+        levels: [
+            {
+                type: 'sort', count: function () {
+                    const getChildrenLevel = function (node) {
+                        let iLevel = node.level;
+                        if (node.children && node.children.length > 0) {
+                            for (const c of node.children) {
+                                iLevel = Math.max(iLevel, getChildrenLevel(c));
+                            }
+                        }
+                        return iLevel;
+                    };
+                    return tenderTree.map(getChildrenLevel).reduce((x, y) => { return Math.max(x, y); }, 0) - 1;
+                }
+            },
+            { type: 'last', title: '最底层' },
+        ],
+        showLevel: function (tag) {
+
+            switch (tag) {
+                case "1":
+                case "2":
+                case "3":
+                case "4":
+                case "5":
+                    expandByLevel(parseInt(tag));
+                    break;
+                case "last":
+                    expandByLevel(20);
+                    break;
+                default: return;
+            }
+        }
+    });
 });
 
 

+ 35 - 4
app/service/material.js

@@ -149,6 +149,7 @@ module.exports = app => {
                 material_tax: this.ctx.session.sessionProject.page_show.openMaterialTax,
                 decimal: preMaterial && preMaterial.decimal ? preMaterial.decimal : JSON.stringify(materialConst.decimal),
                 is_new: 1,
+                is_stage_self: data.is_stage_self,
             };
             const transaction = await this.db.beginTransaction();
             try {
@@ -166,6 +167,25 @@ module.exports = app => {
                 } else {
                     throw '新增期数据失败';
                 }
+                const insertMaterialStage = [];
+                if (data.is_stage_self) {
+                    // 新建多期单独单价表,工料表
+                    for (const [i, d] of data.stage_id.entries()) {
+                        insertMaterialStage.push({
+                            tid: tenderId,
+                            mid: newMaterial.id,
+                            sid: d,
+                            order: data.s_order.split(',')[i],
+                        });
+                    }
+                    if (insertMaterialStage.length > 0) {
+                        const resultStage = await transaction.insert(this.ctx.service.materialStage.tableName, insertMaterialStage);
+                        // 获取刚批量添加的所有list
+                        for (let j = 0; j < insertMaterialStage.length; j++) {
+                            insertMaterialStage[j].id = resultStage.insertId + j;
+                        }
+                    }
+                }
                 // 存在上一期时,复制上一期审批流程、不参与调差的清单、上期清单并算本期有效价差,本期应耗数量,并算本期总金额
                 if (preMaterial) {
                     const auditResult = await this.ctx.service.materialAudit.copyPreMaterialAuditors(transaction, preMaterial, newMaterial);
@@ -180,13 +200,19 @@ module.exports = app => {
                     await this.ctx.service.materialListSelf.copyNewStageSelfList(transaction, preSelfList, newMaterial.id);
                     // 复制调差清单工料关联表
                     // await this.ctx.service.materialList.copyPreMaterialList(transaction, preMaterial, newMaterial);
-                    await this.ctx.service.materialList.copyPreMaterialList2(transaction, data.material_list, data.material_self_list, preNotJoinList, newMaterial);
+                    await this.ctx.service.materialList.copyPreMaterialList2(transaction, data.material_list, data.material_self_list, preNotJoinList, newMaterial, insertMaterialStage);
                     // 新增或删除list_gcl表
                     await this.ctx.service.materialListGcl.insertOrDelGcl(transaction, data.insertGclList, data.removeGclList, newMaterial.id);
                     // 设置list_gcl表old=>new更新
                     await this.ctx.service.materialListGcl.setNewOldData(transaction, this.ctx.tender.id);
                     // 修改本期应耗数量值和有效价差,需要剔除不参与调差的清单数据,并返回总金额
-                    const [m_tp, m_tax_tp] = await this.ctx.service.materialBills.updateNewMaterial(transaction, this.ctx.tender.id, newMaterial.id, this.ctx, newMaterial.stage_id, JSON.parse(newMaterial.decimal));
+                    let m_tp = null;
+                    let m_tax_tp = null;
+                    if (data.is_stage_self) {
+                        [m_tp, m_tax_tp] = await this.ctx.service.materialStageBills.insertBills(transaction, this.ctx.tender.id, newMaterial.id, newMaterial.stage_id, insertMaterialStage, JSON.parse(newMaterial.decimal));
+                    } else {
+                        [m_tp, m_tax_tp] = await this.ctx.service.materialBills.updateNewMaterial(transaction, this.ctx.tender.id, newMaterial.id, this.ctx, newMaterial.stage_id, JSON.parse(newMaterial.decimal));
+                    }
                     // 修改现行价格指数,并返回调差基数json
                     const ex_calc = await this.ctx.service.materialExponent.updateNewMaterial(transaction, newMaterial.id, this.ctx, newMaterial.stage_id, preMaterial.ex_calc, JSON.parse(newMaterial.decimal));
                     // 计算得出本期总金额
@@ -273,6 +299,10 @@ module.exports = app => {
                 await this.ctx.service.materialListGcl.setNewOldData(transaction, this.ctx.tender.id, 'old2new');
                 // 还要从material_list表更新gcl的old数据,更新方法
                 await this.ctx.service.materialListGcl.setOldFromLast(transaction, this.ctx.tender.id, materialInfo.order - 2);
+                if (materialInfo.is_stage_self) {
+                    await transaction.delete(this.ctx.service.materialStage.tableName, { mid: id });
+                    await transaction.delete(this.ctx.service.materialStageBills.tableName, { mid: id });
+                }
                 await transaction.delete(this.tableName, { id });
                 // 记录删除日志
                 await this.ctx.service.projectLog.addProjectLog(transaction, projectLogConst.type.material, projectLogConst.status.delete, '第' + materialInfo.order + '期');
@@ -417,12 +447,13 @@ module.exports = app => {
             return result && result.count !== 0;
         }
 
-        async saveDecimal(newUp, newTp) {
+        async saveDecimal(newUp, newTp, newQty) {
             const transaction = await this.db.beginTransaction();
             try {
-                await this.ctx.service.materialBills.resetDecimal(transaction, newUp, newTp);
+                await this.ctx.service.materialBills.resetDecimal(transaction, newUp, newTp, newQty);
                 this.ctx.material.decimal.up = newUp;
                 this.ctx.material.decimal.tp = newTp;
+                this.ctx.material.decimal.qty = newQty;
                 const m_tp = await this.ctx.service.materialBills.calcMaterialMTp(transaction);
                 let update_calc = false;
                 if (this.ctx.material.ex_calc) {

+ 275 - 57
app/service/material_bills.js

@@ -36,6 +36,7 @@ module.exports = app => {
             const order = await this._getMaxOrder(this.ctx.tender.id);
             const transaction = await this.db.beginTransaction();
             try {
+                const resultData = {};
                 const newBills = {
                     tid: this.ctx.tender.id,
                     mid: this.ctx.material.id,
@@ -47,6 +48,10 @@ module.exports = app => {
                 if (result.affectedRows !== 1) {
                     throw '新增工料数据失败';
                 }
+                if (this.ctx.material.is_stage_self) {
+                    await this.ctx.service.materialStageBills.add(transaction, result.insertId);
+                    resultData.pushStageBillsData = await transaction.select(this.ctx.service.materialStageBills.tableName, { where: { mid: this.ctx.material.id, mb_id: result.insertId } });
+                }
                 const insertArray = [];
                 const material_month = this.ctx.material.months ? this.ctx.material.months.split(',') : [];
                 for (const ym of material_month) {
@@ -61,7 +66,8 @@ module.exports = app => {
                 }
                 if (insertArray.length !== 0) await transaction.insert(this.ctx.service.materialMonth.tableName, insertArray);
                 await transaction.commit();
-                return await this.getDataById(result.insertId);
+                resultData.info = await this.getDataById(result.insertId);
+                return resultData;
             } catch (error) {
                 console.log(error);
                 await transaction.rollback();
@@ -88,19 +94,35 @@ module.exports = app => {
             // 判断t_type是否为费用,且存在quantity,m_spread值
             const transaction = await this.db.beginTransaction();
             try {
+                // 防止多页面操作时,清单工料含量存在时工料可删
+                const materialListNum = await this.ctx.service.materialList.count({ tid: this.ctx.tender.id, mb_id: id });
+                if (materialListNum > 0) {
+                    throw '该工料已存在对应的清单工料含量,删除失败';
+                }
                 const mbInfo = await this.getDataById(id);
                 await transaction.delete(this.tableName, { id });
-                let m_tp = this.ctx.material.m_tp;
-                if (mbInfo.t_type === materialConst.t_type[1].value && mbInfo.quantity !== null && mbInfo.m_spread !== null) {
+                const m_tp = this.ctx.material.m_tp;
+                const result = { m_tp };
+                if (this.ctx.material.is_stage_self) {
+                    await transaction.delete(this.ctx.service.materialStageBills.tableName, { mb_id: id });
+                    // 金额发生变化,则重新计算本期金额
+                    for (const sid of this.ctx.material.stage_id.split(',')) {
+                        const msInfo = await transaction.get(this.ctx.service.materialStage.tableName, { tid: this.ctx.tender.id, sid });
+                        await this.ctx.service.materialStage.updateMtp(transaction, msInfo.id);
+                    }
+                    result.stageBillsData = await transaction.select(this.ctx.service.materialStageBills.tableName, { where: { mid: this.ctx.material.id } });
+                    result.stageData = await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: this.ctx.material.id } });
+                    result.m_tp = await this.calcMaterialMTp(transaction);
+                } else if (mbInfo.t_type === materialConst.t_type[1].value && mbInfo.quantity !== null && mbInfo.m_spread !== null) {
                     // 金额发生变化,则重新计算本期金额
-                    m_tp = await this.calcMaterialMTp(transaction);
+                    result.m_tp = await this.calcMaterialMTp(transaction);
                 }
                 const material_month = this.ctx.material.months ? this.ctx.material.months.split(',') : [];
                 if (material_month.length > 0) {
                     await transaction.delete(this.ctx.service.materialMonth.tableName, { mb_id: id });
                 }
                 await transaction.commit();
-                return m_tp;
+                return result;
             } catch (err) {
                 await transaction.rollback();
                 throw err;
@@ -143,7 +165,7 @@ module.exports = app => {
          * @param {Object} data 工料内容
          * @return {void}
          */
-        async save(data) {
+        async save(data, ms_id = null) {
             if (!this.ctx.tender || !this.ctx.material) {
                 throw '数据错误';
             }
@@ -153,16 +175,90 @@ module.exports = app => {
             // 判断t_type是否为费用
             const transaction = await this.db.beginTransaction();
             try {
+                const result = {};
+                if (this.ctx.material.is_stage_self) {
+                    if (!ms_id) {
+                        throw '期参数有误';
+                    }
+                    const needUp = await this.updateOneBillsData(transaction, data, ms_id);
+                    const [one_m_tp, one_tax_tp] = await this.ctx.service.materialStageBills.update(transaction, data, ms_id);
+                    // 更新materialStage 值
+                    data.m_tp = this.ctx.helper.round(one_m_tp, this.ctx.material.decimal.tp);
+                    data.m_tax_tp = this.ctx.helper.round(one_tax_tp, this.ctx.material.decimal.tp);
+                    data.quantity = null;
+                    data.msg_tp = null;
+                    data.msg_times = null;
+                    data.msg_spread = null;
+                    data.m_spread = null;
+                    delete data.ms_id;
+
+                    // 更新materialStage 值
+                    await this.ctx.service.materialStage.updateMtp(transaction, ms_id);
+                    result.stageBillsData = this.ctx.material.is_stage_self && needUp ?
+                        await transaction.select(this.ctx.service.materialStageBills.tableName, { where: { mid: this.ctx.material.id, mb_id: data.id } }) :
+                        await transaction.select(this.ctx.service.materialStageBills.tableName, { where: { mid: this.ctx.material.id, ms_id, mb_id: data.id } });
+                    result.stageData = this.ctx.material.is_stage_self && needUp ?
+                        await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: this.ctx.material.id } }) :
+                        await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: this.ctx.material.id, id: ms_id } });
+                }
                 await transaction.update(this.tableName, data);
-                const m_tp = await this.calcMaterialMTp(transaction);
+                result.m_tp = await this.calcMaterialMTp(transaction);
                 await transaction.commit();
-                return m_tp;
+                return result;
             } catch (err) {
                 await transaction.rollback();
                 throw err;
             }
         }
 
+        async updateOneBillsData(transaction, data, ms_id) {
+            // 当以下值和bills值不相同时,需要同步更新最新的计算值到stageBills表里
+            const updateColsArray = ['t_type', 'm_tax', 'basic_price', 'm_up_risk', 'm_down_risk', 'is_summary'];
+            let needUp = null;
+            const mbInfo = await this.getDataById(data.id);
+            for (const uc of updateColsArray) {
+                if (data[uc] !== undefined && data[uc] !== mbInfo[uc]) {
+                    needUp = uc;
+                    break;
+                }
+            }
+            if (needUp) {
+                const msList = await this.ctx.service.materialStage.getAllDataByCondition({ where: { mid: this.ctx.material.id } });
+                for (const ms of msList) {
+                    if (ms.id !== parseInt(ms_id)) {
+                        const msbInfo = await this.ctx.service.materialStageBills.getDataByCondition({
+                            mid: this.ctx.material.id,
+                            ms_id: ms.id,
+                            mb_id: data.id,
+                        });
+                        const updateData = {
+                            id: msbInfo.id,
+                        };
+                        if (needUp === 'm_tax') {
+                            updateData.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(msbInfo.m_tp, (1 + this.ctx.helper.div(data.m_tax, 100))), this.ctx.material.decimal.tp);
+                        } else if (needUp === 'm_up_risk' || needUp === 'm_down_risk' || needUp === 'basic_price') {
+                            const basic_price = needUp === 'basic_price' ? data.basic_price : mbInfo.basic_price;
+                            const [msg_spread, m_spread] = await this.getSpread(mbInfo, msbInfo.msg_tp, this.ctx.material.decimal.up, basic_price);
+                            updateData.msg_spread = msg_spread;
+                            updateData.m_spread = m_spread;
+                            const newTp = this.ctx.helper.round(this.ctx.helper.mul(msbInfo.quantity, m_spread), this.ctx.material.decimal.tp);
+                            updateData.m_tp = newTp;
+                            updateData.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mbInfo.m_tax, 100))), this.ctx.material.decimal.tp);
+                        } else if (needUp === 't_type') {
+                            updateData.quantity = null;
+                            updateData.m_tp = null;
+                            updateData.m_tax_tp = null;
+                        } else if (needUp === 'is_summary') {
+                            updateData.is_summary = data.is_summary;
+                        }
+                        await transaction.update(this.ctx.service.materialStageBills.tableName, updateData);
+                        await this.ctx.service.materialStage.updateMtp(transaction, ms.id);
+                    }
+                }
+            }
+            return needUp;
+        }
+
         async saveOrigin(data) {
             if (!this.ctx.tender || !this.ctx.material) {
                 throw '数据错误';
@@ -190,7 +286,7 @@ module.exports = app => {
          * @param {Object} data 工料内容
          * @return {void}
          */
-        async saveDatas(datas) {
+        async saveDatas(datas, ms_id = null) {
             if (!this.ctx.tender || !this.ctx.material) {
                 throw '数据错误';
             }
@@ -200,15 +296,34 @@ module.exports = app => {
             try {
                 for (const data of datas) {
                     delete data.in_time;
+                    let needUp = null;
+                    if (this.ctx.material.is_stage_self) {
+                        needUp = await this.updateOneBillsData(transaction, data, ms_id);
+                        const [one_m_tp, one_tax_tp] = await this.ctx.service.materialStageBills.update(transaction, data, ms_id);
+                        // 更新materialStage 值
+                        data.m_tp = this.ctx.helper.round(one_m_tp, this.ctx.material.decimal.tp);
+                        data.m_tax_tp = this.ctx.helper.round(one_tax_tp, this.ctx.material.decimal.tp);
+                        data.quantity = null;
+                        data.msg_tp = null;
+                        data.msg_times = null;
+                        data.msg_spread = null;
+                        data.msg_spread = null;
+                        data.m_spread = null;
+                    }
                     // delete data.m_tp;
                     // console.log(data);
                     await transaction.update(this.tableName, data);
                 }
-                // console.log(datas);
-                // await transaction.update(this.tableName, datas);
-                const m_tp = await this.calcMaterialMTp(transaction);
+                // 更新materialStage 值
+                const result = {};
+                if (this.ctx.material.is_stage_self) {
+                    await this.ctx.service.materialStage.updateMtp(transaction, ms_id);
+                    result.stageBillsData = await transaction.select(this.ctx.service.materialStageBills.tableName, { where: { mid: this.ctx.material.id } });
+                    result.stageData = await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: this.ctx.material.id } });
+                }
+                result.m_tp = await this.calcMaterialMTp(transaction);
                 await transaction.commit();
-                return m_tp;
+                return result;
             } catch (err) {
                 await transaction.rollback();
                 throw err;
@@ -297,10 +412,11 @@ module.exports = app => {
          * @param data
          * @returns {Promise<void>}
          */
-        async getSpread(data, msg_tp, newDecimalUp = this.ctx.material.decimal.up) {
+        async getSpread(data, msg_tp, newDecimalUp = this.ctx.material.decimal.up, basic_price = null) {
             data.msg_tp = msg_tp;
-            const msg_spread = this.ctx.helper.round(this.ctx.helper.sub(data.msg_tp, data.basic_price), newDecimalUp);
-            const cor = msg_spread >= 0 ? this.ctx.helper.mul(data.basic_price, this.ctx.helper.div(data.m_up_risk, 100)) : this.ctx.helper.mul(data.basic_price, this.ctx.helper.div(data.m_down_risk, 100));
+            const newBp = basic_price ? basic_price : data.basic_price;
+            const msg_spread = this.ctx.helper.round(this.ctx.helper.sub(data.msg_tp, newBp), newDecimalUp);
+            const cor = msg_spread >= 0 ? this.ctx.helper.mul(newBp, this.ctx.helper.div(data.m_up_risk, 100)) : this.ctx.helper.mul(newBp, this.ctx.helper.div(data.m_down_risk, 100));
             const m_spread = Math.abs(msg_spread) > Math.abs(cor) ? (msg_spread > 0 ? this.ctx.helper.round(this.ctx.helper.sub(msg_spread, cor), newDecimalUp) : this.ctx.helper.round(this.ctx.helper.add(msg_spread, cor), newDecimalUp)) : 0;
             return [msg_spread, m_spread];
         }
@@ -316,19 +432,60 @@ module.exports = app => {
             }
             const transaction = await this.db.beginTransaction();
             try {
-                const mbInfo = await this.getDataById(data.id);
-                data.m_tp = this.ctx.helper.round(this.ctx.helper.mul(data.quantity, mbInfo.m_spread), this.ctx.material.decimal.tp);
-                data.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(data.m_tp, (1 + this.ctx.helper.div(mbInfo.m_tax, 100))), this.ctx.material.decimal.tp);
-                await transaction.update(this.tableName, data);
-                let m_tp = this.ctx.material.m_tp;
-                if (mbInfo.quantity !== data.quantity) {
-                    m_tp = await this.calcMaterialMTp(transaction);
+                const returnData = {};
+                returnData.m_tp = this.ctx.material.m_tp;
+                if (this.ctx.material.is_stage_self) {
+                    const mbInfo = await this.getDataById(data.id);
+                    let all_m_tp = 0;
+                    let all_tax_tp = 0;
+                    for (const sid of this.ctx.material.stage_id.split(',')) {
+                        const materialCalculator = new MaterialCalculator(this.ctx, sid, this.ctx.tender.info);
+                        const quantity = await materialCalculator.calculateExpr(data.expr);
+                        const msInfo = await this.ctx.service.materialStage.getDataByCondition({ mid: this.ctx.material.id, sid });
+                        const msbInfo = await this.ctx.service.materialStageBills.getDataByCondition({ mid: this.ctx.material.id, mb_id: data.id, ms_id: msInfo.id });
+                        const newQuantity = quantity !== 0 ? this.ctx.helper.round(quantity, this.ctx.material.decimal.qty) : null;
+                        const m_tp = newQuantity ? this.ctx.helper.round(this.ctx.helper.mul(newQuantity, msbInfo.m_spread), this.ctx.material.decimal.tp) : null;
+                        const updateData = {
+                            id: data.id,
+                            quantity: newQuantity,
+                            m_tp,
+                            m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(m_tp, (1 + this.ctx.helper.div(mbInfo.m_tax, 100))), this.ctx.material.decimal.tp),
+                        };
+                        const [one_bill_m_tp, one_bill_tax_tp] = await this.ctx.service.materialStageBills.update(transaction, updateData, msInfo.id);
+                        await this.ctx.service.materialStage.updateMtp(transaction, msInfo.id);
+                        all_m_tp = this.ctx.helper.round(one_bill_m_tp, this.ctx.material.decimal.tp);
+                        all_tax_tp = this.ctx.helper.round(one_bill_tax_tp, this.ctx.material.decimal.tp);
+                    }
+                    const updateBillsData = {
+                        id: data.id,
+                        expr: data.expr,
+                        m_tp: all_m_tp ? all_m_tp : null,
+                        m_tax_tp: all_tax_tp ? all_tax_tp : null,
+                    };
+                    console.log(all_m_tp);
+                    await transaction.update(this.tableName, updateBillsData);
+                    returnData.m_tp = await this.calcMaterialMTp(transaction);
+                    returnData.stageBillsData = await transaction.select(this.ctx.service.materialStageBills.tableName, { where: { mid: this.ctx.material.id, mb_id: data.id } });
+                    returnData.stageData = await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: this.ctx.material.id } });
+                } else {
+                    const materialCalculator = new MaterialCalculator(this.ctx, this.ctx.material.stage_id, this.ctx.tender.info);
+                    const quantity = await materialCalculator.calculateExpr(data.expr);
+                    // 更新quantity值并重新返回计算本期金额,截止本期金额
+                    const updateData = {
+                        id: data.id,
+                        quantity: quantity !== 0 ? this.ctx.helper.round(quantity, this.ctx.material.decimal.qty) : null,
+                        expr: data.expr,
+                    };
+                    const mbInfo = await this.getDataById(updateData.id);
+                    updateData.m_tp = this.ctx.helper.round(this.ctx.helper.mul(updateData.quantity, mbInfo.m_spread), this.ctx.material.decimal.tp);
+                    updateData.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(updateData.m_tp, (1 + this.ctx.helper.div(mbInfo.m_tax, 100))), this.ctx.material.decimal.tp);
+                    await transaction.update(this.tableName, updateData);
+                    if (mbInfo.quantity !== updateData.quantity) {
+                        returnData.m_tp = await this.calcMaterialMTp(transaction);
+                    }
                 }
                 await transaction.commit();
-                const returnData = {
-                    m_tp,
-                    info: await this.getDataById(data.id),
-                }
+                returnData.info = await this.getDataById(data.id);
                 return returnData;
             } catch (err) {
                 await transaction.rollback();
@@ -356,49 +513,110 @@ module.exports = app => {
         }
 
         // 小数位变化更新单价和金额
-        async resetDecimal(transaction, newDecimalUp, newDecimalTp) {
+        async resetDecimal(transaction, newDecimalUp, newDecimalTp, newDecimalQty) {
             const mbList = await transaction.select(this.tableName, { where: { tid: this.ctx.tender.id }, orders: [['order', 'asc']] });
             const updateList = [];
             const material_month = this.ctx.material.months ? this.ctx.material.months.split(',') : [];
             const updateMonthList = [];
+            const materialStageList = this.ctx.material.is_stage_self ? await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: this.ctx.material.id } }) : [];
             for (const mb of mbList) {
                 const updateData = {
                     id: mb.id,
                 };
-                if (newDecimalUp !== this.ctx.material.decimal.up) {
-                    let newmsg_tp = this.ctx.helper.round(mb.msg_tp, newDecimalUp);
-                    mb.msg_tp = newmsg_tp;
-                    // 判断是否有月信息价,如果有则msg_tp值由月信息价的平均单价获得,并更新月信息价单价
-                    if (material_month.length > 0) {
-                        const monthList = await transaction.select(this.ctx.service.materialMonth.tableName, { where: { mb_id: mb.id, mid: this.ctx.material.id } });
-                        if (monthList.length !== 0) {
-                            for (const m of monthList) {
-                                // 更新月信息单价小数位
-                                const newMonthMsgTP = this.ctx.helper.round(m.msg_tp, newDecimalUp);
-                                if (m.msg_tp && newMonthMsgTP !== m.msg_tp) {
-                                    m.msg_tp = newMonthMsgTP;
-                                    updateMonthList.push({ id: m.id, msg_tp: m.msg_tp });
+                if (this.ctx.material.is_stage_self) {
+                    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 });
+                        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 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);
+                            if (newQuantity !== msb.quantity) {
+                                updateStageBillData.quantity = newQuantity;
+                                msb.quantity = newQuantity;
+                            }
+                        }
+                        if (newDecimalUp !== this.ctx.material.decimal.up) {
+                            const newmsg_tp = this.ctx.helper.round(msb.msg_tp, newDecimalUp);
+                            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;
+                            updateStageBillData.msg_tp = newmsg_tp;
+                            updateStageBillData.msg_spread = newmsg_spread;
+                            updateStageBillData.m_spread = newm_spread;
+                        }
+                        const newTp = this.ctx.helper.round(this.ctx.helper.mul(msb.quantity, msb.m_spread), newDecimalTp);
+                        updateStageBillData.m_tp = newTp;
+                        updateStageBillData.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), newDecimalTp);
+                        updateStageBillsList.push(updateStageBillData);
+                    }
+                    if (newDecimalUp !== this.ctx.material.decimal.up) {
+                        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';
+                    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);
+                        mb.msg_tp = newmsg_tp;
+                        // 判断是否有月信息价,如果有则msg_tp值由月信息价的平均单价获得,并更新月信息价单价
+                        if (material_month.length > 0) {
+                            const monthList = await transaction.select(this.ctx.service.materialMonth.tableName, { where: { mb_id: mb.id, mid: this.ctx.material.id } });
+                            if (monthList.length !== 0) {
+                                for (const m of monthList) {
+                                    // 更新月信息单价小数位
+                                    const newMonthMsgTP = this.ctx.helper.round(m.msg_tp, newDecimalUp);
+                                    if (m.msg_tp && newMonthMsgTP !== m.msg_tp) {
+                                        m.msg_tp = newMonthMsgTP;
+                                        updateMonthList.push({ id: m.id, msg_tp: m.msg_tp });
+                                    }
                                 }
+                                const mb_msg_tp_sum = this._.sumBy(monthList, 'msg_tp');
+                                const month_num = material_month.length - this.ctx.helper.arrayCount(this._.map(monthList, 'msg_tp'), [null, '', 0]);
+                                newmsg_tp = month_num !== 0 ? this.ctx.helper.round(this.ctx.helper.div(mb_msg_tp_sum, month_num), newDecimalUp) : null;
+                                mb.msg_tp = newmsg_tp;
                             }
-                            const mb_msg_tp_sum = this._.sumBy(monthList, 'msg_tp');
-                            const month_num = material_month.length - this.ctx.helper.arrayCount(this._.map(monthList, 'msg_tp'), [null, '', 0]);
-                            newmsg_tp = month_num !== 0 ? this.ctx.helper.round(this.ctx.helper.div(mb_msg_tp_sum, month_num), newDecimalUp) : null;
-                            mb.msg_tp = newmsg_tp;
                         }
+                        const newbasic_price = this.ctx.helper.round(mb.basic_price, newDecimalUp);
+                        mb.basic_price = newbasic_price;
+                        const [newmsg_spread, newm_spread] = await this.getSpread(mb, mb.msg_tp, newDecimalUp);
+                        mb.m_spread = newm_spread;
+                        updateData.basic_price = newbasic_price;
+                        updateData.msg_tp = newmsg_tp;
+                        updateData.msg_spread = newmsg_spread;
+                        updateData.m_spread = newm_spread;
                     }
-                    const newbasic_price = this.ctx.helper.round(mb.basic_price, newDecimalUp);
-                    mb.basic_price = newbasic_price;
-                    const [newmsg_spread, newm_spread] = await this.getSpread(mb, mb.msg_tp, newDecimalUp);
-                    mb.m_spread = newm_spread;
-                    updateData.basic_price = newbasic_price;
-                    updateData.msg_tp = newmsg_tp;
-                    updateData.msg_spread = newmsg_spread;
-                    updateData.m_spread = newm_spread;
+                    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 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);
+                        mb.quantity = newQuantity;
+                        updateData.quantity = newQuantity;
+                    }
+                    const newTp = this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, mb.m_spread), newDecimalTp);
+                    updateData.m_tp = newTp;
+                    updateData.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), newDecimalTp);
+                    updateList.push(updateData);
+                }
+            }
+            if (this.ctx.material.is_stage_self) {
+                for (const ms of materialStageList) {
+                    await this.ctx.service.materialStage.updateMtp(transaction, ms.id);
                 }
-                const newTp = this.ctx.helper.round(this.ctx.helper.mul(mb.quantity, mb.m_spread), newDecimalTp);
-                updateData.m_tp = newTp;
-                updateData.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), newDecimalTp);
-                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);

+ 82 - 21
app/service/material_list.js

@@ -27,7 +27,7 @@ module.exports = app => {
          * 添加工料清单关联
          * @return {void}
          */
-        async add(data) {
+        async add(data, ms_id = null) {
             if (!this.ctx.tender || !this.ctx.material) {
                 throw '数据错误';
             }
@@ -44,6 +44,7 @@ module.exports = app => {
                     gather_qty: data.gather_qty,
                     is_join: data.is_join,
                     is_self: 1,
+                    ms_id: ms_id ? ms_id : null,
                     in_time: new Date(),
                 };
                 list.push(newLists);
@@ -62,7 +63,7 @@ module.exports = app => {
          * @param {int} id 工料id
          * @return {void}
          */
-        async del(id, mb_id) {
+        async del(id, mb_id, ms_id = null) {
             if (!this.ctx.tender || !this.ctx.material) {
                 throw '数据错误';
             }
@@ -70,7 +71,7 @@ module.exports = app => {
             try {
                 // 判断是否可删
                 await transaction.delete(this.tableName, { id });
-                await this.calcQuantityByML(transaction, mb_id);
+                await this.calcQuantityByML(transaction, mb_id, ms_id);
                 await transaction.commit();
                 return true;
             } catch (err) {
@@ -85,7 +86,7 @@ module.exports = app => {
          * @param {int} order 期数
          * @return {void}
          */
-        async save(data, order) {
+        async save(data, ms_id = null) {
             if (!this.ctx.tender || !this.ctx.material) {
                 throw '数据错误';
             }
@@ -95,7 +96,7 @@ module.exports = app => {
                 const mb_id = data.mb_id;
                 delete data.mb_id;
                 await transaction.update(this.tableName, data);
-                await this.calcQuantityByML(transaction, mb_id);
+                await this.calcQuantityByML(transaction, mb_id, ms_id);
                 await transaction.commit();
                 return true;
             } catch (err) {
@@ -109,7 +110,7 @@ module.exports = app => {
          * @param {Object} data 工料内容
          * @return {void}
          */
-        async saveDatas(datas) {
+        async saveDatas(datas, ms_id = null) {
             if (!this.ctx.tender || !this.ctx.material) {
                 throw '数据错误';
             }
@@ -121,7 +122,7 @@ module.exports = app => {
                     const mb_id = data.mb_id;
                     delete data.mb_id;
                     await transaction.update(this.tableName, data);
-                    await this.calcQuantityByML(transaction, mb_id);
+                    await this.calcQuantityByML(transaction, mb_id, ms_id);
                 }
                 await transaction.commit();
                 return true;
@@ -209,25 +210,76 @@ module.exports = app => {
          * @param mb_id
          * @return {Promise<*>}
          */
-        async calcQuantityByML(transaction, mb_id) {
+        async calcQuantityByML(transaction, mb_id, ms_id = null, updateAllStage = '') {
             // 修改material_bills值
             const mbInfo = await this.ctx.service.materialBills.getDataById(mb_id);
             if (!mbInfo) {
                 throw '不存在该工料';
             }
-            const sql = 'SELECT SUM(`gather_qty`*`quantity`) as quantity FROM ' + this.tableName + ' WHERE `mid`=? AND `mb_id`=? AND `is_join`=1';
+            let m_spread = mbInfo.m_spread;
+            let updateId = mb_id;
+            if (ms_id) {
+                const msbInfo = await this.ctx.service.materialStageBills.getDataByCondition({ mid: this.ctx.material.id, mb_id, ms_id });
+                m_spread = msbInfo.m_spread;
+                updateId = msbInfo.id;
+            }
+            const msSql = ms_id ? ' AND `ms_id` = ' + ms_id : '';
+            const sql = 'SELECT SUM(`gather_qty`*`quantity`) as quantity FROM ' + this.tableName + ' WHERE `mid`=? AND `mb_id`=?' + msSql + ' AND `is_join`=1';
             const sqlParam = [this.ctx.material.id, mb_id];
             const mb_quantity = await transaction.queryOne(sql, sqlParam);
             console.log(mb_quantity);
             const newQuantity = this.ctx.helper.round(mb_quantity.quantity, this.ctx.material.decimal.qty);
-            const newTp = this.ctx.helper.round(this.ctx.helper.mul(newQuantity, mbInfo.m_spread), this.ctx.material.decimal.tp);
+            const newTp = this.ctx.helper.round(this.ctx.helper.mul(newQuantity, m_spread), this.ctx.material.decimal.tp);
             const updateData = {
-                id: mb_id,
+                id: updateId,
                 quantity: newQuantity,
                 m_tp: newTp,
                 m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mbInfo.m_tax, 100))), this.ctx.material.decimal.tp),
             };
-            await transaction.update(this.ctx.service.materialBills.tableName, updateData);
+            if (ms_id) {
+                await transaction.update(this.ctx.service.materialStageBills.tableName, updateData);
+                await this.ctx.service.materialStage.updateMtp(transaction, ms_id);
+                if (updateAllStage === 'all') {
+                    const updateDatas = [];
+                    const updateMsIds = [];
+                    const msbList = await transaction.select(this.ctx.service.materialStageBills.tableName, { where: { mid: this.ctx.material.id, mb_id } });
+                    for (const msb of msbList) {
+                        if (msb.ms_id !== parseInt(ms_id)) {
+                            const sql4 = 'SELECT SUM(`gather_qty`*`quantity`) as quantity FROM ' + this.tableName + ' WHERE `mid`=? AND `mb_id`=? AND `ms_id`=? AND `is_join`=1';
+                            const sqlParam4 = [this.ctx.material.id, mb_id, msb.ms_id];
+                            const mb_quantity4 = await transaction.queryOne(sql4, sqlParam4);
+                            const newQuantity4 = this.ctx.helper.round(mb_quantity4.quantity, this.ctx.material.decimal.qty);
+                            const newTp4 = this.ctx.helper.round(this.ctx.helper.mul(newQuantity4, msb.m_spread), this.ctx.material.decimal.tp);
+                            const updateData4 = {
+                                id: msb.id,
+                                quantity: newQuantity4,
+                                m_tp: newTp4,
+                                m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp4, (1 + this.ctx.helper.div(mbInfo.m_tax, 100))), this.ctx.material.decimal.tp),
+                            };
+                            updateDatas.push(updateData4);
+                            updateMsIds.push(msb.ms_id);
+                        }
+                    }
+                    if (updateDatas.length > 0) {
+                        await transaction.updateRows(this.ctx.service.materialStageBills.tableName, updateDatas);
+                        for (const msId of updateMsIds) {
+                            await this.ctx.service.materialStage.updateMtp(transaction, msId);
+                        }
+                    }
+                }
+                // 还要更新bills表的m_tp和m_tax_tp值
+                const sql3 = '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 sqlParam3 = [this.ctx.tender.id, this.ctx.material.id, mb_id];
+                const tp3 = await transaction.queryOne(sql3, sqlParam3);
+                const updateBillsData = {
+                    id: mb_id,
+                    m_tp: tp3.total_price,
+                    m_tax_tp: tp3.tax_total_price,
+                };
+                await transaction.update(this.ctx.service.materialBills.tableName, updateBillsData);
+            } else {
+                await transaction.update(this.ctx.service.materialBills.tableName, updateData);
+            }
             // 计算本期总金额
             const sql2 = '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.materialBills.tableName + ' WHERE `tid` = ? AND `is_summary` = 1';
             const sqlParam2 = [this.ctx.tender.id];
@@ -248,7 +300,7 @@ module.exports = app => {
          * @return {void}
          */
         async getMaterialData(tid, mid) {
-            const sql = 'SELECT ml.`id`, mb.`code`, mb.`name`, mb.`unit`, ml.`order`, ml.`quantity`, ml.`expr`, ml.`mb_id`, ml.`gcl_id`, ml.`xmj_id`, ml.`mx_id`, ml.`tid`, ml.`mid`, mb.m_spread' +
+            const sql = 'SELECT ml.`id`, mb.`code`, mb.`name`, mb.`unit`, ml.`order`, ml.`quantity`, ml.`expr`, ml.`mb_id`, ml.`gcl_id`, ml.`xmj_id`, ml.`mx_id`, ml.`ms_id`, ml.`tid`, ml.`mid`, mb.m_spread' +
                 ' FROM ' + this.tableName + ' as ml' +
                 ' LEFT JOIN ' + this.ctx.service.materialBills.tableName + ' as mb' +
                 ' ON ml.`mb_id` = mb.`id`' +
@@ -258,7 +310,7 @@ module.exports = app => {
         }
 
         async getPreMaterialData(tid, mid) {
-            const sql = 'SELECT ml.`id`, mb.`code`, mb.`name`, mb.`unit`, ml.`order`, ml.`quantity`, ml.`expr`, ml.`mb_id`, ml.`gcl_id`, ml.`xmj_id`, ml.`mx_id`, ml.`tid`, ml.`mid`, mbh.m_spread' +
+            const sql = 'SELECT ml.`id`, mb.`code`, mb.`name`, mb.`unit`, ml.`order`, ml.`quantity`, ml.`expr`, ml.`mb_id`, ml.`gcl_id`, ml.`xmj_id`, ml.`mx_id`, ml.`ms_id` ml.`tid`, ml.`mid`, mbh.m_spread' +
                 ' FROM ' + this.tableName + ' as ml' +
                 ' LEFT JOIN ' + this.ctx.service.materialBills.tableName + ' as mb ON ml.`mb_id` = mb.`id`' +
                 ' LEFT JOIN ' + this.ctx.service.materialBillsHistory.tableName + ' as mbh ON ml.`mb_id` = mbh.`mb_id` and mbh.mid = ?' +
@@ -311,7 +363,7 @@ module.exports = app => {
          * @param newMid
          * @return {Promise<void>}
          */
-        async copyPreMaterialList2(transaction, materialListData, materialSelfListData, notJoinList, newMaterial) {
+        async copyPreMaterialList2(transaction, materialListData, materialSelfListData, notJoinList, newMaterial, materialStageData) {
             if (materialListData && materialListData.length > 0) {
                 const copyMLArray = [];
                 for (const ml of materialListData) {
@@ -330,6 +382,10 @@ module.exports = app => {
                         is_join: is_join ? 0 : 1,
                         in_time: new Date(),
                     };
+                    if (ml.sid) {
+                        const ms = this._.find(materialStageData, { sid: ml.sid });
+                        if (ms && ms.id) newMaterialList.ms_id = ms.id;
+                    }
                     copyMLArray.push(newMaterialList);
                 }
                 if (copyMLArray.length !== 0) await transaction.insert(this.tableName, copyMLArray);
@@ -353,6 +409,10 @@ module.exports = app => {
                         is_self: 1,
                         in_time: new Date(),
                     };
+                    if (ml.sid) {
+                        const ms = this._.find(materialStageData, { sid: ml.sid });
+                        if (ms && ms.id) newMaterialList.ms_id = ms.id;
+                    }
                     copyMLArray2.push(newMaterialList);
                 }
                 if (copyMLArray2.length !== 0) await transaction.insert(this.tableName, copyMLArray2);
@@ -398,6 +458,7 @@ module.exports = app => {
                                 gcl_id: xmj.gcl_id,
                                 xmj_id: xmj.xmj_id,
                                 mx_id: xmj.mx_id,
+                                ms_id: xmj.ms_id ? xmj.ms_id : null,
                                 gather_qty: xmj.gather_qty,
                                 in_time: new Date(),
                                 is_join: xmj.is_join,
@@ -463,7 +524,7 @@ module.exports = app => {
          * @param {int} id 工料id
          * @return {void}
          */
-        async dels(datas, checklist = false, fromCheckList = false) {
+        async dels(datas, checklist = false, fromCheckList = false, ms_id = null) {
             if (!this.ctx.tender || !this.ctx.material) {
                 throw '数据错误';
             }
@@ -479,7 +540,7 @@ module.exports = app => {
                     }
                 }
                 // await transaction.delete(this.tableName, { id });
-                await this.calcQuantityByML(transaction, datas.mb_id);
+                await this.calcQuantityByML(transaction, datas.mb_id, ms_id, 'all');
                 if (checklist) {
                     await this.ctx.service.materialChecklist.updateHadBills(transaction, checklist.id, checklist.had_bills);
                 }
@@ -502,7 +563,7 @@ module.exports = app => {
          * @param {int} order 期数
          * @return {void}
          */
-        async saves(datas, checklist = false) {
+        async saves(datas, checklist = false, ms_id = null) {
             if (!this.ctx.tender || !this.ctx.material) {
                 throw '数据错误';
             }
@@ -550,7 +611,7 @@ module.exports = app => {
                 }
                 if (updateDatas.length > 0) await transaction.updateRows(this.tableName, updateDatas);
                 if (updateListGcl.length > 0) await transaction.updateRows(this.service.materialListGcl.tableName, updateListGcl);
-                await this.calcQuantityByML(transaction, mb_id);
+                await this.calcQuantityByML(transaction, mb_id, ms_id, 'all');
                 await transaction.commit();
                 const gclList = await this.ctx.service.materialListGcl.getAllDataByCondition({ where: { tid: this.ctx.tender.id } });
                 return checklist ? gclList : {
@@ -568,7 +629,7 @@ module.exports = app => {
          * @param {Object} data 工料内容
          * @return {void}
          */
-        async savePastes(datas, checklist = false) {
+        async savePastes(datas, checklist = false, ms_id = null) {
             if (!this.ctx.tender || !this.ctx.material) {
                 throw '数据错误';
             }
@@ -617,7 +678,7 @@ module.exports = app => {
                     }
                     if (updateDatas.length > 0) await transaction.updateRows(this.tableName, updateDatas);
                     if (updateListGcl.length > 0) await transaction.updateRows(this.service.materialListGcl.tableName, updateListGcl);
-                    await this.calcQuantityByML(transaction, data.mb_id);
+                    await this.calcQuantityByML(transaction, data.mb_id, ms_id, 'all');
                 }
                 await transaction.commit();
                 const gclList = await this.ctx.service.materialListGcl.getAllDataByCondition({ where: { tid: this.ctx.tender.id } });

+ 6 - 6
app/service/material_list_notjoin.js

@@ -26,7 +26,7 @@ module.exports = app => {
          * 添加不参与调差的清单
          * @return {void}
          */
-        async add(data) {
+        async add(data, ms_id = null) {
             if (!this.ctx.tender || !this.ctx.material) {
                 throw '数据错误';
             }
@@ -42,7 +42,7 @@ module.exports = app => {
                 };
                 data.xmj_id = data.id;
                 data.mx_id = data.mx_id ? data.mx_id : '';
-                await this.updateAllMaterials(transaction, data, 'add');
+                await this.updateAllMaterials(transaction, data, 'add', ms_id);
                 // 新增不参与调差清单
                 const result = await transaction.insert(this.tableName, newListNotJoin);
                 if (result.affectedRows === 0) {
@@ -61,14 +61,14 @@ module.exports = app => {
          * @param {int} id 工料id
          * @return {void}
          */
-        async del(id) {
+        async del(id, ms_id = null) {
             if (!this.ctx.tender || !this.ctx.material) {
                 throw '数据错误';
             }
             const transaction = await this.db.beginTransaction();
             try {
                 const notJoinInfo = await this.getDataById(id);
-                await this.updateAllMaterials(transaction, notJoinInfo, 'del');
+                await this.updateAllMaterials(transaction, notJoinInfo, 'del', ms_id);
                 // 判断是否可删
                 const result = await transaction.delete(this.tableName, { id });
                 await transaction.commit();
@@ -84,7 +84,7 @@ module.exports = app => {
          * @param transaction
          * @returns {Promise<void>}
          */
-        async updateAllMaterials(transaction, data, type) {
+        async updateAllMaterials(transaction, data, type, ms_id = null) {
             // 先判断material_list是否存在值并quantity不为null
             const searchSql = {
                 mid: this.ctx.material.id,
@@ -115,7 +115,7 @@ module.exports = app => {
                 }
                 // 重新计算金额
                 for (const mb_id of mbIdList) {
-                    await this.service.materialList.calcQuantityByML(transaction, mb_id);
+                    await this.service.materialList.calcQuantityByML(transaction, mb_id, ms_id, 'all');
                 }
             }
         }

+ 49 - 22
app/service/material_list_self.js

@@ -71,14 +71,14 @@ module.exports = app => {
          * @param {int} id 工料id
          * @return {void}
          */
-        async del(id) {
+        async del(id, ms_id = null,) {
             if (!this.ctx.tender || !this.ctx.material) {
                 throw '数据错误';
             }
             const transaction = await this.db.beginTransaction();
             try {
                 const selfInfo = await this.getDataById(id);
-                await this.updateAllMaterials(transaction, selfInfo);
+                await this.updateAllMaterials(transaction, selfInfo, ms_id);
                 // 判断是否可删
                 const result = await transaction.delete(this.tableName, { id });
                 await transaction.commit();
@@ -94,7 +94,7 @@ module.exports = app => {
          * @param transaction
          * @returns {Promise<void>}
          */
-        async updateAllMaterials(transaction, data, type) {
+        async updateAllMaterials(transaction, data, ms_id = null) {
             // 先判断material_list是否存在值并quantity不为null
             const searchSql = {
                 mid: this.ctx.material.id,
@@ -109,8 +109,6 @@ module.exports = app => {
                 where: searchSql,
             });
             if (materialListData && materialListData.length > 0) {
-                const gather_qty = materialListData[0].gather_qty;
-                const is_join = materialListData[0].is_join;
                 const mbIdList = [];
                 for (const ml of materialListData) {
                     if (mbIdList.indexOf(ml.mb_id) === -1) {
@@ -128,27 +126,56 @@ module.exports = app => {
                     where: { tid: this.ctx.tender.id, gcl_id: data.gcl_id },
                 });
                 const insertList = [];
-                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 (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;
+                        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,
+                                ms_id: ms.id,
+                                gather_qty,
+                                quantity: m.quantity,
+                                expr: m.expr,
+                                is_join,
+                                is_self: 0,
+                                in_time: new Date(),
+                            });
+                        }
+                    }
+                } 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);
+                    await this.service.materialList.calcQuantityByML(transaction, mb_id, ms_id, 'all');
                 }
             }
         }

+ 38 - 0
app/service/material_stage.js

@@ -0,0 +1,38 @@
+'use strict';
+
+/**
+ * 调差表(多期独立单价使用) 数据模型
+ *
+ * @author Mai
+ * @date 2018/8/13
+ * @version
+ */
+
+
+module.exports = app => {
+    class MaterialStage extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'material_stage';
+        }
+
+        async updateMtp(transaction, id) {
+            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 `ms_id` = ? AND `is_summary` = 1';
+            const sqlParam = [this.ctx.tender.id, id];
+            const tp = await transaction.queryOne(sql, sqlParam);
+            const updateData2 = {
+                id,
+                m_tp: tp.total_price,
+                m_tax_tp: tp.tax_total_price,
+            };
+            return await transaction.update(this.ctx.service.materialStage.tableName, updateData2);
+        }
+    }
+    return MaterialStage;
+};

+ 208 - 0
app/service/material_stage_bills.js

@@ -0,0 +1,208 @@
+'use strict';
+
+/**
+ * 调差工料表(多期独立单价使用) 数据模型
+ *
+ * @author Mai
+ * @date 2018/8/13
+ * @version
+ */
+const auditConst = require('../const/audit').material;
+const materialConst = require('../const/material');
+const MaterialCalculator = require('../lib/material_calc');
+
+const needUpdateArray = ['quantity', 'msg_tp', 'msg_times', 'msg_spread', 'm_spread', 'm_tp', 'm_tax_tp', 'is_summary', 'remark'];
+
+module.exports = app => {
+    class MaterialStageBills extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'material_stage_bills';
+        }
+        async insertBills(transaction, tid, mid, stage_id, materialStageData, decimal) {
+            let m_tp = 0;
+            let m_tax_tp = 0;
+            // 复制工料表并生成
+            const billsList = await transaction.select(this.ctx.service.materialBills.tableName, { where: { tid } });
+            if (billsList.length > 0) {
+                const insertStageBillsData = [];
+                for (const ms of materialStageData) {
+                    const materialCalculator = new MaterialCalculator(this.ctx, ms.sid, this.ctx.tender.info);
+                    for (const b of billsList) {
+                        const oneStageBillsData = {
+                            tid,
+                            mid,
+                            mb_id: b.id,
+                            ms_id: ms.id,
+                            is_summary: b.is_summary,
+                        };
+                        const [one_tp, one_tax_tp] = await this.calcQuantityByMB(transaction, mid, b, oneStageBillsData, materialCalculator, decimal);
+                        insertStageBillsData.push(oneStageBillsData);
+                        m_tp = this.ctx.helper.add(m_tp, one_tp);
+                        m_tax_tp = this.ctx.helper.add(m_tax_tp, one_tax_tp);
+                    }
+                }
+                await transaction.insert(this.tableName, insertStageBillsData);
+                // 更新bill表和截止上期数据
+                const updateBillsData = [];
+                for (const mb of billsList) {
+                    const [newmsg_spread, newm_spread] = await this.getSpread(mb, null, decimal.up);
+                    const newTp = this._.sumBy(insertStageBillsData, function(item) {
+                        return item.mb_id === mb.id ? item.m_tp : 0;
+                    });
+                    const oneBillsData = {
+                        id: mb.id,
+                        quantity: null,
+                        msg_tp: null,
+                        msg_times: null,
+                        msg_spread: newmsg_spread,
+                        m_spread: newm_spread,
+                        origin: null,
+                        m_tp: newTp,
+                        pre_tp: mb.m_tp !== null ? this.ctx.helper.add(mb.pre_tp, mb.m_tp) : mb.pre_tp,
+                        m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp),
+                        tax_pre_tp: mb.m_tax_tp !== null ? this.ctx.helper.add(mb.tax_pre_tp, mb.m_tax_tp) : mb.tax_pre_tp,
+                    };
+                    updateBillsData.push(oneBillsData);
+                }
+                await transaction.updateRows(this.ctx.service.materialBills.tableName, updateBillsData);
+                // 更新单个期的本期金额
+                const updateStageData = [];
+                for (const ms of materialStageData) {
+                    const newTp = this._.sumBy(insertStageBillsData, function(item) {
+                        return item.ms_id === ms.id ? item.m_tp : 0;
+                    });
+                    const newTaxTp = this._.sumBy(insertStageBillsData, function(item) {
+                        return item.ms_id === ms.id ? item.m_tax_tp : 0;
+                    });
+                    const oneStageData = {
+                        id: ms.id,
+                        m_tp: newTp,
+                        m_tax_tp: newTaxTp,
+                    };
+                    updateStageData.push(oneStageData);
+                }
+                await transaction.updateRows(this.ctx.service.materialStage.tableName, updateStageData);
+            }
+            return [m_tp, m_tax_tp];
+        }
+
+        // 添加工料时同步生成
+        async add(transaction, id) {
+            for (const sid of this.ctx.material.stage_id.split(',')) {
+                const msInfo = await transaction.get(this.ctx.service.materialStage.tableName, { tid: this.ctx.tender.id, sid });
+                const insertData = {
+                    tid: this.ctx.tender.id,
+                    mid: this.ctx.material.id,
+                    ms_id: msInfo.id,
+                    mb_id: id,
+                };
+                await transaction.insert(this.tableName, insertData);
+            }
+        }
+
+        // 单个修改工料时同步修改
+        async update(transaction, data, ms_id) {
+            const msbInfo = await transaction.get(this.tableName, { tid: this.ctx.tender.id, ms_id, mb_id: data.id });
+            const updateData = {
+                id: msbInfo.id,
+            };
+            for (const nu of needUpdateArray) {
+                if (data[nu] !== undefined) updateData[nu] = data[nu];
+            }
+            await transaction.update(this.tableName, updateData);
+            // 金额发生变化,返回重新计算本期这条工料的金额
+            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';
+            const sqlParam = [this.ctx.tender.id, this.ctx.material.id, data.id];
+            const tp = await transaction.queryOne(sql, sqlParam);
+            return [tp.total_price, tp.tax_total_price];
+        }
+
+        /**
+         * 修改quantity,m_spread值和返回单条调差金额(新增一期)
+         * @param transaction
+         * @param mid
+         * @param mb
+         * @returns {Promise<*>}
+         */
+        async calcQuantityByMB(transaction, mid, mb, msb, materialCalculator, decimal) {
+            const [newmsg_spread, newm_spread] = await this.getSpread(mb, null, decimal.up);
+            if (mb.t_type === materialConst.t_type[0].value) {
+                const sql = 'SELECT SUM(`gather_qty`*`quantity`) as quantity FROM ' + this.ctx.service.materialList.tableName + ' WHERE `mid`=? AND `ms_id`=? AND `mb_id`=? AND `is_join`=1';
+                const sqlParam = [mid, msb.ms_id, mb.id];
+                const mb_quantity = await transaction.queryOne(sql, sqlParam);
+                console.log(mb_quantity);
+                // 取历史期记录获取截止上期调差金额,并清空本期单价和时间,来源地,重新计算价差和有效价差
+                const newQuantity = this.ctx.helper.round(mb_quantity.quantity, decimal.qty);
+                const newTp = this.ctx.helper.round(this.ctx.helper.mul(newQuantity, newm_spread), decimal.tp);
+                msb.quantity = newQuantity;
+                msb.msg_spread = newmsg_spread;
+                msb.m_spread = newm_spread;
+                msb.m_tp = newTp;
+                msb.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp);
+                // const updateData = {
+                //     id: mb.id,
+                //     quantity: null,
+                //     msg_tp: null,
+                //     msg_times: null,
+                //     msg_spread: newmsg_spread,
+                //     m_spread: newm_spread,
+                //     origin: null,
+                //     m_tp: newTp,
+                //     pre_tp: mb.m_tp !== null ? this.ctx.helper.add(mb.pre_tp, mb.m_tp) : mb.pre_tp,
+                //     m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp),
+                //     tax_pre_tp: mb.m_tax_tp !== null ? this.ctx.helper.add(mb.tax_pre_tp, mb.m_tax_tp) : mb.tax_pre_tp,
+                // };
+                // await transaction.update(this.tableName, updateData);
+                const m_tp = mb.is_summary === 1 ? await this.ctx.helper.round(this.ctx.helper.mul(mb_quantity.quantity, newm_spread), decimal.tp) : 0;
+                const m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(m_tp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp);
+                return [m_tp, m_tax_tp];
+            } else if (mb.t_type === materialConst.t_type[1].value) {
+                const quantity = await materialCalculator.calculateExpr(mb.expr);
+                const newTp = quantity !== 0 && quantity !== null ? this.ctx.helper.round(this.ctx.helper.mul(this.ctx.helper.round(quantity, decimal.qty), newm_spread), decimal.tp) : null;
+                msb.quantity = quantity !== 0 && quantity !== null ? this.ctx.helper.round(quantity, decimal.qty) : null;
+                msb.msg_spread = newmsg_spread;
+                msb.m_spread = newm_spread;
+                msb.m_tp = newTp;
+                msb.m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp);
+                // const updateData = {
+                //     id: mb.id,
+                //     quantity: quantity !== 0 && quantity !== null ? this.ctx.helper.round(quantity, decimal.qty) : null,
+                //     msg_tp: null,
+                //     msg_times: null,
+                //     msg_spread: newmsg_spread,
+                //     m_spread: newm_spread,
+                //     origin: null,
+                //     m_tp: newTp,
+                //     pre_tp: mb.m_tp !== null ? this.ctx.helper.add(mb.pre_tp, mb.m_tp) : mb.pre_tp,
+                //     m_tax_tp: this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp),
+                //     tax_pre_tp: mb.m_tax_tp !== null ? this.ctx.helper.add(mb.tax_pre_tp, mb.m_tax_tp) : mb.tax_pre_tp,
+                // };
+                // await transaction.update(this.tableName, updateData);
+                const m_tp = mb.is_summary === 1 ? await this.ctx.helper.round(this.ctx.helper.mul(quantity, newm_spread), decimal.tp) : 0;
+                const m_tax_tp = this.ctx.helper.round(this.ctx.helper.mul(m_tp, (1 + this.ctx.helper.div(mb.m_tax, 100))), decimal.tp);
+                return [m_tp, m_tax_tp];
+            }
+        }
+
+        /**
+         * 清空本期信息价后更新价差和有效价差
+         * @param data
+         * @returns {Promise<void>}
+         */
+        async getSpread(data, msg_tp, newDecimalUp = this.ctx.material.decimal.up) {
+            data.msg_tp = msg_tp;
+            const msg_spread = this.ctx.helper.round(this.ctx.helper.sub(data.msg_tp, data.basic_price), newDecimalUp);
+            const cor = msg_spread >= 0 ? this.ctx.helper.mul(data.basic_price, this.ctx.helper.div(data.m_up_risk, 100)) : this.ctx.helper.mul(data.basic_price, this.ctx.helper.div(data.m_down_risk, 100));
+            const m_spread = Math.abs(msg_spread) > Math.abs(cor) ? (msg_spread > 0 ? this.ctx.helper.round(this.ctx.helper.sub(msg_spread, cor), newDecimalUp) : this.ctx.helper.round(this.ctx.helper.add(msg_spread, cor), newDecimalUp)) : 0;
+            return [msg_spread, m_spread];
+        }
+    }
+    return MaterialStageBills;
+};

+ 8 - 0
app/service/project.js

@@ -177,6 +177,14 @@ module.exports = app => {
             return result;
         }
 
+        async getTenderSjsRela(id, show) {
+            const projectData = await this.db.get(this.tableName, { id });
+            const result = projectData.sjs_rela ? JSON.parse(projectData.sjs_rela) : {};
+            this.ctx.helper._.defaults(result, sjsRelaConst);
+            if (!show) result.ledgerCol.forEach(x => { x.show = 0 });
+            return result;
+        }
+
         async updateSjsRela(id, sub, field, key, value) {
             const sjsRela = await this.getSjsRela(id);
             if (!sjsRela[sub]) throw '数据异常';

+ 1 - 1
app/service/stage.js

@@ -696,7 +696,7 @@ module.exports = app => {
          */
         async getStageMsgByStageId(stage_id_list) {
             const list = [];
-            stage_id_list = stage_id_list.split(',');
+            stage_id_list = stage_id_list.toString().split(',');
             for (const sid of stage_id_list) {
                 const stage = await this.getDataById(sid);
                 stage.auditors = await this.service.stageAudit.getAuditors(stage.id, stage.times);

+ 1 - 1
app/view/dashboard/index.ejs

@@ -35,7 +35,7 @@
                 <div class="col-6 px-0">
                     <div class="card ml-3">
                         <div class="card-header card-white d-flex justify-content-between">
-                            <div class="card-big-htext"><span class="card-icon mr-2"></span>需要你处理</div>
+                            <div class="card-big-htext"><span class="card-icon mr-2"></span>参与的标段动态</div>
                             <div>
                                 <select class="form-control form-control-sm" id="select-doing-type">
                                     <option value="0">全部</option>

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

@@ -713,6 +713,14 @@
                                 <input type="number" step="1" min="0" max="6" id="decimal_tp" name="tp" class="form-control" value="<%- material.decimal.tp %>" <% if (!((material.status === auditConst.status.uncheck || material.status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === material.user_id)) { %>disabled<% } %>>
                             </div>
                         </div>
+                        <div class="col-4">
+                            <div class="input-group input-group-sm">
+                                <div class="input-group-prepend">
+                                    <span class="input-group-text">数量</span>
+                                </div>
+                                <input type="number" step="1" min="0" max="6" id="decimal_qty" name="qty" class="form-control" value="<%- material.decimal.qty %>" <% if (!((material.status === auditConst.status.uncheck || material.status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === material.user_id)) { %>disabled<% } %>>
+                            </div>
+                        </div>
                     </div>
                 </div>
             </div>
@@ -846,6 +854,7 @@
     function checkSetDecimal() {
         const up = parseInt($('#decimal_up').val());
         const tp = parseInt($('#decimal_tp').val());
+        const qty = parseInt($('#decimal_qty').val());
         let flag = false;
         if(_.isNaN(up) || up > 6 || up < 0) {
             toastr.error('单价小数位数设置不能大于6或小于0');
@@ -855,6 +864,10 @@
             toastr.error('金额小数位数设置不能大于6或小于0');
             flag = true;
         }
+        if(_.isNaN(qty) || qty > 6 || qty < 0) {
+            toastr.error('数量小数位数设置不能大于6或小于0');
+            flag = true;
+        }
         if (flag) {
             return false;
         }

+ 4 - 1
app/view/material/checklist.ejs

@@ -63,10 +63,13 @@
 </div>
 <script>
     const materialType = JSON.parse('<%- materialType %>');
+    const isStageSelf = parseInt('<%- material.is_stage_self %>');
     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 stage_order = <%- material.order %>;
     const materialID = <%- material.id %>;
     const materialDecimal = JSON.parse(unescape('<%- escape(JSON.stringify(material.decimal)) %>'));
-    let materialChecklistData, notJoinList, ledger, curLedgerData, pos, curPosData, gclGatherData, gclList;
+    let materialChecklistData, notJoinList, ledger, curLedgerData, pos, curPosData, gclGatherData, gclList, gclGatherListData;
 </script>

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

@@ -39,7 +39,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>

+ 130 - 69
app/view/material/info.ejs

@@ -34,7 +34,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,12 +43,47 @@
         <div class="c-header p-0">
         </div>
         <div class="row w-100 sub-content">
-            <div id="left-view" class="c-body" style="width: 100%">
+            <div class="col-12 c-body">
                 <!--上部分-->
-                <div class="sjs-height-1" id="material-spread">
+                <div class="sjs-height-1 row w-100 sub-content">
+                    <div class="c-body" id="left-view" style="width: 100%">
+                        <!--上部分-->
+                        <% if (material.is_stage_self) { %>
+                            <div class="c-body" style="width: 100%">
+                                <ul class="nav nav-tabs" id="myTab" role="tablist">
+                                    <% for (const [index,ms] of materialStageData.entries()) { %>
+                                        <li class="nav-item">
+                                            <a class="nav-link change-material-stage <% if (index === 0) { %>active<% } %>" data-msid="<%- ms.id %>" data-toggle="tab" href="javascript:void(0);" role="tab" aria-selected="<% if (index === 0) { %>true<% } else { %>false<% } %>">第<%- ms.order %>期</a>
+                                        </li>
+                                    <% } %>
+                                </ul>
+                                <div class="sjs-height-material" id="material-spread"></div>
+                            </div>
+                        <% } else { %>
+                            <div class="sjs-height-1" id="material-spread">
+                            </div>
+                        <% } %>
+                    </div>
+                    <div class="c-body" id="right-view" style="width: 30%">
+                        <div class="resize-x" id="right-spr" r-Type="width" div1="#left-view" div2="#right-view" title="调整大小" a-type="percent"><!--调整左右高度条--></div>
+                        <div class="tab-content" style="width: 100%">
+                            <div id="qianyue" class="tab-pane active">
+                                <% if ((material.status === auditConst.status.uncheck || material.status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === material.user_id) {%>
+                                    <div class="sjs-bar-1">
+                                        <div class="pb-1">
+                                            <a href="#add-month" data-toggle="modal" data-target="#add-month" class="btn btn-sm btn-primary">创建月信息价</a>
+                                            <a href="#remove-month" data-toggle="modal" data-target="#remove-month" class="btn btn-sm btn-outline-danger">移除月信息价</a>
+                                        </div>
+                                    </div>
+                                <% } %>
+                                <div class="sjs-height-material-month" id="material-month-spread">
+                                </div>
+                            </div>
+                        </div>
+                    </div>
                 </div>
                 <!--下部分-->
-                <div class="bcontent-wrap" id="main-bottom">
+                <div class="bcontent-wrap mt-1" id="main-bottom">
                     <div id="main-resize" class="resize-y" r-Type="height" div1=".sjs-height-1" div2=".bcontent-wrap" title="调整大小"><!--调整上下高度条--></div>
 
                     <div class="bc-bar mb-1">
@@ -75,77 +110,93 @@
                             <!--</select>-->
                         </div>
                     </div>
-                    <% if (!material.material_tax && !old_had_tax) { %>
-                    <div class="sp-wrap" style="max-width: 800px;min-width: 500px;">
-                        <div class="col-12 p-0">
-                            <table class="table table-sm table-bordered">
-                                <tr><th rowspan="2"></th><th colspan="2" class="text-center">信息价</th><th colspan="2" class="text-center">价格指数</th></tr>
-                                <tr class="text-center"><th>本期金额</th><th>截止本期金额</th>
-                                    <th>本期金额
-                                        <a href="javascript:void(0);" id="ex_expr" data-toggle="tooltip" data-placement="bottom" title="本期价差:<%- material.ex_expr ? material.ex_expr : '' %>"><i class="fa fa-question-circle-o"></i></a></th>
-                                    <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.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>
-                                </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.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>
-                                </tr>
-                            </table>
+                    <div class="material-table-height row mr-1" style="overflow-y: auto">
+                        <div class="col-8">
+                            <% if (!material.material_tax && !old_had_tax) { %>
+                                <div class="sp-wrap" style="max-width: 800px;min-width: 500px;">
+                                    <div class="col-12 p-0">
+                                        <table class="table table-sm table-bordered">
+                                            <tr><th rowspan="2"></th><th colspan="2" class="text-center">信息价</th><th colspan="2" class="text-center">价格指数</th></tr>
+                                            <tr class="text-center"><th>本期金额</th><th>截止本期金额</th>
+                                                <th>本期金额
+                                                    <a href="javascript:void(0);" id="ex_expr" data-toggle="tooltip" data-placement="bottom" title="本期价差:<%- material.ex_expr ? material.ex_expr : '' %>"><i class="fa fa-question-circle-o"></i></a></th>
+                                                <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.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>
+                                            </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.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>
+                                            </tr>
+                                        </table>
+                                    </div>
+                                </div>
+                            <% } else { %>
+                                <div class="sp-wrap" style="max-width: 800px;min-width: 500px;">
+                                    <div class="col-12 p-0">
+                                        <table class="table table-sm table-bordered">
+                                            <tr><th rowspan="2"></th><th colspan="2" class="text-center">信息价</th><th colspan="2" class="text-center">价格指数</th></tr>
+                                            <tr class="text-center"><th>本期金额</th><th>截止本期金额</th>
+                                                <th>本期金额
+                                                    <a href="javascript:void(0);" id="ex_expr" data-toggle="tooltip" data-placement="bottom" title="本期价差:<%- material.ex_expr ? material.ex_expr : '' %>"><i class="fa fa-question-circle-o"></i></a></th>
+                                                <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.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>
+                                            </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">-</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.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>
+                                            </tr>
+                                        </table>
+                                    </div>
+                                </div>
+                            <% } %>
                         </div>
-                    </div>
-                    <% } else { %>
-                    <div class="sp-wrap" style="max-width: 800px;min-width: 500px;">
-                        <div class="col-12 p-0">
-                            <table class="table table-sm table-bordered">
-                                <tr><th rowspan="2"></th><th colspan="2" class="text-center">信息价</th><th colspan="2" class="text-center">价格指数</th></tr>
-                                <tr class="text-center"><th>本期金额</th><th>截止本期金额</th>
-                                    <th>本期金额
-                                        <a href="javascript:void(0);" id="ex_expr" data-toggle="tooltip" data-placement="bottom" title="本期价差:<%- material.ex_expr ? material.ex_expr : '' %>"><i class="fa fa-question-circle-o"></i></a></th>
-                                    <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.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>
+                        <% if (material.is_stage_self) { %>
+                        <div class="col-4">
+                            <table class="table table-bordered">
+                                <thead>
+                                <tr class="text-center"><th colspan="<% if (material.material_tax) { %>3<% } else { %>2<% } %>">期明细</th></tr>
+                                <tr><th class="text-center">期数</th>
+                                    <th class="text-center">本期调差金额</th>
+                                    <% if (material.material_tax) { %>
+                                    <th class="text-center">本期调差金额(材料税)</th>
+                                    <% } %>
                                 </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">-</td>
-                                    <td class="text-center">-</td>
+                                </thead>
+                                <tbody id="materialStageTable">
+                                <% for (const ms of materialStageData) { %>
+                                <tr><td>第<%- ms.order %>期</td><td class="text-center"><%- ms.m_tp %></td>
+                                    <% if (material.material_tax) { %>
+                                        <td class="text-center"><%- ms.m_tax_tp %></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.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>
+                                <% } %>
+                                <tr><td>合计</td><td class="text-center"><%- material.m_tp %></td>
+                                    <% if (material.material_tax) { %>
+                                        <td class="text-center"><%- material.m_tax_tp %></td>
+                                    <% } %>
                                 </tr>
+                                </tbody>
                             </table>
                         </div>
-                    </div>
-                    <% } %>
-                </div>
-            </div>
-            <div id="right-view" class="c-body" style="display:none;width: 33%">
-                <div class="resize-x" id="right-spr" r-Type="width" div1="#left-view" div2="#right-view" title="调整大小" a-type="percent"><!--调整左右高度条--></div>
-                <div class="tab-content" style="width: 100%">
-                    <div id="qianyue" class="tab-pane active">
-                        <% if ((material.status === auditConst.status.uncheck || material.status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === material.user_id) {%>
-                        <div class="sjs-bar-1">
-                            <div class="pb-1">
-                                <a href="#add-month" data-toggle="modal" data-target="#add-month" class="btn btn-sm btn-primary">创建月信息价</a>
-                                <a href="#remove-month" data-toggle="modal" data-target="#remove-month" class="btn btn-sm btn-outline-danger">移除月信息价</a>
-                            </div>
-                        </div>
                         <% } %>
-                        <div class="sjs-height-6" id="material-month-spread">
-                        </div>
                     </div>
                 </div>
             </div>
@@ -153,9 +204,11 @@
         <div class="side-menu">
             <!--右侧菜单-->
             <ul class="nav flex-column right-nav">
+                <% if (!material.is_stage_self) { %>
                 <li class="nav-item">
                     <a class="nav-link" content="#month-tab" href="javascript: void(0);">月信息价</a>
                 </li>
+                <% } %>
             </ul>
         </div>
     </div>
@@ -169,7 +222,10 @@
 <!--<script src="/public/js/jquery-ui/datepicker-zh-CN.js"></script>-->
 <script>
     const materialType = JSON.parse('<%- materialType %>');
+    const isStageSelf = parseInt('<%- material.is_stage_self %>');
     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)) %>')) : [];
     const materialListData = JSON.parse('<%- JSON.stringify(materialListData) %>');
     const readOnly = <%- material.readOnly %>;
     const materialID = <%- material.id %>;
@@ -184,7 +240,12 @@
     const ex_pre_tp_hs = <%= ex_pre_tp_hs !== null ? ex_pre_tp_hs : 0 %>;
     let m_tax_tp = <%= material.m_tax_tp !== null ? material.m_tax_tp : 0 %>;
     const m_tax_pre_tp = <%= material.m_tax_pre_tp !== null ? material.m_tax_pre_tp : 0 %>;
-    const calcBase = JSON.parse('<%- JSON.stringify(calcBase) %>');
+    let calcBase = JSON.parse(unescape('<%- escape(JSON.stringify(calcBase)) %>'));
+    let calcBaseList = [];
+    if (isStageSelf) {
+        calcBaseList = JSON.parse(unescape('<%- escape(JSON.stringify(calcBase)) %>'));
+        calcBase = calcBaseList[0].calcBase;
+    }
     const months = JSON.parse('<%- JSON.stringify(months) %>');
     let monthsList = JSON.parse('<%- JSON.stringify(monthsList) %>');
 </script>

+ 5 - 2
app/view/material/info_modal.ejs

@@ -19,9 +19,12 @@
                 </div>
                 <table class="table table-sm table-bordered">
                     <tr><th>基数</th><th>代号</th><th>值</th></tr>
-                    <% for (let iBase = 0; iBase < calcBase.length; iBase++) { %>
-                    <tr><td><%- calcBase[iBase].name %></td><td><%- calcBase[iBase].code %></td><td><%- calcBase[iBase].value %></td></tr>
+                    <tbody id="calcBase">
+                    <% const calcB = material.is_stage_self ? calcBase[0].calcBase : calcBase; %>
+                    <% for (let iBase = 0; iBase < calcB.length; iBase++) { %>
+                        <tr><td><%- calcB[iBase].name %></td><td><%- calcB[iBase].code %></td><td><%- calcB[iBase].value %></td></tr>
                     <% } %>
+                    </tbody>
                 </table>
             </div>
             <div class="modal-footer">

+ 15 - 3
app/view/material/list.ejs

@@ -21,7 +21,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>
@@ -34,7 +34,16 @@
                 <!--上部分-->
                 <div class="sjs-height-1 row w-100 sub-content">
                     <div class="c-body" id="left-view" style="width: 70%">
-                        <div class="sjs-height-1" id="ledger-spread"></div>
+                        <% if (material.is_stage_self) { %>
+                        <ul class="nav nav-tabs" id="myTab" role="tablist">
+                            <% for (const [index,ms] of materialStageData.entries()) { %>
+                                <li class="nav-item">
+                                    <a class="nav-link change-material-stage <% if (index === 0) { %>active<% } %>" data-msid="<%- ms.id %>" data-toggle="tab" href="javascript:void(0);" role="tab" aria-selected="<% if (index === 0) { %>true<% } else { %>false<% } %>">第<%- ms.order %>期</a>
+                                </li>
+                            <% } %>
+                        </ul>
+                        <% } %>
+                        <div class="<% if (material.is_stage_self) { %>sjs-height-material<% } else { %>sjs-height-1<% } %>" id="ledger-spread"></div>
                     </div>
                     <div class="c-body" id="right-view" style="width: 30%">
                         <div class="resize-x" id="right-spr" r-Type="width" div1="#left-view" div2="#right-view" title="调整大小" a-type="percent"><!--调整左右高度条--></div>
@@ -89,12 +98,15 @@
 </div>
 <script>
     const materialType = JSON.parse('<%- materialType %>');
+    const isStageSelf = parseInt('<%- material.is_stage_self %>');
     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 stage_order = <%- material.order %>;
     const materialID = <%- material.id %>;
     const tenderID = <%- tender.id %>;
     const materialDecimal = JSON.parse(unescape('<%- escape(JSON.stringify(material.decimal)) %>'));
     const openMaterialChecklist = parseInt(<%- ctx.session.sessionProject.page_show.openMaterialChecklist %>);
-    let materialListData, materialChecklistData, notJoinList, ledger, curLedgerData, pos, curPosData, gclGatherData, gclList, selfList;
+    let materialListData, materialChecklistData, notJoinList, ledger, curLedgerData, pos, curPosData, gclGatherData, gclList, selfList, gclGatherListData;
 </script>

+ 13 - 0
app/view/material/modal.ejs

@@ -29,6 +29,19 @@
                         <% } %>
                     </div>
                 </div>
+                <div class="form-group" id="material_unitPrice" style="display: none">
+                    <label>多期计量-材料单价使用</label>
+                    <div>
+                        <div class="form-check form-check-inline">
+                            <input type="radio" class="form-check-input" name="is_stage_self" id="unitPrice_gy" value="0" checked>
+                            <label class="form-check-label" for="unitPrice_gy">共用单价</label>
+                        </div>
+                        <div class="form-check form-check-inline">
+                            <input type="radio" class="form-check-input" name="is_stage_self" id="unitPrice_dl" value="1">
+                            <label class="form-check-label" for="unitPrice_dl">独立单价</label>
+                        </div>
+                    </div>
+                </div>
             </div>
             <div class="modal-footer">
                 <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />

+ 1 - 1
app/view/setting/fun.ejs

@@ -97,7 +97,7 @@
                                         <div class="form-group mb-1">
                                             <div class="form-check form-check-inline">
                                                 <input class="form-check-input" type="checkbox" id="openMaterialChecklist" <% if(ctx.session.sessionProject.page_show.openMaterialChecklist) { %>checked<% } %> onchange="updateSetting();">
-                                                <label class="form-check-label" for="openMaterialChecklist">开启「清单设置」添加调差工料功能</label>
+                                                <label class="form-check-label" for="openMaterialChecklist">开启「批量设置调差清单」添加调差工料功能</label>
                                             </div>
                                         </div>
                                     </div>

+ 1 - 0
app/view/stage/compare.ejs

@@ -17,6 +17,7 @@
                             <a class="dropdown-item" name="showLevel" tag="5" href="javascirpt: void(0);">第五层</a>
                             <a class="dropdown-item" name="showLevel" tag="last" href="javascirpt: void(0);">最底层</a>
                             <a class="dropdown-item" name="showLevel" tag="leafXmj" href="javascirpt: void(0);">只显示项目节</a>
+                            <a class="dropdown-item" name="showLevel" tag="hasDiffer" href="javascirpt: void(0);">只显示审批调整</a>
                         </div>
                     </div>
                 </div>

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

@@ -699,6 +699,10 @@
                         <label class="custom-control-label" for="ledger-cl-qty">错漏增减</label>
                     </div>
                     <div class="custom-control custom-checkbox mb-2">
+                        <input type="checkbox" class="custom-control-input" id="ex-memo" checked="">
+                        <label class="custom-control-label" for="ex-memo">台账新增列</label>
+                    </div>
+                    <div class="custom-control custom-checkbox mb-2">
                         <input type="checkbox" class="custom-control-input" id="thousandth" checked="">
                         <label class="custom-control-label" for="thousandth">千分位</label>
                     </div>
@@ -1484,6 +1488,7 @@
     function loadDisplayProperty () {
         $('#ledger-dgn-qty')[0].checked = property.display.ledger.dgnQty;
         $('#ledger-cl-qty')[0].checked = property.display.ledger.clQty;
+        $('#ex-memo')[0].checked = property.display.exMemo;
         $('#thousandth')[0].checked = property.display.thousandth;
         $('#stage-rc')[0].checked = property.display.stage.realComplete;
         $('#stage-correct')[0].checked = property.display.stage.correct;
@@ -1496,6 +1501,7 @@
         const prop = {
             display: {
                 ledger: { 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 },
                 dayMode: $('#dayMode')[0].checked,

+ 1 - 5
app/view/tender/sub_menu.ejs

@@ -3,12 +3,8 @@
         <div>
             <div class="d-inline-block mr-2">
                 <button href="#cate-set" class="btn btn-sm btn-light text-primary" data-toggle="modal" data-target="#cate-set"><i class="fa fa-sitemap fa-rotate-270"></i> 分类</button>
-                <button type="button" class="btn btn-sm btn-light dropdown-toggle text-primary" data-toggle="dropdown">展开/收起</button>
-                <div class="dropdown-menu">
-                    <a class="dropdown-item tree-toggle" href="javascript:void(0);" data-item="open">展开所有</a>
-                    <a class="dropdown-item tree-toggle" href="javascript:void(0);" data-item="hide">收起所有</a>
-                </div>
             </div>
+            <div class="d-inline-block" id="show-level"></div>
             <div class="d-inline-block">
                 <div class="btn-group btn-group-toggle group-tab" data-toggle="buttons">
                     <label class="btn btn-sm btn-light <% if (ctx.url === '/list') { %>active<% } %>" onclick="window.location.href='/list'">

+ 4 - 0
config/web.js

@@ -61,6 +61,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_list.js',
                 ],
                 mergeFile: 'tender_list',
@@ -72,6 +73,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_list_info.js',
                 ],
                 mergeFile: 'tender_list_info',
@@ -83,6 +85,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_list_progress.js',
                 ],
                 mergeFile: 'tender_list_progress',
@@ -94,6 +97,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_list_manage.js',
                 ],
                 mergeFile: 'tender_list_manage',

+ 38 - 1
sql/update.sql

@@ -16,4 +16,41 @@ ADD COLUMN `end_qc_minus_jl`  decimal(24,8) NULL DEFAULT 0 COMMENT '截止本期
 ALTER TABLE `zh_stage_rela_im_bills`
 ADD COLUMN `qc_minus_jl`  decimal(24,8) NULL DEFAULT 0 COMMENT '不计价' AFTER `qc_jl`,
 ADD COLUMN `pre_qc_minus_jl`  decimal(24,8) NULL DEFAULT 0 COMMENT '截止上期-不计价' AFTER `pre_qc_jl`,
-ADD COLUMN `end_qc_minus_jl`  decimal(24,8) NULL DEFAULT 0 COMMENT '截止本期-不计价' AFTER `end_qc_jl`;
+ADD COLUMN `end_qc_minus_jl`  decimal(24,8) NULL DEFAULT 0 COMMENT '截止本期-不计价' AFTER `end_qc_jl`;
+
+ALTER TABLE `zh_material` ADD `is_stage_self` TINYINT(1) NOT NULL DEFAULT '0' COMMENT '多期共用单价还是独立单价,默认是共用0' AFTER `is_new`;
+
+ALTER TABLE `zh_material_list` ADD `ms_id` INT NULL DEFAULT NULL COMMENT '调差多期单独计价期id' AFTER `mb_id`;
+
+CREATE TABLE `zh_material_stage`  (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `tid` int(11) NOT NULL COMMENT '标段id',
+  `mid` int(11) NOT NULL COMMENT '调差id',
+  `sid` int(11) NOT NULL COMMENT '计量期id',
+  `order` tinyint(4) NOT NULL COMMENT '计量期期数',
+  `m_tp` decimal(30, 8) NULL DEFAULT NULL COMMENT '本期金额',
+  `m_tax_tp` decimal(30, 8) NULL DEFAULT NULL COMMENT '材料含税总金额',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `tid`(`tid`) USING BTREE,
+  INDEX `mid`(`mid`) USING BTREE
+) ENGINE = InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+CREATE TABLE `zh_material_stage_bills`  (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `tid` int(11) NOT NULL COMMENT '标段id',
+  `mid` int(11) NOT NULL COMMENT '调差id',
+  `ms_id` int(11) NOT NULL COMMENT '调差多期单独计价期id',
+  `mb_id` int(11) NOT NULL COMMENT '工料id',
+  `quantity` decimal(30, 8) NULL DEFAULT NULL COMMENT '本期应耗数量',
+  `msg_tp` decimal(30, 8) NULL DEFAULT NULL COMMENT '本期信息价单价',
+  `msg_times` varchar(30) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '本期信息价时间',
+  `msg_spread` decimal(30, 8) NULL DEFAULT NULL COMMENT '本期信息价价差',
+  `m_spread` decimal(30, 8) NULL DEFAULT NULL COMMENT '本期材料调差有效价差',
+  `m_tp` decimal(30, 8) NULL DEFAULT NULL COMMENT '本期金额',
+  `m_tax_tp` decimal(30, 8) NULL DEFAULT NULL COMMENT '调差金额(材料税)',
+  `is_summary` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否汇总',
+  `remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL COMMENT '备注',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `tid`(`tid`) USING BTREE,
+  INDEX `mid`(`mid`) USING BTREE
+) ENGINE = InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;