/** * 工具函数集合 * 包含打字机效果、ID生成、回调安全调用等通用工具函数 */ /* ======================= * ID 生成工具 * ======================= */ export class IdUtils { /** * 生成消息 ID */ static generateMessageId(): string { const timestamp = Date.now() const chars = 'abcdefghijklmnopqrstuvwxyz' const randomStr = Array.from({ length: 4 }, () => chars.charAt(Math.floor(Math.random() * chars.length)) ).join('') return `mid${randomStr}${timestamp}` } } /* ======================= * 回调安全调用工具 * ======================= */ export type CallbackMap = Record any> export interface BatchCallbackConfig { name: string args?: any[] } export class CallbackUtils { /** * 安全调用回调函数 */ static safeCall( callbacks: CallbackMap | null | undefined, callbackName: string, ...args: any[] ): void { const cb = callbacks?.[callbackName] if (typeof cb === 'function') { try { cb(...args) } catch (error) { console.error(`回调函数 ${callbackName} 执行出错:`, error) } } else { console.warn(`回调函数 ${callbackName} 不可用`) } } /** * 批量安全调用回调函数 */ static safeBatchCall( callbacks: CallbackMap | null | undefined, callbackConfigs: BatchCallbackConfig[] ): void { callbackConfigs.forEach(({ name, args = [] }) => { this.safeCall(callbacks, name, ...args) }) } } /* ======================= * 消息处理工具 * ======================= */ export interface BaseMessage { type: string content?: any timestamp: number isComplete?: boolean [key: string]: any } export class MessageUtils { /** * 验证消息格式 */ static validateMessage(message: unknown): message is BaseMessage { return ( typeof message === 'object' && message !== null && 'type' in message ) } /** * 格式化消息 */ static formatMessage( type: string, content: T, options: Partial = {} ): BaseMessage { return { type, content, timestamp: Date.now(), ...options, } } /** * 是否为完整消息 */ static isCompleteMessage(message: Partial | null | undefined): boolean { return message?.isComplete === true } /** * 是否为心跳 pong */ static isPongMessage(messageData: unknown): boolean { if (typeof messageData === 'string') { return messageData === 'pong' || messageData.toLowerCase().includes('pong') } if (typeof messageData === 'object' && messageData !== null) { return (messageData as any).type === 'pong' } return false } /** * 安全解析 JSON */ static safeParseJSON(messageStr: string): T | null { try { return JSON.parse(messageStr) as T } catch { console.warn('JSON 解析失败:', messageStr) return null } } /** * 创建打字机消息 */ static createTypewriterMessage( content: string, isComplete = false, type = 'typewriter' ): BaseMessage { return { type, content, isComplete, timestamp: Date.now(), } } /** * 创建加载消息 */ static createLoadingMessage(content = '加载中...'): BaseMessage { return { type: 'loading', content, timestamp: Date.now(), } } /** * 创建错误消息 */ static createErrorMessage(error: unknown): BaseMessage { return { type: 'error', content: error instanceof Error ? error.message : String(error ?? '未知错误'), timestamp: Date.now(), } } } /* ======================= * 定时器工具 * ======================= */ export type TimerType = 'timeout' | 'interval' export interface CancelableTimer { cancel(): void isActive(): boolean } export class TimerUtils { static safeClear( timerId: number | null, type: TimerType = 'timeout' ): null { if (timerId !== null) { type === 'interval' ? clearInterval(timerId) : clearTimeout(timerId) } return null } static clearTimer( timerId: number | null, type: TimerType = 'timeout' ): null { return this.safeClear(timerId, type) } static createCancelableTimeout( callback: () => void, delay: number ): CancelableTimer { let timerId: number | null = window.setTimeout(callback, delay) return { cancel() { if (timerId !== null) { clearTimeout(timerId) timerId = null } }, isActive() { return timerId !== null }, } } static createCancelableInterval( callback: () => void, interval: number ): CancelableTimer { let timerId: number | null = window.setInterval(callback, interval) return { cancel() { if (timerId !== null) { clearInterval(timerId) timerId = null } }, isActive() { return timerId !== null }, } } } /* ======================= * 防抖工具 * ======================= */ export class DebounceUtils { static createDebounce void>( func: T, delay: number ): (...args: Parameters) => void { let timerId: number | null = null return function (this: unknown, ...args: Parameters) { if (timerId !== null) { clearTimeout(timerId) } timerId = window.setTimeout(() => func.apply(this, args), delay) } } } /* ======================= * 节流工具 * ======================= */ export class ThrottleUtils { static createThrottle void>( func: T, delay: number ): (...args: Parameters) => void { let prev = Date.now() return function (this: unknown, ...args: Parameters) { const now = Date.now() if (now - prev >= delay) { func.apply(this, args) prev = now } } } } /* ======================= * 日期工具 * ======================= */ export class DateUtils { static formatDate( date: Date = new Date(), format: string = 'yyyy-MM-dd' ): string { 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', String(year)) .replace('MM', month) .replace('dd', day) } } /* ======================= * 手机号校验 * ======================= */ export class PhoneUtils { static validatePhone(phone: string): boolean { const phoneRegex = /^1[3-9]\d{9}$/ return phoneRegex.test(phone) } } /* ======================= * 默认导出 * ======================= */ export default { IdUtils, CallbackUtils, MessageUtils, TimerUtils, DateUtils, DebounceUtils, ThrottleUtils, PhoneUtils, }