123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554 |
- import logger from './logger'; // -----------------检测类型工具函数-----------------
- /**
- * 检测input类型是否为Map
- * @param {*} input 任意类型的输入
- * @returns {Boolean} true->map / false->not a map
- */
- export const isMap = function (input) {
- return getType(input) === 'map';
- };
- /**
- * 检测input类型是否为Set
- * @param {*} input 任意类型的输入
- * @returns {Boolean} true->set / false->not a set
- */
- export const isSet = function (input) {
- return getType(input) === 'set';
- };
- /**
- * 检测input类型是否为File
- * @param {*} input 任意类型的输入
- * @returns {Boolean} true->file / false->not a file
- */
- export const isFile = function (input) {
- return getType(input) === 'file';
- };
- /**
- * 检测input类型是否为number
- * @param {*} input 任意类型的输入
- * @returns {Boolean} true->number / false->not a number
- */
- export const isNumber = function (input) {
- return input !== null && (typeof input === 'number' && !isNaN(input - 0) || typeof input === 'object' && input.constructor === Number);
- };
- /**
- * 检测input类型是否为string
- * @param {*} input 任意类型的输入
- * @returns {Boolean} true->string / false->not a string
- */
- export const isString = function (input) {
- return typeof input === 'string';
- };
- export const isObject = function (input) {
- // null is object, hence the extra check
- return input !== null && typeof input === 'object';
- };
- /**
- * Checks to see if a value is an object and only an object
- * plain object: 没有标准定义,一般认为通过 {} 或者 new Object() 或者 Object.create(null) 方式创建的对象是纯粹对象
- * @param {*} input 任意类型的输入
- * @returns {Boolean} true->an object and only an object
- */
- export const isPlainObject = function (input) {
- // 注意不能使用以下方式判断,因为IE9/IE10下,对象的__proto__是undefined
- // return isObject(input) && input.__proto__ === Object.prototype;
- if (typeof input !== 'object' || input === null) {
- return false;
- }
- const proto = Object.getPrototypeOf(input);
- if (proto === null) {
- // edge case Object.create(null)
- return true;
- }
- let baseProto = proto;
- while (Object.getPrototypeOf(baseProto) !== null) {
- baseProto = Object.getPrototypeOf(baseProto);
- } // 2. 原型链第一个和最后一个比较
- return proto === baseProto;
- };
- /**
- * 检测input类型是否为数组
- * @param {*} input 任意类型的输入
- * @returns {Boolean} true->array / false->not an array
- */
- export const isArray = function (input) {
- if (typeof Array.isArray === 'function') {
- return Array.isArray(input);
- }
- return getType(input) === 'array';
- };
- /**
- * Checks to see if a value is undefined
- * @param {*} input 任意类型的输入
- * @returns {Boolean} true->input value is undefined
- */
- export const isUndefined = function (input) {
- return typeof input === 'undefined';
- };
- const isNativeClassRegex = /^class\s/;
- /**
- * Is ES6+ class
- * @param {*} input 任意类型的输入
- * @returns {Boolean} true->input is ES6+ class
- */
- export const isNativeClass = function (input) {
- return typeof input === 'function' && isNativeClassRegex.test(input.toString());
- };
- /**
- * 检测input类型是否为数组或者object
- * @param {*} input 任意类型的输入
- * @returns {Boolean} true->input is an array or an object
- */
- export const isArrayOrObject = function (input) {
- return isArray(input) || isObject(input);
- };
- /**
- * 检测input类型是否为function
- * @param {*} input 任意类型的输入
- * @returns {Boolean} true->input is a function
- */
- export const isFunction = function (input) {
- return typeof input === 'function';
- };
- export const isBoolean = function (input) {
- return typeof input === 'boolean';
- };
- /**
- * 检测input是否为Error的实例
- * @param {*} input 任意类型的输入
- * @returns {Boolean} true->input is an instance of Error
- */
- export const isInstanceOfError = function (input) {
- return input instanceof Error;
- };
- /**
- * Get the object type string
- * @param {*} input 任意类型的输入
- * @returns {String} the object type string
- */
- export const getType = function (input) {
- return Object.prototype.toString.call(input).match(/^\[object (.*)\]$/)[1].toLowerCase();
- };
- /**
- * ### 用于 request 参数 key 名称的合法性验证。
- * > 不合法的 key 有:
- * - 非 string 类型的 key ;
- * - 非字母和数字开头的 key ;
- * @param {string} key - 参数 key
- * @returns {boolean}
- * - true : 合法;
- * - false: 非法;
- */
- export const isValidRequestKey = function (key) {
- // 非 string 类型的 key
- if (typeof key !== 'string') {
- return false;
- }
- const firstCharactor = key[0]; // 非字母和数字开头的 key
- if (/[^a-zA-Z0-9]/.test(firstCharactor)) {
- return false;
- }
- return true;
- }; // -----------------获取时间工具函数,计算耗时用-----------------
- let baseTime = 0;
- if (!Date.now) {
- Date.now = function now() {
- return new Date().getTime();
- };
- }
- export const TimeUtil = {
- now() {
- if (baseTime === 0) {
- baseTime = Date.now() - 1;
- }
- const diff = Date.now() - baseTime;
- if (diff > 0xffffffff) {
- baseTime += 0xffffffff;
- return Date.now() - baseTime;
- }
- return diff;
- },
- utc() {
- return Math.round(Date.now() / 1000);
- }
- }; // -----------------深度合并工具函数-----------------
- /**
- * 深度 merge 两个对象。merge source to target.
- * @param {Object|Object[]} target 目标对象
- * @param {Object|Object[]} source 来源对象
- * @param {String[]} [keysIgnore] 要忽略的 keys。命中的 key 会在merge时被忽略
- * @param {*[]} [valuesIgnore] 要忽略的 values。命中的 value 会在merge时被忽略
- * @returns {Number} merge的次数(只有key相同value不同的时候才会merge),如果target和source既不是数组也不是object,则返回0
- */
- export const deepMerge = function (target, source, keysIgnore, valuesIgnore) {
- // 1. 非 Array 或 Object 类型则直接 return
- if (!(isArrayOrObject(target) && isArrayOrObject(source))) {
- return 0;
- }
- let mergedCount = 0;
- const keys = Object.keys(source);
- let tmpKey;
- for (let i = 0, len = keys.length; i < len; i++) {
- tmpKey = keys[i];
- if (isUndefined(source[tmpKey]) || keysIgnore && keysIgnore.includes(tmpKey)) {
- continue;
- }
- if (isArrayOrObject(target[tmpKey]) && isArrayOrObject(source[tmpKey])) {
- // 递归merge
- mergedCount += deepMerge(target[tmpKey], source[tmpKey], keysIgnore, valuesIgnore);
- } else {
- if (valuesIgnore && valuesIgnore.includes(source[tmpKey])) {
- continue;
- }
- if (target[tmpKey] !== source[tmpKey]) {
- target[tmpKey] = source[tmpKey];
- mergedCount += 1;
- }
- }
- }
- return mergedCount;
- }; // 简单的深拷贝实现
- export function deepCopy(val) {
- if (Object.prototype.toString.call(val) === '[object Array]' && Object.prototype.toString.call(val) === '[object Object]') {
- return val
- }
- let target = Array.isArray(val) ? [] : {} //数组兼容
- for (var k in val) {
- if (val.hasOwnProperty(k)) {
- if (typeof val[k] === 'object') {
- target[k] = deepCopy(val[k])
- } else {
- target[k] = val[k]
- }
- }
- }
- return target
- }
- /**
- * 序列化Error实例,只序列化Error实例的message和code属性(如果有的话)
- * @param {Error} error Error实例
- * @returns {String} 序列化后的内容
- */
- export const stringifyError = function (error) {
- return JSON.stringify(error, ['message', 'code']);
- };
- /**
- * 返回一个 ISO(ISO 8601 Extended Format)格式的字符串,如"2019-11-15T18:45:06.000+0800",用于记录sso上报时的时间
- * @returns {String}
- */
- export const date2ISOString = function () {
- const date = new Date(); // YYYY-MM-DDTHH:mm:ss.sssZ。时区总是UTC(协调世界时),加一个后缀“Z”标识。
- const tempISOString = date.toISOString(); // 返回协调世界时(UTC)相对于当前时区的时间差值,单位为分钟。
- // 如果本地时区晚于协调世界时,则该差值为正值,如果早于协调世界时则为负值
- const timezoneOffset = date.getTimezoneOffset();
- const currentTimeZoneInHour = timezoneOffset / 60;
- let replaceString = '';
- if (currentTimeZoneInHour < 0) {
- // 东区
- if (currentTimeZoneInHour > -10) {
- replaceString = `+0${Math.abs(currentTimeZoneInHour * 100)}`;
- } else {
- replaceString = `+${Math.abs(currentTimeZoneInHour * 100)}`;
- }
- } else {
- // 西区
- if (currentTimeZoneInHour >= 10) {
- replaceString = `-${currentTimeZoneInHour * 100}`;
- } else {
- replaceString = `-0${currentTimeZoneInHour * 100}`;
- }
- } // 不需要 encodeURIComponent 把 + 转成 %2B,kibana能识别
- return tempISOString.replace('Z', replaceString);
- };
- /**
- * 把map的内容转成字符串,
- * @param {Map} input 字典
- * @returns {String} 字典的内容
- */
- export const map2String = function (input) {
- if (!isMap(input)) {
- return 'not a map!!!';
- }
- let result = '';
- for (const [k, v] of input.entries()) {
- if (!isMap(v)) {
- result += `[k=${k} v=${v}] `;
- } else {
- return `[k=${k} -> ${map2String(v)}`;
- }
- }
- return result;
- };
- /**
- * 获取字符串占用的字节数
- * @param {String} string - 字符串
- * @returns {Number} 字符串的长度
- */
- export const stringSize = function (string) {
- if (string.length === 0) {
- return 0;
- }
- let i = 0;
- let char = '';
- let len = 0;
- let sizeStep = 1;
- const charSet = function () {
- if (typeof document !== 'undefined' && typeof document.characterSet !== 'undefined') {
- return document.characterSet;
- }
- return 'UTF-8';
- }();
- while (typeof string[i] !== 'undefined') {
- char = string[i++];
- if (char.charCodeAt[i] <= 255) {
- sizeStep = 1;
- } else {
- sizeStep = charSet === 'UTF-8' >= 0 ? 3 : 2;
- }
- len += sizeStep;
- }
- return len;
- };
- /**
- * 用于生成随机整数
- * @param {Number} level - 整数的级别 例如: 99, 999 , 9999 等
- * @returns {Number} 随机数字
- */
- export const randomInt = function (level) {
- const lv = level || 99999999;
- return Math.round(Math.random() * lv);
- };
- const CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
- const CHARS_LENGTH = CHARS.length;
- /**
- * 获取[0,9],[a-z],[A,Z]拼成的随机字符串,长度32
- * @returns {String} 长度为32的随机字符串
- */
- export const randomString = function () {
- let result = '';
- for (let i = 32; i > 0; --i) {
- result += CHARS[Math.floor(Math.random() * CHARS_LENGTH)];
- }
- return result;
- }; // 判断传入的枚举值是否有效
- export const isValidType = function (obj, type) {
- for (const k in obj) {
- if (obj[k] === type) {
- return true;
- }
- }
- return false;
- };
- const AIIList = {};
- export const autoincrementIndex = function (key) {
- if (!key) {
- logger.error('autoincrementIndex(string: key) need key parameter');
- return false;
- }
- if (typeof AIIList[key] === 'undefined') {
- const dateInstance = new Date();
- let hoursString = `3${dateInstance.getHours()}`.slice(-2); // 小时数,用3占位,因为一天中不会出现30小时
- let minuteString = `0${dateInstance.getMinutes()}`.slice(-2);
- let secondString = `0${dateInstance.getSeconds()}`.slice(-2);
- AIIList[key] = parseInt([hoursString, minuteString, secondString, '0001'].join(''));
- hoursString = null;
- minuteString = null;
- secondString = null;
- logger.warn(`utils.autoincrementIndex() create new sequence : ${key} = ${AIIList[key]}`);
- }
- return AIIList[key]++;
- }; // 统一用HTTPS
- export const uniformHTTPS = function (url) {
- if (url.indexOf('http://') === -1 || url.indexOf('https://') === -1) {
- return `https://${url}`;
- }
- return url.replace(/https|http/, 'https');
- };
- /**
- * 使用转JSON方式克隆一个对象
- * @param {Object} data 要克隆的对象
- * @returns {Object} 克隆后的对象
- */
- export const cloneBaseOnJSON = function (data) {
- try {
- return JSON.parse(JSON.stringify(data));
- } catch (error) {
- logger.error('cloneBaseOnJSON Error: ', error);
- return data;
- }
- };
- /**
- * 深度克隆
- * @param {Object} data 要克隆的对象
- * @returns {Object} 克隆后的对象
- */
- export const clone = function (data) {
- if (Object.getOwnPropertyNames(data).length === 0) {
- return Object.create(null);
- }
- const newObject = Array.isArray(data) ? [] : Object.create(null);
- let type = ''; // eslint-disable-next-line guard-for-in
- for (const key in data) {
- // null 是一个特殊的对象,优先处理掉
- if (data[key] === null) {
- newObject[key] = null;
- continue;
- } // undefined 也优先处理掉
- if (data[key] === undefined) {
- newObject[key] = undefined;
- continue;
- }
- type = typeof data[key];
- if (['string', 'number', 'function', 'boolean'].indexOf(type) >= 0) {
- newObject[key] = data[key];
- continue;
- } // 只剩对象,递归
- newObject[key] = clone(data[key]);
- }
- return newObject;
- };
- /**
- * 更新自定义字段,如资料自定义字段,群组自定义字段,群成员自定义字段
- * @param {Object[]} target 待更新的自定义字段数组 [{key,value}, {key,value}, ...]
- * @param {Object[]} source 最新的自定义字段数组 [{key,value}, {key,value}, ...]
- */
- export function updateCustomField(target, source) {
- if (!isArray(target) || !isArray(source)) {
- logger.warn('updateCustomField target 或 source 不是数组,忽略此次更新。');
- return;
- }
- source.forEach(({
- key,
- value
- }) => {
- const customField = target.find(item => item.key === key);
- if (customField) {
- customField.value = value;
- } else {
- target.push({
- key,
- value
- });
- }
- });
- }
- /**
- * 类似 lodash.mapKeys 功能,并具备过滤 keys 的功能
- * @export
- * @param {*} obj
- * @param {*} iteratee
- */
- export function filterMapKeys(obj, iteratee) {
- const newObj = Object.create(null);
- Object.keys(obj).forEach(key => {
- const nextKey = iteratee(obj[key], key); // 回调返回 false 则过滤 key
- if (nextKey) {
- newObj[nextKey] = obj[key];
- }
- });
- return newObj;
- } // -----------------类lodash.mapKeys函数-----------------
- export function mapKeys(obj, iteratee) {
- const newObj = {};
- Object.keys(obj).forEach(key => {
- newObj[iteratee(obj[key], key)] = obj[key];
- });
- return newObj;
- } // -----------------类lodash.mapValues函数-----------------
- export function mapValues(obj, iteratee) {
- const newObj = {};
- Object.keys(obj).forEach(key => {
- newObj[key] = iteratee(obj[key], key);
- });
- return newObj;
- }
|