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

Merge remote-tracking branch 'remotes/origin/dev' into uat

MaiXinRong 4 лет назад
Родитель
Сommit
e83d49da5d
49 измененных файлов с 1928 добавлено и 485 удалено
  1. 20 0
      app/const/advance.js
  2. 1 0
      app/const/tender_info.js
  3. 7 7
      app/const/third_party.js
  4. 1 1
      app/controller/advance_controller.js
  5. 7 15
      app/controller/ledger_controller.js
  6. 5 2
      app/controller/report_controller.js
  7. 12 20
      app/controller/revise_controller.js
  8. 35 7
      app/controller/setting_controller.js
  9. 8 16
      app/controller/stage_controller.js
  10. 16 0
      app/controller/tender_controller.js
  11. 114 0
      app/controller/wap_controller.js
  12. 0 165
      app/extend/helper.js
  13. 174 33
      app/lib/ledger.js
  14. 151 25
      app/lib/rptCustomData.js
  15. 3 3
      app/lib/stage_im.js
  16. 7 3
      app/lib/wechat.js
  17. 5 0
      app/public/js/change_information_set.js
  18. 24 11
      app/public/js/ledger_check.js
  19. 4 4
      app/public/js/shares/cs_tools.js
  20. 1 7
      app/public/js/stage.js
  21. 5 2
      app/public/js/stage_bwtz.js
  22. 93 27
      app/public/report/js/rpt_main.js
  23. 2 0
      app/public/report/js/rpt_preview_common.js
  24. 1 0
      app/public/report/js/rpt_print.js
  25. 5 0
      app/router.js
  26. 55 5
      app/service/advance_audit.js
  27. 5 5
      app/service/ledger_revise.js
  28. 3 3
      app/service/pos.js
  29. 0 1
      app/service/project.js
  30. 1 13
      app/service/project_account.js
  31. 4 0
      app/service/report.js
  32. 52 4
      app/service/revise_audit.js
  33. 68 0
      app/service/s2b_proj.js
  34. 5 5
      app/view/advance/detail.ejs
  35. 19 19
      app/view/advance/modal_audit.ejs
  36. 6 6
      app/view/change/index.ejs
  37. 5 5
      app/view/material/audit_modal.ejs
  38. 1 11
      app/view/setting/fun.ejs
  39. 140 52
      app/view/setting/s2b.ejs
  40. 2 0
      app/view/stage/bwtz.ejs
  41. 7 1
      app/view/tender/detail_modal.ejs
  42. 54 1
      app/view/wap/dashboard.ejs
  43. 145 0
      app/view/wap/shenpi_advance.ejs
  44. 259 0
      app/view/wap/shenpi_advance_detail.ejs
  45. 1 1
      app/view/wap/shenpi_change.ejs
  46. 225 0
      app/view/wap/shenpi_revise.ejs
  47. 1 1
      app/view/wap/shenpi_stage.ejs
  48. 95 3
      app/view/wap/tender.ejs
  49. 74 1
      builder_report_index_define.js

+ 20 - 0
app/const/advance.js

@@ -0,0 +1,20 @@
+'use strict';
+
+/**
+ * 预付款相关常量
+ *
+ * @author EllisRan
+ * @date 2021/6/17
+ * @version
+ */
+
+// 预付款类型
+const typeCol = [
+    { key: 'start', type: 0, name: '开工预付款' },
+    { key: 'material', type: 1, name: '材料预付款' },
+    // { key: 'safe', type: 2, name: '安全生产预付款' },
+]
+
+module.exports = {
+    typeCol,
+};

+ 1 - 0
app/const/tender_info.js

@@ -158,6 +158,7 @@ const defaultInfo = {
     ledger_check: {
         same_code: true,
         sibling: true,
+        over: true,
     }
 };
 

+ 7 - 7
app/const/third_party.js

@@ -9,15 +9,15 @@
  */
 
 const gxby = [
-    {value: 0, name: '未开始'},
-    {value: 1, name: '进行中'},
-    {value: 2, name: '已完成', color: '#5ACD94'}
+    { value: 0, name: '未开始', limit: false, },
+    { value: 1, name: '进行中', limit: false, },
+    { value: 2, name: '已完成', color: '#5ACD94', limit: true, }
 ];
 const dagl = [
-    {value: 0, name: '未完备'},
-    {value: 1, name: '第一阶段'},
-    {value: 2, name: '第二阶段'},
-    {value: 10, name: '完备', color: '#5ACD94'}
+    { value: 0, name: '未完备', limit: false },
+    { value: 1, name: '第一阶段', limit: true, ratio: 100, },
+    { value: 2, name: '第二阶段', limit: true, ratio: 100, },
+    { value: 10, name: '完备', color: '#5ACD94', limit: true, ratio: 100 }
 ];
 
 module.exports = {

+ 1 - 1
app/controller/advance_controller.js

@@ -167,7 +167,7 @@ module.exports = app => {
                     prev_total_amount = ctx.helper.formatMoney(ctx.helper.add(cur_amount, ctx.advance.prev_amount), ',', isLimitMax ? s2.length : 2);
                 } else {
                     cur_amount = ctx.advance.cur_amount;
-                    const s2 = parseFloat(ctx.advance.prev_total_amount).toString().split('.')[1];
+                    const s2 = parseFloat(ctx.advance.prev_total_amount).toString().split('.')[1] || '';
                     prev_total_amount = ctx.helper.formatMoney(ctx.advance.prev_total_amount, ',', isLimitMax ? s2.length : 2);
                 }
 

+ 7 - 15
app/controller/ledger_controller.js

@@ -472,26 +472,18 @@ module.exports = app => {
                     ? await ctx.service.pos.getPosData({ tid: ctx.tender.id }) : [];
 
                 const checkDataModel = require('../lib/ledger').checkData;
-                const checkData = new checkDataModel(ctx);
+                const checkData = new checkDataModel(ctx, measureType);
                 checkData.loadData(ledgerData, posData);
-                const sameCodeError = ctx.tender.info.ledger_check.same_code ? checkData.checkSameCode() : [];
-                const siblingError = ctx.tender.info.ledger_check.sibling ? checkData.checkSibling() : [];
 
-                const qtyData = ctx.helper.checkBillsWithPos(ledgerData, posData,
-                    ['sgfh_qty', 'qtcl_qty', 'sjcl_qty', 'quantity']);
-                qtyData.error.forEach(x => { x.errorType = 'qty'; });
-                const tpData = ctx.helper.checkBillsTp(ledgerData, [
+                ctx.tender.info.ledger_check.same_code && checkData.checkSameCode();
+                ctx.tender.info.ledger_check.sibling && checkData.checkSibling();
+
+                checkData.checkBillsQty(['sgfh_qty', 'qtcl_qty', 'sjcl_qty', 'quantity']);
+                checkData.checkBillsTp([
                     {qty: 'sgfh_qty', tp: 'sgfh_tp'}, {qty: 'qtcl_qty', tp: 'qtcl_tp'},
                     {qty: 'sjcl_qty', tp: 'sjcl_tp'}, {qty: 'quantity', tp: 'total_price'}
                 ], this.ctx.tender.info.decimal);
-                tpData.error.forEach(x => { x.errorType = 'tp'; });
-                ctx.body = { err: 0, msg: '', data: {
-                    error: [...qtyData.error, ...tpData.error, ...sameCodeError, ...siblingError],
-                    source: {
-                        bills: [...qtyData.source.bills, ...tpData.source.bills],
-                        pos: [...qtyData.source.pos, ...tpData.source.pos],
-                    },
-                }};
+                ctx.body = { err: 0, msg: '', data: checkData.checkResult };
             } catch (err) {
                 this.log(err);
                 ctx.body = this.ajaxErrorBody(err, '检查数据错误');

+ 5 - 2
app/controller/report_controller.js

@@ -72,7 +72,10 @@ module.exports = app => {
         async index(ctx) {
             try {
                 await this._getStageAuditViewData(ctx);
-                const pageShow = ctx.session.sessionProject.page_show;
+                let pageShow = ctx.session.sessionProject.page_show;
+                if (pageShow === null || pageShow === undefined) {
+                    pageShow = {};
+                }
                 // console.log(pageShow);
                 pageShow.showArchive = 0;
                 const tender = ctx.tender;
@@ -464,7 +467,7 @@ module.exports = app => {
                 return;
             }
             await this._saveCustomSelects(params);
-            const pageRstArr = await getMultiRptsCommon(ctx, params, JV.OUTPUT_TYPE_NORMAL, this.app.baseDir);
+            const pageRstArr = await getMultiRptsCommon(ctx, params, JV.OUTPUT_TYPE_NORMAL, this.app.baseDir) || [];
             for (const pageRst of pageRstArr) {
                 for (const page of pageRst.items) {
                     page[JV.PROP_WATERMARK_CELLS] = [];

+ 12 - 20
app/controller/revise_controller.js

@@ -460,27 +460,17 @@ module.exports = app => {
                 const revisePos = await ctx.service.revisePos.getData(ctx.tender.id);
 
                 const checkDataModel = require('../lib/ledger').checkData;
-                const checkData = new checkDataModel(ctx);
-                checkData.loadData(reviseBills, revisePos);
-                const sameCodeError = ctx.tender.info.ledger_check.same_code ? checkData.checkSameCode() : [];
-                const siblingError = ctx.tender.info.ledger_check.sibling ? checkData.checkSibling() : [];
-
-                const qtyData = ctx.helper.checkBillsWithPos(reviseBills, revisePos,
-                    ['sgfh_qty', 'qtcl_qty', 'sjcl_qty', 'quantity']);
-                qtyData.error.forEach(x => { x.errorType = 'qty'; });
-                const tpData = ctx.helper.checkBillsTp(reviseBills, [
+                const reviseCheck = new checkDataModel(ctx, measureType);
+                reviseCheck.loadData(reviseBills, revisePos);
+                ctx.tender.info.ledger_check.same_code && reviseCheck.checkSameCode();
+                ctx.tender.info.ledger_check.sibling && reviseCheck.checkSibling();
+
+                reviseCheck.checkBillsQty(['sgfh_qty', 'qtcl_qty', 'sjcl_qty', 'quantity']);
+                reviseCheck.checkBillsTp([
                     {qty: 'sgfh_qty', tp: 'sgfh_tp'}, {qty: 'qtcl_qty', tp: 'qtcl_tp'},
                     {qty: 'sjcl_qty', tp: 'sjcl_tp'}, {qty: 'quantity', tp: 'total_price'}
                 ], this.ctx.tender.info.decimal);
-                tpData.error.forEach(x => { x.errorType = 'tp'; });
-                ctx.body = { err: 0, msg: '', data: {
-                        error: [...qtyData.error, ...tpData.error, ...sameCodeError, ...siblingError],
-                        source: {
-                            bills: [...qtyData.source.bills, ...tpData.source.bills],
-                            pos: [...qtyData.source.pos, ...tpData.source.pos],
-                        },
-                    }
-                };
+                ctx.body = { err: 0, msg: '', data: reviseCheck.checkResult };
             } catch (err) {
                 this.log(err);
                 ctx.body = this.ajaxErrorBody(err, '检查数据错误');
@@ -891,11 +881,13 @@ module.exports = app => {
 
                 await ctx.service.reviseAudit.check(revise, checkType, ctx.request.body.opinion, revise.times);
 
-                ctx.redirect('/tender/' + ctx.tender.id + '/revise/info');
+                // ctx.redirect('/tender/' + ctx.tender.id + '/revise/info');
+                ctx.redirect(ctx.request.headers.referer);
             } catch (err) {
                 this.log(err);
                 this.postError(err, '审批失败');
-                ctx.redirect('/tender/' + ctx.tender.id + '/revise/info');
+                // ctx.redirect('/tender/' + ctx.tender.id + '/revise/info');
+                ctx.redirect(ctx.request.headers.referer);
             }
         }
 

+ 35 - 7
app/controller/setting_controller.js

@@ -34,11 +34,10 @@ module.exports = app => {
         }
 
         async _checkMenu(pid) {
-            const s2bData = new S2b(this.ctx);
-            const s2bProj = await s2bData.getS2bProj(pid);
-            // this.ctx.subMenu.s2b.display = !!s2bProj && (!!s2bProj.gxby || !!s2bProj.dagl);
-            this.ctx.subMenu.s2b.display = false;
-            return s2bProj;
+            const ctx = this.ctx;
+            await this.ctx.service.s2bProj.refreshSessionS2b(pid);
+            ctx.subMenu.s2b.display = !!ctx.session.sessionProject.gxby || !!ctx.session.sessionProject.dagl;
+            // this.ctx.subMenu.s2b.display = false;
         }
 
         /**
@@ -770,7 +769,7 @@ module.exports = app => {
                 for (const t of tenders) {
                     t.measure_type_str = t.measure_type === measureType.tz.value ? measureType.tz.title : measureType.gcl.title;
                     const stages = await ctx.service.stage.getAllDataByCondition({ where: { tid: t.id } });
-                    t.stage_count_str = `第${stages.count || 0}期`;
+                    t.stage_count_str = `第${stages.length || 0}期`;
                     const user = await ctx.service.projectAccount.getAccountInfoById(t.user_id);
                     t.user_str = user.name + '-' + user.company;
                     t.show_time = stages.length > 0 ? stages[stages.length - 1].cache_time_r || stages[stages.length - 1].in_time : t.create_time;
@@ -804,7 +803,36 @@ module.exports = app => {
                 ctx.body = { err: 0, msg: '', data: null };
             } catch (error) {
                 ctx.helper.log(error);
-                ctx.ajaxError(error, '保存数据错误');
+                this.ajaxErrorBody(error, '保存数据失败');
+            }
+        }
+
+        async s2bUpdateStatus(ctx) {
+            try {
+                const projectId = ctx.session.sessionProject.id;
+                const projectData = await ctx.service.project.getDataById(projectId);
+                if (projectData === null) throw '没有对应的项目数据';
+                if (ctx.session.sessionUser.is_admin === 0) throw '没有访问权限';
+
+                const data = JSON.parse(ctx.request.body.data);
+                console.log(data);
+                if (!data.type || data.status === undefined) throw '提交数据错误';
+
+                const responseData = { err: 0, msg: '', data: null };
+                switch (data.type) {
+                    case 'gxby':
+                        responseData.data = await this.ctx.service.s2bProj.updateGxbyStatus(projectId, data.status, data.limit);
+                        break;
+                    case 'dagl':
+                        responseData.data = await this.ctx.service.s2bProj.updateDaglStatus(projectId, data.status, data.limit, data.ratio);
+                        break;
+                    default: throw '提交数据错误';
+                }
+                ctx.body = responseData;
+            } catch (error) {
+                console.log(error);
+                ctx.helper.log(error);
+                this.ajaxErrorBody(error, '保存数据失败');
             }
         }
     }

+ 8 - 16
app/controller/stage_controller.js

@@ -358,29 +358,21 @@ module.exports = app => {
 
         async check(ctx) {
             try {
-                const projRela = await this.ctx.service.project.getFunRela(this.ctx.session.sessionProject.id);
                 const ledgerData = await this._getStageLedgerData(ctx);
                 const posData = await this._getStagePosData(ctx);
 
                 const checkDataModel = require('../lib/ledger').checkData;
-                const checkData = new checkDataModel(ctx);
+                const checkData = new checkDataModel(ctx, measureType);
                 checkData.loadData(ledgerData, posData);
-                const check3fResult = checkData.check3fLimit(ctx.tender.data);
-                const [qtyData, overData] = ctx.helper.checkBillsWithPos2(ledgerData, posData,
-                    ['contract_qty', 'qc_qty'], projRela.banOver, this.ctx.tender.data.measure_type === measureType.tz.value);
-                qtyData.error.forEach(x => { x.errorType = 'qty'; });
-                overData.error.forEach(x => {x.errorType = 'over'});
-                const tpData = ctx.helper.checkBillsTp(ledgerData.filter(x => {return !x.is_tp}), [
+                await this.ctx.service.s2bProj.refreshSessionS2b();
+                checkData.check3fLimit(ctx.tender.data);
+                checkData.checkBillsQty(['sgfh_qty', 'qtcl_qty', 'sjcl_qty', 'quantity']);
+
+                ctx.tender.info.ledger_check.over && checkData.checkOverRange(['contract_qty', 'qc_qty']);
+                checkData.checkBillsTp([
                     { qty: 'contract_qty', tp: 'contract_tp' }, { qty: 'qc_qty', tp: 'qc_tp' },
                 ], this.ctx.tender.info.decimal);
-                tpData.error.forEach(x => { x.errorType = 'tp'; });
-                ctx.body = { err: 0, msg: '', data: {
-                    error: [...qtyData.error, ...tpData.error, ...overData.error, ...check3fResult.error],
-                    source: {
-                        bills: ctx.helper._.uniqBy([...qtyData.source.bills, ...tpData.source.bills, ...overData.source.bills, ...check3fResult.source.bills], 'id'),
-                        pos: ctx.helper._.uniqBy([...qtyData.source.pos, ...tpData.source.pos, ...overData.source.pos, ...check3fResult.source.pos], 'id'),
-                    },
-                } };
+                ctx.body = { err: 0, msg: '', data: checkData.checkResult };
             } catch (err) {
                 this.log(err);
                 ctx.body = this.ajaxErrorBody(err, '检查数据错误');

+ 16 - 0
app/controller/tender_controller.js

@@ -529,6 +529,22 @@ module.exports = app => {
                 ctx.body = this.ajaxErrorBody(err, '保存标段设置失败');
             }
         }
+        async saveTenderInfo2(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                if (!data || !data.ledger_check) throw '提交数据错误';
+                if (!ctx.session.sessionUser.is_admin) throw '您无权修改该内容';
+
+                const updateData = {};
+                if (data.ledger_check) updateData.ledger_check = data.ledger_check;
+                await ctx.service.tenderInfo.saveTenderInfo(ctx.tender.id, data);
+
+                ctx.body = { err: 0, msg: '', data: JSON.parse(ctx.request.body.data) };
+            } catch (err) {
+                this.log(err);
+                ctx.body = this.ajaxErrorBody(err, '保存失败');
+            }
+        }
 
         /**
          * 设置标段计量类型并调整到标段概况(Get)

+ 114 - 0
app/controller/wap_controller.js

@@ -11,6 +11,7 @@ const URL = require('url');
 const maintainConst = require('../const/maintain');
 const auditConst = require('../const/audit');
 const changeConst = require('../const/change');
+const advanceConst = require('../const/advance');
 
 module.exports = app => {
 
@@ -124,10 +125,21 @@ module.exports = app => {
             }
             // 获取待审批的变更期
             const auditChanges = await ctx.service.changeAudit.getAuditChangeByWap(ctx.session.sessionUser.accountId);
+            // 获取待审批的台账修订
+            const auditRevise = await ctx.service.reviseAudit.getAuditReviseByWap(ctx.session.sessionUser.accountId);
+            for (const revise of auditRevise) {
+                const yb_audit = await ctx.service.projectAccount.getAccountInfoById(revise.audit_id);
+                revise.yb_name = yb_audit.name;
+            }
+            // 获取待审批的预付款
+            const auditAdvance = await ctx.service.advanceAudit.getAuditAdvanceByWap(ctx.session.sessionUser.accountId);
             const renderData = {
                 auditStages,
                 auditChanges,
+                auditRevise,
+                auditAdvance,
                 changeConst,
+                advanceConst,
                 tpUnit: 2,
             };
             await ctx.render('wap/dashboard.ejs', renderData);
@@ -246,13 +258,32 @@ module.exports = app => {
                     c.curAuditor = await ctx.service.changeAudit.getLastUser(c.cid, c.times);
                 }
 
+                // 台账修订列表
+                const revises = await ctx.service.ledgerRevise.getReviseList(ctx.tender.id);
+                for (const lr of revises) {
+                    if (lr.valid) {
+                        lr.curAuditor = await ctx.service.reviseAudit.getAuditorByStatus(lr.id, lr.status, lr.times);
+                    }
+                }
+
+                // 预付款期数获取
+                const advanceList = [];
+                for (const t of advanceConst.typeCol) {
+                    const advance = await ctx.service.advance.getLastestAdvance(ctx.tender.id, t.type, true);
+                    advanceList.push(advance);
+                }
+
                 const renderData = {
                     tender,
                     stages,
                     changes,
+                    revises,
+                    advanceList,
                     auditConst: auditConst.stage,
                     auditChangeConst: auditConst.flow,
+                    auditReviseConst: auditConst.revise,
                     changeConst,
+                    advanceConst,
                     tpUnit: ctx.tender.info.decimal.tp,
                     monthProgress,
                     stagesEcharts: JSON.parse(JSON.stringify(stages)).reverse(),
@@ -342,6 +373,89 @@ module.exports = app => {
         }
 
         /**
+         * 修订审批详细页
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async revise(ctx) {
+            try {
+                const tender = ctx.tender.data;
+                const revise = await ctx.service.ledgerRevise.getDataByCondition({ id: ctx.params.rid });
+                revise.user = await ctx.service.projectAccount.getAccountInfoById(revise.uid);
+                const times = revise.status === auditConst.revise.status.checkNo ? revise.times - 1 : revise.times;
+                revise.curAuditor = await ctx.service.reviseAudit.getAuditorByStatus(revise.id, revise.status, times);
+                revise.auditors = await ctx.service.reviseAudit.getAuditors(revise.id, times);
+                console.log(times, revise.auditors);
+                const renderData = {
+                    tender,
+                    revise,
+                    auditConst: auditConst.revise,
+                };
+                await ctx.render('wap/shenpi_revise.ejs', renderData);
+            } catch (err) {
+                this.log(err);
+                ctx.redirect('/wap/list');
+            }
+        }
+
+        /**
+         * 预付款列表页
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        async advance(ctx) {
+            try {
+                const tender = ctx.tender.data;
+                const { decimal } = ctx.tender.info;
+                this.decimal = decimal.pay ? decimal.payTp : decimal.tp;
+                const advancePayTotalList = [];
+                const advanceList = [];
+                for (const t of advanceConst.typeCol) {
+                    const advancePayTotal = ctx.tender.info.deal_param[t.key + 'Advance'];
+                    advancePayTotalList.push(advancePayTotal);
+                    const advances = await ctx.service.advance.getAdvanceList(ctx.tender.id, t.type, this.decimal, advancePayTotal);
+                    advanceList.push(advances);
+                }
+                const renderData = {
+                    tender,
+                    advancePayTotalList,
+                    advanceList,
+                    auditConst: auditConst.advance,
+                    advanceConst,
+                };
+                await ctx.render('wap/shenpi_advance.ejs', renderData);
+            } catch (err) {
+                this.log(err);
+                ctx.redirect('/wap/list');
+            }
+        }
+
+        /**
+         * 预付款详情页 GET
+         * @param {Object} ctx 全局上下文
+         */
+        async advanceDetail(ctx) {
+            try {
+                const tender = ctx.tender.data;
+                ctx.advance.advancePayTotal = ctx.tender.info.deal_param[ advanceConst.typeCol[ctx.advance.type].key + 'Advance'];
+                // 获取审批流程中左边列表
+                ctx.advance.auditors2 = await ctx.service.advanceAudit.getAuditGroupByList(ctx.advance.id, ctx.advance.times);
+                const renderData = {
+                    tender,
+                    advance: ctx.advance,
+                    auditConst: auditConst.advance,
+                    advanceConst,
+                };
+                await ctx.render('wap/shenpi_advance_detail.ejs', renderData);
+            } catch (error) {
+                this.log(error);
+                ctx.redirect('/wap/tender/' + ctx.tender.id + '/advance');
+            }
+        }
+
+        /**
          * 变更令审批
          * @param {Object} ctx - egg全局变量
          * @return {void}

+ 0 - 165
app/extend/helper.js

@@ -1156,171 +1156,6 @@ module.exports = {
         return request.url.indexOf('/wap/') !== -1;
     },
 
-    getDefaultCheckResult() {
-        return {
-            error: [],
-            source: {
-                bills: [],
-                pos: [],
-            },
-        };
-    },
-
-    checkBillsWithPos(bills, pos, fields) {
-        const result = this.getDefaultCheckResult();
-        for (const b of bills) {
-            const pr = _.remove(pos, { lid: b.id });
-            const checkData = {},
-                calcData = {};
-            if (pr && pr.length > 0) {
-                for (const field of fields) {
-                    checkData[field] = b[field] ? b[field] : 0;
-                }
-                for (const p of pr) {
-                    for (const field of fields) {
-                        calcData[field] = this.add(calcData[field], p[field]);
-                    }
-                }
-                if (!_.isMatch(checkData, calcData)) {
-                    result.error.push({
-                        ledger_id: b.ledger_id,
-                        b_code: b.b_code,
-                        name: b.name,
-                        error: { checkData, calcData },
-                    });
-                    result.source.bills.push(b);
-                    for (const p of pr) {
-                        result.source.pos.push(p);
-                    }
-                }
-            }
-        }
-        return result;
-    },
-
-    checkBillsOverRange(bills, posRange, isTz) {
-        // if (isTz && posRange.length > 0) {
-        //     for (const p of posRange) {
-        //         const end_contract_qty = this.add(p.pre_contract_qty, p.contract_qty);
-        //         if (end_contract_qty > p.quantity) return true;
-        //     }
-        //     return false;
-        // } else {
-        //     const end_qc_qty = this.add(bills.qc_qty, bills.pre_qc_qty);
-        //     const end_qc_tp = this.add(bills.qc_tp, bills.pre_qc_tp);
-        //     const end_gather_qty = this.sum([bills.contract_qty, bills.pre_contract_qty, end_qc_qty]);
-        //     const end_gather_tp = this.sum([bills.contract_tp, bills.pre_contract_tp, end_qc_tp]);
-        //     if (isTz) {
-        //         if (end_gather_qty) {
-        //             return !bills.quantity || Math.abs(end_gather_qty) > Math.abs(this.add(bills.quantity, end_qc_qty));
-        //         } else if (end_gather_tp) {
-        //             return !bills.total_price || Math.abs(end_gather_tp) > Math.abs(this.add(bills.total_price, end_qc_tp));
-        //         }
-        //     } else {
-        //         if (end_gather_qty) {
-        //             return !bills.deal_qty || Math.abs(end_gather_qty) > Math.abs(this.add(bills.deal_qty, end_qc_qty));
-        //         } else if (end_gather_tp) {
-        //             return !bills.deal_tp || Math.abs(end_gather_tp) > Math.abs(this.add(bills.deal_tp, end_qc_tp));
-        //         }
-        //     }
-        // }
-        if (isTz && posRange.length > 0) {
-            if (posRange.length > 0) {
-                for (const p of posRange) {
-                    const end_contract_qty = this.add(p.pre_contract_qty, p.contract_qty);
-                    if (!p.quantity) return !!end_contract_qty;
-                    return p.quantity > 0
-                        ? end_contract_qty > p.quantity
-                        : end_contract_qty < p.quantity || end_contract_qty > 0;
-                }
-                return false;
-            }
-        } else {
-            const end_contract_qty = this.add(bills.contract_qty, bills.pre_contract_qty);
-            const end_contract_tp = this.add(bills.contract_tp, bills.pre_contract_tp);
-            if (bills.is_tp) {
-                const compare_tp = isTz ? bills.total_price : bills.deal_tp;
-                if (!compare_tp) return !!end_contract_tp;
-                return compare_tp >= 0 ? end_contract_tp > compare_tp : end_contract_tp < compare_tp || end_contract_tp > 0;
-            } else {
-                const compare_qty = isTz ? bills.quantity : bills.deal_qty;
-                if (!compare_qty) return !!end_contract_qty;
-                return compare_qty >= 0 ? end_contract_qty > compare_qty : end_contract_qty < compare_qty || end_contract_qty > 0;
-            }
-        }
-
-    },
-
-    checkBillsWithPos2(bills, pos, fields, checkOver, isTz) {
-        const result = this.getDefaultCheckResult(), overResult = this.getDefaultCheckResult();
-        for (const b of bills) {
-            let hasSource = false;
-            const pr = _.remove(pos, { lid: b.id });
-            const checkData = {},
-                calcData = {};
-            if (pr && pr.length > 0) {
-                for (const field of fields) {
-                    checkData[field] = b[field] ? b[field] : 0;
-                }
-                for (const p of pr) {
-                    for (const field of fields) {
-                        calcData[field] = this.add(calcData[field], p[field]);
-                    }
-                }
-                if (!_.isMatch(checkData, calcData)) {
-                    hasSource = true;
-                    result.error.push({
-                        ledger_id: b.ledger_id,
-                        b_code: b.b_code,
-                        name: b.name,
-                        error: { checkData, calcData },
-                    });
-                    result.source.bills.push(b);
-                    for (const p of pr) {
-                        result.source.pos.push(p);
-                    }
-                }
-            }
-            if (checkOver && this.checkBillsOverRange(b, pr, isTz)) {
-                overResult.error.push({
-                    ledger_id: b.ledger_id,
-                    b_code: b.b_code,
-                    name: b.name,
-                });
-                if (!hasSource) {
-                    overResult.source.bills.push(b);
-                    for (const p of pr) {
-                        overResult.source.pos.push(p);
-                    }
-                }
-            }
-        }
-        return [result, overResult];
-    },
-
-    checkBillsTp(bills, field, decimal) {
-        const result = this.getDefaultCheckResult();
-        for (const b of bills) {
-            if (!b.check_calc) continue;
-
-            const checkData = {}, calcData = {};
-            for (const f of field) {
-                checkData[f.tp] = b[f.tp] || 0;
-                calcData[f.tp] = this.mul(b.unit_price, b[f.qty], decimal.tp) || 0;
-            }
-            if (!this._.isMatch(checkData, calcData)) {
-                result.error.push({
-                    ledger_id: b.ledger_id,
-                    b_code: b.b_code,
-                    name: b.name,
-                    error: { checkData, calcData },
-                });
-                result.source.bills.push(b);
-            }
-        }
-        return result;
-    },
-
     check18MainCode(code) {
         return /^([0-9]([0-9][0-9])*)?(GD[0-9]{3}([0-9][0-9])*)?$/.test(code);
     },

+ 174 - 33
app/lib/ledger.js

@@ -573,10 +573,18 @@ class pos {
 }
 
 class checkData {
-    constructor(ctx) {
+    constructor(ctx, measureType) {
         this.ctx = ctx;
         this.checkBills = new billsTree(ctx, { id: 'ledger_id', pid: 'ledger_pid', order: 'order', level: 'level', rootId: -1 });
         this.checkPos = new pos({ id: 'id', ledgerId: 'lid' });
+        this.checkResult = {
+            error: [],
+            source: {
+                bills: [],
+                pos: [],
+            },
+        };
+        this.measureType = measureType;
     }
 
     _check3f(data, limit, ratio) {
@@ -587,7 +595,7 @@ class checkData {
             if (ratio === 0) {
                 if (!data.contract_tp && !data.pre_contract_tp) return 2; // 漏计
             } else {
-                const tp = this.ctx.helper.mul(data.total_price, ratio, this.ctx.tender.info.decimal.tp);
+                const tp = this.ctx.helper.mul(data.total_price, this.ctx.helper.div(ratio, 100, 4), this.ctx.tender.info.decimal.tp);
                 const checkTp = this.ctx.helper.add(data.contract_tp, data.pre_contract_tp);
                 if (tp > checkTp) return 1; // 违规
                 if (tp < checkTp) return 2; // 漏计
@@ -600,11 +608,11 @@ class checkData {
             if (data.contract_qty || data.qc_qty || data.pre_contract_qty || data.pre_qc_qty) return 1; // 违规
         }
         if (limit === 1) {
-            if (ratio === 0) {
+            if (!ratio || ratio === 0) {
                 if (!data.contract_qty && !data.qc_qty && !data.pre_contract_qty && !data.pre_qc_qty) return 2; // 漏计
             } else {
                 const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, unit);
-                const checkQty = this.ctx.helper.mul(data.quantity, ratio, precision.value);
+                const checkQty = this.ctx.helper.mul(data.quantity, this.ctx.helper.div(ratio, 100, 4), precision.value);
                 const qty = this.ctx.helper.add(data.contract_qty, data.pre_contract_qty);
                 if (qty > checkQty) return 1; // 违规
                 if (qty < checkQty) return 2; // 漏计
@@ -613,20 +621,36 @@ class checkData {
         return 0; // 合法
     }
 
-    _checkLeafBills3fLimit(checkType, bills, result, checkInfo) {
+    _getRatio(type, status) {
+        if (type === 'gxby') return null;
+        const gs = this.ctx.session.sessionProject.dagl_status.find(x => { return x.value === status });
+        return gs ? gs.ratio : null;
+    }
+
+
+    _getValid = function (type, status, limit) {
+        if (limit) {
+            const statusConst = type === 'gxby' ? this.ctx.session.sessionProject.gxby_status : this.ctx.session.sessionProject.dagl_status;
+            const sc = statusConst.find(x => { return x.value === status; });
+            return sc ? (sc.limit ? 1 : 0) : 0;
+        } else {
+            return -1;
+        }
+    };
+
+    _checkLeafBills3fLimit(checkType, bills, checkInfo) {
         const over = [], lost = [];
         const posRange = this.checkPos.getLedgerPos(bills.id);
         if (posRange && posRange.length > 0) {
             for (const p of posRange) {
                 const posCheckInfo = this.ctx.helper._.assign({}, checkInfo);
                 for (const ct of checkType) {
-                    if (p[ct + '_limit'] >= 0) {
+                    if (p[ct + '_limit'] > 0) {
                         posCheckInfo[ct + '_limit'] = p[ct + '_limit'];
-                        posCheckInfo[ct + '_ratio'] = p[ct + '_ratio'];
                     }
                 }
                 for (const ct of checkType) {
-                    const checkResult = this._check3fQty(p, posCheckInfo[ct + '_limit'], posCheckInfo[ct + '_ratio'], bills.unit);
+                    const checkResult = this._check3fQty(p, this._getValid(ct, p[ct + '_status'], posCheckInfo[ct + '_limit']), this._getRatio(ct, p[ct+'_status']), bills.unit);
                     if (checkResult === 1) {
                         if (over.indexOf(ct) === -1) over.push(ct);
                     }
@@ -638,8 +662,8 @@ class checkData {
         } else {
             for (const ct of checkType) {
                 const checkResult = bills.is_tp
-                    ? this._check3f(bills, checkInfo[ct + '_limit'], checkInfo[ct + '_ratio'])
-                    : this._check3fQty(bills, checkInfo[ct + '_limit'], checkInfo[ct + '_ratio'], bills.unit);
+                    ? this._check3f(bills, this._getValid(ct, bills[ct + '_status'], checkInfo[ct + '_limit']), this._getRatio(ct, bills[ct+'_status']))
+                    : this._check3fQty(bills, this._getValid(ct, bills[ct + '_status'], checkInfo[ct + '_limit']), this._getRatio(ct, bills[ct+'_status']), bills.unit);
                 if (checkResult === 1) {
                     if (over.indexOf(ct) === -1) over.push(ct);
                 }
@@ -650,7 +674,7 @@ class checkData {
         }
         if (over.length + lost.length > 0) {
             for (const o of over) {
-                result.error.push({
+                this.checkResult.error.push({
                     ledger_id: bills.ledger_id,
                     b_code: bills.b_code,
                     name: bills.name,
@@ -658,31 +682,32 @@ class checkData {
                 });
             }
             for (const l of lost) {
-                result.error.push({
+                this.checkResult.error.push({
                     ledger_id: bills.ledger_id,
                     b_code: bills.b_code,
                     name: bills.name,
                     errorType: 's2b_lost_' + l,
                 });
             }
-            result.source.bills.push(bills);
-            if (posRange && posRange.length > 0) result.source.pos.push(...posRange);
+            if (!this.checkResult.source.bills.find(x => {return x.ledger_id === b.ledger_id})) {
+                this.checkResult.source.bills.push(bills);
+                if (posRange && posRange.length > 0) this.checkResult.source.pos.push(...posRange);
+            }
         }
     }
-    _recursiveCheckBills3fLimit(checkType, bills, result, parentCheckInfo) {
+    _recursiveCheckBills3fLimit(checkType, bills, parentCheckInfo) {
         const checkInfo = this.ctx.helper._.assign({}, parentCheckInfo);
         for (const ct of checkType) {
-            if (bills[ct + '_limit'] >= 0) {
+            if (bills[ct + '_limit'] > 0) {
                 checkInfo[ct + '_limit'] = bills[ct + '_limit'];
-                checkInfo[ct + '_ratio'] = bills[ct + '_ratio'];
             }
         }
         if (bills.children && bills.children.length > 0) {
             for (const c of bills.children) {
-                this._recursiveCheckBills3fLimit(checkType, c, result, checkInfo);
+                this._recursiveCheckBills3fLimit(checkType, c, checkInfo);
             }
         } else {
-            this._checkLeafBills3fLimit(checkType, bills, result, checkInfo);
+            this._checkLeafBills3fLimit(checkType, bills, checkInfo);
         }
     }
 
@@ -692,7 +717,6 @@ class checkData {
     }
 
     checkSibling() {
-        const error = [];
         for (const node of this.checkBills.nodes) {
             if (!node.children || node.children.length === 0) continue;
             let hasXmj, hasGcl;
@@ -700,25 +724,23 @@ class checkData {
                 if (child.b_code) hasXmj = true;
                 if (!child.b_code) hasGcl = true;
             }
-            if (hasXmj && hasGcl) error.push({
+            if (hasXmj && hasGcl) this.checkResult.error.push({
                 ledger_id: node.ledger_id,
                 b_code: node.b_code,
                 name: node.name,
                 errorType: 'sibling',
             });
         }
-        return error;
     }
 
     checkSameCode() {
-        const error = [];
         let xmj = this.checkBills.nodes.filter(x => { return /^((GD*)|G)?[0-9]+/.test(x.code); });
         let check = null;
         while (xmj.length > 0) {
             [check, xmj] = this.ctx.helper._.partition(xmj, x => { return x.code === xmj[0].code; });
             if (check.length > 1) {
                 for (const c of check) {
-                    error.push({
+                    this.checkResult.error.push({
                         ledger_id: c.ledger_id,
                         b_code: c.b_code,
                         name: c.name,
@@ -727,24 +749,143 @@ class checkData {
                 }
             }
         }
-        return error;
     }
 
     check3fLimit(tender) {
-        const result = {
-            error: [],
-            source: {bills: [], pos: []},
-        };
-
         const check = [];
         if (tender.s2b_gxby_limit) check.push('gxby');
         if (tender.s2b_dagl_limit) check.push('dagl');
-        if (check.length === 0) return result;
+        if (check.length === 0) return;
 
         for (const b of this.checkBills.children) {
-            this._recursiveCheckBills3fLimit(check, b, result, {});
+            this._recursiveCheckBills3fLimit(check, b, {});
+        }
+    }
+    checkBillsQty(fields) {
+        for (const b of this.checkBills.nodes) {
+            if (b.children && b.children.length > 0) continue;
+            const pr = this.checkPos.getLedgerPos(b.id);
+            if (!pr || pr.length === 0) continue;
+            const checkData = {},
+                calcData = {};
+            for (const field of fields) {
+                checkData[field] = b[field] ? b[field] : 0;
+            }
+            for (const p of pr) {
+                for (const field of fields) {
+                    calcData[field] = this.ctx.helper.add(calcData[field], p[field]);
+                }
+            }
+            if (!this.ctx.helper._.isMatch(checkData, calcData)) {
+                this.checkResult.error.push({
+                    ledger_id: b.ledger_id,
+                    b_code: b.b_code,
+                    name: b.name,
+                    errorType: 'qty',
+                    error: { checkData, calcData },
+                });
+                if (!this.checkResult.source.bills.find(x => {return x.ledger_id === b.ledger_id})) {
+                    this.checkResult.source.bills.push(b);
+                    for (const p of pr) {
+                        this.checkResult.source.pos.push(p);
+                    }
+                }
+            }
+        }
+    }
+    checkBillsTp(field, decimal) {
+        for (const b of this.checkBills.nodes) {
+            if ((b.children && b.children.length > 0) || !b.check_calc) continue;
+
+            const checkData = {}, calcData = {};
+            for (const f of field) {
+                checkData[f.tp] = b[f.tp] || 0;
+                calcData[f.tp] = this.ctx.helper.mul(b.unit_price, b[f.qty], decimal.tp) || 0;
+            }
+            if (!this.ctx.helper._.isMatch(checkData, calcData)) {
+                this.checkResult.error.push({
+                    ledger_id: b.ledger_id,
+                    b_code: b.b_code,
+                    name: b.name,
+                    errorType: 'tp',
+                    error: { checkData, calcData },
+                });
+                if (!this.checkResult.source.bills.find(x => {return x.ledger_id === b.ledger_id})) {
+                    this.checkResult.source.bills.push(b);
+                }
+            }
+        }
+    }
+    _checkBillsOverRange(bills, posRange, isTz) {
+        // if (isTz && posRange.length > 0) {
+        //     for (const p of posRange) {
+        //         const end_contract_qty = this.add(p.pre_contract_qty, p.contract_qty);
+        //         if (end_contract_qty > p.quantity) return true;
+        //     }
+        //     return false;
+        // } else {
+        //     const end_qc_qty = this.add(bills.qc_qty, bills.pre_qc_qty);
+        //     const end_qc_tp = this.add(bills.qc_tp, bills.pre_qc_tp);
+        //     const end_gather_qty = this.sum([bills.contract_qty, bills.pre_contract_qty, end_qc_qty]);
+        //     const end_gather_tp = this.sum([bills.contract_tp, bills.pre_contract_tp, end_qc_tp]);
+        //     if (isTz) {
+        //         if (end_gather_qty) {
+        //             return !bills.quantity || Math.abs(end_gather_qty) > Math.abs(this.add(bills.quantity, end_qc_qty));
+        //         } else if (end_gather_tp) {
+        //             return !bills.total_price || Math.abs(end_gather_tp) > Math.abs(this.add(bills.total_price, end_qc_tp));
+        //         }
+        //     } else {
+        //         if (end_gather_qty) {
+        //             return !bills.deal_qty || Math.abs(end_gather_qty) > Math.abs(this.add(bills.deal_qty, end_qc_qty));
+        //         } else if (end_gather_tp) {
+        //             return !bills.deal_tp || Math.abs(end_gather_tp) > Math.abs(this.add(bills.deal_tp, end_qc_tp));
+        //         }
+        //     }
+        // }
+        if (isTz && posRange.length > 0) {
+            if (posRange.length > 0) {
+                for (const p of posRange) {
+                    const end_contract_qty = this.ctx.helper.add(p.pre_contract_qty, p.contract_qty);
+                    if (!p.quantity) return !!end_contract_qty;
+                    return p.quantity > 0
+                        ? end_contract_qty > p.quantity
+                        : end_contract_qty < p.quantity || end_contract_qty > 0;
+                }
+                return false;
+            }
+        } else {
+            const end_contract_qty = this.ctx.helper.add(bills.contract_qty, bills.pre_contract_qty);
+            const end_contract_tp = this.ctx.helper.add(bills.contract_tp, bills.pre_contract_tp);
+            if (bills.is_tp) {
+                const compare_tp = isTz ? bills.total_price : bills.deal_tp;
+                if (!compare_tp) return !!end_contract_tp;
+                return compare_tp >= 0 ? end_contract_tp > compare_tp : end_contract_tp < compare_tp || end_contract_tp > 0;
+            } else {
+                const compare_qty = isTz ? bills.quantity : bills.deal_qty;
+                if (!compare_qty) return !!end_contract_qty;
+                return compare_qty >= 0 ? end_contract_qty > compare_qty : end_contract_qty < compare_qty || end_contract_qty > 0;
+            }
+        }
+    }
+    checkOverRange() {
+        const isTz = this.ctx.tender.data.measure_type === this.measureType.tz.value;
+        for (const b of this.checkBills.nodes) {
+            if (b.children && b.children.length > 0) continue;
+            const pr = this.checkPos.getLedgerPos(b.id) || [];
+
+            if (this._checkBillsOverRange(b, pr, isTz)) {
+                this.checkResult.error.push({
+                    ledger_id: b.ledger_id,
+                    b_code: b.b_code,
+                    name: b.name,
+                    errorType: 'over',
+                });
+                if (!this.checkResult.source.bills.find(x => {return x.ledger_id === b.ledger_id})) {
+                    this.checkResult.source.bills.push(b);
+                    if (pr.length > 0) this.checkResult.source.pos.push(...pr);
+                }
+            }
         }
-        return result;
     }
 }
 

+ 151 - 25
app/lib/rptCustomData.js

@@ -8,6 +8,7 @@
  * @version
  */
 const auditConst = require('../const/audit');
+const Ledger = require('./ledger');
 
 /**
  * 季华项目 定制报表
@@ -228,28 +229,24 @@ class jhHelper {
         }
     }
 
-    async _loadStageBillsData(tender, stage, gsDefine, auditors) {
+    async _loadStageBillsData(tender, stage, gsDefine, auditors, filterGcl = true) {
         const helper = this.ctx.helper;
         // 加载截止上期/本期
         let billsData = await this.ctx.service.ledger.getData(tender.id);
-        billsData = billsData.filter(x => { return x.b_code && x.is_leaf });
+        if (filterGcl) billsData = billsData.filter(x => { return x.b_code && x.is_leaf });
         const curStage = await this.ctx.service.stageBills.getLastestStageData(tender.id, stage.id);
         const preStage = stage.order > 1 ? await this.ctx.service.stageBillsFinal.getFinalData(tender, stage.order - 1) : [];
         const loadData = [
-            { data: curStage, fields: ['qc_qty', 'qc_tp'], prefix: '', relaId: 'lid' },
-            { data: preStage, fields: ['qc_qty', 'qc_tp'], prefix: 'pre_', relaId: 'lid' }
+            { data: curStage, fields: this.billsQueryField, prefix: '', relaId: 'lid' },
+            { data: preStage, fields: this.billsQueryField, prefix: 'pre_', relaId: 'lid' }
         ];
         for (const dc of gsDefine.defaultCompare) {
             const auditor = auditors[dc];
+            if (!auditor) continue;
             const auditorStage = await this.ctx.service.stageBills.getAuditorStageData(tender.id, stage.id, auditor.times, auditor.order);
-            loadData.push({ data: auditorStage, fields: ['qc_qty', 'qc_tp'], prefix: `r${dc}_`, relaId: 'lid' });
+            loadData.push({ data: auditorStage, fields: this.billsQueryField, prefix: `r${dc}_`, relaId: 'lid' });
         }
         helper.assignRelaData(billsData, loadData);
-        // 计算截止本期
-        billsData.forEach(x => {
-            x.end_qc_qty = helper.add(x.qc_qty, x.pre_qc_qty);
-            x.end_qc_tp = helper.add(x.qc_tp, x.pre_qc_tp);
-        });
         return billsData;
     }
 
@@ -264,13 +261,11 @@ class jhHelper {
         ];
         for (const dc of gsDefine.defaultCompare) {
             const auditor = auditors[dc];
+            if (!auditor) continue;
             const auditorStage = await this.ctx.service.stagePos.getAuditorStageData2(tender.id, stage.id, auditor.times, auditor.order);
             loadData.push({ data: auditorStage, fields: ['qc_qty'], prefix: `r${dc}_`, relaId: 'pid' });
         }
         helper.assignRelaData(posData, loadData);
-        posData.forEach(x => {
-            x.end_qc_qty = helper.add(x.qc_qty, x.pre_qc_qty);
-        });
         return posData;
     }
 
@@ -287,7 +282,15 @@ class jhHelper {
             times: stage.curTimes, order: 0
         });
         const billsData = await this._loadStageBillsData(tender, stage, gsDefine, auditors);
+        // 计算截止本期
+        billsData.forEach(x => {
+            x.end_qc_qty = helper.add(x.qc_qty, x.pre_qc_qty);
+            x.end_qc_tp = helper.add(x.qc_tp, x.pre_qc_tp);
+        });
         const posData = await this._loadStagePosData(tender, stage, gsDefine, auditors);
+        posData.forEach(x => {
+            x.end_qc_qty = helper.add(x.qc_qty, x.pre_qc_qty);
+        });
         // 创建索引
         const billsIndex = {};
         for (const b of billsData) {
@@ -308,27 +311,111 @@ class jhHelper {
         this._loadChangeDetail(billsIndex, finalChangeData, gsDefine, 'pre_');
         this._generateResult(billsData, gsDefine, tender.info.decimal);
     }
+    async _gatherStageBillsData(tender, stage, gsDefine) {
+        if (!stage) return;
+        const helper = this.ctx.helper;
+
+        await this.ctx.service.stage.doCheckStage(stage);
+
+        const auditors = this.getLastestAuditors(stage.auditors);
+        const user = await this.ctx.service.projectAccount.getDataById(stage.user_id);
+        auditors.unshift({
+            aid: user.id, name: user.name, company: user.company, role: user.role,
+            times: stage.curTimes, order: 0
+        });
+        const billsData = await this._loadStageBillsData(tender, stage, gsDefine, auditors, false);
+        const billsTree = new Ledger.billsTree(this.ctx, {
+            id: 'ledger_id',
+            pid: 'ledger_pid',
+            order: 'order',
+            level: 'level',
+            rootId: -1,
+            keys: ['id', 'ledger_id'],
+            stageId: 'id',
+            calcFields: ['deal_tp', 'total_price', 'contract_tp', 'qc_tp', 'gather_tp', 'pre_contract_tp', 'pre_qc_tp', 'pre_gather_tp'],
+            calc: function (node) {
+                if (node.children && node.children.length === 0) {
+                    node.pre_gather_qty = helper.add(node.pre_contract_qty, node.pre_qc_qty);
+                    node.gather_qty = helper.add(node.contract_qty, node.qc_qty);
+                    node.end_contract_qty = helper.add(node.pre_contract_qty, node.contract_qty);
+                    node.end_qc_qty = helper.add(node.pre_qc_qty, node.qc_qty);
+                    node.end_gather_qty = helper.add(node.pre_gather_qty, node.gather_qty);
+                }
+                node.pre_gather_tp = helper.add(node.pre_contract_tp, node.pre_qc_tp);
+                node.gather_tp = helper.add(node.contract_tp, node.qc_tp);
+                node.end_contract_tp = helper.add(node.pre_contract_tp, node.contract_tp);
+                node.end_qc_tp = helper.add(node.pre_qc_tp, node.qc_tp);
+                node.end_gather_tp = helper.add(node.pre_gather_tp, node.gather_tp);
+                for (const dc of gsDefine.defaultCompare) {
+                    const prefix = `r${dc}_`;
+                    node[prefix + 'gather_qty'] = helper.add(node[prefix + 'contract_qty'], node[prefix + 'qc_qty']);
+                    node[prefix + 'gather_tp'] = helper.add(node[prefix + 'contract_tp'], node[prefix + 'qc_tp']);
+                }
+            }
+        });
+        billsTree.loadDatas(billsData);
+        billsTree.calculateAll();
+
+        this.resultTree.loadGatherTree(billsTree, function (gatherNode, sourceNode) {
+            gatherNode.s_qty = helper.add(gatherNode.s_qty, sourceNode.quantity);
+            gatherNode.s_tp = helper.add(gatherNode.s_tp, sourceNode.total_price);
 
-    async _gatherMonthData(tender, month, defaultCompare) {
+            gatherNode.s_dgn_qty1 = helper.add(gatherNode.s_dgn_qty1, sourceNode.dgn_qty1);
+            gatherNode.s_dgn_qty2 = helper.add(gatherNode.s_dgn_qty2, sourceNode.dgn_qty2);
+
+            gatherNode.s_contract_qty = helper.add(gatherNode.s_contract_qty, sourceNode.contract_qty);
+            gatherNode.s_contract_tp = helper.add(gatherNode.s_contract_tp, sourceNode.contract_tp);
+            gatherNode.s_qc_qty = helper.add(gatherNode.s_qc_qty, sourceNode.qc_qty);
+            gatherNode.s_qc_tp = helper.add(gatherNode.s_qc_tp, sourceNode.qc_tp);
+            gatherNode.s_gather_qty = helper.add(gatherNode.s_gather_qty, sourceNode.gather_qty);
+            gatherNode.s_gather_tp = helper.add(gatherNode.s_gather_tp, sourceNode.gather_tp);
+
+            gatherNode.s_pre_contract_qty = helper.add(gatherNode.s_pre_contract_qty, sourceNode.pre_contract_qty);
+            gatherNode.s_pre_contract_tp = helper.add(gatherNode.s_pre_contract_tp, sourceNode.pre_contract_tp);
+            gatherNode.s_pre_qc_qty = helper.add(gatherNode.s_pre_qc_qty, sourceNode.pre_qc_qty);
+            gatherNode.s_pre_qc_tp = helper.add(gatherNode.s_pre_qc_tp, sourceNode.pre_qc_tp);
+            gatherNode.s_pre_gather_qty = helper.add(gatherNode.s_pre_gather_qty, sourceNode.pre_gather_qty);
+            gatherNode.s_pre_gather_tp = helper.add(gatherNode.s_pre_gather_tp, sourceNode.pre_gather_tp);
+
+            gatherNode.s_end_contract_qty = helper.add(gatherNode.s_end_contract_qty, sourceNode.end_contract_qty);
+            gatherNode.s_end_contract_tp = helper.add(gatherNode.s_end_contract_tp, sourceNode.end_contract_tp);
+            gatherNode.s_end_qc_qty = helper.add(gatherNode.s_end_qc_qty, sourceNode.end_qc_qty);
+            gatherNode.s_end_qc_tp = helper.add(gatherNode.s_end_qc_tp, sourceNode.end_qc_tp);
+            gatherNode.s_end_gather_qty = helper.add(gatherNode.s_end_gather_qty, sourceNode.end_gather_qty);
+            gatherNode.s_end_gather_tp = helper.add(gatherNode.s_end_gather_tp, sourceNode.end_gather_tp);
+
+            for (const dc of gsDefine.defaultCompare) {
+                const prefix = `r${dc}_`;
+                gatherNode[prefix + 'contract_qty'] = helper.add(gatherNode[prefix + 'contract_qty'], sourceNode[prefix + 'contract_qty']);
+                gatherNode[prefix + 'contract_tp'] = helper.add(gatherNode[prefix + 'contract_tp'], sourceNode[prefix + 'contract_tp']);
+                gatherNode[prefix + 'qc_qty'] = helper.add(gatherNode[prefix + 'qc_qty'], sourceNode[prefix + 'qc_qty']);
+                gatherNode[prefix + 'qc_tp'] = helper.add(gatherNode[prefix + 'qc_tp'], sourceNode[prefix + 'qc_tp']);
+                gatherNode[prefix + 'gather_qty'] = helper.add(gatherNode[prefix + 'gather_qty'], sourceNode[prefix + 'gather_qty']);
+                gatherNode[prefix + 'gather_tp'] = helper.add(gatherNode[prefix + 'gather_tp'], sourceNode[prefix + 'gather_tp']);
+            }
+        });
+    }
+
+    async _gatherMonthData(tender, month, defaultCompare, fun) {
         const stages = await this._getValidStages(tender.id);
         const stage = this.ctx.helper._.find(stages, {s_time: month});
-        await this._gatherStageData(tender, stage, defaultCompare);
+        await fun.call(this, tender, stage, defaultCompare);
     }
 
-    async _gatherFinalData(tender, defaultCompare) {
+    async _gatherFinalData(tender, defaultCompare, fun) {
         const stages = await this._getValidStages(tender.id);
-        await this._gatherStageData(tender, stages[0], defaultCompare);
+        await fun.call(this, tender, stages[0], defaultCompare);
     }
 
-    async _gatherCheckedFinalData(tender, defaultCompare) {
+    async _gatherCheckedFinalData(tender, defaultCompare, fun) {
         const stages = await this._getCheckedStages(tender.id);
-        await this._gatherStageData(tender, stages[0], defaultCompare);
+        await fun.call(this, tender, stages[0], defaultCompare);
     }
 
-    async _gatherIndexData(tender, index, defaultCompare) {
+    async _gatherIndexData(tender, index, defaultCompare, fun) {
         const stages = await this._getValidStages(tender.id);
         const stage = this.ctx.helper._.find(stages, {order: index});
-        await this._gatherStageData(tender, stage, defaultCompare);
+        await fun.call(this, tender, stage, defaultCompare);
     }
 
     /**
@@ -339,6 +426,7 @@ class jhHelper {
      * @returns {Promise<Array>}
      */
     async gather(memFieldKeys, gsDefine, gsCustom) {
+        this.billsQueryField = ['qc_qty', 'qc_tp'];
         if (!gsDefine || !gsDefine.enable) return [];
         if (!gsCustom || !gsCustom.tenders || gsCustom.tenders.length === 0) return [];
 
@@ -349,16 +437,16 @@ class jhHelper {
 
             switch (gsSetting.type) {
                 case 'month':
-                    await this._gatherMonthData(tender, gsCustom.month, gsSetting);
+                    await this._gatherMonthData(tender, gsCustom.month, gsSetting, this._gatherStageData);
                     break;
                 case 'final':
-                    await this._gatherFinalData(tender, gsSetting);
+                    await this._gatherFinalData(tender, gsSetting, this._gatherStageData);
                     break;
                 case 'checked-final':
-                    await this._gatherCheckedFinalData(tender, gsSetting);
+                    await this._gatherCheckedFinalData(tender, gsSetting, this._gatherStageData);
                     break;
                 case 'stage':
-                    await this._gatherIndexData(tender, gsCustom.stage, gsSetting);
+                    await this._gatherIndexData(tender, gsCustom.stage, gsSetting, this._gatherStageData);
                     break;
                 default: throw '未知汇总类型';
             }
@@ -370,6 +458,7 @@ class jhHelper {
     }
 
     async convert(tid, sid, memFieldKeys, option) {
+        this.billsQueryField = ['qc_qty', 'qc_tp'];
         if (!option) return [];
         const setting = JSON.parse(option);
         if (!setting || !setting.defaultCompare) return [];
@@ -381,6 +470,43 @@ class jhHelper {
         this.result.sort((x, y) => { return helper.compareCode(x.b_code, y.b_code); });
         return this.result;
     }
+
+    async gatherBills(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.defaultCompare) return [];
+        this.billsQueryField = ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'];
+        this.resultTree = new Ledger.gatherTree(this.ctx, {
+            id: 'id',
+            pid: 'pid',
+            order: 'order',
+            level: 'level',
+            rootId: -1
+        });
+        for (const t of gsCustom.tenders) {
+            const tender = await this.ctx.service.tender.getCheckTender(t.tid);
+
+            switch (gsSetting.type) {
+                case 'month':
+                    await this._gatherMonthData(tender, gsCustom.month, gsSetting, this._gatherStageBillsData);
+                    break;
+                case 'final':
+                    await this._gatherFinalData(tender, gsSetting, this._gatherStageBillsData);
+                    break;
+                case 'checked-final':
+                    await this._gatherCheckedFinalData(tender, gsSetting, this._gatherStageBillsData);
+                    break;
+                case 'stage':
+                    await this._gatherIndexData(tender, gsCustom.stage, gsSetting, this._gatherStageBillsData);
+                    break;
+                default: throw '未知汇总类型';
+            }
+        }
+        this.resultTree.generateSortNodes();
+        return this.resultTree.getDefaultDatas();
+    }
 }
 
 module.exports = {

+ 3 - 3
app/lib/stage_im.js

@@ -319,11 +319,11 @@ class StageIm {
                 (!im.pid || im.pid === d.pid) &&
                 (!im.pos_name || im.pos_name === d.pos_name);
         });
-        if (im.code === '101-1-b') console.log(im, cd);
         if (cd) {
-            im.custom_define = cd.custom_define ? cd.custom_define.split(',') : this.imFields;
+            im.custom_define = im.custom_define !== null
+                ? (cd.custom_define ? cd.custom_define.split(',') : [])
+                : this.imFields;
             this._.assignInWith(im, cd, function(oV, sV, key) {
-                if (key === 'calc_memo') console.log(im.code, sV);
                 return im.custom_define.indexOf(key) > -1 ? sV : oV;
             });
             if (im.code === '101-1-b') console.log(im.calc_memo);

+ 7 - 3
app/lib/wechat.js

@@ -36,7 +36,8 @@ class WX {
         try {
             // const templateId = template;
             let templateId = '';
-            const sck = 'https://scn.ink/';
+            // const sck = 'https://scn.ink/';
+            const sck = '';
             for (const openid of wx_openid) {
                 let url = '';
                 let msgData = '';
@@ -113,7 +114,8 @@ class WX {
                         break;
                     case wxConst.template.revise:
                         templateId = wxConst.templateId.revise;
-                        remark = data.status === wxConst.status.check ? '微信暂无法在线审批' :
+                        url = this.ctx.protocol + '://' + this.ctx.host + '/wx/url2wap?project=' + data.code + '&url=' + sck + data.wap_url;
+                        remark = data.status === wxConst.status.check ? '微信可快速审批,如需进行详细审批' :
                             (data.status === wxConst.status.success ? '审批已通过,查看审批结果' :
                                 (data.status === wxConst.status.back ? '审批被退回,查看退回结果' : '审批已上报,查看审批结果'));
                         msgData = {
@@ -136,6 +138,7 @@ class WX {
                         break;
                     case wxConst.template.material:
                         templateId = wxConst.templateId.material;
+                        url = this.ctx.protocol + '://' + this.ctx.host + '/wx/url2wap?project=' + data.code + '&url=' + sck + data.wap_url;
                         remark = data.status === wxConst.status.check ? '微信暂无法在线审批' :
                             (data.status === wxConst.status.success ? '审批已通过,查看审批结果' : '审批被退回,查看退回结果');
                         msgData = {
@@ -164,7 +167,8 @@ class WX {
                         break;
                     case wxConst.template.advance:
                         templateId = wxConst.templateId.advance;
-                        remark = data.status === wxConst.status.check ? '微信暂无法在线审批' :
+                        url = this.ctx.protocol + '://' + this.ctx.host + '/wx/url2wap?project=' + data.code + '&url=' + sck + data.wap_url;
+                        remark = data.status === wxConst.status.check ? '微信可快速审批,如需进行详细审批' :
                             (data.status === wxConst.status.success ? '审批已通过,查看审批结果' : '审批被退回,查看退回结果');
                         msgData = {
                             first: {

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

@@ -416,6 +416,10 @@ $(document).ready(() => {
                 return;
             });
         },
+        valueChanged(e, info) {
+            // 防止ctrl+z撤销数据
+            SpreadJsObj.reLoadRowData(info.sheet, info.row);
+        }
     };
 
     const preUrl = window.location.pathname.split('/').slice(0, 4).join('/');
@@ -520,6 +524,7 @@ $(document).ready(() => {
         changeSpread.bind(spreadNS.Events.EditEnded, changeSpreadObj.editEnded);
         changeSpread.bind(spreadNS.Events.SelectionChanged, changeSpreadObj.selectionChanged);
         changeSpread.bind(spreadNS.Events.ClipboardPasted, changeSpreadObj.clipboardPasted);
+        changeSpread.bind(spreadNS.Events.ValueChanged, changeSpreadObj.valueChanged);
         SpreadJsObj.addDeleteBind(changeSpread, changeSpreadObj.deletePress);
         changeSpreadSheet.getCell(-1, 10).foreColor('#dc3545');
 

+ 24 - 11
app/public/js/ledger_check.js

@@ -144,6 +144,20 @@ const ledgerCheckUtil = {
             }
             return list.other;
         };
+        const getRatio = function (type, status) {
+            if (type === 'gxby') return null;
+            const gs = option.status.dagl.find(x => { return x.value === status });
+            return gs ? gs.ratio : null;
+        };
+        const getValid = function (type, status, limit) {
+            if (limit) {
+                const statusConst = type === 'gxby' ? option.status.gxby : option.status.dagl;
+                const sc = statusConst.find(x => { return x.value === status; });
+                return sc ? (sc.limit ? 1 : 0) : 0;
+            } else {
+                return -1;
+            }
+        };
         const check3f = function (data, limit, ratio) {
             if (limit === 0) {
                 if (data.contract_tp || data.pre_contract_tp) return 1; // 违规
@@ -152,7 +166,7 @@ const ledgerCheckUtil = {
                 if (ratio === 0) {
                     if (!data.contract_tp && !data.pre_contract_tp) return 2; // 漏计
                 } else {
-                    const tp = ZhCalc.mul(data.total_price, ratio, this.ctx.tender.info.decimal.tp);
+                    const tp = ZhCalc.mul(data.total_price, ZhCalc.div(ratio, 100, 4), this.ctx.tender.info.decimal.tp);
                     const checkTp = ZhCalc.add(data.contract_tp, data.pre_contract_tp);
                     if (tp > checkTp) return 1; // 违规
                     if (tp < checkTp) return 2; // 漏计
@@ -165,12 +179,12 @@ const ledgerCheckUtil = {
                 if (data.contract_qty || data.qc_qty || data.pre_contract_qty || data.pre_qc_qty) return 1; // 违规
             }
             if (limit === 1) {
-                if (ratio <= 0) {
+                if (!ratio || ratio === 0) {
                     if (!data.contract_qty && !data.qc_qty && !data.pre_contract_qty && !data.pre_qc_qty) return 2; // 漏计
                 } else {
                     const precision = findPrecision(tenderInfo.precision, unit);
-                    const checkQty = ZhCalc.mul(data.quantity, ratio, precision.value);
-                    const qty = ZhCalc.add(data.contract_qty, data.pre_contract_qty);
+                    const checkQty = ZhCalc.mul(data.quantity, ZhCalc.div(ratio, 100, 4), precision.value);
+                    const qty = ZhCalc.add(data.contract_qty, data.pre_contract_qty) || 0;
                     if (qty > checkQty) return 1; // 违规
                     if (qty < checkQty) return 2; // 漏计
                 }
@@ -184,13 +198,13 @@ const ledgerCheckUtil = {
                 for (const p of posRange) {
                     const posCheckInfo = _.assign({}, checkInfo);
                     for (const ct of option.checkType) {
-                        if (p[ct + '_limit'] >= 0) {
+                        if (p[ct + '_limit'] > 0) {
                             posCheckInfo[ct + '_limit'] = p[ct + '_limit'];
-                            posCheckInfo[ct + '_ratio'] = p[ct + '_ratio'];
                         }
                     }
                     for (const ct of option.checkType) {
-                        const checkResult = check3fQty(p, posCheckInfo[ct + '_limit'], posCheckInfo[ct + '_ratio'], bills.unit);
+                        const checkResult = check3fQty(p, getValid(ct, p[ct + '_status'], posCheckInfo[ct + '_limit']),
+                            getRatio(ct, p[ct + '_status']), bills.unit);
                         if (checkResult === 1) {
                             if (over.indexOf(ct) === -1) over.push(ct);
                         }
@@ -202,8 +216,8 @@ const ledgerCheckUtil = {
             } else {
                 for (const ct of option.checkType) {
                     const checkResult = bills.is_tp
-                        ? check3f(bills, checkInfo[ct + '_limit'], checkInfo[ct + '_ratio'])
-                        : check3fQty(bills, checkInfo[ct + '_limit'], checkInfo[ct + '_ratio'], bills.unit);
+                        ? check3f(bills, getValid(ct, bills[ct + '_status'], checkInfo[ct + '_limit']), getRatio(ct, bills[ct + '_status']))
+                        : check3fQty(bills, getValid(ct, bills[ct + '_status'], checkInfo[ct + '_limit']), getRatio(ct, bills[ct + '_status']), bills.unit);
                     if (checkResult === 1) {
                         if (over.indexOf(ct) === -1) over.push(ct);
                     }
@@ -221,9 +235,8 @@ const ledgerCheckUtil = {
         const recursiveCheckBills3fLimit = function (bills, parentCheckInfo) {
             const checkInfo = _.assign({}, parentCheckInfo);
             for (const ct of option.checkType) {
-                if (bills[ct + '_limit'] >= 0) {
+                if (bills[ct + '_limit'] > 0) {
                     checkInfo[ct + '_limit'] = bills[ct + '_limit'];
-                    checkInfo[ct + '_ratio'] = bills[ct + '_ratio'];
                 }
             }
             if (bills.children && bills.children.length > 0) {

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

@@ -43,7 +43,7 @@ const showSideTools = function (show) {
 
 const showSelectTab = function(select, spread, afterShow) {
     const tab = $(select), tabPanel = $(tab.attr('content'));
-    $('a', '#side-menu').removeClass('active');
+    $('a', '.side-menu').removeClass('active');
     tab.addClass('active');
     $('.tab-content .tab-pane').removeClass('active');
     tabPanel.addClass('active');
@@ -156,7 +156,7 @@ const showSelectTab = function(select, spread, afterShow) {
             };
             const showErrorList = function () {
                 const tab = $(setting.tabSelector), tabPanel = $(tab.attr('content'));
-                $('a', '#side-menu').removeClass('active');
+                $('a', '.side-menu').removeClass('active');
                 tab.addClass('active');
                 $('.tab-content .tab-pane').removeClass('active');
                 tabPanel.addClass('active');
@@ -307,7 +307,7 @@ const showSelectTab = function(select, spread, afterShow) {
             const hideCheckData = function () {
                 const tab = $(setting.tabSelector), tabPanel = $(tab.attr('content'));
                 if (tab.hasClass('active')) {
-                    $('a', '#side-menu').removeClass('active');
+                    $('a', '.side-menu').removeClass('active');
                     tab.addClass('active');
                     $('.tab-content .tab-pane').removeClass('active');
                     tabPanel.addClass('active');
@@ -335,7 +335,7 @@ const showSelectTab = function(select, spread, afterShow) {
             };
             const showCheckList = function () {
                 const tab = $(setting.tabSelector), tabPanel = $(tab.attr('content'));
-                $('a', '#side-menu').removeClass('active');
+                $('a', '.side-menu').removeClass('active');
                 tab.addClass('active');
                 $('.tab-content .tab-pane').removeClass('active');
                 tabPanel.addClass('active');

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

@@ -242,7 +242,7 @@ $(document).ready(() => {
             enable: 1, isTz: checkTzMeasureType(),
         },
         limit3f: {
-            enable: 1, checkType: [],
+            enable: 1, checkType: [], status: thirdParty,
         }
     };
     if (tender.s2b_gxby_check) checkOption.limit3f.checkType.push('gxby');
@@ -632,12 +632,6 @@ $(document).ready(() => {
     // 初始化 台账 spread
     const slSpread = SpreadJsObj.createNewSpread($('#stage-ledger')[0]);
     customizeStageTreeSetting(ledgerSpreadSetting, customColDisplay());
-    ledgerSpreadSetting.cols.push(
-        {title: '工序限制', colSpan: '1', rowSpan: '2', field: 'gxby_limit', hAlign: 0, width: 80, readOnly: true},
-    );
-    posSpreadSetting.cols.push(
-        {title: '工序限制', colSpan: '1', rowSpan: '2', field: 'gxby_limit', hAlign: 0, width: 80, readOnly: true},
-    );
     // 数量变更列,添加按钮
     const qcCol = _.find(ledgerSpreadSetting.cols, {field: 'qc_qty'});
     qcCol.readOnly = true;

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

@@ -345,6 +345,8 @@ $(document).ready(() => {
             headerFont: 'bold 10px 微软雅黑',
             font: '10px 微软雅黑'
         };
+        if (gxby) setting.cols.push({title: '工序报验', colSpan: '1', rowSpan: '2', field: 'gxby', hAlign: 1, width: 80, formatter: '@'});
+        if (dagl) setting.cols.push({title: '档案管理', colSpan: '1', rowSpan: '2', field: 'dagl', hAlign: 1, width: 80, formatter: '@'});
         if (!xmjSheet.zh_tree) return;
         for (const node of xmjSheet.zh_tree.nodes) {
             data.push({
@@ -353,7 +355,7 @@ $(document).ready(() => {
                 contract_tp: node.contract_tp, qc_tp: node.qc_tp, gather_tp: node.gather_tp,
                 end_contract_tp: node.end_contract_tp, end_qc_tp: node.end_qc_tp, end_gather_tp: node.end_gather_tp,
                 end_gather_percent: node.end_gather_percent,
-                drawing_code: node.drawing_code, postil: node.postil, memo: node.memo
+                drawing_code: node.drawing_code, postil: node.postil, memo: node.memo, gxby: getGxbyText(node), dagl: getDaglText(node),
             });
             if (node.unitTree) {
                 for (const unitNode of node.unitTree.nodes) {
@@ -368,7 +370,8 @@ $(document).ready(() => {
                         end_qc_qty: unitNode.end_qc_qty, end_qc_tp: unitNode.end_qc_tp,
                         end_gather_qty: unitNode.end_gather_qty, end_gather_tp: unitNode.end_gather_tp,
                         end_gather_percent: unitNode.end_gather_percent,
-                        drawing_code: unitNode.drawing_code_merge, postil: unitNode.postil_merge, memo: unitNode.memo_merge
+                        drawing_code: unitNode.drawing_code_merge, postil: unitNode.postil_merge, memo: unitNode.memo_merge,
+                        gxby: getGxbyText(unitNode), dagl: getDaglText(unitNode),
                     });
                 }
             }

+ 93 - 27
app/public/report/js/rpt_main.js

@@ -596,16 +596,28 @@ let rptControlObj = {
             if (chkNodes.length > 0) {
                 delete params.orientation; // 打印时有勾选的话,不需要提供方向
             }
+            $.bootstrapLoading.start();
             CommonAjax.postXsrfEx("/tender/report_api/createExcelFilesInOneBook", params, WAIT_TIME_EXPORT, true, getCookie('csrfToken_j'), function(result){
-                    if (result) {
-                        let uuIdUrls = [];
-                        let uuIdUrl =  "/getFileByUUID/" + result.data[0].uuid + "/" + stringUtil.replaceAll(result.data[0].reportName, "#", "_") + "/xlsx";
-                        uuIdUrls.push(uuIdUrl);
-                        downloadReport(uuIdUrls);
-                    } else {
-                        //
-                    }
-                }, null, null
+                $.bootstrapLoading.end();
+                if (result) {
+                    let uuIdUrls = [];
+                    let uuIdUrl =  "/getFileByUUID/" + result.data[0].uuid + "/" + stringUtil.replaceAll(result.data[0].reportName, "#", "_") + "/xlsx";
+                    uuIdUrls.push(uuIdUrl);
+                    downloadReport(uuIdUrls);
+                } else {
+                    //
+                }
+                },
+                function(failRst){
+                    // closeWaitingView();
+                    $.bootstrapLoading.end();
+                    console.log(failRst);
+                },
+                function(exceptionRst){
+                    // closeWaitingView();
+                    $.bootstrapLoading.end();
+                    console.log(exceptionRst);
+                }
             );
         }
     },
@@ -627,19 +639,30 @@ let rptControlObj = {
             if (chkNodes.length > 0) {
                 delete params.orientation; // 打印时有勾选的话,不需要提供方向
             }
-
+            $.bootstrapLoading.start();
             CommonAjax.postXsrfEx("/tender/report_api/createExcelFiles", params, WAIT_TIME_EXPORT, true, getCookie('csrfToken_j'), function(result){
-                    if (result) {
-                        let uuIdUrls = [];
-                        for (let uuIdObj of result.data) {
-                            let uuIdUrl =  "/getFileByUUID/" + uuIdObj.uuid + "/" + stringUtil.replaceAll(uuIdObj.reportName, "#", "_") + "/xlsx";
-                            uuIdUrls.push(uuIdUrl);
-                        }
-                        downloadReport(uuIdUrls);
-                    } else {
-                        //
+                $.bootstrapLoading.end();
+                if (result) {
+                    let uuIdUrls = [];
+                    for (let uuIdObj of result.data) {
+                        let uuIdUrl =  "/getFileByUUID/" + uuIdObj.uuid + "/" + stringUtil.replaceAll(uuIdObj.reportName, "#", "_") + "/xlsx";
+                        uuIdUrls.push(uuIdUrl);
                     }
-                }, null, null
+                    downloadReport(uuIdUrls);
+                } else {
+                    //
+                }
+            },
+            function(failRst){
+                // closeWaitingView();
+                $.bootstrapLoading.end();
+                console.log(failRst);
+            },
+            function(exceptionRst){
+                // closeWaitingView();
+                $.bootstrapLoading.end();
+                console.log(exceptionRst);
+            }
             );
         }
     },
@@ -888,8 +911,44 @@ let rptControlObj = {
 
 function downloadPDFReport(pageDataArr, pageSize, rpt_names, signatureRelArr, signatureRelInfo, refRptTplIds, STAGE_AUDIT) {
     rptControlObj.currentDownloadIdx = 0;
-    const private_download = function() {
-        if (rptControlObj.currentDownloadIdx < pageDataArr.length) {
+    const _resetPageDataByBreaks = function(breakAmt, newRptNames) {
+        let rst = [];
+        for (let pi = 0; pi < pageDataArr.length; pi++) {
+            let pageItem = pageDataArr[pi];
+            let currentRptName = rpt_names[pi];
+            if (pageItem.items.length > breakAmt) {
+                let pa = Math.floor(pageItem.items.length / breakAmt);
+                if (pageItem.items.length % breakAmt > 0) {
+                    pa++;
+                }
+                for (let idx = 0; idx < pa; idx++) {
+                    let newPageDataObj = {items: []};
+                    // newPageDataObj[JV.NODE_PAGE_INFO] = JSON.parse(JSON.stringify(pageItem[JV.NODE_PAGE_INFO]));
+                    newPageDataObj[JV.NODE_PAGE_INFO] = pageItem[JV.NODE_PAGE_INFO];
+                    // newPageDataObj[JV.BAND_PROP_MERGE_BAND] = JSON.parse(JSON.stringify(pageItem[JV.BAND_PROP_MERGE_BAND]));
+                    newPageDataObj[JV.BAND_PROP_MERGE_BAND] = pageItem[JV.BAND_PROP_MERGE_BAND];
+
+                    newPageDataObj[JV.NODE_FONT_COLLECTION] = pageItem[JV.NODE_FONT_COLLECTION];
+                    newPageDataObj[JV.NODE_STYLE_COLLECTION] = pageItem[JV.NODE_STYLE_COLLECTION];
+                    newPageDataObj[JV.NODE_CONTROL_COLLECTION] = pageItem[JV.NODE_CONTROL_COLLECTION];
+
+                    for ( let dIdx = idx * breakAmt; dIdx < (Math.min( (idx + 1) * breakAmt, pageItem.items.length)); dIdx++) {
+                        // newPageDataObj.items.push(JSON.parse(JSON.stringify( pageItem.items[dIdx] )));
+                        newPageDataObj.items.push(pageItem.items[dIdx]);
+                    }
+                    rst.push(newPageDataObj);
+                    newRptNames.push(currentRptName + '_' + (idx + 1));
+                }
+            } else {
+                rst.push(pageItem);
+                newRptNames.push(currentRptName);
+            }
+        }
+        return rst;
+    };
+
+    const private_download = function(newPageDataArr, new_rpt_rames) {
+        if (rptControlObj.currentDownloadIdx < newPageDataArr.length) {
             let singleSignatureRelArr = [];
             for (let rIdx = 0; rIdx < signatureRelInfo.length; rIdx++) {
                 // for (const rptId of refRptTplIds) {
@@ -908,14 +967,21 @@ function downloadPDFReport(pageDataArr, pageSize, rpt_names, signatureRelArr, si
                 //     break;
                 // }
             }
-            let pageData = pageDataArr[rptControlObj.currentDownloadIdx];
-            let rptName = rpt_names[rptControlObj.currentDownloadIdx];
+            let pageData = newPageDataArr[rptControlObj.currentDownloadIdx];
+            let rptName = new_rpt_rames[rptControlObj.currentDownloadIdx];
             rptControlObj.currentDownloadIdx++;
             JpcJsPDFHelper.outputAsPdf(pageData, pageSize, rptName, singleSignatureRelArr, STAGE_AUDIT); // 精确控制签名
-            if (rptControlObj.currentDownloadIdx < pageDataArr.length) setTimeout(private_download, 2000);
+            if (rptControlObj.currentDownloadIdx < newPageDataArr.length) setTimeout(private_download(newPageDataArr, new_rpt_rames), 2000);
         }
-    }
-    private_download();
+    };
+    /*
+    // 这里控制导出PDF的页码数量(如果有设置的话)
+    let newRptNames = []; //这个为导出PDF控制分页用
+    let newPageDataRst = _resetPageDataByBreaks(10, newRptNames);
+    private_download(newPageDataRst, newRptNames);
+    /*/
+    private_download(pageDataArr, rpt_names);
+    //*/
 }
 
 function downloadReport(urls) {

+ 2 - 0
app/public/report/js/rpt_preview_common.js

@@ -6,6 +6,7 @@ let G_OFFSET_X = 0, G_OFFSET_Y = 0;
 let STAGE_AUDIT = []; //注意这个,与rpt_main.js不要混了
 let STAGE_LIST = [];
 let STAGE_AUDIT_ORG = [];
+let current_stage_id = -1;
 // 设置Date对象Format函数
 // -- 打印预览需要重新设置一遍 ------------------------------------------------
 Date.prototype.Format = function(fmt) {
@@ -32,6 +33,7 @@ function printPageLoading() {
     let refRptTplIds = JSON.parse(sessionStorage.refRptTplIds);
     STAGE_LIST = JSON.parse(sessionStorage.STAGE_LIST);
     STAGE_AUDIT_ORG = JSON.parse(sessionStorage.STAGE_AUDIT_ORG);
+    current_stage_id = parseInt(sessionStorage.current_stage_id);
     let scaleFactor = 1;
     CommonAjax.postXsrfEx("/tender/report_api/getMultiReports", params, 60000, true, getCookie('csrfToken_j'),
         function(result){

+ 1 - 0
app/public/report/js/rpt_print.js

@@ -27,6 +27,7 @@ let rptPrintHelper = {
             sessionStorage.refRptTplIds = JSON.stringify(refRptTplIds);
             sessionStorage.STAGE_LIST = JSON.stringify(STAGE_LIST);
             sessionStorage.STAGE_AUDIT_ORG = JSON.stringify(STAGE_AUDIT_ORG);
+            sessionStorage.current_stage_id = getStageId();
             // sessionStorage.STAGE_AUDIT = JSON.stringify(STAGE_AUDIT);
             if (sessionStorage.pageSize === 'A3') {
                 window.open('/printReport/A3');

+ 5 - 0
app/router.js

@@ -91,6 +91,7 @@ module.exports = app => {
     // 接口设置
     app.get('/setting/api', sessionAuth, 'settingController.s2b');
     app.post('/setting/api/update', sessionAuth, 'settingController.s2bUpdate');
+    app.post('/setting/api/update-status', sessionAuth, 'settingController.s2bUpdateStatus');
 
 
     // 项目相关
@@ -122,6 +123,7 @@ module.exports = app => {
     app.get('/tender/:id', sessionAuth, tenderCheck, 'tenderController.tenderInfo');
     app.get('/tender/:id/type', sessionAuth, 'tenderController.tenderType');
     app.post('/tender/:id/save', sessionAuth, tenderCheck, 'tenderController.saveTenderInfo');
+    app.post('/tender/:id/save2', sessionAuth, tenderCheck, 'tenderController.saveTenderInfo2');
     app.post('/tender/rule', sessionAuth, 'tenderController.rule');
     app.post('/tender/:id/rule/first', sessionAuth, tenderCheck, 'tenderController.ruleFirst');
     app.get('/tender/:id/shenpi', sessionAuth, tenderCheck, 'tenderController.shenpiSet');
@@ -448,6 +450,9 @@ module.exports = app => {
     app.get('/wap/tender/:id/stage/:order', sessionAuth, tenderCheck, uncheckTenderCheck, 'wapController.stage');
     app.get('/wap/tender/:id/change/:cid/info', sessionAuth, tenderCheck, uncheckTenderCheck, 'wapController.change');
     app.post('/wap/tender/:id/change/approval', sessionAuth, tenderCheck, uncheckTenderCheck, 'wapController.changeApproval');
+    app.get('/wap/tender/:id/revise/:rid/info', sessionAuth, tenderCheck, uncheckTenderCheck, 'wapController.revise');
+    app.get('/wap/tender/:id/advance', sessionAuth, tenderCheck, uncheckTenderCheck, 'wapController.advance');
+    app.get('/wap/tender/:id/advance/:order/detail', sessionAuth, tenderCheck, uncheckTenderCheck, advanceCheck, 'wapController.advanceDetail');
 
     // 微信
     app.get('/wx', 'wechatController.index');

+ 55 - 5
app/service/advance_audit.js

@@ -5,6 +5,7 @@ const shenpiConst = require('../const/shenpi');
 const pushType = require('../const/audit').pushType;
 const smsTypeConst = require('../const/sms_type');
 const wxConst = require('../const/wechat_template.js');
+const advanceConst = require('../const/advance');
 module.exports = app => {
     class AdvanceAudit extends app.BaseService {
         constructor(ctx) {
@@ -234,11 +235,16 @@ module.exports = app => {
 
                 // 微信模板通知
                 const advanceInfo = await this.ctx.service.advance.getDataById(vid);
+                const shenpiUrl = await this.ctx.helper.urlToShort(
+                    this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + advanceInfo.tid + '/advance/' + advanceInfo.id + '/detail'
+                );
                 const wechatData = {
-                    qi: advanceInfo.type === 0 ? '开工预付款第' + advanceInfo.order + '期' : '材料预付款第' + advanceInfo.order + '期',
+                    wap_url: shenpiUrl,
+                    qi: advanceConst.typeCol[advanceInfo.type].name + '第' + advanceInfo.order + '期',
                     status: wxConst.status.check,
                     tips: wxConst.tips.check,
                     tp: parseFloat(advanceInfo.cur_amount),
+                    code: this.ctx.session.sessionProject.code,
                 };
                 await this.ctx.helper.sendWechat(audit.audit_id, smsTypeConst.const.YFK, smsTypeConst.judge.approval.toString(), wxConst.template.advance, wechatData);
                 await transaction.commit();
@@ -279,6 +285,9 @@ module.exports = app => {
                 // 无下一审核人表示,审核结束
 
                 const advanceInfo = await this.ctx.service.advance.getDataById(advanceId);
+                const shenpiUrl = await this.ctx.helper.urlToShort(
+                    this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + advanceInfo.tid + '/advance/' + advanceInfo.id + '/detail'
+                );
                 if (nextAudit) {
                     // 流程至下一审批人
                     await transaction.update(this.tableName, { id: nextAudit.id, status: auditConst.status.checking, create_time: time });
@@ -289,11 +298,14 @@ module.exports = app => {
                         status: auditConst.status.checking,
                     });
                     // 微信模板通知
+
                     const wechatData = {
-                        qi: advanceInfo.type === 0 ? '开工预付款第' + advanceInfo.order + '期' : '材料预付款第' + advanceInfo.order + '期',
+                        wap_url: shenpiUrl,
+                        qi: advanceConst.typeCol[advanceInfo.type].name + '第' + advanceInfo.order + '期',
                         status: wxConst.status.check,
                         tips: wxConst.tips.check,
                         tp: parseFloat(advanceInfo.cur_amount),
+                        code: this.ctx.session.sessionProject.code,
                     };
                     await this.ctx.helper.sendWechat(nextAudit.audit_id, smsTypeConst.const.YFK, smsTypeConst.judge.approval.toString(), wxConst.template.advance, wechatData);
                 } else {
@@ -306,10 +318,12 @@ module.exports = app => {
                     // 微信模板通知
                     const users = this._.uniq(this._.concat(this._.map(auditors, 'audit_id'), advanceInfo.uid));
                     const wechatData = {
-                        qi: advanceInfo.type === 0 ? '开工预付款第' + advanceInfo.order + '期' : '材料预付款第' + advanceInfo.order + '期',
+                        wap_url: shenpiUrl,
+                        qi: advanceConst.typeCol[advanceInfo.type].name + '第' + advanceInfo.order + '期',
                         status: wxConst.status.success,
                         tips: wxConst.tips.success,
                         tp: parseFloat(advanceInfo.cur_amount),
+                        code: this.ctx.session.sessionProject.code,
                     };
                     await this.ctx.helper.sendWechat(users, smsTypeConst.const.YFK, smsTypeConst.judge.result.toString(), wxConst.template.advance, wechatData);
                 }
@@ -358,11 +372,16 @@ module.exports = app => {
                 // 微信模板通知
                 const advanceInfo = await this.ctx.service.advance.getDataById(advanceId);
                 const users = this._.uniq(this._.concat(this._.map(auditors, 'audit_id'), advanceInfo.uid));
+                const shenpiUrl = await this.ctx.helper.urlToShort(
+                    this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + advanceInfo.tid + '/advance/' + advanceInfo.id + '/detail'
+                );
                 const wechatData = {
-                    qi: advanceInfo.type === 0 ? '开工预付款第' + advanceInfo.order + '期' : '材料预付款第' + advanceInfo.order + '期',
+                    wap_url: shenpiUrl,
+                    qi: advanceConst.typeCol[advanceInfo.type].name + '第' + advanceInfo.order + '期',
                     status: wxConst.status.back,
                     tips: wxConst.tips.back,
                     tp: parseFloat(advanceInfo.cur_amount),
+                    code: this.ctx.session.sessionProject.code,
                 };
                 await this.ctx.helper.sendWechat(users, smsTypeConst.const.YFK, smsTypeConst.judge.result.toString(), wxConst.template.advance, wechatData);
                 // 拷贝新一次审核流程列表
@@ -424,11 +443,16 @@ module.exports = app => {
                 });
                 // 微信模板通知
                 const advanceInfo = await this.ctx.service.advance.getDataById(advanceId);
+                const shenpiUrl = await this.ctx.helper.urlToShort(
+                    this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + advanceInfo.tid + '/advance/' + advanceInfo.id + '/detail'
+                );
                 const wechatData = {
-                    qi: advanceInfo.type === 0 ? '开工预付款第' + advanceInfo.order + '期' : '材料预付款第' + advanceInfo.order + '期',
+                    wap_url: shenpiUrl,
+                    qi: advanceConst.typeCol[advanceInfo.type].name + '第' + advanceInfo.order + '期',
                     status: wxConst.status.check,
                     tips: wxConst.tips.check,
                     tp: parseFloat(advanceInfo.cur_amount),
+                    code: this.ctx.session.sessionProject.code,
                 };
                 await this.ctx.helper.sendWechat(preAuditor.audit_id, smsTypeConst.const.YFK, smsTypeConst.judge.approval.toString(), wxConst.template.advance, wechatData);
                 await transaction.insert(this.tableName, newAuditors);
@@ -609,6 +633,32 @@ module.exports = app => {
                 throw err;
             }
         }
+
+        /**
+         * 取待审批期列表(wap用)
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getAuditAdvanceByWap(auditorId) {
+            const sql =
+                'SELECT ad.`id`, ad.`tid`, ad.`pay_ratio`, ad.`cur_amount`, ad.`prev_amount`, ad.`prev_total_amount`, ad.`type`, ad.`order`, ' +
+                // '    s.`order` As `sorder`, s.`status` As `sstatus`, s.`s_time`, s.`contract_tp`, s.`qc_tp`, s.`pre_contract_tp`, s.`pre_qc_tp`, s.`yf_tp`, s.`pre_yf_tp`, ' +
+                '    t.`name`, t.`project_id`, t.`user_id`,' +
+                '    ti.`deal_info`, ti.`deal_param` ' +
+                '  FROM ?? AS aa, ?? AS ad, ?? As t, ?? AS ti ' +
+                '  WHERE aa.`audit_id` = ? and aa.`status` = ?' +
+                '    and aa.`vid` = ad.`id` and aa.`tid` = t.`id` and ti.`tid` = t.`id`';
+            const sqlParam = [
+                this.tableName,
+                this.ctx.service.advance.tableName,
+                this.ctx.service.tender.tableName,
+                this.ctx.service.tenderInfo.tableName,
+                auditorId,
+                auditConst.status.checking,
+            ];
+            return await this.db.query(sql, sqlParam);
+        }
     }
     return AdvanceAudit;
 };

+ 5 - 5
app/service/ledger_revise.js

@@ -30,7 +30,7 @@ module.exports = app => {
          * @returns {Promise<*>} - ledger_change下所有数据,并关联 project_account(读取提交人名称、单位、公司)
          */
         async getReviseList (tid) {
-            const sql = 'SELECT lc.id, lc.tid, lc.corder, lc.in_time, lc.uid, lc.begin_time, lc.end_time, lc.times, lc.status, lc.valid,' +
+            const sql = 'SELECT lc.id, lc.tid, lc.corder, lc.in_time, lc.uid, lc.begin_time, lc.end_time, lc.times, lc.status, lc.valid, lc.content,' +
                 '    pa.name As user_name, pa.role As user_role, pa.company As user_company' +
                 '  FROM ' + this.tableName + ' As lc' +
                 '  INNER JOIN ' + this.ctx.service.projectAccount.tableName + ' As pa ON lc.uid = pa.id' +
@@ -100,12 +100,12 @@ module.exports = app => {
                 '     quantity, total_price, unit_price, drawing_code, memo, dgn_qty1, dgn_qty2, deal_qty, deal_tp,' +
                 '     sgfh_qty, sgfh_tp, sjcl_qty, sjcl_tp, qtcl_qty, qtcl_tp, node_type, crid, tender_id, is_tp,' +
                 '     sgfh_expr, sjcl_expr, qtcl_expr, check_calc,' +
-                '     gxby_status, dagl_status, dagl_url, gxby_limit, gxby_ratio, dagl_limit, dagl_ratio)' +
+                '     gxby_status, dagl_status, dagl_url, gxby_limit, dagl_limit)' +
                 '  Select id, code, b_code, name, unit, source, remark, ledger_id, ledger_pid, level, `order`, full_path, is_leaf,' +
                 '      quantity, total_price, unit_price, drawing_code, memo, dgn_qty1, dgn_qty2, deal_qty, deal_tp,' +
                 '      sgfh_qty, sgfh_tp, sjcl_qty, sjcl_tp, qtcl_qty, qtcl_tp, node_type, crid, tender_id, is_tp,' +
                 '      sgfh_expr, sjcl_expr, qtcl_expr, 0,' +
-                '      gxby_status, dagl_status, dagl_url, gxby_limit, gxby_ratio, dagl_limit, dagl_ratio' +
+                '      gxby_status, dagl_status, dagl_url, gxby_limit, dagl_limit' +
                 '  From ' + this.ctx.service.ledger.tableName +
                 '  Where `tender_id` = ?';
             const sqlParam = [tid];
@@ -117,11 +117,11 @@ module.exports = app => {
                 '  (id, tid, lid, name, drawing_code, quantity, add_stage, add_times, add_user,' +
                 '     sgfh_qty, sjcl_qty, qtcl_qty, crid, in_time, porder, position,' +
                 '     sgfh_expr, sjcl_expr, qtcl_expr, real_qty,' +
-                '     gxby_status, dagl_status, dagl_url, gxby_limit, gxby_ratio, dagl_limit, dagl_ratio)' +
+                '     gxby_status, dagl_status, dagl_url, gxby_limit, dagl_limit)' +
                 '  Select id, tid, lid, name, drawing_code, quantity, add_stage, add_times, add_user,' +
                 '     sgfh_qty, sjcl_qty, qtcl_qty, crid, in_time, porder, position,' +
                 '     sgfh_expr, sjcl_expr, qtcl_expr, real_qty,' +
-                '     gxby_status, dagl_status, dagl_url, gxby_limit, gxby_ratio, dagl_limit, dagl_ratio' +
+                '     gxby_status, dagl_status, dagl_url, gxby_limit, dagl_limit' +
                 '  From ' + this.ctx.service.pos.tableName +
                 '  Where `tid` = ?';
             const sqlParam = [tid];

+ 3 - 3
app/service/pos.js

@@ -29,7 +29,7 @@ module.exports = app => {
                 where: condition,
                 columns: ['id', 'tid', 'lid', 'name', 'quantity', 'position', 'drawing_code', 'sgfh_qty', 'sjcl_qty',
                     'qtcl_qty', 'in_time', 'porder', 'add_stage', 'sgfh_expr', 'sjcl_expr', 'qtcl_expr', 'real_qty',
-                    'dagl_status', 'dagl_url', 'gxby_status', 'gxby_limit', 'gxby_ratio', 'dagl_limit', 'dagl_status'],
+                    'dagl_status', 'dagl_url', 'gxby_status', 'gxby_limit', 'dagl_limit', 'dagl_status'],
                 order: [['porder', 'ASC']],
             });
         }
@@ -38,7 +38,7 @@ module.exports = app => {
             const sql = 'SELECT p.id, p.tid, p.lid, p.name, p.quantity, p.position, p.drawing_code,' +
                 '    p.sgfh_qty, p.sjcl_qty, p.qtcl_qty, p.porder, p.add_stage, p.add_times, p.add_user, s.order As add_stage_order,' +
                 '    p.sgfh_expr, p.sjcl_expr, p.qtcl_expr, p.real_qty, p.gxby_status, p.dagl_status, p.dagl_url,' +
-                '    p.gxby_limit, p.dagl_limit, p.gxby_ratio, p.dagl_ratio' +
+                '    p.gxby_limit, p.dagl_limit' +
                 '  FROM ' + this.tableName + ' p ' +
                 '  LEFT JOIN ' + this.ctx.service.stage.tableName + ' s' +
                 '  ON p.add_stage = s.id'
@@ -50,7 +50,7 @@ module.exports = app => {
             if (ids instanceof Array && ids.length > 0) {
                 const sql = 'SELECT id, tid, lid, name, quantity, position, drawing_code,' +
                     '    sgfh_qty, sjcl_qty, qtcl_qty, add_stage, add_times, add_user, sgfh_expr, sjcl_expr, qtcl_expr, real_qty,' +
-                    '    dagl_status, dagl_url, gxby_status, gxby_limit, dagl_limit, gxby_ratio, dagl_ratio' +
+                    '    dagl_status, dagl_url, gxby_status, gxby_limit, dagl_limit' +
                     '  FROM ' + this.tableName +
                     '  WHERE id in (' + this.ctx.helper.getInArrStrSqlFilter(ids) + ')';
                 return await this.db.query(sql, []);

+ 0 - 1
app/service/project.js

@@ -164,7 +164,6 @@ module.exports = app => {
             });
             return result.affectedRows === 1;
         }
-
     }
 
     return Project;

+ 1 - 13
app/service/project_account.js

@@ -13,7 +13,6 @@ const crypto = require('crypto');
 const SSO = require('../lib/sso');
 const SMS = require('../lib/sms');
 const SmsAliConst = require('../const/sms_alitemplate');
-const thirdPartyConst = require('../const/third_party');
 const loginWay = require('../const/setting').loginWay;
 const smsTypeConst = require('../const/sms_type').type;
 module.exports = app => {
@@ -229,19 +228,8 @@ module.exports = app => {
                         // cooperation,
                     };
 
-                    const thirdParty = await this.db.get('zh_s2b_proj', { pid: projectInfo.id });
-                    if (thirdParty) {
-                        thirdParty.gxby_option = thirdParty.gxby_option ? JSON.parse(thirdParty.gxby_option) : null;
-                        projectInfo.gxby = thirdParty.gxby;
-                        projectInfo.gxby_status = thirdParty.gxby_option && thirdParty.gxby_option.status
-                            ? thirdParty.gxby_option.status : thirdPartyConst.gxby;
-
-                        thirdParty.dagl_option = thirdParty.dagl_option ? JSON.parse(thirdParty.dagl_option) : null;
-                        projectInfo.dagl = thirdParty.dagl;
-                        projectInfo.dagl_status = thirdParty.dagl_option && thirdParty.dagl_option.status
-                            ? thirdParty.dagl_option.status : thirdPartyConst.dagl;
-                    }
                     this.ctx.session.sessionProject = projectInfo;
+                    await this.ctx.service.s2bProj.refreshSessionS2b();
                     this.ctx.session.sessionProjectList = projectList;
                     // 记录登录日志
                     await this.ctx.service.loginLogging.addLoginLog(loginType, loginStatus);

+ 4 - 0
app/service/report.js

@@ -247,6 +247,10 @@ module.exports = app => {
                         const jhHelper2 = new rptCustomData.jhHelper(this.ctx);
                         rst[filter] = await jhHelper2.gather(memFieldKeys[filter], customDefine.gather_select, customSelect ? customSelect.gather_select : null);
                         break;
+                    case 'mem_jh_gather_stage_bills_compare':
+                        const jhHelper3 = new rptCustomData.jhHelper(this.ctx);
+                        rst[filter] = await jhHelper3.gatherBills(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;

+ 52 - 4
app/service/revise_audit.js

@@ -267,9 +267,14 @@ module.exports = app => {
                 //     smsTypeConst.judge.approval.toString(), '台账修订需要您审批,请登录系统处理。');
                 await this.ctx.helper.sendAliSms(audit.audit_id, smsTypeConst.const.XD, smsTypeConst.judge.approval.toString(), SmsAliConst.template.revise_check);
                 // 微信模板通知
+                const shenpiUrl = await this.ctx.helper.urlToShort(
+                    this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + revise.tid + '/revise/' + revise.id + '/info'
+                );
                 const wechatData = {
+                    wap_url: shenpiUrl,
                     status: wxConst.status.check,
                     tips: wxConst.tips.check,
+                    code: this.ctx.session.sessionProject.code,
                     begin_time: Date.parse(time),
                 };
                 await this.ctx.helper.sendWechat(audit.audit_id, smsTypeConst.const.XD, smsTypeConst.judge.approval.toString(), wxConst.template.revise, wechatData);
@@ -281,9 +286,11 @@ module.exports = app => {
                 await this.ctx.helper.sendAliSms(users, smsTypeConst.const.XD, smsTypeConst.judge.result.toString(), SmsAliConst.template.revise_report);
                 // 微信模板通知
                 const wechatData2 = {
+                    wap_url: shenpiUrl,
                     status: wxConst.status.report,
                     tips: wxConst.tips.report,
                     begin_time: Date.parse(time),
+                    code: this.ctx.session.sessionProject.code,
                 };
                 await this.ctx.helper.sendWechat(users, smsTypeConst.const.XD, smsTypeConst.judge.result.toString(), wxConst.template.revise, wechatData2);
                 await transaction.commit();
@@ -304,12 +311,12 @@ module.exports = app => {
                 '     quantity, total_price, unit_price, drawing_code, memo, dgn_qty1, dgn_qty2, deal_qty, deal_tp,' +
                 '     sgfh_qty, sgfh_tp, sjcl_qty, sjcl_tp, qtcl_qty, qtcl_tp, node_type, crid, tender_id, is_tp,' +
                 '     sgfh_expr, sjcl_expr, qtcl_expr, check_calc,' +
-                '     gxby_status, dagl_status, dagl_url, gxby_limit, gxby_ratio, dagl_limit, dagl_ratio)' +
+                '     gxby_status, dagl_status, dagl_url, gxby_limit,  dagl_limit)' +
                 '  Select id, code, b_code, name, unit, source, remark, ledger_id, ledger_pid, level, `order`, full_path, is_leaf,' +
                 '      quantity, total_price, unit_price, drawing_code, memo, dgn_qty1, dgn_qty2, deal_qty, deal_tp,' +
                 '      sgfh_qty, sgfh_tp, sjcl_qty, sjcl_tp, qtcl_qty, qtcl_tp, node_type, crid, tender_id, is_tp, ' +
                 '      sgfh_expr, sjcl_expr, qtcl_expr, check_calc,' +
-                '      gxby_status, dagl_status, dagl_url, gxby_limit, gxby_ratio, dagl_limit, dagl_ratio' +
+                '      gxby_status, dagl_status, dagl_url, gxby_limit,  dagl_limit' +
                 '  From ' +
                 this.ctx.service.reviseBills.tableName +
                 '  Where `tender_id` = ?';
@@ -321,11 +328,11 @@ module.exports = app => {
                 '  (id, tid, lid, name, drawing_code, quantity, add_stage, add_times, add_user,' +
                 '     sgfh_qty, sjcl_qty, qtcl_qty, crid, porder, position, ' +
                 '     sgfh_expr, sjcl_expr, qtcl_expr, real_qty,' +
-                '     gxby_status, dagl_status, dagl_url, gxby_limit, gxby_ratio, dagl_limit, dagl_ratio)' +
+                '     gxby_status, dagl_status, dagl_url, gxby_limit,  dagl_limit)' +
                 '  Select id, tid, lid, name, drawing_code, quantity, add_stage, add_times, add_user,' +
                 '     sgfh_qty, sjcl_qty, qtcl_qty, crid, porder, position,' +
                 '     sgfh_expr, sjcl_expr, qtcl_expr, real_qty,' +
-                '     gxby_status, dagl_status, dagl_url, gxby_limit, gxby_ratio, dagl_limit, dagl_ratio' +
+                '     gxby_status, dagl_status, dagl_url, gxby_limit,  dagl_limit' +
                 '  From ' +
                 this.ctx.service.revisePos.tableName +
                 '  Where `tid` = ?';
@@ -403,9 +410,14 @@ module.exports = app => {
                         //     smsTypeConst.judge.approval.toString(), '台账修订需要您审批,请登录系统处理。');
                         await this.ctx.helper.sendAliSms(nextAudit.audit_id, smsTypeConst.const.XD, smsTypeConst.judge.approval.toString(), SmsAliConst.template.revise_check);
                         // 微信模板通知
+                        const shenpiUrl = await this.ctx.helper.urlToShort(
+                            this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + revise.tid + '/revise/' + revise.id + '/info'
+                        );
                         const wechatData = {
+                            wap_url: shenpiUrl,
                             status: wxConst.status.check,
                             tips: wxConst.tips.check,
+                            code: this.ctx.session.sessionProject.code,
                             begin_time: Date.parse(revise.begin_time),
                         };
                         await this.ctx.helper.sendWechat(nextAudit.audit_id, smsTypeConst.const.XD, smsTypeConst.judge.approval.toString(), wxConst.template.revise, wechatData);
@@ -471,10 +483,15 @@ module.exports = app => {
                         users.push(revise.uid);
 
                         // 微信模板通知
+                        const shenpiUrl = await this.ctx.helper.urlToShort(
+                            this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + revise.tid + '/revise/' + revise.id + '/info'
+                        );
                         const wechatData2 = {
+                            wap_url: shenpiUrl,
                             status: wxConst.status.success,
                             tips: wxConst.tips.success,
                             begin_time: Date.parse(revise.begin_time),
+                            code: this.ctx.session.sessionProject.code,
                         };
                         await this.ctx.helper.sendWechat(users, smsTypeConst.const.XD, smsTypeConst.judge.result.toString(), wxConst.template.revise, wechatData2);
                     }
@@ -505,10 +522,15 @@ module.exports = app => {
                         status: SmsAliConst.status.back,
                     });
                     // 微信模板通知
+                    const shenpiUrl = await this.ctx.helper.urlToShort(
+                        this.ctx.protocol + '://' + this.ctx.host + '/wap/tender/' + revise.tid + '/revise/' + revise.id + '/info'
+                    );
                     const wechatData = {
+                        wap_url: shenpiUrl,
                         status: wxConst.status.back,
                         tips: wxConst.tips.back,
                         begin_time: Date.parse(revise.begin_time),
+                        code: this.ctx.session.sessionProject.code,
                     };
                     await this.ctx.helper.sendWechat(revise.uid, smsTypeConst.const.XD, smsTypeConst.judge.result.toString(), wxConst.template.revise, wechatData);
                     // 其他参与人
@@ -525,9 +547,11 @@ module.exports = app => {
                     );
                     // 微信模板通知
                     const wechatData2 = {
+                        wap_url: shenpiUrl,
                         status: wxConst.status.back,
                         tips: wxConst.tips.back,
                         begin_time: Date.parse(revise.begin_time),
+                        code: this.ctx.session.sessionProject.code,
                     };
                     await this.ctx.helper.sendWechat(this._.map(auditors, 'user_id'), smsTypeConst.const.XD, smsTypeConst.judge.result.toString(), wxConst.template.revise, wechatData2);
                 }
@@ -540,6 +564,30 @@ module.exports = app => {
         }
 
         /**
+         * 取待审批修订列表(wap用)
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getAuditReviseByWap(auditorId) {
+            const sql =
+                'SELECT ra.`audit_id`, ra.`times`, ra.`audit_order`, ra.`begin_time`, ra.`end_time`,' +
+                '    r.id, r.corder, r.uid, r.status, r.content, r.in_time, ' +
+                '    t.id As t_id, t.`name` As t_name, t.`project_id` As t_pid, t.`type` As t_type, t.`user_id` As t_uid, t.`status` As t_status, ' +
+                '    ti.`deal_info`, ' +
+                '    p.name As audit_name, p.role As audit_role, p.company As audit_company' +
+                '  FROM ' + this.tableName + ' AS ra' +
+                '  Left Join ' + this.ctx.service.ledgerRevise.tableName + ' As r On ra.rid = r.id' +
+                '  Left Join ' + this.ctx.service.tender.tableName + ' AS t On r.tid = t.id' +
+                '  Left Join ' + this.ctx.service.tenderInfo.tableName + ' AS ti On r.tid = ti.tid' +
+                '  Left Join ' + this.ctx.service.projectAccount.tableName + ' As p On ra.audit_id = p.id' +
+                '  WHERE r.`valid` != 0 and ra.`audit_id` = ? and ra.`status` = ?' +
+                '  ORDER BY ra.`begin_time` DESC';
+            const sqlParam = [auditorId, auditConst.status.checking];
+            return await this.db.query(sql, sqlParam);
+        }
+
+        /**
          * 获取审核人需要审核的标段列表
          *
          * @param auditorId

+ 68 - 0
app/service/s2b_proj.js

@@ -0,0 +1,68 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date 2021/6/17
+ * @version
+ */
+const thirdPartyConst = require('../const/third_party');
+
+module.exports = app => {
+
+    class S2bProj extends app.BaseService {
+
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 's2b_proj';
+        }
+
+        async getDataByPid(pid) {
+            const sp = await this.getDataByCondition({ pid });
+            if (sp) {
+                sp.gxby_option = sp.gxby_option ? JSON.parse(sp.gxby_option) : null;
+                sp.dagl_option = sp.dagl_option ? JSON.parse(sp.dagl_option) : null;
+                sp.gxby_status = sp.gxby_status ? JSON.parse(sp.gxby_status) : thirdPartyConst.gxby;
+                sp.dagl_status = sp.dagl_status ? JSON.parse(sp.dagl_status) : thirdPartyConst.dagl;
+            }
+            return sp;
+        }
+
+        async refreshSessionS2b() {
+            const s2bProj = await this.getDataByPid(this.ctx.session.sessionProject.id);
+            this.ctx.session.sessionProject.gxby = s2bProj ? s2bProj.gxby : false;
+            this.ctx.session.sessionProject.gxby_status = s2bProj ? s2bProj.gxby_status : thirdPartyConst.gxby;
+            this.ctx.session.sessionProject.dagl = s2bProj ? s2bProj.dagl : false;
+            this.ctx.session.sessionProject.dagl_status = s2bProj ? s2bProj.dagl_status : thirdPartyConst.dagl;
+        }
+
+        async updateGxbyStatus(pid, status, limit) {
+            const sp = await this.getDataByPid(pid);
+            const gs = sp.gxby_status.find(x => { return x.value === status; });
+            if (!gs) throw '提交数据错误';
+            gs.limit = limit;
+            await this.db.update(this.tableName, { gxby_status: JSON.stringify(sp.gxby_status) }, { where: { pid } });
+            return gs;
+        }
+
+        async updateDaglStatus(pid, status, limit, ratio) {
+            const sp = await this.getDataByPid(pid);
+            const ds = sp.dagl_status.find(x => { return x.value === status; });
+            if (!ds) throw '提交数据错误';
+            if (limit !== undefined && limit !== null) ds.limit = limit;
+            if (ratio !== undefined && ratio !== null) ds.ratio = this.ctx.helper.round(ratio, 2);
+            await this.db.update(this.tableName, { dagl_status: JSON.stringify(sp.dagl_status) }, { where: { pid } });
+            return ds;
+        }
+
+    }
+
+    return S2bProj;
+};

+ 5 - 5
app/view/advance/detail.ejs

@@ -206,7 +206,7 @@
                                 </td>
                                 <td width="70%">
 
-                                    <% auditHistory.forEach((auditors, idx) => { %>
+                                    <% auditHistory.forEach((history, idx) => { %>
                                         <!-- 展开/收起历史流程 -->
                                         <% if(idx === auditHistory.length - 1 && auditHistory.length !== 1) { %>
                                             <div class="text-right">
@@ -216,7 +216,7 @@
                                         <div class="<%- idx < auditHistory.length - 1 ? 'fold-card' : '' %>">
                                             <div class="text-center text-muted" ><%- idx+1 %>#</div>
                                             <ul class="timeline-list list-unstyled mt-2">
-                                                <% auditors.forEach((auditor, index) => { %>
+                                                <% history.forEach((auditor, index) => { %>
                                                 <% if (index === 0) { %>
                                                 <li class="timeline-list-item pb-2">
                                                     <div class="timeline-item-date">
@@ -244,7 +244,7 @@
                                                     <div class="timeline-item-date">
                                                         <%- ctx.helper.formatDate(auditor.end_time) %>
                                                     </div>
-                                                    <% if(index < auditors.length - 1) { %>
+                                                    <% if(index < history.length - 1) { %>
                                                     <div class="timeline-item-tail"></div>
                                                     <% } %>
                                                     <% if(auditor.status === auditConst.status.checked) { %>
@@ -288,7 +288,7 @@
                                                     <div class="timeline-item-date">
                                                         <%- ctx.helper.formatDate(auditor.end_time) %>
                                                     </div>
-                                                    <% if(index < auditors.length - 1) { %>
+                                                    <% if(index < history.length - 1) { %>
                                                     <div class="timeline-item-tail"></div>
                                                     <% } %>
                                                     <% if(auditor.status === auditConst.status.checked) { %>
@@ -317,7 +317,7 @@
                                                                             class="pull-right
                                                                                         <%- auditConst.statusClass[auditor.status] %>"><%- auditor.status !== auditConst.status.uncheck ? auditConst.statusString[auditor.status] : ''%>
                                                                             <%- auditor.status === auditConst.status.checkNo ? advance.user.name : '' %>
-                                                                            <%- auditor.status === auditConst.status.checkNoPre ? auditors[index-1].name : '' %>
+                                                                            <%- auditor.status === auditConst.status.checkNoPre ? auditors.find(item => item.order === auditor.sort-1).name : '' %>
                                                                         </span>
                                                                     </p>
                                                                     <p class="text-muted mb-0"><%- auditor.role %></p>

+ 19 - 19
app/view/advance/modal_audit.ejs

@@ -74,7 +74,7 @@
                         </div>
                     </div>
                     <div class="col-8 modal-height-500" style="overflow: auto">
-                        <% auditHistory.forEach((auditors, idx) => { %>
+                        <% auditHistory.forEach((history, idx) => { %>
                             <!-- 展开/收起历史流程 -->
                         <% if(idx === auditHistory.length - 1 && auditHistory.length !== 1) { %>
                             <div class="text-right">
@@ -84,7 +84,7 @@
                         <div class="<%- idx < auditHistory.length - 1 ? 'fold-card' : '' %>">
                             <div class="text-center text-muted"><%- idx+1 %>#</div>
                             <ul class="timeline-list list-unstyled mt-2">
-                                <% auditors.forEach((auditor, index) => { %>
+                                <% history.forEach((auditor, index) => { %>
                                 <% if (index === 0) { %>
                                 <li class="timeline-list-item pb-2">
                                     <div class="timeline-item-date">
@@ -112,7 +112,7 @@
                                     <div class="timeline-item-date">
                                         <%- ctx.helper.formatDate(auditor.end_time) %>
                                     </div>
-                                    <% if(index < auditors.length - 1) { %>
+                                    <% if(index < history.length - 1) { %>
                                     <div class="timeline-item-tail"></div>
                                     <% } %>
                                     <% if(auditor.status === auditConst.status.checked) { %>
@@ -156,7 +156,7 @@
                                     <div class="timeline-item-date">
                                         <%- ctx.helper.formatDate(auditor.end_time) %>
                                     </div>
-                                    <% if(index < auditors.length - 1) { %>
+                                    <% if(index < history.length - 1) { %>
                                     <div class="timeline-item-tail"></div>
                                     <% } %>
                                     <% if(auditor.status === auditConst.status.checked) { %>
@@ -184,7 +184,7 @@
                                                             class="pull-right
                                                                             <%- auditConst.statusClass[auditor.status] %>"><%- auditor.status !== auditConst.status.uncheck ? auditConst.statusString[auditor.status] : ''%>
                                                             <%- auditor.status === auditConst.status.checkNo ? advance.user.name : '' %>
-                                                            <%- auditor.status === auditConst.status.checkNoPre ? auditors[index-1].name : '' %>
+                                                            <%- auditor.status === auditConst.status.checkNoPre ? history[index-1].name : '' %>
                                                         </span>
                                                     </p>
                                                     <p class="text-muted mb-0"><%- auditor.role %></p>
@@ -253,7 +253,7 @@
                                 </div>
                             </div>
                             <div class="col-8 modal-height-500" style="overflow: auto">
-                                <% auditHistory.forEach((auditors, idx) => { %>
+                                <% auditHistory.forEach((history, idx) => { %>
                                     <!-- 展开/收起历史流程 -->
                                 <% if(idx === auditHistory.length - 1 && auditHistory.length !== 1) { %>
                                     <div class="text-right">
@@ -263,7 +263,7 @@
                                 <div class="<%- idx < auditHistory.length - 1 ? 'fold-card' : '' %>">
                                     <div class="text-center text-muted"><%- idx+1 %>#</div>
                                     <ul class="timeline-list list-unstyled mt-2">
-                                        <% auditors.forEach((auditor, index) => { %>
+                                        <% history.forEach((auditor, index) => { %>
                                         <% if (index === 0) { %>
                                         <li class="timeline-list-item pb-2">
                                             <div class="timeline-item-date">
@@ -291,7 +291,7 @@
                                             <div class="timeline-item-date">
                                                 <%- ctx.helper.formatDate(auditor.end_time) %>
                                             </div>
-                                            <% if(index < auditors.length - 1) { %>
+                                            <% if(index < history.length - 1) { %>
                                             <div class="timeline-item-tail"></div>
                                             <% } %>
                                             <% if(auditor.status === auditConst.status.checked) { %>
@@ -340,7 +340,7 @@
                                             <div class="timeline-item-date">
                                                 <%- ctx.helper.formatDate(auditor.end_time) %>
                                             </div>
-                                            <% if(index < auditors.length - 1) { %>
+                                            <% if(index < history.length - 1) { %>
                                             <div class="timeline-item-tail"></div>
                                             <% } %>
                                             <% if(auditor.status === auditConst.status.checked) { %>
@@ -368,7 +368,7 @@
                                                                     class="pull-right
                                                                                     <%- auditConst.statusClass[auditor.status] %>"><%- auditor.status !== auditConst.status.uncheck ? auditConst.statusString[auditor.status] : ''%>
                                                                     <%- auditor.status === auditConst.status.checkNo ? advance.user.name : '' %>
-                                                                    <%- auditor.status === auditConst.status.checkNoPre ? auditors[index-1].name : '' %>
+                                                                    <%- auditor.status === auditConst.status.checkNoPre ? history[index-1].name : '' %>
                                                                 </span>
                                                             </p>
                                                             <p class="text-muted mb-0"><%- auditor.role %></p>
@@ -445,7 +445,7 @@
                                 </div>
                             </div>
                             <div class="col-8 modal-height-500" style="overflow: auto">
-                                <% auditHistory.forEach((auditors, idx) => { %>
+                                <% auditHistory.forEach((history, idx) => { %>
                                     <!-- 展开/收起历史流程 -->
                                 <% if(idx === auditHistory.length - 1 && auditHistory.length !== 1) { %>
                                     <div class="text-right">
@@ -455,7 +455,7 @@
                                 <div class="<%- idx < auditHistory.length - 1 ? 'fold-card' : '' %>">
                                     <div class="text-center text-muted"><%- idx+1 %>#</div>
                                     <ul class="timeline-list list-unstyled mt-2">
-                                        <% auditors.forEach((auditor, index) => { %>
+                                        <% history.forEach((auditor, index) => { %>
                                         <% if (index === 0) { %>
                                         <li class="timeline-list-item pb-2">
                                             <div class="timeline-item-date">
@@ -483,7 +483,7 @@
                                             <div class="timeline-item-date">
                                                 <%- ctx.helper.formatDate(auditor.end_time) %>
                                             </div>
-                                            <% if(index < auditors.length - 1) { %>
+                                            <% if(index < history.length - 1) { %>
                                             <div class="timeline-item-tail"></div>
                                             <% } %>
                                             <% if(auditor.status === auditConst.status.checked) { %>
@@ -529,13 +529,13 @@
                                                                 <label class="form-check-label" for="inlineRadio1">退回原报
                                                                     <%- ctx.advance.user.name %></label>
                                                             </div>
-                                                            <% if (auditor.order > 1 && auditor.audit_id !== auditors[0].audit_id) { %>
+                                                            <% if (auditor.sort > 1 && auditor.audit_id !== history[0].audit_id) { %>
                                                             <div class="form-check form-check-inline">
                                                                 <input class="form-check-input" type="radio" name="checkType"
                                                                     id="inlineRadio2"
                                                                     value="<%- auditConst.status.checkNoPre %>">
                                                                 <label class="form-check-label" for="inlineRadio2">退回上一审批人
-                                                                    <%- auditors[index-1].name %></label>
+                                                                    <%- auditors.find(item => item.order === auditor.sort-1).name %></label>
                                                             </div>
                                                             <% } %>
                                                         </div>
@@ -553,7 +553,7 @@
                                             <div class="timeline-item-date">
                                                 <%- ctx.helper.formatDate(auditor.end_time) %>
                                             </div>
-                                            <% if(index < auditors.length - 1) { %>
+                                            <% if(index < history.length - 1) { %>
                                             <div class="timeline-item-tail"></div>
                                             <% } %>
                                             <% if(auditor.status === auditConst.status.checked) { %>
@@ -581,7 +581,7 @@
                                                                     class="pull-right
                                                                                     <%- auditConst.statusClass[auditor.status] %>"><%- auditor.status !== auditConst.status.uncheck ? auditConst.statusString[auditor.status] : ''%>
                                                                     <%- auditor.status === auditConst.status.checkNo ? advance.user.name : '' %>
-                                                                    <%- auditor.status === auditConst.status.checkNoPre ? auditors[index-1].name : '' %>
+                                                                    <%- auditor.status === auditConst.status.checkNoPre ? history[index-1].name : '' %>
                                                                 </span>
                                                             </p>
                                                             <p class="text-muted mb-0"><%- auditor.role %></p>
@@ -603,13 +603,13 @@
                                                                         <label class="form-check-label" for="inlineRadio1">退回原报
                                                                             <%- ctx.advance.user.name %></label>
                                                                     </div>
-                                                                    <% if (auditor.order > 1 && auditor.audit_id !== auditors[0].audit_id) { %>
+                                                                    <% if (auditor.sort > 1 && auditor.audit_id !== history[0].audit_id) { %>
                                                                     <div class="form-check form-check-inline">
                                                                         <input class="form-check-input" type="radio" name="checkType"
                                                                             id="inlineRadio2"
                                                                             value="<%- auditConst.status.checkNoPre %>">
                                                                         <label class="form-check-label" for="inlineRadio2">退回上一审批人
-                                                                            <%- auditors[index-1].name %></label>
+                                                                            <%- auditors.find(item => item.order === auditor.sort-1).name %></label>
                                                                     </div>
                                                                     <% } %>
                                                                 </div>

+ 6 - 6
app/view/change/index.ejs

@@ -70,21 +70,21 @@
                     <thead>
                     <tr>
                         <th width="20%" id="sort_change">申请编号/变更令号</th><th width="30%">工程名称</th>
-                        <th width="10%">变更类别</th><th width="10%">变更金额</th>
+                        <th width="10%">变更性质</th><th width="10%">变更金额</th>
                         <th width="10%">审批状态</th><th width="15%">审批进度</th><th></th>
                     </tr>
                     </thead>
                     <tbody id="changeList">
-                    <% const classArray = []; %>
-                    <% for (const t in changeConst.class) { %>
-                    <% const cClass = changeConst.class[t] %>
-                    <% classArray[cClass.value] = cClass.name %>
+                    <% const qualityArray = []; %>
+                    <% for (const t in changeConst.quality) { %>
+                    <% const cQuality = changeConst.quality[t] %>
+                    <% qualityArray[cQuality.value] = cQuality.name %>
                     <% } %>
                     <% for (const c of changes) { %>
                     <tr>
                         <td><a href="/tender/<%- tender.id %>/change/<%- c.cid %>/information"><% if (c.status !== auditConst.status.checked) { %><%- c.code %><% } else { %><%- c.p_code %><% } %></a></td>
                         <td><%- c.name %></td>
-                        <td><%- classArray[c.class] %><% c.class %></td>
+                        <td><%- qualityArray[c.quality] %><% c.quality %></td>
                         <td style="text-align: right"><%= ctx.helper.roundNum(c.total_price, tpUnit) %></td>
                         <% if (c.status === auditConst.status.uncheck && ctx.tender.isTourist) { %>
                             <td>

+ 5 - 5
app/view/material/audit_modal.ejs

@@ -219,7 +219,7 @@
                                                             class="pull-right
                                                                             <%- auditConst.statusClass[auditor.status] %>"><%- auditor.status !== auditConst.status.uncheck ? auditConst.statusString[auditor.status] : ''%>
                                                             <%- auditor.status === auditConst.status.checkNo ? ctx.material.user.name : '' %>
-                                                            <%- auditor.status === auditConst.status.checkNoPre ? auditors[index-1].name : '' %>
+                                                            <%- auditor.status === auditConst.status.checkNoPre ? ctx.material.auditors2.find(item => item.order === auditor.sort-1).name : '' %>
                                                         </span>
                                                     </p>
                                                     <p class="text-muted mb-0"><%- auditor.role %></p>
@@ -407,7 +407,7 @@
                                                                     class="pull-right
                                                                                     <%- auditConst.statusClass[auditor.status] %>"><%- auditor.status !== auditConst.status.uncheck ? auditConst.statusString[auditor.status] : ''%>
                                                                     <%- auditor.status === auditConst.status.checkNo ? ctx.material.user.name : '' %>
-                                                                    <%- auditor.status === auditConst.status.checkNoPre ? auditors[index-1].name : '' %>
+                                                                    <%- auditor.status === auditConst.status.checkNoPre ? ctx.material.auditors2.find(item => item.order === auditor.sort-1).name : '' %>
                                                                 </span>
                                                             </p>
                                                             <p class="text-muted mb-0"><%- auditor.role %></p>
@@ -574,7 +574,7 @@
                                                                     id="inlineRadio2"
                                                                     value="<%- auditConst.status.checkNoPre %>">
                                                                 <label class="form-check-label" for="inlineRadio2">退回上一审批人
-                                                                    <%- auditors[index-1].name %></label>
+                                                                    <%- ctx.material.auditors2.find(item => item.order === auditor.sort-1).name %></label>
                                                             </div>
                                                             <% } %>
                                                         </div>
@@ -620,7 +620,7 @@
                                                                     class="pull-right
                                                                                     <%- auditConst.statusClass[auditor.status] %>"><%- auditor.status !== auditConst.status.uncheck ? auditConst.statusString[auditor.status] : ''%>
                                                                     <%- auditor.status === auditConst.status.checkNo ? ctx.material.user.name : '' %>
-                                                                    <%- auditor.status === auditConst.status.checkNoPre ? auditors[index-1].name : '' %>
+                                                                    <%- auditor.status === auditConst.status.checkNoPre ? ctx.material.auditors2.find(item => item.order === auditor.sort-1).name : '' %>
                                                                 </span>
                                                             </p>
                                                             <p class="text-muted mb-0"><%- auditor.role %></p>
@@ -648,7 +648,7 @@
                                                                         id="inlineRadio2"
                                                                         value="<%- auditConst.status.checkNoPre %>">
                                                                     <label class="form-check-label" for="inlineRadio2">退回上一审批人
-                                                                        <%- auditors[index-1].name %></label>
+                                                                        <%- ctx.material.auditors2.find(item => item.order === auditor.sort-1).name %></label>
                                                                 </div>
                                                                 <% } %>
                                                             </div>

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

@@ -11,16 +11,6 @@
                 <div class="row m-0 mt-3">
                     <div class="col-6">
                         <div class="form-group">
-                            <label>超计控制</label>
-                            <div>
-                                <div class="form-check form-check-inline">
-                                    <input class="form-check-input" type="checkbox" name="ban_over" <% if (funRela.banOver) { %>checked<% } %> onchange="updateSetting();">
-                                    <label class="form-check-label" for="inlineCheckbox6">超计时限制上报审批/审批通过</label>
-                                </div>
-                            </div>
-                        </div>
-
-                        <div class="form-group">
                             <label>中间计量模式设置</label>
                             <div>
                                 <% for (const i in imType) { %>
@@ -46,6 +36,6 @@
         autoFlashHeight();
     });
     const updateSetting = function () {
-        postData('/setting/fun/update', {imType: parseInt($('[name=im_type]:checked').val()), banOver: $('[name=ban_over]')[0].checked});
+        postData('/setting/fun/update', {imType: parseInt($('[name=im_type]:checked').val())});
     }
 </script>

+ 140 - 52
app/view/setting/s2b.ejs

@@ -8,65 +8,153 @@
     <div class="content-wrap">
         <div class="c-body">
             <div class="sjs-height-0">
-                <% if (tenders.length === 0) { %>
-                <div class="jumbotron m-3">
-                    <h3 class="display-6">没有标段数据</h3>
-                </div>
-                <% } else { %>
+                <nav class="nav nav-tabs m-3" role="tablist">
+                    <a class="nav-item nav-link active" data-toggle="tab" href="#user-purview" role="tab">业务配置</a>
+                    <a class="nav-item nav-link" data-toggle="tab" href="#user-list" role="tab">标段列表</a>
+                </nav>
                 <div class="m-3">
-                    <table class="table table-hover table-bordered">
-                        <thead>
-                        <tr>
-                            <th class="text-center" >名称</th>
-                            <th class="text-center" >计量模式</th>
-                            <th class="text-center" >计量期数</th>
-                            <th class="text-center" >创建人</th>
-                            <th class="text-center" >标段创建时间/期审批时间</th>
-                            <th class="text-center">工序报验</th>
-                            <th class="text-center">档案管理</th>
-                        </tr>
-                        </thead>
-                        <% for (const t of tenders) { %>
-                        <tr tid="<%- t.id %>">
-                            <td><%- t.name %></td>
-                            <td><%- t.measure_type_str %></td>
-                            <td><%- t.stage_count_str %></td>
-                            <td><%- t.user_str %></td>
-                            <td><%- ctx.moment(t.show_time).format('YYYY-MM-DD HH:mm:ss') %></td>
-                            <td class="text-center">
-                                <div class="form-check form-check-inline">
-                                    <input class="form-check-input" type="checkbox" id="inlineCheckbox1" <% if (t.s2b_gxby_check) { %>checked<% } %> name="gxby_check" onchange="updateS2bSetting(this);" value="<%- t.s2b_gxby_check %>">
-                                    <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
-                                    <label class="form-check-label" for="inlineCheckbox1">检查计量</label>
-                                </div>
-                                <div class="form-check form-check-inline">
-                                    <input class="form-check-input" type="checkbox" id="inlineCheckbox2" <% if (t.s2b_gxby_limit) { %>checked<% } %> name="gxby_limit" onchange="updateS2bSetting(this);" value="<%- t.s2b_gxby_limit %>">
-                                    <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
-                                    <label class="form-check-label" for="inlineCheckbox2">限制上报</label>
-                                </div>
-                            </td>
-                            <td class="text-center">
-                                <div class="form-check form-check-inline">
-                                    <input class="form-check-input" type="checkbox" id="inlineCheckbox3" <% if (t.s2b_dagl_check) { %>checked<% } %> name="dagl_check" onchange="updateS2bSetting(this);" value="<%- t.s2b_dagl_check %>">
-                                    <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
-                                    <label class="form-check-label" for="inlineCheckbox3">检查计量</label>
-                                </div>
-                                <div class="form-check form-check-inline">
-                                    <input class="form-check-input" type="checkbox" id="inlineCheckbox4" <% if (t.s2b_dagl_limit) { %>checked<% } %> name="dagl_limit" onchange="updateS2bSetting(this);" value="<%- t.s2b_dagl_limit %>">
-                                    <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
-                                    <label class="form-check-label" for="inlineCheckbox4">限制上报</label>
-                                </div>
-                            </td>
-                        </tr>
-                        <% } %>
-                    </table>
+                    <div class="tab-content">
+                        <div class="tab-pane active" id="user-purview">
+                            <div class="col-4">
+                                <legend>工序报验</legend>
+                                <table class="table table-hover table-bordered">
+                                    <thead><tr><th>值</th><th>名称</th><th>允许计量</th></tr></thead>
+                                    <tbody id="gxby_list">
+                                    <% for (const s of ctx.session.sessionProject.gxby_status) { %>
+                                    <tr>
+                                        <td><%- s.value %></td>
+                                        <td><%- s.name %></td>
+                                        <td>
+                                            <div class="form-check form-check-inline">
+                                                <input class="form-check-input" type="checkbox" id="inlineCheckbox-g<%- s.value %>" <% if (s.limit) { %>checked<% } %> status="<%- s.value %>" onchange="updateStatusLimit(this, 'gxby');">
+                                                <label class="form-check-label" for="inlineCheckbox-g<%- s.value %>"></label>
+                                            </div>
+                                        </td>
+                                    </tr>
+                                    <% } %>
+                                    </tbody>
+                                </table>
+
+                                <legend>档案管理</legend>
+                                <table class="table table-hover table-bordered">
+                                    <thead><tr><th>值</th><th>名称</th><th>允许计量</th><th>计量比例</th></tr></thead>
+                                    <% for (const s of ctx.session.sessionProject.dagl_status) { %>
+                                    <tbody id="dagl_list">
+                                    <tr>
+                                        <td><%- s.value %></td>
+                                        <td><%- s.name %></td>
+                                        <td>
+                                            <div class="form-check form-check-inline">
+                                                <input class="form-check-input" type="checkbox" id="inlineCheckbox-d<%- s.value %>" <% if (s.limit) { %>checked<% } %> status="<%- s.value %>" onchange="updateStatusLimit(this, 'dagl');">
+                                                <label class="form-check-label" for="inlineCheckbox-d<%- s.value %>"></label>
+                                            </div>
+                                        </td>
+                                        <% if (s.value === 0) { %>
+                                        <td>-</td>
+                                        <% } else { %>
+                                        <td>
+                                            <div class="input-group input-group-sm" style="width:90px">
+                                                <input type="number" class="form-control" max="100" min="0" step="2" value="<%- s.ratio || 0 %>" status="<%- s.value %>" onchange="updateStatusRatio(this);">
+                                                <div class="input-group-append">
+                                                    <span class="input-group-text">%</span>
+                                                </div>
+                                            </div>
+                                        </td>
+                                        <% } %>
+                                    </tr>
+                                    <% } %>
+                                    </tbody>
+                                </table>
+                            </div>
+                        </div>
+                        <div class="tab-pane" id="user-list">
+                            <!--没有标段数据-->
+                            <% if (tenders.length === 0) { %>
+                            <div class="jumbotron m-3">
+                                <h3 class="display-6">没有标段数据</h3>
+                            </div>
+                            <% } else { %>
+                            <table class="table table-hover table-bordered">
+                                <thead>
+                                <tr>
+                                    <th class="text-center" >名称</th>
+                                    <th class="text-center" >计量模式</th>
+                                    <th class="text-center" >计量期数</th>
+                                    <th class="text-center" >创建人</th>
+                                    <th class="text-center" >标段创建时间/期审批时间</th>
+                                    <th class="text-center">工序报验</th>
+                                    <th class="text-center">档案管理</th>
+                                </tr>
+                                </thead>
+                                <% for (const t of tenders) { %>
+                                <tr tid="<%- t.id %>">
+                                    <td><%- t.name %></td>
+                                    <td><%- t.measure_type_str %></td>
+                                    <td><%- t.stage_count_str %></td>
+                                    <td><%- t.user_str %></td>
+                                    <td><%- ctx.moment(t.show_time).format('YYYY-MM-DD HH:mm:ss') %></td>
+                                    <td class="text-center">
+                                        <div class="form-check form-check-inline">
+                                            <input class="form-check-input" type="checkbox" id="inlineCheckbox1" <% if (t.s2b_gxby_check) { %>checked<% } %> name="gxby_check" onchange="updateS2bSetting(this);" value="<%- t.s2b_gxby_check %>">
+                                            <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
+                                            <label class="form-check-label" for="inlineCheckbox1">检查计量</label>
+                                        </div>
+                                        <div class="form-check form-check-inline">
+                                            <input class="form-check-input" type="checkbox" id="inlineCheckbox2" <% if (t.s2b_gxby_limit) { %>checked<% } %> name="gxby_limit" onchange="updateS2bSetting(this);" value="<%- t.s2b_gxby_limit %>">
+                                            <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
+                                            <label class="form-check-label" for="inlineCheckbox2">限制上报</label>
+                                        </div>
+                                    </td>
+                                    <td class="text-center">
+                                        <div class="form-check form-check-inline">
+                                            <input class="form-check-input" type="checkbox" id="inlineCheckbox3" <% if (t.s2b_dagl_check) { %>checked<% } %> name="dagl_check" onchange="updateS2bSetting(this);" value="<%- t.s2b_dagl_check %>">
+                                            <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
+                                            <label class="form-check-label" for="inlineCheckbox3">检查计量</label>
+                                        </div>
+                                        <div class="form-check form-check-inline">
+                                            <input class="form-check-input" type="checkbox" id="inlineCheckbox4" <% if (t.s2b_dagl_limit) { %>checked<% } %> name="dagl_limit" onchange="updateS2bSetting(this);" value="<%- t.s2b_dagl_limit %>">
+                                            <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
+                                            <label class="form-check-label" for="inlineCheckbox4">限制上报</label>
+                                        </div>
+                                    </td>
+                                </tr>
+                                <% } %>
+                            </table>
+                            <% } %>
+                        </div>
+                    </div>
                 </div>
-                <% } %>
             </div>
         </div>
     </div>
 </div>
 <script>
+    const updateStatusLimit = function (obj, type) {
+        const data = { type };
+        data.status = parseInt(obj.getAttribute('status'));
+        data.limit = obj.checked;
+        postData('api/update-status', data, function(result) {
+        }, function () {
+            obj.checked = !obj.checked;
+        });
+    }
+    const updateStatusRatio = function (obj) {
+        const data = { type: 'dagl' };
+        data.status = parseInt(obj.getAttribute('status'));
+        try {
+            data.ratio = parseFloat(obj.value);
+            if (data.ratio > 100 || data.ratio < 0) throw '请输入0-100间的数字';
+        } catch (error) {
+            toastr.warning('请输入0-100间的数字');
+            return;
+        }
+        postData('api/update-status', data, function(result) {
+            obj.org = result.ratio;
+            obj.value = result.ratio;
+        }, function () {
+            obj.value = obj.org;
+        });
+    }
     const updateS2bSetting = function (obj) {
         try {
             const name = obj.getAttribute('name');

+ 2 - 0
app/view/stage/bwtz.ejs

@@ -253,4 +253,6 @@
     };
     const decimal = <%- ctx.tender.info.decimal.tp %>;
     const thousandth = <%- ctx.tender.info.display.thousandth %>;
+    const gxby = <%- ctx.session.sessionProject.gxby %>;
+    const dagl = <%- ctx.session.sessionProject.dagl %>;
 </script>

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

@@ -1607,6 +1607,10 @@
                         <input type="checkbox" class="custom-control-input" id="lc_sibling" checked="">
                         <label class="custom-control-label" for="lc_sibling">项目节清单同层次</label>
                     </div>
+                    <div class="custom-control custom-checkbox mb-2">
+                        <input type="checkbox" class="custom-control-input" id="lc_over" checked="">
+                        <label class="custom-control-label" for="lc_over">超计判断</label>
+                    </div>
                 </div>
             </div>
             <div class="modal-footer">
@@ -1624,6 +1628,7 @@
     const loadLedgerCheckProperty = function () {
         $('#lc_same_code')[0].checked = property.ledger_check.same_code;
         $('#lc_sibling')[0].checked = property.ledger_check.sibling;
+        $('#lc_over')[0].checked = property.ledger_check.over;
     }
     $('#bd-set-10').on('show.bs.modal', function () {
         loadLedgerCheckProperty();
@@ -1633,10 +1638,11 @@
             ledger_check: {
                 same_code: $('#lc_same_code')[0].checked,
                 sibling: $('#lc_sibling')[0].checked,
+                over: $('#lc_over')[0].checked,
             },
         };
         const tenderId = window.location.pathname.split('/')[2];
-        postData('/tender/' + tenderId + '/save', prop, function (data) {
+        postData('/tender/' + tenderId + '/save2', prop, function (data) {
             property.ledger_check = data.ledger_check;
             $('#bd-set-10').modal('hide');
         });

+ 54 - 1
app/view/wap/dashboard.ejs

@@ -36,7 +36,7 @@
         </nav>
         <!--待审批期列表-->
         <div class="py-6">
-            <% if (auditStages.length !== 0 || auditChanges.length !== 0) { %>
+            <% if (auditStages.length !== 0 || auditChanges.length !== 0 || auditRevise.length !== 0 || auditAdvance.length !== 0) { %>
                 <% for (const audit of auditStages) { %>
                 <div class="card mb-3">
                     <div class="card-header d-flex justify-content-between">
@@ -62,6 +62,28 @@
                     </div>
                 </div>
                 <% } %>
+                <% for (const revise of auditRevise) { %>
+                    <div class="card mb-3">
+                        <div class="card-header d-flex justify-content-between">
+                            <span><%- JSON.parse(revise.deal_info).buildName %></span>
+                            <span class="badge badge-pill badge-info">台帐修订</span>
+                        </div>
+                        <div class="bg-light p-2 px-3"><b><%- revise.t_name %></b></div>
+                        <div class="card-body">
+                            <div class="d-flex justify-content-between"><span>第<%- revise.corder %>次修订</span></div>
+                            <div class="my-2">
+                                <table class="table table-sm table-bordered">
+                                    <tr><th width="90">修订时间</th><td class="text-right"><%- ctx.moment(revise.in_time).format('YYYY-MM-DD') %></td></tr>
+                                    <tr><th>修订人</th><td class="text-right"><%- revise.yb_name %></td></tr>
+                                    <tr><th>修订详情</th><td class=""><% if (revise.content.length <= 22) { %><%- revise.content %><% } else { %><%- revise.content.substring(0,22) %><a class="show-content" data-content="<%- revise.content %>" href="javascript:void(0);">展开更多</a><% } %></td></tr>
+                                </table>
+                            </div>
+                            <div class="">
+                                <a href="/wap/tender/<%- revise.t_id %>/revise/<%- revise.id %>/info" class="btn btn-block btn-success">审批</a>
+                            </div>
+                        </div>
+                    </div>
+                <% } %>
                 <% for (const change of auditChanges) { %>
                     <div class="card mb-3">
                         <div class="card-header d-flex justify-content-between">
@@ -85,6 +107,30 @@
                         </div>
                     </div>
                 <% } %>
+                <% for (const advance of auditAdvance) { %>
+                    <div class="card mb-3">
+                        <div class="card-header d-flex justify-content-between">
+                            <span><%- JSON.parse(advance.deal_info).buildName %></span>
+                            <span class="badge badge-pill badge-warning">预付款</span>
+                        </div>
+                        <div class="bg-light p-2 px-3"><b><%- advance.name %></b></div>
+                        <div class="card-body">
+                            <div class="d-flex justify-content-between"><span><%- advanceConst.typeCol[advance.type].name %>-第<%- advance.order %>期</span><span></span></div>
+                            <div class="my-2">
+                                <table class="table table-sm table-bordered">
+                                    <% const advancePayTotal = JSON.parse(advance.deal_param)[advanceConst.typeCol[advance.type].key + 'Advance']; %>
+                                    <tr><th>签约预付款</th><td class="text-right"><%- ctx.helper.formatMoney(advancePayTotal, ',', parseFloat(advancePayTotal).toString().split('.')[1] && parseFloat(advancePayTotal).toString().split('.')[1].length || 0) %></td></tr>
+                                    <tr><th>本期支付比例</th><td class="text-right"><%- advance.pay_ratio %>%</td></tr>
+                                    <tr><th>本期金额</th><td class="text-right"><%- advance.cur_amount %></td></tr>
+                                    <tr><th>截止本期金额</th><td class="text-right"><%- advance.prev_total_amount %></td></tr>
+                                </table>
+                            </div>
+                            <div class="">
+                                <a href="/wap/tender/<%- advance.tid %>/advance/<%- advance.id %>/detail" class="btn btn-block btn-success">审批</a>
+                            </div>
+                        </div>
+                    </div>
+                <% } %>
             <% } else { %>
                 <h3 class="text-center text-muted">暂无待审批期计量</h3>
             <% } %>
@@ -108,6 +154,13 @@
     <script src="/public/js/bootstrap/bootstrap.min.js"></script>
     <script src="/public/js/cookies.js"></script>
     <script src="/public/js/wap/global.js"></script>
+<script>
+    $(function () {
+        $('.show-content').on('click', function () {
+            $(this).parents('td').html($(this).data('content'));
+        });
+    })
+</script>
 </body>
 
 </html>

+ 145 - 0
app/view/wap/shenpi_advance.ejs

@@ -0,0 +1,145 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <title>标段概况-计量支付</title>
+    <link rel="stylesheet" href="/public/css/bootstrap/bootstrap.min.css">
+    <link rel="stylesheet" href="/public/css/wap/main.css">
+    <link rel="stylesheet" href="/public/css/toast.css">
+    <link rel="stylesheet" href="/public/css/font-awesome/font-awesome.min.css">
+    <script src=/public/js/echarts/echarts.min.js></script>
+    <link rel="shortcut icon" href="/public/images/favicon.ico">
+    <style>
+        body {
+            padding: 0;
+        }
+    </style>
+</head>
+<body>
+<div class="container">
+    <!--顶部-->
+    <nav class="fixed-top bg-dark">
+        <div class="my-2 d-flex justify-content-between">
+            <span class="text-white ml-3"><a href="/wap/tender/<%- tender.id %>#yufukuan" class="mr-2 text-white show-loading"><i class="fa fa-chevron-left"></i>预付款</a></span>
+            <a tabindex="0" href="javascript:void(0)" class="text-white text-truncate text-center"
+               style="width:150px" data-toggle="popover" data-placement="top"
+               data-content="<%- tender.name %>" data-trigger="focus"><%- tender.name %></a>
+            <div class="mr-3">
+                <div class="dropdown">
+                    <button class="btn btn-sm btn-light dropdown-toggle" type="button" data-toggle="dropdown">
+                        <%- ctx.session.sessionUser.name.substr(ctx.session.sessionUser.name.length > 2 ? ctx.session.sessionUser.name.length - 2 : 0) %>
+                    </button>
+                    <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
+                        <a class="dropdown-item" href="/wap/logout">退出登录</a>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </nav>
+    <!--标段概况-->
+    <div class="py-6">
+        <ul class="nav nav-tabs nav-fill">
+            <% for (const t of advanceConst.typeCol) { %>
+            <li class="nav-item">
+                <a class="px-1 nav-link <% if (t.key === advanceConst.typeCol[0].key) {  %>active<% } %>" data-toggle="tab" href="#<%- t.key %>" role="tab"><%- t.name %></a>
+            </li>
+            <% } %>
+        </ul>
+        <div class="tab-content">
+            <% for (const t of advanceConst.typeCol) { %>
+            <div class="tab-pane <% if (t.key === advanceConst.typeCol[0].key) {  %>active<% } %>" id="<%- t.key %>">
+                <dl class="mb-2 mt-3">
+                    <% for (const advance of advanceList[t.type]) { %>
+                    <dt class="bg-light p-2 d-flex justify-content-between"><span><%- t.name %>-第<%- advance.order %>期</span>
+                        <span class="<%- auditConst.statusClass[advance.status] %>">
+                            <% if (advance.curAuditor) { %>
+                                <%- advance.curAuditor.name %><%if (advance.curAuditor.role !== '' && advance.curAuditor.role !== null) { %>-<%- advance.curAuditor.role %><% } %>
+                            <% } %>
+                            <%- auditConst.statusString[advance.status] %>
+                        </span>
+                    </dt>
+                    <dd>
+                        <table class="table table-hover">
+                            <tbody>
+                            <tr>
+                                <td>
+                                    <p class="mb-0">签约预付款</p>
+                                </td>
+                                <td class="text-right">
+                                    <b><%- advancePayTotalList[t.type] %></b>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <p class="mb-0">本期支付比例</p>
+                                </td>
+                                <td class="text-right">
+                                    <b><%- advance.pay_ratio %>%</b>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <p class="mb-0">本期金额</p>
+                                </td>
+                                <td class="text-right">
+                                    <b><%- advance.cur_amount %></b>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <p class="mb-0">截止本期金额</p>
+                                </td>
+                                <td class="text-right">
+                                    <b><%- advance.prev_total_amount %></b>
+                                </td>
+                            </tr>
+                            <% if (advance.curAuditor && advance.status == auditConst.status.checking && advance.curAuditor.audit_id === ctx.session.sessionUser.accountId) { %>
+                            <tr>
+                                <td colspan="2">
+                                    <a class="btn btn-block btn-success" href="/wap/tender/<%- tender.id %>/advance/<%- advance.id %>/detail">审批</a>
+                                </td>
+                            </tr>
+                            <% } %>
+                            </tbody></table>
+                    </dd>
+                    <% } %>
+                </dl>
+            </div>
+            <% } %>
+        </div>
+    </div>
+    <!--底栏菜单-->
+    <nav class="fixed-bottom navbar-dark bg-light border-top">
+        <ul class="nav nav-fill my-2">
+            <li class="nav-item">
+                <a class="nav-link text-muted show-loading" href="/wap/dashboard"><i class="fa fa-check-square-o"></i> 待审批</a>
+            </li>
+            <li class="nav-item">
+                <a class="nav-link active show-loading" href="/wap/list"><i class="fa fa-list-ul"></i> 项目</a>
+            </li>
+        </ul>
+    </nav>
+</div>
+<!-- JS. -->
+<script src="/public/js/jquery/jquery-3.2.1.min.js"></script>
+<script src="/public/js/popper/popper.min.js"></script>
+<script src="/public/js/bootstrap/bootstrap.min.js"></script>
+<script src="/public/js/cookies.js"></script>
+<script src="/public/js/wap/global.js"></script>
+<script>
+    $(document).ready(function () {
+        <% for (const t of advanceConst.typeCol) { %>
+        if (window.location.hash && window.location.hash === '#<%- t.key %>') {
+            $('#start').removeClass('active');
+            $('.nav-item a[href="#start"]').removeClass('active');
+
+            $('#<%- t.key %>').addClass('active');
+            $('.nav-item a[href="#<%- t.key %>"]').addClass('active');
+        }
+        <% } %>
+    });
+</script>
+</body>
+</html>

+ 259 - 0
app/view/wap/shenpi_advance_detail.ejs

@@ -0,0 +1,259 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <title>标段概况-计量支付</title>
+    <link rel="stylesheet" href="/public/css/bootstrap/bootstrap.min.css">
+    <link rel="stylesheet" href="/public/css/wap/main.css">
+    <link rel="stylesheet" href="/public/css/toast.css">
+    <link rel="stylesheet" href="/public/css/font-awesome/font-awesome.min.css">
+    <script src=/public/js/echarts/echarts.min.js></script>
+    <link rel="shortcut icon" href="/public/images/favicon.ico">
+    <style>
+        body {
+            padding: 0;
+        }
+    </style>
+</head>
+<body>
+<div class="container">
+    <!--顶部-->
+    <nav class="fixed-top bg-dark">
+        <div class="my-2 d-flex justify-content-between">
+            <span class="text-white ml-3"><a href="/wap/tender/<%- tender.id %>/advance#<%- advanceConst.typeCol[advance.type].key %>" class="mr-2 text-white show-loading"><i class="fa fa-chevron-left"></i><%- advanceConst.typeCol[advance.type].name %></a></span>
+            <a tabindex="0" href="javascript:void(0)" class="text-white text-truncate text-center"
+               style="width:150px" data-toggle="popover" data-placement="top"
+               data-content="<%- tender.name %>" data-trigger="focus"><%- tender.name %></a>
+            <div class="mr-3">
+                <div class="dropdown">
+                    <button class="btn btn-sm btn-light dropdown-toggle" type="button" data-toggle="dropdown">
+                        <%- ctx.session.sessionUser.name.substr(ctx.session.sessionUser.name.length > 2 ? ctx.session.sessionUser.name.length - 2 : 0) %>
+                    </button>
+                    <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
+                        <a class="dropdown-item" href="/wap/logout">退出登录</a>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </nav>
+    <!--标段概况-->
+    <div class="py-6">
+        <!--最新期-->
+        <% let audit = 0; %>
+        <% if (advance) { %>
+            <dl class="mb-2 mt-3">
+                <dt class="bg-light p-2 d-flex justify-content-between"><span><%- advanceConst.typeCol[advance.type].name %>-第<%- advance.order %>期</span>
+                    <span class="<%- auditConst.statusClass[advance.status] %>">
+                        <% if (advance.curAuditor) { %>
+                            <%- advance.curAuditor.name %><%if (advance.curAuditor.role !== '' && advance.curAuditor.role !== null) { %>-<%- advance.curAuditor.role %><% } %>
+                        <% } %>
+                        <%- auditConst.statusString[advance.status] %>
+                        </span>
+                </dt>
+                <dd>
+                    <table class="table table-hover">
+                        <tbody>
+                        <tr>
+                            <td>
+                                <p class="mb-0">签约预付款</p>
+                            </td>
+                            <td class="text-right">
+                                <b><%- advance.advancePayTotal %></b>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td>
+                                <p class="mb-0">本期支付比例</p>
+                            </td>
+                            <td class="text-right">
+                                <b><%- advance.pay_ratio %>%</b>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td>
+                                <p class="mb-0">本期金额</p>
+                            </td>
+                            <td class="text-right">
+                                <b><%- advance.cur_amount %></b>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td>
+                                <p class="mb-0">截止本期金额</p>
+                            </td>
+                            <td class="text-right">
+                                <b><%- advance.prev_total_amount %></b>
+                            </td>
+                        </tr>
+                        </tbody></table>
+                </dd>
+            </dl>
+            <!--审批流程-->
+            <div class="card mt-3">
+                <ul class="list-group list-group-flush">
+                    <li class="list-group-item">
+                        <% if (advance.status === auditConst.status.uncheck) { %>
+                            <span class="pull-right"> 上报中</span>
+                        <% } else { %>
+                            <span class="text-success pull-right"><small><%- advance.auditors[0].create_time.toLocaleDateString() %></small> 上报</span>
+                        <% } %>
+                        <h5 class="card-title"><i class="fa fa-play-circle fa-rotate-90 text-success"></i> <%- advance.user.name %><small class="text-muted"><%- advance.user.role %></small></h5>
+                    </li>
+                    <% for (let iA = 0; iA < advance.auditors.length; iA++) { %>
+                        <% const auditors = advance.auditors; %>
+                        <li class="list-group-item">
+                            <% if (auditors[iA].status === auditConst.status.checked) { %>
+                                <span class="text-success pull-right"><small><%- auditors[iA].end_time.toLocaleDateString() %></small> 审批通过</span>
+                                <h5 class="card-title"><i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down text-success' : 'fa fa-stop-circle text-success') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
+                                <p class="card-text"><%- auditors[iA].opinion %></p>
+                            <% } else if (auditors[iA].status == auditConst.status.checking) { %>
+                                <span class="pull-right">审批中</span>
+                                <h5 class="card-title"><i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down' : 'fa fa-stop-circle') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
+                                <% if (auditors[iA].audit_id === ctx.session.sessionUser.accountId) { %>
+                                    <% audit = auditors[iA]; %>
+                                    <div class="form-group">
+                                        <div class="text-center">
+                                            <button class="btn btn-success" data-toggle="modal" data-target="#sp-done" >审批通过</button>
+                                            <button class="btn btn-warning" data-toggle="modal" data-target="#sp-back" >审批退回</button>
+                                        </div>
+                                    </div>
+                                <% } %>
+                            <% } else if (auditors[iA].status === auditConst.status.checkNoPre) { %>
+                                <% const auditorIndex = advance.auditors2.findIndex(function (item) { return item.audit_id === auditors[iA].audit_id }) %>
+                                <span class="text-warning pull-right"><small><%- auditors[iA].end_time.toLocaleDateString() %></small>审批退回 <%- advance.auditors2[auditorIndex-1].name %></span>
+                                <h5 class="card-title"><i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down text-warning' : 'fa fa-stop-circle text-warning') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
+                                <p class="card-text"><%- auditors[iA].opinion %></p>
+                            <% } else if (auditors[iA].status === auditConst.status.checkNo) { %>
+                                <span class="text-warning pull-right"><small><%- auditors[iA].end_time.toLocaleDateString() %></small>审批退回</span>
+                                <h5 class="card-title"><i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down text-warning' : 'fa fa-stop-circle text-warning') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
+                                <p class="card-text"><%- auditors[iA].opinion %></p>
+                            <% } else { %>
+                                <h5 class="card-title"><i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down' : 'fa fa-stop-circle') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
+                            <% } %>
+                        </li>
+                    <% } %>
+                </ul>
+            </div>
+        <% } %>
+    </div>
+    <!--底栏菜单-->
+    <nav class="fixed-bottom navbar-dark bg-light border-top">
+        <ul class="nav nav-fill my-2">
+            <li class="nav-item">
+                <a class="nav-link text-muted show-loading" href="/wap/dashboard"><i class="fa fa-check-square-o"></i> 待审批</a>
+            </li>
+            <li class="nav-item">
+                <a class="nav-link active show-loading" href="/wap/list"><i class="fa fa-list-ul"></i> 项目</a>
+            </li>
+        </ul>
+    </nav>
+</div>
+<!--审批通过弹窗-->
+<div class="modal" tabindex="-1" role="dialog" id="sp-done">
+    <div class="modal-dialog" role="document">
+        <form class="modal-content" action="/tender/<%- tender.id %>/advance/<%- advance.id %>/audit/check" method="post" id="audit-check0" onsubmit="auditCheck(0)">
+            <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="form-group">
+                    <label>审批意见</label>
+                    <textarea class="form-control" rows="8" name="opinion">同意</textarea>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
+                <input type="hidden" name="checkType" value="<%= auditConst.status.checked %>" />
+                <button type="submit" class="btn btn-success">审批通过</button>
+            </div>
+        </form>
+    </div>
+</div>
+<!--审批退回弹窗-->
+<div class="modal" tabindex="-1" role="dialog" id="sp-back">
+    <div class="modal-dialog" role="document">
+        <form class="modal-content" action="/tender/<%- advance.tid %>/advance/<%- advance.id %>/audit/check" method="post" id="audit-check1" onsubmit="auditCheck(1)">
+            <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="form-group">
+                    <label>审批意见</label>
+                    <textarea class="form-control" rows="8" name="opinion">不同意</textarea>
+                </div>
+                <div class="alert alert-warning">
+                    <div class="custom-control custom-radio custom-control-inline">
+                        <input type="radio" id="customRadioInline1" name="checkType" class="custom-control-input" value="<%- auditConst.status.checkNo %>" <% if (audit.order === 1 || audit.audit_id === advance.auditors[0].audit_id) { %>checked<% } %>>
+                        <label class="custom-control-label" for="customRadioInline1">退回原报 <%- advance.user.name %></label>
+                    </div>
+                    <% if (audit.order > 1 && audit.audit_id !== advance.auditors[0].audit_id) { %>
+                        <% const auditorIndex = advance.auditors2.findIndex(function (item) { return item.audit_id === audit.audit_id }) %>
+                        <div class="custom-control custom-radio custom-control-inline">
+                            <input class="custom-control-input" type="radio" name="checkType" id="customRadioInline2" value="<%- auditConst.status.checkNoPre %>" checked>
+                            <label class="custom-control-label" for="customRadioInline2">退回上一审批人 <%- advance.auditors2[auditorIndex-1].name %></label>
+                        </div>
+                    <% } %>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
+                <button type="submit" class="btn btn-warning">确认退回</button>
+            </div>
+        </form>
+    </div>
+</div>
+<!-- JS. -->
+<script src="/public/js/jquery/jquery-3.2.1.min.js"></script>
+<script src="/public/js/popper/popper.min.js"></script>
+<script src="/public/js/bootstrap/bootstrap.min.js"></script>
+<script src="/public/js/cookies.js"></script>
+<script src="/public/js/wap/global.js"></script>
+<script>
+    // $(document).ready(function () {
+    //     $('#audit-check0').submit(function (e) {
+    //         if (auditCheck(0)) {
+    //             const data = {
+    //                 opinion: $('[name=opinion]', this).val(),
+    //                 checkType: parseInt($('[name=checkType]', this).val()),
+    //             };
+    //             postData(this.action, data, function () {
+    //                 window.location.reload();
+    //             });
+    //         }
+    //         return false;
+    //     });
+    //     $('#audit-check1').submit(function (e) {
+    //         if (auditCheck(1)) {
+    //             const data = {
+    //                 opinion: $('[name=opinion]', this).val(),
+    //                 checkType: parseInt($('[name=checkType]:checked', this).val()),
+    //             };
+    //             postData(this.action, data, function () {
+    //                 window.location.reload();
+    //             });
+    //         }
+    //         return false;
+    //     });
+    // })
+
+    // texterea换行
+
+    function auditCheck(i) {
+        const opinion = $('textarea[name="opinion"]').eq(i).val().replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\s/g, ' ');
+        $('textarea[name="opinion"]').eq(i).val(opinion);
+        return true;
+    }
+</script>
+</body>
+
+</html>

+ 1 - 1
app/view/wap/shenpi_change.ejs

@@ -21,7 +21,7 @@
     <!--顶部-->
     <nav class="fixed-top bg-dark">
         <div class="my-2 d-flex justify-content-between">
-            <span class="text-white ml-3"><a href="/wap/tender/<%- tender.id %>" class="mr-2 text-white show-loading"><i class="fa fa-chevron-left"></i>工程变更</a></span>
+            <span class="text-white ml-3"><a href="/wap/tender/<%- tender.id %>#biangeng" class="mr-2 text-white show-loading"><i class="fa fa-chevron-left"></i>工程变更</a></span>
             <a tabindex="0" href="javascript:void(0)" class="text-white text-truncate text-center"
                style="width:150px" data-toggle="popover" data-placement="top"
                data-content="<%- tender.name %>" data-trigger="focus"><%- tender.name %></a>

+ 225 - 0
app/view/wap/shenpi_revise.ejs

@@ -0,0 +1,225 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <title>标段概况-计量支付</title>
+    <link rel="stylesheet" href="/public/css/bootstrap/bootstrap.min.css">
+    <link rel="stylesheet" href="/public/css/wap/main.css">
+    <link rel="stylesheet" href="/public/css/toast.css">
+    <link rel="stylesheet" href="/public/css/font-awesome/font-awesome.min.css">
+    <script src=/public/js/echarts/echarts.min.js></script>
+    <link rel="shortcut icon" href="/public/images/favicon.ico">
+    <style>
+        body {
+            padding: 0;
+        }
+    </style>
+</head>
+<body>
+<div class="container">
+    <!--顶部-->
+    <nav class="fixed-top bg-dark">
+        <div class="my-2 d-flex justify-content-between">
+            <span class="text-white ml-3"><a href="/wap/tender/<%- tender.id %>#tzxiuding" class="mr-2 text-white show-loading"><i class="fa fa-chevron-left"></i>台账修订</a></span>
+            <a tabindex="0" href="javascript:void(0)" class="text-white text-truncate text-center"
+               style="width:150px" data-toggle="popover" data-placement="top"
+               data-content="<%- tender.name %>" data-trigger="focus"><%- tender.name %></a>
+            <div class="mr-3">
+                <div class="dropdown">
+                    <button class="btn btn-sm btn-light dropdown-toggle" type="button" data-toggle="dropdown">
+                        <%- ctx.session.sessionUser.name.substr(ctx.session.sessionUser.name.length > 2 ? ctx.session.sessionUser.name.length - 2 : 0) %>
+                    </button>
+                    <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
+                        <a class="dropdown-item" href="/wap/logout">退出登录</a>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </nav>
+    <!--标段概况-->
+    <div class="py-6">
+        <!--最新期-->
+        <% let audit = 0; %>
+        <% if (revise) { %>
+            <dl class="mb-2 mt-3">
+                <dt class="bg-light p-2 d-flex justify-content-between"><span>第<%- revise.corder %>次修订</span>
+                    <% if (!revise.valid) {%>
+                    <span class="text-danger">
+                        作废
+                    </span>
+                    <% } else { %>
+                    <span class="<%- auditConst.auditStringClass[revise.status] %>">
+                        <% if (revise.curAuditor && revise.status !== auditConst.status.checked) { %>
+                            <%- revise.curAuditor.name %><%if (revise.curAuditor.role !== '' && revise.curAuditor.role !== null) { %>-<%- revise.curAuditor.role %><% } %>
+                        <% } %>
+                        <%- revise.status === auditConst.status.checked ? '审批完成' : auditConst.auditProgress[revise.status] %>
+                    </span>
+                    <% } %>
+                </dt>
+                <dd>
+                    <table class="table table-hover">
+                        <tr><td width="90">修订时间</td><td><%- ctx.moment(revise.in_time).format('YYYY-MM-DD') %></td></tr>
+                        <tr><td>修订人</td><td><%- revise.user.name %></td></tr>
+                        <tr><td>修订详情</td><td><%- revise.content %></td></tr>
+                    </table>
+                </dd>
+            </dl>
+            <!--审批流程-->
+            <div class="card mt-3">
+                <ul class="list-group list-group-flush">
+                    <li class="list-group-item">
+                        <% if (!revise.valid) { %>
+                            <span class="text-danger pull-right"> 作废</span>
+                        <% } else if (revise.status === auditConst.status.uncheck) { %>
+                            <span class="pull-right"> 上报中</span>
+                        <% } else { %>
+                            <span class="text-success pull-right"><small><%- revise.auditors[0].begin_time.toLocaleDateString() %></small> 上报</span>
+                        <% } %>
+                        <h5 class="card-title"><i class="fa fa-play-circle fa-rotate-90 text-success"></i> <%- revise.user.name %><small class="text-muted"><%- revise.user.role %></small></h5>
+                    </li>
+                    <% for (let iA = 0; iA < revise.auditors.length; iA++) { %>
+                        <% const auditors = revise.auditors; %>
+                        <li class="list-group-item">
+                            <% if (auditors[iA].status === auditConst.status.checked) { %>
+                                <span class="text-success pull-right"><small><%- auditors[iA].end_time.toLocaleDateString() %></small> 审批通过</span>
+                                <h5 class="card-title"><i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down text-success' : 'fa fa-stop-circle text-success') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
+                                <p class="card-text"><%- auditors[iA].opinion %></p>
+                            <% } else if (auditors[iA].status == auditConst.status.checking) { %>
+                                <span class="pull-right">审批中</span>
+                                <h5 class="card-title"><i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down' : 'fa fa-stop-circle') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
+                                <% if (auditors[iA].audit_id === ctx.session.sessionUser.accountId) { %>
+                                    <% audit = auditors[iA]; %>
+                                    <div class="form-group">
+                                        <div class="text-center">
+                                            <button class="btn btn-success" data-toggle="modal" data-target="#sp-done" >审批通过</button>
+                                            <button class="btn btn-warning" data-toggle="modal" data-target="#sp-back" >审批退回</button>
+                                        </div>
+                                    </div>
+                                <% } %>
+                            <% } else if (auditors[iA].status === auditConst.status.checkNo) { %>
+                                <span class="text-warning pull-right"><small><%- auditors[iA].end_time.toLocaleDateString() %></small>审批退回</span>
+                                <h5 class="card-title"><i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down text-warning' : 'fa fa-stop-circle text-warning') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
+                                <p class="card-text"><%- auditors[iA].opinion %></p>
+                            <% } else { %>
+                                <h5 class="card-title"><i class="<%- (iA < auditors.length - 1 ? 'fa fa-chevron-circle-down' : 'fa fa-stop-circle') %>"></i> <%- auditors[iA].name %> <small class="text-muted"><%- auditors[iA].role %></small></h5>
+                            <% } %>
+                        </li>
+                    <% } %>
+                </ul>
+            </div>
+        <% } %>
+    </div>
+    <!--底栏菜单-->
+    <nav class="fixed-bottom navbar-dark bg-light border-top">
+        <ul class="nav nav-fill my-2">
+            <li class="nav-item">
+                <a class="nav-link text-muted show-loading" href="/wap/dashboard"><i class="fa fa-check-square-o"></i> 待审批</a>
+            </li>
+            <li class="nav-item">
+                <a class="nav-link active show-loading" href="/wap/list"><i class="fa fa-list-ul"></i> 项目</a>
+            </li>
+        </ul>
+    </nav>
+</div>
+<!--审批通过弹窗-->
+<div class="modal" tabindex="-1" role="dialog" id="sp-done">
+    <div class="modal-dialog" role="document">
+        <form class="modal-content" action="/tender/<%- tender.id %>/revise/audit/check" method="post" id="audit-check0" onsubmit="auditCheck(0)">
+            <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="form-group">
+                    <label>审批意见</label>
+                    <textarea class="form-control" rows="8" name="opinion">同意</textarea>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
+                <input type="hidden" name="checkType" value="<%= auditConst.status.checked %>" />
+                <button type="submit" class="btn btn-success">审批通过</button>
+            </div>
+        </form>
+    </div>
+</div>
+<!--审批退回弹窗-->
+<div class="modal" tabindex="-1" role="dialog" id="sp-back">
+    <div class="modal-dialog" role="document">
+        <form class="modal-content" action="/tender/<%- revise.tid %>/revise/audit/check" method="post" id="audit-check1" onsubmit="auditCheck(1)">
+            <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="form-group">
+                    <label>审批意见</label>
+                    <textarea class="form-control" rows="8" name="opinion">不同意</textarea>
+                </div>
+                <div class="alert alert-warning">
+                    <div class="custom-control custom-radio custom-control-inline">
+                        <input type="radio" id="customRadioInline1" name="checkType" checked class="custom-control-input" value="<%- auditConst.status.checkNo %>" <% if (audit.order === 1 || audit.audit_id === revise.auditors[0].audit_id) { %>checked<% } %>>
+                        <label class="custom-control-label" for="customRadioInline1">退回原报 <%- revise.user.name %></label>
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
+                <button type="submit" class="btn btn-warning">确认退回</button>
+            </div>
+        </form>
+    </div>
+</div>
+<!-- JS. -->
+<script src="/public/js/jquery/jquery-3.2.1.min.js"></script>
+<script src="/public/js/popper/popper.min.js"></script>
+<script src="/public/js/bootstrap/bootstrap.min.js"></script>
+<script src="/public/js/cookies.js"></script>
+<script src="/public/js/wap/global.js"></script>
+<script>
+    // $(document).ready(function () {
+    //     $('#audit-check0').submit(function (e) {
+    //         if (auditCheck(0)) {
+    //             const data = {
+    //                 opinion: $('[name=opinion]', this).val(),
+    //                 checkType: parseInt($('[name=checkType]', this).val()),
+    //             };
+    //             postData(this.action, data, function () {
+    //                 window.location.reload();
+    //             });
+    //         }
+    //         return false;
+    //     });
+    //     $('#audit-check1').submit(function (e) {
+    //         if (auditCheck(1)) {
+    //             const data = {
+    //                 opinion: $('[name=opinion]', this).val(),
+    //                 checkType: parseInt($('[name=checkType]:checked', this).val()),
+    //             };
+    //             postData(this.action, data, function () {
+    //                 window.location.reload();
+    //             });
+    //         }
+    //         return false;
+    //     });
+    // })
+
+    // texterea换行
+
+    function auditCheck(i) {
+        const opinion = $('textarea[name="opinion"]').eq(i).val().replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\s/g, ' ');
+        $('textarea[name="opinion"]').eq(i).val(opinion);
+        return true;
+    }
+</script>
+</body>
+
+</html>

+ 1 - 1
app/view/wap/shenpi_stage.ejs

@@ -22,7 +22,7 @@
     <!--顶部-->
     <nav class="fixed-top bg-dark">
         <div class="my-2 d-flex justify-content-between">
-            <span class="text-white ml-3"><a href="/wap/tender/<%- tender.id %>" class="mr-2 text-white show-loading"><i class="fa fa-chevron-left"></i>计量期</a></span>
+            <span class="text-white ml-3"><a href="/wap/tender/<%- tender.id %>#jlqi" class="mr-2 text-white show-loading"><i class="fa fa-chevron-left"></i>计量期</a></span>
             <a tabindex="0" href="javascript:void(0)" class="text-white text-truncate text-center"
                style="width:150px" data-toggle="popover" data-placement="top"
                data-content="<%- tender.name %>" data-trigger="focus"><%- tender.name %></a>

+ 95 - 3
app/view/wap/tender.ejs

@@ -15,6 +15,15 @@
         body {
             padding: 0;
         }
+        .tab-content > .tab-pane,.pill-content > .pill-pane {
+            display: block;
+            height: 0;
+            overflow-y: hidden;
+        }
+
+        .tab-content > .active,.pill-content > .active {
+            height: auto;
+        }
     </style>
 </head>
 <body>
@@ -43,13 +52,19 @@
         <!--标签-->
         <ul class="nav nav-tabs nav-fill">
             <li class="nav-item">
-                <a class="nav-link active" data-toggle="tab" href="#gaikuang" role="tab">概况</a>
+                <a class="px-1 nav-link active" data-toggle="tab" href="#gaikuang" role="tab">概况</a>
+            </li>
+            <li class="nav-item">
+                <a class="px-1 nav-link" data-toggle="tab" href="#yufukuan" role="tab">预付款</a>
             </li>
             <li class="nav-item">
-                <a class="nav-link" data-toggle="tab" href="#jlqi" role="tab">计量期</a>
+                <a class="px-1 nav-link" data-toggle="tab" href="#tzxiuding" role="tab">台帐修订</a>
             </li>
             <li class="nav-item">
-                <a class="nav-link" data-toggle="tab" href="#biangeng" role="tab">工程变更</a>
+                <a class="px-1 nav-link" data-toggle="tab" href="#jlqi" role="tab">计量期</a>
+            </li>
+            <li class="nav-item">
+                <a class="px-1 nav-link" data-toggle="tab" href="#biangeng" role="tab">工程变更</a>
             </li>
         </ul>
         <div class="tab-content">
@@ -76,6 +91,49 @@
                     </div>
                 </div>
             </div>
+            <div class="tab-pane" id="yufukuan">
+                <% for (const t of advanceConst.typeCol) { %>
+                <div class="card my-3">
+                    <div class="card-body">
+                        <a href="/wap/tender/<%- tender.id %>/advance#<%- t.key %>"><h5 class="card-title d-flex justify-content-between"><%- t.name %><span><% if (advanceList[t.type]) { %>第<%- advanceList[t.type].order %>期<% } %></span></h5></a>
+                    </div>
+                </div>
+                <% } %>
+            </div>
+            <div class="tab-pane" id="tzxiuding">
+                <dl class="mb-2 mt-3">
+                    <% for (const lr of revises) { %>
+                    <dt class="bg-light p-2 d-flex justify-content-between"><span>第<%- lr.corder %>次修订</span>
+                        <% if (!lr.valid) {%>
+                        <span class="text-danger">
+                            作废
+                        </span>
+                        <% } else { %>
+                        <span class="<%- auditReviseConst.auditStringClass[lr.status] %>">
+                            <% if (lr.curAuditor && lr.status !== auditReviseConst.status.checked) { %>
+                                <%- lr.curAuditor.name %><%if (lr.curAuditor.role !== '' && lr.curAuditor.role !== null) { %>-<%- lr.curAuditor.role %><% } %>
+                            <% } %>
+                            <%- lr.status === auditReviseConst.status.checked ? '审批完成' : auditReviseConst.auditProgress[lr.status] %>
+                        </span>
+                        <% } %>
+                    </dt>
+                    <dd>
+                        <table class="table table-hover">
+                            <tr><td width="90">修订时间</td><td><%- ctx.moment(lr.in_time).format('YYYY-MM-DD') %></td></tr>
+                            <tr><td>修订人</td><td><%- lr.user_name %></td></tr>
+                            <tr><td>修订详情</td><td><% if (lr.content) { %><% if (lr.content.length <= 22) { %><%- lr.content %><% } else { %><%- lr.content.substring(0,22) %><a class="show-content" data-content="<%- lr.content %>" href="javascript:void(0);">展开更多</a><% } %><% } %></td></tr>
+                            <% if (lr.curAuditor && lr.status == auditReviseConst.status.checking && lr.curAuditor.audit_id === ctx.session.sessionUser.accountId) { %>
+                            <tr>
+                                <td colspan="2">
+                                    <a class="btn btn-block btn-success" href="/wap/tender/<%- tender.id %>/revise/<%- lr.id %>/info">审批</a>
+                                </td>
+                            </tr>
+                            <% } %>
+                        </table>
+                    </dd>
+                    <% } %>
+                </dl>
+            </div>
             <div class="tab-pane" id="jlqi">
                 <!--期列表-->
                 <dl class="mb-2 mt-3">
@@ -418,6 +476,40 @@
     myChart.setOption(option);
     //3 标段月进度//
 </script>
+<script>
+    $(document).ready(function () {
+        if (window.location.hash && window.location.hash === '#yufukuan') {
+            $('#gaikuang').removeClass('active');
+            $('.nav-item a[href="#gaikuang"]').removeClass('active');
+
+            $('#yufukuan').addClass('active');
+            $('.nav-item a[href="#yufukuan"]').addClass('active');
+        } else if (window.location.hash && window.location.hash === '#tzxiuding') {
+            $('#gaikuang').removeClass('active');
+            $('.nav-item a[href="#gaikuang"]').removeClass('active');
+
+            $('#tzxiuding').addClass('active');
+            $('.nav-item a[href="#tzxiuding"]').addClass('active');
+        } else if (window.location.hash && window.location.hash === '#jlqi') {
+            $('#gaikuang').removeClass('active');
+            $('.nav-item a[href="#gaikuang"]').removeClass('active');
+
+            $('#jlqi').addClass('active');
+            $('.nav-item a[href="#jlqi"]').addClass('active');
+        } else if (window.location.hash && window.location.hash === '#biangeng') {
+            $('#gaikuang').removeClass('active');
+            $('.nav-item a[href="#gaikuang"]').removeClass('active');
+
+            $('#biangeng').addClass('active');
+            $('.nav-item a[href="#biangeng"]').addClass('active');
+        }
+
+        $('.show-content').on('click', function () {
+            $(this).parents('td').html($(this).data('content'));
+        });
+
+    });
+</script>
 </body>
 
 </html>

+ 74 - 1
builder_report_index_define.js

@@ -1692,6 +1692,79 @@ const jh_gather_im_change = {
         { name: '本期-数量变更-金额_4', field: 'r4_qc_tp', type: dataType.currency },
     ],
 };
+const jh_gather_stage_bills_compare = {
+    name: '【定制】季华-期-清单-汇总-多审 数据表(mem_jh_gather_stage_bills_compare)',
+    remark: '',
+    id: 64,
+    key: 'mem_jh_gather_stage_bills_compare',
+    prefix: '【定制】季华-期-清单-汇总-多审',
+    cols: [
+        { name: '项目节编号', field: 'code', type: dataType.str },
+        { name: '清单编号', field: 'b_code', type: dataType.str },
+        { name: '名称', field: 'name', type: dataType.str },
+        { name: '单位', field: 'unit', type: dataType.str },
+        { name: '单价', field: 'unit_price', type: dataType.currency },
+
+        { name: '(合计)台账-数量', field: 's_qty', type: dataType.currency },
+        { name: '(合计)台账-金额', field: 's_tp', type: dataType.currency },
+
+        { name: '(合计)本期-合同-数量', field: 's_contract_qty', type: dataType.currency },
+        { name: '(合计)本期-合同-金额', field: 's_contract_tp', type: dataType.currency },
+        { name: '(合计)本期-变更-数量', field: 's_qc_qty', type: dataType.currency },
+        { name: '(合计)本期-变更-金额', field: 's_qc_tp', type: dataType.currency },
+        { name: '(合计)本期-完成-数量', field: 's_gather_qty', type: dataType.currency },
+        { name: '(合计)本期-完成-金额', field: 's_gather_tp', type: dataType.currency },
+
+        { name: '(合计)截止上期-合同-数量', field: 's_pre_contract_qty', type: dataType.currency },
+        { name: '(合计)截止上期-合同-金额', field: 's_pre_contract_tp', type: dataType.currency },
+        { name: '(合计)截止上期-变更-数量', field: 's_pre_qc_qty', type: dataType.currency },
+        { name: '(合计)截止上期-变更-金额', field: 's_pre_qc_tp', type: dataType.currency },
+        { name: '(合计)截止上期-完成-数量', field: 's_pre_gather_qty', type: dataType.currency },
+        { name: '(合计)截止上期-完成-金额', field: 's_pre_gather_tp', type: dataType.currency },
+
+        { name: '(合计)截止本期-合同-数量', field: 's_end_contract_qty', type: dataType.currency },
+        { name: '(合计)截止本期-合同-金额', field: 's_end_contract_tp', type: dataType.currency },
+        { name: '(合计)截止本期-变更-数量', field: 's_end_qc_qty', type: dataType.currency },
+        { name: '(合计)截止本期-变更-金额', field: 's_end_qc_tp', type: dataType.currency },
+        { name: '(合计)截止本期-完成-数量', field: 's_end_gather_qty', type: dataType.currency },
+        { name: '(合计)截止本期-完成-金额', field: 's_end_gather_tp', type: dataType.currency },
+
+        { name: '(原报)本期-合同-数量', field: 'r0_contract_qty', type: dataType.currency },
+        { name: '(原报)本期-合同-金额', field: 'r0_contract_tp', type: dataType.currency },
+        { name: '(原报)本期-变更-数量', field: 'r0_qc_qty', type: dataType.currency },
+        { name: '(原报)本期-变更-金额', field: 'r0_qc_tp', type: dataType.currency },
+        { name: '(原报)本期-完成-数量', field: 'r0_gather_qty', type: dataType.currency },
+        { name: '(原报)本期-完成-金额', field: 'r0_gather_tp', type: dataType.currency },
+
+        { name: '(1审)本期-合同-数量', field: 'r1_contract_qty', type: dataType.currency },
+        { name: '(1审)本期-合同-金额', field: 'r1_contract_tp', type: dataType.currency },
+        { name: '(1审)本期-变更-数量', field: 'r1_qc_qty', type: dataType.currency },
+        { name: '(1审)本期-变更-金额', field: 'r1_qc_tp', type: dataType.currency },
+        { name: '(1审)本期-完成-数量', field: 'r1_gather_qty', type: dataType.currency },
+        { name: '(1审)本期-完成-金额', field: 'r1_gather_tp', type: dataType.currency },
+
+        { name: '(2审)本期-合同-数量', field: 'r2_contract_qty', type: dataType.currency },
+        { name: '(2审)本期-合同-金额', field: 'r2_contract_tp', type: dataType.currency },
+        { name: '(2审)本期-变更-数量', field: 'r2_qc_qty', type: dataType.currency },
+        { name: '(2审)本期-变更-金额', field: 'r2_qc_tp', type: dataType.currency },
+        { name: '(2审)本期-完成-数量', field: 'r2_gather_qty', type: dataType.currency },
+        { name: '(2审)本期-完成-金额', field: 'r2_gather_tp', type: dataType.currency },
+
+        { name: '(3审)本期-合同-数量', field: 'r3_contract_qty', type: dataType.currency },
+        { name: '(3审)本期-合同-金额', field: 'r3_contract_tp', type: dataType.currency },
+        { name: '(3审)本期-变更-数量', field: 'r3_qc_qty', type: dataType.currency },
+        { name: '(3审)本期-变更-金额', field: 'r3_qc_tp', type: dataType.currency },
+        { name: '(3审)本期-完成-数量', field: 'r3_gather_qty', type: dataType.currency },
+        { name: '(3审)本期-完成-金额', field: 'r3_gather_tp', type: dataType.currency },
+
+        { name: '树结构-id', field: 'id', type: dataType.int },
+        { name: '树结构-父项id', field: 'pid', type: dataType.int },
+        { name: '树结构-层次', field: 'level', type: dataType.int },
+        { name: '树结构-排序', field: 'order', type: dataType.int },
+        { name: '树结构-完整路径', field: 'full_path', type: dataType.str },
+        { name: '树结构-是否子项', field: 'is_leaf', type: dataType.int },
+    ],
+};
 
 const custom_select = {
     name: '【用户交互】用户选择信息 数据表(mem_custom_select)',
@@ -1829,7 +1902,7 @@ const defines = [
     stage_change, stage_change_bills, stage_change_ledger,
     gcl_gather_bills, gcl_gather_xmj,
     ledger_tag, stage_tag, all_tag,
-    jh_im_change, jh_gather_im_change,
+    jh_im_change, jh_gather_im_change, jh_gather_stage_bills_compare,
     custom_select,
 ];
 for (const d of defines) {