iFileProxyAdmin/src/App.vue

130 lines
No EOL
2.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<router-view v-slot="{ Component }">
<transition
name="fade"
mode="out-in"
@before-leave="showLoadingMask"
@after-enter="hideLoadingMask">
<component :is="Component" />
</transition>
</router-view>
<!-- 全局加载遮罩 -->
<transition name="fade">
<div v-if="isLoading" class="global-loading-mask">
<div class="loading-spinner"></div>
</div>
</transition>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { UserAPI } from '@/api/user'
import { initFingerprint } from '@/utils/fingerprint'
const router = useRouter()
const isLoading = ref(false)
const showLoadingMask = () => {
isLoading.value = true
}
const hideLoadingMask = () => {
isLoading.value = false
}
// 检查登录状态
const checkAuthStatus = async () => {
const token = localStorage.getItem('token')
const isAuthenticated = localStorage.getItem('isAuthenticated')
// 只有当存在token和认证状态时才检查
if (token && isAuthenticated) {
try {
const response = await UserAPI.getUserInfo()
if (response.retcode !== 0) {
clearAuthData('登录已失效,请重新登录')
}
} catch (error) {
// 如果是401错误清除认证数据并重定向
if (error.response?.status === 401) {
clearAuthData('登录已过期,请重新登录')
}
}
}
}
// 清除认证数据
const clearAuthData = (message) => {
localStorage.removeItem('token')
localStorage.removeItem('isAuthenticated')
localStorage.removeItem('userRole')
localStorage.removeItem('userInfo')
// 如果当前不在访客页面,显示提示并重定向到登录页
if (!router.currentRoute.value.path.startsWith('/visitor')) {
if (message) {
ElMessage.warning(message)
}
router.push('/login')
}
}
onMounted(async () => {
// 初始化指纹
await initFingerprint()
// 检查登录状态
await checkAuthStatus()
})
</script>
<style>
.app-container {
height: 100vh;
}
/* 过渡动画 */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
/* 全局加载遮罩 */
.global-loading-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(8px);
z-index: 9999;
display: flex;
justify-content: center;
align-items: center;
}
/* 加载动画 */
.loading-spinner {
width: 40px;
height: 40px;
border: 3px solid #f3f3f3;
border-top: 3px solid #1890ff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>