282 lines
7.7 KiB
HTML
282 lines
7.7 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>FMS 企业管理系统</title>
|
|
<style>
|
|
:root {
|
|
--boot-bg: #ffffff;
|
|
--boot-fg: #17171f;
|
|
--boot-muted: #9a9aa8;
|
|
--boot-error: #dc2626;
|
|
--boot-accent: #863bff;
|
|
--boot-accent-2: #5b8def;
|
|
--boot-glow: rgba(134, 59, 255, 0.22);
|
|
}
|
|
|
|
.dark {
|
|
--boot-bg: #0e0e14;
|
|
--boot-fg: #f4f4f8;
|
|
--boot-muted: #7a7a8a;
|
|
--boot-error: #f87171;
|
|
--boot-accent: #a774ff;
|
|
--boot-accent-2: #6fa8ff;
|
|
--boot-glow: rgba(167, 116, 255, 0.28);
|
|
}
|
|
|
|
html,
|
|
body,
|
|
#app {
|
|
width: 100%;
|
|
height: 100%;
|
|
margin: 0;
|
|
}
|
|
|
|
.app-boot {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 9999;
|
|
display: grid;
|
|
place-items: center;
|
|
color: var(--boot-fg);
|
|
font-family:
|
|
Inter,
|
|
ui-sans-serif,
|
|
system-ui,
|
|
-apple-system,
|
|
BlinkMacSystemFont,
|
|
'Segoe UI',
|
|
sans-serif;
|
|
background:
|
|
radial-gradient(120% 120% at 50% 0%, var(--boot-glow), transparent 55%),
|
|
var(--boot-bg);
|
|
transition: opacity 0.4s ease;
|
|
}
|
|
|
|
.app-boot__content {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 24px;
|
|
}
|
|
|
|
.app-boot__mark {
|
|
position: relative;
|
|
display: grid;
|
|
width: 104px;
|
|
height: 104px;
|
|
place-items: center;
|
|
}
|
|
|
|
.app-boot__ring {
|
|
position: absolute;
|
|
inset: 0;
|
|
box-sizing: border-box;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.app-boot__ring--1 {
|
|
border: 2px solid color-mix(in srgb, var(--boot-accent) 22%, transparent);
|
|
border-top-color: var(--boot-accent);
|
|
animation: app-boot-spin 1.1s linear infinite;
|
|
}
|
|
|
|
.app-boot__ring--2 {
|
|
inset: 11px;
|
|
border: 2px solid transparent;
|
|
border-bottom-color: var(--boot-accent-2);
|
|
animation: app-boot-spin 1.7s linear infinite reverse;
|
|
}
|
|
|
|
.app-boot__ring--3 {
|
|
inset: 22px;
|
|
border: 2px dashed color-mix(in srgb, var(--boot-accent) 30%, transparent);
|
|
animation: app-boot-spin 2.6s linear infinite;
|
|
}
|
|
|
|
.app-boot__logo {
|
|
width: 46px;
|
|
height: 46px;
|
|
font-size: 20px;
|
|
font-weight: 800;
|
|
letter-spacing: 0.5px;
|
|
line-height: 1;
|
|
display: grid;
|
|
place-items: center;
|
|
background: linear-gradient(135deg, var(--boot-accent), var(--boot-accent-2));
|
|
-webkit-background-clip: text;
|
|
background-clip: text;
|
|
color: transparent;
|
|
animation: app-boot-pulse 1.9s ease-in-out infinite;
|
|
}
|
|
|
|
.app-boot__title {
|
|
margin: 0;
|
|
font-size: 17px;
|
|
font-weight: 700;
|
|
letter-spacing: 0.5px;
|
|
background: linear-gradient(90deg, var(--boot-accent), var(--boot-accent-2), var(--boot-accent));
|
|
background-size: 200% auto;
|
|
-webkit-background-clip: text;
|
|
background-clip: text;
|
|
color: transparent;
|
|
animation: app-boot-flow 2.4s linear infinite;
|
|
}
|
|
|
|
.app-boot__hint {
|
|
margin: 0;
|
|
font-size: 13px;
|
|
color: var(--boot-muted);
|
|
letter-spacing: 0.5px;
|
|
}
|
|
|
|
.app-boot__message {
|
|
max-width: 320px;
|
|
margin: 0;
|
|
color: var(--boot-error);
|
|
font-size: 13px;
|
|
line-height: 1.5;
|
|
text-align: center;
|
|
}
|
|
|
|
.app-boot__retry {
|
|
height: 32px;
|
|
padding: 0 14px;
|
|
color: var(--boot-fg);
|
|
font: inherit;
|
|
font-size: 13px;
|
|
cursor: pointer;
|
|
background: transparent;
|
|
border: 1px solid color-mix(in srgb, var(--boot-fg) 22%, transparent);
|
|
border-radius: 8px;
|
|
transition: background 0.2s ease;
|
|
}
|
|
|
|
.app-boot__retry:hover {
|
|
background: color-mix(in srgb, var(--boot-fg) 8%, transparent);
|
|
}
|
|
|
|
.app-boot--error .app-boot__ring,
|
|
.app-boot--error .app-boot__logo,
|
|
.app-boot--error .app-boot__title,
|
|
.app-boot--error .app-boot__hint {
|
|
display: none;
|
|
}
|
|
|
|
[hidden] {
|
|
display: none !important;
|
|
}
|
|
|
|
@keyframes app-boot-spin {
|
|
to {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
|
|
@keyframes app-boot-pulse {
|
|
0%,
|
|
100% {
|
|
transform: scale(1);
|
|
opacity: 1;
|
|
}
|
|
50% {
|
|
transform: scale(1.12);
|
|
opacity: 0.82;
|
|
}
|
|
}
|
|
|
|
@keyframes app-boot-flow {
|
|
to {
|
|
background-position: 200% center;
|
|
}
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.app-boot__ring,
|
|
.app-boot__logo,
|
|
.app-boot__title {
|
|
animation-duration: 2.4s;
|
|
}
|
|
}
|
|
</style>
|
|
<script>
|
|
// 提前恢复深色模式,避免 CSS 加载前闪白
|
|
// 与 pinia-plugin-persistedstate 的存储结构保持一致
|
|
try {
|
|
var app = JSON.parse(localStorage.getItem('app') || '{}')
|
|
if (app && app.darkMode) {
|
|
document.documentElement.classList.add('dark')
|
|
}
|
|
} catch (e) {}
|
|
</script>
|
|
<script>
|
|
// 加载失败处理:普通内联脚本(非 module),不依赖外部文件。
|
|
// 仅处理确凿的失败信号 —— 入口 <script> 的 error 事件,立即报错并提供重试。
|
|
;(function () {
|
|
function getEl(id) {
|
|
return document.getElementById(id)
|
|
}
|
|
function bindRetry(retry) {
|
|
if (!retry) return
|
|
retry.hidden = false
|
|
retry.addEventListener(
|
|
'click',
|
|
function () {
|
|
window.location.reload()
|
|
},
|
|
{ once: true }
|
|
)
|
|
}
|
|
window.__appBoot = {
|
|
fail: function (msg) {
|
|
var boot = getEl('app-boot')
|
|
if (!boot || boot.classList.contains('app-boot--error')) return
|
|
var message = getEl('app-boot-message')
|
|
var retry = getEl('app-boot-retry')
|
|
boot.classList.add('app-boot--error')
|
|
boot.setAttribute('aria-busy', 'false')
|
|
boot.setAttribute('aria-label', '应用加载失败')
|
|
if (message) {
|
|
message.textContent = msg || '应用加载失败,请检查网络后重试'
|
|
message.hidden = false
|
|
}
|
|
bindRetry(retry)
|
|
}
|
|
}
|
|
})()
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<div id="app">
|
|
<div
|
|
id="app-boot"
|
|
class="app-boot"
|
|
role="status"
|
|
aria-label="应用加载中"
|
|
aria-live="polite"
|
|
aria-busy="true"
|
|
>
|
|
<div class="app-boot__content">
|
|
<div class="app-boot__mark" aria-hidden="true">
|
|
<span class="app-boot__ring app-boot__ring--1"></span>
|
|
<span class="app-boot__ring app-boot__ring--2"></span>
|
|
<span class="app-boot__ring app-boot__ring--3"></span>
|
|
<span class="app-boot__logo">FMS</span>
|
|
</div>
|
|
<h1 class="app-boot__title">FMS 企业管理系统</h1>
|
|
<p class="app-boot__hint" id="app-boot-hint">正在加载应用,请稍候…</p>
|
|
<p id="app-boot-message" class="app-boot__message" hidden></p>
|
|
<button id="app-boot-retry" class="app-boot__retry" type="button" hidden>重新加载</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script
|
|
type="module"
|
|
src="/src/main.js"
|
|
onerror="window.__appBoot && window.__appBoot.fail('应用资源加载失败,请检查网络后重试')"
|
|
></script>
|
|
</body>
|
|
</html>
|