123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 |
- 'use strict';
- const { CrudService } = require('naf-framework-mongoose/lib/service');
- const { BusinessError, ErrorCode } = require('naf-core').Error;
- const { ObjectId } = require('mongoose').Types;
- const moment = require('moment');
- const _ = require('lodash');
- const compressing = require('compressing');
- const { sep } = require('path');
- const path = require('path');
- const fs = require('fs');
- const encoding = require('encoding'); // 编码转换
- const fxp = require('fast-xml-parser'); // xml转换
- // 专利运营专利申请预警表
- class PatentwarningService extends CrudService {
- constructor(ctx) {
- super(ctx, 'patentwarning');
- this.model = this.ctx.model.Patent.Patentwarning;
- this.import_root_path = _.get(this.ctx.app.config.import, 'root_path');
- this.patentInfo = this.ctx.model.Patent.Patentinfo;
- this.patentApply = this.ctx.model.Patent.Patentapply;
- this.personalModel = this.ctx.model.Personal;
- this.cpcErrorMsg = this.ctx.model.Patent.Cpcimporterror;
- }
- async import({ uri }) {
- uri = uri.replace('/files', this.import_root_path);
- const fileFullName = path.basename(uri);
- const arr = fileFullName.split('.');
- const ext = _.last(arr);
- const uncompressFilePath = `${this.import_root_path}${sep}temp`;
- if (ext !== 'zip') {
- throw new BusinessError(ErrorCode.FILE_FAULT, '只接收压缩格式为zip的压缩包');
- }
- // 解压
- try {
- await compressing.zip.uncompress(uri, `${uncompressFilePath}`);
- } catch (error) {
- throw new BusinessError(ErrorCode.FILE_FAULT, '解压失败');
- }
- // 修改,多个专利:需要扫描下解压后的文件夹,然后循环处理下面所有的内容
- const tempDirRootPath = `${uncompressFilePath}${sep}`;
- let tempDir = fs.readdirSync(tempDirRootPath);
- let errorList = [];
- // 2023-02-06: zip格式修改: zip套dir => zip套zip, zip解压出dir;
- // 也就是需要将zip再次解压一遍,并将所有的zip删除即可
- const isAllZip = tempDir.some((f) => f.includes('zip'));
- if (isAllZip) {
- for (const p of tempDir) {
- if (!p.includes('.zip')) continue;
- const zipFullPath = `${uncompressFilePath}${sep}${p}`;
- const zipArr = p.split('.');
- const name = _.head(zipArr);
- try {
- await compressing.zip.uncompress(zipFullPath, `${uncompressFilePath}${sep}${name}`);
- } catch (error) {
- await this.dirDelete(uncompressFilePath);
- errorList.push({ key: p, word: '內部解压包,解压发生错误', error });
- }
- }
- // 删除zip
- await this.deleteZip(uncompressFilePath);
- tempDir = fs.readdirSync(tempDirRootPath);
- }
- for (const tempDirPath of tempDir) {
- if (tempDirPath.includes('.zip')) continue;
- // const thisDirPath = `${tempDirRootPath}${sep}${tempDirPath}`;
- const thisDirPath = path.resolve(tempDirRootPath, tempDirPath);
- const patentNumber = tempDirPath;
- // 找到
- let filePaths = [];
- try {
- filePaths = await this.findFileNameLoop(thisDirPath);
- } catch (error) {
- errorList.push({ key: patentNumber, word: '格式不对', error });
- continue;
- }
- if (filePaths.length <= 0) {
- errorList.push({ key: patentNumber, word: '未找到文件' });
- continue;
- }
- // 2021-10-16 修改: 取出第一层的xml文件,即:路径最短的;除文件名外,字符串长度最小的
- let xmlPaths = filePaths.filter((f) => f.includes('.xml'));
- if (xmlPaths.length > 0) {
- // 去掉文件名
- xmlPaths = xmlPaths.map((i) => {
- const arr = i.split(sep);
- arr.pop();
- const obj = { dir: arr.join(sep), fullPath: i };
- return obj;
- });
- // // 按路径字符串长度排序
- // xmlPaths = xmlPaths.sort((a, b) => {
- // const anum = a.fullPath.length;
- // const bnum = b.fullPath.length;
- // return anum - bnum;
- // });
- xmlPaths = xmlPaths.filter((f) => f.fullPath.includes('list.xml'));
- }
- const xmlPath = _.get(_.head(xmlPaths), 'fullPath');
- if (!xmlPath) {
- errorList.push({ key: patentNumber, word: '未找到xml文件' });
- continue;
- // throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到xml文件');
- }
- let xmlData;
- try {
- xmlData = await this.dealXml(xmlPath);
- } catch (error) {
- errorList.push({ key: patentNumber, word: `解析xml数据中的 申请号 和 专利名称 失败 于:${xmlPath}`, ...xmlData });
- continue;
- // throw new BusinessError(ErrorCode.SERVICE_FAULT, '解析申请号失败');
- }
- if (!xmlData) {
- errorList.push({ key: patentNumber, word: '未找到xml的数据' });
- continue;
- // throw new BusinessError(ErrorCode.FILE_FAULT, '未找到申请号');
- }
- /**
- * @property {Array} patent 专利信息
- * @property {Boolean || null} needChange 是否修改数据
- */
- let result;
- try {
- // 2022-09-02 修改为在数组中查询,所以下面所有关于result的处理都需要变成数组的处理
- result = await this.getPatent(xmlData);
- } catch (error) {
- errorList.push({ key: patentNumber, word: '查询专利信息失败', ...xmlData });
- continue;
- // throw new BusinessError(ErrorCode.SERVICE_FAULT, '查询专利信息失败');
- }
- // 2022-09-02 数组处理模式 ↑
- const patents = _.get(result, 'patent');
- if (!patents || patents.length <= 0) {
- errorList.push({ key: patentNumber, word: '未通过 申请号 或 专利名称 找到指定专利', ...xmlData });
- continue;
- }
- for (const patent of patents) {
- // 2022-09-02 原处理进入循环中处理
- let warningData;
- try {
- warningData = await this.getWarningData(patent);
- } catch (error) {
- errorList.push({ key: patentNumber, word: '组织专利信息警告数据失败', ...xmlData });
- continue;
- // throw new BusinessError(ErrorCode.SERVICE_FAULT, '组织专利信息警告数据失败');
- }
- // 2023-02-07 原来是.tif,现在是.pdf
- const uploadPaths = filePaths.filter((f) => f.includes('.pdf'));
- if (uploadPaths && uploadPaths.length > 0) {
- try {
- await this.toUploadFile(warningData, uploadPaths);
- } catch (error) {
- errorList.push({ key: patentNumber, word: '存储数据失败', ...xmlData });
- continue;
- }
- }
- }
- }
- try {
- // await this.dirDelete(`${thisDirPath}`);
- await this.dirDelete(uncompressFilePath);
- } catch (error) {
- this.ctx.logger.error('清除缓存失败');
- }
- // 2022-09-05 将错误信息添加到表中
- errorList = errorList.map((i) => ({ ...i, filepath: uri, time: moment().format('YYYY-MM-DD HH:mm:ss') }));
- await this.cpcErrorMsg.insertMany(errorList);
- if (errorList.length > 0) return errorList;
- return 'ok';
- }
- /**
- * 上传图片,保存
- * @param {Array} data 警告数据,未保存
- * @param {Array} files tif图片文件路径数组
- */
- async toUploadFile(data, files) {
- const filePaths = [];
- const savePath = ObjectId();
- for (const file of files) {
- let arr = file.split(sep);
- const fullFileName = _.last(arr);
- arr = fullFileName.split('.');
- // 文件后缀
- const ext = _.last(arr);
- // 图片文件
- const buffer = await fs.readFileSync(file);
- // 新文件名
- const randomStr = ObjectId();
- // 新文件名带后缀
- const newFileName = `${randomStr}.${ext}`;
- // 上传后部分路径
- const shortPath = `platform${sep}patent${sep}${savePath}${sep}`;
- // 上传全路径
- const path = `${this.import_root_path}${sep}${shortPath}`;
- // 检查上传全路径是否存在,不存在就创建文件夹
- await this.checkPathAndCreate(path);
- // 另存文件
- await fs.writeFileSync(`${path}${newFileName}`, buffer);
- // 替换为files开头
- let dataPath = path.replace(this.import_root_path, '/files');
- while (dataPath.indexOf('\\') >= 0) {
- dataPath = dataPath.replace('\\', '/');
- }
- // 补全请求用路径的所有路径
- dataPath += newFileName;
- filePaths.push(dataPath);
- }
- for (const i of data) {
- i.file_url = filePaths;
- }
- const res = await this.model.insertMany(data);
- return res;
- }
- /**
- * 检查路径,没有创建
- * @param {Array} filePath 图片路径数组
- */
- async checkPathAndCreate(filePath) {
- const arr = filePath.split(sep);
- // w:第一个是盘符,直接和第二个合并
- // l:前几个应该都是存在的.也可以合并
- let head = _.head(arr);
- if (arr[1]) head = `${head}${sep}${arr[1]}`;
- arr.shift();
- arr[0] = head;
- let curPath;
- for (const p of arr) {
- curPath = `${curPath ? curPath + sep : ''}${p}`;
- if (!fs.existsSync(curPath)) {
- await fs.mkdirSync(curPath);
- }
- }
- }
- /**
- * 组织专利预警数据
- * @param {Object} patent 专利
- */
- async getWarningData(patent) {
- const object = {};
- const arr = [];
- if (_.get(patent, 'create_number')) object.create_number = _.get(patent, 'create_number');
- if (_.get(patent, 'id')) object.patent_id = _.get(patent, 'id');
- if (_.get(patent, 'name')) object.patent_name = _.get(patent, 'name');
- // 找人的信息
- const users = _.get(patent, 'user_id');
- if (users && _.isArray(users)) {
- for (const user of users) {
- if (!_.get(user, 'user_id') || !_.get(user, 'name')) continue;
- const { user_id, name } = user;
- const obj = _.cloneDeep(object);
- obj.to_id = user_id;
- obj.to_name = name;
- arr.push(obj);
- }
- // 2021-11-18 添加,user,mech,admin,agentmech是否存在,如果存在,也添加预警信息
- const list = ['user', 'mech', 'admin', 'agentmech'];
- const suffix = ['id', 'name'];
- for (const prefix of list) {
- const marr = suffix.map((i) => `${prefix}_${i}`);
- const r = marr.every((i) => _.get(patent, i));
- if (r) {
- const obj = _.cloneDeep(object);
- for (const key of suffix) {
- obj[`to_${key}`] = _.get(patent, `${prefix}_${key}`);
- }
- arr.push(obj);
- }
- }
- } else if (users) {
- const obj = _.cloneDeep(object);
- const name = _.get(patent, 'user_name');
- obj.to_id = users;
- obj.to_name = name;
- arr.push(obj);
- }
- return arr;
- }
- /**
- * 在patentApply/patentInfo表中找指定的专利
- * @param {Object} object xml的数据
- */
- async getPatent(object) {
- let { name, create_number } = object;
- create_number = `CN${create_number}`;
- const arr = create_number.split('');
- arr.splice(arr.length - 1, 0, '.');
- create_number = arr.join('');
- let res;
- const needChange = false;
- // 2022-09-02 改为多条数据查询,不再针对一个数据
- // 1,名称相同,关联人不同:
- const listPA = await this.patentApply.find({ $or: [{ create_number }, { name }] });
- for (const i of listPA) {
- const { create_number: ocn, _id } = i;
- // create_number 不一致,就去更改
- if (ocn !== create_number) await this.patentApply.updateOne({ _id }, { create_number });
- }
- const listPI = await this.patentInfo.find({ $or: [{ create_number }, { name }] });
- res = [...listPA, ...listPI];
- const returnObject = {};
- if (res.length > 0) {
- returnObject.patent = JSON.parse(JSON.stringify(res));
- if (needChange) {
- returnObject.create_number = create_number;
- returnObject.needChange = needChange;
- }
- return returnObject;
- }
- // res = await this.patentApply.findOne({ create_number });
- // // 如果在申请中,使用名称找到,则之后需要将该数据的专利号改为xml中的专利号
- // if (!res) {
- // res = await this.patentApply.findOne({ name });
- // needChange = true;
- // }
- // if (!res) {
- // res = await this.patentInfo.findOne({ create_number });
- // }
- // if (!res) {
- // res = await this.patentInfo.findOne({ name });
- // // }
- // const returnObject = {};
- // if (res) {
- // if (needChange) {
- // res.create_number = create_number;
- // returnObject.needChange = needChange;
- // }
- // returnObject.patent = res;
- // return returnObject;
- // }
- return null;
- }
- /**
- * 根据路径找到xml,再找到该xml的申请号和专利名称
- * @param {String} filePath xml的文件路径
- */
- async dealXml(filePath) {
- const buffer = await fs.readFileSync(filePath);
- let str = encoding.convert(buffer, 'UTF8', 'UTF8');
- if (!str) throw new BusinessError(ErrorCode.FILE_FAULT, '读取xml文件失败');
- str = str.toString();
- const json = fxp.parse(str);
- const create_number = _.get(json, 'data-bus.TONGZHISXJ.SHUXINGXX.SHENQINGH');
- const name = _.get(json, 'data-bus.TONGZHISXJ.SHUXINGXX.FAMINGMC');
- if (!name) return null;
- return { name, create_number };
- }
- /**
- * 找到深层的tif和xml
- * 因为命名方式都是以文件名,之后tif的文件夹也在深层fileName.套娃且文件名都是fileName
- * @param {String} uri temp路径
- */
- async findFileNameLoop(uri) {
- const filePath = uri;
- if (!fs.existsSync(filePath)) {
- return [];
- }
- const files = fs.readdirSync(filePath);
- let result = [];
- for (const file of files) {
- const curPath = path.resolve(filePath, file);
- if (fs.statSync(curPath).isDirectory()) {
- const arr = await this.findFileNameLoop(curPath);
- result.push(...arr);
- } else {
- result.push(curPath);
- }
- }
- // 2023-02-07 原来是.tif,现在是.pdf
- result = result.filter((f) => f.includes('.pdf') || f.includes('.xml'));
- return result;
- }
- /**
- * 删除路径下的所有内容
- * @param {String} filePath 路径
- */
- async dirDelete(filePath) {
- if (fs.existsSync(filePath)) {
- const files = fs.readdirSync(filePath);
- for (const file of files) {
- const curPath = `${filePath}${sep}${file}`;
- if (fs.statSync(curPath).isDirectory()) {
- // recurse
- this.dirDelete(curPath);
- } else {
- // delete file
- fs.unlinkSync(curPath);
- }
- }
- fs.rmdirSync(filePath);
- }
- }
- /**
- * 删除路径下的所有zip
- * @param {String} filePath 路径
- */
- async deleteZip(filePath) {
- if (!fs.existsSync(filePath)) return;
- const files = fs.readdirSync(filePath);
- for (const file of files) {
- if (!file.includes('.zip')) continue;
- const curPath = `${filePath}${sep}${file}`;
- if (!fs.existsSync(curPath)) continue;
- fs.unlinkSync(curPath);
- }
- }
- }
- module.exports = PatentwarningService;
|