196 lines
4.5 KiB
JavaScript
196 lines
4.5 KiB
JavaScript
/**
|
|
* 通用工具函数
|
|
*/
|
|
|
|
/**
|
|
* 防抖函数
|
|
* @param {Function} func 要防抖的函数
|
|
* @param {number} wait 等待时间
|
|
* @param {boolean} immediate 是否立即执行
|
|
* @returns {Function}
|
|
*/
|
|
export function debounce(func, wait, immediate) {
|
|
let timeout
|
|
return function executedFunction(...args) {
|
|
const later = () => {
|
|
timeout = null
|
|
if (!immediate) func(...args)
|
|
}
|
|
const callNow = immediate && !timeout
|
|
clearTimeout(timeout)
|
|
timeout = setTimeout(later, wait)
|
|
if (callNow) func(...args)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 节流函数
|
|
* @param {Function} func 要节流的函数
|
|
* @param {number} limit 时间间隔
|
|
* @returns {Function}
|
|
*/
|
|
export function throttle(func, limit) {
|
|
let inThrottle
|
|
return function(...args) {
|
|
if (!inThrottle) {
|
|
func.apply(this, args)
|
|
inThrottle = true
|
|
setTimeout(() => inThrottle = false, limit)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 深拷贝
|
|
* @param {*} obj 要拷贝的对象
|
|
* @returns {*}
|
|
*/
|
|
export function 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 (obj.hasOwnProperty(key)) {
|
|
clonedObj[key] = deepClone(obj[key])
|
|
}
|
|
}
|
|
return clonedObj
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 格式化日期
|
|
* @param {Date|string|number} date 日期
|
|
* @param {string} format 格式化字符串
|
|
* @returns {string}
|
|
*/
|
|
export function formatDate(date, format = 'YYYY-MM-DD HH:mm:ss') {
|
|
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')
|
|
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 format
|
|
.replace('YYYY', year)
|
|
.replace('MM', month)
|
|
.replace('DD', day)
|
|
.replace('HH', hours)
|
|
.replace('mm', minutes)
|
|
.replace('ss', seconds)
|
|
}
|
|
|
|
/**
|
|
* 生成唯一ID
|
|
* @returns {string}
|
|
*/
|
|
export function generateId() {
|
|
return Date.now().toString(36) + Math.random().toString(36).substr(2)
|
|
}
|
|
|
|
/**
|
|
* 验证邮箱格式
|
|
* @param {string} email 邮箱地址
|
|
* @returns {boolean}
|
|
*/
|
|
export function validateEmail(email) {
|
|
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
|
return re.test(email)
|
|
}
|
|
|
|
/**
|
|
* 验证手机号格式
|
|
* @param {string} phone 手机号
|
|
* @returns {boolean}
|
|
*/
|
|
export function validatePhone(phone) {
|
|
const re = /^1[3-9]\d{9}$/
|
|
return re.test(phone)
|
|
}
|
|
|
|
/**
|
|
* 获取文件扩展名
|
|
* @param {string} filename 文件名
|
|
* @returns {string}
|
|
*/
|
|
export function getFileExtension(filename) {
|
|
return filename.slice((filename.lastIndexOf('.') - 1 >>> 0) + 2)
|
|
}
|
|
|
|
/**
|
|
* 格式化文件大小
|
|
* @param {number} bytes 字节数
|
|
* @returns {string}
|
|
*/
|
|
export function formatFileSize(bytes) {
|
|
if (bytes === 0) return '0 Bytes'
|
|
|
|
const k = 1024
|
|
const sizes = ['Bytes', '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 {Array} tree 树形数据
|
|
* @param {string} childrenKey 子节点键名
|
|
* @returns {Array}
|
|
*/
|
|
export function flattenTree(tree, childrenKey = 'children') {
|
|
const result = []
|
|
|
|
function traverse(nodes, parent = null) {
|
|
nodes.forEach(node => {
|
|
const item = { ...node, parent }
|
|
delete item[childrenKey]
|
|
result.push(item)
|
|
|
|
if (node[childrenKey] && node[childrenKey].length > 0) {
|
|
traverse(node[childrenKey], node)
|
|
}
|
|
})
|
|
}
|
|
|
|
traverse(tree)
|
|
return result
|
|
}
|
|
|
|
/**
|
|
* 数组转树形结构
|
|
* @param {Array} list 扁平数组
|
|
* @param {string} idKey ID键名
|
|
* @param {string} parentIdKey 父ID键名
|
|
* @param {string} childrenKey 子节点键名
|
|
* @returns {Array}
|
|
*/
|
|
export function arrayToTree(list, idKey = 'id', parentIdKey = 'parentId', childrenKey = 'children') {
|
|
const map = {}
|
|
const roots = []
|
|
|
|
// 创建映射
|
|
list.forEach(item => {
|
|
map[item[idKey]] = { ...item, [childrenKey]: [] }
|
|
})
|
|
|
|
// 构建树形结构
|
|
list.forEach(item => {
|
|
const node = map[item[idKey]]
|
|
if (item[parentIdKey] && map[item[parentIdKey]]) {
|
|
map[item[parentIdKey]][childrenKey].push(node)
|
|
} else {
|
|
roots.push(node)
|
|
}
|
|
})
|
|
|
|
return roots
|
|
} |