Explorar o código

多人协同功能实现

laiguoran %!s(int64=4) %!d(string=hai) anos
pai
achega
9dcacce530

+ 40 - 2
app/controller/stage_controller.js

@@ -193,6 +193,7 @@ module.exports = app => {
                     attData[index].in_time = moment(attData[index].in_time * 1000).format('YYYY-MM-DD');
                     attData[index].in_time = moment(attData[index].in_time * 1000).format('YYYY-MM-DD');
                 }
                 }
                 renderData.attData = attData;
                 renderData.attData = attData;
+                renderData.coopwd = (ctx.stage.status === auditConst.status.uncheck && ctx.session.sessionUser.accountId === ctx.stage.user_id) || (ctx.stage.status === auditConst.status.checking && ctx.stage.curAuditor && ctx.stage.curAuditor.aid === ctx.session.sessionUser.accountId);
                 await this.layout('stage/index.ejs', renderData, 'stage/modal.ejs');
                 await this.layout('stage/index.ejs', renderData, 'stage/modal.ejs');
             } catch (err) {
             } catch (err) {
                 this.log(err);
                 this.log(err);
@@ -329,8 +330,12 @@ module.exports = app => {
                             responseData.data.tags = await ctx.service.ledgerTag.getDatas(ctx.tender.id, ctx.stage.id);
                             responseData.data.tags = await ctx.service.ledgerTag.getDatas(ctx.tender.id, ctx.stage.id);
                             break;
                             break;
                         case 'cooperation':
                         case 'cooperation':
-                            responseData.data.cooperation = await this.ctx.service.ledgerCooperation.getValidData(
-                                ctx.tender.id, ctx.session.sessionUser.accountId);
+                            const uid = ctx.stage.curAuditor ? ctx.stage.curAuditor.aid : ctx.stage.status === auditConst.status.uncheck ? ctx.session.sessionUser.accountId : null;
+                            responseData.data.cooperation = uid !== null ? await ctx.service.ledgerCooperation.getValidData(
+                                ctx.tender.id, uid) : [];
+                            responseData.data.cooperationPwd = uid !== null ? await ctx.service.cooperationPwd.getValidData(ctx.tender.id, uid) : [];
+                            const stageTimes = (ctx.stage.status === auditConst.status.checkNo && ctx.stage.user_id !== ctx.session.sessionUser.accountId) ? ctx.stage.times - 1 : ctx.stage.times;
+                            responseData.data.cooperationConfirm = uid !== null ? await ctx.service.cooperationConfirm.getValidData(ctx.tender.id, ctx.stage.id, stageTimes, uid) : [];
                             break;
                             break;
                         case 'spec':
                         case 'spec':
                             const spec = {zlj: JSON.parse(JSON.stringify(stdConst.zlj)), jrg: stdConst.jrg};
                             const spec = {zlj: JSON.parse(JSON.stringify(stdConst.zlj)), jrg: stdConst.jrg};
@@ -1806,6 +1811,39 @@ module.exports = app => {
                 ctx.redirect(ctx.request.header.referer);
                 ctx.redirect(ctx.request.header.referer);
             }
             }
         }
         }
+
+        /**
+         * 删除本次审批 - 期审批管理页面
+         * @param ctx
+         * @return {Promise<void>}
+         */
+        async saveCooperationData(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                const responseData = { err: 0, msg: '', data: {} };
+                switch (data.type) {
+                    case 'save-confirm':
+                        await ctx.service.cooperationConfirm.save(data.postData);
+                        responseData.data.cooperationConfirm = await ctx.service.cooperationConfirm.getValidData(ctx.tender.id, ctx.stage.id, ctx.stage.times, ctx.session.sessionUser.accountId);
+                        break;
+                    case 'del-confirm':
+                        await ctx.service.cooperationConfirm.del(data.postData);
+                        responseData.data.cooperationConfirm = await ctx.service.cooperationConfirm.getValidData(ctx.tender.id, ctx.stage.id, ctx.stage.times, ctx.session.sessionUser.accountId);
+                        break;
+                    case 'save-pwd':
+                        const result = await ctx.service.cooperationPwd.save(data.postData);
+                        responseData.data.cooperationPwd = await ctx.service.cooperationPwd.getValidData(ctx.tender.id, ctx.session.sessionUser.accountId);
+                        break;
+                    default:
+                        throw '参数有误';
+                }
+
+                ctx.body = responseData;
+            } catch (err) {
+                this.log(err);
+                ctx.body = { err: 1, msg: err.toString(), data: null };
+            }
+        }
     }
     }
 
 
     return StageController;
     return StageController;

BIN=BIN
app/public/images/wechat.png


+ 43 - 1
app/public/js/path_tree.js

@@ -1181,6 +1181,48 @@ const createNewPathTree = function (type, setting) {
             this.loadingPwd = false;
             this.loadingPwd = false;
         }
         }
 
 
+        // 解锁相关
+        _loadOnlinePwd() {
+            const cacheArr = this.pwdList;
+            for (const ca of cacheArr) {
+                if (!ca) continue;
+                if (!ca.ledger_id || !ca.pwd) continue;
+
+                const p = this.pwd.find(x => {return x.ledger_id == ca.ledger_id});
+                if (p) p.check = p.pwd === ca.pwd;
+            }
+        }
+        // 确认相关
+        _loadOnlineConfirm() {
+            const cacheArr = this.confirmList;
+            for (const ca of cacheArr) {
+                if (!ca) continue;
+                if (!ca.ledger_id) continue;
+
+                const p = this.pwd.find(x => {return x.ledger_id == ca.ledger_id});
+                if (p) {
+                    p.confirm = true;
+                    p.confirm_time = ca.create_time;
+                }
+            }
+        }
+        loadOnlinePwd(data, pwdList, confirmList) {
+            this.loadingPwd = true;
+            try {
+                this.pwdList = pwdList;
+                this.confirmList = confirmList;
+                this.pwd = data;
+                this._loadOnlinePwd();
+                this._loadOnlineConfirm();
+                // 旧数据上传,新数据补齐
+                for (const p of this.pwd) {
+                    p.node = this.getItems(p.ledger_id);
+                    this.lockNode(p, !p.check);
+                }
+            } catch(err) {}
+            this.loadingPwd = false;
+        }
+
         getStageItems(id) {
         getStageItems(id) {
             return this.stageItems[itemsPre + id];
             return this.stageItems[itemsPre + id];
         }
         }
@@ -1369,7 +1411,7 @@ const createNewPathTree = function (type, setting) {
                 pn.lock = isLock;
                 pn.lock = isLock;
                 refresh.push(this.getNodeIndex(pn));
                 refresh.push(this.getNodeIndex(pn));
             }
             }
-            if (!this.loadingPwd) this._savePwdCache();
+            // if (!this.loadingPwd) this._savePwdCache();
             return refresh;
             return refresh;
         }
         }
     }
     }

+ 82 - 5
app/public/js/stage.js

@@ -309,15 +309,37 @@ $(document).ready(() => {
     };
     };
     const stagePos = new StagePosData(stagePosSetting);
     const stagePos = new StagePosData(stagePosSetting);
 
 
+    const setCooperationSelectHtml = function () {
+        const selectHtml = [];
+        selectHtml.push('<option>全部</option>');
+        const cooName = _.uniqWith(_.map(stageTree.pwd, 'company'));
+        for (const i of cooName) {
+            selectHtml.push('<option>', i, '</option>');
+        }
+        $('#cooperationSelect').html(selectHtml.join(''));
+    };
+
     const reloadCooperationHtml = function () {
     const reloadCooperationHtml = function () {
         const html = [];
         const html = [];
-        for (const p of stageTree.pwd) {
+        const select = $('#cooperationSelect').val();
+        const list = select !== '全部' ? _.filter(stageTree.pwd, { company: select }) : stageTree.pwd;
+        for (const p of list) {
             if (!p.node) continue;
             if (!p.node) continue;
-            html.push('<tr>', `<td>${p.node.code}</td>`, `<td>${p.node.name}</td>`);
-            html.push('<td>', p.check ? `已解锁:${p.pwd}` : `<a name="ledger-unlock" lid="${p.ledger_id}" href="javascript: void(0);">解锁</a>`, '</td>');
+            if (p.confirm) {
+                html.push(`<tr class="text-success">`);
+            } else {
+                html.push(`<tr>`);
+            }
+            html.push(`<td>${p.node.code}</td>`, `<td>${p.node.name}</td>`);
+            if(coopwd) {
+                html.push('<td>', p.check ? `已解锁:${p.pwd}` : `<a name="ledger-unlock" lid="${p.ledger_id}" href="javascript: void(0);">解锁</a>`, '</td>');
+            }
+            html.push('<td>', p.company, '</td>');
+            html.push('<td>', p.check ? (p.confirm ? (moment(p.confirm_time).format('YYYY-MM-DD HH:mm') + ' ' + (coopwd ? `<a name="ledger-unconfirm" href="javascript: void(0);" lid="${p.ledger_id}">重新审批</a>` : '')) : `<a name="ledger-confirm" href="javascript: void(0);" lid="${p.ledger_id}" class="btn btn-sm btn-success">确认</a>`) : '' ,'</td>');
             html.push('</tr>');
             html.push('</tr>');
         }
         }
         $('#cooperationList').html(html.join(''));
         $('#cooperationList').html(html.join(''));
+
     };
     };
 
 
     class Changes {
     class Changes {
@@ -1924,9 +1946,11 @@ $(document).ready(() => {
         treeCalc.calculateAll(stageTree);
         treeCalc.calculateAll(stageTree);
         // 加载解锁相关
         // 加载解锁相关
         if (result.cooperation) {
         if (result.cooperation) {
-            stageTree.loadPwd(result.cooperation, 'bills-p-' + userID + '-' + window.location.pathname.split('/')[2]);
+            // stageTree.loadPwd(result.cooperation, 'bills-p-' + userID + '-' + window.location.pathname.split('/')[2]);
+            stageTree.loadOnlinePwd(result.cooperation, result.cooperationPwd, result.cooperationConfirm);
             $('#cooperationCount').html(stageTree.pwd.length || '');
             $('#cooperationCount').html(stageTree.pwd.length || '');
             if (stageTree.pwd.length > 0) $('#cooperationCount').parent().show();
             if (stageTree.pwd.length > 0) $('#cooperationCount').parent().show();
+            setCooperationSelectHtml();
             reloadCooperationHtml();
             reloadCooperationHtml();
         }
         }
         for (const t of result.tags) {
         for (const t of result.tags) {
@@ -3982,6 +4006,13 @@ $(document).ready(() => {
     });
     });
     $('[name=stage-start]').submit(function (e) {
     $('[name=stage-start]').submit(function (e) {
         if (checkAuditorFrom()) {
         if (checkAuditorFrom()) {
+            // 再检查多人协同确认情况
+            const list = stageTree.pwd.find(x => {return !x.confirm });
+            if(list) {
+                toastr.error('请检查多人协同确认情况再上报');
+                $('#hide-all').hide();
+                return false;
+            }
             $(this).parent().parent().parent().modal('hide');
             $(this).parent().parent().parent().modal('hide');
             dataChecker.checkAndPost(this.action, {});
             dataChecker.checkAndPost(this.action, {});
             $('#hide-all').hide();
             $('#hide-all').hide();
@@ -3989,6 +4020,14 @@ $(document).ready(() => {
         return false;
         return false;
     });
     });
     $('#audit-check0').submit(function (e) {
     $('#audit-check0').submit(function (e) {
+        // 再检查多人协同确认情况
+        const list = stageTree.pwd.find(x => {return !x.confirm });
+        if(list) {
+            toastr.error('请检查多人协同确认情况再审批通过');
+            $('#hide-all').hide();
+            return false;
+        }
+        return false;
         const checkType = parseInt($('[name=checkType]').val());
         const checkType = parseInt($('[name=checkType]').val());
         const data = {
         const data = {
             opinion: $(`${'#sp-done'}`).find('[name=opinion]').val().replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\s/g, ' '),
             opinion: $(`${'#sp-done'}`).find('[name=opinion]').val().replace(/\r\n/g, '<br/>').replace(/\n/g, '<br/>').replace(/\s/g, ' '),
@@ -4073,6 +4112,10 @@ $(document).ready(() => {
 
 
         if (p.pwd === $('#unlock-pwd').val()) {
         if (p.pwd === $('#unlock-pwd').val()) {
             const refresh = stageTree.lockNode(p, false);
             const refresh = stageTree.lockNode(p, false);
+            // 修改线上
+            postData(window.location.pathname + '/save/cooperation', { type: 'save-pwd', postData: { ledger_id: lid, pwd: $('#unlock-pwd').val() } }, function (result) {
+                stageTree.pwdList = result.cooperationPwd;
+            });
             SpreadJsObj.reloadRowsReadonly(slSpread.getActiveSheet(), refresh);
             SpreadJsObj.reloadRowsReadonly(slSpread.getActiveSheet(), refresh);
             stagePosSpreadObj.loadCurPosData();
             stagePosSpreadObj.loadCurPosData();
             $('#unlock').modal('hide');
             $('#unlock').modal('hide');
@@ -4082,5 +4125,39 @@ $(document).ready(() => {
             $('.invalid-feedback', '#unlock').show();
             $('.invalid-feedback', '#unlock').show();
             $('.alert-warning', '#unlock').show();
             $('.alert-warning', '#unlock').show();
         }
         }
-    })
+    });
+    $('#cooperationSelect').change(function () {
+        reloadCooperationHtml();
+    });
+    // 确认
+    $('body').on('click', '[name=ledger-confirm]', function() {
+        const lid = this.getAttribute('lid');
+        if (!lid) return;
+
+        const p = stageTree.pwd.find(x => {return x.ledger_id == lid});
+        if (!p) return;
+        // 修改线上
+        postData(window.location.pathname + '/save/cooperation', { type: 'save-confirm', postData: { ledger_id: lid } }, function (result) {
+            p.confirm = true;
+            p.confirm_time = new Date();
+            stageTree.confirmList = result.cooperationConfirm;
+            reloadCooperationHtml();
+        });
+    });
+
+    // 确认
+    $('body').on('click', '[name=ledger-unconfirm]', function() {
+        const lid = this.getAttribute('lid');
+        if (!lid) return;
+
+        const p = stageTree.pwd.find(x => {return x.ledger_id == lid});
+        if (!p) return;
+        // 修改线上
+        postData(window.location.pathname + '/save/cooperation', { type: 'del-confirm', postData: { ledger_id: lid } }, function (result) {
+            p.confirm = false;
+            p.confirm_time = null;
+            stageTree.confirmList = result.cooperationConfirm;
+            reloadCooperationHtml();
+        });
+    });
 });
 });

+ 2 - 0
app/router.js

@@ -235,6 +235,7 @@ module.exports = app => {
     app.post('/tender/:id/measure/stage/:order/valid-change', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.searchValidChange');
     app.post('/tender/:id/measure/stage/:order/valid-change', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.searchValidChange');
     app.post('/tender/:id/measure/stage/:order/use-change', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.useChange');
     app.post('/tender/:id/measure/stage/:order/use-change', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.useChange');
     app.post('/tender/:id/measure/stage/:order/check', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.check');
     app.post('/tender/:id/measure/stage/:order/check', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.check');
+    app.post('/tender/:id/measure/stage/:order/save/cooperation', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.saveCooperationData');
 
 
     // 计量附件
     // 计量附件
     app.post('/tender/:id/measure/stage/:order/upload/file', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.uploadFile');
     app.post('/tender/:id/measure/stage/:order/upload/file', sessionAuth, tenderCheck, uncheckTenderCheck, stageCheck, 'stageController.uploadFile');
@@ -328,6 +329,7 @@ module.exports = app => {
     app.post('/tender/report_api/updateArchive/:prjId/:stgId/:rptId/:orgName', sessionAuth, 'reportArchiveController.updateReportArchive');
     app.post('/tender/report_api/updateArchive/:prjId/:stgId/:rptId/:orgName', sessionAuth, 'reportArchiveController.updateReportArchive');
     app.post('/tender/report_api/removeArchive/:prjId/:stgId/:rptId/:orgName', sessionAuth, 'reportArchiveController.removeReportArchive');
     app.post('/tender/report_api/removeArchive/:prjId/:stgId/:rptId/:orgName', sessionAuth, 'reportArchiveController.removeReportArchive');
 
 
+
     // 变更管理
     // 变更管理
     app.get('/tender/:id/change', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.index');
     app.get('/tender/:id/change', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.index');
     app.get('/tender/:id/change/status/:status', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.status');
     app.get('/tender/:id/change/status/:status', sessionAuth, tenderCheck, uncheckTenderCheck, 'changeController.status');

+ 59 - 0
app/service/cooperation_confirm.js

@@ -0,0 +1,59 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date 2018/6/1
+ * @version
+ */
+
+module.exports = app => {
+    class CooperationConfirm extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'cooperation_confirm';
+        }
+
+        async save(data) {
+            const info = await this.getDataByCondition({ tid: this.ctx.tender.id, sid: this.ctx.stage.id, times: this.ctx.stage.times, ledger_id: data.ledger_id, uid: this.ctx.session.sessionUser.accountId });
+            if (info) {
+                const updateData = {
+                    id: info.id,
+                    create_time: new Date(),
+                };
+                return await this.db.update(this.tableName, updateData);
+            }
+            const insertData = {
+                tid: this.ctx.tender.id,
+                sid: this.ctx.stage.id,
+                times: this.ctx.stage.times,
+                uid: this.ctx.session.sessionUser.accountId,
+                ledger_id: data.ledger_id,
+                create_time: new Date(),
+            };
+            return await this.db.insert(this.tableName, insertData);
+        }
+
+        async del(data) {
+            return await this.db.delete(this.tableName, { tid: this.ctx.tender.id, sid: this.ctx.stage.id, times: this.ctx.stage.times, ledger_id: data.ledger_id, uid: this.ctx.session.sessionUser.accountId });
+        }
+
+        async getValidData(tid, sid, times, uid) {
+            const condition = { where: { tid, sid, times, uid } };
+            // if (uid) {
+            //     condition.where.uid = uid;
+            //     condition.colums = ['ledger_id', 'pwd'];
+            // }
+            return await this.getAllDataByCondition(condition);
+        }
+    }
+
+    return CooperationConfirm;
+};

+ 55 - 0
app/service/cooperation_pwd.js

@@ -0,0 +1,55 @@
+'use strict';
+
+/**
+ *
+ *
+ * @author Mai
+ * @date 2018/6/1
+ * @version
+ */
+
+module.exports = app => {
+    class CooperationPwd extends app.BaseService {
+        /**
+         * 构造函数
+         *
+         * @param {Object} ctx - egg全局变量
+         * @return {void}
+         */
+        constructor(ctx) {
+            super(ctx);
+            this.tableName = 'cooperation_pwd';
+        }
+
+        async save(data) {
+            const info = await this.getDataByCondition({ tid: this.ctx.tender.id, ledger_id: data.ledger_id, uid: this.ctx.session.sessionUser.accountId });
+            if (info) {
+                const updateData = {
+                    id: info.id,
+                    pwd: data.pwd,
+                    create_time: new Date(),
+                };
+                return await this.db.update(this.tableName, updateData);
+            }
+            const insertData = {
+                tid: this.ctx.tender.id,
+                uid: this.ctx.session.sessionUser.accountId,
+                ledger_id: data.ledger_id,
+                pwd: data.pwd,
+                create_time: new Date(),
+            };
+            return await this.db.insert(this.tableName, insertData);
+        }
+
+        async getValidData(tid, uid) {
+            const condition = { where: { tid } };
+            if (uid) {
+                condition.where.uid = uid;
+                condition.colums = ['ledger_id', 'pwd'];
+            }
+            return await this.getAllDataByCondition(condition);
+        }
+    }
+
+    return CooperationPwd;
+};

+ 1 - 0
app/view/stage/index.ejs

@@ -615,6 +615,7 @@
     // const cur_uid = parseInt('<%- ctx.session.sessionUser.accountId %>');
     // const cur_uid = parseInt('<%- ctx.session.sessionUser.accountId %>');
     const curAuditor = JSON.parse('<%- JSON.stringify(curAuditor) %>');
     const curAuditor = JSON.parse('<%- JSON.stringify(curAuditor) %>');
     const thirdParty = JSON.parse('<%- JSON.stringify(thirdParty) %>');
     const thirdParty = JSON.parse('<%- JSON.stringify(thirdParty) %>');
+    const coopwd = <%- coopwd %>;
 </script>
 </script>
 <style>
 <style>
 
 

+ 13 - 4
app/view/stage/modal.ejs

@@ -460,17 +460,26 @@
 </div>
 </div>
 <!--多人协同-->
 <!--多人协同-->
 <div class="modal fade" id="cooperation" data-backdrop="static">
 <div class="modal fade" id="cooperation" data-backdrop="static">
-    <div class="modal-dialog" role="document">
+    <div class="modal-dialog modal-lg" role="document">
         <div class="modal-content">
         <div class="modal-content">
             <div class="modal-header">
             <div class="modal-header">
                 <h5 class="modal-title">多人协同</h5>
                 <h5 class="modal-title">多人协同</h5>
             </div>
             </div>
             <div class="modal-body">
             <div class="modal-body">
-                <div class="alert alert-warning">以下项目节及其子项被锁定,请输入密码解锁。</div>
+                <% if (coopwd) { %>
+                    <div class="alert alert-warning">以下项目节及其子项被锁定,请输入密码解锁。</div>
+                <% } else { %>
+                    <div class="alert alert-warning">以下项目节及其子项(灰色项)未确认审批。</div>
+                <% } %>
+                <div class="mb-2">
+                    <select class="form-control form-control-sm w-25" id="cooperationSelect">
+                        <option>全部</option>
+                    </select>
+                </div>
                 <div class="modal-height-300">
                 <div class="modal-height-300">
                     <table class="table table-hover table-bordered">
                     <table class="table table-hover table-bordered">
                         <thead>
                         <thead>
-                        <tr><th>项目节编号</th><th>项目节名称</th><th>解锁  </th></tr>
+                        <tr><th>项目节编号</th><th>项目节名称</th><% if (coopwd) { %><th>解锁  </th><% } %><th>单位/协同人名称</th><th>确认数据</th></tr>
                         </thead>
                         </thead>
                         <tbody id="cooperationList">
                         <tbody id="cooperationList">
                         </tbody>
                         </tbody>
@@ -479,7 +488,7 @@
             </div>
             </div>
             <div class="modal-footer">
             <div class="modal-footer">
                 <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">关闭</button>
                 <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">关闭</button>
-                <button type="button" class="btn btn-sm btn-primary">确认</button>
+                <!--<button type="button" class="btn btn-sm btn-primary">确认</button>-->
             </div>
             </div>
         </div>
         </div>
     </div>
     </div>