296 lines
6.8 KiB
JavaScript
296 lines
6.8 KiB
JavaScript
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<boolean>} 是否复制成功
|
|
*/
|
|
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)
|
|
}
|