patentwarning.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. 'use strict';
  2. const { CrudService } = require('naf-framework-mongoose/lib/service');
  3. const { BusinessError, ErrorCode } = require('naf-core').Error;
  4. const { ObjectId } = require('mongoose').Types;
  5. const _ = require('lodash');
  6. const compressing = require('compressing');
  7. const { sep } = require('path');
  8. const path = require('path');
  9. const fs = require('fs');
  10. const encoding = require('encoding'); // 编码转换
  11. const fxp = require('fast-xml-parser'); // xml转换
  12. // 专利运营专利申请预警表
  13. class PatentwarningService extends CrudService {
  14. constructor(ctx) {
  15. super(ctx, 'patentwarning');
  16. this.model = this.ctx.model.Patent.Patentwarning;
  17. this.import_root_path = _.get(this.ctx.app.config.import, 'root_path');
  18. this.patentInfo = this.ctx.model.Patent.Patentinfo;
  19. this.patentApply = this.ctx.model.Patent.Patentapply;
  20. this.personalModel = this.ctx.model.Personal;
  21. }
  22. async import({ uri }) {
  23. uri = uri.replace('/files', this.import_root_path);
  24. const fileFullName = path.basename(uri);
  25. const arr = fileFullName.split('.');
  26. const ext = _.last(arr);
  27. const fileName = _.head(arr);
  28. const uncompressFilePath = `${this.import_root_path}${sep}temp`;
  29. if (ext !== 'zip') {
  30. throw new BusinessError(ErrorCode.FILE_FAULT, '只接收压缩格式为zip的压缩包');
  31. }
  32. // 解压
  33. try {
  34. await compressing.zip.uncompress(uri, `${uncompressFilePath}`);
  35. } catch (error) {
  36. throw new BusinessError(ErrorCode.FILE_FAULT, '解压失败');
  37. }
  38. // 修改,多个专利:需要扫描下解压后的文件夹,然后循环处理下面所有的内容
  39. const tempDirRootPath = `${uncompressFilePath}${sep}${fileName}`;
  40. const tempDir = await fs.readdirSync(tempDirRootPath);
  41. const errorList = [];
  42. for (const tempDirPath of tempDir) {
  43. const thisDirPath = `${tempDirRootPath}${sep}${tempDirPath}`;
  44. const patentNumber = tempDirPath;
  45. // 找到
  46. let filePaths = [];
  47. try {
  48. filePaths = await this.findFileNameLoop(thisDirPath);
  49. } catch (error) {
  50. errorList.push({ key: patentNumber, word: '解析文件具体位置失败' });
  51. continue;
  52. }
  53. if (filePaths.length <= 0) {
  54. errorList.push({ key: patentNumber, word: '未找到文件' });
  55. continue;
  56. }
  57. const xmlPath = filePaths.find(f => f.includes('.xml'));
  58. if (!xmlPath) {
  59. errorList.push({ key: patentNumber, word: '未找到xml文件' });
  60. continue;
  61. // throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到xml文件');
  62. }
  63. let create_number;
  64. try {
  65. create_number = await this.dealXml(xmlPath);
  66. } catch (error) {
  67. errorList.push({ key: patentNumber, word: '解析申请号失败' });
  68. continue;
  69. // throw new BusinessError(ErrorCode.SERVICE_FAULT, '解析申请号失败');
  70. }
  71. if (!create_number) {
  72. errorList.push({ key: patentNumber, word: '未找到申请号' });
  73. continue;
  74. // throw new BusinessError(ErrorCode.FILE_FAULT, '未找到申请号');
  75. }
  76. let result;
  77. try {
  78. result = await this.getPatentFromInfo(create_number);
  79. } catch (error) {
  80. errorList.push({ key: patentNumber, word: '查询专利信息失败' });
  81. continue;
  82. // throw new BusinessError(ErrorCode.SERVICE_FAULT, '查询专利信息失败');
  83. }
  84. // 再找
  85. if (!result) {
  86. try {
  87. result = await this.getPatentFromApply(create_number);
  88. } catch (error) {
  89. errorList.push({ key: patentNumber, word: '查询申请信息失败' });
  90. continue;
  91. }
  92. }
  93. // 找不到就算了,弹回去了
  94. if (!result) {
  95. errorList.push({ key: patentNumber, word: '未通过申请号找到指定专利' });
  96. continue;
  97. // throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未通过申请号找到指定专利');
  98. }
  99. let warningData;
  100. try {
  101. warningData = await this.getWarningData(result);
  102. } catch (error) {
  103. errorList.push({ key: patentNumber, word: '组织专利信息警告数据失败' });
  104. continue;
  105. // throw new BusinessError(ErrorCode.SERVICE_FAULT, '组织专利信息警告数据失败');
  106. }
  107. const tifPaths = filePaths.filter(f => f.includes('.tif'));
  108. let lastResult;
  109. if (tifPaths && tifPaths.length > 0) {
  110. try {
  111. lastResult = await this.toUploadTif(warningData, tifPaths);
  112. } catch (error) {
  113. errorList.push({ key: patentNumber, word: '存储数据失败' });
  114. continue;
  115. }
  116. }
  117. if (lastResult) {
  118. try {
  119. await this.dirDelete(`${uncompressFilePath}`);
  120. } catch (error) {
  121. errorList.push({ key: patentNumber, word: '清除缓存失败' });
  122. continue;
  123. }
  124. }
  125. }
  126. if (errorList.length > 0) return errorList;
  127. return 'ok';
  128. }
  129. /**
  130. * 上传图片,保存
  131. * @param {Array} data 警告数据,未保存
  132. * @param {Array} files tif图片文件路径数组
  133. */
  134. async toUploadTif(data, files) {
  135. const filePaths = [];
  136. const savePath = ObjectId();
  137. for (const file of files) {
  138. let arr = file.split(sep);
  139. const fullFileName = _.last(arr);
  140. arr = fullFileName.split('.');
  141. // 文件后缀
  142. const ext = _.last(arr);
  143. // 图片文件
  144. const buffer = await fs.readFileSync(file);
  145. // 新文件名
  146. const randomStr = ObjectId();
  147. // 新文件名带后缀
  148. const newFileName = `${randomStr}.${ext}`;
  149. // 上传后部分路径
  150. const shortPath = `platform${sep}patent${sep}${savePath}${sep}`;
  151. // 上传全路径
  152. const path = `${this.import_root_path}${sep}${shortPath}`;
  153. // 检查上传全路径是否存在,不存在就创建文件夹
  154. await this.checkPathAndCreate(path);
  155. // 另存文件
  156. await fs.writeFileSync(`${path}${newFileName}`, buffer);
  157. // 替换为files开头
  158. let dataPath = path.replace(this.import_root_path, '/files');
  159. while (dataPath.indexOf('\\') >= 0) {
  160. dataPath = dataPath.replace('\\', '/');
  161. }
  162. // 补全请求用路径的所有路径
  163. dataPath += newFileName;
  164. filePaths.push(dataPath);
  165. }
  166. for (const i of data) {
  167. i.file_url = filePaths;
  168. }
  169. const res = await this.model.insertMany(data);
  170. return res;
  171. }
  172. /**
  173. * 检查路径,没有创建
  174. * @param {Array} filePath 图片路径数组
  175. */
  176. async checkPathAndCreate(filePath) {
  177. const arr = filePath.split(sep);
  178. // w:第一个是盘符,直接和第二个合并
  179. // l:前几个应该都是存在的.也可以合并
  180. let head = _.head(arr);
  181. if (arr[1]) head = `${head}${sep}${arr[1]}`;
  182. arr.shift();
  183. arr[0] = head;
  184. let curPath;
  185. for (const p of arr) {
  186. curPath = `${curPath ? curPath + sep : ''}${p}`;
  187. if (!fs.existsSync(curPath)) {
  188. await fs.mkdirSync(curPath);
  189. }
  190. }
  191. }
  192. /**
  193. * 组织专利预警数据
  194. * @param {Object} patent 专利
  195. */
  196. async getWarningData(patent) {
  197. const object = {};
  198. if (_.get(patent, 'create_number'))object.create_number = _.get(patent, 'create_number');
  199. if (_.get(patent, 'id'))object.patent_id = _.get(patent, 'id');
  200. if (_.get(patent, 'name'))object.patent_name = _.get(patent, 'name');
  201. // 找人的信息
  202. let userIds = _.get(patent, 'user_id', _.get(patent, 'inventor'));
  203. if (!userIds) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到专利的发明人');
  204. if (!_.isArray(userIds)) userIds = [ userIds ];
  205. userIds = userIds.map(i => ObjectId(i));
  206. const users = await this.personalModel.find({ _id: userIds });
  207. const arr = [];
  208. for (const user of users) {
  209. if (!_.get(user, '_id') || !_.get(user, 'name')) continue;
  210. const { _id, name } = user;
  211. const obj = _.cloneDeep(object);
  212. obj.to_id = _id;
  213. obj.to_name = name;
  214. arr.push(obj);
  215. }
  216. return arr;
  217. }
  218. /**
  219. * 在patentApply表中找指定的专利
  220. * @param {String} create_number 专利的申请号
  221. */
  222. async getPatentFromApply(create_number) {
  223. const res = await this.patentApply.findOne({ create_number });
  224. return res;
  225. }
  226. /**
  227. * 在patentInfo表中找指定的专利
  228. * @param {String} create_number 专利的申请号
  229. */
  230. async getPatentFromInfo(create_number) {
  231. const res = await this.patentInfo.findOne({ create_number });
  232. return res;
  233. }
  234. /**
  235. * 根据路径找到xml,再找到该xml的申请号
  236. * @param {String} filePath xml的文件路径
  237. */
  238. async dealXml(filePath) {
  239. const buffer = await fs.readFileSync(filePath);
  240. let str = encoding.convert(buffer, 'UTF8', 'GBK');
  241. if (!str) throw new BusinessError(ErrorCode.FILE_FAULT, '读取xml文件失败');
  242. str = str.toString();
  243. const json = fxp.parse(str);
  244. const create_number = _.get(json, 'data-bus.TONGZHISXJ.SHUXINGXX.SHENQINGH');
  245. return create_number;
  246. }
  247. /**
  248. * 找到深层的tif和xml
  249. * 因为命名方式都是以文件名,之后tif的文件夹也在深层fileName.套娃且文件名都是fileName
  250. * @param {String} uri temp路径
  251. */
  252. async findFileNameLoop(uri) {
  253. const filePath = `${_.trimEnd(uri, sep)}${sep}`;
  254. if (!fs.existsSync(filePath)) {
  255. return [];
  256. }
  257. const files = fs.readdirSync(filePath);
  258. let result = [];
  259. for (const file of files) {
  260. const curPath = `${filePath}${file}`;
  261. if (fs.statSync(curPath).isDirectory()) {
  262. const arr = await this.findFileNameLoop(curPath);
  263. result.push(...arr);
  264. } else {
  265. result.push(curPath);
  266. }
  267. }
  268. result = result.filter(f => f.includes('.tif') || f.includes('.xml'));
  269. return result;
  270. }
  271. /**
  272. * 删除路径下的所有内容
  273. * @param {String} filePath 路径
  274. */
  275. async dirDelete(filePath) {
  276. if (fs.existsSync(filePath)) {
  277. const files = fs.readdirSync(filePath);
  278. for (const file of files) {
  279. const curPath = `${filePath}${sep}${file}`;
  280. if (fs.statSync(curPath).isDirectory()) { // recurse
  281. this.dirDelete(curPath);
  282. } else { // delete file
  283. fs.unlinkSync(curPath);
  284. }
  285. }
  286. fs.rmdirSync(filePath);
  287. }
  288. }
  289. }
  290. module.exports = PatentwarningService;