127 lines
4.0 KiB
HTML
127 lines
4.0 KiB
HTML
<!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; }
|
|
.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; }
|
|
</style>
|
|
<script>
|
|
(function() {
|
|
var STREAMLIT_URL = 'http://localhost:8501';
|
|
var retries = 0;
|
|
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);
|
|
setTimeout(check, 500);
|
|
};
|
|
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();
|
|
}
|
|
})();
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<div class="loader">
|
|
<div class="spinner"></div>
|
|
<p>正在加载...</p>
|
|
</div>
|
|
</body>
|
|
</html>
|