|
@@ -4,13 +4,236 @@ const { BusinessError, ErrorCode } = require('naf-core').Error;
|
|
const { ObjectId } = require('mongoose').Types;
|
|
const { ObjectId } = require('mongoose').Types;
|
|
const _ = require('lodash');
|
|
const _ = require('lodash');
|
|
const assert = require('assert');
|
|
const assert = require('assert');
|
|
-
|
|
|
|
-
|
|
|
|
|
|
+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转换
|
|
|
|
+const mime = require('mime-types'); // 任意类型转换
|
|
// 专利运营专利申请预警表
|
|
// 专利运营专利申请预警表
|
|
class PatentwarningService extends CrudService {
|
|
class PatentwarningService extends CrudService {
|
|
constructor(ctx) {
|
|
constructor(ctx) {
|
|
super(ctx, 'patentwarning');
|
|
super(ctx, 'patentwarning');
|
|
this.model = this.ctx.model.Patent.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;
|
|
|
|
+ }
|
|
|
|
+ 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 fileName = _.head(arr);
|
|
|
|
+ const uncompressFilePath = `${this.import_root_path}${sep}temp`;
|
|
|
|
+ if (ext !== 'zip') {
|
|
|
|
+ throw new BusinessError(ErrorCode.FILE_FAULT, '只接收压缩格式为zip的压缩包');
|
|
|
|
+ }
|
|
|
|
+ // 解压
|
|
|
|
+ await compressing.zip.uncompress(uri, `${uncompressFilePath}`);
|
|
|
|
+ // 找到
|
|
|
|
+ const filePaths = await this.findFileNameLoop(uncompressFilePath, fileName);
|
|
|
|
+ const xmlPath = filePaths.find(f => f.includes('.xml'));
|
|
|
|
+ const create_number = await this.dealXml(xmlPath);
|
|
|
|
+ if (!create_number) throw new BusinessError(ErrorCode.FILE_FAULT, '未找到申请号');
|
|
|
|
+ let result = await this.getPatentFromInfo(create_number);
|
|
|
|
+ // 再找
|
|
|
|
+ if (!result) result = await this.getPatentFromApply(create_number);
|
|
|
|
+ // 找不到就算了,弹回去了
|
|
|
|
+ if (!result) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未通过申请号找到指定专利');
|
|
|
|
+ const warningData = await this.getWarningData(result);
|
|
|
|
+ const tifPaths = filePaths.filter(f => f.includes('.tif'));
|
|
|
|
+ if (tifPaths && tifPaths.length > 0) this.toUploadTif(warningData, tifPaths);
|
|
|
|
+ await this.dirDelete(`${uncompressFilePath}${fileName}`);
|
|
|
|
+ return 'ok';
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 上传图片,保存
|
|
|
|
+ * @param {Array} data 警告数据,未保存
|
|
|
|
+ * @param {Array} files tif图片文件路径数组
|
|
|
|
+ */
|
|
|
|
+ async toUploadTif(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 = {};
|
|
|
|
+ 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');
|
|
|
|
+ // 找人的信息
|
|
|
|
+ let userIds = _.get(patent, 'user_id', _.get(patent, 'inventer'));
|
|
|
|
+ if (!userIds) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到专利的发明人');
|
|
|
|
+ userIds = userIds.map(i => ObjectId(i));
|
|
|
|
+ const users = await this.personalModel.find({ _id: userIds });
|
|
|
|
+ const arr = [];
|
|
|
|
+ for (const user of users) {
|
|
|
|
+ if (!_.get(user, '_id') || !_.get(user, 'name')) continue;
|
|
|
|
+ const { _id, name } = user;
|
|
|
|
+ const obj = _.cloneDeep(object);
|
|
|
|
+ obj.to_id = _id;
|
|
|
|
+ obj.to_name = name;
|
|
|
|
+ arr.push(obj);
|
|
|
|
+ }
|
|
|
|
+ return arr;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 在patentApply表中找指定的专利
|
|
|
|
+ * @param {String} create_number 专利的申请号
|
|
|
|
+ */
|
|
|
|
+ async getPatentFromApply(create_number) {
|
|
|
|
+ const res = await this.patentApply.findOne({ create_number });
|
|
|
|
+ return res;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 在patentInfo表中找指定的专利
|
|
|
|
+ * @param {String} create_number 专利的申请号
|
|
|
|
+ */
|
|
|
|
+ async getPatentFromInfo(create_number) {
|
|
|
|
+ const res = await this.patentInfo.findOne({ create_number });
|
|
|
|
+ return res;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 根据路径找到xml,再找到该xml的申请号
|
|
|
|
+ * @param {String} filePath xml的文件路径
|
|
|
|
+ */
|
|
|
|
+ async dealXml(filePath) {
|
|
|
|
+ const buffer = await fs.readFileSync(filePath);
|
|
|
|
+ let str = encoding.convert(buffer, 'UTF8', 'GBK');
|
|
|
|
+ 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');
|
|
|
|
+ return create_number;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 找到深层的tif和xml
|
|
|
|
+ * 因为命名方式都是以文件名,之后tif的文件夹也在深层fileName.套娃且文件名都是fileName
|
|
|
|
+ * @param {String} uri temp路径
|
|
|
|
+ * @param {String} fileName 文件名
|
|
|
|
+ */
|
|
|
|
+ async findFileNameLoop(uri, fileName) {
|
|
|
|
+ const filePath = `${uri}${sep}${fileName}`;
|
|
|
|
+ if (!fs.existsSync(filePath)) {
|
|
|
|
+ return [];
|
|
|
|
+ }
|
|
|
|
+ const files = fs.readdirSync(filePath);
|
|
|
|
+ let result = [];
|
|
|
|
+ for (const file of files) {
|
|
|
|
+ const curPath = `${filePath}${sep}${file}`;
|
|
|
|
+ if (fs.statSync(curPath).isDirectory()) {
|
|
|
|
+ const res = await this.findFileNameLoop(curPath, file);
|
|
|
|
+ result.push(...res);
|
|
|
|
+ } else {
|
|
|
|
+ result.push(curPath);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ result = result.filter(f => f.includes('.tif') || 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);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 转换图片为base64
|
|
|
|
+ * @param {Object} object excel获取的图片object
|
|
|
|
+ * @property extension 后缀,文件类型
|
|
|
|
+ * @property buffer 图片内容,不含头部信息的,
|
|
|
|
+ */
|
|
|
|
+ turnImageToBase64(object = {}) {
|
|
|
|
+ const { extension, buffer } = object;
|
|
|
|
+ if (extension && buffer) {
|
|
|
|
+ const suffix = object.extension;
|
|
|
|
+ const ib = object.buffer.toString('base64');
|
|
|
|
+ const base64 = `data:image/${suffix};base64,${ib}`;
|
|
|
|
+ return base64;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|