customer-chat-sdk 1.1.1 → 1.1.3
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/dist/core/CustomerSDK.d.ts +1 -0
- package/dist/core/CustomerSDK.d.ts.map +1 -1
- package/dist/core/IconManager.d.ts +6 -1
- package/dist/core/IconManager.d.ts.map +1 -1
- package/dist/core/IframeManager.d.ts +1 -0
- package/dist/core/IframeManager.d.ts.map +1 -1
- package/dist/core/ScreenshotManager.d.ts +1 -1
- package/dist/core/ScreenshotManager.d.ts.map +1 -1
- package/dist/customer-sdk.cjs.js +253 -146
- package/dist/customer-sdk.esm.js +253 -146
- package/dist/customer-sdk.min.js +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/customer-sdk.cjs.js
CHANGED
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
5
5
|
// 直接使用base64字符串,避免打包后路径问题
|
|
6
6
|
const iconImage = 'data:image/png;base64,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';
|
|
7
7
|
class IconManager {
|
|
8
|
-
constructor(position, debug = false) {
|
|
8
|
+
constructor(position, debug = false, target) {
|
|
9
9
|
this.iconElement = null;
|
|
10
10
|
this.badgeElement = null;
|
|
11
11
|
this.onClickCallback = null;
|
|
@@ -23,8 +23,11 @@ class IconManager {
|
|
|
23
23
|
this.iconPosition = null; // 图标位置配置
|
|
24
24
|
this.debug = false; // debug 模式标志
|
|
25
25
|
this.isClickEnabled = true; // 是否允许点击(iframe 打开时禁用)
|
|
26
|
+
this.target = null; // 图标传送目标元素(可以是 HTMLElement 或选择器字符串)
|
|
26
27
|
this.iconPosition = position || null;
|
|
27
28
|
this.debug = debug;
|
|
29
|
+
// 保存 target(可以是 HTMLElement 或字符串选择器)
|
|
30
|
+
this.target = target || null;
|
|
28
31
|
}
|
|
29
32
|
/**
|
|
30
33
|
* 显示悬浮图标
|
|
@@ -123,8 +126,18 @@ class IconManager {
|
|
|
123
126
|
this.iconElement.appendChild(imgContainer);
|
|
124
127
|
// 添加拖动和点击事件
|
|
125
128
|
this.setupDragEvents();
|
|
126
|
-
//
|
|
127
|
-
|
|
129
|
+
// 添加到目标元素(如果 target 是字符串,需要重新查找,因为可能在初始化时元素还不存在)
|
|
130
|
+
const targetElement = this.getTargetElement();
|
|
131
|
+
if (targetElement) {
|
|
132
|
+
targetElement.appendChild(this.iconElement);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
// 如果目标元素不存在,回退到 document.body
|
|
136
|
+
document.body.appendChild(this.iconElement);
|
|
137
|
+
if (this.debug) {
|
|
138
|
+
console.warn('Target element not found, icon added to document.body');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
128
141
|
if (this.debug) {
|
|
129
142
|
console.log('CustomerSDK icon displayed');
|
|
130
143
|
}
|
|
@@ -497,6 +510,44 @@ class IconManager {
|
|
|
497
510
|
this.iconElement.style.cursor = 'pointer';
|
|
498
511
|
}
|
|
499
512
|
}
|
|
513
|
+
/**
|
|
514
|
+
* 获取目标元素(支持动态查找)
|
|
515
|
+
*/
|
|
516
|
+
getTargetElement() {
|
|
517
|
+
if (!this.target) {
|
|
518
|
+
return document.body;
|
|
519
|
+
}
|
|
520
|
+
// 如果 target 是字符串选择器,每次都需要重新查找(支持动态元素)
|
|
521
|
+
if (typeof this.target === 'string') {
|
|
522
|
+
const element = document.querySelector(this.target);
|
|
523
|
+
if (element) {
|
|
524
|
+
return element;
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
// 如果元素不存在,回退到 document.body
|
|
528
|
+
if (this.debug) {
|
|
529
|
+
console.warn(`Target element not found: ${this.target}, falling back to document.body`);
|
|
530
|
+
}
|
|
531
|
+
return document.body;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
// 如果 target 是 HTMLElement
|
|
535
|
+
if (this.target instanceof HTMLElement) {
|
|
536
|
+
// 检查元素是否还在 DOM 中
|
|
537
|
+
if (document.body.contains(this.target)) {
|
|
538
|
+
return this.target;
|
|
539
|
+
}
|
|
540
|
+
else {
|
|
541
|
+
// 如果元素不在 DOM 中,回退到 document.body
|
|
542
|
+
if (this.debug) {
|
|
543
|
+
console.warn('Target element no longer in DOM, falling back to document.body');
|
|
544
|
+
}
|
|
545
|
+
return document.body;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
// 默认回退到 document.body
|
|
549
|
+
return document.body;
|
|
550
|
+
}
|
|
500
551
|
/**
|
|
501
552
|
* 创建消息徽章(简化版)
|
|
502
553
|
*/
|
|
@@ -576,7 +627,15 @@ class IframeManager {
|
|
|
576
627
|
*/
|
|
577
628
|
async init() {
|
|
578
629
|
try {
|
|
630
|
+
// PC模式:预创建遮罩层(隐藏状态),避免后续移动DOM导致iframe重新加载
|
|
631
|
+
const actualMode = this.getActualMode();
|
|
632
|
+
const isPC = actualMode === 'popup';
|
|
633
|
+
if (isPC) {
|
|
634
|
+
// 创建遮罩层但不立即显示(showImmediately = false)
|
|
635
|
+
this.createOverlay(false);
|
|
636
|
+
}
|
|
579
637
|
// 创建隐藏的iframe(预连接到SSE)
|
|
638
|
+
// 注意:createIframe 会将容器添加到遮罩层(PC模式)或 body(移动端)
|
|
580
639
|
this.createIframe();
|
|
581
640
|
this.isCreated = true;
|
|
582
641
|
if (this.debug) {
|
|
@@ -604,10 +663,30 @@ class IframeManager {
|
|
|
604
663
|
const isPC = actualMode === 'popup';
|
|
605
664
|
// PC模式:创建或显示遮罩层
|
|
606
665
|
if (isPC) {
|
|
607
|
-
|
|
666
|
+
// 如果遮罩层不存在,创建并显示;如果已存在,直接显示
|
|
667
|
+
this.createOverlay(true); // showImmediately = true,立即显示
|
|
608
668
|
}
|
|
609
669
|
// 显示已创建的容器
|
|
670
|
+
// 关键优化:容器在 init() 时已经添加到正确位置,这里只改变样式,不移动 DOM
|
|
671
|
+
// 这样可以避免 iframe 重新加载
|
|
610
672
|
if (this.containerElement) {
|
|
673
|
+
// 确保容器在 DOM 中(理论上已经在 init() 时添加,但为了安全)
|
|
674
|
+
if (!this.containerElement.parentNode) {
|
|
675
|
+
// 如果容器不在 DOM 中(异常情况),根据模式添加到正确位置
|
|
676
|
+
if (isPC && this.overlayElement) {
|
|
677
|
+
// PC模式:确保遮罩层在 DOM 中,然后将容器添加到遮罩层
|
|
678
|
+
if (!this.overlayElement.parentNode) {
|
|
679
|
+
document.body.appendChild(this.overlayElement);
|
|
680
|
+
}
|
|
681
|
+
this.overlayElement.appendChild(this.containerElement);
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
// 移动端模式:直接添加到 body
|
|
685
|
+
document.body.appendChild(this.containerElement);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
// 注意:不再检查容器是否在遮罩层内,因为 init() 时已经正确放置
|
|
689
|
+
// 如果移动容器会导致 iframe 重新加载,所以不移动
|
|
611
690
|
if (isPC) {
|
|
612
691
|
// PC模式:配置为居中弹窗样式
|
|
613
692
|
Object.assign(this.containerElement.style, {
|
|
@@ -619,17 +698,18 @@ class IframeManager {
|
|
|
619
698
|
opacity: '1',
|
|
620
699
|
display: 'block'
|
|
621
700
|
});
|
|
622
|
-
//
|
|
623
|
-
// 只有当容器不在遮罩层内时才移动,且确保遮罩层在 DOM 中
|
|
701
|
+
// 显示遮罩层(确保在 DOM 中)
|
|
624
702
|
if (this.overlayElement) {
|
|
625
|
-
//
|
|
703
|
+
// 确保遮罩层在 DOM 中
|
|
626
704
|
if (!this.overlayElement.parentNode) {
|
|
627
705
|
document.body.appendChild(this.overlayElement);
|
|
628
706
|
}
|
|
629
|
-
//
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
707
|
+
// 显示遮罩层(只改变样式,不移动)
|
|
708
|
+
Object.assign(this.overlayElement.style, {
|
|
709
|
+
visibility: 'visible',
|
|
710
|
+
opacity: '1',
|
|
711
|
+
display: 'flex'
|
|
712
|
+
});
|
|
633
713
|
}
|
|
634
714
|
}
|
|
635
715
|
else {
|
|
@@ -710,11 +790,16 @@ class IframeManager {
|
|
|
710
790
|
*/
|
|
711
791
|
destroy() {
|
|
712
792
|
this.hide();
|
|
793
|
+
// 移除容器和遮罩层
|
|
713
794
|
if (this.containerElement) {
|
|
714
795
|
this.containerElement.remove();
|
|
715
796
|
this.containerElement = null;
|
|
716
797
|
this.iframeElement = null;
|
|
717
798
|
}
|
|
799
|
+
if (this.overlayElement) {
|
|
800
|
+
this.overlayElement.remove();
|
|
801
|
+
this.overlayElement = null;
|
|
802
|
+
}
|
|
718
803
|
this.isCreated = false;
|
|
719
804
|
if (this.debug) {
|
|
720
805
|
console.log('CustomerSDK container destroyed');
|
|
@@ -736,25 +821,23 @@ class IframeManager {
|
|
|
736
821
|
}
|
|
737
822
|
/**
|
|
738
823
|
* 创建遮罩层(PC模式使用)
|
|
824
|
+
* @param showImmediately 是否立即显示,默认 false(用于 init() 时创建但不显示)
|
|
739
825
|
*/
|
|
740
|
-
createOverlay() {
|
|
741
|
-
//
|
|
742
|
-
if (this.overlayElement
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
opacity: '1',
|
|
756
|
-
display: 'flex'
|
|
757
|
-
});
|
|
826
|
+
createOverlay(showImmediately = false) {
|
|
827
|
+
// 如果遮罩层已存在
|
|
828
|
+
if (this.overlayElement) {
|
|
829
|
+
// 如果不在 DOM 中,添加到 DOM
|
|
830
|
+
if (!this.overlayElement.parentNode) {
|
|
831
|
+
document.body.appendChild(this.overlayElement);
|
|
832
|
+
}
|
|
833
|
+
// 根据参数决定是否显示
|
|
834
|
+
if (showImmediately) {
|
|
835
|
+
Object.assign(this.overlayElement.style, {
|
|
836
|
+
visibility: 'visible',
|
|
837
|
+
opacity: '1',
|
|
838
|
+
display: 'flex'
|
|
839
|
+
});
|
|
840
|
+
}
|
|
758
841
|
return;
|
|
759
842
|
}
|
|
760
843
|
// 创建新的遮罩层
|
|
@@ -768,10 +851,12 @@ class IframeManager {
|
|
|
768
851
|
height: '100%',
|
|
769
852
|
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
770
853
|
zIndex: '999998',
|
|
771
|
-
display: 'flex',
|
|
854
|
+
display: showImmediately ? 'flex' : 'none', // 根据参数决定初始显示状态
|
|
772
855
|
alignItems: 'center',
|
|
773
856
|
justifyContent: 'center',
|
|
774
|
-
cursor: this.config.allowClose ? 'pointer' : 'default'
|
|
857
|
+
cursor: this.config.allowClose ? 'pointer' : 'default',
|
|
858
|
+
visibility: showImmediately ? 'visible' : 'hidden',
|
|
859
|
+
opacity: showImmediately ? '1' : '0'
|
|
775
860
|
});
|
|
776
861
|
// 点击遮罩层关闭(只添加一次事件监听器)
|
|
777
862
|
if (this.config.allowClose) {
|
|
@@ -901,8 +986,16 @@ class IframeManager {
|
|
|
901
986
|
this.injectMobileStyles();
|
|
902
987
|
}
|
|
903
988
|
});
|
|
904
|
-
//
|
|
905
|
-
|
|
989
|
+
// 关键优化:PC模式将容器添加到遮罩层(如果遮罩层已创建),避免后续移动DOM导致iframe重新加载
|
|
990
|
+
// 移动端直接添加到body
|
|
991
|
+
if (isPC && this.overlayElement) {
|
|
992
|
+
// PC模式:添加到遮罩层(遮罩层已在 init() 中创建)
|
|
993
|
+
this.overlayElement.appendChild(this.containerElement);
|
|
994
|
+
}
|
|
995
|
+
else {
|
|
996
|
+
// 移动端模式:直接添加到body
|
|
997
|
+
document.body.appendChild(this.containerElement);
|
|
998
|
+
}
|
|
906
999
|
if (this.debug) {
|
|
907
1000
|
console.log('CustomerSDK container created (hidden, ready for SSE)');
|
|
908
1001
|
}
|
|
@@ -14544,7 +14637,7 @@ class ScreenshotManager {
|
|
|
14544
14637
|
useProxy: options.useProxy ?? true, // 默认启用代理(如果配置了proxyUrl)
|
|
14545
14638
|
engine: options.engine ?? 'modern-screenshot',
|
|
14546
14639
|
corsMode: options.corsMode ?? 'canvas-proxy',
|
|
14547
|
-
|
|
14640
|
+
debug: options.debug !== undefined ? options.debug : false, // 默认 false,不输出日志
|
|
14548
14641
|
maxRetries: options.maxRetries ?? 2,
|
|
14549
14642
|
preloadImages: options.preloadImages ?? false, // 默认不预加载,按需加载
|
|
14550
14643
|
maxConcurrentDownloads: options.maxConcurrentDownloads ?? 10, // 增加并发数
|
|
@@ -14564,9 +14657,9 @@ class ScreenshotManager {
|
|
|
14564
14657
|
this.setupMessageListener();
|
|
14565
14658
|
this.setupVisibilityChangeListener();
|
|
14566
14659
|
// 打印初始化信息
|
|
14567
|
-
if (
|
|
14660
|
+
if (this.options.debug) {
|
|
14568
14661
|
console.log('📸 ScreenshotManager 初始化完成');
|
|
14569
|
-
console.log(`📸 配置: interval=${this.options.interval}ms, engine=${this.options.engine},
|
|
14662
|
+
console.log(`📸 配置: interval=${this.options.interval}ms, engine=${this.options.engine}, debug=${this.options.debug}`);
|
|
14570
14663
|
console.log('📸 等待 iframe 发送 checkScreenshot 消息...');
|
|
14571
14664
|
}
|
|
14572
14665
|
// 启动缓存清理定时器
|
|
@@ -14589,7 +14682,7 @@ class ScreenshotManager {
|
|
|
14589
14682
|
if (this.screenshotContext) {
|
|
14590
14683
|
try {
|
|
14591
14684
|
destroyContext(this.screenshotContext);
|
|
14592
|
-
if (
|
|
14685
|
+
if (this.options.debug) {
|
|
14593
14686
|
console.log('📸 目标元素变化,清理 context');
|
|
14594
14687
|
}
|
|
14595
14688
|
}
|
|
@@ -14612,7 +14705,7 @@ class ScreenshotManager {
|
|
|
14612
14705
|
this.handleIframeMessage(event);
|
|
14613
14706
|
};
|
|
14614
14707
|
window.addEventListener('message', this.messageHandler);
|
|
14615
|
-
if (
|
|
14708
|
+
if (this.options.debug) {
|
|
14616
14709
|
console.log('📸 消息监听器已设置,正在监听 iframe 消息...');
|
|
14617
14710
|
}
|
|
14618
14711
|
}
|
|
@@ -14622,12 +14715,12 @@ class ScreenshotManager {
|
|
|
14622
14715
|
setupVisibilityChangeListener() {
|
|
14623
14716
|
document.addEventListener('visibilitychange', () => {
|
|
14624
14717
|
if (document.hidden) {
|
|
14625
|
-
if (
|
|
14718
|
+
if (this.options.debug) {
|
|
14626
14719
|
console.log('📸 页面隐藏,截图轮询已暂停');
|
|
14627
14720
|
}
|
|
14628
14721
|
}
|
|
14629
14722
|
else {
|
|
14630
|
-
if (
|
|
14723
|
+
if (this.options.debug) {
|
|
14631
14724
|
console.log('📸 页面显示,截图轮询已恢复');
|
|
14632
14725
|
}
|
|
14633
14726
|
}
|
|
@@ -14644,7 +14737,7 @@ class ScreenshotManager {
|
|
|
14644
14737
|
}
|
|
14645
14738
|
// 如果提供了发送消息的回调,保存它(用于后续发送二进制数据)
|
|
14646
14739
|
// 注意:消息来源验证在 setupMessageListener 中处理
|
|
14647
|
-
if (
|
|
14740
|
+
if (this.options.debug) {
|
|
14648
14741
|
console.log('📸 [iframe] 收到消息:', event.data);
|
|
14649
14742
|
}
|
|
14650
14743
|
// 尝试解析为二进制配置(新格式)
|
|
@@ -14658,7 +14751,7 @@ class ScreenshotManager {
|
|
|
14658
14751
|
if (isValid) {
|
|
14659
14752
|
// 启用截图功能
|
|
14660
14753
|
if (!this.isEnabled) {
|
|
14661
|
-
if (
|
|
14754
|
+
if (this.options.debug) {
|
|
14662
14755
|
console.log('📸 [iframe] 启用截图功能(二进制模式)');
|
|
14663
14756
|
}
|
|
14664
14757
|
this.isEnabled = true;
|
|
@@ -14668,7 +14761,7 @@ class ScreenshotManager {
|
|
|
14668
14761
|
// 计算剩余有效时间(毫秒)
|
|
14669
14762
|
const remainingTime = binaryConfig.ttl - currentTime;
|
|
14670
14763
|
// 启动或更新截图轮询
|
|
14671
|
-
if (
|
|
14764
|
+
if (this.options.debug) {
|
|
14672
14765
|
const remainingMinutes = Math.ceil(remainingTime / 60000);
|
|
14673
14766
|
console.log(`📸 [iframe] 设置轮询间隔: ${this.dynamicInterval}ms,剩余有效时间: ${remainingMinutes}分钟`);
|
|
14674
14767
|
}
|
|
@@ -14680,7 +14773,7 @@ class ScreenshotManager {
|
|
|
14680
14773
|
this.expirationTimer = null;
|
|
14681
14774
|
}
|
|
14682
14775
|
this.expirationTimer = setTimeout(() => {
|
|
14683
|
-
if (
|
|
14776
|
+
if (this.options.debug) {
|
|
14684
14777
|
console.log('📸 [iframe] 二进制配置已过期,停止截图');
|
|
14685
14778
|
}
|
|
14686
14779
|
this.stopScreenshot();
|
|
@@ -14691,7 +14784,7 @@ class ScreenshotManager {
|
|
|
14691
14784
|
}
|
|
14692
14785
|
else {
|
|
14693
14786
|
// 禁用截图功能(ttl == 0 或已过期)
|
|
14694
|
-
if (
|
|
14787
|
+
if (this.options.debug) {
|
|
14695
14788
|
if (binaryConfig.ttl === 0) {
|
|
14696
14789
|
console.log('📸 [iframe] ttl == 0,禁用截图功能');
|
|
14697
14790
|
}
|
|
@@ -14710,11 +14803,15 @@ class ScreenshotManager {
|
|
|
14710
14803
|
return;
|
|
14711
14804
|
}
|
|
14712
14805
|
// 如果不是二进制配置格式,记录错误
|
|
14713
|
-
|
|
14806
|
+
if (this.options.debug) {
|
|
14807
|
+
console.error('📸 [iframe] 解析配置失败:未识别的配置格式');
|
|
14808
|
+
}
|
|
14714
14809
|
this.uploadError = '解析配置失败:仅支持二进制配置格式';
|
|
14715
14810
|
}
|
|
14716
14811
|
catch (error) {
|
|
14717
|
-
|
|
14812
|
+
if (this.options.debug) {
|
|
14813
|
+
console.error('📸 [iframe] 处理消息失败:', error);
|
|
14814
|
+
}
|
|
14718
14815
|
this.uploadError = error instanceof Error ? error.message : String(error);
|
|
14719
14816
|
}
|
|
14720
14817
|
}
|
|
@@ -14753,17 +14850,19 @@ class ScreenshotManager {
|
|
|
14753
14850
|
*/
|
|
14754
14851
|
startScreenshot(customInterval) {
|
|
14755
14852
|
if (!this.isEnabled) {
|
|
14756
|
-
|
|
14853
|
+
if (this.options.debug) {
|
|
14854
|
+
console.warn('📸 截图功能已禁用,无法启动');
|
|
14855
|
+
}
|
|
14757
14856
|
return;
|
|
14758
14857
|
}
|
|
14759
14858
|
const currentInterval = customInterval || this.dynamicInterval || this.options.interval;
|
|
14760
14859
|
if (this.isRunning) {
|
|
14761
|
-
if (
|
|
14860
|
+
if (this.options.debug) {
|
|
14762
14861
|
console.log(`📸 更新轮询间隔: ${currentInterval}ms`);
|
|
14763
14862
|
}
|
|
14764
14863
|
this.stopScreenshot();
|
|
14765
14864
|
}
|
|
14766
|
-
if (
|
|
14865
|
+
if (this.options.debug) {
|
|
14767
14866
|
console.log(`📸 开始轮询截图,间隔: ${currentInterval}ms`);
|
|
14768
14867
|
}
|
|
14769
14868
|
this.isRunning = true;
|
|
@@ -14776,7 +14875,7 @@ class ScreenshotManager {
|
|
|
14776
14875
|
const scheduleNext = async () => {
|
|
14777
14876
|
// 如果上次任务还没完成,等待完成
|
|
14778
14877
|
if (!this.isCurrentTaskCompleted) {
|
|
14779
|
-
if (
|
|
14878
|
+
if (this.options.debug) {
|
|
14780
14879
|
console.log('📸 [定时] 等待上次任务完成...');
|
|
14781
14880
|
}
|
|
14782
14881
|
// 每100ms检查一次任务是否完成
|
|
@@ -14796,7 +14895,7 @@ class ScreenshotManager {
|
|
|
14796
14895
|
this.isCurrentTaskCompleted = false;
|
|
14797
14896
|
// 记录定时开始时间
|
|
14798
14897
|
const scheduleStartTime = performance.now();
|
|
14799
|
-
if (
|
|
14898
|
+
if (this.options.debug) {
|
|
14800
14899
|
console.log(`📸 [定时开始] 开始新一轮截图任务`);
|
|
14801
14900
|
}
|
|
14802
14901
|
try {
|
|
@@ -14828,7 +14927,7 @@ class ScreenshotManager {
|
|
|
14828
14927
|
const combinedBufferSize = combinedBuffer.byteLength;
|
|
14829
14928
|
const combineTime = performance.now() - combineStartTime;
|
|
14830
14929
|
// 打印大小信息
|
|
14831
|
-
if (
|
|
14930
|
+
if (this.options.debug) {
|
|
14832
14931
|
console.log('📸 [轮询-大小统计]');
|
|
14833
14932
|
console.log(` Base64 大小: ${base64Size} 字符`);
|
|
14834
14933
|
console.log(` 图片字节大小: ${(imageBufferSize / 1024).toFixed(2)} KB (${imageBufferSize} 字节)`);
|
|
@@ -14849,7 +14948,7 @@ class ScreenshotManager {
|
|
|
14849
14948
|
const sendCallbackTime = performance.now() - sendCallbackStartTime;
|
|
14850
14949
|
const totalSendTime = performance.now() - sendStartTime;
|
|
14851
14950
|
const totalTime = performance.now() - scheduleStartTime;
|
|
14852
|
-
if (
|
|
14951
|
+
if (this.options.debug) {
|
|
14853
14952
|
console.log('📸 [轮询] ✅ 二进制数据已发送到 iframe');
|
|
14854
14953
|
console.log(` ⏱️ 发送回调耗时: ${sendCallbackTime.toFixed(2)}ms`);
|
|
14855
14954
|
console.log(` ⏱️ 发送阶段总耗时: ${totalSendTime.toFixed(2)}ms`);
|
|
@@ -14858,7 +14957,9 @@ class ScreenshotManager {
|
|
|
14858
14957
|
}
|
|
14859
14958
|
}
|
|
14860
14959
|
catch (error) {
|
|
14861
|
-
|
|
14960
|
+
if (this.options.debug) {
|
|
14961
|
+
console.error('📸 [轮询] ❌ 处理二进制数据失败:', error);
|
|
14962
|
+
}
|
|
14862
14963
|
}
|
|
14863
14964
|
}
|
|
14864
14965
|
// 任务完成(无压缩模式)
|
|
@@ -14867,7 +14968,7 @@ class ScreenshotManager {
|
|
|
14867
14968
|
else if (this.currentBinaryConfig && this.options.compress) {
|
|
14868
14969
|
// 启用了压缩,等待 Worker 压缩完成后在 onmessage 中发送
|
|
14869
14970
|
// 任务完成标志会在压缩完成的回调中设置
|
|
14870
|
-
if (
|
|
14971
|
+
if (this.options.debug) {
|
|
14871
14972
|
console.log('📸 [轮询] 等待 Worker 压缩完成后发送到 iframe...');
|
|
14872
14973
|
}
|
|
14873
14974
|
}
|
|
@@ -14877,7 +14978,7 @@ class ScreenshotManager {
|
|
|
14877
14978
|
}
|
|
14878
14979
|
}
|
|
14879
14980
|
catch (error) {
|
|
14880
|
-
if (
|
|
14981
|
+
if (this.options.debug) {
|
|
14881
14982
|
console.error('📸 [轮询] 截图失败:', error);
|
|
14882
14983
|
}
|
|
14883
14984
|
// 任务失败,标记为完成
|
|
@@ -14902,7 +15003,7 @@ class ScreenshotManager {
|
|
|
14902
15003
|
if (!this.isRunning) {
|
|
14903
15004
|
return;
|
|
14904
15005
|
}
|
|
14905
|
-
if (
|
|
15006
|
+
if (this.options.debug) {
|
|
14906
15007
|
console.log('📸 停止轮询截图');
|
|
14907
15008
|
}
|
|
14908
15009
|
this.isRunning = false;
|
|
@@ -14919,7 +15020,9 @@ class ScreenshotManager {
|
|
|
14919
15020
|
*/
|
|
14920
15021
|
async captureOnce(force = false) {
|
|
14921
15022
|
if (!this.isEnabled && !force) {
|
|
14922
|
-
|
|
15023
|
+
if (this.options.debug) {
|
|
15024
|
+
console.warn('📸 截图功能已禁用,无法执行截图。如需测试,请先调用 enable(true) 启用截图功能');
|
|
15025
|
+
}
|
|
14923
15026
|
return false;
|
|
14924
15027
|
}
|
|
14925
15028
|
return await this.takeScreenshot();
|
|
@@ -14929,14 +15032,16 @@ class ScreenshotManager {
|
|
|
14929
15032
|
*/
|
|
14930
15033
|
async takeScreenshot(scheduleStartTime) {
|
|
14931
15034
|
if (!this.targetElement) {
|
|
14932
|
-
|
|
15035
|
+
if (this.options.debug) {
|
|
15036
|
+
console.warn('📸 目标元素不存在');
|
|
15037
|
+
}
|
|
14933
15038
|
return false;
|
|
14934
15039
|
}
|
|
14935
15040
|
// 记录截图开始时间
|
|
14936
15041
|
const screenshotStartTime = performance.now();
|
|
14937
15042
|
this.setupGlobalErrorHandlers();
|
|
14938
15043
|
try {
|
|
14939
|
-
if (
|
|
15044
|
+
if (this.options.debug) {
|
|
14940
15045
|
console.log(`📸 开始截图 #${this.screenshotCount + 1}...`);
|
|
14941
15046
|
if (scheduleStartTime) {
|
|
14942
15047
|
const waitTime = screenshotStartTime - scheduleStartTime;
|
|
@@ -14950,7 +15055,7 @@ class ScreenshotManager {
|
|
|
14950
15055
|
this.waitForFonts()
|
|
14951
15056
|
]);
|
|
14952
15057
|
const waitStylesTime = performance.now() - waitStylesStartTime;
|
|
14953
|
-
if (
|
|
15058
|
+
if (this.options.debug) {
|
|
14954
15059
|
console.log(` ⏱️ 等待样式和字体加载耗时: ${waitStylesTime.toFixed(2)}ms`);
|
|
14955
15060
|
}
|
|
14956
15061
|
// 等待元素完全渲染(特别是对于 modern-screenshot)
|
|
@@ -14959,12 +15064,12 @@ class ScreenshotManager {
|
|
|
14959
15064
|
requestAnimationFrame(() => resolve());
|
|
14960
15065
|
}));
|
|
14961
15066
|
const waitRenderTime = performance.now() - waitRenderStartTime;
|
|
14962
|
-
if (
|
|
15067
|
+
if (this.options.debug) {
|
|
14963
15068
|
console.log(` ⏱️ 等待渲染完成耗时: ${waitRenderTime.toFixed(2)}ms`);
|
|
14964
15069
|
}
|
|
14965
15070
|
// 选择截图引擎
|
|
14966
15071
|
const selectedEngine = this.options.engine || 'modern-screenshot';
|
|
14967
|
-
if (
|
|
15072
|
+
if (this.options.debug) {
|
|
14968
15073
|
console.log(`📸 使用截图引擎: ${selectedEngine}`);
|
|
14969
15074
|
}
|
|
14970
15075
|
// 优化:如果启用预加载,才预处理图片;否则让引擎按需加载
|
|
@@ -15004,7 +15109,7 @@ class ScreenshotManager {
|
|
|
15004
15109
|
dataUrl = await this.takeScreenshotWithModernScreenshot(this.targetElement);
|
|
15005
15110
|
}
|
|
15006
15111
|
const engineTime = performance.now() - engineStartTime;
|
|
15007
|
-
if (
|
|
15112
|
+
if (this.options.debug) {
|
|
15008
15113
|
console.log(` ⏱️ 截图引擎执行耗时: ${engineTime.toFixed(2)}ms`);
|
|
15009
15114
|
}
|
|
15010
15115
|
const timestamp = Date.now();
|
|
@@ -15018,7 +15123,7 @@ class ScreenshotManager {
|
|
|
15018
15123
|
const removed = this.screenshotHistory.shift();
|
|
15019
15124
|
// 强制 GC(如果可能)
|
|
15020
15125
|
if (removed && removed.length > 1000000) { // 大于1MB的字符串
|
|
15021
|
-
if (
|
|
15126
|
+
if (this.options.debug) {
|
|
15022
15127
|
console.log(`📸 清理旧截图,释放内存: ${Math.round(removed.length * 0.75 / 1024)} KB`);
|
|
15023
15128
|
}
|
|
15024
15129
|
}
|
|
@@ -15032,7 +15137,7 @@ class ScreenshotManager {
|
|
|
15032
15137
|
if (removed) {
|
|
15033
15138
|
const removedSize = removed.length;
|
|
15034
15139
|
totalSize -= removedSize;
|
|
15035
|
-
if (
|
|
15140
|
+
if (this.options.debug) {
|
|
15036
15141
|
console.warn(`📸 ⚠️ 历史记录总大小超过限制,清理最旧截图: ${Math.round(removedSize * 0.75 / 1024)} KB`);
|
|
15037
15142
|
}
|
|
15038
15143
|
}
|
|
@@ -15044,7 +15149,7 @@ class ScreenshotManager {
|
|
|
15044
15149
|
const screenshotTotalTime = performance.now() - screenshotStartTime;
|
|
15045
15150
|
// 打印基本信息
|
|
15046
15151
|
const base64Data = dataUrl.split(',')[1] || '';
|
|
15047
|
-
if (
|
|
15152
|
+
if (this.options.debug) {
|
|
15048
15153
|
console.log('📸 截图完成:');
|
|
15049
15154
|
console.log(`📸 编号: #${this.screenshotCount}`);
|
|
15050
15155
|
console.log(`📸 时间: ${new Date(timestamp).toLocaleTimeString()}`);
|
|
@@ -15063,7 +15168,7 @@ class ScreenshotManager {
|
|
|
15063
15168
|
// 确保 Worker 已创建
|
|
15064
15169
|
if (!this.worker) {
|
|
15065
15170
|
this.worker = this.createWorker();
|
|
15066
|
-
if (
|
|
15171
|
+
if (this.options.debug) {
|
|
15067
15172
|
if (this.worker) {
|
|
15068
15173
|
console.log('📸 Worker 已创建,准备压缩');
|
|
15069
15174
|
}
|
|
@@ -15075,7 +15180,7 @@ class ScreenshotManager {
|
|
|
15075
15180
|
if (this.worker) {
|
|
15076
15181
|
// 记录压缩开始时间
|
|
15077
15182
|
const compressStartTime = performance.now();
|
|
15078
|
-
if (
|
|
15183
|
+
if (this.options.debug) {
|
|
15079
15184
|
console.log('📸 发送到 WebWorker 进行压缩...');
|
|
15080
15185
|
}
|
|
15081
15186
|
// 保存原始 dataUrl 用于后续对比(在 Worker 压缩完成后)
|
|
@@ -15098,7 +15203,7 @@ class ScreenshotManager {
|
|
|
15098
15203
|
}
|
|
15099
15204
|
else {
|
|
15100
15205
|
// Worker 不可用,如果配置了二进制模式,直接发送原始截图
|
|
15101
|
-
if (
|
|
15206
|
+
if (this.options.debug) {
|
|
15102
15207
|
console.warn('📸 ⚠️ Worker 不可用,跳过压缩(使用原始截图)');
|
|
15103
15208
|
}
|
|
15104
15209
|
// Worker 不可用时,如果配置了二进制模式,立即发送原始截图
|
|
@@ -15114,7 +15219,7 @@ class ScreenshotManager {
|
|
|
15114
15219
|
data: combinedBuffer
|
|
15115
15220
|
};
|
|
15116
15221
|
this.sendToIframeCallback(message);
|
|
15117
|
-
if (
|
|
15222
|
+
if (this.options.debug) {
|
|
15118
15223
|
console.log('📸 [Worker 不可用] ✅ 原始截图已发送到 iframe');
|
|
15119
15224
|
}
|
|
15120
15225
|
}
|
|
@@ -15139,7 +15244,7 @@ class ScreenshotManager {
|
|
|
15139
15244
|
console.error('📸 截图失败:', err);
|
|
15140
15245
|
this.error = errorMessage;
|
|
15141
15246
|
}
|
|
15142
|
-
else if (
|
|
15247
|
+
else if (this.options.debug) {
|
|
15143
15248
|
console.warn('📸 截图遇到跨域问题(已忽略)');
|
|
15144
15249
|
}
|
|
15145
15250
|
return false;
|
|
@@ -15156,7 +15261,7 @@ class ScreenshotManager {
|
|
|
15156
15261
|
* 注意:snapdom 内部使用 worker 进行截图处理,会在后台线程执行,不会阻塞主线程
|
|
15157
15262
|
*/
|
|
15158
15263
|
async takeScreenshotWithSnapdom(element) {
|
|
15159
|
-
if (
|
|
15264
|
+
if (this.options.debug) {
|
|
15160
15265
|
console.log('📸 使用 snapdom 引擎截图...');
|
|
15161
15266
|
}
|
|
15162
15267
|
// 限制只截图可见区域(viewport),避免截图不可见区域
|
|
@@ -15196,7 +15301,7 @@ class ScreenshotManager {
|
|
|
15196
15301
|
// 简化方案:直接使用 body,但添加尺寸限制选项(如果 snapdom 支持)
|
|
15197
15302
|
// 如果不支持,则只能截图整个 body
|
|
15198
15303
|
targetElement = element;
|
|
15199
|
-
if (
|
|
15304
|
+
if (this.options.debug) {
|
|
15200
15305
|
console.log(`📸 注意:snapdom 将截图整个 body,建议使用 html2canvas 或 modern-screenshot 来限制可见区域`);
|
|
15201
15306
|
console.log(`📸 可见区域尺寸: ${window.innerWidth}x${window.innerHeight}`);
|
|
15202
15307
|
}
|
|
@@ -15213,7 +15318,7 @@ class ScreenshotManager {
|
|
|
15213
15318
|
elementRect.left >= 0 &&
|
|
15214
15319
|
elementRect.bottom <= window.innerHeight &&
|
|
15215
15320
|
elementRect.right <= window.innerWidth;
|
|
15216
|
-
if (!isFullyVisible &&
|
|
15321
|
+
if (!isFullyVisible && this.options.debug) {
|
|
15217
15322
|
console.warn(`📸 ⚠️ 元素部分不可见,snapdom 可能会截图整个元素(包括不可见部分)`);
|
|
15218
15323
|
console.warn(`📸 建议:使用 html2canvas 或 modern-screenshot 来限制可见区域`);
|
|
15219
15324
|
}
|
|
@@ -15231,12 +15336,12 @@ class ScreenshotManager {
|
|
|
15231
15336
|
proxyUrl = proxyUrl.endsWith('?') ? proxyUrl + 'url=' : proxyUrl + '?url=';
|
|
15232
15337
|
}
|
|
15233
15338
|
options.useProxy = proxyUrl;
|
|
15234
|
-
if (
|
|
15339
|
+
if (this.options.debug) {
|
|
15235
15340
|
console.log(`📸 使用代理服务器处理跨域图片: ${proxyUrl}`);
|
|
15236
15341
|
}
|
|
15237
15342
|
}
|
|
15238
15343
|
else {
|
|
15239
|
-
if (
|
|
15344
|
+
if (this.options.debug) {
|
|
15240
15345
|
if (!this.options.useProxy) {
|
|
15241
15346
|
console.log('📸 代理功能已禁用(useProxy: false)');
|
|
15242
15347
|
}
|
|
@@ -15278,7 +15383,7 @@ class ScreenshotManager {
|
|
|
15278
15383
|
parent.removeChild(container);
|
|
15279
15384
|
}
|
|
15280
15385
|
}
|
|
15281
|
-
if (
|
|
15386
|
+
if (this.options.debug) {
|
|
15282
15387
|
console.log(`📸 snapdom 截图成功!格式: ${outputFormat}, 尺寸: ${img.width}x${img.height}`);
|
|
15283
15388
|
}
|
|
15284
15389
|
return dataUrl;
|
|
@@ -15296,14 +15401,14 @@ class ScreenshotManager {
|
|
|
15296
15401
|
const errorName = error instanceof Error ? error.name : 'Unknown';
|
|
15297
15402
|
// 针对不同类型的错误给出具体提示
|
|
15298
15403
|
if (errorName === 'EncodingError' || errorMessage.includes('cannot be decoded')) {
|
|
15299
|
-
if (
|
|
15404
|
+
if (this.options.debug) {
|
|
15300
15405
|
console.warn('📸 ⚠️ 图片解码失败 - 这通常是因为跨域图片无法访问');
|
|
15301
15406
|
console.warn('📸 💡 解决方案:配置 proxyUrl 选项');
|
|
15302
15407
|
console.warn('📸 📖 参考: https://snapdom.dev/#cors');
|
|
15303
15408
|
}
|
|
15304
15409
|
}
|
|
15305
15410
|
else if (errorMessage.includes('CORS') || errorMessage.includes('cross-origin')) {
|
|
15306
|
-
if (
|
|
15411
|
+
if (this.options.debug) {
|
|
15307
15412
|
console.warn('📸 ⚠️ 检测到 CORS 错误,建议配置 proxyUrl 选项');
|
|
15308
15413
|
}
|
|
15309
15414
|
}
|
|
@@ -15328,7 +15433,7 @@ class ScreenshotManager {
|
|
|
15328
15433
|
* - 需要快速截图
|
|
15329
15434
|
*/
|
|
15330
15435
|
async takeScreenshotWithHtml2Canvas(element) {
|
|
15331
|
-
if (
|
|
15436
|
+
if (this.options.debug) {
|
|
15332
15437
|
console.log('📸 使用 html2canvas 引擎截图...');
|
|
15333
15438
|
}
|
|
15334
15439
|
try {
|
|
@@ -15382,7 +15487,7 @@ class ScreenshotManager {
|
|
|
15382
15487
|
: (isMobile ? 0.5 : 0.6), // 用户未配置,使用默认值
|
|
15383
15488
|
useCORS: this.options.enableCORS,
|
|
15384
15489
|
allowTaint: !this.options.enableCORS, // 如果启用 CORS,不允许 taint
|
|
15385
|
-
logging:
|
|
15490
|
+
logging: this.options.debug, // 使用配置的静默模式
|
|
15386
15491
|
// foreignObjectRendering: true, // ❌ 移除:可能导致跨域图片不显示
|
|
15387
15492
|
// removeContainer: true, // ❌ 移除:移到后面,避免重复定义
|
|
15388
15493
|
// 不设置 width 和 height,让 html2canvas 自动计算
|
|
@@ -15520,12 +15625,12 @@ class ScreenshotManager {
|
|
|
15520
15625
|
}
|
|
15521
15626
|
catch (e) {
|
|
15522
15627
|
// 忽略内联化错误
|
|
15523
|
-
if (
|
|
15628
|
+
if (this.options.debug) {
|
|
15524
15629
|
console.warn('📸 iOS 样式内联化失败:', e);
|
|
15525
15630
|
}
|
|
15526
15631
|
}
|
|
15527
15632
|
}
|
|
15528
|
-
if (
|
|
15633
|
+
if (this.options.debug) {
|
|
15529
15634
|
const styleLinks = clonedDoc.querySelectorAll('link[rel="stylesheet"]').length;
|
|
15530
15635
|
const styleTags = clonedDoc.querySelectorAll('style').length;
|
|
15531
15636
|
console.log(`📸 onclone: 已复制 ${styleLinks} 个样式表链接和 ${styleTags} 个内联样式标签${isIOS ? ' (iOS 模式:已内联化计算样式)' : ''}`);
|
|
@@ -15574,7 +15679,7 @@ class ScreenshotManager {
|
|
|
15574
15679
|
const cachedDataUrl = this.getCachedImage(originalSrc);
|
|
15575
15680
|
if (cachedDataUrl) {
|
|
15576
15681
|
img.src = cachedDataUrl;
|
|
15577
|
-
if (
|
|
15682
|
+
if (this.options.debug) {
|
|
15578
15683
|
console.log(`📸 使用缓存的图片: ${originalSrc.substring(0, 50)}...`);
|
|
15579
15684
|
}
|
|
15580
15685
|
return;
|
|
@@ -15583,7 +15688,7 @@ class ScreenshotManager {
|
|
|
15583
15688
|
// 构建代理 URL
|
|
15584
15689
|
try {
|
|
15585
15690
|
if (!this.options.proxyUrl) {
|
|
15586
|
-
if (
|
|
15691
|
+
if (this.options.debug) {
|
|
15587
15692
|
console.warn(`📸 ⚠️ 未配置代理 URL,跨域图片可能无法显示: ${originalSrc}`);
|
|
15588
15693
|
}
|
|
15589
15694
|
return;
|
|
@@ -15596,19 +15701,19 @@ class ScreenshotManager {
|
|
|
15596
15701
|
baseUrl = baseUrl.replace(/[?&]$/, '');
|
|
15597
15702
|
const proxyUrl = `${baseUrl}?${params.toString()}`;
|
|
15598
15703
|
img.src = proxyUrl;
|
|
15599
|
-
if (
|
|
15704
|
+
if (this.options.debug) {
|
|
15600
15705
|
console.log(`📸 使用代理 URL 替换跨域图片: ${originalSrc.substring(0, 50)}... -> ${proxyUrl.substring(0, 50)}...`);
|
|
15601
15706
|
}
|
|
15602
15707
|
}
|
|
15603
15708
|
catch (error) {
|
|
15604
|
-
if (
|
|
15709
|
+
if (this.options.debug) {
|
|
15605
15710
|
console.warn(`📸 ⚠️ 处理图片 URL 失败: ${originalSrc}`, error);
|
|
15606
15711
|
}
|
|
15607
15712
|
}
|
|
15608
15713
|
});
|
|
15609
15714
|
};
|
|
15610
15715
|
}
|
|
15611
|
-
if (
|
|
15716
|
+
if (this.options.debug) {
|
|
15612
15717
|
console.log(`📸 html2canvas 配置: 元素尺寸 ${elementWidth}x${elementHeight}, 质量 ${finalQuality.toFixed(2)}, 缩放 ${options.scale}`);
|
|
15613
15718
|
console.log(`📸 html2canvas 将自动计算截图尺寸(不限制 width/height)`);
|
|
15614
15719
|
console.log(`📸 用户配置质量: ${this.options.quality}, 实际使用质量: ${finalQuality.toFixed(2)}`);
|
|
@@ -15653,7 +15758,7 @@ class ScreenshotManager {
|
|
|
15653
15758
|
if (!dataUrl || dataUrl.length < 100) {
|
|
15654
15759
|
throw new Error('生成的截图数据无效或过短');
|
|
15655
15760
|
}
|
|
15656
|
-
if (
|
|
15761
|
+
if (this.options.debug) {
|
|
15657
15762
|
console.log(`📸 html2canvas 截图成功!格式: ${mimeType}, 尺寸: ${canvas.width}x${canvas.height}, 质量: ${finalQualityForExport?.toFixed(2) || 'N/A (PNG)'}`);
|
|
15658
15763
|
console.log(`📸 输出格式: ${mimeType}, 用户配置质量: ${this.options.quality}, 实际使用质量: ${finalQualityForExport?.toFixed(2) || 'N/A (PNG)'}`);
|
|
15659
15764
|
}
|
|
@@ -15661,7 +15766,7 @@ class ScreenshotManager {
|
|
|
15661
15766
|
}
|
|
15662
15767
|
catch (error) {
|
|
15663
15768
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
15664
|
-
if (
|
|
15769
|
+
if (this.options.debug) {
|
|
15665
15770
|
console.error('📸 html2canvas 截图失败:', errorMessage);
|
|
15666
15771
|
if (errorMessage.includes('CORS') || errorMessage.includes('cross-origin')) {
|
|
15667
15772
|
console.warn('📸 💡 建议:配置 proxyUrl 选项处理跨域图片');
|
|
@@ -15694,7 +15799,7 @@ class ScreenshotManager {
|
|
|
15694
15799
|
if (this.isScreenshotInProgress) {
|
|
15695
15800
|
// 队列最多保留 1 个请求,避免积压
|
|
15696
15801
|
if (this.screenshotQueue.length >= 1) {
|
|
15697
|
-
if (
|
|
15802
|
+
if (this.options.debug) {
|
|
15698
15803
|
console.log('📸 截图队列已满,跳过当前请求(等待队列处理)');
|
|
15699
15804
|
}
|
|
15700
15805
|
// 等待队列中的请求完成
|
|
@@ -15723,7 +15828,7 @@ class ScreenshotManager {
|
|
|
15723
15828
|
});
|
|
15724
15829
|
}
|
|
15725
15830
|
this.isScreenshotInProgress = true;
|
|
15726
|
-
if (
|
|
15831
|
+
if (this.options.debug) {
|
|
15727
15832
|
console.log('📸 使用 modern-screenshot 引擎截图(Worker 模式)...');
|
|
15728
15833
|
}
|
|
15729
15834
|
try {
|
|
@@ -15743,7 +15848,7 @@ class ScreenshotManager {
|
|
|
15743
15848
|
elementWidth = element.clientWidth || element.offsetWidth || element.scrollWidth;
|
|
15744
15849
|
elementHeight = element.clientHeight || element.offsetHeight || element.scrollHeight;
|
|
15745
15850
|
}
|
|
15746
|
-
if (
|
|
15851
|
+
if (this.options.debug) {
|
|
15747
15852
|
console.log(`📸 目标元素: ${element.tagName}${element.id ? '#' + element.id : ''}${element.className ? '.' + element.className.split(' ').join('.') : ''}`);
|
|
15748
15853
|
console.log(`📸 元素尺寸: ${elementWidth}x${elementHeight}`);
|
|
15749
15854
|
console.log(`📸 scrollWidth: ${element.scrollWidth}, scrollHeight: ${element.scrollHeight}`);
|
|
@@ -15777,7 +15882,7 @@ class ScreenshotManager {
|
|
|
15777
15882
|
// 检查内存缓存(优先使用缓存,带过期时间检查)
|
|
15778
15883
|
const cachedDataUrl = this.getCachedImage(url);
|
|
15779
15884
|
if (cachedDataUrl) {
|
|
15780
|
-
if (
|
|
15885
|
+
if (this.options.debug) {
|
|
15781
15886
|
console.log(`📸 ✅ 使用内存缓存图片: ${url.substring(0, 50)}...`);
|
|
15782
15887
|
}
|
|
15783
15888
|
return cachedDataUrl;
|
|
@@ -15829,7 +15934,7 @@ class ScreenshotManager {
|
|
|
15829
15934
|
}
|
|
15830
15935
|
}
|
|
15831
15936
|
catch (error) {
|
|
15832
|
-
if (
|
|
15937
|
+
if (this.options.debug) {
|
|
15833
15938
|
console.warn(`📸 代理处理图片失败: ${url.substring(0, 100)}...`, error);
|
|
15834
15939
|
}
|
|
15835
15940
|
// 失败时返回原 URL,让 modern-screenshot 自己处理
|
|
@@ -15878,7 +15983,7 @@ class ScreenshotManager {
|
|
|
15878
15983
|
// 按照 demo 的方式:只在 context 不存在时创建,之后一直复用
|
|
15879
15984
|
// 不进行复杂的检测和重新创建逻辑
|
|
15880
15985
|
if (!this.screenshotContext) {
|
|
15881
|
-
if (
|
|
15986
|
+
if (this.options.debug) {
|
|
15882
15987
|
console.log(`📸 创建截图 Worker 上下文...`);
|
|
15883
15988
|
console.log(`📸 Worker 模式: ${workerNumber} 个 Worker`);
|
|
15884
15989
|
}
|
|
@@ -15899,23 +16004,23 @@ class ScreenshotManager {
|
|
|
15899
16004
|
// 如果用户指定了 workerUrl,使用指定的 URL
|
|
15900
16005
|
if (this.options.workerUrl) {
|
|
15901
16006
|
simpleContextOptions.workerUrl = this.options.workerUrl;
|
|
15902
|
-
if (
|
|
16007
|
+
if (this.options.debug) {
|
|
15903
16008
|
console.log(`📸 使用指定的 Worker URL: ${this.options.workerUrl}`);
|
|
15904
16009
|
}
|
|
15905
16010
|
}
|
|
15906
16011
|
else {
|
|
15907
|
-
if (
|
|
16012
|
+
if (this.options.debug) {
|
|
15908
16013
|
console.log('📸 Worker URL 未指定,modern-screenshot 将自动处理');
|
|
15909
16014
|
}
|
|
15910
16015
|
}
|
|
15911
16016
|
try {
|
|
15912
16017
|
this.screenshotContext = await createContext$1(element, simpleContextOptions);
|
|
15913
|
-
if (
|
|
16018
|
+
if (this.options.debug) {
|
|
15914
16019
|
console.log('📸 Worker 上下文创建成功');
|
|
15915
16020
|
}
|
|
15916
16021
|
}
|
|
15917
16022
|
catch (error) {
|
|
15918
|
-
if (
|
|
16023
|
+
if (this.options.debug) {
|
|
15919
16024
|
console.error('📸 创建 Worker 上下文失败:', error);
|
|
15920
16025
|
}
|
|
15921
16026
|
throw error;
|
|
@@ -15925,7 +16030,7 @@ class ScreenshotManager {
|
|
|
15925
16030
|
// 按照 demo 的方式:使用 domToWebp 时传递配置参数
|
|
15926
16031
|
let dataUrl;
|
|
15927
16032
|
const outputFormat = this.options.outputFormat || 'webp';
|
|
15928
|
-
if (
|
|
16033
|
+
if (this.options.debug) {
|
|
15929
16034
|
console.log(`📸 使用 ${outputFormat.toUpperCase()} 格式截图(直接输出,无需转换)...`);
|
|
15930
16035
|
}
|
|
15931
16036
|
// 构建 domToWebp/domToJpeg/domToPng 的配置参数(和 demo 一致)
|
|
@@ -15960,14 +16065,14 @@ class ScreenshotManager {
|
|
|
15960
16065
|
if (!dataUrl || dataUrl.length < 100) {
|
|
15961
16066
|
throw new Error('生成的截图数据无效或过短');
|
|
15962
16067
|
}
|
|
15963
|
-
if (
|
|
16068
|
+
if (this.options.debug) {
|
|
15964
16069
|
console.log(`📸 ✅ modern-screenshot 截图成功(Worker 模式,${outputFormat.toUpperCase()} 格式)`);
|
|
15965
16070
|
}
|
|
15966
16071
|
return dataUrl;
|
|
15967
16072
|
}
|
|
15968
16073
|
catch (workerError) {
|
|
15969
16074
|
// Worker 模式失败,回退到普通模式(和 demo 一致)
|
|
15970
|
-
if (
|
|
16075
|
+
if (this.options.debug) {
|
|
15971
16076
|
console.warn('📸 Worker 模式失败,回退到普通模式:', workerError);
|
|
15972
16077
|
}
|
|
15973
16078
|
// 销毁失败的 context
|
|
@@ -16010,7 +16115,7 @@ class ScreenshotManager {
|
|
|
16010
16115
|
if (!dataUrl || dataUrl.length < 100) {
|
|
16011
16116
|
throw new Error('生成的截图数据无效或过短');
|
|
16012
16117
|
}
|
|
16013
|
-
if (
|
|
16118
|
+
if (this.options.debug) {
|
|
16014
16119
|
console.log(`📸 ✅ modern-screenshot 截图成功(普通模式,${outputFormat.toUpperCase()} 格式)`);
|
|
16015
16120
|
}
|
|
16016
16121
|
return dataUrl;
|
|
@@ -16018,7 +16123,7 @@ class ScreenshotManager {
|
|
|
16018
16123
|
}
|
|
16019
16124
|
catch (error) {
|
|
16020
16125
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
16021
|
-
if (
|
|
16126
|
+
if (this.options.debug) {
|
|
16022
16127
|
console.error('📸 modern-screenshot 截图失败:', errorMessage);
|
|
16023
16128
|
console.error('📸 元素信息:', {
|
|
16024
16129
|
width: rect.width,
|
|
@@ -16042,7 +16147,7 @@ class ScreenshotManager {
|
|
|
16042
16147
|
catch (error) {
|
|
16043
16148
|
// 外层错误处理:确保即使发生错误也释放锁
|
|
16044
16149
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
16045
|
-
if (
|
|
16150
|
+
if (this.options.debug) {
|
|
16046
16151
|
console.error('📸 modern-screenshot 截图异常:', errorMessage);
|
|
16047
16152
|
}
|
|
16048
16153
|
throw error;
|
|
@@ -16096,7 +16201,7 @@ class ScreenshotManager {
|
|
|
16096
16201
|
link.crossOrigin = 'anonymous';
|
|
16097
16202
|
document.head.appendChild(link);
|
|
16098
16203
|
this.preconnected = true;
|
|
16099
|
-
if (
|
|
16204
|
+
if (this.options.debug) {
|
|
16100
16205
|
console.log(`📸 ✅ 已预连接代理服务器: ${proxyOrigin}`);
|
|
16101
16206
|
}
|
|
16102
16207
|
}
|
|
@@ -16221,7 +16326,7 @@ class ScreenshotManager {
|
|
|
16221
16326
|
if (networkImages.length === 0) {
|
|
16222
16327
|
return;
|
|
16223
16328
|
}
|
|
16224
|
-
if (
|
|
16329
|
+
if (this.options.debug) {
|
|
16225
16330
|
const totalImages = images.length;
|
|
16226
16331
|
console.log(`📸 发现 ${networkImages.length}/${totalImages} 个可视区域内的跨域图片,开始并行预加载...`);
|
|
16227
16332
|
}
|
|
@@ -16229,7 +16334,7 @@ class ScreenshotManager {
|
|
|
16229
16334
|
// 只有当 useProxy 为 true 且 proxyUrl 存在时才使用代理
|
|
16230
16335
|
const shouldUseProxy = this.options.useProxy && this.options.proxyUrl && this.options.proxyUrl.trim() !== '';
|
|
16231
16336
|
if (shouldUseProxy) {
|
|
16232
|
-
if (
|
|
16337
|
+
if (this.options.debug) {
|
|
16233
16338
|
console.log(`📸 使用代理服务器处理跨域图片: ${this.options.proxyUrl}`);
|
|
16234
16339
|
}
|
|
16235
16340
|
// 优化:增加并发数,使用更大的批次
|
|
@@ -16257,13 +16362,13 @@ class ScreenshotManager {
|
|
|
16257
16362
|
}
|
|
16258
16363
|
catch (error) {
|
|
16259
16364
|
// 静默失败,不影响其他图片
|
|
16260
|
-
if (
|
|
16365
|
+
if (this.options.debug) {
|
|
16261
16366
|
console.warn(`📸 ❌ 代理预加载失败: ${originalSrc.substring(0, 50)}...`);
|
|
16262
16367
|
}
|
|
16263
16368
|
}
|
|
16264
16369
|
}));
|
|
16265
16370
|
}));
|
|
16266
|
-
if (
|
|
16371
|
+
if (this.options.debug) {
|
|
16267
16372
|
console.log(`📸 ✅ 预处理完成,缓存了 ${this.imageProxyCache.size} 个代理图片`);
|
|
16268
16373
|
}
|
|
16269
16374
|
}
|
|
@@ -16288,7 +16393,7 @@ class ScreenshotManager {
|
|
|
16288
16393
|
// 移除末尾的 ? 或 &(如果有)
|
|
16289
16394
|
baseUrl = baseUrl.replace(/[?&]$/, '');
|
|
16290
16395
|
const requestUrl = `${baseUrl}?${params.toString()}`;
|
|
16291
|
-
if (
|
|
16396
|
+
if (this.options.debug) {
|
|
16292
16397
|
console.log(`📸 🔄 代理请求 URL: ${requestUrl.substring(0, 200)}...`);
|
|
16293
16398
|
}
|
|
16294
16399
|
// 请求代理服务器
|
|
@@ -16307,7 +16412,7 @@ class ScreenshotManager {
|
|
|
16307
16412
|
const blob = await response.blob();
|
|
16308
16413
|
// 将 blob 转换为 data URL(用于 modern-screenshot 兼容性)
|
|
16309
16414
|
const dataUrl = await this.blobToDataUrl(blob);
|
|
16310
|
-
if (
|
|
16415
|
+
if (this.options.debug) {
|
|
16311
16416
|
console.log(`📸 ✅ 代理模式成功(已转换为 data URL): ${imageUrl.substring(0, 100)}...`);
|
|
16312
16417
|
}
|
|
16313
16418
|
return dataUrl;
|
|
@@ -16338,7 +16443,7 @@ class ScreenshotManager {
|
|
|
16338
16443
|
if (sizeMB > maxSizeMB) {
|
|
16339
16444
|
if (this.options.skipLargeImages) {
|
|
16340
16445
|
// 跳过过大的图片,返回占位符
|
|
16341
|
-
if (
|
|
16446
|
+
if (this.options.debug) {
|
|
16342
16447
|
console.warn(`📸 ⚠️ 跳过过大图片(${sizeMB.toFixed(2)}MB > ${maxSizeMB}MB): ${url.substring(0, 100)}...`);
|
|
16343
16448
|
}
|
|
16344
16449
|
// 返回一个 1x1 的透明占位符,避免截图失败
|
|
@@ -16346,7 +16451,7 @@ class ScreenshotManager {
|
|
|
16346
16451
|
}
|
|
16347
16452
|
else {
|
|
16348
16453
|
// 不跳过,但添加警告
|
|
16349
|
-
if (
|
|
16454
|
+
if (this.options.debug) {
|
|
16350
16455
|
console.warn(`📸 ⚠️ 图片较大(${sizeMB.toFixed(2)}MB),可能导致内存问题: ${url.substring(0, 100)}...`);
|
|
16351
16456
|
}
|
|
16352
16457
|
}
|
|
@@ -16360,14 +16465,14 @@ class ScreenshotManager {
|
|
|
16360
16465
|
if (blobSizeMB > maxSizeMB) {
|
|
16361
16466
|
if (this.options.skipLargeImages) {
|
|
16362
16467
|
// 跳过过大的图片,返回占位符
|
|
16363
|
-
if (
|
|
16468
|
+
if (this.options.debug) {
|
|
16364
16469
|
console.warn(`📸 ⚠️ 跳过过大图片(实际大小 ${blobSizeMB.toFixed(2)}MB > ${maxSizeMB}MB): ${url.substring(0, 100)}...`);
|
|
16365
16470
|
}
|
|
16366
16471
|
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';
|
|
16367
16472
|
}
|
|
16368
16473
|
else {
|
|
16369
16474
|
// 不跳过,但添加警告
|
|
16370
|
-
if (
|
|
16475
|
+
if (this.options.debug) {
|
|
16371
16476
|
console.warn(`📸 ⚠️ 图片较大(实际大小 ${blobSizeMB.toFixed(2)}MB),可能导致内存问题: ${url.substring(0, 100)}...`);
|
|
16372
16477
|
}
|
|
16373
16478
|
}
|
|
@@ -16383,7 +16488,7 @@ class ScreenshotManager {
|
|
|
16383
16488
|
}
|
|
16384
16489
|
catch (error) {
|
|
16385
16490
|
// 下载失败,返回原 URL,让 modern-screenshot 自己处理
|
|
16386
|
-
if (
|
|
16491
|
+
if (this.options.debug) {
|
|
16387
16492
|
console.warn(`📸 ⚠️ 下载图片失败: ${url.substring(0, 100)}...`, error);
|
|
16388
16493
|
}
|
|
16389
16494
|
return url;
|
|
@@ -16814,7 +16919,7 @@ class ScreenshotManager {
|
|
|
16814
16919
|
// 更新历史记录为压缩后的数据
|
|
16815
16920
|
this.screenshotHistory[this.screenshotHistory.length - 1] = compressed.dataUrl;
|
|
16816
16921
|
// 打印压缩统计信息和 base64 对比
|
|
16817
|
-
if (
|
|
16922
|
+
if (this.options.debug) {
|
|
16818
16923
|
if (compressed.error) {
|
|
16819
16924
|
// 压缩失败,使用原始数据
|
|
16820
16925
|
console.warn('📸 [Worker 压缩] ⚠️ 压缩失败,使用原始截图');
|
|
@@ -16868,7 +16973,7 @@ class ScreenshotManager {
|
|
|
16868
16973
|
};
|
|
16869
16974
|
newWorker.onerror = (e) => {
|
|
16870
16975
|
console.error('📸 WebWorker 错误:', e);
|
|
16871
|
-
if (
|
|
16976
|
+
if (this.options.debug) {
|
|
16872
16977
|
console.warn('📸 Worker 压缩失败,使用原始截图');
|
|
16873
16978
|
}
|
|
16874
16979
|
// Worker 发生错误时,如果配置了二进制模式,发送原始截图
|
|
@@ -16884,7 +16989,7 @@ class ScreenshotManager {
|
|
|
16884
16989
|
data: combinedBuffer
|
|
16885
16990
|
};
|
|
16886
16991
|
this.sendToIframeCallback(message);
|
|
16887
|
-
if (
|
|
16992
|
+
if (this.options.debug) {
|
|
16888
16993
|
console.log('📸 [Worker 错误] ✅ 原始截图已发送到 iframe');
|
|
16889
16994
|
}
|
|
16890
16995
|
}
|
|
@@ -17049,7 +17154,7 @@ class ScreenshotManager {
|
|
|
17049
17154
|
async takeScreenshotAndSendBinary(config) {
|
|
17050
17155
|
// 如果已经在运行,先停止再重新开始
|
|
17051
17156
|
if (this.isRunning) {
|
|
17052
|
-
if (
|
|
17157
|
+
if (this.options.debug) {
|
|
17053
17158
|
console.log(`📸 更新轮询间隔: ${this.dynamicInterval || this.options.interval}ms`);
|
|
17054
17159
|
}
|
|
17055
17160
|
this.stopScreenshot();
|
|
@@ -17080,7 +17185,7 @@ class ScreenshotManager {
|
|
|
17080
17185
|
// 验证:base64Data(从 latestScreenshot 提取)和 imageBufferBase64(从 imageBuffer 转换)应该一致
|
|
17081
17186
|
const isBase64Same = base64Data === imageBufferBase64;
|
|
17082
17187
|
// 打印 imageBuffer 的 base64 编码(用于和接收端对比)
|
|
17083
|
-
if (
|
|
17188
|
+
if (this.options.debug) {
|
|
17084
17189
|
console.log('📸 [发送前] 数据流程分析:');
|
|
17085
17190
|
console.log(` latestScreenshot: ${latestScreenshot.substring(0, 50)}... (原始 data URL)`);
|
|
17086
17191
|
console.log(` base64Data (从 latestScreenshot 提取): 长度 ${base64Data.length} 字符`);
|
|
@@ -17106,7 +17211,7 @@ class ScreenshotManager {
|
|
|
17106
17211
|
const combinedBuffer = this.combineBinaryData(configBuffer, imageBuffer);
|
|
17107
17212
|
const combinedBufferSize = combinedBuffer.byteLength;
|
|
17108
17213
|
// 打印大小信息
|
|
17109
|
-
if (
|
|
17214
|
+
if (this.options.debug) {
|
|
17110
17215
|
console.log('📸 [大小统计]');
|
|
17111
17216
|
console.log(` Base64 大小: ${base64Size} 字符`);
|
|
17112
17217
|
console.log(` 图片字节大小: ${(imageBufferSize / 1024).toFixed(2)} KB (${imageBufferSize} 字节)`);
|
|
@@ -17120,7 +17225,7 @@ class ScreenshotManager {
|
|
|
17120
17225
|
data: combinedBuffer
|
|
17121
17226
|
};
|
|
17122
17227
|
this.sendToIframeCallback(message);
|
|
17123
|
-
if (
|
|
17228
|
+
if (this.options.debug) {
|
|
17124
17229
|
console.log('📸 [iframe] ✅ 二进制数据已发送到 iframe');
|
|
17125
17230
|
}
|
|
17126
17231
|
}
|
|
@@ -17134,14 +17239,14 @@ class ScreenshotManager {
|
|
|
17134
17239
|
}
|
|
17135
17240
|
}
|
|
17136
17241
|
else {
|
|
17137
|
-
if (
|
|
17242
|
+
if (this.options.debug) {
|
|
17138
17243
|
console.warn('📸 [iframe] 截图完成但未找到截图数据');
|
|
17139
17244
|
}
|
|
17140
17245
|
}
|
|
17141
17246
|
}
|
|
17142
17247
|
else {
|
|
17143
17248
|
// 启用了压缩,等待 Worker 压缩完成后在 onmessage 中自动发送
|
|
17144
|
-
if (
|
|
17249
|
+
if (this.options.debug) {
|
|
17145
17250
|
console.log('📸 [iframe] 等待 Worker 压缩完成后发送到 iframe...');
|
|
17146
17251
|
}
|
|
17147
17252
|
}
|
|
@@ -17171,7 +17276,7 @@ class ScreenshotManager {
|
|
|
17171
17276
|
const base64Data = dataUrl.split(',')[1] || '';
|
|
17172
17277
|
const base64Size = base64Data.length;
|
|
17173
17278
|
// 完整打印发送前的 base64 信息(用于调试)
|
|
17174
|
-
if (
|
|
17279
|
+
if (this.options.debug) {
|
|
17175
17280
|
console.log('📸 [发送前] Base64 信息:');
|
|
17176
17281
|
console.log(` Base64 长度: ${base64Size} 字符`);
|
|
17177
17282
|
console.log(` 📸 [发送前] 完整 Base64:`);
|
|
@@ -17195,7 +17300,7 @@ class ScreenshotManager {
|
|
|
17195
17300
|
const combinedBufferSize = combinedBuffer.byteLength;
|
|
17196
17301
|
const combineTime = performance.now() - combineStartTime;
|
|
17197
17302
|
// 打印大小信息
|
|
17198
|
-
if (
|
|
17303
|
+
if (this.options.debug) {
|
|
17199
17304
|
console.log('📸 [压缩后-大小统计]');
|
|
17200
17305
|
console.log(` Base64 大小: ${base64Size} 字符`);
|
|
17201
17306
|
console.log(` 图片字节大小: ${(imageBufferSize / 1024).toFixed(2)} KB (${imageBufferSize} 字节)`);
|
|
@@ -17218,7 +17323,7 @@ class ScreenshotManager {
|
|
|
17218
17323
|
if (scheduleStartTime) {
|
|
17219
17324
|
totalTime = performance.now() - scheduleStartTime;
|
|
17220
17325
|
}
|
|
17221
|
-
if (
|
|
17326
|
+
if (this.options.debug) {
|
|
17222
17327
|
console.log('📸 [压缩后] ✅ 二进制数据已发送到 iframe');
|
|
17223
17328
|
console.log(` ⏱️ 发送回调耗时: ${sendCallbackTime.toFixed(2)}ms`);
|
|
17224
17329
|
console.log(` ⏱️ 发送阶段总耗时: ${totalSendTime.toFixed(2)}ms`);
|
|
@@ -17321,8 +17426,8 @@ class ScreenshotManager {
|
|
|
17321
17426
|
if (newOptions.compress !== undefined) {
|
|
17322
17427
|
this.options.compress = newOptions.compress;
|
|
17323
17428
|
}
|
|
17324
|
-
if (newOptions.
|
|
17325
|
-
this.options.
|
|
17429
|
+
if (newOptions.debug !== undefined) {
|
|
17430
|
+
this.options.debug = newOptions.debug;
|
|
17326
17431
|
}
|
|
17327
17432
|
if (newOptions.proxyUrl !== undefined) {
|
|
17328
17433
|
this.options.proxyUrl = newOptions.proxyUrl;
|
|
@@ -17335,7 +17440,7 @@ class ScreenshotManager {
|
|
|
17335
17440
|
if (this.screenshotContext) {
|
|
17336
17441
|
try {
|
|
17337
17442
|
destroyContext(this.screenshotContext);
|
|
17338
|
-
if (
|
|
17443
|
+
if (this.options.debug) {
|
|
17339
17444
|
console.log(`📸 引擎已从 ${oldEngine} 切换到 ${newEngine},已清理旧 context`);
|
|
17340
17445
|
}
|
|
17341
17446
|
}
|
|
@@ -17344,12 +17449,12 @@ class ScreenshotManager {
|
|
|
17344
17449
|
}
|
|
17345
17450
|
this.screenshotContext = null;
|
|
17346
17451
|
}
|
|
17347
|
-
if (
|
|
17452
|
+
if (this.options.debug) {
|
|
17348
17453
|
console.log(`📸 截图引擎已更新: ${oldEngine} → ${newEngine}`);
|
|
17349
17454
|
console.log(`📸 下次截图时将使用新引擎: ${newEngine}`);
|
|
17350
17455
|
}
|
|
17351
17456
|
}
|
|
17352
|
-
else if (
|
|
17457
|
+
else if (this.options.debug) {
|
|
17353
17458
|
console.log('📸 截图配置已更新');
|
|
17354
17459
|
}
|
|
17355
17460
|
}
|
|
@@ -17449,7 +17554,7 @@ class ScreenshotManager {
|
|
|
17449
17554
|
const itemSizeMB = value.dataUrl.length * 0.75 / (1024 * 1024);
|
|
17450
17555
|
this.imageProxyCache.delete(key);
|
|
17451
17556
|
currentSizeMB -= itemSizeMB;
|
|
17452
|
-
if (
|
|
17557
|
+
if (this.options.debug) {
|
|
17453
17558
|
console.log(`📸 清理内存缓存(超过限制): ${key.substring(0, 50)}...`);
|
|
17454
17559
|
}
|
|
17455
17560
|
}
|
|
@@ -17474,7 +17579,7 @@ class ScreenshotManager {
|
|
|
17474
17579
|
expiredUrls.forEach(url => {
|
|
17475
17580
|
this.imageProxyCache.delete(url);
|
|
17476
17581
|
});
|
|
17477
|
-
if (expiredUrls.length > 0 &&
|
|
17582
|
+
if (expiredUrls.length > 0 && this.options.debug) {
|
|
17478
17583
|
console.log(`📸 清理了 ${expiredUrls.length} 个过期缓存`);
|
|
17479
17584
|
}
|
|
17480
17585
|
}
|
|
@@ -17486,7 +17591,7 @@ class ScreenshotManager {
|
|
|
17486
17591
|
// 每2分钟清理一次过期缓存(从5分钟改为2分钟,更频繁)
|
|
17487
17592
|
setInterval(() => {
|
|
17488
17593
|
this.cleanExpiredCache();
|
|
17489
|
-
if (
|
|
17594
|
+
if (this.options.debug) {
|
|
17490
17595
|
const memoryCacheSize = this.imageProxyCache.size;
|
|
17491
17596
|
const memoryCacheSizeMB = Array.from(this.imageProxyCache.values())
|
|
17492
17597
|
.reduce((sum, cached) => sum + cached.dataUrl.length * 0.75 / (1024 * 1024), 0);
|
|
@@ -20826,9 +20931,10 @@ class CustomerServiceSDK {
|
|
|
20826
20931
|
agent: config.agent,
|
|
20827
20932
|
timestamp: Date.now()
|
|
20828
20933
|
};
|
|
20829
|
-
//
|
|
20934
|
+
// 创建悬浮图标管理器(支持自定义位置和传送目标)
|
|
20830
20935
|
const iconPosition = options?.iconPosition || undefined;
|
|
20831
|
-
|
|
20936
|
+
const iconTarget = options?.target || undefined;
|
|
20937
|
+
this.iconManager = new IconManager(iconPosition, this.debug, iconTarget);
|
|
20832
20938
|
await this.iconManager.show();
|
|
20833
20939
|
// 创建iframe管理器(自动检测设备类型)
|
|
20834
20940
|
this.iframeManager = new IframeManager({
|
|
@@ -20868,10 +20974,10 @@ class CustomerServiceSDK {
|
|
|
20868
20974
|
// 默认截图目标为 document.body,可以通过配置自定义
|
|
20869
20975
|
const targetElement = document.body;
|
|
20870
20976
|
// 传入发送消息到 iframe 的回调函数
|
|
20871
|
-
// 将 debug
|
|
20977
|
+
// 将 debug 配置传递给截图管理器
|
|
20872
20978
|
const screenshotOptions = {
|
|
20873
20979
|
...config.screenshot,
|
|
20874
|
-
|
|
20980
|
+
debug: this.debug // 直接传递 debug 标志
|
|
20875
20981
|
};
|
|
20876
20982
|
this.screenshotManager = new ScreenshotManager(targetElement, screenshotOptions, (data) => {
|
|
20877
20983
|
// 通过 IframeManager 发送消息到 iframe
|
|
@@ -21086,8 +21192,9 @@ class CustomerServiceSDK {
|
|
|
21086
21192
|
return result.visitorId;
|
|
21087
21193
|
}
|
|
21088
21194
|
catch (error) {
|
|
21089
|
-
|
|
21090
|
-
|
|
21195
|
+
if (this.debug) {
|
|
21196
|
+
console.warn('❌ Failed to get device fingerprint, using fallback:', error);
|
|
21197
|
+
}
|
|
21091
21198
|
const fallbackId = 'device_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
|
|
21092
21199
|
if (this.debug) {
|
|
21093
21200
|
console.log('🆔 Fallback Device ID:', fallbackId);
|