Przeglądaj źródła

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

MaiXinRong 4 lat temu
rodzic
commit
632d9a265f
100 zmienionych plików z 1373 dodań i 282 usunięć
  1. 2 2
      app/base/base_service.js
  2. 2 0
      app/const/tender_info.js
  3. 3 0
      app/controller/change_controller.js
  4. 104 1
      app/controller/login_controller.js
  5. 2 0
      app/controller/report_controller.js
  6. 64 2
      app/controller/setting_controller.js
  7. 7 4
      app/controller/stage_controller.js
  8. 8 5
      app/controller/tender_controller.js
  9. 17 1
      app/controller/wechat_controller.js
  10. 108 11
      app/extend/helper.js
  11. 18 4
      app/lib/analysis_excel.js
  12. 3 0
      app/lib/gcl_gather.js
  13. 64 0
      app/lib/rpt_data_analysis.js
  14. 4 0
      app/middleware/sort_filter.js
  15. 1 1
      app/middleware/tender_check.js
  16. 2 2
      app/middleware/uncheck_tender_check.js
  17. BIN
      app/public/images/icon-pc.png
  18. BIN
      app/public/images/icon-qrcode.png
  19. 6 6
      app/public/js/bootstrap/bootstrap-paginator.js
  20. 2 2
      app/public/js/change_approval.js
  21. 1 1
      app/public/js/change_detail.js
  22. 4 0
      app/public/js/change_information.js
  23. 6 2
      app/public/js/change_information_approval.js
  24. 69 8
      app/public/js/change_information_set.js
  25. 5 1
      app/public/js/change_information_show.js
  26. 1 1
      app/public/js/common_ajax.js
  27. 1 1
      app/public/js/draw.js
  28. 58 8
      app/public/js/global.js
  29. 1 24
      app/public/js/ledger_check.js
  30. 1 1
      app/public/js/login.js
  31. 2 2
      app/public/js/profile.js
  32. 9 2
      app/public/js/setting.js
  33. 1 0
      app/public/js/shares/cs_tools.js
  34. 4 2
      app/public/js/spreadjs_rela/spreadjs_zh.js
  35. 3 39
      app/public/js/stage.js
  36. 1 1
      app/public/js/stage_audit.js
  37. 15 6
      app/public/js/stage_gather.js
  38. 2 2
      app/public/js/wap/global.js
  39. 7 4
      app/public/report/js/rpt_main.js
  40. 23 1
      app/public/report/js/rpt_preview_common.js
  41. 3 1
      app/public/report/js/rpt_print.js
  42. 4 4
      app/public/report/js/rpt_signature.js
  43. 1 0
      app/reports/rpt_component/helper/jpc_helper_discrete.js
  44. 11 0
      app/router.js
  45. 4 1
      app/service/advance.js
  46. 50 1
      app/service/change_audit_list.js
  47. 1 1
      app/service/customer.js
  48. 2 2
      app/service/message.js
  49. 30 0
      app/service/project.js
  50. 17 9
      app/service/project_account.js
  51. 30 6
      app/service/report.js
  52. 58 2
      app/service/report_memory.js
  53. 134 0
      app/service/rpt_archive.js
  54. 3 0
      app/service/stage.js
  55. 3 2
      app/service/stage_audit.js
  56. 5 4
      app/service/stage_bills_final.js
  57. 1 1
      app/service/stage_jgcl.js
  58. 1 1
      app/service/stage_pos_final.js
  59. 1 1
      app/service/version.js
  60. 1 1
      app/view/account/index.ejs
  61. 1 1
      app/view/advance/index.ejs
  62. 2 2
      app/view/advance/modal_audit.ejs
  63. 1 1
      app/view/boot/index.ejs
  64. 1 1
      app/view/change/info.ejs
  65. 4 4
      app/view/change/info_modal.ejs
  66. 1 1
      app/view/change/information.ejs
  67. 6 6
      app/view/change/information_modal.ejs
  68. 1 1
      app/view/change/modal.ejs
  69. 1 1
      app/view/dashboard/msg_add.ejs
  70. 44 2
      app/view/layout/page.ejs
  71. 3 3
      app/view/ledger/audit_modal.ejs
  72. 2 2
      app/view/ledger/explode_modal.ejs
  73. 42 3
      app/view/login/login.ejs
  74. 1 1
      app/view/login/login_port.ejs
  75. 74 0
      app/view/login/wxproject.ejs
  76. 4 4
      app/view/material/audit_modal.ejs
  77. 2 2
      app/view/material/modal.ejs
  78. 2 2
      app/view/measure/audit_modal.ejs
  79. 2 2
      app/view/measure/stage_modal.ejs
  80. 1 1
      app/view/profile/info.ejs
  81. 1 1
      app/view/profile/safe.ejs
  82. 2 2
      app/view/profile/sms.ejs
  83. 1 1
      app/view/profile/wechat.ejs
  84. 1 1
      app/view/profile/wechat_modal.ejs
  85. 1 1
      app/view/project/info.ejs
  86. 67 23
      app/view/report/index.ejs
  87. 8 6
      app/view/report/rpt_all_popup.ejs
  88. 4 4
      app/view/revise/info_modal.ejs
  89. 2 2
      app/view/revise/modal.ejs
  90. 51 0
      app/view/setting/fun.ejs
  91. 1 1
      app/view/setting/info.ejs
  92. 4 4
      app/view/setting/user_modal.ejs
  93. 2 2
      app/view/setting/user_permission_modal.ejs
  94. 5 5
      app/view/stage/audit_modal.ejs
  95. 2 2
      app/view/stage/manager_modal.ejs
  96. 26 0
      app/view/tender/detail_modal.ejs
  97. 2 2
      app/view/tender/shenpi_modal.ejs
  98. 6 0
      app/view/tender/tender_sub_mini_menu.ejs
  99. 1 1
      app/view/wap/login.ejs
  100. 0 0
      app/view/wap/shenpi_change.ejs

+ 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) {

+ 2 - 0
app/const/tender_info.js

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

+ 3 - 0
app/controller/change_controller.js

@@ -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;

+ 104 - 1
app/controller/login_controller.js

@@ -9,6 +9,7 @@
  */
 const URL = require('url');
 const maintainConst = require('../const/maintain');
+const OAuth = require('co-wechat-oauth');
 
 module.exports = app => {
 
@@ -25,6 +26,7 @@ module.exports = app => {
                 ctx.redirect('/wap');
                 return;
             }
+
             const errorMessage = ctx.session.loginError;
             // 显示完删除
             ctx.session.loginError = null;
@@ -39,9 +41,110 @@ module.exports = app => {
                 maintainData,
                 maintainConst,
                 errorMessage,
+                hostUrl: ctx.protocol + '://' + ctx.host,
             };
             await ctx.render('login/login.ejs', renderData);
         }
+        /**
+         * 微信扫码认证并返回
+         *
+         * @param {Object} ctx - egg全局页面
+         * @return {void}
+         */
+        async wxAuth(ctx) {
+            const code = ctx.query.code;
+            try {
+                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);
+                if (!token) {
+                    throw '微信扫码获取信息失败';
+                }
+                // 判断扫码者项目是否只有一个,是则直接跳到登录页,否则显示项目选择页
+                const paList = await ctx.service.projectAccount.getAllDataByCondition({ where: { wx_unionid: token.data.unionid } });
+                if (paList && paList.length === 1) {
+                    const pro = await ctx.service.project.getDataById(paList[0].project_id);
+                    let redirect_url = ctx.protocol + '://' + ctx.host;
+                    redirect_url += ctx.query.state ? ctx.query.state : '/dashboard';
+                    ctx.redirect('/wx/url2web?project=' + pro.code + '&url=' + redirect_url + '&unionid=' + token.data.unionid);
+                } else {
+                    ctx.session.wechatLogin = token.data.unionid;
+                    ctx.redirect('/wxproject');
+                }
+            } catch (error) {
+                this.log(error);
+                ctx.session.loginError = error;
+                ctx.redirect('/login');
+            }
+        }
+
+        async wxProject(ctx) {
+            try {
+                const unionid = ctx.session.wechatLogin;
+                if (!unionid) {
+                    throw '扫码信息已失效,请重新登录';
+                }
+                ctx.session.wechatLogin = null;
+                const paList = await ctx.service.projectAccount.getAllDataByCondition({ where: { wx_unionid: unionid } });
+                const pidList = ctx.app._.uniq(ctx.app._.map(paList, 'project_id'));
+                const pList = [];
+                const redirect_url = ctx.protocol + '://' + ctx.host + '/dashboard';
+                for (const p of pidList) {
+                    const pro = await ctx.service.project.getDataById(p);
+                    pro.userMsg = ctx.app._.find(paList, { project_id: p });
+                    pList.push(pro);
+                }
+                // 获取系统维护信息
+                const maintainData = await ctx.service.maintain.getDataById(1);
+                const renderData = {
+                    maintainData,
+                    maintainConst,
+                    unionid,
+                    pList,
+                    redirect_url,
+                };
+                await ctx.render('login/wxproject.ejs', renderData);
+            } catch (error) {
+                this.log(error);
+                ctx.session.loginError = error;
+                ctx.redirect('/login');
+            }
+        }
+
+        // 设置用户微信登录项目,跳转到对应wap页面
+        async url2web(ctx) {
+            try {
+                if (!ctx.query.project || !ctx.query.url || !ctx.query.unionid) {
+                    throw '参数有误';
+                }
+                const code = ctx.query.project;
+                // 查找项目数据
+                const projectData = await ctx.service.project.getProjectByCode(code.toString().trim());
+                if (projectData === null) {
+                    throw '不存在项目数据';
+                }
+                const pa = await ctx.service.projectAccount.getDataByCondition({ project_id: projectData.id, wx_unionid: ctx.query.unionid });
+                if (!pa) {
+                    throw '该微信号未绑定此项目';
+                }
+                if (pa.enable !== 1) {
+                    throw '该账号已被停用,请联系销售人员';
+                }
+                // 设置项目和用户session记录
+                const result = await ctx.service.projectAccount.accountLogin({ project: projectData, accountData: pa }, 3);
+                if (!result) {
+                    throw '登录出错';
+                }
+                ctx.redirect(ctx.query.url);
+            } catch (error) {
+                const renderData = {
+                    status: 1,
+                    msg: error,
+                };
+                await ctx.render('wechat/tips.ejs', renderData);
+            }
+        }
 
         /**
          * 登录操作
@@ -206,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;

+ 2 - 0
app/controller/report_controller.js

@@ -68,6 +68,8 @@ module.exports = app => {
             try {
                 await this._getStageAuditViewData(ctx);
                 const pageShow = ctx.session.sessionProject.page_show;
+                // console.log(pageShow);
+                // pageShow.showArchive = 1;
                 const tender = ctx.tender;
                 const stage = ctx.stage;
                 let stage_id = -1;

+ 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;

+ 7 - 4
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) {

+ 8 - 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');

+ 17 - 1
app/controller/wechat_controller.js

@@ -110,7 +110,7 @@ module.exports = app => {
                     throw '先关注公众号才能绑定项目';
                 }
 
-                const result2 = await ctx.service.projectAccount.bindWx(accountData.id, ctx.session.wechatToken.openid, user.nickname);
+                const result2 = await ctx.service.projectAccount.bindWx(accountData.id, ctx.session.wechatToken.openid, user.nickname, user.unionid);
                 if (!result2) {
                     throw '绑定失败';
                 }
@@ -254,6 +254,22 @@ 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 = [];

+ 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;
     };
 };

+ 1 - 1
app/middleware/tender_check.js

@@ -65,7 +65,7 @@ module.exports = options => {
                 (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) {
                 throw '您无权查看该项目';
             }
 

+ 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) {
                     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) {
                     throw '您无权查看该内容';
                 }
             }

BIN
app/public/images/icon-pc.png


BIN
app/public/images/icon-qrcode.png


+ 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: {

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

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

+ 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',

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

@@ -236,6 +236,10 @@ $(document).ready(() => {
         headerFont: '12px 微软雅黑',
         font: '12px 微软雅黑',
         readOnly: true,
+        localCache: {
+            key: 'changes-xmj',
+            colWidth: true,
+        }
     };
     SpreadJsObj.initSheet(xmjSpread.getActiveSheet(), xmjSpreadSetting);
 });

+ 6 - 2
app/public/js/change_information_approval.js

@@ -42,6 +42,10 @@ $(document).ready(() => {
                 },
             },
         ],
+        localCache: {
+            key: 'changes-spread',
+            colWidth: true,
+        }
     };
     for (const aid of aidList) {
         const userinfo = _.find(auditList2, { 'uid': aid });
@@ -378,8 +382,8 @@ const postDataWithAsync = function (url, data, successCallback, errorCallBack, s
         async: false,
         timeout: 60000,
         beforeSend: function(xhr) {
-            let csrfToken = Cookies.get('csrfToken');
-            xhr.setRequestHeader('x-csrf-token', csrfToken);
+            let csrfToken = Cookies.get('csrfToken_j');
+            xhr.setRequestHeader('x-csrf-token_j', csrfToken);
         },
         success: function(result){
             if (result.err === 0) {

+ 69 - 8
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'},
@@ -119,6 +119,10 @@ $(document).ready(() => {
                 },
             },
         ],
+        localCache: {
+            key: 'changes-spread',
+            colWidth: true,
+        }
     };
 
     const changeCol = {
@@ -180,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);
@@ -318,6 +332,7 @@ $(document).ready(() => {
                         }
                         continue;
                     }
+
                     if (colSetting.type === 'Number') {
                         if (isNaN(validText)) {
                             toastMessageUniq(getPasteHint(hint.numberExpr, hintRow));
@@ -330,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);
@@ -472,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',
@@ -494,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',
@@ -836,9 +898,8 @@ function tableDataRemake(changeListData) {
                     let pushbwmx = '0*;*0';
                     if (listinfo.leafXmjs !== undefined) {
                         const leafInfo = listinfo.leafXmjs.find(function (item) {
-                            return (item.bwmx === undefined || item.bwmx === clinfo.bwmx) && (item.quantity !== null ? item.quantity === parseFloat(clinfo.oamount) : 0 === parseFloat(clinfo.oamount));
+                            return (item.bwmx === undefined || item.bwmx === clinfo.bwmx) && item.code === clinfo.xmj_code && (item.quantity !== null ? item.quantity === parseFloat(clinfo.oamount) : 0 === parseFloat(clinfo.oamount));
                         });
-                        console.log(leafInfo);
                         if (leafInfo) {
                             pushbwmx = leafInfo.code + '!_!' + (leafInfo.jldy !== undefined ? leafInfo.jldy : '') + '!_!' +
                                 (leafInfo.dwgc ? leafInfo.dwgc : '') + '!_!' +
@@ -868,7 +929,7 @@ function tableDataRemake(changeListData) {
                     let pushbwmx = '0*;*0';
                     if (listinfo.leafXmjs !== undefined) {
                         const leafInfo = listinfo.leafXmjs.find(function (item) {
-                            return (item.bwmx === undefined || item.bwmx === clinfo.bwmx || item.jldy === clinfo.bwmx) && (item.quantity !== null ? item.quantity === parseFloat(clinfo.oamount) : 0 === parseFloat(clinfo.oamount));
+                            return (item.bwmx === undefined || item.bwmx === clinfo.bwmx || item.jldy === clinfo.bwmx) && item.code === clinfo.xmj_code && (item.quantity !== null ? item.quantity === parseFloat(clinfo.oamount) : 0 === parseFloat(clinfo.oamount));
                         });
                         if (leafInfo) {
                             pushbwmx = leafInfo.code + '!_!' + (leafInfo.jldy !== undefined ? leafInfo.jldy : '') + '!_!' +

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

@@ -44,6 +44,10 @@ $(document).ready(() => {
                 },
             },
         ],
+        localCache: {
+            key: 'changes-spread',
+            colWidth: true,
+        }
     };
     for (const aid of aidList) {
         const userinfo = _.find(auditList2, { 'uid': aid });
@@ -184,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',

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

@@ -127,7 +127,7 @@ var CommonAjax = {
             async: isAsync,
             timeout: dftTimeOutMilSec,
             beforeSend: function (xhr) {
-                xhr.setRequestHeader('x-csrf-token', csrfToken);
+                xhr.setRequestHeader('x-csrf-token_j', csrfToken);
             },
             success: function(result){
                 if (result) {

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

@@ -220,7 +220,7 @@ Draw.prototype = {
     formData.append('image', blob, 'sign');
 
     xhr.open('POST', url, true);
-    xhr.setRequestHeader("x-csrf-token", csrf);
+    xhr.setRequestHeader("x-csrf-token_j", csrf);
     xhr.onload = () => {
       if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
         success(xhr.responseText);

+ 58 - 8
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,8 +157,8 @@ const postData = function (url, data, successCallback, errorCallBack, showWaitin
         cache: false,
         timeout: 60000,
         beforeSend: function(xhr) {
-            let csrfToken = Cookies.get('csrfToken');
-            xhr.setRequestHeader('x-csrf-token', csrfToken);
+            let csrfToken = Cookies.get('csrfToken_j');
+            xhr.setRequestHeader('x-csrf-token_j', csrfToken);
         },
         success: function(result){
             if (result.err === 0) {
@@ -200,8 +206,8 @@ const postDataCompress = function (url, data, successCallback, errorCallBack, ht
         cache: false,
         timeout: 80000, // 导入清单Excel(10w行)预计需要时间
         beforeSend: function(xhr) {
-            let csrfToken = Cookies.get('csrfToken');
-            xhr.setRequestHeader('x-csrf-token', csrfToken);
+            let csrfToken = Cookies.get('csrfToken_j');
+            xhr.setRequestHeader('x-csrf-token_j', csrfToken);
         },
         success: function(result){
             if (htype === 'progress') doneProgress();
@@ -260,8 +266,8 @@ const postDataWithFile = function (url, formData, successCallback, errorCallBack
         processData: false,
         timeout: 60000,
         beforeSend: function(xhr) {
-            let csrfToken = Cookies.get('csrfToken');
-            xhr.setRequestHeader('x-csrf-token', csrfToken);
+            let csrfToken = Cookies.get('csrfToken_j');
+            xhr.setRequestHeader('x-csrf-token_j', csrfToken);
         },
         success: function(result){
             if (result.err === 0) {
@@ -304,8 +310,8 @@ const postDataWithFileProgress = function (url, formData, successCallback, error
         // 告诉jQuery不要去处理发送的数据
         processData: false,
         beforeSend: function(xhr) {
-            let csrfToken = Cookies.get('csrfToken');
-            xhr.setRequestHeader('x-csrf-token', csrfToken);
+            let csrfToken = Cookies.get('csrfToken_j');
+            xhr.setRequestHeader('x-csrf-token_j', csrfToken);
         },
         success: function(result){
             doneProgress();
@@ -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'];

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

@@ -102,30 +102,7 @@ const ledgerCheckUtil = {
         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;
     },

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

@@ -94,7 +94,7 @@ $(document).ready(function() {
                 dataType: 'json',
                 beforeSend: function(xhr) {
                     let csrfToken = csrf;
-                    xhr.setRequestHeader('x-csrf-token', csrfToken);
+                    xhr.setRequestHeader('x-csrf-token_j', csrfToken);
                 },
                 success: function (result) {
                     if (result.err === 1) {

+ 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',

+ 9 - 2
app/public/js/setting.js

@@ -84,8 +84,8 @@ $(document).ready(() => {
                     throw '网络错误!';
                 },
                 beforeSend: function(xhr) {
-                    let csrfToken = Cookies.get('csrfToken');
-                    xhr.setRequestHeader('x-csrf-token', csrfToken);
+                    let csrfToken = Cookies.get('csrfToken_j');
+                    xhr.setRequestHeader('x-csrf-token_j', 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/wap/global.js

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

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

@@ -351,6 +351,9 @@ let zTreeOprObj = {
         }
         return rst;
     },
+    _setupArchive: function() {
+        //
+    },
     requestNormalReport: function (params) {
         let me = zTreeOprObj;
         if (COMMON_WATER_MARK_PIC_DATA === null || COMMON_WATER_MARK_PIC_DATA === '') {
@@ -359,7 +362,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;
@@ -569,7 +572,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";
@@ -601,7 +604,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) {
@@ -696,7 +699,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();

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

@@ -3,14 +3,36 @@
  */
 
 let G_OFFSET_X = 0, G_OFFSET_Y = 0;
+let STAGE_AUDIT = []; //注意这个,与rpt_main.js不要混了
+// 设置Date对象Format函数
+// -- 打印预览需要重新设置一遍 ------------------------------------------------
+Date.prototype.Format = function(fmt) {
+    const o = {
+        'M+': this.getMonth() + 1, // 月份
+        'd+': this.getDate(), // 日
+        'h+': this.getHours(), // 小时
+        'm+': this.getMinutes(), // 分
+        's+': this.getSeconds(), // 秒
+        'q+': Math.floor((this.getMonth() + 3) / 3), // 季度
+        'S': this.getMilliseconds(), // 毫秒
+    };
+    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length));
+    for (const k in o) {
+        if (new RegExp('(' + k + ')').test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)));
+    }
+    return fmt;
+};
+
 function printPageLoading() {
     let params = JSON.parse(sessionStorage.report_params);
     let _current_stage_status = parseInt(sessionStorage.current_stage_status);
     let closeWaterMark = parseInt(sessionStorage.closeWaterMark);
+    let refRptTplIds = JSON.parse(sessionStorage.refRptTplIds);
     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;
             // sessionStorage.waterMarkStr = result.waterMarkStr;
             if (params.needWaterMark) sessionStorage.waterMarkStr = result.waterMarkStr;
             for (const signatureRel of result.signatureRelInfo) {

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

@@ -24,6 +24,8 @@ let rptPrintHelper = {
             sessionStorage.closeWaterMark = getCloseWatermark();
             sessionStorage.pageSize = rptControlObj.getCurrentPageSize();
             sessionStorage.waterMarkStr = COMMON_WATER_MARK_PIC_DATA;
+            sessionStorage.refRptTplIds = JSON.stringify(refRptTplIds);
+            // sessionStorage.STAGE_AUDIT = JSON.stringify(STAGE_AUDIT);
             if (sessionStorage.pageSize === 'A3') {
                 window.open('/printReport/A3');
             } else {
@@ -46,7 +48,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 = {};

+ 1 - 0
app/reports/rpt_component/helper/jpc_helper_discrete.js

@@ -57,6 +57,7 @@ const JpcDiscreteHelper = {
                                                 }
                                             }
                                             // value = map_data_field[JV.PROP_AD_HOC_DATA][0];
+                                            value = this._getSegPageValue(value, segPageIdx);
                                         } else value = '';
                                     }
                                     if (map_data_field && map_data_field[JV.PROP_PRECISION] && map_data_field.flexiblePrecisionRefObj) {

+ 11 - 0
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');
@@ -458,4 +462,11 @@ module.exports = app => {
     // 书签
     app.post('/tender/:id/ledger/tag', sessionAuth, tenderCheck, uncheckTenderCheck, 'tenderController.billsTag');
     app.post('/tender/:id/measure/stage/:order/tag', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'tenderController.billsTag');
+
+    // 扫码登录
+    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,

+ 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;

+ 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;

+ 17 - 9
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;
@@ -764,9 +764,10 @@ module.exports = app => {
          * @param {String} id - 账号id
          * @param {Number} openid - openid
          * @param {Number} nickname - 微信名称
+         * @param {Number} unionid - unionid
          * @return {Boolean} - 返回修改结果
          */
-        async bindWx(id, openid, nickname) {
+        async bindWx(id, openid, nickname, unionid) {
             const wx_type = {};
             for (const key in smsTypeConst) {
                 if (smsTypeConst.hasOwnProperty(key)) {
@@ -779,6 +780,7 @@ module.exports = app => {
                 id,
                 wx_openid: openid,
                 wx_name: nickname,
+                wx_unionid: unionid,
                 wx_type: JSON.stringify(wx_type),
             };
 
@@ -788,6 +790,12 @@ 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.getDataByCondition({ 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);

+ 134 - 0
app/service/rpt_archive.js

@@ -0,0 +1,134 @@
+/**
+ * Created by Tony on 2021/3/30.
+ */
+
+const BaseService = require('../base/base_service');
+
+module.exports = app => {
+
+    class RptArchive extends BaseService {
+
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'rpt_archive';
+            this.dataId = 'archive_id';
+        }
+
+        async getArchiveById(id) {
+            this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('archive_id', {
+                value: id,
+                operate: '=',
+            });
+            this.sqlBuilder.columns = ['archive_id', 'prj_id', 'stage_id', 'content'];
+            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
+            const list = await this.db.query(sql, sqlParam);
+            return list;
+        }
+
+        async getPrjStgArchive(prjId, stgId) {
+            this.initSqlBuilder();
+            this.sqlBuilder.setAndWhere('prj_id', {
+                value: prjId,
+                operate: '=',
+            });
+            this.sqlBuilder.setAndWhere('stage_id', {
+                value: stgId,
+                operate: '=',
+            });
+            this.sqlBuilder.columns = ['archive_id', 'prj_id', 'stage_id', 'content'];
+            const [sql, sqlParam] = this.sqlBuilder.build(this.tableName);
+            const list = await this.db.query(sql, sqlParam);
+            return list;
+        }
+
+        async createArchive(prj_id, stg_id, archiveArr) {
+            let rst = null;
+            this.transaction = await this.db.beginTransaction();
+            try {
+                const data = {
+                    prj_id,
+                    stg_id,
+                    content: JSON.stringify(archiveArr),
+                };
+                // console.log(data);
+                rst = await this.transaction.insert(this.tableName, data);
+                await this.transaction.commit();
+            } catch (ex) {
+                console.log(ex);
+                // 回滚
+                await this.transaction.rollback();
+            }
+            return rst;
+        }
+        //
+        // async addInitialStageData(tender_id, stage, preStage) {
+        //     // 在加stage的时候需要挂上这个,copy之前的签名人
+        //     const rst = [];
+        //     const preRoleRelList = await this.getRoleRptRelByTenderId(tender_id, preStage.id);
+        //     for (const rptRoleRel of preRoleRelList) {
+        //         const relList = JSON.parse(rptRoleRel.rel_content);
+        //         // const newRptRoleRel = {tender_id: tender_id, rpt_id: rptRoleRel.rpt_id, sid: stage.id, rel_content: ''};
+        //         const newRelList = [];
+        //         for (const role of relList) {
+        //             const newRole = {};
+        //             newRelList.push(newRole);
+        //             for (const key in role) {
+        //                 if (key !== 'sign_date') {
+        //                     newRole[key] = role[key];
+        //                 } else {
+        //                     newRole[key] = '';
+        //                 }
+        //             }
+        //         }
+        //         // rst.push(await this.createRoleRelationship(tender_id, rptRoleRel.rpt_id, stage.id, newRelList));
+        //         await this.createRoleRelationship(tender_id, rptRoleRel.rpt_id, stage.id, newRelList); // 暂时用不到,就先不返回结果
+        //     }
+        //     return rst;
+        // }
+
+        // async updateRoleRelationship(id, tender_id, rpt_id, sid, relArr) {
+        //     let rst = null;
+        //     if (id < 0) {
+        //         rst = await this.createRoleRelationship(tender_id, rpt_id, sid, relArr);
+        //     } else {
+        //         this.transaction = await this.db.beginTransaction();
+        //         try {
+        //             const data = { id, tender_id, rpt_id, sid, rel_content: JSON.stringify(relArr) };
+        //             rst = await this.transaction.update(this.tableName, data);
+        //             await this.transaction.commit();
+        //         } catch (ex) {
+        //             console.log(ex);
+        //             // 回滚
+        //             await this.transaction.rollback();
+        //         }
+        //     }
+        //     return rst;
+        // }
+        //
+        // async updateMultiRoleRelationship(orgParams, newRelArr) {
+        //     for (let idx = 0; idx < orgParams.length; idx++) {
+        //         const param = orgParams[idx];
+        //         const data = { tender_id: param[0], sid: param[1], rpt_id: param[2] };
+        //         this.transaction = await this.db.beginTransaction();
+        //         try {
+        //             await this.transaction.delete(this.tableName, data);
+        //             this.transaction.commit();
+        //             await this.createRoleRelationship(param[0], param[2], param[1], newRelArr);
+        //         } catch (ex) {
+        //             console.log(ex.toString());
+        //             // 回滚
+        //             await this.transaction.rollback();
+        //         }
+        //     }
+        //     return true;
+        // }
+    }
+    return RptArchive;
+};

+ 3 - 0
app/service/stage.js

@@ -355,6 +355,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 +

+ 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>

+ 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',

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

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

+ 6 - 6
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>
@@ -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>

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

@@ -30,7 +30,9 @@
                 </form>
             <% } else { %>
                 <!--演示版-->
-                <form class="form-signin" method="post" action="/login">
+                <form class="form-signin" method="post" action="/login" id="normal-form" style="min-width: 360px;position: relative">
+                    <!--<div class="change-form" style="position: absolute;right: 0;top: 0px;cursor: pointer;"><i style="padding:5px;font-size: 50px;color: #212529" class="fa fa-qrcode"></i></div>-->
+                    <div class="change-form" data-toggle="tooltip" data-placement="left" title="微信登录" style="position: absolute;right: 0;top: 0px;cursor: pointer;"><img alt="微信扫码登录" style="padding:5px;" width="50px" src="/public/images/icon-qrcode.png"></div>
                     <!-- <h4 class="text-center mb-2">纵横云计量</h4> -->
                     <h5 class="text-center mb-2" id="project_name"></h5>
                     <h5 class="text-center mb-4 text-muted">用户登录</h5>
@@ -66,13 +68,19 @@
                     </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">
                         <a href="#fg-password" data-toggle="modal" data-target="#fg-password"  class="mr-3">忘记密码?</a>
                     </div>
                 </form>
+                <form class="form-signin" id="code-form" style="min-width: 360px;position: relative;display: none">
+                    <!--<div class="change-form" style="position: absolute;right: 0;top: 0px;cursor: pointer;"><i style="padding:5px;font-size: 40px;color: #212529" class="fa fa-laptop"></i></div>-->
+                    <div class="change-form" data-toggle="tooltip" data-placement="left" title="账号登录" style="position: absolute;right: 0;top: 0px;cursor: pointer;"><img alt="账号登录" style="padding:5px;" width="50px" src="/public/images/icon-pc.png"></div>
+                    <div id="wx-code" style="text-align: center">
+                    </div>
+                </form>
             <% } %>
             <!--项目版-->
         </div>
@@ -135,6 +143,37 @@
     const csrf = '<%= ctx.csrf %>'
 </script>
 <script src="/public/js/login.js"></script>
-</body>
+<script src="http://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",
+            scope: "snsapi_login",
+            redirect_uri: "<%- hostUrl %>/wxAuth",
+            state: getQueryString('referer'),
+            style: "black",
+            href: ""
+        });
 
+        function getQueryString(name) {
+            var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
+            var r = window.location.search.substr(1).match(reg); //获取url中"?"符后的字符串并正则匹配
+            var context = "";
+
+            if (r != null)
+                context = r[2];
+            reg = null;
+            r = null;
+            return context == null || context == "" || context == "undefined" ? "" : context;
+        }
+
+        $('.change-form').on('click', function () {
+            $(this).parents('form').hide();
+            $(this).parents('form').siblings('form').show();
+        })
+    })
+</script>
+</body>
 </html>

+ 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" >

+ 74 - 0
app/view/login/wxproject.ejs

@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
+    <meta http-equiv="x-ua-compatible" content="ie=edge">
+    <title>项目列表-计量支付</title>
+    <link rel="stylesheet" href="/public/css/bootstrap/bootstrap.min.css">
+    <link rel="stylesheet" href="/public/css/wap/main.css">
+    <link rel="stylesheet" href="/public/css/toast.css">
+    <link rel="stylesheet" href="/public/css/font-awesome/font-awesome.min.css">
+    <link rel="shortcut icon" href="/public/images/favicon.ico">
+</head>
+<body>
+<div class="container">
+    <!--顶部-->
+    <nav class="fixed-top bg-dark">
+        <div class="my-2 d-flex justify-content-between">
+            <span class="text-white ml-3">项目列表</span>
+            <div class="mr-3"><a class="text-white" href="/login">重新登录</a>
+                <!-- <div class="dropdown">
+                  <button class="btn btn-sm btn-light dropdown-toggle" type="button" data-toggle="dropdown">
+                    张三
+                  </button>
+                  <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
+                    <a class="dropdown-item" href="#">退出登录</a>
+                  </div>
+                </div> -->
+            </div>
+        </div>
+    </nav>
+    <% if (maintainData.status === maintainConst.status.ongoing) { %>
+        <form class="card m-3 mt-3">
+            <div class="card-body">
+                <h4 class="text-center mb-3"><i class="fa fa-wrench"></i>系统正在维护</h4>
+                <h4>预计恢复时间<%- (maintainData.duration !== maintainConst.duration.forever ? '为 ' + ctx.helper.dateTran(parseFloat(maintainData.maintain_time) + ctx.helper.timeAdd(maintainData.duration)) : ' 暂未确定') %></h4>
+                <h4>造成不便敬请谅解。</h4>
+            </div>
+        </form>
+    <% } else { %>
+    <!--待审批期列表-->
+    <div class="py-6">
+        <% if (pList.length !== 0) { %>
+        <p class="text-muted">您的微信已绑定以下项目:</p>
+        <% for (const p of pList) { %>
+        <div class="card mb-3">
+            <div class="card-header d-flex justify-content-between">
+                <span><%- p.name %></span>
+            </div>
+            <div class="d-flex justify-content-between">
+                <div class="p-2 px-3 row w-75"><div class="col-6">项目编号:<%- p.code %></div><div class="col-6"> 用户账号:<%- p.userMsg.account %><%- p.userMsg.role ? '-'+ p.userMsg.role : '' %></div></div>
+                <div class=""><a href="/wx/url2web?project=<%- p.code %>&url=<%- redirect_url %>&unionid=<%- unionid %>" class="btn btn-block btn-link">进入项目</a></div>
+            </div>
+        </div>
+        <% } %>
+        <% } else { %>
+        <p class="text-muted">当前微信未绑定过任何计量项目,请扫码或搜索 关注“纵横造价”服务号绑定项目</p>
+        <div class="w-50"><img class="w-100" src="/public/images/wechat.png"></div>
+        <% } %>
+    </div>
+    <% } %>
+</div>
+<!-- JS. -->
+<div class="toast" style="text-align: center">
+    <i class="icon fa"></i>
+    <span class="message"></span>
+</div>
+<!-- JS. -->
+<script src="/public/js/jquery/jquery-3.2.1.min.js"></script>
+<script src="/public/js/popper/popper.min.js"></script>
+<script src="/public/js/bootstrap/bootstrap.min.js"></script>
+<script src="/public/js/wap/global.js"></script>
+</body>
+</html>

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

@@ -59,7 +59,7 @@
             </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 %>">
                 <button class="btn btn-primary btn-sm" type="submit">确认上报</button>
             </form>
         </div>
@@ -242,7 +242,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 +437,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 +672,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 - 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>

+ 67 - 23
app/view/report/index.ejs

@@ -65,6 +65,25 @@
                                     导出报表
                                 </div>
                             </div>
+                            <div class="panel" <% if (pageShow === null || parseInt(pageShow.showArchive) === 0 || isNaN(parseInt(pageShow.showArchive))) { %> style="display:none" <% } %>>
+                                <div class="panel-body">
+                                    <div class="btn-group" role="group">
+                                        <button type="button" class="btn btn-outline-primary btn-sm" data-toggle="modal" data-target="#guidang"><i class="fa fa-archive"></i> 归档报表</button>
+                                        <div class="btn-group" role="group">
+                                            <button id="btnGroupDrop1" type="button" class="btn btn-success btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                                                已归档
+                                            </button>
+                                            <div class="dropdown-menu" aria-labelledby="btnGroupDrop1" style="min-width:112px">
+                                                <a class="dropdown-item" href="#">#1 2021-03-01</a>
+                                                <a class="dropdown-item" href="#">#2 2021-02-28</a>
+                                            </div>
+                                        </div>
+                                    </div>
+                                </div>
+                                <div class="panel-foot text-muted">
+                                    报表归档
+                                </div>
+                            </div>
                             <div class="panel">
                                 <div class="panel-body">
                                     <div class="btn-group" role="group" aria-label="Button group with nested dropdown">
@@ -272,17 +291,20 @@
 
 <script type="text/javascript">
     let TOP_TREE_NODES = <%- rpt_tpl_data %>;
-    const PAGE_SHOW = {closeWatermark: 0, closeExportPdf: 0, closeExportExcel: 0};
+    const PAGE_SHOW = {closeWatermark: 0, closeExportPdf: 0, closeExportExcel: 0, showArchive: 0};
     <% if (pageShow !== null) { %>
-    <% if (parseInt(pageShow.closeWatermark) === 1) { %>
-    PAGE_SHOW['closeWatermark'] = 1;
-    <% } %>
-    <% if (parseInt(pageShow.closeExportPdf) === 1) { %>
-    PAGE_SHOW['closeExportPdf'] = 1;
-    <% } %>
-    <% if (parseInt(pageShow.closeExportExcel) === 1) { %>
-    PAGE_SHOW['closeExportExcel'] = 1;
-    <% } %>
+        <% if (parseInt(pageShow.closeWatermark) === 1) { %>
+            PAGE_SHOW['closeWatermark'] = 1;
+        <% } %>
+        <% if (parseInt(pageShow.closeExportPdf) === 1) { %>
+            PAGE_SHOW['closeExportPdf'] = 1;
+        <% } %>
+        <% if (parseInt(pageShow.closeExportExcel) === 1) { %>
+            PAGE_SHOW['closeExportExcel'] = 1;
+        <% } %>
+        <% if (parseInt(pageShow.showArchive) === 1) { %>
+            PAGE_SHOW['showArchive'] = 1;
+        <% } %>
     <% } %>
 
 //    PAGE_SHOW['closeWatermark'] = 0; //测试用,check in 前要屏蔽
@@ -399,26 +421,48 @@
     }
 
     function filterUnchkTplTreeNode(topNode, srcData) {
-        for (let rIdx = topNode.items.length - 1; rIdx >= 0; rIdx--) {
-            if (srcData.indexOf(topNode.items[rIdx].name) < 0) {
-                //topNode.items.splice(rIdx, 1);
-                //支持第二层判断
-                //备注:如果选择了父项,那不用再去判断子项
-                if (topNode.items[rIdx].items && topNode.items[rIdx].items.length > 0) {
-                    for (let rIdx2 = topNode.items[rIdx].items.length - 1; rIdx2 >= 0; rIdx2--) {
-                        let tName = topNode.items[rIdx].name + FOLDER_SEPERATER + topNode.items[rIdx].items[rIdx2].name;
-                        if (srcData.indexOf(tName) < 0) {
-                            topNode.items[rIdx].items.splice(rIdx2, 1);
+        const _chkAndSpliceItem = function(pNode, pStr) {
+            let rst = false;
+            if (srcData.indexOf(pStr + pNode.name) < 0) {
+                if (pNode.items && pNode.items.length > 0) {
+                    for (let subIdx = pNode.items.length - 1; subIdx >= 0; subIdx--) {
+                        if (!_chkAndSpliceItem(pNode.items[subIdx], pStr + pNode.name + FOLDER_SEPERATER)) {
+                            pNode.items.splice(subIdx, 1);
+                        } else {
+                            rst = true;
                         }
                     }
-                } else {
-                    topNode.items.splice(rIdx, 1);
                 }
+            } else {
+                rst = true;
             }
-            if (!topNode.items[rIdx].hasOwnProperty('items') || topNode.items[rIdx].items.length === 0) {
+            return rst;
+        };
+        for (let rIdx = topNode.items.length - 1; rIdx >= 0; rIdx--) {
+            if (!_chkAndSpliceItem(topNode.items[rIdx], '')) {
                 topNode.items.splice(rIdx, 1);
             }
         }
+//        for (let rIdx = topNode.items.length - 1; rIdx >= 0; rIdx--) {
+//            if (srcData.indexOf(topNode.items[rIdx].name) < 0) {
+//                //topNode.items.splice(rIdx, 1);
+//                //支持第二层判断
+//                //备注:如果选择了父项,那不用再去判断子项
+//                if (topNode.items[rIdx].items && topNode.items[rIdx].items.length > 0) {
+//                    for (let rIdx2 = topNode.items[rIdx].items.length - 1; rIdx2 >= 0; rIdx2--) {
+//                        let tName = topNode.items[rIdx].name + FOLDER_SEPERATER + topNode.items[rIdx].items[rIdx2].name;
+//                        if (srcData.indexOf(tName) < 0) {
+//                            topNode.items[rIdx].items.splice(rIdx2, 1);
+//                        }
+//                    }
+//                } else {
+//                    topNode.items.splice(rIdx, 1);
+//                }
+//            }
+//            if (!topNode.items[rIdx].hasOwnProperty('items') || topNode.items[rIdx].items.length === 0) {
+//                topNode.items.splice(rIdx, 1);
+//            }
+//        }
     }
 
     function buildTplTree() {

+ 8 - 6
app/view/report/rpt_all_popup.ejs

@@ -673,7 +673,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;
@@ -760,7 +760,7 @@
             }
             return rst;
         };
-        let _pushRptLine = function (parentItem, rptItem, level, needChk, parentNodeIdStr, thisItemSeq) {
+        let _pushRptLine = function (parentItem, rptItem, level, needChk, parentNodeIdStr, thisItemSeq, pHiddenVal) {
             if (rptItem.nodeType === 1) {
                 let amt = _countAvailableTpls(rptItem);
                 if (amt > 0) {
@@ -772,7 +772,7 @@
                         padding_leftStr = 'padding-left: ' + rem + 'rem!important'; //不受层数限制
                     }
                     if (needChk) {
-                        let chkName = parentItem.name + FOLDER_SEPERATER + rptItem.name;
+                        let chkName = pHiddenVal + parentItem.name + FOLDER_SEPERATER + rptItem.name;
                         let checkedStr = (checkingArr.indexOf(chkName) >= 0) ? ' checked' : '';
                         let sIdStr = parentNodeIdStr + '_sub_' + thisItemSeq;
                         // tbDom.append('<tr><td class="' + classStr + '">' + rptItem.name + '</td><td>' + amt + '</td><td><input id="' + sIdStr + '" onchange="changeFolder(this, ' + isCommonStr + ', \'' + parentNodeIdStr + '\' )" hiddenval="' + chkName + '" type="checkbox"' + checkedStr + '></td></tr>');
@@ -782,8 +782,10 @@
                         tbDom.append('<tr><td style="' + padding_leftStr + '">' + rptItem.name + '</td><td>' + amt + '</td><td></td></tr>');
                     }
                     if (rptItem.items && rptItem.items.length > 0) {
+                        let subDtlSeq = 0;
                         for (const subItem of rptItem.items) {
-                            _pushRptLine(rptItem, subItem, level + 1, true, '');
+                            _pushRptLine(rptItem, subItem, level + 1, true, '', subDtlSeq, parentItem.name + FOLDER_SEPERATER);
+                            subDtlSeq++;
                         }
                     }
                 }
@@ -802,7 +804,7 @@
                 if (topItem.items && topItem.items.length > 0) {
                     let subSeq = 0;
                     for (const subItem of topItem.items) {
-                        _pushRptLine(topItem, subItem, 1, true, pIdStr, subSeq);
+                        _pushRptLine(topItem, subItem, 1, true, pIdStr, subSeq, '');
                     }
                     subSeq++;
                 }
@@ -814,7 +816,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) { %>

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

@@ -59,7 +59,7 @@
                 </div>
                 <form class="modal-footer" method="post" action="<%- preUrl %>/audit/start" name="stage-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>
@@ -246,7 +246,7 @@
                     </div>
                 </div>
                 <form class="modal-footer" method="post" action="<%- preUrl %>/audit/start" name="stage-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(ctx.stage.status === auditConst.status.checkNo && ctx.session.sessionUser.accountId === ctx.stage.user_id) { %>
                     <button class="btn btn-primary btn-sm sp-list-item" type="submit">确认上报</button>
@@ -442,7 +442,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>
@@ -673,7 +673,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>
@@ -782,7 +782,7 @@
             </div>
             <div class="modal-footer">
                 <input type="hidden" name="stage_id" value="<%= ctx.stage.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/stage/manager_modal.ejs

@@ -30,7 +30,7 @@
                 <p class="mb-2"><input type="text" name="confirm" class="form-control form-control-sm" placeholder="输入文本,确认删除"></p>
             </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-danger">确认删除</button>
             </div>
@@ -71,7 +71,7 @@
             <div class="modal-footer">
                 <input type="hidden" name="stage_id" value="<%= lastStage.id %>">
                 <input type="hidden" name="stage_order" value="<%- ctx.stage.order %>">
-                <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>

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

@@ -357,6 +357,28 @@
                                             <input type="date" class="form-control" value="" id="bid-start-date">
                                         </div>
                                     </div>
+                                    <div class="col-12 mb-2">
+                                        <div class="input-group input-group-sm">
+                                            <div class="input-group-prepend">
+                                                <span class="input-group-text" >招标方式</span>
+                                            </div>
+                                            <select class="form-control" id="bid-type">
+                                                <option>公开招标</option>
+                                                <option>邀请招标</option>
+                                            </select>
+                                        </div>
+                                    </div>
+                                    <div class="col-12 mb-2">
+                                        <div class="input-group input-group-sm">
+                                            <div class="input-group-prepend">
+                                                <span class="input-group-text" style="width:90px">合同计价方式</span>
+                                            </div>
+                                            <select class="form-control" id="deal-calc-type">
+                                                <option>总价合同</option>
+                                                <option>单价合同</option>
+                                            </select>
+                                        </div>
+                                    </div>
                                 </div>
                             </div>
                         </div>
@@ -839,6 +861,8 @@
         $('#control-price').val(property.bid_info.controlPrice);
         $('#bid-price').val(property.bid_info.bidPrice);
         $('#bid-start-date').val(property.bid_info.bidStartDate);
+        $('#bid-type').find("option:contains('" + property.bid_info.bidType + "')").attr("selected",true);
+        $('#deal-calc-type').find("option:contains('" + property.bid_info.dealCalcType + "')").attr("selected",true);
     }
 
     $('#bd-set-1').on('show.bs.modal', function () {
@@ -898,6 +922,8 @@
                 controlPrice: _.toNumber($('#control-price').val()),
                 bidPrice: _.toNumber($('#bid-price').val()),
                 bidStartDate: $('#bid-start-date').val(),
+                bidType: $('#bid-type').find("option:selected").text(),
+                dealCalcType: $('#deal-calc-type').find("option:selected").text(),
             }
         };
         const tenderId = window.location.pathname.split('/')[2];

+ 2 - 2
app/view/tender/shenpi_modal.ejs

@@ -98,7 +98,7 @@
                 <div class="row">
                     <div class="col-6">
                         <% const yb = ctx.helper._.find(accountList, { id: ctx.tender.data.user_id }) %>
-                        <div class="modal-height-300">
+                        <div class="modal-height-500">
                             <table class="table table-hover table-bordered">
                                 <thead>
                                 <tr><th colspan="3" class="text-center" id="stage_audit"><%- yb.name %>(原报)</th></tr>
@@ -120,7 +120,7 @@
                                 <% } %>
                             </select>
                         </div>
-                        <div class="modal-height-300" style="overflow: auto;" id="ledger-spread">
+                        <div class="modal-height-500" style="overflow: auto;" id="ledger-spread">
                         </div>
                     </div>
                 </div>

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

@@ -11,6 +11,12 @@
             </ul>
         </div>
         <div class="nav-box">
+            <ul class="nav-list list-unstyled">
+                <% const curUrl = `/tender/${ctx.tender.id}/advance` %>
+                <li <% if (ctx.url.indexOf(curUrl) !== -1) { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/advance"><i class="fa fa-handshake-o"></i> <span>预付款</span></a></li>
+            </ul>
+        </div>
+        <div class="nav-box">
             <h3><i class="fa fa-list-alt"></i> 0号台账</h3>
             <ul class="nav-list list-unstyled sub-list">
                 <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/ledger') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/ledger"><span>台账分解</span></a></li>

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

@@ -51,7 +51,7 @@
                     </div>
                     <div class="form-group mb-3">
                         <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">

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


Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików