UNPKG

gcl

Version:

码农村nodejs类库,完成解决回调陷阱,配置框架,IOC框架,统一多DB访问框架,可扩展日志框架和io/db/net/thread/pool 克隆表达式,加解密算法等等一系列基础类库和算法的实现

1,692 lines (1,656 loc) 47.5 kB
"use strict"; import util from "util"; import { parse, resolve, normalize } from "path"; import { createHash, createHmac, createSign, createVerify, createCipheriv, createCipher, createDecipheriv, createDecipher, } from "crypto"; import v4 from "uuid/v4"; import SnowflakeId from "snowflake-id"; import Decimal from "decimal.js"; import parser from "fast-xml-parser"; import he from "he"; import pako from "pako"; /* 减少语句路径 少用pop,push 改为i++--操作和[length]=new 频繁new的对象改为inherit2方法 尽管inherit2方法无法私有对象 多用三元?少用if 多用空方法 少用if 除非必须 少用delete 使用 || 代替 getValue 或者3元 使用for if(i++>1) 判断是否为空 使用substr lastIndexOf 代替split 尽量使用原生方法(native)代替自己的方法 */ export const environment = { os: process.cwd().indexOf("\\") >= 0 ? "windows" : "linux/unix", splitChar: process.cwd().indexOf("\\") >= 0 ? "\\" : "/", }; /** * 采用代理模式给类和类内方法添加属性 * @param(调用时的原方法对象,键值,键值上的一个新值) * @returns decorator */ export const prop = (target, k, v) => { target[k] = target[k] || []; target[k].push(v); }; /** * 添加link属性用于连接方法需求 * @param (link) */ export const link = (url) => { return (target) => prop(target, "link", url); }; /** * 添加多个desc属性用于动态显示方法描述 * @param (desc) */ export const desc = (des) => { return (target) => prop(target, "desc", des); }; /** * 判断对象是否有效 含有 not in (null,undefined,'null','',\s+,0,false) */ export const isValid = (data) => !!data && (data.replace == undefined || data.replace(/\s/g, "").length > 0); /** * 三元表达式,简化 多数情况可以用默认值或者 value || defaultValue 替换,但是当其为null时则不好判断 */ export const getValue = (data, defaultData) => isValid(data) ? data : defaultData; /** * 私有方法,返回_,__命名的一个自身对象和一个私有对象。一般在类方法第一句使用 * @param(this,__) * @return({this,private}) */ export const pris = () => { const key = Symbol("private"); return (obj, priv) => { obj[key] = (priv ? merge(obj[key], priv) : obj[key]) || {}; return { _: obj, __: obj[key], }; }; }; /** * 字符串格式化,使用<%k.v%>,{k.v}等等方式进行递进的属性替换,当字符串模板不可用时使用。 */ export const format = function (s, o) { if (!s || !o) { return getValue(s, ""); } if (s.indexOf("<%=") >= 0) return __.funrep(s, o, /<%=[^(%>)]+%>/gi, /<%=/g, /%>/g); if (s.indexOf("{") >= 0) return __.funrep(s, o, /\{[^(})]+\}/gi, /\{/g, /\}/g); return s; }; /** * 返回私有StringBuilder对象实例,含有 */ export const sb = () => new __.StringBuilder(); export const showException = (name = "", e) => { if (isValid(e)) { name += "\r\nmessage:" + getValue(e.message, e) + (e.stack ? "\r\nstack:" + e.stack + (e.fileName ? "\r\nfile:" + e.fileName : "") + (e.lineNumber ? "\r\nlineNumber:" + e.lineNumber : "") : e.description ? "\r\ndescription:" + e.description : ""); console.log(name); } }; export const showEx = showException; export const tryF = (func, errcall) => new Proxy(func, __.tryHandle(errcall)); export const tryC = (func, errcall) => tryF(func, errcall)(); export const tryC2 = (err, func, errcall) => err ? (errcall || __.showEx)(e) : tryC(func, errcall); export const watch = (restart) => { if (!__.start || restart) { __.start = new Date(); console.log("VESH.watch开始" + __.start); } else { console.log("VESH.watch 持续了:" + __.start.diff("ms", new Date())); } }; export const isArray = Array.isArray; export const once = (func, timeout) => { timeout = timeout || 1; if (func.timeoutID) { clearTimeout(func.timeoutID); } if (timeout == 1) process.nextTick(() => tryC(func)); else func.timeoutID = setTimeout(() => tryC(func), timeout); }; //exp的非链式操作与链式操作,非链式不保证执行顺序,链式保证执行顺序,对象的随机并发操作与顺序执行,数组的map随机并发操作与顺序执行 //使用once满足非promise截止的请求,循环全部是promise截止的r //根据执行的源头不同分为 whileC(链式、非链式,promise),forC(链式、非链式,promise),each(链式、非链式,promise),next(链式 promise),finalC(非链式 promise) 不同种类 根据链式与非链式, //保证异步的同步执行 //保证当直接返回true或者call(null,true)时中断循环 export const whileC = (exp, func, isSequ = false) => isSequ ? isSequ > 1 ? __.disorderlWhile(exp, func, isSequ) : __.sequfunc(exp, func, exp()) : __.disorderfunc(exp, func, exp()); export const each = (data, func, isSequ = false) => isSequ ? isSequ > 1 ? __.disorderlEach(data, func, isSequ) : __.sequEach(data, func) : __.disorderEach(data, func); export const forC = (obj, func, isSequ = false) => isSequ ? isSequ > 1 ? __.disorderlFor(obj, func, isSequ) : __.sequFor(obj, func) : __.disorderFor(obj, func); export const finalC = (...funs) => { const data = {}, finalF = funs.pop(); return each(funs, (v) => callback2(v, null, data)).then(() => callback2(finalF, null, data), ); }; export const next = (...funs) => { const data = {}; return each(funs, (v) => callback2(v, null, data), true); }; /** * 用于链式处理事务 参数为成对定义的正向和回滚方法{go:func,rollback:func} 也可简写为 {g:func,r:func} */ export const tnext = (...funs) => { let i = 1; const data = {}, goerr = () => { throw new Error("请在第" + i + "个对象定义g或者go方法"); }, rollbacks = []; return each( funs, (v) => callback2(v.g || v.go || goerr, v, data) .then((v2) => { rollbacks.unshift( v.r || v.rollback || (function () { throw new Error("请在第" + i + "个对象定义r或者rollback方法"); })(), ); i++; return v2; }) .catch((e2) => { if (typeof e2 === "string" || typeof e2 === "boolean") rollbacks.unshift( v.r || v.rollback || (function () { throw new Error("请在第" + i + "个对象定义r或者rollback方法"); })(), ); throw typeof e2 === "string" ? new Error(e2) : e2; }), true, ).catch((e) => next(...rollbacks).then(() => { throw e; }), ); }; /** * 异步改同步请求 * 兼容直接返回值,返回一个Promise或者返回undefined 最后一个参数调用call(e,data) 三种情况 * @param {*} args */ export const callback2 = function (...args) { return new Promise(async (re, rj) => { try { const call = (e, data) => (e ? rj(e) : re(data)); const func = args[0]; const _this = args[1] || null; const paras = args.slice(2).concat([call]); let data = Reflect.apply(func, _this, paras); //this 不对 Reflect.apply(func, null, paras); if (data && data.then) data = (await data) || false; switch (typeof data) { case "function": data(call); case "undefined": break; default: call(null, data); break; } } catch (e) { rj(e); } }); }; /** * 仅适用最后一个参数为call的情况 * @param {*} args */ export const callback = function (...args) { const func = args[0]; args[0] = function (...args2) { const that = this; Reflect.apply(func, that, args2); }; return callback2(...args); }; export const random = () => parseInt("" + __.index++ + new Date().getTime()); export const hashRandom = function (min = 0, max) { return Math.floor(Math.abs(hash(guid()) % (max - min))) + min; }; /** * 获取字符串的哈希值 * @param {String} str * @param {Boolean} caseSensitive * @return {Number} hashCode */ export const hash = (str, caseSensitive = false) => { str = str.toString(); if (!caseSensitive) { str = str.toLowerCase(); } // 1315423911=b'1001110011001111100011010100111' let hash = 1315423911, i, ch; for (i = str.length - 1; i >= 0; i--) { ch = str.charCodeAt(i); hash ^= (hash << 5) + ch + (hash >> 2); } return hash & 0x7fffffff; }; /** * 获取字符串的sha1 base64 哈希值 * @param {String} str * @param {Boolean} caseSensitive * @return {Number} hashCode */ export const hash2 = (str) => { let ret = createHash("sha256").update(str).digest("base64"); return ( ret.substr(0, 2) + ret.substr(11, 1) + ret.substr(3, 10) + ret.substr(2, 1) + ret.substr(12) ); }; export const formatPrice = function ( number, decimals, dec_point, thousands_sep, ) { number = (number + "").replace(/[^0-9+-Ee.]/g, ""); let n = !isFinite(+number) ? 0 : +number, prec = !isFinite(+decimals) ? 2 : Math.abs(decimals), sep = typeof thousands_sep === "undefined" ? "," : thousands_sep, dec = typeof dec_point === "undefined" ? "." : dec_point, s = "", toFixedFix = function (n, prec) { const k = Math.pow(10, prec); return "" + Math.round(n * k) / k; }; // Fix for IE parseFloat(0.55).toFixed(0) = 0; s = (prec ? toFixedFix(n, prec) : "" + Math.round(n)).split("."); if (s[0].length > 3) { s[0] = s[0].replace(/B(?=(?:fd{3})+(?!d))/g, sep); } if ((s[1] || "").length < prec) { s[1] = s[1] || ""; s[1] += new Array(prec - s[1].length + 1).join("0"); } return s.join(dec); }; /** * 只更新标点符号不更新全半角文字的encode * @param {String} html * @return {String} encodeURIComponent之后的字段 */ //replace(/[\r\n]+/g, '>v>j>').replace(/\s+/g, ' ').replace(/>v>j>/g, '\r\n'). export const encHtml = (html = "") => ((html || "").match(__.encmatch) || []) .join("") .replace(__.encreg, (a) => __.encother[a] || encodeURIComponent(a)); export const decHtml = (html = "") => decodeURIComponent(html); export const toJsonString = JSON.stringify; export const json = JSON.parse; /** * * @param {*} 二维数组 * @param {*} 是否需要引号 */ export const toTJson = (data = [], quotation = true) => { if (!isArray(data)) data = [data]; const res = []; if (data[0] && isArray(data[0])) { for (const i in data) { res[i] = toTJson(data[i]); } } else { //找到第一个不是数组的实例对象进行处理 res[0] = []; for (const k in data[0]) { res[0].push(quotation ? '"' + k + '"' : "" + k); } for (const v in data) { const obj = []; for (const k2 in data[0]) obj.push(__.getTJsonValue(data[v][k2], quotation)); res.push(obj); } } return res; }; export const getType = (x = null) => { if (x == null) { return "null"; } const t = typeof x; if (t != "object" && t != "Object") { return t; } if (isArray(x)) { return "Array"; } let c = Object.prototype.toString.apply(x); c = c.substring(8, c.length - 1); if (c != "Object") { return c; } if (x.constructor == Object) { return c; } if ( x.prototype && "classname" in x.prototype.constructor && typeof x.prototype.constructor.classname == "string" ) { return x.constructor.prototype.classname; } return "ukObject"; }; export const merge = (...argu) => { if (argu.length < 2) { return argu[0] ? argu[0] : {}; } if (argu.length > 0 && true === argu[argu.length - 1]) { let _ = argu[0]; for (let i2 = 1; i2 < argu.length; i2++) _ = __.merge(_, argu[i2]); return _; } else { let _ = {}; for (let i2 = 0; i2 < argu.length; i2++) _ = __.merge(_, argu[i2]); return _; } }; export const inherits = function (parent, args) { //绕过了parent的构造函数,重新链接原型链条 const _temp = (function () { const F = function () {}; util.inherits(F, parent); //F.prototype = parent.prototype; F.prototype.isF = true; return new F(); })(); _temp.constructor = parent; if (!this.prototype) { //这里确认是实例 //确定是打断了原型链 使得this的原型为Object parent.apply(this, args); //从新接驳原型链 使得原型链上的prototype都设置到最早的类的prototype上了 if (this.__proto__ && !this.__proto__.isF) { util.inherits(this.__proto__.constructor, _temp.__proto__.constructor); //this.__proto__.constructor.prototype = _temp.__proto__.constructor.prototype; } //son.prototype = _temp; //这里可以分层 但是会使得prototype实例变了又变 废弃 this.__proto__ = _temp; //父类方法只能找到静态方法 this.base = this.__proto__.constructor.prototype; } else { console.log("如果失败,需要配合子类构造函数中使用parent.apply(this,[***])"); //这里确认是类定义 this.prototype = _temp; } }; export const create2 = function (type, args) { if (typeof type == "function") { return new type(...args); } else showException("请传入类定义"); }; export const create = function (type, args) { if (typeof type == "function") { args = isArray(args) ? args : [args]; let ret = "(new type("; if (isArray(args)) { for (const i in args) { ret += "args[" + i + "],"; } if (args.length > 0) { ret = ret.substr(0, ret.length - 1); } } return eval(ret + "))"); } else showException("请传入类定义"); }; /** * 分别尝试全路径.js/全路径.njs/全路径加载类 并对处理结果进行缓存 会导致热更新失败错误! * @param {text} md5源串 */ export const md5 = function (text) { return createHash("md5").update(text, "utf-8").digest("hex"); }; /** * 扩展hash * https://www.jb51.net/article/50668.htm * @param {string} text 原文 * @param {string} type 算法 譬如 md5 * @param {string} ecode 入栈 譬如 utf8 * @param {string} ocode 出栈 譬如 hex */ export const xhash = function ( text, type = "md5", ecode = "utf8", ocode = "hex", ) { return createHash(type).update(text, ecode).digest(ocode); }; /** * 带秘钥hash * https://www.jb51.net/article/50668.htm * @param {string} text 原文 * @param {string} key 秘钥 譬如 111 * @param {string} type 算法 譬如 md5 * @param {string} ecode 入栈 譬如 utf8 * @param {string} ocode 出栈 譬如 hex */ export const xhmac = function ( text, key, type = "sha256", ecode = "utf8", ocode = "base64", ) { return createHmac(type, key).update(text, ecode).digest(ocode); }; /** * 带秘钥生成签名 * https://www.jb51.net/article/50668.htm * openssl list-public-key-algorithms 看所有的签名算法 * @param {*} text * @param {*} key * @param {*} type * @param {*} keycode */ export const xsign = function ( text, key, type = "RSA-SHA256", keycode = "hex", ) { const sign = createSign(type); sign.update(text); return sign.sign(key, keycode); }; /** * 带秘钥验证签名 * https://www.jb51.net/article/50668.htm * openssl list-public-key-algorithms 看所有的签名算法 * @param {*} text * @param {*} key * @param {*} type * @param {*} keycode */ export const xverify = function ( text, key, type = "RSA-SHA256", keycode = "hex", ) { const sign = createVerify(type); sign.update(text); return sign.verify(key, keycode); }; /** * 加密 * https://www.jb51.net/article/50668.htm * https://blog.csdn.net/shmnh/article/details/48254001?utm_source=blogxgwz0 * @param {string} text 原文 * @param {string} key 秘钥 譬如 111 * @param {string} type 算法 譬如 md5 * @param {string} ecode 入栈 譬如 utf8 * @param {string} ocode 出栈 譬如 base64 */ export const xcrypt = function ( text, key, type = "aes-256-cbc", ecode = "utf8", ocode = "base64", ) { var cipher = createCipher(type, key); return cipher.update(text, ecode, ocode) + cipher.final(ocode); }; /** * 解密 * https://www.jb51.net/article/50668.htm * https://blog.csdn.net/shmnh/article/details/48254001?utm_source=blogxgwz0 * @param {string} text 原文 * @param {string} key 秘钥 譬如 111 * @param {string} type 算法 譬如 md5 * @param {string} ecode 入栈 譬如 base64 * @param {string} ocode 出栈 譬如 utf8 */ export const xdcrypt = function ( text, key, type = "aes-256-cbc", ecode = "base64", ocode = "utf8", ) { var cipher = createDecipher(type, key); return cipher.update(text, ecode, ocode) + cipher.final(ocode); }; /** * 加密 * https://www.jb51.net/article/50668.htm * https://blog.csdn.net/shmnh/article/details/48254001?utm_source=blogxgwz0 * @param {string} text 原文 * @param {string} key 秘钥 譬如 111 * @param {string} iv 偏移 一般是 8或者16位默认可用Buffer.alloc(0) * @param {string} type 算法 譬如 md5 * @param {string} ecode 入栈 譬如 utf8 * @param {string} ocode 出栈 譬如 base64 */ export const xcryptiv = function ( text, key, iv = Buffer.alloc(0), type = "aes-256-cbc", ecode = "utf8", ocode = "base64", ) { var cipher = createCipheriv(type, key, iv); return cipher.update(text, ecode, ocode) + cipher.final(ocode); }; /** * 解密 * https://www.jb51.net/article/50668.htm * https://blog.csdn.net/shmnh/article/details/48254001?utm_source=blogxgwz0 * @param {string} text 原文 * @param {string} key 秘钥 譬如 111 * @param {string} iv 偏移 一般是 8或者16位默认可用Buffer.alloc(0) * @param {string} type 算法 譬如 md5 * @param {string} ecode 入栈 譬如 base64 * @param {string} ocode 出栈 譬如 utf8 */ export const xdcryptiv = function ( text, key, iv = Buffer.alloc(0), type = "aes-256-cbc", ecode = "base64", ocode = "utf8", ) { var cipher = createCipheriv(type, key, iv); return cipher.update(text, ecode, ocode) + cipher.final(ocode); }; /** * 加密 已经被 xcryptiv取代 * https://www.jb51.net/article/50668.htm * https://blog.csdn.net/shmnh/article/details/48254001?utm_source=blogxgwz0 * @param {string} text 原文 * @param {string} key 秘钥 譬如 111 * @param {string} ecode 入栈 譬如 utf8 * @param {string} ocode 出栈 譬如 base64 */ export const xcrypt_a1e = function ( text, key, iv = "", ecode = "utf8", ocode = "base64", ) { var cipher = createCipheriv("aes-128-ecb", key, iv); cipher.setAutoPadding(true); return cipher.update(text, ecode, ocode) + cipher.final(ocode); }; /** * 解密 已经被 xdcryptiv取代 * https://www.jb51.net/article/50668.htm * https://blog.csdn.net/shmnh/article/details/48254001?utm_source=blogxgwz0 * @param {string} text 原文 * @param {string} key 秘钥 譬如 111 * @param {string} type 算法 譬如 md5 * @param {string} ecode 入栈 譬如 base64 * @param {string} ocode 出栈 譬如 utf8 */ export const xdcrypt_a1e = function ( text, key, iv = "", ecode = "base64", ocode = "utf8", ) { var cipher = createDecipheriv("aes-128-ecb", key, iv); cipher.setAutoPadding(true); return cipher.update(text, ecode, ocode) + cipher.final(ocode); }; /** 专门给Java 的 AES方法提供密码转换, https://www.zhihuclub.com/149867.shtml 一般可以用 xdcrypt_a1e(string,SHA1PRNG(key)); 与Java互通 */ export const SHA1PRNG = function (pwd) { return Buffer.from( createHash("sha1") .update(createHash("sha1").update(pwd).digest("buffer")) .digest("hex") .substring(0, 32), "hex", ); }; /** * 分别尝试全路径.js/全路径.njs/全路径加载类 并对处理结果进行缓存 会导致热更新失败错误! * @param {文件上级路径} path * @param {类名} base */ export const include = function (path, base = null) { const paths = `${path}|${base}`; return ( __.include[paths] || (function () { if (__.unclude[paths]) throw new Error(`加载${paths}失败!`); __.include[paths] = (function () { try { if (path.startWith("\\") || path.startWith("/")) { base = base ? format(base) : parse(resolve(normalize(process.mainModule.filename))).dir; if ("windows".eq(environment.os || "")) { //windows base = base.replace(/\//g, "\\"); path = path.trim("/").trim("\\").replace(/\//g, "\\"); } else { //linux base = base.replace(/\\\\/g, "/"); path = path.trim("\\").trim("/").replace(/\\\\/g, "/"); } try { try { return require(`${base}${environment.splitChar}${path}.njs`); } catch (e2) { if ( path.endWith("action") && e2.message.indexOf("action.njs") < 0 ) console.log( `${base}${environment.splitChar}${path}.njs 加载失败!`, e2.stack, ); return require(`${base}${environment.splitChar}${path}.js`); } } catch (e3) { return require(path); } } else return require(path); } catch (e) { //console.log(e.stack); __.unclude[paths] = true; throw new Error(`加载${paths}失败!!${e.stack}`); } })(); return __.include[paths]; })() ); }; export const applyCAE = function (S) { //功能出现严重问题 无法在ES6下使用 S[__.settings] = {}; S[__.exsettings] = {}; //获取不存在就配置 S.getSettings = function (key, data) { if (!isValid(S[__.settings][key])) { if (isValid(S[__.exsettings][key])) { S[__.settings][key] = merge(getValue(data, {}), S[__.exsettings][key]); delete S[__.exsettings][key]; } else S[__.settings][key] = getValue(data, {}); } return S[__.settings][key]; }; //扩展默认配置 S.extendSettings = function (key, data) { if (isValid(S[__.settings][key])) { S[__.settings][key] = merge(S[__.settings][key], data); } else { if (S.exSettings[key]) { S[__.exsettings][key] = merge( S[__.exsettings][key], getValue(data, {}), ); } else { S[__.exsettings][key] = getValue(data, {}); } } }; S.clearSettings = function () { S[__.settings] = {}; }; S.registCommand = function (name, func) { const comms = S.getSettings("comms", []); const data = comms[name]; if (isValid(data) && typeof data != "function") { func.apply(null, data); } comms[name] = func; }; /* V用于调用被调用页面注册的命令以处理异步命令调用,当命令尚未注册而已经被调用时,参数会先被缓存下来,然后当命令注册时,已知的参数再被调用。 --案例 S.callCommand('showXXList',[{id:1}]) */ S.callCommand = function (name, data) { const caller = null; const comms = S.getSettings("comms", []); const func = comms[name]; data = isArray(data) ? data : [data]; if (isValid(func) && typeof func == "function") { once(function () { func.apply(caller, data); }); } else { comms[name] = data; } }; /* 用来判断是否调用页面,当已经调用过(part),返回true,否则返回false; --案例 if (!S.hasCommand('editor.open')) S.part("/FileServer/layout/editor/editor.htm"); */ S.hasCommand = function (name) { const comms = S.getSettings("comms", []); const func = comms[name]; return isValid(func) && typeof func == "function"; }; /* 仅限iframe方式调用时,先取消原页面添加的方法 //业务逻辑深度交叉,iframe落后的控件连接方式时使用 一定要在part前 --案例 S.cleanCommand('editor.open'); S.part("/FileServer/layout/editor/editor.htm",null,"iframe",function(){}); */ S.cleanCommand = function (name) { const comms = S.getSettings("comms", []); delete comms[name]; }; /* V用于被调用页面注册命令以处理异步命令调用,当命令尚未注册而已经被调用时,参数会先被缓存下来,然后当命令注册时,已知的参数再被调用。 并约定1分钟内 允许注册者多次被触发 --案例 S.registEvent('showXXList',getData),S.registEvent(['showXXList',''],getData) */ S.registEvent = function (name, func, isTop) { const fun = function (name, func, isTop) { const events = S.getSettings("events", []); let funs = events[name]; if (!isValid(funs)) { funs = []; events[name] = funs; } if (typeof func == "function") { if (isTop && !funs.top) { funs.top = func; funs.unshift(func); } else { if (isTop && funs.top) { showException("S.registEvent:" + name + " 事件已经有订阅者被置顶!"); } funs.push(func); } let ecall = S.getSettings("eventcall", {}); ecall = ecall[name] ? ecall[name] : {}; if (ecall.time && ecall.time >= new Date().getTime()) { once(function () { func.apply(ecall.caller, ecall.data); }); } } }; if (isArray(name)) { each( name, function (v) { fun(v, func, isTop); return false; }, true, ); } else { fun(name, func, isTop); } }; /* V用于调用被调用页面注册的事件以处理异步命令调用,当命令尚未注册而已经被调用时,参数会先被缓存下来,然后当命令注册时,已知的参数再被调用。 并约定1分钟内 允许注册者多次被触发 --案例 S.callEvent('showXXList',[{id:1}]) */ S.callEvent = function (name, data) { const caller = null; const events = S.getSettings("events", []); const funs = events[name]; data = isArray(data) ? data : [data]; if (isValid(funs) && isArray(funs)) { each(funs, function (func) { //报错不下火线 tryC(function () { func.apply(caller, data); }); }); } let ecall = S.getSettings("eventcall", {}); if (!ecall[name]) { ecall[name] = {}; } ecall = ecall[name]; ecall.time = new Date().add("n", 1).getTime(); ecall.data = data; ecall.caller = caller; }; /* 用来判断是否调用页面,当已经调用过(part),返回true,否则返回false; --案例 if (!S.hasEvent('editor.open')) S.part("/FileServer/layout/editor/editor.htm"); */ S.hasEvent = function (name) { const events = S.getSettings("events", []); const funs = events[name]; if (isValid(funs) && isArray(funs)) { return true; } return false; }; /* 仅限iframe方式调用时,先取消原页面添加的方法 //业务逻辑深度交叉,iframe落后的控件连接方式时使用 一定要在part前 --案例 S.cleanEvent('editor.open'); S.part("/FileServer/layout/editor/editor.htm",null,"iframe",function(){}); */ S.cleanEvent = function (name) { const events = S.getSettings("events", []); delete events[name]; }; }; /** * 转换文本内容为压缩格式 * @param {*} str */ export const deflateBase64 = function (str) { return Buffer.from(pako.deflate(str, { to: "string" })).toString("base64"); }; /** * base64还原文本内容 * @param {*} str */ export const inflateBase64 = function (str) { var ret; try { ret = Buffer.from(str, "base64"); return pako.inflate(ret, { to: "string" }); } catch (e) { ret = _decodeEmoji(str); } return ret || str; }; export const encodeEmoji = deflateBase64; export const decodeEmoji = inflateBase64; /** * 转换Emoji为base64格式 * @param {*} str */ export const _encodeEmoji = function (str) { return __.convert2Base64( encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) { return String.fromCharCode("0x" + p1); }), ); }; /** * base64还原emoji * @param {*} str */ export const _decodeEmoji = function (str) { var ret; try { ret = __.convert2Binary(str).split(""); var ret2 = []; ret.forEach(function (c) { ret2.push("%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2)); }); return decodeURIComponent(ret2.join("")); } catch (e) { ret = decodeURIComponent(str); } return ret || str; }; /** * 生成xml解析对象 toJson用于转换xml2Json toXml用于转换json2xml * @param {config} config * 譬如 attributeNamePrefix: "@_", attrNodeName: "attr", //default is 'false' textNodeName: "#text", ignoreAttributes: true, ignoreNameSpace: false, allowBooleanAttributes: false, parseNodeValue: true, parseAttributeValue: false, trimValues: true, cdataTagName: "__cdata", //default is 'false' cdataPositionChar: "\\c", localeRange: "", //To support non english character in tag/attribute values. parseTrueNumberOnly: false, attrValueProcessor: a => he.decode(a, { isAttributeValue: true }), //default is a=>a tagValueProcessor: a => he.decode(a) //default is a=>a */ export const xml = (config) => { config = merge(__.xmloptions, config || {}); var Jconfig = merge(config, { tagValueProcessor: (a) => he.encode(a, { useNamedReferences: true }), // default is a=>a attrValueProcessor: (a) => he.encode(a, { isAttributeValue: isAttribute, useNamedReferences: true }), // default is a=>a }); const j2x = new parser.j2xParser(config); const ret = { toXml: (json) => { try { return j2x.parse({ xml: json }); } catch (e) { if (e.message.indexOf("html.replace") >= 0) throw new Error("toXml:JSON中的值不能是非字符串内容!"); else throw e; } }, toJson: (xml) => { xml = (xml + "").replace(/(<\?).+\?>/g, ""); !xml.startWith("<xml") && (xml = `<xml>${xml}</xml>`); return ret.deCDATA(parser.parse(xml), Jconfig); }, deCDATA: (json) => { for (var k in json) { if (json[k][config.cdataTagName]) json[k] = json[k][config.cdataTagName]; else if (typeof json[k] == "object") ret.deCDATA(json[k]); } return json.xml; }, }; return ret; }; /** * 生成GUID */ export const GUID = function () { return v4().replace(/\-/g, ""); }; let SnowId = null; /** * 生成雪花ID */ export const SNOWID = function () { if (!SnowId) SnowId = new SnowflakeId({ mid: 42, offset: (new Date().getFullYear() - 1970) * 31536000 * 1000, }); return SnowId.generate(); }; export default { environment, prop, link, desc, isValid, getValue, format, sb, showEx, showException, include, random, hashRandom, tryC, tryC2, watch, isArray, once, whileC, forC, each, finalC, next, callback, callback2, encHtml, decHtml, toJsonString, json, merge, inherits, create, create2, applyCAE, pris, hash, hash2, toTJson, getType, formatPrice, encodeEmoji, decodeEmoji, GUID, md5, xhash, xhmac, xsign, xverify, xcrypt, xdcrypt, xml, xcrypt_a1e, xdcrypt_a1e, SHA1PRNG, SNOWID, xcryptiv, xdcryptiv, deflateBase64, inflateBase64, }; //const symbol = Symbol; const pri = pris(); const __ = { settings: Symbol("settings"), exsettings: Symbol("exsettings"), encreg: /<|>|~|(\r\n)|!|@|#|\$|%|\^|;|\*|\(|\)|_|\+|\{|\}|\||:|\"|\?|`|\-|=|\[|\]|\\|;|\'|,|\.|\/|,|;|\s/g, encmatch: /[a-zA-Z0-9\u4E00-\u9FA5\uF900-\uFA2D]|[\u3002|\uff1f|\uff01|\uff0c|\u3001|\uff1b|\uff1a|\u201c|\u201d|\u2018|\u2019|\uff08|\uff09|\u300a|\u300b|\u3008|\u3009|\u3010|\u3011|\u300e|\u300f|\u300c|\u300d|\ufe43|\ufe44|\u3014|\u3015|\u2026|\u2014|\uff5e|\ufe4f|\uffe5]|<|>|~|(\r\n)|!|@|#|\$|%|\^|;|\*|\(|\)|_|\+|\{|\}|\||:|\"|\?|`|\-|=|\[|\]|\\|;|\'|,|\.|\/|,|;|\s/g, encother: { "(": "%28", ")": "%29", "*": "%2a", "'": "%27", ".": "%2e", "-": "%2d", _: "%5f", }, funrep: function (s, o, reg, lreg, rreg) { return s.replace(reg, function (word) { const key = "" + word.replace(lreg, "").replace(rreg, ""); return typeof o[key] == "undefined" ? "" : o[key]; }); }, /** * StringBuilder nodejs版本 用于连续操作字符串对象而不经常移动数组 比较准确快捷的修改字符串内容 */ StringBuilder: class { constructor() { const that = this; const { _, __ } = pri(that, { data: [], length: 0, append: (str = "") => { const { _, __ } = pri(that); __.data.push(str); __.length += str.length; }, }); } get length() { return pri(this).__.length; } append(str) { const { _, __ } = pri(this); str = !!str ? __.append(str) : ""; return this; } appendFormat(fmt, data) { return this.append(format(fmt, data)); } insert(start, data) { const { _, __ } = pri(this); const str = _.toString(); __.data = [str.substr(0, start), data, str.substr(start)]; __.length = str.length + data.length; return this; } insertFormat(start, fmt, data) { this.insert(start, format(fmt, data)); } remove(start, length) { const { _, __ } = pri(this); let str = _.toString(); __.data = [str.substr(0, start), str.substr(start + length)]; __.length = Math.max(0, str.length - length); return _; } toString() { const { _, __ } = pri(this); __.data = [__.data.join("")]; return __.data[0]; } clear() { let ret = this.toString(); const { _, __ } = pri(this); __.data = []; __.length = 0; return ret; } }, showEx: (e) => showEx("", e), tryHandle: function (errcall = __.showEx) { return { apply: function (target, context, proxy) { try { return Reflect.apply(...arguments); } catch (e) { try { errcall(e); } catch (e2) { __.showEx(e); } } }, }; }, start: null, emptyfunc: () => true, sequfunc: async (exp, func, val) => { let isStop = false; while (!isStop && val != undefined) { isStop = true === (await callback2(func, null, val)); val = exp(); } return true; }, disorderfunc: (exp, func, val) => { let data = []; while (val != undefined) { data.push(callback2(func, null, val)); val = exp(); } return Promise.all(data); }, disorderlfunc: (each, call) => { while ( !each.isStop && each.i <= each.data.length - 1 && each.count < each.limit ) { each.count++; callback2(each.func, null, each.data[each.i++]) .then(function (ret) { each.isStop = !!ret; each.count--; __.disorderlfunc(each, call); }) .catch(function (e) { each.error = e; each.isStop = true; each.count--; __.disorderlfunc(each, call); }); } if (each.count <= 0 && (each.isStop || each.i > each.data.length - 1)) call(each.error, true); return true; }, disorderlEach: (data = [], func, limit = 1) => { var each = { data, func, i: 0, count: 0, limit, isStop: false, error: null, }; return callback2((call) => { __.disorderlfunc(each, call); }); }, disorderffunc: (each, call) => { while ( !each.isStop && each.i <= each.data.length - 1 && each.count < each.limit ) { each.count++; const val = each.data[each.i++]; callback2(each.func, null, val.k, val.v) .then(function (ret) { each.isStop = !!ret; each.count--; __.disorderffunc(each, call); }) .catch(function (e) { each.error = e; each.isStop = true; each.count--; __.disorderffunc(each, call); }); } if (each.count <= 0 && (each.isStop || each.i > each.data.length - 1)) call(each.error, true); return true; }, disorderlFor: (data = {}, func, limit = 1) => { var each = { data: [], func, i: 0, count: 0, limit, isStop: false, error: null, }; for (const k in data) { each.data.push({ k, v: data[k] }); } return callback2((call) => { __.disorderffunc(each, call); }); }, disorderwfunc: (each, call) => { while (!each.isStop && each.now != null && each.count < each.limit) { each.count++; var val = each.now; each.now = each.exp(); if (val != null) callback2(each.func, null, val) .then(function (ret) { each.isStop = !!ret; each.count--; __.disorderwfunc(each, call); }) .catch(function (e) { each.error = e; each.isStop = true; each.count--; __.disorderwfunc(each, call); }); } if (each.count <= 0 && (each.isStop || each.now == null)) call(each.error, true); return true; }, disorderlWhile: (exp, func, limit = 1) => { var each = { exp, func, i: 0, count: 0, limit, isStop: false, error: null }; return callback2((call) => { each.now = exp(); __.disorderwfunc(each, call); }); }, sequEach: (data = [], func) => { let i = 0; return __.sequfunc(() => data[i++], func, data[i++]); }, disorderEach: (data = [], func) => { var ret = []; data.forEach((k) => ret.push(callback2(func, null, k))); return Promise.all(ret); }, sequFor: async (obj = {}, func) => { for (const k in obj) { if (true === (await callback2(func, obj, k, obj[k]))) return true; } return true; }, disorderFor: (obj = {}, func) => { let data = []; for (const k in obj) data.push(callback2(func, obj, k, obj[k])); return Promise.all(data); }, index: 0, getTJsonValue: (p, quotation = true) => { switch (typeof p) { //case 'number': //case 'boolean': // return p; case "undefined": return '""'; case "object": switch (p + "") { case "null": return '""'; default: return quotation ? '"' + (p + "").replace(/['"\\]/g, function (v) { return "\\" + v; }) + '"' : "" + p; } default: return quotation ? '"' + (p + "").replace(/['"\\]/g, function (v) { return "\\" + v; }) + '"' : "" + p; } }, clone: (source) => { switch (getType(source)) { case "Object": case "object": return __.merge({}, source); case "array": case "Array": const aim = []; for (const i in source) { aim.push(__.clone(source[i])); } return aim; default: return source; } }, merge: (aim, source) => { //tochange VJ's merge if (!(typeof source == "object" && !isArray(source))) { return aim; } for (const i in source) { if (source[i] !== undefined) { if (!isValid(aim[i])) { aim[i] = __.clone(source[i]); } else { switch (getType(aim[i])) { case "object": case "Object": __.merge(aim[i], source[i]); break; case "Array": //处理数组 let hasmergeIndex = false; for ( let i3 = 0, k = source[i][i3]; i3 < source[i].length; i3++, k = source[i][i3] ) { if (k === null || k === undefined) continue; if (typeof k.mergeIndex == "number") { hasmergeIndex = true; if (aim[i].length < k.mergeIndex + 1) { aim[i].push(k); } else { aim[i][i3] = __.merge(aim[i][i3], k); } } else if (typeof k.moveIndex == "number") { hasmergeIndex = true; aim[i].splice(k.moveIndex, 0, k); } } if (!hasmergeIndex) { aim[i] = __.clone(source[i]); } break; default: aim[i] = source[i]; break; } } } } return aim; }, /** * 从base64 转成 binary */ convert2Binary: (str) => { return Buffer.from(str, "base64").toString("binary"); }, /** * 从string 转成 base64 */ convert2Base64: (str) => { var buffer; if (str instanceof Buffer) { buffer = str; } else { buffer = Buffer.from(str.toString(), "binary"); } return buffer.toString("base64"); }, include: {}, unclude: {}, xmloptions: { attributeNamePrefix: "@_", attrNodeName: "attr", //default is 'false' textNodeName: "#text", ignoreAttributes: true, ignoreNameSpace: false, allowBooleanAttributes: false, parseNodeValue: true, parseAttributeValue: false, trimValues: true, cdataTagName: "__cdata", //default is 'false' cdataPositionChar: "\\c", localeRange: "", //To support non english character in tag/attribute values. parseTrueNumberOnly: false, attrValueProcessor: (a) => he.decode(a, { isAttributeValue: true }), //default is a=>a tagValueProcessor: (a) => he.decode(a), //default is a=>a }, }; { //日期函数处理 Date.prototype.DIC = { y: "FullYear", q: "Month", m: "Month", w: "Date", d: "Date", h: "Hours", n: "Minutes", s: "Seconds", ms: "MilliSeconds", }; Date.prototype.add = function (interval, number) { var d = new Date(this.getTime()); var k = Date.prototype.DIC; var n = { q: 3, w: 7 }; k[interval] ? d["set" + k[interval]]( Math.A(d["get" + k[interval]](), Math.X(n[interval] || 1, number)), ) : (function () { throw new Error("interval参数不是支持的类型:" + toJsonString(k)); })(); return d; }; /* 计算两日期相差的日期年月日等 new Date().diff('h',new Date().add('d',1)); */ Date.prototype.diff = function (interval, objDate2) { const d = this, i = {}, t = d.getTime(), t2 = objDate2.getTime(); i["y"] = objDate2.getFullYear() - d.getFullYear(); i["q"] = i["y"] * 4 + Math.floor(objDate2.getMonth() / 4) - Math.floor(d.getMonth() / 4); i["m"] = i["y"] * 12 + objDate2.getMonth() - d.getMonth(); i["ms"] = objDate2.getTime() - d.getTime(); // i['w'] = Math.floor((t2 + 345600000) / (604800000)) - Math.floor((t + 345600000) / (604800000)); // i['d'] = Math.floor(t2 / 86400000) - Math.floor(t / 86400000); // i['h'] = Math.floor(t2 / 3600000) - Math.floor(t / 3600000); // i['n'] = Math.floor(t2 / 60000) - Math.floor(t / 60000); // i['s'] = Math.floor(t2 / 1000) - Math.floor(t / 1000); i["w"] = Math.floor(Math.D(Math.S(t2, t), 604800000.0)); i["d"] = Math.floor(Math.D(Math.S(t2, t), 86400000.0)); i["h"] = Math.floor(Math.D(Math.S(t2, t), 3600000.0)); i["n"] = Math.floor(Math.D(Math.S(t2, t), 60000.0)); i["s"] = Math.floor(Math.D(Math.S(t2, t), 1000.0)); return i[interval]; }; /* 计算两日期相差的日期年月日等 new Date().diff('h',new Date().add('d',1)); */ Date.prototype.sub = function (interval, objDate2) { return Date.prototype.diff.apply(objDate2, [interval, this]); }; /* 计算两日期相差的日期年月日等 new Date().toString('yyyy-MM-dd'); */ Date.prototype.toString = function (fmt) { const o = { "M+": this.getMonth() + 1, //月份 "d+": this.getDate(), //日 "h+": this.getHours() % 12 == 0 ? 12 : this.getHours() % 12, //小时 "H+": this.getHours(), //小时 "m+": this.getMinutes(), //分 "s+": this.getSeconds(), //秒 "q+": Math.floor((this.getMonth() + 3) / 3), //季度 S: this.getMilliseconds(), //毫秒 }; const week = { 0: "/u65e5", 1: "/u4e00", 2: "/u4e8c", 3: "/u4e09", 4: "/u56db", 5: "/u4e94", 6: "/u516d", }; if (fmt) { } else { fmt = "yyyy/MM/dd HH:mm:ss"; } if (/(y+)/.test(fmt)) { fmt = fmt.replace( RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length), ); } if (/(E+)/.test(fmt)) { fmt = fmt.replace( RegExp.$1, (RegExp.$1.length > 1 ? RegExp.$1.length > 2 ? "/u661f/u671f" : "/u5468" : "") + week[this.getDay() + ""], ); } for (const k in o) { if (new RegExp("(" + k + ")").test(fmt)) { fmt = fmt.replace( RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length), ); } } return fmt; }; //字符串函数扩展 String.prototype.endWith = String.prototype.endsWith; String.prototype.startWith = function (str) { if ( str == null || str == "" || this.length == 0 || str.length > this.length ) return false; if (this.substr(0, str.length) == str) return true; else return false; }; String.prototype.startsWith = String.prototype.startsWith || String.prototype.startWith; String.prototype.eq = function (str = "", isOri) { str = str + ""; return isOri ? this == str : this.toLowerCase() == str.toLowerCase(); }; String.prototype.trim = function (chr) { switch (chr) { case "/": case "\\": case "?": case "[": case "]": case ".": case "*": case "(": case ")": case "{": case "}": case "|": case "^": case "$": case "+": chr = "\\" + chr; break; } return this.replace( isValid(chr) ? new RegExp("(^(" + chr + ")+)|((" + chr + ")+$)", "g") : /(^\s+)|(\s+$)/g, "", ); }; /** * 高精度 加法 */ Math.A = function (...args) { var a = new Decimal(0); args.forEach((v) => (a = a.add(v))); return a.toNumber(); }; /** * 高精度 减法 */ Math.S = function (...args) { var a = new Decimal(args[0]); args.slice(1).forEach((v) => (a = a.sub(v))); return a.toNumber(); }; /** * 高精度 乘法 */ Math.X = function (...args) { var a = new Decimal(1); args.forEach((v) => (a = a.mul(v))); return a.toNumber(); }; /** * 高精度 除法 */ Math.D = function (...args) { var a = new Decimal(args[0]); args.slice(1).forEach((v) => (a = a.div(v))); return a.toNumber(); }; }