'use strict'; /** * * * @author Mai * @date * @version */ const path = require('path'); const fs = require('fs'); const sendToWormhole = require('stream-wormhole'); module.exports = app => { class TemplateController extends app.BaseController { /** * 下载 各种模板 * @param ctx * @returns {Promise} */ async download(ctx) { const file = ctx.params.file; if (file) { try { let fileName; switch (file) { case '导入分项清单EXCEL格式.xlsx': fileName = path.join(this.app.baseDir, 'app', 'public', 'files', 'template', 'ledger', '导入分项清单EXCEL格式.xlsx'); break; case '导入工程量清单EXCEL格式.xls': fileName = path.join(this.app.baseDir, 'app', 'public', 'files', 'template', 'ledger', '导入工程量清单EXCEL格式.xls'); break; case '估概预算示例EXCEL格式.xlsx': fileName = path.join(this.app.baseDir, 'app', 'public', 'files', 'template', file); break; case '控制价示例EXCEL格式.xlsx': fileName = path.join(this.app.baseDir, 'app', 'public', 'files', 'template', file); break; default: throw '参数错误' } ctx.body = await fs.readFileSync(fileName); } catch (err) { this.log(err); if (err.stack) { ctx.body = '您下载的示例文件不存在'; } else { ctx.body = err; } } } else { ctx.body = '参数错误'; } } async posCalc(ctx) { try { const renderData = { validColInfo: ctx.service.calcTmpl.TemplateRela.posCalc.ValidColInfo, jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.template.posCalc), }; renderData.templateList = await ctx.service.calcTmpl.getAllTemplate(ctx.session.sessionProject.id, 'posCalc'); await ctx.service.calcTmpl.checkTemplateUsed(renderData.templateList, 'posCalc'); const specList = await ctx.service.stdExtraList.getList(0); renderData.specList = specList.map(x => { return { value: x.id, text: x.name }; }); await this.layout('template/pos_calc.ejs', renderData, 'template/pos_calc_modal.ejs'); } catch (err) { ctx.log(err); ctx.postError(err, '查看模板数据错误'); ctx.redirect(ctx.request.header.referer); } } async cost(ctx) { try { const renderData = { validColInfo: ctx.service.calcTmpl.TemplateRela.cost.ValidColInfo, jsFiles: this.app.jsFiles.common.concat(this.app.jsFiles.template.cost), }; renderData.templateList = await ctx.service.calcTmpl.getAllTemplate(ctx.session.sessionProject.id, 'cost'); await ctx.service.calcTmpl.checkTemplateUsed(renderData.templateList, 'cost'); await this.layout('template/cost.ejs', renderData, 'template/cost_modal.ejs'); } catch (err) { ctx.log(err); ctx.postError(err, '查看模板数据错误'); ctx.redirect(ctx.request.header.referer); } } // ------------ 以下方法为所有模板共用 -------------- async load(ctx) { try { const data = JSON.parse(ctx.request.body.data); const filter = data.filter ? data.filter.split(';') : []; const result = {}; for (const f of filter) { switch(f) { case 'detail': result[f] = await this.ctx.service.calcTmpl.getTemplate(data.id, data.type); break; default: throw '未知数据类型'; } } ctx.body = { err: 0, msg: '', data: result }; } catch (error) { ctx.log(error); ctx.ajaxErrorBody(error, '加载数据失败'); } } async saveTemplate(ctx) { try { const data = JSON.parse(ctx.request.body.data); const result = await ctx.service.calcTmpl.saveTemplate(data); ctx.body = { err: 0, msg: '', data: result }; } catch (err) { ctx.log(err); ctx.ajaxErrorBody(err, '修改数据失败'); } } async preview(ctx) { try { const data = JSON.parse(ctx.request.body.data); const spreadSetting = this.ctx.service.calcTmpl.calcSpreadCache(data.type, data.col_set, data.multi_header); const testData = await this.ctx.service.calcTmpl.getCalcTestData(data.col_set, data.type, 3); const calc = this.ctx.service.calcTmpl._getCalcExpr(spreadSetting.cols); ctx.body = { err: 0, msg: '', data: { spreadSetting, testData, calc } }; } catch (error) { ctx.log(error); ctx.ajaxErrorBody(error, '预览失败'); } } async reCalcTemplate(ctx) { try { const templateId = ctx.query.tid; await ctx.service.calcTmpl.reCalcTemplate(templateId, true); } catch(error) { ctx.log(error); ctx.postError(error, '重算模板失败'); } ctx.redirect(ctx.request.header.referer); } async exportTemplate(ctx) { try { const template = await ctx.service.calcTmpl.getTemplate(ctx.query.tid); if (!template) throw '计算模板不存在'; if (template.project_id !== ctx.session.sessionProject.id) throw '您无权导出该模板数据'; const Cpd = require('../lib/crypt').cpd; const cpd = new Cpd(); const filename = `${template.name}.ctd`; const filepath = path.join(this.ctx.app.baseDir, 'temp', filename); await cpd.encrypt({ type: template.type, col_set: template.col_set, multi_header: template.multi_header }, filepath); const userAgent = (ctx.request.header['user-agent'] || '').toLowerCase(); let disposition = ''; if (userAgent.indexOf('msie') >= 0 || userAgent.indexOf('chrome') >= 0) { disposition = 'attachment; filename=' + encodeURIComponent(filename); } else if (userAgent.indexOf('firefox') >= 0) { disposition = 'attachment; filename*="utf8\'\'' + encodeURIComponent(filename) + '"'; } else { /* safari等其他非主流浏览器只能自求多福了 */ disposition = 'attachment; filename=' + new Buffer(filename).toString('binary'); } ctx.response.set({ 'Content-Type': 'application/octet-stream', 'Content-Disposition': disposition, }); ctx.body = await fs.readFileSync(filepath); } catch(err) { ctx.log(err); ctx.postError(err, '导出模板数据失败'); } } async importTemplate(ctx) { const template = await ctx.service.calcTmpl.getTemplate(ctx.query.tid); if (!template) throw '计算模板不存在'; const create_time = Date.parse(new Date()) / 1000; const filepath = path.join(this.ctx.app.baseDir, 'temp', `计算模板${create_time}.ctd`); let stream, index = 0; try { const parts = ctx.multipart({ autoFields: true }); stream = await parts(); while (stream !== undefined) { if (!stream.filename) throw '未发现上传文件!'; // 保存文件 await ctx.helper.saveStreamFile(stream, filepath); await sendToWormhole(stream); ++index; if (Array.isArray(parts.field.size) && index < parts.field.size.length) { stream = await parts(); } else { stream = undefined; } } const Cpd = require('../lib/crypt').cpd; const cpd = new Cpd(); const data = await cpd.decrypt(filepath); if (template.type !== data.type) throw '导入的模板文件与当前模板类型不一致,不可导入'; const result =await ctx.service.calcTmpl.saveTemplate({ update: { id: template.id, col_set: data.col_set, multi_header: data.multi_header } }); ctx.body = { err: 0, mgs: '', data: result }; } catch (err) { // 失败需要消耗掉stream 以防卡死 if (stream) await sendToWormhole(stream); ctx.log(err); ctx.ajaxErrorBody(err, '导入模板文件失败'); } } // --------------------------------------------------- async saveLedgerTemplate(ctx) { try { const data = JSON.parse(ctx.request.body.data); const result = await ctx.service.ledgerTemplate.saveTemplate(data); ctx.body = { err: 0, msg: '', data: result }; } catch (err) { ctx.log(err); ctx.ajaxErrorBody(err, '修改数据失败'); } } } return TemplateController; };