前端常用的方法工具

// import {singleFileDownload} from '@/utils/downloads'
import cryptoJs from 'crypto-js'
import {
  Message
} from "element-ui";

/**
 * @description 本地存储包装器
 * @param type不传默认为 localStorage, 传 session 为 sessionStorage
 */
let storage = {
  checkWindow() {
    if (!window) {
      console.warn("[Storage] === Storage can ONLY used in browser.");
      return false;
    }
    return true;
  },
  checkSupport(type) {
    let winFlag = this.checkWindow();
    if (winFlag && window[type]) {
      return true;
    } else {
      console.warn(`[Storage] === ${type} Storage is NOT supported.`);
      return false;
    }
  },
  checkType(type) {
    if (type && type === "session") {
      return "sessionStorage";
    } else {
      return "localStorage";
    }
  },
  setObj(obj, type) {
    Object.keys(obj).forEach((item) => {
      this.set(item, obj[item], type);
    });
  },
  set(key, value, type) {
    let curTime = new Date().getTime();
    let target = this.checkType(type);
    if (this.checkSupport(target)) {
      if (typeof value === "string" || Array.isArray(value)) {
        return window[target].setItem(key, JSON.stringify(value));
      } else {
        let data = Object.assign({}, value, {
          time: curTime,
        });
        return window[target].setItem(key, JSON.stringify(data));
      }
    }
  },
  get(key, type) {
    let target = this.checkType(type);
    if (this.checkSupport(target)) {
      if (
        window &&
        window[target] &&
        window[target][key] &&
        window[target][key] !== "undefined"
      ) {
        let data = window[target][key] || false;
        return data;
      } else {
        return window[target][key];
      }
    }
  },

  removeArr(arr, type) {
    if (Array.isArray(arr) && arr.length) {
      arr.forEach((item) => {
        this.remove(item, type);
      });
    } else {
      console.warn("[Storage] === Params must be an array.");
    }
  },
  remove(key, type) {
    let target = this.checkType(type);
    if (this.checkSupport(target)) {
      if (window[target][key] && window[target][key] !== "undefined") {
        return window[target].removeItem(key);
      }
    }
  },
  clear(type) {
    let target = this.checkType(type);
    window[target].clear();
  },
};

/**
 * [deepClone 对象拷贝]
 * @param  {[Object]} obj [需要被拷贝的对象]
 * @return {[type]}     [description]
 */
let deepClone = function (obj, ...args) {
  let copy;

  if (obj == null || typeof obj !== "object") return obj;
  if (obj instanceof Date) {
    copy = new Date();
    copy.setTime(obj.getTime());
    return copy;
  }

  // Handle Array
  if (obj instanceof Array) {
    copy = [];
    for (let i = 0, len = obj.length; i < len; i++) {
      copy[i] = deepClone(obj[i]);
    }
    return copy;
  }

  // Handle Function
  if (obj instanceof Function) {
    copy = function () {
      return obj.apply(this, args);
    };
    return copy;
  }

  // Handle Object
  if (obj instanceof Object) {
    copy = {};
    for (let attr in obj) {
      if (obj.hasOwnProperty(attr)) copy[attr] = deepClone(obj[attr]);
    }
    return copy;
  }

  throw new Error(
    "Unable to copy obj as type isn't supported " + obj.constructor.name
  );
};

/**
 * [setToken 设置token]
 * @param {[type]} token      [description]
 * @param {[type]} token_type [description]
 */
function setToken(token, token_type) {
  storage.set("token", token);
  storage.set("token_type", token_type);
}

/**
 * [clearToken 清除token]
 * @param {[type]} token [description]
 */
function clearToken(token) {
  storage.remove("token");
  storage.remove("token_type");
}

/**
 * [uniqueArray 数组去重]
 * @param  {[type]} arr [description]
 * @return {[type]}     [description]
 */
function uniqueArray(arr) {
  const set = new Set(arr);
  return [...set];
}

/**
 * [sum 数组求和]
 * @param  {[type]} arr [description]
 * @return {[type]}     [description]
 */
function sum(arr) {
  return arr.reduce(function (prev, curr, idx, arr) {
    return prev + curr;
  });
}

/**
 * [uniqueArrayObject 数组对象去重]
 * @param  {[type]} arr [description]
 * @param  {[type]} key [description]
 * @return {[type]}     [description]
 */
function uniqueArrayObject(arr, key) {
  let obj = {};
  return arr.reduce(function (item, next) {
    obj[next[key]] ? "" : (obj[next[key]] = true && item.push(next));
    return item;
  }, []);
}

/**
 * [getDateFormat 获取当前时间]
 * @param  {String} fmt [yyyy-MM-dd]
 * @return {[type]}     [description]
 * 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,
 * 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
 * 例子:getDateFormat("yyyy-MM-dd hh:mm:ss.S")
 */
function getDateFormat(fmt = "yyyy-MM-dd", day) {
  let date = day || new Date();
  let o = {
    "M+": date.getMonth() + 1, // 月份
    "d+": date.getDate(), // 日
    "h+": date.getHours(), // 小时
    "m+": date.getMinutes(), // 分
    "s+": date.getSeconds(), // 秒
    "q+": Math.floor((date.getMonth() + 3) / 3), // 季度
    S: date.getMilliseconds(), // 毫秒
  };
  if (/(y+)/.test(fmt))
    fmt = fmt.replace(
      RegExp.$1,
      (date.getFullYear() + "").substr(4 - RegExp.$1.length)
    );
  for (let 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;
}

/**
 * [getTimeDistance 获取时间间隔]
 * @param  {[type]} time [description]
 * @return {[type]}      [description]
 */
function getTimeDistance(time) {
  // 支持传入10位或13位毫秒数,如 1587367194536,"1587367194"
  // 支持传入日期格式,如 "2020/4/20 15:31:18"

  if (typeof time == "number" || Number(time) == time) {
    if (String(time).length == 10) {
      time = Number(time) * 1000;
    } else if (String(time).length == 13) {
      time = Number(time);
    } else {
      console.log("时间格式错误");
      return time;
    }
  } else {
    if (
      typeof time == "string" &&
      time.split(" ").length == 2 &&
      time.split(/[- : \/]/).length == 6
    ) {
      time = new Date(time.replace(/\-/g, "/")).getTime();
    } else {
      console.log("时间格式错误");
      return time;
    }
  }

  // 处理之后的time为13位数字格式的毫秒数

  var date_now = new Date();
  var date_time = new Date(time);
  var distance = date_now.getTime() - time;

  var days = parseInt(distance / (1000 * 60 * 60 * 24));
  if (days == 1) {
    return "昨天";
  } else if (days > 1 && days < 4) {
    return days + "天前";
  } else if (days > 3) {
    // 超过3天的,返回日期,如 2018-12-05
    // 如果是今年的,就省去年份,返回 12-05
    var year = date_time.getFullYear();
    var month = date_time.getMonth() + 1;
    if (month < 10) {
      month = "0" + month;
    }
    var day = date_time.getDate();
    if (day < 10) {
      day = "0" + day;
    }
    if (date_now.getFullYear() == year) {
      return month + "-" + day;
    } else {
      return year + "-" + month + "-" + day;
    }
  }

  var hours = parseInt((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
  if (hours > 0) {
    return hours + "小时前";
  }

  var minutes = parseInt((distance % (1000 * 60 * 60)) / (1000 * 60));
  if (minutes > 0) {
    return minutes + "分钟前";
  }

  return "刚刚";
}

/**
 * [funDate 获取7天之前的日期或者7天之后的日期]
 * @param  {Number} num  [description]
 * @param  {[type]} date [description]
 * @return {[type]}      [description]
 */
function funDate(num = 7, date) {
  let date1 = date || new Date();
  //今天时间
  let time1 =
    date1.getFullYear() + "-" + (date1.getMonth() + 1) + "-" + date1.getDate();
  let date2 = new Date(date1);
  date2.setDate(date1.getDate() + num);
  //num是正数表示之后的时间,num负数表示之前的时间,0表示今天
  return {
    today: time1,
    date: date2.getFullYear() +
      "-" +
      (date2.getMonth() + 1) +
      "-" +
      date2.getDate(),
  };
}

/**
 * [chunkArray 根据指点长度分割数组]
 * @param  {[type]} array 数组
 * @param  {[type]} size  长度
 * @return {[type]}       [description]
 */
function chunkArray(array, size) {
  //获取数组的长度,如果你传入的不是数组,那么获取到的就是undefined
  const length = array.length;
  //判断不是数组,或者size没有设置,size小于1,就返回空数组
  if (!length || !size || size < 1) {
    return [];
  }
  //核心部分
  let index = 0; //用来表示切割元素的范围start
  let resIndex = 0; //用来递增表示输出数组的下标

  //根据length和size算出输出数组的长度,并且创建它。
  let result = new Array(Math.ceil(length / size));
  //进行循环
  while (index < length) {
    //循环过程中设置result[0]和result[1]的值。该值根据array.slice切割得到。
    result[resIndex++] = array.slice(index, (index += size));
  }
  //输出新数组
  return result;
}

/**
 * [getExtensionFileName 获取文件后缀]
 * @param  {[type]} filename [description]
 * @return {[type]}          [description]
 */
function getExtensionFileName(filename) {
  let reg = /(\\+)/g;
  let pString = filename.replace(reg, "#"); //用正则表达式来将\或\\替换成#
  let arr = pString.split("#"); // 以“#”为分隔符,将字符分解为数组 例如 D Program Files bg.png
  let lastString = arr[arr.length - 1]; //取最后一个字符
  let arr2 = lastString.split("."); //   再以"."作为分隔符
  return arr2[arr2.length - 1]; //将后缀名返回出来
}

/**
 * [getOssImgResize 按比例缩放图片]
 * @param  {[type]} url   [description]
 * @param  {[type]} size  [description]
 * @param  {[type]} force [description]
 * @return {[type]}       [description]
 */
function getOssImgResize(url, size, force) {
  if (force)
    return `${url}?x-oss-process=image/resize,m_fixed,h_${size},w_${size}`;
  return `${url}?x-oss-process=image/resize,w_${size}`;
}

/**
 * [getTimeStamp 获取当前时间戳]
 * @return {[type]} [description]
 */
function getTimeStamp(key) {
  return `${key}_${new Date().getTime()}_${
      Math.floor(Math.random() * (100 - 1)) + 1
    }`;
}

/**
 * [cookie方法封装]
 * @type {Object}
 */
const cookie = {
  //设置cookie,增加到vue实例方便全局调用
  setCookie: (c_name, value, expiredays) => {
    let exdate = new Date();
    exdate.setDate(exdate.getDate() + expiredays);
    document.cookie =
      c_name +
      "=" +
      escape(value) +
      (expiredays == null ? "" : ";expires=" + exdate.toGMTString());
  },

  //获取cookie、
  getCookie: (name) => {
    let arr,
      reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
    if ((arr = document.cookie.match(reg))) return arr[2];
    else return null;
  },

  //删除cookie
  delCookie: (name) => {
    let exp = new Date();
    exp.setTime(exp.getTime() - 1);
    let cval = cookie.getCookie(name);
    if (cval != null)
      document.cookie = name + "=" + cval + ";expires=" + exp.toGMTString();
  },

  // 清除所有cookie
  clearAllCookie() {
    var keys = document.cookie.match(/[^ =;]+(?=\=)/g);
    if (keys) {
      for (var i = keys.length; i--;)
        document.cookie = keys[i] + "=0;expires=" + new Date(0).toUTCString();
    }
  },
};

/**
 * [getTokenInfo 解析token获取信息]
 * @return {[type]} [description]
 */
const getTokenInfo = function () {
  const token = getToken();
  if (token) {
    const info = decodeURIComponent(escape(window.atob(token.split(".")[1])));
    return JSON.parse(info);
  } else {
    return {};
  }
};

/**
 * [getToken 获取本地存储的token]
 * @return {[type]} [description]
 */
const getToken = function () {
  // return storage.get('token');
  return cookie.getCookie("token");
};

/**
 * @name:判断当前时间是否在指定的两个时间范围内
 * @param {*} d1
 * @param {*} d2
 * @return {*}
 */
function nowInDateBetwen(d1, d2) {
  //如果时间格式是正确的,那下面这一步转化时间格式就可以不用了
  // var dateBegin = new Date(d1.replace(/-/g, "/"));//将-转化为/,使用new Date
  // var dateEnd = new Date(d2.replace(/-/g, "/"));//将-转化为/,使用new Date
  var dateBegin = new Date(d1); //将-转化为/,使用new Date
  var dateEnd = new Date(d2); //将-转化为/,使用new Date
  var dateNow = new Date(); //获取当前时间

  var beginDiff = dateNow.getTime() - dateBegin.getTime(); //时间差的毫秒数
  var beginDayDiff = Math.floor(beginDiff / (24 * 3600 * 1000)); //计算出相差天数

  var endDiff = dateEnd.getTime() - dateNow.getTime(); //时间差的毫秒数
  var endDayDiff = Math.floor(endDiff / (24 * 3600 * 1000)); //计算出相差天数
  if (endDayDiff < 0) {
    //已过期
    return false;
  }
  if (beginDayDiff < 0) {
    //没到开始时间
    return false;
  }
  return true;
}

// 是否图片
function isImg(suffix) {
  const suffixes = [
    "bmp",
    "jpeg",
    "png",
    "tiff",
    "gif",
    "pcx",
    "tga",
    "exif",
    "fpx",
    "svg",
    "psd",
    "jpg",
  ];
  const suffix_ = suffix.toLowerCase();
  return suffixes.some((it) => it == suffix_);
}

// 是否excel
function isExcel(suffix) {
  const suffixes = ["xls", "xlsx"];
  const suffix_ = suffix.toLowerCase();
  return suffixes.some((it) => it == suffix_);
}

// 是否doc
function isDoc(suffix) {
  const suffixes = ["doc", "docx"];
  const suffix_ = suffix.toLowerCase();
  return suffixes.some((it) => it == suffix_);
}

// 是否ppt
function isPpt(suffix) {
  const suffixes = ["ppt", "pptx"];
  const suffix_ = suffix.toLowerCase();
  return suffixes.some((it) => it == suffix_);
}

// 是否pdf
function isPdf(suffix) {
  const suffixes = ["pdf"];
  const suffix_ = suffix.toLowerCase();
  return suffixes.some((it) => it == suffix_);
}

// 是否压缩包
function isZip(suffix) {
  const suffixes = ["rar", "zip", "7z", "tar"];
  const suffix_ = suffix.toLowerCase();
  return suffixes.some((it) => it == suffix_);
}

// 是否视频
function isVideo(suffix) {
  const suffixes = [
    "avi",
    "mov",
    "qt",
    "asf",
    "mkv",
    "rm",
    "revb",
    "mod",
    "mp4",
    "wmv",
  ];
  const suffix_ = suffix.toLowerCase();
  return suffixes.some((it) => it == suffix_);
}

// 是否音频
function isAudio(suffix) {
  const suffixes = ["mp3", "wma", "wav"];
  const suffix_ = suffix.toLowerCase();
  return suffixes.some((it) => it == suffix_);
}

// 获取文件名后缀
const getSuffix = (fileName) => {
  if (!fileName) return "";
  let clips = fileName.split(".");
  return clips[clips.length - 1];
};

/**
 * [防抖函数]
 * @param  {Function} fn   [需要执行的函数]
 * @param  {[type]}   wait [函数需要等待的时间]
 * @return {[type]}        void
 */
const debounce = (fn, wait) => {
  var timeout = null;
  return function () {
    if (timeout !== null) clearTimeout(timeout);
    timeout = setTimeout(fn, wait);
  };
};

//判断字符串是否是金钱
function validMoney(money) {
  let pattern = /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/;
  if (pattern.test(money)) {
    return true;
  } else {
    return false;
  }
}

//获取两个日期之间相隔的所有日期
function getDayAll(starDay, endDay) {
  var arr = [];
  var dates = [];
  // 设置两个日期UTC时间
  var db = new Date(starDay);
  var de = new Date(endDay);
  // 获取两个日期GTM时间
  var s = db.getTime() - 24 * 60 * 60 * 1000;
  var d = de.getTime() - 24 * 60 * 60 * 1000;
  // 获取到两个日期之间的每一天的毫秒数
  for (var i = s; i <= d;) {
    i = i + 24 * 60 * 60 * 1000;
    arr.push(parseInt(i));
  }
  // 获取每一天的时间  YY-MM-DD
  for (var j in arr) {
    var time = new Date(arr[j]);
    var year = time.getFullYear(time);
    var mouth =
      time.getMonth() + 1 >= 10 ?
      time.getMonth() + 1 :
      "0" + (time.getMonth() + 1);
    var day = time.getDate() >= 10 ? time.getDate() : "0" + time.getDate();
    var YYMMDD = year + "-" + mouth + "-" + day;
    dates.push(YYMMDD);
  }
  return dates;
}

//xml字符串转换xml对象数据
function xmlStr2XmlObj(xmlStr) {
  var xmlObj = {};
  if (document.all) {
    var xmlDom = new ActiveXObject("Microsoft.XMLDOM");
    xmlDom.loadXML(xmlStr);
    xmlObj = xmlDom;
  } else {
    xmlObj = new DOMParser().parseFromString(xmlStr, "text/xml");
  }
  return xmlObj;
}

//xml字符串转换json数据
function xmlObj2json(xml) {
  var xmlObj = xmlStr2XmlObj(xml);
  var jsonObj = {};
  if (xmlObj.childNodes.length > 0) {
    jsonObj = xml2json(xmlObj);
  }
  return jsonObj;
}

//xml转换json数据
function xml2json(xml) {
  try {
    var obj = {};
    if (xml.children.length > 0) {
      for (var i = 0; i < xml.children.length; i++) {
        var item = xml.children.item(i);
        var nodeName = item.nodeName;
        if (typeof (obj[nodeName]) == "undefined") {
          obj[nodeName] = xml2json(item);
        } else {
          if (typeof (obj[nodeName].push) == "undefined") {
            var old = obj[nodeName];
            obj[nodeName] = [];
            obj[nodeName].push(old);
          }
          obj[nodeName].push(xml2json(item));
        }
      }
    } else {
      obj = xml.textContent;
    }
    return obj;
  } catch (e) {
    console.log(e.message);
  }
}

//标准时间转时间
const formatDate = (timestamp, type = "datetime") => {
  let time = null;
  if ((timestamp.toString()).length == 13) {
    time = new Date(timestamp)
  } else {
    time = new Date(timestamp * 1000)
  }
  let year = time.getFullYear()
  let month = time.getMonth() + 1
  let date = time.getDate()
  let hours = time.getHours()
  let minute = time.getMinutes()
  let second = time.getSeconds()

  if (month < 10) {
    month = '0' + month
  }
  if (date < 10) {
    date = '0' + date
  }
  if (hours < 10) {
    hours = '0' + hours
  }
  if (minute < 10) {
    minute = '0' + minute
  }
  if (second < 10) {
    second = '0' + second
  }
  if (type == "datetime") {
    return year + '-' + month + '-' + date + ' ' + hours + ':' + minute + ':' + second;
  } else {
    return year + '-' + month + '-' + date
  }

}

/**
 * [获取当前文件上传服务器类型]
 * @return {[string]} [服务器类型]
 */
const getServerType = () => {
  // const deploy_way = storage.get("deploy_way");
  // if (deploy_way && deploy_way == 1) {
  //   return "local";
  // } else {
  //   return "oss";
  // }
  return "local"
};

const fileParse = (file, type = "base64") => {
  return new Promise((resolve, reject) => {
    let fileRead = new FileReader();
    if (type === "base64") {
      fileRead.readAsDataURL(file);
    } else if (type === "buffer") {
      fileRead.readAsArrayBuffer(file);
    }
    // console.log(fileRead, "fileRead");
    fileRead.onload = (ev) => {
      resolve(ev.target.result);

    };
    fileRead.onprogress = (e) => {
      console.log(e.loaded);
      console.log(e.total);
    };
    fileRead.onerror = (err) => {
      reject(err)
    }
  });
}

//寻找父类id
const findPnodeId = (data = [], nodeId, allData = []) => {
  let res = [];
  if (data.length) {
    data.forEach(item => {
      if (item.children && item.children.length) {
        if (item.children.some(v => v.id == nodeId)) {
          res.push(item.id);
          res = res.concat(findPnodeId(allData, item.id, allData))
        } else {
          res = res.concat(findPnodeId(item.children, nodeId, allData))
        }
      } else {
        return
      }
    });
  }
  return res;
}

//获取用户信息
const getUserInfo = () => {
  return JSON.parse(storage.get("userInfo"));
}

/**
 * [loopRouterChildren 查找子路由]
 * @param  {[type]} router [description]
 * @param  {[type]} find   [description]
 * @return {[type]}        [description]
 */
const loopRouterChildren = (router, find) => {
  let res = [];
  router.map((v) => {
    if (v.path === find) {
      res.push(v);
    }
    if (v.children && v.children.length) {
      res = res.concat(loopRouterChildren(v.children, find));
    }
  });
  return res
};

const realFormatSecond = (second) => {
  var secondType = typeof second;
  if (secondType === "number" || secondType === "string") {
    second = parseInt(second);
    var hours = Math.floor(second / 3600);
    second = second - hours * 3600;
    var mimute = Math.floor(second / 60);
    second = second - mimute * 60;
    return (
      ("0" + hours).slice(-2) + ":" + ("0" + mimute).slice(-2) + ":" + ("0" + second).slice(-2)
    );
  } else {
    return "00:00:00";
  }
}

//获取周日期范围
const weekDate = (day = 0) => {
  var date = new Date();
  // 本周日的日期,0周日,1 周一
  date.setDate(date.getDate() - date.getDay() + day);
  var begin = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
  // 本周六的日期
  date.setDate(date.getDate() + 6);
  var end = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
  let timeInfo = {
    begin: begin,
    end: end
  }
  return timeInfo
}

// 获取两个日期之间相差的天数
const getDaysBetween = (dateString1, dateString2) => {
  let startDate = Date.parse(dateString1);
  let endDate = Date.parse(dateString2);
  let days = (endDate - startDate) / (1 * 24 * 60 * 60 * 1000);
  // alert(days);
  return days;
}

//JS将字符串yyyyMMddHHmmss转Date
const strFormatedDate = (dateStr) => {
  let pattern = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/;
  let formatedDate1 = dateStr.replace(pattern, '$1/$2/$3 $4:$5:$6');
  let ddate1 = new Date(formatedDate1);
  return formatedDate1;
}

//比较时间字符串相差几分钟
const compareTimeMin = (time1, time2) => {
  let m = 0;
  //判断开始时间是否大于结束日期
  if (time1 > time2) {
    m = 0;
  } else {
    //截取字符串,得到日期部分"2009-12-02",用split把字符串分隔成数组
    var begin1 = time1.substr(0, 10).split("-");
    var end1 = time2.substr(0, 10).split("-");

    var beginTime1 = time1.substr(11, 8).split(":");
    var endTime1 = time2.substr(11, 8).split(":");
    //将拆分的数组重新组合,并实例成化新的日期对象
    var date1 = new Date(begin1[0] + '-' + begin1[1] + '-' + begin1[2] + ' ' + beginTime1[0] + ':' + beginTime1[1] + ':' + beginTime1[2]);
    var date2 = new Date(end1[0] + '-' + end1[1] + '-' + end1[2] + ' ' + endTime1[0] + ':' + endTime1[1] + ':' + endTime1[2]);

    //得到两个日期之间的差值m,以分钟为单位
    m = parseInt(Math.abs(date2 - date1) / 1000 / 60);
  }
  return m;
}

const isRepeat = (arr) => {
  var hash = {};
  for (var i in arr) {
    if (hash[arr[i]]) {
      return true;
    }
    // 不存在该元素,则赋值为true,可以赋任意值,相应的修改if判断条件即可
    hash[arr[i]] = true;
  }
  return false;
}

// DES加密
const encryptDes = (message, key = "200ceb26807d6bf99fd6f4f0d1ca54d4") => {
  var keyHex = cryptoJs.enc.Utf8.parse(key)
  var option = {
    mode: cryptoJs.mode.ECB,
    padding: cryptoJs.pad.Pkcs7
  }
  var encrypted = cryptoJs.DES.encrypt(message, keyHex, option)
  return encrypted.ciphertext.toString()
}

// DES解密
const decryptDes = (message, key = "200ceb26807d6bf99fd6f4f0d1ca54d4") => {
  var keyHex = cryptoJs.enc.Utf8.parse(key)
  var decrypted = cryptoJs.DES.decrypt({
      ciphertext: cryptoJs.enc.Hex.parse(message)
    },
    keyHex, {
      mode: cryptoJs.mode.ECB,
      padding: cryptoJs.pad.Pkcs7
    }
  )
  return decrypted.toString(cryptoJs.enc.Utf8)
}

/**判断是否是手机号**/
const isPhoneNumber = (tel) => {
  var reg = /^0?1[3|4|5|6|7|8][0-9]\d{8}$/;////手机电话
  var zjdh = /^((0\d{2,3})-)?(\d{7,8})$/; //座机电话
  if (!reg.test(tel)&&!zjdh.test(tel)) {
    return false;
  } else {
    return true;
  }
}

//获取身份证呼叫
const getIdentityAddress = (str) => {
  let _arr = [{
      id: "11",
      name: "北京"
    },
    {
      id: "12",
      name: "天津"
    },
    {
      id: "13",
      name: "河北"
    },

    {
      id: "14",
      name: "山西"
    },
    {
      id: "15",
      name: "内蒙"
    },
    {
      id: "21",
      name: "辽宁"
    },

    {
      id: "22",
      name: "吉林"
    },
    {
      id: "23",
      name: "黑龙江"
    },

    {
      id: "31",
      name: "上海"
    },
    {
      id: "32",
      name: "江苏"
    },

    {
      id: "33",
      name: "浙江"
    },
    {
      id: "34",
      name: "安徽"
    },

    {
      id: "35",
      name: "福建"
    },
    {
      id: "36",
      name: "江西"
    },
    {
      id: "37",
      name: "山东"
    },
    {
      id: "41",
      name: "河南"
    },
    {
      id: "42",
      name: "湖北"
    },
    {
      id: "43",
      name: "湖南"
    },
    {
      id: "44",
      name: "广东"
    },
    {
      id: "45",
      name: "广西"
    },

    {
      id: "46",
      name: "海南"
    },
    {
      id: "50",
      name: "重庆"
    },

    {
      id: "51",
      name: "四川"
    },
    {
      id: "52",
      name: "贵州"
    },

    {
      id: "53",
      name: "云南"
    },
    {
      id: "54",
      name: "西藏"
    },
    {
      id: "61",
      name: "陕西"
    },

    {
      id: "62",
      name: "甘肃"
    },
    {
      id: "63",
      name: "青海"
    },

    {
      id: "64",
      name: "宁夏"
    },

    {
      id: "65",
      name: "新疆"
    },
    {
      id: "71",
      name: "台湾"
    },

    {
      id: "81",
      name: "香港"
    },
    {
      id: "82",
      name: "澳门"
    },
    {
      id: "91",
      name: "海外"
    }
  ]
  if (str) {
    let _obj=_arr.find(v=>v.id==str);
    return _obj?.name||""
  } else {
    return ""
  }
} 

//手机号脱敏
const phoneNuberConvert=(number)=>{
  if (!number) return "";
  let pat = /(\d{3})\d*(\d{4})/;
  let result = number.replace(pat, "$1***$2");
  return result;
}

/**
 * 名字脱敏
 */
const nameConvert=(name)=>{
  let userName = "";
  if (name.length == 2) {
    userName = name.substring(0, 1) + "*"; //截取name 字符串截取第一个字符,
  } else if (name.length == 3) {
    userName = name.substring(0, 1) + "*" + name.substring(2, 3); //截取第一个和第三个字符
  } else if (name.length > 3) {
    userName =
      name.substring(0, 1) + "*" + "*" + name.substring(3, name.length); //截取第一个和大于第4个字符
  }
  return userName;
}

//身份证、银行卡脱敏
const icardAndBankConvert=(str)=>{
  if (str) {
    return str.replace(/^(.{6})(?:\d+)(.{4})$/, "$1****$2");
  } else {
    return ""
  }
}


//数组分组
const groupArray=(data,cols)=>{
  const r=data.reduce((r,t)=>{
    r.current.push(t);
    if(r.current.length===cols){
      r.list.push(r.current);
      r.current=[];
    }
    return r;
  },{list:[],current:[]});
  if (r.current.length) {
    r.list.push(r.current);
  }
  return r.list;
}

//复制数据工具
const copyDataUtil=(str)=>{
  let aux = document.createElement('input')
  // 获取复制内容
  // const content = v
  // 设置元素内容
  aux.setAttribute('value', str)
  // 将元素插入页面进行调用
  document.body.appendChild(aux)
  // 复制内容
  aux.select()
  // 将内容复制到剪贴板
  document.execCommand('copy')
  // 删除创建元素
  document.body.removeChild(aux)
}

//地址脱敏
const desensitizedAddr=(str)=>{
  if (!str) {
      return "";
  }
  let _addrReg = /(.{4})(.*)/; // 地址正则
  if(_addrReg.test(str)){
      let text1 = RegExp.$1;
      let text2 = RegExp.$2.replace(/./g,"*");
      return  text1 + text2 ;
  }
  return str;
}

/**
 * 根据日期字符串获取星期几
 * @param dateString 日期字符串(如:2020-05-02)
 * @returns {String}
 */
const getWeek = (dateString) => {
  if (!dateString) {
    return "未知"
  }
  let _arr=(dateString||"").split(" ");
  let _str="";
  if (_arr.length==2) {
    _str=_arr[0];
  } else {
    _str=dateString;
  }
  if (!checkDate(_str)) {
    return "时间格式有误"
  }
  let dateArray = _str.split("-");
  let date = new Date(dateArray[0], parseInt(dateArray[1] - 1), dateArray[2]);
  return "周" + "日一二三四五六".charAt(date.getDay());
};

// 判断日期格式是否合理,格式2022-04-16
const checkDate=(str)=>{
  let r = new RegExp(/^\d{4}\-\d{2}\-\d{2}$/);
  return r.test(str);
}

//扁平函数
const flattenFun=(arr,key="children")=> {
  let result = [];

  for(let i = 0; i < arr.length; i++) {
    result.push(arr[i]);
    if (arr[i].hasOwnProperty(key)&&arr[i][key].length) {
      result = result.concat(flattenFun(arr[i][key],key));
    }
  }
  return result;
}

/**
 * 获取设备类型
 */
export const getDeviceType = () => {
  const reg =  /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i
  return reg.test(navigator.userAgent) ? 'Mobile' : 'Desktop'
}

// 用户数据排序
export const userAlphabeticSort = (arr,key="name") => {
  if (!String.prototype.localeCompare) return null
  let letters = 'ABCDEFGHJKLMNOPQRSTWXYZ'.split('')
  let zh = '阿八嚓哒妸发旮哈讥咔垃痳拏噢妑七呥扨它穵夕丫帀'.split('')
  let segs = []
  letters.map((item, i) => {
    let cur = {
      letter: item,
      data: []
    }
    arr.map((item) => {
      if (item[key].localeCompare(zh[i]) >= 0 && item[key].localeCompare(zh[i + 1]) < 0) {
        cur.data.push(item)
      }
    })
    if (cur.data.length != 0) {
      cur.data.sort(function (a, b) {
        return a[key].localeCompare(b[key], 'zh')
      })
      segs.push(cur)
    }
  })
  return segs
}

//获取当前指定的前几天的日期
//console.log(getBeforeDate(1));//昨天的日期
const getBeforeDate = (days) => {
  var now = new Date().getTime();
  var ago = now - 86400000 * days; //一天的毫秒数为86400000
  var agoData = new Date(ago);
  var year = agoData.getFullYear();
  var mon = agoData.getMonth() + 1;
  var day = agoData.getDate();
  mon = mon < 10 ? '0' + mon : mon;
  day = day < 10 ? '0' + day : day;
  var date = year + '-' + mon + '-' + day;
  return date;
}

//获取唯一值
export function getUUID(len=10){
  return Number(
    Math.random().toString().substr(3, len) + Date.now()
  ).toString(36);
}

export function getCurrentTime() {
  let _m=new Date().getMonth() + 1;
  //获取当前时间并打印
  let yy = new Date().getFullYear();
  let mm = _m<10?'0'+_m:_m;
  let dd = new Date().getDate()<10?'0'+new Date().getDate():new Date().getDate();
  let hh = new Date().getHours()<10?'0'+new Date().getHours():new Date().getHours();
  let mf = new Date().getMinutes() < 10 ? '0' + new Date().getMinutes() : new Date().getMinutes();
  let ss = new Date().getSeconds() < 10 ? '0' + new Date().getSeconds() : new Date().getSeconds();
  let time = yy + '/' + mm + '/' + dd + ' ' + hh + ':' + mf + ':' + ss;
  return time;
}

/**
 * JS 计算两个时间间隔多久(时分秒)
 * @param startTime "2019-10-23 15:27:23"
 * @param endTime "2019-10-23 15:27:55"
 * @return 1天2时3分5秒
 */
export function twoTimeInterval(startTime, endTime) {
 
  // 开始时间
  let d1 = startTime.replace(/\-/g, "/");
  let date1 = new Date(d1);
 
  // 结束时间
  let d2 = endTime.replace(/\-/g, "/");
  let date2 = new Date(d2);
 
  // 时间相差秒数
  let dateDiff = date2.getTime() - date1.getTime();
 
  // 计算出相差天数
  let days = Math.floor(dateDiff / (24 * 3600 * 1000));
 
  // 计算出小时数
  let residue1 = dateDiff % (24 * 3600 * 1000); // 计算天数后剩余的毫秒数
  let hours = Math.floor(residue1 / (3600 * 1000));
 
  // 计算相差分钟数
  let residue2 = residue1 % (3600 * 1000); // 计算小时数后剩余的毫秒数
  let minutes = Math.floor(residue2 / (60 * 1000));
 
  // 计算相差秒数
  let residue3 = residue2 % (60 * 1000); // 计算分钟数后剩余的毫秒数
  let seconds = Math.round(residue3 / 1000);
 
  let returnVal =
    ((days == 0) ? "" : days+"天") +
    ((hours == 0) ? "" : hours +"时") +
    ((minutes == 0) ? "" : minutes+"分") +
    ((seconds == 0) ? "" : seconds+"秒");
 
  return returnVal;
 
}

/**
 * 
 * @param {秒数转化为时分秒} s 
 * @returns 
 */
export function secTotime(s) {
  let t = '';
  if(s > -1){
    let hour = Math.floor(s/3600)
    let min = Math.floor(s/60) % 60
    let sec = s % 60
    t=hour<10?'0'+ hour + ":":hour + ":";
    if(min < 10){
      t += "0"
    } 
    t += min + ":"
    if(sec < 10){
      t += "0"
    } 
    t += sec.toFixed(0)
  } 
  return t
}

/**
 * 获取Url的参数
 * @param {*} url 
 * @returns 
 */
const getUtlParam =(url)=>{
  url = url ? url : window.location.href.substring(0, window.location.href.length);
  let str = url.substring(url.indexOf('?') + 1);
  let arrs = str.split('&');
  let result = {};
  arrs.forEach(item => {
    let keyArr = item.split('=');
    let name = keyArr[0];
    let value = keyArr[1];
    result[name] = value;
  });
  return result;
}

/**
 * 扁平数组
 * @param {*} arr 扁平数据数据 
 * @param {*} key 树形key
 */
export function flatArr(arr=[],key="children") {
  let _arr=[];
  (arr||[]).map(item=>{
    _arr.push(item);
    if (item[key]?.length) {
      _arr=_arr.concat(flatArr(item[key],key));
    }
  })
  return _arr;
}

/**
 * 校验密码
 * @param {*} str 校验密码字符串
 * @param {*} reg 正则表达式
 * @param {*} msg 校验提示语
 * @returns 
 */
export function verifyPasswordFun(str, msg = "密码必须包含大小写字母、数字、特殊字符且8~20位", reg = "^(?![A-Za-z0-9]+$)(?![a-z0-9\\W]+$)(?![A-Za-z\\W]+$)(?![A-Z0-9\\W]+$)[a-zA-Z0-9\\W]{8,20}$") {
  let _result = true
  let regexp = new RegExp(reg);
  if (!regexp.test(str)) {
    this.$message.error(msg);
    _result = false;
  }
  return _result;
}

/**
 * 日期时间有效性检查 格式为:YYYY-MM-DD HH:MM:SS 
 * @param {*} str 
 * @returns 
 */
const CheckDateTime=(str)=>{ 
  var reg = /^(\d+)-(\d{1,2})-(\d{1,2}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/;
  var r = str.match(reg);
  if(r==null)return false;
  r[2]=r[2]-1;
  var d= new Date(r[1], r[2],r[3], r[4],r[5], r[6]);
  if(d.getFullYear()!=r[1])return false;
  if(d.getMonth()!=r[2])return false;
  if(d.getDate()!=r[3])return false;
  if(d.getHours()!=r[4])return false;
  if(d.getMinutes()!=r[5])return false;
  if(d.getSeconds()!=r[6])return false;
  return true;
} 

/**
 * 判断是否是外部连接
 * @param path 路径
 * @returns
 */
const isExternal = (path: string) => {
  const reg = /^(https?:|mailto:|tel:)/;
  return reg.test(path);
};

/**
 * 字符串校验
 * @param {*} str 字符串
 * @param {*} rang 范围正则
 * @returns 
 */
const stringVerification=(str,rang=/^.{8,20}$/)=>{
  let _arr=[];//大写字母:capital,小写字母:lowerCase,特殊字符:specialCharacters,数字:digit,长度在范围中:inScope
  let reg = /^(?=.*?[A-Z])/;
  let reg1 = /^(?=.*?[a-z])/;
  let reg2 = /^(?=.*?\d)/;
  let reg3 = /^(?=.*?[?!&¥$%^#,.\/@";:><\[\]}{\-=+_\\|》《。,、?’‘“”~ `])/;
  if (reg.test(str)) {
    _arr.push('capital')
  }
  if (reg1.test(str)) {
    _arr.push('lowerCase')
  }
  if (reg2.test(str)) {
    _arr.push('digit')
  }
  if (reg3.test(str)) {
    _arr.push('specialCharacters')
  }
  if (rang.test(str)) {
    _arr.push("inScope")
  }

  return _arr;
}


/**
 * AES加密
 * @param {*} data 
 * @param {*} key 密钥字符串必须为16、24、32
 * @param {*} iv  iv16位的字符串
 * @returns 
 */
const encryptAES = (data, key, iv="tdrdadq59tbss5n7")=>{ //key,iv:16位的字符串
  let key1 = cryptoJs.enc.Utf8.parse(key);
  let iv1 = cryptoJs.enc.Utf8.parse(iv);
  return cryptoJs.AES.encrypt(data, key1, {
      iv: iv1,
      mode: cryptoJs.mode.CBC,
      padding: cryptoJs.pad.Pkcs7
  }).toString();
}

/**
 * AES解密
 * @param {*} data 
 * @param {*} key 密钥字符串必须为16、24、32
 * @param {*} iv  iv16位的字符串
 * @returns 
 */
const decryptAES =(data, key, iv="tdrdadq59tbss5n7")=>{ //key,iv:16位的字符串
  let key1 = cryptoJs.enc.Utf8.parse(key);
  let iv1 = cryptoJs.enc.Utf8.parse(iv);
  let decrypted = cryptoJs.AES.decrypt(data, key1, {
      iv: iv1,
      mode: cryptoJs.mode.CBC,
      padding: cryptoJs.pad.Pkcs7
  });
  return decrypted.toString(cryptoJs.enc.Utf8)
}

// 生成随机字符串
// 数字0~9对应的ASCII码值是 48-57
// 大写字母A-Z对应的ASCII码值是 65-90
// 小写字母a-z对应的ASCII码值是 97-122
// 特殊字符对应的ASCII码的值是33-47 58-64
const getPassword = (legnth) => {
  // 定义一个空数组保存我们的密码
  let passArrItem = [];


  // 定义获取密码成员的方法
  const getNumber = () => Math.floor(Math.random() * 10); // 0~9的数字
  const getUpLetter = () => String.fromCharCode(Math.floor(Math.random() * 26) + 65); // A-Z
  const getLowLetter = () => String.fromCharCode(Math.floor(Math.random() * 26) + 97); // a-z
  const getCode = () => String.fromCharCode(Math.floor(Math.random() * 15) + 33) || String.fromCharCode(Math.floor(Math.random() * 7) + 58)

  // 将获取成员的方法保存在一个数组中方便用后面生成的随机index取用
  const passMethodArr = [getNumber, getUpLetter, getLowLetter, getCode];

  // 随机index
  const getIndex = () => Math.floor(Math.random() * 4);

  // 从0-9,a-z,A-Z,以及特殊字符中随机获取一项
  const getPassItem = () => passMethodArr[getIndex()]();

  // 不多解释
  Array(legnth - 4).fill('').forEach(() => {
    passArrItem.push(getPassItem());
  })

  const confirmItem = [getNumber(), getUpLetter(), getLowLetter(), getCode()];

  // 加上我们确认的四项,从而使生成的密码,大写字母、小写字母、数字和特殊字符至少各包含一个
  passArrItem.push(...confirmItem);

  // 转为字符串返回
  return passArrItem.join('');
}

/**
 * 时间校验
 * @param {*} str 校验格式 YYYY-MM-DD hh:mm:ss
 */
const timeFormatCheck=(str)=>{
  let regex = /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/;
  return regex.test(str)
}

/**
*校验文件路径是否存在
*/
const checkFilePath=async(filePath)=> {
  console.log(filePath,"filePath++++");
  return new Promise((resolve, reject)=> {
    let xhr = new XMLHttpRequest();
    xhr.open('HEAD', filePath, true);
    xhr.onreadystatechange = function () {
      // console.log(xhr,"xhr");
      // console.log(xhr.readyState);
      // console.log(xhr.status);
      if (xhr.readyState == 4) {
        if (xhr.status == 200) {
          resolve(true); // 存在
        } else {
          resolve(false); // 存在
        }
      }
    };
    xhr.send();
  });
}

/**
 * 校验字符串
 * @param {*} str 
 */
 const verifyString=(str)=>{
  let regex =  /\$var<[a-zA-Z\d_]+>/;
  return regex.test(str)
}

/**
 * 抽取字符串变量
 * @param {*} str 
 */
const extractStringVariables=(str,type="protocol")=>{
    let _arr=[];
    // 创建一个正则表达式,用于匹配以 $var 开头,后面跟着一对尖括号 < 和 > 的字符串
    const regex = /\$var<([^>]+)>/g;
    // 使用 matchAll() 方法获取所有匹配项
    const matches = str.matchAll(regex);
    // 遍历匹配项并提取尖括号内的内容
    for (const match of matches) {
      _arr.push({
        id:match[1],
        key:match[0],
        value:"",
        index:match.index,
        type:type
      })
    }
    return _arr;
}

/**
 * 通过base64转文件上传,获取文件路径
 */
const getFileUrlByBase64TurFile=({fileBase64="",that=null,urlCallBack=()=>{}})=>{
  const arr = fileBase64.split(',');
  const mime = arr[0].match(/:(.*?);/)[1];
  const buffer = Buffer.from(arr[1], 'base64');
  let _tempFile=new File([buffer], `${getUUID()}.png`, { type: mime });
  commonFunc.uploadFile({
    that: that,
    file: _tempFile,
    showTips: true,
    uploadDoneCallback: (res) => {
      console.log(res, "base64转file上传成功");
      if (res.fileUrl) {
        urlCallBack(res.fileUrl);
      }else{
        urlCallBack(null);
      }
    },
    clientCallback: (props) => {
      console.error(props, "base64转file上传失败");
    }
  })
}

/**
 * 处理模板数据变量
 * @param {*} arr 
 * @returns 
 */
const handleTemplatedVariable=(arr=[])=>{
  let _protocolData=[];
  (arr || []).forEach(item => {
    if (item.type==2&&item.textStr) {
      _protocolData=[..._protocolData,...extractStringVariables(item.textStr)];
    }
  });
  return _protocolData
}

/**
 * 处理调解函数据的变量
 * @param {*} _obj 
 * @returns 
 */
const handleMediationLetterVariable=(_obj={})=>{

  let _protocolData=[];
  if (_obj?.letter?.content) {
    _protocolData=[..._protocolData,...extractStringVariables(_obj?.letter?.content,"letter")];
  }
  if (_obj?.sms?.content) {
    _protocolData=[..._protocolData,...extractStringVariables(_obj?.sms?.content,"sms")];
  }
  return _protocolData
}

/**
 * 重置日期格式
 * @param {*} str 
 * @returns 
 */
const resetDateType=(str="")=>{
  if (!str) {
    return null
  }
  return str.replace(/-/g, '年') + '日';
}

/**
 * 检查音频频道(音频文件的声道数量)
 * @param {*} file 
 * @returns 
 */
const checkAudioChannels=(file)=> {  
  return new Promise((resolve, reject) => {  
      // 创建一个AudioContext实例  
      const audioContext = new (window.AudioContext || window.webkitAudioContext)();  

      // 创建一个FileReader来读取文件  
      const reader = new FileReader();  

      // 读取完成后的回调函数  
      reader.onload = function(e) {  
          // 创建一个ArrayBuffer  
          const arrayBuffer = e.target.result;  

          // 使用AudioContext的decodeAudioData方法来解码音频数据  
          audioContext.decodeAudioData(arrayBuffer, function(audioBuffer) {  
              // audioBuffer.numberOfChannels 将给出声道数量  
              const channels = audioBuffer.numberOfChannels;  
              resolve(channels);  
          }, function(err) {  
              reject(err);  
          });  
      };  

      // 使用FileReader读取文件为ArrayBuffer  
      reader.readAsArrayBuffer(file);  
  });  
}

/**
 * 音频文件的采样率
 * @param {*} file 
 * @returns 
 */
const getAudioSampleRate=(file)=> {  
  return new Promise((resolve, reject) => {  
      // 创建一个AudioContext实例  
      const audioContext = new (window.AudioContext || window.webkitAudioContext)();  

      // 读取文件为ArrayBuffer  
      const reader = new FileReader();  
      reader.onload = function(e) {  
          const arrayBuffer = e.target.result;  

          // 解码音频数据  
          audioContext.decodeAudioData(arrayBuffer, function(audioBuffer) {  
              // audioBuffer.sampleRate 将给出采样率  
              resolve(audioBuffer.sampleRate);  
          }, function(err) {  
              reject(err);  
          });  
      };  

      // 触发文件读取  
      reader.readAsArrayBuffer(file);  
  });  
}

export{
  storage,
  deepClone,
  getToken,
  setToken,
  clearToken,
  getTokenInfo,
  uniqueArray,
  uniqueArrayObject,
  sum,
  getDateFormat,
  getTimeDistance,
  funDate,
  chunkArray,
  getExtensionFileName,
  getOssImgResize,
  getTimeStamp,
  cookie,
  nowInDateBetwen,
  isImg,
  isExcel,
  isDoc,
  isPpt,
  isPdf,
  isZip,
  isVideo,
  isAudio,
  getSuffix,
  validMoney,
  debounce,
  getDayAll,
  getServerType,
  xmlObj2json,
  formatDate,
  fileParse,
  findPnodeId,
  getUserInfo,
  loopRouterChildren,
  realFormatSecond,
  weekDate,
  getDaysBetween,
  strFormatedDate,
  compareTimeMin,
  isRepeat,
  encryptDes,
  decryptDes,
  isPhoneNumber,
  getIdentityAddress,
  phoneNuberConvert,
  nameConvert,
  icardAndBankConvert,
  groupArray,
  desensitizedAddr,
  getWeek,
  checkDate,
  flattenFun,
  copyDataUtil,
  getDeviceType,
  userAlphabeticSort,
  getBeforeDate,
  getUUID,
  getCurrentTime,
  twoTimeInterval,
  secTotime,
  getUtlParam,
  flatArr,
  verifyPasswordFun,
  CheckDateTime,
  isExternal,
  stringVerification,
  encryptAES,
  decryptAES,
  getPassword,
  timeFormatCheck,
  checkFilePath,
  verifyString,
  extractStringVariables,
  getFileUrlByBase64TurFile,
  handleTemplatedVariable,
  handleMediationLetterVariable,
  resetDateType,
  checkAudioChannels,
  getAudioSampleRate
};

 

posted @ 2022-02-14 14:08  春春&  阅读(39)  评论(0编辑  收藏  举报