customer-chat-sdk 1.3.0 → 1.3.6
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.
- package/README.md +503 -293
- package/dist/core/CustomerSDK.d.ts +70 -25
- package/dist/core/CustomerSDK.d.ts.map +1 -1
- package/dist/customer-sdk.cjs.js +292 -892
- package/dist/customer-sdk.esm.js +291 -888
- package/dist/customer-sdk.min.js +4 -4
- package/dist/index.d.ts +10 -47
- package/dist/index.d.ts.map +1 -1
- package/dist/types/index.d.ts +8 -2
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/customer-sdk.esm.js
CHANGED
|
@@ -2181,741 +2181,6 @@ class IconManager {
|
|
|
2181
2181
|
}
|
|
2182
2182
|
}
|
|
2183
2183
|
|
|
2184
|
-
class IframeManager {
|
|
2185
|
-
constructor(config = {}) {
|
|
2186
|
-
this.iframeElement = null;
|
|
2187
|
-
this.containerElement = null; // 包装容器,包含iframe和关闭按钮
|
|
2188
|
-
this.isOpen = false;
|
|
2189
|
-
this.isCreated = false;
|
|
2190
|
-
this.debug = false; // debug 模式标志
|
|
2191
|
-
this.targetElement = null; // 目标元素(用于自适应宽度)
|
|
2192
|
-
this.messageHandler = null; // 消息监听器引用(用于清理)
|
|
2193
|
-
this.config = {
|
|
2194
|
-
src: '',
|
|
2195
|
-
mode: 'auto', // 默认自动检测设备类型
|
|
2196
|
-
width: 450, // PC 模式默认宽度
|
|
2197
|
-
height: 600,
|
|
2198
|
-
allowClose: true,
|
|
2199
|
-
...config
|
|
2200
|
-
};
|
|
2201
|
-
this.debug = config.debug ?? false;
|
|
2202
|
-
// 不在构造函数中添加消息监听器,延迟到 init() 中添加
|
|
2203
|
-
// 这样可以避免创建多个实例时产生多个监听器
|
|
2204
|
-
}
|
|
2205
|
-
/**
|
|
2206
|
-
* 初始化iframe(隐藏状态)
|
|
2207
|
-
* 预创建iframe并连接到SSE,但不显示
|
|
2208
|
-
*/
|
|
2209
|
-
async init() {
|
|
2210
|
-
try {
|
|
2211
|
-
// 设置消息监听器(在 init() 中而不是构造函数中,避免多次创建实例时产生多个监听器)
|
|
2212
|
-
this.setupMessageListener();
|
|
2213
|
-
// 关键修复:在初始化前,先清理页面上所有旧的容器元素
|
|
2214
|
-
// 防止切换模式或多次初始化时产生重复的元素
|
|
2215
|
-
this.cleanupOrphanedElements();
|
|
2216
|
-
// 创建隐藏的iframe(预连接到SSE)
|
|
2217
|
-
// 注意:createIframe 会将容器添加到 body
|
|
2218
|
-
this.createIframe();
|
|
2219
|
-
this.isCreated = true;
|
|
2220
|
-
if (this.debug) {
|
|
2221
|
-
console.log('CustomerSDK iframe initialized (hidden, SSE connected)');
|
|
2222
|
-
}
|
|
2223
|
-
}
|
|
2224
|
-
catch (error) {
|
|
2225
|
-
// 错误始终输出
|
|
2226
|
-
console.error('Failed to initialize iframe:', error);
|
|
2227
|
-
// 如果初始化失败,清理消息监听器
|
|
2228
|
-
if (this.messageHandler) {
|
|
2229
|
-
window.removeEventListener('message', this.messageHandler);
|
|
2230
|
-
this.messageHandler = null;
|
|
2231
|
-
}
|
|
2232
|
-
throw error;
|
|
2233
|
-
}
|
|
2234
|
-
}
|
|
2235
|
-
/**
|
|
2236
|
-
* 显示iframe聊天窗口
|
|
2237
|
-
*/
|
|
2238
|
-
show() {
|
|
2239
|
-
if (this.isOpen) {
|
|
2240
|
-
return;
|
|
2241
|
-
}
|
|
2242
|
-
if (!this.isCreated) {
|
|
2243
|
-
throw new Error('Iframe not initialized. Call init() first.');
|
|
2244
|
-
}
|
|
2245
|
-
try {
|
|
2246
|
-
// 显示已创建的容器
|
|
2247
|
-
// 关键优化:容器在 init() 时已经添加到正确位置,这里只改变样式,不移动 DOM
|
|
2248
|
-
// 这样可以避免 iframe 重新加载
|
|
2249
|
-
if (this.containerElement) {
|
|
2250
|
-
// 确保容器在 DOM 中(理论上已经在 init() 时添加,但为了安全)
|
|
2251
|
-
if (!this.containerElement.parentNode) {
|
|
2252
|
-
// 如果容器不在 DOM 中(异常情况),添加到 target 或 body
|
|
2253
|
-
if (this.targetElement && this.targetElement !== document.body) {
|
|
2254
|
-
// 确保 target 是相对定位
|
|
2255
|
-
const targetStyle = window.getComputedStyle(this.targetElement);
|
|
2256
|
-
if (targetStyle.position === 'static') {
|
|
2257
|
-
this.targetElement.style.position = 'relative';
|
|
2258
|
-
}
|
|
2259
|
-
this.targetElement.appendChild(this.containerElement);
|
|
2260
|
-
if (this.debug) {
|
|
2261
|
-
console.log('Iframe container re-added to target element in show()');
|
|
2262
|
-
}
|
|
2263
|
-
}
|
|
2264
|
-
else {
|
|
2265
|
-
// 没有 target 或 target 是 body,添加到 body
|
|
2266
|
-
document.body.appendChild(this.containerElement);
|
|
2267
|
-
if (this.debug) {
|
|
2268
|
-
console.log('Iframe container re-added to document.body in show()');
|
|
2269
|
-
}
|
|
2270
|
-
}
|
|
2271
|
-
}
|
|
2272
|
-
// 根据是否有 target 设置正确的定位方式
|
|
2273
|
-
const useTargetWidth = !!this.targetElement && this.targetElement !== document.body;
|
|
2274
|
-
const displayStyles = useTargetWidth ? {
|
|
2275
|
-
// 使用 target 时,保持 absolute 定位(相对于 target)
|
|
2276
|
-
position: 'absolute',
|
|
2277
|
-
visibility: 'visible',
|
|
2278
|
-
opacity: '1',
|
|
2279
|
-
display: 'block'
|
|
2280
|
-
} : {
|
|
2281
|
-
// 没有 target 时,使用 fixed 定位(相对于视口)
|
|
2282
|
-
position: 'fixed',
|
|
2283
|
-
visibility: 'visible',
|
|
2284
|
-
opacity: '1',
|
|
2285
|
-
display: 'block'
|
|
2286
|
-
};
|
|
2287
|
-
Object.assign(this.containerElement.style, displayStyles);
|
|
2288
|
-
// 禁用body滚动,防止出现滚动条
|
|
2289
|
-
this.preventBodyScroll(true);
|
|
2290
|
-
}
|
|
2291
|
-
this.isOpen = true;
|
|
2292
|
-
if (this.debug) {
|
|
2293
|
-
console.log('CustomerSDK iframe shown');
|
|
2294
|
-
}
|
|
2295
|
-
}
|
|
2296
|
-
catch (error) {
|
|
2297
|
-
// 错误始终输出
|
|
2298
|
-
console.error('Failed to show iframe:', error);
|
|
2299
|
-
}
|
|
2300
|
-
}
|
|
2301
|
-
/**
|
|
2302
|
-
* 打开iframe聊天窗口(保持兼容性)
|
|
2303
|
-
*/
|
|
2304
|
-
open() {
|
|
2305
|
-
this.show();
|
|
2306
|
-
}
|
|
2307
|
-
/**
|
|
2308
|
-
* 隐藏iframe聊天窗口(类似v-show)
|
|
2309
|
-
*/
|
|
2310
|
-
hide() {
|
|
2311
|
-
if (!this.isOpen) {
|
|
2312
|
-
return;
|
|
2313
|
-
}
|
|
2314
|
-
// 隐藏容器但保留DOM元素(不移动容器,避免 iframe 重新加载)
|
|
2315
|
-
if (this.containerElement) {
|
|
2316
|
-
Object.assign(this.containerElement.style, {
|
|
2317
|
-
visibility: 'hidden',
|
|
2318
|
-
opacity: '0',
|
|
2319
|
-
display: 'none'
|
|
2320
|
-
});
|
|
2321
|
-
// 注意:不移动容器,保持容器在当前位置(body),避免 iframe 重新加载
|
|
2322
|
-
}
|
|
2323
|
-
// 恢复body滚动
|
|
2324
|
-
this.preventBodyScroll(false);
|
|
2325
|
-
this.isOpen = false;
|
|
2326
|
-
if (this.debug) {
|
|
2327
|
-
console.log('CustomerSDK iframe hidden (SSE still connected)');
|
|
2328
|
-
}
|
|
2329
|
-
// 触发关闭回调
|
|
2330
|
-
if (this.config.onClose) {
|
|
2331
|
-
this.config.onClose();
|
|
2332
|
-
}
|
|
2333
|
-
}
|
|
2334
|
-
/**
|
|
2335
|
-
* 关闭iframe聊天窗口(完全销毁,保持兼容性)
|
|
2336
|
-
*/
|
|
2337
|
-
close() {
|
|
2338
|
-
this.hide(); // 默认只隐藏,不销毁
|
|
2339
|
-
}
|
|
2340
|
-
/**
|
|
2341
|
-
* 完全销毁iframe(需要时才调用)
|
|
2342
|
-
*/
|
|
2343
|
-
destroy() {
|
|
2344
|
-
this.hide();
|
|
2345
|
-
// 移除消息监听器(防止内存泄漏)
|
|
2346
|
-
if (this.messageHandler) {
|
|
2347
|
-
window.removeEventListener('message', this.messageHandler);
|
|
2348
|
-
this.messageHandler = null;
|
|
2349
|
-
}
|
|
2350
|
-
// 移除容器
|
|
2351
|
-
if (this.containerElement) {
|
|
2352
|
-
this.containerElement.remove();
|
|
2353
|
-
this.containerElement = null;
|
|
2354
|
-
this.iframeElement = null;
|
|
2355
|
-
}
|
|
2356
|
-
this.isCreated = false;
|
|
2357
|
-
if (this.debug) {
|
|
2358
|
-
console.log('CustomerSDK container destroyed');
|
|
2359
|
-
}
|
|
2360
|
-
}
|
|
2361
|
-
/**
|
|
2362
|
-
* 检查是否已打开
|
|
2363
|
-
*/
|
|
2364
|
-
isIframeOpen() {
|
|
2365
|
-
return this.isOpen;
|
|
2366
|
-
}
|
|
2367
|
-
/**
|
|
2368
|
-
* 向iframe发送消息
|
|
2369
|
-
*/
|
|
2370
|
-
sendToIframe(data) {
|
|
2371
|
-
if (this.iframeElement && this.iframeElement.contentWindow) {
|
|
2372
|
-
this.iframeElement.contentWindow.postMessage(data, '*');
|
|
2373
|
-
}
|
|
2374
|
-
}
|
|
2375
|
-
/**
|
|
2376
|
-
* 清理页面上孤立的容器元素(防止重复创建)
|
|
2377
|
-
*/
|
|
2378
|
-
cleanupOrphanedElements() {
|
|
2379
|
-
// 清理所有旧的容器元素(不属于当前实例的)
|
|
2380
|
-
const existingContainers = document.querySelectorAll('.customer-sdk-container');
|
|
2381
|
-
existingContainers.forEach((container) => {
|
|
2382
|
-
if (container !== this.containerElement) {
|
|
2383
|
-
container.remove();
|
|
2384
|
-
if (this.debug) {
|
|
2385
|
-
console.log('清理旧的容器元素');
|
|
2386
|
-
}
|
|
2387
|
-
}
|
|
2388
|
-
});
|
|
2389
|
-
}
|
|
2390
|
-
/**
|
|
2391
|
-
* 创建iframe(默认隐藏状态,用于SSE连接)
|
|
2392
|
-
*/
|
|
2393
|
-
createIframe() {
|
|
2394
|
-
// 创建包装容器(包含iframe和关闭按钮)
|
|
2395
|
-
this.containerElement = document.createElement('div');
|
|
2396
|
-
this.containerElement.className = 'customer-sdk-container';
|
|
2397
|
-
// 确保容器不可拖动
|
|
2398
|
-
this.containerElement.draggable = false;
|
|
2399
|
-
// 创建iframe元素
|
|
2400
|
-
this.iframeElement = document.createElement('iframe');
|
|
2401
|
-
this.iframeElement.className = 'customer-sdk-iframe';
|
|
2402
|
-
// 设置iframe属性
|
|
2403
|
-
// 注意:URL只在初始化时设置一次,之后不会刷新
|
|
2404
|
-
// 如果需要更新URL参数,需要重新初始化SDK
|
|
2405
|
-
this.iframeElement.src = this.config.src || '';
|
|
2406
|
-
this.iframeElement.frameBorder = '0';
|
|
2407
|
-
// 添加必要权限(只保留常用的)
|
|
2408
|
-
this.iframeElement.setAttribute('allow', [
|
|
2409
|
-
'microphone', // 麦克风权限
|
|
2410
|
-
'camera', // 摄像头权限
|
|
2411
|
-
'geolocation', // 地理位置权限
|
|
2412
|
-
'clipboard-read', // 剪贴板读取权限
|
|
2413
|
-
'clipboard-write', // 剪贴板写入权限
|
|
2414
|
-
'fullscreen', // 全屏权限
|
|
2415
|
-
'autoplay', // 自动播放权限
|
|
2416
|
-
'encrypted-media' // 加密媒体权限
|
|
2417
|
-
].join('; '));
|
|
2418
|
-
// 设置sandbox属性(允许所有必要功能)
|
|
2419
|
-
this.iframeElement.setAttribute('sandbox', [
|
|
2420
|
-
'allow-same-origin', // 允许同源
|
|
2421
|
-
'allow-scripts', // 允许脚本
|
|
2422
|
-
'allow-forms', // 允许表单
|
|
2423
|
-
'allow-popups', // 允许弹窗
|
|
2424
|
-
'allow-popups-to-escape-sandbox', // 允许弹窗逃逸沙箱
|
|
2425
|
-
'allow-presentation', // 允许演示
|
|
2426
|
-
'allow-top-navigation', // 允许顶级导航
|
|
2427
|
-
'allow-top-navigation-by-user-activation', // 允许用户激活的顶级导航
|
|
2428
|
-
'allow-downloads', // 允许下载
|
|
2429
|
-
'allow-modals', // 允许模态框
|
|
2430
|
-
'allow-orientation-lock', // 允许方向锁定
|
|
2431
|
-
'allow-pointer-lock', // 允许指针锁定
|
|
2432
|
-
'allow-storage-access-by-user-activation' // 允许用户激活的存储访问
|
|
2433
|
-
].join(' '));
|
|
2434
|
-
// 获取目标元素(如果提供了 target)
|
|
2435
|
-
if (this.config.target) {
|
|
2436
|
-
this.targetElement = this.getTargetElement(this.config.target);
|
|
2437
|
-
}
|
|
2438
|
-
// 根据设备类型设置模式
|
|
2439
|
-
const actualMode = this.getActualMode();
|
|
2440
|
-
const isPC = actualMode === 'popup';
|
|
2441
|
-
this.iframeElement.scrolling = 'auto'; // PC和移动端都显示滚动条
|
|
2442
|
-
// 判断是否使用 target 的自适应宽度
|
|
2443
|
-
const useTargetWidth = !!this.targetElement && this.targetElement !== document.body;
|
|
2444
|
-
// PC模式:如果传了 target,使用 target 的宽度(自适应);否则使用配置的宽度
|
|
2445
|
-
// 移动端:如果传了 target,使用 target 的宽度(自适应);否则全屏
|
|
2446
|
-
const containerStyles = useTargetWidth ? {
|
|
2447
|
-
// 使用 target 的宽度(自适应),PC 和移动端都适用
|
|
2448
|
-
// 宽度 100% 自适应 target 的实际宽度(target 本身可能有 max-width 限制)
|
|
2449
|
-
width: '100%',
|
|
2450
|
-
height: '100%',
|
|
2451
|
-
maxWidth: '100%', // 不超过 target 的宽度
|
|
2452
|
-
maxHeight: '100%',
|
|
2453
|
-
backgroundColor: '#ffffff',
|
|
2454
|
-
borderRadius: isPC ? '0' : '0',
|
|
2455
|
-
boxShadow: isPC ? 'none' : '0 -4px 16px rgba(0, 0, 0, 0.25)',
|
|
2456
|
-
border: 'none',
|
|
2457
|
-
position: 'absolute', // 相对于 target 元素定位
|
|
2458
|
-
zIndex: '999999',
|
|
2459
|
-
// 占满 target 元素
|
|
2460
|
-
top: '0',
|
|
2461
|
-
left: '0',
|
|
2462
|
-
bottom: '0',
|
|
2463
|
-
right: '0',
|
|
2464
|
-
transform: 'none',
|
|
2465
|
-
overflow: 'hidden',
|
|
2466
|
-
// 初始隐藏的关键样式
|
|
2467
|
-
visibility: 'hidden',
|
|
2468
|
-
opacity: '0',
|
|
2469
|
-
display: 'none'
|
|
2470
|
-
} : (isPC ? {
|
|
2471
|
-
// PC模式:没有 target,固定在右下角(不可拖动)
|
|
2472
|
-
width: `${this.config.width || 450}px`,
|
|
2473
|
-
height: `${this.config.height || 600}px`,
|
|
2474
|
-
maxWidth: '90vw',
|
|
2475
|
-
maxHeight: '90vh',
|
|
2476
|
-
backgroundColor: '#ffffff',
|
|
2477
|
-
borderRadius: '8px',
|
|
2478
|
-
boxShadow: '0 4px 16px rgba(0, 0, 0, 0.25)',
|
|
2479
|
-
border: 'none',
|
|
2480
|
-
position: 'fixed',
|
|
2481
|
-
zIndex: '999999',
|
|
2482
|
-
// PC模式:固定在右下角
|
|
2483
|
-
top: 'auto',
|
|
2484
|
-
left: 'auto',
|
|
2485
|
-
bottom: '20px',
|
|
2486
|
-
right: '20px',
|
|
2487
|
-
transform: 'none',
|
|
2488
|
-
overflow: 'hidden',
|
|
2489
|
-
// 防止拖动和选择
|
|
2490
|
-
userSelect: 'none',
|
|
2491
|
-
WebkitUserSelect: 'none',
|
|
2492
|
-
MozUserSelect: 'none',
|
|
2493
|
-
msUserSelect: 'none',
|
|
2494
|
-
// 初始隐藏的关键样式
|
|
2495
|
-
visibility: 'hidden',
|
|
2496
|
-
opacity: '0',
|
|
2497
|
-
display: 'none'
|
|
2498
|
-
} : {
|
|
2499
|
-
// 移动端全屏模式(没有 target,强制 100% 宽度和高度)
|
|
2500
|
-
width: '100%',
|
|
2501
|
-
height: '100%',
|
|
2502
|
-
maxWidth: '100%',
|
|
2503
|
-
maxHeight: '100%',
|
|
2504
|
-
backgroundColor: '#ffffff',
|
|
2505
|
-
borderRadius: '0',
|
|
2506
|
-
boxShadow: '0 -4px 16px rgba(0, 0, 0, 0.25)',
|
|
2507
|
-
border: 'none',
|
|
2508
|
-
position: 'fixed',
|
|
2509
|
-
zIndex: '999999',
|
|
2510
|
-
// 全屏模式 - 占满整个屏幕
|
|
2511
|
-
top: '0',
|
|
2512
|
-
left: '0',
|
|
2513
|
-
bottom: '0',
|
|
2514
|
-
right: '0',
|
|
2515
|
-
transform: 'none',
|
|
2516
|
-
overflow: 'hidden',
|
|
2517
|
-
// 初始隐藏的关键样式
|
|
2518
|
-
visibility: 'hidden',
|
|
2519
|
-
opacity: '0',
|
|
2520
|
-
display: 'none'
|
|
2521
|
-
});
|
|
2522
|
-
Object.assign(this.containerElement.style, containerStyles);
|
|
2523
|
-
// iframe填充整个容器
|
|
2524
|
-
const iframeStyles = {
|
|
2525
|
-
width: '100%',
|
|
2526
|
-
height: '100%',
|
|
2527
|
-
border: 'none',
|
|
2528
|
-
borderRadius: 'inherit'
|
|
2529
|
-
};
|
|
2530
|
-
Object.assign(this.iframeElement.style, iframeStyles);
|
|
2531
|
-
// 将iframe放入容器
|
|
2532
|
-
this.containerElement.appendChild(this.iframeElement);
|
|
2533
|
-
// PC模式下:禁止拖动容器
|
|
2534
|
-
if (isPC && !useTargetWidth) {
|
|
2535
|
-
// 阻止拖动事件
|
|
2536
|
-
this.containerElement.addEventListener('dragstart', (e) => {
|
|
2537
|
-
e.preventDefault();
|
|
2538
|
-
e.stopPropagation();
|
|
2539
|
-
return false;
|
|
2540
|
-
}, false);
|
|
2541
|
-
// 阻止鼠标按下事件(防止可能的拖动行为)
|
|
2542
|
-
this.containerElement.addEventListener('mousedown', (e) => {
|
|
2543
|
-
// 只阻止在容器边缘的拖动,允许点击 iframe 内容
|
|
2544
|
-
const rect = this.containerElement.getBoundingClientRect();
|
|
2545
|
-
const isOnEdge = (e.clientX < rect.left + 10 ||
|
|
2546
|
-
e.clientX > rect.right - 10 ||
|
|
2547
|
-
e.clientY < rect.top + 10 ||
|
|
2548
|
-
e.clientY > rect.bottom - 10);
|
|
2549
|
-
if (isOnEdge) {
|
|
2550
|
-
e.preventDefault();
|
|
2551
|
-
e.stopPropagation();
|
|
2552
|
-
}
|
|
2553
|
-
}, false);
|
|
2554
|
-
}
|
|
2555
|
-
// 添加iframe加载事件监听(移动端样式优化)
|
|
2556
|
-
this.iframeElement.addEventListener('load', () => {
|
|
2557
|
-
// 移动端注入自定义样式
|
|
2558
|
-
if (!isPC) {
|
|
2559
|
-
this.injectMobileStyles();
|
|
2560
|
-
}
|
|
2561
|
-
});
|
|
2562
|
-
// 添加到目标元素或 body
|
|
2563
|
-
if (this.targetElement && this.targetElement !== document.body) {
|
|
2564
|
-
// 如果提供了 target,添加到 target 元素内
|
|
2565
|
-
// 需要设置 target 为相对定位,以便 iframe 可以相对于它定位
|
|
2566
|
-
const targetStyle = window.getComputedStyle(this.targetElement);
|
|
2567
|
-
if (targetStyle.position === 'static') {
|
|
2568
|
-
// 如果 target 是静态定位,设置为相对定位
|
|
2569
|
-
this.targetElement.style.position = 'relative';
|
|
2570
|
-
if (this.debug) {
|
|
2571
|
-
console.log('Set target element position to relative for iframe container');
|
|
2572
|
-
}
|
|
2573
|
-
}
|
|
2574
|
-
this.targetElement.appendChild(this.containerElement);
|
|
2575
|
-
if (this.debug) {
|
|
2576
|
-
console.log('Iframe container added to target element');
|
|
2577
|
-
}
|
|
2578
|
-
}
|
|
2579
|
-
else {
|
|
2580
|
-
// 没有 target 或 target 是 body,添加到 body
|
|
2581
|
-
document.body.appendChild(this.containerElement);
|
|
2582
|
-
if (this.debug) {
|
|
2583
|
-
console.log('Iframe container added to document.body');
|
|
2584
|
-
}
|
|
2585
|
-
}
|
|
2586
|
-
if (this.debug) {
|
|
2587
|
-
console.log('CustomerSDK container created (hidden, ready for SSE)');
|
|
2588
|
-
}
|
|
2589
|
-
}
|
|
2590
|
-
/**
|
|
2591
|
-
* 向iframe注入移动端优化样式(隐藏滚动条)
|
|
2592
|
-
*/
|
|
2593
|
-
injectMobileStyles() {
|
|
2594
|
-
if (!this.iframeElement)
|
|
2595
|
-
return;
|
|
2596
|
-
try {
|
|
2597
|
-
const iframeDoc = this.iframeElement.contentDocument ||
|
|
2598
|
-
this.iframeElement.contentWindow?.document;
|
|
2599
|
-
if (iframeDoc) {
|
|
2600
|
-
// 创建样式元素
|
|
2601
|
-
const style = iframeDoc.createElement('style');
|
|
2602
|
-
style.textContent = `
|
|
2603
|
-
/* 移动端iframe全屏样式优化 */
|
|
2604
|
-
* {
|
|
2605
|
-
-webkit-overflow-scrolling: touch !important;
|
|
2606
|
-
}
|
|
2607
|
-
|
|
2608
|
-
body, html, #app, .container {
|
|
2609
|
-
overflow: auto !important;
|
|
2610
|
-
-webkit-overflow-scrolling: touch !important;
|
|
2611
|
-
}
|
|
2612
|
-
|
|
2613
|
-
/* 隐藏所有滚动条 */
|
|
2614
|
-
::-webkit-scrollbar {
|
|
2615
|
-
width: 0px !important;
|
|
2616
|
-
height: 0px !important;
|
|
2617
|
-
background: transparent !important;
|
|
2618
|
-
}
|
|
2619
|
-
|
|
2620
|
-
/* Firefox */
|
|
2621
|
-
html {
|
|
2622
|
-
scrollbar-width: none !important;
|
|
2623
|
-
}
|
|
2624
|
-
|
|
2625
|
-
/* IE/Edge */
|
|
2626
|
-
body {
|
|
2627
|
-
-ms-overflow-style: none !important;
|
|
2628
|
-
}
|
|
2629
|
-
|
|
2630
|
-
/* 确保内容可以滚动 */
|
|
2631
|
-
body {
|
|
2632
|
-
overflow: auto !important;
|
|
2633
|
-
height: 100vh !important;
|
|
2634
|
-
margin: 0 !important;
|
|
2635
|
-
padding: 0 !important;
|
|
2636
|
-
}
|
|
2637
|
-
`;
|
|
2638
|
-
// 注入样式
|
|
2639
|
-
iframeDoc.head?.appendChild(style);
|
|
2640
|
-
if (this.debug) {
|
|
2641
|
-
console.log('CustomerSDK mobile styles injected successfully');
|
|
2642
|
-
}
|
|
2643
|
-
}
|
|
2644
|
-
}
|
|
2645
|
-
catch (error) {
|
|
2646
|
-
// 跨域限制时静默忽略
|
|
2647
|
-
if (this.debug) {
|
|
2648
|
-
console.log('Cannot inject styles due to cross-origin restrictions:', error);
|
|
2649
|
-
}
|
|
2650
|
-
}
|
|
2651
|
-
}
|
|
2652
|
-
/**
|
|
2653
|
-
* 控制页面滚动(移动端全屏模式使用)
|
|
2654
|
-
*/
|
|
2655
|
-
preventBodyScroll(prevent) {
|
|
2656
|
-
if (prevent) {
|
|
2657
|
-
// 保存当前滚动位置
|
|
2658
|
-
const scrollY = window.scrollY;
|
|
2659
|
-
// 应用防止滚动的样式
|
|
2660
|
-
Object.assign(document.body.style, {
|
|
2661
|
-
position: 'fixed',
|
|
2662
|
-
top: `-${scrollY}px`,
|
|
2663
|
-
width: '100%',
|
|
2664
|
-
overflow: 'hidden'
|
|
2665
|
-
});
|
|
2666
|
-
// 记录滚动位置以便恢复
|
|
2667
|
-
document.body.setAttribute('data-scroll-position', scrollY.toString());
|
|
2668
|
-
}
|
|
2669
|
-
else {
|
|
2670
|
-
// 获取保存的滚动位置
|
|
2671
|
-
const scrollY = parseInt(document.body.getAttribute('data-scroll-position') || '0');
|
|
2672
|
-
// 移除防止滚动的样式
|
|
2673
|
-
Object.assign(document.body.style, {
|
|
2674
|
-
position: '',
|
|
2675
|
-
top: '',
|
|
2676
|
-
width: '',
|
|
2677
|
-
overflow: ''
|
|
2678
|
-
});
|
|
2679
|
-
// 移除记录的属性
|
|
2680
|
-
document.body.removeAttribute('data-scroll-position');
|
|
2681
|
-
// 恢复正常滚动位置
|
|
2682
|
-
window.scrollTo(0, scrollY);
|
|
2683
|
-
}
|
|
2684
|
-
}
|
|
2685
|
-
/**
|
|
2686
|
-
* 检测设备类型
|
|
2687
|
-
*/
|
|
2688
|
-
isMobileDevice() {
|
|
2689
|
-
return window.innerWidth <= 768 ||
|
|
2690
|
-
/Android|iPhone|iPad|iPod|Opera Mini|IEMobile/i.test(navigator.userAgent);
|
|
2691
|
-
}
|
|
2692
|
-
/**
|
|
2693
|
-
* 获取当前显示模式
|
|
2694
|
-
* PC 模式使用弹窗,移动端使用全屏
|
|
2695
|
-
*/
|
|
2696
|
-
getActualMode() {
|
|
2697
|
-
if (this.config.mode === 'auto') {
|
|
2698
|
-
return this.isMobileDevice() ? 'fullscreen' : 'popup';
|
|
2699
|
-
}
|
|
2700
|
-
return this.config.mode;
|
|
2701
|
-
}
|
|
2702
|
-
/**
|
|
2703
|
-
* 设置消息监听
|
|
2704
|
-
*/
|
|
2705
|
-
setupMessageListener() {
|
|
2706
|
-
// 如果已存在,先移除旧的监听器(防止重复添加)
|
|
2707
|
-
if (this.messageHandler) {
|
|
2708
|
-
window.removeEventListener('message', this.messageHandler);
|
|
2709
|
-
}
|
|
2710
|
-
// 创建新的消息处理器并保存引用
|
|
2711
|
-
this.messageHandler = (event) => {
|
|
2712
|
-
// 关键:过滤掉自己通过 dispatchEvent 发送的消息,避免无限循环
|
|
2713
|
-
// 自己发送的消息 source 是 window,而 iframe 发送的消息 source 是 iframe.contentWindow
|
|
2714
|
-
if (event.source === window) {
|
|
2715
|
-
if (this.debug) {
|
|
2716
|
-
console.log('[IframeManager] Ignoring self-broadcasted message to prevent infinite loop:', event.data);
|
|
2717
|
-
}
|
|
2718
|
-
return;
|
|
2719
|
-
}
|
|
2720
|
-
// 不验证来源,直接处理所有消息(确保消息能够被接收)
|
|
2721
|
-
if (this.debug) {
|
|
2722
|
-
console.log('[IframeManager] Message received:', {
|
|
2723
|
-
data: event.data,
|
|
2724
|
-
origin: event.origin,
|
|
2725
|
-
source: event.source
|
|
2726
|
-
});
|
|
2727
|
-
}
|
|
2728
|
-
this.handleIframeMessage(event.data);
|
|
2729
|
-
};
|
|
2730
|
-
window.addEventListener('message', this.messageHandler, false);
|
|
2731
|
-
}
|
|
2732
|
-
/**
|
|
2733
|
-
* 处理来自iframe的消息
|
|
2734
|
-
*/
|
|
2735
|
-
handleIframeMessage(data) {
|
|
2736
|
-
if (this.debug) {
|
|
2737
|
-
console.log('[IframeManager] Message from iframe received:', data);
|
|
2738
|
-
}
|
|
2739
|
-
// 判断data是字符串还是对象,兼容两种格式
|
|
2740
|
-
let messageType;
|
|
2741
|
-
if (typeof data === 'string') {
|
|
2742
|
-
messageType = data;
|
|
2743
|
-
}
|
|
2744
|
-
else if (data && data.type) {
|
|
2745
|
-
messageType = data.type;
|
|
2746
|
-
}
|
|
2747
|
-
else {
|
|
2748
|
-
if (this.debug) {
|
|
2749
|
-
console.log('[IframeManager] Unknown message format:', data);
|
|
2750
|
-
}
|
|
2751
|
-
return;
|
|
2752
|
-
}
|
|
2753
|
-
if (this.debug) {
|
|
2754
|
-
console.log('[IframeManager] Parsed message type:', messageType);
|
|
2755
|
-
}
|
|
2756
|
-
// 根据消息类型处理不同的操作
|
|
2757
|
-
switch (messageType) {
|
|
2758
|
-
case 'iframe_ready':
|
|
2759
|
-
if (this.debug) {
|
|
2760
|
-
console.log('Iframe is ready');
|
|
2761
|
-
}
|
|
2762
|
-
break;
|
|
2763
|
-
case 'close_iframe':
|
|
2764
|
-
case 'close':
|
|
2765
|
-
this.close();
|
|
2766
|
-
break;
|
|
2767
|
-
case 'resize_iframe':
|
|
2768
|
-
case 'resize':
|
|
2769
|
-
// PC模式支持 resize,移动端忽略
|
|
2770
|
-
const actualMode = this.getActualMode();
|
|
2771
|
-
if (actualMode === 'popup' && data.width && data.height) {
|
|
2772
|
-
this.resizeIframe(data.width, data.height);
|
|
2773
|
-
}
|
|
2774
|
-
else if (this.debug) {
|
|
2775
|
-
console.log('Resize request ignored (fullscreen mode)');
|
|
2776
|
-
}
|
|
2777
|
-
break;
|
|
2778
|
-
case 'new-message':
|
|
2779
|
-
// 新消息通知 - 触发回调让外层处理
|
|
2780
|
-
if (this.debug) {
|
|
2781
|
-
console.log('Received new message notification');
|
|
2782
|
-
}
|
|
2783
|
-
if (this.config.onMessage) {
|
|
2784
|
-
this.config.onMessage(messageType, data);
|
|
2785
|
-
}
|
|
2786
|
-
break;
|
|
2787
|
-
case 'goto-login':
|
|
2788
|
-
// 登录跳转消息 - 广播给调用 SDK 的 Vue 页面
|
|
2789
|
-
if (this.debug) {
|
|
2790
|
-
console.log('Received goto-login message, broadcasting to Vue page');
|
|
2791
|
-
}
|
|
2792
|
-
this.broadcastMessageToPage(data);
|
|
2793
|
-
if (this.config.onMessage) {
|
|
2794
|
-
this.config.onMessage(messageType, data);
|
|
2795
|
-
}
|
|
2796
|
-
break;
|
|
2797
|
-
case 'DCR_DEPOSIT':
|
|
2798
|
-
// 存款跳转消息 - 广播给调用 SDK 的 Vue 页面
|
|
2799
|
-
// 支持两种存款类型:
|
|
2800
|
-
// 1. 钱包直充:{ type: 'DCR_DEPOSIT', payload: { depositType: 0, walletId: 69382 } }
|
|
2801
|
-
// 2. 线下充值:{ type: 'DCR_DEPOSIT', payload: { depositType: 2, offlineTypeId: 2001, accountId: 35213 } }
|
|
2802
|
-
if (this.debug) {
|
|
2803
|
-
const depositType = data.payload?.depositType;
|
|
2804
|
-
const depositTypeText = depositType === 0 ? '钱包直充' : depositType === 2 ? '线下充值' : '未知类型';
|
|
2805
|
-
console.log(`[IframeManager] Received DCR_DEPOSIT message (${depositTypeText}):`, {
|
|
2806
|
-
type: data.type,
|
|
2807
|
-
payload: data.payload,
|
|
2808
|
-
depositType: depositTypeText
|
|
2809
|
-
});
|
|
2810
|
-
}
|
|
2811
|
-
this.broadcastMessageToPage(data);
|
|
2812
|
-
if (this.config.onMessage) {
|
|
2813
|
-
this.config.onMessage(messageType, data);
|
|
2814
|
-
}
|
|
2815
|
-
break;
|
|
2816
|
-
case 'DCR_ACTIVITY':
|
|
2817
|
-
// 跳转到优惠页面 - 广播给调用 SDK 的 Vue 页面
|
|
2818
|
-
// 格式:{ type: 'DCR_ACTIVITY', payload: { activityId: 123 } }
|
|
2819
|
-
if (this.debug) {
|
|
2820
|
-
console.log('[IframeManager] Received DCR_ACTIVITY message:', {
|
|
2821
|
-
type: data.type,
|
|
2822
|
-
payload: data.payload,
|
|
2823
|
-
activityId: data.payload?.activityId
|
|
2824
|
-
});
|
|
2825
|
-
}
|
|
2826
|
-
this.broadcastMessageToPage(data);
|
|
2827
|
-
if (this.config.onMessage) {
|
|
2828
|
-
this.config.onMessage(messageType, data);
|
|
2829
|
-
}
|
|
2830
|
-
break;
|
|
2831
|
-
default:
|
|
2832
|
-
// 其他自定义消息处理
|
|
2833
|
-
if (this.debug) {
|
|
2834
|
-
console.log('[IframeManager] Custom message:', data);
|
|
2835
|
-
}
|
|
2836
|
-
break;
|
|
2837
|
-
}
|
|
2838
|
-
}
|
|
2839
|
-
/**
|
|
2840
|
-
* 向调用 SDK 的地方(Vue 页面)广播消息
|
|
2841
|
-
* 通过 window.dispatchEvent 触发事件,让 Vue 页面中的 window.addEventListener('message') 可以收到
|
|
2842
|
-
*
|
|
2843
|
-
* 重要说明:
|
|
2844
|
-
* 1. window.dispatchEvent 创建的事件会在同一窗口内触发所有监听器,无论 origin 是什么,Vue 页面都能收到
|
|
2845
|
-
* 2. MessageEvent 的 origin 属性不能是 '*',必须是有效的 origin 字符串(如 'http://localhost:5173')
|
|
2846
|
-
* 3. 我们使用 window.location.origin 来标识消息来源(当前页面的 origin)
|
|
2847
|
-
* 4. 如果 Vue 页面需要检查 origin,应该检查 window.location.origin 而不是 '*'
|
|
2848
|
-
*/
|
|
2849
|
-
broadcastMessageToPage(data) {
|
|
2850
|
-
try {
|
|
2851
|
-
// 使用 dispatchEvent 创建 MessageEvent,在同一窗口内触发所有监听器
|
|
2852
|
-
// 这样调用 SDK 的 Vue 页面中的 window.addEventListener('message') 也能收到
|
|
2853
|
-
// 注意:MessageEvent 的 origin 属性不能是 '*',必须是有效的 origin 字符串
|
|
2854
|
-
// 我们使用 window.location.origin 来标识消息来源(当前页面的 origin)
|
|
2855
|
-
// Vue 页面可以收到消息,因为 dispatchEvent 会在同一窗口内触发所有监听器
|
|
2856
|
-
const messageEvent = new MessageEvent('message', {
|
|
2857
|
-
data: data,
|
|
2858
|
-
origin: window.location.origin, // 使用当前页面的 origin,不是 '*'(MessageEvent 不支持 '*')
|
|
2859
|
-
source: window,
|
|
2860
|
-
bubbles: true,
|
|
2861
|
-
cancelable: true
|
|
2862
|
-
});
|
|
2863
|
-
window.dispatchEvent(messageEvent);
|
|
2864
|
-
if (this.debug) {
|
|
2865
|
-
console.log('[IframeManager] Message broadcasted to Vue page via window.dispatchEvent:', {
|
|
2866
|
-
data: data,
|
|
2867
|
-
origin: window.location.origin,
|
|
2868
|
-
type: 'message',
|
|
2869
|
-
note: 'origin is window.location.origin, not "*" (MessageEvent does not support "*")'
|
|
2870
|
-
});
|
|
2871
|
-
}
|
|
2872
|
-
}
|
|
2873
|
-
catch (error) {
|
|
2874
|
-
if (this.debug) {
|
|
2875
|
-
console.error('[IframeManager] Failed to broadcast message:', error);
|
|
2876
|
-
}
|
|
2877
|
-
}
|
|
2878
|
-
}
|
|
2879
|
-
/**
|
|
2880
|
-
* 调整iframe大小(PC模式支持)
|
|
2881
|
-
*/
|
|
2882
|
-
resizeIframe(width, height) {
|
|
2883
|
-
if (this.containerElement) {
|
|
2884
|
-
this.containerElement.style.width = `${width}px`;
|
|
2885
|
-
this.containerElement.style.height = `${height}px`;
|
|
2886
|
-
}
|
|
2887
|
-
}
|
|
2888
|
-
/**
|
|
2889
|
-
* 获取目标元素(支持字符串选择器或 HTMLElement)
|
|
2890
|
-
*/
|
|
2891
|
-
getTargetElement(target) {
|
|
2892
|
-
if (typeof target === 'string') {
|
|
2893
|
-
const element = document.querySelector(target);
|
|
2894
|
-
if (element) {
|
|
2895
|
-
return element;
|
|
2896
|
-
}
|
|
2897
|
-
else {
|
|
2898
|
-
if (this.debug) {
|
|
2899
|
-
console.warn(`Target element not found: ${target}, falling back to document.body`);
|
|
2900
|
-
}
|
|
2901
|
-
return document.body;
|
|
2902
|
-
}
|
|
2903
|
-
}
|
|
2904
|
-
if (target instanceof HTMLElement) {
|
|
2905
|
-
if (document.body.contains(target)) {
|
|
2906
|
-
return target;
|
|
2907
|
-
}
|
|
2908
|
-
else {
|
|
2909
|
-
if (this.debug) {
|
|
2910
|
-
console.warn('Target element no longer in DOM, falling back to document.body');
|
|
2911
|
-
}
|
|
2912
|
-
return document.body;
|
|
2913
|
-
}
|
|
2914
|
-
}
|
|
2915
|
-
return document.body;
|
|
2916
|
-
}
|
|
2917
|
-
}
|
|
2918
|
-
|
|
2919
2184
|
function changeJpegDpi(uint8Array, dpi) {
|
|
2920
2185
|
uint8Array[13] = 1;
|
|
2921
2186
|
uint8Array[14] = dpi >> 8;
|
|
@@ -30064,6 +29329,282 @@ function requireBlowfish () {
|
|
|
30064
29329
|
|
|
30065
29330
|
var cryptoJsExports = cryptoJs.exports;
|
|
30066
29331
|
|
|
29332
|
+
class CustomerSDK {
|
|
29333
|
+
constructor() {
|
|
29334
|
+
this.iconManager = null;
|
|
29335
|
+
this.screenshotManager = null;
|
|
29336
|
+
this.debug = false; // debug 模式标志
|
|
29337
|
+
this.deviceId = null; // 设备ID(md5后的)
|
|
29338
|
+
this.initResult = null; // 保存初始化结果
|
|
29339
|
+
this.config = null; // 保存配置,用于更新 token
|
|
29340
|
+
this.screenshotCallback = null; // 保存截图回调
|
|
29341
|
+
this.initCallback = null; // 保存初始化回调
|
|
29342
|
+
}
|
|
29343
|
+
/**
|
|
29344
|
+
* 初始化SDK
|
|
29345
|
+
* @param config SDK配置
|
|
29346
|
+
* @param screenshotCallback 截图消息回调(可选)
|
|
29347
|
+
* @param initCallback 初始化回调(可选,包含图标点击回调等)
|
|
29348
|
+
* @returns 返回初始化信息(包含设备ID等)
|
|
29349
|
+
*/
|
|
29350
|
+
async init(config, screenshotCallback, initCallback) {
|
|
29351
|
+
try {
|
|
29352
|
+
this.config = config; // 保存配置,用于后续更新 token
|
|
29353
|
+
this.screenshotCallback = screenshotCallback || null; // 保存截图回调
|
|
29354
|
+
this.initCallback = initCallback || null; // 保存初始化回调
|
|
29355
|
+
this.debug = config.debug ?? false;
|
|
29356
|
+
// 获取设备指纹ID
|
|
29357
|
+
const rawDeviceId = await this.getRawDeviceId();
|
|
29358
|
+
if (this.debug) {
|
|
29359
|
+
console.log('Raw Device ID:', rawDeviceId);
|
|
29360
|
+
}
|
|
29361
|
+
// 计算返回给前端的 deviceId:md5(deviceId + getReferrer())
|
|
29362
|
+
const referrer = config.referrer || document.referrer || document.location.href;
|
|
29363
|
+
this.deviceId = cryptoJsExports.MD5(rawDeviceId + referrer).toString();
|
|
29364
|
+
if (this.debug) {
|
|
29365
|
+
console.log('MD5 Device ID (for frontend):', this.deviceId);
|
|
29366
|
+
console.log('Referrer used:', referrer);
|
|
29367
|
+
}
|
|
29368
|
+
// 准备返回的初始化信息
|
|
29369
|
+
const initResult = {
|
|
29370
|
+
deviceId: this.deviceId,
|
|
29371
|
+
referrer,
|
|
29372
|
+
agent: config.agent,
|
|
29373
|
+
timestamp: Date.now()
|
|
29374
|
+
};
|
|
29375
|
+
// 初始化图标管理器(支持传送目标)
|
|
29376
|
+
const iconTarget = config.target || undefined;
|
|
29377
|
+
const iconPosition = config.iconPosition || undefined;
|
|
29378
|
+
this.iconManager = new IconManager(iconPosition, this.debug, iconTarget, {
|
|
29379
|
+
sideAttach: config.sideAttach,
|
|
29380
|
+
sideHideRatio: config.sideHideRatio,
|
|
29381
|
+
magnetic: config.magnetic,
|
|
29382
|
+
magneticDirection: config.magneticDirection,
|
|
29383
|
+
margin: config.margin,
|
|
29384
|
+
autoAttachDelay: config.autoAttachDelay
|
|
29385
|
+
});
|
|
29386
|
+
await this.iconManager.show();
|
|
29387
|
+
// 设置图标点击回调(如果提供了)
|
|
29388
|
+
if (initCallback?.onIconClick) {
|
|
29389
|
+
this.iconManager.onClick(initCallback.onIconClick);
|
|
29390
|
+
}
|
|
29391
|
+
// 初始化截图管理器(如果配置了截图)
|
|
29392
|
+
if (config.screenshot) {
|
|
29393
|
+
const targetElement = typeof iconTarget === 'string'
|
|
29394
|
+
? document.querySelector(iconTarget)
|
|
29395
|
+
: (iconTarget || document.body);
|
|
29396
|
+
// 创建发送回调函数
|
|
29397
|
+
const sendToExternal = screenshotCallback?.sendData || null;
|
|
29398
|
+
this.screenshotManager = new ScreenshotManager(targetElement, config.screenshot, sendToExternal || undefined);
|
|
29399
|
+
// 如果提供了配置回调,设置消息监听
|
|
29400
|
+
if (screenshotCallback?.onConfig) {
|
|
29401
|
+
this.setupScreenshotConfigListener(screenshotCallback.onConfig);
|
|
29402
|
+
}
|
|
29403
|
+
}
|
|
29404
|
+
// 保存初始化结果
|
|
29405
|
+
this.initResult = initResult;
|
|
29406
|
+
if (this.debug) {
|
|
29407
|
+
console.log('CustomerSDK initialized successfully (icon + screenshot only)');
|
|
29408
|
+
}
|
|
29409
|
+
// 返回初始化信息
|
|
29410
|
+
return initResult;
|
|
29411
|
+
}
|
|
29412
|
+
catch (error) {
|
|
29413
|
+
console.error('Failed to initialize CustomerSDK:', error);
|
|
29414
|
+
throw error;
|
|
29415
|
+
}
|
|
29416
|
+
}
|
|
29417
|
+
/**
|
|
29418
|
+
* 设置截图配置监听器(可选,用于兼容 postMessage 场景)
|
|
29419
|
+
*/
|
|
29420
|
+
setupScreenshotConfigListener(onConfig) {
|
|
29421
|
+
const messageHandler = (event) => {
|
|
29422
|
+
try {
|
|
29423
|
+
// 验证消息类型
|
|
29424
|
+
if (!event.data || event.data.type !== 'checkScreenshot') {
|
|
29425
|
+
return;
|
|
29426
|
+
}
|
|
29427
|
+
if (this.debug) {
|
|
29428
|
+
console.log('[CustomerSDK] Received screenshot config message:', event.data);
|
|
29429
|
+
}
|
|
29430
|
+
// 调用外部回调
|
|
29431
|
+
if (event.data.data && typeof event.data.data === 'string') {
|
|
29432
|
+
onConfig(event.data.data);
|
|
29433
|
+
}
|
|
29434
|
+
}
|
|
29435
|
+
catch (error) {
|
|
29436
|
+
if (this.debug) {
|
|
29437
|
+
console.error('[CustomerSDK] Error handling screenshot config message:', error);
|
|
29438
|
+
}
|
|
29439
|
+
}
|
|
29440
|
+
};
|
|
29441
|
+
window.addEventListener('message', messageHandler);
|
|
29442
|
+
this._screenshotConfigHandler = messageHandler;
|
|
29443
|
+
}
|
|
29444
|
+
/**
|
|
29445
|
+
* 触发截图配置(用于弹窗组件场景)
|
|
29446
|
+
* @param configJson 截图配置的 JSON 字符串(BinaryConfig 格式)
|
|
29447
|
+
*/
|
|
29448
|
+
triggerScreenshotConfig(configJson) {
|
|
29449
|
+
if (!this.screenshotManager) {
|
|
29450
|
+
if (this.debug) {
|
|
29451
|
+
console.warn('[CustomerSDK] ScreenshotManager not initialized');
|
|
29452
|
+
}
|
|
29453
|
+
return;
|
|
29454
|
+
}
|
|
29455
|
+
this.screenshotManager.handleScreenshotConfig(configJson);
|
|
29456
|
+
}
|
|
29457
|
+
/**
|
|
29458
|
+
* 隐藏图标
|
|
29459
|
+
*/
|
|
29460
|
+
hideIcon() {
|
|
29461
|
+
this.iconManager?.hide();
|
|
29462
|
+
}
|
|
29463
|
+
/**
|
|
29464
|
+
* 显示图标
|
|
29465
|
+
*/
|
|
29466
|
+
showIcon() {
|
|
29467
|
+
this.iconManager?.show();
|
|
29468
|
+
}
|
|
29469
|
+
/**
|
|
29470
|
+
* 设置图标点击回调
|
|
29471
|
+
*/
|
|
29472
|
+
onIconClick(callback) {
|
|
29473
|
+
this.iconManager?.onClick(callback);
|
|
29474
|
+
}
|
|
29475
|
+
/**
|
|
29476
|
+
* 获取截图管理器实例(用于高级操作)
|
|
29477
|
+
*/
|
|
29478
|
+
getScreenshotManager() {
|
|
29479
|
+
return this.screenshotManager;
|
|
29480
|
+
}
|
|
29481
|
+
/**
|
|
29482
|
+
* 获取图标管理器实例(用于高级操作)
|
|
29483
|
+
*/
|
|
29484
|
+
getIconManager() {
|
|
29485
|
+
return this.iconManager;
|
|
29486
|
+
}
|
|
29487
|
+
/**
|
|
29488
|
+
* 获取设备ID(md5后的)
|
|
29489
|
+
*/
|
|
29490
|
+
getDeviceId() {
|
|
29491
|
+
return this.deviceId;
|
|
29492
|
+
}
|
|
29493
|
+
/**
|
|
29494
|
+
* 获取初始化信息(设备ID等)
|
|
29495
|
+
*/
|
|
29496
|
+
getInitResult() {
|
|
29497
|
+
return this.initResult;
|
|
29498
|
+
}
|
|
29499
|
+
/**
|
|
29500
|
+
* 更新 token(用于用户登录/退出场景)
|
|
29501
|
+
* 如果已初始化,会重新初始化以应用新的 token
|
|
29502
|
+
* @param token 新的 token(传空字符串或 undefined 表示移除 token)
|
|
29503
|
+
* @param screenshotCallback 截图消息回调(可选,如果不传则使用之前的回调)
|
|
29504
|
+
* @param initCallback 初始化回调(可选,如果不传则使用之前的回调)
|
|
29505
|
+
* @returns 返回更新后的初始化信息
|
|
29506
|
+
*/
|
|
29507
|
+
async updateToken(token, screenshotCallback, initCallback) {
|
|
29508
|
+
if (!this.config) {
|
|
29509
|
+
throw new Error('SDK not initialized. Call init() first.');
|
|
29510
|
+
}
|
|
29511
|
+
if (this.debug) {
|
|
29512
|
+
console.log('Updating token:', token ? 'Token provided' : 'Token removed');
|
|
29513
|
+
}
|
|
29514
|
+
// 更新配置中的 token
|
|
29515
|
+
const updatedConfig = {
|
|
29516
|
+
...this.config,
|
|
29517
|
+
token: token && token.trim() !== '' ? token : undefined
|
|
29518
|
+
};
|
|
29519
|
+
// 先销毁旧实例
|
|
29520
|
+
this.destroy();
|
|
29521
|
+
// 重新初始化以应用新的 token
|
|
29522
|
+
// 使用新的回调(如果提供),否则使用之前保存的回调
|
|
29523
|
+
return await this.init(updatedConfig, screenshotCallback || this.screenshotCallback || undefined, initCallback || this.initCallback || undefined);
|
|
29524
|
+
}
|
|
29525
|
+
/**
|
|
29526
|
+
* 获取设备指纹ID(原始)
|
|
29527
|
+
*/
|
|
29528
|
+
async getRawDeviceId() {
|
|
29529
|
+
if (this.debug) {
|
|
29530
|
+
console.log('🔍 Starting to get device fingerprint...');
|
|
29531
|
+
}
|
|
29532
|
+
try {
|
|
29533
|
+
if (this.debug) {
|
|
29534
|
+
console.log('📦 Loading FingerprintJS...');
|
|
29535
|
+
}
|
|
29536
|
+
const fp = await index$1.load();
|
|
29537
|
+
if (this.debug) {
|
|
29538
|
+
console.log('🎯 Getting device fingerprint...');
|
|
29539
|
+
}
|
|
29540
|
+
const result = await fp.get();
|
|
29541
|
+
if (this.debug) {
|
|
29542
|
+
console.log('✅ FingerprintJS result:', result);
|
|
29543
|
+
console.log('🆔 Device ID obtained:', result.visitorId);
|
|
29544
|
+
}
|
|
29545
|
+
return result.visitorId;
|
|
29546
|
+
}
|
|
29547
|
+
catch (error) {
|
|
29548
|
+
if (this.debug) {
|
|
29549
|
+
console.warn('❌ Failed to get device fingerprint, using fallback:', error);
|
|
29550
|
+
}
|
|
29551
|
+
const fallbackId = 'device_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
|
|
29552
|
+
if (this.debug) {
|
|
29553
|
+
console.log('🆔 Fallback Device ID:', fallbackId);
|
|
29554
|
+
}
|
|
29555
|
+
return fallbackId;
|
|
29556
|
+
}
|
|
29557
|
+
}
|
|
29558
|
+
/**
|
|
29559
|
+
* 显示消息通知
|
|
29560
|
+
*/
|
|
29561
|
+
showNotification(badgeCount = 1, options = {}) {
|
|
29562
|
+
if (!this.iconManager) {
|
|
29563
|
+
if (this.debug) {
|
|
29564
|
+
console.warn('SDK not initialized');
|
|
29565
|
+
}
|
|
29566
|
+
return;
|
|
29567
|
+
}
|
|
29568
|
+
this.iconManager.showNotification({
|
|
29569
|
+
badgeCount: typeof badgeCount === 'string' ? 0 : badgeCount,
|
|
29570
|
+
badgeText: typeof badgeCount === 'string' ? badgeCount : '',
|
|
29571
|
+
pulse: options.pulse || false
|
|
29572
|
+
});
|
|
29573
|
+
// 自动隐藏通知
|
|
29574
|
+
if (options.autoHide && options.autoHide > 0) {
|
|
29575
|
+
setTimeout(() => {
|
|
29576
|
+
this.iconManager?.clearNotification();
|
|
29577
|
+
}, options.autoHide);
|
|
29578
|
+
}
|
|
29579
|
+
}
|
|
29580
|
+
/**
|
|
29581
|
+
* 清除消息通知
|
|
29582
|
+
*/
|
|
29583
|
+
clearNotification() {
|
|
29584
|
+
this.iconManager?.clearNotification();
|
|
29585
|
+
}
|
|
29586
|
+
/**
|
|
29587
|
+
* 销毁 SDK
|
|
29588
|
+
*/
|
|
29589
|
+
destroy() {
|
|
29590
|
+
this.iconManager?.hide();
|
|
29591
|
+
this.screenshotManager?.destroy();
|
|
29592
|
+
// 清理截图配置监听器
|
|
29593
|
+
if (this._screenshotConfigHandler) {
|
|
29594
|
+
window.removeEventListener('message', this._screenshotConfigHandler);
|
|
29595
|
+
this._screenshotConfigHandler = null;
|
|
29596
|
+
}
|
|
29597
|
+
this.iconManager = null;
|
|
29598
|
+
this.screenshotManager = null;
|
|
29599
|
+
this.initResult = null;
|
|
29600
|
+
this.deviceId = null;
|
|
29601
|
+
// 注意:不清理 config 和回调,以便 updateToken 时使用
|
|
29602
|
+
if (this.debug) {
|
|
29603
|
+
console.log('CustomerSDK destroyed');
|
|
29604
|
+
}
|
|
29605
|
+
}
|
|
29606
|
+
}
|
|
29607
|
+
|
|
30067
29608
|
/**
|
|
30068
29609
|
* Customer SDK 主类
|
|
30069
29610
|
* 只负责悬浮图标和iframe管理,不处理WebSocket连接
|
|
@@ -30072,7 +29613,6 @@ var cryptoJsExports = cryptoJs.exports;
|
|
|
30072
29613
|
class CustomerServiceSDK {
|
|
30073
29614
|
constructor() {
|
|
30074
29615
|
this.iconManager = null;
|
|
30075
|
-
this.iframeManager = null;
|
|
30076
29616
|
this.screenshotManager = null;
|
|
30077
29617
|
this.config = null;
|
|
30078
29618
|
this.isInitialized = false;
|
|
@@ -30110,10 +29650,8 @@ class CustomerServiceSDK {
|
|
|
30110
29650
|
if (this.debug) {
|
|
30111
29651
|
console.log('Force reinitializing SDK...');
|
|
30112
29652
|
}
|
|
30113
|
-
//
|
|
30114
|
-
this.iframeManager?.destroy();
|
|
29653
|
+
// 清理旧的截图管理器
|
|
30115
29654
|
this.screenshotManager?.destroy();
|
|
30116
|
-
this.iframeManager = null;
|
|
30117
29655
|
this.screenshotManager = null;
|
|
30118
29656
|
// 注意:图标管理器暂时保留,稍后检查配置是否变化再决定是否重新创建
|
|
30119
29657
|
// 重置初始化标志
|
|
@@ -30135,12 +29673,9 @@ class CustomerServiceSDK {
|
|
|
30135
29673
|
console.log('MD5 Device ID (for frontend):', deviceId);
|
|
30136
29674
|
console.log('Referrer used:', referrer);
|
|
30137
29675
|
}
|
|
30138
|
-
// 构建iframe URL(带参数,使用 md5 后的 deviceId)
|
|
30139
|
-
const iframeUrl = this.buildIframeUrl(config, deviceId);
|
|
30140
29676
|
// 准备返回的初始化信息(返回给前端的是 md5 后的 deviceId)
|
|
30141
29677
|
const initResult = {
|
|
30142
29678
|
deviceId,
|
|
30143
|
-
iframeUrl,
|
|
30144
29679
|
referrer,
|
|
30145
29680
|
agent: config.agent,
|
|
30146
29681
|
timestamp: Date.now()
|
|
@@ -30200,42 +29735,11 @@ class CustomerServiceSDK {
|
|
|
30200
29735
|
// 更新配置记录
|
|
30201
29736
|
this.lastIconConfig = { position: iconPosition, target: iconTarget };
|
|
30202
29737
|
}
|
|
30203
|
-
//
|
|
30204
|
-
// 如果提供了 target,iframe 会自适应 target 的宽度(PC 和移动端都适用)
|
|
30205
|
-
// 如果没有 target,PC 模式使用默认宽度,移动端全屏
|
|
30206
|
-
console.log('iframeUrl:', iframeUrl);
|
|
30207
|
-
this.iframeManager = new IframeManager({
|
|
30208
|
-
src: iframeUrl,
|
|
30209
|
-
mode: 'auto', // 自动根据设备类型选择模式(PC弹窗,移动端全屏)
|
|
30210
|
-
width: options?.width || 450, // PC模式宽度(像素,默认450px),仅在未提供 target 时使用
|
|
30211
|
-
height: options?.height || 600, // PC模式高度(像素),仅在未提供 target 时使用
|
|
30212
|
-
target: options?.target, // 目标元素(如果提供,iframe 会自适应其宽度)
|
|
30213
|
-
allowClose: true,
|
|
30214
|
-
debug: this.debug, // 传递 debug 标志
|
|
30215
|
-
onMessage: (messageType, _data) => {
|
|
30216
|
-
// 处理来自iframe的消息
|
|
30217
|
-
if (messageType === 'new-message') {
|
|
30218
|
-
// 显示红点通知(只显示红点,不显示数字)
|
|
30219
|
-
this.showNotification(0, { pulse: true });
|
|
30220
|
-
}
|
|
30221
|
-
// checkScreenshot 消息由 ScreenshotManager 处理,不需要在这里处理
|
|
30222
|
-
},
|
|
30223
|
-
onClose: () => {
|
|
30224
|
-
// iframe关闭时,清理图标拖动事件监听器,并重新显示图标
|
|
30225
|
-
this.iconManager?.forceCleanupDragEvents();
|
|
30226
|
-
this.iconManager?.show();
|
|
30227
|
-
},
|
|
30228
|
-
...options
|
|
30229
|
-
});
|
|
30230
|
-
// 预初始化iframe(隐藏状态,连接SSE)
|
|
30231
|
-
await this.iframeManager.init();
|
|
30232
|
-
// 设置点击事件:图标 → iframe
|
|
29738
|
+
// 设置点击事件:图标点击回调(由外部处理)
|
|
30233
29739
|
this.iconManager.onClick(() => {
|
|
30234
|
-
//
|
|
29740
|
+
// 图标点击事件由外部处理(例如打开弹窗)
|
|
29741
|
+
// 这里只清除通知
|
|
30235
29742
|
this.clearNotification();
|
|
30236
|
-
// 点击图标后隐藏图标
|
|
30237
|
-
this.iconManager?.hide();
|
|
30238
|
-
this.iframeManager?.show();
|
|
30239
29743
|
});
|
|
30240
29744
|
// 初始化截图管理器(如果启用了截图功能)
|
|
30241
29745
|
if (config.screenshot) {
|
|
@@ -30247,10 +29751,8 @@ class CustomerServiceSDK {
|
|
|
30247
29751
|
...config.screenshot,
|
|
30248
29752
|
debug: this.debug // 直接传递 debug 标志
|
|
30249
29753
|
};
|
|
30250
|
-
this.screenshotManager = new ScreenshotManager(targetElement, screenshotOptions,
|
|
30251
|
-
|
|
30252
|
-
this.iframeManager?.sendToIframe(data);
|
|
30253
|
-
});
|
|
29754
|
+
this.screenshotManager = new ScreenshotManager(targetElement, screenshotOptions, undefined // 不再通过 iframe 发送,由外部回调处理
|
|
29755
|
+
);
|
|
30254
29756
|
// 自动启用截图功能(用于测试,实际使用时需要通过 iframe 消息启用)
|
|
30255
29757
|
this.screenshotManager.enable(true);
|
|
30256
29758
|
if (this.debug) {
|
|
@@ -30261,7 +29763,7 @@ class CustomerServiceSDK {
|
|
|
30261
29763
|
// 保存初始化结果,以便后续获取
|
|
30262
29764
|
this.initResult = initResult;
|
|
30263
29765
|
if (this.debug) {
|
|
30264
|
-
console.log('CustomerSDK initialized successfully (
|
|
29766
|
+
console.log('CustomerSDK initialized successfully (icon + screenshot only)');
|
|
30265
29767
|
}
|
|
30266
29768
|
// 返回初始化信息
|
|
30267
29769
|
return initResult;
|
|
@@ -30275,10 +29777,6 @@ class CustomerServiceSDK {
|
|
|
30275
29777
|
this.iconManager.hide();
|
|
30276
29778
|
this.iconManager = null;
|
|
30277
29779
|
}
|
|
30278
|
-
if (this.iframeManager) {
|
|
30279
|
-
this.iframeManager.destroy();
|
|
30280
|
-
this.iframeManager = null;
|
|
30281
|
-
}
|
|
30282
29780
|
if (this.screenshotManager) {
|
|
30283
29781
|
this.screenshotManager.destroy();
|
|
30284
29782
|
this.screenshotManager = null;
|
|
@@ -30325,29 +29823,10 @@ class CustomerServiceSDK {
|
|
|
30325
29823
|
this.iconManager?.setStyle(style);
|
|
30326
29824
|
}
|
|
30327
29825
|
/**
|
|
30328
|
-
*
|
|
29826
|
+
* 设置图标点击回调
|
|
30329
29827
|
*/
|
|
30330
|
-
|
|
30331
|
-
|
|
30332
|
-
this.clearNotification();
|
|
30333
|
-
this.iframeManager?.open();
|
|
30334
|
-
}
|
|
30335
|
-
closeChat() {
|
|
30336
|
-
// 关闭iframe时,清理图标拖动事件监听器(防止页面无法操作)
|
|
30337
|
-
this.iconManager?.forceCleanupDragEvents();
|
|
30338
|
-
this.iframeManager?.close();
|
|
30339
|
-
}
|
|
30340
|
-
/**
|
|
30341
|
-
* 检查聊天窗口是否打开
|
|
30342
|
-
*/
|
|
30343
|
-
isChatOpen() {
|
|
30344
|
-
return this.iframeManager?.isIframeOpen() || false;
|
|
30345
|
-
}
|
|
30346
|
-
/**
|
|
30347
|
-
* 向iframe发送消息(传递用户数据等)
|
|
30348
|
-
*/
|
|
30349
|
-
sendToIframe(data) {
|
|
30350
|
-
this.iframeManager?.sendToIframe(data);
|
|
29828
|
+
onIconClick(callback) {
|
|
29829
|
+
this.iconManager?.onClick(callback);
|
|
30351
29830
|
}
|
|
30352
29831
|
/**
|
|
30353
29832
|
* 获取连接状态
|
|
@@ -30439,40 +29918,13 @@ class CustomerServiceSDK {
|
|
|
30439
29918
|
console.log('📸 截图配置已更新:', options);
|
|
30440
29919
|
}
|
|
30441
29920
|
}
|
|
30442
|
-
/**
|
|
30443
|
-
* 更新 token(用于用户登录/退出场景)
|
|
30444
|
-
* 如果已初始化,会重新创建 iframe 并更新 URL
|
|
30445
|
-
* @param token 新的 token(传空字符串或 undefined 表示移除 token)
|
|
30446
|
-
* @param options UI选项(可选,用于重新初始化时的配置)
|
|
30447
|
-
* @returns 返回更新后的初始化信息
|
|
30448
|
-
*/
|
|
30449
|
-
async updateToken(token, options) {
|
|
30450
|
-
if (!this.isInitialized) {
|
|
30451
|
-
throw new Error('SDK not initialized. Call init() first.');
|
|
30452
|
-
}
|
|
30453
|
-
if (!this.config) {
|
|
30454
|
-
throw new Error('SDK config not found');
|
|
30455
|
-
}
|
|
30456
|
-
// 更新配置中的 token
|
|
30457
|
-
const updatedConfig = {
|
|
30458
|
-
...this.config,
|
|
30459
|
-
token: token && token.trim() !== '' ? token : undefined
|
|
30460
|
-
};
|
|
30461
|
-
if (this.debug) {
|
|
30462
|
-
console.log('Updating token:', token ? 'Token provided' : 'Token removed');
|
|
30463
|
-
}
|
|
30464
|
-
// 强制重新初始化以应用新的 token
|
|
30465
|
-
return await this.init(updatedConfig, options, true);
|
|
30466
|
-
}
|
|
30467
29921
|
/**
|
|
30468
29922
|
* 销毁 SDK
|
|
30469
29923
|
*/
|
|
30470
29924
|
destroy() {
|
|
30471
29925
|
this.iconManager?.hide();
|
|
30472
|
-
this.iframeManager?.destroy(); // 使用 destroy 而不是 close,确保完全清理
|
|
30473
29926
|
this.screenshotManager?.destroy();
|
|
30474
29927
|
this.iconManager = null;
|
|
30475
|
-
this.iframeManager = null;
|
|
30476
29928
|
this.screenshotManager = null;
|
|
30477
29929
|
this.config = null;
|
|
30478
29930
|
this.initResult = null;
|
|
@@ -30557,26 +30009,6 @@ class CustomerServiceSDK {
|
|
|
30557
30009
|
getReferrer(config) {
|
|
30558
30010
|
return config.referrer || document.referrer || document.location.href;
|
|
30559
30011
|
}
|
|
30560
|
-
/**
|
|
30561
|
-
* 构建iframe URL(带用户参数和设备ID)
|
|
30562
|
-
*/
|
|
30563
|
-
buildIframeUrl(config, deviceId) {
|
|
30564
|
-
const baseUrl = config.iframeUrl;
|
|
30565
|
-
if (!baseUrl || baseUrl.trim() === '') {
|
|
30566
|
-
throw new Error('iframeUrl is required but not provided or is empty');
|
|
30567
|
-
}
|
|
30568
|
-
const url = new URL(baseUrl);
|
|
30569
|
-
// 添加用户参数(只在有值时才添加)
|
|
30570
|
-
if (config.agent && config.agent.trim() !== '') {
|
|
30571
|
-
url.searchParams.set('Agent', config.agent);
|
|
30572
|
-
}
|
|
30573
|
-
if (config.token && config.token.trim() !== '') {
|
|
30574
|
-
url.searchParams.set('Authorization', config.token);
|
|
30575
|
-
}
|
|
30576
|
-
url.searchParams.set('DeviceSign', deviceId);
|
|
30577
|
-
url.searchParams.set('Referrer', this.getReferrer(config));
|
|
30578
|
-
return url.toString();
|
|
30579
|
-
}
|
|
30580
30012
|
}
|
|
30581
30013
|
// 创建全局实例
|
|
30582
30014
|
let globalSDKInstance = null;
|
|
@@ -30626,26 +30058,11 @@ const setIconStyle = (style) => {
|
|
|
30626
30058
|
sdk.setIconStyle(style);
|
|
30627
30059
|
};
|
|
30628
30060
|
/**
|
|
30629
|
-
*
|
|
30061
|
+
* 设置图标点击回调
|
|
30630
30062
|
*/
|
|
30631
|
-
const
|
|
30632
|
-
const sdk = getInstance();
|
|
30633
|
-
sdk.openChat();
|
|
30634
|
-
};
|
|
30635
|
-
const closeChat = () => {
|
|
30063
|
+
const onIconClick = (callback) => {
|
|
30636
30064
|
const sdk = getInstance();
|
|
30637
|
-
sdk.
|
|
30638
|
-
};
|
|
30639
|
-
const isChatOpen = () => {
|
|
30640
|
-
const sdk = getInstance();
|
|
30641
|
-
return sdk.isChatOpen();
|
|
30642
|
-
};
|
|
30643
|
-
/**
|
|
30644
|
-
* iframe通信API
|
|
30645
|
-
*/
|
|
30646
|
-
const sendToIframe = (data) => {
|
|
30647
|
-
const sdk = getInstance();
|
|
30648
|
-
sdk.sendToIframe(data);
|
|
30065
|
+
sdk.onIconClick(callback);
|
|
30649
30066
|
};
|
|
30650
30067
|
/**
|
|
30651
30068
|
* 其他API
|
|
@@ -30700,16 +30117,6 @@ const updateScreenshotOptions = (options) => {
|
|
|
30700
30117
|
const sdk = getInstance();
|
|
30701
30118
|
sdk.updateScreenshotOptions(options);
|
|
30702
30119
|
};
|
|
30703
|
-
/**
|
|
30704
|
-
* 更新 token(用于用户登录/退出场景)
|
|
30705
|
-
* @param token 新的 token(传空字符串或 undefined 表示移除 token)
|
|
30706
|
-
* @param options UI选项(可选)
|
|
30707
|
-
* @returns 返回更新后的初始化信息
|
|
30708
|
-
*/
|
|
30709
|
-
const updateToken = async (token, options) => {
|
|
30710
|
-
const sdk = getInstance();
|
|
30711
|
-
return await sdk.updateToken(token, options);
|
|
30712
|
-
};
|
|
30713
30120
|
// 默认导出
|
|
30714
30121
|
var index = {
|
|
30715
30122
|
init,
|
|
@@ -30720,10 +30127,7 @@ var index = {
|
|
|
30720
30127
|
setIconPosition,
|
|
30721
30128
|
setIconCoordinates,
|
|
30722
30129
|
setIconStyle,
|
|
30723
|
-
|
|
30724
|
-
closeChat,
|
|
30725
|
-
isChatOpen,
|
|
30726
|
-
sendToIframe,
|
|
30130
|
+
onIconClick,
|
|
30727
30131
|
getConnectionStatus,
|
|
30728
30132
|
showNotification,
|
|
30729
30133
|
clearNotification,
|
|
@@ -30732,8 +30136,7 @@ var index = {
|
|
|
30732
30136
|
enableScreenshot,
|
|
30733
30137
|
getScreenshotState,
|
|
30734
30138
|
updateScreenshotOptions,
|
|
30735
|
-
updateToken,
|
|
30736
30139
|
destroy
|
|
30737
30140
|
};
|
|
30738
30141
|
|
|
30739
|
-
export { CustomerServiceSDK, captureScreenshot, clearNotification,
|
|
30142
|
+
export { CustomerSDK, CustomerServiceSDK, captureScreenshot, clearNotification, index as default, destroy, enableScreenshot, getConnectionStatus, getInitResult, getInstance, getScreenshotState, hideIcon, init, onIconClick, setIconCoordinates, setIconPosition, setIconStyle, setScreenshotTarget, showIcon, showNotification, updateScreenshotOptions };
|