lrf402788946 3 år sedan
förälder
incheckning
52ae3a0770

+ 16 - 16
app.js

@@ -1,16 +1,16 @@
-'use strict';
-class AppBootHook {
-  constructor(app) {
-    this.app = app;
-  }
-
-  async didReady() {
-    // 应用已经启动完毕
-    const ctx = await this.app.createAnonymousContext();
-    // 检查种子
-    await ctx.service.install.index();
-    // await ctx.service.rabbitmq.receiveQueueMsg('user_bind');
-  }
-
-}
-module.exports = AppBootHook;
+'use strict';
+class AppBootHook {
+  constructor(app) {
+    this.app = app;
+  }
+
+  async serverDidReady() {
+    // 应用已经启动完毕
+    const ctx = await this.app.createAnonymousContext();
+    // 检查种子
+    // await ctx.service.install.index();
+    await ctx.service.util.rabbitMq.mission();
+  }
+
+}
+module.exports = AppBootHook;

+ 3 - 0
app/controller/patent/.disclosure.js

@@ -86,4 +86,7 @@ module.exports = {
   cacheImport: {
     requestBody: ["data", "temp_id"],
   },
+  toExport: {
+    requestBody: ["id"],
+  },
 };

+ 7 - 0
app/controller/patent/disclosure.js

@@ -13,5 +13,12 @@ class DisclosureController extends Controller {
     const data = await this.service.haveReport(this.ctx.query);
     this.ctx.ok(data);
   }
+
+
+  async toExport() {
+    await this.service.toExport(this.ctx.request.body);
+    this.ctx.ok();
+  }
+
 }
 module.exports = CrudController(DisclosureController, meta);

+ 1 - 0
app/router/patent/disclosure.js

@@ -15,4 +15,5 @@ module.exports = app => {
   router.post(target, `${profix}${vision}/${index}/${target}/check`, controller[index][target].check);
   router.post(target, `${profix}${vision}/${index}/${target}/import`, controller[index][target].import);
   router.post(target, `${profix}${vision}/${index}/${target}/cacheImport`, controller[index][target].cacheImport);
+  router.post(target, `${profix}${vision}/${index}/${target}/toExport`, controller[index][target].toExport);
 };

+ 40 - 1
app/service/dock/patent.js

@@ -9,11 +9,14 @@ const { sep } = require('path');
 const fs = require('fs');
 const { CrudService } = require('naf-framework-mongoose/lib/service');
 const { BusinessError, ErrorCode } = require('naf-core').Error;
+const { trimData } = require('naf-core').Util;
 
 class PatentService extends CrudService {
   constructor(ctx) {
     super(ctx, 'patent');
     this.model = this.ctx.model.Dock.Patent;
+    this.personalModel = this.ctx.model.Personal;
+    this.organizationModel = this.ctx.model.Organization;
     this.root_path = _.get(this.ctx.app.config.export, 'root_path');
     if (process.env.NODE_ENV === 'development') this.root_path = 'E:\\exportFile\\';
     this.file_type = '';
@@ -26,6 +29,42 @@ class PatentService extends CrudService {
     this.export_limit = 50;
   }
 
+  async query(query, { skip = 0, limit = 0 }) {
+    query = await this.resetCode(query);
+    const res = await this.model.find(query).skip(parseInt(skip)).limit(parseInt(limit))
+      .sort({ 'meta.createdAt': -1 });
+    return res;
+
+  }
+  async count(query) {
+    query = await this.resetCode(query);
+    console.log(query);
+    const res = await this.model.countDocuments(trimData(query)).exec();
+    return res;
+  }
+
+  async resetCode(query) {
+    query = this.ctx.service.util.util.dealQuery(query);
+    const { type } = query;
+    if (type === 'else') {
+      query.$and = [{ type: { $ne: '发明' } }, { type: { $ne: '实用新型' } }];
+      delete query.type;
+    }
+    const { code } = query;
+    let ids = [];
+    if (code) {
+      const plist = await this.personalModel.find({ code });
+      ids = plist.map(i => i._id);
+      const olist = await this.organizationModel.find({ code });
+      ids = [ ...ids, ...olist.map(i => i._id) ];
+    }
+    if (ids.lenght > 0) {
+      query.user_id = { $elemMatch: ids };
+      delete query.code;
+    }
+    return query;
+  }
+
   async toImport({ uri, origin }) {
     assert(uri, '未获取到文件地址');
     const file = await this.ctx.curl(`${this.domain}${uri}`);
@@ -102,7 +141,7 @@ class PatentService extends CrudService {
       title: '专利导出',
       params: {
         project: 'market',
-        service: 'patent',
+        service: 'dock.patent',
         method: 'export',
       },
       user,

+ 169 - 4
app/service/patent/disclosure.js

@@ -1,6 +1,7 @@
 'use strict';
 const { CrudService } = require('naf-framework-mongoose/lib/service');
 const { BusinessError, ErrorCode } = require('naf-core').Error;
+const Path = require('path');
 const _ = require('lodash');
 const moment = require('moment');
 const assert = require('assert');
@@ -18,6 +19,15 @@ class DisclosureService extends CrudService {
     this.personalModel = this.ctx.model.Personal;
     this.organizationModel = this.ctx.model.Organization;
     this.itemp = this.ctx.model.Patent.ImportTemp;
+
+    this.root_path = _.get(this.ctx.app.config.export, 'root_path');
+    if (!fs.existsSync(`${this.root_path}`)) {
+      // 如果不存在文件夹,就创建
+      fs.mkdirSync(`${this.root_path}`);
+    }
+    this.excel_path = `${sep}excel${sep}`;
+    this.domain = _.get(this.ctx.app.config.export, 'domain');
+    this.export_limit = 50;
   }
 
   /**
@@ -68,7 +78,6 @@ class DisclosureService extends CrudService {
   async check({ id, status, remark }) {
     const data = { status };
     if (status === '4') data['meta.state'] = 1;
-    console.log(data);
     await this.model.updateOne({ _id: ObjectId(id) }, data);
     // 换成对应的状态码,record在下面
     return await this.record({ id, method: status, remark });
@@ -187,9 +196,8 @@ class DisclosureService extends CrudService {
 
   // 导入
   async import({ uri }) {
-    const domain = process.env.NODE_ENV === 'development' ? 'http://broadcast.waityou24.cn/' : 'http://127.0.0.1';
     assert(uri, '未获取到文件地址');
-    const file = await this.ctx.curl(`${domain}${uri}`);
+    const file = await this.ctx.curl(`${this.domain}${uri}`);
     if (!(file && file.data)) {
       throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到指定文件');
     }
@@ -368,6 +376,163 @@ class DisclosureService extends CrudService {
       return base64;
     }
   }
-}
 
+
+  async toExport({ id, ...others }) {
+    const data = {
+      title: '专利运营-专利导出',
+      params: {
+        project: 'market',
+        service: 'patent.disclosure',
+        method: 'exportAction',
+        body: { id, ...others },
+      },
+      tenant: 'disclosure.export',
+      user: id,
+    };
+    try {
+      await this.ctx.service.util.httpUtil.cpost('/api/mission', 'mission', data);
+    } catch (error) {
+      console.log(error);
+      throw new BusinessError(ErrorCode.SERVICE_FAULT, '任务创建失败');
+
+    }
+  }
+
+  async exportAction({ missionid, ...body }) {
+    const nowDate = new Date().getTime();
+    const filename = `专利运营-专利导出-${nowDate}.xlsx`;
+    const path = `${this.root_path}${this.excel_path}`;
+    if (!path) {
+      throw new BusinessError(ErrorCode.BUSINESS, '服务端没有设置存储路径');
+    }
+    if (!fs.existsSync(path)) {
+      // 如果不存在文件夹,就创建
+      fs.mkdirSync(path);
+    }
+    // 整理条件
+    const total = await this.ctx.service.dock.patent.count(body);
+    console.log(total);
+    if (total === 0) {
+      try {
+        const data = {
+          progress: 0,
+          status: '3',
+          remark: '未查到任何数据,无法导出',
+        };
+        await this.ctx.service.util.httpUtil.cpost(`/api/mission/update/${missionid}`, 'mission', data);
+      } catch (error) {
+        this.logger.error(`任务id:${missionid},更新失败操作 失败`);
+      }
+      return;
+    }
+    let skip = 0;
+    let downloadPath;
+    // 将数据分割,否则容易直接把js堆栈干满了,服务就炸了
+    for (let i = 0; i < total; i = i + this.export_limit) {
+      const list = await this.ctx.service.dock.patent.query(body, { 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}`;
+  }
+
+  getHeader() {
+    const arr = [
+      { header: '申请号', key: 'create_number', width: 30, style: { alignment: { wrapText: true, vertical: 'middle', horizontal: 'center' } } },
+      { header: '申请日', key: 'create_date', width: 30, style: { alignment: { wrapText: true, vertical: 'middle', horizontal: 'center' } } },
+      { header: '公开(公告)号', key: 'success_number', width: 30, style: { alignment: { wrapText: true, vertical: 'middle', horizontal: 'center' } } },
+      { header: '公开(公告)日', key: 'success_date', width: 30, style: { alignment: { wrapText: true, vertical: 'middle', horizontal: 'center' } } },
+      { header: '发明人', key: 'inventor', width: 30, style: { alignment: { wrapText: true, vertical: 'middle', horizontal: 'center' } } },
+      { header: '代理机构', key: 'agent', width: 30, style: { alignment: { wrapText: true, vertical: 'middle', horizontal: 'center' } } },
+      { header: '代理人', key: 'agent_personal', width: 30, style: { alignment: { wrapText: true, vertical: 'middle', horizontal: 'center' } } },
+      { header: '摘要', key: 'abstract', width: 30, style: { alignment: { wrapText: true, vertical: 'middle', horizontal: 'center' } } },
+      { header: '发明人地址', key: 'address', width: 30, style: { alignment: { wrapText: true, vertical: 'middle', horizontal: 'center' } } },
+      { header: '标题', key: 'name', width: 30, style: { alignment: { wrapText: true, vertical: 'middle', horizontal: 'center' } } },
+      { header: '申请人', key: 'apply_personal', width: 30, style: { alignment: { wrapText: true, vertical: 'middle', horizontal: 'center' } } },
+      { header: '专利有效性', key: 'term', width: 30, style: { alignment: { wrapText: true, vertical: 'middle', horizontal: 'center' } } },
+      { header: '专利类型', key: 'type', width: 30, style: { alignment: { wrapText: true, vertical: 'middle', horizontal: 'center' } } },
+      { header: '首页附图', width: 30, style: { alignment: { wrapText: true, vertical: 'middle', horizontal: 'center' } } },
+    ];
+    return arr;
+  }
+}
 module.exports = DisclosureService;

+ 72 - 66
app/service/util/rabbitMq.js

@@ -1,66 +1,72 @@
-'use strict';
-
-const Service = require('egg').Service;
-
-class RabbitmqService extends Service {
-
-  constructor(ctx) {
-    super(ctx);
-    this.exType = 'topic';
-    this.durable = true;
-  }
-
-  // 接收消息
-  async receiveQueueMsg(ex) {
-    this.ctx.logger.info('调用mq的' + ex);
-    const self = this;
-    const { mq } = self.ctx;
-    if (mq) {
-      const ch = await mq.conn.createChannel();
-      await ch.assertExchange(ex, 'topic', { durable: true });
-      const q = await ch.assertQueue('', { exclusive: true });
-      await ch.bindQueue(q.queue, ex, '*');
-      await ch.consume(q.queue, msg => this.logMessage(msg, this), { noAck: true });
-    } else {
-      this.ctx.logger.error('!!!!!!没有配置MQ插件!!!!!!');
-    }
-  }
-
-  async logMessage(msg) {
-    const result = msg.content.toString();
-    const headers = msg.properties.headers;
-  }
-
-  // mission队列处理
-  async mission() {
-    const { mq } = this.ctx;
-    if (mq) {
-      const ch = await mq.conn.createChannel();
-      const queue = 'mission/market';
-      try {
-        // 创建队列:在没有队列的情况,直接获取会导致程序无法启动
-        await ch.assertQueue(queue, { durable: false });
-        await ch.consume(queue, msg => this.dealMission(msg), { noAck: true });
-      } catch (error) {
-        this.ctx.logger.error('未找到订阅的队列');
-      }
-    } else {
-      this.ctx.logger.error('!!!!!!没有配置MQ插件!!!!!!');
-    }
-  }
-  // 执行任务
-  async dealMission(bdata) {
-    if (!bdata) this.ctx.logger.error('mission队列中信息不存在');
-    let data = bdata.content.toString();
-    try {
-      data = JSON.parse(data);
-    } catch (error) {
-      this.ctx.logger.error('数据不是object');
-    }
-    const { service, method, ...others } = data;
-    if (service && method) this.ctx.service[service][method](others);
-
-  }
-}
-
-module.exports = RabbitmqService;
+'use strict';
+
+const Service = require('egg').Service;
+const _ = require('lodash');
+
+class RabbitmqService extends Service {
+
+  constructor(ctx) {
+    super(ctx);
+    this.exType = 'topic';
+    this.durable = true;
+  }
+
+  // 接收消息
+  async receiveQueueMsg(ex) {
+    this.ctx.logger.info('调用mq的' + ex);
+    const self = this;
+    const { mq } = self.ctx;
+    if (mq) {
+      const ch = await mq.conn.createChannel();
+      await ch.assertExchange(ex, 'topic', { durable: true });
+      const q = await ch.assertQueue('', { exclusive: true });
+      await ch.bindQueue(q.queue, ex, '*');
+      await ch.consume(q.queue, msg => this.logMessage(msg, this), { noAck: true });
+    } else {
+      this.ctx.logger.error('!!!!!!没有配置MQ插件!!!!!!');
+    }
+  }
+
+  async logMessage(msg) {
+    const result = msg.content.toString();
+    const headers = msg.properties.headers;
+  }
+
+  // mission队列处理
+  async mission() {
+    const { mq } = this.ctx;
+    if (mq) {
+      const ch = await mq.conn.createChannel();
+      const queue = 'mission/market';
+      try {
+        // 创建队列:在没有队列的情况,直接获取会导致程序无法启动
+        await ch.assertQueue(queue, { durable: false });
+        await ch.consume(queue, msg => this.dealMission(msg), { noAck: true });
+      } catch (error) {
+        this.ctx.logger.error('未找到订阅的队列');
+      }
+    } else {
+      this.ctx.logger.error('!!!!!!没有配置MQ插件!!!!!!');
+    }
+  }
+  // 执行任务
+  async dealMission(bdata) {
+    if (!bdata) this.ctx.logger.error('mission队列中信息不存在');
+    let data = bdata.content.toString();
+    try {
+      data = JSON.parse(data);
+    } catch (error) {
+      this.ctx.logger.error('数据不是object');
+    }
+    const { service, method, project, ...others } = data;
+    const arr = service.split('.');
+    let s = this.ctx.service;
+    for (const key of arr) {
+      s = s[key];
+    }
+    s[method](others);
+
+  }
+}
+
+module.exports = RabbitmqService;

+ 2 - 1
config/config.default.js

@@ -73,7 +73,8 @@ module.exports = appInfo => {
   };
 
   config.export = {
-    root_path: 'D:\\workspace\\service\\service-file\\upload\\',
+    root_path: 'E:\\exportFile',
+    domain: 'http://broadcast.waityou24.cn',
   };
   config.project = {
     mission: 'http://127.0.0.1:4001',

+ 4 - 0
config/config.prod.js

@@ -28,5 +28,9 @@ module.exports = () => {
     },
   };
 
+  config.export = {
+    root_path: 'D:\\workspace\\service\\service-file\\upload',
+    domain: 'http://127.0.0.1',
+  };
   return config;
 };