'use strict'; /** * * * @author Mai * @date 2018/6/20 * @version */ const moment = require('moment'); const auditConst = require('../const/audit'); const spreadConst = require('../const/spread'); const tenderConst = require('../const/tender'); const payConst = require('../const/deal_pay.js'); const measureType = tenderConst.measureType; const path = require('path'); module.exports = app => { class StageController extends app.BaseController { /** * 构造函数 * * @param {Object} ctx - egg全局变量 * @return {void} */ constructor(ctx) { super(ctx); ctx.showProject = true; ctx.showTender = true; ctx.showTitle = true; } /** * 获取通用的renderData(用于layout, Menu, subMenu部分) * @param ctx * @returns {{tender, tenderMenu, auditConst}} * @private */ _getDefaultRenderData (ctx) { const data = { tender: ctx.tender.data, tenderMenu: JSON.parse(JSON.stringify(this.menu.stageMenu)), auditConst: auditConst.flow, measureType, preUrl: '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.params.order, stage: ctx.stage, }; data.tenderMenu.back.children[0].url = '/tender/' + ctx.tender.id + '/measure/stage'; return data; } _stageReadOnly(stage) { return stage.status === auditConst.flow.status.checked; } /** * 获取SpreadSetting * @private */ _getSpreadSetting() { const _ = this.app._; function removeFieldCols(setting, cols) { _.remove(setting.cols, function (c) { return cols.indexOf(c.field) > -1; }); } function setColFormat(cols, field, formatter) { const filterCols = cols.filter(function (c) { return c.field.search(field) !== -1; }); for (const col of filterCols) { col.formatter = formatter; } } const tpFormatter = this.ctx.helper.getNumberFormatter(this.ctx.tender.info.decimal.tp); const upFormatter = this.ctx.helper.getNumberFormatter(2); const ledger = JSON.parse(JSON.stringify(spreadConst.stage.ledger)); setColFormat(ledger.cols, 'unit_price', upFormatter); setColFormat(ledger.cols, 'total_price', tpFormatter); setColFormat(ledger.cols, 'tp', tpFormatter); const pos = JSON.parse(JSON.stringify(spreadConst.stage.pos)); const tender = this.ctx.tender, stage = this.ctx.stage; if (this._stageReadOnly(stage)) { ledger.readOnly = true; pos.readOnly = true; } if (tender.data.measure_type === measureType.tz.value) { removeFieldCols(ledger, spreadConst.filterCols.tzWithoutCols); removeFieldCols(pos, spreadConst.filterCols.posTzWithoutCols); } if (!tender.info.display.ledger.dgnQty) { removeFieldCols(ledger, spreadConst.filterCols.dgnCols); } return [ledger, pos]; } /** * 获取期数据 * @param ctx * @returns {Promise} * @private */ async _getStage(ctx) { const stageOrder = parseInt(ctx.params.order); ctx.stage = await ctx.service.stage.getDataByCondition({ tid: ctx.tender.id, order: stageOrder, }); ctx.stage.auditors = await ctx.service.stageAudit.getAuditors(ctx.stage.id, ctx.stage.times); ctx.stage.curAuditor = await ctx.service.stageAudit.getCurAuditor(ctx.stage.id, ctx.stage.times); } /** * 期计量页面 (Get) * @param {Object} ctx - egg全局变量 * @returns {Promise} */ async index(ctx) { try { await this._getStage(ctx); const renderData = this._getDefaultRenderData(ctx); [renderData.ledgerSpread, renderData.posSpread] = this._getSpreadSetting(); renderData.ledgerData = await ctx.service.ledger.getDataByTenderId(ctx.tender.id, -1); renderData.curStageData = await ctx.service.stageBills.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.times, 0); renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.index); // 查询截止上期数据 //if (ctx.stage.order > 0) { //renderData.preStageData //} await this.layout('stage/index.ejs', renderData, 'stage/modal.ejs'); } catch (err) { this.log(err); ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage'); } } /** * 获取期数据(截止上期 & 本期) * @param ctx * @returns {Promise} */ async getStagePosData(ctx) { try { await this._getStage(ctx); const condition = JSON.parse(ctx.request.body.data) || {}; condition.tid = ctx.tender.id; const responseData = {err: 0, msg: '', data: {}}; responseData.data.pos = await ctx.service.pos.getPosData(condition); // todo 根据当前人,或指定对象查询数据 responseData.data.curStageData = await ctx.service.stagePos.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.times, ctx.stage.curAuditor ? ctx.stage.curAuditor.order : 0, this.app._.map(responseData.data.pos, 'id')); ctx.body = responseData; } catch (err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 保存数据 * @param ctx * @returns {Promise} */ async updateStageData(ctx) { try { await this._getStage(ctx); // 检查登录用户,是否可操作 if (ctx.session.sessionUser.accountId === ctx.stage.user_id) { if (ctx.stage.status === auditConst.flow.status.checking || ctx.stage.status === auditConst.flow.status.checked) { throw '该计量期当前您无权操作'; } } else { // 检查是否可修改 //const curAuditor = await ctx.service.stageAudit.get } const data = JSON.parse(ctx.request.body.data); const responseData = { err: 0, msg: '', data: {}, }; if (data.pos) { responseData.data = await ctx.service.stagePos.updateStageData(data.pos); } else if (data.bills) { responseData.data.bills = await ctx.service.stageBills.updateStageData(data.bills); } ctx.body = responseData; } catch (err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 中间计量 * @param ctx * @returns {Promise} */ async detail(ctx) { try { await this._getStage(ctx); const renderData = this._getDefaultRenderData(ctx); renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.detail); renderData.imType = tenderConst.imType; await this.layout('stage/detail.ejs', renderData, 'stage/detail_modal.ejs'); } catch (err) { this.log(err); ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage/' + ctx.params.order); } } /** * 设置中间计量生成规则,并生成中间计量数据 * @param ctx * @returns {Promise} */ async buildDetailData (ctx) { try { await this._getStage(ctx); // 检查登录用户,是否可操作 if (ctx.session.sessionUser.accountId === ctx.stage.user_id) { if (ctx.stage.status === auditConst.flow.status.checking || ctx.stage.status === auditConst.flow.status.checked) { throw '该计量期当前您无权操作'; } } const data = JSON.parse(ctx.request.body.data); await ctx.service.stage.buildDetailData(ctx.tender.id, ctx.stage.order, data); ctx.body = {err: 0, msg: '', data: null}; } catch (err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 加载数据 * @param ctx * @returns {Promise} */ async loadDetailRelaData(ctx) { try { await this._getStage(ctx); const data = JSON.parse(ctx.request.body.data); // 加载台账数据 if (data.loadType === 'ledger') { const ledgerData = await ctx.service.ledger.getDataByTenderId(ctx.tender.id, -1); ctx.body = {err: 0, msg: '', data: ledgerData }; } else if (data.loadType === 'all') { const ledger = await ctx.service.ledger.getDataByTenderId(ctx.tender.id, -1); const curStage = await ctx.service.stageBills.getLastestStageData(ctx.tender.id, ctx.stage.id); const stageDetail = await ctx.service.stageDetail.getLastestStageData(ctx.tender.id, ctx.stage.id); ctx.body = { err: 0, msg: '', data: { ledger, curStage, stageDetail, } }; } } catch (err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 中间计量,生成规则,高级设置 * @param ctx * @returns {Promise} */ async setAdvancedConfig(ctx) { try { await this._getStage(ctx); // 检查登录用户,是否可操作 if (ctx.session.sessionUser.accountId === ctx.stage.user_id) { if (ctx.stage.status === auditConst.flow.status.checking || ctx.stage.status === auditConst.flow.status.checked) { throw '该计量期当前您无权操作'; } } const data = JSON.parse(ctx.request.body.data); await ctx.service.stage.update(data, { id: ctx.stage.id }); ctx.body = {err: 0, msg: '', data: this.ctx.stage}; } catch (err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 中间计量,编辑中间计量数据 * @param ctx * @returns {Promise} */ async saveDetailData(ctx) { try { await this._getStage(ctx); // 检查登录用户,是否可操作 if (ctx.session.sessionUser.accountId === ctx.stage.user_id) { if (ctx.stage.status === auditConst.flow.status.checking || ctx.stage.status === auditConst.flow.status.checked) { throw '该计量期当前您无权操作'; } } else { // 检查是否可修改 //const curAuditor = await ctx.service.stageAudit.get } const data = JSON.parse(ctx.request.body.data); const responseData = { err: 0, msg: '', data: {}, }; responseData.data = await ctx.service.stageDetail.saveDetailData(data); ctx.body = responseData; } catch (err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 中间计量,添加草图,上传图片 * @param ctx * @returns {Promise} */ async addCalcImage(ctx) { try { const stream = await ctx.getFileStream(); const create_time = Date.parse(new Date()) / 1000; const fileInfo = path.parse(stream.filename); const fileName = path.join('public/upload', this.ctx.tender.id.toString(), 'im', 'calcImg_' + create_time + fileInfo.ext); await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, 'app', fileName)); ctx.body = {err: 0, msg: '', data: fileName}; } catch(err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 中间计量,设置草图 * @param ctx * @returns {Promise} */ async mergeCalcImage(ctx) { try { await this._getStage(ctx); // 检查登录用户,是否可操作 if (ctx.session.sessionUser.accountId === ctx.stage.user_id) { if (ctx.stage.status === auditConst.flow.status.checking || ctx.stage.status === auditConst.flow.status.checked) { throw '该计量期当前您无权操作'; } } else { // 检查是否可修改 //const curAuditor = await ctx.service.stageAudit.get } const data = JSON.parse(ctx.request.body.data); if (data.updateType === 'update') { const create_time = Date.parse(new Date()) / 1000; const fileName = path.join('public/upload', this.ctx.tender.id.toString(), 'im', 'calcImg_' + create_time + '.jpg'); const base64Data = data.img.replace(/^data:image\/\w+;base64,/, ""); const dataBuffer = new Buffer(base64Data, 'base64'); await this.ctx.helper.saveBufferFile(dataBuffer, path.join(this.app.baseDir, 'app', fileName)); data.calc_img = fileName; data.calc_img_org = JSON.stringify(data.imgInfo); delete data.updateType; delete data.img; delete data.imgInfo; } else if (data.updateType === 'clear') { data.calc_img = null; data.calc_img_org = null; delete data.updateType; } await this.ctx.service.stageDetail.saveDetailData(data); const imData = await ctx.service.stageDetail.getLastestImStageData(this.ctx.tender.id, this.ctx.stage.id, data.lid, data.uuid); const responseData = {err: 0, msg: '', data: imData}; ctx.body = responseData; } catch (err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 获取计算参数 * @param ctx * @returns {Promise<*[]>} * @private */ async _getPayCalcBase(ctx) { //const calcBase = JSON.parse(JSON.stringify(payConst.calcBase)); const calcBase = [ {name: '签约合同价', code: 'htj'}, {name: '签约合同价(不含暂列金)', code: 'htjszl'}, {name: '签约开工预付款', code: 'kgyfk'}, {name: '签约材料预付款', code: 'clyfk'}, {name: '本期完成计量', code: 'bqwc'}, {name: '100章本期完成计量', code: 'ybbqwc'}, ]; const param = ctx.tender.info.deal_param; for (const cb of calcBase) { switch (cb.code) { case 'htj': cb.value = param.contractPrice; break; case 'htjszl': cb.value = this.app._.subtract(param.contractPrice, param.zanLiePrice); break; case 'kgyfk': cb.value = param.startAdvance; break; case 'clyfk': cb.value = param.materialAdvance; break; case 'bqwc': const sum = await ctx.service.stageBills.getSumTotalPrice(ctx.stage); cb.value = this.app._.add(sum.contract_tp, sum.qc_tp); break; case 'ybbqwc': const sumGcl = await ctx.service.stageBills.getSumTotalPriceGcl(ctx.stage, '^1[0-9]{2}-'); cb.value = this.app._.add(sumGcl.contract_tp, sumGcl.qc_tp); break; default: cb.value = 0; } } return calcBase; } /** * 合同支付 * @param ctx * @returns {Promise} */ async pay(ctx) { try { await this._getStage(ctx); const renderData = this._getDefaultRenderData(ctx); const dealPay = await ctx.service.pay.getAllDataByCondition({ where: { tid: ctx.tender.id }, orders: [['order', 'acs']], }); if (dealPay && dealPay.length > 0) { renderData.dealPay = dealPay; } else { await ctx.service.pay.addDefaultPayData(); renderData.dealPay = await ctx.service.pay.getAllDataByCondition({where: { tid: ctx.tender.id } }); } renderData.calcBase = await this._getPayCalcBase(ctx); renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.pay); await this.layout('stage/pay.ejs', renderData, 'stage/pay_modal.ejs'); } catch (err) { this.log(err); ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage'); } } async savePayData(ctx) { try { await this._getStage(ctx); // 检查登录用户,是否可操作 if (ctx.session.sessionUser.accountId === ctx.stage.user_id) { if (ctx.stage.status === auditConst.flow.status.checking || ctx.stage.status === auditConst.flow.status.checked) { throw '该计量期当前您无权操作'; } } else { if (!ctx.stage.curAuditor || ctx.stage.curAuditor.id !== ctx.session.sessionUser.accountId) { throw '该计量期当前您无权操作'; } } const data = JSON.parse(ctx.request.body.data); const responseData = { err: 0, msg: '', data: {}, }; switch (data.type) { case 'add': responseData.data = await ctx.service.pay.add(); break; case 'del': responseData.data = await ctx.service.pay.del(data.id); break; case 'changeOrder': responseData.data = await ctx.service.pay.changeOrder(data.id1, data.id2); break; case 'info': responseData.data = await ctx.service.pay.save(data.updateData); break; case 'stage': responseData.data = await ctx.service.stagePay.saveData(data.updateData); break; } ctx.body = responseData; } catch(err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 合同支付 - 章节明细 * @param ctx * @returns {Promise} */ async chapterDetail(ctx) { const _ = this.app._; const fields = ['contract_tp', 'qc_tp', 'gather_tp', 'end_gather_tp']; function assignStageData(chapter, curStage, preStage) { chapter.contract_tp = curStage.contract_tp; chapter.qc_tp = curStage.qc_tp; chapter.gather_tp = _.add(curStage.contract_tp, curStage.qc_tp); if (preStage) { chapter.pre_contract_tp = preStage.contract_tp; chapter.pre_qc_tp = preStage.qc_tp; chapter.pre_gather_tp = _.add(preStage.contract_tp, preStage.qc_tp); chapter.end_contract_tp = _.add(curStage.contract_tp, preStage.contract_tp); chapter.end_qc_tp = _.add(curStage.qc_tp, preStage.qc_tp); chapter.end_gather_tp = _.add(chapter.gather_tp, chapter.pre_gather_tp); } else { chapter.end_contract_tp = curStage.contract_tp; chapter.end_qc_tp = curStage.qc_tp; chapter.end_gather_tp = chapter.gather_tp; } } try { await this._getStage(ctx); const chapterDetail = JSON.parse(JSON.stringify(payConst.chapterDetail)); const calcDetail = _.sortBy(chapterDetail, ['cType']); for (const cd of calcDetail) { switch (cd.cType) { case 1: const tp = await ctx.service.stageBills.getSumTotalPriceGcl(ctx.stage, cd.filter); assignStageData(cd, tp); break; case 11: assignStageData(cd, await ctx.service.stageBills.getSumTotalPriceGcl(ctx.stage)); break; case 21: const sum = _.find(calcDetail, {cType: 11}); const chapters = _.filter(calcDetail, {cType: 1}); for (const f of fields) { cd[f] = _.subtract(sum[f], _.sumBy(chapters, f)); } break; case 31: assignStageData(cd, await ctx.service.stageBills.getSumTotalPriceNotGcl(ctx.stage)); break; case 41: const sum1 = _.find(calcDetail, {cType: 11}); const sum2 = _.find(calcDetail, {cType: 31}); for (const f of fields) { cd[f] = _.add(sum1.value, sum2.value); } break; } } ctx.body = {err: 0, msg: '', data: {detail: chapterDetail, decimal: ctx.tender.info.decimal}}; } catch (err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 变更令 * @param ctx * @returns {Promise} */ async change(ctx) { try { await this._getStage(ctx); const renderData = this._getDefaultRenderData(ctx); await this.layout('stage/change.ejs', renderData); } catch (err) { this.log(err); ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage'); } } // 审批相关 /** * 添加审批人 * @param ctx * @returns {Promise} */ async addAudit(ctx) { try { await this._getStage(ctx); const data = JSON.parse(ctx.request.body.data); const id = this.app._.toInteger(data.auditorId); if (isNaN(id) || id <= 0) { throw '参数错误'; } // 检查权限等 if (ctx.stage.user_id !== ctx.session.sessionUser.accountId) { throw '您无权添加审核人'; } if (ctx.stage.status === auditConst.flow.status.checking || ctx.stage.status === auditConst.flow.status.checked) { throw '当前不允许添加审核人'; } // 检查审核人是否已存在 const exist = this.app._.find(ctx.stage.auditors, {aid: id}); if (exist) { throw '该审核人已存在,请勿重复添加'; } const result = await ctx.service.stageAudit.addAuditor(ctx.stage.id, id); if (!result) { throw '添加审核人失败'; } const audit = await ctx.service.stageAudit.getAuditor(ctx.stage.id, id); ctx.body = {err: 0, msg: '', data: audit}; } catch (err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 移除审批人 * @param ctx * @returns {Promise} */ async deleteAudit(ctx) { try { await this._getStage(ctx); 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.stageAudit.deleteAuditor(ctx.stage.id, id, ctx.stage.times); if (!result) { throw '移除审核人失败'; } const auditors = await ctx.service.stageAudit.getAuditors(ctx.stage.id); ctx.body = {err: 0, msg: '', data: auditors}; } catch (err) { ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 上报 * @param ctx * @returns {Promise} */ async startAudit(ctx) { } /** * 审批 * @param ctx * @returns {Promise} */ async checkAudit(ctx) { } _getGatherSpreadSetting() { const _ = this.app._; function removeFieldCols(setting, cols) { _.remove(setting.cols, function (c) { return cols.indexOf(c.field) > -1; }); } function setColFormat(cols, field, formatter) { const filterCols = cols.filter(function (c) { return c.field.search(field) !== -1; }); for (const col of filterCols) { col.formatter = formatter; } } const tpFormatter = this.ctx.helper.getNumberFormatter(this.ctx.tender.info.decimal.tp); const upFormatter = this.ctx.helper.getNumberFormatter(2); const gcl = JSON.parse(JSON.stringify(spreadConst.stageGather.gcl)); setColFormat(gcl.cols, 'unit_price', upFormatter); setColFormat(gcl.cols, 'total_price', tpFormatter); setColFormat(gcl.cols, 'tp', tpFormatter); const leafXmj = JSON.parse(JSON.stringify(spreadConst.stageGather.leafXmj)); const tender = this.ctx.tender; if (tender.data.measure_type === measureType.tz.value) { removeFieldCols(gcl, spreadConst.filterCols.tzWithoutCols); } return [gcl, leafXmj]; } /** * 清单汇总 * @param ctx * @returns {Promise} */ async gather(ctx) { try { await this._getStage(ctx); const renderData = this._getDefaultRenderData(ctx); [renderData.gclSpread, renderData.leafXmjSpread] = this._getGatherSpreadSetting(); renderData.ledger = await ctx.service.ledger.getDataByTenderId(ctx.tender.id, -1); renderData.curLedgerData = await ctx.service.stageBills.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.times, 0); renderData.pos = await ctx.service.pos.getPosData({tid: ctx.tender.id}); // todo 根据当前人,或指定对象查询数据 renderData.curPosData = await ctx.service.stagePos.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.times, ctx.stage.curAuditor ? ctx.stage.curAuditor.order : 0); //renderData.gcl = await this.ctx.service.ledger.getAllLeafGclBills(this.ctx.tender.id); renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.gather); await this.layout('stage/gather.ejs', renderData); } catch (err) { this.log(err); ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage/' + ctx.params.order); } } /** * 审核比较 * @param ctx * @returns {Promise} */ async compare(ctx) { function getCompareSpreadSetting () { function setColFormat(cols, field, formatter) { const filterCols = cols.filter(function (c) { return c.field.search(field) !== -1; }); for (const col of filterCols) { col.formatter = formatter; } } const tpFormatter = ctx.helper.getNumberFormatter(ctx.tender.info.decimal.tp); const upFormatter = ctx.helper.getNumberFormatter(2); const ledger = JSON.parse(JSON.stringify(spreadConst.stageCompare.ledger)); setColFormat(ledger.baseCols, 'unit_price', upFormatter); setColFormat(ledger.extraCols, 'total_price', tpFormatter); setColFormat(ledger.extraCols, 'tp', tpFormatter); const pos = JSON.parse(JSON.stringify(spreadConst.stageCompare.pos)); return [ledger, pos]; }; try { await this._getStage(ctx); const renderData = this._getDefaultRenderData(ctx); [renderData.ledgerSpread, renderData.posSpread] = getCompareSpreadSetting(); renderData.ledger = await ctx.service.ledger.getDataByTenderId(ctx.tender.id, -1); renderData.orgStageLedger = await ctx.service.stageBills.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.times, 0); renderData.pos = await ctx.service.pos.getPosData({tid: ctx.tender.id}); renderData.orgStagePos = await ctx.service.stagePos.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.times, ctx.stage.curAuditor ? ctx.stage.curAuditor.order : 0); renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.compare); await this.layout('stage/compare.ejs', renderData, 'stage/compare_modal.ejs'); } catch (err) { this.log(err); ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage/' + ctx.params.order); } } async compareAuditor(ctx) { try { await this._getStage(ctx); const data = JSON.parse(ctx.request.body.data); const result = []; for (const order of data.auditors) { const data = { order: order, bills: [], pos: [] }; data.bills = await ctx.service.stageBills.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.times, order); data.pos = await ctx.service.stagePos.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.times, order); result.push(data); } ctx.body = {err: 0, msg: '', data: result}; } catch (err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 报表 * @param ctx * @returns {Promise} */ async report(ctx) { try { await this._getStage(ctx); const renderData = this._getDefaultRenderData(ctx); await this.layout('stage/report.ejs', renderData, 'stage/report_modal.ejs'); } catch (err) { this.log(err); ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage'); } } } return StageController; };