'use strict'; const accountGroup = require('../const/account_group').group; const JV = require('../reports/rpt_component/jpc_value_define'); const shenpiConst = require('../const/shenpi'); const auditConst = require('../const/audit').stage; const paymentConst = require('../const/payment'); const moment = require('moment'); const path = require('path'); const sendToWormhole = require('stream-wormhole'); const fs = require('fs'); module.exports = app => { class PaymentController extends app.BaseController { /** * 构造函数 * * @param {Object} ctx - egg全局变量 * @return {void} */ constructor(ctx) { super(ctx); ctx.showProject = true; // ctx.showTitle = true; } /** * 支付审批列表页 * * @param {Object} ctx - egg全局页面 * @return {void} */ async index(ctx) { try { const auditPermission = await this.ctx.service.paymentPermissionAudit.getOnePermission(ctx.session.sessionUser.is_admin, ctx.session.sessionUser.accountId); if (!auditPermission) { throw '权限不足'; } // 列表读取及目录读取 const renderData = { auditPermission, jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.payment.index), }; if (ctx.session.sessionUser.is_admin) { const projectId = ctx.session.sessionProject.id; const permissionAudits = await ctx.service.paymentPermissionAudit.getList(projectId); // 获取所有项目参与者 const accountList = await ctx.service.projectAccount.getAllDataByCondition({ where: { project_id: ctx.session.sessionProject.id, enable: 1 }, columns: ['id', 'name', 'company', 'role', 'enable', 'is_admin', 'account_group', 'mobile'], }); const unitList = await ctx.service.constructionUnit.getAllDataByCondition({ where: { pid: projectId } }); const accountGroupList = unitList.map(item => { const groupList = accountList.filter(item1 => item1.company === item.name); return { groupName: item.name, groupList }; }); // const accountGroupList = accountGroup.map((item, idx) => { // const groupList = accountList.filter(item => item.account_group === idx); // return { groupName: item, groupList }; // }); renderData.permissionAudits = permissionAudits; renderData.accountList = accountList; renderData.accountGroup = accountGroupList; } await this.layout('payment/index.ejs', renderData, 'payment/modal.ejs'); } catch (err) { console.log(err); this.log(err); ctx.session.postError = err.toString(); ctx.redirect(this.menu.menu.dashboard.url); } } async listLoad(ctx) { const responseData = { err: 0, msg: '', data: {}, }; const auditPermission = await this.ctx.service.paymentPermissionAudit.getOnePermission(ctx.session.sessionUser.is_admin, ctx.session.sessionUser.accountId); if (!auditPermission) { throw '权限不足'; } // 先获取你创建的标段及参与的标段 const tenderList = await ctx.service.paymentTender.getList(ctx.session.sessionUser.accountId, auditPermission); // 获取你创建的目录及对应目录下的所有目录 const folderList = await ctx.service.paymentFolder.getList(ctx.session.sessionUser.accountId, tenderList, auditPermission); if (tenderList.length > 0) { for (const t of tenderList) { t.have_notice = await ctx.service.paymentDetail.haveNotice2Tender(t.id, ctx.session.sessionUser.accountId); t.have_detail = await ctx.service.paymentDetail.haveDetail2Tender(t.id); } } responseData.data.folderList = ctx.helper._.orderBy(folderList, ['in_time'], ['asc']); responseData.data.tenderList = ctx.helper._.orderBy(tenderList, ['in_time'], ['asc']); ctx.body = responseData; } async permissionSave(ctx) { try { if (ctx.session.sessionUser.is_admin === 0) throw '没有设置权限'; const projectId = ctx.session.sessionProject.id; const responseData = { err: 0, msg: '', data: null, }; const data = JSON.parse(ctx.request.body.data); if (!data.type) { throw '提交数据错误'; } let uids; let result = false; let auditList = []; switch (data.type) { case 'add-audit': // 判断用户是单个还是数组 uids = data.id instanceof Array ? data.id : [data.id]; // 判断该用户的组是否已加入到表中,已加入则提示无需添加 auditList = await ctx.service.paymentPermissionAudit.getAllDataByCondition({ where: { pid: projectId, uid: uids } }); const addAidList = ctx.helper._.difference(uids, ctx.helper._.map(auditList, 'uid')); if (addAidList.length === 0) { throw '用户已存在权限中,无需重复添加'; } const accountList = await ctx.service.projectAccount.getAllDataByCondition({ where: { id: addAidList } }); await ctx.service.paymentPermissionAudit.saveAudits(projectId, accountList); responseData.data = await ctx.service.paymentPermissionAudit.getList(projectId); break; case 'del-audit': uids = data.id instanceof Array ? data.id : [data.id]; auditList = await ctx.service.paymentPermissionAudit.getAllDataByCondition({ where: { id: uids } }); if (auditList.length !== uids.length) { throw '该用户已不存在权限中,移除失败'; } await ctx.service.paymentPermissionAudit.delAudit(uids); responseData.data = await ctx.service.paymentPermissionAudit.getList(projectId); break; case 'save-permission-one': result = await ctx.service.paymentPermissionAudit.updateOnePermission(data.updateData); if (!result) { throw '修改权限失败'; } break; // case 'save-permission-all': // result = await ctx.service.paymentPermissionAudit.updateAllPermission(projectId, data.permission_type, data.value); // if (!result) { // throw '修改权限失败'; // } // responseData.data = await ctx.service.paymentPermissionAudit.getList(projectId); // break; default: throw '参数有误'; } ctx.body = responseData; } catch (err) { this.log(err); ctx.body = { err: 1, msg: err.toString(), data: null }; } } async save(ctx) { try { const projectId = ctx.session.sessionProject.id; const auditPermission = await this.ctx.service.paymentPermissionAudit.getOnePermission(ctx.session.sessionUser.is_admin, ctx.session.sessionUser.accountId); if (!auditPermission) { throw '权限不足'; } const responseData = { err: 0, msg: '', data: {}, }; const data = JSON.parse(ctx.request.body.data); if (!data.type) { throw '提交数据错误'; } if (!auditPermission.admin) { throw '您没有权限操作此功能'; } let type = ''; switch (data.type) { case 'add-folder': await ctx.service.paymentFolder.addFolder(projectId, ctx.session.sessionUser.accountId, data.parentId, data.name); break; case 'add-tender': await ctx.service.paymentTender.addTender(projectId, ctx.session.sessionUser.accountId, data.folderId, data.name); break; case 'edit-name': type = data.postData.type; const updateData = { name: data.postData.name, }; const conditionData = { id: data.postData.id, }; if (type === 'tender') { const tenderInfo = await ctx.service.paymentTender.getDataById(conditionData.id); if (!tenderInfo) throw '标段不存在'; if (tenderInfo.uid !== ctx.session.sessionUser.accountId && !ctx.session.sessionUser.is_admin) { throw '您没有权限重命名此标段'; } await ctx.service.paymentTender.update(updateData, conditionData); } else { const folderInfo = await ctx.service.paymentFolder.getDataById(conditionData.id); if (!folderInfo) throw '文件夹不存在'; if (folderInfo.uid !== ctx.session.sessionUser.accountId && !ctx.session.sessionUser.is_admin) { throw '您没有权限重命名此文件夹'; } await ctx.service.paymentFolder.update(updateData, conditionData); } break; case 'del': type = data.postData.type; if (type === 'tender') { await ctx.service.paymentTender.deleteTender(data.postData.id); } else { await ctx.service.paymentFolder.deleteFolder(data.postData.id); } break; case 'mode-setting': if (!ctx.session.sessionUser.is_admin) { throw '您无权操作'; } const projectInfo = await ctx.service.project.getDataById(ctx.session.sessionProject.id); const modes = projectInfo.payment_setting ? JSON.parse(projectInfo.payment_setting) : ctx.helper._.cloneDeep(paymentConst.setting_modes); const checked = data.checked; if (modes[data.mode_type]) { const detailCount = await ctx.service.paymentDetail.getCountByPidType(ctx.session.sessionProject.id, modes[data.mode_type].value); if (detailCount > 0 && !checked) { throw '已存在对应模块的详情,无法关闭该模块'; } const mode = modes[data.mode_type]; if (mode.checked === checked) { throw '已选中该模块,无须重复选中'; } mode.checked = checked; } else if (paymentConst.setting_modes[data.mode_type]) { modes[data.mode_type] = ctx.helper._.cloneDeep(paymentConst.setting_modes[data.mode_type]); modes[data.mode_type].checked = checked; } else { throw '该模块不存在'; } await ctx.service.project.defaultUpdate({ id: ctx.session.sessionProject.id, payment_setting: JSON.stringify(modes) }); break; default: throw '参数有误'; } // 先获取你创建的标段及参与的标段 const tenderList = await ctx.service.paymentTender.getList(ctx.session.sessionUser.accountId, auditPermission); // 获取你创建的目录及对应目录下的所有目录 const folderList = await ctx.service.paymentFolder.getList(ctx.session.sessionUser.accountId, tenderList, auditPermission); responseData.data.folderList = ctx.helper._.orderBy(folderList, ['in_time'], ['asc']); responseData.data.tenderList = ctx.helper._.orderBy(tenderList, ['in_time'], ['asc']); ctx.body = responseData; } catch (err) { this.log(err); ctx.body = { err: 1, msg: err.toString(), data: null }; } } async setting(ctx) { try { if (!ctx.session.sessionUser.is_admin) { throw '您无权打开此页'; } const projectInfo = await ctx.service.project.getDataById(ctx.session.sessionProject.id); const modes = projectInfo.payment_setting ? JSON.parse(projectInfo.payment_setting) : ctx.helper._.cloneDeep(paymentConst.setting_modes); for (const m in modes) { const detailCount = await ctx.service.paymentDetail.getCountByPidType(ctx.session.sessionProject.id, modes[m].value); modes[m].can_check = !detailCount; } const renderData = { setting_modes: paymentConst.setting_modes, modes, jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.payment.setting), }; await this.layout('payment/setting.ejs', renderData); } catch (err) { console.log(err); this.log(err); ctx.session.postError = err.toString(); ctx.redirect('/payment'); } } /** * 获取审批界面所需的 原报、审批人数据等 * @param ctx * @return {Promise} * @private */ async _getDetailAuditViewData(ctx) { const times = ctx.detail.status === auditConst.status.checkNo ? ctx.detail.times - 1 : ctx.detail.times; ctx.detail.user = await ctx.service.projectAccount.getAccountInfoById(ctx.detail.uid); ctx.detail.auditHistory = []; if (times >= 1) { for (let i = 1; i <= times; i++) { ctx.detail.auditHistory.push(await ctx.service.paymentDetailAudit.getAuditors(ctx.detail.id, i)); } } // 获取审批流程中左边列表 ctx.detail.auditors2 = ctx.detail.status === auditConst.status.checkNo && ctx.detail.uid !== ctx.session.sessionUser.accountId ? await ctx.service.paymentDetailAudit.getAuditorsWithOwner(ctx.detail.id, times) : await ctx.service.paymentDetailAudit.getAuditorsWithOwner(ctx.detail.id, ctx.detail.times); if (ctx.detail.status === auditConst.status.uncheck || ctx.detail.status === auditConst.status.checkNo) { ctx.detail.auditorList = await ctx.service.paymentDetailAudit.getAuditors(ctx.detail.id, ctx.detail.times); } // 是否已验证手机短信 const pa = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId); ctx.detail.authMobile = pa.auth_mobile; } /** * 支付表单页面 * * @param {Object} ctx - egg全局页面 * @return {void} */ async detail(ctx) { try { await this._getDetailAuditViewData(ctx); // 报表信息实时更新 if (ctx.trInfo.uid === ctx.session.sessionUser.accountId && ctx.trInfo.is_del === 0 && ctx.trInfo.rpt_id && (ctx.detail.status === auditConst.status.uncheck || ctx.detail.status === auditConst.status.checkNo)) { const rptTpl = await ctx.service.rptTpl.getDataById(ctx.trInfo.rpt_id); if (rptTpl) { const pageRst = await ctx.service.jpcReport.getAllPreviewPagesCommon(rptTpl, 'A4'); const rptMsg = pageRst.items[0]; // 判断与原有的报表审批人列表是否有区别 let difference = false; let auditDifference = false; let needChange = false; if (ctx.trInfo.report_items_json) { const report_items_json = JSON.parse(ctx.trInfo.report_items_json); const items = ['cells', 'signature_audit_cells', 'signature_cells', 'signature_date_cells', 'interact_cells']; for (const item of items) { if (report_items_json[item] && !ctx.helper._.isEmpty(ctx.helper._.differenceWith(JSON.parse(JSON.stringify(rptMsg[item])), report_items_json[item], ctx.helper._.isEqual))) { // 因为interact_cells里存在undefind值,必须先用JSON.parse和JSON.stringify转义才能对比 difference = true; needChange = true; if (item === 'signature_cells') { auditDifference = true; } // break; } } } else { difference = true; } if (difference) { // 删除rpt_audit重新配置 const updateData = { id: ctx.trInfo.id, report_items_json: JSON.stringify(ctx.helper._.cloneDeep(rptMsg)), }; // 删除rpt_audit重新配置 if (auditDifference) { updateData.rpt_audit = null; ctx.trInfo.rpt_audit = null; } if (needChange) { updateData.is_change = 1; ctx.trInfo.is_change = 1; } await ctx.service.paymentTenderRpt.defaultUpdate(updateData); ctx.trInfo.report_items_json = rptMsg; } } } const auditIdList = ctx.helper._.map(ctx.detail.auditors, 'aid'); const rptAuditIdList = ctx.helper._.map(ctx.detail.rptAudits, 'uid'); const uidList = ctx.helper._.uniq([...auditIdList, ...rptAuditIdList]); // 获取附件列表 const attList = await ctx.service.paymentDetailAtt.getPaymentDetailAttachment(ctx.detail.id, 'desc'); const renderData = { trInfo: ctx.trInfo, paymentConst, jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.payment.detail), auditConst, shenpiConst, attList, moment, whiteList: ctx.app.config.multipart.whitelist, uidList, preUrl: '/payment/' + ctx.paymentTender.id + '/detail/' + ctx.detail.id, OSS_PATH: ctx.app.config.fujianOssPath, }; renderData.nextDetail = await ctx.service.paymentDetail.getDataByCondition({ tr_id: ctx.trInfo.id, order: ctx.detail.order + 1 }); let report_json = JSON.parse(ctx.detail.report_json); const content = []; // 获取当前报表人 const rptAudit = await ctx.service.paymentRptAudit.getDataByCondition({ td_id: ctx.detail.id, uid: ctx.session.sessionUser.accountId }); if (report_json.items[0].interact_cells.length > 0) { for (const [i, cell] of report_json.items[0].interact_cells.entries()) { cell.index = i; } const numberList = ctx.helper._.filter(report_json.items[0].interact_cells, { DataType: 'intact_type_number' }); for (const [i, cell] of report_json.items[0].interact_cells.entries()) { if (cell.Label.indexOf('大写') !== -1 && cell.link === undefined) { if (numberList.length > 0) { const numberInfo = ctx.helper._.find(ctx.helper._.orderBy(numberList, ['index'], ['desc']), function(item) { return item.index < i; }); cell.link = numberInfo ? numberInfo.index : ''; } else { cell.link = ''; } } const push_item = { type: paymentConst.rpt_dataType[cell.DataType], value: cell.Prefix ? ctx.helper._.replace(cell.Value, cell.Prefix, '') : cell.Value, label: cell.Label, index: i, }; if (cell.link !== undefined) push_item.link = cell.link; const thisBandName = paymentConst.rpt_band_name[cell.BandName] ? cell.BandName : 'content'; const oneShowContent = ctx.helper._.find(content, { BandName: thisBandName }); if (oneShowContent) { oneShowContent.items.push(push_item); } else { content.push({ BandName: thisBandName, title: paymentConst.rpt_band_name[thisBandName], items: [push_item], }); } } renderData.numberList = numberList; if (rptAudit && ((ctx.detail.status !== auditConst.status.checkNo && ctx.detail.status !== auditConst.status.checked) || (ctx.detail.status === auditConst.status.checked && !renderData.nextDetail) || (ctx.detail.status === auditConst.status.checkNo && ctx.detail.uid === ctx.session.sessionUser.accountId))) { // 获取个人签字,单位章,个人章地址 const userInfo = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId); const stampPathList = userInfo.stamp_path ? userInfo.stamp_path.split('!;!') : []; const companyInfo = userInfo.company ? await ctx.service.constructionUnit.getDataByCondition({ pid: ctx.session.sessionProject.id, name: userInfo.company }) : {}; if (rptAudit.signature_msg) { const sign_msg = JSON.parse(rptAudit.signature_msg); report_json = await ctx.service.paymentDetail.signOneSignatureData(report_json, rptAudit.signature_name, sign_msg); rptAudit.signature_msg = sign_msg; } else { rptAudit.signature_msg = paymentConst.signature_msg; rptAudit.signature_msg.sign_path = userInfo.sign_path ? userInfo.sign_path : ''; } renderData.signPath = userInfo.sign_path ? userInfo.sign_path : ''; renderData.stampPathList = stampPathList; renderData.currentStamp = rptAudit && rptAudit.signature_msg.stamp_path ? rptAudit.signature_msg.stamp_path : (stampPathList.length > 0 ? stampPathList[0] : ''); renderData.companyStamp = companyInfo && companyInfo.sign_path ? companyInfo.sign_path : ''; } } renderData.rptAudit = rptAudit; renderData.content = content; renderData.report_json = report_json; if ((ctx.detail.status === auditConst.status.uncheck || ctx.detail.status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === ctx.detail.uid) { // data.accountGroup = accountGroup; // 获取所有项目参与者 const accountList = await ctx.service.projectAccount.getAllDataByCondition({ where: { project_id: ctx.session.sessionProject.id, enable: 1 }, columns: ['id', 'name', 'company', 'role', 'enable', 'is_admin', 'account_group', 'mobile'], }); renderData.accountList = accountList; const unitList = await ctx.service.constructionUnit.getAllDataByCondition({ where: { pid: ctx.session.sessionProject.id } }); const accountGroupList = unitList.map(item => { const groupList = accountList.filter(item1 => item1.company === item.name); return { groupName: item.name, groupList }; }); renderData.accountGroup = accountGroupList; } await this.layout('payment/detail.ejs', renderData, 'payment/detail_modal.ejs'); } catch (err) { console.log(err); this.log(err); ctx.session.postError = err.toString(); if (ctx.detail.tender_id && ctx.detail.tr_id) { ctx.redirect('/payment' + ctx.detail.tender_id + '/list/' + ctx.detail.tr_id); } ctx.redirect(this.menu.menu.dashboard.url); } } async detailSave(ctx) { try { const data = JSON.parse(ctx.request.body.data); if (!data.type) { throw '提交数据错误'; } // 检查权限等 if (ctx.detail.uid !== ctx.session.sessionUser.accountId && data.type !== 'update_sign') { throw '您无权操作'; } if (data.type !== 'update_sign' && ctx.detail.status !== auditConst.status.uncheck && ctx.detail.status !== auditConst.status.checkNo) { throw '您无权操作'; } const responseData = { err: 0, msg: '', data: {}, }; switch (data.type) { case 'update_rpt': responseData.data = await ctx.service.paymentDetail.updateReportJson(ctx.detail.id, data.report_json); break; case 'update_sign': if (ctx.detail.status === auditConst.status.checked) { // 判断是否存在下一期,是则无法签章 const detailMsg = await ctx.service.paymentDetail.getDataByCondition({ tr_id: ctx.detail.tr_id, order: ctx.detail.order + 1 }); if (detailMsg) { throw '您无法操作签字/签章'; } } responseData.data = await ctx.service.paymentRptAudit.updateSignatureMsg(ctx.detail.id, ctx.session.sessionUser.accountId, data.signature_msg); break; case 'add_audit': const auditorId = this.app._.toInteger(data.auditorId); if (isNaN(auditorId) || auditorId <= 0) { throw '参数错误'; } ctx.detail.auditorList = await ctx.service.paymentDetailAudit.getAuditors(ctx.detail.id, ctx.detail.times); // 检查审核人是否已存在 const exist = this.app._.find(ctx.detail.auditorList, { aid: auditorId }); if (exist) { throw '该审核人已存在,请勿重复添加'; } const shenpiInfo = await ctx.service.paymentShenpiAudit.getDataByCondition({ tr_id: ctx.trInfo.id, sp_status: shenpiConst.sp_status.gdzs }); const is_gdzs = shenpiInfo && ctx.trInfo.sp_status === shenpiConst.sp_status.gdzs ? 1 : 0; const result = await ctx.service.paymentDetailAudit.addAuditor(ctx.detail.id, auditorId, ctx.detail.times, is_gdzs); if (!result) { throw '添加审核人失败'; } responseData.data = await ctx.service.paymentDetailAudit.getAuditorsWithOwner(ctx.detail.id, ctx.detail.times); break; case 'del_audit': const auditorId2 = data.auditorId instanceof Number ? data.auditorId : this.app._.toNumber(data.auditorId); if (isNaN(auditorId2) || auditorId2 <= 0) { throw '参数错误'; } const result2 = await ctx.service.paymentDetailAudit.deleteAuditor(ctx.detail.id, auditorId2, ctx.detail.times); if (!result2) { throw '移除审核人失败'; } responseData.data = await ctx.service.paymentDetailAudit.getAuditors(ctx.detail.id, ctx.detail.times); break; case 'follow_rpt_audit': if (ctx.trInfo.shenpi_status === shenpiConst.sp_status.gdspl) { throw '当前表单已设置为固定审批流,无法同步'; } const result3 = await ctx.service.paymentDetailAudit.followAuditByRptAudit(ctx.detail); if (!result3) { throw '同步表单角色失败'; } responseData.data = await ctx.service.paymentDetailAudit.getAuditorsWithOwner(ctx.detail.id, ctx.detail.times); break; default: throw '参数有误'; } ctx.body = responseData; } catch (err) { this.log(err); ctx.body = { err: 1, msg: err.toString(), data: null }; } } async deleteDetail(ctx) { try { const detail_id = ctx.request.body.detail_id; const detailInfo = await ctx.service.paymentDetail.getDataById(detail_id); if (!detailInfo) { throw '所选报表表单详情已删除'; } // 获取最新的期数 const detail_highOrder = await ctx.service.paymentDetail.count({ tr_id: detailInfo.tr_id, }); if (!(ctx.session.sessionUser.is_admin || ((detailInfo.status === auditConst.status.uncheck || detailInfo.status === auditConst.status.checkNo) && detailInfo.uid === ctx.session.sessionUser.accountId)) || detail_highOrder !== detailInfo.order) { throw '您无权删除所选报表表单详情'; } const result = await ctx.service.paymentDetail.deleteDetail(detail_id); if (!result) { throw '删除报表表单详情失败,请重试'; } ctx.redirect('/payment/' + ctx.paymentTender.id + '/list/' + detailInfo.tr_id); } catch (err) { this.log(err); ctx.session.postError = err.toString(); ctx.redirect(ctx.request.header.referer); } } /** * 期审批流程(Get) * @param ctx * @return {Promise} */ async detailAuditors(ctx) { try { const responseData = { err: 0, msg: '', data: {}, }; const order = JSON.parse(ctx.request.body.data).order; const tr_id = ctx.params.trid; const detailInfo = await ctx.service.paymentDetail.getDataByCondition({ tr_id, order }); // 获取审批流程中右边列表 const auditHistory = []; const times = detailInfo.status === auditConst.status.checkNo ? detailInfo.times - 1 : detailInfo.times; if (times >= 1) { for (let i = 1; i <= times; i++) { auditHistory.push(await ctx.service.paymentDetailAudit.getAuditors(detailInfo.id, i)); } } responseData.data.auditHistory = auditHistory; // 获取审批流程中左边列表 responseData.data.auditors = await ctx.service.paymentDetailAudit.getAuditorsWithOwner(detailInfo.id, times); responseData.data.user = await ctx.service.projectAccount.getAccountInfoById(detailInfo.uid); ctx.body = responseData; } catch (error) { this.log(error); ctx.body = { err: 1, msg: error.toString(), data: null }; } } async _returnRptProjectList(ctx, formProcess = false) { // 获取报表表单列表 if (ctx.payment.auditPermission.view_all || ctx.paymentTender.uid === ctx.session.sessionUser.accountId || formProcess) { const rptProject = await ctx.service.rptTreeNode.getDataByCondition({ pid: ctx.session.sessionProject.id, name: '01.支付审批报表' }); const rptProjectList = []; const newRptList = rptProject && rptProject.items ? JSON.parse(rptProject.items) : []; ctx.rptListNum = 0; await this.getNewRptProjectList(ctx, newRptList, rptProjectList, 1); const tenderRptList = await ctx.service.paymentTenderRpt.getProcessList(ctx.paymentTender.id); if (tenderRptList === -1) { throw '未配置表单设置,请联系管理员处理'; } return await ctx.service.paymentTenderRpt.checkAndUpdateList(tenderRptList, rptProjectList, formProcess); } return await ctx.service.paymentTenderRpt.getList(ctx.paymentTender.id, ctx.session.sessionUser.accountId); } // 循环获取到到rptProject async getNewRptProjectList(ctx, newRptList, rptProjectList, level = 1) { if (newRptList.length > 0) { for (const r of newRptList) { r.level = level; r.index = ctx.rptListNum; ctx.rptListNum = ctx.rptListNum + 1; rptProjectList.push(r); if (r.items && r.items.length > 0) { await this.getNewRptProjectList(ctx, r.items, rptProjectList, level + 1); } } } } async process(ctx) { try { if (!ctx.payment.auditPermission || !ctx.payment.auditPermission.admin || !(ctx.session.sessionUser.is_admin || ctx.paymentTender.uid === ctx.session.sessionUser.accountId)) { throw '权限不足'; } let [tenderRptList, rptProjectList] = await this._returnRptProjectList(ctx, true); const safeRpt = tenderRptList.find(x => { return x.type === 1 }); tenderRptList = ctx.helper._.filter(tenderRptList, { type: 0, is_del: 0 }); // for (const tr of tenderRptList) { // if (tr.status === shenpiConst.sp_status.gdspl) { // tr.auditList = await ctx.service.paymentShenpiAudit.getAuditList(ctx.tender.id, tr.id, tr.sp_status); // } else if (tr.status === shenpiConst.sp_status.gdzs) { // tr.audit = await ctx.service.paymentShenpiAudit.getAudit(ctx.tender.id, tr.id, tr.sp_status); // } // } // 获取所有项目参与者 const accountList = await ctx.service.projectAccount.getAllDataByCondition({ where: { project_id: ctx.session.sessionProject.id, enable: 1 }, columns: ['id', 'name', 'company', 'role', 'enable', 'is_admin', 'account_group', 'mobile'], }); const unitList = await ctx.service.constructionUnit.getAllDataByCondition({ where: { pid: ctx.session.sessionProject.id } }); const accountGroupList = unitList.map(item => { const groupList = accountList.filter(item1 => item1.company === item.name); return { groupName: item.name, groupList }; }); const renderData = { tender: ctx.paymentTender, jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.payment.process), safeRpt, rptProjectList, tenderRptList, shenpi: shenpiConst, accountList, accountGroup: accountGroupList, }; await this.layout('payment/process.ejs', renderData, 'payment/process_modal.ejs'); } catch (err) { console.log(err); this.log(err); ctx.session.postError = err.toString(); ctx.redirect(this.request && this.request.headers && this.request.headers.referer ? this.request.headers.referer : '/payment'); } } async processSave(ctx) { try { if (!ctx.payment.auditPermission || !ctx.payment.auditPermission.admin) { throw '权限不足'; } const responseData = { err: 0, msg: '', data: {}, }; const data = JSON.parse(ctx.request.body.data); if (!data.type) { throw '提交数据错误'; } switch (data.type) { case 'add-rpt': responseData.data = await ctx.service.paymentTenderRpt.setRpt(ctx.paymentTender.id, data.rpt_list); break; case 'change-status': responseData.data = await ctx.service.paymentTenderRpt.setStatus(data.tr_id, data.status); break; case 'get-audits': responseData.data = await ctx.service.paymentShenpiAudit.getShenpiAudit(data.tr_id, data.status); break; case 'add-audit': responseData.data = await ctx.service.paymentShenpiAudit.addAudit(data); break; case 'del-audit': responseData.data = await ctx.service.paymentShenpiAudit.removeAudit(data); break; case 'update-report': responseData.data = await ctx.service.paymentTenderRpt.updateReport(data); break; default: throw '参数有误'; } ctx.body = responseData; } catch (err) { this.log(err); ctx.body = { err: 1, msg: err.toString(), data: null }; } } async rptList(ctx) { try { const tenderRptList = await this._returnRptProjectList(ctx); if (tenderRptList === -1) { throw '未配置表单设置,请联系管理员处理'; } if (tenderRptList.length === 0) { throw '未配置表单设置,请联系管理员处理'; } for (const tr of tenderRptList) { tr.have_notice = await ctx.service.paymentDetail.haveNotice2TenderRpt(tr.id, ctx.session.sessionUser.accountId); } const trid = ctx.params.trid ? parseInt(ctx.params.trid) : 0; const trInfo = trid ? ctx.helper._.find(tenderRptList, { id: trid }) : tenderRptList[0]; if (!trInfo) { throw '该模块已关闭或未进行表单审批设置'; } // 获取列表 const trDetailList = await ctx.service.paymentDetail.getValidDetails(trInfo.id); const accountList = await ctx.service.projectAccount.getAllDataByCondition({ where: { project_id: ctx.session.sessionProject.id, enable: 1 }, columns: ['id', 'name', 'company', 'role', 'enable', 'is_admin', 'account_group', 'mobile'], }); if (trDetailList.length > 0) { for (const s of trDetailList) { // s.curAuditor = null; // 根据期状态返回展示用户 s.curAuditor = await ctx.service.paymentDetailAudit.getAuditorByStatus(s.id, s.status, s.times); const userInfo = ctx.helper._.find(accountList, { id: s.uid }); s.user_name = userInfo ? userInfo.name : ''; } trDetailList[0].emptySign = await ctx.service.paymentRptAudit.haveEmptySign(trDetailList[0].id); } const renderData = { tender: ctx.paymentTender, jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.payment.list), tenderRptList, trInfo, trDetailList, rptMsg: null, auditConst, accountGroup: [], accountList: [], paymentConst, preUrl: '/payment/' + ctx.paymentTender.id + '/list/' + trInfo.id, }; // 获取报表信息,新增时及设置报表角色时使用 if (trInfo.uid === ctx.session.sessionUser.accountId && trInfo.is_del === 0 && trInfo.rpt_id) { const rptTpl = await ctx.service.rptTpl.getDataById(trInfo.rpt_id); if (rptTpl) { const pageRst = await ctx.service.jpcReport.getAllPreviewPagesCommon(rptTpl, 'A4'); renderData.rptMsg = pageRst.items[0]; // 判断与原有的报表审批人列表是否有区别 let difference = false; let auditDifference = false; let needChange = false; if (trInfo.report_items_json) { const report_items_json = JSON.parse(trInfo.report_items_json); const items = ['cells', 'signature_audit_cells', 'signature_cells', 'signature_date_cells', 'interact_cells']; for (const item of items) { if (report_items_json[item] && !ctx.helper._.isEmpty(ctx.helper._.differenceWith(JSON.parse(JSON.stringify(renderData.rptMsg[item])), report_items_json[item], ctx.helper._.isEqual))) { // 因为interact_cells里存在undefind值,必须先用JSON.parse和JSON.stringify转义才能对比 difference = true; needChange = true; if (item === 'signature_cells') { auditDifference = true; } // break; } } } else { difference = true; } if (difference) { // 删除rpt_audit重新配置 const updateData = { id: trInfo.id, report_items_json: JSON.stringify(ctx.helper._.cloneDeep(renderData.rptMsg)), }; // 删除rpt_audit重新配置 if (auditDifference) { updateData.rpt_audit = null; trInfo.rpt_audit = null; } if (needChange) { updateData.is_change = 1; trInfo.is_change = 1; } await ctx.service.paymentTenderRpt.defaultUpdate(updateData); trInfo.report_items_json = renderData.rptMsg; } if (trInfo.rpt_audit) { trInfo.rpt_audit = JSON.parse(trInfo.rpt_audit); const prjAccList = await ctx.service.projectAccount.getAllAccountByProjectId(ctx.session.sessionProject.id); for (const audit of trInfo.rpt_audit) { if (audit.uid) { const info = ctx.helper._.find(prjAccList, { id: audit.uid }); audit.name = info.name; } } } else { trInfo.rpt_audit = []; for (const sc of renderData.rptMsg.signature_cells) { trInfo.rpt_audit.push({ uid: null, rpt_name: sc.signature_name, }); } } renderData.trInfo = trInfo; } if (renderData.rptMsg) { // 获取所有项目参与者 const accountList = await ctx.service.projectAccount.getAllDataByCondition({ where: { project_id: ctx.session.sessionProject.id, enable: 1 }, columns: ['id', 'name', 'company', 'role', 'enable', 'is_admin', 'account_group', 'mobile'], }); const unitList = await ctx.service.constructionUnit.getAllDataByCondition({ where: { pid: ctx.session.sessionProject.id } }); const accountGroupList = unitList.map(item => { const groupList = accountList.filter(item1 => item1.company === item.name); return { groupName: item.name, groupList }; }); renderData.accountList = accountList; renderData.accountGroup = accountGroupList; } } await this.layout('payment/list.ejs', renderData, 'payment/list_modal.ejs'); } catch (err) { console.log(err); this.log(err); ctx.session.postError = err.toString(); ctx.redirect(this.request && this.request.headers && this.request.headers.referer ? this.request.headers.referer : '/payment'); } } async rptSave(ctx) { try { const tr_id = ctx.params.trid; if (!tr_id) { throw '参数有误'; } const trInfo = await ctx.service.paymentTenderRpt.getDataById(tr_id); if (!trInfo) { throw '标段报表不存在'; } if (ctx.session.sessionUser.accountId !== trInfo.uid) { throw '权限不足'; } const responseData = { err: 0, msg: '', data: {}, }; const data = JSON.parse(ctx.request.body.data); if (!data.type) { throw '提交数据错误'; } switch (data.type) { case 'rpt_audit': responseData.data = await ctx.service.paymentTenderRpt.updateRptAudit(trInfo, data.rpt_audit); break; case 'add-detail': responseData.data = await ctx.service.paymentDetail.addDetail(trInfo, data.code, data.s_time); break; default: throw '参数有误'; } ctx.body = responseData; } catch (err) { this.log(err); ctx.body = { err: 1, msg: err.toString(), data: null }; } } /** * 上报和重新上报 * @param ctx * @return {Promise} */ async startAudit(ctx) { try { if (ctx.detail.uid !== ctx.session.sessionUser.accountId) { throw '您无权上报报表表单详情数据'; } if (ctx.detail.status === auditConst.status.checking || ctx.detail.status === auditConst.status.checked) { throw '该报表表单详情数据当前无法上报'; } await ctx.service.paymentDetailAudit.start(ctx.detail.id, ctx.detail.times); ctx.redirect(ctx.request.header.referer); } catch (err) { this.log(err); ctx.session.postError = err.toString(); ctx.redirect(ctx.request.header.referer); } } /** * 审批 * @param ctx * @return {Promise} */ async checkAudit(ctx) { try { if (!ctx.detail || ctx.detail.status !== auditConst.status.checking) { throw '当前报表表单详情数据有误'; } if (!ctx.detail.curAuditor || ctx.detail.curAuditor.aid !== ctx.session.sessionUser.accountId) { throw '您无权进行该操作'; } const data = { checkType: parseInt(ctx.request.body.checkType), opinion: ctx.request.body.opinion, }; if (!data.checkType || isNaN(data.checkType)) { throw '提交数据错误'; } if (data.checkType === auditConst.status.checkNo) { if (!data.checkType || isNaN(data.checkType)) { throw '提交数据错误'; } } await ctx.service.paymentDetailAudit.check(ctx.detail.id, data, ctx.detail.times); ctx.redirect(ctx.request.header.referer); } catch (err) { this.log(err); ctx.session.postError = err.toString(); ctx.redirect(ctx.request.header.referer); } } /** * 上传附件 * @param {Object} ctx - egg全局变量 * @return {void} */ async uploadDetailFile(ctx) { const responseData = { err: 0, msg: '', data: [], }; let stream; try { const parts = ctx.multipart({ autoFields: true }); const files = []; let index = 0; const extra_upload = ctx.detail.status === auditConst.status.checked; const original_data = { tender_id: ctx.paymentTender.id, tr_id: ctx.trInfo.id, td_id: ctx.detail.id, } while ((stream = await parts()) !== undefined) { // 判断用户是否选择上传文件 if (!stream.filename) { throw '请选择上传的文件!'; } const fileInfo = path.parse(stream.filename); const create_time = Date.parse(new Date()) / 1000; const filepath = `app/public/upload/payment/${original_data.tender_id}/detail/fujian_${create_time + index.toString() + fileInfo.ext}`; await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + filepath, stream); await sendToWormhole(stream); // 保存数据到att表 const fileData = { upload_time: new Date(), filename: fileInfo.name, fileext: fileInfo.ext, filesize: Array.isArray(parts.field.size) ? parts.field.size[index] : parts.field.size, filepath, extra_upload, }; const result = await ctx.service.paymentDetailAtt.save(original_data, fileData, ctx.session.sessionUser.accountId); if (!result) { throw '导入数据库保存失败'; } fileData.uid = ctx.session.sessionUser.accountId; fileData.id = result.insertId; fileData.orginpath = ctx.app.config.fujianOssPath + filepath; delete fileData.filepath; if (!ctx.helper.canPreview(fileData.fileext)) { fileData.filepath = `/payment/${original_data.tender_id}/detail/${original_data.td_id}/file/${fileData.id}/download`; } else { fileData.filepath = ctx.app.config.fujianOssPath + filepath; } files.push(fileData); ++index; } responseData.data = files; } catch (err) { this.log(err); // 失败需要消耗掉stream 以防卡死 if (stream) { await sendToWormhole(stream); } this.setMessage(err.toString(), this.messageType.ERROR); } ctx.body = responseData; } /** * 下载附件 * @param {Object} ctx - egg全局变量 * @return {void} */ async downloadDetailFile(ctx) { const id = ctx.params.fid; if (id) { try { const fileInfo = await ctx.service.paymentDetailAtt.getDataById(id); if (fileInfo !== undefined && fileInfo !== '') { // 解决中文无法下载问题 const userAgent = (ctx.request.header['user-agent'] || '').toLowerCase(); let disposition = ''; if (userAgent.indexOf('msie') >= 0 || userAgent.indexOf('chrome') >= 0) { disposition = 'attachment; filename=' + encodeURIComponent(fileInfo.filename + fileInfo.fileext); } else if (userAgent.indexOf('firefox') >= 0) { disposition = 'attachment; filename*="utf8\'\'' + encodeURIComponent(fileInfo.filename + fileInfo.fileext) + '"'; } else { /* safari等其他非主流浏览器只能自求多福了 */ disposition = 'attachment; filename=' + new Buffer(fileInfo.filename + fileInfo.fileext).toString('binary'); } ctx.response.set({ 'Content-Type': 'application/octet-stream', 'Content-Disposition': disposition, 'Content-Length': fileInfo.filesize, }); // ctx.body = await fs.createReadStream(fileName); ctx.body = await ctx.helper.ossFileGet(fileInfo.filepath); } else { throw '不存在该文件'; } } catch (err) { this.log(err); this.setMessage(err.toString(), this.messageType.ERROR); } } } /** * 删除附件 * @param {Object} ctx - egg全局变量 * @return {void} */ async deleteDetailFile(ctx) { const responseData = { err: 0, msg: '', data: '', }; try { const data = JSON.parse(ctx.request.body.data); const fileInfo = await ctx.service.paymentDetailAtt.getDataById(data.id); if (!fileInfo || !Object.keys(fileInfo).length) { throw '该文件不存在'; } if (!fileInfo.extra_upload && ctx.detail.status === auditConst.status.checked) { throw '无权限删除'; } if (fileInfo !== undefined && fileInfo !== '') { // 先删除文件 await ctx.app.fujianOss.delete(ctx.app.config.fujianOssFolder + fileInfo.filepath); // 再删除数据库 await ctx.service.paymentDetailAtt.deleteById(data.id); responseData.data = ''; } else { throw '不存在该文件'; } } catch (err) { responseData.err = 1; responseData.msg = err; } ctx.body = responseData; } async safeBills(ctx) { try { await this._getDetailAuditViewData(ctx); const auditIdList = ctx.helper._.map(ctx.detail.auditors, 'aid'); const rptAuditIdList = ctx.helper._.map(ctx.detail.rptAudits, 'uid'); const uidList = ctx.helper._.uniq([...auditIdList, ...rptAuditIdList]); // 获取附件列表 const attList = await ctx.service.paymentDetailAtt.getPaymentDetailAttachment(ctx.detail.id, 'desc'); const stdBills = await ctx.service.stdGclList.getSafeGcl(); const renderData = { trInfo: ctx.trInfo, paymentConst, jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.payment.safe), auditConst, shenpiConst, attList, moment, whiteList: ctx.app.config.multipart.whitelist, uidList, preUrl: '/payment/' + ctx.paymentTender.id + '/detail/' + ctx.detail.id, OSS_PATH: ctx.app.config.fujianOssPath, stdBills, }; renderData.nextDetail = await ctx.service.paymentDetail.getDataByCondition({ tr_id: ctx.trInfo.id, order: ctx.detail.order + 1 }); const content = []; renderData.content = content; if ((ctx.detail.status === auditConst.status.uncheck || ctx.detail.status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === ctx.detail.uid) { // 获取所有项目参与者 const accountList = await ctx.service.projectAccount.getAllDataByCondition({ where: { project_id: ctx.session.sessionProject.id, enable: 1 }, columns: ['id', 'name', 'company', 'role', 'enable', 'is_admin', 'account_group', 'mobile'], }); renderData.accountList = accountList; const unitList = await ctx.service.constructionUnit.getAllDataByCondition({ where: { pid: ctx.session.sessionProject.id } }); const accountGroupList = unitList.map(item => { const groupList = accountList.filter(item1 => item1.company === item.name); return { groupName: item.name, groupList }; }); renderData.accountGroup = accountGroupList; } await this.layout('payment_safe/index.ejs', renderData, 'payment_safe/modal.ejs'); } catch (err) { this.log(err); this.ctx.postError(err, '读取安全生产费错误'); if (ctx.detail.tender_id && ctx.detail.tr_id) { ctx.redirect('/payment' + ctx.detail.tender_id + '/list'); } else { ctx.redirect(this.menu.menu.dashboard.url); } } } async safeCompare(ctx) { try { const renderData = { trInfo: ctx.trInfo, paymentConst, jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.payment.compare), auditConst, }; await this.layout('payment_safe/compare.ejs', renderData); } catch (err) { this.log(err); this.ctx.postError(err, '读取安全生产费错误'); if (ctx.detail.tender_id && ctx.detail.tr_id) { ctx.redirect('/payment' + ctx.detail.tender_id + '/list'); } else { ctx.redirect(this.menu.menu.dashboard.url); } } } async safeLoad(ctx) { try { const data = JSON.parse(ctx.request.body.data); const filter = data.filter.split(';'); const responseData = { err: 0, msg: '', data: {}, hpack: [] }; for (const f of filter) { switch (f) { case 'bills': responseData.data.bills = await ctx.service.paymentSafeBills.getAllDataByCondition({ where: {detail_id: ctx.params.did }}); break; default: responseData.data[f] = []; break; } } ctx.body = responseData; } catch (err) { this.log(err); ctx.body = { err: 1, msg: err.toString(), data: null }; } } async _billsBase(detail, type, data) { if (isNaN(data.id) || data.id <= 0) throw '数据错误'; if (type !== 'add') { if (isNaN(data.count) || data.count <= 0) data.count = 1; } switch (type) { case 'add': return await this.ctx.service.paymentSafeBills.addSafeBillsNode(detail, data.id, data.count); case 'delete': return await this.ctx.service.paymentSafeBills.delete(detail.id, data.id, data.count); case 'up-move': return await this.ctx.service.paymentSafeBills.upMoveNode(detail.id, data.id, data.count); case 'down-move': return await this.ctx.service.paymentSafeBills.downMoveNode(detail.id, data.id, data.count); case 'up-level': return await this.ctx.service.paymentSafeBills.upLevelNode(detail.id, data.id, data.count); case 'down-level': return await this.ctx.service.paymentSafeBills.downLevelNode(detail.id, data.id, data.count); } } async safeUpdate(ctx) { try { const data = JSON.parse(ctx.request.body.data); if (!data.postType || !data.postData) throw '数据错误'; const responseData = { err: 0, msg: '', data: {} }; switch (data.postType) { case 'add': case 'delete': case 'up-move': case 'down-move': case 'up-level': case 'down-level': responseData.data = await this._billsBase(ctx.detail, data.postType, data.postData); break; case 'update': responseData.data = await this.ctx.service.paymentSafeBills.updateCalc(ctx.detail, data.postData); break; case 'add-std': responseData.data = await this.ctx.service.paymentSafeBills.addStdNodeWithParent(ctx.detail, data.postData.id, data.postData.stdData); break; default: throw '未知操作'; } ctx.body = responseData; } catch (err) { this.log(err); ctx.body = this.ajaxErrorBody(err, '数据错误'); } } } return PaymentController; };