Browse Source

协审功能

laiguoran 3 years ago
parent
commit
3041767bb9

+ 87 - 11
app/controller/change_controller.js

@@ -2007,6 +2007,7 @@ module.exports = app => {
             if (ctx.change.status === auditConst.status.uncheck || ctx.change.status === auditConst.status.back) {
                 ctx.change.auditorList = await ctx.service.changeProjectAudit.getAuditors(ctx.change.id, ctx.change.times);
             }
+            ctx.change.xsAuditors = await ctx.service.changeProjectXsAudit.getAuditList(ctx.change.id);
         }
 
         async projectInformation(ctx) {
@@ -2026,19 +2027,19 @@ module.exports = app => {
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.change.project_information),
                     preUrl: '/tender/' + ctx.tender.id + '/change/project/' + ctx.change.id + '/information',
                 };
-                if ((ctx.change.status === audit.changeProject.status.uncheck || ctx.change.status === audit.changeProject.status.back) && (ctx.session.sessionUser.accountId === ctx.change.uid || ctx.tender.isTourist)) {
+                // if ((ctx.change.status === audit.changeProject.status.uncheck || ctx.change.status === audit.changeProject.status.back) && (ctx.session.sessionUser.accountId === ctx.change.uid || ctx.tender.isTourist)) {
                     // data.accountGroup = accountGroup;
                     // 获取所有项目参与者
-                    const accountList = await ctx.service.projectAccount.getAllDataByCondition({
-                        where: { project_id: ctx.session.sessionProject.id, enable: 1 },
-                        columns: ['id', 'name', 'company', 'role', 'enable', 'is_admin', 'account_group', 'mobile'],
-                    });
-                    renderData.accountList = accountList;
-                    renderData.accountGroup = accountGroup.map((item, idx) => {
-                        const groupList = accountList.filter(item => item.account_group === idx);
-                        return { groupName: item, groupList };
-                    });
-                }
+                const accountList = await ctx.service.projectAccount.getAllDataByCondition({
+                    where: { project_id: ctx.session.sessionProject.id, enable: 1 },
+                    columns: ['id', 'name', 'company', 'role', 'enable', 'is_admin', 'account_group', 'mobile'],
+                });
+                renderData.accountList = accountList;
+                renderData.accountGroup = accountGroup.map((item, idx) => {
+                    const groupList = accountList.filter(item => item.account_group === idx);
+                    return { groupName: item, groupList };
+                });
+                // }
                 await this.layout('change/project_information.ejs', renderData, 'change/project_information_modal.ejs');
             } catch (err) {
                 this.log(err);
@@ -2067,6 +2068,12 @@ module.exports = app => {
                 if (ctx.change.status === auditConst.status.checking || ctx.change.status === auditConst.status.checked) {
                     throw '当前不允许添加审核人';
                 }
+                // 判断是否是协审人,是则无法添加到审批人中
+                const xsAuditorList = await ctx.service.changeProjectXsAudit.getAuditList(ctx.change.id);
+                const xsAidList = this.app._.map(xsAuditorList, 'aid');
+                if (this.app._.indexOf(xsAidList, id) !== -1) {
+                    throw '该用户已添加到协审人列表中,请删除该协审人再添加';
+                }
 
                 ctx.change.auditorList = await ctx.service.changeProjectAudit.getAuditors(ctx.change.id, ctx.change.times);
                 // 检查审核人是否已存在
@@ -2115,6 +2122,75 @@ module.exports = app => {
         }
 
         /**
+         * 添加协审人
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async addProjectXsAudit(ctx) {
+            try {
+                const auditConst = audit.changeProject;
+                const data = JSON.parse(ctx.request.body.data);
+                const id = this.app._.toInteger(data.auditorId);
+                if (isNaN(id) || id <= 0) {
+                    throw '参数错误';
+                }
+                const times = ctx.change.status === auditConst.status.back ? ctx.change.times - 1 : ctx.change.times;
+                const spAuditors = await ctx.service.changeProjectAudit.getAuditorsWithOwner(ctx.change.id, times);
+                const aidLists = this.app._.map(spAuditors, 'aid');
+                // 检查权限等
+                if (this.app._.indexOf(aidLists, ctx.session.sessionUser.accountId) === -1) {
+                    throw '您无权添加协审人';
+                }
+                // 如果已经是审批人则无法添加此人为协审
+                if (this.app._.indexOf(aidLists, id) !== -1) {
+                    throw '该用户为审批人或原报,无需添加至协审人';
+                }
+
+                const auditorList = await ctx.service.changeProjectXsAudit.getAuditList(ctx.change.id);
+                // 检查审核人是否已存在
+                const exist = this.app._.find(auditorList, { aid: id });
+                if (exist) {
+                    throw '该协审人已存在,请勿重复添加';
+                }
+                const result = await ctx.service.changeProjectXsAudit.addAuditor(ctx.change.id, id);
+                if (!result) {
+                    throw '添加协审人失败';
+                }
+
+                const auditors = await ctx.service.changeProjectXsAudit.getOneAudit(ctx.change.id, id);
+                ctx.body = { err: 0, msg: '', data: auditors };
+            } catch (err) {
+                this.log(err);
+                ctx.body = { err: 1, msg: err.toString(), data: null };
+            }
+        }
+
+        /**
+         * 移除协审人
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async deleteProjectXsAudit(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                const id = data.auditorId instanceof Number ? data.auditorId : this.app._.toNumber(data.auditorId);
+                if (isNaN(id) || id <= 0) {
+                    throw '参数错误';
+                }
+
+                const result = await ctx.service.changeProjectXsAudit.deleteAuditor(ctx.change.id, id);
+                if (!result) {
+                    throw '移除协审人失败';
+                }
+
+                const auditors = await ctx.service.changeProjectXsAudit.getAuditList(ctx.change.id);
+                ctx.body = { err: 0, msg: '', data: auditors };
+            } catch (err) {
+                ctx.body = { err: 1, msg: err.toString(), data: null };
+            }
+        }
+
+        /**
          * 上传附件
          * @param {*} ctx 上下文
          */

+ 3 - 1
app/middleware/change_project_check.js

@@ -34,12 +34,14 @@ module.exports = options => {
             // 读取原报、审核人数据
             change.auditors = yield this.service.changeProjectAudit.getAuditors(change.id, change.times);
             change.curAuditor = yield this.service.changeProjectAudit.getCurAuditor(change.id, change.times);
+            change.xsAuditors = yield this.service.changeProjectXsAudit.getAuditList(change.id);
 
             if (!change) throw '变更令数据有误';
             // 权限相关
             // todo 校验权限 (标段参与人、分享)
             const accountId = this.session.sessionUser.accountId,
                 auditorIds = _.map(change.auditors, 'aid'),
+                xsAuditorIds = _.map(change.xsAuditors, 'aid'),
                 shareIds = [];
             if (accountId === change.uid) { // 原报
                 // if (change.curAuditor) {
@@ -66,7 +68,7 @@ module.exports = options => {
                     change.curOrder = change.curAuditor.order;
                 }
                 change.filePermission = this.tender.touristPermission.file || auditorIds.indexOf(accountId) !== -1;
-            } else if (auditorIds.indexOf(accountId) !== -1) { // 审批人
+            } else if (auditorIds.indexOf(accountId) !== -1 || xsAuditorIds.indexOf(accountId) !== -1) { // 审批人或者协审人
                 if (change.status === status.uncheck) {
                     throw '您无权查看该数据';
                 }

+ 3 - 1
app/middleware/tender_check.js

@@ -65,6 +65,8 @@ module.exports = options => {
             const materialAuditorsId = this.helper._.map(materialAuditors, 'aid');
             const changeProjectAuditors = this.session.sessionProject.page_show.openChangeProject ? yield this.service.changeProjectAudit.getAllAuditors(tender.id) : [];
             const changeProjectAuditorsId = this.helper._.map(changeProjectAuditors, 'aid');
+            const changeProjectXsAuditors = this.session.sessionProject.page_show.openChangeProject ? yield this.service.changeProjectXsAudit.getAllAuditors(tender.id) : [];
+            const changeProjectXsAuditorsId = this.helper._.map(changeProjectXsAuditors, 'aid');
             const changeApplyAuditors = this.session.sessionProject.page_show.openChangeApply ? yield this.service.changeApplyAudit.getAllAuditors(tender.id) : [];
             const changeApplyAuditorsId = this.helper._.map(changeApplyAuditors, 'aid');
             const tenderPermission = this.session.sessionUser.permission ? this.session.sessionUser.permission.tender : null;
@@ -77,7 +79,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 &&
-                changeProjectAuditorsId.indexOf(accountId) === -1 && changeApplyAuditorsId.indexOf(accountId) === -1 &&
+                changeProjectAuditorsId.indexOf(accountId) === -1 && changeProjectXsAuditorsId.indexOf(accountId) === -1 && changeApplyAuditorsId.indexOf(accountId) === -1 &&
                 advanceAuditorsId.indexOf(accountId) === -1 && !this.session.sessionUser.is_admin && !isTenderTourist) {
                 throw '您无权查看该项目';
             }

+ 106 - 6
app/public/js/change_project_audit.js

@@ -11,6 +11,8 @@
 $(document).ready(function () {
     let timer = null
     let oldSearchVal = null
+    let timer2 = null
+    let oldSearchVal2 = null
 
     $('#gr-search').bind('input propertychange', function(e) {
         oldSearchVal = e.target.value
@@ -26,8 +28,8 @@ $(document).ready(function () {
                         <span class="text-muted">${item.role || ''}</span>
                     </dd>`
                 })
-                $('.book-list').empty()
-                $('.book-list').append(html)
+                $('.search-user-list').empty()
+                $('.search-user-list').append(html)
             } else {
                 if (!$('.acc-btn').length) {
                     accountGroup.forEach((group, idx) => {
@@ -46,15 +48,15 @@ $(document).ready(function () {
                         });
                         html += '</div>'
                     })
-                    $('.book-list').empty()
-                    $('.book-list').append(html)
+                    $('.search-user-list').empty()
+                    $('.search-user-list').append(html)
                 }
             }
         }, 400);
     })
 
     // 添加审批流程按钮逻辑
-    $('.book-list').on('click', 'dt', function () {
+    $('.search-user-list').on('click', 'dt', function () {
         const idx = $(this).find('.acc-btn').attr('data-groupid')
         const type = $(this).find('.acc-btn').attr('data-type')
         if (type === 'hide') {
@@ -73,7 +75,7 @@ $(document).ready(function () {
     })
 
     // 添加到审批流程中
-    $('dl').on('click', 'dd', function () {
+    $('.search-user-list').on('click', 'dd', function () {
         const id = parseInt($(this).data('id'));
         if (id) {
             postData(preUrl + '/audit/add', { auditorId: id }, (datas) => {
@@ -161,6 +163,104 @@ $(document).ready(function () {
             }
         });
     });
+    // 协审人搜索
+    $('#gr-search2').bind('input propertychange', function(e) {
+        oldSearchVal2 = e.target.value;
+        timer2 && clearTimeout(timer2);
+        timer2 = setTimeout(() => {
+            const newVal = $('#gr-search2').val();
+            let html = '';
+            if (newVal && newVal === oldSearchVal2) {
+                accountList.filter(item => item && (item.name.indexOf(newVal) !== -1 || (item.mobile && item.mobile.indexOf(newVal) !== -1))).forEach(item => {
+                    html += `<dd class="border-bottom p-2 mb-0 " data-id="${item.id}" >
+                        <p class="mb-0 d-flex"><span class="text-primary">${item.name}</span><span
+                                class="ml-auto">${item.mobile || ''}</span></p>
+                        <span class="text-muted">${item.role || ''}</span>
+                    </dd>`
+                })
+                $('.search-user-list2').empty();
+                $('.search-user-list2').append(html);
+            } else {
+                if (!$('.acc-btn').length) {
+                    accountGroup.forEach((group, idx) => {
+                        if (!group) return
+                        html += `<dt><a href="javascript: void(0);" class="acc-btn" data-groupid="${idx}" data-type="hide"><i class="fa fa-plus-square"></i>
+                        </a> ${group.groupName}</dt>
+                        <div class="dd-content" data-toggleid="${idx}">`
+                        group.groupList.forEach(item => {
+                            html += `<dd class="border-bottom p-2 mb-0 " data-id="${item.id}" >
+                                <p class="mb-0 d-flex"><span class="text-primary">${item.name}</span><span
+                                        class="ml-auto">${item.mobile || ''}</span></p>
+                                <span class="text-muted">${item.role || ''}</span>
+                            </dd>`
+                        });
+                        html += '</div>'
+                    })
+                    $('.search-user-list2').empty();
+                    $('.search-user-list2').append(html);
+                }
+            }
+        }, 400);
+    })
+
+    // 添加审批流程按钮逻辑
+    $('.search-user-list2').on('click', 'dt', function () {
+        const idx = $(this).find('.acc-btn').attr('data-groupid')
+        const type = $(this).find('.acc-btn').attr('data-type')
+        if (type === 'hide') {
+            $(this).parent().find(`div[data-toggleid="${idx}"]`).show(() => {
+                $(this).children().find('i').removeClass('fa-plus-square').addClass('fa-minus-square-o')
+                $(this).find('.acc-btn').attr('data-type', 'show')
+
+            })
+        } else {
+            $(this).parent().find(`div[data-toggleid="${idx}"]`).hide(() => {
+                $(this).children().find('i').removeClass('fa-minus-square-o').addClass('fa-plus-square')
+                $(this).find('.acc-btn').attr('data-type', 'hide')
+            })
+        }
+        return false
+    });
+
+    // 添加到审批流程中
+    $('.search-user-list2').on('click', 'dd', function () {
+        const id = parseInt($(this).data('id'));
+        if (id) {
+            console.log(id);
+            postData(preUrl + '/xsaudit/add', { auditorId: id }, (data) => {
+                const html = [];
+                html.push('<span class="d-inline-block">\n' +
+                    '                    <span class="badge badge-light">\n' +
+                    '                      ' + data.name + '\n' +
+                    '                        <span class="dropdown">\n' +
+                    '                        <a href="javascript:void(0)" class="btn-sm text-danger px-1" title="移除" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-remove"></i></a>\n' +
+                    '                        <div class="dropdown-menu">\n' +
+                    '                          <a class="dropdown-item" href="javascript:void(0);">确认移除审批人?</a>\n' +
+                    '                          <div class="dropdown-divider"></div>\n' +
+                    '                          <div class="px-2 py-1 text-center">\n' +
+                    '                            <button class="btn btn-sm btn-danger" aid="'+ data.aid +'">移除</button>\n' +
+                    '                            <button class="btn btn-sm btn-secondary">取消</button>\n' +
+                    '                          </div>\n' +
+                    '                        </div>\n' +
+                    '                      </span>\n' +
+                    '                    </span>\n' +
+                    '                  </span> ');
+                $('#xs-list').append(html.join(''));
+            });
+        }
+    });
+
+    // 删除审批人
+    $('body').on('click', '#xs-list .btn-danger', function () {
+        const li = $(this).parents('.d-inline-block');
+        const data = {
+            auditorId: parseInt($(this).attr('aid')),
+        };
+        postData(preUrl +  '/xsaudit/delete', data, (result) => {
+            li.remove();
+        });
+    });
+
     // 退回选择修改审批人流程
     $('#hideSp').click(function () {
         $('#sp-list').modal('hide');

+ 2 - 0
app/router.js

@@ -466,6 +466,8 @@ module.exports = app => {
     app.post('/tender/:id/change/project/:cpid/information/audit/delete', sessionAuth, tenderCheck, uncheckTenderCheck, changeProjectCheck, 'changeController.deleteProjectAudit');
     app.post('/tender/:id/change/project/:cpid/information/audit/start', sessionAuth, tenderCheck, uncheckTenderCheck, changeProjectCheck, 'changeController.startProjectAudit');
     app.post('/tender/:id/change/project/:cpid/information/audit/check', sessionAuth, tenderCheck, uncheckTenderCheck, changeProjectCheck, 'changeController.checkProjectAudit');
+    app.post('/tender/:id/change/project/:cpid/information/xsaudit/add', sessionAuth, tenderCheck, uncheckTenderCheck, changeProjectCheck, 'changeController.addProjectXsAudit');
+    app.post('/tender/:id/change/project/:cpid/information/xsaudit/delete', sessionAuth, tenderCheck, uncheckTenderCheck, changeProjectCheck, 'changeController.deleteProjectXsAudit');
     // 变更申请
     app.get('/tender/:id/change/apply', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.apply');
     app.get('/tender/:id/change/apply/status/:status', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.applyStatus');

+ 4 - 2
app/service/change_apply.js

@@ -102,7 +102,7 @@ module.exports = app => {
                     case 0: // 包含你的所有变更立项
                         sql =
                             'SELECT a.*, p.name as account_name FROM ?? AS a LEFT JOIN ?? AS p On a.notice_uid = p.id WHERE a.tid = ? AND ' +
-                            '(a.uid = ? OR (a.status != ? AND a.id IN (SELECT b.caid FROM ?? AS b WHERE b.aid = ? AND a.times = b.times GROUP BY b.caid)))';
+                            '(a.uid = ? OR (a.status != ? AND a.id IN (SELECT b.caid FROM ?? AS b WHERE b.aid = ? AND a.times = b.times GROUP BY b.caid)) OR a.status = ?)';
                         sqlParam = [
                             this.tableName,
                             this.ctx.service.projectAccount.tableName,
@@ -111,6 +111,7 @@ module.exports = app => {
                             audit.status.uncheck,
                             this.ctx.service.changeApplyAudit.tableName,
                             this.ctx.session.sessionUser.accountId,
+                            audit.status.checked,
                         ];
                         break;
                     case 1: // 待处理(你的)
@@ -183,7 +184,7 @@ module.exports = app => {
                 case 0: // 包含你的所有变更令
                     const sql =
                         'SELECT count(*) AS count FROM ?? AS a WHERE a.tid = ? AND ' +
-                        '(a.uid = ? OR (a.status != ? AND a.id IN (SELECT b.caid FROM ?? AS b WHERE b.aid = ? AND a.times = b.times GROUP BY b.caid)))';
+                        '(a.uid = ? OR (a.status != ? AND a.id IN (SELECT b.caid FROM ?? AS b WHERE b.aid = ? AND a.times = b.times GROUP BY b.caid)) OR a.status != ?)';
                     const sqlParam = [
                         this.tableName,
                         tenderId,
@@ -191,6 +192,7 @@ module.exports = app => {
                         audit.status.uncheck,
                         this.ctx.service.changeApplyAudit.tableName,
                         this.ctx.session.sessionUser.accountId,
+                        audit.status.checked,
                     ];
                     const result = await this.db.query(sql, sqlParam);
                     return result[0].count;

+ 12 - 6
app/service/change_project.js

@@ -104,7 +104,7 @@ module.exports = app => {
                     case 0: // 包含你的所有变更立项
                         sql =
                             'SELECT a.*, p.name as account_name FROM ?? AS a LEFT JOIN ?? AS p On a.uid = p.id WHERE a.tid = ? AND ' +
-                            '(a.uid = ? OR (a.status != ? AND a.id IN (SELECT b.cpid FROM ?? AS b WHERE b.aid = ? AND a.times = b.times GROUP BY b.cpid)) OR a.status = ? )';
+                            '(a.uid = ? OR (a.status != ? AND (a.id IN (SELECT b.cpid FROM ?? AS b WHERE b.aid = ? AND a.times = b.times GROUP BY b.cpid) OR a.id IN (SELECT c.cpid FROM ?? AS c WHERE c.aid = ? AND c.tid = ?))) OR a.status = ? )';
                         sqlParam = [
                             this.tableName,
                             this.ctx.service.projectAccount.tableName,
@@ -113,6 +113,9 @@ module.exports = app => {
                             audit.status.uncheck,
                             this.ctx.service.changeProjectAudit.tableName,
                             this.ctx.session.sessionUser.accountId,
+                            this.ctx.service.changeProjectXsAudit.tableName,
+                            this.ctx.session.sessionUser.accountId,
+                            tenderId,
                             audit.status.checked,
                         ];
                         break;
@@ -139,8 +142,8 @@ module.exports = app => {
                     case 4: // 终止(所有的)
                         sql =
                             'SELECT a.*, p.name as account_name FROM ?? AS a LEFT JOIN ?? AS p On a.uid = p.id WHERE ' +
-                            'a.status = ? AND a.tid = ? AND (a.uid = ? OR a.id IN (SELECT b.cpid FROM ?? AS b WHERE b.aid = ? AND a.times = b.times GROUP BY b.cpid))';
-                        sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, status, tenderId, this.ctx.session.sessionUser.accountId, this.ctx.service.changeProjectAudit.tableName, this.ctx.session.sessionUser.accountId];
+                            'a.status = ? AND a.tid = ? AND (a.uid = ? OR a.id IN (SELECT b.cpid FROM ?? AS b WHERE b.aid = ? AND a.times = b.times GROUP BY b.cpid) OR a.id IN (SELECT c.cpid FROM ?? AS c WHERE c.aid = ? AND c.tid = ?))';
+                        sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, status, tenderId, this.ctx.session.sessionUser.accountId, this.ctx.service.changeProjectAudit.tableName, this.ctx.session.sessionUser.accountId, this.ctx.service.changeProjectXsAudit.tableName, this.ctx.session.sessionUser.accountId, tenderId];
                         break;
                     case 3: // 已完成(所有的)
                         sql = 'SELECT a.*, p.name as account_name FROM ?? AS a LEFT JOIN ?? AS p On a.uid = p.id WHERE a.status = ? AND a.tid = ?';
@@ -186,7 +189,7 @@ module.exports = app => {
                 case 0: // 包含你的所有变更令
                     const sql =
                         'SELECT count(*) AS count FROM ?? AS a WHERE a.tid = ? AND ' +
-                        '(a.uid = ? OR (a.status != ? AND a.id IN (SELECT b.cpid FROM ?? AS b WHERE b.aid = ? AND a.times = b.times GROUP BY b.cpid)) OR a.status = ? )';
+                        '(a.uid = ? OR (a.status != ? AND (a.id IN (SELECT b.cpid FROM ?? AS b WHERE b.aid = ? AND a.times = b.times GROUP BY b.cpid) OR a.id IN (SELECT c.cpid FROM ?? AS c WHERE c.aid = ? AND c.tid = ?))) OR a.status = ? )';
                     const sqlParam = [
                         this.tableName,
                         tenderId,
@@ -194,6 +197,9 @@ module.exports = app => {
                         audit.status.uncheck,
                         this.ctx.service.changeProjectAudit.tableName,
                         this.ctx.session.sessionUser.accountId,
+                        this.ctx.service.changeProjectXsAudit.tableName,
+                        this.ctx.session.sessionUser.accountId,
+                        tenderId,
                         audit.status.checked,
                     ];
                     const result = await this.db.query(sql, sqlParam);
@@ -227,8 +233,8 @@ module.exports = app => {
                 case 4: // 终止(所有的)
                     const sql3 =
                         'SELECT count(*) AS count FROM ?? AS a WHERE ' +
-                        'a.status = ? AND a.tid = ? AND (a.uid = ? OR a.id IN (SELECT b.cpid FROM ?? AS b WHERE b.aid = ? AND a.times = b.times GROUP BY b.cpid))';
-                    const sqlParam3 = [this.tableName, status, tenderId, this.ctx.session.sessionUser.accountId, this.ctx.service.changeProjectAudit.tableName, this.ctx.session.sessionUser.accountId];
+                        'a.status = ? AND a.tid = ? AND (a.uid = ? OR a.id IN (SELECT b.cpid FROM ?? AS b WHERE b.aid = ? AND a.times = b.times GROUP BY b.cpid) OR a.id IN (SELECT c.cpid FROM ?? AS c WHERE c.aid = ? AND c.tid = ?))';
+                    const sqlParam3 = [this.tableName, status, tenderId, this.ctx.session.sessionUser.accountId, this.ctx.service.changeProjectAudit.tableName, this.ctx.session.sessionUser.accountId, this.ctx.service.changeProjectXsAudit.tableName, this.ctx.session.sessionUser.accountId, tenderId];
                     const result3 = await this.db.query(sql3, sqlParam3);
                     return result3[0].count;
                 case 3: // 已完成(所有的)

+ 162 - 0
app/service/change_project_xs_audit.js

@@ -0,0 +1,162 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date 2018/8/14
+ * @version
+ */
+
+const auditConst = require('../const/audit').changeProject;
+const pushType = require('../const/audit').pushType;
+
+module.exports = app => {
+    class ChangeProjectXsAudit extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'change_project_xs_audit';
+        }
+
+        /**
+         * 获取协审人列表
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getAuditList(changeId) {
+            const sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`cpid`, la.`aid` ' +
+                '  FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id`' +
+                '  WHERE la.`cpid` = ? ORDER BY la.`id`';
+            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, changeId];
+            return await this.db.query(sql, sqlParam);
+        }
+
+        /**
+         * 获取单个协审人
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getOneAudit(cpid, aid) {
+            const sql = 'SELECT la.`aid`, pa.`name`, pa.`company`, pa.`role`, la.`cpid`, la.`aid` ' +
+                '  FROM ?? AS la Left Join ?? AS pa On la.`aid` = pa.`id`' +
+                '  WHERE la.`cpid` = ? AND la.`aid` = ?';
+            const sqlParam = [this.tableName, this.ctx.service.projectAccount.tableName, cpid, aid];
+            return await this.db.queryOne(sql, sqlParam);
+        }
+
+        /**
+         * 新增协审人
+         *
+         * @param {Number} cpId - 立项书id
+         * @param {Number} auditorId - 审核人id
+         * @param {Number} times - 第几次审批
+         * @return {Promise<number>}
+         */
+        async addAuditor(cpId, auditorId) {
+            const transaction = await this.db.beginTransaction();
+            let flag = false;
+            try {
+                const data = {
+                    tid: this.ctx.tender.id,
+                    cpid: cpId,
+                    aid: auditorId,
+                    for_aid: this.ctx.session.sessionUser.accountId,
+                    in_time: new Date(),
+                };
+                const result = await transaction.insert(this.tableName, data);
+                await transaction.commit();
+                flag = result.effectRows = 1;
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+            return flag;
+        }
+
+        /**
+         * 移除协审人
+         *
+         * @param {Number} cpId - 变更立项书id
+         * @param {Number} auditorId - 审核人id
+         * @param {Number} times - 第几次审批
+         * @return {Promise<boolean>}
+         */
+        async deleteAuditor(cpId, auditorId) {
+            const transaction = await this.db.beginTransaction();
+            try {
+                const condition = { cpid: cpId, aid: auditorId };
+                const auditor = await this.getDataByCondition(condition);
+                if (!auditor) {
+                    throw '该审核人不存在';
+                }
+                await transaction.delete(this.tableName, condition);
+                await transaction.commit();
+            } catch (err) {
+                await transaction.rollback();
+                throw err;
+            }
+            return true;
+        }
+
+        /**
+         * 获取审核人需要审核的期列表
+         *
+         * @param auditorId
+         * @return {Promise<*>}
+         */
+        async getAuditChangeProject(auditorId) {
+            const sql = 'SELECT ma.`aid`, ma.`times`, ma.`order`, ma.`begin_time`, ma.`end_time`, ma.`tid`, ma.`cpid`,' +
+                '    m.`status` As `mstatus`, m.`code` As `mcode`,' +
+                '    t.`name`, t.`project_id`, t.`type`, t.`user_id` ' +
+                '  FROM ?? AS ma, ?? AS m, ?? As t ' +
+                '  WHERE ((ma.`aid` = ? and ma.`status` = ?) OR (m.`uid` = ? and ma.`status` = ? and m.`status` = ? and ma.`times` = (m.`times`-1)))' +
+                '    and ma.`cpid` = m.`id` and ma.`tid` = t.`id` ORDER BY ma.`begin_time` DESC';
+            const sqlParam = [this.tableName, this.ctx.service.changeProject.tableName, this.ctx.service.tender.tableName, auditorId, auditConst.status.checking, auditorId, auditConst.status.back, auditConst.status.back];
+            return await this.db.query(sql, sqlParam);
+        }
+
+        /**
+         * 复制上一期的协审人列表给最新一期
+         *
+         * @param transaction - 新增一期的事务
+         * @param {Object} preMaterial - 上一期
+         * @param {Object} newaMaterial - 最新一期
+         * @return {Promise<*>}
+         */
+        async copyPreChangeProjectXsAuditors(transaction, preChange, newChange) {
+            const auditors = await this.getAuditList(preChange.id);
+            const newAuditors = [];
+            for (const a of auditors) {
+                const na = {
+                    tid: preChange.tid,
+                    cpid: newChange.id,
+                    aid: a.aid,
+                    for_aid: preChange.for_aid,
+                    in_time: new Date(),
+                };
+                newAuditors.push(na);
+            }
+            const result = await transaction.insert(this.tableName, newAuditors);
+            return result.affectedRows === auditors.length;
+        }
+
+        async getAllAuditors(tenderId) {
+            const sql = 'SELECT ma.aid, ma.tid FROM ' + this.tableName + ' ma' +
+                '  LEFT JOIN ' + this.ctx.service.tender.tableName + ' t On ma.tid = t.id' +
+                '  WHERE t.id = ?' +
+                '  GROUP BY  ma.aid';
+            const sqlParam = [tenderId];
+            return this.db.query(sql, sqlParam);
+        }
+    }
+
+    return ChangeProjectXsAudit;
+};

+ 6 - 3
app/service/tender.js

@@ -111,10 +111,13 @@ module.exports = app => {
                 // 根据用户权限查阅标段
                 // tender 163条数据,project_account 68条数据测试
                 // 查询两张表耗时0.003s,查询tender左连接project_account耗时0.002s
-                const changeProjectSql = this.ctx.session.sessionProject.openChangeProject ? '    OR (t.`ledger_status` = ' + auditConst.ledger.status.checked + ' AND ' +
+                const changeProjectSql = this.ctx.session.sessionProject.page_show.openChangeProject ? '    OR (t.`ledger_status` = ' + auditConst.ledger.status.checked + ' AND ' +
                     '        t.id IN ( SELECT cpa.`tid` FROM ' + this.ctx.service.changeProjectAudit.tableName + ' AS cpa WHERE cpa.`aid` = ' + session.sessionUser.accountId + ' GROUP BY cpa.`tid`))' : '';
-                const changeApplySql = this.ctx.session.sessionProject.openChangeApply ? '    OR (t.`ledger_status` = ' + auditConst.ledger.status.checked + ' AND ' +
+                const changeApplySql = this.ctx.session.sessionProject.page_show.openChangeApply ? '    OR (t.`ledger_status` = ' + auditConst.ledger.status.checked + ' AND ' +
                     '        t.id IN ( SELECT caa.`tid` FROM ' + this.ctx.service.changeApplyAudit.tableName + ' AS caa WHERE caa.`aid` = ' + session.sessionUser.accountId + ' GROUP BY caa.`tid`))' : '';
+                // 协审sql
+                const changeProjectXsSql = this.ctx.session.sessionProject.page_show.openChangeProject ? '    OR (t.`ledger_status` = ' + auditConst.ledger.status.checked + ' AND ' +
+                    '        t.id IN ( SELECT cpxa.`tid` FROM ' + this.ctx.service.changeProjectXsAudit.tableName + ' AS cpxa WHERE cpxa.`aid` = ' + session.sessionUser.accountId + ' GROUP BY cpxa.`tid`))' : '';
                 sql = 'SELECT t.`id`, t.`project_id`, t.`name`, t.`status`, t.`category`, t.`ledger_times`, t.`ledger_status`, t.`measure_type`, t.`user_id`, t.`create_time`, t.`total_price`, t.`deal_tp`,' +
                     '    pa.`name` As `user_name`, pa.`role` As `user_role`, pa.`company` As `user_company` ' +
                     // '  FROM ?? As t, ?? As pa ' +
@@ -143,7 +146,7 @@ module.exports = app => {
                     // 参与审批 预付款 的标段
                     '    OR (t.id IN ( SELECT ad.`tid` FROM ?? AS ad WHERE ad.`audit_id` = ? GROUP BY ad.`tid`))' +
                     // 参与审批 变更立项书及变更申请 的标段
-                    changeProjectSql + changeApplySql +
+                    changeProjectSql + changeApplySql + changeProjectXsSql +
                     // 游客权限的标段
                     '    OR (t.id IN ( SELECT tt.`tid` FROM ?? AS tt WHERE tt.`user_id` = ?))' +
                     // 未参与,但可见的标段

+ 1 - 0
app/view/change/project_information.ejs

@@ -12,6 +12,7 @@
                 </div>
             </div>
             <div class="ml-auto" id="sp-btn">
+                <a href="#xieshen" data-toggle="modal" data-target="#xieshen" class="btn btn-sm btn-primary mr-2">添加协审</a>
                 <% if (ctx.change.status === auditConst.status.uncheck) { %>
                     <% if (ctx.session.sessionUser.accountId === ctx.change.uid) { %>
                         <a id="sub-sp-btn" href="javascript: void(0);" data-toggle="modal" data-target="#sub-sp" class="btn btn-primary btn-sm">上报审批</a>

+ 67 - 1
app/view/change/project_information_modal.ejs

@@ -39,7 +39,7 @@
                                  style="width:220px">
                                 <div class="mb-2 p-2"><input class="form-control form-control-sm"
                                                              placeholder="姓名/手机 检索" id="gr-search" autocomplete="off"></div>
-                                <dl class="list-unstyled book-list">
+                                <dl class="list-unstyled book-list search-user-list">
                                     <% accountGroup.forEach((group, idx) => { %>
                                         <dt><a href="javascript: void(0);" class="acc-btn" data-groupid="<%- idx %>" data-type="hide"><i class="fa fa-plus-square"></i></a> <%- group.groupName %></dt>
                                         <div class="dd-content" data-toggleid="<%- idx %>">
@@ -710,6 +710,72 @@
         </div>
     <% } %>
 <% } %>
+<!--弹出添加协审-->
+<div class="modal fade" id="xieshen" data-backdrop="static">
+    <div class="modal-dialog" role="document">
+        <div class="modal-content">
+            <div class="modal-header">
+                <h5 class="modal-title">添加协审</h5>
+            </div>
+            <div class="modal-body modal-height">
+                <div class="mb-3">协审帐号可以查看本变更,上传附件。</div>
+                <div>
+                    <div class="dropdown mb-3">
+                        <button class="btn btn-outline-primary btn-sm dropdown-toggle" type="button"
+                                id="dropdownMenuButton2" data-toggle="dropdown" aria-haspopup="true"
+                                aria-expanded="false">
+                            选择协审人
+                        </button>
+                        <div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton2"
+                             style="width:220px">
+                            <div class="mb-2 p-2"><input class="form-control form-control-sm"
+                                                         placeholder="姓名/手机 检索" id="gr-search2" autocomplete="off"></div>
+                            <dl class="list-unstyled book-list search-user-list2">
+                                <% accountGroup.forEach((group, idx) => { %>
+                                    <dt><a href="javascript: void(0);" class="acc-btn" data-groupid="<%- idx %>" data-type="hide"><i class="fa fa-plus-square"></i></a> <%- group.groupName %></dt>
+                                    <div class="dd-content" data-toggleid="<%- idx %>">
+                                        <% group.groupList.forEach(item => { %>
+                                            <dd class="border-bottom p-2 mb-0 " data-id="<%- item.id %>" >
+                                                <p class="mb-0 d-flex"><span class="text-primary"><%- item.name %></span><span
+                                                            class="ml-auto"><%- item.mobile %></span></p>
+                                                <span class="text-muted"><%- item.role %></span>
+                                            </dd>
+                                        <% });%>
+                                    </div>
+                                <% }) %>
+                            </dl>
+                        </div>
+                    </div>
+                    <div class="modal-height-max100" id="xs-list">
+                        <% for (const xs of change.xsAuditors) { %>
+                  <span class="d-inline-block">
+                    <span class="badge badge-light">
+                      <%- xs.name %>
+                        <% if (ctx.helper._.indexOf(ctx.helper._.map(change.auditors2, 'aid'), ctx.session.sessionUser.accountId) !== -1) { %>
+                        <span class="dropdown">
+                        <a href="javascript:void(0)" class="btn-sm text-danger px-1" title="移除" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-remove"></i></a>
+                        <div class="dropdown-menu">
+                          <a class="dropdown-item" href="javascript:void(0);">确认移除审批人?</a>
+                          <div class="dropdown-divider"></div>
+                          <div class="px-2 py-1 text-center">
+                            <button class="btn btn-sm btn-danger" aid="<%- xs.aid %>">移除</button>
+                            <button class="btn btn-sm btn-secondary">取消</button>
+                          </div>
+                        </div>
+                      </span>
+                        <% } %>
+                    </span>
+                  </span>
+                            <% } %>
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-secondary btn-sm" data-dismiss="modal">关闭</button>
+            </div>
+        </div>
+    </div>
+</div>
 <% if (ctx.session.sessionUser.accountId === ctx.change.uid && (ctx.change.status === auditConst.status.uncheck || ctx.change.status === auditConst.status.back)) { %>
     <script>
         const accountGroup = JSON.parse(unescape('<%- escape(JSON.stringify(accountGroup)) %>'));