This commit is contained in:
mzltMpfqGS
2026-04-15 19:45:16 +08:00
commit e4a087e67e
301 changed files with 35048 additions and 0 deletions

296
wechat/utils/util.js Normal file
View File

@@ -0,0 +1,296 @@
// 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查看完整运行演示。
*/