Browse Source

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

# Conflicts:
#	app/view/report/index.ejs
TonyKang 4 years ago
parent
commit
7f853ea732
100 changed files with 1167 additions and 584 deletions
  1. 6 1
      app.js
  2. 2 2
      app/base/base_service.js
  3. 0 1
      app/const/spread.js
  4. 2 0
      app/const/tender_info.js
  5. 4 1
      app/controller/change_controller.js
  6. 4 3
      app/controller/ledger_controller.js
  7. 4 3
      app/controller/login_controller.js
  8. 64 2
      app/controller/setting_controller.js
  9. 31 28
      app/controller/stage_controller.js
  10. 43 5
      app/controller/tender_controller.js
  11. 0 16
      app/controller/wechat_controller.js
  12. 108 11
      app/extend/helper.js
  13. 18 4
      app/lib/analysis_excel.js
  14. 3 0
      app/lib/gcl_gather.js
  15. 64 0
      app/lib/rpt_data_analysis.js
  16. 2 1
      app/middleware/change_check.js
  17. 12 0
      app/middleware/material_check.js
  18. 4 0
      app/middleware/sort_filter.js
  19. 18 1
      app/middleware/stage_check.js
  20. 6 1
      app/middleware/tender_check.js
  21. 2 2
      app/middleware/uncheck_tender_check.js
  22. 6 6
      app/public/js/bootstrap/bootstrap-paginator.js
  23. 1 1
      app/public/js/change_approval.js
  24. 1 1
      app/public/js/change_detail.js
  25. 1 1
      app/public/js/change_information_approval.js
  26. 63 5
      app/public/js/change_information_set.js
  27. 1 1
      app/public/js/change_information_show.js
  28. 72 4
      app/public/js/global.js
  29. 3 3
      app/public/js/ledger.js
  30. 34 67
      app/public/js/ledger_check.js
  31. 0 169
      app/public/js/number-precision.js
  32. 2 2
      app/public/js/profile.js
  33. 8 1
      app/public/js/setting.js
  34. 1 0
      app/public/js/shares/cs_tools.js
  35. 4 2
      app/public/js/spreadjs_rela/spreadjs_zh.js
  36. 3 39
      app/public/js/stage.js
  37. 1 1
      app/public/js/stage_audit.js
  38. 15 6
      app/public/js/stage_gather.js
  39. 2 2
      app/public/js/stage_pay.js
  40. 1 1
      app/public/js/wap/global.js
  41. 4 4
      app/public/report/js/rpt_main.js
  42. 1 1
      app/public/report/js/rpt_preview_common.js
  43. 1 1
      app/public/report/js/rpt_print.js
  44. 4 4
      app/public/report/js/rpt_signature.js
  45. 5 2
      app/router.js
  46. 4 1
      app/service/advance.js
  47. 69 66
      app/service/change.js
  48. 7 3
      app/service/change_audit.js
  49. 50 1
      app/service/change_audit_list.js
  50. 1 1
      app/service/customer.js
  51. 1 1
      app/service/material.js
  52. 2 2
      app/service/message.js
  53. 30 0
      app/service/project.js
  54. 8 14
      app/service/project_account.js
  55. 30 6
      app/service/report.js
  56. 58 2
      app/service/report_memory.js
  57. 14 1
      app/service/stage.js
  58. 3 2
      app/service/stage_audit.js
  59. 5 4
      app/service/stage_bills_final.js
  60. 1 1
      app/service/stage_jgcl.js
  61. 1 1
      app/service/stage_pos_final.js
  62. 3 0
      app/service/tender.js
  63. 66 0
      app/service/tender_tourist.js
  64. 1 1
      app/service/version.js
  65. 1 1
      app/view/account/index.ejs
  66. 1 1
      app/view/advance/index.ejs
  67. 2 2
      app/view/advance/modal_audit.ejs
  68. 1 1
      app/view/boot/index.ejs
  69. 6 2
      app/view/change/index.ejs
  70. 1 1
      app/view/change/info.ejs
  71. 4 4
      app/view/change/info_modal.ejs
  72. 11 3
      app/view/change/information.ejs
  73. 7 7
      app/view/change/information_modal.ejs
  74. 1 1
      app/view/change/modal.ejs
  75. 1 1
      app/view/dashboard/msg_add.ejs
  76. 44 2
      app/view/layout/page.ejs
  77. 3 3
      app/view/ledger/audit_modal.ejs
  78. 2 2
      app/view/ledger/explode_modal.ejs
  79. 3 3
      app/view/login/login.ejs
  80. 1 1
      app/view/login/login_port.ejs
  81. 2 0
      app/view/material/audit_btn.ejs
  82. 10 8
      app/view/material/audit_modal.ejs
  83. 2 0
      app/view/material/file.ejs
  84. 2 2
      app/view/material/modal.ejs
  85. 2 2
      app/view/measure/audit_modal.ejs
  86. 2 2
      app/view/measure/stage_modal.ejs
  87. 1 1
      app/view/profile/info.ejs
  88. 1 1
      app/view/profile/safe.ejs
  89. 2 2
      app/view/profile/sms.ejs
  90. 1 1
      app/view/profile/wechat.ejs
  91. 1 1
      app/view/profile/wechat_modal.ejs
  92. 1 1
      app/view/project/info.ejs
  93. 2 2
      app/view/report/rpt_all_popup.ejs
  94. 4 4
      app/view/revise/info_modal.ejs
  95. 2 2
      app/view/revise/modal.ejs
  96. 51 0
      app/view/setting/fun.ejs
  97. 1 1
      app/view/setting/info.ejs
  98. 4 4
      app/view/setting/user_modal.ejs
  99. 2 2
      app/view/setting/user_permission_modal.ejs
  100. 0 0
      app/view/stage/audit_btn.ejs

+ 6 - 1
app.js

@@ -73,7 +73,12 @@ module.exports = app => {
     });
 
     //压缩前端js
-    app.jsFiles = { common: JsFiles.commonFiles };
+    if (app.config.min) {
+        app.jsFiles = { common: JsFiles.commonFiles };
+        app.jsFiles.common.push('/public/js/web/global' + '.' + app.config.version + '.min.js');
+    } else {
+        app.jsFiles = { common: JsFiles.commonFiles.concat(JsFiles.needMin) };
+    }
     for (const c in JsFiles.controller) {
         const controller = JsFiles.controller[c];
         app.jsFiles[c] = {};

+ 2 - 2
app/base/base_service.js

@@ -170,8 +170,8 @@ class BaseService extends Service {
         }
 
         // 分页相关
-        this.sqlBuilder.limit = this.app.config.pageSize;
-        this.sqlBuilder.offset = this.app.config.pageSize * (this.ctx.page - 1);
+        this.sqlBuilder.limit = this.ctx.pageSize ? this.ctx.pageSize : this.app.config.pageSize;
+        this.sqlBuilder.offset = this.sqlBuilder.limit * (this.ctx.page - 1);
 
         // 数据筛选
         if (this.ctx.sort !== undefined && this.ctx.sort.length > 0) {

+ 0 - 1
app/const/spread.js

@@ -545,7 +545,6 @@ const blank = {
     font: '12px 微软雅黑',
 };
 
-
 module.exports = {
     withCl,
     withoutCl,

+ 2 - 0
app/const/tender_info.js

@@ -66,6 +66,8 @@ const defaultInfo = {
         controlPrice: 0,
         bidPrice: 0,
         bidStartDate: '',
+        bidType: '公开招标',
+        dealCalcType: '单价合同',
     },
     // 小数位数
     decimal: {

+ 4 - 1
app/controller/change_controller.js

@@ -610,7 +610,7 @@ module.exports = app => {
                     // 获取已选清单
                     const changeList = await ctx.service.changeAuditList.getList(change.cid);
                     renderData.changeList = changeList;
-                } else if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7) {
+                } else if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7 || auditStatus === 8) {
                     // 展示页左侧审批流程列表和清单审批列表数据
                     const times = change.status === audit.flow.status.back ?
                         change.times - 1 : change.times;
@@ -730,6 +730,9 @@ module.exports = app => {
                     case 'add':
                         responseData.data = await ctx.service.changeAuditList.add(data.postData);
                         break;
+                    case 'batchadd':
+                        responseData.data = await ctx.service.changeAuditList.batchAdd(data);
+                        break;
                     case 'del':
                         await ctx.service.changeAuditList.del(data.id);
                         break;

+ 4 - 3
app/controller/ledger_controller.js

@@ -62,7 +62,7 @@ module.exports = app => {
             const isUser = tender.user_id === this.ctx.session.sessionUser.accountId;
             const auditorsId = this.ctx.helper._.map(auditors, 'audit_id');
             const isAuditor  = auditorsId.indexOf(this.ctx.session.sessionUser.accountId) >= 0;
-            const upPermission = this.ctx.session.sessionUser.permission
+            const upPermission = this.ctx.session.sessionUser.permission && this.ctx.session.sessionUser.permission.tender
                 ? this.ctx.session.sessionUser.permission.tender.indexOf('3') >= 0
                 : false;
             return ((tender.ledger_status === auditConst.status.uncheck || tender.ledger_status === auditConst.status.checkNo) && isUser) ||
@@ -133,7 +133,7 @@ module.exports = app => {
                 const times = tender.data.ledger_status === auditConst.status.checkNo ? tender.data.ledger_times - 1 : tender.data.ledger_times;
 
                 const curAuditor = await ctx.service.ledgerAudit.getCurAuditor(tender.id, tender.data.ledger_times);
-                const auditors = tender.data.ledger_status === auditConst.status.checkNo && tender.data.user_id !== ctx.session.sessionUser.accountId ?
+                const auditors = tender.data.ledger_status === auditConst.status.checkNo && tender.data.user_id !== ctx.session.sessionUser.accountId && !ctx.tender.isTourist ?
                     await ctx.service.ledgerAudit.getAuditorsWithOwner(tender.id, times) :
                     await ctx.service.ledgerAudit.getAuditorsWithOwner(tender.id, tender.data.ledger_times);
                 const user = await ctx.service.projectAccount.getAccountInfoById(ctx.tender.data.user_id);
@@ -183,7 +183,8 @@ module.exports = app => {
             } catch (err) {
                 ctx.helper.log(err);
                 this.postError(err, '标段数据错误');
-                await this.redirect('/dashboard');
+                // await this.redirect('/dashboard');
+                ctx.redirect(ctx.request.header.referer);
             }
         }
 

+ 4 - 3
app/controller/login_controller.js

@@ -26,6 +26,7 @@ module.exports = app => {
                 ctx.redirect('/wap');
                 return;
             }
+
             const errorMessage = ctx.session.loginError;
             // 显示完删除
             ctx.session.loginError = null;
@@ -35,12 +36,12 @@ module.exports = app => {
             if (!ctx.app.config.is_debug) {
                 await ctx.service.maintain.syncMaintainData();
             }
-
             const renderData = {
                 maintainData,
                 maintainConst,
                 errorMessage,
                 hostUrl: ctx.protocol + '://' + ctx.host,
+                appid: ctx.app.config.wxCode.appid,
             };
             await ctx.render('login/login.ejs', renderData);
         }
@@ -53,7 +54,7 @@ module.exports = app => {
         async wxAuth(ctx) {
             const code = ctx.query.code;
             try {
-                const client = new OAuth('wx5320cd30cecdbd68', 'ca7c0dbd9e94dc3b1c3b0e73865743f4');
+                const client = new OAuth(ctx.app.config.wxCode.appid, ctx.app.config.wxCode.appsecret);
                 const token = await client.getAccessToken(code);
                 // const user = await client.getUser(token.data.openid);
                 // console.log(user);
@@ -308,7 +309,7 @@ module.exports = app => {
                     ctx.redirect('/dashboard');
                 }
             } catch (error) {
-                this.log(error);
+                // this.log(error);
                 ctx.session.loginError = error;
             }
             const errorMessage = ctx.session.loginError;

+ 64 - 2
app/controller/setting_controller.js

@@ -14,6 +14,7 @@ const settingMenu = require('../../config/menu').settingMenu;
 const accountGroup = require('../const/account_group').group;
 const permission = require('../const/account_permission').permission;
 const projectLog = require('../const/project_log');
+const imType = require('../const/tender').imType;
 
 module.exports = app => {
 
@@ -97,6 +98,7 @@ module.exports = app => {
                 }
 
                 const page = ctx.page;
+                const pageSize = ctx.pageSize;
 
                 // 过滤数据
                 ctx.service.projectAccount.searchFilter(ctx.request.query, projectId);
@@ -126,7 +128,10 @@ module.exports = app => {
                 // 分页相关
                 const pageInfo = {
                     page,
-                    total: Math.ceil(total / app.config.pageSize),
+                    pageSizeSelect: 1,
+                    pageSize,
+                    total_num: total,
+                    total: Math.ceil(total / pageSize),
                     queryData: JSON.stringify(ctx.urlInfo.query),
                 };
 
@@ -197,6 +202,7 @@ module.exports = app => {
                 // const rule = ctx.service.projectAccount.rule('updateUser');
                 // const frontRule = ctx.helper.validateConvert(rule);
                 const page = ctx.page;
+                const pageSize = ctx.pageSize;
                 ctx.sort = ['id', 'desc'];
                 const total = await ctx.service.projectAccount.count({ project_id: projectId });
                 // 获取项目用户列表
@@ -212,7 +218,10 @@ module.exports = app => {
                 // 分页相关
                 const pageInfo = {
                     page,
-                    total: Math.ceil(total / app.config.pageSize),
+                    pageSizeSelect: 1,
+                    pageSize,
+                    total_num: total,
+                    total: Math.ceil(total / pageSize),
                     queryData: JSON.stringify(ctx.urlInfo.query),
                 };
 
@@ -679,6 +688,59 @@ module.exports = app => {
                 ctx.redirect('/dashboard');
             }
         }
+
+        async fun(ctx) {
+            try {
+                const projectId = ctx.session.sessionProject.id;
+                const projectData = await ctx.service.project.getDataById(projectId);
+                const funRela = await ctx.service.project.getFunRela(projectId);
+                if (projectData === null) {
+                    throw '没有对应的项目数据';
+                }
+                if (ctx.session.sessionUser.is_admin === 0) {
+                    throw '没有访问权限';
+                }
+                await this.layout('setting/fun.ejs', {
+                    projectData,
+                    funRela,
+                    imType,
+                })
+            } catch (error) {
+                ctx.helper.log(error);
+                ctx.redirect('/dashboard');
+            }
+        }
+
+        /**
+         * 保存功能设置相关
+         * @param ctx
+         * @returns {Promise<void>}
+         */
+        async updateFun(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);
+                if (data) ctx.request.body = data;
+                const rule = ctx.service.project.rule('fun');
+                ctx.validate(rule);
+
+                const result = await ctx.service.project.updateFunRela(projectId, ctx.request.body);
+                if (!result) throw '保存数据失败';
+
+                ctx.body = {err: 0, msg: '', data: null};
+            } catch(error) {
+                ctx.helper.log(error);
+                this.ajaxErrorBody(error, '保存数据失败');
+            }
+        }
     }
 
     return SettingController;

+ 31 - 28
app/controller/stage_controller.js

@@ -349,20 +349,23 @@ 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 qtyData = ctx.helper.checkBillsWithPos(ledgerData, posData, ['contract_qty', 'qc_qty']);
+                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}), [
                     { 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],
+                    error: [...qtyData.error, ...tpData.error, ...overData.error],
                     source: {
-                        bills: [...qtyData.source.bills, ...tpData.source.bills],
-                        pos: [...qtyData.source.pos, ...tpData.source.pos],
+                        bills: [...qtyData.source.bills, ...tpData.source.bills, ...overData.source.bills],
+                        pos: [...qtyData.source.pos, ...tpData.source.pos, ...overData.source.pos],
                     },
                 } };
             } catch (err) {
@@ -1284,27 +1287,27 @@ module.exports = app => {
          * 检查当前期当前用户是否在审核列表中,如果是的话允许再次上传附件
          * @param {Object} ctx 上下文
          */
-        // _checkStageCanModifyRe(ctx) {
-        //     // 检查登录用户,是否可操作
-        //     if (ctx.stage.readOnly) {
-        //         if (ctx.stage.status === auditConst.status.checked) {
-        //             // 当前期状态为完成,且提交人是审核列表中的则可再次上传
-        //             if (ctx.stage.user_id === ctx.session.sessionUser.accountId || ctx.stage.auditors.findIndex(auditor => auditor.aid === ctx.session.sessionUser.accountId) !== -1) {
-        //                 // 再次上传的图片要给个标识,方便给前端进行编辑操作
-        //                 ctx.reUploadPermission = true;
-        //                 return;
-        //             }
-
-        //             throw '该计量期当前您无权操作';
-
-        //         } else {
-        //             throw '该计量期当前您无权操作';
-        //         }
-        //     }
-        //     if (ctx.stage.revising) {
-        //         throw '台账修订中,请勿修改提交期数据';
-        //     }
-        // }
+        _checkStageCanModifyRe(ctx) {
+            // 检查登录用户,是否可操作
+            if (ctx.stage.readOnly) {
+                if (ctx.stage.status === auditConst.status.checked) {
+                    // 当前期状态为完成,且提交人是审核列表中的则可再次上传
+                    if (ctx.stage.user_id === ctx.session.sessionUser.accountId || ctx.stage.auditors.findIndex(auditor => auditor.aid === ctx.session.sessionUser.accountId) !== -1) {
+                        // 再次上传的图片要给个标识,方便给前端进行编辑操作
+                        // ctx.reUploadPermission = true;
+                        return;
+                    }
+
+                    throw '该计量期当前您无权操作';
+
+                } else {
+                    throw '该计量期当前您无权操作';
+                }
+            }
+            if (ctx.stage.revising) {
+                throw '台账修订中,请勿修改提交期数据';
+            }
+        }
         /**
          * 上传附件
          * @param {Object} ctx - egg全局变量
@@ -1318,7 +1321,7 @@ module.exports = app => {
             };
             let stream;
             try {
-                // this._checkStageCanModifyRe(ctx);
+                this._checkStageCanModifyRe(ctx);
 
                 const parts = ctx.multipart({ autoFields: true });
                 const files = [];
@@ -1467,7 +1470,7 @@ module.exports = app => {
                 data: '',
             };
             try {
-                // this._checkStageCanModifyRe(ctx);
+                this._checkStageCanModifyRe(ctx);
 
                 const data = JSON.parse(ctx.request.body.data);
                 const fileInfo = await ctx.service.stageAtt.getDataById(data.id);
@@ -1513,7 +1516,7 @@ module.exports = app => {
             };
             let stream;
             try {
-                // this._checkStageCanModifyRe(ctx);
+                this._checkStageCanModifyRe(ctx);
                 stream = await ctx.getFileStream({ requireFile: false });
                 let fileData = {};
                 if (stream.filename !== undefined) {

+ 43 - 5
app/controller/tender_controller.js

@@ -121,7 +121,7 @@ module.exports = app => {
                 const userPermission = accountInfo !== undefined && accountInfo.permission !== ''
                     ? JSON.parse(accountInfo.permission) : null;
 
-                const tenderList = await this.ctx.service.tender.getList('', userPermission);
+                const tenderList = await this.ctx.service.tender.getList('', userPermission, this.ctx.session.sessionUser.is_admin);
 
                 for (const t of tenderList) {
                     if (t.user_id === this.ctx.session.sessionUser.accountId && (
@@ -174,7 +174,7 @@ module.exports = app => {
         async _list(view, renderData, modal = '', list_status = '') {
             console.log(1);
             try {
-                renderData.tenderList = await this.ctx.service.tender.getList(list_status, renderData.userPermission);
+                renderData.tenderList = await this.ctx.service.tender.getList(list_status, renderData.userPermission, this.ctx.session.sessionUser.is_admin);
 
                 for (const t of renderData.tenderList) {
                     if (t.ledger_status === auditConst.ledger.status.checked) {
@@ -453,8 +453,8 @@ module.exports = app => {
                     audit: auditConst,
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.tender.tenderInfo),
                 };
-                if (ctx.session.sessionProject.page_show !== null && parseInt(ctx.session.sessionProject.page_show.xxjd) === 1 && ctx.session.sessionUser.is_admin) {
-                    // 形象进度内容
+                if (ctx.session.sessionUser.is_admin) {
+                    renderData.tourists = await ctx.service.tenderTourist.getTourists(tender.id);
                     // 获取所有项目参与者
                     const accountList = await ctx.service.projectAccount.getAllDataByCondition({
                         where: { project_id: ctx.session.sessionProject.id, enable: 1 },
@@ -464,9 +464,12 @@ module.exports = app => {
                         const groupList = accountList.filter(item => item.account_group === idx);
                         return { groupName: item, groupList };
                     });
-                    renderData.scheduleAuditList = await ctx.service.scheduleAudit.getAllDataByCondition({ where: { tid: tender.id } });
                     renderData.accountList = accountList;
                     renderData.accountGroup = accountGroupList;
+                }
+                if (ctx.session.sessionProject.page_show !== null && parseInt(ctx.session.sessionProject.page_show.xxjd) === 1 && ctx.session.sessionUser.is_admin) {
+                    // 形象进度内容
+                    renderData.scheduleAuditList = await ctx.service.scheduleAudit.getAllDataByCondition({ where: { tid: tender.id } });
                     renderData.scPermission = scheduleConst.permission;
                 }
                 await this.layout('tender/detail.ejs', renderData, 'tender/detail_modal.ejs');
@@ -965,6 +968,41 @@ module.exports = app => {
         }
 
         /**
+         * 游客账号设置
+         * @param {object} ctx - 上下文
+         */
+        async saveTourist(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                if (!data) {
+                    throw '提交数据错误';
+                }
+                // 判断修改权限
+                if (ctx.session.sessionUser.is_admin === 0) {
+                    throw '你没有权限修改游客账号';
+                }
+                let info = '';
+                switch (data.type) {
+                    case 'add':
+                        const result = await ctx.service.tenderTourist.addAudit(data);
+                        if (!result) {
+                            throw '添加审批人失败';
+                        }
+                        info = result;
+                        break;
+                    case 'del':
+                        await ctx.service.tenderTourist.removeAudit(data);
+                        break;
+                    default:break;
+                }
+                ctx.body = { err: 0, msg: '', data: info };
+            } catch (err) {
+                this.log(err);
+                ctx.body = this.ajaxErrorBody(err, '保存游客账号设置失败');
+            }
+        }
+
+        /**
          * 获取部位明细数据(Ajax)
          *
          * @param ctx

+ 0 - 16
app/controller/wechat_controller.js

@@ -254,22 +254,6 @@ module.exports = app => {
                 ctx.body = error;
             }
         }
-
-        async batchUpdateUnionid(ctx) {
-            try {
-                const wxList = await ctx.service.projectAccount.getUnionIdList();
-                const updateList = [];
-                for (const wx of wxList) {
-                    const user = await app.wechat.api.getUser(wx.wx_openid);
-                    updateList.push({ id: wx.id, wx_unionid: user.unionid });
-                }
-                await ctx.service.projectAccount.updateRows(updateList);
-                ctx.body = 'success';
-            } catch (error) {
-                console.log(error);
-                ctx.body = error;
-            }
-        }
     }
 
     return WechatController;

+ 108 - 11
app/extend/helper.js

@@ -273,7 +273,7 @@ module.exports = {
 
         // 然后再验证是否有多余的数据
         const postData = this.ctx.request.body;
-        delete postData._csrf;
+        delete postData._csrf_j;
 
         const postDataKey = Object.keys(postData);
         const ruleKey = Object.keys(rule);
@@ -707,7 +707,6 @@ module.exports = {
      * @return {*}
      */
     round(value, decimal) {
-        // return value ? bc.round(value, decimal) : null;
         return value ? new Decimal(value).toDecimalPlaces(decimal).toNumber() : null;
     },
     /**
@@ -1148,14 +1147,18 @@ module.exports = {
         return request.url.indexOf('/wap/') !== -1;
     },
 
-    checkBillsWithPos(bills, pos, fields) {
-        const result = {
+    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 = {},
@@ -1186,14 +1189,108 @@ module.exports = {
         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 = {
-            error: [],
-            source: {
-                bills: [],
-                pos: [],
-            },
-        };
+        const result = this.getDefaultCheckResult();
         for (const b of bills) {
             if (!b.check_calc) continue;
 

+ 18 - 4
app/lib/analysis_excel.js

@@ -11,7 +11,7 @@ const _ = require('lodash');
 const colDefineType = {
     match: 1,
     pos: 2,
-}
+};
 const aeUtils = {
     toNumber: function (value) {
         let num = _.toNumber(value);
@@ -205,6 +205,16 @@ class ImportBaseTree {
         }
     }
 
+    _assignRelaField(temp, node) {
+        if (!temp.quantity) temp.quantity = node.quantity;
+        if (!temp.dgn_qty1) temp.dgn_qty1 = node.dgn_qty1;
+        if (!temp.dgn_qty2) temp.dgn_qty2 = node.dgn_qty2;
+        if (!temp.unit_price) temp.unit_price = node.unit_price;
+        if (!temp.drawing_code) temp.drawing_code = node.drawing_code;
+        if (!temp.memo) temp.memo = node.memo;
+        if (!temp.total_price) temp.total_price = node.total_price;
+    }
+
     /**
      * 添加 项目节
      * @param {Object} node - 项目节
@@ -218,6 +228,7 @@ class ImportBaseTree {
             const temp = this.findTempData(node);
             if (temp) {
                 this.defineCacheData(temp);
+                this._assignRelaField(temp, node);
                 return temp;
             } else {
                 const parent = this.findXmjParent(node.code);
@@ -229,6 +240,7 @@ class ImportBaseTree {
                 return this.addNodeWithParent(node, null);
             } else {
                 this.defineCacheData(n);
+                this._assignRelaField(n, node);
                 return n;
             }
         }
@@ -432,6 +444,7 @@ class ImportStd18Tree extends ImportBaseTree {
         const temp = this.findTempData(node);
         if (temp) {
             this.defineCacheData(temp);
+            this._assignRelaField(temp, node);
             return temp;
         } else {
             const parent = this.findXmjParent(node.code);
@@ -446,6 +459,7 @@ class AnalysisExcelTree {
      */
     constructor(ctx) {
         this.ctx = ctx;
+        this.decimal = ctx.tender.info.decimal;
         this.colsDef = null;
         this.colHeaderMatch = {
             code: {value: ['项目节编号', '预算项目节'], type: colDefineType.match},
@@ -501,7 +515,7 @@ class AnalysisExcelTree {
             node.quantity = this.ctx.helper.round(aeUtils.toNumber(row[this.colsDef.quantity]), precision.value);
             node.dgn_qty1 = aeUtils.toNumber(row[this.colsDef.dgn_qty1]);
             node.dgn_qty2 = aeUtils.toNumber(row[this.colsDef.dgn_qty2]);
-            node.unit_price = aeUtils.toNumber(row[this.colsDef.unit_price]);
+            node.unit_price = this.ctx.helper.round(aeUtils.toNumber(row[this.colsDef.unit_price]), this.decimal.up);
             node.drawing_code = this.ctx.helper.replaceReturn(row[this.colsDef.drawing_code]);
             node.memo = this.ctx.helper.replaceReturn(row[this.colsDef.memo]);
             if (node.quantity && node.unit_price) {
@@ -539,7 +553,7 @@ class AnalysisExcelTree {
         const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, node.unit);
         node.quantity = this.ctx.helper.round(aeUtils.toNumber(row[this.colsDef.quantity]), precision.value);
         node.sgfh_qty = node.quantity;
-        node.unit_price = aeUtils.toNumber(row[this.colsDef.unit_price]);
+        node.unit_price = this.ctx.helper.round(aeUtils.toNumber(row[this.colsDef.unit_price]), this.decimal.up);
         node.drawing_code = this.ctx.helper.replaceReturn(row[this.colsDef.drawing_code]);
         node.memo = this.ctx.helper.replaceReturn(row[this.colsDef.memo]);
         if (node.quantity && node.unit_price) {
@@ -751,7 +765,7 @@ class AnalysisGclExcelTree {
         node.unit = this.ctx.helper.replaceReturn(row[this.colsDef.unit]);
         const precision = this.ctx.helper.findPrecision(this.ctx.tender.info.precision, node.unit);
         node.quantity = this.ctx.helper.round(aeUtils.toNumber(row[this.colsDef.quantity]), precision.value);
-        node.unit_price = aeUtils.toNumber(row[this.colsDef.unit_price]);
+        node.unit_price = this.ctx.helper.round(aeUtils.toNumber(row[this.colsDef.unit_price]), this.ctx.tender.info.decimal.up);
         if (node.quantity && node.unit_price) {
             node.total_price = this.ctx.helper.mul(node.quantity, node.unit_price, this.ctx.tender.info.decimal.tp);
         } else {

+ 3 - 0
app/lib/gcl_gather.js

@@ -244,6 +244,9 @@ const gclGatherModel = class {
         const loadLeafXmj = function (detail, calcSource) {
             const dx = helper._.assign({}, cacheLeafXmj);
             dx.gcl_id = gcl.id;
+            dx.org_gcl_id = node.id;
+            // dx.org_gcl_id = gcl.id;
+            // dx.gcl_id = node.id;
             if (detail.name !== node.name) {
                 dx.bwmx = detail.name;
                 dx.mx_id = detail.id;

+ 64 - 0
app/lib/rpt_data_analysis.js

@@ -12,6 +12,7 @@ const math = require('mathjs');
 const standard = require('../const/standard');
 const moment = require('moment');
 moment.locale('zh-cn');
+const fs = require('fs');
 
 const valueCheck = {
     _typeFun: {
@@ -1712,6 +1713,68 @@ const gatherGcl2 = {
         data.mem_gcl_gather_xmj = gatherUtil.leafXmjs;
     }
 };
+const gatherMaterialGl = {
+    name: '分类汇总调差工料',
+    hint: '根据工程量清单分类汇总调差工料,要求先使用【工程量清单汇总2】处理得到工程量清单数据,并引入【调差工料明细】',
+    _relaGl(source, data) {
+        if (!source) return;
+        const gl = source.find(x => {return x.id === data.mb_id;});
+        if (gl) {
+            data.gl_code = gl.code;
+            data.gl_name = gl.name;
+            data.gl_unit = gl.unit;
+            data.gl_spec = gl.spec;
+
+            data.gl_base_price = gl.base_price;
+            data.gl_base_times = gl.base_times;
+
+            data.gl_msg_tp = gl.msg_tp;
+            data.gl_msg_times = gl.msg_times;
+            data.gl_msg_spread = gl.msg_spread;
+
+            data.gl_m_up_risk = gl.m_up_risk;
+            data.gl_m_down_risk = gl.m_down_risk;
+            data.gl_m_spread = gl.m_spread;
+        }
+    },
+    fun(ctx, data, fieldsKey, options, csRela) {
+        if (!data.mem_gcl_gather_bills || !data.mem_gcl_gather_xmj || !data.mem_material_gl_detail) return;
+
+        const result = [];
+        for (const d of data.mem_material_gl_detail) {
+            const xmj = data.mem_gcl_gather_xmj.find(x => {
+                return d.gcl_id === x.org_gcl_id && d.xmj_id === x.id && (!d.mx_id || d.mx_id === x.mx_id);
+            });
+            if (!xmj) continue;
+
+            const gcl = data.mem_gcl_gather_bills.find(x => {
+                return x.id === xmj.gcl_id;
+            });
+            if (!gcl) continue;
+
+            const gd = result.find(x => {
+                return x.gather_gcl_id === gcl.id && x.mb_id === d.mb_id;
+            });
+            if (!gd) {
+                const newGd = {
+                    gather_gcl_id: gcl.id,
+                    mb_id: d.mb_id, gather_qty: d.gather_qty, quantity: d.quantity,
+                    b_code: gcl.b_code, name: gcl.name, unit: gcl.unit, unit_price: gcl.unit_price,
+                    cur_contract_qty: gcl.contract_qty, cur_contract_tp: gcl.contract_tp,
+                    cur_qc_qty: gcl.qc_qty, cur_qc_tp: gcl.qc_tp,
+                    cur_gather_qty: gcl.gather_qty, cur_gather_tp: gcl.gather_tp,
+                };
+                this._relaGl(data.mem_material_gl, newGd);
+                result.push(newGd);
+            } else {
+                gd.gather_qty = ctx.helper.add(gd.gather_qty, d.gather_qty);
+                gd.quantity = ctx.helper.add(gd.quantity, d.quantity);
+            }
+        }
+        console.log(result);
+        data.mem_material_gl_detail = result;
+    }
+};
 
 const analysisObj = {
     changeSort,
@@ -1735,6 +1798,7 @@ const analysisObj = {
     getChangeLedger,
     treeFilter,
     gatherGcl2,
+    gatherMaterialGl,
 };
 const analysisDefine = (function(obj) {
     const result = [];

+ 2 - 1
app/middleware/change_check.js

@@ -32,7 +32,6 @@ module.exports = options => {
             // 读取原报、审核人数据
             change.auditors = yield this.service.changeAudit.getListGroupByTimes(change.cid, change.times);
             change.curAuditor = yield this.service.changeAudit.getCurAuditor(change.cid, change.times);
-            console.log(change.curAuditor);
 
             if (!change) throw '变更令数据有误';
             // 权限相关
@@ -47,6 +46,8 @@ module.exports = options => {
                 } else {
                     change.readOnly = change.status !== status.uncheck && change.status !== status.back;
                 }
+            } else if (this.tender.isTourist) {
+                change.readOnly = true;
             } else if (auditorIds.indexOf(accountId) !== -1) { // 审批人
                 if (change.status === status.uncheck) {
                     throw '您无权查看该数据';

+ 12 - 0
app/middleware/material_check.js

@@ -70,6 +70,16 @@ module.exports = options => {
                 } else {
                     material.curOrder = material.curAuditor.aid === accountId ? material.curAuditor.order : material.curAuditor.order - 1;
                 }
+                material.filePermission = true;
+            } else if (this.tender.isTourist) {
+                material.curTimes = material.times;
+                if (material.status === status.uncheck || material.status === status.checkNo) {
+                    material.curOrder = 0;
+                } else if (material.status === status.checked) {
+                    material.curOrder = _.max(_.map(material.auditors, 'order'));
+                } else {
+                    material.curOrder = material.curAuditor.order;
+                }
             } else if (auditorIds.indexOf(accountId) !== -1) { // 审批人
                 if (material.status === status.uncheck) {
                     throw '您无权查看该数据';
@@ -86,6 +96,7 @@ module.exports = options => {
                 } else {
                     material.curOrder = accountId === material.curAuditor.aid ? material.curAuditor.order : material.curAuditor.order - 1;
                 }
+                material.filePermission = true;
             } else if (shareIds.indexOf(accountId) !== -1) { // 分享人
                 if (material.status === status.uncheck) {
                     throw '您无权查看该数据';
@@ -93,6 +104,7 @@ module.exports = options => {
                 // material.readOnly = true;
                 material.curTimes = material.status === status.checkNo ? material.times - 1 : material.times;
                 material.curOrder = material.status === status.checked ? _.max(_.map(material.auditors, 'order')) : material.curAuditor.order - 1;
+                material.filePermission = false;
             } else { // 其他不可见
                 throw '您无权查看该数据';
             }

+ 4 - 0
app/middleware/sort_filter.js

@@ -20,6 +20,10 @@ module.exports = options => {
         page = parseInt(page);
         page = isNaN(page) || page <= 0 ? 1 : page;
         this.page = page;
+        let pageSize = this.request.query.pageSize;
+        pageSize = parseInt(pageSize);
+        pageSize = isNaN(pageSize) || pageSize <= 0 ? this.app.config.pageSize : pageSize;
+        this.pageSize = pageSize;
         yield next;
     };
 };

+ 18 - 1
app/middleware/stage_check.js

@@ -59,7 +59,7 @@ module.exports = options => {
                 return item.s_order.split(',').indexOf(stage.highOrder.toString()) !== -1;
             });
             // 权限相关
-            // todo 校验权限 (标段参与人、分享)
+            // todo 校验权限 (标段参与人、分享、游客
             const accountId = this.session.sessionUser.accountId,
                 auditorIds = _.map(stage.auditors, 'aid'),
                 shareIds = [];
@@ -79,6 +79,21 @@ module.exports = options => {
                 } else {
                     stage.curOrder = stage.curAuditor.aid === accountId ? stage.curAuditor.order : stage.curAuditor.order - 1;
                 }
+                stage.filePermission = true;
+            } else if (this.tender.isTourist) {
+                if (auditorIds.indexOf(accountId) !== -1) {
+                    stage.readOnly = (stage.status !== status.checking && stage.status !== status.checkNoPre) || accountId !== stage.curAuditor.aid;
+                } else {
+                    stage.readOnly = true;
+                }
+                stage.curTimes = stage.times;
+                if (stage.status === status.uncheck || stage.status === status.checkNo) {
+                    stage.curOrder = 0;
+                } else if (stage.status === status.checked) {
+                    stage.curOrder = _.max(_.map(stage.auditors, 'order'));
+                } else {
+                    stage.curOrder = stage.curAuditor.order;
+                }
             } else if (auditorIds.indexOf(accountId) !== -1) { // 审批人
                 if (stage.status === status.uncheck) {
                     throw '您无权查看该数据';
@@ -95,6 +110,7 @@ module.exports = options => {
                     stage.curOrder = accountId === stage.curAuditor.aid ? stage.curAuditor.order : stage.curAuditor.order - 1;
                 }
                 stage.readOnly = (stage.status !== status.checking && stage.status !== status.checkNoPre) || accountId !== stage.curAuditor.aid;
+                stage.filePermission = true;
             } else if (shareIds.indexOf(accountId) !== -1 || (permission !== null && permission.tender !== undefined && permission.tender.indexOf('2') !== -1)) { // 分享人
                 if (stage.status === status.uncheck) {
                     throw '您无权查看该数据';
@@ -109,6 +125,7 @@ module.exports = options => {
                 } else {
                     stage.curOrder = stage.status === status.checked ? _.max(_.map(stage.auditors, 'order')) : stage.curAuditor.order - 1;
                 }
+                stage.filePermission = false;
             } else { // 其他不可见
                 throw '您无权查看该数据';
             }

+ 6 - 1
app/middleware/tender_check.js

@@ -61,11 +61,14 @@ module.exports = options => {
             const materialAuditors = yield this.service.materialAudit.getAllAuditors(tender.id);
             const materialAuditorsId = this.helper._.map(materialAuditors, 'aid');
             const tenderPermission = this.session.sessionUser.permission ? this.session.sessionUser.permission.tender : null;
+            const isTenderTourist = yield this.service.tenderTourist.getDataByCondition({ tid: tender.id, user_id: accountId });
+            // 判断访问人是否具有游客身份
+            tender.isTourist = isTenderTourist !== null;
             if (auditorsId.indexOf(accountId) === -1 && tender.data.user_id !== accountId &&
                 (tenderPermission === null || tenderPermission === undefined || tenderPermission.indexOf('2') === -1) &&
                 stageAuditorsId.indexOf(accountId) === -1 && changeAuditorsId.indexOf(accountId) === -1 &&
                 reviseAuditorsId.indexOf(accountId) === -1 && materialAuditorsId.indexOf(accountId) === -1 &&
-                advanceAuditorsId.indexOf(accountId) === -1) {
+                advanceAuditorsId.indexOf(accountId) === -1 && !this.session.sessionUser.is_admin && !isTenderTourist) {
                 throw '您无权查看该项目';
             }
 
@@ -83,6 +86,8 @@ module.exports = options => {
                 const scheduleUser = yield this.service.scheduleAudit.getDataByCondition({ tid: tender.id, audit_id: this.session.sessionUser.accountId });
                 if (scheduleUser) {
                     schedule_permission = scheduleUser.permission;
+                } else if (tender.isTourist) {
+                    schedule_permission = scPermission.show;
                 }
             }
             tender.schedule_permission = schedule_permission;

+ 2 - 2
app/middleware/uncheck_tender_check.js

@@ -23,9 +23,9 @@ module.exports = options => {
     return function* uncheckTenderCheck(next) {
         try {
             if (this.tender.data.ledger_status === auditConst.status.uncheck) {
-                if (this.tender.data.user_id !== this.session.sessionUser.accountId && this.tender.advanceAuditorsId.indexOf(this.session.sessionUser.accountId) === -1) {
+                if (this.tender.data.user_id !== this.session.sessionUser.accountId && !this.session.sessionUser.is_admin && this.tender.advanceAuditorsId.indexOf(this.session.sessionUser.accountId) === -1 && !this.tender.isTourist) {
                     throw '您无权查看该项目';
-                } else if (this.tender.advanceAuditorsId.indexOf(this.session.sessionUser.accountId) !== -1) {
+                } else if (this.tender.advanceAuditorsId.indexOf(this.session.sessionUser.accountId) !== -1 && !this.session.sessionUser.is_admin && !this.tender.isTourist) {
                     throw '您无权查看该内容';
                 }
             }

+ 6 - 6
app/public/js/bootstrap/bootstrap-paginator.js

@@ -670,17 +670,17 @@
 
             switch (type) {
             case "first":
-                return "Go to first page";
+                return "转到第一页";
             case "prev":
-                return "Go to previous page";
+                return "转到上一页";
             case "next":
-                return "Go to next page";
+                return "转到下一页";
             case "last":
-                return "Go to last page";
+                return "转到最后一页";
             case "page":
-                return (page === current) ? "Current page is " + page : "Go to page " + page;
+                return (page === current) ? "当前页为 " + page : "转到第 " + page + ' 页';
             case "more":
-                return "more pages";
+                return "更多页数";
             }
         },
         bootstrapTooltipOptions: {

+ 1 - 1
app/public/js/change_approval.js

@@ -122,7 +122,7 @@ const postDataWithAsync = function (url, data, successCallback, errorCallBack, s
         async: false,
         timeout: 60000,
         beforeSend: function(xhr) {
-            let csrfToken = Cookies.get('csrfToken');
+            let csrfToken = Cookies.get('csrfToken_j');
             xhr.setRequestHeader('x-csrf-token', csrfToken);
         },
         success: function(result){

+ 1 - 1
app/public/js/change_detail.js

@@ -204,7 +204,7 @@ $(document).ready(() => {
         const btn = $(this);
 
         $.ajax({
-            url: '/profile/code?_csrf=' + csrf,
+            url: '/profile/code?_csrf_j=' + csrf,
             type: 'post',
             data: { mobile: authMobile, type: 'shenpi' },
             dataTye: 'json',

+ 1 - 1
app/public/js/change_information_approval.js

@@ -382,7 +382,7 @@ const postDataWithAsync = function (url, data, successCallback, errorCallBack, s
         async: false,
         timeout: 60000,
         beforeSend: function(xhr) {
-            let csrfToken = Cookies.get('csrfToken');
+            let csrfToken = Cookies.get('csrfToken_j');
             xhr.setRequestHeader('x-csrf-token', csrfToken);
         },
         success: function(result){

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

@@ -90,7 +90,7 @@ $(document).ready(() => {
             {title: '名称', colSpan: '1', rowSpan: '2', field: 'name', hAlign: 0, width: 120, formatter: '@', readOnly: 'readOnly.isEdit'},
             {title: '变更部位', colSpan: '1', rowSpan: '2', field: 'bwmx', hAlign: 0, width: 120, formatter: '@', readOnly: 'readOnly.isEdit'},
             {title: '变更详情', colSpan: '1', rowSpan: '2', field: 'detail', hAlign: 0, width: 120, formatter: '@', readOnly: false},
-            {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@', readOnly: 'readOnly.isEdit', cellType: 'unit', comboItems: changeUnits},
+            {title: '单位', colSpan: '1', rowSpan: '2', field: 'unit', hAlign: 1, width: 60, formatter: '@', readOnly: 'readOnly.isEdit', cellType: 'unit', comboItems: changeUnits, comboEdit: true},
             {title: '单价', colSpan: '1', rowSpan: '2', field: 'unit_price', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.isEdit', getValue: 'getValue.unit_price'},
             {title: '原设计|数量', colSpan: '2|1', rowSpan: '1|1', field: 'oamount', hAlign: 2, width: 60, type: 'Number', readOnly: 'readOnly.isEdit', getValue: 'getValue.oamount'},
             {title: '|金额', colSpan: '|1', rowSpan: '|1', field: 'oa_tp', hAlign: 2, width: 80, type: 'Number', readOnly: true, getValue: 'getValue.oa_tp'},
@@ -184,6 +184,16 @@ $(document).ready(() => {
                 }
             });
         },
+        batchAdd: function(num) {
+            postData(window.location.pathname + '/save', {type: 'batchadd', num}, function (result) {
+                if (result) {
+                    changeList = _.concat(changeList, result);
+                    SpreadJsObj.loadSheetData(changeSpreadSheet, SpreadJsObj.DataType.Data, changeList);
+                    changeSpreadObj.makeSjsFooter();
+                    changeSpreadObj.resetXmjSpread();
+                }
+            });
+        },
         del: function () {
             const select = SpreadJsObj.getSelectObject(changeSpreadSheet);
             const index = changeList.indexOf(select);
@@ -322,6 +332,7 @@ $(document).ready(() => {
                         }
                         continue;
                     }
+
                     if (colSetting.type === 'Number') {
                         if (isNaN(validText)) {
                             toastMessageUniq(getPasteHint(hint.numberExpr, hintRow));
@@ -334,17 +345,18 @@ $(document).ready(() => {
                             validText = ZhCalc.round(validText, findDecimal(sortData[curRow].unit)) || 0;
                         }
                     }
+                    let unitdecimal = validText;
                     if (colSetting.field === 'unit') {
                         //粘贴内容要为下拉列表里所有的单位,不然为空
                         if (changeUnits.indexOf(validText) === -1) {
-                            validText = '';
+                            unitdecimal = '';
                         }
-                        cLData.camount = ZhCalc.round(sortData[curRow].camount, findDecimal(validText)) || 0;
-                        cLData.oamount = ZhCalc.round(sortData[curRow].oamount, findDecimal(validText)) || 0;
+                        cLData.camount = ZhCalc.round(sortData[curRow].camount, findDecimal(unitdecimal)) || 0;
+                        cLData.oamount = ZhCalc.round(sortData[curRow].oamount, findDecimal(unitdecimal)) || 0;
                     }
                     cLData[colSetting.field] = validText;
                     sortData[curRow][colSetting.field] = validText;
-                    cLData.spamount = ZhCalc.round(sortData[curRow].camount, findDecimal(validText)) || 0;
+                    cLData.spamount = ZhCalc.round(sortData[curRow].camount, findDecimal(unitdecimal)) || 0;
                 }
                 if (bPaste) {
                     data.push(cLData);
@@ -476,6 +488,33 @@ $(document).ready(() => {
         SpreadJsObj.addDeleteBind(changeSpread, changeSpreadObj.deletePress);
         changeSpreadSheet.getCell(-1, 10).foreColor('#dc3545');
 
+        let batchInsertObj;
+        $.contextMenu.types.batchInsert = function (item, opt, root) {
+            const self = this;
+            if ($.isFunction(item.icon)) {
+                item._icon = item.icon.call(this, this, $t, key, item);
+            } else {
+                if (typeof(item.icon) === 'string' && item.icon.substring(0, 3) === 'fa-') {
+                    // to enable font awesome
+                    item._icon = root.classNames.icon + ' ' + root.classNames.icon + '--fa fa ' + item.icon;
+                } else {
+                    item._icon = root.classNames.icon + ' ' + root.classNames.icon + '-' + item.icon;
+                }
+            }
+            this.addClass(item._icon);
+            const $obj = $('<div>' + item.name + '<input class="text-right ml-1 mr-1" type="tel" max="100" min="1" value="' + item.value + '" style="width: 30px; height: 18px; padding-right: 4px;">行</div>')
+                .appendTo(this);
+            const $input = $obj.find('input');
+            const event = () => {
+                if (self.hasClass('context-menu-disabled')) return;
+                item.batchInsert($input[0], root);
+            };
+            $obj.on('click', event).keypress(function (e) {if (e.keyCode === 13) { event(); }});
+            $input.click((e) => {e.stopPropagation();})
+                .keyup((e) => {if (e.keyCode === 13) item.batchInsert($input[0], root);})
+                .on('input', function () {this.value = this.value.replace(/[^\d]/g, '');});
+        };
+
         // 右键菜单
         $.contextMenu({
             selector: '#change-spread',
@@ -498,6 +537,25 @@ $(document).ready(() => {
                         changeSpreadObj.add(changeSpreadSheet);
                     },
                 },
+                'batchInsert': {
+                    name: '批量添加空白清单',
+                    type: 'batchInsert',
+                    value: '2',
+                    icon: 'fa-sign-in',
+                    batchInsert: function (obj, root) {
+                        if (_.toNumber(obj.value) > _.toNumber(obj.max)) {
+                            obj.value = obj.max;
+                            toastr.warning('批量添加不可多于' + obj.max);
+                        } else if(_.toNumber(obj.value) < _.toNumber(obj.min)) {
+                            obj.value = obj.min;
+                            toastr.warning('批量添加不可少于' + obj.min);
+                        } else {
+                            // treeOperationObj.addNode(ledgerSpread.getActiveSheet(), parseInt(obj.value));
+                            changeSpreadObj.batchAdd(obj.value);
+                            root.$menu.trigger('contextmenu:hide');
+                        }
+                    },
+                },
                 'delete': {
                     name: '删除',
                     icon: 'fa-remove',

+ 1 - 1
app/public/js/change_information_show.js

@@ -188,7 +188,7 @@ $(document).ready(() => {
         const btn = $(this);
 
         $.ajax({
-            url: '/profile/code?_csrf=' + csrf,
+            url: '/profile/code?_csrf_j=' + csrf,
             type: 'post',
             data: { mobile: authMobile, type: 'shenpi' },
             dataTye: 'json',

+ 72 - 4
app/public/js/global.js

@@ -101,6 +101,12 @@ $(function(){
         }
         $(this).data("datepicker", "1");
     });
+
+    $('a[href="/setting/user"]').each(function () {
+        if (getLocalCache('account-pageSize')) {
+            $(this).attr('href', $(this).attr('href') + '?pageSize=' + getLocalCache('account-pageSize'));
+        }
+    });
 });
 
 function checkShowLast (count) {
@@ -151,7 +157,7 @@ const postData = function (url, data, successCallback, errorCallBack, showWaitin
         cache: false,
         timeout: 60000,
         beforeSend: function(xhr) {
-            let csrfToken = Cookies.get('csrfToken');
+            let csrfToken = Cookies.get('csrfToken_j');
             xhr.setRequestHeader('x-csrf-token', csrfToken);
         },
         success: function(result){
@@ -200,7 +206,7 @@ const postDataCompress = function (url, data, successCallback, errorCallBack, ht
         cache: false,
         timeout: 80000, // 导入清单Excel(10w行)预计需要时间
         beforeSend: function(xhr) {
-            let csrfToken = Cookies.get('csrfToken');
+            let csrfToken = Cookies.get('csrfToken_j');
             xhr.setRequestHeader('x-csrf-token', csrfToken);
         },
         success: function(result){
@@ -260,7 +266,7 @@ const postDataWithFile = function (url, formData, successCallback, errorCallBack
         processData: false,
         timeout: 60000,
         beforeSend: function(xhr) {
-            let csrfToken = Cookies.get('csrfToken');
+            let csrfToken = Cookies.get('csrfToken_j');
             xhr.setRequestHeader('x-csrf-token', csrfToken);
         },
         success: function(result){
@@ -304,7 +310,7 @@ const postDataWithFileProgress = function (url, formData, successCallback, error
         // 告诉jQuery不要去处理发送的数据
         processData: false,
         beforeSend: function(xhr) {
-            let csrfToken = Cookies.get('csrfToken');
+            let csrfToken = Cookies.get('csrfToken_j');
             xhr.setRequestHeader('x-csrf-token', csrfToken);
         },
         success: function(result){
@@ -860,6 +866,50 @@ $.fn.extend({
     }
 });
 
+const checkUtils = {
+    posOver(data) {
+        if (!data) return false;
+        if (!data.quantity) return !!data.end_contract_qty;
+        return data.quantity > 0
+            ? data.end_contract_qty > data.quantity
+            : data.end_contract_qty < data.quantity || data.end_contract_qty > 0;
+    },
+    billsOver(data, isTz, relaPos) {
+        if (!data) return false;
+        if (isTz) {
+            const posRange = relaPos.ledgerPos[itemsPre + data.id] || [];
+            if (posRange.length > 0) {
+                for (const p of posRange) {
+                    if (checkUtils.posOver(p)) return true;
+                }
+                return false;
+            }
+            if (data.is_tp) {
+                if (!data.total_price) return !!data.end_contract_tp;
+                return data.total_price > 0
+                    ? data.end_contract_tp > data.total_price
+                    : data.end_contract_tp < data.total_price || data.end_contract_tp > 0;
+            } else {
+                if (!data.quantity) return !!data.end_contract_qty;
+                return data.quantity > 0
+                    ? data.end_contract_qty > data.quantity
+                    : data.end_contract_qty < data.quantity || data.end_contract_qty > 0;
+            }
+        } else {
+            if (data.is_tp) {
+                if (!data.deal_tp) return !!data.end_contract_tp;
+                return data.deal_tp > 0
+                    ? data.end_contract_tp > data.deal_tp
+                    : data.end_contract_tp < data.deal_tp || data.end_contract_tp > 0;
+            } else {
+                if (!data.deal_qty) return !!data.end_contract_qty;
+                return data.deal_qty > 0
+                    ? data.end_contract_qty > data.deal_qty
+                    : data.end_contract_qty < data.deal_qty || data.end_contract_qty > 0;
+            }
+        }
+    }
+};
 
 Number.prototype.format2Str = function (pattern) {
     var strarr = this?this.toString().split('.'):['0'];
@@ -915,3 +965,21 @@ Number.prototype.format2Str = function (pattern) {
     }
     return retstr.replace(/^,+/,'').replace(/\.$/,'');
 };
+
+function transFormToChinese(num) {
+    const changeNum = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
+    const unit = ["", "十", "百", "千", "万"];
+    num = parseInt(num);
+    let getWan = (temp) => {
+        let strArr = temp.toString().split("").reverse();
+        let newNum = "";
+        for (var i = 0; i < strArr.length; i++) {
+            newNum = (i == 0 && strArr[i] == 0 ? "" : (i > 0 && strArr[i] == 0 && strArr[i - 1] == 0 ? "" : changeNum[strArr[i]] + (strArr[i] == 0 ? unit[0] : unit[i]))) + newNum;
+        }
+        return strArr.length === 2 && newNum.indexOf("一十") !== -1 ? newNum.replace('一十', '十') : newNum;
+    }
+    let overWan = Math.floor(num / 10000);
+    let noWan = num % 10000;
+    if (noWan.toString().length < 4) noWan = "0" + noWan;
+    return overWan ? getWan(overWan) + "万" + getWan(noWan) : getWan(num);
+}

+ 3 - 3
app/public/js/ledger.js

@@ -51,7 +51,8 @@ const checkOption = {
             {qty: 'quantity', tp: 'total_price'},
             {qty: 'deal_qty', tp: 'deal_tp'},
         ],
-    }
+    },
+    same_code: { enable: 1 },
 };
 
 $(document).ready(function() {
@@ -1820,7 +1821,6 @@ $(document).ready(function() {
                     return;
                 }
 
-                //const node = treeOperationObj.getSelectNode(ledgerSpread.getActiveSheet());
                 const node = posOperationObj.ledgerTreeNode;
                 if (!node) {
                     toastr.error('数据错误,请选择台账节点后再试');
@@ -1830,7 +1830,7 @@ $(document).ready(function() {
                     toastr.error('父节点不可插入计量单元');
                     SpreadJsObj.reLoadRowData(info.sheet, info.row);
                     return;
-                } else if (newText && newText !== '' && (!node.b_code || node.b_code === '')) {
+                }else if (newText && newText !== '' && (!node.b_code || node.b_code === '')) {
                     toastr.error('项目节不可插入计量单元');
                     SpreadJsObj.reLoadRowData(info.sheet, info.row);
                     return;

+ 34 - 67
app/public/js/ledger_check.js

@@ -10,15 +10,16 @@
 
 
 const ledgerCheckType = {
-    sibling: {value: 1, text: '项目节、清单同层'},
-    empty_code: {value: 2, text: '项目节、清单编号同时为空'},
-    calc: {value: 3, text: '清单数量不等于计量单元之和'},
-    zero: {value: 4, text: '清单数量或单价为0'},
-    tp: {value: 5, text: '清单金额≠数量×单价'},
-    over: {value: 6, text: '超计'},
+    sibling: {value: 1, text: '项目节、清单同层', fun: 'checkSibling', },
+    empty_code: {value: 2, text: '项目节、清单编号同时为空', fun: 'checkCodeEmpty', },
+    calc: {value: 3, text: '清单数量不等于计量单元之和', fun: 'checkCalc', },
+    zero: {value: 4, text: '清单数量或单价为0', fun: 'checkZero', },
+    tp: {value: 5, text: '清单金额≠数量×单价', fun: 'checkTp', },
+    over: {value: 6, text: '超计', fun: 'checkOver', },
+    same_code: {value: 7, text: '重复项目节', fun: 'checkSameCode', },
 };
 const ledgerCheckUtil = {
-    checkSibling: function (ledgerTree) {
+    checkSibling: function (ledgerTree, ledgerPos, decimal, option) {
         const error = [];
         for (const node of ledgerTree.nodes) {
             if (!node.children || node.children.length === 0) continue;
@@ -31,7 +32,7 @@ const ledgerCheckUtil = {
         }
         return error;
     },
-    checkCodeEmpty: function (ledgerTree) {
+    checkCodeEmpty: function (ledgerTree, ledgerPos, decimal, option) {
         const error = [];
         const checkNodeCode = function (node) {
             if ((!node.code || node.code === '') && (!node.b_code || node.b_code === '')) error.push(node);
@@ -40,15 +41,15 @@ const ledgerCheckUtil = {
                     checkNodeCode(child);
                 }
             }
-        }
+        };
         for (const topLevel of ledgerTree.children) {
-            if (topLevel.node_type !== 1) continue;
+            if ([1, 3, 4].indexOf(topLevel.node_type) < 0) continue;
 
             checkNodeCode(topLevel);
         }
         return error;
     },
-    checkCalc: function (ledgerTree, ledgerPos, option) {
+    checkCalc: function (ledgerTree, ledgerPos, decimal, option) {
         const error = [];
         for (const node of ledgerTree.nodes) {
             if (node.children && node.children.length > 0) continue;
@@ -70,7 +71,7 @@ const ledgerCheckUtil = {
         }
         return error;
     },
-    checkZero: function (ledgerTree) {
+    checkZero: function (ledgerTree, ledgerPos, decimal, option) {
         const error = [];
         for (const node of ledgerTree.nodes) {
             if ((!node.b_code || node.b_code === '')) continue;
@@ -82,7 +83,7 @@ const ledgerCheckUtil = {
         }
         return error;
     },
-    checkTp: function (ledgerTree, decimal, option) {
+    checkTp: function (ledgerTree, ledgerPos, decimal, option) {
         const error = [];
         for (const node of ledgerTree.nodes) {
             if (node.children && node.children.length > 0) continue;
@@ -97,38 +98,27 @@ const ledgerCheckUtil = {
         }
         return error;
     },
-    checkOver: function(ledgerTree, ledgerPos, option) {
+    checkOver: function(ledgerTree, ledgerPos, decimal, option) {
         const error = [];
         for (const node of ledgerTree.nodes) {
             if (node.children && node.children.length > 0) continue;
 
-            if (option.isTz) {
-                const posRange = ledgerPos.getLedgerPos(node.id) || [];
-                if (posRange.length > 0) {
-                    for (const p of posRange) {
-                        if (p.end_contract_qty > p.quantity) {
-                            error.push(node);
-                            continue;
-                        }
-                    }
-                }
-            }
-            if (node.is_tp) {
-                if (option.isTz) {
-                    if (node.end_contract_tp > node.total_price) error.push(node);
-                } else {
-                    if (node.end_contract_tp > node.deal_tp) error.push(node);
-                }
-            } else {
-                if (option.isTz) {
-                    if (node.end_contract_qty > node.quantity) error.push(node);
-                } else {
-                    if (node.end_contract_qty > node.deal_qty) error.push(node);
-                }
-            }
+            if (checkUtils.billsOver(node, option.isTz, ledgerPos)) error.push(node);
         }
         return error;
     },
+    checkSameCode: function (ledgerTree, ledgerPos, decimal, option) {
+        const error = [];
+        let xmj = ledgerTree.nodes.filter(x => { return /^((GD*)|G)?[0-9]+/.test(x.code); });
+        let check = null;
+        while (xmj.length > 0) {
+            [check, xmj] = _.partition(xmj, x => { return x.code === xmj[0].code; });
+            if (check.length > 1) {
+                error.push(...check);
+            }
+        }
+        return error;
+    }
 };
 
 const ledgerCheck2 = function (setting) {
@@ -152,35 +142,12 @@ const ledgerCheck2 = function (setting) {
         warning_data: [],
     };
     const progressData = [];
-    if (checkOption.sibling.enable) {
-        const sibling = ledgerCheckUtil.checkSibling(ledger, checkOption.sibling) || [];
-        assignWarningData(sibling, ledgerCheckType.sibling.value, checkData.warning_data);
-        progressData.push({key: 'sibling', caption: ledgerCheckType.sibling.text, error: sibling.length});
-    }
-    if (checkOption.empty_code.enable) {
-        const empty_code = ledgerCheckUtil.checkCodeEmpty(ledger, checkOption.empty_code) || [];
-        assignWarningData(empty_code, ledgerCheckType.empty_code.value, checkData.warning_data);
-        progressData.push({key: 'empty_code', caption: ledgerCheckType.empty_code.text, error: empty_code.length});
-    }
-    if (checkOption.calc.enable) {
-        const calc = ledgerCheckUtil.checkCalc(ledger, ledgerPos, checkOption.calc) || [];
-        assignWarningData(calc, ledgerCheckType.calc.value, checkData.warning_data);
-        progressData.push({key: 'calc', caption: ledgerCheckType.calc.text, error: calc.length});
-    }
-    if (checkOption.zero.enable) {
-        const zero = ledgerCheckUtil.checkZero(ledger, checkOption.zero) || [];
-        assignWarningData(zero, ledgerCheckType.zero.value, checkData.warning_data);
-        progressData.push({key: 'zero', caption: ledgerCheckType.zero.text, error: zero.length});
-    }
-    if (checkOption.tp.enable) {
-        const tp = ledgerCheckUtil.checkTp(ledger, decimal, checkOption.tp) || [];
-        assignWarningData(tp, ledgerCheckType.tp.value, checkData.warning_data);
-        progressData.push({key: 'tp', caption: ledgerCheckType.tp.text, error: tp.length});
-    }
-    if (checkOption.over && checkOption.over.enable) {
-        const over = ledgerCheckUtil.checkOver(ledger, ledgerPos, checkOption.over) || [];
-        assignWarningData(over, ledgerCheckType.over.value, checkData.warning_data);
-        progressData.push({key: 'over', caption: ledgerCheckType.over.text, error: over.length});
+    for (const prop in ledgerCheckType) {
+        if (!checkOption[prop] || !checkOption[prop].enable) continue;
+
+        const errors = ledgerCheckUtil[ledgerCheckType[prop].fun](ledger, ledgerPos, decimal, checkOption[prop]) || [];
+        assignWarningData(errors, ledgerCheckType[prop].value, checkData.warning_data);
+        progressData.push({key: prop, caption: ledgerCheckType[prop].text, error: errors.length});
     }
     setting.checkList.clearCheckData();
     if (checkData.warning_data.length > 0) {

+ 0 - 169
app/public/js/number-precision.js

@@ -1,169 +0,0 @@
-var NP = (function (exports) {
-    'use strict';
-
-    /**
-     * @desc 解决浮动运算问题,避免小数点后产生多位数和计算精度损失。
-     * 问题示例:2.3 + 2.4 = 4.699999999999999,1.0 - 0.9 = 0.09999999999999998
-     */
-    /**
-     * 把错误的数据转正
-     * strip(0.09999999999999998)=0.1
-     */
-    function strip(num, precision) {
-        if (precision === void 0) { precision = 12; }
-        return +parseFloat(num.toPrecision(precision));
-    }
-    /**
-     * Return digits length of a number
-     * @param {*number} num Input number
-     */
-    function digitLength(num) {
-        // Get digit length of e
-        var eSplit = num.toString().split(/[eE]/);
-        var len = (eSplit[0].split('.')[1] || '').length - (+(eSplit[1] || 0));
-        return len > 0 ? len : 0;
-    }
-    function powLength(num) {
-        var eSplit = num.toString().split(/[eE]/);
-        var rs = num.toString().reverse();
-        var rs1 = rs.replace('/^0+/g', '');
-        return rs.length - rs1.length;
-    }
-    /**
-     * 把小数转成整数,支持科学计数法。如果是小数则放大成整数
-     * @param {*number} num 输入数
-     */
-    function float2Fixed(num) {
-        if (num.toString().indexOf('e') === -1) {
-            return Number(num.toString().replace('.', ''));
-        }
-        var dLen = digitLength(num);
-        return dLen > 0 ? strip(num * Math.pow(10, dLen)) : num;
-    }
-    /**
-     * 检测数字是否越界,如果越界给出提示
-     * @param {*number} num 输入数
-     */
-    function checkBoundary(num) {
-        if (_boundaryCheckingState) {
-            if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) {
-                console.warn(num + " is beyond boundary when transfer to integer, the results may not be accurate");
-            }
-        }
-    }
-    /**
-     * 精确乘法
-     */
-    function times(num1, num2) {
-        var others = [];
-        for (var _i = 2; _i < arguments.length; _i++) {
-            others[_i - 2] = arguments[_i];
-        }
-        if (others.length > 0) {
-            return times.apply(void 0, [times(num1, num2), others[0]].concat(others.slice(1)));
-        }
-        var num1Changed = float2Fixed(num1);
-        var num2Changed = float2Fixed(num2);
-        var baseNum = digitLength(num1) + digitLength(num2);
-        var leftValue = num1Changed * num2Changed;
-        checkBoundary(leftValue);
-        return leftValue / Math.pow(10, baseNum);
-    }
-    /**
-     * 精确加法
-     */
-    function plus(num1, num2) {
-        var others = [];
-        for (var _i = 2; _i < arguments.length; _i++) {
-            others[_i - 2] = arguments[_i];
-        }
-        if (others.length > 0) {
-            return plus.apply(void 0, [plus(num1, num2), others[0]].concat(others.slice(1)));
-        }
-        var baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
-        return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
-        //return (num1 + num2) / baseNum;
-    }
-    /**
-     * 精确减法
-     */
-    function minus(num1, num2) {
-        var others = [];
-        for (var _i = 2; _i < arguments.length; _i++) {
-            others[_i - 2] = arguments[_i];
-        }
-        if (others.length > 0) {
-            return minus.apply(void 0, [minus(num1, num2), others[0]].concat(others.slice(1)));
-        }
-        var digit1 = digitLength(num1);
-        var digit2 = digitLength(num2);
-        var baseNum = Math.pow(10, Math.max(digit1, digit2));
-        return round((times(num1, baseNum) - times(num2, baseNum)) / baseNum, digit1>=digit2 ? digit1 : digit2);
-    }
-    /**
-     * 精确除法
-     */
-    function divide(num1, num2) {
-        var others = [];
-        for (var _i = 2; _i < arguments.length; _i++) {
-            others[_i - 2] = arguments[_i];
-        }
-        if (others.length > 0) {
-            return divide.apply(void 0, [divide(num1, num2), others[0]].concat(others.slice(1)));
-        }
-        var num1Changed = float2Fixed(num1);
-        var num2Changed = float2Fixed(num2);
-        checkBoundary(num1Changed);
-        checkBoundary(num2Changed);
-        return times((num1Changed / num2Changed), Math.pow(10, digitLength(num2) - digitLength(num1)));
-    }
-    /**
-     * 四舍五入
-     */
-    function round(num, ratio) {
-        var base = Math.pow(10, ratio);
-        return divide(Math.round(times(num, base)), base);
-    }
-    var _boundaryCheckingState = true;
-    /**
-     * 是否进行边界检查,默认开启
-     * @param flag 标记开关,true 为开启,false 为关闭,默认为 true
-     */
-    function enableBoundaryChecking(flag) {
-        if (flag === void 0) { flag = true; }
-        _boundaryCheckingState = flag;
-    }
-    var index = { strip: strip, plus: plus, minus: minus, times: times, divide: divide, round: round, digitLength: digitLength, float2Fixed: float2Fixed, enableBoundaryChecking: enableBoundaryChecking };
-
-    exports.strip = strip;
-    exports.plus = plus;
-    exports.minus = minus;
-    exports.times = times;
-    exports.divide = divide;
-    exports.round = round;
-    exports.digitLength = digitLength;
-    exports.float2Fixed = float2Fixed;
-    exports.enableBoundaryChecking = enableBoundaryChecking;
-    exports['default'] = index;
-
-    return exports;
-
-}({}));
-
-function transFormToChinese(num) {
-    const changeNum = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
-    const unit = ["", "十", "百", "千", "万"];
-    num = parseInt(num);
-    let getWan = (temp) => {
-        let strArr = temp.toString().split("").reverse();
-        let newNum = "";
-        for (var i = 0; i < strArr.length; i++) {
-            newNum = (i == 0 && strArr[i] == 0 ? "" : (i > 0 && strArr[i] == 0 && strArr[i - 1] == 0 ? "" : changeNum[strArr[i]] + (strArr[i] == 0 ? unit[0] : unit[i]))) + newNum;
-        }
-        return strArr.length === 2 && newNum.indexOf("一十") !== -1 ? newNum.replace('一十', '十') : newNum;
-    }
-    let overWan = Math.floor(num / 10000);
-    let noWan = num % 10000;
-    if (noWan.toString().length < 4) noWan = "0" + noWan;
-    return overWan ? getWan(overWan) + "万" + getWan(noWan) : getWan(num);
-}

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

@@ -52,7 +52,7 @@ $(document).ready(function() {
             const btn = $(this);
 
             $.ajax({
-                url: '/profile/code?_csrf=' + csrf,
+                url: '/profile/code?_csrf_j=' + csrf,
                 type: 'post',
                 data: { mobile: mobile },
                 dataTye: 'json',
@@ -92,7 +92,7 @@ $(document).ready(function() {
                 return false;
             }
             $.ajax({
-                url: '/profile/bind?_csrf=' + csrf,
+                url: '/profile/bind?_csrf_j=' + csrf,
                 type: 'post',
                 data: { auth_mobile: mobile, code: code },
                 dataTye: 'json',

+ 8 - 1
app/public/js/setting.js

@@ -84,7 +84,7 @@ $(document).ready(() => {
                     throw '网络错误!';
                 },
                 beforeSend: function(xhr) {
-                    let csrfToken = Cookies.get('csrfToken');
+                    let csrfToken = Cookies.get('csrfToken_j');
                     xhr.setRequestHeader('x-csrf-token', csrfToken);
                     isChange = true;
                     btn.html('<i class="fa fa-spinner fa-pulse"></i>');
@@ -193,6 +193,13 @@ $(document).ready(() => {
             $('#nav_tender').attr('href', item.path)
         });
     });
+    // 设置页显示数目
+    $('.nav-tabs .nav-link').each(function () {
+        const pageSize = getLocalCache('account-pageSize') ? getLocalCache('account-pageSize') : '';
+        if (getLocalCache('account-pageSize')) {
+            $(this).attr('href', $(this).attr('href') + '?pageSize=' + getLocalCache('account-pageSize'));
+        }
+    });
 });
 
 function checkPasswordForm() {

+ 1 - 0
app/public/js/shares/cs_tools.js

@@ -75,6 +75,7 @@ const showSelectTab = function(select, spread, afterShow) {
                             switch (x.errorType) {
                                 case 'qty': return '数量';
                                 case 'tp': return '金额';
+                                case 'over': return '超计';
                                 default: return '';
                             }
                         }

+ 4 - 2
app/public/js/spreadjs_rela/spreadjs_zh.js

@@ -662,7 +662,8 @@ const SpreadJsObj = {
         }
         if (colSetting.cellType === 'unit') {
             if (!sheet.extendCellType.unit) {
-                sheet.extendCellType.unit = colSetting.comboItems ? this.CellType.getUnitCellType(colSetting.comboItems) : this.CellType.getUnitCellType();
+                const comboEdit = colSetting.comboEdit ? colSetting.comboEdit : false;
+                sheet.extendCellType.unit = colSetting.comboItems ? this.CellType.getUnitCellType(comboEdit, colSetting.comboItems) : this.CellType.getUnitCellType(comboEdit);
                 SpreadJsObj._addActivePaintEvents(sheet, sheet.extendCellType.unit);
             }
             sheet.getRange(-1, col, -1, 1).cellType(sheet.extendCellType.unit);
@@ -2167,11 +2168,12 @@ const SpreadJsObj = {
          * 获取 单位的CellType
          * @returns {GC.Spread.Sheets.CellTypes.ComboBox}
          */
-        getUnitCellType: function (items = ['m', 'km', 'm2', 'm3', 'dm3', 'kg', 't', 'm3·km',
+        getUnitCellType: function (comboEdit, items = ['m', 'km', 'm2', 'm3', 'dm3', 'kg', 't', 'm3·km',
             '总额', '月' ,'项', '处' ,'个', '根', '棵', '块', '台', '系统', '延米', '每一试桩',
             '桥长米', '公路公里', '株', '组', '座', '元', '工日', '套', '台班', '艘班', '亩', '片',
             'm/处', 'm/道', 'm/座', 'm2/m', 'm3/m', 'm3/处', '根/米', 'm3/m2']) {
             let combo = this.getActiveComboCellType();
+            combo.editable(comboEdit);
             combo.itemHeight(10).items(items);
             return combo;
         },

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

@@ -641,25 +641,7 @@ $(document).ready(() => {
                 if (def && def.color) return def.color;
             }
 
-            if (checkTzMeasureType()) {
-                const posRange = stagePos.ledgerPos[itemsPre + data.id] || [];
-                if (posRange.length > 0) {
-                    for (const p of posRange) {
-                        if (p.end_contract_qty > p.quantity) return '#f8d7da';
-                    }
-                }
-                if (data.is_tp) {
-                    return data.end_contract_tp > data.total_price ? '#f8d7da' : defaultColor;
-                } else {
-                    return data.end_contract_qty > data.quantity ? '#f8d7da' : defaultColor;
-                }
-            } else {
-                if (data.is_tp) {
-                    return data.end_contract_tp > data.deal_tp ? '#f8d7da' : defaultColor;
-                } else {
-                    return data.end_contract_qty > data.deal_qty ? '#f8d7da' : defaultColor;
-                }
-            }
+            return checkUtils.billsOver(data, checkTzMeasureType(), stagePos) ? '#f8d7da' : defaultColor;
         } else {
             return defaultColor;
         }
@@ -753,7 +735,7 @@ $(document).ready(() => {
             }
         }
         if (checkTzMeasureType()) {
-            return data && data.end_contract_qty > data.quantity ? '#f8d7da' : defaultColor;
+            return checkUtils.posOver(data)  ? '#f8d7da' : defaultColor;
         }
     };
     sjsSettingObj.setGridSelectStyle(posSpreadSetting);
@@ -3559,25 +3541,7 @@ $(document).ready(() => {
                         }, {
                             key: 'over', title: '超计', valid: true,
                             check: function (node) {
-                                if (checkTzMeasureType()) {
-                                    const posRange = stagePos.ledgerPos[itemsPre + node.id] || [];
-                                    if (posRange.length > 0) {
-                                        for (const p of posRange) {
-                                            if (p.end_contract_qty > p.quantity) return true;
-                                        }
-                                        return false;
-                                    } else if (node.end_gather_qty) {
-                                        return !node.quantity || Math.abs(node.end_gather_qty) > Math.abs(ZhCalc.add(node.quantity, node.end_qc_qty));
-                                    } else if (node.end_gather_tp) {
-                                        return !node.total_price || Math.abs(node.end_gather_tp) > Math.abs(ZhCalc.add(node.total_price, node.end_qc_tp));
-                                    }
-                                } else {
-                                    if (node.end_gather_qty) {
-                                        return !node.deal_qty || Math.abs(node.end_gather_qty) > Math.abs(ZhCalc.add(node.deal_qty, node.end_qc_qty));
-                                    } else if (node.end_gather_tp) {
-                                        return !node.deal_tp || Math.abs(node.end_gather_tp) > Math.abs(ZhCalc.add(node.deal_tp, node.end_qc_tp));
-                                    }
-                                }
+                                return checkUtils.billsOver(node, checkTzMeasureType(), stagePos);
                             }
                         }, {
                             key: 'empty', title: '漏计', valid: false,

+ 1 - 1
app/public/js/stage_audit.js

@@ -218,7 +218,7 @@ $(document).ready(function () {
         const btn = $(this);
 
         $.ajax({
-            url: '/profile/code?_csrf=' + csrf,
+            url: '/profile/code?_csrf_j=' + csrf,
             type: 'post',
             data: { mobile: authMobile, type: 'shenpi' },
             dataTye: 'json',

+ 15 - 6
app/public/js/stage_gather.js

@@ -79,16 +79,25 @@ $(document).ready(function () {
     }
     // 超计显示
     function checkOverRange(data) {
+        const billsGatherOver = function (data, qtyField, tpField, per) {
+            if (data.end_contract_qty) {
+                if (!data[qtyField]) return true;
+                return data[qtyField] > 0
+                    ? data.end_contract_qty > ZhCalc.mul(data[qtyField], per)
+                    : data.end_contract_qty < ZhCalc.mul(data[qtyField], per) || data.end_contract_qty > 0;
+            } else {
+                if (!data[tpField]) return !!data.end_contract_tp;
+                return data[tpField] > 0
+                    ? data.end_contract_tp > ZhCalc.mul(data[tpField], per)
+                    : data.end_contract_tp < ZhCalc.mul(data[tpField], per) || data.end_contract_tp > 0;
+            }
+        };
         const bQty = $('#customRadio1')[0].checked, bDealQty = $('#customRadio2')[0].checked;
         const nPercent = Math.min(Math.max(ZhCalc.div(parseFloat($('#over-percent').val()), 100), 0.5), 1);
         for (const node of data) {
             if (node) {
-                const bOverRangeTz = node.end_contract_qty
-                    ? (node.quantity ? node.end_contract_qty > ZhCalc.mul(node.quantity, nPercent) : node.end_contract_qty)
-                    : (node.total_price ? node.end_contract_tp > ZhCalc.mul(node.total_price, nPercent) : node.end_contract_tp);
-                const bOverRangeDeal = node.end_contract_qty
-                    ? (node.deal_bills_qty ? node.end_contract_qty > ZhCalc.mul(node.deal_bills_qty, nPercent) : node.end_contract_qty)
-                    : (node.deal_bills_tp ? node.end_contract_tp > ZhCalc.mul(node.deal_bills_tp, nPercent) : node.end_contract_tp);
+                const bOverRangeTz = billsGatherOver(node, 'quantity', 'total_price', nPercent);
+                const bOverRangeDeal = billsGatherOver(node, 'deal_bills_qty', 'deal_bills_tp', nPercent);
                 node.overRange = bQty ? bOverRangeTz : (bDealQty ? bOverRangeDeal : bOverRangeTz || bOverRangeDeal);
             }
         }

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

@@ -244,14 +244,14 @@ $(document).ready(() => {
                 if (payBase.isOld(data)) {
                     return payBase.isStarted(data) || !payBase.isYB(data);
                 } else {
-                    return payBase.isWC(data) || payBase.isSF(data) || !(payBase.isOwner(data) || payBase.isYB());
+                    return payBase.isWC(data) || payBase.isSF(data) || payBase.isYF(data) || !(payBase.isOwner(data) || payBase.isYB());
                 }
             },
             rprice: function (data) {
                 if (payBase.isOld(data)) {
                     return !payBase.isYB(data);
                 } else {
-                    return payBase.isWC(data) || payBase.isSF(data) && !(payBase.isOwner(data) || payBase.isYB());
+                    return payBase.isWC(data) || payBase.isSF(data) || payBase.isYF(data) || !(payBase.isOwner(data) || payBase.isYB());
                 }
             },
         },

+ 1 - 1
app/public/js/wap/global.js

@@ -24,7 +24,7 @@ const postData = function (url, data, successCallback, errorCallBack, showWaitin
         cache: false,
         timeout: 60000,
         beforeSend: function(xhr) {
-            let csrfToken = Cookies.get('csrfToken');
+            let csrfToken = Cookies.get('csrfToken_j');
             xhr.setRequestHeader('x-csrf-token', csrfToken);
         },
         success: function(result){

+ 4 - 4
app/public/report/js/rpt_main.js

@@ -363,7 +363,7 @@ let zTreeOprObj = {
             params.needWaterMark = false;
         }
         $.bootstrapLoading.start();
-        CommonAjax.postXsrfEx("/tender/report_api/getReport", params, 300000, true, getCookie('csrfToken'),
+        CommonAjax.postXsrfEx("/tender/report_api/getReport", params, 300000, true, getCookie('csrfToken_j'),
             function(result){
                 $.bootstrapLoading.end();
                 let pageRst = result.data;
@@ -576,7 +576,7 @@ let rptControlObj = {
             if (chkNodes.length > 0) {
                 delete params.orientation; // 打印时有勾选的话,不需要提供方向
             }
-            CommonAjax.postXsrfEx("/tender/report_api/createExcelFilesInOneBook", params, WAIT_TIME_EXPORT, true, getCookie('csrfToken'), function(result){
+            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";
@@ -608,7 +608,7 @@ let rptControlObj = {
                 delete params.orientation; // 打印时有勾选的话,不需要提供方向
             }
 
-            CommonAjax.postXsrfEx("/tender/report_api/createExcelFiles", params, WAIT_TIME_EXPORT, true, getCookie('csrfToken'), function(result){
+            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) {
@@ -703,7 +703,7 @@ let rptControlObj = {
                 } else {
                     params.needWaterMark = false;
                 }
-                CommonAjax.postXsrfEx("/tender/report_api/getMultiReports", params, WAIT_TIME_EXPORT, true, getCookie('csrfToken'),
+                CommonAjax.postXsrfEx("/tender/report_api/getMultiReports", params, WAIT_TIME_EXPORT, true, getCookie('csrfToken_j'),
                     function(result){
                         // closeWaitingView();
                         $.bootstrapLoading.end();

+ 1 - 1
app/public/report/js/rpt_preview_common.js

@@ -33,7 +33,7 @@ function printPageLoading() {
     STAGE_LIST = JSON.parse(sessionStorage.STAGE_LIST);
     STAGE_AUDIT_ORG = JSON.parse(sessionStorage.STAGE_AUDIT_ORG);
     let scaleFactor = 1;
-    CommonAjax.postXsrfEx("/tender/report_api/getMultiReports", params, 60000, true, getCookie('csrfToken'),
+    CommonAjax.postXsrfEx("/tender/report_api/getMultiReports", params, 60000, true, getCookie('csrfToken_j'),
         function(result){
             const signatureRelArr = [];
             STAGE_AUDIT = result.stageAudit;

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

@@ -50,7 +50,7 @@ let rptPrintHelper = {
             } else {
                 params.needWaterMark = false;
             }
-            CommonAjax.postXsrfEx("/tender/report_api/getMultiReports", params, 60000, true, getCookie('csrfToken'),
+            CommonAjax.postXsrfEx("/tender/report_api/getMultiReports", params, 60000, true, getCookie('csrfToken_j'),
                 function(result){
                     const signatureRelArr = [];
                     for (const signatureRel of result.signatureRelInfo) {

+ 4 - 4
app/public/report/js/rpt_signature.js

@@ -171,7 +171,7 @@ let rptSignatureHelper = {
             params.uid = userAcc.id;
             params.prj_id = PROJECT_ID;
             params.tender_id = TENDER_ID;
-            CommonAjax.postXsrfEx("/tender/report_api/updateSignatureUsed", params, 10000, true, getCookie('csrfToken'),
+            CommonAjax.postXsrfEx("/tender/report_api/updateSignatureUsed", params, 10000, true, getCookie('csrfToken_j'),
                 function(result){
                     console.log(result);
                     USED_LIST = result.data;
@@ -443,7 +443,7 @@ let rptSignatureHelper = {
         params.rel_content = ROLE_REL_LIST;
         params.selectedTenders = selectedTenders;
         rptSignatureHelper.originalRoleRelList = JSON.parse(JSON.stringify(ROLE_REL_LIST));
-        CommonAjax.postXsrfEx("/tender/report_api/updateMultiRoleRelationship", params, 10000, true, getCookie('csrfToken'),
+        CommonAjax.postXsrfEx("/tender/report_api/updateMultiRoleRelationship", params, 10000, true, getCookie('csrfToken_j'),
             function(result){
                 console.log(result);
                 if (result.data && result.data.insertId > 0) {
@@ -484,7 +484,7 @@ let rptSignatureHelper = {
         // rptSignatureHelper.originalRoleRelList = [];
         // rptSignatureHelper.originalRoleRelList = rptSignatureHelper.originalRoleRelList.concat(ROLE_REL_LIST);
         rptSignatureHelper.originalRoleRelList = JSON.parse(JSON.stringify(ROLE_REL_LIST));
-        CommonAjax.postXsrfEx("/tender/report_api/updateRoleRelationship", params, 10000, true, getCookie('csrfToken'),
+        CommonAjax.postXsrfEx("/tender/report_api/updateRoleRelationship", params, 10000, true, getCookie('csrfToken_j'),
             function(result){
                 console.log(result);
                 if (result.data && result.data.insertId > 0) {
@@ -513,7 +513,7 @@ let rptSignatureHelper = {
             params.bind_acc_id = selectedAcc.id;
             params.prj_id = PROJECT_ID;
             params.tender_id = TENDER_ID;
-            CommonAjax.postXsrfEx("/tender/report_api/createSignatureRole", params, 10000, true, getCookie('csrfToken'),
+            CommonAjax.postXsrfEx("/tender/report_api/createSignatureRole", params, 10000, true, getCookie('csrfToken_j'),
                 function(result){
                     console.log(result);
                     const newRole = {};

+ 5 - 2
app/router.js

@@ -85,6 +85,10 @@ module.exports = app => {
     // 操作日志
     app.get('/setting/logs', sessionAuth, 'settingController.logs');
     app.get('/setting/logs/type/:type', sessionAuth, 'settingController.logs');
+    // 功能设置
+    app.get('/setting/fun', sessionAuth, 'settingController.fun');
+    app.post('/setting/fun/update', sessionAuth, 'settingController.updateFun');
+
 
     // 项目相关
     app.get('/project/info', sessionAuth, 'projectController.info');
@@ -123,6 +127,7 @@ module.exports = app => {
     app.post('/tender/:id/shenpi/ledger/load', sessionAuth, tenderCheck, 'tenderController.loadLedgerData');
     app.post('/tender/:id/shenpi/save-sign', sessionAuth, tenderCheck, 'tenderController.saveCooperateSign');
     app.post('/tender/:id/copy-setting', sessionAuth, tenderCheck, 'tenderController.copyTender');
+    app.post('/tender/:id/tourist/audit/save', sessionAuth, tenderCheck, uncheckTenderCheck, 'tenderController.saveTourist');
 
     // 预付款
     app.get('/tender/:id/advance', sessionAuth, tenderCheck, 'advanceController.index');
@@ -470,6 +475,4 @@ module.exports = app => {
     app.get('/wxAuth', 'loginController.wxAuth');
     app.get('/wxproject', 'loginController.wxProject');
     app.get('/wx/url2web', 'loginController.url2web');
-
-    app.get('/wx/unionid', wechatAuth, 'wechatController.batchUpdateUnionid');
 };

+ 4 - 1
app/service/advance.js

@@ -105,7 +105,10 @@ module.exports = app => {
             const { ctx } = this;
             const uid = ctx.session.sessionUser.accountId;
             const tid = ctx.tender.id;
-            let latestOrder = await this.getLastestAdvance(tid, type);
+            let latestOrder = await this.getLastestAdvance(tid, type, true);
+            if (latestOrder && latestOrder.status === auditConst.status.uncheck) {
+                return '';
+            }
             if (!latestOrder) {
                 latestOrder = {
                     order: 1,

+ 69 - 66
app/service/change.js

@@ -230,53 +230,58 @@ module.exports = app => {
         async getListByStatus(tenderId, status = 0, hadlimit = 1) {
             let sql = '';
             let sqlParam = '';
-            switch (status) {
-                case 0: // 包含你的所有变更令
-                    sql =
-                        'SELECT a.* FROM ?? AS a WHERE a.tid = ? AND ' +
-                        '(a.uid = ? OR (a.status != ? AND a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid)) OR a.status = ? ) ORDER BY a.in_time DESC';
-                    sqlParam = [
-                        this.tableName,
-                        tenderId,
-                        this.ctx.session.sessionUser.accountId,
-                        audit.flow.status.uncheck,
-                        this.ctx.service.changeAudit.tableName,
-                        this.ctx.session.sessionUser.accountId,
-                        audit.flow.status.checked,
-                    ];
-                    break;
-                case 1: // 待处理(你的)
-                    sql = 'SELECT a.* FROM ?? as a WHERE cid in(SELECT b.cid FROM ?? as b WHERE tid = ? AND uid = ? AND status = ?) ORDER BY in_time DESC';
-                    sqlParam = [this.tableName, this.ctx.service.changeAudit.tableName, tenderId, this.ctx.session.sessionUser.accountId, audit.flow.auditStatus.checking];
-                    break;
-                case 5: // 待上报(所有的)PS:取未上报和退回的变更令
-                    sql =
-                        'SELECT a.* FROM ?? AS a WHERE ' +
-                        'a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? GROUP BY b.cid) AND ' +
-                        '(a.status = ? OR a.status = ?) AND a.tid = ? ORDER BY a.in_time DESC';
-                    sqlParam = [
-                        this.tableName,
-                        this.ctx.service.changeAudit.tableName,
-                        this.ctx.session.sessionUser.accountId,
-                        audit.flow.status.uncheck,
-                        audit.flow.status.back,
-                        tenderId,
-                    ];
-                    break;
-                case 2: // 进行中(所有的)
-                case 4: // 终止(所有的)
-                    sql =
-                        'SELECT a.* FROM ?? AS a WHERE ' +
-                        'a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid) AND ' +
-                        'a.status = ? AND a.tid = ? ORDER BY a.in_time DESC';
-                    sqlParam = [this.tableName, this.ctx.service.changeAudit.tableName, this.ctx.session.sessionUser.accountId, status, tenderId];
-                    break;
-                case 3: // 已完成(所有的)
-                    sql = 'SELECT a.* FROM ?? AS a WHERE a.status = ? AND a.tid = ? ORDER BY a.in_time DESC';
-                    sqlParam = [this.tableName, status, tenderId];
-                    break;
-                default:
-                    break;
+            if (this.ctx.tender.isTourist && status === 0) {
+                sql = 'SELECT * FROM ?? WHERE tid = ? ORDER BY in_time DESC';
+                sqlParam = [this.tableName, tenderId];
+            } else {
+                switch (status) {
+                    case 0: // 包含你的所有变更令
+                        sql =
+                            'SELECT a.* FROM ?? AS a WHERE a.tid = ? AND ' +
+                            '(a.uid = ? OR (a.status != ? AND a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid)) OR a.status = ? ) ORDER BY a.in_time DESC';
+                        sqlParam = [
+                            this.tableName,
+                            tenderId,
+                            this.ctx.session.sessionUser.accountId,
+                            audit.flow.status.uncheck,
+                            this.ctx.service.changeAudit.tableName,
+                            this.ctx.session.sessionUser.accountId,
+                            audit.flow.status.checked,
+                        ];
+                        break;
+                    case 1: // 待处理(你的)
+                        sql = 'SELECT a.* FROM ?? as a WHERE cid in(SELECT b.cid FROM ?? as b WHERE tid = ? AND uid = ? AND status = ?) ORDER BY in_time DESC';
+                        sqlParam = [this.tableName, this.ctx.service.changeAudit.tableName, tenderId, this.ctx.session.sessionUser.accountId, audit.flow.auditStatus.checking];
+                        break;
+                    case 5: // 待上报(所有的)PS:取未上报和退回的变更令
+                        sql =
+                            'SELECT a.* FROM ?? AS a WHERE ' +
+                            'a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? GROUP BY b.cid) AND ' +
+                            '(a.status = ? OR a.status = ?) AND a.tid = ? ORDER BY a.in_time DESC';
+                        sqlParam = [
+                            this.tableName,
+                            this.ctx.service.changeAudit.tableName,
+                            this.ctx.session.sessionUser.accountId,
+                            audit.flow.status.uncheck,
+                            audit.flow.status.back,
+                            tenderId,
+                        ];
+                        break;
+                    case 2: // 进行中(所有的)
+                    case 4: // 终止(所有的)
+                        sql =
+                            'SELECT a.* FROM ?? AS a WHERE ' +
+                            'a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid) AND ' +
+                            'a.status = ? AND a.tid = ? ORDER BY a.in_time DESC';
+                        sqlParam = [this.tableName, this.ctx.service.changeAudit.tableName, this.ctx.session.sessionUser.accountId, status, tenderId];
+                        break;
+                    case 3: // 已完成(所有的)
+                        sql = 'SELECT a.* FROM ?? AS a WHERE a.status = ? AND a.tid = ? ORDER BY a.in_time DESC';
+                        sqlParam = [this.tableName, status, tenderId];
+                        break;
+                    default:
+                        break;
+                }
             }
             if (hadlimit) {
                 const limit = this.app.config.pageSize;
@@ -295,6 +300,12 @@ module.exports = app => {
          * @return {void}
          */
         async getCountByStatus(tenderId, status) {
+            if (this.ctx.tender.isTourist && status === 0) {
+                const sql5 = 'SELECT count(*) AS count FROM ?? WHERE tid = ? ORDER BY in_time DESC';
+                const sqlParam5 = [this.tableName, tenderId];
+                const result5 = await this.db.query(sql5, sqlParam5);
+                return result5[0].count;
+            }
             switch (status) {
                 case 0: // 包含你的所有变更令
                     const sql =
@@ -1114,37 +1125,29 @@ module.exports = app => {
                 }
             }
             const sql =
-                'SELECT C.*, Sum(U.utp) As used_tp, Round(Sum(U.utp) / C.total_price * 100, 2) As used_pt' +
-                '  FROM ' +
-                this.tableName +
-                ' As C' +
-                '  LEFT JOIN (SELECT sc.tid, sc.cid, sc.cbid, Round(SUM(sc.qty) * cb.unit_price, ?) As utp' +
-                '    FROM ' +
-                this.ctx.service.stageChange.tableName +
-                ' As sc' +
+                'SELECT C.*, Sum(U.utp) As used_tp, TRUNCATE(Sum(U.utp) / C.total_price * 100 + 0.005, 2) As used_pt' +
+                '  FROM ' + this.tableName + ' As C' +
+                '  LEFT JOIN (SELECT sc.tid, sc.cid, sc.cbid, IF(SUM(sc.qty) > 0, TRUNCATE(SUM(sc.qty) * cb.unit_price + ?, 0), TRUNCATE(SUM(sc.qty) * cb.unit_price - ?, ?)) As utp' +
+                '    FROM ' + this.ctx.service.stageChange.tableName + ' As sc' +
                 '    INNER JOIN (' +
                 '      SELECT MAX(`stimes`) As `stimes`, MAX(`sorder`) As `sorder`, `lid`, `pid`, `cbid`, sChange.`sid` ' +
-                '        FROM ' +
-                this.ctx.service.stageChange.tableName +
-                ' As sChange ' +
-                '        LEFT JOIN ' +
-                this.ctx.service.stage.tableName +
-                ' As s' +
+                '        FROM ' + this.ctx.service.stageChange.tableName + ' As sChange ' +
+                '        LEFT JOIN ' + this.ctx.service.stage.tableName + ' As s' +
                 '        ON sChange.sid = s.id' +
-                '        WHERE sChange.tid = ?' +
-                filter +
+                '        WHERE sChange.tid = ?' + filter +
                 '        GROUP By `lid`, `pid`, `cbid`, `sid`' +
                 '    ) As m' +
                 '    ON sc.stimes = m.stimes And sc.sorder = m.sorder And sc.`cbid` = m.`cbid` AND sc.`sid` = m.`sid` And sc.`lid` = m.`lid` And sc.`pid` = m.`pid`' +
-                '    LEFT JOIN ' +
-                this.ctx.service.changeAuditList.tableName +
+                '    LEFT JOIN ' + this.ctx.service.changeAuditList.tableName +
                 ' As cb ON sc.cbid = cb.id' +
                 '    GROUP By sc.`cbid`' +
                 '  ) As U ON C.cid = U.cid' +
                 '  WHERE C.tid = ? And C.status = ? And C.valid' +
                 '  GROUP By C.cid' +
                 '  ORDER By in_time';
-            const sqlParam = [this.ctx.tender.info.decimal.tp, tid, tid, audit.flow.status.checked];
+            // 舍入步长
+            const step = parseFloat('0.' + '0000000'.substr(0, this.ctx.tender.info.decimal.tp) + '5');
+            const sqlParam = [step, step, this.ctx.tender.info.decimal.tp, tid, tid, audit.flow.status.checked];
             return await this.db.query(sql, sqlParam);
         }
 

+ 7 - 3
app/service/change_audit.js

@@ -105,7 +105,7 @@ module.exports = app => {
             const auditStatusConst = auditConst.auditStatus;
             const uid = this.ctx.session.sessionUser.accountId;
             const changeAuditInfo = await this.getAllDataByCondition({ where: { cid: change.cid, times: change.times, uid }, orders: [['id', 'desc']], limit: 1, offset: 0 });
-            if (!change.status === statusConst.checked && (changeAuditInfo === null || changeAuditInfo[0] === undefined)) {
+            if (!change.status === statusConst.checked && (changeAuditInfo === null || changeAuditInfo[0] === undefined) && !ctx.tender.isTourist) {
                 // 无权限查看此变更令
                 return 0;
             }
@@ -125,12 +125,15 @@ module.exports = app => {
             } else if (change.status === statusConst.checkNo) {
                 // 已终止
                 return 5;
-            } else if ((change.status === statusConst.checking || change.status === statusConst.backnew) && changeAuditInfo[0].status === auditStatusConst.checking) {
+            } else if ((change.status === statusConst.checking || change.status === statusConst.backnew) && changeAuditInfo.length > 0 && changeAuditInfo[0].status === auditStatusConst.checking) {
                 // 待你审批
                 return 6;
-            } else if ((change.status === statusConst.checking || change.status === statusConst.backnew) && changeAuditInfo[0].status !== auditStatusConst.checking) {
+            } else if ((change.status === statusConst.checking || change.status === statusConst.backnew) && changeAuditInfo.length > 0 && changeAuditInfo[0].status !== auditStatusConst.checking) {
                 // 审批中但你未到你审批或你已审批
                 return 7;
+            } else if (this.ctx.tender.isTourist) {
+                // 游客模式,只预览不能操作
+                return 8;
             }
             // 无权限查看此变更令
             return 0;
@@ -157,6 +160,7 @@ module.exports = app => {
                 case 4:// 已完成
                 case 5:// 已终止
                 case 7:// 审批中但你未到你审批或你已审批
+                case 8:// 游客
                     // 获取完整的审批顺序
                     sql = 'SELECT * FROM ?? WHERE ' +
                         'cid = ? ORDER BY usort';

+ 50 - 1
app/service/change_audit_list.js

@@ -71,6 +71,55 @@ module.exports = app => {
         }
 
         /**
+         * 批量添加空白变更清单
+         * @return {void}
+         */
+        async batchAdd(data) {
+            if (!this.ctx.tender || !this.ctx.change) {
+                throw '数据错误';
+            }
+            const num = data.num ? parseInt(data.num) : 0;
+            if (num < 1 || num > 100) {
+                throw '批量添加的空白清单数目不能小于1或大于100';
+            }
+            const insertArray = [];
+            for (let i = 0; i < num; i++) {
+                const insertData = {
+                    tid: this.ctx.tender.id,
+                    cid: this.ctx.change.cid,
+                    lid: '0',
+                    code: '',
+                    name: '',
+                    bwmx: '',
+                    unit: '',
+                    unit_price: null,
+                    oamount: 0,
+                    camount: 0,
+                    samount: '',
+                    detail: '',
+                    spamount: 0,
+                    xmj_code: null,
+                    xmj_jldy: null,
+                    xmj_dwgc: null,
+                    xmj_fbgc: null,
+                    xmj_fxgc: null,
+                    gcl_id: '',
+                };
+                insertArray.push(insertData);
+            }
+            // 新增工料
+            const result = await this.db.insert(this.tableName, insertArray);
+            if (result.affectedRows !== num) {
+                throw '批量添加空白清单数据失败';
+            }
+            // 获取刚批量添加的所有list
+            for (let j = 0; j < num; j++) {
+                insertArray[j].id = result.insertId + j;
+            }
+            return insertArray;
+        }
+
+        /**
          * 删除变更清单
          * @param {int} id 清单id
          * @return {void}
@@ -84,7 +133,7 @@ module.exports = app => {
                 // 判断是否可删
                 await transaction.delete(this.tableName, { id });
                 // 重新算变更令总额
-                // await this.calcQuantityByML(transaction, mb_id);
+                await this.calcCamountSum(transaction);
                 await transaction.commit();
                 return true;
             } catch (err) {

+ 1 - 1
app/service/customer.js

@@ -121,7 +121,7 @@ module.exports = app => {
         async boot(postData) {
             const sessionUser = this.ctx.session.sessionUser;
 
-            delete postData._csrf;
+            delete postData._csrf_j;
             const result = await this.update(postData, { email: sessionUser.account });
 
             return result;

+ 1 - 1
app/service/material.js

@@ -80,7 +80,7 @@ module.exports = app => {
             });
             if (materials.length !== 0) {
                 const lastMaterial = materials[materials.length - 1];
-                if (lastMaterial.status === auditConst.status.uncheck && lastMaterial.user_id !== this.ctx.session.sessionUser.accountId) {
+                if (lastMaterial.status === auditConst.status.uncheck && lastMaterial.user_id !== this.ctx.session.sessionUser.accountId && !this.ctx.tender.isTourist) {
                     materials.splice(materials.length - 1, 1);
                 }
             }

+ 2 - 2
app/service/message.js

@@ -96,8 +96,8 @@ module.exports = app => {
          * @return {Boolean} - 返回修改结果
          */
         async save(id, data, user, projectId) {
-            if (data._csrf !== undefined) {
-                delete data._csrf;
+            if (data._csrf_j !== undefined) {
+                delete data._csrf_j;
             }
             if (id > 0) {
                 // 修改操作时

+ 30 - 0
app/service/project.js

@@ -7,6 +7,11 @@
  * @date 2017/11/16
  * @version
  */
+const imType = require('../const/tender').imType;
+const defaultFunRela = {
+    banOver: false,
+    imType: imType.zl.value,
+};
 
 module.exports = app => {
 
@@ -43,6 +48,12 @@ module.exports = app => {
                         name: { type: 'string', required: true, min: 2 },
                     };
                     break;
+                case 'fun':
+                    rule = {
+                        imType: {type: 'enum', values: [imType.tz.value, imType.zl.value, imType.bb.value, imType.bw.value], required: true},
+                        banOver: {type: 'bool', required: true,}
+                    };
+                    break;
                 default:
                     break;
             }
@@ -135,6 +146,25 @@ module.exports = app => {
             return projectData.page_show ? JSON.parse(projectData.page_show) : null;
         }
 
+        /**
+         * 功能设置
+         * @param id
+         * @returns {Promise<null>}
+         */
+        async getFunRela(id) {
+            const projectData = await this.db.get(this.tableName, { id });
+            const result = projectData.fun_rela ? JSON.parse(projectData.fun_rela) : {};
+            this.ctx.helper._.defaults(result, defaultFunRela);
+            return result;
+        }
+
+        async updateFunRela(id, data) {
+            const result = await this.db.update(this.tableName, {
+                id: id, fun_rela: JSON.stringify({banOver: data.banOver, imType: data.imType}),
+            });
+            return result.affectedRows === 1;
+        }
+
     }
 
     return Project;

+ 8 - 14
app/service/project_account.js

@@ -384,8 +384,8 @@ module.exports = app => {
          * @return {Boolean} - 返回修改结果
          */
         async save(data) {
-            if (data._csrf !== undefined) {
-                delete data._csrf;
+            if (data._csrf_j !== undefined) {
+                delete data._csrf_j;
             }
             const id = data.id !== undefined ? parseInt(data.id) : 0;
             if (id > 0) {
@@ -425,8 +425,8 @@ module.exports = app => {
          * @return {Boolean} - 返回修改结果
          */
         async saveInfo(data, id) {
-            if (data._csrf !== undefined) {
-                delete data._csrf;
+            if (data._csrf_j !== undefined) {
+                delete data._csrf_j;
             }
             data.id = parseInt(id);
             const operate = await this.db.update(this.tableName, data);
@@ -620,8 +620,8 @@ module.exports = app => {
          * @return {Boolean} - 返回权限修改结果
          */
         async permissionSave(id, data) {
-            if (data._csrf !== undefined) {
-                delete data._csrf;
+            if (data._csrf_j !== undefined) {
+                delete data._csrf_j;
             }
             const updateData = {
                 id,
@@ -650,8 +650,8 @@ module.exports = app => {
          * @return {Boolean} - 返回修改结果
          */
         async noticeTypeSet(id, data) {
-            if (data._csrf !== undefined) {
-                delete data._csrf;
+            if (data._csrf_j !== undefined) {
+                delete data._csrf_j;
             }
             const type = parseInt(data.type) === 1 ? 1 : 0; // 对应微信通知和短信通知设置
             delete data.type;
@@ -790,12 +790,6 @@ module.exports = app => {
 
             return result;
         }
-
-        async getUnionIdList() {
-            const sql = 'SELECT * FROM ?? WHERE wx_openid != ? and wx_unionid = ?';
-            const sqlParam = [this.tableName, null, null];
-            return await this.db.query(sql, sqlParam);
-        }
     }
 
     return ProjectAccount;

+ 30 - 6
app/service/report.js

@@ -158,6 +158,18 @@ module.exports = app => {
                             runnableRst.push(service.reportMemory.getMaterialGl(params.tender_id, params.material_order, memFieldKeys[filter]));
                             runnableKey.push(filter);
                             break;
+                        case 'mem_material_gl_detail':
+                            runnableRst.push(service.reportMemory.getMaterialGlDetail(params.tender_id, params.material_order, memFieldKeys[filter]));
+                            runnableKey.push(filter);
+                            break;
+                        case 'mem_material_bills':
+                            runnableRst.push(service.reportMemory.getMaterialBills(params.tender_id, params.material_order, memFieldKeys[filter]));
+                            runnableKey.push(filter);
+                            break;
+                        case 'mem_material_pos':
+                            runnableRst.push(service.reportMemory.getMaterialPos(params.tender_id, params.material_order, memFieldKeys[filter]));
+                            runnableKey.push(filter);
+                            break;
                         case 'mem_stage_sum_bills':
                             runnableRst.push(service.rptStageSumMemory.getStageSumBills(params.tender_id, memFieldKeys[filter],
                                 customDefine.stage_select, customSelect ? customSelect.stage_select : null));
@@ -180,6 +192,18 @@ module.exports = app => {
                             runnableRst.push(service.stageChangeFinal.getFinalData(params.tender_id));
                             runnableKey.push(filter);
                             break;
+                        case 'mem_ledger_tag':
+                            runnableRst.push(service.ledgerTag.getDatas(params.tender_id));
+                            runnableKey.push(filter);
+                            break;
+                        case 'mem_stage_tag':
+                            runnableRst.push(service.ledgerTag.getDatas(params.tender_id, params.stage_id));
+                            runnableKey.push(filter);
+                            break;
+                        case 'mem_all_tag':
+                            runnableRst.push(service.ledgerTag.getAllDataByCondition({ where: { tid: params.tender_id } }));
+                            runnableKey.push(filter);
+                            break;
                         default:
                             break;
                     }
@@ -206,12 +230,12 @@ module.exports = app => {
                     case 'mem_change_bills':
                         rst[filter] = await service.reportMemory.getChangeBillsData(params.tender_id, params.stage_id, memFieldKeys[filter]);
                         break;
-                    case 'mem_material_bills':
-                        rst[filter] = await service.rptGatherMemory.getMaterialBills(params.tender_id, params.material_order, memFieldKeys[filter]);
-                        break;
-                    case 'mem_material_bills_gl':
-                        rst[filter] = await service.rptGatherMemory.getMaterialBillsGl(params.tender_id, params.material_order, memFieldKeys[filter]);
-                        break;
+                    // case 'mem_material_bills':
+                    //     rst[filter] = await service.rptGatherMemory.getMaterialBills(params.tender_id, params.material_order, memFieldKeys[filter]);
+                    //     break;
+                    // case 'mem_material_bills_gl':
+                    //     rst[filter] = await service.rptGatherMemory.getMaterialBillsGl(params.tender_id, params.material_order, memFieldKeys[filter]);
+                    //     break;
                     default:
                         break;
                 }

+ 58 - 2
app/service/report_memory.js

@@ -882,7 +882,7 @@ module.exports = app => {
             }
         }
 
-        async getMaterial(tender_id, material_order, memFieldKeys) {
+        async getMaterial(tender_id, material_order, fields) {
             return await this.ctx.service.material.getValidMaterials(tender_id);
         }
 
@@ -902,7 +902,7 @@ module.exports = app => {
             }
         }
 
-        async getMaterialGl(tender_id, material_order, memFieldKeys) {
+        async getMaterialGl(tender_id, material_order, fields) {
             const materials = await this.ctx.service.material.getAllDataByCondition({
                 where: {tid: tender_id},
                 orders: [['order', 'desc']],
@@ -933,6 +933,62 @@ module.exports = app => {
             }
         }
 
+        async getMaterialGlDetail(tender_id, material_order, fields) {
+            const material = await this.ctx.service.material.getDataByCondition({tid: tender_id, order: material_order});
+            return material ? await this.ctx.service.materialList.getMaterialData(tender_id, material.id) : [];
+        }
+
+        async getMaterialBills(tender_id, material_order, fields) {
+            const material = await this.ctx.service.material.getDataByCondition({tid: tender_id, order: material_order});
+            try {
+                const billsData = await this.ctx.service.ledger.getData(tender_id);
+                if (this._checkFieldsExist(fields, billsFields.stage)) {
+                    const curStage = await this.ctx.service.stageBills.getStagesData(tender_id, material.stage_id);
+                    this.ctx.helper.assignRelaData(billsData, [
+                        {data: curStage, fields: ['contract_qty', 'contract_tp', 'contract_expr', 'qc_qty', 'qc_tp', 'postil'], prefix: '', relaId: 'lid'}
+                    ]);
+                }
+
+                const billsTree = this._getNewBillsTree();
+                billsTree.loadDatas(billsData);
+                billsTree.calculateAll();
+
+                return billsTree.getDatas([
+                    'id', 'tender_id', 'ledger_id', 'ledger_pid', 'level', 'order', 'full_path', 'is_leaf',
+                    'code', 'b_code', 'name', 'unit', 'unit_price',
+                    'deal_qty', 'deal_tp',
+                    'sgfh_qty', 'sgfh_tp', 'sjcl_qty', 'sjcl_tp', 'qtcl_qty', 'qtcl_tp', 'quantity', 'total_price',
+                    'dgn_qty1', 'dgn_qty2',
+                    'drawing_code', 'memo', 'node_type', 'is_tp',
+                    'contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'gather_qty', 'gather_tp', 'postil',
+                    'sgfh_expr', 'sjcl_expr', 'qtcl_expr', 'contract_expr',
+                ]);
+            } catch(err) {
+                this.ctx.helper.log(err);
+                return [];
+            }
+        }
+
+        async getMaterialPos(tender_id, material_order, fields) {
+            const material = await this.ctx.service.material.getDataByCondition({tid: tender_id, order: material_order});
+            try {
+                const posData = await this.ctx.service.pos.getAllDataByCondition({ where: {tid: tender_id }});
+                if (this._checkFieldsExist(fields, posFields.stage)) {
+                    const curPosStage = await this.ctx.service.stagePos.getStagesData(tender_id, material.stage_id);
+                    this.ctx.helper.assignRelaData(posData, [
+                        {data: curPosStage, fields: ['contract_qty', 'qc_qty', 'contract_expr', 'postil'], prefix: '', relaId: 'pid'}
+                    ]);
+                }
+                this.pos.loadDatas(posData);
+                this.pos.calculateAll();
+
+                return this.pos.getDatas();
+            } catch (err) {
+                this.ctx.helper.log(err);
+                return [];
+            }
+        }
+
         async getSumStageBillsData(tid, sid, fields) {
             try {
                 await this.ctx.service.tender.checkTender(tid);

+ 14 - 1
app/service/stage.js

@@ -90,6 +90,16 @@ module.exports = app => {
                 } else {
                     stage.curOrder = stage.curAuditor.aid === accountId ? stage.curAuditor.order : stage.curAuditor.order - 1;
                 }
+            } else if (this.ctx.tender.isTourist) { // 游客
+                stage.readOnly = true;
+                stage.curTimes = stage.times;
+                if (stage.status === status.uncheck || stage.status === status.checkNo) {
+                    stage.curOrder = 0;
+                } else if (stage.status === status.checked) {
+                    stage.curOrder = this._.max(this._.map(stage.auditors, 'order'));
+                } else {
+                    stage.curOrder = stage.curAuditor.order;
+                }
             } else if (auditorIds.indexOf(accountId) !== -1) { // 审批人
                 if (stage.status === status.uncheck) {
                     throw '您无权查看该数据';
@@ -257,7 +267,7 @@ module.exports = app => {
             }
             if (stages.length !== 0) {
                 const lastStage = stages[0];
-                if (lastStage.status === auditConst.status.uncheck && lastStage.user_id !== this.ctx.session.sessionUser.accountId) {
+                if (lastStage.status === auditConst.status.uncheck && lastStage.user_id !== this.ctx.session.sessionUser.accountId && !this.ctx.tender.isTourist) {
                     stages.splice(0, 1);
                 }
             }
@@ -355,6 +365,9 @@ module.exports = app => {
                     const sumTp = await this._getSumTp({tid: preStage.tid}, 'sf_tp');
                     newStage.pre_sf_tp = sumTp.sf_tp || 0;
                 }
+            } else {
+                const projFunRela = await this.ctx.service.project.getFunRela(this.ctx.session.sessionProject.id);
+                newStage.im_type = projFunRela.imType;
             }
             const transaction = await this.db.beginTransaction();
             try {

+ 3 - 2
app/service/stage_audit.js

@@ -1234,6 +1234,7 @@ module.exports = app => {
                 const yfPay = stagePay.find(function(x) {
                     return x.ptype === payConst.payType.yf;
                 });
+                console.log(stagePay);
                 const sfPay = stagePay.find(function(x) {
                     return x.ptype === payConst.payType.sf;
                 });
@@ -1245,8 +1246,8 @@ module.exports = app => {
                     contract_tp: tpData.contract_tp,
                     qc_tp: tpData.qc_tp,
                     times: nowTimes,
-                    yf_tp: yfPay.tp,
-                    sf_tp: sfPay.tp,
+                    yf_tp: yfPay ? yfPay.tp : null,
+                    sf_tp: sfPay ? sfPay.tp : null,
                     tp_history: JSON.stringify(this.ctx.stage.tp_history),
                     cache_time_l: time,
                     cache_time_r: time,

+ 5 - 4
app/service/stage_bills_final.js

@@ -94,10 +94,12 @@ module.exports = app => {
                         c.contract_tp = this.ctx.helper.add(c.contract_tp, p.contract_tp);
                         c.qc_qty = this.ctx.helper.add(c.qc_qty, p.qc_qty);
                         c.qc_tp = this.ctx.helper.add(c.qc_tp, p.qc_tp);
-                        c.used = p.used || !this.ctx.helper.checkZero(c.contract_qty) || !this.ctx.helper.checkZero(c.qc_qty);
+                        c.used = p.used || !this.ctx.helper.checkZero(c.contract_qty) || !this.ctx.helper.checkZero(c.qc_qty)
+                            || !this.ctx.helper.checkZero(c.contract_tp) || !this.ctx.helper.checkZero(c.qc_tp);
                         pre.splice(pre.indexOf(p), 1);
                     } else {
-                        c.used = !this.ctx.helper.checkZero(c.contract_qty) || !this.ctx.helper.checkZero(c.qc_qty);
+                        c.used = !this.ctx.helper.checkZero(c.contract_qty) || !this.ctx.helper.checkZero(c.qc_qty)
+                            || !this.ctx.helper.checkZero(c.contract_tp) || !this.ctx.helper.checkZero(c.qc_tp);
                     }
                 }
 
@@ -105,13 +107,12 @@ module.exports = app => {
                     if (p.id !== undefined) delete p.id;
                     p.sid = stage.id;
                     p.sorder = stage.order;
-                    p.used = p.used || !this.ctx.helper.checkZero(p.contract_qty) || !this.ctx.helper.checkZero(p.qc_qty);
                 }
                 await transaction.insert(this.tableName, cur ? cur.concat(pre) : pre);
             } else {
                 const sql = 'Insert Into ??(tid, sid, lid, sorder, contract_qty, contract_tp, qc_qty, qc_tp, used)' +
                     '  SELECT b.tid, b.sid, b.lid, ? As `sorder`, b.contract_qty, b.contract_tp, b.qc_qty, b.qc_tp,' +
-                    '    IFNULL((b.contract_qty <> 0 or b.contract_tp <> 0 or b.qc_qty <> 0 or b.qc_tp <> 0), 0) As used' +
+                    '    IF(IFNULL(b.contract_qty, 0) <> 0 or IFNULL(b.contract_tp, 0) <> 0 or IFNULL(b.qc_qty, 0) <> 0 or IFNULL(b.qc_tp, 0) <> 0, 1, 0) As used' +
                     '  FROM ' + this.ctx.service.stageBills.tableName + ' AS b' +
                     '  INNER JOIN(' +
                     '    SELECT Max(`times` * ' + timesLen + ' + `order`) As `flow`, `lid` FROM ' + this.ctx.service.stageBills.tableName +

+ 1 - 1
app/service/stage_jgcl.js

@@ -226,7 +226,7 @@ module.exports = app => {
                 throw '标段数据有误';
             }
             const preDatas = await this.getAllDataByCondition({
-                columns: ['uuid', 'name', 'unit', 'unit_price', 'source', 'bills_code', 'check_code', 'memo', 'add_uid', 'add_sid', 'order', 'arrive_qty', 'deduct_qty'],
+                columns: ['uuid', 'name', 'unit', 'unit_price', 'source', 'bills_code', 'check_code', 'memo', 'add_uid', 'add_sid', 'tid', 'order', 'arrive_qty', 'deduct_qty', 'pre_used'],
                 where: { sid: preStage.id },
             });
             if (preDatas.length > 0) {

+ 1 - 1
app/service/stage_pos_final.js

@@ -101,7 +101,7 @@ module.exports = app => {
             } else {
                 const sql = 'Insert Into ??(tid, sid, lid, pid, sorder, contract_qty, qc_qty, used)' +
                             '  SELECT p.tid, p.sid, p.lid, p.pid, ? As `sorder`, p.contract_qty, p.qc_qty,' +
-                            '    IFNULL((p.contract_qty <> 0 or p.qc_qty <> 0), 0) As used' +
+                            '    IF(IFNULL(p.contract_qty, 0) <> 0 or IFNULL(p.qc_qty, 0) <> 0, 1, 0) As used' +
                             '  FROM ' + this.ctx.service.stagePos.tableName + ' AS p' +
                             '  INNER JOIN(' +
                             '    SELECT Max(`times` * ' + timesLen +' + `order`) As `flow`, `pid` FROM ' + this.ctx.service.stagePos.tableName +

+ 3 - 0
app/service/tender.js

@@ -135,6 +135,8 @@ module.exports = app => {
                     '        t.id IN ( SELECT ma.`tid` FROM ?? AS ma WHERE ma.`aid` = ? GROUP BY ma.`tid`))' +
                     // 参与审批 预付款 的标段
                     '    OR (t.id IN ( SELECT ad.`tid` FROM ?? AS ad WHERE ad.`audit_id` = ? GROUP BY ad.`tid`))' +
+                    // 游客权限的标段
+                    '    OR (t.id IN ( SELECT tt.`tid` FROM ?? AS tt WHERE tt.`user_id` = ?))' +
                     // 未参与,但可见的标段
                     ') ORDER BY CONVERT(t.`name` USING GBK) ASC';
                 sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, session.sessionProject.id, session.sessionUser.accountId,
@@ -144,6 +146,7 @@ module.exports = app => {
                     this.ctx.service.reviseAudit.tableName, session.sessionUser.accountId,
                     this.ctx.service.materialAudit.tableName, session.sessionUser.accountId,
                     this.ctx.service.advanceAudit.tableName, session.sessionUser.accountId,
+                    this.ctx.service.tenderTourist.tableName, session.sessionUser.accountId,
                 ];
             }
             const list = await this.db.query(sql, sqlParam);

+ 66 - 0
app/service/tender_tourist.js

@@ -0,0 +1,66 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Ellisran
+ * @date 2021/4/8
+ * @version
+ */
+
+module.exports = app => {
+
+    class TenderTourist extends app.BaseService {
+
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'tender_tourist';
+        }
+
+        async getTourists(tid) {
+            const sql = 'SELECT tt.*,' +
+                'pa.`name` As `user_name`, pa.`role` As `user_role`, pa.`company` As `user_company` ' +
+                'FROM ?? As tt LEFT JOIN ?? As pa ON tt.`user_id` = pa.`id` ' +
+                'WHERE tt.`tid` = ?';
+            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, tid];
+            return await this.db.query(sql, sqlParam);
+        }
+
+        async addAudit(data) {
+            const transaction = await this.db.beginTransaction();
+            try {
+                const insertData = {
+                    tid: this.ctx.tender.id,
+                    user_id: data.user_id,
+                    in_time: new Date(),
+                };
+                const result = await transaction.insert(this.tableName, insertData);
+                await transaction.commit();
+                return await this.getDataById(result.insertId);
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+
+        async removeAudit(data) {
+            const transaction = await this.db.beginTransaction();
+            try {
+                await transaction.delete(this.tableName, { id: data.id });
+                await transaction.commit();
+                return true;
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+        }
+    }
+
+    return TenderTourist;
+};

+ 1 - 1
app/service/version.js

@@ -55,7 +55,7 @@ module.exports = app => {
         async save(data, id = 0) {
             id = parseInt(id);
             id = isNaN(id) ? 0 : id;
-            delete data._csrf;
+            delete data._csrf_j;
 
             if (id > 0) {
                 delete data.create_time;

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

@@ -144,7 +144,7 @@ $(document).ready(function() {
         }
 
         $.ajax({
-            url: '/project/account/permission/' + currentId + "?_csrf=<%= ctx.csrf %>",
+            url: '/project/account/permission/' + currentId + "?_csrf_j=<%= ctx.csrf %>",
             type: 'post',
             data: { permission: selectPermission.join(',') },
             error: function() {

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

@@ -31,7 +31,7 @@
             <div class="ml-auto">
                 <% if(showAddBtn) { %>
                     <form action="<%- preUrl %>" method="POST">
-                        <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                        <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                         <button type="submit" class="btn btn-primary btn-sm">开始新一期</button>
                     </form>
                     <!-- <a id="advance_add" href="" class="btn btn-primary btn-sm pull-right"></a> -->

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

@@ -400,7 +400,7 @@
                     </div>
                     <div class="modal-footer">
                         <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
-                        <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                        <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 btn-sm">确认通过</button>
                     </div>
@@ -635,7 +635,7 @@
                     </div>
                     <div class="modal-footer">
                         <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
-                        <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                        <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
                         <button type="submit" class="btn btn-warning btn-sm">确认退回</button>
                     </div>
                 </form>

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

@@ -76,7 +76,7 @@
                                 </div>
                             </div>
                             <div class="form-group">
-                                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>"/>
+                                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>"/>
                                 <button class="btn btn-primary btn-sm btn-block" type="submit">下一步</button>
                             </div>
                         </form>

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

@@ -48,7 +48,11 @@
                         <td><%- c.name %></td>
                         <td><%- classArray[c.class] %><% c.class %></td>
                         <td style="text-align: right"><%= ctx.helper.roundNum(c.total_price, tpUnit) %></td>
-                        <% if (c.auditStatus) { %>
+                        <% if (c.status === auditConst.status.uncheck && ctx.tender.isTourist) { %>
+                            <td>
+                                上报中
+                            </td>
+                        <% } else if (c.auditStatus) { %>
                         <td>
                             <a href="/tender/<%- tender.id %>/change/<%- c.cid %>/information" class="btn <%- auditConst.statusButtonClass[c.status] %> btn-sm">
                                 <%- auditConst.statusButton[c.status] %>
@@ -69,7 +73,7 @@
                             <span class="<%- auditConst.auditStatusClass[c.changeAudit.status] %>"><%- auditConst.auditStatusString[c.changeAudit.status] %></span>
                         </td>
                         <% } %>
-                        <td><% if (c.status === auditConst.status.uncheck || (c.status === auditConst.status.back && c.uid === uid)) { %><a href="#del-bg" cid="<%= c.cid %>" data-toggle="modal" data-target="#del-bg" class="btn btn-outline-danger btn-sm delete-cid-modal">删除</a><% } %></td>
+                        <td><% if ((c.status === auditConst.status.uncheck || (c.status === auditConst.status.back && c.uid === uid)) && !ctx.tender.isTourist) { %><a href="#del-bg" cid="<%= c.cid %>" data-toggle="modal" data-target="#del-bg" class="btn btn-outline-danger btn-sm delete-cid-modal">删除</a><% } %></td>
                     </tr>
                     <% } %>
                     </tbody>

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

@@ -188,7 +188,7 @@
             <div class="sjs-height-0 container-fluid">
             <!--变更信息-->
             <% if (auditStatus === 1 || auditStatus === 2) { %>
-            <form action="/tender/<%- change.tid %>/change/save?_csrf=<%= ctx.csrf %>" method="post" id="change_form">
+            <form action="/tender/<%- change.tid %>/change/save?_csrf_j=<%= ctx.csrf %>" method="post" id="change_form">
                 <div class="row">
                     <div class="col-md-4">
                         <div class="form-group">

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

@@ -430,7 +430,7 @@
     <!--审批通过-->
     <div class="modal fade sp-location-list" id="sp-done" data-backdrop="static">
         <div class="modal-dialog modal-lg" role="document">
-            <form class="modal-content" action="/tender/<%- tender.id %>/change/approval?_csrf=<%= ctx.csrf %>" method="post" id="success-approval">
+            <form class="modal-content" action="/tender/<%- tender.id %>/change/approval?_csrf_j=<%= ctx.csrf %>" method="post" id="success-approval">
                 <div class="modal-header">
                     <h5 class="modal-title">审批通过</h5>
                 </div>
@@ -666,7 +666,7 @@
     <!--审批退回-->
     <div class="modal fade sp-location-list" id="sp-back" data-backdrop="static">
         <div class="modal-dialog modal-lg" role="document">
-            <form class="modal-content" action="/tender/<%- tender.id %>/change/approval?_csrf=<%= ctx.csrf %>" method="post" id="fail-approval">
+            <form class="modal-content" action="/tender/<%- tender.id %>/change/approval?_csrf_j=<%= ctx.csrf %>" method="post" id="fail-approval">
                 <div class="modal-header">
                     <h5 class="modal-title">审批退回</h5>
                 </div>
@@ -974,7 +974,7 @@
             </div>
             <div class="modal-footer">
                 <input type="hidden" name="cid" value="<%= change.cid %>">
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
                 <button type="button" id="re-shenpi-btn" class="btn btn-warning btn-sm" <% if (ctx.session.sessionUser.loginStatus === 0) { %>disabled<% } %>>确定重审</button>
             </div>
@@ -1089,7 +1089,7 @@
         data.code = code;
         <% } %>
         $.ajax({
-            url: '/tender/<%- tender.id %>/change/check/again?_csrf=' + csrf,
+            url: '/tender/<%- tender.id %>/change/check/again?_csrf_j=' + csrf,
             type: 'post',
             data: data,
             dataTye: 'json',

+ 11 - 3
app/view/change/information.ejs

@@ -23,7 +23,7 @@
                         <label class="custom-control-label" for="customCheck1">变更详情</label>
                     </div>
                 </div>
-                <% if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7) { %>
+                <% if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7 || auditStatus === 8) { %>
                     <div class="d-inline-block ml-3">
                         <div class="custom-control custom-checkbox" style="line-height: normal;">
                             <input type="checkbox" class="custom-control-input" id="show-table-detail">
@@ -49,6 +49,12 @@
                     <a href="#sp-back" data-toggle="modal" data-target="#sp-back" class="btn btn-warning btn-sm">审批退回</a>
                 <% } else if (auditStatus === 7) { %>
                     <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-secondary btn-sm">审批中</a>
+                <% } else if (auditStatus === 8) { %>
+                    <% if (change.status === auditConst.status.uncheck) { %>
+                    <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-secondary btn-sm">上报中</a>
+                    <% } else if (change.status === auditConst.status.checking) { %>
+                    <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-secondary btn-sm">审批中</a>
+                    <% } %>
                 <% } %>
                 <% if (auditStatus === 4 && ctx.session.sessionUser.accountId === auditList[auditList.length-1].uid) { %>
                     <% if (stageChangeNum === 0) { %>
@@ -87,7 +93,9 @@
                             <!--所有附件 翻页-->
                             <a href="javascript: void(0);" data-toggle="modal" class="btn btn-sm btn-primary" id="bach-download"><i class="fa fa-download "></i> 批量下载</a>
                             <a href="javascript:void(0);" class="page-select ml-3" content="pre"><i class="fa fa-chevron-left"></i></a> <span id="currentPage">1</span>/<span id="totalPage">10</span> <a href="javascript:void(0);" class="page-select mr-3" content="next"><i class="fa fa-chevron-right"></i></a>
+                            <% if (auditStatus !== 8) { %>
                             <a href="#addfujian" data-toggle="modal" class="btn btn-sm btn-light text-primary" data-placement="bottom" title="" data-original-title="上传附件"><i class="fa fa-cloud-upload" aria-hidden="true"></i> 上传附件</a>
+                            <% } %>
                             <a href="" id="downloadZip" style="display: none;" download></a>
                         </li>
                     </ul>
@@ -96,7 +104,7 @@
                     <div class="tab-pane active" id="bgxinxi">
                         <div class="sjs-sh-1" style="overflow-y: auto;">
                             <% if (auditStatus === 1 || auditStatus === 2) { %>
-                            <form class="p-2" action="/tender/<%- change.tid %>/change/<%- change.cid %>/information/save?_csrf=<%= ctx.csrf %>" method="post" id="change_form">
+                            <form class="p-2" action="/tender/<%- change.tid %>/change/<%- change.cid %>/information/save?_csrf_j=<%= ctx.csrf %>" method="post" id="change_form">
                                 <div class="form-group">
                                     <label><b class="text-danger">*&nbsp;</b>申请编号</label>
                                     <a href="javascript:void(0);" class="pull-right reduction-code" data-toggle="tooltip" data-placement="bottom" title="" data-code="<%- change.code %>" data-original-title="重置"><i class="fa fa-repeat"></i></a>
@@ -430,7 +438,7 @@
 </script>
 <script src="/public/js/change_information_set.js"></script>
 <script src="/public/js/change_audit.js"></script>
-<% } else if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7) { %>
+<% } else if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7 || auditStatus === 8) { %>
 <script>
     const auditList2 = JSON.parse(unescape('<%- escape(JSON.stringify(auditList2)) %>'));
     const aidList = _.map(auditList2, 'uid');

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

@@ -93,7 +93,7 @@
             </div>
             <form class="modal-footer" method="post" action="<%- preUrl %>/audit/start" onsubmit="return checkChangeFrom()">
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                 <button type="submit" class="btn btn-primary btn-sm">确认上报</button>
             </form>
         </div>
@@ -280,7 +280,7 @@
                 </div>
                 <form class="modal-footer" method="post" action="<%- preUrl %>/audit/start" onsubmit="return checkChangeFrom()">
                     <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
-                    <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                    <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                     <button type="submit" class="btn btn-primary btn-sm">确认上报</button>
                 </form>
             </div>
@@ -289,7 +289,7 @@
 <% } %>
 <% } %>
 
-<% if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7) { %>
+<% if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7 || auditStatus === 8) { %>
 <!--审批流程/结果-->
 <div class="modal fade" id="sp-list" data-backdrop="static">
     <div class="modal-dialog modal-lg" role="document">
@@ -424,7 +424,7 @@
     <!--审批通过-->
     <div class="modal fade sp-location-list" id="sp-done" data-backdrop="static">
         <div class="modal-dialog modal-lg" role="document">
-            <form class="modal-content" action="/tender/<%- tender.id %>/change/approval?_csrf=<%= ctx.csrf %>" method="post" id="success-approval">
+            <form class="modal-content" action="/tender/<%- tender.id %>/change/approval?_csrf_j=<%= ctx.csrf %>" method="post" id="success-approval">
                 <div class="modal-header">
                     <h5 class="modal-title">审批通过</h5>
                 </div>
@@ -660,7 +660,7 @@
     <!--审批退回-->
     <div class="modal fade sp-location-list" id="sp-back" data-backdrop="static">
         <div class="modal-dialog modal-lg" role="document">
-            <form class="modal-content" action="/tender/<%- tender.id %>/change/approval?_csrf=<%= ctx.csrf %>" method="post" id="fail-approval">
+            <form class="modal-content" action="/tender/<%- tender.id %>/change/approval?_csrf_j=<%= ctx.csrf %>" method="post" id="fail-approval">
                 <div class="modal-header">
                     <h5 class="modal-title">审批退回</h5>
                 </div>
@@ -968,7 +968,7 @@
             </div>
             <div class="modal-footer">
                 <input type="hidden" name="cid" value="<%= change.cid %>">
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
                 <button type="button" id="re-shenpi-btn" class="btn btn-warning btn-sm" <% if (ctx.session.sessionUser.loginStatus === 0) { %>disabled<% } %>>确定重审</button>
             </div>
@@ -1084,7 +1084,7 @@
         data.code = code;
         <% } %>
         $.ajax({
-            url: '/tender/<%- tender.id %>/change/check/again?_csrf=' + csrf,
+            url: '/tender/<%- tender.id %>/change/check/again?_csrf_j=' + csrf,
             type: 'post',
             data: data,
             dataTye: 'json',

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

@@ -10,7 +10,7 @@
             </div>
             <form class="modal-footer" action="/tender/<%- tender.id %>/change/delete" method="post">
                 <input type="hidden" name="cid" id="delete-cid" value="">
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">取消</button>
                 <button type="submit" class="btn btn-danger btn-sm">确定删除</button>
             </form>

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

@@ -27,7 +27,7 @@
                     <div class="col-3 bd-toc">
                         <div class="card">
                             <div class="card-body">
-                                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                                 <% if (msgInfo.id === undefined) { %>
                                     <button type="submit" class="btn btn-primary">确认添加</button>
                                 <% } else { %>

+ 44 - 2
app/view/layout/page.ejs

@@ -5,7 +5,8 @@
     }
 </style>
 <nav aria-label="Page navigation example">
-    <ul class="pagination pagination-sm"></ul>
+    <ul class="pagination pagination-sm">
+    </ul>
 </nav>
 <script type="text/javascript" src="/public/js/bootstrap/bootstrap-paginator.js"></script>
 <script type="text/javascript">
@@ -98,9 +99,50 @@
             return  queryString === '' ? '?' + firstQuery : '?' + firstQuery + '&' + queryString;
         }
     };
-    if (options.totalPages > 1) {
+    const pageSizeSelect = <%- pageInfo.pageSizeSelect ? parseInt(pageInfo.pageSizeSelect) : 0 %>;
+    if (options.totalPages > 1 || pageSizeSelect) {
         $(".pagination").bootstrapPaginator(options);
+        setSelectPageSize(pageSizeSelect);
     } else {
         $(".pagination").hide();
     }
+
+    function setSelectPageSize(psSelect) {
+        if (psSelect === 1) {
+            let queryData = JSON.parse('<%- pageInfo.queryData %>');
+            // 有其它数据则重新赋值page,然后组合字符串
+            delete queryData.page;
+            delete queryData.pageSize;
+            let queryArray = [];
+            for(let tmp in queryData) {
+                let tempString = tmp + '=' + queryData[tmp];
+                queryArray.push(tempString);
+            }
+            let firstQuery = queryArray.shift();
+            let queryString = queryArray.join('&');
+            queryString = firstQuery ? (queryString === '' ? '?' + firstQuery : '?' + firstQuery + '&' + queryString) : '';
+
+            const pshtml = '<li class="page-item disabled">\n' +
+                '            <span class="page-link" >共' + <%- pageInfo.total_num %> + '条</span>\n' +
+                '            </li>\n' +
+                '            <li class="page-item">\n' +
+                '            <span class="page-link" >\n' +
+                '            <div class="btn-group">\n' +
+                '            <a type="button" class="text-primary dropdown-toggle" data-toggle="dropdown" id="zhankai" >每页' + <%- pageInfo.pageSize %> + '条</a>\n' +
+                '            <div class="dropdown-menu" id="zhankaiSelect" aria-labelledby="zhankai" style="">\n' +
+                '            <a class="dropdown-item" data-size="15" href="'+ (queryString === '' ? '?pageSize=15' : queryString + '&pageSize=15') +'">每页15条</a>\n' +
+                '            <a class="dropdown-item" data-size="30" href="'+ (queryString === '' ? '?pageSize=30' : queryString + '&pageSize=30') +'">每页30条</a>\n' +
+                '            <a class="dropdown-item" data-size="50" href="'+ (queryString === '' ? '?pageSize=50' : queryString + '&pageSize=50') +'">每页50条</a>\n' +
+                '            <a class="dropdown-item" data-size="100" href="'+ (queryString === '' ? '?pageSize=100' : queryString + '&pageSize=100') +'">每页100条</a>\n' +
+                '            </div>\n' +
+                '            </div>\n' +
+                '            </span>\n' +
+                '            </li>';
+            $('.pagination').prepend(pshtml);
+        }
+    }
+
+    $('#zhankaiSelect a').on('click', function () {
+        setLocalCache('account-pageSize', $(this).data('size'));
+    })
 </script>

+ 3 - 3
app/view/ledger/audit_modal.ejs

@@ -183,7 +183,7 @@
             </div>
             <div class="modal-footer">
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                <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 btn-sm">确认通过</button>
             </div>
@@ -378,7 +378,7 @@
             </div>
             <div class="modal-footer">
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
                 <input type="hidden" name="checkType" value="<%= auditConst.status.checkNo %>" />
                 <button type="submit" class="btn btn-warning btn-sm">确认退回</button>
             </div>
@@ -561,7 +561,7 @@
                 </div>
             </div>
             <form class="modal-footer" method="post" action="<%- preUrl %>/ledger/audit/start" onsubmit="return checkAuditorFrom()">
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
                 <% if(tender.ledger_status === auditConst.status.checkNo && ctx.session.sessionUser.accountId === tender.user_id) { %>
                     <button class="btn btn-primary btn-sm sp-list-item" type="submit">确认上报</button>

+ 2 - 2
app/view/ledger/explode_modal.ejs

@@ -151,7 +151,7 @@
             </div>
             <form class="modal-footer" method="post" action="<%- preUrl %>/ledger/audit/start" name="audit-start">
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                 <button class="btn btn-primary btn-sm" type="submit" >确认上报</button>
             </form>
         </div>
@@ -334,7 +334,7 @@
                 </div>
             </div>
             <form class="modal-footer" method="post" action="<%- preUrl %>/ledger/audit/start" name="audit-start">
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
                 <% if(tender.ledger_status === auditConst.status.checkNo && ctx.session.sessionUser.accountId === tender.user_id) { %>
                     <button class="btn btn-primary btn-sm sp-list-item" type="submit">确认上报</button>

+ 3 - 3
app/view/login/login.ejs

@@ -68,7 +68,7 @@
                     </div>
                     <div class="form-group">
                         <button class="btn btn-primary btn-block" type="submit">登录</button>
-                        <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                        <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
                         <input type="hidden" name="type" value="2" />
                     </div>
                     <div class="pt-1 d-flex justify-content-end">
@@ -143,13 +143,13 @@
     const csrf = '<%= ctx.csrf %>'
 </script>
 <script src="/public/js/login.js"></script>
-<script src="http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"></script>
+<script src="https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"></script>
 <script>
     $(function () {
         const obj = new WxLogin({
             self_redirect:false,
             id:"wx-code",
-            appid: "wx5320cd30cecdbd68",
+            appid: "<%- appid %>",
             scope: "snsapi_login",
             redirect_uri: "<%- hostUrl %>/wxAuth",
             state: getQueryString('referer'),

+ 1 - 1
app/view/login/login_port.ejs

@@ -44,7 +44,7 @@
                             <h5>单位:<span class="text-danger"><%- accountData.company %></span></h5>
                             <h5>职称:<span class="text-danger"><%- accountData.role %></span></h5>
                             <div class="form-group mt-4">
-                                <input type="hidden" value="<%= ctx.csrf %>" name="_csrf" >
+                                <input type="hidden" value="<%= ctx.csrf %>" name="_csrf_j" >
                                 <input type="hidden" value="3" name="type" >
                                 <input type="hidden" value="<%= projectData.code %>" name="code" >
                                 <input type="hidden" value="<%= accountData.id %>" name="accountId" >

+ 2 - 0
app/view/material/audit_btn.ejs

@@ -2,6 +2,8 @@
     <% if (ctx.material.status === auditConst.status.uncheck) { %>
         <% if (ctx.session.sessionUser.accountId === ctx.material.user_id) { %>
             <a id="sub-sp-btn" href="javascript: void(0);" data-toggle="modal" data-target="#sub-sp" class="btn btn-primary btn-sm btn-block">上报审批</a>
+        <% } else { %>
+            <a id="sub-sp-btn" href="javascript: void(0);" data-toggle="modal" data-target="#sub-sp" class="btn btn-outline-secondary btn-sm btn-block">上报中</a>
         <% } %>
     <% } else if (ctx.material.status === auditConst.status.checking) { %>
         <% if (ctx.material.curAuditor && ctx.material.curAuditor.aid === ctx.session.sessionUser.accountId) { %>

+ 10 - 8
app/view/material/audit_modal.ejs

@@ -1,4 +1,4 @@
-<% if ((ctx.material.status === auditConst.status.uncheck || ctx.material.status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === ctx.material.user_id) { %>
+<% if ((ctx.material.status === auditConst.status.uncheck || ctx.material.status === auditConst.status.checkNo) && (ctx.session.sessionUser.accountId === ctx.material.user_id || ctx.tender.isTourist)) { %>
 <!--上报审批-->
 <div class="modal fade" id="sub-sp" data-backdrop="static">
     <div class="modal-dialog" role="document">
@@ -8,7 +8,7 @@
             </div>
             <div class="modal-body">
                 <div class="dropdown text-right">
-                    <% if (ctx.tender.info.shenpi.material !== shenpiConst.sp_status.gdspl) { %>
+                    <% if (ctx.tender.info.shenpi.material !== shenpiConst.sp_status.gdspl && ctx.session.sessionUser.accountId === ctx.material.user_id) { %>
                     <button class="btn btn-outline-primary btn-sm dropdown-toggle" type="button"
                         id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true"
                         aria-expanded="false">
@@ -45,8 +45,8 @@
                     <ul class="list-group list-group-flush" id="auditors">
                         <% for (let i = 0, iLen = ctx.material.auditorList.length; i < iLen; i++) { %>
                         <li class="list-group-item" auditorId="<%- ctx.material.auditorList[i].aid %>">
-                            <% if (ctx.tender.info.shenpi.material === shenpiConst.sp_status.sqspr ||
-                                    (ctx.tender.info.shenpi.material === shenpiConst.sp_status.gdzs && i+1 !== iLen)) { %>
+                            <% if ((ctx.tender.info.shenpi.material === shenpiConst.sp_status.sqspr ||
+                                    (ctx.tender.info.shenpi.material === shenpiConst.sp_status.gdzs && i+1 !== iLen)) && ctx.session.sessionUser.accountId === ctx.material.user_id && !ctx.tender.isTourist) { %>
                             <a href="javascript: void(0)" class="text-danger pull-right">移除</a>
                             <% } %>
                             <span><%- ctx.material.auditorList[i].order %> <%- ctx.material.auditorList[i].name %></span>
@@ -59,8 +59,10 @@
             </div>
             <form class="modal-footer" method="post" action="<%- preUrl %>/audit/start" onsubmit="return checkAuditorFrom()">
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
+                <% if (ctx.session.sessionUser.accountId === ctx.material.user_id) { %>
                 <button class="btn btn-primary btn-sm" type="submit">确认上报</button>
+                <% } %>
             </form>
         </div>
     </div>
@@ -242,7 +244,7 @@
                 </div>
             </div>
             <form class="modal-footer" method="post" action="<%- preUrl %>/audit/start" onsubmit="return checkAuditorFrom()">
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
                 <% if(ctx.material.status === auditConst.status.checkNo && ctx.session.sessionUser.accountId === ctx.material.user_id) { %>
                     <button class="btn btn-primary btn-sm sp-list-item" type="submit">确认上报</button>
@@ -437,7 +439,7 @@
                     </div>
                     <div class="modal-footer">
                         <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
-                        <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                        <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 btn-sm">确认通过</button>
                     </div>
@@ -672,7 +674,7 @@
                     </div>
                     <div class="modal-footer">
                         <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
-                        <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                        <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
                         <button type="submit" class="btn btn-warning btn-sm">确认退回</button>
                     </div>
                 </form>

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

@@ -13,7 +13,9 @@
           </div>
         </div>
         <div class="d-inline-block">
+          <% if (!ctx.tender.isTourist && material.filePermission) { %>
           <a href="#addfujian" data-toggle="modal" class="btn btn-sm btn-light text-primary" data-toggle="tooltip" data-placement="bottom" title="" data-original-title="添加清单"><i class="fa fa-cloud-upload" aria-hidden="true"></i> 上传附件</a>
+          <% } %>
           <a href="javascript: void(0);" data-toggle="modal" class="btn btn-sm btn-light text-primary" id="bach-download"><i class="fa fa-download "></i> 批量下载</a>
           <a href="" id="downloadZip" style="display: none;" download></a>
         </div>

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

@@ -27,7 +27,7 @@
                 </div>
             </div>
             <div class="modal-footer">
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
                 <input type="hidden" name="s_order" value="" id="s_order" />
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
                 <button type="submit" id="addMaterial" class="btn btn-primary btn-sm">确定添加</button>
@@ -50,7 +50,7 @@
             </div>
             <div class="modal-footer">
                 <input type="hidden" name="material_id" value="<%= materials[0].id %>">
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">取消</button>
                 <button type="submit" class="btn btn-danger btn-sm">确定删除</button>
             </div>

+ 2 - 2
app/view/measure/audit_modal.ejs

@@ -30,7 +30,7 @@
             </div>
             <div class="modal-footer">
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
                 <input type="hidden" name="mid" value="<%- measure.mid %>" />
                 <input type="hidden" name="checkType" value="<%= auditConst.status.checked %>" />
                 <button type="submit" class="btn btn-success btn-sm" >确认通过</button>
@@ -69,7 +69,7 @@
             </div>
             <div class="modal-footer">
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
                 <input type="hidden" name="mid" value="<%- measure.mid %>" />
                 <input type="hidden" name="checkType" value="<%= auditConst.status.checkNo %>" />
                 <button type="submit" class="btn btn-warning btn-sm" >确认退回</button>

+ 2 - 2
app/view/measure/stage_modal.ejs

@@ -39,7 +39,7 @@
                 </div>
             </div>
             <div class="modal-footer">
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
                 <button type="submit" class="btn btn-primary btn-sm" id="add-stage-btn">确定添加</button>
             </div>
@@ -95,7 +95,7 @@
                 </div>
             </div>
             <div class="modal-footer">
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
                 <input type="hidden" name="order" id="edit-order" value="<%- stages[0].order %>">
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
                 <button type="submit" class="btn btn-primary btn-sm" id="edit-ok" >确定修改</button>

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

@@ -18,7 +18,7 @@
                             <input-text label="角色/职称" value="<%= accountData.role %>" name="role"></input-text>
                             <input-text label="手机" value="<%= accountData.mobile %>" name="mobile" maxlength="11" :readonly="<%= accountData.bind === 1 %>" msg="已绑定第三方平台,无法修改"></input-text>
                             <input-text label="电话" value="<%= accountData.telephone %>" name="telephone"></input-text>
-                            <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                            <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                             <button type="submit" class="btn btn-primary btn-sm" id="base-submit">确认修改</button>
                         </form>
                     </div>

+ 1 - 1
app/view/profile/safe.ejs

@@ -16,7 +16,7 @@
                                 <input-text label="旧密码" password="true" name="password"></input-text>
                                 <input-text label="新密码" password="true" name="new_password" id="new_password"></input-text>
                                 <input-text label="确认新密码" password="true" name="confirm_password"></input-text>
-                                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                                 <button type="submit" class="btn btn-primary btn-sm" id="modify-password">修改密码</button>
                             <% } else { %>
                                 <p>SSO用户请到<a href="#">此处</a>修改密码</p>

+ 2 - 2
app/view/profile/sms.ejs

@@ -37,7 +37,7 @@
                         <div class="form-group">
                             <div class="input-group mb-3">
                                 <input class="form-control form-control-sm" type="text" readonly="readonly" name="code" placeholder="输入短信中的6位验证码" />
-                                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                             </div>
                         </div>
                         <button type="button" class="btn btn-secondary btn-sm disabled" id="bind-btn">确认绑定</button>
@@ -48,7 +48,7 @@
                         <h4>通知类型</h4>
                         <p class="text-muted">勾选您需要接收的短信类型。</p>
                         <form id="sms-form" method="post" action="/profile/sms/type?csrf=<%- ctx.csrf %>">
-                            <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                            <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                             <% const user_smsType = accountData.sms_type !== '' ? JSON.parse(accountData.sms_type) : null; %>
                             <% for (const s in smsType) { %>
                             <% if (smsType[s].sms) { %>

+ 1 - 1
app/view/profile/wechat.ejs

@@ -34,7 +34,7 @@
                         <h4>通知类型</h4>
                         <p class="text-muted">勾选您需要接收的微信类型。</p>
                         <form id="sms-form" method="post" action="/profile/sms/type">
-                            <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                            <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                             <% const user_wxType = accountData.wx_type !== '' ? JSON.parse(accountData.wx_type) : null; %>
                             <% for (const s in smsType) { %>
                             <% if (smsType[s].wechat) { %>

+ 1 - 1
app/view/profile/wechat_modal.ejs

@@ -13,7 +13,7 @@
                 <h6>解绑后无法在微信接收通知。</h6>
             </div>
             <div class="modal-footer">
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                 <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">取消</button>
                 <button type="submit" class="btn btn-sm btn-primary">确定解绑</button>
             </div>

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

@@ -35,7 +35,7 @@
                         
                         <input-text value="<%= moment(projectData.create_time * 1000).format('YYYY-MM-DD HH:mm:ss') %>"
                             label="创建时间" readonly="readonly" name="create_time"></input-text>
-                        <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                        <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
                     </form>
                 </div>
             </div>

+ 2 - 2
app/view/report/rpt_all_popup.ejs

@@ -700,7 +700,7 @@
             }
         }
         $.bootstrapLoading.start();
-        CommonAjax.postXsrfEx("/tender/report_api/getMultiRoleRelationships", params, 30000, true, getCookie('csrfToken'),
+        CommonAjax.postXsrfEx("/tender/report_api/getMultiRoleRelationships", params, 30000, true, getCookie('csrfToken_j'),
             function(result){
                 $.bootstrapLoading.end();
                 let relArr = result.data;
@@ -843,7 +843,7 @@
     function updateCustRptCfg(){
         let params = {};
         params.nodeItems = CUST_TREE_NODES;
-        CommonAjax.postXsrfEx("/tender/report_api/updateCustNode", params, 60000, true, getCookie('csrfToken'),
+        CommonAjax.postXsrfEx("/tender/report_api/updateCustNode", params, 60000, true, getCookie('csrfToken_j'),
             function(result){
                 try {
                     // console.log(result);

+ 4 - 4
app/view/revise/info_modal.ejs

@@ -95,7 +95,7 @@
             <form class="modal-footer" method="post" action="/tender/<%- ctx.tender.id %>/revise/audit/start"
                 name="revise-start">
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                 <button class="btn btn-primary btn-sm" type="submit">确认上报</button>
             </form>
         </div>
@@ -288,7 +288,7 @@
                 </div>
                 <div class="modal-footer">
                     <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
-                    <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                    <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 btn-sm">确认通过</button>
                 </div>
@@ -524,7 +524,7 @@
                 </div>
                 <div class="modal-footer">
                     <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
-                    <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                    <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
                     <button type="submit" class="btn btn-warning btn-sm">确认退回</button>
                 </div>
             </form>
@@ -707,7 +707,7 @@
                 </div>
                 <form class="modal-footer" method="post" action="<%- preUrl %>/revise/audit/start"
                     name="revise-start">
-                    <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                    <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                     <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
                     <% if(revise.status === auditConst.status.checkNo && ctx.session.sessionUser.accountId === revise.uid) { %>
                     <button class="btn btn-primary btn-sm sp-list-item" type="submit">确认上报</button>

+ 2 - 2
app/view/revise/modal.ejs

@@ -9,7 +9,7 @@
                 <h5>创建修订后,本期计量将暂时锁定,锁定后本期计量无法计量和上报,需修订完成后,才能解锁。</h5>
             </div>
             <div class="modal-footer">
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
                 <button id="add-ok" type="submit" class="btn btn-primary btn-sm">确定新建</button>
             </div>
@@ -60,7 +60,7 @@
                 </div>
             </div>
             <div class="modal-footer">
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>" />
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>" />
                 <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal" >取消</button>
                 <button type="submit" class="btn btn-danger btn-sm">确认作废</button>
             </div>

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

@@ -0,0 +1,51 @@
+<% include ./sub_menu.ejs %>
+<div class="panel-content">
+    <div class="panel-title">
+        <div class="title-main">
+            <h2>功能设置</h2>
+        </div>
+    </div>
+    <div class="content-wrap">
+        <div class="c-body">
+            <div class="sjs-height-0">
+                <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) { %>
+                                <div class="form-check form-check-inline">
+                                    <input class="form-check-input" type="radio" id="radio_<%- i %>" value="<%- imType[i].value %>" <% if (funRela.imType === imType[i].value) { %>checked<% } %> name="im_type" onchange="updateSetting();">
+                                    <label class="form-check-label" for="radio_<%- i %>" name="im_type"><%- imType[i].name %></label>
+                                </div>
+                                <% } %>
+                            </div>
+                            <div>
+                                <label class="form-text text-danger">切换模式,仅对未开始第一期计量的标段生效。</label>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<script src="/public/js/setting.js"></script>
+<script>
+    $(() => {
+        autoFlashHeight();
+    });
+    const updateSetting = function () {
+        postData('/setting/fun/update', {imType: parseInt($('[name=im_type]:checked').val()), banOver: $('[name=ban_over]')[0].checked});
+    }
+</script>

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

@@ -12,7 +12,7 @@
             <div class="sjs-height-0">
                 <div class="row m-0 mt-3">
                     <div class="col-5">
-                        <% if (projectData.user_account === ctx.session.sessionUser.account) { %><form id="info-form" action="/<%= ctx.controllerName %>/updateinfo/<%= projectData.id === undefined ? 0 : projectData.id %>?_csrf=<%= ctx.csrf %>" method="post"><% } %>
+                        <% if (projectData.user_account === ctx.session.sessionUser.account) { %><form id="info-form" action="/<%= ctx.controllerName %>/updateinfo/<%= projectData.id === undefined ? 0 : projectData.id %>?_csrf_j=<%= ctx.csrf %>" method="post"><% } %>
                             <div class="form-group">
                                 <label>项目编号</label>
                                 <input class="form-control form-control-sm" value="<%= projectData.code%>" type="text" readonly>

+ 4 - 4
app/view/setting/user_modal.ejs

@@ -5,7 +5,7 @@
             <div class="modal-header">
                 <h5 class="modal-title">添加账号</h5>
             </div>
-            <form method="post" action="/setting/user/add?_csrf=<%= ctx.csrf %>" onsubmit="return checkUserForm('add');">
+            <form method="post" action="/setting/user/add?_csrf_j=<%= ctx.csrf %>" onsubmit="return checkUserForm('add');">
             <div class="modal-body">
                 <div class="form-group">
                     <label><b class="text-danger">*</b>账号组</label>
@@ -69,7 +69,7 @@
             <div class="modal-header">
                 <h5 class="modal-title">编辑账号</h5>
             </div>
-            <form method="post" action="/setting/user/update?_csrf=<%= ctx.csrf %>" onsubmit="return checkUserForm('update');">
+            <form method="post" action="/setting/user/update?_csrf_j=<%= ctx.csrf %>" onsubmit="return checkUserForm('update');">
             <div class="modal-body">
                 <div class="form-group">
                     <label>账号组<b class="text-danger">*</b></label>
@@ -167,7 +167,7 @@
                 <h4>确认解除 <span id="bind_account">陈特 15812644017</span> 的绑定状态?</h4>
             </div>
             <form method="post" action="/setting/user/unbind" class="modal-footer">
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                 <input type="hidden" name="id" id="account_id" value="">
                 <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">关闭</button>
                 <button type="submit" class="btn btn-sm btn-sm btn-primary">确定解绑</button>
@@ -206,7 +206,7 @@
                 <div class="alert alert-warning py-1 px-2">若修改登录账号,必须重新设置新密码。新密码会发送至已认证手机。</div>
             </div>
             <div class="modal-footer">
-                <input type="hidden" name="_csrf" value="<%= ctx.csrf %>">
+                <input type="hidden" name="_csrf_j" value="<%= ctx.csrf %>">
                 <input type="hidden" name="id" value="">
                 <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">关闭</button>
                 <button type="submit" class="btn btn-sm btn-primary">提交修改</button>

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

@@ -5,7 +5,7 @@
             <div class="modal-header">
                 <h5 class="modal-title">添加账号</h5>
             </div>
-            <form method="post" action="/setting/user/add?_csrf=<%= ctx.csrf %>" onsubmit="return checkUserForm('add');">
+            <form method="post" action="/setting/user/add?_csrf_j=<%= ctx.csrf %>" onsubmit="return checkUserForm('add');">
             <div class="modal-body">
                 <div class="form-group">
                     <label><b class="text-danger">*</b>账号组</label>
@@ -69,7 +69,7 @@
             <div class="modal-header">
                 <h5 class="modal-title">编辑权限</h5>
             </div>
-            <form method="post" action="/setting/user/permission?_csrf=<%= ctx.csrf %>">
+            <form method="post" action="/setting/user/permission?_csrf_j=<%= ctx.csrf %>">
             <div class="modal-body">
                 <% let index = 0; %>
                 <% for (const pm in permission) { %>

+ 0 - 0
app/view/stage/audit_btn.ejs


Some files were not shown because too many files changed in this diff