'use strict'; /** * * * @author Mai * @date 2018/8/14 * @version */ const moment = require('moment'); const sendToWormhole = require('stream-wormhole'); const fs = require('fs'); const path = require('path'); const audit = require('../const/audit'); const codeRuleConst = require('../const/code_rule'); const changeConst = require('../const/change'); const accountGroup = require('../const/account_group').group; // const tenderMenu = require('../../config/menu').tenderMenu; module.exports = app => { class ChangeController extends app.BaseController { /** * 构造函数 * * @param {Object} ctx - egg全局变量 * @return {void} */ constructor(ctx) { super(ctx); ctx.showProject = true; ctx.showTender = true; ctx.showTitle = true; } async _filterChanges(ctx, status = 0) { const tenderId = ctx.params.id; ctx.session.sessionUser.tenderId = tenderId; const tender = await this.service.tender.getDataById(tenderId); const tenderList = await this.service.tender.getList(); const page = ctx.page; const changes = await ctx.service.change.getListByStatus(tender.id, status); const total = await ctx.service.change.getCountByStatus(tender.id, status); if (changes !== null) { let i = 0; for (const c of changes) { const status = c.status === audit.flow.status.uncheck ? 0 : 1; // 根据审批人对当前变更令的状态取不同的展示方式。 let changeAudit = ''; let auditStatus = 0; switch (c.status) { case 1: auditStatus = 1; break; case 2: changeAudit = await ctx.service.changeAudit.getLastUser(c.cid, c.times, status); auditStatus = changeAudit.uid === ctx.session.sessionUser.accountId ? 1 : 0; break; case 3: case 4: auditStatus = 0; changeAudit = await ctx.service.changeAudit.getLastUser(c.cid, c.times, status); break; case 5: changeAudit = await ctx.service.changeAudit.getLastUser(c.cid, c.times - 1, status); auditStatus = c.uid === ctx.session.sessionUser.accountId ? 1 : 0; break; case 6: changeAudit = await ctx.service.changeAudit.getLastBackUser(c.cid, c.times); const checkingAudit = await ctx.service.changeAudit.getLastUser(c.cid, c.times, status); auditStatus = checkingAudit.uid === ctx.session.sessionUser.accountId ? 1 : 0; break; default: break; } changes[i].changeAudit = changeAudit; changes[i].auditStatus = auditStatus; i++; } } // 分页相关 const pageInfo = { page, total: parseInt(total / app.config.pageSize), queryData: JSON.stringify(ctx.urlInfo.query), }; const filter = JSON.parse(JSON.stringify(audit.filter)); filter.count = []; filter.count[filter.status.pending] = await ctx.service.change.getCountByStatus(tender.id, filter.status.pending);// await ctx.service.change.pendingDatas(tender.id, ctx.session.sessionUser.accountId); filter.count[filter.status.uncheck] = await ctx.service.change.getCountByStatus(tender.id, filter.status.uncheck);// await ctx.service.change.checkingDatas(tender.id, ctx.session.sessionUser.accountId); filter.count[filter.status.checking] = await ctx.service.change.getCountByStatus(tender.id, filter.status.checking);// await ctx.service.change.checkedDatas(tender.id, ctx.session.sessionUser.accountId); filter.count[filter.status.checked] = await ctx.service.change.getCountByStatus(tender.id, filter.status.checked);// await ctx.service.change.pendingDatas(tender.id, ctx.session.sessionUser.accountId); filter.count[filter.status.checkNo] = await ctx.service.change.getCountByStatus(tender.id, filter.status.checkNo);// await ctx.service.change.pendingDatas(tender.id, ctx.session.sessionUser.accountId); const codeRule = tender.c_rule ? JSON.parse(tender.c_rule) : []; for (const rule of codeRule) { switch (rule.rule_type) { case codeRuleConst.measure.ruleType.tenderName: rule.preview = tender.name; break; case codeRuleConst.measure.ruleType.inDate: rule.preview = moment().format('YYYY'); break; case codeRuleConst.measure.ruleType.text: rule.preview = rule.text; break; case codeRuleConst.measure.ruleType.addNo: const s = '0000000000'; rule.preview = s.substr(s.length - rule.format); break; default: break; } } const renderData = { uid: ctx.session.sessionUser.accountId, moment, tender, tenderList, pageInfo, changes, filter, status, codeRule, auditConst: audit.flow, changeConst, ruleType: codeRuleConst.ruleType.change, ruleConst: codeRuleConst.measure, tenderMenu: this.menu.tenderMenu, preUrl: '/tender/' + tenderId, }; await this.layout('change/index.ejs', renderData, 'change/modal.ejs'); } /** * 变更管理 页面 (Get) * * @param {Object} ctx - egg全局变量 * @return {void} */ async index(ctx) { try { await this._filterChanges(ctx); } catch (err) { this.log(err); ctx.redirect('/dashboard'); } } /** * * @param {Object} ctx - egg全局变量 * @return {void} */ async newCode(ctx) { const responseData = { err: 0, msg: '', data: '', }; try { const tenderId = ctx.params.id; if (!tenderId) { throw '当前未打开标段'; } const tenderData = await ctx.service.tender.getDataById(tenderId); const cCodeRule = tenderData.c_rule !== null ? JSON.parse(tenderData.c_rule) : []; const code = []; for (const rule of cCodeRule) { switch (rule.rule_type) { case codeRuleConst.measure.ruleType.tenderName: code.push(tenderData.name); break; case codeRuleConst.measure.ruleType.text: code.push(rule.text); break; case codeRuleConst.measure.ruleType.inDate: code.push(moment().format('YYYY')); break; case codeRuleConst.measure.ruleType.addNo: let s = '0000000000'; const count = rule.start + await ctx.service.change.count({ tid: tenderId }); s = s + count; code.push(s.substr(s.length - rule.format)); break; default: break; } } responseData.data = code.join(tenderData.c_connector !== null && tenderData.c_connector !== 3 ? codeRuleConst.measure.connectorString[tenderData.c_connector] : ''); } catch (err) { responseData.err = 1; responseData.msg = err; } ctx.body = responseData; } /** * 新增变更 (Post) * * @param {Object} ctx - egg全局变量 * @return {void} */ async add(ctx) { try { const tenderId = ctx.params.id; if (!tenderId) { throw '当前未打开标段'; } const data = JSON.parse(ctx.request.body.data); if (!data.code || data.code === '' || !data.name || data.name === '') { throw '变更令号不能为空'; } const change = await ctx.service.change.add(tenderId, ctx.session.sessionUser.accountId, data.code, data.name); ctx.body = { err: 0, msg: '', data: change }; } catch (err) { this.log(err); ctx.body = { err: 1, msg: err.toString() }; } } /** * 变更管理 状态筛选 页面 (Get) * @param {Object} ctx - egg全局变量 * @return {void} */ async status(ctx) { try { const status = parseInt(ctx.params.status); await this._filterChanges(ctx, status); } catch (err) { this.logger.error(err); ctx.redirect('/tender/' + ctx.params.id + '/change'); } } /** * 变更信息 页面 (Get) * * @param {Object} ctx - egg全局变量 * @return {void} */ async info(ctx) { try { const whiteList = this.ctx.app.config.multipart.whitelist; const tenderid = ctx.params.id !== undefined ? ctx.params.id : ctx.session.sessionUser.tenderId; ctx.session.sessionUser.tenderId = tenderid; const tender = await this.service.tender.getDataById(tenderid); const change = await ctx.service.change.getDataByCondition({ cid: ctx.params.cid }); // 后台判断当前人查看info状态 const auditStatus = await ctx.service.changeAudit.getStatusByChange(change); // 获取附件列表 const attList = await ctx.service.changeAtt.getAllDataByCondition({ where: { cid: ctx.params.cid } }); // 根据auditStatus获取审批人列表 const auditList = await ctx.service.changeAudit.getListByStatus(change, auditStatus); // 获取已选清单 const changeList = await ctx.service.changeAuditList.getAllDataByCondition({ where: { cid: ctx.params.cid } }); const renderData = { uid: ctx.session.sessionUser.accountId, tender, change, changeConst, auditStatus, auditConst: audit.flow, attList, whiteList, auditList, changeList, tpUnit: ctx.tender.info.decimal.tp, upUnit: ctx.tender.info.decimal.up, }; // 根据auditStatus状态获取的不同的数据 if (auditStatus === 1 || auditStatus === 2) { // 获取标准清单列表 const dealBillList = await ctx.service.dealBills.getAllDataByCondition({ where: { tender_id: tenderid } }); // 获取清单列表和台账清单列表 const ledger = await ctx.service.ledger.getDataByTenderId(tenderid, -1); const pos = await ctx.service.pos.getPosData({ tid: tenderid }); renderData.ledger = ledger; renderData.pos = pos; renderData.dealBillList = dealBillList; renderData.changeUnits = changeConst.units; renderData.precision = ctx.tender.info.precision; renderData.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'], }); renderData.accountList = accountList; // 重新上报获取审批流程 if (auditStatus === 2) { const auditList2 = await ctx.service.changeAudit.getListByBack(change.cid, change.times); // 展示页右侧审批流程列表 const auditList3 = []; for (let time = 1; time <= change.times; time++) { const auditTimeList = []; for (const al of auditList2) { if (al.times === time) { auditTimeList.push(al); } } auditList3.push(auditTimeList); } renderData.auditList3 = auditList3; } // 根据清单获取提交数据和计算总金额 const changeListData = []; const changeWhiteListData = []; let ototalCost = 0; let ctotalCost = 0; for (const cl of changeList) { const cLArray = [ cl.code, cl.name, cl.bwmx, cl.unit, cl.unit_price, cl.oamount, cl.camount, cl.detail, cl.lid, ]; ototalCost += ctx.helper.accMul(cl.unit_price, cl.oamount); ctotalCost += ctx.helper.accMul(cl.unit_price, cl.camount); if (cl.lid !== 0) { changeListData.push(cLArray.join(';')); } else { changeWhiteListData.push(cLArray.join(';')); } } renderData.changeListData = changeListData.join('^_^'); renderData.changeWhiteListData = changeWhiteListData.join('^_^'); renderData.ototalCost = ototalCost; renderData.ctotalCost = ctotalCost; // 获取公司列表 const companyList = await ctx.service.changeCompany.getAllDataByCondition({ where: { tid: tenderid } }); renderData.companyList = companyList; } else if (auditStatus === 3 || auditStatus === 4 || auditStatus === 5 || auditStatus === 7) { // 展示页左侧审批流程列表和清单审批列表数据 const auditList2 = await ctx.service.changeAudit.getListGroupByTimes(change.cid, change.times); // 展示页右侧审批流程列表 const auditList3 = []; for (let time = 1; time <= change.times; time++) { const auditTimeList = []; for (const al of auditList) { if (al.times === time) { auditTimeList.push(al); } } auditList3.push(auditTimeList); } renderData.auditList3 = auditList3; renderData.changeList = changeList.sort(); let ototalCost = 0; let ctotalCost = 0; let stotalCost = 0; const auditTotalCost = []; for (const cl of changeList) { ototalCost += parseFloat(ctx.helper.roundNum(ctx.helper.accMul(cl.unit_price, cl.oamount), renderData.tpUnit)); ctotalCost += parseFloat(ctx.helper.roundNum(ctx.helper.accMul(cl.unit_price, cl.camount), renderData.tpUnit)); stotalCost += cl.samount !== '' ? parseFloat(ctx.helper.roundNum(ctx.helper.accMul(cl.unit_price, cl.samount), renderData.tpUnit)) : 0; const audit_amount = cl.audit_amount !== null && cl.audit_amount !== '' ? cl.audit_amount.split(',') : ''; auditTotalCost.push(audit_amount); } renderData.ototalCost = ototalCost; renderData.ctotalCost = ctotalCost; renderData.stotalCost = stotalCost; // 清单表页赋值 for (const [index, au] of auditList2.entries()) { if (au.usite !== 0) { au.list_amount = []; au.totalCost = 0; for (const [auindex, at] of auditTotalCost.entries()) { au.list_amount.push(at[index - 1]); au.totalCost += at[index - 1] !== undefined ? parseFloat(ctx.helper.roundNum(ctx.helper.accMul(changeList[auindex].unit_price, at[index - 1]), renderData.tpUnit)) : 0; } } } renderData.auditList2 = auditList2; } else if (auditStatus === 6) { renderData.changeList = changeList.sort(); let ototalCost = 0; let ctotalCost = 0; const auditTotalCost = []; const auditUnit = []; for (const cl of changeList) { ototalCost += parseFloat(ctx.helper.roundNum(ctx.helper.accMul(cl.unit_price, cl.oamount), renderData.tpUnit)); ctotalCost += parseFloat(ctx.helper.roundNum(ctx.helper.accMul(cl.unit_price, cl.camount), renderData.tpUnit)); const audit_amount = cl.audit_amount !== null && cl.audit_amount !== '' ? cl.audit_amount.split(',') : ''; auditTotalCost.push(audit_amount); } renderData.ototalCost = ototalCost; renderData.ctotalCost = ctotalCost; // 清单表页赋值 for (const [index, au] of auditList.entries()) { if (au.usite !== 0) { au.list_amount = []; au.totalCost = 0; if (au.uid === renderData.uid) { for (const [auindex, at] of auditTotalCost.entries()) { if (at[index - 2] !== undefined) { au.list_amount.push(at[index - 2]); au.totalCost += parseFloat(ctx.helper.roundNum(ctx.helper.accMul(changeList[auindex].unit_price, at[index - 2]), renderData.tpUnit)); } else if (at[index - 2] === undefined) { au.list_amount.push(changeList[auindex].camount); au.totalCost += parseFloat(ctx.helper.roundNum(ctx.helper.accMul(changeList[auindex].unit_price, changeList[auindex].camount), renderData.tpUnit)); } } } else { for (const [auindex, at] of auditTotalCost.entries()) { au.list_amount.push(at[index - 1]); au.totalCost += at[index - 1] !== undefined ? parseFloat(ctx.helper.roundNum(ctx.helper.accMul(changeList[auindex].unit_price, at[index - 1]), renderData.tpUnit)) : 0; } } } } } renderData.auditList = auditList; await this.layout('change/info.ejs', renderData, 'change/info_modal.ejs'); } catch (err) { this.log(err); ctx.redirect('/tender/' + ctx.params.id + '/change'); } } /** * 变更令上报和保存 * @param {Object} ctx - egg全局变量 * @return {void} */ async save(ctx) { try { const result = await ctx.service.change.save(ctx.request.body, ctx.session.sessionUser.tenderId); if (!result) { throw '上报失败'; } if (ctx.request.body.changestatus !== undefined && parseInt(ctx.request.body.changestatus) === 2) { ctx.body = { err: 0, msg: '保存成功' }; } else { ctx.redirect('/tender/' + ctx.session.sessionUser.tenderId + '/change'); } } catch (err) { this.log(err); if (ctx.request.body.changestatus !== undefined && parseInt(ctx.request.body.changestatus) === 2) { ctx.body = { err: 1, msg: err.toString() }; } else { ctx.redirect('/tender/' + ctx.session.sessionUser.tenderId + '/change/' + ctx.request.body.cid + '/info'); } } } /** * 变更令审批 * @param {Object} ctx - egg全局变量 * @return {void} */ async approval(ctx) { try { const changeData = await ctx.service.change.getDataByCondition({cid: ctx.request.body.change_id}); if (!changeData) { throw '变更令数据错误'; } const status = parseInt(ctx.request.body.status); let result = false; switch (status) { case 3:// 审批通过 result = await ctx.service.change.approvalSuccess(ctx.request.body, changeData); break; case 4:// 审批终止 result = await ctx.service.change.approvalStop(ctx.request.body); break; case 5:// 审批退回到原报人 result = await ctx.service.change.approvalBack(ctx.request.body, changeData); break; case 6:// 审批退回到上一个审批人 result = await ctx.service.change.approvalBackNew(ctx.request.body, changeData); break; default:break; } if (!result) { throw '审批失败'; } ctx.redirect('/tender/' + changeData.tid + '/change'); } catch (err) { console.log(err); ctx.redirect(ctx.request.header.referer); } } /** * 变更公司管理 * @param {Object} ctx - egg全局变量 * @return {void} */ async updateCompany(ctx) { const responseData = { err: 0, msg: '', data: '', }; try { const data = JSON.parse(ctx.request.body.data); 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 uploadFile(ctx) { const responseData = { err: 0, msg: '', data: [], }; let stream; try { const parts = ctx.multipart({ autoFields: true }); const files = []; let index = 0; while ((stream = await parts()) !== undefined) { // 判断用户是否选择上传文件 if (!stream.filename) { throw '请选择上传的文件!'; } const create_time = Date.parse(new Date()) / 1000; const fileInfo = path.parse(stream.filename); const dirName = 'app/public/upload/changes/' + moment().format('YYYYMMDD'); const fileName = 'changes' + 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); // 保存数据到att表 const fileData = { 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.changeAtt.save(parts.field, fileData, ctx.session.sessionUser.accountId); if (!result) { throw '导入数据库保存失败'; } fileData.in_time = moment(create_time * 1000).format('YYYY-MM-DD'); fileData.filesize = await ctx.helper.bytesToSize(fileData.filesize); fileData.id = result.insertId; delete fileData.filepath; files.push(fileData); ++index; } responseData.data = files; } catch (err) { this.log(err); // 失败需要消耗掉stream 以防卡死 if (stream) { await sendToWormhole(stream); } this.setMessage(err.toString(), this.messageType.ERROR); } ctx.body = responseData; } /** * 下载附件 * @param {Object} ctx - egg全局变量 * @return {void} */ async downloadFile(ctx) { const id = ctx.params.id; if (id) { try { const fileInfo = await ctx.service.changeAtt.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 { const data = JSON.parse(ctx.request.body.data); const fileInfo = await ctx.service.changeAtt.getDataById(data.id); if (fileInfo !== undefined && fileInfo !== '') { // 先删除文件 await fs.unlinkSync(path.join(this.app.baseDir, fileInfo.filepath)); // 再删除数据库 await ctx.service.changeAtt.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 delete(ctx) { try { const result = await ctx.service.change.delete(ctx.request.body.cid); if (!result) { throw '删除变更令失败'; } ctx.redirect(ctx.request.header.referer); } catch (err) { console.log(err); ctx.redirect(ctx.request.header.referer); } } /** * 变更令重新审批 * @param {Object} ctx - egg全局变量 * @return {void} */ async checkAgain(ctx) { try { const changeData = await ctx.service.change.getDataByCondition({ cid: ctx.request.body.cid }); if (!changeData) { throw '变更令数据错误'; } if (changeData.status !== audit.flow.status.checked || ctx.session.sessionUser.accountId !== changeData.uid) { throw '您无权进行该操作'; } // 重新审批 const result = await ctx.service.change.checkAgain(changeData.cid); if (!result) { throw '重新审批失败'; } ctx.redirect('/tender/' + changeData.tid + '/change/' + changeData.cid + '/info'); } catch (err) { console.log(err); ctx.redirect(ctx.request.header.referer); } } } return ChangeController; };