import CryptoJS from 'crypto-js' function getUniversalZoomLevel() { // 现代浏览器方案 if (window.visualViewport) { return window.visualViewport.scale; } // 备用方案1 if (window.devicePixelRatio) { return window.devicePixelRatio; } // 备用方案2(不精确) return window.outerWidth / window.innerWidth; } const getMousePosition = (e: any, bor: any) => { // if(e?.stopPropagation)e.stopPropagation() // if(e?.preventDefault)e.preventDefault(); let event: any if (bor) { const touch = e.changedTouches[0] as any; event = { offsetX: touch.clientX - e.target.getBoundingClientRect().left, offsetY: touch.clientY - e.target.getBoundingClientRect().top, clientX: touch.clientX, clientY: touch.clientY, screenX: touch.screenX, screenY: touch.screenY, target: e.target, } // if(dom){ // event.offsetX = touch.clientX - dom.getBoundingClientRect().left // event.offsetY = touch.clientY - dom.getBoundingClientRect().top // } } else { event = { offsetX: e.offsetX, offsetY: e.offsetY, clientX: e.clientX, clientY: e.clientY, screenX: e.screenX, screenY: e.screenY, target: e.target, } } return event } /** * 生成UUID v4 * @returns 返回一个标准的UUID v4字符串,格式:xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx */ export function generateUUID(): string { // 优先使用现代浏览器的crypto.randomUUID()方法 if (typeof crypto !== 'undefined' && crypto.randomUUID) { return crypto.randomUUID() } // 备用方案:手动生成UUID v4 return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { const r = Math.random() * 16 | 0 const v = c === 'x' ? r : (r & 0x3 | 0x8) return v.toString(16) }) } export { getUniversalZoomLevel, getMousePosition, } /** 时间格式化-自定义格式 * @param value 时间对象|时间戳|时间字符串 * @param format 格式化字符串,默认值为 'YYYY-MM-DD HH:mm:ss' * @returns 格式化后的时间字符串 */ export function FormatDate(value: Date | number | string, format: string = 'YYYY-MM-DD HH:mm:ss') { const d = new Date(value); if (!d || isNaN(d.getTime())) return 'Invalid Date'; const pad = (n) => String(n).padStart(2, '0'); const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; const tokens = { YYYY: d.getFullYear(), YY: String(d.getFullYear()).slice(-2), MM: pad(d.getMonth() + 1), M: d.getMonth() + 1, SM: months[d.getMonth()], DD: pad(d.getDate()), D: d.getDate(), HH: pad(d.getHours()), H: d.getHours(), hh: pad(d.getHours() % 12 || 12), h: d.getHours() % 12 || 12, mm: pad(d.getMinutes()), m: d.getMinutes(), ss: pad(d.getSeconds()), s: d.getSeconds(), A: d.getHours() < 12 ? 'AM' : 'PM', a: d.getHours() < 12 ? 'am' : 'pm' } const reg = new RegExp(Object.keys(tokens).join('|'), 'g') return format.replace(reg, match => tokens[match]); } /** * 下载图片 * @param list 图片列表 * @param onProgress 下载进度回调 * @param onError 下载错误回调 * @param onSuccess 下载成功回调 */ export async function DownloadImages(list: Array<{ url: string, name?: string }>, onProgress?: (count: number, total: number, item: any) => void, onError?: (count: number, total: number, item: any) => void, onSuccess?: (successCount: number, errCount: number) => void) { const total = list.length; let count = 0; let successCount = 0; let errCount = 0; for (let i = 0; i < list.length; i++) { await new Promise((resolve) => { const xhr = new XMLHttpRequest(); xhr.open("GET", list[i].url); xhr.responseType = "blob" xhr.onload = function () { count++; if (this.status === 200) { const blob = this.response; const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = list[i].name || list[i].url.split('/').pop().split('?').shift(); a.click(); successCount++; typeof onProgress === "function" && onProgress(count, total, list[i]); resolve(blob); } else { errCount++; typeof onError === "function" && onError(count, total, list[i]); resolve(true); } }; xhr.onerror = function () { count++; errCount++; typeof onError === "function" && onError(count, total, list[i]); resolve(true); }; xhr.send(); }) } typeof onSuccess === "function" && onSuccess(successCount, errCount); } /** * MD5加密密码 * @param password 原始密码 * @returns MD5加密后的密码 */ export function encryptPassword(password: string): string { return CryptoJS.MD5(password).toString() } /** * 图片分享到WhatsApp * @param url 图片URL * @returns 无 */ export async function shareImageToWhatsapp(url: string) { // 把图片 URL 转为 Blob const blob = await fetch(url).then((res) => res.blob()) // 创建文件对象 const file = new File([blob], 'image.jpg', { type: 'image/jpeg' }) // 判断浏览器是否支持文件分享 if (navigator.canShare && navigator.canShare({ files: [file] })) { await navigator.share({ files: [file] }) } else { // 你可以附加一些自定义文本 const message = 'share image ' + url // 构造WhatsApp链接 const whatsappLink = `https://api.whatsapp.com/send/?text=${encodeURIComponent(message)}` window.open(whatsappLink, '_blank') } } /** * 倒计时 * @param time 倒计时时间,单位秒 * @returns 倒计时字符串,格式为 mm:ss */ export function CountDown(time: number) { const mm = String(Math.floor(time / 60)).padStart(2, '0'); const ss = String(time % 60).padStart(2, '0'); return `${mm}:${ss}`; } /** * 字节转换为可读格式 * @param {number} bytes - 字节数 * @param {number} decimals - 保留小数位数,默认2位 * @returns {string} 格式化后的字符串 */ export function FormatBytes(bytes, decimals = 2) { if (bytes === 0) return '0 B'; if (!bytes || isNaN(bytes)) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); const value = bytes / Math.pow(k, i); return `${Number(value.toFixed(decimals))} ${sizes[i]}`; }