Files
termi-blog/frontend/src/pages/maintenance.astro
limitcool 36d505ece6
All checks were successful
ui-regression / playwright-regression (push) Successful in 6m20s
docker-images / resolve-build-targets (push) Successful in 6s
docker-images / build-and-push (admin) (push) Successful in 25s
docker-images / build-and-push (backend) (push) Successful in 35s
docker-images / build-and-push (frontend) (push) Successful in 1m46s
docker-images / submit-indexnow (push) Successful in 15s
feat: 添加站点设置中的 favicon URL 支持,更新相关接口和页面
2026-04-03 02:13:27 +08:00

153 lines
5.9 KiB
Plaintext

---
import '../styles/global.css'
import { api, DEFAULT_SITE_SETTINGS } from '../lib/api/client'
import { sanitizeMaintenanceReturnTo } from '../lib/maintenance'
const errorCode = Astro.url.searchParams.get('error')
const returnTo = sanitizeMaintenanceReturnTo(Astro.url.searchParams.get('returnTo'))
let siteSettings = DEFAULT_SITE_SETTINGS
try {
siteSettings = await api.getSiteSettings()
} catch (error) {
console.error('Failed to load site settings on maintenance page:', error)
}
const errorMessage =
errorCode === 'empty'
? '请先输入访问口令。'
: errorCode === 'invalid'
? '口令不正确,请重新输入。'
: errorCode === 'unavailable'
? '当前无法校验访问口令,请稍后再试。'
: ''
---
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="robots" content="noindex, nofollow" />
<link rel="icon" href="/favicon.ico" />
<title>{siteSettings.siteName} · 维护模式</title>
</head>
<body class="min-h-screen bg-[var(--bg)] text-[var(--text)]">
<main class="mx-auto flex min-h-screen w-full max-w-6xl items-center px-4 py-10 sm:px-6 lg:px-8">
<section class="terminal-toolbar-shell mx-auto w-full max-w-2xl overflow-hidden rounded-[2rem] p-0">
<div class="border-b border-[var(--border-color)] px-6 py-5 sm:px-8">
<div class="flex items-center gap-3">
<span class="flex h-12 w-12 items-center justify-center rounded-2xl border border-[var(--border-color)] bg-[var(--primary)]/10 text-xl font-semibold text-[var(--primary)]">
{siteSettings.siteShortName?.charAt(0) || siteSettings.siteName?.charAt(0) || 'T'}
</span>
<div class="min-w-0">
<p class="terminal-toolbar-label">MAINTENANCE ACCESS</p>
<h1 class="mt-1 text-2xl font-bold text-[var(--title-color)] sm:text-3xl">
{siteSettings.siteName} 正在维护
</h1>
</div>
</div>
</div>
<div class="space-y-6 px-6 py-6 sm:px-8 sm:py-8">
<div class="rounded-3xl border border-[var(--border-color)] bg-[var(--terminal-bg)]/80 p-5">
<p class="text-sm leading-7 text-[var(--text-secondary)]">
当前前台内容暂时对外隐藏。你如果拿到了测试口令,可以直接输入进入站点继续浏览;没有口令的话,等我们开放后再访问即可。
</p>
{errorMessage && (
<div class="mt-4 rounded-2xl border border-[var(--danger)]/20 bg-[var(--danger)]/8 px-4 py-3 text-sm text-[var(--danger)]">
{errorMessage}
</div>
)}
</div>
<form
method="post"
action="/api/maintenance/unlock"
class="space-y-4"
data-maintenance-unlock-form
>
<input type="hidden" name="returnTo" value={returnTo} />
<label class="block">
<span class="terminal-form-label">访问口令</span>
<input
type="password"
name="code"
autocomplete="current-password"
placeholder="请输入测试口令"
class="terminal-form-input"
/>
</label>
<div class="flex flex-col gap-3 sm:flex-row sm:items-center">
<button type="submit" class="terminal-action-button terminal-action-button-primary min-w-[10rem]">
进入站点
</button>
<p class="text-sm leading-6 text-[var(--text-tertiary)]">
口令修改后,旧的访问凭证会自动失效。
</p>
</div>
</form>
<div class="rounded-3xl border border-dashed border-[var(--border-color)] bg-[var(--header-bg)]/40 px-5 py-4">
<p class="text-xs uppercase tracking-[0.22em] text-[var(--text-tertiary)]">
Return Target
</p>
<p class="mt-2 font-mono text-sm text-[var(--title-color)]">{returnTo}</p>
</div>
</div>
</section>
</main>
<script>
const maintenanceForm = document.querySelector('[data-maintenance-unlock-form]');
if (maintenanceForm instanceof HTMLFormElement) {
maintenanceForm.addEventListener('submit', async (event) => {
event.preventDefault();
const submitButton = maintenanceForm.querySelector('button[type="submit"]');
if (submitButton instanceof HTMLButtonElement) {
submitButton.disabled = true;
}
try {
const formData = new FormData(maintenanceForm);
const response = await fetch(maintenanceForm.action, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
credentials: 'same-origin',
body: JSON.stringify({
code: String(formData.get('code') || ''),
returnTo: String(formData.get('returnTo') || '/'),
}),
});
window.location.assign(response.url);
} catch (error) {
console.error('Failed to submit maintenance unlock form:', error);
const currentUrl = new URL(window.location.href);
const nextUrl = new URL('/maintenance', currentUrl.origin);
const returnToValue = new FormData(maintenanceForm).get('returnTo');
nextUrl.searchParams.set(
'returnTo',
String(returnToValue || currentUrl.searchParams.get('returnTo') || '/'),
);
nextUrl.searchParams.set('error', 'unavailable');
window.location.assign(nextUrl.toString());
} finally {
if (submitButton instanceof HTMLButtonElement) {
submitButton.disabled = false;
}
}
});
}
</script>
</body>
</html>