'use strict'; /** * 台账相关控制器 * * @author CaiAoLin * @date 2017/11/30 * @version */ const stdDataAddType = { self: 1, withParent: 2, }; const auditConst = require('../const/audit').flow; const tenderMenu = require('../../config/menu').tenderMenu; const measureType = require('../const/tender').measureType; const spreadConst = require('../const/spread'); const fs = require('fs'); const LzString = require('lz-string'); module.exports = app => { class LedgerController extends app.BaseController { /** * 构造函数 * * @param {Object} ctx - egg全局变量 * @return {void} */ constructor(ctx) { super(ctx); ctx.showProject = true; ctx.showTitle = true; ctx.showTender = true; } /** * 检查标段是否只读(审核中,审核完成) * @param {Object} tenderData * @return {boolean} * @private */ _ledgerReadOnly() { const tender = this.ctx.tender.data; return tender.ledger_status === auditConst.status.checking || tender.ledger_status === auditConst.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 col = _.find(cols, function (c) { return c.field === field; }); 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.ledgerSpread)); setColFormat(ledger.cols, 'unit_price', upFormatter); setColFormat(ledger.cols, 'total_price', tpFormatter); setColFormat(ledger.cols, 'deal_tp', tpFormatter); const pos = JSON.parse(JSON.stringify(spreadConst.ledgerPosSpread)); const tender = this.ctx.tender; if (this._ledgerReadOnly(tender.data)) { ledger.readOnly = true; pos.readOnly = true; } if (tender.data.measure_type === measureType.tz.value) { removeFieldCols(ledger, spreadConst.filterCols.tzWithoutCols); } if (!tender.info.display.ledger.dgnQty) { removeFieldCols(ledger, spreadConst.filterCols.dgnCols); } return [ledger, pos]; } /** * 台账分解页面 (Get) * * @param {Object} ctx - egg全局变量 * @return {void} */ async explode(ctx) { try { const tender = ctx.tender; const [ledgerSpread, posSpread] = this._getSpreadSetting(); const curAuditor = await ctx.service.ledgerAudit.getCurAuditor(tender.id, tender.data.ledger_times); const times = tender.data.ledger_status === auditConst.status.checkNo ? tender.data.ledger_times - 1 : tender.data.ledger_times; const auditors = await ctx.service.ledgerAudit.getAuditors(tender.id, times); const content = auditors.length > 0 ? await ctx.service.ledgerAuditContent.getAllDataByCondition({ where: { tender_id: tender.id, times, audit_id: auditors[0].audit_id }, }) : null; const ledgerData = await ctx.service.ledger.getDataByTenderId(tender.id, -1); const user = await ctx.service.projectAccount.getAccountInfoById(ctx.tender.data.user_id); const auditHistory = []; if (ctx.tender.data.ledger_times > 1) { for (let i = 1; i < ctx.tender.data.ledger_times; i++) { auditHistory.push(await ctx.service.ledgerAudit.getAuditors(ctx.tender.id, i)); } } const renderData = { tender: tender.data, tenderInfo: tender.info, auditConst, auditors, curAuditor, user, auditHistory, content, ledger: JSON.stringify(ledgerData), ledgerSpreadSetting: JSON.stringify(ledgerSpread), posSpreadSetting: JSON.stringify(posSpread), tenderMenu, preUrl: '/tender/' + tender.id, measureType, jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.ledger.explode), }; await this.layout('ledger/explode.ejs', renderData, 'ledger/explode_modal.ejs'); } catch (err) { this.log(err); await this.layout('/dashboard'); } } /** * 获取子节点 (Ajax) * @param ctx * @return {Promise} */ async getChildren(ctx) { const responseData = { err: 0, msg: '', data: [], }; try { const data = JSON.parse(ctx.request.body.data); const id = data.ledger_id; if (isNaN(id) || id <= 0) { throw '参数错误'; } responseData.data = await ctx.service.ledger.getChildrenByParentId(ctx.tender.id, id); } catch (err) { responseData.err = 1; responseData.msg = err; } ctx.body = responseData; } /** * 树结构基本操作(增、删、上下移、升降级)(Ajax) * @param {Object} ctx - egg全局变量 * @return {Promise} */ async baseOperation(ctx) { const responseData = { err: 0, msg: '', data: [], }; try { if (!ctx.tender.data || ctx.tender.data.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly()) { throw '标段数据错误'; } const data = JSON.parse(ctx.request.body.data); switch (data.postType) { case 'add': responseData.data = await ctx.service.ledger.addNode(ctx.tender.id, data.id); break; case 'delete': responseData.data = await ctx.service.ledger.deleteNode(ctx.tender.id, data.id); break; case 'up-move': responseData.data = await ctx.service.ledger.upMoveNode(ctx.tender.id, data.id); break; case 'down-move': responseData.data = await ctx.service.ledger.downMoveNode(ctx.tender.id, data.id); break; case 'up-level': responseData.data = await ctx.service.ledger.upLevelNode(ctx.tender.id, data.id); break; case 'down-level': responseData.data = await ctx.service.ledger.downLevelNode(ctx.tender.id, data.id); break; default: throw '未知操作'; } } catch (err) { responseData.err = 1; responseData.msg = err; this.log(err); } ctx.body = responseData; } /** * 提交更新数据 (Ajax) * @param ctx * @return {Promise} */ async updateInfo(ctx) { const responseData = { err: 0, msg: '', data: [], }; try { if (!ctx.tender.data || ctx.tender.data.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly()) { throw '标段数据错误'; } const data = JSON.parse(ctx.request.body.data); if (data instanceof Array) { responseData.data = await ctx.service.ledger.updateInfos(ctx.tender.id, data); } else { responseData.data = await ctx.service.ledger.updateInfo(ctx.tender.id, data); } } catch (err) { responseData.err = 1; responseData.msg = err; } ctx.body = responseData; } async update(ctx) { const responseData = { err: 0, msg: '', data: [], }; try { const tenderId = parseInt(ctx.params.id); if (!tenderId) { throw '当前未打开标段'; } const tenderData = await ctx.service.tender.getDataById(tenderId); if (!tenderData || tenderData.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly(tenderData)) { throw '标段数据错误'; } const data = JSON.parse(ctx.request.body.data); responseData.data = await ctx.service.ledger.updateCalc(ctx.tender.id, data); } catch (err) { this.log(err); responseData.err = 1; responseData.msg = err; } ctx.body = responseData; } /** * 复制粘贴整块 (Ajax) * * @param ctx * @return {Promise} */ async pasteBlock(ctx) { const responseData = { err: 0, msg: '', data: [], }; try { if (!ctx.tender.data || ctx.tender.data.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly()) { throw '标段数据错误'; } const data = JSON.parse(ctx.request.body.data); if ((isNaN(data.id) || data.id <= 0) || (!data.block || data.block.length <= 0)) { throw '参数错误'; } responseData.data = await ctx.service.ledger.pasteBlock(ctx.tender.id, data.id, data.block); } catch (err) { responseData.err = 1; responseData.msg = err; } ctx.body = responseData; } /** * 从标准项目表添加数据 (Ajax) * @param ctx * @return {Promise} */ async addFromStandardLib(ctx) { const responseData = { err: 0, msg: '', data: [], }; try { if (!ctx.tender.data || ctx.tender.data.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly()) { throw '标段数据错误'; } const data = JSON.parse(ctx.request.body.data); if ((isNaN(data.id) || data.id <= 0) || !data.stdType || !data.stdNode) { throw '参数错误'; } // todo 校验项目是否使用该库的权限 let stdLib; switch (data.stdType) { case 'chapter': stdLib = ctx.service.stdChapter; break; case 'bills': stdLib = ctx.service.stdBills; break; default: throw '未知标准库'; } const stdData = await stdLib.getDataByDataId(data.stdLibId, data.stdNode); const addType = stdDataAddType.withParent; switch (addType) { case stdDataAddType.self: responseData.data = await ctx.service.ledger.addStdNode(ctx.tender.id, data.id, stdData); break; case stdDataAddType.withParent: responseData.data = await ctx.service.ledger.addStdNodeWithParent(ctx.tender.id, stdData, stdLib); break; default: throw '未知添加方法'; } } catch (err) { responseData.err = 1; responseData.msg = err; } ctx.body = responseData; } /** * 批量插入数据 (Ajax) * * data = {id, batchData, batchType} * data.batchType = 'batchInsertChild'/'batchInsertNext' * data.batchData = [{name, children}] -- 项目节列表 * data.batchData.children = [{code, name, unit, unit_price, quantity}] -- 工程量清单列表 * * @param ctx * @return {Promise} */ async batchInsert(ctx) { const responseData = { err: 0, msg: '', data: [], }; try { if (!ctx.tender.data || ctx.tender.data.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly()) { throw '标段数据错误'; } const data = JSON.parse(ctx.request.body.data); if ((isNaN(data.id) || data.id <= 0) || !data.batchType) { throw '参数错误'; } switch (data.batchType) { case 'child': responseData.data = await ctx.service.ledger.batchInsertChild(ctx.tender.id, data.id, data.batchData); break; case 'next': responseData.data = await ctx.service.ledger.batchInsertNext(ctx.tender.id, data.id, data.batchData); break; default: throw '参数错误'; } } catch (err) { this.log(err); responseData.err = 1; responseData.msg = err; } ctx.body = responseData; } /** * 查询 * * @param ctx * @return {Promise} */ async search(ctx) { const responseData = { err: 0, msg: '', data: [], }; try { const tenderId = ctx.params.id; if (!tenderId) { throw '当前未打开标段'; } const data = JSON.parse(ctx.request.body.data); if (!data.keyword || data.keyword === '') { throw '参数错误'; } responseData.data = await ctx.service.ledger.search(tenderId, { value: ctx.app.mysql.escape('%' + data.keyword + '%'), operate: 'Like', fields: ['code', 'b_code', 'name'], }); } catch (err) { this.log(err); responseData.err = 1; responseData.msg = err; } ctx.body = responseData; } /** * 定位 * @param ctx * @return {Promise} */ async locate(ctx) { const responseData = { err: 0, msg: '', data: [], }; try { const tenderId = ctx.params.id; if (!tenderId) { throw '当前未打开标段'; } const data = JSON.parse(ctx.request.body.data); if ((isNaN(data.id) || data.id <= 0)) { throw '参数错误'; } responseData.data = await ctx.service.ledger.locateNode(tenderId, data.id); } catch (err) { this.log(err); responseData.err = 1; responseData.msg = err; } ctx.body = responseData; } /** * 获取全部子节点 * * @param ctx * @return {Promise} */ async posterity(ctx) { const responseData = { err: 0, msg: '', data: [], }; try { const tenderId = ctx.params.id; if (!tenderId) { throw '当前未打开标段'; } const data = JSON.parse(ctx.request.body.data); if ((isNaN(data.id) || data.id <= 0)) { throw '参数错误'; } const expandData = await ctx.service.ledger.getPosterityByParentId(tenderId, data.id); responseData.data = { expand: expandData }; } catch (err) { this.log(err); responseData.err = 1; responseData.msg = err; } ctx.body = responseData; } /** * 获取部位明细数据(Ajax) * * @param ctx * @return {Promise} */ async pos(ctx) { try { await this.checkMeasureType(measureType.tz.value); const condition = JSON.parse(ctx.request.body.data) || {}; condition.tid = ctx.tender.id; const posData = await ctx.service.pos.getPosData(condition); ctx.body = { err: 0, msg: '', data: posData }; } catch (err) { this.log(err); ctx.body = { err: 1, msg: err.toString(), data: [] }; } } /** * 更新部位明细数据 * * @param ctx * @return {Promise} */ async posUpdate(ctx) { try { await this.checkMeasureType(measureType.tz.value); const data = JSON.parse(ctx.request.body.data); const responseData = await ctx.service.pos.savePosData(data, ctx.tender.id); ctx.body = { err: 0, msg: '', data: responseData }; } catch (err) { this.log(err); ctx.body = { err: 1, msg: err.toString(), data: null }; } } /** * 上传 清单Excel 并导入 * @param ctx * @return {Promise} */ async uploadExcel(ctx) { try { const compressData = ctx.request.body.data; const data = JSON.parse(LzString.decompressFromUTF16(compressData)); const responseData = { err: 0, msg: '', data: {}, }; await ctx.service.ledger.importExcel(data); responseData.data.bills = await ctx.service.ledger.getDataByTenderId(ctx.tender.id, -1); responseData.data.pos = await ctx.service.pos.getPosData(null); ctx.body = responseData; } catch (err) { this.log(err); ctx.body = { err: 1, msg: err.toString(), data: null }; } } /** * 下载(清单Excel模板 or 导出项目台账Excel) * @param ctx * @return {Promise} */ async download(ctx) { const file = ctx.params.file; if (file) { try { let fileName; if (file === 'template') { fileName = this.app.baseDir + '/app/public/files/template/ledger/导入分项清单Excel格式.xls'; } else if (file === 'ledger') { const create_time = Date.parse(new Date()) / 1000; fileName = this.app.baseDir + '/app/public/files/downloads/ledger/' + ctx.tender.id + '-' + create_time + '.xlsx'; // todo 导出台账清单Excel } ctx.body = await fs.readFileSync(fileName); } catch (err) { this.log(err); this.setMessage(err.toString(), this.messageType.ERROR); } } } /** * 台账变更页面 (Get) * * @param {object} ctx - egg全局变量 * @return {void} */ async change(ctx) { try { const renderData = { tender: ctx.tender.data, tenderMenu: this.menu.tenderMenu, preUrl: '/tender/' + ctx.tender.id, }; await this.layout('ledger/change.ejs', renderData, 'ledger/change_modal.ejs'); } catch (err) { this.log(err); ctx.redirect(ctx.request.header.referer); } } /** * 计量台账页面 (Get) * * @param {object} ctx - egg全局变量 * @return {void} */ async index(ctx) { const renderData = {}; await this.layout('ledger/index.ejs', renderData); } } return LedgerController; };