Просмотр исходного кода

feat: 新增变更管理相关接口,优化变更审核逻辑

lanjianrong 1 месяц назад
Родитель
Сommit
957b6b791e
3 измененных файлов с 269 добавлено и 0 удалено
  1. 30 0
      app/const/weapp.js
  2. 236 0
      app/controller/weapp_tender_controller.js
  3. 3 0
      app/router.js

+ 30 - 0
app/const/weapp.js

@@ -7,6 +7,35 @@ const jwtSecret = '.wxapp_jwt_#*%)@!2nf874';
 const accessTokenExpiresIn = '2h'; // 业务token
 const refreshTokenExpiresIn = '7d'; // 续签token
 const redisExpire = 7 * 24 * 3600; // Redis 7天
+
+// 变更令相关映射
+const changeMap = {
+    change: {
+        service: 'change',
+        auditService: 'changeAudit',
+        idKey: 'cid',
+        pageShowKey: '',
+    },
+    changePlan: {
+        service: 'changePlan',
+        auditService: 'changePlanAudit',
+        idKey: 'id',
+        pageShowKey: 'openChangePlan',
+    },
+    changeApply: {
+        service: 'changeApply',
+        auditService: 'changeApplyAudit',
+        idKey: 'id',
+        pageShowKey: 'openChangeApply',
+    },
+    changeProject: {
+        service: 'changeProject',
+        auditService: 'changeProjectAudit',
+        idKey: 'id',
+        pageShowKey: 'openChangeProject',
+    },
+};
+
 module.exports = {
     baseUrl,
     AppID,
@@ -15,4 +44,5 @@ module.exports = {
     accessTokenExpiresIn,
     refreshTokenExpiresIn,
     redisExpire,
+    changeMap,
 };

+ 236 - 0
app/controller/weapp_tender_controller.js

@@ -1,5 +1,6 @@
 'use strict';
 const auditConst = require('../const/audit');
+const changeMap = require('../const/weapp').changeMap;
 const measureType = require('../const/tender').measureType;
 const advanceConst = require('../const/advance');
 const shenpiConst = require('../const/shenpi');
@@ -445,6 +446,241 @@ module.exports = app => {
                 ctx.body = { code: -1, msg: error.toString(), data: null };
             }
         }
+
+        async changeList(ctx) {
+            try {
+                const { type } = ctx.request.query;
+                const curChangeMap = changeMap[type];
+                if (!curChangeMap) {
+                    throw '变更类型错误';
+                }
+                const tender = ctx.tender.data;
+                const list = await ctx.service[curChangeMap.service].getListByStatus(tender.id, 0, 1, 0, 0, 0);
+
+                ctx.body = { code: 0, msg: '', data: list };
+            } catch (error) {
+                this.log(error);
+                ctx.body = { code: -1, msg: error.toString(), data: null };
+            }
+        }
+
+        async changeCheck(ctx) {
+            try {
+                const { type } = ctx.request.query || ctx.request.body;
+                const curChangeMap = changeMap[type];
+                const subProject = await ctx.service.subProject.getDataById(ctx.tender.data.spid);
+                if (curChangeMap && curChangeMap.pageShowKey && !subProject.page_show[curChangeMap.pageShowKey]) {
+                    throw '该功能已关闭';
+                }
+                const id = ctx.request.query.id || this.request.body.id;
+                if (!id) {
+                    throw '您访问的变更数据不存在';
+                }
+                const condition = { [type === 'change' ? 'cid' : 'id']: id };
+                const change = await ctx.service[curChangeMap.service].getDataByCondition(condition);
+                console.log(change);
+
+                if (!change) throw '变更方案数据有误';
+                // 读取原报、审核人数据
+                await ctx.service[curChangeMap.service].loadChangeUser(change);
+                // decimal小数位设置
+                change.decimal = change.decimal ? JSON.parse(change.decimal) : { tp: ctx.tender.info.decimal.tp, up: ctx.tender.info.decimal.up, precision: ctx.tender.info.precision };
+
+                // 权限相关
+                // todo 校验权限 (标段参与人、分享)
+                const accountId = ctx.session.sessionUser.accountId,
+                    shareIds = [];
+                const permission = ctx.session.sessionUser.permission;
+                const status = auditConst[type].status;
+
+                if (accountId === change.uid) { // 原报
+                    change.curTimes = change.times;
+                    change.filePermission = true;
+                } else if (change.auditorIds.indexOf(accountId) !== -1) { // 审批人
+                    if (change.status === status.uncheck) {
+                        throw '您无权查看该数据';
+                    }
+                    // change.readOnly = change.status !== status.checking || accountId !== change.curAuditor.aid;
+                    change.curTimes = change.status === status.checkNo || change.status === status.revise ? change.times - 1 : change.times;
+                    change.filePermission = true;
+                } else if ((change.status === status.checkNo || change.status === status.revise) && change.uid !== accountId) {
+                    const preAuditors = await ctx.service[curChangeMap.auditService].getAuditors(change.id, change.times - 1);
+                    const preAuditorIds = _.map(preAuditors, 'aid');
+                    if (preAuditorIds.indexOf(accountId) === -1) {
+                        throw '您无权查看该数据';
+                    }
+                    change.filePermission = true;
+                } else if (ctx.tender.isTourist || ctx.session.sessionUser.is_admin) {
+                    change.curTimes = change.times;
+                    change.filePermission = ctx.tender.touristPermission.file || change.auditorIds.indexOf(accountId) !== -1;
+                } else if (shareIds.indexOf(accountId) !== -1 || (permission !== null && permission.tender !== undefined && permission.tender.indexOf('2') !== -1)) { // 分享人
+                    if (change.status === auditConsts[type].status.uncheck) {
+                        throw '您无权查看该数据';
+                    }
+                    // change.readOnly = true;
+                    change.curTimes = change.status === auditConsts[type].status.checkNo || change.status === auditConsts[type].status.revise ? change.times - 1 : change.times;
+                    change.filePermission = false;
+                } else { // 其他不可见
+                    throw '您无权查看该数据';
+                }
+                // 调差的readOnly 指表格和页面只能看不能改,和审批无关
+                change.readOnly = !((change.status === status.uncheck || change.status === status.checkNo || change.status === status.revise) && accountId === change.uid);
+                change.shenpiPower = change.status === status.checking && change.curAuditorIds.indexOf(accountId) !== -1;
+                this.change = change;
+                await ctx.service[curChangeMap.service].doCheckChangeCanCancel(this.change);
+            } catch (error) {
+                this.log(error);
+                ctx.body = { code: -1, msg: error.toString(), data: null };
+            }
+        }
+
+        async changeDetail(ctx) {
+            try {
+                await this.changeCheck(ctx);
+                const { type } = ctx.request.query || ctx.request.body;
+                const curChangeMap = changeMap[type];
+                await ctx.service[curChangeMap.service].loadChangeUser(this.change);
+                await ctx.service[curChangeMap.service].loadChangeAuditViewData(this.change);
+
+                const tpUnit = ctx.tender.info.decimal.tp;
+                const subProject = await ctx.service.subProject.getDataById(ctx.tender.data.spid);
+                const fun_set = subProject.fun_set;
+
+                const auditHistory = this.change.auditHistory && this.change.auditHistory.length && this.change.auditHistory[this.change.auditHistory.length - 1].reduce((prev, curr, idx) => {
+                    prev.push({
+                        name: curr.is_final ? '终审' : curr.audit_order === 0 ? '原报' : `${curr.audit_order}审`,
+                        audit_type: curr.audit_type,
+                        status: curr.status,
+                        auditors: curr.auditors.map(a => ({...a, audit_id: a.uid})),
+                    });
+                    return prev;
+                }, []);
+                const curAuditors = this.change.curAuditors;
+
+                const change = {
+                    id: this.change.id || this.change.cid,
+                    name: this.change.name,
+                    status: this.change.status,
+                    code: this.change.code,
+                    p_code: this.change.p_code,
+                    quality: this.change.quality,
+                    auditHistory,
+                    originHistory: this.change.auditHistory,
+                    curAuditors: curAuditors.map(a => ({...a, audit_id: a.uid})),
+                    total_price: ctx.helper.add(this.change.total_price, tpUnit),
+                    valuation_tp: ctx.helper.add(this.change.valuation_tp, tpUnit),
+                    unvaluation_tp: ctx.helper.add(this.change.unvaluation_tp, tpUnit),
+                    state_name: subProject.page_show.openChangeState ? ctx.helper._.find(fun_set.change_state, { order: this.change.state }).name : '',
+                    plan_code: this.change.plan_code,
+                    peg: this.change.peg,
+                    org_name: this.change.org_name,
+                };
+
+                ctx.body = { code: 0, msg: '', data: {
+                    change,
+                } };
+            } catch (error) {
+                this.log(error);
+                ctx.body = { code: -1, msg: error.toString(), data: null };
+            }
+        }
+
+        async changeAuditCheck(ctx) {
+            const id = ctx.request.body.id;
+            if (!id) {
+                throw '您访问的变更数据不存在';
+            }
+            const type = ctx.request.body.type;
+            const curChangeMap = changeMap[type];
+            if (!this.change) {
+                const change = await this.service[curChangeMap.service].getDataById(id);
+                if (!change) throw '变更数据有误';
+                await this.service[curChangeMap.service].loadChangeUser(change);
+                this.change = change;
+            }
+            const change = this.change;
+            const status = auditConst[type].status;
+            if ((change.status === status.uncheck || change.status === status.checkNo || change.status === status.revise) && ctx.tender.info.shenpi.change !== shenpiConst.sp_status.sqspr) {
+                const shenpi_status = ctx.tender.info.shenpi.change;
+                // 进一步比较审批流是否与审批流程设置的相同,不同则替换为固定审批流或固定的终审
+                const auditList = await ctx.service[curChangeMap.auditService].getAllDataByCondition({ where: { caid: change.id, times: change.times }, orders: [['order', 'asc']] });
+                if (shenpi_status === shenpiConst.sp_status.gdspl) {
+                    // 判断并获取审批组
+                    const group = await ctx.service.shenpiGroup.getSelectGroupByChangeType(ctx.tender.id, shenpiConst.sp_type.change, type, change.sp_group);
+                    if ((group && change.sp_group !== group.id) || (!group && change.sp_group !== 0)) {
+                        change.sp_group = group ? group.id : 0;
+                        await ctx.service[curChangeMap.service].defaultUpdate({ id: change.id, sp_group: change.sp_group });
+                    }
+                    const condition = { tid: ctx.tender.id, sp_type: shenpiConst.sp_type.change, sp_status: shenpi_status, sp_group: change.sp_group };
+                    const shenpiList = await ctx.service.shenpiAudit.getAllDataByCondition({ where: condition, orders: [['audit_order', 'asc']] });
+                    await ctx.service.shenpiAudit.noYbShenpiList(change.uid, shenpiList);
+                    if (change.sp_group === 0 && shenpiList.length === 0) {
+                        ctx.tender.info.shenpi.change = shenpiConst.sp_status.sqspr;
+                    } else {
+                        // 判断2个id数组是否相同,不同则删除原审批流,切换成固定的审批流
+                        let sameAudit = auditList.length === shenpiList.length;
+                        if (sameAudit) {
+                            for (const audit of auditList) {
+                                const shenpi = shenpiList.find(x => { return x.audit_id === audit.aid; });
+                                if (!shenpi || shenpi.audit_order !== audit.audit_order || shenpi.audit_type !== audit.audit_type) {
+                                    sameAudit = false;
+                                    break;
+                                }
+                            }
+                        }
+                        if (!sameAudit) {
+                            await ctx.service[curChangeMap.auditService].updateNewAuditList(change, shenpiList);
+                            await ctx.service[curChangeMap.service].loadChangeUser(change);
+                            await ctx.service[curChangeMap.service].doCheckChangeCanCancel(change);
+                        }
+                    }
+                } else if (shenpi_status === shenpiConst.sp_status.gdzs) {
+                    const shenpiInfo = await ctx.service.shenpiAudit.getDataByCondition({ tid: ctx.tender.id, sp_type: shenpiConst.sp_type.change, sp_status: shenpi_status });
+                    if (!shenpiInfo || (shenpiInfo && shenpiInfo.audit_id === change.uid)) {
+                        // 不存在终审人 或 存在终审但与原报相同时, 这里恢复为授权审批人
+                        ctx.tender.info.shenpi.change = shenpiConst.sp_status.sqspr;
+                    } else {
+                        // 判断最后一个id是否与固定终审id相同,不同则删除原审批流中如果存在的id和添加终审
+                        const lastAuditors = auditList.filter(x => {
+                            return x.order === auditList.length - 1;
+                        });
+                        if (shenpiInfo && (lastAuditors.length === 0 || (lastAuditors.length > 1 || shenpiInfo.audit_id !== lastAuditors[0].aid))) {
+                            await ctx.service[curChangeMap.auditService].updateLastAudit(change, auditList, shenpiInfo.audit_id);
+                            await ctx.service[curChangeMap.service].loadChangeUser(change);
+                            await ctx.service[curChangeMap.service].doCheckChangeCanCancel(change);
+                        }
+                    }
+                }
+            }
+        }
+
+        async changeAudit(ctx) {
+            try {
+                const { type } = ctx.request.body;
+                await this.changeCheck(ctx);
+                await this.changeAuditCheck(ctx);
+                const curChangeMap = changeMap[type];
+                const auditConst = auditConsts[type];
+                if (!ctx.change || ctx.change.status !== auditConst.status.checking) {
+                    throw '当前变更申请数据有误';
+                }
+                if (ctx.change.curAuditorIds.length === 0 || ctx.change.curAuditorIds.indexOf(ctx.session.sessionUser.accountId) === -1) {
+                    throw '您无权进行该操作';
+                }
+                const data = {
+                    checkType: parseInt(ctx.request.body.checkType),
+                    opinion: ctx.request.body.opinion,
+                };
+                if (!data.checkType || isNaN(data.checkType)) {
+                    throw '提交数据错误';
+                }
+                await ctx.service[auditConst.auditService].check(ctx.change.id, data, ctx.change.times);
+                ctx.body = { code: 0, msg: '操作成功', data: null };
+            } catch (error) {
+                this.log(error);
+                ctx.body = { code: -1, msg: error.toString(), data: null };
+            }
+        }
     }
 
     return WeappTenderController;

+ 3 - 0
app/router.js

@@ -1261,4 +1261,7 @@ module.exports = app => {
     app.post('/wx/weapp/advance/audit', weappAuth, weappTenderCheck, 'weappTenderController.advanceAudit');
     app.get('/wx/weapp/ledger/detail', weappAuth, weappTenderCheck, 'weappTenderController.ledgerDetail');
     app.post('/wx/weapp/ledger/audit', weappAuth, weappTenderCheck, 'weappTenderController.ledgerAudit');
+    app.get('/wx/weapp/change/list', weappAuth, weappTenderCheck, 'weappTenderController.changeList');
+    app.get('/wx/weapp/change/detail', weappAuth, weappTenderCheck, 'weappTenderController.changeDetail');
+    app.post('/wx/weapp/change/audit', weappAuth, weappTenderCheck, 'weappTenderController.changeAudit');
 };