customer-chat-sdk 1.2.0 → 1.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2185,741 +2185,6 @@ class IconManager {
2185
2185
  }
2186
2186
  }
2187
2187
 
2188
- class IframeManager {
2189
- constructor(config = {}) {
2190
- this.iframeElement = null;
2191
- this.containerElement = null; // 包装容器,包含iframe和关闭按钮
2192
- this.isOpen = false;
2193
- this.isCreated = false;
2194
- this.debug = false; // debug 模式标志
2195
- this.targetElement = null; // 目标元素(用于自适应宽度)
2196
- this.messageHandler = null; // 消息监听器引用(用于清理)
2197
- this.config = {
2198
- src: '',
2199
- mode: 'auto', // 默认自动检测设备类型
2200
- width: 450, // PC 模式默认宽度
2201
- height: 600,
2202
- allowClose: true,
2203
- ...config
2204
- };
2205
- this.debug = config.debug ?? false;
2206
- // 不在构造函数中添加消息监听器,延迟到 init() 中添加
2207
- // 这样可以避免创建多个实例时产生多个监听器
2208
- }
2209
- /**
2210
- * 初始化iframe(隐藏状态)
2211
- * 预创建iframe并连接到SSE,但不显示
2212
- */
2213
- async init() {
2214
- try {
2215
- // 设置消息监听器(在 init() 中而不是构造函数中,避免多次创建实例时产生多个监听器)
2216
- this.setupMessageListener();
2217
- // 关键修复:在初始化前,先清理页面上所有旧的容器元素
2218
- // 防止切换模式或多次初始化时产生重复的元素
2219
- this.cleanupOrphanedElements();
2220
- // 创建隐藏的iframe(预连接到SSE)
2221
- // 注意:createIframe 会将容器添加到 body
2222
- this.createIframe();
2223
- this.isCreated = true;
2224
- if (this.debug) {
2225
- console.log('CustomerSDK iframe initialized (hidden, SSE connected)');
2226
- }
2227
- }
2228
- catch (error) {
2229
- // 错误始终输出
2230
- console.error('Failed to initialize iframe:', error);
2231
- // 如果初始化失败,清理消息监听器
2232
- if (this.messageHandler) {
2233
- window.removeEventListener('message', this.messageHandler);
2234
- this.messageHandler = null;
2235
- }
2236
- throw error;
2237
- }
2238
- }
2239
- /**
2240
- * 显示iframe聊天窗口
2241
- */
2242
- show() {
2243
- if (this.isOpen) {
2244
- return;
2245
- }
2246
- if (!this.isCreated) {
2247
- throw new Error('Iframe not initialized. Call init() first.');
2248
- }
2249
- try {
2250
- // 显示已创建的容器
2251
- // 关键优化:容器在 init() 时已经添加到正确位置,这里只改变样式,不移动 DOM
2252
- // 这样可以避免 iframe 重新加载
2253
- if (this.containerElement) {
2254
- // 确保容器在 DOM 中(理论上已经在 init() 时添加,但为了安全)
2255
- if (!this.containerElement.parentNode) {
2256
- // 如果容器不在 DOM 中(异常情况),添加到 target 或 body
2257
- if (this.targetElement && this.targetElement !== document.body) {
2258
- // 确保 target 是相对定位
2259
- const targetStyle = window.getComputedStyle(this.targetElement);
2260
- if (targetStyle.position === 'static') {
2261
- this.targetElement.style.position = 'relative';
2262
- }
2263
- this.targetElement.appendChild(this.containerElement);
2264
- if (this.debug) {
2265
- console.log('Iframe container re-added to target element in show()');
2266
- }
2267
- }
2268
- else {
2269
- // 没有 target 或 target 是 body,添加到 body
2270
- document.body.appendChild(this.containerElement);
2271
- if (this.debug) {
2272
- console.log('Iframe container re-added to document.body in show()');
2273
- }
2274
- }
2275
- }
2276
- // 根据是否有 target 设置正确的定位方式
2277
- const useTargetWidth = !!this.targetElement && this.targetElement !== document.body;
2278
- const displayStyles = useTargetWidth ? {
2279
- // 使用 target 时,保持 absolute 定位(相对于 target)
2280
- position: 'absolute',
2281
- visibility: 'visible',
2282
- opacity: '1',
2283
- display: 'block'
2284
- } : {
2285
- // 没有 target 时,使用 fixed 定位(相对于视口)
2286
- position: 'fixed',
2287
- visibility: 'visible',
2288
- opacity: '1',
2289
- display: 'block'
2290
- };
2291
- Object.assign(this.containerElement.style, displayStyles);
2292
- // 禁用body滚动,防止出现滚动条
2293
- this.preventBodyScroll(true);
2294
- }
2295
- this.isOpen = true;
2296
- if (this.debug) {
2297
- console.log('CustomerSDK iframe shown');
2298
- }
2299
- }
2300
- catch (error) {
2301
- // 错误始终输出
2302
- console.error('Failed to show iframe:', error);
2303
- }
2304
- }
2305
- /**
2306
- * 打开iframe聊天窗口(保持兼容性)
2307
- */
2308
- open() {
2309
- this.show();
2310
- }
2311
- /**
2312
- * 隐藏iframe聊天窗口(类似v-show)
2313
- */
2314
- hide() {
2315
- if (!this.isOpen) {
2316
- return;
2317
- }
2318
- // 隐藏容器但保留DOM元素(不移动容器,避免 iframe 重新加载)
2319
- if (this.containerElement) {
2320
- Object.assign(this.containerElement.style, {
2321
- visibility: 'hidden',
2322
- opacity: '0',
2323
- display: 'none'
2324
- });
2325
- // 注意:不移动容器,保持容器在当前位置(body),避免 iframe 重新加载
2326
- }
2327
- // 恢复body滚动
2328
- this.preventBodyScroll(false);
2329
- this.isOpen = false;
2330
- if (this.debug) {
2331
- console.log('CustomerSDK iframe hidden (SSE still connected)');
2332
- }
2333
- // 触发关闭回调
2334
- if (this.config.onClose) {
2335
- this.config.onClose();
2336
- }
2337
- }
2338
- /**
2339
- * 关闭iframe聊天窗口(完全销毁,保持兼容性)
2340
- */
2341
- close() {
2342
- this.hide(); // 默认只隐藏,不销毁
2343
- }
2344
- /**
2345
- * 完全销毁iframe(需要时才调用)
2346
- */
2347
- destroy() {
2348
- this.hide();
2349
- // 移除消息监听器(防止内存泄漏)
2350
- if (this.messageHandler) {
2351
- window.removeEventListener('message', this.messageHandler);
2352
- this.messageHandler = null;
2353
- }
2354
- // 移除容器
2355
- if (this.containerElement) {
2356
- this.containerElement.remove();
2357
- this.containerElement = null;
2358
- this.iframeElement = null;
2359
- }
2360
- this.isCreated = false;
2361
- if (this.debug) {
2362
- console.log('CustomerSDK container destroyed');
2363
- }
2364
- }
2365
- /**
2366
- * 检查是否已打开
2367
- */
2368
- isIframeOpen() {
2369
- return this.isOpen;
2370
- }
2371
- /**
2372
- * 向iframe发送消息
2373
- */
2374
- sendToIframe(data) {
2375
- if (this.iframeElement && this.iframeElement.contentWindow) {
2376
- this.iframeElement.contentWindow.postMessage(data, '*');
2377
- }
2378
- }
2379
- /**
2380
- * 清理页面上孤立的容器元素(防止重复创建)
2381
- */
2382
- cleanupOrphanedElements() {
2383
- // 清理所有旧的容器元素(不属于当前实例的)
2384
- const existingContainers = document.querySelectorAll('.customer-sdk-container');
2385
- existingContainers.forEach((container) => {
2386
- if (container !== this.containerElement) {
2387
- container.remove();
2388
- if (this.debug) {
2389
- console.log('清理旧的容器元素');
2390
- }
2391
- }
2392
- });
2393
- }
2394
- /**
2395
- * 创建iframe(默认隐藏状态,用于SSE连接)
2396
- */
2397
- createIframe() {
2398
- // 创建包装容器(包含iframe和关闭按钮)
2399
- this.containerElement = document.createElement('div');
2400
- this.containerElement.className = 'customer-sdk-container';
2401
- // 确保容器不可拖动
2402
- this.containerElement.draggable = false;
2403
- // 创建iframe元素
2404
- this.iframeElement = document.createElement('iframe');
2405
- this.iframeElement.className = 'customer-sdk-iframe';
2406
- // 设置iframe属性
2407
- // 注意:URL只在初始化时设置一次,之后不会刷新
2408
- // 如果需要更新URL参数,需要重新初始化SDK
2409
- this.iframeElement.src = this.config.src || '';
2410
- this.iframeElement.frameBorder = '0';
2411
- // 添加必要权限(只保留常用的)
2412
- this.iframeElement.setAttribute('allow', [
2413
- 'microphone', // 麦克风权限
2414
- 'camera', // 摄像头权限
2415
- 'geolocation', // 地理位置权限
2416
- 'clipboard-read', // 剪贴板读取权限
2417
- 'clipboard-write', // 剪贴板写入权限
2418
- 'fullscreen', // 全屏权限
2419
- 'autoplay', // 自动播放权限
2420
- 'encrypted-media' // 加密媒体权限
2421
- ].join('; '));
2422
- // 设置sandbox属性(允许所有必要功能)
2423
- this.iframeElement.setAttribute('sandbox', [
2424
- 'allow-same-origin', // 允许同源
2425
- 'allow-scripts', // 允许脚本
2426
- 'allow-forms', // 允许表单
2427
- 'allow-popups', // 允许弹窗
2428
- 'allow-popups-to-escape-sandbox', // 允许弹窗逃逸沙箱
2429
- 'allow-presentation', // 允许演示
2430
- 'allow-top-navigation', // 允许顶级导航
2431
- 'allow-top-navigation-by-user-activation', // 允许用户激活的顶级导航
2432
- 'allow-downloads', // 允许下载
2433
- 'allow-modals', // 允许模态框
2434
- 'allow-orientation-lock', // 允许方向锁定
2435
- 'allow-pointer-lock', // 允许指针锁定
2436
- 'allow-storage-access-by-user-activation' // 允许用户激活的存储访问
2437
- ].join(' '));
2438
- // 获取目标元素(如果提供了 target)
2439
- if (this.config.target) {
2440
- this.targetElement = this.getTargetElement(this.config.target);
2441
- }
2442
- // 根据设备类型设置模式
2443
- const actualMode = this.getActualMode();
2444
- const isPC = actualMode === 'popup';
2445
- this.iframeElement.scrolling = 'auto'; // PC和移动端都显示滚动条
2446
- // 判断是否使用 target 的自适应宽度
2447
- const useTargetWidth = !!this.targetElement && this.targetElement !== document.body;
2448
- // PC模式:如果传了 target,使用 target 的宽度(自适应);否则使用配置的宽度
2449
- // 移动端:如果传了 target,使用 target 的宽度(自适应);否则全屏
2450
- const containerStyles = useTargetWidth ? {
2451
- // 使用 target 的宽度(自适应),PC 和移动端都适用
2452
- // 宽度 100% 自适应 target 的实际宽度(target 本身可能有 max-width 限制)
2453
- width: '100%',
2454
- height: '100%',
2455
- maxWidth: '100%', // 不超过 target 的宽度
2456
- maxHeight: '100%',
2457
- backgroundColor: '#ffffff',
2458
- borderRadius: isPC ? '0' : '0',
2459
- boxShadow: isPC ? 'none' : '0 -4px 16px rgba(0, 0, 0, 0.25)',
2460
- border: 'none',
2461
- position: 'absolute', // 相对于 target 元素定位
2462
- zIndex: '999999',
2463
- // 占满 target 元素
2464
- top: '0',
2465
- left: '0',
2466
- bottom: '0',
2467
- right: '0',
2468
- transform: 'none',
2469
- overflow: 'hidden',
2470
- // 初始隐藏的关键样式
2471
- visibility: 'hidden',
2472
- opacity: '0',
2473
- display: 'none'
2474
- } : (isPC ? {
2475
- // PC模式:没有 target,固定在右下角(不可拖动)
2476
- width: `${this.config.width || 450}px`,
2477
- height: `${this.config.height || 600}px`,
2478
- maxWidth: '90vw',
2479
- maxHeight: '90vh',
2480
- backgroundColor: '#ffffff',
2481
- borderRadius: '8px',
2482
- boxShadow: '0 4px 16px rgba(0, 0, 0, 0.25)',
2483
- border: 'none',
2484
- position: 'fixed',
2485
- zIndex: '999999',
2486
- // PC模式:固定在右下角
2487
- top: 'auto',
2488
- left: 'auto',
2489
- bottom: '20px',
2490
- right: '20px',
2491
- transform: 'none',
2492
- overflow: 'hidden',
2493
- // 防止拖动和选择
2494
- userSelect: 'none',
2495
- WebkitUserSelect: 'none',
2496
- MozUserSelect: 'none',
2497
- msUserSelect: 'none',
2498
- // 初始隐藏的关键样式
2499
- visibility: 'hidden',
2500
- opacity: '0',
2501
- display: 'none'
2502
- } : {
2503
- // 移动端全屏模式(没有 target,强制 100% 宽度和高度)
2504
- width: '100%',
2505
- height: '100%',
2506
- maxWidth: '100%',
2507
- maxHeight: '100%',
2508
- backgroundColor: '#ffffff',
2509
- borderRadius: '0',
2510
- boxShadow: '0 -4px 16px rgba(0, 0, 0, 0.25)',
2511
- border: 'none',
2512
- position: 'fixed',
2513
- zIndex: '999999',
2514
- // 全屏模式 - 占满整个屏幕
2515
- top: '0',
2516
- left: '0',
2517
- bottom: '0',
2518
- right: '0',
2519
- transform: 'none',
2520
- overflow: 'hidden',
2521
- // 初始隐藏的关键样式
2522
- visibility: 'hidden',
2523
- opacity: '0',
2524
- display: 'none'
2525
- });
2526
- Object.assign(this.containerElement.style, containerStyles);
2527
- // iframe填充整个容器
2528
- const iframeStyles = {
2529
- width: '100%',
2530
- height: '100%',
2531
- border: 'none',
2532
- borderRadius: 'inherit'
2533
- };
2534
- Object.assign(this.iframeElement.style, iframeStyles);
2535
- // 将iframe放入容器
2536
- this.containerElement.appendChild(this.iframeElement);
2537
- // PC模式下:禁止拖动容器
2538
- if (isPC && !useTargetWidth) {
2539
- // 阻止拖动事件
2540
- this.containerElement.addEventListener('dragstart', (e) => {
2541
- e.preventDefault();
2542
- e.stopPropagation();
2543
- return false;
2544
- }, false);
2545
- // 阻止鼠标按下事件(防止可能的拖动行为)
2546
- this.containerElement.addEventListener('mousedown', (e) => {
2547
- // 只阻止在容器边缘的拖动,允许点击 iframe 内容
2548
- const rect = this.containerElement.getBoundingClientRect();
2549
- const isOnEdge = (e.clientX < rect.left + 10 ||
2550
- e.clientX > rect.right - 10 ||
2551
- e.clientY < rect.top + 10 ||
2552
- e.clientY > rect.bottom - 10);
2553
- if (isOnEdge) {
2554
- e.preventDefault();
2555
- e.stopPropagation();
2556
- }
2557
- }, false);
2558
- }
2559
- // 添加iframe加载事件监听(移动端样式优化)
2560
- this.iframeElement.addEventListener('load', () => {
2561
- // 移动端注入自定义样式
2562
- if (!isPC) {
2563
- this.injectMobileStyles();
2564
- }
2565
- });
2566
- // 添加到目标元素或 body
2567
- if (this.targetElement && this.targetElement !== document.body) {
2568
- // 如果提供了 target,添加到 target 元素内
2569
- // 需要设置 target 为相对定位,以便 iframe 可以相对于它定位
2570
- const targetStyle = window.getComputedStyle(this.targetElement);
2571
- if (targetStyle.position === 'static') {
2572
- // 如果 target 是静态定位,设置为相对定位
2573
- this.targetElement.style.position = 'relative';
2574
- if (this.debug) {
2575
- console.log('Set target element position to relative for iframe container');
2576
- }
2577
- }
2578
- this.targetElement.appendChild(this.containerElement);
2579
- if (this.debug) {
2580
- console.log('Iframe container added to target element');
2581
- }
2582
- }
2583
- else {
2584
- // 没有 target 或 target 是 body,添加到 body
2585
- document.body.appendChild(this.containerElement);
2586
- if (this.debug) {
2587
- console.log('Iframe container added to document.body');
2588
- }
2589
- }
2590
- if (this.debug) {
2591
- console.log('CustomerSDK container created (hidden, ready for SSE)');
2592
- }
2593
- }
2594
- /**
2595
- * 向iframe注入移动端优化样式(隐藏滚动条)
2596
- */
2597
- injectMobileStyles() {
2598
- if (!this.iframeElement)
2599
- return;
2600
- try {
2601
- const iframeDoc = this.iframeElement.contentDocument ||
2602
- this.iframeElement.contentWindow?.document;
2603
- if (iframeDoc) {
2604
- // 创建样式元素
2605
- const style = iframeDoc.createElement('style');
2606
- style.textContent = `
2607
- /* 移动端iframe全屏样式优化 */
2608
- * {
2609
- -webkit-overflow-scrolling: touch !important;
2610
- }
2611
-
2612
- body, html, #app, .container {
2613
- overflow: auto !important;
2614
- -webkit-overflow-scrolling: touch !important;
2615
- }
2616
-
2617
- /* 隐藏所有滚动条 */
2618
- ::-webkit-scrollbar {
2619
- width: 0px !important;
2620
- height: 0px !important;
2621
- background: transparent !important;
2622
- }
2623
-
2624
- /* Firefox */
2625
- html {
2626
- scrollbar-width: none !important;
2627
- }
2628
-
2629
- /* IE/Edge */
2630
- body {
2631
- -ms-overflow-style: none !important;
2632
- }
2633
-
2634
- /* 确保内容可以滚动 */
2635
- body {
2636
- overflow: auto !important;
2637
- height: 100vh !important;
2638
- margin: 0 !important;
2639
- padding: 0 !important;
2640
- }
2641
- `;
2642
- // 注入样式
2643
- iframeDoc.head?.appendChild(style);
2644
- if (this.debug) {
2645
- console.log('CustomerSDK mobile styles injected successfully');
2646
- }
2647
- }
2648
- }
2649
- catch (error) {
2650
- // 跨域限制时静默忽略
2651
- if (this.debug) {
2652
- console.log('Cannot inject styles due to cross-origin restrictions:', error);
2653
- }
2654
- }
2655
- }
2656
- /**
2657
- * 控制页面滚动(移动端全屏模式使用)
2658
- */
2659
- preventBodyScroll(prevent) {
2660
- if (prevent) {
2661
- // 保存当前滚动位置
2662
- const scrollY = window.scrollY;
2663
- // 应用防止滚动的样式
2664
- Object.assign(document.body.style, {
2665
- position: 'fixed',
2666
- top: `-${scrollY}px`,
2667
- width: '100%',
2668
- overflow: 'hidden'
2669
- });
2670
- // 记录滚动位置以便恢复
2671
- document.body.setAttribute('data-scroll-position', scrollY.toString());
2672
- }
2673
- else {
2674
- // 获取保存的滚动位置
2675
- const scrollY = parseInt(document.body.getAttribute('data-scroll-position') || '0');
2676
- // 移除防止滚动的样式
2677
- Object.assign(document.body.style, {
2678
- position: '',
2679
- top: '',
2680
- width: '',
2681
- overflow: ''
2682
- });
2683
- // 移除记录的属性
2684
- document.body.removeAttribute('data-scroll-position');
2685
- // 恢复正常滚动位置
2686
- window.scrollTo(0, scrollY);
2687
- }
2688
- }
2689
- /**
2690
- * 检测设备类型
2691
- */
2692
- isMobileDevice() {
2693
- return window.innerWidth <= 768 ||
2694
- /Android|iPhone|iPad|iPod|Opera Mini|IEMobile/i.test(navigator.userAgent);
2695
- }
2696
- /**
2697
- * 获取当前显示模式
2698
- * PC 模式使用弹窗,移动端使用全屏
2699
- */
2700
- getActualMode() {
2701
- if (this.config.mode === 'auto') {
2702
- return this.isMobileDevice() ? 'fullscreen' : 'popup';
2703
- }
2704
- return this.config.mode;
2705
- }
2706
- /**
2707
- * 设置消息监听
2708
- */
2709
- setupMessageListener() {
2710
- // 如果已存在,先移除旧的监听器(防止重复添加)
2711
- if (this.messageHandler) {
2712
- window.removeEventListener('message', this.messageHandler);
2713
- }
2714
- // 创建新的消息处理器并保存引用
2715
- this.messageHandler = (event) => {
2716
- // 关键:过滤掉自己通过 dispatchEvent 发送的消息,避免无限循环
2717
- // 自己发送的消息 source 是 window,而 iframe 发送的消息 source 是 iframe.contentWindow
2718
- if (event.source === window) {
2719
- if (this.debug) {
2720
- console.log('[IframeManager] Ignoring self-broadcasted message to prevent infinite loop:', event.data);
2721
- }
2722
- return;
2723
- }
2724
- // 不验证来源,直接处理所有消息(确保消息能够被接收)
2725
- if (this.debug) {
2726
- console.log('[IframeManager] Message received:', {
2727
- data: event.data,
2728
- origin: event.origin,
2729
- source: event.source
2730
- });
2731
- }
2732
- this.handleIframeMessage(event.data);
2733
- };
2734
- window.addEventListener('message', this.messageHandler, false);
2735
- }
2736
- /**
2737
- * 处理来自iframe的消息
2738
- */
2739
- handleIframeMessage(data) {
2740
- if (this.debug) {
2741
- console.log('[IframeManager] Message from iframe received:', data);
2742
- }
2743
- // 判断data是字符串还是对象,兼容两种格式
2744
- let messageType;
2745
- if (typeof data === 'string') {
2746
- messageType = data;
2747
- }
2748
- else if (data && data.type) {
2749
- messageType = data.type;
2750
- }
2751
- else {
2752
- if (this.debug) {
2753
- console.log('[IframeManager] Unknown message format:', data);
2754
- }
2755
- return;
2756
- }
2757
- if (this.debug) {
2758
- console.log('[IframeManager] Parsed message type:', messageType);
2759
- }
2760
- // 根据消息类型处理不同的操作
2761
- switch (messageType) {
2762
- case 'iframe_ready':
2763
- if (this.debug) {
2764
- console.log('Iframe is ready');
2765
- }
2766
- break;
2767
- case 'close_iframe':
2768
- case 'close':
2769
- this.close();
2770
- break;
2771
- case 'resize_iframe':
2772
- case 'resize':
2773
- // PC模式支持 resize,移动端忽略
2774
- const actualMode = this.getActualMode();
2775
- if (actualMode === 'popup' && data.width && data.height) {
2776
- this.resizeIframe(data.width, data.height);
2777
- }
2778
- else if (this.debug) {
2779
- console.log('Resize request ignored (fullscreen mode)');
2780
- }
2781
- break;
2782
- case 'new-message':
2783
- // 新消息通知 - 触发回调让外层处理
2784
- if (this.debug) {
2785
- console.log('Received new message notification');
2786
- }
2787
- if (this.config.onMessage) {
2788
- this.config.onMessage(messageType, data);
2789
- }
2790
- break;
2791
- case 'goto-login':
2792
- // 登录跳转消息 - 广播给调用 SDK 的 Vue 页面
2793
- if (this.debug) {
2794
- console.log('Received goto-login message, broadcasting to Vue page');
2795
- }
2796
- this.broadcastMessageToPage(data);
2797
- if (this.config.onMessage) {
2798
- this.config.onMessage(messageType, data);
2799
- }
2800
- break;
2801
- case 'DCR_DEPOSIT':
2802
- // 存款跳转消息 - 广播给调用 SDK 的 Vue 页面
2803
- // 支持两种存款类型:
2804
- // 1. 钱包直充:{ type: 'DCR_DEPOSIT', payload: { depositType: 0, walletId: 69382 } }
2805
- // 2. 线下充值:{ type: 'DCR_DEPOSIT', payload: { depositType: 2, offlineTypeId: 2001, accountId: 35213 } }
2806
- if (this.debug) {
2807
- const depositType = data.payload?.depositType;
2808
- const depositTypeText = depositType === 0 ? '钱包直充' : depositType === 2 ? '线下充值' : '未知类型';
2809
- console.log(`[IframeManager] Received DCR_DEPOSIT message (${depositTypeText}):`, {
2810
- type: data.type,
2811
- payload: data.payload,
2812
- depositType: depositTypeText
2813
- });
2814
- }
2815
- this.broadcastMessageToPage(data);
2816
- if (this.config.onMessage) {
2817
- this.config.onMessage(messageType, data);
2818
- }
2819
- break;
2820
- case 'DCR_ACTIVITY':
2821
- // 跳转到优惠页面 - 广播给调用 SDK 的 Vue 页面
2822
- // 格式:{ type: 'DCR_ACTIVITY', payload: { activityId: 123 } }
2823
- if (this.debug) {
2824
- console.log('[IframeManager] Received DCR_ACTIVITY message:', {
2825
- type: data.type,
2826
- payload: data.payload,
2827
- activityId: data.payload?.activityId
2828
- });
2829
- }
2830
- this.broadcastMessageToPage(data);
2831
- if (this.config.onMessage) {
2832
- this.config.onMessage(messageType, data);
2833
- }
2834
- break;
2835
- default:
2836
- // 其他自定义消息处理
2837
- if (this.debug) {
2838
- console.log('[IframeManager] Custom message:', data);
2839
- }
2840
- break;
2841
- }
2842
- }
2843
- /**
2844
- * 向调用 SDK 的地方(Vue 页面)广播消息
2845
- * 通过 window.dispatchEvent 触发事件,让 Vue 页面中的 window.addEventListener('message') 可以收到
2846
- *
2847
- * 重要说明:
2848
- * 1. window.dispatchEvent 创建的事件会在同一窗口内触发所有监听器,无论 origin 是什么,Vue 页面都能收到
2849
- * 2. MessageEvent 的 origin 属性不能是 '*',必须是有效的 origin 字符串(如 'http://localhost:5173')
2850
- * 3. 我们使用 window.location.origin 来标识消息来源(当前页面的 origin)
2851
- * 4. 如果 Vue 页面需要检查 origin,应该检查 window.location.origin 而不是 '*'
2852
- */
2853
- broadcastMessageToPage(data) {
2854
- try {
2855
- // 使用 dispatchEvent 创建 MessageEvent,在同一窗口内触发所有监听器
2856
- // 这样调用 SDK 的 Vue 页面中的 window.addEventListener('message') 也能收到
2857
- // 注意:MessageEvent 的 origin 属性不能是 '*',必须是有效的 origin 字符串
2858
- // 我们使用 window.location.origin 来标识消息来源(当前页面的 origin)
2859
- // Vue 页面可以收到消息,因为 dispatchEvent 会在同一窗口内触发所有监听器
2860
- const messageEvent = new MessageEvent('message', {
2861
- data: data,
2862
- origin: window.location.origin, // 使用当前页面的 origin,不是 '*'(MessageEvent 不支持 '*')
2863
- source: window,
2864
- bubbles: true,
2865
- cancelable: true
2866
- });
2867
- window.dispatchEvent(messageEvent);
2868
- if (this.debug) {
2869
- console.log('[IframeManager] Message broadcasted to Vue page via window.dispatchEvent:', {
2870
- data: data,
2871
- origin: window.location.origin,
2872
- type: 'message',
2873
- note: 'origin is window.location.origin, not "*" (MessageEvent does not support "*")'
2874
- });
2875
- }
2876
- }
2877
- catch (error) {
2878
- if (this.debug) {
2879
- console.error('[IframeManager] Failed to broadcast message:', error);
2880
- }
2881
- }
2882
- }
2883
- /**
2884
- * 调整iframe大小(PC模式支持)
2885
- */
2886
- resizeIframe(width, height) {
2887
- if (this.containerElement) {
2888
- this.containerElement.style.width = `${width}px`;
2889
- this.containerElement.style.height = `${height}px`;
2890
- }
2891
- }
2892
- /**
2893
- * 获取目标元素(支持字符串选择器或 HTMLElement)
2894
- */
2895
- getTargetElement(target) {
2896
- if (typeof target === 'string') {
2897
- const element = document.querySelector(target);
2898
- if (element) {
2899
- return element;
2900
- }
2901
- else {
2902
- if (this.debug) {
2903
- console.warn(`Target element not found: ${target}, falling back to document.body`);
2904
- }
2905
- return document.body;
2906
- }
2907
- }
2908
- if (target instanceof HTMLElement) {
2909
- if (document.body.contains(target)) {
2910
- return target;
2911
- }
2912
- else {
2913
- if (this.debug) {
2914
- console.warn('Target element no longer in DOM, falling back to document.body');
2915
- }
2916
- return document.body;
2917
- }
2918
- }
2919
- return document.body;
2920
- }
2921
- }
2922
-
2923
2188
  function changeJpegDpi(uint8Array, dpi) {
2924
2189
  uint8Array[13] = 1;
2925
2190
  uint8Array[14] = dpi >> 8;
@@ -16453,6 +15718,26 @@ class ScreenshotManager {
16453
15718
  }
16454
15719
  });
16455
15720
  }
15721
+ /**
15722
+ * 处理截图配置(公共方法,用于外部调用)
15723
+ * @param configJson 配置的 JSON 字符串(BinaryConfig 格式)
15724
+ */
15725
+ handleScreenshotConfig(configJson) {
15726
+ try {
15727
+ const event = {
15728
+ data: {
15729
+ type: 'checkScreenshot',
15730
+ data: configJson
15731
+ }
15732
+ };
15733
+ this.handleIframeMessage(event);
15734
+ }
15735
+ catch (error) {
15736
+ if (this.options.debug) {
15737
+ console.error('📸 [ScreenshotManager] Error handling screenshot config:', error);
15738
+ }
15739
+ }
15740
+ }
16456
15741
  /**
16457
15742
  * 处理 iframe postMessage 消息
16458
15743
  */
@@ -30048,6 +29333,244 @@ function requireBlowfish () {
30048
29333
 
30049
29334
  var cryptoJsExports = cryptoJs.exports;
30050
29335
 
29336
+ class CustomerSDK {
29337
+ constructor() {
29338
+ this.iconManager = null;
29339
+ this.screenshotManager = null;
29340
+ this.debug = false; // debug 模式标志
29341
+ this.deviceId = null; // 设备ID(md5后的)
29342
+ this.initResult = null; // 保存初始化结果
29343
+ }
29344
+ /**
29345
+ * 初始化SDK
29346
+ * @param config SDK配置
29347
+ * @param screenshotCallback 截图消息回调(可选)
29348
+ * @returns 返回初始化信息(包含设备ID等)
29349
+ */
29350
+ async init(config, screenshotCallback) {
29351
+ try {
29352
+ this.debug = config.debug ?? false;
29353
+ // 获取设备指纹ID
29354
+ const rawDeviceId = await this.getRawDeviceId();
29355
+ if (this.debug) {
29356
+ console.log('Raw Device ID:', rawDeviceId);
29357
+ }
29358
+ // 计算返回给前端的 deviceId:md5(deviceId + getReferrer())
29359
+ const referrer = config.referrer || document.referrer || document.location.href;
29360
+ this.deviceId = cryptoJsExports.MD5(rawDeviceId + referrer).toString();
29361
+ if (this.debug) {
29362
+ console.log('MD5 Device ID (for frontend):', this.deviceId);
29363
+ console.log('Referrer used:', referrer);
29364
+ }
29365
+ // 准备返回的初始化信息
29366
+ const initResult = {
29367
+ deviceId: this.deviceId,
29368
+ referrer,
29369
+ agent: config.agent,
29370
+ timestamp: Date.now()
29371
+ };
29372
+ // 初始化图标管理器(支持传送目标)
29373
+ const iconTarget = config.target || undefined;
29374
+ const iconPosition = config.iconPosition || undefined;
29375
+ this.iconManager = new IconManager(iconPosition, this.debug, iconTarget, {
29376
+ sideAttach: config.sideAttach,
29377
+ sideHideRatio: config.sideHideRatio,
29378
+ magnetic: config.magnetic,
29379
+ magneticDirection: config.magneticDirection,
29380
+ margin: config.margin,
29381
+ autoAttachDelay: config.autoAttachDelay
29382
+ });
29383
+ await this.iconManager.show();
29384
+ // 初始化截图管理器(如果配置了截图)
29385
+ if (config.screenshot) {
29386
+ const targetElement = typeof iconTarget === 'string'
29387
+ ? document.querySelector(iconTarget)
29388
+ : (iconTarget || document.body);
29389
+ // 创建发送回调函数
29390
+ const sendToExternal = screenshotCallback?.sendData || null;
29391
+ this.screenshotManager = new ScreenshotManager(targetElement, config.screenshot, sendToExternal || undefined);
29392
+ // 如果提供了配置回调,设置消息监听
29393
+ if (screenshotCallback?.onConfig) {
29394
+ this.setupScreenshotConfigListener(screenshotCallback.onConfig);
29395
+ }
29396
+ }
29397
+ // 保存初始化结果
29398
+ this.initResult = initResult;
29399
+ if (this.debug) {
29400
+ console.log('CustomerSDK initialized successfully (icon + screenshot only)');
29401
+ }
29402
+ // 返回初始化信息
29403
+ return initResult;
29404
+ }
29405
+ catch (error) {
29406
+ console.error('Failed to initialize CustomerSDK:', error);
29407
+ throw error;
29408
+ }
29409
+ }
29410
+ /**
29411
+ * 设置截图配置监听器(可选,用于兼容 postMessage 场景)
29412
+ */
29413
+ setupScreenshotConfigListener(onConfig) {
29414
+ const messageHandler = (event) => {
29415
+ try {
29416
+ // 验证消息类型
29417
+ if (!event.data || event.data.type !== 'checkScreenshot') {
29418
+ return;
29419
+ }
29420
+ if (this.debug) {
29421
+ console.log('[CustomerSDK] Received screenshot config message:', event.data);
29422
+ }
29423
+ // 调用外部回调
29424
+ if (event.data.data && typeof event.data.data === 'string') {
29425
+ onConfig(event.data.data);
29426
+ }
29427
+ }
29428
+ catch (error) {
29429
+ if (this.debug) {
29430
+ console.error('[CustomerSDK] Error handling screenshot config message:', error);
29431
+ }
29432
+ }
29433
+ };
29434
+ window.addEventListener('message', messageHandler);
29435
+ this._screenshotConfigHandler = messageHandler;
29436
+ }
29437
+ /**
29438
+ * 触发截图配置(用于弹窗组件场景)
29439
+ * @param configJson 截图配置的 JSON 字符串(BinaryConfig 格式)
29440
+ */
29441
+ triggerScreenshotConfig(configJson) {
29442
+ if (!this.screenshotManager) {
29443
+ if (this.debug) {
29444
+ console.warn('[CustomerSDK] ScreenshotManager not initialized');
29445
+ }
29446
+ return;
29447
+ }
29448
+ this.screenshotManager.handleScreenshotConfig(configJson);
29449
+ }
29450
+ /**
29451
+ * 隐藏图标
29452
+ */
29453
+ hideIcon() {
29454
+ this.iconManager?.hide();
29455
+ }
29456
+ /**
29457
+ * 显示图标
29458
+ */
29459
+ showIcon() {
29460
+ this.iconManager?.show();
29461
+ }
29462
+ /**
29463
+ * 设置图标点击回调
29464
+ */
29465
+ onIconClick(callback) {
29466
+ this.iconManager?.onClick(callback);
29467
+ }
29468
+ /**
29469
+ * 获取截图管理器实例(用于高级操作)
29470
+ */
29471
+ getScreenshotManager() {
29472
+ return this.screenshotManager;
29473
+ }
29474
+ /**
29475
+ * 获取图标管理器实例(用于高级操作)
29476
+ */
29477
+ getIconManager() {
29478
+ return this.iconManager;
29479
+ }
29480
+ /**
29481
+ * 获取设备ID(md5后的)
29482
+ */
29483
+ getDeviceId() {
29484
+ return this.deviceId;
29485
+ }
29486
+ /**
29487
+ * 获取初始化信息(设备ID等)
29488
+ */
29489
+ getInitResult() {
29490
+ return this.initResult;
29491
+ }
29492
+ /**
29493
+ * 获取设备指纹ID(原始)
29494
+ */
29495
+ async getRawDeviceId() {
29496
+ if (this.debug) {
29497
+ console.log('🔍 Starting to get device fingerprint...');
29498
+ }
29499
+ try {
29500
+ if (this.debug) {
29501
+ console.log('📦 Loading FingerprintJS...');
29502
+ }
29503
+ const fp = await index$1.load();
29504
+ if (this.debug) {
29505
+ console.log('🎯 Getting device fingerprint...');
29506
+ }
29507
+ const result = await fp.get();
29508
+ if (this.debug) {
29509
+ console.log('✅ FingerprintJS result:', result);
29510
+ console.log('🆔 Device ID obtained:', result.visitorId);
29511
+ }
29512
+ return result.visitorId;
29513
+ }
29514
+ catch (error) {
29515
+ if (this.debug) {
29516
+ console.warn('❌ Failed to get device fingerprint, using fallback:', error);
29517
+ }
29518
+ const fallbackId = 'device_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
29519
+ if (this.debug) {
29520
+ console.log('🆔 Fallback Device ID:', fallbackId);
29521
+ }
29522
+ return fallbackId;
29523
+ }
29524
+ }
29525
+ /**
29526
+ * 显示消息通知
29527
+ */
29528
+ showNotification(badgeCount = 1, options = {}) {
29529
+ if (!this.iconManager) {
29530
+ if (this.debug) {
29531
+ console.warn('SDK not initialized');
29532
+ }
29533
+ return;
29534
+ }
29535
+ this.iconManager.showNotification({
29536
+ badgeCount: typeof badgeCount === 'string' ? 0 : badgeCount,
29537
+ badgeText: typeof badgeCount === 'string' ? badgeCount : '',
29538
+ pulse: options.pulse || false
29539
+ });
29540
+ // 自动隐藏通知
29541
+ if (options.autoHide && options.autoHide > 0) {
29542
+ setTimeout(() => {
29543
+ this.iconManager?.clearNotification();
29544
+ }, options.autoHide);
29545
+ }
29546
+ }
29547
+ /**
29548
+ * 清除消息通知
29549
+ */
29550
+ clearNotification() {
29551
+ this.iconManager?.clearNotification();
29552
+ }
29553
+ /**
29554
+ * 销毁 SDK
29555
+ */
29556
+ destroy() {
29557
+ this.iconManager?.hide();
29558
+ this.screenshotManager?.destroy();
29559
+ // 清理截图配置监听器
29560
+ if (this._screenshotConfigHandler) {
29561
+ window.removeEventListener('message', this._screenshotConfigHandler);
29562
+ this._screenshotConfigHandler = null;
29563
+ }
29564
+ this.iconManager = null;
29565
+ this.screenshotManager = null;
29566
+ this.initResult = null;
29567
+ this.deviceId = null;
29568
+ if (this.debug) {
29569
+ console.log('CustomerSDK destroyed');
29570
+ }
29571
+ }
29572
+ }
29573
+
30051
29574
  /**
30052
29575
  * Customer SDK 主类
30053
29576
  * 只负责悬浮图标和iframe管理,不处理WebSocket连接
@@ -30056,7 +29579,6 @@ var cryptoJsExports = cryptoJs.exports;
30056
29579
  class CustomerServiceSDK {
30057
29580
  constructor() {
30058
29581
  this.iconManager = null;
30059
- this.iframeManager = null;
30060
29582
  this.screenshotManager = null;
30061
29583
  this.config = null;
30062
29584
  this.isInitialized = false;
@@ -30094,10 +29616,8 @@ class CustomerServiceSDK {
30094
29616
  if (this.debug) {
30095
29617
  console.log('Force reinitializing SDK...');
30096
29618
  }
30097
- // 清理旧的 iframe 和截图管理器
30098
- this.iframeManager?.destroy();
29619
+ // 清理旧的截图管理器
30099
29620
  this.screenshotManager?.destroy();
30100
- this.iframeManager = null;
30101
29621
  this.screenshotManager = null;
30102
29622
  // 注意:图标管理器暂时保留,稍后检查配置是否变化再决定是否重新创建
30103
29623
  // 重置初始化标志
@@ -30119,12 +29639,9 @@ class CustomerServiceSDK {
30119
29639
  console.log('MD5 Device ID (for frontend):', deviceId);
30120
29640
  console.log('Referrer used:', referrer);
30121
29641
  }
30122
- // 构建iframe URL(带参数,使用 md5 后的 deviceId)
30123
- const iframeUrl = this.buildIframeUrl(config, deviceId);
30124
29642
  // 准备返回的初始化信息(返回给前端的是 md5 后的 deviceId)
30125
29643
  const initResult = {
30126
29644
  deviceId,
30127
- iframeUrl,
30128
29645
  referrer,
30129
29646
  agent: config.agent,
30130
29647
  timestamp: Date.now()
@@ -30184,42 +29701,11 @@ class CustomerServiceSDK {
30184
29701
  // 更新配置记录
30185
29702
  this.lastIconConfig = { position: iconPosition, target: iconTarget };
30186
29703
  }
30187
- // 创建iframe管理器(自动检测设备类型)
30188
- // 如果提供了 target,iframe 会自适应 target 的宽度(PC 和移动端都适用)
30189
- // 如果没有 target,PC 模式使用默认宽度,移动端全屏
30190
- console.log('iframeUrl:', iframeUrl);
30191
- this.iframeManager = new IframeManager({
30192
- src: iframeUrl,
30193
- mode: 'auto', // 自动根据设备类型选择模式(PC弹窗,移动端全屏)
30194
- width: options?.width || 450, // PC模式宽度(像素,默认450px),仅在未提供 target 时使用
30195
- height: options?.height || 600, // PC模式高度(像素),仅在未提供 target 时使用
30196
- target: options?.target, // 目标元素(如果提供,iframe 会自适应其宽度)
30197
- allowClose: true,
30198
- debug: this.debug, // 传递 debug 标志
30199
- onMessage: (messageType, _data) => {
30200
- // 处理来自iframe的消息
30201
- if (messageType === 'new-message') {
30202
- // 显示红点通知(只显示红点,不显示数字)
30203
- this.showNotification(0, { pulse: true });
30204
- }
30205
- // checkScreenshot 消息由 ScreenshotManager 处理,不需要在这里处理
30206
- },
30207
- onClose: () => {
30208
- // iframe关闭时,清理图标拖动事件监听器,并重新显示图标
30209
- this.iconManager?.forceCleanupDragEvents();
30210
- this.iconManager?.show();
30211
- },
30212
- ...options
30213
- });
30214
- // 预初始化iframe(隐藏状态,连接SSE)
30215
- await this.iframeManager.init();
30216
- // 设置点击事件:图标 → iframe
29704
+ // 设置点击事件:图标点击回调(由外部处理)
30217
29705
  this.iconManager.onClick(() => {
30218
- // 打开iframe时清除红点通知
29706
+ // 图标点击事件由外部处理(例如打开弹窗)
29707
+ // 这里只清除通知
30219
29708
  this.clearNotification();
30220
- // 点击图标后隐藏图标
30221
- this.iconManager?.hide();
30222
- this.iframeManager?.show();
30223
29709
  });
30224
29710
  // 初始化截图管理器(如果启用了截图功能)
30225
29711
  if (config.screenshot) {
@@ -30231,10 +29717,8 @@ class CustomerServiceSDK {
30231
29717
  ...config.screenshot,
30232
29718
  debug: this.debug // 直接传递 debug 标志
30233
29719
  };
30234
- this.screenshotManager = new ScreenshotManager(targetElement, screenshotOptions, (data) => {
30235
- // 通过 IframeManager 发送消息到 iframe
30236
- this.iframeManager?.sendToIframe(data);
30237
- });
29720
+ this.screenshotManager = new ScreenshotManager(targetElement, screenshotOptions, undefined // 不再通过 iframe 发送,由外部回调处理
29721
+ );
30238
29722
  // 自动启用截图功能(用于测试,实际使用时需要通过 iframe 消息启用)
30239
29723
  this.screenshotManager.enable(true);
30240
29724
  if (this.debug) {
@@ -30245,7 +29729,7 @@ class CustomerServiceSDK {
30245
29729
  // 保存初始化结果,以便后续获取
30246
29730
  this.initResult = initResult;
30247
29731
  if (this.debug) {
30248
- console.log('CustomerSDK initialized successfully (iframe pre-connected to SSE)');
29732
+ console.log('CustomerSDK initialized successfully (icon + screenshot only)');
30249
29733
  }
30250
29734
  // 返回初始化信息
30251
29735
  return initResult;
@@ -30259,10 +29743,6 @@ class CustomerServiceSDK {
30259
29743
  this.iconManager.hide();
30260
29744
  this.iconManager = null;
30261
29745
  }
30262
- if (this.iframeManager) {
30263
- this.iframeManager.destroy();
30264
- this.iframeManager = null;
30265
- }
30266
29746
  if (this.screenshotManager) {
30267
29747
  this.screenshotManager.destroy();
30268
29748
  this.screenshotManager = null;
@@ -30308,31 +29788,6 @@ class CustomerServiceSDK {
30308
29788
  setIconStyle(style) {
30309
29789
  this.iconManager?.setStyle(style);
30310
29790
  }
30311
- /**
30312
- * 打开/关闭聊天窗口
30313
- */
30314
- openChat() {
30315
- // 打开iframe时清除红点通知
30316
- this.clearNotification();
30317
- this.iframeManager?.open();
30318
- }
30319
- closeChat() {
30320
- // 关闭iframe时,清理图标拖动事件监听器(防止页面无法操作)
30321
- this.iconManager?.forceCleanupDragEvents();
30322
- this.iframeManager?.close();
30323
- }
30324
- /**
30325
- * 检查聊天窗口是否打开
30326
- */
30327
- isChatOpen() {
30328
- return this.iframeManager?.isIframeOpen() || false;
30329
- }
30330
- /**
30331
- * 向iframe发送消息(传递用户数据等)
30332
- */
30333
- sendToIframe(data) {
30334
- this.iframeManager?.sendToIframe(data);
30335
- }
30336
29791
  /**
30337
29792
  * 获取连接状态
30338
29793
  * 注意:真正的连接状态保存在iframe中的SSE连接中
@@ -30423,40 +29878,13 @@ class CustomerServiceSDK {
30423
29878
  console.log('📸 截图配置已更新:', options);
30424
29879
  }
30425
29880
  }
30426
- /**
30427
- * 更新 token(用于用户登录/退出场景)
30428
- * 如果已初始化,会重新创建 iframe 并更新 URL
30429
- * @param token 新的 token(传空字符串或 undefined 表示移除 token)
30430
- * @param options UI选项(可选,用于重新初始化时的配置)
30431
- * @returns 返回更新后的初始化信息
30432
- */
30433
- async updateToken(token, options) {
30434
- if (!this.isInitialized) {
30435
- throw new Error('SDK not initialized. Call init() first.');
30436
- }
30437
- if (!this.config) {
30438
- throw new Error('SDK config not found');
30439
- }
30440
- // 更新配置中的 token
30441
- const updatedConfig = {
30442
- ...this.config,
30443
- token: token && token.trim() !== '' ? token : undefined
30444
- };
30445
- if (this.debug) {
30446
- console.log('Updating token:', token ? 'Token provided' : 'Token removed');
30447
- }
30448
- // 强制重新初始化以应用新的 token
30449
- return await this.init(updatedConfig, options, true);
30450
- }
30451
29881
  /**
30452
29882
  * 销毁 SDK
30453
29883
  */
30454
29884
  destroy() {
30455
29885
  this.iconManager?.hide();
30456
- this.iframeManager?.destroy(); // 使用 destroy 而不是 close,确保完全清理
30457
29886
  this.screenshotManager?.destroy();
30458
29887
  this.iconManager = null;
30459
- this.iframeManager = null;
30460
29888
  this.screenshotManager = null;
30461
29889
  this.config = null;
30462
29890
  this.initResult = null;
@@ -30541,26 +29969,6 @@ class CustomerServiceSDK {
30541
29969
  getReferrer(config) {
30542
29970
  return config.referrer || document.referrer || document.location.href;
30543
29971
  }
30544
- /**
30545
- * 构建iframe URL(带用户参数和设备ID)
30546
- */
30547
- buildIframeUrl(config, deviceId) {
30548
- const baseUrl = config.iframeUrl;
30549
- if (!baseUrl || baseUrl.trim() === '') {
30550
- throw new Error('iframeUrl is required but not provided or is empty');
30551
- }
30552
- const url = new URL(baseUrl);
30553
- // 添加用户参数(只在有值时才添加)
30554
- if (config.agent && config.agent.trim() !== '') {
30555
- url.searchParams.set('Agent', config.agent);
30556
- }
30557
- if (config.token && config.token.trim() !== '') {
30558
- url.searchParams.set('Authorization', config.token);
30559
- }
30560
- url.searchParams.set('DeviceSign', deviceId);
30561
- url.searchParams.set('Referrer', this.getReferrer(config));
30562
- return url.toString();
30563
- }
30564
29972
  }
30565
29973
  // 创建全局实例
30566
29974
  let globalSDKInstance = null;
@@ -30609,28 +30017,6 @@ const setIconStyle = (style) => {
30609
30017
  const sdk = getInstance();
30610
30018
  sdk.setIconStyle(style);
30611
30019
  };
30612
- /**
30613
- * 聊天控制API
30614
- */
30615
- const openChat = () => {
30616
- const sdk = getInstance();
30617
- sdk.openChat();
30618
- };
30619
- const closeChat = () => {
30620
- const sdk = getInstance();
30621
- sdk.closeChat();
30622
- };
30623
- const isChatOpen = () => {
30624
- const sdk = getInstance();
30625
- return sdk.isChatOpen();
30626
- };
30627
- /**
30628
- * iframe通信API
30629
- */
30630
- const sendToIframe = (data) => {
30631
- const sdk = getInstance();
30632
- sdk.sendToIframe(data);
30633
- };
30634
30020
  /**
30635
30021
  * 其他API
30636
30022
  */
@@ -30684,16 +30070,6 @@ const updateScreenshotOptions = (options) => {
30684
30070
  const sdk = getInstance();
30685
30071
  sdk.updateScreenshotOptions(options);
30686
30072
  };
30687
- /**
30688
- * 更新 token(用于用户登录/退出场景)
30689
- * @param token 新的 token(传空字符串或 undefined 表示移除 token)
30690
- * @param options UI选项(可选)
30691
- * @returns 返回更新后的初始化信息
30692
- */
30693
- const updateToken = async (token, options) => {
30694
- const sdk = getInstance();
30695
- return await sdk.updateToken(token, options);
30696
- };
30697
30073
  // 默认导出
30698
30074
  var index = {
30699
30075
  init,
@@ -30704,10 +30080,6 @@ var index = {
30704
30080
  setIconPosition,
30705
30081
  setIconCoordinates,
30706
30082
  setIconStyle,
30707
- openChat,
30708
- closeChat,
30709
- isChatOpen,
30710
- sendToIframe,
30711
30083
  getConnectionStatus,
30712
30084
  showNotification,
30713
30085
  clearNotification,
@@ -30716,14 +30088,13 @@ var index = {
30716
30088
  enableScreenshot,
30717
30089
  getScreenshotState,
30718
30090
  updateScreenshotOptions,
30719
- updateToken,
30720
30091
  destroy
30721
30092
  };
30722
30093
 
30094
+ exports.CustomerSDK = CustomerSDK;
30723
30095
  exports.CustomerServiceSDK = CustomerServiceSDK;
30724
30096
  exports.captureScreenshot = captureScreenshot;
30725
30097
  exports.clearNotification = clearNotification;
30726
- exports.closeChat = closeChat;
30727
30098
  exports.default = index;
30728
30099
  exports.destroy = destroy;
30729
30100
  exports.enableScreenshot = enableScreenshot;
@@ -30733,9 +30104,6 @@ exports.getInstance = getInstance;
30733
30104
  exports.getScreenshotState = getScreenshotState;
30734
30105
  exports.hideIcon = hideIcon;
30735
30106
  exports.init = init;
30736
- exports.isChatOpen = isChatOpen;
30737
- exports.openChat = openChat;
30738
- exports.sendToIframe = sendToIframe;
30739
30107
  exports.setIconCoordinates = setIconCoordinates;
30740
30108
  exports.setIconPosition = setIconPosition;
30741
30109
  exports.setIconStyle = setIconStyle;
@@ -30743,4 +30111,3 @@ exports.setScreenshotTarget = setScreenshotTarget;
30743
30111
  exports.showIcon = showIcon;
30744
30112
  exports.showNotification = showNotification;
30745
30113
  exports.updateScreenshotOptions = updateScreenshotOptions;
30746
- exports.updateToken = updateToken;