'use strict'; const { CrudService } = require('naf-framework-mongoose/lib/service'); const { BusinessError, ErrorCode } = require('naf-core').Error; const _ = require('lodash'); const assert = require('assert'); const fs = require('fs'); const path = require('path'); const PizZip = require('pizzip'); const Docxtemplater = require('docxtemplater'); const archiver = require('archiver'); const moment = require('moment'); // 企业需求 class InvestigationService extends CrudService { constructor(ctx) { super(ctx, 'investigation'); this.model = this.ctx.model.Investigation; this.root_path = _.get(this.ctx.app.config.export, 'root_path'); this.dir = [ 'question', 'investigation' ]; this.exportPrefix = '企业需求调查表'; } async query(filter, options = {}) { const { filter: nf, options: no } = this.ctx.service.util.util.dealQuery(_.cloneDeep(filter), _.cloneDeep(options)); const { skip, limit, sort, projection } = no; const rs = await this.model.find(nf, projection, { skip, limit, sort }).exec(); return rs; } async count(filter) { const nf = this.ctx.service.util.util.dealFilter(_.cloneDeep(filter)); const res = await this.model.countDocuments(nf).exec(); return res; } async export() { // 检验数据是否存在 const data = await this.model.find(); if (data.length <= 0) return '没有企业需求调查的数据'; // 检测,创建目录 let newPath = this.root_path; for (const p of this.dir) { newPath = path.join(newPath, p); if (!fs.existsSync(newPath)) { fs.mkdirSync(newPath); } } // 循环处理 // 存储文件名, 为了之后打包文件,然后把压缩包内对应的文件删除掉 const fileArray = []; for (const dup of data) { const d = _.omit(JSON.parse(JSON.stringify(dup)), [ 'meta' ]); d['meta.createdAt'] = moment(_.get(dup, 'meta.createdAt')).format('YYYY-MM-DD'); for (const key in d) { const e = d[key]; if (!_.isObject(e)) continue; for (const okey of Object.keys(e)) { d[`${key}.${okey}`] = e[okey]; } } // 获取模板 const content = fs.readFileSync(path.resolve('./', 'template', 'template.docx')); const zip = new PizZip(content); const doc = new Docxtemplater(zip, { paragraphLoop: true, linebreaks: true }); doc.render(d); const buf = doc.getZip().generate({ type: 'nodebuffer' }); const fileName = `${_.get(d, 'name', _.get(d, '_id'))}.docx`; fileArray.push(fileName); fs.writeFileSync(path.join(newPath, fileName), buf); } const zipPath = await this.buildZip(newPath, fileArray); return zipPath; } /** * 打zip包 * @param {String} dirPath 路径 * @param {Array} files 文件数组 */ async buildZip(dirPath, files) { const zipName = `${this.exportPrefix}-${new Date().getTime()}.zip`; const output = fs.createWriteStream(path.join(`${dirPath}`, zipName)); const archive = archiver('zip', { zlib: { level: 9 }, }); archive.pipe(output); for (const f of files) { archive.file(path.join(dirPath, f), { name: path.basename(f), }); } await archive.finalize(); // 删除文件 for (const f of files) { const filePath = path.join(dirPath, f); fs.unlinkSync(filePath); } // 拼接口返回的路径 /files/... const returnPath = `/files/${this.dir.join('/')}/${zipName}`; return returnPath; } } module.exports = InvestigationService;