npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ratingdog-common-utils

v1.0.9

Published

通用方法库

Readme

1 存储类方法
1.1 存储localStorage
/**
 * 存储localStorage
 * @param {String} key 本地存储键名
 * @param {String} content 本地存储值名
 */
export const setStore = (key: string, content: string) => {
  if (!key) {
    return
  }
  if (typeof content !== 'string') {
    content = JSON.stringify(content)
  }
  window.localStorage.setItem(key, content)
}
1.2 获取localStorage
/**
 * 获取localStorage
 * @param {String} key 本地存储键名
 */
export const getStore = (key: string) => {
  if (!key) {
    return
  }
  return window.localStorage.getItem(key)
}
1.3 删除localStorage
/**
 * 删除localStorage
 * @param {String} key 本地存储键名
 */
export const removeStore = (key: string) => {
  if (!key) {
    return
  }
  window.localStorage.removeItem(key)
}
1.4 存储sessionStorage
/**
 * 存储sessionStorage
 * @param {String} key 本地存储键名
 * @param {String} content 本地存储值名
 */
export const setSessionStorage = (key: string, content: string) => {
  if (!key) {
    return
  }
  if (typeof content !== 'string') {
    content = JSON.stringify(content)
  }
  window.sessionStorage.setItem(key, content)
}
1.5 获取sessionStorage
/**
 * 获取sessionStorage
 * @param {String} key 本地存储键名
 */
export const getSessionStorage = (key: string) => {
  if (!key) {
    return
  }
  return window.sessionStorage.getItem(key)
}
1.6 删除sessionStorage
/**
 * 删除sessionStorage
 * @param {String} key 本地存储键名
 */
export const removeSessionStorage = (key: string) => {
  if (!key) {
    return
  }
  window.sessionStorage.removeItem(key)
}
1.7 默认的cookie写入方法
/**
 * 默认的cookie写入方法
 * @param {String} name 键
 * @param {String} value 值
 * @param {Number} Days 时间 单位(天) 默认为5
 * @param {String} path 默认为'/'
 */
export const setCookie = (
  name: string,
  value: string,
  Days = 5,
  path = '/'
) => {
  Cookies.set(name, value, { expires: Days })
  Cookies.set(name, value, { expires: Days, path })
  Cookies.set(name, value, { expires: Days, path, domain: 'rd2.ratingdog.cn' })
}
1.8 获取指定名称的cookie的值
/**
 * 获取指定名称的cookie的值
 * @param {String} name 需要获取的cookie键
 * @return {String} 结果值
 */
export const getCookie = (name: string) => {
  return Cookies.get(name) ||
    Cookies.get(name, { path: '/', domain: '.ratingdog.cn' })
}
1.9 清空cookie
/**
 * 清空cookie
 */
export const delAllCookie = () => {
  const keys = document.cookie.match(/[^ =;]+(?==)/g)
  if (keys) {
    for (let i = keys.length; i--;) {
      document.cookie =
        keys[i] + '=0;path=/;expires=' + new Date(0).toUTCString() // 清除当前域名下的,例如:m.ratingdog.cn
      document.cookie =
        keys[i] +
        '=0;path=/;domain=' +
        document.domain +
        ';expires=' +
        new Date(0).toUTCString() // 清除当前域名下的,例如 .m.ratingdog.cn
      document.cookie =
        keys[i] +
        '=0;path=/;domain=rd2.ratingdog.cn;expires=' +
        new Date(0).toUTCString() // 清除一级域名下的或指定的,例如 .ratingdog.cn
    }
  }
}
2.0 删除指定名称的cookie的值
/**
 * 删除指定名称的cookie的值
 * @param {String} name
 */
export const delCookie = (name: string) => {
  // 获取指定名称的cookie的值
  Cookies.remove(name)
  const pathArr = ['/']
  const doaimArr = [document.domain, '.ratingdog.cn']
  pathArr.forEach(path => {
    setCookie(name, '', 0, path)
    Cookies.remove(name, { path, domain: document.domain })
    doaimArr.forEach(domain => {
      Cookies.remove(name, { path, domain })
    })
    // Cookies.remove(name, { path, domain: '.ratingdog.cn' })
    // Cookies.remove(name, { path, domain: 'www.ratingdog.cn' })
    // Cookies.remove(name, { path, domain: 'm.ratingdog.cn' })
  })
}
2.1 删除指定名称的cookie的值
/**
 * 删除指定名称的cookie的值
 * @param {String} name
 */
export const delCookie2 = (name: string) => { // 获取指定名称的cookie的值
  Cookies.remove(name)
  const pathArr = [
    '/',
    '/rating',
    '/rating/',
    '/rating/rating',
    '/rating/newDebt',
    '/rating/transaction',
    '/rating/frontDeskDeal',
    '/rating/report',
    '/rating/cityVote',
    '/rating/highYieldDebt',
    '/research',
    '/curve',
    '/schedule',
    '/comparison',
    '/dataSheet',
    '/spreadChart',
    '/spreadChart',
    '/economic',
    '/personalCenter',
    '/securitySettings',
    '/messageBox',
    '/FDDNotice',
    '/register',
    '/privacyPolicy',
    '/previewPDF',
    '/bindPhone',
    '/retrievePSD',
    '/subjectReview',
    '/ratingTable'
  ]
  const doaimArr = [
    document.domain,
    '.ratingdog.cn',
    'www.ratingdog.cn',
    'm.ratingdog.cn'
  ]
  pathArr.forEach(path => {
    setCookie(name, '', 0, path)
    Cookies.remove(name, { path, domain: document.domain })
    doaimArr.forEach(domain => {
      Cookies.remove(name, { path, domain })
    })
    // Cookies.remove(name, { path, domain: '.ratingdog.cn' })
    // Cookies.remove(name, { path, domain: 'www.ratingdog.cn' })
    // Cookies.remove(name, { path, domain: 'm.ratingdog.cn' })
  })
}
2 判断平台环境方法
2.1 判断微信环境
/**
 * 判断微信环境
 * @return {Boolean} 返回是否在微信
 */
export const isWeChat = () => {
  const ua = navigator.userAgent.toLowerCase()
  if (ua.match(/MicroMessenger/i) + '' === 'micromessenger') {
    return true
  }
  return false
}
2.2 判断手机是安卓还是ios
/**
 * 判断手机是安卓还是ios
 * @return {Boolean} 返回是否在安卓
 */
export const isAndroid = () => {
  const u = navigator.userAgent
  const isAndroid = u.includes('Android') || u.includes('Adr') // android终端
  // var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/) // ios终端
  if (isAndroid) return true
  return false
}
2.3 判断是否是PC端
/**
 * 判断是否是PC端
 * @return {Boolean} 返回是否是PC端
 */
export const IsPC = () => {
  const userAgentInfo = navigator.userAgent
  const Agents = [
    'Android',
    'iPhone',
    'SymbianOS',
    'Windows Phone',
    'iPad',
    'iPod'
  ]
  let flag = true
  for (let v = 0; v < Agents.length; v++) {
    if (userAgentInfo.indexOf(Agents[v]) > 0) {
      flag = false
      break
    }
  }
  return flag
}
2.4 判断浏览器是否支持3D属性
/**
 * 判断浏览器是否支持3D属性
 * @return {Boolean} 返回判断结果
 */
export const has3d = () => {
  if (!window.getComputedStyle) {
    return false
  }

  const el: any = document.createElement('p')
  let has3d
  const transforms: any = {
    webkitTransform: '-webkit-transform',
    OTransform: '-o-transform',
    msTransform: '-ms-transform',
    MozTransform: '-moz-transform',
    transform: 'transform'
  }

  // Add it to the body to get the computed style.
  document.body.insertBefore(el, null)

  for (const t in transforms) {
    if (el.style[t] !== undefined) {
      el.style[t] = 'translate3d(1px,1px,1px)'
      has3d = window.getComputedStyle(el).getPropertyValue(transforms[t])
    }
  }

  document.body.removeChild(el)

  return has3d !== undefined && has3d.length > 0 && has3d !== 'none'
}
2.5 判断浏览器是否为IE
/**
 * 判断浏览器是否为IE
 * @return {Boolean} 返回判断结果
 */
export const isIE = () => {
  return !!window.ActiveXObject || 'ActiveXObject' in window
}
##### 3 处理字符串方法
###### 3.1 获取url地址参数
/**
 * 获取url地址参数
 * @param  {String} name 地址参数键
 * @return {string | null} 返回地址参数值,找不到返回null
 */
export const getQueryString = (name: string) => {
  const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i')
  const r = window.location.search.substr(1).match(reg)
  if (r != null) return unescape(r[2])
  return null
}
3.2 获取字符串长度(区分英文汉字)
/**
 * 获取字符串长度(区分英文汉字)
 * @param  {String} str 地址参数键
 * @return {Number} 返回字符串长度
 */
export const strlen = (str: string) => {
  let len = 0
  for (let i = 0; i < str.length; i++) {
    const c = str.charCodeAt(i)
    // 单字节加1
    if ((c >= 0x0001 && c <= 0x007e) || (c >= 0xff60 && c <= 0xff9f)) {
      len++
    } else {
      len += 2
    }
  }
  return len
}
3.3 判断是否存在空格
/**
 * 判断是否存在空格
 * @param  {String} str 邮箱地址
 * @return {Boolean} 返回验证结果
 */
export const blank = (str: string) => {
  const reg = /\s/
  if (reg.test(str)) {
    return true
  }
  return false
}
3.4 判断url中是否含有某个值
/**
 * 判断url中是否含有某个值
 * @param  {String} name 需要查询的值
 * @return {Boolean} 返回判断结果
 */
export const urlJudgment = (name: string) => {
  const href = window.location.href
  if (href.includes(name)) return true
  return false
}
3.5 字符串过滤
/**
 * 字符串过滤
 * @param  {String} str 需要查询的值
 * @return {String} 返回处理过后的字符串
 */
export const strFilter = (str: string) => {
  const arr = str.split('.')
  return arr[0]
}
3.6 判断是否时json字符串
/**
 * 判断是否时json字符串
 * @param {String} str 需要判断的字符串
 * @return {Boolean} 返回判断结果
 */
export const isJSON = (str: string) => {
  if (typeof str === 'string') {
    try {
      const obj = JSON.parse(str)
      if (typeof obj === 'object' && obj) {
        return true
      } else {
        return false
      }
    } catch (e) {
      return false
    }
  }
}
3.7 获取当前静态资源url
/**
 * 获取当前静态资源url
 * @return {String} 返回当前静态资源url
 */
export const getStaticUrl = () => {
  const href = window.location.href
  const arr = href.split('#')[0].split('/')
  arr.pop()
  const result = arr.join('/')
  return result
}
3.8 去除字符串首尾空格
/**
 * 去除字符串首尾空格
 * @param {String} str 需要处理的字符串
 * @return {String} 返回当前静态资源url
 */
export const trim = (str: string) => {
  return str.replace(/^(\s|\u00A0)+/, '').replace(/(\s|\u00A0)+$/, '')
}
3.9 去除字符串两侧空格
/**
 * 去除字符串两侧空格
 * @param {Any} this 当前组件this
 * @param {String} str 需要处理的字符串
 * @param {String} name 名称
 * @param {Boolean} isForm 是否有前缀form
 * @param {String} formStr form 包含两层字段
 */
export const removeSpaces = function (this: any, str: string, name: string, isForm = false, formStr = '') {
  if (isForm) {
    formStr ? this.form[name][formStr] = str && str.trim() : this.form[name] = str && str.trim()
  } else {
    this[name] = str ? str.trim() : ''
  }
}
3.10 将url地址参数分解为对象形式
/**
 * 将url地址参数分解为对象形式
 * @param {String} url 需要处理的url地址
 * @return {Object} 返回对象形式url地址
 */
export const queryString = (url: string) => {
  let arr = [] // 存储参数的数组
  const res: any = {} // 存储最终JSON结果对象
  const params = url.split('?')[1] || ''
  arr = params.split('&') // arr=["a=1", "b=2", "c=test", "d"]

  for (let i = 0, len = arr.length; i < len; i++) {
    // 如果有等号,则执行赋值操作
    if (arr[i].includes('=')) {
      const str = arr[i].split('=')
      res[str[0]] = str[1]
    } else {
      // 没有等号,则赋予空值
      res[arr[i]] = ''
    }
  }
  // res = JSON.stringify(res)// 转化为JSON字符串
  return res // {"a": "1", "b": "2", "c": "test", "d": ""}
}
3.11 处理电话前缀
/**
 * 处理电话前缀
 * @param {String} preInput 电话前缀
 * @return {String} 返回处理过后的电话前缀
 */
export const getPreInput = (preInput: string) => {
  let result = preInput || '86'
  if (result[0] === '+') result = result.substr(1)
  return result
}
3.12 按字节长度截取字符串
/**
 * 按字节长度截取字符串
 * @param {String} str 要截取的字符串
 * @param {Number} L 要截取的字节长度,注意是字节不是字符,一个汉字两个字节
 * @return {String} 返回截取的字符串
 */
export const cutStr = (str: string, L: number) => {
  let result = ''
  const strlen = str.length // 字符串长度
  const chrlen = str.replace(/[^x00-\xff]/g, '**').length // 字节长度

  if (chrlen <= L) {
    return str
  }

  for (let i = 0, j = 0; i < strlen; i++) {
    const chr = str.charAt(i)
    if (/[x00-\xff]/.test(chr)) {
      j++ // ascii码为0-255,一个字符就是一个字节的长度
    } else {
      j += 2 // ascii码为0-255以外,一个字符就是两个字节的长度
    }
    if (j <= L) {
      // 当加上当前字符以后,如果总字节长度小于等于L,则将当前字符真实的+在result后
      result += chr
    } else {
      // 反之则说明result已经是不拆分字符的情况下最接近L的值了,直接返回
      return result
    }
  }
}
3.13 处理YY评级字段
/**
 * 处理YY评级字段
 * @param {String | null} YYRating YY评级
 */
export const handleYYRating = (YYRating: string | null) => {
  let result = 0
  if (!YYRating || YYRating === '-') return result
  if (YYRating[1]) { // 有 + | -
    if (YYRating[1] === '+') {
      result = parseInt(YYRating[0]) - 0.3
    } else {
      result = parseInt(YYRating[0]) + 0.3
    }
  } else {
    result = parseInt(YYRating)
  }
  return result
}
3.14 处理期限字段
/**
 * 处理期限字段
 * @param {String | null} term 期限
 */
export const handleTerm = (term: string | null) => {
  let result = 0
  if (!term || term === '-') return result
  result = parseFloat(term.split('(')[0]) // 只取(前的
  return result
}
3.15 处理剩余期限字段
/**
 * 处理剩余期限字段
 * @param {String | null} residualMaturity 剩余期限
 */
export const handleResidualMaturity = (residualMaturity: string | null) => {
  let result = 0
  if (!residualMaturity || residualMaturity === '-') return result
  const str = residualMaturity.split('+')[0] // 只取+前的
  if (residualMaturity.includes('Y')) { // Y为单位
    result = str === 'Y' ? 1 : parseFloat(str)
  } else {
    result = parseFloat(str) / 365 //  D结尾除以365
  }
  return result
}
3.16 获取加密字符串 中间带*
/**
 * 获取加密字符串 中间带*
 * @param {String} str 需要处理的字符串
 */
export const encryptedString = (str: string): string => {
  if (!str) return '-'
  const phone = str.split('')
  let result = ''
  phone.splice(3, 4, '****')
  result = phone.join('')
  return result
}
3.17 富文本字符格式加粗处理
// 富文本字符格式加粗处理  使用时把下面注释打开
export const richTextFormat = (html: string) => {
  let str = html
  // 标签加粗处理 使用时把下面注释打开
  <!-- const boldArr = ['<strong>', '<h1>', '<h2>'] -->
  if (str) {
    boldArr.map(el => {
      if (str.includes(el)) {
        str = str.split(el).join(el.split('>').join(' style="font-weight:bold">'))
      }
    })
  }
  return str
}
3.18 url转码
// url转码
export const urlencode = (str: string) => {
  str = (str + '').toString()

  return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28')
    .replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+')
}
3.19 字符串比较 排序
// 字符串比较
export const localeCompareHandler = (arr: any[], sortParamKey: string, SortingName: string, filterVal?: any) => {
  if (!SortingName) return [...arr]
  const { emptyValDatas, sortDatas } = splitData(arr, sortParamKey, filterVal)
  if (['ascending', 'ASC'].includes(SortingName)) {
    sortDatas.sort((data1: any, data2: any) => data1[sortParamKey].localeCompare(data2[sortParamKey]))
  } else if (['descending', 'DES'].includes(SortingName)) {
    sortDatas.sort((data1: any, data2: any) => data2[sortParamKey].localeCompare(data1[sortParamKey]))
  }
  return [...sortDatas, ...emptyValDatas]
}
4 正则校验
4.1 手机号码验证
/**
 * 手机号码验证
 * @param  {String} str 手机号码
 * @return {Boolean} 返回验证结果
 */
export const pattern = (str: string) => {
  const pattern = /^1(3|4|5|6|7|8|9)\d{9}$/
  return pattern.test(str)
}
4.2 邮箱验证
/**
 * 邮箱验证
 * @param  {String} str 邮箱地址
 * @return {Boolean} 返回验证结果
 */
export const emaileVer = (str: string) => {
  const reg = /^([a-zA-Z]|[0-9])(\w|-|\.)+@[a-zA-Z0-9](\w|-|\.)+\.([a-zA-Z]{2,4})$/
  if (reg.test(str)) {
    return true
  }
  return false
}
4.3 密码验证 必须包含字母和数字
/**
 * 密码验证 必须包含字母和数字
 * @param  {String} str 密码
 * @return {Boolean} 返回验证结果
 */
export const psdVer = (str: string) => {
  const reg = /([0-9]+[a-zA-Z]+|[a-zA-Z]+[0-9]+)[0-9a-zA-Z]*/
  if (reg.test(str)) {
    return true
  } else {
    return false
  }
}
5 时间日期类方法
5.1 将时间戳改为时间格式
/**
 * 将时间戳改为时间格式
 * @param  {[Number || String]} time 时间戳
 * @param  {[String]} format 时间格式 yyyy-MM-dd hh:mm:ss
 * @return {[String]} 返回需要的时间
 */
export const changeTimeType = (
  time: number | string | Date,
  format: string
) => {
  if (typeof time === 'string') time = (time + '').replace(/-/g, '/')
  const date = new Date(time) // 获取一个时间对象  注意:如果是uinx时间戳记得乘于1000。比如php函数time()获得的时间戳就要乘于1000
  // 定义一个数组接收时间格式所有数据
  const formatArr: any = [
    // txt: 所属字段 -- index: 当前所处索引位置
    { yyyy: '', txt: 'yyyy', index: 0 }, // 年
    { MM: '', txt: 'MM', index: 1 }, // 月
    { dd: '', txt: 'dd', index: 2 }, // 日
    { hh: '', txt: 'hh', index: 3 }, // 时
    { mm: '', txt: 'mm', index: 4 }, // 分
    { ss: '', txt: 'ss', index: 5 } // 秒
  ]
  // 如果含有当前字段 做响应处理
  if (format.includes(formatArr[0].txt)) formatArr[0].yyyy = date.getFullYear() + ''
  if (format.includes(formatArr[1].txt)) {
    formatArr[1].MM =
      (date.getMonth() + 1 < 10
        ? '0' + (date.getMonth() + 1)
        : date.getMonth() + 1) + ''
  }
  if (format.includes(formatArr[2].txt)) {
    formatArr[2].dd =
      (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ''
  }
  if (format.includes(formatArr[3].txt)) {
    formatArr[3].hh =
      (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ''
  }
  if (format.includes(formatArr[4].txt)) {
    formatArr[4].mm =
      (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()) +
      ''
  }
  if (format.includes(formatArr[5].txt)) {
    formatArr[5].ss =
      (date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()) +
      ''
  }
  // 获取中间格式
  const splitArr = format.split(/yyyy|MM|dd|hh|mm|ss/)
  for (let i = 0; i < formatArr.length; i++) {
    // 给索引赋值
    formatArr[i].index = format.indexOf(formatArr[i].txt)
    if (format.includes(formatArr[i].txt)) {
      // 如果不存在当前项则跳过
      continue
    } else {
      // 否则插入当前项
      splitArr.splice(i, 0, '')
    }
  }
  // 排序数组
  for (let i = 0; i < formatArr.length - 1; i++) {
    for (let j = 0; j < formatArr.length - 1 - i; j++) {
      if (formatArr[j + 1].index < 0) continue
      if (formatArr[j].index > formatArr[j + 1].index) {
        const temp = formatArr[j]
        formatArr[j] = formatArr[j + 1]
        formatArr[j + 1] = temp
      }
    }
  }
  // 拼接字符串得到结果
  let result = ''
  for (let i = 0; i < formatArr.length; i++) {
    if (formatArr[i].txt) {
      result += splitArr[i] + formatArr[i][formatArr[i].txt]
    }
  }
  return result
}
5.2 将时间戳转为时间格式 日 时 分 秒
/**
 * 将时间戳转为时间格式 日 时 分 秒
 * @param {Number} mss 时间戳
 * @param {Unit} unit 时间单位
 * @return {String} 返回转化过后的时间格式
 */
export interface Unit {
  day: string;
  hour: string;
  minute: string;
  second: string;
}
export const formatDuring = (
  mss: number,
  unit: Unit = {
    day: '天',
    hour: '小时',
    minute: '分钟',
    second: '秒'
  }
) => {
  const days = parseInt(mss / (1000 * 60 * 60) / 24 + '')
  const hours = parseInt((mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60) + '')
  const minutes = parseInt((mss % (1000 * 60 * 60)) / (1000 * 60) + '')
  const seconds = parseInt((mss % (1000 * 60)) / 1000 + '')
  let result = ''
  if (days) {
    result = days + unit.day
  } else if (hours) {
    result = hours + unit.hour
  } else if (minutes) {
    result = minutes + unit.minute
  } else if (seconds) {
    result = seconds + unit.second
  }
  return result
}
5.3 将时间改为时间戳格式
/**
 * 将时间改为时间戳格式
 * @param {String} time 时间
 */
export const getTimestamp = (time?: string) => {
  if (time) return new Date(time).getTime()
  return new Date().getTime() // 如果没传time值 获取当前时间
}
5.4 转换时间格式 处理8小时时间差
/**
 * 转换时间格式 处理8小时时间差
 * @param {Date} time 需要转换的时间
 */
export const getTime = (time: Date | ''): Date | '' => {
  if (!time) return ''
  const date = new Date(time).getTime()
  return new Date(date)
}
5.5 获取时间区间末尾项 加一天
/**
 * 获取时间区间末尾项 加一天
 * @param {Date} time 需要转换的时间
 */
export const getEndTime = (time: Date | '' | null): Date | '' => {
  if (!time) return ''
  const date = new Date(time).getTime() + 24 * 60 * 59 * 1000
  return new Date(date)
}
5.6 转换时间格式 处理8小时时间差
/**
 * 转换时间格式 处理8小时时间差
 * @param {Date} string 需要转换的时间
 */
export const getTimeAdd8h = (time: Date | '' | null): Date | '' => {
  if (!time) return ''
  const date = new Date(time).getTime() + 8 * 60 * 60 * 1000
  // const date = changeTimeType(time, 'yyyy-MM-dd')
  // const date = (new Date(time)).getTime()
  return new Date(date)
  // return date
}
5.7 转换时间格式 添加天数
/**
 * 转换时间格式 添加天数
 * @param {Date} string 需要转换的时间
 * @param {Date} num 需要添加的天数
 */
export const getTimeAdd1d = (time: Date | '', num: number): Date | '' => {
  if (!time) return ''
  const date = new Date(time).getTime() + 24 * 60 * 60 * 1000 * num
  return new Date(date)
}
5.8 获得上周周一 - 周日的年月日
// 获得上周周一 - 周日的年月日
export const getLastWeekData = () => {
  const lastweek = {} as any
  const date = new Date()
  // 上周一的日期
  date.setDate(date.getDate() - 7 - date.getDay() + 1)
  const month = date.getMonth() + 1 > 9 ? date.getMonth() + 1 : '0' + (date.getMonth() + 1)
  lastweek.startDay = date.getFullYear() + '.' + month + '.' + (date.getDate() > 9 ? date.getDate() : '0' + (date.getDate()))

  // 上周日的日期
  date.setDate(date.getDate() + 6)
  lastweek.endDay = date.getFullYear() + '.' + month + '.' + (date.getDate() > 9 ? date.getDate() : '0' + (date.getDate()))
  return lastweek.startDay + '-' + lastweek.endDay
}
5.9 获取上一个月日期
// 获取上一个月日期
export const getLastMonth = () => {
  const date = new Date()
  let year = date.getFullYear() // 当前年:四位数字
  let month: string | number = date.getMonth() // 当前月:0-11

  if (month === 0) { // 如果是0,则说明是1月份,上一个月就是去年的12月
    year -= 1
    month = 12
  }
  month = month < 10 ? ('0' + month) : month // 月份格式化:月份小于10则追加个0
  const lastYearMonth = year + '.' + month
  return lastYearMonth
}
5.10 获取昨天的日期
// 获取昨天的日期
export const getYesterdayDate = () => {
  const day1 = new Date()
  day1.setTime(day1.getTime() - 24 * 60 * 60 * 1000)
  // const s1 = day1.getFullYear() + '-' + (day1.getMonth() + 1) + '-' + day1.getDate()
  return changeTimeType(day1, 'yyyy.MM.dd')
}
5.11 获取当前的季度
// 获取当前的季度
export const getQuarterDate = () => {
  const today = new Date()
  // 得到上一个季度的第一天
  const lastQuarterFirstDay = new Date(today.getFullYear(), today.getMonth() - 3, 1)
  const year = lastQuarterFirstDay.getFullYear() // 获取完整的年份(4位)
  const month = lastQuarterFirstDay.getMonth() + 1 // 获取当前月份(0-11,0代表1月)
  let q = ''
  if (month <= 3) {
    q = 'Q1'
  } else if (month > 3 && month <= 6) {
    q = 'Q2'
  } else if (month > 6 && month <= 9) {
    q = 'Q3'
  } else if (month > 9 && month <= 12) {
    q = 'Q4'
  }
  return year.toString() + '年' + q
}
5.12 比较两个日期字符串大小
/**
 * @description: 比较两个日期字符串大小 不保证传入参数是否为空
 * @param { string } d1 比较日期
 * @param { string } d2 被日期
 * @return { bool } bool 结果
 */
export const compareDate = (d1: string | null, d2: string | null) => {
  if (d1 === null || d1 === '' || d1 === undefined) {
    return false
  } else if (d2 === null || d2 === '' || d2 === undefined) {
    return true
  } else {
    return ((new Date(d1.replace(/-/g, '\/'))) > (new Date(d2.replace(/-/g, '\/'))))
  }
}
5.13 日期比较
// 日期比较
export const dateSortHandler = (arr: any[], sortParamKey: string, SortingName: string, filterVal?: any) => {
  if (!SortingName) return [...arr]
  const { emptyValDatas, sortDatas } = splitData(arr, sortParamKey, filterVal)
  if (['ascending', 'ASC'].includes(SortingName)) {
    sortDatas.sort((data1: any, data2: any) => new Date(data1[sortParamKey] as Date).getTime() - new Date(data2[sortParamKey] as Date).getTime()
    )
  } else if (['descending', 'DES'].includes(SortingName)) {
    sortDatas.sort((data1: any, data2: any) => new Date(data2[sortParamKey] as Date).getTime() - new Date(data1[sortParamKey] as Date).getTime()
    )
  }
  return [...sortDatas, ...emptyValDatas]
}
6 对象方法集合
6.1 深度拷贝
/**
 * 深度拷贝
 * @param {Object} obj 需要拷贝的对象
 * @return {Object} 返回处理过后的对象
 */
export const cloneObject = (obj: object) => {
  try {
    const _obj = JSON.stringify(obj)
    const objClone = JSON.parse(_obj)
    return objClone
  } catch (error) {
    return obj
  }
}
6.2 遍历递归拷贝
/**
 * 遍历递归拷贝
 * @param {Object} obj 需要拷贝的对象
 * @return {Object} 返回处理过后的对象
 */
export const cloneObjectOther = (obj: any) => {
  let temp: any = null
  if (obj instanceof Array) {
    temp = obj.concat()
  } else if (obj instanceof Function) {
    temp = obj
  } else {
    temp = {}
    for (const item of Object.keys(obj)) {
      const val = obj[item]
      temp[item] = typeof val === 'object' ? cloneObjectOther(val) : val
    }
  }
  return temp
}
6.3 获取整洁的对象(去除值为空的对象)
/**
 * 获取整洁的对象(去除值为空的对象)
 * @param {Object} obj 需要处理的对象
 * @param {Boolean} saveArray 是否保留数组
 * @return {Object} 返回处理过后的对象
 */
export const getCleanObj = (obj: any, saveArray?: boolean) => {
  const filter: any = {}
  for (const key in obj) {
    // 只传入有值的项
    if (obj[key] || obj[key] === false || obj[key] === 0) {
      // 如果该项有值
      if (typeof obj[key] === 'object' && !(obj[key] instanceof Date) && ((saveArray && !Array.isArray(obj[key])) || !saveArray)) {
        // 如果还有内层对象
        let isNull = true
        for (const key2 in obj[key]) {
          if (
            obj[key][key2] ||
            obj[key][key2] === false ||
            obj[key][key2] === 0
          ) {
            // 只要有某个有值
            isNull = false
            break
          }
        }
        if (!isNull) {
          filter[key] = obj[key]
        }
      } else {
        filter[key] = obj[key]
      }
    }
  }
  return filter
}
6.4 对象深拷贝
/**
 * This is just a simple version of deep copy
 * Has a lot of edge cases bug
 * If you want to use a perfect deep copy, use lodash's _.cloneDeep
 * @param {Object} source
 * @returns {Object}
 */
export function deepClone (source: any) {
  if (!source && typeof source !== 'object') {
    throw new Error('error arguments')
  }
  const targetObj: any = source.constructor === Array ? [] : {}
  Object.keys(source).forEach(keys => {
    if (source[keys] && typeof source[keys] === 'object') {
      targetObj[keys] = deepClone(source[keys])
    } else {
      targetObj[keys] = source[keys]
    }
  })
  return targetObj
}
6.5 检查对象是否为空
/**
 * @description: 检查对象是否为空
 * @param {object} obj 对象
 * @return {boolean}
 */
export const getObjectIsEmpty = (obj: object): boolean => {
  let bool = false
  if (obj && Object.prototype.toString.call(obj) === '[object Object]') {
    bool = Object.keys(obj).length < 1
  }
  return bool
}
6.7 ecahrt对象数据是否都为0
/**
 * ecahrt对象数据是否都为0
 * @param name 排除x轴的名称
 * @param obj 传入的对象
 * @returns
 */
export const ObjectDataIsNil = (name: string, obj: any) => {
  let sum = 0
  for (const key in obj) {
    if (key !== name) {
      const number = typeof obj[key] === 'string' ? parseFloat(obj[key]) : Number(obj[key])
      sum += Math.abs(number)
    }
  }
  return sum
}
7 数组方法集合
7.1 从数组中找到含有某个键值对的数组索引
/**
 * 从数组中找到含有某个键值对的数组索引
 * @param {Array} arraytosearch 搜索的数组
 * @param {String} key 键
 * @param {String} valuetosearch 值
 * @return {Number} 返回索引 没找到返回null
 */
export const findIndexByKeyValue = (
  arraytosearch: any,
  key: string,
  valuetosearch: string
) => {
  for (let i = 0; i < arraytosearch.length; i++) {
    if (arraytosearch[i][key] === valuetosearch) {
      return i
    }
  }
  return null
}
7.2 包含对象的数组去重 返回新数组
/**
 * 包含对象的数组去重 返回新数组
 * @param {T[]} 泛型数组
 * @return {T[]} 泛型数组
 */
export function uniqueArray<T> (arr: T[]): T[] {
  const newArr: T[] = []
  arr.forEach((el: T) => {
    let state = true
    const s1: string = Object.values(el as any).join('')
    for (let n = 0; n < newArr.length; n++) {
      const s2: string = Object.values(newArr[n] as any).join('')
      if (s1 === s2) {
        state = false
        break
      }
    }
    if (state) {
      newArr.push(el)
    }
  })
  return newArr
}
7.3 数组去重
/**
 * 数组去重
 * @param {Array} arr 待处理数组
 * @returns {Array} 返回新数组
 */
export const unique = (arr: any[]): any[] => {
  // 如果新数组的当前元素的索引值 == 该元素在原始数组中的第一个索引,则返回当前元素
  return arr.filter((item, index) => {
    return arr.indexOf(item, 0) === index
  })
}
7.3 传入数组参数 检查所有参数是否为空值
// 传入数组参数 检查所有参数是否为空值
export const handleCheckParamsIsNullForArray = (arr: any[]) => {
  if (!arr || arr.length === 0) return true
  let isNull = false
  isNull = arr.some((el) => {
    return el !== null && el !== undefined && (Array.isArray(el) ? el.length > 0 : el !== '')
  })
  return isNull
}
7.4 分割排序集合与空值集合
// 分割排序集合与空值集合
export const splitData = (arr: any[], paramName: string, filterVal?: any) => {
  const emptyValDatas = [] as any[]
  const sortDatas = [] as any[]
  arr.forEach(item => {
    if (item[paramName] === null || item[paramName] === undefined || item[paramName] === '') emptyValDatas.push(item)
    else if (filterVal !== undefined && item[paramName] === filterVal) emptyValDatas.push(item)
    else sortDatas.push(item)
  })
  return { emptyValDatas, sortDatas }
}
7.5-扁平化数据树化
/**
 * @description 扁平数组转树结构---父子id对应的数据
 * @param { Array } flatArrData 初始扁平数据
 * @param { Function } callBack 自定义数据格式
 */
  export const ArrayToTreeReduce = (flatArrData: any, callBack: any) => {
    const map: any = {}
    const tree = flatArrData.reduce((acc: any, node: any) => {
      map[node.id] = { ...callBack(node), children: [] }
      if (node.parentId === null) {
        acc.push(map[node.id])
      } else {
        map[node.parentId].children.push(map[node.id])
      }
      return acc
    }, [])
    return tree
  }
7.6-扁平化数据树化
/**
   * @description 给每个层级打上标记
   * @param {Array} data 打标记的数据
   * @param {Number} level 打标记的数据
   */
export const ArrayFlagLevel = (data: any, level: number) => {
  if (!data || !data.length) return
  data.forEach((item: any) => {
    item.level = level
    if (item.children && item.children.length) {
      ArrayFlagLevel(item.children, level + 1)
    }
  })
}
7.7-table列合并
/**
 * table列合并
 * @param { string } id 需要合并字段
 * @param { number } rowIndex 当前行
 * @param { any } data 列表数据
 */
export const mergeCol = (id: string, rowIndex: number, data: any) => {
  // 合并单元格
  // id:属性名
  // rowIndex:行索引值
  const idName = data[rowIndex][id] // 获取当前单元格的值
  if (rowIndex > 0) {
    // 判断是不是第一行
    // eslint-disable-next-line eqeqeq
    if (data[rowIndex][id] != data[rowIndex - 1][id]) {
      // 先判断当前单元格的值是不是和上一行的值相等
      let i = rowIndex
      let num = 0 // 定义一个变量i,用于记录行索引值并进行循环,num用于计数
      while (i < data.length) {
        // 当索引值小于table的数组长度时,循环执行
        if (data[i][id] === idName) {
          // 判断循环的单元格的值是不是和当前行的值相等
          i++ // 如果相等,则索引值加1
          num++ // 合并的num计数加1
        } else {
          i = data.length // 如果不相等,将索引值设置为table的数组长度,跳出循环
        }
      }
      return {
        rowspan: num, // 最终将合并的行数返回
        colspan: 1
      }
    } else {
      return {
        rowspan: 0, // 如果相等,则将rowspan设置为0
        colspan: 1
      }
    }
  } else {
    // 如果是第一行,则直接返回
    let i = rowIndex
    let num = 0
    while (i < data.length) {
      // 当索引值小于table的数组长度时,循环执行
      if (data[i][id] === idName) {
        i++
        num++
      } else {
        i = data.length
      }
    }
    return {
      rowspan: num,
      colspan: 1
    }
  }
}
8 dom元素方法
8.1 平滑滚动
/**
 * 平滑滚动
 * @param {Element} dom dom元素
 * @param {Number} target 滚动距离
 */
export const smoothScrolling = (dom: Element, target: number) => {
  const timer = setInterval(function () {
    let leader = dom.scrollTop || 0
    let temp = (target - leader) / 10
    temp = temp > 0 ? Math.ceil(temp) : Math.floor(temp)
    leader = leader + temp
    if (
      target <= leader ||
      dom.scrollTop + dom.clientHeight >= dom.scrollHeight
    ) {
      // 已经超过目标值 | 已经滚动到底部
      dom.scrollTo(0, target)
      clearInterval(timer)
    } else {
      try {
        dom.scrollTo(0, leader)
      } catch (error) {
        clearInterval(timer)
      }
    }
  }, 15)
}
8.2 获取dom元素的指定样式
/**
 * 获取dom元素的指定样式
 * @param {any} dom 需要查询的dom元素
 * @param {String} style 需要查询的样式名称
 */
export const getStyle = (dom: any, style: string) => {
  return dom.style[style]
}
8.3 获取滚动条的宽度
/**
 * 获取滚动条的宽度
 */
export const getScrollbarWidth = () => {
  const odiv: any = document.createElement('div') // 创建一个div
  const styles: any = {
    width: '100px',
    height: '100px',
    overflowY: 'scroll' // 让他有滚动条
  }
  let i: any = ''
  let scrollbarWidth: any = ''
  for (i in styles) odiv.style[i] = styles[i]
  document.body.appendChild(odiv) // 把div添加到body中
  scrollbarWidth = odiv.offsetWidth - odiv.clientWidth // 相减
  odiv.remove() // 移除创建的div
  return scrollbarWidth // 返回滚动条宽度
}
8.4 判断是否需要展示提示 。。。
// 判断是否需要展示提示
export const showTips = (obj: any, data: any, key: string, fontSize = '14px') => {
  const TemporaryTag = document.createElement('span')
  TemporaryTag.innerText = data[key]
  TemporaryTag.className = 'getTextWidth'
  TemporaryTag.style.fontSize = fontSize
  ;(document.querySelector('body') as any).appendChild(TemporaryTag)
  const currentWidth = (document.querySelector('.getTextWidth') as any).offsetWidth

  ;(document.querySelector('.getTextWidth') as any).remove()
  /* cellWidth为表格容器的宽度*/
  const cellWidth = obj.target.offsetWidth
  /* 当文本宽度小于||等于容器宽度,代表文本显示未超出*/

  return !(currentWidth <= cellWidth)
}
9 文件格式
9.1 文件格式限制
/**
 * 文件格式限制
 * @param {String | Number} moduleType 模块名称
 */
export const fileSuffixs = (moduleType: string) => {
  const fileTypeArr = [
    {
      type: 'application/pdf',
      moduleTypeList: ['研究报告', '客户管理', '调研交流']
    },
    {
      type: 'audio/mpeg',
      moduleTypeList: ['研究报告']
    },
    {
      type: 'application/msword',
      moduleTypeList: ['研究报告', '客户管理', '调研交流']
    },
    {
      type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
      moduleTypeList: ['研究报告', '客户管理', '调研交流']
    },
    {
      type: 'application/vnd.ms-excel',
      moduleTypeList: ['客户管理']
    },
    {
      type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      moduleTypeList: ['客户管理']
    },
    {
      type: 'application/vnd.ms-powerpoint',
      moduleTypeList: ['客户管理']
    },
    {
      type: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
      moduleTypeList: ['客户管理']
    },
    {
      type: 'image/png',
      moduleTypeList: ['调研交流']
    },
    {
      type: 'image/jpeg',
      moduleTypeList: ['调研交流']
    }
  ]
  const fileTypeList = fileTypeArr.filter(item => {
    if (item.moduleTypeList.includes(moduleType)) return item
  }).map(item => item.type)
  return fileTypeList
}
10 数字相关方法
10.1 数字加千位分隔符
/**
 * 数字加千位分隔符
 * @param {String | Number} num 需要处理的数字
 */
export const addThousandsSeparator = (num: string | number) => {
  const res = num.toString().replace(/\d+/, function (n) {
    // 先提取整数部分
    return n.replace(/(\d)(?=(\d{3})+$)/g, function ($1) {
      return $1 + ','
    })
  })
  return res
}
10.2 字符串去除千位分隔符
/**
 * 字符串去除千位分隔符
 * @param {String} str 需要处理的字符串
 */
export const removeThousandsSeparator = (str: string | number) => {
  // 处理非字符及数字
  if (typeof str !== 'string' && typeof str !== 'number') {
    str = '-'
  }
  const res = str.toString().replace(/,/g, '')
  return res
}
10.3 检查是否数字
/**
 * @description: 检查是否数字
 * @param {any} value
 * @return {boolean}
 */
export const customIsNumber = (value: any) => {
  return (typeof value === 'number' && !isNaN(value))
}
10.4 四舍五入保留数值指定小数位
/**
 * @description: 四舍五入保留数值指定小数位 (默认两位 不够位数使用0替补) 保留数据单位文本描述
 * @param {string | number | null} value 参数值
 * @param {number} places 指定小数位
 * @param {boolean} needUnit 是否需要保存单位文本描述
 * @return {string} val 四舍五入保留值
 */
export const keepDecimalPlaces = (value: string | number | null, places = 2, needUnit = true) => {
  const reg = /-?\d*\.?\d+/
  if (value && isNaN(Number(value))) {
    return value.toString()
  }
  if (!value || value === '') {
    return '00.00'
  }
  const valueStr = value.toString()
  const arr: (string | number)[] | null = reg.exec(valueStr)
  let val: string = valueStr
  if (arr && arr[0]) {
    const replaceLen = arr[0].toString().length
    const maxLen = valueStr.length
    let power = 10 ** 2
    // 检查幂
    if (customIsNumber(places)) {
      power = 10 ** places
    }
    // 四舍五入
    val = (Math.floor(parseFloat(arr[0].toString()) * power) / power).toString()

    // 检查是否为整数
    let decimal: number = val.indexOf('.') // 小数点的索引值
    if (decimal < 0) {
      decimal = val.length
      val += '.'
    }
    // 文本补位
    while (val.length <= decimal + places) {
      val += '0'
    }
    // 添加单位/其他文本描述
    if (needUnit && replaceLen < maxLen) {
      val += valueStr.slice(replaceLen, maxLen)
    }
  }
  return val
}
10.5 获取忽略标点符号字符串的字节数
/**
 * @description: 获取忽略标点符号字符串的字节数
 * @param {string} str 字符串
 * @param {boolean} isIgnoreChineseByte 是否忽略中文字节限制
 * @return {*} number
 */
export const getStrLenThatIgnorePunctuation = (str: string, isIgnoreChineseByte = true) => {
  if (!str) return str
  let count = 0 // 初始化字节数递加变量并获取字符串参数的字符个数
  const reg = /[`:_.~!@#$%^&*() \+ =<>?"{}|, \/ ;' \\ [ \] ·~!@#¥%……&*()—— \+ ={}|《》?:“”【】、;‘’,。、]/g
  const temp = str.toString().replace(reg, '') // del the blankspace, like trim().
  if (isIgnoreChineseByte) {
    count = temp.length
  } else {
    count = temp.replace(/[^\x00-\xff]/g, '**').length // A Chinese two ** instead
  }
  return count
}
10.6 格式化丢失精度的浮点数字
/**
 * @description: 格式化丢失精度的浮点数字
 * @param {number} num 数值
 * @return {*}
 */
export const floatEasyHandle = (num: number) => {
  if (num && customIsNumber(num)) {
    let r = 0
    try {
      r = num.toString().split('.')[1].length
    } catch (e) {
      r = 0
    }
    const m = Math.pow(10, r)
    return num * m / m
  }
  return num
}
10.6 保留小数精度
// 保留小数精度
export const retainDecimalPercision = (value: number, digit = 2) => {
  if (digit <= 0) return
  return Math.round((value) * Math.pow(10, digit)) / Math.pow(10, digit)
}
10.7 判断是否为NAN
export const isPureDigits = (value: any) => {
  if (value === null) return false
  return !isNaN(value)
}
10.8 乘法精度丢失处理
// 乘法精度丢失处理
export const floatMultiply = (arg1: number, arg2: number) => {
  let m = 0
  const s1 = arg1.toString()
  const s2 = arg2.toString()
  try { m += s1.split('.')[1].length } catch (e) {
    console.log()
  }
  try { m += s2.split('.')[1].length } catch (e) {
    console.log()
  }
  return Number(s1.replace('.', '')) * Number(s2.replace('.', '')) / Math.pow(10, m)
}
10.9 除法精度丢失处理
// 除法精度丢失处理
export const floatDivide = (arg1: number, arg2: number) => {
  let t1 = 0
  let t2 = 0
  let r1 = 0
  let r2 = 0
  try { t1 = arg1.toString().split('.')[1].length } catch (e) {
    console.log()
  }
  try { t2 = arg2.toString().split('.')[1].length } catch (e) {
    console.log()
  }
  r1 = Number(arg1.toString().replace('.', ''))
  r2 = Number(arg2.toString().replace('.', ''))
  const intDiv = r1 / r2
  const pow = Math.pow(10, t2 - t1)
  return floatMultiply(intDiv, pow) // 这里用上面定义好的乘法运算
}
10.10 数字转成汉字
/**
   * 数字转成汉字
   * @params num === 要转换的数字
   * @return 汉字
   * */
export const toChinesNum = (num: any) => {
  const arr1 = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
  const arr2 = ['', '十', '百', '千', '万', '十', '百', '千', '亿', '十', '百', '千', '万', '十', '百', '千', '亿']// 可继续追加更高位转换值
  if (!num || isNaN(num)) {
    return '零'
  }
  const english = num.toString().split('')
  let result = ''
  for (let i = 0; i < english.length; i++) {
    const desI = english.length - 1 - i// 倒序排列设值
    result = arr2[i] + result
    const arr1Index = english[desI]
    result = arr1[arr1Index] + result
  }
  // 将【零千、零百】换成【零】 【十零】换成【十】
  result = result.replace(/零(千|百|十)/g, '零').replace(/十零/g, '十')
  // 合并中间多个零为一个零
  result = result.replace(/零+/g, '零')
  // 将【零亿】换成【亿】【零万】换成【万】
  result = result.replace(/零亿/g, '亿').replace(/零万/g, '万')
  // 将【亿万】换成【亿】
  result = result.replace(/亿万/g, '亿')
  // 移除末尾的零
  result = result.replace(/零+$/, '')
  // 将【零一十】换成【零十】
  // result = result.replace(/零一十/g, '零十');//貌似正规读法是零一十
  // 将【一十】换成【十】
  result = result.replace(/^一十/g, '十')
  return result
}
10.11 数字比较 排序
// 数字比较
export const digitCompareHandler = (arr: any[], sortParamKey: string, SortingName: string, filterVal?: any) => {
  if (!SortingName) return [...arr]
  const { emptyValDatas, sortDatas } = splitData(arr, sortParamKey, filterVal)
  if (['ascending', 'ASC'].includes(SortingName)) {
    sortDatas.sort((data1: any, data2: any) => {
      const sortData1 = typeof data1[sortParamKey] === 'string' ? removeThousandsSeparator(data1[sortParamKey]) : data1[sortParamKey]
      const sortData2 = typeof data2[sortParamKey] === 'string' ? removeThousandsSeparator(data2[sortParamKey]) : data2[sortParamKey]
      return sortData1 - sortData2
    })
  } else if (['descending', 'DES'].includes(SortingName)) {
    sortDatas.sort((data1: any, data2: any) => data2[sortParamKey] - data1[sortParamKey])
  }
  return [...sortDatas, ...emptyValDatas]
}
10.12 保留两位小数|多位小数
// 保留两位小数
export const setKeepDecimalPlaces  = (num: number, fix = 2, unit?: string) => {
  if (isNaN(num)) {
    return num
  } else {
    const result = Math.round(num * Math.pow(10, fix)) / Math.pow(10, fix)
    let val = result.toString()
    let decimal: number = val.indexOf('.') // 小数点的索引值
    if (decimal < 0) {
      decimal = val.length
      val += '.'
    }
    // 文本补位
    while (val.length <= decimal + fix) {
      val += '0'
    }
    return unit ? val + unit : val
  }
}
12 其他
12.1 评级列表值
// 评级列表值
export const RatingMap = {
  '1': 1,
  '2': 2,
  '3': 3,
  '4+': 3.67,
  '4': 4,
  '4-': 4.33,
  '5+': 4.67,
  '5': 5,
  '5-': 5.33,
  '6+': 5.67,
  '6': 6,
  '6-': 6.33,
  '7+': 6.67,
  '7': 7,
  '7-': 7.33,
  '8+': 7.67,
  '8': 8,
  '8-': 8.33,
  '9': 9,
  '10': 10
}

export const RatingAxis = [
  '0',
  '1',
  '2',
  '3',
  '4+',
  '4',
  '4-',
  '5+',
  '5',
  '5-',
  '6+',
  '6',
  '6-',
  '7+',
  '7',
  '7-',
  '8+',
  '8',
  '8-',
  '9',
  '10',
  '11'
]
12.2 客户跳转www
export const goToOtherLocationHref = () => {
  const hostNameList = ['xyzq', 'bjxt', 'gdlc', 'gfjj', 'gfzghk', 'gszc', 'gtja', 'gxzq', 'htzg', 'jqtz', 'jsyh', 'jxyh', 'pacx', 'rbzc', 'sczq', 'sgtxt', 'shns', 'shxt', 'sjzq', 'szyh', 'tsyh', 'txsk', 'wkxt', 'xmxt', 'xylc', 'xyxt', 'ycxt', 'yfd', 'zhxt', 'zjgs', 'hxzq', 'ajxt', 'bhhjzg', 'cayh', 'dycy', 'dfzq', 'dwzq', 'dwzg', 'fxjt', 'fxbdx', 'fxlh', 'htzq', 'cjzq', 'zscf', 'zszq', 'zjtxt', 'zxjtgj', 'zxjt', 'zylc', 'bqtz', 'dyqh', 'gjzg', 'jxbxzg', 'jygjxt', 'jktz', 'rfyh', 'yacx', 'thjj', 'grzq', 'xyyh', 'sxzx', 'kljz', 'zzxy', 'hhlc', 'ygzg', 'qnyh', 'spzc', 'zhhryh', 'sygk', 'gkzl', 'xdhk', 'xbjj', 'jscc', 'jysld', 'ycdf', 'gstzbx', 'xmyh', 'hflcz', 'tpyzq', 'zsjj', 'gyzq', 'zojj', 'alzg', 'wlzq', 'hbzl', 'dwjj', 'jsjj', 'taconic', 'dzgj', 'myjr', 'yhjh', 'yszg', 'sczg', 'hnzg', 'zszq2', 'jsxt', 'gyrx', 'zbgx', 'kljk', 'djtz', 'payh', 'hft', 'ddh', 'hsjj', 'gfzq', 'zxxt', 'xdjz', 'xnzq', 'nylc', 'zhfjfh', 'xmgjyh', 'zszl', 'yhjj', 'brxt', 'bbwyh', 'dbzg', 'ctzq', 'xysf', 'hazq', 'cczc', 'gdaxjj', 'habzrs', 'jxlc', 'zxzq', 'byjj', 'tfzg', 'xylc2', 'ztxt', 'tkzc', 'cft', 'dxm', 'cxxt', 'szxx', 'hzlh', 'pajj', 'bsjj', 'cdzq', 'phjj', 'gsyl', 'qzyh', 'fzzq', 'szjj', 'nylc2', 'xayh', 'palc', 'pyzc', 'zylc2', 'nfjj', 'gjjj', 'zrxt', 'hbjj', 'sldjy', 'fgjj', 'rbyl', 'bhxt', 'ndjj', 'dcjj', 'cjyl', 'gjzg2', 'fdjj', 'gzns', 'jgxt', 'jxxt', 'axjj', 'hylc', 'zhxt2', 'shzq', 'sdxy', 'sylc', 'gycw', 'tdhl', 'sxzq', 'msyh', 'nhns', 'dgyh', 'dbzq', 'htfk', 'sdns', 'dfjj', 'fgjjcl', 'swhy', 'xbzq', 'ctzg', 'zylc3', 'zxzqzy', 'jxyl', 'axzq', 'cxzq', 'cqns', 'yxzc', 'zszq3', 'mshk', 'zsxnzc', 'hkyh', 'zlxt', 'xkrs', 'dgzq', 'mtyh', 'dczq', 'zhrs', 'htrs', 'axzg', 'nyf', 'zsjj2', 'zxxtylj', 'bdfzrs', 'xtrs', 'szns', 'nexus', 'xday', 'pfsf', 'zyrs', 'scjt', 'txjj', 'tkxt', 'jygj', 'yczg', 'zszy']
  const host = document.domain.split('.')[0] + ''
  const isHasHost = hostNameList.some(element => {
    return element === host
  })
  if (isHasHost) {
    const path = window.location.href.replace(window.location.host, 'www.ratingdog.cn')
    window.location.href = path
    return
  }
}
12.3 判断数据是否为空
export const isEmpty = (val: any) => {
  // null or undefined
  if (val == null) return true
  if (typeof val === 'boolean') return false
  if (typeof val === 'number') return !val
  if (val instanceof Error) return val.message === ''
  switch (Object.prototype.toString.call(val)) {
    // String or Array
    case '[object String]':
    case '[object Array]':
      return !val.length
    // Map or Set or File
    case '[object File]':
    case '[object Map]':
    case '[object Set]': {
      return !val.size
    }
    // Plain Object
    case '[object Object]': {
      return !Object.keys(val).length
    }
  }
  return false
}