alert-view.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. (() => {
  2. /**
  3. * 全局提示遮罩层管理
  4. * 用于服务器断开连接时阻止 UI 交互并显示重连状态
  5. */
  6. class AlertView {
  7. constructor(options = {}) {
  8. this.overlay = null;
  9. this.message = null;
  10. this.checkInterval = options.checkInterval || 3000; // 检测间隔
  11. this.pingUrl = options.pingUrl || '/api/disk/list?path='; // 用于检测连接的接口
  12. this.isConnected = true;
  13. this.reconnectTimer = null;
  14. this.init();
  15. }
  16. async init() {
  17. // 直接使用 DOM 中的元素,不再需要 fetch 加载
  18. this.overlay = document.getElementById('alertOverlay');
  19. this.message = document.getElementById('alertOverlayMessage');
  20. // 如果元素不存在,等待 DOM 加载完成
  21. if (!this.overlay || !this.message) {
  22. await this.waitForElements();
  23. }
  24. this.startConnectionCheck();
  25. }
  26. async waitForElements() {
  27. // 等待元素出现(最多等待 1 秒)
  28. const maxWait = 1000;
  29. const startTime = Date.now();
  30. while (!this.overlay || !this.message) {
  31. if (Date.now() - startTime > maxWait) {
  32. console.error('Alert Overlay 元素未找到');
  33. return;
  34. }
  35. await new Promise(resolve => setTimeout(resolve, 50));
  36. this.overlay = document.getElementById('alertOverlay');
  37. this.message = document.getElementById('alertOverlayMessage');
  38. }
  39. }
  40. show(msg) {
  41. if (this.overlay) {
  42. if (msg && this.message) {
  43. this.message.textContent = msg;
  44. }
  45. this.overlay.classList.add('show');
  46. }
  47. }
  48. hide() {
  49. if (this.overlay) {
  50. this.overlay.classList.remove('show');
  51. }
  52. }
  53. startConnectionCheck() {
  54. // 定期检测服务器连接
  55. setInterval(() => this.checkConnection(), this.checkInterval);
  56. }
  57. async checkConnection() {
  58. try {
  59. const controller = new AbortController();
  60. const timeoutId = setTimeout(() => controller.abort(), 5000);
  61. const response = await fetch(this.pingUrl, {
  62. method: 'GET',
  63. signal: controller.signal
  64. });
  65. clearTimeout(timeoutId);
  66. if (response.ok) {
  67. if (!this.isConnected) {
  68. // 重连成功
  69. this.isConnected = true;
  70. this.hide();
  71. this.onReconnected();
  72. }
  73. } else {
  74. this.handleDisconnect();
  75. }
  76. } catch (error) {
  77. this.handleDisconnect();
  78. }
  79. }
  80. handleDisconnect() {
  81. if (this.isConnected) {
  82. this.isConnected = false;
  83. this.show('服务器断开连接,正在重连...');
  84. this.startReconnect();
  85. }
  86. }
  87. startReconnect() {
  88. if (this.reconnectTimer) {
  89. clearInterval(this.reconnectTimer);
  90. }
  91. // 每 2 秒尝试重连一次
  92. this.reconnectTimer = setInterval(() => {
  93. this.tryReconnect();
  94. }, 2000);
  95. }
  96. async tryReconnect() {
  97. try {
  98. const controller = new AbortController();
  99. const timeoutId = setTimeout(() => controller.abort(), 5000);
  100. const response = await fetch(this.pingUrl, {
  101. method: 'GET',
  102. signal: controller.signal
  103. });
  104. clearTimeout(timeoutId);
  105. if (response.ok) {
  106. // 重连成功
  107. clearInterval(this.reconnectTimer);
  108. this.reconnectTimer = null;
  109. this.isConnected = true;
  110. this.hide();
  111. this.onReconnected();
  112. }
  113. } catch (error) {
  114. // 重连失败,继续尝试
  115. }
  116. }
  117. onReconnected() {
  118. // 重连成功后刷新页面数据
  119. if (window.diskManager && typeof window.diskManager.loadFiles === 'function') {
  120. window.diskManager.loadFiles();
  121. }
  122. }
  123. }
  124. // 导出到全局
  125. window.AlertView = AlertView;
  126. // 页面加载完成后自动初始化(已禁用)
  127. // document.addEventListener('DOMContentLoaded', () => {
  128. // window.alertView = new AlertView();
  129. // });
  130. })();