浏览代码

游客功能提交

laiguoran 4 年之前
父节点
当前提交
f2100ef019

+ 1 - 1
app/controller/change_controller.js

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

+ 0 - 1
app/controller/login_controller.js

@@ -56,7 +56,6 @@ module.exports = app => {
             try {
                 const client = new OAuth(ctx.app.config.wxCode.appid, ctx.app.config.wxCode.appsecret);
                 const token = await client.getAccessToken(code);
-                ctx.session.wxbindtoken = token;
                 // const user = await client.getUser(token.data.openid);
                 // console.log(user);
                 if (!token) {

+ 24 - 24
app/controller/stage_controller.js

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

+ 36 - 1
app/controller/tender_controller.js

@@ -454,7 +454,7 @@ module.exports = app => {
                     jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.tender.tenderInfo),
                 };
                 if (ctx.session.sessionUser.is_admin) {
-                    // renderData.tourists = await ctx.service.tenderTourist.getTourists(tender.id);
+                    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 },
@@ -968,6 +968,41 @@ module.exports = app => {
         }
 
         /**
+         * 游客账号设置
+         * @param {object} ctx - 上下文
+         */
+        async saveTourist(ctx) {
+            try {
+                const data = JSON.parse(ctx.request.body.data);
+                if (!data) {
+                    throw '提交数据错误';
+                }
+                // 判断修改权限
+                if (ctx.session.sessionUser.is_admin === 0) {
+                    throw '你没有权限修改游客账号';
+                }
+                let info = '';
+                switch (data.type) {
+                    case 'add':
+                        const result = await ctx.service.tenderTourist.addAudit(data);
+                        if (!result) {
+                            throw '添加审批人失败';
+                        }
+                        info = result;
+                        break;
+                    case 'del':
+                        await ctx.service.tenderTourist.removeAudit(data);
+                        break;
+                    default:break;
+                }
+                ctx.body = { err: 0, msg: '', data: info };
+            } catch (err) {
+                this.log(err);
+                ctx.body = this.ajaxErrorBody(err, '保存游客账号设置失败');
+            }
+        }
+
+        /**
          * 获取部位明细数据(Ajax)
          *
          * @param ctx

+ 0 - 16
app/controller/wechat_controller.js

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

+ 2 - 1
app/middleware/change_check.js

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

+ 12 - 0
app/middleware/material_check.js

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

+ 14 - 1
app/middleware/stage_check.js

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

+ 6 - 1
app/middleware/tender_check.js

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

+ 1 - 2
app/router.js

@@ -127,6 +127,7 @@ module.exports = app => {
     app.post('/tender/:id/shenpi/ledger/load', sessionAuth, tenderCheck, 'tenderController.loadLedgerData');
     app.post('/tender/:id/shenpi/save-sign', sessionAuth, tenderCheck, 'tenderController.saveCooperateSign');
     app.post('/tender/:id/copy-setting', sessionAuth, tenderCheck, 'tenderController.copyTender');
+    app.post('/tender/:id/tourist/audit/save', sessionAuth, tenderCheck, uncheckTenderCheck, 'tenderController.saveTourist');
 
     // 预付款
     app.get('/tender/:id/advance', sessionAuth, tenderCheck, 'advanceController.index');
@@ -467,6 +468,4 @@ module.exports = app => {
     app.get('/wxAuth', 'loginController.wxAuth');
     app.get('/wxproject', 'loginController.wxProject');
     app.get('/wx/url2web', 'loginController.url2web');
-
-    app.get('/wx/unionid', wechatAuth, 'wechatController.batchUpdateUnionid');
 };

+ 58 - 47
app/service/change.js

@@ -230,53 +230,58 @@ module.exports = app => {
         async getListByStatus(tenderId, status = 0, hadlimit = 1) {
             let sql = '';
             let sqlParam = '';
-            switch (status) {
-                case 0: // 包含你的所有变更令
-                    sql =
-                        'SELECT a.* FROM ?? AS a WHERE a.tid = ? AND ' +
-                        '(a.uid = ? OR (a.status != ? AND a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid)) OR a.status = ? ) ORDER BY a.in_time DESC';
-                    sqlParam = [
-                        this.tableName,
-                        tenderId,
-                        this.ctx.session.sessionUser.accountId,
-                        audit.flow.status.uncheck,
-                        this.ctx.service.changeAudit.tableName,
-                        this.ctx.session.sessionUser.accountId,
-                        audit.flow.status.checked,
-                    ];
-                    break;
-                case 1: // 待处理(你的)
-                    sql = 'SELECT a.* FROM ?? as a WHERE cid in(SELECT b.cid FROM ?? as b WHERE tid = ? AND uid = ? AND status = ?) ORDER BY in_time DESC';
-                    sqlParam = [this.tableName, this.ctx.service.changeAudit.tableName, tenderId, this.ctx.session.sessionUser.accountId, audit.flow.auditStatus.checking];
-                    break;
-                case 5: // 待上报(所有的)PS:取未上报和退回的变更令
-                    sql =
-                        'SELECT a.* FROM ?? AS a WHERE ' +
-                        'a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? GROUP BY b.cid) AND ' +
-                        '(a.status = ? OR a.status = ?) AND a.tid = ? ORDER BY a.in_time DESC';
-                    sqlParam = [
-                        this.tableName,
-                        this.ctx.service.changeAudit.tableName,
-                        this.ctx.session.sessionUser.accountId,
-                        audit.flow.status.uncheck,
-                        audit.flow.status.back,
-                        tenderId,
-                    ];
-                    break;
-                case 2: // 进行中(所有的)
-                case 4: // 终止(所有的)
-                    sql =
-                        'SELECT a.* FROM ?? AS a WHERE ' +
-                        'a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid) AND ' +
-                        'a.status = ? AND a.tid = ? ORDER BY a.in_time DESC';
-                    sqlParam = [this.tableName, this.ctx.service.changeAudit.tableName, this.ctx.session.sessionUser.accountId, status, tenderId];
-                    break;
-                case 3: // 已完成(所有的)
-                    sql = 'SELECT a.* FROM ?? AS a WHERE a.status = ? AND a.tid = ? ORDER BY a.in_time DESC';
-                    sqlParam = [this.tableName, status, tenderId];
-                    break;
-                default:
-                    break;
+            if (this.ctx.tender.isTourist && status === 0) {
+                sql = 'SELECT * FROM ?? WHERE tid = ? ORDER BY in_time DESC';
+                sqlParam = [this.tableName, tenderId];
+            } else {
+                switch (status) {
+                    case 0: // 包含你的所有变更令
+                        sql =
+                            'SELECT a.* FROM ?? AS a WHERE a.tid = ? AND ' +
+                            '(a.uid = ? OR (a.status != ? AND a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid)) OR a.status = ? ) ORDER BY a.in_time DESC';
+                        sqlParam = [
+                            this.tableName,
+                            tenderId,
+                            this.ctx.session.sessionUser.accountId,
+                            audit.flow.status.uncheck,
+                            this.ctx.service.changeAudit.tableName,
+                            this.ctx.session.sessionUser.accountId,
+                            audit.flow.status.checked,
+                        ];
+                        break;
+                    case 1: // 待处理(你的)
+                        sql = 'SELECT a.* FROM ?? as a WHERE cid in(SELECT b.cid FROM ?? as b WHERE tid = ? AND uid = ? AND status = ?) ORDER BY in_time DESC';
+                        sqlParam = [this.tableName, this.ctx.service.changeAudit.tableName, tenderId, this.ctx.session.sessionUser.accountId, audit.flow.auditStatus.checking];
+                        break;
+                    case 5: // 待上报(所有的)PS:取未上报和退回的变更令
+                        sql =
+                            'SELECT a.* FROM ?? AS a WHERE ' +
+                            'a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? GROUP BY b.cid) AND ' +
+                            '(a.status = ? OR a.status = ?) AND a.tid = ? ORDER BY a.in_time DESC';
+                        sqlParam = [
+                            this.tableName,
+                            this.ctx.service.changeAudit.tableName,
+                            this.ctx.session.sessionUser.accountId,
+                            audit.flow.status.uncheck,
+                            audit.flow.status.back,
+                            tenderId,
+                        ];
+                        break;
+                    case 2: // 进行中(所有的)
+                    case 4: // 终止(所有的)
+                        sql =
+                            'SELECT a.* FROM ?? AS a WHERE ' +
+                            'a.cid IN (SELECT b.cid FROM ?? AS b WHERE b.uid = ? AND a.times = b.times GROUP BY b.cid) AND ' +
+                            'a.status = ? AND a.tid = ? ORDER BY a.in_time DESC';
+                        sqlParam = [this.tableName, this.ctx.service.changeAudit.tableName, this.ctx.session.sessionUser.accountId, status, tenderId];
+                        break;
+                    case 3: // 已完成(所有的)
+                        sql = 'SELECT a.* FROM ?? AS a WHERE a.status = ? AND a.tid = ? ORDER BY a.in_time DESC';
+                        sqlParam = [this.tableName, status, tenderId];
+                        break;
+                    default:
+                        break;
+                }
             }
             if (hadlimit) {
                 const limit = this.app.config.pageSize;
@@ -295,6 +300,12 @@ module.exports = app => {
          * @return {void}
          */
         async getCountByStatus(tenderId, status) {
+            if (this.ctx.tender.isTourist && status === 0) {
+                const sql5 = 'SELECT count(*) AS count FROM ?? WHERE tid = ? ORDER BY in_time DESC';
+                const sqlParam5 = [this.tableName, tenderId];
+                const result5 = await this.db.query(sql5, sqlParam5);
+                return result5[0].count;
+            }
             switch (status) {
                 case 0: // 包含你的所有变更令
                     const sql =

+ 7 - 3
app/service/change_audit.js

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

+ 1 - 1
app/service/material.js

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

+ 0 - 12
app/service/project_account.js

@@ -790,18 +790,6 @@ module.exports = app => {
 
             return result;
         }
-
-        async getUnionIdList() {
-            const sql = 'SELECT * FROM ?? WHERE wx_openid is not null and wx_unionid is null';
-            const sqlParam = [this.tableName];
-            return await this.db.query(sql, sqlParam);
-        }
-
-        async updateUnionid(updateList) {
-            if (updateList.length > 0) {
-                return await this.db.updateRows(updateList);
-            }
-        }
     }
 
     return ProjectAccount;

+ 1 - 1
app/service/stage.js

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

+ 3 - 0
app/service/tender.js

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

+ 66 - 0
app/service/tender_tourist.js

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

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

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

+ 10 - 2
app/view/change/information.ejs

@@ -23,7 +23,7 @@
                         <label class="custom-control-label" for="customCheck1">变更详情</label>
                     </div>
                 </div>
-                <% if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7) { %>
+                <% if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7 || auditStatus === 8) { %>
                     <div class="d-inline-block ml-3">
                         <div class="custom-control custom-checkbox" style="line-height: normal;">
                             <input type="checkbox" class="custom-control-input" id="show-table-detail">
@@ -49,6 +49,12 @@
                     <a href="#sp-back" data-toggle="modal" data-target="#sp-back" class="btn btn-warning btn-sm">审批退回</a>
                 <% } else if (auditStatus === 7) { %>
                     <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-secondary btn-sm">审批中</a>
+                <% } else if (auditStatus === 8) { %>
+                    <% if (change.status === auditConst.status.uncheck) { %>
+                    <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-secondary btn-sm">上报中</a>
+                    <% } else if (change.status === auditConst.status.checking) { %>
+                    <a href="#sp-list" data-toggle="modal" data-target="#sp-list" class="btn btn-outline-secondary btn-sm">审批中</a>
+                    <% } %>
                 <% } %>
                 <% if (auditStatus === 4 && ctx.session.sessionUser.accountId === auditList[auditList.length-1].uid) { %>
                     <% if (stageChangeNum === 0) { %>
@@ -87,7 +93,9 @@
                             <!--所有附件 翻页-->
                             <a href="javascript: void(0);" data-toggle="modal" class="btn btn-sm btn-primary" id="bach-download"><i class="fa fa-download "></i> 批量下载</a>
                             <a href="javascript:void(0);" class="page-select ml-3" content="pre"><i class="fa fa-chevron-left"></i></a> <span id="currentPage">1</span>/<span id="totalPage">10</span> <a href="javascript:void(0);" class="page-select mr-3" content="next"><i class="fa fa-chevron-right"></i></a>
+                            <% if (auditStatus !== 8) { %>
                             <a href="#addfujian" data-toggle="modal" class="btn btn-sm btn-light text-primary" data-placement="bottom" title="" data-original-title="上传附件"><i class="fa fa-cloud-upload" aria-hidden="true"></i> 上传附件</a>
+                            <% } %>
                             <a href="" id="downloadZip" style="display: none;" download></a>
                         </li>
                     </ul>
@@ -430,7 +438,7 @@
 </script>
 <script src="/public/js/change_information_set.js"></script>
 <script src="/public/js/change_audit.js"></script>
-<% } else if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7) { %>
+<% } else if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7 || auditStatus === 8) { %>
 <script>
     const auditList2 = JSON.parse(unescape('<%- escape(JSON.stringify(auditList2)) %>'));
     const aidList = _.map(auditList2, 'uid');

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

@@ -289,7 +289,7 @@
 <% } %>
 <% } %>
 
-<% if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7) { %>
+<% if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7 || auditStatus === 8) { %>
 <!--审批流程/结果-->
 <div class="modal fade" id="sp-list" data-backdrop="static">
     <div class="modal-dialog modal-lg" role="document">

+ 1 - 1
app/view/material/audit_btn.ejs

@@ -1,6 +1,6 @@
 <div class="contarl-box">
     <% if (ctx.material.status === auditConst.status.uncheck) { %>
-        <% if (ctx.session.sessionUser.accountId === ctx.material.user_id) { %>
+        <% if (ctx.session.sessionUser.accountId === ctx.material.user_id || ctx.tender.isTourist) { %>
             <a id="sub-sp-btn" href="javascript: void(0);" data-toggle="modal" data-target="#sub-sp" class="btn btn-primary btn-sm btn-block">上报审批</a>
         <% } %>
     <% } else if (ctx.material.status === auditConst.status.checking) { %>

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

@@ -1,4 +1,4 @@
-<% if ((ctx.material.status === auditConst.status.uncheck || ctx.material.status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === ctx.material.user_id) { %>
+<% if ((ctx.material.status === auditConst.status.uncheck || ctx.material.status === auditConst.status.checkNo) && (ctx.session.sessionUser.accountId === ctx.material.user_id || ctx.tender.isTourist)) { %>
 <!--上报审批-->
 <div class="modal fade" id="sub-sp" data-backdrop="static">
     <div class="modal-dialog" role="document">
@@ -8,7 +8,7 @@
             </div>
             <div class="modal-body">
                 <div class="dropdown text-right">
-                    <% if (ctx.tender.info.shenpi.material !== shenpiConst.sp_status.gdspl) { %>
+                    <% if (ctx.tender.info.shenpi.material !== shenpiConst.sp_status.gdspl && ctx.session.sessionUser.accountId === ctx.material.user_id) { %>
                     <button class="btn btn-outline-primary btn-sm dropdown-toggle" type="button"
                         id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true"
                         aria-expanded="false">
@@ -45,8 +45,8 @@
                     <ul class="list-group list-group-flush" id="auditors">
                         <% for (let i = 0, iLen = ctx.material.auditorList.length; i < iLen; i++) { %>
                         <li class="list-group-item" auditorId="<%- ctx.material.auditorList[i].aid %>">
-                            <% if (ctx.tender.info.shenpi.material === shenpiConst.sp_status.sqspr ||
-                                    (ctx.tender.info.shenpi.material === shenpiConst.sp_status.gdzs && i+1 !== iLen)) { %>
+                            <% if ((ctx.tender.info.shenpi.material === shenpiConst.sp_status.sqspr ||
+                                    (ctx.tender.info.shenpi.material === shenpiConst.sp_status.gdzs && i+1 !== iLen)) && ctx.session.sessionUser.accountId === ctx.material.user_id) { %>
                             <a href="javascript: void(0)" class="text-danger pull-right">移除</a>
                             <% } %>
                             <span><%- ctx.material.auditorList[i].order %> <%- ctx.material.auditorList[i].name %></span>
@@ -60,7 +60,9 @@
             <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_j" value="<%= ctx.csrf %>">
+                <% if (ctx.session.sessionUser.accountId === ctx.material.user_id) { %>
                 <button class="btn btn-primary btn-sm" type="submit">确认上报</button>
+                <% } %>
             </form>
         </div>
     </div>

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

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

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

@@ -245,7 +245,7 @@
     });
 </script>
 <script>
-    const tenders = JSON.parse('<%- JSON.stringify(tenderList) %>');
+    const tenders = JSON.parse(unescape('<%- escape(JSON.stringify(tenderList)) %>'));
     const category = JSON.parse('<%- JSON.stringify(categoryData) %>');
     const auditConst = JSON.parse('<%- JSON.stringify(auditConst) %>');
     const ledgerAuditConst = JSON.parse('<%- JSON.stringify(ledgerAuditConst) %>');

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

@@ -1,5 +1,5 @@
 <% if (ctx.stage && (ctx.stage.status === auditConst.status.uncheck || ctx.stage.status === auditConst.status.checkNo)) { %>
-    <% if (ctx.session.sessionUser.accountId === ctx.stage.user_id) {%>
+    <% if (ctx.session.sessionUser.accountId === ctx.stage.user_id || ctx.tender.isTourist) {%>
     <!--上报审批-->
     <div class="modal fade" id="sub-sp" data-backdrop="static">
         <div class="modal-dialog" role="document">
@@ -9,7 +9,7 @@
                 </div>
                 <div class="modal-body">
                     <div class="dropdown text-right">
-                        <% if (ctx.tender.info.shenpi.stage !== shenpiConst.sp_status.gdspl) { %>
+                        <% if (ctx.tender.info.shenpi.stage !== shenpiConst.sp_status.gdspl && ctx.session.sessionUser.accountId === ctx.stage.user_id) { %>
                         <button class="btn btn-outline-primary btn-sm dropdown-toggle" type="button" id="dropdownMenuButton"
                             data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                             添加审批流程
@@ -46,7 +46,7 @@
                                 <% for (let i = 0, iLen = ctx.stage.auditorList.length; i < iLen; i++) { %>
                                 <li class="list-group-item" auditorId="<%- ctx.stage.auditorList[i].aid %>">
                                     <% if (ctx.tender.info.shenpi.stage === shenpiConst.sp_status.sqspr ||
-                                            (ctx.tender.info.shenpi.stage === shenpiConst.sp_status.gdzs && i+1 !== iLen)) { %>
+                                            (ctx.tender.info.shenpi.stage === shenpiConst.sp_status.gdzs && i+1 !== iLen) && ctx.session.sessionUser.accountId === ctx.stage.user_id) { %>
                                     <a href="javascript: void(0)" class="text-danger pull-right">移除</a>
                                     <% } %>
                                     <span><%- ctx.stage.auditorList[i].order %> <%- ctx.stage.auditorList[i].name %></span>
@@ -60,7 +60,9 @@
                 <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_j" value="<%= ctx.csrf %>">
+                    <% if (ctx.session.sessionUser.accountId === ctx.stage.user_id) { %>
                     <button class="btn btn-primary btn-sm" type="submit">确认上报</button>
+                    <% } %>
                 </form>
             </div>
         </div>

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

@@ -273,7 +273,9 @@
                                     <a href="javascript:void(0);" id="bach-download" class="btn btn-sm btn-primary" type="curr">批量下载</a>
                                     <!--所有附件 翻页-->
                                     <span id="showPage" style="display: none"><a href="javascript:void(0);" class="page-select ml-3" content="pre"><i class="fa fa-chevron-left"></i></a> <span id="currentPage">1</span>/<span id="totalPage">10</span> <a href="javascript:void(0);" class="page-select mr-3" content="next"><i class="fa fa-chevron-right"></i></a></span>
+                                    <% if (!ctx.tender.isTourist && stage.filePermission) { %>
                                     <a href="#upload" data-toggle="modal" data-target="#upload"  class="btn btn-sm btn-outline-primary ml-3">上传</a>
+                                    <% } %>
                                 </li>
                             </ul>
                         </div>

+ 2 - 2
app/view/stage/pay.ejs

@@ -56,8 +56,8 @@
     <img src="/public/images/file_clip_hover.png" id="rela-file-hover" />
 </div>
 <script>
-    const tender = JSON.parse('<%- JSON.stringify(tender) %>');
-    const stage = JSON.parse('<%- JSON.stringify(ctx.stage) %>');
+    const tender = JSON.parse(unescape('<%- escape(JSON.stringify(tender)) %>'));
+    const stage = JSON.parse(unescape('<%- escape(JSON.stringify(ctx.stage)) %>'));
     const readOnly = <%- stage.readOnly || stage.revising %>;
     const dealPay = JSON.parse(unescape('<%- escape(JSON.stringify(dealPay)) %>'));
     const calcBase = JSON.parse('<%- JSON.stringify(calcBase) %>');

+ 1 - 0
app/view/tender/detail.ejs

@@ -107,6 +107,7 @@
                                 <a href="javascript: void(0);" class="btn btn-sm btn-outline-primary" id="copyBtn">拷贝设置</a>
                                 <% if (ctx.session.sessionUser.is_admin) { %>
                                 <a href="/tender/<%- tender.id %>/shenpi" class="btn btn-sm btn-outline-primary">审批流程</a>
+                                    <a href="#bd-set-9" data-toggle="modal" data-target="#bd-set-9" class="btn btn-sm btn-outline-primary">游客账号 <span id="tourist-num" <% if (tourists.length !== 0) { %>class="badge badge-secondary"<% } %>><% if (tourists.length !== 0) { %><%- tourists.length %><% } %></span></a>
                                 <% } %>
                             </div>
                         </div>

+ 188 - 10
app/view/tender/detail_modal.ejs

@@ -1531,7 +1531,189 @@
         });
     }
 </script>
+<% if (ctx.session.sessionUser.is_admin) { %>
+<!--游客账号-->
+<div class="modal fade" id="bd-set-9" 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">
+                <div class="dropdown text-right">
+                    <button class="btn btn-outline-primary btn-sm dropdown-toggle" type="button" id="tourist_dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                        添加游客
+                    </button>
+                    <div class="dropdown-menu dropdown-menu-right" id="tourist_dropdownMenu" aria-labelledby="tourist_dropdownMenuButton" style="width:220px">
+                        <div class="mb-2 p-2"><input class="form-control form-control-sm gr-search"
+                                                     placeholder="姓名/手机 检索" autocomplete="off"></div>
+                        <dl class="list-unstyled book-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 %>">
+                                    <% group.groupList.forEach(item => { %>
+                                        <% if (item.id !== ctx.tender.data.user_id) { %>
+                                            <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="card mt-3">
+                    <div class="card-header">
+                        游客列表
+                    </div>
+                    <div class="modal-height-300">
+                        <ul class="list-group list-group-flush" id="tourist-users">
+                            <% for (const t of tourists) { %>
+                                <li class="list-group-item"  data-id="<%- t.user_id %>">
+                                    <a href="javascript:void(0);" class="text-danger pull-right remove-tourist-user" data-id="<%- t.id %>">移除</a><%- t.user_name %>  <small class="text-muted"><%- t.user_role %></small><p class="m-0 ml-2"><small class="text-muted"><%- t.user_company %></small></p></li>
+                            <% } %>
+                        </ul>
+                    </div>
+                </div>
+            </div>
+            <div class="modal-footer">
+                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">关闭</button>
+            </div>
+        </div>
+    </div>
+</div>
+<script>
+    const accountGroup = JSON.parse(unescape('<%- escape(JSON.stringify(accountGroup)) %>'));
+    const accountList = JSON.parse(unescape('<%- escape(JSON.stringify(accountList)) %>'));
+    const cur_tender_uid = parseInt('<%- ctx.tender.data.user_id %>');
+    const cur_tenderid = parseInt('<%- ctx.tender.id %>');
+    $(function () {
+        // 形象进度
+        let timer2 = null;
+        let oldSearchVal2 = null;
+        $('body').on('input propertychange', '#tourist_dropdownMenu .gr-search', function (e) {
+            oldSearchVal2 = e.target.value;
+            timer2 && clearTimeout(timer2);
+            timer2 = setTimeout(() => {
+                const newVal = $(this).val();
+                let html = '';
+                if (newVal && newVal === oldSearchVal) {
+                    accountList.filter(item => item && item.id !== cur_tender_uid && (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>`
+                    });
+                    $('#tourist_dropdownMenu .book-list').empty();
+                    $('#tourist_dropdownMenu .book-list').append(html);
+                } else {
+                    if (!$('#tourist_dropdownMenu .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 => {
+                                if (item.id !== cur_tender_uid) {
+                                    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>';
+                        });
+                        $('#tourist_dropdownMenu .book-list').empty();
+                        $('#tourist_dropdownMenu .book-list').append(html);
+                    }
+                }
+            }, 400);
+        });
+
+        // 添加审批流程按钮逻辑
+        $('body').on('click', '#tourist_dropdownMenu .book-list 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;
+        });
+
+        // 选中用户
+        $('body').on('click', '#tourist_dropdownMenu dl dd', function () {
+            const id = parseInt($(this).data('id'));
+            if (id) {
+                const user = _.find(accountList, function (item) {
+                    return item.id === id;
+                });
+                const saIdList = [];
+                for (let i = 0; i < $('#tourist-users li').length; i++) {
+                    saIdList.push(parseInt($('#tourist-users li').eq(i).data('id')));
+                }
+                if (_.includes(saIdList, id)) {
+                    toastr.error('该用户已存在列表中,无需重复添加');
+                    return;
+                }
+
+                const prop = {
+                    user_id: id,
+                    type: 'add',
+                };
+                postData('/tender/' + cur_tenderid + '/tourist/audit/save', prop, function (data) {
+                    const html = '<li class="list-group-item"  data-id="' + user.id + '">\n' +
+                        '<a href="javascript:void(0);" class="text-danger pull-right remove-tourist-user" data-id="' + data.id + '">移除</a>' + user.name + '  ' +
+                        '<small class="text-muted">' + user.role + '</small><p class="m-0 ml-2"><small class="text-muted">' + user.company + '</small></p></li>';
+                    $('#tourist-users').append(html);
+                    // 外面显示游客数量
+                    const num = $('#tourist-users li').length;
+                    if (!$('#tourist-num').hasClass('badge')) {
+                        $('#tourist-num').addClass('badge badge-secondary').text(num);
+                    } else {
+                        $('#tourist-num').text(num);
+                    }
+                });
+            }
+        });
 
+        // 移除用户
+        $('body').on('click', '#tourist-users .remove-tourist-user', function () {
+            const id = parseInt($(this).data('id'));
+            if (id) {
+                const prop = {
+                    id,
+                    type: 'del',
+                };
+                const _self = $(this);
+                postData('/tender/' + cur_tenderid + '/tourist/audit/save', prop, function (data) {
+                    _self.parents('li').remove();
+                    // 外面显示游客数量
+                    const num = $('#tourist-users li').length;
+                    if (num == 0) {
+                        $('#tourist-num').removeClass('badge badge-secondary').text('');
+                    } else {
+                        $('#tourist-num').text(num);
+                    }
+                });
+            }
+        });
+    });
+</script>
+<% } %>
 <% if (ctx.session.sessionProject.page_show !== null && parseInt(ctx.session.sessionProject.page_show.xxjd) === 1 && ctx.session.sessionUser.is_admin) { %>
 <!--标段设置-形象进度-->
 <div class="modal fade" id="xxjd-set" data-backdrop="static">
@@ -1601,22 +1783,18 @@
 </div>
 <script>
     $(function () {
-        const accountGroup = JSON.parse(unescape('<%- escape(JSON.stringify(accountGroup)) %>'));
-        const accountList = JSON.parse(unescape('<%- escape(JSON.stringify(accountList)) %>'));
-        const cur_uid = parseInt('<%- ctx.tender.data.user_id %>');
-        const cur_tenderid = parseInt('<%- ctx.tender.id %>');
         const scPermission = JSON.parse(unescape('<%- escape(JSON.stringify(scPermission)) %>'));
         // 形象进度
         let timer = null;
         let oldSearchVal = null;
-        $('body').on('input propertychange', '.gr-search', function(e) {
+        $('body').on('input propertychange', '#xxjd_dropdownMenu .gr-search', function(e) {
             oldSearchVal = e.target.value;
             timer && clearTimeout(timer);
             timer = setTimeout(() => {
                 const newVal = $(this).val();
                 let html = '';
                 if (newVal && newVal === oldSearchVal) {
-                    accountList.filter(item => item && item.id !== cur_uid && (item.name.indexOf(newVal) !== -1 || (item.mobile && item.mobile.indexOf(newVal) !== -1))).forEach(item => {
+                    accountList.filter(item => item && item.id !== cur_tender_uid && (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>
@@ -1633,7 +1811,7 @@
                         </a> ${group.groupName}</dt>
                         <div class="dd-content" data-toggleid="${idx}">`;
                             group.groupList.forEach(item => {
-                                if (item.id !== cur_uid) {
+                                if (item.id !== cur_tender_uid) {
                                     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>
@@ -1651,7 +1829,7 @@
         });
 
         // 添加审批流程按钮逻辑
-        $('body').on('click', '.book-list dt', function () {
+        $('body').on('click', '#xxjd_dropdownMenu .book-list dt', function () {
             const idx = $(this).find('.acc-btn').attr('data-groupid');
             const type = $(this).find('.acc-btn').attr('data-type');
             if (type === 'hide') {
@@ -1670,7 +1848,7 @@
         });
 
         // 选中用户
-        $('body').on('click', 'dl dd', function () {
+        $('body').on('click', '#xxjd_dropdownMenu dl dd', function () {
             const id = parseInt($(this).data('id'));
             if (id) {
                 const user = _.find(accountList, function (item) {
@@ -1709,7 +1887,7 @@
         });
 
         // 移除用户
-        $('body').on('click', '.remove-schedule-user', function () {
+        $('body').on('click', '#schedule-users .remove-schedule-user', function () {
             const id = parseInt($(this).data('id'));
             if (id) {
                 const prop = {

+ 1 - 1
app/view/tender/tender_sub_menu.ejs

@@ -43,7 +43,7 @@
                 <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/material') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/measure/material"><i class="fa fa-line-chart"></i> <span>材料调差</span></a></li>
             </ul>
         </div>
-        <% if (ctx.session.sessionProject.page_show !== null && parseInt(ctx.session.sessionProject.page_show.xxjd) === 1 && ctx.tender.schedule_permission !== 0) { %>
+        <% if (ctx.session.sessionProject.page_show !== null && parseInt(ctx.session.sessionProject.page_show.xxjd) === 1 && (ctx.tender.schedule_permission !== 0 || ctx.tender.isTourist)) { %>
         <div class="nav-box">
             <h3><i class="fa fa-bar-chart "></i> 形象进度</h3>
             <ul class="nav-list list-unstyled sub-list">

+ 1 - 1
app/view/tender/tender_sub_mini_menu.ejs

@@ -47,7 +47,7 @@
                 <li <% if (ctx.url === '/tender/' + ctx.tender.id + '/measure/material') { %>class="active"<% } %>><a href="/tender/<%- ctx.tender.id %>/measure/material"><i class="fa fa-line-chart"></i> <span>材料调差</span></a></li>
             </ul>
         </div>
-        <% if (ctx.session.sessionProject.page_show !== null && parseInt(ctx.session.sessionProject.page_show.xxjd) === 1 && ctx.tender.schedule_permission !== 0) { %>
+        <% if (ctx.session.sessionProject.page_show !== null && parseInt(ctx.session.sessionProject.page_show.xxjd) === 1 && (ctx.tender.schedule_permission !== 0|| ctx.tender.isTourist)) { %>
         <div class="nav-box">
             <h3><i class="fa fa-bar-chart "></i> 形象进度</h3>
             <ul class="nav-list list-unstyled sub-list">

+ 0 - 3
config/config.default.js

@@ -84,9 +84,6 @@ module.exports = appInfo => {
 
     // 安全性配置
     config.security = {
-        xframe: {
-            enable: false, // X-Frame-Options 内嵌关闭
-        },
         csrf: {
             ignoreJSON: false, // 默认为 false,当设置为 true 时,将会放过所有 content-type 为 `application/json` 的请求
             cookieName: 'csrfToken_j',    // csrf token's cookie name