'use strict'; /** * 台账相关控制器 * * @author CaiAoLin * @date 2017/11/30 * @version */ const stdDataAddType = { withParent: 1, child: 2, next: 3, }; const audit = require('../const/audit'); const auditConst = audit.ledger; 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'); const accountGroup = require('../const/account_group').group; 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 hideFieldCols(setting, cols) { for (const c of setting.cols) { if (cols.indexOf(c.field) > -1) { c.visible = false; } } } 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(this.ctx.tender.info.decimal.up); const tender = this.ctx.tender; const setting = tender.info.display.ledger.clQty ? spreadConst.withCl : spreadConst.withoutCl; const ledger = JSON.parse(JSON.stringify(setting.ledger)); // setColFormat(ledger.cols, 'unit_price', upFormatter); // setColFormat(ledger.cols, 'dgn_price', upFormatter); // setColFormat(ledger.cols, 'total_price', tpFormatter); // setColFormat(ledger.cols, 'deal_tp', tpFormatter); const pos = JSON.parse(JSON.stringify(setting.pos)); 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 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 [stdBills, stdChapters] = await this.ctx.service.valuation.getValuationStdList(ctx.tender.data.valuation); const renderData = { tender: tender.data, tenderInfo: tender.info, auditConst, auditors, curAuditor, user, auditHistory, 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), stdBills, stdChapters, }; if ((tender.data.ledger_status === auditConst.status.uncheck || tender.data.ledger_status === auditConst.status.checkNo) && tender.data.user_id === ctx.session.sessionUser.accountId) { 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; renderData.auditorList = await ctx.service.ledgerAudit.getAuditors(tender.id, tender.data.ledger_times); } await this.layout('ledger/explode.ejs', renderData, 'ledger/explode_modal.ejs'); } catch (err) { this.log(err); await this.redirect('/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; } /** * 树结构基本操作(增、删、上下移、升降级) * @param {Object} ctx - egg全局变量 * @return {Promise} */ async _base(ctx, type, data) { if (isNaN(data.id) || data.id <= 0) throw '数据错误'; if (type !== 'add') { if (isNaN(data.count) || data.count <= 0) data.count = 1; } switch (type) { case 'add': return await ctx.service.ledger.addNode(ctx.tender.id, data.id); case 'delete': return await ctx.service.ledger.delete(ctx.tender.id, data.id, data.count); case 'up-move': return await ctx.service.ledger.upMoveNode(ctx.tender.id, data.id, data.count); case 'down-move': return await ctx.service.ledger.downMoveNode(ctx.tender.id, data.id, data.count); case 'up-level': return await ctx.service.ledger.upLevelNode(ctx.tender.id, data.id, data.count); case 'down-level': return await ctx.service.ledger.downLevelNode(ctx.tender.id, data.id, data.count); } } /** * 复制粘贴整块 * * @param ctx * @return {Promise} */ async _pasteBlock(ctx, data) { if ((isNaN(data.id) || data.id <= 0) || (!data.tid && data.tid <= 0) || (!data.block || data.block.length <= 0)) throw '参数错误'; return await ctx.service.ledger.pasteBlock(data.tid, data.id, data.block); } /** * 从标准项目表添加数据 * @param ctx * @return {Promise} */ async _addStd(ctx, data) { if ((isNaN(data.id) || data.id <= 0) || !data.stdType || !data.stdNode) throw '参数错误'; // todo 校验项目是否使用该库的权限 let stdLib, addType; switch (data.stdType) { case 'xmj': stdLib = ctx.service.stdXmj; addType = stdDataAddType.withParent; break; case 'gcl': stdLib = ctx.service.stdGcl; const selectNode = await ctx.service.ledger.getDataByNodeId(ctx.tender.id, data.id); if (selectNode.b_code) { addType = stdDataAddType.next; } else { addType = stdDataAddType.child; } break; default: throw '未知标准库'; } const stdData = await stdLib.getDataByDataId(data.stdLibId, data.stdNode); switch (addType) { case stdDataAddType.child: return await ctx.service.ledger.addStdNodeAsChild(ctx.tender.id, data.id, stdData); break; case stdDataAddType.next: return await ctx.service.ledger.addStdNode(ctx.tender.id, data.id, stdData); case stdDataAddType.withParent: return await ctx.service.ledger.addStdNodeWithParent(ctx.tender.id, stdData, stdLib); default: throw '未知添加方式'; } } /** * 从签约清单添加节点 * @param ctx * @returns {Promise} */ async _addDeal(ctx, data) { if (!data.type || !data.dealBills) throw '数据错误'; if (data.type === 'child') { return await ctx.service.ledger.addChild(ctx.tender.id, data.id, data.dealBills); } else if (data.type === 'next') { return await ctx.service.ledger.addNode(ctx.tender.id, data.id, data.dealBills); } else { throw '数据错误'; } } /** * 批量插入数据 * * 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, data) { if ((isNaN(data.id) || data.id <= 0) || !data.batchType) throw '参数错误'; switch (data.batchType) { case 'child': return await ctx.service.ledger.batchInsertChild(ctx.tender.id, data.id, data.batchData); case 'next': return await ctx.service.ledger.batchInsertNext(ctx.tender.id, data.id, data.batchData); default: throw '参数错误'; } } /** * 更新清单相关 (Ajax) * @param ctx * @returns {Promise} */ async update(ctx) { try { if (!ctx.tender.data) throw '标段数据错误'; if (ctx.tender.data.user_id !== ctx.session.sessionUser.accountId || this._ledgerReadOnly()) throw '您无权进行该操作'; const data = JSON.parse(ctx.request.body.data); if (!data.postType || !data.postData) throw '数据错误'; const responseData = { err: 0, msg: '', data: [], }; switch (data.postType) { case 'add': case 'delete': case 'up-move': case 'down-move': case 'up-level': case 'down-level': responseData.data = await this._base(ctx, data.postType, data.postData); break; case 'update': responseData.data = await ctx.service.ledger.updateCalc(ctx.tender.id, data.postData); break; case 'paste-block': responseData.data = await this._pasteBlock(ctx, data.postData); break; case 'add-std': responseData.data = await this._addStd(ctx, data.postData); break; case 'add-deal': responseData.data = await this._addDeal(ctx, data.postData); break; case 'batch-insert': responseData.data = await this._batchInsert(ctx, data.postData); break; default: throw '未知操作'; } ctx.body = responseData; } catch (err) { this.log(err); ctx.body = this.ajaxErrorBody(err); } } /** * 定位 * @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 loadExplodeData(ctx) { try { const ledgerData = await ctx.service.ledger.getData(ctx.tender.id); const posData = this.ctx.tender.data.measure_type === measureType.tz.value ? await ctx.service.pos.getPosData({tid: ctx.tender.id}) : []; ctx.body = { err: 0, msg: '', data: {bills: ledgerData, pos: 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 }; } } /** * 复制粘贴 部位明细 * @param ctx * @returns {Promise} */ async posPaste(ctx) { try { await this.checkMeasureType(measureType.tz.value); const data = JSON.parse(ctx.request.body.data); const result = await ctx.service.pos.pastePosData(data, ctx.tender.id); ctx.body = { err: 0, msg: '', data: result }; } 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: {}, }; const templateId = await this.ctx.service.valuation.getValuationTemplate(this.ctx.tender.data.valuation); responseData.data = await ctx.service.ledger.importExcel(templateId, data); 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 ctx * @returns {Promise} */ async gather(ctx) { try { const renderData = { tender: ctx.tender.data, jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.ledger.gather) }; await this.layout('ledger/gather.ejs', renderData); } catch (err) { this.log(err); await this.redirect(ctx.request.header.referer); } } /** * 获取 台账对比 数据 (Ajax) * @param ctx * @returns {Promise} */ async loadGatherData(ctx) { try { const billsData = await ctx.service.ledger.getData(ctx.tender.id); const posData = this.ctx.tender.data.measure_type === measureType.tz.value ? await ctx.service.pos.getPosData({tid: ctx.tender.id}) : []; const dealBills = await ctx.service.dealBills.getAllDataByCondition({ where: {tender_id: this.ctx.tender.id} }); ctx.body = { err: 0, msg: '', data: {bills: billsData, pos: posData, dealBills: dealBills} }; } catch (err) { this.log(err); ctx.body = { err: 1, msg: err.toString(), data: [] }; } } /** * 计量台账页面 (Get) * * @param {object} ctx - egg全局变量 * @return {void} */ async index(ctx) { const renderData = {}; await this.layout('ledger/index.ejs', renderData); } } return LedgerController; };