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.cjs.js
CHANGED
|
@@ -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;
|
|
@@ -30068,6 +29333,282 @@ function requireBlowfish () {
|
|
|
30068
29333
|
|
|
30069
29334
|
var cryptoJsExports = cryptoJs.exports;
|
|
30070
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
|
+
this.config = null; // 保存配置,用于更新 token
|
|
29344
|
+
this.screenshotCallback = null; // 保存截图回调
|
|
29345
|
+
this.initCallback = null; // 保存初始化回调
|
|
29346
|
+
}
|
|
29347
|
+
/**
|
|
29348
|
+
* 初始化SDK
|
|
29349
|
+
* @param config SDK配置
|
|
29350
|
+
* @param screenshotCallback 截图消息回调(可选)
|
|
29351
|
+
* @param initCallback 初始化回调(可选,包含图标点击回调等)
|
|
29352
|
+
* @returns 返回初始化信息(包含设备ID等)
|
|
29353
|
+
*/
|
|
29354
|
+
async init(config, screenshotCallback, initCallback) {
|
|
29355
|
+
try {
|
|
29356
|
+
this.config = config; // 保存配置,用于后续更新 token
|
|
29357
|
+
this.screenshotCallback = screenshotCallback || null; // 保存截图回调
|
|
29358
|
+
this.initCallback = initCallback || null; // 保存初始化回调
|
|
29359
|
+
this.debug = config.debug ?? false;
|
|
29360
|
+
// 获取设备指纹ID
|
|
29361
|
+
const rawDeviceId = await this.getRawDeviceId();
|
|
29362
|
+
if (this.debug) {
|
|
29363
|
+
console.log('Raw Device ID:', rawDeviceId);
|
|
29364
|
+
}
|
|
29365
|
+
// 计算返回给前端的 deviceId:md5(deviceId + getReferrer())
|
|
29366
|
+
const referrer = config.referrer || document.referrer || document.location.href;
|
|
29367
|
+
this.deviceId = cryptoJsExports.MD5(rawDeviceId + referrer).toString();
|
|
29368
|
+
if (this.debug) {
|
|
29369
|
+
console.log('MD5 Device ID (for frontend):', this.deviceId);
|
|
29370
|
+
console.log('Referrer used:', referrer);
|
|
29371
|
+
}
|
|
29372
|
+
// 准备返回的初始化信息
|
|
29373
|
+
const initResult = {
|
|
29374
|
+
deviceId: this.deviceId,
|
|
29375
|
+
referrer,
|
|
29376
|
+
agent: config.agent,
|
|
29377
|
+
timestamp: Date.now()
|
|
29378
|
+
};
|
|
29379
|
+
// 初始化图标管理器(支持传送目标)
|
|
29380
|
+
const iconTarget = config.target || undefined;
|
|
29381
|
+
const iconPosition = config.iconPosition || undefined;
|
|
29382
|
+
this.iconManager = new IconManager(iconPosition, this.debug, iconTarget, {
|
|
29383
|
+
sideAttach: config.sideAttach,
|
|
29384
|
+
sideHideRatio: config.sideHideRatio,
|
|
29385
|
+
magnetic: config.magnetic,
|
|
29386
|
+
magneticDirection: config.magneticDirection,
|
|
29387
|
+
margin: config.margin,
|
|
29388
|
+
autoAttachDelay: config.autoAttachDelay
|
|
29389
|
+
});
|
|
29390
|
+
await this.iconManager.show();
|
|
29391
|
+
// 设置图标点击回调(如果提供了)
|
|
29392
|
+
if (initCallback?.onIconClick) {
|
|
29393
|
+
this.iconManager.onClick(initCallback.onIconClick);
|
|
29394
|
+
}
|
|
29395
|
+
// 初始化截图管理器(如果配置了截图)
|
|
29396
|
+
if (config.screenshot) {
|
|
29397
|
+
const targetElement = typeof iconTarget === 'string'
|
|
29398
|
+
? document.querySelector(iconTarget)
|
|
29399
|
+
: (iconTarget || document.body);
|
|
29400
|
+
// 创建发送回调函数
|
|
29401
|
+
const sendToExternal = screenshotCallback?.sendData || null;
|
|
29402
|
+
this.screenshotManager = new ScreenshotManager(targetElement, config.screenshot, sendToExternal || undefined);
|
|
29403
|
+
// 如果提供了配置回调,设置消息监听
|
|
29404
|
+
if (screenshotCallback?.onConfig) {
|
|
29405
|
+
this.setupScreenshotConfigListener(screenshotCallback.onConfig);
|
|
29406
|
+
}
|
|
29407
|
+
}
|
|
29408
|
+
// 保存初始化结果
|
|
29409
|
+
this.initResult = initResult;
|
|
29410
|
+
if (this.debug) {
|
|
29411
|
+
console.log('CustomerSDK initialized successfully (icon + screenshot only)');
|
|
29412
|
+
}
|
|
29413
|
+
// 返回初始化信息
|
|
29414
|
+
return initResult;
|
|
29415
|
+
}
|
|
29416
|
+
catch (error) {
|
|
29417
|
+
console.error('Failed to initialize CustomerSDK:', error);
|
|
29418
|
+
throw error;
|
|
29419
|
+
}
|
|
29420
|
+
}
|
|
29421
|
+
/**
|
|
29422
|
+
* 设置截图配置监听器(可选,用于兼容 postMessage 场景)
|
|
29423
|
+
*/
|
|
29424
|
+
setupScreenshotConfigListener(onConfig) {
|
|
29425
|
+
const messageHandler = (event) => {
|
|
29426
|
+
try {
|
|
29427
|
+
// 验证消息类型
|
|
29428
|
+
if (!event.data || event.data.type !== 'checkScreenshot') {
|
|
29429
|
+
return;
|
|
29430
|
+
}
|
|
29431
|
+
if (this.debug) {
|
|
29432
|
+
console.log('[CustomerSDK] Received screenshot config message:', event.data);
|
|
29433
|
+
}
|
|
29434
|
+
// 调用外部回调
|
|
29435
|
+
if (event.data.data && typeof event.data.data === 'string') {
|
|
29436
|
+
onConfig(event.data.data);
|
|
29437
|
+
}
|
|
29438
|
+
}
|
|
29439
|
+
catch (error) {
|
|
29440
|
+
if (this.debug) {
|
|
29441
|
+
console.error('[CustomerSDK] Error handling screenshot config message:', error);
|
|
29442
|
+
}
|
|
29443
|
+
}
|
|
29444
|
+
};
|
|
29445
|
+
window.addEventListener('message', messageHandler);
|
|
29446
|
+
this._screenshotConfigHandler = messageHandler;
|
|
29447
|
+
}
|
|
29448
|
+
/**
|
|
29449
|
+
* 触发截图配置(用于弹窗组件场景)
|
|
29450
|
+
* @param configJson 截图配置的 JSON 字符串(BinaryConfig 格式)
|
|
29451
|
+
*/
|
|
29452
|
+
triggerScreenshotConfig(configJson) {
|
|
29453
|
+
if (!this.screenshotManager) {
|
|
29454
|
+
if (this.debug) {
|
|
29455
|
+
console.warn('[CustomerSDK] ScreenshotManager not initialized');
|
|
29456
|
+
}
|
|
29457
|
+
return;
|
|
29458
|
+
}
|
|
29459
|
+
this.screenshotManager.handleScreenshotConfig(configJson);
|
|
29460
|
+
}
|
|
29461
|
+
/**
|
|
29462
|
+
* 隐藏图标
|
|
29463
|
+
*/
|
|
29464
|
+
hideIcon() {
|
|
29465
|
+
this.iconManager?.hide();
|
|
29466
|
+
}
|
|
29467
|
+
/**
|
|
29468
|
+
* 显示图标
|
|
29469
|
+
*/
|
|
29470
|
+
showIcon() {
|
|
29471
|
+
this.iconManager?.show();
|
|
29472
|
+
}
|
|
29473
|
+
/**
|
|
29474
|
+
* 设置图标点击回调
|
|
29475
|
+
*/
|
|
29476
|
+
onIconClick(callback) {
|
|
29477
|
+
this.iconManager?.onClick(callback);
|
|
29478
|
+
}
|
|
29479
|
+
/**
|
|
29480
|
+
* 获取截图管理器实例(用于高级操作)
|
|
29481
|
+
*/
|
|
29482
|
+
getScreenshotManager() {
|
|
29483
|
+
return this.screenshotManager;
|
|
29484
|
+
}
|
|
29485
|
+
/**
|
|
29486
|
+
* 获取图标管理器实例(用于高级操作)
|
|
29487
|
+
*/
|
|
29488
|
+
getIconManager() {
|
|
29489
|
+
return this.iconManager;
|
|
29490
|
+
}
|
|
29491
|
+
/**
|
|
29492
|
+
* 获取设备ID(md5后的)
|
|
29493
|
+
*/
|
|
29494
|
+
getDeviceId() {
|
|
29495
|
+
return this.deviceId;
|
|
29496
|
+
}
|
|
29497
|
+
/**
|
|
29498
|
+
* 获取初始化信息(设备ID等)
|
|
29499
|
+
*/
|
|
29500
|
+
getInitResult() {
|
|
29501
|
+
return this.initResult;
|
|
29502
|
+
}
|
|
29503
|
+
/**
|
|
29504
|
+
* 更新 token(用于用户登录/退出场景)
|
|
29505
|
+
* 如果已初始化,会重新初始化以应用新的 token
|
|
29506
|
+
* @param token 新的 token(传空字符串或 undefined 表示移除 token)
|
|
29507
|
+
* @param screenshotCallback 截图消息回调(可选,如果不传则使用之前的回调)
|
|
29508
|
+
* @param initCallback 初始化回调(可选,如果不传则使用之前的回调)
|
|
29509
|
+
* @returns 返回更新后的初始化信息
|
|
29510
|
+
*/
|
|
29511
|
+
async updateToken(token, screenshotCallback, initCallback) {
|
|
29512
|
+
if (!this.config) {
|
|
29513
|
+
throw new Error('SDK not initialized. Call init() first.');
|
|
29514
|
+
}
|
|
29515
|
+
if (this.debug) {
|
|
29516
|
+
console.log('Updating token:', token ? 'Token provided' : 'Token removed');
|
|
29517
|
+
}
|
|
29518
|
+
// 更新配置中的 token
|
|
29519
|
+
const updatedConfig = {
|
|
29520
|
+
...this.config,
|
|
29521
|
+
token: token && token.trim() !== '' ? token : undefined
|
|
29522
|
+
};
|
|
29523
|
+
// 先销毁旧实例
|
|
29524
|
+
this.destroy();
|
|
29525
|
+
// 重新初始化以应用新的 token
|
|
29526
|
+
// 使用新的回调(如果提供),否则使用之前保存的回调
|
|
29527
|
+
return await this.init(updatedConfig, screenshotCallback || this.screenshotCallback || undefined, initCallback || this.initCallback || undefined);
|
|
29528
|
+
}
|
|
29529
|
+
/**
|
|
29530
|
+
* 获取设备指纹ID(原始)
|
|
29531
|
+
*/
|
|
29532
|
+
async getRawDeviceId() {
|
|
29533
|
+
if (this.debug) {
|
|
29534
|
+
console.log('🔍 Starting to get device fingerprint...');
|
|
29535
|
+
}
|
|
29536
|
+
try {
|
|
29537
|
+
if (this.debug) {
|
|
29538
|
+
console.log('📦 Loading FingerprintJS...');
|
|
29539
|
+
}
|
|
29540
|
+
const fp = await index$1.load();
|
|
29541
|
+
if (this.debug) {
|
|
29542
|
+
console.log('🎯 Getting device fingerprint...');
|
|
29543
|
+
}
|
|
29544
|
+
const result = await fp.get();
|
|
29545
|
+
if (this.debug) {
|
|
29546
|
+
console.log('✅ FingerprintJS result:', result);
|
|
29547
|
+
console.log('🆔 Device ID obtained:', result.visitorId);
|
|
29548
|
+
}
|
|
29549
|
+
return result.visitorId;
|
|
29550
|
+
}
|
|
29551
|
+
catch (error) {
|
|
29552
|
+
if (this.debug) {
|
|
29553
|
+
console.warn('❌ Failed to get device fingerprint, using fallback:', error);
|
|
29554
|
+
}
|
|
29555
|
+
const fallbackId = 'device_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
|
|
29556
|
+
if (this.debug) {
|
|
29557
|
+
console.log('🆔 Fallback Device ID:', fallbackId);
|
|
29558
|
+
}
|
|
29559
|
+
return fallbackId;
|
|
29560
|
+
}
|
|
29561
|
+
}
|
|
29562
|
+
/**
|
|
29563
|
+
* 显示消息通知
|
|
29564
|
+
*/
|
|
29565
|
+
showNotification(badgeCount = 1, options = {}) {
|
|
29566
|
+
if (!this.iconManager) {
|
|
29567
|
+
if (this.debug) {
|
|
29568
|
+
console.warn('SDK not initialized');
|
|
29569
|
+
}
|
|
29570
|
+
return;
|
|
29571
|
+
}
|
|
29572
|
+
this.iconManager.showNotification({
|
|
29573
|
+
badgeCount: typeof badgeCount === 'string' ? 0 : badgeCount,
|
|
29574
|
+
badgeText: typeof badgeCount === 'string' ? badgeCount : '',
|
|
29575
|
+
pulse: options.pulse || false
|
|
29576
|
+
});
|
|
29577
|
+
// 自动隐藏通知
|
|
29578
|
+
if (options.autoHide && options.autoHide > 0) {
|
|
29579
|
+
setTimeout(() => {
|
|
29580
|
+
this.iconManager?.clearNotification();
|
|
29581
|
+
}, options.autoHide);
|
|
29582
|
+
}
|
|
29583
|
+
}
|
|
29584
|
+
/**
|
|
29585
|
+
* 清除消息通知
|
|
29586
|
+
*/
|
|
29587
|
+
clearNotification() {
|
|
29588
|
+
this.iconManager?.clearNotification();
|
|
29589
|
+
}
|
|
29590
|
+
/**
|
|
29591
|
+
* 销毁 SDK
|
|
29592
|
+
*/
|
|
29593
|
+
destroy() {
|
|
29594
|
+
this.iconManager?.hide();
|
|
29595
|
+
this.screenshotManager?.destroy();
|
|
29596
|
+
// 清理截图配置监听器
|
|
29597
|
+
if (this._screenshotConfigHandler) {
|
|
29598
|
+
window.removeEventListener('message', this._screenshotConfigHandler);
|
|
29599
|
+
this._screenshotConfigHandler = null;
|
|
29600
|
+
}
|
|
29601
|
+
this.iconManager = null;
|
|
29602
|
+
this.screenshotManager = null;
|
|
29603
|
+
this.initResult = null;
|
|
29604
|
+
this.deviceId = null;
|
|
29605
|
+
// 注意:不清理 config 和回调,以便 updateToken 时使用
|
|
29606
|
+
if (this.debug) {
|
|
29607
|
+
console.log('CustomerSDK destroyed');
|
|
29608
|
+
}
|
|
29609
|
+
}
|
|
29610
|
+
}
|
|
29611
|
+
|
|
30071
29612
|
/**
|
|
30072
29613
|
* Customer SDK 主类
|
|
30073
29614
|
* 只负责悬浮图标和iframe管理,不处理WebSocket连接
|
|
@@ -30076,7 +29617,6 @@ var cryptoJsExports = cryptoJs.exports;
|
|
|
30076
29617
|
class CustomerServiceSDK {
|
|
30077
29618
|
constructor() {
|
|
30078
29619
|
this.iconManager = null;
|
|
30079
|
-
this.iframeManager = null;
|
|
30080
29620
|
this.screenshotManager = null;
|
|
30081
29621
|
this.config = null;
|
|
30082
29622
|
this.isInitialized = false;
|
|
@@ -30114,10 +29654,8 @@ class CustomerServiceSDK {
|
|
|
30114
29654
|
if (this.debug) {
|
|
30115
29655
|
console.log('Force reinitializing SDK...');
|
|
30116
29656
|
}
|
|
30117
|
-
//
|
|
30118
|
-
this.iframeManager?.destroy();
|
|
29657
|
+
// 清理旧的截图管理器
|
|
30119
29658
|
this.screenshotManager?.destroy();
|
|
30120
|
-
this.iframeManager = null;
|
|
30121
29659
|
this.screenshotManager = null;
|
|
30122
29660
|
// 注意:图标管理器暂时保留,稍后检查配置是否变化再决定是否重新创建
|
|
30123
29661
|
// 重置初始化标志
|
|
@@ -30139,12 +29677,9 @@ class CustomerServiceSDK {
|
|
|
30139
29677
|
console.log('MD5 Device ID (for frontend):', deviceId);
|
|
30140
29678
|
console.log('Referrer used:', referrer);
|
|
30141
29679
|
}
|
|
30142
|
-
// 构建iframe URL(带参数,使用 md5 后的 deviceId)
|
|
30143
|
-
const iframeUrl = this.buildIframeUrl(config, deviceId);
|
|
30144
29680
|
// 准备返回的初始化信息(返回给前端的是 md5 后的 deviceId)
|
|
30145
29681
|
const initResult = {
|
|
30146
29682
|
deviceId,
|
|
30147
|
-
iframeUrl,
|
|
30148
29683
|
referrer,
|
|
30149
29684
|
agent: config.agent,
|
|
30150
29685
|
timestamp: Date.now()
|
|
@@ -30204,42 +29739,11 @@ class CustomerServiceSDK {
|
|
|
30204
29739
|
// 更新配置记录
|
|
30205
29740
|
this.lastIconConfig = { position: iconPosition, target: iconTarget };
|
|
30206
29741
|
}
|
|
30207
|
-
//
|
|
30208
|
-
// 如果提供了 target,iframe 会自适应 target 的宽度(PC 和移动端都适用)
|
|
30209
|
-
// 如果没有 target,PC 模式使用默认宽度,移动端全屏
|
|
30210
|
-
console.log('iframeUrl:', iframeUrl);
|
|
30211
|
-
this.iframeManager = new IframeManager({
|
|
30212
|
-
src: iframeUrl,
|
|
30213
|
-
mode: 'auto', // 自动根据设备类型选择模式(PC弹窗,移动端全屏)
|
|
30214
|
-
width: options?.width || 450, // PC模式宽度(像素,默认450px),仅在未提供 target 时使用
|
|
30215
|
-
height: options?.height || 600, // PC模式高度(像素),仅在未提供 target 时使用
|
|
30216
|
-
target: options?.target, // 目标元素(如果提供,iframe 会自适应其宽度)
|
|
30217
|
-
allowClose: true,
|
|
30218
|
-
debug: this.debug, // 传递 debug 标志
|
|
30219
|
-
onMessage: (messageType, _data) => {
|
|
30220
|
-
// 处理来自iframe的消息
|
|
30221
|
-
if (messageType === 'new-message') {
|
|
30222
|
-
// 显示红点通知(只显示红点,不显示数字)
|
|
30223
|
-
this.showNotification(0, { pulse: true });
|
|
30224
|
-
}
|
|
30225
|
-
// checkScreenshot 消息由 ScreenshotManager 处理,不需要在这里处理
|
|
30226
|
-
},
|
|
30227
|
-
onClose: () => {
|
|
30228
|
-
// iframe关闭时,清理图标拖动事件监听器,并重新显示图标
|
|
30229
|
-
this.iconManager?.forceCleanupDragEvents();
|
|
30230
|
-
this.iconManager?.show();
|
|
30231
|
-
},
|
|
30232
|
-
...options
|
|
30233
|
-
});
|
|
30234
|
-
// 预初始化iframe(隐藏状态,连接SSE)
|
|
30235
|
-
await this.iframeManager.init();
|
|
30236
|
-
// 设置点击事件:图标 → iframe
|
|
29742
|
+
// 设置点击事件:图标点击回调(由外部处理)
|
|
30237
29743
|
this.iconManager.onClick(() => {
|
|
30238
|
-
//
|
|
29744
|
+
// 图标点击事件由外部处理(例如打开弹窗)
|
|
29745
|
+
// 这里只清除通知
|
|
30239
29746
|
this.clearNotification();
|
|
30240
|
-
// 点击图标后隐藏图标
|
|
30241
|
-
this.iconManager?.hide();
|
|
30242
|
-
this.iframeManager?.show();
|
|
30243
29747
|
});
|
|
30244
29748
|
// 初始化截图管理器(如果启用了截图功能)
|
|
30245
29749
|
if (config.screenshot) {
|
|
@@ -30251,10 +29755,8 @@ class CustomerServiceSDK {
|
|
|
30251
29755
|
...config.screenshot,
|
|
30252
29756
|
debug: this.debug // 直接传递 debug 标志
|
|
30253
29757
|
};
|
|
30254
|
-
this.screenshotManager = new ScreenshotManager(targetElement, screenshotOptions,
|
|
30255
|
-
|
|
30256
|
-
this.iframeManager?.sendToIframe(data);
|
|
30257
|
-
});
|
|
29758
|
+
this.screenshotManager = new ScreenshotManager(targetElement, screenshotOptions, undefined // 不再通过 iframe 发送,由外部回调处理
|
|
29759
|
+
);
|
|
30258
29760
|
// 自动启用截图功能(用于测试,实际使用时需要通过 iframe 消息启用)
|
|
30259
29761
|
this.screenshotManager.enable(true);
|
|
30260
29762
|
if (this.debug) {
|
|
@@ -30265,7 +29767,7 @@ class CustomerServiceSDK {
|
|
|
30265
29767
|
// 保存初始化结果,以便后续获取
|
|
30266
29768
|
this.initResult = initResult;
|
|
30267
29769
|
if (this.debug) {
|
|
30268
|
-
console.log('CustomerSDK initialized successfully (
|
|
29770
|
+
console.log('CustomerSDK initialized successfully (icon + screenshot only)');
|
|
30269
29771
|
}
|
|
30270
29772
|
// 返回初始化信息
|
|
30271
29773
|
return initResult;
|
|
@@ -30279,10 +29781,6 @@ class CustomerServiceSDK {
|
|
|
30279
29781
|
this.iconManager.hide();
|
|
30280
29782
|
this.iconManager = null;
|
|
30281
29783
|
}
|
|
30282
|
-
if (this.iframeManager) {
|
|
30283
|
-
this.iframeManager.destroy();
|
|
30284
|
-
this.iframeManager = null;
|
|
30285
|
-
}
|
|
30286
29784
|
if (this.screenshotManager) {
|
|
30287
29785
|
this.screenshotManager.destroy();
|
|
30288
29786
|
this.screenshotManager = null;
|
|
@@ -30329,29 +29827,10 @@ class CustomerServiceSDK {
|
|
|
30329
29827
|
this.iconManager?.setStyle(style);
|
|
30330
29828
|
}
|
|
30331
29829
|
/**
|
|
30332
|
-
*
|
|
29830
|
+
* 设置图标点击回调
|
|
30333
29831
|
*/
|
|
30334
|
-
|
|
30335
|
-
|
|
30336
|
-
this.clearNotification();
|
|
30337
|
-
this.iframeManager?.open();
|
|
30338
|
-
}
|
|
30339
|
-
closeChat() {
|
|
30340
|
-
// 关闭iframe时,清理图标拖动事件监听器(防止页面无法操作)
|
|
30341
|
-
this.iconManager?.forceCleanupDragEvents();
|
|
30342
|
-
this.iframeManager?.close();
|
|
30343
|
-
}
|
|
30344
|
-
/**
|
|
30345
|
-
* 检查聊天窗口是否打开
|
|
30346
|
-
*/
|
|
30347
|
-
isChatOpen() {
|
|
30348
|
-
return this.iframeManager?.isIframeOpen() || false;
|
|
30349
|
-
}
|
|
30350
|
-
/**
|
|
30351
|
-
* 向iframe发送消息(传递用户数据等)
|
|
30352
|
-
*/
|
|
30353
|
-
sendToIframe(data) {
|
|
30354
|
-
this.iframeManager?.sendToIframe(data);
|
|
29832
|
+
onIconClick(callback) {
|
|
29833
|
+
this.iconManager?.onClick(callback);
|
|
30355
29834
|
}
|
|
30356
29835
|
/**
|
|
30357
29836
|
* 获取连接状态
|
|
@@ -30443,40 +29922,13 @@ class CustomerServiceSDK {
|
|
|
30443
29922
|
console.log('📸 截图配置已更新:', options);
|
|
30444
29923
|
}
|
|
30445
29924
|
}
|
|
30446
|
-
/**
|
|
30447
|
-
* 更新 token(用于用户登录/退出场景)
|
|
30448
|
-
* 如果已初始化,会重新创建 iframe 并更新 URL
|
|
30449
|
-
* @param token 新的 token(传空字符串或 undefined 表示移除 token)
|
|
30450
|
-
* @param options UI选项(可选,用于重新初始化时的配置)
|
|
30451
|
-
* @returns 返回更新后的初始化信息
|
|
30452
|
-
*/
|
|
30453
|
-
async updateToken(token, options) {
|
|
30454
|
-
if (!this.isInitialized) {
|
|
30455
|
-
throw new Error('SDK not initialized. Call init() first.');
|
|
30456
|
-
}
|
|
30457
|
-
if (!this.config) {
|
|
30458
|
-
throw new Error('SDK config not found');
|
|
30459
|
-
}
|
|
30460
|
-
// 更新配置中的 token
|
|
30461
|
-
const updatedConfig = {
|
|
30462
|
-
...this.config,
|
|
30463
|
-
token: token && token.trim() !== '' ? token : undefined
|
|
30464
|
-
};
|
|
30465
|
-
if (this.debug) {
|
|
30466
|
-
console.log('Updating token:', token ? 'Token provided' : 'Token removed');
|
|
30467
|
-
}
|
|
30468
|
-
// 强制重新初始化以应用新的 token
|
|
30469
|
-
return await this.init(updatedConfig, options, true);
|
|
30470
|
-
}
|
|
30471
29925
|
/**
|
|
30472
29926
|
* 销毁 SDK
|
|
30473
29927
|
*/
|
|
30474
29928
|
destroy() {
|
|
30475
29929
|
this.iconManager?.hide();
|
|
30476
|
-
this.iframeManager?.destroy(); // 使用 destroy 而不是 close,确保完全清理
|
|
30477
29930
|
this.screenshotManager?.destroy();
|
|
30478
29931
|
this.iconManager = null;
|
|
30479
|
-
this.iframeManager = null;
|
|
30480
29932
|
this.screenshotManager = null;
|
|
30481
29933
|
this.config = null;
|
|
30482
29934
|
this.initResult = null;
|
|
@@ -30561,26 +30013,6 @@ class CustomerServiceSDK {
|
|
|
30561
30013
|
getReferrer(config) {
|
|
30562
30014
|
return config.referrer || document.referrer || document.location.href;
|
|
30563
30015
|
}
|
|
30564
|
-
/**
|
|
30565
|
-
* 构建iframe URL(带用户参数和设备ID)
|
|
30566
|
-
*/
|
|
30567
|
-
buildIframeUrl(config, deviceId) {
|
|
30568
|
-
const baseUrl = config.iframeUrl;
|
|
30569
|
-
if (!baseUrl || baseUrl.trim() === '') {
|
|
30570
|
-
throw new Error('iframeUrl is required but not provided or is empty');
|
|
30571
|
-
}
|
|
30572
|
-
const url = new URL(baseUrl);
|
|
30573
|
-
// 添加用户参数(只在有值时才添加)
|
|
30574
|
-
if (config.agent && config.agent.trim() !== '') {
|
|
30575
|
-
url.searchParams.set('Agent', config.agent);
|
|
30576
|
-
}
|
|
30577
|
-
if (config.token && config.token.trim() !== '') {
|
|
30578
|
-
url.searchParams.set('Authorization', config.token);
|
|
30579
|
-
}
|
|
30580
|
-
url.searchParams.set('DeviceSign', deviceId);
|
|
30581
|
-
url.searchParams.set('Referrer', this.getReferrer(config));
|
|
30582
|
-
return url.toString();
|
|
30583
|
-
}
|
|
30584
30016
|
}
|
|
30585
30017
|
// 创建全局实例
|
|
30586
30018
|
let globalSDKInstance = null;
|
|
@@ -30630,26 +30062,11 @@ const setIconStyle = (style) => {
|
|
|
30630
30062
|
sdk.setIconStyle(style);
|
|
30631
30063
|
};
|
|
30632
30064
|
/**
|
|
30633
|
-
*
|
|
30065
|
+
* 设置图标点击回调
|
|
30634
30066
|
*/
|
|
30635
|
-
const
|
|
30636
|
-
const sdk = getInstance();
|
|
30637
|
-
sdk.openChat();
|
|
30638
|
-
};
|
|
30639
|
-
const closeChat = () => {
|
|
30067
|
+
const onIconClick = (callback) => {
|
|
30640
30068
|
const sdk = getInstance();
|
|
30641
|
-
sdk.
|
|
30642
|
-
};
|
|
30643
|
-
const isChatOpen = () => {
|
|
30644
|
-
const sdk = getInstance();
|
|
30645
|
-
return sdk.isChatOpen();
|
|
30646
|
-
};
|
|
30647
|
-
/**
|
|
30648
|
-
* iframe通信API
|
|
30649
|
-
*/
|
|
30650
|
-
const sendToIframe = (data) => {
|
|
30651
|
-
const sdk = getInstance();
|
|
30652
|
-
sdk.sendToIframe(data);
|
|
30069
|
+
sdk.onIconClick(callback);
|
|
30653
30070
|
};
|
|
30654
30071
|
/**
|
|
30655
30072
|
* 其他API
|
|
@@ -30704,16 +30121,6 @@ const updateScreenshotOptions = (options) => {
|
|
|
30704
30121
|
const sdk = getInstance();
|
|
30705
30122
|
sdk.updateScreenshotOptions(options);
|
|
30706
30123
|
};
|
|
30707
|
-
/**
|
|
30708
|
-
* 更新 token(用于用户登录/退出场景)
|
|
30709
|
-
* @param token 新的 token(传空字符串或 undefined 表示移除 token)
|
|
30710
|
-
* @param options UI选项(可选)
|
|
30711
|
-
* @returns 返回更新后的初始化信息
|
|
30712
|
-
*/
|
|
30713
|
-
const updateToken = async (token, options) => {
|
|
30714
|
-
const sdk = getInstance();
|
|
30715
|
-
return await sdk.updateToken(token, options);
|
|
30716
|
-
};
|
|
30717
30124
|
// 默认导出
|
|
30718
30125
|
var index = {
|
|
30719
30126
|
init,
|
|
@@ -30724,10 +30131,7 @@ var index = {
|
|
|
30724
30131
|
setIconPosition,
|
|
30725
30132
|
setIconCoordinates,
|
|
30726
30133
|
setIconStyle,
|
|
30727
|
-
|
|
30728
|
-
closeChat,
|
|
30729
|
-
isChatOpen,
|
|
30730
|
-
sendToIframe,
|
|
30134
|
+
onIconClick,
|
|
30731
30135
|
getConnectionStatus,
|
|
30732
30136
|
showNotification,
|
|
30733
30137
|
clearNotification,
|
|
@@ -30736,14 +30140,13 @@ var index = {
|
|
|
30736
30140
|
enableScreenshot,
|
|
30737
30141
|
getScreenshotState,
|
|
30738
30142
|
updateScreenshotOptions,
|
|
30739
|
-
updateToken,
|
|
30740
30143
|
destroy
|
|
30741
30144
|
};
|
|
30742
30145
|
|
|
30146
|
+
exports.CustomerSDK = CustomerSDK;
|
|
30743
30147
|
exports.CustomerServiceSDK = CustomerServiceSDK;
|
|
30744
30148
|
exports.captureScreenshot = captureScreenshot;
|
|
30745
30149
|
exports.clearNotification = clearNotification;
|
|
30746
|
-
exports.closeChat = closeChat;
|
|
30747
30150
|
exports.default = index;
|
|
30748
30151
|
exports.destroy = destroy;
|
|
30749
30152
|
exports.enableScreenshot = enableScreenshot;
|
|
@@ -30753,9 +30156,7 @@ exports.getInstance = getInstance;
|
|
|
30753
30156
|
exports.getScreenshotState = getScreenshotState;
|
|
30754
30157
|
exports.hideIcon = hideIcon;
|
|
30755
30158
|
exports.init = init;
|
|
30756
|
-
exports.
|
|
30757
|
-
exports.openChat = openChat;
|
|
30758
|
-
exports.sendToIframe = sendToIframe;
|
|
30159
|
+
exports.onIconClick = onIconClick;
|
|
30759
30160
|
exports.setIconCoordinates = setIconCoordinates;
|
|
30760
30161
|
exports.setIconPosition = setIconPosition;
|
|
30761
30162
|
exports.setIconStyle = setIconStyle;
|
|
@@ -30763,4 +30164,3 @@ exports.setScreenshotTarget = setScreenshotTarget;
|
|
|
30763
30164
|
exports.showIcon = showIcon;
|
|
30764
30165
|
exports.showNotification = showNotification;
|
|
30765
30166
|
exports.updateScreenshotOptions = updateScreenshotOptions;
|
|
30766
|
-
exports.updateToken = updateToken;
|