420 lines
10 KiB
JavaScript
420 lines
10 KiB
JavaScript
/**
|
|
* 工具函数集合
|
|
* 包含打字机效果、ID生成、回调安全调用等通用工具函数
|
|
*/
|
|
|
|
/**
|
|
* ID生成工具类
|
|
* 提供各种ID生成功能
|
|
*/
|
|
export class IdUtils {
|
|
/**
|
|
* 生成消息ID
|
|
* @returns {string} 消息ID
|
|
*/
|
|
static generateMessageId() {
|
|
const timestamp = new Date().getTime();
|
|
const chars = "abcdefghijklmnopqrstuvwxyz";
|
|
const randomStr = Array.from({ length: 4 }, () =>
|
|
chars.charAt(Math.floor(Math.random() * chars.length))
|
|
).join("");
|
|
return "mid" + randomStr + timestamp;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 回调函数安全调用工具类
|
|
* 提供安全的回调函数调用机制
|
|
*/
|
|
export class CallbackUtils {
|
|
/**
|
|
* 安全调用回调函数
|
|
* @param {Object} callbacks - 回调函数对象
|
|
* @param {string} callbackName - 回调函数名称
|
|
* @param {...any} args - 传递给回调函数的参数
|
|
*/
|
|
static safeCall(callbacks, callbackName, ...args) {
|
|
if (callbacks && typeof callbacks[callbackName] === "function") {
|
|
try {
|
|
callbacks[callbackName](...args);
|
|
} catch (error) {
|
|
console.error(`回调函数 ${callbackName} 执行出错:`, error);
|
|
}
|
|
} else {
|
|
console.warn(`回调函数 ${callbackName} 不可用`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 批量安全调用回调函数
|
|
* @param {Object} callbacks - 回调函数对象
|
|
* @param {Array} callbackConfigs - 回调配置数组 [{name, args}, ...]
|
|
*/
|
|
static safeBatchCall(callbacks, callbackConfigs) {
|
|
callbackConfigs.forEach((config) => {
|
|
const { name, args = [] } = config;
|
|
this.safeCall(callbacks, name, ...args);
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 消息处理工具类
|
|
* 提供消息相关的工具函数
|
|
*/
|
|
export class MessageUtils {
|
|
/**
|
|
* 验证消息格式
|
|
* @param {any} message - 消息对象
|
|
* @returns {boolean} 是否为有效消息格式
|
|
*/
|
|
static validateMessage(message) {
|
|
return message && typeof message === "object" && message.type;
|
|
}
|
|
|
|
/**
|
|
* 格式化消息
|
|
* @param {string} type - 消息类型
|
|
* @param {any} content - 消息内容
|
|
* @param {Object} options - 额外选项
|
|
* @returns {Object} 格式化后的消息对象
|
|
*/
|
|
static formatMessage(type, content, options = {}) {
|
|
return {
|
|
type,
|
|
content,
|
|
timestamp: Date.now(),
|
|
...options,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 检查是否为完整消息
|
|
* @param {any} message - 消息对象
|
|
* @returns {boolean} 是否为完整消息
|
|
*/
|
|
static isCompleteMessage(message) {
|
|
return message && message.isComplete === true;
|
|
}
|
|
|
|
/**
|
|
* 检查消息是否为心跳响应
|
|
* @param {any} messageData - 消息数据
|
|
* @returns {boolean} 是否为心跳响应
|
|
*/
|
|
static isPongMessage(messageData) {
|
|
if (typeof messageData === "string") {
|
|
return (
|
|
messageData === "pong" || messageData.toLowerCase().includes("pong")
|
|
);
|
|
}
|
|
if (typeof messageData === "object" && messageData !== null) {
|
|
return messageData.type === "pong";
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 安全解析JSON消息
|
|
* @param {string} messageStr - 消息字符串
|
|
* @returns {Object|null} 解析后的对象或null
|
|
*/
|
|
static safeParseJSON(messageStr) {
|
|
try {
|
|
return JSON.parse(messageStr);
|
|
} catch (error) {
|
|
console.warn("JSON解析失败:", messageStr);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 创建打字机消息对象
|
|
* @param {string} content - 消息内容
|
|
* @param {boolean} isComplete - 是否完成
|
|
* @param {string} type - 消息类型
|
|
* @returns {Object} 消息对象
|
|
*/
|
|
static createTypewriterMessage(
|
|
content,
|
|
isComplete = false,
|
|
type = "typewriter"
|
|
) {
|
|
return {
|
|
type,
|
|
content,
|
|
isComplete,
|
|
timestamp: Date.now(),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 创建加载消息对象
|
|
* @param {string} content - 加载内容
|
|
* @returns {Object} 加载消息对象
|
|
*/
|
|
static createLoadingMessage(content = "加载中...") {
|
|
return {
|
|
type: "loading",
|
|
content,
|
|
timestamp: Date.now(),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 创建错误消息对象
|
|
* @param {string} error - 错误信息
|
|
* @returns {Object} 错误消息对象
|
|
*/
|
|
static createErrorMessage(error) {
|
|
return {
|
|
type: "error",
|
|
content: error.message || error || "未知错误",
|
|
timestamp: Date.now(),
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 定时器管理工具类
|
|
* 提供定时器的统一管理
|
|
*/
|
|
export class TimerUtils {
|
|
/**
|
|
* 安全清除定时器
|
|
* @param {number|null} timerId - 定时器ID
|
|
* @param {string} type - 定时器类型 'timeout' | 'interval'
|
|
* @returns {null} 返回null便于重置变量
|
|
*/
|
|
static safeClear(timerId, type = "timeout") {
|
|
if (timerId) {
|
|
if (type === "interval") {
|
|
clearInterval(timerId);
|
|
} else {
|
|
clearTimeout(timerId);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 清除定时器(别名方法)
|
|
* @param {number|null} timerId - 定时器ID
|
|
* @param {string} type - 定时器类型 'timeout' | 'interval'
|
|
* @returns {null} 返回null便于重置变量
|
|
*/
|
|
static clearTimer(timerId, type = "timeout") {
|
|
return this.safeClear(timerId, type);
|
|
}
|
|
|
|
/**
|
|
* 创建可取消的延时执行
|
|
* @param {Function} callback - 回调函数
|
|
* @param {number} delay - 延时时间
|
|
* @returns {Object} 包含cancel方法的对象
|
|
*/
|
|
static createCancelableTimeout(callback, delay) {
|
|
let timerId = setTimeout(callback, delay);
|
|
return {
|
|
cancel() {
|
|
if (timerId) {
|
|
clearTimeout(timerId);
|
|
timerId = null;
|
|
}
|
|
},
|
|
isActive() {
|
|
return timerId !== null;
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 创建可取消的定时执行
|
|
* @param {Function} callback - 回调函数
|
|
* @param {number} interval - 间隔时间
|
|
* @returns {Object} 包含cancel方法的对象
|
|
*/
|
|
static createCancelableInterval(callback, interval) {
|
|
let timerId = setInterval(callback, interval);
|
|
return {
|
|
cancel() {
|
|
if (timerId) {
|
|
clearInterval(timerId);
|
|
timerId = null;
|
|
}
|
|
},
|
|
isActive() {
|
|
return timerId !== null;
|
|
},
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 防抖工具类
|
|
* 提供防抖功能,防止函数在短时间内被重复调用
|
|
*/
|
|
export class DebounceUtils {
|
|
/**
|
|
* 创建防抖函数
|
|
* @param {Function} func - 要防抖的函数
|
|
* @param {number} delay - 防抖延迟时间
|
|
* @returns {Function} 防抖后的函数
|
|
*/
|
|
static createDebounce(func, delay) {
|
|
let timerId = null;
|
|
|
|
return function (...args) {
|
|
if (timerId) {
|
|
clearTimeout(timerId);
|
|
}
|
|
|
|
timerId = setTimeout(() => func.apply(this, args), delay);
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 节流工具类
|
|
* 提供节流功能,防止函数在短时间内被重复调用
|
|
*/
|
|
export class ThrottleUtils {
|
|
/**
|
|
* 创建节流函数(传统时间戳方式)
|
|
* @param {Function} func - 要节流的函数
|
|
* @param {number} delay - 节流延迟时间
|
|
* @returns {Function} 节流后的函数
|
|
*/
|
|
static createThrottle(func, delay) {
|
|
let prev = Date.now();
|
|
|
|
return function (...args) {
|
|
let now = Date.now();
|
|
|
|
if (now - prev >= delay) {
|
|
func.apply(this, args);
|
|
prev = now;
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 创建异步安全的节流函数(带执行状态锁)
|
|
* 适用于支付等需要等待完成的异步操作
|
|
* @param {Function} func - 要节流的异步函数
|
|
* @param {number} delay - 节流延迟时间(毫秒)
|
|
* @returns {Function} 节流后的函数
|
|
*/
|
|
static createAsyncThrottle(func, delay = 1000) {
|
|
let isExecuting = false; // 执行状态锁
|
|
let lastExecTime = 0; // 上次执行时间
|
|
|
|
return async function (...args) {
|
|
const now = Date.now();
|
|
|
|
// 如果正在执行中,直接返回
|
|
if (isExecuting) {
|
|
console.warn('函数正在执行中,跳过此次调用');
|
|
return;
|
|
}
|
|
|
|
// 如果还在节流时间内,直接返回
|
|
if (now - lastExecTime < delay) {
|
|
console.warn('节流时间内,跳过此次调用');
|
|
return;
|
|
}
|
|
|
|
// 加锁
|
|
isExecuting = true;
|
|
lastExecTime = now;
|
|
|
|
try {
|
|
// 执行异步函数
|
|
return await func.apply(this, args);
|
|
} catch (error) {
|
|
console.error('异步节流函数执行出错:', error);
|
|
throw error;
|
|
} finally {
|
|
// 无论成功失败都解锁
|
|
isExecuting = false;
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 创建执行锁函数(最简单的防重复方式,只锁执行状态)
|
|
* 适用于支付等场景,上一次没完成前绝对不执行第二次
|
|
* @param {Function} func - 要加锁的函数
|
|
* @returns {Function} 加锁后的函数
|
|
*/
|
|
static createExecutionLock(func) {
|
|
let isExecuting = false;
|
|
|
|
return async function (...args) {
|
|
// 如果正在执行中,直接返回
|
|
if (isExecuting) {
|
|
console.warn('函数正在执行中,跳过此次调用');
|
|
return;
|
|
}
|
|
|
|
// 加锁
|
|
isExecuting = true;
|
|
|
|
try {
|
|
// 执行函数
|
|
return await func.apply(this, args);
|
|
} catch (error) {
|
|
console.error('执行锁函数执行出错:', error);
|
|
throw error;
|
|
} finally {
|
|
// 无论成功失败都解锁
|
|
isExecuting = false;
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 日期工具类
|
|
* 提供日期格式化功能
|
|
* */
|
|
export class DateUtils {
|
|
/**
|
|
* 格式化日期为指定格式
|
|
* @param {Date} date - 日期对象
|
|
* @param {string} format - 格式化字符串,默认值为 "yyyy-MM-dd"
|
|
* @returns {string} 格式化后的日期字符串
|
|
*/
|
|
static formatDate(date = new Date(), format = "yyyy-MM-dd") {
|
|
const year = date.getFullYear();
|
|
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
const day = String(date.getDate()).padStart(2, "0");
|
|
|
|
return format.replace("yyyy", year).replace("MM", month).replace("dd", day);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 验证手机号工具类
|
|
* @param {string} phone - 手机号字符串
|
|
* @returns {boolean} 是否为有效手机号
|
|
*/
|
|
export class PhoneUtils {
|
|
static validatePhone(phone) {
|
|
const phoneRegex = /^1[3-9]\d{9}$/;
|
|
return phoneRegex.test(phone);
|
|
}
|
|
}
|
|
|
|
// 默认导出所有工具类
|
|
export default {
|
|
IdUtils,
|
|
CallbackUtils,
|
|
MessageUtils,
|
|
TimerUtils,
|
|
DateUtils,
|
|
DebounceUtils,
|
|
ThrottleUtils,
|
|
PhoneUtils,
|
|
};
|