investigation.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. 'use strict';
  2. const { CrudService } = require('naf-framework-mongoose/lib/service');
  3. const { BusinessError, ErrorCode } = require('naf-core').Error;
  4. const _ = require('lodash');
  5. const assert = require('assert');
  6. const fs = require('fs');
  7. const path = require('path');
  8. const PizZip = require('pizzip');
  9. const Docxtemplater = require('docxtemplater');
  10. const archiver = require('archiver');
  11. const moment = require('moment');
  12. // 企业需求
  13. class InvestigationService extends CrudService {
  14. constructor(ctx) {
  15. super(ctx, 'investigation');
  16. this.model = this.ctx.model.Investigation;
  17. this.root_path = _.get(this.ctx.app.config.export, 'root_path');
  18. this.dir = [ 'question', 'investigation' ];
  19. this.exportPrefix = '企业需求调查表';
  20. }
  21. async query(filter, options = {}) {
  22. const { filter: nf, options: no } = this.ctx.service.util.util.dealQuery(_.cloneDeep(filter), _.cloneDeep(options));
  23. const { skip, limit, sort, projection } = no;
  24. const rs = await this.model.find(nf, projection, { skip, limit, sort }).exec();
  25. return rs;
  26. }
  27. async count(filter) {
  28. const nf = this.ctx.service.util.util.dealFilter(_.cloneDeep(filter));
  29. const res = await this.model.countDocuments(nf).exec();
  30. return res;
  31. }
  32. async export() {
  33. // 检验数据是否存在
  34. const data = await this.model.find();
  35. if (data.length <= 0) return '没有企业需求调查的数据';
  36. // 检测,创建目录
  37. let newPath = this.root_path;
  38. for (const p of this.dir) {
  39. newPath = path.join(newPath, p);
  40. if (!fs.existsSync(newPath)) {
  41. fs.mkdirSync(newPath);
  42. }
  43. }
  44. // 循环处理
  45. // 存储文件名, 为了之后打包文件,然后把压缩包内对应的文件删除掉
  46. const fileArray = [];
  47. for (const dup of data) {
  48. const d = _.omit(JSON.parse(JSON.stringify(dup)), [ 'meta' ]);
  49. d['meta.createdAt'] = moment(_.get(dup, 'meta.createdAt')).format('YYYY-MM-DD');
  50. for (const key in d) {
  51. const e = d[key];
  52. if (!_.isObject(e)) continue;
  53. for (const okey of Object.keys(e)) {
  54. d[`${key}.${okey}`] = e[okey];
  55. }
  56. }
  57. // 获取模板
  58. const content = fs.readFileSync(path.resolve('./', 'template', 'template.docx'));
  59. const zip = new PizZip(content);
  60. const doc = new Docxtemplater(zip, { paragraphLoop: true, linebreaks: true });
  61. doc.render(d);
  62. const buf = doc.getZip().generate({ type: 'nodebuffer' });
  63. const fileName = `${_.get(d, 'name', _.get(d, '_id'))}.docx`;
  64. fileArray.push(fileName);
  65. fs.writeFileSync(path.join(newPath, fileName), buf);
  66. }
  67. const zipPath = await this.buildZip(newPath, fileArray);
  68. return zipPath;
  69. }
  70. /**
  71. * 打zip包
  72. * @param {String} dirPath 路径
  73. * @param {Array} files 文件数组
  74. */
  75. async buildZip(dirPath, files) {
  76. const zipName = `${this.exportPrefix}-${new Date().getTime()}.zip`;
  77. const output = fs.createWriteStream(path.join(`${dirPath}`, zipName));
  78. const archive = archiver('zip', {
  79. zlib: { level: 9 },
  80. });
  81. archive.pipe(output);
  82. for (const f of files) {
  83. archive.file(path.join(dirPath, f), {
  84. name: path.basename(f),
  85. });
  86. }
  87. await archive.finalize();
  88. // 删除文件
  89. for (const f of files) {
  90. const filePath = path.join(dirPath, f);
  91. fs.unlinkSync(filePath);
  92. }
  93. // 拼接口返回的路径 /files/...
  94. const returnPath = `/files/${this.dir.join('/')}/${zipName}`;
  95. return returnPath;
  96. }
  97. }
  98. module.exports = InvestigationService;