Просмотр исходного кода

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

Tony Kang 1 год назад
Родитель
Сommit
8e68f17be3
55 измененных файлов с 1856 добавлено и 255 удалено
  1. 2 0
      app/const/page_show.js
  2. 76 14
      app/controller/change_controller.js
  3. 5 3
      app/controller/dashboard_controller.js
  4. 1 1
      app/controller/datacollect_controller.js
  5. 27 6
      app/controller/material_controller.js
  6. 4 0
      app/controller/measure_controller.js
  7. 31 0
      app/middleware/http_header.js
  8. 3 0
      app/middleware/material_check.js
  9. 6 11
      app/public/js/budget_detail.js
  10. 4 4
      app/public/js/category.js
  11. 17 0
      app/public/js/change_information.js
  12. 22 5
      app/public/js/change_information_approval.js
  13. 3 0
      app/public/js/change_information_set.js
  14. 7 4
      app/public/js/ledger.js
  15. 17 13
      app/public/js/material.js
  16. 3 6
      app/public/js/payment_safe.js
  17. 3 1
      app/public/js/revise.js
  18. 6 0
      app/public/js/spreadjs_rela/spreadjs_zh.js
  19. 2 2
      app/public/js/sr_detail.js
  20. 3 0
      app/public/js/stage.js
  21. 2 2
      app/public/js/stage_im.js
  22. 1 0
      app/router.js
  23. 78 0
      app/service/change.js
  24. 9 0
      app/service/change_audit_list.js
  25. 6 3
      app/service/material.js
  26. 17 4
      app/service/material_bills.js
  27. 8 6
      app/service/material_stage_bills.js
  28. 4 0
      app/service/report.js
  29. 16 10
      app/service/rpt_archive.js
  30. 170 9
      app/service/rpt_gather_memory.js
  31. 40 0
      app/service/stage_audit_ass.js
  32. 12 6
      app/service/stage_change.js
  33. 10 8
      app/view/change/index.ejs
  34. 2 0
      app/view/change/information.ejs
  35. 7 9
      app/view/change/information_modal.ejs
  36. 955 0
      app/view/change/modal.ejs
  37. 25 2
      app/view/dashboard/index.ejs
  38. 78 49
      app/view/datacollect/index4GY18Y.ejs
  39. 2 2
      app/view/material/index.ejs
  40. 11 5
      app/view/material/info.ejs
  41. 1 2
      app/view/material/modal.ejs
  42. 6 1
      app/view/measure/stage.ejs
  43. 1 1
      app/view/revise/history.ejs
  44. 1 1
      app/view/revise/info.ejs
  45. 2 2
      app/view/setting/category_modal.ejs
  46. 1 1
      app/view/setting/fun.ejs
  47. 2 0
      app/view/tender/tender_sub_menu.ejs
  48. 2 0
      app/view/tender/tender_sub_mini_menu.ejs
  49. 5 1
      config/config.default.js
  50. 3 0
      config/config.local.js
  51. 3 0
      config/config.qa.js
  52. 17 7
      db_script/change_valuation.js
  53. 61 0
      db_script/material_rate_tp.js
  54. 2 54
      sql/update.sql
  55. 54 0
      sql/update20240624.sql

+ 2 - 0
app/const/page_show.js

@@ -27,6 +27,7 @@ const pageStatus = {
 const defaultSetting = {
     bwtz: 0,
     xxjd: 0,
+    openMaterial: 1,
     stageExtra: 1,
     closeExportPdf: 0,
     closeExportExcel: 0,
@@ -58,6 +59,7 @@ const defaultSetting = {
     openBudget: 1,
     openPayment: 1,
     openConstruction: 1,
+    openMaterialStageRepeat: 0,
 };
 
 

+ 76 - 14
app/controller/change_controller.js

@@ -146,6 +146,7 @@ module.exports = app => {
                 dealCode: ctx.tender.info.deal_info.dealCode,
                 auditConst: audit.change,
                 changeConst,
+                shenpiConst,
                 state,
                 ruleType: codeRuleConst.ruleType.change,
                 ruleConst: codeRuleConst.measure,
@@ -321,6 +322,46 @@ module.exports = app => {
             }
         }
 
+        async batchChangeFun(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                const responseData = {
+                    err: 0,
+                    msg: '',
+                    data: {},
+                };
+                switch (data.type) {
+                    case 'get_report_list':
+                        responseData.data.shenpi_status = ctx.tender.info.shenpi.change;
+                        responseData.data.uncheckList = await ctx.service.change.getUncheckList(ctx.tender.id, ctx.tender.info.shenpi.change);
+                        if (ctx.tender.info.shenpi.change === shenpiConst.sp_status.gdspl) {
+                            responseData.data.spGroupList = await ctx.service.shenpiGroup.getGroupListByChangeType(ctx.tender.id, shenpiConst.sp_type.change, 'change');
+                        } else {
+                            // 获取所有项目参与者
+                            const accountList = await ctx.service.projectAccount.getAllDataByCondition({
+                                where: { project_id: ctx.session.sessionProject.id, enable: 1 },
+                                columns: ['id', 'name', 'company', 'role', 'enable', 'is_admin', 'account_group', 'mobile'],
+                            });
+                            responseData.data.accountList = accountList;
+                            const unitList = await ctx.service.constructionUnit.getAllDataByCondition({ where: { pid: ctx.session.sessionProject.id } });
+                            responseData.data.accountGroup = unitList.map(item => {
+                                const groupList = accountList.filter(item1 => item1.company === item.name);
+                                return { groupName: item.name, groupList };
+                            });
+                        }
+                        break;
+                    case 'get_shenpi_list':
+                        responseData.data.checkingList = await ctx.service.change.getCheckingList(ctx.tender.id, ctx.session.sessionUser.accountId);
+                        break;
+                    default: throw '参数有误';
+                }
+                ctx.body = responseData;
+            } catch (err) {
+                this.log(err);
+                ctx.body = { err: 1, msg: err.toString(), data: null };
+            }
+        }
+
         /**
          * 获取审批界面所需的 原报、审批人数据等
          * @param ctx
@@ -503,6 +544,7 @@ module.exports = app => {
                 await this.layout('change/information.ejs', renderData, 'change/information_modal.ejs');
             } catch (err) {
                 this.log(err);
+                ctx.session.postError = err.toString();
                 ctx.redirect('/tender/' + ctx.params.id + '/change');
             }
         }
@@ -622,6 +664,11 @@ module.exports = app => {
          * @return {Promise<void>}
          */
         async startAudit(ctx) {
+            const responseData = {
+                err: 0,
+                msg: '',
+                data: {},
+            };
             try {
                 // 检查权限等
                 if (!ctx.change) {
@@ -654,11 +701,13 @@ module.exports = app => {
                     }
                 }
                 await ctx.service.changeAudit.start(ctx.change.cid, ctx.change.times);
-                ctx.redirect(ctx.request.header.referer);
+                // ctx.redirect(ctx.request.header.referer);
+                ctx.body = responseData;
             } catch (err) {
                 this.log(err);
-                ctx.session.postError = err.toString();
-                ctx.redirect(ctx.request.header.referer);
+                // ctx.session.postError = err.toString();
+                // ctx.redirect(ctx.request.header.referer);
+                ctx.body = { err: 1, msg: err.toString(), data: null };
             }
         }
 
@@ -721,7 +770,7 @@ module.exports = app => {
                     throw '移除审核人失败';
                 }
 
-                const auditors = await ctx.service.changeAudit.getAuditorsNew(ctx.change.cid, ctx.change.times);
+                const auditors = await ctx.service.changeAudit.getUserGroup(ctx.change.cid, ctx.change.times);
                 ctx.body = { err: 0, msg: '', data: auditors };
             } catch (err) {
                 ctx.body = { err: 1, msg: err.toString(), data: null };
@@ -803,12 +852,18 @@ module.exports = app => {
                     if (ledgerIdList.length > 0) {
                         for (const lid of ledgerIdList) {
                             const data = ctx.helper._.find(ledgerData, { id: lid });
-                            data.cid = 1;
+                            if (data) data.cid = 1;
                         }
                     }
                 }
-                ctx.body = { err: 0, msg: '', data: { bills: ctx.helper._.concat(ledgerData, changeLedgerData), pos: ctx.helper._.concat(posData, changePosData), dealBills } };
+                const bodyData = { bills: ctx.helper._.concat(ledgerData, changeLedgerData), pos: ctx.helper._.concat(posData, changePosData), dealBills };
+                if (data.from === 'batch') {
+                    bodyData.changeLedgerList = changeLedgerData;
+                    bodyData.changePosList = changePosData;
+                }
+                ctx.body = { err: 0, msg: '', data: bodyData };
             } catch (err) {
+                console.log(err);
                 this.log(err);
                 ctx.body = { err: 1, msg: err.toString(), data: [] };
             }
@@ -848,12 +903,18 @@ module.exports = app => {
          * @return {void}
          */
         async approval(ctx) {
+            const data = JSON.parse(ctx.request.body.data);
+            const responseData = {
+                err: 0,
+                msg: '',
+                data: {},
+            };
             try {
-                const changeData = await ctx.service.change.getDataByCondition({ cid: ctx.request.body.change_id });
+                const changeData = await ctx.service.change.getDataByCondition({ cid: data.change_id });
                 if (!changeData) {
                     throw '变更令数据错误';
                 }
-                const status = parseInt(ctx.request.body.status);
+                const status = parseInt(data.status);
                 // 判断是否到你审批,如果不是则无法审批
                 const curAuditor = await ctx.service.changeAudit.getCurAuditors(changeData.cid, changeData.times);
                 if (!curAuditor || (curAuditor && ctx.helper._.findIndex(curAuditor, { uid: ctx.session.sessionUser.accountId }) === -1)) {
@@ -867,27 +928,28 @@ module.exports = app => {
                 const pid = this.ctx.session.sessionProject.id;
                 switch (status) {
                     case 3:// 审批通过
-                        result = await ctx.service.change.approvalSuccess(pid, ctx.request.body, changeData);
+                        result = await ctx.service.change.approvalSuccess(pid, data, changeData);
                         break;
                     // case 4:// 审批终止
                     //     result = await ctx.service.change.approvalStop(ctx.request.body);
                     //     break;
                     case 5:// 审批退回到原报人
-                        result = await ctx.service.change.approvalCheckNo(pid, ctx.request.body, changeData);
+                        result = await ctx.service.change.approvalCheckNo(pid, data, changeData);
                         break;
                     case 6:// 审批退回到上一个审批人
-                        result = await ctx.service.change.approvalCheckNoPre(pid, ctx.request.body, changeData);
+                        result = await ctx.service.change.approvalCheckNoPre(pid, data, changeData);
                         break;
                     default:break;
                 }
                 if (!result) {
                     throw '审批失败';
                 }
-                ctx.redirect(ctx.request.header.referer);
+                ctx.body = responseData;
             } catch (err) {
                 console.log(err);
-                ctx.session.postError = err.toString();
-                ctx.redirect(ctx.request.header.referer);
+                // ctx.session.postError = err.toString();
+                // ctx.redirect(ctx.request.header.referer);
+                ctx.body = { err: 1, msg: err.toString(), data: null };
             }
         }
 

+ 5 - 3
app/controller/dashboard_controller.js

@@ -29,12 +29,13 @@ module.exports = app => {
             const auditStages = await ctx.service.stageAudit.getAuditStage(ctx.session.sessionUser.accountId);
             const auditChanges = await ctx.service.changeAudit.getAuditChange(ctx.session.sessionUser.accountId);
             const auditRevise = await ctx.service.reviseAudit.getAuditRevise(ctx.session.sessionUser.accountId);
-            const auditMaterial = await ctx.service.materialAudit.getAuditMaterial(ctx.session.sessionUser.accountId);
+            const auditMaterial = ctx.session.sessionProject.page_show.openMaterial ? await ctx.service.materialAudit.getAuditMaterial(ctx.session.sessionUser.accountId) : [];
             const auditAdvance = await ctx.service.advanceAudit.getAuditAdvance(ctx.session.sessionUser.accountId);
             const auditChangeProject = ctx.session.sessionProject.page_show.openChangeProject ? await ctx.service.changeProjectAudit.getAuditChangeProject(ctx.session.sessionUser.accountId) : [];
             const auditChangeApply = ctx.session.sessionProject.page_show.openChangeApply ? await ctx.service.changeApplyAudit.getAuditChangeApply(ctx.session.sessionUser.accountId) : [];
             const auditChangePlan = ctx.session.sessionProject.page_show.openChangePlan ? await ctx.service.changePlanAudit.getAuditChangePlan(ctx.session.sessionUser.accountId) : [];
             const auditPayments = ctx.session.sessionProject.page_show.openPayment ? await ctx.service.paymentDetailAudit.getAuditPayment(ctx.session.sessionUser.accountId) : [];
+            const auditStageAss = await ctx.service.stageAuditAss.getAuditStageAss(ctx.session.sessionUser.accountId);
             const pa = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId);
             const noticeList = await ctx.service.noticePush.getNotice(ctx.session.sessionProject.id, pa.id);
             const projectData = await ctx.service.project.getDataById(ctx.session.sessionProject.id);
@@ -62,7 +63,7 @@ module.exports = app => {
             if (ctx.session.sessionProject.page_show.openChangeProject) shenpi_count.push({ count: await ctx.service.changeProjectAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '变更立项' });
             if (ctx.session.sessionProject.page_show.openChangeApply) shenpi_count.push({ count: await ctx.service.changeApplyAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '变更申请' });
             if (ctx.session.sessionProject.page_show.openChangePlan) shenpi_count.push({ count: await ctx.service.changePlanAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '变更方案' });
-            shenpi_count.push({ count: await ctx.service.materialAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '材料调差' });
+            if (ctx.session.sessionProject.page_show.openMaterial) shenpi_count.push({ count: await ctx.service.materialAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '材料调差' });
             // shenpi_count.push({ count: await ctx.service.advanceAudit.getCountByChecked(ctx.session.sessionUser.accountId), name: '预付款' });
             const total_count = ctx.app._.sumBy(shenpi_count, 'count');
             const shenpi_lastime = [
@@ -74,7 +75,7 @@ module.exports = app => {
                 ctx.session.sessionProject.page_show.openChangeProject ? await ctx.service.changeProjectAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId) : null,
                 ctx.session.sessionProject.page_show.openChangeApply ? await ctx.service.changeApplyAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId) : null,
                 ctx.session.sessionProject.page_show.openChangePlan ? await ctx.service.changePlanAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId) : null,
-                await ctx.service.materialAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId),
+                ctx.session.sessionProject.page_show.openMaterial ? await ctx.service.materialAudit.getLastEndTimeByChecked(ctx.session.sessionUser.accountId) : null,
             ];
             const last_time = ctx.app._.max(shenpi_lastime);
             // console.log(ctx.app._.max(shenpi_lastime), ctx.helper.calcDayNum(last_time));
@@ -89,6 +90,7 @@ module.exports = app => {
                 auditChangeApply,
                 auditChangePlan,
                 auditPayments,
+                auditStageAss,
                 shenpi_count,
                 total_count,
                 last_day: ctx.helper.calcDayNum(last_time),

+ 1 - 1
app/controller/datacollect_controller.js

@@ -99,7 +99,7 @@ module.exports = app => {
                     const glCategory = categoryData.find(item => item.name === '管理类别');
                     const dpCategory = [];
                     for (const d of renderData.daping06Set.cb_show) {
-                        dpCategory.push(glCategory.value.find(item => item.id === d));
+                        if (glCategory && glCategory.value) dpCategory.push(glCategory.value.find(item => item.id === d));
                     }
                     renderData.dpCategory = dpCategory;
                     await this.layout('datacollect/index4GY18Y.ejs', renderData);

+ 27 - 6
app/controller/material_controller.js

@@ -45,6 +45,9 @@ module.exports = app => {
          */
         async index(ctx) {
             try {
+                if (!ctx.session.sessionProject.page_show.openMaterial) {
+                    throw '该功能已关闭';
+                }
                 // 列展示
                 const tenderMsg = await ctx.service.tender.getTender(ctx.tender.id, ['material_col_show']);
                 const material_col_show = tenderMsg.material_col_show ? JSON.parse(tenderMsg.material_col_show) : ctx.helper._.cloneDeep(tenderConst.materialColShow);
@@ -79,12 +82,14 @@ module.exports = app => {
                     // s.curAuditor = null;
                     // 根据期状态返回展示用户
                     s.curAuditor = await ctx.service.materialAudit.getAuditorByStatus(s.id, s.status, s.times);
-                    const materialStageList = s.stage_id.split(',');
-                    for (const ms of materialStageList) {
-                        const index = stages.findIndex(function(item) {
-                            return item.id === parseInt(ms);
-                        });
-                        stages.splice(index, 1);
+                    if (!ctx.session.sessionProject.page_show.openMaterialStageRepeat) {
+                        const materialStageList = s.stage_id.split(',');
+                        for (const ms of materialStageList) {
+                            const index = stages.findIndex(function(item) {
+                                return item.id === parseInt(ms);
+                            });
+                            stages.splice(index, 1);
+                        }
                     }
                     if (allMaterialTax && s.material_tax === 0) {
                         allMaterialTax = false;
@@ -113,6 +118,7 @@ module.exports = app => {
                 await this.layout('material/index.ejs', renderData, 'material/modal.ejs');
             } catch (err) {
                 this.log(err);
+                ctx.session.postError = err.toString();
                 ctx.redirect(this.menu.menu.dashboard.url);
             }
         }
@@ -124,6 +130,9 @@ module.exports = app => {
          */
         async materialAuditors(ctx) {
             try {
+                if (!ctx.session.sessionProject.page_show.openMaterial) {
+                    throw '该功能已关闭';
+                }
                 const responseData = {
                     err: 0, msg: '', data: {},
                 };
@@ -160,6 +169,9 @@ module.exports = app => {
          */
         async save(ctx) {
             try {
+                if (!ctx.session.sessionProject.page_show.openMaterial) {
+                    throw '该功能已关闭';
+                }
                 const data = {
                     mid: ctx.request.body.mid,
                     period: ctx.request.body.period,
@@ -189,6 +201,9 @@ module.exports = app => {
          */
         async saveData(ctx) {
             try {
+                if (!ctx.session.sessionProject.page_show.openMaterial) {
+                    throw '该功能已关闭';
+                }
                 const data = JSON.parse(ctx.request.body.data);
                 const responseData = {
                     err: 0,
@@ -215,6 +230,9 @@ module.exports = app => {
          */
         async add(ctx) {
             try {
+                if (!ctx.session.sessionProject.page_show.openMaterial) {
+                    throw '该功能已关闭';
+                }
                 if (ctx.session.sessionUser.accountId !== ctx.tender.data.user_id) {
                     throw '您无权创建材料调差期';
                 }
@@ -247,6 +265,9 @@ module.exports = app => {
          */
         async delete(ctx) {
             try {
+                if (!ctx.session.sessionProject.page_show.openMaterial) {
+                    throw '该功能已关闭';
+                }
                 const material_id = ctx.request.body.material_id;
                 const materialInfo = await ctx.service.material.getDataById(material_id);
                 // 获取最新的期数

+ 4 - 0
app/controller/measure_controller.js

@@ -49,6 +49,10 @@ module.exports = app => {
                 };
                 renderData.stages = await ctx.service.stage.getValidStages(ctx.tender.id, this.ctx.session.sessionUser.is_admin);
                 for (const s of renderData.stages) {
+                    if (!s.rpt_filed) {
+                        s.rpt_filed = await ctx.service.rptArchive.count({ stage_id: s.id });
+                        if (s.rpt_filed) await ctx.service.stage.defaultUpdate({ id: s.id, rpt_filed: 1});
+                    }
                     if (!s.final_auditor_str || s.status !== auditConst.status.checked) {
                         // 根据期状态返回展示用户
                         s.curAuditors = await ctx.service.stageAudit.getAuditorsByStatus(s.id, s.status, s.times);

+ 31 - 0
app/middleware/http_header.js

@@ -0,0 +1,31 @@
+'use strict';
+
+module.exports = options => {
+    return async function httpHeader(ctx, next) {
+        await next();
+
+        // CT-638506 避免获取用户敏感信息
+        ctx.set('X-Content-Type-Options', 'nosniff');
+        // CT-638385 点击劫持相关
+        // 禁止以iframe或者frame的形式嵌入 (deny/sameorign都可)
+        ctx.set('X-Frame-Options', 'deny');
+        // CT-638235
+        // 避免钓鱼欺骗 (启用XSS过滤器。如果检测到攻击,浏览器将不会清理页面,而是完全阻止页面的渲染)
+        ctx.set('X-XSS-Protection', '1; mode=block');
+        // 可以节省一次请求重定向(HSTS预加载服务,按指示提交域名后,浏览器将永不使用非安全方式链接)
+        ctx.set('strict-transport-security', 'max-age=31536000; includeSubDomains; preload');
+        //
+        const csp = [
+            'default-src', `'self' data: 'unsafe-inline' 'unsafe-eval' https://*.smartcost.com.cn https://*.aliyuncs.com https://*.qq.com/`,
+        ];
+        ctx.set('Content-Security-Policy', csp.join(' '));
+        // IE8以上版本用户,在下载时,不显示打开选项
+        ctx.set('X-Download-Options', 'noopen');
+        // 针对三方网站隐藏referer,防止隐私泄露和钓鱼攻击
+        // same-origin 同源则发送,反之不发送
+        // strict-origin 安全级别相同发送,反之不发送(例如https->http)
+        ctx.set('referer-policy', 'same-origin');
+        //
+        ctx.set('X-Permitted-Cross-Domain-Policies', 'master-only');
+    };
+};

+ 3 - 0
app/middleware/material_check.js

@@ -33,6 +33,9 @@ module.exports = options => {
      */
     return function* materialCheck(next) {
         try {
+            if (!this.session.sessionProject.page_show.openMaterial) {
+                throw '该功能已关闭';
+            }
             // 读取标段数据
             const materialOrder = parseInt(this.params.order);
             if (materialOrder <= 0) {

+ 6 - 11
app/public/js/budget_detail.js

@@ -593,18 +593,12 @@ $(document).ready(() => {
         budgetTreeOpr.refreshOperationValid(budgetSheet);
     });
 
-    const stdLibCellDoubleClick = function (e, info) {
-        const stdSheet = info.sheet;
-        if (!stdSheet.zh_setting || !stdSheet.zh_tree || !budgetSheet.zh_tree) return;
-
-        const stdTree = stdSheet.zh_tree;
-        const stdNode = stdTree.nodes[info.row];
+    const stdLibCellDoubleClick = function (updateData, stdNode, stdTree) {
+        if (!stdTree || !budgetSheet.zh_tree) return;
         if (!stdNode) return;
 
-        const budgetTree = budgetSheet.zh_tree;
-        const sel = budgetSheet.getSelections()[0];
-        const mainNode = budgetTree.nodes[sel.row];
-        if (info.sheet.zh_setting.stdType === 'gcl') {
+        const mainNode = SpreadJsObj.getSelectObject(budgetSheet);
+        if (updateData.postData.stdType === 'gcl') {
             if (mainNode.code && mainNode.code !== '' && !budgetTree.isLeafXmj(mainNode)) {
                 toastr.warning('非最底层项目下,不应添加清单');
                 return;
@@ -616,11 +610,12 @@ $(document).ready(() => {
             postData: {
                 id: budgetTree.getNodeKey(mainNode),
                 tender_id: mainNode.tender_id,
-                stdType: info.sheet.zh_setting.stdType,
+                stdType: updateData.postData.stdType,
                 stdLibId: stdNode.list_id,
                 stdNode: stdTree.getNodeKey(stdNode)
             }
         }, function (result) {
+            const sel = budgetSheet.getSelections()[0];
             const refreshNode = budgetTree.loadPostData(result);
             budgetTreeOpr.refreshTree(budgetSheet, refreshNode);
             if (refreshNode.create && refreshNode.create.length > 0) {

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

@@ -59,11 +59,11 @@ function getValueHtml(value, index = null) {
     let i = index ? index : 1;
     for (const v of value) {
         html.push('<tr name="value" vid="' + v.id + '">');
-        html.push('<td width="35" class="text-center">'+ i +'</td>');
+        html.push('<td width="10%" class="text-center">'+ i +'</td>');
         html.push('<td><input class="form-control form-control-sm" name="value" placeholder="请输入值" value="' + v.value + '" vid ="' + v.id +  '"></td>');
-        html.push('<td><a href="javascript:void(0);" class="up-btn mr-2" title="上移"><i class="fa fa-caret-up"></i></a><a href="javascript:void(0);" class="down-btn" title="下移"><i class="fa fa-caret-down "></i></a></td>');
-        html.push('<td>', v.relaTenders.length + v.newTenders.length ,'</td>');
-        html.push('<td><a href="javascript: void(0);" class="text-danger" name="del-value" vid="' + v.id + '">删除</a></td>');
+        html.push('<td width="10%">', v.relaTenders.length + v.newTenders.length ,'</td>');
+        html.push('<td width="40px"><a href="javascript:void(0);" class="up-btn mr-2" title="上移"><i class="fa fa-caret-up"></i></a><a href="javascript:void(0);" class="down-btn" title="下移"><i class="fa fa-caret-down "></i></a></td>');
+        html.push('<td width="10%"><a href="javascript: void(0);" class="text-danger" name="del-value" vid="' + v.id + '">删除</a></td>');
         html.push('</tr>');
         i++;
     }

+ 17 - 0
app/public/js/change_information.js

@@ -637,6 +637,8 @@ $(document).ready(() => {
 function calcChangePrice() {
     let positive_tp = 0;
     let negative_tp = 0;
+    let valuation_tp = 0;
+    let unvaluation_tp = 0;
     let new_tp = 0;
     for (const c of changeList) {
         if (c.spamount) {
@@ -647,6 +649,11 @@ function calcChangePrice() {
             } else {
                 negative_tp = ZhCalc.add(negative_tp, price);
             }
+            if (c.is_valuation) {
+                valuation_tp = ZhCalc.add(valuation_tp, price);
+            } else {
+                unvaluation_tp = ZhCalc.add(unvaluation_tp, price);
+            }
         }
     }
     const updateTpList = {};
@@ -663,11 +670,21 @@ function calcChangePrice() {
         updateTpList.negative_tp = negative_tp;
         updateFlag = true;
     }
+    if (valuation_tp !== changeVp) {
+        updateTpList.valuation_tp = valuation_tp;
+        updateFlag = true;
+    }
+    if (unvaluation_tp !== changeUp) {
+        updateTpList.unvaluation_tp = unvaluation_tp;
+        updateFlag = true;
+    }
     if (updateFlag) {
         console.log(updateTpList);
         postData(window.location.pathname + '/save', { type:'update_tp', updateData: updateTpList }, function () {
             changePp = positive_tp;
             changeNp = negative_tp;
+            changeVp = valuation_tp;
+            changeUp = unvaluation_tp;
             changeTp = new_tp;
         });
     }

+ 22 - 5
app/public/js/change_information_approval.js

@@ -456,6 +456,10 @@ $(document).ready(() => {
     $('.approval-btn').on('click', function () {
         // 判断审批状态
         let returnflag = true;
+        const pData = {
+            change_id: $('#changeId').val(),
+            w_code: $.trim($('#w_code').val()),
+        }
         if ($(this).hasClass('btn-success')) {
             const sdesc = $('#success-approval').find('textarea').val();
             if (sdesc === '') {
@@ -467,21 +471,24 @@ $(document).ready(() => {
                 returnflag = false;
             } else if ($('input[name="p_code"]').val() !== undefined) {
                 $('input[name="p_code"]').val($.trim($('input[name="p_code"]').val()));
-                const postData = {
+                const postData2 = {
                     p_code: $('input[name="p_code"]').val(),
                 };
-                postDataWithAsync('/tender/' + $('#tenderId').val() + '/change/' + $('#changeId').val() + '/check/codeRepeat',postData, function (result) {
+                postDataWithAsync('/tender/' + $('#tenderId').val() + '/change/' + $('#changeId').val() + '/check/codeRepeat',postData2, function (result) {
                 }, function (data) {
                     returnflag = false;
                 });
+                pData.p_code = $('input[name="p_code"]').val();
             }
 
             if(returnflag) {
                 $('input[name="w_code"]').val($.trim($('#w_code').val()));
 
                 $('#success-approval').find('textarea').val(sdesc.replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\s/g, ' '));
-                if ($('#warning-text').length) $('#warning-text').remove()
-                $('#success-approval').submit();
+                if ($('#warning-text').length) $('#warning-text').remove();
+                // $('#success-approval').submit();
+                pData.status = auditConst.status.checked;
+                pData.sdesc = sdesc.replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\s/g, ' ');
             }
         } else {
             const sdesc = $('#fail-approval').find('textarea').val();
@@ -500,9 +507,17 @@ $(document).ready(() => {
             if(returnflag) {
                 $('#fail-approval').find('textarea').val(sdesc.replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\s/g, ' '));
                 $('input[name="w_code"]').val($.trim($('#w_code').val()));
-                $('#fail-approval').submit();
+                // $('#fail-approval').submit();
+                pData.status = type;
+                pData.sdesc = sdesc.replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\s/g, ' ');
             }
         }
+        if (pData.status) {
+            console.log(pData);
+            postData('/tender/' + $('#tenderId').val() + '/change/approval', pData, function (result) {
+                window.location.reload();
+            });
+        }
     })
 });
 const postDataWithAsync = function (url, data, successCallback, errorCallBack, showWaiting = true) {
@@ -708,6 +723,7 @@ function makePushBwmx(clinfo, listinfo, removeList, updateList) {
             if (needUpdate) {
                 updateList.push(oneUpdate);
             }
+            info = leafInfo;
         } else {
             toastr.warning('台账清单列表已不存在'+ clinfo.code +',已更新变更清单列表');
             if (changeStatus !== auditConst.status.revise) {
@@ -718,6 +734,7 @@ function makePushBwmx(clinfo, listinfo, removeList, updateList) {
             return false;
         }
     }
+    return info;
 }
 function isObjEqual(o1,o2){
     var props1 = Object.getOwnPropertyNames(o1);

+ 3 - 0
app/public/js/change_information_set.js

@@ -2043,6 +2043,9 @@ function checkChangeFrom() {
     if (returnFlag) {
         return false;
     }
+    postData(preUrl + '/audit/start', {}, function (result) {
+        window.location.reload();
+    })
 }
 // 检查上报情况
 function checkAuditorFrom () {

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

@@ -1964,7 +1964,7 @@ $(document).ready(function() {
                     if (type === 'delete') {
                         for (const p of result.pos) {
                             const posInfo = pos.getPos(p);
-                            billsTag.afterDeletePos(posInfo);
+                            billsTag.afterDeletePos([posInfo]);
                         }
                         pos.removeDatas(result.pos);
                         sheet.deleteRows(row, count);
@@ -2160,7 +2160,7 @@ $(document).ready(function() {
                 postData('/tender/' + getTenderId() + '/pos/update', data, function (result) {
                     for (const p of result.pos) {
                         const posInfo = pos.getPos(p);
-                        billsTag.afterDeletePos(posInfo);
+                        billsTag.afterDeletePos([posInfo]);
                     }
                     pos.removeDatas(result.pos);
                     sheet.deleteRows(row, count);
@@ -2216,7 +2216,8 @@ $(document).ready(function() {
                 const data = [];
                 const sortData = info.sheet.zh_data || [];
                 if (sortData.length === 0 || info.cellRange.row + info.cellRange.rowCount > sortData.length) {
-                    if (info.cellRange.col !== 0) {
+                    const nameCol = info.sheet.zh_setting.cols.findIndex(x => { return x.field === 'name'; });
+                    if (info.cellRange.col > nameCol || info.cellRange.col + info.cellRange.colCount < nameCol) {
                         toastr.warning('新增计量单元请先输入名称');
                         posOperationObj.loadCurPosData();
                         return;
@@ -2256,7 +2257,9 @@ $(document).ready(function() {
                             try {
                                 const exprInfo = getExprInfo(colSetting.field, true);
                                 posData[exprInfo.expr] = trimInvalidChar(info.sheet.getText(curRow, curCol));
-                                posData[exprInfo.qty] = math.evaluate(transExpr(posData[exprInfo.expr]));
+                                if (posData[exprInfo.expr] || !posData[exprInfo.qty]) {
+                                    posData[exprInfo.qty] = math.evaluate(transExpr(posData[exprInfo.expr]));
+                                }
                                 bPaste = true;
                             } catch (err) {
                                 toastMessageUniq(hint.expr);

+ 17 - 13
app/public/js/material.js

@@ -127,31 +127,35 @@ DatePickerCellType.prototype.updateEditor = function (editorContext, cellStyle,
 function resetTpTable() {
     $('#tp_set').find('td').eq(1).text(ZhCalc.round(m_tp, materialDecimal.tp));
     $('#tp_set').find('td').eq(2).text(ZhCalc.add(pre_tp, ZhCalc.round(m_tp, materialDecimal.tp)));
-    if (materialTax) {
-        $('#tax_rate_set').find('td').eq(1).text(ZhCalc.round(m_tax_tp, materialDecimal.tp));
-        $('#tax_rate_set').find('td').eq(2).text(ZhCalc.add(m_tax_pre_tp, ZhCalc.round(m_tax_tp, materialDecimal.tp)));
-    } else {
-        const rate = $('#rateInput').val();
-        const bqhs = ZhCalc.round(ZhCalc.mul(m_tp, 1+rate/100), materialDecimal.tp);
-        const jzbqhs = ZhCalc.add(pre_tp_hs, bqhs);
-        $('#rate_set').find('td').eq(1).text(bqhs !== 0 ? bqhs : '');
-        $('#rate_set').find('td').eq(2).text(jzbqhs !== 0 ? jzbqhs : '');
-    }
-
+    let sum = 0;
     if (isStageSelf) {
         let html = '';
+        const rate = $('#rateInput').val();
         for (const ms of materialStageData) {
-            const taxHtml = materialTax ? '                                        <td class="text-center">' + (ms.m_tax_tp !== null ? ms.m_tax_tp : '') + '</td>\n' : '';
+            if (!materialTax) {
+                sum = ZhCalc.add(sum, ZhCalc.round(ZhCalc.mul(ms.m_tp, 1+rate/100), materialDecimal.tp));
+            }
+            const taxHtml = '                                        <td class="text-center">' + (materialTax ? (ms.m_tax_tp !== null ? ms.m_tax_tp : '') : ZhCalc.round(ZhCalc.mul(ms.m_tp, 1+rate/100), materialDecimal.tp) ) + '</td>\n';
             html += '<tr><td>第' + ms.order + '期</td><td class="text-center">' + (ms.m_tp !== null ? ms.m_tp : '') + '</td>\n' +
                 taxHtml +
                 '                                </tr>';
         }
-        const allTaxHtml = materialTax ? '                                        <td class="text-center">' + m_tax_tp + '</td>\n' : '';
+        const allTaxHtml = '                                        <td class="text-center">' + (materialTax ? m_tax_tp : sum) + '</td>\n';
         html += '<tr><td>合计</td><td class="text-center">' + m_tp + '</td>\n' +
             allTaxHtml +
             '                                </tr>';
         $('#materialStageTable').html(html);
     }
+    if (materialTax) {
+        $('#tax_rate_set').find('td').eq(1).text(ZhCalc.round(m_tax_tp, materialDecimal.tp));
+        $('#tax_rate_set').find('td').eq(2).text(ZhCalc.add(m_tax_pre_tp, ZhCalc.round(m_tax_tp, materialDecimal.tp)));
+    } else {
+        const rate = $('#rateInput').val();
+        const bqhs = isStageSelf ? sum : ZhCalc.round(ZhCalc.mul(m_tp, 1+rate/100), materialDecimal.tp);
+        const jzbqhs = ZhCalc.add(pre_tp_hs, bqhs);
+        $('#rate_set').find('td').eq(1).text(bqhs !== 0 ? bqhs : '');
+        $('#rate_set').find('td').eq(2).text(jzbqhs !== 0 ? jzbqhs : '');
+    }
 }
 function getPasteHint (str, row = '') {
     let returnObj = str;

+ 3 - 6
app/public/js/payment_safe.js

@@ -892,14 +892,11 @@ $(document).ready(function() {
         },
         page: 'paymentSafe',
         tid: getTenderId(),
-        cellDoubleClick: function (e, info) {
-            const stdSheet = info.sheet;
-            const stdTree = stdSheet.zh_tree;
-            const stdNode = stdTree.nodes[info.row];
-            if (!stdNode || !stdNode.b_code) return;
+        cellDoubleClick: function (updateData, stdNode, stdTree) {
+            if (!stdTree || !stdNode || !stdNode.b_code) return;
 
             const mainSheet = billsObj.sheet;
-            if (!stdSheet.zh_setting || !stdSheet.zh_tree || !mainSheet.zh_tree) return;
+            if ( !mainSheet.zh_tree) return;
             const mainTree = mainSheet.zh_tree;
             const sel = mainSheet.getSelections()[0];
 

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

@@ -1968,7 +1968,9 @@ $(document).ready(() => {
                         try {
                             const exprInfo = getExprInfo(colSetting.field, true);
                             posData[exprInfo.expr] = trimInvalidChar(info.sheet.getText(curRow, curCol));
-                            posData[exprInfo.qty] = math.evaluate(transExpr(posData[exprInfo.expr]));
+                            if (posData[exprInfo.expr] || !posData[exprInfo.qty]) {
+                                posData[exprInfo.qty] = math.evaluate(transExpr(posData[exprInfo.expr]));
+                            }
                             bPaste = true;
                         } catch (err) {
                             toastMessageUniq(hint.expr);

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

@@ -1121,6 +1121,12 @@ const SpreadJsObj = {
         sheet.getParent().focus();
         sheet.showRow(row, spreadNS.VerticalPosition.center);
     },
+    locateDataBy: function(sheet, fun) {
+        if (!sheet.zh_data) { return }
+        const index = sheet.zh_data.findIndex(d => { return fun(d); });
+        if (index < 0) return;
+        this.locateRow(sheet, index);
+    },
     saveTopAndSelect: function (sheet, cacheKey) {
         const sel = sheet.getSelections()[0];
         const top = sheet.getViewportTopRow(1);

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

@@ -545,8 +545,8 @@ $(document).ready(() => {
         stagePosSpreadObj.loadCurPosData();
         SpreadJsObj.resetTopAndSelect(spSpread.getActiveSheet());
         // 加载中间计量
-        stageIm.init(relaStage, imType, tenderInfo.decimal);
-        stageIm.loadData4Rela(result.ledgerData, result.posData, result.detailData, result.stageChange, result.detailAtt);
+        stageIm.init(tenderInfo, relaStage, imType, tenderInfo.decimal);
+        stageIm.loadData4Rela(result.ledgerData, result.posData, result.detailData, result.stageChange || [], result.detailAtt);
     }, null, true);
     spSpread.bind(spreadNS.Events.SelectionChanged, stagePosSpreadObj.selectionChanged);
 

+ 3 - 0
app/public/js/stage.js

@@ -3530,6 +3530,9 @@ $(document).ready(() => {
                 if (select && select.source) {
                     SpreadJsObj.locateTreeNode(slSpread.getActiveSheet(), select.source[curIndex-1].id, true);
                     stagePosSpreadObj.loadCurPosData();
+                    if (select.source[curIndex-1].pos_id) {
+                        SpreadJsObj.locateDataBy(spSpread.getActiveSheet(), function(data){ return data.id === select.source[curIndex-1].pos_id});
+                    }
                 }
             });
             $('#im-locate-pre').click(function () {

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

@@ -700,7 +700,7 @@ const stageIm = (function () {
                             };
                             nodeImData.push(im);
                         }
-                        im.source.push({id: p.ledger_id, code: p.code, b_code: p.b_code});
+                        im.source.push({id: p.ledger_id, code: p.code, b_code: p.b_code, pos_id: pp.id, pos_name: pp.name});
 
                         for (const c of changes) {
                             if (c.lid === p.id && c.pid == pp.id && c.qty && c.qty !== 0) {
@@ -889,7 +889,7 @@ const stageIm = (function () {
                         position: pp.position,
                         lIndex: nodeIndex,
                         custom_define: [],
-                        source: [{id: p.ledger_id, code: p.code, b_code: p.b_code}],
+                        source: [{id: p.ledger_id, code: p.code, b_code: p.b_code, pos_id: pp.id, pos_name: pp.name}],
                         im_type: imType.bw.value,
                     };
                     im.calc_memo = '本期计量:' + (checkZero(im.jl) ? 0 : im.jl) + (im.qc_minus_jl ? (` (不计价 ${im.qc_minus_jl}) `) : ' ') + im.unit;

+ 1 - 0
app/router.js

@@ -549,6 +549,7 @@ module.exports = app => {
 
     app.post('/tender/:id/change/:cid/check/codeRepeat', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.checkCodeRepeat');
     app.post('/tender/:id/change/:cid/info/copy', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.copyChange');
+    app.post('/tender/:id/change/batch/fun', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.batchChangeFun');
     // 变更单位管理
     app.post('/change/update/company', sessionAuth, 'changeController.updateCompany');
 

+ 78 - 0
app/service/change.js

@@ -21,6 +21,7 @@ const wxConst = require('../const/wechat_template');
 const pushType = require('../const/audit').pushType;
 const projectLogConst = require('../const/project_log');
 const pushOperate = require('../const/spec_3f').pushOperate;
+const shenpiConst = require('../const/shenpi');
 
 module.exports = app => {
     class Change extends app.BaseService {
@@ -2095,6 +2096,83 @@ module.exports = app => {
             }
             return list;
         }
+
+        async getUncheckList(tid, shenpi_status) {
+            const sql = 'select c.* from ?? as c where c.tid = ? ' +
+                'and (c.status = ? OR c.status = ?) AND c.code != "" AND c.name != "" AND c.content is not NULL AND c.content != ""';
+            const sqlParams = [this.tableName, tid, audit.change.status.uncheck, audit.change.status.checkNo];
+            const list = await this.db.query(sql, sqlParams);
+            const returnList = [];
+            for (const l of list) {
+                const changeList = await this.ctx.service.changeAuditList.getAllDataByCondition({ where: { cid: l.cid } });
+                // 清单名称不能为空
+                const nullList = this._.filter(changeList, function(item) {
+                    return !item.name;
+                });
+                if (nullList.length > 0) continue;
+                // 判断是否需要更新auditList
+                const auditList = await this.ctx.service.changeAudit.getAllDataByCondition({ where: { cid: l.cid, times: l.times }, orders: [['usite', 'asc']] });
+                auditList.shift();
+                if (shenpi_status === shenpiConst.sp_status.gdspl) {
+                    // 判断并获取审批组
+                    const group = await this.ctx.service.shenpiGroup.getSelectGroupByChangeType(tid, shenpiConst.sp_type.change, 'change', l.sp_group);
+                    if ((group && l.sp_group !== group.id) || (!group && l.sp_group !== 0)) {
+                        l.sp_group = group ? group.id : 0;
+                        await this.ctx.service.change.defaultUpdate({ sp_group: l.sp_group }, { where: { cid: l.cid } });
+                    }
+                    const condition = { tid, sp_type: shenpiConst.sp_type.change, sp_status: shenpi_status, sp_group: l.sp_group };
+                    const shenpiList = await this.ctx.service.shenpiAudit.getAllDataByCondition({ where: condition, orders: [['audit_order', 'asc']] });
+                    if (l.sp_group !== 0 || shenpiList.length !== 0) {
+                        // const shenpiIdList = _.map(shenpiList, 'audit_id');
+                        // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
+                        let sameAudit = auditList.length === shenpiList.length;
+                        if (sameAudit) {
+                            for (const audit of auditList) {
+                                const shenpi = shenpiList.find(x => { return x.audit_id === audit.uid; });
+                                if (!shenpi || shenpi.audit_order !== audit.audit_order || shenpi.audit_type !== audit.audit_type) {
+                                    sameAudit = false;
+                                    break;
+                                }
+                            }
+                        }
+                        if (!sameAudit) {
+                            await this.ctx.service.changeAudit.updateNewAuditList(l, shenpiList);
+                        }
+                    }
+                } else if (shenpi_status === shenpiConst.sp_status.gdzs) {
+                    const shenpiInfo = await this.service.shenpiAudit.getDataByCondition({ tid: this.tender.id, sp_type: shenpiConst.sp_type.change, sp_status: shenpi_status });
+                    // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审
+                    const lastAuditors = auditList.filter(x => { return x.usite === auditList.length - 1; });
+                    if (shenpiInfo && (lastAuditors.length === 0 || (lastAuditors.length > 1 || shenpiInfo.audit_id !== lastAuditors[0].uid))) {
+                        await this.service.changeAudit.updateLastAudit(l, auditList, shenpiInfo.audit_id);
+                    }
+                }
+                l.auditList = await this.ctx.service.changeAudit.getUniqUserGroup(l.cid, l.times);
+                l.changeList = changeList;
+                returnList.push(l);
+            }
+            return returnList;
+        }
+
+        async getCheckingList(tid, uid) {
+            const sql = 'select c.* from ?? as c LEFT JOIN ?? as ca ON c.cid = ca.cid where c.tid = ? and ca.status = ? and ca.uid = ?';
+            const sqlParams = [this.tableName, this.ctx.service.changeAudit.tableName, tid, audit.change.status.checking, uid];
+            const list = await this.db.query(sql, sqlParams);
+            const returnList = [];
+            // 判断是否是终审
+            for (const l of list) {
+                const changeList = await this.ctx.service.changeAuditList.getAllDataByCondition({ where: { cid: l.cid } });
+                const auditors = await this.ctx.service.changeAudit.getAuditorsNew(l.cid, l.times); // 全部参与的审批人
+                const auditorGroups = this.ctx.helper.groupAuditors(auditors, 'usort');
+                const userGroups = this.ctx.helper.groupAuditorsUniq(auditorGroups);
+                const finalAuditorIds = userGroups[userGroups.length - 1].map(x => { return x.uid; });
+                l.is_finalAudit = finalAuditorIds.includes(uid);
+                l.changeList = changeList;
+                l.p_code = l.p_code ? l.p_code : l.code;
+                returnList.push(l);
+            }
+            return returnList;
+        }
     }
 
     return Change;

+ 9 - 0
app/service/change_audit_list.js

@@ -408,6 +408,8 @@ module.exports = app => {
             let total_price = 0;
             let positive_tp = 0;
             let negative_tp = 0;
+            let valuation_tp = 0;
+            let unvaluation_tp = 0;
             const tp_decimal = this.ctx.change.tp_decimal ? this.ctx.change.tp_decimal : this.ctx.tender.info.decimal.tp;
             for (const cl of changeList) {
                 const price = this.ctx.helper.mul(cl.unit_price, cl.spamount, tp_decimal);
@@ -417,11 +419,18 @@ module.exports = app => {
                 } else {
                     negative_tp = this.ctx.helper.accAdd(negative_tp, price);
                 }
+                if (cl.is_valuation) {
+                    valuation_tp = this.ctx.helper.accAdd(valuation_tp, price);
+                } else {
+                    unvaluation_tp = this.ctx.helper.accAdd(unvaluation_tp, price);
+                }
             }
             const updateData = {
                 total_price,
                 positive_tp,
                 negative_tp,
+                valuation_tp,
+                unvaluation_tp,
             };
             if (updateTpDecimal) {
                 updateData.tp_decimal = tp_decimal;

+ 6 - 3
app/service/material.js

@@ -157,6 +157,7 @@ module.exports = app => {
                 is_stage_self: data.is_stage_self,
                 qty_source: data.qty_source,
                 is_new_qty: 1,
+                rate: 9,
             };
             const transaction = await this.db.beginTransaction();
             try {
@@ -215,10 +216,11 @@ module.exports = app => {
                     // 修改本期应耗数量值和有效价差,需要剔除不参与调差的清单数据,并返回总金额
                     let m_tp = null;
                     let m_tax_tp = null;
+                    let rate_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), preMaterial.is_stage_self, data.qty_source);
+                        [m_tp, m_tax_tp, rate_tp] = await this.ctx.service.materialStageBills.insertBills(transaction, this.ctx.tender.id, newMaterial.id, newMaterial.stage_id, insertMaterialStage, JSON.parse(newMaterial.decimal), preMaterial.is_stage_self, data.qty_source, newMaterial.rate);
                     } 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), preMaterial.is_stage_self, data.qty_source);
+                        [m_tp, m_tax_tp, rate_tp] = await this.ctx.service.materialBills.updateNewMaterial(transaction, this.ctx.tender.id, newMaterial.id, this.ctx, newMaterial.stage_id, JSON.parse(newMaterial.decimal), preMaterial.is_stage_self, data.qty_source, newMaterial.rate);
                     }
                     // 修改现行价格指数,并返回调差基数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));
@@ -229,6 +231,7 @@ module.exports = app => {
                         id: newMaterial.id,
                         m_tp,
                         m_tax_tp,
+                        rate_tp,
                         ex_calc: JSON.stringify(ex_calc),
                         tp_data: JSON.stringify(tp_data),
                     };
@@ -399,7 +402,7 @@ module.exports = app => {
          * @return {Promise<*>}
          */
         async getPreTpHs(tid, order, tp) {
-            const sql = 'SELECT SUM(ROUND(`m_tp`*(1+ `rate`/100),' + tp + ')) AS `pre_tp_hs` FROM ?? WHERE `tid` = ? AND `material_tax` = ? AND `order` < ?';
+            const sql = 'SELECT SUM(`rate_tp`) AS `pre_tp_hs` FROM ?? WHERE `tid` = ? AND `material_tax` = ? AND `order` < ?';
             const sqlParam = [this.tableName, tid, 0, order];
             const result = await this.db.queryOne(sql, sqlParam);
             return result.pre_tp_hs;

+ 17 - 4
app/service/material_bills.js

@@ -584,7 +584,7 @@ module.exports = app => {
          * @param mid
          * @returns {Promise<number>}
          */
-        async updateNewMaterial(transaction, tid, mid, ctx, stage_id, decimal, pre_is_stage_self = 0, qty_source = 1) {
+        async updateNewMaterial(transaction, tid, mid, ctx, stage_id, decimal, pre_is_stage_self = 0, qty_source = 1, rate) {
             const materialBillsData = await this.getAllDataByCondition({ where: { tid } });
             let m_tp = 0;
             let m_tax_tp = 0;
@@ -594,7 +594,8 @@ module.exports = app => {
                 m_tp = this.ctx.helper.add(m_tp, one_tp);
                 m_tax_tp = this.ctx.helper.add(m_tax_tp, one_tax_tp);
             }
-            return [m_tp, m_tax_tp];
+            const rate_tp = this.ctx.helper.round(this.ctx.helper.mul(m_tp, (1 + this.ctx.helper.div(rate, 100))), decimal.tp);
+            return [m_tp, m_tax_tp, rate_tp];
         }
 
         /**
@@ -607,8 +608,8 @@ module.exports = app => {
         async calcQuantityByMB(transaction, mid, mb, materialCalculator, decimal, pre_is_stage_self, qty_source) {
             const [newmsg_spread, newm_spread] = await this.getSpread(mb, null, decimal.up);
             if (mb.t_type === materialConst.t_type[0].value) {
-                const newQuantity = await this.ctx.service.materialList.getMbQuantity(transaction, mid, qty_source, decimal.qty, mb.id, 0);
-                const newTp = this.ctx.helper.round(this.ctx.helper.mul(this.ctx.helper.round(newQuantity, decimal.qty), newm_spread), decimal.tp);
+                const newQuantity = await this.ctx.service.materialList.getMbQuantity(transaction, mid, qty_source, decimal.qty, mb.id);
+                const newTp = this.ctx.helper.round(this.ctx.helper.mul(newQuantity, newm_spread), decimal.tp);
                 const updateData = {
                     id: mb.id,
                     quantity: newQuantity,
@@ -767,6 +768,18 @@ module.exports = app => {
                 m_tp: tp.total_price,
                 m_tax_tp: tp.tax_total_price,
             };
+            // 计算建筑税价
+            if (this.ctx.material.is_stage_self) {
+                const materialStages = await transaction.select(this.ctx.service.materialStage.tableName, { where: { mid: this.ctx.material.id } });
+                let rate_tp = 0;
+                for (const ms of materialStages) {
+                    const ms_rate_tp = this.ctx.helper.round(this.ctx.helper.mul(ms.m_tp, 1 + this.ctx.material.rate / 100), this.ctx.material.decimal.tp);
+                    rate_tp = this.ctx.helper.add(rate_tp, ms_rate_tp);
+                }
+                updateData2.rate_tp = rate_tp;
+            } else {
+                updateData2.rate_tp = this.ctx.helper.round(this.ctx.helper.mul(tp.total_price, 1 + this.ctx.material.rate / 100), this.ctx.material.decimal.tp);
+            }
             console.log(tp);
             // if (this.ctx.material.material_tax) {
             //     updateData2.m_tax_tp = tp.tax_total_price;

+ 8 - 6
app/service/material_stage_bills.js

@@ -25,9 +25,10 @@ module.exports = app => {
             super(ctx);
             this.tableName = 'material_stage_bills';
         }
-        async insertBills(transaction, tid, mid, stage_id, materialStageData, decimal, pre_is_stage_self = 0, qty_source = 1) {
+        async insertBills(transaction, tid, mid, stage_id, materialStageData, decimal, pre_is_stage_self = 0, qty_source = 1, rate) {
             let m_tp = 0;
             let m_tax_tp = 0;
+            let rate_tp = 0;
             // 复制工料表并生成
             const billsList = await transaction.select(this.ctx.service.materialBills.tableName, { where: { tid } });
             if (billsList.length > 0) {
@@ -88,16 +89,17 @@ module.exports = app => {
                         m_tax_tp: newTaxTp,
                     };
                     updateStageData.push(oneStageData);
+                    rate_tp = this.ctx.helper.add(rate_tp, this.ctx.helper.round(this.ctx.helper.mul(newTp, (1 + this.ctx.helper.div(rate, 100))), decimal.tp));
                 }
                 await transaction.updateRows(this.ctx.service.materialStage.tableName, updateStageData);
             }
-            return [m_tp, m_tax_tp];
+            return [m_tp, m_tax_tp, rate_tp];
         }
 
         // 添加工料时同步生成
         async add(transaction, id, remark = null) {
             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 msInfo = await transaction.get(this.ctx.service.materialStage.tableName, { tid: this.ctx.tender.id, mid: this.ctx.material.id, sid });
                 const insertData = {
                     tid: this.ctx.tender.id,
                     mid: this.ctx.material.id,
@@ -113,7 +115,7 @@ module.exports = app => {
         async adds(transaction, billsList, remark = null, ms_id = null) {
             // 这里有坑!必须按独立期分开入库才行,不然会出现第二期之后msg_tp的数据无法入库的情况,奇怪的bug
             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 msInfo = await transaction.get(this.ctx.service.materialStage.tableName, { tid: this.ctx.tender.id, mid: this.ctx.material.id, sid });
                 const insertList = [];
                 for (const b of billsList) {
                     const insertData = {
@@ -223,8 +225,8 @@ module.exports = app => {
         async calcQuantityByMB(transaction, mid, mb, msb, materialCalculator, decimal, pre_is_stage_self, qty_source) {
             const [newmsg_spread, newm_spread] = await this.getSpread(mb, null, decimal.up);
             if (mb.t_type === materialConst.t_type[0].value) {
-                const newQuantity = await this.ctx.service.materialList.getMbQuantity(transaction, mid, qty_source, decimal.qty, mb.id, msb.ms_id, 0);
-                const newTp = this.ctx.helper.round(this.ctx.helper.mul(this.ctx.helper.round(newQuantity, decimal.qty), newm_spread), decimal.tp);
+                const newQuantity = await this.ctx.service.materialList.getMbQuantity(transaction, mid, qty_source, decimal.qty, mb.id, msb.ms_id);
+                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;

+ 4 - 0
app/service/report.js

@@ -499,6 +499,10 @@ module.exports = app => {
                         rst[filter] = await service.rptGatherMemory.getGatherStagePos(memFieldKeys[filter],
                             customDefine.gather_select, customSelect ? customSelect.gather_select : null);
                         break;
+                    case 'mem_gather_stage_change':
+                        rst[filter] = await service.rptGatherMemory.getGatherStageChange(memFieldKeys[filter],
+                            customDefine.gather_select, customSelect ? customSelect.gather_select : null);
+                        break;
                     // case 'mem_material_bills':
                     //     rst[filter] = await service.rptGatherMemory.getMaterialBills(params.tender_id, params.material_order, memFieldKeys[filter]);
                     //     break;

+ 16 - 10
app/service/rpt_archive.js

@@ -125,17 +125,23 @@ module.exports = app => {
             let rst = null;
             this.transaction = await this.db.beginTransaction();
             try {
-                const data = {
-                    id,
-                    prj_id,
-                    stage_id,
-                    business_id,
-                    tender_id,
-                    business_type: rptArchiveConst.getBusinessType(stage_id),
-                    content: JSON.stringify(archiveArr),
-                };
                 // console.log(data);
-                rst = await this.transaction.update(this.tableName, data);
+                // rst = await this.transaction.update(this.tableName, data);
+                if (archiveArr.length === 0) {
+                    await this.transaction.delete(this.tableName, { id });
+                    await this.transaction.update(this.ctx.service.stage.tableName, { id: stage_id, rpt_filed: 0 });
+                } else {
+                    const data = {
+                        id,
+                        prj_id,
+                        stage_id,
+                        business_id,
+                        tender_id,
+                        business_type: rptArchiveConst.getBusinessType(stage_id),
+                        content: JSON.stringify(archiveArr),
+                    };
+                    rst = await this.transaction.update(this.tableName, data);
+                }
                 await this.transaction.commit();
             } catch (ex) {
                 console.log(ex);

+ 170 - 9
app/service/rpt_gather_memory.js

@@ -831,14 +831,25 @@ module.exports = app => {
 
                 info.pre_contract_tp = stage.pre_contract_tp;
                 info.pre_qc_tp = stage.pre_qc_tp;
+                info.pre_positive_qc_tp = stage.pre_positive_qc_tp;
+                info.pre_negative_qc_tp = stage.pre_negative_qc_tp;
                 info.pre_gather_tp = helper.add(info.pre_contract_tp, info.pre_qc_tp);
 
                 info.contract_tp = stage.contract_tp;
                 info.qc_tp = stage.qc_tp;
-                info.gather_tp = helper.add(info.contract_tp, info.qc_tp);
-
-                info.end_contract_tp = helper.add(info.pre_contract_tp, info.contract_tp);
-                info.end_qc_tp = helper.add(info.pre_qc_tp, info.qc_tp);
+                info.positive_qc_tp = stage.positive_qc_tp;
+                info.positive_qc_pc_tp = stage.positive_qc_pc_tp;
+                info.negative_qc_tp = stage.negative_qc_tp;
+                info.negative_qc_pc_tp = stage.negative_qc_pc_tp;
+                info.contract_pc_tp = stage.contract_pc_tp;
+                info.qc_pc_tp = stage.qc_pc_tp;
+                info.pc_tp = stage.pc_tp;
+                info.gather_tp = helper.sum([info.contract_tp, info.qc_tp, info.pc_tp]);
+
+                info.end_contract_tp = helper.sum([info.pre_contract_tp, info.contract_tp, info.contract_pc_tp]);
+                info.end_qc_tp = helper.sum([info.pre_qc_tp, info.qc_tp, info.qc_pc_tp]);
+                info.end_positive_qc_tp = helper.sum([info.pre_positive_qc_tp, info.positive_qc_tp, info.positive_qc_pc_tp]);
+                info.end_negative_qc_tp = helper.sum([info.pre_negative_qc_tp, info.negative_qc_tp, info.negative_qc_pc_tp]);
                 info.end_gather_tp = helper.add(info.pre_gather_tp, info.gather_tp);
 
                 info.yf_tp = stage.yf_tp;
@@ -855,25 +866,41 @@ module.exports = app => {
             if (preStage) {
                 info.pre_contract_tp = helper.add(preStage.contract_tp, preStage.pre_contract_tp);
                 info.pre_qc_tp = helper.add(preStage.qc_tp, preStage.pre_qc_tp);
+                info.pre_positive_qc_tp = helper.add(preStage.positive_qc_tp, preStage.pre_positive_qc_tp);
+                info.pre_negative_qc_tp = helper.add(preStage.negative_qc_tp, preStage.pre_negative_qc_tp);
                 info.pre_gather_tp = helper.add(info.pre_contract_tp, info.pre_qc_tp);
                 info.pre_yf_tp = helper.add(preStage.yf_tp, preStage.pre_yf_tp);
+                info.pre_sf_tp = helper.add(preStage.sf_tp, preStage.pre_sf_tp);
             }
 
             for (const stage of stages) {
                 await this.ctx.service.stage.doCheckStage(stage);
                 await this.ctx.service.stage.checkStageGatherData(stage, this.ctx.session.sessionUser.is_admin);
 
-
                 info.contract_tp = helper.add(info.contract_tp, stage.contract_tp);
                 info.qc_tp = helper.add(info.qc_tp, stage.qc_tp);
 
+                info.positive_qc_tp = helper.add(info.positive_qc_tp, stage.positive_qc_tp);
+                info.positive_qc_pc_tp = helper.add(info.positive_qc_tp, stage.positive_qc_pc_tp);
+                info.negative_qc_tp = helper.add(info.negative_qc_tp, stage.negative_qc_tp);
+                info.negative_qc_pc_tp = helper.add(info.negative_qc_pc_tp, stage.negative_qc_pc_tp);
+
+                info.contract_pc_tp = helper.add(info.contract_pc_tp, stage.contract_pc_tp);
+                info.qc_pc_tp = helper.add(info.qc_pc_tp, stage.qc_pc_tp);
+                info.pc_tp = helper.add(info.pc_tp, stage.pc_tp);
+
                 info.yf_tp = helper.add(info.yf_tp, stage.yf_tp);
+
+                info.sf_tp = helper.add(info.sf_tp, stage.sf_tp);
             }
-            info.gather_tp = helper.add(info.contract_tp, info.qc_tp);
-            info.end_contract_tp = helper.add(info.pre_contract_tp, info.contract_tp);
-            info.end_qc_tp = helper.add(info.pre_qc_tp, info.qc_tp);
+            info.gather_tp = helper.sum([info.contract_tp, info.qc_tp, info.pc_tp]);
+            info.end_contract_tp = helper.sum([info.pre_contract_tp, info.contract_tp, info.contract_pc_tp]);
+            info.end_qc_tp = helper.sum([info.pre_qc_tp, info.qc_tp, info.qc_pc_tp]);
+            info.end_positive_qc_tp = helper.sum([info.pre_positive_qc_tp, info.positive_qc_tp, info.positive_qc_pc_tp]);
+            info.end_negative_qc_tp = helper.sum([info.pre_negative_qc_tp, info.negative_qc_tp, info.negative_qc_pc_tp]);
             info.end_gather_tp = helper.add(info.pre_gather_tp, info.gather_tp);
             info.end_yf_tp = helper.add(info.pre_yf_tp, info.yf_tp);
+            info.end_sf_tp = helper.add(info.pre_sf_tp, info.sf_tp);
         }
         async _gatherZoneTenderInfo(tender, index, zone) {
             const info = await this._getBaseTenderInfo(tender);
@@ -1213,7 +1240,7 @@ module.exports = app => {
             if (!gsDefine || !gsDefine.enable) return [];
             if (!gsCustom || !gsCustom.tenders || gsCustom.tenders.length === 0) return [];
 
-            this.resultTenderInfo = [];
+            this.resultDealBills = [];
             const gsSetting = JSON.parse(gsDefine.setting);
             let commonIndex = 0;
             const completeDatas = [];
@@ -1343,6 +1370,140 @@ module.exports = app => {
             return result;
         }
 
+        async _gatherStagesChange(completeData, tender, stages, preStage, gatherType = 'flow'){
+            const result = [];
+            const findR = function(source) {
+                let r = result.find(x => { return x.cbid === source.cbid});
+                if (!r) {
+                    r = { cid: source.cid, cbid: source.cbid, qty: 0, pre_qty: 0 };
+                    result.push(r);
+                }
+                return r;
+            };
+            const helper = this.ctx.helper;
+
+            if (preStage) {
+                const preStageChange = await this.ctx.service.stageChangeFinal.getEndStageData(stage.tid, preStage.order);
+                if (gatherType === 'flow') {
+                    result.push(...preStageChange);
+                } else {
+                    preStageChange.forEach(sc => {
+                        const r = findR(sc);
+                        r.pre_qty = helper.add(r.pre_qty, sc.qty);
+                    });
+                }
+            }
+
+            for (const stage of stages) {
+                let curStageChange;
+                if (stage.status === auditConst.stage.status.checked) {
+                    curStageChange = await this.ctx.service.stageChangeFinal.getAllDataByCondition({ where: { tid: stage.tid, sid: stage.id } });
+                } else {
+                    await this.ctx.service.stage.doCheckStage(stage);
+                    curStageChange = await this.ctx.service.stageChange.getCurStageData(stage.tid, stage.id, stage.curTimes, stage.curOrder);
+                }
+                if (gatherType === 'flow') {
+                    result.push(...curStageChange);
+                } else {
+                    curStageChange.forEach(sc => {
+                        const r = findR(sc);
+                        r.qty = helper.add(r.qty, sc.qty);
+                    });
+                }
+            }
+
+            result.forEach(r => { r.end_qty = helper.add(r.pre_qty, r.qty); });
+            return result;
+        }
+        async _gatherCustomZoneStageChange(sTender, completeData, timeType, gatherType) {
+            const [stages, preStage, endStage] = await this._getCustomZoneStages(tender, zone, timeType);
+            await this._gatherStagesChange(completeData, tender, stages, preStage, gatherType);
+        }
+        async _gatherStageChange(completeData, tender, stage, hasPre, gatherType = 'flow'){
+            if (!stage) return [];
+            const helper = this.ctx.helper;
+            await this.ctx.service.stage.doCheckStage(stage);
+
+            const curStageChange = await this.ctx.service.stageChange.getCurStageData(stage.tid, stage.id, stage.curTimes, stage.curOrder);
+            const preStageChange = hasPre && stage.preCheckedStage ? await this.ctx.service.stageChangeFinal.getEndStageData(stage.tid, stage.preCheckedStage.order) : [];
+            if (gatherType === 'flow') return [...preStageChange, ...curStageChange];
+
+            const result = [];
+            const findR = function(source) {
+                let r = result.find(x => { return x.cbid === source.cbid});
+                if (!r) {
+                    r = { cid: source.cid, cbid: source.cbid, qty: 0, pre_qty: 0 };
+                    result.push(r);
+                }
+                return r;
+            };
+            curStageChange.forEach(sc => {
+                const r = findR(sc);
+                r.qty = helper.add(r.qty, sc.qty);
+            });
+            preStageChange.forEach(sc => {
+                const r = findR(sc);
+                r.pre_qty = helper.add(r.pre_qty, sc.qty);
+            });
+            result.forEach(r => { r.end_qty = helper.add(r.pre_qty, r.qty); });
+            return result;
+        }
+        async _gatherMonthStageChange(sTender, completeData, month, hasPre, gatherType) {
+            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+            const stages = await this._getValidStages(tender.id);
+            const stage = this.ctx.helper._.find(stages, {s_time: month});
+            await this._gatherStageChange(completeData, tender, stage, hasPre, gatherType);
+        }
+        async _gatherOrderStageChange(sTender, completeData, order, hasPre, gatherType) {
+            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+            const stages = await this._getValidStages(tender.id);
+            const stage = this.ctx.helper._.find(stages, {order: order});
+            await this._gatherStageChange(completeData, tender, stage, hasPre, gatherType);
+        }
+        async _gatherFinalStageChange(sTender, completeData, hasPre, gatherType) {
+            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+            const stages = await this._getValidStages(tender.id);
+            await this._gatherStageChange(completeData, tender, stages[0], hasPre, gatherType);
+        }
+        async _gatherCheckedFinalStageChange(sTender, completeData, hasPre, gatherType) {
+            const tender = await this.ctx.service.tender.getCheckTender(sTender.tid);
+            const stages = await this._getCheckedStages(tender.id);
+            await this._gatherStageChange(completeData, tender, stages[0], hasPre, gatherType);
+        }
+        async getGatherStageChange(memFieldKeys, gsDefine, gsCustom) {
+            if (!gsDefine || !gsDefine.enable) return [];
+            if (!gsCustom || !gsCustom.tenders || gsCustom.tenders.length === 0) return [];
+            const gsSetting = JSON.parse(gsDefine.setting);
+            if (gsSetting.type !== 'stage') return [];
+
+            this.resultStageChange = [];
+            let commonIndex = 0;
+            const completeDatas = [];
+            for (const tender of gsCustom.tenders) {
+                const completeData = { prefix: 't_' + commonIndex + '_' };
+                completeDatas.push(completeData);
+                switch (gsSetting.type) {
+                    case 'month':
+                        await this._gatherMonthStageChange(tender, completeData, gsCustom.month, gsSetting.hasPre, gsSetting.gather);
+                        break;
+                    case 'final':
+                        await this._gatherFinalStageChange(tender, completeData, gsSetting.hasPre, gsSetting.gather);
+                        break;
+                    case 'checked-final':
+                        await this._gatherCheckedFinalStageChange(tender, completeData, gsSetting.hasPre, gsSetting.gather);
+                        break;
+                    case 'stage':
+                        await this._gatherOrderStageChange(tender, completeData, gsCustom.stage, gsSetting.hasPre, gsSetting.gather);
+                        break;
+                    case 'custom-zone':
+                        await this._gatherCustomZoneStageChange(tender, completeData, gsCustom.custom_zone, gsSetting.timeType, gsSetting.gather);
+                        break;
+                }
+                commonIndex++;
+            }
+            return this.resultStageChange;
+        }
+
         async getGatherAdvancePay(memFieldKeys, gsDefine, gsCustom) {
             if (!gsDefine || !gsDefine.enable) return [];
             if (!gsCustom || !gsCustom.tenders || gsCustom.tenders.length === 0) return [];

+ 40 - 0
app/service/stage_audit_ass.js

@@ -40,6 +40,46 @@ module.exports = app => {
             return result;
         }
 
+        async getAuditStageAss(ass_user_id) {
+            // 找出待上报或待审批的协同字段
+            const accountStageAssData = await this.getAllDataByCondition({ where: { ass_user_id, confirm: 0 } });
+            const result = [];
+            const accountAssData = await this.ctx.service.auditAss.getAllDataByCondition({ where: { ass_user_id } });
+            for (const as of accountStageAssData) {
+                const index = accountAssData.findIndex(x => { return x.tid === as.tid && x.user_id === as.user_id; });
+                if (index >= 0) {
+                    accountAssData.splice(index, 1);
+                    result.push(as);
+                }
+            }
+            result.push(...accountAssData);
+            // 判断该标段是否存在待审批或待上报的协同人,同时到本人协同阶段
+            const result2 = [];
+            if (result.length > 0) {
+                for (const r of result) {
+                    const t = await this.ctx.service.tender.getDataById(r.tid);
+                    const s = r.sid ? await this.ctx.service.stage.getDataById(r.sid) : await this.ctx.service.stage.getLastestStage(r.tid);
+                    if (s) {
+                        r.tender_name = t.name;
+                        r.sstatus = s.status;
+                        r.sorder = s.order;
+                        if (s && s.status === auditConst.stage.status.checkNo && s.user_id === r.user_id) {
+                            const lastAudit = await this.ctx.service.stageAudit.getLastestAuditor(s.id, s.times - 1, auditConst.stage.status.checkNo);
+                            r.begin_time = lastAudit ? lastAudit.end_time : s.in_time;
+                            result2.push(r);
+                        } else {
+                            const curAudits = await this.ctx.service.stageAudit.getCurAuditors(s.id, s.times);
+                            if (curAudits.length > 0 && this._.findIndex(curAudits, { user_id: r.user_id }) !== -1) {
+                                r.begin_time = curAudits[0].begin_time;
+                                result2.push(r);
+                            }
+                        }
+                    }
+                }
+            }
+            return result2;
+        }
+
         async getUserAssist(stage, user_id) {
             const stageData = await this.getAllDataByCondition({ where: { sid: stage.id, times: stage.times, user_id } });
             if (stage.status === auditConst.stage.status.checked) return stageData;

+ 12 - 6
app/service/stage_change.js

@@ -643,12 +643,18 @@ module.exports = app => {
          * @return {Promise<void>}
          */
         async getStageUsedChangeId(sid) {
-            const sql = 'SELECT lid, pid, cid, cbid, qty, stimes, sorder FROM ' + this.tableName + ' WHERE sid = ?';
+            const sql = 'SELECT lid, pid, cid, cbid, qty, stimes, sorder, no_value FROM ' + this.tableName + ' WHERE sid = ?';
             const curAll = await this.db.query(sql, [sid]);
-            const cur = this.ctx.helper.filterLastestData(curAll, ['lid', 'pid', 'cbid'], 'stimes', 'sorder');
+            const cur = this.ctx.helper.filterLastestData(curAll, ['lid', 'pid', 'cbid', 'no_value'], 'stimes', 'sorder');
             return this._.map(this._.filter(cur, 'qty'), 'cid');
         }
 
+        async getCurStageData(tid, sid, stimes, sorder) {
+            const sql = `SELECT * From ${this.tableName} WHERE tid = ? AND sid = ? AND (stimes < ? OR (stimes = ? AND sorder < ?))`;
+            const data = await this.db.query(sql, [tid, sid, stimes, stimes, sorder]);
+            return this.ctx.helper.filterLastestData(data, ['lid', 'pid', 'cbid', 'no_value'], 'stimes', 'sorder');
+        }
+
         async getFinalStageData(tid, sid) {
             const data = await this.getAllDataByCondition({ where: { tid, sid } });
             return this.ctx.helper.filterLastestData(data, ['lid', 'pid', 'cbid', 'no_value'], 'stimes', 'sorder');
@@ -678,7 +684,7 @@ module.exports = app => {
                 '  LEFT JOIN ' + this.ctx.service.change.tableName + ' c ON sc.cid = c.cid' +
                 '  WHERE sid = ? ' + (stage.readOnly ? ` and (stimes < ${stage.curTimes} or (stimes = ${stage.curTimes} and sorder <= ${stage.curOrder}))` : '');
             let data = await this.db.query(sql, [stage.id]);
-            data = helper.filterLastestData(data, ['lid', 'pid', 'cbid'], 'stimes', 'sorder');
+            data = helper.filterLastestData(data, ['lid', 'pid', 'cbid', 'no_value'], 'stimes', 'sorder');
             const bqData = [];
             for (const d of data) {
                 if (!d.qty || d.no_value) continue;
@@ -767,18 +773,18 @@ module.exports = app => {
 
         async getStageMinusChange(stage) {
             const data = await this.getAllDataByCondition({ where: { sid: stage.id, minus: 1 } });
-            return this.ctx.helper.filterLastestData(data, ['lid', 'pid', 'cbid'], 'stimes', 'sorder');
+            return this.ctx.helper.filterLastestData(data, ['lid', 'pid', 'cbid', 'no_value'], 'stimes', 'sorder');
         };
 
         async getBillsMinusQty(stage, lid) {
             const data = await this.getAllDataByCondition({ where: { sid: stage.id, lid, minus: 1 } });
-            const filter = this.ctx.helper.filterLastestData(data, ['lid', 'pid', 'cbid'], 'stimes', 'sorder');
+            const filter = this.ctx.helper.filterLastestData(data, ['lid', 'pid', 'cbid', 'no_value'], 'stimes', 'sorder');
             return { lid, qty: this.ctx.helper.sum(filter.map(x => { return x.qty; })) };
         };
 
         async getPosMinusQty(stage, pid) {
             const data = await this.getAllDataByCondition({ where: { sid: stage.id, pid, minus: 1 } });
-            const filter = this.ctx.helper.filterLastestData(data, ['lid', 'pid', 'cbid'], 'stimes', 'sorder');
+            const filter = this.ctx.helper.filterLastestData(data, ['lid', 'pid', 'cbid', 'no_value'], 'stimes', 'sorder');
             return { pid, qty: this.ctx.helper.sum(filter.map(x => { return x.qty; })) };
         };
 

+ 10 - 8
app/view/change/index.ejs

@@ -68,12 +68,14 @@
                     <span class="ml-3">本页小计:<%- page_total %>元</span><span class="ml-3">合计:<%- tp %>元</span>
                 </div>
             </div>
-            <% if (tender.user_id === ctx.session.sessionUser.accountId) { %>
             <div class="ml-auto">
-                <a href="#add-bj" data-toggle="modal" data-target="#add-bj" class="btn btn-sm btn-primary pull-right ml-1">新建变更令</a>
-                <a href="#setting" data-toggle="modal" data-target="#setting" class="btn btn-sm btn-outline-primary pull-right ml-1"><i class="fa fa-cog"></i></a>
+                <% if (tender.user_id === ctx.session.sessionUser.accountId) { %>
+                    <a href="#add-bj" data-toggle="modal" data-target="#add-bj" class="btn btn-sm btn-primary pull-right ml-1">新建变更令</a>
+                    <a href="#setting" data-toggle="modal" data-target="#setting" class="btn btn-sm btn-outline-primary pull-right ml-2"><i class="fa fa-cog"></i></a>
+                    <a href="#batch-sb" data-toggle="modal" data-target="#batch-sb" class="btn btn-sm btn-primary pull-right ml-2">批量上报</a>
+                <% } %>
+                    <a href="#batch-sp" data-toggle="modal" data-target="#batch-sp" class="btn btn-sm btn-success pull-right">批量审批</a>
             </div>
-            <% } %>
         </div>
     </div>
     <div class="content-wrap">
@@ -87,8 +89,8 @@
                     <tr><th width="3%">序号</th>
                         <th width="18%" id="sort_change">申请编号/变更令号</th><th width="24%">变更工程名称</th>
                         <th width="7%">变更性质</th><% if (ctx.session.sessionProject.page_show.openChangeState) { %><th width="7%">变更令状态</th><% } %>
-                        <th width="7%">变更金额</th><th width="7%">正变更金额</th>
-                        <th width="7%">负变更金额</th><th width="7%">审批状态</th>
+                        <th width="7%">变更金额</th><th width="7%">计价金额</th>
+                        <th width="7%">不计价金额</th><th width="7%">审批状态</th>
                         <th width="14%">审批进度</th><th width="4%">操作</th>
                     </tr>
                     </thead>
@@ -109,8 +111,8 @@
                         <td><%- ctx.helper._.find(changeState, { order: c.state }).name %></td>
                         <% } %>
                         <td style="text-align: right"><%= ctx.helper.roundNum(c.total_price, tpUnit) %></td>
-                        <td style="text-align: right"><%= ctx.helper.roundNum(c.positive_tp, tpUnit) %></td>
-                        <td style="text-align: right"><%= ctx.helper.roundNum(c.negative_tp, tpUnit) %></td>
+                        <td style="text-align: right"><%= ctx.helper.roundNum(c.valuation_tp, tpUnit) %></td>
+                        <td style="text-align: right"><%= ctx.helper.roundNum(c.unvaluation_tp, tpUnit) %></td>
                         <td class="text-center">
                             <% if (c.status === auditConst.status.uncheck && c.uid === ctx.session.sessionUser.accountId) { %>
                                 <a href="<%- '/tender/' + ctx.tender.id + '/change/' + c.cid %>/information" class="btn <%- auditConst.statusButtonClass[c.status] %> btn-sm"><%- auditConst.statusButton[c.status] %></a>

+ 2 - 0
app/view/change/information.ejs

@@ -485,6 +485,8 @@
     let changeTp = parseFloat('<%- change.total_price ? change.total_price : 0 %>');
     let changePp = parseFloat('<%- change.positive_tp ? change.positive_tp : 0 %>');
     let changeNp = parseFloat('<%- change.negative_tp ? change.negative_tp : 0 %>');
+    let changeVp = parseFloat('<%- change.valuation_tp ? change.valuation_tp : 0 %>');
+    let changeUp = parseFloat('<%- change.unvaluation_tp ? change.unvaluation_tp : 0 %>');
     const changeStatus = parseFloat('<%- change.status %>');
     const touristPermission = parseInt('<%- ctx.tender.touristPermission.file %>');
     const precision = JSON.parse('<%- JSON.stringify(precision) %>');

+ 7 - 9
app/view/change/information_modal.ejs

@@ -209,11 +209,10 @@
                         </div>
                     </div>
                 </div>
-                <form class="modal-footer" method="post" action="<%- preUrl %>/audit/start" onsubmit="return checkChangeFrom()">
-                    <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
-                    <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
-                    <button type="submit" class="btn btn-primary btn-sm">确认上报</button>
-                </form>
+                <div class="modal-footer">
+                    <button class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
+                    <button class="btn btn-primary btn-sm" onclick="checkChangeFrom();">确认上报</button>
+                </div>
             </div>
         </div>
     </div>
@@ -389,13 +388,12 @@
                         </div>
                     </div>
                 </div>
-                <form class="modal-footer" method="post" action="<%- preUrl %>/audit/start" onsubmit="return checkChangeFrom()">
+                <div class="modal-footer">
                     <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
-                    <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                     <% if((ctx.change.status === auditConst.status.checkNo || ctx.change.status === auditConst.status.revise) && ctx.session.sessionUser.accountId === ctx.change.uid) { %>
-                        <button class="btn btn-primary btn-sm sp-list-item" type="submit">确认上报</button>
+                        <button class="btn btn-primary btn-sm sp-list-item" onclick="checkChangeFrom();">确认上报</button>
                     <% } %>
-                </form>
+                </div>
             </div>
         </div>
     </div>

+ 955 - 0
app/view/change/modal.ejs

@@ -167,7 +167,136 @@
         </div>
     </div>
 </div>
+<!--批量上报变更令-->
+<div class="modal fade" id="batch-sb" data-backdrop="static" style="">
+    <div class="modal-dialog modal-lg" style="max-width:1100px;" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">批量上报变更令</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <div class="row">
+                    <!-- 左侧变更令 -->
+                    <div class="col-6" >
+                        <div class="modal-height-500" style="overflow-y:auto;">
+                            <table class="table table-hover table-bordered">
+                                <thead>
+                                <tr>
+                                    <th width="15%" class="text-center"><div class="align-middle"><input id="select-all-uncheck" type="checkbox"></div></th>
+                                    <th width="40%">变更令编号</th>
+                                    <th width="">原审批流程</th>
+                                </tr>
+                                </thead>
+                                <tbody id="uncheck_list">
+                                </tbody>
+                            </table>
+                        </div>
+                    </div>
+                    <!-- 右侧新审批流程 -->
+                    <div class="col-6">
+                        <div class=" ml-auto">
+                            <div class="dropdown text-right" id="show-audit-select">
+                            </div>
+                            <div class="card mt-1">
+                                <div class="card-header">
+                                    审批流程
+                                </div>
+                                <div class="modal-height-500" style="overflow-y:auto;">
+                                    <ul class="list-group list-group-flush" id="auditList">
+                                    </ul>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <div class="alert alert-warning mt-2 mb-0">批量操作会覆盖原审批流程,请合理选择。</div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>
+                <button class="btn btn-sm btn-primary" id="batch_uncheck_btn">确定</button>
+            </div>
+        </div>
+    </div>
+</div>
+<!--批量上报变更令进度条modal-->
+<div class="modal fade" id="batch-sb-progress" data-backdrop="static" style="">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">批量上报变更令</h5>
+            </div>
+            <div class="modal-body">
+                <div class="progress">
+                    <div class="progress-tz-bar progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 100%" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
+                </div>
+                <div class="mt-1 progress-tz-text">台账获取并处理中...</div>
+                <div class="change-progress">
+                </div>
+            </div>
+            <div class="modal-footer" style="display: none">
+                <button class="btn btn-sm btn-primary" onclick="window.location.reload();">刷新页面</button>
+            </div>
+        </div>
+    </div>
+</div>
 <% } %>
+<!--批量审批变更令-->
+<div class="modal fade" id="batch-sp" data-backdrop="static" style="">
+    <div class="modal-dialog modal-lg" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">批量审批变更令</h5>
+                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                    <span aria-hidden="true">&times;</span>
+                </button>
+            </div>
+            <div class="modal-body">
+                <div class="modal-height-500" style="overflow-y:auto;">
+                    <table class="table table-hover table-bordered">
+                        <thead>
+                        <tr>
+                            <th width="5%"><div class="align-middle text-center"><input type="checkbox" id="select-all-checking"></div></th>
+                            <th width="25%">变更令编号</th>
+                            <th width="">变更令名称</th>
+                            <th width="25%">批量编号</th>
+                        </tr>
+                        </thead>
+                        <tbody id="checking_list">
+                        </tbody>
+                    </table>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>
+                <button type="button" class="btn btn-sm btn-primary" id="batch_checking_btn">确定</button>
+            </div>
+        </div>
+    </div>
+</div>
+<!--批量审批变更令进度条modal-->
+<div class="modal fade" id="batch-sp-progress" data-backdrop="static" style="">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">批量审批变更令</h5>
+            </div>
+            <div class="modal-body">
+                <div class="progress">
+                    <div class="progress-tz-bar progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 100%" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
+                </div>
+                <div class="mt-1 progress-tz-text">台账获取并处理中...</div>
+                <div class="change-progress">
+                </div>
+            </div>
+            <div class="modal-footer" style="display: none">
+                <button class="btn btn-sm btn-primary" onclick="window.location.reload();">刷新页面</button>
+            </div>
+        </div>
+    </div>
+</div>
 <script>
     const ruleType = <%- ruleType %>;
     const ruleConst = JSON.parse('<%- JSON.stringify(ruleConst) %>');
@@ -197,4 +326,830 @@
     });
 </script>
 <script src="/public/js/moment/moment.min.js"></script>
+<script src="/public/js/decimal.min.js"></script>
+<script src="/public/js/zh_calc.js"></script>
+<script src="/public/js/path_tree.js"></script>
+<script src="/public/js/gcl_gather.js"></script>
+<script>
+    const shenpiConst = JSON.parse(unescape('<%- escape(JSON.stringify(shenpiConst)) %>'));
+    $(function () {
+        const intervalIds = {};
+        <% if (tender.user_id === ctx.session.sessionUser.accountId) { %>
+        let this_cid = null;
+        let shenpi_status = shenpiConst.sp_status.sqspr;
+        let accountList, accountGroup;
+        let uncheckList = [];
+        // 批量上报变更令部分
+        $('#batch-sb').on('show.bs.modal', function () {
+            postData(`/tender/${tenderId}/change/batch/fun`, { type: 'get_report_list' }, function (res) {
+                let html = '';
+                $('#select-all-uncheck').prop('checked', false);
+                shenpi_status = res.shenpi_status;
+                uncheckList = res.uncheckList;
+                for (const l of res.uncheckList) {
+                    html += '<tr>' +
+                        `<td class="text-center"><input type="checkbox" value="${l.cid}"></td>` +
+                        `<td class=""><a href="/tender/${tenderId}/change/${l.cid}/information" target="_blank">${l.code}</a></td>` +
+                        '<td>' + setAuditList(l.auditList) +'</td>' +
+                        '</tr>';
+                }
+                $('#uncheck_list').html(html);
+                if (res.uncheckList.length > 0) {
+                    $('#uncheck_list tr').eq(0).addClass('table-warning');
+                    this_cid = res.uncheckList[0].cid;
+                    makeSpList(res.uncheckList[0].auditList);
+                } else {
+                    $('#uncheck_list tr').removeClass('table-warning');
+                    this_cid = null;
+                    makeSpList([]);
+                }
+                let showAuditSelectHtml = '';
+                if (res.spGroupList && res.spGroupList.length > 0 && shenpi_status === shenpiConst.sp_status.gdspl) {
+                    let optionHtml = '';
+                    for (const g of res.spGroupList) { %>
+                        optionHtml += `<option value="${g.id}" ${res.uncheckList.length > 0 && g.id === res.uncheckList[0].sp_group ? 'selected' : ''}>${g.name}</option>`;
+                    }
+                    showAuditSelectHtml += '<div class="row">' +
+                        '<div class="col-7"></div>' +
+                    '<div class="col-5">' +
+                        '<select class="form-control form-control-sm change-sp-group">' + optionHtml + '</select>' +
+                    '</div></div>';
+                } else {
+                    accountList = res.accountList;
+                    accountGroup = res.accountGroup;
+                    showAuditSelectHtml += getSelectAuditHtml('report');
+                }
+                $('#show-audit-select').html(showAuditSelectHtml);
+            })
+        });
+
+        function setAuditList(auditList) {
+            let html = [];
+            // 去除原报
+            if (auditList.length > 1) {
+                for (const [i,a] of auditList.entries()) {
+                    if (i === 0) continue;
+                    const oneAuditNames = _.map(a, 'name');
+                    let names = oneAuditNames.join('、');
+                    if (oneAuditNames.length > 1) {
+                        names = (a[0].audit_type === auditType.key.and ? '(会)' : (a[0].audit_type === auditType.key.or ? '(或)' : '')) + names;
+                    }
+                    html.push(names);
+                }
+            }
+            return html.join('-');
+        }
+
+        function getSelectAuditHtml(code) {
+            let divhtml = '';
+            accountGroup.forEach((group, idx) => {
+                let didivhtml = '';
+                if(group) {
+                    group.groupList.forEach(item => {
+                        didivhtml += '<dd class="border-bottom p-2 mb-0 " data-id="' + item.id + '" >\n' +
+                            '<p class="mb-0 d-flex"><span class="text-primary">' + item.name + '</span><span\n' +
+                            '                                                                                class="ml-auto">' + item.mobile + '</span></p>\n' +
+                            '                                                                    <span class="text-muted">' + item.role + '</span>\n' +
+                            '                                                                    </dd>\n';
+                    });
+                    divhtml += '<dt><a href="javascript: void(0);" class="acc-btn" data-groupid="' + idx + '" data-type="hide"><i class="fa fa-plus-square"></i></a> ' + group.groupName + '</dt>\n' +
+                        '                                                                <div class="dd-content" data-toggleid="' + idx + '">\n' + didivhtml +
+                        '                                                                </div>\n';
+                }
+            });
+            const html =
+                '                                                    <button class="btn btn-outline-primary btn-sm dropdown-toggle" type="button" id="' + code + '_dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">\n' +
+                '                                                        添加审批流程\n' +
+                '                                                    </button>\n' +
+                '                                                    <div class="dropdown-menu dropdown-menu-right" id="' + code + '_dropdownMenu" aria-labelledby="' + code + '_dropdownMenuButton" style="width:220px">\n' +
+                '                                                        <div class="mb-2 p-2"><input class="form-control form-control-sm gr-search"\n' +
+                '                                                                                     placeholder="姓名/手机 检索" autocomplete="off" data-code="' + code + '"></div>\n' +
+                '                                                        <dl class="list-unstyled book-list">\n' + divhtml +
+                '                                                        </dl>\n' +
+                '                                                    </div>\n';
+            return html;
+        }
+
+        // uncheckList tr  切换
+        $('#uncheck_list').on('click', 'tr', function () {
+            $('#uncheck_list tr').removeClass('table-warning');
+            $(this).addClass('table-warning');
+            this_cid = $(this).find('a').attr('href').split('/')[4];
+            makeSpList(uncheckList.find(l => l.cid === this_cid).auditList);
+        });
+
+        $('#uncheck_list').on('click', 'input[type="checkbox"]', function (e) {
+            e.stopPropagation();
+        });
+
+        // uncheckList tr全选
+        $('#select-all-uncheck').click(function () {
+            $('#uncheck_list tr').find('input[type="checkbox"]').prop('checked', $(this).prop('checked'));
+        });
+
+        let timer = null;
+        let oldSearchVal = null;
+        $('body').on('input propertychange', 'div[id$="_dropdownMenu"] .gr-search', function(e) {
+            oldSearchVal = e.target.value;
+            timer && clearTimeout(timer);
+            timer = setTimeout(() => {
+                const newVal = $(this).val();
+                const code = $(this).attr('data-code');
+                let html = '';
+                if (newVal && newVal === oldSearchVal) {
+                    accountList.filter(item => item && (item.name.indexOf(newVal) !== -1 || (item.mobile && item.mobile.indexOf(newVal) !== -1))).forEach(item => {
+                        html += `<dd class="border-bottom p-2 mb-0 " data-id="${item.id}" >
+                        <p class="mb-0 d-flex"><span class="text-primary">${item.name}</span><span
+                                class="ml-auto">${item.mobile || ''}</span></p>
+                        <span class="text-muted">${item.role || ''}</span>
+                    </dd>`;
+                    });
+                    $('#' + code + '_dropdownMenu .book-list').empty();
+                    $('#' + code + '_dropdownMenu .book-list').append(html);
+                } else {
+                    if (!$('#' + code + '_dropdownMenu .acc-btn').length) {
+                        accountGroup.forEach((group, idx) => {
+                            if (!group) return;
+                            html += `<dt><a href="javascript: void(0);" class="acc-btn" data-groupid="${idx}" data-type="hide"><i class="fa fa-plus-square"></i>
+                        </a> ${group.groupName}</dt>
+                        <div class="dd-content" data-toggleid="${idx}">`;
+                            group.groupList.forEach(item => {
+                                // if (item.id !== changesUid) {
+                                html += `<dd class="border-bottom p-2 mb-0 " data-id="${item.id}" >
+                                    <p class="mb-0 d-flex"><span class="text-primary">${item.name}</span><span
+                                            class="ml-auto">${item.mobile || ''}</span></p>
+                                    <span class="text-muted">${item.role || ''}</span>
+                                </dd>`;
+                                // }
+                            });
+                            html += '</div>';
+                        });
+                        $('#' + code + '_dropdownMenu .book-list').empty();
+                        $('#' + code + '_dropdownMenu .book-list').append(html);
+                    }
+                }
+            }, 400);
+        });
+        // 添加审批流程按钮逻辑
+        $('body').on('click', 'div[id$="_dropdownMenu"] .book-list dt', function () {
+            const idx = $(this).find('.acc-btn').attr('data-groupid');
+            const type = $(this).find('.acc-btn').attr('data-type');
+            if (type === 'hide') {
+                $(this).parent().find(`div[data-toggleid="${idx}"]`).show(() => {
+                    $(this).children().find('i').removeClass('fa-plus-square').addClass('fa-minus-square-o');
+                    $(this).find('.acc-btn').attr('data-type', 'show');
+
+                })
+            } else {
+                $(this).parent().find(`div[data-toggleid="${idx}"]`).hide(() => {
+                    $(this).children().find('i').removeClass('fa-minus-square-o').addClass('fa-plus-square');
+                    $(this).find('.acc-btn').attr('data-type', 'hide');
+                })
+            }
+            return false;
+        });
+
+        // 添加到审批流程中
+        $('body').on('click', 'div[id$="_dropdownMenu"] dl dd', function () {
+            const id = parseInt($(this).data('id'));
+            if (!this_cid) {
+                toastr.error('请选择变更令');
+                return false;
+            }
+            if (id !== 0) {
+                postData('/tender/' + tenderId + '/change/' + this_cid + '/information/audit/add', { auditorId: id }, (datas) => {
+                    makeSpList(datas);
+                    const index = uncheckList.findIndex(item => item.cid === this_cid);
+                    if (index !== -1) {
+                        uncheckList[index].auditList = datas;
+                        $('#uncheck_list tr').eq(index).children('td').eq(2).html(setAuditList(datas));
+                    }
+                });
+            }
+        });
+
+        // 移除审批流程的审批人
+        $('body').on('click', '#auditList li a', function () {
+            const uid = $(this).parents('li').attr('data-auditid');
+            const li = $(this).parents('li');
+            const data = {
+                auditorId: uid,
+            };
+            if (!this_cid) {
+                toastr.error('请选择变更令');
+                return false;
+            }
+            postData('/tender/' + tenderId + '/change/' + this_cid + '/information/audit/delete', data, (datas) => {
+                li.remove();
+                let liIndex = 1;
+                $('#auditList li').each(function () {
+                    $(this).children('.col-auto').eq(0).text(liIndex);
+                    liIndex++;
+                });
+                const index = uncheckList.findIndex(item => item.cid === this_cid);
+                if (index !== -1) {
+                    uncheckList[index].auditList = datas;
+                    $('#uncheck_list tr').eq(index).children('td').eq(2).html(setAuditList(datas));
+                }
+            });
+        });
+        // 切换审批组
+        $('body').on('change', '.change-sp-group', function () {
+            const data = {
+                type: 'change_sp_group',
+                sp_group: parseInt($(this).val()),
+            }
+            if (!this_cid) {
+                toastr.error('请选择变更令');
+                return false;
+            }
+            if (!data.sp_group) {
+                toastr.error('请选择固定审批组');
+                return false;
+            }
+            console.log(data);
+            postData('/tender/' + tenderId + '/change/' + this_cid + '/information/audit/spgroup', data, (datas) => {
+                makeSpList(datas);
+                const index = uncheckList.findIndex(item => item.cid === this_cid);
+                if (index !== -1) {
+                    uncheckList[index].auditList = datas;
+                    $('#uncheck_list tr').eq(index).children('td').eq(2).html(setAuditList(datas));
+                }
+            });
+        });
+
+        function makeSpList(datas) {
+            const html = [];
+            // 如果是重新上报,添加到重新上报列表中
+            const auditorshtml = [];
+            if (datas.length > 0) {
+                for (const [index,data] of datas.entries()) {
+                    if (index !== 0) {
+                        html.push('<li class="list-group-item d-flex" data-auditid="'+ data[0].uid +'">');
+                        html.push(`<div class="col-auto">${index}</div>`);
+                        html.push('<div class="col">');
+                        for (const auditor of data) {
+                            html.push(`<div class="d-inline-block mx-1" auditorId="${auditor.uid}"><i class="fa fa-user text-muted"></i> ${auditor.name} <small class="text-muted">${auditor.role}</small></div>`);
+                        }
+                        html.push('</div>');
+                        html.push('<div class="col-auto">');
+                        // todo 添加会签或签时
+                        if (data[0].audit_type !== auditType.key.common) {
+                            html.push(`<span class="badge badge-pill badge-${auditType.info[data[0].audit_type].class} badge-bg-small"><small>${auditType.info[data[0].audit_type].long}</small></span>`);
+                        }
+                        if (shenpi_status === shenpiConst.sp_status.sqspr || (shenpi_status === shenpiConst.sp_status.gdzs && index+1 !== datas.length)) {
+                            html.push('<a href="javascript: void(0)" class="text-danger pull-right">移除</a>');
+                        }
+                        html.push('</div>');
+                        html.push('</li>');
+                    }
+                }
+            }
+            $('#auditList').html(html.join(''));
+        }
+
+        $('#batch_uncheck_btn').click(function () {
+            // 至少勾选一个
+            if ($('#uncheck_list input:checked').length === 0) {
+                toastr.error('请至少勾选一个变更令');
+                return false;
+            }
+            const cids = [];
+            $('#uncheck_list input:checked').each(function () {
+                cids.push($(this).val());
+            });
+            $('#batch-sb').modal('hide');
+            $('#batch-sb-progress').modal('show');
+            $('#batch-sb-progress .progress-tz-bar').css('width', '0%');
+            $('#batch-sb-progress .modal-footer').hide();
+            setProgress($('#batch-sb-progress .progress-tz-bar'), 30, 'tz1');
+            $('#batch-sb-progress .progress-tz-text').text('台账数据获取中...').removeClass('text-success');
+
+            let changeListData;
+            let gclGatherData;
+            postData('/tender/' + tenderId + '/change/defaultBills', { form: 'batch' }, async function (result) {
+                gclGatherModel.loadLedgerData(result.bills);
+                gclGatherModel.loadPosData(result.pos);
+
+                gclGatherData = gclGatherModel.gatherGclData();
+                gclGatherData = _.filter(gclGatherData, function (item) {
+                    return item.leafXmjs && item.leafXmjs.length !== 0;
+                });
+                for (const ggd in gclGatherData) {
+                    if (gclGatherData[ggd].leafXmjs && gclGatherData[ggd].leafXmjs.length === 0) {
+                        gclGatherData.splice(ggd, 1);
+                    }
+                    gclGatherData[ggd].code = gclGatherData[ggd].b_code;
+                    let hadcid = 0;
+                    for (const xmj of gclGatherData[ggd].leafXmjs) {
+                        const changeLedger = _.find(result.changeLedgerList, { id: xmj.gcl_id });
+                        const changePos = _.find(result.changePosList, { id: xmj.mx_id, lid: xmj.gcl_id });
+                        if (changeLedger || changePos) {
+                            xmj.cid = 1;
+                            xmj.ccid = changeLedger ? changeLedger.ccid : changePos.ccid;
+                            hadcid = 1;
+                        }
+                    }
+
+                    if (hadcid !== 0) gclGatherData[ggd].cid = 1;
+                }
+                // console.log(gclGatherData);
+                // 数组去重
+                const dealBillList = result.dealBills;
+                for (const db of gclGatherData) {
+                    const exist_index = dealBillList.findIndex(function (item) {
+                        return item.code === db.code && item.name === db.name && item.unit === db.unit && item.unit_price === db.unit_price;
+                    });
+                    if (exist_index !== -1) {
+                        dealBillList.splice(exist_index, 1);
+                    }
+                }
+                changeListData = gclGatherData.concat(dealBillList).sort(sortByCode);
+                console.log(changeListData);
+                stopProgress($('#batch-sb-progress .progress-tz-bar'), 'tz1');
+                $('#batch-sb-progress .progress-tz-text').text('台账数据加载完成').addClass('text-success');
+                $('#batch-sb-progress .change-progress').html('');
+                for (const c of cids) {
+                    const cInfo = uncheckList.find(item => item.cid === c);
+                    if (cInfo) {
+                        $('#batch-sb-progress .change-progress').append(`<div id="change-${cInfo.cid}-progress"><div class="mt-3 progress">` +
+                            '<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>' +
+                    '</div>' +
+                    `<div class="mt-1">变更令 <b>${cInfo.code}</b> <span class="progress-change-text">上报处理中...</span></div></div>`);
+                        await checkAndChange(cInfo, changeListData, result.changeLedgerList);
+                    }
+                }
+                $('#batch-sb-progress .modal-footer').show();
+            });
+        });
+        <% } %>
+        let checkingList = [];
+        $('#batch-sp').on('show.bs.modal', function () {
+            postData(`/tender/${tenderId}/change/batch/fun`, { type: 'get_shenpi_list' }, function (res) {
+                let html = '';
+                $('#select-all-checking').prop('checked', false);
+                checkingList = res.checkingList;
+                for (const l of res.checkingList) {
+                    const finalHtml = l.is_finalAudit ? `<input type="text" class="form-control form-control-sm final_pcode_input" data-cid="${l.cid}" value="${l.p_code}" />` : '';
+                    html += '<tr>' +
+                        `<td class="text-center"><input type="checkbox" value="${l.cid}"></td>` +
+                        `<td class=""><a href="/tender/${tenderId}/change/${l.cid}/information" target="_blank">${l.code}</a></td>` +
+                        `<td>${l.name}</td>` +
+                        `<td>${finalHtml}</td>` +
+                        '</tr>';
+                }
+                $('#checking_list').html(html);
+            });
+        });
+
+        $('body').on('change', '.final_pcode_input', function () {
+            const cid = $(this).data('cid');
+            const cInfo = checkingList.find(item => item.cid === cid);
+            cInfo.p_code = $(this).val();
+        });
+
+        $('#checking_list').on('click', 'input[type="checkbox"]', function (e) {
+            e.stopPropagation();
+        });
+
+        // uncheckList tr全选
+        $('#select-all-checking').click(function () {
+            $('#checking_list tr').find('input[type="checkbox"]').prop('checked', $(this).prop('checked'));
+        });
+
+        $('#batch_checking_btn').click(function () {
+            // 至少勾选一个
+            if ($('#checking_list input:checked').length === 0) {
+                toastr.error('请至少勾选一个变更令');
+                return false;
+            }
+            const cids = [];
+            $('#checking_list input:checked').each(function () {
+                cids.push($(this).val());
+            });
+            $('#batch-sp').modal('hide');
+            $('#batch-sp-progress').modal('show');
+            $('#batch-sp-progress .progress-tz-bar').css('width', '0%');
+            $('#batch-sp-progress .modal-footer').hide();
+            setProgress($('#batch-sp-progress .progress-tz-bar'), 30, 'tz2');
+            $('#batch-sp-progress .progress-tz-text').text('台账数据获取中...').removeClass('text-success');
+
+            let changeListData;
+            let gclGatherData;
+            postData('/tender/' + tenderId + '/change/defaultBills', { from: 'batch' }, async function (result) {
+                gclGatherModel.loadLedgerData(result.bills);
+                gclGatherModel.loadPosData(result.pos);
+
+                gclGatherData = gclGatherModel.gatherGclData();
+                gclGatherData = _.filter(gclGatherData, function (item) {
+                    return item.leafXmjs && item.leafXmjs.length !== 0;
+                });
+                for (const ggd in gclGatherData) {
+                    if (gclGatherData[ggd].leafXmjs && gclGatherData[ggd].leafXmjs.length === 0) {
+                        gclGatherData.splice(ggd, 1);
+                    }
+                    gclGatherData[ggd].code = gclGatherData[ggd].b_code;
+                    let hadcid = 0;
+                    for (const xmj of gclGatherData[ggd].leafXmjs) {
+                        const changeLedger = _.find(result.changeLedgerList, { id: xmj.gcl_id });
+                        const changePos = _.find(result.changePosList, { id: xmj.mx_id, lid: xmj.gcl_id });
+                        if (changeLedger || changePos) {
+                            xmj.cid = 1;
+                            xmj.ccid = changeLedger ? changeLedger.ccid : changePos.ccid;
+                            hadcid = 1;
+                        }
+                    }
+
+                    if (hadcid !== 0) gclGatherData[ggd].cid = 1;
+                }
+                // console.log(gclGatherData);
+                // 数组去重
+                const dealBillList = result.dealBills;
+                for (const db of gclGatherData) {
+                    const exist_index = dealBillList.findIndex(function (item) {
+                        return item.code === db.code && item.name === db.name && item.unit === db.unit && item.unit_price === db.unit_price;
+                    });
+                    if (exist_index !== -1) {
+                        dealBillList.splice(exist_index, 1);
+                    }
+                }
+                changeListData = gclGatherData.concat(dealBillList).sort(sortByCode);
+                console.log(changeListData);
+                stopProgress($('#batch-sp-progress .progress-tz-bar'), 'tz2');
+                $('#batch-sp-progress .progress-tz-text').text('台账数据加载完成').addClass('text-success');
+                $('#batch-sp-progress .change-progress').html('');
+                for (const c of cids) {
+                    const cInfo = checkingList.find(item => item.cid === c);
+                    if (cInfo) {
+                        $('#batch-sp-progress .change-progress').append(`<div id="change-${cInfo.cid}-progress"><div class="mt-3 progress">` +
+                            '<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 0%" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>' +
+                            '</div>' +
+                            `<div class="mt-1">变更令 <b>${cInfo.code}</b> <span class="progress-change-text">审批处理中...</span></div></div>`);
+                        await checkAndChange(cInfo, changeListData, result.changeLedgerList, 'checking');
+                    }
+                }
+                $('#batch-sp-progress .modal-footer').show();
+            }, function (res) {
+            }, false);
+        });
+
+        let value = 0;
+        // let interval;
+        let stop = false;
+        function setProgress(_this, time = 50, name) {
+            let intervalId = setInterval(function () {
+                if (value < 100) {
+                    value = parseInt(value) + 1;
+                    _this.css("width", value + "%").text(value + "%");
+                } else if (value === 100) {
+                    value = parseInt(value) + 1;
+                    value = 30;
+                }
+            }, time);
+            intervalIds[name] = intervalId;
+        }
+        function resetProgress(_this) {
+            _this.removeClass('bg-success');
+            _this.css("width", "0%").text("0%").attr('aria-valuenow', '0');
+        }
+
+        function failProgress(_this, name) {
+            if (intervalIds[name]) {
+                _this.addClass('bg-danger');
+                _this.css("width", "100%").text("失败");
+                value = 0;
+                stop = true;
+                clearInterval(intervalIds[name]);
+                intervalIds[name] = 0;
+            }
+        }
+
+        function stopProgress(_this, name) {
+            if (intervalIds[name]) {
+                _this.addClass('bg-success');
+                _this.css("width", "100%").text("100%");
+                value = 0;
+                stop = true;
+                clearInterval(intervalIds[name]);
+                intervalIds[name] = 0;
+            }
+        }
+        async function checkAndChange(cInfo, changeListData, changeLedgerList, status = 'uncheck') {
+            setProgress($(`#change-${cInfo.cid}-progress .progress-bar`), 30, `change-${cInfo.cid}`);
+            // 根据已添加的清单显示
+            if (cInfo.changeList.length > 0 && cInfo.changeList[0]) {
+                const removeList = [];
+                const updateList = [];
+                const updateGclIdList = [];
+                for (const [index,clinfo] of cInfo.changeList.entries()) {
+                    if (clinfo.lid != 0) {
+                        let listinfo = changeListData.find(function (item) {
+                            return (item.id !== undefined && item.id == clinfo.lid) || (item.id === undefined && item.leafXmjs !== undefined && item.leafXmjs.length !== 0 && item.leafXmjs[0].gcl_id == clinfo.lid);
+                        });
+                        if (listinfo === undefined || (clinfo.lid && clinfo.gcl_id && clinfo.lid !== clinfo.gcl_id)) {
+                            // 有可能这部分台账发生变化,此时要更新清单lid信息,防止数据丢失
+                            const newlistinfo = changeListData.find(function (item) {
+                                return (item.id !== undefined && item.id == clinfo.gcl_id) || (item.id === undefined && item.leafXmjs !== undefined && item.leafXmjs.length !== 0 && _.find(item.leafXmjs, {gcl_id: clinfo.gcl_id }));
+                            });
+                            if ((listinfo === undefined && newlistinfo) || (listinfo && newlistinfo && !isObjEqual(listinfo, newlistinfo))) {
+                                listinfo = newlistinfo;
+                                updateList.push({id: clinfo.id, lid: newlistinfo.leafXmjs[0].gcl_id});
+                                // 更新lid
+                                cInfo.changeList[index].lid = newlistinfo.leafXmjs[0].gcl_id;
+                            }
+                        }
+                        if (listinfo === undefined) {
+                            // 针对旧数据获取清单信息
+                            listinfo = changeListData[clinfo.lid - 1];
+                            if (listinfo === undefined) {
+                                removeList.push(clinfo);
+                                break;
+                            }
+                        }
+                        const info = makePushBwmx(clinfo, listinfo, removeList, updateList);
+                        if (info) break;
+                        if (_.findIndex(changeLedgerList, { id: clinfo.gcl_id }) !== -1) {
+                            // 可能因为升降级关系:细目,分部分项等会发生变化,更新清单
+                            const updateInfo = {};
+                            if (info.code !== clinfo.xmj_code) {
+                                updateInfo.xmj_code = info.code;
+                                // changeList[index].xmj_code = info.code;
+                            }
+                            if (info.jldy !== clinfo.xmj_jldy) {
+                                updateInfo.xmj_jldy = info.jldy;
+                                // changeList[index].xmj_jldy = info.jldy;
+                            }
+                            if (info.dwgc !== clinfo.xmj_dwgc) {
+                                updateInfo.xmj_dwgc = info.dwgc;
+                                // changeList[index].xmj_dwgc = info.dwgc;
+                            }
+                            if (info.fbgc !== clinfo.xmj_fbgc) {
+                                updateInfo.xmj_fbgc = info.fbgc;
+                                // changeList[index].xmj_fbgc = info.fbgc;
+                            }
+                            if (info.fxgc !== clinfo.xmj_fxgc) {
+                                updateInfo.xmj_fxgc = info.fxgc;
+                                // changeList[index].xmj_fxgc = info.fxgc;
+                            }
+                            if (!_.isEmpty(updateInfo) && _.indexOf(updateGclIdList, clinfo.gcl_id) === -1) {
+                                updateGclIdList.push(clinfo.gcl_id);
+                                // updateInfo.gcl_id = info.id;
+                                updateList.push({ row: updateInfo, where: { tid: tenderId, gcl_id: clinfo.gcl_id } });
+                                break;
+                            }
+                        }
+                    }
+                }
+                await sleep(2000);
+                if (updateList.length > 0 || removeList.length > 0) {
+                    failProgress($('#change-' + cInfo.cid + '-progress .progress-bar'), `change-${cInfo.cid}`);
+                    $('#change-' + cInfo.cid + '-progress .mt-1').addClass('text-danger');
+                    $('#change-' + cInfo.cid + '-progress .progress-change-text').text('清单数据发生变化,需要进入到详情页处理');
+                    return;
+                }
+                // 上报或审批变更令
+                let ss = true;
+                if (status === 'uncheck') {
+                    postDataWithAsync('/tender/' + tenderId + '/change/' + cInfo.cid + '/information/audit/start', {}, function () {
+                    }, function (res) {
+                        ss = false;
+                        failProgress($('#change-' + cInfo.cid + '-progress .progress-bar'), `change-${cInfo.cid}`);
+                        $('#change-' + cInfo.cid + '-progress .mt-1').addClass('text-danger');
+                        $('#change-' + cInfo.cid + '-progress .progress-change-text').text(res);
+                        return;
+                    }, false);
+                } else {
+                    const pData = {
+                        change_id: cInfo.cid,
+                        w_code: cInfo.code,
+                        status: auditConst.status.checked,
+                        sdesc: '同意',
+                    }
+                    if (cInfo.is_finalAudit) {
+                        if (cInfo.p_code) {
+                            pData.p_code = cInfo.p_code;
+                            const postData2 = {
+                                p_code: cInfo.p_code,
+                            };
+                            let returnflag = true;
+                            postDataWithAsync('/tender/' + tenderId + '/change/' + cInfo.cid + '/check/codeRepeat',postData2, function (result) {
+                            }, function (data) {
+                                returnflag = false;
+                            });
+                            if (!returnflag) {
+                                failProgress($('#change-' + cInfo.cid + '-progress .progress-bar'), `change-${cInfo.cid}`);
+                                $('#change-' + cInfo.cid + '-progress .mt-1').addClass('text-danger');
+                                $('#change-' + cInfo.cid + '-progress .progress-change-text').text('批复编号不能与其它变更令重复!');
+                                return;
+                            }
+                        } else {
+                            failProgress($('#change-' + cInfo.cid + '-progress .progress-bar'), `change-${cInfo.cid}`);
+                            $('#change-' + cInfo.cid + '-progress .mt-1').addClass('text-danger');
+                            $('#change-' + cInfo.cid + '-progress .progress-change-text').text('变更令号(批复编号)不能为空!');
+                            return;
+                        }
+                    }
+                    postDataWithAsync('/tender/' + tenderId + '/change/approval', pData, function (result) {
+                    }, function (res) {
+                        ss = false;
+                        failProgress($('#change-' + cInfo.cid + '-progress .progress-bar'), `change-${cInfo.cid}`);
+                        $('#change-' + cInfo.cid + '-progress .mt-1').addClass('text-danger');
+                        $('#change-' + cInfo.cid + '-progress .progress-change-text').text(res);
+                        return;
+                    }, false);
+                }
+                if (ss) {
+                    stopProgress($('#change-' + cInfo.cid + '-progress .progress-bar'), `change-${cInfo.cid}`);
+                    $('#change-' + cInfo.cid + '-progress .mt-1').addClass('text-success');
+                    $('#change-' + cInfo.cid + '-progress .progress-change-text').text((status === 'uncheck' ? '上报' : '审批') + '成功');
+                }
+            }
+        }
+
+        const postDataWithAsync = function (url, data, successCallback, errorCallBack, showWaiting = true) {
+            if (showWaiting) showWaitingView();
+            $.ajax({
+                type:"POST",
+                url: url,
+                data: {'data': JSON.stringify(data)},
+                dataType: 'json',
+                cache: false,
+                async: false,
+                timeout: 60000,
+                beforeSend: function(xhr) {
+                    let csrfToken = Cookies.get('csrfToken_j');
+                    xhr.setRequestHeader('x-csrf-token', csrfToken);
+                },
+                success: function(result){
+                    if (result.err === 0) {
+                        if (successCallback) {
+                            successCallback(result.data);
+                        }
+                    } else {
+                        toastr.error(result.msg);
+                        if (errorCallBack) {
+                            errorCallBack(result.msg);
+                        }
+                    }
+                    if (showWaiting) closeWaitingView();
+                },
+                error: function(jqXHR, textStatus, errorThrown){
+                    toastr.error('error: ' + textStatus + " " + errorThrown);
+                    if (errorCallBack) {
+                        errorCallBack();
+                    }
+                    if (showWaiting) closeWaitingView();
+                }
+            });
+        };
+
+        function sleep(millisecond) {
+            return new Promise(resolve => {
+                setTimeout(() => {
+                    resolve()
+                }, millisecond)
+            })
+        }
+
+        function isObjEqual(o1,o2){
+            var props1 = Object.getOwnPropertyNames(o1);
+            var props2 = Object.getOwnPropertyNames(o2);
+            if (props1.length != props2.length) {
+                return false;
+            }
+            for (var i = 0,max = props1.length; i < max; i++) {
+                var propName = props1[i];
+                if (o1[propName] !== o2[propName]) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        function makePushBwmx(clinfo, listinfo, removeList, updateList) {
+            let needUpdate = false;
+            const checkKey = ['name', 'code', 'unit', 'unit_price'];
+            const checkLeafKey = ['oamount', 'bwmx', 'code', 'dwgc', 'fbgc', 'fxgc', 'jldy'];
+            if (listinfo.leafXmjs !== undefined) {
+                const leafInfo = listinfo.leafXmjs.find(function (item) {
+                    // const flag = (item.bwmx === undefined || item.bwmx === clinfo.bwmx || item.jldy === clinfo.bwmx) && item.gcl_id === clinfo.gcl_id && (!clinfo.mx_id || (item.mx_id && clinfo.mx_id && item.mx_id === clinfo.mx_id)) && (item.quantity !== null ? item.quantity === parseFloat(clinfo.oamount) : 0 === parseFloat(clinfo.oamount));
+                    const flag = item.gcl_id === clinfo.gcl_id && (!clinfo.mx_id || (item.mx_id && clinfo.mx_id && item.mx_id === clinfo.mx_id));
+                    if (flag && item.code === clinfo.xmj_code) {
+                        return flag && item.code === clinfo.xmj_code;
+                    }
+                    return flag;
+                });
+                if (leafInfo) {
+                    const oneUpdate = { id: clinfo.id };
+                    // 判断要不要更新名称,单位,原数量,单价
+                    checkKey.forEach(function (key) {
+                        if (listinfo[key] !== clinfo[key]) {
+                            oneUpdate[key] = listinfo[key];
+                            // clinfo[key] = listinfo[key];
+                            if (key === 'unit') {
+                                const changeKey = ['oamount', 'oamount2', 'camount'];
+                                changeKey.forEach(function (key) {
+                                    const value = ZhCalc.round(clinfo[key], findDecimal(listinfo[key]));
+                                    if (value !== clinfo[key]) {
+                                        oneUpdate[key] = value;
+                                        // clinfo[key] = value;
+                                    }
+                                });
+                            }
+                            needUpdate = true;
+                        }
+                    });
+                    checkLeafKey.forEach(function (key) {
+                        // 只有数量是对比leafInfo,其它对比listinfo,且有些值需要重新计算
+                        if (key === 'oamount') {
+                            if (leafInfo.quantity !== clinfo[key]) {
+                                oneUpdate[key] = leafInfo.quantity;
+                                // clinfo[key] = leafInfo.quantity;
+                                needUpdate = true;
+                            }
+                        } else if (key === 'bwmx') {
+                            if (leafInfo[key] !== undefined && leafInfo[key] !== clinfo[key]) {
+                                oneUpdate[key] = leafInfo[key];
+                                // clinfo[key] = leafInfo[key];
+                                needUpdate = true;
+                            } else if (leafInfo[key] === undefined && leafInfo.jldy !== clinfo[key]) {
+                                oneUpdate[key] = leafInfo.jldy;
+                                // clinfo[key] = leafInfo.jldy;
+                                needUpdate = true;
+                            }
+                        } else {
+                            if (leafInfo[key] !== clinfo['xmj_' + key]) {
+                                oneUpdate['xmj_' + key] = leafInfo[key];
+                                // clinfo['xmj_' + key] = leafInfo[key];
+                                needUpdate = true;
+                            }
+                        }
+                    });
+                    if (needUpdate) {
+                        updateList.push(oneUpdate);
+                    }
+                } else {
+                    removeList.push(clinfo);
+                    needUpdate = true;
+                }
+            }
+            return needUpdate;
+        }
+
+        // 编号排序,多重判断
+        function sortByCode(a, b) {
+            let code1 = a.code.split('-');
+            let code2 = b.code.split('-');
+            let code1length = code1.length;
+            let code2length = code2.length;
+            for (let i = 0; i < code1length; i ++) {
+                if (i+1 <= code2length) {
+                    if (code1[i] != code2[i]) {
+                        if (/^\d+$/.test(code1[i]) && /^\d+$/.test(code2[i])) {
+                            return parseInt(code1[i]) - parseInt(code2[i]);
+                        } else if (!/^\d+$/.test(code1[i]) && /^\d+$/.test(code2[i])) {
+                            return 1;
+                        } else if (/^\d+$/.test(code1[i]) && !/^\d+$/.test(code2[i])) {
+                            return -1;
+                        } else {
+                            const str1length = code1[i].length;
+                            const str2length = code2[i].length;
+                            for (let j = 0; j < str1length; j++) {
+                                if (j+1 <= str2length) {
+                                    if (code1[i].charAt(j) != code2[i].charAt(j)) {
+                                        return code1[i].charAt(j).charCodeAt() - code2[i].charAt(j).charCodeAt();
+                                    }  else if (j+1 == str1length && code1[i].charAt(j) == code2[i].charAt(j)) {
+                                        if (str1length == str2length) {
+                                            return 0;
+                                        } else {
+                                            return str1length - str2length;
+                                        }
+                                    }
+                                } else {
+                                    if (j+1 >= str1length) {
+                                        return 1;
+                                    } else {
+                                        return -1;
+                                    }
+                                }
+                            }
+                        }
+                    } else if (i+1 == code1length && code1[i] == code2[i]) {
+                        if (code1length == code2length) {
+                            return 0;
+                        } else {
+                            return code1length - code2length;
+                        }
+                    }
+                } else {
+                    if (i+1 >= code1length) {
+                        return 1;
+                    } else {
+                        return -1;
+                    }
+                }
+            }
+        }
+    });
+</script>
 

+ 25 - 2
app/view/dashboard/index.ejs

@@ -63,7 +63,7 @@
                                     <% if (ctx.session.sessionProject.page_show.openChangePlan && auditChangePlan.length !== 0) { %>
                                         <option value="9">变更方案(<%- auditChangePlan.length %>)</option>
                                     <% } %>
-                                    <% if (auditMaterial.length !== 0) { %>
+                                    <% if (ctx.session.sessionProject.page_show.openMaterial && auditMaterial.length !== 0) { %>
                                     <option value="1">材料调差(<%- auditMaterial.length %>)</option>
                                     <% } %>
                                     <% if (ctx.session.sessionProject.page_show.openPayment && auditPayments.length !== 0) { %>
@@ -143,6 +143,25 @@
                                                 </tr>
                                             <% } %>
                                         <% } %>
+                                        <% for (const audit of auditStageAss) { %>
+                                            <% if (audit.sstatus !== acStage.status.checkNo) { %>
+                                                <tr data-type="2">
+                                                    <td><span class="bg-new-stage text-new-stage badge text-width">计量审批</span></td>
+                                                    <td><a href="/tender/<%- audit.tid %>"><%- audit.tender_name %></a> <a href="/tender/<%- audit.tid %>/measure/stage/<%- audit.sorder %>">第<%- audit.sorder %>期</a></td>
+                                                    <td>第<%- audit.sorder %>期</td>
+                                                    <td><%- ctx.moment(audit.begin_time).format('YYYY/MM/DD HH:mm') %></td>
+                                                    <td><a href="/tender/<%- audit.tid %>/measure/stage/<%- audit.sorder %>" class="btn btn-outline-primary btn-sm btn-table" role="button">协同审批</a></td>
+                                                </tr>
+                                            <% } else { %>
+                                                <tr data-type="2">
+                                                    <td><span class="bg-new-stage text-new-stage badge text-width">计量审批</span></td>
+                                                    <td><a href="/tender/<%- audit.tid %>"><%- audit.tender_name %></a> <a href="/tender/<%- audit.tid %>/measure/stage/<%- audit.sorder %>">第<%- audit.sorder %>期</a></td>
+                                                    <td>第<%- audit.sorder %>期</td>
+                                                    <td><%- ctx.moment(audit.begin_time).format('YYYY/MM/DD HH:mm') %></td>
+                                                    <td><a href="/tender/<%- audit.tid %>/measure/stage/<%- audit.sorder %>" class="btn btn-outline-warning btn-sm btn-table text-warning" role="button">协同上报</a></td>
+                                                </tr>
+                                            <% } %>
+                                        <% } %>
                                         <% for (const change of auditChanges) { %>
                                             <tr data-type="3">
                                                 <td><span class="bg-new-change text-new-change badge text-width">变更审批</span></td>
@@ -358,7 +377,9 @@
                                     <% if (ctx.session.sessionProject.page_show.openChangePlan) { %>
                                         <option value="9">变更方案</option>
                                     <% } %>
+                                    <% if (ctx.session.sessionProject.page_show.openMaterial) { %>
                                     <option value="1">材料调差</option>
+                                    <% } %>
                                 </select>
                             </div>
                         </div>
@@ -395,7 +416,7 @@
                                                     <td class="<%- acStage.statusClass[notice.status]%>"><%- acStage.statusString[notice.status]%></td>
                                                     <td><%- notice.opinion ? notice.opinion : '' %></td>
                                                 </tr>
-                                            <% } else if(notice.type === pushType.material) { %>
+                                            <% } else if(notice.type === pushType.material && ctx.session.sessionProject.page_show.openMaterial) { %>
                                                 <tr data-type="1">
                                                     <td><span class="bg-new-material text-new-material badge text-width">材料调差</span></td>
                                                     <td><a href="/tender/<%- notice.tid %>"><%- notice.name %></a> <a href="/tender/<%- notice.tid %>/measure/material/<%- notice.order %>">第<%- notice.order %>期</a></td>
@@ -606,7 +627,9 @@
             <% if (ctx.session.sessionProject.page_show.openChangePlan) { %>
             'rgba(114, 46, 209,'+ transparentCount +')',
             <% } %>
+            <% if (ctx.session.sessionProject.page_show.openMaterial) { %>
             'rgba(187, 41, 210,'+ transparentCount +')',
+            <% } %>
         ],
         tooltip: {
             trigger: 'item'

+ 78 - 49
app/view/datacollect/index4GY18Y.ejs

@@ -256,8 +256,11 @@
         tooltip: {
             trigger: 'axis',
             axisPointer: {            // 坐标轴指示器,坐标轴触发有效
-                type: 'shadow'        // 默认为直线,可选为:'line' | 'shadow'
+                type: 'shadow',        // 默认为直线,可选为:'line' | 'shadow'
             },
+            position: function (pos, params, dom, rect, size) {
+                return {top: pos[1], left: pos[0]};
+            }
         },
         dataZoom: [
             {
@@ -300,12 +303,18 @@
                     },
                     formatter: function(value) {
                         var res = value;
-                        if(res.length > 10) {
-                            res = res.substring(0, 10) + "..";
+                        if(res.length > 5) {
+                            res = res.substring(0, 4) + "..";
                         }
                         return res;
+                    },
+                    rich: {
+                        ellipsis: {
+                            width: 100, // 控制显示宽度
+                            overflow: 'break',
+                        }
                     }
-                }
+                },
             }
         ],
         yAxis: [
@@ -428,33 +437,36 @@
                     }
                     return res;
                 }
-            }
-        },
-        dataZoom: [
-            {
-                brushSelect:false,
-                start: 0,
-                end: 10,
-                type: 'slider',
-                show: true,
-                handleSize: 0,
-                realtime: true,
-                showDetail: false,
-                // filterMode: 'empty',
-                yAxisIndex: [0,1],
-                width: 10,
-                height: '80%',
-                right: '5%',
-                bottom:'2%'
             },
-        ],
+            margin: 10,
+        },
+        // dataZoom: [
+        //     {
+        //         brushSelect:false,
+        //         start: 0,
+        //         end: 10,
+        //         type: 'slider',
+        //         show: true,
+        //         handleSize: 0,
+        //         realtime: true,
+        //         showDetail: false,
+        //         // filterMode: 'empty',
+        //         yAxisIndex: [0,1],
+        //         width: 10,
+        //         height: '80%',
+        //         right: '5%',
+        //         bottom:'2%'
+        //     },
+        // ],
         series: [
             {
                 name: '情况',
                 type: 'bar',
                 stack: 'total',
                 label: {
-                    show: true
+                    show: true,
+                    // position: 'insideLeft',
+                    align: 'left'
                 },
                 emphasis: {
                     focus: 'series'
@@ -704,10 +716,11 @@
                 showDataShadow: false,
                 // dataZoomIndex: 10,
                 start: 0,
-                end: 8,
+                end: 1,
                 handleSize: 0,
                 height: 10,
                 bottom: '10%',
+                zoomLock: true,
             },
         ],
         legend: {
@@ -734,10 +747,16 @@
                     },
                     formatter: function(value) {
                         var res = value;
-                        if(res.length > 10) {
-                            res = res.substring(0, 10) + "..";
+                        if(res.length > 4) {
+                            res = res.substring(0, 4) + "..";
                         }
                         return res;
+                    },
+                    rich: {
+                        ellipsis: {
+                            width: 100, // 控制显示宽度
+                            overflow: 'break',
+                        }
                     }
                 }
             }
@@ -776,7 +795,8 @@
                 emphasis: {
                     focus: 'series'
                 },
-                data: []
+                data: [],
+                barMaxWidth: 30
             },
             {
                 name: '已支付',
@@ -785,7 +805,8 @@
                 emphasis: {
                     focus: 'series'
                 },
-                data: []
+                data: [],
+                barMaxWidth: 30
             }
         ]
     };
@@ -795,6 +816,11 @@
         dpgl_charts[d] = echarts.init(dpgl_chart[d], 'dark');
         const option = _.cloneDeep(dpglChartOption);
         option.title.text = dpCategory[d].value;
+        if (d == 0) {
+            option.tooltip.position = function (pos, params, dom, rect, size) {
+                return {top: pos[1], left: pos[0]};
+            }
+        }
         dpgl_charts[d].setOption(option);
     }
     let tenders = '';
@@ -947,12 +973,12 @@
             // 工程收入明细
             const gcsrmx_chart_option = gcsrmxChart.getOption();
             gcsrmx_chart_option.dataZoom[0].start = 0;
-            gcsrmx_chart_option.dataZoom[0].end = computedPosition(sr_tenders.length);
+            gcsrmx_chart_option.dataZoom[0].end = computedPosition(sr_tenders.length, 6);
             gcsrmx_chart_option.xAxis[0].data = srmx_chart_option_name;
             gcsrmx_chart_option.series[0].data = srmx_chart_option_data.end_gather_tp;
             gcsrmx_chart_option.series[1].data = srmx_chart_option_data.end_yf_tp;
             gcsrmx_chart_option.series[2].data = srmx_chart_option_data.end_sf_tp;
-            if (sr_tenders.length >= 8) {
+            if (sr_tenders.length >= 6) {
                 gcsrmx_chart_option.dataZoom[0].show = true;
             } else {
                 gcsrmx_chart_option.dataZoom[0].show = false;
@@ -961,14 +987,14 @@
 
             // 工程收入情况
             const gcsrqk_chart_option = gcsrqkChart.getOption();
-            gcsrqk_chart_option.dataZoom[0].start = 0;
-            gcsrqk_chart_option.dataZoom[0].end = computedPosition(sr_tenders.length);
+            // gcsrqk_chart_option.dataZoom[0].start = 0;
+            // gcsrqk_chart_option.dataZoom[0].end = computedPosition(sr_tenders.length);
             gcsrqk_chart_option.series[0].data = [sr_chart_option_data.end_ds_tp, sr_chart_option_data.end_sf_tp, sr_chart_option_data.end_yf_tp, sr_chart_option_data.end_gather_tp, sr_chart_option_data.contract_price];
-            if (sr_tenders.length >= 8) {
-                gcsrqk_chart_option.dataZoom[0].show = true;
-            } else {
-                gcsrqk_chart_option.dataZoom[0].show = false;
-            }
+            // if (sr_tenders.length >= 8) {
+            //     gcsrqk_chart_option.dataZoom[0].show = true;
+            // } else {
+            //     gcsrqk_chart_option.dataZoom[0].show = false;
+            // }
             gcsrqkChart.setOption(gcsrqk_chart_option);
 
             const cb_chart_option_data = {
@@ -1042,7 +1068,7 @@
                     });
                     // 找出最近的一个had_ys为true值
                     if (hadYsDatas.length > 0) {
-                        c4.ys_tp = hadYsDatas[hadYsDatas.length - 1].ys_tp + c4.ys_tp;
+                        c4.ys_tp = ZhCalc.add(hadYsDatas[hadYsDatas.length - 1].ys_tp, c4.ys_tp);
                     }
                     // if (!c4.had_ys) {
                     //     const hadYsDatas = _.filter(new_yingsf_option_data, function (item) {
@@ -1059,7 +1085,7 @@
                     });
                     // 找出最近的一个had_yf为true值
                     if (hadYfDatas.length > 0) {
-                        c4.yf_tp = hadYfDatas[hadYfDatas.length - 1].yf_tp + c4.yf_tp;
+                        c4.yf_tp = ZhCalc.add(hadYfDatas[hadYfDatas.length - 1].yf_tp, c4.yf_tp);
                     }
                     // if (!c4.had_yf) {
                     //     const hadYfDatas = _.filter(new_yingsf_option_data, function (item) {
@@ -1099,7 +1125,7 @@
                     });
                     // 找出最近的一个had_ys为true值
                     if (hadYsDatas.length > 0) {
-                        c4.ys_tp = hadYsDatas[hadYsDatas.length - 1].ys_tp + c4.ys_tp;
+                        c4.ys_tp = ZhCalc.add(hadYsDatas[hadYsDatas.length - 1].ys_tp, c4.ys_tp);
                     }
                     // if (!c4.had_ys) {
                     //     const hadYsDatas = _.filter(new_yisf_option_data, function (item) {
@@ -1116,7 +1142,7 @@
                     });
                     // 找出最近的一个had_yf为true值
                     if (hadYfDatas.length > 0) {
-                        c4.yf_tp = hadYfDatas[hadYfDatas.length - 1].yf_tp + c4.yf_tp;
+                        c4.yf_tp = ZhCalc.add(hadYfDatas[hadYfDatas.length - 1].yf_tp, c4.yf_tp);
                     }
                     // if (!c4.had_yf) {
                     //     const hadYfDatas = _.filter(new_yisf_option_data, function (item) {
@@ -1174,11 +1200,11 @@
                         }
                         oneCbgl.end_df_tp = ZhCalc.sub(oneCbgl.end_yf_tp, oneCbgl.end_sf_tp);
                         gccbglhz.push(oneCbgl);
-                        dpgl_option.dataZoom[0].end = computedPosition(cbgl_tenders.length);
+                        dpgl_option.dataZoom[0].end = computedPosition(cbgl_tenders.length, 4);
                         dpgl_option.xAxis[0].data = dpgl_chart_option_name;
                         dpgl_option.series[0].data = dpgl_chart_option_data.end_gather_tp;
                         dpgl_option.series[1].data = dpgl_chart_option_data.end_sf_tp;
-                        if (cbgl_tenders.length >= 8) {
+                        if (cbgl_tenders.length >= 4) {
                             dpgl_option.dataZoom[0].show = true;
                         } else {
                             dpgl_option.dataZoom[0].show = false;
@@ -1198,10 +1224,10 @@
                 allgccb.end_gather_tp = ZhCalc.add(allgccb.end_gather_tp, cb.end_gather_tp);
                 allgccb.end_sf_tp = ZhCalc.add(allgccb.end_sf_tp, cb.end_sf_tp);
                 allgccb.end_yf_tp = ZhCalc.add(allgccb.end_yf_tp, cb.end_yf_tp);
-                hzHtml += '<tr class="bg-dark" style="line-height: 2rem;text-align: center;"><td style="text-align: left">' + cb.name + '</td><td>' + cb.end_gather_tp + '</td><td>' + cb.end_yf_tp + '</td><td>' + cb.end_sf_tp + '</td><td>' + cb.end_df_tp + '</td></tr>';
+                hzHtml += '<tr class="bg-dark" style="line-height: 2rem;text-align: center;"><td style="text-align: left;min-width: 95px;">' + cb.name + '</td><td>' + cb.end_gather_tp + '</td><td>' + cb.end_yf_tp + '</td><td>' + cb.end_sf_tp + '</td><td>' + cb.end_df_tp + '</td></tr>';
             }
             allgccb.end_df_tp = ZhCalc.sub(allgccb.end_yf_tp, allgccb.end_sf_tp);
-            hzHtml += '<tr class="bg-dark" style="line-height: 2rem;text-align: center;"><td style="text-align: left">' + allgccb.name + '</td><td>' + allgccb.end_gather_tp + '</td><td>' + allgccb.end_yf_tp + '</td><td>' + allgccb.end_sf_tp + '</td><td>' + allgccb.end_df_tp + '</td></tr>';
+            hzHtml += '<tr class="bg-dark" style="line-height: 2rem;text-align: center;"><td style="text-align: left;min-width: 95px;">' + allgccb.name + '</td><td>' + allgccb.end_gather_tp + '</td><td>' + allgccb.end_yf_tp + '</td><td>' + allgccb.end_sf_tp + '</td><td>' + allgccb.end_df_tp + '</td></tr>';
             $('.stage-data').html(hzHtml);
             setTableboxHeight();
             // console.log(sr_tenders, cb_tenders);
@@ -1294,9 +1320,12 @@
         });
     });
     // 计算显示滚动条长度
-    function computedPosition(xArrayLength) {
-        if (xArrayLength >= 8) {
-            return Math.floor(8 / xArrayLength * 100) > 100 ? 100 : Math.floor(8 / xArrayLength * 100);
+    function computedPosition(xArrayLength, maxNum = 8) {
+        if (xArrayLength >= maxNum) {
+            // return Math.floor(maxNum / xArrayLength * 100) > 100 ? 100 : Math.floor(maxNum / xArrayLength * 100);
+            const endValue = (maxNum / xArrayLength) * 100;
+            return endValue > Math.floor(endValue) + 0.5 ? Math.floor(endValue) + 0.5 : (Math.floor(endValue) === 0 ? 0.5 : Math.floor(endValue));
+            // return Math.round((maxNum / xArrayLength) * 100 * 100)/100;
             // return length <= 10 ? 35 : 100 - Math.floor(35 / length * 100);
         } else {
             return 100;

+ 2 - 2
app/view/material/index.ejs

@@ -81,7 +81,7 @@
                             <% if (materialColShow[0].checked) { %>
                             <td class="text-right"><%= m.m_tp !== null ? ctx.helper.round(m.m_tp, m.decimal.tp) : null %></td>
                             <% if (openMaterialTax) { %><td class="text-right"><% if (m.material_tax) { %><% if (m.m_tax_tp) { %><%- m.m_tax_tp %><% } else { %><%- m.m_tp %><% } %><% } %></td><% } %>
-                            <% if ((openMaterialTax && !allMaterialTax) || !openMaterialTax) { %><td class="text-right"><% if (!m.material_tax) { %><%= m.m_tp !== null ? ctx.helper.round(ctx.helper.mul(m.m_tp, 1+m.rate/100), m.decimal.tp) : null %><% } %></td><% } %>
+                            <% if ((openMaterialTax && !allMaterialTax) || !openMaterialTax) { %><td class="text-right"><% if (!m.material_tax) { %><%- m.rate_tp %><% } %></td><% } %>
                             <% } %>
                             <% if (materialColShow[1].checked) { %>
                             <td class="text-right"><%= m.ex_tp !== null ? ctx.helper.round(m.ex_tp, m.decimal.tp) : null %></td>
@@ -90,7 +90,7 @@
                             <% if (materialColShow[2].checked) { %>
                             <td class="text-right"><%= ctx.helper.add(ctx.helper.round(m.ex_tp, m.decimal.tp), ctx.helper.round(m.m_tp, m.decimal.tp)) %></td>
                             <% if (openMaterialTax) { %><td class="text-right"><% if (m.material_tax) { %><% if (m.m_tax_tp) { %><%- m.m_tax_tp %><% } else { %><%- m.m_tp %><% } %><% } %></td><% } %>
-                            <td class="text-right"><% if (m.material_tax) { %><%= m.ex_tp !== null ? ctx.helper.round(ctx.helper.mul(m.ex_tp, 1+m.exponent_rate/100), m.decimal.tp) : null %><% } else { %><%= ctx.helper.add(ctx.helper.round(ctx.helper.mul(m.ex_tp, 1+m.exponent_rate/100), m.decimal.tp), ctx.helper.round(ctx.helper.mul(m.m_tp, 1+m.rate/100), m.decimal.tp)) %><% } %></td>
+                            <td class="text-right"><% if (m.material_tax) { %><%= m.ex_tp !== null ? ctx.helper.round(ctx.helper.mul(m.ex_tp, 1+m.exponent_rate/100), m.decimal.tp) : null %><% } else { %><%= ctx.helper.add(ctx.helper.round(ctx.helper.mul(m.ex_tp, 1+m.exponent_rate/100), m.decimal.tp), m.rate_tp) %><% } %></td>
                             <% } %>
                             <td class="<%- auditConst.auditProgressClass[m.status] %>">
                                 <% if (m.curAuditor) { %>

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

@@ -191,8 +191,8 @@
                                                     <td class="text-center"><%= material.ex_tp !== null || material.ex_pre_tp !== null ? ctx.helper.add(material.ex_pre_tp, ctx.helper.round(material.ex_tp, material.decimal.tp)) : null %></td>
                                                 </tr>
                                                 <tr id="rate_set"><td>材料价差费用(含建筑税)</td>
-                                                    <td class="text-center"><%= material.m_tp !== null ? ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), material.decimal.tp) : null %></td>
-                                                    <td class="text-center"><%= material.m_tp !== null || pre_tp_hs !== null ? ctx.helper.add(pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), material.decimal.tp)) : null %></td>
+                                                    <td class="text-center"><%= material.m_tp !== null ? material.rate_tp : null %></td>
+                                                    <td class="text-center"><%= material.m_tp !== null || pre_tp_hs !== null ? ctx.helper.add(pre_tp_hs, material.rate_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.add(ex_pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.exponent_rate/100), material.decimal.tp)) : null %></td>
                                                 </tr>
@@ -217,8 +217,8 @@
                                                     <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.add(pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.m_tp, 1+material.rate/100), material.decimal.tp)) : null) : pre_tp_hs !== null ? pre_tp_hs : '-' %></td>
+                                                    <td class="text-center"><%= !material.material_tax ? material.rate_tp : '-' %></td>
+                                                    <td class="text-center"><%= !material.material_tax ? (material.m_tp !== null || pre_tp_hs !== null ? ctx.helper.add(pre_tp_hs, material.rate_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.add(ex_pre_tp_hs, ctx.helper.round(ctx.helper.mul(material.ex_tp, 1+material.exponent_rate/100), material.decimal.tp)) : null %></td>
                                                 </tr>
@@ -231,11 +231,13 @@
                                         <div class="sp-wrap" style="overflow: auto;">
                                             <table class="table table-bordered">
                                                 <thead>
-                                                <tr class="text-center"><th colspan="<% if (material.material_tax) { %>3<% } else { %>2<% } %>">期明细</th></tr>
+                                                <tr class="text-center"><th colspan="3">期明细</th></tr>
                                                 <tr><th class="text-center">期数</th>
                                                     <th class="text-center">本期调差金额</th>
                                                     <% if (material.material_tax) { %>
                                                         <th class="text-center">本期调差金额(材料税)</th>
+                                                    <% } else { %>
+                                                    <th class="text-center">本期调差金额(建筑税)</th>
                                                     <% } %>
                                                 </tr>
                                                 </thead>
@@ -244,12 +246,16 @@
                                                     <tr><td>第<%- ms.order %>期</td><td class="text-center"><%- ms.m_tp !== null ? ms.m_tp : null %></td>
                                                         <% if (material.material_tax) { %>
                                                             <td class="text-center"><%- ms.m_tax_tp !== null ? ms.m_tax_tp : null %></td>
+                                                        <% } else { %>
+                                                        <td class="text-center"><%= ms.m_tp !== null ? ctx.helper.round(ctx.helper.mul(ms.m_tp, 1+material.rate/100), material.decimal.tp) : null %></td>
                                                         <% } %>
                                                     </tr>
                                                 <% } %>
                                                 <tr><td>合计</td><td class="text-center"><%- material.m_tp %></td>
                                                     <% if (material.material_tax) { %>
                                                         <td class="text-center"><%- material.m_tax_tp %></td>
+                                                    <% } else { %>
+                                                    <td class="text-center"><%- material.rate_tp %></td>
                                                     <% } %>
                                                 </tr>
                                                 </tbody>

+ 1 - 2
app/view/material/modal.ejs

@@ -23,7 +23,7 @@
                         <div class="col-4">
                             <div class="custom-control custom-checkbox">
                                 <input type="checkbox" class="custom-control-input select-stage-order" id="stage_<%= stage.id %>" name="stage_id[]" value="<%= stage.id %>" data-order="<%= stage.order %>">
-                                <label class="custom-control-label" for="stage_<%= stage.id %>">第<%= stage.order %>期</label>
+                                <label class="custom-control-label" for="stage_<%= stage.id %>">第<%= stage.order %>期(<%- stage.s_time  %>)</label>
                             </div>
                         </div>
                         <% } %>
@@ -47,7 +47,6 @@
                     <div>
                         <% for (const qs of qtySourceConst) { %>
                         <div class="form-check form-check-inline">
-                            <% console.log(materials.length) %>
                             <input type="radio" name="qty_source" id="<%- qs.key %>_source" class="form-check-input" value="<%- qs.value %>" <% if (materials && materials.length === 0 && qs.value === 1) { %>checked<% } else if (materials && materials.length > 0 && materials[0].qty_source === qtySourceValueConst[qs.key]) { %>checked<% } %>>
                             <label class="form-check-label" for="<%- qs.key %>_source"><%- qs.name %></label>
                         </div>

+ 6 - 1
app/view/measure/stage.ejs

@@ -30,7 +30,7 @@
                 <table class="table table-bordered table-hover">
                     <thead>
                     <tr>
-                        <th class="text-center" width="70px">计量期数</th>
+                        <th class="text-center" width="80px">计量期数</th>
                         <th class="text-center" width="70px">计量月份</th>
                         <th class="text-center" width="70px">截止日期</th>
                         <th class="text-center" width="100px" name="contract_tp">本期合同计量</th>
@@ -55,6 +55,11 @@
                             <% if ((i === 0 || (stages[i-1] && stages[i-1].status !== auditConst.status.checked)) && s.user_id === ctx.session.sessionUser.accountId) { %>
                             <a href="#edit" class="edit-stage" data-index="<%- i %>" data-toggle="modal" data-target="#edit"><i class="fa fa-pencil-square-o "></i></a>
                             <% } %>
+                            <% if (!s.rpt_filed) { %>
+                            <a data-toggle="tooltip" data-placement="top" data-original-title="报表未归档">
+                                <i class="fa fa-file-pdf-o text-danger"></i>
+                            </a>
+                            <% } %>
                         </td>
                         <td class="text-center"><%- s.s_time %></td>
                         <td class="text-center">

+ 1 - 1
app/view/revise/history.ejs

@@ -94,7 +94,7 @@
                 <li class="nav-item">
                     <a class="nav-link" content="#search" href="javascript: void(0);">查找定位</a>
                 </li>
-                <li class="nav-item" style="display: none">
+                <li class="nav-item">
                     <a class="nav-link" content="#fujian" href="javascript: void(0);">附件</a>
                 </li>
             </ul>

+ 1 - 1
app/view/revise/info.ejs

@@ -222,7 +222,7 @@
                     <a class="nav-link" content="#bills-tag" href="javascript: void(0);">书签</a>
                 </li>
                 <li class="nav-item">
-                    <a class="nav-link" content="#fujian" href="javascript: void(0);" style="display: none">附件</a>
+                    <a class="nav-link" content="#fujian" href="javascript: void(0);">附件</a>
                 </li>
                 <li class="nav-item">
                     <a class="nav-link" content="#error-list" id="error-list-tab" href="javascript: void(0);" style="display: none;">错误列表</a>

+ 2 - 2
app/view/setting/category_modal.ejs

@@ -50,7 +50,7 @@
 </div>
 <!--弹出添加值-->
 <div class="modal fade" id="add" data-backdrop="static">
-    <div class="modal-dialog" role="document">
+    <div class="modal-dialog modal-lg" role="document">
         <div class="modal-content">
             <div class="modal-header">
                 <h5 class="modal-title">添加值</h5>
@@ -58,7 +58,7 @@
             <div class="modal-body" style="max-height: 500px;overflow: auto">
                 <table class="table table-bordered">
                     <thead>
-                    <tr><th width="35" class="text-center">序号</th><th>值</th><th width="40">排序</th><th>包含标段</th><th>删除</th></tr>
+                    <tr><th width="10%" class="text-center">序号</th><th>值</th><th width="10%">包含标段</th><th width="40px">排序</th><th width="10%">删除</th></tr>
                     </thead>
                     <tbody id="value-list">
                     </tbody>

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

@@ -188,7 +188,7 @@
                                     </div>
                                 </div>
                             </div>
-                            <div class="col-6">
+                            <div class="col-6" <% if (!ctx.session.sessionProject.page_show.openMaterial) { %>style="display: none;"<% } %>>
                                 <div class="card mb-3">
                                     <div class="card-body">
                                         <h5 class="card-title">材料调差</h5>

+ 2 - 0
app/view/tender/tender_sub_menu.ejs

@@ -47,11 +47,13 @@
             </ul>
             <% } %>
         </div>
+        <% if (ctx.session.sessionProject.page_show.openMaterial) { %>
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
                 <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/material') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/measure/material" class="h3"><i class="fa fa-line-chart fa-fw"></i> <span>材料调差</span></a></li>
             </ul>
         </div>
+        <% } %>
         <% if (ctx.session.sessionProject.page_show.xxjd && (ctx.tender.schedule_permission !== 0 || ctx.tender.isTourist)) { %>
         <div class="nav-box">
             <h3><i class="fa fa-bar-chart fa-fw"></i> 投资进度</h3>

+ 2 - 0
app/view/tender/tender_sub_mini_menu.ejs

@@ -48,11 +48,13 @@
                 </ul>
             <% } %>
         </div>
+        <% if (ctx.session.sessionProject.page_show.openMaterial) { %>
         <div class="nav-box">
             <ul class="nav-list list-unstyled">
                 <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/material') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/measure/material" class="h3"><i class="fa fa-line-chart fa-fw"></i> <span>材料调差</span></a></li>
             </ul>
         </div>
+        <% } %>
         <% if (ctx.session.sessionProject.page_show.xxjd && (ctx.tender.schedule_permission !== 0 || ctx.tender.isTourist)) { %>
             <div class="nav-box">
                 <h3><i class="fa fa-bar-chart fa-fw"></i> 投资进度</h3>

+ 5 - 1
config/config.default.js

@@ -93,6 +93,10 @@ module.exports = appInfo => {
             sessionName: 'csrfToken_j',   // csrf token's session name
             bodyName: '_csrf_j',          // request csrf token's name in body
             queryName: '_csrf_j',         // request csrf token's name in query
+            cookie: {
+                httpOnly: true,
+                // secure: true,  // 如果站点使用了HTTPS,可以开启此选项
+            }
         },
     };
 
@@ -253,7 +257,7 @@ module.exports = appInfo => {
     config.fujianOssPath = 'https://jiliang-saas-oss-cdn.smartcost.com.cn/';
     config.fujianOssFolder = '';
 
-    config.syncUrl = 'http://sync.jl.smartcost.com.cn/';
+    config.syncUrl = 'https://jl-sync.smartcost.com.cn/';
 
     // 项目管理跳转路径
     config.managementPath = 'https://pm.smartcost.com.cn';

+ 3 - 0
config/config.local.js

@@ -49,6 +49,9 @@ module.exports = appInfo => {
         key: '9b67989994f9def437ea68bb495f0162',
     };
 
+    // 中间件
+    config.middleware = ['httpHeader', 'gzip', 'urlParse', 'sortFilter', 'autoLogger', 'autoFinishLogger'];
+
     // 前端验证
     config.jsValidator = {
         client: {},

+ 3 - 0
config/config.qa.js

@@ -31,6 +31,9 @@ module.exports = appInfo => {
     // 表名前缀
     config.tablePrefix = 'zh_';
 
+    // 中间件
+    config.middleware = ['httpHeader', 'gzip', 'urlParse', 'sortFilter', 'autoLogger', 'autoFinishLogger'];
+
     // redis设置
     config.redis = {
         client: {

+ 17 - 7
db_script/change_valuation.js

@@ -6,13 +6,17 @@ const status = require('../app/const/audit').change.status;
 const querySql = BaseUtil.querySql;
 const ZhCalc = BaseUtil.ZhCalc;
 
-const checkChange = async function(change) {
+const checkChange = async function(change, decimal) {
     const changeBills = await querySql('Select * From zh_change_audit_list where cid = ?', [change.cid]);
     let valuation_tp = 0;
     let unvaluation_tp = 0;
     for (const cb of changeBills) {
-        valuation_tp = cb.is_valuation ? ZhCalc.add(valuation_tp, cb.checked_price) : valuation_tp;
-        unvaluation_tp = !cb.is_valuation ? ZhCalc.add(unvaluation_tp, cb.checked_price) : unvaluation_tp;
+        cb.tp = ZhCalc.mul(cb.spamount, cb.unit_price, change.tp_decimal || decimal.tp);
+        if (cb.is_valuation) {
+            valuation_tp = ZhCalc.add(valuation_tp, cb.tp);
+        } else {
+            unvaluation_tp = ZhCalc.add(unvaluation_tp, cb.tp);
+        }
     }
     await querySql('Update zh_change Set valuation_tp = ?, unvaluation_tp = ? Where cid = ?', [valuation_tp, unvaluation_tp, change.cid]);
     console.log(`Update Change ${change.cid}`);
@@ -23,9 +27,12 @@ const doComplete = async function() {
         const tender = await querySql('Select * From zh_tender');
         for (const t of tender) {
             console.log(`Update Tender ${t.id}:`);
-            const changes = await querySql('Select * From zh_change where tid = ? AND status = ?', [t.id, status.checked]);
+            const info = await querySql('Select * From zh_tender_info where tid = ?', [t.id]);
+            const decimal = info.length > 0 && info[0].decimal ? JSON.parse(info[0].decimal) : defaultInfo.defaultInfo.decimal;
+
+            const changes = await querySql('Select * From zh_change where tid = ?', [t.id]);
             for (const c of changes) {
-                await checkChange(c);
+                await checkChange(c, decimal);
             }
         }
     } catch (err) {
@@ -38,9 +45,12 @@ const doCompleteTest = async function(tid) {
         const tender = await querySql('Select * From zh_tender where id = ?', [tid]);
         for (const t of tender) {
             console.log(`Update Tender ${t.id}:`);
-            const changes = await querySql('Select * From zh_change where tid = ? AND status = ?', [t.id, status.checked]);
+            const info = await querySql('Select * From zh_tender_info where tid = ?', [t.id]);
+            const decimal = info.length > 0 && info[0].decimal ? JSON.parse(info[0].decimal) : defaultInfo.defaultInfo.decimal;
+
+            const changes = await querySql('Select * From zh_change where tid = ?', [t.id]);
             for (const c of changes) {
-                await checkChange(c);
+                await checkChange(c, decimal);
             }
         }
     } catch (err) {

+ 61 - 0
db_script/material_rate_tp.js

@@ -0,0 +1,61 @@
+// 计算调差建筑税金额
+
+const materialConst = require('../app/const/material');
+const BaseUtil = require('./baseUtils');
+const querySql = BaseUtil.querySql;
+const ZhCalc = BaseUtil.ZhCalc;
+
+const checkMaterial = async function(material) {
+    let rate_tp = 0;
+    material.decimal = material.decimal ? JSON.parse(material.decimal) : materialConst.decimal;
+    if (material.is_stage_self) {
+        const materialStages = await querySql('Select * From zh_material_stage Where mid = ?', [material.id]);
+        for (const ms of materialStages) {
+            const ms_rate_tp = ZhCalc.round(ZhCalc.mul(ms.m_tp, 1 + material.rate / 100), material.decimal.tp);
+            rate_tp = ZhCalc.add(rate_tp, ms_rate_tp);
+        }
+    } else {
+        rate_tp = ZhCalc.round(ZhCalc.mul(material.m_tp, 1 + material.rate / 100), material.decimal.tp);
+    }
+    await querySql('Update zh_material Set rate_tp = ? Where id = ?', [rate_tp, material.id]);
+    console.log(`Update Material ${material.id}`);
+};
+
+const doComplete = async function() {
+    try {
+        const tender = await querySql('Select * From zh_tender');
+        for (const t of tender) {
+            console.log(`Update Tender ${t.id}:`);
+
+            const materials = await querySql('Select * From zh_material where tid = ?', [t.id]);
+            for (const m of materials) {
+                await checkMaterial(m);
+            }
+        }
+    } catch (err) {
+        console.log(err);
+    }
+    BaseUtil.closePool();
+};
+const doCompleteTest = async function(tid) {
+    try {
+        const tender = await querySql('Select * From zh_tender where id = ?', [tid]);
+        for (const t of tender) {
+            console.log(`Update Tender ${t.id}:`);
+            const materials = await querySql('Select * From zh_material where tid = ?', [t.id]);
+            for (const m of materials) {
+                await checkMaterial(m);
+            }
+        }
+    } catch (err) {
+        console.log(err);
+    }
+    BaseUtil.closePool();
+};
+
+const tenderId = process.argv[3];
+if (tenderId) {
+    doCompleteTest(tenderId);
+} else {
+    doComplete();
+}

+ 2 - 54
sql/update.sql

@@ -1,54 +1,2 @@
-ALTER TABLE `zh_project`
-ADD COLUMN `common_json` json NULL COMMENT '通用json,没有sql查询值必要的可放这' AFTER `notice_setting`;
-ALTER TABLE `zh_ledger_tag`
-ADD COLUMN `pos_id` varchar(36) NOT NULL DEFAULT '' COMMENT '关联计量单元id(zh_pos表中的id)' AFTER `id`;
-
-ALTER TABLE `zh_change`
-ADD COLUMN `valuation_tp` decimal(30, 8) NULL DEFAULT 0 COMMENT '计价金额(审批完成后统计)' AFTER `negative_tp`,
-ADD COLUMN `unvaluation_tp` decimal(30, 8) NULL DEFAULT 0 COMMENT '不计价金额(审批完成后统计)' AFTER `valuation_tp`;
-
-ALTER TABLE `zh_change`
-MODIFY COLUMN `positive_tp` decimal(30, 8) NOT NULL DEFAULT 0.00000000 COMMENT '正变更金额' AFTER `order_by`,
-MODIFY COLUMN `negative_tp` decimal(30, 8) NOT NULL DEFAULT 0.00000000 COMMENT '负变更金额' AFTER `positive_tp`;
-
-ALTER TABLE `zh_change_audit_list`
-ADD COLUMN `oamount2` decimal(30, 8) NULL DEFAULT NULL COMMENT '原数量(可编辑)' AFTER `oamount`;
-
-ALTER TABLE `zh_ledger_attachment`
-MODIFY COLUMN `tid` int(11) UNSIGNED NOT NULL COMMENT '标段id' AFTER `id`,
-ADD COLUMN `revise_id` varchar(36) NOT NULL COMMENT '修订id' AFTER `tid`,
-ADD COLUMN `revising` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '修订中' AFTER `revise_id`,
-MODIFY COLUMN `uid` int(11) UNSIGNED NOT NULL COMMENT '上传者id' AFTER `lid`,
-ADD COLUMN `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间' AFTER `in_time`;
-
-ALTER TABLE `zh_ledger_attachment`
-ADD INDEX `idx_tid`(`tid`),
-ADD INDEX `idx_tid_sid`(`tid`, `settle_id`),
-ADD INDEX `idx_tid_rid`(`tid`, `revise_id`),
-ADD INDEX `idx_tid_revising`(`tid`, `revising`);
-
-CREATE TABLE `zh_ancillary_gcl`  (
-  `id` varchar(36) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'uuid',
-  `tid` int(11) UNSIGNED NOT NULL COMMENT '标段id',
-  `lid` varchar(36) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '台账id(zh_ledger.id)',
-  `g_order` int(11) UNSIGNED NOT NULL DEFAULT 1 COMMENT '排序',
-  `is_aux` tinyint(4) UNSIGNED NOT NULL DEFAULT 0 COMMENT '辅材',
-  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '名称',
-  `unit` varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '单位',
-  `quantity` decimal(24, 8) NOT NULL DEFAULT 0.00000000 COMMENT '设计量',
-  `expr` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '设计量公式',
-  `drawing_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '图册号',
-  `memo` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '备注',
-  `add_user_id` int(11) UNSIGNED NOT NULL COMMENT '创建人',
-  `add_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
-  `update_user_id` int(11) UNSIGNED NOT NULL COMMENT '最后修改人',
-  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
-  PRIMARY KEY (`id`) USING BTREE,
-  INDEX `idx_tid`(`tid`) USING BTREE,
-  INDEX `idex_tid_lid`(`tid`, `lid`) USING BTREE
-) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_unicode_ci COMMENT = '台账-附属工程量' ROW_FORMAT = Dynamic;
-
---修复转换值问题,并且需要再运行一次db_script/check_bills更新checked_price方法
-UPDATE `zh_change_audit_list` SET `checked_amount` = CONVERT(`samount`, DECIMAL(30, 8)) WHERE `samount` != '';
-
-UPDATE `zh_change_audit_list` SET `oamount2` = `oamount`;
+ALTER TABLE `zh_material`
+ADD COLUMN `rate_tp` decimal(30, 8) NULL DEFAULT NULL COMMENT '建筑含税总金额' AFTER `rate`;

+ 54 - 0
sql/update20240624.sql

@@ -0,0 +1,54 @@
+ALTER TABLE `zh_project`
+ADD COLUMN `common_json` json NULL COMMENT '通用json,没有sql查询值必要的可放这' AFTER `notice_setting`;
+ALTER TABLE `zh_ledger_tag`
+ADD COLUMN `pos_id` varchar(36) NOT NULL DEFAULT '' COMMENT '关联计量单元id(zh_pos表中的id)' AFTER `id`;
+
+ALTER TABLE `zh_change`
+ADD COLUMN `valuation_tp` decimal(30, 8) NULL DEFAULT 0 COMMENT '计价金额(审批完成后统计)' AFTER `negative_tp`,
+ADD COLUMN `unvaluation_tp` decimal(30, 8) NULL DEFAULT 0 COMMENT '不计价金额(审批完成后统计)' AFTER `valuation_tp`;
+
+ALTER TABLE `zh_change`
+MODIFY COLUMN `positive_tp` decimal(30, 8) NOT NULL DEFAULT 0.00000000 COMMENT '正变更金额' AFTER `order_by`,
+MODIFY COLUMN `negative_tp` decimal(30, 8) NOT NULL DEFAULT 0.00000000 COMMENT '负变更金额' AFTER `positive_tp`;
+
+ALTER TABLE `zh_change_audit_list`
+ADD COLUMN `oamount2` decimal(30, 8) NULL DEFAULT NULL COMMENT '原数量(可编辑)' AFTER `oamount`;
+
+ALTER TABLE `zh_ledger_attachment`
+MODIFY COLUMN `tid` int(11) UNSIGNED NOT NULL COMMENT '标段id' AFTER `id`,
+ADD COLUMN `revise_id` varchar(36) NOT NULL COMMENT '修订id' AFTER `tid`,
+ADD COLUMN `revising` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '修订中' AFTER `revise_id`,
+MODIFY COLUMN `uid` int(11) UNSIGNED NOT NULL COMMENT '上传者id' AFTER `lid`,
+ADD COLUMN `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间' AFTER `in_time`;
+
+ALTER TABLE `zh_ledger_attachment`
+ADD INDEX `idx_tid`(`tid`),
+ADD INDEX `idx_tid_sid`(`tid`, `settle_id`),
+ADD INDEX `idx_tid_rid`(`tid`, `revise_id`),
+ADD INDEX `idx_tid_revising`(`tid`, `revising`);
+
+CREATE TABLE `zh_ancillary_gcl`  (
+  `id` varchar(36) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT 'uuid',
+  `tid` int(11) UNSIGNED NOT NULL COMMENT '标段id',
+  `lid` varchar(36) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '台账id(zh_ledger.id)',
+  `g_order` int(11) UNSIGNED NOT NULL DEFAULT 1 COMMENT '排序',
+  `is_aux` tinyint(4) UNSIGNED NOT NULL DEFAULT 0 COMMENT '辅材',
+  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '名称',
+  `unit` varchar(20) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '单位',
+  `quantity` decimal(24, 8) NOT NULL DEFAULT 0.00000000 COMMENT '设计量',
+  `expr` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '设计量公式',
+  `drawing_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '图册号',
+  `memo` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '备注',
+  `add_user_id` int(11) UNSIGNED NOT NULL COMMENT '创建人',
+  `add_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_user_id` int(11) UNSIGNED NOT NULL COMMENT '最后修改人',
+  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后更新时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  INDEX `idx_tid`(`tid`) USING BTREE,
+  INDEX `idex_tid_lid`(`tid`, `lid`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_unicode_ci COMMENT = '台账-附属工程量' ROW_FORMAT = Dynamic;
+
+--修复转换值问题,并且需要再运行一次db_script/check_bills更新checked_price方法
+UPDATE `zh_change_audit_list` SET `checked_amount` = CONVERT(`samount`, DECIMAL(30, 8)) WHERE `samount` != '';
+
+UPDATE `zh_change_audit_list` SET `oamount2` = `oamount`;