/** * 格式化日期时间 * @param {string|Date} date - 日期 * @param {boolean} includeTime - 是否包含时间 * @returns {string} */ export function formatDateTime(date, includeTime = true) { if (!date) return '-'; const d = new Date(date); if (isNaN(d.getTime())) return '-'; const year = d.getFullYear(); const month = String(d.getMonth() + 1).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0'); if (!includeTime) { return `${year}-${month}-${day}`; } const hours = String(d.getHours()).padStart(2, '0'); const minutes = String(d.getMinutes()).padStart(2, '0'); const seconds = String(d.getSeconds()).padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } /** * 格式化相对时间(多久之前) * @param {string|Date} date - 日期 * @returns {string} */ export function formatRelativeTime(date) { if (!date) return '-'; const d = new Date(date); if (isNaN(d.getTime())) return '-'; const now = new Date(); const diff = now - d; // 毫秒差 const seconds = Math.floor(diff / 1000); const minutes = Math.floor(seconds / 60); const hours = Math.floor(minutes / 60); const days = Math.floor(hours / 24); if (seconds < 60) return '刚刚'; if (minutes < 60) return `${minutes} 分钟前`; if (hours < 24) return `${hours} 小时前`; if (days < 7) return `${days} 天前`; return formatDateTime(date, false); } /** * 格式化文件大小 * @param {number} bytes - 字节数 * @returns {string} */ export function formatFileSize(bytes) { if (!bytes || bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`; } /** * 防抖函数 * @param {Function} fn - 要防抖的函数 * @param {number} delay - 延迟时间(毫秒) * @returns {Function} */ export function debounce(fn, delay = 300) { let timer = null; return function (...args) { if (timer) clearTimeout(timer); timer = setTimeout(() => { fn.apply(this, args); }, delay); }; } /** * 节流函数 * @param {Function} fn - 要节流的函数 * @param {number} delay - 延迟时间(毫秒) * @returns {Function} */ export function throttle(fn, delay = 300) { let timer = null; let lastTime = 0; return function (...args) { const now = Date.now(); if (now - lastTime < delay) { if (timer) clearTimeout(timer); timer = setTimeout(() => { lastTime = now; fn.apply(this, args); }, delay); } else { lastTime = now; fn.apply(this, args); } }; } /** * 复制文本到剪贴板 * @param {string} text - 要复制的文本 * @returns {Promise} */ export async function copyToClipboard(text) { try { if (navigator.clipboard && window.isSecureContext) { await navigator.clipboard.writeText(text); return true; } else { // 降级方案 const textArea = document.createElement('textarea'); textArea.value = text; textArea.style.position = 'fixed'; textArea.style.left = '-999999px'; document.body.appendChild(textArea); textArea.focus(); textArea.select(); try { document.execCommand('copy'); textArea.remove(); return true; } catch (error) { console.error('复制失败', error); textArea.remove(); return false; } } } catch (error) { console.error('复制失败', error); return false; } }