'use strict'; /** * * 成本管理 * @author Mai * @date * @version */ const audit = require('../const/audit'); const shenpiConst = require('../const/shenpi'); const moment = require('moment'); const sendToWormhole = require('stream-wormhole'); const fs = require('fs'); const path = require('path'); module.exports = app => { class CostController extends app.BaseController { constructor(ctx) { super(ctx); ctx.showProject = true; // ctx.showTitle = true; } loadMenu(ctx) { super.loadMenu(ctx); // 虚拟menu,以保证标题显示正确 ctx.menu = { name: '成本管理', display: false, caption: '成本管理', controller: 'cost', }; } async tender(ctx) { try { if (!ctx.subProject.page_show.cost) throw '该功能已关闭'; const renderData = { jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.cost.tender), }; const accountList = await ctx.service.projectAccount.getAllSubProjectAccount(ctx.subProject); 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 }; }).filter(x => { return x.groupList.length > 0; }); renderData.accountGroup = accountGroupList; renderData.accountInfo = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId); renderData.tenderList = await ctx.service.tender.getSpecList(ctx.service.tenderPermission, 'cost', ctx.session.sessionUser.is_admin ? 'all' : ''); renderData.categoryData = await this.ctx.service.category.getAllCategory(this.ctx.subProject); renderData.selfCategoryLevel = this.ctx.subProject.permission.self_category_level; renderData.permissionConst = ctx.service.tenderPermission.partPermissionConst('cost'); renderData.permissionBlock = ctx.service.tenderPermission.partPermissionBlock('cost'); renderData.costLedgerTemplates = await ctx.app.mysql.select('zh_bills_template_list', { where: { sub_type: 1} }); renderData.costAnalysisTemplates = await ctx.app.mysql.select('zh_bills_template_list', { where: { sub_type: 2} }); renderData.costCalcTemplates = await ctx.service.calcTmpl.getAllTemplate(this.ctx.session.sessionProject.id, 'cost'); await this.layout('cost/tender.ejs', renderData, 'cost/tender_modal.ejs'); } catch (err) { ctx.log(err); ctx.postError(err, '无法查看成本管理数据'); ctx.redirect(`/sp/${ctx.subProject.id}/dashboard`); } } async member(ctx) { try { const data = JSON.parse(ctx.request.body.data); const result = await ctx.service.tenderPermission.getPartsPermission(data.tid, data.parts); ctx.body = { err: 0, msg: '', data: result }; } catch (err) { ctx.log(err); ctx.ajaxErrorBody(err, '查询标段权限错误'); } } async memberSave(ctx) { try { const data = JSON.parse(ctx.request.body.data); await ctx.service.tenderPermission.savePermission(data.tid, data.member, data.permissionBlock); ctx.body = { err: 0, msg: '', data: '' }; } catch (err) { ctx.log(err); ctx.ajaxErrorBody(err, '保存标段权限错误'); } } async ledger(ctx) { try { const stage_type = this.ctx.service.costStage.stageType.ledger.key; const stages = await this.ctx.service.costStage.getAllStages(ctx.tender.id, stage_type, 'DESC'); for (const s of stages) { if (s.audit_status !== audit.common.status.checked) await this.ctx.service.costStage.loadUser(s); s.can_del = (s.create_user_id === ctx.session.sessionUser.accountId || ctx.session.sessionUser.is_admin) && (s.audit_status === audit.common.status.uncheck || s.audit_status === audit.common.status.checkNo); } const renderData = { stage_type, auditType: audit.auditType, stages, auditConst: audit.common, jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.cost.cost_stage) }; await this.layout('cost/ledger_list.ejs', renderData, 'cost/ledger_list_modal.ejs'); } catch(err) { ctx.log(err); ctx.redirect(ctx.request.header.referer); } } async book(ctx) { try { const stage_type = this.ctx.service.costStage.stageType.book.key; const stages = await this.ctx.service.costStage.getAllStages(ctx.tender.id, stage_type, 'DESC'); for (const s of stages) { if (s.audit_status !== audit.common.status.checked) await this.ctx.service.costStage.loadUser(s); s.can_del = (s.create_user_id === ctx.session.sessionUser.accountId || ctx.session.sessionUser.is_admin) && (s.audit_status === audit.common.status.uncheck || s.audit_status === audit.common.status.checkNo); } const validLedgerStages = await this.ctx.service.costStage.getAllStages(ctx.tender.id, 'ledger', 'DESC'); const renderData = { stage_type, auditType: audit.auditType, stages, validLedgerStages, auditConst: audit.common, jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.cost.cost_stage) }; await this.layout('cost/book_list.ejs', renderData, 'cost/book_list_modal.ejs'); } catch(err) { ctx.log(err); ctx.redirect(ctx.request.header.referer); } } async analysis(ctx) { try { const stage_type = this.ctx.service.costStage.stageType.analysis.key; const stages = await this.ctx.service.costStage.getAllStages(ctx.tender.id, stage_type, 'DESC'); for (const s of stages) { if (s.audit_status !== audit.common.status.checked) await this.ctx.service.costStage.loadUser(s); s.can_del = (s.create_user_id === ctx.session.sessionUser.accountId || ctx.session.sessionUser.is_admin) && (s.audit_status === audit.common.status.uncheck || s.audit_status === audit.common.status.checkNo); } const renderData = { stage_type, auditType: audit.auditType, stages, auditConst: audit.common, jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.cost.cost_stage) }; await this.layout('cost/ledger_list.ejs', renderData, 'cost/analysis_list_modal.ejs'); } catch(err) { ctx.log(err); ctx.redirect(ctx.request.header.referer); } } async addStage(ctx) { const stage_type = ctx.request.body.stage_type; try { if (!ctx.permission.cost[stage_type + '_add']) throw '您无权创建期'; const stage_date = ctx.request.body.date; if (stage_type !== 'book' && !stage_date) throw '请选择年月'; const stages = await ctx.service.costStage.getAllStages(ctx.tender.id, stage_type, 'DESC'); const unCompleteCount = stages.filter(s => { return s.status !== audit.common.status.checked; }).length; if (unCompleteCount.length > 0) throw '最新一期未审批通过,请审批通过后再新增'; let newStage; if (stage_type === 'ledger') { newStage = await ctx.service.costStage.add(ctx.tender.id, stage_type, stage_date); } if (stage_type === 'book') { const stage_order = ctx.request.body.stage; if (!stage_order) throw '请选择关联成本'; const ledgerStage = await ctx.service.costStage.getStageByOrder(ctx.tender.id, 'ledger', stage_order); if (!ledgerStage) throw '选择的关联成本不存在'; newStage = await ctx.service.costStage.add(ctx.tender.id, stage_type, ledgerStage.stage_date, { sid: ledgerStage.id, sorder: ledgerStage.stage_order }); } if (!newStage) throw '新增期失败'; ctx.redirect(`/sp/${ctx.subProject.id}/cost/tender/${ctx.tender.id}/${stage_type}/${newStage.stage_order}/stage`); } catch (err) { ctx.log(err); ctx.postError(err, '新增期失败'); ctx.redirect(`/sp/${ctx.subProject.id}/cost/tender/${ctx.tender.id}/${stage_type}`); } } async delStage(ctx) { try { const stage_id = ctx.request.body.stage_id; const stage = await ctx.service.costStage.getDataById(stage_id); if (!stage) throw '删除的期不存在,请刷新页面'; if (!ctx.session.sessionUser.is_admin && stage.create_user_id !== ctx.session.sessionUser.accountId) throw '您无权删除本期'; // 获取最新的期数 const stages = await ctx.service.costStage.getAllStages(ctx.tender.id, stage.stage_type, 'DESC'); if (stage.id !== stages[0].id) throw '非最新一期,不可删除'; await ctx.service.costStage.delete(stage_id); ctx.redirect(`/sp/${ctx.subProject.id}/cost/tender/${ctx.tender.id}/${stage.stage_type}`); } catch (err) { ctx.log(err); ctx.postError(err, '删除期失败'); ctx.redirect(ctx.request.header.referer); } } async _getStageAuditViewData(ctx) { await this.ctx.service.costStage.loadAuditViewData(ctx.costStage); } async stage(ctx) { const stageTypeInfo = ctx.service.costStage.stageType[ctx.costStage.stage_type]; try { await this._getStageAuditViewData(ctx); // 流程审批人相关数据 const accountList = await ctx.service.projectAccount.getAllSubProjectAccount(ctx.subProject); const unitList = await ctx.service.constructionUnit.getAllDataByCondition({ where: { pid: ctx.session.sessionProject.id } }); const accountGroup = unitList.map(item => { const groupList = accountList.filter(item1 => item1.company === item.name); return { groupName: item.name, groupList }; }).filter(x => { return x.groupList.length > 0; }); // 是否已验证手机短信 const pa = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId); const commonJson = ctx.subProject.common_json ? JSON.parse(ctx.subProject.common_json) : null; const contractTypes = commonJson && commonJson.tender_contract_type ? commonJson.tender_contract_type : []; const renderData = { auditConst: audit.common, auditType: audit.auditType, accountList, accountGroup, shenpiConst, authMobile: pa.auth_mobile, jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.cost[`cost_stage_${stageTypeInfo.key}`]), shenpi_status: ctx.tender.info.shenpi[stageTypeInfo.shenpi_status] || 1, contractTypes, }; await this.layout(`cost/${stageTypeInfo.key}.ejs`, renderData, `cost/${stageTypeInfo.key}_modal.ejs`); } catch (err) { ctx.log(err); ctx.postError(err, '读取成本报审错误'); ctx.redirect(`/sp/${ctx.subProject.id}/cost/tender/${ctx.tender.id}/${stageTypeInfo.key}`); } } async _ledgerLoad(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 = ctx.costStage.readOnly ? await ctx.service.costStageLedger.getReadData(ctx.costStage) : await ctx.service.costStageLedger.getEditData(ctx.costStage); break; case 'billsCompare': responseData.data[f] = await ctx.service.costStageLedger.getCompareData(ctx.costStage); break; case 'detail': responseData.data.detail = ctx.costStage.readOnly ? await ctx.service.costStageDetail.getReadData(ctx.costStage) : await ctx.service.costStageDetail.getEditData(ctx.costStage); break; case 'detailCompare': // todo responseData.data.detailCompare = await ctx.service.costStageDetail.getCompareData(ctx.costStage); break; case 'auditFlow': responseData.data[f] = await ctx.service.costStageAudit.getViewFlow(ctx.costStage); break; case 'att': responseData.data[f] = await ctx.service.costStageFile.getData(ctx.costStage.id, 'DESC'); break; case 'tags': responseData.data[f] = await ctx.service.costStageTag.getDatas(ctx.costStage.id); break; case 'contract': const contractTree = await ctx.service.contractTree.getAllDataByCondition({ columns: ['id', 'contract_id', 'contract_pid', 'order', 'level', 'is_leaf', 'full_path', 'code', 'name'], where: {tid: ctx.costStage.tid, contract_type: 1} }); const contractData = await this.ctx.service.contract.getAllDataByCondition({ columns: ['id', 'contract_id', 'contract_pid', 'order', 'level', 'is_leaf', 'full_path', 'c_code', 'name'], where: {tid: ctx.costStage.tid, contract_type: 1} }); responseData.data[f] = [...contractTree, ...contractData]; break; default: responseData.data[f] = []; break; } } ctx.body = responseData; } catch (err) { this.log(err); ctx.body = { err: 1, msg: err.toString(), data: null }; } } async _bookLoad(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': const ledger = await ctx.service.costStageLedger.getReadData(ctx.costStage.relaStage); ledger.forEach(l => { delete l.postil; delete l.memo; }); const book = ctx.costStage.readOnly ? await ctx.service.costStageBook.getReadData(ctx.costStage) : await ctx.service.costStageBook.getEditData(ctx.costStage); ctx.helper.assignRelaData(ledger, [ { data: book, fields: ['pre_in_tp', 'pre_in_excl_tax_tp', 'in_tp', 'in_excl_tax_tp', 'end_in_tp', 'end_in_excl_tax_tp', 'postil', 'memo'], prefix: '', relaId: 'ledger_id' }, { data: book, fields: ['id'], prefix: 'book_', relaId: 'ledger_id' }, ]); responseData.data[f] = ledger; break; case 'billsCompare': const ledgerC = await ctx.service.costStageLedger.getReadData(ctx.costStage.relaStage); ledgerC.forEach(l => { delete l.postil; delete l.memo; }); const bookC = await ctx.service.costStageBook.getCompareData(ctx.costStage); ctx.helper.assignRelaData(ledgerC, [ { data: bookC, fields: ['pre_in_tp', 'pre_in_excl_tax_tp', 'calc_his', 'postil', 'memo'], prefix: '', relaId: 'ledger_id' }, ]); responseData.data[f] = ledgerC; break; case 'detail': const detail = await ctx.service.costStageDetail.getReadData(ctx.costStage.relaStage); detail.forEach(l => { delete l.postil; delete l.memo; }); const bookDetail = ctx.costStage.readOnly ? await ctx.service.costStageBookDetail.getReadData(ctx.costStage) : await ctx.service.costStageBookDetail.getEditData(ctx.costStage); ctx.helper.assignRelaData(detail, [ { data: bookDetail, fields: ['in_tp', 'in_excl_tax_tp', 'postil', 'memo'], prefix: '', relaId: 'detail_id' }, { data: bookDetail, fields: ['id'], prefix: 'book_', relaId: 'detail_id' }, ]); responseData.data[f] = detail; break; case 'detailCompare': const detailC = await ctx.service.costStageLedger.getReadData(ctx.costStage.relaStage); detailC.forEach(l => { delete l.postil; delete l.memo; }); const bookDetailC = await ctx.service.costStageBook.getCompareData(ctx.costStage); ctx.helper.assignRelaData(detailC, [ { data: bookDetailC, fields: ['calc_his', 'postil', 'memo'], prefix: '', relaId: 'detail_id' }, ]); responseData.data[f] = detailC; break; case 'auditFlow': responseData.data[f] = await ctx.service.costStageAudit.getViewFlow(ctx.costStage); break; case 'att': responseData.data[f] = await ctx.service.costStageFile.getData(ctx.costStage.id, 'DESC'); break; default: responseData.data[f] = []; break; } } ctx.body = responseData; } catch (err) { this.log(err); ctx.body = { err: 1, msg: err.toString(), data: null }; } } async _analysisLoad(ctx) { } async stageLoad(ctx) { const updateFun = `_${ctx.costStage.stage_type}Load`; if (this[updateFun]) { await this[updateFun](ctx); } else { ctx.ajaxErrorBody('未知期数据类型', '加载数据错误'); } } async _billsBase(stage, 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.costStageLedger.addLedgerNode(stage, data.id, data.count); case 'delete': return await this.ctx.service.costStageLedger.delete(stage.id, data.id, data.count); case 'up-move': return await this.ctx.service.costStageLedger.upMoveNode(stage.id, data.id, data.count); case 'down-move': return await this.ctx.service.costStageLedger.downMoveNode(stage.id, data.id, data.count); case 'up-level': return await this.ctx.service.costStageLedger.upLevelNode(stage.id, data.id, data.count); case 'down-level': return await this.ctx.service.costStageLedger.downLevelNode(stage.id, data.id, data.count); } } async _ledgerUpdate(ctx) { try { const data = JSON.parse(ctx.request.body.data); if (!data.target) throw '数据错误'; const responseData = { err: 0, msg: '', data: {} }; if (data.target === 'ledger') { if (!data.postType || !data.postData) throw '数据错误'; 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.costStage, data.postType, data.postData); break; case 'update': responseData.data = await this.ctx.service.costStageLedger.updateCalc(ctx.costStage, data.postData); break; default: throw '未知操作'; } } else if (data.target === 'detail') { responseData.data = await this.ctx.service.costStageDetail.updateDatas(data); } else if (data.target === 'importContract') { if (!data.types && !data.ids) throw '数据错误'; responseData.data = await this.ctx.service.costStageDetail.importContract(data); } ctx.body = responseData; } catch (err) { this.log(err); ctx.body = this.ajaxErrorBody(err, '数据错误'); } } async _bookUpdate(ctx) { try { const data = JSON.parse(ctx.request.body.data); if (!data.target || !data.update) throw '数据错误'; const responseData = { err: 0, msg: '', data: {} }; switch (data.target) { case 'ledger': responseData.data = await this.ctx.service.costStageBook.updateDatas(data.update); break; case 'detail': responseData.data = await this.ctx.service.costStageBookDetail.updateDatas(data.update); break; default: throw '未知操作'; } ctx.body = responseData; } catch (err) { this.log(err); ctx.body = this.ajaxErrorBody(err, '数据错误'); } } async _analysisBillsBase(stage, 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.costStageAnalysis.addSafeBillsNode(stage, data.id, data.count); case 'delete': return await this.ctx.service.costStageAnalysis.delete(stage.id, data.id, data.count); case 'up-move': return await this.ctx.service.costStageAnalysis.upMoveNode(stage.id, data.id, data.count); case 'down-move': return await this.ctx.service.costStageAnalysis.downMoveNode(stage.id, data.id, data.count); case 'up-level': return await this.ctx.service.costStageAnalysis.upLevelNode(stage.id, data.id, data.count); case 'down-level': return await this.ctx.service.costStageAnalysis.downLevelNode(stage.id, data.id, data.count); } } async _analysisUpdate(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._analysisBillsBase(ctx.costStage, data.postType, data.postData); break; case 'update': responseData.data = await this.ctx.service.costStageAnalysis.updateCalc(ctx.costStage, data.postData); break; default: throw '未知操作'; } ctx.body = responseData; } catch (err) { this.log(err); ctx.body = this.ajaxErrorBody(err, '数据错误'); } } async stageUpdate(ctx) { const updateFun = `_${ctx.costStage.stage_type}Update`; if (this[updateFun]) { await this[updateFun](ctx); } else { ctx.ajaxErrorBody('未知期数据类型', '保存数据错误'); } } async uploadStageFile(ctx) { let stream; try { const parts = ctx.multipart({ autoFields: true }); let index = 0; const create_time = Date.parse(new Date()) / 1000; let stream = await parts(); const user = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId); const rela_id = parts.field.rela_id; const rela_sub_id = parts.field.rela_sub_id || ''; const uploadfiles = []; while (stream !== undefined) { if (!stream.filename) throw '未发现上传文件!'; const fileInfo = path.parse(stream.filename); const filepath = `app/public/upload/${ctx.costStage.tid}/costStage/${ctx.moment().format('YYYYMMDD')}/${create_time + '_' + index + fileInfo.ext}`; // 保存文件 await ctx.app.fujianOss.put(ctx.app.config.fujianOssFolder + filepath, stream); await sendToWormhole(stream); // 插入到stage_pay对应的附件列表中 uploadfiles.push({ rela_id, rela_sub_id, filename: fileInfo.name, fileext: fileInfo.ext, filesize: Array.isArray(parts.field.size) ? parts.field.size[index] : parts.field.size, filepath, }); ++index; if (Array.isArray(parts.field.size) && index < parts.field.size.length) { stream = await parts(); } else { stream = undefined; } } const result = await ctx.service.costStageFile.addFiles(ctx.costStage, uploadfiles, user); ctx.body = { err: 0, msg: '', data: result }; } catch (error) { ctx.log(error); // 失败需要消耗掉stream 以防卡死 if (stream) await sendToWormhole(stream); ctx.body = this.ajaxErrorBody(error, '上传附件失败,请重试'); } } async deleteStageFile(ctx) { try { const data = JSON.parse(ctx.request.body.data); if (!data && !data.id) throw '缺少参数'; const result = await ctx.service.costStageFile.delFiles(data.id); ctx.body = { err: 0, msg: '', data: result }; } catch (error) { ctx.log(error); ctx.ajaxErrorBody(error, '删除附件失败'); } } async tag(ctx) { try { const isRelaUser = ctx.costStage.userIds.indexOf(this.ctx.session.sessionUser.accountId) >= 0; const isValidTourist = ctx.permission.cost.view && ctx.tender.touristPermission.tag; if (!isRelaUser && !isValidTourist) throw '您无权进行该操作'; const data = JSON.parse(ctx.request.body.data); const result = await ctx.service.costStageTag.update(data); ctx.body = { err: 0, msg: '', data: result }; } catch (err) { this.log(err); ctx.body = this.ajaxErrorBody(err, '书签数据错误'); } } /** * 添加审批人 * @param ctx * @return {Promise} */ async addStageAudit(ctx) { try { const data = JSON.parse(ctx.request.body.data); const id = this.app._.toInteger(data.auditorId); if (isNaN(id) || id <= 0) throw '参数错误'; // 检查权限等 if (ctx.costStage.create_user_id !== ctx.session.sessionUser.accountId) throw '您无权添加审核人'; if (ctx.costStage.audit_status !== audit.common.status.uncheck && ctx.costStage.audit_status !== audit.common.status.checkNo) { throw '当前不允许添加审核人'; } // 检查审核人是否已存在 const exist = await ctx.service.costStageAudit.getDataByCondition({ stage_id: ctx.costStage.id, audit_times: ctx.costStage.audit_times, audit_id: id }); if (exist) throw '该审核人已存在,请勿重复添加'; const auditorInfo = await this.ctx.service.projectAccount.getDataById(id); if (!auditorInfo) throw '添加的审批人不存在'; const shenpiInfo = await ctx.service.shenpiAudit.getDataByCondition({ tid: ctx.tender.id, sp_type: shenpiConst.sp_type.safe_payment, sp_status: shenpiConst.sp_status.gdzs }); const is_gdzs = shenpiInfo && ctx.tender.info.shenpi.safe_payment === shenpiConst.sp_status.gdzs ? 1 : 0; const result = await ctx.service.costStageAudit.addAuditor(ctx.costStage.id, auditorInfo, ctx.costStage.audit_times, is_gdzs); if (!result) throw '添加审核人失败'; const auditors = await ctx.service.costStageAudit.getAuditorGroup(ctx.costStage.id, ctx.costStage.audit_times); ctx.body = { err: 0, msg: '', data: auditors }; } catch (err) { ctx.log(err); ctx.body = { err: 1, msg: err.toString(), data: null }; } } /** * 移除审批人 * @param ctx * @return {Promise} */ async deleteStageAudit(ctx) { try { const data = JSON.parse(ctx.request.body.data); const id = data.auditorId instanceof Number ? data.auditorId : this.app._.toNumber(data.auditorId); if (isNaN(id) || id <= 0) throw '参数错误'; const result = await ctx.service.costStageAudit.deleteAuditor(ctx.costStage.id, id, ctx.costStage.audit_times); if (!result) throw '移除审核人失败'; const auditors = await ctx.service.costStageAudit.getAuditors(ctx.costStage.id, ctx.costStage.audit_times); ctx.body = { err: 0, msg: '', data: auditors }; } catch (err) { ctx.log(err); ctx.body = { err: 1, msg: err.toString(), data: null }; } } async stageAuditStart(ctx) { try { if (ctx.costStage.create_user_id !== ctx.session.sessionUser.accountId) throw '您无权上报该期数据'; if (ctx.costStage.revising) throw '台账修订中,不可上报'; if (ctx.costStage.audit_status !== audit.common.status.uncheck && ctx.costStage.audit_status !== audit.common.status.checkNo) throw '该期数据当前无法上报'; await ctx.service.costStageAudit.start(ctx.costStage); ctx.redirect(ctx.request.header.referer); } catch (err) { ctx.log(err); ctx.postError(err, '上报失败'); ctx.redirect(`/sp/${ctx.subProject.id}/cost/tender/${ctx.tender.id}/${ctx.costStage.stage_type}/${ctx.costStage.stage_order}/bills`); } } async stageAuditCheck(ctx) { try { if (!ctx.costStage || (ctx.costStage.audit_status !== audit.common.status.checking && ctx.costStage.audit_status !== audit.common.status.checkNoPre)) { throw '当前期数据有误'; } if (ctx.costStage.curAuditorIds.indexOf(ctx.session.sessionUser.accountId) < 0) { throw '您无权进行该操作'; } if (ctx.costStage.revising) throw '台账修订中,不可审批'; const checkType = parseInt(ctx.request.body.checkType); const opinion = ctx.request.body.opinion.replace(/\r\n/g, '
').replace(/\n/g, '
').replace(/\s/g, ' '); await ctx.service.costStageAudit.check(ctx.costStage, checkType, opinion); } catch (err) { ctx.log(err); ctx.postError(err, '审批失败'); } ctx.redirect(ctx.request.header.referer); } async stageAuditCheckAgain(ctx) { try { if (!ctx.costStage.isLatest) throw '非最新一期,不可重新审批'; if (ctx.costStage.audit_status !== audit.common.status.checked) throw '未审批完成,不可重新审批'; if (ctx.costStage.revising) throw '台账修订中,不可重审'; if (ctx.session.sessionUser.loginStatus === 0) { const user = await ctx.service.projectAccount.getDataById(ctx.session.sessionUser.accountId); if (!user.auth_mobile) throw '未绑定手机号'; const code = ctx.request.body.code; const cacheKey = 'smsCode:' + ctx.session.sessionUser.accountId; const cacheCode = await app.redis.get(cacheKey); if (cacheCode === null || code === undefined || cacheCode !== (code + pa.auth_mobile)) { throw '验证码不正确!'; } } const adminCheckAgain = ctx.request.body.confirm === '确认设置终审审批' && ctx.session.sessionUser.is_admin; if (ctx.costStage.finalAuditorIds.indexOf(ctx.session.sessionUser.accountId) < 0 && !adminCheckAgain) throw '您无权重新审批'; await ctx.service.costStageAudit.checkAgain(ctx.costStage, adminCheckAgain); } catch (err) { ctx.log(err); ctx.postError(err, '重新审批失败'); } ctx.redirect(ctx.request.header.referer); } async stageAuditCheckCancel(ctx) { try { if (ctx.costStage.revising) throw '台账修订中,不可撤回'; if (!ctx.costStage.cancancel) throw '您无权进行该操作'; await ctx.service.costStageAudit.checkCancel(ctx.costStage); } catch (err) { ctx.log(err); ctx.postError(err, '撤回失败'); } ctx.redirect(ctx.request.header.referer); } /** * 期审批流程(POST) * @param ctx * @return {Promise} */ async loadAuditors(ctx) { try { const stageOrder = JSON.parse(ctx.request.body.data).order; const stageType = ctx.params.stype; const stage = await ctx.service.costStage.getStageByOrder(ctx.tender.id, stageType, stageOrder); await ctx.service.costStage.loadUser(stage); await ctx.service.costStage.loadAuditViewData(stage); ctx.body = { err: 0, msg: '', data: stage }; } catch (error) { ctx.log(error); ctx.body = { err: 1, msg: error.toString(), data: null }; } } } return CostController; };