WhiteSevsUtils

一个好用的工具类

Version vom 22.03.2023. Aktuellste Version

Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greatest.deepsurf.us/scripts/455186/1164713/WhiteSevsUtils.js

/**
 * @description	 自己常用的工具类定义
 * @copyright  GPL-3.0-only
 * @author  WhiteSevs
 * @version  1.6
 **/
(function (Utils) {
  /**
   * @description JSON数据从源端替换到目标端中,如果目标端存在该数据则替换,不添加,返回结果为目标端替换完毕的结果
   * @param {object} target	目标端
   * @param {object} source	源端
   * @example
   * 	Utils.assignJSON(
   * 	{
   * 	 "1":1,
   * 	 "2":{
   * 		 "3":3
   * 	 }
   * 	},
   * 	{
   * 	 "2":{
   * 		 "3":4
   * 	 }
   * 	}
   * 	);
   * @return
   * \{
   * 	"1":1,
   * 	"2":{
   * 		"3":4
   * 	}
   * }
   **/
  Utils.assignJSON = function (target, source) {
    for (var target_key in target) {
      if (typeof source[target_key] !== "undefined") {
        if (
          typeof source[target_key] === "object" &&
          !(source[target_key] instanceof Node)
        ) {
          target[target_key] = this.assignJSON(
            target[target_key],
            source[target_key]
          );
        } else {
          target[target_key] = source[target_key];
        }
      }
    }
    return target;
  };

  /**
   * @description 同步执行,等待数组内部执行完毕,注意,该内部不能同步
   * @param {Object} arrayData	需要遍历的数组
   * @param {Function} handleDataFunction	对该数组进行操作的函数,该函数的参数为数组格式的参数,[数组下标,数组项]
   * @example
   * 	await Utils.asyncArrayForEach([1,2,3],xxxFunction);
   **/
  Utils.asyncArrayForEach = function (arrayData, handleDataFunction) {
    var _this = this;
    if (typeof arrayData !== "object") {
      throw "Utils.asyncArrayForEach 参数 arrayData 必须为 object 类型";
    }
    if (
      typeof handleDataFunction !== "function" &&
      typeof handleDataFunction !== "string"
    ) {
      throw "Utils.asyncArrayForEach 参数 handleDataFunction 必须为 function|string 类型";
    }
    return Promise.all(
      Array.from(arrayData).map(async (item, index) => {
        await _this.tryCatch(handleDataFunction, [index, item]);
      })
    );
  };

  /**
   * @description 同步File对象转base64
   * @param {Object} fileObj	需要转换的File对象
   * @return {String} base64格式的数据
   * @example
   * 	await Utils.asyncFileToBase64(object);
   * @return
   * 	data:image/jpeg:base64/,xxxxxx
   **/
  Utils.asyncFileToBase64 = function (fileObj) {
    var reader = new FileReader();
    reader.readAsDataURL(fileObj);
    return new Promise((resolve) => {
      reader.onload = function (e) {
        resolve(e.target.result);
      };
    });
  };

  /**
   * @description 同步执行延时函数
   * @param {Object|String} fnStr	需要延时的函数或字符串格式的函数
   * @param {Number} delayTime	需要检测的元素
   * @return {?undefined}	返回自定义类型数据或者无返回
   * @example
   * 	await Utils.asyncSetTimeOut(xxxFunction, 2500);
   * @return
   * 	xxx
   * @example
   * 	await Utils.asyncSetTimeOut("()=>{console.log(12345)}", 2500);
   * @return
   * 	undefined
   **/
  Utils.asyncSetTimeOut = function (fnStr, delayTime) {
    var _this_ = this;
    if (typeof fnStr !== "function" && typeof fnStr !== "string") {
      throw "Utils.asyncSetTimeOut 参数 fnStr 必须为 function|string 类型";
    }
    if (typeof delayTime !== "number") {
      throw "Utils.asyncSetTimeOut 参数 delayTime 必须为 number 类型";
    }
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve(_this_.tryCatch(fnStr));
      }, delayTime);
    });
  };

  /**
   * @description base64转blob
   * @param {String} dataurl	base64的数据
   * @return {String} blob的链接
   * @example
   * 	Utils.base64ToBlob("data:image/jpeg;base64,.....");
   * @return
   * 	blob://xxxxxxx
   **/
  Utils.base64ToBlob = function (dataurl) {
    if (typeof dataurl !== "string") {
      throw "Utils.base64ToBlob 参数 dataurl 必须为 string 类型";
    }
    var arr = dataurl.split(","),
      mime = arr[0].match(/:(.*?);/)[1],
      bstr = atob(arr[1]),
      n = bstr.length,
      u8arr = new Uint8Array(n);
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n);
    }
    return new Blob([u8arr], {
      type: mime,
    });
  };

  /**
   * @description base64转File对象
   * @param {String} dataurl	base64的数据
   * @return {String}	blob的链接
   * @example
   * 	Utils.base64ToFile("data:image/jpeg;base64,.....");
   * @return
   * 	object
   **/
  Utils.base64ToFile = function (dataurl, fileName) {
    if (typeof dataurl !== "string") {
      throw "Utils.base64ToFile 参数 dataurl 必须为 string 类型";
    }
    if (typeof fileName !== "string") {
      throw "Utils.base64ToFile 参数 fileName 必须为 string 类型";
    }
    var arr = dataurl.split(","),
      mime = arr[0].match(/:(.*?);/)[1],
      bstr = atob(arr[1]),
      n = bstr.length,
      u8arr = new Uint8Array(n);
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n);
    }
    return new File([u8arr], fileName, {
      type: mime,
    });
  };

  /**
   * @description blob转File对象
   * @param {String} theBlob	需要转换的blob的链接
   * @param {String} fileName	转换成的File对象的文件名称
   * @return {Object} File对象
   * @example
   * 	Utils.blobToFile("blob://xxxxx");
   * @return
   * 	object
   **/
  Utils.blobToFile = function (theBlob, fileName) {
    if (typeof theBlob !== "string") {
      throw "Utils.blobToFile 参数 theBlob 必须为 string 类型";
    }
    if (typeof fileName !== "string") {
      throw "Utils.blobToFile 参数 fileName 必须为 string 类型";
    }
    theBlob.lastModifiedDate = new Date();
    theBlob.name = fileName;
    return theBlob;
  };

  /**
   * @description 【手机】检测点击的地方是否在该元素区域内
   * @param {Object} obj	需要检测的元素
   * @return {Boolean}	返回true或false
   * @example
   * 	Utils.checkUserClickInNode(document.querySelector(".xxx"));
   * @return
   * 	false
   **/
  Utils.checkUserClickInNode = function (targetNode) {
    if (!(targetNode instanceof Node)) {
      throw "Utils.checkUserClickInNode 参数 targetNode 必须为 Node 类型";
    }
    var mouseClickPosX = Number(window.event.clientX); /* 鼠标相对屏幕横坐标 */
    var mouseClickPosY = Number(window.event.clientY); /* 鼠标相对屏幕纵坐标 */
    var elementPosXLeft = Number(
      targetNode.getBoundingClientRect().left
    ); /* 要检测的元素的相对屏幕的横坐标最左边 */
    var elementPosXRight = Number(
      targetNode.getBoundingClientRect().right
    ); /* 要检测的元素的相对屏幕的横坐标最右边 */
    var elementPosYTop = Number(
      targetNode.getBoundingClientRect().top
    ); /* 要检测的元素的相对屏幕的纵坐标最上边 */
    var elementPosYBottom = Number(
      targetNode.getBoundingClientRect().bottom
    ); /* 要检测的元素的相对屏幕的纵坐标最下边 */
    if (
      mouseClickPosX >= elementPosXLeft &&
      mouseClickPosX <= elementPosXRight &&
      mouseClickPosY >= elementPosYTop &&
      mouseClickPosY <= elementPosYBottom
    ) {
      return true;
    } else if (
      targetNode.innerHTML.indexOf(window.event.target.innerHTML) !== -1
    ) {
      /* 这种情况是应对在界面中隐藏的元素,getBoundingClientRect获取的都是0 */
      return true;
    } else {
      return false;
    }
  };

  /**
   * @description 删除某个父元素,父元素可能在上层或上上层或上上上层...
   * @param {Object} target	当前元素
   * @param {Object} handleFunc	判断是否满足父元素,参数为当前处理的父元素,满足返回true,否则false
   * @return {Boolean} 如果找到就删除返回true,如果未删除返回false
   * @example
   * 	Utils.deleteParentNode(
   * 		document.querySelector(".xxx"),(node)=>{
   * 			return node.id="xxx" ? true:false
   * 		}
   * 	);
   * @return
   * 	true
   **/
  Utils.deleteParentNode = function (target, handleFunc) {
    if (target == null) {
      throw "Utils.deleteParentNode 参数 target 不能为 null";
    }
    if (!(target instanceof Node)) {
      throw "Utils.deleteParentNode 参数 target 必须为 Node 类型";
    }
    if (typeof handleFunc !== "function") {
      throw "Utils.deleteParentNode 参数 handleFunc 必须为 function 类型";
    }
    var result = false;
    var parentNode = target.parentElement;
    while (!0) {
      if (parentNode == null) {
        return;
      }
      var handleStatus = handleFunc(parentNode);
      if (handleStatus) {
        result = true;
        parentNode.remove();
        break;
      }
      parentNode = parentNode.parentElement;
    }
    return result;
  };

  /**
   * @description 自定义字典,用于new
   * @example
   *let dictionary = new Utils.Dictionary();
   *dictionary.set("xxx","xxx");
   *dictionary.get("xxx");
   *dictionary.has("xxx");
   **/
  Utils.Dictionary = function () {
    this.items = {};
    this.has = function (key) {
      /* 检查是否有某一个键 */
      return this.items.hasOwnProperty(key);
    };
    this.set = function (key, val = "") {
      /* 为字典添加某一个值 */
      if (key === undefined) {
        throw "Utils.Dictionary().set 参数 key 不能为空";
      }
      this.items[key] = val;
    };
    this.delete = function (key) {
      /* 删除某一个键 */
      if (this.has(key)) {
        delete this.items[key];
        return true;
      }
      return false;
    };
    this.get = function (key) {
      /* 查找某一特定项 */
      return this.has(key) ? this.items[key] : undefined;
    };
    this.values = function () {
      /* 返回字典中的所有值 */
      var resultList = [];
      for (var prop in this.items) {
        if (this.has(prop)) {
          resultList.push(this.items[prop]);
        }
      }
      return resultList;
    };
    this.clear = function () {
      /* 清空字典 */
      this.items = {};
    };
    this.size = function () {
      /* 获取字典的长度 */
      return Object.keys(this.items).length;
    };
    this.keys = function () {
      /* 获取字典所有的键 */
      return Object.keys(this.items);
    };
    this.getItems = function () {
      /* 返回字典本身 */
      return this.items;
    };
  };

  /**
   * @description 下载base64格式的数据
   * @param {String} base64Content	需要转换的base64数据
   * @param {String} fileName	需要保存的文件名
   * @example
   * 	Utils.downloadBase64("data:image/jpeg:base64/,xxxxxx");
   **/
  Utils.downloadBase64 = function (base64Content, fileName) {
    if (typeof base64Content !== "string") {
      throw "Utils.downloadBase64 参数 base64Content 必须为 string 类型";
    }
    if (typeof fileName !== "string") {
      throw "Utils.downloadBase64 参数 fileName 必须为 string 类型";
    }
    var aLink = document.createElement("a");
    var blob = this.base64ToBlob(base64Content);
    var evt = document.createEvent("HTMLEvents");
    evt.initEvent(
      "click",
      true,
      true
    ); /* initEvent 不加后两个参数在FF下会报错  事件类型,是否冒泡,是否阻止浏览器的默认行为 */
    aLink.download = fileName;
    aLink.href = URL.createObjectURL(blob);
    aLink.click();
  };

  /**
   * @description 获取某个父元素,父元素可能在上层或上上层或上上上层...
   * @param {Object} target	当前元素
   * @param {Object} handleFunc	判断是否满足父元素,参数为当前处理的父元素,满足返回true,否则false
   * @return {Boolean}	如果找到返回满足要求的父元素,如果未找到返回null
   * @example
   * 	Utils.findParentNode(document.querySelector(".xxx"),(node)=>{return node.id==="xxx"});
   * @return
   * 	Node;
   **/
  Utils.findParentNode = function (target, handleFunc) {
    if (target == null) {
      throw "Utils.findParentNode 参数 target 不能为null";
    }
    if (!(target instanceof Node)) {
      throw "Utils.findParentNode 参数 target 必须为 Node 类型";
    }
    if (typeof handleFunc !== "function") {
      throw "Utils.findParentNode 参数 handleFunc 必须为 function 类型";
    }
    let result = null;
    let parentNode = target.parentElement;
    while (!0) {
      if (parentNode == null) {
        return;
      }
      let handleStatus = handleFunc(parentNode);
      if (handleStatus) {
        result = parentNode;
        break;
      }
      parentNode = parentNode.parentElement;
    }
    return result;
  };

  /**
   * @description 定位网页中字符串位置并标亮,注意,该字符串必须是能在网页中看得到的,隐藏的是无法定位的
   * @param {String} str	需要寻找的字符串
   * @param {Boolean} caseSensitive	区分大小写
   * @return {Boolean}
   * + 找到	===> true
   * + 找不到 ===> false
   * @example
   * 	Utils.findWindowPageString("xxxxx");
   * @return
   * 	true
   **/
  Utils.findWindowPageString = function (str = "", caseSensitive = false) {
    var TRange = null;
    var strFound;
    if (window.find) {
      /* CODE FOR BROWSERS THAT SUPPORT window.find */
      strFound = self.find(str, caseSensitive, true, true, false);
      if (strFound && self.getSelection && !self.getSelection().anchorNode) {
        strFound = self.find(str, caseSensitive, true, true, false);
      }
      if (!strFound) {
        strFound = self.find(str, 0, 1);
        while (self.find(str, 0, 1)) continue;
      }
    } else if (navigator.appName.indexOf("Microsoft") != -1) {
      /* EXPLORER-SPECIFIC CODE */
      if (TRange != null) {
        TRange.collapse(false);
        strFound = TRange.findText(str);
        if (strFound) TRange.select();
      }
      if (TRange == null || strFound == 0) {
        TRange = self.document.body.createTextRange();
        strFound = TRange.findText(str);
        if (strFound) TRange.select();
      }
    } else if (navigator.appName == "Opera") {
      alert("Opera browsers not supported, sorry...");
      return;
    }
    return strFound ? true : false;
  };

  /**
   * @description 字符串格式的时间转时间戳
   * @param {String} str	字符串格式的时间,例如:
   * + 2022-11-21 00:00:00
   * + 00:00:00
   * @return {Number}
   * 	返回时间戳
   * @example
   * 	Utils.formatTextToTimeStamp("2022-11-21 00:00:00");
   * @return
   * 	1668960000000
   **/
  Utils.formatTextToTimeStamp = function (text) {
    /* 把字符串格式的时间(完整,包括日期和时间)格式化成时间戳 */
    if (typeof text !== "string") {
      throw "Utils.formatTextToTimeStamp 参数 text 必须为 string 类型";
    }
    if (text.length === 8) {
      /* 参数只有时间 */
      var today = new Date();
      text =
        today.getFullYear() +
        "-" +
        (today.getMonth() + 1) +
        "-" +
        today.getDate() +
        " " +
        text;
    }
    text = text.substring(0, 19);
    text = text.replace(/-/g, "/");
    var timestamp = new Date(text).getTime();
    return timestamp;
  };

  /**
   * @description 格式化byte为KB、MB、GB、TB、PB、EB、ZB、YB、BB、NB、DB
   * @param {Number} bitSize	字节
   * @param {Boolean} addType	是否添加单位,默认添加
   * @return {String|Number}	添加单位就是字符串,否则为float类型,保留两位
   * @example
   * 	Utils.formatByteToSize("812304");
   * @return
   * 	793.27KB
   **/
  Utils.formatByteToSize = function (byteSize, addType = true) {
    /* B字节转KB、MB、GB */
    byteSize = parseInt(byteSize);
    if (isNaN(byteSize)) {
      throw "Utils.formatByteToSize 参数 byteSize 格式不正确";
    }
    var result = 0;
    var resultType = "KB";
    var sizeData = {};
    sizeData.KB = 1024;
    sizeData.MB = sizeData.KB * sizeData.KB;
    sizeData.GB = sizeData.MB * sizeData.KB;
    sizeData.TB = sizeData.GB * sizeData.KB;
    sizeData.PB = sizeData.TB * sizeData.KB;
    sizeData.EB = sizeData.PB * sizeData.KB;
    sizeData.ZB = sizeData.EB * sizeData.KB;
    sizeData.YB = sizeData.ZB * sizeData.KB;
    sizeData.BB = sizeData.YB * sizeData.KB;
    sizeData.NB = sizeData.BB * sizeData.KB;
    sizeData.DB = sizeData.NB * sizeData.KB;
    for (key in sizeData) {
      result = byteSize / sizeData[key];
      resultType = key;
      if (sizeData.KB >= result) {
        break;
      }
    }
    result = result.toFixed(2);
    result = addType ? result + resultType.toString() : parseFloat(result);
    return result;
  };

  /**
   * @description 获取数组的随机值
   * @param {String} array	数组数据
   * @return {String}	返回数组的随机值
   * @example
   * 	Utils.getArrayRandValue(["Utils","getArrayRandValue"]);
   * @return
   * 	getArrayRandValue
   **/
  Utils.getArrayRandValue = function (_array_) {
    return _array_[Math.floor(Math.random() * _array_.length)];
  };

  /**
   * @description 获取格式化后的Date类型时间
   * @param {String} text	需要格式化的字符串或者时间戳
   * @param {String} types	格式化成的显示类型
   * + yyyy 年
   * + MM 月
   * + dd 天
   * + HH 时 (24小时制)
   * + hh 时 (12小时制)
   * + mm 分
   * + ss 秒
   * @return {String}	返回格式化后的时间
   * @example
   * 	Utils.getFormatTime("HH:mm:ss","2022-08-21 23:59:00");
   * @return
   * 	23:59:00
   * @example
   * 	Utils.getFormatTime("HH:mm:ss",1899187424988);
   * @return
   * 	15:10:13
   **/
  Utils.getFormatTime = function (types = "yyyy-MM-dd HH:mm:ss", text) {
    if (typeof types !== "string") {
      throw "Utils.getFormatTime 参数 types 必须为 string 类型";
    }
    if (text != null && typeof text !== "string" && typeof text !== "number") {
      throw "Utils.getFormatTime 参数 text 必须为 string|number 类型";
    }
    var time = text == null ? new Date() : new Date(text);
    function _checkTime_(i) {
      /* 校验时间补0 */
      if (i < 10) return "0" + i;
      return i;
    }

    function _timeSystemChange_(_hour_) {
      /* 时间制修改 24小时制转12小时制 */
      return _hour_ > 12 ? _hour_ - 12 : _hour_;
    }

    var timeRegexp = {
      yyyy: time.getFullYear(),
      /* 年 */
      MM: _checkTime_(time.getMonth() + 1),
      /* 月 */
      dd: _checkTime_(time.getDate()),
      /* 日 */
      HH: _checkTime_(time.getHours()),
      /* 时 (24小时制) */
      hh: _checkTime_(_timeSystemChange_(time.getHours())),
      /* 时 (12小时制) */
      mm: _checkTime_(time.getMinutes()),
      /* 分 */
      ss: _checkTime_(time.getSeconds()),
      /* 秒 */
    };
    Object.keys(timeRegexp).forEach(function (key) {
      var replaecRegexp = new RegExp(key, "g");
      types = types.replace(replaecRegexp, timeRegexp[key]);
    });
    return types;
  };

  /**
   * @description 获取页面中最大的z-index
   * @return {String}	User-Agent
   * @example
   * 	Utils.getRandomPCUA();
   * @return
   * 	Mozilla/5.0....
   **/
  Utils.getMaxZIndex = function () {
    let arr = [...document.all].map(
      (e) => +window.getComputedStyle(e).zIndex || 0
    );
    return arr.length ? Math.max(...arr) + 1 : 0;
  };

  /**
   * @description 获取随机的安卓手机User-Agent(25)个
   * @return {String}	User-Agent
   * @example
   * 	Utils.getRandomAndroidUA();
   * @return
   * 	Mozilla/5.0 ....
   **/
  Utils.getRandomAndroidUA = function () {
    const ANDROID_UA = [
      "Mozilla/5.0 (Linux; Android 12; LDN-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.3538.80 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 12; RNE-L03) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.3538.80 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 12; ASUS_X00ID Build/NMF26F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.3497.100 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 12; WAS-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.3538.80 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 12; PRA-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.3538.80 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 12; MYA-L03) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.3538.64 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 12; PBEM00 Build/PKQ1.190519.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/89.3904.62 XWEB/2891 MMWEBSDK/200901 Mobile Safari/537.36 MMWEBID/4773 MicroMessenger/12.19.1760(0x28901335) Process/toolsmp WeChat/arm64 NetType/4G Language/zh_CN ABI/arm64",
      "Mozilla/5.0 (Linux; Android 11; M2003J15SC Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/89.0.4389.72 MQQBrowser/6.2 TBS/046011 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 11; Moto G Play) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.3538.64 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 11; Moto C Build/NRD90M.063) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.3440.91 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 11; Redmi Note 4 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.3396.87 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 11; HUAWEI VNS-L21 Build/HUAWEIVNS-L21) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.3359.158 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 10; VTR-L09) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.3538.80 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 10; ANG-AN00 Build/HUAWEIANG-AN00; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/89.0.4389.72 MQQBrowser/6.2 TBS/046011 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 10; MI 5X Build/OPM1.171019.019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/89.3904.62 XWEB/2891 MMWEBSDK/200801 Mobile Safari/537.36 MMWEBID/9633 MicroMessenger/12.18.1740(0x2890123B) Process/toolsmp WeChat/arm64 NetType/4G Language/zh_CN ABI/arm64",
      "Mozilla/5.0 (Linux; Android 10; Moto C Plus Build/NRD90M.04.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.3440.91 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 10; TRT-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.3538.64 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 9; Moto G (5) Build/NPPS25.137-93-14; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/89.0.3497.100 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/193.0.0.45.101;]",
      "Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 9.0; ARM; Trident/12; Touch; rv:11.0; IEMobile/11.0; HTC; Windows Phone 8X by HTC) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537",
      "Mozilla/5.0 (Linux; Android 9; Moto G Build/MOB30M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/89.0.2403.119 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 8; MI 6 Build/OPR1.170623.027; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.24 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 8; M2003J15SC Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.4960.1 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 8; M2003J15SC Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4873.1 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 8; M2003J15SC Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4749.1 Mobile Safari/537.36",
      "Mozilla/5.0 (Linux; Android 8; M2003J15SC Build/RP1A.200720.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4600.1 Mobile Safari/537.36",
    ];
    return ANDROID_UA[Math.floor(Math.random() * ANDROID_UA.length)];
  };

  /**
   * @description 获取两个数字区间的随机值
   * @param {Number}	number	数字区间
   * @param {Number}	number2	数字区间
   * @return {Number}	返回两个数字区间的随机值
   * @example
   * 	Utils.getRandomNumber(1,10);
   * @return
   * 	5
   * @example
   * 	Utils.getRandomNumber(10,1);
   * @return
   * 	8
   **/
  Utils.getRandomNumber = function (number, number2) {
    if (typeof number !== "number") {
      throw "Utils.getRandNumber 参数 number 必须为 number 类型";
    }
    if (typeof number2 !== "number") {
      throw "Utils.getRandNumber 参数 number2 必须为 number 类型";
    }
    var leftNumber = number > number2 ? number2 : number;
    var rightNumber = number > number2 ? number : number2;
    return Math.round(Math.random() * (rightNumber - leftNumber)) + leftNumber;
  };

  /**
   * @description 获取随机的电脑端User-Agent(25)个
   * @return {String} - User-Agent
   * @example
   * 	Utils.getRandomPCUA();
   * @return
   * 	Mozilla/5.0....
   **/
  Utils.getRandomPCUA = function () {
    const PC_UA = [
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.5304.107 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.5249.119 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.81 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5089.1 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.24 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.4960.1 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4873.1 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.94 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4749.1 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4687.2 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4658.2 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4635.4 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4600.1 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4573.1 Safari/537.36 Edge/43.0.2442.991",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4510.2 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4461.1 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4412.5 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4388.4 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.2272.101 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.218 Safari/537.36 Edge/13.10586",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4279.4 Safari/537.36 Edge/13.10586",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.2228.0 Safari/537.36",
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.3538.67 Safari/537.36",
    ];
    return PC_UA[Math.floor(Math.random() * PC_UA.length)];
  };

  /**
   * @description 对于GM_cookie的兼容写法,当无法使用GM_cookie时可以使用这个,但是并不完全兼容,有些写不出来且限制了httponly是无法访问的
   * @example
   *	let GM_cookie = new Utils.GM_Cookie();
   *	GM_cookie.list({name:"xxx_cookie_xxx"},function(cookies,error){
   *		if (!error) {
   *			console.log(cookies);
   *			console.log(cookies.value);
   *		} else {
   *			console.error(error);
   *		}
   *	});
   *	GM_cookie.set({name:"xxx_cookie_test_xxx",value:"这是Cookie测试值"},function(error){
   *		if (error) {
   *			console.error(error);
   *		} else {
   *			console.log('Cookie set successfully.');
   *		}
   *	})
   *	GM_cookie.delete({name:"xxx_cookie_test_xxx"},function(error){
   *		if (error) {
   *			console.error(error);
   *		} else {
   *			console.log('Cookie set successfully.');
   *		}
   *	})
   **/
  Utils.GM_Cookie = function () {
    /**
	 * 获取Cookie
	 * @param {Object} details 
		+ url string? 默认为当前的url
		+ domain string? 默认为当前的域名(window.location.hostname)
		+ name string? 需要检索的Cookie的名字
		+ path string? 需要检索的Cookie的路径,默认为"/"
	* @param {Function} callback 
		+ cookies object[] 
		+ error string|undefined
	*/
    this.list = (details = {}, callback = () => {}) => {
      var getReturn = [];
      try {
        var _details_ = {
          url: window.location.href,
          domain: window.location.hostname,
          name: "",
          path: "/",
        };
        details = Utils.assignJSON(_details_, details);
        var cookies = document.cookie.split(";");
        cookies.forEach((item) => {
          let nameRegexp = new RegExp("^" + details.name + "=", "g");
          item = item.trimStart();
          if (item.match(nameRegexp)) {
            getReturn = [
              ...getReturn,
              {
                domain: window.location.hostname,
                expirationDate: undefined,
                hostOnly: true,
                httpOnly: false,
                name: item,
                path: "/",
                sameSite: "unspecified",
                secure: true,
                session: false,
                value: decodeURIComponent(item.replace(nameRegexp, "")),
              },
            ];

            return;
          }
        });
        callback(getReturn, undefined);
      } catch (error) {
        callback(getReturn, error);
      }
    };

    /**
     * 设置Cookie
     * @param {Object} details
     * @param {Function} callback
     */
    this.set = (details = {}, callback = () => {}) => {
      try {
        var _details_ = {
          url: window.location.href,
          name: "",
          value: "",
          domain: window.location.hostname,
          path: "/",
          secure: true,
          httpOnly: false,
          expirationDate: Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 30, // Expires in 30 days
        };
        details = Utils.assignJSON(_details_, details);
        var life = details.expirationDate
          ? details.expirationDate
          : Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 30;
        var cookieStr =
          details.name +
          "=" +
          decodeURIComponent(details.value) +
          ";expires=" +
          new Date(life).toGMTString();
        document.cookie = cookieStr;
        callback();
      } catch (error) {
        callback(error);
      }
    };

    /**
     * 删除Cookie
     * @param {Object} details
     * @param {Function} callback
     */
    this.delete = (details = {}, callback = () => {}) => {
      try {
        var _details_ = {
          url: window.location.href,
          name: "",
          firstPartyDomain: "",
        };
        details = Utils.assignJSON(_details_, details);
        var cookieStr =
          details.name +
          "=" +
          decodeURIComponent("null") +
          ";expires=" +
          new Date().toGMTString();
        document.cookie = cookieStr;
        callback();
      } catch (error) {
        callback(error);
      }
    };
  };

  /**
   * @description 注册油猴菜单
   * @param {Object} data - 传递的菜单数据
   * @param {Boolean} autoReload - 点击该菜单后数据改变后自动重载页面,true为自动重载,false不开启自动重载
   * @example
   * var GM_Menu = new Utils.GM_Menu({
   *    menu_key:{
   *    text:"测试按钮"
   *    enable:true,
   *    showText:(text,enable)=>{
   *      return "[" + (enable ? "√" : "×") + "]" + text;
   *    },
   *    callback:(key,status)=>{
   *      console.log("点击菜单,值修改",status);
   *    }
   *  }
   * });
   *  GM_Menu.get("menu_key"); // 获取某个菜单项的值
   *
   * @exampleResult [√]测试按钮
   **/
  Utils.GM_Menu = function (data = {}, autoReload = false) {
    if (typeof GM_getValue === "undefined") {
      throw "Utils.GM_Menu 请在脚本开头加上 @grant  GM_getValue";
    }
    if (typeof GM_setValue === "undefined") {
      throw "Utils.GM_Menu 请在脚本开头加上 @grant  GM_setValue";
    }
    if (typeof GM_registerMenuCommand === "undefined") {
      throw "Utils.GM_Menu 请在脚本开头加上 @grant  GM_registerMenuCommand";
    }
    if (typeof GM_unregisterMenuCommand === "undefined") {
      throw "Utils.GM_Menu 请在脚本开头加上 @grant  GM_unregisterMenuCommand";
    }
    let _this_ = this;
    let GM_Menu_Id_Data = []; /* 注册的菜单的id */
    let init = function () {
      /* 初始化数据 */
      Object.keys(data).forEach((key) => {
        let value = GM_getValue(key);
        if (value == null) {
          GM_setValue(key, data[key].enable);
          value = GM_getValue(key);
        }
        data[key]["enable"] = value;
      });
    };

    let register = function () {
      /* 注册油猴菜单 */
      Object.keys(data).forEach((key) => {
        let item = data[key];
        let text = item["text"]; /* 文本 */
        let enable = item["enable"]; /* 用户开启的状态 */
        let showText =
          typeof item["showText"] === "function"
            ? item["showText"](text, enable)
            : text; /* 油猴菜单上显示的文本 */
        let callback = item["callback"]; /* 用户点击后的回调 */
        let GM_Menu_Id = null;
        GM_Menu_Id = GM_registerMenuCommand(showText, function () {
          let _enable_ = enable ? false : true;
          GM_setValue(key, _enable_);
          if (typeof callback === "function") {
            callback(key, _enable_);
          }
          if (autoReload) {
            window.location.reload();
          } else {
            _this_.update();
          }
        });
        GM_Menu_Id_Data = [...GM_Menu_Id_Data, GM_Menu_Id];
      });
    };
    this.get = function (key) {
      /* 获取键值开启状态 */
      return data[key]["enable"];
    };
    this.add = function (data) {
      /* 新增菜单 */
      GM_Menu_Id_Data = [...GM_Menu_Id_Data, data];
      init();
      register();
    };
    this.update = function (data) {
      /* 更新菜单 */
      if (data) {
        Object.assign(GM_Menu_Id_Data, data);
      }
      GM_Menu_Id_Data.forEach((_menu_) => {
        GM_unregisterMenuCommand(_menu_);
      });
      init();
      register();
    };
    this.delete = function (key) {
      /* 卸载菜单 */
      GM_unregisterMenuCommand(key);
    };
    init(); /* 初始化数据 */
    register(); /* 注册到油猴菜单中 */
  };

  /**
   * @description 基于Function prototype,能够勾住和释放任何函数
   * [bool]hook:params{
   * 		realFunc[String|must]:用于保存原始函数的函数名称,用于unHook;
   * 		hookFunc[Function|must]:替换的hook函数;
   * 		context[Object|opt]:目标函数所在对象,用于hook非window对象下的函数,如String.protype.slice,carInstance1
   * 		methodName[String|opt]:匿名函数需显式传入目标函数名eg:this.Begin = function(){....};}
   * [bool]unhook:params{
   * 		realFunc[String|must]:用于保存原始函数的函数名称,用于unHook;
   * 		funcName[String|must]:被Hook的函数名称
   * 		context[Object|opt]:目标函数所在对象,用于hook非window对象下的函数,如String.protype.slice,carInstance1}
   * @example
   *	var hook = new Utils.Hooks();
   *	hook.initEnv();
   *	function myFunction(){
   *		console.log("我自己需要执行的函数");
   *	}
   *	function testFunction(){
   *		console.log("正常执行的函数");
   *	}
   *	testFunction.hook(testFunction,myFunction,window)
   *
   **/
  Utils.Hooks = function () {
    this.initEnv = function () {
      Function.prototype.hook = function (realFunc, hookFunc, context) {
        var _context = null; //函数上下文
        var _funcName = null; //函数名

        _context = context || window;
        _funcName = getFuncName(this);
        _context["realFunc_" + _funcName] = this;

        console.log(window);

        if (
          _context[_funcName].prototype &&
          _context[_funcName].prototype.isHooked
        ) {
          console.log("Already has been hooked,unhook first");
          return false;
        }
        function getFuncName(fn) {
          // 获取函数名
          var strFunc = fn.toString();
          var _regex = /function\s+(\w+)\s*\(/;
          var patten = strFunc.match(_regex);
          if (patten) {
            return patten[1];
          }
          return "";
        }
        try {
          eval(
            "_context[_funcName] = function " +
              _funcName +
              "(){\n" +
              "var args = Array.prototype.slice.call(arguments,0);\n" +
              "var obj = this;\n" +
              "hookFunc.apply(obj,args);\n" +
              "return _context['realFunc_" +
              _funcName +
              "'].apply(obj,args);\n" +
              "};"
          );
          _context[_funcName].prototype.isHooked = true;
          return true;
        } catch (e) {
          console.log("Hook failed,check the params.");
          return false;
        }
      };
      Function.prototype.unhook = function (realFunc, funcName, context) {
        var _context = null;
        var _funcName = null;
        _context = context || window;
        _funcName = funcName;
        if (!_context[_funcName].prototype.isHooked) {
          console.log("No function is hooked on");
          return false;
        }
        _context[_funcName] = _context["realFunc" + _funcName];
        delete _context["realFunc_" + _funcName];
        return true;
      };
    };
    this.cleanEnv = function () {
      if (Function.prototype.hasOwnProperty("hook")) {
        delete Function.prototype.hook;
      }
      if (Function.prototype.hasOwnProperty("unhook")) {
        delete Function.prototype.unhook;
      }
      return true;
    };
  };

  /**
   * @description 浏览器端的indexedDB操作封装
   * @example
   *  let db = new Utils.indexedDB('web_DB', 'nav_text')
   *  let data = {name:'管理员', roleId: 1, type: 1};
   *  db.save('list',data).then((resolve)=>{
   *      console.log(resolve,'存储成功')
   *  })
   *
   *  db.get('list').then((resolve)=>{
   *      console.log(resolve,'查询成功')
   *  })
   *
   *  db.getPaging('list',20,10).then((resolve)=>{
   *      console.log(resolve,'查询分页偏移第20,一共10行成功');
   *  })
   *
   *  db.delete('list').then(resolve=>{
   *      console.log(resolve,'删除成功---->>>>>>name')
   *  })
   *
   *  db.deleteAll().then(resolve=>{
   *      console.log(resolve,'清除数据库---->>>>>>name')
   *  })
   *
   **/
  Utils.indexedDB = function (
    dbName = "default_db",
    storeName = "default_form"
  ) {
    this.dbName = dbName; /* 数据存储名 */
    this.slqVersion =
      "1"; /* websql的版本号,由于ios的问题,版本号的写法不一样 */
    this.dbVersion = 1; /* indexDB的版本号 */
    this.storeName = storeName; /* store----即“表”的名字 */
    this.indexedDB =
      window.indexedDB ||
      window.mozIndexedDB ||
      window.webkitIndexedDB ||
      window.msIndexedDB; /* 监听IndexDB */
    if (!this.indexedDB) {
      alert("很抱歉,您的浏览器不支持indexedDB");
    }
    this.db = {}; /* 缓存数据库,避免同一个页面重复创建和销毁 */
    this.store = null;
    this.errorCode = {
      /* 错误码 */
      success: {
        code: 200,
        msg: "操作成功",
      },
      error: {
        code: 401,
        msg: "操作失败",
      },
      open: { code: 91001, msg: "打开数据库失败" },
      save: { code: 91002, msg: "保存数据失败" },
      get: { code: 91003, msg: "获取数据失败" },
      delete: { code: 91004, msg: "删除数据失败" },
      deleteAll: { code: 91005, msg: "清空数据库失败" },
    };
    /* 创建“表” */
    this.createStore = function (dbName) {
      let txn, store;
      if (this.indexedDB) {
        /* 如果是支持IndexDB的 */
        txn = this.db[dbName].transaction(
          this.storeName,
          "readwrite"
        ); /* IndexDB的读写权限 */
        store = txn.objectStore(this.storeName);
      }
      return store;
    };
    this.open = function (callback, dbName) {
      let that = this;
      /* 打开数据库 */
      if (that.indexedDB) {
        /* 如果支持IndexDB */
        if (!that.db[dbName]) {
          /* 如果缓存中没有,则进行数据库的创建或打开,提高效率 */
          let request = that.indexedDB.open(dbName, that.dbVersion);
          request.onerror = function (e) {
            callback({
              code: that.errorCode.open.code,
              msg: that.errorCode.open.msg,
              error: e,
            });
          };
          request.onsuccess = function (e) {
            if (!that.db[dbName]) {
              that.db[dbName] = e.target.result;
            }
            let store = that.createStore(dbName);
            callback(store);
          };
          request.onupgradeneeded = function (e) {
            that.db[dbName] = e.target.result;
            let store = that.db[dbName].createObjectStore(that.storeName, {
              keyPath: "key",
            });
            store.transaction.oncomplete = function (event) {
              callback(store);
            };
          };
        } else {
          /* 如果缓存中已经打开了数据库,就直接使用 */
          let store = that.createStore(dbName);
          callback(store);
        }
      }
    };
    this.save = function (key, value) {
      /* 保存数据到数据库  key---数据key  value----数据值 */
      let that = this;
      if (that.indexedDB) {
        return new Promise((resolve, reject) => {
          let dbName = that.dbName;
          let inData = {
            key: key,
            value: value,
          };
          that.open(function (result) {
            let error = result.hasOwnProperty("error");
            if (error) {
              resolve(result);
            } else {
              let request = result.put(inData);
              request.onsuccess = function (e) {
                resolve({
                  code: that.errorCode.success.code,
                  msg: that.errorCode.success.msg,
                  success: true,
                }); /* 保存成功有success 字段 */
              };
              request.onerror = function (e) {
                resolve({
                  code: that.errorCode.save.code,
                  msg: that.errorCode.save.msg,
                  error: e,
                });
              };
            }
          }, dbName);
        });
      }
    };
    this.get = function (key) {
      /* 根据key获取值 */
      let that = this;
      return new Promise((resolve, reject) => {
        let dbName = that.dbName;
        if (that.indexedDB) {
          that.open(function (result) {
            let error =
              result.hasOwnProperty(
                "error"
              ); /* 判断返回的数据中是否有error字段 */
            if (error) {
              reject({
                code: that.errorCode.open.get,
                msg: that.errorCode.get.msg,
                error: error,
                result: result,
              });
            } else {
              let request = result.get(key);
              request.onsuccess = function (e) {
                let result = e.target.result;
                let data = result ? result.value : undefined;
                resolve({
                  code: data
                    ? that.errorCode.success.code
                    : that.errorCode.error.code,
                  msg: data
                    ? that.errorCode.success.msg
                    : that.errorCode.error.msg,
                  data: data || [],
                  success: true,
                });
              };
              request.onerror = function (e) {
                reject({
                  code: that.errorCode.get.code,
                  msg: that.errorCode.get.msg,
                  result: result,
                  error: e,
                });
              };
            }
          }, dbName);
        }
      });
    };
    this.regexpGet = function (key) {
      let that = this;
      var list = [];
      return new Promise((resolve, reject) => {
        /* 正则查询 */
        let dbName = that.dbName;
        if (that.indexedDB) {
          that.open(function (result) {
            let error =
              result.hasOwnProperty(
                "error"
              ); /* 判断返回的数据中是否有error字段 */
            if (error) {
              reject({
                code: that.errorCode.open.get,
                msg: that.errorCode.get.msg,
                error: error,
                result: result,
              });
            } else {
              let request = result.getAll();
              request.onsuccess = function (e) {
                let result = e.target.result;
                if (result.length !== 0) {
                  result.forEach((item, index) => {
                    if (item["key"].match(key)) {
                      var concatList = item["value"];
                      concatList["key"] = item["key"];
                      list = [...list, concatList];
                    }
                  });
                }
                resolve({
                  code: that.errorCode.success.code,
                  msg: that.errorCode.success.msg,
                  data: list,
                  success: true,
                });
              };
              request.onerror = function (e) {
                reject({
                  code: that.errorCode.get.code,
                  msg: that.errorCode.get.msg,
                  result: result,
                  error: e,
                });
              };
            }
          }, dbName);
        }
      });
    };
    this.getPaging = function (key, offset = 0, count = 1) {
      /* 查询分页(未完成) */
      let that = this;
      return new Promise((resolve, reject) => {
        that.get(key).then((_resolve_) => {
          if (_resolve_["code"] !== 200) {
            resolve(_resolve_);
          }
          resolve();
        }),
          (_reject_) => {
            reject(_reject_);
          };
      });
    };
    this.delete = function (key) {
      let that = this;
      return new Promise((resolve, reject) => {
        /* 根据key删除某条数据 */
        let dbName = that.dbName;
        if (that.indexedDB) {
          that.open(function (result) {
            let error = result.hasOwnProperty("error");
            if (error) {
              resolve(result);
            } else {
              let request = result.get(key);
              request.onsuccess = function (e) {
                let recode = e.target.result;
                if (recode) {
                  request = result.delete(key);
                }
                resolve({
                  code: recode
                    ? that.errorCode.success.code
                    : that.errorCode.error.code,
                  msg: recode
                    ? that.errorCode.success.msg
                    : that.errorCode.error.msg,
                  success: true,
                });
              };
              request.onerror = function (e) {
                resolve({
                  code: that.errorCode.delete.code,
                  msg: that.errorCode.delete.msg,
                  error: e,
                });
              };
            }
          }, dbName);
        }
      });
    };
    this.deleteAll = function () {
      let that = this;
      return new Promise((resolve, reject) => {
        /* 清空数据库 */
        let dbName = that.dbName;
        if (that.indexedDB) {
          that.open(function (result) {
            let error = result.hasOwnProperty("error");
            if (error) {
              resolve({
                code: that.errorCode.deleteAll.code,
                msg: that.errorCode.deleteAll.msg,
                error: error,
                result: result,
              });
            } else {
              result.clear();
              resolve({
                code: that.errorCode.success.code,
                msg: that.errorCode.success.msg,
                success: true,
              });
            }
          }, dbName);
        }
      });
    };
  };

  /**
   * @description 判断是否是手机访问
   * @return {Boolean} - 返回如果是手机true,否则false
   * @example
   * 	Utils.isPhone();
   * @return true
   **/
  Utils.isPhone = function () {
    return Boolean(/(iPhone|iPad|iPod|iOS|Android)/i.test(navigator.userAgent));
  };

  /**
   * @description 判断对象或数据是否为空
   * @param {Object} _obj_ - 需要判断的变量
   * @example
   * 	Utils.isNull({});
   * @return  true
   * @example
   * 	Utils.isNull([]);
   * @return  true
   **/
  Utils.isNull = function (_obj_) {
    var result = false;
    if (typeof _obj_ === "undefined") {
      result = true;
    } else if (typeof _obj_ === "object") {
      if (Object.keys(_obj_).length === 0) {
        result = true;
      }
    } else if (typeof _obj_ === "number") {
      result = _obj_ === 0 ? true : false;
    }
    return result;
  };

  /**
   * @description JSON内所有的值转为Array数组
   * @param {Object} _json_ JSON数据
   * @return {Object} 返回数组
   * @example
   * 	Utils.jsonAllValueToArray({"Utils":"jsonToArray","return","Array"});
   * @return ['jsonToArray', 'Array']
   **/
  Utils.jsonAllValueToArray = function (_json_) {
    if (typeof _json_ !== "object") {
      throw "Utils.jsonAllValueToArray 参数 _json_ 必须为 object 类型";
    }
    var retArray = [];
    Object.keys(_json_).forEach(function (key) {
      retArray = [...retArray, _json_[key]];
    });
    return retArray;
  };

  /**
   * @description JSON格式的字符串转为JSON对象
   * @param {String} text - JSON格式的字符串
   * @return {Object} - 返回JSON对象
   * @example
   * 	Utils.jsonStrToObject('{"Utils":"jsonStrToObject","return","json"}');
   * @return
   * 	'{"Utils":"jsonStrToObject","return","json"}'
   **/
  Utils.jsonStrToObject = function (text) {
    if (typeof text !== "string") {
      throw "Utils.jsonStrToObject 参数 text 必须为 string 类型";
    }
    return window.eval("(" + text + ")");
  };

  /**
   * @description 监听某个元素键盘按键事件或window全局按键事件
   * @param {Window|Node} listenObj 需要监听的对象,可以是全局Window或者某个元素
   * @param {Function|undefined} callback 自己定义的回调事件,参数1为当前的key,参数2为组合按键,数组类型,包含ctrl、shift、alt和meta(win键或mac的cmd键)
   * @example 
   * Utils.listenKeyPress(window,(keyName,otherKey)=>{
   * 	if(keyName === "Enter"){
   * 		console.log("回车按键")
   * 	}
   * 	if(otherKey.indexOf("ctrl") && keyName === "Enter" ){
   * 		console.log("Ctrl和回车键");
   *    }
   * })
   * @example
   * 字母和数字键的键码值(keyCode)
	按键	键码	按键	键码	按键	键码	按键	键码
	A	65	J	74	S	83	1	49
	B	66	K	75	T	84	2	50
	C	67	L	76	U	85	3	51
	D	68	M	77	V	86	4	52
	E	69	N	78	W	87	5	53
	F	70	O	79	X	88	6	54
	G	71	P	80	Y	89	7	55
	H	72	Q	81	Z	90	8	56
	I	73	R	82	0	48	9	57

	数字键盘上的键的键码值(keyCode)	
	功能键键码值(keyCode)
	按键	键码	按键  	键码	按键	键码	按键	键码
	0	96	8	104	F1	112	F7	118
	1	97	9	105	F2	113	F8	119
	2	98	*	106	F3	114	F9	120
	3	99	+	107	F4	115	F10	121
	4	100	Enter	108	F5	116	F11	122
	5	101	-	109	F6	117	F12	123
	6	102	.	110	 	 	 	 
	7	103	/	111	 	 
	
	控制键键码值(keyCode)
	按键		键码	按键		键码	按键		键码	按键		键码
	BackSpace	8	Esc		27	→		39	-_		189
	Tab		9	Spacebar	32	↓		40	.>		190
	Clear		12	Page Up		33	Insert		45	/?		191
	Enter		13	Page Down	34	Delete		46	`~		192
	Shift		16	End		35	Num Lock	144	[{		219
	Control		17	Home		36	;:		186	\|		220
	Alt		18	←		37	=+		187	]}		221
	Cape Lock	20	↑		38	,<		188	'"		222

	多媒体键码值(keyCode)
	按键		键码
	音量加		175
	音量减		174
	停止		179
	静音		173
	浏览器		172
	邮件		180
	搜索		170
	收藏		171

   *
   **/
  Utils.listenKeyPress = function (listenObj, callback) {
    if (!(listenObj instanceof Window) && !(listenObj instanceof Node)) {
      throw "Utils.listenKeyPress 参数 listenObj 必须为 Window|Node 类型";
    }
    listenObj.addEventListener("keypress", function (event) {
      event = event ? event : window.event;
      let keyName = event.code ? event.code : event.key;
      let otherCodeList = [];
      if (event.ctrlKey) {
        otherCodeList = [...otherCodeList, "ctrl"];
      }
      if (event.altKey) {
        otherCodeList = [...otherCodeList, "alt"];
      }
      if (event.metaKey) {
        otherCodeList = [...otherCodeList, "meta"];
      }
      if (event.shiftKey) {
        otherCodeList = [...otherCodeList, "shift"];
      }
      if (typeof callback === "function") {
        callback(keyName, otherCodeList);
      }
    });
  };

  /**
   * @description 自动锁对象,用于循环判断运行的函数,在循环外new后使用,注意,如果函数内部存在异步操作,需要使用await
   * @param {object} func - 需要执行的函数
   * @param {object|undefined} funcArgs - 需要执行的函数的参数
   * @example var lock = new Utils.lockFunction(xxxx)
   * 					--- 此处是循环内 ---
   *          lock.run();
   *          --- 此处是循环内 ---
   * @example var lock = new Utils.lockFunction(xxxx,true) -- 异步操作
   * 					--- 此处是循环内 ---
   *          await lock.run();
   *          --- 此处是循环内 ---
   **/
  Utils.lockFunction = function (func) {
    this.flag = false;
    this.lock = function () {
      this.flag = true;
    };
    this.unlock = function () {
      this.flag = false;
    };
    this.run = async function () {
      if (this.flag) {
        return;
      }
      this.lock();
      await func(arguments); /* arguments调用 */
      this.unlock();
    };
  };

  /**
   * @description 数组内数据部分字段合并成字符串
   * @example Utils.mergeArrayToString([{"name":"数组内数据部分字段合并成字符串->"},{"name":"mergeToString"}],(item)=>{return item["name"]});
   * @exampleResult 数组内数据部分字段合并成字符串->mergeArrayToString
   **/
  Utils.mergeArrayToString = function (data, handleFunc) {
    if (!(data instanceof Array)) {
      throw "Utils.mergeArrayToString 参数 data 必须为 Array 类型";
    }
    if (typeof handleFunc !== "function") {
      throw "Utils.mergeArrayToString 参数 handleFunc 必须为 Function 类型";
    }
    let content = "";
    data.forEach((item) => {
      content = content + handleFunc(item);
    });
    return content;
  };

  /**
   * @description 监听页面元素改变并处理
   * @param {object|Node} target - 需要监听的元素,如果不存在,可以等待它出现
   * @param {object} observer_config - MutationObserver的配置
   * @example Utils.mutationObserver("div.xxxx",{"fn":(mutations)=>{},"config":{childList:true,attributes:true}});
   * @example Utils.mutationObserver(document.querySelector("div.xxxx"),{"fn":(mutations)=>{},"config":{childList:true,attributes:true}});
   * @example Utils.mutationObserver(document.querySelectorAll("div.xxxx"),{"fn":(mutations)=>{},"config":{childList:true,attributes:true}});
   * @example Utils.mutationObserver($("div.xxxx"),{"fn":(mutations)=>{},"config":{childList:true,attributes:true}});
   **/
  Utils.mutationObserver = function (target, observer_config) {
    if (
      typeof target !== "string" &&
      !(target instanceof Node) &&
      !(target instanceof NodeList) &&
      !(window.jQuery != null && target instanceof jQuery)
    ) {
      throw "Utils.mutationObserver 参数 target 必须为 string|Node|NodeList|jQuery类型";
    }

    var default_obverser_config = {
      /* 监听到元素有反馈,需执行的函数 */
      fn: () => {},
      config: {
        /* 当为 true 时,将会监听以 target 为根节点的整个子树。包括子树中所有节点的属性,而不仅仅是针对 target。默认值为 false */
        subtree: undefined,
        /* 当为 true 时,监听 target 节点中发生的节点的新增与删除(同时,如果 subtree 为 true,会针对整个子树生效)。默认值为 false。 */
        childList: undefined,
        /* 当为 true 时观察所有监听的节点属性值的变化。默认值为 true,当声明了 attributeFilter 或 attributeOldValue,默认值则为 false */
        attributes: undefined,
        /* 一个用于声明哪些属性名会被监听的数组。如果不声明该属性,所有属性的变化都将触发通知 */
        attributeFilter: undefined,
        /* 当为 true 时,记录上一次被监听的节点的属性变化;可查阅 MutationObserver 中的 Monitoring attribute values 了解关于观察属性变化和属性值记录的详情。默认值为 false */
        attributeOldValue: undefined,
        /* 当为 true 时,监听声明的 target 节点上所有字符的变化。默认值为 true,如果声明了 characterDataOldValue,默认值则为 false */
        characterData: undefined,
        /* 当为 true 时,记录前一个被监听的节点中发生的文本变化。默认值为 false */
        characterDataOldValue: undefined,
      },
    };
    observer_config = this.assignJSON(default_obverser_config, observer_config);
    var MutationObserver =
      window.MutationObserver ||
      window.webkitMutationObserver ||
      window.MozMutationObserver;
    var mutationObserver = new MutationObserver(function (mutations) {
      observer_config.fn(mutations);
    });
    if (target instanceof Node) {
      /* 传入的参数是节点元素 */
      mutationObserver.observe(target, observer_config.config);
    } else if (target instanceof NodeList) {
      /* 传入的参数是节点元素数组 */
      target.forEach((item) => {
        mutationObserver.observe(item, observer_config.config);
      });
    } else if (typeof jQuery !== "undefined" && target instanceof jQuery) {
      /* 传入的参数是jQuery对象 */
      target.each((index, item) => {
        mutationObserver.observe(item, observer_config.config);
      });
    } else if (typeof target === "string") {
      /* 传入的target是字符串 */
      this.waitNode(target).then((NodeList) => {
        NodeList.forEach((item) => {
          mutationObserver.observe(item, observer_config.config);
        });
      });
    } else {
      /* 未知 */
      console.error("Utils.mutationObserver 未知参数", arguments);
    }
  };
  /**
   * @description (恢复|释放)该对象内部方法,让它执行(无效|有效)
   * @param {Object} needReleaseObject - 需要操作的对象
   * @param {String} needReleaseName - 需要操作的对象的名字
   * @param {Array} functionNameList - 需要释放的方法,如果为空,默认全部方法
   * @return {Boolean} release - true为释放该对象下的某些方法,false为恢复该对象下的某些方法,默认为true
   * @example Utils.noConflict(console,"console",["log"],true);console.log; // 释放该方法
   * @example Utils.noConflict(console,"console",["log"],false);console.log; //恢复该方法
   * @example Utils.noConflict(console,"console",[],true);console; // 释放所有方法
   * @example Utils.noConflict(console,"console",[],false);console; //恢复所有方法
   **/
  Utils.noConflict = function (
    needReleaseObject,
    needReleaseName,
    functionNameList = [],
    release = true
  ) {
    if (typeof needReleaseObject !== "object") {
      throw "Utils.noConflict 参数 needReleaseObject 必须为 object 类型";
    }
    if (!(functionNameList instanceof Array)) {
      throw "Utils.noConflict 参数 functionName 必须为 Array 类型";
    }
    var needReleaseKey = "__" + needReleaseName;
    function cloneObj(obj) {
      /* 复制对象 */
      var newObj = {};
      if (obj instanceof Array) {
        newObj = [];
      }
      for (var key in obj) {
        var val = obj[key];
        newObj[key] = typeof val === "object" ? cloneObj(val) : val;
      }
      return newObj;
    }
    function releaseAll() {
      /* 释放所有 */
      if (typeof window[needReleaseKey] !== "undefined") {
        /* 已存在 */
        return;
      }
      window[needReleaseKey] = cloneObj(needReleaseObject);
      Object.values(needReleaseObject).forEach((value) => {
        if (typeof value === "function") {
          needReleaseObject[value.name] = () => {};
        }
      });
    }
    function releaseOne() {
      /* 释放单个 */
      Array.from(functionNameList).forEach((item) => {
        Object.values(needReleaseObject).forEach((value) => {
          if (typeof value === "function") {
            if (typeof window[needReleaseKey] === "undefined") {
              window[needReleaseKey] = {};
            }
            if (item === value.name) {
              window[needReleaseKey][value.name] =
                needReleaseObject[value.name];
              needReleaseObject[value.name] = () => {};
            }
          }
        });
      });
    }
    function recoveryAll() {
      /* 恢复所有 */
      if (typeof window[needReleaseKey] === "undefined") {
        /* 未存在 */
        return;
      }
      Object.assign(needReleaseObject, window[needReleaseKey]);
      delete window[needReleaseKey];
    }

    function recoveryOne() {
      /* 恢复单个 */
      if (typeof window[needReleaseKey] === "undefined") {
        /* 未存在 */
        return;
      }
      Array.from(functionNameList).forEach((item) => {
        if (window[needReleaseKey][item]) {
          needReleaseObject[item] = window[needReleaseKey][item];
          delete window[needReleaseKey][item];
          if (Object.keys(window[needReleaseKey]).length === 0) {
            delete window[needReleaseKey];
          }
        }
      });
    }
    if (release) {
      /* 释放 */
      if (functionNameList.length === 0) {
        releaseAll();
      } else {
        /* 对单个进行操作 */
        releaseOne();
      }
    } else {
      /* 恢复 */
      if (functionNameList.length === 0) {
        recoveryAll();
      } else {
        /* 对单个进行操作 */
        recoveryOne();
      }
    }
  };

  /**
   * 将正则匹配到的结果取出最后一个值并转换成int格式
   * @param matchList 正则匹配的列表
   * @param defaultValue 正则匹配的列表为空时,或者正则匹配的列表最后一项不为Int,返回该默认值
   * @example Utils.parseInt(["dadaadada123124","123124"],0);
   * @return 123124
   * @example Utils.parseInt(null,0);
   * @return 0
   * @example Utils.parseInt(["aaaaaa"]);
   * @return 0
   * @example Utils.parseInt(["aaaaaa"],"66");
   * @return 66
   * @example Utils.parseInt(["aaaaaaa"],"aa");
   * @return NaN
   **/
  Utils.parseInt = function (matchList = [], defaultValue = 0) {
    if (matchList == null) {
      return parseInt(defaultValue);
    }
    let parseValue = parseInt(matchList[matchList.length - 1]);
    if (isNaN(parseValue)) {
      parseValue = parseInt(defaultValue);
    }
    return parseValue;
  };
  /**
   * 在canvas元素节点上绘制进度圆圈
   * @param _config_ {Object} 配置信息
   * @example let progress = new Utils.Process({canvasNode:document.querySelector("canvas")});
   * 					progress.draw();
   * **/
  Utils.Progress = function (_config_) {
    this.config = {
      canvasNode: null /* canvas元素节点 */,
      deg: 95 /* 绘制角度 */,
      progress: 0 /* 进度 */,
      lineWidth: 10 /* 绘制的线宽度 */,
      lineBgColor: "#1e637c" /* 绘制的背景颜色 */,
      lineColor: "#25deff",
      textColor: "#000000" /* 文字的颜色 */,
      fontSize: 22 /* 字体大小(px) */,
      circleRadius: 50 /* 圆半径 */,
      draw: () => {} /* 控制绘制 */,
    };
    this.config = Utils.assignJSON(this.config, _config_);
    if (!(this.config.canvasNode instanceof HTMLCanvasElement)) {
      throw "Utils.Progress 参数 canvasNode 必须是 HTMLCanvasElement";
    }
    let ctx = this.config.canvasNode.getContext("2d"); /* 获取画笔 */
    let width = this.config.canvasNode.width; /* 元素宽度 */
    let height = this.config.canvasNode.height; /* 元素高度 */

    /* 清除锯齿 */
    if (window.devicePixelRatio) {
      this.config.canvasNode.style.width = width + "px";
      this.config.canvasNode.style.height = height + "px";
      this.config.canvasNode.height = height * window.devicePixelRatio;
      this.config.canvasNode.width = width * window.devicePixelRatio;
      ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
    }
    /* 设置线宽 */
    ctx.lineWidth = this.config.lineWidth;
    /* 绘制 */
    this.draw = function () {
      let degActive = (this.config.progress * 360) / 100;
      ctx.clearRect(0, 0, width, height); //清除画布
      ctx.beginPath(); //开始绘制底圆
      ctx.arc(width / 2, height / 2, this.config.circleRadius, 1, 8);
      ctx.strokeStyle = this.config.lineBgColor;
      ctx.stroke();
      ctx.beginPath(); //开始绘制动态圆
      ctx.arc(
        width / 2,
        height / 2,
        this.config.circleRadius,
        -Math.PI / 2,
        (degActive * Math.PI) / 180 - Math.PI / 2
      );
      ctx.strokeStyle = this.config.lineColor;
      ctx.stroke();
      let txt = parseInt(this.config.progress) + "%"; //获取百分比
      ctx.font = this.config.fontSize + "px SimHei";
      let w = ctx.measureText(txt).width; //获取文本宽度
      let h = this.config.fontSize / 2;
      ctx.fillStyle = this.config.textColor;
      ctx.fillText(txt, width / 2 - w / 2, height / 2 + h / 2);
    }.bind(this);
  };

  /**
   * @description 复制到剪贴板
   * @param {string|number} text - 需要复制到剪贴板的文本
   * @example Utils.setClip("xxxx");
   **/
  Utils.setClip = function (text) {
    if (typeof text !== "string") {
      return;
    }
    let chipBoardNode = document.createElement("input");
    chipBoardNode.type = "text";
    chipBoardNode.setAttribute("style", "opacity:0;position:absolute;");
    chipBoardNode.id = "whitesevClipBoardInput";
    document.body.append(chipBoardNode);
    let clipBoardInputNode = document.querySelector("#whitesevClipBoardInput");
    clipBoardInputNode.value = text;
    clipBoardInputNode.removeAttribute("disabled");
    clipBoardInputNode.select();
    document.execCommand("copy");
    clipBoardInputNode.remove();
  };
  /**
   * @description 同步延迟xxx毫秒
   * @param {number} delayTime - 需要遍历的数组
   * @return {无返回值}
   * @example await Utils.sleep(2500); - 同步延时2500毫秒
   **/
  Utils.sleep = function (delayTime) {
    if (typeof delayTime !== "number") {
      throw "Utils.sleep 参数 delayTime 必须为 number 类型";
    }
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve();
      }, delayTime);
    });
  };

  /**
   * @description 数组按照内部某个值的大小比对排序,如[{"time":"2022-1-1"},{"time":"2022-2-2"}]
   * @param {string} getPropertyValueFunc - 数组内部项的某个属性的值的方法,参数为这个项
   * @param {boolean} sortByDesc - 排序方式,true倒序(值最大排第一个,如:6、5、4、3...),false为正序(值最小排第一个,如:1、2、3、4...)
   * @return {object} - 返回比较排序完成的数组
   * @example [{"time":"2022-1-1"},{"time":"2022-2-2"}].sort(Utils.sortListByProperty((item)=>{return item["time"]}))
   * @example [{"time":"2022-1-1"},{"time":"2022-2-2"}].sort(Utils.sortListByProperty((item)=>{return item["time"]},false))
   **/
  Utils.sortListByProperty = function (
    getPropertyValueFunc,
    sortByDesc = true
  ) {
    if (typeof getPropertyValueFunc !== "function") {
      throw "Utils.sortListByProperty 参数 getPropertyValueFunc 必须为 function 类型";
    }
    if (typeof sortByDesc !== "boolean") {
      throw "Utils.sortListByProperty 参数 sortByDesc 必须为 boolean 类型";
    }

    return function (after_obj, before_obj) {
      var beforeValue = getPropertyValueFunc(before_obj); /*  前 */
      var afterValue = getPropertyValueFunc(after_obj); /* 后 */
      if (sortByDesc) {
        if (afterValue > beforeValue) {
          return -1;
        } else if (afterValue < beforeValue) {
          return 1;
        } else {
          return 0;
        }
      } else {
        if (afterValue < beforeValue) {
          return -1;
        } else if (afterValue > beforeValue) {
          return 1;
        } else {
          return 0;
        }
      }
    };
  };

  /**
   * 对获取的元素列表进行排序
   * @param {NodeList|jQuery} nodeListCallBack 获取元素列表,可以使用querySelectorAll或者jQuery的遍历
   * @param {Function} valueCallBack 获取当前循环列表中元素的要比较的值
   * @param {Boolean} reverse 元素升序(false)或降序(true),默认-升序
   * @example Utils.sortNodeListByProprety( ()=>{ document.querySelectorAll("table tr")}, (item)=>{return parseInt(item.getAttribute("data-value"));}, false);
   */
  Utils.sortNodeListByProprety = function (
    nodeListCallBack,
    valueCallBack,
    reverse = false
  ) {
    let nodeList = nodeListCallBack();
    let nodeListLength = nodeList.length;
    for (var i = 0; i < nodeListLength - 1; i++) {
      for (var j = 0; j < nodeListLength - 1 - i; j++) {
        let beforeNode = nodeList[j];
        let afterNode = nodeList[j + 1];
        let beforeValue = valueCallBack(beforeNode);
        let afterValue = valueCallBack(afterNode);
        if (
          (reverse == true && beforeValue < afterValue) ||
          (reverse == false && beforeValue > afterValue)
        ) {
          /* 升序/降序 */
          /* 相邻元素两两对比 */
          let temp = beforeNode.nextElementSibling;
          afterNode.after(beforeNode);
          if (temp == null) {
            /* 如果为空,那么是最后一个元素,使用append */
            temp.parentNode.appendChild(afterNode);
          } else {
            /* 不为空,使用before */
            temp.before(afterNode);
          }
          nodeList = nodeListCallBack();
        }
      }
    }
  };
  /**
   * @param {string|function} func - 需要捕获错误的函数或函数格式的字符串
   * @param {object} params - 该函数的参数和捕获到错误的函数的参数,类型为数组Array
   * @param {string|function} errorFunc - 捕获到错误后执行的函数或函数格式的字符串
   * @example Utils.tryCatch("(pam)=>{console.log('this is a function and params is' + pam[0])}",["参数1"],"()=>{console.log('对错误进行处理判断')}");
   * @example Utils.tryCatch((pam)=>{console.log('this is a function and params is' + pam[0])},["参数1"],"()=>{console.log('对错误进行处理判断')}");
   **/
  Utils.tryCatch = function (func, params, errorFunc) {
    /* 捕获错误 */
    if (func == null) {
      throw "Utils.tryCatch 警告: 参数 func 为不存在";
    }
    if (typeof func !== "function" && typeof func !== "string") {
      throw "Utils.tryCatch 参数 func 必须为 Function|String 类型";
    }
    if (
      params != null &&
      typeof params !== "object" &&
      typeof params !== "string"
    ) {
      throw "Utils.tryCatch 参数 params 必须为 object|String 类型";
    }
    if (
      errorFunc != null &&
      typeof errorFunc !== "object" &&
      typeof errorFunc !== "string"
    ) {
      throw "Utils.tryCatch 参数 errorFunc 必须为 Function|String 类型";
    }
    var result = null;
    try {
      result = typeof func === "string" ? window.eval(func) : func(params);
    } catch (error) {
      console.log(
        "%c" + (func?.name ? func?.name : func + "出现错误"),
        "color: #f20000"
      );
      console.log("%c" + ("错误原因:" + error), "color: #f20000");
      console.trace(func);
      result =
        typeof func === "string" ? window.eval(errorFunc) : errorFunc(params);
    } finally {
      return result;
    }
  };
  /**
   * @param {string|function} func - 需要捕获错误的函数或函数格式的字符串
   * @param {object} params - 该函数的参数和捕获到错误的函数的参数,类型为数组Array
   * @param {string|function} errorFunc - 捕获到错误后执行的函数或函数格式的字符串
   * @example Utils.tryCatch("(pam)=>{console.log('this is a function and params is' + pam[0])}",["参数1"],"()=>{console.log('对错误进行处理判断')}");
   * @example Utils.tryCatch((pam)=>{console.log('this is a function and params is' + pam[0])},["参数1"],"()=>{console.log('对错误进行处理判断')}");
   **/
  Utils.tryCatch = function (func, params, errorFunc) {
    /* 捕获错误 */
    if (func == null) {
      throw "Utils.tryCatch 警告: 参数 func 为不存在";
    }
    if (typeof func !== "function" && typeof func !== "string") {
      throw "Utils.tryCatch 参数 func 必须为 Function|String 类型";
    }
    if (
      params != null &&
      typeof params !== "object" &&
      typeof params !== "string"
    ) {
      throw "Utils.tryCatch 参数 params 必须为 object|String 类型";
    }
    if (
      errorFunc != null &&
      typeof errorFunc !== "object" &&
      typeof errorFunc !== "string"
    ) {
      throw "Utils.tryCatch 参数 errorFunc 必须为 Function|String 类型";
    }
    var result = null;
    try {
      result = typeof func === "string" ? window.eval(func) : func(params);
    } catch (error) {
      console.log(
        "%c" + (func?.name ? func?.name : func + "出现错误"),
        "color: #f20000"
      );
      console.log("%c" + ("错误原因:" + error), "color: #f20000");
      console.trace(func);
      result =
        typeof func === "string" ? window.eval(errorFunc) : errorFunc(params);
    } finally {
      return result;
    }
  };
  /**
   * @description 数组去重,去除重复的值
   * @param {object} uniqueArrayData - 需要去重的数组
   * @param {object} compareArrayData - 用来比较的数组
   * @param {function} compareFun - 数组比较方法,如果值相同,去除该数据
   * @return {object} - 返回去重完毕的数组
   * @example Utils.uniqueArray([1,2,3],[1,2],(item,item2)=>{return item===item2 ? true:false});
   * @exampleResult [3]
   * @example Utils.uniqueArray([{"key":1,"value":2},{"key":2}],[{"key":1}],(item,item2)=>{return item["key"] === item2["key"] ? true:false});
   * @exampleResult [{"key": 2}]
   **/
  Utils.uniqueArray = function (
    uniqueArrayData = [],
    compareArrayData = [],
    compareFun
  ) {
    if (typeof compareFun !== "function") {
      throw "Utils.uniqueArray 参数 compareFun 必须为 function 类型";
    }
    return Array.from(uniqueArrayData).filter(
      (item) =>
        !Array.from(compareArrayData).some(function (ele) {
          return compareFun(item, ele);
        })
    );
  };

  /**
   * @description 等待某个对象出现,结果为异步,需要await或者then
   * @param {string} target - 需要寻找的元素,传入字符串格式的元素选择器,如div#xxxx...
   * @param {number} intervalNumMax - 循环查找元素次数
   * @param {number} intervalTime - 循环查找元素间隔时间
   * @return {Array} - 如果找到返回数组形式的Node类型的对象,否则返回空数组
   * @example await Utils.waitNode("div.xxx");
   * @example Utils.waitNode("div#xxx").then((node)=>{xxxx});
   **/
  Utils.waitNode = function (target, intervalNumMax = 90, intervalTime = 300) {
    if (typeof target !== "string") {
      throw "Utils.waitNode 参数 target 必须为 string 类型";
    }
    intervalNumMax = parseInt(intervalNumMax);
    intervalTime = parseInt(intervalTime);
    var intervalNum = 0;
    return new Promise((resolve) => {
      var interval = setInterval(function () {
        if (intervalNum > intervalNumMax) {
          resolve([]);
          clearInterval(interval);
          return;
        }
        let queryTargetNodeList = document.querySelectorAll(target);
        if (queryTargetNodeList.length !== 0) {
          resolve(queryTargetNodeList);
          clearInterval(interval);
          return;
        }
        intervalNum++;
      }, intervalTime);
    });
  };
})((Utils = {}));