/** * Utils - 通用工具函数 */ /** 生成唯一 ID */ export function generateId() { return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; } /** 格式化时间戳 */ export function formatTime(ts) { const d = new Date(ts); const pad = n => String(n).padStart(2, '0'); return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`; } /** 截断文本 */ export function truncate(str, len = 50) { if (!str) return ''; return str.length > len ? str.substring(0, len) + '...' : str; } /** 防抖 */ export function debounce(fn, ms = 300) { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), ms); }; } /** 格式化字节大小 */ export function formatSize(bytes) { if (!bytes) return ''; const units = ['B', 'KB', 'MB', 'GB', 'TB']; let i = 0; let size = bytes; while (size >= 1024 && i < units.length - 1) { size /= 1024; i++; } return `${size.toFixed(1)} ${units[i]}`; } /** HTML 转义 */ export function escapeHtml(str) { const map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; return String(str).replace(/[&<>"']/g, (c) => map[c]); } /** 下载文件 */ export function downloadFile(filename, content, type) { const blob = new Blob([content], { type: type + ';charset=utf-8' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url); } /** File → Base64(去前缀) */ export function fileToBase64(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => { const base64 = reader.result.split(',')[1]; resolve(base64); }; reader.onerror = reject; reader.readAsDataURL(file); }); }