Files
mzltMpfqGS e4a087e67e init
2026-04-15 19:45:16 +08:00

297 lines
6.7 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// utils/util.js
// 工具函数封装
const formatTime = date => {
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()
return `${[year, month, day].map(formatNumber).join('/')} ${[hour, minute, second].map(formatNumber).join(':')}`
}
const formatNumber = n => {
n = n.toString()
return n[1] ? n : `0${n}`
}
/**
* 格式化日期
* @param {Date|string|number} date - 日期
* @param {string} format - 格式化模板
* @returns {string}
*/
const 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)
}
/**
* 相对时间格式化
* @param {Date|string|number} date - 日期
* @returns {string}
*/
const formatRelativeTime = (date) => {
if (!date) return ''
const now = Date.now()
const d = new Date(date).getTime()
const diff = now - d
const minute = 60 * 1000
const hour = 60 * minute
const day = 24 * hour
const week = 7 * day
const month = 30 * day
const year = 365 * day
if (diff < minute) {
return '刚刚'
} else if (diff < hour) {
return Math.floor(diff / minute) + '分钟前'
} else if (diff < day) {
return Math.floor(diff / hour) + '小时前'
} else if (diff < week) {
return Math.floor(diff / day) + '天前'
} else if (diff < month) {
return Math.floor(diff / week) + '周前'
} else if (diff < year) {
return Math.floor(diff / month) + '月前'
} else {
return Math.floor(diff / year) + '年前'
}
}
/**
* 手机号脱敏
* @param {string} phone - 手机号
* @returns {string}
*/
const maskPhone = (phone) => {
if (!phone || phone.length !== 11) return phone
return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
}
/**
* 邮箱脱敏
* @param {string} email - 邮箱
* @returns {string}
*/
const maskEmail = (email) => {
if (!email || !email.includes('@')) return email
const [username, domain] = email.split('@')
if (username.length <= 3) {
return `***@${domain}`
}
return username.substring(0, 3) + '***@' + domain
}
/**
* 生成随机ID
* @param {number} length - 长度
* @returns {string}
*/
const generateId = (length = 16) => {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
let result = ''
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length))
}
return result
}
/**
* 防抖函数
* @param {Function} func - 执行函数
* @param {number} wait - 等待时间(ms)
* @returns {Function}
*/
const debounce = (func, wait = 300) => {
let timeout
return function (...args) {
clearTimeout(timeout)
timeout = setTimeout(() => {
func.apply(this, args)
}, wait)
}
}
/**
* 节流函数
* @param {Function} func - 执行函数
* @param {number} wait - 间隔时间(ms)
* @returns {Function}
*/
const throttle = (func, wait = 300) => {
let timeout
return function (...args) {
if (!timeout) {
timeout = setTimeout(() => {
timeout = null
func.apply(this, args)
}, wait)
}
}
}
/**
* 深拷贝
* @param {any} obj - 对象
* @returns {any}
*/
const deepClone = (obj) => {
if (obj === null || typeof obj !== 'object') return obj
if (Array.isArray(obj)) {
return obj.map(item => deepClone(item))
}
const clone = {}
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key])
}
}
return clone
}
/**
* URL参数解析
* @param {string} url - URL
* @returns {object}
*/
const parseQuery = (url) => {
const query = {}
const index = url.indexOf('?')
if (index !== -1) {
const params = url.substring(index + 1).split('&')
params.forEach(param => {
const [key, value] = param.split('=')
query[decodeURIComponent(key)] = decodeURIComponent(value || '')
})
}
return query
}
/**
* 对象转URL参数
* @param {object} obj - 对象
* @returns {string}
*/
const stringifyQuery = (obj) => {
const params = []
for (const key in obj) {
if (obj.hasOwnProperty(key) && obj[key] !== null && obj[key] !== undefined) {
params.push(`${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`)
}
}
return params.join('&')
}
/**
* 验证手机号
* @param {string} phone - 手机号
* @returns {boolean}
*/
const isValidPhone = (phone) => {
return /^1[3-9]\d{9}$/.test(phone)
}
/**
* 验证邮箱
* @param {string} email - 邮箱
* @returns {boolean}
*/
const isValidEmail = (email) => {
return /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$/.test(email)
}
/**
* 验证URL
* @param {string} url - URL
* @returns {boolean}
*/
const isValidUrl = (url) => {
return /^https?:\/\/.+/.test(url)
}
/**
* 数字格式化(千分位)
* @param {number} num - 数字
* @returns {string}
*/
const formatNumber = (num) => {
if (num === null || num === undefined) return ''
return String(num).replace(/\B(?=(\d{3})+(?!\d))/g, ',')
}
/**
* 文件大小格式化
* @param {number} bytes - 字节
* @returns {string}
*/
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 {string} str - 字符串
* @param {number} length - 长度
* @param {string} suffix - 后缀
* @returns {string}
*/
const truncate = (str, length = 50, suffix = '...') => {
if (!str || str.length <= length) return str
return str.substring(0, length) + suffix
}
module.exports = {
formatTime,
formatDate,
formatRelativeTime,
maskPhone,
maskEmail,
generateId,
debounce,
throttle,
deepClone,
parseQuery,
stringifyQuery,
isValidPhone,
isValidEmail,
isValidUrl,
formatNumber,
formatFileSize,
truncate
}
/**
* @联系作者16768118056
* @描述:(此项目非免费分享)源码百分百可用,搞定毕设不发愁,支持远程调试安装、二次开发、定制、讲解、文档类。
* @访问https://www.notmaker.com/detail/8326a897119d4542896c863a69d7bbe7/gtt20260415查看完整运行演示。
*/