SOURCE

// const isVoidReg = /^\S*$/
const isNumberReg = /^[0-9]*$/
const isMobileReg = /^(((13[0-9]{1})|(14[0-9]{1})|(15[0-9]{1})|(16[0-9]{1})|(17[0-9]{1})|(18[0-9]{1}|(19[0-9]{1})))+\d{8})$/
const isChineseCharacterReg = /^[\u2E80-\u9FFF]+$/
const isEmailReg = /^[A-Za-z0-9._%-]+@([A-Za-z0-9-]+\.)+[A-Za-z]{2,4}$/
const isPasswordReg = /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$/ // 8-16位数字和字母混合
function getHash(ev) {
    let file = ev.target.files || ev.dataTransfer.files;
    console.log(ev);
    let reader = new FileReader();

    reader.onload = function (event) {
        let binary = event.target.result;
        this.md5Hash = md5(binary).toString();
    };
    reader.readAsBinaryString(file[0]);
}
export const isVoid = function (val) {
    val = val.trim()
    if (val === '') {
        return true
    }
    return false
}

export const isMobile = function (val) {
    return isMobileReg.test(val)
}

export const isNumber = function (val) {
    return isNumberReg.test(val)
}

export const lengthLimit = function (val) {
    let args = arguments
    if (args.length === 1) {
        return true
    } else if (args.length === 2) {
        return val.length > args[1]
    } else {
        return val.length > args[1] && val.length < args[2]
    }
}

export const isChineseCharacter = function (val) {
    return isChineseCharacterReg.test(val)
}

export const isEmail = function (val) {
    return isEmailReg.test(val)
}

export const isPassword = function (val) {
    return isPasswordReg.test(val)
}

export function check(val) {
    return new CHECK(val)
}
class CHECK {
    constructor(val) {
        this.val = val
        this.result = []
    }
}
CHECK.prototype.isVoid = function () {
    if (isVoid(this.val)) {
        this.result.push('isVoid')
    }
    return this
}
CHECK.prototype.lengthLimit = function () {
    if (!lengthLimit(this.val, ...arguments)) {
        this.result.push('lengthLimit')
    }
    return this
}
CHECK.prototype.isNumber = function () {
    if (!isNumber(this.val)) {
        this.result.push('isNumber')
    }
    return this
}
CHECK.prototype.isMobile = function () {
    if (!isMobile(this.val)) {
        this.result.push('isMobile')
    }
    return this
}
CHECK.prototype.isChineseCharacter = function () {
    if (!isChineseCharacter(this.val)) {
        this.result.push('isChineseCharacter')
    }
    return this
}
CHECK.prototype.isEmail = function () {
    if (!isEmail(this.val)) {
        this.result.push('isEmail')
    }
    return this
}
CHECK.prototype.isPassword = function () {
    if (!isPassword(this.val)) {
        this.result.push('isPassword')
    }
    return this
}

export const throttle = (fn, gapTime = 300) => { // 节流
    let timer = null
    let startTime = new Date().getTime()
    return function () {
        let ctx = this
        let args = arguments
        let currentTime = new Date().getTime()
        clearTimeout(timer)
        if (currentTime - startTime >= gapTime) {
            fn.apply(ctx, args)
            startTime = currentTime
        } else {
            timer = setTimeout(() => {
                fn.apply(ctx, args)
            }, gapTime)
        }
    }
}
export const debounce = (fn, delay = 300) => { // 防抖
    let timer = null
    return function () {
        let args = arguments
        let _this = this
        clearTimeout(timer)
        timer = setTimeout(() => {
            fn.apply(_this, args)
        }, delay)
    }
}
export const scrollAnimate = ($el, currentY, targetY) => { // 滚动动画
    let needScrollTop = targetY - currentY
    let _currentY = currentY
    setTimeout(() => {
        // 一次调用滑动帧数,每次调用会不一样
        const dist = Math.ceil(needScrollTop / 10)
        _currentY += dist
        $el.scrollTop = _currentY
        // 如果移动幅度小于十个像素,直接移动,否则递归调用,实现动画效果
        if (needScrollTop > 10 || needScrollTop < -10) {
            scrollAnimate($el, _currentY, targetY)
        } else {
            $el.scrollTop = targetY
        }
    }, 1)
}

export const fileCheck = ({ fileNameLength, size, suffixReg, file }) => {
    if (suffixReg !== undefined) {
        if (suffixReg instanceof RegExp) {
            if (!suffixReg.test(file.name.substring(file.name.lastIndexOf('.') + 1))) {
                return 'suffixReg'
            }
        } else {
            throw new Error('suffixReg must be RegExp')
        }
    }
    if (size !== undefined) {
        if (file.size > size) {
            return 'size'
        }
    }
    if (fileNameLength !== undefined) {
        if (file.name.substring(0, file.name.lastIndexOf('.')).length > fileNameLength) {
            return 'fileNameLengthLimit'
        }
    }
    return true
}

/**
 * 图片转Base64
 * @param image 原图片
 * @param compress 是否压缩
 * @param scale 图片缩放比例
 * @param quality 压缩图片的质量
 * @param transparency 背景透明度
 * @example ImageToBase64(file, {compress: false, scale: 1, quality: 0.92}).then().catch()
 */
export const ImageToBase64 = (image, { compress = false, scale = 1, quality = 0.92, transparency = null } = {}) => {
    // 获取图片Base64
    const GetImageBase64 = (file) => {
        return new Promise((resolve, reject) => {
            const reader = new FileReader()
            reader.readAsDataURL(file)
            reader.onload = ({ target: { result } }) => {
                resolve(result)
            }
            reader.onerror = (error) => {
                reject(error)
            }
        })
    }
    const dataFilter = (data) => {
        for (let i = 0; i < data.length; i += 4) {
            let r = data[i]
            let g = data[i + 1]
            let b = data[i + 2]
            // 色值在250-256之间都认为是白色
            if (r > transparency.r || g > transparency.g || b > transparency.b) {
                data[i + 3] = 0 // 把白色改成透明的
            }
        }
        return data
    }
    return new Promise(async (resolve, reject) => {
        // 图片转成Base64
        let imagBase64 = null
        try {
            imagBase64 = await GetImageBase64(image)
        } catch (error) {
            reject(new Error('image transform base64 error'))
        }
        // 不需要压缩并且不需要处理背景色
        if (!compress && !transparency) {
            resolve(imagBase64)
            return
        }
        // 需要压缩
        let innerImage = new Image()
        innerImage.src = imagBase64
        // 图片加载
        innerImage.onload = () => {
            // 原始宽高
            const originWidth = innerImage.width
            const originHeight = innerImage.height
            // 目标宽高
            const targetWidth = originWidth * scale
            const targetHeight = originHeight * scale
            // 创建画布
            let canvas = document.createElement('canvas')
            let context = canvas.getContext('2d')
            canvas.width = targetWidth
            canvas.height = targetHeight
            // 清除画布
            context.clearRect(0, 0, targetWidth, targetHeight)
            // 压缩图片
            context.drawImage(innerImage, 0, 0, targetWidth, targetHeight)
            if (transparency) {
                // 获取画布像素信息
                const imageData = context.getImageData(0, 0, targetWidth, targetHeight)
                const data = imageData.data
                dataFilter(data)
                context.putImageData(imageData, 0, 0)
                resolve(canvas.toDataURL('image/png'))
            }
            // 压缩后图片的URL(base64)
            const compressBase64 = canvas.toDataURL('image/png', quality)
            resolve(compressBase64)
        }
        innerImage.onerror = error => {
            reject(error)
        }
        image.error = error => {
            reject(error)
        }
    })
}

/**
 * 获取base64的内容
 * @param base64 图片base64
 */
export const GetBase64Content = (base64) => {
    if (base64.includes('data:image')) {
        return base64.split(',')[1]
    }
    return base64
}
/**
 * 添加base64的头信息
 * @param base64 图片base64
 * @param type 添加的类型
 */
export const AddBase64Header = (base64, type = 'jpeg') => {
    if (base64.includes('data:image')) {
        return base64
    }
    return `data:image/${type};base64,${base64}`
}
/**
 * 文件导出
 * obj.data后端返回的流数据
 * obj.name下载后所要展示的文件名
*/
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.responseType = "blob"; // 返回类型blob  blob 存储着大量的二进制数据
xhr.onload = function () {
    console.log(xhr)
    if (this.status === 200) {
        var blob = this.response;
        var reader = new FileReader();
        reader.readAsDataURL(blob); // 转换为base64,可以直接放入a标签href
        reader.onload = function (e) {
            var a = document.createElement("a"); // 转换完成,创建一个a标签用于下载
            a.download = name + ".xls";
            a.href = e.target.result;
            $("body").append(a); // 修复firefox中无法触发click
            a.click();
            $(a).remove();
        };
    }
}
xhr.send(); // 发送ajax请求
// axios
export const exportFile = (obj) => {
    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
        window.navigator.msSaveOrOpenBlob(new Blob([obj.data]), obj.name);
        return
    }
    const url = window.URL.createObjectURL(new Blob([obj.data]))
    const link = document.createElement('a')
    link.style.display = 'none'
    link.href = url
    link.setAttribute('download', obj.name)
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
    window.URL.revokeObjectURL(link.href)
}
/** base64格式图片转换为二进制文件流
 * @
 */
export const base64ToBlob = (base64, type = 'string') => {
    let base64Content = GetBase64Content(base64)
    let decodeStr = atob(base64Content)
    let n = decodeStr.length
    let u8arr = new Uint8Array(n)
    while (n--) {
        u8arr[n] = decodeStr.charCodeAt(n)
    }
    return new Blob([u8arr], {
        type: 'image/png'
    })
}
const h = this.$createElement
const message = h('div', null, [
    h('span', null, '无麦克风或者麦克风已禁用:呼叫,会议,监听,SOS呼叫功能将不可用。请连接麦克风并打开权限')
    // h('el-button', {
    //   props: {
    //     type: 'text'
    //   },
    //   on: {
    //     click: this.showMircrophoneAuthTip
    //   }
    // }, '打开权限')
])

this.$message({
    type: 'error',
    dangerouslyUseHTMLString: true,
    duration: 5000,
    showClose: false,
    message
})
console 命令行工具 X clear

                    
>
console