ruifeng_liu %!s(int64=3) %!d(string=hai) anos
pai
achega
9470e81e73

+ 9 - 0
app/controller/patent/.patentinfo.js

@@ -81,5 +81,14 @@ module.exports = {
       count: true,
     },
   },
+
+  toImport: {
+    requestBody: ["uri", "origin","user_id"],
+    service: "toImport",
+  },
+  toExport: {
+    requestBody: ["user"],
+    service: "toExport",
+  },
   
 };

+ 2 - 2
app/model/patent/patentinfo.js

@@ -21,8 +21,8 @@ const patentinfo = {
   img_url: { type: Array }, // 图片
   origin: { type: String }, // 数据来源(手写的)
   user_id: { type: [ ObjectId ] },
-  status: { type: String, required: false }, // 状态
-  trans_status: { type: String, required: false }, // 交易状态
+  status: { type: String, required: false, default: '0' }, // 状态
+  trans_status: { type: String, required: false, default: '0' }, // 交易状态
 };
 const schema = new Schema(patentinfo, { toJSON: { virtuals: true } });
 schema.index({ id: 1 });

+ 2 - 0
app/router/patent/patentinfo.js

@@ -10,4 +10,6 @@ module.exports = app => {
   const metaTime = app.middleware.createTime();
   router.resources(target, `${profix}${vision}/${index}/${target}`, metaTime, controller[index][target]); // index、create、show、destroy
   router.post(target, `${profix}${vision}/${index}/${target}/update/:id`, controller[index][target].update);
+  router.post(target, `${profix}${vision}/${index}/${target}/toImport`, controller[index][target].toImport);
+  router.post(target, `${profix}${vision}/${index}/${target}/toExport`, controller[index][target].toExport);
 };

+ 234 - 2
app/service/patent/patentinfo.js

@@ -1,8 +1,14 @@
 'use strict';
+const assert = require('assert');
+const moment = require('moment');
+const Excel = require('exceljs');
+const Path = require('path');
+const _ = require('lodash');
+const { sep } = require('path');
+const fs = require('fs');
 const { CrudService } = require('naf-framework-mongoose/lib/service');
 const { BusinessError, ErrorCode } = require('naf-core').Error;
-const _ = require('lodash');
-const assert = require('assert');
+const { trimData } = require('naf-core').Util;
 
 // 专利信息
 class PatentinfoService extends CrudService {
@@ -10,6 +16,232 @@ class PatentinfoService extends CrudService {
     super(ctx, 'patentinfo');
     this.model = this.ctx.model.Patent.Patentinfo;
   }
+
+  async toImport({ uri, origin, user_id }) {
+    assert(uri, '未获取到文件地址');
+    const file = await this.ctx.curl(`${this.domain}${uri}`);
+    if (!(file && file.data)) {
+      throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到指定文件');
+    }
+    const workbook = new Excel.Workbook();
+    await workbook.xlsx.load(file.data);
+    const sheet = workbook.getWorksheet(1);
+    const arr = [];
+    const allNotice = [];
+    const sheetImageInfo = sheet.getImages();
+    const imgids = _.compact(sheetImageInfo.map(i => {
+      const { imageId, range } = i;
+      const row = _.get(range, 'tl.nativeRow');
+      if (row) return { row, imageId };
+    }));
+    sheet.eachRow((row, rindex) => {
+      if (rindex !== 1) {
+        // 组织数据,图片的索引和行索引不一致,准确的说是:图片索引比行索引少1
+        // 原因:图片在工作簿中获取,按照1,2,3...顺序排序,但是行的第一行是表头(当前文件),所以当前行数需要减掉表头那一行
+        const imgid = imgids.find(f => f.row === rindex - 1);
+        const img_url = [];
+        if (imgid) {
+          img_url.push({
+            url: this.turnImageToBase64(workbook.getImage(imgid.imageId)),
+          });
+        }
+        const create_number = row.getCell(2).value || undefined,
+          create_date =
+            moment(row.getCell(3).value).format('YYYY-MM-DD') || undefined,
+          success_number = row.getCell(4).value || undefined,
+          success_date =
+            moment(row.getCell(5).value).format('YYYY-MM-DD') || undefined,
+          inventor = row.getCell(6).value || undefined,
+          agent = row.getCell(7).value || undefined,
+          agent_personal = row.getCell(8).value || undefined,
+          abstract = row.getCell(9).value || undefined,
+          address = row.getCell(10).value || undefined,
+          name = row.getCell(11).value || undefined,
+          apply_personal = row.getCell(12).value || undefined,
+          term = row.getCell(13).value || undefined,
+          type = row.getCell(14).value || undefined,
+          number = row.getCell(1).value || undefined;
+        const obj = {
+          create_number,
+          create_date,
+          success_number,
+          success_date,
+          inventor,
+          agent,
+          agent_personal,
+          abstract,
+          address,
+          name,
+          apply_personal,
+          term,
+          type,
+          img_url,
+          number,
+          origin,
+          user_id: [ user_id ],
+        };
+        // 此处添加判断条件,不限制则不需要加,直接放过即可
+        const { result, notice } = this.tocheckData(obj);
+        if (result) {
+          arr.push(obj);
+        } else {
+          allNotice.push(notice);
+        }
+      }
+    });
+    if (allNotice.length > 0) return allNotice;
+    await this.model.insertMany(arr);
+
+  }
+  async toExport({ user }) {
+    const data = {
+      title: '专利导出',
+      params: {
+        project: 'market',
+        service: 'dock.patent',
+        method: 'export',
+      },
+      user,
+    };
+    try {
+      await this.ctx.service.util.httpUtil.cpost('/api/mission', 'mission', data);
+    } catch (error) {
+      console.log(error);
+      throw new BusinessError(ErrorCode.SERVICE_FAULT, '任务创建失败');
+
+    }
+  }
+
+  async export({ missionid }) {
+    const nowDate = new Date().getTime();
+    const filename = `导出结果-${nowDate}.xlsx`;
+    const path = `${this.root_path}${this.file_type}${this.excel_path}`;
+    if (!path) {
+      throw new BusinessError(ErrorCode.BUSINESS, '服务端没有设置存储路径');
+    }
+    if (!fs.existsSync(path)) {
+      // 如果不存在文件夹,就创建
+      fs.mkdirSync(path);
+    }
+    const total = await this.model.count();
+    let skip = 0;
+    let downloadPath;
+    // 将数据分割,否则容易直接把js堆栈干满了,服务就炸了
+    for (let i = 0; i < total; i = i + this.export_limit) {
+      const list = await this.model.find().skip(skip).limit(this.export_limit);
+      skip = skip + this.export_limit;
+      downloadPath = await this.asyncExport(list, filename, path, downloadPath);
+      try {
+        const data = {
+          progress: _.ceil((skip / total) * 100),
+          status: '1',
+          id: missionid,
+        };
+        this.ctx.service.util.httpUtil.cpost('/api/mission/progress', 'mission', data);
+      } catch (error) {
+        this.logger.error(`任务id:${missionid},进度更新失败`);
+      }
+    }
+    try {
+      const data = {
+        progress: 100,
+        status: '2',
+        uri: downloadPath,
+      };
+      await this.ctx.service.util.httpUtil.cpost(`/api/mission/update/${missionid}`, 'mission', data);
+    } catch (error) {
+      this.logger.error(`任务id:${missionid},已完成更新失败`);
+    }
+    return downloadPath;
+
+  }
+
+  async asyncExport(list, filename, path, downloadPath) {
+    const workbook = new Excel.Workbook();
+    let sheet;
+    if (!downloadPath) {
+      sheet = workbook.addWorksheet('sheet');
+    } else {
+      const file = await this.ctx.curl(`${this.domain}${downloadPath}`);
+      if (!(file && file.data)) {
+        throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到指定文件');
+      }
+      await workbook.xlsx.load(file.data);
+      sheet = workbook.getWorksheet('sheet');
+    }
+    const rowNumber = sheet.rowCount || 1;
+    const meta = this.getHeader();
+    sheet.columns = meta;
+    sheet.addRows(list);
+    for (let i = 0; i < list.length; i++) {
+      const e = list[i];
+      const { img_url, _id } = e;
+      try {
+        if (img_url) {
+          const is_base64 = img_url.includes('base64,');
+          let imgid;
+          if (is_base64) {
+            imgid = workbook.addImage({
+              base64: img_url,
+              extension: 'jpeg',
+            });
+          } else if (img_url.includes('/files')) {
+            const prefix = `${this.root_path}`;
+            const new_url = img_url.replace('/files', prefix);
+            const suffix = Path.extname(img_url).substring(1);
+            imgid = workbook.addImage({
+              filename: new_url,
+              extension: suffix,
+            });
+          } else {
+            // 什么都不是,那就下一个
+            continue;
+          }
+
+          sheet.addImage(imgid, {
+            tl: { col: 13.2, row: i + rowNumber + 0.2 },
+            br: { col: 14, row: i + rowNumber + 1 },
+          });
+        }
+      } catch (error) {
+        this.ctx.logger.error(`导出,id为:${_id}的图片处理出现错误!`);
+      }
+
+    }
+    const filepath = `${path}${filename}`;
+    if (list.length <= 0) return;
+    await workbook.xlsx.writeFile(filepath);
+    return `/files/excel/${filename}`;
+  }
+
+  /**
+   * 检查数据是否没填 必填项
+   * @param {Object} object 每行数据,已转换成model的字段名
+   */
+  tocheckData(object) {
+    let result = true;
+    const { number } = object;
+    let notice;
+    const arr = [
+      { column: 'create_number', zh: '申请号' },
+      { column: 'create_date', zh: '申请日' },
+      { column: 'success_number', zh: '公开(公告)号' },
+      { column: 'success_date', zh: '公开(公告)日' },
+      { column: 'name', zh: '标题' },
+    ];
+    const word = [];
+    for (const o of arr) {
+      const { column, zh } = o;
+      if (!_.get(object, column)) {
+        result = false;
+        word.push(`${zh}`);
+      }
+    }
+    if (!result) {
+      notice = `序号${number}缺少:${word.join(';')}`;
+    }
+    return { result, notice };
+  }
 }
 
 module.exports = PatentinfoService;