268 lines
8.1 KiB
HTML
268 lines
8.1 KiB
HTML
<!doctype html>
|
|
<html lang="zh-CN">
|
|
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<title>YOLO 更新检查</title>
|
|
<meta http-equiv="Content-Security-Policy"
|
|
content="default-src 'self'; style-src 'unsafe-inline' 'self'; script-src 'self' 'unsafe-inline'; img-src 'self' data:;">
|
|
<meta name="color-scheme" content="light dark">
|
|
<style>
|
|
:root {
|
|
--bg: #0b1220;
|
|
--card: #0f172a;
|
|
--text: #e5e7eb;
|
|
--muted: #9ca3af;
|
|
--accent: #60a5fa;
|
|
--accent-2: #34d399;
|
|
--bar-bg: #1f2937;
|
|
--bar-fg: linear-gradient(90deg, var(--accent), var(--accent-2));
|
|
--ok: #34d399;
|
|
--error: #ef4444;
|
|
}
|
|
|
|
@media (prefers-color-scheme: light) {
|
|
:root {
|
|
--bg: #f8fafc;
|
|
--card: #ffffff;
|
|
--text: #0f172a;
|
|
--muted: #64748b;
|
|
--bar-bg: #e5e7eb;
|
|
}
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
html,
|
|
body {
|
|
height: 100%;
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial;
|
|
background: radial-gradient(1200px 600px at 20% -10%, rgba(96, 165, 250, .25), transparent 50%),
|
|
radial-gradient(1200px 600px at 120% 120%, rgba(52, 211, 153, .25), transparent 50%),
|
|
var(--bg);
|
|
color: var(--text);
|
|
display: grid;
|
|
place-items: center;
|
|
}
|
|
|
|
.card {
|
|
width: 560px;
|
|
max-width: calc(100% - 40px);
|
|
background: linear-gradient(180deg, rgba(255, 255, 255, .04), rgba(255, 255, 255, 0)), var(--card);
|
|
border: 1px solid rgba(255, 255, 255, .08);
|
|
border-radius: 20px;
|
|
padding: 28px;
|
|
box-shadow: 0 10px 40px rgba(0, 0, 0, .25);
|
|
backdrop-filter: blur(6px);
|
|
}
|
|
|
|
.header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 14px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.logo {
|
|
width: 36px;
|
|
height: 36px;
|
|
border-radius: 10px;
|
|
background: linear-gradient(135deg, var(--accent), var(--accent-2));
|
|
display: grid;
|
|
place-items: center;
|
|
color: white;
|
|
font-weight: 900;
|
|
text-shadow: 0 1px 2px rgba(0, 0, 0, .3);
|
|
}
|
|
|
|
h1 {
|
|
font-size: 18px;
|
|
margin: 0;
|
|
}
|
|
|
|
.sub {
|
|
color: var(--muted);
|
|
font-size: 13px;
|
|
margin-top: 2px;
|
|
}
|
|
|
|
.status {
|
|
margin: 20px 0 16px;
|
|
padding: 12px 14px;
|
|
background: rgba(255, 255, 255, .04);
|
|
border: 1px dashed rgba(255, 255, 255, .18);
|
|
border-radius: 12px;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.progress-wrap {
|
|
background: var(--bar-bg);
|
|
border-radius: 999px;
|
|
overflow: hidden;
|
|
height: 14px;
|
|
width: 100%;
|
|
box-shadow: inset 0 1px 2px rgba(0, 0, 0, .25);
|
|
}
|
|
|
|
.progress-bar {
|
|
height: 100%;
|
|
width: 0%;
|
|
background: var(--bar-fg);
|
|
transition: width .25s ease;
|
|
}
|
|
|
|
.row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: 14px;
|
|
margin-top: 10px;
|
|
font-size: 12px;
|
|
color: var(--muted);
|
|
}
|
|
|
|
.actions {
|
|
margin-top: 18px;
|
|
display: flex;
|
|
gap: 10px;
|
|
}
|
|
|
|
button {
|
|
appearance: none;
|
|
border: 0;
|
|
border-radius: 12px;
|
|
padding: 10px 14px;
|
|
cursor: pointer;
|
|
background: linear-gradient(90deg, var(--accent), var(--accent-2));
|
|
color: white;
|
|
font-weight: 600;
|
|
font-size: 14px;
|
|
box-shadow: 0 6px 18px rgba(56, 189, 248, .35);
|
|
}
|
|
|
|
button.ghost {
|
|
background: transparent;
|
|
border: 1px solid rgba(255, 255, 255, .18);
|
|
color: var(--text);
|
|
}
|
|
|
|
.ok {
|
|
color: var(--ok);
|
|
}
|
|
|
|
.err {
|
|
color: var(--error);
|
|
}
|
|
|
|
.fade {
|
|
animation: fade .3s ease both;
|
|
}
|
|
|
|
@keyframes fade {
|
|
from {
|
|
opacity: .0;
|
|
transform: translateY(6px)
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
transform: none
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<div class="card fade">
|
|
<div class="header">
|
|
<div class="logo">PY</div>
|
|
<div>
|
|
<h1>YOLO 启动 / 更新检查</h1>
|
|
<div class="sub">为你自动检查可用更新并在后台下载</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="status" class="status">正在初始化…</div>
|
|
|
|
<div class="progress-wrap" aria-label="下载进度">
|
|
<div id="bar" class="progress-bar"></div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div>速度:<span id="speed">0</span> MB/s</div>
|
|
<div>已下:<span id="transferred">0</span>/<span id="total">0</span> MB</div>
|
|
<div>进度:<span id="percent">0</span>%</div>
|
|
</div>
|
|
|
|
<div class="actions">
|
|
<button id="btn-install" style="display:none;">立即重启安装</button>
|
|
<button id="btn-hide" class="ghost">最小化到托盘</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const $ = (id) => document.getElementById(id);
|
|
const statusEl = $('status');
|
|
const bar = $('bar');
|
|
const sp = $('speed'), tf = $('transferred'), tt = $('total'), pc = $('percent');
|
|
const btnInstall = $('btn-install');
|
|
const btnHide = $('btn-hide');
|
|
|
|
// 订阅主进程事件
|
|
window.electronAPI.onUpdateStatus(({ status, version, notes, currentVersion, message }) => {
|
|
switch (status) {
|
|
case 'checking':
|
|
statusEl.textContent = '正在检查更新…';
|
|
break;
|
|
case 'available':
|
|
statusEl.innerHTML = `检测到新版本 <b>v${version}</b>,正在下载…`;
|
|
break;
|
|
case 'none':
|
|
statusEl.innerHTML = `已是最新版本 <span class="ok">(v${currentVersion})</span>。3 秒后自动最小化。`;
|
|
bar.style.width = '100%'; pc.textContent = '100';
|
|
setTimeout(() => window.close(), 3000);
|
|
break;
|
|
case 'downloaded':
|
|
statusEl.innerHTML = `下载完成!可立即安装更新 <b>v${version}</b>。`;
|
|
bar.style.width = '100%'; pc.textContent = '100';
|
|
btnInstall.style.display = '';
|
|
// 也可自动倒计时安装:
|
|
// setTimeout(() => btnInstall.click(), 3000);
|
|
break;
|
|
case 'error':
|
|
statusEl.innerHTML = `更新失败:<span class="err">${message || '未知错误'}</span>`;
|
|
break;
|
|
default:
|
|
statusEl.textContent = '状态:' + status;
|
|
}
|
|
});
|
|
|
|
window.electronAPI.onUpdateProgress(({ percent, transferred, total, speed }) => {
|
|
bar.style.width = Math.max(0, Math.min(100, percent || 0)) + '%';
|
|
sp.textContent = speed ?? 0;
|
|
tf.textContent = transferred ?? 0;
|
|
tt.textContent = total ?? 0;
|
|
pc.textContent = (percent ?? 0).toFixed(1);
|
|
});
|
|
|
|
// 交互
|
|
btnInstall.addEventListener('click', () => {
|
|
statusEl.textContent = '即将重启并安装更新…';
|
|
window.electronAPI.installNow();
|
|
});
|
|
|
|
btnHide.addEventListener('click', () => {
|
|
window.close(); // 在 main.js 里拦截 close -> hide()
|
|
});
|
|
|
|
// 首次加载立即请求检查
|
|
window.electronAPI.checkForUpdates();
|
|
</script>
|
|
</body>
|
|
|
|
</html> |