123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- 'use strict';
- /**
- * 指标模板控制器
- *
- * @author Mai
- * @data 2018/4/19
- * @version
- */
- const fs = require('fs');
- const streamToArray = require('stream-to-array');
- const mathjs = require('mathjs');
- module.exports = {
- /**
- * 转换数据
- *
- * @param {Array} list - 数据库查找的数据
- * @param {Boolean} tree - 是否展示为树形结构
- * @param {String} id - id属性名
- * @param {String} pid - pid属性名
- * @return {Object} - 返回转换后的数据
- */
- convertData(list, tree = true, id, pid) {
- const rootData = [];
- const childData = {};
- let listData = [];
- for (const tmp of list) {
- if (tmp[pid] === 0 || tmp[pid] === -1) {
- rootData.push(tmp);
- continue;
- }
- if (childData[tmp[pid]] === undefined) {
- childData[tmp[pid]] = [];
- }
- childData[tmp[pid]].push(tmp);
- }
- // 递归组织数据
- if (tree) {
- this._recursionTreeData(rootData, childData, id);
- } else {
- this._recursionData(rootData, childData, listData, id);
- }
- return tree ? rootData : listData;
- },
- /**
- * 递归组织数组结构数据
- *
- * @param {Array} parent - 父节点
- * @param {Object} childData - 子元素(以pid为key的对象)
- * @param {Array} outputData - 处理后的数据
- * @param {String} id - id属性名
- * @return {void}
- */
- _recursionData(parent, childData, outputData = [], id) {
- for (const index in parent) {
- // 父节点先进数组
- outputData.push(parent[index]);
- // 判断是否存在子项
- if (childData[parent[index][id]] !== undefined) {
- // 子项作为父节点递归查找子项中是否还有子项
- const tmpParent = childData[parent[index][id]];
- // 已用的子项删除
- delete childData[parent[index][id]];
- // 递归元素
- this._recursionData(tmpParent, childData, outputData);
- }
- }
- },
- /**
- * 递归组织树结构数据
- *
- * @param {Array} parent - 父节点
- * @param {Object} childData - 子元素(以pid为key的对象)
- * @param {String} id - id属性名
- * @return {void}
- */
- _recursionTreeData(parent, childData = {}, id) {
- if (Object.keys(childData).length <= 0) {
- return;
- }
- for (const index in parent) {
- // 判断是否存在子项
- if (childData[parent[index][id]] !== undefined) {
- // 子项作为父节点递归查找子项中是否还有子项
- const tmpParent = childData[parent[index][id]];
- // 已用的子项删除
- delete childData[parent[index][id]];
- this._recursionTreeData(tmpParent, childData, id);
- // 递归完赋值回原数据
- parent[index].children = tmpParent;
- }
- }
- },
- /**
- * 将文件流的数据保存至本地文件
- * @param stream
- * @param fileName
- * @returns {Promise<void>}
- */
- async saveStreamFile(stream, fileName) {
- // 读取字节流
- const parts = await streamToArray(stream);
- // 转化为buffer
- const buffer = Buffer.concat(parts);
- // 写入文件
- await fs.writeFileSync(fileName, buffer);
- },
- /**
- * 检查code是否是指标模板数据
- * @param {String} code
- * @returns {boolean}
- */
- ValidTemplateCode(code) {
- const reg1 = /(^[a-z]+)([a-z0-9\-]*)/i;
- const reg2 = /([a-z0-9]+$)/i;
- return reg1.test(code) && reg2.test(code);
- },
- /**
- * 检查code 是否是 指标节点编号
- * @param {String} code
- * @returns {boolean}
- */
- ValidTemplateNodeCode(code) {
- const reg1 = /(^[a-z]+)([a-z0-9\-]*$)/i;
- const reg2 = /([a-z0-9]+$)/i;
- const reg3 = /([\-][0-9]+$)/i;
- return reg1.test(code) && reg2.test(code) && (!reg3.test(code));
- },
- /**
- * 检查code 是否是 指标节点编号
- * @param {String} code
- * @returns {boolean}
- */
- ValidTemplateIndexCode(code) {
- const reg1 = /(^[a-z]+)([a-z0-9\-]*$)/i;
- const reg2 = /([0-9]+$)/i;
- return reg1.test(code) && reg2.test(code);
- },
- /**
- * 检查code 是否 是有效的绑定分项编号
- * @param {String} code - 编号
- * @return {Boolean}
- */
- validMatchCode(code) {
- const parts = code.split('-');
- const reg1 = /(^[a-z]+$)/i;
- const reg2 = /(^[0-9]+$)/;
- for (const i in parts) {
- if (i == 0) {
- if (!reg2.test(parts[i])) {
- return false;
- }
- } else {
- if (!(reg1.test(parts[i]) || reg2.test(parts[i]))) {
- return false;
- }
- }
- }
- return true;
- },
- /**
- * 在数组arr中查找a.field=value的成员a
- *
- * @param {Array} arr - 数组
- * @param {String} field - 匹配属性名称
- * @param {any} value - 匹配属性值
- * @returns {*}
- */
- findObj(arr, field, value) {
- if (arr.length === 0) { return undefined; }
- for (const a of arr) {
- if (a[field] && a[field] === value) {
- return a;
- }
- }
- return undefined;
- },
- /**
- * 读取json文件并解析
- *
- * @param {String} fileName - json文件路径
- * @returns {any}
- */
- loadJsonFile(fileName) {
- const sJson = fs.readFileSync(fileName);
- return JSON.parse(sJson);
- },
- /**
- * 增删改单条json数据
- * @param {string} json 单条json值
- * @param {String} key 属性
- * @param {String} value 值
- * @returns {string}
- */
- operationJson(json,key, value) {
- if(typeof value === "undefined") {
- delete json[key];
- } else {
- json[key] = value;
- }
- return json;
- },
- /**
- * 判断value是否是四则运算符
- * @param {String} value - 判断字符串
- * @return {Boolean}
- */
- isOperator(value) {
- const operatorString = "+-*/()";
- return operatorString.indexOf(value) > -1;
- },
- /**
- * Rpn解析栈
- * @param exp
- * @returns {Array}
- */
- parse2Rpn(exp) {
- const getPriority = function (value){
- switch(value){
- case '+':
- case '-':
- return 1;
- case '*':
- case '/':
- return 2;
- default:
- return 0;
- }
- };
- const priority = function (o1, o2){
- return getPriority(o1) <= getPriority(o2);
- };
- const inputStack = [];
- const outputStack = [];
- const outputQueue = [];
- for (let i = 0, len = exp.length; i < len; i++) {
- const cur = exp[i];
- if (cur !== ' ' ) {
- inputStack.push(cur);
- }
- }
- let num = '', isNumPre = false, isOperatorPre = false;
- while(inputStack.length > 0){
- const cur = inputStack.shift();
- if (this.isOperator(cur) && !(cur === '-' && !isNumPre)) {
- if (isNumPre) {
- outputQueue.push(parseFloat(num));
- num = '';
- }
- if (cur === '(') {
- outputStack.push(cur);
- } else if (cur === ')') {
- let po = outputStack.pop();
- while (po !== '(' && outputStack.length > 0) {
- outputQueue.push(po);
- po = outputStack.pop();
- }
- if (po !== '(') {
- throw "error: unmatched ()";
- }
- } else {
- while(priority(cur, outputStack[outputStack.length - 1]) && outputStack.length > 0){
- outputQueue.push(outputStack.pop());
- }
- outputStack.push(cur);
- }
- isNumPre = false;
- isOperatorPre = true;
- } else {
- num = num + cur;
- isNumPre = true;
- isOperatorPre = false;
- if (inputStack.length === 0) {
- outputQueue.push(parseFloat(num));
- }
- }
- }
- if (outputStack.length > 0) {
- if (outputStack[outputStack.length - 1] === ')' || outputStack[outputStack.length - 1] === '(') {
- throw "error: unmatched ()";
- }
- while (outputStack.length > 0) {
- outputQueue.push(outputStack.pop());
- }
- }
- return outputQueue;
- },
- /**
- * 计算Rpn解析栈
- * @param rpnQueue
- * @returns {*}
- */
- evalRpn(rpnQueue) {
- const getResult = function (num1, num2, opera) {
- switch (opera) {
- case '+':
- return num1 + num2;
- case '-':
- return num1 - num2;
- case '*':
- return num1 * num2;
- case '/':
- return num1 / num2;
- default:
- throw '参数错误';
- }
- };
- const outputStack = [];
- while(rpnQueue.length > 0){
- const cur = rpnQueue.shift();
- if (!this.isOperator(cur)) {
- outputStack.push(cur);
- } else {
- if (outputStack.length < 2) {
- throw "unvalid stack length";
- }
- const sec = outputStack.pop();
- const fir = outputStack.pop();
- outputStack.push(getResult(fir, sec, cur));
- }
- }
- if (outputStack.length !== 1) {
- throw "unvalid expression";
- } else {
- return outputStack[0];
- }
- },
- /**
- * 解析四则运算字符串并计算
- * @param {String} expr
- * @returns
- */
- calcExprStrRpn(expr) {
- try {
- if (!isNaN(Number(expr))) {
- return Number(expr);
- } else {
- const rpnArr = this.parse2Rpn(expr);
- const result = this.evalRpn(rpnArr);
- return result === Infinity ? null : result;
- }
- } catch (err) {
- return null;
- }
- },
- /**
- * 使用四则运算符分隔
- * @param expr
- * @returns {Array}
- */
- splitByOperator (expr) {
- const exprStack = [];
- const result = [];
- for(let i = 0, len = expr.length; i < len; i++){
- const cur = expr[i];
- if(cur !== ' ' ){
- exprStack.push(cur);
- }
- }
- let param = '', isParamBefore = false;
- while(exprStack.length > 0){
- const cur = exprStack.shift();
- if (this.isOperator(cur)) {
- if (isParamBefore) {
- result.push(param);
- param = '';
- }
- result.push(cur);
- isParamBefore = false;
- } else {
- param = param + cur;
- isParamBefore = true;
- if (exprStack.length === 0) {
- result.push(param);
- param = '';
- }
- }
- }
- return result;
- },
- /**
- * 解析 数学计算式(字符串) 并计算
- * @param expr
- * @returns {null}
- */
- calcExprStr(expr) {
- try {
- const result = mathjs.eval(expr);
- return result === Infinity ? null : result;
- } catch (err) {
- return null;
- }
- }
- };
|