customer-chat-sdk 1.0.42 → 1.0.43

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.
@@ -14310,11 +14310,8 @@ class ScreenshotManager {
14310
14310
  this.error = null;
14311
14311
  this.isEnabled = false;
14312
14312
  // 上传相关状态
14313
- this.isUploading = false;
14314
14313
  this.uploadError = null;
14315
- this.uploadProgress = { success: 0, failed: 0 };
14316
- this.currentUploadConfig = null;
14317
- this.currentBinaryConfig = null; // 二进制配置(新格式)
14314
+ this.currentBinaryConfig = null; // 二进制配置
14318
14315
  this.sendToIframeCallback = null; // 发送消息到 iframe 的回调函数
14319
14316
  // WebWorker 相关
14320
14317
  this.worker = null;
@@ -14548,9 +14545,8 @@ class ScreenshotManager {
14548
14545
  // 尝试解析为二进制配置(新格式)
14549
14546
  const binaryConfig = this.parseBinaryConfig(event.data.data);
14550
14547
  if (binaryConfig) {
14551
- // 新格式:二进制配置
14548
+ // 二进制配置
14552
14549
  this.currentBinaryConfig = binaryConfig;
14553
- this.currentUploadConfig = null; // 清除旧格式配置
14554
14550
  // 根据 ttl 判断是否开启截图功能
14555
14551
  const currentTime = Date.now();
14556
14552
  const isValid = binaryConfig.ttl > 0 && binaryConfig.ttl > currentTime;
@@ -14562,8 +14558,8 @@ class ScreenshotManager {
14562
14558
  }
14563
14559
  this.isEnabled = true;
14564
14560
  }
14565
- // 设置动态轮询间隔
14566
- this.dynamicInterval = this.options.interval;
14561
+ // 设置动态轮询间隔(使用配置中的 duration)
14562
+ this.dynamicInterval = binaryConfig.duration || this.options.interval;
14567
14563
  // 计算剩余有效时间(毫秒)
14568
14564
  const remainingTime = binaryConfig.ttl - currentTime;
14569
14565
  // 启动或更新截图轮询
@@ -14608,73 +14604,9 @@ class ScreenshotManager {
14608
14604
  }
14609
14605
  return;
14610
14606
  }
14611
- // 旧格式:解析上传配置
14612
- const config = this.parseUploadConfig(event.data.data);
14613
- if (!config) {
14614
- console.error('📸 [iframe] 解析配置失败');
14615
- this.uploadError = '解析上传配置失败';
14616
- return;
14617
- }
14618
- // 保存当前配置
14619
- this.currentUploadConfig = config;
14620
- this.currentBinaryConfig = null; // 清除二进制配置
14621
- // 根据 ttl 判断是否开启截图功能
14622
- // ttl == 0 表示禁用,ttl > 0 且大于当前时间表示有效
14623
- const currentTime = Date.now();
14624
- const isValid = config.ttl > 0 && config.ttl > currentTime;
14625
- if (isValid) {
14626
- // 启用截图功能
14627
- if (!this.isEnabled) {
14628
- if (!this.options.silentMode) {
14629
- console.log('📸 [iframe] 启用截图功能');
14630
- }
14631
- this.isEnabled = true;
14632
- }
14633
- // 设置动态轮询间隔(使用 duration,单位:毫秒)
14634
- this.dynamicInterval = config.duration || this.options.interval;
14635
- // 计算剩余有效时间(毫秒)
14636
- const remainingTime = config.ttl - currentTime;
14637
- // 启动或更新截图轮询
14638
- if (!this.options.silentMode) {
14639
- const remainingMinutes = Math.ceil(remainingTime / 60000);
14640
- console.log(`📸 [iframe] 设置轮询间隔: ${this.dynamicInterval}ms,剩余有效时间: ${remainingMinutes}分钟`);
14641
- }
14642
- // 先执行一次截图,等待完成后再上传
14643
- this.takeScreenshotAndUpload(config);
14644
- // 设置过期定时器
14645
- if (this.expirationTimer) {
14646
- clearTimeout(this.expirationTimer);
14647
- this.expirationTimer = null;
14648
- }
14649
- this.expirationTimer = setTimeout(() => {
14650
- if (!this.options.silentMode) {
14651
- console.log('📸 [iframe] 上传配置已过期,停止截图');
14652
- }
14653
- this.stopScreenshot();
14654
- this.isEnabled = false;
14655
- this.currentUploadConfig = null;
14656
- this.expirationTimer = null;
14657
- }, remainingTime);
14658
- }
14659
- else {
14660
- // 禁用截图功能(ttl == 0 或已过期)
14661
- if (!this.options.silentMode) {
14662
- if (config.ttl === 0) {
14663
- console.log('📸 [iframe] ttl == 0,禁用截图功能');
14664
- }
14665
- else {
14666
- console.log('📸 [iframe] ttl 已过期,禁用截图功能');
14667
- }
14668
- }
14669
- this.stopScreenshot();
14670
- this.isEnabled = false;
14671
- this.currentUploadConfig = null;
14672
- if (this.expirationTimer) {
14673
- clearTimeout(this.expirationTimer);
14674
- this.expirationTimer = null;
14675
- }
14676
- return;
14677
- }
14607
+ // 如果不是二进制配置格式,记录错误
14608
+ console.error('📸 [iframe] 解析配置失败:未识别的配置格式');
14609
+ this.uploadError = '解析配置失败:仅支持二进制配置格式';
14678
14610
  }
14679
14611
  catch (error) {
14680
14612
  console.error('📸 [iframe] 处理消息失败:', error);
@@ -14682,63 +14614,7 @@ class ScreenshotManager {
14682
14614
  }
14683
14615
  }
14684
14616
  /**
14685
- * 执行截图并上传
14686
- */
14687
- async takeScreenshotAndUpload(config) {
14688
- // 如果已经在运行,先停止再重新开始(更新间隔)
14689
- if (this.isRunning) {
14690
- if (!this.options.silentMode) {
14691
- console.log(`📸 更新轮询间隔: ${this.dynamicInterval || this.options.interval}ms`);
14692
- }
14693
- this.stopScreenshot();
14694
- }
14695
- // 启动轮询
14696
- this.startScreenshot(this.dynamicInterval || config.duration || this.options.interval);
14697
- // 等待第一次截图完成
14698
- try {
14699
- const success = await this.takeScreenshot();
14700
- if (success) {
14701
- // 截图完成后,等待一小段时间确保数据已保存
14702
- await new Promise(resolve => setTimeout(resolve, 100));
14703
- // 获取最新截图并上传
14704
- const latestScreenshot = this.getLatestScreenshot();
14705
- if (latestScreenshot) {
14706
- // 执行上传
14707
- this.isUploading = true;
14708
- this.uploadError = null;
14709
- this.uploadScreenshot(latestScreenshot, config)
14710
- .then((success) => {
14711
- if (success) {
14712
- if (!this.options.silentMode) {
14713
- console.log('📸 [iframe] ✅ 截图上传成功');
14714
- }
14715
- }
14716
- else {
14717
- console.error('📸 [iframe] ❌ 截图上传失败');
14718
- }
14719
- })
14720
- .catch((error) => {
14721
- console.error('📸 [iframe] ❌ 上传异常:', error);
14722
- this.uploadError = error instanceof Error ? error.message : String(error);
14723
- })
14724
- .finally(() => {
14725
- this.isUploading = false;
14726
- });
14727
- }
14728
- else {
14729
- if (!this.options.silentMode) {
14730
- console.warn('📸 [iframe] 截图完成但未找到截图数据');
14731
- }
14732
- }
14733
- }
14734
- }
14735
- catch (error) {
14736
- console.error('📸 [iframe] 截图失败:', error);
14737
- this.uploadError = error instanceof Error ? error.message : String(error);
14738
- }
14739
- }
14740
- /**
14741
- * 解析二进制配置(新格式)
14617
+ * 解析二进制配置
14742
14618
  */
14743
14619
  parseBinaryConfig(data) {
14744
14620
  try {
@@ -14755,7 +14631,10 @@ class ScreenshotManager {
14755
14631
  type: config.type,
14756
14632
  topic: config.topic,
14757
14633
  routingKey: config.routingKey,
14758
- ttl: config.ttl
14634
+ ttl: config.ttl,
14635
+ duration: typeof config.duration === 'number' && config.duration > 0
14636
+ ? config.duration
14637
+ : this.options.interval // 如果没有提供或无效,使用默认间隔
14759
14638
  };
14760
14639
  }
14761
14640
  return null;
@@ -14765,38 +14644,6 @@ class ScreenshotManager {
14765
14644
  return null;
14766
14645
  }
14767
14646
  }
14768
- /**
14769
- * 解析上传配置
14770
- */
14771
- parseUploadConfig(data) {
14772
- try {
14773
- const configStr = typeof data === 'string' ? data : JSON.stringify(data);
14774
- const config = JSON.parse(configStr);
14775
- if (!config.uploadUrl || !config.contentType) {
14776
- console.error('📸 [上传] 配置缺少必需字段:', config);
14777
- return null;
14778
- }
14779
- // 确保 duration 存在,如果没有则使用默认值
14780
- if (typeof config.duration !== 'number' || config.duration <= 0) {
14781
- config.duration = this.options.interval;
14782
- }
14783
- // 确保 ttl 存在,如果没有则尝试从 expirationMinutes 转换(兼容旧格式)
14784
- if (typeof config.ttl !== 'number') {
14785
- if (typeof config.expirationMinutes === 'number' && config.expirationMinutes > 0) {
14786
- // 兼容旧格式:将 expirationMinutes 转换为 ttl
14787
- config.ttl = Date.now() + config.expirationMinutes * 60 * 1000;
14788
- }
14789
- else {
14790
- config.ttl = 0; // 默认禁用
14791
- }
14792
- }
14793
- return config;
14794
- }
14795
- catch (error) {
14796
- console.error('📸 [上传] 解析配置失败:', error, '原始数据:', data);
14797
- return null;
14798
- }
14799
- }
14800
14647
  /**
14801
14648
  * 开始轮询截图
14802
14649
  */
@@ -14826,16 +14673,6 @@ class ScreenshotManager {
14826
14673
  if (this.isRunning && this.isEnabled && !document.hidden) {
14827
14674
  try {
14828
14675
  await this.takeScreenshot();
14829
- // 如果配置了上传,且当前有上传配置,自动上传
14830
- if (this.currentUploadConfig) {
14831
- const latestScreenshot = this.getLatestScreenshot();
14832
- if (latestScreenshot && !this.isUploading) {
14833
- this.uploadScreenshot(latestScreenshot, this.currentUploadConfig)
14834
- .catch((error) => {
14835
- console.error('📸 [轮询] 自动上传失败:', error);
14836
- });
14837
- }
14838
- }
14839
14676
  // 如果配置了二进制模式,发送二进制数据
14840
14677
  if (this.currentBinaryConfig) {
14841
14678
  const latestScreenshot = this.getLatestScreenshot();
@@ -16918,62 +16755,6 @@ class ScreenshotManager {
16918
16755
  this.globalRejectionHandler = null;
16919
16756
  }
16920
16757
  }
16921
- /**
16922
- * 上传截图到 S3
16923
- */
16924
- async uploadScreenshot(dataUrl, config) {
16925
- try {
16926
- if (!this.options.silentMode) {
16927
- console.log('📸 [上传] 开始上传截图...');
16928
- }
16929
- const blob = this.dataUrlToBlob(dataUrl, config.contentType);
16930
- // 使用标准的 fetch 方法(与 demo 代码一致)
16931
- const response = await fetch(config.uploadUrl, {
16932
- method: 'PUT',
16933
- body: blob,
16934
- headers: {
16935
- 'Content-Type': config.contentType
16936
- }
16937
- });
16938
- if (response.status === 200 || response.status === 204) {
16939
- if (!this.options.silentMode) {
16940
- console.log('📸 [上传] ✅ 上传成功');
16941
- }
16942
- this.uploadProgress.success++;
16943
- return true;
16944
- }
16945
- else {
16946
- const errorText = await response.text().catch(() => '');
16947
- const errorMsg = `上传失败: HTTP ${response.status} ${response.statusText}${errorText ? ` - ${errorText.substring(0, 200)}` : ''}`;
16948
- console.error('📸 [上传] ❌', errorMsg);
16949
- this.uploadError = errorMsg;
16950
- this.uploadProgress.failed++;
16951
- return false;
16952
- }
16953
- }
16954
- catch (error) {
16955
- const errorMsg = error instanceof Error ? error.message : String(error);
16956
- console.error('📸 [上传] ❌ 上传异常:', errorMsg);
16957
- this.uploadError = `上传异常: ${errorMsg}`;
16958
- this.uploadProgress.failed++;
16959
- return false;
16960
- }
16961
- }
16962
- /**
16963
- * 将 base64 data URL 转换为 Blob
16964
- */
16965
- dataUrlToBlob(dataUrl, contentType) {
16966
- const arr = dataUrl.split(',');
16967
- const mimeMatch = arr[0].match(/:(.*?);/);
16968
- const mime = mimeMatch ? mimeMatch[1] : contentType;
16969
- const bstr = atob(arr[1]);
16970
- let n = bstr.length;
16971
- const u8arr = new Uint8Array(n);
16972
- while (n--) {
16973
- u8arr[n] = bstr.charCodeAt(n);
16974
- }
16975
- return new Blob([u8arr], { type: mime });
16976
- }
16977
16758
  /**
16978
16759
  * 将 base64 data URL 转换为 ArrayBuffer
16979
16760
  */
@@ -17273,10 +17054,8 @@ class ScreenshotManager {
17273
17054
  lastScreenshotTime: this.lastScreenshotTime,
17274
17055
  error: this.error,
17275
17056
  isEnabled: this.isEnabled,
17276
- isUploading: this.isUploading,
17277
17057
  uploadError: this.uploadError,
17278
- uploadProgress: { ...this.uploadProgress },
17279
- currentUploadConfig: this.currentUploadConfig
17058
+ currentBinaryConfig: this.currentBinaryConfig
17280
17059
  };
17281
17060
  }
17282
17061
  }