'use strict'; /** * * * @author Mai * @date 2018/6/20 * @version */ const moment = require('moment'); const auditConst = require('../const/audit').stage; const changeAudit = require('../const/audit').flow; const spreadConst = require('../const/spread'); const tenderConst = require('../const/tender'); const payConst = require('../const/deal_pay.js'); const changeConst = require('../const/change'); const measureType = tenderConst.measureType; const path = require('path'); const PayCalculator = require('../lib/pay_calc'); const accountGroup = require('../const/account_group').group; const sendToWormhole = require('stream-wormhole'); const fs = require('fs'); 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 */ async _getDefaultRenderData (ctx) { const data = { tender: ctx.tender.data, tenderMenu: JSON.parse(JSON.stringify(this.menu.stageMenu)), auditConst, measureType, preUrl: '/tender/' + ctx.tender.id + '/measure/stage/' + ctx.params.order, stage: ctx.stage, }; if ((ctx.stage.status === auditConst.status.uncheck || ctx.stage.status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === ctx.stage.user_id) { 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'], }); data.accountList = accountList; } data.tenderMenu.back.children[0].url = '/tender/' + ctx.tender.id + '/measure/stage'; return data; } /** * 获取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 tender = this.ctx.tender, stage = this.ctx.stage; const stageSetting = tender.data.measure_type === measureType.tz.value ? spreadConst.stageTz : (tender.info.display.ledger.clQty ? spreadConst.stageCl : spreadConst.stageNoCl); const ledger = JSON.parse(JSON.stringify(stageSetting.ledger)); // setColFormat(ledger.cols, 'unit_price', upFormatter); // setColFormat(ledger.cols, 'total_price', tpFormatter); // setColFormat(ledger.cols, 'tp', tpFormatter); if (!tender.info.display.ledger.dgnQty) { removeFieldCols(ledger, spreadConst.filterCols.stageDgnCols); } const pos = JSON.parse(JSON.stringify(stageSetting.pos)); if (this.ctx.stage.readOnly || this.ctx.stage.revising) { ledger.readOnly = true; pos.readOnly = true; } return [ledger, pos]; } /** * 获取审批界面所需的 原报、审批人数据等 * @param ctx * @returns {Promise} * @private */ async _getStageAuditViewData (ctx) { const times = ctx.stage.status === auditConst.status.checkNo ? ctx.stage.times - 1 : ctx.stage.times; ctx.stage.user = await ctx.service.projectAccount.getAccountInfoById(ctx.stage.user_id); ctx.stage.auditHistory = []; if (ctx.stage.times > 1) { for (let i = 1; i < ctx.stage.times; i++) { ctx.stage.auditHistory.push(await ctx.service.stageAudit.getAuditors(ctx.stage.id, i)); } } // 获取审批流程中左边列表 ctx.stage.auditors2 = await ctx.service.stageAudit.getAuditGroupByList(ctx.stage.id, times); if (ctx.stage.status === auditConst.status.uncheck || ctx.stage.status === auditConst.status.checkNo) { ctx.stage.auditorList = await ctx.service.stageAudit.getAuditors(ctx.stage.id, ctx.stage.times); } } _checkStageCanModify(ctx) { // 检查登录用户,是否可操作 if (ctx.stage.readOnly) { throw '该计量期当前您无权操作'; } if (ctx.stage.revising) { throw '台账修订中,请勿修改提交期数据'; } } /** * 期计量页面 (Get) * @param {Object} ctx - egg全局变量 * @returns {Promise} */ async index(ctx) { try { await this._getStageAuditViewData(ctx); const renderData = await this._getDefaultRenderData(ctx); [renderData.ledgerSpread, renderData.posSpread] = this._getSpreadSetting(); renderData.changeConst = changeConst; // renderData.ledgerData = await ctx.service.ledger.getData(ctx.tender.id); // const dgnData = await ctx.service.stageBillsDgn.getDgnData(ctx.tender.id); // for (const d of dgnData) { // const l = ctx.app._.find(renderData.ledgerData, {id: d.id}); // ctx.app._.assignIn(l, d); // } // let curStageData, preStageData; // // 当前操作人查看最新数据,其他人查看历史数据 // if (ctx.stage.readOnly) { // curStageData = await ctx.service.stageBills.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.curTimes, ctx.stage.curOrder); // } else { // curStageData = await ctx.service.stageBills.getLastestStageData(ctx.tender.id, ctx.stage.id); // } // // 查询截止上期数据 // if (ctx.stage.order > 1) { // preStageData = await ctx.service.stageBillsFinal.getFinalData(ctx.tender.data, ctx.stage.order - 1); // //renderData.preStageData = await ctx.service.stageBills.getEndStageData(ctx.tender.id, ctx.stage.order - 1); // } else { // preStageData = []; // } // this.ctx.helper.assignRelaData(renderData.ledgerData, [ // {data: curStageData, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'postil'], prefix: '', relaId: 'lid',}, // {data: preStageData, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'], prefix: 'pre_', relaId: 'lid',} // ]); renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.index); renderData.whiteList = this.ctx.app.config.multipart.whitelist; renderData.imType = tenderConst.imType; // 获取附件列表 const attData = await ctx.service.stageAtt.getDataByTenderIdAndStageId(ctx.tender.id, ctx.params.order); for (const index in attData) { attData[index].in_time = moment(attData[index].in_time * 1000).format('YYYY-MM-DD'); } renderData.attData = attData; await this.layout('stage/index.ejs', renderData, 'stage/modal.ejs'); } catch (err) { this.log(err); ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage'); } } async _getStageLedgerData(ctx) { const ledgerData = await ctx.service.ledger.getData(ctx.tender.id); const dgnData = await ctx.service.stageBillsDgn.getDgnData(ctx.tender.id); for (const d of dgnData) { const l = ctx.app._.find(ledgerData, {id: d.id}); ctx.app._.assignIn(l, d); } let curStageData, preStageData; // 当前操作人查看最新数据,其他人查看历史数据 if (ctx.stage.readOnly) { curStageData = await ctx.service.stageBills.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.curTimes, ctx.stage.curOrder); } else { curStageData = await ctx.service.stageBills.getLastestStageData(ctx.tender.id, ctx.stage.id); } // 查询截止上期数据 if (ctx.stage.order > 1) { preStageData = await ctx.service.stageBillsFinal.getFinalData(ctx.tender.data, ctx.stage.order - 1); //renderData.preStageData = await ctx.service.stageBills.getEndStageData(ctx.tender.id, ctx.stage.order - 1); } else { preStageData = []; } this.ctx.helper.assignRelaData(ledgerData, [ {data: curStageData, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'postil'], prefix: '', relaId: 'lid',}, {data: preStageData, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp', 'used'], prefix: 'pre_', relaId: 'lid',} ]); return ledgerData; } async _getStagePosData(ctx) { let curStageData, preStageData; const posData = await ctx.service.pos.getPosDataWithAddStageOrder({tid: ctx.tender.id}); // 根据当前人,或指定对象查询数据 //console.time('cur'); if (ctx.stage.readOnly) { curStageData = await ctx.service.stagePos.getAuditorStageData2(ctx.tender.id, ctx.stage.id, ctx.stage.curTimes, ctx.stage.curOrder); } else { curStageData = await ctx.service.stagePos.getLastestStageData2(ctx.tender.id, ctx.stage.id); } //console.timeEnd('cur'); // 查询截止上期数据 //console.time('pre'); if (ctx.stage.order > 1) { preStageData = await ctx.service.stagePosFinal.getFinalData(ctx.tender.data, ctx.stage.order - 1); //responseData.data.preStageData = await ctx.service.stagePos.getEndStageData(ctx.tender.id, ctx.stage.order - 1); } else { preStageData = []; } //console.timeEnd('pre'); //console.time('assign'); //console.log('cur: ' + curStageData.length); //console.log('pre: ' + preStageData.length); this.ctx.helper.assignRelaData(posData, [ {data: curStageData, fields: ['contract_qty', 'qc_qty', 'postil'], prefix: '', relaId: 'pid'}, {data: preStageData, fields: ['contract_qty', 'qc_qty'], prefix: 'pre_', relaId: 'pid'} ]); return posData; } async _getStageDetailData(ctx) { if (ctx.stage.readOnly) { return await ctx.service.stageDetail.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.curTimes, ctx.stage.curOrder); } else { return await ctx.service.stageDetail.getLastestStageData(ctx.tender.id, ctx.stage.id); } } async _getStageChangeData(ctx) { if (ctx.stage.readOnly) { return await ctx.service.stageChange.getAuditorAllStageData(ctx.tender.id, ctx.stage.id, ctx.stage.curTimes, ctx.stage.curOrder); } else { return await ctx.service.stageChange.getLastestAllStageData(ctx.tender.id, ctx.stage.id); } } async getStageData(ctx) { try { const ledgerData = await this._getStageLedgerData(ctx); const posData = await this._getStagePosData(ctx); const detailData = await this._getStageDetailData(ctx); const changeData = await this._getStageChangeData(ctx); ctx.body = {err: 0, msg: '', data: { ledgerData, posData, detailData, changeData, }}; } catch (err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 获取期数据(截止上期 & 本期) (Ajax) * @param ctx * @returns {Promise} */ async getStagePosData(ctx) { try { const condition = JSON.parse(ctx.request.body.data) || {}; condition.tid = ctx.tender.id; const responseData = {err: 0, msg: '', data: {}}; let curStageData, preStageData; responseData.data = await ctx.service.pos.getPosDataWithAddStageOrder(condition); // 根据当前人,或指定对象查询数据 //console.time('cur'); const curWhere = JSON.parse(ctx.request.body.data); if (ctx.stage.readOnly) { curStageData = await ctx.service.stagePos.getAuditorStageData2(ctx.tender.id, ctx.stage.id, ctx.stage.curTimes, ctx.stage.curOrder, curWhere); } else { curStageData = await ctx.service.stagePos.getLastestStageData2(ctx.tender.id, ctx.stage.id, curWhere); } //console.timeEnd('cur'); // 查询截止上期数据 //console.time('pre'); if (ctx.stage.order > 1) { preStageData = await ctx.service.stagePosFinal.getFinalData(ctx.tender.data, ctx.stage.order - 1); //responseData.data.preStageData = await ctx.service.stagePos.getEndStageData(ctx.tender.id, ctx.stage.order - 1); } else { preStageData = []; } //console.timeEnd('pre'); //console.time('assign'); //console.log('cur: ' + curStageData.length); //console.log('pre: ' + preStageData.length); this.ctx.helper.assignRelaData(responseData.data, [ {data: curStageData, fields: ['contract_qty', 'qc_qty', 'postil'], prefix: '', relaId: 'pid'}, {data: preStageData, fields: ['contract_qty', 'qc_qty'], prefix: 'pre_', relaId: 'pid'} ]); //console.timeEnd('assign'); ctx.body = responseData; } catch (err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 保存数据 (Ajax) * @param ctx * @returns {Promise} */ async updateStageData(ctx) { try { this._checkStageCanModify(ctx); 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) { if (data.bills.main) { const updateDatas = data.bills.main instanceof Array ? data.bills.main : [data.bills.main]; const result = await ctx.app.mysql.updateRows(ctx.service.ledger.tableName, updateDatas); responseData.data.bills = await ctx.service.ledger.getDataByIds(this.ctx.helper._.map(updateDatas, 'id')); } if (data.bills.dgn) { responseData.data.dgn = await ctx.service.stageBillsDgn.saveDgnData(data.bills.dgn); } if (data.bills.stage) { responseData.data.curStageData = await ctx.service.stageBills.updateStageData(data.bills.stage); } if (data.bills.calcType) { responseData.data = await ctx.service.stageBills.updateStageBillsCalcType(data.bills.calcType); } } await ctx.service.stage.updateCheckCalcFlag(ctx.stage.id, true); await ctx.service.stage.updateCacheTime(ctx.stage.id); ctx.body = responseData; } catch (err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 查询可用变更令 (Ajax-Post) * @param ctx * @returns {Promise} */ async searchValidChange(ctx) { try { const data = JSON.parse(ctx.request.body.data); if (!data.bills && !data.pos) { throw '数据错误'; } const bills = data.bills ? data.bills : await ctx.service.ledger.getDataById(data.pos.lid); const pos = data.pos; const changes = await ctx.service.change.getValidChanges(ctx.tender.id, bills); const useChanges = await ctx.service.stageChange.getLastestStageData(ctx.tender.id, ctx.stage.id, bills.id, pos ? pos.id : -1); ctx.body = {err: 0, msg: '', data: {changes, useChanges}}; } catch(err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 调用变更令 (Ajax-Post) * @param ctx * @returns {Promise} */ async useChange(ctx) { try { this._checkStageCanModify(ctx); const data = JSON.parse(ctx.request.body.data); if (!data.target || (!data.target.bills && !data.target.pos) || !data.change) { throw '调用变更令数据错误' } let result; if (data.target.pos) { result = await ctx.service.stageChange.posChange(data.target.pos, data.change); result.change = { target: {lid: data.target.pos.lid, pid: data.target.pos.id } }; result.change.data = await ctx.service.stageChange.getLastestStageData(ctx.tender.id, ctx.stage.id, data.target.pos.lid, data.target.pos.id); } else { result = await ctx.service.stageChange.billsChange(data.target.bills, data.change); result.change = { target: { lid: data.target.bills.id, pid: '-1' } }; result.change.data = await ctx.service.stageChange.getLastestStageData(ctx.tender.id, ctx.stage.id, data.target.bills.id, '-1'); } await ctx.service.stage.updateCheckCalcFlag(ctx.stage.id, true); await ctx.service.stage.updateCacheTime(ctx.stage.id); ctx.body = {err: 0, msg: '', data: result}; } catch(err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 查询变更令 明细数据(包括附件、变更清单、累计使用情况、本期使用情况) (Ajax-Post) * @param ctx * @returns {Promise} */ async changeDetail(ctx) { try { const data = JSON.parse(ctx.request.body.data); if (!data.cid) { throw '查询数据错误'; } const detailData = await this._getChangeDetailData(ctx.tender.id, ctx.stage.id, data.cid); ctx.body = {err: 0, msg: '', data: detailData}; } catch(err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 中间计量 (Get) * @param ctx * @returns {Promise} */ async detail(ctx) { try { await this._getStageAuditViewData(ctx); const renderData = await 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); } } /** * 设置中间计量生成规则,并生成中间计量数据 (Ajax) * @param ctx * @returns {Promise} */ async buildDetailData (ctx) { try { this._checkStageCanModify(ctx); const data = JSON.parse(ctx.request.body.data); await ctx.service.stage.buildDetailData(ctx.tender.id, ctx.stage.order, data); await ctx.service.stage.updateCacheTime(ctx.stage.id); ctx.body = {err: 0, msg: '', data: null}; } catch (err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 加载数据 (Ajax) * @param ctx * @returns {Promise} */ async loadDetailRelaData(ctx) { try { const data = JSON.parse(ctx.request.body.data); // 加载台账数据 if (data.loadType === 'ledger') { const ledgerData = await ctx.service.ledger.getData(ctx.tender.id); ctx.body = {err: 0, msg: '', data: ledgerData }; } else if (data.loadType === 'all') { const result = {}; result.ledger = await ctx.service.ledger.getData(ctx.tender.id); result.pos = await ctx.service.pos.getPosData({tid: ctx.tender.id}); if (ctx.stage.readOnly) { const curStage = await ctx.service.stageBills.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.curTimes, ctx.stage.curOrder); this.ctx.helper.assignRelaData(result.ledger, [ {data: curStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'], prefix: '', relaId: 'lid'} ]); const curPosStage = await ctx.service.stagePos.getAuditorStageData2(ctx.tender.id, ctx.stage.id, ctx.stage.curTimes, ctx.stage.curOrder); this.ctx.helper.assignRelaData(result.pos, [ {data: curPosStage, fields: ['contract_qty', 'qc_qty'], prefix: '', relaId: 'pid'} ]); } else { const curStage = await ctx.service.stageBills.getLastestStageData(ctx.tender.id, ctx.stage.id); this.ctx.helper.assignRelaData(result.ledger, [ {data: curStage, fields: ['contract_qty', 'contract_tp', 'qc_qty', 'qc_tp'], prefix: '', relaId: 'lid'} ]); const curPosStage = await ctx.service.stagePos.getLastestStageData2(ctx.tender.id, ctx.stage.id); this.ctx.helper.assignRelaData(result.pos, [ {data: curPosStage, fields: ['contract_qty', 'qc_qty'], prefix: '', relaId: 'pid'} ]); } result.stageDetail = await this._getStageDetailData(ctx); result.changeData = await this._getStageChangeData(ctx); ctx.body = { err: 0, msg: '', data: result }; } } catch (err) { this.log(err); ctx.body = { err: 1, msg: err.toString(), data: null }; } } /** * 中间计量,生成规则,高级设置 (Ajax) * @param ctx * @returns {Promise} */ async setAdvancedConfig(ctx) { try { this._checkStageCanModify(ctx); const data = JSON.parse(ctx.request.body.data); await ctx.service.stage.update(data, { id: ctx.stage.id }); await ctx.service.stage.updateCacheTime(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}; } } /** * 中间计量,编辑中间计量数据(Ajax) * @param ctx * @returns {Promise} */ async saveDetailData(ctx) { try { this._checkStageCanModify(ctx); const data = JSON.parse(ctx.request.body.data); const responseData = { err: 0, msg: '', data: {}, }; if (data instanceof Array) { responseData.data = await ctx.service.stageDetail.saveDetailDatas(data); } else { responseData.data = await ctx.service.stageDetail.saveDetailData(data); } await ctx.service.stage.updateCacheTime(ctx.stage.id); ctx.body = responseData; } catch (err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 中间计量,添加草图,上传图片 (Ajax) * @param ctx * @returns {Promise} */ async addCalcImage(ctx) { try { this._checkStageCanModify(ctx); 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}; } } /** * 中间计量,设置草图 (Ajax) * @param ctx * @returns {Promise} */ async mergeCalcImage(ctx) { try { this._checkStageCanModify(ctx); 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 + '.png'); 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); await ctx.service.stage.updateCacheTime(ctx.stage.id); const responseData = {err: 0, msg: '', data: imData}; ctx.body = responseData; } catch (err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 合同支付 (Get) * @param ctx * @returns {Promise} */ async pay(ctx) { try { await this._getStageAuditViewData(ctx); const renderData = await this._getDefaultRenderData(ctx); const dealPay = await ctx.service.stagePay.getStagePays(ctx.stage); // 附件不取下载地址 for (const index in dealPay) { if (dealPay[index].attachment !== null) { const attachments = JSON.parse(dealPay[index].attachment); for (const att_index in attachments) { delete attachments[att_index].filepath; attachments[att_index].username = (await ctx.service.projectAccount.getAccountInfoById(attachments[att_index].uid)).name; } dealPay[index].attachment = attachments; } } renderData.dealPay = dealPay; renderData.calcBase = await ctx.service.stage.getStagePayCalcBase(ctx.stage, ctx.tender.info); renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.pay); renderData.whiteList = this.ctx.app.config.multipart.whitelist; if (ctx.stage.order > 1) { renderData.pre = await ctx.service.stageBillsFinal.getSumTotalPrice(ctx.stage.tid, ctx.stage.order - 1); renderData.pre.gather_tp = ctx.helper.add(renderData.pre.contract_tp, renderData.pre.qc_tp); } else { renderData.pre = {contract_tp: null, qc_tp: null, gather_tp: null}; } // 用户有无权限上传和删除附件 renderData.uploadPermission = ((ctx.stage.status === auditConst.status.uncheck || ctx.stage.status === auditConst.status.checkNo) && ctx.session.sessionUser.accountId === ctx.stage.user_id) || (ctx.stage.status === auditConst.status.checkNoPre && ctx.session.sessionUser.accountId === ctx.stage.curAuditor.aid) || (ctx.stage.status === auditConst.status.checking && ctx.stage.curAuditor && ctx.stage.curAuditor.aid === ctx.session.sessionUser.accountId); if (!ctx.stage.readOnly) { // 计算 本期金额 const payCalculator = new PayCalculator(ctx, ctx.stage, ctx.tender.info); await payCalculator.calculateAll(renderData.dealPay); await this.ctx.service.stage.update({ check_calc: false, contract_tp: payCalculator.cur.contract_tp, qc_tp: payCalculator.cur.qc_tp, yf_tp: payCalculator.yf.tp, }, {id: this.ctx.stage.id}); } await this.layout('stage/pay.ejs', renderData, 'stage/pay_modal.ejs'); } catch (err) { console.log(err); this.log(err); ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage'); } } /** * 合同支付 - 编辑合同支付项 (Ajax) * @param ctx * @returns {Promise} */ async savePayData(ctx) { function checkCalcField(data) { return data.sexpr !== undefined || data.sprice !== undefined || data.rexpr !== undefined || data.rprice !== undefined || data.minus !== undefined || data.is_yf !== undefined || data.dl_type !== undefined } try { this._checkStageCanModify(ctx); const data = JSON.parse(ctx.request.body.data); const responseData = { err: 0, msg: '', data: {}, }; const payCalculator = new PayCalculator(ctx, ctx.stage, ctx.tender.info); switch (data.type) { case 'add': responseData.data = await ctx.service.pay.add(); responseData.data = await ctx.service.stagePay.getStagePay(ctx.stage, responseData.data.pid); break; case 'del': await ctx.service.pay.del(data.id); responseData.data = await ctx.service.stagePay.getStagePays(ctx.stage); await payCalculator.calculate(responseData.data); await this.ctx.service.stage.update({ check_calc: false, contract_tp: payCalculator.cur.contract_tp, qc_tp: payCalculator.cur.qc_tp, yf_tp: payCalculator.yf.tp, }, {id: this.ctx.stage.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); const bReCalc = data.updateData instanceof Array ? checkCalcField(data.updateData[0]) : checkCalcField(data.updateData); if (bReCalc) { responseData.data = await ctx.service.stagePay.getStagePays(ctx.stage); await payCalculator.calculateAll(responseData.data); await this.ctx.service.stage.update({ check_calc: false, contract_tp: payCalculator.cur.contract_tp, qc_tp: payCalculator.cur.qc_tp, yf_tp: payCalculator.yf.tp, }, {id: this.ctx.stage.id}); } else { if (data.updateData instanceof Array) { responseData.data = await ctx.service.stagePay.getStagePay(ctx.stage, this.app._.map(responseData.data, 'id')); } else { responseData.data = await ctx.service.stagePay.getStagePay(ctx.stage, responseData.data.id); } } break; case 'stage': await ctx.service.stagePay.save(data.updateData); responseData.data = await ctx.service.stagePay.getStagePays(ctx.stage); await payCalculator.calculateAll(responseData.data); await this.ctx.service.stage.update({ check_calc: false, contract_tp: payCalculator.cur.contract_tp, qc_tp: payCalculator.cur.qc_tp, yf_tp: payCalculator.yf.tp, }, {id: this.ctx.stage.id}); break; } ctx.body = responseData; } catch(err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 合同支付 - 章节明细 (Ajax-Post) * @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 = ctx.helper.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 = ctx.helper.add(preStage.contract_tp, preStage.qc_tp); chapter.end_contract_tp = ctx.helper.add(curStage.contract_tp, preStage.contract_tp); chapter.end_qc_tp = ctx.helper.add(curStage.qc_tp, preStage.qc_tp); chapter.end_gather_tp = ctx.helper.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 { 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] = ctx.helper.sub(sum[f], this.ctx.helper.sum(_.map(chapters, 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] = ctx.helper.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 tid * @param sid * @param cid * @returns {Promise<{}>} * @private */ async _getChangeDetailData(tid, sid, cid) { const data = {}; data.attachments = await this.ctx.service.changeAtt.getChangeAttachment(cid); data.bills = await this.ctx.service.changeAuditList.getAllDataByCondition({where: {cid: cid}}); data.addUsedBills = await this.ctx.service.stageChange.getUsedData(tid, cid); data.curUsedBills = await this.ctx.service.stageChange.getStageUsedData(sid, cid); return data; } /** * 获取变更数据 Post(Ajax) * @param ctx * @returns {Promise} */ async getChangeData(ctx) { try { const data = {}; data.tenderInfo = ctx.tender.info; data.ledger = await ctx.service.ledger.getData(ctx.tender.id); data.usedChangesId = await ctx.service.stageChange.getStageUsedChangeId(ctx.stage.id); data.changes = await ctx.service.change.getChangeAndUsedInfo(ctx.tender.id); if (data.changes.length > 0) { const change = data.changes[0]; change.detail = await this._getChangeDetailData(ctx.tender.id, ctx.stage.id, change.cid); } ctx.body = {err: 0, msg: '', data: data}; } catch (err) { this.log(err); ctx.body = {err: 1, msg: err.toString(), data: null}; } } /** * 变更令 (Get) * @param ctx * @returns {Promise} */ async change(ctx) { try { await this._getStageAuditViewData(ctx); const renderData = await this._getDefaultRenderData(ctx); renderData.changeConst = changeConst; renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.change); await this.layout('stage/change.ejs', renderData, 'stage/audit_modal.ejs'); } catch (err) { this.log(err); ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage'); } } // 审批相关 /** * 添加审批人 * @param ctx * @returns {Promise} */ async addAudit(ctx) { try { this._checkStageCanModify(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.status.checking || ctx.stage.status === auditConst.status.checked) { throw '当前不允许添加审核人'; } ctx.stage.auditorList = await ctx.service.stageAudit.getAuditors(ctx.stage.id, ctx.stage.times); // 检查审核人是否已存在 const exist = this.app._.find(ctx.stage.auditorList, {aid: id}); if (exist) { throw '该审核人已存在,请勿重复添加'; } const result = await ctx.service.stageAudit.addAuditor(ctx.stage.id, id, ctx.stage.times); if (!result) { throw '添加审核人失败'; } const audit = await ctx.service.stageAudit.getAuditor(ctx.stage.id, id, ctx.stage.times); 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 { this._checkStageCanModify(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.stage.times); 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) { try { this._checkStageCanModify(ctx); if (ctx.stage.user_id !== ctx.session.sessionUser.accountId) { throw '您无权上报该期数据'; } if (ctx.stage.status === auditConst.status.checking || ctx.stage.status === auditConst.status.checked) { throw '该期数据当前无法上报'; } await ctx.service.stageAudit.start(ctx.stage.id, ctx.stage.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 * @returns {Promise} */ async checkAudit(ctx) { try { this._checkStageCanModify(ctx); if (!this.ctx.stage || (this.ctx.stage.status !== auditConst.status.checking && this.ctx.stage.status !== auditConst.status.checkNoPre)) { throw '当前期数据有误'; } if (!this.ctx.stage.curAuditor || this.ctx.stage.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.stageAudit.check(ctx.stage.id, data, ctx.stage.times); ctx.redirect(ctx.request.header.referer); } catch (err) { console.log(err); this.log(err); ctx.session.postError = err.toString(); ctx.redirect(ctx.request.header.referer); } } /** * 重新审批 * @param ctx * @returns {Promise} */ async checkAuditAgain(ctx) { try { if (ctx.stage.revising) { throw '台账修订中,请勿修改提交期数据'; } if (ctx.stage.auditors[ctx.stage.auditors.length - 1].aid === ctx.session.sessionUser.accountId && ctx.stage.status === auditConst.status.checked && ctx.stage.order === ctx.stage.highOrder) { await ctx.service.stageAudit.checkAgain(ctx.stage.id, ctx.stage.times); console.log('success'); ctx.redirect(ctx.request.header.referer); } else { throw '您无权进行该操作'; } } catch (err) { console.log(err); this.log(err); ctx.session.postError = err.toString(); ctx.redirect(ctx.request.header.referer); } } // 清单汇总相关 _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]; } /** * 清单汇总 页面 (Get) * @param ctx * @returns {Promise} */ async gather(ctx) { try { await this._getStageAuditViewData(ctx); const renderData = await this._getDefaultRenderData(ctx); [renderData.gclSpread, renderData.leafXmjSpread] = this._getGatherSpreadSetting(); renderData.ledger = await ctx.service.ledger.getData(ctx.tender.id); renderData.curLedgerData = await ctx.service.stageBills.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.curTimes, ctx.stage.curOrder); if (ctx.stage.order > 1) { renderData.preLedgerData = await ctx.service.stageBillsFinal.getFinalData(ctx.tender.data, ctx.stage.order - 1); } else { renderData.preLedgerData = []; } 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.curTimes, ctx.stage.curOrder); if (ctx.stage.order > 1) { renderData.prePosData = await ctx.service.stagePosFinal.getFinalData(ctx.tender.data, ctx.stage.order - 1); } else { renderData.prePosData = []; } renderData.dealBills = await ctx.service.dealBills.getAllDataByCondition({ where: {tender_id: this.ctx.tender.id} }); renderData.jsFiles = this.app.jsFiles.common.concat(this.app.jsFiles.stage.gather); await this.layout('stage/gather.ejs', renderData, 'stage/gather_modal.ejs'); } catch (err) { this.log(err); ctx.redirect('/tender/' + ctx.tender.id + '/measure/stage/' + ctx.params.order); } } /** * 审核比较 页面 (Get) * @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._getStageAuditViewData(ctx); const renderData = await this._getDefaultRenderData(ctx); if (ctx.stage.times !== ctx.stage.curTimes) { renderData.compareAuditors = ctx.stage.auditHistory[ctx.stage.curTimes - 1]; } else { renderData.compareAuditors = ctx.stage.auditors; } [renderData.ledgerSpread, renderData.posSpread] = getCompareSpreadSetting(); 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 { const data = JSON.parse(ctx.request.body.data); const result = { main: null, roles: [] }; if (data.main) { result.main = {}; result.main.ledger = await ctx.service.ledger.getData(ctx.tender.id); result.main.pos = await ctx.service.pos.getPosData({tid: ctx.tender.id}); } for (const order of data.roles) { const data = { order: order, bills: [], pos: [] }; data.bills = await ctx.service.stageBills.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.curTimes, order); data.pos = await ctx.service.stagePos.getAuditorStageData(ctx.tender.id, ctx.stage.id, ctx.stage.curTimes, order); result.roles.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 { const renderData = await 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'); } } /** * 上传附件 * @param {Object} ctx - egg全局变量 * @return {void} */ async uploadFile(ctx) { const responseData = { err: 0, msg: '', data: [], }; let stream; try { this._checkStageCanModify(ctx); const parts = ctx.multipart({ autoFields: true }); const files = []; let index = 0; while ((stream = await parts()) !== undefined) { // 判断用户是否选择上传文件 if (!stream.filename) { throw '请选择上传的文件!'; } const dirName = 'app/public/upload/stage/' + moment().format('YYYYMMDD'); // 判断文件夹是否存在,不存在则直接创建文件夹 if (!fs.existsSync(path.join(this.app.baseDir, dirName))) { await fs.mkdirSync(path.join(this.app.baseDir, dirName)); } const create_time = Date.parse(new Date()) / 1000; const fileInfo = path.parse(stream.filename); const fileName = 'stage' + create_time + '_' + index + fileInfo.ext; // 保存文件 await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, dirName, fileName)); if (stream) { await sendToWormhole(stream); } // 保存数据到att表 const fileData = { tid: ctx.params.id, sid: ctx.params.order, in_time: create_time, filename: fileInfo.name, fileext: fileInfo.ext, filesize: Array.isArray(parts.field.size) ? parts.field.size[index] : parts.field.size, filepath: path.join(dirName, fileName), }; const result = await ctx.service.stageAtt.save(parts.field, fileData, ctx.session.sessionUser.accountId); if (!result) { throw '导入数据库保存失败'; } const attData = await ctx.service.stageAtt.getDataByFid(result.insertId); attData.in_time = moment(create_time * 1000).format('YYYY-MM-DD'); files.length !== 0 ? files.unshift(attData) : files.push(attData); ++index; } responseData.data = files; } catch (err) { this.log(err); // 失败需要消耗掉stream 以防卡死 if (stream) { await sendToWormhole(stream); } this.setMessage(err.toString(), this.messageType.ERROR); responseData.err = 1; responseData.msg = err.toString(); } ctx.body = responseData; } /** * 下载附件 * @param {Object} ctx - egg全局变量 * @return {void} */ async downloadFile(ctx) { const id = ctx.params.fid; if (id) { try { const fileInfo = await ctx.service.stageAtt.getDataById(id); if (fileInfo !== undefined && fileInfo !== '') { const fileName = path.join(this.app.baseDir, fileInfo.filepath); // 解决中文无法下载问题 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); } else { throw '不存在该文件'; } } catch (err) { this.log(err); this.setMessage(err.toString(), this.messageType.ERROR); } } } /** * 删除附件 * @param {Object} ctx - egg全局变量 * @return {void} */ async deleteFile(ctx) { const responseData = { err: 0, msg: '', data: '', }; try { this._checkStageCanModify(ctx); const data = JSON.parse(ctx.request.body.data); const fileInfo = await ctx.service.stageAtt.getDataById(data.id); if (fileInfo !== undefined && fileInfo !== '') { // 先删除文件 await fs.unlinkSync(path.join(this.app.baseDir, fileInfo.filepath)); // 再删除数据库 await ctx.service.stageAtt.deleteById(data.id); responseData.data = ''; } else { throw '不存在该文件'; } // if (data.tid === undefined || data.uci === undefined || data.uc === undefined || data.ac === undefined) { // throw '参数有误'; // } // const [addCompany, selectCompany] = await ctx.service.changeCompany.setCompanyList(data); // responseData.data = { add: addCompany, select: selectCompany }; } catch (err) { responseData.err = 1; responseData.msg = err; } ctx.body = responseData; } /** * 保存附件(或替换) * @param {Object} ctx - egg全局变量 * @return {void} */ async saveFile(ctx) { const responseData = { err: 0, msg: '', data: [], }; let stream; try { this._checkStageCanModify(ctx); stream = await ctx.getFileStream({ requireFile: false }); let fileData = {}; if (stream.filename !== undefined) { const create_time = Date.parse(new Date()) / 1000; const fileInfo = path.parse(stream.filename); const dirName = 'app/public/upload/stage/' + moment().format('YYYYMMDD'); const fileName = 'stage' + create_time + fileInfo.ext; // 判断文件夹是否存在,不存在则直接创建文件夹 if (!fs.existsSync(path.join(this.app.baseDir, dirName))) { await fs.mkdirSync(path.join(this.app.baseDir, dirName)); } // 保存文件 await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, dirName, fileName)); // 保存数据到att表 fileData = { filesize: stream.fields.size, filepath: path.join(dirName, fileName), }; } const result = await ctx.service.stageAtt.updateByID(stream.fields, fileData); if (!result) { throw '导入数据库保存失败'; } const attData = await ctx.service.stageAtt.getDataByFid(stream.fields.id); attData.in_time = moment(attData.in_time * 1000).format('YYYY-MM-DD'); responseData.data = attData; } catch (err) { this.log(err); // 失败需要消耗掉stream 以防卡死 if (stream) { await sendToWormhole(stream); } this.setMessage(err.toString(), this.messageType.ERROR); responseData.err = 1; responseData.msg = err.toString(); } ctx.body = responseData; } /** * 合同支付上传附件 * @param {Object} ctx - egg全局变量 * @return {void} */ async payUploadFile(ctx) { const responseData = { err: 0, msg: '', data: [], }; let stream; try { this._checkStageCanModify(ctx); const parts = ctx.multipart({ autoFields: true }); const files = []; let index = 0; const create_time = Date.parse(new Date()) / 1000; while ((stream = await parts()) !== undefined) { // 判断用户是否选择上传文件 if (!stream.filename) { throw '请选择上传的文件!'; } const fileInfo = path.parse(stream.filename); const dirName = 'app/public/upload/pay/' + moment().format('YYYYMMDD'); const fileName = 'pay' + create_time + '_' + index + fileInfo.ext; // 判断文件夹是否存在,不存在则直接创建文件夹 if (!fs.existsSync(path.join(this.app.baseDir, dirName))) { await fs.mkdirSync(path.join(this.app.baseDir, dirName)); } // 保存文件 await ctx.helper.saveStreamFile(stream, path.join(this.app.baseDir, dirName, fileName)); await sendToWormhole(stream); // 插入到stage_pay对应的附件列表中 const attData = { filename: fileInfo.name, fileext: fileInfo.ext, filesize: Array.isArray(parts.field.size) ? parts.field.size[index] : parts.field.size, filepath: path.join(dirName, fileName), uid: ctx.session.sessionUser.accountId, in_time: moment(create_time * 1000).format('YYYY-MM-DD'), }; const result = await ctx.service.stagePay.saveAtt(parts.field.pay_id, attData); if (!result) { throw '导入数据库保存失败'; } delete attData.filepath; attData.username = ctx.session.sessionUser.name; files.length !== 0 ? files.unshift(attData) : files.push(attData); ++index; } responseData.data = files; } catch (err) { this.log(err); // 失败需要消耗掉stream 以防卡死 if (stream) { await sendToWormhole(stream); } this.setMessage(err.toString(), this.messageType.ERROR); responseData.err = 1; responseData.msg = err.toString(); } ctx.body = responseData; } /** * 合同支付下载附件 * @param {Object} ctx - egg全局变量 * @return {void} */ async payDownloadFile(ctx) { const id = ctx.params.pid; const index = ctx.params.index; if (id && index) { try { const payInfo = await ctx.service.stagePay.getDataById(id); if (payInfo !== undefined && payInfo.attachment !== null) { const fileInfo = JSON.parse(payInfo.attachment)[index]; const fileName = path.join(this.app.baseDir, fileInfo.filepath); // 解决中文无法下载问题 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); } else { throw '不存在该文件'; } } catch (err) { this.log(err); this.setMessage(err.toString(), this.messageType.ERROR); } } } /** * 合同支付删除附件 * @param {Object} ctx - egg全局变量 * @return {void} */ async payDeleteFile(ctx) { const responseData = { err: 0, msg: '', data: '', }; try { this._checkStageCanModify(ctx); const data = JSON.parse(ctx.request.body.data); const payInfo = await ctx.service.stagePay.getDataById(data.id); if (payInfo !== undefined) { const fileInfo = JSON.parse(payInfo.attachment)[data.index]; // 先删除文件 await fs.unlinkSync(path.join(this.app.baseDir, fileInfo.filepath)); // 再删除数据库 const attachment = JSON.parse(payInfo.attachment); attachment.splice(data.index, 1); const result = await ctx.service.stagePay.deleteAtt(data.id, attachment); responseData.data = ''; } else { throw '不存在该文件'; } // if (data.tid === undefined || data.uci === undefined || data.uc === undefined || data.ac === undefined) { // throw '参数有误'; // } // const [addCompany, selectCompany] = await ctx.service.changeCompany.setCompanyList(data); // responseData.data = { add: addCompany, select: selectCompany }; } catch (err) { responseData.err = 1; responseData.msg = err; } ctx.body = responseData; } } return StageController; };