import dayjs from 'dayjs' import 'dayjs/locale/zh-cn' // 设置dayjs语言 dayjs.locale('zh-cn') /** * 日期格式化 * @param {Date|string} date 日期 * @param {string} format 格式 * @returns {string} 格式化后的日期字符串 */ export const formatDate = (date, format = 'YYYY-MM-DD HH:mm:ss') => { if (!date) return '' return dayjs(date).format(format) } /** * 相对时间 * @param {Date|string} date 日期 * @returns {string} 相对时间字符串 */ export const fromNow = (date) => { if (!date) return '' return dayjs(date).fromNow() } /** * 手机号格式化 * @param {string} phone 手机号 * @returns {string} 格式化后的手机号 */ export const formatPhone = (phone) => { if (!phone) return '' return phone.replace(/(\d{3})(\d{4})(\d{4})/, '$1****$3') } /** * 金额格式化 * @param {number} amount 金额 * @param {number} decimals 小数位数 * @returns {string} 格式化后的金额 */ export const formatMoney = (amount, decimals = 2) => { if (amount === null || amount === undefined) return '0.00' return Number(amount).toFixed(decimals) } /** * 文件大小格式化 * @param {number} bytes 字节数 * @returns {string} 格式化后的文件大小 */ export const formatFileSize = (bytes) => { if (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 parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i] } /** * 防抖函数 * @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) } } /** * 节流函数 * @param {Function} func 要节流的函数 * @param {number} limit 限制时间 * @returns {Function} 节流后的函数 */ export const throttle = (func, limit) => { let inThrottle return function() { const args = arguments const context = this if (!inThrottle) { func.apply(context, args) inThrottle = true setTimeout(() => inThrottle = false, limit) } } } /** * 深拷贝 * @param {any} obj 要拷贝的对象 * @returns {any} 拷贝后的对象 */ export const deepClone = (obj) => { if (obj === null || typeof obj !== 'object') return obj if (obj instanceof Date) return new Date(obj.getTime()) if (obj instanceof Array) return obj.map(item => deepClone(item)) if (typeof obj === 'object') { const clonedObj = {} for (const key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { clonedObj[key] = deepClone(obj[key]) } } return clonedObj } } /** * 生成UUID * @returns {string} UUID字符串 */ export const generateUUID = () => { 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) }) } /** * 验证手机号 * @param {string} phone 手机号 * @returns {boolean} 是否有效 */ export const validatePhone = (phone) => { const phoneRegex = /^1[3-9]\d{9}$/ return phoneRegex.test(phone) } /** * 验证邮箱 * @param {string} email 邮箱 * @returns {boolean} 是否有效 */ export const validateEmail = (email) => { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ return emailRegex.test(email) } /** * 验证身份证号 * @param {string} idCard 身份证号 * @returns {boolean} 是否有效 */ export const validateIdCard = (idCard) => { const idCardRegex = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/ return idCardRegex.test(idCard) } /** * 获取URL参数 * @param {string} name 参数名 * @returns {string|null} 参数值 */ export const getUrlParam = (name) => { const urlParams = new URLSearchParams(window.location.search) return urlParams.get(name) } /** * 设置URL参数 * @param {string} name 参数名 * @param {string} value 参数值 */ export const setUrlParam = (name, value) => { const url = new URL(window.location) url.searchParams.set(name, value) window.history.replaceState({}, '', url) } /** * 移除URL参数 * @param {string} name 参数名 */ export const removeUrlParam = (name) => { const url = new URL(window.location) url.searchParams.delete(name) window.history.replaceState({}, '', url) } /** * 复制文本到剪贴板 * @param {string} text 要复制的文本 * @returns {Promise} 是否复制成功 */ export const copyToClipboard = async (text) => { try { await navigator.clipboard.writeText(text) return true } catch (err) { // 降级方案 const textArea = document.createElement('textarea') textArea.value = text document.body.appendChild(textArea) textArea.select() try { document.execCommand('copy') document.body.removeChild(textArea) return true } catch (err) { document.body.removeChild(textArea) return false } } } /** * 下载文件 * @param {string} url 文件URL * @param {string} filename 文件名 */ export const downloadFile = (url, filename) => { const link = document.createElement('a') link.href = url link.download = filename document.body.appendChild(link) link.click() document.body.removeChild(link) } /** * 获取浏览器信息 * @returns {object} 浏览器信息 */ export const getBrowserInfo = () => { const ua = navigator.userAgent const browser = { name: '', version: '', os: '' } // 检测浏览器 if (ua.includes('Chrome')) { browser.name = 'Chrome' } else if (ua.includes('Firefox')) { browser.name = 'Firefox' } else if (ua.includes('Safari')) { browser.name = 'Safari' } else if (ua.includes('Edge')) { browser.name = 'Edge' } else if (ua.includes('MSIE') || ua.includes('Trident')) { browser.name = 'IE' } // 检测操作系统 if (ua.includes('Windows')) { browser.os = 'Windows' } else if (ua.includes('Mac')) { browser.os = 'Mac' } else if (ua.includes('Linux')) { browser.os = 'Linux' } else if (ua.includes('Android')) { browser.os = 'Android' } else if (ua.includes('iOS')) { browser.os = 'iOS' } return browser } /** * 检查是否为移动设备 * @returns {boolean} 是否为移动设备 */ export const isMobile = () => { return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) } /** * 检查是否为微信浏览器 * @returns {boolean} 是否为微信浏览器 */ export const isWeChat = () => { return /MicroMessenger/i.test(navigator.userAgent) } /** * 检查是否为支付宝浏览器 * @returns {boolean} 是否为支付宝浏览器 */ export const isAlipay = () => { return /AlipayClient/i.test(navigator.userAgent) }