From 5426688ad51ed36c5632aba9fbf39a151fc54ac0 Mon Sep 17 00:00:00 2001 From: KQL Date: Wed, 24 Sep 2025 15:20:12 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=AB=AF=E5=8F=A3=E6=A3=80?= =?UTF-8?q?=E6=B5=8B=EF=BC=8C=E4=BD=BF=E7=94=A8localStorage=E7=BC=93?= =?UTF-8?q?=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 使用简化的Image检测方法,更可靠 - 添加localStorage缓存,减少重复检测 - 添加单个端口刷新按钮 - 显示最后检查时间 - 顺序检测避免并发过多 - 强制刷新功能清除缓存 --- index-backup.html | 665 +++++++++++++++++++++++++++++++++++++++++++++ index-final.html | 668 ++++++++++++++++++++++++++++++++++++++++++++++ index.html | 232 +++++++++------- 3 files changed, 1464 insertions(+), 101 deletions(-) create mode 100644 index-backup.html create mode 100644 index-final.html diff --git a/index-backup.html b/index-backup.html new file mode 100644 index 0000000..b566aaf --- /dev/null +++ b/index-backup.html @@ -0,0 +1,665 @@ + + + + + + 教务系统 - 产业导航 + + + +
+

🎓 教务系统产业管理中心

+

智能化多产业教务管理平台 - 支持12个产业独立运行

+
+ +
+ +
+

💡 Windows 用户快速启动指南

+
    +
  1. 方法一:双击运行 start-industry.bat 文件
  2. +
  3. 方法二:打开命令提示符(CMD),输入 start-industry.bat
  4. +
  5. 方法三:使用 PowerShell 运行 .\start-industry.ps1
  6. +
  7. 方法四:直接在本页面点击下方的控制按钮
  8. +
+
+ + +
+

🎛️ 快速控制中心

+
+ + + + + 🚀 打开启动器 (Windows) + +
+
+

💻 当前系统:

+

📁 项目路径:

+
+
+ + +
+ + + +
+ + + + \ No newline at end of file diff --git a/index-final.html b/index-final.html new file mode 100644 index 0000000..35a7493 --- /dev/null +++ b/index-final.html @@ -0,0 +1,668 @@ + + + + + + 教务系统 - 产业导航 + + + +
+

🎓 教务系统产业管理中心

+

智能化多产业教务管理平台 - 支持12个产业独立运行

+
+ +
+ +
+

💡 Windows 用户快速启动指南

+
    +
  1. 方法一:双击运行 start-industry.bat 文件
  2. +
  3. 方法二:打开命令提示符(CMD),输入 start-industry.bat
  4. +
  5. 方法三:使用 PowerShell 运行 .\start-industry.ps1
  6. +
  7. 方法四:直接在本页面点击下方的控制按钮
  8. +
+
+ + +
+

🎛️ 快速控制中心

+
+ + + + + 🚀 打开启动器 (Windows) + +
+
+

💻 当前系统:

+

📁 项目路径:

+

⏰ 最后检查: 从未检查

+
+
+ + +
+ + + +
+ + + + \ No newline at end of file diff --git a/index.html b/index.html index a902116..35a7493 100644 --- a/index.html +++ b/index.html @@ -395,8 +395,8 @@ - 🚀 打开启动器 (Windows) @@ -405,6 +405,7 @@

💻 当前系统:

📁 项目路径:

+

⏰ 最后检查: 从未检查

@@ -413,7 +414,7 @@
@@ -435,6 +436,9 @@ { id: 12, name: '环保产业', dir: 'frontend_环保', port: 5161, icon: '🌱' } ]; + // 状态缓存 + const statusCache = {}; + // 检测平台信息 function detectPlatform() { const platform = navigator.platform; @@ -450,7 +454,7 @@ } document.getElementById('platformInfo').textContent = osInfo; - document.getElementById('projectPath').textContent = window.location.pathname.replace('/index.html', ''); + document.getElementById('projectPath').textContent = window.location.pathname.replace('/index-final.html', ''); } // 创建产业卡片 @@ -482,8 +486,8 @@ - @@ -495,103 +499,134 @@ detectPlatform(); const grid = document.getElementById('industryGrid'); grid.innerHTML = industries.map(industry => createIndustryCard(industry)).join(''); + + // 从localStorage读取缓存的状态 + loadStatusFromCache(); + + // 然后执行实际检查 checkAllStatus(); } - // 检查单个产业状态 - async function checkStatus(port) { - const statusEl = document.getElementById(`status-${port}`); - - // 默认设置为停止状态 - let isRunning = false; - - // 创建一个Promise来处理超时 - const checkPromise = new Promise((resolve) => { - // 使用Image对象检测,这是最可靠的跨域方法 - const img = new Image(); - let hasResponded = false; - - // 设置超时 - const timeout = setTimeout(() => { - if (!hasResponded) { - hasResponded = true; - resolve(false); // 超时则认为服务停止 - } - }, 1500); - - img.onload = () => { - if (!hasResponded) { - hasResponded = true; - clearTimeout(timeout); - resolve(true); // 加载成功说明服务运行中 - } - }; - - img.onerror = () => { - if (!hasResponded) { - hasResponded = true; - clearTimeout(timeout); - // 图片加载失败,尝试fetch检测 - fetch(`http://localhost:${port}/`, { - mode: 'no-cors', - cache: 'no-cache' - }).then(() => { - // 如果fetch没有抛出错误,说明服务可能在运行 - // 但由于CORS,我们无法获取响应内容 - // 这种情况下我们需要更谨慎的判断 - - // 创建一个iframe来尝试加载页面 - const iframe = document.createElement('iframe'); - iframe.style.display = 'none'; - iframe.src = `http://localhost:${port}/`; - - const iframeTimeout = setTimeout(() => { - document.body.removeChild(iframe); - resolve(false); // iframe也无法加载,服务停止 - }, 1000); - - iframe.onload = () => { - clearTimeout(iframeTimeout); - document.body.removeChild(iframe); - resolve(true); // iframe加载成功,服务运行中 - }; - - iframe.onerror = () => { - clearTimeout(iframeTimeout); - document.body.removeChild(iframe); - resolve(false); // iframe加载失败,服务停止 - }; - - document.body.appendChild(iframe); - }).catch(() => { - // fetch失败,服务未运行 - resolve(false); + // 从缓存加载状态 + function loadStatusFromCache() { + const cached = localStorage.getItem('industryStatus'); + if (cached) { + try { + const data = JSON.parse(cached); + const now = Date.now(); + // 如果缓存不超过5分钟,使用缓存数据 + if (data.timestamp && (now - data.timestamp) < 300000) { + Object.keys(data.status).forEach(port => { + updateStatusUI(port, data.status[port]); }); + document.getElementById('lastCheck').textContent = new Date(data.timestamp).toLocaleTimeString(); } - }; - - // 尝试加载favicon或vite.svg - img.src = `http://localhost:${port}/vite.svg?t=${Date.now()}`; - }); - - // 等待检测结果 - isRunning = await checkPromise; - - // 更新UI - if (isRunning) { - statusEl.className = 'status status-running'; - statusEl.innerHTML = ' 运行中'; - } else { - statusEl.className = 'status status-stopped'; - statusEl.innerHTML = ' 已停止'; + } catch (e) { + console.error('读取缓存失败:', e); + } } } + // 保存状态到缓存 + function saveStatusToCache() { + const data = { + timestamp: Date.now(), + status: statusCache + }; + localStorage.setItem('industryStatus', JSON.stringify(data)); + } + + // 更新UI状态 + function updateStatusUI(port, isRunning) { + const statusEl = document.getElementById(`status-${port}`); + if (statusEl) { + if (isRunning) { + statusEl.className = 'status status-running'; + statusEl.innerHTML = ' 运行中'; + } else { + statusEl.className = 'status status-stopped'; + statusEl.innerHTML = ' 已停止'; + } + } + statusCache[port] = isRunning; + } + + // 检查单个端口 + async function checkSinglePort(port) { + const statusEl = document.getElementById(`status-${port}`); + statusEl.className = 'status status-checking'; + statusEl.innerHTML = ' 检查中...'; + + const isRunning = await checkPort(port); + updateStatusUI(port, isRunning); + saveStatusToCache(); + } + + // 实际的端口检查逻辑 + async function checkPort(port) { + // 方法1: 使用Image检测 + const checkImage = () => { + return new Promise((resolve) => { + const img = new Image(); + let resolved = false; + + const timeout = setTimeout(() => { + if (!resolved) { + resolved = true; + resolve(false); + } + }, 2000); + + img.onload = () => { + if (!resolved) { + resolved = true; + clearTimeout(timeout); + resolve(true); + } + }; + + img.onerror = () => { + if (!resolved) { + resolved = true; + clearTimeout(timeout); + resolve(false); + } + }; + + // 添加时间戳避免缓存 + img.src = `http://localhost:${port}/vite.svg?_=${Date.now()}`; + }); + }; + + // 执行检查 + const result = await checkImage(); + return result; + } + // 检查所有状态 - function checkAllStatus() { - industries.forEach(industry => { - checkStatus(industry.port); - }); + async function checkAllStatus() { + console.log('开始检查所有端口状态...'); + const checkTime = new Date().toLocaleTimeString(); + + // 顺序检查每个端口,避免并发过多 + for (const industry of industries) { + const isRunning = await checkPort(industry.port); + updateStatusUI(industry.port, isRunning); + // 添加小延迟,避免请求过快 + await new Promise(resolve => setTimeout(resolve, 100)); + } + + saveStatusToCache(); + document.getElementById('lastCheck').textContent = checkTime; + console.log('状态检查完成'); + } + + // 强制刷新所有状态 + function forceCheckAllStatus() { + // 清除缓存 + localStorage.removeItem('industryStatus'); + // 重新检查 + checkAllStatus(); } // 打开产业系统 @@ -599,11 +634,6 @@ window.open(`http://localhost:${port}`, '_blank'); } - // 启动/停止产业(提示用户使用启动器) - function toggleIndustry(id) { - alert(`请使用启动器控制产业 ${id}:\n\nWindows用户:\n- 运行 start-industry.bat\n- 选择选项 ${id}\n\nMac/Linux用户:\n- 运行 ./start-industry.sh\n- 选择选项 ${id}`); - } - // 启动所有产业 function startAllIndustries() { if (confirm('启动所有产业需要使用系统启动器。\n\nWindows: 运行 start-industry.bat 选择 [0]\nMac/Linux: 运行 ./start-industry.sh 选择 [0]\n\n是否打开启动器?')) { @@ -631,8 +661,8 @@ // 页面加载完成后初始化 document.addEventListener('DOMContentLoaded', initPage); - // 自动刷新状态(每10秒) - setInterval(checkAllStatus, 10000); + // 自动刷新状态(每30秒) + setInterval(checkAllStatus, 30000); \ No newline at end of file