/**
* 存储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)
}
/**
* 获取localStorage
* @param {String} key 本地存储键名
*/
export const getStore = (key: string) => {
if (!key) {
return
}
return window.localStorage.getItem(key)
}
/**
* 删除localStorage
* @param {String} key 本地存储键名
*/
export const removeStore = (key: string) => {
if (!key) {
return
}
window.localStorage.removeItem(key)
}
/**
* 存储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)
}
/**
* 获取sessionStorage
* @param {String} key 本地存储键名
*/
export const getSessionStorage = (key: string) => {
if (!key) {
return
}
return window.sessionStorage.getItem(key)
}
/**
* 删除sessionStorage
* @param {String} key 本地存储键名
*/
export const removeSessionStorage = (key: string) => {
if (!key) {
return
}
window.sessionStorage.removeItem(key)
}
/**
* 默认的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' })
}
/**
* 获取指定名称的cookie的值
* @param {String} name 需要获取的cookie键
* @return {String} 结果值
*/
export const getCookie = (name: string) => {
return Cookies.get(name) ||
Cookies.get(name, { path: '/', domain: '.ratingdog.cn' })
}
/**
* 清空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
}
}
}
/**
* 删除指定名称的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' })
})
}
/**
* 删除指定名称的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' })
})
}
/**
* 判断微信环境
* @return {Boolean} 返回是否在微信
*/
export const isWeChat = () => {
const ua = navigator.userAgent.toLowerCase()
if (ua.match(/MicroMessenger/i) + '' === 'micromessenger') {
return true
}
return false
}
/**
* 判断手机是安卓还是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
}
/**
* 判断是否是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
}
/**
* 判断浏览器是否支持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'
}
/**
* 判断浏览器是否为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
}
/**
* 获取字符串长度(区分英文汉字)
* @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
}
/**
* 判断是否存在空格
* @param {String} str 邮箱地址
* @return {Boolean} 返回验证结果
*/
export const blank = (str: string) => {
const reg = /\s/
if (reg.test(str)) {
return true
}
return false
}
/**
* 判断url中是否含有某个值
* @param {String} name 需要查询的值
* @return {Boolean} 返回判断结果
*/
export const urlJudgment = (name: string) => {
const href = window.location.href
if (href.includes(name)) return true
return false
}
/**
* 字符串过滤
* @param {String} str 需要查询的值
* @return {String} 返回处理过后的字符串
*/
export const strFilter = (str: string) => {
const arr = str.split('.')
return arr[0]
}
/**
* 判断是否时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
}
}
}
/**
* 获取当前静态资源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
}
/**
* 去除字符串首尾空格
* @param {String} str 需要处理的字符串
* @return {String} 返回当前静态资源url
*/
export const trim = (str: string) => {
return str.replace(/^(\s|\u00A0)+/, '').replace(/(\s|\u00A0)+$/, '')
}
/**
* 去除字符串两侧空格
* @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() : ''
}
}
/**
* 将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": ""}
}
/**
* 处理电话前缀
* @param {String} preInput 电话前缀
* @return {String} 返回处理过后的电话前缀
*/
export const getPreInput = (preInput: string) => {
let result = preInput || '86'
if (result[0] === '+') result = result.substr(1)
return result
}
/**
* 按字节长度截取字符串
* @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
}
}
}
/**
* 处理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
}
/**
* 处理期限字段
* @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
}
/**
* 处理剩余期限字段
* @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
}
/**
* 获取加密字符串 中间带*
* @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
}
// 富文本字符格式加粗处理 使用时把下面注释打开
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
}
// 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, '+')
}
// 字符串比较
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]
}
/**
* 手机号码验证
* @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)
}
/**
* 邮箱验证
* @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
}
/**
* 密码验证 必须包含字母和数字
* @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
}
}
/**
* 将时间戳改为时间格式
* @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
}
/**
* 将时间戳转为时间格式 日 时 分 秒
* @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
}
/**
* 将时间改为时间戳格式
* @param {String} time 时间
*/
export const getTimestamp = (time?: string) => {
if (time) return new Date(time).getTime()
return new Date().getTime() // 如果没传time值 获取当前时间
}
/**
* 转换时间格式 处理8小时时间差
* @param {Date} time 需要转换的时间
*/
export const getTime = (time: Date | ''): Date | '' => {
if (!time) return ''
const date = new Date(time).getTime()
return new Date(date)
}
/**
* 获取时间区间末尾项 加一天
* @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)
}
/**
* 转换时间格式 处理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
}
/**
* 转换时间格式 添加天数
* @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)
}
// 获得上周周一 - 周日的年月日
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
}
// 获取上一个月日期
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
}
// 获取昨天的日期
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')
}
// 获取当前的季度
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
}
/**
* @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, '\/'))))
}
}
// 日期比较
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]
}
/**
* 深度拷贝
* @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
}
}
/**
* 遍历递归拷贝
* @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
}
/**
* 获取整洁的对象(去除值为空的对象)
* @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
}
/**
* 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
}
/**
* @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
}
/**
* 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
}
/**
* 从数组中找到含有某个键值对的数组索引
* @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
}
/**
* 包含对象的数组去重 返回新数组
* @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
}
/**
* 数组去重
* @param {Array} arr 待处理数组
* @returns {Array} 返回新数组
*/
export const unique = (arr: any[]): any[] => {
// 如果新数组的当前元素的索引值 == 该元素在原始数组中的第一个索引,则返回当前元素
return arr.filter((item, index) => {
return arr.indexOf(item, 0) === index
})
}
// 传入数组参数 检查所有参数是否为空值
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
}
// 分割排序集合与空值集合
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 }
}
/**
* @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
}
/**
* @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)
}
})
}
/**
* 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
}
}
}
/**
* 平滑滚动
* @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)
}
/**
* 获取dom元素的指定样式
* @param {any} dom 需要查询的dom元素
* @param {String} style 需要查询的样式名称
*/
export const getStyle = (dom: any, style: string) => {
return dom.style[style]
}
/**
* 获取滚动条的宽度
*/
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 // 返回滚动条宽度
}
// 判断是否需要展示提示
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)
}
/**
* 文件格式限制
* @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
}
/**
* 数字加千位分隔符
* @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
}
/**
* 字符串去除千位分隔符
* @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
}
/**
* @description: 检查是否数字
* @param {any} value
* @return {boolean}
*/
export const customIsNumber = (value: any) => {
return (typeof value === 'number' && !isNaN(value))
}
/**
* @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
}
/**
* @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
}
/**
* @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
}
// 保留小数精度
export const retainDecimalPercision = (value: number, digit = 2) => {
if (digit <= 0) return
return Math.round((value) * Math.pow(10, digit)) / Math.pow(10, digit)
}
export const isPureDigits = (value: any) => {
if (value === null) return false
return !isNaN(value)
}
// 乘法精度丢失处理
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)
}
// 除法精度丢失处理
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) // 这里用上面定义好的乘法运算
}
/**
* 数字转成汉字
* @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
}
// 数字比较
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]
}
// 保留两位小数
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
}
}
export const isMatch = (Regexp: string, fullPath: string, hasRouteParams = false) => {
if (!Regexp || !fullPath) return false
const keys: any[] = []
const regex = pathToRegexp(Regexp, keys)
const path = fullPath.split('?')
const matchResult = regex.exec(path[0])
if (!hasRouteParams || !matchResult) return matchResult
const params: { [key: string]: string } = {}
for (let i = 1; i < matchResult.length; i++) {
params[keys[i - 1].name] = matchResult[i]
}
return params
}
// 页面缓存列表
export const COMMON_CACHE_COMPONENT_LIST = [
'/researchIssuer/issuerDetails/:id' // 主体详情
]
###### 12.3 判断是否缓存页面
export const isCachePage = (delItem: Common.Tag) => {
const { path: fullPath } = delItem
let isCacheComponent: string | boolean = false
for (let index = 0; index < COMMON_CACHE_COMPONENT_LIST.length; index++) {
const matchResult = isMatch(COMMON_CACHE_COMPONENT_LIST[index], fullPath)
if (matchResult) {
isCacheComponent = COMMON_CACHE_COMPONENT_LIST[index]
break
}
}
return isCacheComponent
}
// 评级列表值
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'
]
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
}
}
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
}