|
@@ -3,12 +3,20 @@ 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 = {}) {
|
|
@@ -23,6 +31,73 @@ class InvestigationService extends CrudService {
|
|
|
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;
|