frontend/src/views/404/index.vue
2026-01-27 10:08:03 +08:00

259 lines
5.6 KiB
Vue

<template>
<div class="not-found">
<!-- Load page -->
<div class="animationload">
<div class="loader"></div>
</div>
<!-- Content Wrapper -->
<div id="wrapper">
<div class="container">
<!-- Switcher -->
<div class="switcher">
<label for="sw" class="sw_btn"></label>
<div class="bg"></div>
</div>
<!-- Dark version -->
<div id="dark" class="row text-center" v-show="isDark">
<div class="info">
<img :src="darkImage" alt="404 error" />
</div>
</div>
<!-- Light version -->
<div
id="light"
class="row text-center"
style="display: flex; justify-content: center; align-items: center"
v-show="!isDark"
>
<div class="info">
<img :src="lightImage" alt="404 error" />
<p>
您要查找的页面已被移动或删除,
<br />
被重新命名,或者可能从未存在过。
</p>
<router-link to="/" class="btn">返回首页</router-link>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import darkImage from '@/assets/images/404/404-dark.png'
import lightImage from '@/assets/images/404/404-light.gif'
// 导入 jQuery 类型
type JQueryStatic = any;
// 声明 Modernizr 类型
interface ModernizrStatic {
// 添加 Modernizr 需要的属性和方法
[key: string]: boolean | string | number | object | undefined
}
// 声明全局类型
declare global {
interface Window {
jQuery: JQueryStatic
$: JQueryStatic
init404Page?: () => void
Modernizr: ModernizrStatic
}
}
// 使用 useRouter 但不需要返回值
useRouter()
const isDark = ref(false)
onMounted(() => {
// Initialize theme
document.body.classList.toggle('dark-theme', isDark.value)
// 在组件挂载后加载脚本
onMounted(() => {
// 加载 CSS 文件
const loadCSS = (href: string) => {
return new Promise<void>((resolve, reject) => {
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = href
link.onload = () => resolve()
link.onerror = (err) => reject(err)
document.head.appendChild(link)
})
}
// 加载 JS 文件
const loadJS = (src: string) => {
return new Promise<void>((resolve, reject) => {
const script = document.createElement('script')
script.src = src
script.onload = () => resolve()
script.onerror = (err) => reject(err)
document.body.appendChild(script)
})
}
// 加载所有资源
const loadAll = async () => {
try {
// 加载 CSS
await Promise.all([
loadCSS('/src/assets/css/bootstrap.min.css'),
loadCSS('/src/assets/css/404.min.css'),
loadCSS('/src/assets/css/font-face.css'),
])
// 加载 JS
await loadJS('/node_modules/jquery/dist/jquery.min.js')
// 设置全局 jQuery
const win = window as unknown as {
jQuery: JQueryStatic
$: JQueryStatic
}
window.jQuery = window.$ = win.jQuery || win.$
await Promise.all([
loadJS('/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js'),
loadJS('/src/assets/js/modernizr.custom.js'),
loadJS('/node_modules/jquery.nicescroll/jquery.nicescroll.min.js'),
loadJS('/src/assets/js/404.min.js'),
])
// 调用初始化函数(如果存在)
if (typeof window.init404Page === 'function') {
window.init404Page()
}
} catch (error) {
console.error('Error loading resources:', error)
}
}
loadAll()
})
})
</script>
<style scoped>
/* Add any component-specific styles here */
.not-found {
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
}
/* Ensure the wrapper takes full height */
#wrapper {
min-height: 100vh;
display: flex;
align-items: center;
}
/* Make sure the container is properly centered */
.container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
/* Make images responsive */
img {
max-width: 100%;
height: auto;
}
/* Style the home button */
.btn {
display: inline-block;
margin-top: 20px;
padding: 10px 20px;
background: #3498db;
color: white;
text-decoration: none;
border-radius: 4px;
transition: background 0.3s ease;
}
.btn:hover {
background: #2980b9;
}
/* Add smooth transitions for theme switching */
#dark,
#light {
transition: opacity 0.3s ease;
}
.info{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
/* Ensure proper spacing for the switcher */
.switcher {
position: fixed;
top: 20px;
right: 20px;
z-index: 1000;
}
/* 主题切换器文本样式 */
.switcher .text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 12px;
color: #666;
text-align: center;
line-height: 1.4;
white-space: nowrap;
pointer-events: none;
user-select: none;
transition: color 0.3s ease;
}
.switcher .text-l {
display: block;
margin-top: 2px;
font-size: 11px;
color: #999;
}
/* 暗色主题下的文本颜色 */
.dark-theme .switcher .text {
color: #ccc;
}
.dark-theme .switcher .text-l {
color: #aaa;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.container {
padding: 10px;
}
.switcher {
position: relative;
top: 0;
right: 0;
margin: 20px auto;
display: inline-block;
}
}
</style>