Files
workspace/code/fms/fms-vue/index.html
T
2026-08-17 17:29:54 +08:00

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>