import { $on, $off, $once, $emit } from './events' declare const window: any export function parseTime(time, cFormat) { if (arguments.length === 0) return null const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}' let date if (typeof time === 'object') { date = time } else { if (('' + time).length === 10) time = parseInt(time) * 1000 date = new Date(time) } const formatObj = { y: date.getFullYear(), m: date.getMonth() + 1, d: date.getDate(), h: date.getHours(), i: date.getMinutes(), s: date.getSeconds(), a: date.getDay(), } const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { let value = formatObj[key] if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1] if (result.length > 0 && value < 10) value = '0' + value return value || 0 }) return time_str } export function formatTime(time, option) { time = +time * 1000 const d = new Date(time) const now = Date.now() const diff = (now - d.getTime()) / 1000 if (diff < 30) return '刚刚' else if (diff < 3600) // less 1 hour return Math.ceil(diff / 60) + '分钟前' else if (diff < 3600 * 24) return Math.ceil(diff / 3600) + '小时前' else if (diff < 3600 * 24 * 2) return '1天前' if (option) return parseTime(time, option) else return ( d.getMonth() + 1 + '月' + d.getDate() + '日' + d.getHours() + '时' + d.getMinutes() + '分' ) } // 格式化时间 export function getQueryObject(url) { url = url == null ? window.location.href : url const search = url.substring(url.lastIndexOf('?') + 1) const obj = {} const reg = /([^?&=]+)=([^?&=]*)/g search.replace(reg, (rs, $1, $2) => { const name = decodeURIComponent($1) let val = decodeURIComponent($2) val = String(val) obj[name] = val return rs }) return obj } /** *get getByteLen * @param {Sting} val input value * @returns {number} output value */ export function getByteLen(val) { let len = 0 for ( let i = 0; i < val.length; i++ // eslint-disable-next-line ) { if (val[i].match(/[^\x00-\xff]/gi) != null) { len += 1 } else len += 0.5 } return Math.floor(len) } export function cleanArray(actual) { const newArray = [] for (let i = 0; i < actual.length; i++) { if (actual[i]) newArray.push(actual[i]) } return newArray } export function param(json) { if (!json) return '' return cleanArray( Object.keys(json).map((key) => { if (json[key] === undefined) return '' return encodeURIComponent(key) + '=' + encodeURIComponent(json[key]) }) ).join('&') } export function param2Obj(url) { const search = url.split('?')[1] if (!search) return {} return JSON.parse( '{"' + decodeURIComponent(search) .replace(/"/g, '\\"') .replace(/&/g, '","') .replace(/=/g, '":"') + '"}' ) } export function html2Text(val) { const div = document.createElement('div') div.innerHTML = val return div.textContent || div.innerText } export function objectMerge(target, source) { /* Merges two objects, giving the last one precedence */ if (typeof target !== 'object') target = {} if (Array.isArray(source)) return source.slice() Object.keys(source).forEach((property) => { const sourceProperty = source[property] if (typeof sourceProperty === 'object') target[property] = objectMerge(target[property], sourceProperty) else target[property] = sourceProperty }) return target } export function scrollTo(element, to, duration) { if (duration <= 0) return const difference = to - element.scrollTop const perTick = (difference / duration) * 10 setTimeout(() => { //console.log(new Date()) element.scrollTop = element.scrollTop + perTick if (element.scrollTop === to) return scrollTo(element, to, duration - 10) }, 10) } export function toggleClass(element, className) { if (!element || !className) return let classString = element.className const nameIndex = classString.indexOf(className) if (nameIndex === -1) classString += '' + className else classString = classString.substr(0, nameIndex) + classString.substr(nameIndex + className.length) element.className = classString } export const pickerOptions = [ { text: '今天', onClick(picker) { const end = new Date() const start = new Date(new Date().toDateString()) end.setTime(start.getTime()) $emit(picker, 'pick', [start, end]) }, }, { text: '最近一周', onClick(picker) { const end = new Date(new Date().toDateString()) const start = new Date() start.setTime(end.getTime() - 3600 * 1000 * 24 * 7) $emit(picker, 'pick', [start, end]) }, }, { text: '最近一个月', onClick(picker) { const end = new Date(new Date().toDateString()) const start = new Date() start.setTime(start.getTime() - 3600 * 1000 * 24 * 30) $emit(picker, 'pick', [start, end]) }, }, { text: '最近三个月', onClick(picker) { const end = new Date(new Date().toDateString()) const start = new Date() start.setTime(start.getTime() - 3600 * 1000 * 24 * 90) $emit(picker, 'pick', [start, end]) }, }, ] export function getTime(type) { if (type === 'start') return new Date().getTime() - 3600 * 1000 * 24 * 90 else return new Date(new Date().toDateString()) } export function debounce(func, wait, immediate) { let timeout, args, context, timestamp, result const later = function () { // 据上一次触发时间间隔 const last = +new Date() - timestamp // 上次被包装函数被调用时间间隔last小于设定时间间隔wait if (last < wait && last > 0) { timeout = setTimeout(later, wait - last) } else { timeout = null // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用 if (!immediate) { result = func.apply(context, args) if (!timeout) context = args = null } } } return function (...args) { context = this timestamp = +new Date() const callNow = immediate && !timeout // 如果延时不存在,重新设定延时 if (!timeout) timeout = setTimeout(later, wait) if (callNow) { result = func.apply(context, args) context = args = null } return result } } /** * 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 */ export function deepClone(source) { if (!source && typeof source !== 'object') throw new Error('error arguments') const targetObj = 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 } // 数组深拷贝 export function ArrayDeepCopy(list) { let newArray = [] for (let i = 0; i < list.length; i++) { let obj = list[i] let obj2 = JSON.parse(JSON.stringify(obj)) newArray.push(obj2) } return newArray } // 数组去重复-by Set export function uniqueArr(arr) { return Array.from(new Set(arr)) } /** 数组去重复-by Map*/ export function uniqueArray(arr) { if (!Array.isArray(arr)) return arr const map = new Map() return arr.filter((item) => map.has(item) && map.set(item, 1)) } export function computeFontSize(str, size, family) { let spanDom = document.createElement('span') spanDom.style.fontSize = size + 'px' spanDom.style.fontFamily = family spanDom.innerHTML = str document.body.append(spanDom) let sizeD: any = {} sizeD.width = spanDom.offsetWidth spanDom.remove() return sizeD } /** * 数字格式化成K,M等格式 * */ export function nFormatter(num, digits = 2) { const si = [ { value: 1, symbol: '' }, { value: 1e3, symbol: 'K' }, { value: 1e6, symbol: 'M' }, { value: 1e9, symbol: 'G' }, { value: 1e12, symbol: 'T' }, { value: 1e15, symbol: 'P' }, { value: 1e18, symbol: 'E' }, ] const rx = /\.0+$|(\.[0-9]*[1-9])0+$/ let i for (i = si.length - 1; i > 0; i--) { if (num >= si[i].value) break } return (num / si[i].value).toFixed(digits).replace(rx, '$1') + si[i].symbol } /** * 根据对象中的某个字段进行组去重 * @param {any[]} arr * @param {string} key * @returns {any[]} */ export function uniqueByKey(arr, key) { const res = new Map() return arr.filter((item) => !res.has(item[key]) && res.set(item[key], 1)) } /** * 生成随机字符串 * @param len 长度 * @returns {string} */ export function randomString(len = 4) { let $chars = 'abcdefhijkmnprstwxyz' /** **默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/ let maxPos = $chars.length let pwd = '' for (let i = 0; i < len; i++) pwd += $chars.charAt(Math.floor(Math.random() * maxPos)) return pwd } /** * 往数组中添加元素,若数组中有则不再添加 * @param array * @param item * @returns {*} */ export function arrayAdd(array, item) { if (!Array.isArray(array)) return [] for (let i = 0; i < array.length; i++) { let value = array[i] if (item === value) return array } array.push(item) return array } // 接口请求参数转formData export function toFormData(data) { const isJson = (obj) => typeof obj == 'object' && Object.prototype.toString.call(obj).toLowerCase() === '[object object]' && !obj.length let fd = new FormData() Object.entries(data).forEach(([key, val]) => { fd.set(key, isJson(val) ? JSON.stringify(val) : val as string) }) return fd } export function urlencode(json) { let str = (JSON.stringify(json) + '').toString() return encodeURIComponent(str) .replace(/!/g, '%21') .replace(/'/g, '%27') .replace(/\(/g, '%28') .replace(/\)/g, '%29') .replace(/\*/g, '%2A') .replace(/%20/g, '+') } /** * 传入一个图片的原始宽高以及最大显示的长度maxSize, 使图片的最大边长不得超过maxSize * @param width {number} * @param height {number} * @param maxSize {number} */ export function showBigImage(width, height, maxSize) { let ratio = width / height let w, h = 0 if (width > height) { w = Math.min(width, maxSize) h = width / ratio } else { h = Math.min(height, maxSize) w = h * ratio } return [w, h] } // 检查是否为动态API export function checkIsDiyApi(url) { return url.indexOf('dyapi/') > -1 } export function handleDocType(fileType) { let docType = '' let fileTypesDoc = [ 'doc', 'docm', 'docx', 'dot', 'dotm', 'dotx', 'epub', 'fodt', 'htm', 'html', 'mht', 'odt', 'ott', 'pdf', 'rtf', 'txt', 'djvu', 'xps', ] let fileTypesCsv = [ 'csv', 'fods', 'ods', 'ots', 'xls', 'xlsm', 'xlsx', 'xlt', 'xltm', 'xltx', ] let fileTypesPPt = [ 'fodp', 'odp', 'otp', 'pot', 'potm', 'potx', 'pps', 'ppsm', 'ppsx', 'ppt', 'pptm', 'pptx', ] if (fileTypesDoc.includes(fileType)) docType = 'text' if (fileTypesCsv.includes(fileType)) docType = 'spreadsheet' if (fileTypesPPt.includes(fileType)) docType = 'presentation' return docType } /** * 生成字母和数字随机数 * @param {*} min * @param {*} max * @returns */ export function RandomRange(min, max) { var returnStr = '', range = max ? Math.round(Math.random() * (max - min)) + min : min, arr = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ] for (var i = 0; i < range; i++) { var index = Math.round(Math.random() * (arr.length - 1)) returnStr += arr[index] } return returnStr } /** * Check if an element has a class * @param {HTMLElement} elm * @param {string} cls * @returns {boolean} */ export function hasClass(ele, cls) { return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)')) } /** * Add class to element * @param {HTMLElement} elm * @param {string} cls */ export function addClass(ele, cls) { if (!hasClass(ele, cls)) ele.className += ' ' + cls } /** * Remove class from element * @param {HTMLElement} elm * @param {string} cls */ export function removeClass(ele, cls) { if (hasClass(ele, cls)) { const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)') ele.className = ele.className.replace(reg, ' ') } } // 检查是否为网址 export function checkIsHref(str) { const regExp = /^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+/ return regExp.test(str) } /** * @description 延时函数 * @param {Number} delay 延时时间 * @param {Function} fn 延时后执行的回调函数 * @returns {Promise} */ export function sleep(delay = 500, fn = null) { return new Promise((resolve, reject) => { try { const timer = setTimeout(() => { fn && fn() clearTimeout(timer) resolve() }, delay) } catch (err) { reject(err) } }) } /** * 多表单校验 * @param arr * @param fn * @returns {Promise} * 参数支持字符串、promise对象的数组集合,校验结果输出 * find为this.$refs对象 */ export function checkFormsByPromise(arr, find) { //容器 const promiseArr = [] //声明函数 function findAll(arr, type = false) { arr.forEach((v, i) => { if (Array.isArray(find[v])) { findAll(find[v], true) } else { try { const item = arr[i].constructor === Promise ? arr[i] : type ? arr[i].validate() : find[v].validate() //判断是否存在,否存放这promise对象 !(promiseArr.indexOf(item) > -1) && promiseArr.push(item) } catch (error) { throw new Error('Object does not contain a validation method') } } }) } //历遍 findAll(arr) //输出结果 return Promise.all(promiseArr) .then(() => true) .catch(() => false) } // /** // * 获取当前接口的api的路径 // * url 当期请求的api, baseUrl 路径 // * @returns {string} // */ // export function getApiName(url, baseUrl) { // // 去掉域名 // // 去掉参数 后面加一个'/' 因为有些不规范。 // return `/${url.replace(baseUrl, '/').split('?')[0]}` // } // /** // * 保存当前页面接口数据到本地 // */ // export function saveApiData(apiObj) { // let path = window.location.pathname // let pageAllData = JSON.parse(sessionStorage.getItem('pageAllData')) // pageAllData[path] = { ...pageAllData[path], ...apiObj } // sessionStorage.setItem('pageAllData', JSON.stringify(pageAllData)) // } // 序列化成对象 function toJson(params) { if (!params) return '' if (params.includes('=')) { let paramsArr = params.split('&') let obj = {} paramsArr.forEach((item) => { let keyValue = item.split('=') obj[keyValue[0]] = keyValue[1] }) return obj } else { return '' } } /** * 生成唯一标识 * @returns {string} */ export function getUUID() { return Math.random().toString(36).substr(3, 10) } export function genUId() { return Number(Math.random().toString().substr(3, 6) + Date.now()).toString(36) } // 数字加单位 /** * * @param {*} num 需要转换的数字 * @param {*} point 需要展示单位后面几位数 * @returns String */ export function tranNumber(num, point) { const $t = window?.$vueApp?.config?.globalProperties?.$t // 将数字转换为字符串,然后通过split方法用.分隔,取到第0个 let numStr = num.toString().split('.')[0] // 如果小于6,,表示10万以内的数字,让其直接显示 let formatterNum = numFormat(num) if (numStr.length >= 6 && numStr.length <= 8) { // 如果数字大于6位,小于8位,让其数字后面加单位万 let decimal = numStr.substring(numStr.length - 4, numStr.length - 4 + point) // 由千位,百位组成的一个数字 let float = parseFloat(parseInt(num / 10000) + '.' + decimal) formatterNum = numFormat(float) + $t('otherLang.wan') } else if (numStr.length > 8) { // 如果数字大于8位,让其数字后面加单位亿 let decimal = numStr.substring(numStr.length - 8, numStr.length - 8 + point) let float = parseFloat(parseInt(num / 100000000) + '.' + decimal) formatterNum = numFormat(float) + $t('otherLang.billion') } return formatterNum } // 数字加千位符 export function numFormat(num) { var res = num.toString().replace(/\d+/, function (n) { // 先提取整数部分 return n.replace(/(\d)(?=(\d{3})+$)/g, function ($1) { return $1 + ',' }) }) return res } export function reqIsSucceed(res) { const passCodes = [200, 800] return passCodes.includes(Number(res.code)) } // 菜单翻译 export function langTitle(target) { if (target?.query?.pageFormTitle) return target.query.pageFormTitle const { enTitle, title } = target.meta try { const menuLanguageObject = JSON.parse(enTitle) if (typeof menuLanguageObject === 'object') { return menuLanguageObject[this.$i18n.locale] || title || 'no-name' } else { return enTitle || 'no-name' } } catch (err) { return this.$i18n.locale === 'en-us' ? enTitle : title || 'no-name' } } export function splitUrl(arr) { let parr = arr.split('&') let obj = {} for (let i of parr) { let arr = i.split('=') obj[arr[0]] = arr[1] } return obj }