/** * ChatbotSDK 入口文件 * 单例模式,IIFE 挂载 window.ChatbotSDK * * 参数映射: * integrateId → roleId(客服角色 ID) * userId → accountId(客户账号 ID) * chatId → 自动管理(从 /conversation/list 获取或自动生成) */ import { SDKConfig, ResolvedConfig, ChatbotSDKInstance } from './types'; import { parseConfig } from './config'; import { setDebug, logger } from './logger'; import { setApiConfig } from './api'; import { injectStyles, removeStyles } from './styles'; import { createLauncher, createChatWindow, enableDrag } from './dom'; import { initChat, initChatHistory, getMessages, setCategory, loadHistoryConversations } from './chat'; import { clearMessages } from './storage'; import { setLocale } from './i18n'; // ==================== 单例状态 ==================== let config: ResolvedConfig | null = null; let isInitialized = false; let launcherEl: HTMLElement | null = null; let windowEl: HTMLElement | null = null; let messagesContainer: HTMLElement | null = null; let inputEl: HTMLTextAreaElement | null = null; let sendBtn: HTMLElement | null = null; let clearBtn: HTMLElement | null = null; let categorySelect: HTMLSelectElement | null = null; let historyPanel: HTMLElement | null = null; let showLoadingFn: (() => HTMLElement) | null = null; let hideLoadingFn: (() => void) | null = null; let dragCleanup: (() => void) | null = null; // ==================== 公开 API ==================== /** 初始化 SDK */ function init(rawConfig: SDKConfig): void { if (isInitialized) { logger.warn('SDK 已初始化,请先调用 destroy() 再重新初始化'); return; } // 1. 配置解析与校验 const parsed = parseConfig(rawConfig); if (!parsed) return; config = parsed; // 2. 设置国际化语言 setLocale(config.locale); // 3. 设置日志级别 setDebug(config.debug); // 4. 设置 API 配置 setApiConfig(config); // 5. 注入样式 injectStyles(config); // 6. 创建悬浮按钮 launcherEl = createLauncher(config, toggle); document.body.appendChild(launcherEl); // 7. 创建聊天弹窗 const dom = createChatWindow(config); windowEl = dom.window; messagesContainer = dom.messagesContainer; inputEl = dom.inputEl; sendBtn = dom.sendBtn; clearBtn = dom.clearBtn; categorySelect = dom.categorySelect; historyPanel = dom.historyPanel; showLoadingFn = dom.showLoading; hideLoadingFn = dom.hideLoading; document.body.appendChild(windowEl); // 8. 启用拖拽 const headerEl = windowEl.querySelector('.csk-header') as HTMLElement; if (headerEl) { dragCleanup = enableDrag(headerEl, windowEl); } // 9. 初始化对话模块 initChat(config, { messagesContainer, inputEl, sendBtn, clearBtn, categorySelect, historyPanel, showLoading: showLoadingFn, hideLoading: hideLoadingFn, }); // 10. 监听知识库分类切换事件 windowEl.addEventListener('csk:categoryChange', ((e: CustomEvent) => { setCategory(e.detail.categoryId); }) as EventListener); // 11. 监听会话管理面板加载事件 windowEl.addEventListener('csk:loadHistory', () => { loadHistoryConversations(); }); isInitialized = true; logger.lifecycleInit(config.integrateId, config.requestDomain); // 12. 异步初始化 chatId 和对话历史(不阻塞 UI) initChatHistory().catch(err => { logger.warn('chatId 初始化失败,将在发送消息时重试', err); }); } /** 销毁 SDK 实例 */ function destroy(): void { if (!isInitialized) return; if (launcherEl && launcherEl.parentNode) { launcherEl.parentNode.removeChild(launcherEl); launcherEl = null; } if (windowEl && windowEl.parentNode) { windowEl.parentNode.removeChild(windowEl); windowEl = null; } if (dragCleanup) { dragCleanup(); dragCleanup = null; } removeStyles(); const oldIntegrateId = config?.integrateId; config = null; isInitialized = false; messagesContainer = null; inputEl = null; sendBtn = null; clearBtn = null; categorySelect = null; historyPanel = null; showLoadingFn = null; hideLoadingFn = null; logger.lifecycleDestroy(oldIntegrateId || ''); } function open(): void { if (!windowEl) return; windowEl.classList.remove('csk-window--hidden'); } function close(): void { if (!windowEl) return; windowEl.classList.add('csk-window--hidden'); } function toggle(): void { if (!windowEl) return; if (windowEl.classList.contains('csk-window--hidden')) { open(); setTimeout(() => { if (inputEl) inputEl.focus(); }, 100); } else { close(); } } function clearHistory(): void { if (!config) return; if (clearBtn) { clearBtn.click(); } else if (confirm('确定清空所有对话记录?')) { clearMessages(config.integrateId); } } // ==================== 挂载到全局 ==================== const ChatbotSDK: ChatbotSDKInstance = { init, destroy, open, close, toggle, clearHistory, }; if (typeof window !== 'undefined') { (window as unknown as Record).ChatbotSDK = ChatbotSDK; } export default ChatbotSDK;