You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

241 lines
6.9 KiB

8 months ago
'use strict';
const Service = require('egg').Service;
const _ = require("lodash")
const mongoose = require('mongoose');
const crc16 = require('crc/crc16');
// const dayjs = require('dayjs');
const ObjectId = mongoose.Types.ObjectId;
class UtilsService extends Service {
//基础表
baseModel() {
let WorkflowlaunchSchema = new mongoose.Schema({
create_at: {
type: Date,
default: Date.now,
index: true
},
update_at: {
type: Date,
default: Date.now,
index: true
},
title: {
type: String,
index: true
},
user: {
type: String,
ref: 'XbyUser',
index: true
},
delete: {
type: Number,
default: 0, //0代表未删除,1代表删除
index: true
},
}, {
strict: false
});
return WorkflowlaunchSchema;
}
//数据库查找表
async findModelByName(name) {
if (!this.ctx.model.hasOwnProperty(name)) {
let baseModel = this.baseModel();
let lowerFirstName = _.lowerFirst(name)
this.ctx.model[name] = mongoose.model(lowerFirstName, baseModel, lowerFirstName);
}
return this.ctx.model[name];
}
/**
* 通用数据获取接口
* @param modelObj
* @param filterOption 过滤条件排序分页条件
* {
"filters": {
"submission.name": {
"$regex": ".*66",
"$options": "i"
}
},
"sort": {
"create_at": -1
},
"skip": 0,
"limit": 20,
}
* @returns {Promise<*>}
*/
async getDataList(name, filterOption = {}) {
// let { ctx } = this;
//facet 查询结果的同时显示总数
let modelObj = await this.findModelByName(name)
let facet = {
$facet: {
total: [{
$count: "total"
}],
results: []
}
};
//sort 排序用
if (!_.isEmpty(filterOption.sort)) {
facet.$facet.results.push({
$sort: filterOption.sort
});
}
//skip 排序用
facet.$facet.results.push({
$skip: _.get(filterOption, ["skip"], 0) || 0
});
//limit 排序用
if (_.get(filterOption, ["limit"], 1)) {
facet.$facet.results.push({
$limit: filterOption.limit
});
}
let agg = [];
//转换字符串_id为objectid,目前只能转第一层和第二层的id,要改为迭代查找
for (let key in (_.get(filterOption, ["filters"], {}) || {})) {
if (key === '_id' && _.isString(filterOption.filters[key]) && ObjectId.isValid(filterOption.filters[key])) {
//值是一个 mongodb id字符串
filterOption.filters[key] = ObjectId(filterOption.filters[key]);
}
else if (key === 'create_at' || key === 'update_at') {
filterOption.filters[key]["$gte"] = new Date(filterOption.filters[key]["$gte"]);
filterOption.filters[key]["$lt"] = new Date(filterOption.filters[key]["$lt"]);
}
}
agg.push({
$match: { delete: 0, ...(_.get(filterOption, ["filters"], {}) || {}) }
});
if (filterOption.hasOwnProperty('project') && !_.isEmpty(filterOption.project)) {
facet.$facet.results.push({
$project: filterOption.project
});
}
//当results ===0 时, 只保留统计
let aggTotal = []
let aggResults = []
aggTotal = [...agg, ...facet["$facet"]["total"]]
aggResults = [...agg, ...facet["$facet"]["results"]]
// ctx.logger.debug(modelObj.modelName, JSON.stringify(aggResults));
let resultRecords = [];
//allowDiskUse:解决管道内数据量超过100M时报错问题
let resultTotal = await modelObj.collection.aggregate(aggTotal, { allowDiskUse: true }).toArray();
if (filterOption.results !== 0) {
resultRecords = await modelObj.collection.aggregate(aggResults, { allowDiskUse: true }).toArray();
}
let r = resultTotal[0] ? resultTotal[0] : { total: 0 }
r["results"] = resultRecords
return r;
}
//修改数据
async update(name, updateData, filter = {}) {
let modelObj = await this.findModelByName(name)
updateData['update_at'] = Date.now();
//转换子路径是因为更新子路径要用.点的形式,不能用字典形式
if ("submission" in updateData) {
_.forEach(updateData.submission, function (value, key) {
updateData["submission." + key] = value;
})
updateData = _.omit(updateData, "submission")
}
updateData = {
$set: updateData
};
filter = _.isEmpty(filter) ? { "_id": updateData["$set"]._id } : filter
delete updateData["$set"]['_id']
return await modelObj.findOneAndUpdate(
filter
, updateData, {
lean: true
}).exec();
}
//新增数据
async save(name, addOption) {
let modelObj = await this.findModelByName(name)
if (!_.isArray(addOption)) {
addOption = [addOption]
}
let saveData = await modelObj.create(addOption)
return saveData
}
//modbus生成crc校验
/**
* MODBUS-RTU CRC校验
* @param data 命令(不带crc16循环冗余码的命令)
* @returns {any[]} 十六进制高低位
* @constructor
*/
MODBUS_CRC(data, isAll = false, type = "string") {
let trimStr = _.replace(data, /[\s]/g, '')
let res = crc16(trimStr, 'hex')
let dataBuffer = Buffer.from(trimStr, "HEX")
let crcValue = 0xFFFF;
for (let i = 0; i < dataBuffer.length; i++) {
crcValue ^= dataBuffer[i]
for (let j = 0; j < 8; j++) {
if (crcValue & 0x0001) {
crcValue >>= 1
crcValue ^= 0xA001
} else {
crcValue >>= 1
}
}
}
crcValue = crcValue.toString(16)
crcValue = _.padStart(crcValue, 4, "0")
//处理进来的字符串
if (type === "string") {
let result = "";
for (let i = 0; i < trimStr.length; i++) {
result += trimStr[i];
if (i % 2 === 1) result += ' ';
}
let returnData = `${crcValue.substring(2, 4)} ${crcValue.substring(0, 2)}`
if (isAll) {
returnData = `${result}${crcValue.substring(2, 4)} ${crcValue.substring(0, 2)}`
}
return returnData
} else {
let result = [];
for (let i = 0; i < trimStr.length; i++) {
if (i % 2 === 1) {
let item = trimStr.substr(i - 1, 2)
result.push(parseInt(`0x${item}`, 16))
};
}
let returnDataArr = [parseInt(`0x${crcValue.substring(2, 4)}`, 16), parseInt(`0x${crcValue.substring(0, 2)}`, 16)]
result.push(returnDataArr[0])
result.push(returnDataArr[1])
if (isAll) {
return Buffer.from(result)
} else {
return Buffer.from(returnDataArr)
}
}
}
sleep(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
async checkPerssion(model, filter) {
let { ctx } = this
try {
let res = await ctx.model[model].find(filter)
if (res && res.length) {
return true
} else {
return false
}
} catch (err) {
return false
}
}
}
module.exports = UtilsService;