Files
tk-electron-ai/waiting.html
2025-10-28 19:40:13 +08:00

274 lines
8.3 KiB
HTML

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline' data:;">
<style>
:root {
color-scheme: dark light;
--bg: #0b1220;
--card: #111827;
--fg: #e6eaf2;
--muted: #9ca3af;
--accent1: #60a5fa;
--accent2: #34d399;
--error: #fca5a5;
--ok: #86efac;
}
html,
body {
height: 100%;
}
body {
margin: 0;
display: flex;
align-items: center;
justify-content: center;
font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial;
background: radial-gradient(1200px 600px at 10% 0%, rgba(96, 165, 250, .2), transparent 70%),
radial-gradient(1200px 600px at 100% 120%, rgba(52, 211, 153, .15), transparent 70%),
var(--bg);
color: var(--fg);
}
.card {
width: min(540px, 92vw);
background: var(--card);
border-radius: 18px;
padding: 32px 26px;
box-shadow: 0 20px 48px rgba(0, 0, 0, .35);
text-align: center;
backdrop-filter: blur(6px);
}
.spinner {
width: 52px;
height: 52px;
margin: 0 auto 18px;
border: 4px solid rgba(255, 255, 255, .15);
border-top-color: var(--accent1);
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg)
}
}
h2 {
margin: 6px 0 10px;
font-weight: 700;
font-size: 20px;
background: linear-gradient(90deg, var(--accent1), var(--accent2));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
p {
margin: 0 0 10px;
opacity: .9;
}
.muted {
opacity: .75;
font-size: 14px;
}
.tips {
margin-top: 16px;
text-align: left;
font-size: 13px;
line-height: 1.6;
opacity: .9;
background: #0f172a;
border-radius: 12px;
padding: 12px 14px;
border: 1px solid rgba(255, 255, 255, .08);
}
code {
background: #0b1220;
padding: 1px 6px;
border-radius: 6px;
font-size: 12px;
}
ul {
padding-left: 18px;
margin: 6px 0 0;
}
/* 更新视图样式 */
.progress {
margin: 18px auto 10px;
width: 100%;
max-width: 440px;
height: 12px;
background: #0b1220;
border-radius: 999px;
overflow: hidden;
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .06);
}
.progress__bar {
height: 100%;
width: 0%;
background: linear-gradient(90deg, var(--accent1), var(--accent2));
transition: width .15s ease;
}
.row {
opacity: .9;
font-size: 14px;
margin-top: 6px;
display: flex;
justify-content: space-between;
padding: 0 6px;
}
.actions {
margin-top: 14px;
}
.btn {
appearance: none;
border: 0;
padding: 9px 16px;
border-radius: 10px;
background: var(--accent1);
color: #fff;
font-weight: 600;
cursor: pointer;
font-size: 14px;
}
.btn[disabled] {
opacity: .6;
cursor: not-allowed;
}
.warn {
color: var(--error);
font-size: 13px;
margin-top: 6px;
}
.ok {
color: var(--ok);
font-size: 13px;
margin-top: 6px;
}
[hidden] {
display: none !important;
}
</style>
</head>
<body>
<div class="card">
<!-- 等待视图 -->
<div id="wait-view">
<div class="spinner"></div>
<h2>正在检查更新…</h2>
<p class="muted">系统会自动检测可用的新版本</p>
<div class="tips">
<strong>如果长时间停留在此页面,可尝试:</strong>
<ul>
<li>检查网络是否可用</li>
<li>确认杀软/防火墙没有拦截本应用</li>
<li>重启应用后再试</li>
</ul>
</div>
</div>
<!-- 更新视图 -->
<div id="update-view" hidden>
<h2 id="upd-title">检测到新版本,正在下载…</h2>
<div class="progress" aria-label="下载进度">
<div id="upd-bar" class="progress__bar"></div>
</div>
<div class="row">
<div id="upd-percent">0.00%</div>
<div id="upd-meta"><small></small></div>
</div>
<div id="upd-msg" class="ok" hidden>下载完成,准备安装</div>
<div id="upd-err" class="warn" hidden></div>
<div class="actions">
<button id="btn-install" class="btn" hidden>立即重启安装</button>
</div>
</div>
</div>
<script>
(function bindUpdaterUI() {
const bridge = window.appUpdater;
if (!bridge) return;
const $ = (id) => document.getElementById(id);
const waitView = $('wait-view');
const updView = $('update-view');
const updBar = $('upd-bar');
const updPercent = $('upd-percent');
const updMeta = $('upd-meta');
const updTitle = $('upd-title');
const updMsg = $('upd-msg');
const updErr = $('upd-err');
const btnInstall = $('btn-install');
const fmtMB = b => (b / 1024 / 1024).toFixed(1) + ' MB';
const fmtSpeed = bps => (bps / 1024).toFixed(0) + ' KB/s';
const showUpdateView = (titleText) => {
if (titleText) updTitle.textContent = titleText;
waitView.hidden = true;
updView.hidden = false;
};
bridge.onAvailable((info) => {
const ver = info?.version || '';
showUpdateView(ver ? `检测到新版本 v${ver},正在下载…` : '检测到新版本,正在下载…');
});
bridge.onProgress((p) => {
if (updView.hidden) showUpdateView('正在下载更新…');
const percent = Math.max(0, Math.min(100, p?.percent || 0));
updBar.style.width = percent.toFixed(2) + '%';
updPercent.textContent = percent.toFixed(2) + '%';
const transferred = typeof p?.transferred === 'number' ? fmtMB(p.transferred) : '-';
const total = typeof p?.total === 'number' ? fmtMB(p.total) : '-';
const speed = typeof p?.bytesPerSecond === 'number' ? fmtSpeed(p.bytesPerSecond) : '-';
updMeta.innerHTML = `<small>${transferred} / ${total} · ${speed}</small>`;
updMsg.hidden = true;
updErr.hidden = true;
});
bridge.onDownloaded(() => {
updTitle.textContent = '更新下载完成';
updBar.style.width = '100%';
updPercent.textContent = '100%';
updMsg.hidden = false;
btnInstall.hidden = false;
});
bridge.onError((err) => {
updTitle.textContent = '更新出错';
updErr.hidden = false;
updErr.textContent = (err && (err.message || err)) || '发生未知错误';
btnInstall.hidden = true;
});
btnInstall.addEventListener('click', () => {
btnInstall.disabled = true;
try { bridge.quitAndInstallNow?.(); } catch (e) { }
});
})();
</script>
</body>
</html>