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 date = new Date(value); const yyyy = String(date.getFullYear()); const yy = String(date.getFullYear()).slice(-2); const MM = String(date.getMonth() + 1).padStart(2, '0'); const M = String(date.getMonth() + 1); const dd = String(date.getDate()).padStart(2, '0'); const d = String(date.getDate()); const HH = String(date.getHours()).padStart(2, '0'); const H = String(date.getHours()); const mm = String(date.getMinutes()).padStart(2, '0'); const m = String(date.getMinutes()); const ss = String(date.getSeconds()).padStart(2, '0'); const s = String(date.getSeconds()); const str = format.replaceAll('yyyy', yyyy) .replaceAll('yy', yy) .replaceAll('MM', MM) .replaceAll('M', M) .replaceAll('dd', dd) .replaceAll('d', d) .replaceAll('HH', HH) .replaceAll('H', H) .replaceAll('mm', mm) .replaceAll('m', m) .replaceAll('ss', ss) .replaceAll('s', s); return str; } /** * 下载图片 * @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); }