diff --git a/src/utils/helpers.js b/src/utils/helpers.js new file mode 100644 index 0000000..4f88440 --- /dev/null +++ b/src/utils/helpers.js @@ -0,0 +1,170 @@ +/** + * 工具函数 + */ + +/** + * 格式化文件大小 + * @param {number} bytes 字节数 + * @returns {string} 格式化的文件大小 + */ +export const formatFileSize = (bytes) => { + // 类型检查和安全转换 + if (bytes === null || bytes === undefined) return '0 Bytes'; + + const numBytes = Number(bytes); + if (isNaN(numBytes) || numBytes < 0) return '0 Bytes'; + if (numBytes === 0) return '0 Bytes'; + + const k = 1024; + const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; + const i = Math.floor(Math.log(numBytes) / Math.log(k)); + + return parseFloat((numBytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; +}; + +/** + * 格式化时间 + * @param {string} dateString 日期字符串 + * @returns {string} 格式化的时间 + */ +export const formatDateTime = (dateString) => { + if (!dateString) return '-'; + + const date = new Date(dateString); + return date.toLocaleString('zh-CN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + }); +}; + +/** + * 格式化转换时间 + * @param {number} seconds 秒数 + * @returns {string} 格式化的转换时间 + */ +export const formatConversionTime = (seconds) => { + // 类型检查和安全转换 + if (seconds === null || seconds === undefined) return '-'; + + // 尝试转换为数字 + const numSeconds = Number(seconds); + + // 如果不是有效数字,返回默认值 + if (isNaN(numSeconds) || numSeconds < 0) return '-'; + + if (numSeconds < 1) { + return `${Math.round(numSeconds * 1000)}ms`; + } else if (numSeconds < 60) { + return `${numSeconds.toFixed(2)}s`; + } else { + const minutes = Math.floor(numSeconds / 60); + const remainingSeconds = (numSeconds % 60).toFixed(2); + return `${minutes}m ${remainingSeconds}s`; + } +}; + +/** + * 获取转换状态的颜色 + * @param {string} status 状态 + * @returns {string} 颜色 + */ +export const getStatusColor = (status) => { + const colors = { + processing: '#1890ff', + success: '#52c41a', + failed: '#ff4d4f', + }; + return colors[status] || '#d9d9d9'; +}; + +/** + * 获取转换状态的文本 + * @param {string} status 状态 + * @returns {string} 状态文本 + */ +export const getStatusText = (status) => { + const texts = { + processing: '转换中', + success: '转换成功', + failed: '转换失败', + }; + return texts[status] || '未知状态'; +}; + +/** + * 验证文件类型 + * @param {File} file 文件对象 + * @returns {boolean} 是否为有效的SQL文件 + */ +export const validateSQLFile = (file) => { + if (!file) return false; + + const allowedExtensions = ['.sql']; + const fileName = file.name.toLowerCase(); + + return allowedExtensions.some(ext => fileName.endsWith(ext)); +}; + +/** + * 下载文件 + * @param {Blob} blob 文件blob + * @param {string} filename 文件名 + */ +export const downloadFile = (blob, filename) => { + const url = window.URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = filename; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + window.URL.revokeObjectURL(url); +}; + +/** + * 复制文本到剪贴板 + * @param {string} text 要复制的文本 + * @returns {Promise} 是否复制成功 + */ +export const copyToClipboard = async (text) => { + try { + await navigator.clipboard.writeText(text); + return true; + } catch (err) { + // 回退方案 + try { + const textArea = document.createElement('textarea'); + textArea.value = text; + document.body.appendChild(textArea); + textArea.select(); + document.execCommand('copy'); + document.body.removeChild(textArea); + return true; + } catch (fallbackErr) { + console.error('复制失败:', fallbackErr); + return false; + } + } +}; + +/** + * 防抖函数 + * @param {Function} func 要防抖的函数 + * @param {number} wait 等待时间 + * @returns {Function} 防抖后的函数 + */ +export const debounce = (func, wait) => { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; +}; \ No newline at end of file