Files
ChouJuGEO/frontend/index.html
T

127 lines
4.0 KiB
HTML
Raw Normal View History

2026-05-30 13:04:03 +08:00
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>丑橘文化传媒GEO内容优化平台</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: #f7fafc;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
.loader {
text-align: center;
}
.spinner {
width: 40px; height: 40px;
border: 4px solid #e2e8f0;
border-top-color: #2563eb;
border-radius: 50%;
animation: spin 0.8s linear infinite;
margin: 0 auto 16px;
}
@keyframes spin { to { transform: rotate(360deg); } }
p { color: #4a5568; font-size: 14px; }
2026-05-30 15:39:42 +08:00
.status { color: #718096; font-size: 13px; margin-top: 12px; }
.retry-btn {
display: none;
margin-top: 16px;
padding: 8px 24px;
background: #2563eb;
color: #fff;
border: none;
border-radius: 6px;
font-size: 14px;
cursor: pointer;
}
.retry-btn:hover { background: #1d4ed8; }
.retry-btn.show { display: inline-block; }
2026-05-30 13:04:03 +08:00
</style>
<script>
(function() {
2026-05-30 15:39:42 +08:00
var STREAMLIT_URL = 'http://localhost:8501';
2026-05-30 13:04:03 +08:00
var retries = 0;
2026-05-30 15:39:42 +08:00
var maxRetries = 120; // 最多等待 120 次(约 60 秒)
var interval = 500; // 每 500ms 检查一次
var statusEl = null;
var retryBtn = null;
function showStatus(msg, isError) {
if (!statusEl) {
statusEl = document.createElement('p');
statusEl.className = 'status';
document.querySelector('.loader').appendChild(statusEl);
}
statusEl.textContent = msg;
if (isError) {
statusEl.style.color = '#dc2626';
} else {
statusEl.style.color = '#718096';
}
if (!retryBtn) {
retryBtn = document.createElement('button');
retryBtn.className = 'retry-btn';
retryBtn.textContent = '手动重试';
retryBtn.onclick = function() {
retries = 0;
retryBtn.classList.remove('show');
showStatus('正在重新连接...', false);
2026-05-30 13:04:03 +08:00
setTimeout(check, 500);
2026-05-30 15:39:42 +08:00
};
document.querySelector('.loader').appendChild(retryBtn);
}
}
function check() {
// 使用 fetch no-cors 模式检测端口是否可达
// no-cors: 请求成功则 resolve,连接失败则 reject
var controller = new AbortController();
var timeoutId = setTimeout(function() { controller.abort(); }, 3000);
fetch(STREAMLIT_URL, { mode: 'no-cors', signal: controller.signal })
.then(function() {
clearTimeout(timeoutId);
// 服务可达 → 跳转
showStatus('服务已就绪,正在进入...');
window.location.replace(STREAMLIT_URL);
})
.catch(function(err) {
clearTimeout(timeoutId);
retries++;
if (retries < maxRetries) {
showStatus('正在启动服务... (' + retries + '/' + maxRetries + ')');
setTimeout(check, interval);
} else {
showStatus('服务启动超时。请确认 Streamlit 已在 :8501 端口运行,或点击下方按钮重试。', true);
if (retryBtn) retryBtn.classList.add('show');
}
});
}
// 等待 DOM 就绪后再开始检测
function start() {
showStatus('正在启动服务...');
// 首次延迟 1.5 秒,给服务一点启动时间
setTimeout(check, 1500);
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', start);
} else {
start();
2026-05-30 13:04:03 +08:00
}
})();
</script>
</head>
<body>
<div class="loader">
<div class="spinner"></div>
<p>正在加载...</p>
</div>
</body>
</html>